diff --git a/src/platform/assets/types/assetDropdownTypes.ts b/src/platform/assets/types/assetDropdownTypes.ts deleted file mode 100644 index 216b21fc8..000000000 --- a/src/platform/assets/types/assetDropdownTypes.ts +++ /dev/null @@ -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 -} diff --git a/src/platform/assets/utils/assetDropdownUtils.ts b/src/platform/assets/utils/assetDropdownUtils.ts deleted file mode 100644 index 9b30a9daf..000000000 --- a/src/platform/assets/utils/assetDropdownUtils.ts +++ /dev/null @@ -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 ?? '' - } -} diff --git a/src/platform/assets/utils/assetSortUtils.ts b/src/platform/assets/utils/assetSortUtils.ts index a093d8854..76158ec06 100644 --- a/src/platform/assets/utils/assetSortUtils.ts +++ b/src/platform/assets/utils/assetSortUtils.ts @@ -7,7 +7,7 @@ import type { AssetSortOption } from '../types/filterTypes' /** * Minimal interface for sortable items - * Works with both AssetItem and AssetDropdownItem + * Works with both AssetItem and FormDropdownItem */ export interface SortableItem { name: string diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.test.ts b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.test.ts index 86b41e0e4..679aeb521 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.test.ts +++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.test.ts @@ -5,15 +5,15 @@ import PrimeVue from 'primevue/config' import type { ComponentPublicInstance } from 'vue' 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 { SimplifiedWidget } from '@/types/simplifiedWidget' import WidgetSelectDropdown from '@/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue' interface WidgetSelectDropdownInstance extends ComponentPublicInstance { - inputItems: AssetDropdownItem[] - outputItems: AssetDropdownItem[] + inputItems: FormDropdownItem[] + outputItems: FormDropdownItem[] updateSelectedItems: (selectedSet: Set) => void } @@ -231,7 +231,7 @@ describe('WidgetSelectDropdown custom label mapping', () => { // The missing value should be accessible via dropdownItems when filter is 'all' (default) const dropdownItems = ( - wrapper.vm as unknown as { dropdownItems: AssetDropdownItem[] } + wrapper.vm as unknown as { dropdownItems: FormDropdownItem[] } ).dropdownItems expect( dropdownItems.some((item) => item.name === 'template_image.png') @@ -248,7 +248,7 @@ describe('WidgetSelectDropdown custom label mapping', () => { const vmWithFilter = wrapper.vm as unknown as { filterSelected: string - dropdownItems: AssetDropdownItem[] + dropdownItems: FormDropdownItem[] } vmWithFilter.filterSelected = 'inputs' @@ -269,8 +269,8 @@ describe('WidgetSelectDropdown custom label mapping', () => { const vmWithFilter = wrapper.vm as unknown as { filterSelected: string - dropdownItems: AssetDropdownItem[] - outputItems: AssetDropdownItem[] + dropdownItems: FormDropdownItem[] + outputItems: FormDropdownItem[] } vmWithFilter.filterSelected = 'outputs' @@ -290,7 +290,7 @@ describe('WidgetSelectDropdown custom label mapping', () => { const wrapper = mountComponent(widget, 'img_001.png') const dropdownItems = ( - wrapper.vm as unknown as { dropdownItems: AssetDropdownItem[] } + wrapper.vm as unknown as { dropdownItems: FormDropdownItem[] } ).dropdownItems expect(dropdownItems).toHaveLength(2) expect( @@ -305,7 +305,7 @@ describe('WidgetSelectDropdown custom label mapping', () => { const wrapper = mountComponent(widget, undefined) const dropdownItems = ( - wrapper.vm as unknown as { dropdownItems: AssetDropdownItem[] } + wrapper.vm as unknown as { dropdownItems: FormDropdownItem[] } ).dropdownItems expect(dropdownItems).toHaveLength(2) expect( diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue index 4edb3c17b..0eec37d8e 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue @@ -4,15 +4,21 @@ import { computed, provide, ref, toRef, watch } from 'vue' import { useTransformCompatOverlayProps } from '@/composables/useTransformCompatOverlayProps' import { t } from '@/i18n' +import { + getAssetDisplayName, + getAssetFilename +} from '@/platform/assets/utils/assetMetadataUtils' import { useToastStore } from '@/platform/updates/common/toastStore' import FormDropdown from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue' -import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes' import type { FilterOption, OptionId } from '@/platform/assets/types/filterTypes' -import { AssetKindKey } from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/types'; -import type { LayoutMode } from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/types'; +import { AssetKindKey } 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 { useAssetWidgetData } from '@/renderer/extensions/vueNodes/widgets/composables/useAssetWidgetData' import type { ResultItemType } from '@/schemas/apiSchema' @@ -100,7 +106,7 @@ function getDisplayLabel(value: string): string { } } -const inputItems = computed(() => { +const inputItems = computed(() => { const values = props.widget.options?.values || [] if (!Array.isArray(values)) { @@ -109,12 +115,12 @@ const inputItems = computed(() => { return values.map((value: string, index: number) => ({ id: `input-${index}`, - previewUrl: getMediaUrl(value, 'input'), + preview_url: getMediaUrl(value, 'input'), name: value, label: getDisplayLabel(value) })) }) -const outputItems = computed(() => { +const outputItems = computed(() => { if (!['image', 'video'].includes(props.assetKind ?? '')) return [] const outputs = new Set() @@ -139,7 +145,7 @@ const outputItems = computed(() => { return Array.from(outputs).map((output) => ({ id: `output-${output}`, - previewUrl: getMediaUrl(output.replace(' [output]', ''), 'output'), + preview_url: getMediaUrl(output.replace(' [output]', ''), 'output'), name: output, label: getDisplayLabel(output) })) @@ -151,20 +157,20 @@ const outputItems = computed(() => { * where the saved value may not exist in the current server environment. * Works for both local mode (inputItems/outputItems) and cloud mode (assetData). */ -const missingValueItem = computed(() => { +const missingValueItem = computed(() => { const currentValue = modelValue.value if (!currentValue) return undefined // Check in cloud mode assets if (props.isAssetMode && assetData) { - const existsInAssets = assetData.dropdownItems.value.some( - (item) => item.name === currentValue + const existsInAssets = assetData.assets.value.some( + (asset) => asset.name === currentValue ) if (existsInAssets) return undefined return { id: `missing-${currentValue}`, - previewUrl: '', + preview_url: '', name: currentValue, label: getDisplayLabel(currentValue) } @@ -187,19 +193,32 @@ const missingValueItem = computed(() => { return { id: `missing-${currentValue}`, - previewUrl: getMediaUrl(strippedValue, isOutput ? 'output' : 'input'), + preview_url: getMediaUrl(strippedValue, isOutput ? 'output' : 'input'), name: currentValue, label: getDisplayLabel(currentValue) } }) -const allItems = computed(() => { +/** + * Transforms AssetItem[] to FormDropdownItem[] for cloud mode. + * Uses getAssetFilename for display name, asset.name for label. + */ +const assetItems = computed(() => { + 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(() => { if (props.isAssetMode && assetData) { - const items = assetData.dropdownItems.value if (missingValueItem.value) { - return [missingValueItem.value, ...items] + return [missingValueItem.value, ...assetItems.value] } - return items + return assetItems.value } return [ ...(missingValueItem.value ? [missingValueItem.value] : []), @@ -208,7 +227,7 @@ const allItems = computed(() => { ] }) -const dropdownItems = computed(() => { +const dropdownItems = computed(() => { if (props.isAssetMode) { return allItems.value } diff --git a/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue b/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue index 8ff3ea5af..b7db9e6fb 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue @@ -5,7 +5,6 @@ import { computed, ref, useTemplateRef } from 'vue' import { t } from '@/i18n' import { useToastStore } from '@/platform/updates/common/toastStore' -import type { AssetDropdownItem } from '@/platform/assets/types/assetDropdownTypes' import type { FilterOption, OptionId @@ -14,10 +13,10 @@ import type { import FormDropdownInput from './FormDropdownInput.vue' import FormDropdownMenu from './FormDropdownMenu.vue' import { defaultSearcher, getDefaultSortOptions } from './shared' -import type { LayoutMode, SortOption } from './types' +import type { FormDropdownItem, LayoutMode, SortOption } from './types' interface Props { - items: AssetDropdownItem[] + items: FormDropdownItem[] placeholder?: string /** * If true, allows multiple selections. If a number is provided, @@ -32,14 +31,14 @@ interface Props { sortOptions?: SortOption[] isSelected?: ( selected: Set, - item: AssetDropdownItem, + item: FormDropdownItem, index: number ) => boolean searcher?: ( query: string, - items: AssetDropdownItem[], + items: FormDropdownItem[], onCleanup: (cleanupFn: () => void) => void - ) => Promise + ) => Promise } const props = withDefaults(defineProps(), { @@ -79,7 +78,7 @@ const maxSelectable = computed(() => { const itemsKey = computed(() => props.items.map((item) => item.id).join('|')) -const filteredItems = ref([]) +const filteredItems = ref([]) const defaultSorter = computed(() => { const sorter = props.sortOptions.find( @@ -98,7 +97,7 @@ const sortedItems = computed(() => { 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 } @@ -127,7 +126,7 @@ function handleFileChange(event: Event) { input.value = '' } -function handleSelection(item: AssetDropdownItem, index: number) { +function handleSelection(item: FormDropdownItem, index: number) { if (props.disabled) return const sel = selected.value if (internalIsSelected(item, index)) { diff --git a/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownInput.vue b/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownInput.vue index 2095ced2b..858e92c58 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownInput.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownInput.vue @@ -1,16 +1,16 @@