alert details

This commit is contained in:
mbecker20
2024-04-06 01:54:20 -07:00
parent 3915f921f1
commit 1ed3d31011
5 changed files with 147 additions and 88 deletions
+129
View File
@@ -0,0 +1,129 @@
import { Section } from "@components/layouts";
import { ResourceComponents } from "@components/resources";
import { ResourceLink } from "@components/util";
import {
alert_level_intention,
text_color_class_by_intention,
} from "@lib/color";
import { fmt_date_with_minutes } from "@lib/formatting";
import { useRead } from "@lib/hooks";
import { Types } from "@monitor/client";
import { UsableResource } from "@types";
import { Button } from "@ui/button";
import { DataTable } from "@ui/data-table";
import { Dialog, DialogContent, DialogHeader, DialogTrigger } from "@ui/dialog";
import { useAtom } from "jotai";
import { atomWithStorage } from "jotai/utils";
import { AlertTriangle } from "lucide-react";
import { useState } from "react";
const openAtom = atomWithStorage("show-alerts-v0", true);
export const OpenAlerts = () => {
const [open, setOpen] = useAtom(openAtom);
const alerts = useRead("ListAlerts", { query: { resolved: false } }).data
?.alerts;
if (!alerts || alerts.length === 0) return null;
return (
<Section
title="Open Alerts"
icon={<AlertTriangle className="w-4 h-4" />}
actions={
<Button variant="ghost" onClick={() => setOpen(!open)}>
{open ? "close" : "open"}
</Button>
}
>
{open && (
<DataTable
data={alerts ?? []}
columns={[
{
header: "Details",
cell: ({ row }) =>
row.original._id?.$oid && (
<AlertDetailsDialog id={row.original._id?.$oid} />
),
},
{
header: "Target",
cell: ({ row }) => {
switch (row.original.target.type) {
case "Server":
return (
<ResourceComponents.Server.Link
id={row.original.target.id}
/>
);
default:
return "Unknown";
}
},
},
{
header: "Level",
cell: ({ row }) => <AlertLevel level={row.original.level} />,
},
{
header: "Alert",
accessorKey: "variant",
},
{
header: "Open Since",
accessorFn: ({ ts }) => fmt_date_with_minutes(new Date(ts)),
},
]}
/>
)}
</Section>
);
};
const AlertLevel = ({ level }: { level: Types.SeverityLevel }) => {
return (
<div
className={text_color_class_by_intention(alert_level_intention(level))}
>
{level}
</div>
);
};
const AlertDetailsDialog = ({ id }: { id: string }) => {
const [open, set] = useState(false);
const alert = useRead("ListAlerts", {}).data?.alerts.find(
(alert) => alert._id?.$oid === id
);
return (
<Dialog open={open} onOpenChange={set}>
<DialogTrigger asChild>
<Button variant="secondary" className="items-center gap-2">
Details
</Button>
</DialogTrigger>
<DialogContent>
{alert && (
<>
<DialogHeader className="flex-row justify-between w-full">
{alert && (
<>
<div className="flex gap-4 items-center">
<ResourceLink
type={alert.target.type as UsableResource}
id={alert.target.id}
/>
<AlertLevel level={alert.level} />
</div>
<div className="text-muted-foreground">
{fmt_date_with_minutes(new Date(alert.ts))}
</div>
</>
)}
</DialogHeader>
<pre>{JSON.stringify(alert.data, undefined, 2)}</pre>
</>
)}
</DialogContent>
</Dialog>
);
};
+6 -4
View File
@@ -12,6 +12,7 @@ import { Button } from "@ui/button";
import { Input } from "@ui/input";
import { Switch } from "@ui/switch";
import {
CheckCircle,
ChevronsUpDown,
MinusCircle,
PlusCircle,
@@ -38,6 +39,7 @@ import {
CommandList,
} from "@ui/command";
import { snake_case_to_upper_space_case } from "@lib/formatting";
import { ConfirmButton } from "@components/util";
export const ConfigItem = ({
label,
@@ -350,14 +352,14 @@ export const ConfirmUpdate = ({ content, onConfirm }: ConfirmUpdateProps) => {
<pre className="h-[300px] overflow-auto">{content}</pre>
</div>
<DialogFooter>
<Button
<ConfirmButton
title="Update"
icon={<CheckCircle className="w-4 h-4" />}
onClick={() => {
onConfirm();
set(false);
}}
>
Confirm
</Button>
/>
</DialogFooter>
</DialogContent>
</Dialog>
-19
View File
@@ -26,7 +26,6 @@ import {
DropdownMenuContent,
DropdownMenuTrigger,
} from "@ui/dropdown-menu";
import { Types } from "@monitor/client";
import { AUTH_TOKEN_STORAGE_KEY } from "@main";
import { UsableResource } from "@types";
import { ResourceComponents } from "./resources";
@@ -335,24 +334,6 @@ export const CopyButton = ({ content }: { content: string | undefined }) => {
);
};
const alert_level_color = (level: Types.SeverityLevel) => {
if (level === Types.SeverityLevel.Ok) return "green-500";
if (level === Types.SeverityLevel.Warning) return "orange-500";
if (level === Types.SeverityLevel.Critical) return "red-500";
};
// const alert_level_fill_color = (level: Types.SeverityLevel) => {
// return `fill-${alert_level_color(level)}`;
// };
const alert_level_text_color = (level: Types.SeverityLevel) => {
return `text-${alert_level_color(level)}`;
};
export const AlertLevel = ({ level }: { level: Types.SeverityLevel }) => {
return <div className={alert_level_text_color(level)}>{level}</div>;
};
export const ResourceLink = ({
type,
id,
+10
View File
@@ -100,3 +100,13 @@ export const deployment_state_intention: (
return "Critical";
}
};
export const alert_level_intention: (
level: Types.SeverityLevel
) => ColorIntention = (level) => {
switch (level) {
case Types.SeverityLevel.Ok: return "Good"
case Types.SeverityLevel.Warning: return "Warning"
case Types.SeverityLevel.Critical: return "Critical"
}
}
+2 -65
View File
@@ -1,17 +1,11 @@
import { useRead } from "@lib/hooks";
import { Page, Section } from "@components/layouts";
import { AlertTriangle, Box, FolderTree } from "lucide-react";
import { DataTable } from "@ui/data-table";
import { Box, FolderTree } from "lucide-react";
import { Link } from "react-router-dom";
import { AlertLevel } from "@components/util";
import { Button } from "@ui/button";
import { Card, CardDescription, CardHeader, CardTitle } from "@ui/card";
import { TagsSummary } from "@components/dashboard/tags";
import { ApiKeysSummary } from "@components/dashboard/api-keys";
import { atomWithStorage } from "jotai/utils";
import { useAtom } from "jotai";
import { fmt_date_with_minutes } from "@lib/formatting";
import { ResourceComponents } from "@components/resources";
import { OpenAlerts } from "@components/alert";
export const Dashboard = () => {
return (
@@ -23,63 +17,6 @@ export const Dashboard = () => {
);
};
const openAtom = atomWithStorage("show-alerts-v0", true);
const OpenAlerts = () => {
const [open, setOpen] = useAtom(openAtom);
const alerts = useRead("ListAlerts", { query: { resolved: false } }).data
?.alerts;
if (!alerts || alerts.length === 0) return null;
return (
<Section
title="Open Alerts"
icon={<AlertTriangle className="w-4 h-4" />}
actions={
<Button variant="ghost" onClick={() => setOpen(!open)}>
{open ? "close" : "open"}
</Button>
}
>
{open && (
<DataTable
data={alerts ?? []}
columns={[
{
header: "Target",
cell: ({ row }) => {
switch (row.original.target.type) {
case "Server":
return (
<Link to={`/servers/${row.original.target.id}`}>
<ResourceComponents.Server.Name
id={row.original.target.id}
/>
</Link>
);
default:
return "Unknown";
}
},
},
{
header: "Level",
cell: ({ row }) => <AlertLevel level={row.original.level} />,
},
{
header: "Alert",
accessorKey: "variant",
},
{
header: "Open Since",
accessorFn: ({ ts }) => fmt_date_with_minutes(new Date(ts)),
},
]}
/>
)}
</Section>
);
};
const Resources = () => (
<Section title="Resources" icon={<Box className="w-4 h-4" />} actions="">
<div className="flex flex-col lg:flex-row gap-4 w-full">