"use client"; import { Bell, BellOff, BellRing, Check, Trash2, Webhook } from "lucide-react"; import Link from "next/link"; import { useSearchParams } from "next/navigation"; import { useEffect, useMemo, useState } from "react"; import { COUNTRIES, EVENT_TYPES, eventGroupOf } from "@websensor/core/client"; import { LiveDot } from "@/components/live-feed"; import { useMounted } from "@/components/theme"; import { Chip, Empty, Flag, Panel, Score, SkeletonRows } from "@/components/ui"; import type { Alert, AlertRule, LiveEvent, Notification } from "@/lib/api"; import { CHANNEL_KEYS, GROUP_LABELS, relTime, typeLabel, utcDateTime } from "@/lib/format"; import { ownerFetch } from "@/lib/owner"; import { useLive } from "@/lib/use-live"; function matches(rule: AlertRule, e: LiveEvent): boolean { if (rule.importance_min !== undefined && e.importance < rule.importance_min) return false; if (rule.signal_min !== undefined && (e.signal ?? e.importance) < rule.signal_min) return false; if (rule.silent_only && !e.silent) return false; if (rule.first_party_only && e.firstParty === false) return false; if (rule.confirmed_only && e.evidence !== "CONFIRMED" && e.clusterState !== "confirmed") return false; if (rule.event_types?.length && !rule.event_types.includes(e.type)) return false; if (rule.groups?.length && !rule.groups.includes(e.group ?? eventGroupOf(e.type))) return false; if (rule.categories?.length && !rule.categories.some((c) => e.categories.includes(c))) return false; if (rule.countries?.length && !(e.country && rule.countries.includes(e.country.toUpperCase()))) return false; if (rule.entities?.length && !e.entities.some((x) => rule.entities!.includes(x.id))) return false; if (rule.sources?.length && !rule.sources.includes(e.source?.id)) return false; if (rule.keywords?.length) { const hay = `${e.title} ${e.summary}`.toLowerCase(); if (!rule.keywords.some((k) => hay.includes(k.toLowerCase()))) return false; } return true; } interface Form { name: string; importance_min: number; signal_min: number; silent_only: boolean; first_party_only: boolean; confirmed_only: boolean; event_types: string[]; groups: string[]; categories: string[]; countries: string[]; entities: string; sources: string; keywords: string; channel: "web" | "webhook"; webhook_url: string; webhook_secret: string; } const EMPTY: Form = { name: "", importance_min: 0, signal_min: 60, silent_only: false, first_party_only: false, confirmed_only: false, event_types: [], groups: [], categories: [], countries: [], entities: "", sources: "", keywords: "", channel: "web", webhook_url: "", webhook_secret: "" }; const PRESETS: { label: string; form: Partial