clawport-ui 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +35 -0
- package/BRANDING.md +131 -0
- package/CLAUDE.md +252 -0
- package/README.md +262 -0
- package/SETUP.md +337 -0
- package/app/agents/[id]/page.tsx +727 -0
- package/app/api/agents/route.ts +12 -0
- package/app/api/chat/[id]/route.ts +139 -0
- package/app/api/cron-runs/route.ts +13 -0
- package/app/api/crons/route.ts +12 -0
- package/app/api/kanban/chat/[id]/route.ts +119 -0
- package/app/api/kanban/chat-history/[ticketId]/route.ts +36 -0
- package/app/api/memory/route.ts +12 -0
- package/app/api/transcribe/route.ts +37 -0
- package/app/api/tts/route.ts +42 -0
- package/app/chat/[id]/page.tsx +10 -0
- package/app/chat/page.tsx +200 -0
- package/app/crons/page.tsx +870 -0
- package/app/docs/page.tsx +399 -0
- package/app/favicon.ico +0 -0
- package/app/globals.css +692 -0
- package/app/kanban/page.tsx +327 -0
- package/app/layout.tsx +45 -0
- package/app/memory/page.tsx +685 -0
- package/app/page.tsx +817 -0
- package/app/providers.tsx +37 -0
- package/app/settings/page.tsx +901 -0
- package/app/settings-provider.tsx +209 -0
- package/components/AgentAvatar.tsx +54 -0
- package/components/AgentNode.tsx +122 -0
- package/components/Breadcrumbs.tsx +126 -0
- package/components/DynamicFavicon.tsx +62 -0
- package/components/ErrorState.tsx +97 -0
- package/components/FeedView.tsx +494 -0
- package/components/GlobalSearch.tsx +571 -0
- package/components/GridView.tsx +532 -0
- package/components/ManorMap.tsx +157 -0
- package/components/MobileSidebar.tsx +251 -0
- package/components/NavLinks.tsx +271 -0
- package/components/OnboardingWizard.tsx +1067 -0
- package/components/Sidebar.tsx +115 -0
- package/components/ThemeToggle.tsx +108 -0
- package/components/chat/AgentList.tsx +537 -0
- package/components/chat/ConversationView.tsx +1047 -0
- package/components/chat/FileAttachment.tsx +140 -0
- package/components/chat/MediaPreview.tsx +111 -0
- package/components/chat/VoiceMessage.tsx +139 -0
- package/components/crons/PipelineGraph.tsx +327 -0
- package/components/crons/WeeklySchedule.tsx +630 -0
- package/components/docs/AgentsSection.tsx +209 -0
- package/components/docs/ApiReferenceSection.tsx +256 -0
- package/components/docs/ArchitectureSection.tsx +221 -0
- package/components/docs/ComponentsSection.tsx +253 -0
- package/components/docs/CronSystemSection.tsx +235 -0
- package/components/docs/DocSection.tsx +346 -0
- package/components/docs/GettingStartedSection.tsx +169 -0
- package/components/docs/ThemingSection.tsx +257 -0
- package/components/docs/TroubleshootingSection.tsx +200 -0
- package/components/kanban/AgentPicker.tsx +321 -0
- package/components/kanban/CreateTicketModal.tsx +333 -0
- package/components/kanban/KanbanBoard.tsx +70 -0
- package/components/kanban/KanbanColumn.tsx +166 -0
- package/components/kanban/TicketCard.tsx +245 -0
- package/components/kanban/TicketDetailPanel.tsx +850 -0
- package/components/ui/badge.tsx +48 -0
- package/components/ui/button.tsx +64 -0
- package/components/ui/card.tsx +92 -0
- package/components/ui/dialog.tsx +158 -0
- package/components/ui/scroll-area.tsx +58 -0
- package/components/ui/separator.tsx +28 -0
- package/components/ui/skeleton.tsx +27 -0
- package/components/ui/tabs.tsx +91 -0
- package/components/ui/tooltip.tsx +57 -0
- package/components.json +23 -0
- package/docs/API.md +648 -0
- package/docs/COMPONENTS.md +1059 -0
- package/docs/THEMING.md +795 -0
- package/lib/agents-registry.ts +35 -0
- package/lib/agents.json +282 -0
- package/lib/agents.test.ts +367 -0
- package/lib/agents.ts +32 -0
- package/lib/anthropic.test.ts +422 -0
- package/lib/anthropic.ts +220 -0
- package/lib/api-error.ts +16 -0
- package/lib/audio-recorder.test.ts +72 -0
- package/lib/audio-recorder.ts +169 -0
- package/lib/conversations.test.ts +331 -0
- package/lib/conversations.ts +117 -0
- package/lib/cron-pipelines.test.ts +69 -0
- package/lib/cron-pipelines.ts +58 -0
- package/lib/cron-runs.test.ts +118 -0
- package/lib/cron-runs.ts +67 -0
- package/lib/cron-utils.test.ts +222 -0
- package/lib/cron-utils.ts +160 -0
- package/lib/crons.test.ts +502 -0
- package/lib/crons.ts +114 -0
- package/lib/env.test.ts +44 -0
- package/lib/env.ts +14 -0
- package/lib/kanban/automation.test.ts +245 -0
- package/lib/kanban/automation.ts +143 -0
- package/lib/kanban/chat-store.test.ts +149 -0
- package/lib/kanban/chat-store.ts +81 -0
- package/lib/kanban/store.test.ts +238 -0
- package/lib/kanban/store.ts +98 -0
- package/lib/kanban/types.ts +50 -0
- package/lib/kanban/useAgentWork.ts +78 -0
- package/lib/memory.ts +45 -0
- package/lib/multimodal.test.ts +219 -0
- package/lib/multimodal.ts +68 -0
- package/lib/pipeline.integration.test.ts +343 -0
- package/lib/sanitize.ts +194 -0
- package/lib/settings.test.ts +137 -0
- package/lib/settings.ts +94 -0
- package/lib/styles.ts +24 -0
- package/lib/themes.ts +9 -0
- package/lib/transcribe.test.ts +141 -0
- package/lib/transcribe.ts +111 -0
- package/lib/types.ts +66 -0
- package/lib/utils.ts +6 -0
- package/lib/validation.test.ts +132 -0
- package/lib/validation.ts +80 -0
- package/next.config.ts +7 -0
- package/package.json +56 -0
- package/postcss.config.mjs +7 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/next.svg +1 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/scripts/setup.mjs +215 -0
- package/tsconfig.json +34 -0
- package/vitest.config.ts +17 -0
|
@@ -0,0 +1,1059 @@
|
|
|
1
|
+
# ClawPort -- Component Reference
|
|
2
|
+
|
|
3
|
+
Every React component in the codebase, grouped by area. For each component: purpose, props, key state, parent usage, and implementation notes.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Component Tree
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
RootLayout (app/layout.tsx)
|
|
11
|
+
ThemeProvider (app/providers.tsx)
|
|
12
|
+
SettingsProvider (app/settings-provider.tsx)
|
|
13
|
+
DynamicFavicon (components/DynamicFavicon.tsx)
|
|
14
|
+
OnboardingWizard (components/OnboardingWizard.tsx)
|
|
15
|
+
Sidebar (components/Sidebar.tsx)
|
|
16
|
+
NavLinks (components/NavLinks.tsx)
|
|
17
|
+
ThemeToggle (components/ThemeToggle.tsx)
|
|
18
|
+
MobileSidebar (components/MobileSidebar.tsx)
|
|
19
|
+
GlobalSearch (components/GlobalSearch.tsx)
|
|
20
|
+
<main> (page content)
|
|
21
|
+
HomePage (app/page.tsx)
|
|
22
|
+
OrgMap (components/OrgMap.tsx)
|
|
23
|
+
AgentNode (components/AgentNode.tsx)
|
|
24
|
+
AgentAvatar (components/AgentAvatar.tsx)
|
|
25
|
+
GridView (components/GridView.tsx)
|
|
26
|
+
AgentAvatar
|
|
27
|
+
FeedView (components/FeedView.tsx)
|
|
28
|
+
ChatPage (app/chat/page.tsx)
|
|
29
|
+
AgentList (components/chat/AgentList.tsx)
|
|
30
|
+
AgentAvatar
|
|
31
|
+
AgentListMobile (components/chat/AgentList.tsx)
|
|
32
|
+
AgentAvatar
|
|
33
|
+
ConversationView (components/chat/ConversationView.tsx)
|
|
34
|
+
VoiceMessage (components/chat/VoiceMessage.tsx)
|
|
35
|
+
FileAttachment (components/chat/FileAttachment.tsx)
|
|
36
|
+
MediaPreview (components/chat/MediaPreview.tsx)
|
|
37
|
+
AgentDetailPage (app/agents/[id]/page.tsx)
|
|
38
|
+
AgentAvatar
|
|
39
|
+
Breadcrumbs (components/Breadcrumbs.tsx)
|
|
40
|
+
KanbanPage (app/kanban/page.tsx)
|
|
41
|
+
KanbanBoard (components/kanban/KanbanBoard.tsx)
|
|
42
|
+
KanbanColumn (components/kanban/KanbanColumn.tsx)
|
|
43
|
+
TicketCard (components/kanban/TicketCard.tsx)
|
|
44
|
+
AgentAvatar
|
|
45
|
+
TicketDetailPanel (components/kanban/TicketDetailPanel.tsx)
|
|
46
|
+
CreateTicketModal (components/kanban/CreateTicketModal.tsx)
|
|
47
|
+
AgentPicker (components/kanban/AgentPicker.tsx)
|
|
48
|
+
AgentAvatar
|
|
49
|
+
CronsPage (app/crons/page.tsx)
|
|
50
|
+
WeeklySchedule (components/crons/WeeklySchedule.tsx)
|
|
51
|
+
PipelineGraph (components/crons/PipelineGraph.tsx)
|
|
52
|
+
MemoryPage (app/memory/page.tsx)
|
|
53
|
+
SettingsPage (app/settings/page.tsx)
|
|
54
|
+
AgentAvatar
|
|
55
|
+
ErrorState (components/ErrorState.tsx)
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Providers
|
|
61
|
+
|
|
62
|
+
### ThemeProvider
|
|
63
|
+
|
|
64
|
+
**File:** `app/providers.tsx`
|
|
65
|
+
**Purpose:** Manages the active theme and applies it to the document root via `data-theme` attribute.
|
|
66
|
+
|
|
67
|
+
| Prop | Type | Required | Description |
|
|
68
|
+
|------|------|----------|-------------|
|
|
69
|
+
| children | `React.ReactNode` | Yes | App content |
|
|
70
|
+
|
|
71
|
+
**Context value:**
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
{ theme: ThemeId; setTheme: (t: ThemeId) => void }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**Key state:**
|
|
78
|
+
- `theme` (useState) -- persisted to `localStorage('clawport-theme')`, defaults to `'dark'`
|
|
79
|
+
|
|
80
|
+
**Implementation:**
|
|
81
|
+
- On mount, reads `localStorage('clawport-theme')` and sets `data-theme` attribute on `<html>`
|
|
82
|
+
- `setTheme` updates state, localStorage, and the DOM attribute in one call
|
|
83
|
+
- Exports `useTheme()` hook for consumers
|
|
84
|
+
|
|
85
|
+
**Used by:** `app/layout.tsx` (wraps entire app)
|
|
86
|
+
|
|
87
|
+
---
|
|
88
|
+
|
|
89
|
+
### SettingsProvider
|
|
90
|
+
|
|
91
|
+
**File:** `app/settings-provider.tsx`
|
|
92
|
+
**Purpose:** Central state management for all user-configurable settings (branding, accent color, operator name, agent display overrides).
|
|
93
|
+
|
|
94
|
+
| Prop | Type | Required | Description |
|
|
95
|
+
|------|------|----------|-------------|
|
|
96
|
+
| children | `React.ReactNode` | Yes | App content |
|
|
97
|
+
|
|
98
|
+
**Context value:**
|
|
99
|
+
|
|
100
|
+
```ts
|
|
101
|
+
interface SettingsContextValue {
|
|
102
|
+
settings: ClawPortSettings
|
|
103
|
+
setAccentColor: (color: string | null) => void
|
|
104
|
+
setPortalName: (name: string | null) => void
|
|
105
|
+
setPortalSubtitle: (subtitle: string | null) => void
|
|
106
|
+
setPortalEmoji: (emoji: string | null) => void
|
|
107
|
+
setPortalIcon: (icon: string | null) => void
|
|
108
|
+
setIconBgHidden: (hidden: boolean) => void
|
|
109
|
+
setEmojiOnly: (emojiOnly: boolean) => void
|
|
110
|
+
setOperatorName: (name: string | null) => void
|
|
111
|
+
setAgentOverride: (agentId: string, override: AgentDisplayOverride | null) => void
|
|
112
|
+
getAgentDisplay: (agent: Agent) => AgentDisplay
|
|
113
|
+
resetAll: () => void
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Key state:**
|
|
118
|
+
- `settings` (useState) -- full `ClawPortSettings` object, persisted to localStorage via `saveSettings()`
|
|
119
|
+
|
|
120
|
+
**Implementation:**
|
|
121
|
+
- Applies CSS custom properties (`--accent`, `--accent-hover`, `--accent-glow`) directly to `document.documentElement.style` when accent color changes
|
|
122
|
+
- `getAgentDisplay(agent)` merges agent defaults with per-agent overrides (custom emoji, image, background)
|
|
123
|
+
- `resetAll()` clears localStorage and resets to defaults
|
|
124
|
+
- Each setter calls `saveSettings()` after updating state
|
|
125
|
+
|
|
126
|
+
**Used by:** `app/layout.tsx` (wraps entire app, inside ThemeProvider)
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## Layout Components
|
|
131
|
+
|
|
132
|
+
### Sidebar
|
|
133
|
+
|
|
134
|
+
**File:** `components/Sidebar.tsx`
|
|
135
|
+
**Purpose:** Client wrapper that coordinates the desktop sidebar, mobile header/sidebar, and Cmd+K search palette.
|
|
136
|
+
|
|
137
|
+
**Props:** None
|
|
138
|
+
|
|
139
|
+
**Key state:**
|
|
140
|
+
- `searchOpen` (useState) -- controls GlobalSearch visibility
|
|
141
|
+
|
|
142
|
+
**Implementation:**
|
|
143
|
+
- Renders `NavLinks` and `ThemeToggle` inside a fixed-width desktop sidebar (`w-[220px]`, hidden on mobile)
|
|
144
|
+
- Renders `MobileSidebar` for mobile viewports
|
|
145
|
+
- Renders `GlobalSearch` (always mounted, visibility controlled by `searchOpen`)
|
|
146
|
+
- Listens for custom event `clawport:open-search` to toggle search open
|
|
147
|
+
- Dispatches search-open from MobileSidebar's search trigger
|
|
148
|
+
|
|
149
|
+
**Used by:** `app/layout.tsx`
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
### NavLinks
|
|
154
|
+
|
|
155
|
+
**File:** `components/NavLinks.tsx`
|
|
156
|
+
**Purpose:** Sidebar navigation links with icons, badges, and operator identity footer.
|
|
157
|
+
|
|
158
|
+
**Props:** None
|
|
159
|
+
|
|
160
|
+
**Key state:**
|
|
161
|
+
- `agentCount` (useState) -- fetched from `/api/agents` on mount
|
|
162
|
+
- `cronErrorCount` (useState) -- fetched from `/api/crons` on mount
|
|
163
|
+
|
|
164
|
+
**Implementation:**
|
|
165
|
+
- Six navigation items: Map, Kanban, Messages, Crons, Memory, Settings
|
|
166
|
+
- Each uses a Lucide icon (`Map`, `Columns3`, `MessageCircle`, `Clock`, `Brain`, `Settings`)
|
|
167
|
+
- Badge system: agent count on Map, cron error count on Crons (red dot)
|
|
168
|
+
- Footer shows operator initials (computed from `operatorName` via `useSettings()`) and display name
|
|
169
|
+
- Falls back to "Operator" / "??" when `operatorName` is unset
|
|
170
|
+
- Uses `usePathname()` for active link highlighting
|
|
171
|
+
|
|
172
|
+
**Used by:** `components/Sidebar.tsx`
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
### MobileSidebar
|
|
177
|
+
|
|
178
|
+
**File:** `components/MobileSidebar.tsx`
|
|
179
|
+
**Purpose:** Fixed mobile header bar with hamburger menu and slide-out sidebar panel.
|
|
180
|
+
|
|
181
|
+
| Prop | Type | Required | Description |
|
|
182
|
+
|------|------|----------|-------------|
|
|
183
|
+
| onOpenSearch | `() => void` | No | Callback to open global search |
|
|
184
|
+
|
|
185
|
+
**Key state:**
|
|
186
|
+
- `isOpen` (useState) -- sidebar panel visibility
|
|
187
|
+
|
|
188
|
+
**Implementation:**
|
|
189
|
+
- Fixed header bar (48px) with portal emoji/name, search icon, and hamburger button
|
|
190
|
+
- Slide-out panel renders NavLinks and ThemeToggle
|
|
191
|
+
- Closes on: route change (`usePathname` effect), ESC key, click outside panel
|
|
192
|
+
- Prevents body scroll when open via `overflow: hidden` on body
|
|
193
|
+
- Only visible on mobile (`md:hidden`)
|
|
194
|
+
|
|
195
|
+
**Used by:** `components/Sidebar.tsx`
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
### GlobalSearch
|
|
200
|
+
|
|
201
|
+
**File:** `components/GlobalSearch.tsx`
|
|
202
|
+
**Purpose:** Cmd+K search palette with fuzzy search across agents, pages, and crons.
|
|
203
|
+
|
|
204
|
+
| Prop | Type | Required | Description |
|
|
205
|
+
|------|------|----------|-------------|
|
|
206
|
+
| open | `boolean` | Yes | Whether the search modal is visible |
|
|
207
|
+
| onClose | `() => void` | Yes | Callback to close the modal |
|
|
208
|
+
|
|
209
|
+
**Exports:** `GlobalSearch` (main modal) and `SearchTrigger` (button that dispatches `clawport:open-search`)
|
|
210
|
+
|
|
211
|
+
**Key state:**
|
|
212
|
+
- `query` (useState) -- search input text
|
|
213
|
+
- `results` (useState) -- filtered search results
|
|
214
|
+
- `selectedIndex` (useState) -- keyboard navigation position
|
|
215
|
+
- `agents` / `crons` (useState) -- fetched on open
|
|
216
|
+
|
|
217
|
+
**Implementation:**
|
|
218
|
+
- Fetches agents and crons from API when modal opens
|
|
219
|
+
- Fuzzy matching: checks if query characters appear in order within result label (case-insensitive)
|
|
220
|
+
- Results grouped by type: agents, pages (hardcoded list), crons
|
|
221
|
+
- Keyboard navigation: ArrowUp/ArrowDown to move, Enter to select, Escape to close
|
|
222
|
+
- Navigates via `router.push()` on selection
|
|
223
|
+
- Global keyboard listener for Cmd+K / Ctrl+K to open
|
|
224
|
+
|
|
225
|
+
**Used by:** `components/Sidebar.tsx`
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
### DynamicFavicon
|
|
230
|
+
|
|
231
|
+
**File:** `components/DynamicFavicon.tsx`
|
|
232
|
+
**Purpose:** Generates and applies a dynamic favicon from the portal emoji or uploaded icon image.
|
|
233
|
+
|
|
234
|
+
**Props:** None (renders `null`)
|
|
235
|
+
|
|
236
|
+
**Key state:** None (effect-only component)
|
|
237
|
+
|
|
238
|
+
**Implementation:**
|
|
239
|
+
- Uses Canvas API to draw favicon onto a 64x64 canvas
|
|
240
|
+
- If `portalIcon` (uploaded image): draws the image scaled to fill the canvas
|
|
241
|
+
- If `portalEmoji`: draws a colored circle background (using accent color) and renders the emoji as centered text
|
|
242
|
+
- If `iconBgHidden`: skips the circle background for emoji mode
|
|
243
|
+
- Converts canvas to PNG data URL and sets it on a `<link rel="icon">` element
|
|
244
|
+
- Re-runs when `portalEmoji`, `portalIcon`, `accentColor`, `iconBgHidden`, or `emojiOnly` change
|
|
245
|
+
|
|
246
|
+
**Used by:** `app/layout.tsx`
|
|
247
|
+
|
|
248
|
+
---
|
|
249
|
+
|
|
250
|
+
### ThemeToggle
|
|
251
|
+
|
|
252
|
+
**File:** `components/ThemeToggle.tsx`
|
|
253
|
+
**Purpose:** Theme selector rendered as a row of emoji buttons with radiogroup semantics.
|
|
254
|
+
|
|
255
|
+
**Props:** None
|
|
256
|
+
|
|
257
|
+
**Key state:** None (reads from `useTheme()`)
|
|
258
|
+
|
|
259
|
+
**Implementation:**
|
|
260
|
+
- Renders one button per theme with emoji indicators
|
|
261
|
+
- Uses `role="radiogroup"` and `aria-checked` for accessibility
|
|
262
|
+
- Arrow key navigation (left/right) cycles through themes
|
|
263
|
+
- Highlights active theme with accent-colored border
|
|
264
|
+
- Themes: dark, glass, color, light, system
|
|
265
|
+
|
|
266
|
+
**Used by:** `components/Sidebar.tsx`, `components/MobileSidebar.tsx`
|
|
267
|
+
|
|
268
|
+
---
|
|
269
|
+
|
|
270
|
+
### Breadcrumbs
|
|
271
|
+
|
|
272
|
+
**File:** `components/Breadcrumbs.tsx`
|
|
273
|
+
**Purpose:** Breadcrumb navigation bar with Lucide ChevronRight separators.
|
|
274
|
+
|
|
275
|
+
| Prop | Type | Required | Description |
|
|
276
|
+
|------|------|----------|-------------|
|
|
277
|
+
| items | `BreadcrumbItem[]` | Yes | Breadcrumb segments |
|
|
278
|
+
|
|
279
|
+
```ts
|
|
280
|
+
interface BreadcrumbItem {
|
|
281
|
+
label: string
|
|
282
|
+
href?: string // If present, renders as Link; otherwise plain text
|
|
283
|
+
icon?: LucideIcon
|
|
284
|
+
}
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
**Implementation:**
|
|
288
|
+
- Last item rendered as plain text (current page), all others as Next.js `Link`
|
|
289
|
+
- Optional Lucide icon rendered before each label
|
|
290
|
+
- Styled with `--text-secondary` and `--text-primary` CSS vars
|
|
291
|
+
|
|
292
|
+
**Used by:** `app/agents/[id]/page.tsx`
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### ErrorState
|
|
297
|
+
|
|
298
|
+
**File:** `components/ErrorState.tsx`
|
|
299
|
+
**Purpose:** Full-screen error display with optional retry button.
|
|
300
|
+
|
|
301
|
+
| Prop | Type | Required | Description |
|
|
302
|
+
|------|------|----------|-------------|
|
|
303
|
+
| message | `string` | Yes | Error message to display |
|
|
304
|
+
| onRetry | `() => void` | No | If provided, shows a retry button |
|
|
305
|
+
|
|
306
|
+
**Implementation:**
|
|
307
|
+
- Centered layout with warning icon, message text, and optional retry button
|
|
308
|
+
- Uses CSS vars for theming
|
|
309
|
+
|
|
310
|
+
**Used by:** `app/page.tsx`, `app/chat/page.tsx`, `app/crons/page.tsx`
|
|
311
|
+
|
|
312
|
+
---
|
|
313
|
+
|
|
314
|
+
### AgentAvatar
|
|
315
|
+
|
|
316
|
+
**File:** `components/AgentAvatar.tsx`
|
|
317
|
+
**Purpose:** Renders an agent's avatar as a profile image, emoji on colored background, or emoji-only (transparent background).
|
|
318
|
+
|
|
319
|
+
| Prop | Type | Required | Description |
|
|
320
|
+
|------|------|----------|-------------|
|
|
321
|
+
| agent | `Agent` | Yes | Agent data object |
|
|
322
|
+
| size | `number` | Yes | Avatar dimensions in pixels |
|
|
323
|
+
| borderRadius | `number` | No | Border radius (default: 12) |
|
|
324
|
+
| style | `CSSProperties` | No | Additional inline styles |
|
|
325
|
+
|
|
326
|
+
**Key state:** None
|
|
327
|
+
|
|
328
|
+
**Implementation:**
|
|
329
|
+
- Uses `useSettings().getAgentDisplay(agent)` to resolve display overrides (custom emoji/image per agent)
|
|
330
|
+
- Three render modes:
|
|
331
|
+
1. **Profile image** (agent has `profileImage` or override image): renders `<img>` with object-fit cover
|
|
332
|
+
2. **Emoji on background**: renders emoji text centered on a colored circle (agent's `color` or override)
|
|
333
|
+
3. **Emoji only** (`emojiOnly` setting): renders emoji with transparent background
|
|
334
|
+
- Background color comes from agent definition or per-agent override
|
|
335
|
+
|
|
336
|
+
**Used by:** `components/AgentNode.tsx`, `components/GridView.tsx`, `components/chat/AgentList.tsx`, `components/kanban/TicketCard.tsx`, `components/kanban/AgentPicker.tsx`, `app/agents/[id]/page.tsx`, `app/settings/page.tsx`, `app/page.tsx`
|
|
337
|
+
|
|
338
|
+
---
|
|
339
|
+
|
|
340
|
+
## Onboarding
|
|
341
|
+
|
|
342
|
+
### OnboardingWizard
|
|
343
|
+
|
|
344
|
+
**File:** `components/OnboardingWizard.tsx`
|
|
345
|
+
**Purpose:** Five-step first-run setup wizard for configuring portal name, theme, accent color, voice chat, and feature overview.
|
|
346
|
+
|
|
347
|
+
| Prop | Type | Required | Description |
|
|
348
|
+
|------|------|----------|-------------|
|
|
349
|
+
| forceOpen | `boolean` | No | If true, opens regardless of onboarding state; pre-populates from current settings |
|
|
350
|
+
| onClose | `() => void` | No | Callback when wizard closes (used with forceOpen from settings page) |
|
|
351
|
+
|
|
352
|
+
**Key state:**
|
|
353
|
+
- `step` (useState) -- current wizard step (0-4)
|
|
354
|
+
- `show` (useState) -- visibility flag
|
|
355
|
+
- `name` / `subtitle` / `emoji` / `operatorName` (useState) -- form fields for step 0
|
|
356
|
+
- `selectedTheme` (useState) -- theme choice for step 1
|
|
357
|
+
- `selectedAccent` (useState) -- accent color for step 2
|
|
358
|
+
- `micStatus` (useState) -- microphone permission state for step 3 (`'idle' | 'requesting' | 'granted' | 'denied' | 'error'`)
|
|
359
|
+
- `micLevel` (useState) -- real-time audio level for mic test visualization
|
|
360
|
+
|
|
361
|
+
**Steps:**
|
|
362
|
+
1. **Welcome** (step 0) -- Portal name, subtitle, emoji picker, operator name. Live sidebar preview showing how NavLinks will look.
|
|
363
|
+
2. **Theme** (step 1) -- Theme grid with preview cards. Applies theme live via `setTheme()`.
|
|
364
|
+
3. **Accent Color** (step 2) -- Color preset grid (12 colors). Applies live via `setAccentColor()`.
|
|
365
|
+
4. **Voice Chat** (step 3) -- Microphone permission test. Uses Web Audio API (`AudioContext` + `AnalyserNode`) to capture real-time audio levels and display a pulsing circle visualization.
|
|
366
|
+
5. **Overview** (step 4) -- Feature summary cards (Agent Map, Chat, Kanban, Crons, Memory).
|
|
367
|
+
|
|
368
|
+
**Implementation:**
|
|
369
|
+
- First-run detection: checks `localStorage('clawport-onboarded')`
|
|
370
|
+
- When `forceOpen` is true: pre-populates all fields from current settings, does NOT set `clawport-onboarded` on completion
|
|
371
|
+
- Normal completion: sets `clawport-onboarded` in localStorage and saves all settings
|
|
372
|
+
- Modal overlay with backdrop blur, step indicator dots, back/next/finish navigation
|
|
373
|
+
- Mic test cleans up audio stream and context on unmount or step change
|
|
374
|
+
|
|
375
|
+
**Used by:** `app/layout.tsx` (always mounted, self-hides), `app/settings/page.tsx` (via forceOpen)
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
## Map / Home Page Components
|
|
380
|
+
|
|
381
|
+
### OrgMap
|
|
382
|
+
|
|
383
|
+
**File:** `components/OrgMap.tsx`
|
|
384
|
+
**Purpose:** React Flow org chart visualization of the agent hierarchy with interactive node selection.
|
|
385
|
+
|
|
386
|
+
| Prop | Type | Required | Description |
|
|
387
|
+
|------|------|----------|-------------|
|
|
388
|
+
| agents | `Agent[]` | Yes | All agents to render |
|
|
389
|
+
| crons | `CronJob[]` | Yes | Cron jobs (for status indicators) |
|
|
390
|
+
| selectedId | `string \| null` | Yes | Currently selected agent ID |
|
|
391
|
+
| onNodeClick | `(agent: Agent) => void` | Yes | Callback when a node is clicked |
|
|
392
|
+
|
|
393
|
+
**Key state:**
|
|
394
|
+
- `nodes` / `edges` (useState) -- React Flow node and edge arrays
|
|
395
|
+
- `highlightedEdges` (derived) -- edges connected to selected node
|
|
396
|
+
|
|
397
|
+
**Implementation:**
|
|
398
|
+
- BFS-based hierarchical layout: starts from root agent (`reportsTo` is null/undefined), assigns x/y positions by level
|
|
399
|
+
- Horizontal spacing: 280px, vertical spacing: 160px
|
|
400
|
+
- Each node rendered as custom `AgentNode` component (registered via `nodeTypes`)
|
|
401
|
+
- Edge highlighting: when an agent is selected, its connected edges get accent color + increased width
|
|
402
|
+
- Non-highlighted edges fade to 20% opacity
|
|
403
|
+
- Uses `ReactFlow` with `fitView`, `panOnScroll`, and zoom controls
|
|
404
|
+
- Dynamically imported in `app/page.tsx` with `{ ssr: false }` to avoid SSR issues with React Flow
|
|
405
|
+
|
|
406
|
+
**Used by:** `app/page.tsx` (HomePage, map view)
|
|
407
|
+
|
|
408
|
+
---
|
|
409
|
+
|
|
410
|
+
### AgentNode
|
|
411
|
+
|
|
412
|
+
**File:** `components/AgentNode.tsx`
|
|
413
|
+
**Purpose:** Custom React Flow node component displaying agent avatar, name, title, and status.
|
|
414
|
+
|
|
415
|
+
| Prop | Type | Required | Description |
|
|
416
|
+
|------|------|----------|-------------|
|
|
417
|
+
| data | `AgentNodeData` | Yes | Node data (passed by React Flow) |
|
|
418
|
+
|
|
419
|
+
```ts
|
|
420
|
+
interface AgentNodeData {
|
|
421
|
+
agent: Agent
|
|
422
|
+
selected: boolean
|
|
423
|
+
cronHealth?: 'ok' | 'error' | 'idle'
|
|
424
|
+
}
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**Implementation:**
|
|
428
|
+
- Renders AgentAvatar (48px) with name, title, and optional description truncated to 2 lines
|
|
429
|
+
- Selected state: accent-colored border and subtle glow effect
|
|
430
|
+
- Cron health indicator: colored dot (green/red/gray) in top-right corner
|
|
431
|
+
- Uses React Flow `Handle` components for source (bottom) and target (top) connections
|
|
432
|
+
- Exports `nodeTypes = { agentNode: AgentNode }` for React Flow registration
|
|
433
|
+
|
|
434
|
+
**Used by:** `components/OrgMap.tsx`
|
|
435
|
+
|
|
436
|
+
---
|
|
437
|
+
|
|
438
|
+
### GridView
|
|
439
|
+
|
|
440
|
+
**File:** `components/GridView.tsx`
|
|
441
|
+
**Purpose:** Card-based grid layout with team grouping hierarchy.
|
|
442
|
+
|
|
443
|
+
| Prop | Type | Required | Description |
|
|
444
|
+
|------|------|----------|-------------|
|
|
445
|
+
| agents | `Agent[]` | Yes | All agents |
|
|
446
|
+
| crons | `CronJob[]` | Yes | Cron jobs for status |
|
|
447
|
+
| selectedId | `string \| null` | Yes | Currently selected agent |
|
|
448
|
+
| onSelect | `(agent: Agent) => void` | Yes | Selection callback |
|
|
449
|
+
|
|
450
|
+
**Implementation:**
|
|
451
|
+
- Builds team hierarchy: identifies "hero" agent (root with no `reportsTo`), groups agents by their `reportsTo` manager, separates solo operators (no reports and not reporting to anyone besides hero)
|
|
452
|
+
- Contains inline `AgentCard` component: renders avatar, name, title, description, cron health dot, and status badge
|
|
453
|
+
- Contains inline `TeamSection` component: collapsible team group with manager header
|
|
454
|
+
- Selected card gets accent border highlight
|
|
455
|
+
- Responsive grid: 1 col mobile, 2 cols md, 3 cols lg
|
|
456
|
+
|
|
457
|
+
**Used by:** `app/page.tsx` (HomePage, grid view)
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
### FeedView
|
|
462
|
+
|
|
463
|
+
**File:** `components/FeedView.tsx`
|
|
464
|
+
**Purpose:** Activity feed focused on cron job status with stat cards and filter pills.
|
|
465
|
+
|
|
466
|
+
| Prop | Type | Required | Description |
|
|
467
|
+
|------|------|----------|-------------|
|
|
468
|
+
| agents | `Agent[]` | Yes | All agents |
|
|
469
|
+
| crons | `CronJob[]` | Yes | Cron jobs to display |
|
|
470
|
+
| selectedId | `string \| null` | Yes | Currently selected agent |
|
|
471
|
+
| onSelect | `(agent: Agent) => void` | Yes | Selection callback |
|
|
472
|
+
|
|
473
|
+
**Key state:**
|
|
474
|
+
- `filter` (useState) -- `'all' | 'ok' | 'error' | 'idle'`
|
|
475
|
+
|
|
476
|
+
**Implementation:**
|
|
477
|
+
- Top stat cards: total crons, healthy count, errors count, idle count
|
|
478
|
+
- Filter pills toggle which crons are shown
|
|
479
|
+
- Crons sorted by status priority (errors first) then by `lastRun` descending
|
|
480
|
+
- Each cron row shows: agent avatar, cron name, schedule, status badge, last run time
|
|
481
|
+
- Contains inline `StatusBadge` and `StatCard` helper components
|
|
482
|
+
- Clicking a cron row selects its associated agent
|
|
483
|
+
|
|
484
|
+
**Used by:** `app/page.tsx` (HomePage, feed view)
|
|
485
|
+
|
|
486
|
+
---
|
|
487
|
+
|
|
488
|
+
## Chat Components
|
|
489
|
+
|
|
490
|
+
### ConversationView
|
|
491
|
+
|
|
492
|
+
**File:** `components/chat/ConversationView.tsx`
|
|
493
|
+
**Purpose:** Main chat interface with message rendering, SSE streaming, file attachments, TTS playback, and markdown formatting.
|
|
494
|
+
|
|
495
|
+
| Prop | Type | Required | Description |
|
|
496
|
+
|------|------|----------|-------------|
|
|
497
|
+
| agent | `Agent` | Yes | The agent being chatted with |
|
|
498
|
+
| conversation | `Conversation` | Yes | Current conversation data |
|
|
499
|
+
| onUpdate | `(conv: Conversation) => void` | Yes | Callback when conversation changes |
|
|
500
|
+
| onBack | `() => void` | No | Mobile back button callback |
|
|
501
|
+
|
|
502
|
+
**Key state:**
|
|
503
|
+
- `input` (useState) -- text input value
|
|
504
|
+
- `isStreaming` (useState) -- whether an SSE response is in progress
|
|
505
|
+
- `streamingText` (useState) -- accumulated streaming response text
|
|
506
|
+
- `attachments` (useState) -- staged `MediaAttachment[]` before send
|
|
507
|
+
- `isRecording` (useState) -- voice recording active
|
|
508
|
+
- `ttsPlaying` (useState) -- message ID currently playing TTS
|
|
509
|
+
- `ttsLoading` (useState) -- message ID currently loading TTS
|
|
510
|
+
|
|
511
|
+
**Implementation:**
|
|
512
|
+
- **SSE streaming:** POST to `/api/chat/[id]` with `ReadableStream` reader. Parses `data:` lines, accumulates text, calls `onUpdate` with final message.
|
|
513
|
+
- **Markdown rendering:** Inline `renderMarkdown()` function handles bold, italic, inline code, code blocks with language labels and copy buttons, links, and bullet lists.
|
|
514
|
+
- **TTS playback:** Sends message text to `/api/tts`, receives audio blob, plays via `Audio` object. Toggle play/stop per message.
|
|
515
|
+
- **File attachments:** Three input methods -- paste (Cmd+V), drag-and-drop, and file picker button. Images resized to 1200px max via Canvas API (`resizeImage` helper). Files converted to base64 data URLs for persistence.
|
|
516
|
+
- **Voice recording:** Uses `createAudioRecorder()` from `lib/audio-recorder.ts`. Records audio, captures waveform, transcribes via `/api/transcribe`, sends transcription as message. Stores audio data URL + waveform for playback.
|
|
517
|
+
- **Auto-scroll:** `useEffect` scrolls to bottom on new messages or streaming updates.
|
|
518
|
+
- **operatorName:** Sends `operatorName` from settings context in POST body for system prompt injection.
|
|
519
|
+
|
|
520
|
+
**Used by:** `app/chat/page.tsx` (ChatPage)
|
|
521
|
+
|
|
522
|
+
---
|
|
523
|
+
|
|
524
|
+
### AgentList / AgentListMobile
|
|
525
|
+
|
|
526
|
+
**File:** `components/chat/AgentList.tsx`
|
|
527
|
+
**Purpose:** Agent selection sidebar for chat. Two exports: `AgentList` (desktop, 300px fixed sidebar) and `AgentListMobile` (full-width, shown on mobile when no agent is selected).
|
|
528
|
+
|
|
529
|
+
| Prop | Type | Required | Description |
|
|
530
|
+
|------|------|----------|-------------|
|
|
531
|
+
| agents | `Agent[]` | Yes | Available agents |
|
|
532
|
+
| conversations | `Map<string, Conversation>` | Yes | All conversations (for previews/timestamps) |
|
|
533
|
+
| activeId | `string \| null` | Yes | Currently selected agent ID |
|
|
534
|
+
| onSelect | `(agent: Agent) => void` | Yes | Selection callback |
|
|
535
|
+
| loading | `boolean` | No | Show skeleton loading state |
|
|
536
|
+
|
|
537
|
+
**Key state:**
|
|
538
|
+
- `search` (useState) -- filter text for agent search
|
|
539
|
+
|
|
540
|
+
**Implementation:**
|
|
541
|
+
- Agents sorted by last activity (most recent conversation first), then alphabetically
|
|
542
|
+
- Each row shows: AgentAvatar, agent name, title, last message preview (truncated), relative timestamp
|
|
543
|
+
- Unread badge: green dot when conversation has unread messages
|
|
544
|
+
- Online status dot: always green (placeholder for future live status)
|
|
545
|
+
- Search filters by agent name or title (case-insensitive)
|
|
546
|
+
- Desktop variant: fixed 300px sidebar with border-right separator
|
|
547
|
+
- Mobile variant: full-width list, hidden when an agent is selected
|
|
548
|
+
|
|
549
|
+
**Used by:** `app/chat/page.tsx` (ChatPage)
|
|
550
|
+
|
|
551
|
+
---
|
|
552
|
+
|
|
553
|
+
### VoiceMessage
|
|
554
|
+
|
|
555
|
+
**File:** `components/chat/VoiceMessage.tsx`
|
|
556
|
+
**Purpose:** Audio waveform playback component with play/pause toggle and animated progress visualization.
|
|
557
|
+
|
|
558
|
+
| Prop | Type | Required | Description |
|
|
559
|
+
|------|------|----------|-------------|
|
|
560
|
+
| src | `string` | Yes | Audio source URL (base64 data URL) |
|
|
561
|
+
| duration | `number` | Yes | Duration in seconds |
|
|
562
|
+
| waveform | `number[]` | Yes | Amplitude samples (40-60 values, 0-1 range) |
|
|
563
|
+
| isUser | `boolean` | Yes | Whether this is the user's message (affects color) |
|
|
564
|
+
|
|
565
|
+
**Key state:**
|
|
566
|
+
- `isPlaying` (useState) -- playback state
|
|
567
|
+
- `progress` (useState) -- playback progress (0-1)
|
|
568
|
+
- `audioRef` (useRef) -- HTMLAudioElement reference
|
|
569
|
+
|
|
570
|
+
**Implementation:**
|
|
571
|
+
- Renders amplitude bars as vertical `<div>` elements with heights proportional to waveform values
|
|
572
|
+
- Progress tracking: bars before the playback position get accent color, bars after get muted color
|
|
573
|
+
- Uses `timeupdate` event on `<audio>` element to update progress
|
|
574
|
+
- Play/pause toggle with Lucide Play/Pause icons
|
|
575
|
+
- Duration display formatted as `m:ss`
|
|
576
|
+
|
|
577
|
+
**Used by:** `components/chat/ConversationView.tsx`
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
### FileAttachment
|
|
582
|
+
|
|
583
|
+
**File:** `components/chat/FileAttachment.tsx`
|
|
584
|
+
**Purpose:** File attachment bubble with type-specific icon and download button.
|
|
585
|
+
|
|
586
|
+
| Prop | Type | Required | Description |
|
|
587
|
+
|------|------|----------|-------------|
|
|
588
|
+
| name | `string` | Yes | File name |
|
|
589
|
+
| size | `number` | No | File size in bytes |
|
|
590
|
+
| mimeType | `string` | No | MIME type for icon selection |
|
|
591
|
+
| url | `string` | Yes | Download URL (base64 data URL) |
|
|
592
|
+
| isUser | `boolean` | Yes | Whether this is the user's message (affects color) |
|
|
593
|
+
|
|
594
|
+
**Implementation:**
|
|
595
|
+
- Type-specific SVG icons: PDF (red), document (blue), text (gray), archive (yellow), generic (gray)
|
|
596
|
+
- Icon selected by MIME type matching
|
|
597
|
+
- File size formatted as human-readable (B, KB, MB)
|
|
598
|
+
- Download button creates a temporary `<a>` element with `download` attribute
|
|
599
|
+
- Styled differently for user vs assistant messages
|
|
600
|
+
|
|
601
|
+
**Used by:** `components/chat/ConversationView.tsx`
|
|
602
|
+
|
|
603
|
+
---
|
|
604
|
+
|
|
605
|
+
### MediaPreview
|
|
606
|
+
|
|
607
|
+
**File:** `components/chat/MediaPreview.tsx`
|
|
608
|
+
**Purpose:** Horizontal strip of staged attachment thumbnails shown below the chat input before sending.
|
|
609
|
+
|
|
610
|
+
| Prop | Type | Required | Description |
|
|
611
|
+
|------|------|----------|-------------|
|
|
612
|
+
| attachments | `MediaAttachment[]` | Yes | Staged attachments to preview |
|
|
613
|
+
| onRemove | `(index: number) => void` | Yes | Callback to remove an attachment by index |
|
|
614
|
+
|
|
615
|
+
**Implementation:**
|
|
616
|
+
- Horizontal scroll container with gap between items
|
|
617
|
+
- Images: renders thumbnail preview with object-fit cover
|
|
618
|
+
- Non-images: renders file icon with name and size
|
|
619
|
+
- Each item has an X button overlay for removal
|
|
620
|
+
- Thumbnails sized at 80x80px with rounded corners
|
|
621
|
+
|
|
622
|
+
**Used by:** `components/chat/ConversationView.tsx`
|
|
623
|
+
|
|
624
|
+
---
|
|
625
|
+
|
|
626
|
+
## Kanban Components
|
|
627
|
+
|
|
628
|
+
### KanbanBoard
|
|
629
|
+
|
|
630
|
+
**File:** `components/kanban/KanbanBoard.tsx`
|
|
631
|
+
**Purpose:** Renders the kanban board as a row of columns with ticket cards.
|
|
632
|
+
|
|
633
|
+
| Prop | Type | Required | Description |
|
|
634
|
+
|------|------|----------|-------------|
|
|
635
|
+
| tickets | `KanbanTicket[]` | Yes | All tickets |
|
|
636
|
+
| agents | `Agent[]` | Yes | All agents (for avatar rendering) |
|
|
637
|
+
| onTicketClick | `(ticket: KanbanTicket) => void` | Yes | Ticket selection callback |
|
|
638
|
+
| onMoveTicket | `(ticketId: string, status: string) => void` | Yes | Ticket move callback |
|
|
639
|
+
| onCreateTicket | `(status: string) => void` | Yes | Create ticket callback |
|
|
640
|
+
| isWorking | `(ticketId: string) => boolean` | No | Whether a ticket has active agent work |
|
|
641
|
+
| filterAgentId | `string \| null` | No | Filter tickets to a specific agent |
|
|
642
|
+
|
|
643
|
+
**Implementation:**
|
|
644
|
+
- Four columns: Backlog, In Progress, Review, Done
|
|
645
|
+
- Filters tickets by `filterAgentId` if set
|
|
646
|
+
- Groups tickets into columns by `status` field
|
|
647
|
+
- Each column rendered as `KanbanColumn` with `TicketCard` children
|
|
648
|
+
- Horizontal scroll on mobile with `overflow-x-auto`
|
|
649
|
+
|
|
650
|
+
**Used by:** `app/kanban/page.tsx`
|
|
651
|
+
|
|
652
|
+
---
|
|
653
|
+
|
|
654
|
+
### KanbanColumn
|
|
655
|
+
|
|
656
|
+
**File:** `components/kanban/KanbanColumn.tsx`
|
|
657
|
+
**Purpose:** Single kanban column with drag-and-drop support.
|
|
658
|
+
|
|
659
|
+
| Prop | Type | Required | Description |
|
|
660
|
+
|------|------|----------|-------------|
|
|
661
|
+
| column | `{ id: string; title: string }` | Yes | Column metadata |
|
|
662
|
+
| tickets | `KanbanTicket[]` | Yes | Tickets in this column |
|
|
663
|
+
| agents | `Agent[]` | Yes | All agents |
|
|
664
|
+
| onTicketClick | `(ticket: KanbanTicket) => void` | Yes | Ticket click callback |
|
|
665
|
+
| onDrop | `(ticketId: string) => void` | Yes | Drop callback (ticket moved to this column) |
|
|
666
|
+
| onCreateTicket | `() => void` | No | Create ticket callback (shown in backlog column) |
|
|
667
|
+
| renderTicket | `(ticket: KanbanTicket) => ReactNode` | Yes | Ticket render function |
|
|
668
|
+
|
|
669
|
+
**Key state:**
|
|
670
|
+
- `dragOver` (useState) -- whether a ticket is being dragged over this column
|
|
671
|
+
|
|
672
|
+
**Implementation:**
|
|
673
|
+
- Column header with title, ticket count badge, and optional + button (backlog only)
|
|
674
|
+
- HTML5 drag-and-drop: `onDragOver` sets visual feedback, `onDrop` extracts ticket ID from `dataTransfer`
|
|
675
|
+
- Drop zone highlight: accent-colored border when dragging over
|
|
676
|
+
- Scrollable ticket list with vertical overflow
|
|
677
|
+
|
|
678
|
+
**Used by:** `components/kanban/KanbanBoard.tsx`
|
|
679
|
+
|
|
680
|
+
---
|
|
681
|
+
|
|
682
|
+
### TicketCard
|
|
683
|
+
|
|
684
|
+
**File:** `components/kanban/TicketCard.tsx`
|
|
685
|
+
**Purpose:** Draggable ticket card displaying ticket metadata and agent assignment.
|
|
686
|
+
|
|
687
|
+
| Prop | Type | Required | Description |
|
|
688
|
+
|------|------|----------|-------------|
|
|
689
|
+
| ticket | `KanbanTicket` | Yes | Ticket data |
|
|
690
|
+
| agent | `Agent \| undefined` | Yes | Assigned agent (if any) |
|
|
691
|
+
| onClick | `() => void` | Yes | Click callback |
|
|
692
|
+
| isWorking | `boolean` | No | Whether agent work is in progress |
|
|
693
|
+
|
|
694
|
+
**Implementation:**
|
|
695
|
+
- HTML5 draggable: sets `ticketId` in `dataTransfer` on drag start
|
|
696
|
+
- Visual elements: priority dot (color-coded: red=urgent, orange=high, blue=medium, gray=low), title, description preview (truncated), assigned agent avatar + name, role badge, relative timestamp
|
|
697
|
+
- Work state indicator: pulsing dot and "Working..." label when `isWorking` is true
|
|
698
|
+
- Opacity reduction during drag
|
|
699
|
+
|
|
700
|
+
**Used by:** `components/kanban/KanbanBoard.tsx` (via `KanbanColumn`)
|
|
701
|
+
|
|
702
|
+
---
|
|
703
|
+
|
|
704
|
+
### TicketDetailPanel
|
|
705
|
+
|
|
706
|
+
**File:** `components/kanban/TicketDetailPanel.tsx`
|
|
707
|
+
**Purpose:** Slide-in side panel for viewing ticket details and chatting with the assigned agent about the ticket.
|
|
708
|
+
|
|
709
|
+
| Prop | Type | Required | Description |
|
|
710
|
+
|------|------|----------|-------------|
|
|
711
|
+
| ticket | `KanbanTicket` | Yes | Ticket to display |
|
|
712
|
+
| agent | `Agent \| undefined` | Yes | Assigned agent |
|
|
713
|
+
| onClose | `() => void` | Yes | Close callback |
|
|
714
|
+
| onStatusChange | `(status: string) => void` | Yes | Status change callback |
|
|
715
|
+
| onDelete | `() => void` | Yes | Delete callback |
|
|
716
|
+
| onRetryWork | `() => void` | No | Retry agent work callback |
|
|
717
|
+
|
|
718
|
+
**Key state:**
|
|
719
|
+
- `chatMessages` (useState) -- inline chat message history
|
|
720
|
+
- `chatInput` (useState) -- chat input text
|
|
721
|
+
- `isStreaming` (useState) -- SSE response in progress
|
|
722
|
+
- `streamingText` (useState) -- accumulated response text
|
|
723
|
+
- `expanded` (useState) -- panel width toggle (narrow/wide)
|
|
724
|
+
|
|
725
|
+
**Implementation:**
|
|
726
|
+
- Slide-in panel from right side (400px default, 600px expanded)
|
|
727
|
+
- Header: ticket title, priority badge, expand/collapse toggle, close button
|
|
728
|
+
- Ticket details: description, status selector (dropdown), assigned agent, role, timestamps
|
|
729
|
+
- Work result section: shows agent work output if available, with retry button
|
|
730
|
+
- Inline chat: SSE streaming to `/api/chat/[id]`, markdown rendering (bold, italic, code, code blocks, links, lists)
|
|
731
|
+
- Status selector: dropdown with all column statuses
|
|
732
|
+
- Delete button with confirmation (red styling)
|
|
733
|
+
|
|
734
|
+
**Used by:** `app/kanban/page.tsx`
|
|
735
|
+
|
|
736
|
+
---
|
|
737
|
+
|
|
738
|
+
### CreateTicketModal
|
|
739
|
+
|
|
740
|
+
**File:** `components/kanban/CreateTicketModal.tsx`
|
|
741
|
+
**Purpose:** Modal dialog for creating new kanban tickets with title, description, priority, agent assignment, and role.
|
|
742
|
+
|
|
743
|
+
| Prop | Type | Required | Description |
|
|
744
|
+
|------|------|----------|-------------|
|
|
745
|
+
| open | `boolean` | Yes | Whether the modal is visible |
|
|
746
|
+
| onOpenChange | `(open: boolean) => void` | Yes | Visibility change callback |
|
|
747
|
+
| agents | `Agent[]` | Yes | Available agents for assignment |
|
|
748
|
+
| onSubmit | `(data: CreateTicketData) => void` | Yes | Form submission callback |
|
|
749
|
+
|
|
750
|
+
**Key state:**
|
|
751
|
+
- `title` / `description` (useState) -- form fields
|
|
752
|
+
- `priority` (useState) -- `'low' | 'medium' | 'high' | 'urgent'`
|
|
753
|
+
- `agentId` (useState) -- assigned agent ID
|
|
754
|
+
- `role` (useState) -- `'executor' | 'reviewer' | 'consultant'`
|
|
755
|
+
|
|
756
|
+
**Implementation:**
|
|
757
|
+
- Uses Radix Dialog (`components/ui/dialog`) for modal behavior
|
|
758
|
+
- Priority selector: four buttons with color-coded dots
|
|
759
|
+
- Agent assignment: uses `AgentPicker` component
|
|
760
|
+
- Role selector: three buttons (Executor, Reviewer, Consultant)
|
|
761
|
+
- Form resets on close
|
|
762
|
+
- Submit disabled when title is empty
|
|
763
|
+
|
|
764
|
+
**Used by:** `app/kanban/page.tsx`
|
|
765
|
+
|
|
766
|
+
---
|
|
767
|
+
|
|
768
|
+
### AgentPicker
|
|
769
|
+
|
|
770
|
+
**File:** `components/kanban/AgentPicker.tsx`
|
|
771
|
+
**Purpose:** Custom dropdown selector for choosing an agent, with search and keyboard navigation.
|
|
772
|
+
|
|
773
|
+
| Prop | Type | Required | Description |
|
|
774
|
+
|------|------|----------|-------------|
|
|
775
|
+
| agents | `Agent[]` | Yes | Available agents |
|
|
776
|
+
| value | `string \| null` | Yes | Selected agent ID |
|
|
777
|
+
| onChange | `(agentId: string \| null) => void` | Yes | Selection callback |
|
|
778
|
+
|
|
779
|
+
**Key state:**
|
|
780
|
+
- `open` (useState) -- dropdown visibility
|
|
781
|
+
- `search` (useState) -- filter text
|
|
782
|
+
- `highlightIndex` (useState) -- keyboard navigation position
|
|
783
|
+
|
|
784
|
+
**Implementation:**
|
|
785
|
+
- Trigger button shows selected agent's avatar + name, or "Unassigned"
|
|
786
|
+
- Dropdown with search input at top
|
|
787
|
+
- Keyboard navigation: ArrowUp/ArrowDown to move, Enter to select, Escape to close
|
|
788
|
+
- "Unassigned" option always shown first
|
|
789
|
+
- Filtered list shows agent avatar, name, and title
|
|
790
|
+
- Checkmark icon on selected agent
|
|
791
|
+
- Closes on selection or outside click
|
|
792
|
+
|
|
793
|
+
**Used by:** `components/kanban/CreateTicketModal.tsx`
|
|
794
|
+
|
|
795
|
+
---
|
|
796
|
+
|
|
797
|
+
## Cron Components
|
|
798
|
+
|
|
799
|
+
### WeeklySchedule
|
|
800
|
+
|
|
801
|
+
**File:** `components/crons/WeeklySchedule.tsx`
|
|
802
|
+
**Purpose:** Seven-day calendar grid showing when cron jobs are scheduled to run.
|
|
803
|
+
|
|
804
|
+
| Prop | Type | Required | Description |
|
|
805
|
+
|------|------|----------|-------------|
|
|
806
|
+
| crons | `CronJob[]` | Yes | Cron jobs to display |
|
|
807
|
+
|
|
808
|
+
**Key state:**
|
|
809
|
+
- `hoveredCron` (useState) -- cron ID for tooltip display
|
|
810
|
+
- `now` (useState) -- current time, updated every 60s for the time indicator
|
|
811
|
+
|
|
812
|
+
**Implementation:**
|
|
813
|
+
- 7-column grid (Mon-Sun) with hour rows for active schedule range
|
|
814
|
+
- Parses cron schedule expressions to determine which hours/days each cron runs
|
|
815
|
+
- Cron pills: colored bars positioned in the appropriate day/hour cells, using the assigned agent's color
|
|
816
|
+
- Status dots on pills: green (ok), red (error), gray (idle)
|
|
817
|
+
- Tooltip on hover: shows cron name, schedule expression, last run time, status
|
|
818
|
+
- Current time indicator: red horizontal line at the current hour position
|
|
819
|
+
- Hour labels on the left axis
|
|
820
|
+
|
|
821
|
+
**Used by:** `app/crons/page.tsx` (schedule tab)
|
|
822
|
+
|
|
823
|
+
---
|
|
824
|
+
|
|
825
|
+
### PipelineGraph
|
|
826
|
+
|
|
827
|
+
**File:** `components/crons/PipelineGraph.tsx`
|
|
828
|
+
**Purpose:** React Flow visualization of cron job pipelines showing dependencies between stages.
|
|
829
|
+
|
|
830
|
+
| Prop | Type | Required | Description |
|
|
831
|
+
|------|------|----------|-------------|
|
|
832
|
+
| crons | `CronJob[]` | Yes | Cron jobs to visualize |
|
|
833
|
+
|
|
834
|
+
**Implementation:**
|
|
835
|
+
- Groups crons into pipelines (crons with `pipeline` field) and standalone crons
|
|
836
|
+
- Topological layout: arranges pipeline stages left-to-right based on dependency order
|
|
837
|
+
- Contains inline `CronPipelineNode` custom React Flow node: shows cron name, schedule, agent, status badge
|
|
838
|
+
- Contains inline `StandaloneCrons` component: grid of non-pipeline crons
|
|
839
|
+
- Edges connect pipeline stages with animated flow indicators
|
|
840
|
+
- Node colors based on status: green (ok), red (error), gray (idle)
|
|
841
|
+
- Uses `ReactFlow` with `fitView` and pan/zoom controls
|
|
842
|
+
|
|
843
|
+
**Used by:** `app/crons/page.tsx` (pipelines tab)
|
|
844
|
+
|
|
845
|
+
---
|
|
846
|
+
|
|
847
|
+
## Page Components
|
|
848
|
+
|
|
849
|
+
### HomePage (Home)
|
|
850
|
+
|
|
851
|
+
**File:** `app/page.tsx`
|
|
852
|
+
**Purpose:** Main dashboard with three view modes (map, grid, feed) and agent detail side panel.
|
|
853
|
+
|
|
854
|
+
**Key state:**
|
|
855
|
+
- `agents` (useState) -- fetched from `/api/agents`
|
|
856
|
+
- `crons` (useState) -- fetched from `/api/crons`
|
|
857
|
+
- `selectedAgent` (useState) -- agent for detail panel
|
|
858
|
+
- `view` (useState) -- `'map' | 'grid' | 'feed'`
|
|
859
|
+
- `loading` / `error` (useState)
|
|
860
|
+
|
|
861
|
+
**Implementation:**
|
|
862
|
+
- View mode toggle: three icon buttons in header (Map, Grid, Activity)
|
|
863
|
+
- Map view: dynamically imports `OrgMap` with `{ ssr: false }`
|
|
864
|
+
- Grid view: renders `GridView`
|
|
865
|
+
- Feed view: renders `FeedView`
|
|
866
|
+
- Agent detail panel: slide-in from right (400px) showing avatar, name, title, description, tools list, hierarchy links, cron health
|
|
867
|
+
- Contains inline `StatusDot` and `MapSkeleton` helper components
|
|
868
|
+
|
|
869
|
+
**Used by:** Route `/`
|
|
870
|
+
|
|
871
|
+
---
|
|
872
|
+
|
|
873
|
+
### ChatPage
|
|
874
|
+
|
|
875
|
+
**File:** `app/chat/page.tsx`
|
|
876
|
+
**Purpose:** Full messaging interface with agent selection and conversation management.
|
|
877
|
+
|
|
878
|
+
**Key state:**
|
|
879
|
+
- `agents` (useState) -- fetched from `/api/agents`
|
|
880
|
+
- `conversations` (useState) -- `Map<string, Conversation>` from localStorage
|
|
881
|
+
- `activeAgent` (useState) -- currently selected agent
|
|
882
|
+
- `loading` / `error` (useState)
|
|
883
|
+
|
|
884
|
+
**Implementation:**
|
|
885
|
+
- Wraps `MessengerApp` in `Suspense` boundary
|
|
886
|
+
- `MessengerApp` reads `agent` query param to pre-select an agent
|
|
887
|
+
- Desktop: two-panel layout (AgentList sidebar + ConversationView)
|
|
888
|
+
- Mobile: shows AgentListMobile when no agent selected, ConversationView when agent selected (with back button)
|
|
889
|
+
- Conversations persisted to localStorage, keyed by agent ID
|
|
890
|
+
- Contains inline `EmptyState` component (shown when no agent selected on desktop)
|
|
891
|
+
|
|
892
|
+
**Used by:** Route `/chat`
|
|
893
|
+
|
|
894
|
+
---
|
|
895
|
+
|
|
896
|
+
### ChatRedirect
|
|
897
|
+
|
|
898
|
+
**File:** `app/chat/[id]/page.tsx`
|
|
899
|
+
**Purpose:** Simple redirect from `/chat/[id]` to `/chat?agent=[id]`.
|
|
900
|
+
|
|
901
|
+
**Implementation:**
|
|
902
|
+
- Server component that uses `redirect()` from Next.js
|
|
903
|
+
- Enables direct agent chat links
|
|
904
|
+
|
|
905
|
+
**Used by:** Route `/chat/[id]`
|
|
906
|
+
|
|
907
|
+
---
|
|
908
|
+
|
|
909
|
+
### AgentDetailPage
|
|
910
|
+
|
|
911
|
+
**File:** `app/agents/[id]/page.tsx`
|
|
912
|
+
**Purpose:** Full agent profile page with hero section, about card, tools, hierarchy, SOUL.md viewer, crons, and voice config.
|
|
913
|
+
|
|
914
|
+
**Key state:**
|
|
915
|
+
- `agent` (useState) -- fetched from `/api/agents`
|
|
916
|
+
- `crons` (useState) -- agent's cron jobs
|
|
917
|
+
- `soulContent` (useState) -- SOUL.md file contents
|
|
918
|
+
- `showSoul` (useState) -- SOUL.md viewer toggle
|
|
919
|
+
|
|
920
|
+
**Implementation:**
|
|
921
|
+
- Hero section: large avatar, name, title, description, "Chat" button linking to `/chat?agent=[id]`
|
|
922
|
+
- About card: agent description and metadata
|
|
923
|
+
- Tools card: list of agent tools/capabilities
|
|
924
|
+
- Hierarchy card: "Reports to" and "Direct reports" links to other agent pages
|
|
925
|
+
- SOUL.md viewer: collapsible panel showing agent's SOUL.md content with syntax highlighting
|
|
926
|
+
- Crons card: list of agent's cron jobs with status badges
|
|
927
|
+
- Voice config card: voice settings display
|
|
928
|
+
- Contains inline `SoulViewer`, `CopyButton`, `Card`, `DetailSkeleton`, `StatusDot` helper components
|
|
929
|
+
- Uses `Breadcrumbs` component for navigation
|
|
930
|
+
|
|
931
|
+
**Used by:** Route `/agents/[id]`
|
|
932
|
+
|
|
933
|
+
---
|
|
934
|
+
|
|
935
|
+
### KanbanPage
|
|
936
|
+
|
|
937
|
+
**File:** `app/kanban/page.tsx`
|
|
938
|
+
**Purpose:** Kanban board for managing agent work tickets with drag-and-drop, CRUD, and agent work integration.
|
|
939
|
+
|
|
940
|
+
**Key state:**
|
|
941
|
+
- `tickets` (useState) -- from `KanbanStore` (localStorage)
|
|
942
|
+
- `agents` (useState) -- fetched from `/api/agents`
|
|
943
|
+
- `selectedTicket` (useState) -- ticket for detail panel
|
|
944
|
+
- `showCreate` (useState) -- create modal visibility
|
|
945
|
+
- `filterAgentId` (useState) -- agent filter
|
|
946
|
+
- `agentWork` -- from `useAgentWork()` hook
|
|
947
|
+
|
|
948
|
+
**Implementation:**
|
|
949
|
+
- Agent filter bar: horizontal scroll of agent avatar buttons to filter by assignee
|
|
950
|
+
- Renders `KanbanBoard` with all tickets and agents
|
|
951
|
+
- `TicketDetailPanel` opens on ticket click
|
|
952
|
+
- `CreateTicketModal` for new ticket creation
|
|
953
|
+
- Ticket CRUD: create, move (status change), delete via `KanbanStore` methods
|
|
954
|
+
- Agent work: `useAgentWork()` hook manages sending tickets to agents for execution, polling for results
|
|
955
|
+
- Retry work: re-sends ticket to agent if previous work failed
|
|
956
|
+
|
|
957
|
+
**Used by:** Route `/kanban`
|
|
958
|
+
|
|
959
|
+
---
|
|
960
|
+
|
|
961
|
+
### CronsPage
|
|
962
|
+
|
|
963
|
+
**File:** `app/crons/page.tsx`
|
|
964
|
+
**Purpose:** Cron monitoring dashboard with three tabs (overview, schedule, pipelines).
|
|
965
|
+
|
|
966
|
+
**Key state:**
|
|
967
|
+
- `crons` (useState) -- fetched from `/api/crons`, auto-refreshes every 60s
|
|
968
|
+
- `agents` (useState) -- fetched from `/api/agents`
|
|
969
|
+
- `tab` (useState) -- `'overview' | 'schedule' | 'pipelines'`
|
|
970
|
+
- `filter` (useState) -- `'all' | 'ok' | 'error' | 'idle'`
|
|
971
|
+
- `loading` / `error` (useState)
|
|
972
|
+
|
|
973
|
+
**Implementation:**
|
|
974
|
+
- **Overview tab:** Health donut chart (SVG), attention-needed cards for errored crons, delivery stats, error banners, recent runs list (lazy-loaded)
|
|
975
|
+
- **Schedule tab:** `WeeklySchedule` component
|
|
976
|
+
- **Pipelines tab:** `PipelineGraph` component
|
|
977
|
+
- Contains many inline helpers:
|
|
978
|
+
- `HealthCard` -- SVG donut chart showing ok/error/idle proportions
|
|
979
|
+
- `AttentionCard` -- clickable cards for crons needing attention
|
|
980
|
+
- `DeliveryCard` -- delivery success rate stats
|
|
981
|
+
- `DeliveryBadge` -- color-coded status badge
|
|
982
|
+
- `ErrorsBanners` -- expandable error detail banners
|
|
983
|
+
- `RecentRuns` -- lazy-loaded recent run history
|
|
984
|
+
- Auto-refresh: `setInterval` every 60s re-fetches cron data
|
|
985
|
+
- Filter pills in overview tab filter the cron list
|
|
986
|
+
|
|
987
|
+
**Used by:** Route `/crons`
|
|
988
|
+
|
|
989
|
+
---
|
|
990
|
+
|
|
991
|
+
### MemoryPage
|
|
992
|
+
|
|
993
|
+
**File:** `app/memory/page.tsx`
|
|
994
|
+
**Purpose:** Two-panel memory file browser with search, navigation, and content viewer.
|
|
995
|
+
|
|
996
|
+
**Key state:**
|
|
997
|
+
- `files` (useState) -- fetched from `/api/memory`
|
|
998
|
+
- `selectedFile` (useState) -- currently viewed file
|
|
999
|
+
- `fileContent` (useState) -- content of selected file
|
|
1000
|
+
- `search` (useState) -- file search filter
|
|
1001
|
+
- `loading` (useState)
|
|
1002
|
+
|
|
1003
|
+
**Implementation:**
|
|
1004
|
+
- Left panel: file tree sidebar with search input, file list with icons, keyboard navigation (arrow keys, enter)
|
|
1005
|
+
- Right panel: content viewer with copy and download buttons
|
|
1006
|
+
- Markdown files: rendered with basic markdown formatting
|
|
1007
|
+
- JSON files: syntax-highlighted with color-coded tokens
|
|
1008
|
+
- Other files: rendered as plain preformatted text
|
|
1009
|
+
- Contains inline `FileIcon`, `FolderIcon`, `BackArrow` helper components
|
|
1010
|
+
- File icons vary by extension (JSON, MD, TXT, etc.)
|
|
1011
|
+
|
|
1012
|
+
**Used by:** Route `/memory`
|
|
1013
|
+
|
|
1014
|
+
---
|
|
1015
|
+
|
|
1016
|
+
### SettingsPage
|
|
1017
|
+
|
|
1018
|
+
**File:** `app/settings/page.tsx`
|
|
1019
|
+
**Purpose:** Settings management page for accent color, branding, agent customization, and setup wizard access.
|
|
1020
|
+
|
|
1021
|
+
**Key state:**
|
|
1022
|
+
- `agents` (useState) -- fetched from `/api/agents`
|
|
1023
|
+
- `showWizard` (useState) -- re-run onboarding wizard toggle
|
|
1024
|
+
- `expandedAgent` (useState) -- which agent's customization section is expanded
|
|
1025
|
+
- `imageUploading` (useState) -- loading state during image upload
|
|
1026
|
+
|
|
1027
|
+
**Sections:**
|
|
1028
|
+
1. **Accent Color** -- preset color grid (12 colors + reset to default)
|
|
1029
|
+
2. **Branding** -- portal name, subtitle, emoji picker, icon upload (with Canvas API resize to 128px)
|
|
1030
|
+
3. **Agent Customization** -- expandable per-agent sections to override emoji or profile image
|
|
1031
|
+
4. **Danger Zone** -- reset all settings button, re-run setup wizard button
|
|
1032
|
+
|
|
1033
|
+
**Implementation:**
|
|
1034
|
+
- Image uploads use Canvas API (`resizeImage` helper) to resize to 128px max and convert to base64 data URL
|
|
1035
|
+
- Agent customization: each agent row expands to show emoji input and image upload
|
|
1036
|
+
- Re-run wizard: renders `<OnboardingWizard forceOpen onClose={...} />` when triggered
|
|
1037
|
+
- Reset all: calls `resetAll()` from settings context
|
|
1038
|
+
|
|
1039
|
+
**Used by:** Route `/settings`
|
|
1040
|
+
|
|
1041
|
+
---
|
|
1042
|
+
|
|
1043
|
+
## UI Primitives
|
|
1044
|
+
|
|
1045
|
+
**Directory:** `components/ui/`
|
|
1046
|
+
|
|
1047
|
+
Radix-based primitive components used throughout the app. These are standard shadcn/ui-style wrappers and are not individually documented in detail.
|
|
1048
|
+
|
|
1049
|
+
| Component | File | Radix Primitive | Purpose |
|
|
1050
|
+
|-----------|------|-----------------|---------|
|
|
1051
|
+
| Badge | `badge.tsx` | -- | Status/label badges with variant styling |
|
|
1052
|
+
| Button | `button.tsx` | Slot | Button with variant and size props |
|
|
1053
|
+
| Card | `card.tsx` | -- | Card container with header, content, footer |
|
|
1054
|
+
| Dialog | `dialog.tsx` | Dialog | Modal dialog with overlay |
|
|
1055
|
+
| ScrollArea | `scroll-area.tsx` | ScrollArea | Custom scrollbar container |
|
|
1056
|
+
| Separator | `separator.tsx` | Separator | Horizontal/vertical divider |
|
|
1057
|
+
| Skeleton | `skeleton.tsx` | -- | Loading placeholder animation |
|
|
1058
|
+
| Tabs | `tabs.tsx` | Tabs | Tab navigation with content panels |
|
|
1059
|
+
| Tooltip | `tooltip.tsx` | Tooltip | Hover tooltip with positioning |
|