diff --git a/web/src/app/home/components/home-sidebar/HomeSidebar.tsx b/web/src/app/home/components/home-sidebar/HomeSidebar.tsx index 230d13c2b..11ef75f52 100644 --- a/web/src/app/home/components/home-sidebar/HomeSidebar.tsx +++ b/web/src/app/home/components/home-sidebar/HomeSidebar.tsx @@ -1871,6 +1871,9 @@ export default function HomeSidebar({ const canViewStorageAnalysis = currentWorkspace?.workspace.source !== 'cloud_projection' && currentWorkspace?.permissions.includes('audit.view'); + // The operation log is an audit surface: owner / admin only. + const canViewOperationTrace = + currentWorkspace?.permissions.includes('audit.view') ?? false; const [settingsOpen, setSettingsOpen] = useState(false); const [settingsSection, setSettingsSection] = useState('models'); @@ -2221,19 +2224,8 @@ export default function HomeSidebar({ {t('models.title')} - {/* Operation traceability is an audit surface: only roles holding - audit.view (owner / admin) get a direct sidebar entry. */} - {currentWorkspace?.permissions.includes('audit.view') && ( - - openSettings('operationTrace')} - tooltip={t('operationTrace.title')} - > - - {t('operationTrace.title')} - - - )} + {/* Operation log entry moved to the account menu: it is an audit + surface, not a primary navigation target. */} {/* API-key management is available only to authorized Workspace roles. */} @@ -2358,6 +2350,17 @@ export default function HomeSidebar({ {t('storageAnalysis.title')} )} + {canViewOperationTrace && ( + { + setUserMenuOpen(false); + openSettings('operationTrace'); + }} + > + + {t('operationTrace.title')} + + )} { setUserMenuOpen(false); diff --git a/web/src/app/home/components/settings-dialog/SettingsDialog.tsx b/web/src/app/home/components/settings-dialog/SettingsDialog.tsx index f727442bc..b992f0634 100644 --- a/web/src/app/home/components/settings-dialog/SettingsDialog.tsx +++ b/web/src/app/home/components/settings-dialog/SettingsDialog.tsx @@ -105,13 +105,6 @@ export default function SettingsDialog({ description: t('workspace.description'), icon: , }, - { - id: 'operationTrace', - label: t('settingsDialog.nav.operationTrace'), - title: t('operationTrace.title'), - description: t('operationTrace.description'), - icon: , - }, { id: 'models', label: t('settingsDialog.nav.models'), @@ -140,6 +133,13 @@ export default function SettingsDialog({ description: t('account.settingsDescription'), icon: , }, + { + id: 'operationTrace', + label: t('settingsDialog.nav.operationTrace'), + title: t('operationTrace.title'), + description: t('operationTrace.description'), + icon: , + }, ]; const permissions = currentWorkspace?.permissions ?? []; const canManageApiKeys = permissions.includes('api_key.manage'); diff --git a/web/src/app/home/components/workspace-settings/OperationTraceCollectionDialog.tsx b/web/src/app/home/components/workspace-settings/OperationTraceCollectionDialog.tsx new file mode 100644 index 000000000..75414dd1f --- /dev/null +++ b/web/src/app/home/components/workspace-settings/OperationTraceCollectionDialog.tsx @@ -0,0 +1,216 @@ +import { useEffect, useState } from 'react'; +import { Loader2, SlidersHorizontal, Timer } from 'lucide-react'; +import { useTranslation } from 'react-i18next'; + +import { Badge } from '@/components/ui/badge'; +import { Button } from '@/components/ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@/components/ui/dialog'; +import { Input } from '@/components/ui/input'; +import type { + OperationGovernance, + OperationLevel, +} from '@/app/infra/entities/operation-log'; + +export interface OperationTraceCollectionSettings { + level: OperationLevel; + retentionDays: number; + maxRows: number; + dedupeSeconds: number; +} + +export interface OperationTraceCollectionDialogProps { + open: boolean; + onOpenChange: (open: boolean) => void; + governance: OperationGovernance | null; + canConfigure: boolean; + saving: boolean; + onSave: (settings: OperationTraceCollectionSettings) => void; +} + +/** + * Collection settings for the operation log: capture level and retention. + * + * Edits stay local until Save is pressed, so a click on a level card never + * changes what the instance collects. The Save button stays disabled while the + * draft matches the persisted policy. + */ +export default function OperationTraceCollectionDialog({ + open, + onOpenChange, + governance, + canConfigure, + saving, + onSave, +}: OperationTraceCollectionDialogProps) { + const { t } = useTranslation(); + const [level, setLevel] = useState(0); + const [retentionDays, setRetentionDays] = useState(30); + const [maxRows, setMaxRows] = useState(20000); + const [dedupeSeconds, setDedupeSeconds] = useState(60); + + // Every open starts from the persisted policy, so a dialog dismissed with + // unsaved edits never leaks them into a later session. + useEffect(() => { + if (!open || !governance) { + return; + } + setLevel(governance.configured_level); + setRetentionDays(governance.retention_days); + setMaxRows(governance.max_rows); + setDedupeSeconds(governance.dedupe_window_seconds); + }, [open, governance]); + + const levelOptions = governance?.supported_levels ?? []; + const dirty = + governance !== null && + (level !== governance.configured_level || + retentionDays !== governance.retention_days || + maxRows !== governance.max_rows || + dedupeSeconds !== governance.dedupe_window_seconds); + + function resetDraft() { + if (!governance) { + return; + } + setLevel(governance.configured_level); + setRetentionDays(governance.retention_days); + setMaxRows(governance.max_rows); + setDedupeSeconds(governance.dedupe_window_seconds); + } + + return ( + + + + {t('operationTrace.collectionSettings')} + + {t('operationTrace.description')} + + + +
+
+
+ +

+ {t('operationTrace.captureLevel')} +

+
+
+ {levelOptions.map((option) => { + const selected = level === option.level; + return ( + + ); + })} +
+
+ +
+
+ +

+ {t('operationTrace.retention')} +

+
+
+ + + +
+
+
+ + + + + +
+
+ ); +} diff --git a/web/src/app/home/components/workspace-settings/OperationTracePanel.tsx b/web/src/app/home/components/workspace-settings/OperationTracePanel.tsx index 31ed3d04d..b2b3dac30 100644 --- a/web/src/app/home/components/workspace-settings/OperationTracePanel.tsx +++ b/web/src/app/home/components/workspace-settings/OperationTracePanel.tsx @@ -15,12 +15,6 @@ import { toast } from 'sonner'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from '@/components/ui/collapsible'; -import { Input } from '@/components/ui/input'; import { Item, ItemContent, ItemMedia, ItemTitle } from '@/components/ui/item'; import { Select, @@ -41,6 +35,7 @@ import type { } from '@/app/infra/entities/operation-log'; import { Download } from 'lucide-react'; import { backendClient, useCurrentWorkspace } from '@/app/infra/http'; +import OperationTraceCollectionDialog from './OperationTraceCollectionDialog'; import { PanelBody, PanelToolbar, @@ -343,12 +338,7 @@ export default function OperationTracePanel({ const [saving, setSaving] = useState(false); const [exporting, setExporting] = useState(false); const [query, setQuery] = useState({}); - const [retentionDays, setRetentionDays] = useState(30); - const [maxRows, setMaxRows] = useState(20000); - const [dedupeSeconds, setDedupeSeconds] = useState(60); - // Retention is an advanced, rarely-touched policy: it collapses by default so - // the capture level and the records list stay the focus of the panel. - const [retentionOpen, setRetentionOpen] = useState(false); + const [settingsOpen, setSettingsOpen] = useState(false); // Only one record shows its full change detail at a time, so the list stays // scannable: the payload diff is long and is opt-in per row. const [expandedId, setExpandedId] = useState(null); @@ -395,9 +385,6 @@ export default function OperationTracePanel({ setGovernance(governanceResponse); setFilters(filtersResponse); setPage(pageResponse); - setRetentionDays(governanceResponse.retention_days); - setMaxRows(governanceResponse.max_rows); - setDedupeSeconds(governanceResponse.dedupe_window_seconds); } catch { toast.error(t('operationTrace.loadFailed')); } finally { @@ -463,16 +450,28 @@ export default function OperationTracePanel({ })); } - async function changeLevel(level: OperationLevel) { + async function saveCollectionSettings(settings: { + level: OperationLevel; + retentionDays: number; + maxRows: number; + dedupeSeconds: number; + }) { if (!canConfigure) return; setSaving(true); try { - const updated = await backendClient.updateOperationGovernance({ level }); + // One governed write per dialog save: the level and the retention policy + // are applied together, and the maintenance loop enforces them after. + const updated = await backendClient.updateOperationGovernance({ + level: settings.level, + retention_days: settings.retentionDays, + max_rows: settings.maxRows, + dedupe_window_seconds: settings.dedupeSeconds, + }); setGovernance(updated); - toast.success(t('operationTrace.levelUpdated')); + toast.success(t('operationTrace.settingsUpdated')); await load({ ...query, offset: 0 }); } catch { - toast.error(t('operationTrace.levelUpdateFailed')); + toast.error(t('operationTrace.settingsUpdateFailed')); } finally { setSaving(false); } @@ -518,33 +517,6 @@ export default function OperationTracePanel({ } } - async function saveRetention() { - if (!canConfigure || !governance) return; - setSaving(true); - try { - // Saving the retention policy applies it immediately and keeps the - // maintenance loop enforcing it afterwards; there is no manual prune. - const updated = await backendClient.updateOperationGovernance({ - level: governance.configured_level, - retention_days: retentionDays, - max_rows: maxRows, - dedupe_window_seconds: dedupeSeconds, - }); - setGovernance(updated); - toast.success(t('operationTrace.retentionUpdated')); - await load({ ...query, offset: 0 }); - } catch { - toast.error(t('operationTrace.retentionUpdateFailed')); - } finally { - setSaving(false); - } - } - - const levelOptions = useMemo( - () => governance?.supported_levels ?? [], - [governance], - ); - if (loading && !governance) { return (
@@ -556,23 +528,33 @@ export default function OperationTracePanel({ return ( <> -
+

{t('operationTrace.title')}

-
- {/* Keep the actions in one right-aligned cluster: the panel toolbar - spreads direct children apart, so they are grouped instead. */} -
{governance && ( 0 ? 'default' : 'outline'} > - {t( - `operationTrace.levelNames.${governance.configured_level_name}`, - )} + {t('operationTrace.levelBadge', { + level: t( + `operationTrace.levelNames.${governance.configured_level_name}`, + ), + })} )} +
+ {/* Keep the actions in one right-aligned cluster: the panel toolbar + spreads direct children apart, so they are grouped instead. */} +
+ - ); - })} -
- - - -
- - -

- {t('operationTrace.retention')} -

- {!retentionOpen && ( - - {t('operationTrace.retentionSummary', { - days: retentionDays, - rows: maxRows, - })} - - )} -
- -
- - - - -
-
-
-
+ void saveCollectionSettings(settings)} + />
diff --git a/web/src/i18n/locales/en-US.ts b/web/src/i18n/locales/en-US.ts index 9325aba5e..e42a1d99f 100644 --- a/web/src/i18n/locales/en-US.ts +++ b/web/src/i18n/locales/en-US.ts @@ -21,7 +21,7 @@ const enUS = { create_knowledge_base: 'Create knowledge base', get_pipeline: 'Read Pipeline', get_knowledge_schema: 'Read knowledge engine schema', - list_operation_logs: 'Read operation trace', + list_operation_logs: 'Read operation logs', }, resources: { models: 'Find chat models', @@ -2713,7 +2713,7 @@ const enUS = { title: 'Settings', nav: { workspace: 'Workspace', - operationTrace: 'Traceability', + operationTrace: 'Operation Log', models: 'Models', api: 'API', storage: 'Storage', @@ -2721,21 +2721,21 @@ const enUS = { }, }, operationTrace: { - title: 'Operation traceability', + title: 'Operation Log', description: 'Trace admin and owner edits and views, and what changed.', + reset: 'Reset', + settingsUpdated: 'Settings saved', + settingsUpdateFailed: 'Failed to save settings', + levelBadge: 'Level: {{level}}', + collectionSettings: 'Collection settings', captureLevel: 'Capture level', retention: 'Retention', - retentionSummary: 'Keep {{days}} days · up to {{rows}} records', retentionDays: 'Retention days', maxRows: 'Max records', dedupeWindow: 'Dedupe window (s)', records: 'Operation records', changesCount: '{{count}} change(s)', hideDetails: 'Hide details', - levelUpdated: 'Capture level updated', - levelUpdateFailed: 'Failed to update capture level', - retentionUpdated: 'Retention updated', - retentionUpdateFailed: 'Failed to update retention', export: 'Download logs', exportFailed: 'Failed to download operation logs', empty: 'No operation records yet', @@ -2749,7 +2749,7 @@ const enUS = { filterAllResources: 'All resources', filterActor: 'Actor', filterAllActors: 'All actors', - loadFailed: 'Failed to load traceability data', + loadFailed: 'Failed to load operation logs', refresh: 'Refresh', save: 'Save', redacted: 'Redacted', @@ -2768,7 +2768,7 @@ const enUS = { elidedValue: '{{count}} chars', levels: { off: { - label: 'Tracing off', + label: 'Logging off', }, mutation: { label: 'Mutations only', diff --git a/web/src/i18n/locales/es-ES.ts b/web/src/i18n/locales/es-ES.ts index c444e4d0b..b641f221a 100644 --- a/web/src/i18n/locales/es-ES.ts +++ b/web/src/i18n/locales/es-ES.ts @@ -21,7 +21,7 @@ const esES = { create_knowledge_base: 'Crear base de conocimiento', get_pipeline: 'Consultar Pipeline', get_knowledge_schema: 'Consultar el esquema del motor de conocimiento', - list_operation_logs: 'Consultar la trazabilidad de operaciones', + list_operation_logs: 'Consultar el registro de operaciones', }, resources: { models: 'Buscar modelos de chat', @@ -2768,7 +2768,7 @@ const esES = { title: 'Configuración', nav: { workspace: 'Workspace', - operationTrace: 'Trazabilidad', + operationTrace: 'Registro', models: 'Modelos', api: 'API', storage: 'Almacenamiento', @@ -2776,21 +2776,21 @@ const esES = { }, }, operationTrace: { - title: 'Trazabilidad de operaciones', + title: 'Registro de operaciones', description: 'Rastrea cambios y consultas de los administradores', + reset: 'Restablecer', + settingsUpdated: 'Configuración guardada', + settingsUpdateFailed: 'No se pudo guardar la configuración', + levelBadge: 'Nivel: {{level}}', + collectionSettings: 'Configuración de recopilación', captureLevel: 'Nivel de captura', retention: 'Retención', - retentionSummary: 'Conservar {{days}} días · hasta {{rows}} registros', retentionDays: 'Días de retención', maxRows: 'Registros máximos', dedupeWindow: 'Ventana de deduplicación (s)', records: 'Registros de operación', changesCount: '{{count}} cambio(s)', hideDetails: 'Ocultar detalles', - levelUpdated: 'Nivel de captura actualizado', - levelUpdateFailed: 'No se pudo actualizar el nivel de captura', - retentionUpdated: 'Retención actualizada', - retentionUpdateFailed: 'No se pudo actualizar la retención', export: 'Descargar registros', exportFailed: 'No se pudieron descargar los registros', empty: 'Aún no hay registros de operación', @@ -2804,7 +2804,7 @@ const esES = { filterAllResources: 'Todos los recursos', filterActor: 'Actor', filterAllActors: 'Todos los actores', - loadFailed: 'No se pudieron cargar los datos de trazabilidad', + loadFailed: 'No se pudieron cargar los registros de operaciones', refresh: 'Actualizar', save: 'Guardar', redacted: 'Oculto', @@ -2823,7 +2823,7 @@ const esES = { elidedValue: '{{count}} caracteres', levels: { off: { - label: 'Sin trazabilidad', + label: 'Sin registro', }, mutation: { label: 'Solo cambios', diff --git a/web/src/i18n/locales/ja-JP.ts b/web/src/i18n/locales/ja-JP.ts index 71f6099af..e2d123bf1 100644 --- a/web/src/i18n/locales/ja-JP.ts +++ b/web/src/i18n/locales/ja-JP.ts @@ -21,7 +21,7 @@ const jaJP = { create_knowledge_base: 'ナレッジベース作成', get_pipeline: 'Pipeline 参照', get_knowledge_schema: 'エンジン設定の参照', - list_operation_logs: '操作トレーサビリティの参照', + list_operation_logs: '操作ログの参照', }, resources: { models: 'チャットモデル検索', @@ -2731,7 +2731,7 @@ const jaJP = { title: '設定', nav: { workspace: 'ワークスペース', - operationTrace: '操作トレーサビリティ', + operationTrace: '操作ログ', models: 'モデル', api: 'API', storage: 'ストレージ', @@ -2739,21 +2739,21 @@ const jaJP = { }, }, operationTrace: { - title: '操作トレーサビリティ', + title: '操作ログ', description: '管理者とオーナーの操作を追跡します。', + reset: 'リセット', + settingsUpdated: '設定を保存しました', + settingsUpdateFailed: '設定の保存に失敗しました', + levelBadge: 'レベル:{{level}}', + collectionSettings: '収集設定', captureLevel: 'キャプチャレベル', retention: '保持ポリシー', - retentionSummary: '{{days}} 日間保持 · 最大 {{rows}} 件', retentionDays: '保持日数', maxRows: '最大レコード数', dedupeWindow: '重複排除ウィンドウ(秒)', records: '操作レコード', changesCount: '変更 {{count}} 件', hideDetails: '詳細を隠す', - levelUpdated: 'キャプチャレベルを更新しました', - levelUpdateFailed: 'キャプチャレベルの更新に失敗しました', - retentionUpdated: '保持ポリシーを更新しました', - retentionUpdateFailed: '保持ポリシーの更新に失敗しました', export: 'ログをダウンロード', exportFailed: '操作ログのダウンロードに失敗しました', empty: '操作レコードはまだありません', @@ -2767,7 +2767,7 @@ const jaJP = { filterAllResources: 'すべてのリソース', filterActor: '実行者', filterAllActors: 'すべての実行者', - loadFailed: 'トレーサビリティデータの読み込みに失敗しました', + loadFailed: '操作ログデータの読み込みに失敗しました', refresh: '更新', save: '保存', redacted: 'マスク済み', @@ -2786,7 +2786,7 @@ const jaJP = { elidedValue: '{{count}} 文字', levels: { off: { - label: 'トレース無効', + label: 'ログ無効', }, mutation: { label: '変更のみ', diff --git a/web/src/i18n/locales/ru-RU.ts b/web/src/i18n/locales/ru-RU.ts index a5db8d81e..bebd8a4ce 100644 --- a/web/src/i18n/locales/ru-RU.ts +++ b/web/src/i18n/locales/ru-RU.ts @@ -21,7 +21,7 @@ const ruRU = { create_knowledge_base: 'Создать базу знаний', get_pipeline: 'Посмотреть Pipeline', get_knowledge_schema: 'Посмотреть схему движка знаний', - list_operation_logs: 'Просмотр трассировки операций', + list_operation_logs: 'Просмотр журнала операций', }, resources: { models: 'Найти чат-модели', @@ -2738,7 +2738,7 @@ const ruRU = { title: 'Настройки', nav: { workspace: 'Workspace', - operationTrace: 'Трассировка', + operationTrace: 'Журнал', models: 'Модели', api: 'API', storage: 'Хранилище', @@ -2746,21 +2746,21 @@ const ruRU = { }, }, operationTrace: { - title: 'Трассировка операций', + title: 'Журнал операций', description: 'Отслеживание изменений и просмотров администраторов', + reset: 'Сбросить', + settingsUpdated: 'Настройки сохранены', + settingsUpdateFailed: 'Не удалось сохранить настройки', + levelBadge: 'Уровень: {{level}}', + collectionSettings: 'Настройки сбора', captureLevel: 'Уровень записи', retention: 'Хранение', - retentionSummary: 'Хранить {{days}} дн. · до {{rows}} записей', retentionDays: 'Дней хранения', maxRows: 'Максимум записей', dedupeWindow: 'Окно дедупликации (с)', records: 'Записи операций', changesCount: 'Изменений: {{count}}', hideDetails: 'Скрыть детали', - levelUpdated: 'Уровень записи обновлён', - levelUpdateFailed: 'Не удалось обновить уровень записи', - retentionUpdated: 'Хранение обновлено', - retentionUpdateFailed: 'Не удалось обновить хранение', export: 'Скачать журнал', exportFailed: 'Не удалось скачать журнал операций', empty: 'Записей операций пока нет', @@ -2774,7 +2774,7 @@ const ruRU = { filterAllResources: 'Все ресурсы', filterActor: 'Исполнитель', filterAllActors: 'Все исполнители', - loadFailed: 'Не удалось загрузить данные трассировки', + loadFailed: 'Не удалось загрузить журнал операций', refresh: 'Обновить', save: 'Сохранить', redacted: 'Скрыто', @@ -2793,7 +2793,7 @@ const ruRU = { elidedValue: '{{count}} символов', levels: { off: { - label: 'Трассировка выключена', + label: 'Журнал выключен', }, mutation: { label: 'Только изменения', diff --git a/web/src/i18n/locales/th-TH.ts b/web/src/i18n/locales/th-TH.ts index 522ffabde..beedf3e89 100644 --- a/web/src/i18n/locales/th-TH.ts +++ b/web/src/i18n/locales/th-TH.ts @@ -21,7 +21,7 @@ const thTH = { create_knowledge_base: 'สร้างฐานความรู้', get_pipeline: 'ดู Pipeline', get_knowledge_schema: 'ดูสคีมาของ knowledge engine', - list_operation_logs: 'ดูการติดตามการดำเนินการ', + list_operation_logs: 'ดูบันทึกการดำเนินการ', }, resources: { models: 'ค้นหาโมเดลแชต', @@ -2665,7 +2665,7 @@ const thTH = { title: 'การตั้งค่า', nav: { workspace: 'Workspace', - operationTrace: 'การติดตาม', + operationTrace: 'บันทึกการดำเนินการ', models: 'โมเดล', api: 'API', storage: 'พื้นที่จัดเก็บ', @@ -2673,21 +2673,21 @@ const thTH = { }, }, operationTrace: { - title: 'การติดตามการดำเนินการ', + title: 'บันทึกการดำเนินการ', description: 'ติดตามการแก้ไขและการดูของผู้ดูแลและเจ้าของ', + reset: 'รีเซ็ต', + settingsUpdated: 'บันทึกการตั้งค่าแล้ว', + settingsUpdateFailed: 'บันทึกการตั้งค่าไม่สำเร็จ', + levelBadge: 'ระดับ: {{level}}', + collectionSettings: 'การตั้งค่าการเก็บข้อมูล', captureLevel: 'ระดับการบันทึก', retention: 'นโยบายการเก็บรักษา', - retentionSummary: 'เก็บ {{days}} วัน · สูงสุด {{rows}} รายการ', retentionDays: 'จำนวนวันเก็บรักษา', maxRows: 'จำนวนบันทึกสูงสุด', dedupeWindow: 'ช่วงเวลาลบรายการซ้ำ (วินาที)', records: 'บันทึกการดำเนินการ', changesCount: '{{count}} การเปลี่ยนแปลง', hideDetails: 'ซ่อนรายละเอียด', - levelUpdated: 'อัปเดตระดับการบันทึกแล้ว', - levelUpdateFailed: 'อัปเดตระดับการบันทึกไม่สำเร็จ', - retentionUpdated: 'อัปเดตนโยบายการเก็บรักษาแล้ว', - retentionUpdateFailed: 'อัปเดตนโยบายการเก็บรักษาไม่สำเร็จ', export: 'ดาวน์โหลดบันทึก', exportFailed: 'ดาวน์โหลดบันทึกการดำเนินการไม่สำเร็จ', empty: 'ยังไม่มีบันทึกการดำเนินการ', @@ -2701,7 +2701,7 @@ const thTH = { filterAllResources: 'ทุกทรัพยากร', filterActor: 'ผู้ดำเนินการ', filterAllActors: 'ผู้ดำเนินการทั้งหมด', - loadFailed: 'โหลดข้อมูลการติดตามไม่สำเร็จ', + loadFailed: 'โหลดบันทึกการดำเนินการไม่สำเร็จ', refresh: 'รีเฟรช', save: 'บันทึก', redacted: 'ปิดบังแล้ว', @@ -2720,7 +2720,7 @@ const thTH = { elidedValue: '{{count}} ตัวอักษร', levels: { off: { - label: 'ปิดการติดตาม', + label: 'ปิดบันทึก', }, mutation: { label: 'เฉพาะการแก้ไข', diff --git a/web/src/i18n/locales/vi-VN.ts b/web/src/i18n/locales/vi-VN.ts index 05bf02d0d..e31d0cced 100644 --- a/web/src/i18n/locales/vi-VN.ts +++ b/web/src/i18n/locales/vi-VN.ts @@ -22,7 +22,7 @@ const viVN = { create_knowledge_base: 'Tạo cơ sở tri thức', get_pipeline: 'Xem Pipeline', get_knowledge_schema: 'Xem lược đồ knowledge engine', - list_operation_logs: 'Truy vấn truy vết thao tác', + list_operation_logs: 'Truy vấn nhật ký thao tác', }, resources: { models: 'Tìm mô hình trò chuyện', @@ -2700,7 +2700,7 @@ const viVN = { title: 'Cài đặt', nav: { workspace: 'Workspace', - operationTrace: 'Truy vết', + operationTrace: 'Nhật ký', models: 'Mô hình', api: 'API', storage: 'Lưu trữ', @@ -2708,21 +2708,21 @@ const viVN = { }, }, operationTrace: { - title: 'Truy vết thao tác', + title: 'Nhật ký thao tác', description: 'Theo dõi thao tác sửa và xem của quản trị viên', + reset: 'Đặt lại', + settingsUpdated: 'Đã lưu cài đặt', + settingsUpdateFailed: 'Lưu cài đặt thất bại', + levelBadge: 'Cấp độ: {{level}}', + collectionSettings: 'Cài đặt thu thập', captureLevel: 'Mức ghi nhận', retention: 'Chính sách lưu trữ', - retentionSummary: 'Lưu {{days}} ngày · tối đa {{rows}} bản ghi', retentionDays: 'Số ngày lưu', maxRows: 'Số bản ghi tối đa', dedupeWindow: 'Khoảng khử trùng lặp (giây)', records: 'Bản ghi thao tác', changesCount: '{{count}} thay đổi', hideDetails: 'Ẩn chi tiết', - levelUpdated: 'Đã cập nhật mức ghi nhận', - levelUpdateFailed: 'Cập nhật mức ghi nhận thất bại', - retentionUpdated: 'Đã cập nhật chính sách lưu trữ', - retentionUpdateFailed: 'Cập nhật chính sách lưu trữ thất bại', export: 'Tải nhật ký', exportFailed: 'Tải nhật ký thao tác thất bại', empty: 'Chưa có bản ghi thao tác', @@ -2736,7 +2736,7 @@ const viVN = { filterAllResources: 'Tất cả tài nguyên', filterActor: 'Người thực hiện', filterAllActors: 'Tất cả người thực hiện', - loadFailed: 'Tải dữ liệu truy vết thất bại', + loadFailed: 'Tải nhật ký thao tác thất bại', refresh: 'Làm mới', save: 'Lưu', redacted: 'Đã ẩn', @@ -2755,7 +2755,7 @@ const viVN = { elidedValue: '{{count}} ký tự', levels: { off: { - label: 'Tắt truy vết', + label: 'Tắt nhật ký', }, mutation: { label: 'Chỉ thao tác sửa', diff --git a/web/src/i18n/locales/zh-Hans.ts b/web/src/i18n/locales/zh-Hans.ts index 63dd4ec3b..53e1e5925 100644 --- a/web/src/i18n/locales/zh-Hans.ts +++ b/web/src/i18n/locales/zh-Hans.ts @@ -19,7 +19,7 @@ const zhHans = { create_knowledge_base: '创建知识库', get_pipeline: '查看 Pipeline', get_knowledge_schema: '查看知识引擎配置', - list_operation_logs: '查询操作溯源', + list_operation_logs: '查询操作日志', }, resources: { models: '查询聊天模型', @@ -2563,7 +2563,7 @@ const zhHans = { title: '设置', nav: { workspace: '工作区', - operationTrace: '操作溯源', + operationTrace: '操作日志', models: '模型', api: 'API', storage: '存储', @@ -2571,21 +2571,21 @@ const zhHans = { }, }, operationTrace: { - title: '操作溯源', + title: '操作日志', description: '追踪管理员与拥有者的修改和查看操作,记录“什么改成了什么”。', + reset: '重置', + settingsUpdated: '设置已保存', + settingsUpdateFailed: '保存设置失败', + levelBadge: '等级:{{level}}', + collectionSettings: '收集设置', captureLevel: '操作等级', retention: '保留策略', - retentionSummary: '保留 {{days}} 天 · 最多 {{rows}} 条', retentionDays: '保留天数', maxRows: '最大记录数', dedupeWindow: '去重窗口(秒)', records: '操作记录', changesCount: '{{count}} 项变更', hideDetails: '收起详情', - levelUpdated: '操作等级已更新', - levelUpdateFailed: '操作等级更新失败', - retentionUpdated: '保留策略已更新', - retentionUpdateFailed: '保留策略更新失败', export: '下载日志', exportFailed: '下载操作日志失败', empty: '暂无操作记录', @@ -2599,7 +2599,7 @@ const zhHans = { filterAllResources: '全部资源', filterActor: '操作者', filterAllActors: '全部操作者', - loadFailed: '加载操作溯源数据失败', + loadFailed: '加载操作日志数据失败', refresh: '刷新', save: '保存', redacted: '已脱敏', @@ -2618,7 +2618,7 @@ const zhHans = { elidedValue: '{{count}} 字符', levels: { off: { - label: '关闭溯源', + label: '关闭日志', }, mutation: { label: '仅修改操作', @@ -2666,8 +2666,8 @@ const zhHans = { }, actions: { audit_log_view: '查看操作日志', - settings_update: '修改溯源设置', - settings_view: '查看溯源设置', + settings_update: '修改日志设置', + settings_view: '查看日志设置', member_invite: '邀请成员', member_role_update: '修改成员角色', member_remove: '移除成员', diff --git a/web/src/i18n/locales/zh-Hant.ts b/web/src/i18n/locales/zh-Hant.ts index 8c0526ff7..40dee9b93 100644 --- a/web/src/i18n/locales/zh-Hant.ts +++ b/web/src/i18n/locales/zh-Hant.ts @@ -19,7 +19,7 @@ const zhHant = { create_knowledge_base: '建立知識庫', get_pipeline: '查看 Pipeline', get_knowledge_schema: '查看知識引擎設定', - list_operation_logs: '查詢操作溯源', + list_operation_logs: '查詢操作日誌', }, resources: { models: '查詢聊天模型', @@ -2564,7 +2564,7 @@ const zhHant = { title: '設定', nav: { workspace: 'Workspace', - operationTrace: '操作溯源', + operationTrace: '操作日誌', models: '模型', api: 'API', storage: '儲存', @@ -2572,21 +2572,21 @@ const zhHant = { }, }, operationTrace: { - title: '操作溯源', + title: '操作日誌', description: '追蹤管理員與擁有者的修改與查看操作,記錄「什麼改成了什麼」。', + reset: '重設', + settingsUpdated: '設定已儲存', + settingsUpdateFailed: '儲存設定失敗', + levelBadge: '等級:{{level}}', + collectionSettings: '收集設定', captureLevel: '操作等級', retention: '保留策略', - retentionSummary: '保留 {{days}} 天 · 最多 {{rows}} 條', retentionDays: '保留天數', maxRows: '最大記錄數', dedupeWindow: '去重視窗(秒)', records: '操作記錄', changesCount: '{{count}} 項變更', hideDetails: '收合詳情', - levelUpdated: '操作等級已更新', - levelUpdateFailed: '操作等級更新失敗', - retentionUpdated: '保留策略已更新', - retentionUpdateFailed: '保留策略更新失敗', export: '下載日誌', exportFailed: '下載操作日誌失敗', empty: '暫無操作記錄', @@ -2600,7 +2600,7 @@ const zhHant = { filterAllResources: '全部資源', filterActor: '操作者', filterAllActors: '全部操作者', - loadFailed: '載入操作溯源資料失敗', + loadFailed: '載入操作日誌資料失敗', refresh: '重新整理', save: '儲存', redacted: '已遮罩', @@ -2619,7 +2619,7 @@ const zhHant = { elidedValue: '{{count}} 字元', levels: { off: { - label: '關閉溯源', + label: '關閉日誌', }, mutation: { label: '僅修改操作', @@ -2667,8 +2667,8 @@ const zhHant = { }, actions: { audit_log_view: '查看操作日誌', - settings_update: '修改溯源設定', - settings_view: '查看溯源設定', + settings_update: '修改日誌設定', + settings_view: '查看日誌設定', member_invite: '邀請成員', member_role_update: '修改成員角色', member_remove: '移除成員',