From 75f6f6452aa94e8d45156c1f93de1e4ac5e3074b Mon Sep 17 00:00:00 2001 From: cliffhall Date: Tue, 17 Mar 2026 10:27:50 -0400 Subject: [PATCH] feat: Add 7 organism screen components with Storybook stories - ServerListScreen: Home page with server card grid and add server menu - ToolsScreen: Three-panel layout (tool list, detail/form, results) - ResourcesScreen: Two-panel with accordion sections and content preview - PromptsScreen: Two-panel with prompt selection and message display - LoggingScreen: Two-panel with log controls and real-time log stream - TasksScreen: Active and completed task card sections - HistoryScreen: Request history with search, filter, and pinned entries Co-Authored-By: Claude Opus 4.6 (1M context) --- .../HistoryScreen/HistoryScreen.stories.tsx | 123 ++++++++++++++++++ .../organisms/HistoryScreen/HistoryScreen.tsx | 107 +++++++++++++++ .../LoggingScreen/LoggingScreen.stories.tsx | 81 ++++++++++++ .../organisms/LoggingScreen/LoggingScreen.tsx | 62 +++++++++ .../PromptsScreen/PromptsScreen.stories.tsx | 72 ++++++++++ .../organisms/PromptsScreen/PromptsScreen.tsx | 44 +++++++ .../ResourcesScreen.stories.tsx | 112 ++++++++++++++++ .../ResourcesScreen/ResourcesScreen.tsx | 111 ++++++++++++++++ .../ServerListScreen.stories.tsx | 123 ++++++++++++++++++ .../ServerListScreen/ServerListScreen.tsx | 45 +++++++ .../TasksScreen/TasksScreen.stories.tsx | 99 ++++++++++++++ .../organisms/TasksScreen/TasksScreen.tsx | 55 ++++++++ .../ToolsScreen/ToolsScreen.stories.tsx | 113 ++++++++++++++++ .../organisms/ToolsScreen/ToolsScreen.tsx | 82 ++++++++++++ 14 files changed, 1229 insertions(+) create mode 100644 clients/web/src/components/organisms/HistoryScreen/HistoryScreen.stories.tsx create mode 100644 clients/web/src/components/organisms/HistoryScreen/HistoryScreen.tsx create mode 100644 clients/web/src/components/organisms/LoggingScreen/LoggingScreen.stories.tsx create mode 100644 clients/web/src/components/organisms/LoggingScreen/LoggingScreen.tsx create mode 100644 clients/web/src/components/organisms/PromptsScreen/PromptsScreen.stories.tsx create mode 100644 clients/web/src/components/organisms/PromptsScreen/PromptsScreen.tsx create mode 100644 clients/web/src/components/organisms/ResourcesScreen/ResourcesScreen.stories.tsx create mode 100644 clients/web/src/components/organisms/ResourcesScreen/ResourcesScreen.tsx create mode 100644 clients/web/src/components/organisms/ServerListScreen/ServerListScreen.stories.tsx create mode 100644 clients/web/src/components/organisms/ServerListScreen/ServerListScreen.tsx create mode 100644 clients/web/src/components/organisms/TasksScreen/TasksScreen.stories.tsx create mode 100644 clients/web/src/components/organisms/TasksScreen/TasksScreen.tsx create mode 100644 clients/web/src/components/organisms/ToolsScreen/ToolsScreen.stories.tsx create mode 100644 clients/web/src/components/organisms/ToolsScreen/ToolsScreen.tsx diff --git a/clients/web/src/components/organisms/HistoryScreen/HistoryScreen.stories.tsx b/clients/web/src/components/organisms/HistoryScreen/HistoryScreen.stories.tsx new file mode 100644 index 00000000..eba8e926 --- /dev/null +++ b/clients/web/src/components/organisms/HistoryScreen/HistoryScreen.stories.tsx @@ -0,0 +1,123 @@ +import type { Meta, StoryObj } from '@storybook/react-vite' +import { fn } from 'storybook/test' +import { HistoryScreen } from './HistoryScreen' +import type { HistoryEntryProps } from '../../molecules/HistoryEntry/HistoryEntry' + +const meta: Meta = { + component: HistoryScreen, + parameters: { layout: 'fullscreen' }, + args: { + searchText: '', + onSearchChange: fn(), + onMethodFilterChange: fn(), + onLoadMore: fn(), + onClearAll: fn(), + onExport: fn(), + }, +} + +export default meta +type Story = StoryObj + +const entry1: HistoryEntryProps = { + timestamp: '2026-03-17T10:00:00Z', + method: 'tools/call', + target: 'send_message', + status: 'success', + durationMs: 120, + parameters: { message: 'Hello, world!' }, + response: { result: 'Message sent successfully' }, + isPinned: false, + isExpanded: false, + onToggleExpand: fn(), + onReplay: fn(), + onTogglePin: fn(), +} + +const entry2: HistoryEntryProps = { + timestamp: '2026-03-17T10:01:00Z', + method: 'resources/read', + target: 'config.json', + status: 'success', + durationMs: 45, + parameters: { uri: 'file:///config.json' }, + response: { contents: [{ uri: 'file:///config.json', text: '{}' }] }, + isPinned: false, + isExpanded: false, + onToggleExpand: fn(), + onReplay: fn(), + onTogglePin: fn(), +} + +const entry3: HistoryEntryProps = { + timestamp: '2026-03-17T10:02:00Z', + method: 'tools/call', + target: 'delete_records', + status: 'error', + durationMs: 350, + parameters: { ids: [1, 2, 3] }, + response: { error: 'Permission denied' }, + isPinned: false, + isExpanded: true, + onToggleExpand: fn(), + onReplay: fn(), + onTogglePin: fn(), +} + +const pinnedEntry1: HistoryEntryProps = { + timestamp: '2026-03-17T09:30:00Z', + method: 'tools/list', + status: 'success', + durationMs: 80, + response: { tools: ['send_message', 'list_users'] }, + isPinned: true, + pinLabel: 'Tool discovery', + isExpanded: false, + onToggleExpand: fn(), + onReplay: fn(), + onTogglePin: fn(), +} + +const pinnedEntry2: HistoryEntryProps = { + timestamp: '2026-03-17T09:35:00Z', + method: 'prompts/get', + target: 'greeting', + status: 'success', + durationMs: 60, + parameters: { name: 'greeting' }, + response: { messages: [{ role: 'user', content: { type: 'text', text: 'Hello!' } }] }, + isPinned: true, + pinLabel: 'Greeting prompt', + isExpanded: false, + onToggleExpand: fn(), + onReplay: fn(), + onTogglePin: fn(), +} + +export const WithEntries: Story = { + args: { + entries: [entry1, entry2, entry3], + pinnedEntries: [pinnedEntry1, pinnedEntry2], + totalCount: 25, + displayedCount: 3, + }, +} + +export const Empty: Story = { + args: { + entries: [], + pinnedEntries: [], + totalCount: 0, + displayedCount: 0, + }, +} + +export const WithFilter: Story = { + args: { + entries: [entry1, entry3], + pinnedEntries: [], + methodFilter: 'tools/call', + totalCount: 10, + displayedCount: 2, + }, +} diff --git a/clients/web/src/components/organisms/HistoryScreen/HistoryScreen.tsx b/clients/web/src/components/organisms/HistoryScreen/HistoryScreen.tsx new file mode 100644 index 00000000..8d31d795 --- /dev/null +++ b/clients/web/src/components/organisms/HistoryScreen/HistoryScreen.tsx @@ -0,0 +1,107 @@ +import { Button, Divider, Group, Paper, Select, Stack, Text, TextInput, Title } from '@mantine/core' +import { HistoryEntry } from '../../molecules/HistoryEntry/HistoryEntry' +import type { HistoryEntryProps } from '../../molecules/HistoryEntry/HistoryEntry' + +export interface HistoryScreenProps { + entries: HistoryEntryProps[] + pinnedEntries: HistoryEntryProps[] + searchText: string + methodFilter?: string + totalCount: number + displayedCount: number + onSearchChange: (text: string) => void + onMethodFilterChange: (method: string) => void + onLoadMore: () => void + onClearAll: () => void + onExport: () => void +} + +const METHOD_OPTIONS = [ + 'tools/call', + 'tools/list', + 'resources/read', + 'resources/list', + 'prompts/get', + 'prompts/list', + 'sampling/createMessage', + 'elicitation/create', +] + +export function HistoryScreen({ + entries, + pinnedEntries, + searchText, + methodFilter, + totalCount, + displayedCount, + onSearchChange, + onMethodFilterChange, + onLoadMore, + onClearAll, + onExport, +}: HistoryScreenProps) { + return ( + + + + Request History + + onSearchChange(event.currentTarget.value)} + /> +