diff --git a/src/features/dashboard/components/DashboardGrid.tsx b/src/features/dashboard/components/DashboardGrid.tsx
index 1d75e5b..1ac2c99 100644
--- a/src/features/dashboard/components/DashboardGrid.tsx
+++ b/src/features/dashboard/components/DashboardGrid.tsx
@@ -1,8 +1,8 @@
import type { SystemHealthStatus } from "../../../types/types";
import { useGetSystemHealth } from "../hooks/useGetSystemHealth";
-import CameraStatus from "./CameraStatus";
-import SystemOverview from "./SystemOverview";
-import SystemStatusCard from "./SystemStatusCard";
+import CameraStatus from "./cameraStatus/CameraStatus";
+import SystemHealthCard from "./systemHealth/SystemHealthCard";
+import SystemStatusCard from "./systemStatus/SystemStatusCard";
const DashboardGrid = () => {
const { query } = useGetSystemHealth();
@@ -37,7 +37,7 @@ const DashboardGrid = () => {
return (
-
void;
};
-const SystemOverview = ({
+const SystemHealthCard = ({
startTime,
uptime,
statuses,
@@ -39,4 +39,4 @@ const SystemOverview = ({
);
};
-export default SystemOverview;
+export default SystemHealthCard;
diff --git a/src/features/dashboard/components/systemHealthModal/SystemHealthModal.tsx b/src/features/dashboard/components/systemHealth/systemHealthModal/SystemHealthModal.tsx
similarity index 81%
rename from src/features/dashboard/components/systemHealthModal/SystemHealthModal.tsx
rename to src/features/dashboard/components/systemHealth/systemHealthModal/SystemHealthModal.tsx
index fb43cb2..eeebe0d 100644
--- a/src/features/dashboard/components/systemHealthModal/SystemHealthModal.tsx
+++ b/src/features/dashboard/components/systemHealth/systemHealthModal/SystemHealthModal.tsx
@@ -1,8 +1,8 @@
-import type { SystemHealthStatus } from "../../../../types/types";
-import Badge from "../../../../ui/Badge";
-import ModalComponent from "../../../../ui/ModalComponent";
-import StatusIndicators from "../../../../ui/StatusIndicators";
-import { capitalize } from "../../../../utils/utils";
+import type { SystemHealthStatus } from "../../../../../types/types";
+import Badge from "../../../../../ui/Badge";
+import ModalComponent from "../../../../../ui/ModalComponent";
+import StatusIndicators from "../../../../../ui/StatusIndicators";
+import { capitalize } from "../../../../../utils/utils";
type SystemHealthModalProps = {
isSystemHealthModalOpen: boolean;
diff --git a/src/features/dashboard/components/systemStatus/StatusItems/DownloadLogButton.tsx b/src/features/dashboard/components/systemStatus/StatusItems/DownloadLogButton.tsx
new file mode 100644
index 0000000..33e51be
--- /dev/null
+++ b/src/features/dashboard/components/systemStatus/StatusItems/DownloadLogButton.tsx
@@ -0,0 +1,50 @@
+import { faDownload } from "@fortawesome/free-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { useDownloadLogFiles } from "../../../hooks/useDownloadLogFiles";
+import { toast } from "sonner";
+
+const DownloadLogButton = () => {
+ const { downloadLogFilesQuery } = useDownloadLogFiles();
+ const isLoading = downloadLogFilesQuery?.isFetching;
+
+ const handleDownloadClick = async () => {
+ try {
+ const blob = await downloadLogFilesQuery?.refetch().then((res) => res.data);
+ if (!blob) {
+ throw new Error("No log file data received");
+ }
+ const url = window.URL.createObjectURL(new Blob([blob]));
+ const link = document.createElement("a");
+ if (!link) {
+ throw new Error("Failed to create download link");
+ } else {
+ link.href = url;
+ link.setAttribute("download", "FlexiAI-0.log");
+ document.body.appendChild(link);
+ link.click();
+ link.parentNode?.removeChild(link);
+ window.URL.revokeObjectURL(url);
+ }
+ } catch (error: unknown) {
+ const errorMessage = error instanceof Error ? error.message : "Unknown error occurred";
+ toast.error(errorMessage);
+ }
+ };
+
+ return (
+
+ );
+};
+
+export default DownloadLogButton;
diff --git a/src/features/dashboard/components/StatusItems/StatusItemCPU.tsx b/src/features/dashboard/components/systemStatus/StatusItems/StatusItemCPU.tsx
similarity index 100%
rename from src/features/dashboard/components/StatusItems/StatusItemCPU.tsx
rename to src/features/dashboard/components/systemStatus/StatusItems/StatusItemCPU.tsx
diff --git a/src/features/dashboard/components/StatusItems/StatusItemLocal.tsx b/src/features/dashboard/components/systemStatus/StatusItems/StatusItemLocal.tsx
similarity index 100%
rename from src/features/dashboard/components/StatusItems/StatusItemLocal.tsx
rename to src/features/dashboard/components/systemStatus/StatusItems/StatusItemLocal.tsx
diff --git a/src/features/dashboard/components/StatusItems/StatusItemThreads.tsx b/src/features/dashboard/components/systemStatus/StatusItems/StatusItemThreads.tsx
similarity index 100%
rename from src/features/dashboard/components/StatusItems/StatusItemThreads.tsx
rename to src/features/dashboard/components/systemStatus/StatusItems/StatusItemThreads.tsx
diff --git a/src/features/dashboard/components/StatusItems/StatusItemUTC.tsx b/src/features/dashboard/components/systemStatus/StatusItems/StatusItemUTC.tsx
similarity index 100%
rename from src/features/dashboard/components/StatusItems/StatusItemUTC.tsx
rename to src/features/dashboard/components/systemStatus/StatusItems/StatusItemUTC.tsx
diff --git a/src/features/dashboard/components/systemStatus/StatusItems/StatusReads.tsx b/src/features/dashboard/components/systemStatus/StatusItems/StatusReads.tsx
new file mode 100644
index 0000000..287c18c
--- /dev/null
+++ b/src/features/dashboard/components/systemStatus/StatusItems/StatusReads.tsx
@@ -0,0 +1,48 @@
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faChartSimple } from "@fortawesome/free-solid-svg-icons";
+
+type StatusReadsProps = {
+ reads: {
+ totalPending: number;
+ totalActive: number;
+ totalSent: number;
+ totalReceived: number;
+ totalLost: number;
+ sanityCheck: boolean;
+ sanityCheckFormula: string;
+ };
+ isReadsLoading?: boolean;
+};
+
+const StatusReads = ({ reads, isReadsLoading }: StatusReadsProps) => {
+ const totalPending = reads?.totalPending ?? 0;
+ const totalActive = reads?.totalActive ?? 0;
+ const totalSent = reads?.totalSent ?? 0;
+ const totalLost = reads?.totalLost ?? 0;
+ const totalReceived = reads?.totalReceived ?? 0;
+
+ if (isReadsLoading) {
+ return Loading reads…
;
+ }
+ return (
+
+
+
+
+ Pending: {totalPending} | Active:{" "}
+ {totalActive} | Lost: {totalLost}
+
+ Sent / Received: {totalSent} |{" "}
+ {totalReceived}
+
+
+ );
+};
+
+export default StatusReads;
diff --git a/src/features/dashboard/components/SystemStatusCard.tsx b/src/features/dashboard/components/systemStatus/SystemStatusCard.tsx
similarity index 53%
rename from src/features/dashboard/components/SystemStatusCard.tsx
rename to src/features/dashboard/components/systemStatus/SystemStatusCard.tsx
index e3307b4..3017367 100644
--- a/src/features/dashboard/components/SystemStatusCard.tsx
+++ b/src/features/dashboard/components/systemStatus/SystemStatusCard.tsx
@@ -1,13 +1,23 @@
-import { useInfoSocket } from "../../../app/context/WebSocketContext";
-import Card from "../../../ui/Card";
-import CardHeader from "../../../ui/CardHeader";
-import StatusItemCPU from "./StatusItems/StatusItemCPU";
+import { useEffect } from "react";
+import { useInfoSocket } from "../../../../app/context/WebSocketContext";
+import Card from "../../../../ui/Card";
+import CardHeader from "../../../../ui/CardHeader";
+import DownloadLogButton from "./StatusItems/DownloadLogButton";
import StatusItemLocal from "./StatusItems/StatusItemLocal";
-import StatusItemThreads from "./StatusItems/StatusItemThreads";
import StatusItemUTC from "./StatusItems/StatusItemUTC";
+import StatusReads from "./StatusItems/StatusReads";
+import { useGetStore } from "../../hooks/useGetStore";
const SystemStatusCard = () => {
const { data: stats } = useInfoSocket();
+ const { storeQuery } = useGetStore();
+
+ const reads = storeQuery?.data;
+ const isReadsLoading = storeQuery.isFetching;
+
+ useEffect(() => {
+ storeQuery.refetch();
+ }, [reads]);
return (
@@ -16,8 +26,8 @@ const SystemStatusCard = () => {
-
-
+
+
) : (
Loading system status…
diff --git a/src/features/dashboard/hooks/useDownloadLogFiles.ts b/src/features/dashboard/hooks/useDownloadLogFiles.ts
new file mode 100644
index 0000000..75bdc15
--- /dev/null
+++ b/src/features/dashboard/hooks/useDownloadLogFiles.ts
@@ -0,0 +1,20 @@
+import { useQuery } from "@tanstack/react-query";
+import { CAMBASE } from "../../../utils/config";
+
+const getDownloadLogFiles = async () => {
+ const response = await fetch(`${CAMBASE}/LogView/download?filename=FlexiAI-0.log`);
+ if (!response.ok) {
+ throw new Error("Failed to download log files");
+ }
+ return response.blob();
+};
+
+export const useDownloadLogFiles = () => {
+ const downloadLogFilesQuery = useQuery({
+ queryKey: ["downloadLogFiles"],
+ queryFn: getDownloadLogFiles,
+ enabled: false,
+ });
+
+ return { downloadLogFilesQuery };
+};
diff --git a/src/features/dashboard/hooks/useGetStore.ts b/src/features/dashboard/hooks/useGetStore.ts
new file mode 100644
index 0000000..887176f
--- /dev/null
+++ b/src/features/dashboard/hooks/useGetStore.ts
@@ -0,0 +1,19 @@
+import { useQuery } from "@tanstack/react-query";
+import { CAMBASE } from "../../../utils/config";
+
+const getStoreData = async () => {
+ const response = await fetch(`${CAMBASE}/Store0/diagnostics-json`);
+ if (!response.ok) {
+ throw new Error("Network response was not ok");
+ }
+ return response.json();
+};
+
+export const useGetStore = () => {
+ const storeQuery = useQuery({
+ queryKey: ["storeData"],
+ queryFn: getStoreData,
+ // refetchInterval: 10 * 60 * 1000,
+ });
+ return { storeQuery };
+};
diff --git a/src/routes/index.tsx b/src/routes/index.tsx
index 301f601..3f2d9cb 100644
--- a/src/routes/index.tsx
+++ b/src/routes/index.tsx
@@ -6,9 +6,5 @@ export const Route = createFileRoute("/")({
});
function HomePage() {
- return (
-
-
-
- );
+ return ;
}