Skip to content

Conversation

@benceruleanlu
Copy link
Member

@benceruleanlu benceruleanlu commented Dec 23, 2025

This adds the list view to the media assets sidepanel, while also adding the active jobs to be displayed right now.

The design for this is actually changing, which is why it is in draft right now. There are technical limitations of the virtual grid that doesn't make it easy for both the active jobs and generated assets to exist on the same container. Currently WIP right now.

Part of the QPO v2 iteration, figma design can be found here. This will be implemented in a series of stacked PRs that can be reviewed and merged individually.

main <-- #7737, #7743, #7745

┆Issue is synchronized with this Notion page by Unito

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 23, 2025

📝 Walkthrough

Walkthrough

Adds a list-view sidebar component that displays active jobs with per-item cancel actions and a grid of generated assets; introduces progress-bar and job-action composables, an AssetsListItem UI component, media-icon utility, storybook stories, and updates AssetsSidebarTab to toggle list vs grid mode.

Changes

Cohort / File(s) Summary
List View Component
src/components/sidebar/tabs/AssetsSidebarListView.vue
New Vue component rendering active jobs (with hover actions/cancel) and a generated-assets VirtualGrid that emits select-asset and approach-end.
Sidebar Tab Integration
src/components/sidebar/tabs/AssetsSidebarTab.vue
Added isListView, showLoadingState, showEmptyState; conditionally renders AssetsSidebarListView when list mode enabled, preserves existing grid otherwise.
Asset List Item UI
src/platform/assets/components/AssetsListItem.vue, src/platform/assets/components/AssetsListItem.stories.ts
New reusable list-item component supporting preview/icon, primary/secondary text, progress bar segments, and actions slot; Storybook stories added.
Progress Bar Composable
src/composables/useProgressBarBackground.ts, src/components/queue/job/QueueJobItem.vue
New composable exports progress class/style helpers and guards; QueueJobItem.vue refactored to use these utilities for progress rendering.
Job Actions Composable
src/composables/queue/useJobActions.ts
New useJobActions() exposing cancelAction, canCancelJob, and runCancelJob to centralize job cancellation logic and UI label.
Job Menu Update
src/composables/queue/useJobMenu.ts
Menu actions now accept an optional item parameter and use a new resolveItem helper; useJobMenu defaulted to () => null.
Media Icon Utility
src/platform/assets/utils/mediaIconUtil.ts
New iconForMediaType(mediaType) mapping MediaKind to icon class strings.
Localization
src/locales/en/main.json
Added sideToolbar.generatedAssetsHeader translation key.

Sequence Diagram

sequenceDiagram
    participant Tab as AssetsSidebarTab
    participant ListView as AssetsSidebarListView
    participant JobItem as AssetsListItem (job)
    participant Grid as VirtualGrid
    participant AssetItem as AssetsListItem (asset)
    participant JobActions as useJobActions

    Tab->>ListView: render when isListView true
    ListView->>JobItem: render active jobs list
    JobItem->>JobActions: query canCancelJob
    JobItem->>JobActions: runCancelJob (on hover action)
    ListView->>Grid: render generated assets grid
    Grid->>AssetItem: render each asset with icon/preview
    AssetItem->>Tab: emit select-asset (on click)
    AssetItem->>Tab: emit approach-end (when needed)
Loading

Possibly related PRs

✨ Finishing touches
  • 📝 Generate docstrings

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link

github-actions bot commented Dec 23, 2025

🎭 Playwright Test Results

All tests passed!

⏰ Completed at: 01/09/2026, 02:45:23 AM UTC

📈 Summary

  • Total Tests: 514
  • Passed: 506 ✅
  • Failed: 0
  • Flaky: 0
  • Skipped: 8 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 494 / ❌ 0 / ⚠️ 0 / ⏭️ 8
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 9 / ❌ 0 / ⚠️ 0 / ⏭️ 0

🎉 Click on the links above to view detailed test results for each browser configuration.

@github-actions
Copy link

github-actions bot commented Dec 23, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/09/2026, 02:40:08 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

🔧 Auto-fixes Applied

This PR has been automatically updated to fix linting and formatting issues.

⚠️ Important: Your local branch is now behind. Run git pull before making additional changes to avoid conflicts.

Changes made:

  • ESLint auto-fixes
  • Prettier formatting

Comment on lines +350 to +370
const showLoadingState = computed(
() =>
loading.value &&
displayAssets.value.length === 0 &&
(!isListView.value || activeJobsCount.value === 0)
)
const showEmptyState = computed(
() =>
!loading.value &&
displayAssets.value.length === 0 &&
(!isListView.value || activeJobsCount.value === 0)
)
Copy link
Member Author

Choose a reason for hiding this comment

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

This change was made because now the view can show even when there are no generated assets, because running jobs were added to this view

@benceruleanlu benceruleanlu marked this pull request as ready for review December 23, 2025 21:13
Copilot AI review requested due to automatic review settings December 23, 2025 21:13
@dosubot dosubot bot added the size:XL This PR changes 500-999 lines, ignoring generated files. label Dec 23, 2025
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds a list view to the media assets sidepanel as part of the QPO v2 iteration. The changes introduce a new card-based list view component that displays both active jobs with progress indicators and generated assets, providing users with a more detailed view of their asset pipeline.

Key Changes:

  • New AssetsListCard component for displaying assets and jobs in list format
  • New AssetsSidebarListView component integrating active jobs and assets display
  • New useJobActions composable for managing job-specific actions
  • Feature flag isQPOV2Enabled enabled to activate the new UI

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/platform/assets/components/AssetsListCard.vue New reusable card component for list view with progress indicators, icons, and action slots
src/platform/assets/components/AssetsListCard.stories.ts Storybook stories demonstrating the AssetsListCard component in various states
src/composables/queue/useJobActions.ts New composable providing job action management (cancel) with i18n support
src/components/sidebar/tabs/AssetsSidebarListView.vue Main list view component integrating active jobs and generated assets with VirtualGrid
src/components/sidebar/tabs/AssetsSidebarTab.vue Updated to conditionally render list view based on feature flag and view mode
src/locales/en/main.json Added "generatedAssetsHeader" translation key for the list view header
src/config/uiFeatureFlags.ts Enabled QPOv2 feature flag to activate the new list view

@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. and removed size:XL This PR changes 500-999 lines, ignoring generated files. labels Dec 23, 2025
@benceruleanlu
Copy link
Member Author

This PR can be split into three if needed, one for the card, one for the actions, and another for the list itself.

@DrJKL
Copy link
Contributor

DrJKL commented Dec 31, 2025

@coderabbitai full review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 31, 2025

✅ Actions performed

Full review triggered.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 05244bb and 8fb9eb8.

📒 Files selected for processing (6)
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
  • src/composables/queue/useJobActions.ts
  • src/locales/en/main.json
  • src/platform/assets/components/AssetsListCard.stories.ts
  • src/platform/assets/components/AssetsListCard.vue
🧰 Additional context used
📓 Path-based instructions (16)
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • src/locales/en/main.json
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
  • src/platform/assets/components/AssetsListCard.stories.ts
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
  • src/platform/assets/components/AssetsListCard.stories.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
  • src/platform/assets/components/AssetsListCard.stories.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
  • src/platform/assets/components/AssetsListCard.stories.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
  • src/platform/assets/components/AssetsListCard.stories.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
  • src/platform/assets/components/AssetsListCard.stories.ts
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3.5+ with TypeScript in .vue files, exclusively using Composition API with <script setup lang="ts"> syntax
Use Tailwind 4 for styling in Vue components; avoid <style> blocks
Name Vue components using PascalCase (e.g., MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer computed() over ref with watch when deriving values
Prefer useModel over separately defining prop and emit for two-way binding
Use vue-i18n in composition API for string literals; place new translation entries in src/locales/en/main.json
Use cn() utility function from @/utils/tailwindUtil for merging Tailwind class names; do not use :class="[]" syntax
Do not use the dark: Tailwind variant; use semantic values from the style.css theme instead (e.g., bg-node-component-surface)
Do not use !important or the ! important prefix for Tailwind classes; find and correct interfering !important classes instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
  • src/platform/assets/components/AssetsListCard.stories.ts
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.stories.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/queue/useJobActions.ts
**/**/use[A-Z]*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the pattern useXyz.ts

Files:

  • src/composables/queue/useJobActions.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize the surface area (exported values) of each module and composable

Files:

  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.stories.ts
🧠 Learnings (23)
📚 Learning: 2025-12-09T04:35:43.971Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/locales/en/main.json:774-780
Timestamp: 2025-12-09T04:35:43.971Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, locale files other than `src/locales/en/main.json` are generated automatically on every release. Developers only need to add English (en) key/values in `src/locales/en/main.json` when making PRs; manual updates to other locale files (fr, ja, ko, ru, zh, zh-TW, es, ar, tr, etc.) are not required and should not be suggested in reviews.

Applied to files:

  • src/locales/en/main.json
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{components,composables}/**/*.{ts,tsx,vue} : Use vue-i18n for ALL user-facing strings by adding them to `src/locales/en/main.json`

Applied to files:

  • src/locales/en/main.json
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
  • src/platform/assets/components/AssetsListCard.stories.ts
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListCard.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.stories.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.stories.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.stories.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListCard.stories.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components

Applied to files:

  • src/platform/assets/components/AssetsListCard.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Implement proper props and emits definitions in Vue components

Applied to files:

  • src/platform/assets/components/AssetsListCard.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement proper props and emits definitions

Applied to files:

  • src/platform/assets/components/AssetsListCard.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,css} : Use the correct tokens from style.css in the design system package

Applied to files:

  • src/platform/assets/components/AssetsListCard.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue TabMenu component with Tabs without panels

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Sidebar component with Drawer

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarTab.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarTab.vue
🧬 Code graph analysis (1)
src/platform/assets/components/AssetsListCard.stories.ts (1)
src/components/input/SingleSelect.stories.ts (1)
  • Story (40-40)
🔇 Additional comments (19)
src/locales/en/main.json (1)

687-687: LGTM - Translation key properly added.

The new translation key generatedAssetsHeader is correctly placed under the sideToolbar scope and follows the existing naming conventions. It's used in the new list view component to label the generated assets section.

src/composables/queue/useJobActions.ts (3)

1-8: LGTM - Proper import structure.

Imports follow the repository conventions with type imports separated from regular imports.


18-37: Well-structured composable implementation.

The composable properly:

  • Uses i18n for internationalized labels
  • Wraps actions with error handling via useErrorHandling
  • Maps job states to available actions using a computed property
  • Provides a clear action structure with icon, label, and variant

39-41: Clarify the intent with the showClear type definition.

The condition job.showClear === false ? [] : (jobActionSets.value[job.state] ?? []) is correct, but the JobListItem type defines showClear?: boolean (optional), while in practice it's always explicitly set to true or false via queueDisplay.ts. The type definition should be non-optional (showClear: boolean) to accurately reflect actual usage and prevent future confusion.

src/platform/assets/components/AssetsListCard.stories.ts (3)

1-21: LGTM - Proper Storybook setup.

The story file follows Storybook conventions with:

  • Correct TypeScript typing with Meta and StoryObj
  • Appropriate decorators for styling context
  • Centered layout for component display

23-51: Well-structured render function using function declaration.

The renderActiveJob function properly uses a function declaration (as preferred in the repository) and demonstrates the component's active state with all relevant slots populated.

Based on learnings, function declarations are preferred for pure functions in this repository.


72-99: Good story coverage for different component states.

The three stories (ActiveJob, FailedJob, GeneratedAsset) effectively demonstrate the component's different visual states and prop combinations, providing useful documentation and testing scenarios.

src/platform/assets/components/AssetsListCard.vue (2)

75-97: LGTM - Proper props definition with partial destructuring.

The component correctly uses Vue 3.5 style with partial destructuring of props. As per repository guidelines, props that are not destructured remain accessible by name in the template scope.


99-101: LGTM - Simple and effective helper function.

The clampPercent function correctly constrains percentage values to the [0, 100] range, preventing visual glitches from invalid progress values.

src/components/sidebar/tabs/AssetsSidebarTab.vue (4)

208-208: LGTM - Proper import of new list view component.

The import follows the repository's conventions and integrates the new AssetsSidebarListView component.


239-239: LGTM - Clear computed for list view mode.

The isListView computed properly gates the list view based on the QPOV2 feature flag and the current view mode.


99-105: LGTM - Conditional rendering for list view.

The component properly switches between list and grid views based on isListView, with event handlers correctly wired to propagate select-asset and approach-end events.


351-363: The code logic is correct and intentional. The condition (!isListView.value || activeJobsCount.value === 0) works as designed:

  • Grid view: !isListView.value is true, so the loading/empty state always shows when assets are empty, regardless of active job count
  • List view with active jobs: When activeJobsCount > 0, the condition becomes false, which hides the loading/empty state to allow the active jobs list to display
  • List view without active jobs: The loading/empty state shows normally

The edge case mentioned (loading true, empty assets, activeJobsCount > 0 in grid view) does not cause a problem—the loading spinner correctly displays. The design intentionally treats grid and list views differently: the list view has special handling for active jobs, while the grid view shows standard loading/empty states.

src/components/sidebar/tabs/AssetsSidebarListView.vue (6)

101-109: LGTM - Proper props and emits definitions.

The component correctly defines props using TypeScript and emits with proper typing, following Vue 3 and repository conventions.


3-36: Well-structured active jobs rendering with hover actions.

The implementation properly:

  • Renders active jobs with AssetsListCard
  • Shows actions only on hover using hoveredJobId state
  • Uses @click.stop (line 18) to prevent event bubbling
  • Provides accessible labels for action buttons

The hover-to-reveal actions pattern improves UI cleanliness while maintaining functionality.


38-47: LGTM - Conditional header for generated assets.

The header correctly uses the new translation key and only appears when assets exist, with appropriate spacing when active jobs are also present.


49-74: LGTM - VirtualGrid integration with proper accessibility.

The VirtualGrid implementation:

  • Uses proper aria-label with dynamic content (lines 59-64)
  • Includes role and tabindex for keyboard navigation
  • Emits approach-end for pagination
  • Applies selection styling conditionally

Following repository guidelines, the button has an aria-label because it's effectively icon-only (the visual content is in slots).


145-173: Well-organized asset display utilities.

The helper functions for asset rendering are well-structured:

  • getAssetPrimaryText: Uses truncateFilename for consistent display
  • getAssetSecondaryText: Prioritizes execution time, then duration, then file size
  • getAssetIconName: Maps media types to appropriate icons

The fallback logic in getAssetSecondaryText ensures graceful handling of missing metadata.


207-209: LGTM - Proper fire-and-forget async handling.

The use of void keyword correctly indicates intentional fire-and-forget for the async action execution, with error handling delegated to runJobAction.

Comment on lines +99 to +105
<AssetsSidebarListView
v-if="isListView"
:assets="displayAssets"
:is-selected="isSelected"
@select-asset="handleAssetSelect"
@approach-end="handleApproachEnd"
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

We should ensure this doesn't exceed screen height on mobile otherwise you won't be able to physically access the generated assets section.

Copy link
Member Author

Choose a reason for hiding this comment

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

can this be non blocking and we fix afterwards? most of the vertical height comes from portions of the sidebar tab template and I think we'd also need to change the virtual grid to account for this

Copy link
Contributor

Choose a reason for hiding this comment

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

@coderabbitai make a tracking issue for this and assign to Ben please

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Create a GitHub issue for tracking the mobile view vertical height concern
gh issue create \
  --repo Comfy-Org/ComfyUI_frontend \
  --title "Mobile view: Active jobs section may block access to generated assets in list view" \
  --body "**Issue Description**

On mobile devices, the active jobs section in the assets sidebar list view may exceed the screen height, preventing users from physically accessing the generated assets section below it.

**Context**

This issue was identified during review of the list view implementation for the assets sidepanel. The vertical height comes from portions of the sidebar tab template, and fixing this will likely require changes to both the sidebar tab template and the virtual grid component to properly account for available vertical space.

**References**

- PR: https://github.com/Comfy-Org/ComfyUI_frontend/pull/7737
- Comment: https://github.com/Comfy-Org/ComfyUI_frontend/pull/7737#discussion_r2654565526
- Reported by: @christian-byrne

**Affected Component**

\`src/components/sidebar/tabs/AssetsSidebarListView.vue\` and related sidebar tab template components" \
  --assignee benceruleanlu

echo "Issue created successfully"

Length of output: 84


@christian-byrne I've created a tracking issue for this mobile view concern and assigned it to Ben:

Issue #7909: Mobile view: Active jobs section may block access to generated assets in list view

The issue captures the concern about the active jobs section potentially exceeding screen height on mobile devices and blocking access to the generated assets section below. It includes references to this PR and the specific comment for context.


🧠 Learnings used
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Sidebar component with Drawer

<template>
<div class="flex h-full flex-col">
<div v-if="activeJobItems.length" class="flex flex-col gap-2 px-2">
<AssetsListCard
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: Could we not name this one Card? It seems more like an entry or item.

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

renamed to ...item

Copy link
Contributor

Choose a reason for hiding this comment

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

nit (definitely non-blocking): Maybe for future: Can we potentially make this a more generalized Item component and then have the AssetListItem that implements the more jobs-specific stuff?

Copy link
Member Author

Choose a reason for hiding this comment

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

sure, although I don't think it wouldn't have any consumers because the QPO itself is planned for deletion after this change

Copy link
Member Author

Choose a reason for hiding this comment

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

@coderabbitai can you write an issue tracking this?

Copy link
Contributor

Choose a reason for hiding this comment

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

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash

# Create GitHub issue tracking the suggestion to generalize AssetsListCard component
gh issue create \
  --repo "Comfy-Org/ComfyUI_frontend" \
  --title "Consider generalizing AssetsListCard into a more reusable Item component" \
  --body "## Context

This issue tracks a suggestion to refactor \`AssetsListCard\` into a more generalized \`Item\` component for broader reusability.

## Background

In PR #7737, @christian-byrne suggested that \`AssetsListCard\` could potentially be made into a more generalized \`Item\` component, with \`AssetListItem\` implementing the more jobs-specific functionality.

While the current QPO is planned for deletion after the changes in #7737, this generalization could still provide value for future use cases.

## References

- Original PR: https://github.com/Comfy-Org/ComfyUI_frontend/pull/7737
- Discussion: https://github.com/Comfy-Org/ComfyUI_frontend/pull/7737#discussion_r2654590279
- Requested by: @benceruleanlu

## Component Location

\`src/platform/assets/components/AssetsListCard.vue\`" \
  --assignee "benceruleanlu"

Length of output: 57


@benceruleanlu I've created issue #7865 to track the suggestion to generalize the AssetsListCard component: #7865

The issue has been assigned to you and includes references to this PR and the discussion context.


🧠 Learnings used
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Implement proper props and emits definitions in Vue components

Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components

v-if="$slots.primary || primaryText"
class="text-xs leading-none text-text-primary"
>
<slot name="primary">{{ primaryText }}</slot>
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we make the text non-selectable if shift or control is down? To prevent text selection when doing Ctrl/Shift selection. Can use https://vueuse.org/core/useMagicKeys/

Copy link
Contributor

Choose a reason for hiding this comment

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

Copy link
Member Author

Choose a reason for hiding this comment

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

I just prevented text selection in general, which matches the grid implementation and is simpler, let me know if we want to gate it to just shift being held

<div
v-if="progressTotalPercent !== undefined"
class="pointer-events-none absolute inset-y-0 left-0 h-full bg-interface-panel-job-progress-primary transition-[width]"
:style="{ width: `${clampPercent(progressTotalPercent)}%` }"
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we generalize this to some composable or directive so any component can simply get the progress bars background styles?

Copy link
Member Author

Choose a reason for hiding this comment

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

done

Copy link
Contributor

Choose a reason for hiding this comment

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

Would be good to put in domain specific folders rather than composables

Copy link
Member Author

Choose a reason for hiding this comment

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

Queue is already domain‑specific but nested under a type bucket. Do you mean a domain root like src/queue/*?

Copy link
Contributor

Choose a reason for hiding this comment

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

Yes

Copy link
Member Author

@benceruleanlu benceruleanlu Jan 9, 2026

Choose a reason for hiding this comment

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

K, did that at the top of the stack to prevent git headaches and keep this one unblocked

draft because I'm going to see how closer I can make it match DDD, it was a first general pass

Comment on lines 42 to 49
const runJobAction = wrapWithErrorHandlingAsync(
async (action: JobAction, job: JobListItem) => {
currentJob.value = job

if (action.key === 'cancel') {
await cancelJob()
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems overly refactored if only used for the cancel action. YAGNI

Copy link
Member Author

Choose a reason for hiding this comment

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

done

variant: 'destructive' | 'secondary' | 'textonly'
}

export function useJobActions() {
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like it would make more sense if the composable wrapped the job (and took it as an argument).

Copy link
Member Author

Choose a reason for hiding this comment

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

done

Copy link
Contributor

Choose a reason for hiding this comment

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

The useJobActions still doesn't take the job as an argument, I might be misunderstanding.

Copy link
Member Author

Choose a reason for hiding this comment

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

I misunderstood, now made the change for useJobActions to take a job ref and wrap it reactively

Comment on lines 21 to 22
const currentJob = ref<JobListItem | null>(null)
const { cancelJob } = useJobMenu(() => currentJob.value)
Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like we are doing a lot of round trips for this:

  1. runJobAction => sets currentJob
  2. The cancelJob relies on getter that returns currentJob
  3. Which we then wait on

Is there a cleaner way to organize this?

Copy link
Member Author

Choose a reason for hiding this comment

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

fixed by two other review comments

Comment on lines 24 to 37
const jobActionSets = computed<Partial<Record<JobState, JobAction[]>>>(() => {
const cancelAction: JobAction = {
key: 'cancel',
icon: 'icon-[lucide--x]',
label: t('sideToolbar.queueProgressOverlay.cancelJobTooltip'),
variant: 'destructive'
}

return {
pending: [cancelAction],
initialization: [cancelAction],
running: [cancelAction]
}
})
Copy link
Contributor

Choose a reason for hiding this comment

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

This is slightly over refactored as well since it just returns a constant object and there's no reactive values internally (besides i18n). YAGNI

Copy link
Member Author

Choose a reason for hiding this comment

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

done

@dosubot dosubot bot added size:XL This PR changes 500-999 lines, ignoring generated files. and removed size:L This PR changes 100-499 lines, ignoring generated files. labels Jan 7, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @src/components/sidebar/tabs/AssetsSidebarListView.vue:
- Around line 25-39: The buttons currently always call runCancelJob(job)
regardless of the action; update the click handling so it dispatches based on
the action item: change the button @click to call a dispatcher (e.g.,
handleJobAction(action, job)) instead of runCancelJob, and implement
handleJobAction to check action.key (or call action.handler if provided by
getJobActions) and route to runCancelJob(job) only when key === 'cancel'
(otherwise call the action.handler/action.callback or perform the appropriate
operation). Ensure getJobActions, runCancelJob, and the new handleJobAction
symbol names are used so the mapping is deterministic and future actions execute
correctly.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9e477d4 and 9c4f808.

📒 Files selected for processing (7)
  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/composables/useProgressBarBackground.ts
  • src/platform/assets/components/AssetsListItem.vue
🧰 Additional context used
📓 Path-based instructions (17)
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/useProgressBarBackground.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/composables/queue/useJobActions.ts
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/useProgressBarBackground.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/composables/queue/useJobActions.ts
**/*.test.ts

📄 CodeRabbit inference engine (AGENTS.md)

**/*.test.ts: Use unit/component tests in tests-ui/ or src/**/*.test.ts with Vitest framework
For mocking in tests, leverage Vitest utilities; keep module mocks contained and avoid global mutable state within test files
Do not write change detector tests or tests dependent on non-behavioral features like utility classes or styles
Aim for behavioral coverage of critical and new features in unit tests

Files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize the surface area (exported values) of each module and composable

Files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • src/composables/useProgressBarBackground.ts
  • src/composables/queue/useJobActions.ts
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListItem.vue
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/useProgressBarBackground.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/composables/queue/useJobActions.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/useProgressBarBackground.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/composables/queue/useJobActions.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/useProgressBarBackground.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/composables/queue/useJobActions.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/useProgressBarBackground.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/composables/queue/useJobActions.ts
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/useProgressBarBackground.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/composables/queue/useJobActions.ts
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3.5+ with TypeScript in .vue files, exclusively using Composition API with <script setup lang="ts"> syntax
Use Tailwind 4 for styling in Vue components; avoid <style> blocks
Name Vue components using PascalCase (e.g., MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer computed() over ref with watch when deriving values
Prefer useModel over separately defining prop and emit for two-way binding
Use vue-i18n in composition API for string literals; place new translation entries in src/locales/en/main.json
Use cn() utility function from @/utils/tailwindUtil for merging Tailwind class names; do not use :class="[]" syntax
Do not use the dark: Tailwind variant; use semantic values from the style.css theme instead (e.g., bg-node-component-surface)
Do not use !important or the ! important prefix for Tailwind classes; find and correct interfering !important classes instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListItem.vue
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/composables/useProgressBarBackground.ts
  • src/composables/queue/useJobActions.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/useProgressBarBackground.ts
  • src/composables/queue/useJobActions.ts
**/**/use[A-Z]*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the pattern useXyz.ts

Files:

  • src/composables/useProgressBarBackground.ts
  • src/composables/queue/useJobActions.ts
🧠 Learnings (46)
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Check assets/ directory for test data when writing tests

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.test.ts : Aim for behavioral coverage of critical and new features in unit tests

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `test` instead of `it` for defining test cases in vitest

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Use `vitest` for unit testing in this project

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Prefer the use of `test.extend` over loose variables; import `test as baseTest` from `vitest`

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.test.ts : For mocking in tests, leverage Vitest utilities; keep module mocks contained and avoid global mutable state within test files

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-11-24T19:48:09.318Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .cursor/rules/unit-test.mdc:0-0
Timestamp: 2025-11-24T19:48:09.318Z
Learning: Applies to test/**/*.{test,spec}.{js,ts,jsx,tsx} : Tests should be cross-platform compatible using `path.resolve`, `path.join`, and `path.sep` for Windows, macOS, and Linux compatibility

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.test.ts : Use unit/component tests in `tests-ui/` or `src/**/*.test.ts` with Vitest framework

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-11-24T19:47:22.909Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: browser_tests/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:22.909Z
Learning: Applies to browser_tests/**/*.{e2e,spec}.{ts,tsx,js,jsx} : Follow naming conventions for browser tests

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • src/composables/useProgressBarBackground.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • src/composables/useProgressBarBackground.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • src/composables/useProgressBarBackground.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • src/composables/useProgressBarBackground.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-10T03:09:13.807Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7303
File: src/components/topbar/CurrentUserPopover.test.ts:199-205
Timestamp: 2025-12-10T03:09:13.807Z
Learning: In test files, prefer selecting or asserting on accessible properties (text content, aria-label, role, accessible name) over data-testid attributes. This ensures tests validate actual user-facing behavior and accessibility, reducing reliance on implementation details like test IDs.

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-12-30T01:31:04.927Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7797
File: tests-ui/tests/lib/litegraph/src/widgets/ComboWidget.test.ts:648-648
Timestamp: 2025-12-30T01:31:04.927Z
Learning: In Vitest v4, when mocking functions that may be called as constructors (using new), the mock implementation must use function() or class syntax rather than an arrow function. Arrow mocks can cause '<anonymous> is not a constructor' errors. This is a breaking change from Vitest v3 where mocks could use an arrow function. Apply this guideline to test files that mock constructor-like calls (e.g., in tests under tests-ui, such as ComboWidget.test.ts) and ensure mock implementations are defined with function() { ... } or class { ... } to preserve constructor behavior.

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • packages/shared-frontend-utils/src/formatUtil.test.ts
  • packages/shared-frontend-utils/src/formatUtil.ts
  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/useProgressBarBackground.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue InlineMessage component with Message

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Steps component with Stepper without panels

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Leverage VueUse functions for performance-enhancing styles in Vue components

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue OverlayPanel component with Popover

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.

Applied to files:

  • src/components/queue/job/QueueJobItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Sidebar component with Drawer

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Prefer `computed()` over `ref` with `watch` when deriving values

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Prefer emit/event-name for state changes over other communication patterns

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement lifecycle hooks with onMounted, onUpdated, etc.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Use `cn()` utility function from `@/utils/tailwindUtil` for merging Tailwind class names; do not use `:class="[]"` syntax

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/**/use[A-Z]*.ts : Name composables using the pattern `useXyz.ts`

Applied to files:

  • src/composables/useProgressBarBackground.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guide

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Implement proper props and emits definitions in Vue components

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement proper props and emits definitions

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
🧬 Code graph analysis (2)
packages/shared-frontend-utils/src/formatUtil.test.ts (1)
packages/shared-frontend-utils/src/formatUtil.ts (1)
  • iconForMediaType (554-565)
src/composables/queue/useJobActions.ts (3)
src/composables/useErrorHandling.ts (1)
  • useErrorHandling (52-112)
src/composables/queue/useJobMenu.ts (1)
  • useJobMenu (43-356)
src/types/queue.ts (1)
  • JobState (4-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: setup
  • GitHub Check: lint-and-format
  • GitHub Check: collect
  • GitHub Check: test
🔇 Additional comments (11)
packages/shared-frontend-utils/src/formatUtil.test.ts (1)

3-7: LGTM! Comprehensive test coverage for icon mapping.

The test suite properly validates the iconForMediaType function for all media types with clear assertions.

Also applies to: 150-157

packages/shared-frontend-utils/src/formatUtil.ts (1)

554-565: LGTM! Clean icon mapping implementation.

The function correctly maps media types to their corresponding Lucide icon classes with a sensible default for the image type.

src/components/queue/job/QueueJobItem.vue (1)

53-69: LGTM! Effective refactoring to centralize progress bar logic.

The component now uses the shared composable for progress bar styling and validation, improving maintainability and reducing code duplication. The guards and style helpers are correctly applied.

Also applies to: 206-206, 251-258

src/composables/queue/useJobActions.ts (1)

22-35: Verify necessity of computed for mostly static action configuration.

The jobActionSets computed returns a static structure where only the i18n label is reactive. A previous reviewer questioned whether this level of abstraction is needed (YAGNI) if only the cancel action is supported.

If additional actions are planned (view, delete, etc.), this structure makes sense. Otherwise, consider simplifying to a single action getter. Please confirm whether this anticipates future action types.

src/composables/useProgressBarBackground.ts (1)

9-36: Prefer function declarations for pure utility functions.

These pure utility functions should use function declarations instead of function expressions for better hoisting clarity and consistency with the codebase guidelines.

🔎 Proposed refactor to function declarations
-function clampPercent(value: number) {
+function clampPercent(value: number): number {
   return Math.min(100, Math.max(0, value))
 }
 
-function normalizeProgressPercent(value: ProgressPercent) {
+function normalizeProgressPercent(value: ProgressPercent): number | undefined {
   if (value === undefined || !Number.isFinite(value)) return undefined
 
   return clampPercent(value)
 }
 
-function hasProgressPercent(value: ProgressPercent) {
+function hasProgressPercent(value: ProgressPercent): boolean {
   return normalizeProgressPercent(value) !== undefined
 }
 
-function hasAnyProgressPercent(
+function hasAnyProgressPercent(
   totalPercent: ProgressPercent,
   currentPercent: ProgressPercent
-) {
+): boolean {
   return hasProgressPercent(totalPercent) || hasProgressPercent(currentPercent)
 }
 
-function progressPercentStyle(value: ProgressPercent) {
+function progressPercentStyle(value: ProgressPercent): { width: string } | undefined {
   const normalized = normalizeProgressPercent(value)
 
   if (normalized === undefined) return undefined
 
   return { width: `${normalized}%` }
 }

Note: The refactor also adds explicit return type annotations for better type safety.

Based on learnings, prefer function declarations over function expressions for pure functions.

⛔ Skipped due to learnings
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:17.361Z
Learning: In the Comfy-Org/ComfyUI_frontend repository, prefer pure function declarations (e.g., `function foo() { ... }`) over function expressions (e.g., `const foo = () => { ... }`) for pure functions, as function declarations are considered more functional than function expressions.
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx,vue} : Use function declarations instead of function expressions when possible
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/**/use[A-Z]*.ts : Name composables using the pattern `useXyz.ts`
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.{ts,tsx} : Minimize the surface area (exported values) of each module and composable
src/platform/assets/components/AssetsListItem.vue (2)

71-107: LGTM: Clean composition API setup.

The script setup properly uses Vue 3.5-style prop destructuring, leverages the shared useProgressBarBackground composable, and follows TypeScript best practices.


1-69: Well-structured template with proper slot composition.

The template correctly uses conditional rendering for progress bars, provides flexible content via slots with prop fallbacks, and applies Tailwind utilities appropriately. The select-none class prevents text selection during interactions as intended.

src/components/sidebar/tabs/AssetsSidebarListView.vue (4)

149-169: Clean fallback chain for asset metadata display.

The secondary text logic properly checks execution time, duration, and size with appropriate formatting. The fallback chain ensures graceful handling of missing metadata.


85-122: Solid composition API setup with proper TypeScript types.

The script setup correctly uses Vue 3.5-style props destructuring, defines typed emits, and leverages appropriate composables for job and action management. The hover state management approach is reasonable given the need to track specific job IDs.


3-41: Active jobs section needs virtualization or height constraints.

Rendering all active jobs without virtualization can cause performance issues with many concurrent jobs and push generated assets far down. Consider wrapping in VirtualGrid with max-h-[40vh] or implementing collapse/expand UX.

Likely an incorrect or invalid review comment.


143-147: Consider extracting job state logic to shared utility.

The isActiveJobState function could be moved to a shared utility (e.g., @/utils/queueUtil.ts) for reuse across components that need to filter job states.

⛔ Skipped due to learnings
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:09.642Z
Learning: In the ComfyUI frontend queue system (src/stores/queueStore.ts), the `useQueuePendingTaskCountStore().count` includes the currently executing task. When count = 1, there is only the active/running task with no pending tasks. When count > 1, there is an active task plus pending tasks waiting in the queue. The "Clear Pending Tasks" button should only be enabled when count > 1 to avoid clearing the currently running task, which should be handled by the "Cancel current run" button instead.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @src/components/sidebar/tabs/AssetsSidebarListView.vue:
- Around line 146-150: Extract the isActiveJobState function into a shared
queueDisplay utility alongside the existing iconForJobState so multiple
components can reuse it; create a new exported function isActiveJobState(state:
JobState) that returns true for 'pending'|'initialization'|'running', replace
the inline function in AssetsSidebarListView.vue with an import from the shared
module, and update any other components that duplicate this logic to import and
use the shared isActiveJobState instead.
- Around line 32-41: The action buttons currently call runCancelJob(job)
unconditionally, so replace that with a dispatcher that uses the action.key from
getJobActions(job); add a handler (e.g., handleJobAction) that accepts (key,
job) and switches on key (call runCancelJob(job) when key === 'cancel'), then
change the @click to call handleJobAction(action.key, job) so future actions are
routed correctly.

In @src/composables/queue/useJobActions.ts:
- Around line 20-33: getJobActionSets currently allocates new action objects on
each call; replace it with a computed memoized value so the cancel action (which
depends on t()) is only recreated when its dependencies change. Implement a
const jobActionSets = computed<Partial<Record<JobState, JobAction[]>>>(() => {
const cancelAction: JobAction = { key: 'cancel', icon: 'icon-[lucide--x]',
label: t('sideToolbar.queueProgressOverlay.cancelJobTooltip'), variant:
'destructive' }; return { pending: [cancelAction], initialization:
[cancelAction], running: [cancelAction] }; }); and use jobActionSets.value where
getJobActionSets() was used; ensure the computed imports/reactivity are
available and that t() is referenced inside the computed so translations update
reactively.

In @src/platform/assets/components/AssetsListItem.vue:
- Around line 21-29: Remove the non-interactive wrapper div's aria-label usage:
stop binding iconAriaLabel to the outer div (the element using cn(...) and
iconWrapperClass) so it does not output aria-label on a plain <div>; instead
ensure the actual icon element (the SVG/Img rendered where aria-hidden is
already set) has aria-hidden="true" and keep any descriptive text in nearby
visible content, leaving iconAriaLabel unused on the wrapper or only applied to
an interactive control if/when the wrapper becomes interactive.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9c4f808 and 434ee52.

📒 Files selected for processing (4)
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/composables/queue/useJobMenu.ts
  • src/platform/assets/components/AssetsListItem.vue
🧰 Additional context used
📓 Path-based instructions (16)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use TypeScript exclusively; do not write new JavaScript code
Use sorted and grouped imports organized by plugin/source
Enforce ESLint rules including Vue + TypeScript rules, disallow floating promises, disallow unused imports, and restrict i18n raw text in templates
Do not use any type or as any type assertions; fix the underlying type issue instead
Write code that is expressive and self-documenting; avoid redundant comments and clean as you go
Keep functions short and functional; minimize nesting and follow the arrow anti-pattern
Avoid mutable state; prefer immutability and assignment at point of declaration
Use function declarations instead of function expressions when possible
Use es-toolkit for utility functions
Implement proper error handling in code

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
**/**/use[A-Z]*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the pattern useXyz.ts

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
**/*.{ts,tsx,vue,js,jsx,json,css}

📄 CodeRabbit inference engine (AGENTS.md)

Apply Prettier formatting with 2-space indentation, single quotes, no trailing semicolons, and 80-character line width

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize the surface area (exported values) of each module and composable

Files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Use Vue 3.5+ with TypeScript in .vue files, exclusively using Composition API with <script setup lang="ts"> syntax
Use Tailwind 4 for styling in Vue components; avoid <style> blocks
Name Vue components using PascalCase (e.g., MenuHamburger.vue)
Use Vue 3.5 TypeScript-style default prop declaration with reactive props destructuring; do not use withDefaults or runtime props declaration
Prefer computed() over ref with watch when deriving values
Prefer useModel over separately defining prop and emit for two-way binding
Use vue-i18n in composition API for string literals; place new translation entries in src/locales/en/main.json
Use cn() utility function from @/utils/tailwindUtil for merging Tailwind class names; do not use :class="[]" syntax
Do not use the dark: Tailwind variant; use semantic values from the style.css theme instead (e.g., bg-node-component-surface)
Do not use !important or the ! important prefix for Tailwind classes; find and correct interfering !important classes instead
Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead
Leverage VueUse functions for performance-enhancing styles in Vue components
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
🧠 Learnings (31)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/**/use[A-Z]*.ts : Name composables using the pattern `useXyz.ts`

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guide

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Implement proper props and emits definitions in Vue components

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Define proper props and emits definitions in Vue components

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement proper props and emits definitions

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.

Applied to files:

  • src/platform/assets/components/AssetsListItem.vue
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Leverage VueUse functions for performance-enhancing styles in Vue components

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Avoid new usage of PrimeVue components; use VueUse, shadcn/vue, or Reka UI instead

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Prefer `computed()` over `ref` with `watch` when deriving values

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement lifecycle hooks with onMounted, onUpdated, etc.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Prefer emit/event-name for state changes over other communication patterns

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T06:04:12.562Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-12-21T06:04:12.562Z
Learning: Applies to **/*.vue : Use `cn()` utility function from `@/utils/tailwindUtil` for merging Tailwind class names; do not use `:class="[]"` syntax

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
🧬 Code graph analysis (2)
src/composables/queue/useJobMenu.ts (3)
src/composables/queue/useJobList.ts (1)
  • JobListItem (33-47)
src/schemas/apiSchema.ts (1)
  • ExecutionErrorWsMessage (162-162)
src/base/common/downloadUtil.ts (1)
  • downloadFile (31-48)
src/composables/queue/useJobActions.ts (3)
src/composables/useErrorHandling.ts (1)
  • useErrorHandling (52-112)
src/composables/queue/useJobMenu.ts (1)
  • useJobMenu (43-359)
src/types/queue.ts (1)
  • JobState (4-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (7)
src/composables/queue/useJobActions.ts (1)

35-45: LGTM!

The getJobActions correctly checks showClear === false to guard against undefined values, and runCancelJob properly wraps the cancel operation with centralized error handling.

src/composables/queue/useJobMenu.ts (3)

55-56: LGTM!

The resolveItem helper cleanly unifies item resolution, supporting both explicit item parameters and fallback to currentMenuItem(). This enables external callers (like useJobActions) to invoke actions directly with a job reference.


74-83: Clean null-safe cancellation flow.

The cancelJob function properly resolves the item, guards against null, and handles state-specific cancellation (interrupt for running/initialization, delete for pending). The queueStore.update() ensures UI consistency after cancellation.


238-242: Good deferred resolution pattern for menu click handlers.

The onInspectAsset callback correctly resolves the current item at click time via resolveItem(), ensuring the callback receives the actual current item when invoked rather than a stale reference captured during menu construction.

src/platform/assets/components/AssetsListItem.vue (1)

84-106: Props definition follows Vue 3.5 style correctly.

The component uses proper Vue 3.5 TypeScript-style prop declaration with reactive props destructuring and defaults (previewAlt = ''). The composable integration with useProgressBarBackground is clean.

src/components/sidebar/tabs/AssetsSidebarListView.vue (2)

156-172: LGTM!

The getAssetSecondaryText function implements a clean fallback chain for displaying asset metadata: execution time → duration → file size → empty string. This provides meaningful secondary information based on available data.


193-200: LGTM!

The getJobIconClass function correctly adds animate-spin for pending jobs without a preview image, providing visual feedback that the job is queued. The conditional logic properly checks for the absence of iconImageUrl before applying the animation.

Comment on lines 32 to 41
<Button
v-for="action in getJobActions(job)"
:key="action.key"
:variant="action.variant"
size="icon"
:aria-label="action.label"
@click.stop="runCancelJob(job)"
>
<i :class="action.icon" class="size-4" />
</Button>
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 7, 2026

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Critical: Action handler ignores action.key, always executes cancel.

The v-for iterates over getJobActions(job), but line 38 always calls runCancelJob(job) regardless of which action button is clicked. While currently only cancel exists, this design will break when additional actions are added. The handler should dispatch based on action.key.

🔎 Proposed fix
 <Button
   v-for="action in getJobActions(job)"
   :key="action.key"
   :variant="action.variant"
   size="icon"
   :aria-label="action.label"
-  @click.stop="runCancelJob(job)"
+  @click.stop="handleJobAction(action.key, job)"
 >

Add a handler function in the script:

function handleJobAction(key: JobAction['key'], job: JobListItem) {
  if (key === 'cancel') {
    runCancelJob(job)
  }
}

Alternatively, if useJobActions is extended to provide a generic runner:

-const { getJobActions, runCancelJob } = useJobActions()
+const { getJobActions, runJobAction } = useJobActions()

// In template:
-@click.stop="runCancelJob(job)"
+@click.stop="runJobAction(action, job)"

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @src/components/sidebar/tabs/AssetsSidebarListView.vue around lines 32 - 41,
The action buttons currently call runCancelJob(job) unconditionally, so replace
that with a dispatcher that uses the action.key from getJobActions(job); add a
handler (e.g., handleJobAction) that accepts (key, job) and switches on key
(call runCancelJob(job) when key === 'cancel'), then change the @click to call
handleJobAction(action.key, job) so future actions are routed correctly.

Copy link
Contributor

Choose a reason for hiding this comment

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

@benceruleanlu This is true right? It's always runCancelJob(job) as the click action? Is that intended?

Copy link
Contributor

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah, the original code was extensible and supported multiple actions, but a review comment said "yagni" because only the cancel button was in the design and the ... menu is another slice of code, so this is the "yagni" implementation

Copy link
Member Author

@benceruleanlu benceruleanlu Jan 9, 2026

Choose a reason for hiding this comment

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

Cleaned this up so that the action.key and other remnants of the previous system is removed so it's more clear that it's just a cancel button

Comment on lines 20 to 33
const getJobActionSets = (): Partial<Record<JobState, JobAction[]>> => {
const cancelAction: JobAction = {
key: 'cancel',
icon: 'icon-[lucide--x]',
label: t('sideToolbar.queueProgressOverlay.cancelJobTooltip'),
variant: 'destructive'
}

return {
pending: [cancelAction],
initialization: [cancelAction],
running: [cancelAction]
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider memoizing the action sets to avoid repeated object creation.

getJobActionSets() creates new objects on every call to getJobActions(). Since the cancel action only depends on t(), consider using computed to memoize the result.

🔎 Proposed optimization
+import { computed } from 'vue'
+
 export function useJobActions() {
   const { t } = useI18n()
   const { wrapWithErrorHandlingAsync } = useErrorHandling()
   const { cancelJob } = useJobMenu()

-  const getJobActionSets = (): Partial<Record<JobState, JobAction[]>> => {
-    const cancelAction: JobAction = {
+  const jobActionSets = computed<Partial<Record<JobState, JobAction[]>>>(() => {
+    const cancelAction: JobAction = {
       key: 'cancel',
       icon: 'icon-[lucide--x]',
       label: t('sideToolbar.queueProgressOverlay.cancelJobTooltip'),
       variant: 'destructive'
     }
-
-    return {
+    return {
       pending: [cancelAction],
       initialization: [cancelAction],
       running: [cancelAction]
     }
-  }
+  })

   const getJobActions = (job: JobListItem): JobAction[] =>
-    job.showClear === false ? [] : (getJobActionSets()[job.state] ?? [])
+    job.showClear === false ? [] : (jobActionSets.value[job.state] ?? [])

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @src/composables/queue/useJobActions.ts around lines 20 - 33,
getJobActionSets currently allocates new action objects on each call; replace it
with a computed memoized value so the cancel action (which depends on t()) is
only recreated when its dependencies change. Implement a const jobActionSets =
computed<Partial<Record<JobState, JobAction[]>>>(() => { const cancelAction:
JobAction = { key: 'cancel', icon: 'icon-[lucide--x]', label:
t('sideToolbar.queueProgressOverlay.cancelJobTooltip'), variant: 'destructive'
}; return { pending: [cancelAction], initialization: [cancelAction], running:
[cancelAction] }; }); and use jobActionSets.value where getJobActionSets() was
used; ensure the computed imports/reactivity are available and that t() is
referenced inside the computed so translations update reactively.

Comment on lines +21 to +29
<div
:class="
cn(
'relative z-1 flex size-8 shrink-0 items-center justify-center overflow-hidden rounded-sm bg-secondary-background',
iconWrapperClass
)
"
:aria-label="iconAriaLabel || undefined"
>
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Accessibility: aria-label on non-interactive div may not be announced.

The wrapper div (lines 21-28) has an aria-label attribute, but screen readers typically don't announce aria-label on non-interactive elements like <div>. Since the icon is decorative (the purpose is conveyed by surrounding text), consider removing the aria-label and keeping only aria-hidden="true" on the icon element (already present at line 46).

🔎 Proposed fix
     <div
       :class="
         cn(
           'relative z-1 flex size-8 shrink-0 items-center justify-center overflow-hidden rounded-sm bg-secondary-background',
           iconWrapperClass
         )
       "
-      :aria-label="iconAriaLabel || undefined"
     >
🤖 Prompt for AI Agents
In @src/platform/assets/components/AssetsListItem.vue around lines 21 - 29,
Remove the non-interactive wrapper div's aria-label usage: stop binding
iconAriaLabel to the outer div (the element using cn(...) and iconWrapperClass)
so it does not output aria-label on a plain <div>; instead ensure the actual
icon element (the SVG/Img rendered where aria-hidden is already set) has
aria-hidden="true" and keep any descriptive text in nearby visible content,
leaving iconAriaLabel unused on the wrapper or only applied to an interactive
control if/when the wrapper becomes interactive.

Copy link
Collaborator

@AustinMroz AustinMroz left a comment

Choose a reason for hiding this comment

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

Changes look good to me.

@christian-byrne christian-byrne self-assigned this Jan 8, 2026
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this belong in formatUtil?

Copy link
Member Author

@benceruleanlu benceruleanlu Jan 9, 2026

Choose a reason for hiding this comment

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

probably not, moved out

Comment on lines +16 to +17
@mouseenter="onJobEnter(job.id)"
@mouseleave="onJobLeave(job.id)"
Copy link
Contributor

Choose a reason for hiding this comment

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

@coderabbitai can we add custom args to useElementHover for this use-case?

Comment on lines 1 to 76
<template>
<div class="flex h-full flex-col">
<div v-if="activeJobItems.length" class="flex flex-col gap-2 px-2">
<AssetsListCard
v-for="job in activeJobItems"
:key="job.id"
:class="getJobCardClass()"
:preview-url="job.iconImageUrl"
:preview-alt="job.title"
:icon-name="job.iconName"
:icon-class="getJobIconClass(job)"
:primary-text="job.title"
:secondary-text="job.meta"
:progress-total-percent="job.progressTotalPercent"
:progress-current-percent="job.progressCurrentPercent"
@mouseenter="onJobEnter(job.id)"
@mouseleave="onJobLeave(job.id)"
@click.stop
>
<template
v-if="hoveredJobId === job.id && getJobActions(job).length"
#actions
>
<Button
v-for="action in getJobActions(job)"
:key="action.key"
:variant="action.variant"
size="icon"
:aria-label="action.label"
@click.stop="handleJobAction(action, job)"
>
<i :class="action.icon" class="size-4" />
</Button>
</template>
</AssetsListCard>
</div>

<div
v-if="assets.length"
:class="cn('px-2', activeJobItems.length && 'mt-2')"
>
<div
class="flex items-center py-2 text-sm font-normal leading-normal text-muted-foreground font-inter"
>
{{ t('sideToolbar.generatedAssetsHeader') }}
</div>
</div>

<VirtualGrid
class="flex-1"
:items="assetItems"
:grid-style="listGridStyle"
@approach-end="emit('approach-end')"
>
<template #item="{ item }">
<AssetsListCard
role="button"
tabindex="0"
:aria-label="
t('assetBrowser.ariaLabel.assetCard', {
name: item.asset.name,
type: getMediaTypeFromFilename(item.asset.name)
})
"
:class="getAssetCardClass(isSelected(item.asset.id))"
:preview-url="item.asset.preview_url"
:preview-alt="item.asset.name"
:icon-name="getAssetIconName(item.asset)"
:primary-text="getAssetPrimaryText(item.asset)"
:secondary-text="getAssetSecondaryText(item.asset)"
@click.stop="emit('select-asset', item.asset)"
/>
</template>
</VirtualGrid>
</div>
</template>
Copy link
Contributor

Choose a reason for hiding this comment

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

That's good, is there no scrollbar in the active jobs when it overflows?

Comment on lines 32 to 41
<Button
v-for="action in getJobActions(job)"
:key="action.key"
:variant="action.variant"
size="icon"
:aria-label="action.label"
@click.stop="runCancelJob(job)"
>
<i :class="action.icon" class="size-4" />
</Button>
Copy link
Contributor

Choose a reason for hiding this comment

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

@benceruleanlu This is true right? It's always runCancelJob(job) as the click action? Is that intended?

Comment on lines +99 to +105
<AssetsSidebarListView
v-if="isListView"
:assets="displayAssets"
:is-selected="isSelected"
@select-asset="handleAssetSelect"
@approach-end="handleApproachEnd"
/>
Copy link
Contributor

Choose a reason for hiding this comment

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

@coderabbitai make a tracking issue for this and assign to Ben please

variant: 'destructive' | 'secondary' | 'textonly'
}

export function useJobActions() {
Copy link
Contributor

Choose a reason for hiding this comment

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

The useJobActions still doesn't take the job as an argument, I might be misunderstanding.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is there any way to move the state of the progress bar into the composable?

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @src/components/sidebar/tabs/AssetsSidebarListView.vue:
- Around line 141-145: The isActiveJobState function in
AssetsSidebarListView.vue duplicates the active-state logic defined as
cancellableStates in useJobActions.ts; remove the local function and instead
import and reuse the shared logic by either exporting a helper
(isActiveJobState) or a shared constant (cancellableStates) from
useJobActions.ts, or call the existing canCancelJob/cancellableStates-based
function there; update AssetsSidebarListView.vue to import and use that exported
helper/constant so both components share the same source of truth.
- Around line 188-195: getJobIconClass currently builds an array to possibly
push a single class then joins it; simplify by returning the conditional class
directly: check whether job.iconImageUrl is falsy and the resolved iconName
(job.iconName ?? iconForJobState(job.state)) equals iconForJobState('pending'),
and if so return 'animate-spin', otherwise return undefined; update references
to getJobIconClass, job.iconName, job.iconImageUrl, iconForJobState and
job.state accordingly.
- Around line 116-119: Replace the manual hover tracking by removing the
hoveredJobId ref and the onJobEnter/onJobLeave handlers and instead use VueUse's
useElementHover: create a hover composable per job item (via useElementHover)
and bind its returned isHovered reactive to the template element ref for each
job in the list; update usages of hoveredJobId (e.g., any class or conditional
rendering) to use the per-item isHovered value and remove related event
listeners so hover state is derived from useElementHover.

In @src/composables/queue/useJobActions.ts:
- Around line 25-28: Replace the mutable array and arrow function with immutable
const assertion and a function declaration: change cancellableStates to a
readonly tuple using a const assertion (cancellableStates =
['pending','initialization','running'] as const) and refactor the arrow function
canCancelJob into a normal function declaration function canCancelJob(job:
JobListItem): boolean { return job.showClear !== false && (cancellableStates as
readonly JobState[]).includes(job.state); } so the list is immutable and the
pure predicate is a declared function for readability and hoisting.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 434ee52 and 578b8fb.

📒 Files selected for processing (3)
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
  • src/platform/assets/utils/mediaIconUtil.ts
🧰 Additional context used
📓 Path-based instructions (17)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

Files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: TypeScript files must use exclusive TypeScript; no new JavaScript files
Use VueUse functions for performance-enhancing styles
Use es-toolkit for utility functions
Implement proper error handling in Vue components and async code

Files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{ts,tsx,vue}: Use separate import type statements; avoid inline type imports mixed with value imports
ESLint rules must enforce Vue + TypeScript rules, no floating promises, no unused imports, and i18n raw text restrictions in templates
Never use any type or as any type assertions; use proper TypeScript types
Keep functions short and functional; minimize nesting with early returns and reduce arrow anti-patterns
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions over function expressions; use function declarations when possible
Write expressive, self-documenting code; minimize unnecessary comments and avoid redundant comments
Ask 'is there a simpler way?' when writing code; use refactoring to make complex code simpler
Watch out for Code Smells and refactor to avoid them

Files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
**/*.{ts,tsx,vue,js,jsx,json,css,md}

📄 CodeRabbit inference engine (AGENTS.md)

Format code with Prettier using 2-space indent, single quotes, no trailing semicolons, 80-character width

Files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
{src/**/*.{ts,tsx,vue},**/*.test.ts}

📄 CodeRabbit inference engine (AGENTS.md)

Use vue-i18n in Composition API for string literals; place translation entries in src/locales/en/main.json and use i18n plurals system

Files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Minimize surface area (exported values) of each module and composable

Files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/queue/useJobActions.ts
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/composables/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Composables must follow the naming convention useXyz.ts

Files:

  • src/composables/queue/useJobActions.ts
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Vue components must be named in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
**/*.vue

📄 CodeRabbit inference engine (AGENTS.md)

**/*.vue: Vue 3.5+ components must use TypeScript with Composition API and <script setup lang="ts">
Use Tailwind 4 for styling; avoid <style> blocks in Vue components
Avoid new usage of PrimeVue components
Never use dark: Tailwind variant; use semantic values from style.css theme (e.g., bg-node-component-surface)
Use cn() utility from '@/utils/tailwindUtil' for merging class names; never use :class="[]"
Never use !important or ! prefix for Tailwind classes; find and fix interfering !important classes instead
Use default prop declaration with destructuring in Vue 3.5 TypeScript style; avoid withDefaults and runtime props
Prefer useModel over separate prop and emit definitions in Vue components
Be judicious with addition of new refs and state in Vue; use props directly, computed instead of watch, useModel instead of prop+emit when appropriate
Use provide/inject for dependency injection only when appropriate; prefer Store or shared composable for simplicity
Utilize Vue 3 Teleport component when needed for portal-style rendering
Use Suspense for async components in Vue 3

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
🧠 Learnings (37)
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/platform/assets/utils/mediaIconUtil.ts
  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-08T22:30:03.686Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T22:30:03.686Z
Learning: Applies to src/composables/**/*.ts : Composables must follow the naming convention useXyz.ts

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2026-01-08T22:30:03.686Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T22:30:03.686Z
Learning: Applies to **/*.{ts,tsx,vue} : Keep functions short and functional; minimize nesting with early returns and reduce arrow anti-patterns

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2026-01-08T22:30:03.686Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T22:30:03.686Z
Learning: Applies to **/*.{ts,tsx,vue} : Ask 'is there a simpler way?' when writing code; use refactoring to make complex code simpler

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-18T16:03:09.642Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:09.642Z
Learning: In the ComfyUI frontend queue system (src/stores/queueStore.ts), the `useQueuePendingTaskCountStore().count` includes the currently executing task. When count = 1, there is only the active/running task with no pending tasks. When count > 1, there is an active task plus pending tasks waiting in the queue. The "Clear Pending Tasks" button should only be enabled when count > 1 to avoid clearing the currently running task, which should be handled by the "Cancel current run" button instead.

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2026-01-08T22:30:03.686Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T22:30:03.686Z
Learning: Applies to **/*.{ts,tsx,vue} : Avoid mutable state; prefer immutability and assignment at point of declaration

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Sidebar component with Drawer

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-08T22:30:03.686Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T22:30:03.686Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Use VueUse functions for performance-enhancing styles

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-08T22:30:03.686Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T22:30:03.686Z
Learning: Applies to **/*.vue : Utilize Vue 3 Teleport component when needed for portal-style rendering

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-08T22:30:03.686Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T22:30:03.686Z
Learning: Applies to **/*.vue : Be judicious with addition of new refs and state in Vue; use props directly, computed instead of watch, useModel instead of prop+emit when appropriate

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-08T22:30:03.686Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T22:30:03.686Z
Learning: Applies to **/*.{ts,tsx,vue} : Watch out for Code Smells and refactor to avoid them

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Prefer emit/event-name for state changes over other communication patterns

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Implement lifecycle hooks with onMounted, onUpdated, etc.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-08T22:30:03.686Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-08T22:30:03.686Z
Learning: Applies to **/*.vue : Use cn() utility from '@/utils/tailwindUtil' for merging class names; never use :class="[]"

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-08T02:26:18.357Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7893
File: src/components/button/IconGroup.vue:5-6
Timestamp: 2026-01-08T02:26:18.357Z
Learning: In components that use the cn utility from '@/utils/tailwindUtil' with tailwind-merge, rely on the behavior that conflicting Tailwind classes are resolved by keeping the last one. For example, cn('base-classes bg-default', propClass) will have any conflicting background class from propClass override bg-default. This additive pattern is intentional and aligns with the shadcn-ui convention; ensure you document or review expectations accordingly in Vue components.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/*.{vue,ts,tsx} : Follow Vue 3 composition API style guide

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
🧬 Code graph analysis (2)
src/platform/assets/utils/mediaIconUtil.ts (1)
src/platform/assets/schemas/mediaAssetSchema.ts (1)
  • MediaKind (7-7)
src/composables/queue/useJobActions.ts (3)
src/composables/useErrorHandling.ts (1)
  • useErrorHandling (52-112)
src/composables/queue/useJobMenu.ts (1)
  • useJobMenu (43-359)
src/types/queue.ts (1)
  • JobState (4-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
  • GitHub Check: setup
  • GitHub Check: lint-and-format
  • GitHub Check: test
  • GitHub Check: collect
🔇 Additional comments (6)
src/platform/assets/utils/mediaIconUtil.ts (1)

1-14: LGTM!

The utility function is well-structured, type-safe, and follows functional programming principles. The icon mapping is clear and uses proper Lucide icon classes.

src/composables/queue/useJobActions.ts (2)

8-23: LGTM!

The JobAction type and cancelAction definition are well-structured. The use of i18n for the label follows best practices.


30-38: LGTM!

The error handling wrapper and composable return structure are correctly implemented, providing a clean public API for job actions.

src/components/sidebar/tabs/AssetsSidebarListView.vue (3)

1-39: LGTM!

The active jobs template section is well-structured with proper accessibility attributes, semantic styling, and correct Vue 3 patterns. The use of @click.stop appropriately prevents event bubbling.


41-81: LGTM!

The generated assets section demonstrates excellent accessibility practices with proper ARIA labels, keyboard navigation support, and semantic markup. The i18n integration and event emission patterns are correct.


147-176: LGTM!

The asset helper functions follow best practices with function declarations, proper use of the cn() utility, and clear fallback logic in getAssetSecondaryText.

Comment on lines 116 to 119
const { t } = useI18n()
const { jobItems } = useJobList()
const { cancelAction, canCancelJob, runCancelJob } = useJobActions()
const hoveredJobId = ref<string | null>(null)
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider using VueUse for hover state management.

The manual hover state tracking with hoveredJobId ref and event handlers could be replaced with VueUse's useElementHover composable for better consistency with the codebase guidelines.

As per coding guidelines, prefer existing VueUse composables over manually managing event listeners. This would eliminate the need for onJobEnter and onJobLeave handlers.

🤖 Prompt for AI Agents
In @src/components/sidebar/tabs/AssetsSidebarListView.vue around lines 116 -
119, Replace the manual hover tracking by removing the hoveredJobId ref and the
onJobEnter/onJobLeave handlers and instead use VueUse's useElementHover: create
a hover composable per job item (via useElementHover) and bind its returned
isHovered reactive to the template element ref for each job in the list; update
usages of hoveredJobId (e.g., any class or conditional rendering) to use the
per-item isHovered value and remove related event listeners so hover state is
derived from useElementHover.

Comment on lines +188 to +195
function getJobIconClass(job: JobListItem): string | undefined {
const classes = []
const iconName = job.iconName ?? iconForJobState(job.state)
if (!job.iconImageUrl && iconName === iconForJobState('pending')) {
classes.push('animate-spin')
}
return classes.length ? classes.join(' ') : undefined
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider simplifying the class logic.

The array construction and join pattern in getJobIconClass could be simplified since only one class is conditionally added.

♻️ Optional simplification
 function getJobIconClass(job: JobListItem): string | undefined {
-  const classes = []
   const iconName = job.iconName ?? iconForJobState(job.state)
   if (!job.iconImageUrl && iconName === iconForJobState('pending')) {
-    classes.push('animate-spin')
+    return 'animate-spin'
   }
-  return classes.length ? classes.join(' ') : undefined
+  return undefined
 }
🤖 Prompt for AI Agents
In @src/components/sidebar/tabs/AssetsSidebarListView.vue around lines 188 -
195, getJobIconClass currently builds an array to possibly push a single class
then joins it; simplify by returning the conditional class directly: check
whether job.iconImageUrl is falsy and the resolved iconName (job.iconName ??
iconForJobState(job.state)) equals iconForJobState('pending'), and if so return
'animate-spin', otherwise return undefined; update references to
getJobIconClass, job.iconName, job.iconImageUrl, iconForJobState and job.state
accordingly.

Comment on lines 25 to 28
const cancellableStates: JobState[] = ['pending', 'initialization', 'running']

const canCancelJob = (job: JobListItem): boolean =>
job.showClear !== false && cancellableStates.includes(job.state)
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Prefer function declaration and const assertion for immutability.

Consider refactoring for consistency with coding guidelines:

  • Use function declaration instead of arrow function for the pure function canCancelJob
  • Add const assertion to cancellableStates for better immutability
♻️ Proposed refactor
-const cancellableStates: JobState[] = ['pending', 'initialization', 'running']
+const cancellableStates = ['pending', 'initialization', 'running'] as const

-const canCancelJob = (job: JobListItem): boolean =>
-  job.showClear !== false && cancellableStates.includes(job.state)
+function canCancelJob(job: JobListItem): boolean {
+  return job.showClear !== false && cancellableStates.includes(job.state)
+}

Based on learnings, prefer function declarations for pure functions to improve readability and hoisting clarity.

📝 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.

Suggested change
const cancellableStates: JobState[] = ['pending', 'initialization', 'running']
const canCancelJob = (job: JobListItem): boolean =>
job.showClear !== false && cancellableStates.includes(job.state)
const cancellableStates = ['pending', 'initialization', 'running'] as const
function canCancelJob(job: JobListItem): boolean {
return job.showClear !== false && cancellableStates.includes(job.state)
}
🤖 Prompt for AI Agents
In @src/composables/queue/useJobActions.ts around lines 25 - 28, Replace the
mutable array and arrow function with immutable const assertion and a function
declaration: change cancellableStates to a readonly tuple using a const
assertion (cancellableStates = ['pending','initialization','running'] as const)
and refactor the arrow function canCancelJob into a normal function declaration
function canCancelJob(job: JobListItem): boolean { return job.showClear !==
false && (cancellableStates as readonly JobState[]).includes(job.state); } so
the list is immutable and the pure predicate is a declared function for
readability and hoisting.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @src/components/sidebar/tabs/AssetsSidebarListView.vue:
- Around line 148-152: isActiveJobState duplicates the cancellableStates list
from useJobActions.ts; centralize the definition to avoid divergence by
exporting a shared constant (e.g., ACTIVE_JOB_STATES) and using it in both
places. Update useJobActions.ts to export the constant (or move it to a shared
file like src/types/queue.ts or src/constants/queue.ts), then replace the local
cancellableStates/reference in useJobActions and replace isActiveJobState in
AssetsSidebarListView.vue to check membership against the exported
ACTIVE_JOB_STATES (or import from useJobActions if you choose that location).
Ensure types remain JobState[] and adjust imports accordingly.
- Around line 141-146: The listGridStyle object is static and should be declared
once at module scope instead of inside the component; move the const
listGridStyle declaration out of the component definition to the top-level of
AssetsSidebarListView.vue (above the export default), keep the exact object
shape and leave all usages inside the component intact, and remove the
in-component declaration so instances no longer recreate it on each render.

In @src/composables/queue/useJobActions.ts:
- Around line 23-29: Move the purely static array cancellableStates out of the
composable and define it as a module-level constant named cancellableStates:
JobState[] = ['pending','initialization','running'] to avoid recreating it on
each invocation; for cancelAction (symbol cancelAction) since it depends on t()
from useI18n(), either keep it inside the composable or convert it to a small
factory function (e.g., createCancelAction(t): JobAction) that builds and
returns the object so the static shape is defined outside while still allowing
localization to be injected.
📜 Review details

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 578b8fb and 0f02b9f.

📒 Files selected for processing (2)
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
  • src/composables/queue/useJobActions.ts
🧰 Additional context used
📓 Path-based instructions (13)
src/**/*.{vue,ts}

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.{vue,ts}: Leverage VueUse functions for performance-enhancing styles
Implement proper error handling
Use vue-i18n in composition API for any string literals. Place new translation entries in src/locales/en/main.json

Leverage VueUse functions for performance-enhancing utilities

Files:

  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/*.ts

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.ts: Use es-toolkit for utility functions
Use TypeScript for type safety

src/**/*.ts: Minimize the surface area (exported values) of each module and composable
Use es-toolkit for utility functions

Files:

  • src/composables/queue/useJobActions.ts
src/**/{services,composables}/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/{services,composables}/**/*.{ts,tsx}: Use api.apiURL() for backend endpoints instead of constructing URLs directly
Use api.fileURL() for static file access instead of constructing URLs directly

Files:

  • src/composables/queue/useJobActions.ts
src/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/*.{ts,tsx,vue}: Sanitize HTML with DOMPurify to prevent XSS attacks
Avoid using @ts-expect-error; use proper TypeScript types instead
Use es-toolkit for utility functions instead of other utility libraries
Implement proper TypeScript types throughout the codebase

src/**/*.{ts,tsx,vue}: Use separate import type statements; do not mix inline type imports in the same statement
Sort and group imports by plugin; run pnpm format before committing
Derive component types using vue-component-type-helpers (ComponentProps, ComponentSlots) instead of separate type files
Code should be well-designed with clear names for everything; write code that is expressive and self-documenting
Avoid redundant comments and clean up code as you go; comments should explain why, not what
Ask if there is a simpler way to implement functionality; refactor complex code to simplify it
Minimize nesting depth (e.g., if () { ... } or for () { ... }); watch for arrow anti-pattern
Watch out for code smells and refactor to avoid them
Never use any type; use proper TypeScript types
Never use as any type assertions; fix the underlying type issue instead
Indent with 2 spaces; use single quotes; no trailing semicolons; max line width 80 (per .prettierrc)
Complex type definitions used in multiple related places should be extracted and named for reuse
Implement proper error handling

Files:

  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/{composables,components}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Clean up subscriptions in state management to prevent memory leaks

Files:

  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/**/{components,composables}/**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Use vue-i18n for ALL user-facing strings by adding them to src/locales/en/main.json

Files:

  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/composables/**/*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables using the useXyz.ts pattern

Files:

  • src/composables/queue/useJobActions.ts
src/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

src/**/*.{ts,tsx}: Keep functions short and functional; use function declarations instead of function expressions when possible
Avoid mutable state; prefer immutability and assignment at point of declaration
Favor pure functions, especially testable ones

Files:

  • src/composables/queue/useJobActions.ts
src/**/*.vue

📄 CodeRabbit inference engine (.github/copilot-instructions.md)

src/**/*.vue: Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)
Use setup() function for component logic
Utilize ref and reactive for reactive state
Implement computed properties with computed()
Use watch and watchEffect for side effects
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection
Use vue 3.5 style of default prop declaration
Use Tailwind CSS for styling
Implement proper props and emits definitions
Utilize Vue 3's Teleport component when needed
Use Suspense for async components
Follow Vue 3 style guide and naming conventions

src/**/*.vue: Use Vue 3 Single File Components (SFCs) with Composition API only; never use Options API
Use <script setup lang="ts"> syntax for component logic
Use Tailwind 4 utility classes for styling; avoid <style> blocks in Vue components
Do not use the dark: Tailwind variant; use semantic values from style.css theme instead (e.g., bg-node-component-surface)
Use cn() utility from @/utils/tailwindUtil for merging class names; never use :class="[]" syntax
Never use !important or the ! prefix for Tailwind classes; find and fix interfering classes instead
Use Tailwind fraction utilities instead of arbitrary percentages (e.g., w-4/5 instead of w-[80%], w-1/2 instead of w-[50%])
Use Vue 3.5 TypeScript style default prop declaration with destructuring; avoid withDefaults and runtime props
Use defineModel for v-model bindings instead of separately defining props and emits
Prefer reactive props destructuring over const props = defineProps<...>
Define slots via template usage, not defineSlots
Use same-name shorthand for slot prop bindings (e.g., :isExpanded instead of :is-expanded="isExpanded")
Use ref for reactive state, computed() for computed properties, and watch/watchEffect for side effects
Avoid using ref and watch t...

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.vue

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.vue: Use setup() function in Vue 3 Composition API
Destructure props using Vue 3.5 style in Vue components
Use ref/reactive for state management in Vue 3 Composition API
Implement computed() for derived state in Vue 3 Composition API
Use provide/inject for dependency injection in Vue components
Prefer emit/@event-name for state changes over other communication patterns
Use defineExpose only for imperative operations (such as form.validate(), modal.open())
Replace PrimeVue Dropdown component with Select
Replace PrimeVue OverlayPanel component with Popover
Replace PrimeVue Calendar component with DatePicker
Replace PrimeVue InputSwitch component with ToggleSwitch
Replace PrimeVue Sidebar component with Drawer
Replace PrimeVue Chips component with AutoComplete with multiple enabled
Replace PrimeVue TabMenu component with Tabs without panels
Replace PrimeVue Steps component with Stepper without panels
Replace PrimeVue InlineMessage component with Message
Extract complex conditionals to computed properties
Implement cleanup for async operations in Vue components
Use lifecycle hooks: onMounted, onUpdated in Vue 3 Composition API
Use Teleport/Suspense when needed for component rendering
Define proper props and emits definitions in Vue components

Name Vue components in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.{vue,css}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,css}: Use Tailwind CSS only for styling (no custom CSS)
Use the correct tokens from style.css in the design system package

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
src/components/**/*.{vue,ts,js}

📄 CodeRabbit inference engine (src/components/CLAUDE.md)

src/components/**/*.{vue,ts,js}: Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners
Use useIntersectionObserver for visibility detection instead of custom scroll handlers
Use vue-i18n for ALL UI strings

Files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
🧠 Learnings (36)
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/composables/**/*.ts : Name composables using the `useXyz.ts` pattern

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-11-24T19:47:34.324Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:34.324Z
Learning: Applies to src/**/{composables,components}/**/*.{ts,tsx,vue} : Clean up subscriptions in state management to prevent memory leaks

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-18T16:03:09.642Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:09.642Z
Learning: In the ComfyUI frontend queue system (src/stores/queueStore.ts), the `useQueuePendingTaskCountStore().count` includes the currently executing task. When count = 1, there is only the active/running task with no pending tasks. When count > 1, there is an active task plus pending tasks waiting in the queue. The "Clear Pending Tasks" button should only be enabled when count > 1 to avoid clearing the currently running task, which should be handled by the "Cancel current run" button instead.

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Ask if there is a simpler way to implement functionality; refactor complex code to simplify it

Applied to files:

  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{ts,tsx} : Avoid mutable state; prefer immutability and assignment at point of declaration

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{ts,tsx} : Favor pure functions, especially testable ones

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{ts,tsx} : Keep functions short and functional; use function declarations instead of function expressions when possible

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-09T03:39:54.501Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7169
File: src/platform/remote/comfyui/jobs/jobTypes.ts:1-107
Timestamp: 2025-12-09T03:39:54.501Z
Learning: In the ComfyUI_frontend project, Zod is on v3.x. Do not suggest Zod v4 standalone validators (z.uuid, z.ulid, z.cuid2, z.nanoid) until an upgrade to Zod 4 is performed. When reviewing TypeScript files (e.g., src/platform/remote/comfyui/jobs/jobTypes.ts) validate against Zod 3 capabilities and avoid introducing v4-specific features; flag any proposal to upgrade or incorporate v4-only validators and propose staying with compatible 3.x patterns.

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-13T11:03:11.264Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7416
File: src/stores/imagePreviewStore.ts:5-7
Timestamp: 2025-12-13T11:03:11.264Z
Learning: In the ComfyUI_frontend repository, lint rules require keeping 'import type' statements separate from non-type imports, even if importing from the same module. Do not suggest consolidating them into a single import statement. Ensure type imports remain on their own line (import type { ... } from 'module') and regular imports stay on separate lines.

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-17T00:40:09.635Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.stories.ts:45-55
Timestamp: 2025-12-17T00:40:09.635Z
Learning: Prefer pure function declarations over function expressions (e.g., use function foo() { ... } instead of const foo = () => { ... }) for pure functions in the repository. Function declarations are more functional-leaning, offer better hoisting clarity, and can improve readability and tooling consistency. Apply this guideline across TypeScript files in Comfy-Org/ComfyUI_frontend, including story and UI component code, except where a function expression is semantically required (e.g., callbacks, higher-order functions with closures).

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-30T22:22:33.836Z
Learnt from: kaili-yang
Repo: Comfy-Org/ComfyUI_frontend PR: 7805
File: src/composables/useCoreCommands.ts:439-439
Timestamp: 2025-12-30T22:22:33.836Z
Learning: When accessing reactive properties from Pinia stores in TypeScript files, avoid using .value on direct property access (e.g., useStore().isOverlayExpanded). Pinia auto-wraps refs when accessed directly, returning the primitive value. The .value accessor is only needed when destructuring store properties or when using storeToRefs().

Applied to files:

  • src/composables/queue/useJobActions.ts
📚 Learning: 2025-12-11T12:25:15.470Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 7358
File: src/components/dialog/content/signin/SignUpForm.vue:45-54
Timestamp: 2025-12-11T12:25:15.470Z
Learning: This repository uses CI automation to format code (pnpm format). Do not include manual formatting suggestions in code reviews for Comfy-Org/ComfyUI_frontend. If formatting issues are detected, rely on the CI formatter or re-run pnpm format. Focus reviews on correctness, readability, performance, accessibility, and maintainability rather than style formatting.

Applied to files:

  • src/composables/queue/useJobActions.ts
  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Replace PrimeVue Sidebar component with Drawer

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use existing VueUse composables (such as useElementHover) instead of manually managing event listeners

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing styles

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{vue,ts} : Leverage VueUse functions for performance-enhancing utilities

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.{vue,ts,js} : Use useIntersectionObserver for visibility detection instead of custom scroll handlers

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize ref and reactive for reactive state

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Utilize Vue 3's Teleport component when needed

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.vue : Use `ref` for reactive state, `computed()` for computed properties, and `watch`/`watchEffect` for side effects

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-18T16:03:02.066Z
Learnt from: henrikvilhelmberglund
Repo: Comfy-Org/ComfyUI_frontend PR: 7617
File: src/components/actionbar/ComfyActionbar.vue:301-308
Timestamp: 2025-12-18T16:03:02.066Z
Learning: In the ComfyUI frontend queue system, useQueuePendingTaskCountStore().count indicates the number of tasks in the queue, where count = 1 means a single active/running task and count > 1 means there are pending tasks in addition to the active task. Therefore, in src/components/actionbar/ComfyActionbar.vue, enable the 'Clear Pending Tasks' button only when count > 1 to avoid clearing the currently running task. The active task should be canceled using the 'Cancel current run' button instead. This rule should be enforced via a conditional check on the queue count, with appropriate disabled/aria-disabled states for accessibility, and tests should verify behavior for count = 1 and count > 1.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Follow Vue 3 style guide and naming conventions

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.vue : Avoid using `ref` and `watch` together if a `computed` would work instead

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:45.616Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/components/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:45.616Z
Learning: Applies to src/components/**/*.vue : Use ref/reactive for state management in Vue 3 Composition API

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.vue : Be judicious with state additions: prefer props, avoid `computed` for simple values, use `computed` instead of `watch` for derived values

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.{ts,tsx,vue} : Watch out for code smells and refactor to avoid them

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-09T21:40:12.361Z
Learnt from: benceruleanlu
Repo: Comfy-Org/ComfyUI_frontend PR: 7297
File: src/components/actionbar/ComfyActionbar.vue:33-43
Timestamp: 2025-12-09T21:40:12.361Z
Learning: In Vue single-file components, allow inline Tailwind CSS class strings for static classes and avoid extracting them into computed properties solely for readability. Prefer keeping static class names inline for simplicity and performance. For dynamic or conditional classes, use Vue bindings (e.g., :class) to compose classes.

Applies to all Vue files in the repository (e.g., src/**/*.vue) where Tailwind utilities are used for static styling.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-09T00:50:57.103Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-09T00:50:57.103Z
Learning: Applies to src/**/*.vue : Use `cn()` utility from `@/utils/tailwindUtil` for merging class names; never use `:class="[]"` syntax

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2026-01-08T02:26:18.357Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7893
File: src/components/button/IconGroup.vue:5-6
Timestamp: 2026-01-08T02:26:18.357Z
Learning: In components that use the cn utility from '@/utils/tailwindUtil' with tailwind-merge, rely on the behavior that conflicting Tailwind classes are resolved by keeping the last one. For example, cn('base-classes bg-default', propClass) will have any conflicting background class from propClass override bg-default. This additive pattern is intentional and aligns with the shadcn-ui convention; ensure you document or review expectations accordingly in Vue components.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-11-24T19:47:02.860Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: .github/copilot-instructions.md:0-0
Timestamp: 2025-11-24T19:47:02.860Z
Learning: Applies to src/**/*.vue : Use the Vue 3 Composition API instead of the Options API when writing Vue components (exception: when overriding or extending PrimeVue components for compatibility)

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-09T03:49:52.828Z
Learnt from: christian-byrne
Repo: Comfy-Org/ComfyUI_frontend PR: 6300
File: src/platform/updates/components/WhatsNewPopup.vue:5-13
Timestamp: 2025-12-09T03:49:52.828Z
Learning: In Vue files across the ComfyUI_frontend repo, when a button is needed, prefer the repo's common button components from src/components/button/ (IconButton.vue, TextButton.vue, IconTextButton.vue) over plain HTML <button> elements. These components wrap PrimeVue with the project’s design system styling. Use only the common button components for consistency and theming, and import them from src/components/button/ as needed.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-16T22:26:49.463Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7537
File: src/components/ui/button/Button.vue:17-17
Timestamp: 2025-12-16T22:26:49.463Z
Learning: In Vue 3.5+ with <script setup>, when using defineProps<Props>() with partial destructuring (e.g., const { as = 'button', class: customClass = '' } = defineProps<Props>() ), props that are not destructured (e.g., variant, size) stay accessible by name in the template scope. This pattern is valid: you can destructure only a subset of props for convenience while referencing the remaining props directly in template expressions. Apply this guideline to Vue components across the codebase (all .vue files).

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-22T21:36:08.369Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/platform/cloud/subscription/components/PricingTable.vue:185-201
Timestamp: 2025-12-22T21:36:08.369Z
Learning: In Vue components, avoid creating single-use variants for common UI components (e.g., Button and other shared components). Aim for reusable variants that cover multiple use cases. It’s acceptable to temporarily mix variant props with inline Tailwind classes when a styling need is unique to one place, but plan and consolidate into shared, reusable variants as patterns emerge across the codebase.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-18T02:07:38.870Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7598
File: src/components/sidebar/tabs/AssetsSidebarTab.vue:131-131
Timestamp: 2025-12-18T02:07:38.870Z
Learning: Tailwind CSS v4 safe utilities (e.g., items-center-safe, justify-*-safe, place-*-safe) are allowed in Vue components under src/ and in story files. Do not flag these specific safe variants as invalid when reviewing code in src/**/*.vue or related stories.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-18T21:15:46.862Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7603
File: src/components/queue/QueueOverlayHeader.vue:49-59
Timestamp: 2025-12-18T21:15:46.862Z
Learning: In the ComfyUI_frontend repository, for Vue components, do not add aria-label to buttons that have visible text content (e.g., buttons containing <span> text). The visible text provides the accessible name. Use aria-label only for elements without visible labels (e.g., icon-only buttons). If a button has no visible label, provide a clear aria-label or associate with an aria-labelledby describing its action.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
📚 Learning: 2025-12-21T01:06:02.786Z
Learnt from: DrJKL
Repo: Comfy-Org/ComfyUI_frontend PR: 7649
File: src/components/graph/selectionToolbox/ColorPickerButton.vue:15-18
Timestamp: 2025-12-21T01:06:02.786Z
Learning: In Comfy-Org/ComfyUI_frontend, in Vue component files, when a filled icon is required (e.g., 'pi pi-circle-fill'), you may mix PrimeIcons with Lucide icons since Lucide lacks filled variants. This mixed usage is acceptable when one icon library does not provide an equivalent filled icon. Apply consistently across Vue components in the src directory where icons are used, and document the rationale when a mixed approach is chosen.

Applied to files:

  • src/components/sidebar/tabs/AssetsSidebarListView.vue
🧬 Code graph analysis (1)
src/composables/queue/useJobActions.ts (3)
src/composables/useErrorHandling.ts (1)
  • useErrorHandling (52-112)
src/composables/queue/useJobMenu.ts (1)
  • useJobMenu (43-359)
src/types/queue.ts (1)
  • JobState (4-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: deploy-and-comment
  • GitHub Check: lint-and-format
  • GitHub Check: setup
  • GitHub Check: collect
  • GitHub Check: test
🔇 Additional comments (2)
src/composables/queue/useJobActions.ts (1)

16-59: Well-structured composable with proper reactive patterns.

The composable correctly:

  • Accepts a reactive job parameter via MaybeRefOrGetter
  • Converts it to a computed ref for consistent reactivity
  • Derives cancellability state reactively
  • Wraps the cancel action with centralized error handling
  • Returns a clean interface with both state and actions
src/components/sidebar/tabs/AssetsSidebarListView.vue (1)

84-203: Well-structured component with good reactive patterns and accessibility.

The component demonstrates several strengths:

  • Proper Vue 3 Composition API usage with <script setup lang="ts">
  • Clean props/emits interface with proper TypeScript typing
  • Good accessibility with aria-label, role, and tabindex attributes
  • Effective use of VirtualGrid for rendering large asset lists efficiently
  • Pure, testable helper functions for asset display logic
  • Proper i18n integration for user-facing strings
  • Reactive hover state management with hoveredJobId feeding into useJobActions

The architecture cleanly separates active jobs (with cancel actions) from generated assets, with appropriate visual hierarchy.

Comment on lines +141 to +146
const listGridStyle = {
display: 'grid',
gridTemplateColumns: 'minmax(0, 1fr)',
padding: '0 0.5rem',
gap: '0.5rem'
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Move static grid style outside the component.

The listGridStyle object is static configuration that doesn't depend on reactive state. It gets recreated on every component instance but never changes. Extract it as a const outside the component for better performance.

♻️ Proposed refactor
 import { cn } from '@/utils/tailwindUtil'
 
+const LIST_GRID_STYLE = {
+  display: 'grid',
+  gridTemplateColumns: 'minmax(0, 1fr)',
+  padding: '0 0.5rem',
+  gap: '0.5rem'
+} as const
+
 const { assets, isSelected } = defineProps<{
   assets: AssetItem[]
   isSelected: (assetId: string) => boolean
 }>()
 
 // ... rest of setup
 
-const listGridStyle = {
-  display: 'grid',
-  gridTemplateColumns: 'minmax(0, 1fr)',
-  padding: '0 0.5rem',
-  gap: '0.5rem'
-}
-
 function isActiveJobState(state: JobState): boolean {

Then update line 56:

-      :grid-style="listGridStyle"
+      :grid-style="LIST_GRID_STYLE"

Based on coding guidelines preferring immutability and assignment at point of declaration.

🤖 Prompt for AI Agents
In @src/components/sidebar/tabs/AssetsSidebarListView.vue around lines 141 -
146, The listGridStyle object is static and should be declared once at module
scope instead of inside the component; move the const listGridStyle declaration
out of the component definition to the top-level of AssetsSidebarListView.vue
(above the export default), keep the exact object shape and leave all usages
inside the component intact, and remove the in-component declaration so
instances no longer recreate it on each render.

Comment on lines +148 to +152
function isActiveJobState(state: JobState): boolean {
return (
state === 'pending' || state === 'initialization' || state === 'running'
)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Eliminate code duplication with useJobActions.

The isActiveJobState function duplicates the cancellableStates logic from useJobActions.ts (line 29). Both define the same three states: pending, initialization, and running. If the definition of active/cancellable states changes, both locations would need updates.

♻️ Proposed refactor

Option 1: Export a shared constant from a common location

Create or use an existing constants file (e.g., src/types/queue.ts or src/constants/queue.ts):

// src/types/queue.ts or src/constants/queue.ts
export const ACTIVE_JOB_STATES: JobState[] = [
  'pending',
  'initialization',
  'running'
] as const

Then import and use in both files:

In useJobActions.ts:

+import { ACTIVE_JOB_STATES } from '@/types/queue'
+
 export function useJobActions(
   job: MaybeRefOrGetter<JobListItem | null | undefined>
 ) {
   // ...
   return (
     currentJob.showClear !== false &&
-    cancellableStates.includes(currentJob.state)
+    ACTIVE_JOB_STATES.includes(currentJob.state)
   )
 }

In AssetsSidebarListView.vue:

+import { ACTIVE_JOB_STATES } from '@/types/queue'
+
 function isActiveJobState(state: JobState): boolean {
-  return (
-    state === 'pending' || state === 'initialization' || state === 'running'
-  )
+  return ACTIVE_JOB_STATES.includes(state)
 }

Option 2: Import directly from useJobActions (if you export the constant)

This centralizes the definition in the composable that owns the logic.

This refactor improves maintainability by ensuring the definition of active/cancellable job states is managed in one place.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @src/components/sidebar/tabs/AssetsSidebarListView.vue around lines 148 -
152, isActiveJobState duplicates the cancellableStates list from
useJobActions.ts; centralize the definition to avoid divergence by exporting a
shared constant (e.g., ACTIVE_JOB_STATES) and using it in both places. Update
useJobActions.ts to export the constant (or move it to a shared file like
src/types/queue.ts or src/constants/queue.ts), then replace the local
cancellableStates/reference in useJobActions and replace isActiveJobState in
AssetsSidebarListView.vue to check membership against the exported
ACTIVE_JOB_STATES (or import from useJobActions if you choose that location).
Ensure types remain JobState[] and adjust imports accordingly.

Comment on lines +23 to +29
const cancelAction: JobAction = {
icon: 'icon-[lucide--x]',
label: t('sideToolbar.queueProgressOverlay.cancelJobTooltip'),
variant: 'destructive'
}

const cancellableStates: JobState[] = ['pending', 'initialization', 'running']
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Move static data outside the function for better performance.

Both cancelAction (lines 23-27) and cancellableStates (line 29) are static data that get recreated on every composable invocation. Moving them outside as constants would improve performance and align with immutability preferences.

♻️ Proposed refactor
+const CANCELLABLE_STATES: JobState[] = [
+  'pending',
+  'initialization',
+  'running'
+]
+
 export function useJobActions(
   job: MaybeRefOrGetter<JobListItem | null | undefined>
 ) {
   const { t } = useI18n()
   const { wrapWithErrorHandlingAsync } = useErrorHandling()
   const { cancelJob } = useJobMenu()
 
-  const cancelAction: JobAction = {
+  const cancelAction: JobAction = {
     icon: 'icon-[lucide--x]',
     label: t('sideToolbar.queueProgressOverlay.cancelJobTooltip'),
     variant: 'destructive'
   }
 
-  const cancellableStates: JobState[] = ['pending', 'initialization', 'running']
-
   const jobRef = computed(() => toValue(job) ?? null)
 
   const canCancelJob = computed(() => {
     const currentJob = jobRef.value
     if (!currentJob) {
       return false
     }
 
     return (
       currentJob.showClear !== false &&
-      cancellableStates.includes(currentJob.state)
+      CANCELLABLE_STATES.includes(currentJob.state)
     )
   })

Note: cancelAction could also be moved outside, but since it uses t() from useI18n(), it would need to be initialized differently (e.g., as a factory or kept as-is). The current implementation is acceptable if i18n reactivity is desired.

Based on coding guidelines emphasizing immutability and minimal mutable state.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @src/composables/queue/useJobActions.ts around lines 23 - 29, Move the purely
static array cancellableStates out of the composable and define it as a
module-level constant named cancellableStates: JobState[] =
['pending','initialization','running'] to avoid recreating it on each
invocation; for cancelAction (symbol cancelAction) since it depends on t() from
useI18n(), either keep it inside the composable or convert it to a small factory
function (e.g., createCancelAction(t): JobAction) that builds and returns the
object so the static shape is defined outside while still allowing localization
to be injected.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants