## Summary
Replace legacy `SearchBox` (PrimeVue) and `SearchBoxV2` with the unified
`SearchInput` (reka-ui) component across all consumers.
## Changes
- **What**: Remove `SearchBox.vue`, `SearchBoxV2.vue`, their tests and
stories. Migrate all 14 consumers to `SearchInput`. Move layout classes
to `ComboboxRoot` for proper flex sizing. Extract filter button/chips in
`NodeLibrarySidebarTab`. Standardize modal search width to `flex-1
max-w-lg`.
- **Dependencies**: None new — `SearchInput` already existed using
reka-ui
## Review Focus
- `NodeLibrarySidebarTab.vue`: filter button and `SearchFilterChip`
rendering moved outside the search component
- `SearchInput.vue`: `className` now applied to `ComboboxRoot` instead
of `ComboboxAnchor` for correct flex layout
- Modal dialogs (`WorkflowTemplateSelectorDialog`, `AssetBrowserModal`,
`SampleModelSelector`) unified to `flex-1 max-w-lg`
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9644-feat-unify-search-components-by-replacing-SearchBox-SearchBoxV2-with-SearchInput-31e6d73d365081ebac55cb265f33b631)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: github-actions <github-actions@github.com>
## Summary
Fix virtual scroll pagination not triggering in media asset panel list
view.
## Changes
**What**: `VirtualGrid` in `AssetsSidebarListView` was missing
`maxColumns=1` and had an incorrect default item height (200px vs actual
~48px). Without `maxColumns`, `cols` was calculated as
`floor(containerWidth / 200)` (e.g. 2), causing the row count to be
halved and `isNearEnd` to never fire correctly. Added `:max-columns="1"`
and `:default-item-height="48"` to fix pagination. Added regression
tests to `VirtualGrid.test.ts`.
## Review Focus
The root cause: `VirtualGrid.cols` computed as `floor(width/200)`
instead of `1` for single-column list layout, breaking spacer heights
and `approach-end` detection.
Test covers both the fix (approach-end fires with maxColumns=1) and the
bug reproduction (does not fire without it).
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9646-fix-virtual-scroll-pagination-not-working-in-media-asset-list-view-31e6d73d3650813d973ad19638ad6933)
by [Unito](https://www.unito.io)
## Problem
Output assets in the assets panel show content hashes (e.g.,
`a1b2c3d4.png`) instead of display names (e.g., `ComfyUI_00001_.png`).
## Root Cause
Cloud inference replaces `filename` with the content hash in the output
transform pipeline. The hashed filename gets stored in the jobs table's
`preview_output` JSONB. The frontend uses this hash as the display name.
## Solution
- Add `display_name` field to `AssetItem` schema and `ResultItemImpl`
- Backend (cloud PR) joins job→assets table to resolve the original name
and injects `display_name` into job responses
- Frontend prefers `display_name` over `name` **only for display text
and download filenames**
- `asset.name` remains unchanged (the hash) for URLs, drag-to-canvas,
export filters, and output key dedup
## Backwards Compatible
- OSS: `display_name` is undefined, falls back to `asset.name` (which is
already the real filename in OSS)
- Cloud pre-deploy: `display_name` absent from API, falls back
gracefully
- Old jobs with no assets: `display_name` not injected, no change
## Cloud PR
https://github.com/Comfy-Org/cloud/pull/2747https://github.com/user-attachments/assets/8a4c9cac-4ade-4ea2-9a70-9af240a56602
## Summary
Additional fixes and updates based on testing
## Changes
- **What**:
- add warning to welcome screen & when sharing an app that has had all
outputs removed
- fix target workflow when changing mode via tab right click menu
- change build app text to be conditional "edit" vs "build" depending on
if an app is already defined
- update empty apps sidebar tab button text to make it clearer
- remove templates button from app mode (we will reintroduce this once
we have app templates)
- add "exit to graph" after applying default mode of node graph
- update cancel button to remove item from queue if it hasn't started
yet
- improve scoping of jobs/outputs to the current workflow [not perfect
but should be much improved]
- close sidebar tabs on entering app mode
- change tooltip to be under the workflow menu rather than covering the
button
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9511-feat-fix-App-mode-QA-feedback-2-31b6d73d365081d59bbbc13111100d46)
by [Unito](https://www.unito.io)
## Summary
Enable `better-tailwindcss/enforce-consistent-class-order` lint rule and
auto-fix all 1027 violations across 263 files. Stacked on #9427.
## Changes
- **What**: Sort Tailwind classes into consistent order via `eslint
--fix`
- Enable `enforce-consistent-class-order` as `'error'` in eslint config
- Purely cosmetic reordering — no behavioral or visual changes
## Review Focus
Mechanical auto-fix PR — all changes are class reordering only. This is
the largest diff but lowest risk since it changes no class names, only
their order.
**Stack:** #9417 → #9427 → **this PR**
Fixes#9300 (partial — 3 of 3 rules)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9428-fix-enable-enforce-consistent-class-order-tailwind-lint-rule-31a6d73d3650811c9065f5178ba3e724)
by [Unito](https://www.unito.io)
## Summary
Enable `better-tailwindcss/enforce-canonical-classes` lint rule and
auto-fix all 611 violations across 173 files. Stacked on #9417.
## Changes
- **What**: Simplify Tailwind classes to canonical forms via `eslint
--fix`:
- `h-X w-X` → `size-X`
- `overflow-x-hidden overflow-y-hidden` → `overflow-hidden`
- and other canonical simplifications
- Enable `enforce-canonical-classes` as `'error'` in eslint config
## Review Focus
Mechanical auto-fix PR — all changes produced by `eslint --fix`. No
visual or behavioral changes; canonical forms are functionally
identical.
**Stack:** #9417 → **this PR** → PR 3 (class order)
Fixes#9300 (partial — 2 of 3 rules)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9427-fix-enable-enforce-canonical-classes-tailwind-lint-rule-31a6d73d365081a49340d7d4640ede45)
by [Unito](https://www.unito.io)
## Summary
Enable `better-tailwindcss/no-deprecated-classes` lint rule and auto-fix
all 103 violations across 65 files. First PR in a stacked series for
#9300.
## Changes
- **What**: Replace deprecated Tailwind v3 classes with v4 equivalents:
- `rounded` → `rounded-sm` (85)
- `flex-shrink-0` → `shrink-0` (16)
- `flex-grow` → `grow` (2)
- Enable `no-deprecated-classes` as `'error'` in eslint config
- Update one test asserting on `'rounded'` class string
## Review Focus
Mechanical auto-fix PR — all changes produced by `eslint --fix`. No
visual or behavioral changes (Tailwind v4 aliases these classes
identically).
Fixes#9300 (partial — 1 of 3 rules)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9417-fix-enable-no-deprecated-classes-tailwind-lint-rule-31a6d73d3650819eaef4cf8ad84fb186)
by [Unito](https://www.unito.io)
Co-authored-by: Alexander Brown <drjkl@comfy.org>
## Summary
Change app mode changes to be written directly to the workflow on change
instead of requiring explicit save via builder.
Temporary: Adds `.app.json` file extension to app files for
identification since we don't currently have a way to identify them with
metadata
Removes app builder save dialog and replaces it with default mode
selection
## Changes
- **What**:
- ensure all save locations handle app mode
- remove dirtyLinearData and flushing
- **Breaking**:
- if people are relying on workflow names and are converting to/from app
mode in the same workflow, they will gain/lose the `.app` part of the
extension
## Screenshots (if applicable)
<img width="689" height="84" alt="image"
src="https://github.com/user-attachments/assets/335596ee-dce9-4e3a-a7b5-f0715c294e41"
/>
<img width="421" height="324" alt="image"
src="https://github.com/user-attachments/assets/ad3cd33c-e9f0-4c30-8874-d4507892fc6b"
/>
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9338-feat-App-mode-saving-rework-3176d73d3650813f9ae1f6c5a234da8c)
by [Unito](https://www.unito.io)
## Summary
Implement 11 Figma design discrepancies for the Node Library sidebar and
V2 Node Search dialog, aligning the UI with the [Toolbox Figma
design](https://www.figma.com/design/xMFxCziXJe6Denz4dpDGTq/Toolbox?node-id=2074-21394&m=dev).
## Changes
- **What**: Sidebar: reorder tabs (All/Essentials/Blueprints), rename
Custom→Blueprints, uppercase section headers, chevron-left of folder
icon, bookmark-on-hover for node rows, filter dropdown with checkbox
items, sort labels (Categorized/A-Z) with label-left/check-right layout,
hide section headers in A-Z mode. Search dialog: expand filter chips
from 3→6, add Recents and source categories to sidebar, remove "Filter
by" label. Pull foundation V2 components from merged PR #8548.
- **Dependencies**: Depends on #8987 (V2 Node Search) and #8548
(NodeLibrarySidebarTabV2)
## Review Focus
- Filter dropdown (`filterOptions`) is UI-scaffolded but not yet wired
to filtering logic (pending V2 integration)
- "Recents" category currently returns frequency-based results as
placeholder until a usage-tracking store is implemented
- Pre-existing type errors from V2 PR dependencies not in the base
commit (SearchBoxV2, usePerTabState, TextTicker, getProviderIcon,
getLinkTypeColor, SidebarContainerKey) are expected and will resolve
when rebased onto main after parent PRs land
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9085-feat-Node-Library-sidebar-and-V2-Search-dialog-Figma-design-improvements-30f6d73d36508175bf72d716f5904476)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Yourz <crazilou@vip.qq.com>
Co-authored-by: github-actions <github-actions@github.com>
## Summary
- fix sizing of sidebars in app mode
- update feedback button to match design
- update job queue notification
- clickable queue spinner item to allow clear queue
- refactor mode out of store to specific workflow instance
- support different saved vs active mode
- other styling/layout tweaks
## Changes
- **What**: Changes the store to a composable and moves the mode state
to the workflow.
- This enables switching between tabs and maintaining the mode they were
in
## Screenshots (if applicable)
<img width="1866" height="1455" alt="image"
src="https://github.com/user-attachments/assets/f9a8cd36-181f-4948-b48c-dd27bd9127cf"
/>
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9137-App-mode-more-updates-fixes-3106d73d365081a18ccff6ffe24fdec7)
by [Unito](https://www.unito.io)
---------
Co-authored-by: github-actions <github-actions@github.com>
## Summary
- emit `preview-click` from `AssetsListItem` when clicking the preview
tile
- wire assets sidebar rows and queue job-history rows so preview-tile
click and row double-click open the viewer/gallery
- gate job-history preview opening by `taskRef.previewOutput` (not
`iconImageUrl`) and use preview output URL/type so video previews are
supported
- add/extend tests for preview click and double-click behavior in assets
list and job history
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9077-fix-open-previewable-assets-from-list-preview-click-double-click-30f6d73d3650810a873cfa2dc085bf97)
by [Unito](https://www.unito.io)
## Summary
Remove Tailwind `@apply` from Vue styles across `src/` and
`apps/desktop-ui/src/` to align with Tailwind v4 guidance, replacing
usages with template utilities or native CSS while preserving behavior.
## Changes
- **What**:
- Batch 1: migrated low-risk template/style utility bundles out of
`@apply`.
- Batch 2: converted PrimeVue/`:deep()` override `@apply` blocks to
native CSS declarations.
- Batch 3: converted `src/components/node/NodeHelpContent.vue` markdown
styling from `@apply` to native CSS/token-based declarations.
- Batch 4: converted final desktop pseudo-element `@apply` styles and
removed stale `@reference` directives no longer required.
- Verified `rg -n "^\s*@apply\b" src apps -g "*.vue"` has no real CSS
`@apply` directives remaining (only known template false-positive event
binding in `NodeSearchContent.vue`).
## Review Focus
- Visual parity in components that previously depended on `@apply` in
`:deep()` selectors and markdown content:
- topbar tabs/popovers, dialogs, breadcrumb, terminal overrides
- desktop install/dialog/update/maintenance surfaces
- node help markdown rendering
- Confirm no regressions from removal of now-unneeded `@reference`
directives.
## Screenshots (if applicable)
- No new screenshots included in this PR.
- Screenshot Playwright suite was run with `--grep="@screenshot"` and
reports baseline diffs in this environment (164 passed, 39 failed, 3
skipped) plus a teardown `EPERM` restore error on local path
`C:\Users\DrJKL\ComfyUI\LTXV\user`.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9146-fix-eradicate-tailwind-apply-usage-in-vue-styles-3116d73d3650813d8642e0bada13df32)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
## Summary
Add frontend-only display name mappings for nodes shown in the
Essentials tab, plus parse the new `essentials_category` field from the
backend.
## Changes
- **What**: Created `src/constants/essentialsDisplayNames.ts` with a
static mapping of node names to user-friendly display names (e.g.
`CLIPTextEncode` → "Text", `ImageScale` → "Resize Image"). Regular nodes
use exact name matching; blueprint nodes use prefix matching since their
filenames include model-specific suffixes. Integrated into
`NodeLibrarySidebarTab.vue`'s `renderedRoot` computed for leaf node
labels with fallback to `display_name`. Added `essentials_category`
(z.string().optional()) to the node def schema and `ComfyNodeDefImpl` to
parse the field already sent by the backend (PR #12357).
## Review Focus
Display names are resolved only in the Essentials tab tree view
(`NodeLibrarySidebarTab.vue`), not globally, to avoid side effects on
search, bookmarks, or other views. Blueprint prefix matching is ordered
longest-first so more specific prefixes (e.g. `image_inpainting_`) match
before shorter ones (e.g. `image_edit`).
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9072-feat-add-display-name-mappings-for-Essentials-tab-nodes-30f6d73d3650817c9acdc9b0315ed0be)
by [Unito](https://www.unito.io)
## Summary
Prevent text/other assets from opening a blank fullscreen viewer by
restricting inspect/zoom to previewable media kinds.
## Changes
- Add `isPreviewableMediaType` helper in shared `formatUtil`.
- Gate inspect/zoom actions in `AssetsSidebarTab`, `MediaAssetCard`, and
`MediaAssetContextMenu` using an allowlist (`image`, `video`, `audio`,
`3D`).
- Build gallery items from previewable assets only.
- Add unit tests for `isPreviewableMediaType`.
## Why
`ResultGallery` only renders image/video/audio; text/other assets could
previously enter fullscreen with no renderable content.
## Review Focus
- Verify text/other assets no longer show Inspect and do not open
fullscreen.
- Verify image/video/audio behavior is unchanged.
- Verify 3D still opens the 3D viewer dialog.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8989-fix-disable-inspect-for-non-previewable-assets-30c6d73d36508103a9b9da4fe50236ea)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Align generated-asset state classification to a single shared source and
implement the missing text/misc states in both card and list previews.
## Changes
- **What**:
- Extended `getMediaTypeFromFilename` in
`packages/shared-frontend-utils` to return `text` and `other`, and
changed unknown/no-extension fallback from `image` to `other`.
- Added text extension handling (`txt`, `md`, `json`, `csv`, `yaml/yml`,
`xml`, `log`) and kept existing media kinds.
- Updated generated-assets UI to use shared media-type detection
directly (removed the local generated-assets classifier).
- Added text and misc card preview components:
- `text` -> `icon-[lucide--text]`
- `other` -> `icon-[lucide--check-check]`
- Updated list-item preview behavior so only `image`/`video` use preview
media URLs; `text`/`other` use icon fallback.
- Widened media kind schema for asset display metadata to include `text`
and `other`.
- **Breaking**: No API breaking changes; internal media kind union
widened for frontend asset display paths.
- **Dependencies**: None.
## Review Focus
- Verify generated text assets render paragraph/text icon state in card
+ list.
- Verify unknown/misc assets consistently render double-check icon state
in card + list.
- Verify existing image/video/audio/3D behavior remains unchanged.
## Screenshots (if applicable)
<img width="282" height="158" alt="image"
src="https://github.com/user-attachments/assets/76cf2d1b-9d34-4c7c-92a1-50bbc55871e5"
/>
<img width="432" height="489" alt="image"
src="https://github.com/user-attachments/assets/024fece3-f241-484d-a37e-11948559ebbc"
/>
<img width="421" height="494" alt="image"
src="https://github.com/user-attachments/assets/ed64ba0c-bf46-4c3b-996e-4bc613ee029e"
/>
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8914-fix-support-text-and-misc-generated-asset-states-3096d73d365081f28ca7c32f306e4b50)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com>
Co-authored-by: GitHub Action <action@github.com>
## Summary
Render generated video previews in list items using a real video element (instead of an image element (this caused errors before)) and include a custom play button with dimming per [the designs](https://www.figma.com/design/LVilZgHGk5RwWOkVN6yCEK/Queue-Progress-Modal?node-id=3928-39270&m=dev).
## Changes
- **What**:
- List item preview path now renders a `video` element when `isVideoPreview` is true.
- Video list preview uses `preload="metadata"`, `muted`, `playsinline`, and `pointer-events-none` so row click behavior stays unchanged.
- Kept the custom overlay/play affordance and increased overlay dimming from `bg-black/10` to `bg-black/15`.
- Updated tests for `AssetsListItem`, `MediaVideoTop`, and `AssetsSidebarListView`.
## Review Focus
- Confirm list item click behavior still opens/selects asset (no inline playback interaction).
- Confirm video list previews now show actual video frame path instead of broken image fallback.
## Limitation
Backend does not currently provide a dedicated poster/thumbnail image for video outputs in the job preview payload. In the frontend today, we can either show a video icon placeholder, or load/render the full video itself to obtain a preview frame.
## Screenshots (if applicable)
<img width="427" height="499" alt="image" src="https://github.com/user-attachments/assets/3f974817-9d73-4fee-9fa5-2f1f68942c06" />
<img width="230" height="92" alt="image" src="https://github.com/user-attachments/assets/1fbfdd6a-72dd-47e2-96bf-8f7eb41c36f2" />
## Summary
Move queue job history into a dedicated sidebar tab (gated by `Comfy.Queue.QPOV2`) and remove mixed job-history UI from the Assets sidebar so assets and job controls are separated.
## Changes
- **What**:
- Added `JobHistorySidebarTab` with reusable job UI primitives: `JobFilterTabs`, `JobFilterActions`, `JobAssetsList`, and shared `JobHistoryActionsMenu`.
- Added reactive `job-history` tab registration in `sidebarTabStore`; prepends above Assets when `Comfy.Queue.QPOV2` is enabled and unregisters cleanly when disabled.
- Added debounced search to `useJobList` (filters by job title, metadata, and prompt id).
- Extracted clear-history dialog logic to `useQueueClearHistoryDialog` and reused it from queue overlay and job history tab.
- Removed active-job rendering and queue-clear controls from assets list/grid/tab views; assets sidebar now focuses on media assets only.
- Removed the QPOV2 gate from `MediaAssetViewModeToggle` and updated queue/job localized copy.
- Added and updated tests for queue overlay header actions, job filters, search filtering, sidebar tab registration, and assets sidebar behavior.
## Review Focus
- Verify QPOV2 toggle behavior:
- `Docked Job History` menu action toggles `Comfy.Queue.QPOV2`.
- `job-history` tab insertion/removal order and active-tab reset on removal.
- Verify behavior split between tabs:
- Job controls (cancel/delete/view/filter/search/clear history/clear queue) live in Job History.
- Assets sidebar loading/empty states and list/grid rendering remain correct after removing active jobs.
## Screenshots (if applicable)
<img width="670" height="707" alt="image" src="https://github.com/user-attachments/assets/3a201fcb-d104-4e95-b5fe-49c4006a30a5" />
Planning to keep updates smaller and more contained in the interest of
collaboration and velocity
- The breadcrumb hamburger menu that provides workflow options is now
displayed in linear mode
- As part of this change, the reka-ui popover component now accepts
primvevue format MenuItems
- I prefer the format I had, but this makes transitioning stuff easier.
- The simplified linear history is moved to always be horizontal and
shown beneath previews.
- The label has been removed from the "Give Feedback" button on desktop
so it does not overlap
- The full side toolbar is displayed in linear mode
- This is temporary, but it gets the dead code pruned out now.
- Lays some groundwork for selecting an asset from the assets panel to
also select the item in the main linear panel
- The api `promptQueued` event can now optionally include a promptIds,
which list the ids for all jobs that were queued together as part of
that batch
- Update the max for the `number of generations` field to respect the
recently updated cloud limits
| Before | After |
| ------ | ----- |
| <img width="360" alt="before"
src="https://github.com/user-attachments/assets/e632679c-d727-4882-841b-09e99a2f81a4"
/> | <img width="360" alt="after"
src="https://github.com/user-attachments/assets/a9bcd809-c314-49bd-a479-2448d1a88456"/>|
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8853-Linear-mode-arrangement-tweaks-3066d73d365081589355ef753513900b)
by [Unito](https://www.unito.io)
## Summary
Rename all internal TypeScript usage of legacy `promptId`/`PromptId`
naming to `jobId`/`JobId` across ~38 files for consistency with the
domain model.
## Changes
- **What**: Renamed internal variable names, type aliases, function
names, class getters, interface fields, and comments from
`promptId`/`PromptId` to `jobId`/`JobId`. Wire-protocol field names
(`prompt_id` in Zod schemas and `e.detail.prompt_id` accesses) are
intentionally preserved since they match the backend API contract.
## Review Focus
- All changes are pure renames with no behavioral changes
- Wire-protocol fields (`prompt_id`) are deliberately unchanged to
maintain backend compatibility
- Test fixtures updated to use consistent `job-id` naming
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8730-refactor-rename-internal-promptId-PromptId-to-jobId-JobId-3016d73d3650813ca40ce337f7c5271a)
by [Unito](https://www.unito.io)
## Description
When clicking a multi-output job to enter folder view,
`resolveOutputAssetItems` fetches job details asynchronously. During
this fetch, the panel showed "No generated files found" because there
was no loading state for the folder resolution—only the media list fetch
had one.
This replaces the empty state flash with skeleton cards that match the
asset grid layout, using the known output count from metadata to render
the correct number of placeholders.
Supersedes #8960.
### Changes
- **Add shadcn/vue `Skeleton` component**
(`src/components/ui/skeleton/Skeleton.vue`)
- **Use `useAsyncState`** from VueUse to track folder asset resolution,
providing `isLoading` automatically
- **Wire `folderLoading`** into `showLoadingState` and `showEmptyState`
computeds
- **Replace `ProgressSpinner`** with a skeleton grid that mirrors the
asset card layout
- **Use `metadata.outputCount`** to predict skeleton count; falls back
to 6
### Before / After
| Before | After |
|--------|-------|
| "No generated files found" flash | Skeleton cards matching grid layout
|
## Checklist
- [x] Code follows project conventions
- [x] No `any` types introduced
- [x] Lint and typecheck pass
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8979-fix-show-skeleton-loading-state-in-asset-folder-view-30c6d73d365081fa9809f616204ed234)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
## Summary
- Add `typescript/no-explicit-any` rule to `.oxlintrc.json` to enforce
no explicit `any` types
- Fix all 40 instances of explicit `any` throughout the codebase
- Improve type safety with proper TypeScript types
## Changes Made
### Configuration
- Added `typescript/no-explicit-any` rule to `.oxlintrc.json`
### Type Fixes
- Replaced `any` with `unknown` for truly unknown types
- Updated generic type parameters to use `unknown` defaults instead of
`any`
- Fixed method `this` parameters to avoid variance issues
- Updated component props to match new generic types
- Fixed test mocks to use proper type assertions
### Key Files Modified
- `src/types/treeExplorerTypes.ts`: Updated TreeExplorerNode interface
generics
- `src/platform/settings/types.ts`: Fixed SettingParams generic default
- `src/lib/litegraph/src/LGraph.ts`: Fixed ParamsArray type constraint
- `src/extensions/core/electronAdapter.ts`: Fixed onChange callbacks
- `src/views/GraphView.vue`: Added proper type imports
- Multiple test files: Fixed type assertions and mocks
## Test Plan
- [x] All lint checks pass (`pnpm lint`)
- [x] TypeScript compilation succeeds (`pnpm typecheck`)
- [x] Pre-commit hooks pass
- [x] No regression in functionality
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8601-feat-add-typescript-no-explicit-any-rule-and-fix-all-instances-2fd6d73d365081fd9beef75d5a6daf5b)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Alexander Brown <drjkl@comfy.org>
## Summary
Replace all runtime `isElectron()` function calls with the build-time
`isDesktop` constant from `@/platform/distribution/types`, enabling
dead-code elimination in non-desktop builds.
## Changes
- **What**: Migrate 30 files from runtime `isElectron()` detection
(checking `window.electronAPI`) to the compile-time `isDesktop` constant
(driven by `__DISTRIBUTION__` Vite define). Remove `isElectron` from
`envUtil.ts`. Update `isNativeWindow()` to use `isDesktop`. Guard
`electronAPI()` calls behind `isDesktop` checks in stores. Update 7 test
files to use `vi.hoisted` + getter mock pattern for per-test `isDesktop`
toggling. Add `DISTRIBUTION=desktop` to `dev:electron` script.
## Review Focus
- The `electronDownloadStore.ts` now guards the top-level
`electronAPI()` call behind `isDesktop` to prevent crashes on
non-desktop builds.
- Test mocking pattern uses `vi.hoisted` with a getter to allow per-test
toggling of the `isDesktop` value.
- Pre-existing issues not addressed: `as ElectronAPI` cast in
`envUtil.ts`, `:class="[]"` in `BaseViewTemplate.vue`,
`@ts-expect-error` in `ModelLibrarySidebarTab.vue`.
- This subsumes PR #8627 and renders PR #6122 and PR #7374 obsolete.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8710-refactor-replace-runtime-isElectron-with-build-time-isDesktop-constant-3006d73d365081c08037f0e61c2f6c77)
by [Unito](https://www.unito.io)
## Summary
Fix all i18n `no-restricted-imports` lint warnings and upgrade rules
from `warn` to `error`.
## Changes
- **What**: Migrate Vue components from `import { t/d } from '@/i18n'`
to `const { t } = useI18n()`. Migrate non-component `.ts` files from
`useI18n()` to `import { t/d } from '@/i18n'`. Allow `st` import from
`@/i18n` in Vue components (it wraps `te`/`t` for safe fallback
translation). Remove `@deprecated` tag from `i18n.ts` global exports
(still used by `st` and non-component code). Upgrade both lint rules
from `warn` to `error`.
## Review Focus
- The `st` helper is intentionally excluded from the Vue component
restriction since it provides safe fallback translation needed for
custom node definitions.
Fixes#8701
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8704-fix-resolve-i18n-no-restricted-imports-lint-warnings-2ff6d73d365081ae84d8eb0dfef24323)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Amp <amp@ampcode.com>
## Summary
Replace the manager button puzzle icon with a custom extensions-blocks
SVG icon and add a "Manage Extensions" text label to the top bar button.
## Changes
- **What**: Swap `icon-[lucide--puzzle]` →
`icon-[comfy--extensions-blocks]` in TopMenuSection, ComfyMenuButton,
and ManagerDialog. Add visible "Manage Extensions" label (hidden below
md). Align tooltip with new label text.
## Review Focus
- Visual appearance of the new icon at different sizes
- Button layout with text label at md+ breakpoints
- Red dot notification positioning with wider button
Fixes COM-12161
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8644-feat-replace-puzzle-icon-with-extensions-blocks-icon-for-manager-button-2fe6d73d3650815c8867efc5a0842ef7)
by [Unito](https://www.unito.io)
Co-authored-by: Alexander Brown <drjkl@comfy.org>
## Summary
Add default keyboard shortcuts for mode toggle and assets panel access.
## Changes
- **Ctrl+Shift+A**: Toggle between Simple Mode and Graph Mode
(`Comfy.ToggleLinear`)
- **A**: Open/toggle assets panel (`Workspace.ToggleSidebarTab.assets`)
- Show keybinding in ModeToggle button tooltip (e.g. "Simple Mode
(Ctrl+Shift+A)")
## Keybinding Rationale
- `A` follows the existing pattern: `w` (workflows), `n` (node-lib), `m`
(model-lib)
- `Ctrl+Shift+A` chosen because:
- Ctrl+Shift is the standard modifier pattern for toggle commands
- "A" mnemonic for "App mode"
- Does not conflict with existing keybindings
## Testing
- Verified typecheck passes
- Verified lint passes
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **New Features**
* Tooltips now show dynamic keyboard shortcut suffixes for mode and tab
controls.
* Added keyboard shortcut: A — toggles the assets sidebar.
* Added keyboard shortcut: Ctrl+Shift+A — toggles linear mode.
* **Localization**
* Added a localized shortcut suffix template so displayed shortcuts
respect translations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8593-feat-add-default-keybindings-for-toggle-mode-and-assets-panel-2fc6d73d36508172bd6ed3378f43de55)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
## Summary
Move ellipsis and punctuation characters into i18n translation strings
for proper internationalization support.
## Changes
- Add 12 new translation keys with punctuation included:
- Placeholder keys with trailing ellipsis (e.g.,
`searchNodesPlaceholder: "Search Nodes..."`)
- `downloadWithSize` with interpolation: `"Download ({size})"`
- `completedWithCheckmark`: `"Completed ✓"`
- Prompt keys with colons (e.g., `enterNewNamePrompt: "Enter new
name:"`)
- Update 20 files to use new translation keys instead of string
concatenation
## Review Focus
This eliminates string concatenation patterns like `$t('key') + '...'`
that break proper internationalization, since different languages may
use different punctuation or may not need ellipsis/colons in the same
contexts.
Fixes#7333
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Chores**
* Standardized localization across the app: unified search placeholders
and input hints; updated dialog prompt texts for renaming,
saving/exporting, and related prompts.
* **New Features**
* Download buttons now show file size via localized text.
* Completed status displays a localized label with a checkmark.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8573-refactor-move-ellipsis-and-punctuation-into-i18n-translation-strings-2fc6d73d365081828ad3f257bcac7799)
by [Unito](https://www.unito.io)
## Summary
Major refactoring of browser tests to improve reliability,
maintainability, and type safety.
## Changes
### Test Infrastructure Decomposition
- Decomposed `ComfyPage.ts` (~1000 lines) into focused helpers:
- `CanvasHelper`, `DebugHelper`, `SubgraphHelper`,
`NodeOperationsHelper`
- `SettingsHelper`, `WorkflowHelper`, `ClipboardHelper`,
`KeyboardHelper`
- Created `ContextMenu` page object, `BaseDialog` base class, and
`BottomPanel` page object
- Extracted `DefaultGraphPositions` constants
### Locator Stability
- Added `data-testid` attributes to Vue components (sidebar, dialogs,
node library)
- Created centralized `selectors.ts` with test ID constants
- Replaced fragile CSS selectors (`.nth()`, `:nth-child()`) with
`getByTestId`/`getByRole`
### Performance & Reliability
- Removed `setTimeout` anti-patterns (replaced with `waitForFunction`)
- Replaced `waitForTimeout` with retrying assertions
- Replaced hardcoded coordinates with computed `NodeReference` positions
- Enforced LF line endings for all text files
### Type Safety
- Enabled `no-explicit-any` lint rule for browser_tests via oxlint
- Purged `as any` casts from browser_tests
- Added Window type augmentation for standardized window access
- Added proper type annotations throughout
### Bug Fixes
- Restored `ExtensionManager` API contract
- Removed test-only settings from production schema
- Fixed flaky selectors and missing test setup
## Testing
- All browser tests pass
- Typecheck passes
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Tests**
* Overhauled browser E2E test infrastructure with many new
helpers/fixtures, updated test APIs, and CI test container image bumped
for consistency.
* **Chores**
* Standardized line endings and applied stricter lint rules for browser
tests; workspace dependency version updated.
* **Documentation**
* Updated Playwright and TypeScript testing guidance and test-run
commands.
* **UI**
* Added stable data-testids to multiple components to improve
testability.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
---------
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
## Summary
Active jobs (pending/running) in the media assets panel now display in
FIFO order - oldest jobs first (first to be processed at top). This
matches the queue processing order and the old queue panel behavior.
## Changes
- **AssetsSidebarListView.vue**: Add `.toReversed()` to `activeJobItems`
computed to reverse job order for display
- **AssetsSidebarGridView.vue**: Same change for grid view consistency
- **AssetsSidebarListView.test.ts**: Unit test verifying oldest-first
ordering
## Root Cause
PR #8225 changed sorting from `queueIndex` to `createTime` descending in
`useJobList.ts`, which placed newest jobs first. For active jobs, users
expect oldest first (FIFO - first to be processed appears at top).
## Solution
Rather than modifying the shared `useJobList` composable (which serves
both the assets panel and queue overlay), the fix applies
`.toReversed()` at the view layer for the active jobs section only.
This:
- Preserves the newest-first order for completed/history jobs
- Displays active jobs in oldest-first order
- Maintains backward compatibility with the queue overlay
## Testing
- Unit test added to verify FIFO ordering of active jobs
- All existing `useJobList` tests pass
Fixes COM-14151
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
* **Bug Fixes**
* Corrected the display order of active jobs in the sidebar to show jobs
in oldest-first (FIFO) sequence.
* **Tests**
* Added unit tests for the assets sidebar list view to verify job
ordering and filtering behavior.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8561-fix-display-active-jobs-in-oldest-first-order-in-media-assets-panel-2fc6d73d365081c6bf31cb076a8d6014)
by [Unito](https://www.unito.io)
Add expandable output stacks to the assets list view.
Monolith ver. of https://github.com/Comfy-Org/ComfyUI_frontend/pull/8298
and its children
List view currently collapses multi-output jobs into a single row, which
makes sibling outputs easy to miss and causes selection/zoom behavior to
drift once items are expanded elsewhere. This change adds a stack toggle
to list rows, expands child outputs derived from job data, and keeps
list-view selection and gallery navigation aligned with the expanded
list. Output mapping and “load full outputs” checks are centralized so
folder view and stacks share the same helper, and job-detail parsing now
yields previewable outputs for the list view. Asset actions now prefer
metadata prompt IDs to support the composite IDs used by stacked
outputs.
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8283-Add-expandable-output-stacks-to-assets-list-view-2f16d73d365081a99fc6f1519ac2e57c)
by [Unito](https://www.unito.io)
---------
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: Johnpaul Chiwetelu <49923152+Myestery@users.noreply.github.com>
## Summary
Migrate keybindings domain to `src/platform/keybindings/` following DDD
principles.
## Changes
- **What**: Consolidate keybinding-related code (types, store, service,
defaults, reserved keys) into a single domain module with flat structure
- Extracted `KeyComboImpl` and `KeybindingImpl` classes into separate
files
- Updated all consumers to import from new location
- Colocated tests with source files
- Updated stores/README.md and services/README.md to remove migrated
entries
## Review Focus
- Verify all import paths were updated correctly
- Check that the flat structure is appropriate (vs nested core/data/ui
layers)
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8369-refactor-migrate-keybindings-to-DDD-structure-2f66d73d36508120b169dc737075fb45)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
## Summary
This PR adds two related features for subgraph blueprints:
### 1. Protect Global Blueprints from Deletion
- Added `isGlobalBlueprint()` helper that distinguishes blueprints by
`python_module` field
- User blueprints have `python_module: 'blueprint'`
- Global (installed) blueprints have `python_module` set to the node
pack name
- Guarded `deleteBlueprint()` to show a warning toast for global
blueprints
- Hidden delete menu in node library for global blueprints
### 2. Category Support for Blueprints
- User blueprints now use category `Subgraph Blueprints/User`
- Global blueprints use `Subgraph Blueprints/{category}` if category is
provided, otherwise `Subgraph Blueprints`
- Extended `GlobalSubgraphData.info` type with optional `category` field
- Added `category` to `zSubgraphDefinition` schema
## Files Changed
- `src/stores/subgraphStore.ts` - Core logic for both features
- `src/stores/subgraphStore.test.ts` - Tests for `isGlobalBlueprint`
- `src/components/sidebar/tabs/nodeLibrary/NodeTreeLeaf.vue` - Hide
delete menu for global blueprints
- `src/scripts/api.ts` - Extended `GlobalSubgraphData` type
- `src/platform/workflow/validation/schemas/workflowSchema.ts` - Added
category to schema
- `src/locales/en/main.json` - Added translation key
## Testing
- ✅ `pnpm typecheck` passed
- ✅ `pnpm lint` passed
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-8378-feat-add-category-support-for-blueprints-and-protect-global-blueprints-2f66d73d36508137aa67c2d88c358b69)
by [Unito](https://www.unito.io)
---------
Co-authored-by: Subagent 5 <subagent@example.com>
Co-authored-by: Amp <amp@ampcode.com>
Co-authored-by: GitHub Action <action@github.com>
Co-authored-by: AustinMroz <austin@comfy.org>