feat(workspaces): groups#153
Merged
Merged
Conversation
Adds user-defined sections for organizing open workspaces. Sections are collapsible, draggable, and persist across sessions. Workspaces can be moved into/out of sections via context menu. - New `WorkspacePanelSection` type and `sections`/`sectionOrder`/ `workspaceSections` fields on `AppState` with full persistence - 8 new mutation functions: `createSection`, `renameSection`, `deleteSection`, `reorderSections`, `moveWorkspaceToSection`, `removeWorkspaceFromSection`, `reorderWorkspaceInSection`, `toggleSectionCollapsed` - "New Section…" entry in the workspace add menu (via `ctx.ui.prompt`) - Section drag-and-drop reordering; workspace DnD within sections - Workspace context menu: "Move to Section ▶" / "Remove from Section" - 49 unit tests covering all new state operations and persistence - Fix path-flicker on workspace switch: `homeDir()` resolved once at module level so `WorkspacesPanel` remounts (caused by column layout changes) don't restart the async load and briefly show the raw absolute path Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Sections can now be assigned an accent color via a new Properties modal (replaces the old Rename prompt). A colored section renders as a unified card — tinted header background, matching border, and colored title text — with transparency levels that adapt to light and dark themes. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ingle-source membership Pre-work cleanup before adding group drag-and-drop, so the feature lands as small additions rather than surgery on a tangled component. - Rename the collapsible-grouping concept "section" -> "group" across state, host, panel, CSS, and user-visible strings (New/Move to/Remove from/Delete Group, Group Properties). Resolves the collision with the SDK's unrelated WorkspaceSectionProvider (extension-contributed row content), which is left untouched. - Extract all panel drag-and-drop into a pure, unit-tested model (workspace-dnd.ts: typed drop intents + resolvers) plus a thin useWorkspaceDnd hook. WorkspacesPanel becomes presentational (571 -> 429 lines); the DnD decision logic gains 21 tests where it had none. - Collapse the three-source membership model: a group's workspaceOrder is now the single source of truth; the workspace->group reverse map is derived (groupIdForWorkspace / workspaceGroupMap), no longer stored or persisted. - ADR 0023: record that panel groups are host-internal (core.* only), a deliberate, reversible exception to the "expose via ctx" default. Typecheck, lint, and tests green (extension-host 454, extensions-core 109). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…panel Make the Workspaces panel a single interleaved, fully drag-reorderable list: groups and ungrouped workspaces share one top-level order, so a group can be dragged anywhere (including above loose workspaces), and workspaces can be dragged into a group, out of a group, and reordered — with clear drop lines. - State: add `panelOrder`, the interleaved top-level order (ungrouped workspace ids + group ids); `workspaceOrder` stays as the public-service registry order. New mutators `reorderPanel` / `ungroupWorkspace`; `moveWorkspaceToGroup` gains a positional anchor. Membership stays single-sourced on each group's `workspaceOrder` (reverse map derived, never stored). `reconcilePanelOrder` self-heals the order on load so a partial/pre-panelOrder index can't hide an entry. - DnD: pure decision model (`workspace-dnd.ts`) — one shared `panelDropForEntity` rule behind top-level rows, three-zone group cards (edge = adjacent, middle = into), and a position-aware background catch-all (drop at the beginning/end). Thin `useWorkspaceDnd` hook holds the React state and dispatches intents; precedence is by DOM specificity via stopPropagation. - Fix the real drag blocker: `enterRegionOnPointer` (click-to-enter focus) was `preventDefault`-ing mousedown on draggable elements, which cancels the native drag. It now leaves draggable elements alone. - CSS: the panel body fills the pane and carries the end-drop zone; top padding gives the "before first" line room; group header uses grid (WebKit won't start a drag from a draggable flex container when a child is grabbed). - ADR 0023 updated for the interleaved model. Unit-tested throughout (pure state mutators + pure DnD resolvers + `reconcilePanelOrder`); typecheck, lint, and tests green (extension-host 461, extensions-core 120). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…nav, panel polish Round of refinements on the workspaces panel groups: - Share the group properties modal between creating and editing a group, so a color can be picked at creation time (openNewGroup + create/edit mode via the pure resolveGroupProps helper); drop the plain name prompt. - Add a second, theme-relative greyscale swatch row: neutrals mix the theme's ink into its background so they invert automatically (lighter on dark themes via a per-theme --ws-group-neutral-ink), offset one column from the hues. - Restore arrow-key navigation across the interleaved list: the roving focus group now spans group headers plus every rendered workspace (extracted to the pure, tested buildNavItems); Enter toggles a group or activates a workspace. - Add top spacing above an ungrouped workspace that follows a group. - Remove the workspace-row tooltips (name/folder/close) that broke during drag. - Drop the separator between "New workspace…" and "New Group…". - Fix the double focus outline on the group name input (rely on the shared focus-visible ring) and document the rule in CLAUDE.md. Also runs prettier over pre-existing unformatted files on the branch to fix the failing format:check CI step. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
WorkspacesPanelto remount, resettinghomeDirstate and briefly showing the raw absolute path instead of the tilde-substituted versionWhat's new
State layer (
packages/extension-host/src/state/)WorkspacePanelSectiontype andsections/sectionOrder/workspaceSectionsfields onAppStatecreateSection,renameSection,deleteSection,reorderSections,moveWorkspaceToSection,removeWorkspaceFromSection,reorderWorkspaceInSection,toggleSectionCollapsedPersistedIndex/buildIndex/hydrate/doPersistdeleteWorkspacenow cleans up section membershipUI (
packages/extensions-core/src/workspaces/)ctx.ui.prompt)FrontTruncatedPath: extracted compute logic to a puretruncatePath()helper; addeduseLayoutEffectfor synchronous before-paint measurement (eliminates the flash of the full untruncated path thatuseEffectalone produced)homeDir()resolved once at module level viauseSyncExternalStoreinstead of per-componentuseState— survives remountsTest plan
pnpm testpasses (49 new section tests + 5 new persistence-model tests)pnpm --filter silo exec tsc --noEmitclean🤖 Generated with Claude Code