fix(settings): 日志保留时间移出顶部并紧凑化
CI / Backend (go vet + test) (push) Canceled after 0s
CI / Frontend (lint + build + test) (push) Canceled after 0s

通用配置卡内顺序改为 主题 → 语言 → 日志保留时间;保留时间从嵌套整卡
压缩为单行分区(标签 + 两个数字输入 + 内联保存),与主题/语言分区同族,
删去 desc 与两条 hint 冗余文案(中英同步)。
This commit is contained in:
opsx committed 2026-10-29 13:06:31 +08:00
1 parent cddd60045c
commit 231fa8e774
4 files changed
+36 -57

No files matched your search

+1 -4
View File
@@ -3,11 +3,8 @@
export default { export default {
retention: { retention: {
title: 'Log retention', title: 'Log retention',
desc: 'How long the platform keeps its own records. Loki log retention itself is configured per deployment (Component Deploy → Retention).', alertLabel: 'Alert history (days)',
alertLabel: 'Alert delivery history (days)',
alertHint: 'Expired records are purged automatically; default 7 days',
auditLabel: 'Audit logs (days)', auditLabel: 'Audit logs (days)',
auditHint: '90–180 days recommended for compliance',
save: 'Save', save: 'Save',
saving: 'Saving…', saving: 'Saving…',
saved: 'Retention saved; expired records purged', saved: 'Retention saved; expired records purged',
+1 -4
View File
@@ -3,11 +3,8 @@
export default { export default {
retention: { retention: {
title: '日志保留时间', title: '日志保留时间',
desc: '平台自身数据的保留期。注意:Loki 日志本身的保留期在「组件部署 → 保留策略」里配置。', alertLabel: '告警历史(天)',
alertLabel: '告警发送历史(天)',
alertHint: '过期记录自动清理,默认 7 天',
auditLabel: '审计日志(天)', auditLabel: '审计日志(天)',
auditHint: '合规场景建议 90~180 天',
save: '保存', save: '保存',
saving: '保存中…', saving: '保存中…',
saved: '保留策略已保存,过期数据已清理', saved: '保留策略已保存,过期数据已清理',
@@ -2,7 +2,6 @@ import { memo, useCallback, useEffect, useState } from 'react'
import { useTranslation } from 'react-i18next' import { useTranslation } from 'react-i18next'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input' import { Input } from '@/components/ui/input'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { systemApi, type RetentionSettings } from '@/api/system' import { systemApi, type RetentionSettings } from '@/api/system'
import { toast } from 'sonner' import { toast } from 'sonner'
@@ -47,53 +46,39 @@ export const RetentionSection = memo(function RetentionSection() {
} }
}, [settings, t]) }, [settings, t])
// 紧凑单行分区(与主题/语言同族):标签 + 两个数字输入 + 内联保存,不再嵌套整卡
return ( return (
<Card> <div className="flex flex-wrap items-center gap-x-4 gap-y-2 border-t border-border pt-3">
<CardHeader className="pb-3"> <span className="min-w-14 shrink-0 text-sm text-muted-foreground">{t('retention.title')}</span>
<CardTitle className="text-base">{t('retention.title')}</CardTitle> <label className="flex items-center gap-1.5 text-xs text-muted-foreground" htmlFor="retention-alert">
<p className="text-xs text-muted-foreground">{t('retention.desc')}</p> {t('retention.alertLabel')}
</CardHeader> <Input
<CardContent className="space-y-4"> id="retention-alert"
<div className="grid grid-cols-1 gap-4 sm:grid-cols-2"> type="number"
<div className="flex flex-col"> min={1}
<label className="text-sm font-medium" htmlFor="retention-alert"> max={365}
{t('retention.alertLabel')} className="h-8 w-20"
</label> disabled={loading}
<Input value={settings.alertDeliveryDays}
id="retention-alert" onChange={e => setSettings(s => ({ ...s, alertDeliveryDays: Number(e.target.value) || 0 }))}
type="number" />
min={1} </label>
max={365} <label className="flex items-center gap-1.5 text-xs text-muted-foreground" htmlFor="retention-audit">
className="mt-1" {t('retention.auditLabel')}
disabled={loading} <Input
value={settings.alertDeliveryDays} id="retention-audit"
onChange={e => setSettings(s => ({ ...s, alertDeliveryDays: Number(e.target.value) || 0 }))} type="number"
/> min={1}
<p className="mt-1 min-h-4 text-xs text-muted-foreground">{t('retention.alertHint')}</p> max={3650}
</div> className="h-8 w-20"
<div className="flex flex-col"> disabled={loading}
<label className="text-sm font-medium" htmlFor="retention-audit"> value={settings.auditLogDays}
{t('retention.auditLabel')} onChange={e => setSettings(s => ({ ...s, auditLogDays: Number(e.target.value) || 0 }))}
</label> />
<Input </label>
id="retention-audit" <Button size="sm" variant="outline" className="ml-auto" onClick={() => void save()} disabled={saving || loading}>
type="number" {saving ? t('retention.saving') : t('retention.save')}
min={1} </Button>
max={3650} </div>
className="mt-1"
disabled={loading}
value={settings.auditLogDays}
onChange={e => setSettings(s => ({ ...s, auditLogDays: Number(e.target.value) || 0 }))}
/>
<p className="mt-1 min-h-4 text-xs text-muted-foreground">{t('retention.auditHint')}</p>
</div>
</div>
<div className="flex justify-end">
<Button onClick={() => void save()} disabled={saving || loading}>
{saving ? t('retention.saving') : t('retention.save')}
</Button>
</div>
</CardContent>
</Card>
) )
}) })
+1 -1
View File
@@ -81,9 +81,9 @@ const SettingsPage = memo(function SettingsPage() {
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent className="space-y-3"> <CardContent className="space-y-3">
<RetentionSection />
<ThemeSection /> <ThemeSection />
<LanguageSection /> <LanguageSection />
<RetentionSection />
</CardContent> </CardContent>
</Card> </Card>