mirror of
https://github.com/rennf93/roboco.git
synced 2026-08-03 07:23:24 +02:00
fix(panel): compact task-status tiles beside the donut; journal ids copyable + task-linked
Five near-empty stat cards become a 2x3 tile band sharing the row with the status donut. Journal entry cards and the entry page render full ids with the shared CopyButton and a /tasks quick-link badge, with the entry-card anchor restructured so links no longer nest.
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { TaskStatusTiles } from "../task-status-tiles";
|
||||
|
||||
describe("TaskStatusTiles", () => {
|
||||
it("renders a tile per status with its label and value", () => {
|
||||
render(
|
||||
<TaskStatusTiles
|
||||
tiles={[
|
||||
{ label: "Pending", value: 3, icon: <span>icon</span> },
|
||||
{ label: "Completed", value: 12, icon: <span>icon</span> },
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
expect(screen.getByText("Pending")).toBeInTheDocument();
|
||||
expect(screen.getByText("3")).toBeInTheDocument();
|
||||
expect(screen.getByText("Completed")).toBeInTheDocument();
|
||||
expect(screen.getByText("12")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders one tile for every entry passed", () => {
|
||||
render(
|
||||
<TaskStatusTiles
|
||||
tiles={[
|
||||
{ label: "A", value: 1, icon: <span>icon</span> },
|
||||
{ label: "B", value: 2, icon: <span>icon</span> },
|
||||
{ label: "C", value: 3, icon: <span>icon</span> },
|
||||
{ label: "D", value: 4, icon: <span>icon</span> },
|
||||
{ label: "E", value: 5, icon: <span>icon</span> },
|
||||
]}
|
||||
/>,
|
||||
);
|
||||
["A", "B", "C", "D", "E"].forEach((label) => {
|
||||
expect(screen.getByText(label)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -3,4 +3,6 @@ export { ModelUsageDonut } from "./model-usage-donut";
|
||||
export { AgentUsageChart } from "./agent-usage-chart";
|
||||
export { TeamUsageChart } from "./team-usage-chart";
|
||||
export { TaskStatusChart } from "./task-status-chart";
|
||||
export { TaskStatusTiles } from "./task-status-tiles";
|
||||
export type { TaskStatusTileData } from "./task-status-tiles";
|
||||
export { SessionsTable } from "./sessions-table";
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
"use client";
|
||||
|
||||
import { Card } from "@/components/ui/card";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface TaskStatusTileData {
|
||||
label: string;
|
||||
value: number;
|
||||
icon: React.ReactNode;
|
||||
}
|
||||
|
||||
interface TaskStatusTilesProps {
|
||||
tiles: TaskStatusTileData[];
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact grid of task-status counts (label + number + status-colored icon
|
||||
* per tile) — replaces five full-size stat cards that sat mostly empty next
|
||||
* to the status donut (CEO feedback: "much smaller cards 2x3 or something").
|
||||
*/
|
||||
export function TaskStatusTiles({ tiles, className }: TaskStatusTilesProps) {
|
||||
return (
|
||||
<div className={cn("grid grid-cols-2 sm:grid-cols-3 gap-2", className)}>
|
||||
{tiles.map((tile) => (
|
||||
<Card key={tile.label} className="gap-1 py-3">
|
||||
<div className="flex items-center gap-1.5 px-3 text-xs text-muted-foreground">
|
||||
{tile.icon}
|
||||
<span className="truncate">{tile.label}</span>
|
||||
</div>
|
||||
<div className="px-3 text-xl font-bold">{tile.value}</div>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user