Skip to content

Open channel Canvas from the channel menu in a side-pane tab - #570

Open
jameskraus wants to merge 37 commits into
block:mainfrom
jameskraus:canvas-tabs
Open

jameskraus wants to merge 37 commits into
block:mainfrom
jameskraus:canvas-tabs

Conversation

@jameskraus

@jameskraus jameskraus commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

On main, Channel actions → View canvas opens Canvas as a modal over the conversation. This PR makes Canvas a bundled plugin whose menu item opens it as a tab in the side pane, so the conversation stays visible while you edit.

Demo

canvas-tabs-demo.mp4

Recorded at 330c3636e with the browser-test fixture, against a synthetic relay. "Channel actions unavailable" in the menu comes from the fixture.

Behavior

  • Channel actions → View canvas opens Canvas in a side-pane tab. If Canvas is already open, the item selects its tab. Solo chats keep Canvas in Chat settings.
  • Saving keeps Canvas open. Closing the tab returns to the remaining tab.
  • Leaving the channel closes its Canvas tab, because Canvas is bound to its channel and visit (see docs/channels.md). The draft is kept and comes back when you reopen it.
  • Closing Canvas while a save is in flight leaves no stale draft.
  • A slow load never takes focus from the composer. Retry loading and Discard and reload keep focus on their pending button, then hand it to the editor when the read lands, unless focus has moved elsewhere.
  • The item appears only for members of writable, unarchived channels, and only while the Canvas plugin is enabled.
  • Edit, History, conflict handling and restore are unchanged.

Changes

  • src/bundled/canvas. A new buzz.canvas plugin, on by default, registers a channelMenu panel, the same contract Channel Usage uses. It also holds the editor, which is the former channels/ChannelCanvasDialog without its modal wrapper.
  • ChannelHeaderMenu and ChannelsPage. The hardcoded View canvas item and the modal state are gone. Canvas arrives through the menu-panel list the channel menu already receives.
  • crates/plugin-manager. buzz.canvas is in the native catalog and enabled by default.
  • Docs. docs/channels.md and docs/plugin-architecture.md describe View canvas as a menu panel.

Not chosen

  • A header button that opens the tab. Header launchers open their tool's drawer, as Todos and Terminal do. A launcher that opens a tab would need a new hook in the shared tab host, while the menu-panel contract already handles the entry, eligibility, tab and focus.
  • Blocking tab close during a save. Changing channel, browser back/forward, Cmd/Ctrl+W and disabling the plugin can't be blocked. Instead, a save retires its draft when the write lands. replaceView guards that clear, so a newer draft is never lost.

Tests

  • Vitest (canvas/CanvasEditor.test.tsx) covers these cases:
    • Editing continues after a save.
    • A save or restore that lands after close retires its draft. Fails without the fix.
    • A reopened editor's newer draft survives.
    • A slow load leaves focus where the user moved it. Fails without the fix.
    • Retry and confirmed reload keep focus while pending and hand it to the editor, including when the read lands while the confirmation is still closing. Fails without the fix.
  • Rust. native_catalog_matches_desktop_bundles covers the catalog entry.
  • Browser journeys (Chromium and WebKit):
    • Added: channel-tabs.spec.mjs › Canvas opens once beside Thread and retains its channel draft. It needs a browser for the real plugin registration, menu, tab focus and channel switching. It fails on main, where no Canvas tab appears, and passes here.
    • Removed: none.
    • Updated from modal to tab assertions: canvas-history, channel-header-menu and channel-modal-dismissal.

Readiness

Draft. Agent-review findings are addressed. Human testing in the app remains before this can be marked ready.

Known gaps

  • The native desktop build and writes to a live relay are not exercised.
  • Menu-panel items share a generic info icon, so View canvas has no file icon. That is a design call.

jameskraus and others added 18 commits October 1, 2026 17:34
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Keep the Canvas plugin alongside the new pairing and channel-usage
plugins, and keep the optional Canvas menu entry alongside main's
channel-menu panels.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Keep the Canvas plugin alongside main's new Voice Notes and Me plugins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
The desktop bundle list includes buzz.canvas, so the native catalog
must list it and enable it by default to keep the two in parity.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Keep main's pending session recovery in the channel workspace; the
modal Canvas state it sat beside stays removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Canvas only renders inside a workspace tab, so drop the editor's
standalone header and close callback; the tab owns closing. Open Canvas
through the same helper the tab picker uses for other channel tools
instead of a parallel copy.

Also restore main's mention picker test: its focus wait is unrelated to
Canvas and belongs in its own change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Main moved the channel tab workspace into the shared useConversationTabs
hook. Move the Canvas tab wiring with it: the shared tool opener, the
Canvas launcher and its pressed state now live in the hook and return
openCanvas, which both the channel and session-channel header menus use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
jameskraus and others added 3 commits October 13, 2026 11:07
Main removed the side pane's New tab picker and tool tabs. Canvas keeps
opening as a workspace tab: the conversation-tabs hook owns one
openCanvas used by the Canvas launcher and both channel menus, and the
launcher hook keeps its tab-activation callback for that launcher.

The Canvas journey finds thread tabs by their new tab value and opens
Canvas on the session channel from its menu, which has no launchers.
The Todos journey returns to main's version.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Register Canvas as a channel menu panel, like Channel Usage, instead of a
header launcher that opened a tab. Channels then owns the View canvas
item, its eligibility check and the tab, so the hardcoded menu item,
the openCanvas wiring and the launcher-to-tab hook changes go away.
Session-channel menus receive the same channel menu panels, keeping
View canvas there.

A channel change retires the Canvas tab, as docs/channels.md already
describes; the editor keeps the draft, so reopening restores it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
@jameskraus jameskraus changed the title Open channel Canvas in the tabbed workspace Open channel Canvas from the channel menu in a side-pane tab Oct 13, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
jameskraus and others added 4 commits October 13, 2026 15:05
A Canvas tab can now unmount while a save or restore is in flight (tab
close, channel change, plugin disable). The unmount fence then skipped
clearing the stored draft, so reopening reported a false conflict and
disabled Save. Retire the draft once the write lands, using the stored
revision captured when it started, so a reopened editor's newer draft
is never cleared.

Canvas also focused its editor whenever loading finished, pulling focus
back from the composer. Take focus only if it is still where the tab
host placed it when Canvas opened.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
The Canvas plugin owns the editor, so colocate it with the plugin and
its styles. Channels no longer imports from the Canvas plugin; the
plugin depends on Channels' history view and shared styles.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Main removed personal groups from the channel workspace while this
branch removed the Canvas modal state beside them; keep both removals.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
jameskraus and others added 8 commits October 13, 2026 18:32
Main's dialog surfaces are now opaque with no backdrop blur. The Canvas
modal assertions no longer apply; the reload confirmation layer keeps
asserting the shared dialog surface with main's new values.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Keep main's join-preview state in the channel workspace; the Canvas
modal state beside it stays removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Keep main's channel conversion menu entry; the hardcoded Canvas entry
stays removed in favor of the Canvas channel menu panel.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Keep main's shared-sessions route handling beside this branch's shared
channel menu panel list and opener.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
Bundled plugins now carry a description and a discovery category.
Canvas is a productivity tool, like the Canvas-backed Todos plugin.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>
@jameskraus
jameskraus marked this pull request as ready for review October 17, 2026 19:23
@jameskraus
jameskraus requested a review from a team as a code owner October 17, 2026 19:23
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord's automated source review via Wes's account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency), and Groot (product/accessibility) lanes.

Reviewed head 76f2cd5b5bff7b9252614971663672ed865a4b86 against base ad7ac95ce73b44be448d9a1285a72e10d9ee7b37.

8/10 — one P2 recovery-focus defect, detailed inline. The existing menu-panel host, session-owned writes, default-enabled browser/native catalogs, and revision-guarded draft retirement fit the stated scope. No additional actionable findings from the other lanes.

Validation: source inspection only; no tests, builds, app launches, or PR code execution. One hosted-check snapshot showed 34 successes and Windows native validation skipped. Reviewed the added tab journey and migrated component/browser coverage; runtime focus, both themes, narrow/enlarged layouts, native/live-relay behavior, performance, comparative test cost, and human acceptance remain unverified. The public description was inspected, but its single demo video could not be decoded here; attachment-content review is incomplete. This COMMENT is not approval or merge authorization.

Comment thread src/bundled/canvas/CanvasEditor.tsx Outdated

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord's automated source review via Wes's account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency), and Groot (product/accessibility) lanes.

Reviewed merge head 951c212d46e8f31c973d339251107c203887a43c against base 16ca8d3f8e6225d17863302aee45a43aa425553e, following the review at 76f2cd5b5bff7b9252614971663672ed865a4b86.

8/10 — the existing recovery-focus P2 remains; no new merge-integration findings. The Canvas feature patch is identical apart from Git object index lines, and the merge has no conflict-resolution delta. We checked the upstream tab/menu contracts, panel lifetime and draft-write guards. The unchanged Retry/Discard-and-reload behavior still needs the repair already described in the existing inline finding; it is referenced here without a duplicate inline comment.

Validation: immutable source inspection only; no tests, builds, app launches, or PR code execution. One hosted-check snapshot showed 7 successes, 26 checks running, and Windows validation skipped. Runtime focus, native/live-relay behavior, both themes, narrow/enlarged layouts, performance, comparative test cost, and human acceptance remain unverified. The public description and merge message were inspected; the existing demo video could not be decoded here, so attachment-content review remains incomplete. This COMMENT is not approval or merge authorization.

Retry loading and Discard and reload cleared the error as their read
began, which unmounted the focused button and dropped focus to the body.
The recovery button now stays mounted and busy while its read is pending,
then hands focus to the editor once the read lands, unless the user moved
it elsewhere. A failed read leaves focus on the renewed button. The reload
confirmation returns focus to the editor when the read lands while it is
still closing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord's automated source review via Wes's account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency), and Groot (product/accessibility) lanes.

Reviewed head 5a947e3858d11876972062df0029069a6b8a455f against base 16ca8d3f8e6225d17863302aee45a43aa425553e, focusing on the two-file repair since 951c212d46e8f31c973d339251107c203887a43c.

9/10 — no actionable findings in this follow-up. The previous recovery-focus P2 is addressed: Retry/Reload retains a focusable pending button, successful reads hand focus to the editor only when appropriate, failures retain the recovery control, and the confirmation uses the shared moved-focus guard when the read finishes during dialog exit. The new test cases cover delayed reads, repeated failure, moved focus, and dialog-exit ordering. Existing generation fences and keyed panel lifetime remain intact.

Validation: immutable source and test inspection only; no tests, builds, app launches, or PR code execution. One hosted-check snapshot showed 6 successes, 27 checks running, and Windows validation skipped. Real browser/native focus timing, screen-reader behavior, themes/layouts, live-relay behavior, performance, comparative test cost, and human acceptance remain unverified. Public description and follow-up commit inspected with no disclosure finding; its existing demo video could not be decoded here, so attachment-content review remains incomplete. This COMMENT is not approval or merge authorization.

Main's Solo chats replace the session-channel menu with Chat actions and
reach Canvas through Chat settings, so only the channel menu offers View
canvas. The journey drops its session-channel step and keeps the channel
switch that retires the Canvas tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: James Kraus <jamespkraus@gmail.com>

@wesbillman wesbillman left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Star Lord's automated source review via Wes's account, integrating independent Rocket (systems/lifecycle), Mantis (correctness/security/concurrency), and Groot (product/accessibility) lanes.

Reviewed head 330c3636e034383cd2fb09d9762bc5ba6b250835 against base 3d079946e590b56f5560bd816ee0cae7d60cc44e, following the review at 5a947e3858d11876972062df0029069a6b8a455f.

9/10 — no actionable findings in this merge follow-up. Canvas editor and registration source are unchanged from the previously reviewed recovery-focus repair. The current channel menu preserves eligibility checks and panel lifetime; Solo retains Canvas through Chat settings. The updated tab journey reflects that split while retaining channel-switch retirement and draft restoration coverage. No new integration defect was demonstrated.

Validation: immutable source and test inspection only; no tests, builds, app launches, or PR code execution. One hosted-check snapshot was still in progress, with Windows native validation skipped. Browser/native focus timing, screen readers, themes/layouts, live-relay behavior, performance, test-cost comparisons, and human acceptance remain unverified. Public description and merge message inspected with no disclosure finding; the single demo video could not be decoded with available tools, so attachment-content review remains incomplete. This COMMENT is not approval or merge authorization.

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