diff --git a/index.html b/index.html index fd0bb43..aec7947 100644 --- a/index.html +++ b/index.html @@ -1,10 +1,10 @@ - + - MAV | BayiQ + BayIQ
diff --git a/src/features/dashboard/components/CameraStatus.tsx b/src/features/dashboard/components/CameraStatus.tsx index e69de29..9c28274 100644 --- a/src/features/dashboard/components/CameraStatus.tsx +++ b/src/features/dashboard/components/CameraStatus.tsx @@ -0,0 +1,19 @@ +import Card from "../../../ui/Card"; +import CardHeader from "../../../ui/CardHeader"; + +type CameraStatusProps = { + title: string; + status?: string; + description: string; +}; + +const CameraStatus = ({ title, status, description }: CameraStatusProps) => { + return ( + + +

{description}

+
+ ); +}; + +export default CameraStatus; diff --git a/src/features/dashboard/components/DashboardGrid.tsx b/src/features/dashboard/components/DashboardGrid.tsx index 8cf481c..b430106 100644 --- a/src/features/dashboard/components/DashboardGrid.tsx +++ b/src/features/dashboard/components/DashboardGrid.tsx @@ -1,9 +1,17 @@ +import CameraStatus from "./CameraStatus"; +import SystemOverview from "./SystemOverview"; import SystemStatusCard from "./SystemStatusCard"; const DashboardGrid = () => { return ( -
+
+ +
+ + + +
); }; diff --git a/src/features/dashboard/components/StatusItems/StatusItemCPU.tsx b/src/features/dashboard/components/StatusItems/StatusItemCPU.tsx new file mode 100644 index 0000000..3ae97f6 --- /dev/null +++ b/src/features/dashboard/components/StatusItems/StatusItemCPU.tsx @@ -0,0 +1,23 @@ +import { faHardDrive } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +type StatusItemProps = { + statusInfoItem: string; + description: string; +}; + +const StatusItemCPU = ({ statusInfoItem, description }: StatusItemProps) => { + return ( +
+
+ + + +

{statusInfoItem}

+
+

{description}

+
+ ); +}; + +export default StatusItemCPU; diff --git a/src/features/dashboard/components/StatusItems/StatusItemLocal.tsx b/src/features/dashboard/components/StatusItems/StatusItemLocal.tsx new file mode 100644 index 0000000..f99cf40 --- /dev/null +++ b/src/features/dashboard/components/StatusItems/StatusItemLocal.tsx @@ -0,0 +1,31 @@ +import { faClock } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +type StatusItemProps = { + statusInfoItem: string; + description: string; +}; + +const StatusItemLocal = ({ statusInfoItem, description }: StatusItemProps) => { + const humanReadable = (string: string) => { + if (description.toLowerCase().includes("local")) { + const text = string.slice(0, statusInfoItem.length - 5); + return text; + } + }; + + return ( +
+
+ + + +

{description.toLowerCase().includes("local") && humanReadable(statusInfoItem)}

+
+ +

{description}

+
+ ); +}; + +export default StatusItemLocal; diff --git a/src/features/dashboard/components/StatusItems/StatusItemThreads.tsx b/src/features/dashboard/components/StatusItems/StatusItemThreads.tsx new file mode 100644 index 0000000..69ce8c8 --- /dev/null +++ b/src/features/dashboard/components/StatusItems/StatusItemThreads.tsx @@ -0,0 +1,24 @@ +import { faMicrochip } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +type StatusItemProps = { + statusInfoItem: string; + description: string; +}; + +const StatusItemThreads = ({ statusInfoItem, description }: StatusItemProps) => { + return ( +
+
+ + + +

{statusInfoItem}

+
+ +

{description}

+
+ ); +}; + +export default StatusItemThreads; diff --git a/src/features/dashboard/components/StatusItems/StatusItemUTC.tsx b/src/features/dashboard/components/StatusItems/StatusItemUTC.tsx new file mode 100644 index 0000000..b4adef8 --- /dev/null +++ b/src/features/dashboard/components/StatusItems/StatusItemUTC.tsx @@ -0,0 +1,32 @@ +import { faClock } from "@fortawesome/free-solid-svg-icons"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; + +type StatusItemProps = { + statusInfoItem: string; + description: string; +}; + +const StatusItemUTC = ({ statusInfoItem, description }: StatusItemProps) => { + const humanReadable = (string: string) => { + if (description.includes("UTC")) { + const text = string.slice(0, statusInfoItem.length - 3); + return text; + } + }; + + return ( +
+
+ + + + +

{description.toLowerCase().includes("utc") && humanReadable(statusInfoItem)}

+
+ +

{description}

+
+ ); +}; + +export default StatusItemUTC; diff --git a/src/features/dashboard/components/SystemHealth.tsx b/src/features/dashboard/components/SystemHealth.tsx new file mode 100644 index 0000000..6f1e12b --- /dev/null +++ b/src/features/dashboard/components/SystemHealth.tsx @@ -0,0 +1,38 @@ +import type { SystemHealthStatus } from "../../../types/types"; +import Badge from "../../../ui/Badge"; + +type SystemHealthProps = { + startTime: string; + uptime: string; + statuses: SystemHealthStatus[]; + isLoading: boolean; +}; + +const SystemHealth = ({ startTime, uptime, statuses, isLoading }: SystemHealthProps) => { + if (isLoading) { + return Loading system health…; + } + + return ( +
+
+
+

Start Time

{startTime} +
+
+

Up Time

{uptime} +
+
+ +
+ {statuses?.map((status: SystemHealthStatus) => ( +
+ {status.id} +
+ ))} +
+
+ ); +}; + +export default SystemHealth; diff --git a/src/features/dashboard/components/SystemOverview.tsx b/src/features/dashboard/components/SystemOverview.tsx new file mode 100644 index 0000000..2a6559d --- /dev/null +++ b/src/features/dashboard/components/SystemOverview.tsx @@ -0,0 +1,22 @@ +import { faArrowsRotate } from "@fortawesome/free-solid-svg-icons"; +import Card from "../../../ui/Card"; +import CardHeader from "../../../ui/CardHeader"; +import { useGetSystemHealth } from "../hooks/useGetSystemHealth"; +import SystemHealth from "./SystemHealth"; + +const SystemOverview = () => { + const { query } = useGetSystemHealth(); + + const startTime = query?.data?.StartTimeHumane; + const uptime = query?.data?.UptimeHumane; + const statuses = query?.data?.Status; + const isLoading = query?.isLoading; + return ( + + + + + ); +}; + +export default SystemOverview; diff --git a/src/features/dashboard/components/SystemStatusCard.tsx b/src/features/dashboard/components/SystemStatusCard.tsx index e7d6c09..e3307b4 100644 --- a/src/features/dashboard/components/SystemStatusCard.tsx +++ b/src/features/dashboard/components/SystemStatusCard.tsx @@ -1,20 +1,24 @@ import { useInfoSocket } from "../../../app/context/WebSocketContext"; import Card from "../../../ui/Card"; import CardHeader from "../../../ui/CardHeader"; +import StatusItemCPU from "./StatusItems/StatusItemCPU"; +import StatusItemLocal from "./StatusItems/StatusItemLocal"; +import StatusItemThreads from "./StatusItems/StatusItemThreads"; +import StatusItemUTC from "./StatusItems/StatusItemUTC"; const SystemStatusCard = () => { const { data: stats } = useInfoSocket(); return ( - - + + {stats ? ( - <> -
UTC: {stats["system-clock-utc"]}
- Local: {stats["system-clock-local"]} - CPU: {stats["memory-cpu-status"]} - Threads: {stats["thread-count"]} - +
+ + + + +
) : ( Loading system status… )} diff --git a/src/features/dashboard/hooks/useGetSystemHealth.ts b/src/features/dashboard/hooks/useGetSystemHealth.ts new file mode 100644 index 0000000..d9599d6 --- /dev/null +++ b/src/features/dashboard/hooks/useGetSystemHealth.ts @@ -0,0 +1,15 @@ +import { useQuery } from "@tanstack/react-query"; + +const fetchData = async () => { + const response = await fetch(`http://100.115.148.59/api/system-health`); + if (!response.ok) throw new Error("Cannot get System overview"); + return response.json(); +}; + +export const useGetSystemHealth = () => { + const query = useQuery({ + queryKey: ["fetchSystemData"], + queryFn: fetchData, + }); + return { query }; +}; diff --git a/src/routes/baywatch.tsx b/src/routes/baywatch.tsx index f7401ab..0cb9718 100644 --- a/src/routes/baywatch.tsx +++ b/src/routes/baywatch.tsx @@ -9,7 +9,6 @@ export const Route = createFileRoute("/baywatch")({ function RouteComponent() { return (
-

Cameras

diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 8cd7e69..301f601 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -8,7 +8,6 @@ export const Route = createFileRoute("/")({ function HomePage() { return (
-

Dashboard

); diff --git a/src/types/types.ts b/src/types/types.ts index e838896..b130f22 100644 --- a/src/types/types.ts +++ b/src/types/types.ts @@ -11,7 +11,13 @@ export type InfoBarData = { "thread-count": string; }; +export type StatusIndicator = "neutral-quaternary" | "dark" | "info" | "success" | "warning" | "danger"; export type Region = { name: string; brushColour: string; }; + +export type SystemHealthStatus = { + id: string; + tags: string[]; +}; diff --git a/src/ui/Badge.tsx b/src/ui/Badge.tsx new file mode 100644 index 0000000..7e088af --- /dev/null +++ b/src/ui/Badge.tsx @@ -0,0 +1,24 @@ +import type { Icon, IconDefinition } from "@fortawesome/fontawesome-svg-core"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { capitalize } from "../utils/utils"; + +type BadgeProps = { + icon?: Icon | IconDefinition; + text: string; +}; + +const Badge = ({ icon, text }: BadgeProps) => { + const lowerCaseWord = text.toLowerCase(); + return ( + + {icon && } + {capitalize(lowerCaseWord)} + + ); +}; + +export default Badge; diff --git a/src/ui/CardHeader.tsx b/src/ui/CardHeader.tsx index 027ecae..3d6c3b2 100644 --- a/src/ui/CardHeader.tsx +++ b/src/ui/CardHeader.tsx @@ -1,18 +1,27 @@ import clsx from "clsx"; +import StatusIndicators from "./StatusIndicators"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import type { IconProp } from "@fortawesome/fontawesome-svg-core"; type CameraOverviewHeaderProps = { title?: string; + status?: string; + refetch?: () => void; + icon?: IconProp; }; -const CardHeader = ({ title }: CameraOverviewHeaderProps) => { +const CardHeader = ({ title, status, icon, refetch }: CameraOverviewHeaderProps) => { return (
-
- {/* {icon && } */} -

{title}

+
+

+ {status && } + {title} +

+ {icon && }
); diff --git a/src/ui/StatusIndicators.tsx b/src/ui/StatusIndicators.tsx new file mode 100644 index 0000000..5d4d529 --- /dev/null +++ b/src/ui/StatusIndicators.tsx @@ -0,0 +1,9 @@ +import clsx from "clsx"; + +type StatusIndicatorsProps = { status: string }; + +const StatusIndicators = ({ status }: StatusIndicatorsProps) => { + return ; +}; + +export default StatusIndicators; diff --git a/src/utils/utils.ts b/src/utils/utils.ts new file mode 100644 index 0000000..23c5527 --- /dev/null +++ b/src/utils/utils.ts @@ -0,0 +1,3 @@ +export function capitalize(s?: string) { + return s ? s.charAt(0).toUpperCase() + s.slice(1) : ""; +}