mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 09:58:04 +08:00
merge main
This commit is contained in:
@ -3,7 +3,6 @@
|
||||
import type { ReactNode } from 'react'
|
||||
import { usePathname, useRouter, useSearchParams } from 'next/navigation'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { SWRConfig } from 'swr'
|
||||
import {
|
||||
EDUCATION_VERIFY_URL_SEARCHPARAMS_ACTION,
|
||||
EDUCATION_VERIFYING_LOCALSTORAGE_ITEM,
|
||||
@ -11,12 +10,13 @@ import {
|
||||
import { fetchSetupStatus } from '@/service/common'
|
||||
import { resolvePostLoginRedirect } from '../signin/utils/post-login-redirect'
|
||||
|
||||
type SwrInitializerProps = {
|
||||
type AppInitializerProps = {
|
||||
children: ReactNode
|
||||
}
|
||||
const SwrInitializer = ({
|
||||
|
||||
export const AppInitializer = ({
|
||||
children,
|
||||
}: SwrInitializerProps) => {
|
||||
}: AppInitializerProps) => {
|
||||
const router = useRouter()
|
||||
const searchParams = useSearchParams()
|
||||
// Tokens are now stored in cookies, no need to check localStorage
|
||||
@ -69,20 +69,5 @@ const SwrInitializer = ({
|
||||
})()
|
||||
}, [isSetupFinished, router, pathname, searchParams])
|
||||
|
||||
return init
|
||||
? (
|
||||
<SWRConfig value={{
|
||||
shouldRetryOnError: false,
|
||||
revalidateOnFocus: false,
|
||||
dedupingInterval: 60000,
|
||||
focusThrottleInterval: 5000,
|
||||
provider: () => new Map(),
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
</SWRConfig>
|
||||
)
|
||||
: null
|
||||
return init ? children : null
|
||||
}
|
||||
|
||||
export default SwrInitializer
|
||||
@ -100,12 +100,12 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
setShowEditModal(false)
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('app.editDone'),
|
||||
message: t('editDone', { ns: 'app' }),
|
||||
})
|
||||
setAppDetail(app)
|
||||
}
|
||||
catch {
|
||||
notify({ type: 'error', message: t('app.editFailed') })
|
||||
notify({ type: 'error', message: t('editFailed', { ns: 'app' }) })
|
||||
}
|
||||
}, [appDetail, notify, setAppDetail, t])
|
||||
|
||||
@ -124,14 +124,14 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
setShowDuplicateModal(false)
|
||||
notify({
|
||||
type: 'success',
|
||||
message: t('app.newApp.appCreated'),
|
||||
message: t('newApp.appCreated', { ns: 'app' }),
|
||||
})
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
onPlanInfoChanged()
|
||||
getRedirection(true, newApp, replace)
|
||||
}
|
||||
catch {
|
||||
notify({ type: 'error', message: t('app.newApp.appCreateFailed') })
|
||||
notify({ type: 'error', message: t('newApp.appCreateFailed', { ns: 'app' }) })
|
||||
}
|
||||
}
|
||||
|
||||
@ -152,7 +152,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
catch {
|
||||
notify({ type: 'error', message: t('app.exportFailed') })
|
||||
notify({ type: 'error', message: t('exportFailed', { ns: 'app' }) })
|
||||
}
|
||||
}
|
||||
|
||||
@ -181,7 +181,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
setSecretEnvList(list)
|
||||
}
|
||||
catch {
|
||||
notify({ type: 'error', message: t('app.exportFailed') })
|
||||
notify({ type: 'error', message: t('exportFailed', { ns: 'app' }) })
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +190,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
return
|
||||
try {
|
||||
await deleteApp(appDetail.id)
|
||||
notify({ type: 'success', message: t('app.appDeleted') })
|
||||
notify({ type: 'success', message: t('appDeleted', { ns: 'app' }) })
|
||||
onPlanInfoChanged()
|
||||
setAppDetail()
|
||||
replace('/apps')
|
||||
@ -198,7 +198,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
catch (e: any) {
|
||||
notify({
|
||||
type: 'error',
|
||||
message: `${t('app.appDeleteFailed')}${'message' in e ? `: ${e.message}` : ''}`,
|
||||
message: `${t('appDeleteFailed', { ns: 'app' })}${'message' in e ? `: ${e.message}` : ''}`,
|
||||
})
|
||||
}
|
||||
setShowConfirmDelete(false)
|
||||
@ -212,7 +212,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
const primaryOperations = [
|
||||
{
|
||||
id: 'edit',
|
||||
title: t('app.editApp'),
|
||||
title: t('editApp', { ns: 'app' }),
|
||||
icon: <RiEditLine />,
|
||||
onClick: () => {
|
||||
setOpen(false)
|
||||
@ -222,7 +222,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
},
|
||||
{
|
||||
id: 'duplicate',
|
||||
title: t('app.duplicate'),
|
||||
title: t('duplicate', { ns: 'app' }),
|
||||
icon: <RiFileCopy2Line />,
|
||||
onClick: () => {
|
||||
setOpen(false)
|
||||
@ -232,7 +232,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
},
|
||||
{
|
||||
id: 'export',
|
||||
title: t('app.export'),
|
||||
title: t('export', { ns: 'app' }),
|
||||
icon: <RiFileDownloadLine />,
|
||||
onClick: exportCheck,
|
||||
},
|
||||
@ -243,7 +243,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
...(appDetail.mode === AppModeEnum.ADVANCED_CHAT || appDetail.mode === AppModeEnum.WORKFLOW)
|
||||
? [{
|
||||
id: 'import',
|
||||
title: t('workflow.common.importDSL'),
|
||||
title: t('common.importDSL', { ns: 'workflow' }),
|
||||
icon: <RiFileUploadLine />,
|
||||
onClick: () => {
|
||||
setOpen(false)
|
||||
@ -263,7 +263,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
// Delete operation
|
||||
{
|
||||
id: 'delete',
|
||||
title: t('common.operation.delete'),
|
||||
title: t('operation.delete', { ns: 'common' }),
|
||||
icon: <RiDeleteBinLine />,
|
||||
onClick: () => {
|
||||
setOpen(false)
|
||||
@ -277,7 +277,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
const switchOperation = (appDetail.mode === AppModeEnum.COMPLETION || appDetail.mode === AppModeEnum.CHAT)
|
||||
? {
|
||||
id: 'switch',
|
||||
title: t('app.switch'),
|
||||
title: t('switch', { ns: 'app' }),
|
||||
icon: <RiExchange2Line />,
|
||||
onClick: () => {
|
||||
setOpen(false)
|
||||
@ -331,14 +331,14 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
</div>
|
||||
<div className="system-2xs-medium-uppercase whitespace-nowrap text-text-tertiary">
|
||||
{appDetail.mode === AppModeEnum.ADVANCED_CHAT
|
||||
? t('app.types.advanced')
|
||||
? t('types.advanced', { ns: 'app' })
|
||||
: appDetail.mode === AppModeEnum.AGENT_CHAT
|
||||
? t('app.types.agent')
|
||||
? t('types.agent', { ns: 'app' })
|
||||
: appDetail.mode === AppModeEnum.CHAT
|
||||
? t('app.types.chatbot')
|
||||
? t('types.chatbot', { ns: 'app' })
|
||||
: appDetail.mode === AppModeEnum.COMPLETION
|
||||
? t('app.types.completion')
|
||||
: t('app.types.workflow')}
|
||||
? t('types.completion', { ns: 'app' })
|
||||
: t('types.workflow', { ns: 'app' })}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -364,7 +364,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
/>
|
||||
<div className="flex flex-1 flex-col items-start justify-center overflow-hidden">
|
||||
<div className="system-md-semibold w-full truncate text-text-secondary">{appDetail.name}</div>
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('app.types.advanced') : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('app.types.agent') : appDetail.mode === AppModeEnum.CHAT ? t('app.types.chatbot') : appDetail.mode === AppModeEnum.COMPLETION ? t('app.types.completion') : t('app.types.workflow')}</div>
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('types.advanced', { ns: 'app' }) : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('types.agent', { ns: 'app' }) : appDetail.mode === AppModeEnum.CHAT ? t('types.chatbot', { ns: 'app' }) : appDetail.mode === AppModeEnum.COMPLETION ? t('types.completion', { ns: 'app' }) : t('types.workflow', { ns: 'app' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* description */}
|
||||
@ -438,8 +438,8 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
)}
|
||||
{showConfirmDelete && (
|
||||
<Confirm
|
||||
title={t('app.deleteAppConfirmTitle')}
|
||||
content={t('app.deleteAppConfirmContent')}
|
||||
title={t('deleteAppConfirmTitle', { ns: 'app' })}
|
||||
content={t('deleteAppConfirmContent', { ns: 'app' })}
|
||||
isShow={showConfirmDelete}
|
||||
onConfirm={onConfirmDelete}
|
||||
onCancel={() => setShowConfirmDelete(false)}
|
||||
@ -462,8 +462,8 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
<Confirm
|
||||
type="info"
|
||||
isShow={showExportWarning}
|
||||
title={t('workflow.sidebar.exportWarning')}
|
||||
content={t('workflow.sidebar.exportWarningDesc')}
|
||||
title={t('sidebar.exportWarning', { ns: 'workflow' })}
|
||||
content={t('sidebar.exportWarningDesc', { ns: 'workflow' })}
|
||||
onConfirm={handleConfirmExport}
|
||||
onCancel={() => setShowExportWarning(false)}
|
||||
/>
|
||||
|
||||
@ -148,7 +148,7 @@ const AppOperations = ({
|
||||
>
|
||||
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
|
||||
<span className="system-xs-medium text-components-button-secondary-text">
|
||||
{t('common.operation.more')}
|
||||
{t('operation.more', { ns: 'common' })}
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
@ -183,7 +183,7 @@ const AppOperations = ({
|
||||
>
|
||||
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
|
||||
<span className="system-xs-medium text-components-button-secondary-text">
|
||||
{t('common.operation.more')}
|
||||
{t('operation.more', { ns: 'common' })}
|
||||
</span>
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
|
||||
@ -99,7 +99,7 @@ const AppSidebarDropdown = ({ navigation }: Props) => {
|
||||
<div className="flex w-full">
|
||||
<div className="system-md-semibold truncate text-text-secondary">{appDetail.name}</div>
|
||||
</div>
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('app.types.advanced') : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('app.types.agent') : appDetail.mode === AppModeEnum.CHAT ? t('app.types.chatbot') : appDetail.mode === AppModeEnum.COMPLETION ? t('app.types.completion') : t('app.types.workflow')}</div>
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('types.advanced', { ns: 'app' }) : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('types.agent', { ns: 'app' }) : appDetail.mode === AppModeEnum.CHAT ? t('types.chatbot', { ns: 'app' }) : appDetail.mode === AppModeEnum.COMPLETION ? t('types.completion', { ns: 'app' }) : t('types.workflow', { ns: 'app' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -98,7 +98,7 @@ export default function AppBasic({ icon, icon_background, name, isExternal, type
|
||||
<div className="system-2xs-medium-uppercase flex text-text-tertiary">{type}</div>
|
||||
)}
|
||||
{!hideType && !isExtraInLine && (
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">{isExternal ? t('dataset.externalTag') : type}</div>
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">{isExternal ? t('externalTag', { ns: 'dataset' }) : type}</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -73,14 +73,14 @@ const DropDown = ({
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
catch {
|
||||
Toast.notify({ type: 'error', message: t('app.exportFailed') })
|
||||
Toast.notify({ type: 'error', message: t('exportFailed', { ns: 'app' }) })
|
||||
}
|
||||
}, [dataset, exportPipelineConfig, handleTrigger, t])
|
||||
|
||||
const detectIsUsedByApp = useCallback(async () => {
|
||||
try {
|
||||
const { is_using: isUsedByApp } = await checkIsUsedInApp(dataset.id)
|
||||
setConfirmMessage(isUsedByApp ? t('dataset.datasetUsedByApp')! : t('dataset.deleteDatasetConfirmContent')!)
|
||||
setConfirmMessage(isUsedByApp ? t('datasetUsedByApp', { ns: 'dataset' })! : t('deleteDatasetConfirmContent', { ns: 'dataset' })!)
|
||||
setShowConfirmDelete(true)
|
||||
}
|
||||
catch (e: any) {
|
||||
@ -95,7 +95,7 @@ const DropDown = ({
|
||||
const onConfirmDelete = useCallback(async () => {
|
||||
try {
|
||||
await deleteDataset(dataset.id)
|
||||
Toast.notify({ type: 'success', message: t('dataset.datasetDeleted') })
|
||||
Toast.notify({ type: 'success', message: t('datasetDeleted', { ns: 'dataset' }) })
|
||||
invalidDatasetList()
|
||||
replace('/datasets')
|
||||
}
|
||||
@ -141,7 +141,7 @@ const DropDown = ({
|
||||
)}
|
||||
{showConfirmDelete && (
|
||||
<Confirm
|
||||
title={t('dataset.deleteDatasetConfirmTitle')}
|
||||
title={t('deleteDatasetConfirmTitle', { ns: 'dataset' })}
|
||||
content={confirmMessage}
|
||||
isShow={showConfirmDelete}
|
||||
onConfirm={onConfirmDelete}
|
||||
|
||||
@ -70,10 +70,10 @@ const DatasetInfo: FC<DatasetInfoProps> = ({
|
||||
{dataset.name}
|
||||
</div>
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">
|
||||
{isExternalProvider && t('dataset.externalTag')}
|
||||
{isExternalProvider && t('externalTag', { ns: 'dataset' })}
|
||||
{!isExternalProvider && isPipelinePublished && dataset.doc_form && dataset.indexing_technique && (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<span>{t(`dataset.chunkingMode.${DOC_FORM_TEXT[dataset.doc_form]}` as any) as string}</span>
|
||||
<span>{t(`chunkingMode.${DOC_FORM_TEXT[dataset.doc_form]}`, { ns: 'dataset' })}</span>
|
||||
<span>{formatIndexingTechniqueAndMethod(dataset.indexing_technique, dataset.retrieval_model_dict?.search_method)}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -26,13 +26,13 @@ const Menu = ({
|
||||
<div className="flex flex-col p-1">
|
||||
<MenuItem
|
||||
Icon={RiEditLine}
|
||||
name={t('common.operation.edit')}
|
||||
name={t('operation.edit', { ns: 'common' })}
|
||||
handleClick={openRenameModal}
|
||||
/>
|
||||
{runtimeMode === 'rag_pipeline' && (
|
||||
<MenuItem
|
||||
Icon={RiFileDownloadLine}
|
||||
name={t('datasetPipeline.operations.exportPipeline')}
|
||||
name={t('operations.exportPipeline', { ns: 'datasetPipeline' })}
|
||||
handleClick={handleExportPipeline}
|
||||
/>
|
||||
)}
|
||||
@ -43,7 +43,7 @@ const Menu = ({
|
||||
<div className="flex flex-col p-1">
|
||||
<MenuItem
|
||||
Icon={RiDeleteBinLine}
|
||||
name={t('common.operation.delete')}
|
||||
name={t('operation.delete', { ns: 'common' })}
|
||||
handleClick={detectIsUsedByApp}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@ -113,10 +113,10 @@ const DatasetSidebarDropdown = ({
|
||||
{dataset.name}
|
||||
</div>
|
||||
<div className="system-2xs-medium-uppercase text-text-tertiary">
|
||||
{isExternalProvider && t('dataset.externalTag')}
|
||||
{isExternalProvider && t('externalTag', { ns: 'dataset' })}
|
||||
{!isExternalProvider && dataset.doc_form && dataset.indexing_technique && (
|
||||
<div className="flex items-center gap-x-2">
|
||||
<span>{t(`dataset.chunkingMode.${DOC_FORM_TEXT[dataset.doc_form]}` as any) as string}</span>
|
||||
<span>{t(`chunkingMode.${DOC_FORM_TEXT[dataset.doc_form]}`, { ns: 'dataset' })}</span>
|
||||
<span>{formatIndexingTechniqueAndMethod(dataset.indexing_technique, dataset.retrieval_model_dict?.search_method)}</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -19,7 +19,7 @@ const TooltipContent = ({
|
||||
|
||||
return (
|
||||
<div className="flex items-center gap-x-1">
|
||||
<span className="system-xs-medium px-0.5 text-text-secondary">{expand ? t('layout.sidebar.collapseSidebar') : t('layout.sidebar.expandSidebar')}</span>
|
||||
<span className="system-xs-medium px-0.5 text-text-secondary">{expand ? t('sidebar.collapseSidebar', { ns: 'layout' }) : t('sidebar.expandSidebar', { ns: 'layout' })}</span>
|
||||
<div className="flex items-center gap-x-0.5">
|
||||
{
|
||||
TOGGLE_SHORTCUT.map(key => (
|
||||
|
||||
@ -22,8 +22,8 @@ const EditItem: FC<Props> = ({
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const avatar = type === EditItemType.Query ? <User className="h-6 w-6" /> : <Robot className="h-6 w-6" />
|
||||
const name = type === EditItemType.Query ? t('appAnnotation.addModal.queryName') : t('appAnnotation.addModal.answerName')
|
||||
const placeholder = type === EditItemType.Query ? t('appAnnotation.addModal.queryPlaceholder') : t('appAnnotation.addModal.answerPlaceholder')
|
||||
const name = type === EditItemType.Query ? t('addModal.queryName', { ns: 'appAnnotation' }) : t('addModal.answerName', { ns: 'appAnnotation' })
|
||||
const placeholder = type === EditItemType.Query ? t('addModal.queryPlaceholder', { ns: 'appAnnotation' }) : t('addModal.answerPlaceholder', { ns: 'appAnnotation' })
|
||||
|
||||
return (
|
||||
<div className="flex" onClick={e => e.stopPropagation()}>
|
||||
|
||||
@ -33,10 +33,10 @@ const AddAnnotationModal: FC<Props> = ({
|
||||
|
||||
const isValid = (payload: AnnotationItemBasic) => {
|
||||
if (!payload.question)
|
||||
return t('appAnnotation.errorMessage.queryRequired')
|
||||
return t('errorMessage.queryRequired', { ns: 'appAnnotation' })
|
||||
|
||||
if (!payload.answer)
|
||||
return t('appAnnotation.errorMessage.answerRequired')
|
||||
return t('errorMessage.answerRequired', { ns: 'appAnnotation' })
|
||||
|
||||
return true
|
||||
}
|
||||
@ -76,7 +76,7 @@ const AddAnnotationModal: FC<Props> = ({
|
||||
isShow={isShow}
|
||||
onHide={onHide}
|
||||
maxWidthClassName="!max-w-[480px]"
|
||||
title={t('appAnnotation.addModal.title') as string}
|
||||
title={t('addModal.title', { ns: 'appAnnotation' }) as string}
|
||||
body={(
|
||||
<div className="space-y-6 p-6 pb-4">
|
||||
<EditItem
|
||||
@ -104,11 +104,11 @@ const AddAnnotationModal: FC<Props> = ({
|
||||
className="flex items-center space-x-2"
|
||||
>
|
||||
<Checkbox id="create-next-checkbox" checked={isCreateNext} onCheck={() => setIsCreateNext(!isCreateNext)} />
|
||||
<div>{t('appAnnotation.addModal.createNext')}</div>
|
||||
<div>{t('addModal.createNext', { ns: 'appAnnotation' })}</div>
|
||||
</div>
|
||||
<div className="mt-2 flex space-x-2">
|
||||
<Button className="h-7 text-xs" onClick={onHide}>{t('common.operation.cancel')}</Button>
|
||||
<Button className="h-7 text-xs" variant="primary" onClick={handleSave} loading={isSaving} disabled={isAnnotationFull}>{t('common.operation.add')}</Button>
|
||||
<Button className="h-7 text-xs" onClick={onHide}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Button className="h-7 text-xs" variant="primary" onClick={handleSave} loading={isSaving} disabled={isAnnotationFull}>{t('operation.add', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -7,7 +7,7 @@ import Confirm from '@/app/components/base/confirm'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
const i18nPrefix = 'appAnnotation.batchAction'
|
||||
const i18nPrefix = 'batchAction'
|
||||
|
||||
type IBatchActionProps = {
|
||||
className?: string
|
||||
@ -45,27 +45,27 @@ const BatchAction: FC<IBatchActionProps> = ({
|
||||
<span className="flex h-5 w-5 items-center justify-center rounded-md bg-text-accent px-1 py-0.5 text-xs font-medium text-text-primary-on-surface">
|
||||
{selectedIds.length}
|
||||
</span>
|
||||
<span className="text-[13px] font-semibold leading-[16px] text-text-accent">{t(`${i18nPrefix}.selected`)}</span>
|
||||
<span className="text-[13px] font-semibold leading-[16px] text-text-accent">{t(`${i18nPrefix}.selected`, { ns: 'appAnnotation' })}</span>
|
||||
</div>
|
||||
<Divider type="vertical" className="mx-0.5 h-3.5 bg-divider-regular" />
|
||||
<div className="flex cursor-pointer items-center gap-x-0.5 px-3 py-2" onClick={showDeleteConfirm}>
|
||||
<RiDeleteBinLine className="h-4 w-4 text-components-button-destructive-ghost-text" />
|
||||
<button type="button" className="px-0.5 text-[13px] font-medium leading-[16px] text-components-button-destructive-ghost-text">
|
||||
{t('common.operation.delete')}
|
||||
{t('operation.delete', { ns: 'common' })}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Divider type="vertical" className="mx-0.5 h-3.5 bg-divider-regular" />
|
||||
<button type="button" className="px-3.5 py-2 text-[13px] font-medium leading-[16px] text-components-button-ghost-text" onClick={onCancel}>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</button>
|
||||
</div>
|
||||
{
|
||||
isShowDeleteConfirm && (
|
||||
<Confirm
|
||||
isShow
|
||||
title={t('appAnnotation.list.delete.title')}
|
||||
confirmText={t('common.operation.delete')}
|
||||
title={t('list.delete.title', { ns: 'appAnnotation' })}
|
||||
confirmText={t('operation.delete', { ns: 'common' })}
|
||||
onConfirm={handleBatchDelete}
|
||||
onCancel={hideDeleteConfirm}
|
||||
isLoading={isDeleting}
|
||||
|
||||
@ -33,36 +33,36 @@ const CSVDownload: FC = () => {
|
||||
|
||||
return (
|
||||
<div className="mt-6">
|
||||
<div className="system-sm-medium text-text-primary">{t('share.generation.csvStructureTitle')}</div>
|
||||
<div className="system-sm-medium text-text-primary">{t('generation.csvStructureTitle', { ns: 'share' })}</div>
|
||||
<div className="mt-2 max-h-[500px] overflow-auto">
|
||||
<table className="w-full table-fixed border-separate border-spacing-0 rounded-lg border border-divider-regular text-xs">
|
||||
<thead className="text-text-tertiary">
|
||||
<tr>
|
||||
<td className="h-9 border-b border-divider-regular pl-3 pr-2">{t('appAnnotation.batchModal.question')}</td>
|
||||
<td className="h-9 border-b border-divider-regular pl-3 pr-2">{t('appAnnotation.batchModal.answer')}</td>
|
||||
<td className="h-9 border-b border-divider-regular pl-3 pr-2">{t('batchModal.question', { ns: 'appAnnotation' })}</td>
|
||||
<td className="h-9 border-b border-divider-regular pl-3 pr-2">{t('batchModal.answer', { ns: 'appAnnotation' })}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="text-text-secondary">
|
||||
<tr>
|
||||
<td className="h-9 border-b border-divider-subtle pl-3 pr-2 text-[13px]">
|
||||
{t('appAnnotation.batchModal.question')}
|
||||
{t('batchModal.question', { ns: 'appAnnotation' })}
|
||||
{' '}
|
||||
1
|
||||
</td>
|
||||
<td className="h-9 border-b border-divider-subtle pl-3 pr-2 text-[13px]">
|
||||
{t('appAnnotation.batchModal.answer')}
|
||||
{t('batchModal.answer', { ns: 'appAnnotation' })}
|
||||
{' '}
|
||||
1
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="h-9 pl-3 pr-2 text-[13px]">
|
||||
{t('appAnnotation.batchModal.question')}
|
||||
{t('batchModal.question', { ns: 'appAnnotation' })}
|
||||
{' '}
|
||||
2
|
||||
</td>
|
||||
<td className="h-9 pl-3 pr-2 text-[13px]">
|
||||
{t('appAnnotation.batchModal.answer')}
|
||||
{t('batchModal.answer', { ns: 'appAnnotation' })}
|
||||
{' '}
|
||||
2
|
||||
</td>
|
||||
@ -79,7 +79,7 @@ const CSVDownload: FC = () => {
|
||||
>
|
||||
<div className="system-xs-medium flex h-[18px] items-center space-x-1 text-text-accent">
|
||||
<DownloadIcon className="mr-1 h-3 w-3" />
|
||||
{t('appAnnotation.batchModal.template')}
|
||||
{t('batchModal.template', { ns: 'appAnnotation' })}
|
||||
</div>
|
||||
</CSVDownloader>
|
||||
</div>
|
||||
|
||||
@ -50,7 +50,7 @@ const CSVUploader: FC<Props> = ({
|
||||
return
|
||||
const files = [...e.dataTransfer.files]
|
||||
if (files.length > 1) {
|
||||
notify({ type: 'error', message: t('datasetCreation.stepOne.uploader.validation.count') })
|
||||
notify({ type: 'error', message: t('stepOne.uploader.validation.count', { ns: 'datasetCreation' }) })
|
||||
return
|
||||
}
|
||||
updateFile(files[0])
|
||||
@ -98,8 +98,8 @@ const CSVUploader: FC<Props> = ({
|
||||
<div className="flex w-full items-center justify-center space-x-2">
|
||||
<CSVIcon className="shrink-0" />
|
||||
<div className="text-text-tertiary">
|
||||
{t('appAnnotation.batchModal.csvUploadTitle')}
|
||||
<span className="cursor-pointer text-text-accent" onClick={selectHandle}>{t('appAnnotation.batchModal.browse')}</span>
|
||||
{t('batchModal.csvUploadTitle', { ns: 'appAnnotation' })}
|
||||
<span className="cursor-pointer text-text-accent" onClick={selectHandle}>{t('batchModal.browse', { ns: 'appAnnotation' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
{dragging && <div ref={dragRef} className="absolute left-0 top-0 h-full w-full" />}
|
||||
@ -113,7 +113,7 @@ const CSVUploader: FC<Props> = ({
|
||||
<span className="shrink-0 text-text-tertiary">.csv</span>
|
||||
</div>
|
||||
<div className="hidden items-center group-hover:flex">
|
||||
<Button variant="secondary" onClick={selectHandle}>{t('datasetCreation.stepOne.uploader.change')}</Button>
|
||||
<Button variant="secondary" onClick={selectHandle}>{t('stepOne.uploader.change', { ns: 'datasetCreation' })}</Button>
|
||||
<div className="mx-2 h-4 w-px bg-divider-regular" />
|
||||
<div className="cursor-pointer p-2" onClick={removeFile} data-testid="remove-file-button">
|
||||
<RiDeleteBinLine className="h-4 w-4 text-text-tertiary" />
|
||||
|
||||
@ -54,15 +54,15 @@ const BatchModal: FC<IBatchModalProps> = ({
|
||||
if (res.job_status === ProcessStatus.WAITING || res.job_status === ProcessStatus.PROCESSING)
|
||||
setTimeout(() => checkProcess(res.job_id), 2500)
|
||||
if (res.job_status === ProcessStatus.ERROR)
|
||||
notify({ type: 'error', message: `${t('appAnnotation.batchModal.runError')}` })
|
||||
notify({ type: 'error', message: `${t('batchModal.runError', { ns: 'appAnnotation' })}` })
|
||||
if (res.job_status === ProcessStatus.COMPLETED) {
|
||||
notify({ type: 'success', message: `${t('appAnnotation.batchModal.completed')}` })
|
||||
notify({ type: 'success', message: `${t('batchModal.completed', { ns: 'appAnnotation' })}` })
|
||||
onAdded()
|
||||
onCancel()
|
||||
}
|
||||
}
|
||||
catch (e: any) {
|
||||
notify({ type: 'error', message: `${t('appAnnotation.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` })
|
||||
notify({ type: 'error', message: `${t('batchModal.runError', { ns: 'appAnnotation' })}${'message' in e ? `: ${e.message}` : ''}` })
|
||||
}
|
||||
}
|
||||
|
||||
@ -78,7 +78,7 @@ const BatchModal: FC<IBatchModalProps> = ({
|
||||
checkProcess(res.job_id)
|
||||
}
|
||||
catch (e: any) {
|
||||
notify({ type: 'error', message: `${t('appAnnotation.batchModal.runError')}${'message' in e ? `: ${e.message}` : ''}` })
|
||||
notify({ type: 'error', message: `${t('batchModal.runError', { ns: 'appAnnotation' })}${'message' in e ? `: ${e.message}` : ''}` })
|
||||
}
|
||||
}
|
||||
|
||||
@ -90,7 +90,7 @@ const BatchModal: FC<IBatchModalProps> = ({
|
||||
|
||||
return (
|
||||
<Modal isShow={isShow} onClose={noop} className="!max-w-[520px] !rounded-xl px-8 py-6">
|
||||
<div className="system-xl-medium relative pb-1 text-text-primary">{t('appAnnotation.batchModal.title')}</div>
|
||||
<div className="system-xl-medium relative pb-1 text-text-primary">{t('batchModal.title', { ns: 'appAnnotation' })}</div>
|
||||
<div className="absolute right-4 top-4 cursor-pointer p-2" onClick={onCancel}>
|
||||
<RiCloseLine className="h-4 w-4 text-text-tertiary" />
|
||||
</div>
|
||||
@ -108,7 +108,7 @@ const BatchModal: FC<IBatchModalProps> = ({
|
||||
|
||||
<div className="mt-[28px] flex justify-end pt-6">
|
||||
<Button className="system-sm-medium mr-2 text-text-tertiary" onClick={onCancel}>
|
||||
{t('appAnnotation.batchModal.cancel')}
|
||||
{t('batchModal.cancel', { ns: 'appAnnotation' })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
@ -116,7 +116,7 @@ const BatchModal: FC<IBatchModalProps> = ({
|
||||
disabled={isAnnotationFull || !currentCSV}
|
||||
loading={importStatus === ProcessStatus.PROCESSING || importStatus === ProcessStatus.WAITING}
|
||||
>
|
||||
{t('appAnnotation.batchModal.run')}
|
||||
{t('batchModal.run', { ns: 'appAnnotation' })}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@ -4,13 +4,16 @@ import ClearAllAnnotationsConfirmModal from './index'
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => {
|
||||
t: (key: string, options?: { ns?: string }) => {
|
||||
const translations: Record<string, string> = {
|
||||
'appAnnotation.table.header.clearAllConfirm': 'Clear all annotations?',
|
||||
'common.operation.confirm': 'Confirm',
|
||||
'common.operation.cancel': 'Cancel',
|
||||
'table.header.clearAllConfirm': 'Clear all annotations?',
|
||||
'operation.confirm': 'Confirm',
|
||||
'operation.cancel': 'Cancel',
|
||||
}
|
||||
return translations[key] || key
|
||||
if (translations[key])
|
||||
return translations[key]
|
||||
const prefix = options?.ns ? `${options.ns}.` : ''
|
||||
return `${prefix}${key}`
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
@ -24,7 +24,7 @@ const ClearAllAnnotationsConfirmModal: FC<Props> = ({
|
||||
onCancel={onHide}
|
||||
onConfirm={onConfirm}
|
||||
type="danger"
|
||||
title={t('appAnnotation.table.header.clearAllConfirm')}
|
||||
title={t('table.header.clearAllConfirm', { ns: 'appAnnotation' })}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -43,9 +43,9 @@ const EditItem: FC<Props> = ({
|
||||
const [newContent, setNewContent] = useState('')
|
||||
const showNewContent = newContent && newContent !== content
|
||||
const avatar = type === EditItemType.Query ? <User className="h-6 w-6" /> : <Robot className="h-6 w-6" />
|
||||
const name = type === EditItemType.Query ? t('appAnnotation.editModal.queryName') : t('appAnnotation.editModal.answerName')
|
||||
const editTitle = type === EditItemType.Query ? t('appAnnotation.editModal.yourQuery') : t('appAnnotation.editModal.yourAnswer')
|
||||
const placeholder = type === EditItemType.Query ? t('appAnnotation.editModal.queryPlaceholder') : t('appAnnotation.editModal.answerPlaceholder')
|
||||
const name = type === EditItemType.Query ? t('editModal.queryName', { ns: 'appAnnotation' }) : t('editModal.answerName', { ns: 'appAnnotation' })
|
||||
const editTitle = type === EditItemType.Query ? t('editModal.yourQuery', { ns: 'appAnnotation' }) : t('editModal.yourAnswer', { ns: 'appAnnotation' })
|
||||
const placeholder = type === EditItemType.Query ? t('editModal.queryPlaceholder', { ns: 'appAnnotation' }) : t('editModal.answerPlaceholder', { ns: 'appAnnotation' })
|
||||
const [isEdit, setIsEdit] = useState(false)
|
||||
|
||||
// Reset newContent when content prop changes
|
||||
@ -95,7 +95,7 @@ const EditItem: FC<Props> = ({
|
||||
}}
|
||||
>
|
||||
<RiEditLine className="mr-1 h-3.5 w-3.5" />
|
||||
<div>{t('common.operation.edit')}</div>
|
||||
<div>{t('operation.edit', { ns: 'common' })}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -119,7 +119,7 @@ const EditItem: FC<Props> = ({
|
||||
<div className="h-3.5 w-3.5">
|
||||
<RiDeleteBinLine className="h-3.5 w-3.5" />
|
||||
</div>
|
||||
<div>{t('common.operation.delete')}</div>
|
||||
<div>{t('operation.delete', { ns: 'common' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@ -136,8 +136,8 @@ const EditItem: FC<Props> = ({
|
||||
autoFocus
|
||||
/>
|
||||
<div className="mt-2 flex space-x-2">
|
||||
<Button size="small" variant="primary" onClick={handleSave}>{t('common.operation.save')}</Button>
|
||||
<Button size="small" onClick={handleCancel}>{t('common.operation.cancel')}</Button>
|
||||
<Button size="small" variant="primary" onClick={handleSave}>{t('operation.save', { ns: 'common' })}</Button>
|
||||
<Button size="small" onClick={handleCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -73,12 +73,12 @@ const EditAnnotationModal: FC<Props> = ({
|
||||
}
|
||||
|
||||
Toast.notify({
|
||||
message: t('common.api.actionSuccess') as string,
|
||||
message: t('api.actionSuccess', { ns: 'common' }) as string,
|
||||
type: 'success',
|
||||
})
|
||||
}
|
||||
catch (error) {
|
||||
const fallbackMessage = t('common.api.actionFailed') as string
|
||||
const fallbackMessage = t('api.actionFailed', { ns: 'common' }) as string
|
||||
const message = error instanceof Error && error.message ? error.message : fallbackMessage
|
||||
Toast.notify({
|
||||
message,
|
||||
@ -96,7 +96,7 @@ const EditAnnotationModal: FC<Props> = ({
|
||||
isShow={isShow}
|
||||
onHide={onHide}
|
||||
maxWidthClassName="!max-w-[480px]"
|
||||
title={t('appAnnotation.editModal.title') as string}
|
||||
title={t('editModal.title', { ns: 'appAnnotation' }) as string}
|
||||
body={(
|
||||
<div>
|
||||
<div className="space-y-6 p-6 pb-4">
|
||||
@ -120,7 +120,7 @@ const EditAnnotationModal: FC<Props> = ({
|
||||
setShowModal(false)
|
||||
onHide()
|
||||
}}
|
||||
title={t('appDebug.feature.annotation.removeConfirm')}
|
||||
title={t('feature.annotation.removeConfirm', { ns: 'appDebug' })}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -142,13 +142,13 @@ const EditAnnotationModal: FC<Props> = ({
|
||||
onClick={() => setShowModal(true)}
|
||||
>
|
||||
<MessageCheckRemove />
|
||||
<div>{t('appAnnotation.editModal.removeThisCache')}</div>
|
||||
<div>{t('editModal.removeThisCache', { ns: 'appAnnotation' })}</div>
|
||||
</div>
|
||||
{createdAt && (
|
||||
<div>
|
||||
{t('appAnnotation.editModal.createdAt')}
|
||||
{t('editModal.createdAt', { ns: 'appAnnotation' })}
|
||||
|
||||
{formatTime(createdAt, t('appLog.dateTimeFormat') as string)}
|
||||
{formatTime(createdAt, t('dateTimeFormat', { ns: 'appLog' }) as string)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -18,11 +18,11 @@ const EmptyElement: FC = () => {
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<div className="box-border h-fit w-[560px] rounded-2xl bg-background-section-burn px-5 py-4">
|
||||
<span className="system-md-semibold text-text-secondary">
|
||||
{t('appAnnotation.noData.title')}
|
||||
{t('noData.title', { ns: 'appAnnotation' })}
|
||||
<ThreeDotsIcon className="relative -left-1.5 -top-3 inline" />
|
||||
</span>
|
||||
<div className="system-sm-regular mt-2 text-text-tertiary">
|
||||
{t('appAnnotation.noData.description')}
|
||||
{t('noData.description', { ns: 'appAnnotation' })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -33,7 +33,7 @@ const Filter: FC<IFilterProps> = ({
|
||||
showLeftIcon
|
||||
showClearIcon
|
||||
value={queryParams.keyword}
|
||||
placeholder={t('common.operation.search')!}
|
||||
placeholder={t('operation.search', { ns: 'common' })!}
|
||||
onChange={(e) => {
|
||||
setQueryParams({ ...queryParams, keyword: e.target.value })
|
||||
}}
|
||||
|
||||
@ -108,12 +108,12 @@ const HeaderOptions: FC<Props> = ({
|
||||
}}
|
||||
>
|
||||
<FilePlus02 className="h-4 w-4 text-text-tertiary" />
|
||||
<span className="system-sm-regular grow text-left text-text-secondary">{t('appAnnotation.table.header.bulkImport')}</span>
|
||||
<span className="system-sm-regular grow text-left text-text-secondary">{t('table.header.bulkImport', { ns: 'appAnnotation' })}</span>
|
||||
</button>
|
||||
<Menu as="div" className="relative h-full w-full">
|
||||
<MenuButton className="mx-1 flex h-9 w-[calc(100%_-_8px)] cursor-pointer items-center space-x-2 rounded-lg px-3 py-2 hover:bg-components-panel-on-panel-item-bg-hover disabled:opacity-50">
|
||||
<FileDownload02 className="h-4 w-4 text-text-tertiary" />
|
||||
<span className="system-sm-regular grow text-left text-text-secondary">{t('appAnnotation.table.header.bulkExport')}</span>
|
||||
<span className="system-sm-regular grow text-left text-text-secondary">{t('table.header.bulkExport', { ns: 'appAnnotation' })}</span>
|
||||
<ChevronRight className="h-[14px] w-[14px] shrink-0 text-text-tertiary" />
|
||||
</MenuButton>
|
||||
<Transition
|
||||
@ -156,7 +156,7 @@ const HeaderOptions: FC<Props> = ({
|
||||
>
|
||||
<RiDeleteBinLine className="h-4 w-4" />
|
||||
<span className="system-sm-regular grow text-left">
|
||||
{t('appAnnotation.table.header.clearAll')}
|
||||
{t('table.header.clearAll', { ns: 'appAnnotation' })}
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -169,7 +169,7 @@ const HeaderOptions: FC<Props> = ({
|
||||
<div className="flex space-x-2">
|
||||
<Button variant="primary" onClick={() => setShowAddModal(true)}>
|
||||
<RiAddLine className="mr-0.5 h-4 w-4" />
|
||||
<div>{t('appAnnotation.table.header.addAnnotation')}</div>
|
||||
<div>{t('table.header.addAnnotation', { ns: 'appAnnotation' })}</div>
|
||||
</Button>
|
||||
<CustomPopover
|
||||
htmlContent={<Operations />}
|
||||
|
||||
@ -98,14 +98,14 @@ const Annotation: FC<Props> = (props) => {
|
||||
|
||||
const handleAdd = async (payload: AnnotationItemBasic) => {
|
||||
await addAnnotation(appDetail.id, payload)
|
||||
Toast.notify({ message: t('common.api.actionSuccess'), type: 'success' })
|
||||
Toast.notify({ message: t('api.actionSuccess', { ns: 'common' }), type: 'success' })
|
||||
fetchList()
|
||||
setControlUpdateList(Date.now())
|
||||
}
|
||||
|
||||
const handleRemove = async (id: string) => {
|
||||
await delAnnotation(appDetail.id, id)
|
||||
Toast.notify({ message: t('common.api.actionSuccess'), type: 'success' })
|
||||
Toast.notify({ message: t('api.actionSuccess', { ns: 'common' }), type: 'success' })
|
||||
fetchList()
|
||||
setControlUpdateList(Date.now())
|
||||
}
|
||||
@ -113,13 +113,13 @@ const Annotation: FC<Props> = (props) => {
|
||||
const handleBatchDelete = async () => {
|
||||
try {
|
||||
await delAnnotations(appDetail.id, selectedIds)
|
||||
Toast.notify({ message: t('common.api.actionSuccess'), type: 'success' })
|
||||
Toast.notify({ message: t('api.actionSuccess', { ns: 'common' }), type: 'success' })
|
||||
fetchList()
|
||||
setControlUpdateList(Date.now())
|
||||
setSelectedIds([])
|
||||
}
|
||||
catch (e: any) {
|
||||
Toast.notify({ type: 'error', message: e.message || t('common.api.actionFailed') })
|
||||
Toast.notify({ type: 'error', message: e.message || t('api.actionFailed', { ns: 'common' }) })
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,7 +132,7 @@ const Annotation: FC<Props> = (props) => {
|
||||
if (!currItem)
|
||||
return
|
||||
await editAnnotation(appDetail.id, currItem.id, { question, answer })
|
||||
Toast.notify({ message: t('common.api.actionSuccess'), type: 'success' })
|
||||
Toast.notify({ message: t('api.actionSuccess', { ns: 'common' }), type: 'success' })
|
||||
fetchList()
|
||||
setControlUpdateList(Date.now())
|
||||
}
|
||||
@ -144,7 +144,7 @@ const Annotation: FC<Props> = (props) => {
|
||||
|
||||
return (
|
||||
<div className="flex h-full flex-col">
|
||||
<p className="system-sm-regular text-text-tertiary">{t('appLog.description')}</p>
|
||||
<p className="system-sm-regular text-text-tertiary">{t('description', { ns: 'appLog' })}</p>
|
||||
<div className="relative flex h-full flex-1 flex-col py-4">
|
||||
<Filter appId={appDetail.id} queryParams={queryParams} setQueryParams={setQueryParams}>
|
||||
<div className="flex items-center space-x-2">
|
||||
@ -152,7 +152,7 @@ const Annotation: FC<Props> = (props) => {
|
||||
<>
|
||||
<div className={cn(!annotationConfig?.enabled && 'pr-2', 'flex h-7 items-center space-x-1 rounded-lg border border-components-panel-border bg-components-panel-bg-blur pl-2')}>
|
||||
<MessageFast className="h-4 w-4 text-util-colors-indigo-indigo-600" />
|
||||
<div className="system-sm-medium text-text-primary">{t('appAnnotation.name')}</div>
|
||||
<div className="system-sm-medium text-text-primary">{t('name', { ns: 'appAnnotation' })}</div>
|
||||
<Switch
|
||||
key={controlRefreshSwitch}
|
||||
defaultValue={annotationConfig?.enabled}
|
||||
@ -171,7 +171,7 @@ const Annotation: FC<Props> = (props) => {
|
||||
await ensureJobCompleted(jobId, AnnotationEnableStatus.disable)
|
||||
await fetchAnnotationConfig()
|
||||
Toast.notify({
|
||||
message: t('common.api.actionSuccess'),
|
||||
message: t('api.actionSuccess', { ns: 'common' }),
|
||||
type: 'success',
|
||||
})
|
||||
}
|
||||
@ -264,7 +264,7 @@ const Annotation: FC<Props> = (props) => {
|
||||
|
||||
await fetchAnnotationConfig()
|
||||
Toast.notify({
|
||||
message: t('common.api.actionSuccess'),
|
||||
message: t('api.actionSuccess', { ns: 'common' }),
|
||||
type: 'success',
|
||||
})
|
||||
setIsShowEdit(false)
|
||||
|
||||
@ -68,11 +68,11 @@ const List: FC<Props> = ({
|
||||
onCheck={handleSelectAll}
|
||||
/>
|
||||
</td>
|
||||
<td className="w-5 whitespace-nowrap bg-background-section-burn pl-2 pr-1">{t('appAnnotation.table.header.question')}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('appAnnotation.table.header.answer')}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('appAnnotation.table.header.createdAt')}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('appAnnotation.table.header.hits')}</td>
|
||||
<td className="w-[96px] whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3">{t('appAnnotation.table.header.actions')}</td>
|
||||
<td className="w-5 whitespace-nowrap bg-background-section-burn pl-2 pr-1">{t('table.header.question', { ns: 'appAnnotation' })}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('table.header.answer', { ns: 'appAnnotation' })}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('table.header.createdAt', { ns: 'appAnnotation' })}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('table.header.hits', { ns: 'appAnnotation' })}</td>
|
||||
<td className="w-[96px] whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3">{t('table.header.actions', { ns: 'appAnnotation' })}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="system-sm-regular text-text-secondary">
|
||||
@ -110,7 +110,7 @@ const List: FC<Props> = ({
|
||||
>
|
||||
{item.answer}
|
||||
</td>
|
||||
<td className="p-3 pr-2">{formatTime(item.created_at, t('appLog.dateTimeFormat') as string)}</td>
|
||||
<td className="p-3 pr-2">{formatTime(item.created_at, t('dateTimeFormat', { ns: 'appLog' }) as string)}</td>
|
||||
<td className="p-3 pr-2">{item.hit_count}</td>
|
||||
<td className="w-[96px] p-3 pr-2" onClick={e => e.stopPropagation()}>
|
||||
{/* Actions */}
|
||||
|
||||
@ -4,13 +4,16 @@ import RemoveAnnotationConfirmModal from './index'
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => {
|
||||
t: (key: string, options?: { ns?: string }) => {
|
||||
const translations: Record<string, string> = {
|
||||
'appDebug.feature.annotation.removeConfirm': 'Remove annotation?',
|
||||
'common.operation.confirm': 'Confirm',
|
||||
'common.operation.cancel': 'Cancel',
|
||||
'feature.annotation.removeConfirm': 'Remove annotation?',
|
||||
'operation.confirm': 'Confirm',
|
||||
'operation.cancel': 'Cancel',
|
||||
}
|
||||
return translations[key] || key
|
||||
if (translations[key])
|
||||
return translations[key]
|
||||
const prefix = options?.ns ? `${options.ns}.` : ''
|
||||
return `${prefix}${key}`
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
@ -22,7 +22,7 @@ const RemoveAnnotationConfirmModal: FC<Props> = ({
|
||||
isShow={isShow}
|
||||
onCancel={onHide}
|
||||
onConfirm={onRemove}
|
||||
title={t('appDebug.feature.annotation.removeConfirm')}
|
||||
title={t('feature.annotation.removeConfirm', { ns: 'appDebug' })}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -11,7 +11,7 @@ const HitHistoryNoData: FC = () => {
|
||||
<div className="inline-block rounded-lg border border-divider-subtle p-3">
|
||||
<ClockFastForward className="h-5 w-5 text-text-tertiary" />
|
||||
</div>
|
||||
<div className="system-sm-regular text-text-tertiary">{t('appAnnotation.viewModal.noHitHistory')}</div>
|
||||
<div className="system-sm-regular text-text-tertiary">{t('viewModal.noHitHistory', { ns: 'appAnnotation' })}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -81,20 +81,20 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||
}, [id, isShow])
|
||||
|
||||
const tabs = [
|
||||
{ value: TabType.annotation, text: t('appAnnotation.viewModal.annotatedResponse') },
|
||||
{ value: TabType.annotation, text: t('viewModal.annotatedResponse', { ns: 'appAnnotation' }) },
|
||||
{
|
||||
value: TabType.hitHistory,
|
||||
text: (
|
||||
hitHistoryList.length > 0
|
||||
? (
|
||||
<div className="flex items-center space-x-1">
|
||||
<div>{t('appAnnotation.viewModal.hitHistory')}</div>
|
||||
<div>{t('viewModal.hitHistory', { ns: 'appAnnotation' })}</div>
|
||||
<Badge
|
||||
text={`${total} ${t(`appAnnotation.viewModal.hit${hitHistoryList.length > 1 ? 's' : ''}`)}`}
|
||||
text={`${total} ${t(`viewModal.hit${hitHistoryList.length > 1 ? 's' : ''}`, { ns: 'appAnnotation' })}`}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
: t('appAnnotation.viewModal.hitHistory')
|
||||
: t('viewModal.hitHistory', { ns: 'appAnnotation' })
|
||||
),
|
||||
},
|
||||
]
|
||||
@ -139,12 +139,12 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||
<table className={cn('w-full min-w-[440px] border-collapse border-0')}>
|
||||
<thead className="system-xs-medium-uppercase text-text-tertiary">
|
||||
<tr>
|
||||
<td className="w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1">{t('appAnnotation.hitHistoryTable.query')}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('appAnnotation.hitHistoryTable.match')}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('appAnnotation.hitHistoryTable.response')}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('appAnnotation.hitHistoryTable.source')}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('appAnnotation.hitHistoryTable.score')}</td>
|
||||
<td className="w-[160px] whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3">{t('appAnnotation.hitHistoryTable.time')}</td>
|
||||
<td className="w-5 whitespace-nowrap rounded-l-lg bg-background-section-burn pl-2 pr-1">{t('hitHistoryTable.query', { ns: 'appAnnotation' })}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('hitHistoryTable.match', { ns: 'appAnnotation' })}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('hitHistoryTable.response', { ns: 'appAnnotation' })}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('hitHistoryTable.source', { ns: 'appAnnotation' })}</td>
|
||||
<td className="whitespace-nowrap bg-background-section-burn py-1.5 pl-3">{t('hitHistoryTable.score', { ns: 'appAnnotation' })}</td>
|
||||
<td className="w-[160px] whitespace-nowrap rounded-r-lg bg-background-section-burn py-1.5 pl-3">{t('hitHistoryTable.time', { ns: 'appAnnotation' })}</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody className="system-sm-regular text-text-secondary">
|
||||
@ -173,7 +173,7 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||
</td>
|
||||
<td className="p-3 pr-2">{item.source}</td>
|
||||
<td className="p-3 pr-2">{item.score ? item.score.toFixed(2) : '-'}</td>
|
||||
<td className="p-3 pr-2">{formatTime(item.created_at, t('appLog.dateTimeFormat') as string)}</td>
|
||||
<td className="p-3 pr-2">{formatTime(item.created_at, t('dateTimeFormat', { ns: 'appLog' }) as string)}</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
@ -220,7 +220,7 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||
setShowModal(false)
|
||||
onHide()
|
||||
}}
|
||||
title={t('appDebug.feature.annotation.removeConfirm')}
|
||||
title={t('feature.annotation.removeConfirm', { ns: 'appDebug' })}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
@ -232,12 +232,12 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||
onClick={() => setShowModal(true)}
|
||||
>
|
||||
<MessageCheckRemove />
|
||||
<div>{t('appAnnotation.editModal.removeThisCache')}</div>
|
||||
<div>{t('editModal.removeThisCache', { ns: 'appAnnotation' })}</div>
|
||||
</div>
|
||||
<div>
|
||||
{t('appAnnotation.editModal.createdAt')}
|
||||
{t('editModal.createdAt', { ns: 'appAnnotation' })}
|
||||
|
||||
{formatTime(createdAt, t('appLog.dateTimeFormat') as string)}
|
||||
{formatTime(createdAt, t('dateTimeFormat', { ns: 'appLog' }) as string)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -49,14 +49,14 @@ export default function AddMemberOrGroupDialog() {
|
||||
<PortalToFollowElemTrigger asChild>
|
||||
<Button variant="ghost-accent" size="small" className="flex shrink-0 items-center gap-x-0.5" onClick={() => setOpen(!open)}>
|
||||
<RiAddCircleFill className="h-4 w-4" />
|
||||
<span>{t('common.operation.add')}</span>
|
||||
<span>{t('operation.add', { ns: 'common' })}</span>
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
{open && <FloatingOverlay />}
|
||||
<PortalToFollowElemContent className="z-[100]">
|
||||
<div className="relative flex max-h-[400px] w-[400px] flex-col overflow-y-auto rounded-xl border-[0.5px] border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-[5px]">
|
||||
<div className="sticky top-0 z-10 bg-components-panel-bg-blur p-2 pb-0.5 backdrop-blur-[5px]">
|
||||
<Input value={keyword} onChange={handleKeywordChange} showLeftIcon placeholder={t('app.accessControlDialog.operateGroupAndMember.searchPlaceholder') as string} />
|
||||
<Input value={keyword} onChange={handleKeywordChange} showLeftIcon placeholder={t('accessControlDialog.operateGroupAndMember.searchPlaceholder', { ns: 'app' }) as string} />
|
||||
</div>
|
||||
{
|
||||
isLoading
|
||||
@ -76,7 +76,7 @@ export default function AddMemberOrGroupDialog() {
|
||||
)
|
||||
: (
|
||||
<div className="flex h-7 items-center justify-center px-2 py-0.5">
|
||||
<span className="system-xs-regular text-text-tertiary">{t('app.accessControlDialog.operateGroupAndMember.noResult')}</span>
|
||||
<span className="system-xs-regular text-text-tertiary">{t('accessControlDialog.operateGroupAndMember.noResult', { ns: 'app' })}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -115,7 +115,7 @@ function SelectedGroupsBreadCrumb() {
|
||||
}, [setSelectedGroupsForBreadcrumb])
|
||||
return (
|
||||
<div className="flex h-7 items-center gap-x-0.5 px-2 py-0.5">
|
||||
<span className={cn('system-xs-regular text-text-tertiary', selectedGroupsForBreadcrumb.length > 0 && 'cursor-pointer text-text-accent')} onClick={handleReset}>{t('app.accessControlDialog.operateGroupAndMember.allMembers')}</span>
|
||||
<span className={cn('system-xs-regular text-text-tertiary', selectedGroupsForBreadcrumb.length > 0 && 'cursor-pointer text-text-accent')} onClick={handleReset}>{t('accessControlDialog.operateGroupAndMember.allMembers', { ns: 'app' })}</span>
|
||||
{selectedGroupsForBreadcrumb.map((group, index) => {
|
||||
return (
|
||||
<div key={index} className="system-xs-regular flex items-center gap-x-0.5 text-text-tertiary">
|
||||
@ -171,7 +171,7 @@ function GroupItem({ group }: GroupItemProps) {
|
||||
className="flex shrink-0 items-center justify-between px-1.5 py-1"
|
||||
onClick={handleExpandClick}
|
||||
>
|
||||
<span className="px-[3px]">{t('app.accessControlDialog.operateGroupAndMember.expand')}</span>
|
||||
<span className="px-[3px]">{t('accessControlDialog.operateGroupAndMember.expand', { ns: 'app' })}</span>
|
||||
<RiArrowRightSLine className="h-4 w-4" />
|
||||
</Button>
|
||||
</BaseItem>
|
||||
@ -210,7 +210,7 @@ function MemberItem({ member }: MemberItemProps) {
|
||||
{currentUser.email === member.email && (
|
||||
<p className="system-xs-regular text-text-tertiary">
|
||||
(
|
||||
{t('common.you')}
|
||||
{t('you', { ns: 'common' })}
|
||||
)
|
||||
</p>
|
||||
)}
|
||||
|
||||
@ -61,25 +61,25 @@ export default function AccessControl(props: AccessControlProps) {
|
||||
submitData.subjects = subjects
|
||||
}
|
||||
await updateAccessMode(submitData)
|
||||
Toast.notify({ type: 'success', message: t('app.accessControlDialog.updateSuccess') })
|
||||
Toast.notify({ type: 'success', message: t('accessControlDialog.updateSuccess', { ns: 'app' }) })
|
||||
onConfirm?.()
|
||||
}, [updateAccessMode, app, specificGroups, specificMembers, t, onConfirm, currentMenu])
|
||||
return (
|
||||
<AccessControlDialog show onClose={onClose}>
|
||||
<div className="flex flex-col gap-y-3">
|
||||
<div className="pb-3 pl-6 pr-14 pt-6">
|
||||
<DialogTitle className="title-2xl-semi-bold text-text-primary">{t('app.accessControlDialog.title')}</DialogTitle>
|
||||
<DialogDescription className="system-xs-regular mt-1 text-text-tertiary">{t('app.accessControlDialog.description')}</DialogDescription>
|
||||
<DialogTitle className="title-2xl-semi-bold text-text-primary">{t('accessControlDialog.title', { ns: 'app' })}</DialogTitle>
|
||||
<DialogDescription className="system-xs-regular mt-1 text-text-tertiary">{t('accessControlDialog.description', { ns: 'app' })}</DialogDescription>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-1 px-6 pb-3">
|
||||
<div className="leading-6">
|
||||
<p className="system-sm-medium text-text-tertiary">{t('app.accessControlDialog.accessLabel')}</p>
|
||||
<p className="system-sm-medium text-text-tertiary">{t('accessControlDialog.accessLabel', { ns: 'app' })}</p>
|
||||
</div>
|
||||
<AccessControlItem type={AccessMode.ORGANIZATION}>
|
||||
<div className="flex items-center p-3">
|
||||
<div className="flex grow items-center gap-x-2">
|
||||
<RiBuildingLine className="h-4 w-4 text-text-primary" />
|
||||
<p className="system-sm-medium text-text-primary">{t('app.accessControlDialog.accessItems.organization')}</p>
|
||||
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.organization', { ns: 'app' })}</p>
|
||||
</div>
|
||||
</div>
|
||||
</AccessControlItem>
|
||||
@ -90,7 +90,7 @@ export default function AccessControl(props: AccessControlProps) {
|
||||
<div className="flex items-center p-3">
|
||||
<div className="flex grow items-center gap-x-2">
|
||||
<RiVerifiedBadgeLine className="h-4 w-4 text-text-primary" />
|
||||
<p className="system-sm-medium text-text-primary">{t('app.accessControlDialog.accessItems.external')}</p>
|
||||
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.external', { ns: 'app' })}</p>
|
||||
</div>
|
||||
{!hideTip && <WebAppSSONotEnabledTip />}
|
||||
</div>
|
||||
@ -98,13 +98,13 @@ export default function AccessControl(props: AccessControlProps) {
|
||||
<AccessControlItem type={AccessMode.PUBLIC}>
|
||||
<div className="flex items-center gap-x-2 p-3">
|
||||
<RiGlobalLine className="h-4 w-4 text-text-primary" />
|
||||
<p className="system-sm-medium text-text-primary">{t('app.accessControlDialog.accessItems.anyone')}</p>
|
||||
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.anyone', { ns: 'app' })}</p>
|
||||
</div>
|
||||
</AccessControlItem>
|
||||
</div>
|
||||
<div className="flex items-center justify-end gap-x-2 p-6 pt-5">
|
||||
<Button onClick={onClose}>{t('common.operation.cancel')}</Button>
|
||||
<Button disabled={isPending} loading={isPending} variant="primary" onClick={handleConfirm}>{t('common.operation.confirm')}</Button>
|
||||
<Button onClick={onClose}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Button disabled={isPending} loading={isPending} variant="primary" onClick={handleConfirm}>{t('operation.confirm', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</AccessControlDialog>
|
||||
|
||||
@ -29,7 +29,7 @@ export default function SpecificGroupsOrMembers() {
|
||||
<div className="flex items-center p-3">
|
||||
<div className="flex grow items-center gap-x-2">
|
||||
<RiLockLine className="h-4 w-4 text-text-primary" />
|
||||
<p className="system-sm-medium text-text-primary">{t('app.accessControlDialog.accessItems.specific')}</p>
|
||||
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.specific', { ns: 'app' })}</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@ -40,7 +40,7 @@ export default function SpecificGroupsOrMembers() {
|
||||
<div className="flex items-center gap-x-1 p-3">
|
||||
<div className="flex grow items-center gap-x-1">
|
||||
<RiLockLine className="h-4 w-4 text-text-primary" />
|
||||
<p className="system-sm-medium text-text-primary">{t('app.accessControlDialog.accessItems.specific')}</p>
|
||||
<p className="system-sm-medium text-text-primary">{t('accessControlDialog.accessItems.specific', { ns: 'app' })}</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-x-1">
|
||||
<AddMemberOrGroupDialog />
|
||||
@ -60,14 +60,14 @@ function RenderGroupsAndMembers() {
|
||||
const specificGroups = useAccessControlStore(s => s.specificGroups)
|
||||
const specificMembers = useAccessControlStore(s => s.specificMembers)
|
||||
if (specificGroups.length <= 0 && specificMembers.length <= 0)
|
||||
return <div className="px-2 pb-1.5 pt-5"><p className="system-xs-regular text-center text-text-tertiary">{t('app.accessControlDialog.noGroupsOrMembers')}</p></div>
|
||||
return <div className="px-2 pb-1.5 pt-5"><p className="system-xs-regular text-center text-text-tertiary">{t('accessControlDialog.noGroupsOrMembers', { ns: 'app' })}</p></div>
|
||||
return (
|
||||
<>
|
||||
<p className="system-2xs-medium-uppercase sticky top-0 text-text-tertiary">{t('app.accessControlDialog.groups', { count: specificGroups.length ?? 0 })}</p>
|
||||
<p className="system-2xs-medium-uppercase sticky top-0 text-text-tertiary">{t('accessControlDialog.groups', { ns: 'app', count: specificGroups.length ?? 0 })}</p>
|
||||
<div className="flex flex-row flex-wrap gap-1">
|
||||
{specificGroups.map((group, index) => <GroupItem key={index} group={group} />)}
|
||||
</div>
|
||||
<p className="system-2xs-medium-uppercase sticky top-0 text-text-tertiary">{t('app.accessControlDialog.members', { count: specificMembers.length ?? 0 })}</p>
|
||||
<p className="system-2xs-medium-uppercase sticky top-0 text-text-tertiary">{t('accessControlDialog.members', { ns: 'app', count: specificMembers.length ?? 0 })}</p>
|
||||
<div className="flex flex-row flex-wrap gap-1">
|
||||
{specificMembers.map((member, index) => <MemberItem key={index} member={member} />)}
|
||||
</div>
|
||||
@ -138,7 +138,7 @@ function BaseItem({ icon, onRemove, children }: BaseItemProps) {
|
||||
export function WebAppSSONotEnabledTip() {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<Tooltip asChild={false} popupContent={t('app.accessControlDialog.webAppSSONotEnabledTip')}>
|
||||
<Tooltip asChild={false} popupContent={t('accessControlDialog.webAppSSONotEnabledTip', { ns: 'app' })}>
|
||||
<RiAlertFill className="h-4 w-4 shrink-0 text-text-warning-secondary" />
|
||||
</Tooltip>
|
||||
)
|
||||
|
||||
@ -76,8 +76,8 @@ const FeaturesWrappedAppPublisher = (props: Props) => {
|
||||
/>
|
||||
{restoreConfirmOpen && (
|
||||
<Confirm
|
||||
title={t('appDebug.resetConfig.title')}
|
||||
content={t('appDebug.resetConfig.message')}
|
||||
title={t('resetConfig.title', { ns: 'appDebug' })}
|
||||
content={t('resetConfig.message', { ns: 'appDebug' })}
|
||||
isShow={restoreConfirmOpen}
|
||||
onConfirm={handleConfirm}
|
||||
onCancel={() => setRestoreConfirmOpen(false)}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
import type { ModelAndParameter } from '../configuration/debug/types'
|
||||
import type { InputVar, Variable } from '@/app/components/workflow/types'
|
||||
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||
import type { PublishWorkflowParams } from '@/types/workflow'
|
||||
import {
|
||||
RiArrowDownSLine,
|
||||
@ -53,7 +54,9 @@ import AccessControl from '../app-access-control'
|
||||
import PublishWithMultipleModel from './publish-with-multiple-model'
|
||||
import SuggestedAction from './suggested-action'
|
||||
|
||||
const ACCESS_MODE_MAP: Record<AccessMode, { label: string, icon: React.ElementType }> = {
|
||||
type AccessModeLabel = I18nKeysByPrefix<'app', 'accessControlDialog.accessItems.'>
|
||||
|
||||
const ACCESS_MODE_MAP: Record<AccessMode, { label: AccessModeLabel, icon: React.ElementType }> = {
|
||||
[AccessMode.ORGANIZATION]: {
|
||||
label: 'organization',
|
||||
icon: RiBuildingLine,
|
||||
@ -84,7 +87,7 @@ const AccessModeDisplay: React.FC<{ mode?: AccessMode }> = ({ mode }) => {
|
||||
<>
|
||||
<Icon className="h-4 w-4 shrink-0 text-text-secondary" />
|
||||
<div className="grow truncate">
|
||||
<span className="system-sm-medium text-text-secondary">{t(`app.accessControlDialog.accessItems.${label}` as any) as string}</span>
|
||||
<span className="system-sm-medium text-text-secondary">{t(`accessControlDialog.accessItems.${label}`, { ns: 'app' })}</span>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
@ -162,11 +165,11 @@ const AppPublisher = ({
|
||||
|
||||
const disabledFunctionTooltip = useMemo(() => {
|
||||
if (!publishedAt)
|
||||
return t('app.notPublishedYet')
|
||||
return t('notPublishedYet', { ns: 'app' })
|
||||
if (missingStartNode)
|
||||
return t('app.noUserInputNode')
|
||||
return t('noUserInputNode', { ns: 'app' })
|
||||
if (noAccessPermission)
|
||||
return t('app.noAccessPermission')
|
||||
return t('noAccessPermission', { ns: 'app' })
|
||||
}, [missingStartNode, noAccessPermission, publishedAt])
|
||||
|
||||
useEffect(() => {
|
||||
@ -256,7 +259,7 @@ const AppPublisher = ({
|
||||
|
||||
const hasPublishedVersion = !!publishedAt
|
||||
const workflowToolDisabled = !hasPublishedVersion || !workflowToolAvailable
|
||||
const workflowToolMessage = workflowToolDisabled ? t('workflow.common.workflowAsToolDisabledHint') : undefined
|
||||
const workflowToolMessage = workflowToolDisabled ? t('common.workflowAsToolDisabledHint', { ns: 'workflow' }) : undefined
|
||||
const showStartNodeLimitHint = Boolean(startNodeLimitExceeded)
|
||||
const upgradeHighlightStyle = useMemo(() => ({
|
||||
background: 'linear-gradient(97deg, var(--components-input-border-active-prompt-1, rgba(11, 165, 236, 0.95)) -3.64%, var(--components-input-border-active-prompt-2, rgba(21, 90, 239, 0.95)) 45.14%)',
|
||||
@ -282,7 +285,7 @@ const AppPublisher = ({
|
||||
className="py-2 pl-3 pr-2"
|
||||
disabled={disabled}
|
||||
>
|
||||
{t('workflow.common.publish')}
|
||||
{t('common.publish', { ns: 'workflow' })}
|
||||
<RiArrowDownSLine className="h-4 w-4 text-components-button-primary-text" />
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
@ -290,13 +293,13 @@ const AppPublisher = ({
|
||||
<div className="w-[320px] rounded-2xl border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-xl shadow-shadow-shadow-5">
|
||||
<div className="p-4 pt-3">
|
||||
<div className="system-xs-medium-uppercase flex h-6 items-center text-text-tertiary">
|
||||
{publishedAt ? t('workflow.common.latestPublished') : t('workflow.common.currentDraftUnpublished')}
|
||||
{publishedAt ? t('common.latestPublished', { ns: 'workflow' }) : t('common.currentDraftUnpublished', { ns: 'workflow' })}
|
||||
</div>
|
||||
{publishedAt
|
||||
? (
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="system-sm-medium flex items-center text-text-secondary">
|
||||
{t('workflow.common.publishedAt')}
|
||||
{t('common.publishedAt', { ns: 'workflow' })}
|
||||
{' '}
|
||||
{formatTimeFromNow(publishedAt)}
|
||||
</div>
|
||||
@ -307,14 +310,14 @@ const AppPublisher = ({
|
||||
onClick={handleRestore}
|
||||
disabled={published}
|
||||
>
|
||||
{t('workflow.common.restore')}
|
||||
{t('common.restore', { ns: 'workflow' })}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div className="system-sm-medium flex items-center text-text-secondary">
|
||||
{t('workflow.common.autoSaved')}
|
||||
{t('common.autoSaved', { ns: 'workflow' })}
|
||||
{' '}
|
||||
·
|
||||
{Boolean(draftUpdatedAt) && formatTimeFromNow(draftUpdatedAt!)}
|
||||
@ -338,10 +341,10 @@ const AppPublisher = ({
|
||||
>
|
||||
{
|
||||
published
|
||||
? t('workflow.common.published')
|
||||
? t('common.published', { ns: 'workflow' })
|
||||
: (
|
||||
<div className="flex gap-1">
|
||||
<span>{t('workflow.common.publishUpdate')}</span>
|
||||
<span>{t('common.publishUpdate', { ns: 'workflow' })}</span>
|
||||
<div className="flex gap-0.5">
|
||||
{PUBLISH_SHORTCUT.map(key => (
|
||||
<span key={key} className="system-kbd h-4 w-4 rounded-[4px] bg-components-kbd-bg-white text-text-primary-on-surface">
|
||||
@ -359,11 +362,11 @@ const AppPublisher = ({
|
||||
className="text-sm font-semibold leading-5 text-transparent"
|
||||
style={upgradeHighlightStyle}
|
||||
>
|
||||
<span className="block">{t('workflow.publishLimit.startNodeTitlePrefix')}</span>
|
||||
<span className="block">{t('workflow.publishLimit.startNodeTitleSuffix')}</span>
|
||||
<span className="block">{t('publishLimit.startNodeTitlePrefix', { ns: 'workflow' })}</span>
|
||||
<span className="block">{t('publishLimit.startNodeTitleSuffix', { ns: 'workflow' })}</span>
|
||||
</p>
|
||||
<p className="mt-1 text-xs leading-4 text-text-secondary">
|
||||
{t('workflow.publishLimit.startNodeDesc')}
|
||||
{t('publishLimit.startNodeDesc', { ns: 'workflow' })}
|
||||
</p>
|
||||
<UpgradeBtn
|
||||
isShort
|
||||
@ -382,7 +385,7 @@ const AppPublisher = ({
|
||||
{systemFeatures.webapp_auth.enabled && (
|
||||
<div className="p-4 pt-3">
|
||||
<div className="flex h-6 items-center">
|
||||
<p className="system-xs-medium text-text-tertiary">{t('app.publishApp.title')}</p>
|
||||
<p className="system-xs-medium text-text-tertiary">{t('publishApp.title', { ns: 'app' })}</p>
|
||||
</div>
|
||||
<div
|
||||
className="flex h-8 cursor-pointer items-center gap-x-0.5 rounded-lg bg-components-input-bg-normal py-1 pl-2.5 pr-2 hover:bg-primary-50 hover:text-text-accent"
|
||||
@ -393,12 +396,12 @@ const AppPublisher = ({
|
||||
<div className="flex grow items-center gap-x-1.5 overflow-hidden pr-1">
|
||||
<AccessModeDisplay mode={appDetail?.access_mode} />
|
||||
</div>
|
||||
{!isAppAccessSet && <p className="system-xs-regular shrink-0 text-text-tertiary">{t('app.publishApp.notSet')}</p>}
|
||||
{!isAppAccessSet && <p className="system-xs-regular shrink-0 text-text-tertiary">{t('publishApp.notSet', { ns: 'app' })}</p>}
|
||||
<div className="flex h-4 w-4 shrink-0 items-center justify-center">
|
||||
<RiArrowRightSLine className="h-4 w-4 text-text-quaternary" />
|
||||
</div>
|
||||
</div>
|
||||
{!isAppAccessSet && <p className="system-xs-regular mt-1 text-text-warning">{t('app.publishApp.notSetDesc')}</p>}
|
||||
{!isAppAccessSet && <p className="system-xs-regular mt-1 text-text-warning">{t('publishApp.notSetDesc', { ns: 'app' })}</p>}
|
||||
</div>
|
||||
)}
|
||||
{
|
||||
@ -412,7 +415,7 @@ const AppPublisher = ({
|
||||
link={appURL}
|
||||
icon={<RiPlayCircleLine className="h-4 w-4" />}
|
||||
>
|
||||
{t('workflow.common.runApp')}
|
||||
{t('common.runApp', { ns: 'workflow' })}
|
||||
</SuggestedAction>
|
||||
</Tooltip>
|
||||
{appDetail?.mode === AppModeEnum.WORKFLOW || appDetail?.mode === AppModeEnum.COMPLETION
|
||||
@ -424,7 +427,7 @@ const AppPublisher = ({
|
||||
link={`${appURL}${appURL.includes('?') ? '&' : '?'}mode=batch`}
|
||||
icon={<RiPlayList2Line className="h-4 w-4" />}
|
||||
>
|
||||
{t('workflow.common.batchRunApp')}
|
||||
{t('common.batchRunApp', { ns: 'workflow' })}
|
||||
</SuggestedAction>
|
||||
</Tooltip>
|
||||
)
|
||||
@ -437,7 +440,7 @@ const AppPublisher = ({
|
||||
disabled={!publishedAt}
|
||||
icon={<CodeBrowser className="h-4 w-4" />}
|
||||
>
|
||||
{t('workflow.common.embedIntoSite')}
|
||||
{t('common.embedIntoSite', { ns: 'workflow' })}
|
||||
</SuggestedAction>
|
||||
)}
|
||||
<Tooltip triggerClassName="flex" disabled={!disabledFunctionButton} popupContent={disabledFunctionTooltip} asChild={false}>
|
||||
@ -450,17 +453,17 @@ const AppPublisher = ({
|
||||
disabled={disabledFunctionButton}
|
||||
icon={<RiPlanetLine className="h-4 w-4" />}
|
||||
>
|
||||
{t('workflow.common.openInExplore')}
|
||||
{t('common.openInExplore', { ns: 'workflow' })}
|
||||
</SuggestedAction>
|
||||
</Tooltip>
|
||||
<Tooltip triggerClassName="flex" disabled={!!publishedAt && !missingStartNode} popupContent={!publishedAt ? t('app.notPublishedYet') : t('app.noUserInputNode')} asChild={false}>
|
||||
<Tooltip triggerClassName="flex" disabled={!!publishedAt && !missingStartNode} popupContent={!publishedAt ? t('notPublishedYet', { ns: 'app' }) : t('noUserInputNode', { ns: 'app' })} asChild={false}>
|
||||
<SuggestedAction
|
||||
className="flex-1"
|
||||
disabled={!publishedAt || missingStartNode}
|
||||
link="./develop"
|
||||
icon={<RiTerminalBoxLine className="h-4 w-4" />}
|
||||
>
|
||||
{t('workflow.common.accessAPIReference')}
|
||||
{t('common.accessAPIReference', { ns: 'workflow' })}
|
||||
</SuggestedAction>
|
||||
</Tooltip>
|
||||
{appDetail?.mode === AppModeEnum.WORKFLOW && (
|
||||
|
||||
@ -72,14 +72,14 @@ const PublishWithMultipleModel: FC<PublishWithMultipleModelProps> = ({
|
||||
disabled={!validModelConfigs.length}
|
||||
className="mt-3 w-full"
|
||||
>
|
||||
{t('appDebug.operation.applyConfig')}
|
||||
{t('operation.applyConfig', { ns: 'appDebug' })}
|
||||
<RiArrowDownSLine className="ml-0.5 h-3 w-3" />
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-50 mt-1 w-[288px]">
|
||||
<div className="rounded-lg border-[0.5px] border-components-panel-border bg-components-panel-bg p-1 shadow-lg">
|
||||
<div className="flex h-[22px] items-center px-3 text-xs font-medium text-text-tertiary">
|
||||
{t('appDebug.publishAs')}
|
||||
{t('publishAs', { ns: 'appDebug' })}
|
||||
</div>
|
||||
{
|
||||
validModelConfigs.map((item, index) => (
|
||||
|
||||
@ -37,7 +37,7 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
|
||||
setTitleError(true)
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('workflow.versionHistory.editField.titleLengthLimit', { limit: TITLE_MAX_LENGTH }),
|
||||
message: t('versionHistory.editField.titleLengthLimit', { ns: 'workflow', limit: TITLE_MAX_LENGTH }),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -50,7 +50,7 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
|
||||
setReleaseNotesError(true)
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('workflow.versionHistory.editField.releaseNotesLengthLimit', { limit: RELEASE_NOTES_MAX_LENGTH }),
|
||||
message: t('versionHistory.editField.releaseNotesLengthLimit', { ns: 'workflow', limit: RELEASE_NOTES_MAX_LENGTH }),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -75,7 +75,7 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
|
||||
<Modal className="p-0" isShow={isOpen} onClose={onClose}>
|
||||
<div className="relative w-full p-6 pb-4 pr-14">
|
||||
<div className="title-2xl-semi-bold text-text-primary first-letter:capitalize">
|
||||
{versionInfo?.marked_name ? t('workflow.versionHistory.editVersionInfo') : t('workflow.versionHistory.nameThisVersion')}
|
||||
{versionInfo?.marked_name ? t('versionHistory.editVersionInfo', { ns: 'workflow' }) : t('versionHistory.nameThisVersion', { ns: 'workflow' })}
|
||||
</div>
|
||||
<div className="absolute right-5 top-5 flex h-8 w-8 cursor-pointer items-center justify-center p-1.5" onClick={onClose}>
|
||||
<RiCloseLine className="h-[18px] w-[18px] text-text-tertiary" />
|
||||
@ -84,22 +84,22 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
|
||||
<div className="flex flex-col gap-y-4 px-6 py-3">
|
||||
<div className="flex flex-col gap-y-1">
|
||||
<div className="system-sm-semibold flex h-6 items-center text-text-secondary">
|
||||
{t('workflow.versionHistory.editField.title')}
|
||||
{t('versionHistory.editField.title', { ns: 'workflow' })}
|
||||
</div>
|
||||
<Input
|
||||
value={title}
|
||||
placeholder={`${t('workflow.versionHistory.nameThisVersion')}${t('workflow.panel.optional')}`}
|
||||
placeholder={`${t('versionHistory.nameThisVersion', { ns: 'workflow' })}${t('panel.optional', { ns: 'workflow' })}`}
|
||||
onChange={handleTitleChange}
|
||||
destructive={titleError}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex flex-col gap-y-1">
|
||||
<div className="system-sm-semibold flex h-6 items-center text-text-secondary">
|
||||
{t('workflow.versionHistory.editField.releaseNotes')}
|
||||
{t('versionHistory.editField.releaseNotes', { ns: 'workflow' })}
|
||||
</div>
|
||||
<Textarea
|
||||
value={releaseNotes}
|
||||
placeholder={`${t('workflow.versionHistory.releaseNotesPlaceholder')}${t('workflow.panel.optional')}`}
|
||||
placeholder={`${t('versionHistory.releaseNotesPlaceholder', { ns: 'workflow' })}${t('panel.optional', { ns: 'workflow' })}`}
|
||||
onChange={handleDescriptionChange}
|
||||
destructive={releaseNotesError}
|
||||
/>
|
||||
@ -107,8 +107,8 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
|
||||
</div>
|
||||
<div className="flex justify-end p-6 pt-5">
|
||||
<div className="flex items-center gap-x-3">
|
||||
<Button onClick={onClose}>{t('common.operation.cancel')}</Button>
|
||||
<Button variant="primary" onClick={handlePublish}>{t('workflow.common.publish')}</Button>
|
||||
<Button onClick={onClose}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Button variant="primary" onClick={handlePublish}>{t('common.publish', { ns: 'workflow' })}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</Modal>
|
||||
|
||||
@ -37,7 +37,7 @@ const OperationBtn: FC<IOperationBtnProps> = ({
|
||||
{iconMap[type]}
|
||||
</div>
|
||||
<div className="text-xs font-medium">
|
||||
{actionName || t(`common.operation.${type}`)}
|
||||
{actionName || t(`operation.${type}`, { ns: 'common' })}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -16,12 +16,12 @@ const FormattingChanged: FC<IFormattingChangedProps> = ({
|
||||
|
||||
return (
|
||||
<WarningMask
|
||||
title={t('appDebug.feature.dataSet.queryVariable.unableToQueryDataSet')}
|
||||
description={t('appDebug.feature.dataSet.queryVariable.unableToQueryDataSetTip')}
|
||||
title={t('feature.dataSet.queryVariable.unableToQueryDataSet', { ns: 'appDebug' })}
|
||||
description={t('feature.dataSet.queryVariable.unableToQueryDataSetTip', { ns: 'appDebug' })}
|
||||
footer={(
|
||||
<div className="flex space-x-2">
|
||||
<Button variant="primary" className="flex !w-[96px] justify-start" onClick={onConfirm}>
|
||||
<span className="text-[13px] font-medium">{t('appDebug.feature.dataSet.queryVariable.ok')}</span>
|
||||
<span className="text-[13px] font-medium">{t('feature.dataSet.queryVariable.ok', { ns: 'appDebug' })}</span>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -24,15 +24,15 @@ const FormattingChanged: FC<IFormattingChangedProps> = ({
|
||||
|
||||
return (
|
||||
<WarningMask
|
||||
title={t('appDebug.formattingChangedTitle')}
|
||||
description={t('appDebug.formattingChangedText')}
|
||||
title={t('formattingChangedTitle', { ns: 'appDebug' })}
|
||||
description={t('formattingChangedText', { ns: 'appDebug' })}
|
||||
footer={(
|
||||
<div className="flex space-x-2">
|
||||
<Button variant="primary" className="flex space-x-2" onClick={onConfirm}>
|
||||
{icon}
|
||||
<span>{t('common.operation.refresh')}</span>
|
||||
<span>{t('operation.refresh', { ns: 'common' })}</span>
|
||||
</Button>
|
||||
<Button onClick={onCancel}>{t('common.operation.cancel') as string}</Button>
|
||||
<Button onClick={onCancel}>{t('operation.cancel', { ns: 'common' }) as string}</Button>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -25,11 +25,11 @@ const HasNotSetAPI: FC<IHasNotSetAPIProps> = ({
|
||||
|
||||
return (
|
||||
<WarningMask
|
||||
title={isTrailFinished ? t('appDebug.notSetAPIKey.trailFinished') : t('appDebug.notSetAPIKey.title')}
|
||||
description={t('appDebug.notSetAPIKey.description')}
|
||||
title={isTrailFinished ? t('notSetAPIKey.trailFinished', { ns: 'appDebug' }) : t('notSetAPIKey.title', { ns: 'appDebug' })}
|
||||
description={t('notSetAPIKey.description', { ns: 'appDebug' })}
|
||||
footer={(
|
||||
<Button variant="primary" className="flex space-x-2" onClick={onSetting}>
|
||||
<span>{t('appDebug.notSetAPIKey.settingBtn')}</span>
|
||||
<span>{t('notSetAPIKey.settingBtn', { ns: 'appDebug' })}</span>
|
||||
{icon}
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@ -94,7 +94,7 @@ const AdvancedPromptInput: FC<Props> = ({
|
||||
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
||||
for (let i = 0; i < promptVariables.length; i++) {
|
||||
if (promptVariables[i].key === newExternalDataTool.variable) {
|
||||
notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
|
||||
notify({ type: 'error', message: t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: promptVariables[i].key }) })
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -152,14 +152,14 @@ const AdvancedPromptInput: FC<Props> = ({
|
||||
>
|
||||
<div className="flex items-center pr-2">
|
||||
<RiErrorWarningFill className="mr-1 h-4 w-4 text-[#F79009]" />
|
||||
<div className="text-[13px] font-medium leading-[18px] text-[#DC6803]">{t('appDebug.promptMode.contextMissing')}</div>
|
||||
<div className="text-[13px] font-medium leading-[18px] text-[#DC6803]">{t('promptMode.contextMissing', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
<Button
|
||||
size="small"
|
||||
variant="secondary-accent"
|
||||
onClick={onHideContextMissingTip}
|
||||
>
|
||||
{t('common.operation.ok')}
|
||||
{t('operation.ok', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
)
|
||||
@ -178,12 +178,12 @@ const AdvancedPromptInput: FC<Props> = ({
|
||||
<div className="flex items-center space-x-1">
|
||||
|
||||
<div className="text-sm font-semibold uppercase text-indigo-800">
|
||||
{t('appDebug.pageTitle.line1')}
|
||||
{t('pageTitle.line1', { ns: 'appDebug' })}
|
||||
</div>
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.promptTip')}
|
||||
{t('promptTip', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -54,7 +54,7 @@ const ConfirmAddVar: FC<IConfirmAddVarProps> = ({
|
||||
{VarIcon}
|
||||
</div>
|
||||
<div className="grow-1">
|
||||
<div className="text-sm font-medium text-text-primary">{t('appDebug.autoAddVar')}</div>
|
||||
<div className="text-sm font-medium text-text-primary">{t('autoAddVar', { ns: 'appDebug' })}</div>
|
||||
<div className="mt-[15px] flex max-h-[66px] flex-wrap space-x-1 overflow-y-auto px-1">
|
||||
{varNameArr.map(name => (
|
||||
<VarHighlight key={name} name={name} />
|
||||
@ -63,8 +63,8 @@ const ConfirmAddVar: FC<IConfirmAddVarProps> = ({
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-7 flex justify-end space-x-2">
|
||||
<Button onClick={onCancel}>{t('common.operation.cancel')}</Button>
|
||||
<Button variant="primary" onClick={onConfirm}>{t('common.operation.add')}</Button>
|
||||
<Button onClick={onCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Button variant="primary" onClick={onConfirm}>{t('operation.add', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -26,11 +26,11 @@ const EditModal: FC<Props> = ({
|
||||
const [tempData, setTempData] = useState(data)
|
||||
return (
|
||||
<Modal
|
||||
title={t('appDebug.feature.conversationHistory.editModal.title')}
|
||||
title={t('feature.conversationHistory.editModal.title', { ns: 'appDebug' })}
|
||||
isShow={isShow}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="mt-6 text-sm font-medium leading-[21px] text-text-primary">{t('appDebug.feature.conversationHistory.editModal.userPrefix')}</div>
|
||||
<div className="mt-6 text-sm font-medium leading-[21px] text-text-primary">{t('feature.conversationHistory.editModal.userPrefix', { ns: 'appDebug' })}</div>
|
||||
<input
|
||||
className="mt-2 box-border h-10 w-full rounded-lg bg-components-input-bg-normal px-3 text-sm leading-10"
|
||||
value={tempData.user_prefix}
|
||||
@ -40,7 +40,7 @@ const EditModal: FC<Props> = ({
|
||||
})}
|
||||
/>
|
||||
|
||||
<div className="mt-6 text-sm font-medium leading-[21px] text-text-primary">{t('appDebug.feature.conversationHistory.editModal.assistantPrefix')}</div>
|
||||
<div className="mt-6 text-sm font-medium leading-[21px] text-text-primary">{t('feature.conversationHistory.editModal.assistantPrefix', { ns: 'appDebug' })}</div>
|
||||
<input
|
||||
className="mt-2 box-border h-10 w-full rounded-lg bg-components-input-bg-normal px-3 text-sm leading-10"
|
||||
value={tempData.assistant_prefix}
|
||||
@ -48,12 +48,12 @@ const EditModal: FC<Props> = ({
|
||||
...tempData,
|
||||
assistant_prefix: e.target.value,
|
||||
})}
|
||||
placeholder={t('common.chat.conversationNamePlaceholder') || ''}
|
||||
placeholder={t('chat.conversationNamePlaceholder', { ns: 'common' }) || ''}
|
||||
/>
|
||||
|
||||
<div className="mt-10 flex justify-end">
|
||||
<Button className="mr-2 shrink-0" onClick={onClose}>{t('common.operation.cancel')}</Button>
|
||||
<Button variant="primary" className="shrink-0" onClick={() => onSave(tempData)} loading={saveLoading}>{t('common.operation.save')}</Button>
|
||||
<Button className="mr-2 shrink-0" onClick={onClose}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Button variant="primary" className="shrink-0" onClick={() => onSave(tempData)} loading={saveLoading}>{t('operation.save', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
|
||||
@ -24,7 +24,7 @@ const HistoryPanel: FC<Props> = ({
|
||||
className="mt-2"
|
||||
title={(
|
||||
<div className="flex items-center gap-2">
|
||||
<div>{t('appDebug.feature.conversationHistory.title')}</div>
|
||||
<div>{t('feature.conversationHistory.title', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
)}
|
||||
headerIcon={(
|
||||
@ -34,7 +34,7 @@ const HistoryPanel: FC<Props> = ({
|
||||
)}
|
||||
headerRight={(
|
||||
<div className="flex items-center">
|
||||
<div className="text-xs text-text-tertiary">{t('appDebug.feature.conversationHistory.description')}</div>
|
||||
<div className="text-xs text-text-tertiary">{t('feature.conversationHistory.description', { ns: 'appDebug' })}</div>
|
||||
<div className="ml-3 h-[14px] w-[1px] bg-divider-regular"></div>
|
||||
<OperationBtn type="edit" onClick={onShowEditModal} />
|
||||
</div>
|
||||
@ -44,14 +44,14 @@ const HistoryPanel: FC<Props> = ({
|
||||
{showWarning && (
|
||||
<div className="flex justify-between rounded-b-xl bg-background-section-burn px-3 py-2 text-xs text-text-secondary">
|
||||
<div>
|
||||
{t('appDebug.feature.conversationHistory.tip')}
|
||||
{t('feature.conversationHistory.tip', { ns: 'appDebug' })}
|
||||
<a
|
||||
href={docLink('/learn-more/extended-reading/what-is-llmops', { 'zh-Hans': '/learn-more/extended-reading/prompt-engineering/README' })}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-[#155EEF]"
|
||||
>
|
||||
{t('appDebug.feature.conversationHistory.learnMore')}
|
||||
{t('feature.conversationHistory.learnMore', { ns: 'appDebug' })}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -162,7 +162,7 @@ const Prompt: FC<IPromptProps> = ({
|
||||
className="mt-3 w-full"
|
||||
>
|
||||
<RiAddLine className="mr-2 h-4 w-4" />
|
||||
<div>{t('appDebug.promptMode.operation.addMessage')}</div>
|
||||
<div>{t('promptMode.operation.addMessage', { ns: 'appDebug' })}</div>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -92,7 +92,7 @@ const Prompt: FC<ISimplePromptInput> = ({
|
||||
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
||||
for (let i = 0; i < promptVariables.length; i++) {
|
||||
if (promptVariables[i].key === newExternalDataTool.variable) {
|
||||
notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
|
||||
notify({ type: 'error', message: t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: promptVariables[i].key }) })
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -178,12 +178,12 @@ const Prompt: FC<ISimplePromptInput> = ({
|
||||
{!noTitle && (
|
||||
<div className="flex h-11 items-center justify-between pl-3 pr-2.5">
|
||||
<div className="flex items-center space-x-1">
|
||||
<div className="h2 system-sm-semibold-uppercase text-text-secondary">{mode !== AppModeEnum.COMPLETION ? t('appDebug.chatSubTitle') : t('appDebug.completionSubTitle')}</div>
|
||||
<div className="h2 system-sm-semibold-uppercase text-text-secondary">{mode !== AppModeEnum.COMPLETION ? t('chatSubTitle', { ns: 'appDebug' }) : t('completionSubTitle', { ns: 'appDebug' })}</div>
|
||||
{!readonly && (
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.promptTip')}
|
||||
{t('promptTip', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -25,7 +25,7 @@ const Field: FC<Props> = ({
|
||||
{isOptional && (
|
||||
<span className="system-xs-regular ml-1 text-text-tertiary">
|
||||
(
|
||||
{t('appDebug.variableConfig.optional')}
|
||||
{t('variableConfig.optional', { ns: 'appDebug' })}
|
||||
)
|
||||
</span>
|
||||
)}
|
||||
|
||||
@ -47,6 +47,12 @@ const getCheckboxDefaultSelectValue = (value: InputVar['default']) => {
|
||||
const parseCheckboxSelectValue = (value: string) =>
|
||||
value === CHECKBOX_DEFAULT_TRUE_VALUE
|
||||
|
||||
const normalizeSelectDefaultValue = (inputVar: InputVar) => {
|
||||
if (inputVar.type === InputVarType.select && inputVar.default === '')
|
||||
return { ...inputVar, default: undefined }
|
||||
return inputVar
|
||||
}
|
||||
|
||||
export type IConfigModalProps = {
|
||||
isCreate?: boolean
|
||||
payload?: InputVar
|
||||
@ -67,7 +73,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
}) => {
|
||||
const { modelConfig } = useContext(ConfigContext)
|
||||
const { t } = useTranslation()
|
||||
const [tempPayload, setTempPayload] = useState<InputVar>(() => payload || getNewVarInWorkflow('') as any)
|
||||
const [tempPayload, setTempPayload] = useState<InputVar>(() => normalizeSelectDefaultValue(payload || getNewVarInWorkflow('') as any))
|
||||
const { type, label, variable, options, max_length } = tempPayload
|
||||
const modalRef = useRef<HTMLDivElement>(null)
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
@ -96,7 +102,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
if (!isValid) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t(`appDebug.varKeyError.${errorMessageKey}` as any, { key: t('appDebug.variableConfig.varName') }) as string,
|
||||
message: t(`varKeyError.${errorMessageKey}`, { ns: 'appDebug', key: t('variableConfig.varName', { ns: 'appDebug' }) }),
|
||||
})
|
||||
return false
|
||||
}
|
||||
@ -138,40 +144,40 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
|
||||
const selectOptions: SelectItem[] = [
|
||||
{
|
||||
name: t('appDebug.variableConfig.text-input'),
|
||||
name: t('variableConfig.text-input', { ns: 'appDebug' }),
|
||||
value: InputVarType.textInput,
|
||||
},
|
||||
{
|
||||
name: t('appDebug.variableConfig.paragraph'),
|
||||
name: t('variableConfig.paragraph', { ns: 'appDebug' }),
|
||||
value: InputVarType.paragraph,
|
||||
},
|
||||
{
|
||||
name: t('appDebug.variableConfig.select'),
|
||||
name: t('variableConfig.select', { ns: 'appDebug' }),
|
||||
value: InputVarType.select,
|
||||
},
|
||||
{
|
||||
name: t('appDebug.variableConfig.number'),
|
||||
name: t('variableConfig.number', { ns: 'appDebug' }),
|
||||
value: InputVarType.number,
|
||||
},
|
||||
{
|
||||
name: t('appDebug.variableConfig.checkbox'),
|
||||
name: t('variableConfig.checkbox', { ns: 'appDebug' }),
|
||||
value: InputVarType.checkbox,
|
||||
},
|
||||
...(supportFile
|
||||
? [
|
||||
{
|
||||
name: t('appDebug.variableConfig.single-file'),
|
||||
name: t('variableConfig.single-file', { ns: 'appDebug' }),
|
||||
value: InputVarType.singleFile,
|
||||
},
|
||||
{
|
||||
name: t('appDebug.variableConfig.multi-files'),
|
||||
name: t('variableConfig.multi-files', { ns: 'appDebug' }),
|
||||
value: InputVarType.multiFiles,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...((!isBasicApp && isSupportJSON)
|
||||
? [{
|
||||
name: t('appDebug.variableConfig.json'),
|
||||
name: t('variableConfig.json', { ns: 'appDebug' }),
|
||||
value: InputVarType.jsonObject,
|
||||
}]
|
||||
: []),
|
||||
@ -182,6 +188,8 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
|
||||
const newPayload = produce(tempPayload, (draft) => {
|
||||
draft.type = type
|
||||
if (type === InputVarType.select)
|
||||
draft.default = undefined
|
||||
if ([InputVarType.singleFile, InputVarType.multiFiles].includes(type)) {
|
||||
(Object.keys(DEFAULT_FILE_UPLOAD_SETTING)).forEach((key) => {
|
||||
if (key !== 'max_length')
|
||||
@ -216,7 +224,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
if (!isValid) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t(`appDebug.varKeyError.${errorMessageKey}` as any, { key: errorKey }) as string,
|
||||
message: t(`varKeyError.${errorMessageKey}`, { ns: 'appDebug', key: errorKey }),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -238,7 +246,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
return
|
||||
|
||||
if (!tempPayload.label) {
|
||||
Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.labelNameRequired') })
|
||||
Toast.notify({ type: 'error', message: t('variableConfig.errorMsg.labelNameRequired', { ns: 'appDebug' }) })
|
||||
return
|
||||
}
|
||||
if (isStringInput || type === InputVarType.number) {
|
||||
@ -246,7 +254,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
}
|
||||
else if (type === InputVarType.select) {
|
||||
if (options?.length === 0) {
|
||||
Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.atLeastOneOption') })
|
||||
Toast.notify({ type: 'error', message: t('variableConfig.errorMsg.atLeastOneOption', { ns: 'appDebug' }) })
|
||||
return
|
||||
}
|
||||
const obj: Record<string, boolean> = {}
|
||||
@ -259,19 +267,19 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
obj[o] = true
|
||||
})
|
||||
if (hasRepeatedItem) {
|
||||
Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.optionRepeat') })
|
||||
Toast.notify({ type: 'error', message: t('variableConfig.errorMsg.optionRepeat', { ns: 'appDebug' }) })
|
||||
return
|
||||
}
|
||||
onConfirm(tempPayload, moreInfo)
|
||||
}
|
||||
else if ([InputVarType.singleFile, InputVarType.multiFiles].includes(type)) {
|
||||
if (tempPayload.allowed_file_types?.length === 0) {
|
||||
const errorMessages = t('workflow.errorMsg.fieldRequired', { field: t('appDebug.variableConfig.file.supportFileTypes') })
|
||||
const errorMessages = t('errorMsg.fieldRequired', { ns: 'workflow', field: t('variableConfig.file.supportFileTypes', { ns: 'appDebug' }) })
|
||||
Toast.notify({ type: 'error', message: errorMessages })
|
||||
return
|
||||
}
|
||||
if (tempPayload.allowed_file_types?.includes(SupportUploadFileTypes.custom) && !tempPayload.allowed_file_extensions?.length) {
|
||||
const errorMessages = t('workflow.errorMsg.fieldRequired', { field: t('appDebug.variableConfig.file.custom.name') })
|
||||
const errorMessages = t('errorMsg.fieldRequired', { ns: 'workflow', field: t('variableConfig.file.custom.name', { ns: 'appDebug' }) })
|
||||
Toast.notify({ type: 'error', message: errorMessages })
|
||||
return
|
||||
}
|
||||
@ -284,34 +292,34 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
|
||||
return (
|
||||
<Modal
|
||||
title={t(`appDebug.variableConfig.${isCreate ? 'addModalTitle' : 'editModalTitle'}`)}
|
||||
title={t(`variableConfig.${isCreate ? 'addModalTitle' : 'editModalTitle'}`, { ns: 'appDebug' })}
|
||||
isShow={isShow}
|
||||
onClose={onClose}
|
||||
>
|
||||
<div className="mb-8" ref={modalRef} tabIndex={-1}>
|
||||
<div className="space-y-2">
|
||||
<Field title={t('appDebug.variableConfig.fieldType')}>
|
||||
<Field title={t('variableConfig.fieldType', { ns: 'appDebug' })}>
|
||||
<TypeSelector value={type} items={selectOptions} onSelect={handleTypeChange} />
|
||||
</Field>
|
||||
|
||||
<Field title={t('appDebug.variableConfig.varName')}>
|
||||
<Field title={t('variableConfig.varName', { ns: 'appDebug' })}>
|
||||
<Input
|
||||
value={variable}
|
||||
onChange={handleVarNameChange}
|
||||
onBlur={handleVarKeyBlur}
|
||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
||||
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||
/>
|
||||
</Field>
|
||||
<Field title={t('appDebug.variableConfig.labelName')}>
|
||||
<Field title={t('variableConfig.labelName', { ns: 'appDebug' })}>
|
||||
<Input
|
||||
value={label as string}
|
||||
onChange={e => handlePayloadChange('label')(e.target.value)}
|
||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
||||
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||
/>
|
||||
</Field>
|
||||
|
||||
{isStringInput && (
|
||||
<Field title={t('appDebug.variableConfig.maxLength')}>
|
||||
<Field title={t('variableConfig.maxLength', { ns: 'appDebug' })}>
|
||||
<ConfigString maxLength={type === InputVarType.textInput ? TEXT_MAX_LENGTH : Infinity} modelId={modelConfig.model_id} value={max_length} onChange={handlePayloadChange('max_length')} />
|
||||
</Field>
|
||||
|
||||
@ -319,50 +327,50 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
|
||||
{/* Default value for text input */}
|
||||
{type === InputVarType.textInput && (
|
||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
||||
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||
<Input
|
||||
value={tempPayload.default || ''}
|
||||
onChange={e => handlePayloadChange('default')(e.target.value || undefined)}
|
||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
||||
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
|
||||
{/* Default value for paragraph */}
|
||||
{type === InputVarType.paragraph && (
|
||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
||||
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||
<Textarea
|
||||
value={String(tempPayload.default ?? '')}
|
||||
onChange={e => handlePayloadChange('default')(e.target.value || undefined)}
|
||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
||||
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
|
||||
{/* Default value for number input */}
|
||||
{type === InputVarType.number && (
|
||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
||||
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||
<Input
|
||||
type="number"
|
||||
value={tempPayload.default || ''}
|
||||
onChange={e => handlePayloadChange('default')(e.target.value || undefined)}
|
||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
||||
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||
/>
|
||||
</Field>
|
||||
)}
|
||||
|
||||
{type === InputVarType.checkbox && (
|
||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
||||
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||
<SimpleSelect
|
||||
className="w-full"
|
||||
optionWrapClassName="max-h-[140px] overflow-y-auto"
|
||||
items={[
|
||||
{ value: CHECKBOX_DEFAULT_TRUE_VALUE, name: t('appDebug.variableConfig.startChecked') },
|
||||
{ value: CHECKBOX_DEFAULT_FALSE_VALUE, name: t('appDebug.variableConfig.noDefaultSelected') },
|
||||
{ value: CHECKBOX_DEFAULT_TRUE_VALUE, name: t('variableConfig.startChecked', { ns: 'appDebug' }) },
|
||||
{ value: CHECKBOX_DEFAULT_FALSE_VALUE, name: t('variableConfig.noDefaultSelected', { ns: 'appDebug' }) },
|
||||
]}
|
||||
defaultValue={checkboxDefaultSelectValue}
|
||||
onSelect={item => handlePayloadChange('default')(parseCheckboxSelectValue(String(item.value)))}
|
||||
placeholder={t('appDebug.variableConfig.selectDefaultValue')}
|
||||
placeholder={t('variableConfig.selectDefaultValue', { ns: 'appDebug' })}
|
||||
allowSearch={false}
|
||||
/>
|
||||
</Field>
|
||||
@ -370,17 +378,17 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
|
||||
{type === InputVarType.select && (
|
||||
<>
|
||||
<Field title={t('appDebug.variableConfig.options')}>
|
||||
<Field title={t('variableConfig.options', { ns: 'appDebug' })}>
|
||||
<ConfigSelect options={options || []} onChange={handlePayloadChange('options')} />
|
||||
</Field>
|
||||
{options && options.length > 0 && (
|
||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
||||
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||
<SimpleSelect
|
||||
key={`default-select-${options.join('-')}`}
|
||||
className="w-full"
|
||||
optionWrapClassName="max-h-[140px] overflow-y-auto"
|
||||
items={[
|
||||
{ value: '', name: t('appDebug.variableConfig.noDefaultValue') },
|
||||
{ value: '', name: t('variableConfig.noDefaultValue', { ns: 'appDebug' }) },
|
||||
...options.filter(opt => opt.trim() !== '').map(option => ({
|
||||
value: option,
|
||||
name: option,
|
||||
@ -388,7 +396,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
]}
|
||||
defaultValue={tempPayload.default || ''}
|
||||
onSelect={item => handlePayloadChange('default')(item.value === '' ? undefined : item.value)}
|
||||
placeholder={t('appDebug.variableConfig.selectDefaultValue')}
|
||||
placeholder={t('variableConfig.selectDefaultValue', { ns: 'appDebug' })}
|
||||
allowSearch={false}
|
||||
/>
|
||||
</Field>
|
||||
@ -403,7 +411,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
onChange={(p: UploadFileSetting) => setTempPayload(p as InputVar)}
|
||||
isMultiple={type === InputVarType.multiFiles}
|
||||
/>
|
||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
||||
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||
<FileUploaderInAttachmentWrapper
|
||||
value={(type === InputVarType.singleFile ? (tempPayload.default ? [tempPayload.default] : []) : (tempPayload.default || [])) as unknown as FileEntity[]}
|
||||
onChange={(files) => {
|
||||
@ -424,7 +432,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
)}
|
||||
|
||||
{type === InputVarType.jsonObject && (
|
||||
<Field title={t('appDebug.variableConfig.jsonSchema')} isOptional>
|
||||
<Field title={t('variableConfig.jsonSchema', { ns: 'appDebug' })} isOptional>
|
||||
<CodeEditor
|
||||
language={CodeLanguage.json}
|
||||
value={jsonSchemaStr}
|
||||
@ -440,12 +448,12 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||
|
||||
<div className="!mt-5 flex h-6 items-center space-x-2">
|
||||
<Checkbox checked={tempPayload.required} disabled={tempPayload.hide} onCheck={() => handlePayloadChange('required')(!tempPayload.required)} />
|
||||
<span className="system-sm-semibold text-text-secondary">{t('appDebug.variableConfig.required')}</span>
|
||||
<span className="system-sm-semibold text-text-secondary">{t('variableConfig.required', { ns: 'appDebug' })}</span>
|
||||
</div>
|
||||
|
||||
<div className="!mt-5 flex h-6 items-center space-x-2">
|
||||
<Checkbox checked={tempPayload.hide} disabled={tempPayload.required} onCheck={() => handlePayloadChange('hide')(!tempPayload.hide)} />
|
||||
<span className="system-sm-semibold text-text-secondary">{t('appDebug.variableConfig.hide')}</span>
|
||||
<span className="system-sm-semibold text-text-secondary">{t('variableConfig.hide', { ns: 'appDebug' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -90,7 +90,7 @@ const ConfigSelect: FC<IConfigSelectProps> = ({
|
||||
className="mt-1 flex h-9 cursor-pointer items-center gap-2 rounded-lg bg-components-button-tertiary-bg px-3 text-components-button-tertiary-text hover:bg-components-button-tertiary-bg-hover"
|
||||
>
|
||||
<RiAddLine className="h-4 w-4" />
|
||||
<div className="system-sm-medium text-[13px]">{t('appDebug.variableConfig.addOption')}</div>
|
||||
<div className="system-sm-medium text-[13px]">{t('variableConfig.addOption', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -84,21 +84,21 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||
})
|
||||
|
||||
const newList = newPromptVariables
|
||||
let errorMsgKey = ''
|
||||
let typeName = ''
|
||||
let errorMsgKey: 'varKeyError.keyAlreadyExists' | '' = ''
|
||||
let typeName: 'variableConfig.varName' | 'variableConfig.labelName' | '' = ''
|
||||
if (hasDuplicateStr(newList.map(item => item.key))) {
|
||||
errorMsgKey = 'appDebug.varKeyError.keyAlreadyExists'
|
||||
typeName = 'appDebug.variableConfig.varName'
|
||||
errorMsgKey = 'varKeyError.keyAlreadyExists'
|
||||
typeName = 'variableConfig.varName'
|
||||
}
|
||||
else if (hasDuplicateStr(newList.map(item => item.name as string))) {
|
||||
errorMsgKey = 'appDebug.varKeyError.keyAlreadyExists'
|
||||
typeName = 'appDebug.variableConfig.labelName'
|
||||
errorMsgKey = 'varKeyError.keyAlreadyExists'
|
||||
typeName = 'variableConfig.labelName'
|
||||
}
|
||||
|
||||
if (errorMsgKey) {
|
||||
if (errorMsgKey && typeName) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t(errorMsgKey as any, { key: t(typeName as any) as string }) as string,
|
||||
message: t(errorMsgKey, { ns: 'appDebug', key: t(typeName, { ns: 'appDebug' }) }),
|
||||
})
|
||||
return false
|
||||
}
|
||||
@ -149,7 +149,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
||||
for (let i = 0; i < promptVariables.length; i++) {
|
||||
if (promptVariables[i].key === newExternalDataTool.variable && i !== index) {
|
||||
Toast.notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
|
||||
Toast.notify({ type: 'error', message: t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: promptVariables[i].key }) })
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -238,12 +238,12 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||
className="mt-2"
|
||||
title={(
|
||||
<div className="flex items-center">
|
||||
<div className="mr-1">{t('appDebug.variableTitle')}</div>
|
||||
<div className="mr-1">{t('variableTitle', { ns: 'appDebug' })}</div>
|
||||
{!readonly && (
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.variableTip')}
|
||||
{t('variableTip', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
@ -255,7 +255,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||
>
|
||||
{!hasVar && (
|
||||
<div className="mt-1 px-3 pb-3">
|
||||
<div className="pb-1 pt-2 text-xs text-text-tertiary">{t('appDebug.notSetVar')}</div>
|
||||
<div className="pb-1 pt-2 text-xs text-text-tertiary">{t('notSetVar', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
)}
|
||||
{hasVar && (
|
||||
@ -307,8 +307,8 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||
{isShowDeleteContextVarModal && (
|
||||
<Confirm
|
||||
isShow={isShowDeleteContextVarModal}
|
||||
title={t('appDebug.feature.dataSet.queryVariable.deleteContextVarTitle', { varName: promptVariables[removeIndex as number]?.name })}
|
||||
content={t('appDebug.feature.dataSet.queryVariable.deleteContextVarTip')}
|
||||
title={t('feature.dataSet.queryVariable.deleteContextVarTitle', { ns: 'appDebug', varName: promptVariables[removeIndex as number]?.name })}
|
||||
content={t('feature.dataSet.queryVariable.deleteContextVarTip', { ns: 'appDebug' })}
|
||||
onConfirm={() => {
|
||||
didRemoveVar(removeIndex as number)
|
||||
hideDeleteContextVarModal()
|
||||
|
||||
@ -16,8 +16,8 @@ const ModalFoot: FC<IModalFootProps> = ({
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className="flex justify-end gap-2">
|
||||
<Button onClick={onCancel}>{t('common.operation.cancel')}</Button>
|
||||
<Button variant="primary" onClick={onConfirm}>{t('common.operation.save')}</Button>
|
||||
<Button onClick={onCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Button variant="primary" onClick={onConfirm}>{t('operation.save', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { InputVarType } from '@/app/components/workflow/types'
|
||||
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||
import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
|
||||
@ -12,7 +13,9 @@ export type ISelectTypeItemProps = {
|
||||
onClick: () => void
|
||||
}
|
||||
|
||||
const i18nFileTypeMap: Record<string, string> = {
|
||||
type VariableConfigTypeKey = I18nKeysByPrefix<'appDebug', 'variableConfig.'>
|
||||
|
||||
const i18nTypeMap: Partial<Record<InputVarType, VariableConfigTypeKey>> = {
|
||||
'file': 'single-file',
|
||||
'file-list': 'multi-files',
|
||||
}
|
||||
@ -23,7 +26,8 @@ const SelectTypeItem: FC<ISelectTypeItemProps> = ({
|
||||
onClick,
|
||||
}) => {
|
||||
const { t } = useTranslation()
|
||||
const typeName = t(`appDebug.variableConfig.${i18nFileTypeMap[type] || type}` as any) as string
|
||||
const typeKey = i18nTypeMap[type] ?? type as VariableConfigTypeKey
|
||||
const typeName = t(`variableConfig.${typeKey}`, { ns: 'appDebug' })
|
||||
|
||||
return (
|
||||
<div
|
||||
|
||||
@ -62,15 +62,15 @@ const SelectVarType: FC<Props> = ({
|
||||
<PortalToFollowElemContent style={{ zIndex: 1000 }}>
|
||||
<div className="min-w-[192px] rounded-lg border border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm">
|
||||
<div className="p-1">
|
||||
<SelectItem type={InputVarType.textInput} value="string" text={t('appDebug.variableConfig.string')} onClick={handleChange}></SelectItem>
|
||||
<SelectItem type={InputVarType.paragraph} value="paragraph" text={t('appDebug.variableConfig.paragraph')} onClick={handleChange}></SelectItem>
|
||||
<SelectItem type={InputVarType.select} value="select" text={t('appDebug.variableConfig.select')} onClick={handleChange}></SelectItem>
|
||||
<SelectItem type={InputVarType.number} value="number" text={t('appDebug.variableConfig.number')} onClick={handleChange}></SelectItem>
|
||||
<SelectItem type={InputVarType.checkbox} value="checkbox" text={t('appDebug.variableConfig.checkbox')} onClick={handleChange}></SelectItem>
|
||||
<SelectItem type={InputVarType.textInput} value="string" text={t('variableConfig.string', { ns: 'appDebug' })} onClick={handleChange}></SelectItem>
|
||||
<SelectItem type={InputVarType.paragraph} value="paragraph" text={t('variableConfig.paragraph', { ns: 'appDebug' })} onClick={handleChange}></SelectItem>
|
||||
<SelectItem type={InputVarType.select} value="select" text={t('variableConfig.select', { ns: 'appDebug' })} onClick={handleChange}></SelectItem>
|
||||
<SelectItem type={InputVarType.number} value="number" text={t('variableConfig.number', { ns: 'appDebug' })} onClick={handleChange}></SelectItem>
|
||||
<SelectItem type={InputVarType.checkbox} value="checkbox" text={t('variableConfig.checkbox', { ns: 'appDebug' })} onClick={handleChange}></SelectItem>
|
||||
</div>
|
||||
<div className="h-px border-t border-components-panel-border"></div>
|
||||
<div className="p-1">
|
||||
<SelectItem Icon={ApiConnection} value="api" text={t('appDebug.variableConfig.apiBasedVar')} onClick={handleChange}></SelectItem>
|
||||
<SelectItem Icon={ApiConnection} value="api" text={t('variableConfig.apiBasedVar', { ns: 'appDebug' })} onClick={handleChange}></SelectItem>
|
||||
</div>
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
|
||||
@ -65,11 +65,11 @@ const ConfigVision: FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex grow items-center">
|
||||
<div className="system-sm-semibold mr-1 text-text-secondary">{t('appDebug.vision.name')}</div>
|
||||
<div className="system-sm-semibold mr-1 text-text-secondary">{t('vision.name', { ns: 'appDebug' })}</div>
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.vision.description')}
|
||||
{t('vision.description', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -42,15 +42,15 @@ const ParamConfigContent: FC = () => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="text-base font-semibold leading-6 text-text-primary">{t('appDebug.vision.visionSettings.title')}</div>
|
||||
<div className="text-base font-semibold leading-6 text-text-primary">{t('vision.visionSettings.title', { ns: 'appDebug' })}</div>
|
||||
<div className="space-y-6 pt-3">
|
||||
<div>
|
||||
<div className="mb-2 flex items-center space-x-1">
|
||||
<div className="text-[13px] font-semibold leading-[18px] text-text-secondary">{t('appDebug.vision.visionSettings.resolution')}</div>
|
||||
<div className="text-[13px] font-semibold leading-[18px] text-text-secondary">{t('vision.visionSettings.resolution', { ns: 'appDebug' })}</div>
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.vision.visionSettings.resolutionTooltip').split('\n').map(item => (
|
||||
{t('vision.visionSettings.resolutionTooltip', { ns: 'appDebug' }).split('\n').map(item => (
|
||||
<div key={item}>{item}</div>
|
||||
))}
|
||||
</div>
|
||||
@ -60,7 +60,7 @@ const ParamConfigContent: FC = () => {
|
||||
<div className="flex items-center gap-1">
|
||||
<OptionCard
|
||||
className="grow"
|
||||
title={t('appDebug.vision.visionSettings.high')}
|
||||
title={t('vision.visionSettings.high', { ns: 'appDebug' })}
|
||||
selected={file?.image?.detail === Resolution.high}
|
||||
onSelect={() => handleChange({
|
||||
...file,
|
||||
@ -69,7 +69,7 @@ const ParamConfigContent: FC = () => {
|
||||
/>
|
||||
<OptionCard
|
||||
className="grow"
|
||||
title={t('appDebug.vision.visionSettings.low')}
|
||||
title={t('vision.visionSettings.low', { ns: 'appDebug' })}
|
||||
selected={file?.image?.detail === Resolution.low}
|
||||
onSelect={() => handleChange({
|
||||
...file,
|
||||
@ -79,11 +79,11 @@ const ParamConfigContent: FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<div className="mb-2 text-[13px] font-semibold leading-[18px] text-text-secondary">{t('appDebug.vision.visionSettings.uploadMethod')}</div>
|
||||
<div className="mb-2 text-[13px] font-semibold leading-[18px] text-text-secondary">{t('vision.visionSettings.uploadMethod', { ns: 'appDebug' })}</div>
|
||||
<div className="flex items-center gap-1">
|
||||
<OptionCard
|
||||
className="grow"
|
||||
title={t('appDebug.vision.visionSettings.both')}
|
||||
title={t('vision.visionSettings.both', { ns: 'appDebug' })}
|
||||
selected={!!file?.allowed_file_upload_methods?.includes(TransferMethod.local_file) && !!file?.allowed_file_upload_methods?.includes(TransferMethod.remote_url)}
|
||||
onSelect={() => handleChange({
|
||||
...file,
|
||||
@ -92,7 +92,7 @@ const ParamConfigContent: FC = () => {
|
||||
/>
|
||||
<OptionCard
|
||||
className="grow"
|
||||
title={t('appDebug.vision.visionSettings.localUpload')}
|
||||
title={t('vision.visionSettings.localUpload', { ns: 'appDebug' })}
|
||||
selected={!!file?.allowed_file_upload_methods?.includes(TransferMethod.local_file) && file?.allowed_file_upload_methods?.length === 1}
|
||||
onSelect={() => handleChange({
|
||||
...file,
|
||||
@ -101,7 +101,7 @@ const ParamConfigContent: FC = () => {
|
||||
/>
|
||||
<OptionCard
|
||||
className="grow"
|
||||
title={t('appDebug.vision.visionSettings.url')}
|
||||
title={t('vision.visionSettings.url', { ns: 'appDebug' })}
|
||||
selected={!!file?.allowed_file_upload_methods?.includes(TransferMethod.remote_url) && file?.allowed_file_upload_methods?.length === 1}
|
||||
onSelect={() => handleChange({
|
||||
...file,
|
||||
@ -114,7 +114,7 @@ const ParamConfigContent: FC = () => {
|
||||
<ParamItem
|
||||
id="upload_limit"
|
||||
className=""
|
||||
name={t('appDebug.vision.visionSettings.uploadLimit')}
|
||||
name={t('vision.visionSettings.uploadLimit', { ns: 'appDebug' })}
|
||||
noTooltip
|
||||
{...{
|
||||
default: 2,
|
||||
|
||||
@ -28,7 +28,7 @@ const ParamsConfig: FC = () => {
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||
<Button variant="ghost" size="small" className={cn('')}>
|
||||
<RiSettings2Line className="h-3.5 w-3.5" />
|
||||
<div className="ml-1">{t('appDebug.voice.settings')}</div>
|
||||
<div className="ml-1">{t('voice.settings', { ns: 'appDebug' })}</div>
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent style={{ zIndex: 50 }}>
|
||||
|
||||
@ -7,7 +7,10 @@ import AgentSettingButton from './agent-setting-button'
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
t: (key: string, options?: { ns?: string }) => {
|
||||
const prefix = options?.ns ? `${options.ns}.` : ''
|
||||
return `${prefix}${key}`
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
|
||||
@ -28,7 +28,7 @@ const AgentSettingButton: FC<Props> = ({
|
||||
<>
|
||||
<Button onClick={() => setIsShowAgentSetting(true)} className="mr-2 shrink-0">
|
||||
<RiSettings2Line className="mr-1 h-4 w-4 text-text-tertiary" />
|
||||
{t('appDebug.agent.setting.name')}
|
||||
{t('agent.setting.name', { ns: 'appDebug' })}
|
||||
</Button>
|
||||
{isShowAgentSetting && (
|
||||
<AgentSetting
|
||||
|
||||
@ -61,7 +61,7 @@ const AgentSetting: FC<Props> = ({
|
||||
>
|
||||
<div className="flex h-14 shrink-0 items-center justify-between border-b border-divider-regular pl-6 pr-5">
|
||||
<div className="flex flex-col text-base font-semibold text-text-primary">
|
||||
<div className="leading-6">{t('appDebug.agent.setting.name')}</div>
|
||||
<div className="leading-6">{t('agent.setting.name', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div
|
||||
@ -85,10 +85,10 @@ const AgentSetting: FC<Props> = ({
|
||||
icon={
|
||||
<CuteRobot className="h-4 w-4 text-indigo-600" />
|
||||
}
|
||||
name={t('appDebug.agent.agentMode')}
|
||||
description={t('appDebug.agent.agentModeDes')}
|
||||
name={t('agent.agentMode', { ns: 'appDebug' })}
|
||||
description={t('agent.agentModeDes', { ns: 'appDebug' })}
|
||||
>
|
||||
<div className="text-[13px] font-medium leading-[18px] text-text-primary">{isFunctionCall ? t('appDebug.agent.agentModeType.functionCall') : t('appDebug.agent.agentModeType.ReACT')}</div>
|
||||
<div className="text-[13px] font-medium leading-[18px] text-text-primary">{isFunctionCall ? t('agent.agentModeType.functionCall', { ns: 'appDebug' }) : t('agent.agentModeType.ReACT', { ns: 'appDebug' })}</div>
|
||||
</ItemPanel>
|
||||
|
||||
<ItemPanel
|
||||
@ -96,8 +96,8 @@ const AgentSetting: FC<Props> = ({
|
||||
icon={
|
||||
<Unblur className="h-4 w-4 text-[#FB6514]" />
|
||||
}
|
||||
name={t('appDebug.agent.setting.maximumIterations.name')}
|
||||
description={t('appDebug.agent.setting.maximumIterations.description')}
|
||||
name={t('agent.setting.maximumIterations.name', { ns: 'appDebug' })}
|
||||
description={t('agent.setting.maximumIterations.description', { ns: 'appDebug' })}
|
||||
>
|
||||
<div className="flex items-center">
|
||||
<Slider
|
||||
@ -138,7 +138,7 @@ const AgentSetting: FC<Props> = ({
|
||||
|
||||
{!isFunctionCall && (
|
||||
<div className="rounded-xl bg-background-section-burn py-2 shadow-xs">
|
||||
<div className="flex h-8 items-center px-4 text-sm font-semibold leading-6 text-text-secondary">{t('tools.builtInPromptTitle')}</div>
|
||||
<div className="flex h-8 items-center px-4 text-sm font-semibold leading-6 text-text-secondary">{t('builtInPromptTitle', { ns: 'tools' })}</div>
|
||||
<div className="h-[396px] overflow-y-auto whitespace-pre-line px-4 text-sm font-normal leading-5 text-text-secondary">
|
||||
{isChatModel ? DEFAULT_AGENT_PROMPT.chat : DEFAULT_AGENT_PROMPT.completion}
|
||||
</div>
|
||||
@ -156,13 +156,13 @@ const AgentSetting: FC<Props> = ({
|
||||
onClick={onCancel}
|
||||
className="mr-2"
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleSave}
|
||||
>
|
||||
{t('common.operation.save')}
|
||||
{t('operation.save', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -152,11 +152,11 @@ const AgentTools: FC = () => {
|
||||
noBodySpacing={tools.length === 0}
|
||||
title={(
|
||||
<div className="flex items-center">
|
||||
<div className="mr-1">{t('appDebug.agent.tools.name')}</div>
|
||||
<div className="mr-1">{t('agent.tools.name', { ns: 'appDebug' })}</div>
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.agent.tools.description')}
|
||||
{t('agent.tools.description', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
@ -169,7 +169,7 @@ const AgentTools: FC = () => {
|
||||
/
|
||||
{tools.length}
|
||||
|
||||
{t('appDebug.agent.tools.enabled')}
|
||||
{t('agent.tools.enabled', { ns: 'appDebug' })}
|
||||
</div>
|
||||
{tools.length < MAX_TOOLS_NUM && (
|
||||
<>
|
||||
@ -220,8 +220,8 @@ const AgentTools: FC = () => {
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
<div className="mb-1.5 text-text-secondary">{item.tool_name}</div>
|
||||
<div className="mb-1.5 text-text-tertiary">{t('tools.toolNameUsageTip')}</div>
|
||||
<div className="cursor-pointer text-text-accent" onClick={() => copy(item.tool_name)}>{t('tools.copyToolName')}</div>
|
||||
<div className="mb-1.5 text-text-tertiary">{t('toolNameUsageTip', { ns: 'tools' })}</div>
|
||||
<div className="cursor-pointer text-text-accent" onClick={() => copy(item.tool_name)}>{t('copyToolName', { ns: 'tools' })}</div>
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
@ -238,7 +238,7 @@ const AgentTools: FC = () => {
|
||||
{item.isDeleted && (
|
||||
<div className="mr-2 flex items-center">
|
||||
<Tooltip
|
||||
popupContent={t('tools.toolRemoved')}
|
||||
popupContent={t('toolRemoved', { ns: 'tools' })}
|
||||
>
|
||||
<div className="mr-1 cursor-pointer rounded-md p-1 hover:bg-black/5">
|
||||
<AlertTriangle className="h-4 w-4 text-[#F79009]" />
|
||||
@ -264,7 +264,7 @@ const AgentTools: FC = () => {
|
||||
<div className="mr-2 hidden items-center gap-1 group-hover:flex">
|
||||
{!item.notAuthor && (
|
||||
<Tooltip
|
||||
popupContent={t('tools.setBuiltInTools.infoAndSetting')}
|
||||
popupContent={t('setBuiltInTools.infoAndSetting', { ns: 'tools' })}
|
||||
needsDelay={false}
|
||||
>
|
||||
<div
|
||||
@ -319,7 +319,7 @@ const AgentTools: FC = () => {
|
||||
setIsShowSettingTool(true)
|
||||
}}
|
||||
>
|
||||
{t('tools.notAuthorized')}
|
||||
{t('notAuthorized', { ns: 'tools' })}
|
||||
<Indicator className="ml-2" color="orange" />
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@ -115,13 +115,13 @@ const SettingBuiltInTool: FC<Props> = ({
|
||||
|
||||
const getType = (type: string) => {
|
||||
if (type === 'number-input')
|
||||
return t('tools.setBuiltInTools.number')
|
||||
return t('setBuiltInTools.number', { ns: 'tools' })
|
||||
if (type === 'text-input')
|
||||
return t('tools.setBuiltInTools.string')
|
||||
return t('setBuiltInTools.string', { ns: 'tools' })
|
||||
if (type === 'checkbox')
|
||||
return 'boolean'
|
||||
if (type === 'file')
|
||||
return t('tools.setBuiltInTools.file')
|
||||
return t('setBuiltInTools.file', { ns: 'tools' })
|
||||
return type
|
||||
}
|
||||
|
||||
@ -137,7 +137,7 @@ const SettingBuiltInTool: FC<Props> = ({
|
||||
{getType(item.type)}
|
||||
</div>
|
||||
{item.required && (
|
||||
<div className="system-xs-medium text-text-warning-secondary">{t('tools.setBuiltInTools.required')}</div>
|
||||
<div className="system-xs-medium text-text-warning-secondary">{t('setBuiltInTools.required', { ns: 'tools' })}</div>
|
||||
)}
|
||||
</div>
|
||||
{item.human_description && (
|
||||
@ -191,7 +191,7 @@ const SettingBuiltInTool: FC<Props> = ({
|
||||
onClick={onHide}
|
||||
>
|
||||
<RiArrowLeftLine className="h-4 w-4" />
|
||||
{t('plugin.detailPanel.operation.back')}
|
||||
{t('detailPanel.operation.back', { ns: 'plugin' })}
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-1">
|
||||
@ -235,20 +235,20 @@ const SettingBuiltInTool: FC<Props> = ({
|
||||
setCurrType(value)
|
||||
}}
|
||||
options={[
|
||||
{ value: 'info', text: t('tools.setBuiltInTools.parameters')! },
|
||||
{ value: 'setting', text: t('tools.setBuiltInTools.setting')! },
|
||||
{ value: 'info', text: t('setBuiltInTools.parameters', { ns: 'tools' })! },
|
||||
{ value: 'setting', text: t('setBuiltInTools.setting', { ns: 'tools' })! },
|
||||
]}
|
||||
/>
|
||||
)
|
||||
: (
|
||||
<div className="system-sm-semibold-uppercase p-4 pb-1 text-text-primary">{t('tools.setBuiltInTools.parameters')}</div>
|
||||
<div className="system-sm-semibold-uppercase p-4 pb-1 text-text-primary">{t('setBuiltInTools.parameters', { ns: 'tools' })}</div>
|
||||
)}
|
||||
<div className="h-0 grow overflow-y-auto px-4">
|
||||
{isInfoActive ? infoUI : settingUI}
|
||||
{!readonly && !isInfoActive && (
|
||||
<div className="flex shrink-0 justify-end space-x-2 rounded-b-[10px] bg-components-panel-bg py-2">
|
||||
<Button className="flex h-8 items-center !px-3 !text-[13px] font-medium " onClick={onHide}>{t('common.operation.cancel')}</Button>
|
||||
<Button className="flex h-8 items-center !px-3 !text-[13px] font-medium" variant="primary" disabled={!isValid} onClick={() => onSave?.(tempSetting)}>{t('common.operation.save')}</Button>
|
||||
<Button className="flex h-8 items-center !px-3 !text-[13px] font-medium " onClick={onHide}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Button className="flex h-8 items-center !px-3 !text-[13px] font-medium" variant="primary" disabled={!isValid} onClick={() => onSave?.(tempSetting)}>{t('operation.save', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -59,14 +59,14 @@ const Editor: FC<Props> = ({
|
||||
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
||||
for (let i = 0; i < promptVariables.length; i++) {
|
||||
if (promptVariables[i].key === newExternalDataTool.variable) {
|
||||
notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
|
||||
notify({ type: 'error', message: t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: promptVariables[i].key }) })
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < externalDataToolsConfig.length; i++) {
|
||||
if (externalDataToolsConfig[i].variable === newExternalDataTool.variable) {
|
||||
notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: externalDataToolsConfig[i].variable }) })
|
||||
notify({ type: 'error', message: t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: externalDataToolsConfig[i].variable }) })
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -79,7 +79,7 @@ const Editor: FC<Props> = ({
|
||||
<div className={cn(className, s.gradientBorder, 'relative')}>
|
||||
<div className="rounded-xl bg-white">
|
||||
<div className={cn(s.boxHeader, 'flex h-11 items-center justify-between rounded-tl-xl rounded-tr-xl bg-white pb-1 pl-4 pr-3 pt-2 hover:shadow-xs')}>
|
||||
<div className="text-sm font-semibold uppercase text-indigo-800">{t(`appDebug.agent.${isFirstPrompt ? 'firstPrompt' : 'nextIteration'}`)}</div>
|
||||
<div className="text-sm font-semibold uppercase text-indigo-800">{t(`agent.${isFirstPrompt ? 'firstPrompt' : 'nextIteration'}`, { ns: 'appDebug' })}</div>
|
||||
<div className={cn(s.optionWrap, 'items-center space-x-1')}>
|
||||
{!isCopied
|
||||
? (
|
||||
|
||||
@ -97,11 +97,11 @@ const AssistantTypePicker: FC<Props> = ({
|
||||
<div className="mr-3 rounded-lg bg-gray-200 p-1 group-hover:bg-white">
|
||||
<Settings04 className="h-4 w-4 text-gray-600 group-hover:text-[#155EEF]" />
|
||||
</div>
|
||||
<div className="text-sm font-medium leading-5 text-gray-900 group-hover:text-[#155EEF]">{t('appDebug.agent.setting.name')}</div>
|
||||
<div className="text-sm font-medium leading-5 text-gray-900 group-hover:text-[#155EEF]">{t('agent.setting.name', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
<ArrowUpRight className="h-4 w-4 text-gray-500 group-hover:text-[#155EEF]" />
|
||||
</div>
|
||||
<div className="ml-9 text-xs font-normal leading-[18px] text-gray-500">{t('appDebug.agent.setting.description')}</div>
|
||||
<div className="ml-9 text-xs font-normal leading-[18px] text-gray-500">{t('agent.setting.description', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
@ -119,19 +119,19 @@ const AssistantTypePicker: FC<Props> = ({
|
||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||
<div className={cn(open && 'bg-gray-50', 'flex h-8 cursor-pointer select-none items-center space-x-1 rounded-lg border border-black/5 px-3 text-indigo-600')}>
|
||||
{isAgent ? <BubbleText className="h-3 w-3" /> : <CuteRobot className="h-3 w-3" />}
|
||||
<div className="text-xs font-medium">{t(`appDebug.assistantType.${isAgent ? 'agentAssistant' : 'chatAssistant'}.name`)}</div>
|
||||
<div className="text-xs font-medium">{t(`assistantType.${isAgent ? 'agentAssistant' : 'chatAssistant'}.name`, { ns: 'appDebug' })}</div>
|
||||
<RiArrowDownSLine className="h-3 w-3" />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent style={{ zIndex: 1000 }}>
|
||||
<div className="relative left-0.5 w-[480px] rounded-xl border border-black/8 bg-white p-6 shadow-lg">
|
||||
<div className="mb-2 text-sm font-semibold leading-5 text-gray-900">{t('appDebug.assistantType.name')}</div>
|
||||
<div className="mb-2 text-sm font-semibold leading-5 text-gray-900">{t('assistantType.name', { ns: 'appDebug' })}</div>
|
||||
<SelectItem
|
||||
Icon={BubbleText}
|
||||
value="chat"
|
||||
disabled={disabled}
|
||||
text={t('appDebug.assistantType.chatAssistant.name')}
|
||||
description={t('appDebug.assistantType.chatAssistant.description')}
|
||||
text={t('assistantType.chatAssistant.name', { ns: 'appDebug' })}
|
||||
description={t('assistantType.chatAssistant.description', { ns: 'appDebug' })}
|
||||
isChecked={!isAgent}
|
||||
onClick={handleChange}
|
||||
/>
|
||||
@ -139,8 +139,8 @@ const AssistantTypePicker: FC<Props> = ({
|
||||
Icon={CuteRobot}
|
||||
value="agent"
|
||||
disabled={disabled}
|
||||
text={t('appDebug.assistantType.agentAssistant.name')}
|
||||
description={t('appDebug.assistantType.agentAssistant.description')}
|
||||
text={t('assistantType.agentAssistant.name', { ns: 'appDebug' })}
|
||||
description={t('assistantType.agentAssistant.description', { ns: 'appDebug' })}
|
||||
isChecked={isAgent}
|
||||
onClick={handleChange}
|
||||
/>
|
||||
|
||||
@ -18,7 +18,7 @@ const AutomaticBtn: FC<IAutomaticBtnProps> = ({
|
||||
return (
|
||||
<Button variant="secondary-accent" size="small" onClick={onClick}>
|
||||
<RiSparklingFill className="mr-1 h-3.5 w-3.5" />
|
||||
<span className="">{t('appDebug.operation.automatic')}</span>
|
||||
<span className="">{t('operation.automatic', { ns: 'appDebug' })}</span>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
||||
@ -41,7 +41,8 @@ import s from './style.module.css'
|
||||
import { GeneratorType } from './types'
|
||||
import useGenData from './use-gen-data'
|
||||
|
||||
const i18nPrefix = 'appDebug.generate'
|
||||
const i18nPrefix = 'generate'
|
||||
|
||||
export type IGetAutomaticResProps = {
|
||||
mode: AppModeEnum
|
||||
isShow: boolean
|
||||
@ -131,17 +132,19 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
icon: RiGitCommitLine,
|
||||
key: 'GitGud',
|
||||
},
|
||||
]
|
||||
] as const
|
||||
|
||||
// eslint-disable-next-line sonarjs/no-nested-template-literals, sonarjs/no-nested-conditional
|
||||
const [instructionFromSessionStorage, setInstruction] = useSessionStorageState<string>(`improve-instruction-${flowId}${isBasicMode ? '' : `-${nodeId}${editorId ? `-${editorId}` : ''}`}`)
|
||||
const instruction = instructionFromSessionStorage || ''
|
||||
const [ideaOutput, setIdeaOutput] = useState<string>('')
|
||||
|
||||
type TemplateKey = typeof tryList[number]['key']
|
||||
|
||||
const [editorKey, setEditorKey] = useState(`${flowId}-0`)
|
||||
const handleChooseTemplate = useCallback((key: string) => {
|
||||
const handleChooseTemplate = useCallback((key: TemplateKey) => {
|
||||
return () => {
|
||||
const template = t(`appDebug.generate.template.${key}.instruction` as any) as string
|
||||
const template = t(`generate.template.${key}.instruction` as const, { ns: 'appDebug' })
|
||||
setInstruction(template)
|
||||
setEditorKey(`${flowId}-${Date.now()}`)
|
||||
}
|
||||
@ -159,8 +162,9 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
if (instruction.trim() === '') {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('common.errorMsg.fieldRequired', {
|
||||
field: t('appDebug.generate.instruction'),
|
||||
message: t('errorMsg.fieldRequired', {
|
||||
ns: 'common',
|
||||
field: t('generate.instruction', { ns: 'appDebug' }),
|
||||
}),
|
||||
})
|
||||
return false
|
||||
@ -194,7 +198,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
const renderLoading = (
|
||||
<div className="flex h-full w-0 grow flex-col items-center justify-center space-y-3">
|
||||
<Loading />
|
||||
<div className="text-[13px] text-text-tertiary">{t('appDebug.generate.loading')}</div>
|
||||
<div className="text-[13px] text-text-tertiary">{t('generate.loading', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -289,8 +293,8 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
<div className="flex h-[680px] flex-wrap">
|
||||
<div className="h-full w-[570px] shrink-0 overflow-y-auto border-r border-divider-regular p-6">
|
||||
<div className="mb-5">
|
||||
<div className={`text-lg font-bold leading-[28px] ${s.textGradient}`}>{t('appDebug.generate.title')}</div>
|
||||
<div className="mt-1 text-[13px] font-normal text-text-tertiary">{t('appDebug.generate.description')}</div>
|
||||
<div className={`text-lg font-bold leading-[28px] ${s.textGradient}`}>{t('generate.title', { ns: 'appDebug' })}</div>
|
||||
<div className="mt-1 text-[13px] font-normal text-text-tertiary">{t('generate.description', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
<div>
|
||||
<ModelParameterModal
|
||||
@ -308,7 +312,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
{isBasicMode && (
|
||||
<div className="mt-4">
|
||||
<div className="flex items-center">
|
||||
<div className="mr-3 shrink-0 text-xs font-semibold uppercase leading-[18px] text-text-tertiary">{t('appDebug.generate.tryIt')}</div>
|
||||
<div className="mr-3 shrink-0 text-xs font-semibold uppercase leading-[18px] text-text-tertiary">{t('generate.tryIt', { ns: 'appDebug' })}</div>
|
||||
<div
|
||||
className="h-px grow"
|
||||
style={{
|
||||
@ -322,7 +326,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
<TryLabel
|
||||
key={item.key}
|
||||
Icon={item.icon}
|
||||
text={t(`appDebug.generate.template.${item.key}.name` as any) as string}
|
||||
text={t(`generate.template.${item.key}.name`, { ns: 'appDebug' })}
|
||||
onClick={handleChooseTemplate(item.key)}
|
||||
/>
|
||||
))}
|
||||
@ -333,7 +337,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
{/* inputs */}
|
||||
<div className="mt-4">
|
||||
<div>
|
||||
<div className="system-sm-semibold-uppercase mb-1.5 text-text-secondary">{t('appDebug.generate.instruction')}</div>
|
||||
<div className="system-sm-semibold-uppercase mb-1.5 text-text-secondary">{t('generate.instruction', { ns: 'appDebug' })}</div>
|
||||
{isBasicMode
|
||||
? (
|
||||
<InstructionEditorInBasic
|
||||
@ -364,7 +368,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
/>
|
||||
|
||||
<div className="mt-7 flex justify-end space-x-2">
|
||||
<Button onClick={onClose}>{t(`${i18nPrefix}.dismiss`)}</Button>
|
||||
<Button onClick={onClose}>{t(`${i18nPrefix}.dismiss`, { ns: 'appDebug' })}</Button>
|
||||
<Button
|
||||
className="flex space-x-1"
|
||||
variant="primary"
|
||||
@ -372,7 +376,7 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Generator className="h-4 w-4" />
|
||||
<span className="text-xs font-semibold">{t('appDebug.generate.generate')}</span>
|
||||
<span className="text-xs font-semibold">{t('generate.generate', { ns: 'appDebug' })}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@ -396,8 +400,8 @@ const GetAutomaticRes: FC<IGetAutomaticResProps> = ({
|
||||
{isShowAutoPromptResPlaceholder() && <ResPlaceholder />}
|
||||
{isShowConfirmOverwrite && (
|
||||
<Confirm
|
||||
title={t('appDebug.generate.overwriteTitle')}
|
||||
content={t('appDebug.generate.overwriteMessage')}
|
||||
title={t('generate.overwriteTitle', { ns: 'appDebug' })}
|
||||
content={t('generate.overwriteMessage', { ns: 'appDebug' })}
|
||||
isShow
|
||||
onConfirm={() => {
|
||||
hideShowConfirmOverwrite()
|
||||
|
||||
@ -7,7 +7,7 @@ import { ArrowDownRoundFill } from '@/app/components/base/icons/src/vender/solid
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
const i18nPrefix = 'appDebug.generate'
|
||||
const i18nPrefix = 'generate'
|
||||
|
||||
type Props = {
|
||||
value: string
|
||||
@ -30,10 +30,10 @@ const IdeaOutput: FC<Props> = ({
|
||||
className="mb-1.5 flex cursor-pointer items-center text-sm font-medium leading-5 text-text-primary"
|
||||
onClick={toggleFoldIdeaOutput}
|
||||
>
|
||||
<div className="system-sm-semibold-uppercase mr-1 text-text-secondary">{t(`${i18nPrefix}.idealOutput`)}</div>
|
||||
<div className="system-sm-semibold-uppercase mr-1 text-text-secondary">{t(`${i18nPrefix}.idealOutput`, { ns: 'appDebug' })}</div>
|
||||
<div className="system-xs-regular text-text-tertiary">
|
||||
(
|
||||
{t(`${i18nPrefix}.optional`)}
|
||||
{t(`${i18nPrefix}.optional`, { ns: 'appDebug' })}
|
||||
)
|
||||
</div>
|
||||
<ArrowDownRoundFill className={cn('size text-text-quaternary', isFoldIdeaOutput && 'relative top-[1px] rotate-[-90deg]')} />
|
||||
@ -41,7 +41,7 @@ const IdeaOutput: FC<Props> = ({
|
||||
{!isFoldIdeaOutput && (
|
||||
<Textarea
|
||||
className="h-[80px]"
|
||||
placeholder={t(`${i18nPrefix}.idealOutputPlaceholder`)}
|
||||
placeholder={t(`${i18nPrefix}.idealOutputPlaceholder`, { ns: 'appDebug' })}
|
||||
value={value}
|
||||
onChange={e => onChange(e.target.value)}
|
||||
/>
|
||||
|
||||
@ -26,7 +26,7 @@ type Props = {
|
||||
isShowLastRunBlock: boolean
|
||||
}
|
||||
|
||||
const i18nPrefix = 'appDebug.generate'
|
||||
const i18nPrefix = 'generate'
|
||||
|
||||
const InstructionEditor: FC<Props> = ({
|
||||
editorKey,
|
||||
@ -46,16 +46,16 @@ const InstructionEditor: FC<Props> = ({
|
||||
const placeholder = isCode
|
||||
? (
|
||||
<div className="system-sm-regular whitespace-break-spaces !leading-6 text-text-placeholder">
|
||||
{t(`${i18nPrefix}.codeGenInstructionPlaceHolderLine`)}
|
||||
{t(`${i18nPrefix}.codeGenInstructionPlaceHolderLine`, { ns: 'appDebug' })}
|
||||
</div>
|
||||
)
|
||||
: (
|
||||
<div className="system-sm-regular text-text-placeholder">
|
||||
<div className="leading-6">{t(`${i18nPrefix}.instructionPlaceHolderTitle`)}</div>
|
||||
<div className="leading-6">{t(`${i18nPrefix}.instructionPlaceHolderTitle`, { ns: 'appDebug' })}</div>
|
||||
<div className="mt-2">
|
||||
<div>{t(`${i18nPrefix}.instructionPlaceHolderLine1`)}</div>
|
||||
<div>{t(`${i18nPrefix}.instructionPlaceHolderLine2`)}</div>
|
||||
<div>{t(`${i18nPrefix}.instructionPlaceHolderLine3`)}</div>
|
||||
<div>{t(`${i18nPrefix}.instructionPlaceHolderLine1`, { ns: 'appDebug' })}</div>
|
||||
<div>{t(`${i18nPrefix}.instructionPlaceHolderLine2`, { ns: 'appDebug' })}</div>
|
||||
<div>{t(`${i18nPrefix}.instructionPlaceHolderLine3`, { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
@ -88,7 +88,7 @@ const InstructionEditor: FC<Props> = ({
|
||||
}
|
||||
if (node.data.type === BlockEnum.Start) {
|
||||
acc.sys = {
|
||||
title: t('workflow.blocks.start'),
|
||||
title: t('blocks.start', { ns: 'workflow' }),
|
||||
type: BlockEnum.Start,
|
||||
}
|
||||
}
|
||||
@ -110,10 +110,10 @@ const InstructionEditor: FC<Props> = ({
|
||||
isSupportFileVar={false}
|
||||
/>
|
||||
<div className="system-xs-regular absolute bottom-0 left-4 flex h-8 items-center space-x-0.5 text-components-input-text-placeholder">
|
||||
<span>{t('appDebug.generate.press')}</span>
|
||||
<span>{t('generate.press', { ns: 'appDebug' })}</span>
|
||||
<span className="system-kbd flex h-4 w-3.5 items-center justify-center rounded-[4px] bg-components-kbd-bg-gray text-text-placeholder">/</span>
|
||||
<span>{t('appDebug.generate.to')}</span>
|
||||
<span onClick={handleInsertVariable} className="!ml-1 cursor-pointer hover:border-b hover:border-dotted hover:border-text-tertiary hover:text-text-tertiary">{t('appDebug.generate.insertContext')}</span>
|
||||
<span>{t('generate.to', { ns: 'appDebug' })}</span>
|
||||
<span onClick={handleInsertVariable} className="!ml-1 cursor-pointer hover:border-b hover:border-dotted hover:border-text-tertiary hover:text-text-tertiary">{t('generate.insertContext', { ns: 'appDebug' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -41,7 +41,7 @@ const PromptResInWorkflow: FC<Props> = ({
|
||||
}
|
||||
if (node.data.type === BlockEnum.Start) {
|
||||
acc.sys = {
|
||||
title: t('workflow.blocks.start'),
|
||||
title: t('blocks.start', { ns: 'workflow' }),
|
||||
type: BlockEnum.Start,
|
||||
}
|
||||
}
|
||||
|
||||
@ -38,7 +38,7 @@ const PromptToast = ({
|
||||
<div className="my-3 flex h-4 items-center justify-between pr-3">
|
||||
<div className="flex items-center space-x-1">
|
||||
<RiSparklingFill className="size-3.5 text-components-input-border-active-prompt-1" />
|
||||
<span className={cn(s.optimizationNoteText, 'system-xs-semibold-uppercase')}>{t('appDebug.generate.optimizationNote')}</span>
|
||||
<span className={cn(s.optimizationNoteText, 'system-xs-semibold-uppercase')}>{t('generate.optimizationNote', { ns: 'appDebug' })}</span>
|
||||
</div>
|
||||
<RiArrowDownSLine className={cn('size-4 cursor-pointer text-text-tertiary', isFold && 'rotate-[-90deg]')} onClick={toggleFold} />
|
||||
</div>
|
||||
|
||||
@ -10,7 +10,7 @@ const ResPlaceholder: FC = () => {
|
||||
<div className="flex h-full w-0 grow flex-col items-center justify-center space-y-3 px-8">
|
||||
<Generator className="size-8 text-text-quaternary" />
|
||||
<div className="text-center text-[13px] font-normal leading-5 text-text-tertiary">
|
||||
<div>{t('appDebug.generate.newNoDataLine1')}</div>
|
||||
<div>{t('generate.newNoDataLine1', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -42,7 +42,7 @@ const Result: FC<Props> = ({
|
||||
<div className="flex h-full flex-col">
|
||||
<div className="mb-3 flex shrink-0 items-center justify-between">
|
||||
<div>
|
||||
<div className="shrink-0 text-base font-semibold leading-[160%] text-text-secondary">{t('appDebug.generate.resTitle')}</div>
|
||||
<div className="shrink-0 text-base font-semibold leading-[160%] text-text-secondary">{t('generate.resTitle', { ns: 'appDebug' })}</div>
|
||||
<VersionSelector
|
||||
versionLen={versions.length}
|
||||
value={currentVersionIndex}
|
||||
@ -54,13 +54,13 @@ const Result: FC<Props> = ({
|
||||
className="px-2"
|
||||
onClick={() => {
|
||||
copy(current.modified)
|
||||
Toast.notify({ type: 'success', message: t('common.actionMsg.copySuccessfully') })
|
||||
Toast.notify({ type: 'success', message: t('actionMsg.copySuccessfully', { ns: 'common' }) })
|
||||
}}
|
||||
>
|
||||
<RiClipboardLine className="h-4 w-4 text-text-secondary" />
|
||||
</Button>
|
||||
<Button variant="primary" onClick={onApply}>
|
||||
{t('appDebug.generate.apply')}
|
||||
{t('generate.apply', { ns: 'appDebug' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -31,7 +31,7 @@ const VersionSelector: React.FC<VersionSelectorProps> = ({ versionLen, value, on
|
||||
}, [moreThanOneVersion, handleOpenToggle])
|
||||
|
||||
const versions = Array.from({ length: versionLen }, (_, index) => ({
|
||||
label: `${t('appDebug.generate.version')} ${index + 1}${index === versionLen - 1 ? ` · ${t('appDebug.generate.latest')}` : ''}`,
|
||||
label: `${t('generate.version', { ns: 'appDebug' })} ${index + 1}${index === versionLen - 1 ? ` · ${t('generate.latest', { ns: 'appDebug' })}` : ''}`,
|
||||
value: index,
|
||||
}))
|
||||
|
||||
@ -54,10 +54,10 @@ const VersionSelector: React.FC<VersionSelectorProps> = ({ versionLen, value, on
|
||||
|
||||
<div className={cn('system-xs-medium flex items-center text-text-tertiary', isOpen && 'text-text-secondary', moreThanOneVersion && 'cursor-pointer')}>
|
||||
<div>
|
||||
{t('appDebug.generate.version')}
|
||||
{t('generate.version', { ns: 'appDebug' })}
|
||||
{' '}
|
||||
{value + 1}
|
||||
{isLatest && ` · ${t('appDebug.generate.latest')}`}
|
||||
{isLatest && ` · ${t('generate.latest', { ns: 'appDebug' })}`}
|
||||
</div>
|
||||
{moreThanOneVersion && <RiArrowDownSLine className="size-3 " />}
|
||||
</div>
|
||||
@ -72,7 +72,7 @@ const VersionSelector: React.FC<VersionSelectorProps> = ({ versionLen, value, on
|
||||
)}
|
||||
>
|
||||
<div className={cn('system-xs-medium-uppercase flex h-[22px] items-center px-3 pl-3 text-text-tertiary')}>
|
||||
{t('appDebug.generate.versions')}
|
||||
{t('generate.versions', { ns: 'appDebug' })}
|
||||
</div>
|
||||
{
|
||||
versions.map(option => (
|
||||
|
||||
@ -28,7 +28,7 @@ import s from '../automatic/style.module.css'
|
||||
import { GeneratorType } from '../automatic/types'
|
||||
import useGenData from '../automatic/use-gen-data'
|
||||
|
||||
const i18nPrefix = 'appDebug.generate'
|
||||
const i18nPrefix = 'generate'
|
||||
export type IGetCodeGeneratorResProps = {
|
||||
flowId: string
|
||||
nodeId: string
|
||||
@ -97,8 +97,9 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
|
||||
if (instruction.trim() === '') {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('common.errorMsg.fieldRequired', {
|
||||
field: t('appDebug.code.instruction'),
|
||||
message: t('errorMsg.fieldRequired', {
|
||||
ns: 'common',
|
||||
field: t('code.instruction', { ns: 'appDebug' }),
|
||||
}),
|
||||
})
|
||||
return false
|
||||
@ -192,7 +193,7 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
|
||||
const renderLoading = (
|
||||
<div className="flex h-full w-0 grow flex-col items-center justify-center space-y-3">
|
||||
<Loading />
|
||||
<div className="text-[13px] text-text-tertiary">{t('appDebug.codegen.loading')}</div>
|
||||
<div className="text-[13px] text-text-tertiary">{t('codegen.loading', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -205,8 +206,8 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
|
||||
<div className="relative flex h-[680px] flex-wrap">
|
||||
<div className="h-full w-[570px] shrink-0 overflow-y-auto border-r border-divider-regular p-6">
|
||||
<div className="mb-5">
|
||||
<div className={`text-lg font-bold leading-[28px] ${s.textGradient}`}>{t('appDebug.codegen.title')}</div>
|
||||
<div className="mt-1 text-[13px] font-normal text-text-tertiary">{t('appDebug.codegen.description')}</div>
|
||||
<div className={`text-lg font-bold leading-[28px] ${s.textGradient}`}>{t('codegen.title', { ns: 'appDebug' })}</div>
|
||||
<div className="mt-1 text-[13px] font-normal text-text-tertiary">{t('codegen.description', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
<div className="mb-4">
|
||||
<ModelParameterModal
|
||||
@ -223,7 +224,7 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
|
||||
</div>
|
||||
<div>
|
||||
<div className="text-[0px]">
|
||||
<div className="system-sm-semibold-uppercase mb-1.5 text-text-secondary">{t('appDebug.codegen.instruction')}</div>
|
||||
<div className="system-sm-semibold-uppercase mb-1.5 text-text-secondary">{t('codegen.instruction', { ns: 'appDebug' })}</div>
|
||||
<InstructionEditor
|
||||
editorKey={editorKey}
|
||||
value={instruction}
|
||||
@ -239,7 +240,7 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
|
||||
/>
|
||||
|
||||
<div className="mt-7 flex justify-end space-x-2">
|
||||
<Button onClick={onClose}>{t(`${i18nPrefix}.dismiss`)}</Button>
|
||||
<Button onClick={onClose}>{t(`${i18nPrefix}.dismiss`, { ns: 'appDebug' })}</Button>
|
||||
<Button
|
||||
className="flex space-x-1"
|
||||
variant="primary"
|
||||
@ -247,7 +248,7 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
|
||||
disabled={isLoading}
|
||||
>
|
||||
<Generator className="h-4 w-4" />
|
||||
<span className="text-xs font-semibold ">{t('appDebug.codegen.generate')}</span>
|
||||
<span className="text-xs font-semibold ">{t('codegen.generate', { ns: 'appDebug' })}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
@ -269,8 +270,8 @@ export const GetCodeGeneratorResModal: FC<IGetCodeGeneratorResProps> = (
|
||||
</div>
|
||||
{isShowConfirmOverwrite && (
|
||||
<Confirm
|
||||
title={t('appDebug.codegen.overwriteConfirmTitle')}
|
||||
content={t('appDebug.codegen.overwriteConfirmMessage')}
|
||||
title={t('codegen.overwriteConfirmTitle', { ns: 'appDebug' })}
|
||||
content={t('codegen.overwriteConfirmMessage', { ns: 'appDebug' })}
|
||||
isShow
|
||||
onConfirm={() => {
|
||||
hideShowConfirmOverwrite()
|
||||
|
||||
@ -17,7 +17,10 @@ vi.mock('use-context-selector', async (importOriginal) => {
|
||||
|
||||
vi.mock('react-i18next', () => ({
|
||||
useTranslation: () => ({
|
||||
t: (key: string) => key,
|
||||
t: (key: string, options?: { ns?: string }) => {
|
||||
const prefix = options?.ns ? `${options.ns}.` : ''
|
||||
return `${prefix}${key}`
|
||||
},
|
||||
}),
|
||||
}))
|
||||
|
||||
|
||||
@ -56,11 +56,11 @@ const ConfigAudio: FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex grow items-center">
|
||||
<div className="system-sm-semibold mr-1 text-text-secondary">{t('appDebug.feature.audioUpload.title')}</div>
|
||||
<div className="system-sm-semibold mr-1 text-text-secondary">{t('feature.audioUpload.title', { ns: 'appDebug' })}</div>
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.feature.audioUpload.description')}
|
||||
{t('feature.audioUpload.description', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -56,11 +56,11 @@ const ConfigDocument: FC = () => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex grow items-center">
|
||||
<div className="system-sm-semibold mr-1 text-text-secondary">{t('appDebug.feature.documentUpload.title')}</div>
|
||||
<div className="system-sm-semibold mr-1 text-text-secondary">{t('feature.documentUpload.title', { ns: 'appDebug' })}</div>
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.feature.documentUpload.description')}
|
||||
{t('feature.documentUpload.description', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -15,8 +15,8 @@ const ContrlBtnGroup: FC<IContrlBtnGroupProps> = ({ onSave, onReset }) => {
|
||||
return (
|
||||
<div className="fixed bottom-0 left-[224px] h-[64px] w-[519px]">
|
||||
<div className={`${s.ctrlBtn} flex h-full items-center gap-2 bg-white pl-4`}>
|
||||
<Button variant="primary" onClick={onSave} data-testid="apply-btn">{t('appDebug.operation.applyConfig')}</Button>
|
||||
<Button onClick={onReset} data-testid="reset-btn">{t('appDebug.operation.resetConfig')}</Button>
|
||||
<Button variant="primary" onClick={onSave} data-testid="apply-btn">{t('operation.applyConfig', { ns: 'appDebug' })}</Button>
|
||||
<Button onClick={onReset} data-testid="reset-btn">{t('operation.resetConfig', { ns: 'appDebug' })}</Button>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@ -102,7 +102,7 @@ const Item: FC<ItemProps> = ({
|
||||
config.provider === 'external' && (
|
||||
<Badge
|
||||
className="shrink-0 group-hover:hidden"
|
||||
text={t('dataset.externalTag') as string}
|
||||
text={t('externalTag', { ns: 'dataset' }) as string}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@ -19,11 +19,11 @@ const ContextVar: FC<Props> = (props) => {
|
||||
<div className="p-1">
|
||||
<BracketsX className="h-4 w-4 text-text-accent" />
|
||||
</div>
|
||||
<div className="mr-1 text-sm font-medium text-text-secondary">{t('appDebug.feature.dataSet.queryVariable.title')}</div>
|
||||
<div className="mr-1 text-sm font-medium text-text-secondary">{t('feature.dataSet.queryVariable.title', { ns: 'appDebug' })}</div>
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[180px]">
|
||||
{t('appDebug.feature.dataSet.queryVariable.tip')}
|
||||
{t('feature.dataSet.queryVariable.tip', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
|
||||
@ -72,7 +72,7 @@ const VarPicker: FC<Props> = ({
|
||||
)
|
||||
: (
|
||||
<div>
|
||||
{notSelectedVarTip || t('appDebug.feature.dataSet.queryVariable.choosePlaceholder')}
|
||||
{notSelectedVarTip || t('feature.dataSet.queryVariable.choosePlaceholder', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -99,8 +99,8 @@ const VarPicker: FC<Props> = ({
|
||||
)
|
||||
: (
|
||||
<div className="w-[240px] rounded-lg border border-components-panel-border bg-components-panel-bg p-6 shadow-lg">
|
||||
<div className="mb-1 text-sm font-medium text-text-secondary">{t('appDebug.feature.dataSet.queryVariable.noVar')}</div>
|
||||
<div className="text-xs leading-normal text-text-tertiary">{t('appDebug.feature.dataSet.queryVariable.noVarTip')}</div>
|
||||
<div className="mb-1 text-sm font-medium text-text-secondary">{t('feature.dataSet.queryVariable.noVar', { ns: 'appDebug' })}</div>
|
||||
<div className="text-xs leading-normal text-text-tertiary">{t('feature.dataSet.queryVariable.noVarTip', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@ -176,7 +176,7 @@ const DatasetConfig: FC = () => {
|
||||
}))
|
||||
}, [setDatasetConfigs, datasetConfigsRef])
|
||||
|
||||
const handleAddCondition = useCallback<HandleAddCondition>(({ name, type }) => {
|
||||
const handleAddCondition = useCallback<HandleAddCondition>(({ id, name, type }) => {
|
||||
let operator: ComparisonOperator = ComparisonOperator.is
|
||||
|
||||
if (type === MetadataFilteringVariableType.number)
|
||||
@ -184,6 +184,7 @@ const DatasetConfig: FC = () => {
|
||||
|
||||
const newCondition = {
|
||||
id: uuid4(),
|
||||
metadata_id: id, // Save metadata.id for reliable reference
|
||||
name,
|
||||
comparison_operator: operator,
|
||||
}
|
||||
@ -256,7 +257,7 @@ const DatasetConfig: FC = () => {
|
||||
return (
|
||||
<FeaturePanel
|
||||
className="mt-2"
|
||||
title={t('appDebug.feature.dataSet.title')}
|
||||
title={t('feature.dataSet.title', { ns: 'appDebug' })}
|
||||
headerRight={(
|
||||
<div className="flex items-center gap-1">
|
||||
{!isAgent && <ParamsConfig disabled={!hasData} selectedDatasets={dataSet} />}
|
||||
@ -282,7 +283,7 @@ const DatasetConfig: FC = () => {
|
||||
)
|
||||
: (
|
||||
<div className="mt-1 px-3 pb-3">
|
||||
<div className="pb-1 pt-2 text-xs text-text-tertiary">{t('appDebug.feature.dataSet.noData')}</div>
|
||||
<div className="pb-1 pt-2 text-xs text-text-tertiary">{t('feature.dataSet.noData', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@ -136,7 +136,7 @@ const ConfigContent: FC<Props> = ({
|
||||
return
|
||||
|
||||
if (mode === RerankingModeEnum.RerankingModel && !currentRerankModel)
|
||||
Toast.notify({ type: 'error', message: t('workflow.errorMsg.rerankModelRequired') })
|
||||
Toast.notify({ type: 'error', message: t('errorMsg.rerankModelRequired', { ns: 'workflow' }) })
|
||||
|
||||
onChange({
|
||||
...datasetConfigs,
|
||||
@ -149,13 +149,13 @@ const ConfigContent: FC<Props> = ({
|
||||
const rerankingModeOptions = [
|
||||
{
|
||||
value: RerankingModeEnum.WeightedScore,
|
||||
label: t('dataset.weightedScore.title'),
|
||||
tips: t('dataset.weightedScore.description'),
|
||||
label: t('weightedScore.title', { ns: 'dataset' }),
|
||||
tips: t('weightedScore.description', { ns: 'dataset' }),
|
||||
},
|
||||
{
|
||||
value: RerankingModeEnum.RerankingModel,
|
||||
label: t('common.modelProvider.rerankModel.key'),
|
||||
tips: t('common.modelProvider.rerankModel.tip'),
|
||||
label: t('modelProvider.rerankModel.key', { ns: 'common' }),
|
||||
tips: t('modelProvider.rerankModel.tip', { ns: 'common' }),
|
||||
},
|
||||
]
|
||||
|
||||
@ -179,7 +179,7 @@ const ConfigContent: FC<Props> = ({
|
||||
|
||||
const handleManuallyToggleRerank = useCallback((enable: boolean) => {
|
||||
if (!currentRerankModel && enable)
|
||||
Toast.notify({ type: 'error', message: t('workflow.errorMsg.rerankModelRequired') })
|
||||
Toast.notify({ type: 'error', message: t('errorMsg.rerankModelRequired', { ns: 'workflow' }) })
|
||||
onChange({
|
||||
...datasetConfigs,
|
||||
reranking_enable: enable,
|
||||
@ -188,15 +188,15 @@ const ConfigContent: FC<Props> = ({
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="system-xl-semibold text-text-primary">{t('dataset.retrievalSettings')}</div>
|
||||
<div className="system-xl-semibold text-text-primary">{t('retrievalSettings', { ns: 'dataset' })}</div>
|
||||
<div className="system-xs-regular text-text-tertiary">
|
||||
{t('dataset.defaultRetrievalTip')}
|
||||
{t('defaultRetrievalTip', { ns: 'dataset' })}
|
||||
</div>
|
||||
{type === RETRIEVE_TYPE.multiWay && (
|
||||
<>
|
||||
<div className="my-2 flex h-6 items-center py-1">
|
||||
<div className="system-xs-semibold-uppercase mr-2 shrink-0 text-text-secondary">
|
||||
{t('dataset.rerankSettings')}
|
||||
{t('rerankSettings', { ns: 'dataset' })}
|
||||
</div>
|
||||
<Divider bgStyle="gradient" className="mx-0 !h-px" />
|
||||
</div>
|
||||
@ -204,21 +204,21 @@ const ConfigContent: FC<Props> = ({
|
||||
selectedDatasetsMode.inconsistentEmbeddingModel
|
||||
&& (
|
||||
<div className="system-xs-medium mt-4 text-text-warning">
|
||||
{t('dataset.inconsistentEmbeddingModelTip')}
|
||||
{t('inconsistentEmbeddingModelTip', { ns: 'dataset' })}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
selectedDatasetsMode.mixtureInternalAndExternal && (
|
||||
<div className="system-xs-medium mt-4 text-text-warning">
|
||||
{t('dataset.mixtureInternalAndExternalTip')}
|
||||
{t('mixtureInternalAndExternalTip', { ns: 'dataset' })}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
{
|
||||
selectedDatasetsMode.allExternal && (
|
||||
<div className="system-xs-medium mt-4 text-text-warning">
|
||||
{t('dataset.allExternalTip')}
|
||||
{t('allExternalTip', { ns: 'dataset' })}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -226,7 +226,7 @@ const ConfigContent: FC<Props> = ({
|
||||
selectedDatasetsMode.mixtureHighQualityAndEconomic
|
||||
&& (
|
||||
<div className="system-xs-medium mt-4 text-text-warning">
|
||||
{t('dataset.mixtureHighQualityAndEconomicTip')}
|
||||
{t('mixtureHighQualityAndEconomicTip', { ns: 'dataset' })}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@ -272,11 +272,11 @@ const ConfigContent: FC<Props> = ({
|
||||
/>
|
||||
)
|
||||
}
|
||||
<div className="system-sm-semibold ml-1 leading-[32px] text-text-secondary">{t('common.modelProvider.rerankModel.key')}</div>
|
||||
<div className="system-sm-semibold ml-1 leading-[32px] text-text-secondary">{t('modelProvider.rerankModel.key', { ns: 'common' })}</div>
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="w-[200px]">
|
||||
{t('common.modelProvider.rerankModel.tip')}
|
||||
{t('modelProvider.rerankModel.tip', { ns: 'common' })}
|
||||
</div>
|
||||
)}
|
||||
popupClassName="ml-1"
|
||||
@ -362,9 +362,9 @@ const ConfigContent: FC<Props> = ({
|
||||
{isInWorkflow && type === RETRIEVE_TYPE.oneWay && (
|
||||
<div className="mt-4">
|
||||
<div className="flex items-center space-x-0.5">
|
||||
<div className="text-[13px] font-medium leading-[32px] text-text-primary">{t('common.modelProvider.systemReasoningModel.key')}</div>
|
||||
<div className="text-[13px] font-medium leading-[32px] text-text-primary">{t('modelProvider.systemReasoningModel.key', { ns: 'common' })}</div>
|
||||
<Tooltip
|
||||
popupContent={t('common.modelProvider.systemReasoningModel.tip')}
|
||||
popupContent={t('modelProvider.systemReasoningModel.tip', { ns: 'common' })}
|
||||
/>
|
||||
</div>
|
||||
<ModelParameterModal
|
||||
|
||||
@ -63,7 +63,7 @@ const ParamsConfig = ({
|
||||
&& tempDataSetConfigs.reranking_mode === RerankingModeEnum.RerankingModel
|
||||
&& !isCurrentRerankModelValid
|
||||
) {
|
||||
errMsg = t('appDebug.datasetConfig.rerankModelRequired')
|
||||
errMsg = t('datasetConfig.rerankModelRequired', { ns: 'appDebug' })
|
||||
}
|
||||
}
|
||||
if (errMsg) {
|
||||
@ -123,7 +123,7 @@ const ParamsConfig = ({
|
||||
disabled={disabled}
|
||||
>
|
||||
<RiEqualizer2Line className="mr-1 h-3.5 w-3.5" />
|
||||
{t('dataset.retrievalSettings')}
|
||||
{t('retrievalSettings', { ns: 'dataset' })}
|
||||
</Button>
|
||||
{
|
||||
rerankSettingModalOpen && (
|
||||
@ -148,9 +148,9 @@ const ParamsConfig = ({
|
||||
setRerankSettingModalOpen(false)
|
||||
}}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button variant="primary" className="shrink-0" onClick={handleSave}>{t('common.operation.save')}</Button>
|
||||
<Button variant="primary" className="shrink-0" onClick={handleSave}>{t('operation.save', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
)
|
||||
|
||||
@ -45,15 +45,15 @@ const WeightedScore = ({
|
||||
/>
|
||||
<div className="mt-3 flex justify-between">
|
||||
<div className="system-xs-semibold-uppercase flex w-[90px] shrink-0 items-center text-util-colors-blue-light-blue-light-500">
|
||||
<div className="mr-1 truncate uppercase" title={t('dataset.weightedScore.semantic') || ''}>
|
||||
{t('dataset.weightedScore.semantic')}
|
||||
<div className="mr-1 truncate uppercase" title={t('weightedScore.semantic', { ns: 'dataset' }) || ''}>
|
||||
{t('weightedScore.semantic', { ns: 'dataset' })}
|
||||
</div>
|
||||
{formatNumber(value.value[0])}
|
||||
</div>
|
||||
<div className="system-xs-semibold-uppercase flex w-[90px] shrink-0 items-center justify-end text-util-colors-teal-teal-500">
|
||||
{formatNumber(value.value[1])}
|
||||
<div className="ml-1 truncate uppercase" title={t('dataset.weightedScore.keyword') || ''}>
|
||||
{t('dataset.weightedScore.keyword')}
|
||||
<div className="ml-1 truncate uppercase" title={t('weightedScore.keyword', { ns: 'dataset' }) || ''}>
|
||||
{t('weightedScore.keyword', { ns: 'dataset' })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,141 @@
|
||||
import type { DataSet } from '@/models/datasets'
|
||||
import { act, fireEvent, render, screen } from '@testing-library/react'
|
||||
import * as React from 'react'
|
||||
|
||||
import { describe, expect, it, vi } from 'vitest'
|
||||
import { IndexingType } from '@/app/components/datasets/create/step-two'
|
||||
import { DatasetPermission } from '@/models/datasets'
|
||||
import { RETRIEVE_METHOD } from '@/types/app'
|
||||
import SelectDataSet from './index'
|
||||
|
||||
vi.mock('@/i18n-config/i18next-config', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
changeLanguage: vi.fn(),
|
||||
addResourceBundle: vi.fn(),
|
||||
use: vi.fn().mockReturnThis(),
|
||||
init: vi.fn(),
|
||||
addResource: vi.fn(),
|
||||
hasResourceBundle: vi.fn().mockReturnValue(true),
|
||||
},
|
||||
}))
|
||||
const mockUseInfiniteScroll = vi.fn()
|
||||
vi.mock('ahooks', async (importOriginal) => {
|
||||
const actual = await importOriginal()
|
||||
return {
|
||||
...(typeof actual === 'object' && actual !== null ? actual : {}),
|
||||
useInfiniteScroll: (...args: any[]) => mockUseInfiniteScroll(...args),
|
||||
}
|
||||
})
|
||||
|
||||
const mockUseInfiniteDatasets = vi.fn()
|
||||
vi.mock('@/service/knowledge/use-dataset', () => ({
|
||||
useInfiniteDatasets: (...args: any[]) => mockUseInfiniteDatasets(...args),
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks/use-knowledge', () => ({
|
||||
useKnowledge: () => ({
|
||||
formatIndexingTechniqueAndMethod: (tech: string, method: string) => `${tech}:${method}`,
|
||||
}),
|
||||
}))
|
||||
|
||||
const baseProps = {
|
||||
isShow: true,
|
||||
onClose: vi.fn(),
|
||||
selectedIds: [] as string[],
|
||||
onSelect: vi.fn(),
|
||||
}
|
||||
|
||||
const makeDataset = (overrides: Partial<DataSet>): DataSet => ({
|
||||
id: 'dataset-id',
|
||||
name: 'Dataset Name',
|
||||
provider: 'internal',
|
||||
icon_info: {
|
||||
icon_type: 'emoji',
|
||||
icon: '💾',
|
||||
icon_background: '#fff',
|
||||
icon_url: '',
|
||||
},
|
||||
embedding_available: true,
|
||||
is_multimodal: false,
|
||||
description: '',
|
||||
permission: DatasetPermission.allTeamMembers,
|
||||
indexing_technique: IndexingType.ECONOMICAL,
|
||||
retrieval_model_dict: {
|
||||
search_method: RETRIEVE_METHOD.fullText,
|
||||
top_k: 5,
|
||||
reranking_enable: false,
|
||||
reranking_model: {
|
||||
reranking_model_name: '',
|
||||
reranking_provider_name: '',
|
||||
},
|
||||
score_threshold_enabled: false,
|
||||
score_threshold: 0,
|
||||
},
|
||||
...overrides,
|
||||
} as DataSet)
|
||||
|
||||
describe('SelectDataSet', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
})
|
||||
|
||||
it('renders dataset entries, allows selection, and fires onSelect', async () => {
|
||||
const datasetOne = makeDataset({
|
||||
id: 'set-1',
|
||||
name: 'Dataset One',
|
||||
is_multimodal: true,
|
||||
indexing_technique: IndexingType.ECONOMICAL,
|
||||
})
|
||||
const datasetTwo = makeDataset({
|
||||
id: 'set-2',
|
||||
name: 'Hidden Dataset',
|
||||
embedding_available: false,
|
||||
provider: 'external',
|
||||
})
|
||||
mockUseInfiniteDatasets.mockReturnValue({
|
||||
data: { pages: [{ data: [datasetOne, datasetTwo] }] },
|
||||
isLoading: false,
|
||||
isFetchingNextPage: false,
|
||||
fetchNextPage: vi.fn(),
|
||||
hasNextPage: false,
|
||||
})
|
||||
|
||||
const onSelect = vi.fn()
|
||||
await act(async () => {
|
||||
render(<SelectDataSet {...baseProps} onSelect={onSelect} selectedIds={[]} />)
|
||||
})
|
||||
|
||||
expect(screen.getByText('Dataset One')).toBeInTheDocument()
|
||||
expect(screen.getByText('Hidden Dataset')).toBeInTheDocument()
|
||||
|
||||
await act(async () => {
|
||||
fireEvent.click(screen.getByText('Dataset One'))
|
||||
})
|
||||
expect(screen.getByText('1 appDebug.feature.dataSet.selected')).toBeInTheDocument()
|
||||
|
||||
const addButton = screen.getByRole('button', { name: 'common.operation.add' })
|
||||
await act(async () => {
|
||||
fireEvent.click(addButton)
|
||||
})
|
||||
expect(onSelect).toHaveBeenCalledWith([datasetOne])
|
||||
})
|
||||
|
||||
it('shows empty state when no datasets are available and disables add', async () => {
|
||||
mockUseInfiniteDatasets.mockReturnValue({
|
||||
data: { pages: [{ data: [] }] },
|
||||
isLoading: false,
|
||||
isFetchingNextPage: false,
|
||||
fetchNextPage: vi.fn(),
|
||||
hasNextPage: false,
|
||||
})
|
||||
|
||||
await act(async () => {
|
||||
render(<SelectDataSet {...baseProps} onSelect={vi.fn()} selectedIds={[]} />)
|
||||
})
|
||||
|
||||
expect(screen.getByText('appDebug.feature.dataSet.noDataSet')).toBeInTheDocument()
|
||||
expect(screen.getByRole('link', { name: 'appDebug.feature.dataSet.toCreate' })).toHaveAttribute('href', '/datasets/create')
|
||||
expect(screen.getByRole('button', { name: 'common.operation.add' })).toBeDisabled()
|
||||
})
|
||||
})
|
||||
@ -116,7 +116,7 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
|
||||
isShow={isShow}
|
||||
onClose={onClose}
|
||||
className="w-[400px]"
|
||||
title={t('appDebug.feature.dataSet.selectTitle')}
|
||||
title={t('feature.dataSet.selectTitle', { ns: 'appDebug' })}
|
||||
>
|
||||
{(isLoading && datasets.length === 0) && (
|
||||
<div className="flex h-[200px]">
|
||||
@ -132,8 +132,8 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
|
||||
borderColor: 'rgba(0, 0, 0, 0.02',
|
||||
}}
|
||||
>
|
||||
<span className="text-text-tertiary">{t('appDebug.feature.dataSet.noDataSet')}</span>
|
||||
<Link href="/datasets/create" className="font-normal text-text-accent">{t('appDebug.feature.dataSet.toCreate')}</Link>
|
||||
<span className="text-text-tertiary">{t('feature.dataSet.noDataSet', { ns: 'appDebug' })}</span>
|
||||
<Link href="/datasets/create" className="font-normal text-text-accent">{t('feature.dataSet.toCreate', { ns: 'appDebug' })}</Link>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -166,7 +166,7 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
|
||||
</div>
|
||||
<div className={cn('max-w-[200px] truncate text-[13px] font-medium text-text-secondary', !item.embedding_available && '!max-w-[120px] opacity-30')}>{item.name}</div>
|
||||
{!item.embedding_available && (
|
||||
<span className="ml-1 shrink-0 rounded-md border border-divider-deep px-1 text-xs font-normal leading-[18px] text-text-tertiary">{t('dataset.unavailable')}</span>
|
||||
<span className="ml-1 shrink-0 rounded-md border border-divider-deep px-1 text-xs font-normal leading-[18px] text-text-tertiary">{t('unavailable', { ns: 'dataset' })}</span>
|
||||
)}
|
||||
</div>
|
||||
{item.is_multimodal && (
|
||||
@ -184,7 +184,7 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
|
||||
}
|
||||
{
|
||||
item.provider === 'external' && (
|
||||
<Badge className="shrink-0" text={t('dataset.externalTag')} />
|
||||
<Badge className="shrink-0" text={t('externalTag', { ns: 'dataset' })} />
|
||||
)
|
||||
}
|
||||
</div>
|
||||
@ -195,11 +195,11 @@ const SelectDataSet: FC<ISelectDataSetProps> = ({
|
||||
{!isLoading && (
|
||||
<div className="mt-8 flex items-center justify-between">
|
||||
<div className="text-sm font-medium text-text-secondary">
|
||||
{selected.length > 0 && `${selected.length} ${t('appDebug.feature.dataSet.selected')}`}
|
||||
{selected.length > 0 && `${selected.length} ${t('feature.dataSet.selected', { ns: 'appDebug' })}`}
|
||||
</div>
|
||||
<div className="flex space-x-2">
|
||||
<Button onClick={onClose}>{t('common.operation.cancel')}</Button>
|
||||
<Button variant="primary" onClick={handleSelect} disabled={hasNoData}>{t('common.operation.add')}</Button>
|
||||
<Button onClick={onClose}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Button variant="primary" onClick={handleSelect} disabled={hasNoData}>{t('operation.add', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -96,7 +96,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
if (loading)
|
||||
return
|
||||
if (!localeCurrentDataset.name?.trim()) {
|
||||
notify({ type: 'error', message: t('datasetSettings.form.nameError') })
|
||||
notify({ type: 'error', message: t('form.nameError', { ns: 'datasetSettings' }) })
|
||||
return
|
||||
}
|
||||
if (
|
||||
@ -106,7 +106,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
indexMethod,
|
||||
})
|
||||
) {
|
||||
notify({ type: 'error', message: t('appDebug.datasetConfig.rerankModelRequired') })
|
||||
notify({ type: 'error', message: t('datasetConfig.rerankModelRequired', { ns: 'appDebug' }) })
|
||||
return
|
||||
}
|
||||
try {
|
||||
@ -146,7 +146,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
})
|
||||
}
|
||||
await updateDatasetSetting(requestParams)
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
notify({ type: 'success', message: t('actionMsg.modifiedSuccessfully', { ns: 'common' }) })
|
||||
onSave({
|
||||
...localeCurrentDataset,
|
||||
indexing_technique: indexMethod,
|
||||
@ -154,7 +154,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
})
|
||||
}
|
||||
catch {
|
||||
notify({ type: 'error', message: t('common.actionMsg.modifiedUnsuccessfully') })
|
||||
notify({ type: 'error', message: t('actionMsg.modifiedUnsuccessfully', { ns: 'common' }) })
|
||||
}
|
||||
finally {
|
||||
setLoading(false)
|
||||
@ -195,7 +195,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
>
|
||||
<div className="flex h-14 shrink-0 items-center justify-between border-b border-divider-regular pl-6 pr-5">
|
||||
<div className="flex flex-col text-base font-semibold text-text-primary">
|
||||
<div className="leading-6">{t('datasetSettings.title')}</div>
|
||||
<div className="leading-6">{t('title', { ns: 'datasetSettings' })}</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<div
|
||||
@ -210,31 +210,31 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
<div className="overflow-y-auto border-b border-divider-regular p-6 pb-[68px] pt-5">
|
||||
<div className={cn(rowClass, 'items-center')}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('datasetSettings.form.name')}</div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.name', { ns: 'datasetSettings' })}</div>
|
||||
</div>
|
||||
<Input
|
||||
value={localeCurrentDataset.name}
|
||||
onChange={e => handleValueChange('name', e.target.value)}
|
||||
className="block h-9"
|
||||
placeholder={t('datasetSettings.form.namePlaceholder') || ''}
|
||||
placeholder={t('form.namePlaceholder', { ns: 'datasetSettings' }) || ''}
|
||||
/>
|
||||
</div>
|
||||
<div className={cn(rowClass)}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('datasetSettings.form.desc')}</div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.desc', { ns: 'datasetSettings' })}</div>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<Textarea
|
||||
value={localeCurrentDataset.description || ''}
|
||||
onChange={e => handleValueChange('description', e.target.value)}
|
||||
className="resize-none"
|
||||
placeholder={t('datasetSettings.form.descPlaceholder') || ''}
|
||||
placeholder={t('form.descPlaceholder', { ns: 'datasetSettings' }) || ''}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={rowClass}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('datasetSettings.form.permissions')}</div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.permissions', { ns: 'datasetSettings' })}</div>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<PermissionSelector
|
||||
@ -250,7 +250,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
{currentDataset && currentDataset.indexing_technique && (
|
||||
<div className={cn(rowClass)}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('datasetSettings.form.indexMethod')}</div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.indexMethod', { ns: 'datasetSettings' })}</div>
|
||||
</div>
|
||||
<div className="grow">
|
||||
<IndexMethod
|
||||
@ -267,7 +267,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
{indexMethod === IndexingType.QUALIFIED && (
|
||||
<div className={cn(rowClass)}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('datasetSettings.form.embeddingModel')}</div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.embeddingModel', { ns: 'datasetSettings' })}</div>
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<div className="h-8 w-full rounded-lg bg-components-input-bg-normal opacity-60">
|
||||
@ -281,8 +281,8 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-2 w-full text-xs leading-6 text-text-tertiary">
|
||||
{t('datasetSettings.form.embeddingModelTip')}
|
||||
<span className="cursor-pointer text-text-accent" onClick={() => setShowAccountSettingModal({ payload: ACCOUNT_SETTING_TAB.PROVIDER })}>{t('datasetSettings.form.embeddingModelTipLink')}</span>
|
||||
{t('form.embeddingModelTip', { ns: 'datasetSettings' })}
|
||||
<span className="cursor-pointer text-text-accent" onClick={() => setShowAccountSettingModal({ payload: ACCOUNT_SETTING_TAB.PROVIDER })}>{t('form.embeddingModelTipLink', { ns: 'datasetSettings' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -319,7 +319,7 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
</div>
|
||||
<RetrievalChangeTip
|
||||
visible={isRetrievalChanged && !isHideChangedTip}
|
||||
message={t('appDebug.datasetConfig.retrieveChangeTip')}
|
||||
message={t('datasetConfig.retrieveChangeTip', { ns: 'appDebug' })}
|
||||
onDismiss={() => setIsHideChangedTip(true)}
|
||||
/>
|
||||
|
||||
@ -330,14 +330,14 @@ const SettingsModal: FC<SettingsModalProps> = ({
|
||||
onClick={onCancel}
|
||||
className="mr-2"
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
disabled={loading}
|
||||
onClick={handleSave}
|
||||
>
|
||||
{t('common.operation.save')}
|
||||
{t('operation.save', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -168,7 +168,10 @@ describe('RetrievalChangeTip', () => {
|
||||
})
|
||||
|
||||
describe('RetrievalSection', () => {
|
||||
const t = (key: string) => key
|
||||
const t = (key: string, options?: { ns?: string }) => {
|
||||
const prefix = options?.ns ? `${options.ns}.` : ''
|
||||
return `${prefix}${key}`
|
||||
}
|
||||
const rowClass = 'row'
|
||||
const labelClass = 'label'
|
||||
|
||||
|
||||
@ -39,7 +39,7 @@ const ExternalRetrievalSection: FC<ExternalRetrievalSectionProps> = ({
|
||||
<div className={rowClass}><Divider /></div>
|
||||
<div className={rowClass}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('datasetSettings.form.retrievalSetting.title')}</div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.retrievalSetting.title', { ns: 'datasetSettings' })}</div>
|
||||
</div>
|
||||
<RetrievalSettings
|
||||
topK={topK}
|
||||
@ -52,7 +52,7 @@ const ExternalRetrievalSection: FC<ExternalRetrievalSectionProps> = ({
|
||||
<div className={rowClass}><Divider /></div>
|
||||
<div className={rowClass}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('datasetSettings.form.externalKnowledgeAPI')}</div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.externalKnowledgeAPI', { ns: 'datasetSettings' })}</div>
|
||||
</div>
|
||||
<div className="w-full max-w-[480px]">
|
||||
<div className="flex h-full items-center gap-1 rounded-lg bg-components-input-bg-normal px-3 py-2">
|
||||
@ -67,7 +67,7 @@ const ExternalRetrievalSection: FC<ExternalRetrievalSectionProps> = ({
|
||||
</div>
|
||||
<div className={rowClass}>
|
||||
<div className={labelClass}>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('datasetSettings.form.externalKnowledgeID')}</div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.externalKnowledgeID', { ns: 'datasetSettings' })}</div>
|
||||
</div>
|
||||
<div className="w-full max-w-[480px]">
|
||||
<div className="flex h-full items-center gap-1 rounded-lg bg-components-input-bg-normal px-3 py-2">
|
||||
@ -100,10 +100,10 @@ const InternalRetrievalSection: FC<InternalRetrievalSectionProps> = ({
|
||||
<div className={rowClass}>
|
||||
<div className={cn(labelClass, 'w-auto min-w-[168px]')}>
|
||||
<div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('datasetSettings.form.retrievalSetting.title')}</div>
|
||||
<div className="system-sm-semibold text-text-secondary">{t('form.retrievalSetting.title', { ns: 'datasetSettings' })}</div>
|
||||
<div className="text-xs font-normal leading-[18px] text-text-tertiary">
|
||||
<a target="_blank" rel="noopener noreferrer" href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#setting-the-retrieval-setting')} className="text-text-accent">{t('datasetSettings.form.retrievalSetting.learnMore')}</a>
|
||||
{t('datasetSettings.form.retrievalSetting.description')}
|
||||
<a target="_blank" rel="noopener noreferrer" href={docLink('/guides/knowledge-base/create-knowledge-and-upload-documents/setting-indexing-methods#setting-the-retrieval-setting')} className="text-text-accent">{t('form.retrievalSetting.learnMore', { ns: 'datasetSettings' })}</a>
|
||||
{t('form.retrievalSetting.description', { ns: 'datasetSettings' })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -78,7 +78,7 @@ const ChatUserInput = ({
|
||||
{type !== 'checkbox' && (
|
||||
<div className="system-sm-semibold mb-1 flex h-6 items-center gap-1 text-text-secondary">
|
||||
<div className="truncate">{name || key}</div>
|
||||
{!required && <span className="system-xs-regular text-text-tertiary">{t('workflow.panel.optional')}</span>}
|
||||
{!required && <span className="system-xs-regular text-text-tertiary">{t('panel.optional', { ns: 'workflow' })}</span>}
|
||||
</div>
|
||||
)}
|
||||
<div className="grow">
|
||||
|
||||
@ -84,7 +84,7 @@ const DebugItem: FC<DebugItemProps> = ({
|
||||
? [
|
||||
{
|
||||
value: 'duplicate',
|
||||
text: t('appDebug.duplicateModel'),
|
||||
text: t('duplicateModel', { ns: 'appDebug' }),
|
||||
},
|
||||
]
|
||||
: []
|
||||
@ -94,7 +94,7 @@ const DebugItem: FC<DebugItemProps> = ({
|
||||
? [
|
||||
{
|
||||
value: 'debug-as-single-model',
|
||||
text: t('appDebug.debugAsSingleModel'),
|
||||
text: t('debugAsSingleModel', { ns: 'appDebug' }),
|
||||
},
|
||||
]
|
||||
: []
|
||||
@ -105,7 +105,7 @@ const DebugItem: FC<DebugItemProps> = ({
|
||||
? [
|
||||
{
|
||||
value: 'remove',
|
||||
text: t('common.operation.remove') as string,
|
||||
text: t('operation.remove', { ns: 'common' }) as string,
|
||||
},
|
||||
]
|
||||
: undefined
|
||||
|
||||
@ -104,7 +104,7 @@ const ModelParameterTrigger: FC<ModelParameterTriggerProps> = ({
|
||||
{
|
||||
!currentModel && (
|
||||
<div className="mr-0.5 truncate text-[13px] font-medium text-text-accent">
|
||||
{t('common.modelProvider.selectModel')}
|
||||
{t('modelProvider.selectModel', { ns: 'common' })}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -147,11 +147,11 @@ const Debug: FC<IDebug> = ({
|
||||
if (isAdvancedMode && mode !== AppModeEnum.COMPLETION) {
|
||||
if (modelModeType === ModelModeType.completion) {
|
||||
if (!hasSetBlockStatus.history) {
|
||||
notify({ type: 'error', message: t('appDebug.otherError.historyNoBeEmpty') })
|
||||
notify({ type: 'error', message: t('otherError.historyNoBeEmpty', { ns: 'appDebug' }) })
|
||||
return false
|
||||
}
|
||||
if (!hasSetBlockStatus.query) {
|
||||
notify({ type: 'error', message: t('appDebug.otherError.queryNoBeEmpty') })
|
||||
notify({ type: 'error', message: t('otherError.queryNoBeEmpty', { ns: 'appDebug' }) })
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -172,12 +172,12 @@ const Debug: FC<IDebug> = ({
|
||||
})
|
||||
|
||||
if (hasEmptyInput) {
|
||||
logError(t('appDebug.errorMessage.valueOfVarRequired', { key: hasEmptyInput }))
|
||||
logError(t('errorMessage.valueOfVarRequired', { ns: 'appDebug', key: hasEmptyInput }))
|
||||
return false
|
||||
}
|
||||
|
||||
if (completionFiles.find(item => item.transfer_method === TransferMethod.local_file && !item.upload_file_id)) {
|
||||
notify({ type: 'info', message: t('appDebug.errorMessage.waitForFileUpload') })
|
||||
notify({ type: 'info', message: t('errorMessage.waitForFileUpload', { ns: 'appDebug' }) })
|
||||
return false
|
||||
}
|
||||
return !hasEmptyInput
|
||||
@ -202,7 +202,7 @@ const Debug: FC<IDebug> = ({
|
||||
|
||||
const sendTextCompletion = async () => {
|
||||
if (isResponding) {
|
||||
notify({ type: 'info', message: t('appDebug.errorMessage.waitForResponse') })
|
||||
notify({ type: 'info', message: t('errorMessage.waitForResponse', { ns: 'appDebug' }) })
|
||||
return false
|
||||
}
|
||||
|
||||
@ -391,7 +391,7 @@ const Debug: FC<IDebug> = ({
|
||||
<>
|
||||
<div className="shrink-0">
|
||||
<div className="flex items-center justify-between px-4 pb-2 pt-3">
|
||||
<div className="system-xl-semibold text-text-primary">{t('appDebug.inputs.title')}</div>
|
||||
<div className="system-xl-semibold text-text-primary">{t('inputs.title', { ns: 'appDebug' })}</div>
|
||||
<div className="flex items-center">
|
||||
{
|
||||
debugWithMultipleModel
|
||||
@ -403,7 +403,7 @@ const Debug: FC<IDebug> = ({
|
||||
disabled={multipleModelConfigs.length >= 4}
|
||||
>
|
||||
<RiAddLine className="mr-1 h-3.5 w-3.5" />
|
||||
{t('common.modelProvider.addModel')}
|
||||
{t('modelProvider.addModel', { ns: 'common' })}
|
||||
(
|
||||
{multipleModelConfigs.length}
|
||||
/4)
|
||||
@ -416,7 +416,7 @@ const Debug: FC<IDebug> = ({
|
||||
{mode !== AppModeEnum.COMPLETION && (
|
||||
<>
|
||||
<TooltipPlus
|
||||
popupContent={t('common.operation.refresh')}
|
||||
popupContent={t('operation.refresh', { ns: 'common' })}
|
||||
>
|
||||
<ActionButton onClick={clearConversation}>
|
||||
<RefreshCcw01 className="h-4 w-4" />
|
||||
@ -425,7 +425,7 @@ const Debug: FC<IDebug> = ({
|
||||
{varList.length > 0 && (
|
||||
<div className="relative ml-1 mr-2">
|
||||
<TooltipPlus
|
||||
popupContent={t('workflow.panel.userInputField')}
|
||||
popupContent={t('panel.userInputField', { ns: 'workflow' })}
|
||||
>
|
||||
<ActionButton state={expanded ? ActionButtonState.Active : undefined} onClick={() => setExpanded(!expanded)}>
|
||||
<RiEqualizer2Line className="h-4 w-4" />
|
||||
@ -506,7 +506,7 @@ const Debug: FC<IDebug> = ({
|
||||
<>
|
||||
{(completionRes || isResponding) && (
|
||||
<>
|
||||
<div className="mx-4 mt-3"><GroupName name={t('appDebug.result')} /></div>
|
||||
<div className="mx-4 mt-3"><GroupName name={t('result', { ns: 'appDebug' })} /></div>
|
||||
<div className="mx-3 mb-8">
|
||||
<TextGeneration
|
||||
className="mt-2"
|
||||
@ -526,7 +526,7 @@ const Debug: FC<IDebug> = ({
|
||||
{!completionRes && !isResponding && (
|
||||
<div className="flex grow flex-col items-center justify-center gap-2">
|
||||
<RiSparklingFill className="h-12 w-12 text-text-empty-state-icon" />
|
||||
<div className="system-sm-regular text-text-quaternary">{t('appDebug.noResult')}</div>
|
||||
<div className="system-sm-regular text-text-quaternary">{t('noResult', { ns: 'appDebug' })}</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@ -490,11 +490,11 @@ const Configuration: FC = () => {
|
||||
isAdvancedMode,
|
||||
)
|
||||
if (Object.keys(removedDetails).length)
|
||||
Toast.notify({ type: 'warning', message: `${t('common.modelProvider.parametersInvalidRemoved')}: ${Object.entries(removedDetails).map(([k, reason]) => `${k} (${reason})`).join(', ')}` })
|
||||
Toast.notify({ type: 'warning', message: `${t('modelProvider.parametersInvalidRemoved', { ns: 'common' })}: ${Object.entries(removedDetails).map(([k, reason]) => `${k} (${reason})`).join(', ')}` })
|
||||
setCompletionParams(filtered)
|
||||
}
|
||||
catch {
|
||||
Toast.notify({ type: 'error', message: t('common.error') })
|
||||
Toast.notify({ type: 'error', message: t('error', { ns: 'common' }) })
|
||||
setCompletionParams({})
|
||||
}
|
||||
}
|
||||
@ -679,7 +679,7 @@ const Configuration: FC = () => {
|
||||
const toolInCollectionList = collectionList.find(c => tool.provider_id === c.id)
|
||||
return {
|
||||
...tool,
|
||||
isDeleted: res.deleted_tools?.some((deletedTool: any) => deletedTool.id === tool.id && deletedTool.tool_name === tool.tool_name) ?? false,
|
||||
isDeleted: res.deleted_tools?.some((deletedTool: any) => deletedTool.provider_id === tool.provider_id && deletedTool.tool_name === tool.tool_name) ?? false,
|
||||
notAuthor: toolInCollectionList?.is_team_authorization === false,
|
||||
...(tool.provider_type === 'builtin'
|
||||
? {
|
||||
@ -765,23 +765,23 @@ const Configuration: FC = () => {
|
||||
const promptVariables = modelConfig.configs.prompt_variables
|
||||
|
||||
if (promptEmpty) {
|
||||
notify({ type: 'error', message: t('appDebug.otherError.promptNoBeEmpty') })
|
||||
notify({ type: 'error', message: t('otherError.promptNoBeEmpty', { ns: 'appDebug' }) })
|
||||
return
|
||||
}
|
||||
if (isAdvancedMode && mode !== AppModeEnum.COMPLETION) {
|
||||
if (modelModeType === ModelModeType.completion) {
|
||||
if (!hasSetBlockStatus.history) {
|
||||
notify({ type: 'error', message: t('appDebug.otherError.historyNoBeEmpty') })
|
||||
notify({ type: 'error', message: t('otherError.historyNoBeEmpty', { ns: 'appDebug' }) })
|
||||
return
|
||||
}
|
||||
if (!hasSetBlockStatus.query) {
|
||||
notify({ type: 'error', message: t('appDebug.otherError.queryNoBeEmpty') })
|
||||
notify({ type: 'error', message: t('otherError.queryNoBeEmpty', { ns: 'appDebug' }) })
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
if (contextVarEmpty) {
|
||||
notify({ type: 'error', message: t('appDebug.feature.dataSet.queryVariable.contextVarNotEmpty') })
|
||||
notify({ type: 'error', message: t('feature.dataSet.queryVariable.contextVarNotEmpty', { ns: 'appDebug' }) })
|
||||
return
|
||||
}
|
||||
const postDatasets = dataSets.map(({ id }) => ({
|
||||
@ -847,7 +847,7 @@ const Configuration: FC = () => {
|
||||
modelConfig: newModelConfig,
|
||||
completionParams,
|
||||
})
|
||||
notify({ type: 'success', message: t('common.api.success') })
|
||||
notify({ type: 'success', message: t('api.success', { ns: 'common' }) })
|
||||
|
||||
setCanReturnToSimpleMode(false)
|
||||
return true
|
||||
@ -964,10 +964,10 @@ const Configuration: FC = () => {
|
||||
<div className="bg-default-subtle absolute left-0 top-0 h-14 w-full">
|
||||
<div className="flex h-14 items-center justify-between px-6">
|
||||
<div className="flex items-center">
|
||||
<div className="system-xl-semibold text-text-primary">{t('appDebug.orchestrate')}</div>
|
||||
<div className="system-xl-semibold text-text-primary">{t('orchestrate', { ns: 'appDebug' })}</div>
|
||||
<div className="flex h-[14px] items-center space-x-1 text-xs">
|
||||
{isAdvancedMode && (
|
||||
<div className="system-xs-medium-uppercase ml-1 flex h-5 items-center rounded-md border border-components-button-secondary-border px-1.5 uppercase text-text-tertiary">{t('appDebug.promptMode.advanced')}</div>
|
||||
<div className="system-xs-medium-uppercase ml-1 flex h-5 items-center rounded-md border border-components-button-secondary-border px-1.5 uppercase text-text-tertiary">{t('promptMode.advanced', { ns: 'appDebug' })}</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
@ -1007,7 +1007,7 @@ const Configuration: FC = () => {
|
||||
)}
|
||||
{isMobile && (
|
||||
<Button className="mr-2 !h-8 !text-[13px] font-medium" onClick={showDebugPanel}>
|
||||
<span className="mr-1">{t('appDebug.operation.debugConfig')}</span>
|
||||
<span className="mr-1">{t('operation.debugConfig', { ns: 'appDebug' })}</span>
|
||||
<CodeBracketIcon className="h-4 w-4 text-text-tertiary" />
|
||||
</Button>
|
||||
)}
|
||||
@ -1049,8 +1049,8 @@ const Configuration: FC = () => {
|
||||
</div>
|
||||
{showUseGPT4Confirm && (
|
||||
<Confirm
|
||||
title={t('appDebug.trailUseGPT4Info.title')}
|
||||
content={t('appDebug.trailUseGPT4Info.description')}
|
||||
title={t('trailUseGPT4Info.title', { ns: 'appDebug' })}
|
||||
content={t('trailUseGPT4Info.description', { ns: 'appDebug' })}
|
||||
isShow={showUseGPT4Confirm}
|
||||
onConfirm={() => {
|
||||
setShowAccountSettingModal({ payload: ACCOUNT_SETTING_TAB.PROVIDER })
|
||||
|
||||
@ -0,0 +1,125 @@
|
||||
import type { IPromptValuePanelProps } from './index'
|
||||
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
|
||||
import * as React from 'react'
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { useStore } from '@/app/components/app/store'
|
||||
import ConfigContext from '@/context/debug-configuration'
|
||||
import { AppModeEnum, ModelModeType, Resolution } from '@/types/app'
|
||||
import PromptValuePanel from './index'
|
||||
|
||||
vi.mock('@/app/components/app/store', () => ({
|
||||
useStore: vi.fn(),
|
||||
}))
|
||||
vi.mock('@/app/components/base/features/new-feature-panel/feature-bar', () => ({
|
||||
__esModule: true,
|
||||
default: ({ onFeatureBarClick }: { onFeatureBarClick: () => void }) => (
|
||||
<button type="button" onClick={onFeatureBarClick}>
|
||||
feature bar
|
||||
</button>
|
||||
),
|
||||
}))
|
||||
|
||||
const mockSetShowAppConfigureFeaturesModal = vi.fn()
|
||||
const mockUseStore = vi.mocked(useStore)
|
||||
const mockSetInputs = vi.fn()
|
||||
const mockOnSend = vi.fn()
|
||||
|
||||
const promptVariables = [
|
||||
{ key: 'textVar', name: 'Text Var', type: 'string', required: true },
|
||||
{ key: 'boolVar', name: 'Boolean Var', type: 'checkbox' },
|
||||
] as const
|
||||
|
||||
const baseContextValue: any = {
|
||||
modelModeType: ModelModeType.completion,
|
||||
modelConfig: {
|
||||
configs: {
|
||||
prompt_template: 'prompt template',
|
||||
prompt_variables: promptVariables,
|
||||
},
|
||||
},
|
||||
setInputs: mockSetInputs,
|
||||
mode: AppModeEnum.COMPLETION,
|
||||
isAdvancedMode: false,
|
||||
completionPromptConfig: {
|
||||
prompt: { text: 'completion' },
|
||||
conversation_histories_role: { user_prefix: 'user', assistant_prefix: 'assistant' },
|
||||
},
|
||||
chatPromptConfig: { prompt: [] },
|
||||
} as any
|
||||
|
||||
const defaultProps: IPromptValuePanelProps = {
|
||||
appType: AppModeEnum.COMPLETION,
|
||||
onSend: mockOnSend,
|
||||
inputs: { textVar: 'initial', boolVar: false },
|
||||
visionConfig: { enabled: false, number_limits: 0, detail: Resolution.low, transfer_methods: [] },
|
||||
onVisionFilesChange: vi.fn(),
|
||||
}
|
||||
|
||||
const renderPanel = (options: {
|
||||
context?: Partial<typeof baseContextValue>
|
||||
props?: Partial<IPromptValuePanelProps>
|
||||
} = {}) => {
|
||||
const contextValue = { ...baseContextValue, ...options.context }
|
||||
const props = { ...defaultProps, ...options.props }
|
||||
return render(
|
||||
<ConfigContext.Provider value={contextValue}>
|
||||
<PromptValuePanel {...props} />
|
||||
</ConfigContext.Provider>,
|
||||
)
|
||||
}
|
||||
|
||||
describe('PromptValuePanel', () => {
|
||||
beforeEach(() => {
|
||||
mockUseStore.mockImplementation(selector => selector({
|
||||
setShowAppConfigureFeaturesModal: mockSetShowAppConfigureFeaturesModal,
|
||||
appSidebarExpand: '',
|
||||
currentLogModalActiveTab: 'prompt',
|
||||
showPromptLogModal: false,
|
||||
showAgentLogModal: false,
|
||||
setShowPromptLogModal: vi.fn(),
|
||||
setShowAgentLogModal: vi.fn(),
|
||||
showMessageLogModal: false,
|
||||
showAppConfigureFeaturesModal: false,
|
||||
} as any))
|
||||
mockSetInputs.mockClear()
|
||||
mockOnSend.mockClear()
|
||||
mockSetShowAppConfigureFeaturesModal.mockClear()
|
||||
})
|
||||
|
||||
it('updates inputs, clears values, and triggers run when ready', async () => {
|
||||
renderPanel()
|
||||
|
||||
const textInput = screen.getByPlaceholderText('Text Var')
|
||||
fireEvent.change(textInput, { target: { value: 'updated' } })
|
||||
expect(mockSetInputs).toHaveBeenCalledWith(expect.objectContaining({ textVar: 'updated' }))
|
||||
|
||||
const clearButton = screen.getByRole('button', { name: 'common.operation.clear' })
|
||||
fireEvent.click(clearButton)
|
||||
|
||||
expect(mockSetInputs).toHaveBeenLastCalledWith({
|
||||
textVar: '',
|
||||
boolVar: '',
|
||||
})
|
||||
|
||||
const runButton = screen.getByRole('button', { name: 'appDebug.inputs.run' })
|
||||
expect(runButton).not.toBeDisabled()
|
||||
fireEvent.click(runButton)
|
||||
await waitFor(() => expect(mockOnSend).toHaveBeenCalledTimes(1))
|
||||
})
|
||||
|
||||
it('disables run when mode is not completion', () => {
|
||||
renderPanel({
|
||||
context: {
|
||||
mode: AppModeEnum.CHAT,
|
||||
},
|
||||
props: {
|
||||
appType: AppModeEnum.CHAT,
|
||||
},
|
||||
})
|
||||
|
||||
const runButton = screen.getByRole('button', { name: 'appDebug.inputs.run' })
|
||||
expect(runButton).toBeDisabled()
|
||||
fireEvent.click(runButton)
|
||||
expect(mockOnSend).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
@ -113,12 +113,12 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
|
||||
<div className="relative z-[1] mx-3 rounded-xl border-[0.5px] border-components-panel-border-subtle bg-components-panel-on-panel-item-bg shadow-md">
|
||||
<div className={cn('px-4 pt-3', userInputFieldCollapse ? 'pb-3' : 'pb-1')}>
|
||||
<div className="flex cursor-pointer items-center gap-0.5 py-0.5" onClick={() => setUserInputFieldCollapse(!userInputFieldCollapse)}>
|
||||
<div className="system-md-semibold-uppercase text-text-secondary">{t('appDebug.inputs.userInputField')}</div>
|
||||
<div className="system-md-semibold-uppercase text-text-secondary">{t('inputs.userInputField', { ns: 'appDebug' })}</div>
|
||||
{userInputFieldCollapse && <RiArrowRightSLine className="h-4 w-4 text-text-secondary" />}
|
||||
{!userInputFieldCollapse && <RiArrowDownSLine className="h-4 w-4 text-text-secondary" />}
|
||||
</div>
|
||||
{!userInputFieldCollapse && (
|
||||
<div className="system-xs-regular mt-1 text-text-tertiary">{t('appDebug.inputs.completionVarTip')}</div>
|
||||
<div className="system-xs-regular mt-1 text-text-tertiary">{t('inputs.completionVarTip', { ns: 'appDebug' })}</div>
|
||||
)}
|
||||
</div>
|
||||
{!userInputFieldCollapse && promptVariables.length > 0 && (
|
||||
@ -132,7 +132,7 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
|
||||
{type !== 'checkbox' && (
|
||||
<div className="system-sm-semibold mb-1 flex h-6 items-center gap-1 text-text-secondary">
|
||||
<div className="truncate">{name || key}</div>
|
||||
{!required && <span className="system-xs-regular text-text-tertiary">{t('workflow.panel.optional')}</span>}
|
||||
{!required && <span className="system-xs-regular text-text-tertiary">{t('panel.optional', { ns: 'workflow' })}</span>}
|
||||
</div>
|
||||
)}
|
||||
<div className="grow">
|
||||
@ -187,7 +187,7 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
|
||||
))}
|
||||
{visionConfig?.enabled && (
|
||||
<div className="mt-3 justify-between xl:flex">
|
||||
<div className="mr-1 w-[120px] shrink-0 py-2 text-sm text-text-primary">{t('common.imageUploader.imageUpload')}</div>
|
||||
<div className="mr-1 w-[120px] shrink-0 py-2 text-sm text-text-primary">{t('imageUploader.imageUpload', { ns: 'common' })}</div>
|
||||
<div className="grow">
|
||||
<TextGenerationImageUploader
|
||||
settings={visionConfig}
|
||||
@ -205,9 +205,9 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
|
||||
)}
|
||||
{!userInputFieldCollapse && (
|
||||
<div className="flex justify-between border-t border-divider-subtle p-4 pt-3">
|
||||
<Button className="w-[72px]" onClick={onClear}>{t('common.operation.clear')}</Button>
|
||||
<Button className="w-[72px]" onClick={onClear}>{t('operation.clear', { ns: 'common' })}</Button>
|
||||
{canNotRun && (
|
||||
<Tooltip popupContent={t('appDebug.otherError.promptNoBeEmpty')}>
|
||||
<Tooltip popupContent={t('otherError.promptNoBeEmpty', { ns: 'appDebug' })}>
|
||||
<Button
|
||||
variant="primary"
|
||||
disabled={canNotRun}
|
||||
@ -215,7 +215,7 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
|
||||
className="w-[96px]"
|
||||
>
|
||||
<RiPlayLargeFill className="mr-0.5 h-4 w-4 shrink-0" aria-hidden="true" />
|
||||
{t('appDebug.inputs.run')}
|
||||
{t('inputs.run', { ns: 'appDebug' })}
|
||||
</Button>
|
||||
</Tooltip>
|
||||
)}
|
||||
@ -227,7 +227,7 @@ const PromptValuePanel: FC<IPromptValuePanelProps> = ({
|
||||
className="w-[96px]"
|
||||
>
|
||||
<RiPlayLargeFill className="mr-0.5 h-4 w-4 shrink-0" aria-hidden="true" />
|
||||
{t('appDebug.inputs.run')}
|
||||
{t('inputs.run', { ns: 'appDebug' })}
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -0,0 +1,29 @@
|
||||
import type { PromptVariable } from '@/models/debug'
|
||||
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { replaceStringWithValues } from './utils'
|
||||
|
||||
const promptVariables: PromptVariable[] = [
|
||||
{ key: 'user', name: 'User', type: 'string' },
|
||||
{ key: 'topic', name: 'Topic', type: 'string' },
|
||||
]
|
||||
|
||||
describe('replaceStringWithValues', () => {
|
||||
it('should replace placeholders when inputs have values', () => {
|
||||
const template = 'Hello {{user}} talking about {{topic}}'
|
||||
const result = replaceStringWithValues(template, promptVariables, { user: 'Alice', topic: 'cats' })
|
||||
expect(result).toBe('Hello Alice talking about cats')
|
||||
})
|
||||
|
||||
it('should use prompt variable name when value is missing', () => {
|
||||
const template = 'Hi {{user}} from {{topic}}'
|
||||
const result = replaceStringWithValues(template, promptVariables, {})
|
||||
expect(result).toBe('Hi {{User}} from {{Topic}}')
|
||||
})
|
||||
|
||||
it('should leave placeholder untouched when no variable is defined', () => {
|
||||
const template = 'Unknown {{missing}} placeholder'
|
||||
const result = replaceStringWithValues(template, promptVariables, {})
|
||||
expect(result).toBe('Unknown {{missing}} placeholder')
|
||||
})
|
||||
})
|
||||
@ -49,7 +49,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
|
||||
const providers: Provider[] = [
|
||||
{
|
||||
key: 'api',
|
||||
name: t('common.apiBasedExtension.selector.title'),
|
||||
name: t('apiBasedExtension.selector.title', { ns: 'common' }),
|
||||
},
|
||||
...(
|
||||
codeBasedExtensionList
|
||||
@ -134,27 +134,27 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
|
||||
|
||||
const handleSave = () => {
|
||||
if (!localeData.type) {
|
||||
notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: t('appDebug.feature.tools.modal.toolType.title') }) })
|
||||
notify({ type: 'error', message: t('errorMessage.valueOfVarRequired', { ns: 'appDebug', key: t('feature.tools.modal.toolType.title', { ns: 'appDebug' }) }) })
|
||||
return
|
||||
}
|
||||
|
||||
if (!localeData.label) {
|
||||
notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: t('appDebug.feature.tools.modal.name.title') }) })
|
||||
notify({ type: 'error', message: t('errorMessage.valueOfVarRequired', { ns: 'appDebug', key: t('feature.tools.modal.name.title', { ns: 'appDebug' }) }) })
|
||||
return
|
||||
}
|
||||
|
||||
if (!localeData.variable) {
|
||||
notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: t('appDebug.feature.tools.modal.variableName.title') }) })
|
||||
notify({ type: 'error', message: t('errorMessage.valueOfVarRequired', { ns: 'appDebug', key: t('feature.tools.modal.variableName.title', { ns: 'appDebug' }) }) })
|
||||
return
|
||||
}
|
||||
|
||||
if (localeData.variable && !/^[a-z_]\w{0,29}$/i.test(localeData.variable)) {
|
||||
notify({ type: 'error', message: t('appDebug.varKeyError.notValid', { key: t('appDebug.feature.tools.modal.variableName.title') }) })
|
||||
notify({ type: 'error', message: t('varKeyError.notValid', { ns: 'appDebug', key: t('feature.tools.modal.variableName.title', { ns: 'appDebug' }) }) })
|
||||
return
|
||||
}
|
||||
|
||||
if (localeData.type === 'api' && !localeData.config?.api_based_extension_id) {
|
||||
notify({ type: 'error', message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale !== LanguagesSupported[1] ? 'API Extension' : 'API 扩展' }) })
|
||||
notify({ type: 'error', message: t('errorMessage.valueOfVarRequired', { ns: 'appDebug', key: locale !== LanguagesSupported[1] ? 'API Extension' : 'API 扩展' }) })
|
||||
return
|
||||
}
|
||||
|
||||
@ -163,7 +163,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
|
||||
if (!localeData.config?.[currentProvider.form_schema[i].variable] && currentProvider.form_schema[i].required) {
|
||||
notify({
|
||||
type: 'error',
|
||||
message: t('appDebug.errorMessage.valueOfVarRequired', { key: locale !== LanguagesSupported[1] ? currentProvider.form_schema[i].label['en-US'] : currentProvider.form_schema[i].label['zh-Hans'] }),
|
||||
message: t('errorMessage.valueOfVarRequired', { ns: 'appDebug', key: locale !== LanguagesSupported[1] ? currentProvider.form_schema[i].label['en-US'] : currentProvider.form_schema[i].label['zh-Hans'] }),
|
||||
})
|
||||
return
|
||||
}
|
||||
@ -178,7 +178,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
|
||||
onSave(formatData(formattedData))
|
||||
}
|
||||
|
||||
const action = data.type ? t('common.operation.edit') : t('common.operation.add')
|
||||
const action = data.type ? t('operation.edit', { ns: 'common' }) : t('operation.add', { ns: 'common' })
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@ -187,11 +187,11 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
|
||||
className="!w-[640px] !max-w-none !p-8 !pb-6"
|
||||
>
|
||||
<div className="mb-2 text-xl font-semibold text-text-primary">
|
||||
{`${action} ${t('appDebug.variableConfig.apiBasedVar')}`}
|
||||
{`${action} ${t('variableConfig.apiBasedVar', { ns: 'appDebug' })}`}
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<div className="text-sm font-medium leading-9 text-text-primary">
|
||||
{t('common.apiBasedExtension.type')}
|
||||
{t('apiBasedExtension.type', { ns: 'common' })}
|
||||
</div>
|
||||
<SimpleSelect
|
||||
defaultValue={localeData.type}
|
||||
@ -206,14 +206,14 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<div className="text-sm font-medium leading-9 text-text-primary">
|
||||
{t('appDebug.feature.tools.modal.name.title')}
|
||||
{t('feature.tools.modal.name.title', { ns: 'appDebug' })}
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<input
|
||||
value={localeData.label || ''}
|
||||
onChange={e => handleValueChange({ label: e.target.value })}
|
||||
className="mr-2 block h-9 grow appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-components-input-text-filled outline-none"
|
||||
placeholder={t('appDebug.feature.tools.modal.name.placeholder') || ''}
|
||||
placeholder={t('feature.tools.modal.name.placeholder', { ns: 'appDebug' }) || ''}
|
||||
/>
|
||||
<AppIcon
|
||||
size="large"
|
||||
@ -226,20 +226,20 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
|
||||
</div>
|
||||
<div className="py-2">
|
||||
<div className="text-sm font-medium leading-9 text-text-primary">
|
||||
{t('appDebug.feature.tools.modal.variableName.title')}
|
||||
{t('feature.tools.modal.variableName.title', { ns: 'appDebug' })}
|
||||
</div>
|
||||
<input
|
||||
value={localeData.variable || ''}
|
||||
onChange={e => handleValueChange({ variable: e.target.value })}
|
||||
className="block h-9 w-full appearance-none rounded-lg bg-components-input-bg-normal px-3 text-sm text-components-input-text-filled outline-none"
|
||||
placeholder={t('appDebug.feature.tools.modal.variableName.placeholder') || ''}
|
||||
placeholder={t('feature.tools.modal.variableName.placeholder', { ns: 'appDebug' }) || ''}
|
||||
/>
|
||||
</div>
|
||||
{
|
||||
localeData.type === 'api' && (
|
||||
<div className="py-2">
|
||||
<div className="flex h-9 items-center justify-between text-sm font-medium text-text-primary">
|
||||
{t('common.apiBasedExtension.selector.title')}
|
||||
{t('apiBasedExtension.selector.title', { ns: 'common' })}
|
||||
<a
|
||||
href={docLink('/guides/extension/api-based-extension/README')}
|
||||
target="_blank"
|
||||
@ -247,7 +247,7 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
|
||||
className="group flex items-center text-xs font-normal text-text-tertiary hover:text-text-accent"
|
||||
>
|
||||
<BookOpen01 className="mr-1 h-3 w-3 text-text-tertiary group-hover:text-text-accent" />
|
||||
{t('common.apiBasedExtension.link')}
|
||||
{t('apiBasedExtension.link', { ns: 'common' })}
|
||||
</a>
|
||||
</div>
|
||||
<ApiBasedExtensionSelector
|
||||
@ -273,13 +273,13 @@ const ExternalDataToolModal: FC<ExternalDataToolModalProps> = ({
|
||||
onClick={onCancel}
|
||||
className="mr-2"
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
onClick={handleSave}
|
||||
>
|
||||
{t('common.operation.save')}
|
||||
{t('operation.save', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
{
|
||||
|
||||
@ -48,7 +48,7 @@ const Tools = () => {
|
||||
const promptVariables = modelConfig?.configs?.prompt_variables || []
|
||||
for (let i = 0; i < promptVariables.length; i++) {
|
||||
if (promptVariables[i].key === newExternalDataTool.variable) {
|
||||
notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: promptVariables[i].key }) })
|
||||
notify({ type: 'error', message: t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: promptVariables[i].key }) })
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -66,7 +66,7 @@ const Tools = () => {
|
||||
|
||||
for (let i = 0; i < existedExternalDataTools.length; i++) {
|
||||
if (existedExternalDataTools[i].variable === newExternalDataTool.variable) {
|
||||
notify({ type: 'error', message: t('appDebug.varKeyError.keyAlreadyExists', { key: existedExternalDataTools[i].variable }) })
|
||||
notify({ type: 'error', message: t('varKeyError.keyAlreadyExists', { ns: 'appDebug', key: existedExternalDataTools[i].variable }) })
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -108,12 +108,12 @@ const Tools = () => {
|
||||
}
|
||||
</div>
|
||||
<div className="mr-1 text-sm font-semibold text-gray-800">
|
||||
{t('appDebug.feature.tools.title')}
|
||||
{t('feature.tools.title', { ns: 'appDebug' })}
|
||||
</div>
|
||||
<Tooltip
|
||||
popupContent={(
|
||||
<div className="max-w-[160px]">
|
||||
{t('appDebug.feature.tools.tips')}
|
||||
{t('feature.tools.tips', { ns: 'appDebug' })}
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
@ -121,7 +121,7 @@ const Tools = () => {
|
||||
{
|
||||
!expanded && !!externalDataToolsConfig.length && (
|
||||
<>
|
||||
<div className="mr-3 text-xs text-gray-500">{t('appDebug.feature.tools.toolsInUse', { count: externalDataToolsConfig.length })}</div>
|
||||
<div className="mr-3 text-xs text-gray-500">{t('feature.tools.toolsInUse', { ns: 'appDebug', count: externalDataToolsConfig.length })}</div>
|
||||
<div className="mr-1 h-3.5 w-[1px] bg-gray-200" />
|
||||
</>
|
||||
)
|
||||
@ -131,7 +131,7 @@ const Tools = () => {
|
||||
onClick={() => handleOpenExternalDataToolModal({}, -1)}
|
||||
>
|
||||
<RiAddLine className="mr-[5px] h-3.5 w-3.5 " />
|
||||
{t('common.operation.add')}
|
||||
{t('operation.add', { ns: 'common' })}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
@ -152,7 +152,7 @@ const Tools = () => {
|
||||
/>
|
||||
<div className="mr-2 text-[13px] font-medium text-gray-800">{item.label}</div>
|
||||
<Tooltip
|
||||
popupContent={copied ? t('appApi.copied') : `${item.variable}, ${t('appApi.copy')}`}
|
||||
popupContent={copied ? t('copied', { ns: 'appApi' }) : `${item.variable}, ${t('copy', { ns: 'appApi' })}`}
|
||||
>
|
||||
<div
|
||||
className="text-xs text-gray-500"
|
||||
|
||||
@ -54,7 +54,7 @@ const AppCard = ({
|
||||
<div className={cn('flex h-8 w-full items-center space-x-2')}>
|
||||
<Button variant="primary" className="grow" onClick={() => onCreate()}>
|
||||
<PlusIcon className="mr-1 h-4 w-4" />
|
||||
<span className="text-xs">{t('app.newApp.useTemplate')}</span>
|
||||
<span className="text-xs">{t('newApp.useTemplate', { ns: 'app' })}</span>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user