Skip to content

Group contract workspace rail into Read / Negotiate / History modes#177

Merged
zgbrenner merged 1 commit into
mainfrom
refactor/workspace-mode-tabs
May 17, 2026
Merged

Group contract workspace rail into Read / Negotiate / History modes#177
zgbrenner merged 1 commit into
mainfrom
refactor/workspace-mode-tabs

Conversation

@zgbrenner
Copy link
Copy Markdown
Owner

Summary

The contract workspace's right rail had six flat sub-tabs (Metadata, Clauses, Review, Lifecycle, Signers, History) that mixed three different user intents into one undifferentiated row — what is this contract, what's happening to it, what happened to it. The audit called this out as "mode confusion."

This adds a top-level mode row above the existing sub-tabs:

Mode Sub-tabs Intent
Read (default) Metadata, Clauses What this contract IS
Negotiate Review, Lifecycle, Signers What's happening to it
History History What happened to it

Default mode is Read, so the workspace opens on the lightest view — metadata + clauses, no in-flight workflow noise.

How it works

Mode is derived from activeTab via a TAB_TO_MODE map, so existing call sites that already do setActiveTab("review"), setActiveTab("signers"), setActiveTab("history") (lifecycle action buttons, overflow menu Send-to-DocuSeal shortcut, gate-remediation checklist, etc.) automatically switch into the right mode without extra coordination.

Clicking a mode tab lands on that mode's first sub-tab (Read → Metadata, Negotiate → Review, History → History). Clicking a mode tab while already in that mode is a no-op.

What landed

New

  • components/WorkspaceModeTabs.tsx — primary mode tab bar (role=tablist), visually heavier than the sub-tab row so it's clear which row is the primary selector.
  • components/__tests__/WorkspaceModeTabs.test.tsx — 4 specs.

Modified

  • pages/ContractWorkspacePage.tsx:
    • Adds WorkspaceMode type + MODE_SUB_TABS and TAB_TO_MODE maps next to the existing SidebarTab type.
    • Sidebar renders <WorkspaceModeTabs> above <RightPanelTabs>, with the sub-tab list filtered to the active mode.
    • handleModeChange picks the first sub-tab of the target mode.

Test updates

  • ContractWorkspacePage.test.tsx:
    • "renders a two-pane layout … all six tabs" → "… with mode tabs and contextual sub-tabs": now asserts the three mode tabs are always present, Read mode shows only Metadata + Clauses (Signers is not in the DOM), Negotiate reveals Review/Lifecycle/Signers and hides the Read tabs, History mode shows the History sub-tab + panel.
    • Two blocked-gate tests that previously did fireEvent.click(getByRole("tab", { name: /signers/i })) now switch to Negotiate first via the mode tab.

Test plan

  • npx vitest run — 1161 passing (+4 from the new mode-tabs spec).
  • npx tsc -b clean.
  • npm run build succeeds; lazy Nango chunk untouched at 11.71 KB; main bundle +1 KB for the mode-tabs component.
  • ruff check . clean (no backend changes).
  • Manual: open a contract, confirm default lands on Read → Metadata. Click each mode tab and verify the sub-tabs change. Use the lifecycle action buttons (which call setActiveTab directly) and confirm the mode tab updates alongside the sub-tab.
  • Manual: trigger Send to DocuSeal via the overflow menu — it should switch to Negotiate → Signers.

Follow-ups (not in this PR)

  • Per-mode counts on the mode tabs themselves (e.g. "Negotiate (3)" when there's a blocking finding) — currently only sub-tabs carry counts.
  • Persisting mode in the URL (?mode=negotiate&tab=signers) so a deep link can land directly in a specific mode-tab combo. Today the URL controls only the contract id.
  • Keyboard arrow-key navigation across mode tabs (the WAI-ARIA tabs pattern).

Generated by Claude Code

The right rail had six flat sub-tabs (Metadata, Clauses, Review,
Lifecycle, Signers, History) that mixed "what is this contract"
(read), "what's happening to it" (negotiate), and "what happened
to it" (versions/history) into one row. Six undifferentiated
options + no signal about which one to use → mode confusion.

This adds a top-level mode row above the sub-tabs:
  - Read       → Metadata, Clauses
  - Negotiate  → Review, Lifecycle, Signers
  - History    → History

The mode is derived from the active sub-tab, so any existing caller
that does ``setActiveTab("review")`` / ``setActiveTab("signers")``
/ ``setActiveTab("history")`` (lifecycle action buttons, the
overflow menu's Send-to-DocuSeal shortcut, the gate remediation
checklist, etc.) automatically switches into the right mode without
extra coordination. Clicking a mode tab lands on that mode's first
sub-tab (Read → Metadata, Negotiate → Review, History → History).

Default mode is Read so the workspace opens on the lightest view —
just metadata and clauses, no in-flight workflow noise.

New ``WorkspaceModeTabs`` component (with role=tablist + role=tab)
sits above the existing ``RightPanelTabs``, which now receives a
filtered sub-tab list driven by the active mode. The two rows are
visually distinct so it's clear which is the primary selector.

Tests:
- New ``WorkspaceModeTabs.test.tsx`` (4 specs): labels, aria-selected
  state, onChange dispatch, tablist semantics.
- Existing workspace test "renders a two-pane layout … all six tabs"
  rewritten to "… with mode tabs and contextual sub-tabs": asserts
  the three mode tabs are present, Read mode shows only Metadata
  + Clauses (Signers is *not* in the DOM), switching to Negotiate
  reveals Review/Lifecycle/Signers and hides Metadata/Clauses, and
  History mode shows the History sub-tab + panel.
- Two blocked-gate tests that previously did
  ``fireEvent.click(getByRole("tab", { name: /signers/i }))`` now
  switch to Negotiate first via the mode tab.

1161 frontend tests passing, build clean. Main bundle +1 KB for
the mode-tabs component; lazy Nango chunk untouched.
@cloudflare-workers-and-pages
Copy link
Copy Markdown

Deploying whereas with  Cloudflare Pages  Cloudflare Pages

Latest commit: 83b2efa
Status: ✅  Deploy successful!
Preview URL: https://62ef0dd6.whereas.pages.dev
Branch Preview URL: https://refactor-workspace-mode-tabs.whereas.pages.dev

View logs

@zgbrenner zgbrenner marked this pull request as ready for review May 17, 2026 18:12
@zgbrenner zgbrenner merged commit 334de28 into main May 17, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants