Skip to content

Refactor: Introduce Modular Workspace Surfaces#1959

Open
justsomelegs wants to merge 9 commits intopingdotgg:mainfrom
justsomelegs:legs/workspace-surface-v2
Open

Refactor: Introduce Modular Workspace Surfaces#1959
justsomelegs wants to merge 9 commits intopingdotgg:mainfrom
justsomelegs:legs/workspace-surface-v2

Conversation

@justsomelegs
Copy link
Copy Markdown
Contributor

@justsomelegs justsomelegs commented Apr 12, 2026

What Changed

This PR replaces the old route-local chat + diff wiring with a real workspace surface system.

Before this branch:

  • the route, ChatView, and diff panel logic all knew too much about each other
  • diff state was a special case spread across multiple files
  • adding another side-panel tool like terminal or git would require more one-off branching

After this branch:

  • workspace state is modeled explicitly as surfaces
  • the secondary panel is route-driven and generic
  • surface behavior is defined in one place instead of being split across catalog/registry/helper switches
  • optimistic panel navigation is centralized and more predictable

Main additions:

  • WorkspaceProvider + WorkspaceShell own workspace state/rendering
  • generic workspace store/reducer for opening/updating/closing surfaces
  • unified surface definition map in workspace/surfaceDefinitions.tsx
  • per-surface modules like:
    • workspace/surfaces/chatSurface.tsx
    • workspace/surfaces/diffSurface.tsx
  • generic panel URL state via workspaceRouteSearch.ts
  • better tests around workspace URL/state transitions

This also rebases the original workspace branch work onto current main and carries forward the route-sync / optimistic-navigation hardening.

Why

We want the app to behave more like a real workspace, not a chat page with one hardcoded special panel.

That matters because we already know more surfaces are coming:

  • git view
  • replacing diff with terminal in the same side panel
  • likely more thread-scoped tools later

The old structure was okay for one special-case diff panel, but it would scale badly. Every new panel/tool would keep adding more route conditionals, more ChatView coupling, and more duplicated “if this panel is open, do X” logic.

This refactor gives us a cleaner extension point now, before terminal/git land.

Concrete benefits

  1. ChatView no longer needs to know route/search-param details for diff.
  2. The route no longer manually composes chat/diff behavior.
  3. Panel state is explicit and testable.
  4. New surfaces can be added by defining a surface module instead of touching scattered switches.

Example: opening a surface

Old mental model:

// route/search-param specific, diff-specific
open diff by mutating route state

New mental model:

openSecondarySurface(
  createTurnDiffSurface(routeThreadRef, turnId, filePath),
  { replace: false },
);

Example: toggling the side panel tool

toggleSecondarySurface(createConversationDiffSurface(threadRef), {
  replace: true,
});

Example: what adding a future surface looks like

A future terminal or git panel would follow the same pattern:

export const gitSurfaceDefinition: WorkspaceSurfaceDefinition<"git"> = {
  id: "git",
  placement: "secondary",
  isEqual: (left, right) => ...,
  isCompatibleWithTarget: (surface, target) => ...,
  render: (surface, renderMode) => <RegisteredGitSurface surface={surface} renderMode={renderMode} />,
  resolveFromSearch: (target, search) => ...,
  serializeToSearch: (surface) => ...,
};

Then register it in one place:

export const workspaceSurfaceDefinitions = {
  chat: chatSurfaceDefinition,
  diff: diffSurfaceDefinition,
  git: gitSurfaceDefinition,
};

That is the main payoff of this PR: the next surface becomes an addition, not another refactor.

URL behavior is now generic
Instead of diff-specific route handling being spread around, panel state is normalized through generic workspace route search:

?panel=diff
?panel=diff&panelTurnId=turn-1&panelFilePath=src/app.ts

That keeps the route model ready for future panel types.

UI Changes

No intentional visual redesign.

User-visible behavior should be the same overall, with the main changes being:

cleaner/safer diff panel routing
more reliable optimistic panel state during navigation
groundwork for future panel replacement (diff -> terminal, etc.)

Checklist

  • This PR is focused on one architectural seam: workspace surface composition/routing
  • I explained what changed and why
  • I included before/after screenshots for any UI changes
  • I included a video for animation/interaction changes

Note

Introduce modular workspace surfaces to manage diff panel state via a store instead of URL params

  • Replaces ad-hoc diff-specific route search params with a generic workspace surface model backed by a Zustand store (workspace/store.ts) and a reducer (workspace/reducer.ts).
  • Adds WorkspaceProvider and WorkspaceShell to both chat thread and draft routes, rendering secondary surfaces (e.g. diff) as a resizable sidebar or sheet depending on viewport.
  • DiffPanel is refactored into a controlled component driven by surface focus props; focus changes propagate back to the workspace via onFocusChange callbacks rather than router navigation.
  • Surface state is still serialized to URL via panel/panelTurnId/panelFilePath search params for shareability, with optimistic transitions reconciled after router sync.
  • Behavioral Change: diff open/close state and turn focus no longer live in diff-specific search params; existing bookmarked diff URLs using the old params will not restore the panel.

Macroscope summarized 22e7b4d.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 12, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 26c5255d-e23e-4a2e-b7e3-8924a94e7185

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions github-actions bot added size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Apr 12, 2026
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp bot commented Apr 12, 2026

Approvability

Verdict: Needs human review

This PR introduces a significant architectural refactor, replacing the existing diff panel routing with a new 'workspace surfaces' abstraction including a zustand store, reducer, surface definitions, and new URL state management. The ~1700 lines of additions create substantial new infrastructure for managing workspace layout and state, warranting human review of the design and implementation.

You can customize Macroscope's approvability policy. Learn more.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL 1,000+ changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant