This pull request introduces improvements to widget customization and UI
consistency in the application. The most notable changes are the
addition of support for icon classes in widget options, updates to
button rendering logic, and enhanced visual consistency for button
components.
Widget customization enhancements:
* Added an optional `iconClass` property to the `IWidgetOptions`
interface in `widgets.ts`, allowing widgets to specify custom icons.
UI and rendering updates:
* Updated `WidgetButton.vue` to render the widget label and, if
provided, an icon using the new `iconClass` option. Also standardized
button styling and label usage.
* Improved button styling in `WidgetRecordAudio.vue` for better visual
consistency with other components.
<img width="662" height="534" alt="Screenshot 2025-11-25 at 01 36 45"
src="https://github.com/user-attachments/assets/43bbe226-07fd-48be-9b98-78b08a726b1b"
/>
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6900-Style-button-widgets-2b66d73d3650818ebeadd9315a47ba0f)
by [Unito](https://www.unito.io)
Updated button widget to support icon display and improved styling to match design system.
- Add icon rendering using widget.options.iconClass
- Update styling to use semantic tokens
- Use widget.label for display instead of widget.name
- Apply consistent button styling with design system tokens
Added programmatic capture button that appears when camera is turned on. The button uses node.addWidget() to integrate with LiteGraph canvas.
- Add captureImage() function to draw video frame to canvas and store in node.imgs
- Add capture button widget in showWidgets() using node.addWidget()
- Create canvas element at module level for efficient reuse
- Widget restoration handled by existing restoreWidgets() cleanup
Add video preview functionality with hover overlay that allows users to:
- Click button to start camera and show live preview
- Hover over video to see stop overlay
- Click anywhere on video to hide preview (keeps camera active)
- Click button again to re-show preview without re-requesting permissions
Uses VueUse's useElementHover for automatic hover detection and proper
MediaStream handling with cleanup on unmount.
Use toRaw() and markRaw() when modifying widget objects to prevent Vue's
reactive proxy from wrapping them. This fixes errors when LiteGraph tries
to access private class members like #value in BaseWidget.
## Summary
Allow the Storybook workflow to run on every PR branch instead of only
`main`.
## Changes
- **What**: remove the `branches: [main]` filter from the Storybook CI
workflow so it triggers for all pull_request events.
## Review Focus
- Confirm broader triggering is desired for all branches while Chromatic
deployment remains restricted to `version-bump-*` or manual runs.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6880-Run-Storybook-CI-on-all-pull-requests-2b56d73d36508169a32afcf50f8e8fd8)
by [Unito](https://www.unito.io)
Co-authored-by: sno <snomiao@gmail.com>
## Summary
- add `data-testid="startup-status-text"` to the status text in
StartupDisplay
- keep the status element targetable for Playwright masks
## Why
Desktop’s Playwright tests mask the troubleshooting version line; this
test id is needed there to keep screenshots stable across releases.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6882-Add-test-id-for-startup-status-text-2b56d73d365081b6a2e4ddca9aa985a4)
by [Unito](https://www.unito.io)
Change to use number prop to fix warnings:
```
WorkflowTemplateSelectorDialog.vue:7 [Vue warn]: Invalid prop: type check failed for prop "tabindex". Expected Number with value 0, got String with value "0".
at <MultiSelect modelValue= [] onUpdate:modelValue=fn class="w-[250px]" ... >
at <MultiSelect modelValue= [] onUpdate:modelValue=fn search-query="" ... >
at <BaseModalLayout content-title="Get Started with a Template" class="workflow-template-selector-dialog" maximized=false >
at <WorkflowTemplateSelectorDialog ref_for=true onClose=fn<hide> maximized=false >
at <BaseTransition onEnter=fn onAfterEnter=fn<bound onAfterEnter> onBeforeLeave=fn<bound onBeforeLeave> ... >
at <Transition name="p-dialog" onEnter=fn<bound onEnter> onAfterEnter=fn<bound onAfterEnter> ... >
at <Portal appendTo="body" >
at <Dialog key="global-workflow-template-selector" visible=true onUpdate:visible=fn<onUpdate:visible> ... >
at <GlobalDialog >
at <App>
```
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6875-fix-tabindex-prop-should-be-number-type-in-MultiSelect-component-2b46d73d3650816d8288fec4cc0f7e7f)
by [Unito](https://www.unito.io)
## Summary
- Fix bug where the "Selected assets count" displayed as 0 in the
Imported tab when selecting assets
## Root Cause
The `getOutputCount` function was returning `0` when
`user_metadata.outputCount` was not present.
- **Generated tab**: Works correctly because `outputCount` metadata is
set during generation
- **Imported tab**: `outputCount` metadata is never set, so it always
returns `0` → selected count shows as 0
## Solution
Changed the default return value from `0` to `1` when `outputCount`
metadata is not present, ensuring every asset counts as at least 1.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Implements a proper Vue toggle widget component and enhances the webcam widget to dynamically show/hide related controls based on camera state, with automatic restoration on component unmount.
## Summary
Fixed an issue where users had to click twice to continue after pasting
a URL in the upload model dialog - once to blur the input, then again to
click the button.
## Changes
- **What**: Replaced `UrlInput` with plain `InputText` in
`UploadModelUrlInput` to emit value immediately on input instead of only
on blur
- **Cleanup**: Moved URL cleaning/normalization to the `fetchMetadata`
handler, removed unused `disableValidation` prop from `UrlInput`
component
## Review Focus
- URL normalization logic in `useUploadModelWizard.ts`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6801-bugfix-Fix-double-click-required-after-pasting-URL-in-upload-model-dialog-2b26d73d3650811881aed0cc064efcc7)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Claude <noreply@anthropic.com>
## Summary
- Removed the `disabled` prop binding from the queue button that was
incorrectly disabling it when there were missing nodes
## Changes
- Removed `:disabled="hasMissingNodes"` from ComfyQueueButton.vue:13
## Test plan
- [x] Verify queue button is no longer incorrectly disabled when there
are missing nodes
- [x] Verify queue functionality works as expected
🤖 Generated with [Claude Code](https://claude.com/claude-code)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6797-fix-disabling-queue-button-2b26d73d3650810783cedd44fce757be)
by [Unito](https://www.unito.io)
## Summary
- replace raw button elements in queue progress overlay UI with shared
IconButton/TextButton/IconTextButton components
- remove forced justify-start from IconTextButton base and add explicit
alignment where needed
- keep queue overlay actions consistent with button styling patterns
## Testing
- pnpm typecheck
- pnpm lint:fix
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-6793-Use-shared-button-components-in-queue-overlay-2b26d73d3650814d9ebfebba74226036)
by [Unito](https://www.unito.io)