Redesign Tasks screen: expandable TaskCard, sidebar controls, and list panel

- Redesign TaskCard to match v1 Task Details panel layout:
  header with task ID + status badge + cancel button,
  always-visible summary row (Status, Last Updated, Created At, TTL)
  with Expand/Collapse button, expandable section with status message,
  progress bar, error, and Full Task Object JSON viewer
- Add TaskControls group: search input + status filter dropdown +
  Refresh/Clear History buttons (mirrors HistoryControls pattern)
- Add TaskListPanel group: scrollable panel with ListToggle for
  expand/collapse all, splits tasks into Active/Completed sections
  with counts, filters by search text and status
- Refactor TasksScreen to sidebar + panel layout matching HistoryScreen:
  manages search/filter state internally, flat tasks array
- Simplify TaskCard callbacks to just onCancel
- Extract named .withProps() subcomponents (HeaderLeftGroup,
  HeaderRightGroup, SectionTitle, SummaryRow, DetailRow) for
  AGENTS.md compliance
- Update all stories (TaskCard, TaskControls, TaskListPanel,
  TasksScreen, ConnectedView)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cliffhall 2026-03-29 22:03:54 -04:00
commit c494d2feb4

View file

@ -0,0 +1,60 @@
import { Button, Group, Select, Stack, TextInput, Title } from "@mantine/core";
import type { TaskStatus } from "../TaskCard/TaskCard";
const STATUS_OPTIONS: TaskStatus[] = [
"waiting",
"running",
"completed",
"failed",
"cancelled",
];
const ToolbarButton = Button.withProps({
variant: "light",
size: "sm",
});
export interface TaskControlsProps {
searchText: string;
statusFilter?: string;
onSearchChange: (text: string) => void;
onStatusFilterChange: (status: string) => void;
onRefresh: () => void;
onClearHistory: () => void;
}
export function TaskControls({
searchText,
statusFilter,
onSearchChange,
onStatusFilterChange,
onRefresh,
onClearHistory,
}: TaskControlsProps) {
return (
<Stack gap="md">
<Title order={4}>Tasks</Title>
<Title order={5}>Search</Title>
<TextInput
placeholder="Search..."
value={searchText}
onChange={(event) => onSearchChange(event.currentTarget.value)}
/>
<Title order={6}>Filter by Status</Title>
<Select
placeholder="All statuses"
data={STATUS_OPTIONS}
value={statusFilter}
onChange={(value) => onStatusFilterChange(value ?? "")}
clearable
/>
<Group>
<ToolbarButton onClick={onRefresh}>Refresh</ToolbarButton>
<ToolbarButton onClick={onClearHistory}>Clear History</ToolbarButton>
</Group>
</Stack>
);
}