refactor(i18n): U32 全量 hash key 清理 — 151 个 hash key → 语义化键 + React Hooks 警告 53→43
- 151 个 hash-style flat key (s+hex 后缀) 全部重命名为语义化 nested key
- monitor 58 个: alertChannelDialog/alertManager/alertRulesTab/chartRangeHint/
esIndexPicker/helpers/hostMonitor/logAlertSpanel/logClusterPanel/logDingAssistant/
logQueryToolbar/logRbac/lokiLabelBrowse/metricsExplorer/middlewareMonit/
mwOverviewChart/portPolicyDialog/prometheusDashb/queryHistoryPan/savedQueriesPan/
siteMonitor/snmpMonitor/snmpOverviewChart/zabbixDashboard/zabbixDatasource
- kubernetes 42 个: deploymentBundle/deploymentEditAdvanced/deploymentEditService/
deploymentView/deploymentWorkload/eventsPage/kubernetesCluster/namespaceManage/
namespaceResource/podExecTerminal/podFileBrowser/podLogsViewer/podMetricsPage/
resourceVisualEditor/workloadViewPage
- aiops 17 个: agentCliMessage/aiAnalysisResult/analyzerHelpers/assistant/predictUtils
- agent 12 个: agentAlerts/agentMonitor/hostDetailDialog
- cloud 13 个: billingRecordDialog/billingRuleDialog/platformManager
- pipeline 6 个: buildNodesManage/deployRbac/deployTargetField
- system 3 个: auditSetting
- 58 个源文件中的 147 处 t()/i18n.t() 调用更新为语义化键路径
- 3 个命名空间冲突修复 (monitor.hostMonitor/agent.agentMonitor/aiops.aiAnalysisResult
原 string 值提升为 .title 子键)
- React Hooks 警告修复 (53→43, -10):
- exhaustive-deps 4→0: useMemo/useCallback 添加 t 到 deps 数组
- preserve-manual-memoization 5→0: 变量遮蔽修复 (filter(t)→filter(tg))
- 1 个冗余 eslint-disable 指令移除 (CronJobManager)
- zh/en 7480=7480 完全对齐, 0 个 hash key 残留
- tsc -b=0, npm build✓ (17.59s), ESLint errors=0/warnings=43/any=0
- go build=0, 17/17 集成测试通过, Docker healthy
This commit is contained in:
1 parent
4f2d279865
commit
ff426d908b
63 files changed
+674
-477
No files matched your search
@@ -124,7 +124,7 @@ export function AgentAlerts() {
|
||||
|
||||
<Tabs value={activeTab} onValueChange={setActiveTab} className="w-full">
|
||||
<TabsList className="bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)]">
|
||||
<TabsTrigger value="events" className="data-[state=active]:bg-[var(--dg-bg-active)]"> {i18n.t('kubernetes.eventspagetsx.s0e5b83cc')} </TabsTrigger>
|
||||
<TabsTrigger value="events" className="data-[state=active]:bg-[var(--dg-bg-active)]"> {i18n.t('kubernetes.eventsPage.alertEvents')} </TabsTrigger>
|
||||
<TabsTrigger value="rules" className="data-[state=active]:bg-[var(--dg-bg-active)]"> {i18n.t('monitor.alertRules')} </TabsTrigger>
|
||||
</TabsList>
|
||||
|
||||
@@ -185,11 +185,11 @@ export function AgentAlerts() {
|
||||
{alert.hostname || '--'}
|
||||
</span>
|
||||
<span className="inline-flex items-center gap-1">
|
||||
<span className="dg-text-secondary"> {i18n.t('agent.agentalertstsx.sbfdcf242')} </span> {getMetricLabel(alert.metric)}
|
||||
<span className="dg-text-secondary"> {i18n.t('agent.agentAlerts.metric')} </span> {getMetricLabel(alert.metric)}
|
||||
</span>
|
||||
{alert.value != null && (
|
||||
<span className="inline-flex items-center gap-1">
|
||||
<span className="dg-text-secondary"> {i18n.t('agent.agentalertstsx.s2d13763b')} </span> {alert.value}
|
||||
<span className="dg-text-secondary"> {i18n.t('agent.agentAlerts.currentValue')} </span> {alert.value}
|
||||
</span>
|
||||
)}
|
||||
<span className="inline-flex items-center gap-1">
|
||||
|
||||
@@ -142,8 +142,8 @@ export function AgentMonitor() {
|
||||
{/* 页头 */}
|
||||
<div className="flex items-center justify-between">
|
||||
<div>
|
||||
<h2 className="text-xl font-semibold text-[var(--dg-text-primary)]">{t("agent.agentmonitortsx.s1a2b3c4d")}</h2>
|
||||
<p className="text-sm dg-text-secondary mt-0.5"> {i18n.t('agent.agentmonitortsx.sa75d7519')} </p>
|
||||
<h2 className="text-xl font-semibold text-[var(--dg-text-primary)]">{t("agent.agentMonitor.title")}</h2>
|
||||
<p className="text-sm dg-text-secondary mt-0.5"> {i18n.t('agent.agentMonitor.subtitle')} </p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
|
||||
@@ -85,7 +85,7 @@ export function HostDetailDialog({
|
||||
<Badge className="bg-red-500/15 dg-text-red border border-red-500/30"> {i18n.t('agent.agentOffline')} </Badge>
|
||||
)}
|
||||
</DialogTitle>
|
||||
<DialogDescription className="sr-only"> {i18n.t('agent.hostdetaildialo.sffa4f720')} </DialogDescription>
|
||||
<DialogDescription className="sr-only"> {i18n.t('agent.hostDetailDialog.desc')} </DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<div className="space-y-4">
|
||||
@@ -109,9 +109,9 @@ export function HostDetailDialog({
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
<SelectContent className="dg-input">
|
||||
<SelectItem value="1"> {i18n.t('agent.hostdetaildialo.s3851af2c')} </SelectItem>
|
||||
<SelectItem value="6"> {i18n.t('agent.hostdetaildialo.s2d59b172')} </SelectItem>
|
||||
<SelectItem value="24"> {i18n.t('agent.hostdetaildialo.s768a1b34')} </SelectItem>
|
||||
<SelectItem value="1"> {i18n.t('agent.hostDetailDialog.last1h')} </SelectItem>
|
||||
<SelectItem value="6"> {i18n.t('agent.hostDetailDialog.last6h')} </SelectItem>
|
||||
<SelectItem value="24"> {i18n.t('agent.hostDetailDialog.last24h')} </SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
@@ -121,7 +121,7 @@ export function HostDetailDialog({
|
||||
<Loader2 className="h-5 w-5 animate-spin dg-text-muted" />
|
||||
</div>
|
||||
) : chartData.length === 0 ? (
|
||||
<div className="h-full flex items-center justify-center text-sm dg-text-muted"> {i18n.t('agent.hostdetaildialo.sdc73dbe9')} </div>
|
||||
<div className="h-full flex items-center justify-center text-sm dg-text-muted"> {i18n.t('agent.hostDetailDialog.noHistoryData')} </div>
|
||||
) : (
|
||||
<ResponsiveContainer width="100%" height="100%">
|
||||
<AreaChart data={chartData} margin={{ top: 5, right: 5, bottom: 0, left: -20 }}>
|
||||
@@ -161,7 +161,7 @@ export function HostDetailDialog({
|
||||
端口发现 ({ports.length})
|
||||
</span>
|
||||
{ports.length === 0 ? (
|
||||
<p className="text-xs dg-text-muted"> {i18n.t('agent.hostdetaildialo.se7887d60')} </p>
|
||||
<p className="text-xs dg-text-muted"> {i18n.t('agent.hostDetailDialog.noPortData')} </p>
|
||||
) : (
|
||||
<div className="flex flex-wrap gap-1.5 max-h-32 overflow-y-auto">
|
||||
{ports.map((p, idx) => (
|
||||
|
||||
@@ -20,7 +20,7 @@ export function AIAnalysisResult({ selectedAlert, isAnalyzing, analysis, onAutoF
|
||||
<CardHeader className="border-b border-[var(--dg-border)] pb-3">
|
||||
<CardTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
|
||||
<Sparkles className="h-5 w-5 dg-text-purple" />
|
||||
{i18n.t('aiops.aiAnalysisResult')}
|
||||
{i18n.t('aiops.aiAnalysisResult.title')}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<ScrollArea className="flex-1">
|
||||
@@ -28,13 +28,13 @@ export function AIAnalysisResult({ selectedAlert, isAnalyzing, analysis, onAutoF
|
||||
{!selectedAlert ? (
|
||||
<div className="flex flex-col items-center justify-center h-64 dg-text-muted">
|
||||
<Brain className="h-16 w-16 mb-4 opacity-30" />
|
||||
<p> {i18n.t('aiops.aianalysisresul.s52bbd52d')} </p>
|
||||
<p> {i18n.t('aiops.aiAnalysisResult.selectAlertHint')} </p>
|
||||
</div>
|
||||
) : isAnalyzing ? (
|
||||
<div className="flex flex-col items-center justify-center h-64">
|
||||
<Loader2 className="h-8 w-8 animate-spin dg-text-purple mb-4" />
|
||||
<p className="dg-text-secondary">{i18n.t('aiops.analyzingRootCause')}</p>
|
||||
<p className="text-xs dg-text-muted mt-2"> {i18n.t('aiops.aianalysisresul.sf7d04a0f')} </p>
|
||||
<p className="text-xs dg-text-muted mt-2"> {i18n.t('aiops.aiAnalysisResult.correlatingHint')} </p>
|
||||
</div>
|
||||
) : analysis ? (
|
||||
<div className="space-y-4">
|
||||
|
||||
@@ -270,7 +270,7 @@ function ThoughtBlock({
|
||||
{open ? <ChevronDown className="w-3.5 h-3.5" /> : <ChevronRight className="w-3.5 h-3.5" />}
|
||||
<Brain className="w-3.5 h-3.5 dg-text-purple" />
|
||||
{!hideRoundLabel && round != null && <span className="dg-text-muted">{i18n.t('aiops.roundThinking', { round })}</span>}
|
||||
{hideRoundLabel && <span className="dg-text-muted"> {i18n.t('aiops.agentclimessage.s21d68b2d')} </span>}
|
||||
{hideRoundLabel && <span className="dg-text-muted"> {i18n.t('aiops.agentCliMessage.thinking')} </span>}
|
||||
{streaming && <Loader2 className="w-3 h-3 dg-text-purple animate-spin" />}
|
||||
<span className="ml-1 dg-text-muted truncate">{!open && preview}</span>
|
||||
</button>
|
||||
|
||||
@@ -53,7 +53,7 @@ export function generateAIAnalysis(alert: AlertItem): AIAnalysis {
|
||||
`考虑临时扩容或将部分流量调度到其他节点`,
|
||||
i18n.t('aiops.analysis.checkAbnormalTasks'),
|
||||
],
|
||||
autoFixScript: `#!/bin/bash\n# CPU 高负载诊断脚本 - ${target}\necho "${i18n.t('aiops.analysis.topCpuProcess')}"\nps aux --sort=-%cpu | head -11\necho ""\necho "${i18n.t('aiops.analyzerhelpers.sc4e238d7')}"\nuptime\necho ""\necho "${i18n.t('aiops.analyzerhelpers.sfaca56f5')}"\nPID=$(ps aux --sort=-%cpu | sed -n '2p' | awk '{print $2}')\nif [ -n "$PID" ]; then\n echo "${i18n.t('aiops.analyzerhelpers.s303a9855')}"\n cat /proc/$PID/cmdline | tr '\\0' ' '\n echo ""\nfi\n`,
|
||||
autoFixScript: `#!/bin/bash\n# CPU 高负载诊断脚本 - ${target}\necho "${i18n.t('aiops.analysis.topCpuProcess')}"\nps aux --sort=-%cpu | head -11\necho ""\necho "${i18n.t('aiops.analyzerHelpers.systemLoad')}"\nuptime\necho ""\necho "${i18n.t('aiops.analyzerHelpers.highCpuProcessDetail')}"\nPID=$(ps aux --sort=-%cpu | sed -n '2p' | awk '{print $2}')\nif [ -n "$PID" ]; then\n echo "${i18n.t('aiops.analyzerHelpers.topCpuProcess')}"\n cat /proc/$PID/cmdline | tr '\\0' ' '\n echo ""\nfi\n`,
|
||||
similarCases: 0,
|
||||
confidence: 0,
|
||||
};
|
||||
@@ -90,7 +90,7 @@ export function generateAIAnalysis(alert: AlertItem): AIAnalysis {
|
||||
i18n.t('aiops.analysis.checkAbnormalTasks'),
|
||||
i18n.t('aiops.analysis.checkAbnormalTasks'),
|
||||
],
|
||||
autoFixScript: `#!/bin/bash\n# 磁盘清理脚本 - ${target}\necho "${i18n.t('aiops.analyzerhelpers.s5b91c16b')}"\ndf -h /\necho ""\necho "${i18n.t('aiops.analyzerhelpers.s3b1993da')}"\nfind /var/log -name "*.log" -mtime +30 -delete 2>/dev/null\nfind /var/log -name "*.gz" -mtime +30 -delete 2>/dev/null\necho ""\necho "${i18n.t('aiops.analyzerhelpers.sb513e117')}"\njournalctl --vacuum-time=7d 2>/dev/null\necho ""\necho "${i18n.t('aiops.analyzerhelpers.s4c139c9f')}"\ndf -h /\n`,
|
||||
autoFixScript: `#!/bin/bash\n# 磁盘清理脚本 - ${target}\necho "${i18n.t('aiops.analyzerHelpers.diskBeforeClean')}"\ndf -h /\necho ""\necho "${i18n.t('aiops.analyzerHelpers.cleanOldLogs')}"\nfind /var/log -name "*.log" -mtime +30 -delete 2>/dev/null\nfind /var/log -name "*.gz" -mtime +30 -delete 2>/dev/null\necho ""\necho "${i18n.t('aiops.analyzerHelpers.cleanSystemCache')}"\njournalctl --vacuum-time=7d 2>/dev/null\necho ""\necho "${i18n.t('aiops.analyzerHelpers.diskAfterClean')}"\ndf -h /\n`,
|
||||
similarCases: 0,
|
||||
confidence: 0,
|
||||
};
|
||||
@@ -127,7 +127,7 @@ export function generateAIAnalysis(alert: AlertItem): AIAnalysis {
|
||||
i18n.t('aiops.analysis.checkAbnormalTasks'),
|
||||
i18n.t('aiops.analysis.checkAbnormalTasks'),
|
||||
],
|
||||
autoFixScript: `#!/bin/bash\n# 服务恢复脚本 - ${target}\necho "${i18n.t('aiops.analyzerhelpers.se59337b9')}"\nsystemctl list-units --state=failed\necho ""\necho "${i18n.t('aiops.analyzerhelpers.scdd631f0')}"\nss -tlnp | grep -E ':(80|443|8080|3306|6379|9090)'\necho ""\necho "${i18n.t('aiops.analyzerhelpers.sad3e7bba')}"\nsystemctl reset-failed\n`,
|
||||
autoFixScript: `#!/bin/bash\n# 服务恢复脚本 - ${target}\necho "${i18n.t('aiops.analyzerHelpers.checkServiceStatus')}"\nsystemctl list-units --state=failed\necho ""\necho "${i18n.t('aiops.analyzerHelpers.checkPortListen')}"\nss -tlnp | grep -E ':(80|443|8080|3306|6379|9090)'\necho ""\necho "${i18n.t('aiops.analyzerHelpers.restartFailedService')}"\nsystemctl reset-failed\n`,
|
||||
similarCases: 0,
|
||||
confidence: 0,
|
||||
};
|
||||
|
||||
@@ -98,9 +98,9 @@ export function costRecommendation(trend: 'up' | 'down' | 'stable', ratio: numbe
|
||||
function budgetRiskAction(metric: 'daily' | 'monthly', provider: string): string {
|
||||
const scope = provider && provider !== i18n.t('aiops.predictutilsts.sg5a3d8e1') ? `${provider} ` : '';
|
||||
if (metric === 'daily') {
|
||||
return i18n.t('aiops.predictutilsts.se4b7a5d2', { scope });
|
||||
return i18n.t('aiops.predictUtils.dailyCostHint', { scope });
|
||||
}
|
||||
return i18n.t('aiops.predictutilsts.sf2d8c6b4', { scope });
|
||||
return i18n.t('aiops.predictUtils.monthlyBillHint', { scope });
|
||||
}
|
||||
|
||||
interface MonthEndForecast {
|
||||
|
||||
@@ -93,12 +93,12 @@ export function BillingRecordDialog({ open, onOpenChange, editingRecord, onSucce
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{editingRecord ? i18n.t('cloud.billingRecordDialog.editRecord') : i18n.t('cloud.recordCost')}</DialogTitle>
|
||||
<DialogDescription> {i18n.t('cloud.billingrecorddi.s09e541fd')} </DialogDescription>
|
||||
<DialogDescription> {i18n.t('cloud.billingRecordDialog.desc')} </DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-3">
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingrecorddi.sb11d8416')} </Label>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingRecordDialog.providerLabel')} </Label>
|
||||
<Select value={form.provider} onValueChange={(v) => setForm({ ...form, provider: v })}>
|
||||
<SelectTrigger className="mt-1"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
@@ -109,13 +109,13 @@ export function BillingRecordDialog({ open, onOpenChange, editingRecord, onSucce
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingrecorddi.s3abdefe2')} </Label>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingRecordDialog.dateLabel')} </Label>
|
||||
<Input type="date" className="mt-1" value={form.billing_date} onChange={(e) => setForm({ ...form, billing_date: e.target.value })} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingrecorddi.s6f252687')} </Label>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingRecordDialog.costLabel')} </Label>
|
||||
<Input type="number" step="0.01" className="mt-1" placeholder="0.00" value={form.cost} onChange={(e) => setForm({ ...form, cost: e.target.value })} />
|
||||
</div>
|
||||
<div>
|
||||
|
||||
@@ -84,7 +84,7 @@ export function BillingRuleDialog({ open, onOpenChange, editingRule, onSuccess }
|
||||
<DialogContent className="max-w-md">
|
||||
<DialogHeader>
|
||||
<DialogTitle>{editingRule ? i18n.t('cloud.billingRuleDialog.editRule') : i18n.t('cloud.billingRuleDialog.addRule')}</DialogTitle>
|
||||
<DialogDescription> {i18n.t('cloud.billingruledial.s75227f20')} </DialogDescription>
|
||||
<DialogDescription> {i18n.t('cloud.billingRuleDialog.desc')} </DialogDescription>
|
||||
</DialogHeader>
|
||||
<div className="space-y-3">
|
||||
<div>
|
||||
@@ -97,7 +97,7 @@ export function BillingRuleDialog({ open, onOpenChange, editingRule, onSuccess }
|
||||
<Select value={form.provider || 'all'} onValueChange={(v) => setForm({ ...form, provider: v === 'all' ? '' : v })}>
|
||||
<SelectTrigger className="mt-1"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all"> {i18n.t('cloud.billingruledial.sc356f198')} </SelectItem>
|
||||
<SelectItem value="all"> {i18n.t('cloud.billingRuleDialog.allProviders')} </SelectItem>
|
||||
{Object.entries(providerLabels).map(([k, v]) => (
|
||||
<SelectItem key={k} value={k}>{v}</SelectItem>
|
||||
))}
|
||||
@@ -117,19 +117,19 @@ export function BillingRuleDialog({ open, onOpenChange, editingRule, onSuccess }
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingruledial.sd7650ece')} </Label>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingRuleDialog.compare')} </Label>
|
||||
<Select value={form.operator} onValueChange={(v) => setForm({ ...form, operator: v })}>
|
||||
<SelectTrigger className="mt-1"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value=">"> {i18n.t('cloud.billingruledial.s3dba9756')} </SelectItem>
|
||||
<SelectItem value=">="> {i18n.t('cloud.billingruledial.s8e1e26d1')} </SelectItem>
|
||||
<SelectItem value="<"> {i18n.t('cloud.billingruledial.s0196c18c')} </SelectItem>
|
||||
<SelectItem value="<="> {i18n.t('cloud.billingruledial.s45c301a8')} </SelectItem>
|
||||
<SelectItem value=">"> {i18n.t('cloud.billingRuleDialog.gt')} </SelectItem>
|
||||
<SelectItem value=">="> {i18n.t('cloud.billingRuleDialog.gte')} </SelectItem>
|
||||
<SelectItem value="<"> {i18n.t('cloud.billingRuleDialog.lt')} </SelectItem>
|
||||
<SelectItem value="<="> {i18n.t('cloud.billingRuleDialog.lte')} </SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingruledial.s11f9fb4c')} </Label>
|
||||
<Label className="text-sm text-[var(--dg-text-secondary)]"> {i18n.t('cloud.billingRuleDialog.thresholdLabel')} </Label>
|
||||
<Input type="number" step="0.01" className="mt-1" placeholder="500.00" value={form.threshold} onChange={(e) => setForm({ ...form, threshold: e.target.value })} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -349,7 +349,7 @@ export function PlatformManager() {
|
||||
<DialogTitle> {i18n.t('k8s.actionModal.confirmDelete')} </DialogTitle>
|
||||
<DialogDescription className="sr-only"> {i18n.t('aiops.llmModelDesc')} </DialogDescription>
|
||||
</DialogHeader>
|
||||
<p className="text-sm dg-text-secondary"> {i18n.t('cloud.platformmanager.s452abbb1')} </p>
|
||||
<p className="text-sm dg-text-secondary"> {i18n.t('cloud.platformManager.deleteConfirm')} </p>
|
||||
<DialogFooter>
|
||||
<Button variant="ghost" onClick={() => setDeleteId(null)}> {i18n.t('rbac.jobRole.cancel')} </Button>
|
||||
<Button variant="destructive" onClick={confirmDelete}> {i18n.t('kubernetes.storage.delete2')} </Button>
|
||||
|
||||
@@ -202,13 +202,13 @@ export default function BuildNodesManager({ embedded = false }: { embedded?: boo
|
||||
<div className="flex items-center gap-2">
|
||||
<Cpu className="h-4 w-4 text-[var(--dg-text-muted)]" />
|
||||
<span className="text-sm font-medium text-[var(--dg-text-primary)]">{i18n.t('deploy.buildNodes.masterBuiltin')}</span>
|
||||
<Badge variant="outline" className="text-[10px]"> {i18n.t('pipeline.buildnodesmanag.sa419fe03')} </Badge>
|
||||
<Badge variant="outline" className="text-[10px]"> {i18n.t('pipeline.buildNodesManage.defaultSchedule')} </Badge>
|
||||
<span className="text-xs text-[var(--dg-text-muted)]">
|
||||
{i18n.t('deploy.buildNodes.executorUsage', { running: master.running_count, max: master.max_executors })}
|
||||
</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Label className="text-xs text-[var(--dg-text-muted)] shrink-0"> {i18n.t('pipeline.buildnodesmanag.s8e408e28')} </Label>
|
||||
<Label className="text-xs text-[var(--dg-text-muted)] shrink-0"> {i18n.t('pipeline.buildNodesManage.maxConcurrency')} </Label>
|
||||
<Input
|
||||
type="number"
|
||||
min={1}
|
||||
@@ -308,11 +308,11 @@ export default function BuildNodesManager({ embedded = false }: { embedded?: boo
|
||||
</div>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs"> {i18n.t('pipeline.buildnodesmanag.s8e408e28')} </Label>
|
||||
<Label className="text-xs"> {i18n.t('pipeline.buildNodesManage.maxConcurrency')} </Label>
|
||||
<Input value={maxExecutors} onChange={(e) => setMaxExecutors(e.target.value)} type="number" min={1} className="h-8 text-xs dg-input" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs"> {i18n.t('pipeline.buildnodesmanag.sbcfcd088')} </Label>
|
||||
<Label className="text-xs"> {i18n.t('pipeline.buildNodesManage.workspacePath')} </Label>
|
||||
<Input value={workspacePath} onChange={(e) => setWorkspacePath(e.target.value)} className="h-8 text-xs font-mono dg-input" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -219,7 +219,7 @@ export default function DeployRBAC() {
|
||||
icon={<Shield className="h-10 w-10" />}
|
||||
title={i18n.t('deploy.rbac.policy.noPolicy')}
|
||||
description={i18n.t('deploy.rbac.policy.createHint')}
|
||||
action={<Button onClick={() => setCreateOpen(true)}><Plus className="h-4 w-4 mr-1" /> {i18n.t('monitor.logrbactsx.s6058845c')} </Button>}
|
||||
action={<Button onClick={() => setCreateOpen(true)}><Plus className="h-4 w-4 mr-1" /> {i18n.t('monitor.logRbac.newPermission')} </Button>}
|
||||
/>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
@@ -313,7 +313,7 @@ export default function DeployRBAC() {
|
||||
</div>
|
||||
{selectedUser ? (
|
||||
assignments.length === 0 ? (
|
||||
<p className="text-xs text-[var(--dg-text-muted)]"> {i18n.t('pipeline.deployrbactsx.sef9548ee')} </p>
|
||||
<p className="text-xs text-[var(--dg-text-muted)]"> {i18n.t('pipeline.deployRbac.noJobPermission')} </p>
|
||||
) : (
|
||||
<div className="space-y-1.5">
|
||||
{assignments.map((a) => {
|
||||
@@ -334,7 +334,7 @@ export default function DeployRBAC() {
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<p className="text-xs text-[var(--dg-text-muted)] flex items-center gap-1"><Users className="w-3.5 h-3.5" /> {i18n.t('monitor.logrbactsx.s9be00c95')} </p>
|
||||
<p className="text-xs text-[var(--dg-text-muted)] flex items-center gap-1"><Users className="w-3.5 h-3.5" /> {i18n.t('monitor.logRbac.selectUserHint')} </p>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -369,7 +369,7 @@ export default function DeployRBAC() {
|
||||
</Badge>
|
||||
))}
|
||||
{previewRoleId !== null && previewMatches.length === 0 && (
|
||||
<span className="text-xs text-[var(--dg-text-muted)]"> {i18n.t('monitor.logrbactsx.s64096f4d')} </span>
|
||||
<span className="text-xs text-[var(--dg-text-muted)]"> {i18n.t('monitor.logRbac.noMatchHint')} </span>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
@@ -210,7 +210,7 @@ export function DeployTargetFields({ value, onChange, requireTarget = true }: De
|
||||
<Loader2 className="h-4 w-4 animate-spin mr-1.5" />加载中
|
||||
</div>
|
||||
) : filteredServers.length === 0 ? (
|
||||
<p className="text-xs text-[var(--dg-text-muted)] text-center py-8"> {i18n.t('pipeline.deploytargetfie.sb4240171')} </p>
|
||||
<p className="text-xs text-[var(--dg-text-muted)] text-center py-8"> {i18n.t('pipeline.deployTargetField.noHostAvailable')} </p>
|
||||
) : (
|
||||
<div className="p-1.5 space-y-1">
|
||||
{filteredServers.map((srv) => {
|
||||
@@ -242,7 +242,7 @@ export function DeployTargetFields({ value, onChange, requireTarget = true }: De
|
||||
</div>
|
||||
)}
|
||||
</ScrollArea>
|
||||
<p className="text-[10px] text-[var(--dg-text-muted)]"> {i18n.t('pipeline.deploytargetfie.sb2b6db98')} </p>
|
||||
<p className="text-[10px] text-[var(--dg-text-muted)]"> {i18n.t('pipeline.deployTargetField.scpDeployHint')} </p>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
<div className="space-y-1">
|
||||
<Label className="text-xs"> {i18n.t('kubernetes.container.containerName')} </Label>
|
||||
|
||||
@@ -170,7 +170,7 @@ export function DeploymentEditAdvanced({ clusterCode, namespace, deploymentName,
|
||||
};
|
||||
const base = buildAdvancedManifest(rawManifest, state);
|
||||
await saveDeploymentManifest(clusterCode, namespace, deploymentName, base);
|
||||
toast({ title: i18n.t('kubernetes.deploymentedita.s9762d0a4'), description: `${deploymentName} 更新已提交` });
|
||||
toast({ title: i18n.t('kubernetes.deploymentEditAdvanced.saved'), description: `${deploymentName} 更新已提交` });
|
||||
onSaved(base);
|
||||
} catch (e) {
|
||||
toast({ title: i18n.t('kubernetes.msg.saveFailed'), description: e instanceof Error ? e.message : String(e), variant: 'destructive' });
|
||||
|
||||
@@ -256,7 +256,7 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
|
||||
<CardContent className="p-3">
|
||||
<div className="flex items-center gap-2 text-xs dg-text-secondary">
|
||||
<Network className="h-3.5 w-3.5 dg-text-blue" />
|
||||
<span> {i18n.t('kubernetes.deploymentedits.sb8eef7f0')} </span>
|
||||
<span> {i18n.t('kubernetes.deploymentEditService.selectorLabel')} </span>
|
||||
<div className="flex flex-wrap gap-1">
|
||||
{Object.entries(selectorLabels).map(([k, v]) => (
|
||||
<code key={k} className="bg-[var(--dg-bg-tertiary)] px-1.5 py-0.5 rounded text-[var(--dg-text-secondary)] text-[11px]">{k}={v}</code>
|
||||
@@ -289,7 +289,7 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
|
||||
<Plus className="h-3 w-3 mr-1" />创建 Service
|
||||
</Button>
|
||||
</div>
|
||||
<p className="text-xs dg-text-muted mt-1"> {i18n.t('kubernetes.deploymentedits.sd0ad85b8')} </p>
|
||||
<p className="text-xs dg-text-muted mt-1"> {i18n.t('kubernetes.deploymentEditService.selectorHint')} </p>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0">
|
||||
{matchedSvcs.length === 0 && showCreate !== 'service' ? (
|
||||
@@ -387,7 +387,7 @@ export function DeploymentEditService({ clusterCode, namespace, deploymentName,
|
||||
)}
|
||||
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button size="sm" variant="outline" className="h-7 text-xs border-[var(--dg-border)] dg-text-secondary" onClick={onCancel}> {i18n.t('kubernetes.deploymentedits.s3a77522f')} </Button>
|
||||
<Button size="sm" variant="outline" className="h-7 text-xs border-[var(--dg-border)] dg-text-secondary" onClick={onCancel}> {i18n.t('kubernetes.deploymentEditService.backToView')} </Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -223,7 +223,7 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
<div className="p-3 space-y-2.5 border-b border-[var(--dg-border)]/80">
|
||||
<div className="flex items-center gap-2 flex-wrap">
|
||||
<VIcon className={`h-4 w-4 ${vtype?.color || 'dg-text-secondary'}`} />
|
||||
<span className="text-xs dg-text-secondary shrink-0"> {i18n.t('kubernetes.deploymentedits.sa3119d33')} </span>
|
||||
<span className="text-xs dg-text-secondary shrink-0"> {i18n.t('kubernetes.deploymentEditService.volumeName')} </span>
|
||||
<Input
|
||||
value={vol.name}
|
||||
onChange={(e) => {
|
||||
@@ -322,7 +322,7 @@ export function DeploymentEditStorage({ clusterCode, namespace, deploymentName,
|
||||
)}
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[11px] dg-text-muted shrink-0"> {i18n.t('kubernetes.deploymentedits.sf4b25a22')} </span>
|
||||
<span className="text-[11px] dg-text-muted shrink-0"> {i18n.t('kubernetes.deploymentEditService.subPath')} </span>
|
||||
<Input
|
||||
value={mount.subPath}
|
||||
onChange={(e) => updateMount(i, mi, { subPath: e.target.value })}
|
||||
|
||||
@@ -195,7 +195,7 @@ export function DeploymentView(props: DeploymentViewProps) {
|
||||
{pods[0].node_name || pods[0].node || '-'}
|
||||
</button>
|
||||
} />
|
||||
<InfoItem label={i18n.t('kubernetes.deploymentviewt.s6d2d954e')} value={<span className="font-mono">{pods[0].ip || pods[0].pod_ip || '-'}</span>} />
|
||||
<InfoItem label={i18n.t('kubernetes.deploymentView.podIp')} value={<span className="font-mono">{pods[0].ip || pods[0].pod_ip || '-'}</span>} />
|
||||
</>
|
||||
)}
|
||||
<InfoItem label={i18n.t('system.userCreatedAt')} value={formatK8sTime(deployment?.created_at || deployment?.creationTimestamp)} />
|
||||
|
||||
@@ -336,7 +336,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={onBack}><ArrowLeft className="h-4 w-4 mr-1" /> {i18n.t('common.back')} </Button>
|
||||
{modeTabs}
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={loadData}><RefreshCw className="h-4 w-4" /></Button>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={() => { setNewImage(deployment?.image || ''); setModal({ kind: 'image' }); }}><ImageIcon className="h-3.5 w-3.5 mr-1" /> {i18n.t('kubernetes.deploymentworkl.sf2e0208b')} </Button>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={() => { setNewImage(deployment?.image || ''); setModal({ kind: 'image' }); }}><ImageIcon className="h-3.5 w-3.5 mr-1" /> {i18n.t('kubernetes.deploymentWorkload.adjustImage')} </Button>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={handleRestart}><RotateCw className="h-3.5 w-3.5 mr-1" /> {i18n.t('agent.agentServiceRestart')} </Button>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" disabled={!!actionLoading} onClick={handleTogglePause}>
|
||||
{deployment?.paused ? <><Play className="h-3.5 w-3.5 mr-1 dg-text-green" /> {i18n.t('kubernetes.deployment.resume')} </> : <><Pause className="h-3.5 w-3.5 mr-1 dg-text-orange" /> {i18n.t('kubernetes.job.suspend')} </>}
|
||||
@@ -352,7 +352,7 @@ export function DeploymentWorkload({ clusterCode, namespace, deploymentName, mod
|
||||
<Badge className={isHealthy ? 'bg-emerald-500/20 dg-text-green border-emerald-500/30' : 'bg-amber-500/20 dg-text-yellow border-amber-500/30'}>
|
||||
{isHealthy ? <CheckCircle className="h-3 w-3 mr-1" /> : <AlertTriangle className="h-3 w-3 mr-1" />}{ready}/{total}
|
||||
</Badge>
|
||||
{deployment?.paused && <Badge className="bg-orange-500/20 dg-text-orange border-orange-500/30"><Pause className="h-3 w-3 mr-1" /> {i18n.t('kubernetes.deploymentworkl.s8be2521d')} </Badge>}
|
||||
{deployment?.paused && <Badge className="bg-orange-500/20 dg-text-orange border-orange-500/30"><Pause className="h-3 w-3 mr-1" /> {i18n.t('kubernetes.deploymentWorkload.paused')} </Badge>}
|
||||
</div>
|
||||
|
||||
{/* ============ 主体:view / edit / yaml ============ */}
|
||||
|
||||
@@ -162,7 +162,7 @@ export default function EventsPage() {
|
||||
|
||||
const filterToolbar = (selectedReason || selectedKind) ? (
|
||||
<div className="flex items-center gap-2 text-xs">
|
||||
<span className="text-[var(--dg-text-muted)]"> {i18n.t('kubernetes.eventspagetsx.s841389c5')} </span>
|
||||
<span className="text-[var(--dg-text-muted)]"> {i18n.t('kubernetes.eventsPage.filterLabel')} </span>
|
||||
{selectedReason && (
|
||||
<button type="button" className="inline-flex items-center gap-1 rounded border border-[var(--dg-border)] px-2 py-0.5 text-[var(--dg-text-secondary)] hover:bg-[var(--dg-bg-tertiary)]" onClick={() => setSelectedReason('')}>
|
||||
原因 {selectedReason} <X className="h-3 w-3" />
|
||||
@@ -206,18 +206,18 @@ export default function EventsPage() {
|
||||
<Select value={selectedNs} onValueChange={(v) => { setSelectedNs(v); setSelectedReason(''); setSelectedKind(''); }}>
|
||||
<SelectTrigger className="w-36 h-9 dg-input"><SelectValue placeholder={i18n.t('kubernetes.namespace.title')} /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all"> {i18n.t('kubernetes.podmetricspaget.s58173b22')} </SelectItem>
|
||||
<SelectItem value="all"> {i18n.t('kubernetes.podMetricsPage.allNamespaces')} </SelectItem>
|
||||
{namespaces.map((n) => <SelectItem key={n} value={n}>{n}</SelectItem>)}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select value={timeWindow} onValueChange={setTimeWindow}>
|
||||
<SelectTrigger className="w-32 h-9 dg-input"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="0"> {i18n.t('kubernetes.eventspagetsx.s98c99f62')} </SelectItem>
|
||||
<SelectItem value="1"> {i18n.t('monitor.helpersts.sf972b7b1')} </SelectItem>
|
||||
<SelectItem value="0"> {i18n.t('kubernetes.eventsPage.allTime')} </SelectItem>
|
||||
<SelectItem value="1"> {i18n.t('monitor.helpers.last1h')} </SelectItem>
|
||||
<SelectItem value="6"> {i18n.t('monitor.siteProtocol.rangeDefault')} </SelectItem>
|
||||
<SelectItem value="24"> {i18n.t('monitor.helpersts.s6e99b786')} </SelectItem>
|
||||
<SelectItem value="168"> {i18n.t('monitor.helpersts.sd765efc4')} </SelectItem>
|
||||
<SelectItem value="24"> {i18n.t('monitor.helpers.last24h')} </SelectItem>
|
||||
<SelectItem value="168"> {i18n.t('monitor.helpers.last7d')} </SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Button variant="outline" size="sm" className="dg-btn-secondary" onClick={() => { loadEvents(); loadSummary(); }} disabled={loading}>
|
||||
@@ -270,7 +270,7 @@ export default function EventsPage() {
|
||||
<Select value={filterType} onValueChange={setFilterType}>
|
||||
<SelectTrigger className="w-28 h-8 dg-input text-xs"><SelectValue /></SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all"> {i18n.t('kubernetes.eventspagetsx.sfb995166')} </SelectItem>
|
||||
<SelectItem value="all"> {i18n.t('kubernetes.eventsPage.allTypes')} </SelectItem>
|
||||
<SelectItem value="Warning">Warning</SelectItem>
|
||||
<SelectItem value="Normal">Normal</SelectItem>
|
||||
</SelectContent>
|
||||
|
||||
@@ -168,7 +168,7 @@ export function KubernetesClusterDialog({
|
||||
</p>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
<Label className="text-[var(--dg-text-secondary)]"> {i18n.t('kubernetes.kubernetesclust.sbf23eb8e')} </Label>
|
||||
<Label className="text-[var(--dg-text-secondary)]"> {i18n.t('kubernetes.kubernetesCluster.versionOptional')} </Label>
|
||||
<Input
|
||||
value={formData.version}
|
||||
onChange={(e) => setFormData({ ...formData, version: e.target.value })}
|
||||
@@ -189,7 +189,7 @@ export function KubernetesClusterDialog({
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<Label className="text-[var(--dg-text-secondary)]"> {i18n.t('kubernetes.kubernetesclust.saaa159b7')} </Label>
|
||||
<Label className="text-[var(--dg-text-secondary)]"> {i18n.t('kubernetes.kubernetesCluster.accessMethod')} </Label>
|
||||
<RadioGroup
|
||||
value={String(formData.config_type)}
|
||||
onValueChange={(v) => setFormData({ ...formData, config_type: Number(v) })}
|
||||
|
||||
@@ -182,7 +182,7 @@ export default function NamespaceManagementPage() {
|
||||
<TableRow className="border-[var(--dg-border)] hover:bg-transparent">
|
||||
<TableHead className="text-[var(--dg-text-secondary)]"> {i18n.t('kubernetes.secret.secretName')} </TableHead>
|
||||
<TableHead className="text-[var(--dg-text-secondary)]"> {i18n.t('system.terminalStatus')} </TableHead>
|
||||
<TableHead className="text-[var(--dg-text-secondary)]"> {i18n.t('kubernetes.namespacemanage.sa01a9963')} </TableHead>
|
||||
<TableHead className="text-[var(--dg-text-secondary)]"> {i18n.t('kubernetes.namespaceManage.age')} </TableHead>
|
||||
<TableHead className="text-[var(--dg-text-secondary)] text-center">Deploy</TableHead>
|
||||
<TableHead className="text-[var(--dg-text-secondary)] text-center">Pods</TableHead>
|
||||
<TableHead className="text-[var(--dg-text-secondary)] text-center">Svc</TableHead>
|
||||
|
||||
@@ -172,7 +172,7 @@ export default function NamespaceResourcePage() {
|
||||
const searchToolbar = (
|
||||
<div className="relative w-56 flex-1 min-w-[200px] max-w-xs">
|
||||
<Search className="absolute left-3 top-1/2 -translate-y-1/2 h-4 w-4 dg-text-muted" />
|
||||
<Input placeholder={i18n.t('kubernetes.namespaceresour.s64e327ed')} value={search} onChange={(e) => setSearch(e.target.value)} className="pl-9 h-9 dg-input" />
|
||||
<Input placeholder={i18n.t('kubernetes.namespaceResource.searchPlaceholder')} value={search} onChange={(e) => setSearch(e.target.value)} className="pl-9 h-9 dg-input" />
|
||||
</div>
|
||||
);
|
||||
|
||||
|
||||
@@ -95,7 +95,7 @@ export function PodDetailDialog({ pod, onClose }: PodDetailDialogProps) {
|
||||
|
||||
{/* 现状详情(Conditions) */}
|
||||
<div>
|
||||
<h4 className="text-sm font-medium text-[var(--dg-text-primary)] mb-3"> {i18n.t('kubernetes.namespaceresour.s1d8d6e2e')} </h4>
|
||||
<h4 className="text-sm font-medium text-[var(--dg-text-primary)] mb-3"> {i18n.t('kubernetes.namespaceResource.conditionsDetail')} </h4>
|
||||
{cond.length === 0 ? (
|
||||
<p className="text-xs text-[var(--dg-text-muted)] py-2"> {i18n.t('aiops.assistantNoData')} </p>
|
||||
) : (
|
||||
|
||||
@@ -273,7 +273,7 @@ export function PodFileBrowser({
|
||||
</div>
|
||||
<div className="flex-1 overflow-auto p-3">
|
||||
<pre className="text-xs text-[var(--dg-text-secondary)] font-mono whitespace-pre-wrap break-all bg-[var(--dg-bg-primary)] rounded p-3">
|
||||
{preview.content || i18n.t('kubernetes.podfilebrowsert.sf42649da')}
|
||||
{preview.content || i18n.t('kubernetes.podFileBrowser.emptyFile')}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -263,7 +263,7 @@ export function ResourceVisualEditor({ clusterCode, namespace, resource, name, o
|
||||
<div className="flex-1 flex items-center justify-center text-center text-[var(--dg-text-muted)]">
|
||||
<div>
|
||||
<p> {i18n.t('k8s.rve.hostPlaceholder')} </p>
|
||||
<Button variant="outline" size="sm" className="mt-4" onClick={() => setMode('yaml')}> {i18n.t('kubernetes.resourcevisuale.s54c78d4f')} </Button>
|
||||
<Button variant="outline" size="sm" className="mt-4" onClick={() => setMode('yaml')}> {i18n.t('kubernetes.resourceVisualEditor.switchToYaml')} </Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
@@ -271,7 +271,7 @@ export function ResourceVisualEditor({ clusterCode, namespace, resource, name, o
|
||||
) : (
|
||||
<div className="text-center py-12 text-[var(--dg-text-muted)]">
|
||||
<p> {i18n.t('k8s.rve.keyPlaceholder')} </p>
|
||||
<Button variant="outline" size="sm" className="mt-4" onClick={() => setMode('yaml')}> {i18n.t('kubernetes.resourcevisuale.s54c78d4f')} </Button>
|
||||
<Button variant="outline" size="sm" className="mt-4" onClick={() => setMode('yaml')}> {i18n.t('kubernetes.resourceVisualEditor.switchToYaml')} </Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -175,7 +175,7 @@ export default function WorkloadViewPage() {
|
||||
<Badge variant="outline" className="border-[var(--dg-border)] text-[var(--dg-text-secondary)]">{namespace}</Badge>
|
||||
{isHealthy
|
||||
? <Badge className="bg-[var(--dg-green)]/20 text-[var(--dg-green)] border-[var(--dg-green)]/30"> {i18n.t('k8s.clusters.statusHealthy')} </Badge>
|
||||
: <Badge className="bg-[var(--dg-orange)]/20 text-[var(--dg-orange)] border-[var(--dg-orange)]/30"> {i18n.t('kubernetes.workloadviewpag.sf339d471')} </Badge>}
|
||||
: <Badge className="bg-[var(--dg-orange)]/20 text-[var(--dg-orange)] border-[var(--dg-orange)]/30"> {i18n.t('kubernetes.workloadViewPage.updating')} </Badge>}
|
||||
</div>
|
||||
|
||||
{!loading && (mode === 'yaml' ? (
|
||||
@@ -198,7 +198,7 @@ export default function WorkloadViewPage() {
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 lg:grid-cols-6 gap-3">
|
||||
{isSts ? (
|
||||
<>
|
||||
<StatCard label={i18n.t('kubernetes.workloadviewpag.sea639697')} value={`${readyReplicas}/${replicas}`} color={isHealthy ? STATUS_COLORS.green : STATUS_COLORS.orange} sub={isHealthy ? i18n.t('kubernetes.workloadviewpag.s23c944c1') : i18n.t('kubernetes.workloadviewpag.sac100213')} />
|
||||
<StatCard label={i18n.t('kubernetes.workloadViewPage.replicasReady')} value={`${readyReplicas}/${replicas}`} color={isHealthy ? STATUS_COLORS.green : STATUS_COLORS.orange} sub={isHealthy ? i18n.t('kubernetes.workloadViewPage.allReady') : i18n.t('kubernetes.workloadViewPage.partialReady')} />
|
||||
<StatCard label={i18n.t('kubernetes.hpa.currentReplicas')} value={currentReplicas} color={STATUS_COLORS.blue} />
|
||||
<StatCard label={i18n.t('kubernetes.deployment.updatedReplicas')} value={updatedReplicas} color={STATUS_COLORS.green} />
|
||||
<StatCard label={i18n.t('k8s.workloadView.currentReplicas')} value={stats.spec.serviceName || '-'} color="var(--dg-text-secondary)" />
|
||||
@@ -277,7 +277,7 @@ export default function WorkloadViewPage() {
|
||||
</div>
|
||||
)}
|
||||
{containers.length === 0 ? (
|
||||
<p className="text-xs text-[var(--dg-text-muted)] py-3"> {i18n.t('kubernetes.workloadviewpag.se4b61048')} </p>
|
||||
<p className="text-xs text-[var(--dg-text-muted)] py-3"> {i18n.t('kubernetes.workloadViewPage.noContainerData')} </p>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
<p className="text-[11px] text-[var(--dg-text-muted)] mb-1 uppercase tracking-wide">Containers</p>
|
||||
|
||||
@@ -81,7 +81,7 @@ export async function saveDeploymentBundleYaml(
|
||||
yamlText: string,
|
||||
): Promise<void> {
|
||||
const { manifests } = await parseEditableManifests(yamlText);
|
||||
if (manifests.length === 0) throw new Error(i18n.t('kubernetes.deploymentbundl.s47161e05'));
|
||||
if (manifests.length === 0) throw new Error(i18n.t('kubernetes.deploymentBundle.yamlEmpty'));
|
||||
|
||||
for (const manifest of manifests) {
|
||||
const kind = String(manifest.kind || '').toLowerCase();
|
||||
|
||||
@@ -19,7 +19,7 @@ export function TolerationsCard({ tolerations, onAdd, onRemove, onUpdate }: Tole
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-3">
|
||||
<div className="flex items-center justify-between">
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)]"> {i18n.t('kubernetes.deploymentedita.s13a8310b')} </CardTitle>
|
||||
<CardTitle className="text-sm text-[var(--dg-text-primary)]"> {i18n.t('kubernetes.deploymentEditAdvanced.tolerations')} </CardTitle>
|
||||
<Button size="sm" variant="outline" className="h-7 border-[var(--dg-border)] text-[var(--dg-text-secondary)] text-xs"
|
||||
onClick={onAdd}>
|
||||
<Plus className="h-3 w-3 mr-1" />添加
|
||||
@@ -27,7 +27,7 @@ export function TolerationsCard({ tolerations, onAdd, onRemove, onUpdate }: Tole
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="pt-0 space-y-2">
|
||||
{tolerations.length === 0 && <p className="text-xs dg-text-muted"> {i18n.t('kubernetes.deploymentedita.s8bc06bde')} </p>}
|
||||
{tolerations.length === 0 && <p className="text-xs dg-text-muted"> {i18n.t('kubernetes.deploymentEditAdvanced.noTolerations')} </p>}
|
||||
{tolerations.map((t, i) => (
|
||||
<div key={i} className="grid grid-cols-[1fr_80px_1fr_100px_80px_auto] gap-2 items-center">
|
||||
<Input value={t.key} placeholder="key" onChange={e => onUpdate(i, { key: e.target.value })}
|
||||
@@ -42,7 +42,7 @@ export function TolerationsCard({ tolerations, onAdd, onRemove, onUpdate }: Tole
|
||||
className="h-7 dg-input text-xs font-mono" />
|
||||
<select value={t.effect} onChange={e => onUpdate(i, { effect: e.target.value })}
|
||||
className="h-7 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] rounded text-xs text-[var(--dg-text-secondary)] px-1">
|
||||
<option value=""> {i18n.t('kubernetes.deploymentedita.s2a6eb2dd')} </option>
|
||||
<option value=""> {i18n.t('kubernetes.deploymentEditAdvanced.any')} </option>
|
||||
<option value="NoSchedule">NoSchedule</option>
|
||||
<option value="PreferNoSchedule">PreferNoSchedule</option>
|
||||
<option value="NoExecute">NoExecute</option>
|
||||
|
||||
@@ -20,7 +20,7 @@ export function IngressListItem({ ing, matched, onEdit, onDelete }: Props) {
|
||||
{matched ? <CheckCircle className="h-4 w-4 dg-text-purple" /> : <GitBranch className="h-4 w-4 dg-text-muted" />}
|
||||
<span className="text-sm font-semibold text-[var(--dg-text-primary)]">{ing.name}</span>
|
||||
<Badge variant="outline" className="border-[var(--dg-border)] dg-text-secondary text-[10px]">{ing.className}</Badge>
|
||||
{matched && <Badge className="bg-purple-500/20 text-purple-300 border-purple-500/30 text-[10px]"> {i18n.t('kubernetes.deploymentedits.s1c3cf7f5')} </Badge>}
|
||||
{matched && <Badge className="bg-purple-500/20 text-purple-300 border-purple-500/30 text-[10px]"> {i18n.t('kubernetes.deploymentEditService.associated')} </Badge>}
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-green ml-auto"
|
||||
onClick={onEdit}>
|
||||
<Pencil className="h-3 w-3 mr-1" />编辑
|
||||
|
||||
@@ -67,7 +67,7 @@ export function ServiceCreateForm({ svcForm, setSvcForm, selectorLabels, deploym
|
||||
|
||||
{/* 快速预设 */}
|
||||
<div>
|
||||
<Label className="dg-text-muted text-[11px] mb-1 block"> {i18n.t('kubernetes.deploymentedits.s83907cde')} </Label>
|
||||
<Label className="dg-text-muted text-[11px] mb-1 block"> {i18n.t('kubernetes.deploymentEditService.quickAddPorts')} </Label>
|
||||
<div className="flex gap-1.5">
|
||||
{PORT_PRESETS.map(p => (
|
||||
<button key={p.name} onClick={() => addPort(p)}
|
||||
@@ -134,7 +134,7 @@ export function ServiceCreateForm({ svcForm, setSvcForm, selectorLabels, deploym
|
||||
<code key={k} className="bg-[var(--dg-bg-tertiary)] px-1 py-0.5 rounded dg-text-secondary ml-1">{k}={v}</code>
|
||||
))
|
||||
) : (
|
||||
<span className="dg-text-muted italic"> {i18n.t('kubernetes.deploymentedits.s5847b0f9')} </span>
|
||||
<span className="dg-text-muted italic"> {i18n.t('kubernetes.deploymentEditService.notDetected')} </span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ export function ServiceListItem({ svc, matched, onEdit, onDelete }: Props) {
|
||||
{matched ? <CheckCircle className="h-4 w-4 dg-text-blue" /> : <Network className="h-4 w-4 dg-text-muted" />}
|
||||
<span className="text-sm font-semibold text-[var(--dg-text-primary)]">{svc.name}</span>
|
||||
<Badge variant="outline" className="border-[var(--dg-border)] dg-text-secondary text-[10px]">{svc.type}</Badge>
|
||||
{matched && <Badge className="bg-blue-500/20 text-blue-300 border-blue-500/30 text-[10px]"> {i18n.t('kubernetes.deploymentedits.s1c3cf7f5')} </Badge>}
|
||||
{matched && <Badge className="bg-blue-500/20 text-blue-300 border-blue-500/30 text-[10px]"> {i18n.t('kubernetes.deploymentEditService.associated')} </Badge>}
|
||||
<code className="text-[11px] dg-text-muted ml-auto">{svc.clusterIP}</code>
|
||||
<Button size="sm" variant="ghost" className="h-6 text-xs dg-text-green"
|
||||
onClick={onEdit}>
|
||||
|
||||
@@ -35,7 +35,7 @@ export function BottomStatusBar({
|
||||
className={cn('flex items-center gap-1', autoScroll ? 'dg-text-green' : 'text-[var(--dg-text-muted)]')}
|
||||
onClick={onToggleAutoScroll}
|
||||
>
|
||||
<Maximize2 className="h-3 w-3" />{autoScroll ? i18n.t('kubernetes.podlogsviewerts.sd7eb1e98') : i18n.t('kubernetes.podlogsviewerts.s130db316')}
|
||||
<Maximize2 className="h-3 w-3" />{autoScroll ? i18n.t('kubernetes.podLogsViewer.followBottom') : i18n.t('kubernetes.podLogsViewer.followPaused')}
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -40,8 +40,8 @@ export function LogsHeader({
|
||||
<span className="text-[var(--dg-text-primary)] font-medium truncate">日志 — {podName}</span>
|
||||
{loading && <Loader2 className="h-3 w-3 animate-spin text-[var(--dg-text-muted)]" />}
|
||||
<span className="text-xs text-[var(--dg-text-muted)]">
|
||||
{streaming ? (paused ? i18n.t('kubernetes.deployment.paused') : i18n.t('kubernetes.podlogsviewerts.sd9c71f71')) : i18n.t('agent.agentServiceStopped')} · {matchedCount}{keyword ? `/${lineCount}` : ''} 行
|
||||
{lineCount >= RING_BUFFER_MAX && i18n.t('kubernetes.podlogsviewerts.sf3280b73')}
|
||||
{streaming ? (paused ? i18n.t('kubernetes.deployment.paused') : i18n.t('kubernetes.podLogsViewer.liveTail')) : i18n.t('agent.agentServiceStopped')} · {matchedCount}{keyword ? `/${lineCount}` : ''} 行
|
||||
{lineCount >= RING_BUFFER_MAX && i18n.t('kubernetes.podLogsViewer.bufferFull')}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -21,9 +21,9 @@ export interface LogLine {
|
||||
export const RING_BUFFER_MAX = 10000;
|
||||
|
||||
export const TAIL_OPTIONS = [
|
||||
{ value: '100', label: i18n.t('kubernetes.podlogsviewerts.s58b02a7a') },
|
||||
{ value: '500', label: i18n.t('kubernetes.podlogsviewerts.s9a036801') },
|
||||
{ value: '1000', label: i18n.t('kubernetes.podlogsviewerts.sf89a330c') },
|
||||
{ value: '100', label: i18n.t('kubernetes.podLogsViewer.last100') },
|
||||
{ value: '500', label: i18n.t('kubernetes.podLogsViewer.last500') },
|
||||
{ value: '1000', label: i18n.t('kubernetes.podLogsViewer.last1000') },
|
||||
{ value: '0', label: i18n.t('system.auditAll') },
|
||||
];
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@ export function ScaleDialog({
|
||||
return (
|
||||
<div className="fixed inset-0 bg-black/60 z-50 flex items-center justify-center" onClick={onClose}>
|
||||
<div className="bg-[var(--dg-bg-secondary)] border border-[var(--dg-border)] rounded-lg p-6 w-80" onClick={e => e.stopPropagation()}>
|
||||
<h3 className="text-sm font-semibold text-[var(--dg-text-primary)] mb-4"> {i18n.t('kubernetes.workloadviewpag.s7f541ee2')} </h3>
|
||||
<h3 className="text-sm font-semibold text-[var(--dg-text-primary)] mb-4"> {i18n.t('kubernetes.workloadViewPage.scaleStatefulSet')} </h3>
|
||||
<div className="flex items-center justify-center gap-4 mb-4">
|
||||
<Button variant="outline" size="icon" className="h-9 w-9" onClick={() => onScaleValueChange(Math.max(0, scaleValue - 1))}>
|
||||
<Minus className="h-4 w-4" />
|
||||
|
||||
@@ -121,7 +121,7 @@ export function AlertChannelDialog({
|
||||
<Dialog open={open} onOpenChange={onOpenChange}>
|
||||
<DialogContent className="dg-input max-w-2xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="text-[var(--dg-text-primary)]"> {i18n.t('monitor.alertchanneldia.s976ad48f')} </DialogTitle>
|
||||
<DialogTitle className="text-[var(--dg-text-primary)]"> {i18n.t('monitor.alertChannelDialog.title')} </DialogTitle>
|
||||
<DialogDescription className="dg-text-muted">
|
||||
管理告警通知渠道(钉钉/企业微信/邮件/短信/Webhook),配置后可在告警规则中引用
|
||||
</DialogDescription>
|
||||
@@ -176,7 +176,7 @@ export function AlertChannelDialog({
|
||||
{ch.test_status === 'success' ? (
|
||||
<span className="text-[11px] dg-text-green"> {i18n.t('monitor.alertChannels.testPassed')} </span>
|
||||
) : (
|
||||
<span className="text-[11px] dg-text-muted"> {i18n.t('monitor.alertchanneldia.s8c852a4c')} </span>
|
||||
<span className="text-[11px] dg-text-muted"> {i18n.t('monitor.alertChannelDialog.notTested')} </span>
|
||||
)}
|
||||
<div className="flex items-center gap-1" onClick={(e) => e.stopPropagation()}>
|
||||
<Button
|
||||
@@ -247,7 +247,7 @@ export function AlertChannelDialog({
|
||||
onCheckedChange={(v) => setChannelForm({ ...channelForm, enabled: v })}
|
||||
className="data-[state=checked]:bg-emerald-600"
|
||||
/>
|
||||
<Label className="dg-text-secondary text-xs"> {i18n.t('monitor.alertchanneldia.sbdab1c59')} </Label>
|
||||
<Label className="dg-text-secondary text-xs"> {i18n.t('monitor.alertChannelDialog.enableChannel')} </Label>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -118,8 +118,8 @@ export function AlertManager() {
|
||||
>
|
||||
<Card className="dg-card">
|
||||
<CardHeader className="pb-2">
|
||||
<CardTitle className="text-[var(--dg-text-primary)]"> {i18n.t('monitor.alertmanagertsx.s358b05d0')} </CardTitle>
|
||||
<CardDescription className="dg-text-muted"> {i18n.t('monitor.alertmanagertsx.s615fa6cb')} </CardDescription>
|
||||
<CardTitle className="text-[var(--dg-text-primary)]"> {i18n.t('monitor.alertManager.trendTitle')} </CardTitle>
|
||||
<CardDescription className="dg-text-muted"> {i18n.t('monitor.alertManager.last24hStats')} </CardDescription>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<div className="h-[200px]">
|
||||
|
||||
@@ -135,7 +135,7 @@ export function AlertRulesTab({
|
||||
</TableHead>
|
||||
<TableHead className="dg-text-secondary"> {i18n.t('monitor.ruleName')} </TableHead>
|
||||
<TableHead className="dg-text-secondary"> {i18n.t('monitor.dashboard.custom.datasource')} </TableHead>
|
||||
<TableHead className="dg-text-secondary"> {i18n.t('monitor.alertrulestabts.s65939ccd')} </TableHead>
|
||||
<TableHead className="dg-text-secondary"> {i18n.t('monitor.alertRulesTab.condition')} </TableHead>
|
||||
<TableHead className="dg-text-secondary"> {i18n.t('kubernetes.event.eventLevel')} </TableHead>
|
||||
<TableHead className="dg-text-secondary"> {i18n.t('monitor.alertDuration')} </TableHead>
|
||||
<TableHead className="dg-text-secondary"> {i18n.t('monitor.notificationChannel')} </TableHead>
|
||||
|
||||
@@ -42,7 +42,7 @@ export function EsIndexPicker({ datasourceId, value, onChange }: Props) {
|
||||
onClick={() => setOpen(!open)}
|
||||
className="h-10 px-2 text-xs rounded flex items-center gap-1 font-mono min-w-[150px] max-w-[220px]"
|
||||
style={{ background: 'var(--dg-bg-tertiary)', border: '1px solid var(--dg-border)', color: 'var(--dg-text-primary)' }}
|
||||
title={i18n.t('monitor.esindexpickerts.sa0eff8ea')}
|
||||
title={i18n.t('monitor.esIndexPicker.selectHint')}
|
||||
>
|
||||
<span className="truncate flex-1 text-left">{value || i18n.t('monitor.selectIndex')}</span>
|
||||
{loading ? <Loader2 className="h-3 w-3 animate-spin shrink-0" /> : <ChevronDown className="h-3 w-3 shrink-0" />}
|
||||
@@ -60,7 +60,7 @@ export function EsIndexPicker({ datasourceId, value, onChange }: Props) {
|
||||
<input
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
placeholder={i18n.t('monitor.esindexpickerts.s9ae0c004')}
|
||||
placeholder={i18n.t('monitor.esIndexPicker.searchPlaceholder')}
|
||||
className="flex-1 bg-transparent text-xs outline-none font-mono"
|
||||
style={{ color: 'var(--dg-text-primary)' }}
|
||||
/>
|
||||
@@ -90,7 +90,7 @@ export function EsIndexPicker({ datasourceId, value, onChange }: Props) {
|
||||
</button>
|
||||
))}
|
||||
{!loading && filtered.length === 0 && (
|
||||
<p className="text-xs px-2 py-3 text-center" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.esindexpickerts.saf5cc132')} </p>
|
||||
<p className="text-xs px-2 py-3 text-center" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.esIndexPicker.noMatch')} </p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -58,7 +58,7 @@ export function LogAlertsPanel() {
|
||||
return (
|
||||
<div className="space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm text-[var(--dg-text-muted)]"> {i18n.t('monitor.logalertspanelt.s5bc514d8')} </p>
|
||||
<p className="text-sm text-[var(--dg-text-muted)]"> {i18n.t('monitor.logAlertSpanel.desc')} </p>
|
||||
<div className="flex gap-2">
|
||||
<Button variant="outline" size="sm" onClick={load} disabled={loading}>
|
||||
<RefreshCw className={`h-4 w-4 mr-1 ${loading ? 'animate-spin' : ''}`} />刷新
|
||||
|
||||
@@ -42,7 +42,7 @@ export function LogClusterPanel({ clusters }: Props) {
|
||||
{/* 头部 */}
|
||||
<div className="flex items-center justify-between px-4 py-2" style={{ background: 'var(--dg-bg-tertiary)', borderBottom: '1px solid var(--dg-border)' }}>
|
||||
<span className="text-xs" style={{ color: 'var(--dg-text-muted)' }}>共 {clusters.length} 个聚类模式,总计 {total.toLocaleString()} 条日志</span>
|
||||
<span className="text-[10px]" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.logclusterpanel.s38112792')} </span>
|
||||
<span className="text-[10px]" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.logClusterPanel.desc')} </span>
|
||||
</div>
|
||||
|
||||
{/* 聚类列表 */}
|
||||
@@ -91,7 +91,7 @@ export function LogClusterPanel({ clusters }: Props) {
|
||||
{/* 展开详情 */}
|
||||
{expanded[i] && (
|
||||
<div className="px-4 py-3 animate-fade-in" style={{ background: 'var(--dg-bg-primary)', paddingLeft: '48px' }}>
|
||||
<p className="text-[10px] mb-1" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.logclusterpanel.se909e426')} </p>
|
||||
<p className="text-[10px] mb-1" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.logClusterPanel.sampleLog')} </p>
|
||||
<div className="p-2 rounded text-[11px] font-mono break-all" style={{ background: 'var(--dg-bg-tertiary)', color: 'var(--dg-text-secondary)' }}>
|
||||
{cluster.sample}
|
||||
</div>
|
||||
|
||||
@@ -20,10 +20,10 @@ export function LogDingAssistant({ onRuleCreated }: { onRuleCreated?: () => void
|
||||
size="lg"
|
||||
className="h-12 rounded-full shadow-lg bg-gradient-to-r from-amber-500 to-orange-500 hover:from-amber-400 hover:to-orange-400 text-white gap-2 px-5"
|
||||
onClick={() => setOpen(true)}
|
||||
title={i18n.t('monitor.logdingassistan.s26b79b6b')}
|
||||
title={i18n.t('monitor.logDingAssistant.addAlert')}
|
||||
>
|
||||
<Sparkles className="h-5 w-5" />
|
||||
<span className="font-medium"> {i18n.t('monitor.logdingassistan.s1a663141')} </span>
|
||||
<span className="font-medium"> {i18n.t('monitor.logDingAssistant.ding')} </span>
|
||||
</Button>
|
||||
</div>
|
||||
<LogAlertFromQueryDialog
|
||||
|
||||
@@ -122,7 +122,7 @@ export function LogQueryToolbar({
|
||||
</button>
|
||||
|
||||
<div className="flex items-center gap-1 ml-1">
|
||||
<span className="text-[10px]" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.logquerytoolbar.s8b76adb2')} </span>
|
||||
<span className="text-[10px]" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.logQueryToolbar.goTo')} </span>
|
||||
<input
|
||||
type="number"
|
||||
value={jumpPage}
|
||||
|
||||
@@ -217,7 +217,7 @@ export default function LogRBAC() {
|
||||
icon={<Shield className="h-10 w-10" />}
|
||||
title={i18n.t('monitor.logRbac.noPolicies')}
|
||||
description={i18n.t('monitor.logRbac.noPoliciesDesc')}
|
||||
action={<Button onClick={() => setCreateOpen(true)}><Plus className="h-4 w-4 mr-1" /> {i18n.t('monitor.logrbactsx.s6058845c')} </Button>}
|
||||
action={<Button onClick={() => setCreateOpen(true)}><Plus className="h-4 w-4 mr-1" /> {i18n.t('monitor.logRbac.newPermission')} </Button>}
|
||||
/>
|
||||
) : (
|
||||
<div className="space-y-2">
|
||||
@@ -319,7 +319,7 @@ export default function LogRBAC() {
|
||||
</div>
|
||||
{selectedUser ? (
|
||||
assignments.length === 0 ? (
|
||||
<p className="text-xs text-[var(--dg-text-muted)]"> {i18n.t('monitor.logrbactsx.sa120fc78')} </p>
|
||||
<p className="text-xs text-[var(--dg-text-muted)]"> {i18n.t('monitor.logRbac.noPermissionAssigned')} </p>
|
||||
) : (
|
||||
<div className="space-y-1.5">
|
||||
{assignments.map((a) => {
|
||||
@@ -340,7 +340,7 @@ export default function LogRBAC() {
|
||||
</div>
|
||||
)
|
||||
) : (
|
||||
<p className="text-xs text-[var(--dg-text-muted)] flex items-center gap-1"><Users className="w-3.5 h-3.5" /> {i18n.t('monitor.logrbactsx.s9be00c95')} </p>
|
||||
<p className="text-xs text-[var(--dg-text-muted)] flex items-center gap-1"><Users className="w-3.5 h-3.5" /> {i18n.t('monitor.logRbac.selectUserHint')} </p>
|
||||
)}
|
||||
</CardContent>
|
||||
</Card>
|
||||
@@ -373,7 +373,7 @@ export default function LogRBAC() {
|
||||
</Badge>
|
||||
))}
|
||||
{previewRoleId !== null && previewMatches.length === 0 && (
|
||||
<span className="text-xs text-[var(--dg-text-muted)]"> {i18n.t('monitor.logrbactsx.s64096f4d')} </span>
|
||||
<span className="text-xs text-[var(--dg-text-muted)]"> {i18n.t('monitor.logRbac.noMatchHint')} </span>
|
||||
)}
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
@@ -98,7 +98,7 @@ export function LokiLabelBrowser({ datasourceId, query, timeRange, onQueryChange
|
||||
))}
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto max-h-48 p-1">
|
||||
{!activeLabel && <p className="text-[11px] px-2 py-4 text-center" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.lokilabelbrowse.s088b9477')} </p>}
|
||||
{!activeLabel && <p className="text-[11px] px-2 py-4 text-center" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.lokiLabelBrowse.selectLabelHint')} </p>}
|
||||
{loadingValues && <div className="flex justify-center py-6"><Loader2 className="h-4 w-4 animate-spin" /></div>}
|
||||
{!loadingValues && activeLabel && values.map((v) => (
|
||||
<button
|
||||
|
||||
@@ -90,8 +90,8 @@ export function QueryHistoryPanel({ visible, onClose, onSelect, onCreateAlert }:
|
||||
{history.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center h-48 gap-2">
|
||||
<Clock className="h-8 w-8" style={{ color: 'var(--dg-border)' }} />
|
||||
<span className="text-xs" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.queryhistorypan.s1e60bc17')} </span>
|
||||
<span className="text-[10px]" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.queryhistorypan.s3895021f')} </span>
|
||||
<span className="text-xs" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.queryHistoryPan.emptyHistory')} </span>
|
||||
<span className="text-[10px]" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.queryHistoryPan.autoRecordHint')} </span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="divide-y" style={{ borderColor: 'var(--dg-border)' }}>
|
||||
@@ -139,7 +139,7 @@ export function QueryHistoryPanel({ visible, onClose, onSelect, onCreateAlert }:
|
||||
onClick={() => onSelect(item)}
|
||||
className="h-6 w-6 flex items-center justify-center rounded transition-colors"
|
||||
style={{ background: 'var(--dg-bg-tertiary)', color: 'var(--dg-green)' }}
|
||||
title={i18n.t('monitor.queryhistorypan.s4fb36a61')}
|
||||
title={i18n.t('monitor.queryHistoryPan.runQuery')}
|
||||
>
|
||||
<Play className="h-3 w-3" />
|
||||
</button>
|
||||
|
||||
@@ -43,7 +43,7 @@ export function SavedQueriesPanel({ visible, onClose, onSelect }: Props) {
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto p-3 space-y-2">
|
||||
{items.length === 0 ? (
|
||||
<p className="text-xs text-center py-8" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.savedqueriespan.s9c8dc62b')} </p>
|
||||
<p className="text-xs text-center py-8" style={{ color: 'var(--dg-text-muted)' }}> {i18n.t('monitor.savedQueriesPan.emptySaved')} </p>
|
||||
) : items.map((item) => (
|
||||
<div
|
||||
key={item.id}
|
||||
|
||||
@@ -46,7 +46,7 @@ export function useAuditSettings() {
|
||||
setApprovalRequired(policy.approvalRequired);
|
||||
useSessionSecurityStore.getState().setPolicy(policy);
|
||||
} catch {
|
||||
toast.error(i18n.t("system.useauditsetting.s32e8a76e"));
|
||||
toast.error(i18n.t("system.auditSetting.loadFailed"));
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
@@ -61,7 +61,7 @@ export function useAuditSettings() {
|
||||
if (
|
||||
!RETENTION_OPTIONS.includes(days as (typeof RETENTION_OPTIONS)[number])
|
||||
) {
|
||||
toast.error(i18n.t("system.useauditsetting.s51680af0"));
|
||||
toast.error(i18n.t("system.auditSetting.invalidRetentionDays"));
|
||||
return;
|
||||
}
|
||||
setApplying(true);
|
||||
@@ -134,7 +134,7 @@ export function useAuditSettings() {
|
||||
detail =
|
||||
s.total > 0
|
||||
? `,清理 ${s.total} 条`
|
||||
: i18n.t("system.useauditsetting.s7d55bd57");
|
||||
: i18n.t("system.auditSetting.noExpiredRecords");
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
|
||||
@@ -56,11 +56,10 @@ export function CronJobManager() {
|
||||
|
||||
const _confirm = useConfirm();
|
||||
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
const pageTabs = useMemo(() => [
|
||||
{ id: 'user', label: t('task.cronJobStats.userJobs'), badge: jobs.length || undefined },
|
||||
{ id: 'system', label: t('automation.systemTask'), badge: systemTaskCount || undefined },
|
||||
], [jobs.length, systemTaskCount]);
|
||||
], [jobs.length, systemTaskCount, t]);
|
||||
|
||||
const openCreate = () => {
|
||||
setEditJob(null);
|
||||
|
||||
Reference in new issue
Block a user