mirror of https://github.com/langgenius/dify.git
chore: merge
This commit is contained in:
commit
21694ab3b6
|
|
@ -4,7 +4,7 @@ on:
|
||||||
push:
|
push:
|
||||||
branches: [main]
|
branches: [main]
|
||||||
paths:
|
paths:
|
||||||
- 'web/i18n/en-US/*.ts'
|
- 'web/i18n/en-US/*.json'
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
contents: write
|
contents: write
|
||||||
|
|
@ -28,13 +28,13 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
git fetch origin "${{ github.event.before }}" || true
|
git fetch origin "${{ github.event.before }}" || true
|
||||||
git fetch origin "${{ github.sha }}" || 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"
|
echo "Changed files: $changed_files"
|
||||||
if [ -n "$changed_files" ]; then
|
if [ -n "$changed_files" ]; then
|
||||||
echo "FILES_CHANGED=true" >> $GITHUB_ENV
|
echo "FILES_CHANGED=true" >> $GITHUB_ENV
|
||||||
file_args=""
|
file_args=""
|
||||||
for file in $changed_files; do
|
for file in $changed_files; do
|
||||||
filename=$(basename "$file" .ts)
|
filename=$(basename "$file" .json)
|
||||||
file_args="$file_args --file $filename"
|
file_args="$file_args --file $filename"
|
||||||
done
|
done
|
||||||
echo "FILE_ARGS=$file_args" >> $GITHUB_ENV
|
echo "FILE_ARGS=$file_args" >> $GITHUB_ENV
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ const getSupportedLocales = (): string[] => {
|
||||||
|
|
||||||
// Helper function to load translation file content
|
// Helper function to load translation file content
|
||||||
const loadTranslationContent = (locale: string): string => {
|
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))
|
if (!fs.existsSync(filePath))
|
||||||
throw new Error(`Translation file not found: ${filePath}`)
|
throw new Error(`Translation file not found: ${filePath}`)
|
||||||
|
|
@ -24,14 +24,14 @@ const loadTranslationContent = (locale: string): string => {
|
||||||
return fs.readFileSync(filePath, 'utf-8')
|
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 } => {
|
const hasUploadFeatures = (content: string): { [key: string]: boolean } => {
|
||||||
return {
|
return {
|
||||||
fileUpload: /fileUpload\s*:\s*\{/.test(content),
|
fileUpload: /"feature\.fileUpload\.title"/.test(content),
|
||||||
imageUpload: /imageUpload\s*:\s*\{/.test(content),
|
imageUpload: /"feature\.imageUpload\.title"/.test(content),
|
||||||
documentUpload: /documentUpload\s*:\s*\{/.test(content),
|
documentUpload: /"feature\.documentUpload\.title"/.test(content),
|
||||||
audioUpload: /audioUpload\s*:\s*\{/.test(content),
|
audioUpload: /"feature\.audioUpload\.title"/.test(content),
|
||||||
featureBar: /bar\s*:\s*\{/.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', () => {
|
it('all locales should have translation files', () => {
|
||||||
supportedLocales.forEach((locale) => {
|
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)
|
expect(fs.existsSync(filePath)).toBe(true)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
@ -76,12 +76,9 @@ describe('Upload Features i18n Translations - Issue #23062', () => {
|
||||||
previouslyMissingLocales.forEach((locale) => {
|
previouslyMissingLocales.forEach((locale) => {
|
||||||
const content = loadTranslationContent(locale)
|
const content = loadTranslationContent(locale)
|
||||||
|
|
||||||
// Verify audioUpload exists
|
// Verify audioUpload exists with title and description (flattened JSON format)
|
||||||
expect(/audioUpload\s*:\s*\{/.test(content)).toBe(true)
|
expect(/"feature\.audioUpload\.title"/.test(content)).toBe(true)
|
||||||
|
expect(/"feature\.audioUpload\.description"/.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)
|
|
||||||
|
|
||||||
console.log(`✅ ${locale} - Issue #23062 resolved: audioUpload feature present`)
|
console.log(`✅ ${locale} - Issue #23062 resolved: audioUpload feature present`)
|
||||||
})
|
})
|
||||||
|
|
@ -91,28 +88,28 @@ describe('Upload Features i18n Translations - Issue #23062', () => {
|
||||||
supportedLocales.forEach((locale) => {
|
supportedLocales.forEach((locale) => {
|
||||||
const content = loadTranslationContent(locale)
|
const content = loadTranslationContent(locale)
|
||||||
|
|
||||||
// Check fileUpload has required properties
|
// Check fileUpload has required properties (flattened JSON format)
|
||||||
if (/fileUpload\s*:\s*\{/.test(content)) {
|
if (/"feature\.fileUpload\.title"/.test(content)) {
|
||||||
expect(/fileUpload[^}]*title\s*:/.test(content)).toBe(true)
|
expect(/"feature\.fileUpload\.title"/.test(content)).toBe(true)
|
||||||
expect(/fileUpload[^}]*description\s*:/.test(content)).toBe(true)
|
expect(/"feature\.fileUpload\.description"/.test(content)).toBe(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check imageUpload has required properties
|
// Check imageUpload has required properties
|
||||||
if (/imageUpload\s*:\s*\{/.test(content)) {
|
if (/"feature\.imageUpload\.title"/.test(content)) {
|
||||||
expect(/imageUpload[^}]*title\s*:/.test(content)).toBe(true)
|
expect(/"feature\.imageUpload\.title"/.test(content)).toBe(true)
|
||||||
expect(/imageUpload[^}]*description\s*:/.test(content)).toBe(true)
|
expect(/"feature\.imageUpload\.description"/.test(content)).toBe(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check documentUpload has required properties
|
// Check documentUpload has required properties
|
||||||
if (/documentUpload\s*:\s*\{/.test(content)) {
|
if (/"feature\.documentUpload\.title"/.test(content)) {
|
||||||
expect(/documentUpload[^}]*title\s*:/.test(content)).toBe(true)
|
expect(/"feature\.documentUpload\.title"/.test(content)).toBe(true)
|
||||||
expect(/documentUpload[^}]*description\s*:/.test(content)).toBe(true)
|
expect(/"feature\.documentUpload\.description"/.test(content)).toBe(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check audioUpload has required properties
|
// Check audioUpload has required properties
|
||||||
if (/audioUpload\s*:\s*\{/.test(content)) {
|
if (/"feature\.audioUpload\.title"/.test(content)) {
|
||||||
expect(/audioUpload[^}]*title\s*:/.test(content)).toBe(true)
|
expect(/"feature\.audioUpload\.title"/.test(content)).toBe(true)
|
||||||
expect(/audioUpload[^}]*description\s*:/.test(content)).toBe(true)
|
expect(/"feature\.audioUpload\.description"/.test(content)).toBe(true)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -70,7 +70,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||||
const navConfig = [
|
const navConfig = [
|
||||||
...(isCurrentWorkspaceEditor
|
...(isCurrentWorkspaceEditor
|
||||||
? [{
|
? [{
|
||||||
name: t('common.appMenus.promptEng'),
|
name: t('appMenus.promptEng', { ns: 'common' }),
|
||||||
href: `/app/${appId}/${(mode === AppModeEnum.WORKFLOW || mode === AppModeEnum.ADVANCED_CHAT) ? 'workflow' : 'configuration'}`,
|
href: `/app/${appId}/${(mode === AppModeEnum.WORKFLOW || mode === AppModeEnum.ADVANCED_CHAT) ? 'workflow' : 'configuration'}`,
|
||||||
icon: RiTerminalWindowLine,
|
icon: RiTerminalWindowLine,
|
||||||
selectedIcon: RiTerminalWindowFill,
|
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`,
|
href: `/app/${appId}/develop`,
|
||||||
icon: RiTerminalBoxLine,
|
icon: RiTerminalBoxLine,
|
||||||
selectedIcon: RiTerminalBoxFill,
|
selectedIcon: RiTerminalBoxFill,
|
||||||
|
|
@ -86,8 +86,8 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||||
...(isCurrentWorkspaceEditor
|
...(isCurrentWorkspaceEditor
|
||||||
? [{
|
? [{
|
||||||
name: mode !== AppModeEnum.WORKFLOW
|
name: mode !== AppModeEnum.WORKFLOW
|
||||||
? t('common.appMenus.logAndAnn')
|
? t('appMenus.logAndAnn', { ns: 'common' })
|
||||||
: t('common.appMenus.logs'),
|
: t('appMenus.logs', { ns: 'common' }),
|
||||||
href: `/app/${appId}/logs`,
|
href: `/app/${appId}/logs`,
|
||||||
icon: RiFileList3Line,
|
icon: RiFileList3Line,
|
||||||
selectedIcon: RiFileList3Fill,
|
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`,
|
href: `/app/${appId}/overview`,
|
||||||
icon: RiDashboard2Line,
|
icon: RiDashboard2Line,
|
||||||
selectedIcon: RiDashboard2Fill,
|
selectedIcon: RiDashboard2Fill,
|
||||||
|
|
@ -104,7 +104,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||||
return navConfig
|
return navConfig
|
||||||
}, [t])
|
}, [t])
|
||||||
|
|
||||||
useDocumentTitle(appDetail?.name || t('common.menus.appDetail'))
|
useDocumentTitle(appDetail?.name || t('menus.appDetail', { ns: 'common' }))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (appDetail) {
|
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 { BlockEnum } from '@/app/components/workflow/types'
|
||||||
import type { UpdateAppSiteCodeResponse } from '@/models/app'
|
import type { UpdateAppSiteCodeResponse } from '@/models/app'
|
||||||
import type { App } from '@/types/app'
|
import type { App } from '@/types/app'
|
||||||
|
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { useCallback, useMemo } from 'react'
|
import { useCallback, useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
@ -62,7 +63,7 @@ const CardView: FC<ICardViewProps> = ({ appId, isInPanel, className }) => {
|
||||||
const buildTriggerModeMessage = useCallback((featureName: string) => (
|
const buildTriggerModeMessage = useCallback((featureName: string) => (
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div className="text-xs text-text-secondary">
|
<div className="text-xs text-text-secondary">
|
||||||
{t('appOverview.overview.disableTooltip.triggerMode', { feature: featureName })}
|
{t('overview.disableTooltip.triggerMode', { ns: 'appOverview', feature: featureName })}
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
className="cursor-pointer text-xs font-medium text-text-accent hover:underline"
|
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')
|
window.open(triggerDocUrl, '_blank')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('appOverview.overview.appInfo.enableTooltip.learnMore')}
|
{t('overview.appInfo.enableTooltip.learnMore', { ns: 'appOverview' })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
), [t, triggerDocUrl])
|
), [t, triggerDocUrl])
|
||||||
|
|
||||||
const disableWebAppTooltip = disableAppCards
|
const disableWebAppTooltip = disableAppCards
|
||||||
? buildTriggerModeMessage(t('appOverview.overview.appInfo.title'))
|
? buildTriggerModeMessage(t('overview.appInfo.title', { ns: 'appOverview' }))
|
||||||
: null
|
: null
|
||||||
const disableApiTooltip = disableAppCards
|
const disableApiTooltip = disableAppCards
|
||||||
? buildTriggerModeMessage(t('appOverview.overview.apiInfo.title'))
|
? buildTriggerModeMessage(t('overview.apiInfo.title', { ns: 'appOverview' }))
|
||||||
: null
|
: null
|
||||||
const disableMcpTooltip = disableAppCards
|
const disableMcpTooltip = disableAppCards
|
||||||
? buildTriggerModeMessage(t('tools.mcp.server.title'))
|
? buildTriggerModeMessage(t('mcp.server.title', { ns: 'tools' }))
|
||||||
: null
|
: null
|
||||||
|
|
||||||
const updateAppDetail = async () => {
|
const updateAppDetail = async () => {
|
||||||
|
|
@ -94,7 +95,7 @@ const CardView: FC<ICardViewProps> = ({ appId, isInPanel, className }) => {
|
||||||
catch (error) { console.error(error) }
|
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'
|
const type = err ? 'error' : 'success'
|
||||||
|
|
||||||
message ||= (type === 'success' ? 'modifiedSuccessfully' : 'modifiedUnsuccessfully')
|
message ||= (type === 'success' ? 'modifiedSuccessfully' : 'modifiedUnsuccessfully')
|
||||||
|
|
@ -104,7 +105,7 @@ const CardView: FC<ICardViewProps> = ({ appId, isInPanel, className }) => {
|
||||||
|
|
||||||
notify({
|
notify({
|
||||||
type,
|
type,
|
||||||
message: t(`common.actionMsg.${message}` as any) as string,
|
message: t(`actionMsg.${message}`, { ns: 'common' }) as string,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
'use client'
|
'use client'
|
||||||
import type { PeriodParams } from '@/app/components/app/overview/app-chart'
|
import type { PeriodParams } from '@/app/components/app/overview/app-chart'
|
||||||
|
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import quarterOfYear from 'dayjs/plugin/quarterOfYear'
|
import quarterOfYear from 'dayjs/plugin/quarterOfYear'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
|
@ -16,7 +17,9 @@ dayjs.extend(quarterOfYear)
|
||||||
|
|
||||||
const today = dayjs()
|
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: 0, name: 'today' },
|
||||||
{ value: 7, name: 'last7days' },
|
{ value: 7, name: 'last7days' },
|
||||||
{ value: 30, name: 'last30days' },
|
{ value: 30, name: 'last30days' },
|
||||||
|
|
@ -35,8 +38,8 @@ export default function ChartView({ appId, headerRight }: IChartViewProps) {
|
||||||
const isChatApp = appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow'
|
const isChatApp = appDetail?.mode !== 'completion' && appDetail?.mode !== 'workflow'
|
||||||
const isWorkflow = appDetail?.mode === 'workflow'
|
const isWorkflow = appDetail?.mode === 'workflow'
|
||||||
const [period, setPeriod] = useState<PeriodParams>(IS_CLOUD_EDITION
|
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('filter.period.today', { ns: 'appLog' }), 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.last7days', { ns: 'appLog' }), query: { start: today.subtract(7, 'day').startOf('day').format(queryDateFormat), end: today.endOf('day').format(queryDateFormat) } },
|
||||||
)
|
)
|
||||||
|
|
||||||
if (!appDetail)
|
if (!appDetail)
|
||||||
|
|
@ -45,7 +48,7 @@ export default function ChartView({ appId, headerRight }: IChartViewProps) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-4">
|
<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">
|
<div className="flex items-center justify-between">
|
||||||
{IS_CLOUD_EDITION
|
{IS_CLOUD_EDITION
|
||||||
? (
|
? (
|
||||||
|
|
|
||||||
|
|
@ -2,13 +2,16 @@
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import type { PeriodParams } from '@/app/components/app/overview/app-chart'
|
import type { PeriodParams } from '@/app/components/app/overview/app-chart'
|
||||||
import type { Item } from '@/app/components/base/select'
|
import type { Item } from '@/app/components/base/select'
|
||||||
|
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import { SimpleSelect } from '@/app/components/base/select'
|
import { SimpleSelect } from '@/app/components/base/select'
|
||||||
|
|
||||||
|
type TimePeriodName = I18nKeysByPrefix<'appLog', 'filter.period.'>
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
periodMapping: { [key: string]: { value: number, name: string } }
|
periodMapping: { [key: string]: { value: number, name: TimePeriodName } }
|
||||||
onSelect: (payload: PeriodParams) => void
|
onSelect: (payload: PeriodParams) => void
|
||||||
queryDateFormat: string
|
queryDateFormat: string
|
||||||
}
|
}
|
||||||
|
|
@ -25,9 +28,9 @@ const LongTimeRangePicker: FC<Props> = ({
|
||||||
const handleSelect = React.useCallback((item: Item) => {
|
const handleSelect = React.useCallback((item: Item) => {
|
||||||
const id = item.value
|
const id = item.value
|
||||||
const value = periodMapping[id]?.value ?? '-1'
|
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) {
|
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) {
|
else if (value === 0) {
|
||||||
const startOfToday = today.startOf('day').format(queryDateFormat)
|
const startOfToday = today.startOf('day').format(queryDateFormat)
|
||||||
|
|
@ -53,7 +56,7 @@ const LongTimeRangePicker: FC<Props> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SimpleSelect
|
<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"
|
className="mt-0 !w-40"
|
||||||
notClearable={true}
|
notClearable={true}
|
||||||
onSelect={handleSelect}
|
onSelect={handleSelect}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import type { Dayjs } from 'dayjs'
|
import type { Dayjs } from 'dayjs'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import type { PeriodParams, PeriodParamsWithTimeRange } from '@/app/components/app/overview/app-chart'
|
import type { PeriodParams, PeriodParamsWithTimeRange } from '@/app/components/app/overview/app-chart'
|
||||||
|
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useState } from 'react'
|
||||||
|
|
@ -13,8 +14,10 @@ import RangeSelector from './range-selector'
|
||||||
|
|
||||||
const today = dayjs()
|
const today = dayjs()
|
||||||
|
|
||||||
|
type TimePeriodName = I18nKeysByPrefix<'appLog', 'filter.period.'>
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
ranges: { value: number, name: string }[]
|
ranges: { value: number, name: TimePeriodName }[]
|
||||||
onSelect: (payload: PeriodParams) => void
|
onSelect: (payload: PeriodParams) => void
|
||||||
queryDateFormat: string
|
queryDateFormat: string
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import type { PeriodParamsWithTimeRange, TimeRange } from '@/app/components/app/overview/app-chart'
|
import type { PeriodParamsWithTimeRange, TimeRange } from '@/app/components/app/overview/app-chart'
|
||||||
import type { Item } from '@/app/components/base/select'
|
import type { Item } from '@/app/components/base/select'
|
||||||
|
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||||
import { RiArrowDownSLine, RiCheckLine } from '@remixicon/react'
|
import { RiArrowDownSLine, RiCheckLine } from '@remixicon/react'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
|
@ -12,9 +13,11 @@ import { cn } from '@/utils/classnames'
|
||||||
|
|
||||||
const today = dayjs()
|
const today = dayjs()
|
||||||
|
|
||||||
|
type TimePeriodName = I18nKeysByPrefix<'appLog', 'filter.period.'>
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isCustomRange: boolean
|
isCustomRange: boolean
|
||||||
ranges: { value: number, name: string }[]
|
ranges: { value: number, name: TimePeriodName }[]
|
||||||
onSelect: (payload: PeriodParamsWithTimeRange) => void
|
onSelect: (payload: PeriodParamsWithTimeRange) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -42,7 +45,7 @@ const RangeSelector: FC<Props> = ({
|
||||||
const renderTrigger = useCallback((item: Item | null, isOpen: boolean) => {
|
const renderTrigger = useCallback((item: Item | null, isOpen: boolean) => {
|
||||||
return (
|
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={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')} />
|
<RiArrowDownSLine className={cn('size-4 text-text-quaternary', isOpen && 'text-text-secondary')} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
@ -66,7 +69,7 @@ const RangeSelector: FC<Props> = ({
|
||||||
}, [])
|
}, [])
|
||||||
return (
|
return (
|
||||||
<SimpleSelect
|
<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"
|
className="mt-0 !w-40"
|
||||||
notClearable={true}
|
notClearable={true}
|
||||||
onSelect={handleSelectRange}
|
onSelect={handleSelectRange}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ import ProviderPanel from './provider-panel'
|
||||||
import TracingIcon from './tracing-icon'
|
import TracingIcon from './tracing-icon'
|
||||||
import { TracingProvider } from './type'
|
import { TracingProvider } from './type'
|
||||||
|
|
||||||
const I18N_PREFIX = 'app.tracing'
|
const I18N_PREFIX = 'tracing'
|
||||||
|
|
||||||
export type PopupProps = {
|
export type PopupProps = {
|
||||||
appId: string
|
appId: string
|
||||||
|
|
@ -327,19 +327,19 @@ const ConfigPopup: FC<PopupProps> = ({
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<TracingIcon size="md" className="mr-2" />
|
<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>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Indicator color={enabled ? 'green' : 'gray'} />
|
<Indicator color={enabled ? 'green' : 'gray'} />
|
||||||
<div className={cn('system-xs-semibold-uppercase ml-1 text-text-tertiary', enabled && 'text-util-colors-green-green-600')}>
|
<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>
|
</div>
|
||||||
{!readOnly && (
|
{!readOnly && (
|
||||||
<>
|
<>
|
||||||
{providerAllNotConfigured
|
{providerAllNotConfigured
|
||||||
? (
|
? (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={t(`${I18N_PREFIX}.disabledTip`)}
|
popupContent={t(`${I18N_PREFIX}.disabledTip`, { ns: 'app' })}
|
||||||
>
|
>
|
||||||
{switchContent}
|
{switchContent}
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
@ -351,14 +351,14 @@ const ConfigPopup: FC<PopupProps> = ({
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="system-xs-regular mt-2 text-text-tertiary">
|
<div className="system-xs-regular mt-2 text-text-tertiary">
|
||||||
{t(`${I18N_PREFIX}.tracingDescription`)}
|
{t(`${I18N_PREFIX}.tracingDescription`, { ns: 'app' })}
|
||||||
</div>
|
</div>
|
||||||
<Divider className="my-3" />
|
<Divider className="my-3" />
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
{(providerAllConfigured || providerAllNotConfigured)
|
{(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">
|
<div className="mt-2 max-h-96 space-y-2 overflow-y-auto">
|
||||||
{langfusePanel}
|
{langfusePanel}
|
||||||
{langSmithPanel}
|
{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">
|
<div className="mt-2 max-h-40 space-y-2 overflow-y-auto">
|
||||||
{configuredProviderPanel()}
|
{configuredProviderPanel()}
|
||||||
</div>
|
</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">
|
<div className="mt-2 max-h-40 space-y-2 overflow-y-auto">
|
||||||
{moreProviderPanel()}
|
{moreProviderPanel()}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ import ConfigButton from './config-button'
|
||||||
import TracingIcon from './tracing-icon'
|
import TracingIcon from './tracing-icon'
|
||||||
import { TracingProvider } from './type'
|
import { TracingProvider } from './type'
|
||||||
|
|
||||||
const I18N_PREFIX = 'app.tracing'
|
const I18N_PREFIX = 'tracing'
|
||||||
|
|
||||||
const Panel: FC = () => {
|
const Panel: FC = () => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
|
|
@ -45,7 +45,7 @@ const Panel: FC = () => {
|
||||||
if (!noToast) {
|
if (!noToast) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('common.api.success'),
|
message: t('api.success', { ns: 'common' }),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -254,7 +254,7 @@ const Panel: FC = () => {
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<TracingIcon size="md" />
|
<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">
|
<div className="rounded-md p-1">
|
||||||
<RiEqualizer2Line className="h-4 w-4 text-text-tertiary" />
|
<RiEqualizer2Line className="h-4 w-4 text-text-tertiary" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -295,7 +295,7 @@ const Panel: FC = () => {
|
||||||
<div className="ml-4 mr-1 flex items-center">
|
<div className="ml-4 mr-1 flex items-center">
|
||||||
<Indicator color={enabled ? 'green' : 'gray'} />
|
<Indicator color={enabled ? 'green' : 'gray'} />
|
||||||
<div className="system-xs-semibold-uppercase ml-1.5 text-text-tertiary">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
{InUseProviderIcon && <InUseProviderIcon className="ml-1 h-4" />}
|
{InUseProviderIcon && <InUseProviderIcon className="ml-1 h-4" />}
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ type Props = {
|
||||||
onChosen: (provider: TracingProvider) => void
|
onChosen: (provider: TracingProvider) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const I18N_PREFIX = 'app.tracing.configProvider'
|
const I18N_PREFIX = 'tracing.configProvider'
|
||||||
|
|
||||||
const arizeConfigTemplate = {
|
const arizeConfigTemplate = {
|
||||||
api_key: '',
|
api_key: '',
|
||||||
|
|
@ -157,7 +157,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
})
|
})
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('common.api.remove'),
|
message: t('api.remove', { ns: 'common' }),
|
||||||
})
|
})
|
||||||
onRemoved()
|
onRemoved()
|
||||||
hideRemoveConfirm()
|
hideRemoveConfirm()
|
||||||
|
|
@ -177,37 +177,37 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
if (type === TracingProvider.arize) {
|
if (type === TracingProvider.arize) {
|
||||||
const postData = config as ArizeConfig
|
const postData = config as ArizeConfig
|
||||||
if (!postData.api_key)
|
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)
|
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)
|
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) {
|
if (type === TracingProvider.phoenix) {
|
||||||
const postData = config as PhoenixConfig
|
const postData = config as PhoenixConfig
|
||||||
if (!postData.api_key)
|
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)
|
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) {
|
if (type === TracingProvider.langSmith) {
|
||||||
const postData = config as LangSmithConfig
|
const postData = config as LangSmithConfig
|
||||||
if (!postData.api_key)
|
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)
|
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) {
|
if (type === TracingProvider.langfuse) {
|
||||||
const postData = config as LangFuseConfig
|
const postData = config as LangFuseConfig
|
||||||
if (!errorMessage && !postData.secret_key)
|
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)
|
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)
|
if (!errorMessage && !postData.host)
|
||||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Host' })
|
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Host' })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === TracingProvider.opik) {
|
if (type === TracingProvider.opik) {
|
||||||
|
|
@ -218,43 +218,43 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
if (type === TracingProvider.weave) {
|
if (type === TracingProvider.weave) {
|
||||||
const postData = config as WeaveConfig
|
const postData = config as WeaveConfig
|
||||||
if (!errorMessage && !postData.api_key)
|
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)
|
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) {
|
if (type === TracingProvider.aliyun) {
|
||||||
const postData = config as AliyunConfig
|
const postData = config as AliyunConfig
|
||||||
if (!errorMessage && !postData.app_name)
|
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)
|
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)
|
if (!errorMessage && !postData.endpoint)
|
||||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Endpoint' })
|
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Endpoint' })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === TracingProvider.mlflow) {
|
if (type === TracingProvider.mlflow) {
|
||||||
const postData = config as MLflowConfig
|
const postData = config as MLflowConfig
|
||||||
if (!errorMessage && !postData.tracking_uri)
|
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) {
|
if (type === TracingProvider.databricks) {
|
||||||
const postData = config as DatabricksConfig
|
const postData = config as DatabricksConfig
|
||||||
if (!errorMessage && !postData.experiment_id)
|
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)
|
if (!errorMessage && !postData.host)
|
||||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Host' })
|
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Host' })
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type === TracingProvider.tencent) {
|
if (type === TracingProvider.tencent) {
|
||||||
const postData = config as TencentConfig
|
const postData = config as TencentConfig
|
||||||
if (!errorMessage && !postData.token)
|
if (!errorMessage && !postData.token)
|
||||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Token' })
|
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Token' })
|
||||||
if (!errorMessage && !postData.endpoint)
|
if (!errorMessage && !postData.endpoint)
|
||||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Endpoint' })
|
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Endpoint' })
|
||||||
if (!errorMessage && !postData.service_name)
|
if (!errorMessage && !postData.service_name)
|
||||||
errorMessage = t('common.errorMsg.fieldRequired', { field: 'Service Name' })
|
errorMessage = t('errorMsg.fieldRequired', { ns: 'common', field: 'Service Name' })
|
||||||
}
|
}
|
||||||
|
|
||||||
return errorMessage
|
return errorMessage
|
||||||
|
|
@ -281,7 +281,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
})
|
})
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('common.api.success'),
|
message: t('api.success', { ns: 'common' }),
|
||||||
})
|
})
|
||||||
onSaved(config)
|
onSaved(config)
|
||||||
if (isAdd)
|
if (isAdd)
|
||||||
|
|
@ -303,8 +303,8 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
<div className="px-8 pt-8">
|
<div className="px-8 pt-8">
|
||||||
<div className="mb-4 flex items-center justify-between">
|
<div className="mb-4 flex items-center justify-between">
|
||||||
<div className="title-2xl-semi-bold text-text-primary">
|
<div className="title-2xl-semi-bold text-text-primary">
|
||||||
{t(`${I18N_PREFIX}.title`)}
|
{t(`${I18N_PREFIX}.title`, { ns: 'app' })}
|
||||||
{t(`app.tracing.${type}.title`)}
|
{t(`tracing.${type}.title`, { ns: 'app' })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -317,7 +317,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as ArizeConfig).api_key}
|
value={(config as ArizeConfig).api_key}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label="Space ID"
|
label="Space ID"
|
||||||
|
|
@ -325,15 +325,15 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as ArizeConfig).space_id}
|
value={(config as ArizeConfig).space_id}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.project`)!}
|
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as ArizeConfig).project}
|
value={(config as ArizeConfig).project}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label="Endpoint"
|
label="Endpoint"
|
||||||
|
|
@ -352,15 +352,15 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as PhoenixConfig).api_key}
|
value={(config as PhoenixConfig).api_key}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.project`)!}
|
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as PhoenixConfig).project}
|
value={(config as PhoenixConfig).project}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label="Endpoint"
|
label="Endpoint"
|
||||||
|
|
@ -379,7 +379,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as AliyunConfig).license_key}
|
value={(config as AliyunConfig).license_key}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label="Endpoint"
|
label="Endpoint"
|
||||||
|
|
@ -404,7 +404,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as TencentConfig).token}
|
value={(config as TencentConfig).token}
|
||||||
onChange={handleConfigChange('token')}
|
onChange={handleConfigChange('token')}
|
||||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'Token' })!}
|
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'Token' })!}
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
label="Endpoint"
|
label="Endpoint"
|
||||||
|
|
@ -432,22 +432,22 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as WeaveConfig).api_key}
|
value={(config as WeaveConfig).api_key}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.project`)!}
|
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as WeaveConfig).project}
|
value={(config as WeaveConfig).project}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label="Entity"
|
label="Entity"
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as WeaveConfig).entity}
|
value={(config as WeaveConfig).entity}
|
||||||
onChange={handleConfigChange('entity')}
|
onChange={handleConfigChange('entity')}
|
||||||
placeholder={t(`${I18N_PREFIX}.placeholder`, { key: 'Entity' })!}
|
placeholder={t(`${I18N_PREFIX}.placeholder`, { ns: 'app', key: 'Entity' })!}
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
label="Endpoint"
|
label="Endpoint"
|
||||||
|
|
@ -473,15 +473,15 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as LangSmithConfig).api_key}
|
value={(config as LangSmithConfig).api_key}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.project`)!}
|
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as LangSmithConfig).project}
|
value={(config as LangSmithConfig).project}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label="Endpoint"
|
label="Endpoint"
|
||||||
|
|
@ -495,20 +495,20 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
{type === TracingProvider.langfuse && (
|
{type === TracingProvider.langfuse && (
|
||||||
<>
|
<>
|
||||||
<Field
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.secretKey`)!}
|
label={t(`${I18N_PREFIX}.secretKey`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as LangFuseConfig).secret_key}
|
value={(config as LangFuseConfig).secret_key}
|
||||||
isRequired
|
isRequired
|
||||||
onChange={handleConfigChange('secret_key')}
|
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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.publicKey`)!}
|
label={t(`${I18N_PREFIX}.publicKey`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as LangFuseConfig).public_key}
|
value={(config as LangFuseConfig).public_key}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label="Host"
|
label="Host"
|
||||||
|
|
@ -527,14 +527,14 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as OpikConfig).api_key}
|
value={(config as OpikConfig).api_key}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.project`)!}
|
label={t(`${I18N_PREFIX}.project`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as OpikConfig).project}
|
value={(config as OpikConfig).project}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label="Workspace"
|
label="Workspace"
|
||||||
|
|
@ -555,7 +555,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
{type === TracingProvider.mlflow && (
|
{type === TracingProvider.mlflow && (
|
||||||
<>
|
<>
|
||||||
<Field
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.trackingUri`)!}
|
label={t(`${I18N_PREFIX}.trackingUri`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as MLflowConfig).tracking_uri}
|
value={(config as MLflowConfig).tracking_uri}
|
||||||
isRequired
|
isRequired
|
||||||
|
|
@ -563,67 +563,67 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
placeholder="http://localhost:5000"
|
placeholder="http://localhost:5000"
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.experimentId`)!}
|
label={t(`${I18N_PREFIX}.experimentId`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
isRequired
|
isRequired
|
||||||
value={(config as MLflowConfig).experiment_id}
|
value={(config as MLflowConfig).experiment_id}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.username`)!}
|
label={t(`${I18N_PREFIX}.username`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as MLflowConfig).username}
|
value={(config as MLflowConfig).username}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.password`)!}
|
label={t(`${I18N_PREFIX}.password`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as MLflowConfig).password}
|
value={(config as MLflowConfig).password}
|
||||||
onChange={handleConfigChange('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 && (
|
{type === TracingProvider.databricks && (
|
||||||
<>
|
<>
|
||||||
<Field
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.experimentId`)!}
|
label={t(`${I18N_PREFIX}.experimentId`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as DatabricksConfig).experiment_id}
|
value={(config as DatabricksConfig).experiment_id}
|
||||||
onChange={handleConfigChange('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
|
isRequired
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.databricksHost`)!}
|
label={t(`${I18N_PREFIX}.databricksHost`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as DatabricksConfig).host}
|
value={(config as DatabricksConfig).host}
|
||||||
onChange={handleConfigChange('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
|
isRequired
|
||||||
/>
|
/>
|
||||||
<Field
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.clientId`)!}
|
label={t(`${I18N_PREFIX}.clientId`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as DatabricksConfig).client_id}
|
value={(config as DatabricksConfig).client_id}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.clientSecret`)!}
|
label={t(`${I18N_PREFIX}.clientSecret`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as DatabricksConfig).client_secret}
|
value={(config as DatabricksConfig).client_secret}
|
||||||
onChange={handleConfigChange('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
|
<Field
|
||||||
label={t(`${I18N_PREFIX}.personalAccessToken`)!}
|
label={t(`${I18N_PREFIX}.personalAccessToken`, { ns: 'app' })!}
|
||||||
labelClassName="!text-sm"
|
labelClassName="!text-sm"
|
||||||
value={(config as DatabricksConfig).personal_access_token}
|
value={(config as DatabricksConfig).personal_access_token}
|
||||||
onChange={handleConfigChange('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"
|
target="_blank"
|
||||||
href={docURL[type]}
|
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" />
|
<LinkExternal02 className="h-3 w-3" />
|
||||||
</a>
|
</a>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
|
|
@ -644,7 +644,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
className="h-9 text-sm font-medium text-text-secondary"
|
className="h-9 text-sm font-medium text-text-secondary"
|
||||||
onClick={showRemoveConfirm}
|
onClick={showRemoveConfirm}
|
||||||
>
|
>
|
||||||
<span className="text-[#D92D20]">{t('common.operation.remove')}</span>
|
<span className="text-[#D92D20]">{t('operation.remove', { ns: 'common' })}</span>
|
||||||
</Button>
|
</Button>
|
||||||
<Divider type="vertical" className="mx-3 h-[18px]" />
|
<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"
|
className="mr-2 h-9 text-sm font-medium text-text-secondary"
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
>
|
>
|
||||||
{t('common.operation.cancel')}
|
{t('operation.cancel', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
className="h-9 text-sm font-medium"
|
className="h-9 text-sm font-medium"
|
||||||
|
|
@ -661,7 +661,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
loading={isSaving}
|
loading={isSaving}
|
||||||
>
|
>
|
||||||
{t(`common.operation.${isAdd ? 'saveAndEnable' : 'save'}`)}
|
{t(`operation.${isAdd ? 'saveAndEnable' : 'save'}`, { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -670,7 +670,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
<div className="border-t-[0.5px] border-divider-regular">
|
<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">
|
<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" />
|
<Lock01 className="mr-1 h-3 w-3 text-text-tertiary" />
|
||||||
{t('common.modelProvider.encrypted.front')}
|
{t('modelProvider.encrypted.front', { ns: 'common' })}
|
||||||
<a
|
<a
|
||||||
className="mx-1 text-primary-600"
|
className="mx-1 text-primary-600"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
|
@ -679,7 +679,7 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
>
|
>
|
||||||
PKCS1_OAEP
|
PKCS1_OAEP
|
||||||
</a>
|
</a>
|
||||||
{t('common.modelProvider.encrypted.back')}
|
{t('modelProvider.encrypted.back', { ns: 'common' })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -691,8 +691,8 @@ const ProviderConfigModal: FC<Props> = ({
|
||||||
<Confirm
|
<Confirm
|
||||||
isShow
|
isShow
|
||||||
type="warning"
|
type="warning"
|
||||||
title={t(`${I18N_PREFIX}.removeConfirmTitle`, { key: t(`app.tracing.${type}.title`) })!}
|
title={t(`${I18N_PREFIX}.removeConfirmTitle`, { ns: 'app', key: t(`tracing.${type}.title`, { ns: 'app' }) })!}
|
||||||
content={t(`${I18N_PREFIX}.removeConfirmContent`)}
|
content={t(`${I18N_PREFIX}.removeConfirmContent`, { ns: 'app' })}
|
||||||
onConfirm={handleRemove}
|
onConfirm={handleRemove}
|
||||||
onCancel={hideRemoveConfirm}
|
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 { cn } from '@/utils/classnames'
|
||||||
import { TracingProvider } from './type'
|
import { TracingProvider } from './type'
|
||||||
|
|
||||||
const I18N_PREFIX = 'app.tracing'
|
const I18N_PREFIX = 'tracing'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type: TracingProvider
|
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 justify-between space-x-1">
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Icon className="h-6" />
|
<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>
|
</div>
|
||||||
{!readOnly && (
|
{!readOnly && (
|
||||||
<div className="flex items-center justify-between space-x-1">
|
<div className="flex items-center justify-between space-x-1">
|
||||||
{hasConfigured && (
|
{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}>
|
<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" />
|
<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>
|
||||||
)}
|
)}
|
||||||
<div
|
<div
|
||||||
|
|
@ -97,13 +97,13 @@ const ProviderPanel: FC<Props> = ({
|
||||||
onClick={handleConfigBtnClick}
|
onClick={handleConfigBtnClick}
|
||||||
>
|
>
|
||||||
<RiEqualizer2Line className="h-3 w-3" />
|
<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>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<div className="system-xs-regular mt-2 text-text-tertiary">
|
<div className="system-xs-regular mt-2 text-text-tertiary">
|
||||||
{t(`${I18N_PREFIX}.${type}.description`)}
|
{t(`${I18N_PREFIX}.${type}.description`, { ns: 'app' })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ const AppDetail: FC<IAppDetail> = ({ children }) => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
useDocumentTitle(t('common.menus.appDetail'))
|
useDocumentTitle(t('menus.appDetail', { ns: 'common' }))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isCurrentWorkspaceDatasetOperator)
|
if (isCurrentWorkspaceDatasetOperator)
|
||||||
|
|
|
||||||
|
|
@ -70,14 +70,14 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||||
const navigation = useMemo(() => {
|
const navigation = useMemo(() => {
|
||||||
const baseNavigation = [
|
const baseNavigation = [
|
||||||
{
|
{
|
||||||
name: t('common.datasetMenus.hitTesting'),
|
name: t('datasetMenus.hitTesting', { ns: 'common' }),
|
||||||
href: `/datasets/${datasetId}/hitTesting`,
|
href: `/datasets/${datasetId}/hitTesting`,
|
||||||
icon: RiFocus2Line,
|
icon: RiFocus2Line,
|
||||||
selectedIcon: RiFocus2Fill,
|
selectedIcon: RiFocus2Fill,
|
||||||
disabled: isButtonDisabledWithPipeline,
|
disabled: isButtonDisabledWithPipeline,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t('common.datasetMenus.settings'),
|
name: t('datasetMenus.settings', { ns: 'common' }),
|
||||||
href: `/datasets/${datasetId}/settings`,
|
href: `/datasets/${datasetId}/settings`,
|
||||||
icon: RiEqualizer2Line,
|
icon: RiEqualizer2Line,
|
||||||
selectedIcon: RiEqualizer2Fill,
|
selectedIcon: RiEqualizer2Fill,
|
||||||
|
|
@ -87,14 +87,14 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||||
|
|
||||||
if (datasetRes?.provider !== 'external') {
|
if (datasetRes?.provider !== 'external') {
|
||||||
baseNavigation.unshift({
|
baseNavigation.unshift({
|
||||||
name: t('common.datasetMenus.pipeline'),
|
name: t('datasetMenus.pipeline', { ns: 'common' }),
|
||||||
href: `/datasets/${datasetId}/pipeline`,
|
href: `/datasets/${datasetId}/pipeline`,
|
||||||
icon: PipelineLine as RemixiconComponentType,
|
icon: PipelineLine as RemixiconComponentType,
|
||||||
selectedIcon: PipelineFill as RemixiconComponentType,
|
selectedIcon: PipelineFill as RemixiconComponentType,
|
||||||
disabled: false,
|
disabled: false,
|
||||||
})
|
})
|
||||||
baseNavigation.unshift({
|
baseNavigation.unshift({
|
||||||
name: t('common.datasetMenus.documents'),
|
name: t('datasetMenus.documents', { ns: 'common' }),
|
||||||
href: `/datasets/${datasetId}/documents`,
|
href: `/datasets/${datasetId}/documents`,
|
||||||
icon: RiFileTextLine,
|
icon: RiFileTextLine,
|
||||||
selectedIcon: RiFileTextFill,
|
selectedIcon: RiFileTextFill,
|
||||||
|
|
@ -105,7 +105,7 @@ const DatasetDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||||
return baseNavigation
|
return baseNavigation
|
||||||
}, [t, datasetId, isButtonDisabledWithPipeline, datasetRes?.provider])
|
}, [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)
|
const setAppSidebarExpand = useStore(state => state.setAppSidebarExpand)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
/* eslint-disable dify-i18n/require-ns-option */
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import Form from '@/app/components/datasets/settings/form'
|
import Form from '@/app/components/datasets/settings/form'
|
||||||
import { getLocaleOnServer, getTranslation } from '@/i18n-config/server'
|
import { getLocaleOnServer, getTranslation } from '@/i18n-config/server'
|
||||||
|
|
@ -9,7 +10,7 @@ const Settings = async () => {
|
||||||
return (
|
return (
|
||||||
<div className="h-full overflow-y-auto">
|
<div className="h-full overflow-y-auto">
|
||||||
<div className="flex flex-col gap-y-0.5 px-6 pb-2 pt-3">
|
<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 className="system-sm-regular text-text-tertiary">{t('desc')}</div>
|
||||||
</div>
|
</div>
|
||||||
<Form />
|
<Form />
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import useDocumentTitle from '@/hooks/use-document-title'
|
||||||
|
|
||||||
const ExploreLayout: FC<PropsWithChildren> = ({ children }) => {
|
const ExploreLayout: FC<PropsWithChildren> = ({ children }) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
useDocumentTitle(t('common.menus.explore'))
|
useDocumentTitle(t('menus.explore', { ns: 'common' }))
|
||||||
return (
|
return (
|
||||||
<ExploreClient>
|
<ExploreClient>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ const ToolsList: FC = () => {
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
useDocumentTitle(t('common.menus.tools'))
|
useDocumentTitle(t('menus.tools', { ns: 'common' }))
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isCurrentWorkspaceDatasetOperator)
|
if (isCurrentWorkspaceDatasetOperator)
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,7 @@ const AuthenticatedLayout = ({ children }: { children: React.ReactNode }) => {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col items-center justify-center gap-y-2">
|
<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." />
|
<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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -94,8 +94,8 @@ const Splash: FC<PropsWithChildren> = ({ children }) => {
|
||||||
if (message) {
|
if (message) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col items-center justify-center gap-y-4">
|
<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} />
|
<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('common.userProfile.logout') : t('share.login.backToHome')}</span>
|
<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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,14 +26,14 @@ export default function CheckCode() {
|
||||||
if (!code.trim()) {
|
if (!code.trim()) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.checkCode.emptyCode'),
|
message: t('checkCode.emptyCode', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!/\d{6}/.test(code)) {
|
if (!/\d{6}/.test(code)) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.checkCode.invalidCode'),
|
message: t('checkCode.invalidCode', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -69,22 +69,22 @@ export default function CheckCode() {
|
||||||
<RiMailSendFill className="h-6 w-6 text-2xl" />
|
<RiMailSendFill className="h-6 w-6 text-2xl" />
|
||||||
</div>
|
</div>
|
||||||
<div className="pb-4 pt-2">
|
<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">
|
<p className="body-md-regular mt-2 text-text-secondary">
|
||||||
<span>
|
<span>
|
||||||
{t('login.checkCode.tipsPrefix')}
|
{t('checkCode.tipsPrefix', { ns: 'login' })}
|
||||||
<strong>{email}</strong>
|
<strong>{email}</strong>
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
{t('login.checkCode.validTime')}
|
{t('checkCode.validTime', { ns: 'login' })}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form action="">
|
<form action="">
|
||||||
<input type="text" className="hidden" />
|
<input type="text" className="hidden" />
|
||||||
<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 value={code} onChange={e => setVerifyCode(e.target.value)} maxLength={6} className="mt-1" placeholder={t('login.checkCode.verificationCodePlaceholder') || ''} />
|
<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('login.checkCode.verify')}</Button>
|
<Button loading={loading} disabled={loading} className="my-3 w-full" variant="primary" onClick={verify}>{t('checkCode.verify', { ns: 'login' })}</Button>
|
||||||
<Countdown onResend={resendCode} />
|
<Countdown onResend={resendCode} />
|
||||||
</form>
|
</form>
|
||||||
<div className="py-2">
|
<div className="py-2">
|
||||||
|
|
@ -94,7 +94,7 @@ export default function CheckCode() {
|
||||||
<div className="bg-background-default-dimm inline-block rounded-full p-1">
|
<div className="bg-background-default-dimm inline-block rounded-full p-1">
|
||||||
<RiArrowLeftLine size={12} />
|
<RiArrowLeftLine size={12} />
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -27,14 +27,14 @@ export default function CheckCode() {
|
||||||
const handleGetEMailVerificationCode = async () => {
|
const handleGetEMailVerificationCode = async () => {
|
||||||
try {
|
try {
|
||||||
if (!email) {
|
if (!email) {
|
||||||
Toast.notify({ type: 'error', message: t('login.error.emailEmpty') })
|
Toast.notify({ type: 'error', message: t('error.emailEmpty', { ns: 'login' }) })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!emailRegex.test(email)) {
|
if (!emailRegex.test(email)) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.error.emailInValid'),
|
message: t('error.emailInValid', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +50,7 @@ export default function CheckCode() {
|
||||||
else if (res.code === 'account_not_found') {
|
else if (res.code === 'account_not_found') {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.error.registrationNotAllowed'),
|
message: t('error.registrationNotAllowed', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
@ -74,21 +74,21 @@ export default function CheckCode() {
|
||||||
<RiLockPasswordLine className="h-6 w-6 text-2xl text-text-accent-light-mode-only" />
|
<RiLockPasswordLine className="h-6 w-6 text-2xl text-text-accent-light-mode-only" />
|
||||||
</div>
|
</div>
|
||||||
<div className="pb-4 pt-2">
|
<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">
|
<p className="body-md-regular mt-2 text-text-secondary">
|
||||||
{t('login.resetPasswordDesc')}
|
{t('resetPasswordDesc', { ns: 'login' })}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form onSubmit={noop}>
|
<form onSubmit={noop}>
|
||||||
<input type="text" className="hidden" />
|
<input type="text" className="hidden" />
|
||||||
<div className="mb-2">
|
<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">
|
<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>
|
||||||
<div className="mt-3">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
@ -99,7 +99,7 @@ export default function CheckCode() {
|
||||||
<div className="inline-block rounded-full bg-background-default-dimmed p-1">
|
<div className="inline-block rounded-full bg-background-default-dimmed p-1">
|
||||||
<RiArrowLeftLine size={12} />
|
<RiArrowLeftLine size={12} />
|
||||||
</div>
|
</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>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -45,15 +45,15 @@ const ChangePasswordForm = () => {
|
||||||
|
|
||||||
const valid = useCallback(() => {
|
const valid = useCallback(() => {
|
||||||
if (!password.trim()) {
|
if (!password.trim()) {
|
||||||
showErrorMessage(t('login.error.passwordEmpty'))
|
showErrorMessage(t('error.passwordEmpty', { ns: 'login' }))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (!validPassword.test(password)) {
|
if (!validPassword.test(password)) {
|
||||||
showErrorMessage(t('login.error.passwordInvalid'))
|
showErrorMessage(t('error.passwordInvalid', { ns: 'login' }))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (password !== confirmPassword) {
|
if (password !== confirmPassword) {
|
||||||
showErrorMessage(t('common.account.notEqual'))
|
showErrorMessage(t('account.notEqual', { ns: 'common' }))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
@ -92,10 +92,10 @@ const ChangePasswordForm = () => {
|
||||||
<div className="flex flex-col md:w-[400px]">
|
<div className="flex flex-col md:w-[400px]">
|
||||||
<div className="mx-auto w-full">
|
<div className="mx-auto w-full">
|
||||||
<h2 className="title-4xl-semi-bold text-text-primary">
|
<h2 className="title-4xl-semi-bold text-text-primary">
|
||||||
{t('login.changePassword')}
|
{t('changePassword', { ns: 'login' })}
|
||||||
</h2>
|
</h2>
|
||||||
<p className="body-md-regular mt-2 text-text-secondary">
|
<p className="body-md-regular mt-2 text-text-secondary">
|
||||||
{t('login.changePasswordTip')}
|
{t('changePasswordTip', { ns: 'login' })}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
@ -104,7 +104,7 @@ const ChangePasswordForm = () => {
|
||||||
{/* Password */}
|
{/* Password */}
|
||||||
<div className="mb-5">
|
<div className="mb-5">
|
||||||
<label htmlFor="password" className="system-md-semibold my-2 text-text-secondary">
|
<label htmlFor="password" className="system-md-semibold my-2 text-text-secondary">
|
||||||
{t('common.account.newPassword')}
|
{t('account.newPassword', { ns: 'common' })}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative mt-1">
|
<div className="relative mt-1">
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -112,7 +112,7 @@ const ChangePasswordForm = () => {
|
||||||
type={showPassword ? 'text' : 'password'}
|
type={showPassword ? 'text' : 'password'}
|
||||||
value={password}
|
value={password}
|
||||||
onChange={e => setPassword(e.target.value)}
|
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">
|
<div className="absolute inset-y-0 right-0 flex items-center">
|
||||||
|
|
@ -125,12 +125,12 @@ const ChangePasswordForm = () => {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
{/* Confirm Password */}
|
{/* Confirm Password */}
|
||||||
<div className="mb-5">
|
<div className="mb-5">
|
||||||
<label htmlFor="confirmPassword" className="system-md-semibold my-2 text-text-secondary">
|
<label htmlFor="confirmPassword" className="system-md-semibold my-2 text-text-secondary">
|
||||||
{t('common.account.confirmPassword')}
|
{t('account.confirmPassword', { ns: 'common' })}
|
||||||
</label>
|
</label>
|
||||||
<div className="relative mt-1">
|
<div className="relative mt-1">
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -138,7 +138,7 @@ const ChangePasswordForm = () => {
|
||||||
type={showConfirmPassword ? 'text' : 'password'}
|
type={showConfirmPassword ? 'text' : 'password'}
|
||||||
value={confirmPassword}
|
value={confirmPassword}
|
||||||
onChange={e => setConfirmPassword(e.target.value)}
|
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">
|
<div className="absolute inset-y-0 right-0 flex items-center">
|
||||||
<Button
|
<Button
|
||||||
|
|
@ -157,7 +157,7 @@ const ChangePasswordForm = () => {
|
||||||
className="w-full"
|
className="w-full"
|
||||||
onClick={handleChangePassword}
|
onClick={handleChangePassword}
|
||||||
>
|
>
|
||||||
{t('login.changePasswordBtn')}
|
{t('changePasswordBtn', { ns: 'login' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -171,7 +171,7 @@ const ChangePasswordForm = () => {
|
||||||
<RiCheckboxCircleFill className="h-6 w-6 text-text-success" />
|
<RiCheckboxCircleFill className="h-6 w-6 text-text-success" />
|
||||||
</div>
|
</div>
|
||||||
<h2 className="title-4xl-semi-bold text-text-primary">
|
<h2 className="title-4xl-semi-bold text-text-primary">
|
||||||
{t('login.passwordChangedTip')}
|
{t('passwordChangedTip', { ns: 'login' })}
|
||||||
</h2>
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx-auto mt-6 w-full">
|
<div className="mx-auto mt-6 w-full">
|
||||||
|
|
@ -183,7 +183,7 @@ const ChangePasswordForm = () => {
|
||||||
router.replace(getSignInUrl())
|
router.replace(getSignInUrl())
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('login.passwordChanged')}
|
{t('passwordChanged', { ns: 'login' })}
|
||||||
{' '}
|
{' '}
|
||||||
(
|
(
|
||||||
{Math.round(countdown / 1000)}
|
{Math.round(countdown / 1000)}
|
||||||
|
|
|
||||||
|
|
@ -45,21 +45,21 @@ export default function CheckCode() {
|
||||||
if (!code.trim()) {
|
if (!code.trim()) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.checkCode.emptyCode'),
|
message: t('checkCode.emptyCode', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!/\d{6}/.test(code)) {
|
if (!/\d{6}/.test(code)) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.checkCode.invalidCode'),
|
message: t('checkCode.invalidCode', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!redirectUrl || !appCode) {
|
if (!redirectUrl || !appCode) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.error.redirectUrlMissing'),
|
message: t('error.redirectUrlMissing', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -108,19 +108,19 @@ export default function CheckCode() {
|
||||||
<RiMailSendFill className="h-6 w-6 text-2xl text-text-accent-light-mode-only" />
|
<RiMailSendFill className="h-6 w-6 text-2xl text-text-accent-light-mode-only" />
|
||||||
</div>
|
</div>
|
||||||
<div className="pb-4 pt-2">
|
<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">
|
<p className="body-md-regular mt-2 text-text-secondary">
|
||||||
<span>
|
<span>
|
||||||
{t('login.checkCode.tipsPrefix')}
|
{t('checkCode.tipsPrefix', { ns: 'login' })}
|
||||||
<strong>{email}</strong>
|
<strong>{email}</strong>
|
||||||
</span>
|
</span>
|
||||||
<br />
|
<br />
|
||||||
{t('login.checkCode.validTime')}
|
{t('checkCode.validTime', { ns: 'login' })}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<form onSubmit={handleSubmit}>
|
<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
|
<Input
|
||||||
ref={codeInputRef}
|
ref={codeInputRef}
|
||||||
id="code"
|
id="code"
|
||||||
|
|
@ -128,9 +128,9 @@ export default function CheckCode() {
|
||||||
onChange={e => setVerifyCode(e.target.value)}
|
onChange={e => setVerifyCode(e.target.value)}
|
||||||
maxLength={6}
|
maxLength={6}
|
||||||
className="mt-1"
|
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} />
|
<Countdown onResend={resendCode} />
|
||||||
</form>
|
</form>
|
||||||
<div className="py-2">
|
<div className="py-2">
|
||||||
|
|
@ -140,7 +140,7 @@ export default function CheckCode() {
|
||||||
<div className="bg-background-default-dimm inline-block rounded-full p-1">
|
<div className="bg-background-default-dimm inline-block rounded-full p-1">
|
||||||
<RiArrowLeftLine size={12} />
|
<RiArrowLeftLine size={12} />
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -23,14 +23,14 @@ export default function MailAndCodeAuth() {
|
||||||
const handleGetEMailVerificationCode = async () => {
|
const handleGetEMailVerificationCode = async () => {
|
||||||
try {
|
try {
|
||||||
if (!email) {
|
if (!email) {
|
||||||
Toast.notify({ type: 'error', message: t('login.error.emailEmpty') })
|
Toast.notify({ type: 'error', message: t('error.emailEmpty', { ns: 'login' }) })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!emailRegex.test(email)) {
|
if (!emailRegex.test(email)) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.error.emailInValid'),
|
message: t('error.emailInValid', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -56,12 +56,12 @@ export default function MailAndCodeAuth() {
|
||||||
<form onSubmit={noop}>
|
<form onSubmit={noop}>
|
||||||
<input type="text" className="hidden" />
|
<input type="text" className="hidden" />
|
||||||
<div className="mb-2">
|
<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">
|
<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>
|
||||||
<div className="mt-3">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -46,25 +46,25 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
||||||
const appCode = getAppCodeFromRedirectUrl()
|
const appCode = getAppCodeFromRedirectUrl()
|
||||||
const handleEmailPasswordLogin = async () => {
|
const handleEmailPasswordLogin = async () => {
|
||||||
if (!email) {
|
if (!email) {
|
||||||
Toast.notify({ type: 'error', message: t('login.error.emailEmpty') })
|
Toast.notify({ type: 'error', message: t('error.emailEmpty', { ns: 'login' }) })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!emailRegex.test(email)) {
|
if (!emailRegex.test(email)) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.error.emailInValid'),
|
message: t('error.emailInValid', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (!password?.trim()) {
|
if (!password?.trim()) {
|
||||||
Toast.notify({ type: 'error', message: t('login.error.passwordEmpty') })
|
Toast.notify({ type: 'error', message: t('error.passwordEmpty', { ns: 'login' }) })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!redirectUrl || !appCode) {
|
if (!redirectUrl || !appCode) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('login.error.redirectUrlMissing'),
|
message: t('error.redirectUrlMissing', { ns: 'login' }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -111,7 +111,7 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
||||||
<form onSubmit={noop}>
|
<form onSubmit={noop}>
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">
|
<label htmlFor="email" className="system-md-semibold my-2 text-text-secondary">
|
||||||
{t('login.email')}
|
{t('email', { ns: 'login' })}
|
||||||
</label>
|
</label>
|
||||||
<div className="mt-1">
|
<div className="mt-1">
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -120,7 +120,7 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
||||||
id="email"
|
id="email"
|
||||||
type="email"
|
type="email"
|
||||||
autoComplete="email"
|
autoComplete="email"
|
||||||
placeholder={t('login.emailPlaceholder') || ''}
|
placeholder={t('emailPlaceholder', { ns: 'login' }) || ''}
|
||||||
tabIndex={1}
|
tabIndex={1}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -128,14 +128,14 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
||||||
|
|
||||||
<div className="mb-3">
|
<div className="mb-3">
|
||||||
<label htmlFor="password" className="my-2 flex items-center justify-between">
|
<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
|
<Link
|
||||||
href={`/webapp-reset-password?${searchParams.toString()}`}
|
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'}`}
|
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}
|
tabIndex={isEmailSetup ? 0 : -1}
|
||||||
aria-disabled={!isEmailSetup}
|
aria-disabled={!isEmailSetup}
|
||||||
>
|
>
|
||||||
{t('login.forget')}
|
{t('forget', { ns: 'login' })}
|
||||||
</Link>
|
</Link>
|
||||||
</label>
|
</label>
|
||||||
<div className="relative mt-1">
|
<div className="relative mt-1">
|
||||||
|
|
@ -149,7 +149,7 @@ export default function MailAndPasswordAuth({ isEmailSetup }: MailAndPasswordAut
|
||||||
}}
|
}}
|
||||||
type={showPassword ? 'text' : 'password'}
|
type={showPassword ? 'text' : 'password'}
|
||||||
autoComplete="current-password"
|
autoComplete="current-password"
|
||||||
placeholder={t('login.passwordPlaceholder') || ''}
|
placeholder={t('passwordPlaceholder', { ns: 'login' }) || ''}
|
||||||
tabIndex={2}
|
tabIndex={2}
|
||||||
/>
|
/>
|
||||||
<div className="absolute inset-y-0 right-0 flex items-center">
|
<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}
|
disabled={isLoading || !email || !password}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
{t('login.signBtn')}
|
{t('signBtn', { ns: 'login' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
|
||||||
|
|
@ -82,7 +82,7 @@ const SSOAuth: FC<SSOAuthProps> = ({
|
||||||
className="w-full"
|
className="w-full"
|
||||||
>
|
>
|
||||||
<Lock01 className="mr-2 h-5 w-5 text-text-accent-light-mode-only" />
|
<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>
|
</Button>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import { cn } from '@/utils/classnames'
|
||||||
export default function SignInLayout({ children }: PropsWithChildren) {
|
export default function SignInLayout({ children }: PropsWithChildren) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||||
useDocumentTitle(t('login.webapp.login'))
|
useDocumentTitle(t('webapp.login', { ns: 'login' }))
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={cn('flex min-h-screen w-full justify-center bg-background-default-burn p-6')}>
|
<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" />
|
<RiContractLine className="h-5 w-5" />
|
||||||
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
|
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
|
||||||
</div>
|
</div>
|
||||||
<p className="system-sm-medium text-text-primary">{t('login.licenseLost')}</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('login.licenseLostTip')}</p>
|
<p className="system-xs-regular mt-1 text-text-tertiary">{t('licenseLostTip', { ns: 'login' })}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -76,8 +76,8 @@ const NormalForm = () => {
|
||||||
<RiContractLine className="h-5 w-5" />
|
<RiContractLine className="h-5 w-5" />
|
||||||
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
|
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
|
||||||
</div>
|
</div>
|
||||||
<p className="system-sm-medium text-text-primary">{t('login.licenseExpired')}</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('login.licenseExpiredTip')}</p>
|
<p className="system-xs-regular mt-1 text-text-tertiary">{t('licenseExpiredTip', { ns: 'login' })}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -92,8 +92,8 @@ const NormalForm = () => {
|
||||||
<RiContractLine className="h-5 w-5" />
|
<RiContractLine className="h-5 w-5" />
|
||||||
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
|
<RiErrorWarningFill className="absolute -right-1 -top-1 h-4 w-4 text-text-warning-secondary" />
|
||||||
</div>
|
</div>
|
||||||
<p className="system-sm-medium text-text-primary">{t('login.licenseInactive')}</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('login.licenseInactiveTip')}</p>
|
<p className="system-xs-regular mt-1 text-text-tertiary">{t('licenseInactiveTip', { ns: 'login' })}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -104,8 +104,8 @@ const NormalForm = () => {
|
||||||
<>
|
<>
|
||||||
<div className="mx-auto mt-8 w-full">
|
<div className="mx-auto mt-8 w-full">
|
||||||
<div className="mx-auto 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>
|
<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('login.welcome')}</p>
|
<p className="body-md-regular mt-2 text-text-tertiary">{t('welcome', { ns: 'login' })}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<div className="mt-6 flex flex-col gap-3">
|
<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 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>
|
||||||
<div className="relative flex justify-center">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -134,7 +134,7 @@ const NormalForm = () => {
|
||||||
<MailAndCodeAuth />
|
<MailAndCodeAuth />
|
||||||
{systemFeatures.enable_email_password_login && (
|
{systemFeatures.enable_email_password_login && (
|
||||||
<div className="cursor-pointer py-1 text-center" onClick={() => { updateAuthType('password') }}>
|
<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>
|
</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
|
|
@ -144,7 +144,7 @@ const NormalForm = () => {
|
||||||
<MailAndPasswordAuth isEmailSetup={systemFeatures.is_email_setup} />
|
<MailAndPasswordAuth isEmailSetup={systemFeatures.is_email_setup} />
|
||||||
{systemFeatures.enable_email_code_login && (
|
{systemFeatures.enable_email_code_login && (
|
||||||
<div className="cursor-pointer py-1 text-center" onClick={() => { updateAuthType('code') }}>
|
<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>
|
</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">
|
<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" />
|
<RiDoorLockLine className="h-5 w-5" />
|
||||||
</div>
|
</div>
|
||||||
<p className="system-sm-medium text-text-primary">{t('login.noLoginMethod')}</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('login.noLoginMethodTip')}</p>
|
<p className="system-xs-regular mt-1 text-text-tertiary">{t('noLoginMethodTip', { ns: 'login' })}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="relative my-2 py-2">
|
<div className="relative my-2 py-2">
|
||||||
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
<div className="absolute inset-0 flex items-center" aria-hidden="true">
|
||||||
|
|
@ -171,7 +171,7 @@ const NormalForm = () => {
|
||||||
{!systemFeatures.branding.enabled && (
|
{!systemFeatures.branding.enabled && (
|
||||||
<>
|
<>
|
||||||
<div className="system-xs-regular mt-2 block w-full text-text-tertiary">
|
<div className="system-xs-regular mt-2 block w-full text-text-tertiary">
|
||||||
{t('login.tosDesc')}
|
{t('tosDesc', { ns: 'login' })}
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
className="system-xs-medium text-text-secondary hover:underline"
|
className="system-xs-medium text-text-secondary hover:underline"
|
||||||
|
|
@ -179,7 +179,7 @@ const NormalForm = () => {
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="https://dify.ai/terms"
|
href="https://dify.ai/terms"
|
||||||
>
|
>
|
||||||
{t('login.tos')}
|
{t('tos', { ns: 'login' })}
|
||||||
</Link>
|
</Link>
|
||||||
&
|
&
|
||||||
<Link
|
<Link
|
||||||
|
|
@ -188,18 +188,18 @@ const NormalForm = () => {
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
href="https://dify.ai/privacy"
|
href="https://dify.ai/privacy"
|
||||||
>
|
>
|
||||||
{t('login.pp')}
|
{t('pp', { ns: 'login' })}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{IS_CE_EDITION && (
|
{IS_CE_EDITION && (
|
||||||
<div className="w-hull system-xs-regular mt-2 block text-text-tertiary">
|
<div className="w-hull system-xs-regular mt-2 block text-text-tertiary">
|
||||||
{t('login.goToInit')}
|
{t('goToInit', { ns: 'login' })}
|
||||||
|
|
||||||
<Link
|
<Link
|
||||||
className="system-xs-medium text-text-secondary hover:underline"
|
className="system-xs-medium text-text-secondary hover:underline"
|
||||||
href="/install"
|
href="/install"
|
||||||
>
|
>
|
||||||
{t('login.setAdminAccount')}
|
{t('setAdminAccount', { ns: 'login' })}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ const WebSSOForm: FC = () => {
|
||||||
if (!redirectUrl) {
|
if (!redirectUrl) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full items-center justify-center">
|
<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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -45,7 +45,7 @@ const WebSSOForm: FC = () => {
|
||||||
if (!systemFeatures.webapp_auth.enabled) {
|
if (!systemFeatures.webapp_auth.enabled) {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full items-center justify-center">
|
<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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -63,7 +63,7 @@ const WebSSOForm: FC = () => {
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col items-center justify-center gap-y-4">
|
<div className="flex h-full flex-col items-center justify-center gap-y-4">
|
||||||
<AppUnavailable className="h-auto w-auto" isUnknownReason={true} />
|
<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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
|
||||||
await updateUserProfile({ url: 'account/avatar', body: { avatar: uploadedFileId } })
|
await updateUserProfile({ url: 'account/avatar', body: { avatar: uploadedFileId } })
|
||||||
setIsShowAvatarPicker(false)
|
setIsShowAvatarPicker(false)
|
||||||
onSave?.()
|
onSave?.()
|
||||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
notify({ type: 'success', message: t('actionMsg.modifiedSuccessfully', { ns: 'common' }) })
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
notify({ type: 'error', message: (e as Error).message })
|
notify({ type: 'error', message: (e as Error).message })
|
||||||
|
|
@ -58,7 +58,7 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
|
||||||
const handleDeleteAvatar = useCallback(async () => {
|
const handleDeleteAvatar = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
await updateUserProfile({ url: 'account/avatar', body: { avatar: '' } })
|
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)
|
setIsShowDeleteConfirm(false)
|
||||||
onSave?.()
|
onSave?.()
|
||||||
}
|
}
|
||||||
|
|
@ -145,11 +145,11 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
|
||||||
|
|
||||||
<div className="flex w-full items-center justify-center gap-2 p-3">
|
<div className="flex w-full items-center justify-center gap-2 p-3">
|
||||||
<Button className="w-full" onClick={() => setIsShowAvatarPicker(false)}>
|
<Button className="w-full" onClick={() => setIsShowAvatarPicker(false)}>
|
||||||
{t('app.iconPicker.cancel')}
|
{t('iconPicker.cancel', { ns: 'app' })}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button variant="primary" className="w-full" disabled={uploading || !inputImageInfo} loading={uploading} onClick={handleSelect}>
|
<Button variant="primary" className="w-full" disabled={uploading || !inputImageInfo} loading={uploading} onClick={handleSelect}>
|
||||||
{t('app.iconPicker.ok')}
|
{t('iconPicker.ok', { ns: 'app' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
@ -160,16 +160,16 @@ const AvatarWithEdit = ({ onSave, ...props }: AvatarWithEditProps) => {
|
||||||
isShow={isShowDeleteConfirm}
|
isShow={isShowDeleteConfirm}
|
||||||
onClose={() => setIsShowDeleteConfirm(false)}
|
onClose={() => setIsShowDeleteConfirm(false)}
|
||||||
>
|
>
|
||||||
<div className="title-2xl-semi-bold mb-3 text-text-primary">{t('common.avatar.deleteTitle')}</div>
|
<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('common.avatar.deleteDescription')}</p>
|
<p className="mb-8 text-text-secondary">{t('avatar.deleteDescription', { ns: 'common' })}</p>
|
||||||
|
|
||||||
<div className="flex w-full items-center justify-center gap-2">
|
<div className="flex w-full items-center justify-center gap-2">
|
||||||
<Button className="w-full" onClick={() => setIsShowDeleteConfirm(false)}>
|
<Button className="w-full" onClick={() => setIsShowDeleteConfirm(false)}>
|
||||||
{t('common.operation.cancel')}
|
{t('operation.cancel', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button variant="warning" className="w-full" onClick={handleDeleteAvatar}>
|
<Button variant="warning" className="w-full" onClick={handleDeleteAvatar}>
|
||||||
{t('common.operation.delete')}
|
{t('operation.delete', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
||||||
|
|
@ -209,9 +209,9 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
{step === STEP.start && (
|
{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="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">
|
<div className="body-md-regular text-text-secondary">
|
||||||
<Trans
|
<Trans
|
||||||
i18nKey="common.account.changeEmail.content1"
|
i18nKey="common.account.changeEmail.content1"
|
||||||
|
|
@ -227,20 +227,20 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={sendCodeToOriginEmail}
|
onClick={sendCodeToOriginEmail}
|
||||||
>
|
>
|
||||||
{t('common.account.changeEmail.sendVerifyCode')}
|
{t('account.changeEmail.sendVerifyCode', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
>
|
>
|
||||||
{t('common.operation.cancel')}
|
{t('operation.cancel', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{step === STEP.verifyOrigin && (
|
{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="space-y-0.5 pb-2 pt-1">
|
||||||
<div className="body-md-regular text-text-secondary">
|
<div className="body-md-regular text-text-secondary">
|
||||||
<Trans
|
<Trans
|
||||||
|
|
@ -251,10 +251,10 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="pt-3">
|
<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
|
<Input
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
placeholder={t('common.account.changeEmail.codePlaceholder')}
|
placeholder={t('account.changeEmail.codePlaceholder', { ns: 'common' })}
|
||||||
value={code}
|
value={code}
|
||||||
onChange={e => setCode(e.target.value)}
|
onChange={e => setCode(e.target.value)}
|
||||||
maxLength={6}
|
maxLength={6}
|
||||||
|
|
@ -267,46 +267,46 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={handleVerifyOriginEmail}
|
onClick={handleVerifyOriginEmail}
|
||||||
>
|
>
|
||||||
{t('common.account.changeEmail.continue')}
|
{t('account.changeEmail.continue', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
>
|
>
|
||||||
{t('common.operation.cancel')}
|
{t('operation.cancel', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="system-xs-regular mt-3 flex items-center gap-1 text-text-tertiary">
|
<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 && (
|
{time > 0 && (
|
||||||
<span>{t('common.account.changeEmail.resendCount', { count: time })}</span>
|
<span>{t('account.changeEmail.resendCount', { ns: 'common', count: time })}</span>
|
||||||
)}
|
)}
|
||||||
{!time && (
|
{!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>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{step === STEP.newEmail && (
|
{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="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>
|
||||||
<div className="pt-3">
|
<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
|
<Input
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
placeholder={t('common.account.changeEmail.emailPlaceholder')}
|
placeholder={t('account.changeEmail.emailPlaceholder', { ns: 'common' })}
|
||||||
value={mail}
|
value={mail}
|
||||||
onChange={e => handleNewEmailValueChange(e.target.value)}
|
onChange={e => handleNewEmailValueChange(e.target.value)}
|
||||||
destructive={newEmailExited || unAvailableEmail}
|
destructive={newEmailExited || unAvailableEmail}
|
||||||
/>
|
/>
|
||||||
{newEmailExited && (
|
{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 && (
|
{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>
|
||||||
<div className="mt-3 space-y-2">
|
<div className="mt-3 space-y-2">
|
||||||
|
|
@ -316,20 +316,20 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={sendCodeToNewEmail}
|
onClick={sendCodeToNewEmail}
|
||||||
>
|
>
|
||||||
{t('common.account.changeEmail.sendVerifyCode')}
|
{t('account.changeEmail.sendVerifyCode', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
>
|
>
|
||||||
{t('common.operation.cancel')}
|
{t('operation.cancel', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
{step === STEP.verifyNew && (
|
{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="space-y-0.5 pb-2 pt-1">
|
||||||
<div className="body-md-regular text-text-secondary">
|
<div className="body-md-regular text-text-secondary">
|
||||||
<Trans
|
<Trans
|
||||||
|
|
@ -340,10 +340,10 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="pt-3">
|
<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
|
<Input
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
placeholder={t('common.account.changeEmail.codePlaceholder')}
|
placeholder={t('account.changeEmail.codePlaceholder', { ns: 'common' })}
|
||||||
value={code}
|
value={code}
|
||||||
onChange={e => setCode(e.target.value)}
|
onChange={e => setCode(e.target.value)}
|
||||||
maxLength={6}
|
maxLength={6}
|
||||||
|
|
@ -356,22 +356,22 @@ const EmailChangeModal = ({ onClose, email, show }: Props) => {
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={submitNewEmail}
|
onClick={submitNewEmail}
|
||||||
>
|
>
|
||||||
{t('common.account.changeEmail.changeTo', { email: mail })}
|
{t('account.changeEmail.changeTo', { ns: 'common', email: mail })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
className="!w-full"
|
className="!w-full"
|
||||||
onClick={onClose}
|
onClick={onClose}
|
||||||
>
|
>
|
||||||
{t('common.operation.cancel')}
|
{t('operation.cancel', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className="system-xs-regular mt-3 flex items-center gap-1 text-text-tertiary">
|
<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 && (
|
{time > 0 && (
|
||||||
<span>{t('common.account.changeEmail.resendCount', { count: time })}</span>
|
<span>{t('account.changeEmail.resendCount', { ns: 'common', count: time })}</span>
|
||||||
)}
|
)}
|
||||||
{!time && (
|
{!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>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ export default function AccountPage() {
|
||||||
try {
|
try {
|
||||||
setEditing(true)
|
setEditing(true)
|
||||||
await updateUserProfile({ url: 'account/name', body: { name: editName } })
|
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()
|
mutateUserProfile()
|
||||||
setEditNameModalVisible(false)
|
setEditNameModalVisible(false)
|
||||||
setEditing(false)
|
setEditing(false)
|
||||||
|
|
@ -80,15 +80,15 @@ export default function AccountPage() {
|
||||||
}
|
}
|
||||||
const valid = () => {
|
const valid = () => {
|
||||||
if (!password.trim()) {
|
if (!password.trim()) {
|
||||||
showErrorMessage(t('login.error.passwordEmpty'))
|
showErrorMessage(t('error.passwordEmpty', { ns: 'login' }))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (!validPassword.test(password)) {
|
if (!validPassword.test(password)) {
|
||||||
showErrorMessage(t('login.error.passwordInvalid'))
|
showErrorMessage(t('error.passwordInvalid', { ns: 'login' }))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (password !== confirmPassword) {
|
if (password !== confirmPassword) {
|
||||||
showErrorMessage(t('common.account.notEqual'))
|
showErrorMessage(t('account.notEqual', { ns: 'common' }))
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,7 +112,7 @@ export default function AccountPage() {
|
||||||
repeat_new_password: confirmPassword,
|
repeat_new_password: confirmPassword,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
notify({ type: 'success', message: t('common.actionMsg.modifiedSuccessfully') })
|
notify({ type: 'success', message: t('actionMsg.modifiedSuccessfully', { ns: 'common' }) })
|
||||||
mutateUserProfile()
|
mutateUserProfile()
|
||||||
setEditPasswordModalVisible(false)
|
setEditPasswordModalVisible(false)
|
||||||
resetPasswordForm()
|
resetPasswordForm()
|
||||||
|
|
@ -146,7 +146,7 @@ export default function AccountPage() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="pb-3 pt-2">
|
<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>
|
||||||
<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">
|
<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} />
|
<AvatarWithEdit avatar={userProfile.avatar_url} name={userProfile.name} onSave={mutateUserProfile} size={64} />
|
||||||
|
|
@ -164,25 +164,25 @@ export default function AccountPage() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-8">
|
<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="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 ">
|
<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>
|
<span className="pl-1">{userProfile.name}</span>
|
||||||
</div>
|
</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}>
|
<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>
|
||||||
</div>
|
</div>
|
||||||
<div className="mb-8">
|
<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="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 ">
|
<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>
|
<span className="pl-1">{userProfile.email}</span>
|
||||||
</div>
|
</div>
|
||||||
{systemFeatures.enable_change_email && (
|
{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)}>
|
<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>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -191,26 +191,26 @@ export default function AccountPage() {
|
||||||
systemFeatures.enable_email_password_login && (
|
systemFeatures.enable_email_password_login && (
|
||||||
<div className="mb-8 flex justify-between gap-2">
|
<div className="mb-8 flex justify-between gap-2">
|
||||||
<div>
|
<div>
|
||||||
<div className="system-sm-semibold mb-1 text-text-secondary">{t('common.account.password')}</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('common.account.passwordTip')}</div>
|
<div className="body-xs-regular mb-2 text-text-tertiary">{t('account.passwordTip', { ns: 'common' })}</div>
|
||||||
</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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div className="mb-6 border-[1px] border-divider-subtle" />
|
<div className="mb-6 border-[1px] border-divider-subtle" />
|
||||||
<div className="mb-8">
|
<div className="mb-8">
|
||||||
<div className={titleClassName}>{t('common.account.langGeniusAccount')}</div>
|
<div className={titleClassName}>{t('account.langGeniusAccount', { ns: 'common' })}</div>
|
||||||
<div className={descriptionClassName}>{t('common.account.langGeniusAccountTip')}</div>
|
<div className={descriptionClassName}>{t('account.langGeniusAccountTip', { ns: 'common' })}</div>
|
||||||
{!!apps.length && (
|
{!!apps.length && (
|
||||||
<Collapse
|
<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 }))}
|
items={apps.map((app: App) => ({ ...app, key: app.id, name: app.name }))}
|
||||||
renderItem={renderAppItem}
|
renderItem={renderAppItem}
|
||||||
wrapperClassName="mt-2"
|
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>
|
</div>
|
||||||
{
|
{
|
||||||
editNameModalVisible && (
|
editNameModalVisible && (
|
||||||
|
|
@ -219,21 +219,21 @@ export default function AccountPage() {
|
||||||
onClose={() => setEditNameModalVisible(false)}
|
onClose={() => setEditNameModalVisible(false)}
|
||||||
className="!w-[420px] !p-6"
|
className="!w-[420px] !p-6"
|
||||||
>
|
>
|
||||||
<div className="title-2xl-semi-bold mb-6 text-text-primary">{t('common.account.editName')}</div>
|
<div className="title-2xl-semi-bold mb-6 text-text-primary">{t('account.editName', { ns: 'common' })}</div>
|
||||||
<div className={titleClassName}>{t('common.account.name')}</div>
|
<div className={titleClassName}>{t('account.name', { ns: 'common' })}</div>
|
||||||
<Input
|
<Input
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
value={editName}
|
value={editName}
|
||||||
onChange={e => setEditName(e.target.value)}
|
onChange={e => setEditName(e.target.value)}
|
||||||
/>
|
/>
|
||||||
<div className="mt-10 flex justify-end">
|
<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
|
<Button
|
||||||
disabled={editing || !editName}
|
disabled={editing || !editName}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={handleSaveName}
|
onClick={handleSaveName}
|
||||||
>
|
>
|
||||||
{t('common.operation.save')}
|
{t('operation.save', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
@ -249,10 +249,10 @@ export default function AccountPage() {
|
||||||
}}
|
}}
|
||||||
className="!w-[420px] !p-6"
|
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 && (
|
{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">
|
<div className="relative mt-2">
|
||||||
<Input
|
<Input
|
||||||
type={showCurrentPassword ? 'text' : 'password'}
|
type={showCurrentPassword ? 'text' : 'password'}
|
||||||
|
|
@ -273,7 +273,7 @@ export default function AccountPage() {
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<div className="system-sm-semibold mt-8 text-text-secondary">
|
<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>
|
||||||
<div className="relative mt-2">
|
<div className="relative mt-2">
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -291,7 +291,7 @@ export default function AccountPage() {
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</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">
|
<div className="relative mt-2">
|
||||||
<Input
|
<Input
|
||||||
type={showConfirmPassword ? 'text' : 'password'}
|
type={showConfirmPassword ? 'text' : 'password'}
|
||||||
|
|
@ -316,14 +316,14 @@ export default function AccountPage() {
|
||||||
resetPasswordForm()
|
resetPasswordForm()
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('common.operation.cancel')}
|
{t('operation.cancel', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
disabled={editing}
|
disabled={editing}
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={handleSavePassword}
|
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>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</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"
|
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" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
|
|
|
||||||
|
|
@ -31,22 +31,22 @@ export default function CheckEmail(props: DeleteAccountProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="body-md-medium py-1 text-text-destructive">
|
<div className="body-md-medium py-1 text-text-destructive">
|
||||||
{t('common.account.deleteTip')}
|
{t('account.deleteTip', { ns: 'common' })}
|
||||||
</div>
|
</div>
|
||||||
<div className="body-md-regular pb-2 pt-1 text-text-secondary">
|
<div className="body-md-regular pb-2 pt-1 text-text-secondary">
|
||||||
{t('common.account.deletePrivacyLinkTip')}
|
{t('account.deletePrivacyLinkTip', { ns: 'common' })}
|
||||||
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('common.account.deletePrivacyLink')}</Link>
|
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('account.deletePrivacyLink', { ns: 'common' })}</Link>
|
||||||
</div>
|
</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
|
<Input
|
||||||
placeholder={t('common.account.deletePlaceholder') as string}
|
placeholder={t('account.deletePlaceholder', { ns: 'common' }) as string}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setUserInputEmail(e.target.value)
|
setUserInputEmail(e.target.value)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="mt-3 flex w-full flex-col gap-2">
|
<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" 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('common.operation.cancel')}</Button>
|
<Button className="w-full" onClick={props.onCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ export default function FeedBack(props: DeleteAccountProps) {
|
||||||
await logout()
|
await logout()
|
||||||
// Tokens are now stored in cookies and cleared by backend
|
// Tokens are now stored in cookies and cleared by backend
|
||||||
router.push('/signin')
|
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) }
|
catch (error) { console.error(error) }
|
||||||
}, [router, t])
|
}, [router, t])
|
||||||
|
|
@ -50,22 +50,22 @@ export default function FeedBack(props: DeleteAccountProps) {
|
||||||
<CustomDialog
|
<CustomDialog
|
||||||
show={true}
|
show={true}
|
||||||
onClose={props.onCancel}
|
onClose={props.onCancel}
|
||||||
title={t('common.account.feedbackTitle')}
|
title={t('account.feedbackTitle', { ns: 'common' })}
|
||||||
className="max-w-[480px]"
|
className="max-w-[480px]"
|
||||||
footer={false}
|
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
|
<Textarea
|
||||||
rows={6}
|
rows={6}
|
||||||
value={userFeedback}
|
value={userFeedback}
|
||||||
placeholder={t('common.account.feedbackPlaceholder') as string}
|
placeholder={t('account.feedbackPlaceholder', { ns: 'common' }) as string}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setUserFeedback(e.target.value)
|
setUserFeedback(e.target.value)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="mt-3 flex w-full flex-col gap-2">
|
<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" loading={isPending} variant="primary" onClick={handleSubmit}>{t('operation.submit', { ns: 'common' })}</Button>
|
||||||
<Button className="w-full" onClick={handleSkip}>{t('common.operation.skip')}</Button>
|
<Button className="w-full" onClick={handleSkip}>{t('operation.skip', { ns: 'common' })}</Button>
|
||||||
</div>
|
</div>
|
||||||
</CustomDialog>
|
</CustomDialog>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -37,24 +37,24 @@ export default function VerifyEmail(props: DeleteAccountProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="body-md-medium pt-1 text-text-destructive">
|
<div className="body-md-medium pt-1 text-text-destructive">
|
||||||
{t('common.account.deleteTip')}
|
{t('account.deleteTip', { ns: 'common' })}
|
||||||
</div>
|
</div>
|
||||||
<div className="body-md-regular pb-2 pt-1 text-text-secondary">
|
<div className="body-md-regular pb-2 pt-1 text-text-secondary">
|
||||||
{t('common.account.deletePrivacyLinkTip')}
|
{t('account.deletePrivacyLinkTip', { ns: 'common' })}
|
||||||
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('common.account.deletePrivacyLink')}</Link>
|
<Link href="https://dify.ai/privacy" className="text-text-accent">{t('account.deletePrivacyLink', { ns: 'common' })}</Link>
|
||||||
</div>
|
</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
|
<Input
|
||||||
minLength={6}
|
minLength={6}
|
||||||
maxLength={6}
|
maxLength={6}
|
||||||
placeholder={t('common.account.verificationPlaceholder') as string}
|
placeholder={t('account.verificationPlaceholder', { ns: 'common' }) as string}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setVerificationCode(e.target.value)
|
setVerificationCode(e.target.value)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div className="mt-3 flex w-full flex-col gap-2">
|
<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" disabled={shouldButtonDisabled} loading={isDeleting} variant="warning" onClick={handleConfirm}>{t('account.permanentlyDeleteButton', { ns: 'common' })}</Button>
|
||||||
<Button className="w-full" onClick={props.onCancel}>{t('common.operation.cancel')}</Button>
|
<Button className="w-full" onClick={props.onCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||||
<Countdown onResend={sendEmail} />
|
<Countdown onResend={sendEmail} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ export default function DeleteAccount(props: DeleteAccountProps) {
|
||||||
<CustomDialog
|
<CustomDialog
|
||||||
show={true}
|
show={true}
|
||||||
onClose={props.onCancel}
|
onClose={props.onCancel}
|
||||||
title={t('common.account.delete')}
|
title={t('account.delete', { ns: 'common' })}
|
||||||
className="max-w-[480px]"
|
className="max-w-[480px]"
|
||||||
footer={false}
|
footer={false}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -32,12 +32,12 @@ const Header = () => {
|
||||||
: <DifyLogo />}
|
: <DifyLogo />}
|
||||||
</div>
|
</div>
|
||||||
<div className="h-4 w-[1px] origin-center rotate-[11.31deg] bg-divider-regular" />
|
<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>
|
||||||
<div className="flex shrink-0 items-center gap-3">
|
<div className="flex shrink-0 items-center gap-3">
|
||||||
<Button className="system-sm-medium gap-2 px-3 py-2" onClick={goToStudio}>
|
<Button className="system-sm-medium gap-2 px-3 py-2" onClick={goToStudio}>
|
||||||
<RiRobot2Line className="h-4 w-4" />
|
<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" />
|
<RiArrowRightUpLine className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
<div className="h-4 w-[1px] bg-divider-regular" />
|
<div className="h-4 w-[1px] bg-divider-regular" />
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ import AccountPage from './account-page'
|
||||||
|
|
||||||
export default function Account() {
|
export default function Account() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
useDocumentTitle(t('common.menus.account'))
|
useDocumentTitle(t('menus.account', { ns: 'common' }))
|
||||||
return (
|
return (
|
||||||
<div className="mx-auto w-full max-w-[640px] px-6 pt-12">
|
<div className="mx-auto w-full max-w-[640px] px-6 pt-12">
|
||||||
<AccountPage />
|
<AccountPage />
|
||||||
|
|
|
||||||
|
|
@ -50,23 +50,23 @@ export default function OAuthAuthorize() {
|
||||||
const SCOPE_INFO_MAP: Record<string, { icon: React.ComponentType<{ className?: string }>, label: string }> = {
|
const SCOPE_INFO_MAP: Record<string, { icon: React.ComponentType<{ className?: string }>, label: string }> = {
|
||||||
'read:name': {
|
'read:name': {
|
||||||
icon: RiInfoCardLine,
|
icon: RiInfoCardLine,
|
||||||
label: t('oauth.scopes.name'),
|
label: t('scopes.name', { ns: 'oauth' }),
|
||||||
},
|
},
|
||||||
'read:email': {
|
'read:email': {
|
||||||
icon: RiMailLine,
|
icon: RiMailLine,
|
||||||
label: t('oauth.scopes.email'),
|
label: t('scopes.email', { ns: 'oauth' }),
|
||||||
},
|
},
|
||||||
'read:avatar': {
|
'read:avatar': {
|
||||||
icon: RiAccountCircleLine,
|
icon: RiAccountCircleLine,
|
||||||
label: t('oauth.scopes.avatar'),
|
label: t('scopes.avatar', { ns: 'oauth' }),
|
||||||
},
|
},
|
||||||
'read:interface_language': {
|
'read:interface_language': {
|
||||||
icon: RiTranslate2,
|
icon: RiTranslate2,
|
||||||
label: t('oauth.scopes.languagePreference'),
|
label: t('scopes.languagePreference', { ns: 'oauth' }),
|
||||||
},
|
},
|
||||||
'read:timezone': {
|
'read:timezone': {
|
||||||
icon: RiGlobalLine,
|
icon: RiGlobalLine,
|
||||||
label: t('oauth.scopes.timezone'),
|
label: t('scopes.timezone', { ns: 'oauth' }),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -106,7 +106,7 @@ export default function OAuthAuthorize() {
|
||||||
catch (err: any) {
|
catch (err: any) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
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
|
hasNotifiedRef.current = true
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
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,
|
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={`mb-4 mt-5 flex flex-col gap-2 ${isLoggedIn ? 'pb-2' : ''}`}>
|
||||||
<div className="title-4xl-semi-bold">
|
<div className="title-4xl-semi-bold">
|
||||||
{isLoggedIn && <div className="text-text-primary">{t('oauth.connect')}</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('oauth.unknownApp')}</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('oauth.tips.notLoggedIn')}</div>}
|
{!isLoggedIn && <div className="text-text-primary">{t('tips.notLoggedIn', { ns: 'oauth' })}</div>}
|
||||||
</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>
|
</div>
|
||||||
|
|
||||||
{isLoggedIn && userProfile && (
|
{isLoggedIn && userProfile && (
|
||||||
|
|
@ -157,7 +157,7 @@ export default function OAuthAuthorize() {
|
||||||
<div className="system-xs-regular text-text-tertiary">{userProfile.email}</div>
|
<div className="system-xs-regular text-text-tertiary">{userProfile.email}</div>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -178,12 +178,12 @@ export default function OAuthAuthorize() {
|
||||||
<div className="flex flex-col items-center gap-2 pt-4">
|
<div className="flex flex-col items-center gap-2 pt-4">
|
||||||
{!isLoggedIn
|
{!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 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('common.operation.cancel')}</Button>
|
<Button size="large" className="w-full" onClick={() => router.push('/apps')}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -199,7 +199,7 @@ export default function OAuthAuthorize() {
|
||||||
</defs>
|
</defs>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,11 +56,11 @@ const ActivateForm = () => {
|
||||||
<div className="flex flex-col md:w-[400px]">
|
<div className="flex flex-col md:w-[400px]">
|
||||||
<div className="mx-auto w-full">
|
<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>
|
<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>
|
||||||
<div className="mx-auto mt-6 w-full">
|
<div className="mx-auto mt-6 w-full">
|
||||||
<Button variant="primary" className="w-full !text-sm">
|
<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>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -100,12 +100,12 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
setShowEditModal(false)
|
setShowEditModal(false)
|
||||||
notify({
|
notify({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('app.editDone'),
|
message: t('editDone', { ns: 'app' }),
|
||||||
})
|
})
|
||||||
setAppDetail(app)
|
setAppDetail(app)
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
notify({ type: 'error', message: t('app.editFailed') })
|
notify({ type: 'error', message: t('editFailed', { ns: 'app' }) })
|
||||||
}
|
}
|
||||||
}, [appDetail, notify, setAppDetail, t])
|
}, [appDetail, notify, setAppDetail, t])
|
||||||
|
|
||||||
|
|
@ -124,14 +124,14 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
setShowDuplicateModal(false)
|
setShowDuplicateModal(false)
|
||||||
notify({
|
notify({
|
||||||
type: 'success',
|
type: 'success',
|
||||||
message: t('app.newApp.appCreated'),
|
message: t('newApp.appCreated', { ns: 'app' }),
|
||||||
})
|
})
|
||||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||||
onPlanInfoChanged()
|
onPlanInfoChanged()
|
||||||
getRedirection(true, newApp, replace)
|
getRedirection(true, newApp, replace)
|
||||||
}
|
}
|
||||||
catch {
|
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)
|
URL.revokeObjectURL(url)
|
||||||
}
|
}
|
||||||
catch {
|
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)
|
setSecretEnvList(list)
|
||||||
}
|
}
|
||||||
catch {
|
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
|
return
|
||||||
try {
|
try {
|
||||||
await deleteApp(appDetail.id)
|
await deleteApp(appDetail.id)
|
||||||
notify({ type: 'success', message: t('app.appDeleted') })
|
notify({ type: 'success', message: t('appDeleted', { ns: 'app' }) })
|
||||||
onPlanInfoChanged()
|
onPlanInfoChanged()
|
||||||
setAppDetail()
|
setAppDetail()
|
||||||
replace('/apps')
|
replace('/apps')
|
||||||
|
|
@ -198,7 +198,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
catch (e: any) {
|
catch (e: any) {
|
||||||
notify({
|
notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: `${t('app.appDeleteFailed')}${'message' in e ? `: ${e.message}` : ''}`,
|
message: `${t('appDeleteFailed', { ns: 'app' })}${'message' in e ? `: ${e.message}` : ''}`,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
setShowConfirmDelete(false)
|
setShowConfirmDelete(false)
|
||||||
|
|
@ -212,7 +212,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
const primaryOperations = [
|
const primaryOperations = [
|
||||||
{
|
{
|
||||||
id: 'edit',
|
id: 'edit',
|
||||||
title: t('app.editApp'),
|
title: t('editApp', { ns: 'app' }),
|
||||||
icon: <RiEditLine />,
|
icon: <RiEditLine />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
|
|
@ -222,7 +222,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'duplicate',
|
id: 'duplicate',
|
||||||
title: t('app.duplicate'),
|
title: t('duplicate', { ns: 'app' }),
|
||||||
icon: <RiFileCopy2Line />,
|
icon: <RiFileCopy2Line />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
|
|
@ -232,7 +232,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'export',
|
id: 'export',
|
||||||
title: t('app.export'),
|
title: t('export', { ns: 'app' }),
|
||||||
icon: <RiFileDownloadLine />,
|
icon: <RiFileDownloadLine />,
|
||||||
onClick: exportCheck,
|
onClick: exportCheck,
|
||||||
},
|
},
|
||||||
|
|
@ -243,7 +243,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
...(appDetail.mode === AppModeEnum.ADVANCED_CHAT || appDetail.mode === AppModeEnum.WORKFLOW)
|
...(appDetail.mode === AppModeEnum.ADVANCED_CHAT || appDetail.mode === AppModeEnum.WORKFLOW)
|
||||||
? [{
|
? [{
|
||||||
id: 'import',
|
id: 'import',
|
||||||
title: t('workflow.common.importDSL'),
|
title: t('common.importDSL', { ns: 'workflow' }),
|
||||||
icon: <RiFileUploadLine />,
|
icon: <RiFileUploadLine />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
|
|
@ -263,7 +263,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
// Delete operation
|
// Delete operation
|
||||||
{
|
{
|
||||||
id: 'delete',
|
id: 'delete',
|
||||||
title: t('common.operation.delete'),
|
title: t('operation.delete', { ns: 'common' }),
|
||||||
icon: <RiDeleteBinLine />,
|
icon: <RiDeleteBinLine />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
|
|
@ -277,7 +277,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
const switchOperation = (appDetail.mode === AppModeEnum.COMPLETION || appDetail.mode === AppModeEnum.CHAT)
|
const switchOperation = (appDetail.mode === AppModeEnum.COMPLETION || appDetail.mode === AppModeEnum.CHAT)
|
||||||
? {
|
? {
|
||||||
id: 'switch',
|
id: 'switch',
|
||||||
title: t('app.switch'),
|
title: t('switch', { ns: 'app' }),
|
||||||
icon: <RiExchange2Line />,
|
icon: <RiExchange2Line />,
|
||||||
onClick: () => {
|
onClick: () => {
|
||||||
setOpen(false)
|
setOpen(false)
|
||||||
|
|
@ -331,14 +331,14 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
</div>
|
</div>
|
||||||
<div className="system-2xs-medium-uppercase whitespace-nowrap text-text-tertiary">
|
<div className="system-2xs-medium-uppercase whitespace-nowrap text-text-tertiary">
|
||||||
{appDetail.mode === AppModeEnum.ADVANCED_CHAT
|
{appDetail.mode === AppModeEnum.ADVANCED_CHAT
|
||||||
? t('app.types.advanced')
|
? t('types.advanced', { ns: 'app' })
|
||||||
: appDetail.mode === AppModeEnum.AGENT_CHAT
|
: appDetail.mode === AppModeEnum.AGENT_CHAT
|
||||||
? t('app.types.agent')
|
? t('types.agent', { ns: 'app' })
|
||||||
: appDetail.mode === AppModeEnum.CHAT
|
: appDetail.mode === AppModeEnum.CHAT
|
||||||
? t('app.types.chatbot')
|
? t('types.chatbot', { ns: 'app' })
|
||||||
: appDetail.mode === AppModeEnum.COMPLETION
|
: appDetail.mode === AppModeEnum.COMPLETION
|
||||||
? t('app.types.completion')
|
? t('types.completion', { ns: 'app' })
|
||||||
: t('app.types.workflow')}
|
: t('types.workflow', { ns: 'app' })}
|
||||||
</div>
|
</div>
|
||||||
</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="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-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>
|
||||||
</div>
|
</div>
|
||||||
{/* description */}
|
{/* description */}
|
||||||
|
|
@ -438,8 +438,8 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
)}
|
)}
|
||||||
{showConfirmDelete && (
|
{showConfirmDelete && (
|
||||||
<Confirm
|
<Confirm
|
||||||
title={t('app.deleteAppConfirmTitle')}
|
title={t('deleteAppConfirmTitle', { ns: 'app' })}
|
||||||
content={t('app.deleteAppConfirmContent')}
|
content={t('deleteAppConfirmContent', { ns: 'app' })}
|
||||||
isShow={showConfirmDelete}
|
isShow={showConfirmDelete}
|
||||||
onConfirm={onConfirmDelete}
|
onConfirm={onConfirmDelete}
|
||||||
onCancel={() => setShowConfirmDelete(false)}
|
onCancel={() => setShowConfirmDelete(false)}
|
||||||
|
|
@ -462,8 +462,8 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||||
<Confirm
|
<Confirm
|
||||||
type="info"
|
type="info"
|
||||||
isShow={showExportWarning}
|
isShow={showExportWarning}
|
||||||
title={t('workflow.sidebar.exportWarning')}
|
title={t('sidebar.exportWarning', { ns: 'workflow' })}
|
||||||
content={t('workflow.sidebar.exportWarningDesc')}
|
content={t('sidebar.exportWarningDesc', { ns: 'workflow' })}
|
||||||
onConfirm={handleConfirmExport}
|
onConfirm={handleConfirmExport}
|
||||||
onCancel={() => setShowExportWarning(false)}
|
onCancel={() => setShowExportWarning(false)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,7 @@ const AppOperations = ({
|
||||||
>
|
>
|
||||||
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
|
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
|
||||||
<span className="system-xs-medium 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>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -183,7 +183,7 @@ const AppOperations = ({
|
||||||
>
|
>
|
||||||
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
|
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
|
||||||
<span className="system-xs-medium 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>
|
</span>
|
||||||
</Button>
|
</Button>
|
||||||
</PortalToFollowElemTrigger>
|
</PortalToFollowElemTrigger>
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,7 @@ const AppSidebarDropdown = ({ navigation }: Props) => {
|
||||||
<div className="flex w-full">
|
<div className="flex w-full">
|
||||||
<div className="system-md-semibold truncate text-text-secondary">{appDetail.name}</div>
|
<div className="system-md-semibold truncate text-text-secondary">{appDetail.name}</div>
|
||||||
</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>
|
</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>
|
<div className="system-2xs-medium-uppercase flex text-text-tertiary">{type}</div>
|
||||||
)}
|
)}
|
||||||
{!hideType && !isExtraInLine && (
|
{!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>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -73,14 +73,14 @@ const DropDown = ({
|
||||||
URL.revokeObjectURL(url)
|
URL.revokeObjectURL(url)
|
||||||
}
|
}
|
||||||
catch {
|
catch {
|
||||||
Toast.notify({ type: 'error', message: t('app.exportFailed') })
|
Toast.notify({ type: 'error', message: t('exportFailed', { ns: 'app' }) })
|
||||||
}
|
}
|
||||||
}, [dataset, exportPipelineConfig, handleTrigger, t])
|
}, [dataset, exportPipelineConfig, handleTrigger, t])
|
||||||
|
|
||||||
const detectIsUsedByApp = useCallback(async () => {
|
const detectIsUsedByApp = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
const { is_using: isUsedByApp } = await checkIsUsedInApp(dataset.id)
|
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)
|
setShowConfirmDelete(true)
|
||||||
}
|
}
|
||||||
catch (e: any) {
|
catch (e: any) {
|
||||||
|
|
@ -95,7 +95,7 @@ const DropDown = ({
|
||||||
const onConfirmDelete = useCallback(async () => {
|
const onConfirmDelete = useCallback(async () => {
|
||||||
try {
|
try {
|
||||||
await deleteDataset(dataset.id)
|
await deleteDataset(dataset.id)
|
||||||
Toast.notify({ type: 'success', message: t('dataset.datasetDeleted') })
|
Toast.notify({ type: 'success', message: t('datasetDeleted', { ns: 'dataset' }) })
|
||||||
invalidDatasetList()
|
invalidDatasetList()
|
||||||
replace('/datasets')
|
replace('/datasets')
|
||||||
}
|
}
|
||||||
|
|
@ -141,7 +141,7 @@ const DropDown = ({
|
||||||
)}
|
)}
|
||||||
{showConfirmDelete && (
|
{showConfirmDelete && (
|
||||||
<Confirm
|
<Confirm
|
||||||
title={t('dataset.deleteDatasetConfirmTitle')}
|
title={t('deleteDatasetConfirmTitle', { ns: 'dataset' })}
|
||||||
content={confirmMessage}
|
content={confirmMessage}
|
||||||
isShow={showConfirmDelete}
|
isShow={showConfirmDelete}
|
||||||
onConfirm={onConfirmDelete}
|
onConfirm={onConfirmDelete}
|
||||||
|
|
|
||||||
|
|
@ -70,10 +70,10 @@ const DatasetInfo: FC<DatasetInfoProps> = ({
|
||||||
{dataset.name}
|
{dataset.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="system-2xs-medium-uppercase text-text-tertiary">
|
<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 && (
|
{!isExternalProvider && isPipelinePublished && dataset.doc_form && dataset.indexing_technique && (
|
||||||
<div className="flex items-center gap-x-2">
|
<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>
|
<span>{formatIndexingTechniqueAndMethod(dataset.indexing_technique, dataset.retrieval_model_dict?.search_method)}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,13 @@ const Menu = ({
|
||||||
<div className="flex flex-col p-1">
|
<div className="flex flex-col p-1">
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Icon={RiEditLine}
|
Icon={RiEditLine}
|
||||||
name={t('common.operation.edit')}
|
name={t('operation.edit', { ns: 'common' })}
|
||||||
handleClick={openRenameModal}
|
handleClick={openRenameModal}
|
||||||
/>
|
/>
|
||||||
{runtimeMode === 'rag_pipeline' && (
|
{runtimeMode === 'rag_pipeline' && (
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Icon={RiFileDownloadLine}
|
Icon={RiFileDownloadLine}
|
||||||
name={t('datasetPipeline.operations.exportPipeline')}
|
name={t('operations.exportPipeline', { ns: 'datasetPipeline' })}
|
||||||
handleClick={handleExportPipeline}
|
handleClick={handleExportPipeline}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
@ -43,7 +43,7 @@ const Menu = ({
|
||||||
<div className="flex flex-col p-1">
|
<div className="flex flex-col p-1">
|
||||||
<MenuItem
|
<MenuItem
|
||||||
Icon={RiDeleteBinLine}
|
Icon={RiDeleteBinLine}
|
||||||
name={t('common.operation.delete')}
|
name={t('operation.delete', { ns: 'common' })}
|
||||||
handleClick={detectIsUsedByApp}
|
handleClick={detectIsUsedByApp}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -113,10 +113,10 @@ const DatasetSidebarDropdown = ({
|
||||||
{dataset.name}
|
{dataset.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="system-2xs-medium-uppercase text-text-tertiary">
|
<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 && (
|
{!isExternalProvider && dataset.doc_form && dataset.indexing_technique && (
|
||||||
<div className="flex items-center gap-x-2">
|
<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>
|
<span>{formatIndexingTechniqueAndMethod(dataset.indexing_technique, dataset.retrieval_model_dict?.search_method)}</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,7 @@ const TooltipContent = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-x-1">
|
<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">
|
<div className="flex items-center gap-x-0.5">
|
||||||
{
|
{
|
||||||
TOGGLE_SHORTCUT.map(key => (
|
TOGGLE_SHORTCUT.map(key => (
|
||||||
|
|
|
||||||
|
|
@ -22,8 +22,8 @@ const EditItem: FC<Props> = ({
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const avatar = type === EditItemType.Query ? <User className="h-6 w-6" /> : <Robot className="h-6 w-6" />
|
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 name = type === EditItemType.Query ? t('addModal.queryName', { ns: 'appAnnotation' }) : t('addModal.answerName', { ns: 'appAnnotation' })
|
||||||
const placeholder = type === EditItemType.Query ? t('appAnnotation.addModal.queryPlaceholder') : t('appAnnotation.addModal.answerPlaceholder')
|
const placeholder = type === EditItemType.Query ? t('addModal.queryPlaceholder', { ns: 'appAnnotation' }) : t('addModal.answerPlaceholder', { ns: 'appAnnotation' })
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex" onClick={e => e.stopPropagation()}>
|
<div className="flex" onClick={e => e.stopPropagation()}>
|
||||||
|
|
|
||||||
|
|
@ -33,10 +33,10 @@ const AddAnnotationModal: FC<Props> = ({
|
||||||
|
|
||||||
const isValid = (payload: AnnotationItemBasic) => {
|
const isValid = (payload: AnnotationItemBasic) => {
|
||||||
if (!payload.question)
|
if (!payload.question)
|
||||||
return t('appAnnotation.errorMessage.queryRequired')
|
return t('errorMessage.queryRequired', { ns: 'appAnnotation' })
|
||||||
|
|
||||||
if (!payload.answer)
|
if (!payload.answer)
|
||||||
return t('appAnnotation.errorMessage.answerRequired')
|
return t('errorMessage.answerRequired', { ns: 'appAnnotation' })
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
@ -76,7 +76,7 @@ const AddAnnotationModal: FC<Props> = ({
|
||||||
isShow={isShow}
|
isShow={isShow}
|
||||||
onHide={onHide}
|
onHide={onHide}
|
||||||
maxWidthClassName="!max-w-[480px]"
|
maxWidthClassName="!max-w-[480px]"
|
||||||
title={t('appAnnotation.addModal.title') as string}
|
title={t('addModal.title', { ns: 'appAnnotation' }) as string}
|
||||||
body={(
|
body={(
|
||||||
<div className="space-y-6 p-6 pb-4">
|
<div className="space-y-6 p-6 pb-4">
|
||||||
<EditItem
|
<EditItem
|
||||||
|
|
@ -104,11 +104,11 @@ const AddAnnotationModal: FC<Props> = ({
|
||||||
className="flex items-center space-x-2"
|
className="flex items-center space-x-2"
|
||||||
>
|
>
|
||||||
<Checkbox id="create-next-checkbox" checked={isCreateNext} onCheck={() => setIsCreateNext(!isCreateNext)} />
|
<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>
|
||||||
<div className="mt-2 flex space-x-2">
|
<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" onClick={onHide}>{t('operation.cancel', { ns: 'common' })}</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" variant="primary" onClick={handleSave} loading={isSaving} disabled={isAnnotationFull}>{t('operation.add', { ns: 'common' })}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ import Confirm from '@/app/components/base/confirm'
|
||||||
import Divider from '@/app/components/base/divider'
|
import Divider from '@/app/components/base/divider'
|
||||||
import { cn } from '@/utils/classnames'
|
import { cn } from '@/utils/classnames'
|
||||||
|
|
||||||
const i18nPrefix = 'appAnnotation.batchAction'
|
const i18nPrefix = 'batchAction'
|
||||||
|
|
||||||
type IBatchActionProps = {
|
type IBatchActionProps = {
|
||||||
className?: string
|
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">
|
<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}
|
{selectedIds.length}
|
||||||
</span>
|
</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>
|
</div>
|
||||||
<Divider type="vertical" className="mx-0.5 h-3.5 bg-divider-regular" />
|
<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}>
|
<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" />
|
<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">
|
<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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider type="vertical" className="mx-0.5 h-3.5 bg-divider-regular" />
|
<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}>
|
<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>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
isShowDeleteConfirm && (
|
isShowDeleteConfirm && (
|
||||||
<Confirm
|
<Confirm
|
||||||
isShow
|
isShow
|
||||||
title={t('appAnnotation.list.delete.title')}
|
title={t('list.delete.title', { ns: 'appAnnotation' })}
|
||||||
confirmText={t('common.operation.delete')}
|
confirmText={t('operation.delete', { ns: 'common' })}
|
||||||
onConfirm={handleBatchDelete}
|
onConfirm={handleBatchDelete}
|
||||||
onCancel={hideDeleteConfirm}
|
onCancel={hideDeleteConfirm}
|
||||||
isLoading={isDeleting}
|
isLoading={isDeleting}
|
||||||
|
|
|
||||||
|
|
@ -33,36 +33,36 @@ const CSVDownload: FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-6">
|
<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">
|
<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">
|
<table className="w-full table-fixed border-separate border-spacing-0 rounded-lg border border-divider-regular text-xs">
|
||||||
<thead className="text-text-tertiary">
|
<thead className="text-text-tertiary">
|
||||||
<tr>
|
<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('batchModal.question', { ns: 'appAnnotation' })}</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.answer', { ns: 'appAnnotation' })}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="text-text-secondary">
|
<tbody className="text-text-secondary">
|
||||||
<tr>
|
<tr>
|
||||||
<td className="h-9 border-b border-divider-subtle pl-3 pr-2 text-[13px]">
|
<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
|
1
|
||||||
</td>
|
</td>
|
||||||
<td className="h-9 border-b border-divider-subtle pl-3 pr-2 text-[13px]">
|
<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
|
1
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td className="h-9 pl-3 pr-2 text-[13px]">
|
<td className="h-9 pl-3 pr-2 text-[13px]">
|
||||||
{t('appAnnotation.batchModal.question')}
|
{t('batchModal.question', { ns: 'appAnnotation' })}
|
||||||
{' '}
|
{' '}
|
||||||
2
|
2
|
||||||
</td>
|
</td>
|
||||||
<td className="h-9 pl-3 pr-2 text-[13px]">
|
<td className="h-9 pl-3 pr-2 text-[13px]">
|
||||||
{t('appAnnotation.batchModal.answer')}
|
{t('batchModal.answer', { ns: 'appAnnotation' })}
|
||||||
{' '}
|
{' '}
|
||||||
2
|
2
|
||||||
</td>
|
</td>
|
||||||
|
|
@ -79,7 +79,7 @@ const CSVDownload: FC = () => {
|
||||||
>
|
>
|
||||||
<div className="system-xs-medium flex h-[18px] items-center space-x-1 text-text-accent">
|
<div className="system-xs-medium flex h-[18px] items-center space-x-1 text-text-accent">
|
||||||
<DownloadIcon className="mr-1 h-3 w-3" />
|
<DownloadIcon className="mr-1 h-3 w-3" />
|
||||||
{t('appAnnotation.batchModal.template')}
|
{t('batchModal.template', { ns: 'appAnnotation' })}
|
||||||
</div>
|
</div>
|
||||||
</CSVDownloader>
|
</CSVDownloader>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ const CSVUploader: FC<Props> = ({
|
||||||
return
|
return
|
||||||
const files = [...e.dataTransfer.files]
|
const files = [...e.dataTransfer.files]
|
||||||
if (files.length > 1) {
|
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
|
return
|
||||||
}
|
}
|
||||||
updateFile(files[0])
|
updateFile(files[0])
|
||||||
|
|
@ -98,8 +98,8 @@ const CSVUploader: FC<Props> = ({
|
||||||
<div className="flex w-full items-center justify-center space-x-2">
|
<div className="flex w-full items-center justify-center space-x-2">
|
||||||
<CSVIcon className="shrink-0" />
|
<CSVIcon className="shrink-0" />
|
||||||
<div className="text-text-tertiary">
|
<div className="text-text-tertiary">
|
||||||
{t('appAnnotation.batchModal.csvUploadTitle')}
|
{t('batchModal.csvUploadTitle', { ns: 'appAnnotation' })}
|
||||||
<span className="cursor-pointer text-text-accent" onClick={selectHandle}>{t('appAnnotation.batchModal.browse')}</span>
|
<span className="cursor-pointer text-text-accent" onClick={selectHandle}>{t('batchModal.browse', { ns: 'appAnnotation' })}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{dragging && <div ref={dragRef} className="absolute left-0 top-0 h-full w-full" />}
|
{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>
|
<span className="shrink-0 text-text-tertiary">.csv</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="hidden items-center group-hover:flex">
|
<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="mx-2 h-4 w-px bg-divider-regular" />
|
||||||
<div className="cursor-pointer p-2" onClick={removeFile} data-testid="remove-file-button">
|
<div className="cursor-pointer p-2" onClick={removeFile} data-testid="remove-file-button">
|
||||||
<RiDeleteBinLine className="h-4 w-4 text-text-tertiary" />
|
<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)
|
if (res.job_status === ProcessStatus.WAITING || res.job_status === ProcessStatus.PROCESSING)
|
||||||
setTimeout(() => checkProcess(res.job_id), 2500)
|
setTimeout(() => checkProcess(res.job_id), 2500)
|
||||||
if (res.job_status === ProcessStatus.ERROR)
|
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) {
|
if (res.job_status === ProcessStatus.COMPLETED) {
|
||||||
notify({ type: 'success', message: `${t('appAnnotation.batchModal.completed')}` })
|
notify({ type: 'success', message: `${t('batchModal.completed', { ns: 'appAnnotation' })}` })
|
||||||
onAdded()
|
onAdded()
|
||||||
onCancel()
|
onCancel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (e: any) {
|
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)
|
checkProcess(res.job_id)
|
||||||
}
|
}
|
||||||
catch (e: any) {
|
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 (
|
return (
|
||||||
<Modal isShow={isShow} onClose={noop} className="!max-w-[520px] !rounded-xl px-8 py-6">
|
<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}>
|
<div className="absolute right-4 top-4 cursor-pointer p-2" onClick={onCancel}>
|
||||||
<RiCloseLine className="h-4 w-4 text-text-tertiary" />
|
<RiCloseLine className="h-4 w-4 text-text-tertiary" />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -108,7 +108,7 @@ const BatchModal: FC<IBatchModalProps> = ({
|
||||||
|
|
||||||
<div className="mt-[28px] flex justify-end pt-6">
|
<div className="mt-[28px] flex justify-end pt-6">
|
||||||
<Button className="system-sm-medium mr-2 text-text-tertiary" onClick={onCancel}>
|
<Button className="system-sm-medium mr-2 text-text-tertiary" onClick={onCancel}>
|
||||||
{t('appAnnotation.batchModal.cancel')}
|
{t('batchModal.cancel', { ns: 'appAnnotation' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
|
|
@ -116,7 +116,7 @@ const BatchModal: FC<IBatchModalProps> = ({
|
||||||
disabled={isAnnotationFull || !currentCSV}
|
disabled={isAnnotationFull || !currentCSV}
|
||||||
loading={importStatus === ProcessStatus.PROCESSING || importStatus === ProcessStatus.WAITING}
|
loading={importStatus === ProcessStatus.PROCESSING || importStatus === ProcessStatus.WAITING}
|
||||||
>
|
>
|
||||||
{t('appAnnotation.batchModal.run')}
|
{t('batchModal.run', { ns: 'appAnnotation' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,16 @@ import ClearAllAnnotationsConfirmModal from './index'
|
||||||
|
|
||||||
vi.mock('react-i18next', () => ({
|
vi.mock('react-i18next', () => ({
|
||||||
useTranslation: () => ({
|
useTranslation: () => ({
|
||||||
t: (key: string) => {
|
t: (key: string, options?: { ns?: string }) => {
|
||||||
const translations: Record<string, string> = {
|
const translations: Record<string, string> = {
|
||||||
'appAnnotation.table.header.clearAllConfirm': 'Clear all annotations?',
|
'table.header.clearAllConfirm': 'Clear all annotations?',
|
||||||
'common.operation.confirm': 'Confirm',
|
'operation.confirm': 'Confirm',
|
||||||
'common.operation.cancel': 'Cancel',
|
'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}
|
onCancel={onHide}
|
||||||
onConfirm={onConfirm}
|
onConfirm={onConfirm}
|
||||||
type="danger"
|
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 [newContent, setNewContent] = useState('')
|
||||||
const showNewContent = newContent && newContent !== content
|
const showNewContent = newContent && newContent !== content
|
||||||
const avatar = type === EditItemType.Query ? <User className="h-6 w-6" /> : <Robot className="h-6 w-6" />
|
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 name = type === EditItemType.Query ? t('editModal.queryName', { ns: 'appAnnotation' }) : t('editModal.answerName', { ns: 'appAnnotation' })
|
||||||
const editTitle = type === EditItemType.Query ? t('appAnnotation.editModal.yourQuery') : t('appAnnotation.editModal.yourAnswer')
|
const editTitle = type === EditItemType.Query ? t('editModal.yourQuery', { ns: 'appAnnotation' }) : t('editModal.yourAnswer', { ns: 'appAnnotation' })
|
||||||
const placeholder = type === EditItemType.Query ? t('appAnnotation.editModal.queryPlaceholder') : t('appAnnotation.editModal.answerPlaceholder')
|
const placeholder = type === EditItemType.Query ? t('editModal.queryPlaceholder', { ns: 'appAnnotation' }) : t('editModal.answerPlaceholder', { ns: 'appAnnotation' })
|
||||||
const [isEdit, setIsEdit] = useState(false)
|
const [isEdit, setIsEdit] = useState(false)
|
||||||
|
|
||||||
// Reset newContent when content prop changes
|
// Reset newContent when content prop changes
|
||||||
|
|
@ -95,7 +95,7 @@ const EditItem: FC<Props> = ({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<RiEditLine className="mr-1 h-3.5 w-3.5" />
|
<RiEditLine className="mr-1 h-3.5 w-3.5" />
|
||||||
<div>{t('common.operation.edit')}</div>
|
<div>{t('operation.edit', { ns: 'common' })}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
|
@ -119,7 +119,7 @@ const EditItem: FC<Props> = ({
|
||||||
<div className="h-3.5 w-3.5">
|
<div className="h-3.5 w-3.5">
|
||||||
<RiDeleteBinLine className="h-3.5 w-3.5" />
|
<RiDeleteBinLine className="h-3.5 w-3.5" />
|
||||||
</div>
|
</div>
|
||||||
<div>{t('common.operation.delete')}</div>
|
<div>{t('operation.delete', { ns: 'common' })}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -136,8 +136,8 @@ const EditItem: FC<Props> = ({
|
||||||
autoFocus
|
autoFocus
|
||||||
/>
|
/>
|
||||||
<div className="mt-2 flex space-x-2">
|
<div className="mt-2 flex space-x-2">
|
||||||
<Button size="small" variant="primary" onClick={handleSave}>{t('common.operation.save')}</Button>
|
<Button size="small" variant="primary" onClick={handleSave}>{t('operation.save', { ns: 'common' })}</Button>
|
||||||
<Button size="small" onClick={handleCancel}>{t('common.operation.cancel')}</Button>
|
<Button size="small" onClick={handleCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -73,12 +73,12 @@ const EditAnnotationModal: FC<Props> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
message: t('common.api.actionSuccess') as string,
|
message: t('api.actionSuccess', { ns: 'common' }) as string,
|
||||||
type: 'success',
|
type: 'success',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
catch (error) {
|
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
|
const message = error instanceof Error && error.message ? error.message : fallbackMessage
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
message,
|
message,
|
||||||
|
|
@ -96,7 +96,7 @@ const EditAnnotationModal: FC<Props> = ({
|
||||||
isShow={isShow}
|
isShow={isShow}
|
||||||
onHide={onHide}
|
onHide={onHide}
|
||||||
maxWidthClassName="!max-w-[480px]"
|
maxWidthClassName="!max-w-[480px]"
|
||||||
title={t('appAnnotation.editModal.title') as string}
|
title={t('editModal.title', { ns: 'appAnnotation' }) as string}
|
||||||
body={(
|
body={(
|
||||||
<div>
|
<div>
|
||||||
<div className="space-y-6 p-6 pb-4">
|
<div className="space-y-6 p-6 pb-4">
|
||||||
|
|
@ -120,7 +120,7 @@ const EditAnnotationModal: FC<Props> = ({
|
||||||
setShowModal(false)
|
setShowModal(false)
|
||||||
onHide()
|
onHide()
|
||||||
}}
|
}}
|
||||||
title={t('appDebug.feature.annotation.removeConfirm')}
|
title={t('feature.annotation.removeConfirm', { ns: 'appDebug' })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -142,13 +142,13 @@ const EditAnnotationModal: FC<Props> = ({
|
||||||
onClick={() => setShowModal(true)}
|
onClick={() => setShowModal(true)}
|
||||||
>
|
>
|
||||||
<MessageCheckRemove />
|
<MessageCheckRemove />
|
||||||
<div>{t('appAnnotation.editModal.removeThisCache')}</div>
|
<div>{t('editModal.removeThisCache', { ns: 'appAnnotation' })}</div>
|
||||||
</div>
|
</div>
|
||||||
{createdAt && (
|
{createdAt && (
|
||||||
<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>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -18,11 +18,11 @@ const EmptyElement: FC = () => {
|
||||||
<div className="flex h-full items-center justify-center">
|
<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">
|
<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">
|
<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" />
|
<ThreeDotsIcon className="relative -left-1.5 -top-3 inline" />
|
||||||
</span>
|
</span>
|
||||||
<div className="system-sm-regular mt-2 text-text-tertiary">
|
<div className="system-sm-regular mt-2 text-text-tertiary">
|
||||||
{t('appAnnotation.noData.description')}
|
{t('noData.description', { ns: 'appAnnotation' })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ const Filter: FC<IFilterProps> = ({
|
||||||
showLeftIcon
|
showLeftIcon
|
||||||
showClearIcon
|
showClearIcon
|
||||||
value={queryParams.keyword}
|
value={queryParams.keyword}
|
||||||
placeholder={t('common.operation.search')!}
|
placeholder={t('operation.search', { ns: 'common' })!}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
setQueryParams({ ...queryParams, keyword: e.target.value })
|
setQueryParams({ ...queryParams, keyword: e.target.value })
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -108,12 +108,12 @@ const HeaderOptions: FC<Props> = ({
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<FilePlus02 className="h-4 w-4 text-text-tertiary" />
|
<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>
|
</button>
|
||||||
<Menu as="div" className="relative h-full w-full">
|
<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">
|
<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" />
|
<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" />
|
<ChevronRight className="h-[14px] w-[14px] shrink-0 text-text-tertiary" />
|
||||||
</MenuButton>
|
</MenuButton>
|
||||||
<Transition
|
<Transition
|
||||||
|
|
@ -156,7 +156,7 @@ const HeaderOptions: FC<Props> = ({
|
||||||
>
|
>
|
||||||
<RiDeleteBinLine className="h-4 w-4" />
|
<RiDeleteBinLine className="h-4 w-4" />
|
||||||
<span className="system-sm-regular grow text-left">
|
<span className="system-sm-regular grow text-left">
|
||||||
{t('appAnnotation.table.header.clearAll')}
|
{t('table.header.clearAll', { ns: 'appAnnotation' })}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -169,7 +169,7 @@ const HeaderOptions: FC<Props> = ({
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<Button variant="primary" onClick={() => setShowAddModal(true)}>
|
<Button variant="primary" onClick={() => setShowAddModal(true)}>
|
||||||
<RiAddLine className="mr-0.5 h-4 w-4" />
|
<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>
|
</Button>
|
||||||
<CustomPopover
|
<CustomPopover
|
||||||
htmlContent={<Operations />}
|
htmlContent={<Operations />}
|
||||||
|
|
|
||||||
|
|
@ -98,14 +98,14 @@ const Annotation: FC<Props> = (props) => {
|
||||||
|
|
||||||
const handleAdd = async (payload: AnnotationItemBasic) => {
|
const handleAdd = async (payload: AnnotationItemBasic) => {
|
||||||
await addAnnotation(appDetail.id, payload)
|
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()
|
fetchList()
|
||||||
setControlUpdateList(Date.now())
|
setControlUpdateList(Date.now())
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleRemove = async (id: string) => {
|
const handleRemove = async (id: string) => {
|
||||||
await delAnnotation(appDetail.id, id)
|
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()
|
fetchList()
|
||||||
setControlUpdateList(Date.now())
|
setControlUpdateList(Date.now())
|
||||||
}
|
}
|
||||||
|
|
@ -113,13 +113,13 @@ const Annotation: FC<Props> = (props) => {
|
||||||
const handleBatchDelete = async () => {
|
const handleBatchDelete = async () => {
|
||||||
try {
|
try {
|
||||||
await delAnnotations(appDetail.id, selectedIds)
|
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()
|
fetchList()
|
||||||
setControlUpdateList(Date.now())
|
setControlUpdateList(Date.now())
|
||||||
setSelectedIds([])
|
setSelectedIds([])
|
||||||
}
|
}
|
||||||
catch (e: any) {
|
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)
|
if (!currItem)
|
||||||
return
|
return
|
||||||
await editAnnotation(appDetail.id, currItem.id, { question, answer })
|
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()
|
fetchList()
|
||||||
setControlUpdateList(Date.now())
|
setControlUpdateList(Date.now())
|
||||||
}
|
}
|
||||||
|
|
@ -144,7 +144,7 @@ const Annotation: FC<Props> = (props) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex h-full flex-col">
|
<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">
|
<div className="relative flex h-full flex-1 flex-col py-4">
|
||||||
<Filter appId={appDetail.id} queryParams={queryParams} setQueryParams={setQueryParams}>
|
<Filter appId={appDetail.id} queryParams={queryParams} setQueryParams={setQueryParams}>
|
||||||
<div className="flex items-center space-x-2">
|
<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')}>
|
<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" />
|
<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
|
<Switch
|
||||||
key={controlRefreshSwitch}
|
key={controlRefreshSwitch}
|
||||||
defaultValue={annotationConfig?.enabled}
|
defaultValue={annotationConfig?.enabled}
|
||||||
|
|
@ -171,7 +171,7 @@ const Annotation: FC<Props> = (props) => {
|
||||||
await ensureJobCompleted(jobId, AnnotationEnableStatus.disable)
|
await ensureJobCompleted(jobId, AnnotationEnableStatus.disable)
|
||||||
await fetchAnnotationConfig()
|
await fetchAnnotationConfig()
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
message: t('common.api.actionSuccess'),
|
message: t('api.actionSuccess', { ns: 'common' }),
|
||||||
type: 'success',
|
type: 'success',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
@ -264,7 +264,7 @@ const Annotation: FC<Props> = (props) => {
|
||||||
|
|
||||||
await fetchAnnotationConfig()
|
await fetchAnnotationConfig()
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
message: t('common.api.actionSuccess'),
|
message: t('api.actionSuccess', { ns: 'common' }),
|
||||||
type: 'success',
|
type: 'success',
|
||||||
})
|
})
|
||||||
setIsShowEdit(false)
|
setIsShowEdit(false)
|
||||||
|
|
|
||||||
|
|
@ -68,11 +68,11 @@ const List: FC<Props> = ({
|
||||||
onCheck={handleSelectAll}
|
onCheck={handleSelectAll}
|
||||||
/>
|
/>
|
||||||
</td>
|
</td>
|
||||||
<td className="w-5 whitespace-nowrap bg-background-section-burn pl-2 pr-1">{t('appAnnotation.table.header.question')}</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('appAnnotation.table.header.answer')}</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('appAnnotation.table.header.createdAt')}</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('appAnnotation.table.header.hits')}</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('appAnnotation.table.header.actions')}</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>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="system-sm-regular text-text-secondary">
|
<tbody className="system-sm-regular text-text-secondary">
|
||||||
|
|
@ -110,7 +110,7 @@ const List: FC<Props> = ({
|
||||||
>
|
>
|
||||||
{item.answer}
|
{item.answer}
|
||||||
</td>
|
</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="p-3 pr-2">{item.hit_count}</td>
|
||||||
<td className="w-[96px] p-3 pr-2" onClick={e => e.stopPropagation()}>
|
<td className="w-[96px] p-3 pr-2" onClick={e => e.stopPropagation()}>
|
||||||
{/* Actions */}
|
{/* Actions */}
|
||||||
|
|
|
||||||
|
|
@ -4,13 +4,16 @@ import RemoveAnnotationConfirmModal from './index'
|
||||||
|
|
||||||
vi.mock('react-i18next', () => ({
|
vi.mock('react-i18next', () => ({
|
||||||
useTranslation: () => ({
|
useTranslation: () => ({
|
||||||
t: (key: string) => {
|
t: (key: string, options?: { ns?: string }) => {
|
||||||
const translations: Record<string, string> = {
|
const translations: Record<string, string> = {
|
||||||
'appDebug.feature.annotation.removeConfirm': 'Remove annotation?',
|
'feature.annotation.removeConfirm': 'Remove annotation?',
|
||||||
'common.operation.confirm': 'Confirm',
|
'operation.confirm': 'Confirm',
|
||||||
'common.operation.cancel': 'Cancel',
|
'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}
|
isShow={isShow}
|
||||||
onCancel={onHide}
|
onCancel={onHide}
|
||||||
onConfirm={onRemove}
|
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">
|
<div className="inline-block rounded-lg border border-divider-subtle p-3">
|
||||||
<ClockFastForward className="h-5 w-5 text-text-tertiary" />
|
<ClockFastForward className="h-5 w-5 text-text-tertiary" />
|
||||||
</div>
|
</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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,20 +81,20 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||||
}, [id, isShow])
|
}, [id, isShow])
|
||||||
|
|
||||||
const tabs = [
|
const tabs = [
|
||||||
{ value: TabType.annotation, text: t('appAnnotation.viewModal.annotatedResponse') },
|
{ value: TabType.annotation, text: t('viewModal.annotatedResponse', { ns: 'appAnnotation' }) },
|
||||||
{
|
{
|
||||||
value: TabType.hitHistory,
|
value: TabType.hitHistory,
|
||||||
text: (
|
text: (
|
||||||
hitHistoryList.length > 0
|
hitHistoryList.length > 0
|
||||||
? (
|
? (
|
||||||
<div className="flex items-center space-x-1">
|
<div className="flex items-center space-x-1">
|
||||||
<div>{t('appAnnotation.viewModal.hitHistory')}</div>
|
<div>{t('viewModal.hitHistory', { ns: 'appAnnotation' })}</div>
|
||||||
<Badge
|
<Badge
|
||||||
text={`${total} ${t(`appAnnotation.viewModal.hit${hitHistoryList.length > 1 ? 's' : ''}`)}`}
|
text={`${total} ${t(`viewModal.hit${hitHistoryList.length > 1 ? 's' : ''}`, { ns: 'appAnnotation' })}`}
|
||||||
/>
|
/>
|
||||||
</div>
|
</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')}>
|
<table className={cn('w-full min-w-[440px] border-collapse border-0')}>
|
||||||
<thead className="system-xs-medium-uppercase text-text-tertiary">
|
<thead className="system-xs-medium-uppercase text-text-tertiary">
|
||||||
<tr>
|
<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="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('appAnnotation.hitHistoryTable.match')}</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('appAnnotation.hitHistoryTable.response')}</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('appAnnotation.hitHistoryTable.source')}</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('appAnnotation.hitHistoryTable.score')}</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('appAnnotation.hitHistoryTable.time')}</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>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody className="system-sm-regular text-text-secondary">
|
<tbody className="system-sm-regular text-text-secondary">
|
||||||
|
|
@ -173,7 +173,7 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 pr-2">{item.source}</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">{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>
|
</tr>
|
||||||
))}
|
))}
|
||||||
</tbody>
|
</tbody>
|
||||||
|
|
@ -220,7 +220,7 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||||
setShowModal(false)
|
setShowModal(false)
|
||||||
onHide()
|
onHide()
|
||||||
}}
|
}}
|
||||||
title={t('appDebug.feature.annotation.removeConfirm')}
|
title={t('feature.annotation.removeConfirm', { ns: 'appDebug' })}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
@ -232,12 +232,12 @@ const ViewAnnotationModal: FC<Props> = ({
|
||||||
onClick={() => setShowModal(true)}
|
onClick={() => setShowModal(true)}
|
||||||
>
|
>
|
||||||
<MessageCheckRemove />
|
<MessageCheckRemove />
|
||||||
<div>{t('appAnnotation.editModal.removeThisCache')}</div>
|
<div>{t('editModal.removeThisCache', { ns: 'appAnnotation' })}</div>
|
||||||
</div>
|
</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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -49,14 +49,14 @@ export default function AddMemberOrGroupDialog() {
|
||||||
<PortalToFollowElemTrigger asChild>
|
<PortalToFollowElemTrigger asChild>
|
||||||
<Button variant="ghost-accent" size="small" className="flex shrink-0 items-center gap-x-0.5" onClick={() => setOpen(!open)}>
|
<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" />
|
<RiAddCircleFill className="h-4 w-4" />
|
||||||
<span>{t('common.operation.add')}</span>
|
<span>{t('operation.add', { ns: 'common' })}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</PortalToFollowElemTrigger>
|
</PortalToFollowElemTrigger>
|
||||||
{open && <FloatingOverlay />}
|
{open && <FloatingOverlay />}
|
||||||
<PortalToFollowElemContent className="z-[100]">
|
<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="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]">
|
<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>
|
</div>
|
||||||
{
|
{
|
||||||
isLoading
|
isLoading
|
||||||
|
|
@ -76,7 +76,7 @@ export default function AddMemberOrGroupDialog() {
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<div className="flex h-7 items-center justify-center px-2 py-0.5">
|
<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>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -115,7 +115,7 @@ function SelectedGroupsBreadCrumb() {
|
||||||
}, [setSelectedGroupsForBreadcrumb])
|
}, [setSelectedGroupsForBreadcrumb])
|
||||||
return (
|
return (
|
||||||
<div className="flex h-7 items-center gap-x-0.5 px-2 py-0.5">
|
<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) => {
|
{selectedGroupsForBreadcrumb.map((group, index) => {
|
||||||
return (
|
return (
|
||||||
<div key={index} className="system-xs-regular flex items-center gap-x-0.5 text-text-tertiary">
|
<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"
|
className="flex shrink-0 items-center justify-between px-1.5 py-1"
|
||||||
onClick={handleExpandClick}
|
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" />
|
<RiArrowRightSLine className="h-4 w-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</BaseItem>
|
</BaseItem>
|
||||||
|
|
@ -210,7 +210,7 @@ function MemberItem({ member }: MemberItemProps) {
|
||||||
{currentUser.email === member.email && (
|
{currentUser.email === member.email && (
|
||||||
<p className="system-xs-regular text-text-tertiary">
|
<p className="system-xs-regular text-text-tertiary">
|
||||||
(
|
(
|
||||||
{t('common.you')}
|
{t('you', { ns: 'common' })}
|
||||||
)
|
)
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -61,25 +61,25 @@ export default function AccessControl(props: AccessControlProps) {
|
||||||
submitData.subjects = subjects
|
submitData.subjects = subjects
|
||||||
}
|
}
|
||||||
await updateAccessMode(submitData)
|
await updateAccessMode(submitData)
|
||||||
Toast.notify({ type: 'success', message: t('app.accessControlDialog.updateSuccess') })
|
Toast.notify({ type: 'success', message: t('accessControlDialog.updateSuccess', { ns: 'app' }) })
|
||||||
onConfirm?.()
|
onConfirm?.()
|
||||||
}, [updateAccessMode, app, specificGroups, specificMembers, t, onConfirm, currentMenu])
|
}, [updateAccessMode, app, specificGroups, specificMembers, t, onConfirm, currentMenu])
|
||||||
return (
|
return (
|
||||||
<AccessControlDialog show onClose={onClose}>
|
<AccessControlDialog show onClose={onClose}>
|
||||||
<div className="flex flex-col gap-y-3">
|
<div className="flex flex-col gap-y-3">
|
||||||
<div className="pb-3 pl-6 pr-14 pt-6">
|
<div className="pb-3 pl-6 pr-14 pt-6">
|
||||||
<DialogTitle className="title-2xl-semi-bold text-text-primary">{t('app.accessControlDialog.title')}</DialogTitle>
|
<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('app.accessControlDialog.description')}</DialogDescription>
|
<DialogDescription className="system-xs-regular mt-1 text-text-tertiary">{t('accessControlDialog.description', { ns: 'app' })}</DialogDescription>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-y-1 px-6 pb-3">
|
<div className="flex flex-col gap-y-1 px-6 pb-3">
|
||||||
<div className="leading-6">
|
<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>
|
</div>
|
||||||
<AccessControlItem type={AccessMode.ORGANIZATION}>
|
<AccessControlItem type={AccessMode.ORGANIZATION}>
|
||||||
<div className="flex items-center p-3">
|
<div className="flex items-center p-3">
|
||||||
<div className="flex grow items-center gap-x-2">
|
<div className="flex grow items-center gap-x-2">
|
||||||
<RiBuildingLine className="h-4 w-4 text-text-primary" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</AccessControlItem>
|
</AccessControlItem>
|
||||||
|
|
@ -90,7 +90,7 @@ export default function AccessControl(props: AccessControlProps) {
|
||||||
<div className="flex items-center p-3">
|
<div className="flex items-center p-3">
|
||||||
<div className="flex grow items-center gap-x-2">
|
<div className="flex grow items-center gap-x-2">
|
||||||
<RiVerifiedBadgeLine className="h-4 w-4 text-text-primary" />
|
<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>
|
</div>
|
||||||
{!hideTip && <WebAppSSONotEnabledTip />}
|
{!hideTip && <WebAppSSONotEnabledTip />}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -98,13 +98,13 @@ export default function AccessControl(props: AccessControlProps) {
|
||||||
<AccessControlItem type={AccessMode.PUBLIC}>
|
<AccessControlItem type={AccessMode.PUBLIC}>
|
||||||
<div className="flex items-center gap-x-2 p-3">
|
<div className="flex items-center gap-x-2 p-3">
|
||||||
<RiGlobalLine className="h-4 w-4 text-text-primary" />
|
<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>
|
</div>
|
||||||
</AccessControlItem>
|
</AccessControlItem>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center justify-end gap-x-2 p-6 pt-5">
|
<div className="flex items-center justify-end gap-x-2 p-6 pt-5">
|
||||||
<Button onClick={onClose}>{t('common.operation.cancel')}</Button>
|
<Button onClick={onClose}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||||
<Button disabled={isPending} loading={isPending} variant="primary" onClick={handleConfirm}>{t('common.operation.confirm')}</Button>
|
<Button disabled={isPending} loading={isPending} variant="primary" onClick={handleConfirm}>{t('operation.confirm', { ns: 'common' })}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AccessControlDialog>
|
</AccessControlDialog>
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ export default function SpecificGroupsOrMembers() {
|
||||||
<div className="flex items-center p-3">
|
<div className="flex items-center p-3">
|
||||||
<div className="flex grow items-center gap-x-2">
|
<div className="flex grow items-center gap-x-2">
|
||||||
<RiLockLine className="h-4 w-4 text-text-primary" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
@ -40,7 +40,7 @@ export default function SpecificGroupsOrMembers() {
|
||||||
<div className="flex items-center gap-x-1 p-3">
|
<div className="flex items-center gap-x-1 p-3">
|
||||||
<div className="flex grow items-center gap-x-1">
|
<div className="flex grow items-center gap-x-1">
|
||||||
<RiLockLine className="h-4 w-4 text-text-primary" />
|
<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>
|
||||||
<div className="flex items-center gap-x-1">
|
<div className="flex items-center gap-x-1">
|
||||||
<AddMemberOrGroupDialog />
|
<AddMemberOrGroupDialog />
|
||||||
|
|
@ -60,14 +60,14 @@ function RenderGroupsAndMembers() {
|
||||||
const specificGroups = useAccessControlStore(s => s.specificGroups)
|
const specificGroups = useAccessControlStore(s => s.specificGroups)
|
||||||
const specificMembers = useAccessControlStore(s => s.specificMembers)
|
const specificMembers = useAccessControlStore(s => s.specificMembers)
|
||||||
if (specificGroups.length <= 0 && specificMembers.length <= 0)
|
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 (
|
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">
|
<div className="flex flex-row flex-wrap gap-1">
|
||||||
{specificGroups.map((group, index) => <GroupItem key={index} group={group} />)}
|
{specificGroups.map((group, index) => <GroupItem key={index} group={group} />)}
|
||||||
</div>
|
</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">
|
<div className="flex flex-row flex-wrap gap-1">
|
||||||
{specificMembers.map((member, index) => <MemberItem key={index} member={member} />)}
|
{specificMembers.map((member, index) => <MemberItem key={index} member={member} />)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -138,7 +138,7 @@ function BaseItem({ icon, onRemove, children }: BaseItemProps) {
|
||||||
export function WebAppSSONotEnabledTip() {
|
export function WebAppSSONotEnabledTip() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
return (
|
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" />
|
<RiAlertFill className="h-4 w-4 shrink-0 text-text-warning-secondary" />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -76,8 +76,8 @@ const FeaturesWrappedAppPublisher = (props: Props) => {
|
||||||
/>
|
/>
|
||||||
{restoreConfirmOpen && (
|
{restoreConfirmOpen && (
|
||||||
<Confirm
|
<Confirm
|
||||||
title={t('appDebug.resetConfig.title')}
|
title={t('resetConfig.title', { ns: 'appDebug' })}
|
||||||
content={t('appDebug.resetConfig.message')}
|
content={t('resetConfig.message', { ns: 'appDebug' })}
|
||||||
isShow={restoreConfirmOpen}
|
isShow={restoreConfirmOpen}
|
||||||
onConfirm={handleConfirm}
|
onConfirm={handleConfirm}
|
||||||
onCancel={() => setRestoreConfirmOpen(false)}
|
onCancel={() => setRestoreConfirmOpen(false)}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import type { ModelAndParameter } from '../configuration/debug/types'
|
import type { ModelAndParameter } from '../configuration/debug/types'
|
||||||
import type { InputVar, Variable } from '@/app/components/workflow/types'
|
import type { InputVar, Variable } from '@/app/components/workflow/types'
|
||||||
|
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||||
import type { PublishWorkflowParams } from '@/types/workflow'
|
import type { PublishWorkflowParams } from '@/types/workflow'
|
||||||
import {
|
import {
|
||||||
RiArrowDownSLine,
|
RiArrowDownSLine,
|
||||||
|
|
@ -53,7 +54,9 @@ import AccessControl from '../app-access-control'
|
||||||
import PublishWithMultipleModel from './publish-with-multiple-model'
|
import PublishWithMultipleModel from './publish-with-multiple-model'
|
||||||
import SuggestedAction from './suggested-action'
|
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]: {
|
[AccessMode.ORGANIZATION]: {
|
||||||
label: 'organization',
|
label: 'organization',
|
||||||
icon: RiBuildingLine,
|
icon: RiBuildingLine,
|
||||||
|
|
@ -84,7 +87,7 @@ const AccessModeDisplay: React.FC<{ mode?: AccessMode }> = ({ mode }) => {
|
||||||
<>
|
<>
|
||||||
<Icon className="h-4 w-4 shrink-0 text-text-secondary" />
|
<Icon className="h-4 w-4 shrink-0 text-text-secondary" />
|
||||||
<div className="grow truncate">
|
<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>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|
@ -162,11 +165,11 @@ const AppPublisher = ({
|
||||||
|
|
||||||
const disabledFunctionTooltip = useMemo(() => {
|
const disabledFunctionTooltip = useMemo(() => {
|
||||||
if (!publishedAt)
|
if (!publishedAt)
|
||||||
return t('app.notPublishedYet')
|
return t('notPublishedYet', { ns: 'app' })
|
||||||
if (missingStartNode)
|
if (missingStartNode)
|
||||||
return t('app.noUserInputNode')
|
return t('noUserInputNode', { ns: 'app' })
|
||||||
if (noAccessPermission)
|
if (noAccessPermission)
|
||||||
return t('app.noAccessPermission')
|
return t('noAccessPermission', { ns: 'app' })
|
||||||
}, [missingStartNode, noAccessPermission, publishedAt])
|
}, [missingStartNode, noAccessPermission, publishedAt])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -256,7 +259,7 @@ const AppPublisher = ({
|
||||||
|
|
||||||
const hasPublishedVersion = !!publishedAt
|
const hasPublishedVersion = !!publishedAt
|
||||||
const workflowToolDisabled = !hasPublishedVersion || !workflowToolAvailable
|
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 showStartNodeLimitHint = Boolean(startNodeLimitExceeded)
|
||||||
const upgradeHighlightStyle = useMemo(() => ({
|
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%)',
|
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"
|
className="py-2 pl-3 pr-2"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{t('workflow.common.publish')}
|
{t('common.publish', { ns: 'workflow' })}
|
||||||
<RiArrowDownSLine className="h-4 w-4 text-components-button-primary-text" />
|
<RiArrowDownSLine className="h-4 w-4 text-components-button-primary-text" />
|
||||||
</Button>
|
</Button>
|
||||||
</PortalToFollowElemTrigger>
|
</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="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="p-4 pt-3">
|
||||||
<div className="system-xs-medium-uppercase flex h-6 items-center text-text-tertiary">
|
<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>
|
</div>
|
||||||
{publishedAt
|
{publishedAt
|
||||||
? (
|
? (
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div className="system-sm-medium flex items-center text-text-secondary">
|
<div className="system-sm-medium flex items-center text-text-secondary">
|
||||||
{t('workflow.common.publishedAt')}
|
{t('common.publishedAt', { ns: 'workflow' })}
|
||||||
{' '}
|
{' '}
|
||||||
{formatTimeFromNow(publishedAt)}
|
{formatTimeFromNow(publishedAt)}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -307,14 +310,14 @@ const AppPublisher = ({
|
||||||
onClick={handleRestore}
|
onClick={handleRestore}
|
||||||
disabled={published}
|
disabled={published}
|
||||||
>
|
>
|
||||||
{t('workflow.common.restore')}
|
{t('common.restore', { ns: 'workflow' })}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
: (
|
: (
|
||||||
<div className="system-sm-medium flex items-center text-text-secondary">
|
<div className="system-sm-medium flex items-center text-text-secondary">
|
||||||
{t('workflow.common.autoSaved')}
|
{t('common.autoSaved', { ns: 'workflow' })}
|
||||||
{' '}
|
{' '}
|
||||||
·
|
·
|
||||||
{Boolean(draftUpdatedAt) && formatTimeFromNow(draftUpdatedAt!)}
|
{Boolean(draftUpdatedAt) && formatTimeFromNow(draftUpdatedAt!)}
|
||||||
|
|
@ -338,10 +341,10 @@ const AppPublisher = ({
|
||||||
>
|
>
|
||||||
{
|
{
|
||||||
published
|
published
|
||||||
? t('workflow.common.published')
|
? t('common.published', { ns: 'workflow' })
|
||||||
: (
|
: (
|
||||||
<div className="flex gap-1">
|
<div className="flex gap-1">
|
||||||
<span>{t('workflow.common.publishUpdate')}</span>
|
<span>{t('common.publishUpdate', { ns: 'workflow' })}</span>
|
||||||
<div className="flex gap-0.5">
|
<div className="flex gap-0.5">
|
||||||
{PUBLISH_SHORTCUT.map(key => (
|
{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">
|
<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"
|
className="text-sm font-semibold leading-5 text-transparent"
|
||||||
style={upgradeHighlightStyle}
|
style={upgradeHighlightStyle}
|
||||||
>
|
>
|
||||||
<span className="block">{t('workflow.publishLimit.startNodeTitlePrefix')}</span>
|
<span className="block">{t('publishLimit.startNodeTitlePrefix', { ns: 'workflow' })}</span>
|
||||||
<span className="block">{t('workflow.publishLimit.startNodeTitleSuffix')}</span>
|
<span className="block">{t('publishLimit.startNodeTitleSuffix', { ns: 'workflow' })}</span>
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs leading-4 text-text-secondary">
|
<p className="mt-1 text-xs leading-4 text-text-secondary">
|
||||||
{t('workflow.publishLimit.startNodeDesc')}
|
{t('publishLimit.startNodeDesc', { ns: 'workflow' })}
|
||||||
</p>
|
</p>
|
||||||
<UpgradeBtn
|
<UpgradeBtn
|
||||||
isShort
|
isShort
|
||||||
|
|
@ -382,7 +385,7 @@ const AppPublisher = ({
|
||||||
{systemFeatures.webapp_auth.enabled && (
|
{systemFeatures.webapp_auth.enabled && (
|
||||||
<div className="p-4 pt-3">
|
<div className="p-4 pt-3">
|
||||||
<div className="flex h-6 items-center">
|
<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>
|
||||||
<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"
|
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">
|
<div className="flex grow items-center gap-x-1.5 overflow-hidden pr-1">
|
||||||
<AccessModeDisplay mode={appDetail?.access_mode} />
|
<AccessModeDisplay mode={appDetail?.access_mode} />
|
||||||
</div>
|
</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">
|
<div className="flex h-4 w-4 shrink-0 items-center justify-center">
|
||||||
<RiArrowRightSLine className="h-4 w-4 text-text-quaternary" />
|
<RiArrowRightSLine className="h-4 w-4 text-text-quaternary" />
|
||||||
</div>
|
</div>
|
||||||
</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>
|
</div>
|
||||||
)}
|
)}
|
||||||
{
|
{
|
||||||
|
|
@ -412,7 +415,7 @@ const AppPublisher = ({
|
||||||
link={appURL}
|
link={appURL}
|
||||||
icon={<RiPlayCircleLine className="h-4 w-4" />}
|
icon={<RiPlayCircleLine className="h-4 w-4" />}
|
||||||
>
|
>
|
||||||
{t('workflow.common.runApp')}
|
{t('common.runApp', { ns: 'workflow' })}
|
||||||
</SuggestedAction>
|
</SuggestedAction>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{appDetail?.mode === AppModeEnum.WORKFLOW || appDetail?.mode === AppModeEnum.COMPLETION
|
{appDetail?.mode === AppModeEnum.WORKFLOW || appDetail?.mode === AppModeEnum.COMPLETION
|
||||||
|
|
@ -424,7 +427,7 @@ const AppPublisher = ({
|
||||||
link={`${appURL}${appURL.includes('?') ? '&' : '?'}mode=batch`}
|
link={`${appURL}${appURL.includes('?') ? '&' : '?'}mode=batch`}
|
||||||
icon={<RiPlayList2Line className="h-4 w-4" />}
|
icon={<RiPlayList2Line className="h-4 w-4" />}
|
||||||
>
|
>
|
||||||
{t('workflow.common.batchRunApp')}
|
{t('common.batchRunApp', { ns: 'workflow' })}
|
||||||
</SuggestedAction>
|
</SuggestedAction>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)
|
)
|
||||||
|
|
@ -437,7 +440,7 @@ const AppPublisher = ({
|
||||||
disabled={!publishedAt}
|
disabled={!publishedAt}
|
||||||
icon={<CodeBrowser className="h-4 w-4" />}
|
icon={<CodeBrowser className="h-4 w-4" />}
|
||||||
>
|
>
|
||||||
{t('workflow.common.embedIntoSite')}
|
{t('common.embedIntoSite', { ns: 'workflow' })}
|
||||||
</SuggestedAction>
|
</SuggestedAction>
|
||||||
)}
|
)}
|
||||||
<Tooltip triggerClassName="flex" disabled={!disabledFunctionButton} popupContent={disabledFunctionTooltip} asChild={false}>
|
<Tooltip triggerClassName="flex" disabled={!disabledFunctionButton} popupContent={disabledFunctionTooltip} asChild={false}>
|
||||||
|
|
@ -450,17 +453,17 @@ const AppPublisher = ({
|
||||||
disabled={disabledFunctionButton}
|
disabled={disabledFunctionButton}
|
||||||
icon={<RiPlanetLine className="h-4 w-4" />}
|
icon={<RiPlanetLine className="h-4 w-4" />}
|
||||||
>
|
>
|
||||||
{t('workflow.common.openInExplore')}
|
{t('common.openInExplore', { ns: 'workflow' })}
|
||||||
</SuggestedAction>
|
</SuggestedAction>
|
||||||
</Tooltip>
|
</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
|
<SuggestedAction
|
||||||
className="flex-1"
|
className="flex-1"
|
||||||
disabled={!publishedAt || missingStartNode}
|
disabled={!publishedAt || missingStartNode}
|
||||||
link="./develop"
|
link="./develop"
|
||||||
icon={<RiTerminalBoxLine className="h-4 w-4" />}
|
icon={<RiTerminalBoxLine className="h-4 w-4" />}
|
||||||
>
|
>
|
||||||
{t('workflow.common.accessAPIReference')}
|
{t('common.accessAPIReference', { ns: 'workflow' })}
|
||||||
</SuggestedAction>
|
</SuggestedAction>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
{appDetail?.mode === AppModeEnum.WORKFLOW && (
|
{appDetail?.mode === AppModeEnum.WORKFLOW && (
|
||||||
|
|
|
||||||
|
|
@ -72,14 +72,14 @@ const PublishWithMultipleModel: FC<PublishWithMultipleModelProps> = ({
|
||||||
disabled={!validModelConfigs.length}
|
disabled={!validModelConfigs.length}
|
||||||
className="mt-3 w-full"
|
className="mt-3 w-full"
|
||||||
>
|
>
|
||||||
{t('appDebug.operation.applyConfig')}
|
{t('operation.applyConfig', { ns: 'appDebug' })}
|
||||||
<RiArrowDownSLine className="ml-0.5 h-3 w-3" />
|
<RiArrowDownSLine className="ml-0.5 h-3 w-3" />
|
||||||
</Button>
|
</Button>
|
||||||
</PortalToFollowElemTrigger>
|
</PortalToFollowElemTrigger>
|
||||||
<PortalToFollowElemContent className="z-50 mt-1 w-[288px]">
|
<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="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">
|
<div className="flex h-[22px] items-center px-3 text-xs font-medium text-text-tertiary">
|
||||||
{t('appDebug.publishAs')}
|
{t('publishAs', { ns: 'appDebug' })}
|
||||||
</div>
|
</div>
|
||||||
{
|
{
|
||||||
validModelConfigs.map((item, index) => (
|
validModelConfigs.map((item, index) => (
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
|
||||||
setTitleError(true)
|
setTitleError(true)
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t('workflow.versionHistory.editField.titleLengthLimit', { limit: TITLE_MAX_LENGTH }),
|
message: t('versionHistory.editField.titleLengthLimit', { ns: 'workflow', limit: TITLE_MAX_LENGTH }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -50,7 +50,7 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
|
||||||
setReleaseNotesError(true)
|
setReleaseNotesError(true)
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -75,7 +75,7 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
|
||||||
<Modal className="p-0" isShow={isOpen} onClose={onClose}>
|
<Modal className="p-0" isShow={isOpen} onClose={onClose}>
|
||||||
<div className="relative w-full p-6 pb-4 pr-14">
|
<div className="relative w-full p-6 pb-4 pr-14">
|
||||||
<div className="title-2xl-semi-bold text-text-primary first-letter:capitalize">
|
<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>
|
||||||
<div className="absolute right-5 top-5 flex h-8 w-8 cursor-pointer items-center justify-center p-1.5" onClick={onClose}>
|
<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" />
|
<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-4 px-6 py-3">
|
||||||
<div className="flex flex-col gap-y-1">
|
<div className="flex flex-col gap-y-1">
|
||||||
<div className="system-sm-semibold flex h-6 items-center text-text-secondary">
|
<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>
|
</div>
|
||||||
<Input
|
<Input
|
||||||
value={title}
|
value={title}
|
||||||
placeholder={`${t('workflow.versionHistory.nameThisVersion')}${t('workflow.panel.optional')}`}
|
placeholder={`${t('versionHistory.nameThisVersion', { ns: 'workflow' })}${t('panel.optional', { ns: 'workflow' })}`}
|
||||||
onChange={handleTitleChange}
|
onChange={handleTitleChange}
|
||||||
destructive={titleError}
|
destructive={titleError}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-y-1">
|
<div className="flex flex-col gap-y-1">
|
||||||
<div className="system-sm-semibold flex h-6 items-center text-text-secondary">
|
<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>
|
</div>
|
||||||
<Textarea
|
<Textarea
|
||||||
value={releaseNotes}
|
value={releaseNotes}
|
||||||
placeholder={`${t('workflow.versionHistory.releaseNotesPlaceholder')}${t('workflow.panel.optional')}`}
|
placeholder={`${t('versionHistory.releaseNotesPlaceholder', { ns: 'workflow' })}${t('panel.optional', { ns: 'workflow' })}`}
|
||||||
onChange={handleDescriptionChange}
|
onChange={handleDescriptionChange}
|
||||||
destructive={releaseNotesError}
|
destructive={releaseNotesError}
|
||||||
/>
|
/>
|
||||||
|
|
@ -107,8 +107,8 @@ const VersionInfoModal: FC<VersionInfoModalProps> = ({
|
||||||
</div>
|
</div>
|
||||||
<div className="flex justify-end p-6 pt-5">
|
<div className="flex justify-end p-6 pt-5">
|
||||||
<div className="flex items-center gap-x-3">
|
<div className="flex items-center gap-x-3">
|
||||||
<Button onClick={onClose}>{t('common.operation.cancel')}</Button>
|
<Button onClick={onClose}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||||
<Button variant="primary" onClick={handlePublish}>{t('workflow.common.publish')}</Button>
|
<Button variant="primary" onClick={handlePublish}>{t('common.publish', { ns: 'workflow' })}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ const OperationBtn: FC<IOperationBtnProps> = ({
|
||||||
{iconMap[type]}
|
{iconMap[type]}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs font-medium">
|
<div className="text-xs font-medium">
|
||||||
{actionName || t(`common.operation.${type}`)}
|
{actionName || t(`operation.${type}`, { ns: 'common' })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -16,12 +16,12 @@ const FormattingChanged: FC<IFormattingChangedProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WarningMask
|
<WarningMask
|
||||||
title={t('appDebug.feature.dataSet.queryVariable.unableToQueryDataSet')}
|
title={t('feature.dataSet.queryVariable.unableToQueryDataSet', { ns: 'appDebug' })}
|
||||||
description={t('appDebug.feature.dataSet.queryVariable.unableToQueryDataSetTip')}
|
description={t('feature.dataSet.queryVariable.unableToQueryDataSetTip', { ns: 'appDebug' })}
|
||||||
footer={(
|
footer={(
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<Button variant="primary" className="flex !w-[96px] justify-start" onClick={onConfirm}>
|
<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>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -24,15 +24,15 @@ const FormattingChanged: FC<IFormattingChangedProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WarningMask
|
<WarningMask
|
||||||
title={t('appDebug.formattingChangedTitle')}
|
title={t('formattingChangedTitle', { ns: 'appDebug' })}
|
||||||
description={t('appDebug.formattingChangedText')}
|
description={t('formattingChangedText', { ns: 'appDebug' })}
|
||||||
footer={(
|
footer={(
|
||||||
<div className="flex space-x-2">
|
<div className="flex space-x-2">
|
||||||
<Button variant="primary" className="flex space-x-2" onClick={onConfirm}>
|
<Button variant="primary" className="flex space-x-2" onClick={onConfirm}>
|
||||||
{icon}
|
{icon}
|
||||||
<span>{t('common.operation.refresh')}</span>
|
<span>{t('operation.refresh', { ns: 'common' })}</span>
|
||||||
</Button>
|
</Button>
|
||||||
<Button onClick={onCancel}>{t('common.operation.cancel') as string}</Button>
|
<Button onClick={onCancel}>{t('operation.cancel', { ns: 'common' }) as string}</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,11 @@ const HasNotSetAPI: FC<IHasNotSetAPIProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<WarningMask
|
<WarningMask
|
||||||
title={isTrailFinished ? t('appDebug.notSetAPIKey.trailFinished') : t('appDebug.notSetAPIKey.title')}
|
title={isTrailFinished ? t('notSetAPIKey.trailFinished', { ns: 'appDebug' }) : t('notSetAPIKey.title', { ns: 'appDebug' })}
|
||||||
description={t('appDebug.notSetAPIKey.description')}
|
description={t('notSetAPIKey.description', { ns: 'appDebug' })}
|
||||||
footer={(
|
footer={(
|
||||||
<Button variant="primary" className="flex space-x-2" onClick={onSetting}>
|
<Button variant="primary" className="flex space-x-2" onClick={onSetting}>
|
||||||
<span>{t('appDebug.notSetAPIKey.settingBtn')}</span>
|
<span>{t('notSetAPIKey.settingBtn', { ns: 'appDebug' })}</span>
|
||||||
{icon}
|
{icon}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -94,7 +94,7 @@ const AdvancedPromptInput: FC<Props> = ({
|
||||||
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
||||||
for (let i = 0; i < promptVariables.length; i++) {
|
for (let i = 0; i < promptVariables.length; i++) {
|
||||||
if (promptVariables[i].key === newExternalDataTool.variable) {
|
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
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -152,14 +152,14 @@ const AdvancedPromptInput: FC<Props> = ({
|
||||||
>
|
>
|
||||||
<div className="flex items-center pr-2">
|
<div className="flex items-center pr-2">
|
||||||
<RiErrorWarningFill className="mr-1 h-4 w-4 text-[#F79009]" />
|
<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>
|
</div>
|
||||||
<Button
|
<Button
|
||||||
size="small"
|
size="small"
|
||||||
variant="secondary-accent"
|
variant="secondary-accent"
|
||||||
onClick={onHideContextMissingTip}
|
onClick={onHideContextMissingTip}
|
||||||
>
|
>
|
||||||
{t('common.operation.ok')}
|
{t('operation.ok', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
@ -178,12 +178,12 @@ const AdvancedPromptInput: FC<Props> = ({
|
||||||
<div className="flex items-center space-x-1">
|
<div className="flex items-center space-x-1">
|
||||||
|
|
||||||
<div className="text-sm font-semibold uppercase text-indigo-800">
|
<div className="text-sm font-semibold uppercase text-indigo-800">
|
||||||
{t('appDebug.pageTitle.line1')}
|
{t('pageTitle.line1', { ns: 'appDebug' })}
|
||||||
</div>
|
</div>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={(
|
popupContent={(
|
||||||
<div className="w-[180px]">
|
<div className="w-[180px]">
|
||||||
{t('appDebug.promptTip')}
|
{t('promptTip', { ns: 'appDebug' })}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -54,7 +54,7 @@ const ConfirmAddVar: FC<IConfirmAddVarProps> = ({
|
||||||
{VarIcon}
|
{VarIcon}
|
||||||
</div>
|
</div>
|
||||||
<div className="grow-1">
|
<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">
|
<div className="mt-[15px] flex max-h-[66px] flex-wrap space-x-1 overflow-y-auto px-1">
|
||||||
{varNameArr.map(name => (
|
{varNameArr.map(name => (
|
||||||
<VarHighlight key={name} name={name} />
|
<VarHighlight key={name} name={name} />
|
||||||
|
|
@ -63,8 +63,8 @@ const ConfirmAddVar: FC<IConfirmAddVarProps> = ({
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-7 flex justify-end space-x-2">
|
<div className="mt-7 flex justify-end space-x-2">
|
||||||
<Button onClick={onCancel}>{t('common.operation.cancel')}</Button>
|
<Button onClick={onCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||||
<Button variant="primary" onClick={onConfirm}>{t('common.operation.add')}</Button>
|
<Button variant="primary" onClick={onConfirm}>{t('operation.add', { ns: 'common' })}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,11 @@ const EditModal: FC<Props> = ({
|
||||||
const [tempData, setTempData] = useState(data)
|
const [tempData, setTempData] = useState(data)
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={t('appDebug.feature.conversationHistory.editModal.title')}
|
title={t('feature.conversationHistory.editModal.title', { ns: 'appDebug' })}
|
||||||
isShow={isShow}
|
isShow={isShow}
|
||||||
onClose={onClose}
|
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
|
<input
|
||||||
className="mt-2 box-border h-10 w-full rounded-lg bg-components-input-bg-normal px-3 text-sm leading-10"
|
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}
|
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
|
<input
|
||||||
className="mt-2 box-border h-10 w-full rounded-lg bg-components-input-bg-normal px-3 text-sm leading-10"
|
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}
|
value={tempData.assistant_prefix}
|
||||||
|
|
@ -48,12 +48,12 @@ const EditModal: FC<Props> = ({
|
||||||
...tempData,
|
...tempData,
|
||||||
assistant_prefix: e.target.value,
|
assistant_prefix: e.target.value,
|
||||||
})}
|
})}
|
||||||
placeholder={t('common.chat.conversationNamePlaceholder') || ''}
|
placeholder={t('chat.conversationNamePlaceholder', { ns: 'common' }) || ''}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="mt-10 flex justify-end">
|
<div className="mt-10 flex justify-end">
|
||||||
<Button className="mr-2 shrink-0" onClick={onClose}>{t('common.operation.cancel')}</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('common.operation.save')}</Button>
|
<Button variant="primary" className="shrink-0" onClick={() => onSave(tempData)} loading={saveLoading}>{t('operation.save', { ns: 'common' })}</Button>
|
||||||
</div>
|
</div>
|
||||||
</Modal>
|
</Modal>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ const HistoryPanel: FC<Props> = ({
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
title={(
|
title={(
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div>{t('appDebug.feature.conversationHistory.title')}</div>
|
<div>{t('feature.conversationHistory.title', { ns: 'appDebug' })}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
headerIcon={(
|
headerIcon={(
|
||||||
|
|
@ -34,7 +34,7 @@ const HistoryPanel: FC<Props> = ({
|
||||||
)}
|
)}
|
||||||
headerRight={(
|
headerRight={(
|
||||||
<div className="flex items-center">
|
<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>
|
<div className="ml-3 h-[14px] w-[1px] bg-divider-regular"></div>
|
||||||
<OperationBtn type="edit" onClick={onShowEditModal} />
|
<OperationBtn type="edit" onClick={onShowEditModal} />
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -44,14 +44,14 @@ const HistoryPanel: FC<Props> = ({
|
||||||
{showWarning && (
|
{showWarning && (
|
||||||
<div className="flex justify-between rounded-b-xl bg-background-section-burn px-3 py-2 text-xs text-text-secondary">
|
<div className="flex justify-between rounded-b-xl bg-background-section-burn px-3 py-2 text-xs text-text-secondary">
|
||||||
<div>
|
<div>
|
||||||
{t('appDebug.feature.conversationHistory.tip')}
|
{t('feature.conversationHistory.tip', { ns: 'appDebug' })}
|
||||||
<a
|
<a
|
||||||
href={docLink('/learn-more/extended-reading/what-is-llmops', { 'zh-Hans': '/learn-more/extended-reading/prompt-engineering/README' })}
|
href={docLink('/learn-more/extended-reading/what-is-llmops', { 'zh-Hans': '/learn-more/extended-reading/prompt-engineering/README' })}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
className="text-[#155EEF]"
|
className="text-[#155EEF]"
|
||||||
>
|
>
|
||||||
{t('appDebug.feature.conversationHistory.learnMore')}
|
{t('feature.conversationHistory.learnMore', { ns: 'appDebug' })}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -162,7 +162,7 @@ const Prompt: FC<IPromptProps> = ({
|
||||||
className="mt-3 w-full"
|
className="mt-3 w-full"
|
||||||
>
|
>
|
||||||
<RiAddLine className="mr-2 h-4 w-4" />
|
<RiAddLine className="mr-2 h-4 w-4" />
|
||||||
<div>{t('appDebug.promptMode.operation.addMessage')}</div>
|
<div>{t('promptMode.operation.addMessage', { ns: 'appDebug' })}</div>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ const Prompt: FC<ISimplePromptInput> = ({
|
||||||
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
||||||
for (let i = 0; i < promptVariables.length; i++) {
|
for (let i = 0; i < promptVariables.length; i++) {
|
||||||
if (promptVariables[i].key === newExternalDataTool.variable) {
|
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
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -178,12 +178,12 @@ const Prompt: FC<ISimplePromptInput> = ({
|
||||||
{!noTitle && (
|
{!noTitle && (
|
||||||
<div className="flex h-11 items-center justify-between pl-3 pr-2.5">
|
<div className="flex h-11 items-center justify-between pl-3 pr-2.5">
|
||||||
<div className="flex items-center space-x-1">
|
<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 && (
|
{!readonly && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={(
|
popupContent={(
|
||||||
<div className="w-[180px]">
|
<div className="w-[180px]">
|
||||||
{t('appDebug.promptTip')}
|
{t('promptTip', { ns: 'appDebug' })}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ const Field: FC<Props> = ({
|
||||||
{isOptional && (
|
{isOptional && (
|
||||||
<span className="system-xs-regular ml-1 text-text-tertiary">
|
<span className="system-xs-regular ml-1 text-text-tertiary">
|
||||||
(
|
(
|
||||||
{t('appDebug.variableConfig.optional')}
|
{t('variableConfig.optional', { ns: 'appDebug' })}
|
||||||
)
|
)
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -102,7 +102,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
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
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -144,40 +144,40 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
|
|
||||||
const selectOptions: SelectItem[] = [
|
const selectOptions: SelectItem[] = [
|
||||||
{
|
{
|
||||||
name: t('appDebug.variableConfig.text-input'),
|
name: t('variableConfig.text-input', { ns: 'appDebug' }),
|
||||||
value: InputVarType.textInput,
|
value: InputVarType.textInput,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t('appDebug.variableConfig.paragraph'),
|
name: t('variableConfig.paragraph', { ns: 'appDebug' }),
|
||||||
value: InputVarType.paragraph,
|
value: InputVarType.paragraph,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t('appDebug.variableConfig.select'),
|
name: t('variableConfig.select', { ns: 'appDebug' }),
|
||||||
value: InputVarType.select,
|
value: InputVarType.select,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t('appDebug.variableConfig.number'),
|
name: t('variableConfig.number', { ns: 'appDebug' }),
|
||||||
value: InputVarType.number,
|
value: InputVarType.number,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t('appDebug.variableConfig.checkbox'),
|
name: t('variableConfig.checkbox', { ns: 'appDebug' }),
|
||||||
value: InputVarType.checkbox,
|
value: InputVarType.checkbox,
|
||||||
},
|
},
|
||||||
...(supportFile
|
...(supportFile
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
name: t('appDebug.variableConfig.single-file'),
|
name: t('variableConfig.single-file', { ns: 'appDebug' }),
|
||||||
value: InputVarType.singleFile,
|
value: InputVarType.singleFile,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: t('appDebug.variableConfig.multi-files'),
|
name: t('variableConfig.multi-files', { ns: 'appDebug' }),
|
||||||
value: InputVarType.multiFiles,
|
value: InputVarType.multiFiles,
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
: []),
|
: []),
|
||||||
...((!isBasicApp && isSupportJSON)
|
...((!isBasicApp && isSupportJSON)
|
||||||
? [{
|
? [{
|
||||||
name: t('appDebug.variableConfig.json'),
|
name: t('variableConfig.json', { ns: 'appDebug' }),
|
||||||
value: InputVarType.jsonObject,
|
value: InputVarType.jsonObject,
|
||||||
}]
|
}]
|
||||||
: []),
|
: []),
|
||||||
|
|
@ -224,7 +224,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
if (!isValid) {
|
if (!isValid) {
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
message: t(`appDebug.varKeyError.${errorMessageKey}` as any, { key: errorKey }) as string,
|
message: t(`varKeyError.${errorMessageKey}`, { ns: 'appDebug', key: errorKey }),
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -246,7 +246,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
return
|
return
|
||||||
|
|
||||||
if (!tempPayload.label) {
|
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
|
return
|
||||||
}
|
}
|
||||||
if (isStringInput || type === InputVarType.number) {
|
if (isStringInput || type === InputVarType.number) {
|
||||||
|
|
@ -254,7 +254,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
}
|
}
|
||||||
else if (type === InputVarType.select) {
|
else if (type === InputVarType.select) {
|
||||||
if (options?.length === 0) {
|
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
|
return
|
||||||
}
|
}
|
||||||
const obj: Record<string, boolean> = {}
|
const obj: Record<string, boolean> = {}
|
||||||
|
|
@ -267,19 +267,19 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
obj[o] = true
|
obj[o] = true
|
||||||
})
|
})
|
||||||
if (hasRepeatedItem) {
|
if (hasRepeatedItem) {
|
||||||
Toast.notify({ type: 'error', message: t('appDebug.variableConfig.errorMsg.optionRepeat') })
|
Toast.notify({ type: 'error', message: t('variableConfig.errorMsg.optionRepeat', { ns: 'appDebug' }) })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
onConfirm(tempPayload, moreInfo)
|
onConfirm(tempPayload, moreInfo)
|
||||||
}
|
}
|
||||||
else if ([InputVarType.singleFile, InputVarType.multiFiles].includes(type)) {
|
else if ([InputVarType.singleFile, InputVarType.multiFiles].includes(type)) {
|
||||||
if (tempPayload.allowed_file_types?.length === 0) {
|
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 })
|
Toast.notify({ type: 'error', message: errorMessages })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if (tempPayload.allowed_file_types?.includes(SupportUploadFileTypes.custom) && !tempPayload.allowed_file_extensions?.length) {
|
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 })
|
Toast.notify({ type: 'error', message: errorMessages })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -292,34 +292,34 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
title={t(`appDebug.variableConfig.${isCreate ? 'addModalTitle' : 'editModalTitle'}`)}
|
title={t(`variableConfig.${isCreate ? 'addModalTitle' : 'editModalTitle'}`, { ns: 'appDebug' })}
|
||||||
isShow={isShow}
|
isShow={isShow}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
>
|
>
|
||||||
<div className="mb-8" ref={modalRef} tabIndex={-1}>
|
<div className="mb-8" ref={modalRef} tabIndex={-1}>
|
||||||
<div className="space-y-2">
|
<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} />
|
<TypeSelector value={type} items={selectOptions} onSelect={handleTypeChange} />
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
<Field title={t('appDebug.variableConfig.varName')}>
|
<Field title={t('variableConfig.varName', { ns: 'appDebug' })}>
|
||||||
<Input
|
<Input
|
||||||
value={variable}
|
value={variable}
|
||||||
onChange={handleVarNameChange}
|
onChange={handleVarNameChange}
|
||||||
onBlur={handleVarKeyBlur}
|
onBlur={handleVarKeyBlur}
|
||||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
<Field title={t('appDebug.variableConfig.labelName')}>
|
<Field title={t('variableConfig.labelName', { ns: 'appDebug' })}>
|
||||||
<Input
|
<Input
|
||||||
value={label as string}
|
value={label as string}
|
||||||
onChange={e => handlePayloadChange('label')(e.target.value)}
|
onChange={e => handlePayloadChange('label')(e.target.value)}
|
||||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
{isStringInput && (
|
{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')} />
|
<ConfigString maxLength={type === InputVarType.textInput ? TEXT_MAX_LENGTH : Infinity} modelId={modelConfig.model_id} value={max_length} onChange={handlePayloadChange('max_length')} />
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
|
|
@ -327,50 +327,50 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
|
|
||||||
{/* Default value for text input */}
|
{/* Default value for text input */}
|
||||||
{type === InputVarType.textInput && (
|
{type === InputVarType.textInput && (
|
||||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||||
<Input
|
<Input
|
||||||
value={tempPayload.default || ''}
|
value={tempPayload.default || ''}
|
||||||
onChange={e => handlePayloadChange('default')(e.target.value || undefined)}
|
onChange={e => handlePayloadChange('default')(e.target.value || undefined)}
|
||||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Default value for paragraph */}
|
{/* Default value for paragraph */}
|
||||||
{type === InputVarType.paragraph && (
|
{type === InputVarType.paragraph && (
|
||||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||||
<Textarea
|
<Textarea
|
||||||
value={String(tempPayload.default ?? '')}
|
value={String(tempPayload.default ?? '')}
|
||||||
onChange={e => handlePayloadChange('default')(e.target.value || undefined)}
|
onChange={e => handlePayloadChange('default')(e.target.value || undefined)}
|
||||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Default value for number input */}
|
{/* Default value for number input */}
|
||||||
{type === InputVarType.number && (
|
{type === InputVarType.number && (
|
||||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||||
<Input
|
<Input
|
||||||
type="number"
|
type="number"
|
||||||
value={tempPayload.default || ''}
|
value={tempPayload.default || ''}
|
||||||
onChange={e => handlePayloadChange('default')(e.target.value || undefined)}
|
onChange={e => handlePayloadChange('default')(e.target.value || undefined)}
|
||||||
placeholder={t('appDebug.variableConfig.inputPlaceholder')!}
|
placeholder={t('variableConfig.inputPlaceholder', { ns: 'appDebug' })!}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{type === InputVarType.checkbox && (
|
{type === InputVarType.checkbox && (
|
||||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||||
<SimpleSelect
|
<SimpleSelect
|
||||||
className="w-full"
|
className="w-full"
|
||||||
optionWrapClassName="max-h-[140px] overflow-y-auto"
|
optionWrapClassName="max-h-[140px] overflow-y-auto"
|
||||||
items={[
|
items={[
|
||||||
{ value: CHECKBOX_DEFAULT_TRUE_VALUE, name: t('appDebug.variableConfig.startChecked') },
|
{ value: CHECKBOX_DEFAULT_TRUE_VALUE, name: t('variableConfig.startChecked', { ns: 'appDebug' }) },
|
||||||
{ value: CHECKBOX_DEFAULT_FALSE_VALUE, name: t('appDebug.variableConfig.noDefaultSelected') },
|
{ value: CHECKBOX_DEFAULT_FALSE_VALUE, name: t('variableConfig.noDefaultSelected', { ns: 'appDebug' }) },
|
||||||
]}
|
]}
|
||||||
defaultValue={checkboxDefaultSelectValue}
|
defaultValue={checkboxDefaultSelectValue}
|
||||||
onSelect={item => handlePayloadChange('default')(parseCheckboxSelectValue(String(item.value)))}
|
onSelect={item => handlePayloadChange('default')(parseCheckboxSelectValue(String(item.value)))}
|
||||||
placeholder={t('appDebug.variableConfig.selectDefaultValue')}
|
placeholder={t('variableConfig.selectDefaultValue', { ns: 'appDebug' })}
|
||||||
allowSearch={false}
|
allowSearch={false}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
@ -378,17 +378,17 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
|
|
||||||
{type === InputVarType.select && (
|
{type === InputVarType.select && (
|
||||||
<>
|
<>
|
||||||
<Field title={t('appDebug.variableConfig.options')}>
|
<Field title={t('variableConfig.options', { ns: 'appDebug' })}>
|
||||||
<ConfigSelect options={options || []} onChange={handlePayloadChange('options')} />
|
<ConfigSelect options={options || []} onChange={handlePayloadChange('options')} />
|
||||||
</Field>
|
</Field>
|
||||||
{options && options.length > 0 && (
|
{options && options.length > 0 && (
|
||||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||||
<SimpleSelect
|
<SimpleSelect
|
||||||
key={`default-select-${options.join('-')}`}
|
key={`default-select-${options.join('-')}`}
|
||||||
className="w-full"
|
className="w-full"
|
||||||
optionWrapClassName="max-h-[140px] overflow-y-auto"
|
optionWrapClassName="max-h-[140px] overflow-y-auto"
|
||||||
items={[
|
items={[
|
||||||
{ value: '', name: t('appDebug.variableConfig.noDefaultValue') },
|
{ value: '', name: t('variableConfig.noDefaultValue', { ns: 'appDebug' }) },
|
||||||
...options.filter(opt => opt.trim() !== '').map(option => ({
|
...options.filter(opt => opt.trim() !== '').map(option => ({
|
||||||
value: option,
|
value: option,
|
||||||
name: option,
|
name: option,
|
||||||
|
|
@ -396,7 +396,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
]}
|
]}
|
||||||
defaultValue={tempPayload.default || ''}
|
defaultValue={tempPayload.default || ''}
|
||||||
onSelect={item => handlePayloadChange('default')(item.value === '' ? undefined : item.value)}
|
onSelect={item => handlePayloadChange('default')(item.value === '' ? undefined : item.value)}
|
||||||
placeholder={t('appDebug.variableConfig.selectDefaultValue')}
|
placeholder={t('variableConfig.selectDefaultValue', { ns: 'appDebug' })}
|
||||||
allowSearch={false}
|
allowSearch={false}
|
||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
|
|
@ -411,7 +411,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
onChange={(p: UploadFileSetting) => setTempPayload(p as InputVar)}
|
onChange={(p: UploadFileSetting) => setTempPayload(p as InputVar)}
|
||||||
isMultiple={type === InputVarType.multiFiles}
|
isMultiple={type === InputVarType.multiFiles}
|
||||||
/>
|
/>
|
||||||
<Field title={t('appDebug.variableConfig.defaultValue')}>
|
<Field title={t('variableConfig.defaultValue', { ns: 'appDebug' })}>
|
||||||
<FileUploaderInAttachmentWrapper
|
<FileUploaderInAttachmentWrapper
|
||||||
value={(type === InputVarType.singleFile ? (tempPayload.default ? [tempPayload.default] : []) : (tempPayload.default || [])) as unknown as FileEntity[]}
|
value={(type === InputVarType.singleFile ? (tempPayload.default ? [tempPayload.default] : []) : (tempPayload.default || [])) as unknown as FileEntity[]}
|
||||||
onChange={(files) => {
|
onChange={(files) => {
|
||||||
|
|
@ -432,7 +432,7 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{type === InputVarType.jsonObject && (
|
{type === InputVarType.jsonObject && (
|
||||||
<Field title={t('appDebug.variableConfig.jsonSchema')} isOptional>
|
<Field title={t('variableConfig.jsonSchema', { ns: 'appDebug' })} isOptional>
|
||||||
<CodeEditor
|
<CodeEditor
|
||||||
language={CodeLanguage.json}
|
language={CodeLanguage.json}
|
||||||
value={jsonSchemaStr}
|
value={jsonSchemaStr}
|
||||||
|
|
@ -448,12 +448,12 @@ const ConfigModal: FC<IConfigModalProps> = ({
|
||||||
|
|
||||||
<div className="!mt-5 flex h-6 items-center space-x-2">
|
<div className="!mt-5 flex h-6 items-center space-x-2">
|
||||||
<Checkbox checked={tempPayload.required} disabled={tempPayload.hide} onCheck={() => handlePayloadChange('required')(!tempPayload.required)} />
|
<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>
|
||||||
|
|
||||||
<div className="!mt-5 flex h-6 items-center space-x-2">
|
<div className="!mt-5 flex h-6 items-center space-x-2">
|
||||||
<Checkbox checked={tempPayload.hide} disabled={tempPayload.required} onCheck={() => handlePayloadChange('hide')(!tempPayload.hide)} />
|
<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>
|
</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"
|
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" />
|
<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>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ import type { FC } from 'react'
|
||||||
import type { InputVar } from '@/app/components/workflow/types'
|
import type { InputVar } from '@/app/components/workflow/types'
|
||||||
import type { ExternalDataTool } from '@/models/common'
|
import type { ExternalDataTool } from '@/models/common'
|
||||||
import type { PromptVariable } from '@/models/debug'
|
import type { PromptVariable } from '@/models/debug'
|
||||||
|
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||||
import { useBoolean } from 'ahooks'
|
import { useBoolean } from 'ahooks'
|
||||||
import { produce } from 'immer'
|
import { produce } from 'immer'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
|
@ -69,14 +70,14 @@ const buildPromptVariableFromInput = (payload: InputVar): PromptVariable => {
|
||||||
const getDuplicateError = (list: PromptVariable[]) => {
|
const getDuplicateError = (list: PromptVariable[]) => {
|
||||||
if (hasDuplicateStr(list.map(item => item.key))) {
|
if (hasDuplicateStr(list.map(item => item.key))) {
|
||||||
return {
|
return {
|
||||||
errorMsgKey: 'appDebug.varKeyError.keyAlreadyExists',
|
errorMsgKey: 'varKeyError.keyAlreadyExists',
|
||||||
typeName: 'appDebug.variableConfig.varName',
|
typeName: 'variableConfig.varName',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hasDuplicateStr(list.map(item => item.name as string))) {
|
if (hasDuplicateStr(list.map(item => item.name as string))) {
|
||||||
return {
|
return {
|
||||||
errorMsgKey: 'appDebug.varKeyError.keyAlreadyExists',
|
errorMsgKey: 'varKeyError.keyAlreadyExists',
|
||||||
typeName: 'appDebug.variableConfig.labelName',
|
typeName: 'variableConfig.labelName',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
|
|
@ -110,10 +111,11 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||||
})
|
})
|
||||||
const duplicateError = getDuplicateError(newPromptVariables)
|
const duplicateError = getDuplicateError(newPromptVariables)
|
||||||
if (duplicateError) {
|
if (duplicateError) {
|
||||||
|
// const a = t(duplicateError.errorMsgKey as any, { ns: 'appDebug' }),
|
||||||
|
|
||||||
Toast.notify({
|
Toast.notify({
|
||||||
type: 'error',
|
type: 'error',
|
||||||
// eslint-disable-next-line ts/no-explicit-any
|
message: t(duplicateError.errorMsgKey as I18nKeysByPrefix<'appDebug', 'duplicateError.'>, { ns: 'appDebug', key: t(duplicateError.typeName as I18nKeysByPrefix<'appDebug', 'duplicateError.'>, { ns: 'appDebug' }) }) as string,
|
||||||
message: t(duplicateError.errorMsgKey as any, { key: t(duplicateError.typeName as any) as string }) as string,
|
|
||||||
})
|
})
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
@ -164,7 +166,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||||
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
onValidateBeforeSaveCallback: (newExternalDataTool: ExternalDataTool) => {
|
||||||
for (let i = 0; i < promptVariables.length; i++) {
|
for (let i = 0; i < promptVariables.length; i++) {
|
||||||
if (promptVariables[i].key === newExternalDataTool.variable && i !== index) {
|
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
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -253,12 +255,12 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
title={(
|
title={(
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div className="mr-1">{t('appDebug.variableTitle')}</div>
|
<div className="mr-1">{t('variableTitle', { ns: 'appDebug' })}</div>
|
||||||
{!readonly && (
|
{!readonly && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={(
|
popupContent={(
|
||||||
<div className="w-[180px]">
|
<div className="w-[180px]">
|
||||||
{t('appDebug.variableTip')}
|
{t('variableTip', { ns: 'appDebug' })}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -270,7 +272,7 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||||
>
|
>
|
||||||
{!hasVar && (
|
{!hasVar && (
|
||||||
<div className="mt-1 px-3 pb-3">
|
<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>
|
</div>
|
||||||
)}
|
)}
|
||||||
{hasVar && (
|
{hasVar && (
|
||||||
|
|
@ -322,8 +324,8 @@ const ConfigVar: FC<IConfigVarProps> = ({ promptVariables, readonly, onPromptVar
|
||||||
{isShowDeleteContextVarModal && (
|
{isShowDeleteContextVarModal && (
|
||||||
<Confirm
|
<Confirm
|
||||||
isShow={isShowDeleteContextVarModal}
|
isShow={isShowDeleteContextVarModal}
|
||||||
title={t('appDebug.feature.dataSet.queryVariable.deleteContextVarTitle', { varName: promptVariables[removeIndex as number]?.name })}
|
title={t('feature.dataSet.queryVariable.deleteContextVarTitle', { ns: 'appDebug', varName: promptVariables[removeIndex as number]?.name })}
|
||||||
content={t('appDebug.feature.dataSet.queryVariable.deleteContextVarTip')}
|
content={t('feature.dataSet.queryVariable.deleteContextVarTip', { ns: 'appDebug' })}
|
||||||
onConfirm={() => {
|
onConfirm={() => {
|
||||||
didRemoveVar(removeIndex as number)
|
didRemoveVar(removeIndex as number)
|
||||||
hideDeleteContextVarModal()
|
hideDeleteContextVarModal()
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ const ModalFoot: FC<IModalFootProps> = ({
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
return (
|
return (
|
||||||
<div className="flex justify-end gap-2">
|
<div className="flex justify-end gap-2">
|
||||||
<Button onClick={onCancel}>{t('common.operation.cancel')}</Button>
|
<Button onClick={onCancel}>{t('operation.cancel', { ns: 'common' })}</Button>
|
||||||
<Button variant="primary" onClick={onConfirm}>{t('common.operation.save')}</Button>
|
<Button variant="primary" onClick={onConfirm}>{t('operation.save', { ns: 'common' })}</Button>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
'use client'
|
'use client'
|
||||||
import type { FC } from 'react'
|
import type { FC } from 'react'
|
||||||
import type { InputVarType } from '@/app/components/workflow/types'
|
import type { InputVarType } from '@/app/components/workflow/types'
|
||||||
|
import type { I18nKeysByPrefix } from '@/types/i18n'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
|
import InputVarTypeIcon from '@/app/components/workflow/nodes/_base/components/input-var-type-icon'
|
||||||
|
|
@ -12,7 +13,9 @@ export type ISelectTypeItemProps = {
|
||||||
onClick: () => void
|
onClick: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const i18nFileTypeMap: Record<string, string> = {
|
type VariableConfigTypeKey = I18nKeysByPrefix<'appDebug', 'variableConfig.'>
|
||||||
|
|
||||||
|
const i18nTypeMap: Partial<Record<InputVarType, VariableConfigTypeKey>> = {
|
||||||
'file': 'single-file',
|
'file': 'single-file',
|
||||||
'file-list': 'multi-files',
|
'file-list': 'multi-files',
|
||||||
}
|
}
|
||||||
|
|
@ -23,7 +26,8 @@ const SelectTypeItem: FC<ISelectTypeItemProps> = ({
|
||||||
onClick,
|
onClick,
|
||||||
}) => {
|
}) => {
|
||||||
const { t } = useTranslation()
|
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 (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
|
||||||
|
|
@ -62,15 +62,15 @@ const SelectVarType: FC<Props> = ({
|
||||||
<PortalToFollowElemContent style={{ zIndex: 1000 }}>
|
<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="min-w-[192px] rounded-lg border border-components-panel-border bg-components-panel-bg-blur shadow-lg backdrop-blur-sm">
|
||||||
<div className="p-1">
|
<div className="p-1">
|
||||||
<SelectItem type={InputVarType.textInput} value="string" text={t('appDebug.variableConfig.string')} 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('appDebug.variableConfig.paragraph')} 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('appDebug.variableConfig.select')} 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('appDebug.variableConfig.number')} 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('appDebug.variableConfig.checkbox')} onClick={handleChange}></SelectItem>
|
<SelectItem type={InputVarType.checkbox} value="checkbox" text={t('variableConfig.checkbox', { ns: 'appDebug' })} onClick={handleChange}></SelectItem>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-px border-t border-components-panel-border"></div>
|
<div className="h-px border-t border-components-panel-border"></div>
|
||||||
<div className="p-1">
|
<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>
|
||||||
</div>
|
</div>
|
||||||
</PortalToFollowElemContent>
|
</PortalToFollowElemContent>
|
||||||
|
|
|
||||||
|
|
@ -65,11 +65,11 @@ const ConfigVision: FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex grow items-center">
|
<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
|
<Tooltip
|
||||||
popupContent={(
|
popupContent={(
|
||||||
<div className="w-[180px]">
|
<div className="w-[180px]">
|
||||||
{t('appDebug.vision.description')}
|
{t('vision.description', { ns: 'appDebug' })}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
|
||||||
|
|
@ -42,15 +42,15 @@ const ParamConfigContent: FC = () => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<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 className="space-y-6 pt-3">
|
||||||
<div>
|
<div>
|
||||||
<div className="mb-2 flex items-center space-x-1">
|
<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
|
<Tooltip
|
||||||
popupContent={(
|
popupContent={(
|
||||||
<div className="w-[180px]">
|
<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 key={item}>{item}</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -60,7 +60,7 @@ const ParamConfigContent: FC = () => {
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
<OptionCard
|
<OptionCard
|
||||||
className="grow"
|
className="grow"
|
||||||
title={t('appDebug.vision.visionSettings.high')}
|
title={t('vision.visionSettings.high', { ns: 'appDebug' })}
|
||||||
selected={file?.image?.detail === Resolution.high}
|
selected={file?.image?.detail === Resolution.high}
|
||||||
onSelect={() => handleChange({
|
onSelect={() => handleChange({
|
||||||
...file,
|
...file,
|
||||||
|
|
@ -69,7 +69,7 @@ const ParamConfigContent: FC = () => {
|
||||||
/>
|
/>
|
||||||
<OptionCard
|
<OptionCard
|
||||||
className="grow"
|
className="grow"
|
||||||
title={t('appDebug.vision.visionSettings.low')}
|
title={t('vision.visionSettings.low', { ns: 'appDebug' })}
|
||||||
selected={file?.image?.detail === Resolution.low}
|
selected={file?.image?.detail === Resolution.low}
|
||||||
onSelect={() => handleChange({
|
onSelect={() => handleChange({
|
||||||
...file,
|
...file,
|
||||||
|
|
@ -79,11 +79,11 @@ const ParamConfigContent: FC = () => {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</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">
|
<div className="flex items-center gap-1">
|
||||||
<OptionCard
|
<OptionCard
|
||||||
className="grow"
|
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)}
|
selected={!!file?.allowed_file_upload_methods?.includes(TransferMethod.local_file) && !!file?.allowed_file_upload_methods?.includes(TransferMethod.remote_url)}
|
||||||
onSelect={() => handleChange({
|
onSelect={() => handleChange({
|
||||||
...file,
|
...file,
|
||||||
|
|
@ -92,7 +92,7 @@ const ParamConfigContent: FC = () => {
|
||||||
/>
|
/>
|
||||||
<OptionCard
|
<OptionCard
|
||||||
className="grow"
|
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}
|
selected={!!file?.allowed_file_upload_methods?.includes(TransferMethod.local_file) && file?.allowed_file_upload_methods?.length === 1}
|
||||||
onSelect={() => handleChange({
|
onSelect={() => handleChange({
|
||||||
...file,
|
...file,
|
||||||
|
|
@ -101,7 +101,7 @@ const ParamConfigContent: FC = () => {
|
||||||
/>
|
/>
|
||||||
<OptionCard
|
<OptionCard
|
||||||
className="grow"
|
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}
|
selected={!!file?.allowed_file_upload_methods?.includes(TransferMethod.remote_url) && file?.allowed_file_upload_methods?.length === 1}
|
||||||
onSelect={() => handleChange({
|
onSelect={() => handleChange({
|
||||||
...file,
|
...file,
|
||||||
|
|
@ -114,7 +114,7 @@ const ParamConfigContent: FC = () => {
|
||||||
<ParamItem
|
<ParamItem
|
||||||
id="upload_limit"
|
id="upload_limit"
|
||||||
className=""
|
className=""
|
||||||
name={t('appDebug.vision.visionSettings.uploadLimit')}
|
name={t('vision.visionSettings.uploadLimit', { ns: 'appDebug' })}
|
||||||
noTooltip
|
noTooltip
|
||||||
{...{
|
{...{
|
||||||
default: 2,
|
default: 2,
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ const ParamsConfig: FC = () => {
|
||||||
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
<PortalToFollowElemTrigger onClick={() => setOpen(v => !v)}>
|
||||||
<Button variant="ghost" size="small" className={cn('')}>
|
<Button variant="ghost" size="small" className={cn('')}>
|
||||||
<RiSettings2Line className="h-3.5 w-3.5" />
|
<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>
|
</Button>
|
||||||
</PortalToFollowElemTrigger>
|
</PortalToFollowElemTrigger>
|
||||||
<PortalToFollowElemContent style={{ zIndex: 50 }}>
|
<PortalToFollowElemContent style={{ zIndex: 50 }}>
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,10 @@ import AgentSettingButton from './agent-setting-button'
|
||||||
|
|
||||||
vi.mock('react-i18next', () => ({
|
vi.mock('react-i18next', () => ({
|
||||||
useTranslation: () => ({
|
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">
|
<Button onClick={() => setIsShowAgentSetting(true)} className="mr-2 shrink-0">
|
||||||
<RiSettings2Line className="mr-1 h-4 w-4 text-text-tertiary" />
|
<RiSettings2Line className="mr-1 h-4 w-4 text-text-tertiary" />
|
||||||
{t('appDebug.agent.setting.name')}
|
{t('agent.setting.name', { ns: 'appDebug' })}
|
||||||
</Button>
|
</Button>
|
||||||
{isShowAgentSetting && (
|
{isShowAgentSetting && (
|
||||||
<AgentSetting
|
<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 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="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>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<div
|
<div
|
||||||
|
|
@ -85,10 +85,10 @@ const AgentSetting: FC<Props> = ({
|
||||||
icon={
|
icon={
|
||||||
<CuteRobot className="h-4 w-4 text-indigo-600" />
|
<CuteRobot className="h-4 w-4 text-indigo-600" />
|
||||||
}
|
}
|
||||||
name={t('appDebug.agent.agentMode')}
|
name={t('agent.agentMode', { ns: 'appDebug' })}
|
||||||
description={t('appDebug.agent.agentModeDes')}
|
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>
|
||||||
|
|
||||||
<ItemPanel
|
<ItemPanel
|
||||||
|
|
@ -96,8 +96,8 @@ const AgentSetting: FC<Props> = ({
|
||||||
icon={
|
icon={
|
||||||
<Unblur className="h-4 w-4 text-[#FB6514]" />
|
<Unblur className="h-4 w-4 text-[#FB6514]" />
|
||||||
}
|
}
|
||||||
name={t('appDebug.agent.setting.maximumIterations.name')}
|
name={t('agent.setting.maximumIterations.name', { ns: 'appDebug' })}
|
||||||
description={t('appDebug.agent.setting.maximumIterations.description')}
|
description={t('agent.setting.maximumIterations.description', { ns: 'appDebug' })}
|
||||||
>
|
>
|
||||||
<div className="flex items-center">
|
<div className="flex items-center">
|
||||||
<Slider
|
<Slider
|
||||||
|
|
@ -138,7 +138,7 @@ const AgentSetting: FC<Props> = ({
|
||||||
|
|
||||||
{!isFunctionCall && (
|
{!isFunctionCall && (
|
||||||
<div className="rounded-xl bg-background-section-burn py-2 shadow-xs">
|
<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">
|
<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}
|
{isChatModel ? DEFAULT_AGENT_PROMPT.chat : DEFAULT_AGENT_PROMPT.completion}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -156,13 +156,13 @@ const AgentSetting: FC<Props> = ({
|
||||||
onClick={onCancel}
|
onClick={onCancel}
|
||||||
className="mr-2"
|
className="mr-2"
|
||||||
>
|
>
|
||||||
{t('common.operation.cancel')}
|
{t('operation.cancel', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="primary"
|
variant="primary"
|
||||||
onClick={handleSave}
|
onClick={handleSave}
|
||||||
>
|
>
|
||||||
{t('common.operation.save')}
|
{t('operation.save', { ns: 'common' })}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -152,11 +152,11 @@ const AgentTools: FC = () => {
|
||||||
noBodySpacing={tools.length === 0}
|
noBodySpacing={tools.length === 0}
|
||||||
title={(
|
title={(
|
||||||
<div className="flex items-center">
|
<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
|
<Tooltip
|
||||||
popupContent={(
|
popupContent={(
|
||||||
<div className="w-[180px]">
|
<div className="w-[180px]">
|
||||||
{t('appDebug.agent.tools.description')}
|
{t('agent.tools.description', { ns: 'appDebug' })}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
@ -169,7 +169,7 @@ const AgentTools: FC = () => {
|
||||||
/
|
/
|
||||||
{tools.length}
|
{tools.length}
|
||||||
|
|
||||||
{t('appDebug.agent.tools.enabled')}
|
{t('agent.tools.enabled', { ns: 'appDebug' })}
|
||||||
</div>
|
</div>
|
||||||
{tools.length < MAX_TOOLS_NUM && (
|
{tools.length < MAX_TOOLS_NUM && (
|
||||||
<>
|
<>
|
||||||
|
|
@ -220,8 +220,8 @@ const AgentTools: FC = () => {
|
||||||
popupContent={(
|
popupContent={(
|
||||||
<div className="w-[180px]">
|
<div className="w-[180px]">
|
||||||
<div className="mb-1.5 text-text-secondary">{item.tool_name}</div>
|
<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="mb-1.5 text-text-tertiary">{t('toolNameUsageTip', { ns: 'tools' })}</div>
|
||||||
<div className="cursor-pointer text-text-accent" onClick={() => copy(item.tool_name)}>{t('tools.copyToolName')}</div>
|
<div className="cursor-pointer text-text-accent" onClick={() => copy(item.tool_name)}>{t('copyToolName', { ns: 'tools' })}</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
@ -238,7 +238,7 @@ const AgentTools: FC = () => {
|
||||||
{item.isDeleted && (
|
{item.isDeleted && (
|
||||||
<div className="mr-2 flex items-center">
|
<div className="mr-2 flex items-center">
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={t('tools.toolRemoved')}
|
popupContent={t('toolRemoved', { ns: 'tools' })}
|
||||||
>
|
>
|
||||||
<div className="mr-1 cursor-pointer rounded-md p-1 hover:bg-black/5">
|
<div className="mr-1 cursor-pointer rounded-md p-1 hover:bg-black/5">
|
||||||
<AlertTriangle className="h-4 w-4 text-[#F79009]" />
|
<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">
|
<div className="mr-2 hidden items-center gap-1 group-hover:flex">
|
||||||
{!item.notAuthor && (
|
{!item.notAuthor && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
popupContent={t('tools.setBuiltInTools.infoAndSetting')}
|
popupContent={t('setBuiltInTools.infoAndSetting', { ns: 'tools' })}
|
||||||
needsDelay={false}
|
needsDelay={false}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
|
|
@ -319,7 +319,7 @@ const AgentTools: FC = () => {
|
||||||
setIsShowSettingTool(true)
|
setIsShowSettingTool(true)
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{t('tools.notAuthorized')}
|
{t('notAuthorized', { ns: 'tools' })}
|
||||||
<Indicator className="ml-2" color="orange" />
|
<Indicator className="ml-2" color="orange" />
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue