strapi-plugin-magic-sessionmanager 4.0.1 → 4.0.3
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/OnlineUsersWidget.jsx +11 -7
- package/admin/src/components/SessionDetailModal.jsx +42 -38
- package/admin/src/components/SessionInfoPanel.jsx +29 -20
- package/admin/src/index.js +9 -0
- package/admin/src/pages/HomePage.jsx +128 -161
- package/admin/src/pages/License.jsx +3 -3
- package/admin/src/pages/Settings.jsx +139 -135
- 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/theme.js +85 -0
- package/dist/_chunks/{Analytics-Dv9f_0eZ.mjs → Analytics-DTE_zmRV.mjs} +2 -2
- package/dist/_chunks/{Analytics-BBdv1I5y.js → Analytics-lw_JaOVy.js} +2 -2
- package/dist/_chunks/{App-CJaZPNjt.js → App-DDKYCjKw.js} +216 -206
- package/dist/_chunks/{App-CIQ-7sa7.mjs → App-DJW1ZNl5.mjs} +216 -206
- package/dist/_chunks/{License-nrmFxoBm.mjs → License-DaOFuImm.mjs} +4 -8
- package/dist/_chunks/{License-D24rgaZQ.js → License-Tk-6UfPl.js} +4 -8
- 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-D5dLEGc_.mjs → Settings-C9xvckgq.mjs} +191 -179
- package/dist/_chunks/{Settings-CqxgjU0y.js → Settings-DyEAuTNQ.js} +191 -179
- 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-WH04CS1c.js → index-CWcvrfXc.js} +45 -42
- package/dist/_chunks/{index-Duk1_Wrz.mjs → index-DQO9bNP7.mjs} +45 -42
- package/dist/_chunks/pt-21-MAb72.js +277 -0
- package/dist/_chunks/pt-zsdTSjba.mjs +277 -0
- package/dist/_chunks/{useLicense-BwOlCyhc.js → useLicense-DtvJOszr.js} +1 -1
- package/dist/_chunks/{useLicense-Ce8GaxB0.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 +1 -1
- package/dist/server/index.mjs +1 -1
- package/package.json +1 -1
- 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,11 +1,12 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useState, useEffect } from "react";
|
|
3
|
+
import { useIntl } from "react-intl";
|
|
3
4
|
import { Flex, Loader, Typography, Button, Box, Badge, Accordion, Grid, SingleSelect, SingleSelectOption, Divider, Alert, TextInput, Toggle, NumberInput, Checkbox, Tabs } from "@strapi/design-system";
|
|
4
5
|
import { useFetchClient, useNotification } from "@strapi/strapi/admin";
|
|
5
6
|
import { Check, Information, Cog, Trash, Shield, Code, Duplicate, Mail } from "@strapi/icons";
|
|
6
7
|
import styled, { css, keyframes } from "styled-components";
|
|
7
|
-
import { a as pluginId } from "./index-
|
|
8
|
-
import { u as useLicense } from "./useLicense-
|
|
8
|
+
import { a as pluginId, g as getTranslation } from "./index-DQO9bNP7.mjs";
|
|
9
|
+
import { u as useLicense } from "./useLicense-DxbD4Wf8.mjs";
|
|
9
10
|
const theme = {
|
|
10
11
|
colors: {
|
|
11
12
|
primary: { 600: "#0284C7", 700: "#075985", 100: "#E0F2FE", 50: "#F0F9FF" },
|
|
@@ -13,7 +14,6 @@ const theme = {
|
|
|
13
14
|
danger: { 600: "#DC2626" },
|
|
14
15
|
neutral: { 0: "#FFFFFF", 200: "#E5E7EB", 400: "#9CA3AF", 700: "#374151" }
|
|
15
16
|
},
|
|
16
|
-
shadows: { sm: "0 1px 3px rgba(0,0,0,0.1)" },
|
|
17
17
|
borderRadius: { md: "8px", lg: "12px" }
|
|
18
18
|
};
|
|
19
19
|
const fadeIn = keyframes`
|
|
@@ -33,9 +33,9 @@ const StickySaveBar = styled(Box)`
|
|
|
33
33
|
position: sticky;
|
|
34
34
|
top: 0;
|
|
35
35
|
z-index: 10;
|
|
36
|
-
background:
|
|
37
|
-
border-bottom: 1px solid ${theme.colors.
|
|
38
|
-
box-shadow:
|
|
36
|
+
background: ${(props) => props.theme.colors.neutral0};
|
|
37
|
+
border-bottom: 1px solid ${(props) => props.theme.colors.neutral200};
|
|
38
|
+
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
|
|
39
39
|
`;
|
|
40
40
|
const ToggleCard = styled(Box)`
|
|
41
41
|
background: ${(props) => props.$active ? "linear-gradient(135deg, #f0fdf4 0%, #dcfce7 100%)" : "linear-gradient(135deg, #fafafa 0%, #f3f4f6 100%)"};
|
|
@@ -333,9 +333,11 @@ const generateSecureKey = () => {
|
|
|
333
333
|
return key;
|
|
334
334
|
};
|
|
335
335
|
const SettingsPage = () => {
|
|
336
|
+
const { formatMessage } = useIntl();
|
|
336
337
|
const { get, post, put } = useFetchClient();
|
|
337
338
|
const { toggleNotification } = useNotification();
|
|
338
339
|
const { isPremium, isAdvanced, isEnterprise } = useLicense();
|
|
340
|
+
const t = (id, defaultMessage, values) => formatMessage({ id: getTranslation(id), defaultMessage }, values);
|
|
339
341
|
const [loading, setLoading] = useState(true);
|
|
340
342
|
const [saving, setSaving] = useState(false);
|
|
341
343
|
const [hasChanges, setHasChanges] = useState(false);
|
|
@@ -401,7 +403,7 @@ const SettingsPage = () => {
|
|
|
401
403
|
console.error("[Settings] Error loading from backend:", err);
|
|
402
404
|
toggleNotification({
|
|
403
405
|
type: "warning",
|
|
404
|
-
message: "Could not load settings from server. Using defaults."
|
|
406
|
+
message: t("notifications.warning.settingsLoad", "Could not load settings from server. Using defaults.")
|
|
405
407
|
});
|
|
406
408
|
setSettings((prev) => ({ ...prev, emailTemplates: getDefaultTemplates() }));
|
|
407
409
|
} finally {
|
|
@@ -419,7 +421,7 @@ const SettingsPage = () => {
|
|
|
419
421
|
if (response?.data?.success) {
|
|
420
422
|
toggleNotification({
|
|
421
423
|
type: "success",
|
|
422
|
-
message: "Settings saved successfully to database!"
|
|
424
|
+
message: t("notifications.success.saved", "Settings saved successfully to database!")
|
|
423
425
|
});
|
|
424
426
|
setHasChanges(false);
|
|
425
427
|
try {
|
|
@@ -434,7 +436,7 @@ const SettingsPage = () => {
|
|
|
434
436
|
console.error("[Settings] Error saving:", err);
|
|
435
437
|
toggleNotification({
|
|
436
438
|
type: "danger",
|
|
437
|
-
message: "Failed to save settings to server"
|
|
439
|
+
message: t("notifications.error.save", "Failed to save settings to server")
|
|
438
440
|
});
|
|
439
441
|
} finally {
|
|
440
442
|
setSaving(false);
|
|
@@ -445,7 +447,7 @@ const SettingsPage = () => {
|
|
|
445
447
|
setHasChanges(false);
|
|
446
448
|
};
|
|
447
449
|
const handleCleanInactive = async () => {
|
|
448
|
-
if (!confirm("[WARNING] This will permanently delete ALL inactive sessions.\n\nContinue?")) {
|
|
450
|
+
if (!confirm(t("settings.general.danger.confirm", "[WARNING] This will permanently delete ALL inactive sessions.\n\nContinue?"))) {
|
|
449
451
|
return;
|
|
450
452
|
}
|
|
451
453
|
setCleaning(true);
|
|
@@ -453,28 +455,31 @@ const SettingsPage = () => {
|
|
|
453
455
|
const { data } = await post(`/${pluginId}/sessions/clean-inactive`);
|
|
454
456
|
toggleNotification({
|
|
455
457
|
type: "success",
|
|
456
|
-
message:
|
|
458
|
+
message: t("notifications.success.cleaned", "Successfully deleted {count} inactive sessions!", { count: data.deletedCount })
|
|
457
459
|
});
|
|
458
460
|
} catch (err) {
|
|
459
461
|
toggleNotification({
|
|
460
462
|
type: "danger",
|
|
461
|
-
message: "Failed to delete inactive sessions"
|
|
463
|
+
message: t("notifications.error.clean", "Failed to delete inactive sessions")
|
|
462
464
|
});
|
|
463
465
|
} finally {
|
|
464
466
|
setCleaning(false);
|
|
465
467
|
}
|
|
466
468
|
};
|
|
467
469
|
if (loading) {
|
|
468
|
-
return /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 8, children: /* @__PURE__ */ jsx(Loader, { children: "Loading
|
|
470
|
+
return /* @__PURE__ */ jsx(Flex, { justifyContent: "center", padding: 8, children: /* @__PURE__ */ jsx(Loader, { children: t("common.loading", "Loading...") }) });
|
|
469
471
|
}
|
|
470
472
|
return /* @__PURE__ */ jsxs(Container, { children: [
|
|
471
473
|
/* @__PURE__ */ jsx(StickySaveBar, { paddingTop: 5, paddingBottom: 5, paddingLeft: 6, paddingRight: 6, children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", children: [
|
|
472
474
|
/* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 1, alignItems: "flex-start", children: [
|
|
473
|
-
/* @__PURE__ */
|
|
474
|
-
|
|
475
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "alpha", fontWeight: "bold", style: { fontSize: "24px" }, children: [
|
|
476
|
+
"⚙️ ",
|
|
477
|
+
t("settings.title", "Session Manager Settings")
|
|
478
|
+
] }),
|
|
479
|
+
/* @__PURE__ */ jsx(Typography, { variant: "epsilon", textColor: "neutral600", children: t("settings.subtitle", "Configure session tracking, security, and email notifications") })
|
|
475
480
|
] }),
|
|
476
481
|
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
477
|
-
hasChanges && /* @__PURE__ */ jsx(Button, { onClick: handleReset, variant: "tertiary", size: "L", children: "Reset" }),
|
|
482
|
+
hasChanges && /* @__PURE__ */ jsx(Button, { onClick: handleReset, variant: "tertiary", size: "L", children: t("settings.reset", "Reset") }),
|
|
478
483
|
/* @__PURE__ */ jsx(
|
|
479
484
|
Button,
|
|
480
485
|
{
|
|
@@ -502,7 +507,7 @@ const SettingsPage = () => {
|
|
|
502
507
|
e.currentTarget.style.transform = "translateY(0)";
|
|
503
508
|
e.currentTarget.style.boxShadow = hasChanges && !saving ? "0 4px 12px rgba(102, 126, 234, 0.4)" : "none";
|
|
504
509
|
},
|
|
505
|
-
children: saving ? "Saving..." : hasChanges ? "Save Changes" : "No Changes"
|
|
510
|
+
children: saving ? t("settings.saving", "Saving...") : hasChanges ? t("settings.save", "Save Changes") : t("settings.noChanges", "No Changes")
|
|
506
511
|
}
|
|
507
512
|
)
|
|
508
513
|
] })
|
|
@@ -511,19 +516,22 @@ const SettingsPage = () => {
|
|
|
511
516
|
/* @__PURE__ */ jsx(Box, { padding: 4, background: "primary50", hasRadius: true, style: { marginBottom: "24px", border: "1px solid #bae6fd" }, children: /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "center", children: [
|
|
512
517
|
/* @__PURE__ */ jsx(Information, { style: { width: "20px", height: "20px", color: "#0284C7" } }),
|
|
513
518
|
/* @__PURE__ */ jsxs(Box, { children: [
|
|
514
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", textColor: "primary700", style: { marginBottom: "4px" }, children: "Current License Status" }),
|
|
519
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", textColor: "primary700", style: { marginBottom: "4px" }, children: t("settings.license.title", "Current License Status") }),
|
|
515
520
|
/* @__PURE__ */ jsxs(Flex, { gap: 3, children: [
|
|
516
521
|
/* @__PURE__ */ jsxs(Badge, { backgroundColor: isPremium ? "success100" : "neutral100", textColor: isPremium ? "success700" : "neutral600", children: [
|
|
517
522
|
isPremium ? "✓" : "✗",
|
|
518
|
-
"
|
|
523
|
+
" ",
|
|
524
|
+
t("settings.license.premium", "Premium")
|
|
519
525
|
] }),
|
|
520
526
|
/* @__PURE__ */ jsxs(Badge, { backgroundColor: isAdvanced ? "primary100" : "neutral100", textColor: isAdvanced ? "primary700" : "neutral600", children: [
|
|
521
527
|
isAdvanced ? "✓" : "✗",
|
|
522
|
-
"
|
|
528
|
+
" ",
|
|
529
|
+
t("settings.license.advanced", "Advanced")
|
|
523
530
|
] }),
|
|
524
531
|
/* @__PURE__ */ jsxs(Badge, { backgroundColor: isEnterprise ? "secondary100" : "neutral100", textColor: isEnterprise ? "secondary700" : "neutral600", children: [
|
|
525
532
|
isEnterprise ? "✓" : "✗",
|
|
526
|
-
"
|
|
533
|
+
" ",
|
|
534
|
+
t("settings.license.enterprise", "Enterprise")
|
|
527
535
|
] })
|
|
528
536
|
] })
|
|
529
537
|
] })
|
|
@@ -534,114 +542,99 @@ const SettingsPage = () => {
|
|
|
534
542
|
Accordion.Trigger,
|
|
535
543
|
{
|
|
536
544
|
icon: Cog,
|
|
537
|
-
description: "Basic session tracking configuration",
|
|
538
|
-
children: "General Settings"
|
|
545
|
+
description: t("settings.general.description", "Basic session tracking configuration"),
|
|
546
|
+
children: t("settings.general.title", "General Settings")
|
|
539
547
|
}
|
|
540
548
|
) }),
|
|
541
549
|
/* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsxs(Box, { padding: 6, children: [
|
|
542
|
-
/* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "16px", display: "block", color: theme.colors.neutral[700] }, children: "SESSION TIMEOUT" }),
|
|
550
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "16px", display: "block", color: theme.colors.neutral[700] }, children: t("settings.general.timeout.title", "SESSION TIMEOUT") }),
|
|
543
551
|
/* @__PURE__ */ jsxs(Grid.Root, { gap: 6, style: { marginBottom: "32px" }, children: [
|
|
544
552
|
/* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
545
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Inactivity Timeout" }),
|
|
553
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.timeout.inactivity", "Inactivity Timeout") }),
|
|
546
554
|
/* @__PURE__ */ jsxs(
|
|
547
555
|
SingleSelect,
|
|
548
556
|
{
|
|
549
557
|
value: String(settings.inactivityTimeout),
|
|
550
558
|
onChange: (value) => handleChange("inactivityTimeout", parseInt(value)),
|
|
551
559
|
children: [
|
|
552
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "5", children: "5 minutes (Very Strict)" }),
|
|
553
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "10", children: "10 minutes (Strict)" }),
|
|
554
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "15", children: "15 minutes (Recommended)" }),
|
|
555
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30", children: "30 minutes (Moderate)" }),
|
|
556
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "60", children: "1 hour (Relaxed)" }),
|
|
557
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "120", children: "2 hours (Very Relaxed)" })
|
|
560
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "5", children: t("settings.general.timeout.5min", "5 minutes (Very Strict)") }),
|
|
561
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "10", children: t("settings.general.timeout.10min", "10 minutes (Strict)") }),
|
|
562
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "15", children: t("settings.general.timeout.15min", "15 minutes (Recommended)") }),
|
|
563
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30", children: t("settings.general.timeout.30min", "30 minutes (Moderate)") }),
|
|
564
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "60", children: t("settings.general.timeout.1hour", "1 hour (Relaxed)") }),
|
|
565
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "120", children: t("settings.general.timeout.2hours", "2 hours (Very Relaxed)") })
|
|
558
566
|
]
|
|
559
567
|
}
|
|
560
568
|
),
|
|
561
|
-
/* @__PURE__ */
|
|
562
|
-
"Sessions inactive for more than ",
|
|
563
|
-
settings.inactivityTimeout,
|
|
564
|
-
" minutes will be marked as offline"
|
|
565
|
-
] })
|
|
569
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t("settings.general.timeout.inactivityHint", "Sessions inactive for more than {minutes} minutes will be marked as offline", { minutes: settings.inactivityTimeout }) })
|
|
566
570
|
] }) }),
|
|
567
571
|
/* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
568
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Last Seen Rate Limit" }),
|
|
572
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.rateLimit.title", "Last Seen Rate Limit") }),
|
|
569
573
|
/* @__PURE__ */ jsxs(
|
|
570
574
|
SingleSelect,
|
|
571
575
|
{
|
|
572
576
|
value: String(settings.lastSeenRateLimit),
|
|
573
577
|
onChange: (value) => handleChange("lastSeenRateLimit", parseInt(value)),
|
|
574
578
|
children: [
|
|
575
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "10", children: "10 seconds" }),
|
|
576
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30", children: "30 seconds (Recommended)" }),
|
|
577
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "60", children: "1 minute" }),
|
|
578
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "120", children: "2 minutes" }),
|
|
579
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "300", children: "5 minutes" })
|
|
579
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "10", children: t("settings.general.rateLimit.10sec", "10 seconds") }),
|
|
580
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30", children: t("settings.general.rateLimit.30sec", "30 seconds (Recommended)") }),
|
|
581
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "60", children: t("settings.general.rateLimit.1min", "1 minute") }),
|
|
582
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "120", children: t("settings.general.rateLimit.2min", "2 minutes") }),
|
|
583
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "300", children: t("settings.general.rateLimit.5min", "5 minutes") })
|
|
580
584
|
]
|
|
581
585
|
}
|
|
582
586
|
),
|
|
583
|
-
/* @__PURE__ */
|
|
584
|
-
"Prevents excessive database writes. Updates throttled to once every ",
|
|
585
|
-
settings.lastSeenRateLimit,
|
|
586
|
-
" seconds"
|
|
587
|
-
] })
|
|
587
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t("settings.general.rateLimit.hint", "Prevents excessive database writes. Updates throttled to once every {seconds} seconds", { seconds: settings.lastSeenRateLimit }) })
|
|
588
588
|
] }) })
|
|
589
589
|
] }),
|
|
590
590
|
/* @__PURE__ */ jsx(Divider, { style: { marginBottom: "24px" } }),
|
|
591
|
-
/* @__PURE__ */
|
|
591
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "16px", display: "block", color: theme.colors.neutral[700] }, children: [
|
|
592
|
+
"🧹 ",
|
|
593
|
+
t("settings.general.cleanup.title", "AUTO-CLEANUP & RETENTION")
|
|
594
|
+
] }),
|
|
592
595
|
/* @__PURE__ */ jsxs(Grid.Root, { gap: 6, children: [
|
|
593
596
|
/* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
594
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Cleanup Interval" }),
|
|
597
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.cleanup.interval", "Cleanup Interval") }),
|
|
595
598
|
/* @__PURE__ */ jsxs(
|
|
596
599
|
SingleSelect,
|
|
597
600
|
{
|
|
598
601
|
value: String(settings.cleanupInterval),
|
|
599
602
|
onChange: (value) => handleChange("cleanupInterval", parseInt(value)),
|
|
600
603
|
children: [
|
|
601
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "15", children: "15 minutes" }),
|
|
602
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30", children: "30 minutes (Recommended)" }),
|
|
603
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "60", children: "1 hour" }),
|
|
604
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "120", children: "2 hours" })
|
|
604
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "15", children: t("settings.general.cleanup.15min", "15 minutes") }),
|
|
605
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30", children: t("settings.general.cleanup.30min", "30 minutes (Recommended)") }),
|
|
606
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "60", children: t("settings.general.cleanup.1hour", "1 hour") }),
|
|
607
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "120", children: t("settings.general.cleanup.2hours", "2 hours") })
|
|
605
608
|
]
|
|
606
609
|
}
|
|
607
610
|
),
|
|
608
|
-
/* @__PURE__ */
|
|
609
|
-
"Inactive sessions are automatically cleaned every ",
|
|
610
|
-
settings.cleanupInterval,
|
|
611
|
-
" minutes"
|
|
612
|
-
] })
|
|
611
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: t("settings.general.cleanup.intervalHint", "Inactive sessions are automatically cleaned every {minutes} minutes", { minutes: settings.cleanupInterval }) })
|
|
613
612
|
] }) }),
|
|
614
613
|
/* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
615
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Retention Period" }),
|
|
614
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.retention.title", "Retention Period") }),
|
|
616
615
|
/* @__PURE__ */ jsxs(
|
|
617
616
|
SingleSelect,
|
|
618
617
|
{
|
|
619
618
|
value: String(settings.retentionDays),
|
|
620
619
|
onChange: (value) => handleChange("retentionDays", parseInt(value)),
|
|
621
620
|
children: [
|
|
622
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "7", children: "7 days" }),
|
|
623
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30", children: "30 days" }),
|
|
624
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "60", children: "60 days" }),
|
|
625
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "90", children: "90 days (Recommended)" }),
|
|
626
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "180", children: "180 days" }),
|
|
627
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "365", children: "1 year" }),
|
|
628
|
-
/* @__PURE__ */ jsx(SingleSelectOption, { value: "-1", children: "Forever" })
|
|
621
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "7", children: t("settings.general.retention.7days", "7 days") }),
|
|
622
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "30", children: t("settings.general.retention.30days", "30 days") }),
|
|
623
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "60", children: t("settings.general.retention.60days", "60 days") }),
|
|
624
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "90", children: t("settings.general.retention.90days", "90 days (Recommended)") }),
|
|
625
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "180", children: t("settings.general.retention.180days", "180 days") }),
|
|
626
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "365", children: t("settings.general.retention.1year", "1 year") }),
|
|
627
|
+
/* @__PURE__ */ jsx(SingleSelectOption, { value: "-1", children: t("settings.general.retention.forever", "Forever") })
|
|
629
628
|
]
|
|
630
629
|
}
|
|
631
630
|
),
|
|
632
|
-
/* @__PURE__ */
|
|
633
|
-
"Old sessions deleted after ",
|
|
634
|
-
settings.retentionDays === -1 ? "never" : `${settings.retentionDays} days`
|
|
635
|
-
] })
|
|
631
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "11px", marginTop: "8px" }, children: settings.retentionDays === -1 ? t("settings.general.retention.hintNever", "Old sessions deleted after never") : t("settings.general.retention.hint", "Old sessions deleted after {days}", { days: `${settings.retentionDays} days` }) })
|
|
636
632
|
] }) }),
|
|
637
633
|
/* @__PURE__ */ jsx(Grid.Item, { col: 12, children: /* @__PURE__ */ jsx(Box, { padding: 4, background: "danger100", style: { borderRadius: theme.borderRadius.md, border: `2px solid ${theme.colors.danger[200]}` }, children: /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-start", children: [
|
|
638
634
|
/* @__PURE__ */ jsx(Trash, { style: { width: "18px", height: "18px", color: theme.colors.danger[600], flexShrink: 0, marginTop: "2px" } }),
|
|
639
635
|
/* @__PURE__ */ jsxs(Box, { style: { flex: 1 }, children: [
|
|
640
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", textColor: "danger700", style: { marginBottom: "8px", display: "block" }, children: "Danger Zone" }),
|
|
641
|
-
/* @__PURE__ */
|
|
642
|
-
/* @__PURE__ */ jsx("strong", { children: "Clean All Inactive:" }),
|
|
643
|
-
" Permanently deletes all inactive sessions. This cannot be undone."
|
|
644
|
-
] })
|
|
636
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", textColor: "danger700", style: { marginBottom: "8px", display: "block" }, children: t("settings.general.danger.title", "Danger Zone") }),
|
|
637
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "danger600", style: { fontSize: "13px", lineHeight: "1.7" }, children: t("settings.general.danger.description", "Clean All Inactive: Permanently deletes all inactive sessions. This cannot be undone.") })
|
|
645
638
|
] }),
|
|
646
639
|
/* @__PURE__ */ jsx(
|
|
647
640
|
Button,
|
|
@@ -652,7 +645,7 @@ const SettingsPage = () => {
|
|
|
652
645
|
variant: "danger",
|
|
653
646
|
size: "S",
|
|
654
647
|
style: { flexShrink: 0 },
|
|
655
|
-
children: "Clean Now"
|
|
648
|
+
children: t("settings.general.danger.cleanNow", "Clean Now")
|
|
656
649
|
}
|
|
657
650
|
)
|
|
658
651
|
] }) }) })
|
|
@@ -664,12 +657,12 @@ const SettingsPage = () => {
|
|
|
664
657
|
Accordion.Trigger,
|
|
665
658
|
{
|
|
666
659
|
icon: Shield,
|
|
667
|
-
description: "Security policies and threat protection",
|
|
668
|
-
children: "Security Settings"
|
|
660
|
+
description: t("settings.security.description", "Security policies and threat protection"),
|
|
661
|
+
children: t("settings.security.title", "Security Settings")
|
|
669
662
|
}
|
|
670
663
|
) }),
|
|
671
664
|
/* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsxs(Box, { padding: 6, children: [
|
|
672
|
-
/* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "16px", display: "block", color: theme.colors.neutral[700] }, children: "SECURITY OPTIONS" }),
|
|
665
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "16px", display: "block", color: theme.colors.neutral[700] }, children: t("settings.security.options", "SECURITY OPTIONS") }),
|
|
673
666
|
/* @__PURE__ */ jsx(
|
|
674
667
|
Box,
|
|
675
668
|
{
|
|
@@ -684,32 +677,26 @@ const SettingsPage = () => {
|
|
|
684
677
|
children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 4, children: [
|
|
685
678
|
/* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 3, children: [
|
|
686
679
|
/* @__PURE__ */ jsx(Shield, { style: { width: 24, height: 24, color: theme.colors.primary[600] } }),
|
|
687
|
-
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: "JWT Encryption Key Generator" })
|
|
680
|
+
/* @__PURE__ */ jsx(Typography, { variant: "delta", fontWeight: "bold", children: t("settings.security.encryption.title", "JWT Encryption Key Generator") })
|
|
688
681
|
] }),
|
|
689
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { lineHeight: 1.6 }, children: "Generate a secure 32-character encryption key for JWT token storage. This key is used to encrypt tokens before saving them to the database." }),
|
|
690
|
-
/* @__PURE__ */
|
|
682
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", textColor: "neutral600", style: { lineHeight: 1.6 }, children: t("settings.security.encryption.description", "Generate a secure 32-character encryption key for JWT token storage. This key is used to encrypt tokens before saving them to the database.") }),
|
|
683
|
+
/* @__PURE__ */ jsx(
|
|
691
684
|
Alert,
|
|
692
685
|
{
|
|
693
686
|
variant: "default",
|
|
694
|
-
title: "Important",
|
|
687
|
+
title: t("settings.security.encryption.important", "Important"),
|
|
695
688
|
style: { marginTop: 8 },
|
|
696
|
-
children:
|
|
697
|
-
"Add this key to your ",
|
|
698
|
-
/* @__PURE__ */ jsx("code", { children: ".env" }),
|
|
699
|
-
" file as ",
|
|
700
|
-
/* @__PURE__ */ jsx("strong", { children: "SESSION_ENCRYPTION_KEY" }),
|
|
701
|
-
" for production."
|
|
702
|
-
]
|
|
689
|
+
children: t("settings.security.encryption.envHint", "Add this key to your .env file as SESSION_ENCRYPTION_KEY for production.")
|
|
703
690
|
}
|
|
704
691
|
),
|
|
705
692
|
/* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-end", children: [
|
|
706
693
|
/* @__PURE__ */ jsx(Box, { style: { flex: 1 }, children: /* @__PURE__ */ jsx(
|
|
707
694
|
TextInput,
|
|
708
695
|
{
|
|
709
|
-
label: "Generated Encryption Key",
|
|
696
|
+
label: t("settings.security.encryption.label", "Generated Encryption Key"),
|
|
710
697
|
value: encryptionKey,
|
|
711
698
|
onChange: (e) => setEncryptionKey(e.target.value),
|
|
712
|
-
placeholder: "Click 'Generate Key' to create a secure key",
|
|
699
|
+
placeholder: t("settings.security.encryption.placeholder", "Click 'Generate Key' to create a secure key"),
|
|
713
700
|
type: showEncryptionKey ? "text" : "password"
|
|
714
701
|
}
|
|
715
702
|
) }),
|
|
@@ -719,7 +706,7 @@ const SettingsPage = () => {
|
|
|
719
706
|
variant: "secondary",
|
|
720
707
|
onClick: () => setShowEncryptionKey(!showEncryptionKey),
|
|
721
708
|
size: "L",
|
|
722
|
-
children: showEncryptionKey ? "Hide" : "Show"
|
|
709
|
+
children: showEncryptionKey ? t("settings.security.encryption.hide", "Hide") : t("settings.security.encryption.show", "Show")
|
|
723
710
|
}
|
|
724
711
|
)
|
|
725
712
|
] }),
|
|
@@ -735,11 +722,11 @@ const SettingsPage = () => {
|
|
|
735
722
|
setShowEncryptionKey(true);
|
|
736
723
|
toggleNotification({
|
|
737
724
|
type: "success",
|
|
738
|
-
message: "32-character encryption key generated!"
|
|
725
|
+
message: t("notifications.success.keyGenerated", "32-character encryption key generated!")
|
|
739
726
|
});
|
|
740
727
|
},
|
|
741
728
|
size: "L",
|
|
742
|
-
children: "Generate Key"
|
|
729
|
+
children: t("settings.security.encryption.generate", "Generate Key")
|
|
743
730
|
}
|
|
744
731
|
),
|
|
745
732
|
/* @__PURE__ */ jsx(
|
|
@@ -752,13 +739,13 @@ const SettingsPage = () => {
|
|
|
752
739
|
navigator.clipboard.writeText(encryptionKey);
|
|
753
740
|
toggleNotification({
|
|
754
741
|
type: "success",
|
|
755
|
-
message: "Encryption key copied to clipboard!"
|
|
742
|
+
message: t("notifications.success.keyCopied", "Encryption key copied to clipboard!")
|
|
756
743
|
});
|
|
757
744
|
}
|
|
758
745
|
},
|
|
759
746
|
disabled: !encryptionKey,
|
|
760
747
|
size: "L",
|
|
761
|
-
children: "Copy to Clipboard"
|
|
748
|
+
children: t("settings.security.encryption.copy", "Copy to Clipboard")
|
|
762
749
|
}
|
|
763
750
|
),
|
|
764
751
|
/* @__PURE__ */ jsx(
|
|
@@ -772,13 +759,13 @@ const SettingsPage = () => {
|
|
|
772
759
|
navigator.clipboard.writeText(envLine);
|
|
773
760
|
toggleNotification({
|
|
774
761
|
type: "success",
|
|
775
|
-
message: "Copied as .env format!"
|
|
762
|
+
message: t("notifications.success.envCopied", "Copied as .env format!")
|
|
776
763
|
});
|
|
777
764
|
}
|
|
778
765
|
},
|
|
779
766
|
disabled: !encryptionKey,
|
|
780
767
|
size: "L",
|
|
781
|
-
children: "Copy for .env"
|
|
768
|
+
children: t("settings.security.encryption.copyEnv", "Copy for .env")
|
|
782
769
|
}
|
|
783
770
|
)
|
|
784
771
|
] }),
|
|
@@ -795,7 +782,7 @@ const SettingsPage = () => {
|
|
|
795
782
|
wordBreak: "break-all"
|
|
796
783
|
},
|
|
797
784
|
children: [
|
|
798
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", style: { marginBottom: 8, display: "block" }, children: "Add to .env file:" }),
|
|
785
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", style: { marginBottom: 8, display: "block" }, children: t("settings.security.encryption.envLabel", "Add to .env file:") }),
|
|
799
786
|
/* @__PURE__ */ jsxs("code", { style: { color: theme.colors.primary[700] }, children: [
|
|
800
787
|
"SESSION_ENCRYPTION_KEY=",
|
|
801
788
|
encryptionKey
|
|
@@ -828,10 +815,10 @@ const SettingsPage = () => {
|
|
|
828
815
|
fontWeight: "bold",
|
|
829
816
|
textColor: settings.blockSuspiciousSessions ? "success700" : "neutral800",
|
|
830
817
|
style: { fontSize: "16px" },
|
|
831
|
-
children: "Block Suspicious Sessions"
|
|
818
|
+
children: t("settings.security.blockSuspicious.title", "Block Suspicious Sessions")
|
|
832
819
|
}
|
|
833
820
|
),
|
|
834
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: "Automatically block sessions from VPNs, proxies, or threat IPs" })
|
|
821
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: t("settings.security.blockSuspicious.description", "Automatically block sessions from VPNs, proxies, or threat IPs") })
|
|
835
822
|
] })
|
|
836
823
|
] })
|
|
837
824
|
}
|
|
@@ -858,10 +845,10 @@ const SettingsPage = () => {
|
|
|
858
845
|
fontWeight: "bold",
|
|
859
846
|
textColor: settings.enableGeolocation ? "success700" : "neutral800",
|
|
860
847
|
style: { fontSize: "16px" },
|
|
861
|
-
children: "IP Geolocation"
|
|
848
|
+
children: t("settings.security.geolocation.title", "IP Geolocation")
|
|
862
849
|
}
|
|
863
850
|
),
|
|
864
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: "Fetch location data for each session (Premium)" })
|
|
851
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: t("settings.security.geolocation.description", "Fetch location data for each session (Premium)") })
|
|
865
852
|
] })
|
|
866
853
|
] })
|
|
867
854
|
}
|
|
@@ -887,10 +874,10 @@ const SettingsPage = () => {
|
|
|
887
874
|
fontWeight: "bold",
|
|
888
875
|
textColor: settings.enableSecurityScoring ? "success700" : "neutral800",
|
|
889
876
|
style: { fontSize: "16px" },
|
|
890
|
-
children: "Security Scoring"
|
|
877
|
+
children: t("settings.security.scoring.title", "Security Scoring")
|
|
891
878
|
}
|
|
892
879
|
),
|
|
893
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: "Calculate security scores and detect threats (Premium)" })
|
|
880
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: t("settings.security.scoring.description", "Calculate security scores and detect threats (Premium)") })
|
|
894
881
|
] })
|
|
895
882
|
] })
|
|
896
883
|
}
|
|
@@ -898,7 +885,10 @@ const SettingsPage = () => {
|
|
|
898
885
|
] })
|
|
899
886
|
] }) }),
|
|
900
887
|
/* @__PURE__ */ jsx(Grid.Root, { gap: 6, children: /* @__PURE__ */ jsx(Grid.Item, { col: 6, s: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
901
|
-
/* @__PURE__ */
|
|
888
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: [
|
|
889
|
+
"🚫 ",
|
|
890
|
+
t("settings.security.maxFailed.title", "Max Failed Login Attempts")
|
|
891
|
+
] }),
|
|
902
892
|
/* @__PURE__ */ jsx(
|
|
903
893
|
NumberInput,
|
|
904
894
|
{
|
|
@@ -908,11 +898,7 @@ const SettingsPage = () => {
|
|
|
908
898
|
max: 20
|
|
909
899
|
}
|
|
910
900
|
),
|
|
911
|
-
/* @__PURE__ */ jsx(Box, { padding: 2, background: "warning50", style: { borderRadius: "4px", marginTop: "8px" }, children: /* @__PURE__ */
|
|
912
|
-
"User will be blocked after ",
|
|
913
|
-
settings.maxFailedLogins,
|
|
914
|
-
" failed attempts"
|
|
915
|
-
] }) })
|
|
901
|
+
/* @__PURE__ */ jsx(Box, { padding: 2, background: "warning50", style: { borderRadius: "4px", marginTop: "8px" }, children: /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "warning700", style: { fontSize: "11px" }, children: t("settings.security.maxFailed.hint", "User will be blocked after {count} failed attempts", { count: settings.maxFailedLogins }) }) })
|
|
916
902
|
] }) }) })
|
|
917
903
|
] }) })
|
|
918
904
|
] }),
|
|
@@ -921,14 +907,17 @@ const SettingsPage = () => {
|
|
|
921
907
|
Accordion.Trigger,
|
|
922
908
|
{
|
|
923
909
|
icon: Mail,
|
|
924
|
-
description: "Email alerts for security events",
|
|
925
|
-
children: "Email Notifications (Advanced)"
|
|
910
|
+
description: t("settings.email.description", "Email alerts for security events"),
|
|
911
|
+
children: t("settings.email.title", "Email Notifications (Advanced)")
|
|
926
912
|
}
|
|
927
913
|
) }),
|
|
928
914
|
/* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsxs(Box, { padding: 6, children: [
|
|
929
915
|
/* @__PURE__ */ jsxs(Box, { background: "neutral100", padding: 5, style: { borderRadius: theme.borderRadius.md, marginBottom: "32px" }, children: [
|
|
930
|
-
/* @__PURE__ */
|
|
931
|
-
|
|
916
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", textAlign: "center", color: theme.colors.neutral[700] }, children: [
|
|
917
|
+
"📧 ",
|
|
918
|
+
t("settings.email.alerts.title", "EMAIL ALERTS")
|
|
919
|
+
] }),
|
|
920
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", textAlign: "center", fontSize: "12px" }, children: t("settings.email.alerts.subtitle", "Send security alerts to users via email") }),
|
|
932
921
|
/* @__PURE__ */ jsx(Grid.Root, { gap: 4, children: /* @__PURE__ */ jsx(Grid.Item, { col: 12, children: /* @__PURE__ */ jsx(
|
|
933
922
|
ToggleCard,
|
|
934
923
|
{
|
|
@@ -950,17 +939,20 @@ const SettingsPage = () => {
|
|
|
950
939
|
fontWeight: "bold",
|
|
951
940
|
textColor: settings.enableEmailAlerts ? "success700" : "neutral800",
|
|
952
941
|
style: { fontSize: "16px" },
|
|
953
|
-
children: "Enable Email Alerts"
|
|
942
|
+
children: t("settings.email.enable.title", "Enable Email Alerts")
|
|
954
943
|
}
|
|
955
944
|
),
|
|
956
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: "Send security alerts for suspicious logins, new locations, and VPN/Proxy usage" })
|
|
945
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: t("settings.email.enable.description", "Send security alerts for suspicious logins, new locations, and VPN/Proxy usage") })
|
|
957
946
|
] })
|
|
958
947
|
] })
|
|
959
948
|
}
|
|
960
949
|
) }) })
|
|
961
950
|
] }),
|
|
962
951
|
settings.enableEmailAlerts && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
963
|
-
/* @__PURE__ */
|
|
952
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "16px", display: "block", color: theme.colors.neutral[700] }, children: [
|
|
953
|
+
"⚙️ ",
|
|
954
|
+
t("settings.email.types.title", "ALERT TYPES")
|
|
955
|
+
] }),
|
|
964
956
|
/* @__PURE__ */ jsxs(Grid.Root, { gap: 4, style: { marginBottom: "32px" }, children: [
|
|
965
957
|
/* @__PURE__ */ jsx(Grid.Item, { col: 4, s: 12, children: /* @__PURE__ */ jsx(
|
|
966
958
|
Box,
|
|
@@ -979,7 +971,7 @@ const SettingsPage = () => {
|
|
|
979
971
|
{
|
|
980
972
|
checked: settings.alertOnSuspiciousLogin,
|
|
981
973
|
onChange: () => handleChange("alertOnSuspiciousLogin", !settings.alertOnSuspiciousLogin),
|
|
982
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", style: { fontSize: "14px" }, children: "Suspicious Login" })
|
|
974
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", style: { fontSize: "14px" }, children: t("settings.email.types.suspicious", "Suspicious Login") })
|
|
983
975
|
}
|
|
984
976
|
)
|
|
985
977
|
}
|
|
@@ -1001,7 +993,7 @@ const SettingsPage = () => {
|
|
|
1001
993
|
{
|
|
1002
994
|
checked: settings.alertOnNewLocation,
|
|
1003
995
|
onChange: () => handleChange("alertOnNewLocation", !settings.alertOnNewLocation),
|
|
1004
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", style: { fontSize: "14px" }, children: "New Location" })
|
|
996
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", style: { fontSize: "14px" }, children: t("settings.email.types.newLocation", "New Location") })
|
|
1005
997
|
}
|
|
1006
998
|
)
|
|
1007
999
|
}
|
|
@@ -1023,24 +1015,24 @@ const SettingsPage = () => {
|
|
|
1023
1015
|
{
|
|
1024
1016
|
checked: settings.alertOnVpnProxy,
|
|
1025
1017
|
onChange: () => handleChange("alertOnVpnProxy", !settings.alertOnVpnProxy),
|
|
1026
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", style: { fontSize: "14px" }, children: "VPN/Proxy" })
|
|
1018
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "semiBold", style: { fontSize: "14px" }, children: t("settings.email.types.vpnProxy", "VPN/Proxy") })
|
|
1027
1019
|
}
|
|
1028
1020
|
)
|
|
1029
1021
|
}
|
|
1030
1022
|
) })
|
|
1031
1023
|
] }),
|
|
1032
1024
|
/* @__PURE__ */ jsx(Divider, { style: { marginBottom: "24px" } }),
|
|
1033
|
-
/* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.neutral[700] }, children: "EMAIL TEMPLATES" }),
|
|
1034
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", fontSize: "12px" }, children: "Customize email notification templates with dynamic variables" }),
|
|
1025
|
+
/* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.neutral[700] }, children: t("settings.email.templates.title", "EMAIL TEMPLATES") }),
|
|
1026
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "20px", display: "block", fontSize: "12px" }, children: t("settings.email.templates.subtitle", "Customize email notification templates with dynamic variables") }),
|
|
1035
1027
|
/* @__PURE__ */ jsxs(Tabs.Root, { value: activeTemplateTab, onValueChange: setActiveTemplateTab, children: [
|
|
1036
1028
|
/* @__PURE__ */ jsxs(Tabs.List, { "aria-label": "Email Templates", children: [
|
|
1037
|
-
/* @__PURE__ */ jsx(Tabs.Trigger, { value: "suspiciousLogin", children: "Suspicious Login" }),
|
|
1038
|
-
/* @__PURE__ */ jsx(Tabs.Trigger, { value: "newLocation", children: "New Location" }),
|
|
1039
|
-
/* @__PURE__ */ jsx(Tabs.Trigger, { value: "vpnProxy", children: "VPN/Proxy" })
|
|
1029
|
+
/* @__PURE__ */ jsx(Tabs.Trigger, { value: "suspiciousLogin", children: t("settings.email.templates.tab.suspicious", "Suspicious Login") }),
|
|
1030
|
+
/* @__PURE__ */ jsx(Tabs.Trigger, { value: "newLocation", children: t("settings.email.templates.tab.newLocation", "New Location") }),
|
|
1031
|
+
/* @__PURE__ */ jsx(Tabs.Trigger, { value: "vpnProxy", children: t("settings.email.templates.tab.vpnProxy", "VPN/Proxy") })
|
|
1040
1032
|
] }),
|
|
1041
1033
|
Object.keys(settings.emailTemplates).map((templateKey) => /* @__PURE__ */ jsx(Tabs.Content, { value: templateKey, children: /* @__PURE__ */ jsxs(Box, { paddingTop: 4, children: [
|
|
1042
1034
|
/* @__PURE__ */ jsxs(Box, { style: { marginBottom: "24px" }, children: [
|
|
1043
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: "Email Subject" }),
|
|
1035
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "8px", display: "block" }, children: t("settings.email.templates.subject", "Email Subject") }),
|
|
1044
1036
|
/* @__PURE__ */ jsx(
|
|
1045
1037
|
TextInput,
|
|
1046
1038
|
{
|
|
@@ -1050,7 +1042,7 @@ const SettingsPage = () => {
|
|
|
1050
1042
|
newTemplates[templateKey].subject = e.target.value;
|
|
1051
1043
|
handleChange("emailTemplates", newTemplates);
|
|
1052
1044
|
},
|
|
1053
|
-
placeholder: "Enter email subject..."
|
|
1045
|
+
placeholder: t("settings.email.templates.subjectPlaceholder", "Enter email subject...")
|
|
1054
1046
|
}
|
|
1055
1047
|
)
|
|
1056
1048
|
] }),
|
|
@@ -1063,7 +1055,7 @@ const SettingsPage = () => {
|
|
|
1063
1055
|
children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
|
1064
1056
|
/* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, children: [
|
|
1065
1057
|
/* @__PURE__ */ jsx(Code, { style: { width: "16px", height: "16px", color: theme.colors.primary[600] } }),
|
|
1066
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", textColor: "primary600", children: "Available Variables (click to copy)" })
|
|
1058
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", textColor: "primary600", children: t("settings.email.templates.variables", "Available Variables (click to copy)") })
|
|
1067
1059
|
] }),
|
|
1068
1060
|
/* @__PURE__ */ jsx(Flex, { gap: 2, wrap: "wrap", children: TEMPLATE_VARIABLES[templateKey].map(({ var: variable, desc }) => /* @__PURE__ */ jsx(
|
|
1069
1061
|
Button,
|
|
@@ -1072,7 +1064,7 @@ const SettingsPage = () => {
|
|
|
1072
1064
|
variant: "tertiary",
|
|
1073
1065
|
onClick: () => {
|
|
1074
1066
|
navigator.clipboard.writeText(variable);
|
|
1075
|
-
toggleNotification({ type: "success", message:
|
|
1067
|
+
toggleNotification({ type: "success", message: t("notifications.success.variableCopied", "{variable} copied!", { variable }) });
|
|
1076
1068
|
},
|
|
1077
1069
|
style: {
|
|
1078
1070
|
fontFamily: "monospace",
|
|
@@ -1096,10 +1088,13 @@ const SettingsPage = () => {
|
|
|
1096
1088
|
children: [
|
|
1097
1089
|
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", style: { marginBottom: "16px" }, children: [
|
|
1098
1090
|
/* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, children: [
|
|
1099
|
-
/* @__PURE__ */
|
|
1100
|
-
|
|
1091
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "delta", fontWeight: "bold", style: { fontSize: "18px" }, children: [
|
|
1092
|
+
"🎨 ",
|
|
1093
|
+
t("settings.email.templates.html.title", "HTML Template")
|
|
1094
|
+
] }),
|
|
1095
|
+
/* @__PURE__ */ jsx(Badge, { variant: "success", children: t("settings.email.templates.html.badge", "Main Template") })
|
|
1101
1096
|
] }),
|
|
1102
|
-
/* @__PURE__ */
|
|
1097
|
+
/* @__PURE__ */ jsxs(
|
|
1103
1098
|
Button,
|
|
1104
1099
|
{
|
|
1105
1100
|
variant: "tertiary",
|
|
@@ -1109,17 +1104,16 @@ const SettingsPage = () => {
|
|
|
1109
1104
|
const newTemplates = { ...settings.emailTemplates };
|
|
1110
1105
|
newTemplates[templateKey].html = defaultTemplates[templateKey].html;
|
|
1111
1106
|
handleChange("emailTemplates", newTemplates);
|
|
1112
|
-
toggleNotification({ type: "success", message: "Default
|
|
1107
|
+
toggleNotification({ type: "success", message: t("notifications.success.defaultLoaded", "Default template loaded!") });
|
|
1113
1108
|
},
|
|
1114
|
-
children:
|
|
1109
|
+
children: [
|
|
1110
|
+
"📋 ",
|
|
1111
|
+
t("settings.email.templates.html.loadDefault", "Load Default")
|
|
1112
|
+
]
|
|
1115
1113
|
}
|
|
1116
1114
|
)
|
|
1117
1115
|
] }),
|
|
1118
|
-
/* @__PURE__ */
|
|
1119
|
-
"HTML template for email notifications. Use variables like ",
|
|
1120
|
-
/* @__PURE__ */ jsx("code", { children: "{{user.email}}" }),
|
|
1121
|
-
" for dynamic content."
|
|
1122
|
-
] }),
|
|
1116
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "16px", display: "block", fontSize: "14px" }, children: t("settings.email.templates.html.description", "HTML template for email notifications. Use variables like {{user.email}} for dynamic content.") }),
|
|
1123
1117
|
/* @__PURE__ */ jsxs(
|
|
1124
1118
|
Box,
|
|
1125
1119
|
{
|
|
@@ -1175,19 +1169,22 @@ const SettingsPage = () => {
|
|
|
1175
1169
|
}
|
|
1176
1170
|
),
|
|
1177
1171
|
/* @__PURE__ */ jsxs(Flex, { gap: 2, style: { marginTop: "12px" }, wrap: "wrap", children: [
|
|
1178
|
-
/* @__PURE__ */
|
|
1172
|
+
/* @__PURE__ */ jsxs(
|
|
1179
1173
|
Button,
|
|
1180
1174
|
{
|
|
1181
1175
|
variant: "secondary",
|
|
1182
1176
|
size: "S",
|
|
1183
1177
|
onClick: () => {
|
|
1184
1178
|
navigator.clipboard.writeText(settings.emailTemplates[templateKey].html);
|
|
1185
|
-
toggleNotification({ type: "success", message: "HTML template copied!" });
|
|
1179
|
+
toggleNotification({ type: "success", message: t("notifications.success.htmlCopied", "HTML template copied!") });
|
|
1186
1180
|
},
|
|
1187
|
-
children:
|
|
1181
|
+
children: [
|
|
1182
|
+
"📋 ",
|
|
1183
|
+
t("settings.email.templates.html.copy", "Copy Template")
|
|
1184
|
+
]
|
|
1188
1185
|
}
|
|
1189
1186
|
),
|
|
1190
|
-
/* @__PURE__ */
|
|
1187
|
+
/* @__PURE__ */ jsxs(
|
|
1191
1188
|
Button,
|
|
1192
1189
|
{
|
|
1193
1190
|
variant: "tertiary",
|
|
@@ -1196,13 +1193,16 @@ const SettingsPage = () => {
|
|
|
1196
1193
|
const validation = validateTemplate(settings.emailTemplates[templateKey].html, templateKey);
|
|
1197
1194
|
toggleNotification({
|
|
1198
1195
|
type: validation.isValid ? "success" : "warning",
|
|
1199
|
-
message: validation.isValid ?
|
|
1196
|
+
message: validation.isValid ? t("notifications.success.validated", "Template valid! Found {found}/{total} variables.", { found: validation.foundVars.length, total: validation.totalAvailable }) : t("notifications.warning.noVariables", "[WARNING] No variables found. Add at least one variable.")
|
|
1200
1197
|
});
|
|
1201
1198
|
},
|
|
1202
|
-
children:
|
|
1199
|
+
children: [
|
|
1200
|
+
"✓ ",
|
|
1201
|
+
t("settings.email.templates.html.validate", "Validate")
|
|
1202
|
+
]
|
|
1203
1203
|
}
|
|
1204
1204
|
),
|
|
1205
|
-
/* @__PURE__ */
|
|
1205
|
+
/* @__PURE__ */ jsxs(
|
|
1206
1206
|
Button,
|
|
1207
1207
|
{
|
|
1208
1208
|
variant: "tertiary",
|
|
@@ -1212,10 +1212,13 @@ const SettingsPage = () => {
|
|
|
1212
1212
|
const chars = settings.emailTemplates[templateKey].html.length;
|
|
1213
1213
|
toggleNotification({
|
|
1214
1214
|
type: "info",
|
|
1215
|
-
message:
|
|
1215
|
+
message: t("notifications.info.templateStats", "Template has {lines} lines and {chars} characters", { lines, chars })
|
|
1216
1216
|
});
|
|
1217
1217
|
},
|
|
1218
|
-
children:
|
|
1218
|
+
children: [
|
|
1219
|
+
"ℹ️ ",
|
|
1220
|
+
t("settings.email.templates.html.info", "Template Info")
|
|
1221
|
+
]
|
|
1219
1222
|
}
|
|
1220
1223
|
)
|
|
1221
1224
|
] })
|
|
@@ -1231,10 +1234,13 @@ const SettingsPage = () => {
|
|
|
1231
1234
|
children: [
|
|
1232
1235
|
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", style: { marginBottom: "16px" }, children: [
|
|
1233
1236
|
/* @__PURE__ */ jsxs(Flex, { alignItems: "center", gap: 2, children: [
|
|
1234
|
-
/* @__PURE__ */
|
|
1235
|
-
|
|
1237
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "delta", fontWeight: "bold", style: { fontSize: "18px" }, children: [
|
|
1238
|
+
"📄 ",
|
|
1239
|
+
t("settings.email.templates.text.title", "Text Template")
|
|
1240
|
+
] }),
|
|
1241
|
+
/* @__PURE__ */ jsx(Badge, { variant: "secondary", children: t("settings.email.templates.text.badge", "Fallback") })
|
|
1236
1242
|
] }),
|
|
1237
|
-
/* @__PURE__ */
|
|
1243
|
+
/* @__PURE__ */ jsxs(
|
|
1238
1244
|
Button,
|
|
1239
1245
|
{
|
|
1240
1246
|
variant: "tertiary",
|
|
@@ -1244,13 +1250,16 @@ const SettingsPage = () => {
|
|
|
1244
1250
|
const newTemplates = { ...settings.emailTemplates };
|
|
1245
1251
|
newTemplates[templateKey].text = defaultTemplates[templateKey].text;
|
|
1246
1252
|
handleChange("emailTemplates", newTemplates);
|
|
1247
|
-
toggleNotification({ type: "success", message: "Default
|
|
1253
|
+
toggleNotification({ type: "success", message: t("notifications.success.defaultLoaded", "Default template loaded!") });
|
|
1248
1254
|
},
|
|
1249
|
-
children:
|
|
1255
|
+
children: [
|
|
1256
|
+
"📋 ",
|
|
1257
|
+
t("settings.email.templates.text.loadDefault", "Load Default")
|
|
1258
|
+
]
|
|
1250
1259
|
}
|
|
1251
1260
|
)
|
|
1252
1261
|
] }),
|
|
1253
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "16px", display: "block", fontSize: "14px" }, children: "Plain text version (no HTML) as fallback for older email clients" }),
|
|
1262
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { marginBottom: "16px", display: "block", fontSize: "14px" }, children: t("settings.email.templates.text.description", "Plain text version (no HTML) as fallback for older email clients") }),
|
|
1254
1263
|
/* @__PURE__ */ jsxs(
|
|
1255
1264
|
Box,
|
|
1256
1265
|
{
|
|
@@ -1305,16 +1314,19 @@ const SettingsPage = () => {
|
|
|
1305
1314
|
]
|
|
1306
1315
|
}
|
|
1307
1316
|
),
|
|
1308
|
-
/* @__PURE__ */ jsx(Flex, { gap: 2, style: { marginTop: "12px" }, wrap: "wrap", children: /* @__PURE__ */
|
|
1317
|
+
/* @__PURE__ */ jsx(Flex, { gap: 2, style: { marginTop: "12px" }, wrap: "wrap", children: /* @__PURE__ */ jsxs(
|
|
1309
1318
|
Button,
|
|
1310
1319
|
{
|
|
1311
1320
|
variant: "secondary",
|
|
1312
1321
|
size: "S",
|
|
1313
1322
|
onClick: () => {
|
|
1314
1323
|
navigator.clipboard.writeText(settings.emailTemplates[templateKey].text);
|
|
1315
|
-
toggleNotification({ type: "success", message: "Text template copied!" });
|
|
1324
|
+
toggleNotification({ type: "success", message: t("notifications.success.textCopied", "Text template copied!") });
|
|
1316
1325
|
},
|
|
1317
|
-
children:
|
|
1326
|
+
children: [
|
|
1327
|
+
"📋 ",
|
|
1328
|
+
t("settings.email.templates.text.copy", "Copy Template")
|
|
1329
|
+
]
|
|
1318
1330
|
}
|
|
1319
1331
|
) })
|
|
1320
1332
|
]
|
|
@@ -1330,8 +1342,8 @@ const SettingsPage = () => {
|
|
|
1330
1342
|
Accordion.Trigger,
|
|
1331
1343
|
{
|
|
1332
1344
|
icon: Code,
|
|
1333
|
-
description: "Discord & Slack integration",
|
|
1334
|
-
children: "Webhook Integration (Advanced)"
|
|
1345
|
+
description: t("settings.webhooks.description", "Discord & Slack integration"),
|
|
1346
|
+
children: t("settings.webhooks.title", "Webhook Integration (Advanced)")
|
|
1335
1347
|
}
|
|
1336
1348
|
) }),
|
|
1337
1349
|
/* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsxs(Box, { padding: 6, children: [
|
|
@@ -1356,17 +1368,20 @@ const SettingsPage = () => {
|
|
|
1356
1368
|
fontWeight: "bold",
|
|
1357
1369
|
textColor: settings.enableWebhooks ? "success700" : "neutral800",
|
|
1358
1370
|
style: { fontSize: "16px" },
|
|
1359
|
-
children: "Enable Webhooks"
|
|
1371
|
+
children: t("settings.webhooks.enable.title", "Enable Webhooks")
|
|
1360
1372
|
}
|
|
1361
1373
|
),
|
|
1362
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: "Send session events to Discord, Slack, or custom endpoints" })
|
|
1374
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "13px", lineHeight: "1.6" }, children: t("settings.webhooks.enable.description", "Send session events to Discord, Slack, or custom endpoints") })
|
|
1363
1375
|
] })
|
|
1364
1376
|
] })
|
|
1365
1377
|
}
|
|
1366
1378
|
) }) }) }),
|
|
1367
1379
|
settings.enableWebhooks && /* @__PURE__ */ jsxs(Grid.Root, { gap: 6, children: [
|
|
1368
1380
|
/* @__PURE__ */ jsx(Grid.Item, { col: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
1369
|
-
/* @__PURE__ */
|
|
1381
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "12px", display: "block" }, children: [
|
|
1382
|
+
"🔗 ",
|
|
1383
|
+
t("settings.webhooks.discord.title", "Discord Webhook URL")
|
|
1384
|
+
] }),
|
|
1370
1385
|
/* @__PURE__ */ jsx(
|
|
1371
1386
|
Box,
|
|
1372
1387
|
{
|
|
@@ -1379,7 +1394,7 @@ const SettingsPage = () => {
|
|
|
1379
1394
|
children: /* @__PURE__ */ jsx(
|
|
1380
1395
|
"textarea",
|
|
1381
1396
|
{
|
|
1382
|
-
placeholder: "https://discord.com/api/webhooks/123456789/abcdefghijklmnopqrstuvwxyz...",
|
|
1397
|
+
placeholder: t("settings.webhooks.discord.placeholder", "https://discord.com/api/webhooks/123456789/abcdefghijklmnopqrstuvwxyz..."),
|
|
1383
1398
|
value: settings.discordWebhookUrl,
|
|
1384
1399
|
onChange: (e) => handleChange("discordWebhookUrl", e.target.value),
|
|
1385
1400
|
rows: 3,
|
|
@@ -1401,15 +1416,15 @@ const SettingsPage = () => {
|
|
|
1401
1416
|
}
|
|
1402
1417
|
),
|
|
1403
1418
|
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", style: { marginTop: "10px" }, children: [
|
|
1404
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px" }, children: "Optional: Post session alerts to your Discord channel" }),
|
|
1405
|
-
settings.discordWebhookUrl && /* @__PURE__ */
|
|
1406
|
-
settings.discordWebhookUrl.length,
|
|
1407
|
-
" characters"
|
|
1408
|
-
] })
|
|
1419
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px" }, children: t("settings.webhooks.discord.hint", "Optional: Post session alerts to your Discord channel") }),
|
|
1420
|
+
settings.discordWebhookUrl && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "primary600", style: { fontSize: "11px", fontFamily: "monospace" }, children: t("settings.webhooks.characters", "{count} characters", { count: settings.discordWebhookUrl.length }) })
|
|
1409
1421
|
] })
|
|
1410
1422
|
] }) }),
|
|
1411
1423
|
/* @__PURE__ */ jsx(Grid.Item, { col: 12, children: /* @__PURE__ */ jsxs(Box, { children: [
|
|
1412
|
-
/* @__PURE__ */
|
|
1424
|
+
/* @__PURE__ */ jsxs(Typography, { variant: "pi", fontWeight: "bold", style: { marginBottom: "12px", display: "block" }, children: [
|
|
1425
|
+
"💬 ",
|
|
1426
|
+
t("settings.webhooks.slack.title", "Slack Webhook URL")
|
|
1427
|
+
] }),
|
|
1413
1428
|
/* @__PURE__ */ jsx(
|
|
1414
1429
|
Box,
|
|
1415
1430
|
{
|
|
@@ -1422,7 +1437,7 @@ const SettingsPage = () => {
|
|
|
1422
1437
|
children: /* @__PURE__ */ jsx(
|
|
1423
1438
|
"textarea",
|
|
1424
1439
|
{
|
|
1425
|
-
placeholder: "https://hooks.slack.com/services/XXXX/XXXX/XXXX",
|
|
1440
|
+
placeholder: t("settings.webhooks.slack.placeholder", "https://hooks.slack.com/services/XXXX/XXXX/XXXX"),
|
|
1426
1441
|
value: settings.slackWebhookUrl,
|
|
1427
1442
|
onChange: (e) => handleChange("slackWebhookUrl", e.target.value),
|
|
1428
1443
|
rows: 3,
|
|
@@ -1444,11 +1459,8 @@ const SettingsPage = () => {
|
|
|
1444
1459
|
}
|
|
1445
1460
|
),
|
|
1446
1461
|
/* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", alignItems: "center", style: { marginTop: "10px" }, children: [
|
|
1447
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px" }, children: "Optional: Post session alerts to your Slack workspace" }),
|
|
1448
|
-
settings.slackWebhookUrl && /* @__PURE__ */
|
|
1449
|
-
settings.slackWebhookUrl.length,
|
|
1450
|
-
" characters"
|
|
1451
|
-
] })
|
|
1462
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "neutral600", style: { fontSize: "12px" }, children: t("settings.webhooks.slack.hint", "Optional: Post session alerts to your Slack workspace") }),
|
|
1463
|
+
settings.slackWebhookUrl && /* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "primary600", style: { fontSize: "11px", fontFamily: "monospace" }, children: t("settings.webhooks.characters", "{count} characters", { count: settings.slackWebhookUrl.length }) })
|
|
1452
1464
|
] })
|
|
1453
1465
|
] }) })
|
|
1454
1466
|
] })
|
|
@@ -1458,8 +1470,8 @@ const SettingsPage = () => {
|
|
|
1458
1470
|
/* @__PURE__ */ jsx(Box, { padding: 5, background: "primary100", style: { borderRadius: theme.borderRadius.md, marginTop: "32px", border: "2px solid #BAE6FD" }, children: /* @__PURE__ */ jsxs(Flex, { gap: 3, alignItems: "flex-start", children: [
|
|
1459
1471
|
/* @__PURE__ */ jsx(Check, { style: { width: "20px", height: "20px", color: theme.colors.success[600], flexShrink: 0, marginTop: "2px" } }),
|
|
1460
1472
|
/* @__PURE__ */ jsxs(Box, { style: { flex: 1 }, children: [
|
|
1461
|
-
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.primary[700] }, children: "Database-Backed Settings" }),
|
|
1462
|
-
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "primary700", style: { fontSize: "13px", lineHeight: "1.8" }, children: "All settings are stored in your Strapi database and shared across all admin users. Changes take effect immediately - no server restart required! Email templates, webhooks, and security options are all managed from this interface." })
|
|
1473
|
+
/* @__PURE__ */ jsx(Typography, { variant: "omega", fontWeight: "bold", style: { marginBottom: "8px", display: "block", color: theme.colors.primary[700] }, children: t("settings.footer.title", "Database-Backed Settings") }),
|
|
1474
|
+
/* @__PURE__ */ jsx(Typography, { variant: "pi", textColor: "primary700", style: { fontSize: "13px", lineHeight: "1.8" }, children: t("settings.footer.description", "All settings are stored in your Strapi database and shared across all admin users. Changes take effect immediately - no server restart required! Email templates, webhooks, and security options are all managed from this interface.") })
|
|
1463
1475
|
] })
|
|
1464
1476
|
] }) })
|
|
1465
1477
|
] })
|