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:
1 parent
ecec73989b
commit
72bfb0e12d
191 files changed
+5057
-7592
No files matched your search
@@ -57,22 +57,19 @@ export function CICDWebhookContent({
|
||||
const restartUrl = `${apiBase}/kubernetes/${clusterCode}/namespace/${namespace}/deployments/${deploymentName}/restart`;
|
||||
|
||||
const updateBody = useMemo(() => {
|
||||
const body: Record<string, string> = { image: image || t('kubernetes.cicdwebhookcontent.sc4be9c') };
|
||||
const body: Record<string, string> = { image: image || t('k8s.cicd.newImagePlaceholder') };
|
||||
if (containerName) body.container_name = containerName;
|
||||
return JSON.stringify(body);
|
||||
}, [image, containerName]);
|
||||
|
||||
const accessKeyPlaceholder = t('k8s.cicd.accessKeyPlaceholder');
|
||||
const updateCurl = accessKey
|
||||
? `curl -X POST '${updateUrl}' \\
|
||||
-H 'X-AIOps-Access-Key: ${accessKey}' \\
|
||||
-H 'Content-Type: application/json' \\
|
||||
-d '${updateBody}'`
|
||||
: t('kubernetes.cicdwebhookcontent.s1976d2', { updateUrl: updateUrl, updateBody: updateBody });
|
||||
? `curl -X POST '${updateUrl}' \\\n -H 'X-AIOps-Access-Key: ${accessKey}' \\\n -H 'Content-Type: application/json' \\\n -d '${updateBody}'`
|
||||
: `curl -X POST '${updateUrl}' \\\n -H 'X-AIOps-Access-Key: ${accessKeyPlaceholder}' \\\n -H 'Content-Type: application/json' \\\n -d '${updateBody}'`;
|
||||
|
||||
const restartCurl = accessKey
|
||||
? `curl -X POST '${restartUrl}' \\
|
||||
-H 'X-AIOps-Access-Key: ${accessKey}'`
|
||||
: t('kubernetes.cicdwebhookcontent.s0e3668', { restartUrl: restartUrl });
|
||||
? `curl -X POST '${restartUrl}' \\\n -H 'X-AIOps-Access-Key: ${accessKey}'`
|
||||
: `curl -X POST '${restartUrl}' \\\n -H 'X-AIOps-Access-Key: ${accessKeyPlaceholder}'`;
|
||||
|
||||
const canCopy = !!accessKey && !keyExpired;
|
||||
|
||||
@@ -81,53 +78,53 @@ export function CICDWebhookContent({
|
||||
<div className="rounded-md bg-[var(--dg-bg-tertiary)]/50 px-3 py-2 text-xs text-[var(--dg-text-muted)] leading-relaxed">
|
||||
{keyLoading ? (
|
||||
<span className="inline-flex items-center gap-1.5">
|
||||
<Loader2 className="h-3 w-3 animate-spin" />正在读取 API 密钥…
|
||||
<Loader2 className="h-3 w-3 animate-spin" />{t('k8s.cicd.readingKey')}
|
||||
</span>
|
||||
) : keyExpired ? (
|
||||
<>
|
||||
访问凭证已过期,请前往
|
||||
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('header.profile')}</Link>
|
||||
调整有效期或轮换凭证后再复制 curl。
|
||||
{t('k8s.cicd.expiredPrefix')}
|
||||
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('k8s.cicd.profileCenter')}</Link>
|
||||
{t('k8s.cicd.expiredSuffix')}
|
||||
</>
|
||||
) : accessKey ? (
|
||||
<>{t('kubernetes.cicdwebhookcontent.scd2b7d')}</>
|
||||
<>{t('k8s.cicd.cachedHint')}</>
|
||||
) : hasKey ? (
|
||||
<>
|
||||
已检测到访问凭证,但本机未缓存明文。请前往
|
||||
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('header.profile')}</Link>
|
||||
轮换凭证一次,之后 curl 将自动填入。
|
||||
{t('k8s.cicd.detectedPrefix')}
|
||||
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('k8s.cicd.profileCenter')}</Link>
|
||||
{t('k8s.cicd.detectedSuffix')}
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
请先在
|
||||
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('header.profile')}</Link>
|
||||
签发 CI/CD 访问凭证,curl 将自动填入。
|
||||
{t('k8s.cicd.noKeyPrefix')}
|
||||
<Link to="/profile" className="text-[var(--dg-blue)] hover:underline mx-1">{t('k8s.cicd.profileCenter')}</Link>
|
||||
{t('k8s.cicd.noKeySuffix')}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<CodeSnippetBlock
|
||||
label=t('kubernetes.deployment.updateImage')
|
||||
label={t('k8s.editImage.updateImage')}
|
||||
code={updateCurl}
|
||||
copyLabel=t('kubernetes.cicdwebhookcontent.s25a990')
|
||||
copyLabel={t('k8s.cicd.copyLabel')}
|
||||
copyDisabled={!canCopy}
|
||||
copyDisabledTitle=t('kubernetes.cicdwebhookcontent.sc3bc41')
|
||||
copyDisabledTitle={t('k8s.cicd.copyDisabledTitle')}
|
||||
/>
|
||||
<CodeSnippetBlock
|
||||
label=t('kubernetes.deployment.restart')
|
||||
label={t('k8s.cicd.rollingRestart')}
|
||||
code={restartCurl}
|
||||
copyLabel=t('kubernetes.cicdwebhookcontent.s25a990')
|
||||
copyLabel={t('k8s.cicd.copyLabel')}
|
||||
copyDisabled={!canCopy}
|
||||
copyDisabledTitle=t('kubernetes.cicdwebhookcontent.sc3bc41')
|
||||
copyDisabledTitle={t('k8s.cicd.copyDisabledTitle')}
|
||||
/>
|
||||
|
||||
<div className="text-xs text-[var(--dg-text-muted)] space-y-1">
|
||||
<p>{t('kubernetes.cicdwebhookcontent.s1bdaf4')}<code className="text-[var(--dg-text-secondary)]">{image || '—'}</code>
|
||||
{containerName ? <> {t('kubernetes.cicdwebhookcontent.s9b07e8')} <code className="text-[var(--dg-text-secondary)]">{containerName}</code></> : null}
|
||||
<p>{t('k8s.cicd.sampleImage')}<code className="text-[var(--dg-text-secondary)]">{image || '—'}</code>
|
||||
{containerName ? <>{t('k8s.cicd.container')}<code className="text-[var(--dg-text-secondary)]">{containerName}</code></> : null}
|
||||
</p>
|
||||
<p>{t('kubernetes.cicdwebhookcontent.se067d1')}</p>
|
||||
<p>{t('kubernetes.cicdwebhookcontent.s311998')} <code className="text-[var(--dg-text-secondary)]">image</code> {t('kubernetes.cicdwebhookcontent.s55260c')}</p>
|
||||
<p>{t('kubernetes.cicdwebhookcontent.s4e20ba')} <code className="text-[var(--dg-text-secondary)]">{t('kubernetes.cicdwebhookcontent.s67cc60')}</code></p>
|
||||
<p>{t('k8s.cicd.tipLongTermKey')}</p>
|
||||
<p>{t('k8s.cicd.tipEditImagePrefix')}<code className="text-[var(--dg-text-secondary)]">image</code>{t('k8s.cicd.tipEditImageSuffix')}</p>
|
||||
<p>{t('k8s.cicd.tipBearerPrefix')}<code className="text-[var(--dg-text-secondary)]">Authorization: Bearer <{t('k8s.cicd.tipBearerKey')}></code>{t('k8s.cicd.tipBearerSuffix')}</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
// EditModeContainer.tsx — 编辑模式 Tab 容器,共享 manifest 状态 // Logan.Li
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Container, Settings, Database, Network } from 'lucide-react';
|
||||
import { DeploymentEditBasic } from '../DeploymentEditBasic';
|
||||
import { DeploymentEditContainers } from '../DeploymentEditContainers';
|
||||
import { DeploymentEditStorage } from '../DeploymentEditStorage';
|
||||
import { DeploymentEditAdvanced } from '../DeploymentEditAdvanced';
|
||||
import { DeploymentEditService } from '../DeploymentEditService';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export interface EditModeContainerProps {
|
||||
clusterCode: string;
|
||||
@@ -36,11 +36,11 @@ export function EditModeContainer({ clusterCode, namespace, deploymentName, mani
|
||||
};
|
||||
|
||||
const tabs: Array<{ key: EditTab; label: string; icon: typeof Settings }> = [
|
||||
{ key: 'basic', label: t('deploy.label.basicInfo'), icon: Settings },
|
||||
{ key: 'containers', label: t('kubernetes.editmodecontainer.sd58c2e'), icon: Container },
|
||||
{ key: 'storage', label: t('kubernetes.editmodecontainer.s9ffdac'), icon: Database },
|
||||
{ key: 'advanced', label: t('kubernetes.editmodecontainer.se37075'), icon: Settings },
|
||||
{ key: 'service', label: t('kubernetes.editmodecontainer.s8bdc2d'), icon: Network },
|
||||
{ key: 'basic', label: t('k8s.editMode.basic'), icon: Settings },
|
||||
{ key: 'containers', label: t('k8s.editMode.containers'), icon: Container },
|
||||
{ key: 'storage', label: t('k8s.editMode.storage'), icon: Database },
|
||||
{ key: 'advanced', label: t('k8s.editMode.advanced'), icon: Settings },
|
||||
{ key: 'service', label: t('k8s.editMode.service'), icon: Network },
|
||||
];
|
||||
|
||||
const commonProps = {
|
||||
|
||||
@@ -8,8 +8,8 @@ import { FileText, RefreshCw, Loader2, X } from 'lucide-react';
|
||||
import { kubernetesApi } from '@/api';
|
||||
import { useToast } from '@/hooks/use-toast';
|
||||
import { useUserStore } from '@/store';
|
||||
import type { JsonData } from '@/types/common';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import type { JsonData } from '@/types/common';
|
||||
|
||||
export interface PodLogsModalProps {
|
||||
clusterCode: string;
|
||||
@@ -32,9 +32,9 @@ export function PodLogsModal({ clusterCode, namespace, podName, containers, onCl
|
||||
setLoading(true);
|
||||
try {
|
||||
const res: JsonData = await kubernetesApi.getPodLogs(clusterCode, namespace, podName, tail, container || undefined);
|
||||
setLogs(res?.data?.logs || res?.logs || res || t('kubernetes.podlogsmodal.s4ff3b4'));
|
||||
setLogs(res?.data?.logs || res?.logs || res || t('k8s.podLogs.noLogs'));
|
||||
} catch {
|
||||
setLogs(t('kubernetes.podlogsmodal.sc93f33'));
|
||||
setLogs(t('k8s.podLogs.loadFailed'));
|
||||
} finally { setLoading(false); }
|
||||
};
|
||||
|
||||
@@ -59,7 +59,7 @@ export function PodLogsModal({ clusterCode, namespace, podName, containers, onCl
|
||||
setLogs(buf);
|
||||
}
|
||||
} catch {
|
||||
toast({ title: t('kubernetes.podlogsmodal.s6273c9'), variant: 'destructive' });
|
||||
toast({ title: t('k8s.podLogs.streamInterrupted'), variant: 'destructive' });
|
||||
} finally { setStreaming(false); }
|
||||
};
|
||||
|
||||
@@ -87,14 +87,14 @@ export function PodLogsModal({ clusterCode, namespace, podName, containers, onCl
|
||||
{loading ? <Loader2 className="h-3 w-3 animate-spin" /> : <RefreshCw className="h-3 w-3" />}
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" className="h-7 border-[var(--dg-border)] dg-text-green text-xs" onClick={startStream} disabled={streaming}>
|
||||
{streaming ? t('kubernetes.podlogsmodal.s2d4fb3') : t('monitor.logStreaming')}
|
||||
{streaming ? t('k8s.podLogs.streaming') : t('k8s.podLogs.liveStream')}
|
||||
</Button>
|
||||
<Button variant="ghost" size="icon" className="h-7 w-7 dg-text-secondary" onClick={onClose}><X className="h-4 w-4" /></Button>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 overflow-auto p-3">
|
||||
<pre className="bg-[var(--dg-bg-primary)] rounded p-3 text-xs text-[var(--dg-text-secondary)] font-mono whitespace-pre-wrap max-h-[60vh] overflow-auto">
|
||||
{logs || t('kubernetes.podlogsmodal.s99eac0')}
|
||||
{logs || t('k8s.podLogs.noLogContent')}
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,9 +4,9 @@ import { Button } from '@/components/ui/button';
|
||||
import { Input } from '@/components/ui/input';
|
||||
import { Label } from '@/components/ui/label';
|
||||
import { ArrowRight, Loader2 } from 'lucide-react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { joinImageRef, parseImageRef } from '../image-ref-utils';
|
||||
import { ModalShell } from './ModalShell';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
export interface UpdateImageModalProps {
|
||||
deployment: any;
|
||||
@@ -48,14 +48,14 @@ export function UpdateImageModal({
|
||||
};
|
||||
|
||||
return (
|
||||
<ModalShell title=t('kubernetes.updateimagemodal.s22a2ed') onClose={onClose} size="xl">
|
||||
<ModalShell title={t('k8s.editImage.title')} onClose={onClose} size="xl">
|
||||
<div className="space-y-5">
|
||||
{/* 当前镜像:只读展示完整地址与 Tag // Logan.Li */}
|
||||
<div className="rounded-lg border border-[var(--dg-border)]/80 bg-[var(--dg-bg-tertiary)]/40 p-4 space-y-3">
|
||||
<p className="text-xs font-medium dg-text-secondary">{t('kubernetes.deployment.currentImage')}</p>
|
||||
<p className="text-xs font-medium dg-text-secondary">{t('k8s.editImage.currentImage')}</p>
|
||||
<div className="grid grid-cols-[1fr_180px] gap-3">
|
||||
<div>
|
||||
<Label className="dg-text-muted text-xs">{t('kubernetes.updateimagemodal.sdbe6a6')}</Label>
|
||||
<Label className="dg-text-muted text-xs">{t('k8s.editImage.imageAddress')}</Label>
|
||||
<p
|
||||
className="mt-1.5 text-sm text-[var(--dg-text-primary)] font-mono break-all leading-relaxed bg-[var(--dg-bg-secondary)]/60 rounded-md px-3 py-2.5 min-h-[42px]"
|
||||
title={current.repository || '-'}
|
||||
@@ -64,7 +64,7 @@ export function UpdateImageModal({
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="dg-text-muted text-xs">{t('kubernetes.updateimagemodal.sf08c71')}</Label>
|
||||
<Label className="dg-text-muted text-xs">{t('k8s.editImage.currentTag')}</Label>
|
||||
<p
|
||||
className="mt-1.5 text-sm text-cyan-300 font-mono break-all leading-relaxed bg-[var(--dg-bg-secondary)]/60 rounded-md px-3 py-2.5 min-h-[42px]"
|
||||
title={current.tag || '-'}
|
||||
@@ -74,7 +74,7 @@ export function UpdateImageModal({
|
||||
</div>
|
||||
</div>
|
||||
<p className="text-[11px] dg-text-muted font-mono break-all" title={currentImage}>
|
||||
完整引用:<span className="dg-text-secondary">{currentImage || '-'}</span>
|
||||
{t('k8s.editImage.fullRef')}<span className="dg-text-secondary">{currentImage || '-'}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -84,10 +84,10 @@ export function UpdateImageModal({
|
||||
|
||||
{/* 新镜像:地址与 Tag 分栏编辑 // Logan.Li */}
|
||||
<div className="rounded-lg border border-blue-500/30 bg-blue-500/5 p-4 space-y-3">
|
||||
<p className="text-xs font-medium text-blue-300/90">{t('kubernetes.deployment.newImage')}</p>
|
||||
<p className="text-xs font-medium text-blue-300/90">{t('k8s.editImage.newImage')}</p>
|
||||
<div className="grid grid-cols-[1fr_180px] gap-3">
|
||||
<div>
|
||||
<Label className="dg-text-secondary text-xs">{t('kubernetes.updateimagemodal.sdbe6a6')}</Label>
|
||||
<Label className="dg-text-secondary text-xs">{t('k8s.editImage.imageAddress')}</Label>
|
||||
<Input
|
||||
value={newRepo}
|
||||
onChange={e => {
|
||||
@@ -100,7 +100,7 @@ export function UpdateImageModal({
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label className="dg-text-secondary text-xs">{t('kubernetes.updateimagemodal.s6a38a8')}</Label>
|
||||
<Label className="dg-text-secondary text-xs">{t('k8s.editImage.newTag')}</Label>
|
||||
<Input
|
||||
value={newTag}
|
||||
onChange={e => {
|
||||
@@ -115,7 +115,7 @@ export function UpdateImageModal({
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap items-center gap-2 text-xs">
|
||||
<span className="dg-text-muted">{t('kubernetes.updateimagemodal.sec74e0')}</span>
|
||||
<span className="dg-text-muted">{t('k8s.editImage.tagChange')}</span>
|
||||
<code className="px-2 py-0.5 rounded bg-[var(--dg-bg-tertiary)] dg-text-secondary font-mono">{current.tag}</code>
|
||||
<ArrowRight className="h-3 w-3 dg-text-muted" />
|
||||
<code
|
||||
@@ -126,28 +126,28 @@ export function UpdateImageModal({
|
||||
{newTag.trim() || '-'}
|
||||
</code>
|
||||
{!tagChanged && !repoChanged && (
|
||||
<span className="dg-text-muted">{t('kubernetes.updateimagemodal.s47c8cf')}</span>
|
||||
<span className="dg-text-muted">{t('k8s.editImage.notModified')}</span>
|
||||
)}
|
||||
{repoChanged && !tagChanged && (
|
||||
<span className="dg-text-yellow/80">{t('kubernetes.updateimagemodal.sdb3122')}</span>
|
||||
<span className="dg-text-yellow/80">{t('k8s.editImage.addressChanged')}</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<p className="text-[11px] dg-text-muted font-mono break-all">
|
||||
更新预览:<span className="text-[var(--dg-text-secondary)]">{previewImage || '-'}</span>
|
||||
{t('k8s.editImage.updatePreview')}<span className="text-[var(--dg-text-secondary)]">{previewImage || '-'}</span>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 pt-1">
|
||||
<Button variant="outline" className="border-[var(--dg-border)] dg-text-secondary" onClick={onClose}>
|
||||
取消
|
||||
{t('common.cancel')}
|
||||
</Button>
|
||||
<Button
|
||||
className="bg-blue-600 hover:bg-blue-700"
|
||||
disabled={actionLoading === 'image' || !previewImage.trim() || !hasChanges}
|
||||
onClick={onUpdateImage}
|
||||
>
|
||||
{actionLoading === 'image' ? <Loader2 className="h-4 w-4 animate-spin" /> : i18n.t('kubernetes.deployment.updateImage')}
|
||||
{actionLoading === 'image' ? <Loader2 className="h-4 w-4 animate-spin" /> : t('k8s.editImage.updateImage')}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in new issue
Block a user