@elevasis/ui 1.19.0 → 1.20.1

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 (94) hide show
  1. package/dist/api/index.js +2 -2
  2. package/dist/auth/index.js +3 -3
  3. package/dist/charts/index.css +14 -0
  4. package/dist/charts/index.js +8 -6
  5. package/dist/{chunk-7ATCF6UL.js → chunk-3DIU726S.js} +11 -4
  6. package/dist/chunk-4SY4EQSK.js +68 -0
  7. package/dist/{chunk-2Z7LYTIX.js → chunk-AQ5MQDSS.js} +30 -17
  8. package/dist/chunk-AWMZCYKH.js +639 -0
  9. package/dist/{chunk-BVNAC4SQ.js → chunk-C7AD6N23.js} +38 -48
  10. package/dist/{chunk-ZFCG5SHW.js → chunk-COTI2QPO.js} +1 -1
  11. package/dist/{chunk-WAPZN2U3.js → chunk-EMN755L5.js} +7 -41
  12. package/dist/{chunk-LBY7FVFD.js → chunk-ERVB3QJQ.js} +31 -715
  13. package/dist/chunk-GBMNCNHX.js +105 -0
  14. package/dist/{chunk-MBZDE6UT.js → chunk-IOKL7BKE.js} +9 -1
  15. package/dist/{chunk-35UWYH2A.js → chunk-JFRG2JJE.js} +8 -2
  16. package/dist/chunk-JIABC3AE.js +2622 -0
  17. package/dist/chunk-JZEXFQ6N.js +671 -0
  18. package/dist/chunk-LGKLC5MG.js +44 -0
  19. package/dist/chunk-MG3NF7QL.js +63 -0
  20. package/dist/{chunk-KBLGVZBD.js → chunk-NNKKBSJN.js} +2 -22
  21. package/dist/{chunk-JNBHUCKW.js → chunk-NVOCKXUQ.js} +1 -1
  22. package/dist/chunk-OFAXUZPZ.js +2411 -0
  23. package/dist/chunk-PDHTXPSF.js +12 -0
  24. package/dist/chunk-QJ2S46NI.js +23 -0
  25. package/dist/{chunk-NUULWBAD.js → chunk-R3R367QY.js} +1 -1
  26. package/dist/{chunk-UANJP5P7.js → chunk-R7WLWGPO.js} +5 -5
  27. package/dist/{chunk-CC3SDRIF.js → chunk-RWQIFKMJ.js} +1 -1
  28. package/dist/chunk-UMFPUM7Q.js +1281 -0
  29. package/dist/{chunk-KNJKCD73.js → chunk-VLTVZXP6.js} +4 -4
  30. package/dist/chunk-WWEMNIHW.js +37 -0
  31. package/dist/{chunk-UTWJZEOJ.js → chunk-XOTN3X3Z.js} +3 -3
  32. package/dist/components/index.css +14 -0
  33. package/dist/components/index.d.ts +41 -7
  34. package/dist/components/index.js +564 -5023
  35. package/dist/components/navigation/index.js +2 -63
  36. package/dist/features/auth/index.css +579 -0
  37. package/dist/features/auth/index.d.ts +2557 -0
  38. package/dist/features/auth/index.js +125 -0
  39. package/dist/features/dashboard/index.css +579 -0
  40. package/dist/features/dashboard/index.d.ts +244 -0
  41. package/dist/features/dashboard/index.js +650 -0
  42. package/dist/features/monitoring/index.css +579 -0
  43. package/dist/features/monitoring/index.d.ts +121 -0
  44. package/dist/features/monitoring/index.js +538 -0
  45. package/dist/features/operations/index.css +14 -0
  46. package/dist/features/operations/index.d.ts +1675 -2
  47. package/dist/features/operations/index.js +2148 -28
  48. package/dist/features/settings/index.css +579 -0
  49. package/dist/features/settings/index.d.ts +2589 -0
  50. package/dist/features/settings/index.js +1437 -0
  51. package/dist/hooks/index.css +14 -0
  52. package/dist/hooks/index.d.ts +29 -11
  53. package/dist/hooks/index.js +13 -13
  54. package/dist/hooks/published.css +14 -0
  55. package/dist/hooks/published.d.ts +29 -11
  56. package/dist/hooks/published.js +12 -12
  57. package/dist/index.css +14 -0
  58. package/dist/index.d.ts +41 -12
  59. package/dist/index.js +15 -15
  60. package/dist/initialization/index.js +2 -2
  61. package/dist/layout/index.d.ts +7 -1
  62. package/dist/layout/index.js +7 -5
  63. package/dist/organization/index.js +2 -2
  64. package/dist/provider/index.css +14 -0
  65. package/dist/provider/index.d.ts +1 -1
  66. package/dist/provider/index.js +10 -10
  67. package/dist/provider/published.d.ts +1 -1
  68. package/dist/provider/published.js +6 -6
  69. package/dist/theme/index.d.ts +1 -1
  70. package/dist/theme/index.js +3 -3
  71. package/dist/theme/presets/__tests__/getPreset.test.d.ts +2 -0
  72. package/dist/theme/presets/__tests__/getPreset.test.d.ts.map +1 -0
  73. package/dist/theme/presets/__tests__/getPreset.test.js +92 -0
  74. package/dist/theme/presets/cyber-volt.d.ts +12 -0
  75. package/dist/theme/presets/cyber-volt.d.ts.map +1 -0
  76. package/dist/theme/presets/cyber-volt.js +70 -0
  77. package/dist/theme/presets/regal.d.ts +8 -0
  78. package/dist/theme/presets/regal.d.ts.map +1 -0
  79. package/dist/theme/presets/regal.js +69 -0
  80. package/dist/theme/presets/rose-gold.d.ts +12 -0
  81. package/dist/theme/presets/rose-gold.d.ts.map +1 -0
  82. package/dist/theme/presets/rose-gold.js +76 -0
  83. package/dist/types/index.d.ts +1 -1
  84. package/dist/utils/index.d.ts +12 -1
  85. package/dist/utils/index.js +1 -1
  86. package/dist/zustand/index.d.ts +80 -0
  87. package/dist/zustand/index.js +105 -0
  88. package/package.json +55 -4
  89. package/dist/chunk-2YW3LDFT.js +0 -1542
  90. package/dist/theme/presets/cyber-void.d.ts +0 -12
  91. package/dist/theme/presets/cyber-void.d.ts.map +0 -1
  92. package/dist/theme/presets/cyber-void.js +0 -75
  93. package/dist/{chunk-DVKEEY5J.js → chunk-TUXTSEAF.js} +1 -1
  94. package/dist/{chunk-U2522LSW.js → chunk-V7XHGJQZ.js} +1 -1
@@ -1,40 +1,72 @@
1
- import { ExecutionStats } from '../../chunk-BVNAC4SQ.js';
2
- import { SubshellLoader, SubshellSidebarSection } from '../../chunk-35UWYH2A.js';
3
- import { PageTitleCaption, TabCountBadge, ResourceCard, useCyberColors, CyberDonut } from '../../chunk-LBY7FVFD.js';
4
- import '../../chunk-KBLGVZBD.js';
5
- import { useStatusFilter, useResourceSearch, useResourcesDomainFilters, filterByDomainFilters } from '../../chunk-UTWJZEOJ.js';
6
- import { usePaginationState, useResources, useRecentExecutionsByResource } from '../../chunk-2Z7LYTIX.js';
7
- import '../../chunk-LXHZYSMQ.js';
1
+ import { ResourceDefinitionSection, CommandQueueTaskRow, getIcon, ActionModal, CommandViewGraph, WorkflowExecutionLogs, AgentExecutionLogs } from '../../chunk-JIABC3AE.js';
2
+ import { SubshellLoader, SubshellSidebarSection, PageContainer } from '../../chunk-JFRG2JJE.js';
3
+ import { ResourceHealthPanel } from '../../chunk-4SY4EQSK.js';
4
+ import { ConfirmationModal, CustomModal } from '../../chunk-GBMNCNHX.js';
5
+ import { ExecutionStats, UnifiedWorkflowGraph, WorkflowExecutionTimeline, AgentExecutionVisualizer, AgentExecutionTimeline } from '../../chunk-C7AD6N23.js';
6
+ import { useCyberColors, CyberDonut } from '../../chunk-ERVB3QJQ.js';
7
+ import { PageTitleCaption, TabCountBadge, ResourceCard, ContextViewer, JsonViewer, APIErrorAlert, EmptyState } from '../../chunk-AWMZCYKH.js';
8
+ import '../../chunk-NNKKBSJN.js';
9
+ import { AppShellLoader } from '../../chunk-WWEMNIHW.js';
10
+ import '../../chunk-QJ2S46NI.js';
11
+ import { useStatusFilter, useResourceSearch, useResourcesDomainFilters, filterByDomainFilters, useCommandViewDomainFilters, showApiErrorNotification } from '../../chunk-XOTN3X3Z.js';
12
+ import { usePaginationState, useResources, useRecentExecutionsByResource, useResourceDefinition, isSessionCapable, useDeleteTask, useCommandQueueTotals, useCommandQueue, useSubmitAction, useCommandViewData, useCommandViewStore, useCommandViewStats, useResourceExecutions, useCheckpointTasks, useExecutionPanelState, useExecution } from '../../chunk-AQ5MQDSS.js';
8
13
  import '../../chunk-NJJ3NQ7B.js';
14
+ import '../../chunk-LXHZYSMQ.js';
9
15
  import '../../chunk-MHW43EOH.js';
10
16
  import '../../chunk-F6RBK7NJ.js';
11
- import '../../chunk-XA34RETF.js';
12
- import '../../chunk-ELJIFLCB.js';
17
+ import { useMergedExecution, useTimelineData, useAgentIterationData } from '../../chunk-XA34RETF.js';
18
+ import { ResourceStatusColors } from '../../chunk-ELJIFLCB.js';
13
19
  import '../../chunk-L4XXM55J.js';
14
20
  import '../../chunk-SLVC5OJ2.js';
15
21
  import '../../chunk-RNP5R5I3.js';
16
- import '../../chunk-KNJKCD73.js';
17
- import '../../chunk-NUULWBAD.js';
22
+ import '../../chunk-VLTVZXP6.js';
23
+ import '../../chunk-R3R367QY.js';
18
24
  import '../../chunk-SZHARWKU.js';
19
- import '../../chunk-2YW3LDFT.js';
20
- import '../../chunk-7ATCF6UL.js';
21
- import '../../chunk-UANJP5P7.js';
25
+ import '../../chunk-OFAXUZPZ.js';
26
+ import '../../chunk-3DIU726S.js';
27
+ import '../../chunk-R7WLWGPO.js';
28
+ import '../../chunk-NVOCKXUQ.js';
29
+ import '../../chunk-V7XHGJQZ.js';
22
30
  import '../../chunk-QJ2KCHKX.js';
23
- import '../../chunk-U2522LSW.js';
24
- import '../../chunk-JNBHUCKW.js';
25
- import { formatRelativeTime, DOMAIN_MAP } from '../../chunk-MBZDE6UT.js';
26
- import '../../chunk-CC3SDRIF.js';
31
+ import { formatRelativeTime, DOMAIN_MAP, getNodeId, PAGE_SIZE_DEFAULT, getErrorInfo, formatErrorMessage, getResourceIcon } from '../../chunk-IOKL7BKE.js';
32
+ import '../../chunk-RWQIFKMJ.js';
27
33
  import '../../chunk-ALA56RGZ.js';
28
- import { useInitialization } from '../../chunk-DVKEEY5J.js';
29
- import '../../chunk-QEPXAWE2.js';
30
- import '../../chunk-DD3CCMCZ.js';
34
+ import { useInitialization } from '../../chunk-TUXTSEAF.js';
35
+ import { useOrganization } from '../../chunk-DD3CCMCZ.js';
36
+ import { useElevasisServices } from '../../chunk-QEPXAWE2.js';
31
37
  import '../../chunk-BRJ3QZ4E.js';
32
38
  import '../../chunk-Q7DJKLEN.js';
33
- import { Stack, Card, Text, Button, Tabs, Group, Pagination, useMantineTheme, Box, Center, Loader, UnstyledButton, TextInput, Divider } from '@mantine/core';
34
- import { IconApps, IconRoute, IconBrain, IconRefresh, IconAdjustmentsHorizontal, IconSearch, IconChevronDown, IconCircleX, IconCircleCheck, IconCircleDashed } from '@tabler/icons-react';
35
- import { useState, useEffect, useMemo } from 'react';
39
+ import { Stack, Card, Text, Button, Tabs, Group, Pagination, useMantineTheme, Box, Center, Loader, UnstyledButton, TextInput, Divider, Paper, Badge, ActionIcon, Title, SimpleGrid, CopyButton, SegmentedControl, ThemeIcon, Alert, Switch, Space, Collapse, Tooltip, Menu, Modal, Textarea, Table, Progress } from '@mantine/core';
40
+ import { IconApps, IconRoute, IconBrain, IconRefresh, IconAdjustmentsHorizontal, IconSearch, IconChevronDown, IconCircleX, IconCircleCheck, IconCircleDashed, IconTrash, IconArrowLeft, IconClock, IconCheck, IconCopy, IconExternalLink, IconPlayerPlay, IconAlertCircle, IconPlus, IconAdjustments, IconSitemap, IconSettings, IconReportAnalytics, IconX, IconCoin, IconChevronRight, IconInfoCircle, IconMessage, IconFlask, IconDotsVertical } from '@tabler/icons-react';
41
+ import { useState, useEffect, useMemo, useRef, useCallback } from 'react';
36
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 { useQuery, useQueryClient, useMutation } from '@tanstack/react-query';
47
+ import { useForm } from '@mantine/form';
48
+ import { formatDistanceToNow } from 'date-fns';
37
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
+ }
38
70
  function ResourcesPage({
39
71
  initialFilter,
40
72
  onTypeChange,
@@ -201,7 +233,6 @@ function ResourcesPage({
201
233
  resource,
202
234
  onClick: onResourceClick,
203
235
  layout: "row",
204
- dormant: isDormant,
205
236
  "data-resource-id": resource.resourceId,
206
237
  lastRunLabel: resource.lastExecution ? `Last run ${formatRelativeTime(resource.lastExecution)}` : void 0,
207
238
  rightSection: /* @__PURE__ */ jsx(
@@ -446,9 +477,11 @@ function ResourcesSidebar({ timeRange }) {
446
477
  {
447
478
  size: "sm",
448
479
  fw: 600,
449
- c: "dimmed",
450
480
  tt: "uppercase",
451
- style: { fontFamily: "var(--elevasis-font-family-subtitle)" },
481
+ style: {
482
+ color: "var(--color-text-subtle)",
483
+ fontFamily: "var(--elevasis-font-family-subtitle)"
484
+ },
452
485
  children: "Domains"
453
486
  }
454
487
  ),
@@ -522,5 +555,2092 @@ function ResourcesSidebar({ timeRange }) {
522
555
  ] })
523
556
  ] });
524
557
  }
558
+ function ResourceHeader({ resource, type, connected, runningCount, sessionCapable }) {
559
+ const { currentMembership } = useOrganization();
560
+ const organizationName = currentMembership?.organization?.name;
561
+ const navigate = useNavigate();
562
+ const Icon = getResourceIcon(type);
563
+ const clipboard = useClipboard({ timeout: 2e3 });
564
+ const handleCopyId = () => {
565
+ clipboard.copy(`"${organizationName}/${resource.resourceId}"`);
566
+ notifications.show({
567
+ message: "Resource ID copied to clipboard",
568
+ color: "teal"
569
+ });
570
+ };
571
+ const handleGoToSessions = () => {
572
+ navigate({
573
+ to: "/operations/sessions",
574
+ search: { agent: resource.resourceId }
575
+ });
576
+ };
577
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
578
+ /* @__PURE__ */ jsx(
579
+ PageTitleCaption,
580
+ {
581
+ title: resource.name,
582
+ caption: resource.description || `${type.charAt(0).toUpperCase()}${type.slice(1)} details`
583
+ }
584
+ ),
585
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
586
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
587
+ /* @__PURE__ */ jsx(Icon, { size: 20, color: "var(--color-primary)" }),
588
+ /* @__PURE__ */ jsxs(Badge, { color: "blue", variant: "light", children: [
589
+ type.charAt(0).toUpperCase(),
590
+ type.slice(1)
591
+ ] }),
592
+ /* @__PURE__ */ jsx(Badge, { color: ResourceStatusColors[resource.status], variant: "outline", size: "sm", children: resource.status.toUpperCase() }),
593
+ resource.version && /* @__PURE__ */ jsxs(Badge, { variant: "outline", size: "sm", children: [
594
+ "v",
595
+ resource.version
596
+ ] }),
597
+ /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
598
+ /* @__PURE__ */ jsxs(Text, { size: "sm", ff: "monospace", c: "dimmed", children: [
599
+ organizationName,
600
+ "/",
601
+ resource.resourceId
602
+ ] }),
603
+ /* @__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" }) }) })
604
+ ] })
605
+ ] }),
606
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
607
+ connected && /* @__PURE__ */ jsx(Badge, { color: "green", variant: "dot", children: "CONNECTED" }),
608
+ runningCount && runningCount > 0 && /* @__PURE__ */ jsxs(Badge, { color: "blue", variant: "filled", children: [
609
+ runningCount,
610
+ " running"
611
+ ] }),
612
+ type === "agent" && sessionCapable && /* @__PURE__ */ jsx(Button, { size: "xs", variant: "light", leftSection: /* @__PURE__ */ jsx(IconMessage, { size: 16 }), onClick: handleGoToSessions, children: "Go to Sessions" }),
613
+ /* @__PURE__ */ jsx(
614
+ Button,
615
+ {
616
+ size: "sm",
617
+ variant: "light",
618
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
619
+ onClick: () => navigate({ to: "/operations/resources" }),
620
+ children: "Resources"
621
+ }
622
+ )
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 }) {
634
+ const navigate = useNavigate();
635
+ const { currentMembership } = useOrganization();
636
+ const orgName = currentMembership?.organization?.name || "current organization";
637
+ return /* @__PURE__ */ jsx(Stack, { children: /* @__PURE__ */ jsx(Card, { children: /* @__PURE__ */ jsxs(Stack, { align: "center", children: [
638
+ /* @__PURE__ */ jsx(Text, { size: "lg", c: "dimmed", fw: 500, children: "Resource not found" }),
639
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", ta: "center", children: [
640
+ "The ",
641
+ type,
642
+ ' "',
643
+ resourceId,
644
+ '" could not be found in ',
645
+ orgName,
646
+ "."
647
+ ] }),
648
+ /* @__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." }),
649
+ /* @__PURE__ */ jsx(
650
+ Button,
651
+ {
652
+ variant: "light",
653
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
654
+ onClick: () => navigate({ to: "/operations", search: { type: void 0 } }),
655
+ children: "Back to Operations"
656
+ }
657
+ )
658
+ ] }) }) });
659
+ }
660
+ function ResourceDetailPage({ type, resourceId, timeRange, renderExecutionPanel }) {
661
+ const { organizationReady } = useInitialization();
662
+ const { data, isLoading, error } = useResources();
663
+ const [connected, setConnected] = useState(false);
664
+ const [runningCount, setRunningCount] = useState(0);
665
+ const resource = data ? (() => {
666
+ const resources = [...data.workflows, ...data.agents];
667
+ const found = resources.find((r) => r.resourceId === resourceId && r.type === type);
668
+ return found || null;
669
+ })() : null;
670
+ const {
671
+ data: resourceDefinition,
672
+ isLoading: definitionLoading,
673
+ error: definitionError
674
+ } = useResourceDefinition(resourceId, true);
675
+ const handleConnectionStatus = (isConnected, count) => {
676
+ setConnected(isConnected);
677
+ setRunningCount(count);
678
+ };
679
+ if (!organizationReady || isLoading || definitionLoading) {
680
+ return /* @__PURE__ */ jsx(SubshellLoader, {});
681
+ }
682
+ if (error) {
683
+ return /* @__PURE__ */ jsx(ResourceErrorState, { error });
684
+ }
685
+ if (!resource) {
686
+ return /* @__PURE__ */ jsx(ResourceNotFoundState, { type, resourceId });
687
+ }
688
+ const validResource = resource;
689
+ const sessionCapable = isSessionCapable(type, resourceDefinition);
690
+ return /* @__PURE__ */ jsxs(Stack, { children: [
691
+ /* @__PURE__ */ jsx(
692
+ ResourceHeader,
693
+ {
694
+ resource: validResource,
695
+ type,
696
+ connected,
697
+ runningCount,
698
+ sessionCapable
699
+ }
700
+ ),
701
+ /* @__PURE__ */ jsx(ResourceHealthPanel, { resourceId, resourceType: type, timeRange }),
702
+ resourceDefinition && /* @__PURE__ */ jsx(ResourceDefinitionSection, { resourceDefinition }),
703
+ /* @__PURE__ */ jsx(
704
+ Paper,
705
+ {
706
+ withBorder: true,
707
+ p: "0",
708
+ style: {
709
+ flex: 1,
710
+ overflow: "hidden",
711
+ display: "flex",
712
+ flexDirection: "column"
713
+ },
714
+ children: definitionError ? /* @__PURE__ */ jsx(ResourceErrorState, { error: definitionError }) : !resourceDefinition ? /* @__PURE__ */ jsx(ResourceErrorState, { error: new Error("Resource definition not found") }) : renderExecutionPanel({
715
+ resourceId,
716
+ resourceType: type,
717
+ resourceName: validResource.name,
718
+ resourceDefinition,
719
+ onConnectionStatus: handleConnectionStatus
720
+ })
721
+ }
722
+ )
723
+ ] });
724
+ }
725
+ function CommandQueuePage({
726
+ timeRange,
727
+ pageSize = 20,
728
+ onNavigateToTask,
729
+ selectedCheckpoint,
730
+ status = "pending",
731
+ priorityRange = [1, 10]
732
+ }) {
733
+ const { organizationReady } = useInitialization();
734
+ const [deleteConfirmId, setDeleteConfirmId] = useState(null);
735
+ const { mutate: deleteTask, isPending: isDeleting } = useDeleteTask();
736
+ const serverStatus = status === "all" ? void 0 : status;
737
+ const { page, setPage, offset, totalPages } = usePaginationState(pageSize, [
738
+ selectedCheckpoint,
739
+ status,
740
+ timeRange,
741
+ priorityRange
742
+ ]);
743
+ const { data: checkpointData, isLoading: isLoadingCheckpoints } = useCommandQueueTotals({
744
+ timeRange,
745
+ priorityMin: priorityRange[0],
746
+ priorityMax: priorityRange[1]
747
+ });
748
+ const { data: tasks = [], isLoading: isLoadingTasks } = useCommandQueue({
749
+ status: serverStatus,
750
+ humanCheckpoint: selectedCheckpoint,
751
+ timeRange,
752
+ priorityMin: priorityRange[0],
753
+ priorityMax: priorityRange[1],
754
+ limit: pageSize,
755
+ offset
756
+ });
757
+ useEffect(() => {
758
+ if (!isLoadingTasks && tasks.length === 0 && page > 1) {
759
+ setPage(page - 1);
760
+ }
761
+ }, [tasks.length, isLoadingTasks]);
762
+ if (isLoadingCheckpoints || !organizationReady) return /* @__PURE__ */ jsx(AppShellLoader, {});
763
+ const totalTasks = checkpointData?.total ?? 0;
764
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
765
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Command Queue", caption: "Human-in-the-loop approval system for agent/workflow actions" }),
766
+ /* @__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(
767
+ CommandQueueTaskRow,
768
+ {
769
+ task,
770
+ onClick: () => onNavigateToTask(task.id),
771
+ onDelete: (taskId) => setDeleteConfirmId(taskId)
772
+ },
773
+ task.id
774
+ )) }),
775
+ totalPages(totalTasks) > 1 && /* @__PURE__ */ jsx(Group, { justify: "center", children: /* @__PURE__ */ jsx(Pagination, { size: "sm", total: totalPages(totalTasks), value: page, onChange: setPage, boundaries: 1 }) }),
776
+ /* @__PURE__ */ jsx(
777
+ ConfirmationModal,
778
+ {
779
+ opened: deleteConfirmId !== null,
780
+ onClose: () => setDeleteConfirmId(null),
781
+ loading: isDeleting,
782
+ icon: /* @__PURE__ */ jsx(IconTrash, { color: "red" }),
783
+ title: "Delete Task",
784
+ text: "Are you sure you want to delete this task? This action cannot be undone.",
785
+ buttonText: "Delete Task",
786
+ buttonColor: "red",
787
+ confirmationHandler: () => {
788
+ if (deleteConfirmId) {
789
+ deleteTask(deleteConfirmId, {
790
+ onSuccess: () => setDeleteConfirmId(null),
791
+ onError: () => setDeleteConfirmId(null)
792
+ });
793
+ }
794
+ }
795
+ }
796
+ )
797
+ ] });
798
+ }
799
+ function getPriorityColor(priority) {
800
+ if (priority >= 8) return "red";
801
+ if (priority >= 5) return "yellow";
802
+ return "gray";
803
+ }
804
+ function getStatusColor(status) {
805
+ switch (status) {
806
+ case "pending":
807
+ return "blue";
808
+ case "processing":
809
+ return "blue";
810
+ case "completed":
811
+ return "green";
812
+ case "failed":
813
+ return "red";
814
+ case "expired":
815
+ return "orange";
816
+ default:
817
+ return "gray";
818
+ }
819
+ }
820
+ function formatDate(date) {
821
+ const now = /* @__PURE__ */ new Date();
822
+ const diffMs = now.getTime() - date.getTime();
823
+ const diffMins = Math.floor(diffMs / 6e4);
824
+ const diffHours = Math.floor(diffMins / 60);
825
+ const diffDays = Math.floor(diffHours / 24);
826
+ if (diffMins < 60) return `${diffMins}m ago`;
827
+ if (diffHours < 24) return `${diffHours}h ago`;
828
+ return `${diffDays}d ago`;
829
+ }
830
+ function CommandQueueDetailPage({
831
+ taskId,
832
+ orgName,
833
+ renderRichText,
834
+ onNavigateBack,
835
+ onViewExecution
836
+ }) {
837
+ const { mutate: submitAction, isPending, error: submitError, reset: resetSubmitAction } = useSubmitAction();
838
+ const { mutate: deleteTask, isPending: isDeleting } = useDeleteTask();
839
+ const [actionModalOpened, setActionModalOpened] = useState(false);
840
+ const [selectedAction, setSelectedAction] = useState(null);
841
+ const [confirmAction, setConfirmAction] = useState(null);
842
+ const [deleteConfirmOpened, setDeleteConfirmOpened] = useState(false);
843
+ const [contextView, setContextView] = useState("formatted");
844
+ const [submitResultError, setSubmitResultError] = useState(null);
845
+ const { data: tasks, isLoading } = useCommandQueue();
846
+ const task = tasks?.find((t) => t.id === taskId);
847
+ const richTextRenderer = renderRichText ? (props) => renderRichText(props) : void 0;
848
+ const submitCallbacks = {
849
+ onSuccess: (data) => {
850
+ if (data.execution?.success === false) {
851
+ setSubmitResultError(data.execution.error?.message || "Action execution failed.");
852
+ } else {
853
+ setSubmitResultError(null);
854
+ }
855
+ },
856
+ onError: (error) => {
857
+ const { message, fields, requestId } = getErrorInfo(error);
858
+ setSubmitResultError(formatErrorMessage(message, requestId, fields));
859
+ }
860
+ };
861
+ const handleActionClick = (action) => {
862
+ if (action.requiresConfirmation) {
863
+ setConfirmAction(action);
864
+ } else if (action.form) {
865
+ setSubmitResultError(null);
866
+ setSelectedAction(action);
867
+ setActionModalOpened(true);
868
+ } else {
869
+ submitAction({ taskId, actionId: action.id }, submitCallbacks);
870
+ }
871
+ };
872
+ const handleConfirm = () => {
873
+ if (!confirmAction) return;
874
+ if (confirmAction.form) {
875
+ setSubmitResultError(null);
876
+ setSelectedAction(confirmAction);
877
+ setActionModalOpened(true);
878
+ } else {
879
+ submitAction({ taskId, actionId: confirmAction.id }, submitCallbacks);
880
+ }
881
+ setConfirmAction(null);
882
+ };
883
+ const handleRetry = () => {
884
+ if (task?.selectedAction) {
885
+ setSubmitResultError(null);
886
+ submitAction({ taskId, actionId: task.selectedAction, payload: task.actionPayload }, submitCallbacks);
887
+ }
888
+ };
889
+ const handleViewExecution = () => {
890
+ if (!task?.targetExecutionId || !task.targetResourceId || !task.targetResourceType) return;
891
+ onViewExecution(task.targetResourceType, task.targetResourceId, task.targetExecutionId);
892
+ };
893
+ if (isLoading) return /* @__PURE__ */ jsx(AppShellLoader, {});
894
+ if (!task) {
895
+ return /* @__PURE__ */ jsxs(Stack, { children: [
896
+ /* @__PURE__ */ jsx(
897
+ PageTitleCaption,
898
+ {
899
+ title: "Task Not Found",
900
+ rightSection: /* @__PURE__ */ jsx(Button, { variant: "subtle", leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }), onClick: onNavigateBack, size: "sm", children: "Back to Queue" })
901
+ }
902
+ ),
903
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Text, { ta: "center", c: "dimmed", children: "This task no longer exists or could not be loaded." }) })
904
+ ] });
905
+ }
906
+ return /* @__PURE__ */ jsxs(Stack, { children: [
907
+ /* @__PURE__ */ jsx(
908
+ PageTitleCaption,
909
+ {
910
+ title: "Task Detail",
911
+ caption: task.description || "Task approval required",
912
+ rightSection: /* @__PURE__ */ jsx(Button, { variant: "light", leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }), onClick: onNavigateBack, size: "sm", children: "Back to Queue" })
913
+ }
914
+ ),
915
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
916
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
917
+ /* @__PURE__ */ jsxs(Badge, { color: getPriorityColor(task.priority), variant: "light", size: "sm", children: [
918
+ "P",
919
+ task.priority
920
+ ] }),
921
+ /* @__PURE__ */ jsx(
922
+ Badge,
923
+ {
924
+ color: getStatusColor(task.status),
925
+ variant: "light",
926
+ size: "sm",
927
+ leftSection: task.status === "processing" ? /* @__PURE__ */ jsx(Loader, { size: 6 }) : void 0,
928
+ children: task.status.toUpperCase()
929
+ }
930
+ ),
931
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
932
+ /* @__PURE__ */ jsx(IconClock, { size: 14, style: { verticalAlign: "middle", marginRight: 4 } }),
933
+ formatDate(task.createdAt)
934
+ ] }),
935
+ task.expiresAt && /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
936
+ "Expires ",
937
+ formatDate(task.expiresAt)
938
+ ] })
939
+ ] }),
940
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
941
+ task.status === "failed" && /* @__PURE__ */ jsx(Button, { variant: "light", color: "red", size: "xs", loading: isPending, onClick: handleRetry, children: "Retry" }),
942
+ /* @__PURE__ */ jsx(
943
+ ActionIcon,
944
+ {
945
+ variant: "subtle",
946
+ color: "red",
947
+ size: "sm",
948
+ disabled: task.status === "processing",
949
+ onClick: () => setDeleteConfirmOpened(true),
950
+ title: "Delete task",
951
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 16 })
952
+ }
953
+ )
954
+ ] })
955
+ ] }),
956
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
957
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Resources" }),
958
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: 2, children: [
959
+ /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
960
+ /* @__PURE__ */ jsx(Text, { size: "xs", children: "Task ID" }),
961
+ /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
962
+ /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.id }),
963
+ /* @__PURE__ */ jsx(CopyButton, { value: task.id, children: ({ copied, copy }) => /* @__PURE__ */ jsx(
964
+ ActionIcon,
965
+ {
966
+ onClick: copy,
967
+ variant: "subtle",
968
+ size: "xs",
969
+ color: copied ? "green" : "var(--color-text-subtle)",
970
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
971
+ }
972
+ ) })
973
+ ] })
974
+ ] }),
975
+ task.humanCheckpoint && /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
976
+ /* @__PURE__ */ jsx(Text, { size: "xs", children: "Checkpoint" }),
977
+ /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.humanCheckpoint })
978
+ ] })
979
+ ] }),
980
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: 2, children: [
981
+ /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
982
+ /* @__PURE__ */ jsx(Text, { size: "xs", children: "Origin Resource" }),
983
+ /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
984
+ /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.originResourceId }),
985
+ /* @__PURE__ */ jsx(CopyButton, { value: task.originResourceId, children: ({ copied, copy }) => /* @__PURE__ */ jsx(
986
+ ActionIcon,
987
+ {
988
+ onClick: copy,
989
+ variant: "subtle",
990
+ size: "xs",
991
+ color: copied ? "green" : "var(--color-text-subtle)",
992
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
993
+ }
994
+ ) })
995
+ ] })
996
+ ] }),
997
+ /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
998
+ /* @__PURE__ */ jsx(Text, { size: "xs", children: "Origin Execution ID" }),
999
+ /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1000
+ /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.originExecutionId }),
1001
+ /* @__PURE__ */ jsx(CopyButton, { value: `${orgName}/${task.originResourceId} ${task.originExecutionId}`, children: ({ copied, copy }) => /* @__PURE__ */ jsx(
1002
+ ActionIcon,
1003
+ {
1004
+ onClick: copy,
1005
+ variant: "subtle",
1006
+ size: "xs",
1007
+ color: copied ? "green" : "var(--color-text-subtle)",
1008
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
1009
+ }
1010
+ ) })
1011
+ ] })
1012
+ ] })
1013
+ ] }),
1014
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: 2, children: [
1015
+ /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
1016
+ /* @__PURE__ */ jsx(Text, { size: "xs", children: "Target Resource" }),
1017
+ /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.targetResourceId || "N/A" })
1018
+ ] }),
1019
+ /* @__PURE__ */ jsxs(Stack, { gap: 2, children: [
1020
+ /* @__PURE__ */ jsx(Text, { size: "xs", children: "Target Execution ID" }),
1021
+ /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1022
+ /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: "var(--color-text-subtle)", children: task.targetExecutionId ?? "N/A" }),
1023
+ task.targetExecutionId && /* @__PURE__ */ jsx(CopyButton, { value: `${orgName}/${task.targetResourceId} ${task.targetExecutionId}`, children: ({ copied, copy }) => /* @__PURE__ */ jsx(
1024
+ ActionIcon,
1025
+ {
1026
+ onClick: copy,
1027
+ variant: "subtle",
1028
+ size: "xs",
1029
+ color: copied ? "green" : "var(--color-text-subtle)",
1030
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconCopy, { size: 14 })
1031
+ }
1032
+ ) })
1033
+ ] })
1034
+ ] })
1035
+ ] }),
1036
+ /* @__PURE__ */ jsx(Group, { justify: "flex-end", children: /* @__PURE__ */ jsx(
1037
+ Button,
1038
+ {
1039
+ variant: "light",
1040
+ color: "var(--color-primary)",
1041
+ size: "sm",
1042
+ leftSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 14 }),
1043
+ onClick: () => window.open(
1044
+ `/operations/resources/${task.originResourceType}/${task.originResourceId}?exec=${task.originExecutionId}`,
1045
+ "_blank",
1046
+ "noopener,noreferrer"
1047
+ ),
1048
+ children: "View Origin Execution"
1049
+ }
1050
+ ) })
1051
+ ] }) }),
1052
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1053
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", children: [
1054
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Context" }),
1055
+ /* @__PURE__ */ jsx(
1056
+ SegmentedControl,
1057
+ {
1058
+ value: contextView,
1059
+ onChange: (v) => setContextView(v),
1060
+ size: "xs",
1061
+ data: [
1062
+ { label: "Formatted", value: "formatted" },
1063
+ { label: "JSON", value: "json" }
1064
+ ]
1065
+ }
1066
+ )
1067
+ ] }),
1068
+ contextView === "formatted" ? /* @__PURE__ */ jsx(ContextViewer, { data: task.context }) : /* @__PURE__ */ jsx(JsonViewer, { data: task.context })
1069
+ ] }) }),
1070
+ (task.status === "pending" || task.status === "failed") && task.actions.length > 0 && /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1071
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Actions" }),
1072
+ /* @__PURE__ */ jsx(Group, { gap: "sm", children: task.actions.map((action) => {
1073
+ const Icon = getIcon(action.icon);
1074
+ const variant = "light";
1075
+ return /* @__PURE__ */ jsx(
1076
+ Button,
1077
+ {
1078
+ variant,
1079
+ color: action.color || (action.type === "danger" ? "red" : "blue"),
1080
+ leftSection: Icon ? /* @__PURE__ */ jsx(Icon, { size: 16 }) : null,
1081
+ loading: isPending,
1082
+ onClick: () => handleActionClick(action),
1083
+ title: action.description,
1084
+ size: "sm",
1085
+ children: action.label
1086
+ },
1087
+ action.id
1088
+ );
1089
+ }) })
1090
+ ] }) }),
1091
+ task.selectedAction && /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
1092
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Action" }),
1093
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1094
+ /* @__PURE__ */ jsx(ThemeIcon, { size: "sm", variant: "light", color: "green", radius: "xl", children: /* @__PURE__ */ jsx(IconCheck, { size: 12 }) }),
1095
+ /* @__PURE__ */ jsxs(Text, { fw: 600, size: "sm", style: { fontFamily: "var(--mantine-font-family-headings)" }, children: [
1096
+ "Submitted: ",
1097
+ task.actions.find((a) => a.id === task.selectedAction)?.label || task.selectedAction
1098
+ ] }),
1099
+ task.targetExecutionId && /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: "cyan", leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 10 }), children: "Executed" })
1100
+ ] }),
1101
+ task.actionPayload !== void 0 && task.actionPayload !== null && /* @__PURE__ */ jsx(JsonViewer, { data: task.actionPayload, maxHeight: 200 }),
1102
+ task.completedAt && /* @__PURE__ */ jsxs(Text, { size: "xs", children: [
1103
+ "Completed ",
1104
+ formatDate(task.completedAt),
1105
+ task.completedBy ? ` by ${task.completedBy}` : ""
1106
+ ] }),
1107
+ task.targetExecutionId && /* @__PURE__ */ jsx(
1108
+ Button,
1109
+ {
1110
+ variant: "light",
1111
+ size: "sm",
1112
+ leftSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 14 }),
1113
+ onClick: handleViewExecution,
1114
+ w: "fit-content",
1115
+ children: "View Target Execution"
1116
+ }
1117
+ )
1118
+ ] }) }),
1119
+ submitResultError && /* @__PURE__ */ jsx(
1120
+ Alert,
1121
+ {
1122
+ color: "red",
1123
+ variant: "light",
1124
+ icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }),
1125
+ title: "Submission failed",
1126
+ withCloseButton: true,
1127
+ onClose: () => setSubmitResultError(null),
1128
+ children: /* @__PURE__ */ jsx(Text, { size: "sm", style: { whiteSpace: "pre-line" }, children: submitResultError })
1129
+ }
1130
+ ),
1131
+ /* @__PURE__ */ jsx(CustomModal, { opened: !!confirmAction, onClose: () => setConfirmAction(null), size: "sm", children: /* @__PURE__ */ jsxs(Stack, { children: [
1132
+ /* @__PURE__ */ jsx(Text, { fw: 600, children: "Confirm Action" }),
1133
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: confirmAction?.confirmationMessage || `Are you sure you want to ${confirmAction?.label.toLowerCase()}?` }),
1134
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
1135
+ /* @__PURE__ */ jsx(Button, { variant: "default", onClick: () => setConfirmAction(null), children: "Cancel" }),
1136
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, children: confirmAction?.label })
1137
+ ] })
1138
+ ] }) }),
1139
+ selectedAction && /* @__PURE__ */ jsx(
1140
+ ActionModal,
1141
+ {
1142
+ action: selectedAction,
1143
+ task,
1144
+ opened: actionModalOpened,
1145
+ onClose: () => {
1146
+ setActionModalOpened(false);
1147
+ resetSubmitAction();
1148
+ },
1149
+ onSubmit: (payload, notes) => {
1150
+ submitAction(
1151
+ { taskId, actionId: selectedAction.id, payload, notes },
1152
+ {
1153
+ onSuccess: (data) => {
1154
+ submitCallbacks.onSuccess(data);
1155
+ setActionModalOpened(false);
1156
+ },
1157
+ onError: submitCallbacks.onError
1158
+ }
1159
+ );
1160
+ },
1161
+ richTextRenderer,
1162
+ error: submitError,
1163
+ isPending
1164
+ }
1165
+ ),
1166
+ /* @__PURE__ */ jsx(CustomModal, { opened: deleteConfirmOpened, onClose: () => setDeleteConfirmOpened(false), size: "sm", children: /* @__PURE__ */ jsxs(Stack, { children: [
1167
+ /* @__PURE__ */ jsx(Text, { fw: 600, children: "Delete Task" }),
1168
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: "Are you sure you want to delete this task? This action cannot be undone." }),
1169
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
1170
+ /* @__PURE__ */ jsx(Button, { variant: "default", onClick: () => setDeleteConfirmOpened(false), children: "Cancel" }),
1171
+ /* @__PURE__ */ jsx(
1172
+ Button,
1173
+ {
1174
+ color: "red",
1175
+ loading: isDeleting,
1176
+ onClick: () => {
1177
+ deleteTask(task.id, {
1178
+ onSuccess: () => onNavigateBack()
1179
+ });
1180
+ setDeleteConfirmOpened(false);
1181
+ },
1182
+ children: "Delete"
1183
+ }
1184
+ )
1185
+ ] })
1186
+ ] }) })
1187
+ ] });
1188
+ }
1189
+
1190
+ // src/hooks/operations/command-view/utils/transformCommandViewData.ts
1191
+ function transformCommandViewData(data) {
1192
+ const nodes = [
1193
+ // Map triggers (resourceId -> id)
1194
+ ...data.triggers.map((trigger) => ({
1195
+ id: trigger.resourceId,
1196
+ type: "trigger",
1197
+ name: trigger.name,
1198
+ description: trigger.description,
1199
+ status: trigger.status,
1200
+ triggerType: trigger.triggerType,
1201
+ webhookPath: trigger.webhookPath,
1202
+ schedule: trigger.schedule
1203
+ })),
1204
+ // Map agents (resourceId -> id)
1205
+ ...data.agents.map((agent) => {
1206
+ const agentWithStats = agent;
1207
+ return {
1208
+ id: agent.resourceId,
1209
+ type: "agent",
1210
+ name: agent.name,
1211
+ description: agent.description,
1212
+ status: agent.status,
1213
+ modelProvider: agent.modelProvider,
1214
+ modelId: agent.modelId,
1215
+ toolCount: agent.toolCount,
1216
+ hasKnowledgeMap: agent.hasKnowledgeMap,
1217
+ hasMemory: agent.hasMemory,
1218
+ stats: agentWithStats.stats || null
1219
+ // Preserve stats if present
1220
+ };
1221
+ }),
1222
+ // Map workflows (resourceId -> id)
1223
+ ...data.workflows.map((workflow) => {
1224
+ const workflowWithStats = workflow;
1225
+ return {
1226
+ id: workflow.resourceId,
1227
+ type: "workflow",
1228
+ name: workflow.name,
1229
+ description: workflow.description,
1230
+ status: workflow.status,
1231
+ stepCount: workflow.stepCount,
1232
+ entryPoint: workflow.entryPoint,
1233
+ stats: workflowWithStats.stats || null
1234
+ // Preserve stats if present
1235
+ };
1236
+ }),
1237
+ // Map integrations (resourceId -> id)
1238
+ ...data.integrations.map((integration) => ({
1239
+ id: integration.resourceId,
1240
+ type: "integration",
1241
+ name: integration.name,
1242
+ description: integration.description,
1243
+ status: integration.status,
1244
+ provider: integration.provider,
1245
+ connectionStatus: "connected",
1246
+ // Default - runtime status not yet available
1247
+ credentialName: integration.credentialName
1248
+ })),
1249
+ // Map external resources (resourceId -> id)
1250
+ ...(data.externalResources ?? []).map((external) => ({
1251
+ id: external.resourceId,
1252
+ type: "external",
1253
+ name: external.name,
1254
+ description: external.description,
1255
+ status: external.status,
1256
+ platform: external.platform,
1257
+ platformUrl: external.platformUrl,
1258
+ externalId: external.externalId
1259
+ })),
1260
+ // Map human checkpoints to human nodes (resourceId -> id)
1261
+ ...(data.humanCheckpoints ?? []).map((humanCheckpoint) => {
1262
+ const checkpointWithStats = humanCheckpoint;
1263
+ return {
1264
+ id: humanCheckpoint.resourceId,
1265
+ type: "human",
1266
+ name: humanCheckpoint.name,
1267
+ description: humanCheckpoint.description ?? "",
1268
+ status: humanCheckpoint.status,
1269
+ stats: checkpointWithStats.stats || null
1270
+ // Preserve stats if present
1271
+ };
1272
+ })
1273
+ ];
1274
+ const edges = data.edges.map((edge, index) => ({
1275
+ id: edge.id || `edge-${index}`,
1276
+ source: edge.source,
1277
+ target: edge.target,
1278
+ relationship: edge.relationship
1279
+ }));
1280
+ return { nodes, edges };
1281
+ }
1282
+
1283
+ // src/hooks/operations/command-view/utils/filterCommandViewData.ts
1284
+ function filterCommandViewData(data, filters) {
1285
+ const { domains: selectedDomains, excludedDomains = [], status: statusFilter, showIntegrations } = filters;
1286
+ const hasDomainFilter = selectedDomains.length > 0;
1287
+ const hasExcludeFilter = excludedDomains.length > 0;
1288
+ const hasStatusFilter = statusFilter !== "all";
1289
+ const hasIntegrationFilter = !showIntegrations;
1290
+ if (!hasDomainFilter && !hasExcludeFilter && !hasStatusFilter && !hasIntegrationFilter) {
1291
+ return data;
1292
+ }
1293
+ const matchesDomainFilter = (domains) => {
1294
+ if (hasExcludeFilter && (domains?.some((d) => excludedDomains.includes(d)) ?? false)) return false;
1295
+ if (hasDomainFilter && !(domains?.some((d) => selectedDomains.includes(d)) ?? false)) return false;
1296
+ return true;
1297
+ };
1298
+ const filteredAgents = data.agents.filter((agent) => {
1299
+ if (hasStatusFilter && agent.status !== statusFilter) return false;
1300
+ if (!matchesDomainFilter(agent.domains)) return false;
1301
+ return true;
1302
+ });
1303
+ const filteredWorkflows = data.workflows.filter((workflow) => {
1304
+ if (hasStatusFilter && workflow.status !== statusFilter) return false;
1305
+ if (!matchesDomainFilter(workflow.domains)) return false;
1306
+ return true;
1307
+ });
1308
+ const filteredTriggers = data.triggers.filter((trigger) => {
1309
+ if (hasStatusFilter && trigger.status !== statusFilter) return false;
1310
+ if (!matchesDomainFilter(trigger.domains)) return false;
1311
+ return true;
1312
+ });
1313
+ const filteredIntegrations = showIntegrations ? data.integrations.filter((integration) => {
1314
+ if (hasStatusFilter && integration.status !== statusFilter) return false;
1315
+ if (!matchesDomainFilter(integration.domains)) return false;
1316
+ return true;
1317
+ }) : [];
1318
+ const filteredExternalResources = (data.externalResources ?? []).filter((external) => {
1319
+ if (hasStatusFilter && external.status !== statusFilter) return false;
1320
+ if (!matchesDomainFilter(external.domains)) return false;
1321
+ return true;
1322
+ });
1323
+ const filteredHumanCheckpoints = (data.humanCheckpoints ?? []).filter((checkpoint) => {
1324
+ if (hasStatusFilter && checkpoint.status !== statusFilter) return false;
1325
+ if (!matchesDomainFilter(checkpoint.domains)) return false;
1326
+ return true;
1327
+ });
1328
+ const remainingNodeIds = /* @__PURE__ */ new Set([
1329
+ ...filteredAgents.map((a) => a.resourceId),
1330
+ ...filteredWorkflows.map((w) => w.resourceId),
1331
+ ...filteredTriggers.map((t) => t.resourceId),
1332
+ ...filteredIntegrations.map((i) => i.resourceId),
1333
+ ...filteredExternalResources.map((e) => e.resourceId),
1334
+ ...filteredHumanCheckpoints.map((h) => h.resourceId)
1335
+ ]);
1336
+ const filteredEdges = data.edges.filter(
1337
+ (edge) => remainingNodeIds.has(edge.source) && remainingNodeIds.has(edge.target)
1338
+ );
1339
+ return {
1340
+ ...data,
1341
+ agents: filteredAgents,
1342
+ workflows: filteredWorkflows,
1343
+ triggers: filteredTriggers,
1344
+ integrations: filteredIntegrations,
1345
+ externalResources: filteredExternalResources,
1346
+ humanCheckpoints: filteredHumanCheckpoints,
1347
+ edges: filteredEdges
1348
+ };
1349
+ }
1350
+
1351
+ // src/hooks/operations/command-view/utils/mergeStatsWithTopology.ts
1352
+ function mergeStatsWithTopology(topology, stats) {
1353
+ return {
1354
+ ...topology,
1355
+ agents: topology.agents.map((agent) => ({
1356
+ ...agent,
1357
+ stats: stats.resources[agent.resourceId] || null
1358
+ })),
1359
+ workflows: topology.workflows.map((workflow) => ({
1360
+ ...workflow,
1361
+ stats: stats.resources[workflow.resourceId] || null
1362
+ })),
1363
+ humanCheckpoints: topology.humanCheckpoints.map((checkpoint) => ({
1364
+ ...checkpoint,
1365
+ stats: stats.humanCheckpoints[checkpoint.resourceId] || null
1366
+ }))
1367
+ };
1368
+ }
1369
+ var FILTER_DEBOUNCE_DELAY = 150;
1370
+ var TOPBAR_AND_PADDING = 54;
1371
+ function CommandViewPage({ timeRange }) {
1372
+ const { organizationReady } = useInitialization();
1373
+ const { data, isLoading, error } = useCommandViewData();
1374
+ const graphRef = useRef(null);
1375
+ const statusFilter = useCommandViewStore((s) => s.statusFilter);
1376
+ const showIntegrations = useCommandViewStore((s) => s.showIntegrations);
1377
+ const fitViewOnFilter = useCommandViewStore((s) => s.fitViewOnFilter);
1378
+ const selectedNodeId = useCommandViewStore((s) => s.selectedNodeId);
1379
+ const setSelectedNodeId = useCommandViewStore((s) => s.setSelectedNodeId);
1380
+ const domainFilters = useCommandViewDomainFilters((s) => s.filters);
1381
+ const { includedDomains, excludedDomains } = useMemo(() => {
1382
+ const included = [];
1383
+ const excluded = [];
1384
+ for (const [id, state] of Object.entries(domainFilters)) {
1385
+ if (state === "include") included.push(id);
1386
+ else if (state === "exclude") excluded.push(id);
1387
+ }
1388
+ return { includedDomains: included, excludedDomains: excluded };
1389
+ }, [domainFilters]);
1390
+ const { data: statsData, error: statsError } = useCommandViewStats(timeRange);
1391
+ const cleanData = data ?? null;
1392
+ const dataWithStats = useMemo(() => {
1393
+ if (!cleanData) return null;
1394
+ if (!statsData) return cleanData;
1395
+ return mergeStatsWithTopology(cleanData, statsData);
1396
+ }, [cleanData, statsData]);
1397
+ const filteredData = useMemo(() => {
1398
+ if (!dataWithStats) return null;
1399
+ return filterCommandViewData(dataWithStats, {
1400
+ domains: includedDomains,
1401
+ excludedDomains,
1402
+ status: statusFilter,
1403
+ showIntegrations
1404
+ });
1405
+ }, [dataWithStats, includedDomains, excludedDomains, statusFilter, showIntegrations]);
1406
+ const debouncedFitView = useCallback(
1407
+ debounce(() => {
1408
+ graphRef.current?.fitView();
1409
+ }, FILTER_DEBOUNCE_DELAY),
1410
+ []
1411
+ );
1412
+ useEffect(() => {
1413
+ return () => debouncedFitView.cancel();
1414
+ }, [debouncedFitView]);
1415
+ useEffect(() => {
1416
+ if (fitViewOnFilter) {
1417
+ debouncedFitView();
1418
+ }
1419
+ }, [domainFilters, statusFilter, showIntegrations, debouncedFitView, fitViewOnFilter]);
1420
+ if (!organizationReady) return /* @__PURE__ */ jsx(AppShellLoader, {});
1421
+ const showLoader = isLoading && !data;
1422
+ return /* @__PURE__ */ jsxs(
1423
+ Box,
1424
+ {
1425
+ style: {
1426
+ height: `calc(100vh - ${TOPBAR_AND_PADDING}px)`,
1427
+ position: "relative",
1428
+ overflow: "hidden",
1429
+ padding: "var(--mantine-spacing-sm)"
1430
+ },
1431
+ children: [
1432
+ showLoader && /* @__PURE__ */ jsx(Center, { style: { height: "100%" }, children: /* @__PURE__ */ jsx(Loader, { size: "xl" }) }),
1433
+ error && !data && /* @__PURE__ */ jsx(APIErrorAlert, { error }),
1434
+ statsError && /* @__PURE__ */ jsx(APIErrorAlert, { error: statsError, title: "Failed to load execution stats", color: "yellow" }),
1435
+ !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." }),
1436
+ filteredData && /* @__PURE__ */ jsx(
1437
+ CommandViewGraph,
1438
+ {
1439
+ ref: graphRef,
1440
+ graph: transformCommandViewData(filteredData),
1441
+ height: "100%",
1442
+ selectedNodeId,
1443
+ onNodeSelect: setSelectedNodeId
1444
+ }
1445
+ )
1446
+ ]
1447
+ }
1448
+ );
1449
+ }
1450
+
1451
+ // src/hooks/operations/calibration/queryKeys.ts
1452
+ var calibrationKeys = {
1453
+ all: ["calibration"],
1454
+ // Projects
1455
+ projects: (org) => [...calibrationKeys.all, "projects", org],
1456
+ projectsByResource: (org, resourceId, resourceType) => [...calibrationKeys.all, "projects", org, resourceId, resourceType],
1457
+ project: (org, projectId) => [...calibrationKeys.all, "project", org, projectId],
1458
+ // Runs
1459
+ runs: (org, projectId) => [...calibrationKeys.all, "runs", org, projectId],
1460
+ run: (org, runId) => [...calibrationKeys.all, "run", org, runId],
1461
+ runFull: (org, runId) => [...calibrationKeys.all, "run-full", org, runId]
1462
+ };
1463
+
1464
+ // src/hooks/operations/calibration/useCalibrationProjects.ts
1465
+ function useAllCalibrationProjects() {
1466
+ const { apiRequest, organizationId, isReady } = useElevasisServices();
1467
+ return useQuery({
1468
+ queryKey: calibrationKeys.projects(organizationId ?? "none"),
1469
+ queryFn: async () => {
1470
+ const response = await apiRequest("/calibration/projects");
1471
+ return response.projects;
1472
+ },
1473
+ enabled: isReady && !!organizationId
1474
+ });
1475
+ }
1476
+ function useCalibrationProjects(resourceId, resourceType) {
1477
+ const { apiRequest, organizationId, isReady } = useElevasisServices();
1478
+ return useQuery({
1479
+ queryKey: calibrationKeys.projectsByResource(organizationId ?? "none", resourceId, resourceType),
1480
+ queryFn: async () => {
1481
+ const response = await apiRequest(
1482
+ `/calibration/projects?resourceId=${resourceId}&resourceType=${resourceType}`
1483
+ );
1484
+ return response.projects;
1485
+ },
1486
+ enabled: isReady && !!resourceId && !!resourceType && !!organizationId
1487
+ });
1488
+ }
1489
+ function useCalibrationProject(projectId) {
1490
+ const { apiRequest, organizationId, isReady } = useElevasisServices();
1491
+ return useQuery({
1492
+ queryKey: calibrationKeys.project(organizationId ?? "none", projectId),
1493
+ queryFn: async () => {
1494
+ const response = await apiRequest(`/calibration/projects/${projectId}`);
1495
+ return response.project;
1496
+ },
1497
+ enabled: isReady && !!projectId && !!organizationId
1498
+ });
1499
+ }
1500
+ function useCreateProject() {
1501
+ const { apiRequest, organizationId } = useElevasisServices();
1502
+ const queryClient = useQueryClient();
1503
+ return useMutation({
1504
+ mutationFn: async (input) => {
1505
+ const response = await apiRequest("/calibration/projects", {
1506
+ method: "POST",
1507
+ body: JSON.stringify(input)
1508
+ });
1509
+ return response.project;
1510
+ },
1511
+ onSuccess: (data) => {
1512
+ queryClient.invalidateQueries({
1513
+ queryKey: calibrationKeys.projects(organizationId ?? "none")
1514
+ });
1515
+ queryClient.invalidateQueries({
1516
+ queryKey: calibrationKeys.projectsByResource(organizationId ?? "none", data.resourceId, data.resourceType)
1517
+ });
1518
+ },
1519
+ onError: (error) => {
1520
+ showApiErrorNotification(error);
1521
+ }
1522
+ });
1523
+ }
1524
+ function useDeleteProject() {
1525
+ const { apiRequest } = useElevasisServices();
1526
+ const queryClient = useQueryClient();
1527
+ return useMutation({
1528
+ mutationFn: async (id) => {
1529
+ await apiRequest(`/calibration/projects/${id}`, {
1530
+ method: "DELETE"
1531
+ });
1532
+ },
1533
+ onSuccess: () => {
1534
+ queryClient.invalidateQueries({
1535
+ queryKey: calibrationKeys.all
1536
+ });
1537
+ },
1538
+ onError: (error) => {
1539
+ showApiErrorNotification(error);
1540
+ }
1541
+ });
1542
+ }
1543
+ function ProjectCard({ project, onNavigate }) {
1544
+ const deleteProject = useDeleteProject();
1545
+ const handleClick = () => {
1546
+ onNavigate(project.id);
1547
+ };
1548
+ const handleDelete = async (e) => {
1549
+ e.stopPropagation();
1550
+ if (window.confirm("Delete this project and all its runs?")) {
1551
+ await deleteProject.mutateAsync(project.id);
1552
+ }
1553
+ };
1554
+ return /* @__PURE__ */ jsx(Card, { shadow: "sm", withBorder: true, style: { cursor: "pointer" }, onClick: handleClick, children: /* @__PURE__ */ jsxs(Stack, { children: [
1555
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
1556
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", align: "center", children: [
1557
+ /* @__PURE__ */ jsx(IconFlask, { size: 20, color: "var(--color-primary)" }),
1558
+ /* @__PURE__ */ jsx(Text, { fw: 600, lineClamp: 1, style: { fontFamily: "var(--elevasis-font-family-subtitle)" }, children: project.name })
1559
+ ] }),
1560
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1561
+ /* @__PURE__ */ jsx(Badge, { variant: "light", size: "sm", children: project.resourceType }),
1562
+ /* @__PURE__ */ jsxs(Menu, { shadow: "md", width: 150, position: "bottom-end", children: [
1563
+ /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsx(IconDotsVertical, { size: 16 }) }) }),
1564
+ /* @__PURE__ */ jsx(Menu.Dropdown, { children: /* @__PURE__ */ jsx(Menu.Item, { leftSection: /* @__PURE__ */ jsx(IconTrash, { size: 14 }), color: "red", onClick: handleDelete, children: "Delete" }) })
1565
+ ] })
1566
+ ] })
1567
+ ] }),
1568
+ project.description && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", lineClamp: 1, children: project.description }),
1569
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1570
+ "Created ",
1571
+ new Date(project.createdAt).toLocaleDateString()
1572
+ ] })
1573
+ ] }) });
1574
+ }
1575
+ function CreateProjectModal({ opened, onClose, resourceId, resourceType }) {
1576
+ const createProject = useCreateProject();
1577
+ const form = useForm({
1578
+ initialValues: {
1579
+ name: "",
1580
+ description: ""
1581
+ },
1582
+ validate: {
1583
+ name: (value) => value.trim().length === 0 ? "Name is required" : null
1584
+ }
1585
+ });
1586
+ const handleSubmit = async (values) => {
1587
+ await createProject.mutateAsync({
1588
+ resourceId,
1589
+ resourceType,
1590
+ name: values.name.trim(),
1591
+ description: values.description.trim() || void 0
1592
+ });
1593
+ form.reset();
1594
+ onClose();
1595
+ };
1596
+ 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: [
1597
+ /* @__PURE__ */ jsx(
1598
+ TextInput,
1599
+ {
1600
+ label: "Project Name",
1601
+ placeholder: "e.g., Q1 2025 Model Selection",
1602
+ required: true,
1603
+ ...form.getInputProps("name")
1604
+ }
1605
+ ),
1606
+ /* @__PURE__ */ jsx(
1607
+ Textarea,
1608
+ {
1609
+ label: "Description",
1610
+ placeholder: "Optional: Describe the goal of this calibration project",
1611
+ minRows: 2,
1612
+ ...form.getInputProps("description")
1613
+ }
1614
+ ),
1615
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", children: [
1616
+ /* @__PURE__ */ jsx(Button, { variant: "subtle", onClick: onClose, children: "Cancel" }),
1617
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: createProject.isPending, children: "Create Project" })
1618
+ ] })
1619
+ ] }) }) });
1620
+ }
1621
+ function CalibrationPage({ resourceId, resourceType, onProjectNavigate }) {
1622
+ const [createModalOpen, setCreateModalOpen] = useState(false);
1623
+ const { data: projects, isLoading, error } = useCalibrationProjects(resourceId, resourceType);
1624
+ if (isLoading) {
1625
+ return /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) });
1626
+ }
1627
+ if (error) {
1628
+ return /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), title: "Error", color: "red", children: "Failed to load calibration projects. Please try again." });
1629
+ }
1630
+ return /* @__PURE__ */ jsx(PageContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
1631
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "center", children: [
1632
+ /* @__PURE__ */ jsxs("div", { children: [
1633
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Calibration Lab" }),
1634
+ /* @__PURE__ */ jsx(Text, { c: "dimmed", size: "sm", children: "Compare AI configurations and optimize performance" })
1635
+ ] }),
1636
+ /* @__PURE__ */ jsx(Button, { leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: () => setCreateModalOpen(true), children: "New Project" })
1637
+ ] }),
1638
+ projects && projects.length === 0 ? /* @__PURE__ */ jsx(
1639
+ EmptyState,
1640
+ {
1641
+ icon: IconAdjustments,
1642
+ title: "No projects yet",
1643
+ description: "Create your first calibration project to start comparing AI configurations."
1644
+ }
1645
+ ) : /* @__PURE__ */ jsx(Stack, { children: projects?.map((project) => /* @__PURE__ */ jsx(ProjectCard, { project, onNavigate: onProjectNavigate }, project.id)) }),
1646
+ /* @__PURE__ */ jsx(
1647
+ CreateProjectModal,
1648
+ {
1649
+ opened: createModalOpen,
1650
+ onClose: () => setCreateModalOpen(false),
1651
+ resourceId,
1652
+ resourceType
1653
+ }
1654
+ )
1655
+ ] }) });
1656
+ }
1657
+ function CalibrationProjectDetailPage({
1658
+ projectId,
1659
+ calibrationRootPath,
1660
+ renderRunCard,
1661
+ renderCreateModal,
1662
+ runs,
1663
+ runsLoading
1664
+ }) {
1665
+ const [createModalOpen, setCreateModalOpen] = useState(false);
1666
+ const { organizationReady } = useInitialization();
1667
+ const { data: project, isLoading: projectLoading, error: projectError } = useCalibrationProject(projectId);
1668
+ const projectNotFound = !projectLoading && (projectError || !project);
1669
+ const isLoading = projectLoading || runsLoading;
1670
+ if (!organizationReady || isLoading) return /* @__PURE__ */ jsx(SubshellLoader, {});
1671
+ if (!project || projectNotFound) {
1672
+ return null;
1673
+ }
1674
+ const runCount = runs?.length ?? 0;
1675
+ const caption = `${project.resourceType} \xB7 ${runCount} run${runCount !== 1 ? "s" : ""}`;
1676
+ return /* @__PURE__ */ jsxs(Stack, { children: [
1677
+ /* @__PURE__ */ jsx(
1678
+ PageTitleCaption,
1679
+ {
1680
+ title: project.name,
1681
+ caption,
1682
+ rightSection: /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
1683
+ /* @__PURE__ */ jsx(
1684
+ Button,
1685
+ {
1686
+ variant: "light",
1687
+ size: "sm",
1688
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
1689
+ component: Link,
1690
+ to: calibrationRootPath,
1691
+ children: "Calibration"
1692
+ }
1693
+ ),
1694
+ /* @__PURE__ */ jsx(Button, { leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: () => setCreateModalOpen(true), children: "New Run" })
1695
+ ] })
1696
+ }
1697
+ ),
1698
+ 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 })) }),
1699
+ renderCreateModal({
1700
+ opened: createModalOpen,
1701
+ onClose: () => setCreateModalOpen(false),
1702
+ projectId
1703
+ })
1704
+ ] });
1705
+ }
1706
+ function CalibrationProjectsPage({ onNavigateToProject }) {
1707
+ const { organizationReady } = useInitialization();
1708
+ const { data: projects, isLoading } = useAllCalibrationProjects();
1709
+ if (!organizationReady || isLoading) return /* @__PURE__ */ jsx(SubshellLoader, {});
1710
+ const projectCount = projects?.length ?? 0;
1711
+ const caption = `${projectCount} Project${projectCount !== 1 ? "s" : ""}`;
1712
+ return /* @__PURE__ */ jsxs(Stack, { children: [
1713
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Calibration Lab", caption }),
1714
+ projects && projects.length > 0 && /* @__PURE__ */ jsx(SimpleGrid, { cols: { base: 1, md: 2 }, children: projects.map((project) => /* @__PURE__ */ jsx(ProjectCard, { project, onNavigate: onNavigateToProject }, project.id)) })
1715
+ ] });
1716
+ }
1717
+ function formatRelativeTime2(date) {
1718
+ if (!date) return "N/A";
1719
+ const dateObj = typeof date === "string" ? new Date(date) : date;
1720
+ return formatDistanceToNow(dateObj, { addSuffix: true });
1721
+ }
1722
+ var FILTER_STATE_ICONS2 = {
1723
+ neutral: IconCircleDashed,
1724
+ include: IconCircleCheck,
1725
+ exclude: IconCircleX
1726
+ };
1727
+ var FILTER_STATE_COLORS2 = {
1728
+ neutral: "var(--color-surface-hover)",
1729
+ include: "var(--mantine-color-green-6)",
1730
+ exclude: "var(--mantine-color-red-6)"
1731
+ };
1732
+ var FILTER_STATE_LABELS2 = {
1733
+ neutral: "Not filtered",
1734
+ include: "Include only",
1735
+ exclude: "Exclude"
1736
+ };
1737
+ var EXECUTION_SECTIONS = [
1738
+ { status: "failed", title: "Failed Executions", badgeColor: "red" },
1739
+ { status: "warning", title: "Warning Executions", badgeColor: "yellow" },
1740
+ { status: "completed", title: "Successful Executions", badgeColor: null }
1741
+ ];
1742
+ var HOVER_CARD_STYLE = {
1743
+ cursor: "pointer",
1744
+ transition: "box-shadow var(--duration-fast) var(--easing)",
1745
+ textDecoration: "none",
1746
+ color: "inherit"
1747
+ };
1748
+ function handleHoverEnter(e) {
1749
+ e.currentTarget.style.boxShadow = "var(--standard-box-shadow)";
1750
+ }
1751
+ function handleHoverLeave(e) {
1752
+ e.currentTarget.style.boxShadow = "";
1753
+ }
1754
+ function ExecutionStatusSection({ executions, status, title, badgeColor, resourceUrl }) {
1755
+ const filtered = executions.filter((e) => e.status === status);
1756
+ if (filtered.length === 0) return null;
1757
+ return /* @__PURE__ */ jsxs("div", { children: [
1758
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: 8, children: [
1759
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", children: title }),
1760
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: filtered.length })
1761
+ ] }),
1762
+ /* @__PURE__ */ jsx(Stack, { gap: "xs", children: filtered.map((execution) => /* @__PURE__ */ jsxs(
1763
+ Card,
1764
+ {
1765
+ padding: "xs",
1766
+ withBorder: true,
1767
+ component: "a",
1768
+ href: `${resourceUrl}?exec=${execution.executionId}`,
1769
+ target: "_blank",
1770
+ rel: "noopener noreferrer",
1771
+ style: HOVER_CARD_STYLE,
1772
+ onMouseEnter: handleHoverEnter,
1773
+ onMouseLeave: handleHoverLeave,
1774
+ children: [
1775
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: status === "failed" && execution.errorMessage ? 4 : 0, children: [
1776
+ badgeColor ? /* @__PURE__ */ jsx(Badge, { size: "xs", color: badgeColor, variant: "light", children: status }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "green", children: "\u2713 Completed" }),
1777
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatRelativeTime2(execution.startedAt) })
1778
+ ] }),
1779
+ status === "failed" && execution.errorMessage && /* @__PURE__ */ jsx(Text, { size: "xs", c: "red", lineClamp: 2, children: execution.errorMessage })
1780
+ ]
1781
+ },
1782
+ execution.executionId
1783
+ )) }),
1784
+ /* @__PURE__ */ jsx(Space, { h: "sm" })
1785
+ ] });
1786
+ }
1787
+ function CommandViewSidebarContent({ timeRange }) {
1788
+ const theme = useMantineTheme();
1789
+ const colors = useCyberColors();
1790
+ const statusFilter = useCommandViewStore((s) => s.statusFilter);
1791
+ const setStatusFilter = useCommandViewStore((s) => s.setStatusFilter);
1792
+ const showIntegrations = useCommandViewStore((s) => s.showIntegrations);
1793
+ const setShowIntegrations = useCommandViewStore((s) => s.setShowIntegrations);
1794
+ const fitViewOnFilter = useCommandViewStore((s) => s.fitViewOnFilter);
1795
+ const setFitViewOnFilter = useCommandViewStore((s) => s.setFitViewOnFilter);
1796
+ const selectedNodeId = useCommandViewStore((s) => s.selectedNodeId);
1797
+ const domainFilters = useCommandViewDomainFilters((s) => s.filters);
1798
+ const cycleDomainFilter = useCommandViewDomainFilters((s) => s.cycle);
1799
+ const { data, isLoading } = useCommandViewData();
1800
+ const { data: statsData } = useCommandViewStats(timeRange);
1801
+ const cleanData = data ?? null;
1802
+ const dataWithStats = useMemo(() => {
1803
+ if (!cleanData) return null;
1804
+ if (!statsData) return cleanData;
1805
+ return mergeStatsWithTopology(cleanData, statsData);
1806
+ }, [cleanData, statsData]);
1807
+ const { donutSuccessCount, donutFailedCount } = useMemo(() => {
1808
+ if (!cleanData || !statsData) return { donutSuccessCount: 0, donutFailedCount: 0 };
1809
+ const allResources = [...cleanData.agents, ...cleanData.workflows];
1810
+ const includes = Object.entries(domainFilters).filter(([, v]) => v === "include").map(([k]) => k);
1811
+ const excludes = Object.entries(domainFilters).filter(([, v]) => v === "exclude").map(([k]) => k);
1812
+ const filtered = allResources.filter((r) => {
1813
+ const domains = r.domains || [];
1814
+ if (excludes.length > 0 && domains.some((d) => excludes.includes(d))) return false;
1815
+ if (includes.length > 0 && !domains.some((d) => includes.includes(d))) return false;
1816
+ if (statusFilter !== "all" && r.status !== statusFilter) return false;
1817
+ return true;
1818
+ });
1819
+ const filteredIds = new Set(filtered.map((r) => r.resourceId));
1820
+ let success = 0;
1821
+ let failed = 0;
1822
+ for (const [id, stats] of Object.entries(statsData.resources)) {
1823
+ if (filteredIds.has(id)) {
1824
+ success += stats.successCount;
1825
+ failed += stats.failureCount;
1826
+ }
1827
+ }
1828
+ return { donutSuccessCount: success, donutFailedCount: failed };
1829
+ }, [cleanData, statsData, domainFilters, statusFilter]);
1830
+ const domainDefinitions = cleanData?.domainDefinitions ?? [];
1831
+ const selectedNode = useMemo(() => {
1832
+ if (!selectedNodeId || !dataWithStats) return null;
1833
+ const allNodes = [
1834
+ ...dataWithStats.agents || [],
1835
+ ...dataWithStats.workflows || [],
1836
+ ...dataWithStats.triggers || [],
1837
+ ...dataWithStats.integrations || [],
1838
+ ...dataWithStats.externalResources || [],
1839
+ ...dataWithStats.humanCheckpoints || []
1840
+ ];
1841
+ return allNodes.find((node) => {
1842
+ const nodeId = getNodeId(node);
1843
+ return nodeId === selectedNodeId || node.name === selectedNodeId;
1844
+ }) || null;
1845
+ }, [selectedNodeId, dataWithStats]);
1846
+ const isNavigable = selectedNode?.type === "agent" || selectedNode?.type === "workflow";
1847
+ const isHumanCheckpoint = selectedNode?.type === "human";
1848
+ const selectedResourceId = useMemo(() => {
1849
+ if (!selectedNode) return null;
1850
+ return getNodeId(selectedNode);
1851
+ }, [selectedNode]);
1852
+ const getNavigationUrl = () => {
1853
+ if (!selectedNode || !selectedResourceId) return null;
1854
+ if (selectedNode.type === "agent") return `/operations/resources/agent/${selectedResourceId}`;
1855
+ if (selectedNode.type === "workflow") return `/operations/resources/workflow/${selectedResourceId}`;
1856
+ if (selectedNode.type === "human") return `/command-center/command-queue?checkpoint=${selectedResourceId}`;
1857
+ return null;
1858
+ };
1859
+ const resourceUrl = selectedNode?.type === "agent" ? `/operations/resources/agent/${selectedResourceId}` : `/operations/resources/workflow/${selectedResourceId}`;
1860
+ const {
1861
+ data: executionsData,
1862
+ isLoading: executionsLoading,
1863
+ error: executionsError
1864
+ } = useResourceExecutions({
1865
+ resourceId: selectedResourceId,
1866
+ timeRange,
1867
+ enabled: isNavigable
1868
+ });
1869
+ const {
1870
+ data: checkpointTasksData,
1871
+ isLoading: checkpointTasksLoading,
1872
+ error: checkpointTasksError
1873
+ } = useCheckpointTasks({
1874
+ checkpointId: selectedResourceId,
1875
+ enabled: isHumanCheckpoint
1876
+ });
1877
+ const totalExecutions = donutSuccessCount + donutFailedCount;
1878
+ const successRate = totalExecutions > 0 ? donutSuccessCount / totalExecutions * 100 : 0;
1879
+ const healthSegments = [
1880
+ { name: "Completed", value: donutSuccessCount, color: colors.green },
1881
+ { name: "Failed", value: donutFailedCount, color: colors.red }
1882
+ ];
1883
+ const centerValueColor = totalExecutions === 0 ? "var(--mantine-color-dimmed)" : successRate >= 95 ? colors.green : successRate >= 80 ? colors.yellow : colors.red;
1884
+ if (isLoading && !data) {
1885
+ return /* @__PURE__ */ jsx(Box, { style: { flex: 1, minHeight: 0, padding: theme.spacing.sm }, children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) });
1886
+ }
1887
+ return /* @__PURE__ */ jsxs(
1888
+ Box,
1889
+ {
1890
+ style: {
1891
+ flex: 1,
1892
+ minHeight: 0,
1893
+ display: "flex",
1894
+ flexDirection: "column",
1895
+ overflow: "hidden"
1896
+ },
1897
+ children: [
1898
+ /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconSitemap, label: "Command View" }),
1899
+ /* @__PURE__ */ jsx(Box, { style: { padding: theme.spacing.sm, paddingBottom: 0 }, children: /* @__PURE__ */ jsx(Box, { pb: "xs", mb: 4, children: /* @__PURE__ */ jsx(
1900
+ CyberDonut,
1901
+ {
1902
+ title: `Execution Health (${timeRange})`,
1903
+ segments: healthSegments,
1904
+ centerValue: totalExecutions === 0 ? "\u2014" : `${Math.round(successRate)}%`,
1905
+ centerLabel: `${totalExecutions} runs`,
1906
+ centerValueColor,
1907
+ glowId: "cvHealthGlow",
1908
+ colors
1909
+ }
1910
+ ) }) }),
1911
+ /* @__PURE__ */ jsxs("div", { style: { flex: 1, overflow: "auto" }, children: [
1912
+ /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconAdjustmentsHorizontal, label: "Node Filters", withTopBorder: true }),
1913
+ /* @__PURE__ */ jsxs(Stack, { gap: "sm", p: "sm", children: [
1914
+ /* @__PURE__ */ jsxs("div", { children: [
1915
+ /* @__PURE__ */ jsx(Text, { size: "sm", mb: 8, children: "Environment" }),
1916
+ /* @__PURE__ */ jsx(
1917
+ SegmentedControl,
1918
+ {
1919
+ value: statusFilter,
1920
+ onChange: (value) => setStatusFilter(value),
1921
+ data: [
1922
+ { label: "All", value: "all" },
1923
+ { label: "Prod", value: "prod" },
1924
+ { label: "Dev", value: "dev" }
1925
+ ],
1926
+ size: "xs",
1927
+ fullWidth: true,
1928
+ color: "var(--color-primary)"
1929
+ }
1930
+ )
1931
+ ] }),
1932
+ /* @__PURE__ */ jsx(
1933
+ Switch,
1934
+ {
1935
+ label: "Show Integrations",
1936
+ description: "Toggle integration relationship edges",
1937
+ checked: showIntegrations,
1938
+ onChange: (event) => setShowIntegrations(event.currentTarget.checked),
1939
+ size: "sm"
1940
+ }
1941
+ ),
1942
+ domainDefinitions.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
1943
+ /* @__PURE__ */ jsx(Text, { size: "sm", mb: 8, children: "Domain" }),
1944
+ /* @__PURE__ */ jsx(Stack, { gap: 2, children: [...domainDefinitions].sort((a, b) => {
1945
+ const bottom = /* @__PURE__ */ new Set(["utility", "diagnostic"]);
1946
+ const aB = bottom.has(a.id) ? 1 : 0;
1947
+ const bB = bottom.has(b.id) ? 1 : 0;
1948
+ if (aB !== bB) return aB - bB;
1949
+ return a.name.localeCompare(b.name);
1950
+ }).map((domain) => {
1951
+ const filterState = domainFilters[domain.id] || "neutral";
1952
+ const StateIcon = FILTER_STATE_ICONS2[filterState];
1953
+ return /* @__PURE__ */ jsx(
1954
+ UnstyledButton,
1955
+ {
1956
+ title: FILTER_STATE_LABELS2[filterState],
1957
+ onClick: () => cycleDomainFilter(domain.id),
1958
+ py: 5,
1959
+ px: 6,
1960
+ style: {
1961
+ transition: "background-color var(--duration-fast) var(--easing)",
1962
+ "&:hover": { backgroundColor: "var(--color-surface-hover)" }
1963
+ },
1964
+ children: /* @__PURE__ */ jsxs(Group, { gap: 10, wrap: "nowrap", children: [
1965
+ /* @__PURE__ */ jsx(
1966
+ StateIcon,
1967
+ {
1968
+ size: 16,
1969
+ style: {
1970
+ color: FILTER_STATE_COLORS2[filterState],
1971
+ flexShrink: 0,
1972
+ transition: "color var(--duration-fast) var(--easing)"
1973
+ }
1974
+ }
1975
+ ),
1976
+ /* @__PURE__ */ jsx(
1977
+ Text,
1978
+ {
1979
+ size: "sm",
1980
+ truncate: true,
1981
+ fw: filterState !== "neutral" ? 500 : 400,
1982
+ c: filterState !== "neutral" ? void 0 : "dimmed",
1983
+ children: domain.name
1984
+ }
1985
+ )
1986
+ ] })
1987
+ },
1988
+ domain.id
1989
+ );
1990
+ }) })
1991
+ ] })
1992
+ ] }),
1993
+ /* @__PURE__ */ jsx(SubshellSidebarSection, { icon: IconSettings, label: "Settings", withTopBorder: true }),
1994
+ /* @__PURE__ */ jsx(Stack, { gap: "sm", p: "sm", children: /* @__PURE__ */ jsx(
1995
+ Switch,
1996
+ {
1997
+ label: "Fit view on filter",
1998
+ description: "Re-center graph when filters change",
1999
+ checked: fitViewOnFilter,
2000
+ onChange: (event) => setFitViewOnFilter(event.currentTarget.checked),
2001
+ size: "sm"
2002
+ }
2003
+ ) }),
2004
+ selectedNode && /* @__PURE__ */ jsxs(Fragment, { children: [
2005
+ /* @__PURE__ */ jsx(Divider, {}),
2006
+ /* @__PURE__ */ jsxs(Stack, { gap: "xs", p: "sm", mt: 8, children: [
2007
+ /* @__PURE__ */ jsx(Title, { order: 4, children: selectedNode.name }),
2008
+ selectedNode.description && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: selectedNode.description }),
2009
+ (isNavigable || isHumanCheckpoint) && /* @__PURE__ */ jsxs(
2010
+ Button,
2011
+ {
2012
+ component: "a",
2013
+ href: getNavigationUrl() || "#",
2014
+ target: "_blank",
2015
+ rel: "noopener noreferrer",
2016
+ variant: "light",
2017
+ size: "xs",
2018
+ leftSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 14 }),
2019
+ mt: 4,
2020
+ children: [
2021
+ "Go to",
2022
+ " ",
2023
+ selectedNode.type === "agent" ? "Agent" : selectedNode.type === "workflow" ? "Workflow" : "Queue"
2024
+ ]
2025
+ }
2026
+ ),
2027
+ /* @__PURE__ */ jsx(Space, { h: "sm" })
2028
+ ] })
2029
+ ] }),
2030
+ 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(
2031
+ ExecutionStatusSection,
2032
+ {
2033
+ executions: executionsData.executions,
2034
+ status: section.status,
2035
+ title: section.title,
2036
+ badgeColor: section.badgeColor,
2037
+ resourceUrl
2038
+ },
2039
+ section.status
2040
+ )) : executionsData ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No executions in the selected time range" }) : null }),
2041
+ 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: [
2042
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: 8, children: [
2043
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", fw: 600, tt: "uppercase", children: "Pending Tasks" }),
2044
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: checkpointTasksData.tasks.length })
2045
+ ] }),
2046
+ /* @__PURE__ */ jsx(Stack, { gap: "xs", children: checkpointTasksData.tasks.map((task) => /* @__PURE__ */ jsxs(
2047
+ Card,
2048
+ {
2049
+ padding: "xs",
2050
+ withBorder: true,
2051
+ component: "a",
2052
+ href: `/command-center/command-queue?task=${task.id}`,
2053
+ target: "_blank",
2054
+ rel: "noopener noreferrer",
2055
+ style: HOVER_CARD_STYLE,
2056
+ onMouseEnter: handleHoverEnter,
2057
+ onMouseLeave: handleHoverLeave,
2058
+ children: [
2059
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: task.description ? 4 : 0, children: [
2060
+ /* @__PURE__ */ jsx(Badge, { size: "xs", color: "orange", variant: "light", children: "pending" }),
2061
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatRelativeTime2(task.createdAt) })
2062
+ ] }),
2063
+ task.description && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", lineClamp: 2, children: task.description })
2064
+ ]
2065
+ },
2066
+ task.id
2067
+ )) })
2068
+ ] }) : checkpointTasksData ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No pending tasks" }) : null })
2069
+ ] })
2070
+ ]
2071
+ }
2072
+ );
2073
+ }
2074
+ function useCalibrationRunFull(runId) {
2075
+ const { apiRequest, organizationId, isReady } = useElevasisServices();
2076
+ return useQuery({
2077
+ queryKey: calibrationKeys.runFull(organizationId ?? "none", runId),
2078
+ queryFn: async () => {
2079
+ const response = await apiRequest(`/calibration/runs/${runId}/full`);
2080
+ return response;
2081
+ },
2082
+ enabled: isReady && !!runId && !!organizationId
2083
+ });
2084
+ }
2085
+ function useExecuteRun() {
2086
+ const { apiRequest, organizationId } = useElevasisServices();
2087
+ const queryClient = useQueryClient();
2088
+ return useMutation({
2089
+ mutationFn: async (runId) => {
2090
+ await apiRequest(`/calibration/runs/${runId}/execute`, {
2091
+ method: "POST"
2092
+ });
2093
+ },
2094
+ onSuccess: (_, runId) => {
2095
+ queryClient.invalidateQueries({
2096
+ queryKey: calibrationKeys.run(organizationId ?? "none", runId)
2097
+ });
2098
+ },
2099
+ onError: (error) => {
2100
+ showApiErrorNotification(error);
2101
+ }
2102
+ });
2103
+ }
2104
+ function useGradeRun() {
2105
+ const { apiRequest, organizationId } = useElevasisServices();
2106
+ const queryClient = useQueryClient();
2107
+ return useMutation({
2108
+ mutationFn: async ({
2109
+ runId,
2110
+ rubric,
2111
+ graderModel
2112
+ }) => {
2113
+ await apiRequest(`/calibration/runs/${runId}/grade`, {
2114
+ method: "POST",
2115
+ body: JSON.stringify({ rubric, graderModel })
2116
+ });
2117
+ },
2118
+ onSuccess: (_, { runId }) => {
2119
+ queryClient.invalidateQueries({
2120
+ queryKey: calibrationKeys.run(organizationId ?? "none", runId)
2121
+ });
2122
+ queryClient.invalidateQueries({
2123
+ queryKey: calibrationKeys.runFull(organizationId ?? "none", runId)
2124
+ });
2125
+ },
2126
+ onError: (error) => {
2127
+ showApiErrorNotification(error);
2128
+ }
2129
+ });
2130
+ }
2131
+ function ComparisonTable({ run, logs, metrics }) {
2132
+ if (run.results.length === 0) {
2133
+ 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." }) });
2134
+ }
2135
+ return /* @__PURE__ */ jsx(Stack, { children: run.results.map((result, index) => /* @__PURE__ */ jsx(ResultCard, { result, run, logs, metrics }, index)) });
2136
+ }
2137
+ function ResultCard({ result, run, logs, metrics }) {
2138
+ const [expanded, setExpanded] = useState(false);
2139
+ const isSingleResult = "executionId" in result;
2140
+ const executionId = isSingleResult ? result.executionId : result.sessionId;
2141
+ const inputIndex = isSingleResult ? result.inputIndex : 0;
2142
+ const log = logs[executionId];
2143
+ const metric = metrics[executionId];
2144
+ const statusColors = {
2145
+ pending: "gray",
2146
+ running: "blue",
2147
+ completed: "green",
2148
+ failed: "red"
2149
+ };
2150
+ return /* @__PURE__ */ jsxs(
2151
+ Paper,
2152
+ {
2153
+ withBorder: true,
2154
+ style: {
2155
+ cursor: "pointer",
2156
+ transition: "background-color var(--duration-fast) var(--easing)"
2157
+ },
2158
+ children: [
2159
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", onClick: () => setExpanded(!expanded), children: [
2160
+ /* @__PURE__ */ jsxs(Group, { gap: "md", wrap: "nowrap", children: [
2161
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", children: expanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: 16 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 16 }) }),
2162
+ /* @__PURE__ */ jsxs(Box, { children: [
2163
+ /* @__PURE__ */ jsx(Text, { fw: 600, size: "sm", style: { fontFamily: "var(--mantine-font-family-headings)" }, children: result.variantName }),
2164
+ run.executionMode === "single" && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2165
+ "Input #",
2166
+ inputIndex + 1
2167
+ ] })
2168
+ ] })
2169
+ ] }),
2170
+ /* @__PURE__ */ jsxs(Group, { gap: "md", wrap: "nowrap", children: [
2171
+ metric?.totalDuration && metric.totalDuration > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
2172
+ /* @__PURE__ */ jsx(IconClock, { size: 14, style: { opacity: 0.5 } }),
2173
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
2174
+ (metric.totalDuration / 1e3).toFixed(2),
2175
+ "s"
2176
+ ] })
2177
+ ] }),
2178
+ metric?.totalCost && metric.totalCost > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
2179
+ /* @__PURE__ */ jsx(IconCoin, { size: 14, style: { opacity: 0.5 } }),
2180
+ /* @__PURE__ */ jsxs(Text, { size: "sm", c: "dimmed", children: [
2181
+ "$",
2182
+ metric.totalCost.toFixed(4)
2183
+ ] })
2184
+ ] }),
2185
+ run.gradingRubric && result.grade && /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
2186
+ result.grade.passed ? /* @__PURE__ */ jsx(IconCheck, { size: 14, color: "var(--color-success)" }) : /* @__PURE__ */ jsx(IconX, { size: 14, color: "var(--color-error)" }),
2187
+ /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
2188
+ (result.grade.score * 100).toFixed(0),
2189
+ "%"
2190
+ ] })
2191
+ ] }),
2192
+ /* @__PURE__ */ jsx(Badge, { color: statusColors[result.status], size: "sm", children: result.status })
2193
+ ] })
2194
+ ] }),
2195
+ /* @__PURE__ */ jsx(Collapse, { in: expanded, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", mt: "md", pt: "md", style: { borderTop: "1px solid var(--color-border)" }, children: [
2196
+ run.testInputs[inputIndex] !== void 0 && /* @__PURE__ */ jsxs(Box, { children: [
2197
+ /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "dimmed", mb: "xs", children: "INPUT" }),
2198
+ /* @__PURE__ */ jsx(Paper, { style: { background: "var(--color-background)" }, children: /* @__PURE__ */ jsx(JsonViewer, { data: run.testInputs[inputIndex], maxHeight: "200px" }) })
2199
+ ] }),
2200
+ /* @__PURE__ */ jsxs(Box, { children: [
2201
+ /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "dimmed", mb: "xs", children: "OUTPUT" }),
2202
+ /* @__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" }) })
2203
+ ] }),
2204
+ log?.error && /* @__PURE__ */ jsxs(Box, { children: [
2205
+ /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "red", mb: "xs", children: "ERROR" }),
2206
+ /* @__PURE__ */ jsxs(Paper, { style: { background: "var(--color-background)" }, children: [
2207
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", children: log.error.message }),
2208
+ log.error.category && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", mt: "xs", children: [
2209
+ "Category: ",
2210
+ log.error.category
2211
+ ] })
2212
+ ] })
2213
+ ] }),
2214
+ result.grade && /* @__PURE__ */ jsxs(Box, { children: [
2215
+ /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "dimmed", mb: "xs", children: "GRADE DETAILS" }),
2216
+ /* @__PURE__ */ jsx(Paper, { style: { background: "var(--color-background)" }, children: /* @__PURE__ */ jsx(Stack, { gap: "xs", children: Object.entries(result.grade.details).map(([criterion, detail]) => {
2217
+ const d = detail;
2218
+ return /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
2219
+ /* @__PURE__ */ jsx(Text, { size: "sm", children: criterion }),
2220
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
2221
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", color: d.score >= 0.7 ? "green" : d.score >= 0.4 ? "yellow" : "red", children: [
2222
+ (d.score * 100).toFixed(0),
2223
+ "%"
2224
+ ] }),
2225
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", style: { maxWidth: 300 }, lineClamp: 1, children: d.justification })
2226
+ ] })
2227
+ ] }, criterion);
2228
+ }) }) })
2229
+ ] }),
2230
+ result.gradeError && /* @__PURE__ */ jsxs(Box, { children: [
2231
+ /* @__PURE__ */ jsx(Text, { size: "xs", fw: 500, c: "red", mb: "xs", children: "GRADING ERROR" }),
2232
+ /* @__PURE__ */ jsx(Paper, { style: { background: "var(--color-background)" }, children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "red", children: result.gradeError }) })
2233
+ ] })
2234
+ ] }) })
2235
+ ]
2236
+ }
2237
+ );
2238
+ }
2239
+ function GradingPanel({ run, rubric }) {
2240
+ const variantSummaries = run.configVariants.map((variant) => {
2241
+ const variantResults = run.results.filter((r) => r.variantName === variant.variantName);
2242
+ const gradedResults = variantResults.filter((r) => r.grade);
2243
+ const avgScore = gradedResults.length > 0 ? gradedResults.reduce((sum, r) => sum + (r.grade?.score ?? 0), 0) / gradedResults.length : null;
2244
+ const passRate = gradedResults.length > 0 ? gradedResults.filter((r) => r.grade?.passed).length / gradedResults.length : null;
2245
+ return {
2246
+ variantName: variant.variantName,
2247
+ avgScore,
2248
+ passRate,
2249
+ total: variantResults.length,
2250
+ graded: gradedResults.length
2251
+ };
2252
+ });
2253
+ return /* @__PURE__ */ jsxs(Stack, { gap: "lg", children: [
2254
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
2255
+ /* @__PURE__ */ jsx(Title, { order: 4, mb: "md", children: "Grading Rubric" }),
2256
+ /* @__PURE__ */ jsxs(Text, { size: "sm", mb: "md", children: [
2257
+ "Passing threshold: ",
2258
+ (rubric.passingThreshold * 100).toFixed(0),
2259
+ "%"
2260
+ ] }),
2261
+ /* @__PURE__ */ jsxs(Table, { children: [
2262
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
2263
+ /* @__PURE__ */ jsx(Table.Th, { children: "Criterion" }),
2264
+ /* @__PURE__ */ jsx(Table.Th, { children: "Weight" }),
2265
+ /* @__PURE__ */ jsx(Table.Th, { children: "Description" })
2266
+ ] }) }),
2267
+ /* @__PURE__ */ jsx(Table.Tbody, { children: rubric.criteria.map((criterion, i) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
2268
+ /* @__PURE__ */ jsx(Table.Td, { fw: 500, children: criterion.name }),
2269
+ /* @__PURE__ */ jsxs(Table.Td, { children: [
2270
+ (criterion.weight * 100).toFixed(0),
2271
+ "%"
2272
+ ] }),
2273
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: criterion.description }) })
2274
+ ] }, i)) })
2275
+ ] })
2276
+ ] }),
2277
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
2278
+ /* @__PURE__ */ jsx(Title, { order: 4, mb: "md", children: "Results by Variant" }),
2279
+ /* @__PURE__ */ jsx(Stack, { gap: "md", children: variantSummaries.map((summary, i) => /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
2280
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: "xs", children: [
2281
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: summary.variantName }),
2282
+ summary.avgScore !== null && /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
2283
+ /* @__PURE__ */ jsx(
2284
+ ThemeIcon,
2285
+ {
2286
+ size: "sm",
2287
+ color: summary.avgScore >= rubric.passingThreshold ? "green" : "red",
2288
+ variant: "light",
2289
+ children: summary.avgScore >= rubric.passingThreshold ? /* @__PURE__ */ jsx(IconCheck, { size: 14 }) : /* @__PURE__ */ jsx(IconX, { size: 14 })
2290
+ }
2291
+ ),
2292
+ /* @__PURE__ */ jsxs(Text, { fw: 500, children: [
2293
+ (summary.avgScore * 100).toFixed(0),
2294
+ "%"
2295
+ ] })
2296
+ ] })
2297
+ ] }),
2298
+ summary.avgScore !== null ? /* @__PURE__ */ jsxs(Fragment, { children: [
2299
+ /* @__PURE__ */ jsx(
2300
+ Progress,
2301
+ {
2302
+ value: summary.avgScore * 100,
2303
+ color: summary.avgScore >= rubric.passingThreshold ? "green" : "red",
2304
+ size: "sm",
2305
+ mb: "xs"
2306
+ }
2307
+ ),
2308
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2309
+ "Pass rate: ",
2310
+ summary.passRate !== null ? `${(summary.passRate * 100).toFixed(0)}%` : "-",
2311
+ " \xB7",
2312
+ " ",
2313
+ summary.graded,
2314
+ "/",
2315
+ summary.total,
2316
+ " graded"
2317
+ ] })
2318
+ ] }) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Not graded yet" })
2319
+ ] }, i)) })
2320
+ ] })
2321
+ ] });
2322
+ }
2323
+ var STATUS_COLORS = {
2324
+ pending: "gray",
2325
+ running: "blue",
2326
+ completed: "green",
2327
+ partial: "yellow",
2328
+ failed: "red"
2329
+ };
2330
+ function CalibrationRunDetailPage({
2331
+ runId,
2332
+ onNavigateToProject,
2333
+ renderSessionComparison,
2334
+ renderProgressPanel
2335
+ }) {
2336
+ const { organizationReady } = useInitialization();
2337
+ const { data: fullData, isLoading, error, refetch } = useCalibrationRunFull(runId);
2338
+ const executeRun = useExecuteRun();
2339
+ const gradeRun = useGradeRun();
2340
+ const [inputsExpanded, setInputsExpanded] = useState(false);
2341
+ if (!organizationReady || isLoading) return /* @__PURE__ */ jsx(SubshellLoader, {});
2342
+ if (!fullData || error) {
2343
+ return null;
2344
+ }
2345
+ const { run, logs, metrics } = fullData;
2346
+ const handleExecute = async () => {
2347
+ await executeRun.mutateAsync(runId);
2348
+ refetch();
2349
+ };
2350
+ const handleGrade = async () => {
2351
+ await gradeRun.mutateAsync({
2352
+ runId,
2353
+ rubric: run.gradingRubric ?? void 0,
2354
+ graderModel: run.graderModel ?? void 0
2355
+ });
2356
+ refetch();
2357
+ };
2358
+ const completedCount = run.results.filter((r) => r.status === "completed").length;
2359
+ const failedCount = run.results.filter((r) => r.status === "failed").length;
2360
+ const totalDuration = Object.values(metrics).reduce((sum, m) => {
2361
+ const metric = m;
2362
+ return sum + (metric.totalDuration || 0);
2363
+ }, 0);
2364
+ const totalCost = Object.values(metrics).reduce((sum, m) => {
2365
+ const metric = m;
2366
+ return sum + (metric.totalCost || 0);
2367
+ }, 0);
2368
+ const caption = `${run.configVariants.length} variants \xB7 ${run.testInputs.length} inputs`;
2369
+ return /* @__PURE__ */ jsxs(Stack, { children: [
2370
+ /* @__PURE__ */ jsx(
2371
+ PageTitleCaption,
2372
+ {
2373
+ title: run.name,
2374
+ caption,
2375
+ rightSection: /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
2376
+ /* @__PURE__ */ jsx(
2377
+ Button,
2378
+ {
2379
+ variant: "light",
2380
+ size: "sm",
2381
+ leftSection: /* @__PURE__ */ jsx(IconArrowLeft, { size: 16 }),
2382
+ onClick: () => onNavigateToProject(run.projectId),
2383
+ children: "Project"
2384
+ }
2385
+ ),
2386
+ /* @__PURE__ */ jsx(Badge, { color: STATUS_COLORS[run.status], children: run.status }),
2387
+ /* @__PURE__ */ jsx(Badge, { variant: "outline", children: run.executionMode }),
2388
+ run.status === "pending" && /* @__PURE__ */ jsx(Button, { leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 }), onClick: handleExecute, loading: executeRun.isPending, children: "Execute" }),
2389
+ run.status === "completed" && run.gradingRubric && /* @__PURE__ */ jsx(
2390
+ Button,
2391
+ {
2392
+ leftSection: /* @__PURE__ */ jsx(IconReportAnalytics, { size: 16 }),
2393
+ variant: "outline",
2394
+ onClick: handleGrade,
2395
+ loading: gradeRun.isPending,
2396
+ children: "Re-Grade"
2397
+ }
2398
+ )
2399
+ ] })
2400
+ }
2401
+ ),
2402
+ /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
2403
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "wrap", gap: "sm", children: [
2404
+ run.results.length > 0 && /* @__PURE__ */ jsxs(Group, { gap: "md", children: [
2405
+ /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
2406
+ /* @__PURE__ */ jsx(IconCheck, { size: 14, color: "var(--color-success)" }),
2407
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, c: "green", children: completedCount }),
2408
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "completed" })
2409
+ ] }),
2410
+ failedCount > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
2411
+ /* @__PURE__ */ jsx(IconX, { size: 14, color: "var(--color-error)" }),
2412
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, c: "red", children: failedCount }),
2413
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "failed" })
2414
+ ] }),
2415
+ totalDuration > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
2416
+ /* @__PURE__ */ jsx(IconClock, { size: 14, style: { opacity: 0.5 } }),
2417
+ /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
2418
+ (totalDuration / 1e3).toFixed(1),
2419
+ "s"
2420
+ ] })
2421
+ ] }),
2422
+ totalCost > 0 && /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
2423
+ /* @__PURE__ */ jsx(IconCoin, { size: 14, style: { opacity: 0.5 } }),
2424
+ /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
2425
+ "$",
2426
+ totalCost.toFixed(4)
2427
+ ] })
2428
+ ] })
2429
+ ] }),
2430
+ /* @__PURE__ */ jsxs(Group, { gap: "md", children: [
2431
+ run.createdAt && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2432
+ "Created: ",
2433
+ new Date(run.createdAt).toLocaleString()
2434
+ ] }),
2435
+ run.completedAt && /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2436
+ "Completed: ",
2437
+ new Date(run.completedAt).toLocaleString()
2438
+ ] })
2439
+ ] })
2440
+ ] }),
2441
+ run.description && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", mt: "xs", children: run.description }),
2442
+ /* @__PURE__ */ jsxs(Box, { mt: "sm", pt: "sm", style: { borderTop: "1px solid var(--color-border)" }, children: [
2443
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", style: { cursor: "pointer" }, onClick: () => setInputsExpanded(!inputsExpanded), children: [
2444
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", children: inputsExpanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: 16 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 16 }) }),
2445
+ /* @__PURE__ */ jsxs(Text, { fw: 500, size: "sm", children: [
2446
+ "Test Inputs (",
2447
+ run.testInputs.length,
2448
+ ")"
2449
+ ] })
2450
+ ] }),
2451
+ /* @__PURE__ */ jsx(Collapse, { in: inputsExpanded, children: /* @__PURE__ */ jsx(Stack, { mt: "sm", children: run.testInputs.map((input, index) => /* @__PURE__ */ jsxs(Box, { children: [
2452
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", mb: "xs", children: [
2453
+ "Input #",
2454
+ index + 1
2455
+ ] }),
2456
+ /* @__PURE__ */ jsx(Paper, { style: { background: "var(--color-background)" }, children: /* @__PURE__ */ jsx(JsonViewer, { data: input, maxHeight: "150px" }) })
2457
+ ] }, index)) }) })
2458
+ ] })
2459
+ ] }),
2460
+ run.status === "running" && renderProgressPanel?.({ runId }),
2461
+ /* @__PURE__ */ jsxs(Tabs, { defaultValue: "comparison", children: [
2462
+ /* @__PURE__ */ jsxs(Tabs.List, { children: [
2463
+ /* @__PURE__ */ jsx(Tabs.Tab, { value: "comparison", children: "Results" }),
2464
+ run.gradingRubric && /* @__PURE__ */ jsx(Tabs.Tab, { value: "grading", children: "Grading" })
2465
+ ] }),
2466
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "comparison", pt: "sm", children: run.executionMode === "session" ? renderSessionComparison?.({ run }) : /* @__PURE__ */ jsx(ComparisonTable, { run, logs, metrics }) }),
2467
+ run.gradingRubric && /* @__PURE__ */ jsx(Tabs.Panel, { value: "grading", pt: "sm", children: /* @__PURE__ */ jsx(GradingPanel, { run, rubric: run.gradingRubric }) })
2468
+ ] })
2469
+ ] });
2470
+ }
2471
+ function WorkflowExecutionPanel({
2472
+ resourceId,
2473
+ resourceDefinition,
2474
+ sseManager,
2475
+ apiUrl,
2476
+ onConnectionStatus
2477
+ }) {
2478
+ const theme = useMantineTheme();
2479
+ const { executions, isLoading, selectedId, setSelectedId, streamingLogs } = useExecutionPanelState({
2480
+ resourceId,
2481
+ manager: sseManager,
2482
+ apiUrl,
2483
+ limit: PAGE_SIZE_DEFAULT,
2484
+ onConnectionStatus
2485
+ });
2486
+ const [selectedStepId, setSelectedStepId] = useState(null);
2487
+ const isValidSelection = selectedId && executions.some((e) => e.id === selectedId);
2488
+ const { data: selectedExecution } = useExecution(resourceId, isValidSelection ? selectedId : "");
2489
+ const executionStreamingLogs = selectedId ? streamingLogs.get(selectedId) : void 0;
2490
+ const mergedExecution = useMergedExecution(selectedExecution, executionStreamingLogs);
2491
+ const timelineData = useTimelineData(mergedExecution, resourceDefinition);
2492
+ const isRemoteStub = resourceDefinition.steps.length === 1 && resourceDefinition.steps[0]?.id === "_remote";
2493
+ useEffect(() => {
2494
+ setSelectedStepId(null);
2495
+ }, [selectedId]);
2496
+ if (isLoading) {
2497
+ return /* @__PURE__ */ jsx(Center, { h: "100%", children: /* @__PURE__ */ jsx(Loader, { size: "md" }) });
2498
+ }
2499
+ return /* @__PURE__ */ jsxs(Stack, { gap: "0", style: { height: "100%", overflow: "hidden" }, children: [
2500
+ 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: [
2501
+ /* @__PURE__ */ jsx(
2502
+ UnifiedWorkflowGraph,
2503
+ {
2504
+ resourceDefinition,
2505
+ executionLogs: mergedExecution?.executionLogs,
2506
+ selectedStepId,
2507
+ onStepSelect: setSelectedStepId
2508
+ }
2509
+ ),
2510
+ timelineData && /* @__PURE__ */ jsx(WorkflowExecutionTimeline, { timelineData, selectedStepId })
2511
+ ] }),
2512
+ /* @__PURE__ */ jsx(
2513
+ "div",
2514
+ {
2515
+ style: {
2516
+ flex: 1,
2517
+ overflow: "hidden",
2518
+ padding: theme.spacing.sm
2519
+ },
2520
+ children: /* @__PURE__ */ jsx(
2521
+ WorkflowExecutionLogs,
2522
+ {
2523
+ resourceId,
2524
+ executionId: selectedId,
2525
+ execution: mergedExecution,
2526
+ selectedStepId,
2527
+ timelineData,
2528
+ onExecutionDeleted: () => setSelectedId(void 0)
2529
+ }
2530
+ )
2531
+ }
2532
+ )
2533
+ ] });
2534
+ }
2535
+ function AgentExecutionPanel({
2536
+ resourceId,
2537
+ resourceDefinition,
2538
+ sseManager,
2539
+ apiUrl,
2540
+ onConnectionStatus
2541
+ }) {
2542
+ const theme = useMantineTheme();
2543
+ const { isLoading, selectedId, setSelectedId, liveExecutions, streamingLogs } = useExecutionPanelState({
2544
+ resourceId,
2545
+ manager: sseManager,
2546
+ apiUrl,
2547
+ limit: PAGE_SIZE_DEFAULT,
2548
+ onConnectionStatus
2549
+ });
2550
+ const [selectedIterationId, setSelectedIterationId] = useState(null);
2551
+ const { data: selectedExecution } = useExecution(resourceId, selectedId || "");
2552
+ const executionStreamingLogs = selectedId ? streamingLogs.get(selectedId) : void 0;
2553
+ const mergedExecution = useMergedExecution(selectedExecution, executionStreamingLogs);
2554
+ const iterationData = useAgentIterationData(mergedExecution, resourceDefinition);
2555
+ if (isLoading) {
2556
+ return /* @__PURE__ */ jsx(Center, { h: "100%", p: "lg", children: /* @__PURE__ */ jsx(Loader, { size: "md" }) });
2557
+ }
2558
+ return /* @__PURE__ */ jsxs(Stack, { gap: "0", style: { height: "100%", overflow: "hidden" }, children: [
2559
+ /* @__PURE__ */ jsx(
2560
+ AgentExecutionVisualizer,
2561
+ {
2562
+ resourceDefinition,
2563
+ iterationData,
2564
+ selectedExecutionId: selectedId,
2565
+ liveExecutions,
2566
+ selectedIterationId,
2567
+ onIterationSelect: setSelectedIterationId
2568
+ }
2569
+ ),
2570
+ iterationData && /* @__PURE__ */ jsx(AgentExecutionTimeline, { iterationData, selectedIterationId }),
2571
+ /* @__PURE__ */ jsx(
2572
+ "div",
2573
+ {
2574
+ style: {
2575
+ flex: 1,
2576
+ overflow: "hidden",
2577
+ padding: theme.spacing.sm
2578
+ },
2579
+ children: /* @__PURE__ */ jsx(
2580
+ AgentExecutionLogs,
2581
+ {
2582
+ resourceId,
2583
+ executionId: selectedId,
2584
+ execution: mergedExecution,
2585
+ selectedIterationId,
2586
+ iterationData,
2587
+ onExecutionDeleted: () => setSelectedId(void 0)
2588
+ }
2589
+ )
2590
+ }
2591
+ )
2592
+ ] });
2593
+ }
2594
+ function ResourceDefinitionError({
2595
+ resourceId,
2596
+ resourceType,
2597
+ resourceName
2598
+ }) {
2599
+ const handleRefresh = () => {
2600
+ window.location.reload();
2601
+ };
2602
+ 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: [
2603
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
2604
+ "Failed to load resource definition for ",
2605
+ resourceType,
2606
+ ' "',
2607
+ resourceName || resourceId,
2608
+ '". This may indicate a data loading issue or an incompatible resource format.'
2609
+ ] }),
2610
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
2611
+ "Resource ID: ",
2612
+ resourceId,
2613
+ /* @__PURE__ */ jsx("br", {}),
2614
+ "Resource Type: ",
2615
+ resourceType
2616
+ ] }),
2617
+ /* @__PURE__ */ jsx(Button, { variant: "light", size: "xs", leftSection: /* @__PURE__ */ jsx(IconRefresh, { size: 14 }), onClick: handleRefresh, mt: "xs", children: "Refresh Page" })
2618
+ ] }) }) });
2619
+ }
2620
+ function isWorkflowDefinition(structure) {
2621
+ return structure.config.type === "workflow";
2622
+ }
2623
+ function isAgentDefinition(structure) {
2624
+ return structure.config.type === "agent";
2625
+ }
2626
+ function ExecutionPanel({
2627
+ resourceId,
2628
+ resourceType,
2629
+ resourceName,
2630
+ resourceDefinition,
2631
+ sseManager,
2632
+ apiUrl,
2633
+ onConnectionStatus
2634
+ }) {
2635
+ const diProps = { resourceId, resourceName, sseManager, apiUrl, onConnectionStatus };
2636
+ switch (resourceType) {
2637
+ case "workflow":
2638
+ return isWorkflowDefinition(resourceDefinition) ? /* @__PURE__ */ jsx(WorkflowExecutionPanel, { ...diProps, resourceDefinition }) : /* @__PURE__ */ jsx(ResourceDefinitionError, { resourceId, resourceType, resourceName });
2639
+ case "agent":
2640
+ return isAgentDefinition(resourceDefinition) ? /* @__PURE__ */ jsx(AgentExecutionPanel, { ...diProps, resourceDefinition }) : /* @__PURE__ */ jsx(ResourceDefinitionError, { resourceId, resourceType, resourceName });
2641
+ default:
2642
+ return isWorkflowDefinition(resourceDefinition) ? /* @__PURE__ */ jsx(WorkflowExecutionPanel, { ...diProps, resourceDefinition }) : /* @__PURE__ */ jsx(ResourceDefinitionError, { resourceId, resourceType, resourceName });
2643
+ }
2644
+ }
525
2645
 
526
- export { ResourcesPage, ResourcesSidebar };
2646
+ export { AgentExecutionPanel, CalibrationPage, CalibrationProjectDetailPage, CalibrationProjectsPage, CalibrationRunDetailPage, CommandQueueDetailPage, CommandQueuePage, CommandViewPage, CommandViewSidebarContent, ExecutionPanel, ResourceDetailPage, ResourcesPage, ResourcesSidebar, WorkflowExecutionPanel };