Skip to content

Phase 7 slice 4b: archive surface + canvas lifecycle UI actions#26

Merged
vicmaster merged 1 commit into
masterfrom
feat/phase7-archive-surface
May 16, 2026
Merged

Phase 7 slice 4b: archive surface + canvas lifecycle UI actions#26
vicmaster merged 1 commit into
masterfrom
feat/phase7-archive-surface

Conversation

@vicmaster
Copy link
Copy Markdown
Owner

Summary

The slice 2 archive flag has been invisible to viewer users since it shipped — surfacing it now closes that gap. Plus, all lifecycle operations (archive / unarchive / permanent-delete) become reachable from the viewer without an MCP client.

What lands

Sidebar

  • New Archive entry below all workspaces, separated by a hairline.
  • Cross-project archived-count badge; active state when on /archive.
  • Folder-with-line SVG icon, visually distinct from project rows.

/archive route + renderArchivePage

  • Cross-project listing of every archived canvas.
  • Each card shows the source project name (since archive spans projects) and the timestamp it was archived.
  • Slightly faded card opacity (0.78), full-saturate on hover — visual "this isn't part of active work" cue.
  • Restore + Delete buttons overlay top-right of each card, fade in on hover. Delete prompts to confirm — irreversible.
  • Empty state when nothing is archived, with a canvas_archive hint.

Detail-page toolbar

  • Archive button when canvas is active; Restore button when archived (mutually exclusive).
  • Delete button always present, styled with a red hover (.btn--danger).
  • lifecycleAction() handler hits the JSON API and bounces back to /project/<canvas.projectId> on success. Delete confirms first.

Lifecycle API endpoints

  • POST /api/canvas/:id/archive
  • POST /api/canvas/:id/unarchive
  • DELETE /api/canvas/:id

Thin wrappers over scene-graph.archiveCanvas / unarchiveCanvas / deleteCanvas. The underlying functions were already covered by test-workspace-mcp-tools.ts; the endpoints just expose them to the viewer's JS.

renderSidebar signature

Parameter renamed activeProjectIdactive. Pass a project ID for project pages or the literal string 'archive' for the archive page. Project IDs are nanoids, so 'archive' is unambiguous.

Test plan

  • npm run build clean
  • npx tsx test-archive-view.ts27/27 pass:
    • Sidebar archive entry on project pages: link, count, not-active state
    • Archive page: title/meta, active-state on archive entry, contains only archived canvases, each card shows correct source project name, both Restore + Delete buttons per card
    • Archive empty state shows the right message + canvas_archive hint
    • Detail page: Archive/Restore buttons toggle correctly based on canvas.archived, Delete always present, lifecycleAction handler defined, Back link goes to canvas's project
    • Sidebar archive count drops dynamically after canvas_delete
  • All 13 existing smokes + benchmark still pass — no regression on PRs Phase 5: responsive hint API + renderer mapping (items #1+#2) #6–25

What's next

Slice 5 (premium UI refresh) is the last Phase 7 piece. Per earlier plan, slice 5 will be dogfooded — I'll mock the new chrome inside canvas-mcp itself first, then implement against the mock. Produces a docs/viewer-refresh-mock.png as a side-effect.

The slice 2 archive flag has been invisible to viewer users since it
shipped — surfacing it now closes that gap. Plus, all lifecycle
operations (archive / unarchive / permanent-delete) become reachable
without an MCP client.

What lands:

Sidebar
  - New "Archive" entry below all workspaces, with cross-project
    archived-count badge. Active state when on /archive. Folder-with-
    line SVG icon for visual distinction from project rows.

/archive route + renderArchivePage
  - Cross-project listing of every archived canvas.
  - Each card shows the source project name (since archive spans
    projects) and the timestamp it was archived.
  - Slightly faded card opacity, full-saturate on hover — visual
    "this isn't part of active work" cue without going overboard.
  - Restore + Delete buttons overlay the top-right of each card,
    fade in on hover. Delete prompts to confirm — irreversible.
  - Empty state when nothing is archived, with a canvas_archive hint.

Detail-page toolbar
  - Archive button when canvas is active; Restore button when archived
    (mutually exclusive). Delete button always present, styled with a
    red hover state (.btn--danger).
  - lifecycleAction() handler hits the JSON API and bounces back to
    /project/<canvas.projectId> on success. Delete confirms first.

Lifecycle API endpoints
  - POST /api/canvas/:id/archive
  - POST /api/canvas/:id/unarchive
  - DELETE /api/canvas/:id
  Thin wrappers around scene-graph.archiveCanvas / unarchiveCanvas /
  deleteCanvas (already covered by test-workspace-mcp-tools.ts).

renderSidebar signature
  - Parameter renamed activeProjectId → active. Pass a projectId for
    project pages or the literal string 'archive' for the archive
    page. Project IDs are nanoids, so 'archive' is unambiguous.

test-archive-view.ts — 27/27 pass:
  - Project page: archive sidebar entry, link, count, not-active state
  - Archive page: title/meta, active-state on archive entry, contains
    only archived canvases, each card shows correct source project
    name and has both Restore + Delete buttons
  - Empty-state when no archived canvases
  - Detail page: Archive/Restore buttons toggle correctly based on
    canvas.archived, Delete always present, lifecycleAction handler
    defined, Back link still goes to canvas's project
  - Sidebar count drops to 0 after canvas_delete

All 13 existing smokes + benchmark still pass.

Slice 5 (premium UI refresh) is the last Phase 7 piece. Per earlier
plan, slice 5 will be dogfooded by mocking the new chrome inside
canvas-mcp itself first.
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.

1 participant