diff --git a/frontend/package-lock.json b/frontend/package-lock.json index fe32663..4e778ef 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -58,18 +58,18 @@ } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "version": "7.29.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.6.tgz", + "integrity": "sha512-QdxmAo/ikZqqRGA8s43ww8lcql6naWRvEz0FFrl6MIlc7Gi6TroXnSdWa5U/kq6fzcpqpHesicQxFZIieZbyIA==", "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", + "@babel/generator": "^7.29.6", "@babel/helper-compilation-targets": "^7.28.6", "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", + "@babel/helpers": "^7.29.2", + "@babel/parser": "^7.29.3", "@babel/template": "^7.28.6", "@babel/traverse": "^7.29.0", "@babel/types": "^7.29.0", @@ -89,14 +89,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -322,9 +322,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -332,9 +332,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -381,13 +381,13 @@ } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -1561,14 +1561,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -2048,9 +2048,6 @@ "cpu": [ "arm64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2067,9 +2064,6 @@ "cpu": [ "arm64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ @@ -2086,9 +2080,6 @@ "cpu": [ "ppc64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2105,9 +2096,6 @@ "cpu": [ "s390x" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2124,9 +2112,6 @@ "cpu": [ "x64" ], - "libc": [ - "glibc" - ], "license": "MIT", "optional": true, "os": [ @@ -2143,9 +2128,6 @@ "cpu": [ "x64" ], - "libc": [ - "musl" - ], "license": "MIT", "optional": true, "os": [ diff --git a/frontend/package.json b/frontend/package.json index 449b45a..da85993 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -32,5 +32,8 @@ "globals": "^17.6.0", "vite": "^8.1.3", "vite-plugin-pwa": "^1.3.0" + }, + "overrides": { + "@babel/core": "7.29.6" } } diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index 265fb53..4a062dd 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -7,7 +7,8 @@ import { STALE_WARNING_MS, STALE_CRITICAL_MS, } from "./lib/constants"; -import { ViewProvider, useView } from "./contexts/ViewContext"; +import { ViewProvider } from "./contexts/ViewContext"; +import { useView } from "./contexts/use-view"; import StatusBanner from "./components/StatusBanner"; import IncidentSection from "./components/IncidentSection"; import MaintenanceBanner from "./components/MaintenanceBanner"; diff --git a/frontend/src/components/MaintenanceBanner.jsx b/frontend/src/components/MaintenanceBanner.jsx index 4a802eb..72aaaab 100644 --- a/frontend/src/components/MaintenanceBanner.jsx +++ b/frontend/src/components/MaintenanceBanner.jsx @@ -8,7 +8,6 @@ export default function MaintenanceBanner({ data }) { const maintenances = data.upcoming_maintenances; const visible = expanded ? maintenances : maintenances.slice(0, 3); - const remaining = maintenances.length - 3; return (
diff --git a/frontend/src/components/StatusBanner.jsx b/frontend/src/components/StatusBanner.jsx index a979c0c..7441415 100644 --- a/frontend/src/components/StatusBanner.jsx +++ b/frontend/src/components/StatusBanner.jsx @@ -10,7 +10,7 @@ export default function StatusBanner({ data, loading }) { ); } - const { overall_status, active_incidents, total_services = 0, healthy_count, unknown_count = 0 } = data; + const { overall_status, active_incidents, total_services = 0, unknown_count = 0 } = data; const hasIncidents = active_incidents && active_incidents.length > 0; const monitored = total_services - unknown_count; const manual = unknown_count; diff --git a/frontend/src/components/ViewToggle.jsx b/frontend/src/components/ViewToggle.jsx index 8635d1c..d0c8ba0 100644 --- a/frontend/src/components/ViewToggle.jsx +++ b/frontend/src/components/ViewToggle.jsx @@ -1,4 +1,4 @@ -import { useView } from "../contexts/ViewContext"; +import { useView } from "../contexts/use-view"; const VIEWS = [ { id: "engineer", label: "Engineer" }, diff --git a/frontend/src/contexts/ViewContext.jsx b/frontend/src/contexts/ViewContext.jsx index 56c0bd9..8b73182 100644 --- a/frontend/src/contexts/ViewContext.jsx +++ b/frontend/src/contexts/ViewContext.jsx @@ -1,6 +1,6 @@ -import { createContext, useContext, useState, useEffect } from "react"; +import { useState, useEffect } from "react"; +import { ViewContext } from "./view-context"; -const ViewContext = createContext(); const STORAGE_KEY = "pulse-view-mode"; export function ViewProvider({ children }) { @@ -26,9 +26,3 @@ export function ViewProvider({ children }) { ); } - -export function useView() { - const ctx = useContext(ViewContext); - if (!ctx) throw new Error("useView must be used inside ViewProvider"); - return ctx; -} diff --git a/frontend/src/contexts/use-view.js b/frontend/src/contexts/use-view.js new file mode 100644 index 0000000..e47cd2a --- /dev/null +++ b/frontend/src/contexts/use-view.js @@ -0,0 +1,8 @@ +import { useContext } from "react"; +import { ViewContext } from "./view-context"; + +export function useView() { + const ctx = useContext(ViewContext); + if (!ctx) throw new Error("useView must be used inside ViewProvider"); + return ctx; +} diff --git a/frontend/src/contexts/view-context.js b/frontend/src/contexts/view-context.js new file mode 100644 index 0000000..f9cca83 --- /dev/null +++ b/frontend/src/contexts/view-context.js @@ -0,0 +1,3 @@ +import { createContext } from "react"; + +export const ViewContext = createContext(); diff --git a/frontend/src/hooks/use-polling.js b/frontend/src/hooks/use-polling.js index c319b54..9900870 100644 --- a/frontend/src/hooks/use-polling.js +++ b/frontend/src/hooks/use-polling.js @@ -9,15 +9,17 @@ export function usePolling(url, intervalMs = 30000) { const lastJsonRef = useRef(null); const urlRef = useRef(url); - // Reset on URL change - if (url !== urlRef.current) { - urlRef.current = url; - lastJsonRef.current = null; - } + useEffect(() => { + if (url !== urlRef.current) { + urlRef.current = url; + lastJsonRef.current = null; + } + }, [url]); const fetchData = useCallback( async (signal) => { if (!url) return; + setLoading((current) => (lastJsonRef.current === null ? true : current)); try { const result = await get(url, signal); const json = JSON.stringify(result); @@ -43,11 +45,14 @@ export function usePolling(url, intervalMs = 30000) { useEffect(() => { const controller = new AbortController(); - setLoading(data === null); - fetchData(controller.signal); + const runFetch = () => { + Promise.resolve().then(() => fetchData(controller.signal)); + }; + + runFetch(); const interval = setInterval(() => { - fetchData(controller.signal); + runFetch(); }, intervalMs); return () => {