mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-05-23 22:25:05 +00:00
refactor(schema): flatten CHART/GALLERIA V2 specs + add input type guards
Extend the FE-800 flattening (COLOR/TEXTAREA/MARKDOWN) to the two
remaining widgets that carried a nested `options` bag, and add the
missing type guards so every widget composable narrows through a
discriminated check instead of a bare type assertion.
- nodeDefSchemaV2:
- zChartInputSpec: hoist nested options.{type,data} to top-level
`chartType` + `data` (rename avoids collision with the discriminator
`type: 'CHART'`).
- zGalleriaInputSpec: hoist nested options.images to top-level
`images`.
- Add `isColorInputSpec`, `isTextareaInputSpec`, `isGalleriaInputSpec`
— matches the existing INT/FLOAT/BOOLEAN/STRING/COMBO/CHART guards.
- Drop unused public exports for ChartInputSpec/GalleriaInputSpec/
TextareaInputSpec; they are now only referenced by their own
guards, matching the IntInputSpec/FloatInputSpec pattern.
- useColorWidget, useTextareaWidget, useGalleriaWidget, useChartWidget:
gate on the type guard up front instead of casting `as XInputSpec`;
read all spec fields at the top level.
- WidgetChart: replace `NonNullable<ChartInputSpec['options']>` type
derivation with an explicit local ChartWidgetOptions; the schema no
longer surfaces an `options` field.
Amp-Thread-ID: https://ampcode.com/threads/T-019e5168-0c71-7667-b1df-683cd9f8acf7
Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
@@ -5,14 +5,14 @@ import { defineComponent, nextTick, ref } from 'vue'
|
||||
import { createI18n } from 'vue-i18n'
|
||||
|
||||
import type { IWidgetOptions } from '@/lib/litegraph/src/types/widgets'
|
||||
import type { ChartInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
|
||||
import WidgetChart from './WidgetChart.vue'
|
||||
import { createMockWidget } from './widgetTestUtils'
|
||||
|
||||
type ChartWidgetOptions = NonNullable<ChartInputSpec['options']> &
|
||||
IWidgetOptions
|
||||
type ChartWidgetOptions = IWidgetOptions & {
|
||||
type?: 'bar' | 'line'
|
||||
}
|
||||
|
||||
const i18n = createI18n({
|
||||
legacy: false,
|
||||
|
||||
@@ -17,11 +17,11 @@ import Chart from 'primevue/chart'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import type { IWidgetOptions } from '@/lib/litegraph/src/types/widgets'
|
||||
import type { ChartInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { SimplifiedWidget } from '@/types/simplifiedWidget'
|
||||
|
||||
type ChartWidgetOptions = NonNullable<ChartInputSpec['options']> &
|
||||
IWidgetOptions
|
||||
type ChartWidgetOptions = IWidgetOptions & {
|
||||
type?: 'bar' | 'line'
|
||||
}
|
||||
|
||||
const value = defineModel<ChartData>({ required: true })
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import type { IChartWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import { isChartInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type {
|
||||
ChartInputSpec,
|
||||
InputSpec as InputSpecV2
|
||||
} from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { InputSpec as InputSpecV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { ComfyWidgetConstructorV2 } from '@/scripts/widgets'
|
||||
|
||||
export const useChartWidget = (): ComfyWidgetConstructorV2 => {
|
||||
@@ -13,14 +10,13 @@ export const useChartWidget = (): ComfyWidgetConstructorV2 => {
|
||||
throw new Error('Invalid input spec for chart widget')
|
||||
}
|
||||
|
||||
const { name, options = {} } = inputSpec as ChartInputSpec
|
||||
const { name, chartType = 'line', data = {} } = inputSpec
|
||||
|
||||
const chartType = options.type || 'line'
|
||||
const widgetOptions = { type: chartType }
|
||||
|
||||
const widget = node.addWidget('chart', name, options.data || {}, () => {}, {
|
||||
const widget = node.addWidget('chart', name, data, () => {}, {
|
||||
serialize: true,
|
||||
type: chartType,
|
||||
...options
|
||||
...widgetOptions
|
||||
}) as IChartWidget
|
||||
|
||||
return widget
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import type { IColorWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import type {
|
||||
ColorInputSpec,
|
||||
InputSpec as InputSpecV2
|
||||
} from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import { isColorInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { InputSpec as InputSpecV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { ComfyWidgetConstructorV2 } from '@/scripts/widgets'
|
||||
|
||||
export const useColorWidget = (): ComfyWidgetConstructorV2 => {
|
||||
return (node: LGraphNode, inputSpec: InputSpecV2): IColorWidget => {
|
||||
const { name, default: defaultValue = '#000000' } =
|
||||
inputSpec as ColorInputSpec
|
||||
if (!isColorInputSpec(inputSpec)) {
|
||||
throw new Error('Invalid input spec for color widget')
|
||||
}
|
||||
|
||||
const { name, default: defaultValue = '#000000' } = inputSpec
|
||||
|
||||
const widget = node.addWidget('color', name, defaultValue, () => {}, {
|
||||
serialize: true
|
||||
|
||||
@@ -1,25 +1,20 @@
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import type { IGalleriaWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import type {
|
||||
GalleriaInputSpec,
|
||||
InputSpec as InputSpecV2
|
||||
} from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import { isGalleriaInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { InputSpec as InputSpecV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { ComfyWidgetConstructorV2 } from '@/scripts/widgets'
|
||||
|
||||
export const useGalleriaWidget = (): ComfyWidgetConstructorV2 => {
|
||||
return (node: LGraphNode, inputSpec: InputSpecV2): IGalleriaWidget => {
|
||||
const { name, options = {} } = inputSpec as GalleriaInputSpec
|
||||
if (!isGalleriaInputSpec(inputSpec)) {
|
||||
throw new Error('Invalid input spec for galleria widget')
|
||||
}
|
||||
|
||||
const widget = node.addWidget(
|
||||
'galleria',
|
||||
name,
|
||||
options.images || [],
|
||||
() => {},
|
||||
{
|
||||
serialize: true,
|
||||
...options
|
||||
}
|
||||
) as IGalleriaWidget
|
||||
const { name, images = [] } = inputSpec
|
||||
|
||||
const widget = node.addWidget('galleria', name, images, () => {}, {
|
||||
serialize: true
|
||||
}) as IGalleriaWidget
|
||||
|
||||
return widget
|
||||
}
|
||||
|
||||
@@ -1,20 +1,19 @@
|
||||
import type { LGraphNode } from '@/lib/litegraph/src/litegraph'
|
||||
import type { ITextareaWidget } from '@/lib/litegraph/src/types/widgets'
|
||||
import type {
|
||||
InputSpec as InputSpecV2,
|
||||
TextareaInputSpec
|
||||
} from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import { isTextareaInputSpec } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { InputSpec as InputSpecV2 } from '@/schemas/nodeDef/nodeDefSchemaV2'
|
||||
import type { ComfyWidgetConstructorV2 } from '@/scripts/widgets'
|
||||
|
||||
export const useTextareaWidget = (): ComfyWidgetConstructorV2 => {
|
||||
return (node: LGraphNode, inputSpec: InputSpecV2): ITextareaWidget => {
|
||||
const textareaSpec = inputSpec as TextareaInputSpec
|
||||
const { name, default: defaultValue = '' } = textareaSpec
|
||||
const widgetOptions = {
|
||||
rows: textareaSpec.rows ?? 5,
|
||||
cols: textareaSpec.cols ?? 50
|
||||
if (!isTextareaInputSpec(inputSpec)) {
|
||||
throw new Error('Invalid input spec for textarea widget')
|
||||
}
|
||||
|
||||
const { name, default: defaultValue = '', rows = 5, cols = 50 } = inputSpec
|
||||
|
||||
const widgetOptions = { rows, cols }
|
||||
|
||||
const widget = node.addWidget('textarea', name, defaultValue, () => {}, {
|
||||
serialize: true,
|
||||
...widgetOptions
|
||||
|
||||
@@ -87,23 +87,15 @@ const zChartInputSpec = zBaseInputOptions.extend({
|
||||
type: z.literal('CHART'),
|
||||
name: z.string(),
|
||||
isOptional: z.boolean().optional(),
|
||||
options: z
|
||||
.object({
|
||||
type: z.enum(['bar', 'line']).optional(),
|
||||
data: z.object({}).optional()
|
||||
})
|
||||
.optional()
|
||||
chartType: z.enum(['bar', 'line']).optional(),
|
||||
data: z.object({}).optional()
|
||||
})
|
||||
|
||||
const zGalleriaInputSpec = zBaseInputOptions.extend({
|
||||
type: z.literal('GALLERIA'),
|
||||
name: z.string(),
|
||||
isOptional: z.boolean().optional(),
|
||||
options: z
|
||||
.object({
|
||||
images: z.array(z.string()).optional()
|
||||
})
|
||||
.optional()
|
||||
images: z.array(z.string()).optional()
|
||||
})
|
||||
|
||||
const zTextareaInputSpec = zBaseInputOptions.extend({
|
||||
@@ -211,9 +203,9 @@ export type ComboInputSpec = z.infer<typeof zComboInputSpec>
|
||||
export type ColorInputSpec = z.infer<typeof zColorInputSpec>
|
||||
export type ImageCompareInputSpec = z.infer<typeof zImageCompareInputSpec>
|
||||
export type BoundingBoxInputSpec = z.infer<typeof zBoundingBoxInputSpec>
|
||||
export type ChartInputSpec = z.infer<typeof zChartInputSpec>
|
||||
export type GalleriaInputSpec = z.infer<typeof zGalleriaInputSpec>
|
||||
export type TextareaInputSpec = z.infer<typeof zTextareaInputSpec>
|
||||
type ChartInputSpec = z.infer<typeof zChartInputSpec>
|
||||
type GalleriaInputSpec = z.infer<typeof zGalleriaInputSpec>
|
||||
type TextareaInputSpec = z.infer<typeof zTextareaInputSpec>
|
||||
export type CurveInputSpec = z.infer<typeof zCurveInputSpec>
|
||||
export type RangeInputSpec = z.infer<typeof zRangeInputSpec>
|
||||
export type CustomInputSpec = z.infer<typeof zCustomInputSpec>
|
||||
@@ -257,3 +249,21 @@ export const isChartInputSpec = (
|
||||
): inputSpec is ChartInputSpec => {
|
||||
return inputSpec.type === 'CHART'
|
||||
}
|
||||
|
||||
export const isColorInputSpec = (
|
||||
inputSpec: InputSpec
|
||||
): inputSpec is ColorInputSpec => {
|
||||
return inputSpec.type === 'COLOR'
|
||||
}
|
||||
|
||||
export const isTextareaInputSpec = (
|
||||
inputSpec: InputSpec
|
||||
): inputSpec is TextareaInputSpec => {
|
||||
return inputSpec.type === 'TEXTAREA'
|
||||
}
|
||||
|
||||
export const isGalleriaInputSpec = (
|
||||
inputSpec: InputSpec
|
||||
): inputSpec is GalleriaInputSpec => {
|
||||
return inputSpec.type === 'GALLERIA'
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user