type safe

This commit is contained in:
Stephen Zhou 2025-12-26 23:46:52 +08:00
parent d9a439d774
commit b6e140f547
No known key found for this signature in database
12 changed files with 37 additions and 20 deletions

View File

@ -19,7 +19,9 @@ export const tagKeys = [
'entertainment',
'utilities',
'other',
]
] as const
export type TagKey = typeof tagKeys[number]
export const categoryKeys = [
PluginCategoryEnum.model,
@ -29,4 +31,6 @@ export const categoryKeys = [
PluginCategoryEnum.extension,
'bundle',
PluginCategoryEnum.trigger,
]
] as const
export type CategoryKey = typeof categoryKeys[number]

View File

@ -1,4 +1,5 @@
import type { TFunction } from 'i18next'
import type { CategoryKey, TagKey } from './constants'
import { useMemo } from 'react'
import { useTranslation } from 'react-i18next'
import {
@ -8,7 +9,7 @@ import {
import { PluginCategoryEnum } from './types'
export type Tag = {
name: string
name: TagKey
label: string
}
@ -20,7 +21,7 @@ export const useTags = (translateFromOut?: TFunction) => {
return tagKeys.map((tag) => {
return {
name: tag,
label: t(`tags.${tag}` as any, { ns: 'pluginTags' }) as string,
label: t(`tags.${tag}`, { ns: 'pluginTags' }),
}
})
}, [t])
@ -48,7 +49,7 @@ export const useTags = (translateFromOut?: TFunction) => {
}
type Category = {
name: string
name: CategoryKey
label: string
}
@ -66,14 +67,14 @@ export const useCategories = (translateFromOut?: TFunction, isSingle?: boolean)
}
return {
name: category,
label: isSingle ? t(`categorySingle.${category}` as any, { ns: 'plugin' }) as string : t(`category.${category}s` as any, { ns: 'plugin' }) as string,
label: isSingle ? t(`categorySingle.${category}`, { ns: 'plugin' }) : t(`category.${category}s`, { ns: 'plugin' }),
}
})
}, [t, isSingle])
const categoriesMap = useMemo(() => {
return categories.reduce((acc, category) => {
acc[category.name] = category as any
acc[category.name] = category
return acc
}, {} as Record<string, Category>)
}, [categories])

View File

@ -208,7 +208,7 @@ export const CreateSubscriptionButton = ({ buttonType = CreateButtonType.FULL_BU
)
: (
<Tooltip
popupContent={subscriptionCount >= MAX_COUNT ? t('subscription.maxCount', { ns: 'pluginTrigger', num: MAX_COUNT }) : t(`subscription.addType.options.${methodType.toLowerCase()}.description` as any, { ns: 'pluginTrigger' })}
popupContent={subscriptionCount >= MAX_COUNT ? t('subscription.maxCount', { ns: 'pluginTrigger', num: MAX_COUNT }) : t(`subscription.addType.options.${methodType.toLowerCase() as Lowercase<SupportedCreationMethods>}.description`, { ns: 'pluginTrigger' })}
disabled={!(supportedMethods?.length === 1 || subscriptionCount >= MAX_COUNT)}
>
<ActionButton

View File

@ -36,8 +36,8 @@ export const useAvailableNodesMetaData = () => {
const availableNodesMetaData = useMemo(() => mergedNodesMetaData.map((node) => {
const { metaData } = node
const title = t(`blocks.${metaData.type}` as any, { ns: 'workflow' }) as string
const description = t(`blocksAbout.${metaData.type}` as any, { ns: 'workflow' }) as string
const title = t(`blocks.${metaData.type}`, { ns: 'workflow' })
const description = t(`blocksAbout.${metaData.type}`, { ns: 'workflow' })
return {
...node,
metaData: {

View File

@ -14,7 +14,7 @@ export const usePipelineTemplate = () => {
data: {
...knowledgeBaseDefault.defaultValue as KnowledgeBaseNodeType,
type: knowledgeBaseDefault.metaData.type,
title: t(`blocks.${knowledgeBaseDefault.metaData.type}` as any, { ns: 'workflow' }) as string,
title: t(`blocks.${knowledgeBaseDefault.metaData.type}`, { ns: 'workflow' }),
selected: true,
},
position: {

View File

@ -176,6 +176,6 @@ const examples = [
}
}`,
},
]
] as const
export default examples

View File

@ -111,7 +111,7 @@ const GetSchema: FC<Props> = ({
}}
className="system-sm-regular cursor-pointer whitespace-nowrap rounded-lg px-3 py-1.5 leading-5 text-text-secondary hover:bg-components-panel-on-panel-item-bg-hover"
>
{t(`createTool.exampleOptions.${item.key}` as any, { ns: 'tools' }) as string}
{t(`createTool.exampleOptions.${item.key}`, { ns: 'tools' })}
</div>
))}
</div>

View File

@ -292,7 +292,7 @@ const EditCustomCollectionModal: FC<Props> = ({
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.authMethod.title', { ns: 'tools' })}</div>
<div className="flex h-9 cursor-pointer items-center justify-between rounded-lg bg-components-input-bg-normal px-2.5" onClick={() => setCredentialsModalShow(true)}>
<div className="system-xs-regular text-text-primary">{t(`createTool.authMethod.types.${credential.auth_type}` as any, { ns: 'tools' }) as string}</div>
<div className="system-xs-regular text-text-primary">{t(`createTool.authMethod.types.${credential.auth_type}`, { ns: 'tools' })}</div>
<RiSettings2Line className="h-4 w-4 text-text-secondary" />
</div>
</div>

View File

@ -78,7 +78,7 @@ const TestApi: FC<Props> = ({
<div>
<div className="system-sm-medium py-2 text-text-primary">{t('createTool.authMethod.title', { ns: 'tools' })}</div>
<div className="flex h-9 cursor-pointer items-center justify-between rounded-lg bg-components-input-bg-normal px-2.5" onClick={() => setCredentialsModalShow(true)}>
<div className="system-xs-regular text-text-primary">{t(`createTool.authMethod.types.${tempCredential.auth_type}` as any, { ns: 'tools' }) as string}</div>
<div className="system-xs-regular text-text-primary">{t(`createTool.authMethod.types.${tempCredential.auth_type}`, { ns: 'tools' })}</div>
<RiSettings2Line className="h-4 w-4 text-text-secondary" />
</div>
</div>

View File

@ -32,18 +32,18 @@ const Empty = ({
const hasLink = type && [ToolTypeEnum.Custom, ToolTypeEnum.MCP].includes(type)
const Comp = (hasLink ? Link : 'div') as any
const linkProps = hasLink ? { href: getLink(type), target: '_blank' } : {}
const renderType = isAgent ? 'agent' : type
const hasTitle = t(`addToolModal.${renderType}.title` as any, { ns: 'tools' }) as string !== `tools.addToolModal.${renderType}.title`
const renderType = isAgent ? 'agent' as const : type
const hasTitle = renderType && t(`addToolModal.${renderType}.title`, { ns: 'tools' }) !== `addToolModal.${renderType}.title`
return (
<div className="flex flex-col items-center justify-center">
<NoToolPlaceholder className={theme === 'dark' ? 'invert' : ''} />
<div className="mb-1 mt-2 text-[13px] font-medium leading-[18px] text-text-primary">
{hasTitle ? t(`addToolModal.${renderType}.title` as any, { ns: 'tools' }) as string : 'No tools available'}
{(hasTitle && renderType) ? t(`addToolModal.${renderType}.title`, { ns: 'tools' }) : 'No tools available'}
</div>
{(!isAgent && hasTitle) && (
{(!isAgent && hasTitle && renderType) && (
<Comp className={cn('flex items-center text-[13px] leading-[18px] text-text-tertiary', hasLink && 'cursor-pointer hover:text-text-accent')} {...linkProps}>
{t(`addToolModal.${renderType}.tip` as any, { ns: 'tools' }) as string}
{t(`addToolModal.${renderType}.tip`, { ns: 'tools' })}
{' '}
{hasLink && <RiArrowRightUpLine className="ml-0.5 h-3 w-3" />}
</Comp>

View File

@ -1,6 +1,11 @@
{
"addToolModal.added": "added",
"addToolModal.agent.tip": "",
"addToolModal.agent.title": "No agent strategy available",
"addToolModal.all.tip": "",
"addToolModal.all.title": "No tools available",
"addToolModal.built-in.tip": "",
"addToolModal.built-in.title": "No built-in tool available",
"addToolModal.category": "category",
"addToolModal.custom.tip": "Create a custom tool",
"addToolModal.custom.title": "No custom tool available",
@ -34,6 +39,7 @@
"createTool.authMethod.type": "Authorization type",
"createTool.authMethod.types.apiKeyPlaceholder": "HTTP header name for API Key",
"createTool.authMethod.types.apiValuePlaceholder": "Enter API Key",
"createTool.authMethod.types.api_key": "API Key",
"createTool.authMethod.types.api_key_header": "Header",
"createTool.authMethod.types.api_key_query": "Query Param",
"createTool.authMethod.types.none": "None",

View File

@ -4,6 +4,7 @@
"blocks.assigner": "Variable Assigner",
"blocks.code": "Code",
"blocks.datasource": "Data Source",
"blocks.datasource-empty": "Empty Data Source",
"blocks.document-extractor": "Doc Extractor",
"blocks.end": "Output",
"blocks.http-request": "HTTP Request",
@ -22,6 +23,7 @@
"blocks.question-classifier": "Question Classifier",
"blocks.start": "User Input",
"blocks.template-transform": "Template",
"blocks.tool": "Tool",
"blocks.trigger-plugin": "Plugin Trigger",
"blocks.trigger-schedule": "Schedule Trigger",
"blocks.trigger-webhook": "Webhook Trigger",
@ -32,21 +34,25 @@
"blocksAbout.assigner": "The variable assignment node is used for assigning values to writable variables(like conversation variables).",
"blocksAbout.code": "Execute a piece of Python or NodeJS code to implement custom logic",
"blocksAbout.datasource": "Data Source About",
"blocksAbout.datasource-empty": "Empty Data Source placeholder",
"blocksAbout.document-extractor": "Used to parse uploaded documents into text content that is easily understandable by LLM.",
"blocksAbout.end": "Define the output and result type of a workflow",
"blocksAbout.http-request": "Allow server requests to be sent over the HTTP protocol",
"blocksAbout.if-else": "Allows you to split the workflow into two branches based on if/else conditions",
"blocksAbout.iteration": "Perform multiple steps on a list object until all results are outputted.",
"blocksAbout.iteration-start": "Iteration Start node",
"blocksAbout.knowledge-index": "Knowledge Base About",
"blocksAbout.knowledge-retrieval": "Allows you to query text content related to user questions from the Knowledge",
"blocksAbout.list-operator": "Used to filter or sort array content.",
"blocksAbout.llm": "Invoking large language models to answer questions or process natural language",
"blocksAbout.loop": "Execute a loop of logic until the termination condition is met or the maximum loop count is reached.",
"blocksAbout.loop-end": "Equivalent to \"break\". This node has no configuration items. When the loop body reaches this node, the loop terminates.",
"blocksAbout.loop-start": "Loop Start node",
"blocksAbout.parameter-extractor": "Use LLM to extract structured parameters from natural language for tool invocations or HTTP requests.",
"blocksAbout.question-classifier": "Define the classification conditions of user questions, LLM can define how the conversation progresses based on the classification description",
"blocksAbout.start": "Define the initial parameters for launching a workflow",
"blocksAbout.template-transform": "Convert data to string using Jinja template syntax",
"blocksAbout.tool": "Use external tools to extend workflow capabilities",
"blocksAbout.trigger-plugin": "Third-party integration trigger that starts workflows from external platform events",
"blocksAbout.trigger-schedule": "Time-based workflow trigger that starts workflows on a schedule",
"blocksAbout.trigger-webhook": "Webhook Trigger receives HTTP pushes from third-party systems to automatically trigger workflows.",