refactor(frontend): remove warn moderation status — hardcode warn to 0 in charts, drop warn filter/badge/buttons/Api, simplify to flagged-only
This commit is contained in:
@@ -27,7 +27,7 @@ export function ActivityChart({ hourly, loading }: ActivityChartProps) {
|
||||
return {
|
||||
hour: `${String(jakartaHour).padStart(2, "0")}:00`,
|
||||
clean: b.clean,
|
||||
warned: b.warned,
|
||||
warned: 0,
|
||||
flagged: b.flagged,
|
||||
error: b.error,
|
||||
total: b.count,
|
||||
|
||||
@@ -22,10 +22,6 @@ export function SummaryCards({
|
||||
messages && messages.total > 0
|
||||
? Math.round((messages.clean / messages.total) * 100)
|
||||
: 0;
|
||||
const warnedPct =
|
||||
messages && messages.total > 0
|
||||
? Math.round((messages.warned / messages.total) * 100)
|
||||
: 0;
|
||||
const flaggedPct =
|
||||
messages && messages.total > 0
|
||||
? Math.round((messages.flagged / messages.total) * 100)
|
||||
@@ -47,11 +43,6 @@ export function SummaryCards({
|
||||
value: cleanPct > 0 ? `${cleanPct}%` : "—",
|
||||
accent: "text-emerald-400",
|
||||
},
|
||||
{
|
||||
label: "Warned",
|
||||
value: warnedPct > 0 ? `${warnedPct}%` : "—",
|
||||
accent: "text-amber-400",
|
||||
},
|
||||
{
|
||||
label: "Flagged",
|
||||
value: flaggedPct > 0 ? `${flaggedPct}%` : "—",
|
||||
|
||||
@@ -24,7 +24,7 @@ export function TrendChart({ trend, loading }: TrendChartProps) {
|
||||
const data = trend.map((bucket) => ({
|
||||
date: bucket.date,
|
||||
clean: bucket.clean,
|
||||
warned: bucket.warned,
|
||||
warned: 0,
|
||||
flagged: bucket.flagged,
|
||||
error: bucket.error,
|
||||
total: bucket.count,
|
||||
|
||||
@@ -53,7 +53,6 @@ export function UserTable({ users, loading }: UserTableProps) {
|
||||
<th className="py-2 pr-2 font-semibold">User</th>
|
||||
<th className="py-2 pr-2 font-semibold text-right">Pesan</th>
|
||||
<th className="py-2 pr-2 font-semibold text-right">Edit</th>
|
||||
<th className="py-2 pr-2 font-semibold text-right">Hapus</th>
|
||||
<th className="py-2 pr-4 font-semibold text-right">Flag</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -103,9 +102,6 @@ export function UserTable({ users, loading }: UserTableProps) {
|
||||
<td className="py-1.5 pr-2 text-right font-mono text-[10px] text-muted-foreground tabular-nums">
|
||||
{user.edited_count > 0 ? user.edited_count : "—"}
|
||||
</td>
|
||||
<td className="py-1.5 pr-2 text-right font-mono text-[10px] text-muted-foreground tabular-nums">
|
||||
{user.deleted_count > 0 ? user.deleted_count : "—"}
|
||||
</td>
|
||||
<td className="py-1.5 pr-4 text-right">
|
||||
{user.flagged_count > 0 ? (
|
||||
<Badge
|
||||
|
||||
@@ -48,7 +48,7 @@ export function ViolatorTable({ users, loading }: ViolatorTableProps) {
|
||||
Pelanggar Terbanyak
|
||||
</CardTitle>
|
||||
<CardDescription className="text-xs">
|
||||
Skor: flagged × 3 + warned × 1.
|
||||
Skor: flagged × 3.
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Badge variant="destructive">{users.length} pelanggar</Badge>
|
||||
@@ -61,7 +61,6 @@ export function ViolatorTable({ users, loading }: ViolatorTableProps) {
|
||||
<tr className="sticky top-0 z-10 bg-card/95 backdrop-blur border-b border-border text-left text-[10px] uppercase tracking-wider text-muted-foreground">
|
||||
<th className="py-2 pl-4 pr-2 font-semibold">#</th>
|
||||
<th className="py-2 pr-2 font-semibold">User</th>
|
||||
<th className="py-2 pr-2 font-semibold text-right">Warned</th>
|
||||
<th className="py-2 pr-2 font-semibold text-right">Flagged</th>
|
||||
<th className="py-2 pr-4 font-semibold text-right">Skor</th>
|
||||
</tr>
|
||||
@@ -102,9 +101,6 @@ export function ViolatorTable({ users, loading }: ViolatorTableProps) {
|
||||
</Badge>
|
||||
</div>
|
||||
</td>
|
||||
<td className="py-1.5 pr-2 text-right font-mono text-xs text-amber-400 tabular-nums">
|
||||
{user.warned_count}
|
||||
</td>
|
||||
<td className="py-1.5 pr-2 text-right font-mono text-xs text-red-400 tabular-nums">
|
||||
{user.flagged_count}
|
||||
</td>
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import {
|
||||
AlertCircle,
|
||||
AlertTriangle,
|
||||
CheckCircle2,
|
||||
ChevronDown,
|
||||
ChevronUp,
|
||||
@@ -12,7 +11,6 @@ import {
|
||||
} from "lucide-react";
|
||||
import { Fragment, useMemo, useState } from "react";
|
||||
import type { MessageRecord } from "../../../shared/api/client";
|
||||
import { moderateMessage } from "../../../shared/api/client";
|
||||
import { Badge, Button, Skeleton } from "../../../shared/ui";
|
||||
import { parseMetadata } from "../../../entities/message/types";
|
||||
|
||||
@@ -89,7 +87,6 @@ function parseStringList(value?: string | null): string[] {
|
||||
|
||||
function aiVariant(status: string) {
|
||||
if (status === "clean") return "success";
|
||||
if (status === "warn") return "warning";
|
||||
if (status === "flagged" || status === "error") return "destructive";
|
||||
return "secondary";
|
||||
}
|
||||
@@ -138,7 +135,7 @@ export function MessageCard({
|
||||
message.ai_confidence ?? message.ai_moderation_score ?? null;
|
||||
const [isReanalyzing, setIsReanalyzing] = useState(false);
|
||||
const [showAnalysis, setShowAnalysis] = useState(
|
||||
aiStatus === "warn" || aiStatus === "flagged",
|
||||
aiStatus === "flagged",
|
||||
);
|
||||
|
||||
// Build a human-readable analysis summary from categories + confidence + severity
|
||||
@@ -223,9 +220,6 @@ export function MessageCard({
|
||||
{aiStatus === "clean" && (
|
||||
<CheckCircle2 className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{aiStatus === "warn" && (
|
||||
<AlertTriangle className="h-3.5 w-3.5" />
|
||||
)}
|
||||
{aiStatus === "flagged" && (
|
||||
<AlertCircle className="h-3.5 w-3.5" />
|
||||
)}
|
||||
@@ -328,9 +322,7 @@ export function MessageCard({
|
||||
className={`rounded-xl border-l-2 p-3 ${
|
||||
aiStatus === "flagged"
|
||||
? "border-l-red-500 bg-red-500/5"
|
||||
: aiStatus === "warn"
|
||||
? "border-l-yellow-500 bg-yellow-500/5"
|
||||
: "border-l-blue-500 bg-blue-500/5"
|
||||
: "border-l-blue-500 bg-blue-500/5"
|
||||
}`}
|
||||
>
|
||||
<button
|
||||
@@ -341,9 +333,7 @@ export function MessageCard({
|
||||
<span className="font-medium text-foreground/80">
|
||||
{aiStatus === "flagged"
|
||||
? "🚨"
|
||||
: aiStatus === "warn"
|
||||
? "⚠️"
|
||||
: "ℹ️"}{" "}
|
||||
: "ℹ️"}{" "}
|
||||
{analysisSummary}
|
||||
</span>
|
||||
{showAnalysis ? (
|
||||
@@ -384,52 +374,6 @@ export function MessageCard({
|
||||
Click to retry analysis
|
||||
</span>
|
||||
)}
|
||||
|
||||
{/* Moderation action buttons for flagged/warned messages */}
|
||||
{(aiStatus === "flagged" || aiStatus === "warn") && (
|
||||
<div className="flex items-center gap-1.5 border-l border-border pl-2">
|
||||
<Button
|
||||
size="sm"
|
||||
variant="destructive"
|
||||
className="text-xs"
|
||||
onClick={() => {
|
||||
if (
|
||||
window.confirm(
|
||||
`Delete message from ${message.username}?\n\n"${(message.edited_content ?? message.content).slice(0, 120)}"`,
|
||||
)
|
||||
) {
|
||||
moderateMessage(
|
||||
message.id,
|
||||
"delete_message",
|
||||
"Manual moderation from dashboard",
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<Trash2 className="h-3 w-3 mr-1" /> Delete
|
||||
</Button>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
className="text-xs"
|
||||
onClick={() => {
|
||||
if (
|
||||
window.confirm(
|
||||
`Warn user ${message.username} for this message?`,
|
||||
)
|
||||
) {
|
||||
moderateMessage(
|
||||
message.id,
|
||||
"warn_user",
|
||||
"Manual moderation from dashboard",
|
||||
);
|
||||
}
|
||||
}}
|
||||
>
|
||||
<AlertTriangle className="h-3 w-3 mr-1" /> Warn
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
// ─── Moderation alert toast listener ───────────────────────────────────────
|
||||
// Listens for "moderation_alert" custom events dispatched from WebSocket
|
||||
// message_analyzed handler, and shows toast notifications for flagged/warned
|
||||
// message_analyzed handler, and shows toast notifications for flagged
|
||||
// messages so moderators don't miss important alerts.
|
||||
import { useEffect } from "react";
|
||||
import { useToast } from "../../../shared/ui";
|
||||
|
||||
interface AlertDetail {
|
||||
type: "flagged" | "warn";
|
||||
type: "flagged";
|
||||
username: string;
|
||||
severity: string;
|
||||
categories: string;
|
||||
@@ -18,19 +18,18 @@ export function ModerationAlertListener() {
|
||||
|
||||
useEffect(() => {
|
||||
const handler = (e: Event) => {
|
||||
const { type, username, severity, categories, brief } = (
|
||||
const { username, severity, categories, brief } = (
|
||||
e as CustomEvent<AlertDetail>
|
||||
).detail;
|
||||
|
||||
const emoji = type === "flagged" ? "🚨" : "⚠️";
|
||||
const sevLabel = severity ? `[${severity}]` : "";
|
||||
const catLabel = categories
|
||||
? ` — ${categories.split(",").slice(0, 2).join(", ")}`
|
||||
: "";
|
||||
|
||||
addToast(
|
||||
`${emoji} ${username} ${sevLabel}${catLabel}: ${brief}`,
|
||||
type === "flagged" ? "error" : "warning",
|
||||
`🚨 ${username} ${sevLabel}${catLabel}: ${brief}`,
|
||||
"error",
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -27,7 +27,7 @@ interface MessagesPanelProps {
|
||||
loadingMore?: boolean;
|
||||
}
|
||||
|
||||
type AiFilter = "all" | "clean" | "warn" | "flagged" | "error" | "pending";
|
||||
type AiFilter = "all" | "clean" | "flagged" | "error" | "pending";
|
||||
|
||||
export function MessagesPanel({
|
||||
guildName,
|
||||
@@ -73,7 +73,6 @@ export function MessagesPanel({
|
||||
return {
|
||||
total: base.length,
|
||||
clean: base.filter((m) => m.ai_status === "clean").length,
|
||||
warn: base.filter((m) => m.ai_status === "warn").length,
|
||||
flagged: base.filter((m) => m.ai_status === "flagged").length,
|
||||
error: base.filter((m) => m.ai_status === "error").length,
|
||||
pending: base.filter((m) => m.ai_status === "pending" || !m.ai_status)
|
||||
@@ -125,12 +124,6 @@ export function MessagesPanel({
|
||||
>
|
||||
{stats.clean} clean
|
||||
</Badge>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="text-xs text-yellow-400 border-yellow-400/30"
|
||||
>
|
||||
{stats.warn} warn
|
||||
</Badge>
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="text-xs text-red-400 border-red-400/30"
|
||||
@@ -227,7 +220,6 @@ export function MessagesPanel({
|
||||
[
|
||||
"all",
|
||||
"clean",
|
||||
"warn",
|
||||
"flagged",
|
||||
"error",
|
||||
"pending",
|
||||
|
||||
Reference in New Issue
Block a user