strapi-plugin-magic-sessionmanager 4.0.0 → 4.0.2
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/README.md +2 -2
- package/admin/src/components/LicenseGuard.jsx +6 -6
- package/admin/src/components/OnlineUsersWidget.jsx +11 -7
- package/admin/src/components/SessionDetailModal.jsx +45 -41
- package/admin/src/components/SessionInfoCard.jsx +3 -3
- package/admin/src/components/SessionInfoPanel.jsx +31 -21
- package/admin/src/index.js +9 -0
- package/admin/src/pages/Analytics.jsx +2 -2
- package/admin/src/pages/HomePage.jsx +129 -165
- package/admin/src/pages/License.jsx +5 -5
- package/admin/src/pages/Settings.jsx +148 -144
- package/admin/src/pages/SettingsNew.jsx +21 -21
- package/admin/src/pages/UpgradePage.jsx +448 -0
- package/admin/src/pluginId.js +1 -0
- package/admin/src/translations/de.json +294 -15
- package/admin/src/translations/en.json +293 -14
- package/admin/src/translations/es.json +284 -18
- package/admin/src/translations/fr.json +284 -18
- package/admin/src/translations/pt.json +284 -18
- package/admin/src/utils/parseUserAgent.js +6 -6
- package/admin/src/utils/theme.js +85 -0
- package/dist/_chunks/{Analytics-mYu_uGwU.mjs → Analytics-DTE_zmRV.mjs} +4 -4
- package/dist/_chunks/{Analytics-ioaeEh-E.js → Analytics-lw_JaOVy.js} +4 -4
- package/dist/_chunks/{App-DdnUYWbC.js → App-DDKYCjKw.js} +221 -216
- package/dist/_chunks/{App-BXpIS12l.mjs → App-DJW1ZNl5.mjs} +221 -216
- package/dist/_chunks/{License-C03C2j9P.mjs → License-DaOFuImm.mjs} +6 -10
- package/dist/_chunks/{License-DZYrOgcx.js → License-Tk-6UfPl.js} +6 -10
- package/dist/_chunks/{OnlineUsersWidget-B8JS1xZu.js → OnlineUsersWidget-C1qTpsws.js} +11 -7
- package/dist/_chunks/{OnlineUsersWidget-ArMl0nen.mjs → OnlineUsersWidget-CADphbXG.mjs} +11 -7
- package/dist/_chunks/{Settings-0ocB3qHk.mjs → Settings-C9xvckgq.mjs} +200 -188
- package/dist/_chunks/{Settings-C6_CqpCC.js → Settings-DyEAuTNQ.js} +200 -188
- package/dist/_chunks/UpgradePage-Dssk8A0Z.js +354 -0
- package/dist/_chunks/UpgradePage-cINvE9zY.mjs +352 -0
- package/dist/_chunks/de-CDA1V0rF.mjs +292 -0
- package/dist/_chunks/de-I-Q-pWqu.js +292 -0
- package/dist/_chunks/en-Bd7_h-4e.js +292 -0
- package/dist/_chunks/en-DzmOCyzQ.mjs +292 -0
- package/dist/_chunks/es-BcAx18XG.js +277 -0
- package/dist/_chunks/es-Cx-SN6qV.mjs +277 -0
- package/dist/_chunks/fr-DCzYMuJ-.js +277 -0
- package/dist/_chunks/fr-DXlXE5Eo.mjs +277 -0
- package/dist/_chunks/{index-DC8Y0qxx.js → index-CWcvrfXc.js} +52 -49
- package/dist/_chunks/{index-DBRS3kt5.mjs → index-DQO9bNP7.mjs} +52 -49
- package/dist/_chunks/pt-21-MAb72.js +277 -0
- package/dist/_chunks/pt-zsdTSjba.mjs +277 -0
- package/dist/_chunks/{useLicense-qgGfMvse.js → useLicense-DtvJOszr.js} +1 -1
- package/dist/_chunks/{useLicense-DSLL9n3Y.mjs → useLicense-DxbD4Wf8.mjs} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/server/index.js +142 -33
- package/dist/server/index.mjs +142 -33
- package/package.json +1 -1
- package/server/src/bootstrap.js +76 -4
- package/server/src/controllers/session.js +59 -9
- package/server/src/middlewares/last-seen.js +5 -4
- package/server/src/routes/content-api.js +11 -2
- package/server/src/services/notifications.js +10 -10
- package/server/src/services/session.js +24 -4
- package/dist/_chunks/de-BxFx1pwE.js +0 -23
- package/dist/_chunks/de-CdO3s01z.mjs +0 -23
- package/dist/_chunks/en-CsPpPJL3.mjs +0 -23
- package/dist/_chunks/en-RqmpDHdS.js +0 -23
- package/dist/_chunks/es-CuLHazN1.js +0 -23
- package/dist/_chunks/es-Dkmjhy9c.mjs +0 -23
- package/dist/_chunks/fr-BAJp2yhI.js +0 -23
- package/dist/_chunks/fr-Bssg_3UF.mjs +0 -23
- package/dist/_chunks/pt-BAP9cKs3.js +0 -23
- package/dist/_chunks/pt-BVNoNcuY.mjs +0 -23
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
const react = require("react");
|
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
|
4
|
+
const reactIntl = require("react-intl");
|
|
4
5
|
const designSystem = require("@strapi/design-system");
|
|
5
6
|
const icons = require("@strapi/icons");
|
|
6
7
|
const admin = require("@strapi/strapi/admin");
|
|
@@ -12,6 +13,7 @@ const pluginPkg = {
|
|
|
12
13
|
strapi
|
|
13
14
|
};
|
|
14
15
|
const pluginId = "magic-sessionmanager";
|
|
16
|
+
const PLUGIN_ID = pluginId;
|
|
15
17
|
const Initializer = () => {
|
|
16
18
|
react.useEffect(() => {
|
|
17
19
|
console.log("[magic-sessionmanager] Plugin initialized");
|
|
@@ -23,20 +25,20 @@ const parseUserAgent = (userAgent) => {
|
|
|
23
25
|
if (!userAgent) {
|
|
24
26
|
return {
|
|
25
27
|
device: "Unknown",
|
|
26
|
-
deviceIcon: "
|
|
28
|
+
deviceIcon: "question",
|
|
27
29
|
browser: "Unknown",
|
|
28
30
|
os: "Unknown"
|
|
29
31
|
};
|
|
30
32
|
}
|
|
31
33
|
const ua = userAgent.toLowerCase();
|
|
32
34
|
let device = "Desktop";
|
|
33
|
-
let deviceIcon = "
|
|
35
|
+
let deviceIcon = "desktop";
|
|
34
36
|
if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(userAgent)) {
|
|
35
37
|
device = "Tablet";
|
|
36
|
-
deviceIcon = "
|
|
38
|
+
deviceIcon = "tablet";
|
|
37
39
|
} else if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(userAgent)) {
|
|
38
40
|
device = "Mobile";
|
|
39
|
-
deviceIcon = "
|
|
41
|
+
deviceIcon = "mobile";
|
|
40
42
|
}
|
|
41
43
|
let browser = "Unknown";
|
|
42
44
|
if (ua.includes("edg/")) {
|
|
@@ -55,11 +57,11 @@ const parseUserAgent = (userAgent) => {
|
|
|
55
57
|
device = "API Client";
|
|
56
58
|
} else if (ua.includes("postman")) {
|
|
57
59
|
browser = "Postman";
|
|
58
|
-
deviceIcon = "
|
|
60
|
+
deviceIcon = "code";
|
|
59
61
|
device = "API Client";
|
|
60
62
|
} else if (ua.includes("insomnia")) {
|
|
61
63
|
browser = "Insomnia";
|
|
62
|
-
deviceIcon = "
|
|
64
|
+
deviceIcon = "code";
|
|
63
65
|
device = "API Client";
|
|
64
66
|
}
|
|
65
67
|
let os = "Unknown";
|
|
@@ -81,14 +83,17 @@ const parseUserAgent = (userAgent) => {
|
|
|
81
83
|
os
|
|
82
84
|
};
|
|
83
85
|
};
|
|
86
|
+
const getTranslation = (id) => `${PLUGIN_ID}.${id}`;
|
|
84
87
|
const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
88
|
+
const { formatMessage } = reactIntl.useIntl();
|
|
85
89
|
const [sessions, setSessions] = react.useState([]);
|
|
86
90
|
const [loading, setLoading] = react.useState(true);
|
|
87
91
|
const [isBlocked, setIsBlocked] = react.useState(false);
|
|
88
92
|
const [actionLoading, setActionLoading] = react.useState(false);
|
|
89
93
|
const { get, post: postRequest } = admin.useFetchClient();
|
|
90
94
|
const { toggleNotification } = admin.useNotification();
|
|
91
|
-
const
|
|
95
|
+
const t = (id, defaultMessage, values) => formatMessage({ id: getTranslation(id), defaultMessage }, values);
|
|
96
|
+
const userId = document?.documentId || documentId;
|
|
92
97
|
react.useEffect(() => {
|
|
93
98
|
if (model !== "plugin::users-permissions.user" || !userId) {
|
|
94
99
|
setLoading(false);
|
|
@@ -116,14 +121,14 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
116
121
|
if (response.data?.success) {
|
|
117
122
|
toggleNotification({
|
|
118
123
|
type: "success",
|
|
119
|
-
message: "All sessions terminated successfully"
|
|
124
|
+
message: t("notifications.success.terminatedAll", "All sessions terminated successfully")
|
|
120
125
|
});
|
|
121
126
|
setSessions([]);
|
|
122
127
|
}
|
|
123
128
|
} catch (error) {
|
|
124
129
|
toggleNotification({
|
|
125
130
|
type: "warning",
|
|
126
|
-
message: "Failed to terminate sessions"
|
|
131
|
+
message: t("notifications.error.terminateAll", "Failed to terminate sessions")
|
|
127
132
|
});
|
|
128
133
|
console.error("[SessionInfoPanel] Logout all error:", error);
|
|
129
134
|
} finally {
|
|
@@ -140,7 +145,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
140
145
|
setIsBlocked(newBlockedStatus);
|
|
141
146
|
toggleNotification({
|
|
142
147
|
type: "success",
|
|
143
|
-
message: newBlockedStatus ? "User blocked successfully" : "User unblocked successfully"
|
|
148
|
+
message: newBlockedStatus ? t("notifications.success.blocked", "User blocked successfully") : t("notifications.success.unblocked", "User unblocked successfully")
|
|
144
149
|
});
|
|
145
150
|
if (newBlockedStatus) {
|
|
146
151
|
setSessions([]);
|
|
@@ -149,7 +154,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
149
154
|
} catch (error) {
|
|
150
155
|
toggleNotification({
|
|
151
156
|
type: "warning",
|
|
152
|
-
message: "Failed to update user status"
|
|
157
|
+
message: t("notifications.error.block", "Failed to update user status")
|
|
153
158
|
});
|
|
154
159
|
console.error("[SessionInfoPanel] Toggle block error:", error);
|
|
155
160
|
} finally {
|
|
@@ -166,13 +171,13 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
166
171
|
}
|
|
167
172
|
if (loading) {
|
|
168
173
|
return {
|
|
169
|
-
title: "Session Info",
|
|
170
|
-
content: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral0", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: "Loading..." }) })
|
|
174
|
+
title: t("panel.title", "Session Info"),
|
|
175
|
+
content: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 4, background: "neutral0", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: t("panel.loading", "Loading...") }) })
|
|
171
176
|
};
|
|
172
177
|
}
|
|
173
178
|
const isOnline = sessions.length > 0;
|
|
174
179
|
return {
|
|
175
|
-
title: "Session Info",
|
|
180
|
+
title: t("panel.title", "Session Info"),
|
|
176
181
|
content: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { style: { width: "100%" }, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 4, alignItems: "stretch", children: [
|
|
177
182
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
178
183
|
designSystem.Box,
|
|
@@ -192,14 +197,10 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
192
197
|
textColor: "neutral0",
|
|
193
198
|
size: "M",
|
|
194
199
|
style: { fontSize: "14px", padding: "6px 12px" },
|
|
195
|
-
children: isOnline ? "
|
|
200
|
+
children: isOnline ? t("panel.status.active", "ACTIVE") : t("panel.status.offline", "OFFLINE")
|
|
196
201
|
}
|
|
197
202
|
),
|
|
198
|
-
/* @__PURE__ */ jsxRuntime.
|
|
199
|
-
sessions.length,
|
|
200
|
-
" active session",
|
|
201
|
-
sessions.length !== 1 ? "s" : ""
|
|
202
|
-
] })
|
|
203
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", textColor: isOnline ? "success700" : "neutral700", children: t("panel.sessions.count", "{count} active session{count, plural, one {} other {s}}", { count: sessions.length }) })
|
|
203
204
|
] })
|
|
204
205
|
}
|
|
205
206
|
),
|
|
@@ -210,8 +211,8 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
210
211
|
background: "danger100",
|
|
211
212
|
hasRadius: true,
|
|
212
213
|
children: [
|
|
213
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", textColor: "danger700", marginBottom: 1, children: "User is blocked" }),
|
|
214
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "danger600", children: "Authentication disabled" })
|
|
214
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", textColor: "danger700", marginBottom: 1, children: t("panel.blocked.title", "User is blocked") }),
|
|
215
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "danger600", children: t("panel.blocked.description", "Authentication disabled") })
|
|
215
216
|
]
|
|
216
217
|
}
|
|
217
218
|
),
|
|
@@ -220,7 +221,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
220
221
|
textAlign: "left",
|
|
221
222
|
letterSpacing: "0.5px",
|
|
222
223
|
fontSize: "12px"
|
|
223
|
-
}, children: "Active Sessions" }),
|
|
224
|
+
}, children: t("panel.sessions.title", "Active Sessions") }),
|
|
224
225
|
sessions.slice(0, 5).map((session) => {
|
|
225
226
|
const deviceInfo = parseUserAgent(session.userAgent);
|
|
226
227
|
const DeviceIcon = getDeviceIcon(deviceInfo.device);
|
|
@@ -254,7 +255,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
254
255
|
backgroundColor: "success600",
|
|
255
256
|
textColor: "neutral0",
|
|
256
257
|
size: "S",
|
|
257
|
-
children: "Active"
|
|
258
|
+
children: t("panel.sessions.active", "Active")
|
|
258
259
|
}
|
|
259
260
|
),
|
|
260
261
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { variant: "pi", textColor: "neutral600", children: [
|
|
@@ -276,21 +277,13 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
276
277
|
minute: "2-digit"
|
|
277
278
|
}) })
|
|
278
279
|
] }),
|
|
279
|
-
session.minutesSinceActive !== void 0 && session.minutesSinceActive < 60 && /* @__PURE__ */ jsxRuntime.
|
|
280
|
-
"Active ",
|
|
281
|
-
session.minutesSinceActive === 0 ? "now" : `${session.minutesSinceActive} min ago`
|
|
282
|
-
] })
|
|
280
|
+
session.minutesSinceActive !== void 0 && session.minutesSinceActive < 60 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "success600", fontWeight: "semiBold", children: session.minutesSinceActive === 0 ? t("panel.sessions.activeNow", "Active now") : t("panel.sessions.activeAgo", "Active {minutes} min ago", { minutes: session.minutesSinceActive }) })
|
|
283
281
|
] })
|
|
284
282
|
},
|
|
285
283
|
session.id
|
|
286
284
|
);
|
|
287
285
|
}),
|
|
288
|
-
sessions.length > 5 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, background: "primary100", hasRadius: true, textAlign: "center", children: /* @__PURE__ */ jsxRuntime.
|
|
289
|
-
"+",
|
|
290
|
-
sessions.length - 5,
|
|
291
|
-
" more session",
|
|
292
|
-
sessions.length - 5 !== 1 ? "s" : ""
|
|
293
|
-
] }) })
|
|
286
|
+
sessions.length > 5 && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { padding: 3, background: "primary100", hasRadius: true, textAlign: "center", children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "primary600", fontWeight: "semiBold", children: t("panel.sessions.more", "+{count} more session{count, plural, one {} other {s}}", { count: sessions.length - 5 }) }) })
|
|
294
287
|
] }) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
295
288
|
designSystem.Box,
|
|
296
289
|
{
|
|
@@ -311,8 +304,8 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
311
304
|
children: "💤"
|
|
312
305
|
}
|
|
313
306
|
),
|
|
314
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", textColor: "neutral700", children: "No active sessions" }),
|
|
315
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", style: { fontSize: "13px" }, children: "User has not logged in yet" })
|
|
307
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "omega", fontWeight: "semiBold", textColor: "neutral700", children: t("panel.empty.title", "No active sessions") }),
|
|
308
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "pi", textColor: "neutral500", style: { fontSize: "13px" }, children: t("panel.empty.description", "User has not logged in yet") })
|
|
316
309
|
] })
|
|
317
310
|
}
|
|
318
311
|
),
|
|
@@ -322,7 +315,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
322
315
|
textAlign: "left",
|
|
323
316
|
letterSpacing: "0.5px",
|
|
324
317
|
fontSize: "12px"
|
|
325
|
-
}, children: "Actions" }),
|
|
318
|
+
}, children: t("panel.actions.title", "Actions") }),
|
|
326
319
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
327
320
|
designSystem.Button,
|
|
328
321
|
{
|
|
@@ -350,7 +343,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
350
343
|
e.currentTarget.style.color = "#dc2626";
|
|
351
344
|
}
|
|
352
345
|
},
|
|
353
|
-
children: "Terminate All Sessions"
|
|
346
|
+
children: t("panel.actions.terminateAll", "Terminate All Sessions")
|
|
354
347
|
}
|
|
355
348
|
),
|
|
356
349
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -380,7 +373,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
380
373
|
e.currentTarget.style.color = isBlocked ? "#16a34a" : "#dc2626";
|
|
381
374
|
}
|
|
382
375
|
},
|
|
383
|
-
children: isBlocked ? "Unblock User" : "Block User"
|
|
376
|
+
children: isBlocked ? t("panel.actions.unblockUser", "Unblock User") : t("panel.actions.blockUser", "Block User")
|
|
384
377
|
}
|
|
385
378
|
)
|
|
386
379
|
] })
|
|
@@ -404,7 +397,7 @@ const index = {
|
|
|
404
397
|
id: `${pluginId}.plugin.name`,
|
|
405
398
|
defaultMessage: pluginPkg.strapi.displayName
|
|
406
399
|
},
|
|
407
|
-
Component: () => Promise.resolve().then(() => require("./App-
|
|
400
|
+
Component: () => Promise.resolve().then(() => require("./App-DDKYCjKw.js"))
|
|
408
401
|
});
|
|
409
402
|
app.createSettingSection(
|
|
410
403
|
{
|
|
@@ -413,6 +406,15 @@ const index = {
|
|
|
413
406
|
to: `/settings/${pluginId}`
|
|
414
407
|
},
|
|
415
408
|
[
|
|
409
|
+
{
|
|
410
|
+
intlLabel: {
|
|
411
|
+
id: `${pluginId}.settings.upgrade`,
|
|
412
|
+
defaultMessage: "Upgrade"
|
|
413
|
+
},
|
|
414
|
+
id: "upgrade",
|
|
415
|
+
to: `/settings/${pluginId}/upgrade`,
|
|
416
|
+
Component: () => Promise.resolve().then(() => require("./UpgradePage-Dssk8A0Z.js"))
|
|
417
|
+
},
|
|
416
418
|
{
|
|
417
419
|
intlLabel: {
|
|
418
420
|
id: `${pluginId}.settings.general`,
|
|
@@ -420,7 +422,7 @@ const index = {
|
|
|
420
422
|
},
|
|
421
423
|
id: "general",
|
|
422
424
|
to: `/settings/${pluginId}/general`,
|
|
423
|
-
Component: () => Promise.resolve().then(() => require("./Settings-
|
|
425
|
+
Component: () => Promise.resolve().then(() => require("./Settings-DyEAuTNQ.js"))
|
|
424
426
|
},
|
|
425
427
|
{
|
|
426
428
|
intlLabel: {
|
|
@@ -429,7 +431,7 @@ const index = {
|
|
|
429
431
|
},
|
|
430
432
|
id: "analytics",
|
|
431
433
|
to: `/settings/${pluginId}/analytics`,
|
|
432
|
-
Component: () => Promise.resolve().then(() => require("./Analytics-
|
|
434
|
+
Component: () => Promise.resolve().then(() => require("./Analytics-lw_JaOVy.js"))
|
|
433
435
|
},
|
|
434
436
|
{
|
|
435
437
|
intlLabel: {
|
|
@@ -438,7 +440,7 @@ const index = {
|
|
|
438
440
|
},
|
|
439
441
|
id: "license",
|
|
440
442
|
to: `/settings/${pluginId}/license`,
|
|
441
|
-
Component: () => Promise.resolve().then(() => require("./License-
|
|
443
|
+
Component: () => Promise.resolve().then(() => require("./License-Tk-6UfPl.js"))
|
|
442
444
|
}
|
|
443
445
|
]
|
|
444
446
|
);
|
|
@@ -456,7 +458,7 @@ const index = {
|
|
|
456
458
|
defaultMessage: "Online Users"
|
|
457
459
|
},
|
|
458
460
|
component: async () => {
|
|
459
|
-
const component = await Promise.resolve().then(() => require("./OnlineUsersWidget-
|
|
461
|
+
const component = await Promise.resolve().then(() => require("./OnlineUsersWidget-C1qTpsws.js"));
|
|
460
462
|
return component.default;
|
|
461
463
|
},
|
|
462
464
|
id: "online-users-widget",
|
|
@@ -482,11 +484,11 @@ const index = {
|
|
|
482
484
|
},
|
|
483
485
|
async registerTrads({ locales }) {
|
|
484
486
|
const importedTrads = {
|
|
485
|
-
en: () => Promise.resolve().then(() => require("./en-
|
|
486
|
-
de: () => Promise.resolve().then(() => require("./de-
|
|
487
|
-
es: () => Promise.resolve().then(() => require("./es-
|
|
488
|
-
fr: () => Promise.resolve().then(() => require("./fr-
|
|
489
|
-
pt: () => Promise.resolve().then(() => require("./pt-
|
|
487
|
+
en: () => Promise.resolve().then(() => require("./en-Bd7_h-4e.js")),
|
|
488
|
+
de: () => Promise.resolve().then(() => require("./de-I-Q-pWqu.js")),
|
|
489
|
+
es: () => Promise.resolve().then(() => require("./es-BcAx18XG.js")),
|
|
490
|
+
fr: () => Promise.resolve().then(() => require("./fr-DCzYMuJ-.js")),
|
|
491
|
+
pt: () => Promise.resolve().then(() => require("./pt-21-MAb72.js"))
|
|
490
492
|
};
|
|
491
493
|
const translatedLanguages = Object.keys(importedTrads).filter(
|
|
492
494
|
(lang) => locales.includes(lang)
|
|
@@ -505,6 +507,7 @@ const index = {
|
|
|
505
507
|
return Promise.resolve(translations);
|
|
506
508
|
}
|
|
507
509
|
};
|
|
510
|
+
exports.getTranslation = getTranslation;
|
|
508
511
|
exports.index = index;
|
|
509
512
|
exports.parseUserAgent = parseUserAgent;
|
|
510
513
|
exports.pluginId = pluginId;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useIntl } from "react-intl";
|
|
3
4
|
import { Box, Typography, Flex, Badge, Divider, Button } from "@strapi/design-system";
|
|
4
5
|
import { Server, Clock, Cross, Check, Phone, Monitor } from "@strapi/icons";
|
|
5
6
|
import { useFetchClient, useNotification } from "@strapi/strapi/admin";
|
|
@@ -11,6 +12,7 @@ const pluginPkg = {
|
|
|
11
12
|
strapi
|
|
12
13
|
};
|
|
13
14
|
const pluginId = "magic-sessionmanager";
|
|
15
|
+
const PLUGIN_ID = pluginId;
|
|
14
16
|
const Initializer = () => {
|
|
15
17
|
useEffect(() => {
|
|
16
18
|
console.log("[magic-sessionmanager] Plugin initialized");
|
|
@@ -22,20 +24,20 @@ const parseUserAgent = (userAgent) => {
|
|
|
22
24
|
if (!userAgent) {
|
|
23
25
|
return {
|
|
24
26
|
device: "Unknown",
|
|
25
|
-
deviceIcon: "
|
|
27
|
+
deviceIcon: "question",
|
|
26
28
|
browser: "Unknown",
|
|
27
29
|
os: "Unknown"
|
|
28
30
|
};
|
|
29
31
|
}
|
|
30
32
|
const ua = userAgent.toLowerCase();
|
|
31
33
|
let device = "Desktop";
|
|
32
|
-
let deviceIcon = "
|
|
34
|
+
let deviceIcon = "desktop";
|
|
33
35
|
if (/(tablet|ipad|playbook|silk)|(android(?!.*mobi))/i.test(userAgent)) {
|
|
34
36
|
device = "Tablet";
|
|
35
|
-
deviceIcon = "
|
|
37
|
+
deviceIcon = "tablet";
|
|
36
38
|
} else if (/Mobile|Android|iP(hone|od)|IEMobile|BlackBerry|Kindle|Silk-Accelerated|(hpw|web)OS|Opera M(obi|ini)/.test(userAgent)) {
|
|
37
39
|
device = "Mobile";
|
|
38
|
-
deviceIcon = "
|
|
40
|
+
deviceIcon = "mobile";
|
|
39
41
|
}
|
|
40
42
|
let browser = "Unknown";
|
|
41
43
|
if (ua.includes("edg/")) {
|
|
@@ -54,11 +56,11 @@ const parseUserAgent = (userAgent) => {
|
|
|
54
56
|
device = "API Client";
|
|
55
57
|
} else if (ua.includes("postman")) {
|
|
56
58
|
browser = "Postman";
|
|
57
|
-
deviceIcon = "
|
|
59
|
+
deviceIcon = "code";
|
|
58
60
|
device = "API Client";
|
|
59
61
|
} else if (ua.includes("insomnia")) {
|
|
60
62
|
browser = "Insomnia";
|
|
61
|
-
deviceIcon = "
|
|
63
|
+
deviceIcon = "code";
|
|
62
64
|
device = "API Client";
|
|
63
65
|
}
|
|
64
66
|
let os = "Unknown";
|
|
@@ -80,14 +82,17 @@ const parseUserAgent = (userAgent) => {
|
|
|
80
82
|
os
|
|
81
83
|
};
|
|
82
84
|
};
|
|
85
|
+
const getTranslation = (id) => `${PLUGIN_ID}.${id}`;
|
|
83
86
|
const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
87
|
+
const { formatMessage } = useIntl();
|
|
84
88
|
const [sessions, setSessions] = useState([]);
|
|
85
89
|
const [loading, setLoading] = useState(true);
|
|
86
90
|
const [isBlocked, setIsBlocked] = useState(false);
|
|
87
91
|
const [actionLoading, setActionLoading] = useState(false);
|
|
88
92
|
const { get, post: postRequest } = useFetchClient();
|
|
89
93
|
const { toggleNotification } = useNotification();
|
|
90
|
-
const
|
|
94
|
+
const t = (id, defaultMessage, values) => formatMessage({ id: getTranslation(id), defaultMessage }, values);
|
|
95
|
+
const userId = document?.documentId || documentId;
|
|
91
96
|
useEffect(() => {
|
|
92
97
|
if (model !== "plugin::users-permissions.user" || !userId) {
|
|
93
98
|
setLoading(false);
|
|
@@ -115,14 +120,14 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
115
120
|
if (response.data?.success) {
|
|
116
121
|
toggleNotification({
|
|
117
122
|
type: "success",
|
|
118
|
-
message: "All sessions terminated successfully"
|
|
123
|
+
message: t("notifications.success.terminatedAll", "All sessions terminated successfully")
|
|
119
124
|
});
|
|
120
125
|
setSessions([]);
|
|
121
126
|
}
|
|
122
127
|
} catch (error) {
|
|
123
128
|
toggleNotification({
|
|
124
129
|
type: "warning",
|
|
125
|
-
message: "Failed to terminate sessions"
|
|
130
|
+
message: t("notifications.error.terminateAll", "Failed to terminate sessions")
|
|
126
131
|
});
|
|
127
132
|
console.error("[SessionInfoPanel] Logout all error:", error);
|
|
128
133
|
} finally {
|
|
@@ -139,7 +144,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
139
144
|
setIsBlocked(newBlockedStatus);
|
|
140
145
|
toggleNotification({
|
|
141
146
|
type: "success",
|
|
142
|
-
message: newBlockedStatus ? "User blocked successfully" : "User unblocked successfully"
|
|
147
|
+
message: newBlockedStatus ? t("notifications.success.blocked", "User blocked successfully") : t("notifications.success.unblocked", "User unblocked successfully")
|
|
143
148
|
});
|
|
144
149
|
if (newBlockedStatus) {
|
|
145
150
|
setSessions([]);
|
|
@@ -148,7 +153,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
148
153
|
} catch (error) {
|
|
149
154
|
toggleNotification({
|
|
150
155
|
type: "warning",
|
|
151
|
-
message: "Failed to update user status"
|
|
156
|
+
message: t("notifications.error.block", "Failed to update user status")
|
|
152
157
|
});
|
|
153
158
|
console.error("[SessionInfoPanel] Toggle block error:", error);
|
|
154
159
|
} finally {
|
|
@@ -165,13 +170,13 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
165
170
|
}
|
|
166
171
|
if (loading) {
|
|
167
172
|
return {
|
|
168
|
-
title: "Session Info",
|
|
169
|
-
content: /* @__PURE__ */ jsx(Box, { padding: 4, background: "neutral0", children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: "Loading..." }) })
|
|
173
|
+
title: t("panel.title", "Session Info"),
|
|
174
|
+
content: /* @__PURE__ */ jsx(Box, { padding: 4, background: "neutral0", children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", children: t("panel.loading", "Loading...") }) })
|
|
170
175
|
};
|
|
171
176
|
}
|
|
172
177
|
const isOnline = sessions.length > 0;
|
|
173
178
|
return {
|
|
174
|
-
title: "Session Info",
|
|
179
|
+
title: t("panel.title", "Session Info"),
|
|
175
180
|
content: /* @__PURE__ */ jsx(Box, { style: { width: "100%" }, children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 4, alignItems: "stretch", children: [
|
|
176
181
|
/* @__PURE__ */ jsx(
|
|
177
182
|
Box,
|
|
@@ -191,14 +196,10 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
191
196
|
textColor: "neutral0",
|
|
192
197
|
size: "M",
|
|
193
198
|
style: { fontSize: "14px", padding: "6px 12px" },
|
|
194
|
-
children: isOnline ? "
|
|
199
|
+
children: isOnline ? t("panel.status.active", "ACTIVE") : t("panel.status.offline", "OFFLINE")
|
|
195
200
|
}
|
|
196
201
|
),
|
|
197
|
-
/* @__PURE__ */
|
|
198
|
-
sessions.length,
|
|
199
|
-
" active session",
|
|
200
|
-
sessions.length !== 1 ? "s" : ""
|
|
201
|
-
] })
|
|
202
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", textColor: isOnline ? "success700" : "neutral700", children: t("panel.sessions.count", "{count} active session{count, plural, one {} other {s}}", { count: sessions.length }) })
|
|
202
203
|
] })
|
|
203
204
|
}
|
|
204
205
|
),
|
|
@@ -209,8 +210,8 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
209
210
|
background: "danger100",
|
|
210
211
|
hasRadius: true,
|
|
211
212
|
children: [
|
|
212
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", textColor: "danger700", marginBottom: 1, children: "User is blocked" }),
|
|
213
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "danger600", children: "Authentication disabled" })
|
|
213
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", textColor: "danger700", marginBottom: 1, children: t("panel.blocked.title", "User is blocked") }),
|
|
214
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "danger600", children: t("panel.blocked.description", "Authentication disabled") })
|
|
214
215
|
]
|
|
215
216
|
}
|
|
216
217
|
),
|
|
@@ -219,7 +220,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
219
220
|
textAlign: "left",
|
|
220
221
|
letterSpacing: "0.5px",
|
|
221
222
|
fontSize: "12px"
|
|
222
|
-
}, children: "Active Sessions" }),
|
|
223
|
+
}, children: t("panel.sessions.title", "Active Sessions") }),
|
|
223
224
|
sessions.slice(0, 5).map((session) => {
|
|
224
225
|
const deviceInfo = parseUserAgent(session.userAgent);
|
|
225
226
|
const DeviceIcon = getDeviceIcon(deviceInfo.device);
|
|
@@ -253,7 +254,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
253
254
|
backgroundColor: "success600",
|
|
254
255
|
textColor: "neutral0",
|
|
255
256
|
size: "S",
|
|
256
|
-
children: "Active"
|
|
257
|
+
children: t("panel.sessions.active", "Active")
|
|
257
258
|
}
|
|
258
259
|
),
|
|
259
260
|
/* @__PURE__ */ jsxs(Typography, { variant: "pi", textColor: "neutral600", children: [
|
|
@@ -275,21 +276,13 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
275
276
|
minute: "2-digit"
|
|
276
277
|
}) })
|
|
277
278
|
] }),
|
|
278
|
-
session.minutesSinceActive !== void 0 && session.minutesSinceActive < 60 && /* @__PURE__ */
|
|
279
|
-
"Active ",
|
|
280
|
-
session.minutesSinceActive === 0 ? "now" : `${session.minutesSinceActive} min ago`
|
|
281
|
-
] })
|
|
279
|
+
session.minutesSinceActive !== void 0 && session.minutesSinceActive < 60 && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "success600", fontWeight: "semiBold", children: session.minutesSinceActive === 0 ? t("panel.sessions.activeNow", "Active now") : t("panel.sessions.activeAgo", "Active {minutes} min ago", { minutes: session.minutesSinceActive }) })
|
|
282
280
|
] })
|
|
283
281
|
},
|
|
284
282
|
session.id
|
|
285
283
|
);
|
|
286
284
|
}),
|
|
287
|
-
sessions.length > 5 && /* @__PURE__ */ jsx(Box, { padding: 3, background: "primary100", hasRadius: true, textAlign: "center", children: /* @__PURE__ */
|
|
288
|
-
"+",
|
|
289
|
-
sessions.length - 5,
|
|
290
|
-
" more session",
|
|
291
|
-
sessions.length - 5 !== 1 ? "s" : ""
|
|
292
|
-
] }) })
|
|
285
|
+
sessions.length > 5 && /* @__PURE__ */ jsx(Box, { padding: 3, background: "primary100", hasRadius: true, textAlign: "center", children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "primary600", fontWeight: "semiBold", children: t("panel.sessions.more", "+{count} more session{count, plural, one {} other {s}}", { count: sessions.length - 5 }) }) })
|
|
293
286
|
] }) : /* @__PURE__ */ jsx(
|
|
294
287
|
Box,
|
|
295
288
|
{
|
|
@@ -310,8 +303,8 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
310
303
|
children: "💤"
|
|
311
304
|
}
|
|
312
305
|
),
|
|
313
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", textColor: "neutral700", children: "No active sessions" }),
|
|
314
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", style: { fontSize: "13px" }, children: "User has not logged in yet" })
|
|
306
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", textColor: "neutral700", children: t("panel.empty.title", "No active sessions") }),
|
|
307
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral500", style: { fontSize: "13px" }, children: t("panel.empty.description", "User has not logged in yet") })
|
|
315
308
|
] })
|
|
316
309
|
}
|
|
317
310
|
),
|
|
@@ -321,7 +314,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
321
314
|
textAlign: "left",
|
|
322
315
|
letterSpacing: "0.5px",
|
|
323
316
|
fontSize: "12px"
|
|
324
|
-
}, children: "Actions" }),
|
|
317
|
+
}, children: t("panel.actions.title", "Actions") }),
|
|
325
318
|
/* @__PURE__ */ jsx(
|
|
326
319
|
Button,
|
|
327
320
|
{
|
|
@@ -349,7 +342,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
349
342
|
e.currentTarget.style.color = "#dc2626";
|
|
350
343
|
}
|
|
351
344
|
},
|
|
352
|
-
children: "Terminate All Sessions"
|
|
345
|
+
children: t("panel.actions.terminateAll", "Terminate All Sessions")
|
|
353
346
|
}
|
|
354
347
|
),
|
|
355
348
|
/* @__PURE__ */ jsx(
|
|
@@ -379,7 +372,7 @@ const SessionInfoPanel = ({ documentId, model, document }) => {
|
|
|
379
372
|
e.currentTarget.style.color = isBlocked ? "#16a34a" : "#dc2626";
|
|
380
373
|
}
|
|
381
374
|
},
|
|
382
|
-
children: isBlocked ? "Unblock User" : "Block User"
|
|
375
|
+
children: isBlocked ? t("panel.actions.unblockUser", "Unblock User") : t("panel.actions.blockUser", "Block User")
|
|
383
376
|
}
|
|
384
377
|
)
|
|
385
378
|
] })
|
|
@@ -403,7 +396,7 @@ const index = {
|
|
|
403
396
|
id: `${pluginId}.plugin.name`,
|
|
404
397
|
defaultMessage: pluginPkg.strapi.displayName
|
|
405
398
|
},
|
|
406
|
-
Component: () => import("./App-
|
|
399
|
+
Component: () => import("./App-DJW1ZNl5.mjs")
|
|
407
400
|
});
|
|
408
401
|
app.createSettingSection(
|
|
409
402
|
{
|
|
@@ -412,6 +405,15 @@ const index = {
|
|
|
412
405
|
to: `/settings/${pluginId}`
|
|
413
406
|
},
|
|
414
407
|
[
|
|
408
|
+
{
|
|
409
|
+
intlLabel: {
|
|
410
|
+
id: `${pluginId}.settings.upgrade`,
|
|
411
|
+
defaultMessage: "Upgrade"
|
|
412
|
+
},
|
|
413
|
+
id: "upgrade",
|
|
414
|
+
to: `/settings/${pluginId}/upgrade`,
|
|
415
|
+
Component: () => import("./UpgradePage-cINvE9zY.mjs")
|
|
416
|
+
},
|
|
415
417
|
{
|
|
416
418
|
intlLabel: {
|
|
417
419
|
id: `${pluginId}.settings.general`,
|
|
@@ -419,7 +421,7 @@ const index = {
|
|
|
419
421
|
},
|
|
420
422
|
id: "general",
|
|
421
423
|
to: `/settings/${pluginId}/general`,
|
|
422
|
-
Component: () => import("./Settings-
|
|
424
|
+
Component: () => import("./Settings-C9xvckgq.mjs")
|
|
423
425
|
},
|
|
424
426
|
{
|
|
425
427
|
intlLabel: {
|
|
@@ -428,7 +430,7 @@ const index = {
|
|
|
428
430
|
},
|
|
429
431
|
id: "analytics",
|
|
430
432
|
to: `/settings/${pluginId}/analytics`,
|
|
431
|
-
Component: () => import("./Analytics-
|
|
433
|
+
Component: () => import("./Analytics-DTE_zmRV.mjs")
|
|
432
434
|
},
|
|
433
435
|
{
|
|
434
436
|
intlLabel: {
|
|
@@ -437,7 +439,7 @@ const index = {
|
|
|
437
439
|
},
|
|
438
440
|
id: "license",
|
|
439
441
|
to: `/settings/${pluginId}/license`,
|
|
440
|
-
Component: () => import("./License-
|
|
442
|
+
Component: () => import("./License-DaOFuImm.mjs")
|
|
441
443
|
}
|
|
442
444
|
]
|
|
443
445
|
);
|
|
@@ -455,7 +457,7 @@ const index = {
|
|
|
455
457
|
defaultMessage: "Online Users"
|
|
456
458
|
},
|
|
457
459
|
component: async () => {
|
|
458
|
-
const component = await import("./OnlineUsersWidget-
|
|
460
|
+
const component = await import("./OnlineUsersWidget-CADphbXG.mjs");
|
|
459
461
|
return component.default;
|
|
460
462
|
},
|
|
461
463
|
id: "online-users-widget",
|
|
@@ -481,11 +483,11 @@ const index = {
|
|
|
481
483
|
},
|
|
482
484
|
async registerTrads({ locales }) {
|
|
483
485
|
const importedTrads = {
|
|
484
|
-
en: () => import("./en-
|
|
485
|
-
de: () => import("./de-
|
|
486
|
-
es: () => import("./es-
|
|
487
|
-
fr: () => import("./fr-
|
|
488
|
-
pt: () => import("./pt-
|
|
486
|
+
en: () => import("./en-DzmOCyzQ.mjs"),
|
|
487
|
+
de: () => import("./de-CDA1V0rF.mjs"),
|
|
488
|
+
es: () => import("./es-Cx-SN6qV.mjs"),
|
|
489
|
+
fr: () => import("./fr-DXlXE5Eo.mjs"),
|
|
490
|
+
pt: () => import("./pt-zsdTSjba.mjs")
|
|
489
491
|
};
|
|
490
492
|
const translatedLanguages = Object.keys(importedTrads).filter(
|
|
491
493
|
(lang) => locales.includes(lang)
|
|
@@ -506,6 +508,7 @@ const index = {
|
|
|
506
508
|
};
|
|
507
509
|
export {
|
|
508
510
|
pluginId as a,
|
|
511
|
+
getTranslation as g,
|
|
509
512
|
index as i,
|
|
510
513
|
parseUserAgent as p
|
|
511
514
|
};
|