Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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>
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down