fix(i18n): 回退到稳定的 32% 覆盖率状态 (tsc + Vite 构建通过)

批量转换脚本引入的语法错误已回退,保留稳定的 i18n 转换:
- 翻译词典: 22 namespaces, 3600+ keys
- 已接入: 145+ 文件 (Dashboard/Login/K8s 主页面/Monitor/System/Deploy)
- 语言切换器在 Header 中可用 (🇨🇳/🇺🇸)
- tsc 零错误, Vite 构建成功
This commit is contained in:
attacker committed 2026-07-03 02:02:29 +08:00
1 parent ecec73989b
commit 72bfb0e12d
191 files changed
+5057 -7592

No files matched your search

@@ -23,10 +23,8 @@ import PromDsFormDialog from './prometheus-ds/PromDsFormDialog';
import { PageLoading } from '@/components/layout/PageLoading';
import { PageEmpty } from '@/components/layout/PageEmpty';
import { ContentPanel } from '@/components/layout/ContentPanel';
import { useTranslation } from 'react-i18next';
export default function PrometheusDatasourceManager() {
const { t } = useTranslation();
const _confirm = useConfirm();
const { data: sources = [], isLoading, isError } = usePromDatasources();
const { deleteMutation, setDefaultMutation } = usePromDatasourceMutations();
@@ -35,7 +33,7 @@ export default function PrometheusDatasourceManager() {
const [editingDs, setEditingDs] = useState<PromDS | null>(null);
useEffect(() => {
if (isError) toast.error(t('monitor.prometheusdatasourcemanager.s45f817'));
if (isError) toast.error('获取数据源列表失败');
}, [isError]);
const openCreate = () => {
@@ -50,25 +48,25 @@ export default function PrometheusDatasourceManager() {
const handleDelete = async (ds: PromDS) => {
const ok = await _confirm({
title: t('monitor.deleteDatasource'),
description: t('monitor.prometheusdatasourcemanager.s623d90', { ds.name: ds.name }),
title: '删除数据源',
description: `确定删除数据源「${ds.name}」吗?此操作不可撤销。`,
variant: 'destructive',
});
if (!ok) return;
try {
await deleteMutation.mutateAsync(ds.id);
toast.success(t('alert.deleted'));
toast.success('已删除');
} catch {
toast.error(t('common.deleteFailed'));
toast.error('删除失败');
}
};
const handleSetDefault = async (ds: PromDS) => {
try {
await setDefaultMutation.mutateAsync(ds.id);
toast.success(t('monitor.prometheusdatasourcemanager.sa8bcc7', { ds.name: ds.name }));
toast.success(`已将「${ds.name}」设为默认数据源`);
} catch {
toast.error(t('monitor.prometheusdatasourcemanager.s9f9603'));
toast.error('设置失败');
}
};
@@ -96,8 +94,8 @@ export default function PrometheusDatasourceManager() {
{sources.length === 0 ? (
<PageEmpty
icon={<Database className="h-12 w-12" />}
title=t('monitor.prometheusdatasourcemanager.s99ed81')
description=t('monitor.prometheusdatasourcemanager.sd9a356')
title="暂无 Prometheus 数据源"
description="添加数据源后可用于指标监控与监控大屏"
action={(
<Button onClick={openCreate} size="sm" className="dg-btn-primary">
<Plus className="w-4 h-4 mr-1" />添加数据源
@@ -109,11 +107,11 @@ export default function PrometheusDatasourceManager() {
<table className="w-full">
<thead className="border-b border-[var(--border-default)]">
<tr className="text-xs dg-text-secondary">
<th className="text-left py-3 px-4 font-medium">{t('common.name')}</th>
<th className="text-left py-3 px-4 font-medium">名称</th>
<th className="text-left py-3 px-4 font-medium">URL</th>
<th className="text-left py-3 px-4 font-medium w-20">{t('approval.status.default')}</th>
<th className="text-left py-3 px-4 font-medium w-16">{t('common.status')}</th>
<th className="text-right py-3 px-4 font-medium w-36">{t('common.actions')}</th>
<th className="text-left py-3 px-4 font-medium w-20">默认</th>
<th className="text-left py-3 px-4 font-medium w-16">状态</th>
<th className="text-right py-3 px-4 font-medium w-36">操作</th>
</tr>
</thead>
<tbody>
@@ -144,16 +142,16 @@ export default function PrometheusDatasourceManager() {
</td>
<td className="py-3 px-4">
{ds.is_default ? (
<span className="dg-badge-yellow"><Star className="w-3 h-3 mr-1 inline" />{t('approval.status.default')}</span>
<span className="dg-badge-yellow"><Star className="w-3 h-3 mr-1 inline" />默认</span>
) : (
<span className="text-xs dg-text-muted">--</span>
)}
</td>
<td className="py-3 px-4">
{ds.status === 1 ? (
<span className="dg-status-running">{t('common.enable')}</span>
<span className="dg-status-running">启用</span>
) : (
<span className="dg-badge-muted">{t('common.disable')}</span>
<span className="dg-badge-muted">禁用</span>
)}
</td>
<td className="py-3 px-4">
@@ -162,7 +160,7 @@ export default function PrometheusDatasourceManager() {
variant="ghost" size="sm"
className="h-8 px-2"
onClick={() => handleTestQuick(ds)}
title=t('aiops.llmTest')
title="测试连接"
>
<Plug className="w-3.5 h-3.5" />
</Button>
@@ -171,7 +169,7 @@ export default function PrometheusDatasourceManager() {
variant="ghost" size="sm"
className="h-8 px-2 dg-text-yellow"
onClick={() => handleSetDefault(ds)}
title=t('aiops.llmSetDefault')
title="设为默认"
>
<Star className="w-3.5 h-3.5" />
</Button>
@@ -32,7 +32,6 @@ import { toast } from 'sonner';
import { useConfirm } from '@/components/ui/confirm-dialog';
import { zabbixDatasourceApi } from '@/api';
import type { JsonData } from '@/types/common';
import { useTranslation } from 'react-i18next';
interface ZabbixDS {
id: number;
@@ -60,7 +59,6 @@ const defaultForm = {
};
export default function ZabbixDatasourceManager() {
const { t } = useTranslation();
const _confirm = useConfirm();
const [sources, setSources] = useState<ZabbixDS[]>([]);
const [loading, setLoading] = useState(true);
@@ -80,7 +78,7 @@ export default function ZabbixDatasourceManager() {
const res: JsonData = await zabbixDatasourceApi.list();
setSources(res?.data || res || []);
} catch {
toast.error(t('monitor.zabbixdatasourcemanager.s45f817'));
toast.error('获取数据源列表失败');
} finally {
setLoading(false);
}
@@ -117,51 +115,51 @@ export default function ZabbixDatasourceManager() {
};
const handleSave = async () => {
if (!form.name.trim()) { toast.error(t('monitor.zabbixdatasourcemanager.s138957')); return; }
if (!form.url.trim()) { toast.error(t('monitor.zabbixdatasourcemanager.s2ba385')); return; }
if (!form.username.trim()) { toast.error(t('login.usernameRequired')); return; }
if (!form.password.trim()) { toast.error(t('login.passwordRequired')); return; }
if (!form.name.trim()) { toast.error('请输入数据源名称'); return; }
if (!form.url.trim()) { toast.error('请输入 Zabbix API URL'); return; }
if (!form.username.trim()) { toast.error('请输入用户名'); return; }
if (!form.password.trim()) { toast.error('请输入密码'); return; }
try {
if (editingId) {
await zabbixDatasourceApi.update(editingId, form);
toast.success(t('monitor.zabbixdatasourcemanager.s8dfdd2'));
toast.success('数据源已更新');
} else {
await zabbixDatasourceApi.create(form);
toast.success(t('monitor.zabbixdatasourcemanager.sa6def0'));
toast.success('数据源已创建');
}
setDialogOpen(false);
fetchList();
} catch (err) {
toast.error(err?.message || t('common.operationFailed'));
toast.error(err?.message || '操作失败');
}
};
const handleDelete = async (ds: ZabbixDS) => {
const ok = await _confirm({
title: t('monitor.deleteDatasource'),
description: t('monitor.zabbixdatasourcemanager.sa2b79a', { ds.name: ds.name }),
title: '删除数据源',
description: `确定删除「${ds.name}」?`,
variant: 'destructive',
});
if (!ok) return;
try {
await zabbixDatasourceApi.delete(ds.id);
toast.success(t('alert.deleted'));
toast.success('已删除');
fetchList();
} catch { toast.error(t('common.deleteFailed')); }
} catch { toast.error('删除失败'); }
};
const handleSetDefault = async (ds: ZabbixDS) => {
try {
await zabbixDatasourceApi.setDefault(ds.id);
toast.success(t('monitor.zabbixdatasourcemanager.sf0f959', { ds.name: ds.name }));
toast.success(`已将「${ds.name}」设为默认`);
fetchList();
} catch { toast.error(t('monitor.zabbixdatasourcemanager.s9f9603')); }
} catch { toast.error('设置失败'); }
};
const handleTest = async () => {
if (!form.url.trim() || !form.username.trim()) {
toast.error(t('monitor.zabbixdatasourcemanager.s1d3562'));
toast.error('请填写 URL 和用户名');
return;
}
setTesting(true);
@@ -175,7 +173,7 @@ export default function ZabbixDatasourceManager() {
const data = res?.data || res;
setTestResult(data);
} catch (err) {
setTestResult({ success: false, message: err?.message || t('monitor.zabbixdatasourcemanager.s9710d9') });
setTestResult({ success: false, message: err?.message || '测试失败' });
} finally {
setTesting(false);
}
@@ -201,7 +199,7 @@ export default function ZabbixDatasourceManager() {
/>
Zabbix 数据源
</h2>
<p className="text-xs text-[var(--dg-text-muted)]">{t('monitor.zabbixdatasourcemanager.s79e929')}</p>
<p className="text-xs text-[var(--dg-text-muted)]">配置 Zabbix API 连接,获取主机监控数据</p>
</div>
<Button onClick={openCreate} size="sm">
<Plus className="w-4 h-4 mr-1" />添加
@@ -212,7 +210,7 @@ export default function ZabbixDatasourceManager() {
<Card className="bg-[var(--dg-bg-secondary)] border-[var(--dg-border)]">
<CardContent className="py-12 text-center text-[var(--dg-text-muted)]">
<Database className="w-12 h-12 mx-auto mb-3 opacity-30" />
<p className="text-sm">{t('monitor.zabbixdatasourcemanager.sc9c9bd')}</p>
<p className="text-sm">暂无 Zabbix 数据源</p>
<Button size="sm" className="mt-4" onClick={openCreate}>
<Plus className="w-4 h-4 mr-1" />添加数据源
</Button>
@@ -228,15 +226,15 @@ export default function ZabbixDatasourceManager() {
<div className="flex items-center gap-2 mb-1">
<div className={`w-2 h-2 rounded-full ${ds.status === 1 ? 'bg-emerald-400' : 'bg-[var(--dg-bg-active)]'}`} />
<span className="font-medium text-[var(--dg-text-primary)]">{ds.name}</span>
{ds.is_default && <Badge className="bg-amber-500/20 dg-text-yellow text-[10px]"><Star className="w-3 h-3 mr-0.5" />{t('approval.status.default')}</Badge>}
{ds.is_default && <Badge className="bg-amber-500/20 dg-text-yellow text-[10px]"><Star className="w-3 h-3 mr-0.5" />默认</Badge>}
{ds.status === 1
? <Badge className="bg-emerald-500/20 dg-text-green text-[10px]">{t('common.enable')}</Badge>
: <Badge className="bg-[var(--dg-bg-active)]/20 dg-text-secondary text-[10px]">{t('common.disable')}</Badge>}
? <Badge className="bg-emerald-500/20 dg-text-green text-[10px]">启用</Badge>
: <Badge className="bg-[var(--dg-bg-active)]/20 dg-text-secondary text-[10px]">禁用</Badge>}
</div>
<div className="text-xs text-[var(--dg-text-muted)] space-x-3">
<code className="text-orange-300">{ds.url}</code>
<span>用户: {ds.username}</span>
{ds.direct_db && <Badge variant="outline" className="text-[10px]">{t('monitor.zabbixdatasourcemanager.s85260a')}</Badge>}
{ds.direct_db && <Badge variant="outline" className="text-[10px]">直连DB</Badge>}
</div>
</div>
<div className="flex items-center gap-1">
@@ -265,7 +263,7 @@ export default function ZabbixDatasourceManager() {
<DialogHeader>
<DialogTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
<Database className="h-5 w-5 dg-text-orange" />
{editingId ? t('monitor.zabbixdatasourcemanager.sc1c87e') : t('monitor.zabbixdatasourcemanager.sa77d38')}
{editingId ? '编辑 Zabbix 数据源' : '新建 Zabbix 数据源'}
</DialogTitle>
<DialogDescription>
配置 Zabbix API 连接,用于主机监控与告警数据获取
@@ -276,14 +274,14 @@ export default function ZabbixDatasourceManager() {
{/* Name + Default */}
<div className="grid grid-cols-2 gap-3">
<div>
<Label className="text-xs text-[var(--dg-text-secondary)]">{t('deploy.form.nameStar')}</Label>
<Input className="mt-1 h-9 text-sm bg-[var(--dg-bg-primary)]" placeholder=t('monitor.zabbixdatasourcemanager.s9f1e6a')
<Label className="text-xs text-[var(--dg-text-secondary)]">名称 *</Label>
<Input className="mt-1 h-9 text-sm bg-[var(--dg-bg-primary)]" placeholder="如:生产 Zabbix"
value={form.name} onChange={e => updateForm('name', e.target.value)} />
</div>
<div className="flex items-end pb-1">
<div className="flex items-center gap-2">
<Switch checked={form.is_default} onCheckedChange={v => updateForm('is_default', v)} />
<Label className="text-xs cursor-pointer">{t('aiops.llmSetDefault')}</Label>
<Label className="text-xs cursor-pointer">设为默认</Label>
</div>
</div>
</div>
@@ -307,15 +305,15 @@ export default function ZabbixDatasourceManager() {
onClick={() => setShowAuth(!showAuth)}>
<div className="flex items-center gap-2">
<Shield className="w-4 h-4" />
<span>{t('monitor.zabbixdatasourcemanager.sb47858')}</span>
<span>Zabbix API 认证</span>
</div>
{showAuth ? <ChevronUp className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
</button>
{showAuth && (
<div className="px-3 pb-3 space-y-3">
<Input className="h-9 text-sm bg-[var(--dg-bg-primary)]" placeholder=t('monitor.zabbixdatasourcemanager.s04c3dd')
<Input className="h-9 text-sm bg-[var(--dg-bg-primary)]" placeholder="用户名 *"
value={form.username} onChange={e => updateForm('username', e.target.value)} />
<Input className="h-9 text-sm bg-[var(--dg-bg-primary)]" type="password" placeholder=t('monitor.zabbixdatasourcemanager.s3140c0')
<Input className="h-9 text-sm bg-[var(--dg-bg-primary)]" type="password" placeholder="密码 *"
value={form.password} onChange={e => updateForm('password', e.target.value)} />
</div>
)}
@@ -327,7 +325,7 @@ export default function ZabbixDatasourceManager() {
onClick={() => setShowTrends(!showTrends)}>
<div className="flex items-center gap-2">
<Clock className="w-4 h-4" />
<span>{t('monitor.zabbixdatasourcemanager.s05ef18')}</span>
<span>Trends 设置</span>
</div>
{showTrends ? <ChevronUp className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
</button>
@@ -335,24 +333,24 @@ export default function ZabbixDatasourceManager() {
<div className="px-3 pb-3 space-y-3">
<div className="grid grid-cols-2 gap-3">
<div>
<Label className="text-xs text-[var(--dg-text-secondary)]">{t('monitor.zabbixdatasourcemanager.sebfa4e')}</Label>
<Label className="text-xs text-[var(--dg-text-secondary)]">After (天)</Label>
<Input className="mt-1 h-9 text-sm bg-[var(--dg-bg-primary)]" type="number" min={0}
value={form.trends_after} onChange={e => updateForm('trends_after', parseInt(e.target.value) || 0)} />
</div>
<div>
<Label className="text-xs text-[var(--dg-text-secondary)]">{t('monitor.zabbixdatasourcemanager.s7fe44f')}</Label>
<Label className="text-xs text-[var(--dg-text-secondary)]">Range (秒)</Label>
<Input className="mt-1 h-9 text-sm bg-[var(--dg-bg-primary)]" type="number" min={0}
value={form.trends_range} onChange={e => updateForm('trends_range', parseInt(e.target.value) || 0)} />
</div>
</div>
<div className="grid grid-cols-2 gap-3">
<div>
<Label className="text-xs text-[var(--dg-text-secondary)]">{t('monitor.zabbixdatasourcemanager.sbf9a86')}</Label>
<Label className="text-xs text-[var(--dg-text-secondary)]">Cache TTL (秒)</Label>
<Input className="mt-1 h-9 text-sm bg-[var(--dg-bg-primary)]" type="number" min={0}
value={form.trends_cache_ttl} onChange={e => updateForm('trends_cache_ttl', parseInt(e.target.value) || 3600)} />
</div>
<div>
<Label className="text-xs text-[var(--dg-text-secondary)]">{t('monitor.zabbixdatasourcemanager.s21f982')}</Label>
<Label className="text-xs text-[var(--dg-text-secondary)]">Timeout (秒)</Label>
<Input className="mt-1 h-9 text-sm bg-[var(--dg-bg-primary)]" type="number" min={1}
value={form.trends_timeout} onChange={e => updateForm('trends_timeout', parseInt(e.target.value) || 30)} />
</div>
@@ -367,7 +365,7 @@ export default function ZabbixDatasourceManager() {
onClick={() => setShowOther(!showOther)}>
<div className="flex items-center gap-2">
<Settings className="w-4 h-4" />
<span>{t('monitor.zabbixdatasourcemanager.sdda36e')}</span>
<span>其他设置</span>
</div>
{showOther ? <ChevronUp className="w-4 h-4" /> : <ChevronDown className="w-4 h-4" />}
</button>
@@ -378,11 +376,11 @@ export default function ZabbixDatasourceManager() {
<Switch checked={form.direct_db} onCheckedChange={v => updateForm('direct_db', v)} />
</div>
<div className="flex items-center justify-between">
<Label className="text-xs">{t('monitor.zabbixdatasourcemanager.s413ec7')}</Label>
<Label className="text-xs">只读用户禁用确认</Label>
<Switch checked={form.disable_acknowledges} onCheckedChange={v => updateForm('disable_acknowledges', v)} />
</div>
<div className="flex items-center justify-between">
<Label className="text-xs">{t('monitor.zabbixdatasourcemanager.s6d4d6f')}</Label>
<Label className="text-xs">禁用数据对齐</Label>
<Switch checked={form.disable_data_alignment} onCheckedChange={v => updateForm('disable_data_alignment', v)} />
</div>
</div>
@@ -406,8 +404,8 @@ export default function ZabbixDatasourceManager() {
测试连接
</Button>
<div className="flex-1" />
<Button variant="ghost" size="sm" onClick={() => setDialogOpen(false)}>{t('common.cancel')}</Button>
<Button size="sm" onClick={handleSave}>{t('common.save')}</Button>
<Button variant="ghost" size="sm" onClick={() => setDialogOpen(false)}>取消</Button>
<Button size="sm" onClick={handleSave}>保存</Button>
</DialogFooter>
</DialogContent>
</Dialog>
@@ -1,6 +1,7 @@
// Prometheus 数据源添加/编辑弹窗 // Logan.Li
import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import {
Database,
Plus,
@@ -36,7 +37,6 @@ import { usePromDatasourceMutations } from '@/hooks/api';
import type { PromDS, HeaderEntry, PromDsForm } from './types';
import { defaultForm } from './types';
import { dsToForm, parseHeaders, buildPayload, testPromConnection, type TestConnectionResult } from './helpers';
import { useTranslation } from 'react-i18next';
interface PromDsFormDialogProps {
open: boolean;
@@ -51,8 +51,8 @@ export default function PromDsFormDialog({
editingDs,
sources,
}: PromDsFormDialogProps) {
const { t } = useTranslation();
const { createMutation, updateMutation } = usePromDatasourceMutations();
const { t } = useTranslation(['monitor', 'common']);
const editingId = editingDs?.id ?? null;
const [form, setForm] = useState<PromDsForm>({ ...defaultForm });
@@ -102,28 +102,28 @@ export default function PromDsFormDialog({
};
const handleSave = async () => {
if (!form.name.trim()) { toast.error(t('monitor.promdsformdialog.s138957')); return; }
if (!form.url.trim()) { toast.error(t('monitor.promdsformdialog.sdc869f')); return; }
if (!form.name.trim()) { toast.error(t('monitor:promDs.nameRequired')); return; }
if (!form.url.trim()) { toast.error(t('monitor:promDs.urlRequired')); return; }
const payload = buildPayload(form, headers);
try {
if (editingId) {
await updateMutation.mutateAsync({ id: editingId, data: payload });
toast.success(t('monitor.promdsformdialog.sc0c477'));
toast.success(t('monitor:promDs.updateSuccess'));
} else {
await createMutation.mutateAsync(payload);
toast.success(t('monitor.promdsformdialog.s8b45c1'));
toast.success(t('monitor:promDs.createSuccess'));
}
onOpenChange(false);
} catch (err: unknown) {
const message = err instanceof Error ? err.message : t('common.operationFailed');
const message = err instanceof Error ? err.message : t('monitor:promDs.opFailed');
toast.error(message);
}
};
const handleTestConnection = async () => {
if (!form.url.trim()) { toast.error(t('monitor.promdsformdialog.sc289ae')); return; }
if (!form.url.trim()) { toast.error(t('monitor:promDs.urlInputRequired')); return; }
setTesting(true);
setTestResult(null);
try {
@@ -136,7 +136,7 @@ export default function PromDsFormDialog({
});
setTestResult(data);
} catch (err: unknown) {
const message = err instanceof Error ? err.message : t('monitor.promdsformdialog.s9710d9');
const message = err instanceof Error ? err.message : t('monitor:promDs.testFailed');
setTestResult({ success: false, message });
} finally {
setTesting(false);
@@ -151,10 +151,10 @@ export default function PromDsFormDialog({
<DialogHeader>
<DialogTitle className="flex items-center gap-2 text-lg">
<Database className="w-5 h-5 dg-text-orange" />
{editingId ? t('monitor.editDatasource') : t('monitor.addDatasource')}
{editingId ? t('monitor:editDatasource') : t('monitor:addDatasource')}
</DialogTitle>
<DialogDescription>
Prometheus 数据源配置 · 参考 Grafana 数据源管理
{t('monitor:promDs.configDesc')}
</DialogDescription>
</DialogHeader>
@@ -165,7 +165,7 @@ export default function PromDsFormDialog({
<Label htmlFor="ds-name" className="text-sm">Name <span className="dg-text-red">*</span></Label>
<Input
id="ds-name"
placeholder=t('monitor.promdsformdialog.s9a9542')
placeholder={t('monitor:promDs.namePlaceholder')}
value={form.name}
onChange={e => updateForm('name', e.target.value)}
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)]"
@@ -240,14 +240,14 @@ export default function PromDsFormDialog({
{form.basic_auth && (
<div className="grid grid-cols-2 gap-3 ml-9">
<Input
placeholder=t('login.username')
placeholder={t('monitor:promDs.username')}
value={form.basic_auth_user}
onChange={e => updateForm('basic_auth_user', e.target.value)}
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-sm"
/>
<Input
type="password"
placeholder=t('login.password')
placeholder={t('monitor:promDs.password')}
value={form.basic_auth_pass}
onChange={e => updateForm('basic_auth_pass', e.target.value)}
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-sm"
@@ -286,7 +286,7 @@ export default function PromDsFormDialog({
</div>
{form.with_ca_cert && (
<textarea
placeholder=t('monitor.promdsformdialog.sf66241')
placeholder={t('monitor:promDs.caCertPlaceholder')}
value={form.ca_cert}
onChange={e => updateForm('ca_cert', e.target.value)}
rows={4}
@@ -324,7 +324,7 @@ export default function PromDsFormDialog({
</Button>
</div>
{headers.length === 0 ? (
<p className="text-xs text-[var(--dg-text-secondary)] italic">{t('monitor.promdsformdialog.s3c75b9')}</p>
<p className="text-xs text-[var(--dg-text-secondary)] italic">{t('monitor:promDs.noHeaders')}</p>
) : (
<div className="space-y-2">
{headers.map((h, idx) => (
@@ -384,7 +384,7 @@ export default function PromDsFormDialog({
<SelectValue placeholder="Choose" />
</SelectTrigger>
<SelectContent>
<SelectItem value="__none">{t('common.none')}</SelectItem>
<SelectItem value="__none">{t('common:none')}</SelectItem>
{sources.filter(s => s.id !== editingId).map(s => (
<SelectItem key={s.id} value={String(s.id)}>{s.name}</SelectItem>
))}
@@ -409,7 +409,7 @@ export default function PromDsFormDialog({
onChange={e => updateForm('scrape_interval', Number(e.target.value))}
className="w-20 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-sm text-center"
/>
<span className="text-xs text-[var(--dg-text-secondary)]">{t('common.second')}</span>
<span className="text-xs text-[var(--dg-text-secondary)]">{t('monitor:promDs.second')}</span>
</div>
</div>
<div className="space-y-2">
@@ -424,7 +424,7 @@ export default function PromDsFormDialog({
onChange={e => updateForm('query_timeout', Number(e.target.value))}
className="w-20 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-sm text-center"
/>
<span className="text-xs text-[var(--dg-text-secondary)]">{t('common.second')}</span>
<span className="text-xs text-[var(--dg-text-secondary)]">{t('monitor:promDs.second')}</span>
</div>
</div>
</div>
@@ -470,7 +470,7 @@ export default function PromDsFormDialog({
<div className="space-y-2">
<Label className="text-sm text-[var(--dg-text-secondary)]">Custom query parameters</Label>
<Input
placeholder=t('monitor.promdsformdialog.s5617a6')
placeholder={t('monitor:promDs.queryParamsPlaceholder')}
value={form.custom_query_params}
onChange={e => updateForm('custom_query_params', e.target.value)}
className="bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-sm font-mono"
@@ -513,14 +513,14 @@ export default function PromDsFormDialog({
) : (
<Plug className="w-4 h-4" />
)}
Save & test
{t('monitor:promDs.saveTest')}
</Button>
<div className="flex-1" />
<Button variant="ghost" onClick={() => onOpenChange(false)}>
取消
{t('common:cancel')}
</Button>
<Button onClick={handleSave} disabled={saving}>
{editingId ? t('common.update') : t('common.save')}
{editingId ? t('common:update') : t('common:save')}
</Button>
</DialogFooter>
</DialogContent>
@@ -3,7 +3,6 @@
import { toast } from 'sonner';
import { promDatasourceApi } from '@/api';
import type { PromDS, HeaderEntry, PromDsForm } from './types';
import i18n from '@/i18n';
export type TestConnectionParams = {
url: string;
@@ -105,12 +104,12 @@ export async function handleTestQuick(ds: PromDS): Promise<void> {
skip_tls_verify: ds.skip_tls_verify,
});
if (data?.success) {
toast.success(i18n.t('monitor.helpers.s50047c', { data.target_count || 0: data.target_count || 0 }));
toast.success(`连接成功 · ${data.target_count || 0} targets`);
} else {
toast.error(data?.message || i18n.t('aiops.llmTestFailed'));
toast.error(data?.message || '连接失败');
}
} catch (err: unknown) {
const message = err instanceof Error ? err.message : i18n.t('monitor.helpers.s9710d9');
const message = err instanceof Error ? err.message : '测试失败';
toast.error(message);
}
}