mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-03 19:20:07 +02:00
Guard issue icons against unknown values (#4206)
This commit is contained in:
@@ -844,6 +844,26 @@ describe("IssueDetail (shared)", () => {
|
||||
expect(screen.getByText(/changed priority/i)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders activity rows with unknown status values without crashing", async () => {
|
||||
mockApiObj.listTimeline.mockResolvedValue([
|
||||
{
|
||||
type: "activity",
|
||||
id: "act-unknown-status",
|
||||
actor_type: "member",
|
||||
actor_id: "user-1",
|
||||
action: "status_changed",
|
||||
details: { from: "todo", to: "mystery_status" },
|
||||
created_at: "2026-01-18T00:00:00Z",
|
||||
},
|
||||
] as TimelineEntry[]);
|
||||
|
||||
renderIssueDetail();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByText(/from Todo to mystery_status/i)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("truncates the trailing activity block to the most recent 8 entries with a show-more toggle", async () => {
|
||||
// 10 activities, all in the trailing block (no comment after them, so it's
|
||||
// the trailing block by definition). Alternating action types so the
|
||||
|
||||
@@ -6,14 +6,14 @@ export function PriorityIcon({
|
||||
className = "",
|
||||
inheritColor = false,
|
||||
}: {
|
||||
priority: IssuePriority;
|
||||
priority: IssuePriority | string;
|
||||
className?: string;
|
||||
inheritColor?: boolean;
|
||||
}) {
|
||||
const cfg = PRIORITY_CONFIG[priority];
|
||||
const cfg = priority in PRIORITY_CONFIG ? PRIORITY_CONFIG[priority as IssuePriority] : null;
|
||||
|
||||
// "none" — simple horizontal dashes
|
||||
if (cfg.bars === 0) {
|
||||
if (!cfg || cfg.bars === 0) {
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 16 16"
|
||||
|
||||
22
packages/views/issues/components/status-icon.test.tsx
Normal file
22
packages/views/issues/components/status-icon.test.tsx
Normal file
@@ -0,0 +1,22 @@
|
||||
// @vitest-environment jsdom
|
||||
|
||||
import { render } from "@testing-library/react";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { PriorityIcon } from "./priority-icon";
|
||||
import { StatusIcon } from "./status-icon";
|
||||
|
||||
describe("issue icons", () => {
|
||||
it("renders a muted fallback for unknown status values", () => {
|
||||
const { container } = render(<StatusIcon status="unexpected_status" />);
|
||||
|
||||
const icon = container.querySelector("svg");
|
||||
expect(icon).toHaveClass("text-muted-foreground");
|
||||
});
|
||||
|
||||
it("renders a muted fallback for unknown priority values", () => {
|
||||
const { container } = render(<PriorityIcon priority="unexpected_priority" />);
|
||||
|
||||
const icon = container.querySelector("svg");
|
||||
expect(icon).toHaveClass("text-muted-foreground");
|
||||
});
|
||||
});
|
||||
@@ -162,18 +162,19 @@ export function StatusIcon({
|
||||
className = "h-4 w-4",
|
||||
inheritColor = false,
|
||||
}: {
|
||||
status: IssueStatus;
|
||||
status: IssueStatus | string;
|
||||
className?: string;
|
||||
inheritColor?: boolean;
|
||||
}) {
|
||||
const cfg = STATUS_CONFIG[status];
|
||||
const Renderer = STATUS_RENDERERS[status];
|
||||
const knownStatus = status in STATUS_RENDERERS ? (status as IssueStatus) : null;
|
||||
const cfg = knownStatus ? STATUS_CONFIG[knownStatus] : null;
|
||||
const Renderer = knownStatus ? STATUS_RENDERERS[knownStatus] : TodoIcon;
|
||||
|
||||
return (
|
||||
<svg
|
||||
viewBox="0 0 14 14"
|
||||
fill="none"
|
||||
className={`${className} ${inheritColor ? "" : cfg.iconColor} shrink-0`}
|
||||
className={`${className} ${inheritColor ? "" : cfg?.iconColor ?? "text-muted-foreground"} shrink-0`}
|
||||
>
|
||||
<Renderer />
|
||||
</svg>
|
||||
|
||||
Reference in New Issue
Block a user