Files
multica/packages/views/issues/components/sub-issues-agent-working-chip.tsx
Naiyuan Qing d58dab0757 fix(issues): stop the sub-issues shimmer chip clipping descenders (#6182)
* fix(issues): stop the shimmer chip clipping descenders

The sub-issues "N agents working" chip paired animate-chat-text-shimmer
with leading-none. The shimmer paints glyphs via background-clip: text,
and the background only covers the line box — with the line box squeezed
to 1em, descenders (g, y, p) fell outside it and rendered transparent.
Drop leading-none; the pill height is governed by the avatar stack, so
the visual size is unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* fix(issues): same descender clip in the per-row activity indicator

Same leading-none + background-clip:text pairing as the sub-issues chip;
"Working" lost its g descender in inbox and issue rows.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-30 16:57:22 +08:00

77 lines
3.0 KiB
TypeScript

"use client";
import { memo } from "react";
import { useQuery } from "@tanstack/react-query";
import {
HoverCard,
HoverCardTrigger,
HoverCardContent,
} from "@multica/ui/components/ui/hover-card";
import { useWorkspaceId } from "@multica/core/hooks";
import { workspaceWorkingAgentsOptions } from "@multica/core/agents";
import { AgentAvatarStack } from "../../agents/components/agent-avatar-stack";
import { WorkingAgentsHoverContent } from "./workspace-agent-working-chip";
import { useT } from "../../i18n";
interface SubIssuesAgentWorkingChipProps {
/** Parent issue whose direct children this chip aggregates over. */
parentIssueId: string;
}
/**
* Aggregate "N agents working" chip for the sub-issues header in issue
* detail (multica#5825). The per-row IssueAgentActivityIndicator answers
* "which sub-issue is being worked on"; this chip answers "how many agents
* are on this parent's children right now" without scanning the rows — and
* keeps that signal visible while the list is collapsed.
*
* It reads the same /api/working-agents projection as the Issues list header,
* narrowed with `parent`. That is deliberate: a header count is a claim about
* a scope, so the server owns both the scope and the arithmetic, exactly as
* it does for the Issues list. Deriving it here from the workspace task
* snapshot would put a second definition of "working" in the client, and the
* count and the hover body would each have to re-derive it.
*
* Row indicators keep reading the snapshot — one shared query sliced per row
* is the right shape for a per-row cue, and a stale row decoration costs
* nothing. A header number is the opposite: it has to be authoritative.
*/
export const SubIssuesAgentWorkingChip = memo(
function SubIssuesAgentWorkingChip({
parentIssueId,
}: SubIssuesAgentWorkingChipProps) {
const { t } = useT("issues");
const wsId = useWorkspaceId();
const { data: agents = [] } = useQuery(
workspaceWorkingAgentsOptions(wsId, "issue", undefined, parentIssueId),
);
if (agents.length === 0) return null;
const agentIds = agents.map((agent) => agent.id);
return (
<HoverCard>
<HoverCardTrigger
render={
<span className="inline-flex shrink-0 items-center gap-1.5 rounded-full bg-muted/60 px-2 py-0.5" />
}
>
<AgentAvatarStack agentIds={agentIds} size="xs" max={3} />
{/* No leading-none: the shimmer paints glyphs via background-clip:
text, and the background only covers the line box — a squeezed
line box leaves descenders transparent. */}
<span className="animate-chat-text-shimmer text-micro font-medium tabular-nums">
{t(($) => $.agent_activity.chip_agents_working, {
count: agentIds.length,
})}
</span>
</HoverCardTrigger>
<HoverCardContent align="start" className="w-72">
<WorkingAgentsHoverContent agents={agents} />
</HoverCardContent>
</HoverCard>
);
},
);