@alepha/ui 0.13.2 → 0.13.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/AdminLayout-JakF7ESb.js +388 -0
- package/dist/admin/AdminLayout-JakF7ESb.js.map +1 -0
- package/dist/admin/AdminLayout-qNsIyl30.js +3 -0
- package/dist/admin/AdminNotifications-BPrxALdS.js +154 -0
- package/dist/admin/AdminNotifications-BPrxALdS.js.map +1 -0
- package/dist/admin/AdminNotifications-DV-35Fi3.js +3 -0
- package/dist/admin/{AdminSessions-CmDVneE2.js → AdminSessions-CMmBtbSw.js} +36 -9
- package/dist/admin/AdminSessions-CMmBtbSw.js.map +1 -0
- package/dist/admin/AdminSessions-Df2VYzlE.js +3 -0
- package/dist/admin/AdminUserCreate-Coa_yi6m.js +103 -0
- package/dist/admin/AdminUserCreate-Coa_yi6m.js.map +1 -0
- package/dist/admin/AdminUserCreate-DjiCcAk0.js +3 -0
- package/dist/admin/AdminUserDetails-BCFwOm9w.js +221 -0
- package/dist/admin/AdminUserDetails-BCFwOm9w.js.map +1 -0
- package/dist/admin/AdminUserDetails-C5yeJNa3.js +3 -0
- package/dist/admin/AdminUserLayout-B8ga5QvP.js +3 -0
- package/dist/admin/AdminUserLayout-CR2OqV9Z.js +153 -0
- package/dist/admin/AdminUserLayout-CR2OqV9Z.js.map +1 -0
- package/dist/admin/AdminUserSessions-A_5KkqTY.js +3 -0
- package/dist/admin/AdminUserSessions-Bcf6-rjG.js +129 -0
- package/dist/admin/AdminUserSessions-Bcf6-rjG.js.map +1 -0
- package/dist/admin/AdminUserSettings-DAsAhFjX.js +3 -0
- package/dist/admin/AdminUserSettings-DRYVdW6S.js +164 -0
- package/dist/admin/AdminUserSettings-DRYVdW6S.js.map +1 -0
- package/dist/admin/AdminUsers-Dd9a5UqO.js +3 -0
- package/dist/admin/{AdminUsers-88De5pev.js → AdminUsers-IN_2yHKt.js} +32 -14
- package/dist/admin/AdminUsers-IN_2yHKt.js.map +1 -0
- package/dist/admin/index.d.ts +5560 -416
- package/dist/admin/index.js +299 -41
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/AuthLayout-BSL8ZHgr.js +19 -0
- package/dist/auth/AuthLayout-BSL8ZHgr.js.map +1 -0
- package/dist/auth/Login-DDsyCNAA.js +4 -0
- package/dist/auth/{Login-OCrvjs9U.js → Login-kBfaRgKG.js} +5 -4
- package/dist/auth/Login-kBfaRgKG.js.map +1 -0
- package/dist/auth/{Register-Ei34GSba.js → Register-BxJmOqpF.js} +9 -6
- package/dist/auth/Register-BxJmOqpF.js.map +1 -0
- package/dist/auth/Register-D10MnlQc.js +4 -0
- package/dist/auth/{ResetPassword-tO0oMzfo.js → ResetPassword-BhyZ9ek4.js} +3 -3
- package/dist/auth/ResetPassword-BhyZ9ek4.js.map +1 -0
- package/dist/auth/ResetPassword-llBG-STp.js +3 -0
- package/dist/auth/VerifyEmail-BvOG-IUC.js +3 -0
- package/dist/auth/VerifyEmail-DeLct3oQ.js +131 -0
- package/dist/auth/VerifyEmail-DeLct3oQ.js.map +1 -0
- package/dist/auth/index.d.ts +2412 -2254
- package/dist/auth/index.js +96 -20
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +280 -95
- package/dist/core/index.js +1381 -392
- package/dist/core/index.js.map +1 -1
- package/package.json +5 -5
- package/src/admin/AdminRouter.ts +116 -29
- package/src/admin/MainRouter.ts +23 -0
- package/src/admin/components/AdminLayout.tsx +86 -103
- package/src/admin/components/AdminNotifications.tsx +196 -12
- package/src/admin/components/AdminSessions.tsx +43 -7
- package/src/admin/components/AdminUserCreate.tsx +84 -0
- package/src/admin/components/AdminUserDetails.tsx +180 -0
- package/src/admin/components/AdminUserLayout.tsx +172 -0
- package/src/admin/components/AdminUserSessions.tsx +158 -0
- package/src/admin/components/AdminUserSettings.tsx +165 -0
- package/src/admin/components/AdminUsers.tsx +29 -9
- package/src/admin/index.ts +12 -3
- package/src/auth/AuthI18n.ts +22 -0
- package/src/auth/AuthRouter.ts +82 -8
- package/src/auth/components/AuthLayout.tsx +12 -0
- package/src/auth/components/Login.tsx +13 -11
- package/src/auth/components/Register.tsx +6 -5
- package/src/auth/components/ResetPassword.tsx +1 -1
- package/src/auth/components/VerifyEmail.tsx +102 -0
- package/src/auth/components/buttons/UserButton.tsx +6 -2
- package/src/auth/index.ts +1 -0
- package/src/core/components/buttons/ActionButton.tsx +11 -4
- package/src/core/components/buttons/DarkModeButton.tsx +1 -1
- package/src/core/components/buttons/ThemeButton.tsx +31 -0
- package/src/core/components/layout/AdminShell.tsx +4 -2
- package/src/core/components/layout/AlephaMantineProvider.tsx +10 -4
- package/src/core/components/layout/Omnibar.tsx +27 -15
- package/src/core/components/layout/Sidebar.tsx +33 -15
- package/src/core/components/table/DataTable.tsx +9 -5
- package/src/core/hooks/useTheme.ts +25 -0
- package/src/core/index.ts +8 -3
- package/src/core/providers/ThemeProvider.ts +87 -0
- package/src/core/themes/aurora.ts +107 -0
- package/src/core/themes/crystal.ts +107 -0
- package/src/core/themes/default.ts +7 -0
- package/src/core/themes/ember.ts +107 -0
- package/src/core/themes/index.ts +7 -0
- package/src/core/themes/midnight.ts +104 -0
- package/src/core/themes/remoraid.ts +278 -0
- package/src/core/themes/slate.ts +81 -0
- package/dist/admin/AdminJobs-BOq6AZOW.js +0 -3
- package/dist/admin/AdminJobs-CDnVxEv6.js +0 -125
- package/dist/admin/AdminJobs-CDnVxEv6.js.map +0 -1
- package/dist/admin/AdminLayout-Bgx25J8m.js +0 -3
- package/dist/admin/AdminLayout-CervL8LV.js +0 -88
- package/dist/admin/AdminLayout-CervL8LV.js.map +0 -1
- package/dist/admin/AdminNotifications-BDQXt3-e.js +0 -3
- package/dist/admin/AdminNotifications-DvI2989x.js +0 -40
- package/dist/admin/AdminNotifications-DvI2989x.js.map +0 -1
- package/dist/admin/AdminParameters-D_v0GAvI.js +0 -3
- package/dist/admin/AdminParameters-P1LB6ZI1.js +0 -40
- package/dist/admin/AdminParameters-P1LB6ZI1.js.map +0 -1
- package/dist/admin/AdminSessions-CmDVneE2.js.map +0 -1
- package/dist/admin/AdminSessions-Dkk_fzWK.js +0 -3
- package/dist/admin/AdminUsers-88De5pev.js.map +0 -1
- package/dist/admin/AdminUsers-oyAXqZ5l.js +0 -3
- package/dist/admin/AdminVerifications-D93TKymL.js +0 -3
- package/dist/admin/AdminVerifications-DBVEoqJe.js +0 -40
- package/dist/admin/AdminVerifications-DBVEoqJe.js.map +0 -1
- package/dist/auth/Login-BC2jTczq.js +0 -4
- package/dist/auth/Login-OCrvjs9U.js.map +0 -1
- package/dist/auth/Register-Dh0lsQmI.js +0 -4
- package/dist/auth/Register-Ei34GSba.js.map +0 -1
- package/dist/auth/ResetPassword-BnlAQAOE.js +0 -3
- package/dist/auth/ResetPassword-tO0oMzfo.js.map +0 -1
package/dist/admin/index.js
CHANGED
|
@@ -1,65 +1,315 @@
|
|
|
1
1
|
import { t as AdminFiles_default } from "./AdminFiles-BjofP3OC.js";
|
|
2
|
-
import { t as
|
|
3
|
-
import { t as
|
|
4
|
-
import { t as
|
|
5
|
-
import { t as
|
|
6
|
-
import { t as
|
|
7
|
-
import { t as
|
|
8
|
-
import { t as
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
2
|
+
import { t as AdminLayout_default } from "./AdminLayout-JakF7ESb.js";
|
|
3
|
+
import { t as AdminNotifications_default } from "./AdminNotifications-BPrxALdS.js";
|
|
4
|
+
import { t as AdminSessions_default } from "./AdminSessions-CMmBtbSw.js";
|
|
5
|
+
import { t as AdminUserCreate_default } from "./AdminUserCreate-Coa_yi6m.js";
|
|
6
|
+
import { t as AdminUserDetails_default } from "./AdminUserDetails-BCFwOm9w.js";
|
|
7
|
+
import { t as AdminUserLayout_default } from "./AdminUserLayout-CR2OqV9Z.js";
|
|
8
|
+
import { t as AdminUserSessions_default } from "./AdminUserSessions-Bcf6-rjG.js";
|
|
9
|
+
import { t as AdminUserSettings_default } from "./AdminUserSettings-DRYVdW6S.js";
|
|
10
|
+
import { t as AdminUsers_default } from "./AdminUsers-IN_2yHKt.js";
|
|
11
|
+
import { AlephaMantineProvider, AlephaUI, DataTable, Flex, Text } from "@alepha/ui";
|
|
12
|
+
import { AlephaUIAuth, AuthRouter } from "@alepha/ui/auth";
|
|
13
|
+
import { $inject, $module, t } from "alepha";
|
|
14
|
+
import { $page, ReactRouter, Redirection, useClient } from "@alepha/react";
|
|
15
|
+
import { ReactAuth } from "@alepha/react/auth";
|
|
16
|
+
import { IconBell, IconCheck, IconClock, IconDevices, IconFile, IconPlayerPlay, IconPlus, IconSettings, IconShieldCheck, IconUser, IconUsers, IconX } from "@tabler/icons-react";
|
|
17
|
+
import { $client } from "alepha/server/links";
|
|
18
|
+
import { useI18n } from "@alepha/react/i18n";
|
|
19
|
+
import { Badge, Stack } from "@mantine/core";
|
|
20
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
21
|
+
import { jobExecutions } from "alepha/api/jobs";
|
|
12
22
|
|
|
13
23
|
//#region src/admin/AdminRouter.ts
|
|
14
24
|
var AdminRouter = class {
|
|
15
|
-
|
|
25
|
+
router = $inject(ReactRouter);
|
|
26
|
+
authRouter = $inject(AuthRouter);
|
|
27
|
+
auth = $inject(ReactAuth);
|
|
28
|
+
userCtrl = $client();
|
|
29
|
+
sessionCtrl = $client();
|
|
30
|
+
notificationCtrl = $client();
|
|
31
|
+
fileCtrl = $client();
|
|
32
|
+
layout = $page({
|
|
33
|
+
name: "AdminLayout",
|
|
16
34
|
path: "/admin",
|
|
17
35
|
label: "Admin",
|
|
18
|
-
lazy: () => import("./AdminLayout-
|
|
36
|
+
lazy: () => import("./AdminLayout-qNsIyl30.js"),
|
|
37
|
+
resolve: ({ user, url }) => {
|
|
38
|
+
if (!user) throw new Redirection(this.router.path(this.authRouter.login.name, { query: { r: url.pathname } }));
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
19
41
|
});
|
|
20
42
|
adminUsers = $page({
|
|
21
|
-
|
|
43
|
+
icon: IconUsers,
|
|
44
|
+
parent: this.layout,
|
|
22
45
|
path: "/users",
|
|
23
46
|
label: "Users",
|
|
24
|
-
|
|
47
|
+
description: "Manage application users and their roles.",
|
|
48
|
+
lazy: () => import("./AdminUsers-Dd9a5UqO.js"),
|
|
49
|
+
can: () => this.userCtrl.findUsers.can()
|
|
25
50
|
});
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
51
|
+
adminUserCreate = $page({
|
|
52
|
+
icon: IconPlus,
|
|
53
|
+
parent: this.layout,
|
|
54
|
+
path: "/users/create",
|
|
55
|
+
label: "Create User",
|
|
56
|
+
description: "Create a new user account.",
|
|
57
|
+
lazy: () => import("./AdminUserCreate-DjiCcAk0.js"),
|
|
58
|
+
can: () => this.userCtrl.createUser.can()
|
|
31
59
|
});
|
|
32
|
-
|
|
33
|
-
|
|
60
|
+
adminUserLayout = $page({
|
|
61
|
+
icon: IconUser,
|
|
62
|
+
parent: this.layout,
|
|
63
|
+
path: "/users/:userId",
|
|
64
|
+
label: "User",
|
|
65
|
+
lazy: () => import("./AdminUserLayout-B8ga5QvP.js"),
|
|
66
|
+
can: () => this.userCtrl.getUser.can()
|
|
67
|
+
});
|
|
68
|
+
adminUserDetails = $page({
|
|
69
|
+
parent: this.adminUserLayout,
|
|
70
|
+
path: "/details",
|
|
71
|
+
label: "Details",
|
|
72
|
+
lazy: () => import("./AdminUserDetails-C5yeJNa3.js")
|
|
73
|
+
});
|
|
74
|
+
adminUserSessions = $page({
|
|
75
|
+
parent: this.adminUserLayout,
|
|
34
76
|
path: "/sessions",
|
|
35
77
|
label: "Sessions",
|
|
36
|
-
lazy: () => import("./
|
|
78
|
+
lazy: () => import("./AdminUserSessions-A_5KkqTY.js")
|
|
37
79
|
});
|
|
38
|
-
|
|
39
|
-
parent: this.
|
|
40
|
-
path: "/
|
|
41
|
-
label: "
|
|
42
|
-
lazy: () => import("./
|
|
80
|
+
adminUserSettings = $page({
|
|
81
|
+
parent: this.adminUserLayout,
|
|
82
|
+
path: "/settings",
|
|
83
|
+
label: "Settings",
|
|
84
|
+
lazy: () => import("./AdminUserSettings-DAsAhFjX.js")
|
|
43
85
|
});
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
86
|
+
adminSessions = $page({
|
|
87
|
+
icon: IconDevices,
|
|
88
|
+
parent: this.layout,
|
|
89
|
+
path: "/sessions",
|
|
90
|
+
label: "Sessions",
|
|
91
|
+
description: "View and manage all active sessions.",
|
|
92
|
+
lazy: () => import("./AdminSessions-Df2VYzlE.js"),
|
|
93
|
+
can: () => this.sessionCtrl.findSessions.can()
|
|
49
94
|
});
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
95
|
+
adminNotifications = $page({
|
|
96
|
+
icon: IconBell,
|
|
97
|
+
parent: this.layout,
|
|
98
|
+
path: "/notifications",
|
|
99
|
+
label: "Notifications",
|
|
100
|
+
description: "View notification history and status.",
|
|
101
|
+
lazy: () => import("./AdminNotifications-DV-35Fi3.js"),
|
|
102
|
+
can: () => this.notificationCtrl.findNotifications.can()
|
|
55
103
|
});
|
|
56
104
|
adminFiles = $page({
|
|
57
|
-
|
|
105
|
+
icon: IconFile,
|
|
106
|
+
parent: this.layout,
|
|
58
107
|
path: "/files",
|
|
59
108
|
label: "Files",
|
|
60
|
-
|
|
109
|
+
description: "Manage uploaded files and storage.",
|
|
110
|
+
lazy: () => import("./AdminFiles-DldZB7oo.js"),
|
|
111
|
+
can: () => this.fileCtrl.findFiles.can()
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/admin/MainRouter.ts
|
|
117
|
+
/**
|
|
118
|
+
* Main application router that combines Auth and Admin routers.
|
|
119
|
+
*
|
|
120
|
+
* We assume that the main application router will always have Admin and Auth routers.
|
|
121
|
+
*
|
|
122
|
+
* This is basically a convenience class to avoid having to inject these routers everywhere.
|
|
123
|
+
* Code is lightweight enough that we can just copy it if needed.
|
|
124
|
+
*/
|
|
125
|
+
var MainRouter = class {
|
|
126
|
+
auth = $inject(AuthRouter);
|
|
127
|
+
admin = $inject(AdminRouter);
|
|
128
|
+
layout = $page({
|
|
129
|
+
component: AlephaMantineProvider,
|
|
130
|
+
children: () => [this.auth.layout, this.admin.layout]
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
//#endregion
|
|
135
|
+
//#region src/admin/components/AdminJobs.tsx
|
|
136
|
+
const AdminJobs = () => {
|
|
137
|
+
const client = useClient();
|
|
138
|
+
const { l } = useI18n();
|
|
139
|
+
const filters = t.object({
|
|
140
|
+
job: t.optional(t.string({ $control: { query: t.pick(jobExecutions.schema, ["job"]) } })),
|
|
141
|
+
status: t.optional(t.enum([
|
|
142
|
+
"STARTED",
|
|
143
|
+
"FAILED",
|
|
144
|
+
"COMPLETED"
|
|
145
|
+
]))
|
|
146
|
+
});
|
|
147
|
+
const getStatusColor = (status) => {
|
|
148
|
+
switch (status) {
|
|
149
|
+
case "COMPLETED": return "green";
|
|
150
|
+
case "FAILED": return "red";
|
|
151
|
+
case "STARTED": return "blue";
|
|
152
|
+
default: return "gray";
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
const getStatusIcon = (status) => {
|
|
156
|
+
switch (status) {
|
|
157
|
+
case "COMPLETED": return /* @__PURE__ */ jsx(IconCheck, { size: 12 });
|
|
158
|
+
case "FAILED": return /* @__PURE__ */ jsx(IconX, { size: 12 });
|
|
159
|
+
case "STARTED": return /* @__PURE__ */ jsx(IconPlayerPlay, { size: 12 });
|
|
160
|
+
default: return /* @__PURE__ */ jsx(IconClock, { size: 12 });
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
const formatDuration = (start, end) => {
|
|
164
|
+
const startTime = new Date(start).getTime();
|
|
165
|
+
const duration = (end ? new Date(end).getTime() : Date.now()) - startTime;
|
|
166
|
+
if (duration < 1e3) return `${duration}ms`;
|
|
167
|
+
if (duration < 6e4) return `${(duration / 1e3).toFixed(1)}s`;
|
|
168
|
+
return `${Math.floor(duration / 6e4)}m ${Math.floor(duration % 6e4 / 1e3)}s`;
|
|
169
|
+
};
|
|
170
|
+
return /* @__PURE__ */ jsx(Flex, {
|
|
171
|
+
flex: 1,
|
|
172
|
+
children: /* @__PURE__ */ jsx(DataTable, {
|
|
173
|
+
submitOnInit: true,
|
|
174
|
+
defaultSize: 10,
|
|
175
|
+
typeFormProps: {
|
|
176
|
+
skipSubmitButton: true,
|
|
177
|
+
columns: 3
|
|
178
|
+
},
|
|
179
|
+
tableProps: {
|
|
180
|
+
horizontalSpacing: "xs",
|
|
181
|
+
verticalSpacing: "xs"
|
|
182
|
+
},
|
|
183
|
+
onFilterChange: (key, _value, form) => {
|
|
184
|
+
if (key === "job" || key === "status") return form.submit();
|
|
185
|
+
},
|
|
186
|
+
filters,
|
|
187
|
+
items: async (filters$1) => {
|
|
188
|
+
return await client.getJobExecutions({ query: filters$1 });
|
|
189
|
+
},
|
|
190
|
+
columns: {
|
|
191
|
+
job: {
|
|
192
|
+
label: "Job",
|
|
193
|
+
value: (item) => /* @__PURE__ */ jsx(Text, {
|
|
194
|
+
size: "sm",
|
|
195
|
+
fw: 500,
|
|
196
|
+
children: item.job
|
|
197
|
+
})
|
|
198
|
+
},
|
|
199
|
+
status: {
|
|
200
|
+
label: "Status",
|
|
201
|
+
fit: true,
|
|
202
|
+
value: (item) => /* @__PURE__ */ jsx(Badge, {
|
|
203
|
+
size: "sm",
|
|
204
|
+
variant: "light",
|
|
205
|
+
color: getStatusColor(item.status),
|
|
206
|
+
leftSection: getStatusIcon(item.status),
|
|
207
|
+
children: item.status
|
|
208
|
+
})
|
|
209
|
+
},
|
|
210
|
+
duration: {
|
|
211
|
+
label: "Duration",
|
|
212
|
+
fit: true,
|
|
213
|
+
value: (item) => /* @__PURE__ */ jsx(Text, {
|
|
214
|
+
size: "xs",
|
|
215
|
+
c: "dimmed",
|
|
216
|
+
ff: "monospace",
|
|
217
|
+
children: formatDuration(item.createdAt, item.finishedAt)
|
|
218
|
+
})
|
|
219
|
+
},
|
|
220
|
+
error: {
|
|
221
|
+
label: "Error",
|
|
222
|
+
value: (item) => item.error ? /* @__PURE__ */ jsx(Text, {
|
|
223
|
+
size: "xs",
|
|
224
|
+
c: "red",
|
|
225
|
+
lineClamp: 1,
|
|
226
|
+
children: item.error
|
|
227
|
+
}) : /* @__PURE__ */ jsx(Text, {
|
|
228
|
+
size: "xs",
|
|
229
|
+
c: "dimmed",
|
|
230
|
+
children: "-"
|
|
231
|
+
})
|
|
232
|
+
},
|
|
233
|
+
createdAt: {
|
|
234
|
+
label: "Started",
|
|
235
|
+
fit: true,
|
|
236
|
+
value: (item) => /* @__PURE__ */ jsx(Text, {
|
|
237
|
+
size: "xs",
|
|
238
|
+
c: "dimmed",
|
|
239
|
+
children: l(item.createdAt, { date: "fromNow" })
|
|
240
|
+
})
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
})
|
|
244
|
+
});
|
|
245
|
+
};
|
|
246
|
+
var AdminJobs_default = AdminJobs;
|
|
247
|
+
|
|
248
|
+
//#endregion
|
|
249
|
+
//#region src/admin/components/AdminParameters.tsx
|
|
250
|
+
const AdminParameters = () => {
|
|
251
|
+
return /* @__PURE__ */ jsx(Flex, {
|
|
252
|
+
flex: 1,
|
|
253
|
+
justify: "center",
|
|
254
|
+
align: "center",
|
|
255
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
256
|
+
align: "center",
|
|
257
|
+
gap: "xs",
|
|
258
|
+
children: [
|
|
259
|
+
/* @__PURE__ */ jsx(IconSettings, {
|
|
260
|
+
size: 48,
|
|
261
|
+
stroke: 1.5,
|
|
262
|
+
color: "var(--mantine-color-dimmed)"
|
|
263
|
+
}),
|
|
264
|
+
/* @__PURE__ */ jsx(Text, {
|
|
265
|
+
c: "dimmed",
|
|
266
|
+
children: "Parameter Management"
|
|
267
|
+
}),
|
|
268
|
+
/* @__PURE__ */ jsx(Text, {
|
|
269
|
+
size: "xs",
|
|
270
|
+
c: "dimmed",
|
|
271
|
+
ta: "center",
|
|
272
|
+
maw: 400,
|
|
273
|
+
children: "Application parameters and configuration settings. Define parameters using the $config primitive to manage dynamic application settings."
|
|
274
|
+
})
|
|
275
|
+
]
|
|
276
|
+
})
|
|
277
|
+
});
|
|
278
|
+
};
|
|
279
|
+
var AdminParameters_default = AdminParameters;
|
|
280
|
+
|
|
281
|
+
//#endregion
|
|
282
|
+
//#region src/admin/components/AdminVerifications.tsx
|
|
283
|
+
const AdminVerifications = () => {
|
|
284
|
+
return /* @__PURE__ */ jsx(Flex, {
|
|
285
|
+
flex: 1,
|
|
286
|
+
justify: "center",
|
|
287
|
+
align: "center",
|
|
288
|
+
children: /* @__PURE__ */ jsxs(Stack, {
|
|
289
|
+
align: "center",
|
|
290
|
+
gap: "xs",
|
|
291
|
+
children: [
|
|
292
|
+
/* @__PURE__ */ jsx(IconShieldCheck, {
|
|
293
|
+
size: 48,
|
|
294
|
+
stroke: 1.5,
|
|
295
|
+
color: "var(--mantine-color-dimmed)"
|
|
296
|
+
}),
|
|
297
|
+
/* @__PURE__ */ jsx(Text, {
|
|
298
|
+
c: "dimmed",
|
|
299
|
+
children: "Verification Management"
|
|
300
|
+
}),
|
|
301
|
+
/* @__PURE__ */ jsx(Text, {
|
|
302
|
+
size: "xs",
|
|
303
|
+
c: "dimmed",
|
|
304
|
+
ta: "center",
|
|
305
|
+
maw: 400,
|
|
306
|
+
children: "Verifications are automatically managed by the system. Email and SMS verification codes are generated and validated through the verification API endpoints."
|
|
307
|
+
})
|
|
308
|
+
]
|
|
309
|
+
})
|
|
61
310
|
});
|
|
62
311
|
};
|
|
312
|
+
var AdminVerifications_default = AdminVerifications;
|
|
63
313
|
|
|
64
314
|
//#endregion
|
|
65
315
|
//#region src/admin/index.ts
|
|
@@ -70,9 +320,17 @@ var AdminRouter = class {
|
|
|
70
320
|
*/
|
|
71
321
|
const AlephaUIAdmin = $module({
|
|
72
322
|
name: "alepha.ui.admin",
|
|
73
|
-
services: [
|
|
323
|
+
services: [
|
|
324
|
+
AlephaUI,
|
|
325
|
+
AlephaUIAuth,
|
|
326
|
+
AdminRouter,
|
|
327
|
+
MainRouter
|
|
328
|
+
],
|
|
329
|
+
register: (alepha) => {
|
|
330
|
+
alepha.with(AdminRouter);
|
|
331
|
+
}
|
|
74
332
|
});
|
|
75
333
|
|
|
76
334
|
//#endregion
|
|
77
|
-
export { AdminFiles_default as AdminFiles, AdminJobs_default as AdminJobs, AdminLayout_default as AdminLayout, AdminNotifications_default as AdminNotifications, AdminParameters_default as AdminParameters, AdminRouter, AdminSessions_default as AdminSessions, AdminUsers_default as AdminUsers, AdminVerifications_default as AdminVerifications, AlephaUIAdmin };
|
|
335
|
+
export { AdminFiles_default as AdminFiles, AdminJobs_default as AdminJobs, AdminLayout_default as AdminLayout, AdminNotifications_default as AdminNotifications, AdminParameters_default as AdminParameters, AdminRouter, AdminSessions_default as AdminSessions, AdminUserCreate_default as AdminUserCreate, AdminUserDetails_default as AdminUserDetails, AdminUserLayout_default as AdminUserLayout, AdminUserSessions_default as AdminUserSessions, AdminUserSettings_default as AdminUserSettings, AdminUsers_default as AdminUsers, AdminVerifications_default as AdminVerifications, AlephaUIAdmin, MainRouter };
|
|
78
336
|
//# sourceMappingURL=index.js.map
|
package/dist/admin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/admin/AdminRouter.ts","../../src/admin/index.ts"],"sourcesContent":["import { $page } from \"@alepha/react\";\n\nexport class AdminRouter {\n admin = $page({\n path: \"/admin\",\n label: \"Admin\",\n lazy: () => import(\"./components/AdminLayout.tsx\"),\n });\n\n adminUsers = $page({\n parent: this.admin,\n path: \"/users\",\n label: \"Users\",\n lazy: () => import(\"./components/AdminUsers.tsx\"),\n });\n\n adminNotifications = $page({\n parent: this.admin,\n path: \"/notifications\",\n label: \"Notifications\",\n lazy: () => import(\"./components/AdminNotifications.tsx\"),\n });\n\n adminSessions = $page({\n parent: this.admin,\n path: \"/sessions\",\n label: \"Sessions\",\n lazy: () => import(\"./components/AdminSessions.tsx\"),\n });\n\n adminVerifications = $page({\n parent: this.admin,\n path: \"/verifications\",\n label: \"Verifications\",\n lazy: () => import(\"./components/AdminVerifications.tsx\"),\n });\n\n adminJobs = $page({\n parent: this.admin,\n path: \"/jobs\",\n label: \"Jobs\",\n lazy: () => import(\"./components/AdminJobs.tsx\"),\n });\n\n adminParameters = $page({\n parent: this.admin,\n path: \"/parameters\",\n label: \"Parameters\",\n lazy: () => import(\"./components/AdminParameters.tsx\"),\n });\n\n adminFiles = $page({\n parent: this.admin,\n path: \"/files\",\n label: \"Files\",\n lazy: () => import(\"./components/AdminFiles.tsx\"),\n });\n}\n","import { AlephaUI } from \"@alepha/ui\";\nimport { $module } from \"alepha\";\nimport { AdminRouter } from \"./AdminRouter.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport { AdminRouter } from \"./AdminRouter.ts\";\nexport { default as AdminFiles } from \"./components/AdminFiles.tsx\";\nexport { default as AdminJobs } from \"./components/AdminJobs.tsx\";\nexport { default as AdminLayout } from \"./components/AdminLayout.tsx\";\nexport { default as AdminNotifications } from \"./components/AdminNotifications.tsx\";\nexport { default as AdminParameters } from \"./components/AdminParameters.tsx\";\nexport type { AdminSessionsProps } from \"./components/AdminSessions.tsx\";\nexport { default as AdminSessions } from \"./components/AdminSessions.tsx\";\nexport type { AdminUsersProps } from \"./components/AdminUsers.tsx\";\nexport { default as AdminUsers } from \"./components/AdminUsers.tsx\";\nexport { default as AdminVerifications } from \"./components/AdminVerifications.tsx\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Admin panel UI Module\n *\n * @module alepha.ui.admin\n */\nexport const AlephaUIAdmin = $module({\n name: \"alepha.ui.admin\",\n services: [AlephaUI, AdminRouter],\n});\n"],"mappings":";;;;;;;;;;;;;AAEA,IAAa,cAAb,MAAyB;CACvB,QAAQ,MAAM;EACZ,MAAM;EACN,OAAO;EACP,YAAY,OAAO;EACpB,CAAC;CAEF,aAAa,MAAM;EACjB,QAAQ,KAAK;EACb,MAAM;EACN,OAAO;EACP,YAAY,OAAO;EACpB,CAAC;CAEF,qBAAqB,MAAM;EACzB,QAAQ,KAAK;EACb,MAAM;EACN,OAAO;EACP,YAAY,OAAO;EACpB,CAAC;CAEF,gBAAgB,MAAM;EACpB,QAAQ,KAAK;EACb,MAAM;EACN,OAAO;EACP,YAAY,OAAO;EACpB,CAAC;CAEF,qBAAqB,MAAM;EACzB,QAAQ,KAAK;EACb,MAAM;EACN,OAAO;EACP,YAAY,OAAO;EACpB,CAAC;CAEF,YAAY,MAAM;EAChB,QAAQ,KAAK;EACb,MAAM;EACN,OAAO;EACP,YAAY,OAAO;EACpB,CAAC;CAEF,kBAAkB,MAAM;EACtB,QAAQ,KAAK;EACb,MAAM;EACN,OAAO;EACP,YAAY,OAAO;EACpB,CAAC;CAEF,aAAa,MAAM;EACjB,QAAQ,KAAK;EACb,MAAM;EACN,OAAO;EACP,YAAY,OAAO;EACpB,CAAC;;;;;;;;;;AC/BJ,MAAa,gBAAgB,QAAQ;CACnC,MAAM;CACN,UAAU,CAAC,UAAU,YAAY;CAClC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["filters"],"sources":["../../src/admin/AdminRouter.ts","../../src/admin/MainRouter.ts","../../src/admin/components/AdminJobs.tsx","../../src/admin/components/AdminParameters.tsx","../../src/admin/components/AdminVerifications.tsx","../../src/admin/index.ts"],"sourcesContent":["import { $page, ReactRouter, Redirection } from \"@alepha/react\";\nimport { ReactAuth } from \"@alepha/react/auth\";\nimport { AuthRouter } from \"@alepha/ui/auth\";\nimport {\n IconBell,\n IconDevices,\n IconFile,\n IconPlus,\n IconUser,\n IconUsers,\n} from \"@tabler/icons-react\";\nimport { $inject } from \"alepha\";\nimport type { FileController } from \"alepha/api/files\";\nimport type { NotificationController } from \"alepha/api/notifications\";\nimport type { SessionController, UserController } from \"alepha/api/users\";\nimport { $client } from \"alepha/server/links\";\n\nexport class AdminRouter {\n protected readonly router = $inject(ReactRouter);\n protected readonly authRouter = $inject(AuthRouter);\n protected readonly auth = $inject(ReactAuth);\n protected readonly userCtrl = $client<UserController>();\n protected readonly sessionCtrl = $client<SessionController>();\n protected readonly notificationCtrl = $client<NotificationController>();\n protected readonly fileCtrl = $client<FileController>();\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Layout\n // ─────────────────────────────────────────────────────────────────────────────\n\n public readonly layout = $page({\n name: \"AdminLayout\",\n path: \"/admin\",\n label: \"Admin\",\n lazy: () => import(\"./components/AdminLayout.tsx\"),\n resolve: ({ user, url }) => {\n if (!user) {\n throw new Redirection(\n this.router.path(this.authRouter.login.name, {\n query: {\n r: url.pathname,\n },\n }),\n );\n }\n return {};\n },\n });\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Users\n // ─────────────────────────────────────────────────────────────────────────────\n\n public readonly adminUsers = $page({\n icon: IconUsers,\n parent: this.layout,\n path: \"/users\",\n label: \"Users\",\n description: \"Manage application users and their roles.\",\n lazy: () => import(\"./components/AdminUsers.tsx\"),\n can: () => this.userCtrl.findUsers.can(),\n });\n\n public readonly adminUserCreate = $page({\n icon: IconPlus,\n parent: this.layout,\n path: \"/users/create\",\n label: \"Create User\",\n description: \"Create a new user account.\",\n lazy: () => import(\"./components/AdminUserCreate.tsx\"),\n can: () => this.userCtrl.createUser.can(),\n });\n\n public readonly adminUserLayout = $page({\n icon: IconUser,\n parent: this.layout,\n path: \"/users/:userId\",\n label: \"User\",\n lazy: () => import(\"./components/AdminUserLayout.tsx\"),\n can: () => this.userCtrl.getUser.can(),\n });\n\n public readonly adminUserDetails = $page({\n parent: this.adminUserLayout,\n path: \"/details\",\n label: \"Details\",\n lazy: () => import(\"./components/AdminUserDetails.tsx\"),\n });\n\n public readonly adminUserSessions = $page({\n parent: this.adminUserLayout,\n path: \"/sessions\",\n label: \"Sessions\",\n lazy: () => import(\"./components/AdminUserSessions.tsx\"),\n });\n\n public readonly adminUserSettings = $page({\n parent: this.adminUserLayout,\n path: \"/settings\",\n label: \"Settings\",\n lazy: () => import(\"./components/AdminUserSettings.tsx\"),\n });\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Sessions\n // ─────────────────────────────────────────────────────────────────────────────\n\n public readonly adminSessions = $page({\n icon: IconDevices,\n parent: this.layout,\n path: \"/sessions\",\n label: \"Sessions\",\n description: \"View and manage all active sessions.\",\n lazy: () => import(\"./components/AdminSessions.tsx\"),\n can: () => this.sessionCtrl.findSessions.can(),\n });\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Notifications\n // ─────────────────────────────────────────────────────────────────────────────\n\n public readonly adminNotifications = $page({\n icon: IconBell,\n parent: this.layout,\n path: \"/notifications\",\n label: \"Notifications\",\n description: \"View notification history and status.\",\n lazy: () => import(\"./components/AdminNotifications.tsx\"),\n can: () => this.notificationCtrl.findNotifications.can(),\n });\n\n // ─────────────────────────────────────────────────────────────────────────────\n // Files\n // ─────────────────────────────────────────────────────────────────────────────\n\n public readonly adminFiles = $page({\n icon: IconFile,\n parent: this.layout,\n path: \"/files\",\n label: \"Files\",\n description: \"Manage uploaded files and storage.\",\n lazy: () => import(\"./components/AdminFiles.tsx\"),\n can: () => this.fileCtrl.findFiles.can(),\n });\n}\n","import { $page } from \"@alepha/react\";\nimport { AlephaMantineProvider } from \"@alepha/ui\";\nimport { AuthRouter } from \"@alepha/ui/auth\";\nimport { $inject } from \"alepha\";\nimport { AdminRouter } from \"./AdminRouter.ts\";\n\n/**\n * Main application router that combines Auth and Admin routers.\n *\n * We assume that the main application router will always have Admin and Auth routers.\n *\n * This is basically a convenience class to avoid having to inject these routers everywhere.\n * Code is lightweight enough that we can just copy it if needed.\n */\nexport class MainRouter {\n auth = $inject(AuthRouter);\n admin = $inject(AdminRouter);\n\n layout = $page({\n component: AlephaMantineProvider,\n children: () => [this.auth.layout, this.admin.layout],\n });\n}\n","import { useClient } from \"@alepha/react\";\nimport { useI18n } from \"@alepha/react/i18n\";\nimport { DataTable, Flex, Text } from \"@alepha/ui\";\nimport { Badge } from \"@mantine/core\";\nimport {\n IconCheck,\n IconClock,\n IconPlayerPlay,\n IconX,\n} from \"@tabler/icons-react\";\nimport { type Page, t } from \"alepha\";\nimport {\n type JobController,\n type JobExecutionEntity,\n jobExecutions,\n} from \"alepha/api/jobs\";\n\nconst AdminJobs = () => {\n const client = useClient<JobController>();\n const { l } = useI18n();\n\n const filters = t.object({\n job: t.optional(\n t.string({\n $control: {\n query: t.pick(jobExecutions.schema, [\"job\"]),\n },\n }),\n ),\n status: t.optional(t.enum([\"STARTED\", \"FAILED\", \"COMPLETED\"])),\n });\n\n const getStatusColor = (status: string) => {\n switch (status) {\n case \"COMPLETED\":\n return \"green\";\n case \"FAILED\":\n return \"red\";\n case \"STARTED\":\n return \"blue\";\n default:\n return \"gray\";\n }\n };\n\n const getStatusIcon = (status: string) => {\n switch (status) {\n case \"COMPLETED\":\n return <IconCheck size={12} />;\n case \"FAILED\":\n return <IconX size={12} />;\n case \"STARTED\":\n return <IconPlayerPlay size={12} />;\n default:\n return <IconClock size={12} />;\n }\n };\n\n const formatDuration = (\n start: Date | string,\n end?: Date | string | null,\n ): string => {\n const startTime = new Date(start).getTime();\n const endTime = end ? new Date(end).getTime() : Date.now();\n const duration = endTime - startTime;\n\n if (duration < 1000) return `${duration}ms`;\n if (duration < 60000) return `${(duration / 1000).toFixed(1)}s`;\n return `${Math.floor(duration / 60000)}m ${Math.floor((duration % 60000) / 1000)}s`;\n };\n\n return (\n <Flex flex={1}>\n <DataTable<JobExecutionEntity, typeof filters>\n submitOnInit\n defaultSize={10}\n typeFormProps={{\n skipSubmitButton: true,\n columns: 3,\n }}\n tableProps={{\n horizontalSpacing: \"xs\",\n verticalSpacing: \"xs\",\n }}\n onFilterChange={(key, _value, form) => {\n if (key === \"job\" || key === \"status\") {\n return form.submit();\n }\n }}\n filters={filters}\n items={async (filters) => {\n const response = await client.getJobExecutions({\n query: filters,\n });\n\n return response as Page<JobExecutionEntity>;\n }}\n columns={{\n job: {\n label: \"Job\",\n value: (item) => (\n <Text size=\"sm\" fw={500}>\n {item.job}\n </Text>\n ),\n },\n status: {\n label: \"Status\",\n fit: true,\n value: (item) => (\n <Badge\n size=\"sm\"\n variant=\"light\"\n color={getStatusColor(item.status)}\n leftSection={getStatusIcon(item.status)}\n >\n {item.status}\n </Badge>\n ),\n },\n duration: {\n label: \"Duration\",\n fit: true,\n value: (item) => (\n <Text size=\"xs\" c=\"dimmed\" ff=\"monospace\">\n {formatDuration(item.createdAt, item.finishedAt)}\n </Text>\n ),\n },\n error: {\n label: \"Error\",\n value: (item) =>\n item.error ? (\n <Text size=\"xs\" c=\"red\" lineClamp={1}>\n {item.error}\n </Text>\n ) : (\n <Text size=\"xs\" c=\"dimmed\">\n -\n </Text>\n ),\n },\n createdAt: {\n label: \"Started\",\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 AdminJobs;\n","import { Flex, Text } from \"@alepha/ui\";\nimport { Stack } from \"@mantine/core\";\nimport { IconSettings } from \"@tabler/icons-react\";\n\nconst AdminParameters = () => {\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Stack align=\"center\" gap=\"xs\">\n <IconSettings\n size={48}\n stroke={1.5}\n color=\"var(--mantine-color-dimmed)\"\n />\n <Text c=\"dimmed\">Parameter Management</Text>\n <Text size=\"xs\" c=\"dimmed\" ta=\"center\" maw={400}>\n Application parameters and configuration settings. Define parameters\n using the $config primitive to manage dynamic application settings.\n </Text>\n </Stack>\n </Flex>\n );\n};\n\nexport default AdminParameters;\n","import { Flex, Text } from \"@alepha/ui\";\nimport { Stack } from \"@mantine/core\";\nimport { IconShieldCheck } from \"@tabler/icons-react\";\n\nconst AdminVerifications = () => {\n return (\n <Flex flex={1} justify=\"center\" align=\"center\">\n <Stack align=\"center\" gap=\"xs\">\n <IconShieldCheck\n size={48}\n stroke={1.5}\n color=\"var(--mantine-color-dimmed)\"\n />\n <Text c=\"dimmed\">Verification Management</Text>\n <Text size=\"xs\" c=\"dimmed\" ta=\"center\" maw={400}>\n Verifications are automatically managed by the system. Email and SMS\n verification codes are generated and validated through the\n verification API endpoints.\n </Text>\n </Stack>\n </Flex>\n );\n};\n\nexport default AdminVerifications;\n","import { AlephaUI } from \"@alepha/ui\";\nimport { AlephaUIAuth } from \"@alepha/ui/auth\";\nimport { $module } from \"alepha\";\nimport { AdminRouter } from \"./AdminRouter.ts\";\nimport { MainRouter } from \"./MainRouter.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport { AdminRouter } from \"./AdminRouter.ts\";\nexport { default as AdminFiles } from \"./components/AdminFiles.tsx\";\nexport { default as AdminJobs } from \"./components/AdminJobs.tsx\";\nexport { default as AdminLayout } from \"./components/AdminLayout.tsx\";\nexport { default as AdminNotifications } from \"./components/AdminNotifications.tsx\";\nexport { default as AdminParameters } from \"./components/AdminParameters.tsx\";\nexport { default as AdminSessions } from \"./components/AdminSessions.tsx\";\nexport { default as AdminUserCreate } from \"./components/AdminUserCreate.tsx\";\nexport { default as AdminUserDetails } from \"./components/AdminUserDetails.tsx\";\nexport { default as AdminUserLayout } from \"./components/AdminUserLayout.tsx\";\nexport { default as AdminUserSessions } from \"./components/AdminUserSessions.tsx\";\nexport { default as AdminUserSettings } from \"./components/AdminUserSettings.tsx\";\nexport { default as AdminUsers } from \"./components/AdminUsers.tsx\";\nexport { default as AdminVerifications } from \"./components/AdminVerifications.tsx\";\nexport { MainRouter } from \"./MainRouter.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Admin panel UI Module\n *\n * @module alepha.ui.admin\n */\nexport const AlephaUIAdmin = $module({\n name: \"alepha.ui.admin\",\n services: [AlephaUI, AlephaUIAuth, AdminRouter, MainRouter],\n register: (alepha) => {\n alepha.with(AdminRouter);\n },\n});\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { NestedView } from "@alepha/react";
|
|
2
|
+
import { Flex } from "@mantine/core";
|
|
3
|
+
import { jsx } from "react/jsx-runtime";
|
|
4
|
+
|
|
5
|
+
//#region src/auth/components/AuthLayout.tsx
|
|
6
|
+
const AuthLayout = () => {
|
|
7
|
+
return /* @__PURE__ */ jsx(Flex, {
|
|
8
|
+
flex: 1,
|
|
9
|
+
align: "center",
|
|
10
|
+
h: "100vh",
|
|
11
|
+
justify: "center",
|
|
12
|
+
children: /* @__PURE__ */ jsx(NestedView, {})
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
var AuthLayout_default = AuthLayout;
|
|
16
|
+
|
|
17
|
+
//#endregion
|
|
18
|
+
export { AuthLayout_default as default };
|
|
19
|
+
//# sourceMappingURL=AuthLayout-BSL8ZHgr.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AuthLayout-BSL8ZHgr.js","names":[],"sources":["../../src/auth/components/AuthLayout.tsx"],"sourcesContent":["import { NestedView } from \"@alepha/react\";\nimport { Flex } from \"@mantine/core\";\n\nconst AuthLayout = () => {\n return (\n <Flex flex={1} align={\"center\"} h={\"100vh\"} justify={\"center\"}>\n <NestedView />\n </Flex>\n );\n};\n\nexport default AuthLayout;\n"],"mappings":";;;;;AAGA,MAAM,mBAAmB;AACvB,QACE,oBAAC;EAAK,MAAM;EAAG,OAAO;EAAU,GAAG;EAAS,SAAS;YACnD,oBAAC,eAAa;GACT;;AAIX,yBAAe"}
|
|
@@ -4,8 +4,8 @@ import { useI18n } from "@alepha/react/i18n";
|
|
|
4
4
|
import { ActionButton, Control, capitalize } from "@alepha/ui";
|
|
5
5
|
import { t } from "alepha";
|
|
6
6
|
import { useRouter } from "@alepha/react";
|
|
7
|
-
import { Card, Flex, Group, Stack, Text } from "@mantine/core";
|
|
8
7
|
import { IconLock, IconUser } from "@tabler/icons-react";
|
|
8
|
+
import { Card, Flex, Group, Stack, Text } from "@mantine/core";
|
|
9
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import { FormValidationError, useForm } from "@alepha/react/form";
|
|
11
11
|
import { HttpError } from "alepha/server";
|
|
@@ -16,7 +16,7 @@ const Login = (props) => {
|
|
|
16
16
|
const auth = useAuth();
|
|
17
17
|
const router = useRouter();
|
|
18
18
|
const { tr } = useI18n();
|
|
19
|
-
const redirect = router.query.
|
|
19
|
+
const redirect = router.query.r || "/";
|
|
20
20
|
const hasUsernamePassword = props.realmConfig.authenticationMethods.find((it) => it.type === "CREDENTIALS");
|
|
21
21
|
const settings = props.realmConfig.settings;
|
|
22
22
|
const loginMethods = useMemo(() => {
|
|
@@ -95,6 +95,7 @@ const Login = (props) => {
|
|
|
95
95
|
password: { autoComplete: "current-password" }
|
|
96
96
|
}),
|
|
97
97
|
/* @__PURE__ */ jsx(ActionButton, {
|
|
98
|
+
color: "blue",
|
|
98
99
|
variant: "filled",
|
|
99
100
|
form,
|
|
100
101
|
children: tr("loginSignIn")
|
|
@@ -142,7 +143,7 @@ const Login = (props) => {
|
|
|
142
143
|
children: tr("loginContinueWith", { args: [capitalize(method.name)] })
|
|
143
144
|
}, method.type))
|
|
144
145
|
}),
|
|
145
|
-
/* @__PURE__ */ jsxs(Text, {
|
|
146
|
+
settings.registrationAllowed && /* @__PURE__ */ jsxs(Text, {
|
|
146
147
|
size: "sm",
|
|
147
148
|
ta: "center",
|
|
148
149
|
children: [
|
|
@@ -173,4 +174,4 @@ const leftSection = (name) => {
|
|
|
173
174
|
|
|
174
175
|
//#endregion
|
|
175
176
|
export { Login_default as t };
|
|
176
|
-
//# sourceMappingURL=Login-
|
|
177
|
+
//# sourceMappingURL=Login-kBfaRgKG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Login-kBfaRgKG.js","names":["IconGoogle","IconGithub"],"sources":["../../src/auth/components/Login.tsx"],"sourcesContent":["import { useRouter } from \"@alepha/react\";\nimport { useAuth } from \"@alepha/react/auth\";\nimport { FormValidationError, useForm } from \"@alepha/react/form\";\nimport { useI18n } from \"@alepha/react/i18n\";\nimport { ActionButton, Control, capitalize } from \"@alepha/ui\";\nimport { Card, Flex, Group, Stack, Text } from \"@mantine/core\";\nimport { IconLock, IconUser } from \"@tabler/icons-react\";\nimport { t } from \"alepha\";\nimport type { UserRealmConfig } from \"alepha/api/users\";\nimport { HttpError } from \"alepha/server\";\nimport { useMemo } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\nimport type { AuthRouter } from \"../AuthRouter.ts\";\nimport IconGithub from \"./icons/IconGithub.tsx\";\nimport IconGoogle from \"./icons/IconGoogle.tsx\";\n\nexport interface LoginProps {\n realmConfig: UserRealmConfig;\n}\n\nconst Login = (props: LoginProps) => {\n const auth = useAuth();\n const router = useRouter<AuthRouter>();\n const { tr } = useI18n<AuthI18n, \"en\">();\n const redirect = router.query.r || \"/\";\n\n const hasUsernamePassword = props.realmConfig.authenticationMethods.find(\n (it) => it.type === \"CREDENTIALS\",\n );\n\n const settings = props.realmConfig.settings;\n\n // Determine what login methods are available\n const loginMethods = useMemo(() => {\n const methods = [];\n if (settings.usernameEnabled !== false) methods.push(\"username\");\n if (settings.emailEnabled !== false) methods.push(\"email\");\n if (settings.phoneEnabled === true) methods.push(\"phone\");\n return methods;\n }, [settings]);\n\n // Create identifier title based on enabled methods\n const identifierTitle = useMemo(() => {\n if (loginMethods.length === 0) return tr(\"loginUsername\");\n if (loginMethods.length === 1) {\n if (loginMethods[0] === \"username\") return tr(\"loginUsername\");\n if (loginMethods[0] === \"email\") return tr(\"loginEmail\");\n if (loginMethods[0] === \"phone\") return tr(\"loginPhone\");\n }\n const labels = loginMethods.map((m) => {\n if (m === \"username\") return tr(\"loginUsername\").toLowerCase();\n if (m === \"email\") return tr(\"loginEmail\").toLowerCase();\n if (m === \"phone\") return tr(\"loginPhone\").toLowerCase();\n return m;\n });\n return capitalize(\n `${labels.slice(0, -1).join(\", \")} or ${labels[labels.length - 1]}`,\n );\n }, [loginMethods, tr]);\n\n const form = useForm({\n schema: t.object({\n identifier: t.string({\n minLength: 1,\n }),\n password: t.string({\n minLength: settings.passwordPolicy?.minLength || 6,\n }),\n }),\n handler: async (data) => {\n try {\n await auth.login(\"credentials\", {\n username: data.identifier,\n password: data.password,\n });\n await router.go(router.query.r || \"/\");\n } catch (error) {\n if (\n error instanceof HttpError &&\n error.error === \"InvalidCredentialsError\"\n ) {\n throw new FormValidationError({\n message: \"Invalid identifier or password\",\n path: \"/password\",\n });\n }\n throw error;\n }\n },\n });\n\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Stack gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n <Stack gap={\"md\"}>\n {hasUsernamePassword && (\n <>\n <form {...form.props}>\n <Stack flex={1} gap={\"md\"}>\n <Control\n title={identifierTitle}\n input={form.input.identifier}\n icon={IconUser}\n text={{\n autoComplete: loginMethods.includes(\"email\")\n ? \"email\"\n : \"username\",\n }}\n />\n <Control\n title={tr(\"loginPassword\")}\n input={form.input.password}\n icon={IconLock}\n password={{\n autoComplete: \"current-password\",\n }}\n />\n <ActionButton color={\"blue\"} variant={\"filled\"} form={form}>\n {tr(\"loginSignIn\")}\n </ActionButton>\n </Stack>\n </form>\n <Stack gap=\"xs\">\n {settings.resetPasswordAllowed && (\n <Text size=\"sm\" ta=\"center\">\n <ActionButton\n href={router.path(\"resetPassword\")}\n anchorProps={{ inherit: true }}\n >\n {tr(\"loginForgotPassword\")}\n </ActionButton>\n </Text>\n )}\n <Group align=\"center\" justify=\"center\" gap={\"md\"}>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-text-muted)\"} />\n <Text size=\"xs\">{tr(\"loginOr\")}</Text>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-text-muted)\"} />\n </Group>\n </Stack>\n </>\n )}\n <Stack gap={\"sm\"}>\n {props.realmConfig.authenticationMethods.map(\n (method) =>\n method.type !== \"CREDENTIALS\" && (\n <ActionButton\n variant={\"default\"}\n key={method.type}\n leftSection={leftSection(method.name.toLowerCase())}\n onClick={() =>\n auth.login(method.name, {\n redirect,\n })\n }\n >\n {tr(\"loginContinueWith\", {\n args: [capitalize(method.name)],\n })}\n </ActionButton>\n ),\n )}\n </Stack>\n {settings.registrationAllowed && (\n <Text size=\"sm\" ta=\"center\">\n {tr(\"loginNoAccount\")}{\" \"}\n <ActionButton\n href={router.path(\"register\")}\n anchorProps={{ inherit: true }}\n >\n {tr(\"loginSignUp\")}\n </ActionButton>\n </Text>\n )}\n </Stack>\n </Card>\n <ActionButton variant={\"subtle\"} href={redirect}>\n {tr(\"loginCancel\")}\n </ActionButton>\n </Stack>\n </Flex>\n );\n};\n\nexport default Login;\n\nconst leftSection = (name: string) => {\n if (name === \"google\") {\n return <IconGoogle />;\n }\n\n if (name === \"github\") {\n return <IconGithub />;\n }\n};\n"],"mappings":"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"}
|
|
@@ -4,8 +4,8 @@ import { useI18n } from "@alepha/react/i18n";
|
|
|
4
4
|
import { ActionButton, Control, capitalize } from "@alepha/ui";
|
|
5
5
|
import { TypeBoxError, t } from "alepha";
|
|
6
6
|
import { useClient, useRouter } from "@alepha/react";
|
|
7
|
-
import { Alert, Card, Flex, Group, PinInput, Stack, Text } from "@mantine/core";
|
|
8
7
|
import { IconAlertCircle, IconLock, IconMail, IconPhone, IconUser } from "@tabler/icons-react";
|
|
8
|
+
import { Alert, Card, Flex, Group, PinInput, Stack, Text } from "@mantine/core";
|
|
9
9
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
10
|
import { useForm } from "@alepha/react/form";
|
|
11
11
|
import { useMemo, useState } from "react";
|
|
@@ -16,7 +16,7 @@ const Register = (props) => {
|
|
|
16
16
|
const userCtrl = useClient();
|
|
17
17
|
const router = useRouter();
|
|
18
18
|
const { tr } = useI18n();
|
|
19
|
-
const redirect = router.query.
|
|
19
|
+
const redirect = router.query.r || "/";
|
|
20
20
|
const [registrationState, setRegistrationState] = useState({ phase: "form" });
|
|
21
21
|
const [emailCode, setEmailCode] = useState("");
|
|
22
22
|
const [phoneCode, setPhoneCode] = useState("");
|
|
@@ -141,7 +141,7 @@ const Register = (props) => {
|
|
|
141
141
|
children: [/* @__PURE__ */ jsx(Text, {
|
|
142
142
|
size: "sm",
|
|
143
143
|
fw: 500,
|
|
144
|
-
children: tr("registerEmailCode")
|
|
144
|
+
children: tr("registerEmailCode")
|
|
145
145
|
}), /* @__PURE__ */ jsx(Flex, {
|
|
146
146
|
justify: "center",
|
|
147
147
|
children: /* @__PURE__ */ jsx(PinInput, {
|
|
@@ -159,7 +159,7 @@ const Register = (props) => {
|
|
|
159
159
|
children: [/* @__PURE__ */ jsx(Text, {
|
|
160
160
|
size: "sm",
|
|
161
161
|
fw: 500,
|
|
162
|
-
children: tr("registerPhoneCode")
|
|
162
|
+
children: tr("registerPhoneCode")
|
|
163
163
|
}), /* @__PURE__ */ jsx(Flex, {
|
|
164
164
|
justify: "center",
|
|
165
165
|
children: /* @__PURE__ */ jsx(PinInput, {
|
|
@@ -173,10 +173,11 @@ const Register = (props) => {
|
|
|
173
173
|
})]
|
|
174
174
|
}),
|
|
175
175
|
/* @__PURE__ */ jsx(ActionButton, {
|
|
176
|
+
color: "blue",
|
|
176
177
|
onClick: handleVerificationSubmit,
|
|
177
178
|
loading: isSubmitting,
|
|
178
179
|
disabled: !canSubmitVerification(),
|
|
179
|
-
children: tr("registerVerifySubmit")
|
|
180
|
+
children: tr("registerVerifySubmit")
|
|
180
181
|
}),
|
|
181
182
|
/* @__PURE__ */ jsx(ActionButton, {
|
|
182
183
|
variant: "subtle",
|
|
@@ -253,6 +254,8 @@ const Register = (props) => {
|
|
|
253
254
|
}),
|
|
254
255
|
/* @__PURE__ */ jsx(ActionButton, {
|
|
255
256
|
form,
|
|
257
|
+
color: "blue",
|
|
258
|
+
variant: "filled",
|
|
256
259
|
children: tr("registerCreateAccount")
|
|
257
260
|
})
|
|
258
261
|
]
|
|
@@ -315,4 +318,4 @@ const leftSection = (name) => {
|
|
|
315
318
|
|
|
316
319
|
//#endregion
|
|
317
320
|
export { Register_default as t };
|
|
318
|
-
//# sourceMappingURL=Register-
|
|
321
|
+
//# sourceMappingURL=Register-BxJmOqpF.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Register-BxJmOqpF.js","names":["IconGoogle","IconGithub"],"sources":["../../src/auth/components/Register.tsx"],"sourcesContent":["import { useClient, useRouter } from \"@alepha/react\";\nimport { useAuth } from \"@alepha/react/auth\";\nimport { useForm } from \"@alepha/react/form\";\nimport { useI18n } from \"@alepha/react/i18n\";\nimport { ActionButton, Control, capitalize } from \"@alepha/ui\";\nimport { Alert, Card, Flex, Group, PinInput, Stack, Text } from \"@mantine/core\";\nimport {\n IconAlertCircle,\n IconLock,\n IconMail,\n IconPhone,\n IconUser,\n} from \"@tabler/icons-react\";\nimport { TypeBoxError, t } from \"alepha\";\nimport type {\n RegistrationIntentResponse,\n UserController,\n UserRealmConfig,\n} from \"alepha/api/users\";\nimport { useMemo, useState } from \"react\";\nimport type { AuthI18n } from \"../AuthI18n.ts\";\nimport type { AuthRouter } from \"../AuthRouter.ts\";\nimport IconGithub from \"./icons/IconGithub.tsx\";\nimport IconGoogle from \"./icons/IconGoogle.tsx\";\n\nexport interface RegisterProps {\n realmConfig: UserRealmConfig;\n}\n\ntype RegistrationPhase = \"form\" | \"verification\";\n\ninterface RegistrationState {\n phase: RegistrationPhase;\n intent?: RegistrationIntentResponse;\n credentials?: {\n identifier: string;\n password: string;\n };\n}\n\nconst Register = (props: RegisterProps) => {\n const auth = useAuth();\n const userCtrl = useClient<UserController>();\n const router = useRouter<AuthRouter>();\n const { tr } = useI18n<AuthI18n, \"en\">();\n const redirect = router.query.r || \"/\";\n\n const [registrationState, setRegistrationState] = useState<RegistrationState>(\n {\n phase: \"form\",\n },\n );\n const [emailCode, setEmailCode] = useState(\"\");\n const [phoneCode, setPhoneCode] = useState(\"\");\n const [verificationError, setVerificationError] = useState<string | null>(\n null,\n );\n const [isSubmitting, setIsSubmitting] = useState(false);\n\n const hasUsernamePassword = props.realmConfig.authenticationMethods.find(\n (it) => it.type === \"CREDENTIALS\",\n );\n\n const settings = props.realmConfig.settings || {};\n const isRegistrationAllowed = settings.registrationAllowed !== false;\n\n const registerSchema = useMemo(() => {\n const registerSchema = t.object({\n username: t.optional(t.text()),\n email: t.optional(t.email()),\n phoneNumber: t.optional(t.e164()),\n password: t.string({ minLength: 8 }),\n confirmPassword: t.string({ minLength: 8 }),\n });\n\n const required = registerSchema.required as string[];\n\n if (settings.usernameRequired) required.push(\"username\");\n if (settings.emailRequired) required.push(\"email\");\n if (settings.phoneRequired) required.push(\"phoneNumber\");\n\n return registerSchema;\n }, []);\n\n const form = useForm({\n schema: registerSchema,\n handler: async (data) => {\n if (data.password !== data.confirmPassword) {\n throw new TypeBoxError({\n message: \"Passwords do not match\",\n instancePath: \"/confirmPassword\",\n keyword: \"not\",\n schemaPath: \"\",\n params: {},\n });\n }\n\n // Phase 1: Create registration intent\n const intent = await userCtrl.createRegistrationIntent({\n body: {\n username: data.username,\n email: data.email,\n phoneNumber: data.phoneNumber,\n password: data.password,\n },\n });\n\n const identifier = data.username ?? data.email ?? data.phoneNumber;\n\n // Check if verification is needed\n if (\n intent.expectEmailVerification ||\n intent.expectPhoneVerification ||\n intent.expectCaptcha\n ) {\n // Move to verification phase\n setRegistrationState({\n phase: \"verification\",\n intent,\n credentials: identifier\n ? { identifier, password: data.password }\n : undefined,\n });\n return;\n }\n\n // No verification needed - complete registration immediately\n await userCtrl.createUserFromIntent({\n body: { intentId: intent.intentId },\n });\n\n // Auto-login after registration\n if (identifier) {\n await auth.login(\"credentials\", {\n username: identifier,\n password: data.password,\n });\n }\n\n await router.go(router.query.r || \"/\");\n },\n });\n\n const handleVerificationSubmit = async () => {\n if (!registrationState.intent) return;\n\n setIsSubmitting(true);\n setVerificationError(null);\n\n try {\n // Phase 2: Complete registration with verification codes\n await userCtrl.createUserFromIntent({\n body: {\n intentId: registrationState.intent.intentId,\n emailCode: registrationState.intent.expectEmailVerification\n ? emailCode\n : undefined,\n phoneCode: registrationState.intent.expectPhoneVerification\n ? phoneCode\n : undefined,\n },\n });\n\n // Auto-login after registration\n if (registrationState.credentials) {\n await auth.login(\"credentials\", {\n username: registrationState.credentials.identifier,\n password: registrationState.credentials.password,\n });\n }\n\n await router.go(router.query.r || \"/\");\n } catch (error) {\n setVerificationError(\n error instanceof Error ? error.message : \"Verification failed\",\n );\n } finally {\n setIsSubmitting(false);\n }\n };\n\n const canSubmitVerification = () => {\n if (!registrationState.intent) return false;\n\n if (\n registrationState.intent.expectEmailVerification &&\n emailCode.length !== 6\n ) {\n return false;\n }\n\n if (\n registrationState.intent.expectPhoneVerification &&\n phoneCode.length !== 6\n ) {\n return false;\n }\n\n return true;\n };\n\n // Verification phase UI\n if (registrationState.phase === \"verification\" && registrationState.intent) {\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Stack gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n <Stack gap={\"md\"}>\n <Text size=\"lg\" fw={500} ta=\"center\">\n {tr(\"registerVerifyTitle\") ?? \"Verify your account\"}\n </Text>\n <Text size=\"sm\" c=\"dimmed\" ta=\"center\">\n {tr(\"registerVerifyDescription\") ??\n \"Please enter the verification code(s) sent to you.\"}\n </Text>\n\n {verificationError && (\n <Alert variant=\"light\" color=\"red\" icon={<IconAlertCircle />}>\n <Text size=\"sm\">{verificationError}</Text>\n </Alert>\n )}\n\n {registrationState.intent.expectEmailVerification && (\n <Stack gap={\"xs\"}>\n <Text size=\"sm\" fw={500}>\n {tr(\"registerEmailCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n value={emailCode}\n onChange={setEmailCode}\n type=\"number\"\n oneTimeCode\n aria-label=\"Email verification code\"\n />\n </Flex>\n </Stack>\n )}\n\n {registrationState.intent.expectPhoneVerification && (\n <Stack gap={\"xs\"}>\n <Text size=\"sm\" fw={500}>\n {tr(\"registerPhoneCode\")}\n </Text>\n <Flex justify=\"center\">\n <PinInput\n length={6}\n value={phoneCode}\n onChange={setPhoneCode}\n type=\"number\"\n oneTimeCode\n aria-label=\"Phone verification code\"\n />\n </Flex>\n </Stack>\n )}\n\n <ActionButton\n color={\"blue\"}\n onClick={handleVerificationSubmit}\n loading={isSubmitting}\n disabled={!canSubmitVerification()}\n >\n {tr(\"registerVerifySubmit\")}\n </ActionButton>\n\n <ActionButton\n variant=\"subtle\"\n onClick={() =>\n setRegistrationState({ phase: \"form\", intent: undefined })\n }\n >\n {tr(\"registerVerifyBack\") ?? \"Back to registration\"}\n </ActionButton>\n </Stack>\n </Card>\n </Stack>\n </Flex>\n );\n }\n\n // Registration form phase UI\n return (\n <Flex flex={1} justify={\"center\"} align={\"center\"}>\n <Stack gap={\"sm\"} w={360}>\n <Card withBorder p={\"lg\"} bg={\"var(--alepha-elevated)\"}>\n <Stack gap={\"md\"}>\n {!isRegistrationAllowed ? (\n <>\n <Alert\n variant=\"light\"\n color=\"yellow\"\n icon={<IconAlertCircle />}\n >\n <Text size=\"sm\">{tr(\"registerDisabled\")}</Text>\n </Alert>\n <ActionButton href={router.path(\"login\")}>\n {tr(\"registerBackToSignIn\")}\n </ActionButton>\n </>\n ) : hasUsernamePassword ? (\n <>\n <form {...form.props}>\n <Stack flex={1} gap={\"md\"}>\n {settings.usernameEnabled !== false &&\n form.input.username && (\n <Control\n title={tr(\"registerUsername\")}\n input={form.input.username}\n icon={<IconUser />}\n text={{\n autoComplete: \"username\",\n }}\n />\n )}\n {settings.emailEnabled !== false && form.input.email && (\n <Control\n title={tr(\"registerEmail\")}\n input={form.input.email}\n icon={<IconMail />}\n text={{\n autoComplete: \"email\",\n }}\n />\n )}\n {settings.phoneEnabled === true &&\n form.input.phoneNumber && (\n <Control\n title={tr(\"registerPhone\")}\n input={form.input.phoneNumber}\n icon={<IconPhone />}\n text={{\n autoComplete: \"tel\",\n }}\n />\n )}\n <Control\n title={tr(\"registerPassword\")}\n input={form.input.password}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <Control\n title={tr(\"registerConfirmPassword\")}\n input={form.input.confirmPassword}\n icon={<IconLock />}\n password={{\n autoComplete: \"new-password\",\n }}\n />\n <ActionButton form={form} color={\"blue\"} variant={\"filled\"}>\n {tr(\"registerCreateAccount\")}\n </ActionButton>\n </Stack>\n </form>\n <Group align=\"center\" justify=\"center\" gap={\"md\"}>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-text-muted)\"} />\n <Text size=\"xs\">{tr(\"registerOr\")}</Text>\n <Flex flex={1} h={\"1px\"} bg={\"var(--alepha-text-muted)\"} />\n </Group>\n </>\n ) : null}\n {isRegistrationAllowed && (\n <>\n <Stack gap={\"sm\"}>\n {props.realmConfig.authenticationMethods.map(\n (method) =>\n method.type !== \"CREDENTIALS\" && (\n <ActionButton\n variant={\"default\"}\n key={method.type}\n leftSection={leftSection(method.name.toLowerCase())}\n onClick={() =>\n auth.login(method.name, {\n redirect,\n })\n }\n >\n {tr(\"registerContinueWith\", {\n args: [capitalize(method.name)],\n })}\n </ActionButton>\n ),\n )}\n </Stack>\n {props.realmConfig.authenticationMethods.length > 0 && (\n <Text size=\"sm\" ta=\"center\">\n {tr(\"registerHaveAccount\")}{\" \"}\n <ActionButton\n href={router.path(\"login\")}\n anchorProps={{ inherit: true }}\n >\n {tr(\"registerSignIn\")}\n </ActionButton>\n </Text>\n )}\n </>\n )}\n </Stack>\n </Card>\n <ActionButton variant={\"subtle\"} href={redirect}>\n {tr(\"registerCancel\")}\n </ActionButton>\n </Stack>\n </Flex>\n );\n};\n\nexport default Register;\n\nconst leftSection = (name: string) => {\n if (name === \"google\") {\n return <IconGoogle />;\n }\n\n if (name === \"github\") {\n return <IconGithub />;\n }\n};\n"],"mappings":"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"}
|