fix(U20): ESLint static-components 清零 + CredDetailDialog 内联组件修复 + i18n 损坏修复

- CredDetailDialog.tsx: Field 内联组件提取为模块级 CredField (react-hooks/static-components 23→0)
- 修复 8 处被批量正则损坏的 i18n.t() 调用 (i18n.t('>名称:</span>') → 语义化键)
- 6 处硬编码中文清零 (凭据详情/密钥数据/无/创建时间/更新时间/安全提示)
- 新增 deploy.cred.sensitiveWarn i18n 键 (zh/en 对齐)
- ESLint warnings 66→43 (-35%), errors=0, any=0, unused=0
- tsc -b=0, npm build✓ (17.29s), go build=0, 17/17 测试通过
This commit is contained in:
attacker committed 2026-07-11 10:22:34 +08:00
1 parent bb2b50276a
commit f953ba3248
6 files changed
+110 -76

No files matched your search

+1 -1
View File
@@ -137,7 +137,7 @@
|------|------|:----------:| |------|------|:----------:|
| 前端未使用变量/导入(ESLint no-unused-vars) | ~~218 处~~ → **0 处** | ~~P1~~ ✅ done | | 前端未使用变量/导入(ESLint no-unused-vars) | ~~218 处~~ → **0 处** | ~~P1~~ ✅ done |
| 前端 console.log/console.error | ~~93 处~~ → **3 处** | ~~P1~~ ✅ done | | 前端 console.log/console.error | ~~93 处~~ → **3 处** | ~~P1~~ ✅ done |
| 前端 React Hooks 关键规则(exhaustive-deps/set-state-in-effect/purity/immutability 等 6 大规则) | ~~82 处回归~~ → **0 处**(U12 修复 i18n 全量改造引入的回归) | ~~P1~~ ✅ done (U12) | || 前端 React Hooks 关键规则(exhaustive-deps/set-state-in-effect/purity/immutability/static-components 等 7 大规则) | ~~82 处回归~~ → **0 处**(U12 修复 i18n 全量改造引入的回归 + U20 修复 CredDetailDialog 内联组件 static-components 23→0) | ~~P1~~ ✅ done |
| 后端 `_ =` 忽略错误 | ~~13 处(3 处中风险)~~ → **controller/middleware 层 DB 写入零忽略**(Q4+Q5 全量治理) | ~~P2~~ ✅ done | | 后端 `_ =` 忽略错误 | ~~13 处(3 处中风险)~~ → **controller/middleware 层 DB 写入零忽略**(Q4+Q5 全量治理) | ~~P2~~ ✅ done |
| 前端硬编码内网 IP(10.10.10.75 等) | 6+ 处 | P2 | | 前端硬编码内网 IP(10.10.10.75 等) | 6+ 处 | P2 |
| 后端告警引擎分布式安全 | ✅ Redis 分布式锁(SetNX + 60s TTL) | 后端 | ~~P2~~ done | | 后端告警引擎分布式安全 | ✅ Redis 分布式锁(SetNX + 60s TTL) | 后端 | ~~P2~~ done |
+1
View File
@@ -513,6 +513,7 @@ services/api.ts (1324L)
| Q38 | 前端巨型组件拆分(UnifiedQueryPanel 529L→353L (-33%),提取 unified-query/useLogQueryEngine.ts 295L 查询执行引擎 Hook + useLogExport.ts 62L 导出/复制 Hook,全项目最后一个 ≥500L 业务组件清零) | P0 | **done** | | Q38 | 前端巨型组件拆分(UnifiedQueryPanel 529L→353L (-33%),提取 unified-query/useLogQueryEngine.ts 295L 查询执行引擎 Hook + useLogExport.ts 62L 导出/复制 Hook,全项目最后一个 ≥500L 业务组件清零) | P0 | **done** |
| U17 | K8s 残余组件 i18n 补全(NodeDetailPage 16 处硬编码中文清零 + 8 个 hash 键替换为语义化 k8s.nodeDetail.* 键 + DeploymentWorkload 12 处 toast/confirm 硬编码中文清零,zh/en 7564→7597 +33 键对齐) | P3 | **done** | | U17 | K8s 残余组件 i18n 补全(NodeDetailPage 16 处硬编码中文清零 + 8 个 hash 键替换为语义化 k8s.nodeDetail.* 键 + DeploymentWorkload 12 处 toast/confirm 硬编码中文清零,zh/en 7564→7597 +33 键对齐) | P3 | **done** |
| U19 | i18n hash 键清理(删除 866 个死 hash 键 + 重命名 21 个高频 live hash 键为语义化键名,zh/en 7597→6731 keys 对齐,文件 328KB→276KB (-16%),tsc -b=0,npm build✓,ESLint=0/66/0,17/17 测试通过) | P3 | **done** | | U19 | i18n hash 键清理(删除 866 个死 hash 键 + 重命名 21 个高频 live hash 键为语义化键名,zh/en 7597→6731 keys 对齐,文件 328KB→276KB (-16%),tsc -b=0,npm build✓,ESLint=0/66/0,17/17 测试通过) | P3 | **done** |
| U20 | ESLint static-components 清零 + CredDetailDialog 内联组件修复 + i18n 批量迁移损坏修复(CredDetailDialog.tsx `Field` 内联组件提取为模块级 `CredField` — 23 处 react-hooks/static-components 警告清零;修复 8 处被批量正则损坏的 `i18n.t()` 调用(`i18n.t('>名称:</span>')` 等 → 语义化键);6 处硬编码中文清零;新增 `deploy.cred.sensitiveWarn` 键;ESLint warnings 66→43 (-35%),tsc -b=0,npm build✓ (17.29s),17/17 测试通过) | P3 | **done** |
--- ---
+17
View File
@@ -1502,3 +1502,20 @@ curl -s -o /dev/null -w "%{http_code}" -H "Authorization: Bearer ${TOKEN}" "http
- [x] Docker 部署 healthy,前端页面正常加载(HTTP 200) - [x] Docker 部署 healthy,前端页面正常加载(HTTP 200)
- [x] Pod 日志查看器功能不变(容器选择/行数限制/previous/sinceTime/关键字过滤+高亮/下载/刷新/实时流/暂停继续/全屏切换全部正常) - [x] Pod 日志查看器功能不变(容器选择/行数限制/previous/sinceTime/关键字过滤+高亮/下载/刷新/实时流/暂停继续/全屏切换全部正常)
---
## U20: ESLint static-components 清零 + CredDetailDialog 内联组件修复 + i18n 损坏修复 [done]
### 通过标准
- [x] `react-hooks/static-components` 警告从 23 降至 **0**(CredDetailDialog.tsx `Field` 内联组件提取为模块级 `CredField`)
- [x] ESLint warnings 从 66 降至 **43**(-35%,全部剩余为 react-refresh/only-export-components 架构性约束 + 1 个 @tanstack/react-virtual 兼容性)
- [x] ESLint errors 保持 **0**
- [x] 修复 8 处被批量正则损坏的 `i18n.t()` 调用(`i18n.t('>名称:</span>')` 等 → 语义化键如 `common.name`、`common.createdAt`)
- [x] 6 处硬编码中文清零(凭据详情、密钥数据、无、创建时间、更新时间、安全提示)
- [x] 新增 `deploy.cred.sensitiveWarn` i18n 键(zh/en 对齐)
- [x] `tsc -b` 零错误
- [x] `npm run build` 零错误(✓ built in 17.29s)
- [x] `go build` 零错误
- [x] 17/17 集成回归测试通过(零回归)
- [x] Docker 部署 healthy
@@ -19,7 +19,52 @@ export interface CredDetailDialogProps {
credId: number | null; credId: number | null;
} }
// 凭据详情弹窗 // Logan.Li // --- Module-level Field component (avoids remount on parent re-render) ---
interface CredFieldProps {
label: string;
value: unknown;
sensitive?: boolean;
fieldKey?: string;
showMap: Record<string, boolean>;
onToggle: (key: string) => void;
onCopy: (val: string) => void;
}
function CredField({ label, value, sensitive, fieldKey, showMap, onToggle, onCopy }: CredFieldProps) {
if (value === undefined || value === null || value === '') return null;
const isLong = typeof value === 'string' && value.length > 80;
const show = fieldKey ? showMap[fieldKey] : false;
return (
<div className="mb-3">
<div className="flex items-center gap-2 text-xs text-[var(--dg-text-muted)] mb-1">
<Lock className="h-3 w-3" />{label}
</div>
<div className="flex gap-1">
{isLong ? (
<textarea readOnly value={sensitive && !show ? '••••••••' : String(value)}
className="flex-1 rounded-md bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] text-[var(--dg-text-primary)] p-2 text-xs font-mono resize-none"
rows={4} />
) : (
<Input readOnly value={sensitive && !show ? '••••••••' : String(value)}
className="flex-1 bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] text-[var(--dg-text-primary)] font-mono text-xs" />
)}
<div className="flex flex-col gap-0.5 shrink-0">
{sensitive && (
<Button variant="ghost" size="icon" className="h-7 w-7" onClick={() => onToggle(fieldKey!)}>
{show ? <EyeOff className="h-3 w-3" /> : <Eye className="h-3 w-3" />}
</Button>
)}
<Button variant="ghost" size="icon" className="h-7 w-7" onClick={() => onCopy(String(value))}>
<Copy className="h-3 w-3" />
</Button>
</div>
</div>
</div>
);
}
// 凭据详情弹窗
export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProps) { export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProps) {
const [showMap, setShowMap] = useState<Record<string, boolean>>({}); const [showMap, setShowMap] = useState<Record<string, boolean>>({});
const { data: detail, isLoading: loading } = useCredentialDetail(credId, open); const { data: detail, isLoading: loading } = useCredentialDetail(credId, open);
@@ -33,38 +78,7 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
const cfg = TYPE_CONFIG[st]; const cfg = TYPE_CONFIG[st];
const content = (detail as Record<string, unknown>)?.content as Record<string, unknown> || {}; const content = (detail as Record<string, unknown>)?.content as Record<string, unknown> || {};
const Field = ({ label, value, sensitive, fieldKey }: { label: string; value: unknown; sensitive?: boolean; fieldKey?: string }) => { const fieldProps = { showMap, onToggle: toggleShow, onCopy: copyValue };
if (value === undefined || value === null || value === '') return null;
const isLong = typeof value === 'string' && value.length > 80;
const show = fieldKey ? showMap[fieldKey] : false;
return (
<div className="mb-3">
<div className="flex items-center gap-2 text-xs text-[var(--dg-text-muted)] mb-1">
<Lock className="h-3 w-3" />{label}
</div>
<div className="flex gap-1">
{isLong ? (
<textarea readOnly value={sensitive && !show ? '••••••••' : String(value)}
className="flex-1 rounded-md bg-[var(--dg-bg-tertiary)] border border-[var(--dg-border)] text-[var(--dg-text-primary)] p-2 text-xs font-mono resize-none"
rows={4} />
) : (
<Input readOnly value={sensitive && !show ? '••••••••' : String(value)}
className="flex-1 bg-[var(--dg-bg-tertiary)] border-[var(--dg-border)] text-[var(--dg-text-primary)] font-mono text-xs" />
)}
<div className="flex flex-col gap-0.5 shrink-0">
{sensitive && (
<Button variant="ghost" size="icon" className="h-7 w-7" onClick={() => toggleShow(fieldKey!)}>
{show ? <EyeOff className="h-3 w-3" /> : <Eye className="h-3 w-3" />}
</Button>
)}
<Button variant="ghost" size="icon" className="h-7 w-7" onClick={() => copyValue(String(value))}>
<Copy className="h-3 w-3" />
</Button>
</div>
</div>
</div>
);
};
const detailRecord = detail as Record<string, unknown> | undefined; const detailRecord = detail as Record<string, unknown> | undefined;
@@ -74,20 +88,20 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
<DialogHeader> <DialogHeader>
<DialogTitle className="text-[var(--dg-text-primary)] flex items-center gap-2"> <DialogTitle className="text-[var(--dg-text-primary)] flex items-center gap-2">
{cfg ? <cfg.icon className={`h-5 w-5 ${cfg.color}`} /> : <Key className="h-5 w-5 text-[var(--dg-text-muted)]" />} {cfg ? <cfg.icon className={`h-5 w-5 ${cfg.color}`} /> : <Key className="h-5 w-5 text-[var(--dg-text-muted)]" />}
凭据详情 {i18n.t('deploy.cred.credDetail')}
</DialogTitle> </DialogTitle>
</DialogHeader> </DialogHeader>
{loading ? ( {loading ? (
<div className="text-center py-8 text-[var(--dg-text-muted)]"> {i18n.t('monitor.logPanel.logResults.loading')} </div> <div className="text-center py-8 text-[var(--dg-text-muted)]"> {i18n.t('monitor.logPanel.logResults.loading')} </div>
) : detail ? ( ) : detail ? (
<div className="space-y-4"> <div className="space-y-4">
{/* 基本信息 // Logan.Li */} {/* 基本信息 */}
<div className="grid grid-cols-2 gap-3 text-sm"> <div className="grid grid-cols-2 gap-3 text-sm">
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('>名称:</span><span className=')} </span><span className="text-[var(--dg-text-primary)] font-medium">{detailRecord?.name as string}</span></div> <div><span className="text-[var(--dg-text-muted)]">{i18n.t('common.name')}:</span><span className="text-[var(--dg-text-primary)] font-medium">{detailRecord?.name as string}</span></div>
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('>名称:</span><span className=')} </span> <div><span className="text-[var(--dg-text-muted)]">{i18n.t('deploy.cred.credType')}:</span>
<Badge variant="outline" className={`text-xs ml-1 ${TYPE_BADGE_CLASS[st] || ''}`}>{cfg?.label || st}</Badge> <Badge variant="outline" className={`text-xs ml-1 ${TYPE_BADGE_CLASS[st] || ''}`}>{cfg?.label || st}</Badge>
</div> </div>
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('approval.detail.statusLabel')} </span> <div><span className="text-[var(--dg-text-muted)]">{i18n.t('approval.detail.statusLabel')}:</span>
{detailRecord?.is_active {detailRecord?.is_active
? <Badge className="bg-green-500/20 dg-text-green text-xs ml-1"><CheckCircle2 className="h-3 w-3 mr-0.5" /> {i18n.t('system.userActive')} </Badge> ? <Badge className="bg-green-500/20 dg-text-green text-xs ml-1"><CheckCircle2 className="h-3 w-3 mr-0.5" /> {i18n.t('system.userActive')} </Badge>
: <Badge className="bg-red-500/20 dg-text-red text-xs ml-1"><XCircle className="h-3 w-3 mr-0.5" /> {i18n.t('system.userInactive')} </Badge>} : <Badge className="bg-red-500/20 dg-text-red text-xs ml-1"><XCircle className="h-3 w-3 mr-0.5" /> {i18n.t('system.userInactive')} </Badge>}
@@ -96,72 +110,72 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
)} )}
</div> </div>
<div className="col-span-2 cursor-pointer" onClick={() => copyValue((detailRecord?.env_prefix as string) || '')}> <div className="col-span-2 cursor-pointer" onClick={() => copyValue((detailRecord?.env_prefix as string) || '')}>
<span className="text-[var(--dg-text-muted)]"> {i18n.t('deploy.cred.refIdLabel')} </span> <span className="text-[var(--dg-text-muted)]">{i18n.t('deploy.cred.refIdLabel')}</span>
<code className="text-[var(--dg-blue)] font-mono text-xs">{detailRecord?.env_prefix as string || '无'}</code> <code className="text-[var(--dg-blue)] font-mono text-xs">{detailRecord?.env_prefix as string || i18n.t('common.none')}</code>
<Copy className="h-3 w-3 inline ml-1 text-[var(--dg-text-muted)]" /> <Copy className="h-3 w-3 inline ml-1 text-[var(--dg-text-muted)]" />
</div> </div>
{(detailRecord?.tags as string[])?.length > 0 && ( {(detailRecord?.tags as string[])?.length > 0 && (
<div className="col-span-2"> <div className="col-span-2">
<span className="text-[var(--dg-text-muted)]"> {i18n.t('无')} </span> <span className="text-[var(--dg-text-muted)]">{i18n.t('common.tag')}:</span>
{(detailRecord?.tags as string[]).map((t: string) => ( {(detailRecord?.tags as string[]).map((t: string) => (
<Badge key={t} variant="outline" className="text-xs ml-1 border-[var(--dg-border)]">{t}</Badge> <Badge key={t} variant="outline" className="text-xs ml-1 border-[var(--dg-border)]">{t}</Badge>
))} ))}
</div> </div>
)} )}
<div className="col-span-2"><span className="text-[var(--dg-text-muted)]"> {i18n.t('无')} </span><span className="text-[var(--dg-text-secondary)]">{(detailRecord?.description as string) || '无'}</span></div> <div className="col-span-2"><span className="text-[var(--dg-text-muted)]">{i18n.t('common.description')}:</span><span className="text-[var(--dg-text-secondary)]">{(detailRecord?.description as string) || i18n.t('common.none')}</span></div>
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('>创建:</span><span className=')} </span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.created_at as string).toLocaleString()}</span></div> <div><span className="text-[var(--dg-text-muted)]">{i18n.t('common.createdAt')}:</span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.created_at as string).toLocaleString()}</span></div>
<div><span className="text-[var(--dg-text-muted)]"> {i18n.t('>创建:</span><span className=')} </span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.updated_at as string).toLocaleString()}</span></div> <div><span className="text-[var(--dg-text-muted)]">{i18n.t('common.updatedAt')}:</span><span className="text-[var(--dg-text-secondary)] text-xs">{new Date(detailRecord?.updated_at as string).toLocaleString()}</span></div>
</div> </div>
{/* 密钥数据 // Logan.Li */} {/* 密钥数据 */}
<div className="border-t border-[var(--dg-border)] pt-3"> <div className="border-t border-[var(--dg-border)] pt-3">
<div className="flex items-center gap-2 text-sm text-[var(--dg-text-primary)] font-medium mb-3"> <div className="flex items-center gap-2 text-sm text-[var(--dg-text-primary)] font-medium mb-3">
<Key className="h-4 w-4 text-yellow-500" />密钥数据 <Key className="h-4 w-4 text-yellow-500" />{i18n.t('deploy.cred.credData')}
</div> </div>
<div className="p-3 rounded-md bg-yellow-500/5 border border-yellow-500/20 mb-3"> <div className="p-3 rounded-md bg-yellow-500/5 border border-yellow-500/20 mb-3">
<p className="text-xs dg-text-yellow/80"> {i18n.t('无')} </p> <p className="text-xs dg-text-yellow/80">{i18n.t('deploy.cred.sensitiveWarn')}</p>
</div> </div>
{st === 'ssh' && <> {st === 'ssh' && <>
<Field label={i18n.t('SSH 用户')} value={content.ssh_user} /> <CredField label={i18n.t('deploy.cred.form.sshUser')} value={content.ssh_user} {...fieldProps} />
<Field label={i18n.t('SSH 用户')} value={content.ssh_port} /> <CredField label={i18n.t('deploy.cred.form.sshPort')} value={content.ssh_port} {...fieldProps} />
<Field label={i18n.t('system.sshPassword')} value={content.password} sensitive fieldKey="ssh_password" /> <CredField label={i18n.t('system.sshPassword')} value={content.password} sensitive fieldKey="ssh_password" {...fieldProps} />
<Field label={i18n.t('system.sshPrivateKey')} value={content.private_key} sensitive fieldKey="ssh_private_key" /> <CredField label={i18n.t('system.sshPrivateKey')} value={content.private_key} sensitive fieldKey="ssh_private_key" {...fieldProps} />
<Field label={i18n.t('system.sshPublicKey')} value={content.public_key} fieldKey="ssh_public_key" /> <CredField label={i18n.t('system.sshPublicKey')} value={content.public_key} fieldKey="ssh_public_key" {...fieldProps} />
</>} </>}
{st === 'docker' && <> {st === 'docker' && <>
<Field label={i18n.t('deploy.form.registryAddr')} value={content.server} /> <CredField label={i18n.t('deploy.cred.form.registryAddr')} value={content.server} {...fieldProps} />
<Field label={i18n.t('system.userName')} value={content.username} /> <CredField label={i18n.t('system.userName')} value={content.username} {...fieldProps} />
<Field label={i18n.t('system.passwordLabel')} value={content.password} sensitive fieldKey="docker_password" /> <CredField label={i18n.t('system.passwordLabel')} value={content.password} sensitive fieldKey="docker_password" {...fieldProps} />
</>} </>}
{st === 'tls' && <> {st === 'tls' && <>
<Field label={i18n.t('私钥')} value={content.cert} sensitive fieldKey="tls_cert" /> <CredField label={i18n.t('deploy.cred.form.certPem')} value={content.cert} sensitive fieldKey="tls_cert" {...fieldProps} />
<Field label={i18n.t('system.sshPrivateKey')} value={content.key} sensitive fieldKey="tls_key" /> <CredField label={i18n.t('deploy.cred.form.keyPem')} value={content.key} sensitive fieldKey="tls_key" {...fieldProps} />
<Field label={i18n.t('数据库类型')} value={content.ca} sensitive fieldKey="tls_ca" /> <CredField label={i18n.t('deploy.cred.form.caCert')} value={content.ca} sensitive fieldKey="tls_ca" {...fieldProps} />
</>} </>}
{st === 'aksk' && <> {st === 'aksk' && <>
<Field label="Access Key ID" value={content.access_key} /> <CredField label="Access Key ID" value={content.access_key} {...fieldProps} />
<Field label="Secret Access Key" value={content.secret_key} sensitive fieldKey="aksk_secret_key" /> <CredField label="Secret Access Key" value={content.secret_key} sensitive fieldKey="aksk_secret_key" {...fieldProps} />
</>} </>}
{st === 'database' && <> {st === 'database' && <>
<Field label={i18n.t('数据库类型')} value={String(content.db_type || '').toUpperCase()} /> <CredField label={i18n.t('deploy.cred.form.dbType')} value={String(content.db_type || '').toUpperCase()} {...fieldProps} />
<Field label={i18n.t('agent.agentHost')} value={content.host} /> <CredField label={i18n.t('deploy.cred.form.host')} value={content.host} {...fieldProps} />
<Field label={i18n.t('system.ldapPort')} value={content.port} /> <CredField label={i18n.t('system.ldapPort')} value={content.port} {...fieldProps} />
<Field label={i18n.t('数据库类型')} value={content.db_name} /> <CredField label={i18n.t('deploy.cred.form.dbName')} value={content.db_name} {...fieldProps} />
<Field label={i18n.t('system.userName')} value={content.username} /> <CredField label={i18n.t('system.userName')} value={content.username} {...fieldProps} />
<Field label={i18n.t('system.passwordLabel')} value={content.password} sensitive fieldKey="db_password" /> <CredField label={i18n.t('system.passwordLabel')} value={content.password} sensitive fieldKey="db_password" {...fieldProps} />
</>} </>}
{st === 'api' && <> {st === 'api' && <>
<Field label="API Key" value={content.api_key} sensitive fieldKey="api_key" /> <CredField label={i18n.t('deploy.cred.form.apiKeyToken')} value={content.api_key} sensitive fieldKey="api_key" {...fieldProps} />
<Field label={i18n.t('数据库类型')} value={content.endpoint} /> <CredField label={i18n.t('deploy.cred.form.apiEndpoint')} value={content.endpoint} {...fieldProps} />
</>} </>}
{st === 'generic' && <> {st === 'generic' && <>
<Field label="Key" value={content.generic_key} /> <CredField label="Key" value={content.generic_key} {...fieldProps} />
<Field label="Value" value={content.generic_value} sensitive fieldKey="generic_value" /> <CredField label="Value" value={content.generic_value} sensitive fieldKey="generic_value" {...fieldProps} />
</>} </>}
</div> </div>
{/* 引用提示 // Logan.Li */} {/* 引用提示 */}
<div className="border-t border-[var(--dg-border)] pt-3"> <div className="border-t border-[var(--dg-border)] pt-3">
<div className="text-xs text-[var(--dg-text-muted)] mb-2"> {i18n.t('deploy.cred.refHint')} </div> <div className="text-xs text-[var(--dg-text-muted)] mb-2"> {i18n.t('deploy.cred.refHint')} </div>
<code className="text-xs bg-[var(--dg-bg-tertiary)] px-3 py-1.5 rounded block text-[var(--dg-blue)]"> <code className="text-xs bg-[var(--dg-bg-tertiary)] px-3 py-1.5 rounded block text-[var(--dg-blue)]">
@@ -173,9 +187,9 @@ export function CredDetailDialog({ open, onClose, credId }: CredDetailDialogProp
<div className="text-center py-8 text-[var(--dg-text-muted)]"> {i18n.t('deploy.cred.noCredData')} </div> <div className="text-center py-8 text-[var(--dg-text-muted)]"> {i18n.t('deploy.cred.noCredData')} </div>
)} )}
<DialogFooter> <DialogFooter>
<Button variant="outline" onClick={onClose}> {i18n.t('agent.portClosed')} </Button> <Button variant="outline" onClick={onClose}> {i18n.t('common.close')} </Button>
</DialogFooter> </DialogFooter>
</DialogContent> </DialogContent>
</Dialog> </Dialog>
); );
} }
+2 -1
View File
@@ -1736,7 +1736,8 @@
"created": "Created", "created": "Created",
"operationFailed": "Operation failed", "operationFailed": "Operation failed",
"tagsLabel": "Tags" "tagsLabel": "Tags"
} },
"sensitiveWarn": "Please keep sensitive information safe"
}, },
"release": { "release": {
"title": "Application Release", "title": "Application Release",
+2 -1
View File
@@ -1736,7 +1736,8 @@
"created": "已创建", "created": "已创建",
"operationFailed": "操作失败", "operationFailed": "操作失败",
"tagsLabel": "标签" "tagsLabel": "标签"
} },
"sensitiveWarn": "敏感信息请妥善保管"
}, },
"release": { "release": {
"title": "应用发布", "title": "应用发布",