- added new dashboard items
- added camera module statuses
This commit is contained in:
@@ -1,17 +1,35 @@
|
|||||||
|
import type { SystemHealthStatus } from "../../../types/types";
|
||||||
import Card from "../../../ui/Card";
|
import Card from "../../../ui/Card";
|
||||||
import CardHeader from "../../../ui/CardHeader";
|
import StatusIndicators from "../../../ui/StatusIndicators";
|
||||||
|
import { capitalize } from "../../../utils/utils";
|
||||||
|
import CameraStatusGridItem from "./CameraStatusGridItem";
|
||||||
|
|
||||||
type CameraStatusProps = {
|
type CameraStatusProps = {
|
||||||
title: string;
|
title: string;
|
||||||
status?: string;
|
category: SystemHealthStatus[];
|
||||||
description: string;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const CameraStatus = ({ title, status, description }: CameraStatusProps) => {
|
const CameraStatus = ({ title, category }: CameraStatusProps) => {
|
||||||
|
const isAllGood = category?.every((status) => status.tags.includes("RUNNING"));
|
||||||
|
// check if some are down
|
||||||
|
// check if all are down
|
||||||
|
//check if offline
|
||||||
return (
|
return (
|
||||||
<Card className="p-4">
|
<Card className="p-4">
|
||||||
<CardHeader title={title} status={status} />
|
<div className="border-b border-gray-600">
|
||||||
<p className=" text-gray-500">{description}</p>
|
<h3 className="text-lg flex flex-row items-center">
|
||||||
|
{isAllGood ? <StatusIndicators status={"bg-green-500"} /> : <StatusIndicators status={"bg-amber-500"} />}
|
||||||
|
{capitalize(title)}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm text-slate-300">{isAllGood ? "All systems running" : "Some systems down"}</p>
|
||||||
|
</div>
|
||||||
|
{category && category?.length <= 0 ? (
|
||||||
|
<p className=" text-gray-500">Loading Camera health...</p>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
<CameraStatusGridItem title={title} statusCategory={category} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
38
src/features/dashboard/components/CameraStatusGridItem.tsx
Normal file
38
src/features/dashboard/components/CameraStatusGridItem.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import { useState } from "react";
|
||||||
|
import type { SystemHealthStatus } from "../../../types/types";
|
||||||
|
import { capitalize } from "../../../utils/utils";
|
||||||
|
import SystemHealthModal from "./systemHealthModal/SystemHealthModal";
|
||||||
|
|
||||||
|
type CameraStatusGridItemProps = {
|
||||||
|
title: string;
|
||||||
|
statusCategory: SystemHealthStatus[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const CameraStatusGridItem = ({ title, statusCategory }: CameraStatusGridItemProps) => {
|
||||||
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const isAllGood = statusCategory?.every((status) => status.tags.includes("RUNNING"));
|
||||||
|
|
||||||
|
const handleClick = () => {
|
||||||
|
setIsOpen(false);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
className="flex flex-col border border-gray-600 p-4 rounded-lg mr-4 hover:bg-[#233241] hover:cursor-pointer m-2 h-70"
|
||||||
|
onClick={() => setIsOpen(true)}
|
||||||
|
>
|
||||||
|
<h3 className="text-lg flex flex-row items-center">{capitalize(title)}</h3>
|
||||||
|
<p className="text-sm text-slate-300">{isAllGood ? "Click to view module status" : "Some systems down"}</p>
|
||||||
|
</div>
|
||||||
|
<SystemHealthModal
|
||||||
|
isSystemHealthModalOpen={isOpen}
|
||||||
|
handleClose={handleClick}
|
||||||
|
statusCategory={statusCategory}
|
||||||
|
title={title}
|
||||||
|
isAllGood={isAllGood}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default CameraStatusGridItem;
|
||||||
@@ -1,16 +1,55 @@
|
|||||||
|
import type { SystemHealthStatus } from "../../../types/types";
|
||||||
|
import { useGetSystemHealth } from "../hooks/useGetSystemHealth";
|
||||||
import CameraStatus from "./CameraStatus";
|
import CameraStatus from "./CameraStatus";
|
||||||
import SystemOverview from "./SystemOverview";
|
import SystemOverview from "./SystemOverview";
|
||||||
import SystemStatusCard from "./SystemStatusCard";
|
import SystemStatusCard from "./SystemStatusCard";
|
||||||
|
|
||||||
const DashboardGrid = () => {
|
const DashboardGrid = () => {
|
||||||
|
const { query } = useGetSystemHealth();
|
||||||
|
const startTime = query?.data?.StartTimeHumane;
|
||||||
|
const uptime = query?.data?.UptimeHumane;
|
||||||
|
const statuses: SystemHealthStatus[] = query?.data?.Status;
|
||||||
|
const isLoading = query?.isLoading;
|
||||||
|
const isError = query?.isError;
|
||||||
|
const dateUpdatedAt = query?.dataUpdatedAt;
|
||||||
|
const refetch = query?.refetch;
|
||||||
|
|
||||||
|
const statusCategories = statuses?.reduce<Record<string, SystemHealthStatus[]>>(
|
||||||
|
(acc, cur) => {
|
||||||
|
if (cur?.groupID === "ChannelA") acc?.channelA?.push(cur);
|
||||||
|
if (cur?.groupID === "ChannelB") acc?.channelB?.push(cur);
|
||||||
|
if (cur?.groupID === "ChannelC") acc?.channelC?.push(cur);
|
||||||
|
if (cur?.groupID === "Default") acc?.default?.push(cur);
|
||||||
|
return acc;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
channelA: [],
|
||||||
|
channelB: [],
|
||||||
|
channelC: [],
|
||||||
|
default: [],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
const categoryA = statusCategories?.channelA ?? [];
|
||||||
|
const categoryB = statusCategories?.channelB ?? [];
|
||||||
|
const categoryC = statusCategories?.channelC ?? [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="grid grid-cols-1 md:grid-rows-2 md:grid-cols-2">
|
<div className="grid grid-cols-1 md:grid-rows-2 md:grid-cols-2">
|
||||||
<SystemStatusCard />
|
<SystemStatusCard />
|
||||||
<SystemOverview />
|
<SystemOverview
|
||||||
|
startTime={startTime}
|
||||||
|
uptime={uptime}
|
||||||
|
statuses={statuses}
|
||||||
|
isLoading={isLoading}
|
||||||
|
isError={isError}
|
||||||
|
dateUpdatedAt={dateUpdatedAt}
|
||||||
|
refetch={refetch}
|
||||||
|
/>
|
||||||
<div className="grid grid-cols-1 md:col-span-2 md:grid-cols-3">
|
<div className="grid grid-cols-1 md:col-span-2 md:grid-cols-3">
|
||||||
<CameraStatus title="Camera 1" status={"bg-red-500"} description={"Camera not responding"} />
|
<CameraStatus title="Camera A" category={categoryA} />
|
||||||
<CameraStatus title="Camera 2" status={"bg-gray-500"} description={"Camera Offline"} />
|
<CameraStatus title="Camera B" category={categoryB} />
|
||||||
<CameraStatus title="Camera 3" status={"bg-gray-500"} description={"Camera Offline"} />
|
<CameraStatus title="Camera C" category={categoryC} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -29,12 +29,7 @@ const SystemHealth = ({ startTime, uptime, statuses, isLoading, isError, dateUpd
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
const convertObjtoArray = (obj: Record<string, SystemHealthStatus[]>) => {
|
const categoryDefault = statusCategories?.default ?? [];
|
||||||
if (!obj) return;
|
|
||||||
const statusCategoryArray = Object.entries(obj);
|
|
||||||
return statusCategoryArray;
|
|
||||||
};
|
|
||||||
const statusCategoryArray = convertObjtoArray(statusCategories);
|
|
||||||
|
|
||||||
if (isError) {
|
if (isError) {
|
||||||
return <span className="text-red-500">Error loading system health.</span>;
|
return <span className="text-red-500">Error loading system health.</span>;
|
||||||
@@ -52,10 +47,8 @@ const SystemHealth = ({ startTime, uptime, statuses, isLoading, isError, dateUpd
|
|||||||
<h3 className="text-lg">Up Time</h3> <span className="text-slate-300">{uptime}</span>
|
<h3 className="text-lg">Up Time</h3> <span className="text-slate-300">{uptime}</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="h-50 overflow-auto grid grid-cols-2 gap-4">
|
<div className="overflow-auto gap-4">
|
||||||
{statusCategoryArray?.map((status) => (
|
<StatusGridItem title={"Modules"} statusCategory={categoryDefault} />
|
||||||
<StatusGridItem title={status[0]} statusCategory={status[1]} />
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="border-t border-gray-500">
|
<div className="border-t border-gray-500">
|
||||||
<small className="italic text-gray-400">{`Last refeshed ${updatedDate}`}</small>
|
<small className="italic text-gray-400">{`Last refeshed ${updatedDate}`}</small>
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
import { faArrowsRotate } from "@fortawesome/free-solid-svg-icons";
|
import { faArrowsRotate } from "@fortawesome/free-solid-svg-icons";
|
||||||
import Card from "../../../ui/Card";
|
import Card from "../../../ui/Card";
|
||||||
import CardHeader from "../../../ui/CardHeader";
|
import CardHeader from "../../../ui/CardHeader";
|
||||||
import { useGetSystemHealth } from "../hooks/useGetSystemHealth";
|
|
||||||
import SystemHealth from "./SystemHealth";
|
import SystemHealth from "./SystemHealth";
|
||||||
|
import type { SystemHealthStatus } from "../../../types/types";
|
||||||
|
|
||||||
const SystemOverview = () => {
|
type SystemOverviewProps = {
|
||||||
const { query } = useGetSystemHealth();
|
startTime: string;
|
||||||
|
uptime: string;
|
||||||
const startTime = query?.data?.StartTimeHumane;
|
statuses: SystemHealthStatus[];
|
||||||
const uptime = query?.data?.UptimeHumane;
|
isLoading: boolean;
|
||||||
const statuses = query?.data?.Status;
|
isError: boolean;
|
||||||
const isLoading = query?.isLoading;
|
dateUpdatedAt: number;
|
||||||
const isError = query?.isError;
|
refetch: () => void;
|
||||||
const dateUpdatedAt = query?.dataUpdatedAt;
|
};
|
||||||
|
|
||||||
|
const SystemOverview = ({
|
||||||
|
startTime,
|
||||||
|
uptime,
|
||||||
|
statuses,
|
||||||
|
isLoading,
|
||||||
|
isError,
|
||||||
|
dateUpdatedAt,
|
||||||
|
refetch,
|
||||||
|
}: SystemOverviewProps) => {
|
||||||
return (
|
return (
|
||||||
<Card className="p-4">
|
<Card className="p-4">
|
||||||
<CardHeader title="System Health" refetch={query?.refetch} icon={faArrowsRotate} />
|
<CardHeader title="System Health" refetch={refetch} icon={faArrowsRotate} />
|
||||||
<SystemHealth
|
<SystemHealth
|
||||||
startTime={startTime}
|
startTime={startTime}
|
||||||
uptime={uptime}
|
uptime={uptime}
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
import type { SystemHealthStatus } from "../types/types";
|
||||||
|
|
||||||
export function capitalize(s?: string) {
|
export function capitalize(s?: string) {
|
||||||
return s ? s.charAt(0).toUpperCase() + s.slice(1) : "";
|
return s ? s.charAt(0).toUpperCase() + s.slice(1) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const convertObjtoArray = (obj: Record<string, SystemHealthStatus[]>) => {
|
||||||
|
if (!obj) return;
|
||||||
|
const statusCategoryArray = Object.entries(obj);
|
||||||
|
return statusCategoryArray;
|
||||||
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user