-
Notifications
You must be signed in to change notification settings - Fork 407
feat(ComboWidget): add ability to have mapped inputs #6585
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -194,20 +194,31 @@ function createAssetService() { | |
| /** | ||
| * Gets assets filtered by a specific tag | ||
| * | ||
| * @param tag - The tag to filter by (e.g., 'models') | ||
| * @param tag - The tag to filter by (e.g., 'models', 'input') | ||
| * @param includePublic - Whether to include public assets (default: true) | ||
| * @param options - Pagination options | ||
| * @param options.limit - Maximum number of assets to return (default: 500) | ||
| * @param options.offset - Number of assets to skip (default: 0) | ||
| * @returns Promise<AssetItem[]> - Full asset objects filtered by tag, excluding missing assets | ||
| */ | ||
| async function getAssetsByTag( | ||
| tag: string, | ||
| includePublic: boolean = true | ||
| includePublic: boolean = true, | ||
| { | ||
| limit = DEFAULT_LIMIT, | ||
| offset = 0 | ||
| }: { limit?: number; offset?: number } = {} | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We're not using pagination yet but, at least we're setup to start doing it.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hrmmmm...
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. i know yagni... but i think sooner is sooner than we think 😂 if you really want it removed, i can remove it. |
||
| ): Promise<AssetItem[]> { | ||
| const queryParams = new URLSearchParams({ | ||
| include_tags: tag, | ||
| limit: DEFAULT_LIMIT.toString(), | ||
| limit: limit.toString(), | ||
| include_public: includePublic ? 'true' : 'false' | ||
| }) | ||
|
|
||
| if (offset > 0) { | ||
| queryParams.set('offset', offset.toString()) | ||
| } | ||
|
|
||
| const data = await handleAssetRequest( | ||
| `${ASSETS_ENDPOINT}?${queryParams.toString()}`, | ||
| `assets for tag ${tag}` | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -11,6 +11,7 @@ import { | |||||||||||||||||||||||||||||||||||||||||||||||||
| assetItemSchema | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } from '@/platform/assets/schemas/assetSchema' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { assetService } from '@/platform/assets/services/assetService' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { isCloud } from '@/platform/distribution/types' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useSettingStore } from '@/platform/settings/settingStore' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { transformInputSpecV2ToV1 } from '@/schemas/nodeDef/migration' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { isComboInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2' | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -22,6 +23,8 @@ import { ComponentWidgetImpl, addWidget } from '@/scripts/domWidget' | |||||||||||||||||||||||||||||||||||||||||||||||||
| import type { BaseDOMWidget } from '@/scripts/domWidget' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { addValueControlWidgets } from '@/scripts/widgets' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import type { ComfyWidgetConstructorV2 } from '@/scripts/widgets' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useAssetsStore } from '@/stores/assetsStore' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| import { getMediaTypeFromFilename } from '@/utils/formatUtil' | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useRemoteWidget } from './useRemoteWidget' | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -32,6 +35,20 @@ const getDefaultValue = (inputSpec: ComboInputSpec) => { | |||||||||||||||||||||||||||||||||||||||||||||||||
| return undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Map node types to expected media types | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const NODE_MEDIA_TYPE_MAP: Record<string, 'image' | 'video' | 'audio'> = { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| LoadImage: 'image', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| LoadVideo: 'video', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| LoadAudio: 'audio' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Map node types to placeholder i18n keys | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const NODE_PLACEHOLDER_MAP: Record<string, string> = { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| LoadImage: 'widgets.uploadSelect.placeholderImage', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| LoadVideo: 'widgets.uploadSelect.placeholderVideo', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| LoadAudio: 'widgets.uploadSelect.placeholderAudio' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+39
to
+50
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Option:
Suggested change
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I will try this again but it cause some typecheck failure fun for me when i did it locally |
||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const addMultiSelectWidget = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node: LGraphNode, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec: ComboInputSpec | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -55,94 +72,176 @@ const addMultiSelectWidget = ( | |||||||||||||||||||||||||||||||||||||||||||||||||
| return widget | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const addComboWidget = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const createAssetBrowserWidget = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node: LGraphNode, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec: ComboInputSpec | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec: ComboInputSpec, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultValue: string | undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): IBaseWidget => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const settingStore = useSettingStore() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const isUsingAssetAPI = settingStore.get('Comfy.Assets.UseAssetAPI') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const isEligible = assetService.isAssetBrowserEligible( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node.comfyClass, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec.name | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentValue = defaultValue | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const displayLabel = currentValue ?? t('widgets.selectModel') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const assetBrowserDialog = useAssetBrowserDialog() | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const widget = node.addWidget( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'asset', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| displayLabel, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| async function (this: IBaseWidget) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isAssetWidget(widget)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Expected asset widget but received ${widget.type}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await assetBrowserDialog.show({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| nodeType: node.comfyClass || '', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputName: inputSpec.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| currentValue: widget.value, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| onAssetSelected: (asset) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const validatedAsset = assetItemSchema.safeParse(asset) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isUsingAssetAPI && isEligible) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const currentValue = getDefaultValue(inputSpec) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const displayLabel = currentValue ?? t('widgets.selectModel') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!validatedAsset.success) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Invalid asset item:', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedAsset.error.errors, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Received:', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| asset | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const assetBrowserDialog = useAssetBrowserDialog() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const filename = validatedAsset.data.user_metadata?.filename | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const validatedFilename = assetFilenameSchema.safeParse(filename) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const widget = node.addWidget( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'asset', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| displayLabel, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| async function (this: IBaseWidget) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isAssetWidget(widget)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Expected asset widget but received ${widget.type}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| await assetBrowserDialog.show({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| nodeType: node.comfyClass || '', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputName: inputSpec.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| currentValue: widget.value, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| onAssetSelected: (asset) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const validatedAsset = assetItemSchema.safeParse(asset) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!validatedAsset.success) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Invalid asset item:', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedAsset.error.errors, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Received:', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| asset | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const filename = validatedAsset.data.user_metadata?.filename | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const validatedFilename = assetFilenameSchema.safeParse(filename) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!validatedFilename.success) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Invalid asset filename:', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedFilename.error.errors, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'for asset:', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedAsset.data.id | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const oldValue = widget.value | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.value = validatedFilename.data | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node.onWidgetChanged?.( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| widget.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedFilename.data, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| oldValue, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| widget | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!validatedFilename.success) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| console.error( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'Invalid asset filename:', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedFilename.error.errors, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'for asset:', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedAsset.data.id | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const oldValue = widget.value | ||||||||||||||||||||||||||||||||||||||||||||||||||
| this.value = validatedFilename.data | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node.onWidgetChanged?.( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| widget.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| validatedFilename.data, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| oldValue, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| widget | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return widget | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const createInputMappingWidget = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node: LGraphNode, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec: ComboInputSpec, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultValue: string | undefined | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): IBaseWidget => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const assetsStore = useAssetsStore() | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const widget = node.addWidget( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'combo', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultValue ?? '', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| () => {}, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| values: [], | ||||||||||||||||||||||||||||||||||||||||||||||||||
| getOptionLabel: (value?: string | null) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!value) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const placeholderKey = | ||||||||||||||||||||||||||||||||||||||||||||||||||
| NODE_PLACEHOLDER_MAP[node.comfyClass ?? ''] ?? | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'widgets.uploadSelect.placeholder' | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return t(placeholderKey) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return assetsStore.getInputName(value) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return widget | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (assetsStore.inputAssets.length === 0 && !assetsStore.inputLoading) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| void assetsStore.updateInputs().then(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // edge for users using nodes with 0 prior inputs | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // force canvas refresh the first time they add an asset | ||||||||||||||||||||||||||||||||||||||||||||||||||
| // so they see filenames instead of hashes. | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node.setDirtyCanvas(true, false) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Create normal combo widget | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const origOptions = widget.options | ||||||||||||||||||||||||||||||||||||||||||||||||||
| widget.options = new Proxy(origOptions, { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| get(target, prop) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (prop !== 'values') { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return target[prop as keyof typeof target] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return assetsStore.inputAssets | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .filter( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| (asset) => | ||||||||||||||||||||||||||||||||||||||||||||||||||
| getMediaTypeFromFilename(asset.name) === | ||||||||||||||||||||||||||||||||||||||||||||||||||
| NODE_MEDIA_TYPE_MAP[node.comfyClass ?? ''] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .map((asset) => asset.asset_hash) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| .filter((hash): hash is string => !!hash) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (inputSpec.control_after_generate) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isComboWidget(widget)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Expected combo widget but received ${widget.type}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| widget.linkedWidgets = addValueControlWidgets( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| widget, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| undefined, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| transformInputSpecV2ToV1(inputSpec) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| return widget | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const addComboWidget = ( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node: LGraphNode, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec: ComboInputSpec | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ): IBaseWidget => { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const defaultValue = getDefaultValue(inputSpec) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const comboOptions = inputSpec.options ?? [] | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isCloud) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const settingStore = useSettingStore() | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const isUsingAssetAPI = settingStore.get('Comfy.Assets.UseAssetAPI') | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const isEligible = assetService.isAssetBrowserEligible( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node.comfyClass, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec.name | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (isUsingAssetAPI && isEligible) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return createAssetBrowserWidget(node, inputSpec, defaultValue) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (NODE_MEDIA_TYPE_MAP[node.comfyClass ?? '']) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| return createInputMappingWidget(node, inputSpec, defaultValue) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| // Standard combo widget | ||||||||||||||||||||||||||||||||||||||||||||||||||
| const widget = node.addWidget( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| 'combo', | ||||||||||||||||||||||||||||||||||||||||||||||||||
| inputSpec.name, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultValue, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| () => {}, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| values: comboOptions | ||||||||||||||||||||||||||||||||||||||||||||||||||
| values: inputSpec.options ?? [] | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| if (inputSpec.remote) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isComboWidget(widget)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Expected combo widget but received ${widget.type}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| const remoteWidget = useRemoteWidget({ | ||||||||||||||||||||||||||||||||||||||||||||||||||
| remoteConfig: inputSpec.remote, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| defaultValue, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -166,6 +265,7 @@ const addComboWidget = ( | |||||||||||||||||||||||||||||||||||||||||||||||||
| if (!isComboWidget(widget)) { | ||||||||||||||||||||||||||||||||||||||||||||||||||
| throw new Error(`Expected combo widget but received ${widget.type}`) | ||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
| widget.linkedWidgets = addValueControlWidgets( | ||||||||||||||||||||||||||||||||||||||||||||||||||
| node, | ||||||||||||||||||||||||||||||||||||||||||||||||||
| widget, | ||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: one of the downsides of this approach is we don't get the fuzzy search filter because that requires setting the array directly.
Talked it over with @AustinMroz and we do think this is the easiest way to map duplicate labels to the correct value