Compare commits

...

5 Commits

Author SHA1 Message Date
GitHub Action
9c15cb5860 [automated] Apply ESLint and Prettier fixes 2025-11-03 02:34:46 +00:00
Christian Byrne
975f45842c refactor: use placeholder to display deserialized values instead of modifying options
Simplified the approach to show deserialized workflow values that are not in
the current options list. Instead of adding missing values to the options array,
we now display them as the placeholder text. This is cleaner, avoids array
manipulation, and addresses performance concerns from code review.
2025-11-02 18:27:27 -08:00
GitHub Action
266b09f7e0 [automated] Apply ESLint and Prettier fixes 2025-11-02 21:32:50 +00:00
Christian Byrne
ad1cdf4a48 fix: add explicit type annotation to fix TS7006 error 2025-11-02 13:30:21 -08:00
Christian Byrne
c92123aece [bugfix] Fix Vue nodes combo widgets not displaying deserialized values
Fixes an issue where combo widgets in Vue nodes would not display values
from deserialized workflows if those values were not in the current options
list (e.g., deleted model files, removed checkpoints). This brings Vue nodes
behavior in line with legacy canvas rendering, which always displays the
current value regardless of whether it exists in the options.
2025-11-02 09:54:47 -08:00
3 changed files with 69 additions and 0 deletions

View File

@@ -179,6 +179,42 @@ describe('WidgetSelect Value Binding', () => {
expect(emitted).toBeDefined()
expect(emitted![0]).toContain('100')
})
it('displays value not in options list as placeholder (deserialized workflow value)', async () => {
// Simulate a workflow loaded with a value that's no longer in the options
// (e.g., a deleted model file)
const currentOptions = ['model1.ckpt', 'model2.safetensors']
const deserializedValue = 'old_deleted_model.ckpt'
const widget = createMockWidget(deserializedValue, {
values: currentOptions
})
const wrapper = mountComponent(widget, deserializedValue)
const select = wrapper.findComponent({ name: 'Select' })
// The deserialized value should be shown as the placeholder
expect(select.props('placeholder')).toBe(deserializedValue)
// The options should remain unchanged (not include the deserialized value)
const options = select.props('options')
expect(options).not.toContain(deserializedValue)
expect(options).toContain('model1.ckpt')
expect(options).toContain('model2.safetensors')
})
it('uses widget placeholder when value exists in options', async () => {
const options = ['option1', 'option2', 'option3']
const widget = createMockWidget('option2', {
values: options,
placeholder: 'Select an option'
})
const wrapper = mountComponent(widget, 'option2')
const select = wrapper.findComponent({ name: 'Select' })
// Should use the widget's placeholder since value is in options
expect(select.props('placeholder')).toBe('Select an option')
})
})
describe('Spec-aware rendering', () => {

View File

@@ -3,6 +3,7 @@
<Select
v-model="localValue"
:options="selectOptions"
:placeholder="selectPlaceholder"
v-bind="combinedProps"
:class="cn(WidgetInputBaseClass, 'w-full text-xs')"
:aria-label="widget.name"
@@ -68,4 +69,22 @@ const selectOptions = computed(() => {
return []
})
// Show the deserialized value as placeholder when it's not in the options list
// This preserves legacy behavior where workflow values are shown even if deleted
const selectPlaceholder = computed(() => {
const currentValue = localValue.value
// If there's a current value and it's not in the options, show it as placeholder
if (
currentValue != null &&
currentValue !== '' &&
!selectOptions.value.includes(currentValue)
) {
return String(currentValue)
}
// Otherwise use the default placeholder from options
return props.widget.options?.placeholder
})
</script>

View File

@@ -128,6 +128,20 @@ const dropdownItems = computed<DropdownItem[]>(() => {
})
const mediaPlaceholder = computed(() => {
const currentValue = localValue.value
const values = props.widget.options?.values || []
// If there's a current value and it's not in the options, show it as placeholder
// This preserves legacy behavior where workflow values are shown even if deleted
if (
currentValue != null &&
currentValue !== '' &&
typeof currentValue === 'string' &&
!values.includes(currentValue)
) {
return currentValue
}
const options = props.widget.options
if (options?.placeholder) {