feat: form not installed indicator

This commit is contained in:
AkaraChen 2025-01-09 14:31:43 +08:00
parent 5ec4695e4a
commit 08cff0045d
4 changed files with 92 additions and 42 deletions

View File

@ -10,11 +10,15 @@ type ModelTriggerProps = {
modelName: string
providerName: string
className?: string
showWarnIcon?: boolean
contentClassName?: string
}
const ModelTrigger: FC<ModelTriggerProps> = ({
modelName,
providerName,
className,
showWarnIcon,
contentClassName,
}) => {
const { t } = useTranslation()
const { modelProviders } = useProviderContext()
@ -24,7 +28,7 @@ const ModelTrigger: FC<ModelTriggerProps> = ({
<div
className={cn('group flex flex-grow box-content items-center p-[3px] pl-1 h-8 gap-1 rounded-lg bg-components-input-bg-disabled cursor-pointer', className)}
>
<div className='flex items-center w-full'>
<div className={cn('flex items-center w-full', contentClassName)}>
<div className='flex items-center py-[1px] gap-1 min-w-0 flex-1'>
<ModelIcon
className="w-4 h-4"
@ -36,9 +40,11 @@ const ModelTrigger: FC<ModelTriggerProps> = ({
</div>
</div>
<div className='shrink-0 flex items-center justify-center'>
{showWarnIcon && (
<Tooltip popupContent={t('common.modelProvider.deprecated')}>
<AlertTriangle className='w-4 h-4 text-text-warning-secondary' />
</Tooltip>
)}
</div>
</div>
</div>

View File

@ -15,6 +15,7 @@ import {
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import classNames from '@/utils/classnames'
type ModelSelectorProps = {
defaultModel?: DefaultModel
@ -24,6 +25,8 @@ type ModelSelectorProps = {
onSelect?: (model: DefaultModel) => void
readonly?: boolean
scopeFeatures?: string[]
deprecatedClassName?: string
showDeprecatedWarnIcon?: boolean
}
const ModelSelector: FC<ModelSelectorProps> = ({
defaultModel,
@ -33,6 +36,8 @@ const ModelSelector: FC<ModelSelectorProps> = ({
onSelect,
readonly,
scopeFeatures = [],
deprecatedClassName,
showDeprecatedWarnIcon = false,
}) => {
const [open, setOpen] = useState(false)
const {
@ -64,7 +69,7 @@ const ModelSelector: FC<ModelSelectorProps> = ({
placement='bottom-start'
offset={4}
>
<div className='relative'>
<div className={classNames('relative')}>
<PortalToFollowElemTrigger
onClick={handleToggle}
className='block'
@ -86,6 +91,8 @@ const ModelSelector: FC<ModelSelectorProps> = ({
modelName={defaultModel?.model || ''}
providerName={defaultModel?.provider || ''}
className={triggerClassName}
showWarnIcon={showDeprecatedWarnIcon}
contentClassName={deprecatedClassName}
/>
)
}

View File

@ -0,0 +1,67 @@
import Tooltip from '@/app/components/base/tooltip'
import { ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
import Indicator from '@/app/components/header/indicator'
import { type FC, useMemo } from 'react'
import { useTranslation } from 'react-i18next'
export type ModelBarProps = {
provider: string
model: string
} | {}
const useAllModel = () => {
const { data: textGeneration } = useModelList(ModelTypeEnum.textGeneration)
const { data: moderation } = useModelList(ModelTypeEnum.moderation)
const { data: rerank } = useModelList(ModelTypeEnum.rerank)
const { data: speech2text } = useModelList(ModelTypeEnum.speech2text)
const { data: textEmbedding } = useModelList(ModelTypeEnum.textEmbedding)
const { data: tts } = useModelList(ModelTypeEnum.tts)
const models = useMemo(() => {
return textGeneration
.concat(moderation)
.concat(rerank)
.concat(speech2text)
.concat(textEmbedding)
.concat(tts)
}, [textGeneration, moderation, rerank, speech2text, textEmbedding, tts])
if (!textGeneration || !moderation || !rerank || !speech2text || !textEmbedding || !tts)
return undefined
return models
}
export const ModelBar: FC<ModelBarProps> = (props) => {
const { t } = useTranslation()
const modelList = useAllModel()
if (!('provider' in props)) {
return <ModelSelector
modelList={[]}
triggerClassName='bg-workflow-block-parma-bg !h-6 !rounded-md'
defaultModel={undefined}
showDeprecatedWarnIcon={false}
readonly
deprecatedClassName='opacity-50'
/>
}
const modelInstalled = modelList?.some(
provider => provider.provider === props.provider && provider.models.some(model => model.model === props.model))
const showWarn = modelList && !modelInstalled
return modelList && <Tooltip
popupContent={t('workflow.nodes.agent.modelNotInstallTooltip')}
triggerMethod='hover'
disabled={!modelList || modelInstalled}
>
<div className='relative'>
<ModelSelector
modelList={modelList}
triggerClassName='bg-workflow-block-parma-bg !h-6 !rounded-md'
defaultModel={props}
showDeprecatedWarnIcon={false}
readonly
deprecatedClassName='opacity-50'
/>
{showWarn && <Indicator color={'red'} className='absolute -right-0.5 -top-0.5' />}
</div>
</Tooltip>
}

View File

@ -2,41 +2,19 @@ import { type FC, memo, useMemo } from 'react'
import type { NodeProps } from '../../types'
import type { AgentNodeType } from './types'
import { SettingItem } from '../_base/components/setting-item'
import ModelSelector from '@/app/components/header/account-setting/model-provider-page/model-selector'
import { Group, GroupLabel } from '../_base/components/group'
import type { ToolIconProps } from './components/tool-icon'
import { ToolIcon } from './components/tool-icon'
import useConfig from './use-config'
import { useTranslation } from 'react-i18next'
import { FormTypeEnum, ModelTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useModelList } from '@/app/components/header/account-setting/model-provider-page/hooks'
import { FormTypeEnum } from '@/app/components/header/account-setting/model-provider-page/declarations'
import { useRenderI18nObject } from '@/hooks/use-i18n'
const useAllModel = () => {
const { data: textGeneration } = useModelList(ModelTypeEnum.textGeneration)
const { data: moderation } = useModelList(ModelTypeEnum.moderation)
const { data: rerank } = useModelList(ModelTypeEnum.rerank)
const { data: speech2text } = useModelList(ModelTypeEnum.speech2text)
const { data: textEmbedding } = useModelList(ModelTypeEnum.textEmbedding)
const { data: tts } = useModelList(ModelTypeEnum.tts)
const models = useMemo(() => {
return textGeneration
.concat(moderation)
.concat(rerank)
.concat(speech2text)
.concat(textEmbedding)
.concat(tts)
}, [textGeneration, moderation, rerank, speech2text, textEmbedding, tts])
if (!textGeneration || !moderation || !rerank || !speech2text || !textEmbedding || !tts)
return undefined
return models
}
import { ModelBar } from './components/model-bar'
const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
const { inputs, currentStrategy, currentStrategyStatus, pluginDetail } = useConfig(props.id, props.data)
const renderI18nObject = useRenderI18nObject()
const { t } = useTranslation()
const modelList = useAllModel()
const models = useMemo(() => {
if (!inputs) return []
// if selected, show in node
@ -46,6 +24,7 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
.filter(param => param.type === FormTypeEnum.modelSelector)
.reduce((acc, param) => {
const item = inputs.agent_parameters?.[param.name]?.value
console.log({ item })
if (!item) {
if (param.required) {
acc.push({ param: param.name })
@ -102,27 +81,18 @@ const AgentNode: FC<NodeProps<AgentNodeType>> = (props) => {
{inputs.agent_strategy_label}
</SettingItem>
: <SettingItem label={t('workflow.nodes.agent.strategyNotSet')} />}
{models.length > 0 && modelList && <Group
<Group
label={<GroupLabel className='mt-1'>
{t('workflow.nodes.agent.model')}
</GroupLabel>}
>
{models.map((model) => {
return <ModelSelector
return <ModelBar
{...model}
key={model.param}
modelList={modelList}
triggerClassName='bg-workflow-block-parma-bg !h-6 !rounded-md'
defaultModel={
'provider' in model
? {
provider: model.provider,
model: model.model,
}
: undefined}
readonly
/>
})}
</Group>}
</Group>
{tools.length > 0 && <Group label={<GroupLabel className='mt-1'>
{t('workflow.nodes.agent.toolbox')}
</GroupLabel>}>