fix(ui): replace work item text wall with visual status
Some checks failed
CD Pipeline / workflow-shape (push) Successful in 0s
CD Pipeline / cancel-stale-cd (push) Has been skipped
CD Pipeline / tests (push) Successful in 46s
CD Pipeline / build-and-deploy (push) Successful in 4m31s
CD Pipeline / post-deploy-checks (push) Has been cancelled

This commit is contained in:
Your Name
2026-07-01 18:17:55 +08:00
parent da46fe30c3
commit a971effce3
3 changed files with 148 additions and 65 deletions

View File

@@ -7863,14 +7863,50 @@ function AiLoopLogSourceTagsPanel({
ids: receiptOutputIds,
},
];
const rootCause = queueNormalizerFieldIds.some((id) =>
id.includes("server_accepts_key_then_session_timeout")
)
? t("rootCause.sessionTimeout")
: queueNormalizerFieldIds.some((id) => id.includes("publickey_offer_timeout"))
? t("rootCause.offerTimeout")
: t("rootCause.unknown");
const visualCards = [
{
key: "blocker",
icon: TriangleAlert,
label: t("visual.blocker"),
value: summary?.ai_loop_current_blocker_id ?? "--",
tone: "border-[#f0c6a8] bg-[#fff8f1] text-[#9a4d16]",
},
{
key: "diagnosis",
icon: SearchCheck,
label: t("visual.diagnosis"),
value: rootCause,
tone: "border-[#c9d8ea] bg-[#eef5ff] text-[#1f5b9b]",
},
{
key: "receipt",
icon: ClipboardList,
label: t("visual.receipt"),
value: t("visual.receiptValue", {
inputs:
summary?.ai_loop_current_blocker_harbor_recovery_receipt_input_count ??
receiptInputIds.length,
outputs:
summary?.ai_loop_current_blocker_harbor_recovery_receipt_output_contract_count ??
receiptOutputIds.length,
}),
tone: "border-[#cbd7bf] bg-[#f4faef] text-[#3d6b24]",
},
];
return (
<section
className="border border-[#e0ddd4] bg-white"
data-testid="ai-loop-log-source-tags-panel"
>
<div className="grid gap-px bg-[#e0ddd4] lg:grid-cols-[minmax(0,1.1fr)_minmax(0,1.6fr)]">
<div className="bg-white p-4">
<div className="bg-white p-4">
<div className="flex items-center gap-3">
<Database className="h-5 w-5 text-[#4A90D9]" aria-hidden="true" />
<div className="min-w-0">
@@ -7885,6 +7921,30 @@ function AiLoopLogSourceTagsPanel({
<p className="mt-3 text-xs leading-5 text-[#77736a]">
{t("subtitle")}
</p>
<div className="mt-4 grid gap-3 lg:grid-cols-3">
{visualCards.map((card) => {
const Icon = card.icon;
return (
<div
key={card.key}
className={cn(
"min-w-0 border px-4 py-3",
card.tone
)}
>
<div className="flex items-center justify-between gap-3">
<span className="text-xs font-semibold">
{card.label}
</span>
<Icon className="h-4 w-4 shrink-0" aria-hidden="true" />
</div>
<div className="mt-3 break-words font-mono text-sm font-semibold leading-5 text-[#141413]">
{loading ? "--" : card.value}
</div>
</div>
);
})}
</div>
<div className="mt-4 grid gap-px border border-[#e0ddd4] bg-[#e0ddd4] sm:grid-cols-2 xl:grid-cols-4">
{metrics.map((metric) => {
const Icon = metric.icon;
@@ -7903,26 +7963,6 @@ function AiLoopLogSourceTagsPanel({
);
})}
</div>
<div className="mt-3 border border-[#d8d3c7] bg-[#faf9f3] px-3 py-2 font-mono text-[11px] leading-5 text-[#5f5b52]">
{t("blocker", {
value: summary?.ai_loop_current_blocker_id ?? "--",
})}
</div>
<div className="mt-3 border border-[#d8d3c7] bg-white px-3 py-2">
<div className="text-[11px] font-semibold text-[#77736a]">
{t("queueFields")}
</div>
<div className="mt-2 flex flex-wrap gap-1.5">
{queueNormalizerFieldIds.slice(0, 7).map((id) => (
<span
key={id}
className="max-w-full break-all border border-[#c9d8ea] bg-[#eef5ff] px-2 py-0.5 font-mono text-[10px] text-[#1f5b9b]"
>
{id}
</span>
))}
</div>
</div>
<div className="mt-3 grid gap-2">
{receiptMetrics.map((metric) => (
<div
@@ -7950,47 +7990,66 @@ function AiLoopLogSourceTagsPanel({
</div>
))}
</div>
</div>
<div className="bg-white p-4">
{tags.length > 0 ? (
<div className="grid gap-2 sm:grid-cols-2 xl:grid-cols-3">
{tags.map((tag) => {
const key = String(tag.tag_key ?? "");
return (
<div
<details className="mt-4 border border-[#d8d3c7] bg-[#faf9f3]">
<summary className="cursor-pointer px-3 py-2 text-xs font-semibold text-[#5f5b52]">
{t("details")}
</summary>
<div className="border-t border-[#d8d3c7] bg-white p-3">
<div className="border border-[#d8d3c7] bg-white px-3 py-2">
<div className="text-[11px] font-semibold text-[#77736a]">
{t("queueFields")}
</div>
<div className="mt-2 flex flex-wrap gap-1.5">
{queueNormalizerFieldIds.map((id) => (
<span
key={id}
className="max-w-full break-all border border-[#c9d8ea] bg-[#eef5ff] px-2 py-0.5 font-mono text-[10px] text-[#1f5b9b]"
>
{id}
</span>
))}
</div>
</div>
{tags.length > 0 ? (
<div className="mt-3 grid gap-2 sm:grid-cols-2 xl:grid-cols-3">
{tags.map((tag) => {
const key = String(tag.tag_key ?? "");
return (
<div
key={key}
className="min-w-0 border border-[#d8d3c7] bg-[#faf9f3] px-3 py-2"
>
<div className="text-[10px] font-semibold uppercase tracking-[0.08em] text-[#9a968c]">
{tagDisplayLabel(key, labelMap)}
</div>
<div className="mt-1 break-all font-mono text-[11px] leading-5 text-[#141413]">
{tag.tag_value || "--"}
</div>
</div>
);
})}
</div>
) : (
<div className="mt-3 border border-[#d8d3c7] bg-[#faf9f3] px-3 py-6 text-center text-xs text-[#77736a]">
{loading ? t("loading") : t("empty")}
</div>
)}
<div className="mt-3 flex flex-wrap gap-1.5">
{groupingKeys.map((key) => (
<span
key={key}
className="min-w-0 border border-[#d8d3c7] bg-[#faf9f3] px-3 py-2"
className="border border-[#c9d8ea] bg-[#eef5ff] px-2 py-0.5 font-mono text-[11px] text-[#1f5b9b]"
>
<div className="text-[10px] font-semibold uppercase tracking-[0.08em] text-[#9a968c]">
{tagDisplayLabel(key, labelMap)}
</div>
<div className="mt-1 break-all font-mono text-[11px] leading-5 text-[#141413]">
{tag.tag_value || "--"}
</div>
</div>
);
})}
{tagDisplayLabel(key, labelMap)}
</span>
))}
</div>
<p className="mt-3 text-[11px] leading-5 text-[#77736a]">
{t("boundary")}
</p>
</div>
) : (
<div className="border border-[#d8d3c7] bg-[#faf9f3] px-3 py-6 text-center text-xs text-[#77736a]">
{loading ? t("loading") : t("empty")}
</div>
)}
<div className="mt-3 flex flex-wrap gap-1.5">
{groupingKeys.map((key) => (
<span
key={key}
className="border border-[#c9d8ea] bg-[#eef5ff] px-2 py-0.5 font-mono text-[11px] text-[#1f5b9b]"
>
{tagDisplayLabel(key, labelMap)}
</span>
))}
</div>
<p className="mt-3 text-[11px] leading-5 text-[#77736a]">
{t("boundary")}
</p>
</div>
</details>
</div>
</section>
);