refactor: rename app crate and binary names to addmon for consistency

This commit is contained in:
Syahdan 2026-01-07 18:35:39 +07:00
parent d19a7bdaa0
commit cb30287fbd
5 changed files with 127 additions and 62 deletions

View file

@ -2,7 +2,7 @@
"$schema": "https://schema.tauri.app/config/2", "$schema": "https://schema.tauri.app/config/2",
"productName": "addmon", "productName": "addmon",
"version": "0.1.0", "version": "0.1.0",
"identifier": "com.tauri.dev", "identifier": "com.littlequartz.addmon",
"build": { "build": {
"frontendDist": "../dist", "frontendDist": "../dist",
"devUrl": "http://localhost:3001", "devUrl": "http://localhost:3001",

View file

@ -1,9 +1,7 @@
import * as React from "react";
import { format } from "date-fns"; import { format } from "date-fns";
import { Plus, Link, Link2Off } from "lucide-react"; import { Link, Link2Off, Plus } from "lucide-react";
import * as React from "react";
import { cn } from "@/lib/utils";
import type { Incident, ProcessedAlert } from "@/lib/types/alerts";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { import {
Card, Card,
@ -15,6 +13,8 @@ import {
} from "@/components/ui/card"; } from "@/components/ui/card";
import { Input } from "@/components/ui/input"; import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label"; import { Label } from "@/components/ui/label";
import type { Incident, ProcessedAlert } from "@/lib/types/alerts";
import { cn } from "@/lib/utils";
interface IncidentManagerProps { interface IncidentManagerProps {
incidents: Incident[]; incidents: Incident[];
@ -137,7 +137,7 @@ export function IncidentManager({
className={cn( className={cn(
"relative transition-colors", "relative transition-colors",
isCurrentAlertAttached && isCurrentAlertAttached &&
"border-primary/50 bg-primary/5", "border-primary/50 bg-primary/5",
)} )}
> >
<CardHeader className="pb-2"> <CardHeader className="pb-2">
@ -166,7 +166,7 @@ export function IncidentManager({
className={cn( className={cn(
"shrink-0", "shrink-0",
isCurrentAlertAttached && isCurrentAlertAttached &&
"bg-destructive/10 text-destructive hover:bg-destructive/20", "bg-destructive/10 text-destructive hover:bg-destructive/20",
)} )}
> >
{isCurrentAlertAttached ? ( {isCurrentAlertAttached ? (
@ -199,7 +199,7 @@ export function IncidentManager({
</div> </div>
</div> </div>
</CardContent> </CardContent>
<CardFooter className="pt-0 pb-3 text-[10px] text-muted-foreground"> <CardFooter className="pt-3 pb-3 text-[10px] text-muted-foreground">
<div className="flex items-center gap-1.5 w-full"> <div className="flex items-center gap-1.5 w-full">
<div <div
className={cn( className={cn(

View file

@ -1,6 +1,7 @@
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Skeleton } from "@/components/ui/skeleton"; import { Skeleton } from "@/components/ui/skeleton";
import type { KpiMetrics } from "@/lib/types/alerts"; import type { KpiMetrics } from "@/lib/types/alerts";
import { KPI_THRESHOLDS } from "@/lib/types/alerts";
import { cn } from "@/lib/utils"; import { cn } from "@/lib/utils";
interface KpiDashboardProps { interface KpiDashboardProps {
@ -11,11 +12,11 @@ interface KpiDashboardProps {
export function KpiDashboard({ kpis, isLoading = false }: KpiDashboardProps) { export function KpiDashboard({ kpis, isLoading = false }: KpiDashboardProps) {
if (isLoading) { if (isLoading) {
return ( return (
<div className="grid gap-4 md:grid-cols-3"> <div className="grid gap-4 md:grid-cols-4">
<Card className="rounded-none"> <Card className="rounded-none">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"> <CardTitle className="text-sm font-medium">
Error Coverage Alert Coverage Ratio
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@ -26,17 +27,7 @@ export function KpiDashboard({ kpis, isLoading = false }: KpiDashboardProps) {
<Card className="rounded-none"> <Card className="rounded-none">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium"> <CardTitle className="text-sm font-medium">
Total Downtime False Positive Rate
</CardTitle>
</CardHeader>
<CardContent>
<Skeleton className="h-7 w-20 rounded-none" />
</CardContent>
</Card>
<Card className="rounded-none">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">
Invalid Alerts
</CardTitle> </CardTitle>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
@ -44,6 +35,23 @@ export function KpiDashboard({ kpis, isLoading = false }: KpiDashboardProps) {
<Skeleton className="mt-1 h-4 w-32 rounded-none" /> <Skeleton className="mt-1 h-4 w-32 rounded-none" />
</CardContent> </CardContent>
</Card> </Card>
<Card className="rounded-none">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Uptime Ratio</CardTitle>
</CardHeader>
<CardContent>
<Skeleton className="h-7 w-20 rounded-none" />
<Skeleton className="mt-1 h-4 w-32 rounded-none" />
</CardContent>
</Card>
<Card className="rounded-none">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Verdict</CardTitle>
</CardHeader>
<CardContent>
<Skeleton className="h-7 w-20 rounded-none" />
</CardContent>
</Card>
</div> </div>
); );
} }
@ -58,29 +66,35 @@ export function KpiDashboard({ kpis, isLoading = false }: KpiDashboardProps) {
); );
} }
const coverageColor = const alertCoverageRatio = kpis.errorCoverageRatio;
kpis.errorCoverageRatio > 80 const falsePositiveRate = kpis.invalidAlertRatio;
? "text-green-500" const MONTHS_MS = 30 * 24 * 60 * 60 * 1000 * 3; // 3 months
: kpis.errorCoverageRatio > 50 const uptimeRatio = ((MONTHS_MS - kpis.overallDowntimeMs) / MONTHS_MS) * 100;
? "text-yellow-500"
: "text-destructive";
const invalidColor = const coveragePassed =
kpis.invalidAlertRatio < 10 alertCoverageRatio >= KPI_THRESHOLDS.alertCoverageRatio;
? "text-green-500" const fpPassed = falsePositiveRate <= KPI_THRESHOLDS.falsePositiveRate;
: kpis.invalidAlertRatio < 25 const uptimePassed = uptimeRatio >= KPI_THRESHOLDS.uptimeRatio;
? "text-yellow-500" const isEffective = coveragePassed && fpPassed && uptimePassed;
: "text-destructive";
const coverageColor = coveragePassed ? "text-green-500" : "text-destructive";
const fpColor = fpPassed ? "text-green-500" : "text-destructive";
const uptimeColor = uptimePassed ? "text-green-500" : "text-destructive";
return ( return (
<div className="grid gap-4 md:grid-cols-3"> <div className="grid gap-4 md:grid-cols-4">
<Card className="rounded-none"> <Card className="rounded-none">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Error Coverage</CardTitle> <CardTitle className="text-sm font-medium">
Alert Coverage Ratio
</CardTitle>
<span className="text-[10px] text-muted-foreground">
{KPI_THRESHOLDS.alertCoverageRatio}%
</span>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className={cn("text-2xl font-bold", coverageColor)}> <div className={cn("text-2xl font-bold", coverageColor)}>
{kpis.errorCoverageRatio.toFixed(1)}% {alertCoverageRatio.toFixed(1)}%
</div> </div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{kpis.coveredIncidents} of {kpis.totalIncidents} incidents {kpis.coveredIncidents} of {kpis.totalIncidents} incidents
@ -90,28 +104,64 @@ export function KpiDashboard({ kpis, isLoading = false }: KpiDashboardProps) {
<Card className="rounded-none"> <Card className="rounded-none">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2"> <CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Total Downtime</CardTitle> <CardTitle className="text-sm font-medium">
False Positive Rate
</CardTitle>
<span className="text-[10px] text-muted-foreground">
{KPI_THRESHOLDS.falsePositiveRate}%
</span>
</CardHeader> </CardHeader>
<CardContent> <CardContent>
<div className="text-2xl font-bold"> <div className={cn("text-2xl font-bold", fpColor)}>
{kpis.overallDowntimeFormatted} {falsePositiveRate.toFixed(1)}%
</div>
</CardContent>
</Card>
<Card className="rounded-none">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Invalid Alerts</CardTitle>
</CardHeader>
<CardContent>
<div className={cn("text-2xl font-bold", invalidColor)}>
{kpis.invalidAlertRatio.toFixed(1)}%
</div> </div>
<p className="text-xs text-muted-foreground"> <p className="text-xs text-muted-foreground">
{kpis.invalidAlerts} of {kpis.totalFiringAlerts} alerts {kpis.invalidAlerts} of {kpis.totalFiringAlerts} alerts
</p> </p>
</CardContent> </CardContent>
</Card> </Card>
<Card className="rounded-none">
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Uptime Ratio</CardTitle>
<span className="text-[10px] text-muted-foreground">
{KPI_THRESHOLDS.uptimeRatio}%
</span>
</CardHeader>
<CardContent>
<div className={cn("text-2xl font-bold", uptimeColor)}>
{uptimeRatio.toFixed(2)}%
</div>
<p className="text-xs text-muted-foreground">
Downtime: {kpis.overallDowntimeFormatted}
</p>
</CardContent>
</Card>
<Card
className={cn(
"rounded-none border-2",
isEffective ? "border-green-500/50" : "border-destructive/50",
)}
>
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-2">
<CardTitle className="text-sm font-medium">Verdict</CardTitle>
</CardHeader>
<CardContent>
<div
className={cn(
"text-xl font-bold",
isEffective ? "text-green-500" : "text-destructive",
)}
>
{isEffective ? "EFFECTIVE" : "NOT EFFECTIVE"}
</div>
<p className="text-xs text-muted-foreground">
{[coveragePassed, fpPassed, uptimePassed].filter(Boolean).length}/3
KPIs passed
</p>
</CardContent>
</Card>
</div> </div>
); );
} }

View file

@ -33,6 +33,19 @@ export interface KpiMetrics {
invalidAlerts: number; invalidAlerts: number;
} }
export const KPI_THRESHOLDS = {
alertCoverageRatio: 99,
falsePositiveRate: 20,
uptimeRatio: 99.9,
} as const;
export interface EffectivenessVerdict {
isEffective: boolean;
alertCoveragePassed: boolean;
falsePositivePassed: boolean;
uptimePassed: boolean;
}
export interface MonitorState { export interface MonitorState {
alerts: ProcessedAlert[]; alerts: ProcessedAlert[];
incidents: Incident[]; incidents: Incident[];

View file

@ -2,6 +2,7 @@ import { createFileRoute } from "@tanstack/react-router";
import { ArrowDownWideNarrow, FileUp, Filter, Search } from "lucide-react"; import { ArrowDownWideNarrow, FileUp, Filter, Search } from "lucide-react";
import * as React from "react"; import * as React from "react";
import { ModeToggle } from "@/components/mode-toggle";
import { AlertList } from "@/components/monitor/alert-list"; import { AlertList } from "@/components/monitor/alert-list";
import { IncidentManager } from "@/components/monitor/incident-manager"; import { IncidentManager } from "@/components/monitor/incident-manager";
import { KpiDashboard } from "@/components/monitor/kpi-dashboard"; import { KpiDashboard } from "@/components/monitor/kpi-dashboard";
@ -218,15 +219,15 @@ function MonitorPage() {
); );
const updatedIncidents = incidentId const updatedIncidents = incidentId
? incidents.map((i) => ? incidents.map((i) =>
i.id === incidentId i.id === incidentId
? { ? {
...i, ...i,
attachedAlertIds: i.attachedAlertIds.filter( attachedAlertIds: i.attachedAlertIds.filter(
(aid) => aid !== alertId, (aid) => aid !== alertId,
), ),
} }
: i, : i,
) )
: incidents; : incidents;
setAlerts(updatedAlerts); setAlerts(updatedAlerts);
@ -249,9 +250,10 @@ function MonitorPage() {
onChange={handleFileInputChange} onChange={handleFileInputChange}
className="hidden" className="hidden"
/> />
<header className="flex shrink-0 items-center justify-between border-b px-4 py-3"> <header className="flex shrink-0 items-center border-b px-4 py-3">
<h1 className="text-sm font-semibold">Alert Monitor</h1> <h1 className="text-sm font-semibold mr-auto">Alert Monitor</h1>
<Button onClick={handleLoadFile} disabled={isLoading} size="sm"> <ModeToggle />
<Button className="ml-2" onClick={handleLoadFile} disabled={isLoading}>
<FileUp className="mr-2 size-4" /> <FileUp className="mr-2 size-4" />
{isLoading ? "Loading..." : "Load Alerts JSON"} {isLoading ? "Loading..." : "Load Alerts JSON"}
</Button> </Button>