feat: workflow presentation ui (#6156)

* icon & gradient

* line & header ui

* basic presentation mode

* ui & icon

* node

* fix

* source color schema

* delete code

* fix build

* fix

* fix

* fix icon

* function position
This commit is contained in:
heheer
2025-12-30 15:27:02 +08:00
committed by GitHub
parent 75b6947cb9
commit f626c961fb
155 changed files with 1687 additions and 830 deletions

View File

@@ -256,3 +256,50 @@ export const AppNodeFlowNodeTypeMap: Record<any, boolean> = {
[FlowNodeTypeEnum.tool]: true,
[FlowNodeTypeEnum.toolSet]: true
};
export const NodeGradients = {
pink: 'linear-gradient(180deg, rgba(255, 161, 206, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
blue: 'linear-gradient(180deg, rgba(104, 192, 255, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
blueLight: 'linear-gradient(180deg, rgba(85, 184, 255, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
blueDark: 'linear-gradient(180deg, rgba(125, 153, 255, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
orange: 'linear-gradient(180deg, rgba(255, 199, 90, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
purple: 'linear-gradient(180deg, rgba(235, 120, 254, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
teal: 'linear-gradient(180deg, rgba(97, 210, 196, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
green: 'linear-gradient(180deg, rgba(62, 217, 170, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
greenLight:
'linear-gradient(180deg, rgba(94, 209, 128, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
indigo: 'linear-gradient(180deg, rgba(120, 147, 254, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
coral: 'linear-gradient(180deg, rgba(252, 162, 143, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
lime: 'linear-gradient(0deg, rgba(255, 255, 255, 0.00) 0%, rgba(92, 216, 201, 0.25) 100%)',
violet: 'linear-gradient(180deg, rgba(155, 142, 255, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
violetDeep:
'linear-gradient(180deg, rgba(212, 117, 255, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
yellowGreen:
'linear-gradient(180deg, rgba(166, 218, 114, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
lafTeal: 'linear-gradient(180deg, rgba(72, 213, 186, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
skyBlue: 'linear-gradient(180deg, rgba(137, 229, 255, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
salmon: 'linear-gradient(180deg, rgba(255, 160, 160, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)',
gray: 'linear-gradient(180deg, rgba(136, 136, 136, 0.20) 0%, rgba(255, 255, 255, 0.00) 100%)'
};
export const NodeBorderColors = {
pink: 'rgba(255, 161, 206, 0.6)',
blue: 'rgba(104, 192, 255, 0.6)',
blueLight: 'rgba(85, 184, 255, 0.6)',
blueDark: 'rgba(125, 153, 255, 0.6)',
orange: 'rgba(255, 199, 90, 0.6)',
purple: 'rgba(235, 120, 254, 0.6)',
teal: 'rgba(97, 210, 196, 0.6)',
green: 'rgba(62, 217, 170, 0.6)',
greenLight: 'rgba(94, 209, 128, 0.6)',
indigo: 'rgba(120, 147, 254, 0.6)',
coral: 'rgba(252, 162, 143, 0.6)',
lime: 'rgba(92, 216, 201, 0.6)',
violet: 'rgba(155, 142, 255, 0.6)',
violetDeep: 'rgba(212, 117, 255, 0.6)',
yellowGreen: 'rgba(166, 218, 114, 0.6)',
lafTeal: 'rgba(72, 213, 186, 0.6)',
skyBlue: 'rgba(137, 229, 255, 0.6)',
salmon: 'rgba(255, 160, 160, 0.6)',
gray: 'rgba(136, 136, 136, 0.6)'
};

View File

@@ -28,7 +28,9 @@ export const AgentNode: FlowNodeTemplateType = {
templateType: FlowNodeTemplateTypeEnum.ai,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/toolCall',
avatar: 'core/workflow/systemNode/toolCall',
avatarLinear: 'core/workflow/systemNode/toolCallLinear',
colorSchema: 'indigo',
name: i18nT('workflow:template.agent'),
intro: i18nT('workflow:template.agent_intro'),
showStatus: true,

View File

@@ -48,7 +48,9 @@ export const AiChatModule: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.chatNode,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/aiChat',
avatar: 'core/workflow/systemNode/aiChat',
avatarLinear: 'core/workflow/systemNode/aiChatLinear',
colorSchema: 'blueDark',
name: i18nT('workflow:template.ai_chat'),
intro: i18nT('workflow:template.ai_chat_intro'),
showStatus: true,

View File

@@ -13,7 +13,9 @@ export const AssignedAnswerModule: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.answerNode,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/reply',
avatar: 'core/workflow/systemNode/reply',
avatarLinear: 'core/workflow/systemNode/replyLinear',
colorSchema: 'blue',
name: i18nT('workflow:assigned_reply'),
intro: i18nT('workflow:intro_assigned_reply'),
courseUrl: '/docs/introduction/guide/dashboard/workflow/reply/',

View File

@@ -25,7 +25,9 @@ export const ClassifyQuestionModule: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.classifyQuestion,
showSourceHandle: false,
showTargetHandle: true,
avatar: 'core/workflow/template/questionClassify',
avatar: 'core/workflow/systemNode/questionClassify',
avatarLinear: 'core/workflow/systemNode/questionClassifyLinear',
colorSchema: 'purple',
name: i18nT('workflow:question_classification'),
intro: i18nT('workflow:intro_question_classification'),
showStatus: true,

View File

@@ -21,7 +21,9 @@ export const ContextExtractModule: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.contentExtract,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/extractJson',
avatar: 'core/workflow/systemNode/extractJson',
avatarLinear: 'core/workflow/systemNode/extractJsonLinear',
colorSchema: 'teal',
name: i18nT('workflow:text_content_extraction'),
intro: i18nT('workflow:intro_text_content_extraction'),
showStatus: true,

View File

@@ -13,7 +13,9 @@ export const CustomFeedbackNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.customFeedback,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/customFeedback',
avatar: 'core/workflow/systemNode/customFeedback',
avatarLinear: 'core/workflow/systemNode/customFeedbackLinear',
colorSchema: 'yellowGreen',
name: i18nT('workflow:custom_feedback'),
intro: i18nT('workflow:intro_custom_feedback'),
courseUrl: '/docs/introduction/guide/dashboard/workflow/custom_feedback/',

View File

@@ -36,7 +36,9 @@ export const DatasetConcatModule: FlowNodeTemplateType = {
templateType: FlowNodeTemplateTypeEnum.other,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/datasetConcat',
avatar: 'core/workflow/systemNode/datasetConcat',
avatarLinear: 'core/workflow/systemNode/datasetConcatLinear',
colorSchema: 'blue',
name: i18nT('workflow:knowledge_base_search_merge'),
intro: i18nT('workflow:intro_knowledge_base_search_merge'),

View File

@@ -25,7 +25,9 @@ export const DatasetSearchModule: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.datasetSearchNode,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/datasetSearch',
avatar: 'core/workflow/systemNode/datasetSearch',
avatarLinear: 'core/workflow/systemNode/datasetSearchLinear',
colorSchema: 'blueLight',
name: i18nT('workflow:template.dataset_search'),
intro: Dataset_SEARCH_DESC,
showStatus: true,

View File

@@ -21,7 +21,9 @@ export const HttpNode468: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.httpRequest468,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/httpRequest',
avatar: 'core/workflow/systemNode/httpRequest',
avatarLinear: 'core/workflow/systemNode/httpRequestLinear',
colorSchema: 'indigo',
name: i18nT('workflow:http_request'),
intro: i18nT('workflow:intro_http_request'),
showStatus: true,

View File

@@ -18,7 +18,9 @@ export const IfElseNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.ifElseNode,
showSourceHandle: false,
showTargetHandle: true,
avatar: 'core/workflow/template/ifelse',
avatar: 'core/workflow/systemNode/ifelse',
avatarLinear: 'core/workflow/systemNode/ifelseLinear',
colorSchema: 'greenLight',
name: i18nT('workflow:condition_checker'),
intro: i18nT('workflow:execute_different_branches_based_on_conditions'),
showStatus: true,

View File

@@ -18,7 +18,9 @@ export const FormInputNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.formInput,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/formInput',
avatar: 'core/workflow/systemNode/formInput',
avatarLinear: 'core/workflow/systemNode/formInputLinear',
colorSchema: 'violetDeep',
name: i18nT('app:workflow.form_input'),
intro: i18nT(`app:workflow.form_input_tip`),
isTool: true,

View File

@@ -18,7 +18,9 @@ export const UserSelectNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.userSelect,
showSourceHandle: false,
showTargetHandle: true,
avatar: 'core/workflow/template/userSelect',
avatar: 'core/workflow/systemNode/userSelect',
avatarLinear: 'core/workflow/systemNode/userSelectLinear',
colorSchema: 'green',
diagram: '/imgs/app/userSelect.svg',
name: i18nT('app:workflow.user_select'),
intro: i18nT(`app:workflow.user_select_tip`),

View File

@@ -26,6 +26,7 @@ export const LafModule: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.lafModule,
showSourceHandle: true,
showTargetHandle: true,
colorSchema: 'lafTeal',
avatar: 'core/workflow/template/lafDispatch',
name: i18nT('workflow:laf_function_call_test'),
intro: i18nT('workflow:intro_laf_function_call'),

View File

@@ -24,7 +24,9 @@ export const LoopNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.loop,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/loop',
avatar: 'core/workflow/systemNode/loop',
avatarLinear: 'core/workflow/systemNode/loopLinear',
colorSchema: 'violetDeep',
name: i18nT('workflow:loop'),
intro: i18nT('workflow:intro_loop'),
showStatus: true,

View File

@@ -15,7 +15,9 @@ export const LoopEndNode: FlowNodeTemplateType = {
showTargetHandle: true,
unique: true,
forbidDelete: true,
avatar: 'core/workflow/template/loopEnd',
avatar: 'core/workflow/systemNode/loopEnd',
avatarLinear: 'core/workflow/systemNode/loopEndLinear',
colorSchema: 'violetDeep',
name: i18nT('workflow:loop_end'),
showStatus: false,
inputs: [

View File

@@ -18,7 +18,9 @@ export const LoopStartNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.loopStart,
showSourceHandle: true,
showTargetHandle: false,
avatar: 'core/workflow/template/loopStart',
avatar: 'core/workflow/systemNode/loopStart',
avatarLinear: 'core/workflow/systemNode/loopStartLinear',
colorSchema: 'violetDeep',
name: i18nT('workflow:loop_start'),
unique: true,
forbidDelete: true,

View File

@@ -9,7 +9,9 @@ export const PluginConfigNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.pluginConfig,
showSourceHandle: false,
showTargetHandle: false,
avatar: 'core/workflow/template/systemConfig',
avatar: 'core/workflow/systemNode/systemConfig',
avatarLinear: 'core/workflow/systemNode/systemConfigLinear',
colorSchema: 'pink',
name: i18nT('workflow:template.system_config'),
intro: '',
unique: true,

View File

@@ -11,7 +11,9 @@ export const PluginInputModule: FlowNodeTemplateType = {
showTargetHandle: false,
unique: true,
forbidDelete: true,
avatar: 'core/workflow/template/workflowStart',
avatar: 'core/workflow/systemNode/workflowStart',
avatarLinear: 'core/workflow/systemNode/workflowStartLinear',
colorSchema: 'blue',
name: i18nT('workflow:plugin_input'),
intro: i18nT('workflow:intro_plugin_input'),
showStatus: false,

View File

@@ -9,12 +9,14 @@ export const PluginOutputModule: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.pluginOutput,
showSourceHandle: false,
showTargetHandle: true,
unique: true,
forbidDelete: true,
avatar: 'core/workflow/template/pluginOutput',
avatar: 'core/workflow/systemNode/pluginOutput',
avatarLinear: 'core/workflow/systemNode/pluginOutputLinear',
colorSchema: 'blue',
name: i18nT('workflow:template.plugin_output'),
intro: i18nT('workflow:intro_custom_plugin_output'),
showStatus: false,
unique: true,
forbidDelete: true,
inputs: [],
outputs: []
};

View File

@@ -23,7 +23,9 @@ export const AiQueryExtension: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.queryExtension,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/queryExtension',
avatar: 'core/workflow/systemNode/queryExtension',
avatarLinear: 'core/workflow/systemNode/queryExtensionLinear',
colorSchema: 'indigo',
name: i18nT('workflow:question_optimization'),
intro: i18nT('workflow:intro_question_optimization'),
showStatus: true,

View File

@@ -19,7 +19,9 @@ export const ReadFilesNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.readFiles,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/readFiles',
avatar: 'core/workflow/systemNode/readFiles',
avatarLinear: 'core/workflow/systemNode/readFilesLinear',
colorSchema: 'green',
name: i18nT('app:workflow.read_files'),
intro: i18nT('app:workflow.read_files_tip'),
showStatus: true,

View File

@@ -8,6 +8,7 @@ export const RunAppNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.appModule,
showSourceHandle: true,
showTargetHandle: true,
colorSchema: 'skyBlue',
intro: '',
name: '',
showStatus: false,

View File

@@ -8,6 +8,7 @@ export const RunPluginModule: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.pluginModule,
showSourceHandle: true,
showTargetHandle: true,
colorSchema: 'salmon',
intro: '',
name: '',
showStatus: false,

View File

@@ -8,6 +8,7 @@ export const RunToolSetNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.toolSet,
showSourceHandle: false,
showTargetHandle: false,
colorSchema: 'salmon',
isTool: true,
intro: '',
name: '',

View File

@@ -21,7 +21,9 @@ export const CodeNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.code,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/codeRun',
avatar: 'core/workflow/systemNode/codeRun',
avatarLinear: 'core/workflow/systemNode/codeRunLinear',
colorSchema: 'lime',
name: i18nT('workflow:code_execution'),
intro: i18nT('workflow:execute_a_simple_script_code_usually_for_complex_data_processing'),
showStatus: true,

View File

@@ -9,7 +9,9 @@ export const StopToolNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.stopTool,
showSourceHandle: false,
showTargetHandle: true,
avatar: 'core/workflow/template/stopTool',
avatar: 'core/workflow/systemNode/stopTool',
avatarLinear: 'core/workflow/systemNode/stopToolLinear',
colorSchema: 'violet',
name: i18nT('workflow:tool_call_termination'),
intro: i18nT('workflow:intro_tool_call_termination'),
inputs: [],

View File

@@ -9,7 +9,9 @@ export const SystemConfigNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.systemConfig,
showSourceHandle: false,
showTargetHandle: false,
avatar: 'core/workflow/template/systemConfig',
avatar: 'core/workflow/systemNode/systemConfig',
avatarLinear: 'core/workflow/systemNode/systemConfigLinear',
colorSchema: 'pink',
name: i18nT('workflow:template.system_config'),
intro: '',
unique: true,

View File

@@ -18,7 +18,9 @@ export const TextEditorNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.textEditor,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/textConcat',
avatar: 'core/workflow/systemNode/textConcat',
avatarLinear: 'core/workflow/systemNode/textConcatLinear',
colorSchema: 'orange',
name: i18nT('workflow:text_concatenation'),
intro: i18nT('workflow:intro_text_concatenation'),
courseUrl: '/docs/introduction/guide/dashboard/workflow/text_editor/',

View File

@@ -9,7 +9,9 @@ export const ToolParamsNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.toolParams,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/toolParams',
avatar: 'core/workflow/systemNode/toolParams',
avatarLinear: 'core/workflow/systemNode/toolParamsLinear',
colorSchema: 'indigo',
name: i18nT('workflow:tool_custom_field'),
intro: i18nT('workflow:intro_tool_params_config'),
isTool: true,

View File

@@ -13,7 +13,9 @@ export const VariableUpdateNode: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.variableUpdate,
showSourceHandle: true,
showTargetHandle: true,
avatar: 'core/workflow/template/variableUpdate',
avatar: 'core/workflow/systemNode/variableUpdate',
avatarLinear: 'core/workflow/systemNode/variableUpdateLinear',
colorSchema: 'coral',
name: i18nT('workflow:variable_update'),
intro: i18nT('workflow:update_specified_node_output_or_global_variable'),
showStatus: false,

View File

@@ -24,7 +24,9 @@ export const WorkflowStart: FlowNodeTemplateType = {
flowNodeType: FlowNodeTypeEnum.workflowStart,
showSourceHandle: true,
showTargetHandle: false,
avatar: 'core/workflow/template/workflowStart',
avatar: 'core/workflow/systemNode/workflowStart',
avatarLinear: 'core/workflow/systemNode/workflowStartLinear',
colorSchema: 'blue',
name: i18nT('workflow:template.workflow_start'),
intro: '',
forbidDelete: true,

View File

@@ -1,4 +1,5 @@
import type { FlowNodeTypeEnum } from '../node/constant';
import type { NodeGradients } from '../node/constant';
import { type FlowNodeTypeEnum } from '../node/constant';
import {
WorkflowIOValueTypeEnum,
NodeOutputKeyEnum,
@@ -66,6 +67,8 @@ export type FlowNodeCommonType = {
abandon?: boolean; // abandon node
avatar?: string;
avatarLinear?: string; // Linear icon for gradient masks
colorSchema?: keyof typeof NodeGradients; // Node color schema
name: string;
intro?: string; // template list intro
toolDescription?: string;