@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
|
@@ -1,18 +1,16 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-CjeV3_4I.js";
|
|
2
1
|
import { ActionButton, ClipboardButton, Control } from "@alepha/ui";
|
|
3
2
|
import { t } from "alepha";
|
|
4
3
|
import { IconActivity, IconCalendar, IconCheck, IconDevices, IconKey, IconShieldCheck, IconUser, IconX } from "@tabler/icons-react";
|
|
5
4
|
import { useRouterState } from "alepha/react/router";
|
|
6
|
-
import { Badge,
|
|
5
|
+
import { Badge, Card, Center, Divider, Flex as Flex$1, Grid, Loader, Paper, SimpleGrid, Text as Text$1, ThemeIcon } from "@mantine/core";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { useClient } from "alepha/react";
|
|
8
8
|
import { useI18n } from "alepha/react/i18n";
|
|
9
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
9
|
import { useEffect, useState } from "react";
|
|
11
10
|
import { useForm } from "alepha/react/form";
|
|
12
11
|
|
|
13
12
|
//#region ../../src/admin/components/users/AdminUserDetails.tsx
|
|
14
|
-
|
|
15
|
-
const DataRow = ({ label, value, copyValue }) => /* @__PURE__ */ jsxs(Group, {
|
|
13
|
+
const DataRow = ({ label, value, copyValue }) => /* @__PURE__ */ jsxs(Flex$1, {
|
|
16
14
|
justify: "space-between",
|
|
17
15
|
py: 8,
|
|
18
16
|
wrap: "nowrap",
|
|
@@ -22,7 +20,7 @@ const DataRow = ({ label, value, copyValue }) => /* @__PURE__ */ jsxs(Group, {
|
|
|
22
20
|
c: "dimmed",
|
|
23
21
|
style: { flexShrink: 0 },
|
|
24
22
|
children: label
|
|
25
|
-
}), /* @__PURE__ */ jsxs(
|
|
23
|
+
}), /* @__PURE__ */ jsxs(Flex$1, {
|
|
26
24
|
gap: 6,
|
|
27
25
|
wrap: "nowrap",
|
|
28
26
|
style: { minWidth: 0 },
|
|
@@ -44,7 +42,7 @@ const StatCard = ({ icon, label, value, color }) => /* @__PURE__ */ jsx(Paper, {
|
|
|
44
42
|
p: "md",
|
|
45
43
|
radius: "md",
|
|
46
44
|
withBorder: true,
|
|
47
|
-
children: /* @__PURE__ */ jsxs(
|
|
45
|
+
children: /* @__PURE__ */ jsxs(Flex$1, {
|
|
48
46
|
gap: "sm",
|
|
49
47
|
children: [/* @__PURE__ */ jsx(ThemeIcon, {
|
|
50
48
|
size: "lg",
|
|
@@ -52,7 +50,7 @@ const StatCard = ({ icon, label, value, color }) => /* @__PURE__ */ jsx(Paper, {
|
|
|
52
50
|
variant: "light",
|
|
53
51
|
color,
|
|
54
52
|
children: icon
|
|
55
|
-
}), /* @__PURE__ */ jsxs(
|
|
53
|
+
}), /* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(Text$1, {
|
|
56
54
|
size: "xl",
|
|
57
55
|
fw: 700,
|
|
58
56
|
lh: 1,
|
|
@@ -121,7 +119,8 @@ const AdminUserDetails = (props) => {
|
|
|
121
119
|
if (!user) return /* @__PURE__ */ jsx(Center, {
|
|
122
120
|
flex: 1,
|
|
123
121
|
py: "xl",
|
|
124
|
-
children: /* @__PURE__ */ jsxs(
|
|
122
|
+
children: /* @__PURE__ */ jsxs(Flex$1, {
|
|
123
|
+
direction: "column",
|
|
125
124
|
align: "center",
|
|
126
125
|
gap: "xs",
|
|
127
126
|
children: [/* @__PURE__ */ jsx(IconUser, {
|
|
@@ -134,7 +133,8 @@ const AdminUserDetails = (props) => {
|
|
|
134
133
|
})
|
|
135
134
|
});
|
|
136
135
|
const displayName = user.firstName && user.lastName ? `${user.firstName} ${user.lastName}` : user.firstName || user.lastName || null;
|
|
137
|
-
return /* @__PURE__ */ jsxs(
|
|
136
|
+
return /* @__PURE__ */ jsxs(Flex$1, {
|
|
137
|
+
direction: "column",
|
|
138
138
|
gap: "md",
|
|
139
139
|
children: [
|
|
140
140
|
/* @__PURE__ */ jsxs(SimpleGrid, {
|
|
@@ -179,7 +179,7 @@ const AdminUserDetails = (props) => {
|
|
|
179
179
|
radius: "md",
|
|
180
180
|
withBorder: true,
|
|
181
181
|
h: "100%",
|
|
182
|
-
children: [/* @__PURE__ */ jsx(
|
|
182
|
+
children: [/* @__PURE__ */ jsx(Flex$1, {
|
|
183
183
|
justify: "space-between",
|
|
184
184
|
p: "md",
|
|
185
185
|
pb: 0,
|
|
@@ -188,7 +188,7 @@ const AdminUserDetails = (props) => {
|
|
|
188
188
|
size: "sm",
|
|
189
189
|
children: "Account Details"
|
|
190
190
|
})
|
|
191
|
-
}), /* @__PURE__ */ jsxs(
|
|
191
|
+
}), /* @__PURE__ */ jsxs(Flex$1, {
|
|
192
192
|
px: "md",
|
|
193
193
|
pb: "md",
|
|
194
194
|
children: [
|
|
@@ -204,7 +204,7 @@ const AdminUserDetails = (props) => {
|
|
|
204
204
|
}),
|
|
205
205
|
/* @__PURE__ */ jsx(DataRow, {
|
|
206
206
|
label: "Email",
|
|
207
|
-
value: /* @__PURE__ */ jsxs(
|
|
207
|
+
value: /* @__PURE__ */ jsxs(Flex$1, {
|
|
208
208
|
gap: 6,
|
|
209
209
|
children: [/* @__PURE__ */ jsx(Text$1, {
|
|
210
210
|
size: "sm",
|
|
@@ -230,7 +230,7 @@ const AdminUserDetails = (props) => {
|
|
|
230
230
|
}),
|
|
231
231
|
/* @__PURE__ */ jsx(DataRow, {
|
|
232
232
|
label: "Status",
|
|
233
|
-
value: /* @__PURE__ */ jsxs(
|
|
233
|
+
value: /* @__PURE__ */ jsxs(Flex$1, {
|
|
234
234
|
gap: 4,
|
|
235
235
|
children: [/* @__PURE__ */ jsx(ThemeIcon, {
|
|
236
236
|
size: 16,
|
|
@@ -258,7 +258,7 @@ const AdminUserDetails = (props) => {
|
|
|
258
258
|
radius: "md",
|
|
259
259
|
withBorder: true,
|
|
260
260
|
h: "100%",
|
|
261
|
-
children: [/* @__PURE__ */ jsxs(
|
|
261
|
+
children: [/* @__PURE__ */ jsxs(Flex$1, {
|
|
262
262
|
justify: "space-between",
|
|
263
263
|
p: "md",
|
|
264
264
|
pb: 0,
|
|
@@ -272,11 +272,12 @@ const AdminUserDetails = (props) => {
|
|
|
272
272
|
onClick: () => setEditing(true),
|
|
273
273
|
children: "Edit"
|
|
274
274
|
})]
|
|
275
|
-
}), editing ? /* @__PURE__ */ jsx(
|
|
275
|
+
}), editing ? /* @__PURE__ */ jsx(Flex$1, {
|
|
276
276
|
p: "md",
|
|
277
277
|
children: /* @__PURE__ */ jsx("form", {
|
|
278
278
|
...form.props,
|
|
279
|
-
children: /* @__PURE__ */ jsxs(
|
|
279
|
+
children: /* @__PURE__ */ jsxs(Flex$1, {
|
|
280
|
+
direction: "column",
|
|
280
281
|
gap: "sm",
|
|
281
282
|
children: [
|
|
282
283
|
/* @__PURE__ */ jsxs(SimpleGrid, {
|
|
@@ -304,7 +305,7 @@ const AdminUserDetails = (props) => {
|
|
|
304
305
|
input: form.input.roles
|
|
305
306
|
}),
|
|
306
307
|
/* @__PURE__ */ jsx(Divider, {}),
|
|
307
|
-
/* @__PURE__ */ jsxs(
|
|
308
|
+
/* @__PURE__ */ jsxs(Flex$1, {
|
|
308
309
|
justify: "flex-end",
|
|
309
310
|
gap: "xs",
|
|
310
311
|
children: [/* @__PURE__ */ jsx(ActionButton, {
|
|
@@ -321,7 +322,7 @@ const AdminUserDetails = (props) => {
|
|
|
321
322
|
]
|
|
322
323
|
})
|
|
323
324
|
})
|
|
324
|
-
}) : /* @__PURE__ */ jsxs(
|
|
325
|
+
}) : /* @__PURE__ */ jsxs(Flex$1, {
|
|
325
326
|
px: "md",
|
|
326
327
|
pb: "md",
|
|
327
328
|
children: [
|
|
@@ -339,7 +340,7 @@ const AdminUserDetails = (props) => {
|
|
|
339
340
|
}),
|
|
340
341
|
/* @__PURE__ */ jsx(DataRow, {
|
|
341
342
|
label: "Roles",
|
|
342
|
-
value: user.roles.length > 0 ? /* @__PURE__ */ jsx(
|
|
343
|
+
value: user.roles.length > 0 ? /* @__PURE__ */ jsx(Flex$1, {
|
|
343
344
|
gap: 4,
|
|
344
345
|
children: user.roles.map((role) => /* @__PURE__ */ jsx(Badge, {
|
|
345
346
|
size: "xs",
|
|
@@ -360,7 +361,7 @@ const AdminUserDetails = (props) => {
|
|
|
360
361
|
padding: 0,
|
|
361
362
|
radius: "md",
|
|
362
363
|
withBorder: true,
|
|
363
|
-
children: [/* @__PURE__ */ jsx(
|
|
364
|
+
children: [/* @__PURE__ */ jsx(Flex$1, {
|
|
364
365
|
justify: "space-between",
|
|
365
366
|
p: "md",
|
|
366
367
|
pb: 0,
|
|
@@ -376,8 +377,8 @@ const AdminUserDetails = (props) => {
|
|
|
376
377
|
},
|
|
377
378
|
p: "md",
|
|
378
379
|
children: [
|
|
379
|
-
/* @__PURE__ */ jsxs(
|
|
380
|
-
/* @__PURE__ */ jsxs(
|
|
380
|
+
/* @__PURE__ */ jsxs(Flex$1, { children: [
|
|
381
|
+
/* @__PURE__ */ jsxs(Flex$1, {
|
|
381
382
|
gap: 6,
|
|
382
383
|
mb: 4,
|
|
383
384
|
children: [/* @__PURE__ */ jsx(IconCalendar, {
|
|
@@ -400,8 +401,8 @@ const AdminUserDetails = (props) => {
|
|
|
400
401
|
children: l(user.createdAt, { date: "fromNow" })
|
|
401
402
|
})
|
|
402
403
|
] }),
|
|
403
|
-
/* @__PURE__ */ jsxs(
|
|
404
|
-
/* @__PURE__ */ jsxs(
|
|
404
|
+
/* @__PURE__ */ jsxs(Flex$1, { children: [
|
|
405
|
+
/* @__PURE__ */ jsxs(Flex$1, {
|
|
405
406
|
gap: 6,
|
|
406
407
|
mb: 4,
|
|
407
408
|
children: [/* @__PURE__ */ jsx(IconCalendar, {
|
|
@@ -424,7 +425,7 @@ const AdminUserDetails = (props) => {
|
|
|
424
425
|
children: l(user.updatedAt, { date: "fromNow" })
|
|
425
426
|
})
|
|
426
427
|
] }),
|
|
427
|
-
/* @__PURE__ */ jsxs(
|
|
428
|
+
/* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsxs(Flex$1, {
|
|
428
429
|
gap: 6,
|
|
429
430
|
mb: 4,
|
|
430
431
|
children: [/* @__PURE__ */ jsx(IconDevices, {
|
|
@@ -440,7 +441,7 @@ const AdminUserDetails = (props) => {
|
|
|
440
441
|
c: "dimmed",
|
|
441
442
|
children: "—"
|
|
442
443
|
})] }),
|
|
443
|
-
/* @__PURE__ */ jsxs(
|
|
444
|
+
/* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsxs(Flex$1, {
|
|
444
445
|
gap: 6,
|
|
445
446
|
mb: 4,
|
|
446
447
|
children: [/* @__PURE__ */ jsx(IconCheck, {
|
|
@@ -472,5 +473,5 @@ const AdminUserDetails = (props) => {
|
|
|
472
473
|
};
|
|
473
474
|
|
|
474
475
|
//#endregion
|
|
475
|
-
export {
|
|
476
|
-
//# sourceMappingURL=AdminUserDetails-
|
|
476
|
+
export { AdminUserDetails as default };
|
|
477
|
+
//# sourceMappingURL=AdminUserDetails-DDe1A1GP.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUserDetails-DDe1A1GP.js","names":["Flex","Text"],"sources":["../../src/admin/components/users/AdminUserDetails.tsx"],"sourcesContent":["import { ActionButton, ClipboardButton, Control } from \"@alepha/ui\";\nimport {\n Badge,\n Card,\n Center,\n Divider,\n Flex,\n Grid,\n Loader,\n Paper,\n SimpleGrid,\n Text,\n ThemeIcon,\n} from \"@mantine/core\";\nimport {\n IconActivity,\n IconCalendar,\n IconCheck,\n IconDevices,\n IconKey,\n IconShieldCheck,\n IconUser,\n IconX,\n} from \"@tabler/icons-react\";\nimport { t } from \"alepha\";\nimport type { AdminUserController, UserEntity } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useForm } from \"alepha/react/form\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouterState } from \"alepha/react/router\";\nimport { type ReactNode, useEffect, useState } from \"react\";\n\nexport interface AdminUserDetailsProps {\n userRealmName?: string;\n}\n\ninterface DataRowProps {\n label: string;\n value: ReactNode;\n copyValue?: string;\n}\n\nconst DataRow = ({ label, value, copyValue }: DataRowProps) => (\n <Flex\n justify=\"space-between\"\n py={8}\n wrap=\"nowrap\"\n style={{ borderBottom: \"1px solid var(--mantine-color-default-border)\" }}\n >\n <Text size=\"sm\" c=\"dimmed\" style={{ flexShrink: 0 }}>\n {label}\n </Text>\n <Flex gap={6} wrap=\"nowrap\" style={{ minWidth: 0 }}>\n {typeof value === \"string\" ? (\n <Text size=\"sm\" fw={500} truncate style={{ maxWidth: 220 }}>\n {value || \"—\"}\n </Text>\n ) : (\n value\n )}\n {copyValue && (\n <ClipboardButton\n value={copyValue}\n size=\"xs\"\n variant=\"subtle\"\n c=\"dimmed\"\n />\n )}\n </Flex>\n </Flex>\n);\n\ninterface StatCardProps {\n icon: ReactNode;\n label: string;\n value: string | number;\n color: string;\n}\n\nconst StatCard = ({ icon, label, value, color }: StatCardProps) => (\n <Paper p=\"md\" radius=\"md\" withBorder>\n <Flex gap=\"sm\">\n <ThemeIcon size=\"lg\" radius=\"md\" variant=\"light\" color={color}>\n {icon}\n </ThemeIcon>\n <Flex>\n <Text size=\"xl\" fw={700} lh={1}>\n {value}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {label}\n </Text>\n </Flex>\n </Flex>\n </Paper>\n);\n\nconst AdminUserDetails = (props: AdminUserDetailsProps) => {\n const state = useRouterState();\n const client = useClient<AdminUserController>();\n const { l } = useI18n();\n const userId = state.params.userId as string;\n\n const [user, setUser] = useState<UserEntity | null>(null);\n const [loading, setLoading] = useState(true);\n const [editing, setEditing] = useState(false);\n\n useEffect(() => {\n const loadUser = async () => {\n try {\n const data = await client.getUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n setUser(data);\n } finally {\n setLoading(false);\n }\n };\n\n loadUser();\n }, [userId]);\n\n const form = useForm({\n schema: t.object({\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n firstName: t.optional(t.string()),\n lastName: t.optional(t.string()),\n roles: t.optional(t.array(t.string())),\n enabled: t.optional(t.boolean()),\n }),\n handler: async (data) => {\n const updated = await client.updateUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n body: data,\n });\n setUser(updated);\n setEditing(false);\n },\n });\n\n useEffect(() => {\n if (user) {\n form.input.email?.set(user.email ?? \"\");\n form.input.phoneNumber?.set(user.phoneNumber ?? \"\");\n form.input.firstName?.set(user.firstName ?? \"\");\n form.input.lastName?.set(user.lastName ?? \"\");\n form.input.roles?.set(user.roles ?? []);\n form.input.enabled?.set(user.enabled);\n }\n }, [user]);\n\n if (loading) {\n return (\n <Center flex={1} py=\"xl\">\n <Loader />\n </Center>\n );\n }\n\n if (!user) {\n return (\n <Center flex={1} py=\"xl\">\n <Flex direction=\"column\" align=\"center\" gap=\"xs\">\n <IconUser size={48} opacity={0.3} />\n <Text c=\"dimmed\">User not found</Text>\n </Flex>\n </Center>\n );\n }\n\n const displayName =\n user.firstName && user.lastName\n ? `${user.firstName} ${user.lastName}`\n : user.firstName || user.lastName || null;\n\n return (\n <Flex direction=\"column\" gap=\"md\">\n {/* Stats Overview */}\n <SimpleGrid cols={{ base: 2, sm: 4 }}>\n <StatCard\n icon={<IconDevices size={18} />}\n label=\"Sessions\"\n value={0}\n color=\"blue\"\n />\n <StatCard\n icon={<IconActivity size={18} />}\n label=\"API Calls\"\n value={0}\n color=\"green\"\n />\n <StatCard\n icon={<IconKey size={18} />}\n label=\"Failed Logins\"\n value={0}\n color=\"orange\"\n />\n <StatCard\n icon={<IconShieldCheck size={18} />}\n label=\"Roles\"\n value={user.roles.length}\n color=\"violet\"\n />\n </SimpleGrid>\n\n <Grid>\n {/* Left Column - Account Details */}\n <Grid.Col span={{ base: 12, md: 6 }}>\n <Card padding={0} radius=\"md\" withBorder h=\"100%\">\n <Flex justify=\"space-between\" p=\"md\" pb={0}>\n <Text fw={600} size=\"sm\">\n Account Details\n </Text>\n </Flex>\n <Flex px=\"md\" pb=\"md\">\n <DataRow label=\"User ID\" value={user.id} copyValue={user.id} />\n <DataRow\n label=\"Username\"\n value={user.username || \"—\"}\n copyValue={user.username}\n />\n <DataRow\n label=\"Email\"\n value={\n <Flex gap={6}>\n <Text size=\"sm\" fw={500}>\n {user.email || \"—\"}\n </Text>\n {user.email && (\n <Badge\n size=\"xs\"\n variant=\"light\"\n color={user.emailVerified ? \"green\" : \"orange\"}\n >\n {user.emailVerified ? \"verified\" : \"unverified\"}\n </Badge>\n )}\n </Flex>\n }\n copyValue={user.email}\n />\n <DataRow\n label=\"Phone\"\n value={user.phoneNumber || \"—\"}\n copyValue={user.phoneNumber}\n />\n <DataRow label=\"Realm\" value={user.realm} />\n <DataRow\n label=\"Status\"\n value={\n <Flex gap={4}>\n <ThemeIcon\n size={16}\n radius=\"xl\"\n color={user.enabled ? \"green\" : \"red\"}\n variant=\"filled\"\n >\n {user.enabled ? (\n <IconCheck size={10} />\n ) : (\n <IconX size={10} />\n )}\n </ThemeIcon>\n <Text size=\"sm\" fw={500}>\n {user.enabled ? \"Active\" : \"Disabled\"}\n </Text>\n </Flex>\n }\n />\n </Flex>\n </Card>\n </Grid.Col>\n\n {/* Right Column - Personal Info */}\n <Grid.Col span={{ base: 12, md: 6 }}>\n <Card padding={0} radius=\"md\" withBorder h=\"100%\">\n <Flex justify=\"space-between\" p=\"md\" pb={0}>\n <Text fw={600} size=\"sm\">\n Personal Information\n </Text>\n {!editing && (\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n onClick={() => setEditing(true)}\n >\n Edit\n </ActionButton>\n )}\n </Flex>\n\n {editing ? (\n <Flex p=\"md\">\n <form {...form.props}>\n <Flex direction=\"column\" gap=\"sm\">\n <SimpleGrid cols={2}>\n <Control\n title=\"First Name\"\n input={form.input.firstName}\n />\n <Control title=\"Last Name\" input={form.input.lastName} />\n </SimpleGrid>\n <SimpleGrid cols={2}>\n <Control title=\"Email\" input={form.input.email} />\n <Control title=\"Phone\" input={form.input.phoneNumber} />\n </SimpleGrid>\n <Control title=\"Roles\" input={form.input.roles} />\n <Divider />\n <Flex justify=\"flex-end\" gap=\"xs\">\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n onClick={() => setEditing(false)}\n >\n Cancel\n </ActionButton>\n <ActionButton size=\"xs\" form={form}>\n Save\n </ActionButton>\n </Flex>\n </Flex>\n </form>\n </Flex>\n ) : (\n <Flex px=\"md\" pb=\"md\">\n <DataRow label=\"First Name\" value={user.firstName || \"—\"} />\n <DataRow label=\"Last Name\" value={user.lastName || \"—\"} />\n <DataRow label=\"Display Name\" value={displayName || \"—\"} />\n <DataRow\n label=\"Roles\"\n value={\n user.roles.length > 0 ? (\n <Flex gap={4}>\n {user.roles.map((role) => (\n <Badge key={role} size=\"xs\" variant=\"light\">\n {role}\n </Badge>\n ))}\n </Flex>\n ) : (\n <Text size=\"sm\" c=\"dimmed\">\n No roles\n </Text>\n )\n }\n />\n </Flex>\n )}\n </Card>\n </Grid.Col>\n </Grid>\n\n {/* Timeline */}\n <Card padding={0} radius=\"md\" withBorder>\n <Flex justify=\"space-between\" p=\"md\" pb={0}>\n <Text fw={600} size=\"sm\">\n Activity Timeline\n </Text>\n </Flex>\n <SimpleGrid cols={{ base: 2, sm: 4 }} p=\"md\">\n <Flex>\n <Flex gap={6} mb={4}>\n <IconCalendar size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Created\n </Text>\n </Flex>\n <Text size=\"sm\" fw={500}>\n {l(user.createdAt, { date: \"ll\" })}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {l(user.createdAt, { date: \"fromNow\" })}\n </Text>\n </Flex>\n <Flex>\n <Flex gap={6} mb={4}>\n <IconCalendar size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Updated\n </Text>\n </Flex>\n <Text size=\"sm\" fw={500}>\n {l(user.updatedAt, { date: \"ll\" })}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {l(user.updatedAt, { date: \"fromNow\" })}\n </Text>\n </Flex>\n <Flex>\n <Flex gap={6} mb={4}>\n <IconDevices size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Last Login\n </Text>\n </Flex>\n <Text size=\"sm\" c=\"dimmed\">\n —\n </Text>\n </Flex>\n <Flex>\n <Flex gap={6} mb={4}>\n <IconCheck size={14} style={{ opacity: 0.5 }} />\n <Text size=\"xs\" c=\"dimmed\">\n Email Verified\n </Text>\n </Flex>\n {user.emailVerified ? (\n <>\n <Text size=\"sm\" fw={500}>\n {l(user.updatedAt, { date: \"ll\" })}\n </Text>\n <Text size=\"xs\" c=\"dimmed\">\n {l(user.updatedAt, { date: \"fromNow\" })}\n </Text>\n </>\n ) : (\n <Text size=\"sm\" c=\"dimmed\">\n Not verified\n </Text>\n )}\n </Flex>\n </SimpleGrid>\n </Card>\n </Flex>\n );\n};\n\nexport default AdminUserDetails;\n"],"mappings":"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"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-CjeV3_4I.js";
|
|
2
1
|
import { ActionButton } from "@alepha/ui";
|
|
3
2
|
import { IconBan, IconChevronDown, IconChevronLeft, IconDevices, IconExternalLink, IconHistory, IconLock, IconMail, IconPencil, IconSettings, IconShieldCheck, IconTrash, IconUser } from "@tabler/icons-react";
|
|
4
3
|
import { NestedView, useActive, useRouter, useRouterState } from "alepha/react/router";
|
|
5
|
-
import { ActionIcon, Avatar, Badge,
|
|
6
|
-
import { useClient } from "alepha/react";
|
|
4
|
+
import { ActionIcon, Avatar, Badge, Button, Center, Flex as Flex$1, Loader, Menu, Tabs, Text as Text$1, Tooltip } from "@mantine/core";
|
|
7
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { useClient } from "alepha/react";
|
|
8
7
|
import { useEffect, useState } from "react";
|
|
9
8
|
|
|
10
9
|
//#region ../../src/admin/components/shared/AdminResourceHeader.tsx
|
|
@@ -47,27 +46,29 @@ const AdminResourceHeader = (props) => {
|
|
|
47
46
|
children: title.charAt(0).toUpperCase()
|
|
48
47
|
});
|
|
49
48
|
};
|
|
50
|
-
return /* @__PURE__ */ jsxs(
|
|
49
|
+
return /* @__PURE__ */ jsxs(Flex$1, {
|
|
50
|
+
direction: "column",
|
|
51
51
|
gap: "xs",
|
|
52
|
-
children: [backHref && /* @__PURE__ */ jsx(
|
|
52
|
+
children: [backHref && /* @__PURE__ */ jsx(Flex$1, { children: /* @__PURE__ */ jsx(ActionButton, {
|
|
53
53
|
variant: "subtle",
|
|
54
54
|
size: "xs",
|
|
55
55
|
href: backHref,
|
|
56
56
|
leftSection: /* @__PURE__ */ jsx(IconChevronLeft, { size: 14 }),
|
|
57
57
|
c: "dimmed",
|
|
58
58
|
children: backLabel
|
|
59
|
-
}) }), /* @__PURE__ */ jsxs(
|
|
59
|
+
}) }), /* @__PURE__ */ jsxs(Flex$1, {
|
|
60
60
|
justify: "space-between",
|
|
61
61
|
align: "flex-start",
|
|
62
62
|
wrap: "nowrap",
|
|
63
|
-
children: [/* @__PURE__ */ jsxs(
|
|
63
|
+
children: [/* @__PURE__ */ jsxs(Flex$1, {
|
|
64
64
|
gap: "md",
|
|
65
65
|
wrap: "nowrap",
|
|
66
|
-
children: [renderAvatar(), /* @__PURE__ */ jsxs(
|
|
66
|
+
children: [renderAvatar(), /* @__PURE__ */ jsxs(Flex$1, {
|
|
67
|
+
direction: "column",
|
|
67
68
|
gap: 2,
|
|
68
69
|
justify: "center",
|
|
69
70
|
style: { minHeight: 56 },
|
|
70
|
-
children: [/* @__PURE__ */ jsxs(
|
|
71
|
+
children: [/* @__PURE__ */ jsxs(Flex$1, {
|
|
71
72
|
gap: "xs",
|
|
72
73
|
align: "center",
|
|
73
74
|
children: [/* @__PURE__ */ jsx(Text$1, {
|
|
@@ -88,7 +89,7 @@ const AdminResourceHeader = (props) => {
|
|
|
88
89
|
children: subtitle
|
|
89
90
|
})]
|
|
90
91
|
})]
|
|
91
|
-
}), /* @__PURE__ */ jsxs(
|
|
92
|
+
}), /* @__PURE__ */ jsxs(Flex$1, {
|
|
92
93
|
gap: "xs",
|
|
93
94
|
children: [
|
|
94
95
|
externalUrl && /* @__PURE__ */ jsx(Tooltip, {
|
|
@@ -158,7 +159,6 @@ const AdminResourceTabs = (props) => {
|
|
|
158
159
|
|
|
159
160
|
//#endregion
|
|
160
161
|
//#region ../../src/admin/components/users/AdminUserLayout.tsx
|
|
161
|
-
var AdminUserLayout_exports = /* @__PURE__ */ __exportAll({ default: () => AdminUserLayout });
|
|
162
162
|
const AdminUserLayout = (props) => {
|
|
163
163
|
const router = useRouter();
|
|
164
164
|
const state = useRouterState();
|
|
@@ -186,7 +186,8 @@ const AdminUserLayout = (props) => {
|
|
|
186
186
|
});
|
|
187
187
|
if (!user) return /* @__PURE__ */ jsx(Center, {
|
|
188
188
|
flex: 1,
|
|
189
|
-
children: /* @__PURE__ */ jsxs(
|
|
189
|
+
children: /* @__PURE__ */ jsxs(Flex$1, {
|
|
190
|
+
direction: "column",
|
|
190
191
|
align: "center",
|
|
191
192
|
gap: "xs",
|
|
192
193
|
children: [/* @__PURE__ */ jsx(IconUser, {
|
|
@@ -241,11 +242,12 @@ const AdminUserLayout = (props) => {
|
|
|
241
242
|
setActionLoading(null);
|
|
242
243
|
}
|
|
243
244
|
};
|
|
244
|
-
return /* @__PURE__ */ jsx(
|
|
245
|
+
return /* @__PURE__ */ jsx(Flex$1, {
|
|
245
246
|
py: "xl",
|
|
246
247
|
px: "xl",
|
|
247
248
|
flex: 1,
|
|
248
|
-
children: /* @__PURE__ */ jsxs(
|
|
249
|
+
children: /* @__PURE__ */ jsxs(Flex$1, {
|
|
250
|
+
direction: "column",
|
|
249
251
|
gap: "lg",
|
|
250
252
|
children: [
|
|
251
253
|
/* @__PURE__ */ jsx(AdminResourceHeader, {
|
|
@@ -329,5 +331,5 @@ const AdminUserLayout = (props) => {
|
|
|
329
331
|
};
|
|
330
332
|
|
|
331
333
|
//#endregion
|
|
332
|
-
export {
|
|
333
|
-
//# sourceMappingURL=AdminUserLayout-
|
|
334
|
+
export { AdminUserLayout as default };
|
|
335
|
+
//# sourceMappingURL=AdminUserLayout-HAlobhWf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUserLayout-HAlobhWf.js","names":["Flex","Text","Flex","Text"],"sources":["../../src/admin/components/shared/AdminResourceHeader.tsx","../../src/admin/components/shared/AdminResourceTabs.tsx","../../src/admin/components/users/AdminUserLayout.tsx"],"sourcesContent":["import { ActionButton } from \"@alepha/ui\";\nimport {\n ActionIcon,\n Avatar,\n Badge,\n Button,\n Flex,\n Menu,\n Text,\n Tooltip,\n} from \"@mantine/core\";\nimport {\n IconChevronDown,\n IconChevronLeft,\n IconExternalLink,\n} from \"@tabler/icons-react\";\nimport { useRouter } from \"alepha/react/router\";\nimport type { ComponentType, ReactNode } from \"react\";\n\nexport interface AdminResourceAction {\n label: string;\n icon?: ComponentType<{ size?: number }>;\n onClick?: () => void;\n href?: string;\n color?: string;\n disabled?: boolean;\n loading?: boolean;\n variant?: \"filled\" | \"light\" | \"outline\" | \"subtle\";\n}\n\nexport interface AdminResourceHeaderProps {\n /**\n * Back navigation URL\n */\n backHref?: string;\n\n /**\n * Back navigation label\n */\n backLabel?: string;\n\n /**\n * Avatar content (letter, image URL, or custom node)\n */\n avatar?: string | ReactNode;\n\n /**\n * Avatar color\n */\n avatarColor?: string;\n\n /**\n * Resource title (e.g., user name)\n */\n title: string;\n\n /**\n * Secondary text (e.g., email)\n */\n subtitle?: string;\n\n /**\n * Tertiary identifier to copy (e.g., user ID)\n */\n identifier?: string;\n\n /**\n * Label for the identifier tooltip\n */\n identifierLabel?: string;\n\n /**\n * Status badge\n */\n status?: {\n label: string;\n color: \"green\" | \"red\" | \"yellow\" | \"blue\" | \"gray\";\n };\n\n /**\n * Additional badges (e.g., roles)\n */\n badges?: Array<{\n label: string;\n color?: string;\n variant?: \"filled\" | \"light\" | \"outline\" | \"dot\";\n }>;\n\n /**\n * Primary action button\n */\n primaryAction?: AdminResourceAction;\n\n /**\n * Menu actions (shown in dropdown)\n */\n menuActions?: AdminResourceAction[];\n\n /**\n * External link URL\n */\n externalUrl?: string;\n\n /**\n * Loading state\n */\n loading?: boolean;\n}\n\nconst ActionMenuItem = (props: { action: AdminResourceAction }) => {\n const { action } = props;\n const router = useRouter();\n\n const menuItemProps: Record<string, unknown> = {};\n if (action.href) {\n Object.assign(menuItemProps, router.anchor(action.href));\n } else if (action.onClick) {\n menuItemProps.onClick = action.onClick;\n }\n\n return (\n <Menu.Item\n leftSection={action.icon ? <action.icon size={16} /> : undefined}\n color={action.color}\n disabled={action.disabled}\n {...menuItemProps}\n >\n {action.label}\n </Menu.Item>\n );\n};\n\nconst AdminResourceHeader = (props: AdminResourceHeaderProps) => {\n const {\n backHref,\n backLabel = \"Back\",\n avatar,\n avatarColor = \"blue\",\n title,\n subtitle,\n identifier,\n identifierLabel = \"ID\",\n status,\n badges = [],\n primaryAction,\n menuActions = [],\n externalUrl,\n } = props;\n\n const renderAvatar = () => {\n if (typeof avatar === \"string\") {\n if (avatar.startsWith(\"http\") || avatar.startsWith(\"/\")) {\n return (\n <Avatar src={avatar} size={56} radius=\"md\" color={avatarColor} />\n );\n }\n return (\n <Avatar size={56} radius=\"md\" color={avatarColor}>\n {avatar}\n </Avatar>\n );\n }\n if (avatar) {\n return avatar;\n }\n return (\n <Avatar size={56} radius=\"md\" color={avatarColor}>\n {title.charAt(0).toUpperCase()}\n </Avatar>\n );\n };\n\n return (\n <Flex direction=\"column\" gap=\"xs\">\n {/* Breadcrumb / Back navigation */}\n {backHref && (\n <Flex>\n <ActionButton\n variant=\"subtle\"\n size=\"xs\"\n href={backHref}\n leftSection={<IconChevronLeft size={14} />}\n c=\"dimmed\"\n >\n {backLabel}\n </ActionButton>\n </Flex>\n )}\n\n {/* Main header */}\n <Flex justify=\"space-between\" align=\"flex-start\" wrap=\"nowrap\">\n {/* Left: Avatar + Info */}\n <Flex gap=\"md\" wrap=\"nowrap\">\n {renderAvatar()}\n\n <Flex\n direction=\"column\"\n gap={2}\n justify=\"center\"\n style={{ minHeight: 56 }}\n >\n {/* Title row */}\n <Flex gap=\"xs\" align=\"center\">\n <Text size=\"md\" fw={600} lh={1.2}>\n {title}\n </Text>\n {status && (\n <Badge\n size=\"xs\"\n variant=\"light\"\n color={status.color}\n tt=\"lowercase\"\n >\n {status.label}\n </Badge>\n )}\n </Flex>\n\n {/* Subtitle */}\n {subtitle && (\n <Text size=\"xs\" c=\"dimmed\">\n {subtitle}\n </Text>\n )}\n </Flex>\n </Flex>\n\n {/* Right: Actions */}\n <Flex gap=\"xs\">\n {externalUrl && (\n <Tooltip label=\"Open in new tab\" openDelay={500}>\n <ActionIcon\n variant=\"subtle\"\n color=\"gray\"\n component=\"a\"\n href={externalUrl}\n target=\"_blank\"\n >\n <IconExternalLink size={18} />\n </ActionIcon>\n </Tooltip>\n )}\n\n {primaryAction && (\n <ActionButton\n variant={primaryAction.variant ?? \"light\"}\n color={primaryAction.color}\n onClick={primaryAction.onClick}\n href={primaryAction.href}\n loading={primaryAction.loading}\n disabled={primaryAction.disabled}\n leftSection={\n primaryAction.icon ? (\n <primaryAction.icon size={16} />\n ) : undefined\n }\n >\n {primaryAction.label}\n </ActionButton>\n )}\n\n {menuActions.length > 0 && (\n <Menu position=\"bottom-end\" shadow=\"md\" width={220}>\n <Menu.Target>\n <Button\n variant=\"default\"\n rightSection={<IconChevronDown size={16} />}\n >\n Actions\n </Button>\n </Menu.Target>\n <Menu.Dropdown>\n {menuActions.map((action, index) => (\n <ActionMenuItem key={index} action={action} />\n ))}\n </Menu.Dropdown>\n </Menu>\n )}\n </Flex>\n </Flex>\n </Flex>\n );\n};\n\nexport default AdminResourceHeader;\n","import { Tabs } from \"@mantine/core\";\nimport { useActive, useRouter } from \"alepha/react/router\";\nimport type { ComponentType, ReactNode } from \"react\";\n\nexport interface AdminResourceTab {\n /**\n * Tab key/value\n */\n value: string;\n\n /**\n * Tab label\n */\n label: string;\n\n /**\n * Tab icon\n */\n icon?: ComponentType<{ size?: number }>;\n\n /**\n * Navigation href\n */\n href: string;\n\n /**\n * Whether tab is disabled\n */\n disabled?: boolean;\n\n /**\n * Badge count to show\n */\n count?: number;\n}\n\nexport interface AdminResourceTabsProps {\n /**\n * Array of tab configurations\n */\n tabs: AdminResourceTab[];\n\n /**\n * Currently active tab value\n */\n activeTab?: string;\n\n /**\n * Content to render below tabs\n */\n children?: ReactNode;\n}\n\nconst TabItem = (props: { tab: AdminResourceTab }) => {\n const { tab } = props;\n const router = useRouter();\n const { isActive, isPending } = useActive({ href: tab.href });\n const anchorProps = router.anchor(tab.href);\n\n return (\n <Tabs.Tab\n value={tab.value}\n component=\"a\"\n leftSection={tab.icon ? <tab.icon size={16} /> : undefined}\n disabled={tab.disabled}\n data-active={isActive || undefined}\n style={{\n opacity: isPending ? 0.6 : 1,\n }}\n {...anchorProps}\n >\n {tab.label}\n {tab.count !== undefined && tab.count > 0 && ` (${tab.count})`}\n </Tabs.Tab>\n );\n};\n\nconst AdminResourceTabs = (props: AdminResourceTabsProps) => {\n const { tabs, activeTab, children } = props;\n\n return (\n <Tabs value={activeTab} variant=\"default\">\n <Tabs.List>\n {tabs.map((tab) => (\n <TabItem key={tab.value} tab={tab} />\n ))}\n </Tabs.List>\n\n {children}\n </Tabs>\n );\n};\n\nexport default AdminResourceTabs;\n","import { Center, Flex, Loader, Text } from \"@mantine/core\";\nimport {\n IconBan,\n IconDevices,\n IconHistory,\n IconLock,\n IconMail,\n IconPencil,\n IconSettings,\n IconShieldCheck,\n IconTrash,\n IconUser,\n} from \"@tabler/icons-react\";\nimport type { AdminUserController, UserEntity } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { NestedView, useRouter, useRouterState } from \"alepha/react/router\";\nimport { useEffect, useState } from \"react\";\nimport type { AdminRouter } from \"../../AdminRouter.ts\";\nimport AdminResourceHeader from \"../shared/AdminResourceHeader.tsx\";\nimport AdminResourceTabs from \"../shared/AdminResourceTabs.tsx\";\n\nexport interface AdminUserLayoutProps {\n userRealmName?: string;\n}\n\nconst AdminUserLayout = (props: AdminUserLayoutProps) => {\n const router = useRouter<AdminRouter>();\n const state = useRouterState();\n const client = useClient<AdminUserController>();\n const userId = state.params.userId as string;\n\n const [user, setUser] = useState<UserEntity | null>(null);\n const [loading, setLoading] = useState(true);\n const [actionLoading, setActionLoading] = useState<string | null>(null);\n\n useEffect(() => {\n const loadUser = async () => {\n try {\n const data = await client.getUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n setUser(data);\n } finally {\n setLoading(false);\n }\n };\n\n loadUser();\n }, [userId]);\n\n if (loading) {\n return (\n <Center flex={1}>\n <Loader />\n </Center>\n );\n }\n\n if (!user) {\n return (\n <Center flex={1}>\n <Flex direction=\"column\" align=\"center\" gap=\"xs\">\n <IconUser size={48} opacity={0.3} />\n <Text c=\"dimmed\">User not found</Text>\n </Flex>\n </Center>\n );\n }\n\n const displayName =\n user.firstName || user.lastName\n ? `${user.firstName ?? \"\"} ${user.lastName ?? \"\"}`.trim()\n : user.username || user.email || \"User\";\n\n const currentPath = state.url.pathname;\n const getActiveTab = () => {\n if (currentPath.endsWith(\"/sessions\")) return \"sessions\";\n if (currentPath.endsWith(\"/settings\")) return \"settings\";\n if (currentPath.endsWith(\"/audits\")) return \"audits\";\n return \"profile\";\n };\n\n const handleBlockUser = async () => {\n setActionLoading(\"block\");\n try {\n const updated = await client.updateUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n body: { enabled: !user.enabled },\n });\n setUser(updated);\n } finally {\n setActionLoading(null);\n }\n };\n\n const handleSendVerification = async () => {\n setActionLoading(\"verify\");\n // TODO: Implement send verification\n await new Promise((resolve) => setTimeout(resolve, 1000));\n setActionLoading(null);\n };\n\n const handleResetPassword = async () => {\n setActionLoading(\"reset\");\n // TODO: Implement reset password\n await new Promise((resolve) => setTimeout(resolve, 1000));\n setActionLoading(null);\n };\n\n const handleDeleteUser = async () => {\n if (\n !confirm(\n \"Are you sure you want to delete this user? This action cannot be undone.\",\n )\n ) {\n return;\n }\n setActionLoading(\"delete\");\n try {\n await client.deleteUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n await router.push(\"adminUsers\");\n } finally {\n setActionLoading(null);\n }\n };\n\n return (\n <Flex py=\"xl\" px=\"xl\" flex={1}>\n <Flex direction=\"column\" gap=\"lg\">\n <AdminResourceHeader\n backHref={router.path(\"adminUsers\")}\n backLabel=\"Users\"\n avatar={user.picture || displayName.charAt(0).toUpperCase()}\n avatarColor={user.enabled ? \"blue\" : \"gray\"}\n title={displayName}\n subtitle={user.email || user.username || undefined}\n status={{\n label: user.enabled ? \"Active\" : \"Disabled\",\n color: user.enabled ? \"green\" : \"red\",\n }}\n menuActions={[\n {\n label: \"Edit Profile\",\n icon: IconPencil,\n href: router.path(\"adminUserDetails\", { params: { userId } }),\n },\n {\n label: user.enabled ? \"Disable User\" : \"Enable User\",\n icon: user.enabled ? IconBan : IconShieldCheck,\n color: user.enabled ? \"orange\" : \"green\",\n onClick: handleBlockUser,\n loading: actionLoading === \"block\",\n },\n ...(user.email && !user.emailVerified\n ? [\n {\n label: \"Send Verification Email\",\n icon: IconMail,\n onClick: handleSendVerification,\n loading: actionLoading === \"verify\",\n },\n ]\n : []),\n {\n label: \"Reset Password\",\n icon: IconLock,\n onClick: handleResetPassword,\n loading: actionLoading === \"reset\",\n },\n {\n label: \"Delete User\",\n icon: IconTrash,\n color: \"red\",\n onClick: handleDeleteUser,\n loading: actionLoading === \"delete\",\n },\n ]}\n />\n\n <AdminResourceTabs\n activeTab={getActiveTab()}\n tabs={[\n {\n value: \"profile\",\n label: \"Profile\",\n icon: IconUser,\n href: router.path(\"adminUserDetails\", { params: { userId } }),\n },\n {\n value: \"sessions\",\n label: \"Sessions\",\n icon: IconDevices,\n href: router.path(\"adminUserSessions\", { params: { userId } }),\n },\n {\n value: \"audits\",\n label: \"Activity\",\n icon: IconHistory,\n href: router.path(\"adminUserAudits\", { params: { userId } }),\n },\n {\n value: \"settings\",\n label: \"Settings\",\n icon: IconSettings,\n href: router.path(\"adminUserSettings\", { params: { userId } }),\n },\n ]}\n />\n\n <NestedView />\n </Flex>\n </Flex>\n );\n};\n\nexport default AdminUserLayout;\n"],"mappings":"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"}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-CjeV3_4I.js";
|
|
2
1
|
import { ActionButton, DataTable, Flex, Text } from "@alepha/ui";
|
|
3
2
|
import { t } from "alepha";
|
|
4
3
|
import { IconDeviceDesktop, IconDeviceMobile, IconDeviceTablet, IconTrash } from "@tabler/icons-react";
|
|
5
4
|
import { useRouterState } from "alepha/react/router";
|
|
6
|
-
import { Badge
|
|
5
|
+
import { Badge } from "@mantine/core";
|
|
6
|
+
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { useClient } from "alepha/react";
|
|
8
8
|
import { useI18n } from "alepha/react/i18n";
|
|
9
|
-
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
9
|
import { useState } from "react";
|
|
11
10
|
|
|
12
11
|
//#region ../../src/admin/components/users/AdminUserSessions.tsx
|
|
13
|
-
var AdminUserSessions_exports = /* @__PURE__ */ __exportAll({ default: () => AdminUserSessions });
|
|
14
12
|
const AdminUserSessions = (props) => {
|
|
15
13
|
const state = useRouterState();
|
|
16
14
|
const client = useClient();
|
|
@@ -59,7 +57,7 @@ const AdminUserSessions = (props) => {
|
|
|
59
57
|
columns: {
|
|
60
58
|
userAgent: {
|
|
61
59
|
label: "Device",
|
|
62
|
-
value: (item) => /* @__PURE__ */ jsx(
|
|
60
|
+
value: (item) => /* @__PURE__ */ jsx(Flex, {
|
|
63
61
|
gap: 4,
|
|
64
62
|
children: item.userAgent ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Badge, {
|
|
65
63
|
size: "xs",
|
|
@@ -127,5 +125,5 @@ const AdminUserSessions = (props) => {
|
|
|
127
125
|
};
|
|
128
126
|
|
|
129
127
|
//#endregion
|
|
130
|
-
export {
|
|
131
|
-
//# sourceMappingURL=AdminUserSessions-
|
|
128
|
+
export { AdminUserSessions as default };
|
|
129
|
+
//# sourceMappingURL=AdminUserSessions-Bq1LnVLf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUserSessions-Bq1LnVLf.js","names":[],"sources":["../../src/admin/components/users/AdminUserSessions.tsx"],"sourcesContent":["import { ActionButton, DataTable, Flex, Text } from \"@alepha/ui\";\nimport { Badge } from \"@mantine/core\";\nimport {\n IconDeviceDesktop,\n IconDeviceMobile,\n IconDeviceTablet,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport { type Page, t } from \"alepha\";\nimport type { AdminSessionController, SessionEntity } from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouterState } from \"alepha/react/router\";\nimport { useState } from \"react\";\n\nexport interface AdminUserSessionsProps {\n userRealmName?: string;\n}\n\nconst AdminUserSessions = (props: AdminUserSessionsProps) => {\n const state = useRouterState();\n const client = useClient<AdminSessionController>();\n const { l } = useI18n();\n const userId = state.params.userId as string;\n const [refreshKey, setRefreshKey] = useState(0);\n\n const getDeviceIcon = (device?: string) => {\n switch (device) {\n case \"MOBILE\":\n return <IconDeviceMobile size={14} />;\n case \"TABLET\":\n return <IconDeviceTablet size={14} />;\n default:\n return <IconDeviceDesktop size={14} />;\n }\n };\n\n const isExpired = (expiresAt: Date | string) => {\n return new Date(expiresAt) < new Date();\n };\n\n const handleDelete = async (sessionId: string) => {\n await client.deleteSession({\n params: { id: sessionId },\n query: { userRealmName: props.userRealmName },\n });\n setRefreshKey((k) => k + 1);\n };\n\n const filters = t.object({});\n\n return (\n <Flex flex={1} direction=\"column\">\n <DataTable<SessionEntity, typeof filters>\n key={refreshKey}\n submitOnInit\n defaultSize={10}\n filters={filters}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n }}\n tableTrProps={(item) => {\n if (isExpired(item.expiresAt)) {\n return {\n opacity: 0.5,\n };\n }\n return {};\n }}\n items={async (filters) => {\n const response = await client.findSessions({\n query: {\n ...filters,\n userId,\n userRealmName: props.userRealmName,\n },\n });\n\n return response as Page<SessionEntity>;\n }}\n columns={{\n userAgent: {\n label: \"Device\",\n value: (item) => (\n <Flex gap={4}>\n {item.userAgent ? (\n <>\n <Badge\n size=\"xs\"\n variant=\"light\"\n leftSection={getDeviceIcon(item.userAgent.device)}\n >\n {item.userAgent.device}\n </Badge>\n <Text size=\"xs\" c=\"dimmed\">\n {item.userAgent.browser} / {item.userAgent.os}\n </Text>\n </>\n ) : (\n <Text size=\"xs\" c=\"dimmed\">\n -\n </Text>\n )}\n </Flex>\n ),\n },\n ip: {\n label: \"IP Address\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" ff=\"monospace\" c=\"dimmed\">\n {item.ip || \"-\"}\n </Text>\n ),\n },\n expiresAt: {\n label: \"Status\",\n fit: true,\n value: (item) => (\n <Badge\n size=\"sm\"\n variant=\"light\"\n color={isExpired(item.expiresAt) ? \"red\" : \"green\"}\n >\n {isExpired(item.expiresAt) ? \"Expired\" : \"Active\"}\n </Badge>\n ),\n },\n createdAt: {\n label: \"Created\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {l(item.createdAt, { date: \"fromNow\" })}\n </Text>\n ),\n },\n actions: {\n label: \"\",\n fit: true,\n value: (item) => (\n <ActionButton\n size=\"xs\"\n variant=\"subtle\"\n color=\"red\"\n onClick={() => handleDelete(item.id)}\n >\n <IconTrash size={14} />\n </ActionButton>\n ),\n },\n }}\n />\n </Flex>\n );\n};\n\nexport default AdminUserSessions;\n"],"mappings":";;;;;;;;;;;AAmBA,MAAM,qBAAqB,UAAkC;CAC3D,MAAM,QAAQ,gBAAgB;CAC9B,MAAM,SAAS,WAAmC;CAClD,MAAM,EAAE,MAAM,SAAS;CACvB,MAAM,SAAS,MAAM,OAAO;CAC5B,MAAM,CAAC,YAAY,iBAAiB,SAAS,EAAE;CAE/C,MAAM,iBAAiB,WAAoB;AACzC,UAAQ,QAAR;GACE,KAAK,SACH,QAAO,oBAAC,oBAAiB,MAAM,KAAM;GACvC,KAAK,SACH,QAAO,oBAAC,oBAAiB,MAAM,KAAM;GACvC,QACE,QAAO,oBAAC,qBAAkB,MAAM,KAAM;;;CAI5C,MAAM,aAAa,cAA6B;AAC9C,SAAO,IAAI,KAAK,UAAU,mBAAG,IAAI,MAAM;;CAGzC,MAAM,eAAe,OAAO,cAAsB;AAChD,QAAM,OAAO,cAAc;GACzB,QAAQ,EAAE,IAAI,WAAW;GACzB,OAAO,EAAE,eAAe,MAAM,eAAe;GAC9C,CAAC;AACF,iBAAe,MAAM,IAAI,EAAE;;AAK7B,QACE,oBAAC;EAAK,MAAM;EAAG,WAAU;YACvB,oBAAC;GAEC;GACA,aAAa;GACb,SARU,EAAE,OAAO,EAAE,CAAC;GAStB,YAAY;IACV,mBAAmB;IACnB,iBAAiB;IAClB;GACD,eAAe,SAAS;AACtB,QAAI,UAAU,KAAK,UAAU,CAC3B,QAAO,EACL,SAAS,IACV;AAEH,WAAO,EAAE;;GAEX,OAAO,OAAO,YAAY;AASxB,WARiB,MAAM,OAAO,aAAa,EACzC,OAAO;KACL,GAAG;KACH;KACA,eAAe,MAAM;KACtB,EACF,CAAC;;GAIJ,SAAS;IACP,WAAW;KACT,OAAO;KACP,QAAQ,SACN,oBAAC;MAAK,KAAK;gBACR,KAAK,YACJ,4CACE,oBAAC;OACC,MAAK;OACL,SAAQ;OACR,aAAa,cAAc,KAAK,UAAU,OAAO;iBAEhD,KAAK,UAAU;QACV,EACR,qBAAC;OAAK,MAAK;OAAK,GAAE;;QACf,KAAK,UAAU;QAAQ;QAAI,KAAK,UAAU;;QACtC,IACN,GAEH,oBAAC;OAAK,MAAK;OAAK,GAAE;iBAAS;QAEpB;OAEJ;KAEV;IACD,IAAI;KACF,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,IAAG;MAAY,GAAE;gBAC9B,KAAK,MAAM;OACP;KAEV;IACD,WAAW;KACT,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MACC,MAAK;MACL,SAAQ;MACR,OAAO,UAAU,KAAK,UAAU,GAAG,QAAQ;gBAE1C,UAAU,KAAK,UAAU,GAAG,YAAY;OACnC;KAEX;IACD,WAAW;KACT,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;OAClC;KAEV;IACD,SAAS;KACP,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MACC,MAAK;MACL,SAAQ;MACR,OAAM;MACN,eAAe,aAAa,KAAK,GAAG;gBAEpC,oBAAC,aAAU,MAAM,KAAM;OACV;KAElB;IACF;KAlGI,WAmGL;GACG"}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-CjeV3_4I.js";
|
|
2
1
|
import { ActionButton, Flex, Text } from "@alepha/ui";
|
|
3
2
|
import { IconAlertCircle, IconCheck, IconMail, IconTrash } from "@tabler/icons-react";
|
|
4
3
|
import { useRouter, useRouterState } from "alepha/react/router";
|
|
5
|
-
import { Alert, Card,
|
|
6
|
-
import { useClient } from "alepha/react";
|
|
4
|
+
import { Alert, Card, Loader } from "@mantine/core";
|
|
7
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { useClient } from "alepha/react";
|
|
8
7
|
import { useEffect, useState } from "react";
|
|
9
8
|
|
|
10
9
|
//#region ../../src/admin/components/users/AdminUserSettings.tsx
|
|
11
|
-
var AdminUserSettings_exports = /* @__PURE__ */ __exportAll({ default: () => AdminUserSettings });
|
|
12
10
|
const AdminUserSettings = (props) => {
|
|
13
11
|
const router = useRouter();
|
|
14
12
|
const state = useRouterState();
|
|
@@ -86,7 +84,8 @@ const AdminUserSettings = (props) => {
|
|
|
86
84
|
children: [user.email && !user.emailVerified && /* @__PURE__ */ jsx(Card, {
|
|
87
85
|
withBorder: true,
|
|
88
86
|
p: "lg",
|
|
89
|
-
children: /* @__PURE__ */ jsxs(
|
|
87
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
88
|
+
direction: "column",
|
|
90
89
|
gap: "md",
|
|
91
90
|
children: [
|
|
92
91
|
/* @__PURE__ */ jsx(Text, {
|
|
@@ -120,7 +119,7 @@ const AdminUserSettings = (props) => {
|
|
|
120
119
|
]
|
|
121
120
|
})
|
|
122
121
|
}),
|
|
123
|
-
/* @__PURE__ */ jsx(
|
|
122
|
+
/* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(ActionButton, {
|
|
124
123
|
leftSection: /* @__PURE__ */ jsx(IconMail, { size: 16 }),
|
|
125
124
|
loading: verifyLoading,
|
|
126
125
|
onClick: handleTriggerEmailVerification,
|
|
@@ -131,7 +130,8 @@ const AdminUserSettings = (props) => {
|
|
|
131
130
|
}), /* @__PURE__ */ jsx(Card, {
|
|
132
131
|
withBorder: true,
|
|
133
132
|
p: "lg",
|
|
134
|
-
children: /* @__PURE__ */ jsxs(
|
|
133
|
+
children: /* @__PURE__ */ jsxs(Flex, {
|
|
134
|
+
direction: "column",
|
|
135
135
|
gap: "md",
|
|
136
136
|
children: [
|
|
137
137
|
/* @__PURE__ */ jsx(Text, {
|
|
@@ -149,7 +149,7 @@ const AdminUserSettings = (props) => {
|
|
|
149
149
|
children: "Deleting this user will permanently remove their account and all associated data. This action cannot be undone."
|
|
150
150
|
})
|
|
151
151
|
}),
|
|
152
|
-
/* @__PURE__ */ jsx(
|
|
152
|
+
/* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(ActionButton, {
|
|
153
153
|
color: "red",
|
|
154
154
|
leftSection: /* @__PURE__ */ jsx(IconTrash, { size: 16 }),
|
|
155
155
|
loading: deleteLoading,
|
|
@@ -163,5 +163,5 @@ const AdminUserSettings = (props) => {
|
|
|
163
163
|
};
|
|
164
164
|
|
|
165
165
|
//#endregion
|
|
166
|
-
export {
|
|
167
|
-
//# sourceMappingURL=AdminUserSettings-
|
|
166
|
+
export { AdminUserSettings as default };
|
|
167
|
+
//# sourceMappingURL=AdminUserSettings-BRsBZoxV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUserSettings-BRsBZoxV.js","names":[],"sources":["../../src/admin/components/users/AdminUserSettings.tsx"],"sourcesContent":["import { ActionButton, Flex, Text } from \"@alepha/ui\";\nimport { Alert, Card, Loader } from \"@mantine/core\";\nimport {\n IconAlertCircle,\n IconCheck,\n IconMail,\n IconTrash,\n} from \"@tabler/icons-react\";\nimport type {\n AdminUserController,\n UserController,\n UserEntity,\n} from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useRouter, useRouterState } from \"alepha/react/router\";\nimport { useEffect, useState } from \"react\";\nimport type { AdminRouter } from \"../../AdminRouter.ts\";\n\nexport interface AdminUserSettingsProps {\n userRealmName?: string;\n}\n\nconst AdminUserSettings = (props: AdminUserSettingsProps) => {\n const router = useRouter<AdminRouter>();\n const state = useRouterState();\n const adminClient = useClient<AdminUserController>();\n const userClient = useClient<UserController>();\n const userId = state.params.userId as string;\n\n const [user, setUser] = useState<UserEntity | null>(null);\n const [loading, setLoading] = useState(true);\n const [deleteLoading, setDeleteLoading] = useState(false);\n const [verifyLoading, setVerifyLoading] = useState(false);\n const [verifySuccess, setVerifySuccess] = useState(false);\n\n useEffect(() => {\n const loadUser = async () => {\n try {\n const data = await adminClient.getUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n setUser(data);\n } finally {\n setLoading(false);\n }\n };\n\n loadUser();\n }, [userId]);\n\n const handleDelete = async () => {\n if (!confirm(\"Are you sure you want to delete this user?\")) {\n return;\n }\n\n setDeleteLoading(true);\n try {\n await adminClient.deleteUser({\n params: { id: userId },\n query: { userRealmName: props.userRealmName },\n });\n await router.push(\"adminUsers\");\n } finally {\n setDeleteLoading(false);\n }\n };\n\n const handleTriggerEmailVerification = async () => {\n if (!user?.email) return;\n\n setVerifyLoading(true);\n setVerifySuccess(false);\n try {\n await userClient.requestEmailVerification({\n query: {\n userRealmName: props.userRealmName,\n method: \"link\",\n verifyUrl: `${window.location.origin}/auth/verify-email`,\n },\n body: { email: user.email },\n });\n setVerifySuccess(true);\n } finally {\n setVerifyLoading(false);\n }\n };\n\n if (loading) {\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Loader />\n </Flex>\n );\n }\n\n if (!user) {\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Text c=\"dimmed\">User not found</Text>\n </Flex>\n );\n }\n\n return (\n <Flex flex={1} direction=\"column\" gap=\"md\">\n {user.email && !user.emailVerified && (\n <Card withBorder p=\"lg\">\n <Flex direction=\"column\" gap=\"md\">\n <Text size=\"lg\" fw={500}>\n Email Verification\n </Text>\n\n <Alert variant=\"light\" color=\"yellow\" icon={<IconMail />}>\n <Text size=\"sm\">\n This user's email ({user.email}) is not verified. You can send a\n verification link to the user.\n </Text>\n </Alert>\n\n {verifySuccess && (\n <Alert variant=\"light\" color=\"green\" icon={<IconCheck />}>\n <Text size=\"sm\">\n Verification link sent successfully to {user.email}.\n </Text>\n </Alert>\n )}\n\n <Flex>\n <ActionButton\n leftSection={<IconMail size={16} />}\n loading={verifyLoading}\n onClick={handleTriggerEmailVerification}\n >\n Send Verification Link\n </ActionButton>\n </Flex>\n </Flex>\n </Card>\n )}\n\n <Card withBorder p=\"lg\">\n <Flex direction=\"column\" gap=\"md\">\n <Text size=\"lg\" fw={500} c=\"red\">\n Danger Zone\n </Text>\n\n <Alert variant=\"light\" color=\"red\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">\n Deleting this user will permanently remove their account and all\n associated data. This action cannot be undone.\n </Text>\n </Alert>\n\n <Flex>\n <ActionButton\n color=\"red\"\n leftSection={<IconTrash size={16} />}\n loading={deleteLoading}\n onClick={handleDelete}\n >\n Delete User\n </ActionButton>\n </Flex>\n </Flex>\n </Card>\n </Flex>\n );\n};\n\nexport default AdminUserSettings;\n"],"mappings":"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"}
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
import { t as __exportAll } from "./rolldown-runtime-CjeV3_4I.js";
|
|
2
1
|
import { DataTable, Text } from "@alepha/ui";
|
|
3
2
|
import { t } from "alepha";
|
|
4
3
|
import { IconCheck, IconUsersPlus, IconX } from "@tabler/icons-react";
|
|
5
4
|
import { useRouter } from "alepha/react/router";
|
|
6
|
-
import { Badge, Flex as Flex$1
|
|
5
|
+
import { Badge, Flex as Flex$1 } from "@mantine/core";
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
import { useClient } from "alepha/react";
|
|
8
8
|
import { useI18n } from "alepha/react/i18n";
|
|
9
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
9
|
import { users } from "alepha/api/users";
|
|
11
10
|
|
|
12
11
|
//#region ../../src/admin/components/users/AdminUsers.tsx
|
|
13
|
-
var AdminUsers_exports = /* @__PURE__ */ __exportAll({ default: () => AdminUsers });
|
|
14
12
|
const AdminUsers = (props) => {
|
|
15
13
|
const client = useClient();
|
|
16
14
|
const router = useRouter();
|
|
@@ -66,7 +64,7 @@ const AdminUsers = (props) => {
|
|
|
66
64
|
},
|
|
67
65
|
email: {
|
|
68
66
|
label: "Email",
|
|
69
|
-
value: (item) => /* @__PURE__ */ jsxs(
|
|
67
|
+
value: (item) => /* @__PURE__ */ jsxs(Flex$1, {
|
|
70
68
|
gap: "xs",
|
|
71
69
|
children: [/* @__PURE__ */ jsx(Text, {
|
|
72
70
|
size: "sm",
|
|
@@ -82,7 +80,7 @@ const AdminUsers = (props) => {
|
|
|
82
80
|
},
|
|
83
81
|
roles: {
|
|
84
82
|
label: "Roles",
|
|
85
|
-
value: (item) => /* @__PURE__ */ jsx(
|
|
83
|
+
value: (item) => /* @__PURE__ */ jsx(Flex$1, {
|
|
86
84
|
gap: 4,
|
|
87
85
|
children: item.roles.map((role) => /* @__PURE__ */ jsx(Badge, {
|
|
88
86
|
size: "xs",
|
|
@@ -116,5 +114,5 @@ const AdminUsers = (props) => {
|
|
|
116
114
|
};
|
|
117
115
|
|
|
118
116
|
//#endregion
|
|
119
|
-
export {
|
|
120
|
-
//# sourceMappingURL=AdminUsers-
|
|
117
|
+
export { AdminUsers as default };
|
|
118
|
+
//# sourceMappingURL=AdminUsers-D71kIOSn.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUsers-D71kIOSn.js","names":["Flex"],"sources":["../../src/admin/components/users/AdminUsers.tsx"],"sourcesContent":["import { DataTable, Text } from \"@alepha/ui\";\nimport { Badge, Flex } from \"@mantine/core\";\nimport { IconCheck, IconUsersPlus, IconX } from \"@tabler/icons-react\";\nimport { type Page, t } from \"alepha\";\nimport {\n type AdminUserController,\n type UserEntity,\n users,\n} from \"alepha/api/users\";\nimport { useClient } from \"alepha/react\";\nimport { useI18n } from \"alepha/react/i18n\";\nimport { useRouter } from \"alepha/react/router\";\nimport type { AdminRouter } from \"../../AdminRouter.ts\";\n\nexport interface AdminUsersProps {\n userRealmName?: string;\n}\n\nconst AdminUsers = (props: AdminUsersProps) => {\n const client = useClient<AdminUserController>();\n const router = useRouter<AdminRouter>();\n const { l } = useI18n();\n\n const filters = t.object({\n query: t.optional(\n t.string({\n $control: {\n query: t.omit(users.schema, [\"id\", \"version\"]),\n },\n }),\n ),\n });\n\n return (\n <Flex flex={1} direction=\"column\">\n <DataTable<UserEntity, typeof filters>\n submitOnInit\n actions={[\n {\n icon: IconUsersPlus,\n href: router.path(\"adminUserCreate\"),\n label: \"Create User\",\n },\n ]}\n defaultSize={10}\n typeFormProps={{\n skipSubmitButton: true,\n columns: 3,\n }}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n striped: false,\n highlightOnHover: true,\n }}\n onFilterChange={(key, value, form) => {\n if (key === \"query\") {\n return form.submit();\n }\n }}\n filters={filters}\n tableTrProps={(item) => {\n const baseProps: Record<string, any> = {\n style: { cursor: \"pointer\" },\n onClick: () =>\n router.push(\"adminUserDetails\", {\n params: { userId: item.id },\n }),\n };\n\n if (!item.enabled) {\n baseProps.opacity = 0.5;\n }\n\n return baseProps;\n }}\n items={async (filters) => {\n const response = await client.findUsers({\n query: {\n ...filters,\n userRealmName: props.userRealmName,\n },\n });\n\n return response as Page<UserEntity>;\n }}\n columns={{\n username: {\n label: \"Username\",\n value: (item) => (\n <Text size=\"sm\" fw={500}>\n {item.username || \"-\"}\n </Text>\n ),\n },\n email: {\n label: \"Email\",\n value: (item) => (\n <Flex gap=\"xs\">\n <Text size=\"sm\">{item.email || \"-\"}</Text>\n {item.email && (\n <Badge\n size=\"xs\"\n variant=\"light\"\n color={item.emailVerified ? \"green\" : \"gray\"}\n leftSection={\n item.emailVerified ? (\n <IconCheck size={10} />\n ) : (\n <IconX size={10} />\n )\n }\n >\n {item.emailVerified ? \"Verified\" : \"Unverified\"}\n </Badge>\n )}\n </Flex>\n ),\n },\n roles: {\n label: \"Roles\",\n value: (item) => (\n <Flex gap={4}>\n {item.roles.map((role: string) => (\n <Badge key={role} size=\"xs\" variant=\"outline\">\n {role}\n </Badge>\n ))}\n </Flex>\n ),\n },\n enabled: {\n label: \"Status\",\n fit: true,\n value: (item) => (\n <Badge\n size=\"sm\"\n variant=\"light\"\n color={item.enabled ? \"green\" : \"red\"}\n >\n {item.enabled ? \"Active\" : \"Disabled\"}\n </Badge>\n ),\n },\n createdAt: {\n label: \"Created\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\">\n {l(item.createdAt, { date: \"fromNow\" })}\n </Text>\n ),\n },\n }}\n />\n </Flex>\n );\n};\n\nexport default AdminUsers;\n"],"mappings":";;;;;;;;;;;AAkBA,MAAM,cAAc,UAA2B;CAC7C,MAAM,SAAS,WAAgC;CAC/C,MAAM,SAAS,WAAwB;CACvC,MAAM,EAAE,MAAM,SAAS;CAEvB,MAAM,UAAU,EAAE,OAAO,EACvB,OAAO,EAAE,SACP,EAAE,OAAO,EACP,UAAU,EACR,OAAO,EAAE,KAAK,MAAM,QAAQ,CAAC,MAAM,UAAU,CAAC,EAC/C,EACF,CAAC,CACH,EACF,CAAC;AAEF,QACE,oBAACA;EAAK,MAAM;EAAG,WAAU;YACvB,oBAAC;GACC;GACA,SAAS,CACP;IACE,MAAM;IACN,MAAM,OAAO,KAAK,kBAAkB;IACpC,OAAO;IACR,CACF;GACD,aAAa;GACb,eAAe;IACb,kBAAkB;IAClB,SAAS;IACV;GACD,YAAY;IACV,mBAAmB;IACnB,iBAAiB;IACjB,SAAS;IACT,kBAAkB;IACnB;GACD,iBAAiB,KAAK,OAAO,SAAS;AACpC,QAAI,QAAQ,QACV,QAAO,KAAK,QAAQ;;GAGf;GACT,eAAe,SAAS;IACtB,MAAM,YAAiC;KACrC,OAAO,EAAE,QAAQ,WAAW;KAC5B,eACE,OAAO,KAAK,oBAAoB,EAC9B,QAAQ,EAAE,QAAQ,KAAK,IAAI,EAC5B,CAAC;KACL;AAED,QAAI,CAAC,KAAK,QACR,WAAU,UAAU;AAGtB,WAAO;;GAET,OAAO,OAAO,YAAY;AAQxB,WAPiB,MAAM,OAAO,UAAU,EACtC,OAAO;KACL,GAAG;KACH,eAAe,MAAM;KACtB,EACF,CAAC;;GAIJ,SAAS;IACP,UAAU;KACR,OAAO;KACP,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,IAAI;gBACjB,KAAK,YAAY;OACb;KAEV;IACD,OAAO;KACL,OAAO;KACP,QAAQ,SACN,qBAACA;MAAK,KAAI;iBACR,oBAAC;OAAK,MAAK;iBAAM,KAAK,SAAS;QAAW,EACzC,KAAK,SACJ,oBAAC;OACC,MAAK;OACL,SAAQ;OACR,OAAO,KAAK,gBAAgB,UAAU;OACtC,aACE,KAAK,gBACH,oBAAC,aAAU,MAAM,KAAM,GAEvB,oBAAC,SAAM,MAAM,KAAM;iBAItB,KAAK,gBAAgB,aAAa;QAC7B;OAEL;KAEV;IACD,OAAO;KACL,OAAO;KACP,QAAQ,SACN,oBAACA;MAAK,KAAK;gBACR,KAAK,MAAM,KAAK,SACf,oBAAC;OAAiB,MAAK;OAAK,SAAQ;iBACjC;SADS,KAEJ,CACR;OACG;KAEV;IACD,SAAS;KACP,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MACC,MAAK;MACL,SAAQ;MACR,OAAO,KAAK,UAAU,UAAU;gBAE/B,KAAK,UAAU,WAAW;OACrB;KAEX;IACD,WAAW;KACT,OAAO;KACP,KAAK;KACL,QAAQ,SACN,oBAAC;MAAK,MAAK;MAAK,GAAE;gBACf,EAAE,KAAK,WAAW,EAAE,MAAM,WAAW,CAAC;OAClC;KAEV;IACF;IACD;GACG"}
|