diff --git a/apps/web/app/components/sidebar.tsx b/apps/web/app/components/sidebar.tsx index 57a886e1b64..e44a1e42360 100644 --- a/apps/web/app/components/sidebar.tsx +++ b/apps/web/app/components/sidebar.tsx @@ -216,7 +216,7 @@ function WorkspaceSection({ tree, onRefresh }: { tree: TreeNode[]; onRefresh: () const handleSelect = useCallback((node: TreeNode) => { // Navigate to workspace page for actionable items if (node.type === "object" || node.type === "document" || node.type === "file" || node.type === "database" || node.type === "report") { - window.location.href = `/workspace?path=${encodeURIComponent(node.path)}`; + window.location.href = `/?path=${encodeURIComponent(node.path)}`; } }, []); @@ -240,7 +240,7 @@ function WorkspaceSection({ tree, onRefresh }: { tree: TreeNode[]; onRefresh: () {/* Full workspace link */} @@ -279,7 +279,7 @@ function ReportsSection({ tree }: { tree: TreeNode[] }) { {reports.map((report) => ( diff --git a/apps/web/app/components/workspace/database-viewer.tsx b/apps/web/app/components/workspace/database-viewer.tsx index ce00bd6bdbe..e86b328f5e9 100644 --- a/apps/web/app/components/workspace/database-viewer.tsx +++ b/apps/web/app/components/workspace/database-viewer.tsx @@ -170,7 +170,7 @@ export function DuckDBMissing() { - - )} - - {/* Main content */} -
- {/* Mobile top bar — always visible on mobile */} - {isMobile && ( -
- -
- {activePath ? activePath.split("/").pop() : (context?.organization?.name || "Workspace")} -
-
- {activePath && content.kind !== "none" && ( - - )} - {showMainChat && ( - - )} -
-
- )} - - {/* When a file is selected: show top bar with breadcrumbs (desktop only, mobile has unified top bar) */} - {!isMobile && activePath && content.kind !== "none" && ( -
- -
- {/* Back to chat button */} - - {/* Chat sidebar toggle (hidden for reserved/virtual paths) */} - {fileContext && ( - - )} -
-
- )} - - {/* Content area */} -
- {showMainChat ? ( - /* Main chat view (default when no file is selected) */ - <> -
- { - setActiveSessionId(id); - setActiveSubagentKey(null); - }} - onSessionsChange={activeSubagent ? undefined : refreshSessions} - onSubagentSpawned={activeSubagent ? undefined : handleSubagentSpawned} - onSubagentClick={handleSubagentClickFromChat} - onFilePathClick={handleFilePathClickFromChat} - onDeleteSession={activeSubagent ? undefined : handleDeleteSession} - onRenameSession={activeSubagent ? undefined : handleRenameSession} - compact={isMobile} - sessionKey={activeSubagent?.childSessionKey} - subagentTask={activeSubagent?.task} - subagentLabel={activeSubagent?.label} - onBack={activeSubagent ? handleBackFromSubagent : undefined} - /> -
- {/* Chat sessions sidebar — static on desktop, drawer overlay on mobile */} - {isMobile ? ( - chatSessionsOpen && ( - { - setActiveSessionId(sessionId); - setActiveSubagentKey(null); - void chatRef.current?.loadSession(sessionId); - }} - onNewSession={() => { - setActiveSessionId(null); - setActiveSubagentKey(null); - void chatRef.current?.newSession(); - router.replace("/workspace", { scroll: false }); - setChatSessionsOpen(false); - }} - onSelectSubagent={handleSelectSubagent} - onDeleteSession={handleDeleteSession} - onRenameSession={handleRenameSession} - mobile - onClose={() => setChatSessionsOpen(false)} - /> - ) - ) : ( - <> - {!rightSidebarCollapsed && ( -
- - {chatSidebarPreview ? ( - setChatSidebarPreview(null)} - /> - ) : ( - { - setActiveSessionId(sessionId); - setActiveSubagentKey(null); - void chatRef.current?.loadSession(sessionId); - }} - onNewSession={() => { - setActiveSessionId(null); - setActiveSubagentKey(null); - void chatRef.current?.newSession(); - router.replace("/workspace", { scroll: false }); - }} - onSelectSubagent={handleSelectSubagent} - onDeleteSession={handleDeleteSession} - onRenameSession={handleRenameSession} - onCollapse={() => setRightSidebarCollapsed(true)} - width={rightSidebarWidth} - /> - )} -
- )} - {rightSidebarCollapsed && ( -
- -
- )} - - )} - - ) : ( - <> - {/* File content area */} -
- -
- - {/* Chat sidebar (file/folder-scoped) — hidden for reserved paths, hidden on mobile */} - {!isMobile && fileContext && showChatSidebar && !rightSidebarCollapsed && ( - <> - - - )} - - )} -
-
- - {/* Entry detail modal (rendered on top of everything) */} - {entryModal && ( - handleOpenEntry(objName, eid)} - onNavigateObject={(objName) => { - handleCloseEntry(); - handleNavigateToObject(objName); - }} - onRefresh={refreshCurrentObject} - /> - )} +
+
); } - -function previewFileTypeBadge(filename: string): { label: string; color: string } { - const ext = filename.split(".").pop()?.toLowerCase() ?? ""; - if (ext === "pdf") {return { label: "PDF", color: "#ef4444" };} - if (["jpg", "jpeg", "png", "gif", "webp", "svg", "bmp", "heic", "avif"].includes(ext)) {return { label: "Image", color: "#3b82f6" };} - if (["mp4", "webm", "mov", "avi", "mkv"].includes(ext)) {return { label: "Video", color: "#8b5cf6" };} - if (["mp3", "wav", "ogg", "m4a", "aac", "flac"].includes(ext)) {return { label: "Audio", color: "#f59e0b" };} - if (["md", "mdx"].includes(ext)) {return { label: "Markdown", color: "#10b981" };} - if (["ts", "tsx", "js", "jsx", "py", "go", "rs", "java", "rb", "swift", "kt", "c", "cpp", "h"].includes(ext)) {return { label: ext.toUpperCase(), color: "#3b82f6" };} - if (["json", "yaml", "yml", "toml", "xml", "csv"].includes(ext)) {return { label: ext.toUpperCase(), color: "#6b7280" };} - if (["duckdb", "sqlite", "sqlite3", "db"].includes(ext)) {return { label: "Database", color: "#6366f1" };} - return { label: ext.toUpperCase() || "File", color: "#6b7280" }; -} - -function shortenPreviewPath(p: string): string { - return p.replace(/^\/Users\/[^/]+/, "~").replace(/^\/home\/[^/]+/, "~"); -} - -function ChatSidebarPreview({ - preview, - onClose, -}: { - preview: ChatSidebarPreviewState; - onClose: () => void; -}) { - const badge = previewFileTypeBadge(preview.filename); - - const openInFinder = useCallback(async () => { - try { - await fetch("/api/workspace/open-file", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ path: preview.path, reveal: true }), - }); - } catch { /* ignore */ } - }, [preview.path]); - - const openWithSystem = useCallback(async () => { - try { - await fetch("/api/workspace/open-file", { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ path: preview.path }), - }); - } catch { /* ignore */ } - }, [preview.path]); - - const downloadUrl = preview.status === "ready" && preview.content.kind === "media" - ? preview.content.url - : null; - - let body: React.ReactNode; - - if (preview.status === "loading") { - body = ( -
- -

- Loading preview... -

-
- ); - } else if (preview.status === "error") { - body = ( -
-
- - - - - -
-
-

- Preview unavailable -

-

- {preview.message} -

-
-
- ); - } else { - const c = preview.content; - switch (c.kind) { - case "media": - if (c.mediaType === "pdf") { - // Hide the browser's built-in PDF toolbar for a cleaner look - const pdfUrl = c.url + (c.url.includes("#") ? "&" : "#") + "toolbar=0&navpanes=0&scrollbar=1"; - body = ( -