From b12eb0a038f9f802b369b311b20e15353ef4b9e7 Mon Sep 17 00:00:00 2001 From: asepharyana Date: Wed, 23 Sep 2026 23:46:22 +0700 Subject: [PATCH] fe(fe): surface moderation explainability in live feed Show confidence bar, flag chips, status dot, and error text per action in the Live Stream Audit Log; drop stale media comment on SkeletonHero. --- .../src/components/LiveModerationFeed.tsx | 80 ++++++++++++++++++- .../frontend/src/components/shared/states.tsx | 2 +- 2 files changed, 80 insertions(+), 2 deletions(-) diff --git a/services/frontend/src/components/LiveModerationFeed.tsx b/services/frontend/src/components/LiveModerationFeed.tsx index 206578a9..07b0bfb3 100644 --- a/services/frontend/src/components/LiveModerationFeed.tsx +++ b/services/frontend/src/components/LiveModerationFeed.tsx @@ -49,6 +49,15 @@ function severityTone( } } +function confidenceTone(confidence?: number | null) { + if (confidence == null) return null; + return confidence >= 0.75 + ? "bg-signal" + : confidence >= 0.5 + ? "bg-amber" + : "bg-vermilion"; +} + export function LiveModerationFeed({ actions, }: { @@ -115,8 +124,27 @@ export function LiveModerationFeed({ className="mod-feed-item hud-card animate-stagger flex items-start gap-3 p-3 transition-all" style={staggerDelay(i)} > - + {actionIcon(a.action_type)} + {a.status && ( + + )}
@@ -151,6 +179,56 @@ export function LiveModerationFeed({

)} + {(a.confidence != null || a.flags?.length) && ( +
+ {a.confidence != null && ( + + + conf + + + + + + {Math.round(a.confidence * 100)}% + + + )} + {a.flags && a.flags.length > 0 && ( + + {a.flags.slice(0, 2).map((flag) => ( + + {flag} + + ))} + {a.flags.length > 2 && ( + + +{a.flags.length - 2} + + )} + + )} + {a.error && ( + + {a.error} + + )} +
+ )} +
TARGET: diff --git a/services/frontend/src/components/shared/states.tsx b/services/frontend/src/components/shared/states.tsx index 53345a56..f1f61856 100644 --- a/services/frontend/src/components/shared/states.tsx +++ b/services/frontend/src/components/shared/states.tsx @@ -75,7 +75,7 @@ export function SkeletonRows({ ); } -/** Hero block placeholder (dashboard / media "now playing"). */ +/** Hero block placeholder (dashboard headline). */ export function SkeletonHero({ className }: { className?: string }) { return (