diff --git a/frontend/src/lib/components/sessions/SessionPicker.svelte b/frontend/src/lib/components/sessions/SessionPicker.svelte index 7e8283e406..898a97739b 100644 --- a/frontend/src/lib/components/sessions/SessionPicker.svelte +++ b/frontend/src/lib/components/sessions/SessionPicker.svelte @@ -60,7 +60,7 @@ import MenuButton, { sidebarClasses } from '$lib/components/sidebar/MenuButton.svelte' import DropdownV2 from '$lib/components/DropdownV2.svelte' import { isGlobalAiEnabled } from '$lib/components/copilot/chat/global/gate' - import { userWorkspaces, workspaceStore } from '$lib/stores' + import { userStore, userWorkspaces, workspaceStore } from '$lib/stores' import { workspaceIsFork } from '$lib/utils/workspaceHierarchy' import { WorkspaceService } from '$lib/gen' import { sendUserToast } from '$lib/toast' @@ -220,7 +220,7 @@ // Workspace tree scoped to the current family (root + its forks), so the rail // only shows the workspaces in the family we're in — not every workspace. const workspaceTreeItems = $derived.by(() => { - const all = buildWorkspaceHierarchy($userWorkspaces) + const all = buildWorkspaceHierarchy($userWorkspaces, $userStore?.email) const currentRoot = $currentWorkspaceRootId if (!currentRoot) return all return all.filter((i) => workspaceRootId(i.workspace.id, $userWorkspaces) === currentRoot) diff --git a/frontend/src/lib/components/sessions/WorkspaceFamilyPicker.svelte b/frontend/src/lib/components/sessions/WorkspaceFamilyPicker.svelte index f5b7e8d34f..09fed8bba6 100644 --- a/frontend/src/lib/components/sessions/WorkspaceFamilyPicker.svelte +++ b/frontend/src/lib/components/sessions/WorkspaceFamilyPicker.svelte @@ -10,11 +10,11 @@ type UserWorkspace } from '$lib/stores' import { - findWorkspaceDescendants, findCanonicalDevWorkspace, findDefaultForkBase, findWorkspaceRoot, - buildWorkspaceHierarchy + buildWorkspaceHierarchy, + workspaceSubtreeRows } from '$lib/utils/workspaceHierarchy' import { useForkableWorkspaces } from '$lib/utils/useForkableWorkspaces.svelte' import { canCreateFork } from '$lib/utils/editInFork' @@ -102,7 +102,11 @@ }) const forkableWorkspaces = $derived(forkableWorkspacesProp ?? ownForkable.current) const root = $derived(findWorkspaceRoot(effectiveId, forkableWorkspaces)) - const forks = $derived(root ? findWorkspaceDescendants(root.id, forkableWorkspaces) : []) + // The same hierarchy the sidebar workspace menu builds: forks of forks follow their parent, and the + // user's own forks lead each group of siblings. + const hierarchy = $derived(buildWorkspaceHierarchy(forkableWorkspaces, $userStore?.email)) + const forkRows = $derived(root ? workspaceSubtreeRows(root.id, hierarchy) : []) + const forks = $derived(forkRows.map((h) => h.workspace)) // The family's canonical dev workspace, if any — still used for gating (a forking-locked root can be // forked via its dev) and as a selectable base with a "dev" badge. @@ -126,13 +130,10 @@ })) ) - // Depth of each workspace within its family (root = 0, its forks = 1, forks of forks = 2, …), from - // the shared hierarchy builder — the same one the sidebar workspace menu uses — so the list indents - // forks of forks under their parent the same way. `forks` is a DFS of descendants (parent before - // child), so indenting each row by its depth nests it under its parent. - const familyDepths = $derived( - new Map(buildWorkspaceHierarchy(forkableWorkspaces).map((h) => [h.workspace.id, h.depth])) - ) + // Depth of each workspace within its family (root = 0, its forks = 1, forks of forks = 2, …). + // `forks` is a DFS (parent before child), so indenting each row by its depth nests it under its + // parent, the same way the sidebar menu does. + const familyDepths = $derived(new Map(hierarchy.map((h) => [h.workspace.id, h.depth]))) // Extra left padding (on top of the row's base px-3) to nest a workspace one step per depth level, // matching the sidebar menu's `depth * 16px`. function indentStyle(id: string): string | undefined { @@ -429,9 +430,16 @@ /> {/if} - {#each forks as f, fi (f.id)} + {#each forkRows as { workspace: f, separatorBefore }, fi (f.id)} {@const forkIdx = (root ? 1 : 0) + fi} {@const accentStyle = forkAccentStyle(f.color)} + {#if separatorBefore} + + {/if}