@alepha/ui 0.16.2 → 0.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/admin/{AdminApiKeys-CoTOTfgU.js → AdminApiKeys-CF_qOO3u.js} +20 -20
- package/dist/admin/AdminApiKeys-CF_qOO3u.js.map +1 -0
- package/dist/admin/{AdminAudits-BmsxFbDa.js → AdminAudits-BQno3hZG.js} +7 -8
- package/dist/admin/AdminAudits-BQno3hZG.js.map +1 -0
- package/dist/admin/{AdminFiles-BBB8knca.js → AdminFiles-kvuUaASF.js} +3 -5
- package/dist/admin/{AdminFiles-BBB8knca.js.map → AdminFiles-kvuUaASF.js.map} +1 -1
- package/dist/admin/AdminJobDashboard-CrPxp0W1.js +485 -0
- package/dist/admin/AdminJobDashboard-CrPxp0W1.js.map +1 -0
- package/dist/admin/AdminJobExecutions-D-b4Zt7W.js +678 -0
- package/dist/admin/AdminJobExecutions-D-b4Zt7W.js.map +1 -0
- package/dist/admin/AdminJobRegistry-CNX5cpDx.js +301 -0
- package/dist/admin/AdminJobRegistry-CNX5cpDx.js.map +1 -0
- package/dist/admin/{AdminLayout-CsjvpeD1.js → AdminLayout-e-ZP5nWw.js} +1 -1
- package/dist/admin/{AdminLayout-CsjvpeD1.js.map → AdminLayout-e-ZP5nWw.js.map} +1 -1
- package/dist/admin/{AdminNotifications-LwR6RKrx.js → AdminNotifications-DeHJFf6W.js} +3 -5
- package/dist/admin/{AdminNotifications-LwR6RKrx.js.map → AdminNotifications-DeHJFf6W.js.map} +1 -1
- package/dist/admin/{AdminParameters-B_83Vie9.js → AdminParameters-iQE8o7a7.js} +43 -36
- package/dist/admin/AdminParameters-iQE8o7a7.js.map +1 -0
- package/dist/admin/{AdminSessions-CWnPosdd.js → AdminSessions-oKJCbd7w.js} +5 -7
- package/dist/admin/AdminSessions-oKJCbd7w.js.map +1 -0
- package/dist/admin/{AdminUserAudits-nHv636E_.js → AdminUserAudits-BNCEle_E.js} +6 -8
- package/dist/admin/AdminUserAudits-BNCEle_E.js.map +1 -0
- package/dist/admin/{AdminUserCreate-CjYD3Kjc.js → AdminUserCreate-CgqeFwCt.js} +6 -7
- package/dist/admin/AdminUserCreate-CgqeFwCt.js.map +1 -0
- package/dist/admin/{AdminUserDetails-Ccq-LsZ0.js → AdminUserDetails-DDe1A1GP.js} +30 -29
- package/dist/admin/AdminUserDetails-DDe1A1GP.js.map +1 -0
- package/dist/admin/{AdminUserLayout-7s41DiF_.js → AdminUserLayout-HAlobhWf.js} +18 -16
- package/dist/admin/AdminUserLayout-HAlobhWf.js.map +1 -0
- package/dist/admin/{AdminUserSessions-Ds3ODq_d.js → AdminUserSessions-Bq1LnVLf.js} +5 -7
- package/dist/admin/AdminUserSessions-Bq1LnVLf.js.map +1 -0
- package/dist/admin/{AdminUserSettings-CGh4gROo.js → AdminUserSettings-BRsBZoxV.js} +10 -10
- package/dist/admin/AdminUserSettings-BRsBZoxV.js.map +1 -0
- package/dist/admin/{AdminUsers-CvPiBzQK.js → AdminUsers-D71kIOSn.js} +6 -8
- package/dist/admin/AdminUsers-D71kIOSn.js.map +1 -0
- package/dist/admin/index.d.ts +7 -83
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +49 -70
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/{Login-DS_OqA0G.js → Login-BS_FYTy0.js} +13 -8
- package/dist/auth/Login-BS_FYTy0.js.map +1 -0
- package/dist/auth/{Profile-Di7N7HZL.js → Profile-CjDsW378.js} +16 -10
- package/dist/auth/Profile-CjDsW378.js.map +1 -0
- package/dist/auth/{Register-BRR2_gux.js → Register-C5eqzAaD.js} +21 -12
- package/dist/auth/Register-C5eqzAaD.js.map +1 -0
- package/dist/auth/{ResetPassword-oQu72lod.js → ResetPassword-XifinVao.js} +14 -8
- package/dist/auth/ResetPassword-XifinVao.js.map +1 -0
- package/dist/auth/{VerifyEmail-DC6HPZjd.js → VerifyEmail-DTgbeJOO.js} +6 -4
- package/dist/auth/VerifyEmail-DTgbeJOO.js.map +1 -0
- package/dist/auth/index.d.ts +4 -0
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +15 -14
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +37 -26
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +444 -193
- package/dist/core/index.js.map +1 -1
- package/dist/demo/DemoDataTable-lnBKWBf8.js +362 -0
- package/dist/demo/DemoDataTable-lnBKWBf8.js.map +1 -0
- package/dist/demo/{DemoHome-DpRrPlBC.js → DemoHome-CUMZsYaH.js} +6 -7
- package/dist/demo/DemoHome-CUMZsYaH.js.map +1 -0
- package/dist/demo/{DemoJsonViewer-zeucGKHV.js → DemoJsonViewer-_uokbGaW.js} +17 -19
- package/dist/demo/DemoJsonViewer-_uokbGaW.js.map +1 -0
- package/dist/demo/{DemoLayout-PhgbAAiQ.js → DemoLayout-DHVoacE6.js} +2 -4
- package/dist/demo/{DemoLayout-PhgbAAiQ.js.map → DemoLayout-DHVoacE6.js.map} +1 -1
- package/dist/demo/{DemoLogin-DSzP0Lkv.js → DemoLogin-DjJ9314c.js} +22 -17
- package/dist/demo/DemoLogin-DjJ9314c.js.map +1 -0
- package/dist/demo/{DemoRegister-DavFBsCz.js → DemoRegister-DzkJ5M83.js} +34 -25
- package/dist/demo/DemoRegister-DzkJ5M83.js.map +1 -0
- package/dist/demo/{DemoResetPassword-BS2rIAQK.js → DemoResetPassword-DWh4_BpQ.js} +27 -21
- package/dist/demo/DemoResetPassword-DWh4_BpQ.js.map +1 -0
- package/dist/demo/{DemoSidebar-zNkUmHRl.js → DemoSidebar-C1csnGhX.js} +2 -2
- package/dist/demo/{DemoSidebar-zNkUmHRl.js.map → DemoSidebar-C1csnGhX.js.map} +1 -1
- package/dist/demo/{DemoTypeForm-B9q7oT0b.js → DemoTypeForm-CWz6fJrJ.js} +2 -2
- package/dist/demo/{DemoTypeForm-B9q7oT0b.js.map → DemoTypeForm-CWz6fJrJ.js.map} +1 -1
- package/dist/demo/{DemoVerifyEmail-Bi4SdWz0.js → DemoVerifyEmail-DbU_tCj8.js} +13 -11
- package/dist/demo/DemoVerifyEmail-DbU_tCj8.js.map +1 -0
- package/dist/demo/{IconGoogle-CTeZyrek.js → IconGoogle-Ch1m3Uzl.js} +1 -1
- package/dist/demo/{IconGoogle-CTeZyrek.js.map → IconGoogle-Ch1m3Uzl.js.map} +1 -1
- package/dist/demo/{Showcase-C9btr_SJ.js → Showcase-BzoXNlCn.js} +10 -10
- package/dist/demo/Showcase-BzoXNlCn.js.map +1 -0
- package/dist/demo/index.d.ts +1 -68
- package/dist/demo/index.d.ts.map +1 -1
- package/dist/demo/index.js +11 -15
- package/dist/demo/index.js.map +1 -1
- package/dist/json/index.js +2 -2
- package/dist/json/index.js.map +1 -1
- package/package.json +9 -5
- package/src/admin/AdminRouter.ts +36 -5
- package/src/admin/components/audits/AdminAudits.tsx +5 -5
- package/src/admin/components/jobs/AdminJobDashboard.tsx +455 -0
- package/src/admin/components/jobs/AdminJobExecutions.tsx +693 -0
- package/src/admin/components/jobs/AdminJobRegistry.tsx +325 -0
- package/src/admin/components/keys/AdminApiKeys.tsx +28 -31
- package/src/admin/components/parameters/AdminParameters.tsx +3 -3
- package/src/admin/components/parameters/ParameterDetails.tsx +34 -29
- package/src/admin/components/parameters/ParameterEmptyState.tsx +5 -5
- package/src/admin/components/parameters/ParameterHistory.tsx +11 -19
- package/src/admin/components/parameters/ParameterTree.tsx +16 -18
- package/src/admin/components/sessions/AdminSessions.tsx +3 -3
- package/src/admin/components/shared/AdminResourceHeader.tsx +20 -16
- package/src/admin/components/users/AdminUserAudits.tsx +5 -5
- package/src/admin/components/users/AdminUserCreate.tsx +3 -3
- package/src/admin/components/users/AdminUserDetails.tsx +51 -53
- package/src/admin/components/users/AdminUserLayout.tsx +7 -7
- package/src/admin/components/users/AdminUserSessions.tsx +3 -3
- package/src/admin/components/users/AdminUserSettings.tsx +9 -9
- package/src/admin/components/users/AdminUsers.tsx +5 -5
- package/src/admin/components/verifications/AdminVerifications.tsx +3 -3
- package/src/admin/index.ts +0 -24
- package/src/auth/components/Login.tsx +13 -13
- package/src/auth/components/Profile.tsx +17 -26
- package/src/auth/components/Register.tsx +21 -31
- package/src/auth/components/ResetPassword.tsx +13 -22
- package/src/auth/components/VerifyEmail.tsx +5 -5
- package/src/auth/components/buttons/UserButton.tsx +14 -4
- package/src/core/components/buttons/ActionButton.tsx +9 -2
- package/src/core/components/data/ErrorViewer.tsx +15 -15
- package/src/core/components/dialogs/AlertDialog.tsx +3 -3
- package/src/core/components/dialogs/ConfirmDialog.tsx +3 -3
- package/src/core/components/dialogs/PromptDialog.tsx +3 -3
- package/src/core/components/form/Control.tsx +9 -0
- package/src/core/components/form/ControlArray.tsx +6 -7
- package/src/core/components/form/ControlObject.tsx +3 -3
- package/src/core/components/form/ControlQueryBuilder.tsx +20 -22
- package/src/core/components/form/ControlSelect.tsx +4 -0
- package/src/core/components/form/TypeForm.tsx +7 -0
- package/src/core/components/layout/Breadcrumb.tsx +6 -6
- package/src/core/components/layout/Omnibar.tsx +2 -1
- package/src/core/components/layout/Sidebar.tsx +5 -1
- package/src/core/components/table/ColumnPicker.tsx +47 -31
- package/src/core/components/table/DataTable.tsx +277 -201
- package/src/core/components/table/DataTableFilters.tsx +8 -0
- package/src/core/components/table/DataTableToolbar.tsx +98 -5
- package/src/core/components/table/FilterPicker.tsx +28 -26
- package/src/core/components/table/types.ts +52 -37
- package/src/core/components/table/useTableSelection.ts +83 -0
- package/src/core/styles.css +1 -0
- package/src/core/utils/parseInput.ts +1 -0
- package/src/demo/components/DemoHome.tsx +5 -5
- package/src/demo/components/core/DemoDataTable.tsx +209 -5
- package/src/demo/components/json/DemoJsonViewer.tsx +1 -1
- package/src/demo/components/shared/MacWindow.tsx +7 -7
- package/src/demo/components/shared/Showcase.tsx +3 -3
- package/src/demo/index.ts +0 -11
- package/src/json/components/JsonViewer.tsx +3 -3
- package/dist/admin/AdminApiKeys-CoTOTfgU.js.map +0 -1
- package/dist/admin/AdminAudits-BmsxFbDa.js.map +0 -1
- package/dist/admin/AdminJobs-C604joTz.js +0 -698
- package/dist/admin/AdminJobs-C604joTz.js.map +0 -1
- package/dist/admin/AdminParameters-B_83Vie9.js.map +0 -1
- package/dist/admin/AdminSessions-CWnPosdd.js.map +0 -1
- package/dist/admin/AdminUserAudits-nHv636E_.js.map +0 -1
- package/dist/admin/AdminUserCreate-CjYD3Kjc.js.map +0 -1
- package/dist/admin/AdminUserDetails-Ccq-LsZ0.js.map +0 -1
- package/dist/admin/AdminUserLayout-7s41DiF_.js.map +0 -1
- package/dist/admin/AdminUserSessions-Ds3ODq_d.js.map +0 -1
- package/dist/admin/AdminUserSettings-CGh4gROo.js.map +0 -1
- package/dist/admin/AdminUsers-CvPiBzQK.js.map +0 -1
- package/dist/admin/rolldown-runtime-CjeV3_4I.js +0 -18
- package/dist/auth/Login-DS_OqA0G.js.map +0 -1
- package/dist/auth/Profile-Di7N7HZL.js.map +0 -1
- package/dist/auth/Register-BRR2_gux.js.map +0 -1
- package/dist/auth/ResetPassword-oQu72lod.js.map +0 -1
- package/dist/auth/VerifyEmail-DC6HPZjd.js.map +0 -1
- package/dist/demo/DemoDataTable-DCsJq8v5.js +0 -149
- package/dist/demo/DemoDataTable-DCsJq8v5.js.map +0 -1
- package/dist/demo/DemoHome-DpRrPlBC.js.map +0 -1
- package/dist/demo/DemoJsonViewer-zeucGKHV.js.map +0 -1
- package/dist/demo/DemoLogin-DSzP0Lkv.js.map +0 -1
- package/dist/demo/DemoRegister-DavFBsCz.js.map +0 -1
- package/dist/demo/DemoResetPassword-BS2rIAQK.js.map +0 -1
- package/dist/demo/DemoVerifyEmail-Bi4SdWz0.js.map +0 -1
- package/dist/demo/Showcase-C9btr_SJ.js.map +0 -1
- package/dist/demo/rolldown-runtime-CjeV3_4I.js +0 -18
- package/src/admin/components/jobs/AdminJobs.tsx +0 -772
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
import { DataTable, Flex, Text, useDialog, useToast } from "@alepha/ui";
|
|
2
|
+
import { Badge } from "@mantine/core";
|
|
3
|
+
import {
|
|
4
|
+
IconCircleCheck,
|
|
5
|
+
IconCircleX,
|
|
6
|
+
IconPlayerPlay,
|
|
7
|
+
} from "@tabler/icons-react";
|
|
8
|
+
import { t } from "alepha";
|
|
9
|
+
import type {
|
|
10
|
+
AdminJobController,
|
|
11
|
+
JobCronInfo,
|
|
12
|
+
JobFailure,
|
|
13
|
+
JobQueueDepth,
|
|
14
|
+
JobRegistration,
|
|
15
|
+
} from "alepha/api/jobs";
|
|
16
|
+
import { useClient } from "alepha/react";
|
|
17
|
+
import { useI18n } from "alepha/react/i18n";
|
|
18
|
+
import { useCallback, useEffect, useState } from "react";
|
|
19
|
+
|
|
20
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
21
|
+
|
|
22
|
+
const getTypeColor = (type: string) => {
|
|
23
|
+
switch (type) {
|
|
24
|
+
case "cron":
|
|
25
|
+
return "violet";
|
|
26
|
+
case "push":
|
|
27
|
+
return "blue";
|
|
28
|
+
case "both":
|
|
29
|
+
return "teal";
|
|
30
|
+
default:
|
|
31
|
+
return "gray";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const registryFilters = t.object({
|
|
36
|
+
type: t.optional(t.enum(["cron", "push", "both"])),
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
40
|
+
|
|
41
|
+
const AdminJobRegistry = () => {
|
|
42
|
+
const client = useClient<AdminJobController>();
|
|
43
|
+
const { l } = useI18n();
|
|
44
|
+
const toast = useToast();
|
|
45
|
+
const dialog = useDialog();
|
|
46
|
+
const [refreshKey, setRefreshKey] = useState(0);
|
|
47
|
+
|
|
48
|
+
// Extra data for enriched panels
|
|
49
|
+
const [cronMap, setCronMap] = useState<Map<string, JobCronInfo>>(new Map());
|
|
50
|
+
const [queueMap, setQueueMap] = useState<Map<string, JobQueueDepth>>(
|
|
51
|
+
new Map(),
|
|
52
|
+
);
|
|
53
|
+
const [failureMap, setFailureMap] = useState<Map<string, JobFailure>>(
|
|
54
|
+
new Map(),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const loadExtraData = useCallback(async () => {
|
|
58
|
+
try {
|
|
59
|
+
const [cronData, queueData, failureData] = await Promise.all([
|
|
60
|
+
client.getCronJobs(),
|
|
61
|
+
client.getQueueDepth(),
|
|
62
|
+
client.getTopFailures(),
|
|
63
|
+
]);
|
|
64
|
+
setCronMap(new Map(cronData.map((c) => [c.name, c])));
|
|
65
|
+
setQueueMap(new Map(queueData.map((q) => [q.jobName, q])));
|
|
66
|
+
setFailureMap(new Map(failureData.map((f) => [f.jobName, f])));
|
|
67
|
+
} catch {
|
|
68
|
+
// non-critical
|
|
69
|
+
}
|
|
70
|
+
}, [client]);
|
|
71
|
+
|
|
72
|
+
useEffect(() => {
|
|
73
|
+
loadExtraData();
|
|
74
|
+
}, [loadExtraData, refreshKey]);
|
|
75
|
+
|
|
76
|
+
const handleTriggerJob = useCallback(
|
|
77
|
+
async (name: string) => {
|
|
78
|
+
const confirmed = await dialog.confirm({
|
|
79
|
+
title: "Trigger Job",
|
|
80
|
+
message: `Are you sure you want to trigger "${name}" manually?`,
|
|
81
|
+
confirmLabel: "Trigger",
|
|
82
|
+
confirmColor: "blue",
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
if (!confirmed) return;
|
|
86
|
+
|
|
87
|
+
return client.triggerJob({ body: { name } }).then(() => {
|
|
88
|
+
toast.success(`Job "${name}" triggered`);
|
|
89
|
+
setRefreshKey((k) => k + 1);
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
[client, dialog, toast],
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<Flex flex={1} direction="column" gap="md">
|
|
97
|
+
<DataTable<JobRegistration, typeof registryFilters>
|
|
98
|
+
key={`registry-${refreshKey}`}
|
|
99
|
+
submitOnInit
|
|
100
|
+
typeFormProps={{
|
|
101
|
+
skipSubmitButton: true,
|
|
102
|
+
columns: 1,
|
|
103
|
+
}}
|
|
104
|
+
tableProps={{
|
|
105
|
+
horizontalSpacing: "sm",
|
|
106
|
+
verticalSpacing: "sm",
|
|
107
|
+
highlightOnHover: true,
|
|
108
|
+
}}
|
|
109
|
+
onFilterChange={(_key, _value, form) => form.submit()}
|
|
110
|
+
filters={registryFilters}
|
|
111
|
+
items={async (filters) => {
|
|
112
|
+
const items = await client.getRegistry();
|
|
113
|
+
const filtered = filters.type
|
|
114
|
+
? items.filter((i) => i.type === filters.type)
|
|
115
|
+
: items;
|
|
116
|
+
return { content: filtered };
|
|
117
|
+
}}
|
|
118
|
+
columns={{
|
|
119
|
+
name: {
|
|
120
|
+
label: "Name",
|
|
121
|
+
value: (item) => (
|
|
122
|
+
<Text size="sm" fw={500} ff="monospace">
|
|
123
|
+
{item.name}
|
|
124
|
+
</Text>
|
|
125
|
+
),
|
|
126
|
+
},
|
|
127
|
+
type: {
|
|
128
|
+
label: "Type",
|
|
129
|
+
fit: true,
|
|
130
|
+
value: (item) => (
|
|
131
|
+
<Badge size="sm" variant="light" color={getTypeColor(item.type)}>
|
|
132
|
+
{item.type}
|
|
133
|
+
</Badge>
|
|
134
|
+
),
|
|
135
|
+
},
|
|
136
|
+
priority: {
|
|
137
|
+
label: "Priority",
|
|
138
|
+
fit: true,
|
|
139
|
+
value: (item) => (
|
|
140
|
+
<Text size="sm" tt="capitalize">
|
|
141
|
+
{item.priority}
|
|
142
|
+
</Text>
|
|
143
|
+
),
|
|
144
|
+
},
|
|
145
|
+
concurrency: {
|
|
146
|
+
label: "Concurrency",
|
|
147
|
+
fit: true,
|
|
148
|
+
value: (item) => (
|
|
149
|
+
<Text size="sm" ff="monospace">
|
|
150
|
+
{item.concurrency}
|
|
151
|
+
</Text>
|
|
152
|
+
),
|
|
153
|
+
},
|
|
154
|
+
queue: {
|
|
155
|
+
label: "Queue",
|
|
156
|
+
fit: true,
|
|
157
|
+
value: (item) => {
|
|
158
|
+
const q = queueMap.get(item.name);
|
|
159
|
+
if (
|
|
160
|
+
!q ||
|
|
161
|
+
q.pending + q.running + q.scheduled + q.retrying + q.dead === 0
|
|
162
|
+
) {
|
|
163
|
+
return (
|
|
164
|
+
<Text size="xs" c="dimmed">
|
|
165
|
+
—
|
|
166
|
+
</Text>
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
return (
|
|
170
|
+
<Flex gap={4}>
|
|
171
|
+
{q.running > 0 && (
|
|
172
|
+
<Badge size="xs" variant="light" color="blue">
|
|
173
|
+
{q.running} run
|
|
174
|
+
</Badge>
|
|
175
|
+
)}
|
|
176
|
+
{q.pending > 0 && (
|
|
177
|
+
<Badge size="xs" variant="light" color="gray">
|
|
178
|
+
{q.pending} pen
|
|
179
|
+
</Badge>
|
|
180
|
+
)}
|
|
181
|
+
{q.retrying > 0 && (
|
|
182
|
+
<Badge size="xs" variant="light" color="yellow">
|
|
183
|
+
{q.retrying} retry
|
|
184
|
+
</Badge>
|
|
185
|
+
)}
|
|
186
|
+
{q.dead > 0 && (
|
|
187
|
+
<Badge size="xs" variant="light" color="red">
|
|
188
|
+
{q.dead} dead
|
|
189
|
+
</Badge>
|
|
190
|
+
)}
|
|
191
|
+
</Flex>
|
|
192
|
+
);
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
actions: {
|
|
196
|
+
label: "",
|
|
197
|
+
fit: true,
|
|
198
|
+
actions: (item) => [
|
|
199
|
+
{
|
|
200
|
+
tooltip: "Trigger",
|
|
201
|
+
color: "blue",
|
|
202
|
+
icon: IconPlayerPlay,
|
|
203
|
+
onClick: () => handleTriggerJob(item.name),
|
|
204
|
+
},
|
|
205
|
+
],
|
|
206
|
+
},
|
|
207
|
+
}}
|
|
208
|
+
panel={(item) => {
|
|
209
|
+
const cron = cronMap.get(item.name);
|
|
210
|
+
const failure = failureMap.get(item.name);
|
|
211
|
+
|
|
212
|
+
return (
|
|
213
|
+
<Flex direction="column" gap="sm" p="sm">
|
|
214
|
+
{/* Config */}
|
|
215
|
+
<Flex gap="lg" wrap="wrap">
|
|
216
|
+
{item.cron && (
|
|
217
|
+
<PanelField label="Cron" value={item.cron} monospace />
|
|
218
|
+
)}
|
|
219
|
+
{item.timeout && (
|
|
220
|
+
<PanelField label="Timeout" value={item.timeout} />
|
|
221
|
+
)}
|
|
222
|
+
{item.retry && (
|
|
223
|
+
<PanelField
|
|
224
|
+
label="Retry"
|
|
225
|
+
value={`${item.retry.retries}x${item.retry.hasBackoff ? " (backoff)" : ""}`}
|
|
226
|
+
/>
|
|
227
|
+
)}
|
|
228
|
+
{item.batch && (
|
|
229
|
+
<PanelField
|
|
230
|
+
label="Batch"
|
|
231
|
+
value={`${item.batch.size} / ${item.batch.window}`}
|
|
232
|
+
/>
|
|
233
|
+
)}
|
|
234
|
+
<PanelField
|
|
235
|
+
label="Schema"
|
|
236
|
+
value={item.hasSchema ? "Yes" : "No"}
|
|
237
|
+
/>
|
|
238
|
+
</Flex>
|
|
239
|
+
|
|
240
|
+
{/* Last cron execution */}
|
|
241
|
+
{cron?.lastExecution && (
|
|
242
|
+
<Flex gap="lg" wrap="wrap" align="center">
|
|
243
|
+
<Text size="xs" c="dimmed" tt="uppercase" fw={600}>
|
|
244
|
+
Last Run
|
|
245
|
+
</Text>
|
|
246
|
+
<Flex align="center" gap={4}>
|
|
247
|
+
{cron.lastExecution.status === "completed" ? (
|
|
248
|
+
<IconCircleCheck
|
|
249
|
+
size={14}
|
|
250
|
+
color="var(--mantine-color-teal-6)"
|
|
251
|
+
/>
|
|
252
|
+
) : (
|
|
253
|
+
<IconCircleX
|
|
254
|
+
size={14}
|
|
255
|
+
color="var(--mantine-color-red-6)"
|
|
256
|
+
/>
|
|
257
|
+
)}
|
|
258
|
+
<Text size="xs" tt="capitalize">
|
|
259
|
+
{cron.lastExecution.status}
|
|
260
|
+
</Text>
|
|
261
|
+
</Flex>
|
|
262
|
+
{cron.lastExecution.startedAt && (
|
|
263
|
+
<Text size="xs" c="dimmed">
|
|
264
|
+
{l(cron.lastExecution.startedAt, { date: "fromNow" })}
|
|
265
|
+
</Text>
|
|
266
|
+
)}
|
|
267
|
+
{cron.lastExecution.error && (
|
|
268
|
+
<Text size="xs" c="red" lineClamp={1}>
|
|
269
|
+
{cron.lastExecution.error}
|
|
270
|
+
</Text>
|
|
271
|
+
)}
|
|
272
|
+
</Flex>
|
|
273
|
+
)}
|
|
274
|
+
|
|
275
|
+
{/* Failures */}
|
|
276
|
+
{failure && (
|
|
277
|
+
<Flex gap="lg" wrap="wrap" align="center">
|
|
278
|
+
<Text size="xs" c="dimmed" tt="uppercase" fw={600}>
|
|
279
|
+
Failures (7d)
|
|
280
|
+
</Text>
|
|
281
|
+
<Badge size="xs" variant="light" color="red">
|
|
282
|
+
{failure.failures}
|
|
283
|
+
</Badge>
|
|
284
|
+
{failure.lastError && (
|
|
285
|
+
<Text
|
|
286
|
+
size="xs"
|
|
287
|
+
c="dimmed"
|
|
288
|
+
lineClamp={1}
|
|
289
|
+
style={{ maxWidth: 400 }}
|
|
290
|
+
>
|
|
291
|
+
{failure.lastError}
|
|
292
|
+
</Text>
|
|
293
|
+
)}
|
|
294
|
+
</Flex>
|
|
295
|
+
)}
|
|
296
|
+
</Flex>
|
|
297
|
+
);
|
|
298
|
+
}}
|
|
299
|
+
/>
|
|
300
|
+
</Flex>
|
|
301
|
+
);
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
305
|
+
|
|
306
|
+
const PanelField = ({
|
|
307
|
+
label,
|
|
308
|
+
value,
|
|
309
|
+
monospace,
|
|
310
|
+
}: {
|
|
311
|
+
label: string;
|
|
312
|
+
value: string;
|
|
313
|
+
monospace?: boolean;
|
|
314
|
+
}) => (
|
|
315
|
+
<Flex direction="column" gap={2}>
|
|
316
|
+
<Text size="xs" c="dimmed" tt="uppercase" fw={600}>
|
|
317
|
+
{label}
|
|
318
|
+
</Text>
|
|
319
|
+
<Text size="sm" ff={monospace ? "monospace" : undefined}>
|
|
320
|
+
{value}
|
|
321
|
+
</Text>
|
|
322
|
+
</Flex>
|
|
323
|
+
);
|
|
324
|
+
|
|
325
|
+
export default AdminJobRegistry;
|
|
@@ -10,13 +10,10 @@ import {
|
|
|
10
10
|
import {
|
|
11
11
|
ActionIcon,
|
|
12
12
|
Badge,
|
|
13
|
-
Box,
|
|
14
13
|
Code,
|
|
15
|
-
Group,
|
|
16
14
|
Paper,
|
|
17
15
|
RingProgress,
|
|
18
16
|
SimpleGrid,
|
|
19
|
-
Stack,
|
|
20
17
|
ThemeIcon,
|
|
21
18
|
Tooltip,
|
|
22
19
|
} from "@mantine/core";
|
|
@@ -121,50 +118,50 @@ const StatsCards = ({ stats, loading }: StatsCardsProps) => {
|
|
|
121
118
|
return (
|
|
122
119
|
<SimpleGrid cols={{ base: 2, sm: 4 }} spacing="md">
|
|
123
120
|
<Paper p="md" radius="md" withBorder>
|
|
124
|
-
<
|
|
125
|
-
<
|
|
121
|
+
<Flex justify="space-between">
|
|
122
|
+
<Flex>
|
|
126
123
|
<Text size="xs" c="dimmed" tt="uppercase" fw={600}>
|
|
127
124
|
Total Keys
|
|
128
125
|
</Text>
|
|
129
126
|
<Text size="xl" fw={700} ff="monospace">
|
|
130
127
|
{stats.total}
|
|
131
128
|
</Text>
|
|
132
|
-
</
|
|
129
|
+
</Flex>
|
|
133
130
|
<ThemeIcon size="lg" radius="md" variant="light" color="blue">
|
|
134
131
|
<IconKey size={20} />
|
|
135
132
|
</ThemeIcon>
|
|
136
|
-
</
|
|
133
|
+
</Flex>
|
|
137
134
|
</Paper>
|
|
138
135
|
|
|
139
136
|
<Paper p="md" radius="md" withBorder>
|
|
140
|
-
<
|
|
141
|
-
<
|
|
137
|
+
<Flex justify="space-between">
|
|
138
|
+
<Flex>
|
|
142
139
|
<Text size="xs" c="dimmed" tt="uppercase" fw={600}>
|
|
143
140
|
Active
|
|
144
141
|
</Text>
|
|
145
142
|
<Text size="xl" fw={700} ff="monospace" c="teal">
|
|
146
143
|
{stats.active}
|
|
147
144
|
</Text>
|
|
148
|
-
</
|
|
145
|
+
</Flex>
|
|
149
146
|
<RingProgress
|
|
150
147
|
size={48}
|
|
151
148
|
thickness={4}
|
|
152
149
|
roundCaps
|
|
153
150
|
sections={[{ value: activePercentage, color: "teal" }]}
|
|
154
151
|
/>
|
|
155
|
-
</
|
|
152
|
+
</Flex>
|
|
156
153
|
</Paper>
|
|
157
154
|
|
|
158
155
|
<Paper p="md" radius="md" withBorder>
|
|
159
|
-
<
|
|
160
|
-
<
|
|
156
|
+
<Flex justify="space-between">
|
|
157
|
+
<Flex>
|
|
161
158
|
<Text size="xs" c="dimmed" tt="uppercase" fw={600}>
|
|
162
159
|
Revoked
|
|
163
160
|
</Text>
|
|
164
161
|
<Text size="xl" fw={700} ff="monospace" c="red">
|
|
165
162
|
{stats.revoked}
|
|
166
163
|
</Text>
|
|
167
|
-
</
|
|
164
|
+
</Flex>
|
|
168
165
|
<ThemeIcon
|
|
169
166
|
size="lg"
|
|
170
167
|
radius="md"
|
|
@@ -173,19 +170,19 @@ const StatsCards = ({ stats, loading }: StatsCardsProps) => {
|
|
|
173
170
|
>
|
|
174
171
|
<IconShieldOff size={20} />
|
|
175
172
|
</ThemeIcon>
|
|
176
|
-
</
|
|
173
|
+
</Flex>
|
|
177
174
|
</Paper>
|
|
178
175
|
|
|
179
176
|
<Paper p="md" radius="md" withBorder>
|
|
180
|
-
<
|
|
181
|
-
<
|
|
177
|
+
<Flex justify="space-between">
|
|
178
|
+
<Flex>
|
|
182
179
|
<Text size="xs" c="dimmed" tt="uppercase" fw={600}>
|
|
183
180
|
Never Used
|
|
184
181
|
</Text>
|
|
185
182
|
<Text size="xl" fw={700} ff="monospace" c="yellow">
|
|
186
183
|
{stats.neverUsed}
|
|
187
184
|
</Text>
|
|
188
|
-
</
|
|
185
|
+
</Flex>
|
|
189
186
|
<ThemeIcon
|
|
190
187
|
size="lg"
|
|
191
188
|
radius="md"
|
|
@@ -194,7 +191,7 @@ const StatsCards = ({ stats, loading }: StatsCardsProps) => {
|
|
|
194
191
|
>
|
|
195
192
|
<IconClock size={20} />
|
|
196
193
|
</ThemeIcon>
|
|
197
|
-
</
|
|
194
|
+
</Flex>
|
|
198
195
|
</Paper>
|
|
199
196
|
</SimpleGrid>
|
|
200
197
|
);
|
|
@@ -338,8 +335,8 @@ const AdminApiKeys = () => {
|
|
|
338
335
|
name: {
|
|
339
336
|
label: "Name",
|
|
340
337
|
value: (item) => (
|
|
341
|
-
<
|
|
342
|
-
<
|
|
338
|
+
<Flex direction="column" gap={2}>
|
|
339
|
+
<Flex gap="xs">
|
|
343
340
|
<ThemeIcon
|
|
344
341
|
size="xs"
|
|
345
342
|
radius="sm"
|
|
@@ -351,20 +348,20 @@ const AdminApiKeys = () => {
|
|
|
351
348
|
<Text size="sm" fw={600}>
|
|
352
349
|
{item.name}
|
|
353
350
|
</Text>
|
|
354
|
-
</
|
|
351
|
+
</Flex>
|
|
355
352
|
{item.description && (
|
|
356
353
|
<Text size="xs" c="dimmed" lineClamp={1}>
|
|
357
354
|
{item.description}
|
|
358
355
|
</Text>
|
|
359
356
|
)}
|
|
360
|
-
</
|
|
357
|
+
</Flex>
|
|
361
358
|
),
|
|
362
359
|
},
|
|
363
360
|
token: {
|
|
364
361
|
label: "Key",
|
|
365
362
|
fit: true,
|
|
366
363
|
value: (item) => (
|
|
367
|
-
<
|
|
364
|
+
<Flex gap={4}>
|
|
368
365
|
<Code
|
|
369
366
|
ff="monospace"
|
|
370
367
|
style={{
|
|
@@ -379,7 +376,7 @@ const AdminApiKeys = () => {
|
|
|
379
376
|
variant="subtle"
|
|
380
377
|
value={formatKeyPreview(item.tokenPrefix, item.tokenSuffix)}
|
|
381
378
|
/>
|
|
382
|
-
</
|
|
379
|
+
</Flex>
|
|
383
380
|
),
|
|
384
381
|
},
|
|
385
382
|
status: {
|
|
@@ -402,7 +399,7 @@ const AdminApiKeys = () => {
|
|
|
402
399
|
roles: {
|
|
403
400
|
label: "Roles",
|
|
404
401
|
value: (item) => (
|
|
405
|
-
<
|
|
402
|
+
<Flex gap={4} wrap="wrap">
|
|
406
403
|
{item.roles.length > 0 ? (
|
|
407
404
|
item.roles.slice(0, 3).map((role) => (
|
|
408
405
|
<Badge key={role} size="xs" variant="outline" color="gray">
|
|
@@ -421,19 +418,19 @@ const AdminApiKeys = () => {
|
|
|
421
418
|
</Badge>
|
|
422
419
|
</Tooltip>
|
|
423
420
|
)}
|
|
424
|
-
</
|
|
421
|
+
</Flex>
|
|
425
422
|
),
|
|
426
423
|
},
|
|
427
424
|
usage: {
|
|
428
425
|
label: "Usage",
|
|
429
426
|
fit: true,
|
|
430
427
|
value: (item) => (
|
|
431
|
-
<
|
|
428
|
+
<Flex direction="column" gap={2}>
|
|
432
429
|
<Text size="xs" ff="monospace" fw={500}>
|
|
433
430
|
{item.usageCount.toLocaleString()} calls
|
|
434
431
|
</Text>
|
|
435
432
|
{item.lastUsedAt ? (
|
|
436
|
-
<
|
|
433
|
+
<Flex gap={4}>
|
|
437
434
|
<Text size="xs" c="dimmed">
|
|
438
435
|
{l(item.lastUsedAt, { date: "fromNow" })}
|
|
439
436
|
</Text>
|
|
@@ -445,13 +442,13 @@ const AdminApiKeys = () => {
|
|
|
445
442
|
/>
|
|
446
443
|
</Tooltip>
|
|
447
444
|
)}
|
|
448
|
-
</
|
|
445
|
+
</Flex>
|
|
449
446
|
) : (
|
|
450
447
|
<Text size="xs" c="yellow">
|
|
451
448
|
Never used
|
|
452
449
|
</Text>
|
|
453
450
|
)}
|
|
454
|
-
</
|
|
451
|
+
</Flex>
|
|
455
452
|
),
|
|
456
453
|
},
|
|
457
454
|
userId: {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Text, useToast } from "@alepha/ui";
|
|
2
|
-
import { Card, Flex
|
|
2
|
+
import { Card, Flex } from "@mantine/core";
|
|
3
3
|
import { IconSettings } from "@tabler/icons-react";
|
|
4
4
|
import type {
|
|
5
5
|
AdminParameterController,
|
|
@@ -153,7 +153,7 @@ const AdminParameters = ({
|
|
|
153
153
|
if (treeData.length === 0) {
|
|
154
154
|
return (
|
|
155
155
|
<Flex flex={1} justify="center" align="center">
|
|
156
|
-
<
|
|
156
|
+
<Flex direction="column" align="center" gap="xs">
|
|
157
157
|
<IconSettings
|
|
158
158
|
size={48}
|
|
159
159
|
stroke={1.5}
|
|
@@ -164,7 +164,7 @@ const AdminParameters = ({
|
|
|
164
164
|
Define parameters using the $parameter primitive to manage dynamic
|
|
165
165
|
application settings. Parameters will appear here once created.
|
|
166
166
|
</Text>
|
|
167
|
-
</
|
|
167
|
+
</Flex>
|
|
168
168
|
</Flex>
|
|
169
169
|
);
|
|
170
170
|
}
|