@alepha/ui 0.14.2 → 0.14.4
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-DIrCCPk3.js.map +1 -1
- package/dist/admin/AdminNotifications-cIbywWKi.js.map +1 -1
- package/dist/admin/AdminParameters-D-q3Qmhv.js.map +1 -1
- package/dist/admin/AdminSessions-vOgkrQ2U.js.map +1 -1
- package/dist/admin/AdminUserAudits-CSsN1fIC.js.map +1 -1
- package/dist/admin/AdminUserCreate-B72nu-3W.js.map +1 -1
- package/dist/admin/AdminUserDetails-CKM2IEMr.js +475 -0
- package/dist/admin/AdminUserDetails-CKM2IEMr.js.map +1 -0
- package/dist/admin/{AdminUserDetails-z1y8kJeB.js → AdminUserDetails-Zib_B6Al.js} +1 -1
- package/dist/admin/{AdminUserLayout-DyQYacQQ.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-DEaGu6n6.js.map +1 -1
- package/dist/admin/{AdminUserSettings-CR7MxX_R.js → AdminUserSettings-Di73D7g2.js} +6 -5
- package/dist/admin/AdminUserSettings-Di73D7g2.js.map +1 -0
- package/dist/admin/AdminUserSettings-yI-JECf5.js +3 -0
- package/dist/admin/AdminUsers-BnGIRvmV.js.map +1 -1
- package/dist/admin/index.d.ts +10 -10
- package/dist/admin/index.d.ts.map +1 -1
- package/dist/admin/index.js +18 -18
- package/dist/admin/index.js.map +1 -1
- package/dist/auth/index.js +4 -4
- package/dist/auth/index.js.map +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +6 -5
- package/dist/core/index.js.map +1 -1
- package/package.json +11 -11
- package/src/admin/AdminRouter.ts +23 -20
- package/src/admin/MainRouter.ts +1 -1
- package/src/admin/components/audits/AdminAudits.tsx +2 -2
- 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 +2 -2
- 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 +2 -2
- package/src/admin/components/users/AdminUserCreate.tsx +2 -2
- package/src/admin/components/users/AdminUserDetails.tsx +337 -85
- package/src/admin/components/users/AdminUserLayout.tsx +164 -108
- package/src/admin/components/users/AdminUserSessions.tsx +2 -2
- package/src/admin/components/users/AdminUserSettings.tsx +10 -5
- package/src/admin/components/users/AdminUsers.tsx +6 -2
- package/src/auth/AuthRouter.ts +4 -4
- package/src/core/components/form/TypeForm.tsx +3 -2
- package/src/core/components/layout/AlephaMantineProvider.tsx +5 -1
- package/src/core/components/layout/Sidebar.tsx +9 -6
- package/dist/admin/AdminUserDetails-BCt8Su-4.js +0 -222
- package/dist/admin/AdminUserDetails-BCt8Su-4.js.map +0 -1
- package/dist/admin/AdminUserLayout-Ck0GLRE5.js +0 -151
- package/dist/admin/AdminUserLayout-Ck0GLRE5.js.map +0 -1
- package/dist/admin/AdminUserSettings-CE66UTIP.js +0 -3
- package/dist/admin/AdminUserSettings-CR7MxX_R.js.map +0 -1
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import { useClient } from "@alepha/react";
|
|
2
2
|
import { NestedView, useRouter, useRouterState } from "@alepha/react/router";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
import { Box, Center, Loader, Stack, Text } from "@mantine/core";
|
|
4
|
+
import {
|
|
5
|
+
IconBan,
|
|
6
|
+
IconDevices,
|
|
7
|
+
IconHistory,
|
|
8
|
+
IconLock,
|
|
9
|
+
IconMail,
|
|
10
|
+
IconPencil,
|
|
11
|
+
IconSettings,
|
|
12
|
+
IconShieldCheck,
|
|
13
|
+
IconTrash,
|
|
14
|
+
IconUser,
|
|
15
|
+
} from "@tabler/icons-react";
|
|
16
|
+
import type { AdminUserController, UserEntity } from "alepha/api/users";
|
|
7
17
|
import { useEffect, useState } from "react";
|
|
8
18
|
import type { AdminRouter } from "../../AdminRouter.ts";
|
|
19
|
+
import AdminResourceHeader from "../shared/AdminResourceHeader.tsx";
|
|
20
|
+
import AdminResourceTabs from "../shared/AdminResourceTabs.tsx";
|
|
9
21
|
|
|
10
22
|
export interface AdminUserLayoutProps {
|
|
11
23
|
userRealmName?: string;
|
|
@@ -14,11 +26,12 @@ export interface AdminUserLayoutProps {
|
|
|
14
26
|
const AdminUserLayout = (props: AdminUserLayoutProps) => {
|
|
15
27
|
const router = useRouter<AdminRouter>();
|
|
16
28
|
const state = useRouterState();
|
|
17
|
-
const client = useClient<
|
|
29
|
+
const client = useClient<AdminUserController>();
|
|
18
30
|
const userId = state.params.userId as string;
|
|
19
31
|
|
|
20
32
|
const [user, setUser] = useState<UserEntity | null>(null);
|
|
21
33
|
const [loading, setLoading] = useState(true);
|
|
34
|
+
const [actionLoading, setActionLoading] = useState<string | null>(null);
|
|
22
35
|
|
|
23
36
|
useEffect(() => {
|
|
24
37
|
const loadUser = async () => {
|
|
@@ -38,127 +51,170 @@ const AdminUserLayout = (props: AdminUserLayoutProps) => {
|
|
|
38
51
|
|
|
39
52
|
if (loading) {
|
|
40
53
|
return (
|
|
41
|
-
<
|
|
54
|
+
<Center flex={1}>
|
|
42
55
|
<Loader />
|
|
43
|
-
</
|
|
56
|
+
</Center>
|
|
44
57
|
);
|
|
45
58
|
}
|
|
46
59
|
|
|
47
60
|
if (!user) {
|
|
48
61
|
return (
|
|
49
|
-
<
|
|
50
|
-
<
|
|
51
|
-
|
|
62
|
+
<Center flex={1}>
|
|
63
|
+
<Stack align="center" gap="xs">
|
|
64
|
+
<IconUser size={48} opacity={0.3} />
|
|
65
|
+
<Text c="dimmed">User not found</Text>
|
|
66
|
+
</Stack>
|
|
67
|
+
</Center>
|
|
52
68
|
);
|
|
53
69
|
}
|
|
54
70
|
|
|
55
|
-
const
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
71
|
+
const displayName =
|
|
72
|
+
user.firstName || user.lastName
|
|
73
|
+
? `${user.firstName ?? ""} ${user.lastName ?? ""}`.trim()
|
|
74
|
+
: user.username || user.email || "User";
|
|
59
75
|
|
|
76
|
+
const currentPath = state.url.pathname;
|
|
60
77
|
const getActiveTab = () => {
|
|
61
78
|
if (currentPath.endsWith("/sessions")) return "sessions";
|
|
62
79
|
if (currentPath.endsWith("/settings")) return "settings";
|
|
63
|
-
return "
|
|
80
|
+
if (currentPath.endsWith("/audits")) return "audits";
|
|
81
|
+
return "profile";
|
|
64
82
|
};
|
|
65
|
-
const activeTab = getActiveTab();
|
|
66
83
|
|
|
67
|
-
const
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
84
|
+
const handleBlockUser = async () => {
|
|
85
|
+
setActionLoading("block");
|
|
86
|
+
try {
|
|
87
|
+
const updated = await client.updateUser({
|
|
88
|
+
params: { id: userId },
|
|
89
|
+
query: { userRealmName: props.userRealmName },
|
|
90
|
+
body: { enabled: !user.enabled },
|
|
91
|
+
});
|
|
92
|
+
setUser(updated);
|
|
93
|
+
} finally {
|
|
94
|
+
setActionLoading(null);
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const handleSendVerification = async () => {
|
|
99
|
+
setActionLoading("verify");
|
|
100
|
+
// TODO: Implement send verification
|
|
101
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
102
|
+
setActionLoading(null);
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
const handleResetPassword = async () => {
|
|
106
|
+
setActionLoading("reset");
|
|
107
|
+
// TODO: Implement reset password
|
|
108
|
+
await new Promise((resolve) => setTimeout(resolve, 1000));
|
|
109
|
+
setActionLoading(null);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const handleDeleteUser = async () => {
|
|
113
|
+
if (
|
|
114
|
+
!confirm(
|
|
115
|
+
"Are you sure you want to delete this user? This action cannot be undone.",
|
|
116
|
+
)
|
|
117
|
+
) {
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
setActionLoading("delete");
|
|
121
|
+
try {
|
|
122
|
+
await client.deleteUser({
|
|
123
|
+
params: { id: userId },
|
|
124
|
+
query: { userRealmName: props.userRealmName },
|
|
125
|
+
});
|
|
126
|
+
await router.go("adminUsers");
|
|
127
|
+
} finally {
|
|
128
|
+
setActionLoading(null);
|
|
129
|
+
}
|
|
130
|
+
};
|
|
71
131
|
|
|
72
132
|
return (
|
|
73
|
-
<
|
|
74
|
-
<
|
|
75
|
-
<
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
</Tabs.List>
|
|
156
|
-
</Tabs>
|
|
157
|
-
|
|
158
|
-
<Flex flex={1}>
|
|
133
|
+
<Box py="xl" px="xl" flex={1}>
|
|
134
|
+
<Stack gap="lg">
|
|
135
|
+
<AdminResourceHeader
|
|
136
|
+
backHref={router.path("adminUsers")}
|
|
137
|
+
backLabel="Users"
|
|
138
|
+
avatar={user.picture || displayName.charAt(0).toUpperCase()}
|
|
139
|
+
avatarColor={user.enabled ? "blue" : "gray"}
|
|
140
|
+
title={displayName}
|
|
141
|
+
subtitle={user.email || user.username || undefined}
|
|
142
|
+
status={{
|
|
143
|
+
label: user.enabled ? "Active" : "Disabled",
|
|
144
|
+
color: user.enabled ? "green" : "red",
|
|
145
|
+
}}
|
|
146
|
+
menuActions={[
|
|
147
|
+
{
|
|
148
|
+
label: "Edit Profile",
|
|
149
|
+
icon: IconPencil,
|
|
150
|
+
href: router.path("adminUserDetails", { params: { userId } }),
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
label: user.enabled ? "Disable User" : "Enable User",
|
|
154
|
+
icon: user.enabled ? IconBan : IconShieldCheck,
|
|
155
|
+
color: user.enabled ? "orange" : "green",
|
|
156
|
+
onClick: handleBlockUser,
|
|
157
|
+
loading: actionLoading === "block",
|
|
158
|
+
},
|
|
159
|
+
...(user.email && !user.emailVerified
|
|
160
|
+
? [
|
|
161
|
+
{
|
|
162
|
+
label: "Send Verification Email",
|
|
163
|
+
icon: IconMail,
|
|
164
|
+
onClick: handleSendVerification,
|
|
165
|
+
loading: actionLoading === "verify",
|
|
166
|
+
},
|
|
167
|
+
]
|
|
168
|
+
: []),
|
|
169
|
+
{
|
|
170
|
+
label: "Reset Password",
|
|
171
|
+
icon: IconLock,
|
|
172
|
+
onClick: handleResetPassword,
|
|
173
|
+
loading: actionLoading === "reset",
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
label: "Delete User",
|
|
177
|
+
icon: IconTrash,
|
|
178
|
+
color: "red",
|
|
179
|
+
onClick: handleDeleteUser,
|
|
180
|
+
loading: actionLoading === "delete",
|
|
181
|
+
},
|
|
182
|
+
]}
|
|
183
|
+
/>
|
|
184
|
+
|
|
185
|
+
<AdminResourceTabs
|
|
186
|
+
activeTab={getActiveTab()}
|
|
187
|
+
tabs={[
|
|
188
|
+
{
|
|
189
|
+
value: "profile",
|
|
190
|
+
label: "Profile",
|
|
191
|
+
icon: IconUser,
|
|
192
|
+
href: router.path("adminUserDetails", { params: { userId } }),
|
|
193
|
+
},
|
|
194
|
+
{
|
|
195
|
+
value: "sessions",
|
|
196
|
+
label: "Sessions",
|
|
197
|
+
icon: IconDevices,
|
|
198
|
+
href: router.path("adminUserSessions", { params: { userId } }),
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
value: "audits",
|
|
202
|
+
label: "Activity",
|
|
203
|
+
icon: IconHistory,
|
|
204
|
+
href: router.path("adminUserAudits", { params: { userId } }),
|
|
205
|
+
},
|
|
206
|
+
{
|
|
207
|
+
value: "settings",
|
|
208
|
+
label: "Settings",
|
|
209
|
+
icon: IconSettings,
|
|
210
|
+
href: router.path("adminUserSettings", { params: { userId } }),
|
|
211
|
+
},
|
|
212
|
+
]}
|
|
213
|
+
/>
|
|
214
|
+
|
|
159
215
|
<NestedView />
|
|
160
|
-
</
|
|
161
|
-
</
|
|
216
|
+
</Stack>
|
|
217
|
+
</Box>
|
|
162
218
|
);
|
|
163
219
|
};
|
|
164
220
|
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
IconTrash,
|
|
11
11
|
} from "@tabler/icons-react";
|
|
12
12
|
import { type Page, t } from "alepha";
|
|
13
|
-
import type {
|
|
13
|
+
import type { AdminSessionController, SessionEntity } from "alepha/api/users";
|
|
14
14
|
import { useState } from "react";
|
|
15
15
|
|
|
16
16
|
export interface AdminUserSessionsProps {
|
|
@@ -19,7 +19,7 @@ export interface AdminUserSessionsProps {
|
|
|
19
19
|
|
|
20
20
|
const AdminUserSessions = (props: AdminUserSessionsProps) => {
|
|
21
21
|
const state = useRouterState();
|
|
22
|
-
const client = useClient<
|
|
22
|
+
const client = useClient<AdminSessionController>();
|
|
23
23
|
const { l } = useI18n();
|
|
24
24
|
const userId = state.params.userId as string;
|
|
25
25
|
const [refreshKey, setRefreshKey] = useState(0);
|
|
@@ -8,7 +8,11 @@ import {
|
|
|
8
8
|
IconMail,
|
|
9
9
|
IconTrash,
|
|
10
10
|
} from "@tabler/icons-react";
|
|
11
|
-
import type {
|
|
11
|
+
import type {
|
|
12
|
+
AdminUserController,
|
|
13
|
+
UserController,
|
|
14
|
+
UserEntity,
|
|
15
|
+
} from "alepha/api/users";
|
|
12
16
|
import { useEffect, useState } from "react";
|
|
13
17
|
import type { AdminRouter } from "../../AdminRouter.ts";
|
|
14
18
|
|
|
@@ -19,7 +23,8 @@ export interface AdminUserSettingsProps {
|
|
|
19
23
|
const AdminUserSettings = (props: AdminUserSettingsProps) => {
|
|
20
24
|
const router = useRouter<AdminRouter>();
|
|
21
25
|
const state = useRouterState();
|
|
22
|
-
const
|
|
26
|
+
const adminClient = useClient<AdminUserController>();
|
|
27
|
+
const userClient = useClient<UserController>();
|
|
23
28
|
const userId = state.params.userId as string;
|
|
24
29
|
|
|
25
30
|
const [user, setUser] = useState<UserEntity | null>(null);
|
|
@@ -31,7 +36,7 @@ const AdminUserSettings = (props: AdminUserSettingsProps) => {
|
|
|
31
36
|
useEffect(() => {
|
|
32
37
|
const loadUser = async () => {
|
|
33
38
|
try {
|
|
34
|
-
const data = await
|
|
39
|
+
const data = await adminClient.getUser({
|
|
35
40
|
params: { id: userId },
|
|
36
41
|
query: { userRealmName: props.userRealmName },
|
|
37
42
|
});
|
|
@@ -51,7 +56,7 @@ const AdminUserSettings = (props: AdminUserSettingsProps) => {
|
|
|
51
56
|
|
|
52
57
|
setDeleteLoading(true);
|
|
53
58
|
try {
|
|
54
|
-
await
|
|
59
|
+
await adminClient.deleteUser({
|
|
55
60
|
params: { id: userId },
|
|
56
61
|
query: { userRealmName: props.userRealmName },
|
|
57
62
|
});
|
|
@@ -67,7 +72,7 @@ const AdminUserSettings = (props: AdminUserSettingsProps) => {
|
|
|
67
72
|
setVerifyLoading(true);
|
|
68
73
|
setVerifySuccess(false);
|
|
69
74
|
try {
|
|
70
|
-
await
|
|
75
|
+
await userClient.requestEmailVerification({
|
|
71
76
|
query: {
|
|
72
77
|
userRealmName: props.userRealmName,
|
|
73
78
|
method: "link",
|
|
@@ -5,7 +5,11 @@ import { DataTable, Text } from "@alepha/ui";
|
|
|
5
5
|
import { Badge, Flex, Group } from "@mantine/core";
|
|
6
6
|
import { IconCheck, IconUsersPlus, IconX } from "@tabler/icons-react";
|
|
7
7
|
import { type Page, t } from "alepha";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
type AdminUserController,
|
|
10
|
+
type UserEntity,
|
|
11
|
+
users,
|
|
12
|
+
} from "alepha/api/users";
|
|
9
13
|
import type { AdminRouter } from "../../AdminRouter.ts";
|
|
10
14
|
|
|
11
15
|
export interface AdminUsersProps {
|
|
@@ -13,7 +17,7 @@ export interface AdminUsersProps {
|
|
|
13
17
|
}
|
|
14
18
|
|
|
15
19
|
const AdminUsers = (props: AdminUsersProps) => {
|
|
16
|
-
const client = useClient<
|
|
20
|
+
const client = useClient<AdminUserController>();
|
|
17
21
|
const router = useRouter<AdminRouter>();
|
|
18
22
|
const { l } = useI18n();
|
|
19
23
|
|
package/src/auth/AuthRouter.ts
CHANGED
|
@@ -47,7 +47,7 @@ export class AuthRouter {
|
|
|
47
47
|
},
|
|
48
48
|
can: () => !this.auth.user,
|
|
49
49
|
lazy: () => import("./components/Login.tsx"),
|
|
50
|
-
|
|
50
|
+
loader: async ({ query }) => {
|
|
51
51
|
return {
|
|
52
52
|
realmConfig: await this.loadRealmConfig(query.realm),
|
|
53
53
|
};
|
|
@@ -64,7 +64,7 @@ export class AuthRouter {
|
|
|
64
64
|
},
|
|
65
65
|
can: () => !this.auth.user,
|
|
66
66
|
lazy: () => import("./components/Register.tsx"),
|
|
67
|
-
|
|
67
|
+
loader: async ({ query }) => {
|
|
68
68
|
return {
|
|
69
69
|
realmConfig: await this.loadRealmConfig(query.realm),
|
|
70
70
|
};
|
|
@@ -81,7 +81,7 @@ export class AuthRouter {
|
|
|
81
81
|
},
|
|
82
82
|
can: () => !this.auth.user,
|
|
83
83
|
lazy: () => import("./components/ResetPassword.tsx"),
|
|
84
|
-
|
|
84
|
+
loader: async ({ query }) => {
|
|
85
85
|
return {
|
|
86
86
|
realmConfig: await this.loadRealmConfig(query.realm),
|
|
87
87
|
};
|
|
@@ -109,7 +109,7 @@ export class AuthRouter {
|
|
|
109
109
|
can: () => !!this.auth.user,
|
|
110
110
|
path: "/logout",
|
|
111
111
|
component: () => null,
|
|
112
|
-
|
|
112
|
+
loader: () => {
|
|
113
113
|
this.auth.logout();
|
|
114
114
|
return {};
|
|
115
115
|
},
|
|
@@ -92,6 +92,7 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
92
92
|
skipFormElement = false,
|
|
93
93
|
skipSubmitButton = false,
|
|
94
94
|
submitButtonProps,
|
|
95
|
+
fill = true,
|
|
95
96
|
} = props;
|
|
96
97
|
|
|
97
98
|
const schema = props.schema || form.options.schema;
|
|
@@ -176,7 +177,7 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
176
177
|
<Flex
|
|
177
178
|
direction={"column"}
|
|
178
179
|
gap={"sm"}
|
|
179
|
-
flex={
|
|
180
|
+
flex={fill ? 1 : undefined}
|
|
180
181
|
{...props.flexProps}
|
|
181
182
|
>
|
|
182
183
|
<Flex direction={"column"} gap={"sm"} flex={1}>
|
|
@@ -212,7 +213,7 @@ const TypeForm = <T extends TObject>(props: TypeFormProps<T>) => {
|
|
|
212
213
|
return (
|
|
213
214
|
<Flex
|
|
214
215
|
component={"form"}
|
|
215
|
-
flex={
|
|
216
|
+
flex={fill ? 1 : undefined}
|
|
216
217
|
{...form.props}
|
|
217
218
|
{...props.flexProps}
|
|
218
219
|
>
|
|
@@ -11,6 +11,7 @@ import { ModalsProvider, type ModalsProviderProps } from "@mantine/modals";
|
|
|
11
11
|
import { Notifications, type NotificationsProps } from "@mantine/notifications";
|
|
12
12
|
import type { NavigationProgressProps } from "@mantine/nprogress";
|
|
13
13
|
import { NavigationProgress, nprogress } from "@mantine/nprogress";
|
|
14
|
+
import { TypeBoxError } from "alepha";
|
|
14
15
|
import type { ReactNode } from "react";
|
|
15
16
|
import { useTheme } from "../../hooks/useTheme.ts";
|
|
16
17
|
import { useToast } from "../../hooks/useToast.ts";
|
|
@@ -39,7 +40,10 @@ const AlephaMantineProvider = (props: AlephaMantineProviderProps) => {
|
|
|
39
40
|
nprogress.complete();
|
|
40
41
|
},
|
|
41
42
|
"react:action:error": ({ error }) => {
|
|
42
|
-
if (
|
|
43
|
+
if (
|
|
44
|
+
error instanceof FormValidationError ||
|
|
45
|
+
error instanceof TypeBoxError
|
|
46
|
+
) {
|
|
43
47
|
// Validation errors are handled by the form component
|
|
44
48
|
return;
|
|
45
49
|
}
|
|
@@ -129,12 +129,14 @@ export const Sidebar = (props: SidebarProps) => {
|
|
|
129
129
|
const getSidebarNodes = (): SidebarNode[] => {
|
|
130
130
|
if (props.items) return props.items;
|
|
131
131
|
if (props.autoPopulateMenu) {
|
|
132
|
-
const items = router.concretePages
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
132
|
+
const items = router.concretePages
|
|
133
|
+
.filter((page) => !page.can || page.can())
|
|
134
|
+
.map((page) => ({
|
|
135
|
+
label: page.label ?? page.name,
|
|
136
|
+
//description: page.description?.slice(0, 32),
|
|
137
|
+
icon: renderIcon(page.icon),
|
|
138
|
+
href: router.path(page.name),
|
|
139
|
+
})) as SidebarMenuItem[];
|
|
138
140
|
if (
|
|
139
141
|
typeof props.autoPopulateMenu === "object" &&
|
|
140
142
|
props.autoPopulateMenu.startsWith
|
|
@@ -142,6 +144,7 @@ export const Sidebar = (props: SidebarProps) => {
|
|
|
142
144
|
const startsWith = props.autoPopulateMenu.startsWith;
|
|
143
145
|
return items.filter((item) => item.href?.startsWith(startsWith));
|
|
144
146
|
}
|
|
147
|
+
return items;
|
|
145
148
|
}
|
|
146
149
|
return [];
|
|
147
150
|
};
|