diff --git a/web/src/components/Statusbar.tsx b/web/src/components/Statusbar.tsx index 88d00d3b7..1ea609d74 100644 --- a/web/src/components/Statusbar.tsx +++ b/web/src/components/Statusbar.tsx @@ -9,6 +9,7 @@ import { useContext, useEffect, useMemo } from "react"; import { FaCheck } from "react-icons/fa"; import { IoIosWarning } from "react-icons/io"; import { MdCircle } from "react-icons/md"; +import { Link } from "react-router-dom"; import useSWR from "swr"; export default function Statusbar() { @@ -43,7 +44,13 @@ export default function Statusbar() { useEffect(() => { clearMessages("stats"); potentialProblems.forEach((problem) => { - addMessage("stats", problem.text, problem.color); + addMessage( + "stats", + problem.text, + problem.color, + undefined, + problem.relevantLink, + ); }); }, [potentialProblems, addMessage, clearMessages]); @@ -110,14 +117,25 @@ export default function Statusbar() { ) : ( Object.entries(messages).map(([key, messageArray]) => (
- {messageArray.map(({ id, text, color }: StatusMessage) => ( -
- - {text} -
- ))} + {messageArray.map(({ id, text, color, link }: StatusMessage) => { + const message = ( +
+ + {text} +
+ ); + + if (link) { + return {message}; + } else { + return message; + } + })}
)) )} diff --git a/web/src/components/menu/GeneralSettings.tsx b/web/src/components/menu/GeneralSettings.tsx index aed5f2173..637a13193 100644 --- a/web/src/components/menu/GeneralSettings.tsx +++ b/web/src/components/menu/GeneralSettings.tsx @@ -139,7 +139,7 @@ export default function GeneralSettings({ className }: GeneralSettings) { System - + { clearMessages("stats"); potentialProblems.forEach((problem) => { - addMessage("stats", problem.text, problem.color); + addMessage( + "stats", + problem.text, + problem.color, + undefined, + problem.relevantLink, + ); }); }, [potentialProblems, addMessage, clearMessages]); @@ -68,14 +75,22 @@ function StatusAlertNav() {
{Object.entries(messages).map(([key, messageArray]) => (
- {messageArray.map(({ id, text, color }: StatusMessage) => ( -
- - {text} -
- ))} + {messageArray.map(({ id, text, color, link }: StatusMessage) => { + const message = ( +
+ + {text} +
+ ); + + if (link) { + return {message}; + } else { + return message; + } + })}
))}
diff --git a/web/src/context/statusbar-provider.tsx b/web/src/context/statusbar-provider.tsx index 6d17fa4de..60954f7be 100644 --- a/web/src/context/statusbar-provider.tsx +++ b/web/src/context/statusbar-provider.tsx @@ -10,6 +10,7 @@ export type StatusMessage = { id: string; text: string; color?: string; + link?: string; }; export type StatusMessagesState = { @@ -27,6 +28,7 @@ type StatusBarMessagesContextValue = { message: string, color?: string, messageId?: string, + link?: string, ) => string; removeMessage: (key: string, messageId: string) => void; clearMessages: (key: string) => void; @@ -43,14 +45,20 @@ export function StatusBarMessagesProvider({ const messages = useMemo(() => messagesState, [messagesState]); const addMessage = useCallback( - (key: string, message: string, color?: string, messageId?: string) => { + ( + key: string, + message: string, + color?: string, + messageId?: string, + link?: string, + ) => { const id = messageId || Date.now().toString(); const msgColor = color || "text-danger"; setMessagesState((prevMessages) => ({ ...prevMessages, [key]: [ ...(prevMessages[key] || []), - { id, text: message, color: msgColor }, + { id, text: message, color: msgColor, link }, ], })); return id; diff --git a/web/src/hooks/use-stats.ts b/web/src/hooks/use-stats.ts index 1cb30dbb7..bafc9e538 100644 --- a/web/src/hooks/use-stats.ts +++ b/web/src/hooks/use-stats.ts @@ -34,11 +34,13 @@ export default function useStats(stats: FrigateStats | undefined) { problems.push({ text: `${capitalizeFirstLetter(key)} is very slow (${det["inference_speed"]} ms)`, color: "text-danger", + relevantLink: "/system#general", }); } else if (det["inference_speed"] > InferenceThreshold.warning) { problems.push({ text: `${capitalizeFirstLetter(key)} is slow (${det["inference_speed"]} ms)`, color: "text-orange-400", + relevantLink: "/system#general", }); } }); @@ -53,6 +55,7 @@ export default function useStats(stats: FrigateStats | undefined) { problems.push({ text: `${capitalizeFirstLetter(name.replaceAll("_", " "))} is offline`, color: "text-danger", + relevantLink: "logs", }); } }); @@ -70,6 +73,7 @@ export default function useStats(stats: FrigateStats | undefined) { problems.push({ text: `${capitalizeFirstLetter(name.replaceAll("_", " "))} has high FFMPEG CPU usage (${ffmpegAvg}%)`, color: "text-danger", + relevantLink: "/system#cameras", }); } @@ -77,6 +81,7 @@ export default function useStats(stats: FrigateStats | undefined) { problems.push({ text: `${capitalizeFirstLetter(name.replaceAll("_", " "))} has high detect CPU usage (${detectAvg}%)`, color: "text-danger", + relevantLink: "/system#cameras", }); } }); diff --git a/web/src/pages/System.tsx b/web/src/pages/System.tsx index 5d296f053..8d30c82ed 100644 --- a/web/src/pages/System.tsx +++ b/web/src/pages/System.tsx @@ -11,6 +11,8 @@ import { FaVideo } from "react-icons/fa"; import Logo from "@/components/Logo"; import useOptimisticState from "@/hooks/use-optimistic-state"; import CameraMetrics from "@/views/system/CameraMetrics"; +import { useHashState } from "@/hooks/use-overlay-state"; +import { capitalizeFirstLetter } from "@/utils/stringUtil"; const metrics = ["general", "storage", "cameras"] as const; type SystemMetric = (typeof metrics)[number]; @@ -18,12 +20,18 @@ type SystemMetric = (typeof metrics)[number]; function System() { // stats page - const [page, setPage] = useState("general"); - const [pageToggle, setPageToggle] = useOptimisticState(page, setPage, 100); + const [page, setPage] = useHashState(); + const [pageToggle, setPageToggle] = useOptimisticState( + page ?? "general", + setPage, + 100, + ); const [lastUpdated, setLastUpdated] = useState(Date.now() / 1000); useEffect(() => { - document.title = `${pageToggle[0].toUpperCase()}${pageToggle.substring(1)} Stats - Frigate`; + if (pageToggle) { + document.title = `${capitalizeFirstLetter(pageToggle)} Stats - Frigate`; + } }, [pageToggle]); // stats collection diff --git a/web/src/types/stats.ts b/web/src/types/stats.ts index 59fb6f69d..2cf277f3d 100644 --- a/web/src/types/stats.ts +++ b/web/src/types/stats.ts @@ -62,6 +62,7 @@ export type StorageStats = { export type PotentialProblem = { text: string; color: string; + relevantLink?: string; }; export type Vainfo = {