mirror of https://github.com/langgenius/dify.git
test(JinaReader): add tests for handling null and undefined limits
- Introduced new test cases to verify that the JinaReader component correctly handles scenarios where the crawl limit is null or undefined, ensuring that the task is not initiated in these cases. - Refactored existing tests to remove unnecessary promise resolutions, improving clarity and maintainability.
This commit is contained in:
commit
fe0b221354
|
|
@ -4,7 +4,7 @@ on:
|
|||
push:
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'web/i18n/en-US/*.ts'
|
||||
- 'web/i18n/en-US/*.json'
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
|
@ -28,13 +28,13 @@ jobs:
|
|||
run: |
|
||||
git fetch origin "${{ github.event.before }}" || true
|
||||
git fetch origin "${{ github.sha }}" || true
|
||||
changed_files=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" -- 'i18n/en-US/*.ts')
|
||||
changed_files=$(git diff --name-only "${{ github.event.before }}" "${{ github.sha }}" -- 'i18n/en-US/*.json')
|
||||
echo "Changed files: $changed_files"
|
||||
if [ -n "$changed_files" ]; then
|
||||
echo "FILES_CHANGED=true" >> $GITHUB_ENV
|
||||
file_args=""
|
||||
for file in $changed_files; do
|
||||
filename=$(basename "$file" .ts)
|
||||
filename=$(basename "$file" .json)
|
||||
file_args="$file_args --file $filename"
|
||||
done
|
||||
echo "FILE_ARGS=$file_args" >> $GITHUB_ENV
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ const getSupportedLocales = (): string[] => {
|
|||
|
||||
// Helper function to load translation file content
|
||||
const loadTranslationContent = (locale: string): string => {
|
||||
const filePath = path.join(I18N_DIR, locale, 'app-debug.ts')
|
||||
const filePath = path.join(I18N_DIR, locale, 'app-debug.json')
|
||||
|
||||
if (!fs.existsSync(filePath))
|
||||
throw new Error(`Translation file not found: ${filePath}`)
|
||||
|
|
@ -24,14 +24,14 @@ const loadTranslationContent = (locale: string): string => {
|
|||
return fs.readFileSync(filePath, 'utf-8')
|
||||
}
|
||||
|
||||
// Helper function to check if upload features exist
|
||||
// Helper function to check if upload features exist (supports flattened JSON)
|
||||
const hasUploadFeatures = (content: string): { [key: string]: boolean } => {
|
||||
return {
|
||||
fileUpload: /fileUpload\s*:\s*\{/.test(content),
|
||||
imageUpload: /imageUpload\s*:\s*\{/.test(content),
|
||||
documentUpload: /documentUpload\s*:\s*\{/.test(content),
|
||||
audioUpload: /audioUpload\s*:\s*\{/.test(content),
|
||||
featureBar: /bar\s*:\s*\{/.test(content),
|
||||
fileUpload: /"feature\.fileUpload\.title"/.test(content),
|
||||
imageUpload: /"feature\.imageUpload\.title"/.test(content),
|
||||
documentUpload: /"feature\.documentUpload\.title"/.test(content),
|
||||
audioUpload: /"feature\.audioUpload\.title"/.test(content),
|
||||
featureBar: /"feature\.bar\.empty"/.test(content),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -45,7 +45,7 @@ describe('Upload Features i18n Translations - Issue #23062', () => {
|
|||
|
||||
it('all locales should have translation files', () => {
|
||||
supportedLocales.forEach((locale) => {
|
||||
const filePath = path.join(I18N_DIR, locale, 'app-debug.ts')
|
||||
const filePath = path.join(I18N_DIR, locale, 'app-debug.json')
|
||||
expect(fs.existsSync(filePath)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
|
@ -76,12 +76,9 @@ describe('Upload Features i18n Translations - Issue #23062', () => {
|
|||
previouslyMissingLocales.forEach((locale) => {
|
||||
const content = loadTranslationContent(locale)
|
||||
|
||||
// Verify audioUpload exists
|
||||
expect(/audioUpload\s*:\s*\{/.test(content)).toBe(true)
|
||||
|
||||
// Verify it has title and description
|
||||
expect(/audioUpload[^}]*title\s*:/.test(content)).toBe(true)
|
||||
expect(/audioUpload[^}]*description\s*:/.test(content)).toBe(true)
|
||||
// Verify audioUpload exists with title and description (flattened JSON format)
|
||||
expect(/"feature\.audioUpload\.title"/.test(content)).toBe(true)
|
||||
expect(/"feature\.audioUpload\.description"/.test(content)).toBe(true)
|
||||
|
||||
console.log(`✅ ${locale} - Issue #23062 resolved: audioUpload feature present`)
|
||||
})
|
||||
|
|
@ -91,28 +88,28 @@ describe('Upload Features i18n Translations - Issue #23062', () => {
|
|||
supportedLocales.forEach((locale) => {
|
||||
const content = loadTranslationContent(locale)
|
||||
|
||||
// Check fileUpload has required properties
|
||||
if (/fileUpload\s*:\s*\{/.test(content)) {
|
||||
expect(/fileUpload[^}]*title\s*:/.test(content)).toBe(true)
|
||||
expect(/fileUpload[^}]*description\s*:/.test(content)).toBe(true)
|
||||
// Check fileUpload has required properties (flattened JSON format)
|
||||
if (/"feature\.fileUpload\.title"/.test(content)) {
|
||||
expect(/"feature\.fileUpload\.title"/.test(content)).toBe(true)
|
||||
expect(/"feature\.fileUpload\.description"/.test(content)).toBe(true)
|
||||
}
|
||||
|
||||
// Check imageUpload has required properties
|
||||
if (/imageUpload\s*:\s*\{/.test(content)) {
|
||||
expect(/imageUpload[^}]*title\s*:/.test(content)).toBe(true)
|
||||
expect(/imageUpload[^}]*description\s*:/.test(content)).toBe(true)
|
||||
if (/"feature\.imageUpload\.title"/.test(content)) {
|
||||
expect(/"feature\.imageUpload\.title"/.test(content)).toBe(true)
|
||||
expect(/"feature\.imageUpload\.description"/.test(content)).toBe(true)
|
||||
}
|
||||
|
||||
// Check documentUpload has required properties
|
||||
if (/documentUpload\s*:\s*\{/.test(content)) {
|
||||
expect(/documentUpload[^}]*title\s*:/.test(content)).toBe(true)
|
||||
expect(/documentUpload[^}]*description\s*:/.test(content)).toBe(true)
|
||||
if (/"feature\.documentUpload\.title"/.test(content)) {
|
||||
expect(/"feature\.documentUpload\.title"/.test(content)).toBe(true)
|
||||
expect(/"feature\.documentUpload\.description"/.test(content)).toBe(true)
|
||||
}
|
||||
|
||||
// Check audioUpload has required properties
|
||||
if (/audioUpload\s*:\s*\{/.test(content)) {
|
||||
expect(/audioUpload[^}]*title\s*:/.test(content)).toBe(true)
|
||||
expect(/audioUpload[^}]*description\s*:/.test(content)).toBe(true)
|
||||
if (/"feature\.audioUpload\.title"/.test(content)) {
|
||||
expect(/"feature\.audioUpload\.title"/.test(content)).toBe(true)
|
||||
expect(/"feature\.audioUpload\.description"/.test(content)).toBe(true)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||
const navConfig = [
|
||||
...(isCurrentWorkspaceEditor
|
||||
? [{
|
||||
name: t('common.appMenus.promptEng'),
|
||||
name: t('appMenus.promptEng', { ns: 'common' }),
|
||||
href: `/app/${appId}/${(mode === AppModeEnum.WORKFLOW || mode === AppModeEnum.ADVANCED_CHAT) ? 'workflow' : 'configuration'}`,
|
||||
icon: RiTerminalWindowLine,
|
||||
selectedIcon: RiTerminalWindowFill,
|
||||
|
|
@ -78,7 +78,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||
: []
|
||||
),
|
||||
{
|
||||
name: t('common.appMenus.apiAccess'),
|
||||
name: t('appMenus.apiAccess', { ns: 'common' }),
|
||||
href: `/app/${appId}/develop`,
|
||||
icon: RiTerminalBoxLine,
|
||||
selectedIcon: RiTerminalBoxFill,
|
||||
|
|
@ -86,8 +86,8 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||
...(isCurrentWorkspaceEditor
|
||||
? [{
|
||||
name: mode !== AppModeEnum.WORKFLOW
|
||||
? t('common.appMenus.logAndAnn')
|
||||
: t('common.appMenus.logs'),
|
||||
? t('appMenus.logAndAnn', { ns: 'common' })
|
||||
: t('appMenus.logs', { ns: 'common' }),
|
||||
href: `/app/${appId}/logs`,
|
||||
icon: RiFileList3Line,
|
||||
selectedIcon: RiFileList3Fill,
|
||||
|
|
@ -95,7 +95,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||
: []
|
||||
),
|
||||
{
|
||||
name: t('common.appMenus.overview'),
|
||||
name: t('appMenus.overview', { ns: 'common' }),
|
||||
href: `/app/${appId}/overview`,
|
||||
icon: RiDashboard2Line,
|
||||
selectedIcon: RiDashboard2Fill,
|
||||
|
|
@ -104,7 +104,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||
return navConfig
|
||||
}, [t])
|
||||
|
||||
useDocumentTitle(appDetail?.name || t('common.menus.appDetail'))
|
||||
useDocumentTitle(appDetail?.name || t('menus.appDetail', { ns: 'common' }))
|
||||
|
||||
useEffect(() => {
|
||||
if (appDetail) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import type { IAppCardProps } from '@/app/components/app/overview/app-card'
|
|||
import type { BlockEnum } from '@/app/components/workflow/types'
|
||||
import type { UpdateAppSiteCodeResponse } from '@/models/app'
|
||||
import type { App } from '@/types/app'
|
||||
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
|
@ -62,7 +63,7 @@ const CardView: FC<ICardViewProps> = ({ appId, isInPanel, className }) => {
|
|||
const buildTriggerModeMessage = useCallback((featureName: string) => (
|
||||
<div className="flex flex-col gap-1">
|
||||
<div className="text-xs text-text-secondary">
|
||||
{t('appOverview.overview.disableTooltip.triggerMode', { feature: featureName })}
|
||||
{t('overview.disableTooltip.triggerMode', { ns: 'appOverview', feature: featureName })}
|
||||
</div>
|
||||
<div
|
||||
className="cursor-pointer text-xs font-medium text-text-accent hover:underline"
|
||||
|
|
@ -71,19 +72,19 @@ const CardView: FC<ICardViewProps> = ({ appId, isInPanel, className }) => {
|
|||
window.open(triggerDocUrl, '_blank')
|
||||
}}
|
||||
>
|
||||
{t('appOverview.overview.appInfo.enableTooltip.learnMore')}
|
||||
{t('overview.appInfo.enableTooltip.learnMore', { ns: 'appOverview' })}
|
||||
</div>
|
||||
</div>
|
||||
), [t, triggerDocUrl])
|
||||
|
||||
const disableWebAppTooltip = disableAppCards
|
||||
? buildTriggerModeMessage(t('appOverview.overview.appInfo.title'))
|
||||
? buildTriggerModeMessage(t('overview.appInfo.title', { ns: 'appOverview' }))
|
||||
: null
|
||||
const disableApiTooltip = disableAppCards
|
||||
? buildTriggerModeMessage(t('appOverview.overview.apiInfo.title'))
|
||||
? buildTriggerModeMessage(t('overview.apiInfo.title', { ns: 'appOverview' }))
|
||||
: null
|
||||
const disableMcpTooltip = disableAppCards
|
||||
? buildTriggerModeMessage(t('tools.mcp.server.title'))
|
||||
? buildTriggerModeMessage(t('mcp.server.title', { ns: 'tools' }))
|
||||
: null
|
||||
|
||||
const updateAppDetail = async () => {
|
||||
|
|
@ -94,7 +95,7 @@ const CardView: FC<ICardViewProps> = ({ appId, isInPanel, className }) => {
|
|||
catch (error) { console.error(error) }
|
||||
}
|
||||
|
||||
const handleCallbackResult = (err: Error | null, message?: string) => {
|
||||
const handleCallbackResult = (err: Error | null, message?: I18nKeysByPrefix<'common', 'actionMsg.'>) => {
|
||||
const type = err ? 'error' : 'success'
|
||||
|
||||
message ||= (type === 'success' ? 'modifiedSuccessfully' : 'modifiedUnsuccessfully')
|
||||
|
|
@ -104,7 +105,7 @@ const CardView: FC<ICardViewProps> = ({ appId, isInPanel, className }) => {
|
|||
|
||||
notify({
|
||||
type,
|
||||
message: t(`common.actionMsg.${message}` as any) as string,
|
||||
message: t(`actionMsg.${message}`, { ns: 'common' }) as string,
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
'use client'
|
||||
import type { PeriodParams } from '@/app/components/app/overview/app-chart'
|
||||
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||
import dayjs from 'dayjs'
|
||||
import quarterOfYear from 'dayjs/plugin/quarterOfYear'
|
||||
import * as React from 'react'
|
||||
|
|
@ -16,7 +17,9 @@ dayjs.extend(quarterOfYear)
|
|||
|
||||
const today = dayjs()
|
||||
|
||||
const TIME_PERIOD_MAPPING = [
|
||||
type TimePeriodName = I18nKeysByPrefix<'appLog', 'filter.period.'>
|
||||
|
||||
const TIME_PERIOD_MAPPING: { value: number, name: TimePeriodName }[] = [
|
||||
{ value: 0, name: 'today' },
|
||||
{ value: 7, name: 'last7days' },
|
||||
{ value: 30, name: 'last30days' },
|
||||
|
|
@ -35,8 +38,8 @@ export default function ChartView({ appId, headerRight }: IChartViewProps) {
|
|||
const isChatApp = appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow'
|
||||
const isWorkflow = appDetail?.mode === 'workflow'
|
||||
const [period, setPeriod] = useState<PeriodParams>(IS_CLOUD_EDITION
|
||||
? { name: t('appLog.filter.period.today'), query: { start: today.startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } }
|
||||
: { name: t('appLog.filter.period.last7days'), query: { start: today.subtract(7, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } },
|
||||
? { name: t('filter.period.today', { ns: 'appLog' }), query: { start: today.startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } }
|
||||
: { name: t('filter.period.last7days', { ns: 'appLog' }), query: { start: today.subtract(7, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } },
|
||||
)
|
||||
|
||||
if (!appDetail)
|
||||
|
|
@ -45,7 +48,7 @@ export default function ChartView({ appId, headerRight }: IChartViewProps) {
|
|||
return (
|
||||
<div>
|
||||
<div className="mb-4">
|
||||
<div className="system-xl-semibold mb-2 text-text-primary">{t('common.appMenus.overview')}</div>
|
||||
<div className="system-xl-semibold mb-2 text-text-primary">{t('appMenus.overview', { ns: 'common' })}</div>
|
||||
<div className="flex items-center justify-between">
|
||||
{IS_CLOUD_EDITION
|
||||
? (
|
||||
|
|
|
|||
|
|
@ -2,13 +2,16 @@
|
|||
import type { FC } from 'react'
|
||||
import type { PeriodParams } from '@/app/components/app/overview/app-chart'
|
||||
import type { Item } from '@/app/components/base/select'
|
||||
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||
import dayjs from 'dayjs'
|
||||
import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
|
||||
type TimePeriodName = I18nKeysByPrefix<'appLog', 'filter.period.'>
|
||||
|
||||
type Props = {
|
||||
periodMapping: { [key: string]: { value: number, name: string } }
|
||||
periodMapping: { [key: string]: { value: number, name: TimePeriodName } }
|
||||
onSelect: (payload: PeriodParams) => void
|
||||
queryDateFormat: string
|
||||
}
|
||||
|
|
@ -25,9 +28,9 @@ const LongTimeRangePicker: FC<Props> = ({
|
|||
const handleSelect = React.useCallback((item: Item) => {
|
||||
const id = item.value
|
||||
const value = periodMapping[id]?.value ?? '-1'
|
||||
const name = item.name || t('appLog.filter.period.allTime')
|
||||
const name = item.name || t('filter.period.allTime', { ns: 'appLog' })
|
||||
if (value === -1) {
|
||||
onSelect({ name: t('appLog.filter.period.allTime'), query: undefined })
|
||||
onSelect({ name: t('filter.period.allTime', { ns: 'appLog' }), query: undefined })
|
||||
}
|
||||
else if (value === 0) {
|
||||
const startOfToday = today.startOf('day').format(queryDateFormat)
|
||||
|
|
@ -53,7 +56,7 @@ const LongTimeRangePicker: FC<Props> = ({
|
|||
|
||||
return (
|
||||
<SimpleSelect
|
||||
items={Object.entries(periodMapping).map(([k, v]) => ({ value: k, name: t(`appLog.filter.period.${v.name}` as any) as string }))}
|
||||
items={Object.entries(periodMapping).map(([k, v]) => ({ value: k, name: t(`filter.period.${v.name}`, { ns: 'appLog' }) }))}
|
||||
className="mt-0 !w-40"
|
||||
notClearable={true}
|
||||
onSelect={handleSelect}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import type { Dayjs } from 'dayjs'
|
||||
import type { FC } from 'react'
|
||||
import type { PeriodParams, PeriodParamsWithTimeRange } from '@/app/components/app/overview/app-chart'
|
||||
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||
import dayjs from 'dayjs'
|
||||
import * as React from 'react'
|
||||
import { useCallback, useState } from 'react'
|
||||
|
|
@ -13,8 +14,10 @@ import RangeSelector from './range-selector'
|
|||
|
||||
const today = dayjs()
|
||||
|
||||
type TimePeriodName = I18nKeysByPrefix<'appLog', 'filter.period.'>
|
||||
|
||||
type Props = {
|
||||
ranges: { value: number, name: string }[]
|
||||
ranges: { value: number, name: TimePeriodName }[]
|
||||
onSelect: (payload: PeriodParams) => void
|
||||
queryDateFormat: string
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import type { FC } from 'react'
|
||||
import type { PeriodParamsWithTimeRange, TimeRange } from '@/app/components/app/overview/app-chart'
|
||||
import type { Item } from '@/app/components/base/select'
|
||||
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||
import { RiArrowDownSLine, RiCheckLine } from '@remixicon/react'
|
||||
import dayjs from 'dayjs'
|
||||
import * as React from 'react'
|
||||
|
|
@ -12,9 +13,11 @@ import { cn } from '@/utils/classnames'
|
|||
|
||||
const today = dayjs()
|
||||
|
||||
type TimePeriodName = I18nKeysByPrefix<'appLog', 'filter.period.'>
|
||||
|
||||
type Props = {
|
||||
isCustomRange: boolean
|
||||
ranges: { value: number, name: string }[]
|
||||
ranges: { value: number, name: TimePeriodName }[]
|
||||
onSelect: (payload: PeriodParamsWithTimeRange) => void
|
||||
}
|
||||
|
||||
|
|
@ -42,7 +45,7 @@ const RangeSelector: FC<Props> = ({
|
|||
const renderTrigger = useCallback((item: Item | null, isOpen: boolean) => {
|
||||
return (
|
||||
<div className={cn('flex h-8 cursor-pointer items-center space-x-1.5 rounded-lg bg-components-input-bg-normal pl-3 pr-2', isOpen && 'bg-state-base-hover-alt')}>
|
||||
<div className="system-sm-regular text-components-input-text-filled">{isCustomRange ? t('appLog.filter.period.custom') : item?.name}</div>
|
||||
<div className="system-sm-regular text-components-input-text-filled">{isCustomRange ? t('filter.period.custom', { ns: 'appLog' }) : item?.name}</div>
|
||||
<RiArrowDownSLine className={cn('size-4 text-text-quaternary', isOpen && 'text-text-secondary')} />
|
||||
</div>
|
||||
)
|
||||
|
|
@ -66,7 +69,7 @@ const RangeSelector: FC<Props> = ({
|
|||
}, [])
|
||||
return (
|
||||
<SimpleSelect
|
||||
items={ranges.map(v => ({ ...v, name: t(`appLog.filter.period.${v.name}` as any) as string }))}
|
||||
items={ranges.map(v => ({ ...v, name: t(`filter.period.${v.name}`, { ns: 'appLog' }) }))}
|
||||
className="mt-0 !w-40"
|
||||
notClearable={true}
|
||||
onSelect={handleSelectRange}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ import ProviderPanel from './provider-panel'
|
|||
import TracingIcon from './tracing-icon'
|
||||
import { TracingProvider } from './type'
|
||||
|
||||
const I18N_PREFIX = 'app.tracing'
|
||||
const I18N_PREFIX = 'tracing'
|
||||
|
||||
export type PopupProps = {
|
||||
appId: string
|
||||
|
|
@ -327,19 +327,19 @@ const ConfigPopup: FC<PopupProps> = ({
|
|||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center">
|
||||
<TracingIcon size="md" className="mr-2" />
|
||||
<div className="title-2xl-semi-bold text-text-primary">{t(`${I18N_PREFIX}.tracing`)}</div>
|
||||
<div className="title-2xl-semi-bold text-text-primary">{t(`${I18N_PREFIX}.tracing`, { ns: 'app' })}</div>
|
||||
</div>
|
||||
<div className="flex items-center">
|
||||
<Indicator color={enabled ? 'green' : 'gray'} />
|
||||
<div className={cn('system-xs-semibold-uppercase ml-1 text-text-tertiary', enabled && 'text-util-colors-green-green-600')}>
|
||||
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
|
||||
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`, { ns: 'app' })}
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<>
|
||||
{providerAllNotConfigured
|
||||
? (
|
||||
<Tooltip
|
||||
popupContent={t(`${I18N_PREFIX}.disabledTip`)}
|
||||
popupContent={t(`${I18N_PREFIX}.disabledTip`, { ns: 'app' })}
|
||||
>
|
||||
{switchContent}
|
||||
</Tooltip>
|
||||
|
|
@ -351,14 +351,14 @@ const ConfigPopup: FC<PopupProps> = ({
|
|||
</div>
|
||||
|
||||
<div className="system-xs-regular mt-2 text-text-tertiary">
|
||||
{t(`${I18N_PREFIX}.tracingDescription`)}
|
||||
{t(`${I18N_PREFIX}.tracingDescription`, { ns: 'app' })}
|
||||
</div>
|
||||
<Divider className="my-3" />
|
||||
<div className="relative">
|
||||
{(providerAllConfigured || providerAllNotConfigured)
|
||||
? (
|
||||
<>
|
||||
<div className="system-xs-medium-uppercase text-text-tertiary">{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`)}</div>
|
||||
<div className="system-xs-medium-uppercase text-text-tertiary">{t(`${I18N_PREFIX}.configProviderTitle.${providerAllConfigured ? 'configured' : 'notConfigured'}`, { ns: 'app' })}</div>
|
||||
<div className="mt-2 max-h-96 space-y-2 overflow-y-auto">
|
||||
{langfusePanel}
|
||||
{langSmithPanel}
|
||||
|
|
@ -375,11 +375,11 @@ const ConfigPopup: FC<PopupProps> = ({
|
|||
)
|
||||
: (
|
||||
<>
|
||||
<div className="system-xs-medium-uppercase text-text-tertiary">{t(`${I18N_PREFIX}.configProviderTitle.configured`)}</div>
|
||||
<div className="system-xs-medium-uppercase text-text-tertiary">{t(`${I18N_PREFIX}.configProviderTitle.configured`, { ns: 'app' })}</div>
|
||||
<div className="mt-2 max-h-40 space-y-2 overflow-y-auto">
|
||||
{configuredProviderPanel()}
|
||||
</div>
|
||||
<div className="system-xs-medium-uppercase mt-3 text-text-tertiary">{t(`${I18N_PREFIX}.configProviderTitle.moreProvider`)}</div>
|
||||
<div className="system-xs-medium-uppercase mt-3 text-text-tertiary">{t(`${I18N_PREFIX}.configProviderTitle.moreProvider`, { ns: 'app' })}</div>
|
||||
<div className="mt-2 max-h-40 space-y-2 overflow-y-auto">
|
||||
{moreProviderPanel()}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ import ConfigButton from './config-button'
|
|||
import TracingIcon from './tracing-icon'
|
||||
import { TracingProvider } from './type'
|
||||
|
||||
const I18N_PREFIX = 'app.tracing'
|
||||
const I18N_PREFIX = 'tracing'
|
||||
|
||||
const Panel: FC = () => {
|
||||
const { t } = useTranslation()
|
||||
|
|
@ -45,7 +45,7 @@ const Panel: FC = () => {
|
|||
if (!noToast) {
|
||||
Toast.notify({
|
||||
type: 'success',
|
||||
message: t('common.api.success'),
|
||||
message: t('api.success', { ns: 'common' }),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -254,7 +254,7 @@ const Panel: FC = () => {
|
|||
)}
|
||||
>
|
||||
<TracingIcon size="md" />
|
||||
<div className="system-sm-semibold mx-2 text-text-secondary">{t(`${I18N_PREFIX}.title`)}</div>
|
||||
<div className="system-sm-semibold mx-2 text-text-secondary">{t(`${I18N_PREFIX}.title`, { ns: 'app' })}</div>
|
||||
<div className="rounded-md p-1">
|
||||
<RiEqualizer2Line className="h-4 w-4 text-text-tertiary" />
|
||||
</div>
|
||||
|
|
@ -295,7 +295,7 @@ const Panel: FC = () => {
|
|||
<div className="ml-4 mr-1 flex items-center">
|
||||
<Indicator color={enabled ? 'green' : 'gray'} />
|
||||
<div className="system-xs-semibold-uppercase ml-1.5 text-text-tertiary">
|
||||
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`)}
|
||||
{t(`${I18N_PREFIX}.${enabled ? 'enabled' : 'disabled'}`, { ns: 'app' })}
|
||||
</div>
|
||||
</div>
|
||||
{InUseProviderIcon && <InUseProviderIcon className="ml-1 h-4" />}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ type Props = {
|
|||
onChosen: (provider: TracingProvider) => void
|
||||
}
|
||||
|
||||
const I18N_PREFIX = 'app.tracing.configProvider'
|
||||
const I18N_PREFIX = 'tracing.configProvider'
|
||||
|
||||
const arizeConfigTemplate = {
|
||||
api_key: '',
|
||||
|
|
@ -157,7 +157,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
})
|
||||
Toast.notify({
|
||||
type: 'success',
|
||||
message: t('common.api.remove'),
|
||||
message: t('api.remove', { ns: 'common' }),
|
||||
})
|
||||
onRemoved()
|
||||
hideRemoveConfirm()
|
||||
|
|
@ -177,37 +177,37 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
if (type === TracingProvider.arize) {
|
||||
const postData = config as ArizeConfig
|
||||
if (!postData.api_key)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'API Key' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'API Key' })
|
||||
if (!postData.space_id)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Space ID' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Space ID' })
|
||||
if (!errorMessage && !postData.project)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.project`) })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t(`${I18N_PREFIX}.project`, { ns: 'app' }) })
|
||||
}
|
||||
|
||||
if (type === TracingProvider.phoenix) {
|
||||
const postData = config as PhoenixConfig
|
||||
if (!postData.api_key)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'API Key' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'API Key' })
|
||||
if (!errorMessage && !postData.project)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.project`) })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t(`${I18N_PREFIX}.project`, { ns: 'app' }) })
|
||||
}
|
||||
|
||||
if (type === TracingProvider.langSmith) {
|
||||
const postData = config as LangSmithConfig
|
||||
if (!postData.api_key)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'API Key' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'API Key' })
|
||||
if (!errorMessage && !postData.project)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.project`) })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t(`${I18N_PREFIX}.project`, { ns: 'app' }) })
|
||||
}
|
||||
|
||||
if (type === TracingProvider.langfuse) {
|
||||
const postData = config as LangFuseConfig
|
||||
if (!errorMessage && !postData.secret_key)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.secretKey`) })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t(`${I18N_PREFIX}.secretKey`, { ns: 'app' }) })
|
||||
if (!errorMessage && !postData.public_key)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.publicKey`) })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t(`${I18N_PREFIX}.publicKey`, { ns: 'app' }) })
|
||||
if (!errorMessage && !postData.host)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Host' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Host' })
|
||||
}
|
||||
|
||||
if (type === TracingProvider.opik) {
|
||||
|
|
@ -218,43 +218,43 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
if (type === TracingProvider.weave) {
|
||||
const postData = config as WeaveConfig
|
||||
if (!errorMessage && !postData.api_key)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'API Key' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'API Key' })
|
||||
if (!errorMessage && !postData.project)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: t(`${I18N_PREFIX}.project`) })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: t(`${I18N_PREFIX}.project`, { ns: 'app' }) })
|
||||
}
|
||||
|
||||
if (type === TracingProvider.aliyun) {
|
||||
const postData = config as AliyunConfig
|
||||
if (!errorMessage && !postData.app_name)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'App Name' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'App Name' })
|
||||
if (!errorMessage && !postData.license_key)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'License Key' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'License Key' })
|
||||
if (!errorMessage && !postData.endpoint)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Endpoint' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Endpoint' })
|
||||
}
|
||||
|
||||
if (type === TracingProvider.mlflow) {
|
||||
const postData = config as MLflowConfig
|
||||
if (!errorMessage && !postData.tracking_uri)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Tracking URI' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Tracking URI' })
|
||||
}
|
||||
|
||||
if (type === TracingProvider.databricks) {
|
||||
const postData = config as DatabricksConfig
|
||||
if (!errorMessage && !postData.experiment_id)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Experiment ID' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Experiment ID' })
|
||||
if (!errorMessage && !postData.host)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Host' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Host' })
|
||||
}
|
||||
|
||||
if (type === TracingProvider.tencent) {
|
||||
const postData = config as TencentConfig
|
||||
if (!errorMessage && !postData.token)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Token' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Token' })
|
||||
if (!errorMessage && !postData.endpoint)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Endpoint' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Endpoint' })
|
||||
if (!errorMessage && !postData.service_name)
|
||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Service Name' })
|
||||
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Service Name' })
|
||||
}
|
||||
|
||||
return errorMessage
|
||||
|
|
@ -281,7 +281,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
})
|
||||
Toast.notify({
|
||||
type: 'success',
|
||||
message: t('common.api.success'),
|
||||
message: t('api.success', { ns: 'common' }),
|
||||
})
|
||||
onSaved(config)
|
||||
if (isAdd)
|
||||
|
|
@ -303,8 +303,8 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
<div className="px-8 pt-8">
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<div className="title-2xl-semi-bold text-text-primary">
|
||||
{t(`${I18N_PREFIX}.title`)}
|
||||
{t(`app.tracing.${type}.title`)}
|
||||
{t(`${I18N_PREFIX}.title`, { ns: 'app' })}
|
||||
{t(`tracing.${type}.title`, { ns: 'app' })}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -317,7 +317,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
isRequired
|
||||
value={(config as ArizeConfig).api_key}
|
||||
onChange={handleConfigChange('api_key')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'API Key' })!}
|
||||
/>
|
||||
<Field
|
||||
label="Space ID"
|
||||
|
|
@ -325,15 +325,15 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
isRequired
|
||||
value={(config as ArizeConfig).space_id}
|
||||
onChange={handleConfigChange('space_id')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'Space ID' })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'Space ID' })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.project`)!}
|
||||
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
isRequired
|
||||
value={(config as ArizeConfig).project}
|
||||
onChange={handleConfigChange('project')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.project`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label="Endpoint"
|
||||
|
|
@ -352,15 +352,15 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
isRequired
|
||||
value={(config as PhoenixConfig).api_key}
|
||||
onChange={handleConfigChange('api_key')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'API Key' })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.project`)!}
|
||||
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
isRequired
|
||||
value={(config as PhoenixConfig).project}
|
||||
onChange={handleConfigChange('project')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.project`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label="Endpoint"
|
||||
|
|
@ -379,7 +379,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
isRequired
|
||||
value={(config as AliyunConfig).license_key}
|
||||
onChange={handleConfigChange('license_key')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'License Key' })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'License Key' })!}
|
||||
/>
|
||||
<Field
|
||||
label="Endpoint"
|
||||
|
|
@ -404,7 +404,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
isRequired
|
||||
value={(config as TencentConfig).token}
|
||||
onChange={handleConfigChange('token')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'Token' })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'Token' })!}
|
||||
/>
|
||||
<Field
|
||||
label="Endpoint"
|
||||
|
|
@ -432,22 +432,22 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
isRequired
|
||||
value={(config as WeaveConfig).api_key}
|
||||
onChange={handleConfigChange('api_key')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'API Key' })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.project`)!}
|
||||
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
isRequired
|
||||
value={(config as WeaveConfig).project}
|
||||
onChange={handleConfigChange('project')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.project`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label="Entity"
|
||||
labelClassName="!text-sm"
|
||||
value={(config as WeaveConfig).entity}
|
||||
onChange={handleConfigChange('entity')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'Entity' })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'Entity' })!}
|
||||
/>
|
||||
<Field
|
||||
label="Endpoint"
|
||||
|
|
@ -473,15 +473,15 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
isRequired
|
||||
value={(config as LangSmithConfig).api_key}
|
||||
onChange={handleConfigChange('api_key')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'API Key' })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.project`)!}
|
||||
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
isRequired
|
||||
value={(config as LangSmithConfig).project}
|
||||
onChange={handleConfigChange('project')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.project`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label="Endpoint"
|
||||
|
|
@ -495,20 +495,20 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
{type === TracingProvider.langfuse && (
|
||||
<>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.secretKey`)!}
|
||||
label={t(`${I18N_PREFIX}.secretKey`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as LangFuseConfig).secret_key}
|
||||
isRequired
|
||||
onChange={handleConfigChange('secret_key')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.secretKey`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.secretKey`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.publicKey`)!}
|
||||
label={t(`${I18N_PREFIX}.publicKey`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
isRequired
|
||||
value={(config as LangFuseConfig).public_key}
|
||||
onChange={handleConfigChange('public_key')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.publicKey`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.publicKey`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label="Host"
|
||||
|
|
@ -527,14 +527,14 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
labelClassName="!text-sm"
|
||||
value={(config as OpikConfig).api_key}
|
||||
onChange={handleConfigChange('api_key')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'API Key' })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'API Key' })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.project`)!}
|
||||
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as OpikConfig).project}
|
||||
onChange={handleConfigChange('project')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.project`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.project`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label="Workspace"
|
||||
|
|
@ -555,7 +555,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
{type === TracingProvider.mlflow && (
|
||||
<>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.trackingUri`)!}
|
||||
label={t(`${I18N_PREFIX}.trackingUri`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as MLflowConfig).tracking_uri}
|
||||
isRequired
|
||||
|
|
@ -563,67 +563,67 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
placeholder="http://localhost:5000"
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.experimentId`)!}
|
||||
label={t(`${I18N_PREFIX}.experimentId`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
isRequired
|
||||
value={(config as MLflowConfig).experiment_id}
|
||||
onChange={handleConfigChange('experiment_id')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.experimentId`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.experimentId`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.username`)!}
|
||||
label={t(`${I18N_PREFIX}.username`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as MLflowConfig).username}
|
||||
onChange={handleConfigChange('username')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.username`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.username`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.password`)!}
|
||||
label={t(`${I18N_PREFIX}.password`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as MLflowConfig).password}
|
||||
onChange={handleConfigChange('password')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.password`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.password`, { ns: 'app' }) })!}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
{type === TracingProvider.databricks && (
|
||||
<>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.experimentId`)!}
|
||||
label={t(`${I18N_PREFIX}.experimentId`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as DatabricksConfig).experiment_id}
|
||||
onChange={handleConfigChange('experiment_id')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.experimentId`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.experimentId`, { ns: 'app' }) })!}
|
||||
isRequired
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.databricksHost`)!}
|
||||
label={t(`${I18N_PREFIX}.databricksHost`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as DatabricksConfig).host}
|
||||
onChange={handleConfigChange('host')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.databricksHost`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.databricksHost`, { ns: 'app' }) })!}
|
||||
isRequired
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.clientId`)!}
|
||||
label={t(`${I18N_PREFIX}.clientId`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as DatabricksConfig).client_id}
|
||||
onChange={handleConfigChange('client_id')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.clientId`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.clientId`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.clientSecret`)!}
|
||||
label={t(`${I18N_PREFIX}.clientSecret`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as DatabricksConfig).client_secret}
|
||||
onChange={handleConfigChange('client_secret')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.clientSecret`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.clientSecret`, { ns: 'app' }) })!}
|
||||
/>
|
||||
<Field
|
||||
label={t(`${I18N_PREFIX}.personalAccessToken`)!}
|
||||
label={t(`${I18N_PREFIX}.personalAccessToken`, { ns: 'app' })!}
|
||||
labelClassName="!text-sm"
|
||||
value={(config as DatabricksConfig).personal_access_token}
|
||||
onChange={handleConfigChange('personal_access_token')}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: t(`${I18N_PREFIX}.personalAccessToken`) })!}
|
||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: t(`${I18N_PREFIX}.personalAccessToken`, { ns: 'app' }) })!}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
|
@ -634,7 +634,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
target="_blank"
|
||||
href={docURL[type]}
|
||||
>
|
||||
<span>{t(`${I18N_PREFIX}.viewDocsLink`, { key: t(`app.tracing.${type}.title`) })}</span>
|
||||
<span>{t(`${I18N_PREFIX}.viewDocsLink`, { ns: 'app', key: t(`tracing.${type}.title`, { ns: 'app' }) })}</span>
|
||||
<LinkExternal02 className="h-3 w-3" />
|
||||
</a>
|
||||
<div className="flex items-center">
|
||||
|
|
@ -644,7 +644,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
className="h-9 text-sm font-medium text-text-secondary"
|
||||
onClick={showRemoveConfirm}
|
||||
>
|
||||
<span className="text-[#D92D20]">{t('common.operation.remove')}</span>
|
||||
<span className="text-[#D92D20]">{t('operation.remove', { ns: 'common' })}</span>
|
||||
</Button>
|
||||
<Divider type="vertical" className="mx-3 h-[18px]" />
|
||||
</>
|
||||
|
|
@ -653,7 +653,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
className="mr-2 h-9 text-sm font-medium text-text-secondary"
|
||||
onClick={onCancel}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
className="h-9 text-sm font-medium"
|
||||
|
|
@ -661,7 +661,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
onClick={handleSave}
|
||||
loading={isSaving}
|
||||
>
|
||||
{t(`common.operation.${isAdd ? 'saveAndEnable' : 'save'}`)}
|
||||
{t(`operation.${isAdd ? 'saveAndEnable' : 'save'}`, { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
|
|
@ -670,7 +670,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
<div className="border-t-[0.5px] border-divider-regular">
|
||||
<div className="flex items-center justify-center bg-background-section-burn py-3 text-xs text-text-tertiary">
|
||||
<Lock01 className="mr-1 h-3 w-3 text-text-tertiary" />
|
||||
{t('common.modelProvider.encrypted.front')}
|
||||
{t('modelProvider.encrypted.front', { ns: 'common' })}
|
||||
<a
|
||||
className="mx-1 text-primary-600"
|
||||
target="_blank"
|
||||
|
|
@ -679,7 +679,7 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
>
|
||||
PKCS1_OAEP
|
||||
</a>
|
||||
{t('common.modelProvider.encrypted.back')}
|
||||
{t('modelProvider.encrypted.back', { ns: 'common' })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -691,8 +691,8 @@ const ProviderConfigModal: FC<Props> = ({
|
|||
<Confirm
|
||||
isShow
|
||||
type="warning"
|
||||
title={t(`${I18N_PREFIX}.removeConfirmTitle`, { key: t(`app.tracing.${type}.title`) })!}
|
||||
content={t(`${I18N_PREFIX}.removeConfirmContent`)}
|
||||
title={t(`${I18N_PREFIX}.removeConfirmTitle`, { ns: 'app', key: t(`tracing.${type}.title`, { ns: 'app' }) })!}
|
||||
content={t(`${I18N_PREFIX}.removeConfirmContent`, { ns: 'app' })}
|
||||
onConfirm={handleRemove}
|
||||
onCancel={hideRemoveConfirm}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { Eye as View } from '@/app/components/base/icons/src/vender/solid/genera
|
|||
import { cn } from '@/utils/classnames'
|
||||
import { TracingProvider } from './type'
|
||||
|
||||
const I18N_PREFIX = 'app.tracing'
|
||||
const I18N_PREFIX = 'tracing'
|
||||
|
||||
type Props = {
|
||||
type: TracingProvider
|
||||
|
|
@ -82,14 +82,14 @@ const ProviderPanel: FC<Props> = ({
|
|||
<div className="flex items-center justify-between space-x-1">
|
||||
<div className="flex items-center">
|
||||
<Icon className="h-6" />
|
||||
{isChosen && <div className="system-2xs-medium-uppercase ml-1 flex h-4 items-center rounded-[4px] border border-text-accent-secondary px-1 text-text-accent-secondary">{t(`${I18N_PREFIX}.inUse`)}</div>}
|
||||
{isChosen && <div className="system-2xs-medium-uppercase ml-1 flex h-4 items-center rounded-[4px] border border-text-accent-secondary px-1 text-text-accent-secondary">{t(`${I18N_PREFIX}.inUse`, { ns: 'app' })}</div>}
|
||||
</div>
|
||||
{!readOnly && (
|
||||
<div className="flex items-center justify-between space-x-1">
|
||||
{hasConfigured && (
|
||||
<div className="flex h-6 cursor-pointer items-center space-x-1 rounded-md border-[0.5px] border-components-button-secondary-border bg-components-button-secondary-bg px-2 text-text-secondary shadow-xs" onClick={viewBtnClick}>
|
||||
<View className="h-3 w-3" />
|
||||
<div className="text-xs font-medium">{t(`${I18N_PREFIX}.view`)}</div>
|
||||
<div className="text-xs font-medium">{t(`${I18N_PREFIX}.view`, { ns: 'app' })}</div>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
|
|
@ -97,13 +97,13 @@ const ProviderPanel: FC<Props> = ({
|
|||
onClick={handleConfigBtnClick}
|
||||
>
|
||||
<RiEqualizer2Line className="h-3 w-3" />
|
||||
<div className="text-xs font-medium">{t(`${I18N_PREFIX}.config`)}</div>
|
||||
<div className="text-xs font-medium">{t(`${I18N_PREFIX}.config`, { ns: 'app' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="system-xs-regular mt-2 text-text-tertiary">
|
||||
{t(`${I18N_PREFIX}.${type}.description`)}
|
||||
{t(`${I18N_PREFIX}.${type}.description`, { ns: 'app' })}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ const AppDetail: FC<IAppDetail> = ({ children }) => {
|
|||
const router = useRouter()
|
||||
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||
const { t } = useTranslation()
|
||||
useDocumentTitle(t('common.menus.appDetail'))
|
||||
useDocumentTitle(t('menus.appDetail', { ns: 'common' }))
|
||||
|
||||
useEffect(() => {
|
||||
if (isCurrentWorkspaceDatasetOperator)
|
||||
|
|
|
|||
|
|
@ -70,14 +70,14 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||
const navigation = useMemo(() => {
|
||||
const baseNavigation = [
|
||||
{
|
||||
name: t('common.datasetMenus.hitTesting'),
|
||||
name: t('datasetMenus.hitTesting', { ns: 'common' }),
|
||||
href: `/datasets/${datasetId}/hitTesting`,
|
||||
icon: RiFocus2Line,
|
||||
selectedIcon: RiFocus2Fill,
|
||||
disabled: isButtonDisabledWithPipeline,
|
||||
},
|
||||
{
|
||||
name: t('common.datasetMenus.settings'),
|
||||
name: t('datasetMenus.settings', { ns: 'common' }),
|
||||
href: `/datasets/${datasetId}/settings`,
|
||||
icon: RiEqualizer2Line,
|
||||
selectedIcon: RiEqualizer2Fill,
|
||||
|
|
@ -87,14 +87,14 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||
|
||||
if (datasetRes?.provider !== 'external') {
|
||||
baseNavigation.unshift({
|
||||
name: t('common.datasetMenus.pipeline'),
|
||||
name: t('datasetMenus.pipeline', { ns: 'common' }),
|
||||
href: `/datasets/${datasetId}/pipeline`,
|
||||
icon: PipelineLine as RemixiconComponentType,
|
||||
selectedIcon: PipelineFill as RemixiconComponentType,
|
||||
disabled: false,
|
||||
})
|
||||
baseNavigation.unshift({
|
||||
name: t('common.datasetMenus.documents'),
|
||||
name: t('datasetMenus.documents', { ns: 'common' }),
|
||||
href: `/datasets/${datasetId}/documents`,
|
||||
icon: RiFileTextLine,
|
||||
selectedIcon: RiFileTextFill,
|
||||
|
|
@ -105,7 +105,7 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
|||
return baseNavigation
|
||||
}, [t, datasetId, isButtonDisabledWithPipeline, datasetRes?.provider])
|
||||
|
||||
useDocumentTitle(datasetRes?.name || t('common.menus.datasets'))
|
||||
useDocumentTitle(datasetRes?.name || t('menus.datasets', { ns: 'common' }))
|
||||
|
||||
const setAppSidebarExpand = useStore(state => state.setAppSidebarExpand)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
/* eslint-disable dify-i18n/require-ns-option */
|
||||
import * as React from 'react'
|
||||
import Form from '@/app/components/datasets/settings/form'
|
||||
import { getLocaleOnServer, getTranslation } from '@/i18n-config/server'
|
||||
|
|
@ -9,7 +10,7 @@ const Settings = async () => {
|
|||
return (
|
||||
<div className="h-full overflow-y-auto">
|
||||
<div className="flex flex-col gap-y-0.5 px-6 pb-2 pt-3">
|
||||
<div className="system-xl-semibold text-text-primary">{t('title') as any}</div>
|
||||
<div className="system-xl-semibold text-text-primary">{t('title')}</div>
|
||||
<div className="system-sm-regular text-text-tertiary">{t('desc')}</div>
|
||||
</div>
|
||||
<Form />
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ import useDocumentTitle from '@/hooks/use-document-title'
|
|||
|
||||
const ExploreLayout: FC<PropsWithChildren> = ({ children }) => {
|
||||
const { t } = useTranslation()
|
||||
useDocumentTitle(t('common.menus.explore'))
|
||||
useDocumentTitle(t('menus.explore', { ns: 'common' }))
|
||||
return (
|
||||
<ExploreClient>
|
||||
{children}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ const ToolsList: FC = () => {
|
|||
const router = useRouter()
|
||||
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||
const { t } = useTranslation()
|
||||
useDocumentTitle(t('common.menus.tools'))
|
||||
useDocumentTitle(t('menus.tools', { ns: 'common' }))
|
||||
|
||||
useEffect(() => {
|
||||
if (isCurrentWorkspaceDatasetOperator)
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ const AuthenticatedLayout = ({ children }: { children: React.ReactNode }) => {
|
|||
return (
|
||||
<div className="flex h-full flex-col items-center justify-center gap-y-2">
|
||||
<AppUnavailable className="h-auto w-auto" code={403} unknownReason="no permission." />
|
||||
<span className="system-sm-regular cursor-pointer text-text-tertiary" onClick={backToHome}>{t('common.userProfile.logout')}</span>
|
||||
<span className="system-sm-regular cursor-pointer text-text-tertiary" onClick={backToHome}>{t('userProfile.logout', { ns: 'common' })}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -94,8 +94,8 @@ const Splash: FC<PropsWithChildren> = ({ children }) => {
|
|||
if (message) {
|
||||
return (
|
||||
<div className="flex h-full flex-col items-center justify-center gap-y-4">
|
||||
<AppUnavailable className="h-auto w-auto" code={code || t('share.common.appUnavailable')} unknownReason={message} />
|
||||
<span className="system-sm-regular cursor-pointer text-text-tertiary" onClick={backToHome}>{code === '403' ? t('common.userProfile.logout') : t('share.login.backToHome')}</span>
|
||||
<AppUnavailable className="h-auto w-auto" code={code || t('common.appUnavailable', { ns: 'share' })} unknownReason={message} />
|
||||
<span className="system-sm-regular cursor-pointer text-text-tertiary" onClick={backToHome}>{code === '403' ? t('userProfile.logout', { ns: 'common' }) : t('login.backToHome', { ns: 'share' })}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,14 +26,14 @@ export default function CheckCode() {
|
|||
if (!code.trim()) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.checkCode.emptyCode'),
|
||||
message: t('checkCode.emptyCode', { ns: 'login' }),
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!/\d{6}/.test(code)) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.checkCode.invalidCode'),
|
||||
message: t('checkCode.invalidCode', { ns: 'login' }),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
@ -69,22 +69,22 @@ export default function CheckCode() {
|
|||
<RiMailSendFill className="h-6 w-6 text-2xl" />
|
||||
</div>
|
||||
<div className="pb-4 pt-2">
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">{t('login.checkCode.checkYourEmail')}</h2>
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">{t('checkCode.checkYourEmail', { ns: 'login' })}</h2>
|
||||
<p className="body-md-regular mt-2 text-text-secondary">
|
||||
<span>
|
||||
{t('login.checkCode.tipsPrefix')}
|
||||
{t('checkCode.tipsPrefix', { ns: 'login' })}
|
||||
<strong>{email}</strong>
|
||||
</span>
|
||||
<br />
|
||||
{t('login.checkCode.validTime')}
|
||||
{t('checkCode.validTime', { ns: 'login' })}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form action="">
|
||||
<input type="text" className="hidden" />
|
||||
<label htmlFor="code" className="system-md-semibold mb-1 text-text-secondary">{t('login.checkCode.verificationCode')}</label>
|
||||
<Input value={code} onChange={e => setVerifyCode(e.target.value)} maxLength={6} className="mt-1" placeholder={t('login.checkCode.verificationCodePlaceholder') || ''} />
|
||||
<Button loading={loading} disabled={loading} className="my-3 w-full" variant="primary" onClick={verify}>{t('login.checkCode.verify')}</Button>
|
||||
<label htmlFor="code" className="system-md-semibold mb-1 text-text-secondary">{t('checkCode.verificationCode', { ns: 'login' })}</label>
|
||||
<Input value={code} onChange={e => setVerifyCode(e.target.value)} maxLength={6} className="mt-1" placeholder={t('checkCode.verificationCodePlaceholder', { ns: 'login' }) || ''} />
|
||||
<Button loading={loading} disabled={loading} className="my-3 w-full" variant="primary" onClick={verify}>{t('checkCode.verify', { ns: 'login' })}</Button>
|
||||
<Countdown onResend={resendCode} />
|
||||
</form>
|
||||
<div className="py-2">
|
||||
|
|
@ -94,7 +94,7 @@ export default function CheckCode() {
|
|||
<div className="bg-background-default-dimm inline-block rounded-full p-1">
|
||||
<RiArrowLeftLine size={12} />
|
||||
</div>
|
||||
<span className="system-xs-regular ml-2">{t('login.back')}</span>
|
||||
<span className="system-xs-regular ml-2">{t('back', { ns: 'login' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -27,14 +27,14 @@ export default function CheckCode() {
|
|||
const handleGetEMailVerificationCode = async () => {
|
||||
try {
|
||||
if (!email) {
|
||||
Toast.notify({ type: 'error', message: t('login.error.emailEmpty') })
|
||||
Toast.notify({ type: 'error', message: t('error.emailEmpty', { ns: 'login' }) })
|
||||
return
|
||||
}
|
||||
|
||||
if (!emailRegex.test(email)) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.error.emailInValid'),
|
||||
message: t('error.emailInValid', { ns: 'login' }),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
@ -50,7 +50,7 @@ export default function CheckCode() {
|
|||
else if (res.code === 'account_not_found') {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.error.registrationNotAllowed'),
|
||||
message: t('error.registrationNotAllowed', { ns: 'login' }),
|
||||
})
|
||||
}
|
||||
else {
|
||||
|
|
@ -74,21 +74,21 @@ export default function CheckCode() {
|
|||
<RiLockPasswordLine className="h-6 w-6 text-2xl text-text-accent-light-mode-only" />
|
||||
</div>
|
||||
<div className="pb-4 pt-2">
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">{t('login.resetPassword')}</h2>
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">{t('resetPassword', { ns: 'login' })}</h2>
|
||||
<p className="body-md-regular mt-2 text-text-secondary">
|
||||
{t('login.resetPasswordDesc')}
|
||||
{t('resetPasswordDesc', { ns: 'login' })}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={noop}>
|
||||
<input type="text" className="hidden" />
|
||||
<div className="mb-2">
|
||||
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">{t('login.email')}</label>
|
||||
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">{t('email', { ns: 'login' })}</label>
|
||||
<div className="mt-1">
|
||||
<Input id="email" type="email" disabled={loading} value={email} placeholder={t('login.emailPlaceholder') as string} onChange={e => setEmail(e.target.value)} />
|
||||
<Input id="email" type="email" disabled={loading} value={email} placeholder={t('emailPlaceholder', { ns: 'login' }) as string} onChange={e => setEmail(e.target.value)} />
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<Button loading={loading} disabled={loading} variant="primary" className="w-full" onClick={handleGetEMailVerificationCode}>{t('login.sendVerificationCode')}</Button>
|
||||
<Button loading={loading} disabled={loading} variant="primary" className="w-full" onClick={handleGetEMailVerificationCode}>{t('sendVerificationCode', { ns: 'login' })}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -99,7 +99,7 @@ export default function CheckCode() {
|
|||
<div className="inline-block rounded-full bg-background-default-dimmed p-1">
|
||||
<RiArrowLeftLine size={12} />
|
||||
</div>
|
||||
<span className="system-xs-regular ml-2">{t('login.backToLogin')}</span>
|
||||
<span className="system-xs-regular ml-2">{t('backToLogin', { ns: 'login' })}</span>
|
||||
</Link>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -45,15 +45,15 @@ const ChangePasswordForm = () => {
|
|||
|
||||
const valid = useCallback(() => {
|
||||
if (!password.trim()) {
|
||||
showErrorMessage(t('login.error.passwordEmpty'))
|
||||
showErrorMessage(t('error.passwordEmpty', { ns: 'login' }))
|
||||
return false
|
||||
}
|
||||
if (!validPassword.test(password)) {
|
||||
showErrorMessage(t('login.error.passwordInvalid'))
|
||||
showErrorMessage(t('error.passwordInvalid', { ns: 'login' }))
|
||||
return false
|
||||
}
|
||||
if (password !== confirmPassword) {
|
||||
showErrorMessage(t('common.account.notEqual'))
|
||||
showErrorMessage(t('account.notEqual', { ns: 'common' }))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
|
@ -92,10 +92,10 @@ const ChangePasswordForm = () => {
|
|||
<div className="flex flex-col md:w-[400px]">
|
||||
<div className="mx-auto w-full">
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">
|
||||
{t('login.changePassword')}
|
||||
{t('changePassword', { ns: 'login' })}
|
||||
</h2>
|
||||
<p className="body-md-regular mt-2 text-text-secondary">
|
||||
{t('login.changePasswordTip')}
|
||||
{t('changePasswordTip', { ns: 'login' })}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
@ -104,7 +104,7 @@ const ChangePasswordForm = () => {
|
|||
{/* Password */}
|
||||
<div className="mb-5">
|
||||
<label htmlFor="password" className="system-md-semibold my-2 text-text-secondary">
|
||||
{t('common.account.newPassword')}
|
||||
{t('account.newPassword', { ns: 'common' })}
|
||||
</label>
|
||||
<div className="relative mt-1">
|
||||
<Input
|
||||
|
|
@ -112,7 +112,7 @@ const ChangePasswordForm = () => {
|
|||
type={showPassword ? 'text' : 'password'}
|
||||
value={password}
|
||||
onChange={e => setPassword(e.target.value)}
|
||||
placeholder={t('login.passwordPlaceholder') || ''}
|
||||
placeholder={t('passwordPlaceholder', { ns: 'login' }) || ''}
|
||||
/>
|
||||
|
||||
<div className="absolute inset-y-0 right-0 flex items-center">
|
||||
|
|
@ -125,12 +125,12 @@ const ChangePasswordForm = () => {
|
|||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="body-xs-regular mt-1 text-text-secondary">{t('login.error.passwordInvalid')}</div>
|
||||
<div className="body-xs-regular mt-1 text-text-secondary">{t('error.passwordInvalid', { ns: 'login' })}</div>
|
||||
</div>
|
||||
{/* Confirm Password */}
|
||||
<div className="mb-5">
|
||||
<label htmlFor="confirmPassword" className="system-md-semibold my-2 text-text-secondary">
|
||||
{t('common.account.confirmPassword')}
|
||||
{t('account.confirmPassword', { ns: 'common' })}
|
||||
</label>
|
||||
<div className="relative mt-1">
|
||||
<Input
|
||||
|
|
@ -138,7 +138,7 @@ const ChangePasswordForm = () => {
|
|||
type={showConfirmPassword ? 'text' : 'password'}
|
||||
value={confirmPassword}
|
||||
onChange={e => setConfirmPassword(e.target.value)}
|
||||
placeholder={t('login.confirmPasswordPlaceholder') || ''}
|
||||
placeholder={t('confirmPasswordPlaceholder', { ns: 'login' }) || ''}
|
||||
/>
|
||||
<div className="absolute inset-y-0 right-0 flex items-center">
|
||||
<Button
|
||||
|
|
@ -157,7 +157,7 @@ const ChangePasswordForm = () => {
|
|||
className="w-full"
|
||||
onClick={handleChangePassword}
|
||||
>
|
||||
{t('login.changePasswordBtn')}
|
||||
{t('changePasswordBtn', { ns: 'login' })}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -171,7 +171,7 @@ const ChangePasswordForm = () => {
|
|||
<RiCheckboxCircleFill className="h-6 w-6 text-text-success" />
|
||||
</div>
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">
|
||||
{t('login.passwordChangedTip')}
|
||||
{t('passwordChangedTip', { ns: 'login' })}
|
||||
</h2>
|
||||
</div>
|
||||
<div className="mx-auto mt-6 w-full">
|
||||
|
|
@ -183,7 +183,7 @@ const ChangePasswordForm = () => {
|
|||
router.replace(getSignInUrl())
|
||||
}}
|
||||
>
|
||||
{t('login.passwordChanged')}
|
||||
{t('passwordChanged', { ns: 'login' })}
|
||||
{' '}
|
||||
(
|
||||
{Math.round(countdown / 1000)}
|
||||
|
|
|
|||
|
|
@ -45,21 +45,21 @@ export default function CheckCode() {
|
|||
if (!code.trim()) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.checkCode.emptyCode'),
|
||||
message: t('checkCode.emptyCode', { ns: 'login' }),
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!/\d{6}/.test(code)) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.checkCode.invalidCode'),
|
||||
message: t('checkCode.invalidCode', { ns: 'login' }),
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!redirectUrl || !appCode) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.error.redirectUrlMissing'),
|
||||
message: t('error.redirectUrlMissing', { ns: 'login' }),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
@ -108,19 +108,19 @@ export default function CheckCode() {
|
|||
<RiMailSendFill className="h-6 w-6 text-2xl text-text-accent-light-mode-only" />
|
||||
</div>
|
||||
<div className="pb-4 pt-2">
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">{t('login.checkCode.checkYourEmail')}</h2>
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">{t('checkCode.checkYourEmail', { ns: 'login' })}</h2>
|
||||
<p className="body-md-regular mt-2 text-text-secondary">
|
||||
<span>
|
||||
{t('login.checkCode.tipsPrefix')}
|
||||
{t('checkCode.tipsPrefix', { ns: 'login' })}
|
||||
<strong>{email}</strong>
|
||||
</span>
|
||||
<br />
|
||||
{t('login.checkCode.validTime')}
|
||||
{t('checkCode.validTime', { ns: 'login' })}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit}>
|
||||
<label htmlFor="code" className="system-md-semibold mb-1 text-text-secondary">{t('login.checkCode.verificationCode')}</label>
|
||||
<label htmlFor="code" className="system-md-semibold mb-1 text-text-secondary">{t('checkCode.verificationCode', { ns: 'login' })}</label>
|
||||
<Input
|
||||
ref={codeInputRef}
|
||||
id="code"
|
||||
|
|
@ -128,9 +128,9 @@ export default function CheckCode() {
|
|||
onChange={e => setVerifyCode(e.target.value)}
|
||||
maxLength={6}
|
||||
className="mt-1"
|
||||
placeholder={t('login.checkCode.verificationCodePlaceholder') || ''}
|
||||
placeholder={t('checkCode.verificationCodePlaceholder', { ns: 'login' }) || ''}
|
||||
/>
|
||||
<Button type="submit" loading={loading} disabled={loading} className="my-3 w-full" variant="primary">{t('login.checkCode.verify')}</Button>
|
||||
<Button type="submit" loading={loading} disabled={loading} className="my-3 w-full" variant="primary">{t('checkCode.verify', { ns: 'login' })}</Button>
|
||||
<Countdown onResend={resendCode} />
|
||||
</form>
|
||||
<div className="py-2">
|
||||
|
|
@ -140,7 +140,7 @@ export default function CheckCode() {
|
|||
<div className="bg-background-default-dimm inline-block rounded-full p-1">
|
||||
<RiArrowLeftLine size={12} />
|
||||
</div>
|
||||
<span className="system-xs-regular ml-2">{t('login.back')}</span>
|
||||
<span className="system-xs-regular ml-2">{t('back', { ns: 'login' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -23,14 +23,14 @@ export default function MailAndCodeAuth() {
|
|||
const handleGetEMailVerificationCode = async () => {
|
||||
try {
|
||||
if (!email) {
|
||||
Toast.notify({ type: 'error', message: t('login.error.emailEmpty') })
|
||||
Toast.notify({ type: 'error', message: t('error.emailEmpty', { ns: 'login' }) })
|
||||
return
|
||||
}
|
||||
|
||||
if (!emailRegex.test(email)) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.error.emailInValid'),
|
||||
message: t('error.emailInValid', { ns: 'login' }),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
@ -56,12 +56,12 @@ export default function MailAndCodeAuth() {
|
|||
<form onSubmit={noop}>
|
||||
<input type="text" className="hidden" />
|
||||
<div className="mb-2">
|
||||
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">{t('login.email')}</label>
|
||||
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">{t('email', { ns: 'login' })}</label>
|
||||
<div className="mt-1">
|
||||
<Input id="email" type="email" value={email} placeholder={t('login.emailPlaceholder') as string} onChange={e => setEmail(e.target.value)} />
|
||||
<Input id="email" type="email" value={email} placeholder={t('emailPlaceholder', { ns: 'login' }) as string} onChange={e => setEmail(e.target.value)} />
|
||||
</div>
|
||||
<div className="mt-3">
|
||||
<Button loading={loading} disabled={loading || !email} variant="primary" className="w-full" onClick={handleGetEMailVerificationCode}>{t('login.signup.verifyMail')}</Button>
|
||||
<Button loading={loading} disabled={loading || !email} variant="primary" className="w-full" onClick={handleGetEMailVerificationCode}>{t('signup.verifyMail', { ns: 'login' })}</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -46,25 +46,25 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
|||
const appCode = getAppCodeFromRedirectUrl()
|
||||
const handleEmailPasswordLogin = async () => {
|
||||
if (!email) {
|
||||
Toast.notify({ type: 'error', message: t('login.error.emailEmpty') })
|
||||
Toast.notify({ type: 'error', message: t('error.emailEmpty', { ns: 'login' }) })
|
||||
return
|
||||
}
|
||||
if (!emailRegex.test(email)) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.error.emailInValid'),
|
||||
message: t('error.emailInValid', { ns: 'login' }),
|
||||
})
|
||||
return
|
||||
}
|
||||
if (!password?.trim()) {
|
||||
Toast.notify({ type: 'error', message: t('login.error.passwordEmpty') })
|
||||
Toast.notify({ type: 'error', message: t('error.passwordEmpty', { ns: 'login' }) })
|
||||
return
|
||||
}
|
||||
|
||||
if (!redirectUrl || !appCode) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: t('login.error.redirectUrlMissing'),
|
||||
message: t('error.redirectUrlMissing', { ns: 'login' }),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
|
@ -111,7 +111,7 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
|||
<form onSubmit={noop}>
|
||||
<div className="mb-3">
|
||||
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">
|
||||
{t('login.email')}
|
||||
{t('email', { ns: 'login' })}
|
||||
</label>
|
||||
<div className="mt-1">
|
||||
<Input
|
||||
|
|
@ -120,7 +120,7 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
|||
id="email"
|
||||
type="email"
|
||||
autoComplete="email"
|
||||
placeholder={t('login.emailPlaceholder') || ''}
|
||||
placeholder={t('emailPlaceholder', { ns: 'login' }) || ''}
|
||||
tabIndex={1}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -128,14 +128,14 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
|||
|
||||
<div className="mb-3">
|
||||
<label htmlFor="password" className="my-2 flex items-center justify-between">
|
||||
<span className="system-md-semibold text-text-secondary">{t('login.password')}</span>
|
||||
<span className="system-md-semibold text-text-secondary">{t('password', { ns: 'login' })}</span>
|
||||
<Link
|
||||
href={`/webapp-reset-password?${searchParams.toString()}`}
|
||||
className={`system-xs-regular ${isEmailSetup ? 'text-components-button-secondary-accent-text' : 'pointer-events-none text-components-button-secondary-accent-text-disabled'}`}
|
||||
tabIndex={isEmailSetup ? 0 : -1}
|
||||
aria-disabled={!isEmailSetup}
|
||||
>
|
||||
{t('login.forget')}
|
||||
{t('forget', { ns: 'login' })}
|
||||
</Link>
|
||||
</label>
|
||||
<div className="relative mt-1">
|
||||
|
|
@ -149,7 +149,7 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
|||
}}
|
||||
type={showPassword ? 'text' : 'password'}
|
||||
autoComplete="current-password"
|
||||
placeholder={t('login.passwordPlaceholder') || ''}
|
||||
placeholder={t('passwordPlaceholder', { ns: 'login' }) || ''}
|
||||
tabIndex={2}
|
||||
/>
|
||||
<div className="absolute inset-y-0 right-0 flex items-center">
|
||||
|
|
@ -172,7 +172,7 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
|||
disabled={isLoading || !email || !password}
|
||||
className="w-full"
|
||||
>
|
||||
{t('login.signBtn')}
|
||||
{t('signBtn', { ns: 'login' })}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -82,7 +82,7 @@ const SSOAuth: FC<SSOAuthProps> = ({
|
|||
className="w-full"
|
||||
>
|
||||
<Lock01 className="mr-2 h-5 w-5 text-text-accent-light-mode-only" />
|
||||
<span className="truncate">{t('login.withSSO')}</span>
|
||||
<span className="truncate">{t('withSSO', { ns: 'login' })}</span>
|
||||
</Button>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ import { cn } from '@/utils/classnames'
|
|||
export default function SignInLayout({ children }: PropsWithChildren) {
|
||||
const { t } = useTranslation()
|
||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||
useDocumentTitle(t('login.webapp.login'))
|
||||
useDocumentTitle(t('webapp.login', { ns: 'login' }))
|
||||
return (
|
||||
<>
|
||||
<div className={cn('flex min-h-screen w-full justify-center bg-background-default-burn p-6')}>
|
||||
|
|
|
|||
|
|
@ -60,8 +60,8 @@ const NormalForm = () => {
|
|||
<RiContractLine className="h-5 w-5" />
|
||||
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
|
||||
</div>
|
||||
<p className="system-sm-medium text-text-primary">{t('login.licenseLost')}</p>
|
||||
<p className="system-xs-regular mt-1 text-text-tertiary">{t('login.licenseLostTip')}</p>
|
||||
<p className="system-sm-medium text-text-primary">{t('licenseLost', { ns: 'login' })}</p>
|
||||
<p className="system-xs-regular mt-1 text-text-tertiary">{t('licenseLostTip', { ns: 'login' })}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -76,8 +76,8 @@ const NormalForm = () => {
|
|||
<RiContractLine className="h-5 w-5" />
|
||||
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
|
||||
</div>
|
||||
<p className="system-sm-medium text-text-primary">{t('login.licenseExpired')}</p>
|
||||
<p className="system-xs-regular mt-1 text-text-tertiary">{t('login.licenseExpiredTip')}</p>
|
||||
<p className="system-sm-medium text-text-primary">{t('licenseExpired', { ns: 'login' })}</p>
|
||||
<p className="system-xs-regular mt-1 text-text-tertiary">{t('licenseExpiredTip', { ns: 'login' })}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -92,8 +92,8 @@ const NormalForm = () => {
|
|||
<RiContractLine className="h-5 w-5" />
|
||||
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
|
||||
</div>
|
||||
<p className="system-sm-medium text-text-primary">{t('login.licenseInactive')}</p>
|
||||
<p className="system-xs-regular mt-1 text-text-tertiary">{t('login.licenseInactiveTip')}</p>
|
||||
<p className="system-sm-medium text-text-primary">{t('licenseInactive', { ns: 'login' })}</p>
|
||||
<p className="system-xs-regular mt-1 text-text-tertiary">{t('licenseInactiveTip', { ns: 'login' })}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -104,8 +104,8 @@ const NormalForm = () => {
|
|||
<>
|
||||
<div className="mx-auto mt-8 w-full">
|
||||
<div className="mx-auto w-full">
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">{systemFeatures.branding.enabled ? t('login.pageTitleForE') : t('login.pageTitle')}</h2>
|
||||
<p className="body-md-regular mt-2 text-text-tertiary">{t('login.welcome')}</p>
|
||||
<h2 className="title-4xl-semi-bold text-text-primary">{systemFeatures.branding.enabled ? t('pageTitleForE', { ns: 'login' }) : t('pageTitle', { ns: 'login' })}</h2>
|
||||
<p className="body-md-regular mt-2 text-text-tertiary">{t('welcome', { ns: 'login' })}</p>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="mt-6 flex flex-col gap-3">
|
||||
|
|
@ -122,7 +122,7 @@ const NormalForm = () => {
|
|||
<div className="h-px w-full bg-gradient-to-r from-background-gradient-mask-transparent via-divider-regular to-background-gradient-mask-transparent"></div>
|
||||
</div>
|
||||
<div className="relative flex justify-center">
|
||||
<span className="system-xs-medium-uppercase px-2 text-text-tertiary">{t('login.or')}</span>
|
||||
<span className="system-xs-medium-uppercase px-2 text-text-tertiary">{t('or', { ns: 'login' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
|
@ -134,7 +134,7 @@ const NormalForm = () => {
|
|||
<MailAndCodeAuth />
|
||||
{systemFeatures.enable_email_password_login && (
|
||||
<div className="cursor-pointer py-1 text-center" onClick={() => { updateAuthType('password') }}>
|
||||
<span className="system-xs-medium text-components-button-secondary-accent-text">{t('login.usePassword')}</span>
|
||||
<span className="system-xs-medium text-components-button-secondary-accent-text">{t('usePassword', { ns: 'login' })}</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
|
@ -144,7 +144,7 @@ const NormalForm = () => {
|
|||
<MailAndPasswordAuth isEmailSetup={systemFeatures.is_email_setup} />
|
||||
{systemFeatures.enable_email_code_login && (
|
||||
<div className="cursor-pointer py-1 text-center" onClick={() => { updateAuthType('code') }}>
|
||||
<span className="system-xs-medium text-components-button-secondary-accent-text">{t('login.useVerificationCode')}</span>
|
||||
<span className="system-xs-medium text-components-button-secondary-accent-text">{t('useVerificationCode', { ns: 'login' })}</span>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
|
@ -158,8 +158,8 @@ const NormalForm = () => {
|
|||
<div className="shadows-shadow-lg mb-2 flex h-10 w-10 items-center justify-center rounded-xl bg-components-card-bg shadow">
|
||||
<RiDoorLockLine className="h-5 w-5" />
|
||||
</div>
|
||||
<p className="system-sm-medium text-text-primary">{t('login.noLoginMethod')}</p>
|
||||
<p className="system-xs-regular mt-1 text-text-tertiary">{t('login.noLoginMethodTip')}</p>
|
||||
<p className="system-sm-medium text-text-primary">{t('noLoginMethod', { ns: 'login' })}</p>
|
||||
<p className="system-xs-regular mt-1 text-text-tertiary">{t('noLoginMethodTip', { ns: 'login' })}</p>
|
||||
</div>
|
||||
<div className="relative my-2 py-2">
|
||||
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
||||
|
|
@ -171,7 +171,7 @@ const NormalForm = () => {
|
|||
{!systemFeatures.branding.enabled && (
|
||||
<>
|
||||
<div className="system-xs-regular mt-2 block w-full text-text-tertiary">
|
||||
{t('login.tosDesc')}
|
||||
{t('tosDesc', { ns: 'login' })}
|
||||
|
||||
<Link
|
||||
className="system-xs-medium text-text-secondary hover:underline"
|
||||
|
|
@ -179,7 +179,7 @@ const NormalForm = () => {
|
|||
rel="noopener noreferrer"
|
||||
href="https://dify.ai/terms"
|
||||
>
|
||||
{t('login.tos')}
|
||||
{t('tos', { ns: 'login' })}
|
||||
</Link>
|
||||
&
|
||||
<Link
|
||||
|
|
@ -188,18 +188,18 @@ const NormalForm = () => {
|
|||
rel="noopener noreferrer"
|
||||
href="https://dify.ai/privacy"
|
||||
>
|
||||
{t('login.pp')}
|
||||
{t('pp', { ns: 'login' })}
|
||||
</Link>
|
||||
</div>
|
||||
{IS_CE_EDITION && (
|
||||
<div className="w-hull system-xs-regular mt-2 block text-text-tertiary">
|
||||
{t('login.goToInit')}
|
||||
{t('goToInit', { ns: 'login' })}
|
||||
|
||||
<Link
|
||||
className="system-xs-medium text-text-secondary hover:underline"
|
||||
href="/install"
|
||||
>
|
||||
{t('login.setAdminAccount')}
|
||||
{t('setAdminAccount', { ns: 'login' })}
|
||||
</Link>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ const WebSSOForm: FC = () => {
|
|||
if (!redirectUrl) {
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<AppUnavailable code={t('share.common.appUnavailable')} unknownReason="redirect url is invalid." />
|
||||
<AppUnavailable code={t('common.appUnavailable', { ns: 'share' })} unknownReason="redirect url is invalid." />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -45,7 +45,7 @@ const WebSSOForm: FC = () => {
|
|||
if (!systemFeatures.webapp_auth.enabled) {
|
||||
return (
|
||||
<div className="flex h-full items-center justify-center">
|
||||
<p className="system-xs-regular text-text-tertiary">{t('login.webapp.disabled')}</p>
|
||||
<p className="system-xs-regular text-text-tertiary">{t('webapp.disabled', { ns: 'login' })}</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
@ -63,7 +63,7 @@ const WebSSOForm: FC = () => {
|
|||
return (
|
||||
<div className="flex h-full flex-col items-center justify-center gap-y-4">
|
||||
<AppUnavailable className="h-auto w-auto" isUnknownReason={true} />
|
||||
<span className="system-sm-regular cursor-pointer text-text-tertiary" onClick={backToHome}>{t('share.login.backToHome')}</span>
|
||||
<span className="system-sm-regular cursor-pointer text-text-tertiary" onClick={backToHome}>{t('login.backToHome', { ns: 'share' })}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
|
|||
await updateUserProfile({ url: 'account/avatar', body: { avatar: uploadedFileId } })
|
||||
setIsShowAvatarPicker(false)
|
||||
onSave?.()
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
notify({ type: 'success', message: t('actionMsg.modifiedSuccessfully', { ns: 'common' }) })
|
||||
}
|
||||
catch (e) {
|
||||
notify({ type: 'error', message: (e as Error).message })
|
||||
|
|
@ -58,7 +58,7 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
|
|||
const handleDeleteAvatar = useCallback(async () => {
|
||||
try {
|
||||
await updateUserProfile({ url: 'account/avatar', body: { avatar: '' } })
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
notify({ type: 'success', message: t('actionMsg.modifiedSuccessfully', { ns: 'common' }) })
|
||||
setIsShowDeleteConfirm(false)
|
||||
onSave?.()
|
||||
}
|
||||
|
|
@ -145,11 +145,11 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
|
|||
|
||||
<div className="flex w-full items-center justify-center gap-2 p-3">
|
||||
<Button className="w-full" onClick={() => setIsShowAvatarPicker(false)}>
|
||||
{t('app.iconPicker.cancel')}
|
||||
{t('iconPicker.cancel', { ns: 'app' })}
|
||||
</Button>
|
||||
|
||||
<Button variant="primary" className="w-full" disabled={uploading || !inputImageInfo} loading={uploading} onClick={handleSelect}>
|
||||
{t('app.iconPicker.ok')}
|
||||
{t('iconPicker.ok', { ns: 'app' })}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
@ -160,16 +160,16 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
|
|||
isShow={isShowDeleteConfirm}
|
||||
onClose={() => setIsShowDeleteConfirm(false)}
|
||||
>
|
||||
<div className="title-2xl-semi-bold mb-3 text-text-primary">{t('common.avatar.deleteTitle')}</div>
|
||||
<p className="mb-8 text-text-secondary">{t('common.avatar.deleteDescription')}</p>
|
||||
<div className="title-2xl-semi-bold mb-3 text-text-primary">{t('avatar.deleteTitle', { ns: 'common' })}</div>
|
||||
<p className="mb-8 text-text-secondary">{t('avatar.deleteDescription', { ns: 'common' })}</p>
|
||||
|
||||
<div className="flex w-full items-center justify-center gap-2">
|
||||
<Button className="w-full" onClick={() => setIsShowDeleteConfirm(false)}>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
|
||||
<Button variant="warning" className="w-full" onClick={handleDeleteAvatar}>
|
||||
{t('common.operation.delete')}
|
||||
{t('operation.delete', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
|
|||
|
|
@ -209,9 +209,9 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
|||
</div>
|
||||
{step === STEP.start && (
|
||||
<>
|
||||
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('common.account.changeEmail.title')}</div>
|
||||
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('account.changeEmail.title', { ns: 'common' })}</div>
|
||||
<div className="space-y-0.5 pb-2 pt-1">
|
||||
<div className="body-md-medium text-text-warning">{t('common.account.changeEmail.authTip')}</div>
|
||||
<div className="body-md-medium text-text-warning">{t('account.changeEmail.authTip', { ns: 'common' })}</div>
|
||||
<div className="body-md-regular text-text-secondary">
|
||||
<Trans
|
||||
i18nKey="common.account.changeEmail.content1"
|
||||
|
|
@ -227,20 +227,20 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
|||
variant="primary"
|
||||
onClick={sendCodeToOriginEmail}
|
||||
>
|
||||
{t('common.account.changeEmail.sendVerifyCode')}
|
||||
{t('account.changeEmail.sendVerifyCode', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
className="!w-full"
|
||||
onClick={onClose}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{step === STEP.verifyOrigin && (
|
||||
<>
|
||||
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('common.account.changeEmail.verifyEmail')}</div>
|
||||
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('account.changeEmail.verifyEmail', { ns: 'common' })}</div>
|
||||
<div className="space-y-0.5 pb-2 pt-1">
|
||||
<div className="body-md-regular text-text-secondary">
|
||||
<Trans
|
||||
|
|
@ -251,10 +251,10 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="pt-3">
|
||||
<div className="system-sm-medium mb-1 flex h-6 items-center text-text-secondary">{t('common.account.changeEmail.codeLabel')}</div>
|
||||
<div className="system-sm-medium mb-1 flex h-6 items-center text-text-secondary">{t('account.changeEmail.codeLabel', { ns: 'common' })}</div>
|
||||
<Input
|
||||
className="!w-full"
|
||||
placeholder={t('common.account.changeEmail.codePlaceholder')}
|
||||
placeholder={t('account.changeEmail.codePlaceholder', { ns: 'common' })}
|
||||
value={code}
|
||||
onChange={e => setCode(e.target.value)}
|
||||
maxLength={6}
|
||||
|
|
@ -267,46 +267,46 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
|||
variant="primary"
|
||||
onClick={handleVerifyOriginEmail}
|
||||
>
|
||||
{t('common.account.changeEmail.continue')}
|
||||
{t('account.changeEmail.continue', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
className="!w-full"
|
||||
onClick={onClose}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="system-xs-regular mt-3 flex items-center gap-1 text-text-tertiary">
|
||||
<span>{t('common.account.changeEmail.resendTip')}</span>
|
||||
<span>{t('account.changeEmail.resendTip', { ns: 'common' })}</span>
|
||||
{time > 0 && (
|
||||
<span>{t('common.account.changeEmail.resendCount', { count: time })}</span>
|
||||
<span>{t('account.changeEmail.resendCount', { ns: 'common', count: time })}</span>
|
||||
)}
|
||||
{!time && (
|
||||
<span onClick={sendCodeToOriginEmail} className="system-xs-medium cursor-pointer text-text-accent-secondary">{t('common.account.changeEmail.resend')}</span>
|
||||
<span onClick={sendCodeToOriginEmail} className="system-xs-medium cursor-pointer text-text-accent-secondary">{t('account.changeEmail.resend', { ns: 'common' })}</span>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{step === STEP.newEmail && (
|
||||
<>
|
||||
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('common.account.changeEmail.newEmail')}</div>
|
||||
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('account.changeEmail.newEmail', { ns: 'common' })}</div>
|
||||
<div className="space-y-0.5 pb-2 pt-1">
|
||||
<div className="body-md-regular text-text-secondary">{t('common.account.changeEmail.content3')}</div>
|
||||
<div className="body-md-regular text-text-secondary">{t('account.changeEmail.content3', { ns: 'common' })}</div>
|
||||
</div>
|
||||
<div className="pt-3">
|
||||
<div className="system-sm-medium mb-1 flex h-6 items-center text-text-secondary">{t('common.account.changeEmail.emailLabel')}</div>
|
||||
<div className="system-sm-medium mb-1 flex h-6 items-center text-text-secondary">{t('account.changeEmail.emailLabel', { ns: 'common' })}</div>
|
||||
<Input
|
||||
className="!w-full"
|
||||
placeholder={t('common.account.changeEmail.emailPlaceholder')}
|
||||
placeholder={t('account.changeEmail.emailPlaceholder', { ns: 'common' })}
|
||||
value={mail}
|
||||
onChange={e => handleNewEmailValueChange(e.target.value)}
|
||||
destructive={newEmailExited || unAvailableEmail}
|
||||
/>
|
||||
{newEmailExited && (
|
||||
<div className="body-xs-regular mt-1 py-0.5 text-text-destructive">{t('common.account.changeEmail.existingEmail')}</div>
|
||||
<div className="body-xs-regular mt-1 py-0.5 text-text-destructive">{t('account.changeEmail.existingEmail', { ns: 'common' })}</div>
|
||||
)}
|
||||
{unAvailableEmail && (
|
||||
<div className="body-xs-regular mt-1 py-0.5 text-text-destructive">{t('common.account.changeEmail.unAvailableEmail')}</div>
|
||||
<div className="body-xs-regular mt-1 py-0.5 text-text-destructive">{t('account.changeEmail.unAvailableEmail', { ns: 'common' })}</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="mt-3 space-y-2">
|
||||
|
|
@ -316,20 +316,20 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
|||
variant="primary"
|
||||
onClick={sendCodeToNewEmail}
|
||||
>
|
||||
{t('common.account.changeEmail.sendVerifyCode')}
|
||||
{t('account.changeEmail.sendVerifyCode', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
className="!w-full"
|
||||
onClick={onClose}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{step === STEP.verifyNew && (
|
||||
<>
|
||||
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('common.account.changeEmail.verifyNew')}</div>
|
||||
<div className="title-2xl-semi-bold pb-3 text-text-primary">{t('account.changeEmail.verifyNew', { ns: 'common' })}</div>
|
||||
<div className="space-y-0.5 pb-2 pt-1">
|
||||
<div className="body-md-regular text-text-secondary">
|
||||
<Trans
|
||||
|
|
@ -340,10 +340,10 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
|||
</div>
|
||||
</div>
|
||||
<div className="pt-3">
|
||||
<div className="system-sm-medium mb-1 flex h-6 items-center text-text-secondary">{t('common.account.changeEmail.codeLabel')}</div>
|
||||
<div className="system-sm-medium mb-1 flex h-6 items-center text-text-secondary">{t('account.changeEmail.codeLabel', { ns: 'common' })}</div>
|
||||
<Input
|
||||
className="!w-full"
|
||||
placeholder={t('common.account.changeEmail.codePlaceholder')}
|
||||
placeholder={t('account.changeEmail.codePlaceholder', { ns: 'common' })}
|
||||
value={code}
|
||||
onChange={e => setCode(e.target.value)}
|
||||
maxLength={6}
|
||||
|
|
@ -356,22 +356,22 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
|||
variant="primary"
|
||||
onClick={submitNewEmail}
|
||||
>
|
||||
{t('common.account.changeEmail.changeTo', { email: mail })}
|
||||
{t('account.changeEmail.changeTo', { ns: 'common', email: mail })}
|
||||
</Button>
|
||||
<Button
|
||||
className="!w-full"
|
||||
onClick={onClose}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
<div className="system-xs-regular mt-3 flex items-center gap-1 text-text-tertiary">
|
||||
<span>{t('common.account.changeEmail.resendTip')}</span>
|
||||
<span>{t('account.changeEmail.resendTip', { ns: 'common' })}</span>
|
||||
{time > 0 && (
|
||||
<span>{t('common.account.changeEmail.resendCount', { count: time })}</span>
|
||||
<span>{t('account.changeEmail.resendCount', { ns: 'common', count: time })}</span>
|
||||
)}
|
||||
{!time && (
|
||||
<span onClick={sendCodeToNewEmail} className="system-xs-medium cursor-pointer text-text-accent-secondary">{t('common.account.changeEmail.resend')}</span>
|
||||
<span onClick={sendCodeToNewEmail} className="system-xs-medium cursor-pointer text-text-accent-secondary">{t('account.changeEmail.resend', { ns: 'common' })}</span>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ export default function AccountPage() {
|
|||
try {
|
||||
setEditing(true)
|
||||
await updateUserProfile({ url: 'account/name', body: { name: editName } })
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
notify({ type: 'success', message: t('actionMsg.modifiedSuccessfully', { ns: 'common' }) })
|
||||
mutateUserProfile()
|
||||
setEditNameModalVisible(false)
|
||||
setEditing(false)
|
||||
|
|
@ -80,15 +80,15 @@ export default function AccountPage() {
|
|||
}
|
||||
const valid = () => {
|
||||
if (!password.trim()) {
|
||||
showErrorMessage(t('login.error.passwordEmpty'))
|
||||
showErrorMessage(t('error.passwordEmpty', { ns: 'login' }))
|
||||
return false
|
||||
}
|
||||
if (!validPassword.test(password)) {
|
||||
showErrorMessage(t('login.error.passwordInvalid'))
|
||||
showErrorMessage(t('error.passwordInvalid', { ns: 'login' }))
|
||||
return false
|
||||
}
|
||||
if (password !== confirmPassword) {
|
||||
showErrorMessage(t('common.account.notEqual'))
|
||||
showErrorMessage(t('account.notEqual', { ns: 'common' }))
|
||||
return false
|
||||
}
|
||||
|
||||
|
|
@ -112,7 +112,7 @@ export default function AccountPage() {
|
|||
repeat_new_password: confirmPassword,
|
||||
},
|
||||
})
|
||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
||||
notify({ type: 'success', message: t('actionMsg.modifiedSuccessfully', { ns: 'common' }) })
|
||||
mutateUserProfile()
|
||||
setEditPasswordModalVisible(false)
|
||||
resetPasswordForm()
|
||||
|
|
@ -146,7 +146,7 @@ export default function AccountPage() {
|
|||
return (
|
||||
<>
|
||||
<div className="pb-3 pt-2">
|
||||
<h4 className="title-2xl-semi-bold text-text-primary">{t('common.account.myAccount')}</h4>
|
||||
<h4 className="title-2xl-semi-bold text-text-primary">{t('account.myAccount', { ns: 'common' })}</h4>
|
||||
</div>
|
||||
<div className="mb-8 flex items-center rounded-xl bg-gradient-to-r from-background-gradient-bg-fill-chat-bg-2 to-background-gradient-bg-fill-chat-bg-1 p-6">
|
||||
<AvatarWithEdit avatar={userProfile.avatar_url} name={userProfile.name} onSave={mutateUserProfile} size={64} />
|
||||
|
|
@ -164,25 +164,25 @@ export default function AccountPage() {
|
|||
</div>
|
||||
</div>
|
||||
<div className="mb-8">
|
||||
<div className={titleClassName}>{t('common.account.name')}</div>
|
||||
<div className={titleClassName}>{t('account.name', { ns: 'common' })}</div>
|
||||
<div className="mt-2 flex w-full items-center justify-between gap-2">
|
||||
<div className="system-sm-regular flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled ">
|
||||
<span className="pl-1">{userProfile.name}</span>
|
||||
</div>
|
||||
<div className="system-sm-medium cursor-pointer rounded-lg bg-components-button-tertiary-bg px-3 py-2 text-components-button-tertiary-text" onClick={handleEditName}>
|
||||
{t('common.operation.edit')}
|
||||
{t('operation.edit', { ns: 'common' })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mb-8">
|
||||
<div className={titleClassName}>{t('common.account.email')}</div>
|
||||
<div className={titleClassName}>{t('account.email', { ns: 'common' })}</div>
|
||||
<div className="mt-2 flex w-full items-center justify-between gap-2">
|
||||
<div className="system-sm-regular flex-1 rounded-lg bg-components-input-bg-normal p-2 text-components-input-text-filled ">
|
||||
<span className="pl-1">{userProfile.email}</span>
|
||||
</div>
|
||||
{systemFeatures.enable_change_email && (
|
||||
<div className="system-sm-medium cursor-pointer rounded-lg bg-components-button-tertiary-bg px-3 py-2 text-components-button-tertiary-text" onClick={() => setShowUpdateEmail(true)}>
|
||||
{t('common.operation.change')}
|
||||
{t('operation.change', { ns: 'common' })}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -191,26 +191,26 @@ export default function AccountPage() {
|
|||
systemFeatures.enable_email_password_login && (
|
||||
<div className="mb-8 flex justify-between gap-2">
|
||||
<div>
|
||||
<div className="system-sm-semibold mb-1 text-text-secondary">{t('common.account.password')}</div>
|
||||
<div className="body-xs-regular mb-2 text-text-tertiary">{t('common.account.passwordTip')}</div>
|
||||
<div className="system-sm-semibold mb-1 text-text-secondary">{t('account.password', { ns: 'common' })}</div>
|
||||
<div className="body-xs-regular mb-2 text-text-tertiary">{t('account.passwordTip', { ns: 'common' })}</div>
|
||||
</div>
|
||||
<Button onClick={() => setEditPasswordModalVisible(true)}>{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</Button>
|
||||
<Button onClick={() => setEditPasswordModalVisible(true)}>{userProfile.is_password_set ? t('account.resetPassword', { ns: 'common' }) : t('account.setPassword', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
<div className="mb-6 border-[1px] border-divider-subtle" />
|
||||
<div className="mb-8">
|
||||
<div className={titleClassName}>{t('common.account.langGeniusAccount')}</div>
|
||||
<div className={descriptionClassName}>{t('common.account.langGeniusAccountTip')}</div>
|
||||
<div className={titleClassName}>{t('account.langGeniusAccount', { ns: 'common' })}</div>
|
||||
<div className={descriptionClassName}>{t('account.langGeniusAccountTip', { ns: 'common' })}</div>
|
||||
{!!apps.length && (
|
||||
<Collapse
|
||||
title={`${t('common.account.showAppLength', { length: apps.length })}`}
|
||||
title={`${t('account.showAppLength', { ns: 'common', length: apps.length })}`}
|
||||
items={apps.map((app: App) => ({ ...app, key: app.id, name: app.name }))}
|
||||
renderItem={renderAppItem}
|
||||
wrapperClassName="mt-2"
|
||||
/>
|
||||
)}
|
||||
{!IS_CE_EDITION && <Button className="mt-2 text-components-button-destructive-secondary-text" onClick={() => setShowDeleteAccountModal(true)}>{t('common.account.delete')}</Button>}
|
||||
{!IS_CE_EDITION && <Button className="mt-2 text-components-button-destructive-secondary-text" onClick={() => setShowDeleteAccountModal(true)}>{t('account.delete', { ns: 'common' })}</Button>}
|
||||
</div>
|
||||
{
|
||||
editNameModalVisible && (
|
||||
|
|
@ -219,21 +219,21 @@ export default function AccountPage() {
|
|||
onClose={() => setEditNameModalVisible(false)}
|
||||
className="!w-[420px] !p-6"
|
||||
>
|
||||
<div className="title-2xl-semi-bold mb-6 text-text-primary">{t('common.account.editName')}</div>
|
||||
<div className={titleClassName}>{t('common.account.name')}</div>
|
||||
<div className="title-2xl-semi-bold mb-6 text-text-primary">{t('account.editName', { ns: 'common' })}</div>
|
||||
<div className={titleClassName}>{t('account.name', { ns: 'common' })}</div>
|
||||
<Input
|
||||
className="mt-2"
|
||||
value={editName}
|
||||
onChange={e => setEditName(e.target.value)}
|
||||
/>
|
||||
<div className="mt-10 flex justify-end">
|
||||
<Button className="mr-2" onClick={() => setEditNameModalVisible(false)}>{t('common.operation.cancel')}</Button>
|
||||
<Button className="mr-2" onClick={() => setEditNameModalVisible(false)}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Button
|
||||
disabled={editing || !editName}
|
||||
variant="primary"
|
||||
onClick={handleSaveName}
|
||||
>
|
||||
{t('common.operation.save')}
|
||||
{t('operation.save', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
@ -249,10 +249,10 @@ export default function AccountPage() {
|
|||
}}
|
||||
className="!w-[420px] !p-6"
|
||||
>
|
||||
<div className="title-2xl-semi-bold mb-6 text-text-primary">{userProfile.is_password_set ? t('common.account.resetPassword') : t('common.account.setPassword')}</div>
|
||||
<div className="title-2xl-semi-bold mb-6 text-text-primary">{userProfile.is_password_set ? t('account.resetPassword', { ns: 'common' }) : t('account.setPassword', { ns: 'common' })}</div>
|
||||
{userProfile.is_password_set && (
|
||||
<>
|
||||
<div className={titleClassName}>{t('common.account.currentPassword')}</div>
|
||||
<div className={titleClassName}>{t('account.currentPassword', { ns: 'common' })}</div>
|
||||
<div className="relative mt-2">
|
||||
<Input
|
||||
type={showCurrentPassword ? 'text' : 'password'}
|
||||
|
|
@ -273,7 +273,7 @@ export default function AccountPage() {
|
|||
</>
|
||||
)}
|
||||
<div className="system-sm-semibold mt-8 text-text-secondary">
|
||||
{userProfile.is_password_set ? t('common.account.newPassword') : t('common.account.password')}
|
||||
{userProfile.is_password_set ? t('account.newPassword', { ns: 'common' }) : t('account.password', { ns: 'common' })}
|
||||
</div>
|
||||
<div className="relative mt-2">
|
||||
<Input
|
||||
|
|
@ -291,7 +291,7 @@ export default function AccountPage() {
|
|||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="system-sm-semibold mt-8 text-text-secondary">{t('common.account.confirmPassword')}</div>
|
||||
<div className="system-sm-semibold mt-8 text-text-secondary">{t('account.confirmPassword', { ns: 'common' })}</div>
|
||||
<div className="relative mt-2">
|
||||
<Input
|
||||
type={showConfirmPassword ? 'text' : 'password'}
|
||||
|
|
@ -316,14 +316,14 @@ export default function AccountPage() {
|
|||
resetPasswordForm()
|
||||
}}
|
||||
>
|
||||
{t('common.operation.cancel')}
|
||||
{t('operation.cancel', { ns: 'common' })}
|
||||
</Button>
|
||||
<Button
|
||||
disabled={editing}
|
||||
variant="primary"
|
||||
onClick={handleSavePassword}
|
||||
>
|
||||
{userProfile.is_password_set ? t('common.operation.reset') : t('common.operation.save')}
|
||||
{userProfile.is_password_set ? t('operation.reset', { ns: 'common' }) : t('operation.save', { ns: 'common' })}
|
||||
</Button>
|
||||
</div>
|
||||
</Modal>
|
||||
|
|
|
|||
|
|
@ -94,7 +94,7 @@ export default function AppSelector() {
|
|||
className="group flex h-9 cursor-pointer items-center justify-start rounded-lg px-3 hover:bg-state-base-hover"
|
||||
>
|
||||
<LogOut01 className="mr-1 flex h-4 w-4 text-text-tertiary" />
|
||||
<div className="text-[14px] font-normal text-text-secondary">{t('common.userProfile.logout')}</div>
|
||||
<div className="text-[14px] font-normal text-text-secondary">{t('userProfile.logout', { ns: 'common' })}</div>
|
||||
</div>
|
||||
</div>
|
||||
</MenuItem>
|
||||
|
|
|
|||
|
|
@ -31,22 +31,22 @@ export default function CheckEmail(props: DeleteAccountProps) {
|
|||
return (
|
||||
<>
|
||||
<div className="body-md-medium py-1 text-text-destructive">
|
||||
{t('common.account.deleteTip')}
|
||||
{t('account.deleteTip', { ns: 'common' })}
|
||||
</div>
|
||||
<div className="body-md-regular pb-2 pt-1 text-text-secondary">
|
||||
{t('common.account.deletePrivacyLinkTip')}
|
||||
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('common.account.deletePrivacyLink')}</Link>
|
||||
{t('account.deletePrivacyLinkTip', { ns: 'common' })}
|
||||
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('account.deletePrivacyLink', { ns: 'common' })}</Link>
|
||||
</div>
|
||||
<label className="system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary">{t('common.account.deleteLabel')}</label>
|
||||
<label className="system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary">{t('account.deleteLabel', { ns: 'common' })}</label>
|
||||
<Input
|
||||
placeholder={t('common.account.deletePlaceholder') as string}
|
||||
placeholder={t('account.deletePlaceholder', { ns: 'common' }) as string}
|
||||
onChange={(e) => {
|
||||
setUserInputEmail(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<div className="mt-3 flex w-full flex-col gap-2">
|
||||
<Button className="w-full" disabled={userInputEmail !== userProfile.email || isSendingEmail} loading={isSendingEmail} variant="primary" onClick={handleConfirm}>{t('common.account.sendVerificationButton')}</Button>
|
||||
<Button className="w-full" onClick={props.onCancel}>{t('common.operation.cancel')}</Button>
|
||||
<Button className="w-full" disabled={userInputEmail !== userProfile.email || isSendingEmail} loading={isSendingEmail} variant="primary" onClick={handleConfirm}>{t('account.sendVerificationButton', { ns: 'common' })}</Button>
|
||||
<Button className="w-full" onClick={props.onCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ export default function FeedBack(props: DeleteAccountProps) {
|
|||
await logout()
|
||||
// Tokens are now stored in cookies and cleared by backend
|
||||
router.push('/signin')
|
||||
Toast.notify({ type: 'info', message: t('common.account.deleteSuccessTip') })
|
||||
Toast.notify({ type: 'info', message: t('account.deleteSuccessTip', { ns: 'common' }) })
|
||||
}
|
||||
catch (error) { console.error(error) }
|
||||
}, [router, t])
|
||||
|
|
@ -50,22 +50,22 @@ export default function FeedBack(props: DeleteAccountProps) {
|
|||
<CustomDialog
|
||||
show={true}
|
||||
onClose={props.onCancel}
|
||||
title={t('common.account.feedbackTitle')}
|
||||
title={t('account.feedbackTitle', { ns: 'common' })}
|
||||
className="max-w-[480px]"
|
||||
footer={false}
|
||||
>
|
||||
<label className="system-sm-semibold mb-1 mt-3 flex items-center text-text-secondary">{t('common.account.feedbackLabel')}</label>
|
||||
<label className="system-sm-semibold mb-1 mt-3 flex items-center text-text-secondary">{t('account.feedbackLabel', { ns: 'common' })}</label>
|
||||
<Textarea
|
||||
rows={6}
|
||||
value={userFeedback}
|
||||
placeholder={t('common.account.feedbackPlaceholder') as string}
|
||||
placeholder={t('account.feedbackPlaceholder', { ns: 'common' }) as string}
|
||||
onChange={(e) => {
|
||||
setUserFeedback(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<div className="mt-3 flex w-full flex-col gap-2">
|
||||
<Button className="w-full" loading={isPending} variant="primary" onClick={handleSubmit}>{t('common.operation.submit')}</Button>
|
||||
<Button className="w-full" onClick={handleSkip}>{t('common.operation.skip')}</Button>
|
||||
<Button className="w-full" loading={isPending} variant="primary" onClick={handleSubmit}>{t('operation.submit', { ns: 'common' })}</Button>
|
||||
<Button className="w-full" onClick={handleSkip}>{t('operation.skip', { ns: 'common' })}</Button>
|
||||
</div>
|
||||
</CustomDialog>
|
||||
)
|
||||
|
|
|
|||
|
|
@ -37,24 +37,24 @@ export default function VerifyEmail(props: DeleteAccountProps) {
|
|||
return (
|
||||
<>
|
||||
<div className="body-md-medium pt-1 text-text-destructive">
|
||||
{t('common.account.deleteTip')}
|
||||
{t('account.deleteTip', { ns: 'common' })}
|
||||
</div>
|
||||
<div className="body-md-regular pb-2 pt-1 text-text-secondary">
|
||||
{t('common.account.deletePrivacyLinkTip')}
|
||||
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('common.account.deletePrivacyLink')}</Link>
|
||||
{t('account.deletePrivacyLinkTip', { ns: 'common' })}
|
||||
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('account.deletePrivacyLink', { ns: 'common' })}</Link>
|
||||
</div>
|
||||
<label className="system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary">{t('common.account.verificationLabel')}</label>
|
||||
<label className="system-sm-semibold mb-1 mt-3 flex h-6 items-center text-text-secondary">{t('account.verificationLabel', { ns: 'common' })}</label>
|
||||
<Input
|
||||
minLength={6}
|
||||
maxLength={6}
|
||||
placeholder={t('common.account.verificationPlaceholder') as string}
|
||||
placeholder={t('account.verificationPlaceholder', { ns: 'common' }) as string}
|
||||
onChange={(e) => {
|
||||
setVerificationCode(e.target.value)
|
||||
}}
|
||||
/>
|
||||
<div className="mt-3 flex w-full flex-col gap-2">
|
||||
<Button className="w-full" disabled={shouldButtonDisabled} loading={isDeleting} variant="warning" onClick={handleConfirm}>{t('common.account.permanentlyDeleteButton')}</Button>
|
||||
<Button className="w-full" onClick={props.onCancel}>{t('common.operation.cancel')}</Button>
|
||||
<Button className="w-full" disabled={shouldButtonDisabled} loading={isDeleting} variant="warning" onClick={handleConfirm}>{t('account.permanentlyDeleteButton', { ns: 'common' })}</Button>
|
||||
<Button className="w-full" onClick={props.onCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
<Countdown onResend={sendEmail} />
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ export default function DeleteAccount(props: DeleteAccountProps) {
|
|||
<CustomDialog
|
||||
show={true}
|
||||
onClose={props.onCancel}
|
||||
title={t('common.account.delete')}
|
||||
title={t('account.delete', { ns: 'common' })}
|
||||
className="max-w-[480px]"
|
||||
footer={false}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -32,12 +32,12 @@ const Header = () => {
|
|||
: <DifyLogo />}
|
||||
</div>
|
||||
<div className="h-4 w-[1px] origin-center rotate-[11.31deg] bg-divider-regular" />
|
||||
<p className="title-3xl-semi-bold relative mt-[-2px] text-text-primary">{t('common.account.account')}</p>
|
||||
<p className="title-3xl-semi-bold relative mt-[-2px] text-text-primary">{t('account.account', { ns: 'common' })}</p>
|
||||
</div>
|
||||
<div className="flex shrink-0 items-center gap-3">
|
||||
<Button className="system-sm-medium gap-2 px-3 py-2" onClick={goToStudio}>
|
||||
<RiRobot2Line className="h-4 w-4" />
|
||||
<p>{t('common.account.studio')}</p>
|
||||
<p>{t('account.studio', { ns: 'common' })}</p>
|
||||
<RiArrowRightUpLine className="h-4 w-4" />
|
||||
</Button>
|
||||
<div className="h-4 w-[1px] bg-divider-regular" />
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import AccountPage from './account-page'
|
|||
|
||||
export default function Account() {
|
||||
const { t } = useTranslation()
|
||||
useDocumentTitle(t('common.menus.account'))
|
||||
useDocumentTitle(t('menus.account', { ns: 'common' }))
|
||||
return (
|
||||
<div className="mx-auto w-full max-w-[640px] px-6 pt-12">
|
||||
<AccountPage />
|
||||
|
|
|
|||
|
|
@ -50,23 +50,23 @@ export default function OAuthAuthorize() {
|
|||
const SCOPE_INFO_MAP: Record<string, { icon: React.ComponentType<{ className?: string }>, label: string }> = {
|
||||
'read:name': {
|
||||
icon: RiInfoCardLine,
|
||||
label: t('oauth.scopes.name'),
|
||||
label: t('scopes.name', { ns: 'oauth' }),
|
||||
},
|
||||
'read:email': {
|
||||
icon: RiMailLine,
|
||||
label: t('oauth.scopes.email'),
|
||||
label: t('scopes.email', { ns: 'oauth' }),
|
||||
},
|
||||
'read:avatar': {
|
||||
icon: RiAccountCircleLine,
|
||||
label: t('oauth.scopes.avatar'),
|
||||
label: t('scopes.avatar', { ns: 'oauth' }),
|
||||
},
|
||||
'read:interface_language': {
|
||||
icon: RiTranslate2,
|
||||
label: t('oauth.scopes.languagePreference'),
|
||||
label: t('scopes.languagePreference', { ns: 'oauth' }),
|
||||
},
|
||||
'read:timezone': {
|
||||
icon: RiGlobalLine,
|
||||
label: t('oauth.scopes.timezone'),
|
||||
label: t('scopes.timezone', { ns: 'oauth' }),
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +106,7 @@ export default function OAuthAuthorize() {
|
|||
catch (err: any) {
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: `${t('oauth.error.authorizeFailed')}: ${err.message}`,
|
||||
message: `${t('error.authorizeFailed', { ns: 'oauth' })}: ${err.message}`,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -117,7 +117,7 @@ export default function OAuthAuthorize() {
|
|||
hasNotifiedRef.current = true
|
||||
Toast.notify({
|
||||
type: 'error',
|
||||
message: invalidParams ? t('oauth.error.invalidParams') : t('oauth.error.authAppInfoFetchFailed'),
|
||||
message: invalidParams ? t('error.invalidParams', { ns: 'oauth' }) : t('error.authAppInfoFetchFailed', { ns: 'oauth' }),
|
||||
duration: 0,
|
||||
})
|
||||
}
|
||||
|
|
@ -141,11 +141,11 @@ export default function OAuthAuthorize() {
|
|||
|
||||
<div className={`mb-4 mt-5 flex flex-col gap-2 ${isLoggedIn ? 'pb-2' : ''}`}>
|
||||
<div className="title-4xl-semi-bold">
|
||||
{isLoggedIn && <div className="text-text-primary">{t('oauth.connect')}</div>}
|
||||
<div className="text-[var(--color-saas-dify-blue-inverted)]">{authAppInfo?.app_label[language] || authAppInfo?.app_label?.en_US || t('oauth.unknownApp')}</div>
|
||||
{!isLoggedIn && <div className="text-text-primary">{t('oauth.tips.notLoggedIn')}</div>}
|
||||
{isLoggedIn && <div className="text-text-primary">{t('connect', { ns: 'oauth' })}</div>}
|
||||
<div className="text-[var(--color-saas-dify-blue-inverted)]">{authAppInfo?.app_label[language] || authAppInfo?.app_label?.en_US || t('unknownApp', { ns: 'oauth' })}</div>
|
||||
{!isLoggedIn && <div className="text-text-primary">{t('tips.notLoggedIn', { ns: 'oauth' })}</div>}
|
||||
</div>
|
||||
<div className="body-md-regular text-text-secondary">{isLoggedIn ? `${authAppInfo?.app_label[language] || authAppInfo?.app_label?.en_US || t('oauth.unknownApp')} ${t('oauth.tips.loggedIn')}` : t('oauth.tips.needLogin')}</div>
|
||||
<div className="body-md-regular text-text-secondary">{isLoggedIn ? `${authAppInfo?.app_label[language] || authAppInfo?.app_label?.en_US || t('unknownApp', { ns: 'oauth' })} ${t('tips.loggedIn', { ns: 'oauth' })}` : t('tips.needLogin', { ns: 'oauth' })}</div>
|
||||
</div>
|
||||
|
||||
{isLoggedIn && userProfile && (
|
||||
|
|
@ -157,7 +157,7 @@ export default function OAuthAuthorize() {
|
|||
<div className="system-xs-regular text-text-tertiary">{userProfile.email}</div>
|
||||
</div>
|
||||
</div>
|
||||
<Button variant="tertiary" size="small" onClick={onLoginSwitchClick}>{t('oauth.switchAccount')}</Button>
|
||||
<Button variant="tertiary" size="small" onClick={onLoginSwitchClick}>{t('switchAccount', { ns: 'oauth' })}</Button>
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
@ -178,12 +178,12 @@ export default function OAuthAuthorize() {
|
|||
<div className="flex flex-col items-center gap-2 pt-4">
|
||||
{!isLoggedIn
|
||||
? (
|
||||
<Button variant="primary" size="large" className="w-full" onClick={onLoginSwitchClick}>{t('oauth.login')}</Button>
|
||||
<Button variant="primary" size="large" className="w-full" onClick={onLoginSwitchClick}>{t('login', { ns: 'oauth' })}</Button>
|
||||
)
|
||||
: (
|
||||
<>
|
||||
<Button variant="primary" size="large" className="w-full" onClick={onAuthorize} disabled={!client_id || !redirect_uri || isError || authorizing} loading={authorizing}>{t('oauth.continue')}</Button>
|
||||
<Button size="large" className="w-full" onClick={() => router.push('/apps')}>{t('common.operation.cancel')}</Button>
|
||||
<Button variant="primary" size="large" className="w-full" onClick={onAuthorize} disabled={!client_id || !redirect_uri || isError || authorizing} loading={authorizing}>{t('continue', { ns: 'oauth' })}</Button>
|
||||
<Button size="large" className="w-full" onClick={() => router.push('/apps')}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
|
@ -199,7 +199,7 @@ export default function OAuthAuthorize() {
|
|||
</defs>
|
||||
</svg>
|
||||
</div>
|
||||
<div className="system-xs-regular mt-3 text-text-tertiary">{t('oauth.tips.common')}</div>
|
||||
<div className="system-xs-regular mt-3 text-text-tertiary">{t('tips.common', { ns: 'oauth' })}</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,11 +56,11 @@ const ActivateForm = () => {
|
|||
<div className="flex flex-col md:w-[400px]">
|
||||
<div className="mx-auto w-full">
|
||||
<div className="mb-3 flex h-20 w-20 items-center justify-center rounded-[20px] border border-divider-regular bg-components-option-card-option-bg p-5 text-[40px] font-bold shadow-lg">🤷♂️</div>
|
||||
<h2 className="text-[32px] font-bold text-text-primary">{t('login.invalid')}</h2>
|
||||
<h2 className="text-[32px] font-bold text-text-primary">{t('invalid', { ns: 'login' })}</h2>
|
||||
</div>
|
||||
<div className="mx-auto mt-6 w-full">
|
||||
<Button variant="primary" className="w-full !text-sm">
|
||||
<a href="https://dify.ai">{t('login.explore')}</a>
|
||||
<a href="https://dify.ai">{t('explore', { ns: 'login' })}</a>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -102,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
|
||||
}
|
||||
|
|
@ -144,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,
|
||||
}]
|
||||
: []),
|
||||
|
|
@ -224,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
|
||||
}
|
||||
|
|
@ -246,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) {
|
||||
|
|
@ -254,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> = {}
|
||||
|
|
@ -267,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
|
||||
}
|
||||
|
|
@ -292,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>
|
||||
|
||||
|
|
@ -327,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>
|
||||
|
|
@ -378,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,
|
||||
|
|
@ -396,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>
|
||||
|
|
@ -411,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) => {
|
||||
|
|
@ -432,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}
|
||||
|
|
@ -448,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>
|
||||
)}
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue