From 694ca840e1008ac28cfb2e6b096e520e0f9844ca Mon Sep 17 00:00:00 2001 From: yyh Date: Mon, 9 Mar 2026 16:37:47 +0800 Subject: [PATCH] feat(web): add warning dot indicator on LLM panel field labels synced with checklist Store checklist items in zustand WorkflowStore so both the checklist UI and node panels share a single source of truth. The LLM panel reads from the store to show a Figma-aligned warning dot (absolute-positioned, no layout shift) on the MODEL field label when the node has checklist warnings. --- web/app/components/workflow/hooks/use-checklist.ts | 4 +++- .../components/workflow/nodes/_base/components/field.tsx | 7 ++++++- web/app/components/workflow/nodes/llm/panel.tsx | 9 ++++++--- web/app/components/workflow/store/workflow/node-slice.ts | 3 +++ web/eslint-suppressions.json | 6 ------ 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/web/app/components/workflow/hooks/use-checklist.ts b/web/app/components/workflow/hooks/use-checklist.ts index 823a2b5d1d..723f3cba12 100644 --- a/web/app/components/workflow/hooks/use-checklist.ts +++ b/web/app/components/workflow/hooks/use-checklist.ts @@ -104,6 +104,7 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { const appMode = useAppStore.getState().appDetail?.mode const shouldCheckStartNode = appMode === AppModeEnum.WORKFLOW || appMode === AppModeEnum.ADVANCED_CHAT const modelProviders = useProviderContextSelector(s => s.modelProviders) + const workflowStore = useWorkflowStore() const map = useNodesAvailableVarList(nodes) const { data: embeddingModelList } = useModelList(ModelTypeEnum.textEmbedding) @@ -261,8 +262,9 @@ export const useChecklist = (nodes: Node[], edges: Edge[]) => { } }) + workflowStore.setState({ checklistItems: list }) return list - }, [nodes, edges, shouldCheckStartNode, nodesExtraData, buildInTools, customTools, workflowTools, language, dataSourceList, triggerPlugins, getToolIcon, strategyProviders, getCheckData, t, map, modelProviders]) + }, [nodes, edges, shouldCheckStartNode, nodesExtraData, buildInTools, customTools, workflowTools, language, dataSourceList, triggerPlugins, getToolIcon, strategyProviders, getCheckData, t, map, modelProviders, workflowStore]) return needWarningNodes } diff --git a/web/app/components/workflow/nodes/_base/components/field.tsx b/web/app/components/workflow/nodes/_base/components/field.tsx index 948dcb603c..3caa107c79 100644 --- a/web/app/components/workflow/nodes/_base/components/field.tsx +++ b/web/app/components/workflow/nodes/_base/components/field.tsx @@ -18,6 +18,7 @@ type Props = { operations?: React.JSX.Element inline?: boolean required?: boolean + warningDot?: boolean } const Field: FC = ({ @@ -30,6 +31,7 @@ const Field: FC = ({ inline, supportFold, required, + warningDot, }) => { const [fold, { toggle: toggleFold, @@ -41,7 +43,10 @@ const Field: FC = ({ className={cn('flex items-center justify-between', supportFold && 'cursor-pointer')} >
-
+
+ {warningDot && ( + + )} {title} {' '} {required && *} diff --git a/web/app/components/workflow/nodes/llm/panel.tsx b/web/app/components/workflow/nodes/llm/panel.tsx index 5948ee7ac5..9796f1bc66 100644 --- a/web/app/components/workflow/nodes/llm/panel.tsx +++ b/web/app/components/workflow/nodes/llm/panel.tsx @@ -15,6 +15,7 @@ import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/compo import Editor from '@/app/components/workflow/nodes/_base/components/prompt/editor' import Split from '@/app/components/workflow/nodes/_base/components/split' import VarList from '@/app/components/workflow/nodes/_base/components/variable/var-list' +import { useStore } from '@/app/components/workflow/store' import { fetchAndMergeValidCompletionParams } from '@/utils/completion-params' import ConfigVision from '../_base/components/config-vision' import MemoryConfig from '../_base/components/memory-config' @@ -31,6 +32,7 @@ const Panel: FC> = ({ data, }) => { const { t } = useTranslation() + const hasChecklistWarning = useStore(s => s.checklistItems.some(item => item.id === id)) const { readOnly, inputs, @@ -102,6 +104,7 @@ const Panel: FC> = ({ > = ({ noDecoration popupContent={(
-
{t('structOutput.modelNotSupported', { ns: 'app' })}
-
{t('structOutput.modelNotSupportedTip', { ns: 'app' })}
+
{t('structOutput.modelNotSupported', { ns: 'app' })}
+
{t('structOutput.modelNotSupportedTip', { ns: 'app' })}
)} > @@ -274,7 +277,7 @@ const Panel: FC> = ({
)} -
{t('structOutput.structured', { ns: 'app' })}
+
{t('structOutput.structured', { ns: 'app' })}
{t('structOutput.structuredTip', { ns: 'app' })}
} diff --git a/web/app/components/workflow/store/workflow/node-slice.ts b/web/app/components/workflow/store/workflow/node-slice.ts index b90f23e925..eb16388ef4 100644 --- a/web/app/components/workflow/store/workflow/node-slice.ts +++ b/web/app/components/workflow/store/workflow/node-slice.ts @@ -1,4 +1,5 @@ import type { StateCreator } from 'zustand' +import type { ChecklistItem } from '@/app/components/workflow/hooks/use-checklist' import type { VariableAssignerNodeType, } from '@/app/components/workflow/nodes/variable-assigner/types' @@ -10,6 +11,7 @@ import type { } from '@/types/workflow' export type NodeSliceShape = { + checklistItems: ChecklistItem[] showSingleRunPanel: boolean setShowSingleRunPanel: (showSingleRunPanel: boolean) => void nodeAnimation: boolean @@ -56,6 +58,7 @@ export type NodeSliceShape = { } export const createNodeSlice: StateCreator = set => ({ + checklistItems: [], showSingleRunPanel: false, setShowSingleRunPanel: showSingleRunPanel => set(() => ({ showSingleRunPanel })), nodeAnimation: false, diff --git a/web/eslint-suppressions.json b/web/eslint-suppressions.json index 983e06f2c5..c9998969fd 100644 --- a/web/eslint-suppressions.json +++ b/web/eslint-suppressions.json @@ -6678,9 +6678,6 @@ "app/components/workflow/nodes/_base/components/field.tsx": { "no-restricted-imports": { "count": 1 - }, - "tailwindcss/enforce-consistent-class-order": { - "count": 2 } }, "app/components/workflow/nodes/_base/components/file-type-item.tsx": { @@ -7937,9 +7934,6 @@ "app/components/workflow/nodes/llm/panel.tsx": { "no-restricted-imports": { "count": 1 - }, - "tailwindcss/enforce-consistent-class-order": { - "count": 3 } }, "app/components/workflow/nodes/llm/use-config.ts": {