mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-27 17:52:16 +00:00
feat: support custom descriptions for subgraph tooltips (#9003)
## Summary
Adds support for custom descriptions on subgraph nodes that display as
tooltips when hovering.
## Changes
- Add optional `description` field to `ExportedSubgraph` interface and
`Subgraph` class
- Use description with fallback to default string in
`subgraphService.createNodeDef()`
- Add `description` to `SubgraphDefinitionBase` interface and Zod schema
for validation
## Review Focus
- Backwards compatibility: undefined description falls back to `Subgraph
node for ${name}`
- Serialization pattern: conditional spread `...(this.description && {
description })`
┆Issue is synchronized with this [Notion
page](https://www.notion.so/PR-9003-feat-support-custom-descriptions-for-subgraph-tooltips-30d6d73d36508129bd75c77eb1c31cfb)
by [Unito](https://www.unito.io)
This commit is contained in:
@@ -2657,6 +2657,8 @@ export class Subgraph
|
|||||||
|
|
||||||
/** The display name of the subgraph. */
|
/** The display name of the subgraph. */
|
||||||
name: string = 'Unnamed Subgraph'
|
name: string = 'Unnamed Subgraph'
|
||||||
|
/** Optional description shown as tooltip when hovering over the subgraph node. */
|
||||||
|
description?: string
|
||||||
|
|
||||||
readonly inputNode = new SubgraphInputNode(this)
|
readonly inputNode = new SubgraphInputNode(this)
|
||||||
readonly outputNode = new SubgraphOutputNode(this)
|
readonly outputNode = new SubgraphOutputNode(this)
|
||||||
@@ -2707,9 +2709,10 @@ export class Subgraph
|
|||||||
| (ISerialisedGraph & ExportedSubgraph)
|
| (ISerialisedGraph & ExportedSubgraph)
|
||||||
| (SerialisableGraph & ExportedSubgraph)
|
| (SerialisableGraph & ExportedSubgraph)
|
||||||
): void {
|
): void {
|
||||||
const { name, inputs, outputs, widgets } = data
|
const { name, description, inputs, outputs, widgets } = data
|
||||||
|
|
||||||
this.name = name
|
this.name = name
|
||||||
|
this.description = description
|
||||||
if (inputs) {
|
if (inputs) {
|
||||||
this.inputs.length = 0
|
this.inputs.length = 0
|
||||||
for (const input of inputs) {
|
for (const input of inputs) {
|
||||||
@@ -2920,6 +2923,7 @@ export class Subgraph
|
|||||||
revision: this.revision,
|
revision: this.revision,
|
||||||
config: this.config,
|
config: this.config,
|
||||||
name: this.name,
|
name: this.name,
|
||||||
|
...(this.description && { description: this.description }),
|
||||||
inputNode: this.inputNode.asSerialisable(),
|
inputNode: this.inputNode.asSerialisable(),
|
||||||
outputNode: this.outputNode.asSerialisable(),
|
outputNode: this.outputNode.asSerialisable(),
|
||||||
inputs: this.inputs.map((x) => x.asSerialisable()),
|
inputs: this.inputs.map((x) => x.asSerialisable()),
|
||||||
|
|||||||
@@ -76,7 +76,6 @@ describe.skip('SubgraphSerialization - Basic Serialization', () => {
|
|||||||
// Verify core properties
|
// Verify core properties
|
||||||
expect(restored.id).toBe(original.id)
|
expect(restored.id).toBe(original.id)
|
||||||
expect(restored.name).toBe(original.name)
|
expect(restored.name).toBe(original.name)
|
||||||
// @ts-expect-error description property not in type definition
|
|
||||||
expect(restored.description).toBe(original.description)
|
expect(restored.description).toBe(original.description)
|
||||||
|
|
||||||
// Verify I/O structure
|
// Verify I/O structure
|
||||||
|
|||||||
@@ -139,6 +139,8 @@ export interface ExportedSubgraph extends SerialisableGraph {
|
|||||||
name: string
|
name: string
|
||||||
/** Optional category for organizing subgraph blueprints in the node library. */
|
/** Optional category for organizing subgraph blueprints in the node library. */
|
||||||
category?: string
|
category?: string
|
||||||
|
/** Optional description shown as tooltip when hovering over the subgraph node. */
|
||||||
|
description?: string
|
||||||
inputNode: ExportedSubgraphIONode
|
inputNode: ExportedSubgraphIONode
|
||||||
outputNode: ExportedSubgraphIONode
|
outputNode: ExportedSubgraphIONode
|
||||||
/** Ordered list of inputs to the subgraph itself. Similar to a reroute, with the input side in the graph, and the output side in the subgraph. */
|
/** Ordered list of inputs to the subgraph itself. Similar to a reroute, with the input side in the graph, and the output side in the subgraph. */
|
||||||
|
|||||||
@@ -396,6 +396,8 @@ interface SubgraphDefinitionBase<
|
|||||||
id: string
|
id: string
|
||||||
revision: number
|
revision: number
|
||||||
name: string
|
name: string
|
||||||
|
/** Optional description shown as tooltip when hovering over the subgraph node. */
|
||||||
|
description?: string
|
||||||
category?: string
|
category?: string
|
||||||
/** Custom metadata for the subgraph (description, searchAliases, etc.) */
|
/** Custom metadata for the subgraph (description, searchAliases, etc.) */
|
||||||
extra?: T extends ComfyWorkflow1BaseInput
|
extra?: T extends ComfyWorkflow1BaseInput
|
||||||
@@ -432,6 +434,8 @@ const zSubgraphDefinition = zComfyWorkflow1
|
|||||||
id: z.string().uuid(),
|
id: z.string().uuid(),
|
||||||
revision: z.number(),
|
revision: z.number(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
|
/** Optional description shown as tooltip when hovering over the subgraph node. */
|
||||||
|
description: z.string().optional(),
|
||||||
category: z.string().optional(),
|
category: z.string().optional(),
|
||||||
inputNode: zExportedSubgraphIONode,
|
inputNode: zExportedSubgraphIONode,
|
||||||
outputNode: zExportedSubgraphIONode,
|
outputNode: zExportedSubgraphIONode,
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ export const useSubgraphService = () => {
|
|||||||
output_tooltips: [],
|
output_tooltips: [],
|
||||||
name: id,
|
name: id,
|
||||||
display_name: name,
|
display_name: name,
|
||||||
description: `Subgraph node for ${name}`,
|
description: exportedSubgraph.description || `Subgraph node for ${name}`,
|
||||||
category: 'subgraph',
|
category: 'subgraph',
|
||||||
output_node: false,
|
output_node: false,
|
||||||
python_module: 'nodes'
|
python_module: 'nodes'
|
||||||
|
|||||||
Reference in New Issue
Block a user