fix: address review comments and improve reset parameters

- Use named import { isEqual } from es-toolkit instead of default compat import
- Use WidgetValue type consistently in WidgetItem setter
- Remove unnecessary code comment in SectionWidgets
- Extract writeWidgetValue helper to reduce duplication
- Fix reset-all button visibility to show whenever widgets exist
- Add unit tests for getWidgetDefaultValue utility

Amp-Thread-ID: https://ampcode.com/threads/T-019c35dc-c58d-7198-8c31-cedd3ffeadac
This commit is contained in:
bymyself
2026-02-06 18:17:50 -08:00
parent cdd77c4a9d
commit 312b380c92
4 changed files with 59 additions and 14 deletions

View File

@@ -63,18 +63,21 @@ const { t } = useI18n()
const getNodeParentGroup = inject(GetNodeParentGroupKey, null)
function writeWidgetValue(widget: IBaseWidget, value: WidgetValue) {
widget.value = value
widget.callback?.(value)
canvasStore.canvas?.setDirty(true, true)
}
function handleResetAllWidgets() {
for (const { widget, node: widgetNode } of widgetsProp) {
const spec = nodeDefStore.getInputSpecForWidget(widgetNode, widget.name)
const defaultValue = getWidgetDefaultValue(spec)
if (defaultValue !== undefined) {
// Ensure Vue reactivity is set up for this widget before updating
getSharedWidgetEnhancements(widgetNode, widget)
widget.value = defaultValue
widget.callback?.(defaultValue)
writeWidgetValue(widget, defaultValue)
}
}
canvasStore.canvas?.setDirty(true, true)
}
function isWidgetShownOnParents(
@@ -136,9 +139,7 @@ function handleLocateNode() {
function handleWidgetValueUpdate(widget: IBaseWidget, newValue: WidgetValue) {
if (newValue === undefined) return
widget.value = newValue
widget.callback?.(newValue)
canvasStore.canvas?.setDirty(true, true)
writeWidgetValue(widget, newValue)
}
function handleWidgetReset(
@@ -147,9 +148,7 @@ function handleWidgetReset(
newValue: WidgetValue
) {
getSharedWidgetEnhancements(widgetNode, widget)
widget.value = newValue
widget.callback?.(newValue)
canvasStore.canvas?.setDirty(true, true)
writeWidgetValue(widget, newValue)
}
defineExpose({
@@ -183,7 +182,7 @@ defineExpose({
</span>
</span>
<Button
v-if="canShowLocateButton"
v-if="!isEmpty"
variant="textonly"
size="icon-sm"
class="subbutton shrink-0 size-8 cursor-pointer text-muted-foreground hover:text-base-foreground"

View File

@@ -1,6 +1,6 @@
<script setup lang="ts">
import { cn } from '@comfyorg/tailwind-utils'
import _ from 'es-toolkit/compat'
import { isEqual } from 'es-toolkit'
import { computed } from 'vue'
import { useI18n } from 'vue-i18n'
@@ -62,7 +62,7 @@ const hasDefault = computed(() => defaultValue.value !== undefined)
const isCurrentValueDefault = computed(() => {
if (!hasDefault.value) return true
return _.isEqual(widget.value, defaultValue.value)
return isEqual(widget.value, defaultValue.value)
})
async function handleRename() {

View File

@@ -88,7 +88,7 @@ const widgetValue = computed({
widget.vueTrack?.()
return widget.value
},
set: (newValue: string | number | boolean | object) => {
set: (newValue: WidgetValue) => {
emit('update:widgetValue', newValue)
}
})

View File

@@ -0,0 +1,46 @@
import { describe, expect, it } from 'vitest'
import type { InputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
import { getWidgetDefaultValue } from '@/utils/widgetUtil'
describe('getWidgetDefaultValue', () => {
it('returns undefined for undefined spec', () => {
expect(getWidgetDefaultValue(undefined)).toBeUndefined()
})
it('returns explicit default when provided', () => {
const spec = { type: 'INT', default: 42 } as InputSpec
expect(getWidgetDefaultValue(spec)).toBe(42)
})
it('returns 0 for INT type without default', () => {
const spec = { type: 'INT' } as InputSpec
expect(getWidgetDefaultValue(spec)).toBe(0)
})
it('returns 0 for FLOAT type without default', () => {
const spec = { type: 'FLOAT' } as InputSpec
expect(getWidgetDefaultValue(spec)).toBe(0)
})
it('returns false for BOOLEAN type without default', () => {
const spec = { type: 'BOOLEAN' } as InputSpec
expect(getWidgetDefaultValue(spec)).toBe(false)
})
it('returns empty string for STRING type without default', () => {
const spec = { type: 'STRING' } as InputSpec
expect(getWidgetDefaultValue(spec)).toBe('')
})
it('returns first option for array options without default', () => {
const spec = { type: 'COMBO', options: ['a', 'b', 'c'] } as InputSpec
expect(getWidgetDefaultValue(spec)).toBe('a')
})
it('returns undefined for unknown type without options', () => {
const spec = { type: 'CUSTOM' } as InputSpec
expect(getWidgetDefaultValue(spec)).toBeUndefined()
})
})