/** * AI Moderation Plugin — Admin Components * * Exports widgets and pages for the admin UI. */ import { Switch } from "@cloudflare/kumo"; import { ShieldCheck, CheckCircle, WarningCircle, FloppyDisk, CircleNotch, Trash, PencilSimple, Plus, TestTube, X, } from "@phosphor-icons/react"; import type { PluginAdminExports } from "emdash"; import { apiFetch, isRecord, parseApiResponse } from "emdash/plugin-utils"; import * as React from "react"; import type { Category } from "./categories.js"; const API_BASE = "/_emdash/api/plugins/ai-moderation"; // ============================================================================= // Dashboard Widget // ============================================================================= interface PluginStatus { enabled: boolean; categoryCount: number; autoApproveClean: boolean; } function StatusWidget() { const [status, setStatus] = React.useState(null); const [isLoading, setIsLoading] = React.useState(true); React.useEffect(() => { async function fetchStatus() { try { const response = await apiFetch(`${API_BASE}/status`); if (!response.ok) return; const data = await parseApiResponse(response); setStatus(data); } catch { // Widget is non-critical } finally { setIsLoading(false); } } void fetchStatus(); }, []); if (isLoading) { return (
); } return (
AI Moderation Active
{status?.categoryCount ?? 0} active categories
Auto-approve clean {status?.autoApproveClean ? "Yes" : "No"}
Configure moderation
); } // ============================================================================= // Category Edit Dialog // ============================================================================= interface CategoryDialogProps { category: Category | null; onSave: (category: Category) => void; onClose: () => void; } function CategoryDialog({ category, onSave, onClose }: CategoryDialogProps) { const [form, setForm] = React.useState( category ?? { id: "", name: "", description: "", action: "hold", builtin: false, }, ); const isEditing = !!category; return (

{isEditing ? "Edit Category" : "Add Category"}

) => setForm({ ...form, id: e.target.value }) } disabled={isEditing} placeholder="e.g. S10" className="w-full px-3 py-2 border rounded-md bg-background text-sm disabled:opacity-50" />
) => setForm({ ...form, name: e.target.value }) } placeholder="e.g. Self-Promotion" className="w-full px-3 py-2 border rounded-md bg-background text-sm" />