From 5128f072a8400a077ecf35bc2caf557d230aa2a9 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Wed, 25 Jun 2025 23:44:57 +1000 Subject: [PATCH] feat: add user_label to FieldIdentifier (#8126) Co-authored-by: Mary Hipp Rogers --- .../session_queue/session_queue_common.py | 1 + .../components/sidePanel/workflow/publish.ts | 18 +++++++++++++----- .../queue/hooks/useEnqueueWorkflows.ts | 10 ++++++---- .../frontend/web/src/services/api/schema.ts | 5 +++++ 4 files changed, 25 insertions(+), 9 deletions(-) diff --git a/invokeai/app/services/session_queue/session_queue_common.py b/invokeai/app/services/session_queue/session_queue_common.py index 0a8b553595..fafb07b49f 100644 --- a/invokeai/app/services/session_queue/session_queue_common.py +++ b/invokeai/app/services/session_queue/session_queue_common.py @@ -205,6 +205,7 @@ class FieldIdentifier(BaseModel): kind: Literal["input", "output"] = Field(description="The kind of field") node_id: str = Field(description="The ID of the node") field_name: str = Field(description="The name of the field") + user_label: str | None = Field(description="The user label of the field, if any") class SessionQueueItemWithoutGraph(BaseModel): diff --git a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/publish.ts b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/publish.ts index 9b304a68bc..3f685e4a88 100644 --- a/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/publish.ts +++ b/invokeai/frontend/web/src/features/nodes/components/sidePanel/workflow/publish.ts @@ -19,6 +19,9 @@ import { useGetBatchStatusQuery } from 'services/api/endpoints/queue'; import { useGetWorkflowQuery } from 'services/api/endpoints/workflows'; import { assert } from 'tsafe'; +type FieldIdentiferWithLabel = FieldIdentifier & { label: string | null }; +type FieldIdentiferWithLabelAndType = FieldIdentiferWithLabel & { type: string }; + export const $isPublishing = atom(false); export const $isInPublishFlow = atom(false); export const $outputNodeId = atom(null); @@ -54,21 +57,26 @@ export const selectFieldIdentifiersWithInvocationTypes = createSelector( selectWorkflowFormNodeFieldFieldIdentifiersDeduped, selectNodesSlice, (fieldIdentifiers, nodes) => { - const result: { nodeId: string; fieldName: string; type: string }[] = []; + const result: FieldIdentiferWithLabelAndType[] = []; for (const fieldIdentifier of fieldIdentifiers) { const node = nodes.nodes.find((node) => node.id === fieldIdentifier.nodeId); assert(isInvocationNode(node), `Node ${fieldIdentifier.nodeId} not found`); - result.push({ nodeId: fieldIdentifier.nodeId, fieldName: fieldIdentifier.fieldName, type: node.data.type }); + result.push({ + nodeId: fieldIdentifier.nodeId, + fieldName: fieldIdentifier.fieldName, + type: node.data.type, + label: node.data.inputs[fieldIdentifier.fieldName]?.label ?? null, + }); } return result; } ); -export const getPublishInputs = (fieldIdentifiers: (FieldIdentifier & { type: string })[], templates: Templates) => { +export const getPublishInputs = (fieldIdentifiers: FieldIdentiferWithLabelAndType[], templates: Templates) => { // Certain field types are not allowed to be input fields on a published workflow - const publishable: FieldIdentifier[] = []; - const unpublishable: FieldIdentifier[] = []; + const publishable: FieldIdentiferWithLabel[] = []; + const unpublishable: FieldIdentiferWithLabel[] = []; for (const fieldIdentifier of fieldIdentifiers) { const fieldTemplate = templates[fieldIdentifier.type]?.inputs[fieldIdentifier.fieldName]; if (!fieldTemplate) { diff --git a/invokeai/frontend/web/src/features/queue/hooks/useEnqueueWorkflows.ts b/invokeai/frontend/web/src/features/queue/hooks/useEnqueueWorkflows.ts index 4e2dbd067f..721f7622f6 100644 --- a/invokeai/frontend/web/src/features/queue/hooks/useEnqueueWorkflows.ts +++ b/invokeai/frontend/web/src/features/queue/hooks/useEnqueueWorkflows.ts @@ -14,7 +14,7 @@ import { buildWorkflowWithValidation } from 'features/nodes/util/workflow/buildW import { groupBy } from 'lodash-es'; import { useCallback } from 'react'; import { enqueueMutationFixedCacheKeyOptions, queueApi } from 'services/api/endpoints/queue'; -import type { Batch, EnqueueBatchArg } from 'services/api/types'; +import type { Batch, EnqueueBatchArg, S } from 'services/api/types'; import { assert } from 'tsafe'; const enqueueRequestedWorkflows = createAction('app/enqueueRequestedWorkflows'); @@ -106,12 +106,13 @@ export const useEnqueueWorkflows = () => { // Derive the input fields from the builder's selected node field elements const fieldIdentifiers = selectFieldIdentifiersWithInvocationTypes(state); const inputs = getPublishInputs(fieldIdentifiers, templates); - const api_input_fields = inputs.publishable.map(({ nodeId, fieldName }) => { + const api_input_fields = inputs.publishable.map(({ nodeId, fieldName, label }) => { return { kind: 'input', node_id: nodeId, field_name: fieldName, - } as const; + user_label: label, + } satisfies S['FieldIdentifier']; }); // Derive the output fields from the builder's selected output node @@ -126,7 +127,8 @@ export const useEnqueueWorkflows = () => { kind: 'output', node_id: outputNodeId, field_name: fieldName, - } as const; + user_label: null, + } satisfies S['FieldIdentifier']; }); assert(nodesState.id, 'Workflow without ID cannot be used for API validation run'); diff --git a/invokeai/frontend/web/src/services/api/schema.ts b/invokeai/frontend/web/src/services/api/schema.ts index 13d8912b46..27c7c659e3 100644 --- a/invokeai/frontend/web/src/services/api/schema.ts +++ b/invokeai/frontend/web/src/services/api/schema.ts @@ -6996,6 +6996,11 @@ export type components = { * @description The name of the field */ field_name: string; + /** + * User Label + * @description The user label of the field, if any + */ + user_label: string | null; }; /** * FieldKind