Skip to content

Conversation

@DrJKL
Copy link
Contributor

@DrJKL DrJKL commented Jan 16, 2026

Summary

Adds an editable Model Info Panel to show and modify asset details in the asset browser.

Changes

  • Add ModelInfoPanel component with editable display name, description, model type, base models, and tags
  • Add updateAssetMetadata action in assetsStore with optimistic cache updates
  • Add shadcn-vue Select components with design system styling
  • Add utility functions in assetMetadataUtils for extracting model metadata
  • Convert BaseModalLayout right panel state to defineModel pattern
  • Add slide-in animation and collapse button for right panel
  • Add class prop to PropertiesAccordionItem for custom styling
  • Fix keyboard handling: Escape in TagsInput/TextArea doesn't close parent modal

Testing

  • Unit tests for ModelInfoPanel component
  • Unit tests for assetMetadataUtils functions

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 16, 2026

📝 Walkthrough

Walkthrough

Adds a Reka-based Select component suite and stories; introduces ModelInfoPanel with tests and editable metadata and optimistic store updates; expands asset metadata utilities/types and store optimistic updates; integrates a right-side panel with focus/blur flows; various UI, layout, i18n, and test timing adjustments.

Changes

Cohort / File(s) Summary
Select component suite
src/components/ui/select/Select.vue, src/components/ui/select/SelectContent.vue, src/components/ui/select/SelectItem.vue, src/components/ui/select/SelectTrigger.vue, src/components/ui/select/SelectValue.vue, src/components/ui/select/SelectGroup.vue, src/components/ui/select/SelectLabel.vue, src/components/ui/select/SelectScrollUpButton.vue, src/components/ui/select/SelectScrollDownButton.vue, src/components/ui/select/SelectSeparator.vue, src/components/ui/select/Select.stories.ts
New wrapper components around reka-ui select primitives with prop/emit forwarding, styling, scroll controls, grouping, separators, and Storybook stories.
ModelInfo panel & tests
src/platform/assets/components/modelInfo/ModelInfoPanel.vue, src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts, src/platform/assets/components/modelInfo/ModelInfoField.vue
New ModelInfoPanel with editable display name/tags/description, debounced persistence, optimistic cache updates; comprehensive unit tests; small ModelInfoField subcomponent.
Asset Browser & focus flow
src/platform/assets/components/AssetBrowserModal.vue, src/platform/assets/components/AssetGrid.vue, src/platform/assets/components/AssetCard.vue
Right-panel integration in modal (v-model:right-panel-open), focusedAsset state, AssetGrid gains focusedAssetId prop and emits (assetFocus, assetBlur, assetShowInfo); AssetCard adds focused prop and focus/blur/showInfo emits and outside-click blur handling.
Asset metadata utils & tests
src/platform/assets/utils/assetMetadataUtils.ts, src/platform/assets/utils/assetMetadataUtils.test.ts
Added utilities: getAssetBaseModels, getAssetDisplayName, getAssetSourceUrl, getAssetTriggerPhrases, getAssetAdditionalTags, getSourceName, getAssetModelType, getAssetUserDescription; expanded tests to cover edge cases.
Schemas & service typing
src/platform/assets/schemas/assetSchema.ts, src/platform/assets/services/assetService.ts
Made created_at optional; added AssetUpdatePayload and AssetUserMetadata types; updateAsset now accepts AssetUpdatePayload.
Assets store (optimistic updates)
src/stores/assetsStore.ts, src/stores/assetsStore.test.ts
Added updateAssetInCache, updateAssetMetadata, updateAssetTags (optimistic cache updates) and exposed actions; defensive nullish handling for created_at in logic and tests.
Layout / Base modal
src/components/widget/layout/BaseModalLayout.vue
Reworked to responsive grid layout, added rightPanelTitle prop and Escape handling, conditional left/right panel rendering and header/main restructuring.
VirtualGrid & spacers
src/components/common/VirtualGrid.vue
Replaced static height spacers with computed spacer styles, added maxColumns prop and mergedGridStyle, and rowsToHeight spacer helper.
Event timing & tests
src/components/common/EditableText.vue, src/components/common/EditableText.test.ts, src/renderer/extensions/vueNodes/components/NodeHeader.test.ts, browser_tests/tests/templates.spec.ts
Switched Enter/Escape handlers from keyupkeydown in components and tests; simplified Playwright header locator and changed mobile nav assertion to notToBeInViewport.
Tags input UX
src/components/ui/tags-input/TagsInputInput.vue
Added Escape handler to blur input and exit editing mode.
Composables & minor API
src/platform/assets/composables/useModelTypes.ts, src/platform/assets/composables/useAssetBrowser.ts, src/renderer/extensions/linearMode/LinearPreview.vue
Exposed guarded fetchModelTypes() and isReady; switched to multi-base-model handling and navItems/selectedNavItem in useAssetBrowser; relaxed formatTime(time?: string).
Docs & i18n
src/components/ui/AGENTS.md, docs/testing/vitest-patterns.md, src/locales/en/main.json
Added AGENTS.md guidelines, Vitest i18n testing guidance, and new locale keys including modelInfo and UI strings.

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant Modal as AssetBrowserModal
    participant Grid as AssetGrid
    participant Card as AssetCard
    participant Panel as ModelInfoPanel
    participant Store as assetsStore

    User->>Modal: Open asset browser
    Modal->>Store: fetchModelTypes()
    Store-->>Modal: model types ready

    User->>Card: Click asset
    Card->>Grid: emit assetFocus(asset)
    Grid->>Modal: emit assetFocus(asset)
    Modal->>Modal: set focusedAsset, open right panel
    Modal->>Panel: provide focused asset

    User->>Panel: Edit display name/tags/description
    Panel->>Store: updateAssetMetadata (optimistic)
    Store-->>Panel: cache updated
    Panel->>Store: persist changes via API

    User->>Card: Click elsewhere
    Card->>Grid: emit assetBlur()
    Grid->>Modal: emit assetBlur()
    Modal->>Modal: clear focusedAsset, close right panel
Loading

Possibly related PRs

Suggested reviewers

  • AustinMroz
  • PabloWiedemann
  • KarryCharon
  • viva-jinyi
  • christian-byrne
  • Yorha4D
✨ Finishing touches
  • 📝 Generate docstrings

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

❤️ Share

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

@github-actions
Copy link

github-actions bot commented Jan 16, 2026

🎭 Playwright Tests: ⚠️ Passed with flaky tests

Results: 505 passed, 0 failed, 1 flaky, 8 skipped (Total: 514)

❌ Failed Tests

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

@github-actions
Copy link

github-actions bot commented Jan 16, 2026

🎨 Storybook Build Status

Build completed successfully!

⏰ Completed at: 01/20/2026, 06:13:13 AM UTC

🔗 Links


🎉 Your Storybook is ready for review!

@DrJKL DrJKL changed the title refactor: Model Info Panel styling and layout improvements feat(assets): add ModelInfoPanel for asset browser right panel Jan 16, 2026
@github-actions
Copy link

github-actions bot commented Jan 16, 2026

Bundle Size Report

Summary

  • Raw size: 21.5 MB baseline 21.3 MB — 🔴 +130 kB
  • Gzip: 4.45 MB baseline 4.43 MB — 🔴 +22.9 kB
  • Brotli: 3.3 MB baseline 3.28 MB — 🔴 +17.6 kB
  • Bundles: 155 current • 155 baseline • 98 added / 98 removed

Category Glance
Vendor & Third-Party 🔴 +84.6 kB (10.5 MB) · Data & Services 🔴 +52.4 kB (3.09 MB) · Graph Workspace 🟢 -7.48 kB (1.01 MB) · Other ⚪ 0 B (6.25 MB) · Panels & Settings ⚪ 0 B (430 kB) · Views & Navigation ⚪ 0 B (80.7 kB) · + 5 more

Per-category breakdown
App Entry Points — 22.4 kB (baseline 22.4 kB) • ⚪ 0 B

Main entry bundles and manifests

File Before After Δ Raw Δ Gzip Δ Brotli
assets/index-ClIoWONr.js (removed) 22.4 kB 🟢 -22.4 kB 🟢 -6.74 kB 🟢 -5.93 kB
assets/index-CohUEuD-.js (new) 22.4 kB 🔴 +22.4 kB 🔴 +6.74 kB 🔴 +5.92 kB

Status: 1 added / 1 removed

Graph Workspace — 1.01 MB (baseline 1.02 MB) • 🟢 -7.48 kB

Graph editor runtime, canvas, workflow orchestration

File Before After Δ Raw Δ Gzip Δ Brotli
assets/GraphView-DX19GHRq.js (removed) 1.02 MB 🟢 -1.02 MB 🟢 -201 kB 🟢 -153 kB
assets/GraphView-Ds-6Q8Zz.js (new) 1.01 MB 🔴 +1.01 MB 🔴 +200 kB 🔴 +152 kB

Status: 1 added / 1 removed

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

Top-level views, pages, and routed surfaces

File Before After Δ Raw Δ Gzip Δ Brotli
assets/CloudSurveyView-Datel9jP.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -3.61 kB 🟢 -3.06 kB
assets/CloudSurveyView-DO8kGa0b.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +3.61 kB 🔴 +3.05 kB
assets/CloudLoginView-BlYEUrNJ.js (removed) 11.8 kB 🟢 -11.8 kB 🟢 -3.1 kB 🟢 -2.72 kB
assets/CloudLoginView-u-fm8HpM.js (new) 11.8 kB 🔴 +11.8 kB 🔴 +3.09 kB 🔴 +2.72 kB
assets/UserCheckView-BatHVH8G.js (new) 10.5 kB 🔴 +10.5 kB 🔴 +2.45 kB 🔴 +2.14 kB
assets/UserCheckView-BgTK5yKN.js (removed) 10.5 kB 🟢 -10.5 kB 🟢 -2.46 kB 🟢 -2.13 kB
assets/CloudLayoutView-BjwFKPHZ.js (removed) 8.54 kB 🟢 -8.54 kB 🟢 -2.25 kB 🟢 -1.97 kB
assets/CloudLayoutView-CA7qM58o.js (new) 8.54 kB 🔴 +8.54 kB 🔴 +2.25 kB 🔴 +1.97 kB
assets/CloudSignupView-BZ6R3nVj.js (new) 8.18 kB 🔴 +8.18 kB 🔴 +2.33 kB 🔴 +2.03 kB
assets/CloudSignupView-DGMC1cUY.js (removed) 8.18 kB 🟢 -8.18 kB 🟢 -2.33 kB 🟢 -2.03 kB
assets/CloudForgotPasswordView-CEOeCMtF.js (new) 6.26 kB 🔴 +6.26 kB 🔴 +1.93 kB 🔴 +1.69 kB
assets/CloudForgotPasswordView-DvyMktDH.js (removed) 6.26 kB 🟢 -6.26 kB 🟢 -1.93 kB 🟢 -1.68 kB
assets/UserSelectView-Ba2jNYDU.js (removed) 5.28 kB 🟢 -5.28 kB 🟢 -1.76 kB 🟢 -1.57 kB
assets/UserSelectView-Do0IcwzW.js (new) 5.28 kB 🔴 +5.28 kB 🔴 +1.76 kB 🔴 +1.57 kB
assets/CloudSubscriptionRedirectView-C65vD9Q2.js (new) 5.27 kB 🔴 +5.27 kB 🔴 +1.73 kB 🔴 +1.54 kB
assets/CloudSubscriptionRedirectView-Ch_p3kwV.js (removed) 5.27 kB 🟢 -5.27 kB 🟢 -1.73 kB 🟢 -1.54 kB
assets/CloudAuthTimeoutView-BEvr5qJb.js (new) 5.24 kB 🔴 +5.24 kB 🔴 +1.71 kB 🔴 +1.48 kB
assets/CloudAuthTimeoutView-DpioZYiG.js (removed) 5.24 kB 🟢 -5.24 kB 🟢 -1.72 kB 🟢 -1.48 kB
assets/CloudSorryContactSupportView-DtBNZtST.js (new) 1.97 kB 🔴 +1.97 kB 🔴 +703 B 🔴 +628 B
assets/CloudSorryContactSupportView-QtHXqQri.js (removed) 1.97 kB 🟢 -1.97 kB 🟢 -703 B 🟢 -627 B
assets/layout-Bf1taiS0.js (removed) 500 B 🟢 -500 B 🟢 -307 B 🟢 -267 B
assets/layout-Dcc8zed8.js (new) 500 B 🔴 +500 B 🔴 +307 B 🔴 +266 B

Status: 11 added / 11 removed

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

Configuration panels, inspectors, and settings screens

File Before After Δ Raw Δ Gzip Δ Brotli
assets/LegacyCreditsPanel-B27G1elU.js (new) 23.8 kB 🔴 +23.8 kB 🔴 +5.95 kB 🔴 +5.23 kB
assets/LegacyCreditsPanel-fSCmxtXj.js (removed) 23.8 kB 🟢 -23.8 kB 🟢 -5.95 kB 🟢 -5.23 kB
assets/SubscriptionPanel-CGvA5lq7.js (removed) 20.6 kB 🟢 -20.6 kB 🟢 -5 kB 🟢 -4.38 kB
assets/SubscriptionPanel-DhjRurxl.js (new) 20.6 kB 🔴 +20.6 kB 🔴 +4.99 kB 🔴 +4.38 kB
assets/KeybindingPanel-BG_TWlhO.js (removed) 14.2 kB 🟢 -14.2 kB 🟢 -3.74 kB 🟢 -3.31 kB
assets/KeybindingPanel-BhzO74uk.js (new) 14.2 kB 🔴 +14.2 kB 🔴 +3.74 kB 🔴 +3.31 kB
assets/AboutPanel-D7eNC-k2.js (new) 10.8 kB 🔴 +10.8 kB 🔴 +2.69 kB 🔴 +2.43 kB
assets/AboutPanel-DtINB2-L.js (removed) 10.8 kB 🟢 -10.8 kB 🟢 -2.69 kB 🟢 -2.43 kB
assets/ExtensionPanel-BbgyiBdT.js (new) 10.2 kB 🔴 +10.2 kB 🔴 +2.71 kB 🔴 +2.4 kB
assets/ExtensionPanel-DG8t_wal.js (removed) 10.2 kB 🟢 -10.2 kB 🟢 -2.71 kB 🟢 -2.4 kB
assets/ServerConfigPanel-BFzQ_zMv.js (new) 7.23 kB 🔴 +7.23 kB 🔴 +2.17 kB 🔴 +1.93 kB
assets/ServerConfigPanel-Dl-BYJtT.js (removed) 7.23 kB 🟢 -7.23 kB 🟢 -2.17 kB 🟢 -1.94 kB
assets/UserPanel-C_RtFgg_.js (new) 6.58 kB 🔴 +6.58 kB 🔴 +1.9 kB 🔴 +1.67 kB
assets/UserPanel-m36VW4ej.js (removed) 6.58 kB 🟢 -6.58 kB 🟢 -1.91 kB 🟢 -1.67 kB
assets/cloudRemoteConfig-Dbh02Jcm.js (removed) 1.82 kB 🟢 -1.82 kB 🟢 -769 B 🟢 -656 B
assets/cloudRemoteConfig-HfuKMe4o.js (new) 1.82 kB 🔴 +1.82 kB 🔴 +768 B 🔴 +668 B
assets/remoteConfig-8CsfdKUp.js (new) 1.07 kB 🔴 +1.07 kB 🔴 +522 B 🔴 +463 B
assets/remoteConfig-B0rgMcLx.js (removed) 1.07 kB 🟢 -1.07 kB 🟢 -519 B 🟢 -460 B
assets/remoteConfig-B9AKXmjZ.js (new) 188 B 🔴 +188 B 🔴 +132 B 🔴 +109 B
assets/remoteConfig-CW7J8vSK.js (removed) 188 B 🟢 -188 B 🟢 -132 B 🟢 -113 B
assets/settings-6DVADt2n.js 34.3 kB 34.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-B0j03ezr.js 38.3 kB 38.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BHe-AJJN.js 29.6 kB 29.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-BT2lfy0S.js 29.5 kB 29.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-Cp0lF2Mp.js 31.2 kB 31.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-CwdesOpm.js 32.1 kB 32.1 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D3SeHgho.js 28.6 kB 28.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-D42m_JEJ.js 25.9 kB 25.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-FF_vLB0C.js 25.2 kB 25.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-reUMVWRn.js 30.4 kB 30.4 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/settings-s7kHNBdQ.js 28.9 kB 28.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 10 added / 10 removed

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

Authentication, profile, and account management bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/auth-CBwHAJ5U.js (removed) 3.54 kB 🟢 -3.54 kB 🟢 -1.24 kB 🟢 -1.08 kB
assets/auth-CZjNR_V0.js (new) 3.54 kB 🔴 +3.54 kB 🔴 +1.24 kB 🔴 +1.06 kB
assets/firebaseAuthStore-CXgkf29M.js (new) 217 B 🔴 +217 B 🔴 +137 B 🔴 +127 B
assets/firebaseAuthStore-D-EebVL7.js (removed) 217 B 🟢 -217 B 🟢 -138 B 🟢 -122 B
assets/auth-c9XBaCpS.js (new) 178 B 🔴 +178 B 🔴 +142 B 🔴 +136 B
assets/auth-Ka6Iu1bV.js (removed) 178 B 🟢 -178 B 🟢 -142 B 🟢 -143 B

Status: 3 added / 3 removed

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

Modals, dialogs, drawers, and in-app editors

File Before After Δ Raw Δ Gzip Δ Brotli
assets/useSubscriptionDialog-Bd-GlWCR.js (new) 2.62 kB 🔴 +2.62 kB 🔴 +1.24 kB 🔴 +1.1 kB
assets/useSubscriptionDialog-D3v76K0U.js (removed) 2.62 kB 🟢 -2.62 kB 🟢 -1.24 kB 🟢 -1.09 kB
assets/useSubscriptionDialog-BbnP4onJ.js (new) 179 B 🔴 +179 B 🔴 +110 B 🔴 +102 B
assets/useSubscriptionDialog-RvWnZ75q.js (removed) 179 B 🟢 -179 B 🟢 -110 B 🟢 -95 B

Status: 2 added / 2 removed

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

Reusable component library chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/SubscribeButton-B3bpukh-.js (removed) 12.5 kB 🟢 -12.5 kB 🟢 -3 kB 🟢 -2.7 kB
assets/SubscribeButton-CWtdcIsy.js (new) 12.5 kB 🔴 +12.5 kB 🔴 +3.01 kB 🔴 +2.71 kB
assets/ComfyQueueButton-CSJ-Kz-7.js (removed) 9.52 kB 🟢 -9.52 kB 🟢 -2.69 kB 🟢 -2.41 kB
assets/ComfyQueueButton-DirzohDM.js (new) 9.52 kB 🔴 +9.52 kB 🔴 +2.69 kB 🔴 +2.41 kB
assets/Button-BFptkwN0.js (removed) 3.75 kB 🟢 -3.75 kB 🟢 -1.37 kB 🟢 -1.21 kB
assets/Button-ClceBKKb.js (new) 3.75 kB 🔴 +3.75 kB 🔴 +1.37 kB 🔴 +1.21 kB
assets/WidgetButton-_hGIrcI2.js (removed) 2.41 kB 🟢 -2.41 kB 🟢 -981 B 🟢 -884 B
assets/WidgetButton-LihOxqCX.js (new) 2.41 kB 🔴 +2.41 kB 🔴 +983 B 🔴 +884 B
assets/CloudBadge-CEzeqobt.js (removed) 1.85 kB 🟢 -1.85 kB 🟢 -729 B 🟢 -646 B
assets/CloudBadge-DvGU9-47.js (new) 1.85 kB 🔴 +1.85 kB 🔴 +731 B 🔴 +646 B
assets/UserAvatar-CkcXZWJQ.js (removed) 1.73 kB 🟢 -1.73 kB 🟢 -728 B 🟢 -639 B
assets/UserAvatar-D8aaiSLe.js (new) 1.73 kB 🔴 +1.73 kB 🔴 +728 B 🔴 +637 B
assets/cloudFeedbackTopbarButton-Da_xjeiO.js (new) 866 B 🔴 +866 B 🔴 +523 B 🔴 +438 B
assets/cloudFeedbackTopbarButton-Y8Rk-crm.js (removed) 866 B 🟢 -866 B 🟢 -524 B 🟢 -438 B
assets/ComfyQueueButton-C1cHc9p2.js (removed) 181 B 🟢 -181 B 🟢 -118 B 🟢 -120 B
assets/ComfyQueueButton-DIEjgUud.js (new) 181 B 🔴 +181 B 🔴 +118 B 🔴 +107 B

Status: 8 added / 8 removed

Data & Services — 3.09 MB (baseline 3.04 MB) • 🔴 +52.4 kB

Stores, services, APIs, and repositories

File Before After Δ Raw Δ Gzip Δ Brotli
assets/dialogService-DxQKnuOM.js (new) 1.92 MB 🔴 +1.92 MB 🔴 +406 kB 🔴 +310 kB
assets/dialogService-CEzbYeif.js (removed) 1.87 MB 🟢 -1.87 MB 🟢 -397 kB 🟢 -304 kB
assets/api-0KjY0MDO.js (new) 1.15 MB 🔴 +1.15 MB 🔴 +240 kB 🔴 +186 kB
assets/api--8uhkDQN.js (removed) 1.15 MB 🟢 -1.15 MB 🟢 -239 kB 🟢 -185 kB
assets/releaseStore-CfkrRjTp.js (removed) 8.91 kB 🟢 -8.91 kB 🟢 -2.41 kB 🟢 -2.13 kB
assets/releaseStore-WAWqXllH.js (new) 8.91 kB 🔴 +8.91 kB 🔴 +2.41 kB 🔴 +2.12 kB
assets/keybindingService-CCX0499C.js (new) 6.78 kB 🔴 +6.78 kB 🔴 +1.74 kB 🔴 +1.52 kB
assets/keybindingService-CfcSeuv9.js (removed) 6.78 kB 🟢 -6.78 kB 🟢 -1.74 kB 🟢 -1.51 kB
assets/serverConfigStore-CDOQj4Ec.js (removed) 2.64 kB 🟢 -2.64 kB 🟢 -878 B 🟢 -777 B
assets/serverConfigStore-DthZnbD8.js (new) 2.64 kB 🔴 +2.64 kB 🔴 +879 B 🔴 +779 B
assets/userStore-BCEuz1Sx.js (removed) 2.16 kB 🟢 -2.16 kB 🟢 -814 B 🟢 -724 B
assets/userStore-CWby6aNR.js (new) 2.16 kB 🔴 +2.16 kB 🔴 +813 B 🔴 +729 B
assets/audioService-BoMXY3Cw.js (new) 2.03 kB 🔴 +2.03 kB 🔴 +931 B 🔴 +824 B
assets/audioService-CcbWb1Nq.js (removed) 2.03 kB 🟢 -2.03 kB 🟢 -932 B 🟢 -821 B
assets/releaseStore-0VIpEt2w.js (removed) 140 B 🟢 -140 B 🟢 -106 B 🟢 -106 B
assets/releaseStore-BxgXn68t.js (new) 140 B 🔴 +140 B 🔴 +106 B 🔴 +107 B

Status: 8 added / 8 removed

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

Helpers, composables, and utility bundles

File Before After Δ Raw Δ Gzip Δ Brotli
assets/colorUtil-De0C_hc6.js (removed) 7.2 kB 🟢 -7.2 kB 🟢 -2.22 kB 🟢 -1.95 kB
assets/colorUtil-udGz2hb8.js (new) 7.2 kB 🔴 +7.2 kB 🔴 +2.22 kB 🔴 +1.95 kB
assets/useErrorHandling-Bec-gWsQ.js (new) 5 kB 🔴 +5 kB 🔴 +1.47 kB 🔴 +1.28 kB
assets/useErrorHandling-CiN0jmUW.js (removed) 5 kB 🟢 -5 kB 🟢 -1.47 kB 🟢 -1.28 kB
assets/subscriptionCheckoutUtil-CJEE5QYg.js (removed) 1.98 kB 🟢 -1.98 kB 🟢 -862 B 🟢 -749 B
assets/subscriptionCheckoutUtil-DJVrVpqa.js (new) 1.98 kB 🔴 +1.98 kB 🔴 +859 B 🔴 +750 B
assets/markdownRendererUtil-0PqWmn-8.js (removed) 1.78 kB 🟢 -1.78 kB 🟢 -886 B 🟢 -772 B
assets/markdownRendererUtil-CGQ8rj6B.js (new) 1.78 kB 🔴 +1.78 kB 🔴 +886 B 🔴 +773 B
assets/audioUtils-Dt0Mb567.js (new) 1.24 kB 🔴 +1.24 kB 🔴 +620 B 🔴 +523 B
assets/audioUtils-T5kpRwN5.js (removed) 1.24 kB 🟢 -1.24 kB 🟢 -620 B 🟢 -524 B
assets/tailwindUtil-BleIg4ZI.js (new) 487 B 🔴 +487 B 🔴 +299 B 🔴 +267 B
assets/tailwindUtil-Chuu3TbR.js (removed) 487 B 🟢 -487 B 🟢 -298 B 🟢 -267 B
assets/useCurrentUser-BtscdR1n.js (removed) 145 B 🟢 -145 B 🟢 -114 B 🟢 -102 B
assets/useCurrentUser-BZGwuzGR.js (new) 145 B 🔴 +145 B 🔴 +114 B 🔴 +103 B
assets/_plugin-vue_export-helper-xVPqUhAl.js 467 B 467 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeFilterUtil-BUCOyXf2.js 421 B 421 B ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 7 added / 7 removed

Vendor & Third-Party — 10.5 MB (baseline 10.4 MB) • 🔴 +84.6 kB

External libraries and shared vendor chunks

File Before After Δ Raw Δ Gzip Δ Brotli
assets/vendor-other-gxcEwL1Z.js (new) 3.92 MB 🔴 +3.92 MB 🔴 +832 kB 🔴 +645 kB
assets/vendor-other-DqqTGPL6.js (removed) 3.92 MB 🟢 -3.92 MB 🟢 -832 kB 🟢 -645 kB
assets/vendor-primevue-BXeW4O65.js (new) 3.04 MB 🔴 +3.04 MB 🔴 +560 kB 🔴 +329 kB
assets/vendor-primevue-EBXVECvF.js (removed) 3.04 MB 🟢 -3.04 MB 🟢 -560 kB 🟢 -329 kB
assets/vendor-reka-ui-CwqRf7Ao.js (new) 256 kB 🔴 +256 kB 🔴 +50.6 kB 🔴 +42.1 kB
assets/vendor-reka-ui-ViWrLgbb.js (removed) 172 kB 🟢 -172 kB 🟢 -35.9 kB 🟢 -30.7 kB
assets/vendor-vue-V1bLMoiq.js (new) 13.6 kB 🔴 +13.6 kB 🔴 +4.38 kB 🔴 +3.92 kB
assets/vendor-vue-VHAq3Lid.js (removed) 13.6 kB 🟢 -13.6 kB 🟢 -4.38 kB 🟢 -3.92 kB
assets/vendor-chart-Dr8GmMlH.js 408 kB 408 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-three-Dqb1VEds.js 1.83 MB 1.83 MB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-tiptap-BxNhpyUI.js 650 kB 650 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/vendor-xterm-CArXWFIl.js 398 kB 398 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 4 added / 4 removed

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

Bundles that do not match a named category

File Before After Δ Raw Δ Gzip Δ Brotli
assets/core-CaDoB35F.js (removed) 177 kB 🟢 -177 kB 🟢 -42.8 kB 🟢 -35.7 kB
assets/core-DNM4_Zt9.js (new) 177 kB 🔴 +177 kB 🔴 +42.8 kB 🔴 +35.7 kB
assets/Load3D-BewWt72v.js (removed) 55.7 kB 🟢 -55.7 kB 🟢 -9.18 kB 🟢 -7.91 kB
assets/Load3D-Bns3tfbp.js (new) 55.7 kB 🔴 +55.7 kB 🔴 +9.18 kB 🔴 +7.9 kB
assets/WidgetSelect-49_NMcM3.js (new) 50.5 kB 🔴 +50.5 kB 🔴 +11.1 kB 🔴 +9.68 kB
assets/WidgetSelect-C7IQksyJ.js (removed) 50.5 kB 🟢 -50.5 kB 🟢 -11.1 kB 🟢 -9.68 kB
assets/SubscriptionRequiredDialogContent-C4pA6WLW.js (removed) 28.7 kB 🟢 -28.7 kB 🟢 -6.78 kB 🟢 -5.91 kB
assets/SubscriptionRequiredDialogContent-DbDxCGSY.js (new) 28.7 kB 🔴 +28.7 kB 🔴 +6.78 kB 🔴 +5.9 kB
assets/WidgetRecordAudio-DB9Kgzav.js (new) 18.2 kB 🔴 +18.2 kB 🔴 +4.97 kB 🔴 +4.42 kB
assets/WidgetRecordAudio-HG3vnHSQ.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.97 kB 🟢 -4.43 kB
assets/WidgetInputNumber-D40Dlma1.js (new) 18.2 kB 🔴 +18.2 kB 🔴 +4.49 kB 🔴 +4 kB
assets/WidgetInputNumber-DCS6z9Vp.js (removed) 18.2 kB 🟢 -18.2 kB 🟢 -4.49 kB 🟢 -4.01 kB
assets/WidgetImageCrop-BbFJdhwm.js (removed) 17.1 kB 🟢 -17.1 kB 🟢 -4.14 kB 🟢 -3.62 kB
assets/WidgetImageCrop-OFihNd55.js (new) 17.1 kB 🔴 +17.1 kB 🔴 +4.14 kB 🔴 +3.63 kB
assets/PanelTemplate-D4tW1Gr6.js (new) 16.2 kB 🔴 +16.2 kB 🔴 +5.45 kB 🔴 +4.79 kB
assets/PanelTemplate-l9SMS8Gm.js (removed) 16.2 kB 🟢 -16.2 kB 🟢 -5.45 kB 🟢 -4.8 kB
assets/LazyImage-B2qJgYQV.js (removed) 14.1 kB 🟢 -14.1 kB 🟢 -4.01 kB 🟢 -3.54 kB
assets/LazyImage-COpjm1te.js (new) 14.1 kB 🔴 +14.1 kB 🔴 +4 kB 🔴 +3.54 kB
assets/AudioPreviewPlayer-4AgM2qQn.js (removed) 12.7 kB 🟢 -12.7 kB 🟢 -3.48 kB 🟢 -3.12 kB
assets/AudioPreviewPlayer-DMoPvpf_.js (new) 12.7 kB 🔴 +12.7 kB 🔴 +3.48 kB 🔴 +3.13 kB
assets/WidgetWithControl-DH5d70ws.js (new) 8.02 kB 🔴 +8.02 kB 🔴 +2.65 kB 🔴 +2.39 kB
assets/WidgetWithControl-XUVzqlyC.js (removed) 8.02 kB 🟢 -8.02 kB 🟢 -2.65 kB 🟢 -2.38 kB
assets/ValueControlPopover-CBhNCRoX.js (new) 4.86 kB 🔴 +4.86 kB 🔴 +1.55 kB 🔴 +1.38 kB
assets/ValueControlPopover-rO-dcvUv.js (removed) 4.86 kB 🟢 -4.86 kB 🟢 -1.55 kB 🟢 -1.37 kB
assets/WidgetBoundingBox-BwJtRMkZ.js (new) 4.71 kB 🔴 +4.71 kB 🔴 +1.14 kB 🔴 +990 B
assets/WidgetBoundingBox-CUDq_bgN.js (removed) 4.71 kB 🟢 -4.71 kB 🟢 -1.14 kB 🟢 -1.02 kB
assets/WidgetGalleria-Bjqrk0m2.js (removed) 4.57 kB 🟢 -4.57 kB 🟢 -1.57 kB 🟢 -1.42 kB
assets/WidgetGalleria-C3FScdU4.js (new) 4.57 kB 🔴 +4.57 kB 🔴 +1.57 kB 🔴 +1.42 kB
assets/Slider-BIIoltvA.js (removed) 4.21 kB 🟢 -4.21 kB 🟢 -1.52 kB 🟢 -1.33 kB
assets/Slider-Dv3V2iW3.js (new) 4.21 kB 🔴 +4.21 kB 🔴 +1.52 kB 🔴 +1.33 kB
assets/WidgetImageCompare-CrN6SGuP.js (removed) 3.79 kB 🟢 -3.79 kB 🟢 -1.28 kB 🟢 -1.12 kB
assets/WidgetImageCompare-DfhEKD3g.js (new) 3.79 kB 🔴 +3.79 kB 🔴 +1.28 kB 🔴 +1.12 kB
assets/WidgetColorPicker-B12VkNVk.js (new) 3.71 kB 🔴 +3.71 kB 🔴 +1.38 kB 🔴 +1.25 kB
assets/WidgetColorPicker-CE6qc5iJ.js (removed) 3.71 kB 🟢 -3.71 kB 🟢 -1.38 kB 🟢 -1.25 kB
assets/WidgetTextarea-CDG12iu3.js (removed) 3.52 kB 🟢 -3.52 kB 🟢 -1.33 kB 🟢 -1.17 kB
assets/WidgetTextarea-ClnHGhcI.js (new) 3.52 kB 🔴 +3.52 kB 🔴 +1.33 kB 🔴 +1.17 kB
assets/WidgetMarkdown-D4Dx6Rvq.js (removed) 3.22 kB 🟢 -3.22 kB 🟢 -1.29 kB 🟢 -1.14 kB
assets/WidgetMarkdown-DOyAIEag.js (new) 3.22 kB 🔴 +3.22 kB 🔴 +1.29 kB 🔴 +1.14 kB
assets/WidgetAudioUI-1qLq9hs6.js (removed) 3.22 kB 🟢 -3.22 kB 🟢 -1.19 kB 🟢 -1.09 kB
assets/WidgetAudioUI-CISyhS1z.js (new) 3.22 kB 🔴 +3.22 kB 🔴 +1.19 kB 🔴 +1.09 kB
assets/WidgetToggleSwitch-CqMv8sri.js (new) 3.08 kB 🔴 +3.08 kB 🔴 +1.19 kB 🔴 +1.06 kB
assets/WidgetToggleSwitch-VNa5cXfN.js (removed) 3.08 kB 🟢 -3.08 kB 🟢 -1.19 kB 🟢 -1.07 kB
assets/GlobalToast-DdDeqMHM.js (new) 3.05 kB 🔴 +3.05 kB 🔴 +1.1 kB 🔴 +938 B
assets/GlobalToast-DFuNh7cd.js (removed) 3.05 kB 🟢 -3.05 kB 🟢 -1.1 kB 🟢 -940 B
assets/SubscribeToRun-CBC6dpBH.js (removed) 2.96 kB 🟢 -2.96 kB 🟢 -1.15 kB 🟢 -1.02 kB
assets/SubscribeToRun-D0EPFMhM.js (new) 2.96 kB 🔴 +2.96 kB 🔴 +1.16 kB 🔴 +1.02 kB
assets/cloudSessionCookie-B20qF5MG.js (removed) 2.9 kB 🟢 -2.9 kB 🟢 -920 B 🟢 -794 B
assets/cloudSessionCookie-DsMiUXzJ.js (new) 2.9 kB 🔴 +2.9 kB 🔴 +918 B 🔴 +794 B
assets/MediaVideoTop-BCNtw1s2.js (removed) 2.84 kB 🟢 -2.84 kB 🟢 -1.06 kB 🟢 -922 B
assets/MediaVideoTop-C5sPtFGN.js (new) 2.84 kB 🔴 +2.84 kB 🔴 +1.06 kB 🔴 +921 B
assets/WidgetChart-1bZGfe6O.js (removed) 2.79 kB 🟢 -2.79 kB 🟢 -1.06 kB 🟢 -958 B
assets/WidgetChart-Cp1E6paZ.js (new) 2.79 kB 🔴 +2.79 kB 🔴 +1.06 kB 🔴 +956 B
assets/WidgetLayoutField-Ki3331vi.js (new) 2.61 kB 🔴 +2.61 kB 🔴 +1.01 kB 🔴 +892 B
assets/WidgetLayoutField-zNq5xTi-.js (removed) 2.61 kB 🟢 -2.61 kB 🟢 -1.01 kB 🟢 -890 B
assets/WidgetInputText-CtnWVTX2.js (removed) 2.58 kB 🟢 -2.58 kB 🟢 -1.01 kB 🟢 -911 B
assets/WidgetInputText-DVuP91Ru.js (new) 2.58 kB 🔴 +2.58 kB 🔴 +1.01 kB 🔴 +912 B
assets/BaseViewTemplate-DeHjfn7g.js (new) 2.42 kB 🔴 +2.42 kB 🔴 +1.05 kB 🔴 +941 B
assets/BaseViewTemplate-DvV0Ic8F.js (removed) 2.42 kB 🟢 -2.42 kB 🟢 -1.04 kB 🟢 -946 B
assets/Media3DTop-Bj6UL3Mt.js (removed) 2.38 kB 🟢 -2.38 kB 🟢 -1.02 kB 🟢 -881 B
assets/Media3DTop-wlYHMja5.js (new) 2.38 kB 🔴 +2.38 kB 🔴 +1.02 kB 🔴 +907 B
assets/MediaImageTop-D0aiBzXG.js (removed) 2.34 kB 🟢 -2.34 kB 🟢 -1.01 kB 🟢 -886 B
assets/MediaImageTop-DBWwPm10.js (new) 2.34 kB 🔴 +2.34 kB 🔴 +1.01 kB 🔴 +878 B
assets/MediaAudioTop-B6zGJaOK.js (new) 2 kB 🔴 +2 kB 🔴 +887 B 🔴 +765 B
assets/MediaAudioTop-D8pQnmES.js (removed) 2 kB 🟢 -2 kB 🟢 -883 B 🟢 -763 B
assets/CloudRunButtonWrapper-BMr61qQT.js (removed) 1.79 kB 🟢 -1.79 kB 🟢 -643 B 🟢 -595 B
assets/CloudRunButtonWrapper-D2C0qWy-.js (new) 1.79 kB 🔴 +1.79 kB 🔴 +639 B 🔴 +591 B
assets/cloudBadges-32T__F85.js (removed) 1.08 kB 🟢 -1.08 kB 🟢 -537 B 🟢 -478 B
assets/cloudBadges-DDEPfaqD.js (new) 1.08 kB 🔴 +1.08 kB 🔴 +538 B 🔴 +481 B
assets/graphHasMissingNodes-CNm0DyBF.js (removed) 1.06 kB 🟢 -1.06 kB 🟢 -460 B 🟢 -425 B
assets/graphHasMissingNodes-D-SMZixm.js (new) 1.06 kB 🔴 +1.06 kB 🔴 +462 B 🔴 +428 B
assets/cloudSubscription-cK0hpsTX.js (new) 976 B 🔴 +976 B 🔴 +460 B 🔴 +397 B
assets/cloudSubscription-DsXtNEwu.js (removed) 976 B 🟢 -976 B 🟢 -455 B 🟢 -393 B
assets/AudioPreviewPlayer-FjjNMkYg.js (removed) 191 B 🟢 -191 B 🟢 -120 B 🟢 -109 B
assets/AudioPreviewPlayer-u2umWaiC.js (new) 191 B 🔴 +191 B 🔴 +120 B 🔴 +116 B
assets/WidgetBoundingBox-DbneBqGa.js (new) 186 B 🔴 +186 B 🔴 +119 B 🔴 +116 B
assets/WidgetBoundingBox-T8Ljl7oe.js (removed) 186 B 🟢 -186 B 🟢 -119 B 🟢 -117 B
assets/WidgetInputNumber-72XXTc2h.js (new) 186 B 🔴 +186 B 🔴 +119 B 🔴 +118 B
assets/WidgetInputNumber-BeePlr-Q.js (removed) 186 B 🟢 -186 B 🟢 -119 B 🟢 -123 B
assets/WidgetLegacy-CPJVrTxv.js (new) 164 B 🔴 +164 B 🔴 +125 B 🔴 +107 B
assets/WidgetLegacy-CtLX1i1n.js (removed) 164 B 🟢 -164 B 🟢 -125 B 🟢 -110 B
assets/WidgetSelect-B_BIH3B6.js (removed) 161 B 🟢 -161 B 🟢 -113 B 🟢 -106 B
assets/WidgetSelect-De9v-ct3.js (new) 161 B 🔴 +161 B 🔴 +113 B 🔴 +110 B
assets/mixpanel.module-DU0Ns9U-.js (new) 143 B 🔴 +143 B 🔴 +125 B 🔴 +107 B
assets/mixpanel.module-FcNs04XW.js (removed) 143 B 🟢 -143 B 🟢 -125 B 🟢 -112 B
assets/Load3D-BoY7EWO7.js (removed) 131 B 🟢 -131 B 🟢 -107 B 🟢 -118 B
assets/Load3D-C8Qjr89L.js (new) 131 B 🔴 +131 B 🔴 +107 B 🔴 +115 B
assets/auto-Bv9cmrEd.js 1.73 kB 1.73 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-6dIwsSNi.js 17.2 kB 17.2 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BahwM9ZP.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BoJZgy7S.js 17 kB 17 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-BQtdp20P.js 20.6 kB 20.6 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CEMgeOuO.js 18.5 kB 18.5 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CnxND6sZ.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-coXkrooi.js 18 kB 18 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-CZcHDaAg.js 18.8 kB 18.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DDPGTXy9.js 17.9 kB 17.9 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-DsGC6118.js 17.8 kB 17.8 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/commands-yZ2AjT4s.js 19.3 kB 19.3 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-BH76kbq7.js 104 kB 104 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-C-gNarDo.js 105 kB 105 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CA0dzqpC.js 124 kB 124 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CbaIObx3.js 121 kB 121 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CKH_pYcz.js 161 kB 161 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-CotnVZA-.js 134 kB 134 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-D-IO_jVl.js 119 kB 119 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-DLii8dI6.js 117 kB 117 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-i8aQGyai.js 145 kB 145 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-Uwzs8jut.js 141 kB 141 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/main-vWcCEZeZ.js 117 kB 117 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-6qSb98D5.js 329 kB 329 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-B4G_Dl5E.js 361 kB 361 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-BhmSU7DZ.js 371 kB 371 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Bxky0ZDY.js 332 kB 332 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CCSKuw9P.js 400 kB 400 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-Cd4f2ERd.js 358 kB 358 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CLdE8MPH.js 355 kB 355 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CqDWLi76.js 399 kB 399 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-CqyprhWq.js 433 kB 433 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-D4Fo85EU.js 358 kB 358 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/nodeDefs-DF-ErmAt.js 351 kB 351 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/OBJLoader2WorkerModule-DTMpvldF.js 109 kB 109 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/preservedQueryNamespaces-BsMrb3S_.js 3.23 kB 3.23 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/previousFullPath-DZ1Jt5wB.js 838 B 838 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/rolldown-runtime-CqTjxoQm.js 1.53 kB 1.53 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widget-Dneex3J5.js 518 B 518 B ⚪ 0 B ⚪ 0 B ⚪ 0 B
assets/widgetPropFilter-DfR_ZXyS.js 1.31 kB 1.31 kB ⚪ 0 B ⚪ 0 B ⚪ 0 B

Status: 43 added / 43 removed

@DrJKL DrJKL force-pushed the drjkl/others-call-it-a-garage-sale branch 4 times, most recently from 3a09d83 to f93d463 Compare January 17, 2026 00:40
@DrJKL DrJKL added the preview label Jan 17, 2026
@DrJKL DrJKL force-pushed the drjkl/others-call-it-a-garage-sale branch from 17e00e1 to 6600086 Compare January 17, 2026 22:29
@DrJKL DrJKL self-assigned this Jan 17, 2026
@DrJKL
Copy link
Contributor Author

DrJKL commented Jan 17, 2026

Let me know if you'd like me to extract the Select component as a separate PR.

@DrJKL DrJKL added the Design Used to request Product feedback on design decisions label Jan 18, 2026
DrJKL and others added 15 commits January 18, 2026 01:25
@DrJKL DrJKL requested review from a team as code owners January 19, 2026 04:03
@dosubot dosubot bot added the size:XXL This PR changes 1000+ lines, ignoring generated files. label Jan 19, 2026
@DrJKL DrJKL assigned PabloWiedemann and comfydesigner and unassigned DrJKL Jan 19, 2026
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 8

Caution

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

⚠️ Outside diff range comments (1)
src/platform/assets/services/assetService.ts (1)

300-326: Use fromZodError for consistent error handling.

The updateAsset method directly includes the Zod error in the thrown message (line 324), which could expose internal schema details. Other methods like validateAssetResponse (line 66) use fromZodError for user-friendly error formatting.

♻️ Proposed fix
+import { fromZodError } from 'zod-validation-error'
+
 // ... in updateAsset function
     const newAsset = assetItemSchema.safeParse(await res.json())
     if (newAsset.success) {
       return newAsset.data
     }

-    throw new Error(
-      `Unable to update asset ${id}: Invalid response - ${newAsset.error}`
-    )
+    const error = fromZodError(newAsset.error)
+    console.error(`Invalid update response for asset ${id}:`, error)
+    throw new Error(`Unable to update asset ${id}: Invalid response`)

Based on learnings, prefer safeParse() with fromZodError() for logging while throwing user-friendly errors that don't reveal internal schema details.

🤖 Fix all issues with AI agents
In `@src/components/ui/select/SelectValue.vue`:
- Around line 1-12: The file SelectValue.vue uses
defineProps<SelectValueProps>() directly; to follow the project's reactive props
destructuring pattern (as used in SelectLabel.vue), destructure props into a
reactive constant (e.g., const props = defineProps<SelectValueProps>() -> const
{ /* ...props */ } = toRefs(defineProps<SelectValueProps>()) or the project's
established helper) and then bind that reactive object to the <SelectValue>
component so props are consistent across Select wrappers; locate
SelectValue.vue, the defineProps and the <SelectValue v-bind="props"> usage and
convert to the same reactive-destructured pattern used by SelectLabel.vue.

In `@src/components/widget/layout/BaseModalLayout.vue`:
- Around line 22-46: The icon-only Buttons (those invoking toggleLeftPanel,
toggleRightPanel, and closeDialog and conditioned by notMobile, hasRightPanel,
isRightPanelOpen, showLeftPanel) lack accessible names; add descriptive
accessible labels by adding an aria-label (or aria-labelledby) and optional
title to each Button so screen readers can announce their purpose (e.g., left
panel toggle, right panel open/close, close dialog), ensuring the label reflects
the dynamic state when applicable (use showLeftPanel to switch the label text).

In `@src/platform/assets/components/AssetGrid.vue`:
- Around line 75-86: The responsive breakpoint logic in AssetGrid.vue works but
can be simplified: replace multiple reactive refs (is2Xl, isXl, isLg, isMd) with
a single current breakpoint read from useBreakpoints().current() and compute
maxColumns based on that single value; update references to the useBreakpoints
import and the computed maxColumns (function name/symbol: maxColumns, and the
useBreakpoints call) to derive columns from the current breakpoint string
instead of multiple greaterOrEqual refs to reduce verbosity while preserving
behavior.

In `@src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts`:
- Around line 131-155: Add a test in ModelInfoPanel.test.ts that verifies both
description fields render: create an asset via createMockAsset with a value that
getAssetDescription(asset) would return and a user-editable description in
user_metadata (or the prop the component uses), mount it with mountPanel, then
assert the read-only description text (from getAssetDescription) appears and
that the editable textarea/input for the user description exists and contains
the expected user-provided value; reference ModelInfoPanel.vue,
getAssetDescription(asset), mountPanel, and createMockAsset to locate where to
add this spec.

In `@src/platform/assets/components/modelInfo/ModelInfoPanel.vue`:
- Around line 141-157: The two ModelInfoField instances both use the same label
key causing duplicate "Description" headings; update the first (read-only)
ModelInfoField and the second (editable) ModelInfoField to use distinct
translation keys (e.g., change the label prop on the read-only ModelInfoField
and the editable one) so they display different labels (e.g., "Source
Description" vs "Your Notes"); update or add corresponding i18n keys for those
new labels and ensure the editable field still binds to userDescription, uses
ref descriptionTextarea and respects isImmutable.

In `@src/platform/assets/composables/useModelTypes.ts`:
- Around line 78-81: The fetchModelTypes function currently returns undefined on
the early exit but returns execute() (a Promise<ModelTypeOption[]>) otherwise,
causing an inconsistent return type; fix this by making the return contract
explicit: either (A) keep it fire-and-forget and make fetchModelTypes async and
await execute() so it always returns Promise<void> (no value) or (B) keep
returning the result and update the signature to
Promise<ModelTypeOption[]|undefined> and explicitly return undefined on early
exit; locate fetchModelTypes and the execute() call (and checks against
isReady.value / isLoading.value) and apply one of these two approaches
consistently across callers.

In `@src/platform/assets/utils/assetMetadataUtils.test.ts`:
- Around line 71-199: Add unit tests for the three new helpers:
getAssetBaseModels, getAssetModelType, and getAssetUserDescription. For
getAssetBaseModels, add tests that return an array when
user_metadata.base_models is an array of strings, filter out non-string entries,
and return [] when missing or not an array; for getAssetModelType, add tests
that return the expected model type string when user_metadata.model_type is a
string (including mixed-case inputs if normalization exists) and return null or
a default when absent or not a string; for getAssetUserDescription, add tests
that return the description string when user_metadata.user_description is a
string and return null/empty when missing or not a string. Use the same
mockAsset pattern as the existing tests and mirror the style used for
getAssetTriggerPhrases/getAssetAdditionalTags to keep consistency.

In `@src/stores/assetsStore.ts`:
- Around line 349-401: The optimistic cache updates in updateAssetMetadata and
updateAssetTags call updateAssetInCache before the network request and lack
rollback on failure; modify these functions to capture the previous asset
state(s) from modelAssetsByNodeType (using the same key-selection logic as
updateAssetInCache), perform the optimistic update, then wrap the
assetService.updateAsset call in try/catch and on error restore the previous
asset state(s) into modelAssetsByNodeType (or trigger a full re-fetch if
restoration is impractical); ensure the rollback honors the optional cacheKey
behavior and that error is re-thrown or handled/logged after restoring state.

Comment on lines +131 to +155
describe('Model Description Section', () => {
it('renders trigger phrases when present', () => {
const asset = createMockAsset({
user_metadata: { trained_words: ['trigger1', 'trigger2'] }
})
const wrapper = mountPanel(asset)
expect(wrapper.text()).toContain('trigger1')
expect(wrapper.text()).toContain('trigger2')
})

it('renders description section', () => {
const wrapper = mountPanel(createMockAsset())
expect(wrapper.text()).toContain(
'assetBrowser.modelInfo.modelDescription'
)
})

it('does not render trigger phrases field when empty', () => {
const asset = createMockAsset()
const wrapper = mountPanel(asset)
expect(wrapper.text()).not.toContain(
'assetBrowser.modelInfo.triggerPhrases'
)
})
})
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider adding a test for the duplicate description field scenario.

Lines 141-146 test the description section rendering, but ModelInfoPanel.vue (lines 141-157) renders two separate description fields:

  1. A read-only description from getAssetDescription(asset) (line 142-146)
  2. An editable user description textarea (line 147-157)

The current test only validates the section label exists. Consider adding a test to verify both description fields render correctly when appropriate.

🤖 Prompt for AI Agents
In `@src/platform/assets/components/modelInfo/ModelInfoPanel.test.ts` around lines
131 - 155, Add a test in ModelInfoPanel.test.ts that verifies both description
fields render: create an asset via createMockAsset with a value that
getAssetDescription(asset) would return and a user-editable description in
user_metadata (or the prop the component uses), mount it with mountPanel, then
assert the read-only description text (from getAssetDescription) appears and
that the editable textarea/input for the user description exists and contains
the expected user-provided value; reference ModelInfoPanel.vue,
getAssetDescription(asset), mountPanel, and createMockAsset to locate where to
add this spec.

Comment on lines 141 to 157
<ModelInfoField
v-if="description"
:label="$t('assetBrowser.modelInfo.description')"
>
<p class="text-sm whitespace-pre-wrap">{{ description }}</p>
</ModelInfoField>
<ModelInfoField :label="$t('assetBrowser.modelInfo.description')">
<textarea
ref="descriptionTextarea"
v-model="userDescription"
:disabled="isImmutable"
:placeholder="$t('assetBrowser.modelInfo.descriptionPlaceholder')"
rows="3"
class="w-full resize-y rounded-lg border border-transparent bg-transparent px-3 py-2 text-sm text-component-node-foreground outline-none transition-colors focus:bg-component-node-widget-background disabled:pointer-events-none"
@keydown.escape.stop="descriptionTextarea?.blur()"
/>
</ModelInfoField>
Copy link
Contributor

@coderabbitai coderabbitai bot Jan 19, 2026

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Duplicate "Description" labels may confuse users.

Both the read-only description (line 143) and the editable user description (line 147) use the same label key assetBrowser.modelInfo.description. Consider using distinct labels (e.g., "Source Description" and "Your Notes") to clarify their purposes.

🤖 Prompt for AI Agents
In `@src/platform/assets/components/modelInfo/ModelInfoPanel.vue` around lines 141
- 157, The two ModelInfoField instances both use the same label key causing
duplicate "Description" headings; update the first (read-only) ModelInfoField
and the second (editable) ModelInfoField to use distinct translation keys (e.g.,
change the label prop on the read-only ModelInfoField and the editable one) so
they display different labels (e.g., "Source Description" vs "Your Notes");
update or add corresponding i18n keys for those new labels and ensure the
editable field still binds to userDescription, uses ref descriptionTextarea and
respects isImmutable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Copy link
Contributor

Choose a reason for hiding this comment

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

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

Comment on lines +349 to +401
function updateAssetInCache(
assetId: string,
updates: Partial<AssetItem>,
cacheKey?: string
) {
const keysToCheck = cacheKey
? [cacheKey]
: Array.from(modelAssetsByNodeType.keys())

for (const key of keysToCheck) {
const assets = modelAssetsByNodeType.get(key)
if (!assets) continue

const index = assets.findIndex((a) => a.id === assetId)
if (index !== -1) {
const updatedAsset = { ...assets[index], ...updates }
const newAssets = [...assets]
newAssets[index] = updatedAsset
modelAssetsByNodeType.set(key, newAssets)
if (cacheKey) return
}
}
}

/**
* Update asset metadata with optimistic cache update
* @param assetId The asset ID to update
* @param userMetadata The user_metadata to save
* @param cacheKey Optional cache key to target for optimistic update
*/
async function updateAssetMetadata(
assetId: string,
userMetadata: Record<string, unknown>,
cacheKey?: string
) {
updateAssetInCache(assetId, { user_metadata: userMetadata }, cacheKey)
await assetService.updateAsset(assetId, { user_metadata: userMetadata })
}

/**
* Update asset tags with optimistic cache update
* @param assetId The asset ID to update
* @param tags The tags array to save
* @param cacheKey Optional cache key to target for optimistic update
*/
async function updateAssetTags(
assetId: string,
tags: string[],
cacheKey?: string
) {
updateAssetInCache(assetId, { tags }, cacheKey)
await assetService.updateAsset(assetId, { tags })
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add rollback/error handling for optimistic updates.

The cache is updated before the network call; if assetService.updateAsset fails, the UI stays out of sync. Capture previous values and revert on failure (or re-fetch) to keep state consistent. As per coding guidelines, implement proper error handling.

💡 Suggested rollback pattern
-      function updateAssetInCache(
+      function updateAssetInCache(
         assetId: string,
         updates: Partial<AssetItem>,
         cacheKey?: string
-      ) {
+      ): Map<string, AssetItem> {
         const keysToCheck = cacheKey
           ? [cacheKey]
           : Array.from(modelAssetsByNodeType.keys())
+        const previousByKey = new Map<string, AssetItem>()

         for (const key of keysToCheck) {
           const assets = modelAssetsByNodeType.get(key)
           if (!assets) continue

           const index = assets.findIndex((a) => a.id === assetId)
           if (index !== -1) {
+            previousByKey.set(key, assets[index])
             const updatedAsset = { ...assets[index], ...updates }
             const newAssets = [...assets]
             newAssets[index] = updatedAsset
             modelAssetsByNodeType.set(key, newAssets)
-            if (cacheKey) return
+            if (cacheKey) break
           }
         }
+        return previousByKey
       }

       async function updateAssetMetadata(
         assetId: string,
         userMetadata: Record<string, unknown>,
         cacheKey?: string
       ) {
-        updateAssetInCache(assetId, { user_metadata: userMetadata }, cacheKey)
-        await assetService.updateAsset(assetId, { user_metadata: userMetadata })
+        const previous = updateAssetInCache(
+          assetId,
+          { user_metadata: userMetadata },
+          cacheKey
+        )
+        try {
+          await assetService.updateAsset(assetId, { user_metadata: userMetadata })
+        } catch (err) {
+          for (const [key, asset] of previous) {
+            updateAssetInCache(assetId, asset, key)
+          }
+          throw err
+        }
       }

       async function updateAssetTags(
         assetId: string,
         tags: string[],
         cacheKey?: string
       ) {
-        updateAssetInCache(assetId, { tags }, cacheKey)
-        await assetService.updateAsset(assetId, { tags })
+        const previous = updateAssetInCache(assetId, { tags }, cacheKey)
+        try {
+          await assetService.updateAsset(assetId, { tags })
+        } catch (err) {
+          for (const [key, asset] of previous) {
+            updateAssetInCache(assetId, asset, key)
+          }
+          throw err
+        }
       }
🤖 Prompt for AI Agents
In `@src/stores/assetsStore.ts` around lines 349 - 401, The optimistic cache
updates in updateAssetMetadata and updateAssetTags call updateAssetInCache
before the network request and lack rollback on failure; modify these functions
to capture the previous asset state(s) from modelAssetsByNodeType (using the
same key-selection logic as updateAssetInCache), perform the optimistic update,
then wrap the assetService.updateAsset call in try/catch and on error restore
the previous asset state(s) into modelAssetsByNodeType (or trigger a full
re-fetch if restoration is impractical); ensure the rollback honors the optional
cacheKey behavior and that error is re-thrown or handled/logged after restoring
state.

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

Caution

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

⚠️ Outside diff range comments (1)
src/components/widget/layout/BaseModalLayout.vue (1)

198-210: Consider converting scoped styles to Tailwind utilities.

Per coding guidelines, Vue components should avoid <style> blocks and use Tailwind for styling. Most of these styles can be expressed as Tailwind utilities:

<div class="h-[80vh] w-[90vw] max-w-[1280px] aspect-[20/13] 
            min-[1450px]:max-w-[1724px] rounded-2xl overflow-hidden relative">

The custom 1450px breakpoint can use Tailwind's arbitrary breakpoint syntax min-[1450px]:.

♻️ Proposed refactor
 <template>
   <div
-    class="base-widget-layout rounded-2xl overflow-hidden relative"
+    class="h-[80vh] w-[90vw] max-w-[1280px] min-[1450px]:max-w-[1724px] aspect-[20/13] rounded-2xl overflow-hidden relative"
     `@keydown.esc.capture`="handleEscape"
   >

Then remove the <style scoped> block entirely.

🤖 Fix all issues with AI agents
In `@src/components/widget/layout/BaseModalLayout.vue`:
- Around line 184-196: The escape handler in handleEscape currently only ignores
HTMLInputElement and HTMLTextAreaElement; update it to also ignore
contenteditable elements, select elements, and inputs inside Shadow DOM by:
treat event.target as Node/HTMLElement, return early if (target as
HTMLElement).isContentEditable is true or if tagName === 'SELECT', and
additionally inspect event.composedPath() for any
HTMLInputElement/HTMLTextAreaElement/select or an element with isContentEditable
so components using Shadow DOM are covered; keep the existing logic that closes
the right panel by setting isRightPanelOpen.value = false and stopping
propagation when none of these conditions match.

Comment on lines +184 to +196
function handleEscape(event: KeyboardEvent) {
const target = event.target
if (
target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement
) {
return
}
if (isRightPanelOpen.value) {
event.stopPropagation()
isRightPanelOpen.value = false
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Consider expanding the escape handler to cover additional editable elements.

The check for HTMLInputElement and HTMLTextAreaElement may not cover all scenarios where escape should be ignored:

  • contenteditable elements
  • <select> elements
  • Components using Shadow DOM inputs

If these element types are used within the right panel, users may experience unexpected panel closure.

🛠️ Optional enhancement
 function handleEscape(event: KeyboardEvent) {
   const target = event.target
+  if (!(target instanceof HTMLElement)) return
   if (
     target instanceof HTMLInputElement ||
-    target instanceof HTMLTextAreaElement
+    target instanceof HTMLTextAreaElement ||
+    target instanceof HTMLSelectElement ||
+    target.isContentEditable
   ) {
     return
   }
   if (isRightPanelOpen.value) {
     event.stopPropagation()
     isRightPanelOpen.value = false
   }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function handleEscape(event: KeyboardEvent) {
const target = event.target
if (
target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement
) {
return
}
if (isRightPanelOpen.value) {
event.stopPropagation()
isRightPanelOpen.value = false
}
}
function handleEscape(event: KeyboardEvent) {
const target = event.target
if (!(target instanceof HTMLElement)) return
if (
target instanceof HTMLInputElement ||
target instanceof HTMLTextAreaElement ||
target instanceof HTMLSelectElement ||
target.isContentEditable
) {
return
}
if (isRightPanelOpen.value) {
event.stopPropagation()
isRightPanelOpen.value = false
}
}
🤖 Prompt for AI Agents
In `@src/components/widget/layout/BaseModalLayout.vue` around lines 184 - 196, The
escape handler in handleEscape currently only ignores HTMLInputElement and
HTMLTextAreaElement; update it to also ignore contenteditable elements, select
elements, and inputs inside Shadow DOM by: treat event.target as
Node/HTMLElement, return early if (target as HTMLElement).isContentEditable is
true or if tagName === 'SELECT', and additionally inspect event.composedPath()
for any HTMLInputElement/HTMLTextAreaElement/select or an element with
isContentEditable so components using Shadow DOM are covered; keep the existing
logic that closes the right panel by setting isRightPanelOpen.value = false and
stopping propagation when none of these conditions match.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/platform/assets/components/AssetCard.vue`:
- Around line 40-52: The Info Button component (the icon-only Button with
v-tooltip.bottom and `@click.stop`="$emit('showInfo', asset)") lacks an accessible
name; add an aria-label attribute to that Button and set its value to the same
i18n key used for the tooltip (i.e. use $t('assetBrowser.modelInfo.title')) so
screen readers announce it; ensure you only add aria-label to this icon-only
Button and not to other buttons like MoreButton.

Comment on lines +40 to +52
<Button
v-tooltip.bottom="$t('assetBrowser.modelInfo.title')"
variant="secondary"
size="sm"
@click.stop="$emit('showInfo', asset)"
>
<i class="icon-[lucide--info]" />
</Button>
<MoreButton
v-if="showAssetOptions"
ref="dropdown-menu-button"
size="sm"
>
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add an accessible label to the icon-only Info button.

Line 40: the tooltip doesn’t provide an accessible name, so screen readers will announce an unlabeled button. Please add an aria-label using the existing i18n key. Based on learnings, add aria-labels only for icon-only buttons.

✅ Suggested fix
-        <Button
-          v-tooltip.bottom="$t('assetBrowser.modelInfo.title')"
-          variant="secondary"
-          size="sm"
-          `@click.stop`="$emit('showInfo', asset)"
-        >
+        <Button
+          v-tooltip.bottom="$t('assetBrowser.modelInfo.title')"
+          :aria-label="$t('assetBrowser.modelInfo.title')"
+          variant="secondary"
+          size="sm"
+          `@click.stop`="$emit('showInfo', asset)"
+        >
🤖 Prompt for AI Agents
In `@src/platform/assets/components/AssetCard.vue` around lines 40 - 52, The Info
Button component (the icon-only Button with v-tooltip.bottom and
`@click.stop`="$emit('showInfo', asset)") lacks an accessible name; add an
aria-label attribute to that Button and set its value to the same i18n key used
for the tooltip (i.e. use $t('assetBrowser.modelInfo.title')) so screen readers
announce it; ensure you only add aria-label to this icon-only Button and not to
other buttons like MoreButton.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/platform/assets/composables/useAssetBrowser.test.ts`:
- Around line 504-508: The test's expected object for navItems.value[2] uses
title: 'BY TYPE' but the mock translation returns 'By type', causing a mismatch;
update the expectation in the test to match the mocked translation (change title
to 'By type') or adjust the mock translation to return 'BY TYPE' so the value
returned by the translation helper and the assertion in the test
(navItems.value[2]) are consistent.
♻️ Duplicate comments (1)
src/platform/assets/components/AssetGrid.vue (1)

81-99: Responsive column logic and static grid style look good.

The breakpoint-driven maxColumns computed property correctly uses VueUse's useBreakpoints as recommended. Converting gridStyle to a static constant is appropriate since the values don't change at runtime.

Note: A past review suggested an optional simplification using useBreakpoints().current(), but the current approach is clear and the performance difference is negligible.

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

🤖 Fix all issues with AI agents
In `@src/platform/assets/composables/useAssetBrowser.test.ts`:
- Around line 382-386: The test calls updateFilters({ sortBy: 'name', ... })
which uses an undocumented value; change the test to use a documented sort key
(e.g., 'name-asc' or 'name-desc' depending on intended behaviour) so it
exercises the actual branches handled by the implementation (updateFilters /
sort logic that expects 'name-asc', 'name-desc', 'recent', 'popular').

In `@src/platform/assets/composables/useAssetBrowser.ts`:
- Around line 15-17: The NavId type alias currently declared as "type NavId =
'all' | 'imported' | string" collapses to plain string; decide whether to keep
arbitrary strings or tighten the type: either leave NavId as string (or replace
the union with just string) if arbitrary category IDs are intended, or replace
NavId with a stricter type such as a branded type or a template literal (e.g.,
Brand<'NavId'> or `type NavId = \`nav-\${string}\``) to preserve autocomplete
while enforcing constraints; update the declaration of NavId accordingly and
adjust any uses of NavId in this file if necessary (look for references to NavId
in useAssetBrowser composable).

Comment on lines 382 to 386
updateFilters({
sortBy: 'name',
fileFormats: [],
baseModels: [],
ownership: 'all'
baseModels: []
})
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use documented sortBy value.

The test uses sortBy: 'name' but the implementation only handles 'name-asc', 'name-desc', 'recent', and 'popular'. While this works (falls through to default), it tests an undocumented value.

🐛 Proposed fix
       updateFilters({
-        sortBy: 'name',
+        sortBy: 'name-asc',
         fileFormats: [],
         baseModels: []
       })
🤖 Prompt for AI Agents
In `@src/platform/assets/composables/useAssetBrowser.test.ts` around lines 382 -
386, The test calls updateFilters({ sortBy: 'name', ... }) which uses an
undocumented value; change the test to use a documented sort key (e.g.,
'name-asc' or 'name-desc' depending on intended behaviour) so it exercises the
actual branches handled by the implementation (updateFilters / sort logic that
expects 'name-asc', 'name-desc', 'recent', 'popular').

Comment on lines +15 to +17
type OwnershipOption = 'all' | 'my-models' | 'public-models'

type NavId = 'all' | 'imported' | string
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Type alias NavId simplifies to string.

The union 'all' | 'imported' | string collapses to just string since any string literal is a subtype of string. If the intent is to provide IDE autocompletion hints for common values while allowing arbitrary strings, this works but loses type safety. Consider either:

  1. Keep as-is if arbitrary category IDs are intentional (current behavior is correct)
  2. Or use a branded type / template literal for stricter typing if you want to restrict values
🤖 Prompt for AI Agents
In `@src/platform/assets/composables/useAssetBrowser.ts` around lines 15 - 17, The
NavId type alias currently declared as "type NavId = 'all' | 'imported' |
string" collapses to plain string; decide whether to keep arbitrary strings or
tighten the type: either leave NavId as string (or replace the union with just
string) if arbitrary category IDs are intended, or replace NavId with a stricter
type such as a branded type or a template literal (e.g., Brand<'NavId'> or `type
NavId = \`nav-\${string}\``) to preserve autocomplete while enforcing
constraints; update the declaration of NavId accordingly and adjust any uses of
NavId in this file if necessary (look for references to NavId in useAssetBrowser
composable).

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

Labels

Design Used to request Product feedback on design decisions preview 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