Conversation
Linear mode will display an unselected placeholder when first entered. The check for this, was performed by ignoring the selected update event when outputs are first populated, but simply testing for a change from no outputs to some outputs meant that a first generation from clean boot on local would not update selection. This is changed to make the selection state update in the specific case it's going from 0 outputs to 1. Still not ideal, but the edge case of entering linear mode with exactly 1 output in history is of less concern
The popover component fails to autosize properly on mobile. I'm not been able to replicate this behavior with artificially tiny desktop window sizes, but I'm not alone in experiencing this. Rather than relying on the previous workaroound (description is link), the button will now functions as a simple link when on mobile
🎨 Storybook Build Status✅ Build completed successfully! ⏰ Completed at: 01/28/2026, 08:54:34 PM UTC 🔗 Links🎉 Your Storybook is ready for review! |
🎭 Playwright Tests:
|
📝 WalkthroughWalkthroughAdds a mobile collapsible menu and responsive Typeform behavior, enables autofocus on the WorkflowTemplateSelectorDialog search box, switches sidebar tab class binding to use a cn utility, adjusts LinearControls textarea class selectors, and refines OutputHistory watch logic; integrates MobileMenu into LinearView. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant MobileMenu
participant Popover
participant WorkflowsTab
participant Dialog
participant CommandStore
User->>MobileMenu: tap trigger
MobileMenu->>MobileMenu: open CollapsibleRoot
User->>MobileMenu: tap "Workflows" button
MobileMenu->>Popover: open Popover
Popover->>WorkflowsTab: render WorkflowsSidebarTab
User->>MobileMenu: tap "Template selector" button
MobileMenu->>Dialog: useWorkflowTemplateSelectorDialog().show('menu')
User->>MobileMenu: tap "Toggle linear mode" button
MobileMenu->>CommandStore: execute(Comfy.ToggleLinear, { source: 'button' })
Possibly related PRs
Suggested reviewers
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 |
Bundle Size ReportSummary
Category Glance Per-category breakdownApp Entry Points — 25.9 kB (baseline 25.9 kB) • ⚪ 0 BMain entry bundles and manifests
Status: 1 added / 1 removed Graph Workspace — 973 kB (baseline 969 kB) • 🔴 +4.21 kBGraph editor runtime, canvas, workflow orchestration
Status: 1 added / 1 removed Views & Navigation — 80.7 kB (baseline 80.7 kB) • ⚪ 0 BTop-level views, pages, and routed surfaces
Status: 9 added / 9 removed Panels & Settings — 471 kB (baseline 471 kB) • 🟢 -8 BConfiguration panels, inspectors, and settings screens
Status: 12 added / 12 removed User & Accounts — 3.94 kB (baseline 3.94 kB) • ⚪ 0 BAuthentication, profile, and account management bundles
Status: 3 added / 3 removed Editors & Dialogs — 2.89 kB (baseline 2.89 kB) • ⚪ 0 BModals, dialogs, drawers, and in-app editors
Status: 2 added / 2 removed UI Components — 33.7 kB (baseline 33.7 kB) • ⚪ 0 BReusable component library chunks
Status: 6 added / 6 removed Data & Services — 2.7 MB (baseline 2.7 MB) • 🔴 +32 BStores, services, APIs, and repositories
Status: 8 added / 8 removed Utilities & Hooks — 25.3 kB (baseline 25.3 kB) • ⚪ 0 BHelpers, composables, and utility bundles
Status: 7 added / 7 removed Vendor & Third-Party — 10.7 MB (baseline 10.7 MB) • 🔴 +6.86 kBExternal libraries and shared vendor chunks
Status: 1 added / 1 removed Other — 7.05 MB (baseline 7.05 MB) • 🟢 -198 BBundles that do not match a named category
Status: 35 added / 35 removed |
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In `@src/components/ui/TypeformPopoverButton.vue`:
- Around line 22-35: The Button is being wrapped by an anchor when isMobile
which creates nested interactive elements and breaks accessibility; instead
render the Button as an anchor (use the Button's as prop) and move
href/target/rel onto it (add rel="noopener noreferrer") and add an aria-label
using an existing i18n key (replace the non-existent linearMode.feedback with
helpCenter.feedback or add linearMode.feedback to locales); make the same
aria-label present for the Popover button variant, and keep using dataTfWidget
and isMobile to build the URL so no other logic changes are needed.
In `@src/renderer/extensions/linearMode/MobileMenu.vue`:
- Around line 18-20: The menu trigger Button in MobileMenu.vue is icon-only and
lacks an accessible name; add a clear aria-label (e.g., "Open menu" or "Open
navigation menu") to the Button (the <Button> element that currently contains
the <i class="icon-[lucide--menu] ...">) and ensure the icon <i> is marked
decorative (aria-hidden="true") if applicable so screen readers announce the
aria-label instead of the icon.
- Around line 33-49: The template currently calls composables/stores inline
(useWorkflowTemplateSelectorDialog() and useCommandStore().execute(...)) which
causes repeated lookups; hoist these by calling
useWorkflowTemplateSelectorDialog and useCommandStore once in the component
setup, store their returned objects (e.g., templateDialog and commandStore) and
expose wrapper methods (e.g., openTemplateMenu -> templateDialog.show('menu')
and toggleLinear -> commandStore.execute('Comfy.ToggleLinear', { metadata: {
source: 'button' } })) so the template binds to these methods instead of calling
composables inline.
In `@src/renderer/extensions/linearMode/OutputHistory.vue`:
- Around line 159-163: The early return in OutputHistory.vue that checks
newAssets vs oldAssets prevents auto-selection when the list goes from empty to
multiple items; update the logic in the watcher (the block referencing
newAssets, oldAssets, and selectedIndex) to instead set selectedIndex to 0 when
oldAssets.length === 0 and newAssets.length > 0 and selectedIndex indicates
"none" (e.g., -1 or [ -1, 0 ]) so the first output is selected; keep the early
return for the case where lengths are equal to avoid unnecessary work, but
remove the branch that returns when oldAssets.length === 0 && newAssets.length
!== 1 and replace it with a conditional that auto-selects the first item if
nothing is selected.
| <Button variant="secondary" class="size-10 self-end m-4 mb-2"> | ||
| <i class="icon-[lucide--menu] size-8" /> | ||
| </Button> |
There was a problem hiding this comment.
Add an accessible label to the icon-only menu trigger.
Screen readers won’t have a name for this control.
✅ Suggested fix
- <Button variant="secondary" class="size-10 self-end m-4 mb-2">
+ <Button
+ variant="secondary"
+ class="size-10 self-end m-4 mb-2"
+ :aria-label="t('linearMode.openMenu')"
+ >
<i class="icon-[lucide--menu] size-8" />
</Button>Based on learnings, “If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.”
🤖 Prompt for AI Agents
In `@src/renderer/extensions/linearMode/MobileMenu.vue` around lines 18 - 20, The
menu trigger Button in MobileMenu.vue is icon-only and lacks an accessible name;
add a clear aria-label (e.g., "Open menu" or "Open navigation menu") to the
Button (the <Button> element that currently contains the <i
class="icon-[lucide--menu] ...">) and ensure the icon <i> is marked decorative
(aria-hidden="true") if applicable so screen readers announce the aria-label
instead of the icon.
| <Button | ||
| variant="secondary" | ||
| size="lg" | ||
| class="w-full" | ||
| @click="useWorkflowTemplateSelectorDialog().show('menu')" | ||
| > | ||
| <i class="icon-[comfy--template]" /> | ||
| {{ t('sideToolbar.templates') }} | ||
| </Button> | ||
| <Button | ||
| variant="secondary" | ||
| size="lg" | ||
| class="w-full" | ||
| @click=" | ||
| useCommandStore().execute('Comfy.ToggleLinear', { | ||
| metadata: { source: 'button' } | ||
| }) |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Hoist composables/stores out of the template handlers.
This avoids repeated calls and keeps logic centralized.
♻️ Suggested refactor
<script setup lang="ts">
import { useWorkflowTemplateSelectorDialog } from '@/composables/useWorkflowTemplateSelectorDialog'
import { t } from '@/i18n'
import { useCommandStore } from '@/stores/commandStore'
+const workflowTemplateSelectorDialog = useWorkflowTemplateSelectorDialog()
+const commandStore = useCommandStore()
</script>- `@click`="useWorkflowTemplateSelectorDialog().show('menu')"
+ `@click`="workflowTemplateSelectorDialog.show('menu')"- `@click`="
- useCommandStore().execute('Comfy.ToggleLinear', {
- metadata: { source: 'button' }
- })
- "
+ `@click`="
+ commandStore.execute('Comfy.ToggleLinear', {
+ metadata: { source: 'button' }
+ })
+ "📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| <Button | |
| variant="secondary" | |
| size="lg" | |
| class="w-full" | |
| @click="useWorkflowTemplateSelectorDialog().show('menu')" | |
| > | |
| <i class="icon-[comfy--template]" /> | |
| {{ t('sideToolbar.templates') }} | |
| </Button> | |
| <Button | |
| variant="secondary" | |
| size="lg" | |
| class="w-full" | |
| @click=" | |
| useCommandStore().execute('Comfy.ToggleLinear', { | |
| metadata: { source: 'button' } | |
| }) | |
| <Button | |
| variant="secondary" | |
| size="lg" | |
| class="w-full" | |
| `@click`="workflowTemplateSelectorDialog.show('menu')" | |
| > | |
| <i class="icon-[comfy--template]" /> | |
| {{ t('sideToolbar.templates') }} | |
| </Button> | |
| <Button | |
| variant="secondary" | |
| size="lg" | |
| class="w-full" | |
| `@click`=" | |
| commandStore.execute('Comfy.ToggleLinear', { | |
| metadata: { source: 'button' } | |
| }) | |
| " | |
| > |
🤖 Prompt for AI Agents
In `@src/renderer/extensions/linearMode/MobileMenu.vue` around lines 33 - 49, The
template currently calls composables/stores inline
(useWorkflowTemplateSelectorDialog() and useCommandStore().execute(...)) which
causes repeated lookups; hoist these by calling
useWorkflowTemplateSelectorDialog and useCommandStore once in the component
setup, store their returned objects (e.g., templateDialog and commandStore) and
expose wrapper methods (e.g., openTemplateMenu -> templateDialog.show('menu')
and toggleLinear -> commandStore.execute('Comfy.ToggleLinear', { metadata: {
source: 'button' } })) so the template binds to these methods instead of calling
composables inline.
| :href="`https://form.typeform.com/to/${dataTfWidget}`" | ||
| target="_blank" | ||
| > | ||
| <Button variant="inverted" class="rounded-full size-12" v-bind="$attrs"> |
There was a problem hiding this comment.
Option: You could do as='a' to render the button as an anchor. It'd accept the anchor properties too.
There was a problem hiding this comment.
Much better. Thanks.
src/views/LinearView.vue
Outdated
| <div class="border-r border-border-subtle"> | ||
| <ModeToggle class="m-2" /> | ||
| </div> | ||
| <div class="flex-1" /> |
There was a problem hiding this comment.
Alternative: ml-auto on the subsequent element. (I like to limit spacers to cases where I need multiple)
There was a problem hiding this comment.
Agreed (and neat)
There was a problem hiding this comment.
This is pretty close to being a component... 😉
There was a problem hiding this comment.
For collapsible? I think too many of my styling tweaks are specific to this use case and still manage to leave some usability problems half solved. I'd rather return to this after I've had more time to think things over.
There was a problem hiding this comment.
For a collapsible menu. I agree with your instincts.
|
I love the screenshots, thanks <3 |
And an unrelated tweak requested by Comfy: when opening templates, the searchbar is autofocused.
┆Issue is synchronized with this Notion page by Unito