-
Notifications
You must be signed in to change notification settings - Fork 407
[bugfix] Fix Vue nodes combo widgets not displaying deserialized values #6545
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 3 commits
c92123a
ad1cdf4
266b09f
975f458
9c15cb5
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 |
|---|---|---|
| @@ -0,0 +1,117 @@ | ||
| import { describe, expect, it } from 'vitest' | ||
|
|
||
| import { ensureValueInOptions } from './widgetOptionsUtils' | ||
|
|
||
| describe('ensureValueInOptions', () => { | ||
| describe('when value exists in options', () => { | ||
| it('returns original options without duplicates', () => { | ||
| const options = ['option1', 'option2', 'option3'] | ||
| const result = ensureValueInOptions(options, 'option2') | ||
|
|
||
| expect(result).toEqual(options) | ||
| expect(result).toHaveLength(3) | ||
| }) | ||
|
|
||
| it('handles first option', () => { | ||
| const options = ['first', 'second', 'third'] | ||
| const result = ensureValueInOptions(options, 'first') | ||
|
|
||
| expect(result).toEqual(options) | ||
| }) | ||
|
|
||
| it('handles last option', () => { | ||
| const options = ['first', 'second', 'third'] | ||
| const result = ensureValueInOptions(options, 'third') | ||
|
|
||
| expect(result).toEqual(options) | ||
| }) | ||
| }) | ||
|
|
||
| describe('when value is missing from options', () => { | ||
| it('prepends missing value to options array', () => { | ||
| const options = ['option1', 'option2', 'option3'] | ||
| const result = ensureValueInOptions(options, 'deleted_model.safetensors') | ||
|
|
||
| expect(result).toEqual([ | ||
| 'deleted_model.safetensors', | ||
| 'option1', | ||
| 'option2', | ||
| 'option3' | ||
| ]) | ||
| expect(result).toHaveLength(4) | ||
| }) | ||
|
|
||
| it('preserves deserialized workflow values', () => { | ||
| const options = ['current_model.ckpt'] | ||
| const oldValue = 'old_model_from_workflow.ckpt' | ||
| const result = ensureValueInOptions(options, oldValue) | ||
|
|
||
| expect(result[0]).toBe(oldValue) | ||
| expect(result).toContain('current_model.ckpt') | ||
| }) | ||
|
|
||
| it('handles numeric values', () => { | ||
| const options = [1, 2, 3] | ||
| const result = ensureValueInOptions(options, 99) | ||
|
|
||
| expect(result).toEqual([99, 1, 2, 3]) | ||
| }) | ||
|
||
| }) | ||
|
|
||
| describe('when value is null or empty', () => { | ||
| it('returns original options for undefined', () => { | ||
| const options = ['option1', 'option2'] | ||
| const result = ensureValueInOptions(options, undefined) | ||
|
|
||
| expect(result).toEqual(options) | ||
| }) | ||
|
|
||
| it('returns original options for null', () => { | ||
| const options = ['option1', 'option2'] | ||
| const result = ensureValueInOptions(options, null) | ||
|
|
||
| expect(result).toEqual(options) | ||
| }) | ||
|
|
||
| it('returns original options for empty string', () => { | ||
| const options = ['option1', 'option2'] | ||
| const result = ensureValueInOptions(options, '') | ||
|
|
||
| expect(result).toEqual(options) | ||
| }) | ||
| }) | ||
|
|
||
| describe('edge cases', () => { | ||
| it('handles empty options array', () => { | ||
| const result = ensureValueInOptions([], 'some_value') | ||
|
|
||
| expect(result).toEqual(['some_value']) | ||
| }) | ||
|
|
||
| it('handles options with special characters', () => { | ||
| const options = ['normal.txt', 'with spaces.png', 'special@#$.jpg'] | ||
| const result = ensureValueInOptions( | ||
| options, | ||
| 'another file with spaces.png' | ||
| ) | ||
|
|
||
| expect(result[0]).toBe('another file with spaces.png') | ||
| expect(result).toHaveLength(4) | ||
| }) | ||
|
|
||
| it('creates new array instance (does not mutate input)', () => { | ||
| const options = ['option1', 'option2'] | ||
| const result = ensureValueInOptions(options, 'option1') | ||
|
|
||
| expect(result).not.toBe(options) | ||
| expect(result).toEqual(options) | ||
| }) | ||
|
|
||
| it('handles readonly arrays', () => { | ||
| const options = ['a', 'b', 'c'] as const | ||
| const result = ensureValueInOptions(options, 'd') | ||
|
|
||
| expect(result).toEqual(['d', 'a', 'b', 'c']) | ||
| }) | ||
| }) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| /** | ||
| * Utility functions for widget option handling | ||
| */ | ||
|
|
||
| /** | ||
| * Ensures the current value is included in the options array. | ||
| * This preserves legacy behavior where deserialized workflow values | ||
| * can be shown even if they're not in the current options list | ||
| * (e.g., deleted models, removed files, etc.) | ||
| * | ||
| * @param options - The available options from widget.options.values | ||
| * @param currentValue - The current widget value | ||
| * @returns Options array with current value prepended if missing | ||
| */ | ||
| export function ensureValueInOptions<T extends string | number>( | ||
| options: readonly T[], | ||
| currentValue: T | undefined | null | ||
| ): T[] { | ||
| // Early return for empty/null values | ||
| if (currentValue == null || currentValue === '') { | ||
|
||
| return [...options] | ||
|
||
| } | ||
|
|
||
| // If value already exists, return original options | ||
| if (options.includes(currentValue)) { | ||
| return [...options] | ||
| } | ||
|
|
||
| // Prepend missing value to options | ||
| return [currentValue, ...options] | ||
| } | ||
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.
[quality] low Priority
Issue: Type annotation added for TS7006 fix but inconsistent application across codebase
Context: The recent fix added explicit type annotation 'as string[]' but this pattern should be consistent with other similar lines in the file
Suggestion: Consider applying the same type annotation pattern to line 211 'selectOptions.filter((opt: string) => opt === "option2")' for consistency