@strapi-community/plugin-better-auth-dashboard 1.0.0-alpha.3 → 1.0.0-alpha.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/{Root-BnRbzS-u.js → Root-7EredGQZ.js} +258 -150
- package/dist/admin/{Root-DBjGZL7H.mjs → Root-B1LuKMEv.mjs} +259 -151
- package/dist/admin/{index-xZ2FHX3i.js → index-CIxfFlzU.js} +1 -1
- package/dist/admin/{index-BpruO4vo.mjs → index-QVlTR8eL.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-CIxfFlzU.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);
|
|
@@ -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 : [];
|
|
@@ -3273,6 +3302,42 @@ 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
|
+
if (!lastActiveByUserId.has(s.userId)) {
|
|
3310
|
+
lastActiveByUserId.set(s.userId, s.createdAt);
|
|
3311
|
+
activeUserIds.push(s.userId);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
const activeUsersQuery = reactQuery.useQuery({
|
|
3315
|
+
queryKey: ["dash-active-users", activeUserIds],
|
|
3316
|
+
queryFn: async () => {
|
|
3317
|
+
if (activeUserIds.length === 0) return [];
|
|
3318
|
+
const params = new URLSearchParams({ uid: "plugin::better-auth.user" });
|
|
3319
|
+
for (let i = 0; i < activeUserIds.length; i++) {
|
|
3320
|
+
params.set(`filters[id][$in][${i}]`, activeUserIds[i]);
|
|
3321
|
+
}
|
|
3322
|
+
params.set("pagination[pageSize]", "12");
|
|
3323
|
+
const { data } = await get(
|
|
3324
|
+
`/better-auth-dashboard/db?${params}`
|
|
3325
|
+
);
|
|
3326
|
+
return data.results ?? [];
|
|
3327
|
+
},
|
|
3328
|
+
enabled: feedMode === "active" && activeUserIds.length > 0
|
|
3329
|
+
});
|
|
3330
|
+
const chartRef = react.useRef(null);
|
|
3331
|
+
const [chartHeight, setChartHeight] = react.useState(0);
|
|
3332
|
+
react.useEffect(() => {
|
|
3333
|
+
const el = chartRef.current;
|
|
3334
|
+
if (!el) return;
|
|
3335
|
+
const ro = new ResizeObserver((entries) => {
|
|
3336
|
+
for (const entry of entries) setChartHeight(entry.contentRect.height);
|
|
3337
|
+
});
|
|
3338
|
+
ro.observe(el);
|
|
3339
|
+
return () => ro.disconnect();
|
|
3340
|
+
}, []);
|
|
3276
3341
|
if (statsQuery.isLoading) {
|
|
3277
3342
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3278
3343
|
designSystem.Flex,
|
|
@@ -3290,8 +3355,12 @@ function OverviewPage() {
|
|
|
3290
3355
|
const graphData = graphQuery.data?.data ?? [];
|
|
3291
3356
|
const rtnData = retentionQuery.data?.data ?? [];
|
|
3292
3357
|
const users = usersQuery.data?.users ?? [];
|
|
3293
|
-
const sessions = sessionsQuery.data ?? [];
|
|
3294
3358
|
const orgCount = orgsQuery.data?.total ?? 0;
|
|
3359
|
+
const activeUserMap = /* @__PURE__ */ new Map();
|
|
3360
|
+
for (const u of activeUsersQuery.data ?? []) {
|
|
3361
|
+
activeUserMap.set(String(u.id), u);
|
|
3362
|
+
}
|
|
3363
|
+
const sortedActiveUsers = activeUserIds.map((uid) => activeUserMap.get(uid)).filter((u) => u !== void 0);
|
|
3295
3364
|
const totalSpark = graphData.map((d) => d.totalUsers);
|
|
3296
3365
|
const newSpark = graphData.map((d) => d.newUsers);
|
|
3297
3366
|
const activeSpark = graphData.map((d) => d.activeUsers);
|
|
@@ -3395,7 +3464,7 @@ function OverviewPage() {
|
|
|
3395
3464
|
/* @__PURE__ */ jsxRuntime.jsx(DivLine, {})
|
|
3396
3465
|
] }),
|
|
3397
3466
|
/* @__PURE__ */ jsxRuntime.jsxs(TwoPanel, { children: [
|
|
3398
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ChartCard, { $delay: 5, children: [
|
|
3467
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ChartCard, { ref: chartRef, $delay: 5, children: [
|
|
3399
3468
|
/* @__PURE__ */ jsxRuntime.jsxs(ChartHeader, { children: [
|
|
3400
3469
|
/* @__PURE__ */ jsxRuntime.jsx(ChartTitle, { children: "User Growth" }),
|
|
3401
3470
|
/* @__PURE__ */ jsxRuntime.jsx(SeriesRow, { children: ALL_SERIES.map((s) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -3431,57 +3500,57 @@ function OverviewPage() {
|
|
|
3431
3500
|
}
|
|
3432
3501
|
)
|
|
3433
3502
|
] }),
|
|
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 })
|
|
3503
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3504
|
+
FeedCard,
|
|
3505
|
+
{
|
|
3506
|
+
$delay: 6,
|
|
3507
|
+
style: chartHeight > 0 ? { height: chartHeight } : void 0,
|
|
3508
|
+
children: [
|
|
3509
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FeedHead, { children: [
|
|
3510
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: feedMode === "signups" ? "Recent Sign-ups" : "Recently Active" }),
|
|
3511
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3512
|
+
FeedSelect,
|
|
3513
|
+
{
|
|
3514
|
+
value: feedMode,
|
|
3515
|
+
onChange: (e) => setFeedMode(e.target.value),
|
|
3516
|
+
children: [
|
|
3517
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "signups", children: "Recent Sign-ups" }),
|
|
3518
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "active", children: "Recently Active" })
|
|
3519
|
+
]
|
|
3520
|
+
}
|
|
3521
|
+
)
|
|
3454
3522
|
] }),
|
|
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
|
-
|
|
3523
|
+
/* @__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: [
|
|
3524
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FeedTop, { children: [
|
|
3525
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 1, style: { minWidth: 0 }, children: [
|
|
3526
|
+
/* @__PURE__ */ jsxRuntime.jsx(Avatar, { name: u.name, src: u.image, size: 20 }),
|
|
3527
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedName, { title: u.name, children: u.name })
|
|
3528
|
+
] }),
|
|
3529
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedMeta, { children: relTime(u.createdAt) })
|
|
3530
|
+
] }),
|
|
3531
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedEmail, { title: u.email, children: u.email })
|
|
3532
|
+
] }, 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: [
|
|
3533
|
+
/* @__PURE__ */ jsxRuntime.jsxs(FeedTop, { children: [
|
|
3534
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "center", gap: 1, style: { minWidth: 0 }, children: [
|
|
3535
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3536
|
+
Avatar,
|
|
3537
|
+
{
|
|
3538
|
+
name: u.name,
|
|
3539
|
+
src: u.image ?? void 0,
|
|
3540
|
+
size: 20
|
|
3541
|
+
}
|
|
3542
|
+
),
|
|
3543
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedName, { title: u.name, children: u.name })
|
|
3544
|
+
] }),
|
|
3545
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedMeta, { children: relTime(
|
|
3546
|
+
lastActiveByUserId.get(String(u.id)) ?? u.createdAt
|
|
3547
|
+
) })
|
|
3548
|
+
] }),
|
|
3549
|
+
/* @__PURE__ */ jsxRuntime.jsx(FeedEmail, { title: u.email, children: u.email })
|
|
3550
|
+
] }, u.documentId)) })
|
|
3551
|
+
]
|
|
3552
|
+
}
|
|
3553
|
+
)
|
|
3485
3554
|
] }),
|
|
3486
3555
|
/* @__PURE__ */ jsxRuntime.jsxs(SectionDivider, { children: [
|
|
3487
3556
|
/* @__PURE__ */ jsxRuntime.jsx(DivLabel, { children: "Retention & Activity" }),
|
|
@@ -3857,9 +3926,10 @@ const SessionCard = styled__default.default.div`
|
|
|
3857
3926
|
align-items: flex-start;
|
|
3858
3927
|
justify-content: space-between;
|
|
3859
3928
|
gap: 12px;
|
|
3860
|
-
padding: 10px
|
|
3861
|
-
|
|
3862
|
-
|
|
3929
|
+
padding: 10px 14px;
|
|
3930
|
+
background: white;
|
|
3931
|
+
border: 1px solid #eaeaef;
|
|
3932
|
+
border-radius: 8px;
|
|
3863
3933
|
`;
|
|
3864
3934
|
const SessionMeta = styled__default.default.div`
|
|
3865
3935
|
display: flex;
|
|
@@ -3965,6 +4035,7 @@ function UserDetailDrawer({
|
|
|
3965
4035
|
const [banExpiresDays, setBanExpiresDays] = react.useState("");
|
|
3966
4036
|
const [confirmRevokeAll, setConfirmRevokeAll] = react.useState(false);
|
|
3967
4037
|
const [confirmRevokeSessionId, setConfirmRevokeSessionId] = react.useState(null);
|
|
4038
|
+
const [confirmBan, setConfirmBan] = react.useState(false);
|
|
3968
4039
|
const [confirmUnban, setConfirmUnban] = react.useState(false);
|
|
3969
4040
|
const [confirmUnlinkAccountId, setConfirmUnlinkAccountId] = react.useState(null);
|
|
3970
4041
|
const [confirmDisable2FA, setConfirmDisable2FA] = react.useState(false);
|
|
@@ -3988,33 +4059,18 @@ function UserDetailDrawer({
|
|
|
3988
4059
|
};
|
|
3989
4060
|
const updateMutation = reactQuery.useMutation({
|
|
3990
4061
|
mutationFn: async () => {
|
|
3991
|
-
const
|
|
3992
|
-
if (editName !== void 0)
|
|
3993
|
-
if (editEmail !== void 0)
|
|
4062
|
+
const body = { ...editExtra };
|
|
4063
|
+
if (editName !== void 0) body.name = editName;
|
|
4064
|
+
if (editEmail !== void 0) body.email = editEmail;
|
|
3994
4065
|
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);
|
|
4066
|
+
body.emailVerified = editEmailVerified;
|
|
4067
|
+
if (editImage !== void 0) body.image = editImage;
|
|
4068
|
+
const documentId = strapiUserQuery.data?.documentId;
|
|
4069
|
+
if (!documentId) throw new Error("Could not resolve documentId for user");
|
|
4070
|
+
await put(
|
|
4071
|
+
`/better-auth-dashboard/db/${documentId}?uid=plugin::better-auth.user`,
|
|
4072
|
+
body
|
|
4073
|
+
);
|
|
4018
4074
|
},
|
|
4019
4075
|
onSuccess: () => {
|
|
4020
4076
|
qc.invalidateQueries({ queryKey: ["dash-user", userId] });
|
|
@@ -4096,6 +4152,7 @@ function UserDetailDrawer({
|
|
|
4096
4152
|
return result.data;
|
|
4097
4153
|
},
|
|
4098
4154
|
onSuccess: () => {
|
|
4155
|
+
setConfirmBan(false);
|
|
4099
4156
|
qc.invalidateQueries({ queryKey: ["dash-user", userId] });
|
|
4100
4157
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
4101
4158
|
setBanReason("");
|
|
@@ -4711,7 +4768,8 @@ function UserDetailDrawer({
|
|
|
4711
4768
|
] })
|
|
4712
4769
|
] })
|
|
4713
4770
|
] }) }),
|
|
4714
|
-
banEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tabs.Content, { value: "ban", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", gap:
|
|
4771
|
+
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: [
|
|
4772
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Ban status" }),
|
|
4715
4773
|
/* @__PURE__ */ jsxRuntime.jsxs(WarnCard, { children: [
|
|
4716
4774
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4717
4775
|
designSystem.Typography,
|
|
@@ -4726,7 +4784,7 @@ function UserDetailDrawer({
|
|
|
4726
4784
|
"Reason: ",
|
|
4727
4785
|
user.banReason
|
|
4728
4786
|
] }),
|
|
4729
|
-
user.banExpires
|
|
4787
|
+
user.banExpires ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", textColor: "danger600", children: [
|
|
4730
4788
|
"Expires:",
|
|
4731
4789
|
" ",
|
|
4732
4790
|
new Date(user.banExpires).toLocaleDateString(
|
|
@@ -4738,8 +4796,7 @@ function UserDetailDrawer({
|
|
|
4738
4796
|
day: "numeric"
|
|
4739
4797
|
}
|
|
4740
4798
|
)
|
|
4741
|
-
] }),
|
|
4742
|
-
!user.banExpires && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "danger600", children: "Duration: Permanent" })
|
|
4799
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "danger600", children: "Duration: Permanent" })
|
|
4743
4800
|
] }),
|
|
4744
4801
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4745
4802
|
designSystem.Button,
|
|
@@ -4749,27 +4806,28 @@ function UserDetailDrawer({
|
|
|
4749
4806
|
children: "Lift ban"
|
|
4750
4807
|
}
|
|
4751
4808
|
) })
|
|
4752
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4809
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(FormSection, { children: [
|
|
4810
|
+
/* @__PURE__ */ jsxRuntime.jsx(SectionLabel, { children: "Apply ban" }),
|
|
4811
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4812
|
+
designSystem.Field.Root,
|
|
4813
|
+
{
|
|
4814
|
+
hint: "Optional — will be shown to the user",
|
|
4815
|
+
style: { width: "100%" },
|
|
4816
|
+
children: [
|
|
4817
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Label, { children: "Reason" }),
|
|
4818
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4819
|
+
designSystem.TextInput,
|
|
4820
|
+
{
|
|
4821
|
+
value: banReason,
|
|
4822
|
+
onChange: (e) => setBanReason(e.target.value),
|
|
4823
|
+
placeholder: "e.g. Violated terms of service"
|
|
4824
|
+
}
|
|
4825
|
+
),
|
|
4826
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Field.Hint, {})
|
|
4827
|
+
]
|
|
4828
|
+
}
|
|
4829
|
+
),
|
|
4753
4830
|
/* @__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
4831
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4774
4832
|
designSystem.Field.Root,
|
|
4775
4833
|
{
|
|
@@ -4790,24 +4848,13 @@ function UserDetailDrawer({
|
|
|
4790
4848
|
]
|
|
4791
4849
|
}
|
|
4792
4850
|
) }),
|
|
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(
|
|
4851
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Grid.Item, { col: 6, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
4805
4852
|
designSystem.Flex,
|
|
4806
4853
|
{
|
|
4807
4854
|
direction: "column",
|
|
4808
4855
|
justifyContent: "flex-end",
|
|
4809
4856
|
style: { height: "100%", paddingBottom: 4 },
|
|
4810
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(PreviewPill, { children: "♾ Permanent ban" })
|
|
4857
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(PreviewPill, { children: banExpiryPreview ? `⏱ Expires ${banExpiryPreview}` : "♾ Permanent ban" })
|
|
4811
4858
|
}
|
|
4812
4859
|
) })
|
|
4813
4860
|
] }),
|
|
@@ -4815,8 +4862,7 @@ function UserDetailDrawer({
|
|
|
4815
4862
|
designSystem.Button,
|
|
4816
4863
|
{
|
|
4817
4864
|
variant: "danger",
|
|
4818
|
-
|
|
4819
|
-
onClick: () => banMutation.mutate(),
|
|
4865
|
+
onClick: () => setConfirmBan(true),
|
|
4820
4866
|
children: "Ban user"
|
|
4821
4867
|
}
|
|
4822
4868
|
) })
|
|
@@ -4843,19 +4889,27 @@ function UserDetailDrawer({
|
|
|
4843
4889
|
] }),
|
|
4844
4890
|
/* @__PURE__ */ jsxRuntime.jsxs(FormSection, { children: [
|
|
4845
4891
|
/* @__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:
|
|
4892
|
+
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
4893
|
/* @__PURE__ */ jsxRuntime.jsxs(SessionMeta, { children: [
|
|
4848
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4849
|
-
|
|
4850
|
-
|
|
4851
|
-
|
|
4852
|
-
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
|
|
4894
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4895
|
+
designSystem.Flex,
|
|
4896
|
+
{
|
|
4897
|
+
gap: 2,
|
|
4898
|
+
alignItems: "center",
|
|
4899
|
+
style: { flexWrap: "wrap" },
|
|
4900
|
+
children: [
|
|
4901
|
+
session.ipAddress && /* @__PURE__ */ jsxRuntime.jsx(IpChip, { children: session.ipAddress }),
|
|
4902
|
+
/* @__PURE__ */ jsxRuntime.jsxs(TimestampText, { children: [
|
|
4903
|
+
"Created",
|
|
4904
|
+
" ",
|
|
4905
|
+
new Date(session.createdAt).toLocaleString(),
|
|
4906
|
+
" · Expires",
|
|
4907
|
+
" ",
|
|
4908
|
+
new Date(session.expiresAt).toLocaleString()
|
|
4909
|
+
] })
|
|
4910
|
+
]
|
|
4911
|
+
}
|
|
4912
|
+
),
|
|
4859
4913
|
session.userAgent && /* @__PURE__ */ jsxRuntime.jsx(AgentText, { children: session.userAgent })
|
|
4860
4914
|
] }),
|
|
4861
4915
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -4917,6 +4971,18 @@ function UserDetailDrawer({
|
|
|
4917
4971
|
onCancel: () => setConfirmRevokeSessionId(null)
|
|
4918
4972
|
}
|
|
4919
4973
|
),
|
|
4974
|
+
confirmBan && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4975
|
+
ConfirmDialog,
|
|
4976
|
+
{
|
|
4977
|
+
title: "Ban user",
|
|
4978
|
+
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.",
|
|
4979
|
+
confirmLabel: "Ban user",
|
|
4980
|
+
variant: "danger",
|
|
4981
|
+
loading: banMutation.isLoading,
|
|
4982
|
+
onConfirm: () => banMutation.mutate(),
|
|
4983
|
+
onCancel: () => setConfirmBan(false)
|
|
4984
|
+
}
|
|
4985
|
+
),
|
|
4920
4986
|
confirmUnban && /* @__PURE__ */ jsxRuntime.jsx(
|
|
4921
4987
|
ConfirmDialog,
|
|
4922
4988
|
{
|
|
@@ -5147,6 +5213,7 @@ const Toolbar = styled__default.default.div`
|
|
|
5147
5213
|
`;
|
|
5148
5214
|
function UsersPage({ config }) {
|
|
5149
5215
|
const qc = reactQuery.useQueryClient();
|
|
5216
|
+
const { toggleNotification } = admin.useNotification();
|
|
5150
5217
|
const banEnabled = hasPlugin(config, "admin");
|
|
5151
5218
|
const emailVerificationEnabled = config.emailVerification.sendVerificationEmailEnabled;
|
|
5152
5219
|
const twoFactorEnabled = hasPlugin(config, "two-factor");
|
|
@@ -5178,6 +5245,13 @@ function UsersPage({ config }) {
|
|
|
5178
5245
|
setConfirmDelete(null);
|
|
5179
5246
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
5180
5247
|
qc.invalidateQueries({ queryKey: ["dash-user-stats"] });
|
|
5248
|
+
toggleNotification({ type: "success", message: "User deleted" });
|
|
5249
|
+
},
|
|
5250
|
+
onError: (err) => {
|
|
5251
|
+
toggleNotification({
|
|
5252
|
+
type: "danger",
|
|
5253
|
+
message: err.message ?? "Failed to delete user"
|
|
5254
|
+
});
|
|
5181
5255
|
}
|
|
5182
5256
|
});
|
|
5183
5257
|
const deleteManyMutation = reactQuery.useMutation({
|
|
@@ -5190,11 +5264,21 @@ function UsersPage({ config }) {
|
|
|
5190
5264
|
throw new Error(result.error.message ?? "Delete failed");
|
|
5191
5265
|
return result.data;
|
|
5192
5266
|
},
|
|
5193
|
-
onSuccess: () => {
|
|
5267
|
+
onSuccess: (_data, userIds) => {
|
|
5194
5268
|
setConfirmDeleteMany(false);
|
|
5195
5269
|
setSelected(/* @__PURE__ */ new Set());
|
|
5196
5270
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
5197
5271
|
qc.invalidateQueries({ queryKey: ["dash-user-stats"] });
|
|
5272
|
+
toggleNotification({
|
|
5273
|
+
type: "success",
|
|
5274
|
+
message: `${userIds.length} user${userIds.length !== 1 ? "s" : ""} deleted`
|
|
5275
|
+
});
|
|
5276
|
+
},
|
|
5277
|
+
onError: (err) => {
|
|
5278
|
+
toggleNotification({
|
|
5279
|
+
type: "danger",
|
|
5280
|
+
message: err.message ?? "Failed to delete users"
|
|
5281
|
+
});
|
|
5198
5282
|
}
|
|
5199
5283
|
});
|
|
5200
5284
|
const banManyMutation = reactQuery.useMutation({
|
|
@@ -5206,10 +5290,20 @@ function UsersPage({ config }) {
|
|
|
5206
5290
|
if (result.error) throw new Error(result.error.message ?? "Ban failed");
|
|
5207
5291
|
return result.data;
|
|
5208
5292
|
},
|
|
5209
|
-
onSuccess: () => {
|
|
5293
|
+
onSuccess: (_data, userIds) => {
|
|
5210
5294
|
setConfirmBanMany(false);
|
|
5211
5295
|
setSelected(/* @__PURE__ */ new Set());
|
|
5212
5296
|
qc.invalidateQueries({ queryKey: ["dash-users"] });
|
|
5297
|
+
toggleNotification({
|
|
5298
|
+
type: "success",
|
|
5299
|
+
message: `${userIds.length} user${userIds.length !== 1 ? "s" : ""} banned`
|
|
5300
|
+
});
|
|
5301
|
+
},
|
|
5302
|
+
onError: (err) => {
|
|
5303
|
+
toggleNotification({
|
|
5304
|
+
type: "danger",
|
|
5305
|
+
message: err.message ?? "Failed to ban users"
|
|
5306
|
+
});
|
|
5213
5307
|
}
|
|
5214
5308
|
});
|
|
5215
5309
|
const toggleSelect = (id) => {
|
|
@@ -5388,14 +5482,28 @@ function UsersPage({ config }) {
|
|
|
5388
5482
|
user.id
|
|
5389
5483
|
)) })
|
|
5390
5484
|
] }) }),
|
|
5391
|
-
pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.
|
|
5392
|
-
|
|
5393
|
-
|
|
5394
|
-
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5485
|
+
pageCount > 1 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
|
5486
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5487
|
+
designSystem.Button,
|
|
5488
|
+
{
|
|
5489
|
+
variant: "tertiary",
|
|
5490
|
+
size: "S",
|
|
5491
|
+
disabled: page === 1,
|
|
5492
|
+
onClick: () => setPage((p) => p - 1),
|
|
5493
|
+
children: "Previous"
|
|
5494
|
+
}
|
|
5495
|
+
),
|
|
5496
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5497
|
+
designSystem.Button,
|
|
5498
|
+
{
|
|
5499
|
+
variant: "tertiary",
|
|
5500
|
+
size: "S",
|
|
5501
|
+
disabled: page >= pageCount,
|
|
5502
|
+
onClick: () => setPage((p) => p + 1),
|
|
5503
|
+
children: "Next"
|
|
5504
|
+
}
|
|
5505
|
+
)
|
|
5506
|
+
] }) }),
|
|
5399
5507
|
showCreate && /* @__PURE__ */ jsxRuntime.jsx(CreateUserDialog, { onClose: () => setShowCreate(false) }),
|
|
5400
5508
|
detailUserId && /* @__PURE__ */ jsxRuntime.jsx(
|
|
5401
5509
|
UserDetailDrawer,
|