Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -43,6 +51,8 @@ export function useDashboardSidebarShortcuts(
groups: DashboardSidebarProject[],
) {
const navigate = useNavigate();
const { toggleProjectCollapsed, toggleSectionCollapsed } =
useDashboardSidebarState();
const flattenedWorkspaces = useMemo(
() =>
groups
Expand All @@ -53,14 +63,55 @@ export function useDashboardSidebarShortcuts(
const workspaceShortcutLabels =
useStableWorkspaceShortcutLabels(flattenedWorkspaces);

const workspaceLocations = useMemo(() => {
const map = new Map<string, WorkspaceLocation>();
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));
Expand Down Expand Up @@ -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", () => {
Expand All @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ export function WorkspaceSidebar({
workspaceId,
gitStatus,
onSelectFile: onSelectDiffFile,
onOpenFile: onSelectFile,
});
const changesTab: SidebarTabDefinition = {
...changesTabDef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand All @@ -15,6 +16,7 @@ export const ChangesFileList = memo(function ChangesFileList({
isLoading,
worktreePath,
onSelectFile,
onOpenFile,
onOpenInEditor,
}: ChangesFileListProps) {
if (isLoading) {
Expand All @@ -41,6 +43,7 @@ export const ChangesFileList = memo(function ChangesFileList({
file={file}
worktreePath={worktreePath}
onSelect={onSelectFile}
onOpenFile={onOpenFile}
onOpenInEditor={onOpenInEditor}
/>
))}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand All @@ -33,13 +41,15 @@ interface FileRowProps {
file: ChangesetFile;
worktreePath?: string;
onSelect?: (path: string, openInNewTab?: boolean) => void;
onOpenFile?: (absolutePath: string, openInNewTab?: boolean) => void;
onOpenInEditor?: (path: string) => void;
}

export const FileRow = memo(function FileRow({
file,
worktreePath,
onSelect,
onOpenFile,
onOpenInEditor,
}: FileRowProps) {
const { dir, basename } = splitPath(file.path);
Expand All @@ -52,46 +62,90 @@ export const FileRow = memo(function FileRow({
: undefined;

const rowButton = (
<button
type="button"
className="flex w-full items-center gap-1.5 py-1 pr-3 pl-3 text-left text-xs hover:bg-accent/50"
onClick={(e) => {
const intent = getSidebarClickIntent(e);
if (intent === "openInEditor") {
onOpenInEditor?.(file.path);
} else {
onSelect?.(file.path, intent === "openInNewTab");
}
}}
>
<FileIcon fileName={basename} className="size-3.5 shrink-0" />
<span className="flex min-w-0 flex-1 items-baseline overflow-hidden">
{dir && <span className="truncate text-muted-foreground">{dir}</span>}
{oldBasename && (
<span className="truncate text-muted-foreground">
{oldBasename}
<span className="px-1">→</span>
<div className="group relative">
<button
type="button"
className="flex w-full items-center gap-1.5 py-1 pr-3 pl-3 text-left text-xs hover:bg-accent/50"
onClick={(e) => {
const intent = getSidebarClickIntent(e);
if (intent === "openInEditor") {
onOpenInEditor?.(file.path);
} else {
onSelect?.(file.path, intent === "openInNewTab");
}
}}
>
<FileIcon fileName={basename} className="size-3.5 shrink-0" />
<span className="flex min-w-0 flex-1 items-baseline overflow-hidden">
{dir && <span className="truncate text-muted-foreground">{dir}</span>}
{oldBasename && (
<span className="truncate text-muted-foreground">
{oldBasename}
<span className="px-1">→</span>
</span>
)}
<span className="min-w-[120px] truncate font-medium text-foreground">
{basename}
</span>
)}
<span className="min-w-[120px] truncate font-medium text-foreground">
{basename}
</span>
</span>
<span className="ml-auto flex shrink-0 items-center gap-1.5">
{(file.additions > 0 || file.deletions > 0) && (
<span className="text-[10px] text-muted-foreground">
{file.additions > 0 && (
<span className="text-green-400">+{file.additions}</span>
)}
{file.additions > 0 && file.deletions > 0 && " "}
{file.deletions > 0 && (
<span className="text-red-400">-{file.deletions}</span>
)}
</span>
)}
<StatusIndicator status={file.status} />
</span>
</button>
<span className="ml-auto flex shrink-0 items-center gap-1.5 group-hover:invisible">
{(file.additions > 0 || file.deletions > 0) && (
<span className="text-[10px] text-muted-foreground">
{file.additions > 0 && (
<span className="text-green-400">+{file.additions}</span>
)}
{file.additions > 0 && file.deletions > 0 && " "}
{file.deletions > 0 && (
<span className="text-red-400">-{file.deletions}</span>
)}
</span>
)}
<StatusIndicator status={file.status} />
</span>
</button>
<div className="pointer-events-none absolute inset-y-0 right-2 flex items-center gap-0.5 opacity-0 group-hover:pointer-events-auto group-hover:opacity-100 has-[[data-state=open]]:pointer-events-auto has-[[data-state=open]]:opacity-100">
<DropdownMenu>
<DropdownMenuTrigger asChild>
<button
type="button"
aria-label="More actions"
className="flex size-5 items-center justify-center rounded text-muted-foreground hover:bg-accent hover:text-foreground data-[state=open]:bg-accent data-[state=open]:text-foreground"
onClick={(e) => e.stopPropagation()}
>
<ChevronDown className="size-3.5" />
</button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-56">
<DropdownMenuItem onSelect={() => onSelect?.(file.path)}>
Open Diff
</DropdownMenuItem>
<DropdownMenuItem onSelect={() => onSelect?.(file.path, true)}>
Open Diff in New Tab
<DropdownMenuShortcut>{SHIFT_CLICK_LABEL}</DropdownMenuShortcut>
</DropdownMenuItem>
<DropdownMenuItem
onSelect={() => absolutePath && onOpenFile?.(absolutePath)}
disabled={!onOpenFile || !absolutePath}
>
Open File
</DropdownMenuItem>
<DropdownMenuItem
onSelect={() => absolutePath && onOpenFile?.(absolutePath, true)}
disabled={!onOpenFile || !absolutePath}
>
Open File in New Tab
</DropdownMenuItem>
<DropdownMenuItem
onSelect={() => onOpenInEditor?.(file.path)}
disabled={!onOpenInEditor}
>
Open in Editor
<DropdownMenuShortcut>{MOD_CLICK_LABEL}</DropdownMenuShortcut>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
</div>
</div>
);

return (
Expand All @@ -110,6 +164,18 @@ export const FileRow = memo(function FileRow({
Open Diff in New Tab
<ContextMenuShortcut>{SHIFT_CLICK_LABEL}</ContextMenuShortcut>
</ContextMenuItem>
<ContextMenuItem
onSelect={() => absolutePath && onOpenFile?.(absolutePath)}
disabled={!onOpenFile || !absolutePath}
>
Open File
</ContextMenuItem>
<ContextMenuItem
onSelect={() => absolutePath && onOpenFile?.(absolutePath, true)}
disabled={!onOpenFile || !absolutePath}
>
Open File in New Tab
</ContextMenuItem>
<ContextMenuItem
onSelect={() => onOpenInEditor?.(file.path)}
disabled={!onOpenInEditor}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -44,6 +45,7 @@ export const ChangesTabContent = memo(function ChangesTabContent({
totalDeletions,
worktreePath,
onSelectFile,
onOpenFile,
onOpenInEditor,
onFilterChange,
onBaseBranchChange,
Expand Down Expand Up @@ -92,6 +94,7 @@ export const ChangesTabContent = memo(function ChangesTabContent({
isLoading={isLoading}
worktreePath={worktreePath}
onSelectFile={onSelectFile}
onOpenFile={onOpenFile}
onOpenInEditor={onOpenInEditor}
/>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ interface UseChangesTabParams {
workspaceId: string;
gitStatus: ReturnType<typeof useGitStatus>;
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();
Expand Down Expand Up @@ -192,6 +194,7 @@ export function useChangesTab({
totalDeletions={totalDeletions}
worktreePath={worktreePath}
onSelectFile={onSelectFile}
onOpenFile={onOpenFile}
onOpenInEditor={handleOpenInEditor}
onFilterChange={setFilter}
onBaseBranchChange={setBaseBranch}
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/next.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,12 @@ const config = {
return [
{
source: "/",
destination: "/installation",
destination: "/overview",
permanent: false,
},
{
source: "/docs",
destination: "/installation",
destination: "/overview",
permanent: false,
},
];
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/src/app/sitemap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}));
}
Loading
Loading