diff --git a/src/locales/en/main.json b/src/locales/en/main.json index 1928f2472..c8b6acbd1 100644 --- a/src/locales/en/main.json +++ b/src/locales/en/main.json @@ -2506,6 +2506,7 @@ "imported": "Imported", "assetCollection": "Asset collection", "assets": "Assets", + "baseModel": "Base model", "baseModels": "Base models", "browseAssets": "Browse Assets", "checkpoints": "Checkpoints", diff --git a/src/platform/assets/types/filterTypes.ts b/src/platform/assets/types/filterTypes.ts index 4d5672e1a..514dfd9ce 100644 --- a/src/platform/assets/types/filterTypes.ts +++ b/src/platform/assets/types/filterTypes.ts @@ -3,17 +3,12 @@ * Shared across AssetBrowser, AssetFilterBar, and widget dropdowns */ -/** - * Generic option identifier type - */ -export type OptionId = string - /** * Generic filter/select option used across components * Compatible with both SelectOption (name/value) and FilterOption (id/name) patterns */ export interface FilterOption { - id: OptionId + id: string name: string } diff --git a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue index 6b19d46df..020fa508c 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/WidgetSelectDropdown.vue @@ -5,6 +5,7 @@ import { computed, provide, ref, toRef, watch } from 'vue' import { useTransformCompatOverlayProps } from '@/composables/useTransformCompatOverlayProps' import { t } from '@/i18n' import { + getAssetBaseModels, getAssetDisplayName, getAssetFilename } from '@/platform/assets/utils/assetMetadataUtils' @@ -12,7 +13,6 @@ import { useToastStore } from '@/platform/updates/common/toastStore' import FormDropdown from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue' import type { FilterOption, - OptionId, OwnershipOption } from '@/platform/assets/types/filterTypes' import { AssetKindKey } from '@/renderer/extensions/vueNodes/widgets/components/form/dropdown/types' @@ -99,7 +99,22 @@ const ownershipOptions = computed(() => [ } ]) -const selectedSet = ref>(new Set()) +const baseModelSelected = ref>(new Set()) +const showBaseModelFilter = computed(() => props.isAssetMode) +const baseModelOptions = computed(() => { + if (!props.isAssetMode || !assetData) return [] + const models = new Set() + for (const asset of assetData.assets.value) { + for (const model of getAssetBaseModels(asset)) { + models.add(model) + } + } + return Array.from(models) + .sort() + .map((model) => ({ id: model, name: model })) +}) + +const selectedSet = ref>(new Set()) /** * Transforms a value using getOptionLabel if available. @@ -222,7 +237,8 @@ const assetItems = computed(() => { name: getAssetFilename(asset), label: getAssetDisplayName(asset), preview_url: asset.preview_url, - is_immutable: asset.is_immutable + is_immutable: asset.is_immutable, + base_models: getAssetBaseModels(asset) })) }) @@ -235,12 +251,23 @@ const ownershipFilteredAssetItems = computed(() => { return assetItems.value.filter((item) => item.is_immutable === isPublic) }) +/** + * Filters asset items by base model selection. + */ +const baseModelFilteredAssetItems = computed(() => { + if (baseModelSelected.value.size === 0) + return ownershipFilteredAssetItems.value + return ownershipFilteredAssetItems.value.filter((item) => + item.base_models?.some((model) => baseModelSelected.value.has(model)) + ) +}) + const allItems = computed(() => { if (props.isAssetMode && assetData) { if (missingValueItem.value) { - return [missingValueItem.value, ...ownershipFilteredAssetItems.value] + return [missingValueItem.value, ...baseModelFilteredAssetItems.value] } - return ownershipFilteredAssetItems.value + return baseModelFilteredAssetItems.value } return [ ...(missingValueItem.value ? [missingValueItem.value] : []), @@ -327,8 +354,8 @@ watch( { immediate: true } ) -function updateSelectedItems(selectedItems: Set) { - let id: OptionId | undefined = undefined +function updateSelectedItems(selectedItems: Set) { + let id: string | undefined = undefined if (selectedItems.size > 0) { id = selectedItems.values().next().value! } @@ -436,6 +463,7 @@ function getMediaUrl( v-model:filter-selected="filterSelected" v-model:layout-mode="layoutMode" v-model:ownership-selected="ownershipSelected" + v-model:base-model-selected="baseModelSelected" :items="dropdownItems" :placeholder="mediaPlaceholder" :multiple="false" @@ -444,6 +472,8 @@ function getMediaUrl( :filter-options :show-ownership-filter :ownership-options + :show-base-model-filter + :base-model-options v-bind="combinedProps" class="w-full" @update:selected="updateSelectedItems" 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 5a10988ba..314b17fa6 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdown.vue @@ -7,7 +7,6 @@ import { useToastStore } from '@/platform/updates/common/toastStore' import type { FilterOption, - OptionId, OwnershipFilterOption, OwnershipOption } from '@/platform/assets/types/filterTypes' @@ -33,8 +32,10 @@ interface Props { sortOptions?: SortOption[] showOwnershipFilter?: boolean ownershipOptions?: OwnershipFilterOption[] + showBaseModelFilter?: boolean + baseModelOptions?: FilterOption[] isSelected?: ( - selected: Set, + selected: Set, item: FormDropdownItem, index: number ) => boolean @@ -56,11 +57,11 @@ const props = withDefaults(defineProps(), { searcher: defaultSearcher }) -const selected = defineModel>('selected', { +const selected = defineModel>('selected', { default: new Set() }) -const filterSelected = defineModel('filterSelected', { default: '' }) -const sortSelected = defineModel('sortSelected', { +const filterSelected = defineModel('filterSelected', { default: '' }) +const sortSelected = defineModel('sortSelected', { default: 'default' }) const layoutMode = defineModel('layoutMode', { @@ -71,6 +72,9 @@ const searchQuery = defineModel('searchQuery', { default: '' }) const ownershipSelected = defineModel('ownershipSelected', { default: 'all' }) +const baseModelSelected = defineModel>('baseModelSelected', { + default: new Set() +}) const toastStore = useToastStore() const popoverRef = ref>() @@ -210,10 +214,13 @@ async function customSearcher( v-model:sort-selected="sortSelected" v-model:search-query="searchQuery" v-model:ownership-selected="ownershipSelected" + v-model:base-model-selected="baseModelSelected" :filter-options :sort-options :show-ownership-filter :ownership-options + :show-base-model-filter + :base-model-options :disabled :searcher="customSearcher" :items="sortedItems" 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 4cbbce654..e8e5b21bf 100644 --- a/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownInput.vue +++ b/src/renderer/extensions/vueNodes/widgets/components/form/dropdown/FormDropdownInput.vue @@ -1,7 +1,6 @@