@strapi-community/plugin-better-auth-dashboard 1.0.0-alpha.3 → 1.0.0-alpha.5
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/{Root-BnRbzS-u.js → Root-CFxaaNC8.js} +262 -153
- package/dist/admin/{Root-DBjGZL7H.mjs → Root-CJNOLkgF.mjs} +263 -154
- package/dist/admin/{index-xZ2FHX3i.js → index-C4--Z2Qg.js} +1 -1
- package/dist/admin/{index-BpruO4vo.mjs → index-QYGGdXAd.mjs} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +6 -5
- package/dist/server/index.mjs +6 -5
- package/package.json +1 -1
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useState, useRef, useMemo } from "react";
|
|
3
3
|
import { useQuery, useQueryClient, useMutation, QueryClient, QueryClientProvider } from "react-query";
|
|
4
|
-
import { Modal, Typography, Button, Portal, Flex, IconButton, Box, Field, TextInput, Combobox, ComboboxOption, Checkbox, SingleSelect, SingleSelectOption, NumberInput, JSONInput, Textarea, Alert, Tabs, Grid, SearchForm, Searchbar, Loader, Badge
|
|
4
|
+
import { Modal, Typography, Button, Portal, Flex, IconButton, Box, Field, TextInput, Combobox, ComboboxOption, Checkbox, SingleSelect, SingleSelectOption, NumberInput, JSONInput, Textarea, Alert, Tabs, Grid, SearchForm, Searchbar, Loader, Badge } from "@strapi/design-system";
|
|
5
5
|
import styled, { keyframes } from "styled-components";
|
|
6
6
|
import { dashClient } from "@better-auth/infra/client";
|
|
7
7
|
import { createAuthClient, InferPlugin } from "better-auth/client";
|
|
8
8
|
import { Cross, Images, Trash, Plus, Pencil } from "@strapi/icons";
|
|
9
9
|
import { useNotification, useFetchClient } from "@strapi/strapi/admin";
|
|
10
|
-
import { g as getMediaLibraryComponent, P as PluginIcon } from "./index-
|
|
10
|
+
import { g as getMediaLibraryComponent, P as PluginIcon } from "./index-QYGGdXAd.mjs";
|
|
11
11
|
const dashPathMethods = () => ({
|
|
12
12
|
id: "dash-path-methods",
|
|
13
13
|
pathMethods: {
|
|
@@ -1038,6 +1038,7 @@ function OrganizationDetail({
|
|
|
1038
1038
|
const schemaQuery = useModelSchema("organization");
|
|
1039
1039
|
const qc = useQueryClient();
|
|
1040
1040
|
const { toggleNotification } = useNotification();
|
|
1041
|
+
const { get, put } = useFetchClient();
|
|
1041
1042
|
const orgQuery = useQuery({
|
|
1042
1043
|
queryKey: ["dash-org", organizationId],
|
|
1043
1044
|
queryFn: async () => {
|
|
@@ -1084,6 +1085,16 @@ function OrganizationDetail({
|
|
|
1084
1085
|
return result.data ?? [];
|
|
1085
1086
|
}
|
|
1086
1087
|
});
|
|
1088
|
+
const strapiOrgQuery = useQuery({
|
|
1089
|
+
queryKey: ["dash-strapi-org", organizationId],
|
|
1090
|
+
enabled: !!orgQuery.data,
|
|
1091
|
+
queryFn: async () => {
|
|
1092
|
+
const { data } = await get(
|
|
1093
|
+
`/better-auth-dashboard/db?uid=plugin::better-auth.organization&filters[id][$eq]=${organizationId}&pagination[pageSize]=1`
|
|
1094
|
+
);
|
|
1095
|
+
return data.results?.[0] ?? null;
|
|
1096
|
+
}
|
|
1097
|
+
});
|
|
1087
1098
|
const [activeTab, setActiveTab] = useState("details");
|
|
1088
1099
|
const [editName, setEditName] = useState(void 0);
|
|
1089
1100
|
const [editSlug, setEditSlug] = useState(void 0);
|
|
@@ -1104,7 +1115,7 @@ function OrganizationDetail({
|
|
|
1104
1115
|
};
|
|
1105
1116
|
const org = orgQuery.data;
|
|
1106
1117
|
const extraData = {
|
|
1107
|
-
...
|
|
1118
|
+
...strapiOrgQuery.data ?? {},
|
|
1108
1119
|
...editExtra
|
|
1109
1120
|
};
|
|
1110
1121
|
const updateOrgMutation = useMutation({
|
|
@@ -1113,13 +1124,13 @@ function OrganizationDetail({
|
|
|
1113
1124
|
if (editName !== void 0) body.name = editName;
|
|
1114
1125
|
if (editSlug !== void 0) body.slug = editSlug;
|
|
1115
1126
|
if (editLogo !== void 0) body.logo = editLogo;
|
|
1116
|
-
const
|
|
1117
|
-
|
|
1118
|
-
|
|
1127
|
+
const documentId = strapiOrgQuery.data?.documentId;
|
|
1128
|
+
if (!documentId)
|
|
1129
|
+
throw new Error("Could not resolve documentId for organization");
|
|
1130
|
+
await put(
|
|
1131
|
+
`/better-auth-dashboard/db/${documentId}?uid=plugin::better-auth.organization`,
|
|
1132
|
+
body
|
|
1119
1133
|
);
|
|
1120
|
-
if (result.error)
|
|
1121
|
-
throw new Error(result.error.message ?? "Update failed");
|
|
1122
|
-
return result.data;
|
|
1123
1134
|
},
|
|
1124
1135
|
onSuccess: () => {
|
|
1125
1136
|
qc.invalidateQueries({ queryKey: ["dash-org", organizationId] });
|
|
@@ -2132,6 +2143,7 @@ function OrgAvatar({ name, logo }) {
|
|
|
2132
2143
|
}
|
|
2133
2144
|
function OrganizationsPage({ teamsEnabled }) {
|
|
2134
2145
|
const qc = useQueryClient();
|
|
2146
|
+
const { toggleNotification } = useNotification();
|
|
2135
2147
|
const [page, setPage] = useState(1);
|
|
2136
2148
|
const [search, setSearch] = useState("");
|
|
2137
2149
|
const [searchInput, setSearchInput] = useState("");
|
|
@@ -2171,6 +2183,13 @@ function OrganizationsPage({ teamsEnabled }) {
|
|
|
2171
2183
|
onSuccess: () => {
|
|
2172
2184
|
setConfirmDelete(null);
|
|
2173
2185
|
qc.invalidateQueries({ queryKey: ["dash-organizations"] });
|
|
2186
|
+
toggleNotification({ type: "success", message: "Organization deleted" });
|
|
2187
|
+
},
|
|
2188
|
+
onError: (err) => {
|
|
2189
|
+
toggleNotification({
|
|
2190
|
+
type: "danger",
|
|
2191
|
+
message: err.message ?? "Failed to delete organization"
|
|
2192
|
+
});
|
|
2174
2193
|
}
|
|
2175
2194
|
});
|
|
2176
2195
|
const deleteManyMutation = useMutation({
|
|
@@ -2183,10 +2202,20 @@ function OrganizationsPage({ teamsEnabled }) {
|
|
|
2183
2202
|
throw new Error(result.error.message ?? "Delete failed");
|
|
2184
2203
|
return result.data;
|
|
2185
2204
|
},
|
|
2186
|
-
onSuccess: () => {
|
|
2205
|
+
onSuccess: (_data, organizationIds) => {
|
|
2187
2206
|
setConfirmDeleteMany(false);
|
|
2188
2207
|
setSelected(/* @__PURE__ */ new Set());
|
|
2189
2208
|
qc.invalidateQueries({ queryKey: ["dash-organizations"] });
|
|
2209
|
+
toggleNotification({
|
|
2210
|
+
type: "success",
|
|
2211
|
+
message: `${organizationIds.length} organization${organizationIds.length !== 1 ? "s" : ""} deleted`
|
|
2212
|
+
});
|
|
2213
|
+
},
|
|
2214
|
+
onError: (err) => {
|
|
2215
|
+
toggleNotification({
|
|
2216
|
+
type: "danger",
|
|
2217
|
+
message: err.message ?? "Failed to delete organizations"
|
|
2218
|
+
});
|
|
2190
2219
|
}
|
|
2191
2220
|
});
|
|
2192
2221
|
const orgs = orgsQuery.data && "organizations" in orgsQuery.data ? orgsQuery.data.organizations : [];
|
|
@@ -3253,7 +3282,7 @@ function OverviewPage() {
|
|
|
3253
3282
|
queryKey: ["dash-recent-sessions"],
|
|
3254
3283
|
queryFn: async () => {
|
|
3255
3284
|
const { data } = await get(
|
|
3256
|
-
"/better-auth-dashboard/db?uid=plugin::better-auth.session&pagination[pageSize]=12&sort[0]=
|
|
3285
|
+
"/better-auth-dashboard/db?uid=plugin::better-auth.session&pagination[pageSize]=12&sort[0]=updatedAt:desc"
|
|
3257
3286
|
);
|
|
3258
3287
|
return data.results ?? [];
|
|
3259
3288
|
},
|
|
@@ -3269,6 +3298,43 @@ function OverviewPage() {
|
|
|
3269
3298
|
return r.data;
|
|
3270
3299
|
}
|
|
3271
3300
|
});
|
|
3301
|
+
const sessionsRaw = sessionsQuery.data ?? [];
|
|
3302
|
+
const activeUserIds = [];
|
|
3303
|
+
const lastActiveByUserId = /* @__PURE__ */ new Map();
|
|
3304
|
+
for (const s of sessionsRaw) {
|
|
3305
|
+
const uid = String(s.userId);
|
|
3306
|
+
if (!lastActiveByUserId.has(uid)) {
|
|
3307
|
+
lastActiveByUserId.set(uid, s.updatedAt ?? s.createdAt);
|
|
3308
|
+
activeUserIds.push(uid);
|
|
3309
|
+
}
|
|
3310
|
+
}
|
|
3311
|
+
const activeUsersQuery = useQuery({
|
|
3312
|
+
queryKey: ["dash-active-users", activeUserIds],
|
|
3313
|
+
queryFn: async () => {
|
|
3314
|
+
if (activeUserIds.length === 0) return [];
|
|
3315
|
+
const params = new URLSearchParams({ uid: "plugin::better-auth.user" });
|
|
3316
|
+
for (let i = 0; i < activeUserIds.length; i++) {
|
|
3317
|
+
params.set(`filters[id][$in][${i}]`, activeUserIds[i]);
|
|
3318
|
+
}
|
|
3319
|
+
params.set("pagination[pageSize]", "12");
|
|
3320
|
+
const { data } = await get(
|
|
3321
|
+
`/better-auth-dashboard/db?${params}`
|
|
3322
|
+
);
|
|
3323
|
+
return data.results ?? [];
|
|
3324
|
+
},
|
|
3325
|
+
enabled: feedMode === "active" && activeUserIds.length > 0
|
|
3326
|
+
});
|
|
3327
|
+
const chartRef = useRef(null);
|
|
3328
|
+
const [chartHeight, setChartHeight] = useState(0);
|
|
3329
|
+
useEffect(() => {
|
|
3330
|
+
const el = chartRef.current;
|
|
3331
|
+
if (!el) return;
|
|
3332
|
+
const ro = new ResizeObserver((entries) => {
|
|
3333
|
+
for (const entry of entries) setChartHeight(entry.contentRect.height);
|
|
3334
|
+
});
|
|
3335
|
+
ro.observe(el);
|
|
3336
|
+
return () => ro.disconnect();
|
|
3337
|
+
}, []);
|
|
3272
3338
|
if (statsQuery.isLoading) {
|
|
3273
3339
|
return /* @__PURE__ */ jsx(
|
|
3274
3340
|
Flex,
|
|
@@ -3286,8 +3352,12 @@ function OverviewPage() {
|
|
|
3286
3352
|
const graphData = graphQuery.data?.data ?? [];
|
|
3287
3353
|
const rtnData = retentionQuery.data?.data ?? [];
|
|
3288
3354
|
const users = usersQuery.data?.users ?? [];
|
|
3289
|
-
const sessions = sessionsQuery.data ?? [];
|
|
3290
3355
|
const orgCount = orgsQuery.data?.total ?? 0;
|
|
3356
|
+
const activeUserMap = /* @__PURE__ */ new Map();
|
|
3357
|
+
for (const u of activeUsersQuery.data ?? []) {
|
|
3358
|
+
activeUserMap.set(String(u.id), u);
|
|
3359
|
+
}
|
|
3360
|
+
const sortedActiveUsers = activeUserIds.map((uid) => activeUserMap.get(uid)).filter((u) => u !== void 0);
|
|
3291
3361
|
const totalSpark = graphData.map((d) => d.totalUsers);
|
|
3292
3362
|
const newSpark = graphData.map((d) => d.newUsers);
|
|
3293
3363
|
const activeSpark = graphData.map((d) => d.activeUsers);
|
|
@@ -3391,7 +3461,7 @@ function OverviewPage() {
|
|
|
3391
3461
|
/* @__PURE__ */ jsx(DivLine, {})
|
|
3392
3462
|
] }),
|
|
3393
3463
|
/* @__PURE__ */ jsxs(TwoPanel, { children: [
|
|
3394
|
-
/* @__PURE__ */ jsxs(ChartCard, { $delay: 5, children: [
|
|
3464
|
+
/* @__PURE__ */ jsxs(ChartCard, { ref: chartRef, $delay: 5, children: [
|
|
3395
3465
|
/* @__PURE__ */ jsxs(ChartHeader, { children: [
|
|
3396
3466
|
/* @__PURE__ */ jsx(ChartTitle, { children: "User Growth" }),
|
|
3397
3467
|
/* @__PURE__ */ jsx(SeriesRow, { children: ALL_SERIES.map((s) => /* @__PURE__ */ jsxs(
|
|
@@ -3427,57 +3497,57 @@ function OverviewPage() {
|
|
|
3427
3497
|
}
|
|
3428
3498
|
)
|
|
3429
3499
|
] }),
|
|
3430
|
-
/* @__PURE__ */ jsxs(
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
/* @__PURE__ */ jsx(FeedName, { title: u.name, children: u.name })
|
|
3500
|
+
/* @__PURE__ */ jsxs(
|
|
3501
|
+
FeedCard,
|
|
3502
|
+
{
|
|
3503
|
+
$delay: 6,
|
|
3504
|
+
style: chartHeight > 0 ? { height: chartHeight } : void 0,
|
|
3505
|
+
children: [
|
|
3506
|
+
/* @__PURE__ */ jsxs(FeedHead, { children: [
|
|
3507
|
+
/* @__PURE__ */ jsx("span", { children: feedMode === "signups" ? "Recent Sign-ups" : "Recently Active" }),
|
|
3508
|
+
/* @__PURE__ */ jsxs(
|
|
3509
|
+
FeedSelect,
|
|
3510
|
+
{
|
|
3511
|
+
value: feedMode,
|
|
3512
|
+
onChange: (e) => setFeedMode(e.target.value),
|
|
3513
|
+
children: [
|
|
3514
|
+
/* @__PURE__ */ jsx("option", { value: "signups", children: "Recent Sign-ups" }),
|
|
3515
|
+
/* @__PURE__ */ jsx("option", { value: "active", children: "Recently Active" })
|
|
3516
|
+
]
|
|
3517
|
+
}
|
|
3518
|
+
)
|
|
3450
3519
|
] }),
|
|
3451
|
-
/* @__PURE__ */ jsx(
|
|
3452
|
-
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
|
|
3462
|
-
|
|
3463
|
-
|
|
3464
|
-
|
|
3465
|
-
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
|
|
3478
|
-
|
|
3479
|
-
|
|
3480
|
-
|
|
3520
|
+
/* @__PURE__ */ jsx(FeedScroll, { children: feedMode === "signups" ? usersQuery.isLoading ? /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsx(Loader, { children: "Loading…" }) }) : users.length === 0 ? /* @__PURE__ */ jsx(Empty, { children: "No users yet" }) : users.map((u) => /* @__PURE__ */ jsxs(FeedItem, { children: [
|
|
3521
|
+
/* @__PURE__ */ jsxs(FeedTop, { children: [
|
|
3522
|
+
/* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 1, style: { minWidth: 0 }, children: [
|
|
3523
|
+
/* @__PURE__ */ jsx(Avatar, { name: u.name, src: u.image, size: 20 }),
|
|
3524
|
+
/* @__PURE__ */ jsx(FeedName, { title: u.name, children: u.name })
|
|
3525
|
+
] }),
|
|
3526
|
+
/* @__PURE__ */ jsx(FeedMeta, { children: relTime(u.createdAt) })
|
|
3527
|
+
] }),
|
|
3528
|
+
/* @__PURE__ */ jsx(FeedEmail, { title: u.email, children: u.email })
|
|
3529
|
+
] }, u.id)) : activeUsersQuery.isLoading || sessionsQuery.isLoading ? /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsx(Loader, { children: "Loading…" }) }) : sortedActiveUsers.length === 0 ? /* @__PURE__ */ jsx(Empty, { children: "No recent activity" }) : sortedActiveUsers.map((u) => /* @__PURE__ */ jsxs(FeedItem, { children: [
|
|
3530
|
+
/* @__PURE__ */ jsxs(FeedTop, { children: [
|
|
3531
|
+
/* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 1, style: { minWidth: 0 }, children: [
|
|
3532
|
+
/* @__PURE__ */ jsx(
|
|
3533
|
+
Avatar,
|
|
3534
|
+
{
|
|
3535
|
+
name: u.name,
|
|
3536
|
+
src: u.image ?? void 0,
|
|
3537
|
+
size: 20
|
|
3538
|
+
}
|
|
3539
|
+
),
|
|
3540
|
+
/* @__PURE__ */ jsx(FeedName, { title: u.name, children: u.name })
|
|
3541
|
+
] }),
|
|
3542
|
+
/* @__PURE__ */ jsx(FeedMeta, { children: relTime(
|
|
3543
|
+
lastActiveByUserId.get(String(u.id)) ?? u.createdAt
|
|
3544
|
+
) })
|
|
3545
|
+
] }),
|
|
3546
|
+
/* @__PURE__ */ jsx(FeedEmail, { title: u.email, children: u.email })
|
|
3547
|
+
] }, u.documentId)) })
|
|
3548
|
+
]
|
|
3549
|
+
}
|
|
3550
|
+
)
|
|
3481
3551
|
] }),
|
|
3482
3552
|
/* @__PURE__ */ jsxs(SectionDivider, { children: [
|
|
3483
3553
|
/* @__PURE__ */ jsx(DivLabel, { children: "Retention & Activity" }),
|
|
@@ -3853,9 +3923,10 @@ const SessionCard = styled.div`
|
|
|
3853
3923
|
align-items: flex-start;
|
|
3854
3924
|
justify-content: space-between;
|
|
3855
3925
|
gap: 12px;
|
|
3856
|
-
padding: 10px
|
|
3857
|
-
|
|
3858
|
-
|
|
3926
|
+
padding: 10px 14px;
|
|
3927
|
+
background: white;
|
|
3928
|
+
border: 1px solid #eaeaef;
|
|
3929
|
+
border-radius: 8px;
|
|
3859
3930
|
`;
|
|
3860
3931
|
const SessionMeta = styled.div`
|
|
3861
3932
|
display: flex;
|
|
@@ -3961,6 +4032,7 @@ function UserDetailDrawer({
|
|
|
3961
4032
|
const [banExpiresDays, setBanExpiresDays] = useState("");
|
|
3962
4033
|
const [confirmRevokeAll, setConfirmRevokeAll] = useState(false);
|
|
3963
4034
|
const [confirmRevokeSessionId, setConfirmRevokeSessionId] = useState(null);
|
|
4035
|
+
const [confirmBan, setConfirmBan] = useState(false);
|
|
3964
4036
|
const [confirmUnban, setConfirmUnban] = useState(false);
|
|
3965
4037
|
const [confirmUnlinkAccountId, setConfirmUnlinkAccountId] = useState(null);
|
|
3966
4038
|
const [confirmDisable2FA, setConfirmDisable2FA] = useState(false);
|
|
@@ -3984,33 +4056,18 @@ function UserDetailDrawer({
|
|
|
3984
4056
|
};
|
|
3985
4057
|
const updateMutation = useMutation({
|
|
3986
4058
|
mutationFn: async () => {
|
|
3987
|
-
const
|
|
3988
|
-
if (editName !== void 0)
|
|
3989
|
-
if (editEmail !== void 0)
|
|
4059
|
+
const body = { ...editExtra };
|
|
4060
|
+
if (editName !== void 0) body.name = editName;
|
|
4061
|
+
if (editEmail !== void 0) body.email = editEmail;
|
|
3990
4062
|
if (editEmailVerified !== void 0)
|
|
3991
|
-
|
|
3992
|
-
if (editImage !== void 0)
|
|
3993
|
-
const
|
|
3994
|
-
if (
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
})
|
|
4000
|
-
);
|
|
4001
|
-
}
|
|
4002
|
-
if (Object.keys(editExtra).length > 0) {
|
|
4003
|
-
const documentId = strapiUserQuery.data?.documentId;
|
|
4004
|
-
if (!documentId)
|
|
4005
|
-
throw new Error("Could not resolve documentId for user");
|
|
4006
|
-
ops.push(
|
|
4007
|
-
put(
|
|
4008
|
-
`/better-auth-dashboard/db/${documentId}?uid=plugin::better-auth.user`,
|
|
4009
|
-
editExtra
|
|
4010
|
-
)
|
|
4011
|
-
);
|
|
4012
|
-
}
|
|
4013
|
-
await Promise.all(ops);
|
|
4063
|
+
body.emailVerified = editEmailVerified;
|
|
4064
|
+
if (editImage !== void 0) body.image = editImage;
|
|
4065
|
+
const documentId = strapiUserQuery.data?.documentId;
|
|
4066
|
+
if (!documentId) throw new Error("Could not resolve documentId for user");
|
|
4067
|
+
await put(
|
|
4068
|
+
`/better-auth-dashboard/db/${documentId}?uid=plugin::better-auth.user`,
|
|
4069
|
+
body
|
|
4070
|
+
);
|
|
4014
4071
|
},
|
|
4015
4072
|
onSuccess: () => {
|
|
4016
4073
|
qc.invalidateQueries({ queryKey: ["dash-user", userId] });
|
|
@@ -4038,7 +4095,7 @@ function UserDetailDrawer({
|
|
|
4038
4095
|
mutationFn: async (sessionId) => {
|
|
4039
4096
|
const result = await client.dash.sessions.revoke(
|
|
4040
4097
|
{},
|
|
4041
|
-
withContext({ sessionId })
|
|
4098
|
+
withContext({ sessionId, userId })
|
|
4042
4099
|
);
|
|
4043
4100
|
if (result.error)
|
|
4044
4101
|
throw new Error(result.error.message ?? "Revoke failed");
|
|
@@ -4092,6 +4149,7 @@ function UserDetailDrawer({
|
|
|
4092
4149
|
return result.data;
|
|
4093
4150
|
},
|
|
4094
4151
|
onSuccess: () => {
|
|
4152
|
+
setConfirmBan(false);
|
|
4095
4153
|
qc.invalidateQueries({ queryKey: ["dash-user", userId] });
|
|
4096
4154
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
4097
4155
|
setBanReason("");
|
|
@@ -4707,7 +4765,8 @@ function UserDetailDrawer({
|
|
|
4707
4765
|
] })
|
|
4708
4766
|
] })
|
|
4709
4767
|
] }) }),
|
|
4710
|
-
banEnabled && /* @__PURE__ */ jsx(Tabs.Content, { value: "ban", children: /* @__PURE__ */ jsx(Flex, { direction: "column", gap:
|
|
4768
|
+
banEnabled && /* @__PURE__ */ jsx(Tabs.Content, { value: "ban", children: /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 5, paddingTop: 6, children: user?.banned ? /* @__PURE__ */ jsxs(FormSection, { children: [
|
|
4769
|
+
/* @__PURE__ */ jsx(SectionLabel, { children: "Ban status" }),
|
|
4711
4770
|
/* @__PURE__ */ jsxs(WarnCard, { children: [
|
|
4712
4771
|
/* @__PURE__ */ jsx(
|
|
4713
4772
|
Typography,
|
|
@@ -4722,7 +4781,7 @@ function UserDetailDrawer({
|
|
|
4722
4781
|
"Reason: ",
|
|
4723
4782
|
user.banReason
|
|
4724
4783
|
] }),
|
|
4725
|
-
user.banExpires
|
|
4784
|
+
user.banExpires ? /* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "danger600", children: [
|
|
4726
4785
|
"Expires:",
|
|
4727
4786
|
" ",
|
|
4728
4787
|
new Date(user.banExpires).toLocaleDateString(
|
|
@@ -4734,8 +4793,7 @@ function UserDetailDrawer({
|
|
|
4734
4793
|
day: "numeric"
|
|
4735
4794
|
}
|
|
4736
4795
|
)
|
|
4737
|
-
] }),
|
|
4738
|
-
!user.banExpires && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "danger600", children: "Duration: Permanent" })
|
|
4796
|
+
] }) : /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "danger600", children: "Duration: Permanent" })
|
|
4739
4797
|
] }),
|
|
4740
4798
|
/* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
|
|
4741
4799
|
Button,
|
|
@@ -4745,27 +4803,28 @@ function UserDetailDrawer({
|
|
|
4745
4803
|
children: "Lift ban"
|
|
4746
4804
|
}
|
|
4747
4805
|
) })
|
|
4748
|
-
] }) : /* @__PURE__ */ jsxs(
|
|
4806
|
+
] }) : /* @__PURE__ */ jsxs(FormSection, { children: [
|
|
4807
|
+
/* @__PURE__ */ jsx(SectionLabel, { children: "Apply ban" }),
|
|
4808
|
+
/* @__PURE__ */ jsxs(
|
|
4809
|
+
Field.Root,
|
|
4810
|
+
{
|
|
4811
|
+
hint: "Optional — will be shown to the user",
|
|
4812
|
+
style: { width: "100%" },
|
|
4813
|
+
children: [
|
|
4814
|
+
/* @__PURE__ */ jsx(Field.Label, { children: "Reason" }),
|
|
4815
|
+
/* @__PURE__ */ jsx(
|
|
4816
|
+
TextInput,
|
|
4817
|
+
{
|
|
4818
|
+
value: banReason,
|
|
4819
|
+
onChange: (e) => setBanReason(e.target.value),
|
|
4820
|
+
placeholder: "e.g. Violated terms of service"
|
|
4821
|
+
}
|
|
4822
|
+
),
|
|
4823
|
+
/* @__PURE__ */ jsx(Field.Hint, {})
|
|
4824
|
+
]
|
|
4825
|
+
}
|
|
4826
|
+
),
|
|
4749
4827
|
/* @__PURE__ */ jsxs(Grid.Root, { gap: 4, children: [
|
|
4750
|
-
/* @__PURE__ */ jsx(Grid.Item, { col: 12, children: /* @__PURE__ */ jsxs(
|
|
4751
|
-
Field.Root,
|
|
4752
|
-
{
|
|
4753
|
-
hint: "Optional — will be shown to the user",
|
|
4754
|
-
style: { width: "100%" },
|
|
4755
|
-
children: [
|
|
4756
|
-
/* @__PURE__ */ jsx(Field.Label, { children: "Reason" }),
|
|
4757
|
-
/* @__PURE__ */ jsx(
|
|
4758
|
-
TextInput,
|
|
4759
|
-
{
|
|
4760
|
-
value: banReason,
|
|
4761
|
-
onChange: (e) => setBanReason(e.target.value),
|
|
4762
|
-
placeholder: "e.g. Violated terms of service"
|
|
4763
|
-
}
|
|
4764
|
-
),
|
|
4765
|
-
/* @__PURE__ */ jsx(Field.Hint, {})
|
|
4766
|
-
]
|
|
4767
|
-
}
|
|
4768
|
-
) }),
|
|
4769
4828
|
/* @__PURE__ */ jsx(Grid.Item, { col: 6, children: /* @__PURE__ */ jsxs(
|
|
4770
4829
|
Field.Root,
|
|
4771
4830
|
{
|
|
@@ -4786,24 +4845,13 @@ function UserDetailDrawer({
|
|
|
4786
4845
|
]
|
|
4787
4846
|
}
|
|
4788
4847
|
) }),
|
|
4789
|
-
/* @__PURE__ */ jsx(Grid.Item, { col: 6, children:
|
|
4790
|
-
Flex,
|
|
4791
|
-
{
|
|
4792
|
-
direction: "column",
|
|
4793
|
-
justifyContent: "flex-end",
|
|
4794
|
-
style: { height: "100%", paddingBottom: 4 },
|
|
4795
|
-
children: /* @__PURE__ */ jsxs(PreviewPill, { children: [
|
|
4796
|
-
"⏱ Expires ",
|
|
4797
|
-
banExpiryPreview
|
|
4798
|
-
] })
|
|
4799
|
-
}
|
|
4800
|
-
) : /* @__PURE__ */ jsx(
|
|
4848
|
+
/* @__PURE__ */ jsx(Grid.Item, { col: 6, children: /* @__PURE__ */ jsx(
|
|
4801
4849
|
Flex,
|
|
4802
4850
|
{
|
|
4803
4851
|
direction: "column",
|
|
4804
4852
|
justifyContent: "flex-end",
|
|
4805
4853
|
style: { height: "100%", paddingBottom: 4 },
|
|
4806
|
-
children: /* @__PURE__ */ jsx(PreviewPill, { children: "♾ Permanent ban" })
|
|
4854
|
+
children: /* @__PURE__ */ jsx(PreviewPill, { children: banExpiryPreview ? `⏱ Expires ${banExpiryPreview}` : "♾ Permanent ban" })
|
|
4807
4855
|
}
|
|
4808
4856
|
) })
|
|
4809
4857
|
] }),
|
|
@@ -4811,8 +4859,7 @@ function UserDetailDrawer({
|
|
|
4811
4859
|
Button,
|
|
4812
4860
|
{
|
|
4813
4861
|
variant: "danger",
|
|
4814
|
-
|
|
4815
|
-
onClick: () => banMutation.mutate(),
|
|
4862
|
+
onClick: () => setConfirmBan(true),
|
|
4816
4863
|
children: "Ban user"
|
|
4817
4864
|
}
|
|
4818
4865
|
) })
|
|
@@ -4839,19 +4886,27 @@ function UserDetailDrawer({
|
|
|
4839
4886
|
] }),
|
|
4840
4887
|
/* @__PURE__ */ jsxs(FormSection, { children: [
|
|
4841
4888
|
/* @__PURE__ */ jsx(SectionLabel, { children: "Active sessions" }),
|
|
4842
|
-
sessionsQuery.isLoading ? /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsx(Loader, { children: "Loading sessions…" }) }) : (sessionsQuery.data ?? []).length === 0 ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "No active sessions." }) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap:
|
|
4889
|
+
sessionsQuery.isLoading ? /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsx(Loader, { children: "Loading sessions…" }) }) : (sessionsQuery.data ?? []).length === 0 ? /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", children: "No active sessions." }) : /* @__PURE__ */ jsx(Flex, { direction: "column", gap: 2, alignItems: "stretch", children: (sessionsQuery.data ?? []).map((session) => /* @__PURE__ */ jsxs(SessionCard, { children: [
|
|
4843
4890
|
/* @__PURE__ */ jsxs(SessionMeta, { children: [
|
|
4844
|
-
/* @__PURE__ */ jsxs(
|
|
4845
|
-
|
|
4846
|
-
|
|
4847
|
-
|
|
4848
|
-
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4891
|
+
/* @__PURE__ */ jsxs(
|
|
4892
|
+
Flex,
|
|
4893
|
+
{
|
|
4894
|
+
gap: 2,
|
|
4895
|
+
alignItems: "center",
|
|
4896
|
+
style: { flexWrap: "wrap" },
|
|
4897
|
+
children: [
|
|
4898
|
+
session.ipAddress && /* @__PURE__ */ jsx(IpChip, { children: session.ipAddress }),
|
|
4899
|
+
/* @__PURE__ */ jsxs(TimestampText, { children: [
|
|
4900
|
+
"Created",
|
|
4901
|
+
" ",
|
|
4902
|
+
new Date(session.createdAt).toLocaleString(),
|
|
4903
|
+
" · Expires",
|
|
4904
|
+
" ",
|
|
4905
|
+
new Date(session.expiresAt).toLocaleString()
|
|
4906
|
+
] })
|
|
4907
|
+
]
|
|
4908
|
+
}
|
|
4909
|
+
),
|
|
4855
4910
|
session.userAgent && /* @__PURE__ */ jsx(AgentText, { children: session.userAgent })
|
|
4856
4911
|
] }),
|
|
4857
4912
|
/* @__PURE__ */ jsx(
|
|
@@ -4913,6 +4968,18 @@ function UserDetailDrawer({
|
|
|
4913
4968
|
onCancel: () => setConfirmRevokeSessionId(null)
|
|
4914
4969
|
}
|
|
4915
4970
|
),
|
|
4971
|
+
confirmBan && /* @__PURE__ */ jsx(
|
|
4972
|
+
ConfirmDialog,
|
|
4973
|
+
{
|
|
4974
|
+
title: "Ban user",
|
|
4975
|
+
message: banReason ? `Ban this user for the following reason: "${banReason}"? They will be prevented from signing in.` : "Are you sure you want to ban this user? They will be prevented from signing in.",
|
|
4976
|
+
confirmLabel: "Ban user",
|
|
4977
|
+
variant: "danger",
|
|
4978
|
+
loading: banMutation.isLoading,
|
|
4979
|
+
onConfirm: () => banMutation.mutate(),
|
|
4980
|
+
onCancel: () => setConfirmBan(false)
|
|
4981
|
+
}
|
|
4982
|
+
),
|
|
4916
4983
|
confirmUnban && /* @__PURE__ */ jsx(
|
|
4917
4984
|
ConfirmDialog,
|
|
4918
4985
|
{
|
|
@@ -5143,6 +5210,7 @@ const Toolbar = styled.div`
|
|
|
5143
5210
|
`;
|
|
5144
5211
|
function UsersPage({ config }) {
|
|
5145
5212
|
const qc = useQueryClient();
|
|
5213
|
+
const { toggleNotification } = useNotification();
|
|
5146
5214
|
const banEnabled = hasPlugin(config, "admin");
|
|
5147
5215
|
const emailVerificationEnabled = config.emailVerification.sendVerificationEmailEnabled;
|
|
5148
5216
|
const twoFactorEnabled = hasPlugin(config, "two-factor");
|
|
@@ -5174,6 +5242,13 @@ function UsersPage({ config }) {
|
|
|
5174
5242
|
setConfirmDelete(null);
|
|
5175
5243
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
5176
5244
|
qc.invalidateQueries({ queryKey: ["dash-user-stats"] });
|
|
5245
|
+
toggleNotification({ type: "success", message: "User deleted" });
|
|
5246
|
+
},
|
|
5247
|
+
onError: (err) => {
|
|
5248
|
+
toggleNotification({
|
|
5249
|
+
type: "danger",
|
|
5250
|
+
message: err.message ?? "Failed to delete user"
|
|
5251
|
+
});
|
|
5177
5252
|
}
|
|
5178
5253
|
});
|
|
5179
5254
|
const deleteManyMutation = useMutation({
|
|
@@ -5186,11 +5261,21 @@ function UsersPage({ config }) {
|
|
|
5186
5261
|
throw new Error(result.error.message ?? "Delete failed");
|
|
5187
5262
|
return result.data;
|
|
5188
5263
|
},
|
|
5189
|
-
onSuccess: () => {
|
|
5264
|
+
onSuccess: (_data, userIds) => {
|
|
5190
5265
|
setConfirmDeleteMany(false);
|
|
5191
5266
|
setSelected(/* @__PURE__ */ new Set());
|
|
5192
5267
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
5193
5268
|
qc.invalidateQueries({ queryKey: ["dash-user-stats"] });
|
|
5269
|
+
toggleNotification({
|
|
5270
|
+
type: "success",
|
|
5271
|
+
message: `${userIds.length} user${userIds.length !== 1 ? "s" : ""} deleted`
|
|
5272
|
+
});
|
|
5273
|
+
},
|
|
5274
|
+
onError: (err) => {
|
|
5275
|
+
toggleNotification({
|
|
5276
|
+
type: "danger",
|
|
5277
|
+
message: err.message ?? "Failed to delete users"
|
|
5278
|
+
});
|
|
5194
5279
|
}
|
|
5195
5280
|
});
|
|
5196
5281
|
const banManyMutation = useMutation({
|
|
@@ -5202,10 +5287,20 @@ function UsersPage({ config }) {
|
|
|
5202
5287
|
if (result.error) throw new Error(result.error.message ?? "Ban failed");
|
|
5203
5288
|
return result.data;
|
|
5204
5289
|
},
|
|
5205
|
-
onSuccess: () => {
|
|
5290
|
+
onSuccess: (_data, userIds) => {
|
|
5206
5291
|
setConfirmBanMany(false);
|
|
5207
5292
|
setSelected(/* @__PURE__ */ new Set());
|
|
5208
5293
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
5294
|
+
toggleNotification({
|
|
5295
|
+
type: "success",
|
|
5296
|
+
message: `${userIds.length} user${userIds.length !== 1 ? "s" : ""} banned`
|
|
5297
|
+
});
|
|
5298
|
+
},
|
|
5299
|
+
onError: (err) => {
|
|
5300
|
+
toggleNotification({
|
|
5301
|
+
type: "danger",
|
|
5302
|
+
message: err.message ?? "Failed to ban users"
|
|
5303
|
+
});
|
|
5209
5304
|
}
|
|
5210
5305
|
});
|
|
5211
5306
|
const toggleSelect = (id) => {
|
|
@@ -5384,14 +5479,28 @@ function UsersPage({ config }) {
|
|
|
5384
5479
|
user.id
|
|
5385
5480
|
)) })
|
|
5386
5481
|
] }) }),
|
|
5387
|
-
pageCount > 1 && /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5482
|
+
pageCount > 1 && /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
5483
|
+
/* @__PURE__ */ jsx(
|
|
5484
|
+
Button,
|
|
5485
|
+
{
|
|
5486
|
+
variant: "tertiary",
|
|
5487
|
+
size: "S",
|
|
5488
|
+
disabled: page === 1,
|
|
5489
|
+
onClick: () => setPage((p) => p - 1),
|
|
5490
|
+
children: "Previous"
|
|
5491
|
+
}
|
|
5492
|
+
),
|
|
5493
|
+
/* @__PURE__ */ jsx(
|
|
5494
|
+
Button,
|
|
5495
|
+
{
|
|
5496
|
+
variant: "tertiary",
|
|
5497
|
+
size: "S",
|
|
5498
|
+
disabled: page >= pageCount,
|
|
5499
|
+
onClick: () => setPage((p) => p + 1),
|
|
5500
|
+
children: "Next"
|
|
5501
|
+
}
|
|
5502
|
+
)
|
|
5503
|
+
] }) }),
|
|
5395
5504
|
showCreate && /* @__PURE__ */ jsx(CreateUserDialog, { onClose: () => setShowCreate(false) }),
|
|
5396
5505
|
detailUserId && /* @__PURE__ */ jsx(
|
|
5397
5506
|
UserDetailDrawer,
|
|
@@ -55,7 +55,7 @@ const index = {
|
|
|
55
55
|
id: `${PLUGIN_ID}.plugin.name`,
|
|
56
56
|
defaultMessage: "Auth Dashboard"
|
|
57
57
|
},
|
|
58
|
-
Component: async () => Promise.resolve().then(() => require("./Root-
|
|
58
|
+
Component: async () => Promise.resolve().then(() => require("./Root-CFxaaNC8.js"))
|
|
59
59
|
});
|
|
60
60
|
},
|
|
61
61
|
bootstrap() {
|