@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
|
@@ -9,7 +9,7 @@ const client$2 = require("@better-auth/infra/client");
|
|
|
9
9
|
const client$1 = require("better-auth/client");
|
|
10
10
|
const icons = require("@strapi/icons");
|
|
11
11
|
const admin = require("@strapi/strapi/admin");
|
|
12
|
-
const index = require("./index-
|
|
12
|
+
const index = require("./index-C4--Z2Qg.js");
|
|
13
13
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
|
14
14
|
const styled__default = /* @__PURE__ */ _interopDefault(styled);
|
|
15
15
|
const dashPathMethods = () => ({
|
|
@@ -1042,6 +1042,7 @@ function OrganizationDetail({
|
|
|
1042
1042
|
const schemaQuery = useModelSchema("organization");
|
|
1043
1043
|
const qc = reactQuery.useQueryClient();
|
|
1044
1044
|
const { toggleNotification } = admin.useNotification();
|
|
1045
|
+
const { get, put } = admin.useFetchClient();
|
|
1045
1046
|
const orgQuery = reactQuery.useQuery({
|
|
1046
1047
|
queryKey: ["dash-org", organizationId],
|
|
1047
1048
|
queryFn: async () => {
|
|
@@ -1088,6 +1089,16 @@ function OrganizationDetail({
|
|
|
1088
1089
|
return result.data ?? [];
|
|
1089
1090
|
}
|
|
1090
1091
|
});
|
|
1092
|
+
const strapiOrgQuery = reactQuery.useQuery({
|
|
1093
|
+
queryKey: ["dash-strapi-org", organizationId],
|
|
1094
|
+
enabled: !!orgQuery.data,
|
|
1095
|
+
queryFn: async () => {
|
|
1096
|
+
const { data } = await get(
|
|
1097
|
+
`/better-auth-dashboard/db?uid=plugin::better-auth.organization&filters[id][$eq]=${organizationId}&pagination[pageSize]=1`
|
|
1098
|
+
);
|
|
1099
|
+
return data.results?.[0] ?? null;
|
|
1100
|
+
}
|
|
1101
|
+
});
|
|
1091
1102
|
const [activeTab, setActiveTab] = react.useState("details");
|
|
1092
1103
|
const [editName, setEditName] = react.useState(void 0);
|
|
1093
1104
|
const [editSlug, setEditSlug] = react.useState(void 0);
|
|
@@ -1108,7 +1119,7 @@ function OrganizationDetail({
|
|
|
1108
1119
|
};
|
|
1109
1120
|
const org = orgQuery.data;
|
|
1110
1121
|
const extraData = {
|
|
1111
|
-
...
|
|
1122
|
+
...strapiOrgQuery.data ?? {},
|
|
1112
1123
|
...editExtra
|
|
1113
1124
|
};
|
|
1114
1125
|
const updateOrgMutation = reactQuery.useMutation({
|
|
@@ -1117,13 +1128,13 @@ function OrganizationDetail({
|
|
|
1117
1128
|
if (editName !== void 0) body.name = editName;
|
|
1118
1129
|
if (editSlug !== void 0) body.slug = editSlug;
|
|
1119
1130
|
if (editLogo !== void 0) body.logo = editLogo;
|
|
1120
|
-
const
|
|
1121
|
-
|
|
1122
|
-
|
|
1131
|
+
const documentId = strapiOrgQuery.data?.documentId;
|
|
1132
|
+
if (!documentId)
|
|
1133
|
+
throw new Error("Could not resolve documentId for organization");
|
|
1134
|
+
await put(
|
|
1135
|
+
`/better-auth-dashboard/db/${documentId}?uid=plugin::better-auth.organization`,
|
|
1136
|
+
body
|
|
1123
1137
|
);
|
|
1124
|
-
if (result.error)
|
|
1125
|
-
throw new Error(result.error.message ?? "Update failed");
|
|
1126
|
-
return result.data;
|
|
1127
1138
|
},
|
|
1128
1139
|
onSuccess: () => {
|
|
1129
1140
|
qc.invalidateQueries({ queryKey: ["dash-org", organizationId] });
|
|
@@ -2136,6 +2147,7 @@ function OrgAvatar({ name, logo }) {
|
|
|
2136
2147
|
}
|
|
2137
2148
|
function OrganizationsPage({ teamsEnabled }) {
|
|
2138
2149
|
const qc = reactQuery.useQueryClient();
|
|
2150
|
+
const { toggleNotification } = admin.useNotification();
|
|
2139
2151
|
const [page, setPage] = react.useState(1);
|
|
2140
2152
|
const [search, setSearch] = react.useState("");
|
|
2141
2153
|
const [searchInput, setSearchInput] = react.useState("");
|
|
@@ -2175,6 +2187,13 @@ function OrganizationsPage({ teamsEnabled }) {
|
|
|
2175
2187
|
onSuccess: () => {
|
|
2176
2188
|
setConfirmDelete(null);
|
|
2177
2189
|
qc.invalidateQueries({ queryKey: ["dash-organizations"] });
|
|
2190
|
+
toggleNotification({ type: "success", message: "Organization deleted" });
|
|
2191
|
+
},
|
|
2192
|
+
onError: (err) => {
|
|
2193
|
+
toggleNotification({
|
|
2194
|
+
type: "danger",
|
|
2195
|
+
message: err.message ?? "Failed to delete organization"
|
|
2196
|
+
});
|
|
2178
2197
|
}
|
|
2179
2198
|
});
|
|
2180
2199
|
const deleteManyMutation = reactQuery.useMutation({
|
|
@@ -2187,10 +2206,20 @@ function OrganizationsPage({ teamsEnabled }) {
|
|
|
2187
2206
|
throw new Error(result.error.message ?? "Delete failed");
|
|
2188
2207
|
return result.data;
|
|
2189
2208
|
},
|
|
2190
|
-
onSuccess: () => {
|
|
2209
|
+
onSuccess: (_data, organizationIds) => {
|
|
2191
2210
|
setConfirmDeleteMany(false);
|
|
2192
2211
|
setSelected(/* @__PURE__ */ new Set());
|
|
2193
2212
|
qc.invalidateQueries({ queryKey: ["dash-organizations"] });
|
|
2213
|
+
toggleNotification({
|
|
2214
|
+
type: "success",
|
|
2215
|
+
message: `${organizationIds.length} organization${organizationIds.length !== 1 ? "s" : ""} deleted`
|
|
2216
|
+
});
|
|
2217
|
+
},
|
|
2218
|
+
onError: (err) => {
|
|
2219
|
+
toggleNotification({
|
|
2220
|
+
type: "danger",
|
|
2221
|
+
message: err.message ?? "Failed to delete organizations"
|
|
2222
|
+
});
|
|
2194
2223
|
}
|
|
2195
2224
|
});
|
|
2196
2225
|
const orgs = orgsQuery.data && "organizations" in orgsQuery.data ? orgsQuery.data.organizations : [];
|
|
@@ -3257,7 +3286,7 @@ function OverviewPage() {
|
|
|
3257
3286
|
queryKey: ["dash-recent-sessions"],
|
|
3258
3287
|
queryFn: async () => {
|
|
3259
3288
|
const { data } = await get(
|
|
3260
|
-
"/better-auth-dashboard/db?uid=plugin::better-auth.session&pagination[pageSize]=12&sort[0]=
|
|
3289
|
+
"/better-auth-dashboard/db?uid=plugin::better-auth.session&pagination[pageSize]=12&sort[0]=updatedAt:desc"
|
|
3261
3290
|
);
|
|
3262
3291
|
return data.results ?? [];
|
|
3263
3292
|
},
|
|
@@ -3273,6 +3302,43 @@ function OverviewPage() {
|
|
|
3273
3302
|
return r.data;
|
|
3274
3303
|
}
|
|
3275
3304
|
});
|
|
3305
|
+
const sessionsRaw = sessionsQuery.data ?? [];
|
|
3306
|
+
const activeUserIds = [];
|
|
3307
|
+
const lastActiveByUserId = /* @__PURE__ */ new Map();
|
|
3308
|
+
for (const s of sessionsRaw) {
|
|
3309
|
+
const uid = String(s.userId);
|
|
3310
|
+
if (!lastActiveByUserId.has(uid)) {
|
|
3311
|
+
lastActiveByUserId.set(uid, s.updatedAt ?? s.createdAt);
|
|
3312
|
+
activeUserIds.push(uid);
|
|
3313
|
+
}
|
|
3314
|
+
}
|
|
3315
|
+
const activeUsersQuery = reactQuery.useQuery({
|
|
3316
|
+
queryKey: ["dash-active-users", activeUserIds],
|
|
3317
|
+
queryFn: async () => {
|
|
3318
|
+
if (activeUserIds.length === 0) return [];
|
|
3319
|
+
const params = new URLSearchParams({ uid: "plugin::better-auth.user" });
|
|
3320
|
+
for (let i = 0; i < activeUserIds.length; i++) {
|
|
3321
|
+
params.set(`filters[id][$in][${i}]`, activeUserIds[i]);
|
|
3322
|
+
}
|
|
3323
|
+
params.set("pagination[pageSize]", "12");
|
|
3324
|
+
const { data } = await get(
|
|
3325
|
+
`/better-auth-dashboard/db?${params}`
|
|
3326
|
+
);
|
|
3327
|
+
return data.results ?? [];
|
|
3328
|
+
},
|
|
3329
|
+
enabled: feedMode === "active" && activeUserIds.length > 0
|
|
3330
|
+
});
|
|
3331
|
+
const chartRef = react.useRef(null);
|
|
3332
|
+
const [chartHeight, setChartHeight] = react.useState(0);
|
|
3333
|
+
react.useEffect(() => {
|
|
3334
|
+
const el = chartRef.current;
|
|
3335
|
+
if (!el) return;
|
|
3336
|
+
const ro = new ResizeObserver((entries) => {
|
|
3337
|
+
for (const entry of entries) setChartHeight(entry.contentRect.height);
|
|
3338
|
+
});
|
|
3339
|
+
ro.observe(el);
|
|
3340
|
+
return () => ro.disconnect();
|
|
3341
|
+
}, []);
|
|
3276
3342
|
if (statsQuery.isLoading) {
|
|
3277
3343
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3278
3344
|
designSystem.Flex,
|
|
@@ -3290,8 +3356,12 @@ function OverviewPage() {
|
|
|
3290
3356
|
const graphData = graphQuery.data?.data ?? [];
|
|
3291
3357
|
const rtnData = retentionQuery.data?.data ?? [];
|
|
3292
3358
|
const users = usersQuery.data?.users ?? [];
|
|
3293
|
-
const sessions = sessionsQuery.data ?? [];
|
|
3294
3359
|
const orgCount = orgsQuery.data?.total ?? 0;
|
|
3360
|
+
const activeUserMap = /* @__PURE__ */ new Map();
|
|
3361
|
+
for (const u of activeUsersQuery.data ?? []) {
|
|
3362
|
+
activeUserMap.set(String(u.id), u);
|
|
3363
|
+
}
|
|
3364
|
+
const sortedActiveUsers = activeUserIds.map((uid) => activeUserMap.get(uid)).filter((u) => u !== void 0);
|
|
3295
3365
|
const totalSpark = graphData.map((d) => d.totalUsers);
|
|
3296
3366
|
const newSpark = graphData.map((d) => d.newUsers);
|
|
3297
3367
|
const activeSpark = graphData.map((d) => d.activeUsers);
|
|
@@ -3395,7 +3465,7 @@ function OverviewPage() {
|
|
|
3395
3465
|
/* @__PURE__ */ jsxRuntime.jsx(DivLine, {})
|
|
3396
3466
|
] }),
|
|
3397
3467
|
/* @__PURE__ */ jsxRuntime.jsxs(TwoPanel, { children: [
|
|
3398
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ChartCard, { $delay: 5, children: [
|
|
3468
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ChartCard, { ref: chartRef, $delay: 5, children: [
|
|
3399
3469
|
/* @__PURE__ */ jsxRuntime.jsxs(ChartHeader, { children: [
|
|
3400
3470
|
/* @__PURE__ */ jsxRuntime.jsx(ChartTitle, { children: "User Growth" }),
|
|
3401
3471
|
/* @__PURE__ */ jsxRuntime.jsx(SeriesRow, { children: ALL_SERIES.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3431,57 +3501,57 @@ function OverviewPage() {
|
|
|
3431
3501
|
}
|
|
3432
3502
|
)
|
|
3433
3503
|
] }),
|
|
3434
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3451
|
-
|
|
3452
|
-
|
|
3453
|
-
/* @__PURE__ */ jsxRuntime.jsx(FeedName, { title: u.name, children: u.name })
|
|
3504
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3505
|
+
FeedCard,
|
|
3506
|
+
{
|
|
3507
|
+
$delay: 6,
|
|
3508
|
+
style: chartHeight > 0 ? { height: chartHeight } : void 0,
|
|
3509
|
+
children: [
|
|
3510
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FeedHead, { children: [
|
|
3511
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: feedMode === "signups" ? "Recent Sign-ups" : "Recently Active" }),
|
|
3512
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3513
|
+
FeedSelect,
|
|
3514
|
+
{
|
|
3515
|
+
value: feedMode,
|
|
3516
|
+
onChange: (e) => setFeedMode(e.target.value),
|
|
3517
|
+
children: [
|
|
3518
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "signups", children: "Recent Sign-ups" }),
|
|
3519
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "active", children: "Recently Active" })
|
|
3520
|
+
]
|
|
3521
|
+
}
|
|
3522
|
+
)
|
|
3454
3523
|
] }),
|
|
3455
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
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
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3524
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedScroll, { children: feedMode === "signups" ? usersQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: "Loading…" }) }) : users.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Empty, { children: "No users yet" }) : users.map((u) => /* @__PURE__ */ jsxRuntime.jsxs(FeedItem, { children: [
|
|
3525
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FeedTop, { children: [
|
|
3526
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 1, style: { minWidth: 0 }, children: [
|
|
3527
|
+
/* @__PURE__ */ jsxRuntime.jsx(Avatar, { name: u.name, src: u.image, size: 20 }),
|
|
3528
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedName, { title: u.name, children: u.name })
|
|
3529
|
+
] }),
|
|
3530
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedMeta, { children: relTime(u.createdAt) })
|
|
3531
|
+
] }),
|
|
3532
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedEmail, { title: u.email, children: u.email })
|
|
3533
|
+
] }, u.id)) : activeUsersQuery.isLoading || sessionsQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: "Loading…" }) }) : sortedActiveUsers.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(Empty, { children: "No recent activity" }) : sortedActiveUsers.map((u) => /* @__PURE__ */ jsxRuntime.jsxs(FeedItem, { children: [
|
|
3534
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FeedTop, { children: [
|
|
3535
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 1, style: { minWidth: 0 }, children: [
|
|
3536
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3537
|
+
Avatar,
|
|
3538
|
+
{
|
|
3539
|
+
name: u.name,
|
|
3540
|
+
src: u.image ?? void 0,
|
|
3541
|
+
size: 20
|
|
3542
|
+
}
|
|
3543
|
+
),
|
|
3544
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedName, { title: u.name, children: u.name })
|
|
3545
|
+
] }),
|
|
3546
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedMeta, { children: relTime(
|
|
3547
|
+
lastActiveByUserId.get(String(u.id)) ?? u.createdAt
|
|
3548
|
+
) })
|
|
3549
|
+
] }),
|
|
3550
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedEmail, { title: u.email, children: u.email })
|
|
3551
|
+
] }, u.documentId)) })
|
|
3552
|
+
]
|
|
3553
|
+
}
|
|
3554
|
+
)
|
|
3485
3555
|
] }),
|
|
3486
3556
|
/* @__PURE__ */ jsxRuntime.jsxs(SectionDivider, { children: [
|
|
3487
3557
|
/* @__PURE__ */ jsxRuntime.jsx(DivLabel, { children: "Retention & Activity" }),
|
|
@@ -3857,9 +3927,10 @@ const SessionCard = styled__default.default.div`
|
|
|
3857
3927
|
align-items: flex-start;
|
|
3858
3928
|
justify-content: space-between;
|
|
3859
3929
|
gap: 12px;
|
|
3860
|
-
padding: 10px
|
|
3861
|
-
|
|
3862
|
-
|
|
3930
|
+
padding: 10px 14px;
|
|
3931
|
+
background: white;
|
|
3932
|
+
border: 1px solid #eaeaef;
|
|
3933
|
+
border-radius: 8px;
|
|
3863
3934
|
`;
|
|
3864
3935
|
const SessionMeta = styled__default.default.div`
|
|
3865
3936
|
display: flex;
|
|
@@ -3965,6 +4036,7 @@ function UserDetailDrawer({
|
|
|
3965
4036
|
const [banExpiresDays, setBanExpiresDays] = react.useState("");
|
|
3966
4037
|
const [confirmRevokeAll, setConfirmRevokeAll] = react.useState(false);
|
|
3967
4038
|
const [confirmRevokeSessionId, setConfirmRevokeSessionId] = react.useState(null);
|
|
4039
|
+
const [confirmBan, setConfirmBan] = react.useState(false);
|
|
3968
4040
|
const [confirmUnban, setConfirmUnban] = react.useState(false);
|
|
3969
4041
|
const [confirmUnlinkAccountId, setConfirmUnlinkAccountId] = react.useState(null);
|
|
3970
4042
|
const [confirmDisable2FA, setConfirmDisable2FA] = react.useState(false);
|
|
@@ -3988,33 +4060,18 @@ function UserDetailDrawer({
|
|
|
3988
4060
|
};
|
|
3989
4061
|
const updateMutation = reactQuery.useMutation({
|
|
3990
4062
|
mutationFn: async () => {
|
|
3991
|
-
const
|
|
3992
|
-
if (editName !== void 0)
|
|
3993
|
-
if (editEmail !== void 0)
|
|
4063
|
+
const body = { ...editExtra };
|
|
4064
|
+
if (editName !== void 0) body.name = editName;
|
|
4065
|
+
if (editEmail !== void 0) body.email = editEmail;
|
|
3994
4066
|
if (editEmailVerified !== void 0)
|
|
3995
|
-
|
|
3996
|
-
if (editImage !== void 0)
|
|
3997
|
-
const
|
|
3998
|
-
if (
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
})
|
|
4004
|
-
);
|
|
4005
|
-
}
|
|
4006
|
-
if (Object.keys(editExtra).length > 0) {
|
|
4007
|
-
const documentId = strapiUserQuery.data?.documentId;
|
|
4008
|
-
if (!documentId)
|
|
4009
|
-
throw new Error("Could not resolve documentId for user");
|
|
4010
|
-
ops.push(
|
|
4011
|
-
put(
|
|
4012
|
-
`/better-auth-dashboard/db/${documentId}?uid=plugin::better-auth.user`,
|
|
4013
|
-
editExtra
|
|
4014
|
-
)
|
|
4015
|
-
);
|
|
4016
|
-
}
|
|
4017
|
-
await Promise.all(ops);
|
|
4067
|
+
body.emailVerified = editEmailVerified;
|
|
4068
|
+
if (editImage !== void 0) body.image = editImage;
|
|
4069
|
+
const documentId = strapiUserQuery.data?.documentId;
|
|
4070
|
+
if (!documentId) throw new Error("Could not resolve documentId for user");
|
|
4071
|
+
await put(
|
|
4072
|
+
`/better-auth-dashboard/db/${documentId}?uid=plugin::better-auth.user`,
|
|
4073
|
+
body
|
|
4074
|
+
);
|
|
4018
4075
|
},
|
|
4019
4076
|
onSuccess: () => {
|
|
4020
4077
|
qc.invalidateQueries({ queryKey: ["dash-user", userId] });
|
|
@@ -4042,7 +4099,7 @@ function UserDetailDrawer({
|
|
|
4042
4099
|
mutationFn: async (sessionId) => {
|
|
4043
4100
|
const result = await client.dash.sessions.revoke(
|
|
4044
4101
|
{},
|
|
4045
|
-
withContext({ sessionId })
|
|
4102
|
+
withContext({ sessionId, userId })
|
|
4046
4103
|
);
|
|
4047
4104
|
if (result.error)
|
|
4048
4105
|
throw new Error(result.error.message ?? "Revoke failed");
|
|
@@ -4096,6 +4153,7 @@ function UserDetailDrawer({
|
|
|
4096
4153
|
return result.data;
|
|
4097
4154
|
},
|
|
4098
4155
|
onSuccess: () => {
|
|
4156
|
+
setConfirmBan(false);
|
|
4099
4157
|
qc.invalidateQueries({ queryKey: ["dash-user", userId] });
|
|
4100
4158
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
4101
4159
|
setBanReason("");
|
|
@@ -4711,7 +4769,8 @@ function UserDetailDrawer({
|
|
|
4711
4769
|
] })
|
|
4712
4770
|
] })
|
|
4713
4771
|
] }) }),
|
|
4714
|
-
banEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "ban", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap:
|
|
4772
|
+
banEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "ban", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 5, paddingTop: 6, children: user?.banned ? /* @__PURE__ */ jsxRuntime.jsxs(FormSection, { children: [
|
|
4773
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Ban status" }),
|
|
4715
4774
|
/* @__PURE__ */ jsxRuntime.jsxs(WarnCard, { children: [
|
|
4716
4775
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4717
4776
|
designSystem.Typography,
|
|
@@ -4726,7 +4785,7 @@ function UserDetailDrawer({
|
|
|
4726
4785
|
"Reason: ",
|
|
4727
4786
|
user.banReason
|
|
4728
4787
|
] }),
|
|
4729
|
-
user.banExpires
|
|
4788
|
+
user.banExpires ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", textColor: "danger600", children: [
|
|
4730
4789
|
"Expires:",
|
|
4731
4790
|
" ",
|
|
4732
4791
|
new Date(user.banExpires).toLocaleDateString(
|
|
@@ -4738,8 +4797,7 @@ function UserDetailDrawer({
|
|
|
4738
4797
|
day: "numeric"
|
|
4739
4798
|
}
|
|
4740
4799
|
)
|
|
4741
|
-
] }),
|
|
4742
|
-
!user.banExpires && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "danger600", children: "Duration: Permanent" })
|
|
4800
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "danger600", children: "Duration: Permanent" })
|
|
4743
4801
|
] }),
|
|
4744
4802
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4745
4803
|
designSystem.Button,
|
|
@@ -4749,27 +4807,28 @@ function UserDetailDrawer({
|
|
|
4749
4807
|
children: "Lift ban"
|
|
4750
4808
|
}
|
|
4751
4809
|
) })
|
|
4752
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4810
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(FormSection, { children: [
|
|
4811
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Apply ban" }),
|
|
4812
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4813
|
+
designSystem.Field.Root,
|
|
4814
|
+
{
|
|
4815
|
+
hint: "Optional — will be shown to the user",
|
|
4816
|
+
style: { width: "100%" },
|
|
4817
|
+
children: [
|
|
4818
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Reason" }),
|
|
4819
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4820
|
+
designSystem.TextInput,
|
|
4821
|
+
{
|
|
4822
|
+
value: banReason,
|
|
4823
|
+
onChange: (e) => setBanReason(e.target.value),
|
|
4824
|
+
placeholder: "e.g. Violated terms of service"
|
|
4825
|
+
}
|
|
4826
|
+
),
|
|
4827
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
|
|
4828
|
+
]
|
|
4829
|
+
}
|
|
4830
|
+
),
|
|
4753
4831
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Grid.Root, { gap: 4, children: [
|
|
4754
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 12, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4755
|
-
designSystem.Field.Root,
|
|
4756
|
-
{
|
|
4757
|
-
hint: "Optional — will be shown to the user",
|
|
4758
|
-
style: { width: "100%" },
|
|
4759
|
-
children: [
|
|
4760
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Reason" }),
|
|
4761
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4762
|
-
designSystem.TextInput,
|
|
4763
|
-
{
|
|
4764
|
-
value: banReason,
|
|
4765
|
-
onChange: (e) => setBanReason(e.target.value),
|
|
4766
|
-
placeholder: "e.g. Violated terms of service"
|
|
4767
|
-
}
|
|
4768
|
-
),
|
|
4769
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
|
|
4770
|
-
]
|
|
4771
|
-
}
|
|
4772
|
-
) }),
|
|
4773
4832
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4774
4833
|
designSystem.Field.Root,
|
|
4775
4834
|
{
|
|
@@ -4790,24 +4849,13 @@ function UserDetailDrawer({
|
|
|
4790
4849
|
]
|
|
4791
4850
|
}
|
|
4792
4851
|
) }),
|
|
4793
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, children:
|
|
4794
|
-
designSystem.Flex,
|
|
4795
|
-
{
|
|
4796
|
-
direction: "column",
|
|
4797
|
-
justifyContent: "flex-end",
|
|
4798
|
-
style: { height: "100%", paddingBottom: 4 },
|
|
4799
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(PreviewPill, { children: [
|
|
4800
|
-
"⏱ Expires ",
|
|
4801
|
-
banExpiryPreview
|
|
4802
|
-
] })
|
|
4803
|
-
}
|
|
4804
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
4852
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4805
4853
|
designSystem.Flex,
|
|
4806
4854
|
{
|
|
4807
4855
|
direction: "column",
|
|
4808
4856
|
justifyContent: "flex-end",
|
|
4809
4857
|
style: { height: "100%", paddingBottom: 4 },
|
|
4810
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(PreviewPill, { children: "♾ Permanent ban" })
|
|
4858
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(PreviewPill, { children: banExpiryPreview ? `⏱ Expires ${banExpiryPreview}` : "♾ Permanent ban" })
|
|
4811
4859
|
}
|
|
4812
4860
|
) })
|
|
4813
4861
|
] }),
|
|
@@ -4815,8 +4863,7 @@ function UserDetailDrawer({
|
|
|
4815
4863
|
designSystem.Button,
|
|
4816
4864
|
{
|
|
4817
4865
|
variant: "danger",
|
|
4818
|
-
|
|
4819
|
-
onClick: () => banMutation.mutate(),
|
|
4866
|
+
onClick: () => setConfirmBan(true),
|
|
4820
4867
|
children: "Ban user"
|
|
4821
4868
|
}
|
|
4822
4869
|
) })
|
|
@@ -4843,19 +4890,27 @@ function UserDetailDrawer({
|
|
|
4843
4890
|
] }),
|
|
4844
4891
|
/* @__PURE__ */ jsxRuntime.jsxs(FormSection, { children: [
|
|
4845
4892
|
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Active sessions" }),
|
|
4846
|
-
sessionsQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: "Loading sessions…" }) }) : (sessionsQuery.data ?? []).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: "No active sessions." }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap:
|
|
4893
|
+
sessionsQuery.isLoading ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", padding: 4, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { children: "Loading sessions…" }) }) : (sessionsQuery.data ?? []).length === 0 ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", children: "No active sessions." }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap: 2, alignItems: "stretch", children: (sessionsQuery.data ?? []).map((session) => /* @__PURE__ */ jsxRuntime.jsxs(SessionCard, { children: [
|
|
4847
4894
|
/* @__PURE__ */ jsxRuntime.jsxs(SessionMeta, { children: [
|
|
4848
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4895
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4896
|
+
designSystem.Flex,
|
|
4897
|
+
{
|
|
4898
|
+
gap: 2,
|
|
4899
|
+
alignItems: "center",
|
|
4900
|
+
style: { flexWrap: "wrap" },
|
|
4901
|
+
children: [
|
|
4902
|
+
session.ipAddress && /* @__PURE__ */ jsxRuntime.jsx(IpChip, { children: session.ipAddress }),
|
|
4903
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimestampText, { children: [
|
|
4904
|
+
"Created",
|
|
4905
|
+
" ",
|
|
4906
|
+
new Date(session.createdAt).toLocaleString(),
|
|
4907
|
+
" · Expires",
|
|
4908
|
+
" ",
|
|
4909
|
+
new Date(session.expiresAt).toLocaleString()
|
|
4910
|
+
] })
|
|
4911
|
+
]
|
|
4912
|
+
}
|
|
4913
|
+
),
|
|
4859
4914
|
session.userAgent && /* @__PURE__ */ jsxRuntime.jsx(AgentText, { children: session.userAgent })
|
|
4860
4915
|
] }),
|
|
4861
4916
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4917,6 +4972,18 @@ function UserDetailDrawer({
|
|
|
4917
4972
|
onCancel: () => setConfirmRevokeSessionId(null)
|
|
4918
4973
|
}
|
|
4919
4974
|
),
|
|
4975
|
+
confirmBan && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4976
|
+
ConfirmDialog,
|
|
4977
|
+
{
|
|
4978
|
+
title: "Ban user",
|
|
4979
|
+
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.",
|
|
4980
|
+
confirmLabel: "Ban user",
|
|
4981
|
+
variant: "danger",
|
|
4982
|
+
loading: banMutation.isLoading,
|
|
4983
|
+
onConfirm: () => banMutation.mutate(),
|
|
4984
|
+
onCancel: () => setConfirmBan(false)
|
|
4985
|
+
}
|
|
4986
|
+
),
|
|
4920
4987
|
confirmUnban && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4921
4988
|
ConfirmDialog,
|
|
4922
4989
|
{
|
|
@@ -5147,6 +5214,7 @@ const Toolbar = styled__default.default.div`
|
|
|
5147
5214
|
`;
|
|
5148
5215
|
function UsersPage({ config }) {
|
|
5149
5216
|
const qc = reactQuery.useQueryClient();
|
|
5217
|
+
const { toggleNotification } = admin.useNotification();
|
|
5150
5218
|
const banEnabled = hasPlugin(config, "admin");
|
|
5151
5219
|
const emailVerificationEnabled = config.emailVerification.sendVerificationEmailEnabled;
|
|
5152
5220
|
const twoFactorEnabled = hasPlugin(config, "two-factor");
|
|
@@ -5178,6 +5246,13 @@ function UsersPage({ config }) {
|
|
|
5178
5246
|
setConfirmDelete(null);
|
|
5179
5247
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
5180
5248
|
qc.invalidateQueries({ queryKey: ["dash-user-stats"] });
|
|
5249
|
+
toggleNotification({ type: "success", message: "User deleted" });
|
|
5250
|
+
},
|
|
5251
|
+
onError: (err) => {
|
|
5252
|
+
toggleNotification({
|
|
5253
|
+
type: "danger",
|
|
5254
|
+
message: err.message ?? "Failed to delete user"
|
|
5255
|
+
});
|
|
5181
5256
|
}
|
|
5182
5257
|
});
|
|
5183
5258
|
const deleteManyMutation = reactQuery.useMutation({
|
|
@@ -5190,11 +5265,21 @@ function UsersPage({ config }) {
|
|
|
5190
5265
|
throw new Error(result.error.message ?? "Delete failed");
|
|
5191
5266
|
return result.data;
|
|
5192
5267
|
},
|
|
5193
|
-
onSuccess: () => {
|
|
5268
|
+
onSuccess: (_data, userIds) => {
|
|
5194
5269
|
setConfirmDeleteMany(false);
|
|
5195
5270
|
setSelected(/* @__PURE__ */ new Set());
|
|
5196
5271
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
5197
5272
|
qc.invalidateQueries({ queryKey: ["dash-user-stats"] });
|
|
5273
|
+
toggleNotification({
|
|
5274
|
+
type: "success",
|
|
5275
|
+
message: `${userIds.length} user${userIds.length !== 1 ? "s" : ""} deleted`
|
|
5276
|
+
});
|
|
5277
|
+
},
|
|
5278
|
+
onError: (err) => {
|
|
5279
|
+
toggleNotification({
|
|
5280
|
+
type: "danger",
|
|
5281
|
+
message: err.message ?? "Failed to delete users"
|
|
5282
|
+
});
|
|
5198
5283
|
}
|
|
5199
5284
|
});
|
|
5200
5285
|
const banManyMutation = reactQuery.useMutation({
|
|
@@ -5206,10 +5291,20 @@ function UsersPage({ config }) {
|
|
|
5206
5291
|
if (result.error) throw new Error(result.error.message ?? "Ban failed");
|
|
5207
5292
|
return result.data;
|
|
5208
5293
|
},
|
|
5209
|
-
onSuccess: () => {
|
|
5294
|
+
onSuccess: (_data, userIds) => {
|
|
5210
5295
|
setConfirmBanMany(false);
|
|
5211
5296
|
setSelected(/* @__PURE__ */ new Set());
|
|
5212
5297
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
5298
|
+
toggleNotification({
|
|
5299
|
+
type: "success",
|
|
5300
|
+
message: `${userIds.length} user${userIds.length !== 1 ? "s" : ""} banned`
|
|
5301
|
+
});
|
|
5302
|
+
},
|
|
5303
|
+
onError: (err) => {
|
|
5304
|
+
toggleNotification({
|
|
5305
|
+
type: "danger",
|
|
5306
|
+
message: err.message ?? "Failed to ban users"
|
|
5307
|
+
});
|
|
5213
5308
|
}
|
|
5214
5309
|
});
|
|
5215
5310
|
const toggleSelect = (id) => {
|
|
@@ -5388,14 +5483,28 @@ function UsersPage({ config }) {
|
|
|
5388
5483
|
user.id
|
|
5389
5484
|
)) })
|
|
5390
5485
|
] }) }),
|
|
5391
|
-
pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5486
|
+
pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
|
5487
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5488
|
+
designSystem.Button,
|
|
5489
|
+
{
|
|
5490
|
+
variant: "tertiary",
|
|
5491
|
+
size: "S",
|
|
5492
|
+
disabled: page === 1,
|
|
5493
|
+
onClick: () => setPage((p) => p - 1),
|
|
5494
|
+
children: "Previous"
|
|
5495
|
+
}
|
|
5496
|
+
),
|
|
5497
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5498
|
+
designSystem.Button,
|
|
5499
|
+
{
|
|
5500
|
+
variant: "tertiary",
|
|
5501
|
+
size: "S",
|
|
5502
|
+
disabled: page >= pageCount,
|
|
5503
|
+
onClick: () => setPage((p) => p + 1),
|
|
5504
|
+
children: "Next"
|
|
5505
|
+
}
|
|
5506
|
+
)
|
|
5507
|
+
] }) }),
|
|
5399
5508
|
showCreate && /* @__PURE__ */ jsxRuntime.jsx(CreateUserDialog, { onClose: () => setShowCreate(false) }),
|
|
5400
5509
|
detailUserId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5401
5510
|
UserDetailDrawer,
|