Skip to content

[feat] Surface missing models in Errors tab (Cloud)#9743

Merged
jaeone94 merged 10 commits intomainfrom
feat/cloud-missing-model-from-errortab
Mar 12, 2026
Merged

[feat] Surface missing models in Errors tab (Cloud)#9743
jaeone94 merged 10 commits intomainfrom
feat/cloud-missing-model-from-errortab

Conversation

@jaeone94
Copy link
Collaborator

@jaeone94 jaeone94 commented Mar 11, 2026

Summary

When a workflow is loaded with missing models, users currently have no way to identify or resolve them from within the UI. This PR adds a full missing-model detection and resolution pipeline that surfaces missing models in the Errors tab, allowing users to install or import them without leaving the editor.

Changes

Missing Model Detection

  • Scan all COMBO widgets across root graph and subgraphs for model-like filenames during workflow load
  • Enrich candidates with embedded workflow metadata (url, hash, directory) when available
  • Verify asset-supported candidates against the asset store asynchronously to confirm installation status
  • Propagate missing model state to executionErrorStore alongside existing node/prompt errors

Errors Tab UI — Model Resolution

  • Group missing models by directory (e.g. checkpoints, loras, vae) with collapsible category cards
  • Each model row displays:
    • Model name with copy-to-clipboard button
    • Expandable list of referencing nodes with locate-on-canvas button
    • Library selector: Pick an alternative from the user's existing models to substitute the missing model with one click
    • URL import: Paste a Civitai or HuggingFace URL to import a model directly; debounced metadata fetch shows filename and file size before confirming; type-mismatch warnings (e.g. importing a LoRA into checkpoints directory) are surfaced with an "Import Anyway" option
    • Upgrade prompt: In cloud environment, free-tier subscribers are shown an upgrade modal when attempting URL import
  • Separate "Import Not Supported" section for custom-node models that cannot be auto-resolved
  • Status card with live download progress, completion, failure, and category-mismatch states

Canvas Integration

  • Highlight nodes and widgets that reference missing models with error indicators
  • Propagate missing-model badges through subgraph containers so issues are visible at every graph level

Code Cleanup

  • Simplify surfacePendingWarnings in workflowService, remove stale widget-detected model merging logic
  • Add flattenWorkflowNodes utility to workflowSchema for traversing nested subgraph structures
  • Extract MissingModelUrlInput, MissingModelLibrarySelect, MissingModelStatusCard as focused single-responsibility components

Testing

  • Unit tests for scan pipeline (missingModelScan.test.ts): enrichment, skip-installed, subgraph flattening
  • Unit tests for store (missingModelStore.test.ts): state management, removal helpers
  • Unit tests for interactions (useMissingModelInteractions.test.ts): combo select, URL input, import flow, library confirm
  • Component tests for MissingModelCard and error grouping (useErrorGroups.test.ts)
  • Updated workflowService.test.ts and workflowSchema.test.ts for new logic

Review Focus

  • Missing model scan + enrichment pipeline in missingModelScan.ts
  • Interaction composable useMissingModelInteractions.ts — URL metadata fetch, library install, upload fallback
  • Store integration and canvas-level error propagation

Screenshots

2026-03-12.000826.mp4

┆Issue is synchronized with this Notion page by Unito

Detect missing models during workflow load and display them in the
right-side-panel Errors tab alongside existing node/prompt errors.

- Scan all COMBO widgets (root + subgraphs) for model-like filenames.
- Enrich candidates with embedded workflow metadata (url, hash, directory).
- Verify asset-supported candidates against the asset store asynchronously.
- Surface confirmed missing models via executionErrorStore.surfaceMissingModels.

- Add missingModelsError state and related computed properties.
- Add hasMissingModelOnNode / isWidgetMissingModel lookup helpers.
- Add �ctiveMissingModelGraphIds for canvas-level error indicators.
- Add isContainerWithMissingModel for subgraph container badges.

- Group missing models by directory with collapsible cards.
- MissingModelCard.vue / MissingModelRow.vue: per-model row with
  library selector (asset-supported) or URL import (Civitai/HuggingFace).
- Debounced URL metadata fetch with type-mismatch warnings.
- Copy model name button and clear URL input button.
- useMissingModelInteractions.ts: composable for all interaction logic.

- Highlight nodes and widgets that reference missing models.
- Propagate missing-model badges through subgraph containers.

- workflowSchema.ts: add lattenWorkflowNodes utility, remove unused
  getSerializedNodeLabel.
- workflowService.ts: simplify surfacePendingWarnings, remove stale
  widget-detected model merging logic.
-
odeTitleUtil.ts: remove 
esolveNodeDisplayLabel wrapper, inline
  at call site.
- 	ypes.ts: add MissingModelCandidate and EmbeddedModelWithSource.
- i18n: add 
ightSidePanel.missingModels.* keys.
Add colocated tests for new missing-model functions introduced in the
previous commit. Also update workflowService.test.ts to reflect the
simplified surfacePendingWarnings logic (removed widget-detected model
merging and error store assertions that no longer apply).

- executionErrorStore.test.ts: surfaceMissingModels, removeMissingModelByName,
  removeMissingModelsByNodeIds, hasMissingModelOnNode, isWidgetMissingModel
- missingModelScan.test.ts: enrichWithEmbeddedMetadata (enrich existing,
  no-overwrite, add new candidate, skip installed)
- useErrorGroups.test.ts: missingModelGroups grouping by directory,
  unsupported separation, same-name merging, allErrorGroups inclusion
- workflowSchema.test.ts: flattenWorkflowNodes (root-only, undefined,
  subgraph prefixing, nested paths)
- MissingModelCard.test.ts: new component test — rendering, props,
  directory/unsupported groups, event forwarding
- workflowService.test.ts: remove stale widget-detected model tests,
  simplify missing model dialog assertions
   - Move interaction state to Pinia store with storeToRefs
   - Replace mutable accumulator with return values in scan functions
   - Parallelize checkModelInstalled calls with Promise.all
   - Add toast notification on polling timeout
   - Use useModelUpload composable for upload dialog
   - Make nodeId/sourceNodeId optional in types
   - Remove unused store functions and their tests
   - Fix semantic color tokens and cn() usage
   - Add computed properties to reduce redundant calls
  - Replace polling with awaitable promise in asset verification (M-10)
  - Extract runMissingModelPipeline from loadGraphData (L-22)
  - Extract MissingModelStatusCard component (M-5)
  - Extract shared getActiveGraphNodeIds utility (M-4)
  - Add unit tests for verifyAssetSupportedCandidates, useMissingModelInteractions, and OSS regression
  - Fix accessibility: role='alert', aria-live, aria-hidden on decorative icons
  - Fix path traversal sanitization in URL filename extraction
  - Return new array from enrichWithEmbeddedMetadata instead of mutating input
  - Guard against stale surfaceMissingModels call after abort
  - Remove overly permissive bidirectional path matching in isAssetInstalled
  - Add AssetVerifier DI to verifyAssetSupportedCandidates
  - Add onScopeDispose for debounce timer cleanup
  - Extract MissingModelUrlInput and MissingModelLibrarySelect from MissingModelRow
  - Use Readonly<ComfyNode>[] return type for flattenWorkflowNodes
  - Surface toast on asset verification failure
  - Cache nodeIdStr in processedWidgets loop
  - Remove unused props destructuring in MissingModelCard
@jaeone94 jaeone94 requested review from a team as code owners March 11, 2026 14:14
@jaeone94 jaeone94 added enhancement New feature or request area:models labels Mar 11, 2026
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Mar 11, 2026
@github-actions
Copy link

github-actions bot commented Mar 11, 2026

🎭 Playwright: ✅ 552 passed, 0 failed · 4 flaky

📊 Browser Reports
  • chromium: View Report (✅ 539 / ❌ 0 / ⚠️ 4 / ⏭️ 10)
  • chromium-2x: View Report (✅ 2 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • chromium-0.5x: View Report (✅ 1 / ❌ 0 / ⚠️ 0 / ⏭️ 0)
  • mobile-chrome: View Report (✅ 10 / ❌ 0 / ⚠️ 0 / ⏭️ 0)

@github-actions
Copy link

github-actions bot commented Mar 11, 2026

🎨 Storybook: ✅ Built — View Storybook

Details

⏰ Completed at: 03/12/2026, 07:10:27 AM UTC

Links

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Mar 11, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds end-to-end missing-model support: detection, embedded-metadata enrichment, async asset verification, a Pinia missingModel store, interaction composables, new UI components, Errors-tab integration, graph-load pipeline wiring, and node/widget validation updates.

Changes

Cohort / File(s) Summary
Core types & store
src/platform/missingModel/types.ts, src/platform/missingModel/missingModelStore.ts
New public types for candidates/view models/groups and a Pinia store managing missing-model candidates, UI state, debounce timers, abort controller, and helper APIs.
Scanning / enrichment / verification
src/platform/missingModel/missingModelScan.ts, src/platform/missingModel/missingModelScan.test.ts
New scanning/enrichment/verification APIs: detect candidates from widgets/assets, enrich with embedded metadata, async-verify asset installs, and grouping; extensive tests cover edge cases and async flows.
Composables / interactions
src/platform/missingModel/composables/useMissingModelInteractions.ts, .../useMissingModelInteractions.test.ts
New composable exposing state keys, display helpers, combo/select/url flows, debounced metadata fetch, confirm/cancel/import handlers, and comprehensive unit tests.
UI components & tests
src/platform/missingModel/components/...
MissingModelCard.vue, MissingModelRow.vue, MissingModelStatusCard.vue, MissingModelUrlInput.vue, MissingModelLibrarySelect.vue, tests
New Vue SFCs for grouped missing-model UI and per-model interactions (props/emits typed); unit tests added for card/row behaviors and flows.
Right-side panel / errors
src/components/rightSidePanel/...
RightSidePanel.vue, errors/TabErrors.vue, errors/types.ts, errors/useErrorGroups.ts, errors/useErrorGroups.test.ts
Adds missing_model ErrorGroup variant, computes/exposes missingModelGroups, renders MissingModelCard in Errors tab, wires locate-model handling, and updates error-count/visibility logic.
App load pipeline
src/scripts/app.ts
Introduces runMissingModelPipeline during graph load: scans, enriches, verifies cloud candidates, sets store state, clears prior state, and surfaces warnings/toasts on verification failure.
Graph & traversal utilities
src/utils/graphTraversalUtil.ts, src/platform/workflow/validation/schemas/workflowSchema.ts, ...workflowSchema.test.ts
Added getActiveGraphNodeIds, made partial path finder return optional, and added flattenWorkflowNodes to flatten root+subgraph nodes with prefixed IDs; tests adjusted/added.
Node/widget validation
src/renderer/extensions/vueNodes/components/LGraphNode.vue, .../NodeWidgets.vue
Node and widget error checks now consult missingModelStore (missing models treated as errors; container checks include missing-model children).
Execution/error store & misc stores
src/stores/executionErrorStore.ts, src/stores/executionErrorStore.test.ts, src/stores/assetsStore.ts
executionErrorStore: integrates missingModelStore, adds surfaceMissingModels, includes missing-model counts/flags; assetsStore: pending-promise tracking to avoid duplicate category loads; tests updated/mocked.
Localization & select slot
src/locales/en/main.json, src/components/ui/select/SelectContent.vue
i18n: added missing-model strings and toast key; SelectContent: added prepend slot.

Sequence Diagram(s)

sequenceDiagram
    participant App as App.loadGraphData()
    participant Pipeline as runMissingModelPipeline()
    participant Scanner as scanAllModelCandidates
    participant Enricher as enrichWithEmbeddedMetadata
    participant Verifier as verifyAssetSupportedCandidates
    participant MissingStore as missingModelStore
    participant ErrorStore as executionErrorStore
    participant UI as RightSidePanel

    App->>MissingStore: clearMissingModels()
    App->>Pipeline: start(graphData)

    Pipeline->>Scanner: scanAllModelCandidates(graphData)
    Scanner-->>Pipeline: candidates

    Pipeline->>Enricher: enrichWithEmbeddedMetadata(candidates)
    Enricher-->>Pipeline: enrichedCandidates

    Pipeline->>Verifier: verifyAssetSupportedCandidates(enrichedCandidates, signal)
    Verifier-->>MissingStore: update isMissing flags

    Pipeline->>MissingStore: setMissingModels(enrichedCandidates)
    Pipeline->>ErrorStore: surfaceMissingModels(enrichedCandidates)

    UI->>MissingStore: read missingModelGroups, activeMissingModelGraphIds
    UI->>UI: render MissingModelCard and handle locate-model events
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I hopped through nodes where hidden models hide,

I sniffed their names and neatly grouped them side by side.
I fetched their tags, I ran the checks, I set the store all right,
Now point and click — I’ll nudge them home with a tiny hop and light.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.64% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title '[feat] Surface missing models in Errors tab (Cloud)' accurately and concisely describes the main feature added — missing model detection and resolution UI surfaced in the Errors tab for cloud environments.
Description check ✅ Passed The PR description comprehensively covers the changeset with detailed Summary, Changes sections (Detection, UI, Canvas, Cleanup), Testing, Review Focus, and Screenshots. It exceeds the template requirements and clearly communicates the feature intent and implementation scope.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/cloud-missing-model-from-errortab

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@github-actions
Copy link

github-actions bot commented Mar 11, 2026

📦 Bundle: 4.58 MB gzip 🔴 +11.6 kB

Details

Summary

  • Raw size: 21.5 MB baseline 21.4 MB — 🔴 +54 kB
  • Gzip: 4.58 MB baseline 4.57 MB — 🔴 +11.6 kB
  • Brotli: 3.54 MB baseline 3.53 MB — 🔴 +8.64 kB
  • Bundles: 233 current • 232 baseline • 215 added / 214 removed

Category Glance
Graph Workspace 🔴 +36.7 kB (1.01 MB) · Data & Services 🔴 +15.8 kB (2.79 MB) · Other 🔴 +1.53 kB (8.04 MB) · Vendor & Third-Party ⚪ 0 B (8.9 MB) · Panels & Settings ⚪ 0 B (438 kB) · Editors & Dialogs ⚪ 0 B (78.3 kB) · + 5 more

App Entry Points — 17.7 kB (baseline 17.7 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-Ckvg569e.js (new) 17.7 kB 🔴 +17.7 kB 🔴 +6.26 kB 🔴 +5.4 kB
assets/index-D3MUusRf.js (removed) 17.7 kB 🟢 -17.7 kB 🟢 -6.26 kB 🟢 -5.44 kB

Status: 1 added / 1 removed

Graph Workspace — 1.01 MB (baseline 974 kB) • 🔴 +36.7 kB

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-Cujm8SpN.js (new) 1.01 MB 🔴 +1.01 MB 🔴 +212 kB 🔴 +161 kB
assets/GraphView-ZfOSt9Os.js (removed) 974 kB 🟢 -974 kB 🟢 -205 kB 🟢 -155 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-BFk9GySM.js (new) 15.5 kB 🔴 +15.5 kB 🔴 +3.32 kB 🔴 +2.82 kB
assets/CloudSurveyView-C6MBjwIS.js (removed) 15.5 kB 🟢 -15.5 kB 🟢 -3.32 kB 🟢 -2.81 kB
assets/CloudLoginView-DYrFiNXE.js (removed) 11.5 kB 🟢 -11.5 kB 🟢 -3.21 kB 🟢 -2.84 kB
assets/CloudLoginView-uMCTBt_f.js (new) 11.5 kB 🔴 +11.5 kB 🔴 +3.21 kB 🔴 +2.84 kB
assets/CloudSignupView-Bod4xw7x.js (new) 9.41 kB 🔴 +9.41 kB 🔴 +2.71 kB 🔴 +2.38 kB
assets/CloudSignupView-CNTTmeK2.js (removed) 9.41 kB 🟢 -9.41 kB 🟢 -2.71 kB 🟢 -2.38 kB
assets/UserCheckView-7gSgKN3s.js (new) 8.42 kB 🔴 +8.42 kB 🔴 +2.23 kB 🔴 +1.94 kB
assets/UserCheckView-DvIXYMz3.js (removed) 8.42 kB 🟢 -8.42 kB 🟢 -2.23 kB 🟢 -1.94 kB
assets/CloudLayoutView-0QeztZrq.js (new) 6.56 kB 🔴 +6.56 kB 🔴 +2.17 kB 🔴 +1.88 kB
assets/CloudLayoutView-Dnf0Rc1A.js (removed) 6.56 kB 🟢 -6.56 kB 🟢 -2.17 kB 🟢 -1.88 kB
assets/CloudForgotPasswordView-BNeDIyg-.js (removed) 5.59 kB 🟢 -5.59 kB 🟢 -1.95 kB 🟢 -1.72 kB
assets/CloudForgotPasswordView-CVRFGstI.js (new) 5.59 kB 🔴 +5.59 kB 🔴 +1.95 kB 🔴 +1.72 kB
assets/CloudAuthTimeoutView-C2hxwFKK.js (removed) 4.96 kB 🟢 -4.96 kB 🟢 -1.79 kB 🟢 -1.57 kB
assets/CloudAuthTimeoutView-CyPbIRSs.js (new) 4.96 kB 🔴 +4.96 kB 🔴 +1.79 kB 🔴 +1.57 kB
assets/CloudSubscriptionRedirectView-BtgfB-O_.js (new) 4.78 kB 🔴 +4.78 kB 🔴 +1.8 kB 🔴 +1.59 kB
assets/CloudSubscriptionRedirectView-DMSe7goN.js (removed) 4.78 kB 🟢 -4.78 kB 🟢 -1.8 kB 🟢 -1.59 kB
assets/UserSelectView-BRjQx8ot.js (removed) 4.55 kB 🟢 -4.55 kB 🟢 -1.67 kB 🟢 -1.48 kB
assets/UserSelectView-Bx8V53S3.js (new) 4.55 kB 🔴 +4.55 kB 🔴 +1.67 kB 🔴 +1.49 kB
assets/CloudSorryContactSupportView-B10VB5H_.js (removed) 1.02 kB 🟢 -1.02 kB 🟢 -540 B 🟢 -462 B
assets/CloudSorryContactSupportView-BFw0sFGo.js (new) 1.02 kB 🔴 +1.02 kB 🔴 +540 B 🔴 +463 B
assets/layout-CNUFnjHE.js (removed) 296 B 🟢 -296 B 🟢 -223 B 🟢 -187 B
assets/layout-Wd88ZKDq.js (new) 296 B 🔴 +296 B 🔴 +223 B 🔴 +190 B

Status: 11 added / 11 removed

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/settings-BMZqZMWV.js (new) 38.5 kB 🔴 +38.5 kB 🔴 +9.34 kB 🔴 +7.67 kB
assets/settings-So53ZGaK.js (removed) 38.5 kB 🟢 -38.5 kB 🟢 -9.34 kB 🟢 -7.69 kB
assets/settings-BhljmVLI.js (new) 34.2 kB 🔴 +34.2 kB 🔴 +8.33 kB 🔴 +7.01 kB
assets/settings-BSfPhDgX.js (removed) 34.2 kB 🟢 -34.2 kB 🟢 -8.33 kB 🟢 -7.01 kB
assets/settings-hSQJdwwK.js (removed) 32.4 kB 🟢 -32.4 kB 🟢 -8.15 kB 🟢 -6.64 kB
assets/settings-x4lDOTHy.js (new) 32.4 kB 🔴 +32.4 kB 🔴 +8.15 kB 🔴 +6.64 kB
assets/settings-CTDqwZOP.js (removed) 30.5 kB 🟢 -30.5 kB 🟢 -8.45 kB 🟢 -7.1 kB
assets/settings-DvY3JpnZ.js (new) 30.5 kB 🔴 +30.5 kB 🔴 +8.45 kB 🔴 +7.1 kB
assets/settings-B3Lo1XmI.js (new) 29.9 kB 🔴 +29.9 kB 🔴 +8.1 kB 🔴 +7.07 kB
assets/settings-CY1qXPWG.js (removed) 29.9 kB 🟢 -29.9 kB 🟢 -8.1 kB 🟢 -7.07 kB
assets/settings-bThwkOsC.js (new) 28.8 kB 🔴 +28.8 kB 🔴 +7.79 kB 🔴 +6.67 kB
assets/settings-D4yKfrVw.js (removed) 28.8 kB 🟢 -28.8 kB 🟢 -7.79 kB 🟢 -6.66 kB
assets/settings-DKN0RxMZ.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -8 kB 🟢 -6.99 kB
assets/settings-OPXE36wg.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +8 kB 🔴 +6.99 kB
assets/settings-BlDXFCUy.js (removed) 27.9 kB 🟢 -27.9 kB 🟢 -7.71 kB 🟢 -6.71 kB
assets/settings-C1uM8WjX.js (new) 27.9 kB 🔴 +27.9 kB 🔴 +7.71 kB 🔴 +6.69 kB
assets/settings-BH2NzvA8.js (removed) 27.8 kB 🟢 -27.8 kB 🟢 -8.12 kB 🟢 -6.78 kB
assets/settings-bRtLtC70.js (new) 27.8 kB 🔴 +27.8 kB 🔴 +8.12 kB 🔴 +6.77 kB
assets/settings-BPjNSOku.js (removed) 24.5 kB 🟢 -24.5 kB 🟢 -7.9 kB 🟢 -6.37 kB
assets/settings-yz0uqs_Z.js (new) 24.5 kB 🔴 +24.5 kB 🔴 +7.91 kB 🔴 +6.37 kB
assets/settings-Qe3udZkm.js (new) 23.9 kB 🔴 +23.9 kB 🔴 +7.66 kB 🔴 +6 kB
assets/settings-rqXXfmcr.js (removed) 23.9 kB 🟢 -23.9 kB 🟢 -7.67 kB 🟢 -6 kB
assets/SecretsPanel-BjmWT6Ne.js (removed) 21.5 kB 🟢 -21.5 kB 🟢 -5.29 kB 🟢 -4.64 kB
assets/SecretsPanel-Cc1dVj30.js (new) 21.5 kB 🔴 +21.5 kB 🔴 +5.3 kB 🔴 +4.65 kB
assets/LegacyCreditsPanel-BP-j8CMY.js (new) 20.7 kB 🔴 +20.7 kB 🔴 +5.59 kB 🔴 +4.92 kB
assets/LegacyCreditsPanel-Bv4dAXzy.js (removed) 20.7 kB 🟢 -20.7 kB 🟢 -5.59 kB 🟢 -4.92 kB
assets/SubscriptionPanel-B2idoVBY.js (new) 18.7 kB 🔴 +18.7 kB 🔴 +4.75 kB 🔴 +4.19 kB
assets/SubscriptionPanel-kxt1Z5fs.js (removed) 18.7 kB 🟢 -18.7 kB 🟢 -4.75 kB 🟢 -4.2 kB
assets/KeybindingPanel-0omhiDgv.js (new) 12.3 kB 🔴 +12.3 kB 🔴 +3.54 kB 🔴 +3.14 kB
assets/KeybindingPanel-zTFkX71l.js (removed) 12.3 kB 🟢 -12.3 kB 🟢 -3.54 kB 🟢 -3.13 kB
assets/AboutPanel-BkW9fsOz.js (removed) 11.2 kB 🟢 -11.2 kB 🟢 -3.12 kB 🟢 -2.8 kB
assets/AboutPanel-BQ1wYdje.js (new) 11.2 kB 🔴 +11.2 kB 🔴 +3.12 kB 🔴 +2.8 kB
assets/ExtensionPanel-BrUbMuOQ.js (new) 9.42 kB 🔴 +9.42 kB 🔴 +2.67 kB 🔴 +2.37 kB
assets/ExtensionPanel-CKdZoMac.js (removed) 9.42 kB 🟢 -9.42 kB 🟢 -2.67 kB 🟢 -2.38 kB
assets/ServerConfigPanel-BU9MbVk0.js (new) 6.49 kB 🔴 +6.49 kB 🔴 +2.13 kB 🔴 +1.93 kB
assets/ServerConfigPanel-U3puuwFb.js (removed) 6.49 kB 🟢 -6.49 kB 🟢 -2.13 kB 🟢 -1.91 kB
assets/UserPanel-Bz6ORZd0.js (removed) 6.2 kB 🟢 -6.2 kB 🟢 -2.01 kB 🟢 -1.77 kB
assets/UserPanel-Cte3W5AZ.js (new) 6.2 kB 🔴 +6.2 kB 🔴 +2 kB 🔴 +1.75 kB
assets/cloudRemoteConfig-DAK55gDU.js (new) 1.48 kB 🔴 +1.48 kB 🔴 +725 B 🔴 +629 B
assets/cloudRemoteConfig-jH4SmrrV.js (removed) 1.48 kB 🟢 -1.48 kB 🟢 -726 B 🟢 -628 B
assets/config-DrIhAAj_.js (removed) 1.22 kB 🟢 -1.22 kB 🟢 -611 B 🟢 -506 B
assets/config-p2eCRj7g.js (new) 1.22 kB 🔴 +1.22 kB 🔴 +610 B 🔴 +499 B
assets/refreshRemoteConfig-BSfeiPKa.js (removed) 1.14 kB 🟢 -1.14 kB 🟢 -517 B 🟢 -473 B
assets/refreshRemoteConfig-U4YPlrp-.js (new) 1.14 kB 🔴 +1.14 kB 🔴 +518 B 🔴 +468 B

Status: 22 added / 22 removed

User & Accounts — 16.1 kB (baseline 16.1 kB) • ⚪ 0 B

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/PasswordFields-OroLpK9a.js (removed) 4.51 kB 🟢 -4.51 kB 🟢 -1.36 kB 🟢 -1.2 kB
assets/PasswordFields-qoMlUe6p.js (new) 4.51 kB 🔴 +4.51 kB 🔴 +1.36 kB 🔴 +1.2 kB
assets/auth-BnGeBBPV.js (removed) 3.4 kB 🟢 -3.4 kB 🟢 -1.17 kB 🟢 -985 B
assets/auth-DJAZJETY.js (new) 3.4 kB 🔴 +3.4 kB 🔴 +1.18 kB 🔴 +986 B
assets/SignUpForm-BmvAD_Du.js (removed) 3.01 kB 🟢 -3.01 kB 🟢 -1.23 kB 🟢 -1.09 kB
assets/SignUpForm-sC8ZK9VB.js (new) 3.01 kB 🔴 +3.01 kB 🔴 +1.23 kB 🔴 +1.09 kB
assets/UpdatePasswordContent-C_RT7Vyf.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +1.08 kB 🔴 +962 B
assets/UpdatePasswordContent-Dap1qyTp.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -1.09 kB 🟢 -956 B
assets/WorkspaceProfilePic-CuIu1FoW.js (removed) 1.59 kB 🟢 -1.59 kB 🟢 -830 B 🟢 -746 B
assets/WorkspaceProfilePic-F0LwTAsD.js (new) 1.59 kB 🔴 +1.59 kB 🔴 +831 B 🔴 +744 B
assets/firebaseAuthStore-B3hPLtGX.js (removed) 831 B 🟢 -831 B 🟢 -405 B 🟢 -362 B
assets/firebaseAuthStore-B6kaC6dn.js (new) 831 B 🔴 +831 B 🔴 +404 B 🔴 +358 B
assets/auth-B5sD1C9s.js (removed) 357 B 🟢 -357 B 🟢 -223 B 🟢 -194 B
assets/auth-JW38loeD.js (new) 357 B 🔴 +357 B 🔴 +226 B 🔴 +193 B

Status: 7 added / 7 removed

Editors & Dialogs — 78.3 kB (baseline 78.3 kB) • ⚪ 0 B

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useShareDialog-DdUlaLY8.js (removed) 77.5 kB 🟢 -77.5 kB 🟢 -16.6 kB 🟢 -14.2 kB
assets/useShareDialog-DIETA-Ku.js (new) 77.5 kB 🔴 +77.5 kB 🔴 +16.6 kB 🔴 +14.2 kB
assets/useSubscriptionDialog-BhyYg-cB.js (removed) 779 B 🟢 -779 B 🟢 -397 B 🟢 -344 B
assets/useSubscriptionDialog-DtM9A_T5.js (new) 779 B 🔴 +779 B 🔴 +396 B 🔴 +340 B

Status: 2 added / 2 removed

UI Components — 56.7 kB (baseline 56.7 kB) • ⚪ 0 B

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/ComfyQueueButton-Ix8nKMJ9.js (new) 13.8 kB 🔴 +13.8 kB 🔴 +3.91 kB 🔴 +3.48 kB
assets/ComfyQueueButton-RscOln1S.js (removed) 13.8 kB 🟢 -13.8 kB 🟢 -3.9 kB 🟢 -3.48 kB
assets/useTerminalTabs-CzA3oAD-.js (removed) 9.87 kB 🟢 -9.87 kB 🟢 -3.41 kB 🟢 -3.01 kB
assets/useTerminalTabs-Dc-r3wCB.js (new) 9.87 kB 🔴 +9.87 kB 🔴 +3.41 kB 🔴 +3.02 kB
assets/TopbarBadge-CDV8z5F5.js (new) 7.39 kB 🔴 +7.39 kB 🔴 +1.79 kB 🔴 +1.59 kB
assets/TopbarBadge-CFptnCMb.js (removed) 7.39 kB 🟢 -7.39 kB 🟢 -1.79 kB 🟢 -1.59 kB
assets/ScrubableNumberInput-4EP9DGiL.js (removed) 6.11 kB 🟢 -6.11 kB 🟢 -2.08 kB 🟢 -1.84 kB
assets/ScrubableNumberInput-CVGQ2PHm.js (new) 6.11 kB 🔴 +6.11 kB 🔴 +2.08 kB 🔴 +1.85 kB
assets/toggle-group-BmeEkX7i.js (new) 3.83 kB 🔴 +3.83 kB 🔴 +1.37 kB 🔴 +1.21 kB
assets/toggle-group-Co1F_GGC.js (removed) 3.83 kB 🟢 -3.83 kB 🟢 -1.37 kB 🟢 -1.22 kB
assets/FormSearchInput-C9jzAgkK.js (removed) 3.73 kB 🟢 -3.73 kB 🟢 -1.55 kB 🟢 -1.36 kB
assets/FormSearchInput-CEMZoefM.js (new) 3.73 kB 🔴 +3.73 kB 🔴 +1.55 kB 🔴 +1.36 kB
assets/Button-BaH4RoVV.js (new) 3.22 kB 🔴 +3.22 kB 🔴 +1.28 kB 🔴 +1.13 kB
assets/Button-DqdxSYaB.js (removed) 3.22 kB 🟢 -3.22 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/SubscribeButton-BGONGihG.js (removed) 2.34 kB 🟢 -2.34 kB 🟢 -1.01 kB 🟢 -880 B
assets/SubscribeButton-DSR7WaSO.js (new) 2.34 kB 🔴 +2.34 kB 🔴 +1.01 kB 🔴 +882 B
assets/WidgetButton-4trmxPNl.js (new) 1.84 kB 🔴 +1.84 kB 🔴 +876 B 🔴 +779 B
assets/WidgetButton-DJ3L6d0X.js (removed) 1.84 kB 🟢 -1.84 kB 🟢 -875 B 🟢 -768 B
assets/cloudFeedbackTopbarButton-awxoTwCD.js (removed) 1.42 kB 🟢 -1.42 kB 🟢 -745 B 🟢 -660 B
assets/cloudFeedbackTopbarButton-CB1WwD61.js (new) 1.42 kB 🔴 +1.42 kB 🔴 +746 B 🔴 +648 B
assets/UserAvatar-BnVnoaj-.js (removed) 1.19 kB 🟢 -1.19 kB 🟢 -626 B 🟢 -528 B
assets/UserAvatar-rA7elnKS.js (new) 1.19 kB 🔴 +1.19 kB 🔴 +627 B 🔴 +529 B
assets/CloudBadge-DbtS52o1.js (removed) 1.11 kB 🟢 -1.11 kB 🟢 -567 B 🟢 -489 B
assets/CloudBadge-KKDIsNYK.js (new) 1.11 kB 🔴 +1.11 kB 🔴 +571 B 🔴 +494 B
assets/ComfyQueueButton-BmoZNx0I.js (removed) 836 B 🟢 -836 B 🟢 -412 B 🟢 -364 B
assets/ComfyQueueButton-CAUSRoVv.js (new) 836 B 🔴 +836 B 🔴 +411 B 🔴 +366 B

Status: 13 added / 13 removed

Data & Services — 2.79 MB (baseline 2.78 MB) • 🔴 +15.8 kB

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-B4hGHy-C.js (new) 1.95 MB 🔴 +1.95 MB 🔴 +438 kB 🔴 +328 kB
assets/dialogService-BYxy-1Dt.js (removed) 1.94 MB 🟢 -1.94 MB 🟢 -435 kB 🟢 -326 kB
assets/api-BvGwiGsa.js (new) 695 kB 🔴 +695 kB 🔴 +157 kB 🔴 +125 kB
assets/api-drCtrnPf.js (removed) 693 kB 🟢 -693 kB 🟢 -156 kB 🟢 -124 kB
assets/load3dService-BhS_di2b.js (new) 91.1 kB 🔴 +91.1 kB 🔴 +19.1 kB 🔴 +16.4 kB
assets/load3dService-CdbMUGTt.js (removed) 91.1 kB 🟢 -91.1 kB 🟢 -19.1 kB 🟢 -16.4 kB
assets/extensionStore-B4-BCFvW.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -4.63 kB 🟢 -4.09 kB
assets/extensionStore-Dy6-QnEP.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +4.63 kB 🔴 +4.1 kB
assets/workflowShareService-s2O2PS40.js (new) 13.3 kB 🔴 +13.3 kB 🔴 +4.11 kB 🔴 +3.63 kB
assets/workflowShareService-WeCyAJoR.js (removed) 13.3 kB 🟢 -13.3 kB 🟢 -4.1 kB 🟢 -3.63 kB
assets/releaseStore-BcVSnC9V.js (new) 7.96 kB 🔴 +7.96 kB 🔴 +2.22 kB 🔴 +1.96 kB
assets/releaseStore-DgE0d3NM.js (removed) 7.96 kB 🟢 -7.96 kB 🟢 -2.22 kB 🟢 -1.95 kB
assets/keybindingService-BPoGKn4r.js (new) 7.16 kB 🔴 +7.16 kB 🔴 +1.72 kB 🔴 +1.48 kB
assets/keybindingService-KcsywU7f.js (removed) 7.16 kB 🟢 -7.16 kB 🟢 -1.72 kB 🟢 -1.48 kB
assets/serverConfigStore-C6zlD0bA.js (removed) 2.32 kB 🟢 -2.32 kB 🟢 -791 B 🟢 -693 B
assets/serverConfigStore-Va3_Wl8r.js (new) 2.32 kB 🔴 +2.32 kB 🔴 +790 B 🔴 +692 B
assets/bootstrapStore-ce3bg_p0.js (new) 2.08 kB 🔴 +2.08 kB 🔴 +873 B 🔴 +793 B
assets/bootstrapStore-RdW_hd7K.js (removed) 2.08 kB 🟢 -2.08 kB 🟢 -874 B 🟢 -802 B
assets/userStore-CE7lf9Re.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +719 B 🔴 +637 B
assets/userStore-Df2CP1u2.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -716 B 🟢 -631 B
assets/audioService-BvYb1kII.js (new) 1.73 kB 🔴 +1.73 kB 🔴 +847 B 🔴 +724 B
assets/audioService-rwTM_7-c.js (removed) 1.73 kB 🟢 -1.73 kB 🟢 -843 B 🟢 -722 B
assets/releaseStore-Bku_NmuQ.js (new) 803 B 🔴 +803 B 🔴 +402 B 🔴 +354 B
assets/releaseStore-DAMKKvc5.js (removed) 803 B 🟢 -803 B 🟢 -404 B 🟢 -359 B
assets/settingStore-BnyfKZ0a.js (new) 787 B 🔴 +787 B 🔴 +405 B 🔴 +359 B
assets/settingStore-DzL9f9AG.js (removed) 787 B 🟢 -787 B 🟢 -405 B 🟢 -358 B
assets/workflowDraftStore-Cvm2uf3k.js (new) 779 B 🔴 +779 B 🔴 +396 B 🔴 +346 B
assets/workflowDraftStore-Dv4XOohM.js (removed) 779 B 🟢 -779 B 🟢 -398 B 🟢 -354 B
assets/dialogService-C_-K_m4-.js (removed) 768 B 🟢 -768 B 🟢 -389 B 🟢 -347 B
assets/dialogService-NphuM9FN.js (new) 768 B 🔴 +768 B 🔴 +388 B 🔴 +340 B
assets/assetsStore-Cq6xLPD9.js (new) 765 B 🔴 +765 B 🔴 +390 B 🔴 +340 B

Status: 16 added / 15 removed

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useLoad3d-CF0PEKD_.js (removed) 14.6 kB 🟢 -14.6 kB 🟢 -3.63 kB 🟢 -3.21 kB
assets/useLoad3d-D-vt0wkw.js (new) 14.6 kB 🔴 +14.6 kB 🔴 +3.63 kB 🔴 +3.21 kB
assets/useLoad3dViewer-D5KuKaeg.js (new) 14.6 kB 🔴 +14.6 kB 🔴 +3.19 kB 🔴 +2.83 kB
assets/useLoad3dViewer-xjTaJp3R.js (removed) 14.6 kB 🟢 -14.6 kB 🟢 -3.19 kB 🟢 -2.84 kB
assets/colorUtil-BFYqWnMD.js (new) 7 kB 🔴 +7 kB 🔴 +2.14 kB 🔴 +1.9 kB
assets/colorUtil-DtNbLD4C.js (removed) 7 kB 🟢 -7 kB 🟢 -2.14 kB 🟢 -1.89 kB
assets/useFeatureFlags-8iJ-JpAq.js (removed) 4.86 kB 🟢 -4.86 kB 🟢 -1.37 kB 🟢 -1.17 kB
assets/useFeatureFlags-BYMeosl9.js (new) 4.86 kB 🔴 +4.86 kB 🔴 +1.36 kB 🔴 +1.17 kB
assets/useWorkspaceUI-BIFkp9O9.js (new) 3 kB 🔴 +3 kB 🔴 +823 B 🔴 +737 B
assets/useWorkspaceUI-C3sq5vOA.js (removed) 3 kB 🟢 -3 kB 🟢 -823 B 🟢 -704 B
assets/subscriptionCheckoutUtil-nWaUfni5.js (new) 2.53 kB 🔴 +2.53 kB 🔴 +1.06 kB 🔴 +955 B
assets/subscriptionCheckoutUtil-qP71s6ng.js (removed) 2.53 kB 🟢 -2.53 kB 🟢 -1.06 kB 🟢 -928 B
assets/useExternalLink-BqAAuQDs.js (new) 1.66 kB 🔴 +1.66 kB 🔴 +770 B 🔴 +680 B
assets/useExternalLink-DkeTMyXe.js (removed) 1.66 kB 🟢 -1.66 kB 🟢 -770 B 🟢 -677 B
assets/markdownRendererUtil-BllOn75O.js (new) 1.56 kB 🔴 +1.56 kB 🔴 +814 B 🔴 +698 B
assets/markdownRendererUtil-DOdPeMQc.js (removed) 1.56 kB 🟢 -1.56 kB 🟢 -814 B 🟢 -700 B
assets/useErrorHandling-CNk09uZU.js (new) 1.5 kB 🔴 +1.5 kB 🔴 +630 B 🔴 +534 B
assets/useErrorHandling-DXTOIy0e.js (removed) 1.5 kB 🟢 -1.5 kB 🟢 -628 B 🟢 -534 B
assets/useCopyToClipboard-C2E_i03q.js (new) 944 B 🔴 +944 B 🔴 +433 B 🔴 +366 B
assets/useCopyToClipboard-PIFM3bWC.js (removed) 944 B 🟢 -944 B 🟢 -430 B 🟢 -366 B
assets/useLoad3d-Dr-gNbct.js (removed) 902 B 🟢 -902 B 🟢 -441 B 🟢 -394 B
assets/useLoad3d-MvRDr9qG.js (new) 902 B 🔴 +902 B 🔴 +442 B 🔴 +392 B
assets/useLoad3dViewer-4-rnYo0N.js (new) 881 B 🔴 +881 B 🔴 +428 B 🔴 +381 B
assets/useLoad3dViewer-BeSU6JvO.js (removed) 881 B 🟢 -881 B 🟢 -428 B 🟢 -384 B
assets/audioUtils-C_KQmMeu.js (removed) 858 B 🟢 -858 B 🟢 -500 B 🟢 -402 B
assets/audioUtils-pChHa2DZ.js (new) 858 B 🔴 +858 B 🔴 +501 B 🔴 +424 B
assets/useCurrentUser-DGVYrhYy.js (removed) 765 B 🟢 -765 B 🟢 -393 B 🟢 -345 B
assets/useCurrentUser-DH1GBbtg.js (new) 765 B 🔴 +765 B 🔴 +391 B 🔴 +343 B
assets/useWorkspaceSwitch-BqwbXWUL.js (new) 688 B 🔴 +688 B 🔴 +353 B 🔴 +296 B
assets/useWorkspaceSwitch-DPpAZTEq.js (removed) 688 B 🟢 -688 B 🟢 -352 B 🟢 -296 B
assets/SkeletonUtils-CXsVEgWz.js (new) 133 B 🔴 +133 B 🔴 +114 B 🔴 +110 B
assets/SkeletonUtils-Cybe2l6l.js (removed) 133 B 🟢 -133 B 🟢 -114 B 🟢 -111 B
assets/_plugin-vue_export-helper-C4xK3rHS.js 315 B 315 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/envUtil-Clzmwvt4.js 466 B 466 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 16 added / 16 removed

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

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-three-C_3GtM2H.js (new) 1.8 MB 🔴 +1.8 MB 🔴 +385 kB 🔴 +280 kB
assets/vendor-three-C69yBO64.js (removed) 1.8 MB 🟢 -1.8 MB 🟢 -385 kB 🟢 -280 kB
assets/vendor-primevue-DrUjG48Z.js (removed) 1.72 MB 🟢 -1.72 MB 🟢 -311 kB 🟢 -189 kB
assets/vendor-primevue-gPZICJA3.js (new) 1.72 MB 🔴 +1.72 MB 🔴 +311 kB 🔴 +189 kB
assets/vendor-other-C-wiidU-.js (removed) 1.54 MB 🟢 -1.54 MB 🟢 -324 kB 🟢 -258 kB
assets/vendor-other-Dj9lOsnu.js (new) 1.54 MB 🔴 +1.54 MB 🔴 +324 kB 🔴 +258 kB
assets/vendor-tiptap-CXbu7Mch.js (new) 634 kB 🔴 +634 kB 🔴 +149 kB 🔴 +121 kB
assets/vendor-tiptap-DTO2QA4Q.js (removed) 634 kB 🟢 -634 kB 🟢 -149 kB 🟢 -121 kB
assets/vendor-chart-05GtjRkv.js (new) 399 kB 🔴 +399 kB 🔴 +95.7 kB 🔴 +79.5 kB
assets/vendor-chart-D82zUMvC.js (removed) 399 kB 🟢 -399 kB 🟢 -95.7 kB 🟢 -79.5 kB
assets/vendor-xterm-Co8jWZ4q.js (removed) 374 kB 🟢 -374 kB 🟢 -75.5 kB 🟢 -61 kB
assets/vendor-xterm-DPkCdaAS.js (new) 374 kB 🔴 +374 kB 🔴 +75.5 kB 🔴 +61 kB
assets/vendor-axios-Cp6hch1I.js 70.7 kB 70.7 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-firebase-BvMr43CG.js 836 kB 836 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-i18n-DNX73mqE.js 133 kB 133 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-markdown-D5S6AC80.js 103 kB 103 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-reka-ui-DlFrLeZ5.js 428 kB 428 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-sentry-SQwstEKc.js 182 kB 182 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vue-core-DtiQ1dr9.js 311 kB 311 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-vueuse-7Q5M-X2w.js 125 kB 125 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-yjs-CP_4YO8u.js 143 kB 143 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-zod-DcCUUPIi.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 6 added / 6 removed

Other — 8.04 MB (baseline 8.04 MB) • 🔴 +1.53 kB

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/i18n-C9MrSS53.js (new) 547 kB 🔴 +547 kB 🔴 +106 kB 🔴 +83.2 kB
assets/i18n-DMDRbV_R.js (removed) 545 kB 🟢 -545 kB 🟢 -106 kB 🟢 -82.8 kB
assets/nodeDefs-BnwYZsRe.js (removed) 494 kB 🟢 -494 kB 🟢 -75.3 kB 🟢 -51.8 kB
assets/nodeDefs-T8ki-3ab.js (new) 494 kB 🔴 +494 kB 🔴 +75.3 kB 🔴 +51.8 kB
assets/nodeDefs-CVMvffJd.js (removed) 453 kB 🟢 -453 kB 🟢 -70.3 kB 🟢 -49.7 kB
assets/nodeDefs-DRlsrA3Y.js (new) 453 kB 🔴 +453 kB 🔴 +70.3 kB 🔴 +49.7 kB
assets/nodeDefs-Bhwr0_qt.js (removed) 452 kB 🟢 -452 kB 🟢 -67.9 kB 🟢 -47.8 kB
assets/nodeDefs-CzCfhTal.js (new) 452 kB 🔴 +452 kB 🔴 +67.9 kB 🔴 +47.8 kB
assets/nodeDefs-CuDYP-Ax.js (new) 418 kB 🔴 +418 kB 🔴 +68.4 kB 🔴 +47.7 kB
assets/nodeDefs-D3rH0GXo.js (removed) 418 kB 🟢 -418 kB 🟢 -68.4 kB 🟢 -47.7 kB
assets/nodeDefs-B8HFl03z.js (removed) 406 kB 🟢 -406 kB 🟢 -66.8 kB 🟢 -47.4 kB
assets/nodeDefs-Comy_sMi.js (new) 406 kB 🔴 +406 kB 🔴 +66.8 kB 🔴 +47.4 kB
assets/nodeDefs-DuxLvF2P.js (new) 402 kB 🔴 +402 kB 🔴 +65.4 kB 🔴 +47.9 kB
assets/nodeDefs-ZRmGudls.js (removed) 402 kB 🟢 -402 kB 🟢 -65.4 kB 🟢 -47.8 kB
assets/nodeDefs-CDP9UeA-.js (new) 402 kB 🔴 +402 kB 🔴 +66.9 kB 🔴 +48.5 kB
assets/nodeDefs-Cxe4eF5X.js (removed) 402 kB 🟢 -402 kB 🟢 -66.9 kB 🟢 -48.5 kB
assets/nodeDefs-BXi-pYlO.js (new) 399 kB 🔴 +399 kB 🔴 +64 kB 🔴 +46.7 kB
assets/nodeDefs-Ci3336-6.js (removed) 399 kB 🟢 -399 kB 🟢 -64 kB 🟢 -46.7 kB
assets/nodeDefs-BQQ7epXP.js (removed) 394 kB 🟢 -394 kB 🟢 -63 kB 🟢 -46.1 kB
assets/nodeDefs-DwSpKc2S.js (new) 394 kB 🔴 +394 kB 🔴 +63 kB 🔴 +46.1 kB
assets/nodeDefs-BBzKxTIy.js (new) 369 kB 🔴 +369 kB 🔴 +65.6 kB 🔴 +45.9 kB
assets/nodeDefs-LI1J_566.js (removed) 369 kB 🟢 -369 kB 🟢 -65.6 kB 🟢 -45.9 kB
assets/nodeDefs-BsK7YlZv.js (new) 366 kB 🔴 +366 kB 🔴 +64.6 kB 🔴 +44.8 kB
assets/nodeDefs-C4H2Yzrv.js (removed) 366 kB 🟢 -366 kB 🟢 -64.6 kB 🟢 -44.8 kB
assets/main-De96SAcR.js (removed) 222 kB 🟢 -222 kB 🟢 -57.4 kB 🟢 -45.3 kB
assets/main-sF5tizy-.js (new) 222 kB 🔴 +222 kB 🔴 +57.4 kB 🔴 +45.3 kB
assets/main-4PccOdiO.js (removed) 199 kB 🟢 -199 kB 🟢 -51.9 kB 🟢 -41.9 kB
assets/main-BVnshHMY.js (new) 199 kB 🔴 +199 kB 🔴 +51.9 kB 🔴 +41.9 kB
assets/main-CZ_ZoKrz.js (removed) 190 kB 🟢 -190 kB 🟢 -51.7 kB 🟢 -41.4 kB
assets/main-hknb2a26.js (new) 190 kB 🔴 +190 kB 🔴 +51.7 kB 🔴 +41.4 kB
assets/main-BMvp_ngw.js (new) 182 kB 🔴 +182 kB 🔴 +51.4 kB 🔴 +41 kB
assets/main-BODcCr1I.js (removed) 182 kB 🟢 -182 kB 🟢 -51.4 kB 🟢 -41 kB
assets/main-Bo_nk-LH.js (removed) 167 kB 🟢 -167 kB 🟢 -49.9 kB 🟢 -41.8 kB
assets/main-DchxU7Pt.js (new) 167 kB 🔴 +167 kB 🔴 +49.9 kB 🔴 +41.8 kB
assets/main-C2EBpmzg.js (new) 164 kB 🔴 +164 kB 🔴 +49.3 kB 🔴 +39.9 kB
assets/main-CM3j3xAc.js (removed) 164 kB 🟢 -164 kB 🟢 -49.3 kB 🟢 -39.9 kB
assets/main-BERG8Y4E.js (removed) 161 kB 🟢 -161 kB 🟢 -48.8 kB 🟢 -40.6 kB
assets/main-Bs4m2I_7.js (new) 161 kB 🔴 +161 kB 🔴 +48.8 kB 🔴 +40.6 kB
assets/main-B0aq4SOP.js (new) 159 kB 🔴 +159 kB 🔴 +49 kB 🔴 +41.2 kB
assets/main-KB02fdvg.js (removed) 159 kB 🟢 -159 kB 🟢 -49 kB 🟢 -41.2 kB
assets/main-C9ucaZMP.js (removed) 158 kB 🟢 -158 kB 🟢 -48.3 kB 🟢 -40.7 kB
assets/main-CumaBqGT.js (new) 158 kB 🔴 +158 kB 🔴 +48.3 kB 🔴 +40.7 kB
assets/main-6sQ9dyIE.js (new) 140 kB 🔴 +140 kB 🔴 +47.6 kB 🔴 +37.9 kB
assets/main-A9K8E17X.js (removed) 140 kB 🟢 -140 kB 🟢 -47.6 kB 🟢 -37.9 kB
assets/main-cwloH2g5.js (removed) 139 kB 🟢 -139 kB 🟢 -47.6 kB 🟢 -37.7 kB
assets/main-Dn_22rOe.js (new) 139 kB 🔴 +139 kB 🔴 +47.6 kB 🔴 +37.7 kB
assets/core-Bb0eRvOK.js (new) 73.7 kB 🔴 +73.7 kB 🔴 +19 kB 🔴 +16.3 kB
assets/core-CuZEkTqo.js (removed) 73.7 kB 🟢 -73.7 kB 🟢 -19 kB 🟢 -16.3 kB
assets/groupNode-BMRecJGn.js (new) 71.8 kB 🔴 +71.8 kB 🔴 +17.7 kB 🔴 +15.5 kB
assets/groupNode-DddaJ-fe.js (removed) 71.8 kB 🟢 -71.8 kB 🟢 -17.6 kB 🟢 -15.5 kB
assets/WidgetSelect-3sEblmxO.js (removed) 58 kB 🟢 -58 kB 🟢 -12.4 kB 🟢 -10.7 kB
assets/WidgetSelect-D2Xkz7Ya.js (new) 58 kB 🔴 +58 kB 🔴 +12.4 kB 🔴 +10.7 kB
assets/SubscriptionRequiredDialogContentWorkspace-Cev1Ab37.js (removed) 46.2 kB 🟢 -46.2 kB 🟢 -8.65 kB 🟢 -7.52 kB
assets/SubscriptionRequiredDialogContentWorkspace-d4TlWXGy.js (new) 46.2 kB 🔴 +46.2 kB 🔴 +8.64 kB 🔴 +7.5 kB
assets/WidgetPainter-CNncXssY.js (removed) 32.9 kB 🟢 -32.9 kB 🟢 -7.97 kB 🟢 -7.07 kB
assets/WidgetPainter-IqNYv0mw.js (new) 32.9 kB 🔴 +32.9 kB 🔴 +7.97 kB 🔴 +7.07 kB
assets/Load3DControls-Ct-3IYXq.js (removed) 30.9 kB 🟢 -30.9 kB 🟢 -5.34 kB 🟢 -4.65 kB
assets/Load3DControls-zKEPkgoZ.js (new) 30.9 kB 🔴 +30.9 kB 🔴 +5.34 kB 🔴 +4.66 kB
assets/WorkspacePanelContent-BJfoYKE9.js (removed) 29.3 kB 🟢 -29.3 kB 🟢 -6.16 kB 🟢 -5.41 kB
assets/WorkspacePanelContent-Kr3_mM8j.js (new) 29.3 kB 🔴 +29.3 kB 🔴 +6.16 kB 🔴 +5.41 kB
assets/SubscriptionRequiredDialogContent-Bi9dBY5n.js (new) 25.6 kB 🔴 +25.6 kB 🔴 +6.56 kB 🔴 +5.79 kB
assets/SubscriptionRequiredDialogContent-C2uoZPZr.js (removed) 25.6 kB 🟢 -25.6 kB 🟢 -6.56 kB 🟢 -5.78 kB
assets/Load3dViewerContent-3ZhRkMl5.js (new) 23 kB 🔴 +23 kB 🔴 +5.18 kB 🔴 +4.5 kB
assets/Load3dViewerContent-CR1JfWIY.js (removed) 23 kB 🟢 -23 kB 🟢 -5.18 kB 🟢 -4.5 kB
assets/WidgetImageCrop-BsEL-Tby.js (new) 22.2 kB 🔴 +22.2 kB 🔴 +5.52 kB 🔴 +4.85 kB
assets/WidgetImageCrop-Dw71c6ig.js (removed) 22.2 kB 🟢 -22.2 kB 🟢 -5.51 kB 🟢 -4.85 kB
assets/SubscriptionPanelContentWorkspace-D8HPai9c.js (new) 22 kB 🔴 +22 kB 🔴 +5.11 kB 🔴 +4.49 kB
assets/SubscriptionPanelContentWorkspace-Dz0C7uQR.js (removed) 22 kB 🟢 -22 kB 🟢 -5.11 kB 🟢 -4.49 kB
assets/CurrentUserPopoverWorkspace-BbII1BC0.js (removed) 20.5 kB 🟢 -20.5 kB 🟢 -4.94 kB 🟢 -4.41 kB
assets/CurrentUserPopoverWorkspace-zbmENrXi.js (new) 20.5 kB 🔴 +20.5 kB 🔴 +4.94 kB 🔴 +4.42 kB
assets/commands-4Ex6JXL0.js (removed) 19.2 kB 🟢 -19.2 kB 🟢 -4.09 kB 🟢 -3.16 kB
assets/commands-BnVLe_Bi.js (new) 19.2 kB 🔴 +19.2 kB 🔴 +4.08 kB 🔴 +3.15 kB
assets/SignInContent-B88gLbXr.js (new) 18.9 kB 🔴 +18.9 kB 🔴 +4.77 kB 🔴 +4.18 kB
assets/SignInContent-EV-XDTM7.js (removed) 18.9 kB 🟢 -18.9 kB 🟢 -4.77 kB 🟢 -4.18 kB
assets/WidgetInputNumber-BpPwoSlD.js (removed) 18.1 kB 🟢 -18.1 kB 🟢 -4.64 kB 🟢 -4.12 kB
assets/WidgetInputNumber-CoOJyrFK.js (new) 18.1 kB 🔴 +18.1 kB 🔴 +4.64 kB 🔴 +4.12 kB
assets/commands-4eY_jIIw.js (removed) 17.9 kB 🟢 -17.9 kB 🟢 -3.76 kB 🟢 -2.96 kB
assets/commands-BL762dz-.js (new) 17.9 kB 🔴 +17.9 kB 🔴 +3.76 kB 🔴 +2.96 kB
assets/commands-BZxSrlEH.js (new) 17.9 kB 🔴 +17.9 kB 🔴 +3.83 kB 🔴 +3.03 kB
assets/commands-DTom9f1s.js (removed) 17.9 kB 🟢 -17.9 kB 🟢 -3.83 kB 🟢 -3.02 kB
assets/WidgetRecordAudio-BBYWUdiI.js (new) 17.4 kB 🔴 +17.4 kB 🔴 +5.01 kB 🔴 +4.49 kB
assets/WidgetRecordAudio-BqpDkkDP.js (removed) 17.4 kB 🟢 -17.4 kB 🟢 -5.01 kB 🟢 -4.47 kB
assets/commands-CdENTy7Q.js (new) 17.3 kB 🔴 +17.3 kB 🔴 +3.86 kB 🔴 +3.04 kB
assets/commands-ZTJwiV8a.js (removed) 17.3 kB 🟢 -17.3 kB 🟢 -3.86 kB 🟢 -3.04 kB
assets/commands-0V4s4r1K.js (new) 17 kB 🔴 +17 kB 🔴 +3.59 kB 🔴 +2.97 kB
assets/commands-Db23kZm5.js (removed) 17 kB 🟢 -17 kB 🟢 -3.59 kB 🟢 -2.97 kB
assets/commands-B2u5OAt2.js (removed) 16.5 kB 🟢 -16.5 kB 🟢 -3.58 kB 🟢 -2.96 kB
assets/commands-BXsNoiTn.js (new) 16.5 kB 🔴 +16.5 kB 🔴 +3.58 kB 🔴 +2.96 kB
assets/commands-BwgnbfCS.js (removed) 16.5 kB 🟢 -16.5 kB 🟢 -3.48 kB 🟢 -2.84 kB
assets/commands-C23MOD89.js (new) 16.5 kB 🔴 +16.5 kB 🔴 +3.49 kB 🔴 +2.84 kB
assets/commands-BAAf-WrY.js (removed) 16.4 kB 🟢 -16.4 kB 🟢 -3.45 kB 🟢 -2.89 kB
assets/commands-DReOpKnh.js (new) 16.4 kB 🔴 +16.4 kB 🔴 +3.45 kB 🔴 +2.88 kB
assets/commands-CMf3AlGU.js (removed) 16.3 kB 🟢 -16.3 kB 🟢 -3.72 kB 🟢 -2.91 kB
assets/commands-Cq73R4Wp.js (new) 16.3 kB 🔴 +16.3 kB 🔴 +3.72 kB 🔴 +2.91 kB
assets/Load3D-BOFjMFTB.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +4.03 kB 🔴 +3.51 kB
assets/Load3D-DDP1r9Jq.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -4.03 kB 🟢 -3.51 kB
assets/commands-CriyFW2y.js (new) 15.6 kB 🔴 +15.6 kB 🔴 +3.64 kB 🔴 +2.75 kB
assets/commands-y391QX3e.js (removed) 15.6 kB 🟢 -15.6 kB 🟢 -3.64 kB 🟢 -2.75 kB
assets/commands-CyFcxndj.js (new) 15.4 kB 🔴 +15.4 kB 🔴 +3.6 kB 🔴 +2.68 kB
assets/commands-uXFULtu8.js (removed) 15.4 kB 🟢 -15.4 kB 🟢 -3.6 kB 🟢 -2.67 kB
assets/load3d-4-NXS2-i.js (new) 14.8 kB 🔴 +14.8 kB 🔴 +4.21 kB 🔴 +3.65 kB
assets/load3d-De4WfBUh.js (removed) 14.8 kB 🟢 -14.8 kB 🟢 -4.21 kB 🟢 -3.65 kB
assets/AudioPreviewPlayer-BVfAeonu.js (removed) 11 kB 🟢 -11 kB 🟢 -3.25 kB 🟢 -2.91 kB
assets/AudioPreviewPlayer-DEfcjl79.js (new) 11 kB 🔴 +11 kB 🔴 +3.25 kB 🔴 +2.92 kB
assets/WidgetCurve-C0pqvMMz.js (removed) 9.36 kB 🟢 -9.36 kB 🟢 -3 kB 🟢 -2.71 kB
assets/WidgetCurve-Dh_Oiqjm.js (new) 9.36 kB 🔴 +9.36 kB 🔴 +3 kB 🔴 +2.71 kB
assets/SelectValue-knMV-ROg.js (new) 9.34 kB 🔴 +9.34 kB 🔴 +2.38 kB 🔴 +2.11 kB
assets/nodeTemplates-BRpMJRU9.js (new) 9.34 kB 🔴 +9.34 kB 🔴 +3.27 kB 🔴 +2.88 kB
assets/nodeTemplates-CuHDWBcz.js (removed) 9.34 kB 🟢 -9.34 kB 🟢 -3.27 kB 🟢 -2.88 kB
assets/SelectValue-D3C-Eb3g.js (removed) 9.3 kB 🟢 -9.3 kB 🟢 -2.38 kB 🟢 -2.1 kB
assets/InviteMemberDialogContent-DhwpXDUg.js (removed) 7.37 kB 🟢 -7.37 kB 🟢 -2.3 kB 🟢 -2.01 kB
assets/InviteMemberDialogContent-Dz3lUP__.js (new) 7.37 kB 🔴 +7.37 kB 🔴 +2.3 kB 🔴 +2.01 kB
assets/WidgetImageCompare-BbyK3jA-.js (removed) 7.35 kB 🟢 -7.35 kB 🟢 -2.18 kB 🟢 -1.9 kB
assets/WidgetImageCompare-CJ9FBr4m.js (new) 7.35 kB 🔴 +7.35 kB 🔴 +2.18 kB 🔴 +1.9 kB
assets/Load3DConfiguration-BWbRQxhx.js (removed) 6.27 kB 🟢 -6.27 kB 🟢 -1.91 kB 🟢 -1.68 kB
assets/Load3DConfiguration-C3buGCuV.js (new) 6.27 kB 🔴 +6.27 kB 🔴 +1.91 kB 🔴 +1.68 kB
assets/onboardingCloudRoutes-DL6BCau1.js (new) 6.07 kB 🔴 +6.07 kB 🔴 +1.89 kB 🔴 +1.64 kB
assets/onboardingCloudRoutes-DY2t0844.js (removed) 6.07 kB 🟢 -6.07 kB 🟢 -1.89 kB 🟢 -1.64 kB
assets/CreateWorkspaceDialogContent-Dh1dMmBu.js (new) 5.54 kB 🔴 +5.54 kB 🔴 +2 kB 🔴 +1.75 kB
assets/CreateWorkspaceDialogContent-HTwLxduA.js (removed) 5.54 kB 🟢 -5.54 kB 🟢 -2 kB 🟢 -1.75 kB
assets/FreeTierDialogContent-AJihlRsO.js (new) 5.42 kB 🔴 +5.42 kB 🔴 +1.91 kB 🔴 +1.68 kB
assets/FreeTierDialogContent-B5Ik7k4V.js (removed) 5.42 kB 🟢 -5.42 kB 🟢 -1.91 kB 🟢 -1.69 kB
assets/EditWorkspaceDialogContent-DDFVD3DC.js (removed) 5.35 kB 🟢 -5.35 kB 🟢 -1.96 kB 🟢 -1.72 kB
assets/EditWorkspaceDialogContent-DmDLC8jE.js (new) 5.35 kB 🔴 +5.35 kB 🔴 +1.96 kB 🔴 +1.73 kB
assets/Preview3d-DlM3bMcp.js (removed) 4.96 kB 🟢 -4.96 kB 🟢 -1.63 kB 🟢 -1.43 kB
assets/Preview3d-zcbqwkER.js (new) 4.96 kB 🔴 +4.96 kB 🔴 +1.63 kB 🔴 +1.43 kB
assets/ValueControlPopover-8THMMvY8.js (removed) 4.93 kB 🟢 -4.93 kB 🟢 -1.77 kB 🟢 -1.59 kB
assets/ValueControlPopover-DqAVNZg8.js (new) 4.93 kB 🔴 +4.93 kB 🔴 +1.77 kB 🔴 +1.58 kB
assets/CancelSubscriptionDialogContent-CGw5KBjp.js (removed) 4.81 kB 🟢 -4.81 kB 🟢 -1.8 kB 🟢 -1.58 kB
assets/CancelSubscriptionDialogContent-DlO6CIvl.js (new) 4.81 kB 🔴 +4.81 kB 🔴 +1.8 kB 🔴 +1.58 kB
assets/AnimationControls-CPCyy2bz.js (removed) 4.61 kB 🟢 -4.61 kB 🟢 -1.6 kB 🟢 -1.41 kB
assets/AnimationControls-DUOF31Ot.js (new) 4.61 kB 🔴 +4.61 kB 🔴 +1.6 kB 🔴 +1.41 kB
assets/WidgetTextarea-B0h4OSSo.js (new) 4.26 kB 🔴 +4.26 kB 🔴 +1.64 kB 🔴 +1.45 kB
assets/WidgetTextarea-b8g5_Bs7.js (removed) 4.26 kB 🟢 -4.26 kB 🟢 -1.64 kB 🟢 -1.45 kB
assets/DeleteWorkspaceDialogContent-C4zk2AFW.js (new) 4.25 kB 🔴 +4.25 kB 🔴 +1.64 kB 🔴 +1.43 kB
assets/DeleteWorkspaceDialogContent-DnlaySce.js (removed) 4.25 kB 🟢 -4.25 kB 🟢 -1.64 kB 🟢 -1.43 kB
assets/WidgetWithControl-Bg--BA2L.js (removed) 4.17 kB 🟢 -4.17 kB 🟢 -1.81 kB 🟢 -1.65 kB
assets/WidgetWithControl-D3OfRGoS.js (new) 4.17 kB 🔴 +4.17 kB 🔴 +1.81 kB 🔴 +1.63 kB
assets/LeaveWorkspaceDialogContent-9Yi5hrlp.js (removed) 4.08 kB 🟢 -4.08 kB 🟢 -1.59 kB 🟢 -1.39 kB
assets/LeaveWorkspaceDialogContent-DhuOMDch.js (new) 4.08 kB 🔴 +4.08 kB 🔴 +1.58 kB 🔴 +1.38 kB
assets/RemoveMemberDialogContent-BOiirvil.js (removed) 4.06 kB 🟢 -4.06 kB 🟢 -1.54 kB 🟢 -1.34 kB
assets/RemoveMemberDialogContent-kCr0dEcY.js (new) 4.06 kB 🔴 +4.06 kB 🔴 +1.54 kB 🔴 +1.35 kB
assets/RevokeInviteDialogContent-Ch7OtGkC.js (new) 3.97 kB 🔴 +3.97 kB 🔴 +1.55 kB 🔴 +1.36 kB
assets/RevokeInviteDialogContent-Dy-Tr21x.js (removed) 3.97 kB 🟢 -3.97 kB 🟢 -1.55 kB 🟢 -1.36 kB
assets/InviteMemberUpsellDialogContent-Bpww65Gn.js (new) 3.86 kB 🔴 +3.86 kB 🔴 +1.42 kB 🔴 +1.25 kB
assets/InviteMemberUpsellDialogContent-EhYhQqUt.js (removed) 3.86 kB 🟢 -3.86 kB 🟢 -1.42 kB 🟢 -1.25 kB
assets/tierBenefits-DD3D4ETV.js (new) 3.66 kB 🔴 +3.66 kB 🔴 +1.31 kB 🔴 +1.16 kB
assets/tierBenefits-F6bCKH-2.js (removed) 3.66 kB 🟢 -3.66 kB 🟢 -1.31 kB 🟢 -1.16 kB
assets/Popover-CRNAN1Zu.js (new) 3.65 kB 🔴 +3.65 kB 🔴 +1.43 kB 🔴 +1.27 kB
assets/Popover-X9cXugD_.js (removed) 3.65 kB 🟢 -3.65 kB 🟢 -1.44 kB 🟢 -1.26 kB
assets/WidgetGalleria-C2PVE-gv.js (removed) 3.6 kB 🟢 -3.6 kB 🟢 -1.4 kB 🟢 -1.25 kB
assets/WidgetGalleria-CWPm_CXr.js (new) 3.6 kB 🔴 +3.6 kB 🔴 +1.4 kB 🔴 +1.25 kB
assets/WidgetToggleSwitch-B5gu8aGL.js (new) 3.54 kB 🔴 +3.54 kB 🔴 +1.34 kB 🔴 +1.19 kB
assets/WidgetToggleSwitch-DC5qx9Iv.js (removed) 3.54 kB 🟢 -3.54 kB 🟢 -1.33 kB 🟢 -1.18 kB
assets/Slider-DK6apKNA.js (new) 3.52 kB 🔴 +3.52 kB 🔴 +1.35 kB 🔴 +1.17 kB
assets/Slider-x2XW5eO3.js (removed) 3.52 kB 🟢 -3.52 kB 🟢 -1.36 kB 🟢 -1.18 kB
assets/saveMesh-CWXTcjYu.js (new) 3.42 kB 🔴 +3.42 kB 🔴 +1.47 kB 🔴 +1.31 kB
assets/saveMesh-x0t1AM-u.js (removed) 3.42 kB 🟢 -3.42 kB 🟢 -1.48 kB 🟢 -1.31 kB
assets/WidgetBoundingBox-BfW4RBS9.js (new) 3.19 kB 🔴 +3.19 kB 🔴 +893 B 🔴 +780 B
assets/WidgetBoundingBox-DCgQGG34.js (removed) 3.19 kB 🟢 -3.19 kB 🟢 -892 B 🟢 -778 B
assets/cloudSessionCookie-BDGeeBif.js (new) 3.14 kB 🔴 +3.14 kB 🔴 +1.1 kB 🔴 +1 kB
assets/cloudSessionCookie-Di3_6Ro6.js (removed) 3.14 kB 🟢 -3.14 kB 🟢 -1.1 kB 🟢 -1.01 kB
assets/WidgetMarkdown-87PSZUoW.js (new) 2.93 kB 🔴 +2.93 kB 🔴 +1.24 kB 🔴 +1.07 kB
assets/WidgetMarkdown-nqccP48m.js (removed) 2.93 kB 🟢 -2.93 kB 🟢 -1.23 kB 🟢 -1.07 kB
assets/GlobalToast-69DOhWaR.js (removed) 2.91 kB 🟢 -2.91 kB 🟢 -1.21 kB 🟢 -1.03 kB
assets/GlobalToast-NrOntoEh.js (new) 2.91 kB 🔴 +2.91 kB 🔴 +1.21 kB 🔴 +1.03 kB
assets/WidgetColorPicker-8EGEDDXs.js (removed) 2.9 kB 🟢 -2.9 kB 🟢 -1.23 kB 🟢 -1.11 kB
assets/WidgetColorPicker-C8_DQL0v.js (new) 2.9 kB 🔴 +2.9 kB 🔴 +1.23 kB 🔴 +1.11 kB
assets/WidgetInputText-BfIILuYF.js (removed) 2.89 kB 🟢 -2.89 kB 🟢 -1.24 kB 🟢 -1.12 kB
assets/WidgetInputText-vevCDAun.js (new) 2.89 kB 🔴 +2.89 kB 🔴 +1.25 kB 🔴 +1.11 kB
assets/MediaVideoTop-BpARjupw.js (new) 2.78 kB 🔴 +2.78 kB 🔴 +1.13 kB 🔴 +1 kB
assets/MediaVideoTop-D0Uxi_8W.js (removed) 2.78 kB 🟢 -2.78 kB 🟢 -1.13 kB 🟢 -1.01 kB
assets/ApiNodesSignInContent-CQGLp8Pg.js (new) 2.69 kB 🔴 +2.69 kB 🔴 +1.05 kB 🔴 +923 B
assets/ApiNodesSignInContent-DdISqJt_.js (removed) 2.69 kB 🟢 -2.69 kB 🟢 -1.05 kB 🟢 -957 B
assets/WidgetChart-BYr9LIig.js (new) 2.21 kB 🔴 +2.21 kB 🔴 +952 B 🔴 +820 B
assets/WidgetChart-D4E64P4X.js (removed) 2.21 kB 🟢 -2.21 kB 🟢 -952 B 🟢 -819 B
assets/SubscribeToRun-Cpz0SLuY.js (new) 2.06 kB 🔴 +2.06 kB 🔴 +951 B 🔴 +846 B
assets/SubscribeToRun-v9U-7SFT.js (removed) 2.06 kB 🟢 -2.06 kB 🟢 -950 B 🟢 -831 B
assets/SubscriptionBenefits-CXHqTaYn.js (new) 2.01 kB 🔴 +2.01 kB 🔴 +701 B 🔴 +599 B
assets/SubscriptionBenefits-DdmixFh-.js (removed) 2.01 kB 🟢 -2.01 kB 🟢 -698 B 🟢 -598 B
assets/WidgetLayoutField-BnXvLfkJ.js (removed) 2 kB 🟢 -2 kB 🟢 -899 B 🟢 -796 B
assets/WidgetLayoutField-V1DZwLgT.js (new) 2 kB 🔴 +2 kB 🔴 +897 B 🔴 +799 B
assets/Media3DTop-BiQkqzKM.js (new) 1.83 kB 🔴 +1.83 kB 🔴 +899 B 🔴 +767 B
assets/Media3DTop-CFJ8TBAs.js (removed) 1.83 kB 🟢 -1.83 kB 🟢 -900 B 🟢 -767 B
assets/MediaImageTop-CZ773gJ9.js (removed) 1.81 kB 🟢 -1.81 kB 🟢 -893 B 🟢 -765 B
assets/MediaImageTop-DoRnE-bZ.js (new) 1.81 kB 🔴 +1.81 kB 🔴 +893 B 🔴 +766 B
assets/BaseViewTemplate-Be40t4Iu.js (removed) 1.78 kB 🟢 -1.78 kB 🟢 -923 B 🟢 -836 B
assets/BaseViewTemplate-CjY84GoU.js (new) 1.78 kB 🔴 +1.78 kB 🔴 +925 B 🔴 +835 B
assets/CloudRunButtonWrapper-DQF6XKGt.js (new) 1.72 kB 🔴 +1.72 kB 🔴 +803 B 🔴 +716 B
assets/CloudRunButtonWrapper-DUMT8_kA.js (removed) 1.72 kB 🟢 -1.72 kB 🟢 -803 B 🟢 -730 B
assets/auto-CtFmjb6K.js (new) 1.7 kB 🔴 +1.7 kB 🔴 +621 B 🔴 +564 B
assets/auto-DaAGiCO7.js (removed) 1.7 kB 🟢 -1.7 kB 🟢 -622 B 🟢 -566 B
assets/cloudBadges-CN3oEecJ.js (removed) 1.54 kB 🟢 -1.54 kB 🟢 -794 B 🟢 -686 B
assets/cloudBadges-DB1tT4J8.js (new) 1.54 kB 🔴 +1.54 kB 🔴 +792 B 🔴 +690 B
assets/signInSchema-C1RDi65C.js (removed) 1.53 kB 🟢 -1.53 kB 🟢 -564 B 🟢 -524 B
assets/signInSchema-Cz3Tp6EE.js (new) 1.53 kB 🔴 +1.53 kB 🔴 +563 B 🔴 +518 B
assets/MediaAudioTop-C_U19GUN.js (removed) 1.43 kB 🟢 -1.43 kB 🟢 -765 B 🟢 -636 B
assets/MediaAudioTop-CRtIRcAY.js (new) 1.43 kB 🔴 +1.43 kB 🔴 +765 B 🔴 +639 B
assets/previousFullPath-B6xFsb42.js (removed) 1.39 kB 🟢 -1.39 kB 🟢 -651 B 🟢 -580 B
assets/previousFullPath-Bb8I5HsF.js (new) 1.39 kB 🔴 +1.39 kB 🔴 +650 B 🔴 +569 B
assets/cloudSubscription-C765e9kz.js (removed) 1.37 kB 🟢 -1.37 kB 🟢 -676 B 🟢 -584 B
assets/cloudSubscription-H9PqCK7n.js (new) 1.37 kB 🔴 +1.37 kB 🔴 +673 B 🔴 +583 B
assets/Textarea-DnTlfSYg.js (removed) 1.37 kB 🟢 -1.37 kB 🟢 -714 B 🟢 -625 B
assets/Textarea-hSoGqB0Z.js (new) 1.37 kB 🔴 +1.37 kB 🔴 +714 B 🔴 +625 B
assets/VideoPlayOverlay-b9xCyIM9.js (new) 1.35 kB 🔴 +1.35 kB 🔴 +699 B 🔴 +618 B
assets/VideoPlayOverlay-BOeozZ2P.js (removed) 1.35 kB 🟢 -1.35 kB 🟢 -701 B 🟢 -620 B
assets/Loader-BzcmNzQH.js (removed) 1.14 kB 🟢 -1.14 kB 🟢 -631 B 🟢 -549 B
assets/Loader-Dxz91Dh1.js (new) 1.14 kB 🔴 +1.14 kB 🔴 +629 B 🔴 +545 B
assets/widgetPropFilter-D5drFiH0.js (new) 1.11 kB 🔴 +1.11 kB 🔴 +516 B 🔴 +462 B
assets/widgetPropFilter-tYaGazrB.js (removed) 1.11 kB 🟢 -1.11 kB 🟢 -513 B 🟢 -453 B
assets/Load3D-ClevQ9RW.js (removed) 1.11 kB 🟢 -1.11 kB 🟢 -519 B 🟢 -458 B
assets/Load3D-tmxxo3Jh.js (new) 1.11 kB 🔴 +1.11 kB 🔴 +516 B 🔴 +458 B
assets/nightlyBadges-CK61RrD0.js (new) 1.04 kB 🔴 +1.04 kB 🔴 +548 B 🔴 +487 B
assets/nightlyBadges-D7GmQBlQ.js (removed) 1.04 kB 🟢 -1.04 kB 🟢 -548 B 🟢 -477 B
assets/Load3dViewerContent-CFKx_IyB.js (removed) 1.04 kB 🟢 -1.04 kB 🟢 -488 B 🟢 -435 B
assets/Load3dViewerContent-D102qm2z.js (new) 1.04 kB 🔴 +1.04 kB 🔴 +486 B 🔴 +432 B
assets/MediaOtherTop-0qy_sUz9.js (removed) 1.02 kB 🟢 -1.02 kB 🟢 -570 B 🟢 -478 B
assets/MediaOtherTop-Bv9_XpJf.js (new) 1.02 kB 🔴 +1.02 kB 🔴 +571 B 🔴 +478 B
assets/MediaTextTop-BIFFsGpz.js (removed) 1.01 kB 🟢 -1.01 kB 🟢 -566 B 🟢 -480 B
assets/MediaTextTop-DOEMDxgs.js (new) 1.01 kB 🔴 +1.01 kB 🔴 +566 B 🔴 +480 B
assets/SubscriptionPanelContentWorkspace-CJrtq2GH.js (removed) 963 B 🟢 -963 B 🟢 -457 B 🟢 -396 B
assets/SubscriptionPanelContentWorkspace-CwDzXCI9.js (new) 963 B 🔴 +963 B 🔴 +457 B 🔴 +396 B
assets/ComfyOrgHeader-BvczSZom.js (removed) 910 B 🟢 -910 B 🟢 -496 B 🟢 -429 B
assets/ComfyOrgHeader-Cp3wIlKI.js (new) 910 B 🔴 +910 B 🔴 +496 B 🔴 +458 B
assets/WidgetLegacy-B73cAf-b.js (new) 787 B 🔴 +787 B 🔴 +403 B 🔴 +345 B
assets/WidgetLegacy-CIG92uhR.js (removed) 787 B 🟢 -787 B 🟢 -403 B 🟢 -349 B
assets/changeTracker-BRTUqoFN.js (removed) 763 B 🟢 -763 B 🟢 -392 B 🟢 -341 B
assets/changeTracker-XP1QMvEj.js (new) 763 B 🔴 +763 B 🔴 +392 B 🔴 +339 B
assets/graphHasMissingNodes-BU5u8lYu.js (new) 761 B 🔴 +761 B 🔴 +373 B 🔴 +318 B
assets/graphHasMissingNodes-DaS1dt2k.js (removed) 761 B 🟢 -761 B 🟢 -372 B 🟢 -320 B
assets/constants-KYihJEkp.js (new) 579 B 🔴 +579 B 🔴 +256 B 🔴 +228 B
assets/constants-ogISyp4e.js (removed) 579 B 🟢 -579 B 🟢 -256 B 🟢 -228 B
assets/WidgetBoundingBox-BiPCu9PR.js (new) 283 B 🔴 +283 B 🔴 +185 B 🔴 +169 B
assets/WidgetBoundingBox-D5TOmv7e.js (removed) 283 B 🟢 -283 B 🟢 -185 B 🟢 -166 B
assets/src-BSEsXra9.js (new) 251 B 🔴 +251 B 🔴 +210 B 🔴 +177 B
assets/src-D0nozNwP.js (removed) 251 B 🟢 -251 B 🟢 -207 B 🟢 -180 B
assets/i18n-B_vVEnei.js (new) 199 B 🔴 +199 B 🔴 +161 B 🔴 +138 B
assets/i18n-Nac_4Ovg.js (removed) 199 B 🟢 -199 B 🟢 -163 B 🟢 -143 B
assets/comfy-logo-single-B810ZRS_.js (new) 198 B 🔴 +198 B 🔴 +162 B 🔴 +127 B
assets/comfy-logo-single-BcOH_oP5.js (removed) 198 B 🟢 -198 B 🟢 -162 B 🟢 -128 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-DLICfi3-.js 1.97 kB 1.97 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/telemetry-zZf2dHJ2.js 226 B 226 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/types-DT3N7am7.js 204 B 204 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-DIRwAHBY.js 3.01 kB 3.01 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetTypes-DzBxiY8I.js 393 B 393 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 120 added / 120 removed

@github-actions
Copy link

github-actions bot commented Mar 11, 2026

⚡ Performance Report

ℹ️ Collecting baseline variance data (0/5 runs). Significance will appear after 2 main branch runs.

Metric Baseline PR Δ
canvas-idle: style recalcs 12 11 -6%
canvas-idle: layouts 0 0 +0%
canvas-idle: task duration 343ms 366ms +7%
canvas-mouse-sweep: style recalcs 77 78 +1%
canvas-mouse-sweep: layouts 12 12 +3%
canvas-mouse-sweep: task duration 779ms 805ms +3%
dom-widget-clipping: style recalcs 15 15 -2%
dom-widget-clipping: layouts 0 0 +0%
dom-widget-clipping: task duration 347ms 359ms +4%
subgraph-dom-widget-clipping: style recalcs 50 49 -2%
subgraph-dom-widget-clipping: layouts 0 0 +0%
subgraph-dom-widget-clipping: task duration 398ms 395ms -1%
subgraph-idle: style recalcs 13 13 +0%
subgraph-idle: layouts 0 0 +0%
subgraph-idle: task duration 356ms 345ms -3%
subgraph-mouse-sweep: style recalcs 78 76 -2%
subgraph-mouse-sweep: layouts 16 16 +0%
subgraph-mouse-sweep: task duration 676ms 695ms +3%
Raw data
{
  "timestamp": "2026-03-12T07:13:32.828Z",
  "gitSha": "d7f4a03e8e0f6cd2d7967badbda2f33c74c69cbb",
  "branch": "feat/cloud-missing-model-from-errortab",
  "measurements": [
    {
      "name": "canvas-idle",
      "durationMs": 2016.0730000000058,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 9.002999999999998,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 358.60900000000004,
      "heapDeltaBytes": 1365372
    },
    {
      "name": "canvas-idle",
      "durationMs": 2037.238000000002,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.776,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 376.03700000000003,
      "heapDeltaBytes": 762612
    },
    {
      "name": "canvas-idle",
      "durationMs": 2033.6840000000507,
      "styleRecalcs": 11,
      "styleRecalcDurationMs": 10.411999999999999,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 364.1979999999999,
      "heapDeltaBytes": 1317804
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 2006.812000000025,
      "styleRecalcs": 83,
      "styleRecalcDurationMs": 58.675999999999995,
      "layouts": 13,
      "layoutDurationMs": 4.5649999999999995,
      "taskDurationMs": 884.005,
      "heapDeltaBytes": 1557160
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1810.5370000000107,
      "styleRecalcs": 74,
      "styleRecalcDurationMs": 39.021,
      "layouts": 12,
      "layoutDurationMs": 3.658,
      "taskDurationMs": 756.316,
      "heapDeltaBytes": 531660
    },
    {
      "name": "canvas-mouse-sweep",
      "durationMs": 1832.9619999999522,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 39.245000000000005,
      "layouts": 12,
      "layoutDurationMs": 3.5370000000000004,
      "taskDurationMs": 774.437,
      "heapDeltaBytes": 2108932
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 592.0270000000301,
      "styleRecalcs": 14,
      "styleRecalcDurationMs": 9.824,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 374.215,
      "heapDeltaBytes": 12337112
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 600.8539999999698,
      "styleRecalcs": 16,
      "styleRecalcDurationMs": 13.811,
      "layouts": 1,
      "layoutDurationMs": 0.19900000000000007,
      "taskDurationMs": 357.542,
      "heapDeltaBytes": 13332000
    },
    {
      "name": "dom-widget-clipping",
      "durationMs": 576.6930000000343,
      "styleRecalcs": 14,
      "styleRecalcDurationMs": 10.258000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 344.915,
      "heapDeltaBytes": 12225000
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 615.7660000000078,
      "styleRecalcs": 50,
      "styleRecalcDurationMs": 13.304,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 398.429,
      "heapDeltaBytes": -4433396
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 601.4790000000403,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 12.8,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 399.15299999999996,
      "heapDeltaBytes": -4124512
    },
    {
      "name": "subgraph-dom-widget-clipping",
      "durationMs": 562.814000000003,
      "styleRecalcs": 48,
      "styleRecalcDurationMs": 11.905,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 386.914,
      "heapDeltaBytes": -4254356
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2004.4510000000173,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 11.312,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 338.97900000000004,
      "heapDeltaBytes": 831764
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2005.8500000000095,
      "styleRecalcs": 15,
      "styleRecalcDurationMs": 15.612,
      "layouts": 1,
      "layoutDurationMs": 0.19800000000000004,
      "taskDurationMs": 359.873,
      "heapDeltaBytes": 1621360
    },
    {
      "name": "subgraph-idle",
      "durationMs": 2019.3869999999947,
      "styleRecalcs": 12,
      "styleRecalcDurationMs": 10.713000000000001,
      "layouts": 0,
      "layoutDurationMs": 0,
      "taskDurationMs": 335.66700000000003,
      "heapDeltaBytes": -5954136
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1731.2760000000367,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 40.106,
      "layouts": 16,
      "layoutDurationMs": 4.744,
      "taskDurationMs": 714.345,
      "heapDeltaBytes": -904472
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1712.615000000028,
      "styleRecalcs": 77,
      "styleRecalcDurationMs": 37.844,
      "layouts": 16,
      "layoutDurationMs": 4.335999999999999,
      "taskDurationMs": 688.297,
      "heapDeltaBytes": -1403884
    },
    {
      "name": "subgraph-mouse-sweep",
      "durationMs": 1718.0329999999913,
      "styleRecalcs": 76,
      "styleRecalcDurationMs": 38.671,
      "layouts": 16,
      "layoutDurationMs": 4.726,
      "taskDurationMs": 681.496,
      "heapDeltaBytes": -1464652
    }
  ]
}

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

Caution

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

⚠️ Outside diff range comments (1)
src/renderer/extensions/vueNodes/components/LGraphNode.vue (1)

343-358: ⚠️ Potential issue | 🟠 Major

Subgraph nodes still miss missing-model error state.

Line 354 passes nodeLocatorId.value, which is built by src/utils/graphTraversalUtil.ts:19-29 and includes the subgraph path, into missingModelStore.hasMissingModelOnNode(). But src/platform/missingModel/missingModelStore.ts:126-136 shows that lookup is currently keyed by raw node IDs only. That makes subgraph leaf nodes return false here, so they never get the red outline/footer even when a missing model is present.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/renderer/extensions/vueNodes/components/LGraphNode.vue` around lines 343
- 358, The missing-model check is using the full nodeLocatorId (which includes
subgraph path) but the missingModelStore keys by raw node IDs, so subgraph leaf
nodes miss the error state; change the call(s) that pass nodeLocatorId.value to
missingModelStore to use the raw node id (nodeData.id) instead—specifically
update missingModelStore.hasMissingModelOnNode(nodeLocatorId.value) to
missingModelStore.hasMissingModelOnNode(nodeData.id) (and any other
missingModelStore lookups here that currently receive nodeLocatorId.value) so
lookups match the store's keying.
🧹 Nitpick comments (3)
src/components/rightSidePanel/errors/useErrorGroups.test.ts (1)

50-55: Drop the unused composable mock from this test too.

useErrorGroups() doesn't load @/platform/missingModel/composables/useMissingModelInteractions, so this mock never participates in the behavior under test. It only expands the fake dependency surface and can drift from production wiring.

Based on learnings: "Do not write tests that just test the mocks; ensure tests fail when code behaves unexpectedly."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/components/rightSidePanel/errors/useErrorGroups.test.ts` around lines 50
- 55, Remove the unused vi.mock call for
'@/platform/missingModel/composables/useMissingModelInteractions' from the
useErrorGroups.test.ts file because useErrorGroups() does not import or exercise
that composable; specifically delete the vi.mock(...) block that returns
clearMissingModelState and confirm no other test helpers reference
clearMissingModelState, then run the tests to ensure nothing else depended on
that fake dependency.
src/stores/executionErrorStore.test.ts (1)

21-26: Remove the dead missing-model composable mock.

The real src/platform/missingModel/composables/useMissingModelInteractions.ts module doesn't export clearMissingModelState, and useExecutionErrorStore() doesn't import that module anyway. This mock can't verify any production behavior and only creates a fake dependency surface that can drift out of sync.

Based on learnings: "Do not write tests that just test the mocks; ensure tests fail when code behaves unexpectedly."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/stores/executionErrorStore.test.ts` around lines 21 - 26, Remove the dead
mock for '@/platform/missingModel/composables/useMissingModelInteractions'
introduced via vi.mock that provides clearMissingModelState; delete that vi.mock
block and any references to clearMissingModelState in the test file
(executionErrorStore.test.ts) so the test no longer stubs a non-existent export
or creates a fake dependency surface, and run the tests to confirm no remaining
imports or usages of useMissingModelInteractions remain.
src/platform/missingModel/missingModelScan.test.ts (1)

939-948: Strengthen the abort test so it covers the expensive path.

This only checks that isMissing stays unresolved. It still passes if verifyAssetSupportedCandidates() calls updateModelsForNodeType() after an already-aborted signal, so it won't catch the stale-work regression in the implementation.

💡 Proposed fix
   await verifyAssetSupportedCandidates(candidates, controller.signal)

   // isMissing should remain undefined since we aborted before resolving
   expect(candidates[0].isMissing).toBeUndefined()
+  expect(mockUpdateModelsForNodeType).not.toHaveBeenCalled()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/missingModel/missingModelScan.test.ts` around lines 939 - 948,
Extend the test for verifyAssetSupportedCandidates so it asserts the expensive
work path (updateModelsForNodeType) is not invoked when the signal is already
aborted: arrange a spy or mock on updateModelsForNodeType (or replace it with a
function that would return a slow promise/throw if called), create the aborted
AbortController, call verifyAssetSupportedCandidates(candidates,
controller.signal), then assert the spy was not called and
candidates[0].isMissing is still undefined; this ensures the implementation
returns early and does not start the expensive updateModelsForNodeType work.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/rightSidePanel/errors/useErrorGroups.ts`:
- Around line 615-623: The title is using
missingModelStore.missingModelCandidates?.length which counts raw candidates
instead of grouped items; update buildMissingModelGroups() to use the grouped
collection (missingModelGroups.value.length or the grouped array produced by
groupCandidatesByName) for the count in the title so the displayed number
matches the collapsed rows (reference function buildMissingModelGroups and the
reactive missingModelGroups.value).

In `@src/platform/missingModel/components/MissingModelCard.test.ts`:
- Around line 22-38: The test stubbed i18n (const i18n) lacks the
rightSidePanel.missingModels.unknownCategory translation so the test only
matches the raw key; add an entry under messages.en.rightSidePanel.missingModels
like unknownCategory: 'Expected Label' and then update the assertion in
MissingModelCard.test.ts (where it currently checks for the substring
"unknownCategory") to assert the rendered text equals or contains the translated
string instead of the key; search for the literal "unknownCategory" in the test
to find and replace the assertion and ensure the component uses the i18n
instance in the test render.

In `@src/platform/missingModel/components/MissingModelUrlInput.vue`:
- Around line 151-153: The template uses canImportModels but it’s assigned from
flags.privateModelsEnabled which is reactive and can change later; wrap the
access in a computed so the template remains reactive: replace the plain const
canImportModels = flags.privateModelsEnabled with a computed(()=>
flags.privateModelsEnabled) (keep useFeatureFlags and useModelUpload usage
as-is) so the component reads the reactive flag instead of a frozen snapshot.

In `@src/platform/missingModel/composables/useMissingModelInteractions.test.ts`:
- Around line 132-136: The test setup in the beforeEach block uses
vi.clearAllMocks(), which only clears call history and leaks module-scoped mock
implementations like mockDownloadList and mockGetNodeByExecutionId across tests;
replace vi.clearAllMocks() with vi.resetAllMocks() in the beforeEach (the block
that also calls setActivePinia(createPinia()) and sets app.rootGraph) so that
both call history and mock implementations are reset between tests.

In `@src/platform/missingModel/composables/useMissingModelInteractions.ts`:
- Around line 192-210: The store.importCategoryMismatch flag is never cleared
when the user changes the URL or retries an import, leaving
isSelectionConfirmable() blocked; update handleUrlInput to clear
store.importCategoryMismatch[key] (e.g., delete
store.importCategoryMismatch[key] or set it false) when the URL is edited before
setting the debounce timer and also clear the same flag at the start of the
import flow where fetchUrlMetadata or the import-start function is invoked so
every new fetch/import attempt resets importCategoryMismatch.
- Around line 204-245: The fetchUrlMetadata flow can still update
store.urlMetadata, store.urlErrors, or selectedLibraryModel after the input has
changed; add a per-key request token or AbortSignal tied to the debounce key
(the same key used in store.setDebounceTimer) and check it before mutating state
in fetchUrlMetadata (and likewise in uploadAssetAsync handlers around
assetService.getAssetMetadata and uploadAssetAsync results). Generate and store
a unique token/abort controller when scheduling the debounce, pass/attach it to
the async call, and on any new edit/cancel/clear replace/abort the token; before
writing to store.urlMetadata, store.urlErrors, or selectedLibraryModel verify
the token/signal still matches/not aborted and skip updates if stale.
- Around line 177-189: When applying the selected model in the loop that uses
getNodeByExecutionId and referencingNodes, don't just set widget.value; invoke
the widget's normal mutation path by calling widget.callback?.(value) (or the
same call signature used elsewhere) immediately after setting widget.value so
the node's internal logic runs, and ensure the graph is marked dirty/modified
via the same mutation/dirtying flow used elsewhere before calling
store.removeMissingModelByNameOnNodes; in short, for each found widget call
widget.callback?.(value) and trigger the graph-modified/dirty mutation prior to
removing the missing-model entry.

In `@src/platform/missingModel/missingModelScan.ts`:
- Around line 162-187: The enrichment map is keyed only by name
(candidatesByName), causing cross-directory collisions; change the key to
include directory as well (e.g. use `${c.name}::${c.directory ?? ''}` when
inserting into candidatesByName and when looking up from embeddedModels use
`${model.name}::${model.directory ?? ''}`), and optionally keep a fallback
name-only lookup if you need backward compatibility (check
candidatesByName.get(`${model.name}::${model.directory ?? ''}`) first, then
candidatesByName.get(model.name) if not found) so each same-named file in
different directories is matched to the correct embedded model before applying
the `??=` assignments.
- Around line 286-316: The function verifyAssetSupportedCandidates currently
waits until after importing the assets store and after each
updateModelsForNodeType call to check signal.aborted, causing wasted work for
aborted workflows; fix it by checking signal?.aborted immediately after
computing pendingNodeTypes and before importing the assets store (abort early),
and also check signal?.aborted inside the per-nodeType loop before calling
store.updateModelsForNodeType(nodeType) to skip refreshes for already-aborted
signals; keep using the provided assetsStore fallback logic and preserve the
existing try/catch around updateModelsForNodeType.

In `@src/platform/workflow/validation/schemas/workflowSchema.ts`:
- Around line 603-610: graphData.definitions?.subgraphs only collects top-level
subgraph definitions so nested subgraph definitions are omitted; replace direct
usage of graphData.definitions?.subgraphs when building pathMap and
subgraphDefMap with a recursive collector (e.g., collectSubgraphDefinitions)
that walks candidate.definitions?.subgraphs and deduplicates by id using
isSubgraphDefinition; then pass the returned flattened array into
buildSubgraphExecutionPaths(rootNodes, collectedSubgraphs) and use it to
construct subgraphDefMap (map by s.id) so nested subgraphs and their nodes are
included in missing-model detection.

In `@src/stores/executionErrorStore.ts`:
- Around line 98-106: The clearAllErrors() function currently calls
missingModelStore.clearMissingModels(), which wipes in-progress missing-model
resolution state; remove the call to missingModelStore.clearMissingModels() from
clearAllErrors() so it only resets UI/error state (lastExecutionError,
lastPromptError, lastNodeErrors, missingNodesError, isErrorOverlayOpen) and do
not touch missing model importTaskIds/URL/importing flags here; keep the full
missingModelStore.clearMissingModels() only in workflow-load/clean/explicit
reset code paths (where workflow changes are handled) rather than in
clearAllErrors().

---

Outside diff comments:
In `@src/renderer/extensions/vueNodes/components/LGraphNode.vue`:
- Around line 343-358: The missing-model check is using the full nodeLocatorId
(which includes subgraph path) but the missingModelStore keys by raw node IDs,
so subgraph leaf nodes miss the error state; change the call(s) that pass
nodeLocatorId.value to missingModelStore to use the raw node id (nodeData.id)
instead—specifically update
missingModelStore.hasMissingModelOnNode(nodeLocatorId.value) to
missingModelStore.hasMissingModelOnNode(nodeData.id) (and any other
missingModelStore lookups here that currently receive nodeLocatorId.value) so
lookups match the store's keying.

---

Nitpick comments:
In `@src/components/rightSidePanel/errors/useErrorGroups.test.ts`:
- Around line 50-55: Remove the unused vi.mock call for
'@/platform/missingModel/composables/useMissingModelInteractions' from the
useErrorGroups.test.ts file because useErrorGroups() does not import or exercise
that composable; specifically delete the vi.mock(...) block that returns
clearMissingModelState and confirm no other test helpers reference
clearMissingModelState, then run the tests to ensure nothing else depended on
that fake dependency.

In `@src/platform/missingModel/missingModelScan.test.ts`:
- Around line 939-948: Extend the test for verifyAssetSupportedCandidates so it
asserts the expensive work path (updateModelsForNodeType) is not invoked when
the signal is already aborted: arrange a spy or mock on updateModelsForNodeType
(or replace it with a function that would return a slow promise/throw if
called), create the aborted AbortController, call
verifyAssetSupportedCandidates(candidates, controller.signal), then assert the
spy was not called and candidates[0].isMissing is still undefined; this ensures
the implementation returns early and does not start the expensive
updateModelsForNodeType work.

In `@src/stores/executionErrorStore.test.ts`:
- Around line 21-26: Remove the dead mock for
'@/platform/missingModel/composables/useMissingModelInteractions' introduced via
vi.mock that provides clearMissingModelState; delete that vi.mock block and any
references to clearMissingModelState in the test file
(executionErrorStore.test.ts) so the test no longer stubs a non-existent export
or creates a fake dependency surface, and run the tests to confirm no remaining
imports or usages of useMissingModelInteractions remain.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 296f8896-b6eb-4e00-bfec-30bdfdfb492d

📥 Commits

Reviewing files that changed from the base of the PR and between 7b9f24f and 4ceba07.

📒 Files selected for processing (29)
  • src/components/rightSidePanel/RightSidePanel.vue
  • src/components/rightSidePanel/errors/TabErrors.vue
  • src/components/rightSidePanel/errors/types.ts
  • src/components/rightSidePanel/errors/useErrorGroups.test.ts
  • src/components/rightSidePanel/errors/useErrorGroups.ts
  • src/locales/en/main.json
  • src/platform/missingModel/components/MissingModelCard.test.ts
  • src/platform/missingModel/components/MissingModelCard.vue
  • src/platform/missingModel/components/MissingModelLibrarySelect.vue
  • src/platform/missingModel/components/MissingModelRow.vue
  • src/platform/missingModel/components/MissingModelStatusCard.vue
  • src/platform/missingModel/components/MissingModelUrlInput.vue
  • src/platform/missingModel/composables/useMissingModelInteractions.test.ts
  • src/platform/missingModel/composables/useMissingModelInteractions.ts
  • src/platform/missingModel/missingModelScan.test.ts
  • src/platform/missingModel/missingModelScan.ts
  • src/platform/missingModel/missingModelStore.test.ts
  • src/platform/missingModel/missingModelStore.ts
  • src/platform/missingModel/types.ts
  • src/platform/workflow/core/services/workflowService.ts
  • src/platform/workflow/validation/schemas/workflowSchema.test.ts
  • src/platform/workflow/validation/schemas/workflowSchema.ts
  • src/renderer/extensions/vueNodes/components/LGraphNode.vue
  • src/renderer/extensions/vueNodes/components/NodeWidgets.vue
  • src/scripts/app.ts
  • src/stores/assetsStore.ts
  • src/stores/executionErrorStore.test.ts
  • src/stores/executionErrorStore.ts
  • src/utils/graphTraversalUtil.ts

- Use grouped model count instead of raw candidates in error title
- Wrap feature flag in computed() for template reactivity
- Trigger widget callback and dirty canvas on model substitution
- Clear importCategoryMismatch on URL change and import retry
- Guard async metadata/import responses with per-key request tokens
- Key enrichment map by name+directory to prevent cross-directory collision
- Add early abort checks in asset verification loop
- Collect nested subgraph definitions recursively for model detection
- Preserve missing model state during clearAllErrors()
- Fix test mock reset and i18n stub coverage
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

♻️ Duplicate comments (1)
src/platform/missingModel/composables/useMissingModelInteractions.ts (1)

196-215: ⚠️ Potential issue | 🟠 Major

Invalidate in-flight requests as soon as the URL changes.

Editing the URL clears the row state, but _requestTokens[key] is only replaced when the next metadata fetch/import actually starts. If an older request finishes during the debounce window, it can still repopulate urlMetadata, urlErrors, or selectedLibraryModel for the previous URL. Invalidate the token in handleUrlInput() before clearing state so older responses are stale immediately.

💡 Suggested fix
 function handleUrlInput(key: string, value: string) {
+  _requestTokens[key] = Symbol()
   store.urlInputs[key] = value
 
   delete store.urlMetadata[key]
   delete store.urlErrors[key]
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/missingModel/composables/useMissingModelInteractions.ts` around
lines 196 - 215, In handleUrlInput, invalidate any in-flight fetch token so old
responses can't repopulate state: before clearing row state
(store.urlMetadata/urlErrors/selectedLibraryModel) set or replace the per-key
request token in the store's _requestTokens map (the same slot fetchUrlMetadata
normally sets) to a fresh/neutral value so previous tokens are considered stale;
this ensures any older response handlers (which check _requestTokens[key]) will
bail out immediately when the URL changes and only the new fetch started by
fetchUrlMetadata can update urlMetadata/urlErrors/selectedLibraryModel.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/components/rightSidePanel/errors/useErrorGroups.ts`:
- Around line 574-623: The missing-model rows aren't being filtered by the
errors search because the computed missingModelGroups (used by TabErrors.vue /
MissingModelCard) always returns the full list; update useErrorGroups to derive
a query-filtered collection (e.g., filteredMissingModelGroups) by applying the
same search logic used for filteredGroups to the groupCandidates/models produced
in missingModelGroups, then have buildMissingModelGroups use that filtered
collection instead of missingModelGroups.value; reference the existing computed
missingModelGroups, the grouping step that calls groupCandidatesByName, and
buildMissingModelGroups so you can reuse or mirror the same query
predicate/filter function to narrow rows based on the current search query.

In `@src/platform/missingModel/missingModelScan.ts`:
- Around line 315-336: When updateModelsForNodeType(nodeType) throws during the
Promise.allSettled stage you must record that nodeType as failed and avoid
classifying any candidates for it; modify the concurrent map over
[...pendingNodeTypes] to add failing nodeTypes into a Set (e.g.,
failedNodeTypes) inside the catch block instead of just logging, then in the
downstream loop over candidates (the for loop using candidates, getAssets, and
isAssetInstalled) skip setting c.isMissing for any candidate whose c.nodeType is
in failedNodeTypes (leave c.isMissing undefined) and preserve the existing
signal?.aborted checks.

---

Duplicate comments:
In `@src/platform/missingModel/composables/useMissingModelInteractions.ts`:
- Around line 196-215: In handleUrlInput, invalidate any in-flight fetch token
so old responses can't repopulate state: before clearing row state
(store.urlMetadata/urlErrors/selectedLibraryModel) set or replace the per-key
request token in the store's _requestTokens map (the same slot fetchUrlMetadata
normally sets) to a fresh/neutral value so previous tokens are considered stale;
this ensures any older response handlers (which check _requestTokens[key]) will
bail out immediately when the URL changes and only the new fetch started by
fetchUrlMetadata can update urlMetadata/urlErrors/selectedLibraryModel.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fc3df2db-f164-438e-ad13-38a3e5a12d5e

📥 Commits

Reviewing files that changed from the base of the PR and between 4ceba07 and c17b2c9.

📒 Files selected for processing (8)
  • src/components/rightSidePanel/errors/useErrorGroups.ts
  • src/platform/missingModel/components/MissingModelCard.test.ts
  • src/platform/missingModel/components/MissingModelUrlInput.vue
  • src/platform/missingModel/composables/useMissingModelInteractions.test.ts
  • src/platform/missingModel/composables/useMissingModelInteractions.ts
  • src/platform/missingModel/missingModelScan.ts
  • src/platform/workflow/validation/schemas/workflowSchema.ts
  • src/stores/executionErrorStore.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/platform/workflow/validation/schemas/workflowSchema.ts
  • src/platform/missingModel/components/MissingModelUrlInput.vue

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (2)
src/platform/missingModel/missingModelScan.ts (2)

310-313: ⚠️ Potential issue | 🟠 Major

Abort again before loading the assets store.

If signal flips after pendingNodeTypes is built, this still imports assetsStore for an abandoned workflow. Add a second signal?.aborted guard immediately before the dynamic import.

💡 Proposed fix
   if (pendingNodeTypes.size === 0) return
+  if (signal?.aborted) return
 
   const store =
     assetsStore ?? (await import('@/stores/assetsStore')).useAssetsStore()
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/missingModel/missingModelScan.ts` around lines 310 - 313, Add a
second abort check immediately before the dynamic import to avoid loading
assetsStore for an abandoned workflow: after the existing pendingNodeTypes.size
=== 0 return and before the line that sets store via assetsStore ?? (await
import(...)).useAssetsStore(), check if signal?.aborted and return early if
true. This uses the same signal reference used earlier in missingModelScan.ts
and prevents importing '@/stores/assetsStore' when the operation was cancelled.

362-385: ⚠️ Potential issue | 🟠 Major

Key the grouped view-model map by directory too.

useErrorGroups() already separates known asset directories, but unsupported and null-directory candidates still arrive here in a shared bucket. Grouping only by c.name collapses same-named models from different directories into one row and keeps an arbitrary representative, which can then feed the wrong nodeType/metadata into MissingModelRow.vue for every reference.

💡 Proposed fix
+function groupedCandidateKey(candidate: MissingModelCandidate): string {
+  return `${candidate.name}::${candidate.directory ?? ''}`
+}
+
 export function groupCandidatesByName(
   candidates: MissingModelCandidate[]
 ): MissingModelViewModel[] {
   const map = new Map<string, MissingModelViewModel>()
   for (const c of candidates) {
-    const existing = map.get(c.name)
+    const key = groupedCandidateKey(c)
+    const existing = map.get(key)
     if (existing) {
       if (c.nodeId) {
         existing.referencingNodes.push({
           nodeId: c.nodeId,
           widgetName: c.widgetName
         })
       }
     } else {
-      map.set(c.name, {
+      map.set(key, {
         name: c.name,
         representative: c,
         referencingNodes: c.nodeId
           ? [{ nodeId: c.nodeId, widgetName: c.widgetName }]
           : []
       })
     }
   }
   return Array.from(map.values())
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/missingModel/missingModelScan.ts` around lines 362 - 385,
groupCandidatesByName currently keys groups only by c.name which merges
candidates from different directories; change the grouping key to include the
candidate directory (e.g. combine c.directory or a sentinel for null/unsupported
with c.name) so each distinct directory+name pair gets its own
MissingModelViewModel. Ensure the map key construction and lookup use that
combined key, and when creating the group (in the else branch) pick the
representative and initial referencingNodes from that candidate as now so
metadata/nodeType remains correct per directory group.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/platform/missingModel/missingModelScan.ts`:
- Around line 203-236: The current Promise.allSettled drops models when
checkModelInstalled throws; change the mapping inside unmatched.map in
missingModelScan.ts so that instead of letting checkModelInstalled rejection
bubble, you catch errors locally and return a MissingModelCandidate that
preserves the model info and marks the install check as unresolved (e.g.,
isMissing: undefined) plus an installCheckError field (or similar optional
field) containing the caught error; keep using the existing symbols (unmatched,
checkModelInstalled, isAssetSupported, MissingModelCandidate, enriched) so the
loop can still push non-null values and the failed checks surface to the caller
instead of being skipped.

---

Duplicate comments:
In `@src/platform/missingModel/missingModelScan.ts`:
- Around line 310-313: Add a second abort check immediately before the dynamic
import to avoid loading assetsStore for an abandoned workflow: after the
existing pendingNodeTypes.size === 0 return and before the line that sets store
via assetsStore ?? (await import(...)).useAssetsStore(), check if
signal?.aborted and return early if true. This uses the same signal reference
used earlier in missingModelScan.ts and prevents importing
'@/stores/assetsStore' when the operation was cancelled.
- Around line 362-385: groupCandidatesByName currently keys groups only by
c.name which merges candidates from different directories; change the grouping
key to include the candidate directory (e.g. combine c.directory or a sentinel
for null/unsupported with c.name) so each distinct directory+name pair gets its
own MissingModelViewModel. Ensure the map key construction and lookup use that
combined key, and when creating the group (in the else branch) pick the
representative and initial referencingNodes from that candidate as now so
metadata/nodeType remains correct per directory group.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4adbf2e0-0f29-4d75-89f3-566724c99f39

📥 Commits

Reviewing files that changed from the base of the PR and between c17b2c9 and f42a27b.

📒 Files selected for processing (1)
  • src/platform/missingModel/missingModelScan.ts

Comment on lines +68 to +71
defineProps<{
missingModelGroups: MissingModelGroup[]
showNodeIdBadge: boolean
}>()
Copy link
Member

Choose a reason for hiding this comment

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

very nit

Suggested change
defineProps<{
missingModelGroups: MissingModelGroup[]
showNodeIdBadge: boolean
}>()
const { missingModelGroups, showNodeIdBadge } = defineProps<{
missingModelGroups: MissingModelGroup[]
showNodeIdBadge: boolean
}>()

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. Applied reactive props destructuring as suggested.

Comment on lines +36 to +38
group.type === 'missing_node' ||
group.type === 'swap_nodes' ||
group.type === 'missing_model'
Copy link
Member

Choose a reason for hiding this comment

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

very nit: can we replace it to computed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. Extracted to a getGroupSize() function using a Set for the full-size group types. Chose a plain function over computed since it takes a parameter (the group) and the Set lookup is O(1).

aria-hidden="true"
class="mt-0.5 icon-[lucide--info] size-3.5 shrink-0 text-muted-foreground"
/>
<span class="text-[11px] leading-tight text-muted-foreground">
Copy link
Member

Choose a reason for hiding this comment

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

I think we can use tailwind class instead

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. Replaced text-[11px] with text-xs.


<script setup lang="ts">
import { useI18n } from 'vue-i18n'
import SelectPlus from '@/components/primevueOverride/SelectPlus.vue'
Copy link
Member

Choose a reason for hiding this comment

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

We decided to stop using PrimeVue and move to Reka UI instead.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. Migrated from PrimeVue SelectPlus to the project's Reka UI Select wrapper. Also added a #prepend slot to SelectContent.vue to support placing a search filter input above the scroll buttons. The search now uses useFuse from @vueuse/integrations for fuzzy matching, which handles large option lists (e.g. 100+ LoRAs) better than simple substring matching.

Comment on lines +45 to +50
confirmLibrarySelect(
modelKey,
model.name,
model.referencingNodes,
directory
)
Copy link
Member

Choose a reason for hiding this comment

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

can you replace it with the handler like handleLibrarySelect?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. Extracted the inline confirmLibrarySelect(...) call into a handleLibrarySelect() function.

Comment on lines +9 to +22
v-bind="
!canImportModels
? {
role: 'button',
tabindex: 0,
onKeydown: (e: KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault()
showUploadDialog()
}
}
}
: {}
"
Copy link
Member

Choose a reason for hiding this comment

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

This v-bind is getting a bit complex with the conditional object and inline handler. It might be cleaner to move this into a computed prop and reference it from the template.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. Extracted to upgradePromptAttrs computed property.

</span>
<span
v-if="(urlMetadata[modelKey]?.content_length ?? 0) > 0"
class="shrink-0 rounded-sm bg-secondary-background-selected px-1.5 py-0.5 text-[10px] font-medium text-muted-foreground"
Copy link
Member

Choose a reason for hiding this comment

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

I think you can use text-sm or text-xs?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. Replaced text-[10px] with text-xs.

aria-hidden="true"
class="mt-0.5 icon-[lucide--triangle-alert] size-3 shrink-0 text-warning-background"
/>
<span class="text-[11px] leading-tight text-warning-background">
Copy link
Member

Choose a reason for hiding this comment

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

Same here!

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Done. Replaced text-[11px] with text-xs.

Comment on lines +91 to +98
<i
aria-hidden="true"
:class="
urlImporting[modelKey]
? 'icon-[lucide--loader-circle] size-4 animate-spin'
: 'icon-[lucide--download] size-4'
"
/>
Copy link
Member

Choose a reason for hiding this comment

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

Question: Doesn’t the button already have a loading state prop?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yes, it does. Replaced the manual spinner icon toggle with :loading="urlImporting[modelKey]" on the Button component.

  - Migrate MissingModelLibrarySelect from PrimeVue to Reka UI Select
  - Add #prepend slot to SelectContent for search filter placement
  - Use useFuse for fuzzy matching in library select dropdown
  - Extract inline handlers and complex v-binds to named functions/computeds
  - Replace arbitrary text sizes with Tailwind classes
  - Use Button loading prop instead of manual spinner
@jaeone94 jaeone94 requested a review from viva-jinyi March 12, 2026 06:01
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/platform/missingModel/components/MissingModelLibrarySelect.vue (1)

76-84: Use defineModel for the selected value API.

This component already has a modelValue-shaped contract, but writes go through a separate select emit. Switching the selected value to defineModel<string | undefined>() keeps the interface idiomatic and lets the extra select event remain purely optional for side effects.

♻️ Suggested refactor
-const { options, showDivider = false } = defineProps<{
-  modelValue: string | undefined
+const modelValue = defineModel<string | undefined>()
+const { options, showDivider = false } = defineProps<{
   options: { name: string; value: string }[]
   showDivider?: boolean
 }>()
@@
 function handleSelect(value: unknown) {
   if (typeof value === 'string') {
     filterQuery.value = ''
+    modelValue.value = value
     emit('select', value)
   }
 }

Based on learnings: Applies to src/**/*.vue : Prefer defineModel to separately defining a prop and emit for v-model bindings.

Also applies to: 101-105

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/missingModel/components/MissingModelLibrarySelect.vue` around
lines 76 - 84, The component defines a v-model style prop/emit pair (modelValue
via defineProps and select via defineEmits) instead of using the composition API
helper; replace the separate prop and emit with a single defineModel<string |
undefined>() call to expose the selected value idiomatically, keep the existing
optional select emit (if side-effects needed) but make v-model reads/writes use
the defineModel binding, and update any internal usages of modelValue and emits
to read/update via the defineModel return value (locate usages around
defineProps/defineEmits and in the component template/script where modelValue or
emit('select', ...) are referenced).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/platform/missingModel/components/MissingModelLibrarySelect.vue`:
- Around line 25-45: When the search input (template using v-if="options.length
> 4") is hidden the reactive filterQuery remains and can empty the dropdown; add
logic to reset filterQuery when options shrink to 4 or fewer. Implement a
watcher or computed effect on the options array (or options.length) in this
component (referencing filterQuery, options, and the computed filteredOptions)
that sets filterQuery = '' whenever options.length <= 4; apply the same
watcher/fix for the other search block referenced around lines 88-105 so both
input UIs clear their filter when hidden.

---

Nitpick comments:
In `@src/platform/missingModel/components/MissingModelLibrarySelect.vue`:
- Around line 76-84: The component defines a v-model style prop/emit pair
(modelValue via defineProps and select via defineEmits) instead of using the
composition API helper; replace the separate prop and emit with a single
defineModel<string | undefined>() call to expose the selected value
idiomatically, keep the existing optional select emit (if side-effects needed)
but make v-model reads/writes use the defineModel binding, and update any
internal usages of modelValue and emits to read/update via the defineModel
return value (locate usages around defineProps/defineEmits and in the component
template/script where modelValue or emit('select', ...) are referenced).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2b71dcd6-2cf8-4640-a1f5-82288c1fd175

📥 Commits

Reviewing files that changed from the base of the PR and between f42a27b and ed074e0.

📒 Files selected for processing (6)
  • src/components/rightSidePanel/errors/TabErrors.vue
  • src/components/ui/select/SelectContent.vue
  • src/platform/missingModel/components/MissingModelCard.vue
  • src/platform/missingModel/components/MissingModelLibrarySelect.vue
  • src/platform/missingModel/components/MissingModelRow.vue
  • src/platform/missingModel/components/MissingModelUrlInput.vue
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/platform/missingModel/components/MissingModelCard.vue
  • src/platform/missingModel/components/MissingModelUrlInput.vue
  • src/platform/missingModel/components/MissingModelRow.vue

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/platform/missingModel/components/MissingModelLibrarySelect.vue (1)

76-84: Align this public API with Vue v-model conventions.

modelValue reads like a standard v-model prop, but the component only emits select. Either expose this as defineModel() / update:modelValue, or rename the prop to something non-v-model-semantic so the API is not misleading.

As per coding guidelines, "Prefer defineModel to separately defining a prop and emit for v-model bindings."

Also applies to: 108-112

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/platform/missingModel/components/MissingModelLibrarySelect.vue` around
lines 76 - 84, The prop/emit pairing is misleading because the component defines
a v-model-looking prop modelValue via defineProps but only emits select; change
the public API to follow Vue v-model conventions: either replace the separate
defineProps/defineEmits for modelValue and select with defineModel(...) /
defineEmits('update:modelValue') (and emit 'update:modelValue' where select is
currently emitted), or rename the prop from modelValue to a non-v-model name
(e.g., selectedValue) and keep the select emit; update all references to
modelValue, select, defineProps, defineEmits, and any emit calls so they match
the chosen approach.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/platform/missingModel/components/MissingModelLibrarySelect.vue`:
- Around line 14-21: The SelectTrigger in MissingModelLibrarySelect.vue
currently sets a static :aria-label which overrides the accessible name; remove
the :aria-label="t('rightSidePanel.missingModels.useFromLibrary')" prop from the
SelectTrigger so the accessible name comes from the SelectValue
(placeholder/selected text) instead; locate the SelectTrigger component and
delete that aria-label binding, leaving SelectValue to provide the visible and
accessible name.

---

Nitpick comments:
In `@src/platform/missingModel/components/MissingModelLibrarySelect.vue`:
- Around line 76-84: The prop/emit pairing is misleading because the component
defines a v-model-looking prop modelValue via defineProps but only emits select;
change the public API to follow Vue v-model conventions: either replace the
separate defineProps/defineEmits for modelValue and select with defineModel(...)
/ defineEmits('update:modelValue') (and emit 'update:modelValue' where select is
currently emitted), or rename the prop from modelValue to a non-v-model name
(e.g., selectedValue) and keep the select emit; update all references to
modelValue, select, defineProps, defineEmits, and any emit calls so they match
the chosen approach.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 93934c94-ca2a-42c6-aa37-18ce09870631

📥 Commits

Reviewing files that changed from the base of the PR and between ed074e0 and 5226863.

📒 Files selected for processing (1)
  • src/platform/missingModel/components/MissingModelLibrarySelect.vue

Copy link
Member

@viva-jinyi viva-jinyi left a comment

Choose a reason for hiding this comment

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

LGTM

@jaeone94 jaeone94 merged commit 2f7f3c4 into main Mar 12, 2026
34 checks passed
@jaeone94 jaeone94 deleted the feat/cloud-missing-model-from-errortab branch March 12, 2026 07:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:models enhancement New feature or request size:XXL This PR changes 1000+ lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants