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