Files
tutti/packages/agent/gui/agent-message-center/WorkspaceAgentMessageCenterGroupHeading.tsx
agent-radar 2ed3415fb7
Publish Claude Code Binaries / Stage and publish binaries (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-arm64 (push) Canceled after 0s
Publish Tutti App Runtime / Build darwin-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build linux-amd64 (push) Canceled after 0s
Publish Tutti App Runtime / Build windows-amd64 (push) Canceled after 0s
Sync Tutti Agent Skills / sync (push) Canceled after 0s
Windows Agent Adapters / Test Windows agent adapters (push) Canceled after 0s
Windows Daemon Adapters / Test Windows daemon adapters (push) Canceled after 0s
Publish Tutti App Runtime / Publish runtime catalog (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:17:27 +08:00

93 lines
2.7 KiB
TypeScript

import { cn, StatusDot } from "@tutti-os/ui-system";
import {
MessageCenterIdentityAvatarMark,
MessageCenterIdentityLabel,
messageCenterStatusToneClass,
type MessageCenterStatusTone
} from "./WorkspaceAgentMessageCenterCard";
import type { MessageCenterGroup } from "./workspaceAgentMessageCenterViewModel";
export function MessageCenterGroupHeading({
group
}: {
group: MessageCenterGroup;
}): React.JSX.Element {
"use memo";
const statusSignal = messageCenterGroupStatusSignal(group.id);
const firstItem = group.items[0];
if (group.provider) {
return (
<h3
aria-label={`${group.label} · ${group.items.length}`}
className="flex min-w-0 items-center gap-1.5 text-[11px] font-normal leading-4 text-[var(--text-tertiary)]"
title={`${group.label} · ${group.items.length}`}
>
{group.identity ? (
<MessageCenterIdentityLabel
agentAvatarUrl={firstItem?.agentAvatarUrl}
agentName={firstItem?.agentName}
identity={group.identity}
provider={group.provider}
/>
) : (
<span className="inline-flex min-w-0 items-center gap-1.5">
<MessageCenterIdentityAvatarMark
agentAvatarUrl={firstItem?.agentAvatarUrl}
identity={null}
provider={group.provider}
userId={group.userId ?? null}
/>
<span className="min-w-0 truncate">{group.label}</span>
</span>
)}
<span className="shrink-0">· {group.items.length}</span>
</h3>
);
}
return (
<h3
className={cn(
"flex min-w-0 items-center gap-1.5 text-[11px] font-normal leading-4",
statusSignal
? messageCenterStatusToneClass(statusSignal.tone)
: "text-[var(--text-tertiary)]"
)}
title={`${group.label} · ${group.items.length}`}
>
{statusSignal ? (
<StatusDot
tone={statusSignal.tone}
pulse={statusSignal.pulse}
size="sm"
title={group.label}
/>
) : null}
<span className="min-w-0 truncate">
{group.label} · {group.items.length}
</span>
</h3>
);
}
function messageCenterGroupStatusSignal(groupId: string): {
pulse: boolean;
tone: Exclude<MessageCenterStatusTone, "neutral">;
} | null {
switch (groupId) {
case "needs-attention":
case "waiting":
return { pulse: true, tone: "amber" };
case "working":
return { pulse: true, tone: "blue" };
case "failed":
return { pulse: false, tone: "red" };
case "recently-completed":
case "completed":
return { pulse: false, tone: "green" };
default:
return null;
}
}