From 34485a0cae285d7c3f83dddc92c878f1365fb3d2 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 23 Jun 2025 11:07:12 +0800 Subject: [PATCH 01/11] move queue to logs --- client/src/Components/Sidebar/index.jsx | 3 +- client/src/Components/StatusBoxes/index.jsx | 2 +- .../Queue/components/FailedJobTable/index.jsx | 4 +- .../Queue/components/JobTable/index.jsx | 6 +-- .../Logs/Queue/components/Metrics/index.jsx | 45 +++++++++++++++++++ .../Queue/components/MetricsTable/index.jsx | 2 +- client/src/Pages/{ => Logs}/Queue/index.jsx | 9 ++-- client/src/Pages/Logs/index.jsx | 41 +++++++++++++++++ client/src/Pages/Settings/SettingsDev.jsx | 37 --------------- client/src/Pages/Settings/index.jsx | 6 +-- client/src/Routes/index.jsx | 7 +-- client/src/Utils/Theme/globalTheme.js | 3 ++ client/src/assets/icons/logs.svg | 5 +++ client/src/locales/en.json | 11 +++-- 14 files changed, 119 insertions(+), 62 deletions(-) rename client/src/Pages/{ => Logs}/Queue/components/FailedJobTable/index.jsx (93%) rename client/src/Pages/{ => Logs}/Queue/components/JobTable/index.jsx (93%) create mode 100644 client/src/Pages/Logs/Queue/components/Metrics/index.jsx rename client/src/Pages/{ => Logs}/Queue/components/MetricsTable/index.jsx (95%) rename client/src/Pages/{ => Logs}/Queue/index.jsx (82%) create mode 100644 client/src/Pages/Logs/index.jsx delete mode 100644 client/src/Pages/Settings/SettingsDev.jsx create mode 100644 client/src/assets/icons/logs.svg diff --git a/client/src/Components/Sidebar/index.jsx b/client/src/Components/Sidebar/index.jsx index 06a140c54..e9f0d3ad7 100644 --- a/client/src/Components/Sidebar/index.jsx +++ b/client/src/Components/Sidebar/index.jsx @@ -8,7 +8,6 @@ import { ListItemButton, ListItemIcon, ListItemText, - ListSubheader, Menu, MenuItem, Stack, @@ -39,6 +38,7 @@ import Docs from "../../assets/icons/docs.svg?react"; import StatusPages from "../../assets/icons/status-pages.svg?react"; import Discussions from "../../assets/icons/discussions.svg?react"; import Notifications from "../../assets/icons/notifications.svg?react"; +import Logs from "../../assets/icons/logs.svg?react"; import "./index.css"; @@ -64,6 +64,7 @@ const getMenu = (t) => [ { name: t("menu.statusPages"), path: "status", icon: }, { name: t("menu.maintenance"), path: "maintenance", icon: }, + { name: t("menu.logs"), path: "logs", icon: }, { name: t("menu.settings"), diff --git a/client/src/Components/StatusBoxes/index.jsx b/client/src/Components/StatusBoxes/index.jsx index 40ea2d182..d97bb6211 100644 --- a/client/src/Components/StatusBoxes/index.jsx +++ b/client/src/Components/StatusBoxes/index.jsx @@ -4,7 +4,7 @@ import SkeletonLayout from "./skeleton"; // Utils import { useTheme } from "@mui/material/styles"; import PropTypes from "prop-types"; -const StatusBoxes = ({ shouldRender, flexWrap = "nowrap", children }) => { +const StatusBoxes = ({ shouldRender = true, flexWrap = "nowrap", children }) => { const theme = useTheme(); if (!shouldRender) { return ( diff --git a/client/src/Pages/Queue/components/FailedJobTable/index.jsx b/client/src/Pages/Logs/Queue/components/FailedJobTable/index.jsx similarity index 93% rename from client/src/Pages/Queue/components/FailedJobTable/index.jsx rename to client/src/Pages/Logs/Queue/components/FailedJobTable/index.jsx index d7284f9da..94fc2f5c3 100644 --- a/client/src/Pages/Queue/components/FailedJobTable/index.jsx +++ b/client/src/Pages/Logs/Queue/components/FailedJobTable/index.jsx @@ -1,10 +1,10 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; -import DataTable from "../../../../Components/Table"; +import DataTable from "../../../../../Components/Table"; import { useNavigate } from "react-router-dom"; import { useTheme } from "@emotion/react"; -import { TypeToPathMap } from "../../../../Utils/monitorUtils"; +import { TypeToPathMap } from "../../../../../Utils/monitorUtils"; import PropTypes from "prop-types"; import { useTranslation } from "react-i18next"; diff --git a/client/src/Pages/Queue/components/JobTable/index.jsx b/client/src/Pages/Logs/Queue/components/JobTable/index.jsx similarity index 93% rename from client/src/Pages/Queue/components/JobTable/index.jsx rename to client/src/Pages/Logs/Queue/components/JobTable/index.jsx index f4aa0768c..e27dd103f 100644 --- a/client/src/Pages/Queue/components/JobTable/index.jsx +++ b/client/src/Pages/Logs/Queue/components/JobTable/index.jsx @@ -1,13 +1,13 @@ import Stack from "@mui/material/Stack"; -import DataTable from "../../../../Components/Table"; +import DataTable from "../../../../../Components/Table"; import Typography from "@mui/material/Typography"; // Utils import PropTypes from "prop-types"; import { useTheme } from "@emotion/react"; import { useNavigate } from "react-router-dom"; -import { TypeToPathMap } from "../../../../Utils/monitorUtils"; +import { TypeToPathMap } from "../../../../../Utils/monitorUtils"; import { useTranslation } from "react-i18next"; -import { createHeaderFactory } from "../../../../Components/Table/TableUtils"; +import { createHeaderFactory } from "../../../../../Components/Table/TableUtils"; const JobTable = ({ jobs = [] }) => { const theme = useTheme(); diff --git a/client/src/Pages/Logs/Queue/components/Metrics/index.jsx b/client/src/Pages/Logs/Queue/components/Metrics/index.jsx new file mode 100644 index 000000000..52117cd3b --- /dev/null +++ b/client/src/Pages/Logs/Queue/components/Metrics/index.jsx @@ -0,0 +1,45 @@ +import Stack from "@mui/material/Stack"; +import Typography from "@mui/material/Typography"; +import StatBox from "../../../../../Components/StatBox"; +import StatusBoxes from "../../../../../Components/StatusBoxes"; + +import { useTranslation } from "react-i18next"; +import { useTheme } from "@emotion/react"; + +const camelToTitle = (str) => { + return str + .replace(/([A-Z])/g, " $1") + .toLowerCase() + .replace(/^./, (m) => m.toUpperCase()); +}; + +const Metrics = ({ metrics = {} }) => { + const { t } = useTranslation(); + const theme = useTheme(); + + const data = Object.keys(metrics) + .filter((key) => key !== "jobsWithFailures") + .map((key) => { + return { key, title: camelToTitle(key), value: metrics[key] }; + }); + + console.log(JSON.stringify(data, null, 2)); + + return ( + + {t("queuePage.metricsTable.title")} + + {data.map((metric) => { + return ( + + ); + })} + + + ); +}; +export default Metrics; diff --git a/client/src/Pages/Queue/components/MetricsTable/index.jsx b/client/src/Pages/Logs/Queue/components/MetricsTable/index.jsx similarity index 95% rename from client/src/Pages/Queue/components/MetricsTable/index.jsx rename to client/src/Pages/Logs/Queue/components/MetricsTable/index.jsx index 818b4e543..204b90035 100644 --- a/client/src/Pages/Queue/components/MetricsTable/index.jsx +++ b/client/src/Pages/Logs/Queue/components/MetricsTable/index.jsx @@ -1,6 +1,6 @@ import Stack from "@mui/material/Stack"; import Typography from "@mui/material/Typography"; -import DataTable from "../../../../Components/Table"; +import DataTable from "../../../../../Components/Table"; // Utils import { useTranslation } from "react-i18next"; diff --git a/client/src/Pages/Queue/index.jsx b/client/src/Pages/Logs/Queue/index.jsx similarity index 82% rename from client/src/Pages/Queue/index.jsx rename to client/src/Pages/Logs/Queue/index.jsx index eb732560c..729f87fe3 100644 --- a/client/src/Pages/Queue/index.jsx +++ b/client/src/Pages/Logs/Queue/index.jsx @@ -1,15 +1,14 @@ // Components import Stack from "@mui/material/Stack"; -import Breadcrumbs from "../../Components/Breadcrumbs"; import JobTable from "./components/JobTable"; -import MetricsTable from "./components/MetricsTable"; +import Metrics from "./components/Metrics"; import FailedJobTable from "./components/FailedJobTable"; import ButtonGroup from "@mui/material/ButtonGroup"; import Button from "@mui/material/Button"; // Utils import { useState } from "react"; -import { useFetchQueueData, useFlushQueue } from "../../Hooks/queueHooks"; +import { useFetchQueueData, useFlushQueue } from "../../../Hooks/queueHooks"; import { useTranslation } from "react-i18next"; import { useTheme } from "@emotion/react"; @@ -23,15 +22,13 @@ const QueueDetails = () => { const [jobs, metrics, isLoading, error] = useFetchQueueData(trigger); const [flushQueue, isFlushing, flushError] = useFlushQueue(); - const BREADCRUMBS = [{ name: t("queuePage.title"), path: "/queue" }]; if (isLoading) return
Loading...
; if (error || flushError) return
Error: {error.message}
; return ( - + - { + const { t } = useTranslation(); + const theme = useTheme(); + + // Local state + const [value, setValue] = useState(0); + + // Handlers + const handleChange = (event, newValue) => { + setValue(newValue); + }; + + const BREADCRUMBS = [{ name: t("logsPage.title"), path: "/logs" }]; + return ( + + + + + + + {value === 0 && } + {value === 1 &&
Not yet
} +
+ ); +}; + +export default Logs; diff --git a/client/src/Pages/Settings/SettingsDev.jsx b/client/src/Pages/Settings/SettingsDev.jsx deleted file mode 100644 index 721a17d5c..000000000 --- a/client/src/Pages/Settings/SettingsDev.jsx +++ /dev/null @@ -1,37 +0,0 @@ -import Box from "@mui/material/Box"; -import Typography from "@mui/material/Typography"; -import ConfigBox from "../../Components/ConfigBox"; -// Utils -import { useTranslation } from "react-i18next"; -import { useNavigate } from "react-router-dom"; -import Link from "../../Components/Link"; - -const SettingsDev = ({ isAdmin, HEADER_SX }) => { - const { t } = useTranslation(); - - if (!isAdmin) return null; - - return ( - - - - {t("settingsDev")} - - {t("settingsDevDescription")} - - - - - - ); -}; - -export default SettingsDev; diff --git a/client/src/Pages/Settings/index.jsx b/client/src/Pages/Settings/index.jsx index ef57a16c7..0cd954e52 100644 --- a/client/src/Pages/Settings/index.jsx +++ b/client/src/Pages/Settings/index.jsx @@ -8,7 +8,6 @@ import SettingsPagespeed from "./SettingsPagespeed"; import SettingsDemoMonitors from "./SettingsDemoMonitors"; import SettingsAbout from "./SettingsAbout"; import SettingsEmail from "./SettingsEmail"; -import SettingsDev from "./SettingsDev"; import Button from "@mui/material/Button"; // Utils import { settingsValidation } from "../../Validation/validation"; @@ -209,10 +208,7 @@ const Settings = () => { emailPasswordHasBeenReset={emailPasswordHasBeenReset} setEmailPasswordHasBeenReset={setEmailPasswordHasBeenReset} /> - + { const AdminCheckedRegister = withAdminCheck(AuthRegister); @@ -187,9 +187,10 @@ const Routes = () => { path="account/team" element={} /> + } + path="logs" + element={} /> diff --git a/client/src/Utils/Theme/globalTheme.js b/client/src/Utils/Theme/globalTheme.js index 58d9943be..ae014432d 100644 --- a/client/src/Utils/Theme/globalTheme.js +++ b/client/src/Utils/Theme/globalTheme.js @@ -407,6 +407,7 @@ const baseTheme = (palette) => ({ }), }, }, + MuiTab: { styleOverrides: { root: ({ theme }) => ({ @@ -475,6 +476,8 @@ const baseTheme = (palette) => ({ MuiTabs: { styleOverrides: { root: ({ theme }) => ({ + height: "34px", + minHeight: "34px", display: "inline-flex", borderRadius: 0, "& .MuiTabs-indicator": { diff --git a/client/src/assets/icons/logs.svg b/client/src/assets/icons/logs.svg new file mode 100644 index 000000000..e1adcb390 --- /dev/null +++ b/client/src/assets/icons/logs.svg @@ -0,0 +1,5 @@ + + + \ No newline at end of file diff --git a/client/src/locales/en.json b/client/src/locales/en.json index 14317e689..0856592fc 100644 --- a/client/src/locales/en.json +++ b/client/src/locales/en.json @@ -30,9 +30,6 @@ "settingsRemoveAllMonitorsDialogTitle": "Do you want to remove all monitors?", "settingsRemoveAllMonitorsDialogConfirm": "Yes, remove all monitors", "settingsAbout": "About", - "settingsDev": "Developer", - "settingsDevDescription": "Developer settings", - "settingsDevViewJobQueueDetails": "View job queue details", "settingsDevelopedBy": "Developed by Bluewave Labs.", "settingsSave": "Save", "settingsSuccessSaved": "Settings saved successfully", @@ -431,6 +428,7 @@ "statusPages": "Status pages", "maintenance": "Maintenance", "integrations": "Integrations", + "logs": "Logs", "settings": "Settings", "support": "Support", "discussions": "Discussions", @@ -756,6 +754,13 @@ "settingsEmailPool": "Enable connection pooling: Reuse existing connections to improve performance", "sendTestNotifications": "Send test notifications", "selectAll": "Select all", + "logsPage": { + "title": "Logs", + "tabs": { + "queue": "Job queue", + "logs": "Logs" + } + }, "queuePage": { "title": "Queue", "refreshButton": "Refresh", From 0b6febbb820c76505e4a188574f93434234a1d01 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 23 Jun 2025 11:25:42 +0800 Subject: [PATCH 02/11] add log cache, routes, and controller --- server/controllers/logController.js | 23 ++++++++++++ server/index.js | 7 ++++ server/routes/logRoutes.js | 18 ++++++++++ server/utils/logger.js | 55 +++++++++++++++++++++++------ 4 files changed, 93 insertions(+), 10 deletions(-) create mode 100644 server/controllers/logController.js create mode 100755 server/routes/logRoutes.js diff --git a/server/controllers/logController.js b/server/controllers/logController.js new file mode 100644 index 000000000..00cf7bbcb --- /dev/null +++ b/server/controllers/logController.js @@ -0,0 +1,23 @@ +import { handleError } from "./controllerUtils.js"; + +const SERVICE_NAME = "JobQueueController"; + +class LogController { + constructor(logger) { + this.logger = logger; + } + + getLogs = async (req, res, next) => { + try { + const logs = await this.logger.getLogs(); + res.success({ + msg: "Logs fetched successfully", + data: logs, + }); + } catch (error) { + next(handleError(error, SERVICE_NAME, "getMetrics")); + return; + } + }; +} +export default LogController; diff --git a/server/index.js b/server/index.js index 99be6de7a..4b74ef46c 100755 --- a/server/index.js +++ b/server/index.js @@ -36,6 +36,9 @@ import StatusPageController from "./controllers/statusPageController.js"; import QueueRoutes from "./routes/queueRoute.js"; import QueueController from "./controllers/queueController.js"; +import LogRoutes from "./routes/logRoutes.js"; +import LogController from "./controllers/logController.js"; + import NotificationRoutes from "./routes/notificationRoute.js"; import NotificationController from "./controllers/notificationController.js"; @@ -294,6 +297,8 @@ const startApp = async () => { ServiceRegistry.get(StringService.SERVICE_NAME) ); + const logController = new LogController(logger); + const statusPageController = new StatusPageController( ServiceRegistry.get(MongoDB.SERVICE_NAME), ServiceRegistry.get(StringService.SERVICE_NAME) @@ -320,6 +325,7 @@ const startApp = async () => { maintenanceWindowController ); const queueRoutes = new QueueRoutes(queueController); + const logRoutes = new LogRoutes(logController); const statusPageRoutes = new StatusPageRoutes(statusPageController); const notificationRoutes = new NotificationRoutes(notificationController); @@ -372,6 +378,7 @@ const startApp = async () => { app.use("/api/v1/checks", verifyJWT, checkRoutes.getRouter()); app.use("/api/v1/maintenance-window", verifyJWT, maintenanceWindowRoutes.getRouter()); app.use("/api/v1/queue", verifyJWT, queueRoutes.getRouter()); + app.use("/api/v1/logs", verifyJWT, logRoutes.getRouter()); app.use("/api/v1/status-page", statusPageRoutes.getRouter()); app.use("/api/v1/notifications", verifyJWT, notificationRoutes.getRouter()); app.use("/api/v1/diagnostic", verifyJWT, diagnosticRoutes.getRouter()); diff --git a/server/routes/logRoutes.js b/server/routes/logRoutes.js new file mode 100755 index 000000000..867826dde --- /dev/null +++ b/server/routes/logRoutes.js @@ -0,0 +1,18 @@ +import { Router } from "express"; +import { isAllowed } from "../middleware/isAllowed.js"; +class LogRoutes { + constructor(logController) { + this.router = Router(); + this.logController = logController; + this.initRoutes(); + } + initRoutes() { + this.router.get("/", isAllowed(["admin", "superadmin"]), this.logController.getLogs); + } + + getRouter() { + return this.router; + } +} + +export default LogRoutes; diff --git a/server/utils/logger.js b/server/utils/logger.js index 155adc957..f19694987 100755 --- a/server/utils/logger.js +++ b/server/utils/logger.js @@ -4,6 +4,8 @@ dotenv.config(); class Logger { constructor() { + this.logCache = []; + this.maxCacheSize = 500; const consoleFormat = format.printf( ({ level, message, service, method, details, timestamp, stack }) => { if (message instanceof Object) { @@ -72,11 +74,17 @@ class Logger { * @param {Object} config.details - Additional details. */ info(config) { - this.logger.info(config.message, { + const logEntry = { + level: "info", + message: config.message, service: config.service, method: config.method, details: config.details, - }); + timestamp: new Date().toISOString(), + }; + + this.cacheLog(logEntry); + this.logger.info(config.message, logEntry); } /** @@ -88,11 +96,17 @@ class Logger { * @param {Object} config.details - Additional details. */ warn(config) { - this.logger.warn(config.message, { + const logEntry = { + level: "warn", + message: config.message, service: config.service, method: config.method, details: config.details, - }); + timestamp: new Date().toISOString(), + }; + + this.cacheLog(logEntry); + this.logger.warn(config.message, logEntry); } /** @@ -104,12 +118,17 @@ class Logger { * @param {Object} config.details - Additional details. */ error(config) { - this.logger.error(config.message, { + const logEntry = { + level: "error", + message: config.message, service: config.service, method: config.method, details: config.details, - stack: config.stack, - }); + timestamp: new Date().toISOString(), + }; + + this.cacheLog(logEntry); + this.logger.error(config.message, logEntry); } /** * Logs a debug message. @@ -120,12 +139,28 @@ class Logger { * @param {Object} config.details - Additional details. */ debug(config) { - this.logger.debug(config.message, { + const logEntry = { + level: "debug", + message: config.message, service: config.service, method: config.method, details: config.details, - stack: config.stack, - }); + timestamp: new Date().toISOString(), + }; + + this.cacheLog(logEntry); + this.logger.debug(config.message, logEntry); + } + + cacheLog(entry) { + this.logCache.push(entry); + if (this.logCache.length > this.maxCacheSize) { + this.logCache.shift(); + } + } + + getLogs() { + return this.logCache; } } From 365ae081237cc4c7aca94124c3029fdf0db712c8 Mon Sep 17 00:00:00 2001 From: Alex Holliday Date: Mon, 23 Jun 2025 12:09:30 +0800 Subject: [PATCH 03/11] FE log component implementation --- client/package-lock.json | 399 +++++++++++------- client/package.json | 2 +- client/src/Hooks/logHooks.js | 35 ++ client/src/Pages/Logs/Logs/index.jsx | 93 ++++ .../Logs/Queue/components/Metrics/index.jsx | 2 - client/src/Pages/Logs/index.jsx | 5 +- client/src/Utils/NetworkService.js | 8 + client/src/assets/icons/logs.svg | 2 +- client/src/locales/en.json | 15 +- 9 files changed, 401 insertions(+), 160 deletions(-) create mode 100644 client/src/Hooks/logHooks.js create mode 100644 client/src/Pages/Logs/Logs/index.jsx diff --git a/client/package-lock.json b/client/package-lock.json index 4050adfbb..f58f56f44 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -45,7 +45,7 @@ "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.6", "prettier": "^3.3.3", - "vite": "^5.4.19" + "vite": "6.3.5" }, "optionalDependencies": { "@rollup/rollup-linux-arm64-musl": "4.41.0" @@ -492,9 +492,9 @@ "license": "MIT" }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", "cpu": [ "ppc64" ], @@ -504,13 +504,13 @@ "aix" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", "cpu": [ "arm" ], @@ -520,13 +520,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", "cpu": [ "arm64" ], @@ -536,13 +536,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", "cpu": [ "x64" ], @@ -552,13 +552,13 @@ "android" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", "cpu": [ "arm64" ], @@ -568,13 +568,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", "cpu": [ "x64" ], @@ -584,13 +584,13 @@ "darwin" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", "cpu": [ "arm64" ], @@ -600,13 +600,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", "cpu": [ "x64" ], @@ -616,13 +616,13 @@ "freebsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", "cpu": [ "arm" ], @@ -632,13 +632,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", "cpu": [ "arm64" ], @@ -648,13 +648,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", "cpu": [ "ia32" ], @@ -664,13 +664,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", "cpu": [ "loong64" ], @@ -680,13 +680,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", "cpu": [ "mips64el" ], @@ -696,13 +696,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", "cpu": [ "ppc64" ], @@ -712,13 +712,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", "cpu": [ "riscv64" ], @@ -728,13 +728,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", "cpu": [ "s390x" ], @@ -744,13 +744,13 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", "cpu": [ "x64" ], @@ -760,13 +760,29 @@ "linux" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", "cpu": [ "x64" ], @@ -776,13 +792,29 @@ "netbsd" ], "engines": { - "node": ">=12" + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", "cpu": [ "x64" ], @@ -792,13 +824,13 @@ "openbsd" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", "cpu": [ "x64" ], @@ -808,13 +840,13 @@ "sunos" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", "cpu": [ "arm64" ], @@ -824,13 +856,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", "cpu": [ "ia32" ], @@ -840,13 +872,13 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", "cpu": [ "x64" ], @@ -856,7 +888,7 @@ "win32" ], "engines": { - "node": ">=12" + "node": ">=18" } }, "node_modules/@eslint-community/eslint-utils": { @@ -3040,9 +3072,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -3172,23 +3204,6 @@ ], "license": "CC-BY-4.0" }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, "node_modules/clsx": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", @@ -3259,6 +3274,15 @@ "node": ">=10" } }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -3820,41 +3844,43 @@ } }, "node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", "hasInstallScript": true, "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { - "node": ">=12" + "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" } }, "node_modules/escalade": { @@ -4052,6 +4078,23 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/eslint/node_modules/globals": { "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", @@ -4184,6 +4227,20 @@ "reusify": "^1.0.4" } }, + "node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -6713,6 +6770,22 @@ "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==", "license": "MIT" }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -6923,20 +6996,23 @@ } }, "node_modules/vite": { - "version": "5.4.19", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", - "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -6945,19 +7021,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -6978,6 +7060,12 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, @@ -7133,12 +7221,17 @@ "license": "ISC" }, "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, "engines": { - "node": ">= 6" + "node": ">= 14.6" } }, "node_modules/yocto-queue": { diff --git a/client/package.json b/client/package.json index 83dfe8407..611ba5093 100644 --- a/client/package.json +++ b/client/package.json @@ -58,7 +58,7 @@ "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.6", "prettier": "^3.3.3", - "vite": "^5.4.19" + "vite": "6.3.5" }, "optionalDependencies": { "@rollup/rollup-linux-arm64-musl": "4.41.0" diff --git a/client/src/Hooks/logHooks.js b/client/src/Hooks/logHooks.js new file mode 100644 index 000000000..000e4d0f0 --- /dev/null +++ b/client/src/Hooks/logHooks.js @@ -0,0 +1,35 @@ +import { useState, useEffect } from "react"; +import { networkService } from "../main"; +import { createToast } from "../Utils/toastUtils"; +import { useTranslation } from "react-i18next"; + +const useFetchLogs = () => { + const { t } = useTranslation(); + const [logs, setLogs] = useState(undefined); + const [isLoading, setIsLoading] = useState(false); + const [error, setError] = useState(undefined); + + useEffect(() => { + const fetchLogs = async () => { + try { + setIsLoading(true); + const response = await networkService.getLogs(); + setLogs(response.data.data); + createToast({ + body: t("logsPage.toast.fetchLogsSuccess"), + }); + } catch (error) { + setError(error); + createToast({ + message: error.message, + }); + } finally { + setIsLoading(false); + } + }; + fetchLogs(); + }, [t]); + return [logs, isLoading, error]; +}; + +export { useFetchLogs }; diff --git a/client/src/Pages/Logs/Logs/index.jsx b/client/src/Pages/Logs/Logs/index.jsx new file mode 100644 index 000000000..d5b0a8469 --- /dev/null +++ b/client/src/Pages/Logs/Logs/index.jsx @@ -0,0 +1,93 @@ +import Stack from "@mui/material/Stack"; +import Box from "@mui/material/Box"; +import Select from "../../../Components/Inputs/Select"; +import Typography from "@mui/material/Typography"; + +import { useFetchLogs } from "../../../Hooks/logHooks"; +import { useTheme } from "@emotion/react"; +import { useState } from "react"; +import { useTranslation } from "react-i18next"; + +const formatLog = (theme, log, idx) => { + const levelColors = { + info: theme.palette.success.main, + warn: theme.palette.warning.main, + error: theme.palette.error.main, + debug: theme.palette.accent.main, + }; + + const color = levelColors[log.level] || theme.palette.primary.contrastText; + + return ( + + [{log.timestamp}]{" "} + {log.level.toUpperCase()} + {": "} + {`(${log.service})`} + {`(${log.method})`} + {": "} + {log.message} +
+
+ ); +}; + +const Logs = () => { + // Local state + const [logLevel, setLogLevel] = useState("all"); + + // Hooks + const theme = useTheme(); + const { t } = useTranslation(); + const [logs, isLoading, error] = useFetchLogs(); + // Setup + const LOG_LEVELS = [ + { _id: "all", name: t("logsPage.logLevelSelect.values.all") }, + { _id: "info", name: t("logsPage.logLevelSelect.values.info") }, + { _id: "warn", name: t("logsPage.logLevelSelect.values.warn") }, + { _id: "error", name: t("logsPage.logLevelSelect.values.error") }, + { _id: "debug", name: t("logsPage.logLevelSelect.values.debug") }, + ]; + return ( + + + {t("logsPage.logLevelSelect.title")} +