inspector/clients/web/src/components/groups/TaskControls/TaskControls.tsx
cliffhall 6abb39a5fe Phase 2: Refactor Tasks cluster to MCP SDK types
Replace ad hoc TaskCardProps data shape with SDK Task type across the
Tasks group components and TasksScreen.

- TaskCard: accept `task: Task` instead of flat props (taskId, status,
  method, target, progress, etc.); derive all display fields from the
  SDK Task object (taskId, status, ttl, createdAt, lastUpdatedAt,
  statusMessage); remove fields not present on SDK Task (method, target,
  progress as number, error, completedAt, elapsed)
- TaskControls: type statusFilter as `TaskStatus | undefined`; add
  runtime validation guard on Select onChange
- TaskListPanel: accept `Task[]` instead of `TaskCardProps[]`; pass
  `onCancel(taskId)` through to each TaskCard; use `task.taskId` as key
- TasksScreen: accept `Task[]` + `onCancel(taskId)` callback; type
  internal statusFilter state as `TaskStatus | undefined`
- Delete re-export of `TaskStatus` from TaskCard (import directly from
  SDK where needed)
- Update all stories with real SDK `Task` fixtures
- Update ConnectedView TasksActive story

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-20 10:28:24 -04:00

61 lines
1.5 KiB
TypeScript

import { Button, Group, Select, Stack, TextInput, Title } from "@mantine/core";
import type { TaskStatus } from "@modelcontextprotocol/sdk/types.js";
const STATUS_OPTIONS: TaskStatus[] = [
"working",
"input_required",
"completed",
"failed",
"cancelled",
];
const ToolbarButton = Button.withProps({
variant: "subtle",
size: "sm",
});
export interface TaskControlsProps {
searchText: string;
statusFilter?: TaskStatus;
onSearchChange: (text: string) => void;
onStatusFilterChange: (status: TaskStatus | undefined) => void;
onRefresh: () => void;
}
export function TaskControls({
searchText,
statusFilter,
onSearchChange,
onStatusFilterChange,
onRefresh,
}: TaskControlsProps) {
return (
<Stack gap="md">
<Group flex={1} justify={"space-between"}>
<Title order={4}>Tasks</Title>
<ToolbarButton onClick={onRefresh}>Refresh</ToolbarButton>
</Group>
<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 ?? null}
onChange={(value) =>
onStatusFilterChange(
value && STATUS_OPTIONS.includes(value as TaskStatus)
? (value as TaskStatus)
: undefined,
)
}
clearable
/>
</Stack>
);
}