2026-04-24 15:50:32 -05:00
|
|
|
// @vitest-environment node
|
|
|
|
|
|
|
|
|
|
import { renderToStaticMarkup } from "react-dom/server";
|
|
|
|
|
import { describe, expect, it } from "vitest";
|
|
|
|
|
import { StatusIcon } from "./StatusIcon";
|
|
|
|
|
|
|
|
|
|
describe("StatusIcon", () => {
|
|
|
|
|
it("renders covered blocked issues with the cyan covered state visual", () => {
|
|
|
|
|
const html = renderToStaticMarkup(
|
|
|
|
|
<StatusIcon
|
|
|
|
|
status="blocked"
|
|
|
|
|
blockerAttention={{
|
|
|
|
|
state: "covered",
|
|
|
|
|
reason: "active_child",
|
|
|
|
|
unresolvedBlockerCount: 1,
|
|
|
|
|
coveredBlockerCount: 1,
|
2026-04-26 21:17:38 -05:00
|
|
|
stalledBlockerCount: 0,
|
2026-04-24 15:50:32 -05:00
|
|
|
attentionBlockerCount: 0,
|
|
|
|
|
sampleBlockerIdentifier: "PAP-2",
|
2026-04-26 21:17:38 -05:00
|
|
|
sampleStalledBlockerIdentifier: null,
|
2026-04-24 15:50:32 -05:00
|
|
|
}}
|
|
|
|
|
/>,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
expect(html).toContain('data-blocker-attention-state="covered"');
|
|
|
|
|
expect(html).toContain('aria-label="Blocked · waiting on active sub-issue PAP-2"');
|
|
|
|
|
expect(html).toContain('title="Blocked · waiting on active sub-issue PAP-2"');
|
|
|
|
|
expect(html).toContain("border-cyan-600");
|
|
|
|
|
expect(html).not.toContain("border-red-600");
|
|
|
|
|
expect(html).not.toContain("border-dashed");
|
|
|
|
|
expect(html).toContain("-bottom-0.5");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("uses covered blocked copy for the active dependency count matrix", () => {
|
|
|
|
|
const html = renderToStaticMarkup(
|
|
|
|
|
<StatusIcon
|
|
|
|
|
status="blocked"
|
|
|
|
|
blockerAttention={{
|
|
|
|
|
state: "covered",
|
|
|
|
|
reason: "active_dependency",
|
|
|
|
|
unresolvedBlockerCount: 2,
|
|
|
|
|
coveredBlockerCount: 2,
|
2026-04-26 21:17:38 -05:00
|
|
|
stalledBlockerCount: 0,
|
2026-04-24 15:50:32 -05:00
|
|
|
attentionBlockerCount: 0,
|
|
|
|
|
sampleBlockerIdentifier: null,
|
2026-04-26 21:17:38 -05:00
|
|
|
sampleStalledBlockerIdentifier: null,
|
2026-04-24 15:50:32 -05:00
|
|
|
}}
|
|
|
|
|
/>,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
expect(html).toContain('aria-label="Blocked · covered by 2 active dependencies"');
|
|
|
|
|
expect(html).toContain("border-cyan-600");
|
|
|
|
|
expect(html).not.toContain("border-dashed");
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
it("keeps normal blocked issues on the attention-required visual", () => {
|
|
|
|
|
const html = renderToStaticMarkup(
|
|
|
|
|
<StatusIcon
|
|
|
|
|
status="blocked"
|
|
|
|
|
blockerAttention={{
|
|
|
|
|
state: "needs_attention",
|
|
|
|
|
reason: "attention_required",
|
|
|
|
|
unresolvedBlockerCount: 1,
|
|
|
|
|
coveredBlockerCount: 0,
|
2026-04-26 21:17:38 -05:00
|
|
|
stalledBlockerCount: 0,
|
2026-04-24 15:50:32 -05:00
|
|
|
attentionBlockerCount: 1,
|
|
|
|
|
sampleBlockerIdentifier: "PAP-2",
|
2026-04-26 21:17:38 -05:00
|
|
|
sampleStalledBlockerIdentifier: null,
|
2026-04-24 15:50:32 -05:00
|
|
|
}}
|
|
|
|
|
/>,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
expect(html).not.toContain('data-blocker-attention-state="covered"');
|
Improve operator workflow QoL (#5291)
## Thinking Path
> - Paperclip is a control plane operators use repeatedly to supervise
agent companies.
> - Common operator workflows depend on fast scanning of inboxes, issue
sidebars, workspaces, cost totals, and runtime services.
> - Several small UI and service gaps made those workflows slower or
less clear.
> - This pull request groups the operator-facing QoL changes that can
stand alone from recovery and adapter work.
> - The benefit is a denser, clearer board experience for issue triage
and workspace operation.
## What Changed
- Added inbox assignee/project grouping and issue list token/runtime
totals.
- Improved issue properties with removable blocker chips and workspace
task links.
- Improved execution workspace layout, runtime controls, issues tab
default, and stopped-port reuse behavior.
- Added mobile markdown/routine dialog fixes, page title company names,
sidebar polish, and dashboard run task label cleanup.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run ui/src/lib/inbox.test.ts
ui/src/components/IssueProperties.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
server/src/__tests__/workspace-runtime.test.ts
server/src/__tests__/costs-service.test.ts`
## Risks
- Medium UI risk because this touches several operator surfaces. The
branch is intentionally grouped around workflow/QoL files and keeps the
file count below the Greptile limit.
## Model Used
- OpenAI GPT-5 Codex via Paperclip `codex_local` adapter, with
shell/git/GitHub CLI tool use.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-05-06 06:30:44 -05:00
|
|
|
expect(html).toContain('data-blocker-attention-state="needs_attention"');
|
|
|
|
|
expect(html).toContain('aria-label="Blocked · 1 blocker needs attention"');
|
2026-04-24 15:50:32 -05:00
|
|
|
expect(html).toContain("border-red-600");
|
|
|
|
|
expect(html).not.toContain("border-dashed");
|
|
|
|
|
});
|
2026-04-26 21:17:38 -05:00
|
|
|
|
Improve operator workflow QoL (#5291)
## Thinking Path
> - Paperclip is a control plane operators use repeatedly to supervise
agent companies.
> - Common operator workflows depend on fast scanning of inboxes, issue
sidebars, workspaces, cost totals, and runtime services.
> - Several small UI and service gaps made those workflows slower or
less clear.
> - This pull request groups the operator-facing QoL changes that can
stand alone from recovery and adapter work.
> - The benefit is a denser, clearer board experience for issue triage
and workspace operation.
## What Changed
- Added inbox assignee/project grouping and issue list token/runtime
totals.
- Improved issue properties with removable blocker chips and workspace
task links.
- Improved execution workspace layout, runtime controls, issues tab
default, and stopped-port reuse behavior.
- Added mobile markdown/routine dialog fixes, page title company names,
sidebar polish, and dashboard run task label cleanup.
## Verification
- `pnpm install --frozen-lockfile`
- `pnpm exec vitest run ui/src/lib/inbox.test.ts
ui/src/components/IssueProperties.test.tsx
ui/src/components/WorkspaceRuntimeControls.test.tsx
server/src/__tests__/workspace-runtime.test.ts
server/src/__tests__/costs-service.test.ts`
## Risks
- Medium UI risk because this touches several operator surfaces. The
branch is intentionally grouped around workflow/QoL files and keeps the
file count below the Greptile limit.
## Model Used
- OpenAI GPT-5 Codex via Paperclip `codex_local` adapter, with
shell/git/GitHub CLI tool use.
## Checklist
- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge
---------
Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-05-06 06:30:44 -05:00
|
|
|
it("shows active covered work on mixed attention-required blockers", () => {
|
|
|
|
|
const html = renderToStaticMarkup(
|
|
|
|
|
<StatusIcon
|
|
|
|
|
status="blocked"
|
|
|
|
|
blockerAttention={{
|
|
|
|
|
state: "needs_attention",
|
|
|
|
|
reason: "attention_required",
|
|
|
|
|
unresolvedBlockerCount: 5,
|
|
|
|
|
coveredBlockerCount: 2,
|
|
|
|
|
stalledBlockerCount: 0,
|
|
|
|
|
attentionBlockerCount: 3,
|
|
|
|
|
sampleBlockerIdentifier: "PAP-3541",
|
|
|
|
|
sampleStalledBlockerIdentifier: null,
|
|
|
|
|
}}
|
|
|
|
|
/>,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
expect(html).toContain('data-blocker-attention-state="needs_attention"');
|
|
|
|
|
expect(html).toContain('aria-label="Blocked · 3 blockers need attention; 2 covered by active work"');
|
|
|
|
|
expect(html).toContain("border-red-600");
|
|
|
|
|
expect(html).not.toContain("border-cyan-600");
|
|
|
|
|
expect(html).toContain("bg-cyan-600");
|
|
|
|
|
});
|
|
|
|
|
|
2026-04-26 21:17:38 -05:00
|
|
|
it("renders stalled review chains with amber visual and stalled-leaf copy", () => {
|
|
|
|
|
const html = renderToStaticMarkup(
|
|
|
|
|
<StatusIcon
|
|
|
|
|
status="blocked"
|
|
|
|
|
blockerAttention={{
|
|
|
|
|
state: "stalled",
|
|
|
|
|
reason: "stalled_review",
|
|
|
|
|
unresolvedBlockerCount: 1,
|
|
|
|
|
coveredBlockerCount: 0,
|
|
|
|
|
stalledBlockerCount: 1,
|
|
|
|
|
attentionBlockerCount: 0,
|
|
|
|
|
sampleBlockerIdentifier: "PAP-2279",
|
|
|
|
|
sampleStalledBlockerIdentifier: "PAP-2279",
|
|
|
|
|
}}
|
|
|
|
|
/>,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
expect(html).toContain('data-blocker-attention-state="stalled"');
|
|
|
|
|
expect(html).toContain('aria-label="Blocked · review stalled on PAP-2279"');
|
|
|
|
|
expect(html).toContain("border-amber-600");
|
|
|
|
|
expect(html).not.toContain("border-cyan-600");
|
|
|
|
|
expect(html).not.toContain("border-red-600");
|
|
|
|
|
});
|
2026-04-24 15:50:32 -05:00
|
|
|
});
|