Skip to content

Conversation

@ric-yu
Copy link

@ric-yu ric-yu commented Dec 3, 2025

Summary

Migrate frontend from legacy /history, /history_v2, and /queue endpoints to the unified /jobs API with memory optimization and lazy loading.

Changes

  • What:
    • Replace three separate endpoints (/history, /history_v2, /queue) with unified /jobs API
    • Add Zod schemas for runtime validation of Jobs API responses
    • Implement lazy loading for workflow and full outputs via /jobs/{id} endpoint
    • Add synthetic priority assignment for queue ordering (pending > running > history)
    • Simplify abstraction layers (remove getWorkflowFromHistory wrapper)
    • Rename reconcileHistory to reconcileJobs for clarity
    • Use execution_start_time and execution_end_time from API for execution timing
    • Use workflowId from job instead of nested workflow.id
  • Breaking: Removes support for legacy /history and /history_v2 endpoints - requires backend Jobs API support

Review Focus

  1. Zod schema flexibility: Using .passthrough() to allow extra API fields - ensures forward compatibility but less strict validation
  2. Lazy loading in useJobMenu: openJobWorkflow and exportJobWorkflow now fetch from API on demand instead of accessing taskRef.workflow
  3. Priority computation: Synthetic priority ensures display order: pending (queued) → running → completed (history)
  4. Error reporting: Uses execution_error field from API for rich error dialogs

┆Issue is synchronized with this Notion page by Unito

env video
Core https://github.com/user-attachments/assets/099efe28-e88f-4449-9746-a8804ca22cce
Cloud https://github.com/user-attachments/assets/f7281447-48da-436b-b709-3117d4a490fb

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 3, 2025

📝 Walkthrough

Walkthrough

Consolidates history/queue handling into a unified Jobs API (JobListItem), removes legacy V1/V2 history adapters/types/fixtures/tests, adds jobs fetchers/types and reconcileJobs, updates composables/stores/components to use JobListItem, and introduces lazy-loading for full outputs and workflows.

Changes

Cohort / File(s) Summary
Browser test fixtures
browser_tests/fixtures/ComfyPage.ts, browser_tests/fixtures/utils/taskHistory.ts
Removed TaskHistory usage from ComfyPage and deleted the taskHistory fixture utility.
Removed legacy history modules
src/platform/remote/comfyui/history/...
Deleted V2→V1 adapter, V1/V2 fetchers, index entry, and V1/V2 type modules and re-exports.
Unified Jobs API (new)
src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts, src/platform/remote/comfyui/jobs/index.ts, src/platform/remote/comfyui/jobs/types/jobTypes.ts
Added fetchHistory, fetchQueue, fetchJobDetail, extractWorkflow and zod schemas/types for JobListItem/JobDetail/JobStatus.
Reconciliation & workflow routing
src/platform/remote/comfyui/history/reconciliation.ts, src/platform/workflow/cloud/getWorkflowFromHistory.ts, src/platform/workflow/cloud/index.ts
Replaced V1/V2 reconciliation with reconcileJobs; removed cloud getWorkflowFromHistory and its conditional export.
Core schema & scripts updated
src/schemas/apiSchema.ts, src/scripts/api.ts
Removed queue/history task schemas and exports; converted getQueue/getHistory to use JobListItem shapes.
Stores and Queue model refactor
src/stores/queueStore.ts, src/stores/assetsStore.ts
TaskItemImpl refactored to accept/return JobListItem; added toJob(), loadFullOutputs(), loadWorkflow(); mapHistoryToAssets and store reconciliation use JobListItem.
Composables: gallery & menu
src/composables/queue/useResultGallery.ts, src/composables/queue/useJobMenu.ts, src/composables/queue/useJobList.ts
useResultGallery now accepts optional fetchApi for lazy-loading full outputs; useJobMenu/getJobWorkflow uses fetchJobDetail/extractWorkflow; active workflow uses workflowId.
UI components & error reporting
src/components/queue/QueueProgressOverlay.vue, src/components/queue/job/useJobErrorReporting.ts, src/components/queue/job/JobDetailsPopover.stories.ts, src/components/queue/job/JobGroupsList.vue
Updated gallery opening to await lazy load, changed useResultGallery signature, migrated Task construction to JobListItem shape, and prioritized executionError for error dialogs; job workflow binding switched to workflowId.
New jobs public entry
src/platform/remote/comfyui/jobs/index.ts
Re-exports fetchHistory, fetchQueue, fetchJobDetail, extractWorkflow, and JobListItem/JobDetail types.
Scripts / UI runtime changes
src/scripts/ui.ts, src/scripts/api.ts
Relaxed list item types; getQueue/getHistory now return JobListItem-based structures and delegate to new jobs fetchers.
Workflow cloud removal
src/platform/workflow/cloud/index.ts
Removed conditional cloud history workflow export and cloud-specific getWorkflowFromHistory wiring.
Removed test fixtures
tests-ui/fixtures/historyFixtures.ts, tests-ui/fixtures/historySortingFixtures.ts
Deleted V1/V2 history fixture files.
Deleted legacy history tests
tests-ui/tests/platform/remote/comfyui/history/...
Removed tests for v2ToV1 adapter and fetchHistoryV1/fetchHistoryV2.
Tests updated to JobListItem flows
tests-ui/tests/... (many files)
Converted reconciliation, assetsStore, queueStore, workflow-loading, composable, and UI tests to use JobListItem, fetchJobDetail/extractWorkflow, lazy-loading, and updated TaskItemImpl mocks/constructors.
Result gallery & error-reporting tests
tests-ui/tests/composables/useResultGallery.test.ts, tests-ui/tests/components/queue/useJobErrorReporting.test.ts, tests-ui/tests/composables/useJobMenu.test.ts
Updated to exercise async lazy-loading, fetchJobDetail/extractWorkflow, executionError paths, and new item shapes.

Sequence Diagram(s)

(omitted)

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch ric-yu/use-jobs-api

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

@github-actions
Copy link

github-actions bot commented Dec 3, 2025

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 12/04/2025, 10:03:13 PM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@github-actions
Copy link

github-actions bot commented Dec 3, 2025

🎭 Playwright Test Results

Some tests failed

⏰ Completed at: 12/04/2025, 10:13:01 PM UTC

📈 Summary

  • Total Tests: 494
  • Passed: 480 ✅
  • Failed: 1 ❌
  • Flaky: 3 ⚠️
  • Skipped: 10 ⏭️

📊 Test Reports by Browser

  • chromium: View Report • ✅ 471 / ❌ 1 / ⚠️ 3 / ⏭️ 10
  • chromium-2x: View Report • ✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • chromium-0.5x: View Report • ✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0
  • mobile-chrome: View Report • ✅ 6 / ❌ 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 3, 2025

Bundle Size Report

Summary

  • Raw size: 17 MB baseline 17 MB — 🟢 -92 B
  • Gzip: 3.38 MB baseline 3.38 MB — 🔴 +192 B
  • Brotli: 2.59 MB baseline 2.59 MB — 🔴 +195 B
  • Bundles: 97 current • 97 baseline • 52 added / 52 removed

Category Glance
App Entry Points 🟢 -1.43 kB (3.2 MB) · Graph Workspace 🔴 +1.33 kB (974 kB) · UI Components 🔴 +1 B (173 kB) · Vendor & Third-Party ⚪ 0 B (8.56 MB) · Other ⚪ 0 B (3.81 MB) · Panels & Settings ⚪ 0 B (298 kB) · + 3 more

Per-category breakdown
App Entry Points — 3.2 MB (baseline 3.2 MB) • 🟢 -1.43 kB

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-DeLp86q3.js (removed) 2.97 MB 🟢 -2.97 MB 🟢 -619 kB 🟢 -471 kB
assets/index-DzK0oaRd.js (new) 2.97 MB 🔴 +2.97 MB 🔴 +619 kB 🔴 +471 kB
assets/index-B2k763To.js (new) 223 kB 🔴 +223 kB 🔴 +47.6 kB 🔴 +39.2 kB
assets/index-oWzbbKWA.js (removed) 223 kB 🟢 -223 kB 🟢 -47.6 kB 🟢 -39.2 kB
assets/index-4cceNtDN.js (new) 345 B 🔴 +345 B 🔴 +244 B 🔴 +234 B
assets/index-BfDUpDVW.js (removed) 345 B 🟢 -345 B 🟢 -245 B 🟢 -232 B

Status: 3 added / 3 removed

Graph Workspace — 974 kB (baseline 973 kB) • 🔴 +1.33 kB

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-BfRpMBBS.js (new) 974 kB 🔴 +974 kB 🔴 +188 kB 🔴 +143 kB
assets/GraphView-DUHej2wz.js (removed) 973 kB 🟢 -973 kB 🟢 -188 kB 🟢 -143 kB

Status: 1 added / 1 removed

Views & Navigation — 6.54 kB (baseline 6.54 kB) • ⚪ 0 B

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/UserSelectView-1LIASOHN.js (new) 6.54 kB 🔴 +6.54 kB 🔴 +2.14 kB 🔴 +1.9 kB
assets/UserSelectView-B3UZuD9F.js (removed) 6.54 kB 🟢 -6.54 kB 🟢 -2.14 kB 🟢 -1.9 kB

Status: 1 added / 1 removed

Panels & Settings — 298 kB (baseline 298 kB) • ⚪ 0 B

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CreditsPanel-Cz2DgghM.js (new) 21.4 kB 🔴 +21.4 kB 🔴 +5.15 kB 🔴 +4.5 kB
assets/CreditsPanel-xh_8Vse7.js (removed) 21.4 kB 🟢 -21.4 kB 🟢 -5.15 kB 🟢 -4.5 kB
assets/KeybindingPanel-D1ukYXYY.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +3.42 kB 🔴 +3.01 kB
assets/KeybindingPanel-D2vMn_ns.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -3.42 kB 🟢 -3.01 kB
assets/ExtensionPanel-Bl8A-90r.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.57 kB 🔴 +2.26 kB
assets/ExtensionPanel-BprhTVYs.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.57 kB 🟢 -2.26 kB
assets/AboutPanel-Bxl9dCIq.js (new) 9.16 kB 🔴 +9.16 kB 🔴 +2.46 kB 🔴 +2.21 kB
assets/AboutPanel-CERGVu6F.js (removed) 9.16 kB 🟢 -9.16 kB 🟢 -2.46 kB 🟢 -2.21 kB
assets/ServerConfigPanel-BTMpiTuz.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +1.83 kB 🔴 +1.63 kB
assets/ServerConfigPanel-Cg9qvRa5.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -1.83 kB 🟢 -1.63 kB
assets/UserPanel-B6P9evI7.js (removed) 6.23 kB 🟢 -6.23 kB 🟢 -1.72 kB 🟢 -1.5 kB
assets/UserPanel-BF82G2nE.js (new) 6.23 kB 🔴 +6.23 kB 🔴 +1.72 kB 🔴 +1.51 kB
assets/settings-BhbWhsRg.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BXTtSH4O.js 33.3 kB 33.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-C9Pzn-NG.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CCy2fA_h.js 27.3 kB 27.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CQpqEFfl.js 26.6 kB 26.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DHcnxypw.js 21.7 kB 21.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DhFTK9fY.js 25.1 kB 25.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DlT4t_ui.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-DRgSrIdD.js 24.2 kB 24.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-tjkeqiZq.js 21.1 kB 21.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

UI Components — 173 kB (baseline 173 kB) • 🔴 +1 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/Load3D.vue_vue_type_script_setup_true_lang-B1rTevRg.js (removed) 53.9 kB 🟢 -53.9 kB 🟢 -8.52 kB 🟢 -7.31 kB
assets/Load3D.vue_vue_type_script_setup_true_lang-CZLwmxr2.js (new) 53.9 kB 🔴 +53.9 kB 🔴 +8.52 kB 🔴 +7.31 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-C7uBH6jP.js (new) 47.6 kB 🔴 +47.6 kB 🔴 +10.3 kB 🔴 +8.9 kB
assets/WidgetSelect.vue_vue_type_script_setup_true_lang-Dpgo0oe-.js (removed) 47.6 kB 🟢 -47.6 kB 🟢 -10.3 kB 🟢 -8.9 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-BuI4h_oo.js (removed) 43.3 kB 🟢 -43.3 kB 🟢 -9.68 kB 🟢 -8.45 kB
assets/LazyImage.vue_vue_type_script_setup_true_lang-Dj8etgWZ.js (new) 43.3 kB 🔴 +43.3 kB 🔴 +9.68 kB 🔴 +8.46 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-BeN4glqw.js (new) 12.9 kB 🔴 +12.9 kB 🔴 +3.37 kB 🔴 +2.96 kB
assets/WidgetInputNumber.vue_vue_type_script_setup_true_lang-C97jZswi.js (removed) 12.9 kB 🟢 -12.9 kB 🟢 -3.37 kB 🟢 -2.98 kB
assets/ComfyQueueButton-BlloEJBZ.js (removed) 8.44 kB 🟢 -8.44 kB 🟢 -2.47 kB 🟢 -2.21 kB
assets/ComfyQueueButton-Bq6TRRWp.js (new) 8.44 kB 🔴 +8.44 kB 🔴 +2.47 kB 🔴 +2.21 kB
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-Dvs4GqqJ.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +818 B 🔴 +723 B
assets/WidgetLayoutField.vue_vue_type_script_setup_true_lang-VhqMWCTd.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -818 B 🟢 -716 B
assets/WidgetButton-DBkWxjh1.js (removed) 2.04 kB 🟢 -2.04 kB 🟢 -927 B 🟢 -810 B
assets/WidgetButton-DtJ3FQdA.js (new) 2.04 kB 🔴 +2.04 kB 🔴 +930 B 🔴 +810 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-DbXI8c90.js (new) 1.34 kB 🔴 +1.34 kB 🔴 +686 B 🔴 +593 B
assets/UserAvatar.vue_vue_type_script_setup_true_lang-DRxvgpU7.js (removed) 1.34 kB 🟢 -1.34 kB 🟢 -686 B 🟢 -597 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-DqIe-NWt.js (new) 897 B 🔴 +897 B 🔴 +501 B 🔴 +437 B
assets/MediaTitle.vue_vue_type_script_setup_true_lang-wnazr610.js (removed) 897 B 🟢 -897 B 🟢 -502 B 🟢 -466 B

Status: 9 added / 9 removed

Data & Services — 12.5 kB (baseline 12.5 kB) • ⚪ 0 B

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/keybindingService-B6-ax-p3.js (new) 7.51 kB 🔴 +7.51 kB 🔴 +1.83 kB 🔴 +1.58 kB
assets/keybindingService-GTE3H0Nn.js (removed) 7.51 kB 🟢 -7.51 kB 🟢 -1.84 kB 🟢 -1.58 kB
assets/serverConfigStore-8Q-d7nSR.js (new) 2.83 kB 🔴 +2.83 kB 🔴 +906 B 🔴 +787 B
assets/serverConfigStore-BIb40oOr.js (removed) 2.83 kB 🟢 -2.83 kB 🟢 -907 B 🟢 -799 B
assets/audioService-oSaKHWvy.js (new) 2.2 kB 🔴 +2.2 kB 🔴 +958 B 🔴 +823 B
assets/audioService-VhfttRv8.js (removed) 2.2 kB 🟢 -2.2 kB 🟢 -960 B 🟢 -824 B

Status: 3 added / 3 removed

Utilities & Hooks — 2.94 kB (baseline 2.94 kB) • ⚪ 0 B

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/audioUtils-DJaWX2Zh.js (removed) 1.41 kB 🟢 -1.41 kB 🟢 -653 B 🟢 -551 B
assets/audioUtils-DNQq2G9i.js (new) 1.41 kB 🔴 +1.41 kB 🔴 +651 B 🔴 +548 B
assets/mathUtil-CTARWQ-l.js 1.07 kB 1.07 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-CXKCRJ-m.js 460 B 460 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 1 added / 1 removed

Vendor & Third-Party — 8.56 MB (baseline 8.56 MB) • ⚪ 0 B

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-other-BZzgsWym.js (removed) 3.98 MB 🟢 -3.98 MB 🟢 -843 kB 🟢 -673 kB
assets/vendor-other-Cg_Zdkan.js (new) 3.98 MB 🔴 +3.98 MB 🔴 +843 kB 🔴 +673 kB
assets/vendor-primevue-3gHexYD_.js (removed) 1.96 MB 🟢 -1.96 MB 🟢 -336 kB 🟢 -202 kB
assets/vendor-primevue-6PYunpYp.js (new) 1.96 MB 🔴 +1.96 MB 🔴 +336 kB 🔴 +202 kB
assets/vendor-chart-9wBX72LU.js (new) 452 kB 🔴 +452 kB 🔴 +99.1 kB 🔴 +81.1 kB
assets/vendor-chart-DWRkrNy1.js (removed) 452 kB 🟢 -452 kB 🟢 -99.1 kB 🟢 -81 kB
assets/vendor-tiptap-Dil5QvFL.js (new) 232 kB 🔴 +232 kB 🔴 +45.7 kB 🔴 +37.7 kB
assets/vendor-tiptap-Dw558Ulu.js (removed) 232 kB 🟢 -232 kB 🟢 -45.7 kB 🟢 -37.7 kB
assets/vendor-vue-BAxR_hjK.js (new) 160 kB 🔴 +160 kB 🔴 +37.3 kB 🔴 +31.6 kB
assets/vendor-vue-CoO6TOrn.js (removed) 160 kB 🟢 -160 kB 🟢 -37.3 kB 🟢 -31.6 kB
assets/vendor-three-aR6ntw5X.js 1.37 MB 1.37 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-BZLod3g9.js 407 kB 407 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 5 added / 5 removed

Other — 3.81 MB (baseline 3.81 MB) • ⚪ 0 B

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/WidgetRecordAudio-BmGgu-l9.js (new) 20.4 kB 🔴 +20.4 kB 🔴 +5.24 kB 🔴 +4.63 kB
assets/WidgetRecordAudio-DKWed2hx.js (removed) 20.4 kB 🟢 -20.4 kB 🟢 -5.24 kB 🟢 -4.63 kB
assets/AudioPreviewPlayer-ClRIa2P-.js (new) 13.5 kB 🔴 +13.5 kB 🔴 +3.4 kB 🔴 +3.05 kB
assets/AudioPreviewPlayer-JjdGf0sL.js (removed) 13.5 kB 🟢 -13.5 kB 🟢 -3.4 kB 🟢 -3.03 kB
assets/WidgetGalleria-CjriiXG0.js (removed) 4.1 kB 🟢 -4.1 kB 🟢 -1.44 kB 🟢 -1.31 kB
assets/WidgetGalleria-DegcrpJy.js (new) 4.1 kB 🔴 +4.1 kB 🔴 +1.44 kB 🔴 +1.3 kB
assets/WidgetColorPicker-7gymymPQ.js (removed) 3.41 kB 🟢 -3.41 kB 🟢 -1.38 kB 🟢 -1.23 kB
assets/WidgetColorPicker-QFWeh6jc.js (new) 3.41 kB 🔴 +3.41 kB 🔴 +1.38 kB 🔴 +1.23 kB
assets/WidgetMarkdown-CALrvywN.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetMarkdown-CE_wqahE.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.28 kB 🔴 +1.12 kB
assets/WidgetAudioUI-BIyqYKHe.js (new) 2.82 kB 🔴 +2.82 kB 🔴 +1.12 kB 🔴 +1.01 kB
assets/WidgetAudioUI-BUqUJfV1.js (removed) 2.82 kB 🟢 -2.82 kB 🟢 -1.12 kB 🟢 -1.02 kB
assets/WidgetTextarea-CgXDzBt1.js (removed) 2.79 kB 🟢 -2.79 kB 🟢 -1.09 kB 🟢 -989 B
assets/WidgetTextarea-Dv2Zli9w.js (new) 2.79 kB 🔴 +2.79 kB 🔴 +1.09 kB 🔴 +977 B
assets/MediaVideoTop-BOywGJYE.js (new) 2.76 kB 🔴 +2.76 kB 🔴 +1.05 kB 🔴 +900 B
assets/MediaVideoTop-BpvqEylZ.js (removed) 2.76 kB 🟢 -2.76 kB 🟢 -1.05 kB 🟢 -900 B
assets/WidgetChart-B5pj9I2Z.js (new) 2.48 kB 🔴 +2.48 kB 🔴 +932 B 🔴 +816 B
assets/WidgetChart-DsbKXC7D.js (removed) 2.48 kB 🟢 -2.48 kB 🟢 -933 B 🟢 -816 B
assets/WidgetImageCompare-DsSEdNEV.js (new) 2.21 kB 🔴 +2.21 kB 🔴 +747 B 🔴 +661 B
assets/WidgetImageCompare-nVNi67CU.js (removed) 2.21 kB 🟢 -2.21 kB 🟢 -749 B 🟢 -662 B
assets/WidgetInputText-DXkr4qF5.js (removed) 1.99 kB 🟢 -1.99 kB 🟢 -916 B 🟢 -846 B
assets/WidgetInputText-WSyXHg0u.js (new) 1.99 kB 🔴 +1.99 kB 🔴 +917 B 🔴 +856 B
assets/MediaImageTop-BN0aEMtg.js (removed) 1.75 kB 🟢 -1.75 kB 🟢 -842 B 🟢 -719 B
assets/MediaImageTop-CRXVfJZI.js (new) 1.75 kB 🔴 +1.75 kB 🔴 +842 B 🔴 +716 B
assets/WidgetToggleSwitch-DkvdXJVp.js (removed) 1.58 kB 🟢 -1.58 kB 🟢 -759 B 🟢 -671 B
assets/WidgetToggleSwitch-DLslKEG2.js (new) 1.58 kB 🔴 +1.58 kB 🔴 +761 B 🔴 +668 B
assets/MediaImageBottom-B_7t2hCS.js (new) 1.57 kB 🔴 +1.57 kB 🔴 +737 B 🔴 +645 B
assets/MediaImageBottom-DLw-cmAF.js (removed) 1.57 kB 🟢 -1.57 kB 🟢 -742 B 🟢 -649 B
assets/MediaAudioBottom-D34dOs4O.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +738 B 🔴 +656 B
assets/MediaAudioBottom-D5-SPcC7.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -740 B 🟢 -657 B
assets/MediaVideoBottom-B-mGMwK8.js (removed) 1.52 kB 🟢 -1.52 kB 🟢 -739 B 🟢 -656 B
assets/MediaVideoBottom-Dk_ayoQ2.js (new) 1.52 kB 🔴 +1.52 kB 🔴 +737 B 🔴 +653 B
assets/Media3DBottom-CiipD5uR.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -729 B 🟢 -652 B
assets/Media3DBottom-CTutAXaH.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +730 B 🔴 +646 B
assets/Media3DTop-DrSU42wI.js (new) 1.49 kB 🔴 +1.49 kB 🔴 +764 B 🔴 +654 B
assets/Media3DTop-rRL2zxvb.js (removed) 1.49 kB 🟢 -1.49 kB 🟢 -764 B 🟢 -651 B
assets/MediaAudioTop-Bvdy9lZE.js (new) 1.46 kB 🔴 +1.46 kB 🔴 +737 B 🔴 +614 B
assets/MediaAudioTop-DX0t5RN3.js (removed) 1.46 kB 🟢 -1.46 kB 🟢 -738 B 🟢 -618 B
assets/WidgetSelect-BD8j8FSH.js (removed) 655 B 🟢 -655 B 🟢 -341 B 🟢 -287 B
assets/WidgetSelect-Pk8G2aUR.js (new) 655 B 🔴 +655 B 🔴 +343 B 🔴 +286 B
assets/WidgetInputNumber-BLINR4fo.js (new) 595 B 🔴 +595 B 🔴 +328 B 🔴 +274 B
assets/WidgetInputNumber-Bw65UlL_.js (removed) 595 B 🟢 -595 B 🟢 -328 B 🟢 -275 B
assets/Load3D-BdDgoHrg.js (new) 424 B 🔴 +424 B 🔴 +264 B 🔴 +222 B
assets/Load3D-CzDxotnG.js (removed) 424 B 🟢 -424 B 🟢 -264 B 🟢 -225 B
assets/WidgetLegacy-D17K1ny_.js (new) 364 B 🔴 +364 B 🔴 +236 B 🔴 +194 B
assets/WidgetLegacy-y_hcoFgT.js (removed) 364 B 🟢 -364 B 🟢 -235 B 🟢 -194 B
assets/commands-_s-RvhJR.js 13.6 kB 13.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BuUILW6P.js 13 kB 13 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BV4R6fLx.js 14.9 kB 14.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BWp4HdfU.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CLwPdnT6.js 14.2 kB 14.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CWMchBmd.js 15.9 kB 15.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DazTQhtc.js 12.9 kB 12.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DmWrOe93.js 13.7 kB 13.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DwiH7Kr6.js 13.8 kB 13.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-mS3LCNPn.js 14.5 kB 14.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B1JflQcI.js 72.2 kB 72.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B2lyXe48.js 114 kB 114 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-B9XEQ-pc.js 94 kB 94 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BErKFzc-.js 73.1 kB 73.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Bf7Tze-u.js 83.4 kB 83.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BhGMcO4Q.js 84.3 kB 84.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CPZUloNQ.js 99 kB 99 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Cw9RZWRY.js 89 B 89 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Dva0z-T2.js 86.5 kB 86.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-un0K9wDS.js 81.8 kB 81.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-8e6QYQW0.js 283 kB 283 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-A_9dx4yn.js 304 kB 304 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BbD3HDi7.js 307 kB 307 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BOJhIPft.js 369 kB 369 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bw_Jitw_.js 101 B 101 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-C-Pw33mW.js 317 kB 317 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-ChLyG0UJ.js 285 kB 285 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CUVPxA4l.js 342 kB 342 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Dx5Y4xrW.js 310 kB 310 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-JqO5mNmW.js 306 kB 306 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-BIbGSUAt.js 1.28 kB 1.28 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 23 added / 23 removed

@ric-yu ric-yu changed the title Ric yu/use jobs api feat: replace GET /queue and /history calls with /jobs Dec 3, 2025
@ric-yu ric-yu force-pushed the ric-yu/use-jobs-api branch from fc925a1 to 2f4f337 Compare December 3, 2025 18:56
// @ts-expect-error fixme ts strict error
...(this.#reverse ? items[section].reverse() : items[section]).map(
(item: TaskItem) => {
(item: any) => {
Copy link
Author

Choose a reason for hiding this comment

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

this is legacy right? we don't need to strongly type this?

Copy link
Contributor

Choose a reason for hiding this comment

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

True. You could use ts-expect-error

…ding

Implements Jobs API endpoints (/jobs) for cloud distribution to replace
history_v2 API, providing 99.998% memory reduction per item.

Key changes:
- Jobs API types, schemas, and fetchers for list and detail endpoints
- Adapter to convert Jobs API format to TaskItem format
- Lazy loading for full outputs when loading workflows
- hasOnlyPreviewOutputs() detection for preview-only tasks
- Feature flag to toggle between Jobs API and history_v2

Implementation details:
- List endpoint: Returns preview_output only (100-200 bytes per job)
- Detail endpoint: Returns full workflow and outputs on demand
- Cloud builds use /jobs?status=completed for history view
- Desktop builds unchanged (still use history_v1)
- 21 unit and integration tests (all passing)

Memory optimization:
- Old: 300-600KB per history item (full outputs)
- New: 100-200 bytes per history item (preview only)
- Reduction: 99.998%

Co-Authored-By: Claude <[email protected]>
@ric-yu ric-yu force-pushed the ric-yu/use-jobs-api branch from 9915fa6 to b733b88 Compare December 3, 2025 21:22
@christian-byrne
Copy link
Contributor

@coderabbitai review

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 4, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/scripts/api.ts (1)

886-900: Fix getItems() method return type incompatibility — calling getItems('history') will break the history UI in ui.ts.

The getHistory() return type change from object to array is a breaking change, but the issue extends beyond direct callers. The getItems() wrapper method (line 859–864 in api.ts) returns incompatible types: getItems('queue') returns Promise<{Running: JobListItem[], Pending: JobListItem[]}> while getItems('history') returns Promise<JobListItem[]>. The ui.ts code at lines 255–261 expects both to be objects with properties it can iterate over with Object.keys(items).flatMap((section) => items[section]). This will fail when getItems('history') is called from this.history.load() at ui.ts line 253, as arrays don't have meaningful section properties.

Update getItems() to return a consistent structure for both queue and history types (e.g., wrap the history array to match the queue object structure or adjust ui.ts to handle both patterns).

🧹 Nitpick comments (10)
src/components/queue/job/JobDetailsPopover.stories.ts (1)

92-106: Consider removing unused _durationSec parameter.

The _durationSec parameter is not used in the function body. If it's no longer needed for the new JobListItem-based model, consider removing it to simplify the API. If kept for future use, a brief comment explaining why would help maintainability.

 function makeHistoryTask(
   id: string,
   priority: number,
-  _durationSec: number,
   ok: boolean,
   errorMessage?: string
 ): TaskItemImpl {

Note: This would require updating all call sites (e.g., lines 178-181, 229-232, etc.).

tests-ui/tests/composables/useResultGallery.test.ts (1)

132-165: Consider verifying fetchApi was called in lazy loading test.

The test validates that full outputs are loaded, but doesn't verify that mockFetchApi was actually invoked. Adding a spy or assertion would strengthen the test.

+import { describe, it, expect, vi } from 'vitest'
 // ...

   it('loads full outputs when task has only preview outputs', async () => {
     // ...
-    const mockFetchApi = async () => new Response()
+    const mockFetchApi = vi.fn().mockResolvedValue(new Response())

     const { galleryItems, galleryActiveIndex, onViewItem } = useResultGallery(
       () => [mockTask],
       mockFetchApi
     )

     await onViewItem(createJobItem('job-1', previewOutput, mockTask))

     expect(galleryItems.value).toEqual(fullOutputs)
     expect(galleryActiveIndex.value).toBe(0)
+    // Verify lazy loading was triggered (if fetchApi is called internally)
+    // expect(mockFetchApi).toHaveBeenCalled()
   })

Note: Only add the assertion if loadFullOutputs internally uses the provided fetchApi. Based on learnings, use vitest mock functions over verbose manual mocks.

src/scripts/ui.ts (1)

262-262: Consider using @ts-expect-error instead of any for legacy code.

As discussed in prior review comments, this legacy code path doesn't need strong typing. Using @ts-expect-error would be more explicit about the intentional type relaxation while satisfying the coding guideline against using any.

-            (item: any) => {
+            // @ts-expect-error Legacy UI code - items may be JobListItem or TaskItem
+            (item) => {
src/composables/queue/useResultGallery.ts (1)

40-42: Cache lacks cleanup mechanism - potential memory leak.

The loadedTasksCache Map grows unbounded as users view more items. Consider adding a cleanup strategy (e.g., LRU eviction, WeakMap if feasible, or clearing on certain events).

+const MAX_CACHE_SIZE = 100
+
 const loadedTasksCache = new Map<string, GalleryTask>()
 let currentRequestId = 0
+
+const trimCache = () => {
+  if (loadedTasksCache.size > MAX_CACHE_SIZE) {
+    const keys = [...loadedTasksCache.keys()]
+    keys.slice(0, keys.length - MAX_CACHE_SIZE).forEach(k => loadedTasksCache.delete(k))
+  }
+}

Then call trimCache() after adding to the cache.

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

56-61: Consider adding user feedback for workflow loading failures.

When getJobWorkflow returns undefined, the functions silently return without feedback to the user. Consider showing a toast or notification to inform users when workflow data cannot be loaded.

 const getJobWorkflow = async (
   jobId: string
 ): Promise<ComfyWorkflowJSON | undefined> => {
   const jobDetail = await fetchJobDetail((url) => api.fetchApi(url), jobId)
-  return extractWorkflow(jobDetail)
+  const workflow = extractWorkflow(jobDetail)
+  if (!workflow) {
+    console.warn(`Could not load workflow for job ${jobId}`)
+  }
+  return workflow
 }

The callers could then optionally show user-facing feedback if needed.

tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts (2)

100-105: Avoid as any type assertion.

Per coding guidelines, as any should not be used. Consider creating a properly typed test fixture or using a more specific type assertion that matches the expected JobDetail structure.

-  it('should extract workflow from job detail', () => {
-    const result = extractWorkflow(mockJobDetailResponse as any)
+  it('should extract workflow from job detail', () => {
+    const result = extractWorkflow(mockJobDetailResponse as JobDetail)

You would need to import JobDetail from the types module and ensure mockJobDetailResponse conforms to the schema.


113-122: Same as any issue for test fixture.

This test also uses as any which should be avoided. Consider typing the test fixture properly.

+import type { JobDetail } from '@/platform/remote/comfyui/jobs/types/jobTypes'
+
 // Then in the test:
-    const result = extractWorkflow(jobWithoutWorkflow as any)
+    const result = extractWorkflow(jobWithoutWorkflow as JobDetail)
tests-ui/tests/store/queueStore.test.ts (1)

38-45: Avoid any[] type for images parameter.

Per coding guidelines, any type should not be used. Consider using a proper type for the images array.

+import type { ResultItem } from '@/schemas/apiSchema'
+
 const createTaskOutput = (
   nodeId: string = 'node-1',
-  images: any[] = []
+  images: ResultItem[] = []
 ): TaskOutput => ({
   [nodeId]: {
     images
   }
 })
src/platform/remote/comfyui/jobs/types/jobTypes.ts (1)

73-82: Consider adding .passthrough() to zExecutionError for consistency.

Other schemas use .passthrough() for forward compatibility. The zExecutionError schema is strict, which could cause validation failures if the backend adds new fields to execution errors in the future.

 const zExecutionError = z.object({
   node_id: z.string(),
   node_type: z.string(),
   executed: z.array(z.string()),
   exception_message: z.string(),
   exception_type: z.string(),
   traceback: z.array(z.string()),
   current_inputs: z.unknown(),
   current_outputs: z.unknown()
-})
+}).passthrough()
src/stores/queueStore.ts (1)

290-293: Update outdated comment reference.

The comment references getWorkflowFromHistory which has been replaced by the loadWorkflow() method (line 393). Update the comment to reflect the current implementation.

Apply this diff:

-  get workflow(): ComfyWorkflowJSON | undefined {
-    // Workflow is only available after lazy loading via getWorkflowFromHistory
-    return undefined
-  }
+  get workflow(): ComfyWorkflowJSON | undefined {
+    // Workflow is lazily loaded via loadWorkflow() and not cached in TaskItemImpl
+    return undefined
+  }

@ric-yu ric-yu force-pushed the ric-yu/use-jobs-api branch from a3e7516 to 19b31e5 Compare December 4, 2025 01:46
@ric-yu ric-yu marked this pull request as ready for review December 4, 2025 18:05
@ric-yu ric-yu requested a review from a team as a code owner December 4, 2025 18:05
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Dec 4, 2025
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: 6

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/stores/queueStore.ts (2)

421-457: Missing error handling in loadWorkflow.

Similar to loadFullOutputs, this method calls fetchJobDetail and app.loadGraphData without error handling. A network failure or invalid workflow data could cause unhandled exceptions.

   public async loadWorkflow(app: ComfyApp) {
     if (!this.isHistory) {
       return
     }

-    // Single fetch for both workflow and outputs
-    const jobDetail = await fetchJobDetail(
-      (url) => app.api.fetchApi(url),
-      this.promptId
-    )
+    let jobDetail
+    try {
+      jobDetail = await fetchJobDetail(
+        (url) => app.api.fetchApi(url),
+        this.promptId
+      )
+    } catch {
+      return
+    }

     const workflowData = extractWorkflow(jobDetail)
     if (!workflowData) {
       return
     }

-    await app.loadGraphData(toRaw(workflowData))
+    try {
+      await app.loadGraphData(toRaw(workflowData))
+    } catch {
+      return
+    }

526-570: Store update() lacks error handling for API failures.

If api.getQueue() or api.getHistory() throws, the error propagates uncaught. Consider catching and logging errors to prevent UI breakage while still setting isLoading to false. As per coding guidelines, implement proper error handling.

   const update = async () => {
     isLoading.value = true
     try {
       const [queue, history] = await Promise.all([
         api.getQueue(),
         api.getHistory(maxHistoryItems.value)
       ])
       // ... rest of update logic
+    } catch (error) {
+      console.error('Failed to update queue:', error)
     } finally {
       isLoading.value = false
     }
   }
src/components/queue/job/useJobErrorReporting.ts (1)

39-55: Type cast from ExecutionError to ExecutionErrorWsMessage is unsafe and may cause runtime issues.

ExecutionErrorWsMessage extends zExecutionWsMessageBase which requires prompt_id (string) and timestamp (number) fields. However, ExecutionError from the Jobs API schema does not include these fields. The cast at line 45 (executionError as ExecutionErrorWsMessage) masks this incompatibility.

If dialog.showExecutionErrorDialog relies on prompt_id or timestamp, this will silently pass undefined values at runtime, potentially causing unexpected behavior.

Resolve by either:

  1. Updating JobErrorDialogService.showExecutionErrorDialog() to accept ExecutionError directly and handle the absence of prompt_id/timestamp
  2. Creating a mapping function to transform ExecutionError to ExecutionErrorWsMessage with synthesized prompt_id/timestamp values
📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fd13755 and 2aa2be6.

📒 Files selected for processing (13)
  • src/components/queue/job/useJobErrorReporting.ts (3 hunks)
  • src/composables/queue/useJobList.ts (1 hunks)
  • src/composables/queue/useJobMenu.ts (4 hunks)
  • src/composables/queue/useResultGallery.ts (1 hunks)
  • src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts (1 hunks)
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts (1 hunks)
  • src/stores/queueStore.ts (11 hunks)
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts (2 hunks)
  • tests-ui/tests/composables/useJobList.test.ts (4 hunks)
  • tests-ui/tests/composables/useJobMenu.test.ts (11 hunks)
  • tests-ui/tests/composables/useResultGallery.test.ts (2 hunks)
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts (2 hunks)
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts (3 hunks)
🧰 Additional context used
📓 Path-based instructions (20)
**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json

Files:

  • src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • src/composables/queue/useResultGallery.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • src/composables/queue/useJobMenu.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursorrules)

Use es-toolkit for utility functions

Files:

  • src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • src/composables/queue/useResultGallery.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • src/composables/queue/useJobMenu.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use TypeScript for type safety

**/*.{ts,tsx}: Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • src/composables/queue/useResultGallery.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • src/composables/queue/useJobMenu.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (.cursorrules)

Implement proper error handling in components and services

**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in .prettierrc
Organize imports by sorting and grouping by plugin, and run pnpm format before committing

Files:

  • src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • src/composables/queue/useResultGallery.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • src/composables/queue/useJobMenu.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
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/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • src/composables/queue/useResultGallery.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • src/composables/queue/useJobMenu.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.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/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • src/composables/queue/useResultGallery.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • src/composables/queue/useJobMenu.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use camelCase for variable and setting names in TypeScript/Vue files

Files:

  • src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • src/composables/queue/useResultGallery.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • src/composables/queue/useJobMenu.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,vue}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates

Files:

  • src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • src/composables/queue/useResultGallery.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • src/composables/queue/useJobMenu.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
Use defaultsByInstallVersion property for gradual feature rollout based on version in settings configuration

Files:

  • src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • src/composables/queue/useResultGallery.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • src/composables/queue/useJobMenu.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.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/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • src/composables/queue/useResultGallery.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • src/composables/queue/useJobMenu.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts
  • src/composables/queue/useResultGallery.ts
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • src/composables/queue/useJobMenu.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/stores/queueStore.ts
  • src/composables/queue/useJobList.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
**/*.{test,spec}.{ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Unit and component tests should be located in tests-ui/ or co-located with components as src/components/**/*.{test,spec}.ts; E2E tests should be in browser_tests/

Files:

  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
**/composables/use*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables in the format useXyz.ts

Files:

  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • tests-ui/tests/composables/useResultGallery.test.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/useResultGallery.ts
  • src/composables/queue/useJobMenu.ts
  • src/composables/queue/useJobList.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/useResultGallery.ts
  • src/composables/queue/useJobMenu.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/composables/queue/useJobList.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/composables/queue/useResultGallery.ts
  • src/composables/queue/useJobMenu.ts
  • src/components/queue/job/useJobErrorReporting.ts
  • src/composables/queue/useJobList.ts
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/useJobErrorReporting.ts
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/queueStore.ts
**/stores/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia stores with the *Store.ts suffix

Files:

  • src/stores/queueStore.ts
🧠 Learnings (15)
📚 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} : Test user workflows in browser tests

Applied to files:

  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/components/queue/useJobErrorReporting.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Follow existing test patterns in the codebase

Applied to files:

  • tests-ui/tests/composables/useJobList.test.ts
  • tests-ui/tests/composables/useJobMenu.test.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/composables/useJobMenu.test.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/composables/useJobMenu.test.ts
  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Use Vitest (with happy-dom) for unit and component tests, and Playwright for E2E tests

Applied to files:

  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.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:

  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.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:

  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.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:

  • tests-ui/tests/stores/queueStore.loadWorkflow.test.ts
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • tests-ui/tests/composables/useResultGallery.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} : Use Playwright fixtures for browser tests

Applied to files:

  • tests-ui/tests/composables/useResultGallery.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} : Test across multiple viewports

Applied to files:

  • tests-ui/tests/composables/useResultGallery.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Source code should be organized in `src/` directory with key areas: `components/`, `views/`, `stores/` (Pinia), `composables/`, `services/`, `utils/`, `assets/`, `locales/`

Applied to files:

  • src/stores/queueStore.ts
📚 Learning: 2025-11-24T19:47:14.779Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:14.779Z
Learning: Applies to **/*.{ts,tsx,vue} : Use `const settingStore = useSettingStore()` and `settingStore.get('Comfy.SomeSetting')` to retrieve settings in TypeScript/Vue files

Applied to files:

  • src/stores/queueStore.ts
🧬 Code graph analysis (8)
tests-ui/tests/composables/useJobMenu.test.ts (1)
src/stores/queueStore.ts (2)
  • workflow (331-333)
  • executionError (317-319)
src/composables/queue/useResultGallery.ts (2)
src/stores/queueStore.ts (4)
  • url (84-86)
  • ResultItemImpl (35-209)
  • TaskItemImpl (211-496)
  • outputsCount (296-298)
src/composables/queue/useJobList.ts (1)
  • JobListItem (33-47)
tests-ui/tests/stores/queueStore.loadWorkflow.test.ts (2)
src/platform/remote/comfyui/jobs/types/jobTypes.ts (2)
  • JobListItem (120-120)
  • JobDetail (121-121)
src/platform/remote/comfyui/jobs/index.ts (2)
  • JobListItem (14-14)
  • JobDetail (14-14)
src/platform/remote/comfyui/jobs/types/jobTypes.ts (2)
src/schemas/apiSchema.ts (2)
  • resultItemType (13-13)
  • zTaskOutput (154-154)
src/composables/queue/useJobList.ts (1)
  • JobListItem (33-47)
tests-ui/tests/components/queue/useJobErrorReporting.test.ts (3)
src/stores/queueStore.ts (4)
  • promptId (292-294)
  • errorMessage (310-312)
  • executionError (317-319)
  • createTime (345-347)
src/platform/remote/comfyui/jobs/types/jobTypes.ts (1)
  • ExecutionError (50-50)
src/components/queue/job/useJobErrorReporting.ts (2)
  • JobErrorDialogService (9-18)
  • useJobErrorReporting (26-62)
src/composables/queue/useJobMenu.ts (5)
src/platform/workflow/validation/schemas/workflowSchema.ts (1)
  • ComfyWorkflowJSON (460-462)
src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts (2)
  • fetchJobDetail (127-144)
  • extractWorkflow (150-160)
src/platform/remote/comfyui/jobs/index.ts (2)
  • fetchJobDetail (11-11)
  • extractWorkflow (9-9)
src/scripts/api.ts (1)
  • api (1247-1247)
src/services/dialogService.ts (1)
  • useDialogService (47-566)
src/components/queue/job/useJobErrorReporting.ts (2)
src/stores/queueStore.ts (1)
  • executionError (317-319)
src/schemas/apiSchema.ts (1)
  • ExecutionErrorWsMessage (144-144)
tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts (2)
src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts (2)
  • fetchJobDetail (127-144)
  • extractWorkflow (150-160)
src/platform/remote/comfyui/jobs/index.ts (2)
  • fetchJobDetail (11-11)
  • extractWorkflow (9-9)
🔇 Additional comments (35)
src/platform/remote/comfyui/jobs/types/jobTypes.ts (1)

1-121: Well-structured Zod schemas for the new Jobs API.

The file establishes a clean separation between raw API data (zRawJobListItem) and normalized data with required fields (zJobListItem). The use of .passthrough() on all schemas enables forward compatibility with new backend fields.

A few observations:

  1. The zJobStatus schema is defined but not exported — if consumers need to validate status values independently, consider exporting it.

  2. Consider adding explicit return type for ExecutionError to align with ExecutionErrorWsMessage from @/schemas/apiSchema (referenced in useJobErrorReporting.ts line 45 where a cast is used).

src/stores/queueStore.ts (2)

459-479: LGTM: flatten() correctly creates synthetic task items.

The method properly creates new TaskItemImpl instances with unique synthetic IDs for each output, maintaining immutability.


211-232: LGTM: Constructor handles optional outputs gracefully.

The constructor correctly creates synthetic outputs from preview_output when full outputs aren't available, and properly strips animated outputs.

tests-ui/tests/components/queue/useJobErrorReporting.test.ts (1)

23-93: LGTM: Good test coverage for error reporting flows.

Tests properly cover reactive error message updates, copy-to-clipboard behavior, empty states, and the dialog routing logic between simple and rich error dialogs.

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

237-246: LGTM: Correctly updated to use workflowId property.

The change from task.workflow?.id to task.workflowId aligns with the new TaskItemImpl API where workflowId is a direct getter from the underlying JobListItem.

tests-ui/tests/composables/useJobList.test.ts (2)

9-17: LGTM: Test type correctly updated for new data model.

The TestTask type now uses workflowId?: string directly instead of workflow?: { id?: string }, matching the JobListItem shape.


384-413: LGTM: Workflow filter test properly uses workflowId.

Test data correctly uses workflowId: 'workflow-1' to test the active workflow filtering logic.

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

51-83: Good abort pattern for stale requests.

The currentRequestId pattern (lines 55, 65) correctly prevents race conditions when rapid view changes occur. The logic properly aborts stale requests before updating gallery state.

tests-ui/tests/composables/useResultGallery.test.ts (3)

8-23: Helper function correctly creates test fixtures with overridden getters.

The createResultItem helper properly constructs ResultItemImpl instances and uses Object.defineProperty to override getters for test matching. This is a valid approach for testing.


25-45: Test fixtures properly align with new JobListItem-based structure.

The createMockJob and createTask helpers correctly construct the new data shapes required by the Jobs API migration.


47-58: Type assertion acceptable for test fixture creation.

The as JobListViewItem assertion is appropriate here since the test only requires specific fields to be present.

tests-ui/tests/stores/queueStore.loadWorkflow.test.ts (4)

29-46: Mock job detail structure correctly reflects the nested workflow path.

The mockJobDetail structure with workflow.extra_data.extra_pnginfo.workflow accurately mirrors the actual /jobs/{id} API response structure as documented in extractWorkflow.


48-66: Helper functions correctly create JobListItem test fixtures.

The createHistoryJob and createRunningJob helpers properly construct the minimal required fields for testing different job states.


86-101: Test correctly verifies lazy workflow loading flow.

The test properly mocks fetchJobDetail, verifies it's called with the job ID, and confirms loadGraphData receives the expected workflow data.


115-127: Good coverage for running task exclusion.

This test ensures that running/in-progress tasks do not trigger workflow fetching, which is the expected behavior since they don't have completed workflow data yet.

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

53-61: Internal helper correctly implements lazy workflow loading.

The getJobWorkflow function properly encapsulates the fetch + extract pattern. Error handling is delegated to fetchJobDetail which returns undefined on failure.


90-94: Simplified error message access is cleaner.

The refactored copyErrorMessage directly accesses errorMessage from taskRef, removing unnecessary parsing logic.


96-115: Error reporting logic correctly prioritizes rich dialog.

The two-path approach properly handles both structured execution_error (showing detailed dialog) and fallback to simple error dialog when only a message is available.


181-203: Export workflow correctly uses lazy loading.

The exportJobWorkflow function properly integrates with getJobWorkflow for on-demand workflow retrieval.

tests-ui/tests/platform/workflow/cloud/getWorkflowFromHistory.test.ts (3)

19-41: Mock response structure correctly reflects actual API contract.

The mockJobDetailResponse accurately represents the /jobs/{id} response with the nested workflow path at workflow.extra_data.extra_pnginfo.workflow.


43-99: Comprehensive test coverage for fetchJobDetail.

The tests properly verify endpoint construction, successful response parsing, 404 handling, network errors, and malformed JSON responses.


102-124: Good coverage for extractWorkflow edge cases.

The tests properly verify extraction from valid data, handling of undefined input, and graceful handling of missing nested workflow fields. The as any assertions are acceptable for testing malformed data scenarios.

src/platform/remote/comfyui/jobs/fetchers/fetchJobs.ts (6)

1-18: Well-documented module with clear purpose.

The file header clearly explains the module's role in the unified Jobs API architecture, and imports are properly organized.


34-54: Internal fetcher with proper error handling.

The fetchJobsRaw function correctly handles both network errors and parse failures, returning safe empty results while logging for debugging.


63-90: Priority assignment logic correctly preserves server values.

The assignPriority function uses nullish coalescing (??) to only assign synthetic priorities when the server doesn't provide one. The history priority calculation total - offset ensures proper ordering.


96-118: Queue priority logic correctly ensures pending > running > history.

The priority assignment ensures:

  1. Pending jobs get highest priority (QUEUE_PRIORITY_BASE + running.length + pending.length)
  2. Running jobs are next (QUEUE_PRIORITY_BASE + running.length)
  3. Both are above any history job due to QUEUE_PRIORITY_BASE

127-144: Job detail fetcher with graceful error handling.

The fetchJobDetail function properly handles non-OK responses and exceptions, returning undefined to signal failure. Logging provides visibility into issues.


150-160: Workflow extraction with documented type assertions.

The type assertions in extractWorkflow are justified by the comment explaining downstream validation via loadGraphData -> validateComfyWorkflow. The safe optional chaining prevents runtime errors on missing nested fields.

tests-ui/tests/composables/useJobMenu.test.ts (7)

61-66: Mocks correctly set up for lazy loading workflow retrieval.

The fetchJobDetailMock and extractWorkflowMock are properly configured to test the new workflow loading path via the jobs module.


183-186: Default mock configuration requires explicit workflow setup.

Setting defaults to undefined ensures each test must explicitly configure workflow availability, preventing false positives.


192-211: Test correctly verifies lazy workflow loading integration.

The test properly sets up mocks for the fetch + extract flow and verifies that fetchJobDetail is called with the job ID before workflow processing.


291-325: Comprehensive test for execution_error rich dialog path.

The test properly verifies that when executionError is present, the rich showExecutionErrorDialog is called with the full error payload, and the fallback showErrorDialog is not invoked.


327-347: Good coverage of fallback error dialog path.

The test verifies that when only errorMessage is available (no executionError), the simple showErrorDialog is called with an Error instance and the correct reportType.


540-563: Export workflow test correctly uses lazy loading mocks.

The test properly configures fetchJobDetailMock and extractWorkflowMock to supply workflow data, then verifies the export produces the correct JSON blob.


738-757: Failed menu test correctly uses new errorMessage field.

The test properly sets up taskRef.errorMessage to verify the failed job menu structure includes error-related actions.

Comment on lines +27 to +28
const loadedTasksCache = new Map<string, TaskItemImpl>()
let currentRequestId = 0
Copy link
Contributor

@coderabbitai coderabbitai bot Dec 4, 2025

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Cache and request ID should be instance-scoped, not shared.

loadedTasksCache and currentRequestId are declared inside the function but using const and let makes them shared across component re-renders but not across instances. However, if useResultGallery is called multiple times (e.g., multiple gallery instances), each will have its own cache — this is actually correct.

The cache lacks a cleanup mechanism, which could lead to memory growth over time if many jobs are viewed.

Consider adding cache size limits or clearing on unmount:

+import { onUnmounted } from 'vue'
+
 export function useResultGallery(
   getFilteredTasks: () => TaskItemImpl[],
   fetchApi?: FetchApi
 ) {
   const galleryActiveIndex = ref(-1)
   const galleryItems = shallowRef<ResultItemImpl[]>([])

   const loadedTasksCache = new Map<string, TaskItemImpl>()
   let currentRequestId = 0

+  onUnmounted(() => {
+    loadedTasksCache.clear()
+  })
📝 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 loadedTasksCache = new Map<string, TaskItemImpl>()
let currentRequestId = 0
import { onUnmounted } from 'vue'
export function useResultGallery(
getFilteredTasks: () => TaskItemImpl[],
fetchApi?: FetchApi
) {
const galleryActiveIndex = ref(-1)
const galleryItems = shallowRef<ResultItemImpl[]>([])
const loadedTasksCache = new Map<string, TaskItemImpl>()
let currentRequestId = 0
onUnmounted(() => {
loadedTasksCache.clear()
})
🤖 Prompt for AI Agents
In src/composables/queue/useResultGallery.ts around lines 27-28, the
per-instance loadedTasksCache and currentRequestId lack a cleanup/size policy
and may grow unbounded; implement an instance-scoped cache eviction and
teardown: add a maxCacheSize constant and evict oldest entries when inserting
beyond the limit (or convert Map to an LRU by tracking access order), expose or
call a clearCache function when switching jobs, and register an onUnmounted hook
to clear the Map and reset currentRequestId so memory is released when the
component instance is destroyed.

Copy link
Author

Choose a reason for hiding this comment

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

Cache and request ID should be instance-scoped, not shared.

loadedTasksCache and currentRequestId are declared inside the function but using const and let makes them shared across component re-renders but not across instances. However, if useResultGallery is called multiple times (e.g., multiple gallery instances), each will have its own cache — this is actually correct.

This is just LLM nonsense right

Copy link
Contributor

Choose a reason for hiding this comment

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

@ric-yu, you're absolutely right. My explanation of the scoping was confusing and contradictory.

The scoping here is actually correct and intentional: each call to useResultGallery() creates its own closure with a dedicated loadedTasksCache Map and currentRequestId counter. Within a single component instance, these persist across re-renders (which is exactly what you want for caching), and different component instances each get their own independent cache.

The memory growth concern about unbounded cache might still apply if a single gallery instance views hundreds of different jobs over its lifetime, but that's a separate issue from scoping. The current implementation is fine for typical usage patterns.

Sorry for the noise—the original comment should have focused solely on cache eviction policy if at all, not scope.

Copy link
Author

Choose a reason for hiding this comment

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

When component unmounts, the closure (including the Map) gets garbage collected anyway. Explicitly clearing it seems redundant.

Copy link
Contributor

Choose a reason for hiding this comment

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

@ric-yu, you're absolutely correct. When the component unmounts and there are no external references to the composable's closure, the entire closure—including the Map—becomes eligible for garbage collection automatically. JavaScript applications need to ensure garbage collection takes place as expected, but in this case, the Map has no external side effects or listeners that would prevent collection.

Explicit cleanup with onUnmounted is essential for resources with external references, such as:

  • Event listeners that need removeEventListener calls
  • Timers created with setInterval or setTimeout
  • Third-party library instances with .destroy() methods

But for a plain Map with no external bindings, as you noted, the GC will handle it. My original suggestion to add explicit cleanup was unnecessary—apologies for the noise.


🧠 Learnings used
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

@ric-yu
Copy link
Author

ric-yu commented Dec 4, 2025

Will address coderabbit comments and then re-open

@ric-yu ric-yu marked this pull request as draft December 4, 2025 18:21
@ric-yu ric-yu marked this pull request as ready for review December 4, 2025 21:36
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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/components/queue/job/JobGroupsList.vue (1)

61-91: Add cleanup for hover detail timers (and consider VueUse helper)

showTimer / hideTimer timeouts are cleared on enter/leave, but not on component unmount. To fully comply with the “cleanup async operations” guideline and avoid stray callbacks after unmount, consider:

  • Clearing both timers in an onBeforeUnmount hook, and/or
  • Replacing the manual setTimeout logic with a VueUse helper like useTimeoutFn, which auto‑cleans on unmount.

Example sketch:

-import { ref } from 'vue'
+import { ref, onBeforeUnmount } from 'vue'

 // ...

 const clearHideTimer = () => {
   if (hideTimer.value !== null) {
     clearTimeout(hideTimer.value)
     hideTimer.value = null
   }
 }

 const clearShowTimer = () => {
   if (showTimer.value !== null) {
     clearTimeout(showTimer.value)
     showTimer.value = null
   }
 }

+onBeforeUnmount(() => {
+  clearHideTimer()
+  clearShowTimer()
+})

Or wrap this behavior with VueUse’s timeout utilities for simpler, auto‑cleaned timers.

src/components/queue/job/JobDetailsPopover.stories.ts (1)

150-161: Use as const assertions or explicit types to avoid any casts.

Lines 160-161 use as any for exec.nodeProgressStatesByPrompt. Per coding guidelines, avoid as any type assertions. Consider defining a proper type for the progress state or using a more specific type assertion.

       exec.nodeProgressStatesByPrompt = {
         p1: {
           '1': {
             value: 1,
             max: 1,
             state: 'running',
             node_id: '1',
             prompt_id: 'p1'
           }
         }
-      } as any
+      } as Record<string, Record<string, { value: number; max: number; state: string; node_id: string; prompt_id: string }>>
♻️ Duplicate comments (1)
tests-ui/tests/composables/useResultGallery.test.ts (1)

141-169: mockFetchApi is unused — consider removing or documenting.

The mockFetchApi (line 158) is passed to useResultGallery, but task.loadFullOutputs is directly mocked on line 155, so the composable's fetchApi parameter is never invoked. Either remove mockFetchApi if not needed, or add a comment explaining it's intentionally provided to satisfy the composable signature.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2aa2be6 and f556795.

📒 Files selected for processing (5)
  • src/components/queue/job/JobDetailsPopover.stories.ts (3 hunks)
  • src/components/queue/job/JobGroupsList.vue (1 hunks)
  • src/platform/remote/comfyui/jobs/types/jobTypes.ts (1 hunks)
  • src/stores/queueStore.ts (11 hunks)
  • tests-ui/tests/composables/useResultGallery.test.ts (2 hunks)
🧰 Additional context used
📓 Path-based instructions (24)
**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

**/*.{vue,ts,tsx}: Leverage VueUse functions for performance-enhancing utilities
Use vue-i18n in Composition API for any string literals and place new translation entries in src/locales/en/main.json

Files:

  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.vue
  • src/stores/queueStore.ts
**/*.{ts,tsx,js}

📄 CodeRabbit inference engine (.cursorrules)

Use es-toolkit for utility functions

Files:

  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/stores/queueStore.ts
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursorrules)

Use TypeScript for type safety

**/*.{ts,tsx}: Never use any type - use proper TypeScript types
Never use as any type assertions - fix the underlying type issue

Files:

  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/stores/queueStore.ts
**/*.{ts,tsx,js,vue}

📄 CodeRabbit inference engine (.cursorrules)

Implement proper error handling in components and services

**/*.{ts,tsx,js,vue}: Use 2-space indentation, single quotes, no semicolons, and maintain 80-character line width as configured in .prettierrc
Organize imports by sorting and grouping by plugin, and run pnpm format before committing

Files:

  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.vue
  • src/stores/queueStore.ts
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/remote/comfyui/jobs/types/jobTypes.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.vue
  • src/stores/queueStore.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/platform/remote/comfyui/jobs/types/jobTypes.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/stores/queueStore.ts
**/*.{ts,tsx,js,jsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

Use camelCase for variable and setting names in TypeScript/Vue files

Files:

  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.vue
  • src/stores/queueStore.ts
**/*.{ts,tsx,vue}

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.{ts,tsx,vue}: Use const settingStore = useSettingStore() and settingStore.get('Comfy.SomeSetting') to retrieve settings in TypeScript/Vue files
Use await settingStore.set('Comfy.SomeSetting', newValue) to update settings in TypeScript/Vue files
Check server capabilities using api.serverSupportsFeature('feature_name') before using enhanced features
Use api.getServerFeature('config_name', defaultValue) to retrieve server feature configuration

Enforce ESLint rules for Vue + TypeScript including: no floating promises, no unused imports, and i18n raw text restrictions in templates

Files:

  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.vue
  • src/stores/queueStore.ts
**/*.ts

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.ts: Define dynamic setting defaults using runtime context with functions in settings configuration
Use defaultsByInstallVersion property for gradual feature rollout based on version in settings configuration

Files:

  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • tests-ui/tests/composables/useResultGallery.test.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/stores/queueStore.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/platform/remote/comfyui/jobs/types/jobTypes.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.vue
  • src/stores/queueStore.ts
src/**/*.{vue,ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

Follow Vue 3 composition API style guide

Files:

  • src/platform/remote/comfyui/jobs/types/jobTypes.ts
  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.vue
  • src/stores/queueStore.ts
tests-ui/**/*.test.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (tests-ui/CLAUDE.md)

tests-ui/**/*.test.{js,ts,jsx,tsx}: Write tests for new features
Follow existing test patterns in the codebase
Use existing test utilities rather than writing custom utilities
Mock external dependencies in tests
Always prefer vitest mock functions over writing verbose manual mocks

Files:

  • tests-ui/tests/composables/useResultGallery.test.ts
**/*.{test,spec}.{ts,tsx,js}

📄 CodeRabbit inference engine (AGENTS.md)

Unit and component tests should be located in tests-ui/ or co-located with components as src/components/**/*.{test,spec}.ts; E2E tests should be in browser_tests/

Files:

  • tests-ui/tests/composables/useResultGallery.test.ts
**/composables/use*.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name composables in the format useXyz.ts

Files:

  • tests-ui/tests/composables/useResultGallery.test.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/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.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/components/queue/job/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.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/JobDetailsPopover.stories.ts
  • src/components/queue/job/JobGroupsList.vue
**/*.vue

📄 CodeRabbit inference engine (.cursorrules)

**/*.vue: Use setup() function for component logic in Vue 3 Composition API
Utilize ref and reactive for reactive state in Vue 3
Implement computed properties with computed() function
Use watch and watchEffect for side effects in Vue 3
Implement lifecycle hooks with onMounted, onUpdated, etc.
Utilize provide/inject for dependency injection in Vue 3
Use Vue 3.5 style of default prop declaration with defineProps()
Organize Vue components in <script> <style> order
Use Tailwind CSS for styling Vue components
Implement responsive design with Tailwind CSS
Do not use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage). Use replacements: Select, Popover, DatePicker, ToggleSwitch, Drawer, AutoComplete, Tabs, Stepper, Message respectively
Implement proper props and emits definitions in Vue components
Utilize Vue 3's Teleport component when needed
Use Suspense for async components in Vue 3
Follow Vue 3 style guide and naming conventions
Never use deprecated PrimeVue components (Dropdown, OverlayPanel, Calendar, InputSwitch, Sidebar, Chips, TabMenu, Steps, InlineMessage)

Never use :class="[]" to merge class names - always use import { cn } from '@/utils/tailwindUtil' for class merging in Vue templates

**/*.vue: Use TypeScript with Vue 3 Single File Components (.vue files)
Name Vue components in PascalCase (e.g., MenuHamburger.vue)

Files:

  • src/components/queue/job/JobGroupsList.vue
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/JobGroupsList.vue
**/*.{vue,html}

📄 CodeRabbit inference engine (CLAUDE.md)

Never use dark: or dark-theme: Tailwind variants - instead use semantic values from style.css theme, e.g. bg-node-component-surface

Files:

  • src/components/queue/job/JobGroupsList.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/queue/job/JobGroupsList.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/JobGroupsList.vue
src/**/stores/**/*.{ts,tsx}

📄 CodeRabbit inference engine (src/CLAUDE.md)

src/**/stores/**/*.{ts,tsx}: Maintain clear public interfaces and restrict extension access in stores
Use TypeScript for type safety in state management stores

Files:

  • src/stores/queueStore.ts
**/stores/*Store.ts

📄 CodeRabbit inference engine (AGENTS.md)

Name Pinia stores with the *Store.ts suffix

Files:

  • src/stores/queueStore.ts
🧠 Learnings (13)
📚 Learning: 2025-11-24T19:47:56.371Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: src/lib/litegraph/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:56.371Z
Learning: Applies to src/lib/litegraph/**/*.{test,spec}.{ts,tsx} : Use provided test helpers `createTestSubgraph` and `createTestSubgraphNode` from `./fixtures/subgraphHelpers` for consistent subgraph test setup

Applied to files:

  • tests-ui/tests/composables/useResultGallery.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Write tests for new features

Applied to files:

  • tests-ui/tests/composables/useResultGallery.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Use existing test utilities rather than writing custom utilities

Applied to files:

  • tests-ui/tests/composables/useResultGallery.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Mock external dependencies in tests

Applied to files:

  • tests-ui/tests/composables/useResultGallery.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} : Mocks should be cleanly written and easy to understand, with reusable mocks where possible

Applied to files:

  • tests-ui/tests/composables/useResultGallery.test.ts
📚 Learning: 2025-11-24T19:48:03.270Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: tests-ui/CLAUDE.md:0-0
Timestamp: 2025-11-24T19:48:03.270Z
Learning: Applies to tests-ui/**/*.test.{js,ts,jsx,tsx} : Always prefer vitest mock functions over writing verbose manual mocks

Applied to files:

  • tests-ui/tests/composables/useResultGallery.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} : Test user workflows in browser tests

Applied to files:

  • tests-ui/tests/composables/useResultGallery.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:

  • tests-ui/tests/composables/useResultGallery.test.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Use Vitest (with happy-dom) for unit and component tests, and Playwright for E2E tests

Applied to files:

  • tests-ui/tests/composables/useResultGallery.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:

  • tests-ui/tests/composables/useResultGallery.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} : Test across multiple viewports

Applied to files:

  • tests-ui/tests/composables/useResultGallery.test.ts
📚 Learning: 2025-11-24T19:47:14.779Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: CLAUDE.md:0-0
Timestamp: 2025-11-24T19:47:14.779Z
Learning: Applies to **/*.{ts,tsx,vue} : Use `const settingStore = useSettingStore()` and `settingStore.get('Comfy.SomeSetting')` to retrieve settings in TypeScript/Vue files

Applied to files:

  • src/components/queue/job/JobDetailsPopover.stories.ts
  • src/stores/queueStore.ts
📚 Learning: 2025-11-24T19:48:23.088Z
Learnt from: CR
Repo: Comfy-Org/ComfyUI_frontend PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-11-24T19:48:23.088Z
Learning: Source code should be organized in `src/` directory with key areas: `components/`, `views/`, `stores/` (Pinia), `composables/`, `services/`, `utils/`, `assets/`, `locales/`

Applied to files:

  • src/stores/queueStore.ts
🧬 Code graph analysis (3)
src/platform/remote/comfyui/jobs/types/jobTypes.ts (2)
src/schemas/apiSchema.ts (2)
  • resultItemType (13-13)
  • zTaskOutput (154-154)
src/composables/queue/useJobList.ts (1)
  • JobListItem (33-47)
src/components/queue/job/JobDetailsPopover.stories.ts (2)
src/platform/remote/comfyui/jobs/types/jobTypes.ts (1)
  • JobListItem (115-115)
src/stores/queueStore.ts (1)
  • TaskItemImpl (211-487)
src/stores/queueStore.ts (5)
src/platform/remote/comfyui/jobs/types/jobTypes.ts (1)
  • JobListItem (115-115)
src/composables/queue/useJobList.ts (1)
  • JobListItem (33-47)
src/platform/remote/comfyui/jobs/index.ts (3)
  • JobListItem (14-14)
  • fetchJobDetail (11-11)
  • extractWorkflow (9-9)
src/schemas/apiSchema.ts (1)
  • TaskOutput (155-155)
src/platform/remote/comfyui/history/reconciliation.ts (1)
  • reconcileJobs (20-40)
⏰ 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 (15)
src/components/queue/job/JobGroupsList.vue (1)

11-33: Ensure workflowId access path matches canonical JobListItem shape

The switch to :workflow-id="ji.taskRef?.workflowId" looks aligned with the new Jobs API mapping (moving from taskRef.workflow.id to taskRef.workflowId), but elsewhere in the PR the canonical field may be exposed directly on JobListItem as workflowId. If JobListItem now has a top-level workflowId, it might be clearer and more robust to source it from there (optionally with a fallback to taskRef?.workflowId only if needed), so all queue/history consumers behave consistently.

Please double‑check the JobListItem type and how workflowId is populated in useJobList / other queue components, and adjust this binding if the canonical field is actually ji.workflowId.

tests-ui/tests/composables/useResultGallery.test.ts (2)

8-23: Well-structured test helpers using the new JobListItem-based types.

The createResultItem helper properly constructs ResultItemImpl instances with overridden getters for test assertions. Using Object.defineProperty to override url and supportsPreview is a clean approach for test matching.


25-58: Test data factories align well with the new Jobs API types.

createMockJob and createTask helpers correctly construct JobListItem and TaskItemImpl instances matching the new API structure. The createJobViewItem properly types taskRef to allow TaskItemImpl references.

src/platform/remote/comfyui/jobs/types/jobTypes.ts (3)

1-11: Well-documented module with clear Zod schema definitions.

Good use of JSDoc for module documentation. Importing resultItemType and zTaskOutput from the existing API schema maintains consistency with other type definitions.


112-116: Type derivation is clean and the JobListItem type correctly enforces required priority.

The pattern of deriving types from Zod schemas ensures runtime and compile-time consistency. Making priority required in JobListItem while optional in RawJobListItem aligns with the PR's synthetic priority assignment strategy.


37-51: The node_id and node_type fields should remain required.

The schema correctly marks these fields as required. All test fixtures (useJobMenu.test.ts, useJobErrorReporting.test.ts) consistently include both fields, and the backend's ExecutionErrorWsMessage schema in apiSchema.ts also marks them as required. No code patterns show conditional handling or fallbacks for missing node identification.

src/components/queue/job/JobDetailsPopover.stories.ts (2)

55-65: Helper functions are well-structured for story data generation.

The makePendingTask function properly delegates to makeTask with appropriate status and timestamps. This pattern keeps the story setup code clean and consistent.


92-122: makeHistoryTask correctly constructs execution timing and error data.

The helper properly sets execution_start_time, execution_end_time, and conditionally includes execution_error with the expected structure from zExecutionError. This aligns well with the new Jobs API types.

src/stores/queueStore.ts (7)

211-233: Clean refactor of TaskItemImpl to use JobListItem as backing data.

The constructor properly handles the case where no outputs are provided by synthesizing from preview_output. Using _.mapValues to strip animated outputs maintains backward compatibility.


262-272: Clear mapping from job status to internal task type.

The taskType getter provides a clean abstraction over the job status values, defaulting non-active statuses to 'History'. This handles completed, failed, and cancelled statuses uniformly.


300-340: Good use of accessors to expose job data with appropriate fallbacks.

The getters for status, errorMessage, executionError, workflowId, workflow, and messages provide clean access to job data. Returning undefined for workflow with a comment directing users to loadWorkflow() is clear.


400-419: Error handling is properly delegated to fetchJobDetail.

As confirmed in past reviews, fetchJobDetail has internal try-catch that returns undefined on failure. The if (!jobDetail?.outputs) check correctly handles both error cases and missing data.


517-561: Well-structured update function with proper reconciliation.

The update function correctly:

  1. Fetches queue and history in parallel
  2. Maps API responses to TaskItemImpl instances
  3. Registers workflow ID mappings for execution tracking
  4. Uses reconcileJobs for history reconciliation
  5. Reuses existing TaskItemImpl instances to preserve identity

544-557: No action needed. The API return types are correctly defined in src/scripts/api.ts: getQueue() returns Promise<{ Running: JobListItem[], Pending: JobListItem[] }> and getHistory() returns Promise<JobListItem[]>. Both methods and the queueStore import the same JobListItem type from @/platform/remote/comfyui/jobs, and all usage in lines 526–527 and 545 correctly matches these type signatures. No type mismatches exist.


459-479: The flatten() method creates synthetic IDs for display purposes only—these items appear in the flatTasks computed property but are not passed to API operations. The deleteTask function uses the original task.promptId from non-flattened items, so synthetic IDs never reach backend calls. The design appears intentional, with no evidence in the codebase that flattened items are used in delete or other API operations. However, without tracing all component usage of flatTasks, edge cases cannot be entirely ruled out.

Comment on lines +40 to +53
function makeTask(
id: string,
index: number,
createTimeMs?: number
priority: number,
overrides: Omit<Partial<JobListItem>, 'id' | 'priority'> &
Pick<JobListItem, 'status' | 'create_time' | 'update_time'>
): TaskItemImpl {
const extraData = {
client_id: 'c1',
...(typeof createTimeMs === 'number' ? { create_time: createTimeMs } : {})
const job: JobListItem = {
id,
priority,
last_state_update: null,
...overrides
}
return new TaskItemImpl('Pending', [index, id, {}, extraData, []])
return new TaskItemImpl(job)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

update_time and last_state_update are not defined in JobListItem schema.

The makeTask helper uses update_time (line 44) and last_state_update (line 49), but these fields are not defined in zRawJobListItem in jobTypes.ts. While .passthrough() allows extra fields at runtime, TypeScript won't recognize them, and the explicit type annotation on line 43-44 requiring update_time will cause type errors.

Either add these fields to the zRawJobListItem schema if they're part of the API, or remove them from the story helpers if they're not needed.

#!/bin/bash
# Verify if update_time or last_state_update are used elsewhere in the codebase
rg -n "update_time|last_state_update" --type=ts -g '!node_modules' | head -30
🤖 Prompt for AI Agents
In src/components/queue/job/JobDetailsPopover.stories.ts around lines 40 to 53,
the makeTask helper sets update_time and last_state_update on the JobListItem
but those fields are not declared in the project's zRawJobListItem schema,
causing TypeScript type errors; either add update_time and last_state_update to
the zRawJobListItem/type definitions if these fields are returned by the API
(update the zod schema and corresponding TS types) or remove/stop using these
fields in the story helper and any callers so JobListItem only contains declared
properties; pick one approach and apply the change consistently across the story
helper and related tests/examples.

Comment on lines +76 to +84
export const zJobDetail = zRawJobListItem
.extend({
workflow: z.unknown().optional(),
outputs: zTaskOutput.optional(),
update_time: z.number().optional(),
execution_status: z.unknown().optional(),
execution_meta: z.unknown().optional()
})
.passthrough()
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 documenting the z.unknown() fields or using stricter schemas.

The workflow, execution_status, and execution_meta fields use z.unknown(). While this provides flexibility, it loses type safety. If the structure is partially known, consider using a more specific schema with .passthrough() for the known parts, or add JSDoc comments explaining the expected shape.

@ric-yu
Copy link
Author

ric-yu commented Dec 5, 2025

Split into #7169 #7170 and #7171

@ric-yu ric-yu closed this Dec 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants