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,9 @@
|
|
|
1
1
|
import { useState, useEffect } from 'react';
|
|
2
|
+
import { useIntl } from 'react-intl';
|
|
2
3
|
import { useFetchClient, useNotification } from '@strapi/strapi/admin';
|
|
3
4
|
import styled, { keyframes, css } from 'styled-components';
|
|
5
|
+
import { getTranslation } from '../utils/getTranslation';
|
|
6
|
+
import { theme } from '../utils/theme';
|
|
4
7
|
import {
|
|
5
8
|
Box,
|
|
6
9
|
Button,
|
|
@@ -36,72 +39,6 @@ import parseUserAgent from '../utils/parseUserAgent';
|
|
|
36
39
|
import SessionDetailModal from '../components/SessionDetailModal';
|
|
37
40
|
import { useLicense } from '../hooks/useLicense';
|
|
38
41
|
|
|
39
|
-
// ================ THEME ================
|
|
40
|
-
const theme = {
|
|
41
|
-
colors: {
|
|
42
|
-
primary: {
|
|
43
|
-
50: '#F0F9FF',
|
|
44
|
-
100: '#E0F2FE',
|
|
45
|
-
500: '#0EA5E9',
|
|
46
|
-
600: '#0284C7',
|
|
47
|
-
700: '#0369A1',
|
|
48
|
-
},
|
|
49
|
-
secondary: {
|
|
50
|
-
500: '#A855F7',
|
|
51
|
-
600: '#9333EA',
|
|
52
|
-
},
|
|
53
|
-
success: {
|
|
54
|
-
100: '#DCFCE7',
|
|
55
|
-
500: '#22C55E',
|
|
56
|
-
600: '#16A34A',
|
|
57
|
-
700: '#15803D',
|
|
58
|
-
},
|
|
59
|
-
warning: {
|
|
60
|
-
100: '#FEF3C7',
|
|
61
|
-
500: '#F59E0B',
|
|
62
|
-
600: '#D97706',
|
|
63
|
-
},
|
|
64
|
-
danger: {
|
|
65
|
-
100: '#FEE2E2',
|
|
66
|
-
500: '#EF4444',
|
|
67
|
-
600: '#DC2626',
|
|
68
|
-
},
|
|
69
|
-
neutral: {
|
|
70
|
-
0: '#FFFFFF',
|
|
71
|
-
50: '#F9FAFB',
|
|
72
|
-
100: '#F3F4F6',
|
|
73
|
-
200: '#E5E7EB',
|
|
74
|
-
600: '#4B5563',
|
|
75
|
-
700: '#374151',
|
|
76
|
-
800: '#1F2937',
|
|
77
|
-
}
|
|
78
|
-
},
|
|
79
|
-
shadows: {
|
|
80
|
-
sm: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px -1px rgba(0, 0, 0, 0.1)',
|
|
81
|
-
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -2px rgba(0, 0, 0, 0.1)',
|
|
82
|
-
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -4px rgba(0, 0, 0, 0.1)',
|
|
83
|
-
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1)',
|
|
84
|
-
},
|
|
85
|
-
transitions: {
|
|
86
|
-
fast: '150ms cubic-bezier(0.4, 0, 0.2, 1)',
|
|
87
|
-
normal: '300ms cubic-bezier(0.4, 0, 0.2, 1)',
|
|
88
|
-
slow: '500ms cubic-bezier(0.4, 0, 0.2, 1)',
|
|
89
|
-
},
|
|
90
|
-
spacing: {
|
|
91
|
-
xs: '4px',
|
|
92
|
-
sm: '8px',
|
|
93
|
-
md: '16px',
|
|
94
|
-
lg: '24px',
|
|
95
|
-
xl: '32px',
|
|
96
|
-
'2xl': '48px',
|
|
97
|
-
},
|
|
98
|
-
borderRadius: {
|
|
99
|
-
md: '8px',
|
|
100
|
-
lg: '12px',
|
|
101
|
-
xl: '16px',
|
|
102
|
-
}
|
|
103
|
-
};
|
|
104
|
-
|
|
105
42
|
// ================ ANIMATIONS ================
|
|
106
43
|
const fadeIn = keyframes`
|
|
107
44
|
from { opacity: 0; transform: translateY(10px); }
|
|
@@ -203,7 +140,7 @@ const HeaderContent = styled(Flex)`
|
|
|
203
140
|
`;
|
|
204
141
|
|
|
205
142
|
const Title = styled(Typography)`
|
|
206
|
-
color:
|
|
143
|
+
color: white;
|
|
207
144
|
font-size: 2rem;
|
|
208
145
|
font-weight: 700;
|
|
209
146
|
letter-spacing: -0.025em;
|
|
@@ -258,7 +195,7 @@ const StatsGrid = styled.div`
|
|
|
258
195
|
`;
|
|
259
196
|
|
|
260
197
|
const StatCard = styled(Box)`
|
|
261
|
-
background: ${theme.colors.
|
|
198
|
+
background: ${props => props.theme.colors.neutral0};
|
|
262
199
|
border-radius: ${theme.borderRadius.lg};
|
|
263
200
|
padding: 28px ${theme.spacing.lg};
|
|
264
201
|
position: relative;
|
|
@@ -267,7 +204,7 @@ const StatCard = styled(Box)`
|
|
|
267
204
|
${css`animation: ${fadeIn} ${theme.transitions.slow} backwards;`}
|
|
268
205
|
animation-delay: ${props => props.$delay || '0s'};
|
|
269
206
|
box-shadow: ${theme.shadows.sm};
|
|
270
|
-
border: 1px solid ${theme.colors.
|
|
207
|
+
border: 1px solid ${props => props.theme.colors.neutral200};
|
|
271
208
|
min-width: 200px;
|
|
272
209
|
flex: 1;
|
|
273
210
|
text-align: center;
|
|
@@ -288,7 +225,7 @@ const StatCard = styled(Box)`
|
|
|
288
225
|
&:hover {
|
|
289
226
|
transform: translateY(-6px);
|
|
290
227
|
box-shadow: ${theme.shadows.xl};
|
|
291
|
-
border-color: ${props => props.$color || theme.colors.
|
|
228
|
+
border-color: ${props => props.$color || props.theme.colors.primary600};
|
|
292
229
|
|
|
293
230
|
.stat-icon {
|
|
294
231
|
transform: scale(1.15) rotate(5deg);
|
|
@@ -296,7 +233,7 @@ const StatCard = styled(Box)`
|
|
|
296
233
|
|
|
297
234
|
.stat-value {
|
|
298
235
|
transform: scale(1.08);
|
|
299
|
-
color: ${props => props.$color || theme.colors.
|
|
236
|
+
color: ${props => props.$color || props.theme.colors.primary600};
|
|
300
237
|
}
|
|
301
238
|
}
|
|
302
239
|
`;
|
|
@@ -308,7 +245,7 @@ const StatIcon = styled(Box)`
|
|
|
308
245
|
display: flex;
|
|
309
246
|
align-items: center;
|
|
310
247
|
justify-content: center;
|
|
311
|
-
background: ${props => props.$bg || theme.colors.
|
|
248
|
+
background: ${props => props.$bg || props.theme.colors.primary100};
|
|
312
249
|
transition: all ${theme.transitions.normal};
|
|
313
250
|
margin: 0 auto 20px;
|
|
314
251
|
box-shadow: ${theme.shadows.sm};
|
|
@@ -316,7 +253,7 @@ const StatIcon = styled(Box)`
|
|
|
316
253
|
svg {
|
|
317
254
|
width: 34px;
|
|
318
255
|
height: 34px;
|
|
319
|
-
color: ${props => props.$color || theme.colors.
|
|
256
|
+
color: ${props => props.$color || props.theme.colors.primary600};
|
|
320
257
|
}
|
|
321
258
|
|
|
322
259
|
@media screen and (max-width: ${breakpoints.mobile}) {
|
|
@@ -334,7 +271,7 @@ const StatIcon = styled(Box)`
|
|
|
334
271
|
const StatValue = styled(Typography)`
|
|
335
272
|
font-size: 2.75rem;
|
|
336
273
|
font-weight: 700;
|
|
337
|
-
color: ${theme.colors.
|
|
274
|
+
color: ${props => props.theme.colors.neutral800};
|
|
338
275
|
line-height: 1;
|
|
339
276
|
margin-bottom: 10px;
|
|
340
277
|
transition: all ${theme.transitions.normal};
|
|
@@ -348,7 +285,7 @@ const StatValue = styled(Typography)`
|
|
|
348
285
|
|
|
349
286
|
const StatLabel = styled(Typography)`
|
|
350
287
|
font-size: 0.95rem;
|
|
351
|
-
color: ${theme.colors.
|
|
288
|
+
color: ${props => props.theme.colors.neutral600};
|
|
352
289
|
font-weight: 500;
|
|
353
290
|
letter-spacing: 0.025em;
|
|
354
291
|
text-align: center;
|
|
@@ -359,22 +296,22 @@ const StatLabel = styled(Typography)`
|
|
|
359
296
|
`;
|
|
360
297
|
|
|
361
298
|
const DataTable = styled(Box)`
|
|
362
|
-
background: ${theme.colors.
|
|
299
|
+
background: ${props => props.theme.colors.neutral0};
|
|
363
300
|
border-radius: ${theme.borderRadius.lg};
|
|
364
301
|
overflow: hidden;
|
|
365
302
|
box-shadow: ${theme.shadows.sm};
|
|
366
|
-
border: 1px solid ${theme.colors.
|
|
303
|
+
border: 1px solid ${props => props.theme.colors.neutral200};
|
|
367
304
|
margin-bottom: ${theme.spacing.xl};
|
|
368
305
|
`;
|
|
369
306
|
|
|
370
307
|
const StyledTable = styled(Table)`
|
|
371
308
|
thead {
|
|
372
|
-
background: ${theme.colors.
|
|
373
|
-
border-bottom: 2px solid ${theme.colors.
|
|
309
|
+
background: ${props => props.theme.colors.neutral100};
|
|
310
|
+
border-bottom: 2px solid ${props => props.theme.colors.neutral200};
|
|
374
311
|
|
|
375
312
|
th {
|
|
376
313
|
font-weight: 600;
|
|
377
|
-
color: ${theme.colors.
|
|
314
|
+
color: ${props => props.theme.colors.neutral800};
|
|
378
315
|
font-size: 0.875rem;
|
|
379
316
|
text-transform: uppercase;
|
|
380
317
|
letter-spacing: 0.025em;
|
|
@@ -384,14 +321,14 @@ const StyledTable = styled(Table)`
|
|
|
384
321
|
|
|
385
322
|
tbody tr {
|
|
386
323
|
transition: all ${theme.transitions.fast};
|
|
387
|
-
border-bottom: 1px solid ${theme.colors.
|
|
324
|
+
border-bottom: 1px solid ${props => props.theme.colors.neutral150};
|
|
388
325
|
|
|
389
326
|
&:last-child {
|
|
390
327
|
border-bottom: none;
|
|
391
328
|
}
|
|
392
329
|
|
|
393
330
|
&:hover {
|
|
394
|
-
background: ${theme.colors.
|
|
331
|
+
background: ${props => props.theme.colors.primary100};
|
|
395
332
|
|
|
396
333
|
.action-buttons {
|
|
397
334
|
opacity: 1;
|
|
@@ -400,7 +337,7 @@ const StyledTable = styled(Table)`
|
|
|
400
337
|
|
|
401
338
|
td {
|
|
402
339
|
padding: ${theme.spacing.lg} ${theme.spacing.lg};
|
|
403
|
-
color: ${theme.colors.
|
|
340
|
+
color: ${props => props.theme.colors.neutral800};
|
|
404
341
|
vertical-align: middle;
|
|
405
342
|
}
|
|
406
343
|
}
|
|
@@ -410,19 +347,19 @@ const OnlineIndicator = styled.div`
|
|
|
410
347
|
width: 10px;
|
|
411
348
|
height: 10px;
|
|
412
349
|
border-radius: 50%;
|
|
413
|
-
background: ${props => props.$online ? theme.colors.success[500] : theme.colors.
|
|
350
|
+
background: ${props => props.$online ? theme.colors.success[500] : props.theme.colors.neutral400};
|
|
414
351
|
display: inline-block;
|
|
415
352
|
margin-right: 8px;
|
|
416
353
|
${css`animation: ${props => props.$online ? pulse : 'none'} 2s ease-in-out infinite;`}
|
|
417
354
|
`;
|
|
418
355
|
|
|
419
356
|
const FilterBar = styled(Flex)`
|
|
420
|
-
background: ${theme.colors.
|
|
357
|
+
background: ${props => props.theme.colors.neutral0};
|
|
421
358
|
padding: ${theme.spacing.md} ${theme.spacing.lg};
|
|
422
359
|
border-radius: ${theme.borderRadius.lg};
|
|
423
360
|
margin-bottom: ${theme.spacing.lg};
|
|
424
361
|
box-shadow: ${theme.shadows.sm};
|
|
425
|
-
border: 1px solid ${theme.colors.
|
|
362
|
+
border: 1px solid ${props => props.theme.colors.neutral200};
|
|
426
363
|
gap: ${theme.spacing.md};
|
|
427
364
|
align-items: center;
|
|
428
365
|
`;
|
|
@@ -439,28 +376,28 @@ const SearchIcon = styled(Search)`
|
|
|
439
376
|
left: 12px;
|
|
440
377
|
width: 16px;
|
|
441
378
|
height: 16px;
|
|
442
|
-
color: ${theme.colors.
|
|
379
|
+
color: ${props => props.theme.colors.neutral600};
|
|
443
380
|
pointer-events: none;
|
|
444
381
|
`;
|
|
445
382
|
|
|
446
383
|
const StyledSearchInput = styled.input`
|
|
447
384
|
width: 100%;
|
|
448
385
|
padding: ${theme.spacing.sm} ${theme.spacing.sm} ${theme.spacing.sm} 36px;
|
|
449
|
-
border: 1px solid ${theme.colors.
|
|
386
|
+
border: 1px solid ${props => props.theme.colors.neutral200};
|
|
450
387
|
border-radius: ${theme.borderRadius.md};
|
|
451
388
|
font-size: 0.875rem;
|
|
452
389
|
transition: all ${theme.transitions.fast};
|
|
453
|
-
background: ${theme.colors.
|
|
454
|
-
color: ${theme.colors.
|
|
390
|
+
background: ${props => props.theme.colors.neutral0};
|
|
391
|
+
color: ${props => props.theme.colors.neutral800};
|
|
455
392
|
|
|
456
393
|
&:focus {
|
|
457
394
|
outline: none;
|
|
458
|
-
border-color: ${theme.colors.
|
|
459
|
-
box-shadow: 0 0 0 3px ${theme.colors.
|
|
395
|
+
border-color: ${props => props.theme.colors.primary600};
|
|
396
|
+
box-shadow: 0 0 0 3px ${props => props.theme.colors.primary100};
|
|
460
397
|
}
|
|
461
398
|
|
|
462
399
|
&::placeholder {
|
|
463
|
-
color: ${theme.colors.
|
|
400
|
+
color: ${props => props.theme.colors.neutral500};
|
|
464
401
|
}
|
|
465
402
|
`;
|
|
466
403
|
|
|
@@ -475,14 +412,42 @@ const ClickableRow = styled(Tr)`
|
|
|
475
412
|
cursor: pointer;
|
|
476
413
|
|
|
477
414
|
&:hover {
|
|
478
|
-
background: ${theme.colors.
|
|
415
|
+
background: ${props => props.theme.colors.primary100} !important;
|
|
479
416
|
}
|
|
480
417
|
`;
|
|
481
418
|
|
|
419
|
+
// Empty state background that works in dark mode
|
|
420
|
+
const EmptyStateBox = styled(Box)`
|
|
421
|
+
background: ${props => props.theme.colors.neutral0};
|
|
422
|
+
border-radius: ${theme.borderRadius.xl};
|
|
423
|
+
border: 2px dashed ${props => props.theme.colors.neutral300};
|
|
424
|
+
padding: 80px 32px;
|
|
425
|
+
text-align: center;
|
|
426
|
+
position: relative;
|
|
427
|
+
overflow: hidden;
|
|
428
|
+
min-height: 400px;
|
|
429
|
+
display: flex;
|
|
430
|
+
align-items: center;
|
|
431
|
+
justify-content: center;
|
|
432
|
+
`;
|
|
433
|
+
|
|
434
|
+
const EmptyStateGradient = styled.div`
|
|
435
|
+
position: absolute;
|
|
436
|
+
top: 0;
|
|
437
|
+
left: 0;
|
|
438
|
+
right: 0;
|
|
439
|
+
bottom: 0;
|
|
440
|
+
background: linear-gradient(135deg, ${theme.colors.primary[50]} 0%, ${theme.colors.secondary[50]} 100%);
|
|
441
|
+
opacity: 0.3;
|
|
442
|
+
z-index: 0;
|
|
443
|
+
`;
|
|
444
|
+
|
|
482
445
|
const HomePage = () => {
|
|
446
|
+
const { formatMessage } = useIntl();
|
|
483
447
|
const { get, post, del } = useFetchClient();
|
|
484
448
|
const { toggleNotification } = useNotification();
|
|
485
449
|
const { isPremium } = useLicense();
|
|
450
|
+
const t = (id, defaultMessage, values) => formatMessage({ id: getTranslation(id), defaultMessage }, values);
|
|
486
451
|
const [sessions, setSessions] = useState([]);
|
|
487
452
|
const [loading, setLoading] = useState(true);
|
|
488
453
|
const [filterStatus, setFilterStatus] = useState('active'); // Default: Active Only
|
|
@@ -518,7 +483,7 @@ const HomePage = () => {
|
|
|
518
483
|
};
|
|
519
484
|
|
|
520
485
|
const handleTerminateSession = async (sessionId) => {
|
|
521
|
-
if (!confirm('Are you sure you want to terminate this session?\n\nThis will set isActive to false (user will be logged out).')) {
|
|
486
|
+
if (!confirm(t('homepage.confirm.terminate', 'Are you sure you want to terminate this session?\n\nThis will set isActive to false (user will be logged out).'))) {
|
|
522
487
|
return;
|
|
523
488
|
}
|
|
524
489
|
|
|
@@ -531,7 +496,7 @@ const HomePage = () => {
|
|
|
531
496
|
};
|
|
532
497
|
|
|
533
498
|
const handleDeleteSession = async (sessionId) => {
|
|
534
|
-
if (!confirm('
|
|
499
|
+
if (!confirm(t('homepage.confirm.delete', '[WARNING] This will PERMANENTLY delete this session from the database!\n\nThis action cannot be undone.\n\nAre you sure?'))) {
|
|
535
500
|
return;
|
|
536
501
|
}
|
|
537
502
|
|
|
@@ -540,13 +505,13 @@ const HomePage = () => {
|
|
|
540
505
|
fetchSessions();
|
|
541
506
|
toggleNotification({
|
|
542
507
|
type: 'success',
|
|
543
|
-
message: 'Session permanently deleted',
|
|
508
|
+
message: t('notifications.success.deleted', 'Session permanently deleted'),
|
|
544
509
|
});
|
|
545
510
|
} catch (err) {
|
|
546
511
|
console.error('[SessionManager] Error deleting session:', err);
|
|
547
512
|
toggleNotification({
|
|
548
513
|
type: 'danger',
|
|
549
|
-
message: 'Failed to delete session',
|
|
514
|
+
message: t('notifications.error.delete', 'Failed to delete session'),
|
|
550
515
|
});
|
|
551
516
|
}
|
|
552
517
|
};
|
|
@@ -555,7 +520,7 @@ const HomePage = () => {
|
|
|
555
520
|
if (!isPremium) {
|
|
556
521
|
toggleNotification({
|
|
557
522
|
type: 'warning',
|
|
558
|
-
message: 'Premium license required for export functionality',
|
|
523
|
+
message: t('notifications.warning.premiumRequired', 'Premium license required for export functionality'),
|
|
559
524
|
});
|
|
560
525
|
return;
|
|
561
526
|
}
|
|
@@ -600,13 +565,13 @@ const HomePage = () => {
|
|
|
600
565
|
|
|
601
566
|
toggleNotification({
|
|
602
567
|
type: 'success',
|
|
603
|
-
message:
|
|
568
|
+
message: t('notifications.success.exported', 'Exported {count} sessions to {format}', { count: filteredSessions.length, format: 'CSV' }),
|
|
604
569
|
});
|
|
605
570
|
} catch (err) {
|
|
606
571
|
console.error('[SessionManager] Export error:', err);
|
|
607
572
|
toggleNotification({
|
|
608
573
|
type: 'danger',
|
|
609
|
-
message: 'Failed to export sessions',
|
|
574
|
+
message: t('notifications.error.export', 'Failed to export sessions'),
|
|
610
575
|
});
|
|
611
576
|
}
|
|
612
577
|
};
|
|
@@ -615,7 +580,7 @@ const HomePage = () => {
|
|
|
615
580
|
if (!isPremium) {
|
|
616
581
|
toggleNotification({
|
|
617
582
|
type: 'warning',
|
|
618
|
-
message: 'Premium license required for export functionality',
|
|
583
|
+
message: t('notifications.warning.premiumRequired', 'Premium license required for export functionality'),
|
|
619
584
|
});
|
|
620
585
|
return;
|
|
621
586
|
}
|
|
@@ -661,13 +626,13 @@ const HomePage = () => {
|
|
|
661
626
|
|
|
662
627
|
toggleNotification({
|
|
663
628
|
type: 'success',
|
|
664
|
-
message:
|
|
629
|
+
message: t('notifications.success.exported', 'Exported {count} sessions to {format}', { count: filteredSessions.length, format: 'JSON' }),
|
|
665
630
|
});
|
|
666
631
|
} catch (err) {
|
|
667
632
|
console.error('[SessionManager] Export error:', err);
|
|
668
633
|
toggleNotification({
|
|
669
634
|
type: 'danger',
|
|
670
|
-
message: 'Failed to export sessions',
|
|
635
|
+
message: t('notifications.error.export', 'Failed to export sessions'),
|
|
671
636
|
});
|
|
672
637
|
}
|
|
673
638
|
};
|
|
@@ -741,10 +706,10 @@ const HomePage = () => {
|
|
|
741
706
|
<HeaderContent justifyContent="space-between" alignItems="center">
|
|
742
707
|
<Flex direction="column" alignItems="flex-start" gap={2}>
|
|
743
708
|
<Title>
|
|
744
|
-
<Monitor /> Session Manager
|
|
709
|
+
<Monitor /> {t('homepage.title', 'Session Manager')}
|
|
745
710
|
</Title>
|
|
746
711
|
<Subtitle>
|
|
747
|
-
Monitor and manage user sessions in real-time
|
|
712
|
+
{t('homepage.subtitle', 'Monitor and manage user sessions in real-time')}
|
|
748
713
|
</Subtitle>
|
|
749
714
|
</Flex>
|
|
750
715
|
|
|
@@ -762,7 +727,7 @@ const HomePage = () => {
|
|
|
762
727
|
fontWeight: '600',
|
|
763
728
|
}}
|
|
764
729
|
>
|
|
765
|
-
Export CSV
|
|
730
|
+
{t('homepage.export.csv', 'Export CSV')}
|
|
766
731
|
</Button>
|
|
767
732
|
<Button
|
|
768
733
|
onClick={handleExportJSON}
|
|
@@ -776,7 +741,7 @@ const HomePage = () => {
|
|
|
776
741
|
fontWeight: '600',
|
|
777
742
|
}}
|
|
778
743
|
>
|
|
779
|
-
Export JSON
|
|
744
|
+
{t('homepage.export.json', 'Export JSON')}
|
|
780
745
|
</Button>
|
|
781
746
|
</Flex>
|
|
782
747
|
)}
|
|
@@ -790,7 +755,7 @@ const HomePage = () => {
|
|
|
790
755
|
<Check />
|
|
791
756
|
</StatIcon>
|
|
792
757
|
<StatValue className="stat-value">{activeSessions.length}</StatValue>
|
|
793
|
-
<StatLabel>Active</StatLabel>
|
|
758
|
+
<StatLabel>{t('homepage.stats.active', 'Active')}</StatLabel>
|
|
794
759
|
</StatCard>
|
|
795
760
|
|
|
796
761
|
<StatCard $delay="0.2s" $color={theme.colors.warning[500]}>
|
|
@@ -798,7 +763,7 @@ const HomePage = () => {
|
|
|
798
763
|
<Clock />
|
|
799
764
|
</StatIcon>
|
|
800
765
|
<StatValue className="stat-value">{idleSessions.length}</StatValue>
|
|
801
|
-
<StatLabel>Idle</StatLabel>
|
|
766
|
+
<StatLabel>{t('homepage.stats.idle', 'Idle')}</StatLabel>
|
|
802
767
|
</StatCard>
|
|
803
768
|
|
|
804
769
|
<StatCard $delay="0.3s" $color={theme.colors.danger[500]}>
|
|
@@ -806,30 +771,30 @@ const HomePage = () => {
|
|
|
806
771
|
<Cross />
|
|
807
772
|
</StatIcon>
|
|
808
773
|
<StatValue className="stat-value">{loggedOutSessions.length}</StatValue>
|
|
809
|
-
<StatLabel>Logged Out</StatLabel>
|
|
774
|
+
<StatLabel>{t('homepage.stats.loggedOut', 'Logged Out')}</StatLabel>
|
|
810
775
|
</StatCard>
|
|
811
776
|
|
|
812
|
-
<StatCard $delay="0.4s" $color=
|
|
813
|
-
<StatIcon className="stat-icon" $bg=
|
|
777
|
+
<StatCard $delay="0.4s" $color="#4B5563">
|
|
778
|
+
<StatIcon className="stat-icon" $bg="#F3F4F6" $color="#4B5563">
|
|
814
779
|
<Cross />
|
|
815
780
|
</StatIcon>
|
|
816
781
|
<StatValue className="stat-value">{terminatedSessions.length}</StatValue>
|
|
817
|
-
<StatLabel>Terminated</StatLabel>
|
|
782
|
+
<StatLabel>{t('homepage.stats.terminated', 'Terminated')}</StatLabel>
|
|
818
783
|
</StatCard>
|
|
819
784
|
|
|
820
|
-
<StatCard $delay="0.5s" $color=
|
|
821
|
-
<StatIcon className="stat-icon" $bg=
|
|
785
|
+
<StatCard $delay="0.5s" $color="#A855F7">
|
|
786
|
+
<StatIcon className="stat-icon" $bg="#EDE9FE" $color="#9333EA">
|
|
822
787
|
<User />
|
|
823
788
|
</StatIcon>
|
|
824
789
|
<StatValue className="stat-value">{sessions.length}</StatValue>
|
|
825
|
-
<StatLabel>Total</StatLabel>
|
|
790
|
+
<StatLabel>{t('homepage.stats.total', 'Total')}</StatLabel>
|
|
826
791
|
</StatCard>
|
|
827
792
|
</StatsGrid>
|
|
828
793
|
|
|
829
794
|
{/* Loading */}
|
|
830
795
|
{loading && (
|
|
831
796
|
<Flex justifyContent="center" padding={8}>
|
|
832
|
-
<Loader>Loading sessions
|
|
797
|
+
<Loader>{t('homepage.loading', 'Loading sessions...')}</Loader>
|
|
833
798
|
</Flex>
|
|
834
799
|
)}
|
|
835
800
|
|
|
@@ -837,8 +802,8 @@ const HomePage = () => {
|
|
|
837
802
|
{!loading && sessions.length > 0 && (
|
|
838
803
|
<Box>
|
|
839
804
|
<Box style={{ marginBottom: theme.spacing.md }}>
|
|
840
|
-
<Typography variant="delta" style={{ marginBottom: theme.spacing.md
|
|
841
|
-
|
|
805
|
+
<Typography variant="delta" textColor="neutral700" style={{ marginBottom: theme.spacing.md }}>
|
|
806
|
+
{t('homepage.allSessions', 'All Sessions')}
|
|
842
807
|
</Typography>
|
|
843
808
|
</Box>
|
|
844
809
|
|
|
@@ -850,7 +815,7 @@ const HomePage = () => {
|
|
|
850
815
|
<StyledSearchInput
|
|
851
816
|
value={searchQuery}
|
|
852
817
|
onChange={(e) => setSearchQuery(e.target.value)}
|
|
853
|
-
placeholder=
|
|
818
|
+
placeholder={t('homepage.search.placeholder', 'Search by user, IP address, or device...')}
|
|
854
819
|
type="text"
|
|
855
820
|
/>
|
|
856
821
|
</SearchInputWrapper>
|
|
@@ -863,11 +828,11 @@ const HomePage = () => {
|
|
|
863
828
|
placeholder="Filter"
|
|
864
829
|
size="S"
|
|
865
830
|
>
|
|
866
|
-
<SingleSelectOption value="all">All Sessions</SingleSelectOption>
|
|
867
|
-
<SingleSelectOption value="active"
|
|
868
|
-
<SingleSelectOption value="idle"
|
|
869
|
-
<SingleSelectOption value="loggedout"
|
|
870
|
-
<SingleSelectOption value="terminated"
|
|
831
|
+
<SingleSelectOption value="all">{t('homepage.filter.all', 'All Sessions')}</SingleSelectOption>
|
|
832
|
+
<SingleSelectOption value="active">{t('homepage.filter.active', 'Active (less than 15 min)')}</SingleSelectOption>
|
|
833
|
+
<SingleSelectOption value="idle">{t('homepage.filter.idle', 'Idle (more than 15 min)')}</SingleSelectOption>
|
|
834
|
+
<SingleSelectOption value="loggedout">{t('homepage.filter.loggedout', 'Logged Out')}</SingleSelectOption>
|
|
835
|
+
<SingleSelectOption value="terminated">{t('homepage.filter.terminated', 'Terminated')}</SingleSelectOption>
|
|
871
836
|
</SingleSelect>
|
|
872
837
|
</Box>
|
|
873
838
|
|
|
@@ -879,10 +844,10 @@ const HomePage = () => {
|
|
|
879
844
|
placeholder="Entries"
|
|
880
845
|
size="S"
|
|
881
846
|
>
|
|
882
|
-
<SingleSelectOption value="10">10 entries</SingleSelectOption>
|
|
883
|
-
<SingleSelectOption value="25">25 entries</SingleSelectOption>
|
|
884
|
-
<SingleSelectOption value="50">50 entries</SingleSelectOption>
|
|
885
|
-
<SingleSelectOption value="100">100 entries</SingleSelectOption>
|
|
847
|
+
<SingleSelectOption value="10">{t('homepage.entries.10', '10 entries')}</SingleSelectOption>
|
|
848
|
+
<SingleSelectOption value="25">{t('homepage.entries.25', '25 entries')}</SingleSelectOption>
|
|
849
|
+
<SingleSelectOption value="50">{t('homepage.entries.50', '50 entries')}</SingleSelectOption>
|
|
850
|
+
<SingleSelectOption value="100">{t('homepage.entries.100', '100 entries')}</SingleSelectOption>
|
|
886
851
|
</SingleSelect>
|
|
887
852
|
</Box>
|
|
888
853
|
</FilterBar>
|
|
@@ -890,8 +855,10 @@ const HomePage = () => {
|
|
|
890
855
|
{/* Results count */}
|
|
891
856
|
<Box style={{ marginBottom: theme.spacing.md }}>
|
|
892
857
|
<Typography variant="pi" textColor="neutral600">
|
|
893
|
-
|
|
894
|
-
|
|
858
|
+
{searchQuery
|
|
859
|
+
? t('homepage.showingFiltered', 'Showing {count} of {total} sessions (filtered by "{query}")', { count: filteredSessions.length, total: sessions.length, query: searchQuery })
|
|
860
|
+
: t('homepage.showing', 'Showing {count} of {total} sessions', { count: filteredSessions.length, total: sessions.length })
|
|
861
|
+
}
|
|
895
862
|
</Typography>
|
|
896
863
|
</Box>
|
|
897
864
|
|
|
@@ -901,13 +868,13 @@ const HomePage = () => {
|
|
|
901
868
|
<StyledTable>
|
|
902
869
|
<Thead>
|
|
903
870
|
<Tr>
|
|
904
|
-
<Th>Status</Th>
|
|
905
|
-
<Th>User</Th>
|
|
906
|
-
<Th>Device</Th>
|
|
907
|
-
<Th>IP Address</Th>
|
|
908
|
-
<Th>Login Time</Th>
|
|
909
|
-
<Th>Last Active</Th>
|
|
910
|
-
<Th>Actions</Th>
|
|
871
|
+
<Th>{t('homepage.table.status', 'Status')}</Th>
|
|
872
|
+
<Th>{t('homepage.table.user', 'User')}</Th>
|
|
873
|
+
<Th>{t('homepage.table.device', 'Device')}</Th>
|
|
874
|
+
<Th>{t('homepage.table.ipAddress', 'IP Address')}</Th>
|
|
875
|
+
<Th>{t('homepage.table.loginTime', 'Login Time')}</Th>
|
|
876
|
+
<Th>{t('homepage.table.lastActive', 'Last Active')}</Th>
|
|
877
|
+
<Th>{t('homepage.table.actions', 'Actions')}</Th>
|
|
911
878
|
</Tr>
|
|
912
879
|
</Thead>
|
|
913
880
|
<Tbody>
|
|
@@ -921,26 +888,26 @@ const HomePage = () => {
|
|
|
921
888
|
active: {
|
|
922
889
|
bg: theme.colors.success[50],
|
|
923
890
|
badgeColor: 'success600',
|
|
924
|
-
label: '
|
|
891
|
+
label: t('homepage.status.active', 'Active'),
|
|
925
892
|
indicator: true
|
|
926
893
|
},
|
|
927
894
|
idle: {
|
|
928
895
|
bg: theme.colors.warning[50],
|
|
929
896
|
badgeColor: 'warning600',
|
|
930
|
-
label: '
|
|
897
|
+
label: t('homepage.status.idle', 'Idle'),
|
|
931
898
|
indicator: false
|
|
932
899
|
},
|
|
933
900
|
loggedout: {
|
|
934
901
|
bg: theme.colors.danger[50],
|
|
935
902
|
badgeColor: 'danger600',
|
|
936
|
-
label: '
|
|
903
|
+
label: t('homepage.status.loggedOut', 'Logged Out'),
|
|
937
904
|
indicator: false,
|
|
938
905
|
opacity: 0.7
|
|
939
906
|
},
|
|
940
907
|
terminated: {
|
|
941
|
-
bg:
|
|
908
|
+
bg: '#F3F4F6',
|
|
942
909
|
badgeColor: 'neutral600',
|
|
943
|
-
label: '
|
|
910
|
+
label: t('homepage.status.terminated', 'Terminated'),
|
|
944
911
|
indicator: false,
|
|
945
912
|
opacity: 0.6
|
|
946
913
|
},
|
|
@@ -975,7 +942,7 @@ const HomePage = () => {
|
|
|
975
942
|
<Td>
|
|
976
943
|
<Flex direction="column" alignItems="flex-start">
|
|
977
944
|
<Typography fontWeight="semiBold" ellipsis>
|
|
978
|
-
{session.user?.username || session.user?.email || 'Unknown'}
|
|
945
|
+
{session.user?.username || session.user?.email || t('homepage.user.unknown', 'Unknown')}
|
|
979
946
|
</Typography>
|
|
980
947
|
{session.user?.email && session.user?.username && (
|
|
981
948
|
<Typography variant="pi" textColor="neutral600" ellipsis>
|
|
@@ -1021,7 +988,7 @@ const HomePage = () => {
|
|
|
1021
988
|
{new Date(session.lastActive || session.loginTime).toLocaleString()}
|
|
1022
989
|
</Typography>
|
|
1023
990
|
<Typography variant="pi" textColor={sessionStatus === 'active' ? 'success600' : 'neutral500'}>
|
|
1024
|
-
{
|
|
991
|
+
{t('homepage.time.minAgo', '{minutes} min ago', { minutes: session.minutesSinceActive })}
|
|
1025
992
|
</Typography>
|
|
1026
993
|
</Flex>
|
|
1027
994
|
</Td>
|
|
@@ -1036,7 +1003,7 @@ const HomePage = () => {
|
|
|
1036
1003
|
e.stopPropagation();
|
|
1037
1004
|
handleSessionClick(session);
|
|
1038
1005
|
}}
|
|
1039
|
-
title=
|
|
1006
|
+
title={t('homepage.actions.viewDetails', 'View Details')}
|
|
1040
1007
|
>
|
|
1041
1008
|
<Eye />
|
|
1042
1009
|
</Button>
|
|
@@ -1048,7 +1015,7 @@ const HomePage = () => {
|
|
|
1048
1015
|
handleTerminateSession(session.id);
|
|
1049
1016
|
}}
|
|
1050
1017
|
disabled={sessionStatus !== 'active' && sessionStatus !== 'idle'}
|
|
1051
|
-
title={session.isActive ?
|
|
1018
|
+
title={session.isActive ? t('homepage.actions.terminate', 'Terminate (Logout)') : t('homepage.actions.alreadyInactive', 'Already inactive')}
|
|
1052
1019
|
>
|
|
1053
1020
|
<Cross />
|
|
1054
1021
|
</Button>
|
|
@@ -1059,7 +1026,7 @@ const HomePage = () => {
|
|
|
1059
1026
|
e.stopPropagation();
|
|
1060
1027
|
handleDeleteSession(session.id);
|
|
1061
1028
|
}}
|
|
1062
|
-
title=
|
|
1029
|
+
title={t('homepage.actions.deletePermanently', 'Delete Permanently')}
|
|
1063
1030
|
>
|
|
1064
1031
|
<Trash />
|
|
1065
1032
|
</Button>
|
|
@@ -1074,10 +1041,10 @@ const HomePage = () => {
|
|
|
1074
1041
|
) : (
|
|
1075
1042
|
/* No results found */
|
|
1076
1043
|
<Box
|
|
1044
|
+
background="neutral0"
|
|
1077
1045
|
style={{
|
|
1078
|
-
background: theme.colors.neutral[0],
|
|
1079
1046
|
borderRadius: theme.borderRadius.xl,
|
|
1080
|
-
border:
|
|
1047
|
+
border: '2px dashed #E5E7EB',
|
|
1081
1048
|
padding: '60px 32px',
|
|
1082
1049
|
textAlign: 'center',
|
|
1083
1050
|
position: 'relative',
|
|
@@ -1122,19 +1089,19 @@ const HomePage = () => {
|
|
|
1122
1089
|
boxShadow: theme.shadows.xl,
|
|
1123
1090
|
}}
|
|
1124
1091
|
>
|
|
1125
|
-
<Search style={{ width: '50px', height: '50px', color:
|
|
1092
|
+
<Search style={{ width: '50px', height: '50px', color: '#0284C7' }} />
|
|
1126
1093
|
</Box>
|
|
1127
1094
|
|
|
1128
1095
|
<Typography
|
|
1129
1096
|
variant="alpha"
|
|
1097
|
+
textColor="neutral800"
|
|
1130
1098
|
style={{
|
|
1131
1099
|
fontSize: '1.5rem',
|
|
1132
1100
|
fontWeight: '700',
|
|
1133
|
-
color: theme.colors.neutral[800],
|
|
1134
1101
|
marginBottom: '4px',
|
|
1135
1102
|
}}
|
|
1136
1103
|
>
|
|
1137
|
-
No sessions found
|
|
1104
|
+
{t('homepage.noResults.title', 'No sessions found')}
|
|
1138
1105
|
</Typography>
|
|
1139
1106
|
|
|
1140
1107
|
<Typography
|
|
@@ -1146,7 +1113,7 @@ const HomePage = () => {
|
|
|
1146
1113
|
lineHeight: '1.6',
|
|
1147
1114
|
}}
|
|
1148
1115
|
>
|
|
1149
|
-
Try adjusting your search query or filters to find sessions
|
|
1116
|
+
{t('homepage.noResults.description', 'Try adjusting your search query or filters to find sessions')}
|
|
1150
1117
|
</Typography>
|
|
1151
1118
|
</Flex>
|
|
1152
1119
|
</Box>
|
|
@@ -1157,10 +1124,10 @@ const HomePage = () => {
|
|
|
1157
1124
|
{/* Empty State */}
|
|
1158
1125
|
{!loading && sessions.length === 0 && (
|
|
1159
1126
|
<Box
|
|
1127
|
+
background="neutral0"
|
|
1160
1128
|
style={{
|
|
1161
|
-
background: theme.colors.neutral[0],
|
|
1162
1129
|
borderRadius: theme.borderRadius.xl,
|
|
1163
|
-
border:
|
|
1130
|
+
border: '2px dashed #E5E7EB',
|
|
1164
1131
|
padding: '80px 32px',
|
|
1165
1132
|
textAlign: 'center',
|
|
1166
1133
|
position: 'relative',
|
|
@@ -1185,10 +1152,7 @@ const HomePage = () => {
|
|
|
1185
1152
|
}}
|
|
1186
1153
|
/>
|
|
1187
1154
|
|
|
1188
|
-
{/* Floating
|
|
1189
|
-
<FloatingEmoji>
|
|
1190
|
-
💻
|
|
1191
|
-
</FloatingEmoji>
|
|
1155
|
+
{/* Floating Icon (removed emoji) */}
|
|
1192
1156
|
|
|
1193
1157
|
<Flex direction="column" alignItems="center" gap={6} style={{ position: 'relative', zIndex: 1 }}>
|
|
1194
1158
|
<Box
|
|
@@ -1203,19 +1167,19 @@ const HomePage = () => {
|
|
|
1203
1167
|
boxShadow: theme.shadows.xl,
|
|
1204
1168
|
}}
|
|
1205
1169
|
>
|
|
1206
|
-
<Monitor style={{ width: '60px', height: '60px', color:
|
|
1170
|
+
<Monitor style={{ width: '60px', height: '60px', color: '#0284C7' }} />
|
|
1207
1171
|
</Box>
|
|
1208
1172
|
|
|
1209
1173
|
<Typography
|
|
1210
1174
|
variant="alpha"
|
|
1175
|
+
textColor="neutral800"
|
|
1211
1176
|
style={{
|
|
1212
1177
|
fontSize: '1.75rem',
|
|
1213
1178
|
fontWeight: '700',
|
|
1214
|
-
color: theme.colors.neutral[800],
|
|
1215
1179
|
marginBottom: '8px',
|
|
1216
1180
|
}}
|
|
1217
1181
|
>
|
|
1218
|
-
No sessions yet
|
|
1182
|
+
{t('homepage.empty.title', 'No sessions yet')}
|
|
1219
1183
|
</Typography>
|
|
1220
1184
|
|
|
1221
1185
|
<Typography
|
|
@@ -1227,7 +1191,7 @@ const HomePage = () => {
|
|
|
1227
1191
|
lineHeight: '1.6',
|
|
1228
1192
|
}}
|
|
1229
1193
|
>
|
|
1230
|
-
Sessions will appear here when users log in to your application
|
|
1194
|
+
{t('homepage.empty.description', 'Sessions will appear here when users log in to your application')}
|
|
1231
1195
|
</Typography>
|
|
1232
1196
|
</Flex>
|
|
1233
1197
|
</Box>
|