@elevasis/ui 2.67.0 → 2.69.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/dist/api/index.d.ts +1 -1
  2. package/dist/api/index.js +3 -3
  3. package/dist/app/index.d.ts +575 -370
  4. package/dist/app/index.js +17 -23
  5. package/dist/auth/index.css +149 -149
  6. package/dist/auth/index.d.ts +5 -0
  7. package/dist/auth/index.js +11 -13
  8. package/dist/charts/index.css +208 -208
  9. package/dist/charts/index.js +11 -13
  10. package/dist/{chunk-M535KHLW.js → chunk-26BTE3Z4.js} +1 -1
  11. package/dist/chunk-3KMDHCAR.js +52 -0
  12. package/dist/chunk-3MEXPLWT.js +265 -0
  13. package/dist/chunk-4JHLS234.js +39 -0
  14. package/dist/chunk-6PZFOHJK.js +1764 -0
  15. package/dist/chunk-7WJEPTE7.js +194 -0
  16. package/dist/chunk-AH52XQB7.js +1 -0
  17. package/dist/{chunk-UFTM5SZZ.js → chunk-AKANHRQ5.js} +9 -3
  18. package/dist/chunk-BZZCNLT6.js +12 -0
  19. package/dist/chunk-C75XWBYZ.js +383 -0
  20. package/dist/chunk-DLR4SDZW.js +51 -0
  21. package/dist/{chunk-4OEVLV66.js → chunk-FLECOYUS.js} +113 -148
  22. package/dist/chunk-IRV6KJPV.js +425 -0
  23. package/dist/chunk-IT7GTJCB.js +10 -0
  24. package/dist/chunk-LGKLC5MG.js +44 -0
  25. package/dist/chunk-MFLM7BVC.js +85 -0
  26. package/dist/chunk-MRVGQLWN.js +1595 -0
  27. package/dist/{chunk-4DV4ECMG.js → chunk-N7U24M2J.js} +4 -0
  28. package/dist/{chunk-I7BZVVVU.js → chunk-NM4A63KJ.js} +104 -415
  29. package/dist/chunk-NU3NBXHP.js +1194 -0
  30. package/dist/chunk-PDHTXPSF.js +12 -0
  31. package/dist/chunk-RW64UJWT.js +1934 -0
  32. package/dist/{chunk-JFBZ6XDW.js → chunk-SNZDFCOQ.js} +3 -49
  33. package/dist/chunk-TUMSNGTX.js +35 -0
  34. package/dist/chunk-UD657ICS.js +589 -0
  35. package/dist/{chunk-XNW3O6QW.js → chunk-VDX6DL7Z.js} +1 -1
  36. package/dist/chunk-WXHAHKKI.js +16411 -0
  37. package/dist/chunk-XAZR3T6Y.js +2162 -0
  38. package/dist/chunk-XQ3ILKYN.js +37 -0
  39. package/dist/chunk-YCRINA2D.js +67 -0
  40. package/dist/chunk-YGCMMOY4.js +1484 -0
  41. package/dist/chunk-YNRYIXUT.js +10945 -0
  42. package/dist/chunk-ZD6LM53O.js +4528 -0
  43. package/dist/chunk-ZPTEGGKU.js +631 -0
  44. package/dist/components/chat/index.js +2 -1
  45. package/dist/components/index.css +208 -208
  46. package/dist/components/index.d.ts +1634 -264
  47. package/dist/components/index.js +2774 -14
  48. package/dist/components/navigation/index.css +149 -149
  49. package/dist/components/navigation/index.js +12 -13
  50. package/dist/features/auth/index.css +149 -149
  51. package/dist/features/auth/index.d.ts +457 -167
  52. package/dist/features/auth/index.js +13 -14
  53. package/dist/features/clients/index.css +208 -208
  54. package/dist/features/clients/index.d.ts +39 -1
  55. package/dist/features/clients/index.js +16 -13
  56. package/dist/features/content/index.d.ts +1788 -0
  57. package/dist/features/content/index.js +2180 -0
  58. package/dist/features/crm/index.d.ts +1802 -231
  59. package/dist/features/crm/index.js +16 -13
  60. package/dist/features/dashboard/index.d.ts +1 -8
  61. package/dist/features/dashboard/index.js +17 -13
  62. package/dist/features/delivery/index.d.ts +457 -167
  63. package/dist/features/delivery/index.js +16 -13
  64. package/dist/features/knowledge/index.css +149 -149
  65. package/dist/features/knowledge/index.js +11 -13
  66. package/dist/features/lead-gen/index.d.ts +53 -104
  67. package/dist/features/lead-gen/index.js +17 -13
  68. package/dist/features/monitoring/index.js +16 -13
  69. package/dist/features/monitoring/requests/index.js +15 -20
  70. package/dist/features/operations/index.d.ts +1 -86
  71. package/dist/features/operations/index.js +22 -12
  72. package/dist/features/public-agent-chat/index.js +2 -1
  73. package/dist/features/seo/index.js +2 -1
  74. package/dist/features/settings/index.d.ts +457 -167
  75. package/dist/features/settings/index.js +15 -13
  76. package/dist/hooks/access/index.css +149 -149
  77. package/dist/hooks/access/index.d.ts +5 -0
  78. package/dist/hooks/access/index.js +11 -13
  79. package/dist/hooks/delivery/index.d.ts +457 -167
  80. package/dist/hooks/delivery/index.js +2 -23
  81. package/dist/hooks/index.d.ts +2203 -244
  82. package/dist/hooks/index.js +11 -13
  83. package/dist/hooks/operations/command-view/utils/transformCommandViewData.d.ts +1 -8
  84. package/dist/hooks/published.d.ts +2203 -244
  85. package/dist/hooks/published.js +11 -13
  86. package/dist/initialization/index.d.ts +465 -169
  87. package/dist/knowledge/index.css +149 -149
  88. package/dist/knowledge/index.d.ts +5 -90
  89. package/dist/knowledge/index.js +3215 -3203
  90. package/dist/{knowledge-search-index-6EZNBNSR.js → knowledge-search-index-LP2WVSQX.js} +689 -695
  91. package/dist/layout/index.css +149 -149
  92. package/dist/layout/index.js +15 -13
  93. package/dist/organization/index.d.ts +10 -4
  94. package/dist/organization/index.js +1 -21
  95. package/dist/profile/index.d.ts +457 -167
  96. package/dist/provider/index.d.ts +576 -372
  97. package/dist/provider/index.js +11 -13
  98. package/dist/provider/published.css +149 -149
  99. package/dist/provider/published.d.ts +576 -372
  100. package/dist/provider/published.js +11 -13
  101. package/dist/supabase/index.d.ts +906 -347
  102. package/dist/test-utils/index.d.ts +15 -2
  103. package/dist/test-utils/index.js +41 -12
  104. package/dist/test-utils/setup-integration.js +1 -1
  105. package/dist/test-utils/setup.js +1 -1
  106. package/dist/theme/index.js +3 -2
  107. package/dist/theme/presets/index.js +1 -1
  108. package/dist/typeform/index.js +2049 -1
  109. package/dist/types/index.d.ts +477 -177
  110. package/dist/utils/index.d.ts +1 -8
  111. package/dist/utils/index.js +1 -1
  112. package/dist/vite/index.js +2 -2
  113. package/dist/vite-plugin-knowledge/index.js +1 -1
  114. package/package.json +7 -3
  115. package/src/features/README.md +28 -28
  116. package/dist/chunk-5TERYXOO.js +0 -51390
  117. package/dist/chunk-AUDNF2Q7.js +0 -2050
  118. package/dist/index.d.ts +0 -17888
  119. package/dist/index.js +0 -30
  120. package/dist/{chunk-GMXGDO3I.js → chunk-MISHPEJX.js} +1 -1
  121. package/dist/{chunk-RBGVNPA6.js → chunk-XQBURFKM.js} +0 -0
  122. package/dist/{index.css → features/content/index.css} +149 -149
@@ -1,29 +1,2789 @@
1
- export { APIErrorAlert, AbsoluteScheduleForm, ActionModal, ActivityCard, ActivityFeedWidget, ActivityFilters as ActivityFiltersBar, ActivityTable, ActivityTimeline, AgentDefinitionDisplay, AgentExecutionLogs, AgentExecutionTimeline, AgentExecutionVisualizer, AgentIterationDetailPanel, AgentIterationEdge, AgentIterationNode, AllTasksPage, ApiKeyDisplayModal, ApiKeyList, ApiKeySettings, AppErrorBoundary, BaseEdge, BaseExecutionLogs, BaseExecutionLogsHeader, BaseExecutionLogsStates, BaseNode, Breadcrumbs, BusinessImpactCard, CenteredErrorState, CheckpointGroup, CollapsibleJsonSection, CollapsibleSection, CommandQueueSidebar, CommandQueueSidebarMiddle, CommandQueueSidebarTop, CommandQueueTaskRow, CompanyDetailPage, ConfigCard, ConfirmationInputModal, ConfirmationModal, ContactDetailPage, ContentSections, ContextUsageBadge, ContextViewer, ContractDisplay, CostBreakdownCard, CostByModelTable, CostMetricsCard, CrashErrorFallback, CreateApiKeyModal, CreateCredentialModal, CreateRoleModal, CreateScheduleModal, CredentialList, CredentialSettings, CrmOverview, CrmSidebar, CrmSidebarMiddle, CrmSidebarTop, CustomModal, CustomSelector, DEAL_STAGES, DEFAULT_KANBAN_CONFIG, DealDetailPage, DealKanbanCard, DealsListPage, DeleteScheduleModal, DeploymentDetailModal, DeploymentList, DeploymentSettings, DeploymentStatusBadge, DetailCardSkeleton, EditApiKeyModal, ElevasisLoader, EmptyState, EmptyVisualizer, ErrorAnalysisCard, ErrorBreakdownTable, ErrorReportCard, ExecutionBreakdownTable, ExecutionErrorSection, ExecutionHealthCard, ExecutionLogsFilters as ExecutionLogsFilterBar, ExecutionLogsTable, ExecutionStats, ExecutionStatusBadge, FeatureUnavailableState, FilterBar, GlowDot, GraphBackground, GraphContainer, GraphFitViewButton, GraphFitViewHandler, GraphLegend, HealthStatusCard, JsonViewer, KanbanBoard, LEAD_GEN_ROUTE_LINKS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarMiddle, LeadGenSidebarTop, ListSkeleton, LogEntry, LogGroup, MdxRenderer, MembershipStatusBadge, MetricsStrip, MilestoneTimeline, MyTasksPanel, NavigationButton, NoAccessState, NotificationBell, NotificationItem, NotificationList, NotificationPanel, OAuthConnectModal, OperationsSidebar, OperationsSidebarMiddle, OperationsSidebarTop, OrganizationMembershipsList, PIPELINE_FUNNEL_ORDER, PageNotFound, PageTitleCaption, PermissionMatrix, PipelineFunnelWidget, ProjectDetailPage, ProjectsListPage, ProjectsSidebar, ProjectsSidebarMiddle, ProjectsSidebarTop, ProvisioningStateBadge, QuickCreateActions, RecurringScheduleForm, RelativeScheduleForm, ResourceCard, ResourceDefinitionSection, ResourceErrorState, ResourceFilter, ResourceHeader, ResourceHealthChart, ResourceHealthPanel, ResourceNotFoundState, RichTextEditor, RoleBadge, RunResourceButton, SAVED_VIEW_PRESETS, SavedViewsPanel, ScheduleCard, ScheduleDetailModal, ScheduleTypeSelector, SessionMemory, SortableHeader, StatCard, StatCardSkeleton, StatsCardSkeleton, StatusBadge, StepConfigForm, TabCountBadge, TabSection, TableSelectionToolbar, TaskCard, TaskScheduler, TimeRangeSelector, TimelineAxis, TimelineBar, TimelineContainer, TimelineRow, ToolsListDisplay, TrendIndicator, UnifiedWorkflowEdge, UnifiedWorkflowGraph, UnifiedWorkflowNode, UpcomingMilestonesPage, VisualizerContainer, WebhookUrlDisplayModal, WorkflowDefinitionDisplay, WorkflowExecutionLogs, WorkflowExecutionTimeline, ZodFormRenderer, buildErrorReport, calculateProgress, crmManifest, deliveryManifest, formatStatusLabel, getEnrichmentColor, getExecutionStatusConfig, getGraphBackgroundStyles, getHealthColor, getIcon, getLogLevelConfig, getStatusColor, iconMap, leadGenManifest, mdxComponents, milestoneStatusColors, monitoringManifest, noteTypeColors, operationsManifest, projectStatusColors, settingsManifest, showApiErrorNotification, showAuthError, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification, taskStatusColors, taskTypeColors, useCrmPipelineSummary, useCrmQuickMetrics, useDeleteLists, useGraphBackgroundStyles, useGraphTheme, useRecentCrmActivity } from '../chunk-5TERYXOO.js';
2
- import '../chunk-4OEVLV66.js';
3
- import '../chunk-RBGVNPA6.js';
1
+ export { AppErrorBoundary, CrashErrorFallback, ErrorReportCard, buildErrorReport } from '../chunk-IRV6KJPV.js';
2
+ import { useBreadcrumbs } from '../chunk-MFLM7BVC.js';
3
+ import '../chunk-AH52XQB7.js';
4
+ import { showAuthError } from '../chunk-XAZR3T6Y.js';
5
+ export { CreateCredentialModal, CredentialList, CredentialSettings, MembershipStatusBadge, OAuthConnectModal, OrganizationMembershipsList, ProvisioningStateBadge, WebhookUrlDisplayModal, showAuthError } from '../chunk-XAZR3T6Y.js';
6
+ import '../chunk-4JHLS234.js';
7
+ import '../chunk-NU3NBXHP.js';
8
+ import { setDealReferrer, compareDealsByPriority } from '../chunk-RW64UJWT.js';
9
+ export { ActivityFeedWidget, CompanyDetailPage, ContactDetailPage, CrmOverview, CrmSidebar, CrmSidebarTop, DealDetailPage, DealsListPage, MetricsStrip, PIPELINE_FUNNEL_ORDER, PipelineFunnelWidget, useCrmPipelineSummary, useCrmQuickMetrics, useRecentCrmActivity } from '../chunk-RW64UJWT.js';
10
+ export { AllTasksPage, HealthStatusCard, MilestoneTimeline, ProjectDetailPage, ProjectsListPage, ProjectsSidebar, ProjectsSidebarMiddle, ProjectsSidebarTop, TaskCard, UpcomingMilestonesPage } from '../chunk-MRVGQLWN.js';
11
+ export { LEAD_GEN_ROUTE_LINKS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarTop, StepConfigForm, TabSection, getEnrichmentColor, getStatusColor, useDeleteLists } from '../chunk-ZD6LM53O.js';
12
+ import '../chunk-7WJEPTE7.js';
13
+ export { ActionModal, AgentDefinitionDisplay, AgentExecutionLogs, BaseExecutionLogs, BaseExecutionLogsHeader, BaseExecutionLogsStates, CommandQueueTaskRow, ConfigCard, ContentSections, ContextUsageBadge, ContractDisplay, ExecutionErrorSection, LogEntry, LogGroup, ResourceDefinitionSection, ResourceErrorState, ResourceFilter, ResourceHeader, ResourceNotFoundState, SessionMemory, ToolsListDisplay, WorkflowDefinitionDisplay, WorkflowExecutionLogs, getExecutionStatusConfig, getIcon, getLogLevelConfig, iconMap } from '../chunk-YNRYIXUT.js';
4
14
  import '../chunk-6ZAP3FOA.js';
5
- import '../chunk-AUDNF2Q7.js';
6
- import '../chunk-6M6OLGQY.js';
15
+ import '../chunk-IT7GTJCB.js';
16
+ import '../chunk-ZPTEGGKU.js';
17
+ import '../chunk-SNZDFCOQ.js';
18
+ import { NotificationList } from '../chunk-6PZFOHJK.js';
19
+ export { ActivityCard, ActivityFilters as ActivityFiltersBar, ActivityTable, BusinessImpactCard, CostBreakdownCard, CostByModelTable, CostMetricsCard, ErrorAnalysisCard, ErrorBreakdownTable, ExecutionBreakdownTable, ExecutionHealthCard, ExecutionLogsFilters as ExecutionLogsFilterBar, ExecutionLogsTable, NotificationItem, NotificationList } from '../chunk-6PZFOHJK.js';
20
+ export { ResourceHealthPanel } from '../chunk-YCRINA2D.js';
21
+ export { ResourceHealthChart, getHealthColor } from '../chunk-LGKLC5MG.js';
22
+ import { AppShellLoader } from '../chunk-XQ3ILKYN.js';
23
+ export { calculateProgress, formatStatusLabel, milestoneStatusColors, noteTypeColors, projectStatusColors, taskStatusColors, taskTypeColors } from '../chunk-DLR4SDZW.js';
24
+ export { AgentExecutionTimeline, AgentExecutionVisualizer, AgentIterationDetailPanel, AgentIterationEdge, AgentIterationNode, BaseEdge, BaseNode, CollapsibleJsonSection, EmptyVisualizer, ExecutionStats, ExecutionStatusBadge, GraphBackground, GraphContainer, GraphFitViewButton, GraphFitViewHandler, GraphLegend, RunResourceButton, TimelineAxis, TimelineBar, TimelineContainer, TimelineRow, UnifiedWorkflowEdge, UnifiedWorkflowGraph, UnifiedWorkflowNode, VisualizerContainer, WorkflowExecutionTimeline, getGraphBackgroundStyles, useGraphBackgroundStyles, useGraphTheme } from '../chunk-YGCMMOY4.js';
25
+ export { ZodFormRenderer } from '../chunk-3MEXPLWT.js';
26
+ export { Graph_module_css_default as graphStyles } from '../chunk-HENXLGVD.js';
27
+ import '../chunk-BZZCNLT6.js';
28
+ export { SortableHeader, TableSelectionToolbar } from '../chunk-TUMSNGTX.js';
29
+ import { FilterBar } from '../chunk-PDHTXPSF.js';
30
+ export { FilterBar } from '../chunk-PDHTXPSF.js';
31
+ import { useCreateOrgRole, usePermissionCatalog, CustomModal, useMarkAllAsRead, useNotifications, useUpdateApiKey, useDeleteApiKey, ListSkeleton, EmptyState, useCreateApiKey, useListApiKeys, PageTitleCaption, StatCard, usePaginationState, useActivateDeployment, useDeactivateDeployment, useDeleteDeployment, useListDeployments, useResources, useCreateSchedule, useListSchedules, usePauseSchedule, useResumeSchedule, useCancelSchedule, useDeleteSchedule, CenteredErrorState, useDeals, useTransitionItem, dealKeys, SubshellContentContainer } from '../chunk-WXHAHKKI.js';
32
+ export { APIErrorAlert, ActivityTimeline, CenteredErrorState, CheckpointGroup, CollapsibleSection, CommandQueueSidebar, CommandQueueSidebarMiddle, CommandQueueSidebarTop, ConfirmationInputModal, ConfirmationModal, ContextViewer, CrmSidebarMiddle, CustomModal, CustomSelector, DetailCardSkeleton, ElevasisLoader, EmptyState, FeatureUnavailableState, GlowDot, JsonViewer, LeadGenSidebarMiddle, ListSkeleton, MyTasksPanel, NavigationButton, OperationsSidebar, OperationsSidebarMiddle, OperationsSidebarTop, OrganizationModelDriftActionIcon, PageNotFound, PageTitleCaption, QuickCreateActions, ResourceCard, SAVED_VIEW_PRESETS, SavedViewsPanel, StatCard, StatCardSkeleton, StatsCardSkeleton, StatusBadge, TabCountBadge, TimeRangeSelector, TrendIndicator, crmManifest, deliveryManifest, leadGenManifest, monitoringManifest, operationsManifest, settingsManifest } from '../chunk-WXHAHKKI.js';
33
+ import '../chunk-FLECOYUS.js';
34
+ import '../chunk-XQBURFKM.js';
7
35
  import '../chunk-MKH2KOAO.js';
8
- import '../chunk-XNW3O6QW.js';
36
+ import '../chunk-VDX6DL7Z.js';
9
37
  import '../chunk-L7BZZ4SI.js';
10
- export { SEOSidebar, SEOSidebarMiddle, SEOSidebarTop, seoManifest } from '../chunk-GMXGDO3I.js';
38
+ import { showSuccessNotification, showErrorNotification, showApiErrorNotification } from '../chunk-C75XWBYZ.js';
39
+ export { showApiErrorNotification, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification } from '../chunk-C75XWBYZ.js';
40
+ export { SEOSidebar, SEOSidebarMiddle, SEOSidebarTop, seoManifest } from '../chunk-MISHPEJX.js';
41
+ import { CardHeader } from '../chunk-62GVNH5U.js';
11
42
  export { CardHeader } from '../chunk-62GVNH5U.js';
12
- import '../chunk-P45GQ3ZW.js';
13
- import '../chunk-DD3CCMCZ.js';
43
+ import { useInitialization } from '../chunk-P45GQ3ZW.js';
14
44
  import '../chunk-M7WWRZ5Z.js';
15
- export { StyledMarkdown } from '../chunk-JFBZ6XDW.js';
45
+ export { StyledMarkdown } from '../chunk-3KMDHCAR.js';
16
46
  import '../chunk-2IFYDILW.js';
17
- import '../chunk-Q7DJKLEN.js';
18
- export { Graph_module_css_default as graphStyles } from '../chunk-HENXLGVD.js';
19
47
  export { CONTAINER_CONSTANTS, SHARED_VIZ_CONSTANTS } from '../chunk-BLXJEIQS.js';
48
+ export { RoleBadge } from '../chunk-UD657ICS.js';
49
+ import '../chunk-DD3CCMCZ.js';
20
50
  import '../chunk-RNP5R5I3.js';
21
51
  import '../chunk-RT4KRGZT.js';
22
- import '../chunk-I7BZVVVU.js';
52
+ import { formatDateTime, PAGE_SIZE_DEFAULT, formatTimeAgo } from '../chunk-NM4A63KJ.js';
23
53
  import '../chunk-Y6I3IC45.js';
24
54
  import '../chunk-6SSQGWK7.js';
25
- import '../chunk-BI5VDO2K.js';
55
+ import { useElevasisServices } from '../chunk-BI5VDO2K.js';
26
56
  import '../chunk-MQZE7SUI.js';
27
57
  import '../chunk-TVTSASST.js';
28
58
  import '../chunk-BRJ3QZ4E.js';
59
+ import { useRouterContext } from '../chunk-Q7DJKLEN.js';
29
60
  import '../chunk-I2KLQ2HA.js';
61
+ import { Stack, Card, Title, Checkbox, Group, Text, Tooltip, Center, TextInput, Textarea, Loader, Alert, Button, Box, Divider, ScrollArea, Popover, Indicator, ActionIcon, Table, Paper, Code, CopyButton, SimpleGrid, Badge, Pagination, SegmentedControl, Switch, Select, Menu, Timeline, ThemeIcon, Tabs, Breadcrumbs as Breadcrumbs$1 } from '@mantine/core';
62
+ import { IconLock, IconBell, IconPencil, IconAlertCircle, IconKey, IconCalendar, IconClock, IconTrash, IconAlertTriangle, IconExclamationMark, IconShieldLock, IconCheck, IconCopy, IconPlus, IconRocket, IconRefresh, IconPower, IconPlayerPlay, IconCircleCheck, IconTag, IconCalendarRepeat, IconCalendarEvent, IconCalendarTime, IconRobot, IconGitBranch, IconSettings, IconExternalLink, IconDotsVertical, IconPlayerPause, IconPlayerStop, IconCalendarDue, IconCalendarStats, IconCalendarOff, IconListCheck } from '@tabler/icons-react';
63
+ import * as runtime from 'react/jsx-runtime';
64
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
65
+ import { useForm } from '@mantine/form';
66
+ import { useRef, useEffect, useState, useMemo, useCallback } from 'react';
67
+ import { z } from 'zod';
68
+ import { useDisclosure } from '@mantine/hooks';
69
+ import { useQuery, useQueryClient } from '@tanstack/react-query';
70
+ import { Link, RichTextEditor as RichTextEditor$1 } from '@mantine/tiptap';
71
+ import { useEditor } from '@tiptap/react';
72
+ import Placeholder from '@tiptap/extension-placeholder';
73
+ import StarterKit from '@tiptap/starter-kit';
74
+ import { Prism } from 'react-syntax-highlighter';
75
+ import { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';
76
+ import { useNavigate } from '@tanstack/react-router';
77
+
78
+ function groupByDomain(catalog) {
79
+ const groups = /* @__PURE__ */ new Map();
80
+ for (const row of catalog) {
81
+ const domain = row.key.split(".")[0] ?? row.key;
82
+ const existing = groups.get(domain);
83
+ if (existing) {
84
+ existing.push(row);
85
+ } else {
86
+ groups.set(domain, [row]);
87
+ }
88
+ }
89
+ return groups;
90
+ }
91
+ var DOMAIN_LABELS = {
92
+ org: "Organization",
93
+ members: "Members",
94
+ roles: "Roles",
95
+ secrets: "Secrets",
96
+ operations: "Operations",
97
+ work: "Work"
98
+ };
99
+ function domainLabel(domain) {
100
+ return DOMAIN_LABELS[domain] ?? domain.charAt(0).toUpperCase() + domain.slice(1);
101
+ }
102
+ function PermissionMatrix({ catalog, selectedKeys, onChange, systemLocked }) {
103
+ const groups = groupByDomain(catalog);
104
+ const isDisplayOnly = !onChange || systemLocked;
105
+ function handleToggle(key, checked) {
106
+ if (!onChange || systemLocked) return;
107
+ if (checked) {
108
+ onChange([...selectedKeys, key]);
109
+ } else {
110
+ onChange(selectedKeys.filter((k) => k !== key));
111
+ }
112
+ }
113
+ return /* @__PURE__ */ jsx(Stack, { gap: "md", children: Array.from(groups.entries()).map(([domain, rows]) => /* @__PURE__ */ jsxs(Card, { withBorder: true, padding: "md", children: [
114
+ /* @__PURE__ */ jsx(Title, { order: 5, mb: "sm", style: { textTransform: "capitalize" }, children: domainLabel(domain) }),
115
+ /* @__PURE__ */ jsx(Stack, { gap: "xs", children: rows.map((row) => {
116
+ const isLocked = !row.isOrgGrantable;
117
+ const isChecked = selectedKeys.includes(row.key);
118
+ const isDisabled = isDisplayOnly || isLocked;
119
+ const checkbox = /* @__PURE__ */ jsx(
120
+ Checkbox,
121
+ {
122
+ checked: isChecked,
123
+ disabled: isDisabled,
124
+ onChange: (e) => handleToggle(row.key, e.currentTarget.checked),
125
+ label: /* @__PURE__ */ jsxs(Group, { gap: 6, wrap: "nowrap", children: [
126
+ /* @__PURE__ */ jsx(Text, { size: "sm", ff: "monospace", c: isLocked ? "var(--color-text-subtle)" : void 0, children: row.key }),
127
+ isLocked && /* @__PURE__ */ jsx(IconLock, { size: 14, style: { color: "var(--color-text-subtle)", flexShrink: 0 } }),
128
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: row.description })
129
+ ] })
130
+ },
131
+ row.key
132
+ );
133
+ if (isLocked) {
134
+ return /* @__PURE__ */ jsx(Tooltip, { label: "Reserved for built-in roles", position: "right", children: /* @__PURE__ */ jsx("div", { children: checkbox }) }, row.key);
135
+ }
136
+ return checkbox;
137
+ }) })
138
+ ] }, domain)) });
139
+ }
140
+ function NoAccessState() {
141
+ return /* @__PURE__ */ jsx(Center, { style: { flex: 1, minHeight: "100%", width: "100%", padding: 24 }, children: /* @__PURE__ */ jsxs(Stack, { align: "center", gap: "xs", style: { maxWidth: 480, textAlign: "center" }, children: [
142
+ /* @__PURE__ */ jsx(IconLock, { size: 44, stroke: 1.8, color: "var(--color-text-subtle)" }),
143
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Access restricted" }),
144
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "You don't have permission to view this page. Contact an org admin if you need access." })
145
+ ] }) });
146
+ }
147
+ var CreateRoleFormSchema = z.object({
148
+ name: z.string().trim().min(2).max(50),
149
+ slug: z.string().regex(/^[a-z0-9-]+$/, "lowercase, numbers, dashes only").min(2).max(50),
150
+ description: z.string().max(200).optional(),
151
+ permissionKeys: z.array(z.string())
152
+ });
153
+ function toSlug(name) {
154
+ return name.toLowerCase().replace(/\s+/g, "-");
155
+ }
156
+ var nameSchema = CreateRoleFormSchema.shape.name;
157
+ var slugSchema = CreateRoleFormSchema.shape.slug;
158
+ var descriptionSchema = z.string().max(200);
159
+ function extractError(result) {
160
+ return result.error.issues[0]?.message ?? "Invalid value";
161
+ }
162
+ function CreateRoleModal({ opened, onClose, onCreated }) {
163
+ const createMutation = useCreateOrgRole();
164
+ const catalog = usePermissionCatalog();
165
+ const slugDirtyRef = useRef(false);
166
+ const form = useForm({
167
+ initialValues: {
168
+ name: "",
169
+ slug: "",
170
+ description: "",
171
+ permissionKeys: []
172
+ },
173
+ validate: {
174
+ name: (value) => {
175
+ const r = nameSchema.safeParse(value);
176
+ return r.success ? null : extractError(r);
177
+ },
178
+ slug: (value) => {
179
+ const r = slugSchema.safeParse(value);
180
+ return r.success ? null : extractError(r);
181
+ },
182
+ description: (value) => {
183
+ if (!value) return null;
184
+ const r = descriptionSchema.safeParse(value);
185
+ return r.success ? null : extractError(r);
186
+ },
187
+ permissionKeys: () => null
188
+ }
189
+ });
190
+ useEffect(() => {
191
+ if (!slugDirtyRef.current) {
192
+ form.setFieldValue("slug", toSlug(form.values.name));
193
+ }
194
+ }, [form.values.name]);
195
+ const handleSlugChange = (e) => {
196
+ slugDirtyRef.current = true;
197
+ form.setFieldValue("slug", e.currentTarget.value);
198
+ };
199
+ const handleClose = () => {
200
+ if (!createMutation.isPending) {
201
+ form.reset();
202
+ slugDirtyRef.current = false;
203
+ onClose();
204
+ }
205
+ };
206
+ const onSubmit = form.onSubmit(async (values) => {
207
+ try {
208
+ const role = await createMutation.mutateAsync({
209
+ name: values.name,
210
+ slug: values.slug,
211
+ description: values.description || void 0,
212
+ permissionKeys: values.permissionKeys
213
+ });
214
+ showSuccessNotification(`Role "${role.name}" created.`);
215
+ onCreated?.(role.id);
216
+ handleClose();
217
+ } catch (err) {
218
+ showAuthError(err);
219
+ }
220
+ });
221
+ const grantableCatalog = (catalog.data?.permissions ?? []).filter((p) => p.isOrgGrantable);
222
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose: handleClose, size: "lg", loading: createMutation.isPending, children: /* @__PURE__ */ jsx("form", { onSubmit, children: /* @__PURE__ */ jsxs(Stack, { p: "md", gap: "md", children: [
223
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Create custom role" }),
224
+ /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
225
+ /* @__PURE__ */ jsx(
226
+ TextInput,
227
+ {
228
+ label: "Display name",
229
+ placeholder: "e.g. Content Editor",
230
+ required: true,
231
+ disabled: createMutation.isPending,
232
+ ...form.getInputProps("name")
233
+ }
234
+ ),
235
+ /* @__PURE__ */ jsx(
236
+ TextInput,
237
+ {
238
+ label: "Slug",
239
+ placeholder: "e.g. content-editor",
240
+ description: "Lowercase letters, numbers, and dashes only",
241
+ required: true,
242
+ disabled: createMutation.isPending,
243
+ ...form.getInputProps("slug"),
244
+ onChange: handleSlugChange
245
+ }
246
+ ),
247
+ /* @__PURE__ */ jsx(
248
+ Textarea,
249
+ {
250
+ label: "Description",
251
+ placeholder: "Optional description",
252
+ minRows: 2,
253
+ disabled: createMutation.isPending,
254
+ ...form.getInputProps("description")
255
+ }
256
+ )
257
+ ] }),
258
+ /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
259
+ /* @__PURE__ */ jsx(Title, { order: 5, children: "Permissions" }),
260
+ catalog.isLoading && /* @__PURE__ */ jsx(Loader, { size: "sm" }),
261
+ catalog.isError && /* @__PURE__ */ jsx(Alert, { color: "red", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: "Failed to load permission catalog. Please close and try again." }) }),
262
+ !catalog.isLoading && !catalog.isError && /* @__PURE__ */ jsx(
263
+ PermissionMatrix,
264
+ {
265
+ catalog: grantableCatalog,
266
+ selectedKeys: form.values.permissionKeys,
267
+ onChange: (keys) => form.setFieldValue("permissionKeys", keys)
268
+ }
269
+ )
270
+ ] }),
271
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", mt: "md", children: [
272
+ /* @__PURE__ */ jsx(Button, { variant: "default", onClick: handleClose, disabled: createMutation.isPending, children: "Cancel" }),
273
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: createMutation.isPending, children: "Create role" })
274
+ ] })
275
+ ] }) }) });
276
+ }
277
+ function NotificationPanel({ notifications, isLoading, onClose, onNavigate }) {
278
+ const markAllAsRead = useMarkAllAsRead();
279
+ const hasUnread = notifications.some((n) => !n.read);
280
+ const handleMarkAllAsRead = async () => {
281
+ await markAllAsRead.mutateAsync();
282
+ };
283
+ return /* @__PURE__ */ jsxs(Box, { children: [
284
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", p: "md", pb: "sm", children: [
285
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, style: { fontFamily: "var(--mantine-font-family-headings)" }, children: "Notifications" }),
286
+ hasUnread && /* @__PURE__ */ jsx(Button, { variant: "subtle", size: "xs", onClick: handleMarkAllAsRead, loading: markAllAsRead.isPending, children: "Mark all as read" })
287
+ ] }),
288
+ /* @__PURE__ */ jsx(Divider, {}),
289
+ /* @__PURE__ */ jsx(ScrollArea, { h: 400, type: "auto", children: /* @__PURE__ */ jsx(
290
+ NotificationList,
291
+ {
292
+ notifications,
293
+ isLoading,
294
+ onClose,
295
+ onNavigate
296
+ }
297
+ ) })
298
+ ] });
299
+ }
300
+ function NotificationBell({ unreadCount, onNavigate }) {
301
+ const [opened, { toggle, close }] = useDisclosure(false);
302
+ const { apiRequest, isReady, workOSOrganizationId } = useElevasisServices();
303
+ const { data: apiCount = 0 } = useQuery({
304
+ queryKey: ["notifications", "unread-count", workOSOrganizationId],
305
+ queryFn: async () => {
306
+ const response = await apiRequest("/notifications/unread-count");
307
+ return response.count;
308
+ },
309
+ enabled: isReady,
310
+ staleTime: 3e4
311
+ });
312
+ const { data, isLoading } = useNotifications({ limit: 20 });
313
+ const notifications = data?.notifications ?? [];
314
+ const count = unreadCount ?? apiCount;
315
+ return /* @__PURE__ */ jsxs(Popover, { opened, onChange: toggle, position: "bottom-end", width: 400, children: [
316
+ /* @__PURE__ */ jsx(Tooltip, { label: "Notifications", disabled: opened, children: /* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(Indicator, { label: count > 99 ? "99+" : count, disabled: count === 0, size: 16, offset: 4, children: /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "lg", onClick: toggle, children: /* @__PURE__ */ jsx(IconBell, { size: 20, color: "var(--color-text-subtle)" }) }) }) }) }),
317
+ /* @__PURE__ */ jsx(Popover.Dropdown, { p: 0, children: /* @__PURE__ */ jsx(
318
+ NotificationPanel,
319
+ {
320
+ notifications,
321
+ isLoading,
322
+ onClose: close,
323
+ onNavigate
324
+ }
325
+ ) })
326
+ ] });
327
+ }
328
+ function EditApiKeyModal({ apiKey, onClose }) {
329
+ const [name, setName] = useState("");
330
+ const [nameError, setNameError] = useState(null);
331
+ const updateMutation = useUpdateApiKey();
332
+ useEffect(() => {
333
+ if (apiKey) {
334
+ setName(apiKey.name);
335
+ setNameError(null);
336
+ }
337
+ }, [apiKey]);
338
+ if (!apiKey) return null;
339
+ const trimmedName = name.trim();
340
+ const hasChanged = trimmedName !== apiKey.name;
341
+ const isValid = trimmedName.length >= 2 && trimmedName.length <= 100;
342
+ const handleClose = () => {
343
+ if (!updateMutation.isPending) {
344
+ onClose();
345
+ }
346
+ };
347
+ const handleNameChange = (value) => {
348
+ setName(value);
349
+ if (nameError) setNameError(null);
350
+ };
351
+ const handleSave = async () => {
352
+ if (trimmedName.length < 2) {
353
+ setNameError("Name must be at least 2 characters");
354
+ return;
355
+ }
356
+ if (trimmedName.length > 100) {
357
+ setNameError("Name must be 100 characters or less");
358
+ return;
359
+ }
360
+ setNameError(null);
361
+ try {
362
+ await updateMutation.mutateAsync({ keyId: apiKey.id, name: trimmedName });
363
+ onClose();
364
+ } catch {
365
+ }
366
+ };
367
+ return /* @__PURE__ */ jsx(CustomModal, { opened: true, onClose: handleClose, size: "md", loading: updateMutation.isPending, children: /* @__PURE__ */ jsxs(Stack, { children: [
368
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
369
+ /* @__PURE__ */ jsx(IconPencil, { size: 24 }),
370
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Edit API Key" })
371
+ ] }),
372
+ /* @__PURE__ */ jsx(
373
+ TextInput,
374
+ {
375
+ label: "Name",
376
+ value: name,
377
+ onChange: (e) => handleNameChange(e.target.value),
378
+ disabled: updateMutation.isPending,
379
+ maxLength: 100,
380
+ error: nameError
381
+ }
382
+ ),
383
+ updateMutation.error && /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, { size: 16 }), color: "red", title: "Update Failed", children: "Failed to rename API key" }),
384
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "sm", children: [
385
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, disabled: updateMutation.isPending, children: "Cancel" }),
386
+ /* @__PURE__ */ jsx(Button, { onClick: handleSave, loading: updateMutation.isPending, disabled: !hasChanged || !isValid, children: "Save" })
387
+ ] })
388
+ ] }) });
389
+ }
390
+ function ApiKeyList({ keys, isLoading }) {
391
+ const [deleteKey, setDeleteKey] = useState(null);
392
+ const [editKey, setEditKey] = useState(null);
393
+ const deleteMutation = useDeleteApiKey();
394
+ const handleDelete = () => {
395
+ if (deleteKey) {
396
+ deleteMutation.mutate(deleteKey.id);
397
+ setDeleteKey(null);
398
+ }
399
+ };
400
+ const handleCloseDelete = () => {
401
+ if (!deleteMutation.isPending) {
402
+ setDeleteKey(null);
403
+ }
404
+ };
405
+ if (isLoading) {
406
+ return /* @__PURE__ */ jsx(ListSkeleton, { rows: 3, rowHeight: 50 });
407
+ }
408
+ if (keys.length === 0) {
409
+ return /* @__PURE__ */ jsx(
410
+ EmptyState,
411
+ {
412
+ icon: IconKey,
413
+ title: "No API keys yet",
414
+ description: "Create your first API key to enable external integrations"
415
+ }
416
+ );
417
+ }
418
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
419
+ /* @__PURE__ */ jsxs(Table, { children: [
420
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
421
+ /* @__PURE__ */ jsx(Table.Th, { children: "Name" }),
422
+ /* @__PURE__ */ jsx(Table.Th, { children: "Created" }),
423
+ /* @__PURE__ */ jsx(Table.Th, { children: "Last Used" }),
424
+ /* @__PURE__ */ jsx(Table.Th, { w: 80 })
425
+ ] }) }),
426
+ /* @__PURE__ */ jsx(Table.Tbody, { children: keys.map((key) => /* @__PURE__ */ jsxs(Table.Tr, { children: [
427
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
428
+ /* @__PURE__ */ jsx(IconKey, { size: 16, style: { opacity: 0.6 } }),
429
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: key.name })
430
+ ] }) }),
431
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
432
+ /* @__PURE__ */ jsx(IconCalendar, { size: 14, style: { opacity: 0.5 } }),
433
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDateTime(key.created_at) })
434
+ ] }) }),
435
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
436
+ /* @__PURE__ */ jsx(IconClock, { size: 14, style: { opacity: 0.5 } }),
437
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDateTime(key.last_used_at) })
438
+ ] }) }),
439
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "flex-end", children: [
440
+ /* @__PURE__ */ jsx(Tooltip, { label: "Edit API key", children: /* @__PURE__ */ jsx(
441
+ ActionIcon,
442
+ {
443
+ variant: "subtle",
444
+ color: "gray",
445
+ onClick: () => setEditKey(key),
446
+ disabled: deleteMutation.isPending,
447
+ children: /* @__PURE__ */ jsx(IconPencil, { size: 16 })
448
+ }
449
+ ) }),
450
+ /* @__PURE__ */ jsx(Tooltip, { label: "Delete API key", position: "left", children: /* @__PURE__ */ jsx(
451
+ ActionIcon,
452
+ {
453
+ variant: "subtle",
454
+ color: "red",
455
+ onClick: () => setDeleteKey(key),
456
+ disabled: deleteMutation.isPending,
457
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 16 })
458
+ }
459
+ ) })
460
+ ] }) })
461
+ ] }, key.id)) })
462
+ ] }),
463
+ /* @__PURE__ */ jsx(CustomModal, { opened: !!deleteKey, onClose: handleCloseDelete, size: "md", loading: deleteMutation.isPending, children: /* @__PURE__ */ jsxs(Stack, { children: [
464
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
465
+ /* @__PURE__ */ jsx(IconAlertTriangle, { size: 24, color: "var(--color-error)" }),
466
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Delete API Key" })
467
+ ] }),
468
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
469
+ "Are you sure you want to delete",
470
+ " ",
471
+ /* @__PURE__ */ jsxs(Text, { span: true, fw: 600, children: [
472
+ '"',
473
+ deleteKey?.name,
474
+ '"'
475
+ ] }),
476
+ "?"
477
+ ] }),
478
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This action cannot be undone. Any integrations using this API key will stop working immediately." }),
479
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "sm", children: [
480
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleCloseDelete, disabled: deleteMutation.isPending, children: "Cancel" }),
481
+ /* @__PURE__ */ jsx(
482
+ Button,
483
+ {
484
+ color: "red",
485
+ onClick: handleDelete,
486
+ loading: deleteMutation.isPending,
487
+ leftSection: /* @__PURE__ */ jsx(IconTrash, { size: 16 }),
488
+ children: "Delete API Key"
489
+ }
490
+ )
491
+ ] })
492
+ ] }) }),
493
+ /* @__PURE__ */ jsx(EditApiKeyModal, { apiKey: editKey, onClose: () => setEditKey(null) })
494
+ ] });
495
+ }
496
+ function CreateApiKeyModal({ opened, onClose, onSuccess }) {
497
+ const createApiKey = useCreateApiKey();
498
+ const form = useForm({
499
+ initialValues: {
500
+ name: ""
501
+ },
502
+ validate: {
503
+ name: (value) => {
504
+ if (!value.trim()) return "API key name is required";
505
+ if (value.trim().length < 2) return "Name must be at least 2 characters";
506
+ if (value.trim().length > 100) return "Name must be less than 100 characters";
507
+ return null;
508
+ }
509
+ }
510
+ });
511
+ const handleSubmit = async (values) => {
512
+ const data = {
513
+ name: values.name.trim()
514
+ };
515
+ try {
516
+ const result = await createApiKey.mutateAsync(data);
517
+ form.reset();
518
+ onSuccess(result);
519
+ } catch (error) {
520
+ console.error("Failed to create API key:", error);
521
+ }
522
+ };
523
+ const handleClose = () => {
524
+ if (!createApiKey.isPending) {
525
+ form.reset();
526
+ onClose();
527
+ }
528
+ };
529
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose: handleClose, size: "md", loading: createApiKey.isPending, children: /* @__PURE__ */ jsx("form", { onSubmit: form.onSubmit(handleSubmit), children: /* @__PURE__ */ jsxs(Stack, { children: [
530
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Create New API Key" }),
531
+ /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconExclamationMark, { size: 16 }), color: "blue", children: "API keys allow external services to execute production workflows in your organization. Keep them secure and never share them publicly." }),
532
+ /* @__PURE__ */ jsx(
533
+ TextInput,
534
+ {
535
+ label: "Key Name",
536
+ description: "A descriptive name to identify this key",
537
+ placeholder: "e.g., Zapier Integration, GitHub Actions",
538
+ leftSection: /* @__PURE__ */ jsx(IconKey, { size: 16 }),
539
+ required: true,
540
+ ...form.getInputProps("name"),
541
+ disabled: createApiKey.isPending
542
+ }
543
+ ),
544
+ createApiKey.error && /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconExclamationMark, { size: 16 }), color: "red", children: createApiKey.error instanceof Error ? createApiKey.error.message : "An error occurred while creating the API key" }),
545
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", gap: "sm", children: [
546
+ /* @__PURE__ */ jsx(Button, { variant: "subtle", onClick: handleClose, disabled: createApiKey.isPending, children: "Cancel" }),
547
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: createApiKey.isPending, leftSection: /* @__PURE__ */ jsx(IconKey, { size: 16 }), children: "Create API Key" })
548
+ ] })
549
+ ] }) }) });
550
+ }
551
+ function ApiKeyDisplayModal({ opened, apiKey, onClose }) {
552
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose, size: "lg", loading: false, children: /* @__PURE__ */ jsxs(Stack, { children: [
553
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
554
+ /* @__PURE__ */ jsx(IconShieldLock, { size: 24, color: "var(--color-success)" }),
555
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "API Key Created Successfully" })
556
+ ] }),
557
+ /* @__PURE__ */ jsxs(Alert, { icon: /* @__PURE__ */ jsx(IconAlertCircle, {}), color: "red", variant: "light", children: [
558
+ /* @__PURE__ */ jsx(Text, { fw: 600, size: "sm", style: { fontFamily: "var(--mantine-font-family-headings)" }, children: "Save this key immediately!" }),
559
+ /* @__PURE__ */ jsx(Text, { size: "sm", mt: 4, children: "This is the only time you will see this key. It cannot be retrieved again. Store it securely in your application's environment variables or secret management system." })
560
+ ] }),
561
+ /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
562
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Your new API Key:" }),
563
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
564
+ /* @__PURE__ */ jsx(IconKey, { size: 16, style: { opacity: 0.6, flexShrink: 0 } }),
565
+ /* @__PURE__ */ jsx(
566
+ Code,
567
+ {
568
+ block: true,
569
+ style: {
570
+ fontSize: "13px",
571
+ wordBreak: "break-all",
572
+ backgroundColor: "transparent",
573
+ padding: 0,
574
+ flex: 1
575
+ },
576
+ children: apiKey.key
577
+ }
578
+ ),
579
+ /* @__PURE__ */ jsx(CopyButton, { value: apiKey.key, timeout: 2e3, children: ({ copied, copy }) => /* @__PURE__ */ jsx(
580
+ ActionIcon,
581
+ {
582
+ color: copied ? "teal" : "gray",
583
+ variant: copied ? "filled" : "subtle",
584
+ onClick: copy,
585
+ size: "lg",
586
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: 18 }) : /* @__PURE__ */ jsx(IconCopy, { size: 18 })
587
+ }
588
+ ) })
589
+ ] }) })
590
+ ] }),
591
+ /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
592
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "How to use this key:" }),
593
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(Code, { block: true, style: { fontSize: "12px", backgroundColor: "transparent" }, children: `
594
+ # Using Authorization header
595
+ curl -X POST https://api.elevasis.io/webhooks/execute \\
596
+ -H "Authorization: Bearer ${apiKey.key}" \\
597
+ -H "Content-Type: application/json" \\
598
+ -d '{"resourceId": "workflow-id", "input": {...}}'` }) })
599
+ ] }),
600
+ /* @__PURE__ */ jsx(Group, { justify: "right", children: /* @__PURE__ */ jsx(Button, { onClick: onClose, size: "sm", leftSection: /* @__PURE__ */ jsx(IconCheck, { size: 16 }), children: "I've saved my key" }) })
601
+ ] }) });
602
+ }
603
+ function ApiKeySettings() {
604
+ const { organizationReady } = useInitialization();
605
+ const [showCreateModal, setShowCreateModal] = useState(false);
606
+ const [newApiKey, setNewApiKey] = useState(null);
607
+ const { data: apiKeys = [], isLoading } = useListApiKeys();
608
+ if (!organizationReady) return /* @__PURE__ */ jsx(AppShellLoader, {});
609
+ const handleKeyCreated = (result) => {
610
+ setNewApiKey(result);
611
+ setShowCreateModal(false);
612
+ };
613
+ const totalKeys = apiKeys.length;
614
+ const recentlyUsed = apiKeys.filter((key) => {
615
+ if (!key.last_used_at) return false;
616
+ const lastUsed = new Date(key.last_used_at);
617
+ const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1e3);
618
+ return lastUsed > dayAgo;
619
+ }).length;
620
+ return /* @__PURE__ */ jsxs(Stack, { children: [
621
+ /* @__PURE__ */ jsx(
622
+ PageTitleCaption,
623
+ {
624
+ title: "API Keys",
625
+ caption: "Manage API keys for external service integrations",
626
+ rightSection: /* @__PURE__ */ jsx(Button, { leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 16 }), onClick: () => setShowCreateModal(true), variant: "light", children: "Create API Key" })
627
+ }
628
+ ),
629
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: 2, children: [
630
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconKey, value: totalKeys, label: "Total Keys", isLoading }),
631
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", icon: IconClock, value: recentlyUsed, label: "Used in 24h", isLoading })
632
+ ] }),
633
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(ApiKeyList, { keys: apiKeys, isLoading }) }),
634
+ /* @__PURE__ */ jsx(
635
+ CreateApiKeyModal,
636
+ {
637
+ opened: showCreateModal,
638
+ onClose: () => setShowCreateModal(false),
639
+ onSuccess: handleKeyCreated
640
+ }
641
+ ),
642
+ newApiKey && /* @__PURE__ */ jsx(ApiKeyDisplayModal, { opened: true, apiKey: newApiKey, onClose: () => setNewApiKey(null) })
643
+ ] });
644
+ }
645
+ var statusConfig = {
646
+ active: { color: "green", label: "Active" },
647
+ deploying: { color: "blue", label: "Deploying" },
648
+ failed: { color: "red", label: "Failed" },
649
+ stopped: { color: "gray", label: "Stopped" },
650
+ rolled_back: { color: "yellow", label: "Rolled Back" }
651
+ };
652
+ function DeploymentStatusBadge({ status }) {
653
+ const config = statusConfig[status] ?? { color: "gray", label: status };
654
+ return /* @__PURE__ */ jsx(Badge, { variant: "light", color: config.color, size: "sm", children: config.label });
655
+ }
656
+ function DetailRow({ label, children }) {
657
+ return /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
658
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", fw: 500, children: label }),
659
+ /* @__PURE__ */ jsx("div", { children })
660
+ ] });
661
+ }
662
+ function DeploymentDetailModal({ deployment, opened, onClose }) {
663
+ if (!deployment) return null;
664
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose, size: "lg", children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
665
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
666
+ /* @__PURE__ */ jsx(IconRocket, { size: 24, color: "var(--color-primary)" }),
667
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Deployment Details" })
668
+ ] }),
669
+ /* @__PURE__ */ jsx(DetailRow, { label: "ID", children: /* @__PURE__ */ jsx(Code, { children: deployment.id }) }),
670
+ /* @__PURE__ */ jsx(DetailRow, { label: "Status", children: /* @__PURE__ */ jsx(DeploymentStatusBadge, { status: deployment.status }) }),
671
+ /* @__PURE__ */ jsx(DetailRow, { label: "SDK Version", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: deployment.sdkVersion }) }),
672
+ /* @__PURE__ */ jsx(DetailRow, { label: "Deployment Version", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: deployment.deploymentVersion ? `v${deployment.deploymentVersion}` : "\u2014" }) }),
673
+ /* @__PURE__ */ jsx(DetailRow, { label: "Created", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: formatDateTime(deployment.createdAt) }) }),
674
+ /* @__PURE__ */ jsx(DetailRow, { label: "Updated", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: formatDateTime(deployment.updatedAt) }) }),
675
+ deployment.tarballPath && /* @__PURE__ */ jsx(DetailRow, { label: "Bundle Path", children: /* @__PURE__ */ jsx(Code, { fz: "xs", children: deployment.tarballPath }) }),
676
+ deployment.errorMessage && /* @__PURE__ */ jsx(Alert, { icon: /* @__PURE__ */ jsx(IconAlertTriangle, { size: 16 }), title: "Error", color: "red", variant: "light", mt: "xs", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: deployment.errorMessage }) })
677
+ ] }) });
678
+ }
679
+ function DeploymentList({ deployments, isLoading }) {
680
+ const [selected, setSelected] = useState(null);
681
+ const [activateTarget, setActivateTarget] = useState(null);
682
+ const [deactivateTarget, setDeactivateTarget] = useState(null);
683
+ const [deleteTarget, setDeleteTarget] = useState(null);
684
+ const { page, setPage, offset, totalPages } = usePaginationState(PAGE_SIZE_DEFAULT, void 0, deployments.length);
685
+ const paginatedDeployments = deployments.slice(offset, offset + PAGE_SIZE_DEFAULT);
686
+ const total = totalPages(deployments.length);
687
+ const activateMutation = useActivateDeployment();
688
+ const deactivateMutation = useDeactivateDeployment();
689
+ const deleteMutation = useDeleteDeployment();
690
+ const handleCloseActivate = () => {
691
+ if (!activateMutation.isPending) setActivateTarget(null);
692
+ };
693
+ const handleCloseDeactivate = () => {
694
+ if (!deactivateMutation.isPending) setDeactivateTarget(null);
695
+ };
696
+ const handleCloseDelete = () => {
697
+ if (!deleteMutation.isPending) setDeleteTarget(null);
698
+ };
699
+ const handleConfirmActivate = () => {
700
+ if (!activateTarget) return;
701
+ activateMutation.mutate(activateTarget.id, { onSuccess: () => setActivateTarget(null) });
702
+ };
703
+ const handleConfirmDeactivate = () => {
704
+ if (!deactivateTarget) return;
705
+ deactivateMutation.mutate(deactivateTarget.id, { onSuccess: () => setDeactivateTarget(null) });
706
+ };
707
+ const handleConfirmDelete = () => {
708
+ if (!deleteTarget) return;
709
+ deleteMutation.mutate(deleteTarget.id, { onSuccess: () => setDeleteTarget(null) });
710
+ };
711
+ if (isLoading) {
712
+ return /* @__PURE__ */ jsx(ListSkeleton, { rows: 3, rowHeight: 50 });
713
+ }
714
+ if (deployments.length === 0) {
715
+ return /* @__PURE__ */ jsx(
716
+ EmptyState,
717
+ {
718
+ icon: IconRocket,
719
+ title: "No deployments yet",
720
+ description: "Deploy your first bundle using the SDK CLI: elevasis deploy"
721
+ }
722
+ );
723
+ }
724
+ const anyMutationPending = activateMutation.isPending || deactivateMutation.isPending || deleteMutation.isPending;
725
+ const mutatingId = activateMutation.isPending ? activateMutation.variables : deactivateMutation.isPending ? deactivateMutation.variables : deleteMutation.isPending ? deleteMutation.variables : null;
726
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
727
+ /* @__PURE__ */ jsxs(Table, { children: [
728
+ /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
729
+ /* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
730
+ /* @__PURE__ */ jsx(Table.Th, { children: "Deployment Version" }),
731
+ /* @__PURE__ */ jsx(Table.Th, { children: "SDK Version" }),
732
+ /* @__PURE__ */ jsx(Table.Th, { children: "Created" }),
733
+ /* @__PURE__ */ jsx(Table.Th, { children: "Updated" }),
734
+ /* @__PURE__ */ jsx(Table.Th, { w: 100 })
735
+ ] }) }),
736
+ /* @__PURE__ */ jsx(Table.Tbody, { children: paginatedDeployments.map((deployment) => {
737
+ const isMutating = deployment.id === mutatingId;
738
+ return /* @__PURE__ */ jsxs(
739
+ Table.Tr,
740
+ {
741
+ onClick: () => setSelected(deployment),
742
+ style: { cursor: "pointer", opacity: isMutating ? 0.6 : 1, transition: "opacity 150ms" },
743
+ children: [
744
+ /* @__PURE__ */ jsx(Table.Td, { children: isMutating ? /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
745
+ /* @__PURE__ */ jsx(Loader, { size: 14 }),
746
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Updating\u2026" })
747
+ ] }) : /* @__PURE__ */ jsx(DeploymentStatusBadge, { status: deployment.status }) }),
748
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: deployment.deploymentVersion ?? "\u2014" }) }),
749
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: deployment.sdkVersion }) }),
750
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
751
+ /* @__PURE__ */ jsx(IconCalendar, { size: 14, style: { opacity: 0.5 } }),
752
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDateTime(deployment.createdAt) })
753
+ ] }) }),
754
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
755
+ /* @__PURE__ */ jsx(IconRefresh, { size: 14, style: { opacity: 0.5 } }),
756
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDateTime(deployment.updatedAt) })
757
+ ] }) }),
758
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "flex-end", children: [
759
+ deployment.status === "active" && /* @__PURE__ */ jsx(Tooltip, { label: "Deactivate deployment", children: /* @__PURE__ */ jsx(
760
+ ActionIcon,
761
+ {
762
+ variant: "subtle",
763
+ color: "orange",
764
+ onClick: (e) => {
765
+ e.stopPropagation();
766
+ setDeactivateTarget(deployment);
767
+ },
768
+ disabled: anyMutationPending,
769
+ children: /* @__PURE__ */ jsx(IconPower, { size: 16 })
770
+ }
771
+ ) }),
772
+ (deployment.status === "stopped" || deployment.status === "rolled_back") && /* @__PURE__ */ jsxs(Fragment, { children: [
773
+ /* @__PURE__ */ jsx(Tooltip, { label: "Activate deployment", children: /* @__PURE__ */ jsx(
774
+ ActionIcon,
775
+ {
776
+ variant: "subtle",
777
+ color: "green",
778
+ onClick: (e) => {
779
+ e.stopPropagation();
780
+ setActivateTarget(deployment);
781
+ },
782
+ disabled: anyMutationPending,
783
+ children: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 })
784
+ }
785
+ ) }),
786
+ /* @__PURE__ */ jsx(Tooltip, { label: "Delete deployment", position: "left", children: /* @__PURE__ */ jsx(
787
+ ActionIcon,
788
+ {
789
+ variant: "subtle",
790
+ color: "red",
791
+ onClick: (e) => {
792
+ e.stopPropagation();
793
+ setDeleteTarget(deployment);
794
+ },
795
+ disabled: anyMutationPending,
796
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 16 })
797
+ }
798
+ ) })
799
+ ] }),
800
+ deployment.status === "failed" && /* @__PURE__ */ jsx(Tooltip, { label: "Delete deployment", position: "left", children: /* @__PURE__ */ jsx(
801
+ ActionIcon,
802
+ {
803
+ variant: "subtle",
804
+ color: "red",
805
+ onClick: (e) => {
806
+ e.stopPropagation();
807
+ setDeleteTarget(deployment);
808
+ },
809
+ disabled: anyMutationPending,
810
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 16 })
811
+ }
812
+ ) })
813
+ ] }) })
814
+ ]
815
+ },
816
+ deployment.id
817
+ );
818
+ }) })
819
+ ] }),
820
+ total > 1 && /* @__PURE__ */ jsx(Group, { justify: "center", mt: "md", children: /* @__PURE__ */ jsx(Pagination, { total, value: page, onChange: setPage }) }),
821
+ /* @__PURE__ */ jsx(DeploymentDetailModal, { deployment: selected, opened: !!selected, onClose: () => setSelected(null) }),
822
+ /* @__PURE__ */ jsx(
823
+ CustomModal,
824
+ {
825
+ opened: !!activateTarget,
826
+ onClose: handleCloseActivate,
827
+ size: "sm",
828
+ loading: activateMutation.isPending,
829
+ children: /* @__PURE__ */ jsxs(Stack, { children: [
830
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
831
+ /* @__PURE__ */ jsx(IconPlayerPlay, { size: 24, color: "var(--mantine-color-green-6)" }),
832
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Activate Deployment" })
833
+ ] }),
834
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
835
+ "Are you sure you want to activate deployment",
836
+ " ",
837
+ /* @__PURE__ */ jsxs(Text, { span: true, fw: 600, children: [
838
+ '"',
839
+ activateTarget?.id.slice(0, 8),
840
+ '..."'
841
+ ] }),
842
+ "?"
843
+ ] }),
844
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This will stop the currently active deployment and replace it with this version." }),
845
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "sm", children: [
846
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleCloseActivate, disabled: activateMutation.isPending, children: "Cancel" }),
847
+ /* @__PURE__ */ jsx(
848
+ Button,
849
+ {
850
+ color: "green",
851
+ onClick: handleConfirmActivate,
852
+ loading: activateMutation.isPending,
853
+ leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 }),
854
+ children: "Activate"
855
+ }
856
+ )
857
+ ] })
858
+ ] })
859
+ }
860
+ ),
861
+ /* @__PURE__ */ jsx(
862
+ CustomModal,
863
+ {
864
+ opened: !!deactivateTarget,
865
+ onClose: handleCloseDeactivate,
866
+ size: "sm",
867
+ loading: deactivateMutation.isPending,
868
+ children: /* @__PURE__ */ jsxs(Stack, { children: [
869
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
870
+ /* @__PURE__ */ jsx(IconPower, { size: 24, color: "var(--mantine-color-orange-6)" }),
871
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Deactivate Deployment" })
872
+ ] }),
873
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
874
+ "Are you sure you want to deactivate deployment",
875
+ " ",
876
+ /* @__PURE__ */ jsxs(Text, { span: true, fw: 600, children: [
877
+ '"',
878
+ deactivateTarget?.id.slice(0, 8),
879
+ '..."'
880
+ ] }),
881
+ "?"
882
+ ] }),
883
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This will stop all workflow and agent executions for this deployment. No resources will be available until a deployment is activated." }),
884
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "sm", children: [
885
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleCloseDeactivate, disabled: deactivateMutation.isPending, children: "Cancel" }),
886
+ /* @__PURE__ */ jsx(
887
+ Button,
888
+ {
889
+ color: "orange",
890
+ onClick: handleConfirmDeactivate,
891
+ loading: deactivateMutation.isPending,
892
+ leftSection: /* @__PURE__ */ jsx(IconPower, { size: 16 }),
893
+ children: "Deactivate"
894
+ }
895
+ )
896
+ ] })
897
+ ] })
898
+ }
899
+ ),
900
+ /* @__PURE__ */ jsx(CustomModal, { opened: !!deleteTarget, onClose: handleCloseDelete, size: "sm", loading: deleteMutation.isPending, children: /* @__PURE__ */ jsxs(Stack, { children: [
901
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
902
+ /* @__PURE__ */ jsx(IconAlertTriangle, { size: 24, color: "var(--color-error)" }),
903
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Delete Deployment" })
904
+ ] }),
905
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
906
+ "Are you sure you want to delete deployment",
907
+ " ",
908
+ /* @__PURE__ */ jsxs(Text, { span: true, fw: 600, children: [
909
+ '"',
910
+ deleteTarget?.id.slice(0, 8),
911
+ '..."'
912
+ ] }),
913
+ "?"
914
+ ] }),
915
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This action cannot be undone. The deployment bundle will be permanently removed." }),
916
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "sm", children: [
917
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleCloseDelete, disabled: deleteMutation.isPending, children: "Cancel" }),
918
+ /* @__PURE__ */ jsx(
919
+ Button,
920
+ {
921
+ color: "red",
922
+ onClick: handleConfirmDelete,
923
+ loading: deleteMutation.isPending,
924
+ leftSection: /* @__PURE__ */ jsx(IconTrash, { size: 16 }),
925
+ children: "Delete"
926
+ }
927
+ )
928
+ ] })
929
+ ] }) })
930
+ ] });
931
+ }
932
+ function DeploymentSettings() {
933
+ const { isReady } = useElevasisServices();
934
+ const { data: deployments = [], isLoading } = useListDeployments();
935
+ if (!isReady) return /* @__PURE__ */ jsx(AppShellLoader, {});
936
+ const totalDeployments = deployments.length;
937
+ const activeDeployment = deployments.find((d) => d.status === "active");
938
+ return /* @__PURE__ */ jsxs(Stack, { children: [
939
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Deployments", caption: "View deployment history for externally deployed SDK bundles" }),
940
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: 3, children: [
941
+ /* @__PURE__ */ jsx(
942
+ StatCard,
943
+ {
944
+ variant: "hero",
945
+ icon: IconRocket,
946
+ value: totalDeployments,
947
+ label: "Total Deployments",
948
+ isLoading
949
+ }
950
+ ),
951
+ /* @__PURE__ */ jsx(
952
+ StatCard,
953
+ {
954
+ variant: "hero",
955
+ icon: IconCircleCheck,
956
+ value: activeDeployment ? activeDeployment.sdkVersion : "None",
957
+ label: "Active SDK Deployment",
958
+ isLoading
959
+ }
960
+ ),
961
+ /* @__PURE__ */ jsx(
962
+ StatCard,
963
+ {
964
+ variant: "hero",
965
+ icon: IconTag,
966
+ value: activeDeployment?.deploymentVersion ?? "None",
967
+ label: "Active Deployment Version",
968
+ isLoading
969
+ }
970
+ )
971
+ ] }),
972
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(DeploymentList, { deployments, isLoading }) })
973
+ ] });
974
+ }
975
+ function ScheduleTypeSelector({ value, onChange, disabled }) {
976
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
977
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Schedule Type" }),
978
+ /* @__PURE__ */ jsx(
979
+ SegmentedControl,
980
+ {
981
+ value,
982
+ onChange: (v) => onChange(v),
983
+ disabled,
984
+ data: [
985
+ {
986
+ value: "recurring",
987
+ label: /* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", children: [
988
+ /* @__PURE__ */ jsx(IconCalendarRepeat, { size: 20 }),
989
+ /* @__PURE__ */ jsx(Text, { size: "xs", children: "Recurring" })
990
+ ] })
991
+ },
992
+ {
993
+ value: "relative",
994
+ label: /* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", children: [
995
+ /* @__PURE__ */ jsx(IconCalendarEvent, { size: 20 }),
996
+ /* @__PURE__ */ jsx(Text, { size: "xs", children: "Relative" })
997
+ ] })
998
+ },
999
+ {
1000
+ value: "absolute",
1001
+ label: /* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", children: [
1002
+ /* @__PURE__ */ jsx(IconCalendarTime, { size: 20 }),
1003
+ /* @__PURE__ */ jsx(Text, { size: "xs", children: "Absolute" })
1004
+ ] })
1005
+ }
1006
+ ],
1007
+ fullWidth: true
1008
+ }
1009
+ ),
1010
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1011
+ value === "recurring" && "Run on a schedule (daily, weekly, or cron expression)",
1012
+ value === "relative" && "Run at offsets from an anchor date (e.g., 3 days before event)",
1013
+ value === "absolute" && "Run at specific dates and times"
1014
+ ] })
1015
+ ] });
1016
+ }
1017
+ function toDateTimeLocal(isoString) {
1018
+ if (!isoString) return "";
1019
+ const date = new Date(isoString);
1020
+ return date.toISOString().slice(0, 16);
1021
+ }
1022
+ function fromDateTimeLocal(dateTimeLocal) {
1023
+ if (!dateTimeLocal) return null;
1024
+ return new Date(dateTimeLocal).toISOString();
1025
+ }
1026
+ function RecurringScheduleForm({ value, onChange, disabled }) {
1027
+ const [useCron, setUseCron] = useState(!!value.cron);
1028
+ const handleChange = (updates) => {
1029
+ onChange({ ...value, ...updates });
1030
+ };
1031
+ return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1032
+ /* @__PURE__ */ jsx(
1033
+ Switch,
1034
+ {
1035
+ label: "Use cron expression",
1036
+ description: "Advanced scheduling with cron syntax",
1037
+ checked: useCron,
1038
+ onChange: (e) => {
1039
+ setUseCron(e.currentTarget.checked);
1040
+ if (e.currentTarget.checked) {
1041
+ handleChange({ cron: "0 9 * * *", interval: void 0, time: void 0 });
1042
+ } else {
1043
+ handleChange({ cron: void 0, interval: "daily", time: "09:00" });
1044
+ }
1045
+ },
1046
+ disabled
1047
+ }
1048
+ ),
1049
+ useCron ? /* @__PURE__ */ jsx(
1050
+ TextInput,
1051
+ {
1052
+ label: "Cron Expression",
1053
+ placeholder: "0 9 * * 1 (Every Monday at 9am)",
1054
+ value: value.cron || "",
1055
+ onChange: (e) => handleChange({ cron: e.currentTarget.value }),
1056
+ description: "Format: minute hour day month weekday",
1057
+ disabled
1058
+ }
1059
+ ) : /* @__PURE__ */ jsxs(Group, { grow: true, children: [
1060
+ /* @__PURE__ */ jsx(
1061
+ Select,
1062
+ {
1063
+ label: "Interval",
1064
+ data: [
1065
+ { value: "daily", label: "Daily" },
1066
+ { value: "weekly", label: "Weekly" },
1067
+ { value: "monthly", label: "Monthly" }
1068
+ ],
1069
+ value: value.interval || "daily",
1070
+ onChange: (v) => handleChange({ interval: v }),
1071
+ disabled
1072
+ }
1073
+ ),
1074
+ /* @__PURE__ */ jsx(
1075
+ TextInput,
1076
+ {
1077
+ label: "Time",
1078
+ type: "time",
1079
+ value: value.time || "09:00",
1080
+ onChange: (e) => handleChange({ time: e.currentTarget.value }),
1081
+ disabled
1082
+ }
1083
+ )
1084
+ ] }),
1085
+ /* @__PURE__ */ jsx(
1086
+ Select,
1087
+ {
1088
+ label: "Timezone",
1089
+ placeholder: "Select timezone",
1090
+ data: [
1091
+ { value: "UTC", label: "UTC" },
1092
+ { value: "America/New_York", label: "Eastern Time" },
1093
+ { value: "America/Chicago", label: "Central Time" },
1094
+ { value: "America/Denver", label: "Mountain Time" },
1095
+ { value: "America/Los_Angeles", label: "Pacific Time" },
1096
+ { value: "Europe/London", label: "London" },
1097
+ { value: "Europe/Paris", label: "Paris" },
1098
+ { value: "Asia/Tokyo", label: "Tokyo" }
1099
+ ],
1100
+ value: value.timezone || "UTC",
1101
+ onChange: (v) => handleChange({ timezone: v || "UTC" }),
1102
+ searchable: true,
1103
+ disabled
1104
+ }
1105
+ ),
1106
+ /* @__PURE__ */ jsx(
1107
+ TextInput,
1108
+ {
1109
+ label: "End Date (Optional)",
1110
+ type: "datetime-local",
1111
+ value: toDateTimeLocal(value.endAt),
1112
+ onChange: (e) => handleChange({ endAt: fromDateTimeLocal(e.currentTarget.value) }),
1113
+ disabled
1114
+ }
1115
+ )
1116
+ ] });
1117
+ }
1118
+ function toDateTimeLocal2(isoString) {
1119
+ if (!isoString) return "";
1120
+ const date = new Date(isoString);
1121
+ return date.toISOString().slice(0, 16);
1122
+ }
1123
+ function fromDateTimeLocal2(dateTimeLocal) {
1124
+ if (!dateTimeLocal) return void 0;
1125
+ return new Date(dateTimeLocal).toISOString();
1126
+ }
1127
+ function RelativeScheduleForm({ value, onChange, disabled }) {
1128
+ const items = value.items || [];
1129
+ const handleAnchorChange = (dateTimeLocal) => {
1130
+ onChange({ ...value, anchorAt: fromDateTimeLocal2(dateTimeLocal) });
1131
+ };
1132
+ const handleItemChange = (index, updates) => {
1133
+ const newItems = [...items];
1134
+ newItems[index] = { ...newItems[index], ...updates };
1135
+ onChange({ ...value, items: newItems });
1136
+ };
1137
+ const handleAddItem = () => {
1138
+ const newItems = [...items, { offset: "+1d", payload: {}, label: "" }];
1139
+ onChange({ ...value, items: newItems });
1140
+ };
1141
+ const handleRemoveItem = (index) => {
1142
+ const newItems = items.filter((_, i) => i !== index);
1143
+ onChange({ ...value, items: newItems });
1144
+ };
1145
+ return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1146
+ /* @__PURE__ */ jsx(
1147
+ TextInput,
1148
+ {
1149
+ label: "Anchor Date",
1150
+ description: "Reference date for calculating run times",
1151
+ type: "datetime-local",
1152
+ value: toDateTimeLocal2(value.anchorAt),
1153
+ onChange: (e) => handleAnchorChange(e.currentTarget.value),
1154
+ required: true,
1155
+ disabled
1156
+ }
1157
+ ),
1158
+ /* @__PURE__ */ jsx(
1159
+ TextInput,
1160
+ {
1161
+ label: "Anchor Label (Optional)",
1162
+ placeholder: "e.g., meeting_date, deadline, event_start",
1163
+ value: value.anchorLabel || "",
1164
+ onChange: (e) => onChange({ ...value, anchorLabel: e.currentTarget.value || void 0 }),
1165
+ disabled
1166
+ }
1167
+ ),
1168
+ /* @__PURE__ */ jsxs(Stack, { children: [
1169
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1170
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Schedule Items" }),
1171
+ /* @__PURE__ */ jsx(
1172
+ Button,
1173
+ {
1174
+ size: "xs",
1175
+ variant: "light",
1176
+ leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 14 }),
1177
+ onClick: handleAddItem,
1178
+ disabled,
1179
+ children: "Add Item"
1180
+ }
1181
+ )
1182
+ ] }),
1183
+ items.length === 0 && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: 'No items yet. Click "Add Item" to create a schedule step.' }),
1184
+ items.map((item, index) => /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1185
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1186
+ /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
1187
+ "Step ",
1188
+ index + 1
1189
+ ] }),
1190
+ /* @__PURE__ */ jsx(
1191
+ ActionIcon,
1192
+ {
1193
+ size: "sm",
1194
+ color: "red",
1195
+ variant: "subtle",
1196
+ onClick: () => handleRemoveItem(index),
1197
+ disabled,
1198
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 14 })
1199
+ }
1200
+ )
1201
+ ] }),
1202
+ /* @__PURE__ */ jsxs(Group, { grow: true, children: [
1203
+ /* @__PURE__ */ jsx(
1204
+ TextInput,
1205
+ {
1206
+ label: "Offset",
1207
+ placeholder: "+3d, -2h, +30m",
1208
+ value: item.offset,
1209
+ onChange: (e) => handleItemChange(index, { offset: e.currentTarget.value }),
1210
+ description: "+ after anchor, - before anchor",
1211
+ disabled
1212
+ }
1213
+ ),
1214
+ /* @__PURE__ */ jsx(
1215
+ TextInput,
1216
+ {
1217
+ label: "Label (Optional)",
1218
+ placeholder: "e.g., Thank you, Follow up",
1219
+ value: item.label || "",
1220
+ onChange: (e) => handleItemChange(index, { label: e.currentTarget.value || void 0 }),
1221
+ disabled
1222
+ }
1223
+ )
1224
+ ] }),
1225
+ /* @__PURE__ */ jsx(
1226
+ Textarea,
1227
+ {
1228
+ label: "Payload (JSON)",
1229
+ placeholder: '{"key": "value"}',
1230
+ value: JSON.stringify(item.payload, null, 2),
1231
+ onChange: (e) => {
1232
+ try {
1233
+ const payload = JSON.parse(e.currentTarget.value);
1234
+ handleItemChange(index, { payload });
1235
+ } catch {
1236
+ }
1237
+ },
1238
+ minRows: 2,
1239
+ disabled
1240
+ }
1241
+ )
1242
+ ] }) }, index))
1243
+ ] })
1244
+ ] });
1245
+ }
1246
+ function toDateTimeLocal3(isoString) {
1247
+ if (!isoString) return "";
1248
+ const date = new Date(isoString);
1249
+ return date.toISOString().slice(0, 16);
1250
+ }
1251
+ function fromDateTimeLocal3(dateTimeLocal) {
1252
+ if (!dateTimeLocal) return "";
1253
+ return new Date(dateTimeLocal).toISOString();
1254
+ }
1255
+ function AbsoluteScheduleForm({ value, onChange, disabled }) {
1256
+ const items = value.items || [];
1257
+ const handleItemChange = (index, updates) => {
1258
+ const newItems = [...items];
1259
+ newItems[index] = { ...newItems[index], ...updates };
1260
+ onChange({ ...value, items: newItems });
1261
+ };
1262
+ const handleAddItem = () => {
1263
+ const newItems = [...items, { runAt: (/* @__PURE__ */ new Date()).toISOString(), payload: {}, label: "" }];
1264
+ onChange({ ...value, items: newItems });
1265
+ };
1266
+ const handleRemoveItem = (index) => {
1267
+ const newItems = items.filter((_, i) => i !== index);
1268
+ onChange({ ...value, items: newItems });
1269
+ };
1270
+ return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1271
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1272
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Scheduled Executions" }),
1273
+ /* @__PURE__ */ jsx(
1274
+ Button,
1275
+ {
1276
+ size: "xs",
1277
+ variant: "light",
1278
+ leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 14 }),
1279
+ onClick: handleAddItem,
1280
+ disabled,
1281
+ children: "Add Execution"
1282
+ }
1283
+ )
1284
+ ] }),
1285
+ items.length === 0 && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: 'No executions yet. Click "Add Execution" to schedule a run.' }),
1286
+ items.map((item, index) => /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1287
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1288
+ /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
1289
+ "Execution ",
1290
+ index + 1
1291
+ ] }),
1292
+ /* @__PURE__ */ jsx(
1293
+ ActionIcon,
1294
+ {
1295
+ size: "sm",
1296
+ color: "red",
1297
+ variant: "subtle",
1298
+ onClick: () => handleRemoveItem(index),
1299
+ disabled,
1300
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 14 })
1301
+ }
1302
+ )
1303
+ ] }),
1304
+ /* @__PURE__ */ jsxs(Group, { grow: true, children: [
1305
+ /* @__PURE__ */ jsx(
1306
+ TextInput,
1307
+ {
1308
+ label: "Run At",
1309
+ type: "datetime-local",
1310
+ value: toDateTimeLocal3(item.runAt),
1311
+ onChange: (e) => handleItemChange(index, { runAt: fromDateTimeLocal3(e.currentTarget.value) }),
1312
+ required: true,
1313
+ disabled
1314
+ }
1315
+ ),
1316
+ /* @__PURE__ */ jsx(
1317
+ TextInput,
1318
+ {
1319
+ label: "Label (Optional)",
1320
+ placeholder: "e.g., Launch, Phase 2",
1321
+ value: item.label || "",
1322
+ onChange: (e) => handleItemChange(index, { label: e.currentTarget.value || void 0 }),
1323
+ disabled
1324
+ }
1325
+ )
1326
+ ] }),
1327
+ /* @__PURE__ */ jsx(
1328
+ Textarea,
1329
+ {
1330
+ label: "Payload (JSON)",
1331
+ placeholder: '{"key": "value"}',
1332
+ value: JSON.stringify(item.payload, null, 2),
1333
+ onChange: (e) => {
1334
+ try {
1335
+ const payload = JSON.parse(e.currentTarget.value);
1336
+ handleItemChange(index, { payload });
1337
+ } catch {
1338
+ }
1339
+ },
1340
+ minRows: 2,
1341
+ disabled
1342
+ }
1343
+ )
1344
+ ] }) }, index))
1345
+ ] });
1346
+ }
1347
+ var defaultRecurringConfig = {
1348
+ type: "recurring",
1349
+ interval: "daily",
1350
+ time: "09:00",
1351
+ timezone: "UTC",
1352
+ payload: {}
1353
+ };
1354
+ var defaultRelativeConfig = {
1355
+ type: "relative",
1356
+ items: []
1357
+ };
1358
+ var defaultAbsoluteConfig = {
1359
+ type: "absolute",
1360
+ items: []
1361
+ };
1362
+ function CreateScheduleModal({ opened, onClose }) {
1363
+ const [name, setName] = useState("");
1364
+ const [description, setDescription] = useState("");
1365
+ const [resourceId, setResourceId] = useState("");
1366
+ const [scheduleType, setScheduleType] = useState("recurring");
1367
+ const [recurringConfig, setRecurringConfig] = useState(defaultRecurringConfig);
1368
+ const [relativeConfig, setRelativeConfig] = useState(defaultRelativeConfig);
1369
+ const [absoluteConfig, setAbsoluteConfig] = useState(defaultAbsoluteConfig);
1370
+ const { data: resourcesData } = useResources();
1371
+ const createSchedule = useCreateSchedule();
1372
+ const allResources = useMemo(() => {
1373
+ if (!resourcesData) return [];
1374
+ const workflows = (resourcesData.workflows || []).map((w) => ({
1375
+ id: w.resourceId,
1376
+ type: "workflow"
1377
+ }));
1378
+ const agents = (resourcesData.agents || []).map((a) => ({
1379
+ id: a.resourceId,
1380
+ type: "agent"
1381
+ }));
1382
+ return [...workflows, ...agents];
1383
+ }, [resourcesData]);
1384
+ const resourceOptions = useMemo(() => {
1385
+ if (!resourcesData) return [];
1386
+ const workflowOptions = (resourcesData.workflows || []).filter((w) => w?.resourceId).map((w) => ({
1387
+ value: w.resourceId,
1388
+ label: `Workflow: ${w.resourceId}`
1389
+ }));
1390
+ const agentOptions = (resourcesData.agents || []).filter((a) => a?.resourceId).map((a) => ({
1391
+ value: a.resourceId,
1392
+ label: `Agent: ${a.resourceId}`
1393
+ }));
1394
+ return [...workflowOptions, ...agentOptions];
1395
+ }, [resourcesData]);
1396
+ const handleScheduleTypeChange = (newType) => {
1397
+ setScheduleType(newType);
1398
+ };
1399
+ const buildScheduleConfig = () => {
1400
+ switch (scheduleType) {
1401
+ case "recurring": {
1402
+ if (!recurringConfig.timezone) {
1403
+ showErrorNotification("Timezone is required");
1404
+ return null;
1405
+ }
1406
+ const config = {
1407
+ type: "recurring",
1408
+ timezone: recurringConfig.timezone,
1409
+ payload: recurringConfig.payload || {},
1410
+ endAt: recurringConfig.endAt
1411
+ };
1412
+ if (recurringConfig.cron) {
1413
+ config.cron = recurringConfig.cron;
1414
+ } else {
1415
+ config.interval = recurringConfig.interval || "daily";
1416
+ config.time = recurringConfig.time || "09:00";
1417
+ }
1418
+ return config;
1419
+ }
1420
+ case "relative": {
1421
+ if (!relativeConfig.anchorAt) {
1422
+ showErrorNotification("Anchor date is required for relative schedules");
1423
+ return null;
1424
+ }
1425
+ if (!relativeConfig.items || relativeConfig.items.length === 0) {
1426
+ showErrorNotification("At least one schedule item is required");
1427
+ return null;
1428
+ }
1429
+ return {
1430
+ type: "relative",
1431
+ anchorAt: relativeConfig.anchorAt,
1432
+ anchorLabel: relativeConfig.anchorLabel,
1433
+ items: relativeConfig.items
1434
+ };
1435
+ }
1436
+ case "absolute": {
1437
+ if (!absoluteConfig.items || absoluteConfig.items.length === 0) {
1438
+ showErrorNotification("At least one scheduled execution is required");
1439
+ return null;
1440
+ }
1441
+ return {
1442
+ type: "absolute",
1443
+ items: absoluteConfig.items
1444
+ };
1445
+ }
1446
+ default:
1447
+ return null;
1448
+ }
1449
+ };
1450
+ const handleSubmit = async (e) => {
1451
+ e.preventDefault();
1452
+ try {
1453
+ const resource = allResources.find((r) => r.id === resourceId);
1454
+ if (!resource) {
1455
+ showErrorNotification("Please select a valid resource");
1456
+ return;
1457
+ }
1458
+ if (!name.trim()) {
1459
+ showErrorNotification("Schedule name is required");
1460
+ return;
1461
+ }
1462
+ const scheduleConfig = buildScheduleConfig();
1463
+ if (!scheduleConfig) {
1464
+ return;
1465
+ }
1466
+ const input = {
1467
+ name: name.trim(),
1468
+ description: description.trim() || void 0,
1469
+ target: {
1470
+ resourceType: resource.type,
1471
+ resourceId: resource.id
1472
+ },
1473
+ scheduleConfig,
1474
+ maxRetries: 3,
1475
+ originResourceType: "api",
1476
+ originResourceId: "task-scheduler-ui"
1477
+ };
1478
+ await createSchedule.mutateAsync(input);
1479
+ showSuccessNotification("Schedule created successfully");
1480
+ handleClose();
1481
+ } catch (error) {
1482
+ showApiErrorNotification(error);
1483
+ }
1484
+ };
1485
+ const handleClose = () => {
1486
+ if (!createSchedule.isPending) {
1487
+ setName("");
1488
+ setDescription("");
1489
+ setResourceId("");
1490
+ setScheduleType("recurring");
1491
+ setRecurringConfig(defaultRecurringConfig);
1492
+ setRelativeConfig(defaultRelativeConfig);
1493
+ setAbsoluteConfig(defaultAbsoluteConfig);
1494
+ onClose();
1495
+ }
1496
+ };
1497
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose: handleClose, size: "lg", loading: createSchedule.isPending, children: /* @__PURE__ */ jsx("form", { onSubmit: handleSubmit, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1498
+ /* @__PURE__ */ jsx(Title, { order: 3, children: "Create Schedule" }),
1499
+ /* @__PURE__ */ jsx(
1500
+ TextInput,
1501
+ {
1502
+ label: "Schedule Name",
1503
+ placeholder: "e.g., Daily Sales Report, Weekly Sync",
1504
+ value: name,
1505
+ onChange: (e) => setName(e.currentTarget.value),
1506
+ required: true,
1507
+ disabled: createSchedule.isPending
1508
+ }
1509
+ ),
1510
+ /* @__PURE__ */ jsx(
1511
+ Textarea,
1512
+ {
1513
+ label: "Description (Optional)",
1514
+ placeholder: "Describe what this schedule does...",
1515
+ value: description,
1516
+ onChange: (e) => setDescription(e.currentTarget.value),
1517
+ disabled: createSchedule.isPending
1518
+ }
1519
+ ),
1520
+ /* @__PURE__ */ jsx(
1521
+ Select,
1522
+ {
1523
+ label: "Resource to Execute",
1524
+ placeholder: resourcesData ? "Select an agent or workflow" : "Loading resources...",
1525
+ data: resourceOptions,
1526
+ value: resourceId,
1527
+ onChange: (value) => setResourceId(value || ""),
1528
+ searchable: true,
1529
+ required: true,
1530
+ disabled: !resourcesData || createSchedule.isPending
1531
+ }
1532
+ ),
1533
+ /* @__PURE__ */ jsx(Divider, {}),
1534
+ /* @__PURE__ */ jsx(
1535
+ ScheduleTypeSelector,
1536
+ {
1537
+ value: scheduleType,
1538
+ onChange: handleScheduleTypeChange,
1539
+ disabled: createSchedule.isPending
1540
+ }
1541
+ ),
1542
+ /* @__PURE__ */ jsx(Divider, {}),
1543
+ scheduleType === "recurring" && /* @__PURE__ */ jsx(
1544
+ RecurringScheduleForm,
1545
+ {
1546
+ value: recurringConfig,
1547
+ onChange: setRecurringConfig,
1548
+ disabled: createSchedule.isPending
1549
+ }
1550
+ ),
1551
+ scheduleType === "relative" && /* @__PURE__ */ jsx(
1552
+ RelativeScheduleForm,
1553
+ {
1554
+ value: relativeConfig,
1555
+ onChange: setRelativeConfig,
1556
+ disabled: createSchedule.isPending
1557
+ }
1558
+ ),
1559
+ scheduleType === "absolute" && /* @__PURE__ */ jsx(
1560
+ AbsoluteScheduleForm,
1561
+ {
1562
+ value: absoluteConfig,
1563
+ onChange: setAbsoluteConfig,
1564
+ disabled: createSchedule.isPending
1565
+ }
1566
+ ),
1567
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", mt: "md", children: [
1568
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, type: "button", disabled: createSchedule.isPending, children: "Cancel" }),
1569
+ /* @__PURE__ */ jsx(Button, { type: "submit", loading: createSchedule.isPending, children: "Create Schedule" })
1570
+ ] })
1571
+ ] }) }) });
1572
+ }
1573
+ function DeleteScheduleModal({ opened, onClose, onConfirm, schedule, isDeleting }) {
1574
+ const handleClose = () => {
1575
+ if (!isDeleting) {
1576
+ onClose();
1577
+ }
1578
+ };
1579
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose: handleClose, size: "sm", loading: isDeleting, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1580
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
1581
+ /* @__PURE__ */ jsx(IconAlertTriangle, { size: 24, color: "var(--color-error)" }),
1582
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Delete Schedule" })
1583
+ ] }),
1584
+ /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
1585
+ "Are you sure you want to delete",
1586
+ " ",
1587
+ /* @__PURE__ */ jsx(Text, { span: true, fw: 600, children: schedule?.name }),
1588
+ "?"
1589
+ ] }),
1590
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This action cannot be undone. Any pending executions will be cancelled." }),
1591
+ /* @__PURE__ */ jsxs(Group, { justify: "flex-end", mt: "md", children: [
1592
+ /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, disabled: isDeleting, children: "Cancel" }),
1593
+ /* @__PURE__ */ jsx(Button, { color: "red", onClick: onConfirm, loading: isDeleting, children: "Delete" })
1594
+ ] })
1595
+ ] }) });
1596
+ }
1597
+ function getStatusColor2(status) {
1598
+ switch (status) {
1599
+ case "active":
1600
+ return "green";
1601
+ case "paused":
1602
+ return "yellow";
1603
+ case "completed":
1604
+ return "blue";
1605
+ case "cancelled":
1606
+ return "gray";
1607
+ }
1608
+ }
1609
+ function formatDate(date) {
1610
+ if (!date) return "N/A";
1611
+ const d = typeof date === "string" ? new Date(date) : date;
1612
+ return d.toLocaleString("en-US", {
1613
+ month: "short",
1614
+ day: "numeric",
1615
+ year: "numeric",
1616
+ hour: "numeric",
1617
+ minute: "2-digit",
1618
+ timeZoneName: "short"
1619
+ });
1620
+ }
1621
+ function ScheduleConfigDetails({ schedule }) {
1622
+ const config = schedule.scheduleConfig;
1623
+ switch (config.type) {
1624
+ case "recurring":
1625
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1626
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1627
+ /* @__PURE__ */ jsx(IconCalendarRepeat, { size: 16, color: "var(--color-text-subtle)" }),
1628
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Recurring Schedule" })
1629
+ ] }),
1630
+ /* @__PURE__ */ jsx(Table, { withRowBorders: false, verticalSpacing: 4, children: /* @__PURE__ */ jsxs(Table.Tbody, { children: [
1631
+ config.cron && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1632
+ /* @__PURE__ */ jsx(Table.Td, { w: 120, children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Cron" }) }),
1633
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Code, { children: config.cron }) })
1634
+ ] }),
1635
+ config.interval && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1636
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Interval" }) }),
1637
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Text, { children: [
1638
+ config.interval,
1639
+ " at ",
1640
+ config.time
1641
+ ] }) })
1642
+ ] }),
1643
+ /* @__PURE__ */ jsxs(Table.Tr, { children: [
1644
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Timezone" }) }),
1645
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: config.timezone }) })
1646
+ ] }),
1647
+ config.endAt && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1648
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Ends" }) }),
1649
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate(config.endAt) }) })
1650
+ ] }),
1651
+ /* @__PURE__ */ jsxs(Table.Tr, { children: [
1652
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Overdue" }) }),
1653
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: config.overduePolicy === "execute" ? "orange" : "gray", children: config.overduePolicy ?? "skip" }) })
1654
+ ] }),
1655
+ Object.keys(config.payload).length > 0 && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1656
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Payload" }) }),
1657
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Code, { block: true, children: JSON.stringify(config.payload, null, 2) }) })
1658
+ ] })
1659
+ ] }) })
1660
+ ] });
1661
+ case "relative":
1662
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1663
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1664
+ /* @__PURE__ */ jsx(IconCalendarEvent, { size: 16, color: "var(--color-text-subtle)" }),
1665
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Relative Schedule" })
1666
+ ] }),
1667
+ /* @__PURE__ */ jsx(Table, { withRowBorders: false, verticalSpacing: 4, children: /* @__PURE__ */ jsxs(Table.Tbody, { children: [
1668
+ /* @__PURE__ */ jsxs(Table.Tr, { children: [
1669
+ /* @__PURE__ */ jsx(Table.Td, { w: 120, children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Anchor" }) }),
1670
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Text, { children: [
1671
+ formatDate(config.anchorAt),
1672
+ config.anchorLabel && ` (${config.anchorLabel})`
1673
+ ] }) })
1674
+ ] }),
1675
+ /* @__PURE__ */ jsxs(Table.Tr, { children: [
1676
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Steps" }) }),
1677
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Stack, { gap: 4, children: config.items.map((item, i) => /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1678
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: i === schedule.currentStep ? "blue" : "gray", children: item.offset }),
1679
+ item.label && /* @__PURE__ */ jsx(Text, { c: "dimmed", children: item.label })
1680
+ ] }, i)) }) })
1681
+ ] })
1682
+ ] }) })
1683
+ ] });
1684
+ case "absolute":
1685
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1686
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1687
+ /* @__PURE__ */ jsx(IconCalendarTime, { size: 16, color: "var(--color-text-subtle)" }),
1688
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Absolute Schedule" })
1689
+ ] }),
1690
+ /* @__PURE__ */ jsx(Stack, { gap: 4, children: config.items.map((item, i) => /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1691
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: i === schedule.currentStep ? "blue" : "gray", children: i + 1 }),
1692
+ /* @__PURE__ */ jsx(Text, { children: formatDate(item.runAt) }),
1693
+ item.label && /* @__PURE__ */ jsxs(Text, { c: "dimmed", children: [
1694
+ "\u2014 ",
1695
+ item.label
1696
+ ] })
1697
+ ] }, i)) })
1698
+ ] });
1699
+ }
1700
+ }
1701
+ function ScheduleDetailModal({ opened, onClose, schedule, resourceStatus }) {
1702
+ const ResourceIcon = schedule?.target.resourceType === "agent" ? IconRobot : IconGitBranch;
1703
+ const resourceNotFound = resourceStatus === void 0;
1704
+ return /* @__PURE__ */ jsx(CustomModal, { opened, onClose, size: "lg", children: schedule && /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1705
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
1706
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
1707
+ /* @__PURE__ */ jsx(ResourceIcon, { size: 24, color: "var(--color-primary)" }),
1708
+ /* @__PURE__ */ jsxs("div", { children: [
1709
+ /* @__PURE__ */ jsx(Title, { order: 4, style: { fontFamily: "var(--elevasis-font-family-subtitle)" }, children: schedule.name }),
1710
+ schedule.description && /* @__PURE__ */ jsx(Text, { c: "dimmed", mt: 2, children: schedule.description })
1711
+ ] })
1712
+ ] }),
1713
+ /* @__PURE__ */ jsx(Badge, { variant: "light", color: getStatusColor2(schedule.status), children: schedule.status })
1714
+ ] }),
1715
+ resourceNotFound && /* @__PURE__ */ jsxs(Alert, { icon: /* @__PURE__ */ jsx(IconAlertTriangle, { size: 18 }), color: "red", variant: "light", title: "Resource not found", children: [
1716
+ "The target resource ",
1717
+ /* @__PURE__ */ jsx(Code, { children: schedule.target.resourceId }),
1718
+ " does not exist in the current deployment. This schedule will fail when it tries to execute. Consider deleting or updating it."
1719
+ ] }),
1720
+ /* @__PURE__ */ jsx(Divider, {}),
1721
+ /* @__PURE__ */ jsxs(Group, { gap: "lg", children: [
1722
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1723
+ /* @__PURE__ */ jsx(ResourceIcon, { size: 14, color: "var(--color-text-subtle)" }),
1724
+ /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Target" })
1725
+ ] }),
1726
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1727
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", radius: "sm", children: schedule.target.resourceType }),
1728
+ /* @__PURE__ */ jsx(Code, { children: schedule.target.resourceId })
1729
+ ] })
1730
+ ] }),
1731
+ /* @__PURE__ */ jsx(Divider, {}),
1732
+ /* @__PURE__ */ jsx(ScheduleConfigDetails, { schedule }),
1733
+ /* @__PURE__ */ jsx(Divider, {}),
1734
+ /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1735
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1736
+ /* @__PURE__ */ jsx(IconSettings, { size: 16, color: "var(--color-text-subtle)" }),
1737
+ /* @__PURE__ */ jsx(Text, { fw: 500, children: "Execution Details" })
1738
+ ] }),
1739
+ /* @__PURE__ */ jsx(Table, { withRowBorders: false, verticalSpacing: 4, children: /* @__PURE__ */ jsxs(Table.Tbody, { children: [
1740
+ /* @__PURE__ */ jsxs(Table.Tr, { children: [
1741
+ /* @__PURE__ */ jsx(Table.Td, { w: 140, children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1742
+ /* @__PURE__ */ jsx(IconClock, { size: 12, color: "var(--color-text-subtle)" }),
1743
+ /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Next Run" })
1744
+ ] }) }),
1745
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate(schedule.nextRunAt) }) })
1746
+ ] }),
1747
+ /* @__PURE__ */ jsxs(Table.Tr, { children: [
1748
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1749
+ /* @__PURE__ */ jsx(IconCalendar, { size: 12, color: "var(--color-text-subtle)" }),
1750
+ /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Last Run" })
1751
+ ] }) }),
1752
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate(schedule.lastRunAt) }) })
1753
+ ] }),
1754
+ /* @__PURE__ */ jsxs(Table.Tr, { children: [
1755
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1756
+ /* @__PURE__ */ jsx(IconRefresh, { size: 12, color: "var(--color-text-subtle)" }),
1757
+ /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Max Retries" })
1758
+ ] }) }),
1759
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: schedule.maxRetries }) })
1760
+ ] }),
1761
+ schedule.idempotencyKey && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1762
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1763
+ /* @__PURE__ */ jsx(IconKey, { size: 12, color: "var(--color-text-subtle)" }),
1764
+ /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Idempotency" })
1765
+ ] }) }),
1766
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Code, { children: schedule.idempotencyKey }) })
1767
+ ] }),
1768
+ schedule.lastExecutionId && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1769
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Last Execution" }) }),
1770
+ /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Code, { children: schedule.lastExecutionId }) })
1771
+ ] })
1772
+ ] }) })
1773
+ ] }),
1774
+ /* @__PURE__ */ jsx(Divider, {}),
1775
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1776
+ /* @__PURE__ */ jsxs(Group, { gap: "lg", children: [
1777
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1778
+ "Created ",
1779
+ formatDate(schedule.createdAt)
1780
+ ] }),
1781
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1782
+ "Updated ",
1783
+ formatDate(schedule.updatedAt)
1784
+ ] })
1785
+ ] }),
1786
+ /* @__PURE__ */ jsx(
1787
+ Button,
1788
+ {
1789
+ variant: "light",
1790
+ size: "xs",
1791
+ rightSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 14 }),
1792
+ component: "a",
1793
+ href: schedule.target.resourceType === "agent" ? `/operations/resources/agent/${schedule.target.resourceId}` : `/operations/resources/workflow/${schedule.target.resourceId}`,
1794
+ target: "_blank",
1795
+ disabled: resourceNotFound,
1796
+ children: "Go to Resource"
1797
+ }
1798
+ )
1799
+ ] })
1800
+ ] }) });
1801
+ }
1802
+ function getScheduleTypeIcon(config) {
1803
+ switch (config.type) {
1804
+ case "recurring":
1805
+ return IconCalendarRepeat;
1806
+ case "relative":
1807
+ return IconCalendarEvent;
1808
+ case "absolute":
1809
+ return IconCalendarTime;
1810
+ }
1811
+ }
1812
+ function getScheduleTypeLabel(config) {
1813
+ switch (config.type) {
1814
+ case "recurring":
1815
+ if (config.cron) return `Cron: ${config.cron}`;
1816
+ if (config.interval)
1817
+ return `${config.interval.charAt(0).toUpperCase() + config.interval.slice(1)} at ${config.time}`;
1818
+ return "Recurring";
1819
+ case "relative":
1820
+ return `${config.items.length} steps from anchor`;
1821
+ case "absolute":
1822
+ return `${config.items.length} scheduled runs`;
1823
+ }
1824
+ }
1825
+ function getStatusColor3(status) {
1826
+ switch (status) {
1827
+ case "active":
1828
+ return "green";
1829
+ case "paused":
1830
+ return "yellow";
1831
+ case "completed":
1832
+ return "blue";
1833
+ case "cancelled":
1834
+ return "gray";
1835
+ }
1836
+ }
1837
+ function formatNextRun(date) {
1838
+ if (!date) return "";
1839
+ const now = /* @__PURE__ */ new Date();
1840
+ const diffMs = date.getTime() - now.getTime();
1841
+ const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
1842
+ const diffHours = Math.floor(diffMs % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
1843
+ if (diffMs < 0) return "Overdue";
1844
+ if (diffDays === 0) {
1845
+ if (diffHours === 0) return "Less than an hour";
1846
+ return `In ${diffHours}h`;
1847
+ }
1848
+ if (diffDays === 1) return "Tomorrow";
1849
+ if (diffDays <= 7) return `In ${diffDays}d`;
1850
+ return date.toLocaleDateString("en-US", {
1851
+ month: "short",
1852
+ day: "numeric"
1853
+ });
1854
+ }
1855
+ function ScheduleCard({
1856
+ schedule,
1857
+ resourceStatus,
1858
+ onPause,
1859
+ onResume,
1860
+ onCancel,
1861
+ onDelete,
1862
+ onClick,
1863
+ isLoading
1864
+ }) {
1865
+ const [hovered, setHovered] = useState(false);
1866
+ const TypeIcon = getScheduleTypeIcon(schedule.scheduleConfig);
1867
+ const ResourceIcon = schedule.target.resourceType === "agent" ? IconRobot : IconGitBranch;
1868
+ const nextRunAt = schedule.nextRunAt ? typeof schedule.nextRunAt === "string" ? new Date(schedule.nextRunAt) : schedule.nextRunAt : void 0;
1869
+ const nextRunLabel = nextRunAt && schedule.status === "active" ? formatNextRun(nextRunAt) : "";
1870
+ return /* @__PURE__ */ jsx(
1871
+ Card,
1872
+ {
1873
+ style: {
1874
+ cursor: "pointer",
1875
+ transition: "background 150ms ease",
1876
+ background: hovered ? "var(--active-background)" : "var(--color-surface)"
1877
+ },
1878
+ onClick: (e) => {
1879
+ if (e.target.closest("[data-menu-dropdown]") || e.target.closest("button")) {
1880
+ return;
1881
+ }
1882
+ onClick?.(schedule);
1883
+ },
1884
+ onMouseEnter: () => setHovered(true),
1885
+ onMouseLeave: () => setHovered(false),
1886
+ children: /* @__PURE__ */ jsxs(
1887
+ "div",
1888
+ {
1889
+ style: {
1890
+ display: "grid",
1891
+ gridTemplateColumns: "18px minmax(120px, 1.5fr) minmax(100px, 1fr) minmax(80px, 1fr) 270px",
1892
+ alignItems: "center",
1893
+ gap: "var(--mantine-spacing-sm)"
1894
+ },
1895
+ children: [
1896
+ /* @__PURE__ */ jsx(ResourceIcon, { size: 18, color: "var(--color-primary)" }),
1897
+ /* @__PURE__ */ jsx(Text, { fw: 600, size: "md", truncate: true, style: { fontFamily: "var(--elevasis-font-family-subtitle)" }, children: schedule.name }),
1898
+ /* @__PURE__ */ jsxs(Group, { gap: 6, wrap: "nowrap", children: [
1899
+ /* @__PURE__ */ jsx(TypeIcon, { size: 14, color: "var(--color-text-subtle)", style: { flexShrink: 0 } }),
1900
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", truncate: true, children: getScheduleTypeLabel(schedule.scheduleConfig) })
1901
+ ] }),
1902
+ /* @__PURE__ */ jsxs(Group, { gap: 6, wrap: "nowrap", style: { minWidth: 0 }, children: [
1903
+ /* @__PURE__ */ jsx(Tooltip, { label: resourceStatus ? `Deployed: ${resourceStatus}` : "Resource not found", children: /* @__PURE__ */ jsx(
1904
+ "div",
1905
+ {
1906
+ style: {
1907
+ width: 8,
1908
+ height: 8,
1909
+ borderRadius: "50%",
1910
+ flexShrink: 0,
1911
+ backgroundColor: resourceStatus ? resourceStatus === "prod" ? "var(--color-success)" : "var(--color-primary)" : "var(--mantine-color-red-6)"
1912
+ }
1913
+ }
1914
+ ) }),
1915
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", truncate: true, ff: "monospace", style: { minWidth: 0 }, children: schedule.target.resourceId })
1916
+ ] }),
1917
+ /* @__PURE__ */ jsxs(Group, { gap: 8, wrap: "nowrap", justify: "flex-end", children: [
1918
+ /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", children: schedule.target.resourceType }),
1919
+ nextRunLabel && /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", children: [
1920
+ /* @__PURE__ */ jsx(IconClock, { size: 12, color: "var(--color-text-subtle)" }),
1921
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", style: { whiteSpace: "nowrap" }, children: nextRunLabel })
1922
+ ] }),
1923
+ /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: getStatusColor3(schedule.status), children: schedule.status }),
1924
+ /* @__PURE__ */ jsxs(Menu, { position: "bottom-end", withinPortal: true, children: [
1925
+ /* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", disabled: isLoading, children: /* @__PURE__ */ jsx(IconDotsVertical, { size: 16 }) }) }),
1926
+ /* @__PURE__ */ jsxs(Menu.Dropdown, { children: [
1927
+ schedule.status === "active" && /* @__PURE__ */ jsx(Menu.Item, { leftSection: /* @__PURE__ */ jsx(IconPlayerPause, { size: 14 }), onClick: () => onPause(schedule.id), children: "Pause" }),
1928
+ schedule.status === "paused" && /* @__PURE__ */ jsx(Menu.Item, { leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 14 }), onClick: () => onResume(schedule.id), children: "Resume" }),
1929
+ (schedule.status === "active" || schedule.status === "paused") && /* @__PURE__ */ jsx(Menu.Item, { leftSection: /* @__PURE__ */ jsx(IconPlayerStop, { size: 14 }), onClick: () => onCancel(schedule.id), children: "Cancel" }),
1930
+ /* @__PURE__ */ jsx(Menu.Item, { leftSection: /* @__PURE__ */ jsx(IconTrash, { size: 14 }), color: "red", onClick: () => onDelete(schedule.id), children: "Delete" })
1931
+ ] })
1932
+ ] })
1933
+ ] })
1934
+ ]
1935
+ }
1936
+ )
1937
+ }
1938
+ );
1939
+ }
1940
+ var TaskScheduler = () => {
1941
+ const { isReady } = useElevasisServices();
1942
+ const [isModalOpen, setIsModalOpen] = useState(false);
1943
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
1944
+ const [scheduleToDelete, setScheduleToDelete] = useState(null);
1945
+ const [selectedSchedule, setSelectedSchedule] = useState(null);
1946
+ const [viewMode, setViewMode] = useState("buckets");
1947
+ const [statusFilter, setStatusFilter] = useState("all");
1948
+ const [typeFilter, setTypeFilter] = useState("all");
1949
+ const queryFilters = useMemo(() => {
1950
+ const filters = {};
1951
+ if (statusFilter !== "all") {
1952
+ filters.status = statusFilter;
1953
+ }
1954
+ return filters;
1955
+ }, [statusFilter]);
1956
+ const { data, isLoading, error } = useListSchedules(queryFilters);
1957
+ const pauseSchedule = usePauseSchedule();
1958
+ const resumeSchedule = useResumeSchedule();
1959
+ const cancelSchedule = useCancelSchedule();
1960
+ const deleteSchedule = useDeleteSchedule();
1961
+ const filteredSchedules = useMemo(() => {
1962
+ if (!data?.schedules) return [];
1963
+ if (typeFilter === "all") return data.schedules;
1964
+ return data.schedules.filter((s) => s.scheduleConfig.type === typeFilter);
1965
+ }, [data?.schedules, typeFilter]);
1966
+ const isActionLoading = pauseSchedule.isPending || resumeSchedule.isPending || cancelSchedule.isPending || deleteSchedule.isPending;
1967
+ const schedulesByType = useMemo(() => {
1968
+ if (!data?.schedules) return { recurring: 0, relative: 0, absolute: 0 };
1969
+ return data.schedules.reduce(
1970
+ (acc, s) => {
1971
+ acc[s.scheduleConfig.type]++;
1972
+ return acc;
1973
+ },
1974
+ { recurring: 0, relative: 0, absolute: 0 }
1975
+ );
1976
+ }, [data?.schedules]);
1977
+ const schedulesByStatus = useMemo(() => {
1978
+ if (!data?.schedules) return { active: 0, paused: 0, completed: 0, cancelled: 0 };
1979
+ return data.schedules.reduce(
1980
+ (acc, s) => {
1981
+ if (s.status === "active") acc.active++;
1982
+ else if (s.status === "paused") acc.paused++;
1983
+ else if (s.status === "completed") acc.completed++;
1984
+ else if (s.status === "cancelled") acc.cancelled++;
1985
+ return acc;
1986
+ },
1987
+ { active: 0, paused: 0, completed: 0, cancelled: 0 }
1988
+ );
1989
+ }, [data?.schedules]);
1990
+ const { data: resourcesData } = useResources();
1991
+ const resourceStatusMap = useMemo(() => {
1992
+ const map = /* @__PURE__ */ new Map();
1993
+ if (!resourcesData) return map;
1994
+ for (const w of resourcesData.workflows) map.set(w.resourceId, w.status);
1995
+ for (const a of resourcesData.agents) map.set(a.resourceId, a.status);
1996
+ return map;
1997
+ }, [resourcesData]);
1998
+ const handleCardClick = useCallback((schedule) => {
1999
+ setSelectedSchedule(schedule);
2000
+ }, []);
2001
+ if (isLoading || !isReady) {
2002
+ return /* @__PURE__ */ jsx(AppShellLoader, {});
2003
+ }
2004
+ const handlePause = async (scheduleId) => {
2005
+ await pauseSchedule.mutateAsync(scheduleId);
2006
+ };
2007
+ const handleResume = async (scheduleId) => {
2008
+ await resumeSchedule.mutateAsync(scheduleId);
2009
+ };
2010
+ const handleCancel = async (scheduleId) => {
2011
+ await cancelSchedule.mutateAsync(scheduleId);
2012
+ };
2013
+ const handleDelete = (scheduleId) => {
2014
+ const schedule = data?.schedules.find((s) => s.id === scheduleId);
2015
+ if (schedule) {
2016
+ setScheduleToDelete(schedule);
2017
+ setIsDeleteModalOpen(true);
2018
+ }
2019
+ };
2020
+ const handleConfirmDelete = async () => {
2021
+ if (scheduleToDelete) {
2022
+ await deleteSchedule.mutateAsync(scheduleToDelete.id);
2023
+ setIsDeleteModalOpen(false);
2024
+ setScheduleToDelete(null);
2025
+ }
2026
+ };
2027
+ const handleCloseDeleteModal = () => {
2028
+ setIsDeleteModalOpen(false);
2029
+ setScheduleToDelete(null);
2030
+ };
2031
+ const formatNextRun2 = (schedule) => {
2032
+ if (!schedule.nextRunAt) return "Not scheduled";
2033
+ const date = typeof schedule.nextRunAt === "string" ? new Date(schedule.nextRunAt) : schedule.nextRunAt;
2034
+ const now = /* @__PURE__ */ new Date();
2035
+ const diffMs = date.getTime() - now.getTime();
2036
+ const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
2037
+ if (diffMs < 0) return "Overdue";
2038
+ if (diffDays === 0) {
2039
+ return `Today at ${date.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })}`;
2040
+ } else if (diffDays === 1) {
2041
+ return `Tomorrow at ${date.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })}`;
2042
+ } else if (diffDays > 0 && diffDays <= 7) {
2043
+ return `In ${diffDays} days at ${date.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })}`;
2044
+ } else {
2045
+ return date.toLocaleString("en-US", {
2046
+ month: "short",
2047
+ day: "numeric",
2048
+ hour: "numeric",
2049
+ minute: "2-digit"
2050
+ });
2051
+ }
2052
+ };
2053
+ const groupByTimeBucket = (schedules) => {
2054
+ const now = /* @__PURE__ */ new Date();
2055
+ const buckets = {
2056
+ today: [],
2057
+ tomorrow: [],
2058
+ thisWeek: [],
2059
+ later: [],
2060
+ noNextRun: []
2061
+ };
2062
+ schedules.forEach((schedule) => {
2063
+ if (!schedule.nextRunAt) {
2064
+ buckets.noNextRun.push(schedule);
2065
+ return;
2066
+ }
2067
+ const nextRun = typeof schedule.nextRunAt === "string" ? new Date(schedule.nextRunAt) : schedule.nextRunAt;
2068
+ const diffMs = nextRun.getTime() - now.getTime();
2069
+ const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
2070
+ if (diffDays < 0) {
2071
+ buckets.today.push(schedule);
2072
+ } else if (diffDays === 0) {
2073
+ buckets.today.push(schedule);
2074
+ } else if (diffDays === 1) {
2075
+ buckets.tomorrow.push(schedule);
2076
+ } else if (diffDays <= 7) {
2077
+ buckets.thisWeek.push(schedule);
2078
+ } else {
2079
+ buckets.later.push(schedule);
2080
+ }
2081
+ });
2082
+ return buckets;
2083
+ };
2084
+ if (error) {
2085
+ return /* @__PURE__ */ jsx(Paper, { children: /* @__PURE__ */ jsx(CenteredErrorState, { error, title: "Failed to load schedules" }) });
2086
+ }
2087
+ const timeBuckets = groupByTimeBucket(filteredSchedules);
2088
+ const renderScheduleCards = (schedules) => schedules.map((schedule) => /* @__PURE__ */ jsx(
2089
+ ScheduleCard,
2090
+ {
2091
+ schedule,
2092
+ resourceStatus: resourceStatusMap.get(schedule.target.resourceId),
2093
+ onPause: handlePause,
2094
+ onResume: handleResume,
2095
+ onCancel: handleCancel,
2096
+ onDelete: handleDelete,
2097
+ onClick: handleCardClick,
2098
+ isLoading: isActionLoading
2099
+ },
2100
+ schedule.id
2101
+ ));
2102
+ return /* @__PURE__ */ jsxs(Stack, { children: [
2103
+ /* @__PURE__ */ jsx(
2104
+ PageTitleCaption,
2105
+ {
2106
+ title: "Task Scheduler",
2107
+ caption: "Schedule agents and workflows to run automatically",
2108
+ rightSection: /* @__PURE__ */ jsx(
2109
+ SegmentedControl,
2110
+ {
2111
+ value: viewMode,
2112
+ onChange: (value) => setViewMode(value),
2113
+ data: [
2114
+ { label: "Buckets", value: "buckets" },
2115
+ { label: "Timeline", value: "timeline" }
2116
+ ]
2117
+ }
2118
+ )
2119
+ }
2120
+ ),
2121
+ /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 2, sm: 5 }, children: [
2122
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Active", value: schedulesByStatus.active, icon: IconCalendarEvent }),
2123
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Paused", value: schedulesByStatus.paused, icon: IconCalendarDue }),
2124
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Completed", value: schedulesByStatus.completed, icon: IconCalendarStats }),
2125
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Cancelled", value: schedulesByStatus.cancelled, icon: IconCalendarOff }),
2126
+ /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Total", value: data?.schedules.length || 0, icon: IconListCheck })
2127
+ ] }),
2128
+ /* @__PURE__ */ jsx(Paper, { children: /* @__PURE__ */ jsxs(Stack, { children: [
2129
+ /* @__PURE__ */ jsxs(
2130
+ FilterBar,
2131
+ {
2132
+ actions: /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
2133
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", variant: "light", leftSection: /* @__PURE__ */ jsx(IconCalendarRepeat, { size: 12 }), children: [
2134
+ schedulesByType.recurring,
2135
+ " Recurring"
2136
+ ] }),
2137
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", variant: "light", leftSection: /* @__PURE__ */ jsx(IconCalendarEvent, { size: 12 }), children: [
2138
+ schedulesByType.relative,
2139
+ " Relative"
2140
+ ] }),
2141
+ /* @__PURE__ */ jsxs(Badge, { size: "sm", variant: "light", leftSection: /* @__PURE__ */ jsx(IconCalendarTime, { size: 12 }), children: [
2142
+ schedulesByType.absolute,
2143
+ " Absolute"
2144
+ ] })
2145
+ ] }),
2146
+ children: [
2147
+ /* @__PURE__ */ jsx(
2148
+ Select,
2149
+ {
2150
+ size: "sm",
2151
+ placeholder: "Status",
2152
+ data: [
2153
+ { value: "all", label: "All Statuses" },
2154
+ { value: "active", label: "Active" },
2155
+ { value: "paused", label: "Paused" },
2156
+ { value: "completed", label: "Completed" },
2157
+ { value: "cancelled", label: "Cancelled" }
2158
+ ],
2159
+ value: statusFilter,
2160
+ onChange: (v) => setStatusFilter(v || "all"),
2161
+ clearable: false,
2162
+ style: { minWidth: 150 }
2163
+ }
2164
+ ),
2165
+ /* @__PURE__ */ jsx(
2166
+ Select,
2167
+ {
2168
+ size: "sm",
2169
+ placeholder: "Type",
2170
+ data: [
2171
+ { value: "all", label: "All Types" },
2172
+ { value: "recurring", label: "Recurring" },
2173
+ { value: "relative", label: "Relative" },
2174
+ { value: "absolute", label: "Absolute" }
2175
+ ],
2176
+ value: typeFilter,
2177
+ onChange: (v) => setTypeFilter(v || "all"),
2178
+ clearable: false,
2179
+ style: { minWidth: 150 }
2180
+ }
2181
+ )
2182
+ ]
2183
+ }
2184
+ ),
2185
+ viewMode === "timeline" && filteredSchedules.length > 0 && /* @__PURE__ */ jsxs(Stack, { children: [
2186
+ /* @__PURE__ */ jsx(CardHeader, { icon: /* @__PURE__ */ jsx(IconCalendarEvent, { size: 18 }), title: "All Schedules" }),
2187
+ /* @__PURE__ */ jsx(Timeline, { bulletSize: 24, lineWidth: 2, children: [...filteredSchedules].sort((a, b) => {
2188
+ const aDate = a.nextRunAt ? typeof a.nextRunAt === "string" ? new Date(a.nextRunAt) : a.nextRunAt : new Date(9999, 0);
2189
+ const bDate = b.nextRunAt ? typeof b.nextRunAt === "string" ? new Date(b.nextRunAt) : b.nextRunAt : new Date(9999, 0);
2190
+ return aDate.getTime() - bDate.getTime();
2191
+ }).map((schedule) => {
2192
+ const nextRun = schedule.nextRunAt ? typeof schedule.nextRunAt === "string" ? new Date(schedule.nextRunAt) : schedule.nextRunAt : null;
2193
+ const isOverdue = nextRun && nextRun.getTime() < Date.now();
2194
+ return /* @__PURE__ */ jsxs(
2195
+ Timeline.Item,
2196
+ {
2197
+ style: { cursor: "pointer" },
2198
+ onClick: () => handleCardClick(schedule),
2199
+ bullet: /* @__PURE__ */ jsx(ThemeIcon, { size: 24, radius: "xl", children: /* @__PURE__ */ jsx(IconClock, { size: 12 }) }),
2200
+ title: /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
2201
+ /* @__PURE__ */ jsx(Text, { fw: 600, style: { fontFamily: "var(--mantine-font-family-headings)" }, children: schedule.name }),
2202
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
2203
+ /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: isOverdue ? "orange" : void 0, children: formatNextRun2(schedule) }),
2204
+ /* @__PURE__ */ jsx(
2205
+ Badge,
2206
+ {
2207
+ size: "sm",
2208
+ variant: "light",
2209
+ color: schedule.status === "active" ? "green" : "yellow",
2210
+ children: schedule.status
2211
+ }
2212
+ )
2213
+ ] })
2214
+ ] }),
2215
+ children: [
2216
+ schedule.description && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", mt: 4, children: schedule.description }),
2217
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", mt: "xs", children: [
2218
+ /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", children: schedule.target.resourceType }),
2219
+ /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "outline", children: schedule.scheduleConfig.type })
2220
+ ] })
2221
+ ]
2222
+ },
2223
+ schedule.id
2224
+ );
2225
+ }) })
2226
+ ] }),
2227
+ viewMode === "buckets" && /* @__PURE__ */ jsxs(Fragment, { children: [
2228
+ timeBuckets.today.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2229
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2230
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Today" }),
2231
+ /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", children: timeBuckets.today.length })
2232
+ ] }),
2233
+ renderScheduleCards(timeBuckets.today)
2234
+ ] }),
2235
+ timeBuckets.tomorrow.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2236
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2237
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Tomorrow" }),
2238
+ /* @__PURE__ */ jsx(Badge, { color: "orange", size: "sm", variant: "light", children: timeBuckets.tomorrow.length })
2239
+ ] }),
2240
+ renderScheduleCards(timeBuckets.tomorrow)
2241
+ ] }),
2242
+ timeBuckets.thisWeek.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2243
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2244
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "This Week" }),
2245
+ /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", children: timeBuckets.thisWeek.length })
2246
+ ] }),
2247
+ renderScheduleCards(timeBuckets.thisWeek)
2248
+ ] }),
2249
+ timeBuckets.later.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2250
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2251
+ /* @__PURE__ */ jsx(Title, { order: 4, children: "Later" }),
2252
+ /* @__PURE__ */ jsx(Badge, { color: "gray", size: "sm", variant: "light", children: timeBuckets.later.length })
2253
+ ] }),
2254
+ renderScheduleCards(timeBuckets.later)
2255
+ ] }),
2256
+ timeBuckets.noNextRun.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2257
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2258
+ /* @__PURE__ */ jsx(Text, { fw: 600, size: "md", c: "dimmed", children: "No Scheduled Run" }),
2259
+ /* @__PURE__ */ jsx(Badge, { color: "gray", size: "sm", variant: "light", children: timeBuckets.noNextRun.length })
2260
+ ] }),
2261
+ renderScheduleCards(timeBuckets.noNextRun)
2262
+ ] })
2263
+ ] }),
2264
+ filteredSchedules.length === 0 && /* @__PURE__ */ jsx(
2265
+ EmptyState,
2266
+ {
2267
+ icon: IconClock,
2268
+ title: "No schedules found",
2269
+ description: statusFilter !== "all" || typeFilter !== "all" ? "No schedules match your filters. Try adjusting the filters or create a new schedule." : "No schedules yet. Use the CLI to create automated task execution."
2270
+ }
2271
+ )
2272
+ ] }) }),
2273
+ /* @__PURE__ */ jsx(CreateScheduleModal, { opened: isModalOpen, onClose: () => setIsModalOpen(false) }),
2274
+ /* @__PURE__ */ jsx(
2275
+ DeleteScheduleModal,
2276
+ {
2277
+ opened: isDeleteModalOpen,
2278
+ onClose: handleCloseDeleteModal,
2279
+ onConfirm: handleConfirmDelete,
2280
+ schedule: scheduleToDelete,
2281
+ isDeleting: deleteSchedule.isPending
2282
+ }
2283
+ ),
2284
+ /* @__PURE__ */ jsx(
2285
+ ScheduleDetailModal,
2286
+ {
2287
+ opened: !!selectedSchedule,
2288
+ onClose: () => setSelectedSchedule(null),
2289
+ schedule: selectedSchedule,
2290
+ resourceStatus: selectedSchedule ? resourceStatusMap.get(selectedSchedule.target.resourceId) : void 0
2291
+ }
2292
+ )
2293
+ ] });
2294
+ };
2295
+ function RichTextEditor({ content, onChange, placeholder }) {
2296
+ const editor = useEditor({
2297
+ extensions: [
2298
+ StarterKit,
2299
+ Link,
2300
+ Placeholder.configure({
2301
+ placeholder: placeholder || "Write something..."
2302
+ })
2303
+ ],
2304
+ content,
2305
+ onUpdate: ({ editor: editor2 }) => onChange(editor2.getHTML())
2306
+ });
2307
+ return /* @__PURE__ */ jsxs(RichTextEditor$1, { editor, children: [
2308
+ /* @__PURE__ */ jsxs(RichTextEditor$1.Toolbar, { sticky: true, stickyOffset: 60, children: [
2309
+ /* @__PURE__ */ jsxs(RichTextEditor$1.ControlsGroup, { children: [
2310
+ /* @__PURE__ */ jsx(RichTextEditor$1.Bold, {}),
2311
+ /* @__PURE__ */ jsx(RichTextEditor$1.Italic, {}),
2312
+ /* @__PURE__ */ jsx(RichTextEditor$1.Strikethrough, {})
2313
+ ] }),
2314
+ /* @__PURE__ */ jsxs(RichTextEditor$1.ControlsGroup, { children: [
2315
+ /* @__PURE__ */ jsx(RichTextEditor$1.H2, {}),
2316
+ /* @__PURE__ */ jsx(RichTextEditor$1.H3, {})
2317
+ ] }),
2318
+ /* @__PURE__ */ jsxs(RichTextEditor$1.ControlsGroup, { children: [
2319
+ /* @__PURE__ */ jsx(RichTextEditor$1.BulletList, {}),
2320
+ /* @__PURE__ */ jsx(RichTextEditor$1.OrderedList, {})
2321
+ ] }),
2322
+ /* @__PURE__ */ jsxs(RichTextEditor$1.ControlsGroup, { children: [
2323
+ /* @__PURE__ */ jsx(RichTextEditor$1.Link, {}),
2324
+ /* @__PURE__ */ jsx(RichTextEditor$1.Unlink, {})
2325
+ ] })
2326
+ ] }),
2327
+ /* @__PURE__ */ jsx(RichTextEditor$1.Content, {})
2328
+ ] });
2329
+ }
2330
+
2331
+ // ../../node_modules/.pnpm/@mdx-js+mdx@3.1.1/node_modules/@mdx-js/mdx/lib/run.js
2332
+ var AsyncFunction = Object.getPrototypeOf(run).constructor;
2333
+ async function run(code, options) {
2334
+ return new AsyncFunction(String(code))(options);
2335
+ }
2336
+ var customCodeTheme = Object.fromEntries(
2337
+ Object.entries(oneDark).map(([key, value]) => [
2338
+ key,
2339
+ typeof value === "object" && value !== null ? { ...value, background: "none", backgroundColor: "none" } : value
2340
+ ])
2341
+ );
2342
+ function Callout({ type = "info", children }) {
2343
+ const colorMap = { info: "blue", warning: "yellow", error: "red" };
2344
+ const color = colorMap[type] ?? "blue";
2345
+ return /* @__PURE__ */ jsx(
2346
+ Paper,
2347
+ {
2348
+ withBorder: true,
2349
+ p: "sm",
2350
+ my: "xs",
2351
+ style: {
2352
+ borderLeft: `3px solid var(--mantine-color-${color}-6)`,
2353
+ backgroundColor: `var(--mantine-color-${color}-light)`
2354
+ },
2355
+ children
2356
+ }
2357
+ );
2358
+ }
2359
+ function TabsWrapper({ children }) {
2360
+ const tabs = [];
2361
+ const childArray = Array.isArray(children) ? children : [children];
2362
+ for (const child of childArray) {
2363
+ if (child && typeof child === "object" && "props" in child && child.props?.label) {
2364
+ tabs.push({ label: child.props.label, content: child.props.children });
2365
+ }
2366
+ }
2367
+ if (tabs.length === 0) return /* @__PURE__ */ jsx(Fragment, { children });
2368
+ return /* @__PURE__ */ jsxs(Tabs, { defaultValue: tabs[0]?.label, my: "xs", children: [
2369
+ /* @__PURE__ */ jsx(Tabs.List, { children: tabs.map((tab) => /* @__PURE__ */ jsx(Tabs.Tab, { value: tab.label, children: tab.label }, tab.label)) }),
2370
+ tabs.map((tab) => /* @__PURE__ */ jsx(Tabs.Panel, { value: tab.label, pt: "xs", children: tab.content }, tab.label))
2371
+ ] });
2372
+ }
2373
+ function Tab({ children }) {
2374
+ return /* @__PURE__ */ jsx(Fragment, { children });
2375
+ }
2376
+ function slugify(text) {
2377
+ return String(text).toLowerCase().replace(/[^\w\s-]/g, "").replace(/\s+/g, "-").trim();
2378
+ }
2379
+ var mdxComponents = {
2380
+ h1: ({ children }) => /* @__PURE__ */ jsx(Title, { order: 3, id: slugify(children), mb: "xs", mt: "md", children }),
2381
+ h2: ({ children }) => /* @__PURE__ */ jsx(Title, { order: 3, id: slugify(children), mb: "xs", mt: "sm", children }),
2382
+ p: ({ children }) => /* @__PURE__ */ jsx(
2383
+ "p",
2384
+ {
2385
+ style: {
2386
+ margin: "0.5rem 0",
2387
+ fontSize: "var(--mantine-font-size-md)",
2388
+ lineHeight: 1.65,
2389
+ color: "var(--color-text-dimmed)"
2390
+ },
2391
+ children
2392
+ }
2393
+ ),
2394
+ ul: ({ children }) => /* @__PURE__ */ jsx("ul", { style: { margin: "0.5rem 0", paddingLeft: "1.5rem" }, children }),
2395
+ ol: ({ children }) => /* @__PURE__ */ jsx("ol", { style: { margin: "0.5rem 0", paddingLeft: "1.5rem" }, children }),
2396
+ li: ({ children }) => /* @__PURE__ */ jsx("li", { style: { marginBottom: "0.25rem", fontSize: "var(--mantine-font-size-md)", color: "var(--color-text-dimmed)" }, children }),
2397
+ code: ({ className, children }) => {
2398
+ const match = /language-(\w+)/.exec(className || "");
2399
+ const codeString = String(children).replace(/\n$/, "");
2400
+ if (match) {
2401
+ return /* @__PURE__ */ jsx(
2402
+ Prism,
2403
+ {
2404
+ style: customCodeTheme,
2405
+ language: match[1],
2406
+ PreTag: "div",
2407
+ customStyle: {
2408
+ margin: "0.5rem 0",
2409
+ borderRadius: "var(--mantine-radius-default)",
2410
+ fontSize: "0.8rem"
2411
+ },
2412
+ children: codeString
2413
+ }
2414
+ );
2415
+ }
2416
+ return /* @__PURE__ */ jsx(Code, { children });
2417
+ },
2418
+ pre: ({ children }) => /* @__PURE__ */ jsx(ScrollArea, { type: "auto", my: "xs", children }),
2419
+ hr: () => /* @__PURE__ */ jsx(
2420
+ "hr",
2421
+ {
2422
+ style: {
2423
+ border: "none",
2424
+ borderTop: "1px solid var(--color-border)",
2425
+ margin: "1rem 0"
2426
+ }
2427
+ }
2428
+ ),
2429
+ blockquote: ({ children }) => /* @__PURE__ */ jsx(
2430
+ Paper,
2431
+ {
2432
+ withBorder: true,
2433
+ p: "sm",
2434
+ my: "xs",
2435
+ style: {
2436
+ borderLeft: "3px solid var(--color-primary)",
2437
+ backgroundColor: "var(--color-surface)"
2438
+ },
2439
+ children
2440
+ }
2441
+ ),
2442
+ table: ({ children }) => /* @__PURE__ */ jsx(ScrollArea, { type: "auto", my: "xs", children: /* @__PURE__ */ jsx(
2443
+ Table,
2444
+ {
2445
+ striped: true,
2446
+ highlightOnHover: true,
2447
+ withTableBorder: true,
2448
+ withColumnBorders: true,
2449
+ fz: "sm",
2450
+ styles: {
2451
+ table: {
2452
+ "--table-border-color": "var(--color-border)",
2453
+ "--table-striped-color": "var(--color-surface-hover)",
2454
+ "--table-highlight-on-hover-color": "var(--color-surface-hover)"
2455
+ }
2456
+ },
2457
+ children
2458
+ }
2459
+ ) }),
2460
+ thead: ({ children }) => /* @__PURE__ */ jsx(Table.Thead, { children }),
2461
+ tbody: ({ children }) => /* @__PURE__ */ jsx(Table.Tbody, { children }),
2462
+ tr: ({ children }) => /* @__PURE__ */ jsx(Table.Tr, { children }),
2463
+ th: ({ children }) => /* @__PURE__ */ jsx(Table.Th, { style: { whiteSpace: "nowrap" }, children }),
2464
+ td: ({ children }) => /* @__PURE__ */ jsx(Table.Td, { style: { color: "var(--color-text-dimmed)" }, children }),
2465
+ Callout,
2466
+ Tabs: TabsWrapper,
2467
+ Tab
2468
+ };
2469
+ function MdxRenderer({ compiledSource }) {
2470
+ const [Content, setContent] = useState(null);
2471
+ const [error, setError] = useState(null);
2472
+ useEffect(() => {
2473
+ let cancelled = false;
2474
+ run(compiledSource, { ...runtime, baseUrl: import.meta.url }).then((mod) => {
2475
+ if (!cancelled) setContent(() => mod.default);
2476
+ }).catch((err) => {
2477
+ if (!cancelled) setError(err instanceof Error ? err.message : String(err));
2478
+ });
2479
+ return () => {
2480
+ cancelled = true;
2481
+ };
2482
+ }, [compiledSource]);
2483
+ if (error) {
2484
+ return /* @__PURE__ */ jsxs("div", { style: { color: "var(--color-error)", padding: "1rem" }, children: [
2485
+ "Error rendering documentation: ",
2486
+ error
2487
+ ] });
2488
+ }
2489
+ if (!Content) return null;
2490
+ return /* @__PURE__ */ jsx(Content, { components: mdxComponents });
2491
+ }
2492
+ var Breadcrumbs = (props) => {
2493
+ const { Link: Link2 } = useRouterContext();
2494
+ const breadcrumbs = useBreadcrumbs(props);
2495
+ const items = breadcrumbs.map((item) => {
2496
+ const isActive = item.isActive;
2497
+ if (isActive) {
2498
+ return /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, c: "var(--color-text)", children: item.label }, item.path || item.label);
2499
+ }
2500
+ return item.path ? /* @__PURE__ */ jsx(
2501
+ Text,
2502
+ {
2503
+ component: Link2,
2504
+ to: item.path,
2505
+ size: "sm",
2506
+ c: "var(--color-text-subtle)",
2507
+ style: {
2508
+ textDecoration: "none",
2509
+ fontWeight: 500
2510
+ },
2511
+ children: item.label
2512
+ },
2513
+ item.path
2514
+ ) : /* @__PURE__ */ jsx(Text, { size: "sm", c: "var(--color-text-subtle)", children: item.label }, item.label);
2515
+ });
2516
+ return /* @__PURE__ */ jsx(
2517
+ Breadcrumbs$1,
2518
+ {
2519
+ separator: "/",
2520
+ styles: {
2521
+ separator: {
2522
+ color: "var(--color-text-subtle)"
2523
+ }
2524
+ },
2525
+ children: items
2526
+ }
2527
+ );
2528
+ };
2529
+ function formatStateLabel(stateKey) {
2530
+ if (!stateKey) return "No state";
2531
+ return stateKey.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
2532
+ }
2533
+ function DealKanbanCard({ deal, config, onClick, onDragStart, onDragEnd }) {
2534
+ const contactFirstName = deal.contact?.first_name || "";
2535
+ const contactLastName = deal.contact?.last_name || "";
2536
+ const contactName = [contactFirstName, contactLastName].filter(Boolean).join(" ");
2537
+ const displayName = contactName || deal.contact_email || "Unknown";
2538
+ const companyName = deal.contact?.company?.name || deal.discovery_data?.company || deal.contact_email?.split("@")[1] || null;
2539
+ const hasInitialFee = typeof deal.initial_fee === "number" && deal.initial_fee > 0;
2540
+ const hasMonthlyFee = typeof deal.monthly_fee === "number" && deal.monthly_fee > 0;
2541
+ const stageColor = (deal.stage_key ? config[deal.stage_key]?.color : null) ?? "gray";
2542
+ const stateLabel = formatStateLabel(deal.state_key);
2543
+ return /* @__PURE__ */ jsx(
2544
+ Paper,
2545
+ {
2546
+ p: "sm",
2547
+ style: {
2548
+ border: "1px solid var(--color-border)",
2549
+ borderLeft: `3px solid var(--mantine-color-${stageColor}-6)`,
2550
+ cursor: "grab",
2551
+ userSelect: "none",
2552
+ transition: `all var(--duration-fast) var(--easing)`
2553
+ },
2554
+ draggable: true,
2555
+ onDragStart: (e) => onDragStart(e, deal),
2556
+ onDragEnd,
2557
+ onClick: () => onClick(deal),
2558
+ children: /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
2559
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", gap: "xs", wrap: "nowrap", children: [
2560
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, lineClamp: 1, style: { minWidth: 0, flex: 1 }, children: displayName }),
2561
+ /* @__PURE__ */ jsx(Tooltip, { label: deal.priority.reason, withArrow: true, children: /* @__PURE__ */ jsx(
2562
+ Badge,
2563
+ {
2564
+ variant: "light",
2565
+ size: "xs",
2566
+ color: deal.priority.color,
2567
+ style: { flexShrink: 0, maxWidth: 112, textTransform: "none" },
2568
+ children: /* @__PURE__ */ jsx(Box, { component: "span", style: { display: "block", maxWidth: 88, overflow: "hidden", textOverflow: "ellipsis" }, children: deal.priority.label })
2569
+ }
2570
+ ) })
2571
+ ] }),
2572
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", lineClamp: 1, children: [
2573
+ "State: ",
2574
+ stateLabel
2575
+ ] }),
2576
+ companyName && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", lineClamp: 1, children: companyName }),
2577
+ /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "wrap", children: [
2578
+ hasInitialFee && /* @__PURE__ */ jsxs(Badge, { variant: "outline", size: "xs", color: "green", children: [
2579
+ "$",
2580
+ deal.initial_fee.toLocaleString()
2581
+ ] }),
2582
+ hasMonthlyFee && /* @__PURE__ */ jsxs(Badge, { variant: "outline", size: "xs", color: "teal", children: [
2583
+ "$",
2584
+ deal.monthly_fee.toLocaleString(),
2585
+ "/mo"
2586
+ ] })
2587
+ ] }),
2588
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatTimeAgo(deal.updated_at) })
2589
+ ] })
2590
+ }
2591
+ );
2592
+ }
2593
+ var UNSTAGED_KEY = "unstaged";
2594
+ var KANBAN_FETCH_LIMIT = 250;
2595
+ function formatStageLabel(stage) {
2596
+ if (stage === UNSTAGED_KEY) return "Unstaged";
2597
+ return stage.split("_").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
2598
+ }
2599
+ function groupDealsByStage(deals, columns) {
2600
+ const map = /* @__PURE__ */ new Map();
2601
+ for (const stage of columns) map.set(stage, []);
2602
+ for (const deal of deals) {
2603
+ const key = deal.stage_key ?? UNSTAGED_KEY;
2604
+ const bucket = map.get(key);
2605
+ if (bucket) {
2606
+ bucket.push(deal);
2607
+ } else {
2608
+ map.get(UNSTAGED_KEY).push(deal);
2609
+ }
2610
+ }
2611
+ for (const bucket of map.values()) {
2612
+ bucket.sort((a, b) => compareDealsByPriority(a, b));
2613
+ }
2614
+ return map;
2615
+ }
2616
+ function KanbanBoard({ config }) {
2617
+ const navigate = useNavigate();
2618
+ const {
2619
+ data: deals,
2620
+ total,
2621
+ isLoading,
2622
+ error
2623
+ } = useDeals({
2624
+ limit: KANBAN_FETCH_LIMIT,
2625
+ offset: 0
2626
+ });
2627
+ const transitionItem = useTransitionItem();
2628
+ const queryClient = useQueryClient();
2629
+ const [dragOverColumn, setDragOverColumn] = useState(null);
2630
+ const draggingDealRef = useRef(null);
2631
+ const resolvedConfig = config ?? {};
2632
+ const configuredStages = Object.keys(resolvedConfig).filter(
2633
+ (stage) => Boolean(resolvedConfig[stage])
2634
+ );
2635
+ const columns = [...configuredStages, UNSTAGED_KEY];
2636
+ const hasConfig = configuredStages.length > 0;
2637
+ const groupedDeals = groupDealsByStage(deals ?? [], columns);
2638
+ const handleDragStart = useCallback((e, deal) => {
2639
+ draggingDealRef.current = deal;
2640
+ e.dataTransfer.effectAllowed = "move";
2641
+ e.dataTransfer.setData("text/plain", deal.id);
2642
+ }, []);
2643
+ const handleDragOver = useCallback((e, column) => {
2644
+ if (column === UNSTAGED_KEY) {
2645
+ e.dataTransfer.dropEffect = "none";
2646
+ return;
2647
+ }
2648
+ e.preventDefault();
2649
+ e.dataTransfer.dropEffect = "move";
2650
+ setDragOverColumn(column);
2651
+ }, []);
2652
+ const handleDragLeave = useCallback(() => {
2653
+ setDragOverColumn(null);
2654
+ }, []);
2655
+ const handleDrop = useCallback(
2656
+ (e, targetStage) => {
2657
+ e.preventDefault();
2658
+ setDragOverColumn(null);
2659
+ if (targetStage === UNSTAGED_KEY) return;
2660
+ const deal = draggingDealRef.current;
2661
+ draggingDealRef.current = null;
2662
+ if (!deal) return;
2663
+ if (deal.stage_key === targetStage) return;
2664
+ queryClient.setQueriesData({ queryKey: dealKeys.lists() }, (old) => {
2665
+ if (!old) return old;
2666
+ return {
2667
+ ...old,
2668
+ data: old.data.map((d) => d.id === deal.id ? { ...d, stage_key: targetStage } : d)
2669
+ };
2670
+ });
2671
+ transitionItem.mutate({ dealId: deal.id, pipelineKey: "crm", stageKey: targetStage });
2672
+ },
2673
+ [queryClient, transitionItem]
2674
+ );
2675
+ const handleDragEnd = useCallback(() => {
2676
+ draggingDealRef.current = null;
2677
+ setDragOverColumn(null);
2678
+ }, []);
2679
+ const handleCardClick = useCallback(
2680
+ (deal) => {
2681
+ setDealReferrer("pipeline");
2682
+ void navigate({ to: "/crm/deals/$dealId", params: { dealId: deal.id } });
2683
+ },
2684
+ [navigate]
2685
+ );
2686
+ if (isLoading) {
2687
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(Center, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(Loader, {}) }) });
2688
+ }
2689
+ if (error) {
2690
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsx(Alert, { color: "red", children: "Failed to load deals" }) });
2691
+ }
2692
+ if (!hasConfig) {
2693
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
2694
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Pipeline", caption: "Kanban view of your deal pipeline" }),
2695
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, p: "xl", children: /* @__PURE__ */ jsx(Center, { py: "xl", children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", align: "center", children: [
2696
+ /* @__PURE__ */ jsx(Text, { fw: 600, children: "Configuration Required" }),
2697
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", ta: "center", children: "Provide a kanban stage config before rendering the pipeline board." })
2698
+ ] }) }) })
2699
+ ] }) });
2700
+ }
2701
+ return /* @__PURE__ */ jsx(SubshellContentContainer, { children: /* @__PURE__ */ jsxs(Stack, { children: [
2702
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Pipeline", caption: "Kanban view of your deal pipeline" }),
2703
+ total > deals.length && /* @__PURE__ */ jsxs(Alert, { color: "yellow", variant: "light", children: [
2704
+ "Showing the first ",
2705
+ deals.length,
2706
+ " of ",
2707
+ total,
2708
+ " deals in the board. This view is temporarily bounded to the list endpoint until full-board pagination lands."
2709
+ ] }),
2710
+ /* @__PURE__ */ jsx(
2711
+ Paper,
2712
+ {
2713
+ p: "lg",
2714
+ style: {
2715
+ border: "1px solid var(--color-border)",
2716
+ overflow: "hidden"
2717
+ },
2718
+ children: /* @__PURE__ */ jsx(ScrollArea, { scrollbarSize: 8, type: "auto", children: /* @__PURE__ */ jsx(Group, { align: "flex-start", wrap: "nowrap", gap: "sm", style: { paddingBottom: 16, minWidth: "max-content" }, children: columns.map((columnKey) => {
2719
+ const columnDeals = groupedDeals.get(columnKey) ?? [];
2720
+ const isUnstaged = columnKey === UNSTAGED_KEY;
2721
+ const isDragTarget = dragOverColumn === columnKey;
2722
+ const badgeColor = isUnstaged ? "gray" : resolvedConfig[columnKey]?.color ?? "gray";
2723
+ return /* @__PURE__ */ jsx(
2724
+ Box,
2725
+ {
2726
+ style: {
2727
+ width: 260,
2728
+ minWidth: 260,
2729
+ borderRadius: 8,
2730
+ padding: "10px 8px",
2731
+ backgroundColor: isDragTarget ? "color-mix(in srgb, var(--color-primary) 6%, transparent)" : "transparent",
2732
+ border: isDragTarget ? "1px solid var(--color-primary)" : "1px solid transparent",
2733
+ transition: `background-color var(--duration-fast) var(--easing), border-color var(--duration-fast) var(--easing)`
2734
+ },
2735
+ onDragOver: (e) => handleDragOver(e, columnKey),
2736
+ onDragLeave: handleDragLeave,
2737
+ onDrop: (e) => handleDrop(e, columnKey),
2738
+ children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2739
+ /* @__PURE__ */ jsx(Group, { justify: "space-between", wrap: "nowrap", children: /* @__PURE__ */ jsxs(Group, { gap: 6, children: [
2740
+ /* @__PURE__ */ jsx(
2741
+ Box,
2742
+ {
2743
+ w: 10,
2744
+ h: 10,
2745
+ style: {
2746
+ borderRadius: "50%",
2747
+ background: `var(--mantine-color-${badgeColor}-6)`,
2748
+ flexShrink: 0
2749
+ }
2750
+ }
2751
+ ),
2752
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, lineClamp: 1, children: formatStageLabel(columnKey) }),
2753
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: badgeColor, children: columnDeals.length })
2754
+ ] }) }),
2755
+ /* @__PURE__ */ jsx(Divider, {}),
2756
+ columnDeals.length === 0 && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", ta: "center", py: "md", style: { opacity: 0.5 }, children: isUnstaged ? "No unstaged deals" : "Drop here" }),
2757
+ /* @__PURE__ */ jsx(Stack, { gap: "xs", children: columnDeals.map((deal) => /* @__PURE__ */ jsx(
2758
+ DealKanbanCard,
2759
+ {
2760
+ deal,
2761
+ config: resolvedConfig,
2762
+ onClick: handleCardClick,
2763
+ onDragStart: handleDragStart,
2764
+ onDragEnd: handleDragEnd
2765
+ },
2766
+ deal.id
2767
+ )) })
2768
+ ] })
2769
+ },
2770
+ columnKey
2771
+ );
2772
+ }) }) })
2773
+ }
2774
+ )
2775
+ ] }) });
2776
+ }
2777
+
2778
+ // src/components/acquisition/kanban/constants.ts
2779
+ var DEAL_STAGES = ["interested", "proposal", "closing", "closed_won", "closed_lost", "nurturing"];
2780
+ var DEFAULT_KANBAN_CONFIG = {
2781
+ interested: { color: "blue" },
2782
+ proposal: { color: "yellow" },
2783
+ closing: { color: "lime" },
2784
+ closed_won: { color: "green" },
2785
+ closed_lost: { color: "red" },
2786
+ nurturing: { color: "grape" }
2787
+ };
2788
+
2789
+ export { AbsoluteScheduleForm, ApiKeyDisplayModal, ApiKeyList, ApiKeySettings, Breadcrumbs, CreateApiKeyModal, CreateRoleModal, CreateScheduleModal, DEAL_STAGES, DEFAULT_KANBAN_CONFIG, DealKanbanCard, DeleteScheduleModal, DeploymentDetailModal, DeploymentList, DeploymentSettings, DeploymentStatusBadge, EditApiKeyModal, KanbanBoard, MdxRenderer, NoAccessState, NotificationBell, NotificationPanel, PermissionMatrix, RecurringScheduleForm, RelativeScheduleForm, RichTextEditor, ScheduleCard, ScheduleDetailModal, ScheduleTypeSelector, TaskScheduler, mdxComponents };