Phase 7 slice 4b: archive surface + canvas lifecycle UI actions#26
Merged
Conversation
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.
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
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
/archive./archiveroute +renderArchivePage0.78), full-saturate on hover — visual "this isn't part of active work" cue.canvas_archivehint.Detail-page toolbar
.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/archivePOST /api/canvas/:id/unarchiveDELETE /api/canvas/:idThin wrappers over
scene-graph.archiveCanvas/unarchiveCanvas/deleteCanvas. The underlying functions were already covered bytest-workspace-mcp-tools.ts; the endpoints just expose them to the viewer's JS.renderSidebarsignatureParameter renamed
activeProjectId→active. 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 buildcleannpx tsx test-archive-view.ts— 27/27 pass:canvas.archived, Delete always present, lifecycleAction handler defined, Back link goes to canvas's projectcanvas_deleteWhat'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.pngas a side-effect.