feat: Compact Mode toggle for Nodes 2.0 (read-only app view)#11846
feat: Compact Mode toggle for Nodes 2.0 (read-only app view)#11846Nynxz wants to merge 6 commits intoComfy-Org:mainfrom
Conversation
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (16)
✅ Files skipped from review due to trivial changes (8)
🚧 Files skipped from review as they are similar to previous changes (6)
📝 WalkthroughWalkthroughAdds a compact-mode feature: new Pinia store, a toggle command and menu item, UI layout/size and interaction gates across Vue node components, and prevention of canvas operations (move, group, paste, delete, convert) while compact mode is enabled. ChangesCompact Mode
Sequence Diagram(s)sequenceDiagram
participant User
participant WorkflowMenu
participant CommandRegistry
participant CompactStore
participant Renderer
User->>WorkflowMenu: click "Toggle Compact Mode"
WorkflowMenu->>CommandRegistry: execute("Comfy.ToggleCompactMode")
CommandRegistry->>CompactStore: toggle() / set(isCompactMode)
alt entering compact
CommandRegistry->>CommandRegistry: savedLinkRenderMode = current Comfy.LinkRenderMode
CommandRegistry->>Renderer: set Comfy.LinkRenderMode = LiteGraph.HIDDEN_LINK
else exiting compact
CommandRegistry->>Renderer: if links hidden -> restore savedLinkRenderMode
CommandRegistry->>CompactStore: savedLinkRenderMode = null
end
CompactStore->>Renderer: UI & interaction layers read isCompactMode and update behavior
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~35 minutes
🚥 Pre-merge checks | ✅ 6 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (6 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. 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. Comment |
🎭 Playwright: ⏳ Running... |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (1)
src/renderer/extensions/vueNodes/components/NodeFooter.test.ts (1)
46-49: ⚡ Quick winAdd at least one compact-mode assertion here.
This helper now bootstraps Pinia, but the suite still exercises only the pre-compact branches. A regression where compact mode re-shows the subgraph/advanced footer, or accidentally hides the error footer, would pass unnoticed.
As per coding guidelines, "Write tests for all changes, especially bug fixes to catch future regressions".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/renderer/extensions/vueNodes/components/NodeFooter.test.ts` around lines 46 - 49, The tests never exercise compact mode; update the NodeFooter tests by adding at least one assertion that uses the existing helper renderFooter to render NodeFooter in compact mode (e.g., call renderFooter({ compact: true }) using the Props/baseProps helper) and assert the compact behavior: verify the subgraph/advanced footer elements are not rendered and the error footer (the error message/footer element) still appears. Use the existing renderFooter, NodeFooter, Props and baseProps symbols to locate where to add the new compact-mode assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/composables/useCoreCommands.ts`:
- Around line 94-95: Compact mode currently still permits the
"Comfy.ClearWorkflow" command (and other listed command handlers) even though
the UI should be read-only; update the command registration logic in
useCoreCommands (where compactModeStore is read) to check
compactModeStore.isCompact (or the existing compact mode flag) and prevent
registration/execution of destructive commands like Comfy.ClearWorkflow, as well
as the other handlers noted (lines ~111-121, 599-621, 904-916, 927-941,
1038-1045). Specifically, wrap or gate the command callbacks (or return early
from the command executor) so when compact mode is active they no-op and
optionally log/notify the user, ensuring the command registry for
useCoreCommands refuses to perform clear/delete/paste actions while compact mode
is true.
- Around line 1362-1383: The toggle command captures savedLinkRenderMode only on
entry which can stale and overwrite user changes made while compact mode is
active; update the exit path in the Comfy.ToggleCompactMode command to read the
current value via settingStore.get('Comfy.LinkRenderMode') and only call
settingStore.set('Comfy.LinkRenderMode', savedLinkRenderMode) when the current
value === LiteGraph.HIDDEN_LINK and savedLinkRenderMode != null; in the other
case simply clear savedLinkRenderMode (set to null) and do not overwrite the
current setting, and ensure savedLinkRenderMode is cleared after any restore or
skip so subsequent toggles behave correctly.
In `@src/composables/useWorkflowActionsMenu.ts`:
- Around line 225-238: The menu item 'toggle-compact-mode' is currently visible
for any non-linear workflow but should only show when Vue Nodes (Nodes 2.0) is
enabled; update the addItem call to include the Vue-nodes feature flag in its
visibility predicate (e.g., change visible: !isLinearMode to visible:
!isLinearMode && <nodes-2-flag>), using the existing store/flag that indicates
Vue Nodes (for example nodesStore.isVueNodesEnabled or isNodes2Enabled); also
ensure the command handler (commandStore.execute('Comfy.ToggleCompactMode'))
remains unchanged but will never be reachable when the flag is false so legacy
canvas users cannot enter the half-enabled compact state.
---
Nitpick comments:
In `@src/renderer/extensions/vueNodes/components/NodeFooter.test.ts`:
- Around line 46-49: The tests never exercise compact mode; update the
NodeFooter tests by adding at least one assertion that uses the existing helper
renderFooter to render NodeFooter in compact mode (e.g., call renderFooter({
compact: true }) using the Props/baseProps helper) and assert the compact
behavior: verify the subgraph/advanced footer elements are not rendered and the
error footer (the error message/footer element) still appears. Use the existing
renderFooter, NodeFooter, Props and baseProps symbols to locate where to add the
new compact-mode assertion.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 031b67ce-5aa5-4dd5-a35e-514968ea2916
📒 Files selected for processing (15)
src/composables/useCoreCommands.tssrc/composables/useWorkflowActionsMenu.tssrc/locales/en/main.jsonsrc/renderer/extensions/vueNodes/components/ImagePreview.vuesrc/renderer/extensions/vueNodes/components/LGraphNode.vuesrc/renderer/extensions/vueNodes/components/NodeFooter.test.tssrc/renderer/extensions/vueNodes/components/NodeFooter.vuesrc/renderer/extensions/vueNodes/components/NodeSlots.vuesrc/renderer/extensions/vueNodes/components/NodeWidgets.vuesrc/renderer/extensions/vueNodes/components/OutputSlot.vuesrc/renderer/extensions/vueNodes/components/SlotConnectionDot.vuesrc/renderer/extensions/vueNodes/composables/useSlotLinkInteraction.tssrc/renderer/extensions/vueNodes/layout/useNodeDrag.tssrc/stores/compactModeStore.test.tssrc/stores/compactModeStore.ts
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/composables/useWorkflowActionsMenu.test.ts (1)
389-406: ⚡ Quick winNew tests cover the key visibility predicate; consider adding a linear-mode guard test.
The enabled/disabled VueNodes cases are well covered. The third branch of
visible: !isLinearMode && isVueNodesEnabled— hiding the item whenisLinearModeis true — has no dedicated test. The fix toprependSeparatorsuggested above also isn't covered here.💡 Suggested additional test (optional)
it('hides the Compact Mode item when in linear (app) mode', () => { mockWorkflowStore.activeWorkflow = { path: 'test.json', isPersisted: true, activeMode: 'app' } as ComfyWorkflow const { menuItems } = useWorkflowActionsMenu(vi.fn(), { isRoot: true }) const labels = menuLabels(menuItems.value) expect(labels).not.toContain('breadcrumbsMenu.enterCompactMode') expect(labels).not.toContain('breadcrumbsMenu.exitCompactMode') })🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/composables/useWorkflowActionsMenu.test.ts` around lines 389 - 406, Add a test that verifies the Compact Mode item is hidden when the workflow is in linear/app mode: set mockWorkflowStore.activeWorkflow with activeMode: 'app' (and other required fields), call useWorkflowActionsMenu(vi.fn(), { isRoot: true }), compute menuLabels(menuItems.value) and assert it does not contain 'breadcrumbsMenu.enterCompactMode' or 'breadcrumbsMenu.exitCompactMode'; also add a short test covering the prependSeparator behavior (using useWorkflowActionsMenu and menuLabels) to ensure the separator is not inserted incorrectly for the first menu item (reference prependSeparator in the code under test).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/composables/useWorkflowActionsMenu.ts`:
- Around line 229-242: The double separator happens because both addItem calls
(the one with id 'enter-app-mode' and this one with id 'toggle-compact-mode')
set prependSeparator: true; change the prependSeparator on the
'toggle-compact-mode' addItem to be conditional so it only adds a separator when
no app-mode item precedes it (e.g. prependSeparator: !showAppModeItems), leaving
the rest of the command logic (ensureWorkflowActive(targetWorkflow.value) and
commandStore.execute('Comfy.ToggleCompactMode')) unchanged.
---
Nitpick comments:
In `@src/composables/useWorkflowActionsMenu.test.ts`:
- Around line 389-406: Add a test that verifies the Compact Mode item is hidden
when the workflow is in linear/app mode: set mockWorkflowStore.activeWorkflow
with activeMode: 'app' (and other required fields), call
useWorkflowActionsMenu(vi.fn(), { isRoot: true }), compute
menuLabels(menuItems.value) and assert it does not contain
'breadcrumbsMenu.enterCompactMode' or 'breadcrumbsMenu.exitCompactMode'; also
add a short test covering the prependSeparator behavior (using
useWorkflowActionsMenu and menuLabels) to ensure the separator is not inserted
incorrectly for the first menu item (reference prependSeparator in the code
under test).
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 016df3ae-9e33-450f-a6a6-66db8c1344a2
📒 Files selected for processing (4)
src/composables/useCoreCommands.tssrc/composables/useWorkflowActionsMenu.test.tssrc/composables/useWorkflowActionsMenu.tssrc/stores/compactModeStore.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/stores/compactModeStore.ts
- src/composables/useCoreCommands.ts
…flow menu item Introduces a transient global Pinia store for a "compact mode" view toggle. The toggle hides graph links via Comfy.LinkRenderMode while active and restores the previous render mode on exit. Adds a menu item to the workflow actions dropdown next to "Enter app mode". Compact mode is intended as a read-only "view" of the graph for using workflows as apps; this commit only wires up the toggle plumbing — read-only enforcement and visual compaction land in follow-up commits.
Adds compact-mode guards across the Vue layer and command store so structural mutations are suppressed while compact mode is on: - Vue node drag (useNodeDrag.startDrag) - Slot link drag / new connection (useSlotLinkInteraction.onPointerDown) - Node resize handles (LGraphNode.handleResizePointerDown) - Right-click context menu (LGraphNode.handleContextMenu) - Graph-mutating commands: Delete, Paste, PasteWithConnect, MoveSelectedNodes (4 directions), GroupSelectedNodes, ConvertToSubgraph Widget interaction, selection, pan, and zoom remain functional so the graph can still be used as a "running app" while structurally locked.
Reshapes nodes for a clean "app view" while compact mode is active: - Hide node header (NodeHeader) and node badges (NodeBadges) - Hide slot rows entirely in node body (canvas links also hidden via Comfy.LinkRenderMode flip in the toggle command) - Slim slot dot wrapper (size-3) + output slot row height (h-3) - Pass dot-only to NodeSlots so widget-linked inputs render without text labels - Compact NodeFooter padding/heights, hide subgraph-enter and advanced buttons (errors still surface), full-rounding when no header above - Body padding switches to symmetric py-4 with rounded top corners so the body matches the outer node shape when no header sits on top - Progress bar repositions to a slim track-and-fill at the top edge of the body in compact mode (avoids overlapping widgets) - Hide image dimensions text under output previews - Hide widget hover-revealed slot dot and resize handles in corners
Adds a capture-phase listener on the node container so ctrl/cmd+click on output nodes runs Comfy.QueueSelectedOutputNodes regardless of where on the node was clicked. Capture phase is required because some widgets (e.g. ImageCompare) bind their own pointer handlers that consume the event before it bubbles up to the node-level handler. Capturing on both pointerdown and click ensures the modifier-click is intercepted on widgets, the body, and borders consistently. Selecting the clicked node first then dispatching the existing queue-selected-output-nodes command keeps the execution path identical to the manual select-then-run flow.
…+ link restore) - Toggle command now restores Comfy.LinkRenderMode only when it is still LiteGraph.HIDDEN_LINK on exit. If the user explicitly toggled link visibility while compact mode was on (e.g. via Comfy.Canvas.ToggleLinkVisibility), honor their choice instead of overwriting it with the saved value. - savedLinkRenderMode moves into useCompactModeStore as a ref so the command no longer needs an IIFE/closure to hold private state. The command stays in charge of side effects (settingStore + LiteGraph); the store stays free of heavy imports. - Workflow actions menu item is now gated on Comfy.VueNodes.Enabled in addition to !isLinearMode. Compact mode only meaningfully transforms Nodes 2.0; without the flag the legacy renderer would land in a half-applied state (commands guarded, but visuals unchanged). Add two unit tests asserting visibility flips with the flag, plus a useSettingStore mock so the test imports load cleanly. Did not guard Comfy.ClearWorkflow — it already requires the user to confirm a dialog, which is a stronger safeguard than a silent no-op. Other destructive commands (Delete, Paste, Move-selected, Group, ConvertToSubgraph) remain guarded since they fire from keybinds with no confirmation.
The Compact Mode menu item unconditionally set prependSeparator: true, which produced two consecutive separators when an app-mode item above it (enter-app-mode / exit-app-mode) had already pushed one. Gate the separator on !showAppModeItems so it only renders when no app-mode item provided one above.

Summary
Opt-in "compact mode" toggle for Nodes 2.0 that turns the graph into a read-only app-style surface. Widgets stay interactive; node moves, link drags, resize, delete, and other structural mutations are locked. Visual chrome (headers, slot rows, links, badges, footer buttons) is hidden so workflows can be driven without accidentally rearranging them.
Changes
useCompactModeStore+Comfy.ToggleCompactModecommand, also added to the workflow actions dropdown.Comfy.LinkRenderMode(saved on enter, restored on exit). Progress bar repositions to a slim track at the top edge.Comfy.QueueSelectedOutputNodes. Capture-phase listener so it triggers even on widgets that consume their own pointer events (e.g., ImageCompare).Review Focus
state.readOnly. That flag forcespointer-events: noneon Vue nodes viashouldHandleNodePointerEvents, which would break widget interaction. Compact mode keeps pointer events live and adds explicit guards instead.Comfy.LinkRenderModein a closure and restores on exit. IfComfy.Canvas.ToggleLinkVisibilityis invoked while compact is on, the saved value goes stale. Happy to read fresh on exit if preferred.pointerdownandclickso widget pointer handlers don't swallow it.Screenshots
Compact Mode
Regular Mode
Workflow Actions Menu (where the toggle lives)
┆Issue is synchronized with this Notion page by Unito