fix(web): add knowledge base quality rail
This commit is contained in:
@@ -1418,6 +1418,16 @@
|
||||
"categoryDistribution": "分類分佈",
|
||||
"categoryOther": "其他分類"
|
||||
},
|
||||
"quality": {
|
||||
"title": "資料品質軌道",
|
||||
"scope": "目前列表",
|
||||
"reviewBacklog": "待審核",
|
||||
"freshWithin7d": "7 天內更新",
|
||||
"incidentLinked": "事故關聯",
|
||||
"signalRich": "訊號完整",
|
||||
"playbookLinked": "Playbook 關聯",
|
||||
"countOfLoaded": "{count} / {total}"
|
||||
},
|
||||
"noResults": "找不到相關知識條目",
|
||||
"createEntry": "新增條目",
|
||||
"viewCount": "瀏覽",
|
||||
|
||||
@@ -1418,6 +1418,16 @@
|
||||
"categoryDistribution": "分類分佈",
|
||||
"categoryOther": "其他分類"
|
||||
},
|
||||
"quality": {
|
||||
"title": "資料品質軌道",
|
||||
"scope": "目前列表",
|
||||
"reviewBacklog": "待審核",
|
||||
"freshWithin7d": "7 天內更新",
|
||||
"incidentLinked": "事故關聯",
|
||||
"signalRich": "訊號完整",
|
||||
"playbookLinked": "Playbook 關聯",
|
||||
"countOfLoaded": "{count} / {total}"
|
||||
},
|
||||
"noResults": "找不到相關知識條目",
|
||||
"createEntry": "新增條目",
|
||||
"viewCount": "瀏覽",
|
||||
|
||||
@@ -390,6 +390,29 @@ export default function KnowledgeBasePage({
|
||||
]
|
||||
}, [categories, totalCount])
|
||||
|
||||
const qualityRows = useMemo(() => {
|
||||
const loaded = displayedEntries.length
|
||||
const now = Date.now()
|
||||
const freshWindowMs = 7 * 24 * 60 * 60 * 1000
|
||||
const pct = (count: number) => loaded > 0 ? Math.round((count / loaded) * 100) : 0
|
||||
const reviewBacklog = displayedEntries.filter(entry => entry.status === 'draft' || entry.status === 'review').length
|
||||
const freshWithin7d = displayedEntries.filter(entry => {
|
||||
const updatedAt = Date.parse(entry.updated_at)
|
||||
return Number.isFinite(updatedAt) && now - updatedAt <= freshWindowMs
|
||||
}).length
|
||||
const incidentLinked = displayedEntries.filter(entry => Boolean(entry.related_incident_id)).length
|
||||
const playbookLinked = displayedEntries.filter(entry => Boolean(entry.related_playbook_id)).length
|
||||
const signalRich = displayedEntries.filter(entry => getSignalTags(entry).length > 0).length
|
||||
|
||||
return [
|
||||
{ key: 'reviewBacklog', count: reviewBacklog, pct: pct(reviewBacklog), tone: 'bg-status-warning' },
|
||||
{ key: 'freshWithin7d', count: freshWithin7d, pct: pct(freshWithin7d), tone: 'bg-status-healthy' },
|
||||
{ key: 'incidentLinked', count: incidentLinked, pct: pct(incidentLinked), tone: 'bg-claw-blue' },
|
||||
{ key: 'signalRich', count: signalRich, pct: pct(signalRich), tone: 'bg-purple-500' },
|
||||
{ key: 'playbookLinked', count: playbookLinked, pct: pct(playbookLinked), tone: 'bg-nothing-gray-400' },
|
||||
] as const
|
||||
}, [displayedEntries])
|
||||
|
||||
const content = (
|
||||
<div className="flex h-[calc(100vh-64px)] flex-col lg:flex-row">
|
||||
|
||||
@@ -542,6 +565,31 @@ export default function KnowledgeBasePage({
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-3 rounded-md border border-nothing-gray-200 bg-white/70 px-3 py-2">
|
||||
<div className="mb-2 flex items-center justify-between gap-2">
|
||||
<p className="text-[10px] font-label uppercase tracking-wider text-muted">{t('quality.title')}</p>
|
||||
<span className="shrink-0 text-[10px] font-body text-muted">{t('quality.scope')}</span>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 gap-2 sm:grid-cols-2 xl:grid-cols-5">
|
||||
{qualityRows.map(row => (
|
||||
<div key={row.key} className="min-w-0">
|
||||
<div className="mb-1 flex items-center justify-between gap-2">
|
||||
<span className="truncate text-[10px] font-body text-secondary">{t(`quality.${row.key}`)}</span>
|
||||
<span className="text-[10px] font-label tabular-nums text-muted">
|
||||
{t('quality.countOfLoaded', { count: formatCount(row.count), total: formatCount(visibleSummary.loaded) })}
|
||||
</span>
|
||||
</div>
|
||||
<div className="h-1.5 overflow-hidden rounded-full bg-nothing-gray-100">
|
||||
<div
|
||||
className={cn('h-full rounded-full', row.tone)}
|
||||
style={{ width: `${row.pct}%` }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{/* 結果列表 */}
|
||||
|
||||
Reference in New Issue
Block a user