feat(web): differentiate invalid variable tooltips by model plugin status

Replace the generic "Invalid variable" message in prompt editor variable
labels with two context-aware messages: one for missing nodes and another
for uninstalled model plugins. Add useLlmModelPluginInstalled hook that
checks LLM node model providers against installed providers via
useProviderContextSelector. Migrate Tooltip usage to base-ui primitives
and replace RiErrorWarningFill with Warning icon in warning color.
This commit is contained in:
yyh
2026-03-09 14:02:26 +08:00
parent 1a26e1669b
commit 1abbaf9fd5
8 changed files with 63 additions and 44 deletions

View File

@ -14,7 +14,7 @@ import {
} from 'react'
import { useTranslation } from 'react-i18next'
import { useReactFlow, useStoreApi } from 'reactflow'
import Tooltip from '@/app/components/base/tooltip'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/app/components/base/ui/tooltip'
import { isConversationVar, isENV, isGlobalVar, isRagVariableVar, isSystemVar } from '@/app/components/workflow/nodes/_base/components/variable/utils'
import VarFullPathPanel from '@/app/components/workflow/nodes/_base/components/variable/var-full-path-panel'
import {
@ -28,6 +28,7 @@ import {
UPDATE_WORKFLOW_NODES_MAP,
} from './index'
import { WorkflowVariableBlockNode } from './node'
import { useLlmModelPluginInstalled } from './use-llm-model-plugin-installed'
type WorkflowVariableBlockComponentProps = {
nodeKey: string
@ -68,6 +69,8 @@ const WorkflowVariableBlockComponent = ({
const node = localWorkflowNodesMap![variables[isRagVar ? 1 : 0]]
const isException = isExceptionVariable(varName, node?.type)
const sourceNodeId = variables[isRagVar ? 1 : 0]
const isLlmModelInstalled = useLlmModelPluginInstalled(sourceNodeId, localWorkflowNodesMap)
const variableValid = useMemo(() => {
let variableValid = true
const isEnv = isENV(variables)
@ -144,7 +147,13 @@ const WorkflowVariableBlockComponent = ({
handleVariableJump()
}}
isExceptionVariable={isException}
errorMsg={!variableValid ? t('errorMsg.invalidVariable', { ns: 'workflow' }) : undefined}
errorMsg={
!variableValid
? t('errorMsg.invalidVariable', { ns: 'workflow' })
: !isLlmModelInstalled
? t('errorMsg.modelPluginNotInstalled', { ns: 'workflow' })
: undefined
}
isSelected={isSelected}
ref={ref}
notShowFullPath={isShowAPart}
@ -155,9 +164,9 @@ const WorkflowVariableBlockComponent = ({
return Item
return (
<Tooltip
noDecoration
popupContent={(
<Tooltip>
<TooltipTrigger disabled={!isShowAPart} render={<div>{Item}</div>} />
<TooltipContent variant="plain">
<VarFullPathPanel
nodeName={node.title}
path={variables.slice(1)}
@ -169,10 +178,7 @@ const WorkflowVariableBlockComponent = ({
: Type.string}
nodeType={node?.type}
/>
)}
disabled={!isShowAPart}
>
<div>{Item}</div>
</TooltipContent>
</Tooltip>
)
}

View File

@ -0,0 +1,27 @@
import type { WorkflowNodesMap } from '@/app/components/base/prompt-editor/types'
import { BlockEnum } from '@/app/components/workflow/types'
import { useProviderContextSelector } from '@/context/provider-context'
function extractPluginId(provider: string): string {
const parts = provider.split('/')
return parts.length >= 2 ? `${parts[0]}/${parts[1]}` : provider
}
export function useLlmModelPluginInstalled(
nodeId: string,
workflowNodesMap: WorkflowNodesMap | undefined,
): boolean {
const node = workflowNodesMap?.[nodeId]
const modelProvider = node?.type === BlockEnum.LLM
? node.modelProvider
: undefined
const modelPluginId = modelProvider ? extractPluginId(modelProvider) : undefined
return useProviderContextSelector((state) => {
if (!modelPluginId)
return true
return state.modelProviders.some(p =>
extractPluginId(p.provider) === modelPluginId,
)
})
}

View File

@ -73,7 +73,7 @@ export type GetVarType = (payload: {
export type WorkflowVariableBlockType = {
show?: boolean
variables?: NodeOutPutVar[]
workflowNodesMap?: Record<string, Pick<Node['data'], 'title' | 'type' | 'height' | 'width' | 'position'>>
workflowNodesMap?: WorkflowNodesMap
onInsert?: () => void
onDelete?: () => void
getVarType?: GetVarType
@ -81,12 +81,14 @@ export type WorkflowVariableBlockType = {
onManageInputField?: () => void
}
export type WorkflowNodesMap = Record<string, Pick<Node['data'], 'title' | 'type' | 'height' | 'width' | 'position'> & { modelProvider?: string }>
export type HITLInputBlockType = {
show?: boolean
nodeId: string
formInputs?: FormInputItem[]
variables?: NodeOutPutVar[]
workflowNodesMap?: Record<string, Pick<Node['data'], 'title' | 'type' | 'height' | 'width' | 'position'>>
workflowNodesMap?: WorkflowNodesMap
getVarType?: GetVarType
onFormInputsChange?: (inputs: FormInputItem[]) => void
onFormInputItemRemove: (varName: string) => void