feat: expand intelligent investigation workspace
Generic Container CI/CD / test-build-publish (push) Successful in 1m52s
Frontend CI/CD / build-test-publish-and-deploy (push) Successful in 1m52s

This commit is contained in:
2026-10-30 17:30:19 +08:00
parent ddd03dbff6
commit c0e4231b83
223 changed files with 13155 additions and 5304 deletions
@@ -1,7 +1,7 @@
import { formatLocalMonthDayTime } from "@/shared/utils/date-time";
import { useCallback, useEffect, useRef, useState, type ReactNode } from "react";
import {
CalendarClock,
ClipboardList,
LoaderCircle,
Pencil,
Plus,
@@ -18,7 +18,7 @@ import { Input } from "@/shared/ui/input";
import { StatusBadge, type StatusTone } from "@/shared/ui/status";
import { Textarea } from "@/shared/ui/textarea";
import { WorkOrderReportPanel } from "../components/scheduled-condition-detail-panel";
import { WorkbenchNotice, WorkbenchSection } from "../components/workbench-panel-ui";
import { WorkbenchNotice } from "../components/workbench-panel-ui";
import type { ScheduledWorkOrderItem } from "../types";
import type {
PeripheralContext,
@@ -67,22 +67,20 @@ export function ManagedTestResources({ client, canWrite, capabilities, refreshGe
};
return (
<WorkbenchSection
title="工单接口测试"
description="分别验证预约工单、投诉与爆管事件工单及后端同步。"
icon={<ClipboardList size={15} />}
tone="teal"
bodyClassName="space-y-3"
actions={(
<Button size="icon-sm" variant="ghost" aria-label="刷新测试工单" disabled={Boolean(busy)} onClick={() => void refresh()}>
<section aria-label="工单管理" className="space-y-4">
<div className="flex items-start justify-between gap-3">
<div className="min-w-0">
<h3 className="text-sm font-semibold">工单管理</h3>
<p className="mt-1 text-xs leading-5 text-muted-foreground">预约安排、投诉调查与爆管处置,按类型查看和维护。</p>
</div>
<Button size="icon-sm" variant="ghost" aria-label="刷新工单" disabled={Boolean(busy)} onClick={() => void refresh()}>
<RefreshCw size={14} className={busy === "refresh" ? "animate-spin" : ""} />
</Button>
)}
>
</div>
{error ? <WorkbenchNotice role="alert" tone="danger">{error}</WorkbenchNotice> : null}
{capabilities.work_orders !== "available" ? (
<WorkbenchNotice tone="warning" title="测试工单存储待供给">
缺少 peripheral_sample.work_orders 或 work_order_revisions。
<WorkbenchNotice tone="warning" title="工单服务未就绪">
当前项目尚未配置工单存储,请联系管理员。
</WorkbenchNotice>
) : (
<WorkOrders
@@ -94,7 +92,7 @@ export function ManagedTestResources({ client, canWrite, capabilities, refreshGe
onAgentTrigger={onAgentTrigger}
/>
)}
</WorkbenchSection>
</section>
);
}
@@ -210,7 +208,8 @@ function WorkOrders({ orders, canWrite, busy, mutate, client, onAgentTrigger }:
scheduled_at: new Date(eventOccurredAt).toISOString(),
work_order_type: eventKind,
location: eventLocation.trim(),
scenario_code: waterQuality ? "WQ-SECONDARY-SUPPLY-001" : "BURST-REPORT-001",
scenario_code: null,
origin: "system_data",
feedback_requirements: []
});
setEventEditorOpen(false);
@@ -220,16 +219,17 @@ function WorkOrders({ orders, canWrite, busy, mutate, client, onAgentTrigger }:
});
const canSave = canWrite && !busy && title.trim() && summary.trim();
const editorInputClassName = "mt-1 h-9 rounded-lg border-[var(--surface-divider)] bg-[var(--surface-reading)]";
const editorInputClassName = "mt-1 h-9 rounded-lg border-border bg-card";
const editingEvent = editing?.work_order_type !== undefined && editing.work_order_type !== "general";
const orderEditor = editorOpen ? (
<section
id={editing ? `work-order-editor-${editing.work_order_id}` : "new-work-order-editor"}
aria-label={editing ? `编辑工单 ${editing.title}` : "新增预约工单"}
className="mt-3 rounded-xl bg-white p-3 ring-1 ring-inset ring-slate-200"
className="mt-4 border-t border-border pt-4"
onKeyDown={(event) => {
if (event.key === "Escape" && !busy) {
if (event.key === "Escape" && !busy && !event.defaultPrevented
&& event.currentTarget.contains(event.target as Node)) {
event.preventDefault();
event.stopPropagation();
closeEditor();
@@ -238,19 +238,19 @@ function WorkOrders({ orders, canWrite, busy, mutate, client, onAgentTrigger }:
>
<EditorHeading title={editing ? "编辑工单" : "新增预约工单"} onClose={closeEditor} disabled={Boolean(busy)} />
<div className="mt-2 grid gap-2 sm:grid-cols-2">
<label className="block text-xs font-medium text-slate-600 sm:col-span-2">标题<Input ref={titleInputRef} className={editorInputClassName} value={title} onChange={(event) => setTitle(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<label className="block text-xs font-medium text-slate-600 sm:col-span-2">说明<Textarea className="mt-1 min-h-16" value={summary} onChange={(event) => setSummary(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<FieldSelect label="工单状态" value={status} onValueChange={(value) => setStatus(value as typeof status)} disabled={!canWrite || Boolean(busy)} options={WORK_ORDER_STATUS_OPTIONS} />
<FieldSelect label="优先级" value={priority} onValueChange={(value) => setPriority(value as typeof priority)} disabled={!canWrite || Boolean(busy)} options={PRIORITY_OPTIONS} />
<label className="block text-xs font-medium text-slate-600">负责人<Input className={editorInputClassName} value={assignee} onChange={(event) => setAssignee(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<label className="block text-xs font-medium text-slate-600">位置<Input className={editorInputClassName} value={location} onChange={(event) => setLocation(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<DateTimeField label={editingEvent ? "发生时间" : "预约时间"} value={scheduledAt} onChange={setScheduledAt} disabled={!canWrite || Boolean(busy)} />
<label className="block text-xs font-medium text-slate-600">场景编号<Input className={editorInputClassName} value={scenarioCode} onChange={(event) => setScenarioCode(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<label className="block text-xs font-medium text-muted-foreground sm:col-span-2">标题<Input ref={titleInputRef} className={editorInputClassName} value={title} onChange={(event) => setTitle(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<label className="block text-xs font-medium text-muted-foreground sm:col-span-2">说明<Textarea className="mt-1 min-h-16" value={summary} onChange={(event) => setSummary(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<FieldSelect contentClassName="workbench-shadcn-surface" label="工单状态" value={status} onValueChange={(value) => setStatus(value as typeof status)} disabled={!canWrite || Boolean(busy)} options={WORK_ORDER_STATUS_OPTIONS} />
<FieldSelect contentClassName="workbench-shadcn-surface" label="优先级" value={priority} onValueChange={(value) => setPriority(value as typeof priority)} disabled={!canWrite || Boolean(busy)} options={PRIORITY_OPTIONS} />
<label className="block text-xs font-medium text-muted-foreground">负责人<Input className={editorInputClassName} value={assignee} onChange={(event) => setAssignee(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<label className="block text-xs font-medium text-muted-foreground">位置<Input className={editorInputClassName} value={location} onChange={(event) => setLocation(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<DateTimeField contentClassName="workbench-shadcn-surface" label={editingEvent ? "发生时间" : "预约时间"} value={scheduledAt} onChange={setScheduledAt} disabled={!canWrite || Boolean(busy)} />
<label className="block text-xs font-medium text-muted-foreground">场景编号<Input className={editorInputClassName} value={scenarioCode} onChange={(event) => setScenarioCode(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
</div>
{editing ? <p className="mt-2 text-[11px] text-slate-500">工单类型:{workOrderTypeLabel(editing.work_order_type)},创建后不可修改。</p> : null}
{editing ? <p className="mt-2 text-[11px] text-muted-foreground">工单类型:{workOrderTypeLabel(editing.work_order_type)},创建后不可修改。</p> : null}
<label className="mt-3 block text-xs font-medium text-slate-600">回执要求(每行一项)<Textarea className="mt-1 min-h-20" value={feedbackRequirements} onChange={(event) => setFeedbackRequirements(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
{editing ? <label className="mt-3 block text-xs font-medium text-slate-600">{editingEvent ? "处置反馈(可选)" : "现场反馈(可选)"}<Textarea className="mt-1 min-h-20" value={progressNote} onChange={(event) => setProgressNote(event.target.value)} disabled={!canWrite || Boolean(busy)} placeholder="记录实际处置、复核或回执;留空则只更新工单信息" /></label> : null}
<label className="mt-3 block text-xs font-medium text-muted-foreground">回执要求(每行一项)<Textarea className="mt-1 min-h-20" value={feedbackRequirements} onChange={(event) => setFeedbackRequirements(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
{editing ? <label className="mt-3 block text-xs font-medium text-muted-foreground">{editingEvent ? "处置反馈(可选)" : "现场反馈(可选)"}<Textarea className="mt-1 min-h-20" value={progressNote} onChange={(event) => setProgressNote(event.target.value)} disabled={!canWrite || Boolean(busy)} placeholder="记录实际处置、复核或回执;留空则只更新工单信息" /></label> : null}
<div className="mt-3 flex gap-2">
<Button size="sm" disabled={!canSave} onClick={() => void mutate("save-order", async () => {
@@ -282,6 +282,7 @@ function WorkOrders({ orders, canWrite, busy, mutate, client, onAgentTrigger }:
assignee: assignee.trim() || null,
scheduled_at: scheduledAt ? new Date(scheduledAt).toISOString() : null,
work_order_type: "general",
origin: "system_data",
location: location.trim() || null,
scenario_code: scenarioCode.trim() || null,
feedback_requirements: requirements
@@ -320,11 +321,7 @@ function WorkOrders({ orders, canWrite, busy, mutate, client, onAgentTrigger }:
return (
<div>
<div className="flex flex-wrap items-center justify-between gap-3">
<div className="min-w-0">
<h4 className="text-xs font-semibold text-slate-800">分类工单</h4>
<p className="mt-0.5 text-[11px] leading-4 text-slate-500">预约工单进入预约任务;投诉与爆管上报进入事件调查。</p>
</div>
<div className="space-y-2">
<div className="flex flex-wrap gap-2">
<Button size="sm" disabled={!canWrite || Boolean(busy)} onClick={() => setEventEditorOpen((current) => !current)}>
<Sparkles size={13} />投诉与爆管上报
@@ -333,17 +330,18 @@ function WorkOrders({ orders, canWrite, busy, mutate, client, onAgentTrigger }:
<Plus size={13} />新增预约工单
</Button>
</div>
<p className="text-xs leading-5 text-muted-foreground">预约工单进入预约任务;投诉与爆管上报进入事件调查。</p>
</div>
{eventEditorOpen ? (
<div className="mt-3 rounded-xl bg-white p-3 ring-1 ring-inset ring-slate-200">
<div className="mt-4 rounded-lg border border-border bg-muted/30 p-3 sm:p-4">
<EditorHeading title="模拟事件上报" onClose={() => setEventEditorOpen(false)} />
<div className="mt-2 grid gap-2 sm:grid-cols-2">
<FieldSelect label="事件类型" value={eventKind} onValueChange={(value) => setEventKind(value as typeof eventKind)} disabled={!canWrite || Boolean(busy)} options={[{ value: "water_quality_complaint", label: "水质投诉" }, { value: "burst_report", label: "爆管上报" }]} />
<DateTimeField label="发生时间" value={eventOccurredAt} onChange={setEventOccurredAt} disabled={!canWrite || Boolean(busy)} />
<FieldSelect contentClassName="workbench-shadcn-surface" label="事件类型" value={eventKind} onValueChange={(value) => setEventKind(value as typeof eventKind)} disabled={!canWrite || Boolean(busy)} options={[{ value: "water_quality_complaint", label: "水质投诉" }, { value: "burst_report", label: "爆管上报" }]} />
<DateTimeField contentClassName="workbench-shadcn-surface" label="发生时间" value={eventOccurredAt} onChange={setEventOccurredAt} disabled={!canWrite || Boolean(busy)} />
</div>
<label className="mt-2 block text-xs font-medium text-slate-600">事件位置<Input className="mt-1 h-9" value={eventLocation} onChange={(event) => setEventLocation(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<label className="mt-2 block text-xs font-medium text-slate-600">现场描述<Textarea className="mt-1 min-h-16" value={eventDescription} onChange={(event) => setEventDescription(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<label className="mt-2 block text-xs font-medium text-muted-foreground">事件位置<Input className="mt-1 h-9" value={eventLocation} onChange={(event) => setEventLocation(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<label className="mt-2 block text-xs font-medium text-muted-foreground">现场描述<Textarea className="mt-1 min-h-16" value={eventDescription} onChange={(event) => setEventDescription(event.target.value)} disabled={!canWrite || Boolean(busy)} /></label>
<div className="mt-3 flex gap-2">
<Button size="sm" disabled={!canWrite || Boolean(busy) || !eventLocation.trim() || !eventDescription.trim()} onClick={createEventWorkOrder}>
{busy === "create-event-order" ? <LoaderCircle className="animate-spin" /> : <Sparkles size={13} />}创建事件工单
@@ -364,25 +362,25 @@ function WorkOrders({ orders, canWrite, busy, mutate, client, onAgentTrigger }:
{editorOpen && !editing ? orderEditor : null}
<div aria-label="分类工单列表" className="mt-3 space-y-3">
<div aria-label="分类工单列表" className="mt-4 divide-y divide-border">
{orderGroups.map((group) => (
<Disclosure
key={group.id}
aria-label={`${group.title}列表`}
initiallyOpen
className="rounded-xl border border-slate-200/90 bg-white px-3"
className="py-3 [&>summary]:rounded-md [&>summary]:py-1"
label={(
<div className="flex min-w-0 items-start justify-between gap-3">
<div className="min-w-0">
<h5 className="text-xs font-semibold text-slate-800">{group.title}</h5>
<p className="mt-0.5 text-[11px] font-normal leading-4 text-slate-500">{group.description}</p>
<h5 className="text-sm font-semibold text-foreground">{group.title}</h5>
<p className="mt-0.5 text-[11px] font-normal leading-4 text-muted-foreground">{group.description}</p>
</div>
<StatusBadge tone="neutral">{group.items.length}</StatusBadge>
</div>
)}
>
{group.items.length ? (
<ol className="space-y-2 border-t border-slate-200/80 py-3">
<ol className="space-y-3 pt-3">
{group.items.map((item, index) => (
<li key={item.work_order_id}>
<WorkOrderCard
@@ -406,7 +404,7 @@ function WorkOrders({ orders, canWrite, busy, mutate, client, onAgentTrigger }:
))}
</ol>
) : (
<p className="mb-3 border-t border-slate-200/80 bg-slate-50 px-3 py-2 text-[11px] text-slate-500">暂无{group.title}</p>
<p className="py-4 text-xs text-muted-foreground">暂无{group.title}</p>
)}
</Disclosure>
))}
@@ -435,16 +433,16 @@ function WorkOrderCard({ item, index, canWrite, busy, editing, editor, onEdit, c
deleteButtonRef.current?.focus();
};
return (
<article className="rounded-xl bg-slate-50 p-3 ring-1 ring-inset ring-slate-200">
<article className="rounded-lg border border-border bg-card p-3 sm:p-4">
<div className="flex items-start gap-2">
<div className="min-w-0 flex-1">
<div className="flex flex-wrap items-center gap-1.5">
<span className="text-[10px] font-semibold text-slate-400">{workOrderTypeLabel(item.work_order_type)} {String(index + 1).padStart(2, "0")}</span>
<span className="text-[10px] font-semibold text-muted-foreground">#{String(index + 1).padStart(2, "0")}</span>
<StatusBadge tone={orderStatusTone(item.status)}>{orderStatus(item.status)}</StatusBadge>
<StatusBadge tone={item.work_order_type === "burst_report" ? "danger" : item.work_order_type === "water_quality_complaint" ? "warning" : "neutral"}>{workOrderTypeLabel(item.work_order_type)}</StatusBadge>
</div>
<h6 className="mt-1 text-balance text-xs font-semibold text-slate-900">{item.title}</h6>
<p className="mt-1 text-[11px] leading-4 text-slate-500">{item.summary}</p>
<h6 className="mt-1 text-balance text-xs font-semibold text-foreground">{item.title}</h6>
<p className="mt-1 text-[11px] leading-4 text-muted-foreground">{item.summary}</p>
</div>
{!editing ? <div className="flex shrink-0 gap-0.5">
<Button id={`work-order-edit-${item.work_order_id}`} size="icon-sm" variant="ghost" aria-label={`编辑工单 ${item.title}`} disabled={!canWrite || Boolean(busy)} onClick={(event) => onEdit(event.currentTarget)}><Pencil size={14} /></Button>
@@ -477,15 +475,19 @@ function WorkOrderCard({ item, index, canWrite, busy, editing, editor, onEdit, c
</div>
) : null}
{editor}
<div className="mt-2 flex flex-wrap items-center gap-x-2 gap-y-1 border-t border-slate-200/80 pt-2 text-[10px] text-slate-500">
<div className="mt-2 flex flex-wrap items-center gap-x-2 gap-y-1 border-t border-border pt-2 text-[10px] text-muted-foreground">
<span>{priorityLabel(item.priority)}优先级</span>
{item.location ? <span>位置:{item.location}</span> : null}
{item.assignee ? <span>负责人:{item.assignee}</span> : null}
{item.scheduled_at ? <span className="inline-flex items-center gap-1"><CalendarClock size={11} />{item.work_order_type === "general" ? "预约" : "发生"}:{formatTimestamp(item.scheduled_at)}</span> : null}
{item.scheduled_at ? <span className="inline-flex items-center gap-1"><CalendarClock size={11} />{item.work_order_type === "general" ? "预约" : "发生"}:{formatLocalMonthDayTime(item.scheduled_at)}</span> : null}
<span className="font-mono">r{item.revision}</span>
</div>
<div className="mt-3">
{workOrder ? <WorkOrderReportPanel condition={workOrder} /> : <EventWorkOrderDetails item={item} />}
{workOrder ? (
<Disclosure aria-label={`工单详情 ${item.title}`} label="查看工单详情" className="border-t border-border pt-1">
<WorkOrderReportPanel condition={workOrder} />
</Disclosure>
) : <EventWorkOrderDetails item={item} />}
</div>
</article>
);
@@ -493,33 +495,33 @@ function WorkOrderCard({ item, index, canWrite, busy, editing, editor, onEdit, c
function EventWorkOrderDetails({ item }: { item: PeripheralWorkOrder }) {
return (
<section aria-label={`${workOrderTypeLabel(item.work_order_type)}信息`} className="rounded-xl border border-slate-200 bg-white px-3 py-3">
<p className="text-[10px] font-semibold text-slate-500">事件信息</p>
<section aria-label={`${workOrderTypeLabel(item.work_order_type)}信息`} className="border-t border-border pt-3">
<p className="text-[10px] font-semibold text-muted-foreground">事件信息</p>
<dl className="mt-2 grid grid-cols-2 gap-1.5 sm:grid-cols-3">
<EventWorkOrderField label="事件类型" value={workOrderTypeLabel(item.work_order_type)} />
<EventWorkOrderField label="发生时间" value={item.scheduled_at ? formatTimestamp(item.scheduled_at) : "未记录"} />
<EventWorkOrderField label="发生时间" value={item.scheduled_at ? formatLocalMonthDayTime(item.scheduled_at) : "未记录"} />
<EventWorkOrderField label="位置" value={item.location ?? "未填写"} />
<EventWorkOrderField label="场景编号" value={item.scenario_code ?? "未填写"} />
<EventWorkOrderField label="处理人" value={item.assignee ?? "待分配"} />
<EventWorkOrderField label="活动记录" value={`${item.activity?.length ?? 0} 条`} />
</dl>
{item.activity?.length ? (
<ol aria-label="事件活动记录" className="mt-3 space-y-1.5 border-t border-slate-200 pt-3">
<ol aria-label="事件活动记录" className="mt-3 space-y-1.5 border-t border-border pt-3">
{item.activity.map((entry) => (
<li key={entry.sequence} className="rounded-lg bg-slate-50 px-2.5 py-2 text-[11px] leading-4 text-slate-600">
<span className="font-semibold text-slate-800">{entry.title}</span>
<li key={entry.sequence} className="rounded-lg bg-muted/50 px-2.5 py-2 text-[11px] leading-4 text-muted-foreground">
<span className="font-semibold text-foreground">{entry.title}</span>
<span className="ml-2">{entry.detail}</span>
<span className="mt-1 block text-[10px] text-slate-400">{formatTimestamp(entry.occurred_at)} · {entry.actor}</span>
<span className="mt-1 block text-[10px] text-muted-foreground">{formatLocalMonthDayTime(entry.occurred_at)} · {entry.actor}</span>
</li>
))}
</ol>
) : <p className="mt-3 border-t border-slate-200 pt-3 text-[11px] text-slate-500">暂无事件活动记录</p>}
) : <p className="mt-3 border-t border-border pt-3 text-[11px] text-muted-foreground">暂无事件活动记录</p>}
</section>
);
}
function EventWorkOrderField({ label, value }: { label: string; value: string }) {
return <div className="min-w-0 rounded-lg bg-slate-50 px-2.5 py-2"><dt className="text-[10px] font-semibold text-slate-500">{label}</dt><dd className="mt-0.5 break-words text-[11px] font-medium text-slate-800">{value}</dd></div>;
return <div className="min-w-0 rounded-lg bg-muted/50 px-2.5 py-2"><dt className="text-[10px] font-semibold text-muted-foreground">{label}</dt><dd className="mt-0.5 break-words text-[11px] font-medium text-foreground">{value}</dd></div>;
}
function toScheduledWorkOrder(item: PeripheralWorkOrder): ScheduledWorkOrderItem {
@@ -549,7 +551,7 @@ function toScheduledWorkOrder(item: PeripheralWorkOrder): ScheduledWorkOrderItem
}
function EditorHeading({ title, onClose, disabled = false }: { title: string; onClose: () => void; disabled?: boolean }) {
return <div className="flex items-center justify-between gap-2"><p className="text-xs font-semibold text-slate-800">{title}</p><Button size="icon-sm" variant="ghost" aria-label="关闭编辑表单" disabled={disabled} onClick={onClose}><X size={14} /></Button></div>;
return <div className="flex items-center justify-between gap-2"><p className="text-xs font-semibold text-foreground">{title}</p><Button size="icon-sm" variant="ghost" aria-label="关闭编辑表单" disabled={disabled} onClick={onClose}><X size={14} /></Button></div>;
}
const WORK_ORDER_STATUS_OPTIONS = [
@@ -566,9 +568,7 @@ function toLocalInput(value: Date) {
const offset = value.getTimezoneOffset() * 60_000;
return new Date(value.getTime() - offset).toISOString().slice(0, 16);
}
function formatTimestamp(value: string) {
return new Intl.DateTimeFormat("zh-CN", { month: "2-digit", day: "2-digit", hour: "2-digit", minute: "2-digit", hour12: false }).format(new Date(value));
}
function message(error: unknown) { return error instanceof Error ? error.message : "外围工单请求失败"; }
function orderStatus(value: PeripheralWorkOrder["status"]) { return ({ draft: "草稿", open: "待处理", in_progress: "处理中", awaiting_reply: "待复令", completed: "已完成", cancelled: "已取消" } satisfies Record<typeof value, string>)[value]; }
function orderStatusTone(value: PeripheralWorkOrder["status"]): StatusTone { return ({ draft: "neutral", open: "info", in_progress: "warning", awaiting_reply: "warning", completed: "success", cancelled: "neutral" } satisfies Record<typeof value, StatusTone>)[value]; }