@elevasis/ui 2.74.0 → 2.76.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 (105) 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/index.js +6 -7
  5. package/dist/charts/index.js +6 -7
  6. package/dist/{chunk-GO4XJ5D4.js → chunk-2GIHWU5O.js} +4 -3
  7. package/dist/chunk-2Y6AKWGU.js +42 -0
  8. package/dist/chunk-3QYRZSHP.js +854 -0
  9. package/dist/{chunk-CRA7WQZH.js → chunk-3RK2NNJX.js} +1 -1
  10. package/dist/{chunk-R6NMRXNO.js → chunk-4WLAVUPS.js} +1 -1
  11. package/dist/{chunk-GPQQGQGT.js → chunk-5R4I2PAN.js} +9 -43
  12. package/dist/{chunk-R5UGIFYU.js → chunk-5ZK7K7YP.js} +25 -1
  13. package/dist/chunk-6B4ZPBQJ.js +7 -0
  14. package/dist/{chunk-ARAFQBNI.js → chunk-73G3I5HJ.js} +160 -160
  15. package/dist/{chunk-ZWI62BQ6.js → chunk-BFLYDVEN.js} +32 -42
  16. package/dist/{chunk-W2QRBQQA.js → chunk-BG6PWDJ3.js} +381 -381
  17. package/dist/{chunk-7ARBBELS.js → chunk-BV2RNLPP.js} +1 -1
  18. package/dist/{chunk-FA7LMNQO.js → chunk-CTT4RDXE.js} +150 -151
  19. package/dist/chunk-E2LJ3FRA.js +237 -0
  20. package/dist/{chunk-E6YGA5WH.js → chunk-EFQLXRYT.js} +1 -2
  21. package/dist/{chunk-FZSG6M6W.js → chunk-EVNLJHDD.js} +3 -3
  22. package/dist/{chunk-ZYNVCWDZ.js → chunk-GDQQX5SL.js} +4 -42
  23. package/dist/{chunk-DCQKTDIG.js → chunk-GFSOQH3N.js} +1 -1
  24. package/dist/{chunk-3LOKYZJC.js → chunk-H5AEYSVX.js} +164 -3
  25. package/dist/{chunk-ZFISGKYW.js → chunk-IIEZXXDD.js} +1 -1
  26. package/dist/{chunk-3QHX4ZKV.js → chunk-INCEZAM3.js} +1 -1
  27. package/dist/{chunk-O32UQ26A.js → chunk-JZQNUQE4.js} +1 -1
  28. package/dist/{chunk-6JN2TLV2.js → chunk-K55TU6CC.js} +2023 -1700
  29. package/dist/chunk-KB5CAN5D.js +33 -0
  30. package/dist/{chunk-2MRRDF32.js → chunk-KMA4FOSV.js} +5682 -5675
  31. package/dist/{chunk-HYQOGRWG.js → chunk-KXNRTJAE.js} +1 -1
  32. package/dist/{chunk-7RJ7P6S6.js → chunk-MGAELVTZ.js} +12 -12
  33. package/dist/chunk-MKH2KOAO.js +39 -0
  34. package/dist/{chunk-4MXNHJTA.js → chunk-NAPXMYFW.js} +939 -1570
  35. package/dist/{chunk-CQPULKKL.js → chunk-OGG3QJYW.js} +14 -5
  36. package/dist/{chunk-4M2BSHVT.js → chunk-P6HHXMLJ.js} +1 -1
  37. package/dist/{chunk-WZU3MCKI.js → chunk-QAILYRC2.js} +1 -1
  38. package/dist/{chunk-RBGVNPA6.js → chunk-RXZ3XDBM.js} +1 -1
  39. package/dist/{chunk-BA3AZJUR.js → chunk-SPW6UA6B.js} +1 -1
  40. package/dist/{chunk-RFNJ2PTO.js → chunk-SVZR4GYA.js} +1 -1
  41. package/dist/{chunk-5A6KCFS5.js → chunk-UEY4AB3R.js} +789 -66
  42. package/dist/{chunk-LN4UW6S4.js → chunk-UL6MPMKY.js} +1 -1
  43. package/dist/{chunk-ZFA56VSR.js → chunk-WELN7DDV.js} +2 -2
  44. package/dist/{chunk-43LC6XAX.js → chunk-WJN2VVVJ.js} +1 -1
  45. package/dist/{chunk-BRTGCFBH.js → chunk-XODQUPFW.js} +11 -11
  46. package/dist/components/index.d.ts +181 -34
  47. package/dist/components/index.js +2249 -1804
  48. package/dist/components/navigation/index.js +7 -8
  49. package/dist/features/auth/index.d.ts +35 -3716
  50. package/dist/features/auth/index.js +9 -10
  51. package/dist/features/clients/index.js +18 -12
  52. package/dist/features/content/index.js +34 -31
  53. package/dist/features/crm/index.css +59 -59
  54. package/dist/features/crm/index.d.ts +18 -1
  55. package/dist/features/crm/index.js +13 -11
  56. package/dist/features/dashboard/index.css +59 -59
  57. package/dist/features/dashboard/index.js +8 -9
  58. package/dist/features/delivery/index.d.ts +3 -0
  59. package/dist/features/delivery/index.js +21 -20
  60. package/dist/features/knowledge/index.js +6 -7
  61. package/dist/features/lead-gen/index.css +59 -59
  62. package/dist/features/lead-gen/index.d.ts +3903 -2
  63. package/dist/features/lead-gen/index.js +15 -13
  64. package/dist/features/monitoring/index.js +10 -11
  65. package/dist/features/monitoring/requests/index.css +59 -59
  66. package/dist/features/monitoring/requests/index.js +8 -9
  67. package/dist/features/notes/index.js +4 -4
  68. package/dist/features/operations/index.css +59 -59
  69. package/dist/features/operations/index.js +13 -15
  70. package/dist/features/seo/index.css +659 -0
  71. package/dist/features/seo/index.d.ts +3962 -1
  72. package/dist/features/seo/index.js +31 -2
  73. package/dist/features/settings/index.css +59 -59
  74. package/dist/features/settings/index.d.ts +87 -3745
  75. package/dist/features/settings/index.js +10 -12
  76. package/dist/hooks/access/index.js +6 -7
  77. package/dist/hooks/delivery/index.css +59 -59
  78. package/dist/hooks/delivery/index.d.ts +13 -4
  79. package/dist/hooks/delivery/index.js +3 -3
  80. package/dist/hooks/published.d.ts +69 -27
  81. package/dist/hooks/published.js +19 -19
  82. package/dist/initialization/index.d.ts +35 -3716
  83. package/dist/knowledge/index.js +11 -11
  84. package/dist/layout/index.d.ts +55 -2
  85. package/dist/layout/index.js +10 -10
  86. package/dist/organization/index.css +59 -59
  87. package/dist/profile/index.d.ts +64 -3716
  88. package/dist/provider/index.d.ts +3 -0
  89. package/dist/provider/index.js +6 -7
  90. package/dist/provider/published.d.ts +3 -0
  91. package/dist/provider/published.js +6 -7
  92. package/dist/test-utils/index.js +3 -3
  93. package/dist/theme/index.js +3 -3
  94. package/dist/theme/presets/index.js +1 -1
  95. package/dist/types/index.d.ts +312 -251
  96. package/dist/utils/index.d.ts +1 -1
  97. package/dist/utils/index.js +1 -1
  98. package/package.json +9 -9
  99. package/src/hooks/README.md +22 -23
  100. package/dist/chunk-6ZAP3FOA.js +0 -93
  101. package/dist/chunk-AH52XQB7.js +0 -1
  102. package/dist/chunk-GDOR57D7.js +0 -165
  103. package/dist/chunk-MISHPEJX.js +0 -244
  104. package/dist/hooks/operations/command-view/utils/transformCommandViewData.d.ts +0 -879
  105. package/dist/hooks/operations/command-view/utils/transformCommandViewData.js +0 -2
@@ -1,59 +1,61 @@
1
- export { AppErrorBoundary, CrashErrorFallback, ErrorReportCard, buildErrorReport } from '../chunk-LN4UW6S4.js';
2
- import { useBreadcrumbs } from '../chunk-7ARBBELS.js';
3
- import '../chunk-AH52XQB7.js';
4
- import { showAuthError } from '../chunk-4MXNHJTA.js';
5
- export { CreateCredentialModal, CredentialList, CredentialSettings, MembershipStatusBadge, OAuthConnectModal, OrganizationMembershipsList, ProvisioningStateBadge, WebhookUrlDisplayModal, showAuthError } from '../chunk-4MXNHJTA.js';
6
- import '../chunk-ZFISGKYW.js';
7
- import '../chunk-GO4XJ5D4.js';
8
- import { setDealReferrer, compareDealsByPriority } from '../chunk-ZWI62BQ6.js';
9
- export { ActivityFeedWidget, CompanyDetailPage, ContactDetailPage, CrmOverview, CrmSidebar, CrmSidebarTop, DealDetailPage, DealsListPage, MetricsStrip, PIPELINE_FUNNEL_ORDER, PipelineFunnelWidget, useCrmPipelineSummary, useCrmQuickMetrics, useRecentCrmActivity } from '../chunk-ZWI62BQ6.js';
10
- export { AllTasksPage, HealthStatusCard, MilestoneTimeline, ProjectDetailPage, ProjectsListPage, ProjectsSidebar, ProjectsSidebarMiddle, ProjectsSidebarTop, TaskCard, UpcomingMilestonesPage } from '../chunk-7RJ7P6S6.js';
11
- import { useCreateOrgRole, useUpdateApiKey, useDeleteApiKey, useCreateApiKey, useListApiKeys, useActivateDeployment, useDeactivateDeployment, useDeleteDeployment, useListDeployments, useTransitionItem } from '../chunk-GPQQGQGT.js';
12
- import '../chunk-DCQKTDIG.js';
13
- import { usePermissionCatalog } from '../chunk-ARAFQBNI.js';
14
- import '../chunk-FZSG6M6W.js';
15
- export { LEAD_GEN_ROUTE_LINKS, LeadGenCompaniesPage, LeadGenContactsPage, LeadGenListDetailPage, LeadGenListsPage, LeadGenOverviewPage, LeadGenRouteShell, LeadGenSidebar, LeadGenSidebarTop, StepConfigForm, TabSection, getEnrichmentColor, getStatusColor, useDeleteLists } from '../chunk-5A6KCFS5.js';
16
- import '../chunk-ZFA56VSR.js';
17
- import '../chunk-GDOR57D7.js';
18
- import '../chunk-3LOKYZJC.js';
19
- import '../chunk-ZYNVCWDZ.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-2MRRDF32.js';
21
- import '../chunk-6ZAP3FOA.js';
22
- import '../chunk-BA3AZJUR.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-W2QRBQQA.js';
24
- import '../chunk-FA7LMNQO.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-CRA7WQZH.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-CQPULKKL.js';
31
- export { ActivityCard, ActivityFilters as ActivityFiltersBar, ActivityTable, BusinessImpactCard, CostBreakdownCard, CostByModelTable, CostMetricsCard, ErrorAnalysisCard, ErrorBreakdownTable, ExecutionBreakdownTable, ExecutionHealthCard, ExecutionLogsFilters as ExecutionLogsFilterBar, ExecutionLogsTable, NotificationItem, NotificationList } from '../chunk-CQPULKKL.js';
32
- import { useMarkAllAsRead, useNotifications } from '../chunk-BRTGCFBH.js';
33
- export { ResourceHealthPanel } from '../chunk-WZU3MCKI.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-43LC6XAX.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-E6YGA5WH.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-4M2BSHVT.js';
43
- import { useCloudStorageFolder, useCloudStorageThumbnails } from '../chunk-3QHX4ZKV.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-6JN2TLV2.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-6JN2TLV2.js';
50
- import '../chunk-R6NMRXNO.js';
51
- import '../chunk-RBGVNPA6.js';
52
- import '../chunk-O32UQ26A.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-HYQOGRWG.js';
55
- export { showApiErrorNotification, showErrorNotification, showInfoNotification, showSuccessNotification, showWarningNotification } from '../chunk-HYQOGRWG.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-R5UGIFYU.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, Badge, Pagination, SegmentedControl, Switch, Select, 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, 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,1276 +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;
584
+ ),
585
+ useCron ? /* @__PURE__ */ jsx(
586
+ TextInput,
587
+ {
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
517
594
  }
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." }),
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
+ )
620
+ ] }),
541
621
  /* @__PURE__ */ jsx(
542
- TextInput,
622
+ Select,
543
623
  {
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
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
551
640
  }
552
641
  ),
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
- ] }) }) });
642
+ /* @__PURE__ */ jsx(
643
+ TextInput,
644
+ {
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
650
+ }
651
+ )
652
+ ] });
559
653
  }
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": {...}}'` }) })
608
- ] }),
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
- ] }) });
654
+ function toDateTimeLocal2(isoString) {
655
+ if (!isoString) return "";
656
+ const date = new Date(isoString);
657
+ return date.toISOString().slice(0, 16);
611
658
  }
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);
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) });
621
667
  };
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: [
668
+ const handleItemChange = (index, updates) => {
669
+ const newItems = [...items];
670
+ newItems[index] = { ...newItems[index], ...updates };
671
+ onChange({ ...value, items: newItems });
672
+ };
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: [
630
682
  /* @__PURE__ */ jsx(
631
- PageTitleCaption,
683
+ TextInput,
632
684
  {
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" })
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
636
692
  }
637
693
  ),
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
694
  /* @__PURE__ */ jsx(
644
- CreateApiKeyModal,
695
+ TextInput,
645
696
  {
646
- opened: showCreateModal,
647
- onClose: () => setShowCreateModal(false),
648
- onSuccess: handleKeyCreated
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
649
702
  }
650
703
  ),
651
- newApiKey && /* @__PURE__ */ jsx(ApiKeyDisplayModal, { opened: true, apiKey: newApiKey, onClose: () => setNewApiKey(null) })
652
- ] });
653
- }
654
- var statusConfig = {
655
- active: { color: "green", label: "Active" },
656
- deploying: { color: "blue", label: "Deploying" },
657
- failed: { color: "red", label: "Failed" },
658
- stopped: { color: "gray", label: "Stopped" },
659
- rolled_back: { color: "yellow", label: "Rolled Back" }
660
- };
661
- function DeploymentStatusBadge({ status }) {
662
- const config = statusConfig[status] ?? { color: "gray", label: status };
663
- return /* @__PURE__ */ jsx(Badge, { variant: "light", color: config.color, size: "sm", children: config.label });
664
- }
665
- function DetailRow({ label, children }) {
666
- return /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
667
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", fw: 500, children: label }),
668
- /* @__PURE__ */ jsx("div", { children })
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(
727
+ ActionIcon,
728
+ {
729
+ size: "sm",
730
+ color: "red",
731
+ variant: "subtle",
732
+ onClick: () => handleRemoveItem(index),
733
+ disabled,
734
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 14 })
735
+ }
736
+ )
737
+ ] }),
738
+ /* @__PURE__ */ jsxs(Group, { grow: true, children: [
739
+ /* @__PURE__ */ jsx(
740
+ TextInput,
741
+ {
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
748
+ }
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
+ )
760
+ ] }),
761
+ /* @__PURE__ */ jsx(
762
+ Textarea,
763
+ {
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
776
+ }
777
+ )
778
+ ] }) }, index))
779
+ ] })
669
780
  ] });
670
781
  }
671
- function DeploymentDetailModal({ deployment, opened, onClose }) {
672
- if (!deployment) return null;
673
- return /* @__PURE__ */ jsx(CustomModal, { opened, onClose, size: "lg", children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", children: [
674
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
675
- /* @__PURE__ */ jsx(IconRocket, { size: 24, color: "var(--color-primary)" }),
676
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Deployment Details" })
677
- ] }),
678
- /* @__PURE__ */ jsx(DetailRow, { label: "ID", children: /* @__PURE__ */ jsx(Code, { children: deployment.id }) }),
679
- /* @__PURE__ */ jsx(DetailRow, { label: "Status", children: /* @__PURE__ */ jsx(DeploymentStatusBadge, { status: deployment.status }) }),
680
- /* @__PURE__ */ jsx(DetailRow, { label: "SDK Version", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: deployment.sdkVersion }) }),
681
- /* @__PURE__ */ jsx(DetailRow, { label: "Deployment Version", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: deployment.deploymentVersion ? `v${deployment.deploymentVersion}` : "\u2014" }) }),
682
- /* @__PURE__ */ jsx(DetailRow, { label: "Created", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: formatDateTime(deployment.createdAt) }) }),
683
- /* @__PURE__ */ jsx(DetailRow, { label: "Updated", children: /* @__PURE__ */ jsx(Text, { size: "sm", children: formatDateTime(deployment.updatedAt) }) }),
684
- deployment.tarballPath && /* @__PURE__ */ jsx(DetailRow, { label: "Bundle Path", children: /* @__PURE__ */ jsx(Code, { fz: "xs", children: deployment.tarballPath }) }),
685
- 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 }) })
686
- ] }) });
782
+ function toDateTimeLocal3(isoString) {
783
+ if (!isoString) return "";
784
+ const date = new Date(isoString);
785
+ return date.toISOString().slice(0, 16);
687
786
  }
688
- function DeploymentList({ deployments, isLoading }) {
689
- const [selected, setSelected] = useState(null);
690
- const [activateTarget, setActivateTarget] = useState(null);
691
- const [deactivateTarget, setDeactivateTarget] = useState(null);
692
- const [deleteTarget, setDeleteTarget] = useState(null);
693
- const { page, setPage, offset, totalPages } = usePaginationState(PAGE_SIZE_DEFAULT, void 0, deployments.length);
694
- const paginatedDeployments = deployments.slice(offset, offset + PAGE_SIZE_DEFAULT);
695
- const total = totalPages(deployments.length);
696
- const activateMutation = useActivateDeployment();
697
- const deactivateMutation = useDeactivateDeployment();
698
- const deleteMutation = useDeleteDeployment();
699
- const handleCloseActivate = () => {
700
- if (!activateMutation.isPending) setActivateTarget(null);
701
- };
702
- const handleCloseDeactivate = () => {
703
- if (!deactivateMutation.isPending) setDeactivateTarget(null);
704
- };
705
- const handleCloseDelete = () => {
706
- if (!deleteMutation.isPending) setDeleteTarget(null);
707
- };
708
- const handleConfirmActivate = () => {
709
- if (!activateTarget) return;
710
- activateMutation.mutate(activateTarget.id, { onSuccess: () => setActivateTarget(null) });
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 });
711
797
  };
712
- const handleConfirmDeactivate = () => {
713
- if (!deactivateTarget) return;
714
- deactivateMutation.mutate(deactivateTarget.id, { onSuccess: () => setDeactivateTarget(null) });
798
+ const handleAddItem = () => {
799
+ const newItems = [...items, { runAt: (/* @__PURE__ */ new Date()).toISOString(), payload: {}, label: "" }];
800
+ onChange({ ...value, items: newItems });
715
801
  };
716
- const handleConfirmDelete = () => {
717
- if (!deleteTarget) return;
718
- deleteMutation.mutate(deleteTarget.id, { onSuccess: () => setDeleteTarget(null) });
802
+ const handleRemoveItem = (index) => {
803
+ const newItems = items.filter((_, i) => i !== index);
804
+ onChange({ ...value, items: newItems });
719
805
  };
720
- if (isLoading) {
721
- return /* @__PURE__ */ jsx(ListSkeleton, { rows: 3, rowHeight: 50 });
722
- }
723
- if (deployments.length === 0) {
724
- return /* @__PURE__ */ jsx(
725
- EmptyState,
726
- {
727
- icon: IconRocket,
728
- title: "No deployments yet",
729
- description: "Deploy your first bundle using the SDK CLI: elevasis deploy"
730
- }
731
- );
732
- }
733
- const anyMutationPending = activateMutation.isPending || deactivateMutation.isPending || deleteMutation.isPending;
734
- const mutatingId = activateMutation.isPending ? activateMutation.variables : deactivateMutation.isPending ? deactivateMutation.variables : deleteMutation.isPending ? deleteMutation.variables : null;
735
- return /* @__PURE__ */ jsxs(Fragment, { children: [
736
- /* @__PURE__ */ jsxs(Table, { children: [
737
- /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
738
- /* @__PURE__ */ jsx(Table.Th, { children: "Status" }),
739
- /* @__PURE__ */ jsx(Table.Th, { children: "Deployment Version" }),
740
- /* @__PURE__ */ jsx(Table.Th, { children: "SDK Version" }),
741
- /* @__PURE__ */ jsx(Table.Th, { children: "Created" }),
742
- /* @__PURE__ */ jsx(Table.Th, { children: "Updated" }),
743
- /* @__PURE__ */ jsx(Table.Th, { w: 100 })
744
- ] }) }),
745
- /* @__PURE__ */ jsx(Table.Tbody, { children: paginatedDeployments.map((deployment) => {
746
- const isMutating = deployment.id === mutatingId;
747
- return /* @__PURE__ */ jsxs(
748
- Table.Tr,
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" }),
809
+ /* @__PURE__ */ jsx(
810
+ Button,
811
+ {
812
+ size: "xs",
813
+ variant: "light",
814
+ leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 14 }),
815
+ onClick: handleAddItem,
816
+ disabled,
817
+ children: "Add Execution"
818
+ }
819
+ )
820
+ ] }),
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,
749
830
  {
750
- onClick: () => setSelected(deployment),
751
- style: { cursor: "pointer", opacity: isMutating ? 0.6 : 1, transition: "opacity 150ms" },
752
- children: [
753
- /* @__PURE__ */ jsx(Table.Td, { children: isMutating ? /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
754
- /* @__PURE__ */ jsx(Loader, { size: 14 }),
755
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "Updating\u2026" })
756
- ] }) : /* @__PURE__ */ jsx(DeploymentStatusBadge, { status: deployment.status }) }),
757
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: deployment.deploymentVersion ?? "\u2014" }) }),
758
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: deployment.sdkVersion }) }),
759
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
760
- /* @__PURE__ */ jsx(IconCalendar, { size: 14, style: { opacity: 0.5 } }),
761
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDateTime(deployment.createdAt) })
762
- ] }) }),
763
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
764
- /* @__PURE__ */ jsx(IconRefresh, { size: 14, style: { opacity: 0.5 } }),
765
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: formatDateTime(deployment.updatedAt) })
766
- ] }) }),
767
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: "xs", justify: "flex-end", children: [
768
- deployment.status === "active" && /* @__PURE__ */ jsx(Tooltip, { label: "Deactivate deployment", children: /* @__PURE__ */ jsx(
769
- ActionIcon,
770
- {
771
- variant: "subtle",
772
- color: "orange",
773
- onClick: (e) => {
774
- e.stopPropagation();
775
- setDeactivateTarget(deployment);
776
- },
777
- disabled: anyMutationPending,
778
- children: /* @__PURE__ */ jsx(IconPower, { size: 16 })
779
- }
780
- ) }),
781
- (deployment.status === "stopped" || deployment.status === "rolled_back") && /* @__PURE__ */ jsxs(Fragment, { children: [
782
- /* @__PURE__ */ jsx(Tooltip, { label: "Activate deployment", children: /* @__PURE__ */ jsx(
783
- ActionIcon,
784
- {
785
- variant: "subtle",
786
- color: "green",
787
- onClick: (e) => {
788
- e.stopPropagation();
789
- setActivateTarget(deployment);
790
- },
791
- disabled: anyMutationPending,
792
- children: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 })
793
- }
794
- ) }),
795
- /* @__PURE__ */ jsx(Tooltip, { label: "Delete deployment", position: "left", children: /* @__PURE__ */ jsx(
796
- ActionIcon,
797
- {
798
- variant: "subtle",
799
- color: "red",
800
- onClick: (e) => {
801
- e.stopPropagation();
802
- setDeleteTarget(deployment);
803
- },
804
- disabled: anyMutationPending,
805
- children: /* @__PURE__ */ jsx(IconTrash, { size: 16 })
806
- }
807
- ) })
808
- ] }),
809
- deployment.status === "failed" && /* @__PURE__ */ jsx(Tooltip, { label: "Delete deployment", position: "left", children: /* @__PURE__ */ jsx(
810
- ActionIcon,
811
- {
812
- variant: "subtle",
813
- color: "red",
814
- onClick: (e) => {
815
- e.stopPropagation();
816
- setDeleteTarget(deployment);
817
- },
818
- disabled: anyMutationPending,
819
- children: /* @__PURE__ */ jsx(IconTrash, { size: 16 })
820
- }
821
- ) })
822
- ] }) })
823
- ]
824
- },
825
- deployment.id
826
- );
827
- }) })
828
- ] }),
829
- total > 1 && /* @__PURE__ */ jsx(Group, { justify: "center", mt: "md", children: /* @__PURE__ */ jsx(Pagination, { total, value: page, onChange: setPage }) }),
830
- /* @__PURE__ */ jsx(DeploymentDetailModal, { deployment: selected, opened: !!selected, onClose: () => setSelected(null) }),
831
- /* @__PURE__ */ jsx(
832
- CustomModal,
833
- {
834
- opened: !!activateTarget,
835
- onClose: handleCloseActivate,
836
- size: "sm",
837
- loading: activateMutation.isPending,
838
- children: /* @__PURE__ */ jsxs(Stack, { children: [
839
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
840
- /* @__PURE__ */ jsx(IconPlayerPlay, { size: 24, color: "var(--mantine-color-green-6)" }),
841
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Activate Deployment" })
842
- ] }),
843
- /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
844
- "Are you sure you want to activate deployment",
845
- " ",
846
- /* @__PURE__ */ jsxs(Text, { span: true, fw: 600, children: [
847
- '"',
848
- activateTarget?.id.slice(0, 8),
849
- '..."'
850
- ] }),
851
- "?"
852
- ] }),
853
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This will stop the currently active deployment and replace it with this version." }),
854
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "sm", children: [
855
- /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleCloseActivate, disabled: activateMutation.isPending, children: "Cancel" }),
856
- /* @__PURE__ */ jsx(
857
- Button,
858
- {
859
- color: "green",
860
- onClick: handleConfirmActivate,
861
- loading: activateMutation.isPending,
862
- leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 }),
863
- children: "Activate"
864
- }
865
- )
866
- ] })
867
- ] })
868
- }
869
- ),
870
- /* @__PURE__ */ jsx(
871
- CustomModal,
872
- {
873
- opened: !!deactivateTarget,
874
- onClose: handleCloseDeactivate,
875
- size: "sm",
876
- loading: deactivateMutation.isPending,
877
- children: /* @__PURE__ */ jsxs(Stack, { children: [
878
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
879
- /* @__PURE__ */ jsx(IconPower, { size: 24, color: "var(--mantine-color-orange-6)" }),
880
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Deactivate Deployment" })
881
- ] }),
882
- /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
883
- "Are you sure you want to deactivate deployment",
884
- " ",
885
- /* @__PURE__ */ jsxs(Text, { span: true, fw: 600, children: [
886
- '"',
887
- deactivateTarget?.id.slice(0, 8),
888
- '..."'
889
- ] }),
890
- "?"
891
- ] }),
892
- /* @__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." }),
893
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "sm", children: [
894
- /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleCloseDeactivate, disabled: deactivateMutation.isPending, children: "Cancel" }),
895
- /* @__PURE__ */ jsx(
896
- Button,
897
- {
898
- color: "orange",
899
- onClick: handleConfirmDeactivate,
900
- loading: deactivateMutation.isPending,
901
- leftSection: /* @__PURE__ */ jsx(IconPower, { size: 16 }),
902
- children: "Deactivate"
903
- }
904
- )
905
- ] })
906
- ] })
907
- }
908
- ),
909
- /* @__PURE__ */ jsx(CustomModal, { opened: !!deleteTarget, onClose: handleCloseDelete, size: "sm", loading: deleteMutation.isPending, children: /* @__PURE__ */ jsxs(Stack, { children: [
910
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
911
- /* @__PURE__ */ jsx(IconAlertTriangle, { size: 24, color: "var(--color-error)" }),
912
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Delete Deployment" })
913
- ] }),
914
- /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
915
- "Are you sure you want to delete deployment",
916
- " ",
917
- /* @__PURE__ */ jsxs(Text, { span: true, fw: 600, children: [
918
- '"',
919
- deleteTarget?.id.slice(0, 8),
920
- '..."'
921
- ] }),
922
- "?"
831
+ size: "sm",
832
+ color: "red",
833
+ variant: "subtle",
834
+ onClick: () => handleRemoveItem(index),
835
+ disabled,
836
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 14 })
837
+ }
838
+ )
923
839
  ] }),
924
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This action cannot be undone. The deployment bundle will be permanently removed." }),
925
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", gap: "sm", children: [
926
- /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleCloseDelete, disabled: deleteMutation.isPending, children: "Cancel" }),
840
+ /* @__PURE__ */ jsxs(Group, { grow: true, children: [
927
841
  /* @__PURE__ */ jsx(
928
- Button,
842
+ TextInput,
929
843
  {
930
- color: "red",
931
- onClick: handleConfirmDelete,
932
- loading: deleteMutation.isPending,
933
- leftSection: /* @__PURE__ */ jsx(IconTrash, { size: 16 }),
934
- children: "Delete"
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
935
860
  }
936
861
  )
937
- ] })
938
- ] }) })
939
- ] });
940
- }
941
- function DeploymentSettings() {
942
- const { isReady } = useElevasisServices();
943
- const { data: deployments = [], isLoading } = useListDeployments();
944
- if (!isReady) return /* @__PURE__ */ jsx(AppShellLoader, {});
945
- const totalDeployments = deployments.length;
946
- const activeDeployment = deployments.find((d) => d.status === "active");
947
- return /* @__PURE__ */ jsxs(Stack, { children: [
948
- /* @__PURE__ */ jsx(PageTitleCaption, { title: "Deployments", caption: "View deployment history for externally deployed SDK bundles" }),
949
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: 3, children: [
950
- /* @__PURE__ */ jsx(
951
- StatCard,
952
- {
953
- variant: "hero",
954
- icon: IconRocket,
955
- value: totalDeployments,
956
- label: "Total Deployments",
957
- isLoading
958
- }
959
- ),
960
- /* @__PURE__ */ jsx(
961
- StatCard,
962
- {
963
- variant: "hero",
964
- icon: IconCircleCheck,
965
- value: activeDeployment ? activeDeployment.sdkVersion : "None",
966
- label: "Active SDK Deployment",
967
- isLoading
968
- }
969
- ),
862
+ ] }),
970
863
  /* @__PURE__ */ jsx(
971
- StatCard,
864
+ Textarea,
972
865
  {
973
- variant: "hero",
974
- icon: IconTag,
975
- value: activeDeployment?.deploymentVersion ?? "None",
976
- label: "Active Deployment Version",
977
- isLoading
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
978
878
  }
979
879
  )
980
- ] }),
981
- /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(DeploymentList, { deployments, isLoading }) })
982
- ] });
983
- }
984
- function ScheduleTypeSelector({ value, onChange, disabled }) {
985
- return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
986
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Schedule Type" }),
987
- /* @__PURE__ */ jsx(
988
- SegmentedControl,
989
- {
990
- value,
991
- onChange: (v) => onChange(v),
992
- disabled,
993
- data: [
994
- {
995
- value: "recurring",
996
- label: /* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", children: [
997
- /* @__PURE__ */ jsx(IconCalendarRepeat, { size: 20 }),
998
- /* @__PURE__ */ jsx(Text, { size: "xs", children: "Recurring" })
999
- ] })
1000
- },
1001
- {
1002
- value: "relative",
1003
- label: /* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", children: [
1004
- /* @__PURE__ */ jsx(IconCalendarEvent, { size: 20 }),
1005
- /* @__PURE__ */ jsx(Text, { size: "xs", children: "Relative" })
1006
- ] })
1007
- },
1008
- {
1009
- value: "absolute",
1010
- label: /* @__PURE__ */ jsxs(Stack, { gap: 4, align: "center", children: [
1011
- /* @__PURE__ */ jsx(IconCalendarTime, { size: 20 }),
1012
- /* @__PURE__ */ jsx(Text, { size: "xs", children: "Absolute" })
1013
- ] })
1014
- }
1015
- ],
1016
- fullWidth: true
1017
- }
1018
- ),
1019
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1020
- value === "recurring" && "Run on a schedule (daily, weekly, or cron expression)",
1021
- value === "relative" && "Run at offsets from an anchor date (e.g., 3 days before event)",
1022
- value === "absolute" && "Run at specific dates and times"
1023
- ] })
880
+ ] }) }, index))
1024
881
  ] });
1025
882
  }
1026
- function toDateTimeLocal(isoString) {
1027
- if (!isoString) return "";
1028
- const date = new Date(isoString);
1029
- return date.toISOString().slice(0, 16);
1030
- }
1031
- function fromDateTimeLocal(dateTimeLocal) {
1032
- if (!dateTimeLocal) return null;
1033
- return new Date(dateTimeLocal).toISOString();
1034
- }
1035
- function RecurringScheduleForm({ value, onChange, disabled }) {
1036
- const [useCron, setUseCron] = useState(!!value.cron);
1037
- const handleChange = (updates) => {
1038
- onChange({ ...value, ...updates });
883
+ var defaultRecurringConfig = {
884
+ type: "recurring",
885
+ interval: "daily",
886
+ time: "09:00",
887
+ timezone: "UTC",
888
+ payload: {}
889
+ };
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);
1039
934
  };
1040
- return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
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
+ }
985
+ };
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;
993
+ }
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" }),
1041
1035
  /* @__PURE__ */ jsx(
1042
- Switch,
1036
+ TextInput,
1043
1037
  {
1044
- label: "Use cron expression",
1045
- description: "Advanced scheduling with cron syntax",
1046
- checked: useCron,
1047
- onChange: (e) => {
1048
- setUseCron(e.currentTarget.checked);
1049
- if (e.currentTarget.checked) {
1050
- handleChange({ cron: "0 9 * * *", interval: void 0, time: void 0 });
1051
- } else {
1052
- handleChange({ cron: void 0, interval: "daily", time: "09:00" });
1053
- }
1054
- },
1055
- disabled
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
1056
1044
  }
1057
1045
  ),
1058
- useCron ? /* @__PURE__ */ jsx(
1059
- TextInput,
1046
+ /* @__PURE__ */ jsx(
1047
+ Textarea,
1060
1048
  {
1061
- label: "Cron Expression",
1062
- placeholder: "0 9 * * 1 (Every Monday at 9am)",
1063
- value: value.cron || "",
1064
- onChange: (e) => handleChange({ cron: e.currentTarget.value }),
1065
- description: "Format: minute hour day month weekday",
1066
- disabled
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
1067
1054
  }
1068
- ) : /* @__PURE__ */ jsxs(Group, { grow: true, children: [
1069
- /* @__PURE__ */ jsx(
1070
- Select,
1071
- {
1072
- label: "Interval",
1073
- data: [
1074
- { value: "daily", label: "Daily" },
1075
- { value: "weekly", label: "Weekly" },
1076
- { value: "monthly", label: "Monthly" }
1077
- ],
1078
- value: value.interval || "daily",
1079
- onChange: (v) => handleChange({ interval: v }),
1080
- disabled
1081
- }
1082
- ),
1083
- /* @__PURE__ */ jsx(
1084
- TextInput,
1085
- {
1086
- label: "Time",
1087
- type: "time",
1088
- value: value.time || "09:00",
1089
- onChange: (e) => handleChange({ time: e.currentTarget.value }),
1090
- disabled
1091
- }
1092
- )
1093
- ] }),
1055
+ ),
1094
1056
  /* @__PURE__ */ jsx(
1095
1057
  Select,
1096
1058
  {
1097
- label: "Timezone",
1098
- placeholder: "Select timezone",
1099
- data: [
1100
- { value: "UTC", label: "UTC" },
1101
- { value: "America/New_York", label: "Eastern Time" },
1102
- { value: "America/Chicago", label: "Central Time" },
1103
- { value: "America/Denver", label: "Mountain Time" },
1104
- { value: "America/Los_Angeles", label: "Pacific Time" },
1105
- { value: "Europe/London", label: "London" },
1106
- { value: "Europe/Paris", label: "Paris" },
1107
- { value: "Asia/Tokyo", label: "Tokyo" }
1108
- ],
1109
- value: value.timezone || "UTC",
1110
- onChange: (v) => handleChange({ timezone: v || "UTC" }),
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 || ""),
1111
1064
  searchable: true,
1112
- disabled
1065
+ required: true,
1066
+ disabled: !resourcesData || createSchedule.isPending
1113
1067
  }
1114
1068
  ),
1069
+ /* @__PURE__ */ jsx(Divider, {}),
1115
1070
  /* @__PURE__ */ jsx(
1116
- TextInput,
1071
+ ScheduleTypeSelector,
1117
1072
  {
1118
- label: "End Date (Optional)",
1119
- type: "datetime-local",
1120
- value: toDateTimeLocal(value.endAt),
1121
- onChange: (e) => handleChange({ endAt: fromDateTimeLocal(e.currentTarget.value) }),
1122
- disabled
1123
- }
1124
- )
1125
- ] });
1126
- }
1127
- function toDateTimeLocal2(isoString) {
1128
- if (!isoString) return "";
1129
- const date = new Date(isoString);
1130
- return date.toISOString().slice(0, 16);
1131
- }
1132
- function fromDateTimeLocal2(dateTimeLocal) {
1133
- if (!dateTimeLocal) return void 0;
1134
- return new Date(dateTimeLocal).toISOString();
1135
- }
1136
- function RelativeScheduleForm({ value, onChange, disabled }) {
1137
- const items = value.items || [];
1138
- const handleAnchorChange = (dateTimeLocal) => {
1139
- onChange({ ...value, anchorAt: fromDateTimeLocal2(dateTimeLocal) });
1140
- };
1141
- const handleItemChange = (index, updates) => {
1142
- const newItems = [...items];
1143
- newItems[index] = { ...newItems[index], ...updates };
1144
- onChange({ ...value, items: newItems });
1145
- };
1146
- const handleAddItem = () => {
1147
- const newItems = [...items, { offset: "+1d", payload: {}, label: "" }];
1148
- onChange({ ...value, items: newItems });
1149
- };
1150
- const handleRemoveItem = (index) => {
1151
- const newItems = items.filter((_, i) => i !== index);
1152
- onChange({ ...value, items: newItems });
1153
- };
1154
- return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1155
- /* @__PURE__ */ jsx(
1156
- TextInput,
1073
+ value: scheduleType,
1074
+ onChange: handleScheduleTypeChange,
1075
+ disabled: createSchedule.isPending
1076
+ }
1077
+ ),
1078
+ /* @__PURE__ */ jsx(Divider, {}),
1079
+ scheduleType === "recurring" && /* @__PURE__ */ jsx(
1080
+ RecurringScheduleForm,
1157
1081
  {
1158
- label: "Anchor Date",
1159
- description: "Reference date for calculating run times",
1160
- type: "datetime-local",
1161
- value: toDateTimeLocal2(value.anchorAt),
1162
- onChange: (e) => handleAnchorChange(e.currentTarget.value),
1163
- required: true,
1164
- disabled
1082
+ value: recurringConfig,
1083
+ onChange: setRecurringConfig,
1084
+ disabled: createSchedule.isPending
1165
1085
  }
1166
1086
  ),
1167
- /* @__PURE__ */ jsx(
1168
- TextInput,
1087
+ scheduleType === "relative" && /* @__PURE__ */ jsx(
1088
+ RelativeScheduleForm,
1169
1089
  {
1170
- label: "Anchor Label (Optional)",
1171
- placeholder: "e.g., meeting_date, deadline, event_start",
1172
- value: value.anchorLabel || "",
1173
- onChange: (e) => onChange({ ...value, anchorLabel: e.currentTarget.value || void 0 }),
1174
- disabled
1090
+ value: relativeConfig,
1091
+ onChange: setRelativeConfig,
1092
+ disabled: createSchedule.isPending
1175
1093
  }
1176
1094
  ),
1177
- /* @__PURE__ */ jsxs(Stack, { children: [
1178
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1179
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Schedule Items" }),
1180
- /* @__PURE__ */ jsx(
1181
- Button,
1182
- {
1183
- size: "xs",
1184
- variant: "light",
1185
- leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 14 }),
1186
- onClick: handleAddItem,
1187
- disabled,
1188
- children: "Add Item"
1189
- }
1190
- )
1191
- ] }),
1192
- items.length === 0 && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: 'No items yet. Click "Add Item" to create a schedule step.' }),
1193
- items.map((item, index) => /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1194
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1195
- /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
1196
- "Step ",
1197
- index + 1
1198
- ] }),
1199
- /* @__PURE__ */ jsx(
1200
- ActionIcon,
1201
- {
1202
- size: "sm",
1203
- color: "red",
1204
- variant: "subtle",
1205
- onClick: () => handleRemoveItem(index),
1206
- disabled,
1207
- children: /* @__PURE__ */ jsx(IconTrash, { size: 14 })
1208
- }
1209
- )
1210
- ] }),
1211
- /* @__PURE__ */ jsxs(Group, { grow: true, children: [
1212
- /* @__PURE__ */ jsx(
1213
- TextInput,
1214
- {
1215
- label: "Offset",
1216
- placeholder: "+3d, -2h, +30m",
1217
- value: item.offset,
1218
- onChange: (e) => handleItemChange(index, { offset: e.currentTarget.value }),
1219
- description: "+ after anchor, - before anchor",
1220
- disabled
1221
- }
1222
- ),
1223
- /* @__PURE__ */ jsx(
1224
- TextInput,
1225
- {
1226
- label: "Label (Optional)",
1227
- placeholder: "e.g., Thank you, Follow up",
1228
- value: item.label || "",
1229
- onChange: (e) => handleItemChange(index, { label: e.currentTarget.value || void 0 }),
1230
- disabled
1231
- }
1232
- )
1233
- ] }),
1234
- /* @__PURE__ */ jsx(
1235
- Textarea,
1236
- {
1237
- label: "Payload (JSON)",
1238
- placeholder: '{"key": "value"}',
1239
- value: JSON.stringify(item.payload, null, 2),
1240
- onChange: (e) => {
1241
- try {
1242
- const payload = JSON.parse(e.currentTarget.value);
1243
- handleItemChange(index, { payload });
1244
- } catch {
1245
- }
1246
- },
1247
- minRows: 2,
1248
- disabled
1249
- }
1250
- )
1251
- ] }) }, index))
1095
+ scheduleType === "absolute" && /* @__PURE__ */ jsx(
1096
+ AbsoluteScheduleForm,
1097
+ {
1098
+ value: absoluteConfig,
1099
+ onChange: setAbsoluteConfig,
1100
+ disabled: createSchedule.isPending
1101
+ }
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" })
1252
1106
  ] })
1253
- ] });
1254
- }
1255
- function toDateTimeLocal3(isoString) {
1256
- if (!isoString) return "";
1257
- const date = new Date(isoString);
1258
- return date.toISOString().slice(0, 16);
1259
- }
1260
- function fromDateTimeLocal3(dateTimeLocal) {
1261
- if (!dateTimeLocal) return "";
1262
- return new Date(dateTimeLocal).toISOString();
1107
+ ] }) }) });
1263
1108
  }
1264
- function AbsoluteScheduleForm({ value, onChange, disabled }) {
1265
- const items = value.items || [];
1266
- const handleItemChange = (index, updates) => {
1267
- const newItems = [...items];
1268
- newItems[index] = { ...newItems[index], ...updates };
1269
- onChange({ ...value, items: newItems });
1270
- };
1271
- const handleAddItem = () => {
1272
- const newItems = [...items, { runAt: (/* @__PURE__ */ new Date()).toISOString(), payload: {}, label: "" }];
1273
- onChange({ ...value, items: newItems });
1274
- };
1275
- const handleRemoveItem = (index) => {
1276
- const newItems = items.filter((_, i) => i !== index);
1277
- onChange({ ...value, items: newItems });
1109
+ function DeleteScheduleModal({ opened, onClose, onConfirm, schedule, isDeleting }) {
1110
+ const handleClose = () => {
1111
+ if (!isDeleting) {
1112
+ onClose();
1113
+ }
1278
1114
  };
1279
- return /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1280
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1281
- /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, children: "Scheduled Executions" }),
1282
- /* @__PURE__ */ jsx(
1283
- Button,
1284
- {
1285
- size: "xs",
1286
- variant: "light",
1287
- leftSection: /* @__PURE__ */ jsx(IconPlus, { size: 14 }),
1288
- onClick: handleAddItem,
1289
- disabled,
1290
- children: "Add Execution"
1291
- }
1292
- )
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" })
1293
1119
  ] }),
1294
- items.length === 0 && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: 'No executions yet. Click "Add Execution" to schedule a run.' }),
1295
- items.map((item, index) => /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1296
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1297
- /* @__PURE__ */ jsxs(Text, { size: "sm", fw: 500, children: [
1298
- "Execution ",
1299
- index + 1
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" })
1130
+ ] })
1131
+ ] }) });
1132
+ }
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
+ }
1144
+ }
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
+ });
1156
+ }
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" })
1300
1165
  ] }),
1301
- /* @__PURE__ */ jsx(
1302
- ActionIcon,
1303
- {
1304
- size: "sm",
1305
- color: "red",
1306
- variant: "subtle",
1307
- onClick: () => handleRemoveItem(index),
1308
- disabled,
1309
- children: /* @__PURE__ */ jsx(IconTrash, { size: 14 })
1310
- }
1311
- )
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
+ ] })
1312
1248
  ] }),
1313
- /* @__PURE__ */ jsxs(Group, { grow: true, children: [
1314
- /* @__PURE__ */ jsx(
1315
- TextInput,
1316
- {
1317
- label: "Run At",
1318
- type: "datetime-local",
1319
- value: toDateTimeLocal3(item.runAt),
1320
- onChange: (e) => handleItemChange(index, { runAt: fromDateTimeLocal3(e.currentTarget.value) }),
1321
- required: true,
1322
- disabled
1323
- }
1324
- ),
1325
- /* @__PURE__ */ jsx(
1326
- TextInput,
1327
- {
1328
- label: "Label (Optional)",
1329
- placeholder: "e.g., Launch, Phase 2",
1330
- value: item.label || "",
1331
- onChange: (e) => handleItemChange(index, { label: e.currentTarget.value || void 0 }),
1332
- disabled
1333
- }
1334
- )
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
+ ] })
1335
1321
  ] }),
1336
1322
  /* @__PURE__ */ jsx(
1337
- Textarea,
1323
+ Button,
1338
1324
  {
1339
- label: "Payload (JSON)",
1340
- placeholder: '{"key": "value"}',
1341
- value: JSON.stringify(item.payload, null, 2),
1342
- onChange: (e) => {
1343
- try {
1344
- const payload = JSON.parse(e.currentTarget.value);
1345
- handleItemChange(index, { payload });
1346
- } catch {
1347
- }
1348
- },
1349
- minRows: 2,
1350
- 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"
1351
1333
  }
1352
1334
  )
1353
- ] }) }, index))
1354
- ] });
1335
+ ] })
1336
+ ] }) });
1355
1337
  }
1356
- var defaultRecurringConfig = {
1357
- type: "recurring",
1358
- interval: "daily",
1359
- time: "09:00",
1360
- timezone: "UTC",
1361
- payload: {}
1362
- };
1363
- var defaultRelativeConfig = {
1364
- type: "relative",
1365
- items: []
1366
- };
1367
- var defaultAbsoluteConfig = {
1368
- type: "absolute",
1369
- items: []
1370
- };
1371
- function CreateScheduleModal({ opened, onClose }) {
1372
- const [name, setName] = useState("");
1373
- const [description, setDescription] = useState("");
1374
- const [resourceId, setResourceId] = useState("");
1375
- const [scheduleType, setScheduleType] = useState("recurring");
1376
- const [recurringConfig, setRecurringConfig] = useState(defaultRecurringConfig);
1377
- const [relativeConfig, setRelativeConfig] = useState(defaultRelativeConfig);
1378
- const [absoluteConfig, setAbsoluteConfig] = useState(defaultAbsoluteConfig);
1379
- const { data: resourcesData } = useResources();
1380
- const createSchedule = useCreateSchedule();
1381
- const allResources = useMemo(() => {
1382
- if (!resourcesData) return [];
1383
- const workflows = (resourcesData.workflows || []).map((w) => ({
1384
- id: w.resourceId,
1385
- type: "workflow"
1386
- }));
1387
- const agents = (resourcesData.agents || []).map((a) => ({
1388
- id: a.resourceId,
1389
- type: "agent"
1390
- }));
1391
- return [...workflows, ...agents];
1392
- }, [resourcesData]);
1393
- const resourceOptions = useMemo(() => {
1394
- if (!resourcesData) return [];
1395
- const workflowOptions = (resourcesData.workflows || []).filter((w) => w?.resourceId).map((w) => ({
1396
- value: w.resourceId,
1397
- label: `Workflow: ${w.resourceId}`
1398
- }));
1399
- const agentOptions = (resourcesData.agents || []).filter((a) => a?.resourceId).map((a) => ({
1400
- value: a.resourceId,
1401
- label: `Agent: ${a.resourceId}`
1402
- }));
1403
- return [...workflowOptions, ...agentOptions];
1404
- }, [resourcesData]);
1405
- const handleScheduleTypeChange = (newType) => {
1406
- setScheduleType(newType);
1407
- };
1408
- const buildScheduleConfig = () => {
1409
- switch (scheduleType) {
1410
- case "recurring": {
1411
- if (!recurringConfig.timezone) {
1412
- showErrorNotification("Timezone is required");
1413
- return null;
1414
- }
1415
- const config = {
1416
- type: "recurring",
1417
- timezone: recurringConfig.timezone,
1418
- payload: recurringConfig.payload || {},
1419
- endAt: recurringConfig.endAt
1420
- };
1421
- if (recurringConfig.cron) {
1422
- config.cron = recurringConfig.cron;
1423
- } else {
1424
- config.interval = recurringConfig.interval || "daily";
1425
- config.time = recurringConfig.time || "09:00";
1426
- }
1427
- return config;
1428
- }
1429
- case "relative": {
1430
- if (!relativeConfig.anchorAt) {
1431
- showErrorNotification("Anchor date is required for relative schedules");
1432
- return null;
1433
- }
1434
- if (!relativeConfig.items || relativeConfig.items.length === 0) {
1435
- showErrorNotification("At least one schedule item is required");
1436
- return null;
1437
- }
1438
- return {
1439
- type: "relative",
1440
- anchorAt: relativeConfig.anchorAt,
1441
- anchorLabel: relativeConfig.anchorLabel,
1442
- items: relativeConfig.items
1443
- };
1444
- }
1445
- case "absolute": {
1446
- if (!absoluteConfig.items || absoluteConfig.items.length === 0) {
1447
- showErrorNotification("At least one scheduled execution is required");
1448
- return null;
1449
- }
1450
- return {
1451
- type: "absolute",
1452
- items: absoluteConfig.items
1453
- };
1454
- }
1455
- default:
1456
- return null;
1457
- }
1458
- };
1459
- const handleSubmit = async (e) => {
1460
- e.preventDefault();
1461
- try {
1462
- const resource = allResources.find((r) => r.id === resourceId);
1463
- if (!resource) {
1464
- showErrorNotification("Please select a valid resource");
1465
- return;
1466
- }
1467
- if (!name.trim()) {
1468
- showErrorNotification("Schedule name is required");
1469
- return;
1470
- }
1471
- const scheduleConfig = buildScheduleConfig();
1472
- if (!scheduleConfig) {
1473
- return;
1474
- }
1475
- const input = {
1476
- name: name.trim(),
1477
- description: description.trim() || void 0,
1478
- target: {
1479
- resourceType: resource.type,
1480
- resourceId: resource.id
1481
- },
1482
- scheduleConfig,
1483
- maxRetries: 3,
1484
- originResourceType: "api",
1485
- originResourceId: "task-scheduler-ui"
1486
- };
1487
- await createSchedule.mutateAsync(input);
1488
- showSuccessNotification("Schedule created successfully");
1489
- handleClose();
1490
- } catch (error) {
1491
- showApiErrorNotification(error);
1492
- }
1493
- };
1494
- const handleClose = () => {
1495
- if (!createSchedule.isPending) {
1496
- setName("");
1497
- setDescription("");
1498
- setResourceId("");
1499
- setScheduleType("recurring");
1500
- setRecurringConfig(defaultRecurringConfig);
1501
- setRelativeConfig(defaultRelativeConfig);
1502
- setAbsoluteConfig(defaultAbsoluteConfig);
1503
- onClose();
1504
- }
1505
- };
1506
- 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: [
1507
- /* @__PURE__ */ jsx(Title, { order: 3, children: "Create Schedule" }),
1508
- /* @__PURE__ */ jsx(
1509
- TextInput,
1510
- {
1511
- label: "Schedule Name",
1512
- placeholder: "e.g., Daily Sales Report, Weekly Sync",
1513
- value: name,
1514
- onChange: (e) => setName(e.currentTarget.value),
1515
- required: true,
1516
- disabled: createSchedule.isPending
1517
- }
1518
- ),
1519
- /* @__PURE__ */ jsx(
1520
- Textarea,
1521
- {
1522
- label: "Description (Optional)",
1523
- placeholder: "Describe what this schedule does...",
1524
- value: description,
1525
- onChange: (e) => setDescription(e.currentTarget.value),
1526
- disabled: createSchedule.isPending
1527
- }
1528
- ),
1529
- /* @__PURE__ */ jsx(
1530
- Select,
1531
- {
1532
- label: "Resource to Execute",
1533
- placeholder: resourcesData ? "Select an agent or workflow" : "Loading resources...",
1534
- data: resourceOptions,
1535
- value: resourceId,
1536
- onChange: (value) => setResourceId(value || ""),
1537
- searchable: true,
1538
- required: true,
1539
- disabled: !resourcesData || createSchedule.isPending
1540
- }
1541
- ),
1542
- /* @__PURE__ */ jsx(Divider, {}),
1543
- /* @__PURE__ */ jsx(
1544
- ScheduleTypeSelector,
1545
- {
1546
- value: scheduleType,
1547
- onChange: handleScheduleTypeChange,
1548
- disabled: createSchedule.isPending
1549
- }
1550
- ),
1551
- /* @__PURE__ */ jsx(Divider, {}),
1552
- scheduleType === "recurring" && /* @__PURE__ */ jsx(
1553
- RecurringScheduleForm,
1554
- {
1555
- value: recurringConfig,
1556
- onChange: setRecurringConfig,
1557
- disabled: createSchedule.isPending
1558
- }
1559
- ),
1560
- scheduleType === "relative" && /* @__PURE__ */ jsx(
1561
- RelativeScheduleForm,
1562
- {
1563
- value: relativeConfig,
1564
- onChange: setRelativeConfig,
1565
- disabled: createSchedule.isPending
1566
- }
1567
- ),
1568
- scheduleType === "absolute" && /* @__PURE__ */ jsx(
1569
- AbsoluteScheduleForm,
1570
- {
1571
- value: absoluteConfig,
1572
- onChange: setAbsoluteConfig,
1573
- disabled: createSchedule.isPending
1574
- }
1575
- ),
1576
- /* @__PURE__ */ jsxs(Group, { justify: "flex-end", mt: "md", children: [
1577
- /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, type: "button", disabled: createSchedule.isPending, children: "Cancel" }),
1578
- /* @__PURE__ */ jsx(Button, { type: "submit", loading: createSchedule.isPending, children: "Create Schedule" })
1579
- ] })
1580
- ] }) }) });
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
+ }
1581
1347
  }
1582
- function DeleteScheduleModal({ opened, onClose, onConfirm, schedule, isDeleting }) {
1583
- const handleClose = () => {
1584
- if (!isDeleting) {
1585
- onClose();
1586
- }
1587
- };
1588
- return /* @__PURE__ */ jsx(CustomModal, { opened, onClose: handleClose, size: "sm", loading: isDeleting, children: /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1589
- /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
1590
- /* @__PURE__ */ jsx(IconAlertTriangle, { size: 24, color: "var(--color-error)" }),
1591
- /* @__PURE__ */ jsx(Title, { order: 4, children: "Delete Schedule" })
1592
- ] }),
1593
- /* @__PURE__ */ jsxs(Text, { size: "sm", children: [
1594
- "Are you sure you want to delete",
1595
- " ",
1596
- /* @__PURE__ */ jsx(Text, { span: true, fw: 600, children: schedule?.name }),
1597
- "?"
1598
- ] }),
1599
- /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: "This action cannot be undone. Any pending executions will be cancelled." }),
1600
- /* @__PURE__ */ jsxs(Group, { justify: "flex-end", mt: "md", children: [
1601
- /* @__PURE__ */ jsx(Button, { variant: "light", onClick: handleClose, disabled: isDeleting, children: "Cancel" }),
1602
- /* @__PURE__ */ jsx(Button, { color: "red", onClick: onConfirm, loading: isDeleting, children: "Delete" })
1603
- ] })
1604
- ] }) });
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
+ }
1605
1360
  }
1606
- function getStatusColor2(status) {
1361
+ function getStatusColor3(status) {
1607
1362
  switch (status) {
1608
1363
  case "active":
1609
1364
  return "green";
@@ -1615,250 +1370,22 @@ function getStatusColor2(status) {
1615
1370
  return "gray";
1616
1371
  }
1617
1372
  }
1618
- function formatDate(date) {
1619
- if (!date) return "N/A";
1620
- const d = typeof date === "string" ? new Date(date) : date;
1621
- 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", {
1622
1387
  month: "short",
1623
- day: "numeric",
1624
- year: "numeric",
1625
- hour: "numeric",
1626
- minute: "2-digit",
1627
- timeZoneName: "short"
1628
- });
1629
- }
1630
- function ScheduleConfigDetails({ schedule }) {
1631
- const config = schedule.scheduleConfig;
1632
- switch (config.type) {
1633
- case "recurring":
1634
- return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1635
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1636
- /* @__PURE__ */ jsx(IconCalendarRepeat, { size: 16, color: "var(--color-text-subtle)" }),
1637
- /* @__PURE__ */ jsx(Text, { fw: 500, children: "Recurring Schedule" })
1638
- ] }),
1639
- /* @__PURE__ */ jsx(Table, { withRowBorders: false, verticalSpacing: 4, children: /* @__PURE__ */ jsxs(Table.Tbody, { children: [
1640
- config.cron && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1641
- /* @__PURE__ */ jsx(Table.Td, { w: 120, children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Cron" }) }),
1642
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Code, { children: config.cron }) })
1643
- ] }),
1644
- config.interval && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1645
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Interval" }) }),
1646
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Text, { children: [
1647
- config.interval,
1648
- " at ",
1649
- config.time
1650
- ] }) })
1651
- ] }),
1652
- /* @__PURE__ */ jsxs(Table.Tr, { children: [
1653
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Timezone" }) }),
1654
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: config.timezone }) })
1655
- ] }),
1656
- config.endAt && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1657
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Ends" }) }),
1658
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate(config.endAt) }) })
1659
- ] }),
1660
- /* @__PURE__ */ jsxs(Table.Tr, { children: [
1661
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Overdue" }) }),
1662
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: config.overduePolicy === "execute" ? "orange" : "gray", children: config.overduePolicy ?? "skip" }) })
1663
- ] }),
1664
- Object.keys(config.payload).length > 0 && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1665
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Payload" }) }),
1666
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Code, { block: true, children: JSON.stringify(config.payload, null, 2) }) })
1667
- ] })
1668
- ] }) })
1669
- ] });
1670
- case "relative":
1671
- return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1672
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1673
- /* @__PURE__ */ jsx(IconCalendarEvent, { size: 16, color: "var(--color-text-subtle)" }),
1674
- /* @__PURE__ */ jsx(Text, { fw: 500, children: "Relative Schedule" })
1675
- ] }),
1676
- /* @__PURE__ */ jsx(Table, { withRowBorders: false, verticalSpacing: 4, children: /* @__PURE__ */ jsxs(Table.Tbody, { children: [
1677
- /* @__PURE__ */ jsxs(Table.Tr, { children: [
1678
- /* @__PURE__ */ jsx(Table.Td, { w: 120, children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Anchor" }) }),
1679
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Text, { children: [
1680
- formatDate(config.anchorAt),
1681
- config.anchorLabel && ` (${config.anchorLabel})`
1682
- ] }) })
1683
- ] }),
1684
- /* @__PURE__ */ jsxs(Table.Tr, { children: [
1685
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Steps" }) }),
1686
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Stack, { gap: 4, children: config.items.map((item, i) => /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1687
- /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: i === schedule.currentStep ? "blue" : "gray", children: item.offset }),
1688
- item.label && /* @__PURE__ */ jsx(Text, { c: "dimmed", children: item.label })
1689
- ] }, i)) }) })
1690
- ] })
1691
- ] }) })
1692
- ] });
1693
- case "absolute":
1694
- return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1695
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1696
- /* @__PURE__ */ jsx(IconCalendarTime, { size: 16, color: "var(--color-text-subtle)" }),
1697
- /* @__PURE__ */ jsx(Text, { fw: 500, children: "Absolute Schedule" })
1698
- ] }),
1699
- /* @__PURE__ */ jsx(Stack, { gap: 4, children: config.items.map((item, i) => /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1700
- /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: i === schedule.currentStep ? "blue" : "gray", children: i + 1 }),
1701
- /* @__PURE__ */ jsx(Text, { children: formatDate(item.runAt) }),
1702
- item.label && /* @__PURE__ */ jsxs(Text, { c: "dimmed", children: [
1703
- "\u2014 ",
1704
- item.label
1705
- ] })
1706
- ] }, i)) })
1707
- ] });
1708
- }
1709
- }
1710
- function ScheduleDetailModal({ opened, onClose, schedule, resourceStatus }) {
1711
- const ResourceIcon = schedule?.target.resourceType === "agent" ? IconRobot : IconGitBranch;
1712
- const resourceNotFound = resourceStatus === void 0;
1713
- return /* @__PURE__ */ jsx(CustomModal, { opened, onClose, size: "lg", children: schedule && /* @__PURE__ */ jsxs(Stack, { gap: "md", children: [
1714
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", align: "flex-start", children: [
1715
- /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
1716
- /* @__PURE__ */ jsx(ResourceIcon, { size: 24, color: "var(--color-primary)" }),
1717
- /* @__PURE__ */ jsxs("div", { children: [
1718
- /* @__PURE__ */ jsx(Title, { order: 4, style: { fontFamily: "var(--elevasis-font-family-subtitle)" }, children: schedule.name }),
1719
- schedule.description && /* @__PURE__ */ jsx(Text, { c: "dimmed", mt: 2, children: schedule.description })
1720
- ] })
1721
- ] }),
1722
- /* @__PURE__ */ jsx(Badge, { variant: "light", color: getStatusColor2(schedule.status), children: schedule.status })
1723
- ] }),
1724
- resourceNotFound && /* @__PURE__ */ jsxs(Alert, { icon: /* @__PURE__ */ jsx(IconAlertTriangle, { size: 18 }), color: "red", variant: "light", title: "Resource not found", children: [
1725
- "The target resource ",
1726
- /* @__PURE__ */ jsx(Code, { children: schedule.target.resourceId }),
1727
- " does not exist in the current deployment. This schedule will fail when it tries to execute. Consider deleting or updating it."
1728
- ] }),
1729
- /* @__PURE__ */ jsx(Divider, {}),
1730
- /* @__PURE__ */ jsxs(Group, { gap: "lg", children: [
1731
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1732
- /* @__PURE__ */ jsx(ResourceIcon, { size: 14, color: "var(--color-text-subtle)" }),
1733
- /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Target" })
1734
- ] }),
1735
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1736
- /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", radius: "sm", children: schedule.target.resourceType }),
1737
- /* @__PURE__ */ jsx(Code, { children: schedule.target.resourceId })
1738
- ] })
1739
- ] }),
1740
- /* @__PURE__ */ jsx(Divider, {}),
1741
- /* @__PURE__ */ jsx(ScheduleConfigDetails, { schedule }),
1742
- /* @__PURE__ */ jsx(Divider, {}),
1743
- /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
1744
- /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
1745
- /* @__PURE__ */ jsx(IconSettings, { size: 16, color: "var(--color-text-subtle)" }),
1746
- /* @__PURE__ */ jsx(Text, { fw: 500, children: "Execution Details" })
1747
- ] }),
1748
- /* @__PURE__ */ jsx(Table, { withRowBorders: false, verticalSpacing: 4, children: /* @__PURE__ */ jsxs(Table.Tbody, { children: [
1749
- /* @__PURE__ */ jsxs(Table.Tr, { children: [
1750
- /* @__PURE__ */ jsx(Table.Td, { w: 140, children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1751
- /* @__PURE__ */ jsx(IconClock, { size: 12, color: "var(--color-text-subtle)" }),
1752
- /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Next Run" })
1753
- ] }) }),
1754
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate(schedule.nextRunAt) }) })
1755
- ] }),
1756
- /* @__PURE__ */ jsxs(Table.Tr, { children: [
1757
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1758
- /* @__PURE__ */ jsx(IconCalendar, { size: 12, color: "var(--color-text-subtle)" }),
1759
- /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Last Run" })
1760
- ] }) }),
1761
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: formatDate(schedule.lastRunAt) }) })
1762
- ] }),
1763
- /* @__PURE__ */ jsxs(Table.Tr, { children: [
1764
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1765
- /* @__PURE__ */ jsx(IconRefresh, { size: 12, color: "var(--color-text-subtle)" }),
1766
- /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Max Retries" })
1767
- ] }) }),
1768
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { children: schedule.maxRetries }) })
1769
- ] }),
1770
- schedule.idempotencyKey && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1771
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsxs(Group, { gap: 4, children: [
1772
- /* @__PURE__ */ jsx(IconKey, { size: 12, color: "var(--color-text-subtle)" }),
1773
- /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Idempotency" })
1774
- ] }) }),
1775
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Code, { children: schedule.idempotencyKey }) })
1776
- ] }),
1777
- schedule.lastExecutionId && /* @__PURE__ */ jsxs(Table.Tr, { children: [
1778
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Text, { c: "dimmed", children: "Last Execution" }) }),
1779
- /* @__PURE__ */ jsx(Table.Td, { children: /* @__PURE__ */ jsx(Code, { children: schedule.lastExecutionId }) })
1780
- ] })
1781
- ] }) })
1782
- ] }),
1783
- /* @__PURE__ */ jsx(Divider, {}),
1784
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
1785
- /* @__PURE__ */ jsxs(Group, { gap: "lg", children: [
1786
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1787
- "Created ",
1788
- formatDate(schedule.createdAt)
1789
- ] }),
1790
- /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
1791
- "Updated ",
1792
- formatDate(schedule.updatedAt)
1793
- ] })
1794
- ] }),
1795
- /* @__PURE__ */ jsx(
1796
- Button,
1797
- {
1798
- variant: "light",
1799
- size: "xs",
1800
- rightSection: /* @__PURE__ */ jsx(IconExternalLink, { size: 14 }),
1801
- component: "a",
1802
- href: schedule.target.resourceType === "agent" ? `/operations/resources/agent/${schedule.target.resourceId}` : `/operations/resources/workflow/${schedule.target.resourceId}`,
1803
- target: "_blank",
1804
- disabled: resourceNotFound,
1805
- children: "Go to Resource"
1806
- }
1807
- )
1808
- ] })
1809
- ] }) });
1810
- }
1811
- function getScheduleTypeIcon(config) {
1812
- switch (config.type) {
1813
- case "recurring":
1814
- return IconCalendarRepeat;
1815
- case "relative":
1816
- return IconCalendarEvent;
1817
- case "absolute":
1818
- return IconCalendarTime;
1819
- }
1820
- }
1821
- function getScheduleTypeLabel(config) {
1822
- switch (config.type) {
1823
- case "recurring":
1824
- if (config.cron) return `Cron: ${config.cron}`;
1825
- if (config.interval)
1826
- return `${config.interval.charAt(0).toUpperCase() + config.interval.slice(1)} at ${config.time}`;
1827
- return "Recurring";
1828
- case "relative":
1829
- return `${config.items.length} steps from anchor`;
1830
- case "absolute":
1831
- return `${config.items.length} scheduled runs`;
1832
- }
1833
- }
1834
- function getStatusColor3(status) {
1835
- switch (status) {
1836
- case "active":
1837
- return "green";
1838
- case "paused":
1839
- return "yellow";
1840
- case "completed":
1841
- return "blue";
1842
- case "cancelled":
1843
- return "gray";
1844
- }
1845
- }
1846
- function formatNextRun(date) {
1847
- if (!date) return "";
1848
- const now = /* @__PURE__ */ new Date();
1849
- const diffMs = date.getTime() - now.getTime();
1850
- const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
1851
- const diffHours = Math.floor(diffMs % (1e3 * 60 * 60 * 24) / (1e3 * 60 * 60));
1852
- if (diffMs < 0) return "Overdue";
1853
- if (diffDays === 0) {
1854
- if (diffHours === 0) return "Less than an hour";
1855
- return `In ${diffHours}h`;
1856
- }
1857
- if (diffDays === 1) return "Tomorrow";
1858
- if (diffDays <= 7) return `In ${diffDays}d`;
1859
- return date.toLocaleDateString("en-US", {
1860
- month: "short",
1861
- day: "numeric"
1388
+ day: "numeric"
1862
1389
  });
1863
1390
  }
1864
1391
  function ScheduleCard({
@@ -1946,361 +1473,1272 @@ function ScheduleCard({
1946
1473
  }
1947
1474
  );
1948
1475
  }
1949
- var TaskScheduler = () => {
1950
- const { isReady } = useElevasisServices();
1951
- const [isModalOpen, setIsModalOpen] = useState(false);
1952
- const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
1953
- const [scheduleToDelete, setScheduleToDelete] = useState(null);
1954
- const [selectedSchedule, setSelectedSchedule] = useState(null);
1955
- const [viewMode, setViewMode] = useState("buckets");
1956
- const [statusFilter, setStatusFilter] = useState("all");
1957
- const [typeFilter, setTypeFilter] = useState("all");
1958
- const queryFilters = useMemo(() => {
1959
- const filters = {};
1960
- if (statusFilter !== "all") {
1961
- filters.status = statusFilter;
1476
+ var TaskScheduler = () => {
1477
+ const { isReady } = useElevasisServices();
1478
+ const [isModalOpen, setIsModalOpen] = useState(false);
1479
+ const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
1480
+ const [scheduleToDelete, setScheduleToDelete] = useState(null);
1481
+ const [selectedSchedule, setSelectedSchedule] = useState(null);
1482
+ const [viewMode, setViewMode] = useState("buckets");
1483
+ const [statusFilter, setStatusFilter] = useState("all");
1484
+ const [typeFilter, setTypeFilter] = useState("all");
1485
+ const queryFilters = useMemo(() => {
1486
+ const filters = {};
1487
+ if (statusFilter !== "all") {
1488
+ filters.status = statusFilter;
1489
+ }
1490
+ return filters;
1491
+ }, [statusFilter]);
1492
+ const { data, isLoading, error } = useListSchedules(queryFilters);
1493
+ const pauseSchedule = usePauseSchedule();
1494
+ const resumeSchedule = useResumeSchedule();
1495
+ const cancelSchedule = useCancelSchedule();
1496
+ const deleteSchedule = useDeleteSchedule();
1497
+ const filteredSchedules = useMemo(() => {
1498
+ if (!data?.schedules) return [];
1499
+ if (typeFilter === "all") return data.schedules;
1500
+ return data.schedules.filter((s) => s.scheduleConfig.type === typeFilter);
1501
+ }, [data?.schedules, typeFilter]);
1502
+ const isActionLoading = pauseSchedule.isPending || resumeSchedule.isPending || cancelSchedule.isPending || deleteSchedule.isPending;
1503
+ const schedulesByType = useMemo(() => {
1504
+ if (!data?.schedules) return { recurring: 0, relative: 0, absolute: 0 };
1505
+ return data.schedules.reduce(
1506
+ (acc, s) => {
1507
+ acc[s.scheduleConfig.type]++;
1508
+ return acc;
1509
+ },
1510
+ { recurring: 0, relative: 0, absolute: 0 }
1511
+ );
1512
+ }, [data?.schedules]);
1513
+ const schedulesByStatus = useMemo(() => {
1514
+ if (!data?.schedules) return { active: 0, paused: 0, completed: 0, cancelled: 0 };
1515
+ return data.schedules.reduce(
1516
+ (acc, s) => {
1517
+ if (s.status === "active") acc.active++;
1518
+ else if (s.status === "paused") acc.paused++;
1519
+ else if (s.status === "completed") acc.completed++;
1520
+ else if (s.status === "cancelled") acc.cancelled++;
1521
+ return acc;
1522
+ },
1523
+ { active: 0, paused: 0, completed: 0, cancelled: 0 }
1524
+ );
1525
+ }, [data?.schedules]);
1526
+ const { data: resourcesData } = useResources();
1527
+ const resourceStatusMap = useMemo(() => {
1528
+ const map = /* @__PURE__ */ new Map();
1529
+ if (!resourcesData) return map;
1530
+ for (const w of resourcesData.workflows) map.set(w.resourceId, w.status);
1531
+ for (const a of resourcesData.agents) map.set(a.resourceId, a.status);
1532
+ return map;
1533
+ }, [resourcesData]);
1534
+ const handleCardClick = useCallback((schedule) => {
1535
+ setSelectedSchedule(schedule);
1536
+ }, []);
1537
+ if (isLoading || !isReady) {
1538
+ return /* @__PURE__ */ jsx(AppShellLoader, {});
1539
+ }
1540
+ const handlePause = async (scheduleId) => {
1541
+ await pauseSchedule.mutateAsync(scheduleId);
1542
+ };
1543
+ const handleResume = async (scheduleId) => {
1544
+ await resumeSchedule.mutateAsync(scheduleId);
1545
+ };
1546
+ const handleCancel = async (scheduleId) => {
1547
+ await cancelSchedule.mutateAsync(scheduleId);
1548
+ };
1549
+ const handleDelete = (scheduleId) => {
1550
+ const schedule = data?.schedules.find((s) => s.id === scheduleId);
1551
+ if (schedule) {
1552
+ setScheduleToDelete(schedule);
1553
+ setIsDeleteModalOpen(true);
1554
+ }
1555
+ };
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);
1962
2155
  }
1963
- return filters;
1964
- }, [statusFilter]);
1965
- const { data, isLoading, error } = useListSchedules(queryFilters);
1966
- const pauseSchedule = usePauseSchedule();
1967
- const resumeSchedule = useResumeSchedule();
1968
- const cancelSchedule = useCancelSchedule();
1969
- const deleteSchedule = useDeleteSchedule();
1970
- const filteredSchedules = useMemo(() => {
1971
- if (!data?.schedules) return [];
1972
- if (typeFilter === "all") return data.schedules;
1973
- return data.schedules.filter((s) => s.scheduleConfig.type === typeFilter);
1974
- }, [data?.schedules, typeFilter]);
1975
- const isActionLoading = pauseSchedule.isPending || resumeSchedule.isPending || cancelSchedule.isPending || deleteSchedule.isPending;
1976
- const schedulesByType = useMemo(() => {
1977
- if (!data?.schedules) return { recurring: 0, relative: 0, absolute: 0 };
1978
- return data.schedules.reduce(
1979
- (acc, s) => {
1980
- acc[s.scheduleConfig.type]++;
1981
- return acc;
1982
- },
1983
- { recurring: 0, relative: 0, absolute: 0 }
1984
- );
1985
- }, [data?.schedules]);
1986
- const schedulesByStatus = useMemo(() => {
1987
- if (!data?.schedules) return { active: 0, paused: 0, completed: 0, cancelled: 0 };
1988
- return data.schedules.reduce(
1989
- (acc, s) => {
1990
- if (s.status === "active") acc.active++;
1991
- else if (s.status === "paused") acc.paused++;
1992
- else if (s.status === "completed") acc.completed++;
1993
- else if (s.status === "cancelled") acc.cancelled++;
1994
- return acc;
1995
- },
1996
- { active: 0, paused: 0, completed: 0, cancelled: 0 }
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
+ }
1997
2173
  );
1998
- }, [data?.schedules]);
1999
- const { data: resourcesData } = useResources();
2000
- const resourceStatusMap = useMemo(() => {
2001
- const map = /* @__PURE__ */ new Map();
2002
- if (!resourcesData) return map;
2003
- for (const w of resourcesData.workflows) map.set(w.resourceId, w.status);
2004
- for (const a of resourcesData.agents) map.set(a.resourceId, a.status);
2005
- return map;
2006
- }, [resourcesData]);
2007
- const handleCardClick = useCallback((schedule) => {
2008
- setSelectedSchedule(schedule);
2009
- }, []);
2010
- if (isLoading || !isReady) {
2011
- return /* @__PURE__ */ jsx(AppShellLoader, {});
2012
2174
  }
2013
- const handlePause = async (scheduleId) => {
2014
- await pauseSchedule.mutateAsync(scheduleId);
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;
2015
2250
  };
2016
- const handleResume = async (scheduleId) => {
2017
- await resumeSchedule.mutateAsync(scheduleId);
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;
2018
2266
  };
2019
- const handleCancel = async (scheduleId) => {
2020
- await cancelSchedule.mutateAsync(scheduleId);
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
+ }
2021
2300
  };
2022
- const handleDelete = (scheduleId) => {
2023
- const schedule = data?.schedules.find((s) => s.id === scheduleId);
2024
- if (schedule) {
2025
- setScheduleToDelete(schedule);
2026
- setIsDeleteModalOpen(true);
2301
+ const handleClose = () => {
2302
+ if (!createCredential.isPending) {
2303
+ form.reset();
2304
+ setSelectedType("api-key");
2305
+ onClose();
2027
2306
  }
2028
2307
  };
2029
- const handleConfirmDelete = async () => {
2030
- if (scheduleToDelete) {
2031
- await deleteSchedule.mutateAsync(scheduleToDelete.id);
2032
- setIsDeleteModalOpen(false);
2033
- setScheduleToDelete(null);
2034
- }
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);
2035
2462
  };
2036
- const handleCloseDeleteModal = () => {
2037
- setIsDeleteModalOpen(false);
2038
- setScheduleToDelete(null);
2463
+ const handleCloseDelete = () => {
2464
+ if (!deleteMutation.isPending) setDeleteTarget(null);
2039
2465
  };
2040
- const formatNextRun2 = (schedule) => {
2041
- if (!schedule.nextRunAt) return "Not scheduled";
2042
- const date = typeof schedule.nextRunAt === "string" ? new Date(schedule.nextRunAt) : schedule.nextRunAt;
2043
- const now = /* @__PURE__ */ new Date();
2044
- const diffMs = date.getTime() - now.getTime();
2045
- const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
2046
- if (diffMs < 0) return "Overdue";
2047
- if (diffDays === 0) {
2048
- return `Today at ${date.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })}`;
2049
- } else if (diffDays === 1) {
2050
- return `Tomorrow at ${date.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })}`;
2051
- } else if (diffDays > 0 && diffDays <= 7) {
2052
- return `In ${diffDays} days at ${date.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" })}`;
2053
- } else {
2054
- return date.toLocaleString("en-US", {
2055
- month: "short",
2056
- day: "numeric",
2057
- hour: "numeric",
2058
- minute: "2-digit"
2059
- });
2060
- }
2466
+ const handleConfirmActivate = () => {
2467
+ if (!activateTarget) return;
2468
+ activateMutation.mutate(activateTarget.id, { onSuccess: () => setActivateTarget(null) });
2061
2469
  };
2062
- const groupByTimeBucket = (schedules) => {
2063
- const now = /* @__PURE__ */ new Date();
2064
- const buckets = {
2065
- today: [],
2066
- tomorrow: [],
2067
- thisWeek: [],
2068
- later: [],
2069
- noNextRun: []
2070
- };
2071
- schedules.forEach((schedule) => {
2072
- if (!schedule.nextRunAt) {
2073
- buckets.noNextRun.push(schedule);
2074
- return;
2075
- }
2076
- const nextRun = typeof schedule.nextRunAt === "string" ? new Date(schedule.nextRunAt) : schedule.nextRunAt;
2077
- const diffMs = nextRun.getTime() - now.getTime();
2078
- const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
2079
- if (diffDays < 0) {
2080
- buckets.today.push(schedule);
2081
- } else if (diffDays === 0) {
2082
- buckets.today.push(schedule);
2083
- } else if (diffDays === 1) {
2084
- buckets.tomorrow.push(schedule);
2085
- } else if (diffDays <= 7) {
2086
- buckets.thisWeek.push(schedule);
2087
- } else {
2088
- buckets.later.push(schedule);
2089
- }
2090
- });
2091
- return buckets;
2470
+ const handleConfirmDeactivate = () => {
2471
+ if (!deactivateTarget) return;
2472
+ deactivateMutation.mutate(deactivateTarget.id, { onSuccess: () => setDeactivateTarget(null) });
2092
2473
  };
2093
- if (error) {
2094
- 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 });
2095
2480
  }
2096
- const timeBuckets = groupByTimeBucket(filteredSchedules);
2097
- const renderScheduleCards = (schedules) => schedules.map((schedule) => /* @__PURE__ */ jsx(
2098
- ScheduleCard,
2099
- {
2100
- schedule,
2101
- resourceStatus: resourceStatusMap.get(schedule.target.resourceId),
2102
- onPause: handlePause,
2103
- onResume: handleResume,
2104
- onCancel: handleCancel,
2105
- onDelete: handleDelete,
2106
- onClick: handleCardClick,
2107
- isLoading: isActionLoading
2108
- },
2109
- schedule.id
2110
- ));
2111
- return /* @__PURE__ */ jsxs(Stack, { children: [
2112
- /* @__PURE__ */ jsx(
2113
- PageTitleCaption,
2481
+ if (deployments.length === 0) {
2482
+ return /* @__PURE__ */ jsx(
2483
+ EmptyState,
2114
2484
  {
2115
- title: "Task Scheduler",
2116
- caption: "Schedule agents and workflows to run automatically",
2117
- rightSection: /* @__PURE__ */ jsx(
2118
- 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,
2119
2507
  {
2120
- value: viewMode,
2121
- onChange: (value) => setViewMode(value),
2122
- data: [
2123
- { label: "Buckets", value: "buckets" },
2124
- { 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
+ ] }) })
2125
2581
  ]
2126
- }
2127
- )
2128
- }
2129
- ),
2130
- /* @__PURE__ */ jsxs(SimpleGrid, { cols: { base: 2, sm: 5 }, children: [
2131
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Active", value: schedulesByStatus.active, icon: IconCalendarEvent }),
2132
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Paused", value: schedulesByStatus.paused, icon: IconCalendarDue }),
2133
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Completed", value: schedulesByStatus.completed, icon: IconCalendarStats }),
2134
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Cancelled", value: schedulesByStatus.cancelled, icon: IconCalendarOff }),
2135
- /* @__PURE__ */ jsx(StatCard, { variant: "hero", label: "Total", value: data?.schedules.length || 0, icon: IconListCheck })
2582
+ },
2583
+ deployment.id
2584
+ );
2585
+ }) })
2136
2586
  ] }),
2137
- /* @__PURE__ */ jsx(Paper, { children: /* @__PURE__ */ jsxs(Stack, { children: [
2138
- /* @__PURE__ */ jsxs(
2139
- FilterBar,
2140
- {
2141
- actions: /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
2142
- /* @__PURE__ */ jsxs(Badge, { size: "sm", variant: "light", leftSection: /* @__PURE__ */ jsx(IconCalendarRepeat, { size: 12 }), children: [
2143
- schedulesByType.recurring,
2144
- " Recurring"
2145
- ] }),
2146
- /* @__PURE__ */ jsxs(Badge, { size: "sm", variant: "light", leftSection: /* @__PURE__ */ jsx(IconCalendarEvent, { size: 12 }), children: [
2147
- schedulesByType.relative,
2148
- " Relative"
2149
- ] }),
2150
- /* @__PURE__ */ jsxs(Badge, { size: "sm", variant: "light", leftSection: /* @__PURE__ */ jsx(IconCalendarTime, { size: 12 }), children: [
2151
- schedulesByType.absolute,
2152
- " Absolute"
2153
- ] })
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
+ "?"
2154
2610
  ] }),
2155
- 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" }),
2156
2614
  /* @__PURE__ */ jsx(
2157
- Select,
2615
+ Button,
2158
2616
  {
2159
- size: "sm",
2160
- placeholder: "Status",
2161
- data: [
2162
- { value: "all", label: "All Statuses" },
2163
- { value: "active", label: "Active" },
2164
- { value: "paused", label: "Paused" },
2165
- { value: "completed", label: "Completed" },
2166
- { value: "cancelled", label: "Cancelled" }
2167
- ],
2168
- value: statusFilter,
2169
- onChange: (v) => setStatusFilter(v || "all"),
2170
- clearable: false,
2171
- style: { minWidth: 150 }
2617
+ color: "green",
2618
+ onClick: handleConfirmActivate,
2619
+ loading: activateMutation.isPending,
2620
+ leftSection: /* @__PURE__ */ jsx(IconPlayerPlay, { size: 16 }),
2621
+ children: "Activate"
2172
2622
  }
2173
- ),
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" }),
2174
2653
  /* @__PURE__ */ jsx(
2175
- Select,
2654
+ Button,
2176
2655
  {
2177
- size: "sm",
2178
- placeholder: "Type",
2179
- data: [
2180
- { value: "all", label: "All Types" },
2181
- { value: "recurring", label: "Recurring" },
2182
- { value: "relative", label: "Relative" },
2183
- { value: "absolute", label: "Absolute" }
2184
- ],
2185
- value: typeFilter,
2186
- onChange: (v) => setTypeFilter(v || "all"),
2187
- clearable: false,
2188
- style: { minWidth: 150 }
2656
+ color: "orange",
2657
+ onClick: handleConfirmDeactivate,
2658
+ loading: deactivateMutation.isPending,
2659
+ leftSection: /* @__PURE__ */ jsx(IconPower, { size: 16 }),
2660
+ children: "Deactivate"
2189
2661
  }
2190
2662
  )
2191
- ]
2192
- }
2193
- ),
2194
- viewMode === "timeline" && filteredSchedules.length > 0 && /* @__PURE__ */ jsxs(Stack, { children: [
2195
- /* @__PURE__ */ jsx(CardHeader, { icon: /* @__PURE__ */ jsx(IconCalendarEvent, { size: 18 }), title: "All Schedules" }),
2196
- /* @__PURE__ */ jsx(Timeline, { bulletSize: 24, lineWidth: 2, children: [...filteredSchedules].sort((a, b) => {
2197
- const aDate = a.nextRunAt ? typeof a.nextRunAt === "string" ? new Date(a.nextRunAt) : a.nextRunAt : new Date(9999, 0);
2198
- const bDate = b.nextRunAt ? typeof b.nextRunAt === "string" ? new Date(b.nextRunAt) : b.nextRunAt : new Date(9999, 0);
2199
- return aDate.getTime() - bDate.getTime();
2200
- }).map((schedule) => {
2201
- const nextRun = schedule.nextRunAt ? typeof schedule.nextRunAt === "string" ? new Date(schedule.nextRunAt) : schedule.nextRunAt : null;
2202
- const isOverdue = nextRun && nextRun.getTime() < Date.now();
2203
- return /* @__PURE__ */ jsxs(
2204
- Timeline.Item,
2205
- {
2206
- style: { cursor: "pointer" },
2207
- onClick: () => handleCardClick(schedule),
2208
- bullet: /* @__PURE__ */ jsx(ThemeIcon, { size: 24, radius: "xl", children: /* @__PURE__ */ jsx(IconClock, { size: 12 }) }),
2209
- title: /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
2210
- /* @__PURE__ */ jsx(Text, { fw: 600, style: { fontFamily: "var(--mantine-font-family-headings)" }, children: schedule.name }),
2211
- /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", children: [
2212
- /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", color: isOverdue ? "orange" : void 0, children: formatNextRun2(schedule) }),
2213
- /* @__PURE__ */ jsx(
2214
- Badge,
2215
- {
2216
- size: "sm",
2217
- variant: "light",
2218
- color: schedule.status === "active" ? "green" : "yellow",
2219
- children: schedule.status
2220
- }
2221
- )
2222
- ] })
2223
- ] }),
2224
- children: [
2225
- schedule.description && /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", mt: 4, children: schedule.description }),
2226
- /* @__PURE__ */ jsxs(Group, { gap: "xs", mt: "xs", children: [
2227
- /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", children: schedule.target.resourceType }),
2228
- /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "outline", children: schedule.scheduleConfig.type })
2229
- ] })
2230
- ]
2231
- },
2232
- schedule.id
2233
- );
2234
- }) })
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" })
2235
2671
  ] }),
2236
- viewMode === "buckets" && /* @__PURE__ */ jsxs(Fragment, { children: [
2237
- timeBuckets.today.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2238
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2239
- /* @__PURE__ */ jsx(Title, { order: 4, children: "Today" }),
2240
- /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", children: timeBuckets.today.length })
2241
- ] }),
2242
- renderScheduleCards(timeBuckets.today)
2243
- ] }),
2244
- timeBuckets.tomorrow.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2245
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2246
- /* @__PURE__ */ jsx(Title, { order: 4, children: "Tomorrow" }),
2247
- /* @__PURE__ */ jsx(Badge, { color: "orange", size: "sm", variant: "light", children: timeBuckets.tomorrow.length })
2248
- ] }),
2249
- renderScheduleCards(timeBuckets.tomorrow)
2250
- ] }),
2251
- timeBuckets.thisWeek.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2252
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2253
- /* @__PURE__ */ jsx(Title, { order: 4, children: "This Week" }),
2254
- /* @__PURE__ */ jsx(Badge, { size: "sm", variant: "light", children: timeBuckets.thisWeek.length })
2255
- ] }),
2256
- renderScheduleCards(timeBuckets.thisWeek)
2257
- ] }),
2258
- timeBuckets.later.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2259
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2260
- /* @__PURE__ */ jsx(Title, { order: 4, children: "Later" }),
2261
- /* @__PURE__ */ jsx(Badge, { color: "gray", size: "sm", variant: "light", children: timeBuckets.later.length })
2262
- ] }),
2263
- 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
+ '..."'
2264
2679
  ] }),
2265
- timeBuckets.noNextRun.length > 0 && /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
2266
- /* @__PURE__ */ jsxs(Group, { justify: "space-between", children: [
2267
- /* @__PURE__ */ jsx(Text, { fw: 600, size: "md", c: "dimmed", children: "No Scheduled Run" }),
2268
- /* @__PURE__ */ jsx(Badge, { color: "gray", size: "sm", variant: "light", children: timeBuckets.noNextRun.length })
2269
- ] }),
2270
- renderScheduleCards(timeBuckets.noNextRun)
2271
- ] })
2680
+ "?"
2272
2681
  ] }),
2273
- filteredSchedules.length === 0 && /* @__PURE__ */ jsx(
2274
- 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,
2275
2710
  {
2276
- icon: IconClock,
2277
- title: "No schedules found",
2278
- 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
2279
2736
  }
2280
2737
  )
2281
- ] }) }),
2282
- /* @__PURE__ */ jsx(CreateScheduleModal, { opened: isModalOpen, onClose: () => setIsModalOpen(false) }),
2283
- /* @__PURE__ */ jsx(
2284
- DeleteScheduleModal,
2285
- {
2286
- opened: isDeleteModalOpen,
2287
- onClose: handleCloseDeleteModal,
2288
- onConfirm: handleConfirmDelete,
2289
- schedule: scheduleToDelete,
2290
- isDeleting: deleteSchedule.isPending
2291
- }
2292
- ),
2293
- /* @__PURE__ */ jsx(
2294
- ScheduleDetailModal,
2295
- {
2296
- opened: !!selectedSchedule,
2297
- onClose: () => setSelectedSchedule(null),
2298
- schedule: selectedSchedule,
2299
- resourceStatus: selectedSchedule ? resourceStatusMap.get(selectedSchedule.target.resourceId) : void 0
2300
- }
2301
- )
2738
+ ] }),
2739
+ /* @__PURE__ */ jsx(Paper, { withBorder: true, children: /* @__PURE__ */ jsx(DeploymentList, { deployments, isLoading }) })
2302
2740
  ] });
2303
- };
2741
+ }
2304
2742
  function RichTextEditor({ content, onChange, placeholder }) {
2305
2743
  const editor = useEditor({
2306
2744
  extensions: [
@@ -2574,7 +3012,14 @@ function DealKanbanCard({ deal, config, onClick, onDragStart, onDragEnd }) {
2574
3012
  size: "xs",
2575
3013
  color: deal.priority.color,
2576
3014
  style: { flexShrink: 0, maxWidth: 112, textTransform: "none" },
2577
- 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
+ )
2578
3023
  }
2579
3024
  ) })
2580
3025
  ] }),
@@ -3085,4 +3530,4 @@ function CloudStorageBrowser({
3085
3530
  ] }) });
3086
3531
  }
3087
3532
 
3088
- export { AbsoluteScheduleForm, ApiKeyDisplayModal, ApiKeyList, ApiKeySettings, Breadcrumbs, CloudStorageBrowser, CloudStorageFileCard, CloudStorageFileGrid, CloudStorageFolderTree, CreateApiKeyModal, CreateRoleModal, CreateScheduleModal, DEAL_STAGES, DEFAULT_KANBAN_CONFIG, DealKanbanCard, DeleteScheduleModal, DeploymentDetailModal, DeploymentList, DeploymentSettings, DeploymentStatusBadge, EditApiKeyModal, KanbanBoard, MdxRenderer, NotificationBell, NotificationPanel, PermissionMatrix, RecurringScheduleForm, RelativeScheduleForm, RichTextEditor, ScheduleCard, ScheduleDetailModal, ScheduleTypeSelector, TaskScheduler, mdxComponents };
3533
+ export { AbsoluteScheduleForm, ApiKeyDisplayModal, ApiKeyList, ApiKeySettings, Breadcrumbs, CloudStorageBrowser, CloudStorageFileCard, CloudStorageFileGrid, CloudStorageFolderTree, CreateApiKeyModal, CreateCredentialModal, CreateRoleModal, CreateScheduleModal, CredentialList, CredentialSettings, DEAL_STAGES, DEFAULT_KANBAN_CONFIG, DealKanbanCard, DeleteScheduleModal, DeploymentDetailModal, DeploymentList, DeploymentSettings, DeploymentStatusBadge, EditApiKeyModal, KanbanBoard, MdxRenderer, NotificationBell, NotificationPanel, PermissionMatrix, RecurringScheduleForm, RelativeScheduleForm, RichTextEditor, ScheduleCard, ScheduleDetailModal, ScheduleTypeSelector, TaskScheduler, mdxComponents };