Implement unified dashboard to display tasks and events from multiple federated Mosaic Stack instances with clear provenance indicators. Backend Integration: - Extended federation API client with query support (sendFederatedQuery) - Added query message fetching functions - Integrated with existing QUERY message type from Phase 3 Components Created: - ProvenanceIndicator: Shows which instance data came from - FederatedTaskCard: Task display with provenance - FederatedEventCard: Event display with provenance - AggregatedDataGrid: Unified grid for multiple data types - Dashboard page at /federation/dashboard Key Features: - Query all ACTIVE federated connections on load - Display aggregated tasks and events in unified view - Clear provenance indicators (instance name badges) - PDA-friendly language throughout (no demanding terms) - Loading states and error handling - Empty state when no connections available Technical Implementation: - Uses POST /api/v1/federation/query to send queries - Queries each connection for tasks.list and events.list - Aggregates responses with provenance metadata - Handles connection failures gracefully - 86 tests passing with >85% coverage - TypeScript strict mode compliant - ESLint compliant PDA-Friendly Design: - "Unable to reach" instead of "Connection failed" - "No data available" instead of "No results" - "Loading data from instances..." instead of "Fetching..." - Calm color palette (soft blues, greens, grays) - Status indicators: 🟢 Active, 📋 No data, ⚠️ Error Files Added: - apps/web/src/lib/api/federation-queries.ts - apps/web/src/lib/api/federation-queries.test.ts - apps/web/src/components/federation/types.ts - apps/web/src/components/federation/ProvenanceIndicator.tsx - apps/web/src/components/federation/ProvenanceIndicator.test.tsx - apps/web/src/components/federation/FederatedTaskCard.tsx - apps/web/src/components/federation/FederatedTaskCard.test.tsx - apps/web/src/components/federation/FederatedEventCard.tsx - apps/web/src/components/federation/FederatedEventCard.test.tsx - apps/web/src/components/federation/AggregatedDataGrid.tsx - apps/web/src/components/federation/AggregatedDataGrid.test.tsx - apps/web/src/app/(authenticated)/federation/dashboard/page.tsx - docs/scratchpads/92-aggregated-dashboard.md Testing: - 86 total tests passing - Unit tests for all components - Integration tests for API client - PDA-friendly language verified - TypeScript type checking passing - ESLint passing Ready for code review and QA testing. Related Issues: - Depends on #85 (FED-005: QUERY Message Type) - COMPLETED - Depends on #91 (FED-008: Connection Manager UI) - COMPLETED - Uses #90 (FED-007: EVENT Subscriptions) infrastructure Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
106 lines
2.8 KiB
TypeScript
106 lines
2.8 KiB
TypeScript
/**
|
|
* ProvenanceIndicator Component Tests
|
|
*/
|
|
|
|
import { describe, it, expect } from "vitest";
|
|
import { render, screen } from "@testing-library/react";
|
|
import { ProvenanceIndicator } from "./ProvenanceIndicator";
|
|
|
|
describe("ProvenanceIndicator", () => {
|
|
it("should render instance name", () => {
|
|
render(
|
|
<ProvenanceIndicator
|
|
instanceId="instance-work-001"
|
|
instanceName="Work Instance"
|
|
instanceUrl="https://mosaic.work.example.com"
|
|
/>
|
|
);
|
|
|
|
expect(screen.getByText("Work Instance")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should render with compact mode", () => {
|
|
const { container } = render(
|
|
<ProvenanceIndicator
|
|
instanceId="instance-work-001"
|
|
instanceName="Work Instance"
|
|
instanceUrl="https://mosaic.work.example.com"
|
|
compact={true}
|
|
/>
|
|
);
|
|
|
|
// Compact mode should have smaller padding
|
|
const badge = container.querySelector(".px-2");
|
|
expect(badge).toBeInTheDocument();
|
|
});
|
|
|
|
it("should render with custom color", () => {
|
|
const { container } = render(
|
|
<ProvenanceIndicator
|
|
instanceId="instance-work-001"
|
|
instanceName="Work Instance"
|
|
instanceUrl="https://mosaic.work.example.com"
|
|
color="bg-blue-100"
|
|
/>
|
|
);
|
|
|
|
const badge = container.querySelector(".bg-blue-100");
|
|
expect(badge).toBeInTheDocument();
|
|
});
|
|
|
|
it("should render with default color when not provided", () => {
|
|
const { container } = render(
|
|
<ProvenanceIndicator
|
|
instanceId="instance-work-001"
|
|
instanceName="Work Instance"
|
|
instanceUrl="https://mosaic.work.example.com"
|
|
/>
|
|
);
|
|
|
|
const badge = container.querySelector(".bg-gray-100");
|
|
expect(badge).toBeInTheDocument();
|
|
});
|
|
|
|
it("should show tooltip with instance details on hover", () => {
|
|
render(
|
|
<ProvenanceIndicator
|
|
instanceId="instance-work-001"
|
|
instanceName="Work Instance"
|
|
instanceUrl="https://mosaic.work.example.com"
|
|
/>
|
|
);
|
|
|
|
// Check for title attribute (tooltip)
|
|
const badge = screen.getByText("Work Instance");
|
|
expect(badge.closest("div")).toHaveAttribute(
|
|
"title",
|
|
"From: Work Instance (https://mosaic.work.example.com)"
|
|
);
|
|
});
|
|
|
|
it("should render with icon when showIcon is true", () => {
|
|
render(
|
|
<ProvenanceIndicator
|
|
instanceId="instance-work-001"
|
|
instanceName="Work Instance"
|
|
instanceUrl="https://mosaic.work.example.com"
|
|
showIcon={true}
|
|
/>
|
|
);
|
|
|
|
expect(screen.getByText("🔗")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should not render icon by default", () => {
|
|
render(
|
|
<ProvenanceIndicator
|
|
instanceId="instance-work-001"
|
|
instanceName="Work Instance"
|
|
instanceUrl="https://mosaic.work.example.com"
|
|
/>
|
|
);
|
|
|
|
expect(screen.queryByText("🔗")).not.toBeInTheDocument();
|
|
});
|
|
});
|