@elevasis/ui 1.26.1 → 1.28.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.
Files changed (57) hide show
  1. package/dist/charts/index.js +2 -2
  2. package/dist/{chunk-MHW43EOH.js → chunk-2IFYDILW.js} +2 -1
  3. package/dist/{chunk-AWT255UH.js → chunk-2IJCM3VQ.js} +37 -37
  4. package/dist/{chunk-4INR75ZS.js → chunk-37NT4BNV.js} +589 -65
  5. package/dist/chunk-5COLSYBE.js +199 -0
  6. package/dist/{chunk-YNGQ7U5H.js → chunk-7CJ5QBN2.js} +2 -2
  7. package/dist/{chunk-L3GVDMCA.js → chunk-C27LLJM6.js} +3 -195
  8. package/dist/chunk-C4WOXS2C.js +6646 -0
  9. package/dist/{chunk-RMPXGBNI.js → chunk-D25AE46Q.js} +2 -2
  10. package/dist/{chunk-ZVJKIJFG.js → chunk-EBCIUZVV.js} +13 -42
  11. package/dist/{chunk-O4UB5DQQ.js → chunk-F2J7675J.js} +1 -1
  12. package/dist/chunk-KLG4H5NM.js +247 -0
  13. package/dist/{chunk-BS4J2LAW.js → chunk-QTD5HPKD.js} +1 -1
  14. package/dist/chunk-S4S6K4MV.js +635 -0
  15. package/dist/{chunk-FEZZ3IDU.js → chunk-TXPUIHX2.js} +10 -10
  16. package/dist/{chunk-L4XXM55J.js → chunk-W4VYXIN7.js} +142 -3
  17. package/dist/{chunk-4WKWLFBZ.js → chunk-ZUJ7WMGV.js} +1 -1
  18. package/dist/chunk-ZXBD5SBV.js +2115 -0
  19. package/dist/components/index.d.ts +339 -73
  20. package/dist/components/index.js +840 -688
  21. package/dist/features/auth/index.d.ts +125 -0
  22. package/dist/features/auth/index.js +2 -2
  23. package/dist/features/dashboard/index.d.ts +28 -2
  24. package/dist/features/dashboard/index.js +21 -635
  25. package/dist/features/monitoring/index.d.ts +28 -1
  26. package/dist/features/monitoring/index.js +19 -529
  27. package/dist/features/operations/index.d.ts +57 -8
  28. package/dist/features/operations/index.js +25 -3760
  29. package/dist/features/settings/index.d.ts +153 -1
  30. package/dist/features/settings/index.js +19 -1438
  31. package/dist/hooks/index.d.ts +262 -25
  32. package/dist/hooks/index.js +12 -8
  33. package/dist/hooks/published.d.ts +137 -25
  34. package/dist/hooks/published.js +11 -7
  35. package/dist/index.d.ts +388 -99
  36. package/dist/index.js +12 -11
  37. package/dist/initialization/index.d.ts +125 -0
  38. package/dist/layout/index.d.ts +2 -0
  39. package/dist/layout/index.js +6 -5
  40. package/dist/organization/index.js +1 -2
  41. package/dist/profile/index.d.ts +125 -0
  42. package/dist/provider/index.d.ts +130 -3
  43. package/dist/provider/index.js +10 -4
  44. package/dist/provider/published.d.ts +130 -3
  45. package/dist/provider/published.js +8 -2
  46. package/dist/router/context.d.ts +1 -0
  47. package/dist/router/index.d.ts +1 -0
  48. package/dist/router/index.js +1 -1
  49. package/dist/supabase/index.d.ts +242 -0
  50. package/dist/theme/index.js +2 -2
  51. package/dist/types/index.d.ts +126 -1
  52. package/package.json +1 -1
  53. package/dist/chunk-LR4WVA7W.js +0 -682
  54. package/dist/chunk-R7WLWGPO.js +0 -126
  55. package/dist/chunk-TCKIAHDC.js +0 -2626
  56. package/dist/chunk-V7XHGJQZ.js +0 -145
  57. package/dist/{chunk-WWEMNIHW.js → chunk-YYBM5LNJ.js} +1 -1
@@ -1,3773 +1,38 @@
1
- import { ChatHeader, ChatSidebar } from '../../chunk-ROSMICXG.js';
2
- import { FormFieldRenderer, ResourceDefinitionSection, CommandQueueTaskRow, getIcon, ActionModal, CommandViewGraph, WorkflowExecutionLogs, AgentExecutionLogs, ResourceFilter, getExecutionStatusConfig, SessionMemory } from '../../chunk-TCKIAHDC.js';
3
- import { SubshellLoader, SubshellSidebarSection, PageContainer, CollapsibleSidebarGroup, SidebarListItem } from '../../chunk-AWT255UH.js';
4
- import { ResourceHealthPanel } from '../../chunk-4WKWLFBZ.js';
5
- import { ConfirmationModal, CustomModal } from '../../chunk-GBMNCNHX.js';
6
- import { ExecutionStats, UnifiedWorkflowGraph, WorkflowExecutionTimeline, AgentExecutionVisualizer, AgentExecutionTimeline } from '../../chunk-O4UB5DQQ.js';
7
- import { useCyberColors, CyberDonut } from '../../chunk-JHVKGZ2P.js';
8
- import { PageTitleCaption, TabCountBadge, ResourceCard, ContextViewer, JsonViewer, APIErrorAlert, EmptyState, CardHeader } from '../../chunk-MCA6LOGM.js';
1
+ export { AgentExecutionPanel, AgentSessionGroup, CalibrationPage, CalibrationProgress, CalibrationProjectDetailPage, CalibrationProjectsPage, CalibrationRunDetailPage, CalibrationSidebar, CommandQueueDetailPage, CommandQueuePage, CommandViewPage, CommandViewSidebarContent, ExecuteWorkflowModal, ExecutionPanel, OperationsSidebar, OperationsSidebarMiddle, OperationsSidebarTop, ResourceDetailPage, ResourceExecuteDialog, ResourceExecuteForm, ResourcesPage, ResourcesSidebar, SessionChatArea, SessionChatInterface, SessionChatPage, SessionDetailsSidebar, SessionExecutionLogs, SessionHeader, SessionListItem, SessionsPage, SessionsSidebar, WorkflowExecutionPanel, operationsManifest } from '../../chunk-C4WOXS2C.js';
2
+ import '../../chunk-ROSMICXG.js';
3
+ import '../../chunk-2IJCM3VQ.js';
4
+ import '../../chunk-ZUJ7WMGV.js';
5
+ import '../../chunk-GBMNCNHX.js';
6
+ import '../../chunk-F2J7675J.js';
7
+ import '../../chunk-JHVKGZ2P.js';
8
+ import '../../chunk-MCA6LOGM.js';
9
9
  import '../../chunk-3KMDHCAR.js';
10
10
  import '../../chunk-NNKKBSJN.js';
11
- import { AppShellLoader } from '../../chunk-WWEMNIHW.js';
12
- import { topbarHeight } from '../../chunk-QJ2S46NI.js';
13
- import { useStatusFilter, useResourceSearch, useResourcesDomainFilters, filterByDomainFilters, useCommandViewDomainFilters } from '../../chunk-YNGQ7U5H.js';
14
- import { usePaginationState, useResources, useRecentExecutionsByResource, useExecuteAsync, useResourceDefinition, isSessionCapable, useDeleteTask, useCommandQueueTotals, useCommandQueue, useSubmitAction, useCommandViewData, useCommandViewStore, useCommandViewStats, useCalibrationProjects, useCalibrationProject, useAllCalibrationProjects, useResourceExecutions, useCheckpointTasks, useCalibrationSSE, useCalibrationRunFull, useExecuteRun, useGradeRun, useCalibrationRuns, useExecutionPanelState, useExecution, useDeleteSession, useCreateSession, useSessions, useSessionExecutions, useSession, calibrationKeys, useDeleteProject, useCreateProject } from '../../chunk-ZVJKIJFG.js';
11
+ import '../../chunk-YYBM5LNJ.js';
12
+ import '../../chunk-7CJ5QBN2.js';
13
+ import '../../chunk-EBCIUZVV.js';
15
14
  import '../../chunk-LXHZYSMQ.js';
16
- import '../../chunk-MHW43EOH.js';
17
15
  import '../../chunk-F6RBK7NJ.js';
18
- import { useMergedExecution, useTimelineData, useAgentIterationData } from '../../chunk-XA34RETF.js';
19
- import { ResourceStatusColors } from '../../chunk-ELJIFLCB.js';
20
- import '../../chunk-L4XXM55J.js';
21
- import '../../chunk-SLVC5OJ2.js';
22
- import '../../chunk-RNP5R5I3.js';
23
- import '../../chunk-RMPXGBNI.js';
16
+ import '../../chunk-XA34RETF.js';
17
+ import '../../chunk-ELJIFLCB.js';
18
+ import '../../chunk-D25AE46Q.js';
24
19
  import '../../chunk-SZHARWKU.js';
25
- import '../../chunk-FEZZ3IDU.js';
20
+ import '../../chunk-TXPUIHX2.js';
26
21
  import '../../chunk-CYXZHBP4.js';
27
- import '../../chunk-R7WLWGPO.js';
22
+ import '../../chunk-KLG4H5NM.js';
23
+ import '../../chunk-5COLSYBE.js';
28
24
  import '../../chunk-NVOCKXUQ.js';
29
- import '../../chunk-V7XHGJQZ.js';
25
+ import '../../chunk-2IFYDILW.js';
26
+ import '../../chunk-W4VYXIN7.js';
30
27
  import '../../chunk-QJ2KCHKX.js';
31
- import { formatRelativeTime, DOMAIN_MAP, getNodeId, PAGE_SIZE_DEFAULT, getErrorInfo, formatErrorMessage, getResourceIcon } from '../../chunk-IOKL7BKE.js';
28
+ import '../../chunk-QJ2S46NI.js';
29
+ import '../../chunk-SLVC5OJ2.js';
30
+ import '../../chunk-RNP5R5I3.js';
31
+ import '../../chunk-IOKL7BKE.js';
32
32
  import '../../chunk-RWQIFKMJ.js';
33
33
  import '../../chunk-ALA56RGZ.js';
34
- import { useInitialization } from '../../chunk-TUXTSEAF.js';
35
- import { useOrganization } from '../../chunk-DD3CCMCZ.js';
34
+ import '../../chunk-TUXTSEAF.js';
35
+ import '../../chunk-DD3CCMCZ.js';
36
36
  import '../../chunk-QEPXAWE2.js';
37
37
  import '../../chunk-BRJ3QZ4E.js';
38
38
  import '../../chunk-Q7DJKLEN.js';
39
- import { Stack, Card, Text, Button, Tabs, Group, Pagination, useMantineTheme, Box, Center, Loader, UnstyledButton, TextInput, Divider, Modal, Code, Alert, LoadingOverlay, Badge, Paper, ActionIcon, Title, SimpleGrid, CopyButton, SegmentedControl, ThemeIcon, Switch, Space, Progress, Timeline, Collapse, ScrollArea, Tooltip, Textarea, Menu, Table } from '@mantine/core';
40
- import { IconApps, IconRoute, IconBrain, IconRefresh, IconAdjustmentsHorizontal, IconSearch, IconChevronDown, IconCircleX, IconCircleCheck, IconCircleDashed, IconCheck, IconExternalLink, IconAlertCircle, IconTrash, IconArrowLeft, IconClock, IconCopy, IconPlayerPlay, IconPlus, IconAdjustments, IconSitemap, IconSettings, IconX, IconChartBar, IconReportAnalytics, IconCoin, IconChevronRight, IconFlask, IconInfoCircle, IconMessage, IconAlertTriangle, IconRobot, IconLayoutSidebarRightExpand, IconNote, IconArchive, IconDownload, IconTimeline, IconDotsVertical } from '@tabler/icons-react';
41
- import { useState, useEffect, useMemo, useRef, useCallback } from 'react';
42
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
43
- import { useClipboard } from '@mantine/hooks';
44
- import { notifications } from '@mantine/notifications';
45
- import { Link, useNavigate } from '@tanstack/react-router';
46
- import { useForm } from '@mantine/form';
47
- import { formatDistanceToNow } from 'date-fns';
48
- import { useQueryClient } from '@tanstack/react-query';
49
-
50
- // ../core/src/platform/utils/debounce.ts
51
- function debounce(fn, wait) {
52
- let timeoutId = null;
53
- const debounced = (...args) => {
54
- if (timeoutId !== null) {
55
- clearTimeout(timeoutId);
56
- }
57
- timeoutId = setTimeout(() => {
58
- fn(...args);
59
- timeoutId = null;
60
- }, wait);
61
- };
62
- debounced.cancel = () => {
63
- if (timeoutId !== null) {
64
- clearTimeout(timeoutId);
65
- timeoutId = null;
66
- }
67
- };
68
- return debounced;
69
- }
70
- function ResourcesPage({
71
- initialFilter,
72
- onTypeChange,
73
- timeRange,
74
- onResourceClick,
75
- pageSize = 20
76
- }) {
77
- const { organizationReady } = useInitialization();
78
- const urlType = initialFilter;
79
- const [selectedFilter, setSelectedFilter] = useState(urlType || "all");
80
- const statusFilter = useStatusFilter((s) => s.value);
81
- const searchQuery = useResourceSearch((s) => s.query);
82
- const domainFilters = useResourcesDomainFilters((s) => s.filters);
83
- const { page, setPage, offset, totalPages } = usePaginationState(pageSize, [
84
- selectedFilter,
85
- statusFilter,
86
- domainFilters,
87
- searchQuery
88
- ]);
89
- useEffect(() => {
90
- if (urlType) {
91
- setSelectedFilter(urlType);
92
- } else {
93
- setSelectedFilter("all");
94
- }
95
- }, [urlType]);
96
- const { data, error, refetch, isFetching } = useResources();
97
- const { data: executionData } = useRecentExecutionsByResource({
98
- timeRange
99
- });
100
- const executionLookup = useMemo(() => {
101
- if (!executionData?.resources) return /* @__PURE__ */ new Map();
102
- return new Map(executionData.resources.map((r) => [r.resourceId, r]));
103
- }, [executionData]);
104
- const { workflows = [], agents = [], total = 0 } = data || {};
105
- const filteredResources = useMemo(() => {
106
- const typedWorkflows = (workflows || []).map((w) => ({ ...w, type: "workflow" }));
107
- const typedAgents = (agents || []).map((a) => ({ ...a, type: "agent" }));
108
- let resources = [];
109
- switch (selectedFilter) {
110
- case "workflow":
111
- resources = typedWorkflows;
112
- break;
113
- case "agent":
114
- resources = typedAgents;
115
- break;
116
- case "all":
117
- resources = [...typedWorkflows, ...typedAgents];
118
- break;
119
- default:
120
- resources = [];
121
- }
122
- if (statusFilter !== "all") {
123
- resources = resources.filter((resource) => resource.status === statusFilter);
124
- }
125
- resources = filterByDomainFilters(resources, domainFilters);
126
- if (searchQuery.trim()) {
127
- const q = searchQuery.toLowerCase();
128
- resources = resources.filter(
129
- (r) => r.name.toLowerCase().includes(q) || r.resourceId.toLowerCase().includes(q) || r.description?.toLowerCase().includes(q)
130
- );
131
- }
132
- const enriched = resources.map((resource) => {
133
- const execData = executionLookup.get(resource.resourceId);
134
- return {
135
- ...resource,
136
- lastExecution: execData?.lastExecution,
137
- totalExecutions: execData?.totalExecutions || 0,
138
- successCount: execData?.successCount || 0,
139
- failureCount: execData?.failureCount || 0,
140
- successRate: execData?.successRate || 0
141
- };
142
- });
143
- enriched.sort((a, b) => {
144
- if (a.lastExecution && b.lastExecution) {
145
- return new Date(b.lastExecution).getTime() - new Date(a.lastExecution).getTime();
146
- }
147
- if (a.lastExecution) return -1;
148
- if (b.lastExecution) return 1;
149
- return a.name.localeCompare(b.name);
150
- });
151
- return enriched;
152
- }, [workflows, agents, selectedFilter, statusFilter, domainFilters, searchQuery, executionLookup]);
153
- if (!organizationReady || isFetching && !data) {
154
- return /* @__PURE__ */ jsx(SubshellLoader, {});
155
- }
156
- if (error) {
157
- return /* @__PURE__ */ jsxs(Stack, { children: [
158
- /* @__PURE__ */ jsx(PageTitleCaption, { title: "Resources", caption: "Failed to load resources" }),
159
- /* @__PURE__ */ jsxs(Card, { children: [
160
- /* @__PURE__ */ jsxs(Text, { c: "red", children: [
161
- "Error: ",
162
- error.message
163
- ] }),
164
- /* @__PURE__ */ jsx(Button, { onClick: () => refetch(), children: "Retry" })
165
- ] })
166
- ] });
167
- }
168
- const getResourceCount = (type) => {
169
- const filteredW = filterByDomainFilters(workflows, domainFilters);
170
- const filteredA = filterByDomainFilters(agents, domainFilters);
171
- switch (type) {
172
- case "workflow":
173
- return filteredW.length;
174
- case "agent":
175
- return filteredA.length;
176
- case "all":
177
- return filteredW.length + filteredA.length;
178
- default:
179
- return 0;
180
- }
181
- };
182
- const handleTabChange = (value) => {
183
- if (value) {
184
- const filterValue = value;
185
- setSelectedFilter(filterValue);
186
- onTypeChange(filterValue === "all" ? void 0 : filterValue);
187
- }
188
- };
189
- const isFiltering = filteredResources.length !== total;
190
- const paginatedResources = filteredResources.slice(offset, offset + pageSize);
191
- return /* @__PURE__ */ jsxs(Stack, { children: [
192
- /* @__PURE__ */ jsx(
193
- PageTitleCaption,
194
- {
195
- title: "Resources",
196
- caption: isFiltering ? `${filteredResources.length} Resources Available, ${total - filteredResources.length} Filtered` : `${total} Resources Available`
197
- }
198
- ),
199
- /* @__PURE__ */ jsx(Tabs, { value: selectedFilter, onChange: handleTabChange, variant: "default", children: /* @__PURE__ */ jsxs(Tabs.List, { children: [
200
- /* @__PURE__ */ jsx(
201
- Tabs.Tab,
202
- {
203
- value: "all",
204
- leftSection: /* @__PURE__ */ jsx(IconApps, { size: 16 }),
205
- rightSection: /* @__PURE__ */ jsx(TabCountBadge, { count: getResourceCount("all"), isLoading: isFetching }),
206
- children: "All"
207
- }
208
- ),
209
- /* @__PURE__ */ jsx(
210
- Tabs.Tab,
211
- {
212
- value: "workflow",
213
- leftSection: /* @__PURE__ */ jsx(IconRoute, { size: 16 }),
214
- rightSection: /* @__PURE__ */ jsx(TabCountBadge, { count: getResourceCount("workflow"), isLoading: isFetching }),
215
- children: "Workflows"
216
- }
217
- ),
218
- /* @__PURE__ */ jsx(
219
- Tabs.Tab,
220
- {
221
- value: "agent",
222
- leftSection: /* @__PURE__ */ jsx(IconBrain, { size: 16 }),
223
- rightSection: /* @__PURE__ */ jsx(TabCountBadge, { count: getResourceCount("agent"), isLoading: isFetching }),
224
- children: "Agents"
225
- }
226
- )
227
- ] }) }),
228
- filteredResources.length > 0 ? /* @__PURE__ */ jsx(Stack, { gap: "xs", children: paginatedResources.map((resource) => {
229
- const isDormant = resource.totalExecutions === 0;
230
- return /* @__PURE__ */ jsx(
231
- ResourceCard,
232
- {
233
- resource,
234
- onClick: onResourceClick,
235
- layout: "row",
236
- "data-resource-id": resource.resourceId,
237
- lastRunLabel: resource.lastExecution ? `Last run ${formatRelativeTime(resource.lastExecution)}` : void 0,
238
- rightSection: /* @__PURE__ */ jsx(
239
- ExecutionStats,
240
- {
241
- totalExecutions: resource.totalExecutions,
242
- successCount: resource.successCount,
243
- failureCount: resource.failureCount,
244
- successRate: resource.successRate,
245
- compact: true
246
- }
247
- ),
248
- style: isDormant ? { opacity: 0.4 } : void 0
249
- },
250
- resource.resourceId
251
- );
252
- }) }) : /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Stack, { align: "center", children: [
253
- /* @__PURE__ */ jsxs(Text, { c: "dimmed", children: [
254
- "No resources found for ",
255
- selectedFilter === "all" ? "any type" : selectedFilter
256
- ] }),
257
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: selectedFilter === "all" ? "Register workflows or agents to see them here" : `Register ${selectedFilter}s to see them here` })
258
- ] }) }),
259
- totalPages(filteredResources.length) > 1 && /* @__PURE__ */ jsx(Group, { justify: "flex-start", children: /* @__PURE__ */ jsx(
260
- Pagination,
261
- {
262
- size: "sm",
263
- total: totalPages(filteredResources.length),
264
- value: page,
265
- onChange: setPage,
266
- boundaries: 1
267
- }
268
- ) })
269
- ] });
270
- }
271
- var FILTER_STATE_ICONS = {
272
- neutral: IconCircleDashed,
273
- include: IconCircleCheck,
274
- exclude: IconCircleX
275
- };
276
- var FILTER_STATE_COLORS = {
277
- neutral: "var(--color-text-subtle)",
278
- include: "var(--mantine-color-green-6)",
279
- exclude: "var(--mantine-color-red-6)"
280
- };
281
- var FILTER_STATE_LABELS = {
282
- neutral: "Not filtered",
283
- include: "Include only",
284
- exclude: "Exclude"
285
- };
286
- function ResourcesSidebar({ timeRange }) {
287
- const searchQuery = useResourceSearch((s) => s.query);
288
- const setSearchQuery = useResourceSearch((s) => s.set);
289
- const statusFilter = useStatusFilter((s) => s.value);
290
- const setStatusFilter = useStatusFilter((s) => s.set);
291
- const [domainsOpen, setDomainsOpen] = useState(true);
292
- const domainFilters = useResourcesDomainFilters((s) => s.filters);
293
- const cycleDomainFilter = useResourcesDomainFilters((s) => s.cycle);
294
- const { organizationReady } = useInitialization();
295
- const { data: resources, isLoading: isResourcesLoading, error, refetch } = useResources();
296
- const theme = useMantineTheme();
297
- const colors = useCyberColors();
298
- const { data: executionData } = useRecentExecutionsByResource({ timeRange });
299
- const activeDomains = useMemo(() => {
300
- if (!resources) return [];
301
- const allResources = [...resources.workflows || [], ...resources.agents || []];
302
- const domainSet = /* @__PURE__ */ new Set();
303
- allResources.forEach((r) => r.domains?.forEach((d) => domainSet.add(d)));
304
- const bottomDomains = /* @__PURE__ */ new Set(["utility", "diagnostic"]);
305
- return Array.from(domainSet).sort((a, b) => {
306
- const aBottom = bottomDomains.has(a) ? 1 : 0;
307
- const bBottom = bottomDomains.has(b) ? 1 : 0;
308
- if (aBottom !== bBottom) return aBottom - bBottom;
309
- return a.localeCompare(b);
310
- });
311
- }, [resources]);
312
- const domainFilteredResources = useMemo(() => {
313
- if (!resources) return [];
314
- const allResources = [...resources.workflows || [], ...resources.agents || []];
315
- return filterByDomainFilters(allResources, domainFilters);
316
- }, [resources, domainFilters]);
317
- const { donutSuccessCount, donutFailedCount } = useMemo(() => {
318
- if (!executionData?.resources || domainFilteredResources.length === 0) {
319
- return { donutSuccessCount: 0, donutFailedCount: 0 };
320
- }
321
- const filteredIds = new Set(domainFilteredResources.map((r) => r.resourceId));
322
- let success = 0;
323
- let failed = 0;
324
- for (const r of executionData.resources) {
325
- if (filteredIds.has(r.resourceId)) {
326
- success += r.successCount;
327
- failed += r.failureCount;
328
- }
329
- }
330
- return { donutSuccessCount: success, donutFailedCount: failed };
331
- }, [executionData, domainFilteredResources]);
332
- if (!organizationReady || isResourcesLoading) {
333
- return /* @__PURE__ */ jsx(Box, { style: { flex: 1, minHeight: 0, padding: theme.spacing.sm }, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) });
334
- }
335
- if (error) {
336
- return /* @__PURE__ */ jsxs(Box, { style: { flex: 1, minHeight: 0, padding: theme.spacing.sm }, children: [
337
- /* @__PURE__ */ jsx(
338
- Text,
339
- {
340
- size: "xs",
341
- fw: 600,
342
- c: "dimmed",
343
- tt: "uppercase",
344
- mb: "md",
345
- style: { fontFamily: "var(--elevasis-font-family-subtitle)" },
346
- children: "Error Loading Resources"
347
- }
348
- ),
349
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", mb: "md", children: error instanceof Error ? error.message : "Failed to load resources" }),
350
- /* @__PURE__ */ jsx(Button, { size: "xs", leftSection: /* @__PURE__ */ jsx(IconRefresh, { size: 14 }), onClick: () => refetch(), variant: "light", children: "Retry" })
351
- ] });
352
- }
353
- const totalExecutions = donutSuccessCount + donutFailedCount;
354
- const successRate = totalExecutions > 0 ? donutSuccessCount / totalExecutions * 100 : 0;
355
- const healthSegments = [
356
- { name: "Completed", value: donutSuccessCount, color: colors.green },
357
- { name: "Failed", value: donutFailedCount, color: colors.red }
358
- ];
359
- const centerValueColor = totalExecutions === 0 ? "var(--mantine-color-dimmed)" : successRate >= 95 ? colors.green : successRate >= 80 ? colors.yellow : colors.red;
360
- return /* @__PURE__ */ jsxs(Stack, { gap: 0, style: { flex: 1, minHeight: 0, overflow: "hidden" }, children: [
361
- /* @__PURE__ */ jsx(Box, { p: "sm", pb: 0, children: /* @__PURE__ */ jsx(Box, { pb: "xs", mb: 4, children: /* @__PURE__ */ jsx(
362
- CyberDonut,
363
- {
364
- title: `Execution Health (${timeRange})`,
365
- segments: healthSegments,
366
- centerValue: totalExecutions === 0 ? "\u2014" : `${Math.round(successRate)}%`,
367
- centerLabel: `${totalExecutions} runs`,
368
- centerValueColor,
369
- glowId: "resHealthGlow",
370
- colors
371
- }
372
- ) }) }),
373
- /* @__PURE__ */ jsx(
374
- SubshellSidebarSection,
375
- {
376
- icon: IconAdjustmentsHorizontal,
377
- label: "Resource Filters",
378
- withTopBorder: true,
379
- rightSection: /* @__PURE__ */ jsx(UnstyledButton, { title: "Refresh resources", onClick: () => refetch(), children: /* @__PURE__ */ jsx(IconRefresh, { size: 16, color: "var(--color-text-subtle)" }) })
380
- }
381
- ),
382
- /* @__PURE__ */ jsxs(Box, { p: "sm", style: { flex: 1, minHeight: 0, display: "flex", flexDirection: "column", overflowY: "auto" }, children: [
383
- resources && (() => {
384
- const stats = [
385
- {
386
- key: "all",
387
- label: "All",
388
- count: domainFilteredResources.length,
389
- color: "var(--color-text)",
390
- activeColor: "var(--color-primary)"
391
- },
392
- {
393
- key: "prod",
394
- label: "Prod",
395
- count: domainFilteredResources.filter((r) => r.status === "prod").length,
396
- color: "var(--color-text)",
397
- activeColor: "var(--color-primary)"
398
- },
399
- {
400
- key: "dev",
401
- label: "Dev",
402
- count: domainFilteredResources.filter((r) => r.status === "dev").length,
403
- color: "var(--color-text)",
404
- activeColor: "var(--color-primary)"
405
- }
406
- ];
407
- return /* @__PURE__ */ jsx(
408
- Group,
409
- {
410
- gap: 0,
411
- mb: "sm",
412
- style: {
413
- flexShrink: 0,
414
- borderRadius: "var(--mantine-radius-default)",
415
- border: "1px solid var(--color-border)",
416
- background: "var(--glass-background)",
417
- overflow: "hidden"
418
- },
419
- children: stats.map((stat, i) => {
420
- const isActive = statusFilter === stat.key;
421
- return /* @__PURE__ */ jsx(
422
- UnstyledButton,
423
- {
424
- onClick: () => setStatusFilter(stat.key),
425
- style: {
426
- flex: 1,
427
- borderLeft: i > 0 ? "1px solid var(--color-border)" : void 0,
428
- background: isActive ? "var(--active-background)" : "transparent",
429
- boxShadow: isActive ? "inset 0 -2px 0 var(--color-primary)" : "none",
430
- transition: "all var(--duration-fast) var(--easing)"
431
- },
432
- children: /* @__PURE__ */ jsxs(Stack, { gap: 0, align: "center", py: 8, children: [
433
- /* @__PURE__ */ jsx(
434
- Text,
435
- {
436
- size: "md",
437
- fw: 700,
438
- ff: "monospace",
439
- style: { color: isActive ? stat.activeColor : "var(--color-text)", lineHeight: 1.2 },
440
- children: stat.count
441
- }
442
- ),
443
- /* @__PURE__ */ jsx(
444
- Text,
445
- {
446
- size: "xs",
447
- c: isActive ? void 0 : "dimmed",
448
- fw: isActive ? 600 : 400,
449
- style: { lineHeight: 1.2 },
450
- children: stat.label
451
- }
452
- )
453
- ] })
454
- },
455
- stat.key
456
- );
457
- })
458
- }
459
- );
460
- })(),
461
- /* @__PURE__ */ jsx(
462
- TextInput,
463
- {
464
- placeholder: "Filter resources...",
465
- leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 16 }),
466
- size: "sm",
467
- value: searchQuery,
468
- onChange: (e) => setSearchQuery(e.currentTarget.value),
469
- mb: "sm",
470
- style: { flexShrink: 0 }
471
- }
472
- ),
473
- activeDomains.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
474
- /* @__PURE__ */ jsx(UnstyledButton, { onClick: () => setDomainsOpen((o) => !o), style: { width: "100%", flexShrink: 0 }, mt: 4, children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
475
- /* @__PURE__ */ jsx(
476
- Text,
477
- {
478
- size: "sm",
479
- fw: 600,
480
- tt: "uppercase",
481
- style: {
482
- color: "var(--color-text-subtle)",
483
- fontFamily: "var(--elevasis-font-family-subtitle)"
484
- },
485
- children: "Domains"
486
- }
487
- ),
488
- /* @__PURE__ */ jsx(
489
- IconChevronDown,
490
- {
491
- size: 14,
492
- style: {
493
- transform: domainsOpen ? "rotate(180deg)" : "rotate(0deg)",
494
- transition: "transform var(--duration-fast) var(--easing)",
495
- color: "var(--color-text-subtle)"
496
- }
497
- }
498
- )
499
- ] }) }),
500
- /* @__PURE__ */ jsx(
501
- "div",
502
- {
503
- style: {
504
- display: "grid",
505
- gridTemplateRows: domainsOpen ? "1fr" : "0fr",
506
- transition: "grid-template-rows 200ms cubic-bezier(0.4, 0, 0.2, 1)"
507
- },
508
- children: /* @__PURE__ */ jsx("div", { style: { overflow: "hidden" }, children: /* @__PURE__ */ jsx(Stack, { gap: 2, mt: "xs", style: { flexShrink: 0 }, children: activeDomains.map((domainId) => {
509
- const domain = DOMAIN_MAP[domainId];
510
- if (!domain) return null;
511
- const filterState = domainFilters[domainId] || "neutral";
512
- const StateIcon = FILTER_STATE_ICONS[filterState];
513
- return /* @__PURE__ */ jsx(
514
- UnstyledButton,
515
- {
516
- title: FILTER_STATE_LABELS[filterState],
517
- onClick: () => cycleDomainFilter(domainId),
518
- py: 5,
519
- px: 6,
520
- style: {
521
- transition: "background-color var(--duration-fast) var(--easing)",
522
- "&:hover": { backgroundColor: "var(--color-surface-hover)" }
523
- },
524
- children: /* @__PURE__ */ jsxs(Group, { gap: 10, wrap: "nowrap", children: [
525
- /* @__PURE__ */ jsx(
526
- StateIcon,
527
- {
528
- size: 16,
529
- style: {
530
- color: FILTER_STATE_COLORS[filterState],
531
- flexShrink: 0,
532
- transition: "color var(--duration-fast) var(--easing)"
533
- }
534
- }
535
- ),
536
- /* @__PURE__ */ jsx(
537
- Text,
538
- {
539
- size: "sm",
540
- truncate: true,
541
- fw: filterState !== "neutral" ? 500 : 400,
542
- c: filterState !== "neutral" ? void 0 : "dimmed",
543
- children: domain.name
544
- }
545
- )
546
- ] })
547
- },
548
- domainId
549
- );
550
- }) }) })
551
- }
552
- ),
553
- /* @__PURE__ */ jsx(Divider, { my: "sm", color: "var(--color-border)", style: { flexShrink: 0 } })
554
- ] })
555
- ] })
556
- ] });
557
- }
558
- function ResourceHeader({
559
- resource,
560
- type,
561
- connected,
562
- runningCount,
563
- sessionCapable,
564
- onRun,
565
- onNavigateToResources,
566
- onNavigateToSessions
567
- }) {
568
- const { currentMembership } = useOrganization();
569
- const organizationName = currentMembership?.organization?.name;
570
- const navigate = useNavigate();
571
- const Icon = getResourceIcon(type);
572
- const clipboard = useClipboard({ timeout: 2e3 });
573
- const handleCopyId = () => {
574
- clipboard.copy(`"${organizationName}/${resource.resourceId}"`);
575
- notifications.show({
576
- message: "Resource ID copied to clipboard",
577
- color: "teal"
578
- });
579
- };
580
- const handleGoToSessions = onNavigateToSessions ?? (() => navigate({
581
- to: "/operations/sessions",
582
- search: { agent: resource.resourceId }
583
- }));
584
- const handleGoToResources = onNavigateToResources ?? (() => navigate({ to: "/operations/resources" }));
585
- return /* @__PURE__ */ jsxs(Fragment, { children: [
586
- /* @__PURE__ */ jsx(
587
- PageTitleCaption,
588
- {
589
- title: resource.name,
590
- caption: resource.description || `${type.charAt(0).toUpperCase()}${type.slice(1)} details`
591
- }
592
- ),
593
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
594
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
595
- /* @__PURE__ */ jsx(Icon, { size: 20, color: "var(--color-primary)" }),
596
- /* @__PURE__ */ jsxs(Badge, { color: "blue", variant: "light", children: [
597
- type.charAt(0).toUpperCase(),
598
- type.slice(1)
599
- ] }),
600
- /* @__PURE__ */ jsx(Badge, { color: ResourceStatusColors[resource.status], variant: "outline", size: "sm", children: resource.status.toUpperCase() }),
601
- resource.version && /* @__PURE__ */ jsxs(Badge, { variant: "outline", size: "sm", children: [
602
- "v",
603
- resource.version
604
- ] }),
605
- /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
606
- /* @__PURE__ */ jsxs(Text, { size: "sm", ff: "monospace", c: "dimmed", children: [
607
- organizationName,
608
- "/",
609
- resource.resourceId
610
- ] }),
611
- /* @__PURE__ */ jsx(Tooltip, { label: clipboard.copied ? "Copied!" : "Copy ID", children: /* @__PURE__ */ jsx(ActionIcon, { size: "sm", variant: "subtle", onClick: handleCopyId, color: clipboard.copied ? "teal" : "gray", children: /* @__PURE__ */ jsx(IconCopy, { size: 14, color: clipboard.copied ? "teal" : "gray" }) }) })
612
- ] })
613
- ] }),
614
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
615
- connected && /* @__PURE__ */ jsx(Badge, { color: "green", variant: "dot", children: "CONNECTED" }),
616
- runningCount && runningCount > 0 && /* @__PURE__ */ jsxs(Badge, { color: "blue", variant: "filled", children: [
617
- runningCount,
618
- " running"
619
- ] }),
620
- onRun && /* @__PURE__ */ jsx(Button, { size: "xs", variant: "filled", leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 }), onClick: onRun, children: "Run" }),
621
- type === "agent" && sessionCapable && /* @__PURE__ */ jsx(Button, { size: "xs", variant: "light", leftSection: /* @__PURE__ */ jsx(IconMessage, { size: 16 }), onClick: handleGoToSessions, children: "Go to Sessions" }),
622
- /* @__PURE__ */ jsx(Button, { size: "xs", variant: "light", leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }), onClick: handleGoToResources, children: "Resources" })
623
- ] })
624
- ] })
625
- ] });
626
- }
627
- function ResourceErrorState({ error }) {
628
- return /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Stack, { align: "center", children: [
629
- /* @__PURE__ */ jsx(Text, { c: "red", children: "Failed to load resource" }),
630
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: error.message })
631
- ] }) }) });
632
- }
633
- function ResourceNotFoundState({ type, resourceId, onNavigateBack }) {
634
- const navigate = useNavigate();
635
- const { currentMembership } = useOrganization();
636
- const orgName = currentMembership?.organization?.name || "current organization";
637
- const handleBack = onNavigateBack ?? (() => navigate({ to: "/operations", search: { type: void 0 } }));
638
- return /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Stack, { align: "center", children: [
639
- /* @__PURE__ */ jsx(Text, { size: "lg", c: "dimmed", fw: 500, children: "Resource not found" }),
640
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", ta: "center", children: [
641
- "The ",
642
- type,
643
- ' "',
644
- resourceId,
645
- '" could not be found in ',
646
- orgName,
647
- "."
648
- ] }),
649
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", ta: "center", children: "This resource may exist in a different organization. Try switching organizations or returning to the overview." }),
650
- /* @__PURE__ */ jsx(Button, { variant: "light", leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }), onClick: handleBack, children: "Back to Operations" })
651
- ] }) }) });
652
- }
653
- function ExecuteWorkflowModal({
654
- opened,
655
- onClose,
656
- resource,
657
- isPending = false,
658
- error,
659
- result,
660
- onViewExecution,
661
- onReset,
662
- children
663
- }) {
664
- const canClose = !isPending;
665
- const title = resource.name ?? resource.resourceId;
666
- return /* @__PURE__ */ jsx(
667
- Modal,
668
- {
669
- opened,
670
- onClose: canClose ? onClose : () => void 0,
671
- centered: true,
672
- size: "lg",
673
- closeOnClickOutside: canClose,
674
- closeOnEscape: canClose,
675
- withCloseButton: canClose,
676
- title: /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
677
- /* @__PURE__ */ jsxs(Text, { fw: 600, children: [
678
- "Run ",
679
- resource.resourceType
680
- ] }),
681
- /* @__PURE__ */ jsx(Badge, { color: "blue", variant: "light", size: "sm", children: resource.resourceType })
682
- ] }),
683
- children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
684
- /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
685
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Target:" }),
686
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: title }),
687
- /* @__PURE__ */ jsx(Code, { children: resource.resourceId })
688
- ] }),
689
- /* @__PURE__ */ jsx(Divider, {}),
690
- result ? /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
691
- /* @__PURE__ */ jsx(Alert, { variant: "light", color: "teal", title: "Execution started", icon: /* @__PURE__ */ jsx(IconCheck, { size: 16 }), children: /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
692
- /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
693
- "The ",
694
- resource.resourceType,
695
- " is now running."
696
- ] }),
697
- /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
698
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Execution ID:" }),
699
- /* @__PURE__ */ jsx(Code, { children: result.executionId })
700
- ] })
701
- ] }) }),
702
- /* @__PURE__ */ jsxs(Group, { justify: "flex-end", gap: "xs", children: [
703
- onReset && /* @__PURE__ */ jsx(Button, { variant: "default", onClick: onReset, children: "Run again" }),
704
- onViewExecution && /* @__PURE__ */ jsx(
705
- Button,
706
- {
707
- leftSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 16 }),
708
- onClick: () => onViewExecution(result.executionId),
709
- children: "View execution"
710
- }
711
- ),
712
- /* @__PURE__ */ jsx(Button, { variant: "light", onClick: onClose, children: "Close" })
713
- ] })
714
- ] }) : error ? /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
715
- /* @__PURE__ */ jsx(Alert, { variant: "light", color: "red", title: "Execution failed to start", icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), children: /* @__PURE__ */ jsx(Text, { size: "sm", children: error.message || "An unknown error occurred." }) }),
716
- /* @__PURE__ */ jsxs(Group, { justify: "flex-end", gap: "xs", children: [
717
- onReset && /* @__PURE__ */ jsx(Button, { variant: "default", onClick: onReset, children: "Try again" }),
718
- /* @__PURE__ */ jsx(Button, { variant: "light", onClick: onClose, children: "Close" })
719
- ] })
720
- ] }) : /* @__PURE__ */ jsxs("div", { style: { position: "relative" }, children: [
721
- /* @__PURE__ */ jsx(LoadingOverlay, { visible: isPending, zIndex: 1e3, overlayProps: { blur: 2 } }),
722
- children ?? /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "No input form provided." })
723
- ] })
724
- ] })
725
- }
726
- );
727
- }
728
- function getInitialValues(fields) {
729
- const values = {};
730
- for (const field of fields) {
731
- values[field.name] = field.defaultValue ?? (field.type === "checkbox" ? false : "");
732
- }
733
- return values;
734
- }
735
- function applyFieldMappings(values, mappings) {
736
- if (!mappings) return values;
737
- const mapped = {};
738
- for (const [key, value] of Object.entries(values)) {
739
- const targetKey = mappings[key] ?? key;
740
- mapped[targetKey] = value;
741
- }
742
- return mapped;
743
- }
744
- function ResourceExecuteForm({
745
- formSchema,
746
- onSubmit,
747
- isPending = false,
748
- disabled = false,
749
- submitLabel = "Run"
750
- }) {
751
- const hasFields = formSchema?.fields?.length > 0;
752
- const form = useForm({
753
- initialValues: hasFields ? getInitialValues(formSchema.fields) : {},
754
- validate: hasFields ? Object.fromEntries(
755
- formSchema.fields.filter((f) => f.required).map((f) => [
756
- f.name,
757
- (value) => !value && value !== false ? `${f.label} is required` : null
758
- ])
759
- ) : {}
760
- });
761
- const handleSubmit = (values) => {
762
- const input = applyFieldMappings(values, formSchema?.fieldMappings);
763
- void onSubmit(input);
764
- };
765
- if (!hasFields) {
766
- return /* @__PURE__ */ jsxs(Stack, { children: [
767
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This workflow takes no input." }),
768
- /* @__PURE__ */ jsx(Button, { onClick: () => void onSubmit({}), loading: isPending, disabled, fullWidth: true, children: isPending ? formSchema?.submitButton?.loadingLabel ?? "Running..." : submitLabel })
769
- ] });
770
- }
771
- return /* @__PURE__ */ jsx("form", { onSubmit: form.onSubmit(handleSubmit), children: /* @__PURE__ */ jsxs(Stack, { children: [
772
- formSchema.fields.map((field) => /* @__PURE__ */ jsx(FormFieldRenderer, { field, form }, field.name)),
773
- /* @__PURE__ */ jsx(Button, { type: "submit", loading: isPending, disabled, fullWidth: true, children: isPending ? formSchema.submitButton?.loadingLabel ?? "Running..." : submitLabel })
774
- ] }) });
775
- }
776
- function ResourceExecuteDialog({ opened, onClose, resource, onViewExecution }) {
777
- const mutation = useExecuteAsync();
778
- const handleSubmit = async (input) => {
779
- await mutation.mutateAsync({
780
- resourceId: resource.resourceId,
781
- resourceType: resource.resourceType,
782
- input
783
- });
784
- };
785
- const handleReset = () => {
786
- mutation.reset();
787
- };
788
- const modalResource = {
789
- resourceId: resource.resourceId,
790
- resourceType: resource.resourceType,
791
- name: resource.name
792
- };
793
- return /* @__PURE__ */ jsx(
794
- ExecuteWorkflowModal,
795
- {
796
- opened,
797
- onClose,
798
- resource: modalResource,
799
- isPending: mutation.isPending,
800
- error: mutation.error,
801
- result: mutation.data ?? null,
802
- onViewExecution,
803
- onReset: handleReset,
804
- children: /* @__PURE__ */ jsx(
805
- ResourceExecuteForm,
806
- {
807
- formSchema: resource.formSchema ?? { fields: [] },
808
- onSubmit: handleSubmit,
809
- isPending: mutation.isPending,
810
- disabled: mutation.isPending
811
- }
812
- )
813
- }
814
- );
815
- }
816
- function ResourceDetailPage({
817
- type,
818
- resourceId,
819
- timeRange,
820
- renderExecutionPanel,
821
- onNavigateToResources,
822
- onNavigateToSessions,
823
- onNavigateBack
824
- }) {
825
- const { organizationReady } = useInitialization();
826
- const { data, isLoading, error } = useResources();
827
- const [connected, setConnected] = useState(false);
828
- const [runningCount, setRunningCount] = useState(0);
829
- const [runOpened, setRunOpened] = useState(false);
830
- const resource = data ? (() => {
831
- const resources = [...data.workflows, ...data.agents];
832
- const found = resources.find((r) => r.resourceId === resourceId && r.type === type);
833
- return found || null;
834
- })() : null;
835
- const {
836
- data: resourceDefinition,
837
- isLoading: definitionLoading,
838
- error: definitionError
839
- } = useResourceDefinition(resourceId, true);
840
- const handleConnectionStatus = (isConnected, count) => {
841
- setConnected(isConnected);
842
- setRunningCount(count);
843
- };
844
- if (!organizationReady || isLoading || definitionLoading) {
845
- return /* @__PURE__ */ jsx(SubshellLoader, {});
846
- }
847
- if (error) {
848
- return /* @__PURE__ */ jsx(ResourceErrorState, { error });
849
- }
850
- if (!resource) {
851
- return /* @__PURE__ */ jsx(ResourceNotFoundState, { type, resourceId, onNavigateBack });
852
- }
853
- const validResource = resource;
854
- const sessionCapable = isSessionCapable(type, resourceDefinition);
855
- return /* @__PURE__ */ jsxs(Fragment, { children: [
856
- /* @__PURE__ */ jsx(
857
- ResourceExecuteDialog,
858
- {
859
- opened: runOpened,
860
- onClose: () => setRunOpened(false),
861
- resource: {
862
- resourceId,
863
- resourceType: type,
864
- name: validResource.name,
865
- formSchema: resourceDefinition?.interface?.form
866
- }
867
- }
868
- ),
869
- /* @__PURE__ */ jsxs(Stack, { children: [
870
- /* @__PURE__ */ jsx(
871
- ResourceHeader,
872
- {
873
- resource: validResource,
874
- type,
875
- connected,
876
- runningCount,
877
- sessionCapable,
878
- onRun: () => setRunOpened(true),
879
- onNavigateToResources,
880
- onNavigateToSessions
881
- }
882
- ),
883
- /* @__PURE__ */ jsx(ResourceHealthPanel, { resourceId, resourceType: type, timeRange }),
884
- resourceDefinition && /* @__PURE__ */ jsx(ResourceDefinitionSection, { resourceDefinition })
885
- ] }),
886
- /* @__PURE__ */ jsx(
887
- Paper,
888
- {
889
- withBorder: true,
890
- p: "0",
891
- style: {
892
- flex: 1,
893
- overflow: "hidden",
894
- display: "flex",
895
- flexDirection: "column"
896
- },
897
- children: definitionError ? /* @__PURE__ */ jsx(ResourceErrorState, { error: definitionError }) : !resourceDefinition ? /* @__PURE__ */ jsx(ResourceErrorState, { error: new Error("Resource definition not found") }) : renderExecutionPanel({
898
- resourceId,
899
- resourceType: type,
900
- resourceName: validResource.name,
901
- resourceDefinition,
902
- onConnectionStatus: handleConnectionStatus
903
- })
904
- }
905
- )
906
- ] });
907
- }
908
- function CommandQueuePage({
909
- timeRange,
910
- pageSize = 20,
911
- onNavigateToTask,
912
- selectedCheckpoint,
913
- status = "pending",
914
- priorityRange = [1, 10]
915
- }) {
916
- const { organizationReady } = useInitialization();
917
- const [deleteConfirmId, setDeleteConfirmId] = useState(null);
918
- const { mutate: deleteTask, isPending: isDeleting } = useDeleteTask();
919
- const serverStatus = status === "all" ? void 0 : status;
920
- const { page, setPage, offset, totalPages } = usePaginationState(pageSize, [
921
- selectedCheckpoint,
922
- status,
923
- timeRange,
924
- priorityRange
925
- ]);
926
- const { data: checkpointData, isLoading: isLoadingCheckpoints } = useCommandQueueTotals({
927
- timeRange,
928
- priorityMin: priorityRange[0],
929
- priorityMax: priorityRange[1]
930
- });
931
- const { data: tasks = [], isLoading: isLoadingTasks } = useCommandQueue({
932
- status: serverStatus,
933
- humanCheckpoint: selectedCheckpoint,
934
- timeRange,
935
- priorityMin: priorityRange[0],
936
- priorityMax: priorityRange[1],
937
- limit: pageSize,
938
- offset
939
- });
940
- useEffect(() => {
941
- if (!isLoadingTasks && tasks.length === 0 && page > 1) {
942
- setPage(page - 1);
943
- }
944
- }, [tasks.length, isLoadingTasks]);
945
- if (isLoadingCheckpoints || !organizationReady) return /* @__PURE__ */ jsx(AppShellLoader, {});
946
- const totalTasks = checkpointData?.total ?? 0;
947
- return /* @__PURE__ */ jsxs(Stack, { children: [
948
- /* @__PURE__ */ jsx(PageTitleCaption, { title: "Command Queue", caption: "Human-in-the-loop approval system for agent/workflow actions" }),
949
- /* @__PURE__ */ jsx(Stack, { gap: "xs", children: isLoadingTasks ? /* @__PURE__ */ jsx(AppShellLoader, {}) : tasks.length === 0 ? /* @__PURE__ */ jsx(Card, { withBorder: true, children: /* @__PURE__ */ jsx(Text, { ta: "center", c: "dimmed", children: "No tasks found" }) }) : tasks.map((task) => /* @__PURE__ */ jsx(
950
- CommandQueueTaskRow,
951
- {
952
- task,
953
- onClick: () => onNavigateToTask(task.id),
954
- onDelete: (taskId) => setDeleteConfirmId(taskId)
955
- },
956
- task.id
957
- )) }),
958
- totalPages(totalTasks) > 1 && /* @__PURE__ */ jsx(Group, { justify: "center", children: /* @__PURE__ */ jsx(Pagination, { size: "sm", total: totalPages(totalTasks), value: page, onChange: setPage, boundaries: 1 }) }),
959
- /* @__PURE__ */ jsx(
960
- ConfirmationModal,
961
- {
962
- opened: deleteConfirmId !== null,
963
- onClose: () => setDeleteConfirmId(null),
964
- loading: isDeleting,
965
- icon: /* @__PURE__ */ jsx(IconTrash, { color: "red" }),
966
- title: "Delete Task",
967
- text: "Are you sure you want to delete this task? This action cannot be undone.",
968
- buttonText: "Delete Task",
969
- buttonColor: "red",
970
- confirmationHandler: () => {
971
- if (deleteConfirmId) {
972
- deleteTask(deleteConfirmId, {
973
- onSuccess: () => setDeleteConfirmId(null),
974
- onError: () => setDeleteConfirmId(null)
975
- });
976
- }
977
- }
978
- }
979
- )
980
- ] });
981
- }
982
- function getPriorityColor(priority) {
983
- if (priority >= 8) return "red";
984
- if (priority >= 5) return "yellow";
985
- return "gray";
986
- }
987
- function getStatusColor(status) {
988
- switch (status) {
989
- case "pending":
990
- return "blue";
991
- case "processing":
992
- return "blue";
993
- case "completed":
994
- return "green";
995
- case "failed":
996
- return "red";
997
- case "expired":
998
- return "orange";
999
- default:
1000
- return "gray";
1001
- }
1002
- }
1003
- function formatDate(date) {
1004
- const now = /* @__PURE__ */ new Date();
1005
- const diffMs = now.getTime() - date.getTime();
1006
- const diffMins = Math.floor(diffMs / 6e4);
1007
- const diffHours = Math.floor(diffMins / 60);
1008
- const diffDays = Math.floor(diffHours / 24);
1009
- if (diffMins < 60) return `${diffMins}m ago`;
1010
- if (diffHours < 24) return `${diffHours}h ago`;
1011
- return `${diffDays}d ago`;
1012
- }
1013
- function CommandQueueDetailPage({
1014
- taskId,
1015
- orgName,
1016
- renderRichText,
1017
- onNavigateBack,
1018
- onViewExecution
1019
- }) {
1020
- const { mutate: submitAction, isPending, error: submitError, reset: resetSubmitAction } = useSubmitAction();
1021
- const { mutate: deleteTask, isPending: isDeleting } = useDeleteTask();
1022
- const [actionModalOpened, setActionModalOpened] = useState(false);
1023
- const [selectedAction, setSelectedAction] = useState(null);
1024
- const [confirmAction, setConfirmAction] = useState(null);
1025
- const [deleteConfirmOpened, setDeleteConfirmOpened] = useState(false);
1026
- const [contextView, setContextView] = useState("formatted");
1027
- const [submitResultError, setSubmitResultError] = useState(null);
1028
- const { data: tasks, isLoading } = useCommandQueue();
1029
- const task = tasks?.find((t) => t.id === taskId);
1030
- const richTextRenderer = renderRichText ? (props) => renderRichText(props) : void 0;
1031
- const submitCallbacks = {
1032
- onSuccess: (data) => {
1033
- if (data.execution?.success === false) {
1034
- setSubmitResultError(data.execution.error?.message || "Action execution failed.");
1035
- } else {
1036
- setSubmitResultError(null);
1037
- }
1038
- },
1039
- onError: (error) => {
1040
- const { message, fields, requestId } = getErrorInfo(error);
1041
- setSubmitResultError(formatErrorMessage(message, requestId, fields));
1042
- }
1043
- };
1044
- const handleActionClick = (action) => {
1045
- if (action.requiresConfirmation) {
1046
- setConfirmAction(action);
1047
- } else if (action.form) {
1048
- setSubmitResultError(null);
1049
- setSelectedAction(action);
1050
- setActionModalOpened(true);
1051
- } else {
1052
- submitAction({ taskId, actionId: action.id }, submitCallbacks);
1053
- }
1054
- };
1055
- const handleConfirm = () => {
1056
- if (!confirmAction) return;
1057
- if (confirmAction.form) {
1058
- setSubmitResultError(null);
1059
- setSelectedAction(confirmAction);
1060
- setActionModalOpened(true);
1061
- } else {
1062
- submitAction({ taskId, actionId: confirmAction.id }, submitCallbacks);
1063
- }
1064
- setConfirmAction(null);
1065
- };
1066
- const handleRetry = () => {
1067
- if (task?.selectedAction) {
1068
- setSubmitResultError(null);
1069
- submitAction({ taskId, actionId: task.selectedAction, payload: task.actionPayload }, submitCallbacks);
1070
- }
1071
- };
1072
- const handleViewExecution = () => {
1073
- if (!task?.targetExecutionId || !task.targetResourceId || !task.targetResourceType) return;
1074
- onViewExecution(task.targetResourceType, task.targetResourceId, task.targetExecutionId);
1075
- };
1076
- if (isLoading) return /* @__PURE__ */ jsx(AppShellLoader, {});
1077
- if (!task) {
1078
- return /* @__PURE__ */ jsxs(Stack, { children: [
1079
- /* @__PURE__ */ jsx(
1080
- PageTitleCaption,
1081
- {
1082
- title: "Task Not Found",
1083
- rightSection: /* @__PURE__ */ jsx(Button, { variant: "subtle", leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }), onClick: onNavigateBack, size: "sm", children: "Back to Queue" })
1084
- }
1085
- ),
1086
- /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Text, { ta: "center", c: "dimmed", children: "This task no longer exists or could not be loaded." }) })
1087
- ] });
1088
- }
1089
- return /* @__PURE__ */ jsxs(Stack, { children: [
1090
- /* @__PURE__ */ jsx(
1091
- PageTitleCaption,
1092
- {
1093
- title: "Task Detail",
1094
- caption: task.description || "Task approval required",
1095
- rightSection: /* @__PURE__ */ jsx(Button, { variant: "light", leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }), onClick: onNavigateBack, size: "sm", children: "Back to Queue" })
1096
- }
1097
- ),
1098
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1099
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1100
- /* @__PURE__ */ jsxs(Badge, { color: getPriorityColor(task.priority), variant: "light", size: "sm", children: [
1101
- "P",
1102
- task.priority
1103
- ] }),
1104
- /* @__PURE__ */ jsx(
1105
- Badge,
1106
- {
1107
- color: getStatusColor(task.status),
1108
- variant: "light",
1109
- size: "sm",
1110
- leftSection: task.status === "processing" ? /* @__PURE__ */ jsx(Loader, { size: 6 }) : void 0,
1111
- children: task.status.toUpperCase()
1112
- }
1113
- ),
1114
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
1115
- /* @__PURE__ */ jsx(IconClock, { size: 14, style: { verticalAlign: "middle", marginRight: 4 } }),
1116
- formatDate(task.createdAt)
1117
- ] }),
1118
- task.expiresAt && /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
1119
- "Expires ",
1120
- formatDate(task.expiresAt)
1121
- ] })
1122
- ] }),
1123
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1124
- task.status === "failed" && /* @__PURE__ */ jsx(Button, { variant: "light", color: "red", size: "xs", loading: isPending, onClick: handleRetry, children: "Retry" }),
1125
- /* @__PURE__ */ jsx(
1126
- ActionIcon,
1127
- {
1128
- variant: "subtle",
1129
- color: "red",
1130
- size: "sm",
1131
- disabled: task.status === "processing",
1132
- onClick: () => setDeleteConfirmOpened(true),
1133
- title: "Delete task",
1134
- children: /* @__PURE__ */ jsx(IconTrash, { size: 16 })
1135
- }
1136
- )
1137
- ] })
1138
- ] }),
1139
- /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1140
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Resources" }),
1141
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: 2, children: [
1142
- /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
1143
- /* @__PURE__ */ jsx(Text, { size: "xs", children: "Task ID" }),
1144
- /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1145
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.id }),
1146
- /* @__PURE__ */ jsx(CopyButton, { value: task.id, children: ({ copied, copy }) => /* @__PURE__ */ jsx(
1147
- ActionIcon,
1148
- {
1149
- onClick: copy,
1150
- variant: "subtle",
1151
- size: "xs",
1152
- color: copied ? "green" : "var(--color-text-subtle)",
1153
- children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
1154
- }
1155
- ) })
1156
- ] })
1157
- ] }),
1158
- task.humanCheckpoint && /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
1159
- /* @__PURE__ */ jsx(Text, { size: "xs", children: "Checkpoint" }),
1160
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.humanCheckpoint })
1161
- ] })
1162
- ] }),
1163
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: 2, children: [
1164
- /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
1165
- /* @__PURE__ */ jsx(Text, { size: "xs", children: "Origin Resource" }),
1166
- /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1167
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.originResourceId }),
1168
- /* @__PURE__ */ jsx(CopyButton, { value: task.originResourceId, children: ({ copied, copy }) => /* @__PURE__ */ jsx(
1169
- ActionIcon,
1170
- {
1171
- onClick: copy,
1172
- variant: "subtle",
1173
- size: "xs",
1174
- color: copied ? "green" : "var(--color-text-subtle)",
1175
- children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
1176
- }
1177
- ) })
1178
- ] })
1179
- ] }),
1180
- /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
1181
- /* @__PURE__ */ jsx(Text, { size: "xs", children: "Origin Execution ID" }),
1182
- /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1183
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.originExecutionId }),
1184
- /* @__PURE__ */ jsx(CopyButton, { value: `${orgName}/${task.originResourceId} ${task.originExecutionId}`, children: ({ copied, copy }) => /* @__PURE__ */ jsx(
1185
- ActionIcon,
1186
- {
1187
- onClick: copy,
1188
- variant: "subtle",
1189
- size: "xs",
1190
- color: copied ? "green" : "var(--color-text-subtle)",
1191
- children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
1192
- }
1193
- ) })
1194
- ] })
1195
- ] })
1196
- ] }),
1197
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: 2, children: [
1198
- /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
1199
- /* @__PURE__ */ jsx(Text, { size: "xs", children: "Target Resource" }),
1200
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.targetResourceId || "N/A" })
1201
- ] }),
1202
- /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
1203
- /* @__PURE__ */ jsx(Text, { size: "xs", children: "Target Execution ID" }),
1204
- /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1205
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.targetExecutionId ?? "N/A" }),
1206
- task.targetExecutionId && /* @__PURE__ */ jsx(CopyButton, { value: `${orgName}/${task.targetResourceId} ${task.targetExecutionId}`, children: ({ copied, copy }) => /* @__PURE__ */ jsx(
1207
- ActionIcon,
1208
- {
1209
- onClick: copy,
1210
- variant: "subtle",
1211
- size: "xs",
1212
- color: copied ? "green" : "var(--color-text-subtle)",
1213
- children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
1214
- }
1215
- ) })
1216
- ] })
1217
- ] })
1218
- ] }),
1219
- /* @__PURE__ */ jsx(Group, { justify: "flex-end", children: /* @__PURE__ */ jsx(
1220
- Button,
1221
- {
1222
- variant: "light",
1223
- color: "var(--color-primary)",
1224
- size: "sm",
1225
- leftSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 14 }),
1226
- onClick: () => window.open(
1227
- `/operations/resources/${task.originResourceType}/${task.originResourceId}?exec=${task.originExecutionId}`,
1228
- "_blank",
1229
- "noopener,noreferrer"
1230
- ),
1231
- children: "View Origin Execution"
1232
- }
1233
- ) })
1234
- ] }) }),
1235
- /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1236
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", children: [
1237
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Context" }),
1238
- /* @__PURE__ */ jsx(
1239
- SegmentedControl,
1240
- {
1241
- value: contextView,
1242
- onChange: (v) => setContextView(v),
1243
- size: "xs",
1244
- data: [
1245
- { label: "Formatted", value: "formatted" },
1246
- { label: "JSON", value: "json" }
1247
- ]
1248
- }
1249
- )
1250
- ] }),
1251
- contextView === "formatted" ? /* @__PURE__ */ jsx(ContextViewer, { data: task.context }) : /* @__PURE__ */ jsx(JsonViewer, { data: task.context })
1252
- ] }) }),
1253
- (task.status === "pending" || task.status === "failed") && task.actions.length > 0 && /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1254
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Actions" }),
1255
- /* @__PURE__ */ jsx(Group, { gap: "sm", children: task.actions.map((action) => {
1256
- const Icon = getIcon(action.icon);
1257
- const variant = "light";
1258
- return /* @__PURE__ */ jsx(
1259
- Button,
1260
- {
1261
- variant,
1262
- color: action.color || (action.type === "danger" ? "red" : "blue"),
1263
- leftSection: Icon ? /* @__PURE__ */ jsx(Icon, { size: 16 }) : null,
1264
- loading: isPending,
1265
- onClick: () => handleActionClick(action),
1266
- title: action.description,
1267
- size: "sm",
1268
- children: action.label
1269
- },
1270
- action.id
1271
- );
1272
- }) })
1273
- ] }) }),
1274
- task.selectedAction && /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
1275
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Action" }),
1276
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1277
- /* @__PURE__ */ jsx(ThemeIcon, { size: "sm", variant: "light", color: "green", radius: "xl", children: /* @__PURE__ */ jsx(IconCheck, { size: 12 }) }),
1278
- /* @__PURE__ */ jsxs(Text, { fw: 600, size: "sm", style: { fontFamily: "var(--mantine-font-family-headings)" }, children: [
1279
- "Submitted: ",
1280
- task.actions.find((a) => a.id === task.selectedAction)?.label || task.selectedAction
1281
- ] }),
1282
- task.targetExecutionId && /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: "cyan", leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 10 }), children: "Executed" })
1283
- ] }),
1284
- task.actionPayload !== void 0 && task.actionPayload !== null && /* @__PURE__ */ jsx(JsonViewer, { data: task.actionPayload, maxHeight: 200 }),
1285
- task.completedAt && /* @__PURE__ */ jsxs(Text, { size: "xs", children: [
1286
- "Completed ",
1287
- formatDate(task.completedAt),
1288
- task.completedBy ? ` by ${task.completedBy}` : ""
1289
- ] }),
1290
- task.targetExecutionId && /* @__PURE__ */ jsx(
1291
- Button,
1292
- {
1293
- variant: "light",
1294
- size: "sm",
1295
- leftSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 14 }),
1296
- onClick: handleViewExecution,
1297
- w: "fit-content",
1298
- children: "View Target Execution"
1299
- }
1300
- )
1301
- ] }) }),
1302
- submitResultError && /* @__PURE__ */ jsx(
1303
- Alert,
1304
- {
1305
- color: "red",
1306
- variant: "light",
1307
- icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }),
1308
- title: "Submission failed",
1309
- withCloseButton: true,
1310
- onClose: () => setSubmitResultError(null),
1311
- children: /* @__PURE__ */ jsx(Text, { size: "sm", style: { whiteSpace: "pre-line" }, children: submitResultError })
1312
- }
1313
- ),
1314
- /* @__PURE__ */ jsx(CustomModal, { opened: !!confirmAction, onClose: () => setConfirmAction(null), size: "sm", children: /* @__PURE__ */ jsxs(Stack, { children: [
1315
- /* @__PURE__ */ jsx(Text, { fw: 600, children: "Confirm Action" }),
1316
- /* @__PURE__ */ jsx(Text, { size: "sm", children: confirmAction?.confirmationMessage || `Are you sure you want to ${confirmAction?.label.toLowerCase()}?` }),
1317
- /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
1318
- /* @__PURE__ */ jsx(Button, { variant: "default", onClick: () => setConfirmAction(null), children: "Cancel" }),
1319
- /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, children: confirmAction?.label })
1320
- ] })
1321
- ] }) }),
1322
- selectedAction && /* @__PURE__ */ jsx(
1323
- ActionModal,
1324
- {
1325
- action: selectedAction,
1326
- task,
1327
- opened: actionModalOpened,
1328
- onClose: () => {
1329
- setActionModalOpened(false);
1330
- resetSubmitAction();
1331
- },
1332
- onSubmit: (payload, notes) => {
1333
- submitAction(
1334
- { taskId, actionId: selectedAction.id, payload, notes },
1335
- {
1336
- onSuccess: (data) => {
1337
- submitCallbacks.onSuccess(data);
1338
- setActionModalOpened(false);
1339
- },
1340
- onError: submitCallbacks.onError
1341
- }
1342
- );
1343
- },
1344
- richTextRenderer,
1345
- error: submitError,
1346
- isPending
1347
- }
1348
- ),
1349
- /* @__PURE__ */ jsx(CustomModal, { opened: deleteConfirmOpened, onClose: () => setDeleteConfirmOpened(false), size: "sm", children: /* @__PURE__ */ jsxs(Stack, { children: [
1350
- /* @__PURE__ */ jsx(Text, { fw: 600, children: "Delete Task" }),
1351
- /* @__PURE__ */ jsx(Text, { size: "sm", children: "Are you sure you want to delete this task? This action cannot be undone." }),
1352
- /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
1353
- /* @__PURE__ */ jsx(Button, { variant: "default", onClick: () => setDeleteConfirmOpened(false), children: "Cancel" }),
1354
- /* @__PURE__ */ jsx(
1355
- Button,
1356
- {
1357
- color: "red",
1358
- loading: isDeleting,
1359
- onClick: () => {
1360
- deleteTask(task.id, {
1361
- onSuccess: () => onNavigateBack()
1362
- });
1363
- setDeleteConfirmOpened(false);
1364
- },
1365
- children: "Delete"
1366
- }
1367
- )
1368
- ] })
1369
- ] }) })
1370
- ] });
1371
- }
1372
-
1373
- // src/hooks/operations/command-view/utils/transformCommandViewData.ts
1374
- function transformCommandViewData(data) {
1375
- const nodes = [
1376
- // Map triggers (resourceId -> id)
1377
- ...data.triggers.map((trigger) => ({
1378
- id: trigger.resourceId,
1379
- type: "trigger",
1380
- name: trigger.name,
1381
- description: trigger.description,
1382
- status: trigger.status,
1383
- triggerType: trigger.triggerType,
1384
- webhookPath: trigger.webhookPath,
1385
- schedule: trigger.schedule
1386
- })),
1387
- // Map agents (resourceId -> id)
1388
- ...data.agents.map((agent) => {
1389
- const agentWithStats = agent;
1390
- return {
1391
- id: agent.resourceId,
1392
- type: "agent",
1393
- name: agent.name,
1394
- description: agent.description,
1395
- status: agent.status,
1396
- modelProvider: agent.modelProvider,
1397
- modelId: agent.modelId,
1398
- toolCount: agent.toolCount,
1399
- hasKnowledgeMap: agent.hasKnowledgeMap,
1400
- hasMemory: agent.hasMemory,
1401
- stats: agentWithStats.stats || null
1402
- // Preserve stats if present
1403
- };
1404
- }),
1405
- // Map workflows (resourceId -> id)
1406
- ...data.workflows.map((workflow) => {
1407
- const workflowWithStats = workflow;
1408
- return {
1409
- id: workflow.resourceId,
1410
- type: "workflow",
1411
- name: workflow.name,
1412
- description: workflow.description,
1413
- status: workflow.status,
1414
- stepCount: workflow.stepCount,
1415
- entryPoint: workflow.entryPoint,
1416
- stats: workflowWithStats.stats || null
1417
- // Preserve stats if present
1418
- };
1419
- }),
1420
- // Map integrations (resourceId -> id)
1421
- ...data.integrations.map((integration) => ({
1422
- id: integration.resourceId,
1423
- type: "integration",
1424
- name: integration.name,
1425
- description: integration.description,
1426
- status: integration.status,
1427
- provider: integration.provider,
1428
- connectionStatus: "connected",
1429
- // Default - runtime status not yet available
1430
- credentialName: integration.credentialName
1431
- })),
1432
- // Map external resources (resourceId -> id)
1433
- ...(data.externalResources ?? []).map((external) => ({
1434
- id: external.resourceId,
1435
- type: "external",
1436
- name: external.name,
1437
- description: external.description,
1438
- status: external.status,
1439
- platform: external.platform,
1440
- platformUrl: external.platformUrl,
1441
- externalId: external.externalId
1442
- })),
1443
- // Map human checkpoints to human nodes (resourceId -> id)
1444
- ...(data.humanCheckpoints ?? []).map((humanCheckpoint) => {
1445
- const checkpointWithStats = humanCheckpoint;
1446
- return {
1447
- id: humanCheckpoint.resourceId,
1448
- type: "human",
1449
- name: humanCheckpoint.name,
1450
- description: humanCheckpoint.description ?? "",
1451
- status: humanCheckpoint.status,
1452
- stats: checkpointWithStats.stats || null
1453
- // Preserve stats if present
1454
- };
1455
- })
1456
- ];
1457
- const edges = data.edges.map((edge, index) => ({
1458
- id: edge.id || `edge-${index}`,
1459
- source: edge.source,
1460
- target: edge.target,
1461
- relationship: edge.relationship
1462
- }));
1463
- return { nodes, edges };
1464
- }
1465
-
1466
- // src/hooks/operations/command-view/utils/filterCommandViewData.ts
1467
- function filterCommandViewData(data, filters) {
1468
- const { domains: selectedDomains, excludedDomains = [], status: statusFilter, showIntegrations } = filters;
1469
- const hasDomainFilter = selectedDomains.length > 0;
1470
- const hasExcludeFilter = excludedDomains.length > 0;
1471
- const hasStatusFilter = statusFilter !== "all";
1472
- const hasIntegrationFilter = !showIntegrations;
1473
- if (!hasDomainFilter && !hasExcludeFilter && !hasStatusFilter && !hasIntegrationFilter) {
1474
- return data;
1475
- }
1476
- const matchesDomainFilter = (domains) => {
1477
- if (hasExcludeFilter && (domains?.some((d) => excludedDomains.includes(d)) ?? false)) return false;
1478
- if (hasDomainFilter && !(domains?.some((d) => selectedDomains.includes(d)) ?? false)) return false;
1479
- return true;
1480
- };
1481
- const filteredAgents = data.agents.filter((agent) => {
1482
- if (hasStatusFilter && agent.status !== statusFilter) return false;
1483
- if (!matchesDomainFilter(agent.domains)) return false;
1484
- return true;
1485
- });
1486
- const filteredWorkflows = data.workflows.filter((workflow) => {
1487
- if (hasStatusFilter && workflow.status !== statusFilter) return false;
1488
- if (!matchesDomainFilter(workflow.domains)) return false;
1489
- return true;
1490
- });
1491
- const filteredTriggers = data.triggers.filter((trigger) => {
1492
- if (hasStatusFilter && trigger.status !== statusFilter) return false;
1493
- if (!matchesDomainFilter(trigger.domains)) return false;
1494
- return true;
1495
- });
1496
- const filteredIntegrations = showIntegrations ? data.integrations.filter((integration) => {
1497
- if (hasStatusFilter && integration.status !== statusFilter) return false;
1498
- if (!matchesDomainFilter(integration.domains)) return false;
1499
- return true;
1500
- }) : [];
1501
- const filteredExternalResources = (data.externalResources ?? []).filter((external) => {
1502
- if (hasStatusFilter && external.status !== statusFilter) return false;
1503
- if (!matchesDomainFilter(external.domains)) return false;
1504
- return true;
1505
- });
1506
- const filteredHumanCheckpoints = (data.humanCheckpoints ?? []).filter((checkpoint) => {
1507
- if (hasStatusFilter && checkpoint.status !== statusFilter) return false;
1508
- if (!matchesDomainFilter(checkpoint.domains)) return false;
1509
- return true;
1510
- });
1511
- const remainingNodeIds = /* @__PURE__ */ new Set([
1512
- ...filteredAgents.map((a) => a.resourceId),
1513
- ...filteredWorkflows.map((w) => w.resourceId),
1514
- ...filteredTriggers.map((t) => t.resourceId),
1515
- ...filteredIntegrations.map((i) => i.resourceId),
1516
- ...filteredExternalResources.map((e) => e.resourceId),
1517
- ...filteredHumanCheckpoints.map((h) => h.resourceId)
1518
- ]);
1519
- const filteredEdges = data.edges.filter(
1520
- (edge) => remainingNodeIds.has(edge.source) && remainingNodeIds.has(edge.target)
1521
- );
1522
- return {
1523
- ...data,
1524
- agents: filteredAgents,
1525
- workflows: filteredWorkflows,
1526
- triggers: filteredTriggers,
1527
- integrations: filteredIntegrations,
1528
- externalResources: filteredExternalResources,
1529
- humanCheckpoints: filteredHumanCheckpoints,
1530
- edges: filteredEdges
1531
- };
1532
- }
1533
-
1534
- // src/hooks/operations/command-view/utils/mergeStatsWithTopology.ts
1535
- function mergeStatsWithTopology(topology, stats) {
1536
- return {
1537
- ...topology,
1538
- agents: topology.agents.map((agent) => ({
1539
- ...agent,
1540
- stats: stats.resources[agent.resourceId] || null
1541
- })),
1542
- workflows: topology.workflows.map((workflow) => ({
1543
- ...workflow,
1544
- stats: stats.resources[workflow.resourceId] || null
1545
- })),
1546
- humanCheckpoints: topology.humanCheckpoints.map((checkpoint) => ({
1547
- ...checkpoint,
1548
- stats: stats.humanCheckpoints[checkpoint.resourceId] || null
1549
- }))
1550
- };
1551
- }
1552
- var FILTER_DEBOUNCE_DELAY = 150;
1553
- var TOPBAR_AND_PADDING = 54;
1554
- function CommandViewPage({ timeRange }) {
1555
- const { organizationReady } = useInitialization();
1556
- const { data, isLoading, error } = useCommandViewData();
1557
- const graphRef = useRef(null);
1558
- const statusFilter = useCommandViewStore((s) => s.statusFilter);
1559
- const showIntegrations = useCommandViewStore((s) => s.showIntegrations);
1560
- const fitViewOnFilter = useCommandViewStore((s) => s.fitViewOnFilter);
1561
- const selectedNodeId = useCommandViewStore((s) => s.selectedNodeId);
1562
- const setSelectedNodeId = useCommandViewStore((s) => s.setSelectedNodeId);
1563
- const domainFilters = useCommandViewDomainFilters((s) => s.filters);
1564
- const { includedDomains, excludedDomains } = useMemo(() => {
1565
- const included = [];
1566
- const excluded = [];
1567
- for (const [id, state] of Object.entries(domainFilters)) {
1568
- if (state === "include") included.push(id);
1569
- else if (state === "exclude") excluded.push(id);
1570
- }
1571
- return { includedDomains: included, excludedDomains: excluded };
1572
- }, [domainFilters]);
1573
- const { data: statsData, error: statsError } = useCommandViewStats(timeRange);
1574
- const cleanData = data ?? null;
1575
- const dataWithStats = useMemo(() => {
1576
- if (!cleanData) return null;
1577
- if (!statsData) return cleanData;
1578
- return mergeStatsWithTopology(cleanData, statsData);
1579
- }, [cleanData, statsData]);
1580
- const filteredData = useMemo(() => {
1581
- if (!dataWithStats) return null;
1582
- return filterCommandViewData(dataWithStats, {
1583
- domains: includedDomains,
1584
- excludedDomains,
1585
- status: statusFilter,
1586
- showIntegrations
1587
- });
1588
- }, [dataWithStats, includedDomains, excludedDomains, statusFilter, showIntegrations]);
1589
- const debouncedFitView = useCallback(
1590
- debounce(() => {
1591
- graphRef.current?.fitView();
1592
- }, FILTER_DEBOUNCE_DELAY),
1593
- []
1594
- );
1595
- useEffect(() => {
1596
- return () => debouncedFitView.cancel();
1597
- }, [debouncedFitView]);
1598
- useEffect(() => {
1599
- if (fitViewOnFilter) {
1600
- debouncedFitView();
1601
- }
1602
- }, [domainFilters, statusFilter, showIntegrations, debouncedFitView, fitViewOnFilter]);
1603
- if (!organizationReady) return /* @__PURE__ */ jsx(AppShellLoader, {});
1604
- const showLoader = isLoading && !data;
1605
- return /* @__PURE__ */ jsxs(
1606
- Box,
1607
- {
1608
- style: {
1609
- height: `calc(100vh - ${TOPBAR_AND_PADDING}px)`,
1610
- position: "relative",
1611
- overflow: "hidden",
1612
- padding: "var(--mantine-spacing-sm)"
1613
- },
1614
- children: [
1615
- showLoader && /* @__PURE__ */ jsx(Center, { style: { height: "100%" }, children: /* @__PURE__ */ jsx(Loader, { size: "xl" }) }),
1616
- error && !data && /* @__PURE__ */ jsx(APIErrorAlert, { error }),
1617
- statsError && /* @__PURE__ */ jsx(APIErrorAlert, { error: statsError, title: "Failed to load execution stats", color: "yellow" }),
1618
- !showLoader && !error && !data && /* @__PURE__ */ jsx(Alert, { color: "gray", title: "No Resources", children: "No resources found for this organization. Create agents, workflows, or integrations to see them here." }),
1619
- filteredData && /* @__PURE__ */ jsx(
1620
- CommandViewGraph,
1621
- {
1622
- ref: graphRef,
1623
- graph: transformCommandViewData(filteredData),
1624
- height: "100%",
1625
- selectedNodeId,
1626
- onNodeSelect: setSelectedNodeId
1627
- }
1628
- )
1629
- ]
1630
- }
1631
- );
1632
- }
1633
- function ProjectCard({ project, onNavigate }) {
1634
- const deleteProject = useDeleteProject();
1635
- const handleClick = () => {
1636
- onNavigate(project.id);
1637
- };
1638
- const handleDelete = async (e) => {
1639
- e.stopPropagation();
1640
- if (window.confirm("Delete this project and all its runs?")) {
1641
- await deleteProject.mutateAsync(project.id);
1642
- }
1643
- };
1644
- return /* @__PURE__ */ jsx(Card, { shadow: "sm", withBorder: true, style: { cursor: "pointer" }, onClick: handleClick, children: /* @__PURE__ */ jsxs(Stack, { children: [
1645
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
1646
- /* @__PURE__ */ jsxs(Group, { gap: "xs", align: "center", children: [
1647
- /* @__PURE__ */ jsx(IconFlask, { size: 20, color: "var(--color-primary)" }),
1648
- /* @__PURE__ */ jsx(Text, { fw: 600, lineClamp: 1, style: { fontFamily: "var(--elevasis-font-family-subtitle)" }, children: project.name })
1649
- ] }),
1650
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1651
- /* @__PURE__ */ jsx(Badge, { variant: "light", size: "sm", children: project.resourceType }),
1652
- /* @__PURE__ */ jsxs(Menu, { shadow: "md", width: 150, position: "bottom-end", children: [
1653
- /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(IconDotsVertical, { size: 16 }) }) }),
1654
- /* @__PURE__ */ jsx(Menu.Dropdown, { children: /* @__PURE__ */ jsx(Menu.Item, { leftSection: /* @__PURE__ */ jsx(IconTrash, { size: 14 }), color: "red", onClick: handleDelete, children: "Delete" }) })
1655
- ] })
1656
- ] })
1657
- ] }),
1658
- project.description && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", lineClamp: 1, children: project.description }),
1659
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1660
- "Created ",
1661
- new Date(project.createdAt).toLocaleDateString()
1662
- ] })
1663
- ] }) });
1664
- }
1665
- function CreateProjectModal({ opened, onClose, resourceId, resourceType }) {
1666
- const createProject = useCreateProject();
1667
- const form = useForm({
1668
- initialValues: {
1669
- name: "",
1670
- description: ""
1671
- },
1672
- validate: {
1673
- name: (value) => value.trim().length === 0 ? "Name is required" : null
1674
- }
1675
- });
1676
- const handleSubmit = async (values) => {
1677
- await createProject.mutateAsync({
1678
- resourceId,
1679
- resourceType,
1680
- name: values.name.trim(),
1681
- description: values.description.trim() || void 0
1682
- });
1683
- form.reset();
1684
- onClose();
1685
- };
1686
- return /* @__PURE__ */ jsx(Modal, { opened, onClose, title: "Create Calibration Project", children: /* @__PURE__ */ jsx("form", { onSubmit: form.onSubmit(handleSubmit), children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1687
- /* @__PURE__ */ jsx(
1688
- TextInput,
1689
- {
1690
- label: "Project Name",
1691
- placeholder: "e.g., Q1 2025 Model Selection",
1692
- required: true,
1693
- ...form.getInputProps("name")
1694
- }
1695
- ),
1696
- /* @__PURE__ */ jsx(
1697
- Textarea,
1698
- {
1699
- label: "Description",
1700
- placeholder: "Optional: Describe the goal of this calibration project",
1701
- minRows: 2,
1702
- ...form.getInputProps("description")
1703
- }
1704
- ),
1705
- /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
1706
- /* @__PURE__ */ jsx(Button, { variant: "subtle", onClick: onClose, children: "Cancel" }),
1707
- /* @__PURE__ */ jsx(Button, { type: "submit", loading: createProject.isPending, children: "Create Project" })
1708
- ] })
1709
- ] }) }) });
1710
- }
1711
- function CalibrationPage({ resourceId, resourceType, onProjectNavigate }) {
1712
- const [createModalOpen, setCreateModalOpen] = useState(false);
1713
- const { data: projects, isLoading, error } = useCalibrationProjects(resourceId, resourceType);
1714
- if (isLoading) {
1715
- return /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) });
1716
- }
1717
- if (error) {
1718
- return /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), title: "Error", color: "red", children: "Failed to load calibration projects. Please try again." });
1719
- }
1720
- return /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
1721
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", children: [
1722
- /* @__PURE__ */ jsxs("div", { children: [
1723
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Calibration Lab" }),
1724
- /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: "Compare AI configurations and optimize performance" })
1725
- ] }),
1726
- /* @__PURE__ */ jsx(Button, { leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: () => setCreateModalOpen(true), children: "New Project" })
1727
- ] }),
1728
- projects && projects.length === 0 ? /* @__PURE__ */ jsx(
1729
- EmptyState,
1730
- {
1731
- icon: IconAdjustments,
1732
- title: "No projects yet",
1733
- description: "Create your first calibration project to start comparing AI configurations."
1734
- }
1735
- ) : /* @__PURE__ */ jsx(Stack, { children: projects?.map((project) => /* @__PURE__ */ jsx(ProjectCard, { project, onNavigate: onProjectNavigate }, project.id)) }),
1736
- /* @__PURE__ */ jsx(
1737
- CreateProjectModal,
1738
- {
1739
- opened: createModalOpen,
1740
- onClose: () => setCreateModalOpen(false),
1741
- resourceId,
1742
- resourceType
1743
- }
1744
- )
1745
- ] }) });
1746
- }
1747
- function CalibrationProjectDetailPage({
1748
- projectId,
1749
- calibrationRootPath,
1750
- renderRunCard,
1751
- renderCreateModal,
1752
- runs,
1753
- runsLoading
1754
- }) {
1755
- const [createModalOpen, setCreateModalOpen] = useState(false);
1756
- const { organizationReady } = useInitialization();
1757
- const { data: project, isLoading: projectLoading, error: projectError } = useCalibrationProject(projectId);
1758
- const projectNotFound = !projectLoading && (projectError || !project);
1759
- const isLoading = projectLoading || runsLoading;
1760
- if (!organizationReady || isLoading) return /* @__PURE__ */ jsx(SubshellLoader, {});
1761
- if (!project || projectNotFound) {
1762
- return null;
1763
- }
1764
- const runCount = runs?.length ?? 0;
1765
- const caption = `${project.resourceType} \xB7 ${runCount} run${runCount !== 1 ? "s" : ""}`;
1766
- return /* @__PURE__ */ jsxs(Stack, { children: [
1767
- /* @__PURE__ */ jsx(
1768
- PageTitleCaption,
1769
- {
1770
- title: project.name,
1771
- caption,
1772
- rightSection: /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
1773
- /* @__PURE__ */ jsx(
1774
- Button,
1775
- {
1776
- variant: "light",
1777
- size: "sm",
1778
- leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
1779
- component: Link,
1780
- to: calibrationRootPath,
1781
- children: "Calibration"
1782
- }
1783
- ),
1784
- /* @__PURE__ */ jsx(Button, { leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: () => setCreateModalOpen(true), children: "New Run" })
1785
- ] })
1786
- }
1787
- ),
1788
- runs && runs.length === 0 ? /* @__PURE__ */ jsx(Alert, { color: "gray", title: "No runs yet", children: "Create your first calibration run to start testing configurations." }) : /* @__PURE__ */ jsx(Stack, { gap: "md", children: runs?.map((run) => renderRunCard({ run, projectId })) }),
1789
- renderCreateModal({
1790
- opened: createModalOpen,
1791
- onClose: () => setCreateModalOpen(false),
1792
- projectId
1793
- })
1794
- ] });
1795
- }
1796
- function CalibrationProjectsPage({ onNavigateToProject }) {
1797
- const { organizationReady } = useInitialization();
1798
- const { data: projects, isLoading } = useAllCalibrationProjects();
1799
- if (!organizationReady || isLoading) return /* @__PURE__ */ jsx(SubshellLoader, {});
1800
- const projectCount = projects?.length ?? 0;
1801
- const caption = `${projectCount} Project${projectCount !== 1 ? "s" : ""}`;
1802
- return /* @__PURE__ */ jsxs(Stack, { children: [
1803
- /* @__PURE__ */ jsx(PageTitleCaption, { title: "Calibration Lab", caption }),
1804
- projects && projects.length > 0 && /* @__PURE__ */ jsx(SimpleGrid, { cols: { base: 1, md: 2 }, children: projects.map((project) => /* @__PURE__ */ jsx(ProjectCard, { project, onNavigate: onNavigateToProject }, project.id)) })
1805
- ] });
1806
- }
1807
- function formatRelativeTime2(date) {
1808
- if (!date) return "N/A";
1809
- const dateObj = typeof date === "string" ? new Date(date) : date;
1810
- return formatDistanceToNow(dateObj, { addSuffix: true });
1811
- }
1812
- var FILTER_STATE_ICONS2 = {
1813
- neutral: IconCircleDashed,
1814
- include: IconCircleCheck,
1815
- exclude: IconCircleX
1816
- };
1817
- var FILTER_STATE_COLORS2 = {
1818
- neutral: "var(--color-surface-hover)",
1819
- include: "var(--mantine-color-green-6)",
1820
- exclude: "var(--mantine-color-red-6)"
1821
- };
1822
- var FILTER_STATE_LABELS2 = {
1823
- neutral: "Not filtered",
1824
- include: "Include only",
1825
- exclude: "Exclude"
1826
- };
1827
- var EXECUTION_SECTIONS = [
1828
- { status: "failed", title: "Failed Executions", badgeColor: "red" },
1829
- { status: "warning", title: "Warning Executions", badgeColor: "yellow" },
1830
- { status: "completed", title: "Successful Executions", badgeColor: null }
1831
- ];
1832
- var HOVER_CARD_STYLE = {
1833
- cursor: "pointer",
1834
- transition: "box-shadow var(--duration-fast) var(--easing)",
1835
- textDecoration: "none",
1836
- color: "inherit"
1837
- };
1838
- function handleHoverEnter(e) {
1839
- e.currentTarget.style.boxShadow = "var(--standard-box-shadow)";
1840
- }
1841
- function handleHoverLeave(e) {
1842
- e.currentTarget.style.boxShadow = "";
1843
- }
1844
- function ExecutionStatusSection({ executions, status, title, badgeColor, resourceUrl }) {
1845
- const filtered = executions.filter((e) => e.status === status);
1846
- if (filtered.length === 0) return null;
1847
- return /* @__PURE__ */ jsxs("div", { children: [
1848
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: 8, children: [
1849
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", children: title }),
1850
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: filtered.length })
1851
- ] }),
1852
- /* @__PURE__ */ jsx(Stack, { gap: "xs", children: filtered.map((execution) => /* @__PURE__ */ jsxs(
1853
- Card,
1854
- {
1855
- padding: "xs",
1856
- withBorder: true,
1857
- component: "a",
1858
- href: `${resourceUrl}?exec=${execution.executionId}`,
1859
- target: "_blank",
1860
- rel: "noopener noreferrer",
1861
- style: HOVER_CARD_STYLE,
1862
- onMouseEnter: handleHoverEnter,
1863
- onMouseLeave: handleHoverLeave,
1864
- children: [
1865
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: status === "failed" && execution.errorMessage ? 4 : 0, children: [
1866
- badgeColor ? /* @__PURE__ */ jsx(Badge, { size: "xs", color: badgeColor, variant: "light", children: status }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "green", children: "\u2713 Completed" }),
1867
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatRelativeTime2(execution.startedAt) })
1868
- ] }),
1869
- status === "failed" && execution.errorMessage && /* @__PURE__ */ jsx(Text, { size: "xs", c: "red", lineClamp: 2, children: execution.errorMessage })
1870
- ]
1871
- },
1872
- execution.executionId
1873
- )) }),
1874
- /* @__PURE__ */ jsx(Space, { h: "sm" })
1875
- ] });
1876
- }
1877
- function CommandViewSidebarContent({ timeRange }) {
1878
- const theme = useMantineTheme();
1879
- const colors = useCyberColors();
1880
- const statusFilter = useCommandViewStore((s) => s.statusFilter);
1881
- const setStatusFilter = useCommandViewStore((s) => s.setStatusFilter);
1882
- const showIntegrations = useCommandViewStore((s) => s.showIntegrations);
1883
- const setShowIntegrations = useCommandViewStore((s) => s.setShowIntegrations);
1884
- const fitViewOnFilter = useCommandViewStore((s) => s.fitViewOnFilter);
1885
- const setFitViewOnFilter = useCommandViewStore((s) => s.setFitViewOnFilter);
1886
- const selectedNodeId = useCommandViewStore((s) => s.selectedNodeId);
1887
- const domainFilters = useCommandViewDomainFilters((s) => s.filters);
1888
- const cycleDomainFilter = useCommandViewDomainFilters((s) => s.cycle);
1889
- const { data, isLoading } = useCommandViewData();
1890
- const { data: statsData } = useCommandViewStats(timeRange);
1891
- const cleanData = data ?? null;
1892
- const dataWithStats = useMemo(() => {
1893
- if (!cleanData) return null;
1894
- if (!statsData) return cleanData;
1895
- return mergeStatsWithTopology(cleanData, statsData);
1896
- }, [cleanData, statsData]);
1897
- const { donutSuccessCount, donutFailedCount } = useMemo(() => {
1898
- if (!cleanData || !statsData) return { donutSuccessCount: 0, donutFailedCount: 0 };
1899
- const allResources = [...cleanData.agents, ...cleanData.workflows];
1900
- const includes = Object.entries(domainFilters).filter(([, v]) => v === "include").map(([k]) => k);
1901
- const excludes = Object.entries(domainFilters).filter(([, v]) => v === "exclude").map(([k]) => k);
1902
- const filtered = allResources.filter((r) => {
1903
- const domains = r.domains || [];
1904
- if (excludes.length > 0 && domains.some((d) => excludes.includes(d))) return false;
1905
- if (includes.length > 0 && !domains.some((d) => includes.includes(d))) return false;
1906
- if (statusFilter !== "all" && r.status !== statusFilter) return false;
1907
- return true;
1908
- });
1909
- const filteredIds = new Set(filtered.map((r) => r.resourceId));
1910
- let success = 0;
1911
- let failed = 0;
1912
- for (const [id, stats] of Object.entries(statsData.resources)) {
1913
- if (filteredIds.has(id)) {
1914
- success += stats.successCount;
1915
- failed += stats.failureCount;
1916
- }
1917
- }
1918
- return { donutSuccessCount: success, donutFailedCount: failed };
1919
- }, [cleanData, statsData, domainFilters, statusFilter]);
1920
- const domainDefinitions = cleanData?.domainDefinitions ?? [];
1921
- const selectedNode = useMemo(() => {
1922
- if (!selectedNodeId || !dataWithStats) return null;
1923
- const allNodes = [
1924
- ...dataWithStats.agents || [],
1925
- ...dataWithStats.workflows || [],
1926
- ...dataWithStats.triggers || [],
1927
- ...dataWithStats.integrations || [],
1928
- ...dataWithStats.externalResources || [],
1929
- ...dataWithStats.humanCheckpoints || []
1930
- ];
1931
- return allNodes.find((node) => {
1932
- const nodeId = getNodeId(node);
1933
- return nodeId === selectedNodeId || node.name === selectedNodeId;
1934
- }) || null;
1935
- }, [selectedNodeId, dataWithStats]);
1936
- const isNavigable = selectedNode?.type === "agent" || selectedNode?.type === "workflow";
1937
- const isHumanCheckpoint = selectedNode?.type === "human";
1938
- const selectedResourceId = useMemo(() => {
1939
- if (!selectedNode) return null;
1940
- return getNodeId(selectedNode);
1941
- }, [selectedNode]);
1942
- const getNavigationUrl = () => {
1943
- if (!selectedNode || !selectedResourceId) return null;
1944
- if (selectedNode.type === "agent") return `/operations/resources/agent/${selectedResourceId}`;
1945
- if (selectedNode.type === "workflow") return `/operations/resources/workflow/${selectedResourceId}`;
1946
- if (selectedNode.type === "human") return `/command-center/command-queue?checkpoint=${selectedResourceId}`;
1947
- return null;
1948
- };
1949
- const resourceUrl = selectedNode?.type === "agent" ? `/operations/resources/agent/${selectedResourceId}` : `/operations/resources/workflow/${selectedResourceId}`;
1950
- const {
1951
- data: executionsData,
1952
- isLoading: executionsLoading,
1953
- error: executionsError
1954
- } = useResourceExecutions({
1955
- resourceId: selectedResourceId,
1956
- timeRange,
1957
- enabled: isNavigable
1958
- });
1959
- const {
1960
- data: checkpointTasksData,
1961
- isLoading: checkpointTasksLoading,
1962
- error: checkpointTasksError
1963
- } = useCheckpointTasks({
1964
- checkpointId: selectedResourceId,
1965
- enabled: isHumanCheckpoint
1966
- });
1967
- const totalExecutions = donutSuccessCount + donutFailedCount;
1968
- const successRate = totalExecutions > 0 ? donutSuccessCount / totalExecutions * 100 : 0;
1969
- const healthSegments = [
1970
- { name: "Completed", value: donutSuccessCount, color: colors.green },
1971
- { name: "Failed", value: donutFailedCount, color: colors.red }
1972
- ];
1973
- const centerValueColor = totalExecutions === 0 ? "var(--mantine-color-dimmed)" : successRate >= 95 ? colors.green : successRate >= 80 ? colors.yellow : colors.red;
1974
- if (isLoading && !data) {
1975
- return /* @__PURE__ */ jsx(Box, { style: { flex: 1, minHeight: 0, padding: theme.spacing.sm }, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) });
1976
- }
1977
- return /* @__PURE__ */ jsxs(
1978
- Box,
1979
- {
1980
- style: {
1981
- flex: 1,
1982
- minHeight: 0,
1983
- display: "flex",
1984
- flexDirection: "column",
1985
- overflow: "hidden"
1986
- },
1987
- children: [
1988
- /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconSitemap, label: "Command View" }),
1989
- /* @__PURE__ */ jsx(Box, { style: { padding: theme.spacing.sm, paddingBottom: 0 }, children: /* @__PURE__ */ jsx(Box, { pb: "xs", mb: 4, children: /* @__PURE__ */ jsx(
1990
- CyberDonut,
1991
- {
1992
- title: `Execution Health (${timeRange})`,
1993
- segments: healthSegments,
1994
- centerValue: totalExecutions === 0 ? "\u2014" : `${Math.round(successRate)}%`,
1995
- centerLabel: `${totalExecutions} runs`,
1996
- centerValueColor,
1997
- glowId: "cvHealthGlow",
1998
- colors
1999
- }
2000
- ) }) }),
2001
- /* @__PURE__ */ jsxs("div", { style: { flex: 1, overflow: "auto" }, children: [
2002
- /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconAdjustmentsHorizontal, label: "Node Filters", withTopBorder: true }),
2003
- /* @__PURE__ */ jsxs(Stack, { gap: "sm", p: "sm", children: [
2004
- /* @__PURE__ */ jsxs("div", { children: [
2005
- /* @__PURE__ */ jsx(Text, { size: "sm", mb: 8, children: "Environment" }),
2006
- /* @__PURE__ */ jsx(
2007
- SegmentedControl,
2008
- {
2009
- value: statusFilter,
2010
- onChange: (value) => setStatusFilter(value),
2011
- data: [
2012
- { label: "All", value: "all" },
2013
- { label: "Prod", value: "prod" },
2014
- { label: "Dev", value: "dev" }
2015
- ],
2016
- size: "xs",
2017
- fullWidth: true,
2018
- color: "var(--color-primary)"
2019
- }
2020
- )
2021
- ] }),
2022
- /* @__PURE__ */ jsx(
2023
- Switch,
2024
- {
2025
- label: "Show Integrations",
2026
- description: "Toggle integration relationship edges",
2027
- checked: showIntegrations,
2028
- onChange: (event) => setShowIntegrations(event.currentTarget.checked),
2029
- size: "sm"
2030
- }
2031
- ),
2032
- domainDefinitions.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
2033
- /* @__PURE__ */ jsx(Text, { size: "sm", mb: 8, children: "Domain" }),
2034
- /* @__PURE__ */ jsx(Stack, { gap: 2, children: [...domainDefinitions].sort((a, b) => {
2035
- const bottom = /* @__PURE__ */ new Set(["utility", "diagnostic"]);
2036
- const aB = bottom.has(a.id) ? 1 : 0;
2037
- const bB = bottom.has(b.id) ? 1 : 0;
2038
- if (aB !== bB) return aB - bB;
2039
- return a.name.localeCompare(b.name);
2040
- }).map((domain) => {
2041
- const filterState = domainFilters[domain.id] || "neutral";
2042
- const StateIcon = FILTER_STATE_ICONS2[filterState];
2043
- return /* @__PURE__ */ jsx(
2044
- UnstyledButton,
2045
- {
2046
- title: FILTER_STATE_LABELS2[filterState],
2047
- onClick: () => cycleDomainFilter(domain.id),
2048
- py: 5,
2049
- px: 6,
2050
- style: {
2051
- transition: "background-color var(--duration-fast) var(--easing)",
2052
- "&:hover": { backgroundColor: "var(--color-surface-hover)" }
2053
- },
2054
- children: /* @__PURE__ */ jsxs(Group, { gap: 10, wrap: "nowrap", children: [
2055
- /* @__PURE__ */ jsx(
2056
- StateIcon,
2057
- {
2058
- size: 16,
2059
- style: {
2060
- color: FILTER_STATE_COLORS2[filterState],
2061
- flexShrink: 0,
2062
- transition: "color var(--duration-fast) var(--easing)"
2063
- }
2064
- }
2065
- ),
2066
- /* @__PURE__ */ jsx(
2067
- Text,
2068
- {
2069
- size: "sm",
2070
- truncate: true,
2071
- fw: filterState !== "neutral" ? 500 : 400,
2072
- c: filterState !== "neutral" ? void 0 : "dimmed",
2073
- children: domain.name
2074
- }
2075
- )
2076
- ] })
2077
- },
2078
- domain.id
2079
- );
2080
- }) })
2081
- ] })
2082
- ] }),
2083
- /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconSettings, label: "Settings", withTopBorder: true }),
2084
- /* @__PURE__ */ jsx(Stack, { gap: "sm", p: "sm", children: /* @__PURE__ */ jsx(
2085
- Switch,
2086
- {
2087
- label: "Fit view on filter",
2088
- description: "Re-center graph when filters change",
2089
- checked: fitViewOnFilter,
2090
- onChange: (event) => setFitViewOnFilter(event.currentTarget.checked),
2091
- size: "sm"
2092
- }
2093
- ) }),
2094
- selectedNode && /* @__PURE__ */ jsxs(Fragment, { children: [
2095
- /* @__PURE__ */ jsx(Divider, {}),
2096
- /* @__PURE__ */ jsxs(Stack, { gap: "xs", p: "sm", mt: 8, children: [
2097
- /* @__PURE__ */ jsx(Title, { order: 4, children: selectedNode.name }),
2098
- selectedNode.description && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: selectedNode.description }),
2099
- (isNavigable || isHumanCheckpoint) && /* @__PURE__ */ jsxs(
2100
- Button,
2101
- {
2102
- component: "a",
2103
- href: getNavigationUrl() || "#",
2104
- target: "_blank",
2105
- rel: "noopener noreferrer",
2106
- variant: "light",
2107
- size: "xs",
2108
- leftSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 14 }),
2109
- mt: 4,
2110
- children: [
2111
- "Go to",
2112
- " ",
2113
- selectedNode.type === "agent" ? "Agent" : selectedNode.type === "workflow" ? "Workflow" : "Queue"
2114
- ]
2115
- }
2116
- ),
2117
- /* @__PURE__ */ jsx(Space, { h: "sm" })
2118
- ] })
2119
- ] }),
2120
- selectedNode && isNavigable && /* @__PURE__ */ jsx(Stack, { p: "sm", children: executionsLoading ? /* @__PURE__ */ jsx(Center, { py: "md", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) }) : executionsError ? /* @__PURE__ */ jsx(APIErrorAlert, { error: executionsError, title: "Failed to load executions" }) : executionsData && executionsData.executions.length > 0 ? EXECUTION_SECTIONS.map((section) => /* @__PURE__ */ jsx(
2121
- ExecutionStatusSection,
2122
- {
2123
- executions: executionsData.executions,
2124
- status: section.status,
2125
- title: section.title,
2126
- badgeColor: section.badgeColor,
2127
- resourceUrl
2128
- },
2129
- section.status
2130
- )) : executionsData ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No executions in the selected time range" }) : null }),
2131
- selectedNode && isHumanCheckpoint && /* @__PURE__ */ jsx(Stack, { p: "sm", children: checkpointTasksLoading ? /* @__PURE__ */ jsx(Center, { py: "md", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) }) : checkpointTasksError ? /* @__PURE__ */ jsx(APIErrorAlert, { error: checkpointTasksError, title: "Failed to load pending tasks" }) : checkpointTasksData && checkpointTasksData.tasks.length > 0 ? /* @__PURE__ */ jsxs("div", { children: [
2132
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: 8, children: [
2133
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", children: "Pending Tasks" }),
2134
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: checkpointTasksData.tasks.length })
2135
- ] }),
2136
- /* @__PURE__ */ jsx(Stack, { gap: "xs", children: checkpointTasksData.tasks.map((task) => /* @__PURE__ */ jsxs(
2137
- Card,
2138
- {
2139
- padding: "xs",
2140
- withBorder: true,
2141
- component: "a",
2142
- href: `/command-center/command-queue?task=${task.id}`,
2143
- target: "_blank",
2144
- rel: "noopener noreferrer",
2145
- style: HOVER_CARD_STYLE,
2146
- onMouseEnter: handleHoverEnter,
2147
- onMouseLeave: handleHoverLeave,
2148
- children: [
2149
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: task.description ? 4 : 0, children: [
2150
- /* @__PURE__ */ jsx(Badge, { size: "xs", color: "orange", variant: "light", children: "pending" }),
2151
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatRelativeTime2(task.createdAt) })
2152
- ] }),
2153
- task.description && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", lineClamp: 2, children: task.description })
2154
- ]
2155
- },
2156
- task.id
2157
- )) })
2158
- ] }) : checkpointTasksData ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No pending tasks" }) : null })
2159
- ] })
2160
- ]
2161
- }
2162
- );
2163
- }
2164
- function ComparisonTable({ run, logs, metrics }) {
2165
- if (run.results.length === 0) {
2166
- return /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Text, { c: "dimmed", ta: "center", children: "No results yet. Execute the calibration run to see comparisons." }) });
2167
- }
2168
- return /* @__PURE__ */ jsx(Stack, { children: run.results.map((result, index) => /* @__PURE__ */ jsx(ResultCard, { result, run, logs, metrics }, index)) });
2169
- }
2170
- function ResultCard({ result, run, logs, metrics }) {
2171
- const [expanded, setExpanded] = useState(false);
2172
- const isSingleResult = "executionId" in result;
2173
- const executionId = isSingleResult ? result.executionId : result.sessionId;
2174
- const inputIndex = isSingleResult ? result.inputIndex : 0;
2175
- const log = logs[executionId];
2176
- const metric = metrics[executionId];
2177
- const statusColors = {
2178
- pending: "gray",
2179
- running: "blue",
2180
- completed: "green",
2181
- failed: "red"
2182
- };
2183
- return /* @__PURE__ */ jsxs(
2184
- Paper,
2185
- {
2186
- withBorder: true,
2187
- style: {
2188
- cursor: "pointer",
2189
- transition: "background-color var(--duration-fast) var(--easing)"
2190
- },
2191
- children: [
2192
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", onClick: () => setExpanded(!expanded), children: [
2193
- /* @__PURE__ */ jsxs(Group, { gap: "md", wrap: "nowrap", children: [
2194
- /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", children: expanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: 16 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 16 }) }),
2195
- /* @__PURE__ */ jsxs(Box, { children: [
2196
- /* @__PURE__ */ jsx(Text, { fw: 600, size: "sm", style: { fontFamily: "var(--mantine-font-family-headings)" }, children: result.variantName }),
2197
- run.executionMode === "single" && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2198
- "Input #",
2199
- inputIndex + 1
2200
- ] })
2201
- ] })
2202
- ] }),
2203
- /* @__PURE__ */ jsxs(Group, { gap: "md", wrap: "nowrap", children: [
2204
- metric?.totalDuration && metric.totalDuration > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
2205
- /* @__PURE__ */ jsx(IconClock, { size: 14, style: { opacity: 0.5 } }),
2206
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
2207
- (metric.totalDuration / 1e3).toFixed(2),
2208
- "s"
2209
- ] })
2210
- ] }),
2211
- metric?.totalCost && metric.totalCost > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
2212
- /* @__PURE__ */ jsx(IconCoin, { size: 14, style: { opacity: 0.5 } }),
2213
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
2214
- "$",
2215
- metric.totalCost.toFixed(4)
2216
- ] })
2217
- ] }),
2218
- run.gradingRubric && result.grade && /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
2219
- result.grade.passed ? /* @__PURE__ */ jsx(IconCheck, { size: 14, color: "var(--color-success)" }) : /* @__PURE__ */ jsx(IconX, { size: 14, color: "var(--color-error)" }),
2220
- /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
2221
- (result.grade.score * 100).toFixed(0),
2222
- "%"
2223
- ] })
2224
- ] }),
2225
- /* @__PURE__ */ jsx(Badge, { color: statusColors[result.status], size: "sm", children: result.status })
2226
- ] })
2227
- ] }),
2228
- /* @__PURE__ */ jsx(Collapse, { in: expanded, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", mt: "md", pt: "md", style: { borderTop: "1px solid var(--color-border)" }, children: [
2229
- run.testInputs[inputIndex] !== void 0 && /* @__PURE__ */ jsxs(Box, { children: [
2230
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "dimmed", mb: "xs", children: "INPUT" }),
2231
- /* @__PURE__ */ jsx(Paper, { style: { background: "var(--color-background)" }, children: /* @__PURE__ */ jsx(JsonViewer, { data: run.testInputs[inputIndex], maxHeight: "200px" }) })
2232
- ] }),
2233
- /* @__PURE__ */ jsxs(Box, { children: [
2234
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "dimmed", mb: "xs", children: "OUTPUT" }),
2235
- /* @__PURE__ */ jsx(Paper, { style: { background: "var(--color-background)" }, children: log?.output ? /* @__PURE__ */ jsx(JsonViewer, { data: log.output, maxHeight: "300px" }) : result.errorMessage ? /* @__PURE__ */ jsx(Text, { c: "red", size: "sm", children: result.errorMessage }) : /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: "No output available" }) })
2236
- ] }),
2237
- log?.error && /* @__PURE__ */ jsxs(Box, { children: [
2238
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "red", mb: "xs", children: "ERROR" }),
2239
- /* @__PURE__ */ jsxs(Paper, { style: { background: "var(--color-background)" }, children: [
2240
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", children: log.error.message }),
2241
- log.error.category && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", mt: "xs", children: [
2242
- "Category: ",
2243
- log.error.category
2244
- ] })
2245
- ] })
2246
- ] }),
2247
- result.grade && /* @__PURE__ */ jsxs(Box, { children: [
2248
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "dimmed", mb: "xs", children: "GRADE DETAILS" }),
2249
- /* @__PURE__ */ jsx(Paper, { style: { background: "var(--color-background)" }, children: /* @__PURE__ */ jsx(Stack, { gap: "xs", children: Object.entries(result.grade.details).map(([criterion, detail]) => {
2250
- const d = detail;
2251
- return /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
2252
- /* @__PURE__ */ jsx(Text, { size: "sm", children: criterion }),
2253
- /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
2254
- /* @__PURE__ */ jsxs(Badge, { size: "sm", color: d.score >= 0.7 ? "green" : d.score >= 0.4 ? "yellow" : "red", children: [
2255
- (d.score * 100).toFixed(0),
2256
- "%"
2257
- ] }),
2258
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", style: { maxWidth: 300 }, lineClamp: 1, children: d.justification })
2259
- ] })
2260
- ] }, criterion);
2261
- }) }) })
2262
- ] }),
2263
- result.gradeError && /* @__PURE__ */ jsxs(Box, { children: [
2264
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "red", mb: "xs", children: "GRADING ERROR" }),
2265
- /* @__PURE__ */ jsx(Paper, { style: { background: "var(--color-background)" }, children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", children: result.gradeError }) })
2266
- ] })
2267
- ] }) })
2268
- ]
2269
- }
2270
- );
2271
- }
2272
- function GradingPanel({ run, rubric }) {
2273
- const variantSummaries = run.configVariants.map((variant) => {
2274
- const variantResults = run.results.filter((r) => r.variantName === variant.variantName);
2275
- const gradedResults = variantResults.filter((r) => r.grade);
2276
- const avgScore = gradedResults.length > 0 ? gradedResults.reduce((sum, r) => sum + (r.grade?.score ?? 0), 0) / gradedResults.length : null;
2277
- const passRate = gradedResults.length > 0 ? gradedResults.filter((r) => r.grade?.passed).length / gradedResults.length : null;
2278
- return {
2279
- variantName: variant.variantName,
2280
- avgScore,
2281
- passRate,
2282
- total: variantResults.length,
2283
- graded: gradedResults.length
2284
- };
2285
- });
2286
- return /* @__PURE__ */ jsxs(Stack, { gap: "lg", children: [
2287
- /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
2288
- /* @__PURE__ */ jsx(Title, { order: 4, mb: "md", children: "Grading Rubric" }),
2289
- /* @__PURE__ */ jsxs(Text, { size: "sm", mb: "md", children: [
2290
- "Passing threshold: ",
2291
- (rubric.passingThreshold * 100).toFixed(0),
2292
- "%"
2293
- ] }),
2294
- /* @__PURE__ */ jsxs(Table, { children: [
2295
- /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
2296
- /* @__PURE__ */ jsx(Table.Th, { children: "Criterion" }),
2297
- /* @__PURE__ */ jsx(Table.Th, { children: "Weight" }),
2298
- /* @__PURE__ */ jsx(Table.Th, { children: "Description" })
2299
- ] }) }),
2300
- /* @__PURE__ */ jsx(Table.Tbody, { children: rubric.criteria.map((criterion, i) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
2301
- /* @__PURE__ */ jsx(Table.Td, { fw: 500, children: criterion.name }),
2302
- /* @__PURE__ */ jsxs(Table.Td, { children: [
2303
- (criterion.weight * 100).toFixed(0),
2304
- "%"
2305
- ] }),
2306
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: criterion.description }) })
2307
- ] }, i)) })
2308
- ] })
2309
- ] }),
2310
- /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
2311
- /* @__PURE__ */ jsx(Title, { order: 4, mb: "md", children: "Results by Variant" }),
2312
- /* @__PURE__ */ jsx(Stack, { gap: "md", children: variantSummaries.map((summary, i) => /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
2313
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: "xs", children: [
2314
- /* @__PURE__ */ jsx(Text, { fw: 500, children: summary.variantName }),
2315
- summary.avgScore !== null && /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
2316
- /* @__PURE__ */ jsx(
2317
- ThemeIcon,
2318
- {
2319
- size: "sm",
2320
- color: summary.avgScore >= rubric.passingThreshold ? "green" : "red",
2321
- variant: "light",
2322
- children: summary.avgScore >= rubric.passingThreshold ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconX, { size: 14 })
2323
- }
2324
- ),
2325
- /* @__PURE__ */ jsxs(Text, { fw: 500, children: [
2326
- (summary.avgScore * 100).toFixed(0),
2327
- "%"
2328
- ] })
2329
- ] })
2330
- ] }),
2331
- summary.avgScore !== null ? /* @__PURE__ */ jsxs(Fragment, { children: [
2332
- /* @__PURE__ */ jsx(
2333
- Progress,
2334
- {
2335
- value: summary.avgScore * 100,
2336
- color: summary.avgScore >= rubric.passingThreshold ? "green" : "red",
2337
- size: "sm",
2338
- mb: "xs"
2339
- }
2340
- ),
2341
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2342
- "Pass rate: ",
2343
- summary.passRate !== null ? `${(summary.passRate * 100).toFixed(0)}%` : "-",
2344
- " \xB7",
2345
- " ",
2346
- summary.graded,
2347
- "/",
2348
- summary.total,
2349
- " graded"
2350
- ] })
2351
- ] }) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Not graded yet" })
2352
- ] }, i)) })
2353
- ] })
2354
- ] });
2355
- }
2356
- function CalibrationProgress({ runId, manager, apiUrl }) {
2357
- const { connected, events, summary, isComplete, error } = useCalibrationSSE({
2358
- runId,
2359
- manager,
2360
- apiUrl,
2361
- enabled: true
2362
- });
2363
- const executionStarted = events.filter((e) => e.type === "execution-started" || e.type === "session-started").length;
2364
- const executionCompleted = events.filter(
2365
- (e) => e.type === "execution-completed" || e.type === "session-completed"
2366
- ).length;
2367
- const executionFailed = events.filter((e) => e.type === "execution-failed").length;
2368
- const gradingCompleted = events.filter((e) => e.type === "grading-completed").length;
2369
- const progressPercent = summary ? (summary.completed + summary.failed) / summary.total * 100 : executionStarted > 0 ? executionCompleted / executionStarted * 100 : 0;
2370
- return /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
2371
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
2372
- connected ? /* @__PURE__ */ jsx(Badge, { color: "green", leftSection: /* @__PURE__ */ jsx(Loader, { size: 10 }), children: "Live" }) : /* @__PURE__ */ jsx(Badge, { color: "gray", children: "Connecting..." }),
2373
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: isComplete ? "Calibration complete" : "Calibration in progress..." })
2374
- ] }),
2375
- /* @__PURE__ */ jsxs("div", { children: [
2376
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: "xs", children: [
2377
- /* @__PURE__ */ jsx(Text, { size: "sm", children: "Progress" }),
2378
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
2379
- executionCompleted,
2380
- "/",
2381
- executionStarted || "?",
2382
- " executions"
2383
- ] })
2384
- ] }),
2385
- /* @__PURE__ */ jsx(
2386
- Progress,
2387
- {
2388
- value: progressPercent,
2389
- color: error ? "red" : isComplete ? "green" : void 0,
2390
- animated: !isComplete
2391
- }
2392
- )
2393
- ] }),
2394
- /* @__PURE__ */ jsxs(Group, { gap: "xl", children: [
2395
- /* @__PURE__ */ jsxs("div", { children: [
2396
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Completed" }),
2397
- /* @__PURE__ */ jsx(Text, { size: "lg", fw: 500, c: "green", children: executionCompleted })
2398
- ] }),
2399
- /* @__PURE__ */ jsxs("div", { children: [
2400
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Failed" }),
2401
- /* @__PURE__ */ jsx(Text, { size: "lg", fw: 500, c: "red", children: executionFailed })
2402
- ] }),
2403
- /* @__PURE__ */ jsxs("div", { children: [
2404
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "Graded" }),
2405
- /* @__PURE__ */ jsx(Text, { size: "lg", fw: 500, children: gradingCompleted })
2406
- ] })
2407
- ] }),
2408
- /* @__PURE__ */ jsxs("div", { children: [
2409
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, mb: "xs", children: "Recent Activity" }),
2410
- /* @__PURE__ */ jsx(Timeline, { active: events.length, bulletSize: 20, lineWidth: 2, children: events.slice(-5).map((event, index) => /* @__PURE__ */ jsx(Timeline.Item, { bullet: getEventBullet(event), title: getEventTitle(event), children: /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "xs", children: getEventDescription(event) }) }, index)) })
2411
- ] }),
2412
- error && /* @__PURE__ */ jsxs(Text, { c: "red", size: "sm", children: [
2413
- "Error: ",
2414
- error
2415
- ] })
2416
- ] }) });
2417
- }
2418
- function getEventBullet(event) {
2419
- const iconSize = 12;
2420
- switch (event.type) {
2421
- case "execution-started":
2422
- case "session-started":
2423
- case "turn-started":
2424
- return /* @__PURE__ */ jsx(ThemeIcon, { size: 20, radius: "xl", children: /* @__PURE__ */ jsx(IconPlayerPlay, { size: iconSize }) });
2425
- case "execution-completed":
2426
- case "session-completed":
2427
- case "turn-completed":
2428
- return /* @__PURE__ */ jsx(ThemeIcon, { size: 20, color: "green", radius: "xl", children: /* @__PURE__ */ jsx(IconCheck, { size: iconSize }) });
2429
- case "execution-failed":
2430
- return /* @__PURE__ */ jsx(ThemeIcon, { size: 20, color: "red", radius: "xl", children: /* @__PURE__ */ jsx(IconX, { size: iconSize }) });
2431
- case "grading-started":
2432
- case "grading-completed":
2433
- return /* @__PURE__ */ jsx(ThemeIcon, { size: 20, color: "violet", radius: "xl", children: /* @__PURE__ */ jsx(IconChartBar, { size: iconSize }) });
2434
- case "grading-failed":
2435
- return /* @__PURE__ */ jsx(ThemeIcon, { size: 20, color: "red", radius: "xl", children: /* @__PURE__ */ jsx(IconX, { size: iconSize }) });
2436
- default:
2437
- return /* @__PURE__ */ jsx(ThemeIcon, { size: 20, color: "gray", radius: "xl", children: /* @__PURE__ */ jsx(IconClock, { size: iconSize }) });
2438
- }
2439
- }
2440
- function getEventTitle(event) {
2441
- switch (event.type) {
2442
- case "connected":
2443
- return "Connected";
2444
- case "execution-started":
2445
- return `Started: ${event.variantName}`;
2446
- case "execution-completed":
2447
- return `Completed: ${event.variantName}`;
2448
- case "execution-failed":
2449
- return `Failed: ${event.variantName}`;
2450
- case "session-started":
2451
- return `Session started: ${event.variantName}`;
2452
- case "session-completed":
2453
- return `Session completed: ${event.variantName}`;
2454
- case "turn-started":
2455
- return `Turn ${event.turnNumber}: ${event.variantName}`;
2456
- case "turn-completed":
2457
- return `Turn ${event.turnNumber} done: ${event.variantName}`;
2458
- case "grading-started":
2459
- return `Grading: ${event.variantName}`;
2460
- case "grading-completed":
2461
- return `Graded: ${event.variantName} (${(event.score * 100).toFixed(0)}%)`;
2462
- case "grading-failed":
2463
- return `Grading failed: ${event.variantName}`;
2464
- case "calibration-completed":
2465
- return "Calibration complete";
2466
- case "calibration-failed":
2467
- return "Calibration failed";
2468
- default:
2469
- return "Unknown event";
2470
- }
2471
- }
2472
- function getEventDescription(event) {
2473
- switch (event.type) {
2474
- case "execution-started":
2475
- return `Input #${(event.inputIndex ?? 0) + 1}`;
2476
- case "execution-completed":
2477
- return `Input #${(event.inputIndex ?? 0) + 1}`;
2478
- case "execution-failed":
2479
- return event.error;
2480
- case "session-completed":
2481
- return `${event.turnCount} turns`;
2482
- case "grading-failed":
2483
- return event.error;
2484
- case "calibration-completed":
2485
- return `${event.summary.completed}/${event.summary.total} succeeded`;
2486
- case "calibration-failed":
2487
- return event.error;
2488
- default:
2489
- return "";
2490
- }
2491
- }
2492
- var STATUS_COLORS = {
2493
- pending: "gray",
2494
- running: "blue",
2495
- completed: "green",
2496
- partial: "yellow",
2497
- failed: "red"
2498
- };
2499
- function CalibrationRunDetailPage({
2500
- runId,
2501
- onNavigateToProject,
2502
- renderSessionComparison,
2503
- manager,
2504
- apiUrl
2505
- }) {
2506
- const { organizationReady } = useInitialization();
2507
- const { data: fullData, isLoading, error, refetch } = useCalibrationRunFull(runId);
2508
- const executeRun = useExecuteRun();
2509
- const gradeRun = useGradeRun();
2510
- const [inputsExpanded, setInputsExpanded] = useState(false);
2511
- if (!organizationReady || isLoading) return /* @__PURE__ */ jsx(SubshellLoader, {});
2512
- if (!fullData || error) {
2513
- return null;
2514
- }
2515
- const { run, logs, metrics } = fullData;
2516
- const handleExecute = async () => {
2517
- await executeRun.mutateAsync(runId);
2518
- refetch();
2519
- };
2520
- const handleGrade = async () => {
2521
- await gradeRun.mutateAsync({
2522
- runId,
2523
- rubric: run.gradingRubric ?? void 0,
2524
- graderModel: run.graderModel ?? void 0
2525
- });
2526
- refetch();
2527
- };
2528
- const completedCount = run.results.filter((r) => r.status === "completed").length;
2529
- const failedCount = run.results.filter((r) => r.status === "failed").length;
2530
- const totalDuration = Object.values(metrics).reduce((sum, m) => {
2531
- const metric = m;
2532
- return sum + (metric.totalDuration || 0);
2533
- }, 0);
2534
- const totalCost = Object.values(metrics).reduce((sum, m) => {
2535
- const metric = m;
2536
- return sum + (metric.totalCost || 0);
2537
- }, 0);
2538
- const caption = `${run.configVariants.length} variants \xB7 ${run.testInputs.length} inputs`;
2539
- return /* @__PURE__ */ jsxs(Stack, { children: [
2540
- /* @__PURE__ */ jsx(
2541
- PageTitleCaption,
2542
- {
2543
- title: run.name,
2544
- caption,
2545
- rightSection: /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
2546
- /* @__PURE__ */ jsx(
2547
- Button,
2548
- {
2549
- variant: "light",
2550
- size: "sm",
2551
- leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
2552
- onClick: () => onNavigateToProject(run.projectId),
2553
- children: "Project"
2554
- }
2555
- ),
2556
- /* @__PURE__ */ jsx(Badge, { color: STATUS_COLORS[run.status], children: run.status }),
2557
- /* @__PURE__ */ jsx(Badge, { variant: "outline", children: run.executionMode }),
2558
- run.status === "pending" && /* @__PURE__ */ jsx(Button, { leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 }), onClick: handleExecute, loading: executeRun.isPending, children: "Execute" }),
2559
- run.status === "completed" && run.gradingRubric && /* @__PURE__ */ jsx(
2560
- Button,
2561
- {
2562
- leftSection: /* @__PURE__ */ jsx(IconReportAnalytics, { size: 16 }),
2563
- variant: "outline",
2564
- onClick: handleGrade,
2565
- loading: gradeRun.isPending,
2566
- children: "Re-Grade"
2567
- }
2568
- )
2569
- ] })
2570
- }
2571
- ),
2572
- /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
2573
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "wrap", gap: "sm", children: [
2574
- run.results.length > 0 && /* @__PURE__ */ jsxs(Group, { gap: "md", children: [
2575
- /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
2576
- /* @__PURE__ */ jsx(IconCheck, { size: 14, color: "var(--color-success)" }),
2577
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, c: "green", children: completedCount }),
2578
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "completed" })
2579
- ] }),
2580
- failedCount > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
2581
- /* @__PURE__ */ jsx(IconX, { size: 14, color: "var(--color-error)" }),
2582
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, c: "red", children: failedCount }),
2583
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "failed" })
2584
- ] }),
2585
- totalDuration > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
2586
- /* @__PURE__ */ jsx(IconClock, { size: 14, style: { opacity: 0.5 } }),
2587
- /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
2588
- (totalDuration / 1e3).toFixed(1),
2589
- "s"
2590
- ] })
2591
- ] }),
2592
- totalCost > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
2593
- /* @__PURE__ */ jsx(IconCoin, { size: 14, style: { opacity: 0.5 } }),
2594
- /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
2595
- "$",
2596
- totalCost.toFixed(4)
2597
- ] })
2598
- ] })
2599
- ] }),
2600
- /* @__PURE__ */ jsxs(Group, { gap: "md", children: [
2601
- run.createdAt && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2602
- "Created: ",
2603
- new Date(run.createdAt).toLocaleString()
2604
- ] }),
2605
- run.completedAt && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2606
- "Completed: ",
2607
- new Date(run.completedAt).toLocaleString()
2608
- ] })
2609
- ] })
2610
- ] }),
2611
- run.description && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", mt: "xs", children: run.description }),
2612
- /* @__PURE__ */ jsxs(Box, { mt: "sm", pt: "sm", style: { borderTop: "1px solid var(--color-border)" }, children: [
2613
- /* @__PURE__ */ jsxs(Group, { gap: "xs", style: { cursor: "pointer" }, onClick: () => setInputsExpanded(!inputsExpanded), children: [
2614
- /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", children: inputsExpanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: 16 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 16 }) }),
2615
- /* @__PURE__ */ jsxs(Text, { fw: 500, size: "sm", children: [
2616
- "Test Inputs (",
2617
- run.testInputs.length,
2618
- ")"
2619
- ] })
2620
- ] }),
2621
- /* @__PURE__ */ jsx(Collapse, { in: inputsExpanded, children: /* @__PURE__ */ jsx(Stack, { mt: "sm", children: run.testInputs.map((input, index) => /* @__PURE__ */ jsxs(Box, { children: [
2622
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", mb: "xs", children: [
2623
- "Input #",
2624
- index + 1
2625
- ] }),
2626
- /* @__PURE__ */ jsx(Paper, { style: { background: "var(--color-background)" }, children: /* @__PURE__ */ jsx(JsonViewer, { data: input, maxHeight: "150px" }) })
2627
- ] }, index)) }) })
2628
- ] })
2629
- ] }),
2630
- run.status === "running" && /* @__PURE__ */ jsx(CalibrationProgress, { runId, manager, apiUrl }),
2631
- /* @__PURE__ */ jsxs(Tabs, { defaultValue: "comparison", children: [
2632
- /* @__PURE__ */ jsxs(Tabs.List, { children: [
2633
- /* @__PURE__ */ jsx(Tabs.Tab, { value: "comparison", children: "Results" }),
2634
- run.gradingRubric && /* @__PURE__ */ jsx(Tabs.Tab, { value: "grading", children: "Grading" })
2635
- ] }),
2636
- /* @__PURE__ */ jsx(Tabs.Panel, { value: "comparison", pt: "sm", children: run.executionMode === "session" ? renderSessionComparison?.({ run }) : /* @__PURE__ */ jsx(ComparisonTable, { run, logs, metrics }) }),
2637
- run.gradingRubric && /* @__PURE__ */ jsx(Tabs.Panel, { value: "grading", pt: "sm", children: /* @__PURE__ */ jsx(GradingPanel, { run, rubric: run.gradingRubric }) })
2638
- ] })
2639
- ] });
2640
- }
2641
- function CalibrationSidebar({
2642
- currentProjectId,
2643
- currentRunId,
2644
- currentPath,
2645
- onProjectClick,
2646
- onRunClick
2647
- }) {
2648
- const theme = useMantineTheme();
2649
- const queryClient = useQueryClient();
2650
- const { organizationReady } = useInitialization();
2651
- const { data: projects, isLoading: isProjectsLoading } = useAllCalibrationProjects();
2652
- const [expandedProjects, setExpandedProjects] = useState(() => {
2653
- if (currentProjectId) {
2654
- return { [currentProjectId]: true };
2655
- }
2656
- return {};
2657
- });
2658
- const toggleProject = (projectId) => {
2659
- setExpandedProjects((prev) => ({
2660
- ...prev,
2661
- [projectId]: !prev[projectId]
2662
- }));
2663
- };
2664
- const handleRefresh = () => {
2665
- queryClient.invalidateQueries({ queryKey: [...calibrationKeys.all, "projects"] });
2666
- };
2667
- const hasData = projects && projects.length > 0;
2668
- const isInitialLoading = !organizationReady || isProjectsLoading && !hasData;
2669
- return /* @__PURE__ */ jsxs(
2670
- Box,
2671
- {
2672
- style: {
2673
- flex: 1,
2674
- minHeight: 0,
2675
- padding: theme.spacing.sm,
2676
- display: "flex",
2677
- flexDirection: "column",
2678
- overflow: "hidden"
2679
- },
2680
- children: [
2681
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: "md", mt: "-4", pt: "0", style: { flexShrink: 0 }, children: [
2682
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 600, c: "dimmed", tt: "uppercase", children: "Projects" }),
2683
- /* @__PURE__ */ jsx(UnstyledButton, { title: "Refresh projects", onClick: handleRefresh, children: /* @__PURE__ */ jsx(IconRefresh, { size: 14, style: { opacity: 0.6 } }) })
2684
- ] }),
2685
- /* @__PURE__ */ jsx(ScrollArea, { style: { flex: 1, minHeight: 0 }, scrollbarSize: 8, children: isInitialLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) }) : projects && projects.length > 0 ? /* @__PURE__ */ jsx(Stack, { gap: "xs", children: projects.map((project) => /* @__PURE__ */ jsx(
2686
- ProjectGroup,
2687
- {
2688
- project,
2689
- isExpanded: expandedProjects[project.id] || false,
2690
- currentPath,
2691
- currentRunId,
2692
- onToggle: () => toggleProject(project.id),
2693
- onProjectClick,
2694
- onRunClick
2695
- },
2696
- project.id
2697
- )) }) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", style: { padding: "6px 8px" }, children: "No projects yet" }) })
2698
- ]
2699
- }
2700
- );
2701
- }
2702
- function ProjectGroup({
2703
- project,
2704
- isExpanded,
2705
- currentPath,
2706
- currentRunId,
2707
- onToggle,
2708
- onProjectClick,
2709
- onRunClick
2710
- }) {
2711
- const { data: runs, isLoading: isRunsLoading } = useCalibrationRuns(isExpanded ? project.id : "");
2712
- const isProjectActive = currentPath.includes(`/project/${project.id}`);
2713
- const hasActiveRun = runs?.some((run) => run.id === currentRunId) || false;
2714
- const isActive = isProjectActive || hasActiveRun;
2715
- return /* @__PURE__ */ jsx(
2716
- CollapsibleSidebarGroup,
2717
- {
2718
- icon: IconFlask,
2719
- label: project.name,
2720
- isExpanded,
2721
- onToggle,
2722
- isActive,
2723
- onLabelClick: () => onProjectClick(project.id),
2724
- isEmpty: !runs || runs.length === 0,
2725
- emptyMessage: "No runs yet",
2726
- isLoading: isRunsLoading,
2727
- loadingComponent: /* @__PURE__ */ jsx(Center, { p: "xs", children: /* @__PURE__ */ jsx(Loader, { size: "xs" }) }),
2728
- children: runs?.map((run) => /* @__PURE__ */ jsx(RunItem, { run, isActive: currentRunId === run.id, onRunClick }, run.id))
2729
- }
2730
- );
2731
- }
2732
- function RunItem({ run, isActive, onRunClick }) {
2733
- return /* @__PURE__ */ jsx(SidebarListItem, { icon: IconPlayerPlay, label: run.name, isActive, onClick: () => onRunClick(run.id) });
2734
- }
2735
- function WorkflowExecutionPanel({
2736
- resourceId,
2737
- resourceDefinition,
2738
- sseManager,
2739
- apiUrl,
2740
- onConnectionStatus
2741
- }) {
2742
- const theme = useMantineTheme();
2743
- const { executions, isLoading, selectedId, setSelectedId, streamingLogs } = useExecutionPanelState({
2744
- resourceId,
2745
- manager: sseManager,
2746
- apiUrl,
2747
- limit: PAGE_SIZE_DEFAULT,
2748
- onConnectionStatus
2749
- });
2750
- const [selectedStepId, setSelectedStepId] = useState(null);
2751
- const isValidSelection = selectedId && executions.some((e) => e.id === selectedId);
2752
- const { data: selectedExecution } = useExecution(resourceId, isValidSelection ? selectedId : "");
2753
- const executionStreamingLogs = selectedId ? streamingLogs.get(selectedId) : void 0;
2754
- const mergedExecution = useMergedExecution(selectedExecution, executionStreamingLogs);
2755
- const timelineData = useTimelineData(mergedExecution, resourceDefinition);
2756
- const isRemoteStub = resourceDefinition.steps.length === 1 && resourceDefinition.steps[0]?.id === "_remote";
2757
- useEffect(() => {
2758
- setSelectedStepId(null);
2759
- }, [selectedId]);
2760
- if (isLoading) {
2761
- return /* @__PURE__ */ jsx(Center, { h: "100%", children: /* @__PURE__ */ jsx(Loader, { size: "md" }) });
2762
- }
2763
- return /* @__PURE__ */ jsxs(Stack, { gap: "0", style: { height: "100%", overflow: "hidden" }, children: [
2764
- isRemoteStub ? /* @__PURE__ */ jsx(Alert, { variant: "light", icon: /* @__PURE__ */ jsx(IconInfoCircle, { size: 16 }), m: "sm", children: "Workflow topology is not available for remotely deployed resources. Execution logs are shown below." }) : /* @__PURE__ */ jsxs(Fragment, { children: [
2765
- /* @__PURE__ */ jsx(
2766
- UnifiedWorkflowGraph,
2767
- {
2768
- resourceDefinition,
2769
- executionLogs: mergedExecution?.executionLogs,
2770
- selectedStepId,
2771
- onStepSelect: setSelectedStepId
2772
- }
2773
- ),
2774
- timelineData && /* @__PURE__ */ jsx(WorkflowExecutionTimeline, { timelineData, selectedStepId })
2775
- ] }),
2776
- /* @__PURE__ */ jsx(
2777
- "div",
2778
- {
2779
- style: {
2780
- flex: 1,
2781
- overflow: "hidden",
2782
- padding: theme.spacing.sm
2783
- },
2784
- children: /* @__PURE__ */ jsx(
2785
- WorkflowExecutionLogs,
2786
- {
2787
- resourceId,
2788
- executionId: selectedId,
2789
- execution: mergedExecution,
2790
- selectedStepId,
2791
- timelineData,
2792
- onExecutionDeleted: () => setSelectedId(void 0)
2793
- }
2794
- )
2795
- }
2796
- )
2797
- ] });
2798
- }
2799
- function AgentExecutionPanel({
2800
- resourceId,
2801
- resourceDefinition,
2802
- sseManager,
2803
- apiUrl,
2804
- onConnectionStatus
2805
- }) {
2806
- const theme = useMantineTheme();
2807
- const { isLoading, selectedId, setSelectedId, liveExecutions, streamingLogs } = useExecutionPanelState({
2808
- resourceId,
2809
- manager: sseManager,
2810
- apiUrl,
2811
- limit: PAGE_SIZE_DEFAULT,
2812
- onConnectionStatus
2813
- });
2814
- const [selectedIterationId, setSelectedIterationId] = useState(null);
2815
- const { data: selectedExecution } = useExecution(resourceId, selectedId || "");
2816
- const executionStreamingLogs = selectedId ? streamingLogs.get(selectedId) : void 0;
2817
- const mergedExecution = useMergedExecution(selectedExecution, executionStreamingLogs);
2818
- const iterationData = useAgentIterationData(mergedExecution, resourceDefinition);
2819
- if (isLoading) {
2820
- return /* @__PURE__ */ jsx(Center, { h: "100%", p: "lg", children: /* @__PURE__ */ jsx(Loader, { size: "md" }) });
2821
- }
2822
- return /* @__PURE__ */ jsxs(Stack, { gap: "0", style: { height: "100%", overflow: "hidden" }, children: [
2823
- /* @__PURE__ */ jsx(
2824
- AgentExecutionVisualizer,
2825
- {
2826
- resourceDefinition,
2827
- iterationData,
2828
- selectedExecutionId: selectedId,
2829
- liveExecutions,
2830
- selectedIterationId,
2831
- onIterationSelect: setSelectedIterationId
2832
- }
2833
- ),
2834
- iterationData && /* @__PURE__ */ jsx(AgentExecutionTimeline, { iterationData, selectedIterationId }),
2835
- /* @__PURE__ */ jsx(
2836
- "div",
2837
- {
2838
- style: {
2839
- flex: 1,
2840
- overflow: "hidden",
2841
- padding: theme.spacing.sm
2842
- },
2843
- children: /* @__PURE__ */ jsx(
2844
- AgentExecutionLogs,
2845
- {
2846
- resourceId,
2847
- executionId: selectedId,
2848
- execution: mergedExecution,
2849
- selectedIterationId,
2850
- iterationData,
2851
- onExecutionDeleted: () => setSelectedId(void 0)
2852
- }
2853
- )
2854
- }
2855
- )
2856
- ] });
2857
- }
2858
- function ResourceDefinitionError({
2859
- resourceId,
2860
- resourceType,
2861
- resourceName
2862
- }) {
2863
- const handleRefresh = () => {
2864
- window.location.reload();
2865
- };
2866
- return /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(Alert, { variant: "light", color: "red", title: "Resource Definition Error", icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), children: /* @__PURE__ */ jsxs(Stack, { children: [
2867
- /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
2868
- "Failed to load resource definition for ",
2869
- resourceType,
2870
- ' "',
2871
- resourceName || resourceId,
2872
- '". This may indicate a data loading issue or an incompatible resource format.'
2873
- ] }),
2874
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2875
- "Resource ID: ",
2876
- resourceId,
2877
- /* @__PURE__ */ jsx("br", {}),
2878
- "Resource Type: ",
2879
- resourceType
2880
- ] }),
2881
- /* @__PURE__ */ jsx(Button, { variant: "light", size: "xs", leftSection: /* @__PURE__ */ jsx(IconRefresh, { size: 14 }), onClick: handleRefresh, mt: "xs", children: "Refresh Page" })
2882
- ] }) }) });
2883
- }
2884
- function isWorkflowDefinition(structure) {
2885
- return structure.config.type === "workflow";
2886
- }
2887
- function isAgentDefinition(structure) {
2888
- return structure.config.type === "agent";
2889
- }
2890
- function ExecutionPanel({
2891
- resourceId,
2892
- resourceType,
2893
- resourceName,
2894
- resourceDefinition,
2895
- sseManager,
2896
- apiUrl,
2897
- onConnectionStatus
2898
- }) {
2899
- const diProps = { resourceId, resourceName, sseManager, apiUrl, onConnectionStatus };
2900
- switch (resourceType) {
2901
- case "workflow":
2902
- return isWorkflowDefinition(resourceDefinition) ? /* @__PURE__ */ jsx(WorkflowExecutionPanel, { ...diProps, resourceDefinition }) : /* @__PURE__ */ jsx(ResourceDefinitionError, { resourceId, resourceType, resourceName });
2903
- case "agent":
2904
- return isAgentDefinition(resourceDefinition) ? /* @__PURE__ */ jsx(AgentExecutionPanel, { ...diProps, resourceDefinition }) : /* @__PURE__ */ jsx(ResourceDefinitionError, { resourceId, resourceType, resourceName });
2905
- default:
2906
- return isWorkflowDefinition(resourceDefinition) ? /* @__PURE__ */ jsx(WorkflowExecutionPanel, { ...diProps, resourceDefinition }) : /* @__PURE__ */ jsx(ResourceDefinitionError, { resourceId, resourceType, resourceName });
2907
- }
2908
- }
2909
- function SessionListItem({ session, onClick, isSelected = false, onDeleted }) {
2910
- const deleteSession = useDeleteSession();
2911
- const [isDeleting, setIsDeleting] = useState(false);
2912
- const [showConfirmation, setShowConfirmation] = useState(false);
2913
- const handleClick = () => {
2914
- onClick(session.sessionId);
2915
- };
2916
- const handleDeleteClick = (e) => {
2917
- e.stopPropagation();
2918
- setShowConfirmation(true);
2919
- };
2920
- const handleConfirmDelete = async () => {
2921
- if (isDeleting) return;
2922
- setIsDeleting(true);
2923
- try {
2924
- await deleteSession.mutateAsync(session.sessionId);
2925
- setShowConfirmation(false);
2926
- onDeleted?.(session.sessionId);
2927
- } catch (error) {
2928
- console.error("Failed to delete session:", error);
2929
- } finally {
2930
- setIsDeleting(false);
2931
- }
2932
- };
2933
- const formatLastActivity = (date) => {
2934
- try {
2935
- return formatRelativeTime(date);
2936
- } catch {
2937
- return "unknown";
2938
- }
2939
- };
2940
- const titleColor = isSelected ? "var(--color-primary)" : "var(--color-text)";
2941
- const descriptionColor = isSelected ? "var(--color-text)" : "var(--color-text-subtle)";
2942
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2943
- /* @__PURE__ */ jsx(
2944
- Card,
2945
- {
2946
- p: "xs",
2947
- withBorder: isSelected,
2948
- style: {
2949
- cursor: "pointer",
2950
- backgroundColor: isSelected ? "color-mix(in srgb, var(--color-primary) 10%, transparent)" : "transparent",
2951
- border: "none",
2952
- boxShadow: "none",
2953
- transition: "all var(--duration-fast) var(--easing)",
2954
- opacity: isDeleting ? 0.5 : 1
2955
- },
2956
- onClick: handleClick,
2957
- children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2958
- /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "space-between", children: [
2959
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
2960
- /* @__PURE__ */ jsx(IconMessage, { color: titleColor, size: 14 }),
2961
- /* @__PURE__ */ jsxs(Text, { size: "xs", fw: 500, c: titleColor, children: [
2962
- session.turnCount,
2963
- " turns"
2964
- ] })
2965
- ] }),
2966
- /* @__PURE__ */ jsx(
2967
- ActionIcon,
2968
- {
2969
- size: "sm",
2970
- variant: "subtle",
2971
- color: "red",
2972
- onClick: handleDeleteClick,
2973
- loading: isDeleting,
2974
- disabled: isDeleting,
2975
- children: /* @__PURE__ */ jsx(IconTrash, { size: 16 })
2976
- }
2977
- )
2978
- ] }),
2979
- /* @__PURE__ */ jsx(Text, { size: "xs", c: descriptionColor, children: formatLastActivity(session.updatedAt) })
2980
- ] })
2981
- }
2982
- ),
2983
- /* @__PURE__ */ jsx(
2984
- ConfirmationModal,
2985
- {
2986
- opened: showConfirmation,
2987
- onClose: () => setShowConfirmation(false),
2988
- icon: /* @__PURE__ */ jsx(IconAlertTriangle, {}),
2989
- title: "Delete Session",
2990
- text: "Are you sure you want to delete this session? This action cannot be undone.",
2991
- buttonText: "Delete",
2992
- buttonColor: "red",
2993
- confirmationHandler: handleConfirmDelete,
2994
- loading: isDeleting
2995
- }
2996
- )
2997
- ] });
2998
- }
2999
- function SessionsPage({
3000
- isReady,
3001
- agentParam,
3002
- buildSessionDetailUrl,
3003
- buildSessionListUrl,
3004
- onNavigate
3005
- }) {
3006
- const { data: resourcesData, isLoading: isResourcesLoading } = useResources();
3007
- const createSession = useCreateSession();
3008
- const [statusFilter, setStatusFilter] = useState("all");
3009
- const allAgents = (resourcesData?.agents || []).filter((agent) => agent.sessionCapable === true);
3010
- const filteredAgents = statusFilter === "all" ? allAgents : allAgents.filter((agent) => agent.status === statusFilter);
3011
- const selectedAgent = agentParam ? allAgents.find((a) => a.resourceId === agentParam) : void 0;
3012
- const { data: sessionsData } = useSessions({
3013
- resourceId: agentParam
3014
- });
3015
- const agentSessions = Array.isArray(sessionsData) ? sessionsData : [];
3016
- const handleCreateSession = async () => {
3017
- if (!selectedAgent) return;
3018
- try {
3019
- const result = await createSession.mutateAsync(selectedAgent.resourceId);
3020
- onNavigate(buildSessionDetailUrl(result.sessionId));
3021
- } catch (error) {
3022
- console.error("Failed to create session:", error);
3023
- }
3024
- };
3025
- const hasResourcesData = allAgents.length > 0;
3026
- if (!isReady || isResourcesLoading && !hasResourcesData) return /* @__PURE__ */ jsx(SubshellLoader, {});
3027
- return /* @__PURE__ */ jsxs(Stack, { style: { flex: 1 }, children: [
3028
- /* @__PURE__ */ jsx(
3029
- PageTitleCaption,
3030
- {
3031
- title: "Sessions",
3032
- caption: "Create and manage multi-turn agent conversations",
3033
- rightSection: !selectedAgent ? /* @__PURE__ */ jsx(ResourceFilter, { value: statusFilter, onChange: setStatusFilter }) : void 0
3034
- }
3035
- ),
3036
- selectedAgent ? /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { children: [
3037
- /* @__PURE__ */ jsx(
3038
- CardHeader,
3039
- {
3040
- icon: /* @__PURE__ */ jsx(IconRobot, { size: 18 }),
3041
- title: selectedAgent.name,
3042
- subtitle: selectedAgent.description || "Simplest possible agent using GPT-5-mini",
3043
- rightSection: /* @__PURE__ */ jsx(
3044
- Button,
3045
- {
3046
- leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }),
3047
- onClick: handleCreateSession,
3048
- loading: createSession.isPending,
3049
- children: "New Session"
3050
- }
3051
- )
3052
- }
3053
- ),
3054
- agentSessions.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
3055
- /* @__PURE__ */ jsx(Divider, {}),
3056
- /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
3057
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, style: { fontFamily: "var(--mantine-font-family-headings)" }, children: "Existing Sessions" }),
3058
- agentSessions.map((session) => /* @__PURE__ */ jsx(
3059
- SessionListItem,
3060
- {
3061
- session,
3062
- onClick: (sessionId) => onNavigate(buildSessionDetailUrl(sessionId))
3063
- },
3064
- session.sessionId
3065
- ))
3066
- ] })
3067
- ] })
3068
- ] }) }) : /* @__PURE__ */ jsx(Stack, { children: filteredAgents.length > 0 ? /* @__PURE__ */ jsx(SimpleGrid, { cols: { base: 1, sm: 2, lg: 3 }, spacing: "sm", children: filteredAgents.map((agent) => /* @__PURE__ */ jsx(
3069
- ResourceCard,
3070
- {
3071
- resource: { ...agent, type: "agent" },
3072
- onClick: () => {
3073
- onNavigate(buildSessionListUrl(agent.resourceId));
3074
- }
3075
- },
3076
- agent.resourceId
3077
- )) }) : /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { align: "center", py: "xl", children: [
3078
- /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "No agents available" }),
3079
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Register agents to start conversation sessions" })
3080
- ] }) }) })
3081
- ] });
3082
- }
3083
- function SessionHeader({
3084
- session: _session,
3085
- connectionState,
3086
- onToggleSidebar,
3087
- isSidebarOpen,
3088
- tokenUsage
3089
- }) {
3090
- const mockTokenUsage = tokenUsage || { used: 45e3, total: 128e3 };
3091
- return /* @__PURE__ */ jsx(
3092
- ChatHeader,
3093
- {
3094
- title: "Session Chat",
3095
- status: {
3096
- label: connectionState.isConnected ? "Connected" : "Disconnected",
3097
- color: connectionState.isConnected ? "green" : "gray"
3098
- },
3099
- contextUsage: mockTokenUsage,
3100
- sidebarIcon: /* @__PURE__ */ jsx(IconLayoutSidebarRightExpand, { size: 20 }),
3101
- onToggleSidebar,
3102
- isSidebarOpen,
3103
- sidebarTooltip: isSidebarOpen ? "Close details" : "Show details"
3104
- }
3105
- );
3106
- }
3107
- function SessionChatInterface({
3108
- sessionId,
3109
- onConnectionStateChange,
3110
- renderConversationView
3111
- }) {
3112
- return /* @__PURE__ */ jsx(Fragment, { children: renderConversationView({
3113
- sessionId,
3114
- onConnectionStateChange,
3115
- emptyStateText: "No messages yet",
3116
- emptyStateSubtext: "Send a message to start the conversation",
3117
- placeholder: "Message the agent..."
3118
- }) });
3119
- }
3120
- function SessionDetailsSidebar({
3121
- session,
3122
- isOpen,
3123
- onClose,
3124
- organizationName,
3125
- onDeleted
3126
- }) {
3127
- const deleteSession = useDeleteSession();
3128
- const [isDeleting, setIsDeleting] = useState(false);
3129
- const [showConfirmation, setShowConfirmation] = useState(false);
3130
- const [copiedResource, setCopiedResource] = useState(false);
3131
- const [copiedSessionId, setCopiedSessionId] = useState(false);
3132
- const { data: executionsData } = useSessionExecutions(session.sessionId);
3133
- const [instructions, setInstructions] = useState(session.metadata?.instructions || "");
3134
- const [isSavingInstructions, setIsSavingInstructions] = useState(false);
3135
- const { data: resourcesData } = useResources();
3136
- const agent = resourcesData?.agents.find((a) => a.resourceId === session.resourceId);
3137
- const { data: agentDefinition } = useResourceDefinition(session.resourceId);
3138
- const agentInfo = {
3139
- name: agent?.name || session.resourceId,
3140
- description: agent?.description || "No description available",
3141
- resourceId: session.resourceId
3142
- };
3143
- const metrics = {
3144
- totalDuration: 0,
3145
- avgTurnTime: 0,
3146
- successRate: 0,
3147
- completedTurns: 0,
3148
- failedTurns: 0
3149
- };
3150
- if (executionsData?.executions) {
3151
- const executions = executionsData.executions;
3152
- metrics.totalDuration = executions.reduce((sum, ex) => sum + (ex.duration || 0), 0);
3153
- metrics.avgTurnTime = executions.length > 0 ? metrics.totalDuration / executions.length : 0;
3154
- metrics.completedTurns = executions.filter((ex) => ex.status === "completed" || ex.status === "warning").length;
3155
- metrics.failedTurns = executions.filter((ex) => ex.status === "failed").length;
3156
- metrics.successRate = executions.length > 0 ? metrics.completedTurns / executions.length * 100 : 0;
3157
- }
3158
- const handleConfirmDelete = async () => {
3159
- if (isDeleting) return;
3160
- setIsDeleting(true);
3161
- try {
3162
- await deleteSession.mutateAsync(session.sessionId);
3163
- setShowConfirmation(false);
3164
- onClose();
3165
- onDeleted?.();
3166
- } catch (error) {
3167
- console.error("Failed to delete session:", error);
3168
- } finally {
3169
- setIsDeleting(false);
3170
- }
3171
- };
3172
- const handleArchive = () => {
3173
- console.log("Archive session:", session.sessionId);
3174
- };
3175
- const handleExport = () => {
3176
- console.log("Export session:", session.sessionId);
3177
- };
3178
- const handleSaveInstructions = async () => {
3179
- setIsSavingInstructions(true);
3180
- try {
3181
- console.log("Saving instructions:", instructions);
3182
- await new Promise((resolve) => setTimeout(resolve, 500));
3183
- } finally {
3184
- setIsSavingInstructions(false);
3185
- }
3186
- };
3187
- const handleCopyResource = async () => {
3188
- const resourcePath = `${organizationName}/${session.resourceId}`;
3189
- await navigator.clipboard.writeText(resourcePath);
3190
- setCopiedResource(true);
3191
- setTimeout(() => setCopiedResource(false), 2e3);
3192
- };
3193
- const handleCopySessionId = async () => {
3194
- await navigator.clipboard.writeText(session.sessionId);
3195
- setCopiedSessionId(true);
3196
- setTimeout(() => setCopiedSessionId(false), 2e3);
3197
- };
3198
- return /* @__PURE__ */ jsxs(Fragment, { children: [
3199
- /* @__PURE__ */ jsxs(ChatSidebar, { isOpen, title: "Session Details", children: [
3200
- /* @__PURE__ */ jsx("div", { style: { flex: 1, overflow: "auto" }, children: /* @__PURE__ */ jsxs(Stack, { p: "sm", children: [
3201
- /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
3202
- /* @__PURE__ */ jsxs("div", { children: [
3203
- /* @__PURE__ */ jsxs(Group, { gap: 4, mb: 4, justify: "space-between", children: [
3204
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", children: "Resource (CLI)" }),
3205
- /* @__PURE__ */ jsx(Tooltip, { label: copiedResource ? "Copied!" : "Copy resource path", position: "right", children: /* @__PURE__ */ jsx(
3206
- ActionIcon,
3207
- {
3208
- variant: "subtle",
3209
- color: copiedResource ? "green" : "gray",
3210
- onClick: handleCopyResource,
3211
- size: "xs",
3212
- children: copiedResource ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
3213
- }
3214
- ) })
3215
- ] }),
3216
- /* @__PURE__ */ jsxs(Text, { size: "sm", ff: "monospace", style: { wordBreak: "break-all" }, children: [
3217
- organizationName,
3218
- "/",
3219
- session.resourceId
3220
- ] })
3221
- ] }),
3222
- /* @__PURE__ */ jsxs("div", { children: [
3223
- /* @__PURE__ */ jsxs(Group, { gap: 4, mb: 4, justify: "space-between", children: [
3224
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", children: "Session ID" }),
3225
- /* @__PURE__ */ jsx(Tooltip, { label: copiedSessionId ? "Copied!" : "Copy session ID", position: "right", children: /* @__PURE__ */ jsx(
3226
- ActionIcon,
3227
- {
3228
- variant: "subtle",
3229
- color: copiedSessionId ? "green" : "gray",
3230
- onClick: handleCopySessionId,
3231
- size: "xs",
3232
- children: copiedSessionId ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
3233
- }
3234
- ) })
3235
- ] }),
3236
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", style: { wordBreak: "break-all" }, children: session.sessionId })
3237
- ] })
3238
- ] }),
3239
- /* @__PURE__ */ jsx(Divider, {}),
3240
- /* @__PURE__ */ jsxs("div", { children: [
3241
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", mb: 8, children: "Agent" }),
3242
- /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
3243
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, children: agentInfo.name }),
3244
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", lineClamp: 3, children: agentInfo.description }),
3245
- agentDefinition && "modelConfig" in agentDefinition && /* @__PURE__ */ jsxs(Fragment, { children: [
3246
- /* @__PURE__ */ jsx(Divider, { my: "xs" }),
3247
- /* @__PURE__ */ jsxs("div", { children: [
3248
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", fw: 600, mb: 4, children: "Model Configuration" }),
3249
- /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
3250
- agentDefinition.modelConfig.model && /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3251
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Model" }),
3252
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", children: agentDefinition.modelConfig.model })
3253
- ] }),
3254
- agentDefinition.modelConfig.temperature !== void 0 && /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3255
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Temperature" }),
3256
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", children: agentDefinition.modelConfig.temperature })
3257
- ] }),
3258
- agentDefinition.modelConfig.maxOutputTokens && /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3259
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Max Tokens" }),
3260
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", children: agentDefinition.modelConfig.maxOutputTokens })
3261
- ] })
3262
- ] })
3263
- ] })
3264
- ] }),
3265
- agentDefinition && "tools" in agentDefinition && agentDefinition.tools.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
3266
- /* @__PURE__ */ jsx(Divider, { my: "sm" }),
3267
- /* @__PURE__ */ jsxs("div", { children: [
3268
- /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", fw: 600, mb: 4, children: [
3269
- "Tools (",
3270
- agentDefinition.tools.length,
3271
- ")"
3272
- ] }),
3273
- /* @__PURE__ */ jsx(Stack, { gap: 4, children: agentDefinition.tools.map(
3274
- (tool, index) => {
3275
- const toolName = typeof tool === "string" ? tool : tool.name;
3276
- const toolKey = typeof tool === "string" ? tool : `${tool.name}-${index}`;
3277
- return /* @__PURE__ */ jsxs(Text, { size: "sm", ff: "monospace", c: "dimmed", children: [
3278
- "\u2022 ",
3279
- toolName
3280
- ] }, toolKey);
3281
- }
3282
- ) })
3283
- ] })
3284
- ] })
3285
- ] })
3286
- ] }),
3287
- /* @__PURE__ */ jsx(Divider, {}),
3288
- /* @__PURE__ */ jsxs("div", { children: [
3289
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: 8, children: [
3290
- /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
3291
- /* @__PURE__ */ jsx(IconNote, { size: 14, color: "var(--color-text-subtle)" }),
3292
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", children: "Session Instructions" })
3293
- ] }),
3294
- isSavingInstructions && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", style: { fontStyle: "italic" }, children: "Saving..." })
3295
- ] }),
3296
- /* @__PURE__ */ jsx(
3297
- Textarea,
3298
- {
3299
- placeholder: "Add custom instructions to append to the system prompt...",
3300
- value: instructions,
3301
- onChange: (e) => setInstructions(e.target.value),
3302
- onBlur: handleSaveInstructions,
3303
- autosize: true,
3304
- minRows: 4,
3305
- maxRows: 8,
3306
- size: "sm",
3307
- styles: {
3308
- input: {
3309
- fontSize: "var(--mantine-font-size-sm)"
3310
- }
3311
- }
3312
- }
3313
- )
3314
- ] }),
3315
- /* @__PURE__ */ jsxs("div", { children: [
3316
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", mb: 8, children: "Timestamps" }),
3317
- /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
3318
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3319
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Created" }),
3320
- /* @__PURE__ */ jsx(Text, { size: "sm", children: new Date(session.createdAt).toLocaleString() })
3321
- ] }),
3322
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3323
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Last Updated" }),
3324
- /* @__PURE__ */ jsx(Text, { size: "sm", children: new Date(session.updatedAt).toLocaleString() })
3325
- ] }),
3326
- session.endedAt && /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3327
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Ended" }),
3328
- /* @__PURE__ */ jsx(Text, { size: "sm", children: new Date(session.endedAt).toLocaleString() })
3329
- ] })
3330
- ] })
3331
- ] }),
3332
- (() => {
3333
- const modelConfig = session.metadata?.modelConfig;
3334
- if (!modelConfig) return null;
3335
- return /* @__PURE__ */ jsxs("div", { children: [
3336
- /* @__PURE__ */ jsx(Divider, {}),
3337
- /* @__PURE__ */ jsxs("div", { children: [
3338
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", mb: 4, children: "Model Configuration" }),
3339
- /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
3340
- modelConfig.model && /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3341
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Model" }),
3342
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", children: modelConfig.model })
3343
- ] }),
3344
- modelConfig.temperature !== void 0 && /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3345
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Temperature" }),
3346
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", children: modelConfig.temperature })
3347
- ] }),
3348
- modelConfig.maxOutputTokens && /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3349
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Max Tokens" }),
3350
- /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", children: modelConfig.maxOutputTokens })
3351
- ] })
3352
- ] })
3353
- ] })
3354
- ] });
3355
- })(),
3356
- /* @__PURE__ */ jsx(Divider, {}),
3357
- /* @__PURE__ */ jsxs("div", { children: [
3358
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", mb: 8, children: "Actions" }),
3359
- /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
3360
- /* @__PURE__ */ jsxs(
3361
- Button,
3362
- {
3363
- size: "sm",
3364
- variant: "light",
3365
- leftSection: /* @__PURE__ */ jsx(IconArchive, { size: 16 }),
3366
- onClick: handleArchive,
3367
- fullWidth: true,
3368
- children: [
3369
- session.isEnded ? "Reopen" : "End",
3370
- " Session"
3371
- ]
3372
- }
3373
- ),
3374
- /* @__PURE__ */ jsx(
3375
- Button,
3376
- {
3377
- size: "sm",
3378
- variant: "light",
3379
- leftSection: /* @__PURE__ */ jsx(IconDownload, { size: 16 }),
3380
- onClick: handleExport,
3381
- fullWidth: true,
3382
- children: "Export Session"
3383
- }
3384
- )
3385
- ] })
3386
- ] })
3387
- ] }) }),
3388
- /* @__PURE__ */ jsx("div", { style: { borderTop: "1px solid var(--color-border)", padding: "var(--mantine-spacing-md)" }, children: /* @__PURE__ */ jsx(
3389
- Button,
3390
- {
3391
- fullWidth: true,
3392
- color: "red",
3393
- variant: "light",
3394
- leftSection: /* @__PURE__ */ jsx(IconTrash, { size: 16 }),
3395
- onClick: () => setShowConfirmation(true),
3396
- loading: isDeleting,
3397
- disabled: isDeleting,
3398
- children: "Delete Session"
3399
- }
3400
- ) })
3401
- ] }),
3402
- /* @__PURE__ */ jsx(
3403
- ConfirmationModal,
3404
- {
3405
- opened: showConfirmation,
3406
- onClose: () => setShowConfirmation(false),
3407
- icon: /* @__PURE__ */ jsx(IconAlertTriangle, {}),
3408
- title: "Delete Session",
3409
- text: "Are you sure you want to delete this session? All messages and execution history will be permanently removed. This action cannot be undone.",
3410
- buttonText: "Delete Session",
3411
- buttonColor: "red",
3412
- confirmationHandler: handleConfirmDelete,
3413
- loading: isDeleting
3414
- }
3415
- )
3416
- ] });
3417
- }
3418
- function SessionChatArea({
3419
- sessionId,
3420
- session,
3421
- organizationName,
3422
- onDeleted,
3423
- renderConversationView
3424
- }) {
3425
- const [isSidebarOpen, setIsSidebarOpen] = useState(false);
3426
- const [connectionState, setConnectionState] = useState({
3427
- isConnected: false,
3428
- isProcessing: false,
3429
- error: null
3430
- });
3431
- return /* @__PURE__ */ jsxs(
3432
- "div",
3433
- {
3434
- style: {
3435
- position: "relative",
3436
- display: "flex",
3437
- flexDirection: "column",
3438
- gap: "16px",
3439
- height: `calc(100vh - ${topbarHeight}px)`,
3440
- flexShrink: 0,
3441
- overflowX: "hidden"
3442
- },
3443
- children: [
3444
- /* @__PURE__ */ jsxs(
3445
- "div",
3446
- {
3447
- style: {
3448
- height: "100%",
3449
- display: "flex",
3450
- flexDirection: "column",
3451
- gap: "16px",
3452
- transition: "margin-right var(--duration-normal) var(--easing)",
3453
- marginRight: isSidebarOpen ? "320px" : "0",
3454
- overflow: "hidden",
3455
- borderRadius: "var(--mantine-radius-md)",
3456
- position: "relative",
3457
- padding: 8
3458
- },
3459
- children: [
3460
- /* @__PURE__ */ jsx(
3461
- SessionHeader,
3462
- {
3463
- session,
3464
- connectionState,
3465
- onToggleSidebar: () => setIsSidebarOpen(!isSidebarOpen),
3466
- isSidebarOpen
3467
- }
3468
- ),
3469
- /* @__PURE__ */ jsx("div", { style: { flex: 1, minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ jsx(
3470
- SessionChatInterface,
3471
- {
3472
- sessionId,
3473
- onConnectionStateChange: setConnectionState,
3474
- renderConversationView
3475
- }
3476
- ) })
3477
- ]
3478
- }
3479
- ),
3480
- /* @__PURE__ */ jsx(
3481
- SessionDetailsSidebar,
3482
- {
3483
- session,
3484
- isOpen: isSidebarOpen,
3485
- onClose: () => setIsSidebarOpen(false),
3486
- organizationName,
3487
- onDeleted
3488
- }
3489
- )
3490
- ]
3491
- }
3492
- );
3493
- }
3494
- function SessionExecutionLogs({ sessionId, session, buildExecutionUrl }) {
3495
- const { data: executions, isLoading } = useSessionExecutions(sessionId);
3496
- if (isLoading) {
3497
- return /* @__PURE__ */ jsxs(Stack, { children: [
3498
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
3499
- /* @__PURE__ */ jsx(IconTimeline, { size: 20 }),
3500
- /* @__PURE__ */ jsx(Text, { fw: 600, size: "sm", style: { fontFamily: "var(--mantine-font-family-headings)" }, children: "Execution Logs" })
3501
- ] }),
3502
- /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) })
3503
- ] });
3504
- }
3505
- if (!executions || executions.executions.length === 0) {
3506
- return /* @__PURE__ */ jsxs(Stack, { children: [
3507
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3508
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
3509
- /* @__PURE__ */ jsx(IconTimeline, { size: 20 }),
3510
- /* @__PURE__ */ jsx(Text, { fw: 600, size: "sm", style: { fontFamily: "var(--mantine-font-family-headings)" }, children: "Execution Logs" })
3511
- ] }),
3512
- /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", children: "0 turns" })
3513
- ] }),
3514
- /* @__PURE__ */ jsx(EmptyState, { icon: IconTimeline, title: "No execution logs yet" })
3515
- ] });
3516
- }
3517
- return /* @__PURE__ */ jsxs(Stack, { children: [
3518
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
3519
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
3520
- /* @__PURE__ */ jsx(IconTimeline, { size: 20 }),
3521
- /* @__PURE__ */ jsx(Text, { fw: 600, size: "sm", style: { fontFamily: "var(--mantine-font-family-headings)" }, children: "Execution Logs" })
3522
- ] }),
3523
- /* @__PURE__ */ jsxs(Badge, { size: "sm", variant: "light", children: [
3524
- executions.executions.length,
3525
- " ",
3526
- executions.executions.length === 1 ? "turn" : "turns"
3527
- ] })
3528
- ] }),
3529
- /* @__PURE__ */ jsx(Stack, { children: executions.executions.map((execution) => /* @__PURE__ */ jsx(
3530
- ExecutionItem,
3531
- {
3532
- execution,
3533
- session,
3534
- buildExecutionUrl
3535
- },
3536
- execution.executionId
3537
- )) })
3538
- ] });
3539
- }
3540
- function ExecutionItem({ execution, session: _session, buildExecutionUrl }) {
3541
- const statusConfig = getExecutionStatusConfig(execution.status);
3542
- const handleClick = () => {
3543
- const url = buildExecutionUrl(execution.executionId);
3544
- window.open(url, "_blank", "noopener,noreferrer");
3545
- };
3546
- return /* @__PURE__ */ jsx(
3547
- Paper,
3548
- {
3549
- p: "sm",
3550
- style: {
3551
- cursor: "pointer",
3552
- transition: "all var(--duration-fast) var(--easing)",
3553
- ":hover": {
3554
- backgroundColor: "var(--mantine-color-gray-0)"
3555
- }
3556
- },
3557
- onClick: handleClick,
3558
- children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
3559
- /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
3560
- /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
3561
- "Turn ",
3562
- execution.turnNumber
3563
- ] }),
3564
- /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: statusConfig.color, children: statusConfig.label }),
3565
- execution.duration && /* @__PURE__ */ jsxs(Badge, { size: "xs", variant: "light", children: [
3566
- (execution.duration / 1e3).toFixed(2),
3567
- "s"
3568
- ] })
3569
- ] }),
3570
- /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
3571
- /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatRelativeTime(execution.startedAt) }),
3572
- /* @__PURE__ */ jsx(IconExternalLink, { size: 16 })
3573
- ] })
3574
- ] })
3575
- }
3576
- );
3577
- }
3578
- function AgentChatOuterSubshellContainer({ children }) {
3579
- return /* @__PURE__ */ jsx(
3580
- "div",
3581
- {
3582
- style: {
3583
- overflow: "auto",
3584
- minWidth: 0,
3585
- minHeight: `calc(100vh - ${topbarHeight}px)`,
3586
- paddingTop: `${topbarHeight}px`
3587
- },
3588
- children
3589
- }
3590
- );
3591
- }
3592
- function SessionChatPage({
3593
- sessionId,
3594
- isReady,
3595
- renderConversationView,
3596
- buildExecutionUrl,
3597
- buildSessionListUrl: _buildSessionListUrl,
3598
- organizationName
3599
- }) {
3600
- const { data: session, isLoading: isSessionLoading } = useSession(sessionId);
3601
- if (!isReady || isSessionLoading) {
3602
- return /* @__PURE__ */ jsx(SubshellLoader, {});
3603
- }
3604
- if (!session) {
3605
- return /* @__PURE__ */ jsxs(Stack, { style: { flex: 1 }, children: [
3606
- /* @__PURE__ */ jsx(PageTitleCaption, { title: "Session Not Found", caption: `Session ${sessionId} not found` }),
3607
- /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "This session may have been deleted or does not exist." }) })
3608
- ] });
3609
- }
3610
- return /* @__PURE__ */ jsx(
3611
- SessionChatPageContent,
3612
- {
3613
- sessionId,
3614
- session,
3615
- renderConversationView,
3616
- buildExecutionUrl,
3617
- organizationName
3618
- }
3619
- );
3620
- }
3621
- function SessionChatPageContent({
3622
- sessionId,
3623
- session,
3624
- renderConversationView,
3625
- buildExecutionUrl,
3626
- organizationName
3627
- }) {
3628
- const { data: resourceDefinition } = useResourceDefinition(session.resourceId);
3629
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsx(AgentChatOuterSubshellContainer, { children: /* @__PURE__ */ jsxs(PageContainer, { children: [
3630
- /* @__PURE__ */ jsx(
3631
- SessionChatArea,
3632
- {
3633
- sessionId,
3634
- session,
3635
- organizationName,
3636
- renderConversationView
3637
- }
3638
- ),
3639
- /* @__PURE__ */ jsx("div", { style: { padding: "8px", display: "flex", flexDirection: "column", gap: "8px" }, children: /* @__PURE__ */ jsxs(Stack, { style: { flex: 1, height: "100%" }, children: [
3640
- resourceDefinition && /* @__PURE__ */ jsx(ResourceDefinitionSection, { resourceDefinition }),
3641
- /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { children: [
3642
- /* @__PURE__ */ jsx(SessionMemory, { memory: session.memorySnapshot }),
3643
- /* @__PURE__ */ jsx(SessionExecutionLogs, { sessionId, session, buildExecutionUrl })
3644
- ] }) })
3645
- ] }) })
3646
- ] }) }) });
3647
- }
3648
- function AgentSessionGroup({
3649
- group,
3650
- onAgentClick,
3651
- onSessionClick,
3652
- selectedSessionId,
3653
- onSessionDeleted
3654
- }) {
3655
- const [isExpanded, setIsExpanded] = useState(group.isExpanded);
3656
- const toggleExpanded = () => {
3657
- setIsExpanded(!isExpanded);
3658
- };
3659
- const handleAgentClick = (e) => {
3660
- onAgentClick(group.resourceId);
3661
- e.stopPropagation();
3662
- };
3663
- return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
3664
- /* @__PURE__ */ jsxs(Group, { gap: "xs", style: { cursor: "pointer", userSelect: "none" }, children: [
3665
- /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", onClick: toggleExpanded, children: isExpanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: 16 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 16 }) }),
3666
- /* @__PURE__ */ jsxs(
3667
- Group,
3668
- {
3669
- gap: "xs",
3670
- onClick: handleAgentClick,
3671
- style: {
3672
- flex: 1,
3673
- padding: "4px 8px",
3674
- borderRadius: "var(--mantine-radius-default)",
3675
- transition: "background-color var(--duration-fast)"
3676
- },
3677
- onMouseEnter: (e) => {
3678
- e.currentTarget.style.backgroundColor = "var(--mantine-color-default-hover)";
3679
- },
3680
- onMouseLeave: (e) => {
3681
- e.currentTarget.style.backgroundColor = "transparent";
3682
- },
3683
- children: [
3684
- /* @__PURE__ */ jsx(IconBrain, { size: 16, color: "var(--color-primary)" }),
3685
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, style: { flex: 1, fontFamily: "var(--elevasis-font-family-subtitle)" }, children: group.agentName }),
3686
- group.sessions.length > 0 && /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", circle: true, children: group.sessions.length })
3687
- ]
3688
- }
3689
- )
3690
- ] }),
3691
- /* @__PURE__ */ jsx(Collapse, { in: isExpanded, children: /* @__PURE__ */ jsx(Stack, { gap: "xs", pl: "xs", children: group.sessions.length > 0 ? group.sessions.map((session) => /* @__PURE__ */ jsx(
3692
- SessionListItem,
3693
- {
3694
- session,
3695
- onClick: onSessionClick,
3696
- isSelected: selectedSessionId === session.sessionId,
3697
- onDeleted: onSessionDeleted
3698
- },
3699
- session.sessionId
3700
- )) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fs: "italic", py: "sm", children: "No sessions" }) }) })
3701
- ] });
3702
- }
3703
- function SessionsSidebar({
3704
- isReady,
3705
- onAgentClick,
3706
- buildSessionDetailUrl,
3707
- sessionId,
3708
- agentParam
3709
- }) {
3710
- const theme = useMantineTheme();
3711
- const { organizationReady } = useInitialization();
3712
- const { data: resourcesData, isLoading: isResourcesLoading } = useResources();
3713
- const agents = resourcesData?.agents || [];
3714
- const isSessionView = !!sessionId;
3715
- const { data: currentSession, isLoading: isCurrentSessionLoading } = useSession(sessionId || "");
3716
- const currentAgentResourceId = currentSession?.resourceId;
3717
- const { data: sessionsData, isLoading: isSessionsLoading } = useSessions(
3718
- currentAgentResourceId ? { resourceId: currentAgentResourceId } : void 0,
3719
- { enabled: !!currentAgentResourceId }
3720
- );
3721
- const agentSessions = isSessionView && currentAgentResourceId ? Array.isArray(sessionsData) ? sessionsData : [] : [];
3722
- const hasResourcesData = agents.length > 0;
3723
- const hasSessionsData = agentSessions.length > 0;
3724
- const isInitialLoading = !isReady || !organizationReady || isResourcesLoading && !hasResourcesData || isSessionView && (isCurrentSessionLoading || isSessionsLoading) && !hasSessionsData;
3725
- return /* @__PURE__ */ jsxs(Box, { style: { flex: 1, minHeight: 0, padding: theme.spacing.sm }, children: [
3726
- /* @__PURE__ */ jsx(Text, { size: "xs", fw: 600, c: "dimmed", tt: "uppercase", mb: "md", children: isSessionView ? "Sessions" : "Agents" }),
3727
- /* @__PURE__ */ jsx(ScrollArea, { style: { height: "100%" }, scrollbarSize: 8, children: isInitialLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, { size: "sm" }) }) : isSessionView ? agentSessions.length > 0 ? /* @__PURE__ */ jsx(Stack, { gap: "xs", children: agentSessions.map((session) => /* @__PURE__ */ jsx(
3728
- SessionListItem,
3729
- {
3730
- session,
3731
- onClick: (id) => window.location.assign(buildSessionDetailUrl(id)),
3732
- isSelected: sessionId === session.sessionId
3733
- },
3734
- session.sessionId
3735
- )) }) : /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", fs: "italic", children: "No sessions found" }) }) : agents.length > 0 ? /* @__PURE__ */ jsx(Stack, { gap: "xs", children: agents.map((agent) => /* @__PURE__ */ jsx(
3736
- AgentListItem,
3737
- {
3738
- agent,
3739
- isSelected: agentParam === agent.resourceId,
3740
- onAgentClick
3741
- },
3742
- agent.resourceId
3743
- )) }) : /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", fs: "italic", children: "No agents found" }) }) })
3744
- ] });
3745
- }
3746
- function AgentListItem({ agent, isSelected, onAgentClick }) {
3747
- const theme = useMantineTheme();
3748
- const titleColor = isSelected ? "var(--color-primary)" : "var(--color-text)";
3749
- const descriptionColor = isSelected ? "var(--color-text)" : "var(--color-text-subtle)";
3750
- return /* @__PURE__ */ jsx(
3751
- Card,
3752
- {
3753
- p: "sm",
3754
- style: {
3755
- cursor: "pointer",
3756
- backgroundColor: isSelected ? "color-mix(in srgb, var(--color-primary) 10%, transparent)" : "transparent",
3757
- boxShadow: "none",
3758
- border: "none",
3759
- transition: "all var(--duration-fast) var(--easing)"
3760
- },
3761
- onClick: () => onAgentClick(agent.resourceId),
3762
- children: /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
3763
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
3764
- /* @__PURE__ */ jsx(IconBrain, { size: 16, color: theme.colors[theme.primaryColor][6] }),
3765
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, c: titleColor, children: agent.name })
3766
- ] }),
3767
- agent.description && /* @__PURE__ */ jsx(Text, { size: "xs", c: descriptionColor, lineClamp: 2, children: agent.description })
3768
- ] })
3769
- }
3770
- );
3771
- }
3772
-
3773
- export { AgentExecutionPanel, AgentSessionGroup, CalibrationPage, CalibrationProgress, CalibrationProjectDetailPage, CalibrationProjectsPage, CalibrationRunDetailPage, CalibrationSidebar, CommandQueueDetailPage, CommandQueuePage, CommandViewPage, CommandViewSidebarContent, ExecuteWorkflowModal, ExecutionPanel, ResourceDetailPage, ResourceExecuteDialog, ResourceExecuteForm, ResourcesPage, ResourcesSidebar, SessionChatArea, SessionChatInterface, SessionChatPage, SessionDetailsSidebar, SessionExecutionLogs, SessionHeader, SessionListItem, SessionsPage, SessionsSidebar, WorkflowExecutionPanel };