diff --git a/frontend/src/components/alert/index.tsx b/frontend/src/components/alert/index.tsx new file mode 100644 index 000000000..3bb9792bd --- /dev/null +++ b/frontend/src/components/alert/index.tsx @@ -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 ( +
} + actions={ + + } + > + {open && ( + + row.original._id?.$oid && ( + + ), + }, + { + header: "Target", + cell: ({ row }) => { + switch (row.original.target.type) { + case "Server": + return ( + + ); + default: + return "Unknown"; + } + }, + }, + { + header: "Level", + cell: ({ row }) => , + }, + { + header: "Alert", + accessorKey: "variant", + }, + { + header: "Open Since", + accessorFn: ({ ts }) => fmt_date_with_minutes(new Date(ts)), + }, + ]} + /> + )} +
+ ); +}; + +const AlertLevel = ({ level }: { level: Types.SeverityLevel }) => { + return ( +
+ {level} +
+ ); +}; + +const AlertDetailsDialog = ({ id }: { id: string }) => { + const [open, set] = useState(false); + const alert = useRead("ListAlerts", {}).data?.alerts.find( + (alert) => alert._id?.$oid === id + ); + return ( + + + + + + {alert && ( + <> + + {alert && ( + <> +
+ + +
+
+ {fmt_date_with_minutes(new Date(alert.ts))} +
+ + )} +
+
{JSON.stringify(alert.data, undefined, 2)}
+ + )} +
+
+ ); +}; diff --git a/frontend/src/components/config/util.tsx b/frontend/src/components/config/util.tsx index 146c487a1..1b73f6a14 100644 --- a/frontend/src/components/config/util.tsx +++ b/frontend/src/components/config/util.tsx @@ -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) => {
{content}
- + /> diff --git a/frontend/src/components/util.tsx b/frontend/src/components/util.tsx index 7a4b841fe..ea22aec60 100644 --- a/frontend/src/components/util.tsx +++ b/frontend/src/components/util.tsx @@ -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
{level}
; -}; - export const ResourceLink = ({ type, id, diff --git a/frontend/src/lib/color.ts b/frontend/src/lib/color.ts index 181bd841c..5fc0e6af3 100644 --- a/frontend/src/lib/color.ts +++ b/frontend/src/lib/color.ts @@ -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" + } +} \ No newline at end of file diff --git a/frontend/src/pages/home/dashboard.tsx b/frontend/src/pages/home/dashboard.tsx index 114174b45..286371686 100644 --- a/frontend/src/pages/home/dashboard.tsx +++ b/frontend/src/pages/home/dashboard.tsx @@ -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 ( -
} - actions={ - - } - > - {open && ( - { - switch (row.original.target.type) { - case "Server": - return ( - - - - ); - default: - return "Unknown"; - } - }, - }, - { - header: "Level", - cell: ({ row }) => , - }, - { - header: "Alert", - accessorKey: "variant", - }, - { - header: "Open Since", - accessorFn: ({ ts }) => fmt_date_with_minutes(new Date(ts)), - }, - ]} - /> - )} -
- ); -}; - const Resources = () => (
} actions="">