refactor: replace AssetDropdownItem with FormDropdownItem

- Create minimal FormDropdownItem interface in dropdown/types.ts

- Remove dropdownItems computed from useAssetWidgetData

- Transform assets in WidgetSelectDropdown using getAssetFilename()

- Delete assetDropdownTypes.ts and assetDropdownUtils.ts

- Update all FormDropdown components to use FormDropdownItem

Amp-Thread-ID: https://ampcode.com/threads/T-019c10c6-5e4c-774a-90ce-cb00178ad6e3
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Alexander Brown
2026-01-30 13:31:50 -08:00
parent 22bb79adcc
commit c10a10c02d
14 changed files with 91 additions and 107 deletions

View File

@@ -1,15 +0,0 @@
import type { OptionId } from './filterTypes'
/**
* Lightweight display projection of AssetItem for dropdown/selection UIs.
* Used by FormDropdown and WidgetSelectDropdown.
*/
export interface AssetDropdownItem {
id: OptionId
/** Display name (user-defined filename or asset name) */
name: string
/** Original filename from asset */
label?: string
/** Preview image/video URL */
previewUrl: string
}

View File

@@ -1,14 +0,0 @@
import type { AssetItem } from '../schemas/assetSchema'
import type { AssetDropdownItem } from '../types/assetDropdownTypes'
/**
* Transforms an AssetItem to AssetDropdownItem for dropdown display.
*/
export function toAssetDropdownItem(asset: AssetItem): AssetDropdownItem {
return {
id: asset.id,
name: (asset.user_metadata?.filename as string | undefined) ?? asset.name,
label: asset.name,
previewUrl: asset.preview_url ?? ''
}
}

View File

@@ -7,7 +7,7 @@ import type { AssetSortOption } from '../types/filterTypes'
/** /**
* Minimal interface for sortable items * Minimal interface for sortable items
* Works with both AssetItem and AssetDropdownItem * Works with both AssetItem and FormDropdownItem
*/ */
export interface SortableItem { export interface SortableItem {
name: string name: string

View File

@@ -5,15 +5,15 @@ import PrimeVue from 'primevue/config'
import type { ComponentPublicInstance } from 'vue' import type { ComponentPublicInstance } from 'vue'
import { describe, expect, it, vi } from 'vitest' import { describe, expect, it, vi } from 'vitest'
import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes' import type { FormDropdownItem } from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/types'
import type { ComboInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2' import type { ComboInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
import type { SimplifiedWidget } from '@/types/simplifiedWidget' import type { SimplifiedWidget } from '@/types/simplifiedWidget'
import WidgetSelectDropdown from '@/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue' import WidgetSelectDropdown from '@/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue'
interface WidgetSelectDropdownInstance extends ComponentPublicInstance { interface WidgetSelectDropdownInstance extends ComponentPublicInstance {
inputItems: AssetDropdownItem[] inputItems: FormDropdownItem[]
outputItems: AssetDropdownItem[] outputItems: FormDropdownItem[]
updateSelectedItems: (selectedSet: Set<string>) => void updateSelectedItems: (selectedSet: Set<string>) => void
} }
@@ -231,7 +231,7 @@ describe('WidgetSelectDropdown custom label mapping', () => {
// The missing value should be accessible via dropdownItems when filter is 'all' (default) // The missing value should be accessible via dropdownItems when filter is 'all' (default)
const dropdownItems = ( const dropdownItems = (
wrapper.vm as unknown as { dropdownItems: AssetDropdownItem[] } wrapper.vm as unknown as { dropdownItems: FormDropdownItem[] }
).dropdownItems ).dropdownItems
expect( expect(
dropdownItems.some((item) => item.name === 'template_image.png') dropdownItems.some((item) => item.name === 'template_image.png')
@@ -248,7 +248,7 @@ describe('WidgetSelectDropdown custom label mapping', () => {
const vmWithFilter = wrapper.vm as unknown as { const vmWithFilter = wrapper.vm as unknown as {
filterSelected: string filterSelected: string
dropdownItems: AssetDropdownItem[] dropdownItems: FormDropdownItem[]
} }
vmWithFilter.filterSelected = 'inputs' vmWithFilter.filterSelected = 'inputs'
@@ -269,8 +269,8 @@ describe('WidgetSelectDropdown custom label mapping', () => {
const vmWithFilter = wrapper.vm as unknown as { const vmWithFilter = wrapper.vm as unknown as {
filterSelected: string filterSelected: string
dropdownItems: AssetDropdownItem[] dropdownItems: FormDropdownItem[]
outputItems: AssetDropdownItem[] outputItems: FormDropdownItem[]
} }
vmWithFilter.filterSelected = 'outputs' vmWithFilter.filterSelected = 'outputs'
@@ -290,7 +290,7 @@ describe('WidgetSelectDropdown custom label mapping', () => {
const wrapper = mountComponent(widget, 'img_001.png') const wrapper = mountComponent(widget, 'img_001.png')
const dropdownItems = ( const dropdownItems = (
wrapper.vm as unknown as { dropdownItems: AssetDropdownItem[] } wrapper.vm as unknown as { dropdownItems: FormDropdownItem[] }
).dropdownItems ).dropdownItems
expect(dropdownItems).toHaveLength(2) expect(dropdownItems).toHaveLength(2)
expect( expect(
@@ -305,7 +305,7 @@ describe('WidgetSelectDropdown custom label mapping', () => {
const wrapper = mountComponent(widget, undefined) const wrapper = mountComponent(widget, undefined)
const dropdownItems = ( const dropdownItems = (
wrapper.vm as unknown as { dropdownItems: AssetDropdownItem[] } wrapper.vm as unknown as { dropdownItems: FormDropdownItem[] }
).dropdownItems ).dropdownItems
expect(dropdownItems).toHaveLength(2) expect(dropdownItems).toHaveLength(2)
expect( expect(

View File

@@ -4,15 +4,21 @@ import { computed, provide, ref, toRef, watch } from 'vue'
import { useTransformCompatOverlayProps } from '@/composables/useTransformCompatOverlayProps' import { useTransformCompatOverlayProps } from '@/composables/useTransformCompatOverlayProps'
import { t } from '@/i18n' import { t } from '@/i18n'
import {
getAssetDisplayName,
getAssetFilename
} from '@/platform/assets/utils/assetMetadataUtils'
import { useToastStore } from '@/platform/updates/common/toastStore' import { useToastStore } from '@/platform/updates/common/toastStore'
import FormDropdown from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue' import FormDropdown from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue'
import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes'
import type { import type {
FilterOption, FilterOption,
OptionId OptionId
} from '@/platform/assets/types/filterTypes' } from '@/platform/assets/types/filterTypes'
import { AssetKindKey } from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/types'; import { AssetKindKey } from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/types'
import type { LayoutMode } from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/types'; import type {
FormDropdownItem,
LayoutMode
} from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/types'
import WidgetLayoutField from '@/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue' import WidgetLayoutField from '@/renderer/extensions/vueNodes/widgets/components/layout/WidgetLayoutField.vue'
import { useAssetWidgetData } from '@/renderer/extensions/vueNodes/widgets/composables/useAssetWidgetData' import { useAssetWidgetData } from '@/renderer/extensions/vueNodes/widgets/composables/useAssetWidgetData'
import type { ResultItemType } from '@/schemas/apiSchema' import type { ResultItemType } from '@/schemas/apiSchema'
@@ -100,7 +106,7 @@ function getDisplayLabel(value: string): string {
} }
} }
const inputItems = computed<AssetDropdownItem[]>(() => { const inputItems = computed<FormDropdownItem[]>(() => {
const values = props.widget.options?.values || [] const values = props.widget.options?.values || []
if (!Array.isArray(values)) { if (!Array.isArray(values)) {
@@ -109,12 +115,12 @@ const inputItems = computed<AssetDropdownItem[]>(() => {
return values.map((value: string, index: number) => ({ return values.map((value: string, index: number) => ({
id: `input-${index}`, id: `input-${index}`,
previewUrl: getMediaUrl(value, 'input'), preview_url: getMediaUrl(value, 'input'),
name: value, name: value,
label: getDisplayLabel(value) label: getDisplayLabel(value)
})) }))
}) })
const outputItems = computed<AssetDropdownItem[]>(() => { const outputItems = computed<FormDropdownItem[]>(() => {
if (!['image', 'video'].includes(props.assetKind ?? '')) return [] if (!['image', 'video'].includes(props.assetKind ?? '')) return []
const outputs = new Set<string>() const outputs = new Set<string>()
@@ -139,7 +145,7 @@ const outputItems = computed<AssetDropdownItem[]>(() => {
return Array.from(outputs).map((output) => ({ return Array.from(outputs).map((output) => ({
id: `output-${output}`, id: `output-${output}`,
previewUrl: getMediaUrl(output.replace(' [output]', ''), 'output'), preview_url: getMediaUrl(output.replace(' [output]', ''), 'output'),
name: output, name: output,
label: getDisplayLabel(output) label: getDisplayLabel(output)
})) }))
@@ -151,20 +157,20 @@ const outputItems = computed<AssetDropdownItem[]>(() => {
* where the saved value may not exist in the current server environment. * where the saved value may not exist in the current server environment.
* Works for both local mode (inputItems/outputItems) and cloud mode (assetData). * Works for both local mode (inputItems/outputItems) and cloud mode (assetData).
*/ */
const missingValueItem = computed<AssetDropdownItem | undefined>(() => { const missingValueItem = computed<FormDropdownItem | undefined>(() => {
const currentValue = modelValue.value const currentValue = modelValue.value
if (!currentValue) return undefined if (!currentValue) return undefined
// Check in cloud mode assets // Check in cloud mode assets
if (props.isAssetMode && assetData) { if (props.isAssetMode && assetData) {
const existsInAssets = assetData.dropdownItems.value.some( const existsInAssets = assetData.assets.value.some(
(item) => item.name === currentValue (asset) => asset.name === currentValue
) )
if (existsInAssets) return undefined if (existsInAssets) return undefined
return { return {
id: `missing-${currentValue}`, id: `missing-${currentValue}`,
previewUrl: '', preview_url: '',
name: currentValue, name: currentValue,
label: getDisplayLabel(currentValue) label: getDisplayLabel(currentValue)
} }
@@ -187,19 +193,32 @@ const missingValueItem = computed<AssetDropdownItem | undefined>(() => {
return { return {
id: `missing-${currentValue}`, id: `missing-${currentValue}`,
previewUrl: getMediaUrl(strippedValue, isOutput ? 'output' : 'input'), preview_url: getMediaUrl(strippedValue, isOutput ? 'output' : 'input'),
name: currentValue, name: currentValue,
label: getDisplayLabel(currentValue) label: getDisplayLabel(currentValue)
} }
}) })
const allItems = computed<AssetDropdownItem[]>(() => { /**
* Transforms AssetItem[] to FormDropdownItem[] for cloud mode.
* Uses getAssetFilename for display name, asset.name for label.
*/
const assetItems = computed<FormDropdownItem[]>(() => {
if (!props.isAssetMode || !assetData) return []
return assetData.assets.value.map((asset) => ({
id: asset.id,
name: getAssetFilename(asset),
label: getAssetDisplayName(asset),
preview_url: asset.preview_url
}))
})
const allItems = computed<FormDropdownItem[]>(() => {
if (props.isAssetMode && assetData) { if (props.isAssetMode && assetData) {
const items = assetData.dropdownItems.value
if (missingValueItem.value) { if (missingValueItem.value) {
return [missingValueItem.value, ...items] return [missingValueItem.value, ...assetItems.value]
} }
return items return assetItems.value
} }
return [ return [
...(missingValueItem.value ? [missingValueItem.value] : []), ...(missingValueItem.value ? [missingValueItem.value] : []),
@@ -208,7 +227,7 @@ const allItems = computed<AssetDropdownItem[]>(() => {
] ]
}) })
const dropdownItems = computed<AssetDropdownItem[]>(() => { const dropdownItems = computed<FormDropdownItem[]>(() => {
if (props.isAssetMode) { if (props.isAssetMode) {
return allItems.value return allItems.value
} }

View File

@@ -5,7 +5,6 @@ import { computed, ref, useTemplateRef } from 'vue'
import { t } from '@/i18n' import { t } from '@/i18n'
import { useToastStore } from '@/platform/updates/common/toastStore' import { useToastStore } from '@/platform/updates/common/toastStore'
import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes'
import type { import type {
FilterOption, FilterOption,
OptionId OptionId
@@ -14,10 +13,10 @@ import type {
import FormDropdownInput from './FormDropdownInput.vue' import FormDropdownInput from './FormDropdownInput.vue'
import FormDropdownMenu from './FormDropdownMenu.vue' import FormDropdownMenu from './FormDropdownMenu.vue'
import { defaultSearcher, getDefaultSortOptions } from './shared' import { defaultSearcher, getDefaultSortOptions } from './shared'
import type { LayoutMode, SortOption } from './types' import type { FormDropdownItem, LayoutMode, SortOption } from './types'
interface Props { interface Props {
items: AssetDropdownItem[] items: FormDropdownItem[]
placeholder?: string placeholder?: string
/** /**
* If true, allows multiple selections. If a number is provided, * If true, allows multiple selections. If a number is provided,
@@ -32,14 +31,14 @@ interface Props {
sortOptions?: SortOption[] sortOptions?: SortOption[]
isSelected?: ( isSelected?: (
selected: Set<OptionId>, selected: Set<OptionId>,
item: AssetDropdownItem, item: FormDropdownItem,
index: number index: number
) => boolean ) => boolean
searcher?: ( searcher?: (
query: string, query: string,
items: AssetDropdownItem[], items: FormDropdownItem[],
onCleanup: (cleanupFn: () => void) => void onCleanup: (cleanupFn: () => void) => void
) => Promise<AssetDropdownItem[]> ) => Promise<FormDropdownItem[]>
} }
const props = withDefaults(defineProps<Props>(), { const props = withDefaults(defineProps<Props>(), {
@@ -79,7 +78,7 @@ const maxSelectable = computed(() => {
const itemsKey = computed(() => props.items.map((item) => item.id).join('|')) const itemsKey = computed(() => props.items.map((item) => item.id).join('|'))
const filteredItems = ref<AssetDropdownItem[]>([]) const filteredItems = ref<FormDropdownItem[]>([])
const defaultSorter = computed<SortOption['sorter']>(() => { const defaultSorter = computed<SortOption['sorter']>(() => {
const sorter = props.sortOptions.find( const sorter = props.sortOptions.find(
@@ -98,7 +97,7 @@ const sortedItems = computed(() => {
return selectedSorter.value({ items: filteredItems.value }) || [] return selectedSorter.value({ items: filteredItems.value }) || []
}) })
function internalIsSelected(item: AssetDropdownItem, index: number): boolean { function internalIsSelected(item: FormDropdownItem, index: number): boolean {
return props.isSelected?.(selected.value, item, index) ?? false return props.isSelected?.(selected.value, item, index) ?? false
} }
@@ -127,7 +126,7 @@ function handleFileChange(event: Event) {
input.value = '' input.value = ''
} }
function handleSelection(item: AssetDropdownItem, index: number) { function handleSelection(item: FormDropdownItem, index: number) {
if (props.disabled) return if (props.disabled) return
const sel = selected.value const sel = selected.value
if (internalIsSelected(item, index)) { if (internalIsSelected(item, index)) {

View File

@@ -1,16 +1,16 @@
<script setup lang="ts"> <script setup lang="ts">
import { computed } from 'vue' import { computed } from 'vue'
import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes'
import type { OptionId } from '@/platform/assets/types/filterTypes' import type { OptionId } from '@/platform/assets/types/filterTypes'
import { cn } from '@/utils/tailwindUtil' import { cn } from '@/utils/tailwindUtil'
import { WidgetInputBaseClass } from '../../layout' import { WidgetInputBaseClass } from '../../layout'
import type { FormDropdownItem } from './types'
interface Props { interface Props {
isOpen?: boolean isOpen?: boolean
placeholder?: string placeholder?: string
items: AssetDropdownItem[] items: FormDropdownItem[]
selected: Set<OptionId> selected: Set<OptionId>
maxSelectable: number maxSelectable: number
uploadable: boolean uploadable: boolean

View File

@@ -3,7 +3,6 @@ import type { MaybeRefOrGetter } from 'vue'
import { cn } from '@/utils/tailwindUtil' import { cn } from '@/utils/tailwindUtil'
import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes'
import type { import type {
FilterOption, FilterOption,
OptionId OptionId
@@ -12,11 +11,11 @@ import type {
import FormDropdownMenuActions from './FormDropdownMenuActions.vue' import FormDropdownMenuActions from './FormDropdownMenuActions.vue'
import FormDropdownMenuFilter from './FormDropdownMenuFilter.vue' import FormDropdownMenuFilter from './FormDropdownMenuFilter.vue'
import FormDropdownMenuItem from './FormDropdownMenuItem.vue' import FormDropdownMenuItem from './FormDropdownMenuItem.vue'
import type { LayoutMode, SortOption } from './types' import type { FormDropdownItem, LayoutMode, SortOption } from './types'
interface Props { interface Props {
items: AssetDropdownItem[] items: FormDropdownItem[]
isSelected: (item: AssetDropdownItem, index: number) => boolean isSelected: (item: FormDropdownItem, index: number) => boolean
filterOptions: FilterOption[] filterOptions: FilterOption[]
sortOptions: SortOption[] sortOptions: SortOption[]
searcher?: ( searcher?: (
@@ -28,7 +27,7 @@ interface Props {
defineProps<Props>() defineProps<Props>()
const emit = defineEmits<{ const emit = defineEmits<{
(e: 'item-click', item: AssetDropdownItem, index: number): void (e: 'item-click', item: FormDropdownItem, index: number): void
}>() }>()
// Define models for two-way binding // Define models for two-way binding
@@ -90,7 +89,7 @@ const searchQuery = defineModel<string>('searchQuery')
:key="item.id" :key="item.id"
:index="index" :index="index"
:selected="isSelected(item, index)" :selected="isSelected(item, index)"
:preview-url="item.previewUrl" :preview-url="item.preview_url ?? ''"
:name="item.name" :name="item.name"
:label="item.label" :label="item.label"
:layout="layoutMode" :layout="layoutMode"

View File

@@ -1,20 +1,19 @@
import { describe, expect, it } from 'vitest' import { describe, expect, it } from 'vitest'
import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes'
import { defaultSearcher, getDefaultSortOptions } from './shared' import { defaultSearcher, getDefaultSortOptions } from './shared'
import type { FormDropdownItem } from './types'
function createItem(name: string, label?: string): AssetDropdownItem { function createItem(name: string, label?: string): FormDropdownItem {
return { return {
id: name, id: name,
previewUrl: '', preview_url: '',
name, name,
label label
} }
} }
describe('defaultSearcher', () => { describe('defaultSearcher', () => {
const items: AssetDropdownItem[] = [ const items: FormDropdownItem[] = [
createItem('apple.png'), createItem('apple.png'),
createItem('banana.jpg'), createItem('banana.jpg'),
createItem('cherry.gif') createItem('cherry.gif')

View File

@@ -1,12 +1,11 @@
import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes'
import type { AssetSortOption } from '@/platform/assets/types/filterTypes' import type { AssetSortOption } from '@/platform/assets/types/filterTypes'
import { sortAssets } from '@/platform/assets/utils/assetSortUtils' import { sortAssets } from '@/platform/assets/utils/assetSortUtils'
import type { SortOption } from './types' import type { FormDropdownItem, SortOption } from './types'
export async function defaultSearcher( export async function defaultSearcher(
query: string, query: string,
items: AssetDropdownItem[] items: FormDropdownItem[]
) { ) {
if (query.trim() === '') return items if (query.trim() === '') return items
const words = query.trim().toLowerCase().split(' ') const words = query.trim().toLowerCase().split(' ')

View File

@@ -1,13 +1,26 @@
import type { ComputedRef, InjectionKey } from 'vue' import type { ComputedRef, InjectionKey } from 'vue'
import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes'
import type { OptionId } from '@/platform/assets/types/filterTypes' import type { OptionId } from '@/platform/assets/types/filterTypes'
import type { AssetKind } from '@/types/widgetTypes' import type { AssetKind } from '@/types/widgetTypes'
/**
* Minimal interface for items in FormDropdown.
* Both AssetItem (from cloud API) and local file items satisfy this contract.
*/
export interface FormDropdownItem {
id: OptionId
/** Display name shown in the dropdown */
name: string
/** Original/alternate label (e.g., original filename) */
label?: string
/** Preview image/video URL */
preview_url?: string
}
export interface SortOption<TId extends OptionId = OptionId> { export interface SortOption<TId extends OptionId = OptionId> {
id: TId id: TId
name: string name: string
sorter: (ctx: { items: readonly AssetDropdownItem[] }) => AssetDropdownItem[] sorter: (ctx: { items: readonly FormDropdownItem[] }) => FormDropdownItem[]
} }
export type LayoutMode = 'list' | 'grid' | 'list-small' export type LayoutMode = 'list' | 'grid' | 'list-small'

View File

@@ -29,12 +29,10 @@ vi.mock('@/stores/modelToNodeStore', () => ({
describe('useAssetWidgetData (desktop/isCloud=false)', () => { describe('useAssetWidgetData (desktop/isCloud=false)', () => {
it('returns empty/default values without calling stores', () => { it('returns empty/default values without calling stores', () => {
const nodeType = ref('CheckpointLoaderSimple') const nodeType = ref('CheckpointLoaderSimple')
const { category, assets, dropdownItems, isLoading, error } = const { category, assets, isLoading, error } = useAssetWidgetData(nodeType)
useAssetWidgetData(nodeType)
expect(category.value).toBeUndefined() expect(category.value).toBeUndefined()
expect(assets.value).toEqual([]) expect(assets.value).toEqual([])
expect(dropdownItems.value).toEqual([])
expect(isLoading.value).toBe(false) expect(isLoading.value).toBe(false)
expect(error.value).toBeNull() expect(error.value).toBeNull()
expect(mockUpdateModelsForNodeType).not.toHaveBeenCalled() expect(mockUpdateModelsForNodeType).not.toHaveBeenCalled()

View File

@@ -64,7 +64,7 @@ describe('useAssetWidgetData (cloud mode, isCloud=true)', () => {
} }
}) })
it('fetches assets and transforms to dropdown items', async () => { it('fetches assets for a given node type', async () => {
const mockAssets: AssetItem[] = [ const mockAssets: AssetItem[] = [
createMockAsset( createMockAsset(
'asset-1', 'asset-1',
@@ -87,8 +87,7 @@ describe('useAssetWidgetData (cloud mode, isCloud=true)', () => {
) )
const nodeType = ref('CheckpointLoaderSimple') const nodeType = ref('CheckpointLoaderSimple')
const { category, assets, dropdownItems, isLoading } = const { category, assets, isLoading } = useAssetWidgetData(nodeType)
useAssetWidgetData(nodeType)
await nextTick() await nextTick()
await vi.waitFor(() => !isLoading.value) await vi.waitFor(() => !isLoading.value)
@@ -98,13 +97,10 @@ describe('useAssetWidgetData (cloud mode, isCloud=true)', () => {
) )
expect(category.value).toBe('checkpoints') expect(category.value).toBe('checkpoints')
expect(assets.value).toEqual(mockAssets) expect(assets.value).toEqual(mockAssets)
expect(assets.value).toHaveLength(2)
expect(dropdownItems.value).toHaveLength(2) expect(assets.value[0].id).toBe('asset-1')
const item = dropdownItems.value[0] expect(assets.value[0].name).toBe('Beautiful Model')
expect(item.id).toBe('asset-1') expect(assets.value[0].preview_url).toBe('/api/preview/asset-1')
expect(item.name).toBe('models/beautiful_model.safetensors')
expect(item.label).toBe('Beautiful Model')
expect(item.previewUrl).toBe('/api/preview/asset-1')
}) })
it('handles API errors gracefully', async () => { it('handles API errors gracefully', async () => {
@@ -238,7 +234,7 @@ describe('useAssetWidgetData (cloud mode, isCloud=true)', () => {
}) })
it('handles undefined node type gracefully', async () => { it('handles undefined node type gracefully', async () => {
const { category, assets, dropdownItems, isLoading, error } = const { category, assets, isLoading, error } =
useAssetWidgetData(undefined) useAssetWidgetData(undefined)
await nextTick() await nextTick()
@@ -246,7 +242,6 @@ describe('useAssetWidgetData (cloud mode, isCloud=true)', () => {
expect(mockUpdateModelsForNodeType).not.toHaveBeenCalled() expect(mockUpdateModelsForNodeType).not.toHaveBeenCalled()
expect(category.value).toBeUndefined() expect(category.value).toBeUndefined()
expect(assets.value).toEqual([]) expect(assets.value).toEqual([])
expect(dropdownItems.value).toEqual([])
expect(isLoading.value).toBe(false) expect(isLoading.value).toBe(false)
expect(error.value).toBeNull() expect(error.value).toBeNull()
}) })

View File

@@ -2,8 +2,6 @@ import { computed, toValue, watch } from 'vue'
import type { MaybeRefOrGetter } from 'vue' import type { MaybeRefOrGetter } from 'vue'
import type { AssetItem } from '@/platform/assets/schemas/assetSchema' import type { AssetItem } from '@/platform/assets/schemas/assetSchema'
import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes'
import { toAssetDropdownItem } from '@/platform/assets/utils/assetDropdownUtils'
import { isCloud } from '@/platform/distribution/types' import { isCloud } from '@/platform/distribution/types'
import { useAssetsStore } from '@/stores/assetsStore' import { useAssetsStore } from '@/stores/assetsStore'
import { useModelToNodeStore } from '@/stores/modelToNodeStore' import { useModelToNodeStore } from '@/stores/modelToNodeStore'
@@ -48,10 +46,6 @@ export function useAssetWidgetData(
return resolvedType ? (assetsStore.getError(resolvedType) ?? null) : null return resolvedType ? (assetsStore.getError(resolvedType) ?? null) : null
}) })
const dropdownItems = computed<AssetDropdownItem[]>(() => {
return (assets.value ?? []).map(toAssetDropdownItem)
})
watch( watch(
() => toValue(nodeType), () => toValue(nodeType),
async (currentNodeType) => { async (currentNodeType) => {
@@ -72,7 +66,6 @@ export function useAssetWidgetData(
return { return {
category, category,
assets, assets,
dropdownItems,
isLoading, isLoading,
error error
} }
@@ -80,8 +73,7 @@ export function useAssetWidgetData(
return { return {
category: computed(() => undefined), category: computed(() => undefined),
assets: computed(() => []), assets: computed<AssetItem[]>(() => []),
dropdownItems: computed(() => []),
isLoading: computed(() => false), isLoading: computed(() => false),
error: computed(() => null) error: computed(() => null)
} }