Fix covered blocked status icons

This commit is contained in:
Dotta committed 2026-04-24 13:32:06 -05:00
1 parent 0ee91c1651
commit f626996e63
5 files changed
+63 -3

No files matched your search

+26 -1
View File
@@ -83,7 +83,9 @@ vi.mock("../lib/assignees", () => ({
}));
vi.mock("./StatusIcon", () => ({
StatusIcon: ({ status }: { status: string }) => <span>{status}</span>,
StatusIcon: ({ status, blockerAttention }: { status: string; blockerAttention?: Issue["blockerAttention"] }) => (
<span data-status-icon-state={blockerAttention?.state}>{status}</span>
),
}));
vi.mock("./PriorityIcon", () => ({
@@ -392,6 +394,29 @@ describe("IssueProperties", () => {
act(() => root.unmount());
});
it("passes blocker attention to the sidebar status icon", async () => {
const root = renderProperties(container, {
issue: createIssue({
status: "blocked",
blockerAttention: {
state: "covered",
reason: "active_child",
unresolvedBlockerCount: 1,
coveredBlockerCount: 1,
attentionBlockerCount: 0,
sampleBlockerIdentifier: "PAP-2",
},
}),
childIssues: [],
onUpdate: vi.fn(),
});
await flush();
expect(container.querySelector('[data-status-icon-state="covered"]')?.textContent).toBe("blocked");
act(() => root.unmount());
});
it("renders blocked-by issues as direct chips and edits them from an add action", async () => {
const onUpdate = vi.fn();
mockIssuesApi.list.mockResolvedValue([
+1
View File
@@ -1044,6 +1044,7 @@ export function IssueProperties({
<PropertyRow label="Status">
<StatusIcon
status={issue.status}
blockerAttention={issue.blockerAttention}
onChange={(status) => onUpdate({ status })}
showLabel
/>
+6
View File
@@ -12,6 +12,7 @@ export type IssueDetailHeaderSeed = {
identifier: string | null;
title: string;
status: Issue["status"];
blockerAttention?: Issue["blockerAttention"];
priority: Issue["priority"];
projectId: string | null;
projectName: string | null;
@@ -47,11 +48,15 @@ function isIssueDetailHeaderSeed(value: unknown): value is IssueDetailHeaderSeed
candidate.originKind === undefined || typeof candidate.originKind === "string";
const hasOriginId =
candidate.originId === undefined || candidate.originId === null || typeof candidate.originId === "string";
const hasBlockerAttention =
candidate.blockerAttention === undefined
|| (typeof candidate.blockerAttention === "object" && candidate.blockerAttention !== null);
return (
typeof candidate.id === "string"
&& (candidate.identifier === null || typeof candidate.identifier === "string")
&& typeof candidate.title === "string"
&& typeof candidate.status === "string"
&& hasBlockerAttention
&& typeof candidate.priority === "string"
&& (candidate.projectId === null || typeof candidate.projectId === "string")
&& (candidate.projectName === null || typeof candidate.projectName === "string")
@@ -66,6 +71,7 @@ function createIssueDetailHeaderSeed(issue: Issue): IssueDetailHeaderSeed {
identifier: issue.identifier ?? null,
title: issue.title,
status: issue.status,
blockerAttention: issue.blockerAttention,
priority: issue.priority,
projectId: issue.projectId ?? null,
projectName: issue.project?.name ?? null,
+28 -1
View File
@@ -229,7 +229,9 @@ vi.mock("../components/ScrollToBottom", () => ({
}));
vi.mock("../components/StatusIcon", () => ({
StatusIcon: ({ status }: { status: string }) => <span>{status}</span>,
StatusIcon: ({ status, blockerAttention }: { status: string; blockerAttention?: Issue["blockerAttention"] }) => (
<span data-status-icon-state={blockerAttention?.state}>{status}</span>
),
}));
vi.mock("../components/PriorityIcon", () => ({
@@ -814,6 +816,31 @@ describe("IssueDetail", () => {
expect(consoleErrorSpy).not.toHaveBeenCalled();
});
it("passes blocker attention to the issue detail header status icon", async () => {
mockIssuesApi.get.mockResolvedValue(createIssue({
status: "blocked",
blockerAttention: {
state: "covered",
reason: "active_child",
unresolvedBlockerCount: 1,
coveredBlockerCount: 1,
attentionBlockerCount: 0,
sampleBlockerIdentifier: "PAP-2",
},
}));
await act(async () => {
root.render(
<QueryClientProvider client={queryClient}>
<IssueDetail />
</QueryClientProvider>,
);
});
await flushReact();
expect(container.querySelector('[data-status-icon-state="covered"]')?.textContent).toBe("blocked");
});
it("refreshes subtree pause state after resuming a hold", async () => {
const childIssue = createIssue({
id: "child-1",
+2 -1
View File
@@ -382,7 +382,7 @@ function IssueDetailLoadingState({
<div className="flex items-center gap-2 min-w-0 flex-wrap">
{headerSeed ? (
<>
<StatusIcon status={headerSeed.status} />
<StatusIcon status={headerSeed.status} blockerAttention={headerSeed.blockerAttention} />
<PriorityIcon priority={headerSeed.priority} />
{identifier ? (
<span className="text-sm font-mono text-muted-foreground shrink-0">{identifier}</span>
@@ -2853,6 +2853,7 @@ export function IssueDetail() {
<div className="flex items-center gap-2 min-w-0 flex-wrap">
<StatusIcon
status={issue.status}
blockerAttention={issue.blockerAttention}
onChange={(status) => updateIssue.mutate({ status })}
/>
<PriorityIcon