From cc4d4adfb9230bbb89c031e76427488f6af800ff Mon Sep 17 00:00:00 2001 From: zhsama Date: Wed, 5 Nov 2025 16:54:49 +0800 Subject: [PATCH] feat: enhance workflow draft processing by adding hydration and sanitization functions --- web/service/workflow-payload.ts | 92 ++++++++++++++++++++++++++++++++- web/service/workflow.ts | 12 +++-- 2 files changed, 99 insertions(+), 5 deletions(-) diff --git a/web/service/workflow-payload.ts b/web/service/workflow-payload.ts index b9f4c02ca8..b80c4a3731 100644 --- a/web/service/workflow-payload.ts +++ b/web/service/workflow-payload.ts @@ -1,5 +1,7 @@ +import { produce } from 'immer' +import type { Edge, Node } from '@/app/components/workflow/types' import { BlockEnum } from '@/app/components/workflow/types' -import type { Node } from '@/app/components/workflow/types' +import type { PluginTriggerNodeType } from '@/app/components/workflow/nodes/trigger-plugin/types' import type { FetchWorkflowDraftResponse } from '@/types/workflow' export type TriggerPluginNodePayload = { @@ -18,6 +20,20 @@ export type WorkflowDraftSyncParams = Pick< 'graph' | 'features' | 'environment_variables' | 'conversation_variables' > +const removeTempProperties = (data: Record): void => { + Object.keys(data).forEach((key) => { + if (key.startsWith('_')) + delete data[key] + }) +} + +type TriggerParameterSchema = Record + +type TriggerPluginHydratePayload = (PluginTriggerNodeType & { + paramSchemas?: TriggerParameterSchema[] + parameters_schema?: TriggerParameterSchema[] +}) + const sanitizeTriggerPluginNode = (node: Node): Node => { const data = node.data @@ -60,3 +76,77 @@ export const sanitizeWorkflowDraftPayload = (params: WorkflowDraftSyncParams): W }, } } + +const isTriggerPluginNode = (node: Node): node is Node => { + const data = node.data as unknown + + if (!data || typeof data !== 'object') + return false + + const payload = data as Partial & { type?: BlockEnum } + + if (payload.type !== BlockEnum.TriggerPlugin) + return false + + return 'event_parameters' in payload +} + +const hydrateTriggerPluginNode = (node: Node): Node => { + if (!isTriggerPluginNode(node)) + return node + + const typedNode = node as Node + const data = typedNode.data + const eventParameters = data.event_parameters ?? {} + const parametersSchema = data.parameters_schema ?? data.paramSchemas ?? [] + const config = data.config ?? eventParameters ?? {} + + const nextData: typeof data = { + ...data, + config, + paramSchemas: data.paramSchemas ?? parametersSchema, + parameters_schema: parametersSchema, + } + + return { + ...typedNode, + data: nextData, + } +} + +export const hydrateWorkflowDraftResponse = (draft: FetchWorkflowDraftResponse): FetchWorkflowDraftResponse => { + return produce(draft, (mutableDraft) => { + if (!mutableDraft?.graph) + return + + if (mutableDraft.graph.nodes) { + mutableDraft.graph.nodes = mutableDraft.graph.nodes + .filter((node: Node) => !node.data?._isTempNode) + .map((node: Node) => { + if (node.data) + removeTempProperties(node.data as Record) + + return hydrateTriggerPluginNode(node) + }) + } + + if (mutableDraft.graph.edges) { + mutableDraft.graph.edges = mutableDraft.graph.edges + .filter((edge: Edge) => !edge.data?._isTemp) + .map((edge: Edge) => { + if (edge.data) + removeTempProperties(edge.data as Record) + + return edge + }) + } + + if (mutableDraft.environment_variables) { + mutableDraft.environment_variables = mutableDraft.environment_variables.map(env => + env.value_type === 'secret' + ? { ...env, value: '[__HIDDEN__]' } + : env, + ) + } + }) +} diff --git a/web/service/workflow.ts b/web/service/workflow.ts index 654fe3d01a..037dee7b6c 100644 --- a/web/service/workflow.ts +++ b/web/service/workflow.ts @@ -12,16 +12,20 @@ import type { BlockEnum } from '@/app/components/workflow/types' import type { VarInInspect } from '@/types/workflow' import type { FlowType } from '@/types/common' import { getFlowPrefix } from './utils' +import { hydrateWorkflowDraftResponse, sanitizeWorkflowDraftPayload } from './workflow-payload' +import type { WorkflowDraftSyncParams } from './workflow-payload' -export const fetchWorkflowDraft = (url: string) => { - return get(url, {}, { silent: true }) as Promise +export const fetchWorkflowDraft = async (url: string) => { + const response = await get(url, {}, { silent: true }) as FetchWorkflowDraftResponse + return hydrateWorkflowDraftResponse(response) } export const syncWorkflowDraft = ({ url, params }: { url: string - params: Pick + params: WorkflowDraftSyncParams }) => { - return post(url, { body: params }, { silent: true }) + const sanitizedParams = sanitizeWorkflowDraftPayload(params) + return post(url, { body: sanitizedParams }, { silent: true }) } export const fetchNodesDefaultConfigs: Fetcher = (url) => {