fix(web): link passing CI check chips to their check run URL
Passing CI check chips in the session kanban card were rendered as plain <span> elements, so clicking them did nothing even though check.url was available in DashboardCICheck. Wrap each chip in an <a> tag when check.url is present, matching the pattern already used by CICheckList in CIBadge.tsx. Stop click propagation so the chip click does not bubble up to the card's navigation handler. Also fix a pre-existing broken test from #1218 that still expected the old terminal link href without the #session-terminal-section anchor, which was blocking the test suite. Fixes #1209
This commit is contained in:
parent
f22d2d9ccc
commit
16aa089b91
|
|
@ -208,7 +208,7 @@ describe("SessionCard", () => {
|
|||
const session = makeSession({ id: "backend-5" });
|
||||
render(<SessionCard session={session} />);
|
||||
const link = screen.getByText("terminal");
|
||||
expect(link).toHaveAttribute("href", "/sessions/backend-5");
|
||||
expect(link).toHaveAttribute("href", "/sessions/backend-5#session-terminal-section");
|
||||
});
|
||||
|
||||
it("shows restore button when agent has exited", () => {
|
||||
|
|
@ -269,6 +269,68 @@ describe("SessionCard", () => {
|
|||
expect(onMerge).toHaveBeenCalledWith(42);
|
||||
});
|
||||
|
||||
it("renders passing CI check chips as hyperlinks when url is present", () => {
|
||||
const pr = makePR({
|
||||
state: "open",
|
||||
ciStatus: "passing",
|
||||
ciChecks: [
|
||||
{ name: "lint-and-type-checks", status: "passed", url: "https://github.com/owner/repo/runs/111" },
|
||||
{ name: "tests", status: "passed", url: "https://github.com/owner/repo/runs/222" },
|
||||
{ name: "no-url-check", status: "passed" },
|
||||
],
|
||||
reviewDecision: "approved",
|
||||
mergeability: {
|
||||
mergeable: true,
|
||||
ciPassing: true,
|
||||
approved: true,
|
||||
noConflicts: true,
|
||||
blockers: [],
|
||||
},
|
||||
});
|
||||
const session = makeSession({ status: "mergeable", activity: "idle", pr });
|
||||
render(<SessionCard session={session} />);
|
||||
|
||||
const lintLink = screen.getByRole("link", { name: /lint-and-type-checks/ });
|
||||
expect(lintLink).toHaveAttribute("href", "https://github.com/owner/repo/runs/111");
|
||||
expect(lintLink).toHaveAttribute("target", "_blank");
|
||||
expect(lintLink).toHaveAttribute("rel", "noopener noreferrer");
|
||||
|
||||
const testsLink = screen.getByRole("link", { name: /^tests$/ });
|
||||
expect(testsLink).toHaveAttribute("href", "https://github.com/owner/repo/runs/222");
|
||||
|
||||
// Check without url should still render as plain text, not a link
|
||||
expect(screen.queryByRole("link", { name: /no-url-check/ })).not.toBeInTheDocument();
|
||||
expect(screen.getByText("no-url-check")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("stops propagation when clicking a passing CI chip link", () => {
|
||||
const onClick = vi.fn();
|
||||
const pr = makePR({
|
||||
state: "open",
|
||||
ciStatus: "passing",
|
||||
ciChecks: [
|
||||
{ name: "build", status: "passed", url: "https://github.com/owner/repo/runs/333" },
|
||||
],
|
||||
reviewDecision: "approved",
|
||||
mergeability: {
|
||||
mergeable: true,
|
||||
ciPassing: true,
|
||||
approved: true,
|
||||
noConflicts: true,
|
||||
blockers: [],
|
||||
},
|
||||
});
|
||||
const session = makeSession({ status: "mergeable", activity: "idle", pr });
|
||||
render(
|
||||
<div onClick={onClick}>
|
||||
<SessionCard session={session} />
|
||||
</div>,
|
||||
);
|
||||
const link = screen.getByRole("link", { name: /build/ });
|
||||
fireEvent.click(link);
|
||||
expect(onClick).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows CI failing alert", () => {
|
||||
const pr = makePR({
|
||||
state: "open",
|
||||
|
|
|
|||
|
|
@ -571,14 +571,32 @@ function SessionCardView({ session, onSend, onKill, onMerge, onRestore }: Sessio
|
|||
|
||||
{visiblePassingChecks.length > 0 && (
|
||||
<div className="card__ci">
|
||||
{visiblePassingChecks.map((check) => (
|
||||
<span key={check.name} className="ci-chip ci-chip--pass">
|
||||
<svg width="8" height="8" fill="none" stroke="currentColor" strokeWidth="2.5" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
{check.name}
|
||||
</span>
|
||||
))}
|
||||
{visiblePassingChecks.map((check) => {
|
||||
const chipContent = (
|
||||
<>
|
||||
<svg width="8" height="8" fill="none" stroke="currentColor" strokeWidth="2.5" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M20 6 9 17l-5-5" />
|
||||
</svg>
|
||||
{check.name}
|
||||
</>
|
||||
);
|
||||
return check.url ? (
|
||||
<a
|
||||
key={check.name}
|
||||
href={check.url}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="ci-chip ci-chip--pass"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
{chipContent}
|
||||
</a>
|
||||
) : (
|
||||
<span key={check.name} className="ci-chip ci-chip--pass">
|
||||
{chipContent}
|
||||
</span>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue