@alepha/ui 0.13.6 → 0.13.8
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-CwvH8e8c.js +215 -0
- package/dist/admin/AdminAudits-CwvH8e8c.js.map +1 -0
- package/dist/admin/AdminAudits-Dv8Vk_6r.js +3 -0
- package/dist/admin/AdminFiles-5CPA3lQk.js +3 -0
- package/dist/admin/{AdminFiles-B_jfB_Py.js → AdminFiles-C_w1tb_x.js} +4 -3
- package/dist/admin/AdminFiles-C_w1tb_x.js.map +1 -0
- package/dist/admin/AdminLayout-BnSmtA4x.js +3 -0
- package/dist/admin/AdminLayout-XiSivwWH.js +39 -0
- package/dist/admin/AdminLayout-XiSivwWH.js.map +1 -0
- package/dist/admin/AdminNotifications-DLjmZWtf.js +3 -0
- package/dist/admin/{AdminNotifications-BFEjqpqx.js → AdminNotifications-DuYy74AN.js} +3 -3
- package/dist/admin/AdminNotifications-DuYy74AN.js.map +1 -0
- package/dist/admin/AdminParameters-DYg48Jwe.js +3 -0
- package/dist/admin/AdminParameters-YagqWTG3.js +575 -0
- package/dist/admin/AdminParameters-YagqWTG3.js.map +1 -0
- package/dist/admin/{AdminSessions-D7DESfWK.js → AdminSessions-BCjgJ-93.js} +4 -4
- package/dist/admin/AdminSessions-BCjgJ-93.js.map +1 -0
- package/dist/admin/AdminSessions-DEh2uN-4.js +3 -0
- package/dist/admin/AdminUserAudits-B_PUXCKC.js +177 -0
- package/dist/admin/AdminUserAudits-B_PUXCKC.js.map +1 -0
- package/dist/admin/AdminUserAudits-D7cTcElL.js +3 -0
- package/dist/admin/{AdminUserCreate-Bhxsn92l.js → AdminUserCreate-DzfRbGZ4.js} +4 -4
- package/dist/admin/AdminUserCreate-DzfRbGZ4.js.map +1 -0
- package/dist/admin/{AdminUserCreate-CYI_xW5T.js → AdminUserCreate-oUA1KDIl.js} +1 -1
- package/dist/admin/{AdminUserDetails-C2y1Ig4n.js → AdminUserDetails-DeTrJm-t.js} +5 -5
- package/dist/admin/AdminUserDetails-DeTrJm-t.js.map +1 -0
- package/dist/admin/{AdminUserDetails-Cmzx9HxH.js → AdminUserDetails-y1H5DW8Y.js} +1 -1
- package/dist/admin/{AdminUserLayout-sW6cjZL0.js → AdminUserLayout-CsfrrZkD.js} +4 -7
- package/dist/admin/AdminUserLayout-CsfrrZkD.js.map +1 -0
- package/dist/admin/{AdminUserLayout-DGSf612u.js → AdminUserLayout-Dejnz13m.js} +1 -1
- package/dist/admin/AdminUserSessions-Bbhcpz4k.js +3 -0
- package/dist/admin/{AdminUserSessions-CvN15wPe.js → AdminUserSessions-DO9H85O-.js} +4 -4
- package/dist/admin/AdminUserSessions-DO9H85O-.js.map +1 -0
- package/dist/admin/{AdminUserSettings-DvaaxgcV.js → AdminUserSettings-B3jA8g3p.js} +4 -4
- package/dist/admin/AdminUserSettings-B3jA8g3p.js.map +1 -0
- package/dist/admin/AdminUserSettings-CE0xpbQc.js +3 -0
- package/dist/admin/AdminUsers-CegGZDhW.js +3 -0
- package/dist/admin/{AdminUsers-BR3C-jrg.js → AdminUsers-ebbrJBT0.js} +13 -17
- package/dist/admin/AdminUsers-ebbrJBT0.js.map +1 -0
- package/dist/admin/index.d.ts +2700 -1178
- package/dist/admin/index.js +65 -62
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/AuthLayout-BAZJHzDG.js +23 -0
- package/dist/auth/AuthLayout-BAZJHzDG.js.map +1 -0
- package/dist/auth/{Login-7HlBjDeV.js → Login-CeNZZjrr.js} +80 -44
- package/dist/auth/Login-CeNZZjrr.js.map +1 -0
- package/dist/auth/Login-hQcu1nlu.js +4 -0
- package/dist/auth/Register-B6HBNVHS.js +4 -0
- package/dist/auth/{Register-CuQr3kgi.js → Register-s4ENeyiE.js} +131 -91
- package/dist/auth/Register-s4ENeyiE.js.map +1 -0
- package/dist/auth/ResetPassword-Cjd-W-Nu.js +3 -0
- package/dist/auth/ResetPassword-GLIFkJT7.js +278 -0
- package/dist/auth/ResetPassword-GLIFkJT7.js.map +1 -0
- package/dist/auth/index.d.ts +605 -532
- package/dist/auth/index.js +26 -18
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts +425 -155
- package/dist/core/index.js +1751 -1369
- package/dist/core/index.js.map +1 -1
- package/package.json +23 -20
- package/src/admin/AdminRouter.ts +70 -16
- package/src/admin/components/AdminLayout.tsx +41 -61
- package/src/admin/components/audits/AdminAudits.tsx +240 -0
- package/src/admin/components/{AdminFiles.tsx → files/AdminFiles.tsx} +1 -1
- package/src/admin/components/{AdminJobs.tsx → jobs/AdminJobs.tsx} +1 -1
- package/src/admin/components/parameters/AdminParameters.tsx +137 -0
- package/src/admin/components/parameters/ParameterDetails.tsx +228 -0
- package/src/admin/components/parameters/ParameterHistory.tsx +146 -0
- package/src/admin/components/parameters/ParameterTree.tsx +146 -0
- package/src/admin/components/parameters/types.ts +35 -0
- package/src/admin/components/{AdminSessions.tsx → sessions/AdminSessions.tsx} +1 -1
- package/src/admin/components/users/AdminUserAudits.tsx +183 -0
- package/src/admin/components/{AdminUserCreate.tsx → users/AdminUserCreate.tsx} +1 -1
- package/src/admin/components/{AdminUserLayout.tsx → users/AdminUserLayout.tsx} +1 -4
- package/src/admin/components/{AdminUserSettings.tsx → users/AdminUserSettings.tsx} +1 -1
- package/src/admin/components/{AdminUsers.tsx → users/AdminUsers.tsx} +10 -12
- package/src/admin/index.ts +24 -16
- package/src/auth/AuthRouter.ts +23 -17
- package/src/auth/components/AuthLayout.tsx +6 -3
- package/src/auth/components/Login.tsx +109 -47
- package/src/auth/components/Register.tsx +158 -94
- package/src/auth/components/ResetPassword.tsx +51 -5
- package/src/auth/components/buttons/UserButton.tsx +2 -0
- package/src/core/atoms/alephaThemeAtom.ts +13 -0
- package/src/core/atoms/alephaThemeListAtom.ts +10 -0
- package/src/core/atoms/themes/default.ts +6 -0
- package/src/core/{themes → atoms/themes}/midnight.ts +3 -5
- package/src/core/components/buttons/ActionButton.tsx +33 -26
- package/src/core/components/buttons/DarkModeButton.tsx +0 -1
- package/src/core/components/buttons/ThemeButton.tsx +10 -7
- package/src/core/components/buttons/ToggleSidebarButton.tsx +19 -16
- package/src/core/components/data/ErrorViewer.tsx +171 -0
- package/src/core/components/data/JsonViewer.tsx +147 -138
- package/src/core/components/form/Control.tsx +95 -18
- package/src/core/components/form/ControlArray.tsx +377 -0
- package/src/core/components/form/ControlObject.tsx +127 -0
- package/src/core/components/form/TypeForm.tsx +99 -37
- package/src/core/components/layout/AdminShell.tsx +14 -1
- package/src/core/components/layout/AlephaMantineProvider.tsx +7 -3
- package/src/core/components/layout/Omnibar.tsx +1 -1
- package/src/core/components/layout/Sidebar.tsx +47 -14
- package/src/core/components/table/ColumnPicker.tsx +126 -0
- package/src/core/components/table/DataTable.tsx +354 -181
- package/src/core/components/table/DataTableFilters.tsx +64 -0
- package/src/core/components/table/DataTablePagination.tsx +59 -0
- package/src/core/components/table/DataTableToolbar.tsx +126 -0
- package/src/core/components/table/FilterPicker.tsx +138 -0
- package/src/core/components/table/types.ts +199 -0
- package/src/core/helpers/isComponentType.ts +9 -0
- package/src/core/helpers/renderIcon.tsx +13 -0
- package/src/core/hooks/useTheme.ts +24 -18
- package/src/core/index.ts +24 -3
- package/src/core/interfaces/AlephaTheme.ts +8 -0
- package/src/core/providers/ThemeProvider.ts +44 -62
- package/src/core/services/DialogService.tsx +24 -0
- package/src/core/utils/parseInput.ts +2 -2
- package/styles.css +1 -1
- package/dist/admin/AdminFiles-B-0UcHVV.js +0 -3
- package/dist/admin/AdminFiles-B_jfB_Py.js.map +0 -1
- package/dist/admin/AdminLayout-BMtiXAzS.js +0 -396
- package/dist/admin/AdminLayout-BMtiXAzS.js.map +0 -1
- package/dist/admin/AdminLayout-BNo3GoHR.js +0 -3
- package/dist/admin/AdminNotifications-BFEjqpqx.js.map +0 -1
- package/dist/admin/AdminNotifications-DJs2ZjNj.js +0 -3
- package/dist/admin/AdminSessions-D7DESfWK.js.map +0 -1
- package/dist/admin/AdminSessions-PS2M8iXi.js +0 -3
- package/dist/admin/AdminUserCreate-Bhxsn92l.js.map +0 -1
- package/dist/admin/AdminUserDetails-C2y1Ig4n.js.map +0 -1
- package/dist/admin/AdminUserLayout-sW6cjZL0.js.map +0 -1
- package/dist/admin/AdminUserSessions-CvN15wPe.js.map +0 -1
- package/dist/admin/AdminUserSessions-D-aOcZgV.js +0 -3
- package/dist/admin/AdminUserSettings-CEMhIYrI.js +0 -3
- package/dist/admin/AdminUserSettings-DvaaxgcV.js.map +0 -1
- package/dist/admin/AdminUsers-BR3C-jrg.js.map +0 -1
- package/dist/admin/AdminUsers-CMW9vN09.js +0 -3
- package/dist/auth/AuthLayout-CzwUKD9y.js +0 -19
- package/dist/auth/AuthLayout-CzwUKD9y.js.map +0 -1
- package/dist/auth/Login-7HlBjDeV.js.map +0 -1
- package/dist/auth/Login-C-e27DGb.js +0 -4
- package/dist/auth/Register-CuQr3kgi.js.map +0 -1
- package/dist/auth/Register-DbvXwgbG.js +0 -4
- package/dist/auth/ResetPassword-BzU-cdd4.js +0 -243
- package/dist/auth/ResetPassword-BzU-cdd4.js.map +0 -1
- package/dist/auth/ResetPassword-DSvrdpaA.js +0 -3
- package/src/admin/AdminSidebar.ts +0 -31
- package/src/admin/components/AdminParameters.tsx +0 -24
- package/src/core/themes/aurora.ts +0 -107
- package/src/core/themes/crystal.ts +0 -107
- package/src/core/themes/default.ts +0 -7
- package/src/core/themes/ember.ts +0 -107
- package/src/core/themes/index.ts +0 -7
- package/src/core/themes/remoraid.ts +0 -278
- package/src/core/themes/slate.ts +0 -81
- /package/src/admin/components/{AdminNotifications.tsx → notifications/AdminNotifications.tsx} +0 -0
- /package/src/admin/components/{AdminUserDetails.tsx → users/AdminUserDetails.tsx} +0 -0
- /package/src/admin/components/{AdminUserSessions.tsx → users/AdminUserSessions.tsx} +0 -0
- /package/src/admin/components/{AdminVerifications.tsx → verifications/AdminVerifications.tsx} +0 -0
|
@@ -3,7 +3,17 @@ import { useAuth } from "@alepha/react/auth";
|
|
|
3
3
|
import { useForm } from "@alepha/react/form";
|
|
4
4
|
import { useI18n } from "@alepha/react/i18n";
|
|
5
5
|
import { ActionButton, Control, capitalize } from "@alepha/ui";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
Alert,
|
|
8
|
+
Card,
|
|
9
|
+
Flex,
|
|
10
|
+
Group,
|
|
11
|
+
Image,
|
|
12
|
+
PinInput,
|
|
13
|
+
Stack,
|
|
14
|
+
Text,
|
|
15
|
+
Title,
|
|
16
|
+
} from "@mantine/core";
|
|
7
17
|
import {
|
|
8
18
|
IconAlertCircle,
|
|
9
19
|
IconLock,
|
|
@@ -57,7 +67,7 @@ const Register = (props: RegisterProps) => {
|
|
|
57
67
|
);
|
|
58
68
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
59
69
|
|
|
60
|
-
const
|
|
70
|
+
const credentialsProvider = props.realmConfig.authenticationMethods.find(
|
|
61
71
|
(it) => it.type === "CREDENTIALS",
|
|
62
72
|
);
|
|
63
73
|
|
|
@@ -97,6 +107,7 @@ const Register = (props: RegisterProps) => {
|
|
|
97
107
|
|
|
98
108
|
// Phase 1: Create registration intent
|
|
99
109
|
const intent = await userCtrl.createRegistrationIntent({
|
|
110
|
+
query: { userRealmName: props.realmConfig.realmName },
|
|
100
111
|
body: {
|
|
101
112
|
username: data.username,
|
|
102
113
|
email: data.email,
|
|
@@ -130,10 +141,11 @@ const Register = (props: RegisterProps) => {
|
|
|
130
141
|
});
|
|
131
142
|
|
|
132
143
|
// Auto-login after registration
|
|
133
|
-
if (identifier) {
|
|
134
|
-
await auth.login(
|
|
144
|
+
if (identifier && credentialsProvider) {
|
|
145
|
+
await auth.login(credentialsProvider.name, {
|
|
135
146
|
username: identifier,
|
|
136
147
|
password: data.password,
|
|
148
|
+
realm: props.realmConfig.realmName,
|
|
137
149
|
});
|
|
138
150
|
}
|
|
139
151
|
|
|
@@ -162,10 +174,11 @@ const Register = (props: RegisterProps) => {
|
|
|
162
174
|
});
|
|
163
175
|
|
|
164
176
|
// Auto-login after registration
|
|
165
|
-
if (registrationState.credentials) {
|
|
166
|
-
await auth.login(
|
|
177
|
+
if (registrationState.credentials && credentialsProvider) {
|
|
178
|
+
await auth.login(credentialsProvider.name, {
|
|
167
179
|
username: registrationState.credentials.identifier,
|
|
168
180
|
password: registrationState.credentials.password,
|
|
181
|
+
realm: props.realmConfig.realmName,
|
|
169
182
|
});
|
|
170
183
|
}
|
|
171
184
|
|
|
@@ -280,12 +293,46 @@ const Register = (props: RegisterProps) => {
|
|
|
280
293
|
);
|
|
281
294
|
}
|
|
282
295
|
|
|
296
|
+
// External login methods
|
|
297
|
+
const externalMethods = props.realmConfig.authenticationMethods.filter(
|
|
298
|
+
(method) => method.type !== "CREDENTIALS",
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
const showOrDivider = credentialsProvider && externalMethods.length > 0;
|
|
302
|
+
|
|
283
303
|
// Registration form phase UI
|
|
284
304
|
return (
|
|
285
305
|
<Flex flex={1} justify={"center"} align={"center"}>
|
|
286
306
|
<Stack gap={"sm"} w={360}>
|
|
287
307
|
<Card withBorder p={"lg"} bg={"var(--alepha-elevated)"}>
|
|
288
308
|
<Stack gap={"md"}>
|
|
309
|
+
{/* Realm branding */}
|
|
310
|
+
{(settings.logoUrl ||
|
|
311
|
+
settings.displayName ||
|
|
312
|
+
settings.description) && (
|
|
313
|
+
<Stack gap={"xs"} align="center" mb="xs">
|
|
314
|
+
{settings.logoUrl && (
|
|
315
|
+
<Image
|
|
316
|
+
src={settings.logoUrl}
|
|
317
|
+
alt={settings.displayName || props.realmConfig.realmName}
|
|
318
|
+
h={48}
|
|
319
|
+
w="auto"
|
|
320
|
+
fit="contain"
|
|
321
|
+
/>
|
|
322
|
+
)}
|
|
323
|
+
{settings.displayName && (
|
|
324
|
+
<Title order={4} ta="center">
|
|
325
|
+
{settings.displayName}
|
|
326
|
+
</Title>
|
|
327
|
+
)}
|
|
328
|
+
{settings.description && (
|
|
329
|
+
<Text size="sm" c="dimmed" ta="center">
|
|
330
|
+
{settings.description}
|
|
331
|
+
</Text>
|
|
332
|
+
)}
|
|
333
|
+
</Stack>
|
|
334
|
+
)}
|
|
335
|
+
|
|
289
336
|
{!isRegistrationAllowed ? (
|
|
290
337
|
<>
|
|
291
338
|
<Alert
|
|
@@ -295,108 +342,125 @@ const Register = (props: RegisterProps) => {
|
|
|
295
342
|
>
|
|
296
343
|
<Text size="sm">{tr("registerDisabled")}</Text>
|
|
297
344
|
</Alert>
|
|
298
|
-
<ActionButton
|
|
345
|
+
<ActionButton
|
|
346
|
+
href={router.path("login", {
|
|
347
|
+
query: { realm: props.realmConfig.realmName },
|
|
348
|
+
})}
|
|
349
|
+
>
|
|
299
350
|
{tr("registerBackToSignIn")}
|
|
300
351
|
</ActionButton>
|
|
301
352
|
</>
|
|
302
|
-
) :
|
|
353
|
+
) : (
|
|
303
354
|
<>
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
355
|
+
{/* Credentials registration form */}
|
|
356
|
+
{credentialsProvider && (
|
|
357
|
+
<form {...form.props}>
|
|
358
|
+
<Stack flex={1} gap={"md"}>
|
|
359
|
+
{settings.usernameEnabled !== false &&
|
|
360
|
+
form.input.username && (
|
|
361
|
+
<Control
|
|
362
|
+
title={tr("registerUsername")}
|
|
363
|
+
input={form.input.username}
|
|
364
|
+
icon={<IconUser />}
|
|
365
|
+
text={{
|
|
366
|
+
autoComplete: "username",
|
|
367
|
+
}}
|
|
368
|
+
/>
|
|
369
|
+
)}
|
|
370
|
+
{settings.emailEnabled !== false && form.input.email && (
|
|
308
371
|
<Control
|
|
309
|
-
title={tr("
|
|
310
|
-
input={form.input.
|
|
311
|
-
icon={<
|
|
372
|
+
title={tr("registerEmail")}
|
|
373
|
+
input={form.input.email}
|
|
374
|
+
icon={<IconMail />}
|
|
312
375
|
text={{
|
|
313
|
-
autoComplete: "
|
|
376
|
+
autoComplete: "email",
|
|
314
377
|
}}
|
|
315
378
|
/>
|
|
316
379
|
)}
|
|
317
|
-
|
|
380
|
+
{settings.phoneEnabled === true &&
|
|
381
|
+
form.input.phoneNumber && (
|
|
382
|
+
<Control
|
|
383
|
+
title={tr("registerPhone")}
|
|
384
|
+
input={form.input.phoneNumber}
|
|
385
|
+
icon={<IconPhone />}
|
|
386
|
+
text={{
|
|
387
|
+
autoComplete: "tel",
|
|
388
|
+
}}
|
|
389
|
+
/>
|
|
390
|
+
)}
|
|
318
391
|
<Control
|
|
319
|
-
title={tr("
|
|
320
|
-
input={form.input.
|
|
321
|
-
icon={<
|
|
322
|
-
|
|
323
|
-
autoComplete: "
|
|
392
|
+
title={tr("registerPassword")}
|
|
393
|
+
input={form.input.password}
|
|
394
|
+
icon={<IconLock />}
|
|
395
|
+
password={{
|
|
396
|
+
autoComplete: "new-password",
|
|
324
397
|
}}
|
|
325
398
|
/>
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
<
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
399
|
+
<Control
|
|
400
|
+
title={tr("registerConfirmPassword")}
|
|
401
|
+
input={form.input.confirmPassword}
|
|
402
|
+
icon={<IconLock />}
|
|
403
|
+
password={{
|
|
404
|
+
autoComplete: "new-password",
|
|
405
|
+
}}
|
|
406
|
+
/>
|
|
407
|
+
<ActionButton
|
|
408
|
+
form={form}
|
|
409
|
+
color={"blue"}
|
|
410
|
+
variant={"filled"}
|
|
411
|
+
>
|
|
412
|
+
{tr("registerCreateAccount")}
|
|
413
|
+
</ActionButton>
|
|
414
|
+
</Stack>
|
|
415
|
+
</form>
|
|
416
|
+
)}
|
|
417
|
+
|
|
418
|
+
{/* OR divider - only when both credentials AND external methods exist */}
|
|
419
|
+
{showOrDivider && (
|
|
420
|
+
<Group align="center" justify="center" gap={"md"}>
|
|
421
|
+
<Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
|
|
422
|
+
<Text size="xs" c="dimmed">
|
|
423
|
+
{tr("registerOr")}
|
|
424
|
+
</Text>
|
|
425
|
+
<Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
|
|
426
|
+
</Group>
|
|
427
|
+
)}
|
|
428
|
+
|
|
429
|
+
{/* External login methods */}
|
|
430
|
+
{externalMethods.length > 0 && (
|
|
431
|
+
<Stack gap={"sm"}>
|
|
432
|
+
{externalMethods.map((method) => (
|
|
433
|
+
<ActionButton
|
|
434
|
+
variant={"default"}
|
|
435
|
+
key={method.type}
|
|
436
|
+
leftSection={leftSection(method.name.toLowerCase())}
|
|
437
|
+
onClick={() =>
|
|
438
|
+
auth.login(method.name, {
|
|
439
|
+
redirect,
|
|
440
|
+
realm: props.realmConfig.realmName,
|
|
441
|
+
})
|
|
442
|
+
}
|
|
443
|
+
>
|
|
444
|
+
{tr("registerContinueWith", {
|
|
445
|
+
args: [capitalize(method.name)],
|
|
446
|
+
})}
|
|
447
|
+
</ActionButton>
|
|
448
|
+
))}
|
|
357
449
|
</Stack>
|
|
358
|
-
</form>
|
|
359
|
-
<Group align="center" justify="center" gap={"md"}>
|
|
360
|
-
<Flex flex={1} h={"1px"} bg={"var(--alepha-text-muted)"} />
|
|
361
|
-
<Text size="xs">{tr("registerOr")}</Text>
|
|
362
|
-
<Flex flex={1} h={"1px"} bg={"var(--alepha-text-muted)"} />
|
|
363
|
-
</Group>
|
|
364
|
-
</>
|
|
365
|
-
) : null}
|
|
366
|
-
{isRegistrationAllowed && (
|
|
367
|
-
<>
|
|
368
|
-
<Stack gap={"sm"}>
|
|
369
|
-
{props.realmConfig.authenticationMethods.map(
|
|
370
|
-
(method) =>
|
|
371
|
-
method.type !== "CREDENTIALS" && (
|
|
372
|
-
<ActionButton
|
|
373
|
-
variant={"default"}
|
|
374
|
-
key={method.type}
|
|
375
|
-
leftSection={leftSection(method.name.toLowerCase())}
|
|
376
|
-
onClick={() =>
|
|
377
|
-
auth.login(method.name, {
|
|
378
|
-
redirect,
|
|
379
|
-
})
|
|
380
|
-
}
|
|
381
|
-
>
|
|
382
|
-
{tr("registerContinueWith", {
|
|
383
|
-
args: [capitalize(method.name)],
|
|
384
|
-
})}
|
|
385
|
-
</ActionButton>
|
|
386
|
-
),
|
|
387
|
-
)}
|
|
388
|
-
</Stack>
|
|
389
|
-
{props.realmConfig.authenticationMethods.length > 0 && (
|
|
390
|
-
<Text size="sm" ta="center">
|
|
391
|
-
{tr("registerHaveAccount")}{" "}
|
|
392
|
-
<ActionButton
|
|
393
|
-
href={router.path("login")}
|
|
394
|
-
anchorProps={{ inherit: true }}
|
|
395
|
-
>
|
|
396
|
-
{tr("registerSignIn")}
|
|
397
|
-
</ActionButton>
|
|
398
|
-
</Text>
|
|
399
450
|
)}
|
|
451
|
+
|
|
452
|
+
{/* Sign in link */}
|
|
453
|
+
<Text size="sm" ta="center">
|
|
454
|
+
{tr("registerHaveAccount")}{" "}
|
|
455
|
+
<ActionButton
|
|
456
|
+
href={router.path("login", {
|
|
457
|
+
query: { realm: props.realmConfig.realmName },
|
|
458
|
+
})}
|
|
459
|
+
anchorProps={{ inherit: true }}
|
|
460
|
+
>
|
|
461
|
+
{tr("registerSignIn")}
|
|
462
|
+
</ActionButton>
|
|
463
|
+
</Text>
|
|
400
464
|
</>
|
|
401
465
|
)}
|
|
402
466
|
</Stack>
|
|
@@ -2,7 +2,16 @@ import { useClient, useRouter } from "@alepha/react";
|
|
|
2
2
|
import { useForm } from "@alepha/react/form";
|
|
3
3
|
import { useI18n } from "@alepha/react/i18n";
|
|
4
4
|
import { ActionButton, Control } from "@alepha/ui";
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
Alert,
|
|
7
|
+
Card,
|
|
8
|
+
Flex,
|
|
9
|
+
Image,
|
|
10
|
+
PinInput,
|
|
11
|
+
Stack,
|
|
12
|
+
Text,
|
|
13
|
+
Title,
|
|
14
|
+
} from "@mantine/core";
|
|
6
15
|
import {
|
|
7
16
|
IconAlertCircle,
|
|
8
17
|
IconCheck,
|
|
@@ -43,8 +52,8 @@ const ResetPassword = (props: ResetPasswordProps) => {
|
|
|
43
52
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
44
53
|
const redirect = router.query.r || "/";
|
|
45
54
|
|
|
46
|
-
const
|
|
47
|
-
|
|
55
|
+
const settings = props.realmConfig.settings;
|
|
56
|
+
const isResetPasswordAllowed = settings?.resetPasswordAllowed !== false;
|
|
48
57
|
|
|
49
58
|
// Phase 1: Request password reset intent
|
|
50
59
|
const emailForm = useForm({
|
|
@@ -52,6 +61,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
|
|
|
52
61
|
handler: async (data) => {
|
|
53
62
|
setError(null);
|
|
54
63
|
const intent = await userCtrl.createPasswordResetIntent({
|
|
64
|
+
query: { userRealmName: props.realmConfig.realmName },
|
|
55
65
|
body: { email: data.email },
|
|
56
66
|
});
|
|
57
67
|
|
|
@@ -111,6 +121,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
|
|
|
111
121
|
|
|
112
122
|
try {
|
|
113
123
|
const intent = await userCtrl.createPasswordResetIntent({
|
|
124
|
+
query: { userRealmName: props.realmConfig.realmName },
|
|
114
125
|
body: { email: resetState.email },
|
|
115
126
|
});
|
|
116
127
|
|
|
@@ -130,6 +141,33 @@ const ResetPassword = (props: ResetPasswordProps) => {
|
|
|
130
141
|
<Stack gap={"sm"} w={360}>
|
|
131
142
|
<Card withBorder p={"lg"} bg={"var(--alepha-elevated)"}>
|
|
132
143
|
<Stack gap={"md"}>
|
|
144
|
+
{/* Realm branding */}
|
|
145
|
+
{(settings.logoUrl ||
|
|
146
|
+
settings.displayName ||
|
|
147
|
+
settings.description) && (
|
|
148
|
+
<Stack gap={"xs"} align="center" mb="xs">
|
|
149
|
+
{settings.logoUrl && (
|
|
150
|
+
<Image
|
|
151
|
+
src={settings.logoUrl}
|
|
152
|
+
alt={settings.displayName || props.realmConfig.realmName}
|
|
153
|
+
h={48}
|
|
154
|
+
w="auto"
|
|
155
|
+
fit="contain"
|
|
156
|
+
/>
|
|
157
|
+
)}
|
|
158
|
+
{settings.displayName && (
|
|
159
|
+
<Title order={4} ta="center">
|
|
160
|
+
{settings.displayName}
|
|
161
|
+
</Title>
|
|
162
|
+
)}
|
|
163
|
+
{settings.description && (
|
|
164
|
+
<Text size="sm" c="dimmed" ta="center">
|
|
165
|
+
{settings.description}
|
|
166
|
+
</Text>
|
|
167
|
+
)}
|
|
168
|
+
</Stack>
|
|
169
|
+
)}
|
|
170
|
+
|
|
133
171
|
{error && (
|
|
134
172
|
<Alert variant="light" color="red" icon={<IconAlertCircle />}>
|
|
135
173
|
<Text size="sm">{error}</Text>
|
|
@@ -145,7 +183,11 @@ const ResetPassword = (props: ResetPasswordProps) => {
|
|
|
145
183
|
>
|
|
146
184
|
<Text size="sm">{tr("resetPasswordDisabled")}</Text>
|
|
147
185
|
</Alert>
|
|
148
|
-
<ActionButton
|
|
186
|
+
<ActionButton
|
|
187
|
+
href={router.path("login", {
|
|
188
|
+
query: { realm: props.realmConfig.realmName },
|
|
189
|
+
})}
|
|
190
|
+
>
|
|
149
191
|
{tr("resetPasswordBackToSignIn")}
|
|
150
192
|
</ActionButton>
|
|
151
193
|
</>
|
|
@@ -241,7 +283,11 @@ const ResetPassword = (props: ResetPasswordProps) => {
|
|
|
241
283
|
<Alert variant="light" color="green" icon={<IconCheck />}>
|
|
242
284
|
<Text size="sm">{tr("resetPasswordSuccess")}</Text>
|
|
243
285
|
</Alert>
|
|
244
|
-
<ActionButton
|
|
286
|
+
<ActionButton
|
|
287
|
+
href={router.path("login", {
|
|
288
|
+
query: { realm: props.realmConfig.realmName },
|
|
289
|
+
})}
|
|
290
|
+
>
|
|
245
291
|
{tr("resetPasswordBackToSignIn")}
|
|
246
292
|
</ActionButton>
|
|
247
293
|
</>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { $atom, type Static, t } from "alepha";
|
|
2
|
+
|
|
3
|
+
export const alephaThemeAtom = $atom({
|
|
4
|
+
name: "alepha.ui.theme",
|
|
5
|
+
schema: t.object({
|
|
6
|
+
index: t.integer(),
|
|
7
|
+
}),
|
|
8
|
+
default: {
|
|
9
|
+
index: 0,
|
|
10
|
+
},
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type CurrentAlephaTheme = Static<typeof alephaThemeAtom.schema>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { $atom, t } from "alepha";
|
|
2
|
+
import type { AlephaTheme } from "../interfaces/AlephaTheme.ts";
|
|
3
|
+
import { defaultTheme } from "./themes/default.ts";
|
|
4
|
+
import { midnightTheme } from "./themes/midnight.ts";
|
|
5
|
+
|
|
6
|
+
export const alephaThemeListAtom = $atom({
|
|
7
|
+
name: "alepha.ui.themeList",
|
|
8
|
+
schema: t.array(t.json<AlephaTheme>()), // TODO: translate to proper schema
|
|
9
|
+
default: [defaultTheme, midnightTheme],
|
|
10
|
+
});
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import type { AlephaTheme } from "
|
|
1
|
+
import type { AlephaTheme } from "../../interfaces/AlephaTheme.ts";
|
|
2
2
|
|
|
3
3
|
export const midnightTheme: AlephaTheme = {
|
|
4
|
-
|
|
5
|
-
label: "Midnight",
|
|
4
|
+
name: "Midnight",
|
|
6
5
|
description: "Clean, developer-focused design",
|
|
7
|
-
primaryColor: "
|
|
6
|
+
primaryColor: "pink",
|
|
8
7
|
primaryShade: { light: 7, dark: 8 },
|
|
9
8
|
fontFamily:
|
|
10
9
|
'-apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"',
|
|
@@ -24,7 +23,6 @@ export const midnightTheme: AlephaTheme = {
|
|
|
24
23
|
h6: { fontSize: "0.75rem", lineHeight: "1.5" },
|
|
25
24
|
},
|
|
26
25
|
},
|
|
27
|
-
|
|
28
26
|
radius: {
|
|
29
27
|
xs: "3px",
|
|
30
28
|
sm: "6px",
|
|
@@ -21,16 +21,17 @@ import {
|
|
|
21
21
|
type ThemeIconProps,
|
|
22
22
|
Tooltip,
|
|
23
23
|
type TooltipProps,
|
|
24
|
+
useMantineTheme,
|
|
24
25
|
} from "@mantine/core";
|
|
25
26
|
import { IconCheck, IconChevronRight } from "@tabler/icons-react";
|
|
26
27
|
import {
|
|
27
28
|
type ButtonHTMLAttributes,
|
|
28
29
|
Children,
|
|
29
30
|
type ComponentType,
|
|
30
|
-
isValidElement,
|
|
31
31
|
type ReactNode,
|
|
32
32
|
} from "react";
|
|
33
33
|
import { ui } from "../../constants/ui.ts";
|
|
34
|
+
import { isComponentType } from "../../helpers/isComponentType.ts";
|
|
34
35
|
|
|
35
36
|
export interface ActionMenuItem {
|
|
36
37
|
/**
|
|
@@ -119,7 +120,7 @@ export interface ActionCommonProps extends ButtonProps {
|
|
|
119
120
|
* Tooltip to display on hover. Can be a string for simple tooltips
|
|
120
121
|
* or a TooltipProps object for advanced configuration.
|
|
121
122
|
*/
|
|
122
|
-
tooltip?: string | TooltipProps;
|
|
123
|
+
tooltip?: string | number | TooltipProps;
|
|
123
124
|
|
|
124
125
|
/**
|
|
125
126
|
* Menu configuration. When provided, the action will display a dropdown menu.
|
|
@@ -148,7 +149,7 @@ export interface ActionCommonProps extends ButtonProps {
|
|
|
148
149
|
/**
|
|
149
150
|
* Visual intent of the action button.
|
|
150
151
|
*/
|
|
151
|
-
intent?: "primary" | "success" | "danger" | "warning" | "info";
|
|
152
|
+
intent?: "primary" | "success" | "danger" | "warning" | "info" | "none";
|
|
152
153
|
}
|
|
153
154
|
|
|
154
155
|
export type ActionProps = ActionCommonProps &
|
|
@@ -239,12 +240,36 @@ const ActionMenuItem = (props: {
|
|
|
239
240
|
};
|
|
240
241
|
|
|
241
242
|
const ActionButton = (_props: ActionProps) => {
|
|
242
|
-
const
|
|
243
|
+
const theme = useMantineTheme();
|
|
244
|
+
const props = { ..._props };
|
|
243
245
|
const { tooltip, menu, icon, ...restProps } = props;
|
|
244
246
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
247
|
+
if (props.variant === "subtle") {
|
|
248
|
+
restProps.c ??= "var(--mantine-color-text)";
|
|
249
|
+
restProps.color ??= "gray";
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
if (props.intent) {
|
|
253
|
+
if (props.intent === "none") {
|
|
254
|
+
restProps.c ??= "var(--mantine-color-text)";
|
|
255
|
+
restProps.color ??= "gray";
|
|
256
|
+
} else if (props.intent === "primary") {
|
|
257
|
+
restProps.c ??= "white";
|
|
258
|
+
restProps.color ??= theme.primaryColor;
|
|
259
|
+
} else if (props.intent === "success") {
|
|
260
|
+
restProps.c ??= "white";
|
|
261
|
+
restProps.color ??= "green";
|
|
262
|
+
} else if (props.intent === "danger") {
|
|
263
|
+
restProps.c ??= "white";
|
|
264
|
+
restProps.color ??= "red";
|
|
265
|
+
} else if (props.intent === "warning") {
|
|
266
|
+
restProps.c ??= "var(--mantine-color-text)";
|
|
267
|
+
restProps.color ??= "yellow";
|
|
268
|
+
} else if (props.intent === "info") {
|
|
269
|
+
restProps.c ??= "white";
|
|
270
|
+
restProps.color ??= "blue";
|
|
271
|
+
}
|
|
272
|
+
}
|
|
248
273
|
|
|
249
274
|
if (props.icon) {
|
|
250
275
|
const icon = isComponentType(props.icon) ? (
|
|
@@ -379,7 +404,7 @@ const ActionButton = (_props: ActionProps) => {
|
|
|
379
404
|
openDelay: 1000,
|
|
380
405
|
};
|
|
381
406
|
const tooltipProps: TooltipProps =
|
|
382
|
-
typeof tooltip === "string"
|
|
407
|
+
typeof tooltip === "string" || typeof tooltip === "number"
|
|
383
408
|
? {
|
|
384
409
|
...defaultTooltipProps,
|
|
385
410
|
label: tooltip,
|
|
@@ -599,21 +624,3 @@ const ActionHrefButton = (props: ActionNavigationButtonProps) => {
|
|
|
599
624
|
};
|
|
600
625
|
|
|
601
626
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
602
|
-
|
|
603
|
-
export function isComponentType(param: any): param is ComponentType<any> {
|
|
604
|
-
if (isValidElement(param)) return false;
|
|
605
|
-
return (
|
|
606
|
-
typeof param === "function" ||
|
|
607
|
-
(typeof param === "object" && param !== null && "$$typeof" in param)
|
|
608
|
-
);
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
export const renderIcon = (icon: ReactNode | ComponentType): ReactNode => {
|
|
612
|
-
if (!icon) return null;
|
|
613
|
-
if (isValidElement(icon)) return icon;
|
|
614
|
-
if (isComponentType(icon)) {
|
|
615
|
-
const IconComponent = icon;
|
|
616
|
-
return <IconComponent size={ui.sizes.icon.md} />;
|
|
617
|
-
}
|
|
618
|
-
return icon as ReactNode;
|
|
619
|
-
};
|
|
@@ -77,7 +77,6 @@ const DarkModeButton = (props: DarkModeButtonProps) => {
|
|
|
77
77
|
size={props.size ?? "sm"}
|
|
78
78
|
aria-label="Toggle color scheme"
|
|
79
79
|
px={"xs"}
|
|
80
|
-
c={colorScheme !== "default" ? undefined : "transparent"}
|
|
81
80
|
fullWidth={props.fullWidth ?? false}
|
|
82
81
|
icon={
|
|
83
82
|
colorScheme === "dark"
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useStore } from "@alepha/react";
|
|
2
2
|
import { IconPalette } from "@tabler/icons-react";
|
|
3
|
+
import { alephaThemeListAtom } from "../../atoms/alephaThemeListAtom.ts";
|
|
3
4
|
import { useTheme } from "../../hooks/useTheme.ts";
|
|
4
|
-
import { ThemeProvider } from "../../providers/ThemeProvider.ts";
|
|
5
5
|
import ActionButton, { type ActionProps } from "./ActionButton.tsx";
|
|
6
6
|
|
|
7
7
|
export interface ThemeButtonProps {
|
|
@@ -10,17 +10,20 @@ export interface ThemeButtonProps {
|
|
|
10
10
|
|
|
11
11
|
const ThemeButton = (props: ThemeButtonProps) => {
|
|
12
12
|
const [theme, setTheme] = useTheme();
|
|
13
|
-
const
|
|
13
|
+
const themeList = useStore(alephaThemeListAtom)[0];
|
|
14
14
|
|
|
15
15
|
return (
|
|
16
16
|
<ActionButton
|
|
17
17
|
variant="subtle"
|
|
18
18
|
icon={IconPalette}
|
|
19
19
|
menu={{
|
|
20
|
-
items:
|
|
21
|
-
label: it.
|
|
22
|
-
onClick: () =>
|
|
23
|
-
|
|
20
|
+
items: themeList.map((it, index) => ({
|
|
21
|
+
label: it.name,
|
|
22
|
+
onClick: () =>
|
|
23
|
+
setTheme({
|
|
24
|
+
index,
|
|
25
|
+
}),
|
|
26
|
+
active: theme.name === it.name,
|
|
24
27
|
})),
|
|
25
28
|
}}
|
|
26
29
|
{...props.actionProps}
|