@alepha/ui 0.14.1 → 0.14.3
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/AdminAudits-B3EhKhN7.js +3 -0
- package/dist/admin/{AdminAudits-CwvH8e8c.js → AdminAudits-DIrCCPk3.js} +3 -2
- package/dist/admin/AdminAudits-DIrCCPk3.js.map +1 -0
- package/dist/admin/AdminFiles-C8OG4dtD.js +3 -0
- package/dist/admin/{AdminFiles-C_w1tb_x.js → AdminFiles-RsL178Ta.js} +2 -2
- package/dist/admin/{AdminFiles-C_w1tb_x.js.map → AdminFiles-RsL178Ta.js.map} +1 -1
- package/dist/admin/AdminNotifications-BSL4B2fQ.js +3 -0
- package/dist/admin/{AdminNotifications-DuYy74AN.js → AdminNotifications-cIbywWKi.js} +2 -2
- package/dist/admin/AdminNotifications-cIbywWKi.js.map +1 -0
- package/dist/admin/{AdminParameters-DYg48Jwe.js → AdminParameters-BKObzzpN.js} +1 -1
- package/dist/admin/{AdminParameters-YagqWTG3.js → AdminParameters-D-q3Qmhv.js} +2 -2
- package/dist/admin/{AdminParameters-YagqWTG3.js.map → AdminParameters-D-q3Qmhv.js.map} +1 -1
- package/dist/admin/AdminSessions-DHG9zPfr.js +3 -0
- package/dist/admin/{AdminSessions-BCjgJ-93.js → AdminSessions-vOgkrQ2U.js} +3 -2
- package/dist/admin/AdminSessions-vOgkrQ2U.js.map +1 -0
- package/dist/admin/{AdminUserAudits-B_PUXCKC.js → AdminUserAudits-CSsN1fIC.js} +3 -2
- package/dist/admin/AdminUserAudits-CSsN1fIC.js.map +1 -0
- package/dist/admin/{AdminUserAudits-D7cTcElL.js → AdminUserAudits-DmAnivo3.js} +1 -1
- package/dist/admin/{AdminUserCreate-DzfRbGZ4.js → AdminUserCreate-B72nu-3W.js} +3 -2
- package/dist/admin/AdminUserCreate-B72nu-3W.js.map +1 -0
- package/dist/admin/{AdminUserCreate-oUA1KDIl.js → AdminUserCreate-DpA13zwj.js} +1 -1
- package/dist/admin/AdminUserDetails-CKM2IEMr.js +475 -0
- package/dist/admin/AdminUserDetails-CKM2IEMr.js.map +1 -0
- package/dist/admin/{AdminUserDetails-y1H5DW8Y.js → AdminUserDetails-Zib_B6Al.js} +1 -1
- package/dist/admin/{AdminUserLayout-Dejnz13m.js → AdminUserLayout-BNBOEiAO.js} +1 -1
- package/dist/admin/AdminUserLayout-D7En9UBq.js +334 -0
- package/dist/admin/AdminUserLayout-D7En9UBq.js.map +1 -0
- package/dist/admin/AdminUserSessions-D9X2_HMA.js +3 -0
- package/dist/admin/{AdminUserSessions-DO9H85O-.js → AdminUserSessions-DEaGu6n6.js} +3 -2
- package/dist/admin/AdminUserSessions-DEaGu6n6.js.map +1 -0
- package/dist/admin/{AdminUserSettings-B3jA8g3p.js → AdminUserSettings-Di73D7g2.js} +8 -6
- package/dist/admin/AdminUserSettings-Di73D7g2.js.map +1 -0
- package/dist/admin/AdminUserSettings-yI-JECf5.js +3 -0
- package/dist/admin/{AdminUsers-ebbrJBT0.js → AdminUsers-BnGIRvmV.js} +3 -2
- package/dist/admin/AdminUsers-BnGIRvmV.js.map +1 -0
- package/dist/admin/AdminUsers-CG9-2Z8W.js +3 -0
- package/dist/admin/index.d.ts +25 -25
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +37 -36
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/{AuthLayout-BAZJHzDG.js → AuthLayout-B1sUB8fB.js} +2 -2
- package/dist/auth/AuthLayout-B1sUB8fB.js.map +1 -0
- package/dist/auth/Login-BWi-pPbO.js +4 -0
- package/dist/auth/{Login-CeNZZjrr.js → Login-Cjxv3EDi.js} +2 -2
- package/dist/auth/Login-Cjxv3EDi.js.map +1 -0
- package/dist/auth/{Register-s4ENeyiE.js → Register-BKBIpHhW.js} +3 -2
- package/dist/auth/Register-BKBIpHhW.js.map +1 -0
- package/dist/auth/Register-CtdvihIM.js +4 -0
- package/dist/auth/ResetPassword-BUdM7T_R.js +3 -0
- package/dist/auth/{ResetPassword-GLIFkJT7.js → ResetPassword-DvqD_1SJ.js} +3 -2
- package/dist/auth/ResetPassword-DvqD_1SJ.js.map +1 -0
- package/dist/auth/VerifyEmail-BYmtnkEl.js +3 -0
- package/dist/auth/{VerifyEmail-R79sSej_.js → VerifyEmail-VaBruOnO.js} +3 -2
- package/dist/auth/VerifyEmail-VaBruOnO.js.map +1 -0
- package/dist/auth/index.d.ts +11 -11
- package/dist/auth/index.d.ts.map +1 -1
- package/dist/auth/index.js +10 -10
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +36 -55
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +50 -350
- package/dist/core/index.js.map +1 -1
- package/dist/demo/DemoDataTable-2mzzf__a.js +150 -0
- package/dist/demo/DemoDataTable-2mzzf__a.js.map +1 -0
- package/dist/demo/DemoHome-CnuL5WV9.js +25 -0
- package/dist/demo/DemoHome-CnuL5WV9.js.map +1 -0
- package/dist/demo/DemoHome-D6Z7EE4V.js +3 -0
- package/dist/demo/DemoJsonViewer-CYUggLop.js +4 -0
- package/dist/demo/DemoJsonViewer-NUGst5wW.js +430 -0
- package/dist/demo/DemoJsonViewer-NUGst5wW.js.map +1 -0
- package/dist/demo/DemoLayout-ZFDzyvY3.js +3 -0
- package/dist/demo/DemoLayout-dvbeuBBf.js +47 -0
- package/dist/demo/DemoLayout-dvbeuBBf.js.map +1 -0
- package/dist/demo/DemoLogin--wE44i23.js +327 -0
- package/dist/demo/DemoLogin--wE44i23.js.map +1 -0
- package/dist/demo/DemoRegister-BtrMksx6.js +488 -0
- package/dist/demo/DemoRegister-BtrMksx6.js.map +1 -0
- package/dist/demo/DemoResetPassword-DVXiiiX7.js +341 -0
- package/dist/demo/DemoResetPassword-DVXiiiX7.js.map +1 -0
- package/dist/demo/DemoSidebar-DWnjYHoP.js +82 -0
- package/dist/demo/DemoSidebar-DWnjYHoP.js.map +1 -0
- package/dist/demo/DemoTypeForm-P5_VInW2.js +83 -0
- package/dist/demo/DemoTypeForm-P5_VInW2.js.map +1 -0
- package/dist/demo/DemoVerifyEmail-C_ooC5u8.js +152 -0
- package/dist/demo/DemoVerifyEmail-C_ooC5u8.js.map +1 -0
- package/dist/demo/IconGoogle-DvmFiEDB.js +58 -0
- package/dist/demo/IconGoogle-DvmFiEDB.js.map +1 -0
- package/dist/demo/Showcase-vemLuO2t.js +187 -0
- package/dist/demo/Showcase-vemLuO2t.js.map +1 -0
- package/dist/demo/index.d.ts +97 -0
- package/dist/demo/index.d.ts.map +1 -0
- package/dist/demo/index.js +121 -0
- package/dist/demo/index.js.map +1 -0
- package/dist/json/index.d.ts +58 -0
- package/dist/json/index.d.ts.map +1 -0
- package/dist/json/index.js +325 -0
- package/dist/json/index.js.map +1 -0
- package/package.json +25 -14
- package/src/admin/AdminRouter.ts +23 -20
- package/src/admin/MainRouter.ts +2 -2
- package/src/admin/components/audits/AdminAudits.tsx +4 -3
- package/src/admin/components/jobs/AdminJobs.tsx +2 -2
- package/src/admin/components/notifications/AdminNotifications.tsx +2 -2
- package/src/admin/components/parameters/AdminParameters.tsx +2 -2
- package/src/admin/components/sessions/AdminSessions.tsx +4 -3
- package/src/admin/components/shared/AdminResourceHeader.tsx +281 -0
- package/src/admin/components/shared/AdminResourceTabs.tsx +94 -0
- package/src/admin/components/shared/index.ts +10 -0
- package/src/admin/components/users/AdminUserAudits.tsx +4 -3
- package/src/admin/components/users/AdminUserCreate.tsx +4 -3
- package/src/admin/components/users/AdminUserDetails.tsx +339 -86
- package/src/admin/components/users/AdminUserLayout.tsx +165 -113
- package/src/admin/components/users/AdminUserSessions.tsx +4 -3
- package/src/admin/components/users/AdminUserSettings.tsx +12 -6
- package/src/admin/components/users/AdminUsers.tsx +8 -3
- package/src/auth/AuthRouter.ts +1 -1
- package/src/auth/components/AuthLayout.tsx +1 -1
- package/src/auth/components/Login.tsx +1 -1
- package/src/auth/components/Register.tsx +2 -1
- package/src/auth/components/ResetPassword.tsx +2 -1
- package/src/auth/components/VerifyEmail.tsx +2 -1
- package/src/auth/components/buttons/UserButton.tsx +1 -1
- package/src/core/RootRouter.ts +1 -1
- package/src/core/components/buttons/ActionButton.tsx +3 -4
- package/src/core/components/form/Control.tsx +12 -1
- package/src/core/components/form/ControlNumber.tsx +5 -0
- package/src/core/components/form/TypeForm.tsx +3 -2
- package/src/core/components/layout/AdminShell.tsx +2 -1
- package/src/core/components/layout/AlephaMantineProvider.tsx +7 -2
- package/src/core/components/layout/Omnibar.tsx +2 -1
- package/src/core/components/layout/Sidebar.tsx +18 -18
- package/src/core/index.ts +1 -2
- package/src/core/services/DialogService.tsx +0 -17
- package/{styles.css → src/core/styles.css} +1 -5
- package/src/demo/DemoRouter.ts +123 -0
- package/src/demo/components/DemoHome.tsx +29 -0
- package/src/demo/components/DemoLayout.tsx +52 -0
- package/src/demo/components/auth/DemoLogin.tsx +130 -0
- package/src/demo/components/auth/DemoRegister.tsx +144 -0
- package/src/demo/components/auth/DemoResetPassword.tsx +69 -0
- package/src/demo/components/auth/DemoVerifyEmail.tsx +28 -0
- package/src/demo/components/core/DemoDataTable.tsx +174 -0
- package/src/demo/components/core/DemoSidebar.tsx +85 -0
- package/src/demo/components/core/DemoTypeForm.tsx +69 -0
- package/src/demo/components/json/DemoJsonViewer.tsx +128 -0
- package/src/demo/components/shared/MacWindow.tsx +105 -0
- package/src/demo/components/shared/Showcase.tsx +112 -0
- package/src/demo/index.ts +30 -0
- package/src/demo/styles.css +0 -0
- package/src/json/components/JsonViewer.css +25 -0
- package/src/json/components/JsonViewer.tsx +526 -0
- package/src/json/extensions/DialogService.tsx +31 -0
- package/src/json/index.ts +5 -0
- package/src/json/styles.css +1 -0
- package/dist/admin/AdminAudits-CwvH8e8c.js.map +0 -1
- package/dist/admin/AdminAudits-Dv8Vk_6r.js +0 -3
- package/dist/admin/AdminFiles-5CPA3lQk.js +0 -3
- package/dist/admin/AdminNotifications-DLjmZWtf.js +0 -3
- package/dist/admin/AdminNotifications-DuYy74AN.js.map +0 -1
- package/dist/admin/AdminSessions-BCjgJ-93.js.map +0 -1
- package/dist/admin/AdminSessions-DEh2uN-4.js +0 -3
- package/dist/admin/AdminUserAudits-B_PUXCKC.js.map +0 -1
- package/dist/admin/AdminUserCreate-DzfRbGZ4.js.map +0 -1
- package/dist/admin/AdminUserDetails-DeTrJm-t.js +0 -221
- package/dist/admin/AdminUserDetails-DeTrJm-t.js.map +0 -1
- package/dist/admin/AdminUserLayout-CsfrrZkD.js +0 -150
- package/dist/admin/AdminUserLayout-CsfrrZkD.js.map +0 -1
- package/dist/admin/AdminUserSessions-Bbhcpz4k.js +0 -3
- package/dist/admin/AdminUserSessions-DO9H85O-.js.map +0 -1
- package/dist/admin/AdminUserSettings-B3jA8g3p.js.map +0 -1
- package/dist/admin/AdminUserSettings-CE0xpbQc.js +0 -3
- package/dist/admin/AdminUsers-CegGZDhW.js +0 -3
- package/dist/admin/AdminUsers-ebbrJBT0.js.map +0 -1
- package/dist/auth/AuthLayout-BAZJHzDG.js.map +0 -1
- package/dist/auth/Login-CeNZZjrr.js.map +0 -1
- package/dist/auth/Login-hQcu1nlu.js +0 -4
- package/dist/auth/Register-B6HBNVHS.js +0 -4
- package/dist/auth/Register-s4ENeyiE.js.map +0 -1
- package/dist/auth/ResetPassword-Cjd-W-Nu.js +0 -3
- package/dist/auth/ResetPassword-GLIFkJT7.js.map +0 -1
- package/dist/auth/VerifyEmail-Dc9ABKUw.js +0 -3
- package/dist/auth/VerifyEmail-R79sSej_.js.map +0 -1
- package/src/core/components/data/JsonViewer.tsx +0 -361
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
import { ActionButton } from "@alepha/ui";
|
|
2
|
+
import { NestedView, useActive, useRouter, useRouterState } from "@alepha/react/router";
|
|
3
|
+
import { IconBan, IconChevronDown, IconChevronLeft, IconDevices, IconExternalLink, IconHistory, IconLock, IconMail, IconPencil, IconSettings, IconShieldCheck, IconTrash, IconUser } from "@tabler/icons-react";
|
|
4
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { useClient } from "@alepha/react";
|
|
6
|
+
import { ActionIcon, Avatar, Badge, Box, Button, Center, Group, Loader, Menu, Stack, Tabs, Text as Text$1, Tooltip } from "@mantine/core";
|
|
7
|
+
import { useEffect, useState } from "react";
|
|
8
|
+
|
|
9
|
+
//#region ../../src/admin/components/shared/AdminResourceHeader.tsx
|
|
10
|
+
const ActionMenuItem = (props) => {
|
|
11
|
+
const { action } = props;
|
|
12
|
+
const router = useRouter();
|
|
13
|
+
const menuItemProps = {};
|
|
14
|
+
if (action.href) Object.assign(menuItemProps, router.anchor(action.href));
|
|
15
|
+
else if (action.onClick) menuItemProps.onClick = action.onClick;
|
|
16
|
+
return /* @__PURE__ */ jsx(Menu.Item, {
|
|
17
|
+
leftSection: action.icon ? /* @__PURE__ */ jsx(action.icon, { size: 16 }) : void 0,
|
|
18
|
+
color: action.color,
|
|
19
|
+
disabled: action.disabled,
|
|
20
|
+
...menuItemProps,
|
|
21
|
+
children: action.label
|
|
22
|
+
});
|
|
23
|
+
};
|
|
24
|
+
const AdminResourceHeader = (props) => {
|
|
25
|
+
const { backHref, backLabel = "Back", avatar, avatarColor = "blue", title, subtitle, identifier, identifierLabel = "ID", status, badges = [], primaryAction, menuActions = [], externalUrl } = props;
|
|
26
|
+
const renderAvatar = () => {
|
|
27
|
+
if (typeof avatar === "string") {
|
|
28
|
+
if (avatar.startsWith("http") || avatar.startsWith("/")) return /* @__PURE__ */ jsx(Avatar, {
|
|
29
|
+
src: avatar,
|
|
30
|
+
size: 56,
|
|
31
|
+
radius: "md",
|
|
32
|
+
color: avatarColor
|
|
33
|
+
});
|
|
34
|
+
return /* @__PURE__ */ jsx(Avatar, {
|
|
35
|
+
size: 56,
|
|
36
|
+
radius: "md",
|
|
37
|
+
color: avatarColor,
|
|
38
|
+
children: avatar
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
if (avatar) return avatar;
|
|
42
|
+
return /* @__PURE__ */ jsx(Avatar, {
|
|
43
|
+
size: 56,
|
|
44
|
+
radius: "md",
|
|
45
|
+
color: avatarColor,
|
|
46
|
+
children: title.charAt(0).toUpperCase()
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
return /* @__PURE__ */ jsxs(Stack, {
|
|
50
|
+
gap: "xs",
|
|
51
|
+
children: [backHref && /* @__PURE__ */ jsx(Group, { children: /* @__PURE__ */ jsx(ActionButton, {
|
|
52
|
+
variant: "subtle",
|
|
53
|
+
size: "xs",
|
|
54
|
+
href: backHref,
|
|
55
|
+
leftSection: /* @__PURE__ */ jsx(IconChevronLeft, { size: 14 }),
|
|
56
|
+
c: "dimmed",
|
|
57
|
+
children: backLabel
|
|
58
|
+
}) }), /* @__PURE__ */ jsxs(Group, {
|
|
59
|
+
justify: "space-between",
|
|
60
|
+
align: "flex-start",
|
|
61
|
+
wrap: "nowrap",
|
|
62
|
+
children: [/* @__PURE__ */ jsxs(Group, {
|
|
63
|
+
gap: "md",
|
|
64
|
+
wrap: "nowrap",
|
|
65
|
+
children: [renderAvatar(), /* @__PURE__ */ jsxs(Stack, {
|
|
66
|
+
gap: 2,
|
|
67
|
+
justify: "center",
|
|
68
|
+
style: { minHeight: 56 },
|
|
69
|
+
children: [/* @__PURE__ */ jsxs(Group, {
|
|
70
|
+
gap: "xs",
|
|
71
|
+
align: "center",
|
|
72
|
+
children: [/* @__PURE__ */ jsx(Text$1, {
|
|
73
|
+
size: "md",
|
|
74
|
+
fw: 600,
|
|
75
|
+
lh: 1.2,
|
|
76
|
+
children: title
|
|
77
|
+
}), status && /* @__PURE__ */ jsx(Badge, {
|
|
78
|
+
size: "xs",
|
|
79
|
+
variant: "light",
|
|
80
|
+
color: status.color,
|
|
81
|
+
tt: "lowercase",
|
|
82
|
+
children: status.label
|
|
83
|
+
})]
|
|
84
|
+
}), subtitle && /* @__PURE__ */ jsx(Text$1, {
|
|
85
|
+
size: "xs",
|
|
86
|
+
c: "dimmed",
|
|
87
|
+
children: subtitle
|
|
88
|
+
})]
|
|
89
|
+
})]
|
|
90
|
+
}), /* @__PURE__ */ jsxs(Group, {
|
|
91
|
+
gap: "xs",
|
|
92
|
+
children: [
|
|
93
|
+
externalUrl && /* @__PURE__ */ jsx(Tooltip, {
|
|
94
|
+
label: "Open in new tab",
|
|
95
|
+
openDelay: 500,
|
|
96
|
+
children: /* @__PURE__ */ jsx(ActionIcon, {
|
|
97
|
+
variant: "subtle",
|
|
98
|
+
color: "gray",
|
|
99
|
+
component: "a",
|
|
100
|
+
href: externalUrl,
|
|
101
|
+
target: "_blank",
|
|
102
|
+
children: /* @__PURE__ */ jsx(IconExternalLink, { size: 18 })
|
|
103
|
+
})
|
|
104
|
+
}),
|
|
105
|
+
primaryAction && /* @__PURE__ */ jsx(ActionButton, {
|
|
106
|
+
variant: primaryAction.variant ?? "light",
|
|
107
|
+
color: primaryAction.color,
|
|
108
|
+
onClick: primaryAction.onClick,
|
|
109
|
+
href: primaryAction.href,
|
|
110
|
+
loading: primaryAction.loading,
|
|
111
|
+
disabled: primaryAction.disabled,
|
|
112
|
+
leftSection: primaryAction.icon ? /* @__PURE__ */ jsx(primaryAction.icon, { size: 16 }) : void 0,
|
|
113
|
+
children: primaryAction.label
|
|
114
|
+
}),
|
|
115
|
+
menuActions.length > 0 && /* @__PURE__ */ jsxs(Menu, {
|
|
116
|
+
position: "bottom-end",
|
|
117
|
+
shadow: "md",
|
|
118
|
+
width: 220,
|
|
119
|
+
children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Button, {
|
|
120
|
+
variant: "default",
|
|
121
|
+
rightSection: /* @__PURE__ */ jsx(IconChevronDown, { size: 16 }),
|
|
122
|
+
children: "Actions"
|
|
123
|
+
}) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: menuActions.map((action, index) => /* @__PURE__ */ jsx(ActionMenuItem, { action }, index)) })]
|
|
124
|
+
})
|
|
125
|
+
]
|
|
126
|
+
})]
|
|
127
|
+
})]
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
var AdminResourceHeader_default = AdminResourceHeader;
|
|
131
|
+
|
|
132
|
+
//#endregion
|
|
133
|
+
//#region ../../src/admin/components/shared/AdminResourceTabs.tsx
|
|
134
|
+
const TabItem = (props) => {
|
|
135
|
+
const { tab } = props;
|
|
136
|
+
const router = useRouter();
|
|
137
|
+
const { isActive, isPending } = useActive({ href: tab.href });
|
|
138
|
+
const anchorProps = router.anchor(tab.href);
|
|
139
|
+
return /* @__PURE__ */ jsxs(Tabs.Tab, {
|
|
140
|
+
value: tab.value,
|
|
141
|
+
component: "a",
|
|
142
|
+
leftSection: tab.icon ? /* @__PURE__ */ jsx(tab.icon, { size: 16 }) : void 0,
|
|
143
|
+
disabled: tab.disabled,
|
|
144
|
+
"data-active": isActive || void 0,
|
|
145
|
+
style: { opacity: isPending ? .6 : 1 },
|
|
146
|
+
...anchorProps,
|
|
147
|
+
children: [tab.label, tab.count !== void 0 && tab.count > 0 && ` (${tab.count})`]
|
|
148
|
+
});
|
|
149
|
+
};
|
|
150
|
+
const AdminResourceTabs = (props) => {
|
|
151
|
+
const { tabs, activeTab, children } = props;
|
|
152
|
+
return /* @__PURE__ */ jsxs(Tabs, {
|
|
153
|
+
value: activeTab,
|
|
154
|
+
variant: "default",
|
|
155
|
+
children: [/* @__PURE__ */ jsx(Tabs.List, { children: tabs.map((tab) => /* @__PURE__ */ jsx(TabItem, { tab }, tab.value)) }), children]
|
|
156
|
+
});
|
|
157
|
+
};
|
|
158
|
+
var AdminResourceTabs_default = AdminResourceTabs;
|
|
159
|
+
|
|
160
|
+
//#endregion
|
|
161
|
+
//#region ../../src/admin/components/users/AdminUserLayout.tsx
|
|
162
|
+
const AdminUserLayout = (props) => {
|
|
163
|
+
const router = useRouter();
|
|
164
|
+
const state = useRouterState();
|
|
165
|
+
const client = useClient();
|
|
166
|
+
const userId = state.params.userId;
|
|
167
|
+
const [user, setUser] = useState(null);
|
|
168
|
+
const [loading, setLoading] = useState(true);
|
|
169
|
+
const [actionLoading, setActionLoading] = useState(null);
|
|
170
|
+
useEffect(() => {
|
|
171
|
+
const loadUser = async () => {
|
|
172
|
+
try {
|
|
173
|
+
setUser(await client.getUser({
|
|
174
|
+
params: { id: userId },
|
|
175
|
+
query: { userRealmName: props.userRealmName }
|
|
176
|
+
}));
|
|
177
|
+
} finally {
|
|
178
|
+
setLoading(false);
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
loadUser();
|
|
182
|
+
}, [userId]);
|
|
183
|
+
if (loading) return /* @__PURE__ */ jsx(Center, {
|
|
184
|
+
flex: 1,
|
|
185
|
+
children: /* @__PURE__ */ jsx(Loader, {})
|
|
186
|
+
});
|
|
187
|
+
if (!user) return /* @__PURE__ */ jsx(Center, {
|
|
188
|
+
flex: 1,
|
|
189
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
190
|
+
align: "center",
|
|
191
|
+
gap: "xs",
|
|
192
|
+
children: [/* @__PURE__ */ jsx(IconUser, {
|
|
193
|
+
size: 48,
|
|
194
|
+
opacity: .3
|
|
195
|
+
}), /* @__PURE__ */ jsx(Text$1, {
|
|
196
|
+
c: "dimmed",
|
|
197
|
+
children: "User not found"
|
|
198
|
+
})]
|
|
199
|
+
})
|
|
200
|
+
});
|
|
201
|
+
const displayName = user.firstName || user.lastName ? `${user.firstName ?? ""} ${user.lastName ?? ""}`.trim() : user.username || user.email || "User";
|
|
202
|
+
const currentPath = state.url.pathname;
|
|
203
|
+
const getActiveTab = () => {
|
|
204
|
+
if (currentPath.endsWith("/sessions")) return "sessions";
|
|
205
|
+
if (currentPath.endsWith("/settings")) return "settings";
|
|
206
|
+
if (currentPath.endsWith("/audits")) return "audits";
|
|
207
|
+
return "profile";
|
|
208
|
+
};
|
|
209
|
+
const handleBlockUser = async () => {
|
|
210
|
+
setActionLoading("block");
|
|
211
|
+
try {
|
|
212
|
+
setUser(await client.updateUser({
|
|
213
|
+
params: { id: userId },
|
|
214
|
+
query: { userRealmName: props.userRealmName },
|
|
215
|
+
body: { enabled: !user.enabled }
|
|
216
|
+
}));
|
|
217
|
+
} finally {
|
|
218
|
+
setActionLoading(null);
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
const handleSendVerification = async () => {
|
|
222
|
+
setActionLoading("verify");
|
|
223
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
224
|
+
setActionLoading(null);
|
|
225
|
+
};
|
|
226
|
+
const handleResetPassword = async () => {
|
|
227
|
+
setActionLoading("reset");
|
|
228
|
+
await new Promise((resolve) => setTimeout(resolve, 1e3));
|
|
229
|
+
setActionLoading(null);
|
|
230
|
+
};
|
|
231
|
+
const handleDeleteUser = async () => {
|
|
232
|
+
if (!confirm("Are you sure you want to delete this user? This action cannot be undone.")) return;
|
|
233
|
+
setActionLoading("delete");
|
|
234
|
+
try {
|
|
235
|
+
await client.deleteUser({
|
|
236
|
+
params: { id: userId },
|
|
237
|
+
query: { userRealmName: props.userRealmName }
|
|
238
|
+
});
|
|
239
|
+
await router.go("adminUsers");
|
|
240
|
+
} finally {
|
|
241
|
+
setActionLoading(null);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
return /* @__PURE__ */ jsx(Box, {
|
|
245
|
+
py: "xl",
|
|
246
|
+
px: "xl",
|
|
247
|
+
flex: 1,
|
|
248
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
249
|
+
gap: "lg",
|
|
250
|
+
children: [
|
|
251
|
+
/* @__PURE__ */ jsx(AdminResourceHeader_default, {
|
|
252
|
+
backHref: router.path("adminUsers"),
|
|
253
|
+
backLabel: "Users",
|
|
254
|
+
avatar: user.picture || displayName.charAt(0).toUpperCase(),
|
|
255
|
+
avatarColor: user.enabled ? "blue" : "gray",
|
|
256
|
+
title: displayName,
|
|
257
|
+
subtitle: user.email || user.username || void 0,
|
|
258
|
+
status: {
|
|
259
|
+
label: user.enabled ? "Active" : "Disabled",
|
|
260
|
+
color: user.enabled ? "green" : "red"
|
|
261
|
+
},
|
|
262
|
+
menuActions: [
|
|
263
|
+
{
|
|
264
|
+
label: "Edit Profile",
|
|
265
|
+
icon: IconPencil,
|
|
266
|
+
href: router.path("adminUserDetails", { params: { userId } })
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
label: user.enabled ? "Disable User" : "Enable User",
|
|
270
|
+
icon: user.enabled ? IconBan : IconShieldCheck,
|
|
271
|
+
color: user.enabled ? "orange" : "green",
|
|
272
|
+
onClick: handleBlockUser,
|
|
273
|
+
loading: actionLoading === "block"
|
|
274
|
+
},
|
|
275
|
+
...user.email && !user.emailVerified ? [{
|
|
276
|
+
label: "Send Verification Email",
|
|
277
|
+
icon: IconMail,
|
|
278
|
+
onClick: handleSendVerification,
|
|
279
|
+
loading: actionLoading === "verify"
|
|
280
|
+
}] : [],
|
|
281
|
+
{
|
|
282
|
+
label: "Reset Password",
|
|
283
|
+
icon: IconLock,
|
|
284
|
+
onClick: handleResetPassword,
|
|
285
|
+
loading: actionLoading === "reset"
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
label: "Delete User",
|
|
289
|
+
icon: IconTrash,
|
|
290
|
+
color: "red",
|
|
291
|
+
onClick: handleDeleteUser,
|
|
292
|
+
loading: actionLoading === "delete"
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
}),
|
|
296
|
+
/* @__PURE__ */ jsx(AdminResourceTabs_default, {
|
|
297
|
+
activeTab: getActiveTab(),
|
|
298
|
+
tabs: [
|
|
299
|
+
{
|
|
300
|
+
value: "profile",
|
|
301
|
+
label: "Profile",
|
|
302
|
+
icon: IconUser,
|
|
303
|
+
href: router.path("adminUserDetails", { params: { userId } })
|
|
304
|
+
},
|
|
305
|
+
{
|
|
306
|
+
value: "sessions",
|
|
307
|
+
label: "Sessions",
|
|
308
|
+
icon: IconDevices,
|
|
309
|
+
href: router.path("adminUserSessions", { params: { userId } })
|
|
310
|
+
},
|
|
311
|
+
{
|
|
312
|
+
value: "audits",
|
|
313
|
+
label: "Activity",
|
|
314
|
+
icon: IconHistory,
|
|
315
|
+
href: router.path("adminUserAudits", { params: { userId } })
|
|
316
|
+
},
|
|
317
|
+
{
|
|
318
|
+
value: "settings",
|
|
319
|
+
label: "Settings",
|
|
320
|
+
icon: IconSettings,
|
|
321
|
+
href: router.path("adminUserSettings", { params: { userId } })
|
|
322
|
+
}
|
|
323
|
+
]
|
|
324
|
+
}),
|
|
325
|
+
/* @__PURE__ */ jsx(NestedView, {})
|
|
326
|
+
]
|
|
327
|
+
})
|
|
328
|
+
});
|
|
329
|
+
};
|
|
330
|
+
var AdminUserLayout_default = AdminUserLayout;
|
|
331
|
+
|
|
332
|
+
//#endregion
|
|
333
|
+
export { AdminUserLayout_default as t };
|
|
334
|
+
//# sourceMappingURL=AdminUserLayout-D7En9UBq.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUserLayout-D7En9UBq.js","names":["Text","Text","AdminResourceHeader","AdminResourceTabs"],"sources":["../../src/admin/components/shared/AdminResourceHeader.tsx","../../src/admin/components/shared/AdminResourceTabs.tsx","../../src/admin/components/users/AdminUserLayout.tsx"],"sourcesContent":["import { useRouter } from \"@alepha/react/router\";\nimport { ActionButton } from \"@alepha/ui\";\nimport {\n ActionIcon,\n Avatar,\n Badge,\n Button,\n Group,\n Menu,\n Stack,\n Text,\n Tooltip,\n} from \"@mantine/core\";\nimport {\n IconChevronDown,\n IconChevronLeft,\n IconExternalLink,\n} from \"@tabler/icons-react\";\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 <Stack gap=\"xs\">\n {/* Breadcrumb / Back navigation */}\n {backHref && (\n <Group>\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 </Group>\n )}\n\n {/* Main header */}\n <Group justify=\"space-between\" align=\"flex-start\" wrap=\"nowrap\">\n {/* Left: Avatar + Info */}\n <Group gap=\"md\" wrap=\"nowrap\">\n {renderAvatar()}\n\n <Stack gap={2} justify=\"center\" style={{ minHeight: 56 }}>\n {/* Title row */}\n <Group 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 </Group>\n\n {/* Subtitle */}\n {subtitle && (\n <Text size=\"xs\" c=\"dimmed\">\n {subtitle}\n </Text>\n )}\n </Stack>\n </Group>\n\n {/* Right: Actions */}\n <Group 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 </Group>\n </Group>\n </Stack>\n );\n};\n\nexport default AdminResourceHeader;\n","import { useActive, useRouter } from \"@alepha/react/router\";\nimport { Tabs } from \"@mantine/core\";\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 { useClient } from \"@alepha/react\";\nimport { NestedView, useRouter, useRouterState } from \"@alepha/react/router\";\nimport { Box, Center, Loader, Stack, 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 { 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 <Stack align=\"center\" gap=\"xs\">\n <IconUser size={48} opacity={0.3} />\n <Text c=\"dimmed\">User not found</Text>\n </Stack>\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.go(\"adminUsers\");\n } finally {\n setActionLoading(null);\n }\n };\n\n return (\n <Box py=\"xl\" px=\"xl\" flex={1}>\n <Stack 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 </Stack>\n </Box>\n );\n};\n\nexport default AdminUserLayout;\n"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ActionButton, DataTable, Flex, Text } from "@alepha/ui";
|
|
2
2
|
import { t } from "alepha";
|
|
3
|
-
import {
|
|
3
|
+
import { useRouterState } from "@alepha/react/router";
|
|
4
4
|
import { IconDeviceDesktop, IconDeviceMobile, IconDeviceTablet, IconTrash } from "@tabler/icons-react";
|
|
5
5
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { useClient } from "@alepha/react";
|
|
6
7
|
import { useI18n } from "@alepha/react/i18n";
|
|
7
8
|
import { Badge, Group } from "@mantine/core";
|
|
8
9
|
import { useState } from "react";
|
|
@@ -126,4 +127,4 @@ var AdminUserSessions_default = AdminUserSessions;
|
|
|
126
127
|
|
|
127
128
|
//#endregion
|
|
128
129
|
export { AdminUserSessions_default as t };
|
|
129
|
-
//# sourceMappingURL=AdminUserSessions-
|
|
130
|
+
//# sourceMappingURL=AdminUserSessions-DEaGu6n6.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUserSessions-DEaGu6n6.js","names":[],"sources":["../../src/admin/components/users/AdminUserSessions.tsx"],"sourcesContent":["import { useClient } from \"@alepha/react\";\nimport { useI18n } from \"@alepha/react/i18n\";\nimport { useRouterState } from \"@alepha/react/router\";\nimport { ActionButton, DataTable, Flex, Text } from \"@alepha/ui\";\nimport { Badge, Group } 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 { 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 <Group 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 </Group>\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;MAAM,KAAK;gBACT,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;OAEH;KAEX;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;;AAIX,gCAAe"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ActionButton, Flex, Text } from "@alepha/ui";
|
|
2
|
-
import {
|
|
2
|
+
import { useRouter, useRouterState } from "@alepha/react/router";
|
|
3
3
|
import { IconAlertCircle, IconCheck, IconMail, IconTrash } from "@tabler/icons-react";
|
|
4
4
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
5
|
+
import { useClient } from "@alepha/react";
|
|
5
6
|
import { Alert, Card, Group, Loader, Stack } from "@mantine/core";
|
|
6
7
|
import { useEffect, useState } from "react";
|
|
7
8
|
|
|
@@ -9,7 +10,8 @@ import { useEffect, useState } from "react";
|
|
|
9
10
|
const AdminUserSettings = (props) => {
|
|
10
11
|
const router = useRouter();
|
|
11
12
|
const state = useRouterState();
|
|
12
|
-
const
|
|
13
|
+
const adminClient = useClient();
|
|
14
|
+
const userClient = useClient();
|
|
13
15
|
const userId = state.params.userId;
|
|
14
16
|
const [user, setUser] = useState(null);
|
|
15
17
|
const [loading, setLoading] = useState(true);
|
|
@@ -19,7 +21,7 @@ const AdminUserSettings = (props) => {
|
|
|
19
21
|
useEffect(() => {
|
|
20
22
|
const loadUser = async () => {
|
|
21
23
|
try {
|
|
22
|
-
setUser(await
|
|
24
|
+
setUser(await adminClient.getUser({
|
|
23
25
|
params: { id: userId },
|
|
24
26
|
query: { userRealmName: props.userRealmName }
|
|
25
27
|
}));
|
|
@@ -33,7 +35,7 @@ const AdminUserSettings = (props) => {
|
|
|
33
35
|
if (!confirm("Are you sure you want to delete this user?")) return;
|
|
34
36
|
setDeleteLoading(true);
|
|
35
37
|
try {
|
|
36
|
-
await
|
|
38
|
+
await adminClient.deleteUser({
|
|
37
39
|
params: { id: userId },
|
|
38
40
|
query: { userRealmName: props.userRealmName }
|
|
39
41
|
});
|
|
@@ -47,7 +49,7 @@ const AdminUserSettings = (props) => {
|
|
|
47
49
|
setVerifyLoading(true);
|
|
48
50
|
setVerifySuccess(false);
|
|
49
51
|
try {
|
|
50
|
-
await
|
|
52
|
+
await userClient.requestEmailVerification({
|
|
51
53
|
query: {
|
|
52
54
|
userRealmName: props.userRealmName,
|
|
53
55
|
method: "link",
|
|
@@ -161,4 +163,4 @@ var AdminUserSettings_default = AdminUserSettings;
|
|
|
161
163
|
|
|
162
164
|
//#endregion
|
|
163
165
|
export { AdminUserSettings_default as t };
|
|
164
|
-
//# sourceMappingURL=AdminUserSettings-
|
|
166
|
+
//# sourceMappingURL=AdminUserSettings-Di73D7g2.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUserSettings-Di73D7g2.js","names":[],"sources":["../../src/admin/components/users/AdminUserSettings.tsx"],"sourcesContent":["import { useClient } from \"@alepha/react\";\nimport { useRouter, useRouterState } from \"@alepha/react/router\";\nimport { ActionButton, Flex, Text } from \"@alepha/ui\";\nimport { Alert, Card, Group, Loader, Stack } 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 { 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.go(\"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}/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 <Stack 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 <Group>\n <ActionButton\n leftSection={<IconMail size={16} />}\n loading={verifyLoading}\n onClick={handleTriggerEmailVerification}\n >\n Send Verification Link\n </ActionButton>\n </Group>\n </Stack>\n </Card>\n )}\n\n <Card withBorder p=\"lg\">\n <Stack 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 <Group>\n <ActionButton\n color=\"red\"\n leftSection={<IconTrash size={16} />}\n loading={deleteLoading}\n onClick={handleDelete}\n >\n Delete User\n </ActionButton>\n </Group>\n </Stack>\n </Card>\n </Flex>\n );\n};\n\nexport default AdminUserSettings;\n"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { DataTable, Text } from "@alepha/ui";
|
|
2
2
|
import { t } from "alepha";
|
|
3
|
-
import {
|
|
3
|
+
import { useRouter } from "@alepha/react/router";
|
|
4
4
|
import { IconCheck, IconUsersPlus, IconX } from "@tabler/icons-react";
|
|
5
5
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
6
|
+
import { useClient } from "@alepha/react";
|
|
6
7
|
import { useI18n } from "@alepha/react/i18n";
|
|
7
8
|
import { Badge, Flex as Flex$1, Group } from "@mantine/core";
|
|
8
9
|
import { users } from "alepha/api/users";
|
|
@@ -115,4 +116,4 @@ var AdminUsers_default = AdminUsers;
|
|
|
115
116
|
|
|
116
117
|
//#endregion
|
|
117
118
|
export { AdminUsers_default as t };
|
|
118
|
-
//# sourceMappingURL=AdminUsers-
|
|
119
|
+
//# sourceMappingURL=AdminUsers-BnGIRvmV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AdminUsers-BnGIRvmV.js","names":["Flex","filters"],"sources":["../../src/admin/components/users/AdminUsers.tsx"],"sourcesContent":["import { useClient } from \"@alepha/react\";\nimport { useI18n } from \"@alepha/react/i18n\";\nimport { useRouter } from \"@alepha/react/router\";\nimport { DataTable, Text } from \"@alepha/ui\";\nimport { Badge, Flex, Group } 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 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.go(\"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 <Group 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 </Group>\n ),\n },\n roles: {\n label: \"Roles\",\n value: (item) => (\n <Group gap={4}>\n {item.roles.map((role: string) => (\n <Badge key={role} size=\"xs\" variant=\"outline\">\n {role}\n </Badge>\n ))}\n </Group>\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,GAAG,oBAAoB,EAC5B,QAAQ,EAAE,QAAQ,KAAK,IAAI,EAC5B,CAAC;KACL;AAED,QAAI,CAAC,KAAK,QACR,WAAU,UAAU;AAGtB,WAAO;;GAET,OAAO,OAAO,cAAY;AAQxB,WAPiB,MAAM,OAAO,UAAU,EACtC,OAAO;KACL,GAAGC;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,qBAAC;MAAM,KAAI;iBACT,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;OAEJ;KAEX;IACD,OAAO;KACL,OAAO;KACP,QAAQ,SACN,oBAAC;MAAM,KAAK;gBACT,KAAK,MAAM,KAAK,SACf,oBAAC;OAAiB,MAAK;OAAK,SAAQ;iBACjC;SADS,KAEJ,CACR;OACI;KAEX;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;;AAIX,yBAAe"}
|
package/dist/admin/index.d.ts
CHANGED
|
@@ -1,43 +1,43 @@
|
|
|
1
1
|
import { AdminShellProps } from "@alepha/ui";
|
|
2
2
|
import { AuthRouter } from "@alepha/ui/auth";
|
|
3
3
|
import * as alepha0 from "alepha";
|
|
4
|
-
import * as _alepha_react2 from "@alepha/react";
|
|
5
|
-
import { ReactRouter, Redirection } from "@alepha/react";
|
|
6
4
|
import { ReactAuth } from "@alepha/react/auth";
|
|
5
|
+
import * as _alepha_react_router2 from "@alepha/react/router";
|
|
6
|
+
import { ReactRouter, Redirection } from "@alepha/react/router";
|
|
7
7
|
import * as alepha_server_links0 from "alepha/server/links";
|
|
8
8
|
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
9
9
|
import { FileController } from "alepha/api/files";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
10
|
+
import { AdminSessionController, AdminUserController } from "alepha/api/users";
|
|
11
|
+
import { AdminAuditController } from "alepha/api/audits";
|
|
12
|
+
import { AdminNotificationController } from "alepha/api/notifications";
|
|
13
|
+
import { AdminConfigController } from "alepha/api/parameters";
|
|
14
14
|
|
|
15
15
|
//#region ../../src/admin/AdminRouter.d.ts
|
|
16
16
|
declare class AdminRouter {
|
|
17
17
|
protected readonly router: ReactRouter<object>;
|
|
18
18
|
protected readonly authRouter: AuthRouter;
|
|
19
19
|
protected readonly auth: ReactAuth;
|
|
20
|
-
protected readonly userCtrl: alepha_server_links0.HttpVirtualClient<
|
|
21
|
-
protected readonly sessionCtrl: alepha_server_links0.HttpVirtualClient<
|
|
22
|
-
protected readonly notificationCtrl: alepha_server_links0.HttpVirtualClient<
|
|
20
|
+
protected readonly userCtrl: alepha_server_links0.HttpVirtualClient<AdminUserController>;
|
|
21
|
+
protected readonly sessionCtrl: alepha_server_links0.HttpVirtualClient<AdminSessionController>;
|
|
22
|
+
protected readonly notificationCtrl: alepha_server_links0.HttpVirtualClient<AdminNotificationController>;
|
|
23
23
|
protected readonly fileCtrl: alepha_server_links0.HttpVirtualClient<FileController>;
|
|
24
|
-
protected readonly configCtrl: alepha_server_links0.HttpVirtualClient<
|
|
25
|
-
protected readonly auditCtrl: alepha_server_links0.HttpVirtualClient<
|
|
24
|
+
protected readonly configCtrl: alepha_server_links0.HttpVirtualClient<AdminConfigController>;
|
|
25
|
+
protected readonly auditCtrl: alepha_server_links0.HttpVirtualClient<AdminAuditController>;
|
|
26
26
|
protected adminShellProps(): AdminShellProps;
|
|
27
27
|
protected onNotAuthorized(url: URL): Redirection;
|
|
28
|
-
readonly
|
|
29
|
-
readonly adminUsers:
|
|
30
|
-
readonly adminUserCreate:
|
|
31
|
-
readonly adminUserLayout:
|
|
32
|
-
readonly adminUserDetails:
|
|
33
|
-
readonly adminUserSessions:
|
|
34
|
-
readonly adminUserSettings:
|
|
35
|
-
readonly adminUserAudits:
|
|
36
|
-
readonly adminAudits:
|
|
37
|
-
readonly adminSessions:
|
|
38
|
-
readonly adminNotifications:
|
|
39
|
-
readonly adminFiles:
|
|
40
|
-
readonly adminParameters:
|
|
28
|
+
readonly adminLayout: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, {}, _alepha_react_router2.TPropsParentDefault>;
|
|
29
|
+
readonly adminUsers: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, {}>;
|
|
30
|
+
readonly adminUserCreate: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, {}>;
|
|
31
|
+
readonly adminUserLayout: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, {}>;
|
|
32
|
+
readonly adminUserDetails: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, any>;
|
|
33
|
+
readonly adminUserSessions: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, any>;
|
|
34
|
+
readonly adminUserSettings: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, any>;
|
|
35
|
+
readonly adminUserAudits: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, any>;
|
|
36
|
+
readonly adminAudits: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, {}>;
|
|
37
|
+
readonly adminSessions: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, {}>;
|
|
38
|
+
readonly adminNotifications: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, {}>;
|
|
39
|
+
readonly adminFiles: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, {}>;
|
|
40
|
+
readonly adminParameters: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, {}>;
|
|
41
41
|
}
|
|
42
42
|
//#endregion
|
|
43
43
|
//#region ../../src/admin/components/AdminLayout.d.ts
|
|
@@ -127,7 +127,7 @@ declare const AdminVerifications: () => react_jsx_runtime0.JSX.Element;
|
|
|
127
127
|
declare class MainRouter {
|
|
128
128
|
auth: AuthRouter;
|
|
129
129
|
admin: AdminRouter;
|
|
130
|
-
layout:
|
|
130
|
+
layout: _alepha_react_router2.PagePrimitive<_alepha_react_router2.PageConfigSchema, any, _alepha_react_router2.TPropsParentDefault>;
|
|
131
131
|
}
|
|
132
132
|
//#endregion
|
|
133
133
|
//#region ../../src/admin/index.d.ts
|