@elevasis/ui 1.26.0 → 1.27.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 (53) hide show
  1. package/dist/charts/index.js +2 -2
  2. package/dist/{chunk-AWT255UH.js → chunk-2IJCM3VQ.js} +37 -37
  3. package/dist/chunk-5COLSYBE.js +199 -0
  4. package/dist/{chunk-RMPXGBNI.js → chunk-5JSR6TL5.js} +2 -2
  5. package/dist/chunk-BAGYETKM.js +635 -0
  6. package/dist/{chunk-L3GVDMCA.js → chunk-C27LLJM6.js} +3 -195
  7. package/dist/{chunk-O4UB5DQQ.js → chunk-F2J7675J.js} +1 -1
  8. package/dist/chunk-ITCEULI5.js +238 -0
  9. package/dist/{chunk-4WKWLFBZ.js → chunk-P5EWG45B.js} +1 -1
  10. package/dist/{chunk-BS4J2LAW.js → chunk-QTD5HPKD.js} +1 -1
  11. package/dist/{chunk-ZVJKIJFG.js → chunk-RCQPWA5X.js} +13 -42
  12. package/dist/chunk-TLAIQC7B.js +6382 -0
  13. package/dist/{chunk-FEZZ3IDU.js → chunk-TXPUIHX2.js} +10 -10
  14. package/dist/{chunk-L4XXM55J.js → chunk-W4VYXIN7.js} +142 -3
  15. package/dist/chunk-WJ7W7JU4.js +2115 -0
  16. package/dist/{chunk-YNGQ7U5H.js → chunk-WLNEJ6JJ.js} +2 -2
  17. package/dist/{chunk-4INR75ZS.js → chunk-Y2SYGFRF.js} +589 -65
  18. package/dist/components/index.d.ts +333 -73
  19. package/dist/components/index.js +838 -686
  20. package/dist/features/auth/index.d.ts +125 -0
  21. package/dist/features/auth/index.js +2 -2
  22. package/dist/features/dashboard/index.d.ts +28 -2
  23. package/dist/features/dashboard/index.js +21 -635
  24. package/dist/features/monitoring/index.d.ts +28 -1
  25. package/dist/features/monitoring/index.js +19 -529
  26. package/dist/features/operations/index.d.ts +51 -8
  27. package/dist/features/operations/index.js +25 -3760
  28. package/dist/features/settings/index.d.ts +153 -1
  29. package/dist/features/settings/index.js +19 -1438
  30. package/dist/hooks/index.d.ts +262 -25
  31. package/dist/hooks/index.js +12 -8
  32. package/dist/hooks/published.d.ts +137 -25
  33. package/dist/hooks/published.js +11 -7
  34. package/dist/index.d.ts +310 -28
  35. package/dist/index.js +12 -11
  36. package/dist/initialization/index.d.ts +125 -0
  37. package/dist/layout/index.d.ts +2 -0
  38. package/dist/layout/index.js +6 -5
  39. package/dist/organization/index.js +1 -2
  40. package/dist/profile/index.d.ts +125 -0
  41. package/dist/provider/index.d.ts +48 -3
  42. package/dist/provider/index.js +10 -4
  43. package/dist/provider/published.d.ts +48 -3
  44. package/dist/provider/published.js +8 -2
  45. package/dist/supabase/index.d.ts +242 -0
  46. package/dist/theme/index.js +2 -2
  47. package/dist/types/index.d.ts +126 -1
  48. package/package.json +1 -1
  49. package/dist/chunk-LR4WVA7W.js +0 -682
  50. package/dist/chunk-R7WLWGPO.js +0 -126
  51. package/dist/chunk-TCKIAHDC.js +0 -2626
  52. package/dist/chunk-V7XHGJQZ.js +0 -145
  53. package/dist/{chunk-WWEMNIHW.js → chunk-YYBM5LNJ.js} +1 -1
@@ -0,0 +1,635 @@
1
+ import { ResourceHealthChart } from './chunk-LGKLC5MG.js';
2
+ import { ExecutionStats } from './chunk-F2J7675J.js';
3
+ import { HeroStatsRow, useCyberColors } from './chunk-JHVKGZ2P.js';
4
+ import { CardHeader, EmptyState, PageTitleCaption, TabCountBadge, GlowDot } from './chunk-MCA6LOGM.js';
5
+ import { AppShellCenteredContainer, AppShellLoader } from './chunk-YYBM5LNJ.js';
6
+ import { useTimeRangeDates } from './chunk-WLNEJ6JJ.js';
7
+ import { useDashboardMetrics, useResources, useUnresolvedErrors, useRecentExecutionsByResource, useCommandQueue, useScheduledTasks, useResourcesHealth } from './chunk-RCQPWA5X.js';
8
+ import { getTimeRangeDates } from './chunk-LXHZYSMQ.js';
9
+ import { ResourceStatusColors } from './chunk-ELJIFLCB.js';
10
+ import { formatTimeAgo, formatRelativeTime } from './chunk-IOKL7BKE.js';
11
+ import { useInitialization } from './chunk-TUXTSEAF.js';
12
+ import { useMemo, useState } from 'react';
13
+ import { Paper, Group, Badge, ActionIcon, Center, Loader, SimpleGrid, Stack, Title, Text, Tabs, Box, Card, Grid, ThemeIcon } from '@mantine/core';
14
+ import { IconDashboard, IconArrowUpRight, IconLayoutDashboard, IconActivity, IconAlertTriangle, IconHandStop, IconCalendarEvent, IconPlayerPlay, IconCircleCheck, IconBrain, IconGitBranch } from '@tabler/icons-react';
15
+ import '@mantine/charts/styles.css';
16
+ import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
17
+
18
+ var DEFAULT_LIMIT = 6;
19
+ var typeIcons = {
20
+ workflow: IconGitBranch,
21
+ agent: IconBrain
22
+ };
23
+ function ResourceCard({ resource, onClick }) {
24
+ const [hovered, setHovered] = useState(false);
25
+ const Icon = typeIcons[resource.type] ?? IconActivity;
26
+ const cyberColors = useCyberColors();
27
+ return /* @__PURE__ */ jsxs(
28
+ Card,
29
+ {
30
+ withBorder: true,
31
+ style: {
32
+ cursor: "pointer",
33
+ transition: "all 150ms ease",
34
+ borderColor: hovered ? "color-mix(in srgb, var(--color-primary) 40%, var(--color-border))" : "var(--color-border)",
35
+ boxShadow: hovered ? "var(--card-shadow), 0 0 12px color-mix(in srgb, var(--color-primary) 25%, transparent)" : "var(--card-shadow)",
36
+ transform: hovered ? "translateY(-1px)" : "none"
37
+ },
38
+ onMouseEnter: () => setHovered(true),
39
+ onMouseLeave: () => setHovered(false),
40
+ onClick,
41
+ children: [
42
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: "sm", wrap: "nowrap", align: "flex-start", children: [
43
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", wrap: "nowrap", style: { minWidth: 0 }, children: [
44
+ /* @__PURE__ */ jsx(ThemeIcon, { size: 32, radius: "md", variant: "light", children: /* @__PURE__ */ jsx(Icon, { size: 18 }) }),
45
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, truncate: true, children: resource.name })
46
+ ] }),
47
+ resource.active && resource.execution ? (() => {
48
+ const rate = resource.execution.successRate;
49
+ const color = rate >= 95 ? cyberColors.green : rate >= 80 ? cyberColors.yellow : cyberColors.red;
50
+ return /* @__PURE__ */ jsxs(Group, { gap: 8, wrap: "nowrap", style: { flexShrink: 0 }, children: [
51
+ /* @__PURE__ */ jsxs(Text, { size: "xs", fw: 500, style: { color, letterSpacing: "0.03em" }, children: [
52
+ rate.toFixed(0),
53
+ "%"
54
+ ] }),
55
+ /* @__PURE__ */ jsx(GlowDot, { size: "md", color })
56
+ ] });
57
+ })() : null
58
+ ] }),
59
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
60
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
61
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", children: resource.type }),
62
+ /* @__PURE__ */ jsx(
63
+ Badge,
64
+ {
65
+ size: "xs",
66
+ variant: "light",
67
+ color: ResourceStatusColors[resource.status],
68
+ children: resource.status
69
+ }
70
+ )
71
+ ] }),
72
+ resource.active && resource.execution ? /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", style: { flexShrink: 0 }, children: [
73
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
74
+ resource.execution.totalExecutions,
75
+ " runs"
76
+ ] }),
77
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "\xB7" }),
78
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
79
+ "Last run ",
80
+ formatTimeAgo(resource.execution.lastExecution)
81
+ ] })
82
+ ] }) : /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No recent activity" })
83
+ ] })
84
+ ]
85
+ }
86
+ );
87
+ }
88
+ function ResourceOverview({
89
+ recentExecutions,
90
+ allResources,
91
+ isLoading,
92
+ limit = DEFAULT_LIMIT,
93
+ onResourceClick
94
+ }) {
95
+ const { displayResources, totalCount } = useMemo(() => {
96
+ const items = [];
97
+ const seenIds = /* @__PURE__ */ new Set();
98
+ const resourceLookup = /* @__PURE__ */ new Map();
99
+ if (allResources) {
100
+ for (const r of [...allResources.workflows, ...allResources.agents]) {
101
+ resourceLookup.set(r.resourceId, r);
102
+ }
103
+ }
104
+ if (recentExecutions) {
105
+ for (const exec of recentExecutions) {
106
+ const def = resourceLookup.get(exec.resourceId);
107
+ items.push({
108
+ resourceId: exec.resourceId,
109
+ name: def?.name ?? exec.resourceName ?? exec.resourceId,
110
+ type: def?.type ?? exec.resourceType ?? "",
111
+ status: def?.status ?? "dev",
112
+ active: true,
113
+ execution: exec
114
+ });
115
+ seenIds.add(exec.resourceId);
116
+ }
117
+ }
118
+ if (allResources) {
119
+ for (const r of [...allResources.workflows, ...allResources.agents]) {
120
+ if (!seenIds.has(r.resourceId)) {
121
+ items.push({
122
+ resourceId: r.resourceId,
123
+ name: r.name,
124
+ type: r.type,
125
+ status: r.status,
126
+ active: false
127
+ });
128
+ seenIds.add(r.resourceId);
129
+ }
130
+ }
131
+ }
132
+ return { displayResources: items.slice(0, limit), totalCount: items.length };
133
+ }, [recentExecutions, allResources, limit]);
134
+ const handleClick = (resource) => {
135
+ onResourceClick?.(resource);
136
+ };
137
+ return /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
138
+ /* @__PURE__ */ jsx(
139
+ CardHeader,
140
+ {
141
+ icon: /* @__PURE__ */ jsx(IconLayoutDashboard, { size: 18 }),
142
+ title: "Resources",
143
+ subtitle: totalCount > limit ? `Showing ${limit} of ${totalCount}` : void 0,
144
+ rightSection: /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
145
+ totalCount > 0 && /* @__PURE__ */ jsxs(Badge, { variant: "light", size: "sm", children: [
146
+ totalCount,
147
+ " total"
148
+ ] }),
149
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", onClick: () => onResourceClick?.(displayResources[0]), children: /* @__PURE__ */ jsx(IconArrowUpRight, { size: 16 }) })
150
+ ] })
151
+ }
152
+ ),
153
+ isLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) : displayResources.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { icon: IconLayoutDashboard, title: "No resources registered" }) : /* @__PURE__ */ jsx(SimpleGrid, { cols: { base: 1, sm: 2, lg: 3 }, children: displayResources.map((resource) => /* @__PURE__ */ jsx(ResourceCard, { resource, onClick: () => handleClick(resource) }, resource.resourceId)) })
154
+ ] });
155
+ }
156
+ var severityColor = {
157
+ critical: "red",
158
+ warning: "yellow",
159
+ info: "blue"
160
+ };
161
+ function Dashboard({
162
+ timeRange,
163
+ onResourceClick,
164
+ onErrorsNavigate,
165
+ onCommandQueueNavigate,
166
+ onScheduledTasksNavigate,
167
+ renderTrendChart
168
+ }) {
169
+ const { organizationReady, error: initError } = useInitialization();
170
+ const { data: dashboardDataRaw, isLoading, error } = useDashboardMetrics(timeRange);
171
+ const dashboardData = dashboardDataRaw;
172
+ const { data: resourcesData, isLoading: resourcesLoading } = useResources();
173
+ const { startDate, endDate } = useTimeRangeDates(timeRange);
174
+ const { data: errorData, isLoading: errorsLoading } = useUnresolvedErrors({ startDate, endDate });
175
+ const { data: recentExecData, isLoading: recentExecLoading } = useRecentExecutionsByResource({
176
+ timeRange,
177
+ limit: 6
178
+ });
179
+ if (initError?.layer === "organization") {
180
+ return /* @__PURE__ */ jsx(AppShellCenteredContainer, { children: /* @__PURE__ */ jsxs(Stack, { align: "center", justify: "center", children: [
181
+ /* @__PURE__ */ jsx(Title, { order: 3, c: "dimmed", children: "No organization detected" }),
182
+ /* @__PURE__ */ jsx(Text, { size: "sm", c: "dimmed", children: initError?.message })
183
+ ] }) });
184
+ }
185
+ if (!organizationReady || isLoading || resourcesLoading) return /* @__PURE__ */ jsx(AppShellLoader, {});
186
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
187
+ /* @__PURE__ */ jsx(PageTitleCaption, { title: "Dashboard", caption: "AI Operations Health & Performance" }),
188
+ /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
189
+ /* @__PURE__ */ jsx(
190
+ HeroStatsRow,
191
+ {
192
+ resourcesData,
193
+ resourcesLoading,
194
+ dashboardData,
195
+ dashboardLoading: isLoading,
196
+ unresolvedErrorCount: errorData?.total ?? null,
197
+ errorsLoading
198
+ }
199
+ ),
200
+ renderTrendChart?.(dashboardData?.executionHealth, isLoading, error ?? void 0)
201
+ ] }),
202
+ /* @__PURE__ */ jsx(
203
+ ResourceOverview,
204
+ {
205
+ recentExecutions: recentExecData?.resources,
206
+ allResources: resourcesData,
207
+ isLoading: resourcesLoading || recentExecLoading,
208
+ limit: 6,
209
+ onResourceClick: onResourceClick ? (resource) => onResourceClick({
210
+ resourceId: resource.resourceId,
211
+ resourceType: resource.type
212
+ }) : void 0
213
+ }
214
+ ),
215
+ /* @__PURE__ */ jsx(
216
+ OperationalOverview,
217
+ {
218
+ timeRange,
219
+ onErrorsNavigate,
220
+ onCommandQueueNavigate,
221
+ onScheduledTasksNavigate
222
+ }
223
+ )
224
+ ] });
225
+ }
226
+ function OperationalOverview({
227
+ timeRange,
228
+ onErrorsNavigate,
229
+ onCommandQueueNavigate,
230
+ onScheduledTasksNavigate
231
+ }) {
232
+ const { startDate, endDate } = useTimeRangeDates(timeRange);
233
+ const { data: errorData, isLoading: errorsLoading } = useUnresolvedErrors({ startDate, endDate });
234
+ const errors = errorData?.errors ?? [];
235
+ const errorCount = errorData?.total ?? 0;
236
+ const { data: allCommands } = useCommandQueue({ status: "pending", limit: 100 });
237
+ const commands = allCommands ?? [];
238
+ const commandCount = commands.length;
239
+ const { data: allTasks, isLoading: tasksLoading } = useScheduledTasks();
240
+ const tasks = allTasks ?? [];
241
+ const now = /* @__PURE__ */ new Date();
242
+ const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
243
+ const { totalScheduled, upcomingTasks } = useMemo(() => {
244
+ const totalScheduled2 = tasks.filter((t) => t.status === "active").length;
245
+ const upcomingTasks2 = tasks.filter((t) => t.status === "active" && t.nextRunAt).sort((a, b) => new Date(a.nextRunAt).getTime() - new Date(b.nextRunAt).getTime()).slice(0, 5);
246
+ return { totalScheduled: totalScheduled2, upcomingTasks: upcomingTasks2 };
247
+ }, [tasks]);
248
+ const defaultTab = useMemo(() => {
249
+ if (errorCount > 0) return "errors";
250
+ if (commandCount > 0) return "commands";
251
+ if (totalScheduled > 0) return "scheduled";
252
+ return "errors";
253
+ }, [errorCount, commandCount, totalScheduled]);
254
+ const [activeTab, setActiveTab] = useState(null);
255
+ const effectiveTab = activeTab ?? defaultTab;
256
+ const formatDaysUntil = (runAt) => {
257
+ const diffMs = runAt.getTime() - now.getTime();
258
+ const diffDays = Math.floor(diffMs / (1e3 * 60 * 60 * 24));
259
+ const diffHours = Math.floor(diffMs / (1e3 * 60 * 60));
260
+ if (diffHours < 0) return "Overdue";
261
+ if (diffHours < 1) return "Soon";
262
+ if (diffDays === 0) return "Today";
263
+ if (diffDays === 1) return "Tomorrow";
264
+ if (diffDays <= 7) return `In ${diffDays}d`;
265
+ return `In ${Math.floor(diffDays / 7)}w`;
266
+ };
267
+ return /* @__PURE__ */ jsxs(Paper, { withBorder: true, children: [
268
+ /* @__PURE__ */ jsx(CardHeader, { icon: /* @__PURE__ */ jsx(IconActivity, { size: 18 }), title: "Operational Overview" }),
269
+ /* @__PURE__ */ jsxs(Tabs, { value: effectiveTab, onChange: setActiveTab, variant: "default", children: [
270
+ /* @__PURE__ */ jsxs(Tabs.List, { children: [
271
+ /* @__PURE__ */ jsx(
272
+ Tabs.Tab,
273
+ {
274
+ value: "errors",
275
+ leftSection: /* @__PURE__ */ jsx(IconAlertTriangle, { size: 16 }),
276
+ rightSection: /* @__PURE__ */ jsx(TabCountBadge, { count: errorCount, isLoading: errorsLoading }),
277
+ children: "Unresolved Errors"
278
+ }
279
+ ),
280
+ /* @__PURE__ */ jsx(
281
+ Tabs.Tab,
282
+ {
283
+ value: "commands",
284
+ leftSection: /* @__PURE__ */ jsx(IconHandStop, { size: 16 }),
285
+ rightSection: /* @__PURE__ */ jsx(TabCountBadge, { count: commandCount }),
286
+ children: "Command Queue"
287
+ }
288
+ ),
289
+ /* @__PURE__ */ jsx(
290
+ Tabs.Tab,
291
+ {
292
+ value: "scheduled",
293
+ leftSection: /* @__PURE__ */ jsx(IconCalendarEvent, { size: 16 }),
294
+ rightSection: /* @__PURE__ */ jsx(TabCountBadge, { count: totalScheduled, isLoading: tasksLoading }),
295
+ children: "Scheduled Tasks"
296
+ }
297
+ )
298
+ ] }),
299
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "errors", pt: "sm", children: errorsLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) : errors.length === 0 ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No unresolved errors" }) : /* @__PURE__ */ jsxs(Stack, { gap: 4, children: [
300
+ errors.map((error) => /* @__PURE__ */ jsx(
301
+ Box,
302
+ {
303
+ px: "sm",
304
+ py: 6,
305
+ onClick: onErrorsNavigate,
306
+ style: {
307
+ borderRadius: 4,
308
+ cursor: onErrorsNavigate ? "pointer" : "default"
309
+ },
310
+ children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
311
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", style: { minWidth: 200, width: 200, flexShrink: 0 }, children: [
312
+ /* @__PURE__ */ jsx(
313
+ Box,
314
+ {
315
+ style: {
316
+ width: 8,
317
+ height: 8,
318
+ borderRadius: "50%",
319
+ backgroundColor: `var(--mantine-color-${severityColor[error.severity]}-6)`,
320
+ flexShrink: 0
321
+ }
322
+ }
323
+ ),
324
+ /* @__PURE__ */ jsxs(Stack, { gap: 0, style: { minWidth: 0 }, children: [
325
+ /* @__PURE__ */ jsx(Text, { size: "xs", lineClamp: 1, children: error.resourceName || error.resourceId }),
326
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", lineClamp: 1, children: error.errorType })
327
+ ] })
328
+ ] }),
329
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", lineClamp: 1, style: { flex: "1 1 auto", minWidth: 0 }, children: error.message }),
330
+ /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", style: { flexShrink: 0 }, children: [
331
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: severityColor[error.severity], children: error.severity }),
332
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatTimeAgo(error.timestamp) })
333
+ ] })
334
+ ] })
335
+ },
336
+ error.id
337
+ )),
338
+ errorCount > 5 && /* @__PURE__ */ jsx(
339
+ Group,
340
+ {
341
+ gap: 4,
342
+ justify: "center",
343
+ pt: 4,
344
+ onClick: onErrorsNavigate,
345
+ style: { cursor: onErrorsNavigate ? "pointer" : "default" },
346
+ children: /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "See all errors" })
347
+ }
348
+ )
349
+ ] }) }),
350
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "commands", pt: "sm", children: commands.length === 0 ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No pending decisions" }) : /* @__PURE__ */ jsx(Stack, { gap: 4, children: commands.slice(0, 5).map((task) => /* @__PURE__ */ jsx(
351
+ Box,
352
+ {
353
+ px: "sm",
354
+ py: 6,
355
+ onClick: onCommandQueueNavigate,
356
+ style: {
357
+ borderRadius: 4,
358
+ cursor: onCommandQueueNavigate ? "pointer" : "default"
359
+ },
360
+ children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
361
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", style: { minWidth: 0 }, children: [
362
+ /* @__PURE__ */ jsx(
363
+ Box,
364
+ {
365
+ style: {
366
+ width: 8,
367
+ height: 8,
368
+ borderRadius: "50%",
369
+ backgroundColor: `var(--mantine-color-${task.priority >= 8 ? "red" : task.priority >= 4 ? "yellow" : "blue"}-6)`,
370
+ flexShrink: 0
371
+ }
372
+ }
373
+ ),
374
+ /* @__PURE__ */ jsx(Text, { size: "xs", lineClamp: 1, children: task.description || "No description" })
375
+ ] }),
376
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", children: task.status })
377
+ ] })
378
+ },
379
+ task.id
380
+ )) }) }),
381
+ /* @__PURE__ */ jsx(Tabs.Panel, { value: "scheduled", pt: "sm", children: tasksLoading ? /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) }) : upcomingTasks.length === 0 ? /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No scheduled tasks" }) : /* @__PURE__ */ jsx(Stack, { gap: 4, children: upcomingTasks.map((task) => {
382
+ const runAt = new Date(task.nextRunAt);
383
+ const daysUntilNum = Math.floor((runAt.getTime() - today.getTime()) / (1e3 * 60 * 60 * 24));
384
+ return /* @__PURE__ */ jsx(
385
+ Box,
386
+ {
387
+ px: "sm",
388
+ py: 6,
389
+ onClick: onScheduledTasksNavigate,
390
+ style: {
391
+ borderRadius: 4,
392
+ cursor: onScheduledTasksNavigate ? "pointer" : "default"
393
+ },
394
+ children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
395
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", wrap: "nowrap", style: { minWidth: 0 }, children: [
396
+ /* @__PURE__ */ jsx(
397
+ Box,
398
+ {
399
+ style: {
400
+ width: 8,
401
+ height: 8,
402
+ borderRadius: "50%",
403
+ backgroundColor: `var(--mantine-color-${daysUntilNum < 0 ? "red" : daysUntilNum <= 1 ? "yellow" : "blue"}-6)`,
404
+ flexShrink: 0
405
+ }
406
+ }
407
+ ),
408
+ /* @__PURE__ */ jsx(Text, { size: "xs", truncate: true, children: task.name || task.target.resourceId })
409
+ ] }),
410
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: daysUntilNum <= 1 ? void 0 : "gray", children: formatDaysUntil(runAt) })
411
+ ] })
412
+ },
413
+ task.id
414
+ );
415
+ }) }) })
416
+ ] })
417
+ ] });
418
+ }
419
+ var entityTypeConfig = {
420
+ workflow: { icon: IconGitBranch, hasPath: true },
421
+ agent: { icon: IconBrain, hasPath: true }
422
+ };
423
+ function getEntityConfig(entityType) {
424
+ return entityTypeConfig[entityType] || { icon: IconActivity, hasPath: false };
425
+ }
426
+ function RecentExecutionsByResource({ timeRange, limit = 5, onResourceClick }) {
427
+ const { data, isLoading, isFetching, error } = useRecentExecutionsByResource({
428
+ timeRange,
429
+ limit
430
+ });
431
+ const showLoading = (isLoading || isFetching) && !data;
432
+ const { data: resourcesData } = useResources();
433
+ const resourceDefLookup = useMemo(() => {
434
+ if (!resourcesData) return /* @__PURE__ */ new Map();
435
+ const allResources = [...resourcesData.workflows || [], ...resourcesData.agents || []];
436
+ return new Map(allResources.map((r) => [r.resourceId, r]));
437
+ }, [resourcesData]);
438
+ const enrichedExecutions = useMemo(() => {
439
+ if (!data?.resources) return [];
440
+ return data.resources.map((exec) => {
441
+ const resourceDef = resourceDefLookup.get(exec.resourceId);
442
+ return {
443
+ ...exec,
444
+ resourceType: resourceDef?.type || "",
445
+ resourceName: resourceDef?.name || exec.resourceId
446
+ };
447
+ });
448
+ }, [data, resourceDefLookup]);
449
+ const resourceIds = useMemo(
450
+ () => enrichedExecutions.map((r) => ({
451
+ entityType: r.resourceType,
452
+ entityId: r.resourceId
453
+ })),
454
+ [enrichedExecutions]
455
+ );
456
+ const { startDate, endDate } = useMemo(() => getTimeRangeDates(timeRange), [timeRange]);
457
+ const granularity = timeRange === "1h" || timeRange === "24h" ? "hour" : "day";
458
+ const { data: healthData } = useResourcesHealth({
459
+ resources: resourceIds,
460
+ startDate,
461
+ endDate,
462
+ granularity
463
+ });
464
+ const healthLookup = useMemo(() => {
465
+ if (!healthData?.resources) return /* @__PURE__ */ new Map();
466
+ return new Map(healthData.resources.map((r) => [`${r.entityType}-${r.entityId}`, r]));
467
+ }, [healthData]);
468
+ const handleResourceClick = (resource) => {
469
+ const config = getEntityConfig(resource.resourceType);
470
+ if (config.hasPath) {
471
+ onResourceClick?.({ resourceType: resource.resourceType, resourceId: resource.resourceId });
472
+ }
473
+ };
474
+ if (showLoading) {
475
+ return /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) });
476
+ }
477
+ if (error) {
478
+ return /* @__PURE__ */ jsx(Center, { py: "md", children: /* @__PURE__ */ jsxs(Text, { size: "sm", c: "red.6", children: [
479
+ "Failed to load: ",
480
+ error.message
481
+ ] }) });
482
+ }
483
+ if (enrichedExecutions.length === 0) {
484
+ return /* @__PURE__ */ jsx(EmptyState, { icon: IconPlayerPlay, title: "No executions in this time range" });
485
+ }
486
+ return /* @__PURE__ */ jsx(Stack, { gap: "sm", children: enrichedExecutions.map((resource) => {
487
+ const config = getEntityConfig(resource.resourceType);
488
+ const Icon = config.icon;
489
+ const resourceKey = `${resource.resourceType}-${resource.resourceId}`;
490
+ const resourceHealth = healthLookup.get(resourceKey);
491
+ const resourceDef = resourceDefLookup.get(resource.resourceId);
492
+ return /* @__PURE__ */ jsx(
493
+ Card,
494
+ {
495
+ withBorder: true,
496
+ style: {
497
+ cursor: config.hasPath ? "pointer" : "default",
498
+ transition: "box-shadow var(--duration-fast) var(--easing)"
499
+ },
500
+ onClick: () => handleResourceClick(resource),
501
+ children: /* @__PURE__ */ jsxs(Grid, { gutter: "sm", align: "center", children: [
502
+ /* @__PURE__ */ jsx(Grid.Col, { span: 8, children: /* @__PURE__ */ jsxs(Group, { gap: "sm", wrap: "nowrap", children: [
503
+ /* @__PURE__ */ jsx(Icon, { size: 24, color: "var(--color-primary)" }),
504
+ /* @__PURE__ */ jsxs(Stack, { gap: 4, style: { flex: 1, minWidth: 0 }, children: [
505
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 500, truncate: true, children: resource.resourceName }),
506
+ resourceDef?.description && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", truncate: true, children: resourceDef.description }),
507
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
508
+ resourceDef?.version && /* @__PURE__ */ jsxs(Badge, { variant: "outline", size: "xs", children: [
509
+ "v",
510
+ resourceDef.version
511
+ ] }),
512
+ resourceDef?.status && /* @__PURE__ */ jsx(Badge, { color: ResourceStatusColors[resourceDef.status], variant: "outline", size: "xs", children: resourceDef.status.toUpperCase() })
513
+ ] }),
514
+ /* @__PURE__ */ jsxs(Text, { size: "xs", c: "dimmed", children: [
515
+ "Last run ",
516
+ formatRelativeTime(resource.lastExecution)
517
+ ] })
518
+ ] })
519
+ ] }) }),
520
+ /* @__PURE__ */ jsx(Grid.Col, { span: 4, children: /* @__PURE__ */ jsxs(Group, { justify: "flex-end", gap: "md", wrap: "nowrap", children: [
521
+ /* @__PURE__ */ jsx(
522
+ ExecutionStats,
523
+ {
524
+ totalExecutions: resource.totalExecutions,
525
+ successCount: resource.successCount,
526
+ failureCount: resource.failureCount,
527
+ warningCount: resource.warningCount,
528
+ successRate: resource.successRate
529
+ }
530
+ ),
531
+ /* @__PURE__ */ jsx(
532
+ ResourceHealthChart,
533
+ {
534
+ healthData: resourceHealth,
535
+ hasExecutions: resource.totalExecutions > 0,
536
+ width: 300,
537
+ height: 60
538
+ }
539
+ )
540
+ ] }) })
541
+ ] })
542
+ },
543
+ resource.resourceId
544
+ );
545
+ }) });
546
+ }
547
+ var severityColor2 = {
548
+ critical: "red",
549
+ warning: "yellow",
550
+ info: "blue"
551
+ };
552
+ function UnresolvedErrorsTeaser({ timeRange, onNavigateToAllErrors }) {
553
+ const { startDate, endDate } = useTimeRangeDates(timeRange);
554
+ const { data, isLoading } = useUnresolvedErrors({ startDate, endDate });
555
+ const errors = data?.errors ?? [];
556
+ const total = data?.total ?? 0;
557
+ if (isLoading) {
558
+ return /* @__PURE__ */ jsx(
559
+ Paper,
560
+ {
561
+ style: {
562
+ background: "var(--glass-background)",
563
+ backdropFilter: "var(--glass-blur)",
564
+ border: "1px solid var(--color-border)",
565
+ borderRadius: 8
566
+ },
567
+ children: /* @__PURE__ */ jsx(Center, { p: "xl", children: /* @__PURE__ */ jsx(Loader, {}) })
568
+ }
569
+ );
570
+ }
571
+ return /* @__PURE__ */ jsxs(
572
+ Paper,
573
+ {
574
+ style: {
575
+ background: "var(--glass-background)",
576
+ backdropFilter: "var(--glass-blur)",
577
+ border: "1px solid var(--color-border)",
578
+ borderRadius: 8
579
+ },
580
+ children: [
581
+ /* @__PURE__ */ jsxs(Group, { justify: "space-between", mb: errors.length > 0 ? "sm" : 0, children: [
582
+ /* @__PURE__ */ jsxs(Group, { gap: "sm", children: [
583
+ /* @__PURE__ */ jsx(ThemeIcon, { size: 28, radius: "md", variant: "light", color: total > 0 ? "red" : "green", children: total > 0 ? /* @__PURE__ */ jsx(IconAlertTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconCircleCheck, { size: 16 }) }),
584
+ /* @__PURE__ */ jsx(Text, { size: "sm", fw: 600, children: "Unresolved Errors" })
585
+ ] }),
586
+ /* @__PURE__ */ jsxs(Group, { gap: "xs", children: [
587
+ total > 0 && /* @__PURE__ */ jsxs(Badge, { size: "xs", variant: "light", color: "red", children: [
588
+ total,
589
+ " unresolved"
590
+ ] }),
591
+ /* @__PURE__ */ jsx(ActionIcon, { variant: "subtle", size: "sm", onClick: onNavigateToAllErrors, children: /* @__PURE__ */ jsx(IconArrowUpRight, { size: 14 }) })
592
+ ] })
593
+ ] }),
594
+ errors.length === 0 && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "No unresolved errors" }),
595
+ errors.length > 0 && /* @__PURE__ */ jsx(Stack, { gap: 4, children: errors.map((error) => /* @__PURE__ */ jsx(
596
+ Box,
597
+ {
598
+ px: "sm",
599
+ py: 6,
600
+ onClick: onNavigateToAllErrors,
601
+ style: {
602
+ borderLeft: `2px solid var(--mantine-color-${severityColor2[error.severity]}-6)`,
603
+ borderRadius: 4,
604
+ cursor: onNavigateToAllErrors ? "pointer" : "default",
605
+ textDecoration: "none",
606
+ color: "inherit"
607
+ },
608
+ children: /* @__PURE__ */ jsxs(Group, { justify: "space-between", wrap: "nowrap", children: [
609
+ /* @__PURE__ */ jsxs(Stack, { gap: 0, style: { minWidth: 0 }, children: [
610
+ /* @__PURE__ */ jsx(Text, { size: "xs", lineClamp: 1, children: error.resourceName || error.resourceId }),
611
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", lineClamp: 1, children: error.errorType })
612
+ ] }),
613
+ /* @__PURE__ */ jsxs(Group, { gap: 4, wrap: "nowrap", style: { flexShrink: 0 }, children: [
614
+ /* @__PURE__ */ jsx(Badge, { size: "xs", variant: "light", color: severityColor2[error.severity], children: error.severity }),
615
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: formatTimeAgo(error.timestamp) })
616
+ ] })
617
+ ] })
618
+ },
619
+ error.id
620
+ )) })
621
+ ]
622
+ }
623
+ );
624
+ }
625
+ var dashboardManifest = {
626
+ key: "dashboard",
627
+ label: "Dashboard",
628
+ navEntry: {
629
+ label: "Dashboard",
630
+ icon: IconDashboard,
631
+ link: "/"
632
+ }
633
+ };
634
+
635
+ export { Dashboard, RecentExecutionsByResource, ResourceOverview, UnresolvedErrorsTeaser, dashboardManifest };