From f4ad7eba37ce51d0e71226a3489b334bea707209 Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Tue, 17 Feb 2026 15:49:09 -0600 Subject: [PATCH] fix(web-hud): support hyphenated widget IDs with regression tests --- apps/web/src/components/hud/HUD.tsx | 2 +- .../components/hud/WidgetRenderer.test.tsx | 37 +++++++++++++++++++ .../web/src/components/hud/WidgetRenderer.tsx | 8 +++- docs/tasks.md | 2 + 4 files changed, 46 insertions(+), 3 deletions(-) create mode 100644 apps/web/src/components/hud/WidgetRenderer.test.tsx diff --git a/apps/web/src/components/hud/HUD.tsx b/apps/web/src/components/hud/HUD.tsx index b9078ab..33a7428 100644 --- a/apps/web/src/components/hud/HUD.tsx +++ b/apps/web/src/components/hud/HUD.tsx @@ -73,7 +73,7 @@ export function HUD({ className = "" }: HUDProps): React.JSX.Element { const handleAddWidget = (widgetType: WidgetRegistryKey): void => { const widgetConfig = WIDGET_REGISTRY[widgetType]; - const widgetId = `${widgetType.toLowerCase()}-${String(Date.now())}`; + const widgetId = `${widgetConfig.name}-${String(Date.now())}`; // Find the next available position const maxY = currentLayout?.layout.reduce((max, w): number => Math.max(max, w.y + w.h), 0) ?? 0; diff --git a/apps/web/src/components/hud/WidgetRenderer.test.tsx b/apps/web/src/components/hud/WidgetRenderer.test.tsx new file mode 100644 index 0000000..00ef010 --- /dev/null +++ b/apps/web/src/components/hud/WidgetRenderer.test.tsx @@ -0,0 +1,37 @@ +import { render, screen } from "@testing-library/react"; +import { describe, it, expect, vi } from "vitest"; +import { WidgetRenderer } from "./WidgetRenderer"; +import type { WidgetPlacement } from "@mosaic/shared"; + +vi.mock("@/components/widgets", () => ({ + TasksWidget: ({ id }: { id: string }): React.JSX.Element =>
Tasks Widget {id}
, + CalendarWidget: ({ id }: { id: string }): React.JSX.Element =>
Calendar Widget {id}
, + QuickCaptureWidget: ({ id }: { id: string }): React.JSX.Element => ( +
Quick Capture Widget {id}
+ ), + AgentStatusWidget: ({ id }: { id: string }): React.JSX.Element => ( +
Agent Status Widget {id}
+ ), +})); + +function createWidgetPlacement(id: string): WidgetPlacement { + return { + i: id, + x: 0, + y: 0, + w: 2, + h: 2, + }; +} + +describe("WidgetRenderer", () => { + it("renders hyphenated quick-capture widget IDs correctly", () => { + render(); + expect(screen.getByText("Quick Capture Widget quick-capture-123")).toBeInTheDocument(); + }); + + it("renders hyphenated agent-status widget IDs correctly", () => { + render(); + expect(screen.getByText("Agent Status Widget agent-status-123")).toBeInTheDocument(); + }); +}); diff --git a/apps/web/src/components/hud/WidgetRenderer.tsx b/apps/web/src/components/hud/WidgetRenderer.tsx index 9555aed..83a11b0 100644 --- a/apps/web/src/components/hud/WidgetRenderer.tsx +++ b/apps/web/src/components/hud/WidgetRenderer.tsx @@ -50,8 +50,12 @@ export function WidgetRenderer({ isEditing = false, onRemove, }: WidgetRendererProps): React.JSX.Element { - // Extract widget type from ID (e.g., "tasks-123" -> "tasks") - const widgetType = widget.i.split("-")[0] as keyof typeof WIDGET_COMPONENTS; + // Extract widget type from ID by removing the trailing unique suffix + // (e.g., "agent-status-123" -> "agent-status"). + const separatorIndex = widget.i.lastIndexOf("-"); + const widgetType = ( + separatorIndex > 0 ? widget.i.substring(0, separatorIndex) : widget.i + ) as keyof typeof WIDGET_COMPONENTS; const WidgetComponent = WIDGET_COMPONENTS[widgetType]; const config = WIDGET_CONFIG[widgetType] || { displayName: "Widget", description: "" }; diff --git a/docs/tasks.md b/docs/tasks.md index ff581b5..c6cae5f 100644 --- a/docs/tasks.md +++ b/docs/tasks.md @@ -381,3 +381,5 @@ | ORCH-OBS-002 | done | Add web proxy route for recent orchestrator events (`/api/orchestrator/events/recent`) | #411 | web | feature/mosaic-stack-finalization | ORCH-OBS-001 | | orch | 2026-02-17T16:28Z | 2026-02-17T16:31Z | 5K | 4K | | ORCH-OBS-003 | done | Add repo-level monitor script (`scripts/agent/orchestrator-events.sh`) for recent/watch modes | #411 | tooling | feature/mosaic-stack-finalization | ORCH-OBS-001 | | orch | 2026-02-17T16:31Z | 2026-02-17T16:36Z | 8K | 5K | | ORCH-OBS-004 | done | Add tests/docs updates for recent events and operator command usage | #411 | orchestrator,docs | feature/mosaic-stack-finalization | ORCH-OBS-001 | | orch | 2026-02-17T16:36Z | 2026-02-17T16:40Z | 8K | 6K | +| ORCH-OBS-005 | done | Fix HUD widget ID generation/parsing for hyphenated widget types (`quick-capture`, `agent-status`) | #411 | web | feature/mosaic-stack-finalization | ORCH-OBS-004 | | orch | 2026-02-17T16:42Z | 2026-02-17T16:48Z | 8K | 6K | +| ORCH-OBS-006 | done | Add `WidgetRenderer` regression tests for hyphenated widget IDs | #411 | web | feature/mosaic-stack-finalization | ORCH-OBS-005 | | orch | 2026-02-17T16:48Z | 2026-02-17T16:50Z | 5K | 3K |