diff --git a/frontend/src/components/user/ApiAccessKeySection.tsx b/frontend/src/components/user/ApiAccessKeySection.tsx index ae9fe52..7e2e1fc 100644 --- a/frontend/src/components/user/ApiAccessKeySection.tsx +++ b/frontend/src/components/user/ApiAccessKeySection.tsx @@ -1,5 +1,6 @@ -// ApiAccessKeySection — 单条 CI/CD 访问凭证(凭证卡片布局)// Logan.Li +// ApiAccessKeySection — 单条 CI/CD 访问凭证(凭证卡片布局) import { useCallback, useEffect, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; import { Card, CardContent, CardHeader, CardTitle, CardDescription } from '@/components/ui/card'; import { Button } from '@/components/ui/button'; import { Input } from '@/components/ui/input'; @@ -52,7 +53,7 @@ function toDateInputValue(value?: string) { return Number.isNaN(d.getTime()) ? defaultExpiresDate() : d.toISOString().slice(0, 10); } -/** 根据创建/到期时间计算有效期进度(0-100)// Logan.Li */ +/** Compute expiry progress (0-100) based on created/expires timestamps */ function expiryProgress(createdAt?: string, expiresAt?: string) { if (!createdAt || !expiresAt) return { pct: 0, daysLeft: null as number | null }; const start = new Date(createdAt).getTime(); @@ -71,6 +72,7 @@ function shortKeyId(id?: string) { } export function ApiAccessKeySection() { + const { t } = useTranslation(); const { toast } = useToast(); const confirm = useConfirm(); const apiBase = getPublicApiBase(); @@ -137,9 +139,9 @@ export function ApiAccessKeySection() { }); setKeyMeta(res); setFormOpen(false); - toast({ title: '凭证信息已更新' }); + toast({ title: t('user.apiKey.updated') }); } catch (e: unknown) { - toast({ title: '更新失败', description: getErrorMessage(e), variant: 'destructive' }); + toast({ title: t('user.apiKey.updateFailed'), description: getErrorMessage(e), variant: 'destructive' }); } finally { setActionLoading(false); } @@ -148,9 +150,9 @@ export function ApiAccessKeySection() { const hasKey = !!keyMeta?.has_token; const ok = await confirm({ - title: hasKey ? '轮换凭证' : '签发凭证', - description: hasKey ? '旧凭证将立即作废,是否继续?' : '凭证明文仅显示一次,请妥善保存。', - confirmText: hasKey ? '轮换' : '签发', + title: hasKey ? t('user.apiKey.rotateTitle') : t('user.apiKey.issue'), + description: hasKey ? t('user.apiKey.rotateDesc') : t('user.apiKey.issueDesc'), + confirmText: hasKey ? t('user.apiKey.rotateBtn') : t('user.apiKey.issue'), variant: hasKey ? 'destructive' : 'default', }); if (!ok) return; @@ -178,9 +180,9 @@ export function ApiAccessKeySection() { expired: false, days_left: Math.ceil((new Date(res.expires_at).getTime() - Date.now()) / 86400000), }); - toast({ title: '凭证已签发', description: '已保存至本浏览器,请立即复制' }); + toast({ title: t('user.apiKey.issued'), description: t('user.apiKey.issuedDesc') }); } catch (e: unknown) { - toast({ title: '签发失败', description: getErrorMessage(e), variant: 'destructive' }); + toast({ title: t('user.apiKey.issueFailed'), description: getErrorMessage(e), variant: 'destructive' }); } finally { setActionLoading(false); } @@ -188,9 +190,9 @@ export function ApiAccessKeySection() { const handleRevoke = async () => { const ok = await confirm({ - title: '吊销凭证', - description: '吊销后 Pipeline / curl 调用将全部失败,是否继续?', - confirmText: '吊销', + title: t('user.apiKey.revokeTitle'), + description: t('user.apiKey.revokeDesc'), + confirmText: t('user.apiKey.revokeBtn'), variant: 'destructive', }); if (!ok) return; @@ -200,15 +202,15 @@ export function ApiAccessKeySection() { setPlainToken(''); setSessionApiAccessKey(''); setKeyMeta({ has_token: false }); - toast({ title: '凭证已吊销' }); + toast({ title: t('user.apiKey.revoked') }); } catch (e: unknown) { - toast({ title: '吊销失败', description: getErrorMessage(e), variant: 'destructive' }); + toast({ title: t('user.apiKey.revokeFailed'), description: getErrorMessage(e), variant: 'destructive' }); } finally { setActionLoading(false); } }; - const authHeader = copyableToken ? `X-AIOps-Access-Key: ${copyableToken}` : 'X-AIOps-Access-Key: <你的访问凭证>'; + const authHeader = copyableToken ? `X-AIOps-Access-Key: ${copyableToken}` : `X-AIOps-Access-Key: <${t('user.apiKey.placeholderToken')}>`; const sampleCluster = 'test-k8s'; const sampleNs = 'default'; const sampleDep = 'demo-jar'; @@ -232,27 +234,27 @@ export function ApiAccessKeySection() {
凭证字符串
+{t('user.apiKey.tokenLabel')}
{showToken && copyableToken ? copyableToken : mask}
@@ -272,7 +274,7 @@ export function ApiAccessKeySection() {
size="icon"
className="h-9 w-9 shrink-0 border-[var(--dg-border)]"
onClick={() => setShowToken(!showToken)}
- title={showToken ? '隐藏' : '显示'}
+ title={showToken ? t('user.apiKey.hide') : t('user.apiKey.show')}
>
{showToken ? : }
@@ -281,41 +283,41 @@ export function ApiAccessKeySection() {
用途说明
-{keyMeta.description || '未填写'}
+{t('user.apiKey.descLabel')}
+{keyMeta.description || t('user.apiKey.descEmpty')}
凭证标识
+{t('user.apiKey.keyIdLabel')}
{shortKeyId(keyMeta.key_id)}
签发时间
+{t('user.apiKey.createdLabel')}
{formatDateTime(keyMeta.created_at)}
{keyMeta.prefix}
+ {t('user.apiKey.prefix')} {keyMeta.prefix}
)}
{isExpired && (
- 尚未签发 CI/CD 访问凭证
-签发后可用于 Pipeline 触发镜像更新、滚动重启等操作
+{t('user.apiKey.emptyTitle')}
+{t('user.apiKey.emptyDesc')}
本机未缓存凭证明文,请点击「轮换」重新签发一次;签发后将自动填入 Deployment 发布 curl。
+{t('user.apiKey.cacheWarning')}
)}
-