diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/hooks/useDashboardSidebarShortcuts/useDashboardSidebarShortcuts.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/hooks/useDashboardSidebarShortcuts/useDashboardSidebarShortcuts.ts index 7660739882c..82413df4232 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/hooks/useDashboardSidebarShortcuts/useDashboardSidebarShortcuts.ts +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/hooks/useDashboardSidebarShortcuts/useDashboardSidebarShortcuts.ts @@ -2,9 +2,17 @@ import { useMatchRoute, useNavigate } from "@tanstack/react-router"; import { useCallback, useMemo, useRef } from "react"; import { useHotkey } from "renderer/hotkeys"; import { navigateToV2Workspace } from "renderer/routes/_authenticated/_dashboard/utils/workspace-navigation"; +import { useDashboardSidebarState } from "renderer/routes/_authenticated/hooks/useDashboardSidebarState"; import type { DashboardSidebarProject } from "../../types"; import { getProjectChildrenWorkspaces } from "../../utils/projectChildren"; +interface WorkspaceLocation { + projectId: string; + projectIsCollapsed: boolean; + sectionId: string | null; + sectionIsCollapsed: boolean; +} + const MAX_SHORTCUT_COUNT = 9; function haveSameIds(left: string[], right: string[]): boolean { @@ -43,6 +51,8 @@ export function useDashboardSidebarShortcuts( groups: DashboardSidebarProject[], ) { const navigate = useNavigate(); + const { toggleProjectCollapsed, toggleSectionCollapsed } = + useDashboardSidebarState(); const flattenedWorkspaces = useMemo( () => groups @@ -53,14 +63,55 @@ export function useDashboardSidebarShortcuts( const workspaceShortcutLabels = useStableWorkspaceShortcutLabels(flattenedWorkspaces); + const workspaceLocations = useMemo(() => { + const map = new Map(); + for (const project of groups) { + for (const child of project.children) { + if (child.type === "workspace") { + map.set(child.workspace.id, { + projectId: project.id, + projectIsCollapsed: project.isCollapsed, + sectionId: null, + sectionIsCollapsed: false, + }); + continue; + } + for (const workspace of child.section.workspaces) { + map.set(workspace.id, { + projectId: project.id, + projectIsCollapsed: project.isCollapsed, + sectionId: child.section.id, + sectionIsCollapsed: child.section.isCollapsed, + }); + } + } + } + return map; + }, [groups]); + + const revealWorkspace = useCallback( + (workspaceId: string) => { + const location = workspaceLocations.get(workspaceId); + if (!location) return; + if (location.projectIsCollapsed) { + toggleProjectCollapsed(location.projectId); + } + if (location.sectionId && location.sectionIsCollapsed) { + toggleSectionCollapsed(location.sectionId); + } + }, + [workspaceLocations, toggleProjectCollapsed, toggleSectionCollapsed], + ); + const switchToWorkspace = useCallback( (index: number) => { const workspace = flattenedWorkspaces[index]; if (workspace) { + revealWorkspace(workspace.id); navigateToV2Workspace(workspace.id, navigate); } }, - [flattenedWorkspaces, navigate], + [flattenedWorkspaces, navigate, revealWorkspace], ); useHotkey("JUMP_TO_WORKSPACE_1", () => switchToWorkspace(0)); @@ -88,7 +139,9 @@ export function useDashboardSidebarShortcuts( ); if (index === -1) return; const prevIndex = index <= 0 ? flattenedWorkspaces.length - 1 : index - 1; - navigateToV2Workspace(flattenedWorkspaces[prevIndex].id, navigate); + const target = flattenedWorkspaces[prevIndex]; + revealWorkspace(target.id); + navigateToV2Workspace(target.id, navigate); }); useHotkey("NEXT_WORKSPACE", () => { @@ -98,7 +151,9 @@ export function useDashboardSidebarShortcuts( ); if (index === -1) return; const nextIndex = index >= flattenedWorkspaces.length - 1 ? 0 : index + 1; - navigateToV2Workspace(flattenedWorkspaces[nextIndex].id, navigate); + const target = flattenedWorkspaces[nextIndex]; + revealWorkspace(target.id); + navigateToV2Workspace(target.id, navigate); }); return workspaceShortcutLabels; diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/WorkspaceSidebar.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/WorkspaceSidebar.tsx index bac06261b80..12e90ced38b 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/WorkspaceSidebar.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/WorkspaceSidebar.tsx @@ -131,6 +131,7 @@ export function WorkspaceSidebar({ workspaceId, gitStatus, onSelectFile: onSelectDiffFile, + onOpenFile: onSelectFile, }); const changesTab: SidebarTabDefinition = { ...changesTabDef, diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/ChangesFileList.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/ChangesFileList.tsx index 36c976d31b0..8a622d02e91 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/ChangesFileList.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/ChangesFileList.tsx @@ -7,6 +7,7 @@ interface ChangesFileListProps { isLoading?: boolean; worktreePath?: string; onSelectFile?: (path: string, openInNewTab?: boolean) => void; + onOpenFile?: (absolutePath: string, openInNewTab?: boolean) => void; onOpenInEditor?: (path: string) => void; } @@ -15,6 +16,7 @@ export const ChangesFileList = memo(function ChangesFileList({ isLoading, worktreePath, onSelectFile, + onOpenFile, onOpenInEditor, }: ChangesFileListProps) { if (isLoading) { @@ -41,6 +43,7 @@ export const ChangesFileList = memo(function ChangesFileList({ file={file} worktreePath={worktreePath} onSelect={onSelectFile} + onOpenFile={onOpenFile} onOpenInEditor={onOpenInEditor} /> ))} diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx index b77d344d761..a1d90d2bbd0 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx @@ -6,7 +6,15 @@ import { ContextMenuShortcut, ContextMenuTrigger, } from "@superset/ui/context-menu"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@superset/ui/dropdown-menu"; import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; +import { ChevronDown } from "lucide-react"; import { memo } from "react"; import { StatusIndicator } from "renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/StatusIndicator"; import { PathActionsMenuItems } from "renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems"; @@ -33,6 +41,7 @@ interface FileRowProps { file: ChangesetFile; worktreePath?: string; onSelect?: (path: string, openInNewTab?: boolean) => void; + onOpenFile?: (absolutePath: string, openInNewTab?: boolean) => void; onOpenInEditor?: (path: string) => void; } @@ -40,6 +49,7 @@ export const FileRow = memo(function FileRow({ file, worktreePath, onSelect, + onOpenFile, onOpenInEditor, }: FileRowProps) { const { dir, basename } = splitPath(file.path); @@ -52,46 +62,90 @@ export const FileRow = memo(function FileRow({ : undefined; const rowButton = ( - + + {(file.additions > 0 || file.deletions > 0) && ( + + {file.additions > 0 && ( + +{file.additions} + )} + {file.additions > 0 && file.deletions > 0 && " "} + {file.deletions > 0 && ( + -{file.deletions} + )} + + )} + + + +
+ + + + + + onSelect?.(file.path)}> + Open Diff + + onSelect?.(file.path, true)}> + Open Diff in New Tab + {SHIFT_CLICK_LABEL} + + absolutePath && onOpenFile?.(absolutePath)} + disabled={!onOpenFile || !absolutePath} + > + Open File + + absolutePath && onOpenFile?.(absolutePath, true)} + disabled={!onOpenFile || !absolutePath} + > + Open File in New Tab + + onOpenInEditor?.(file.path)} + disabled={!onOpenInEditor} + > + Open in Editor + {MOD_CLICK_LABEL} + + + +
+ ); return ( @@ -110,6 +164,18 @@ export const FileRow = memo(function FileRow({ Open Diff in New Tab {SHIFT_CLICK_LABEL} + absolutePath && onOpenFile?.(absolutePath)} + disabled={!onOpenFile || !absolutePath} + > + Open File + + absolutePath && onOpenFile?.(absolutePath, true)} + disabled={!onOpenFile || !absolutePath} + > + Open File in New Tab + onOpenInEditor?.(file.path)} disabled={!onOpenInEditor} diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesTabContent/ChangesTabContent.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesTabContent/ChangesTabContent.tsx index 33442519c15..211fb8500cb 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesTabContent/ChangesTabContent.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesTabContent/ChangesTabContent.tsx @@ -24,6 +24,7 @@ interface ChangesTabContentProps { totalDeletions: number; worktreePath?: string; onSelectFile?: (path: string, openInNewTab?: boolean) => void; + onOpenFile?: (absolutePath: string, openInNewTab?: boolean) => void; onOpenInEditor?: (path: string) => void; onFilterChange: (filter: ChangesFilter) => void; onBaseBranchChange: (branchName: string) => void; @@ -44,6 +45,7 @@ export const ChangesTabContent = memo(function ChangesTabContent({ totalDeletions, worktreePath, onSelectFile, + onOpenFile, onOpenInEditor, onFilterChange, onBaseBranchChange, @@ -92,6 +94,7 @@ export const ChangesTabContent = memo(function ChangesTabContent({ isLoading={isLoading} worktreePath={worktreePath} onSelectFile={onSelectFile} + onOpenFile={onOpenFile} onOpenInEditor={onOpenInEditor} /> diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/useChangesTab.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/useChangesTab.tsx index 809df197830..4660bf8cb31 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/useChangesTab.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/useChangesTab.tsx @@ -22,12 +22,14 @@ interface UseChangesTabParams { workspaceId: string; gitStatus: ReturnType; onSelectFile?: (path: string, openInNewTab?: boolean) => void; + onOpenFile?: (absolutePath: string, openInNewTab?: boolean) => void; } export function useChangesTab({ workspaceId, gitStatus: status, onSelectFile, + onOpenFile, }: UseChangesTabParams): SidebarTabDefinition { const collections = useCollections(); const utils = workspaceTrpc.useUtils(); @@ -192,6 +194,7 @@ export function useChangesTab({ totalDeletions={totalDeletions} worktreePath={worktreePath} onSelectFile={onSelectFile} + onOpenFile={onOpenFile} onOpenInEditor={handleOpenInEditor} onFilterChange={setFilter} onBaseBranchChange={setBaseBranch} diff --git a/apps/docs/next.config.mjs b/apps/docs/next.config.mjs index 2b0fcb13ec8..c656a361dd4 100644 --- a/apps/docs/next.config.mjs +++ b/apps/docs/next.config.mjs @@ -29,12 +29,12 @@ const config = { return [ { source: "/", - destination: "/installation", + destination: "/overview", permanent: false, }, { source: "/docs", - destination: "/installation", + destination: "/overview", permanent: false, }, ]; diff --git a/apps/docs/src/app/sitemap.ts b/apps/docs/src/app/sitemap.ts index c78151903f6..7072ac1cbfc 100644 --- a/apps/docs/src/app/sitemap.ts +++ b/apps/docs/src/app/sitemap.ts @@ -11,6 +11,6 @@ export default function sitemap(): MetadataRoute.Sitemap { url: `${baseUrl}${page.url}`, lastModified: new Date(), changeFrequency: "weekly" as const, - priority: page.url === "/installation" ? 1.0 : 0.8, + priority: page.url === "/overview" ? 1.0 : 0.8, })); } diff --git a/packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx b/packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx index c6fb91f210f..0f99f630b01 100644 --- a/packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx +++ b/packages/panes/src/react/components/Workspace/components/TabBar/TabBar.tsx @@ -45,8 +45,8 @@ function AddTabButton<_TData>({ }) { const button = (