feat: admin panel — new triggers, member/vote stats, health checks
Backend: - /trigger-fetch-news, /trigger-fetch-votes, /trigger-member-trend-scores endpoints - Stats: total_members, house_count, senate_count, members_missing_chamber, total_votes, stanced_bills_total, stanced_bills_with_votes - API health: redis, smtp, pytrends tests added Frontend: - Fetch News, Fetch Votes, Member Trend Scores buttons in recurring tasks - Fetch Votes shows "needed" badge when stanced bills are missing votes - Stats table: member sync breakdown + vote/alignment coverage row - Health panel: Redis, SMTP, pytrends rows Authored by: Jack Levy
This commit is contained in:
@@ -380,6 +380,9 @@ export default function SettingsPage() {
|
||||
{ label: "Pending LLM analysis", value: stats.pending_llm, color: stats.pending_llm > 0 ? "text-amber-600 dark:text-amber-400" : "text-muted-foreground", icon: "🔄", action: stats.pending_llm > 0 ? "Resume Analysis" : undefined },
|
||||
{ label: "Briefs missing citations", value: stats.uncited_briefs, color: stats.uncited_briefs > 0 ? "text-amber-600 dark:text-amber-400" : "text-muted-foreground", icon: "⚠️", action: stats.uncited_briefs > 0 ? "Backfill Citations" : undefined },
|
||||
{ label: "Briefs with unlabeled points", value: stats.unlabeled_briefs, color: stats.unlabeled_briefs > 0 ? "text-amber-600 dark:text-amber-400" : "text-muted-foreground", icon: "🏷️", action: stats.unlabeled_briefs > 0 ? "Backfill Labels" : undefined },
|
||||
{ label: "Members synced", value: stats.total_members, color: "text-foreground", icon: "🏛️", note: `${stats.house_count} House · ${stats.senate_count} Senate${stats.members_missing_chamber > 0 ? ` · ⚠️ ${stats.members_missing_chamber} missing chamber` : ""}` },
|
||||
{ label: "Roll-call votes stored", value: stats.total_votes, color: "text-foreground", icon: "🗳️" },
|
||||
{ label: "Stanced bills with votes", value: stats.stanced_bills_with_votes, color: "text-foreground", icon: "⚖️", note: stats.stanced_bills_total > 0 ? `${stats.stanced_bills_with_votes} of ${stats.stanced_bills_total} stanced bills have vote data` : "No stanced bills yet", action: stats.stanced_bills_total > 0 && stats.stanced_bills_with_votes < stats.stanced_bills_total ? "Fetch Votes" : undefined },
|
||||
].map(({ label, value, color, icon, note, action }) => (
|
||||
<div key={label} className="flex items-center justify-between py-2.5 gap-3">
|
||||
<div className="flex items-center gap-2 min-w-0">
|
||||
@@ -688,6 +691,9 @@ export default function SettingsPage() {
|
||||
{ key: "newsapi", label: "NewsAPI.org" },
|
||||
{ key: "google_news", label: "Google News RSS" },
|
||||
{ key: "rep_lookup", label: "Rep Lookup (Nominatim + TIGERweb)" },
|
||||
{ key: "redis", label: "Redis" },
|
||||
{ key: "smtp", label: "SMTP (Email)" },
|
||||
{ key: "pytrends", label: "Google Trends (pytrends)" },
|
||||
].map(({ key, label }) => {
|
||||
const r = healthData[key];
|
||||
if (!r) return null;
|
||||
@@ -826,6 +832,29 @@ export default function SettingsPage() {
|
||||
fn: adminAPI.triggerTrendScores,
|
||||
status: "on-demand",
|
||||
},
|
||||
{
|
||||
key: "fetch-news",
|
||||
name: "Fetch News",
|
||||
description: "Pull recent news articles for all active bills from NewsAPI and Google News. Runs automatically every 6 hours.",
|
||||
fn: adminAPI.triggerFetchNews,
|
||||
status: "on-demand",
|
||||
},
|
||||
{
|
||||
key: "fetch-votes",
|
||||
name: "Fetch Votes",
|
||||
description: "Fetch roll-call votes for all bills you have stanced (Pocket Veto or Pocket Boost). Required for Alignment to show data. Re-fetches bills with new activity since the last run.",
|
||||
fn: adminAPI.triggerFetchVotes,
|
||||
status: stats ? (stats.stanced_bills_total > 0 && stats.stanced_bills_with_votes < stats.stanced_bills_total ? "needed" : "on-demand") : "on-demand",
|
||||
count: stats ? stats.stanced_bills_total - stats.stanced_bills_with_votes : undefined,
|
||||
countLabel: "stanced bills missing votes",
|
||||
},
|
||||
{
|
||||
key: "member-trends",
|
||||
name: "Member Trend Scores",
|
||||
description: "Calculate newsworthiness scores for legislators based on recent news coverage. Runs automatically nightly.",
|
||||
fn: adminAPI.triggerMemberTrendScores,
|
||||
status: "on-demand",
|
||||
},
|
||||
{
|
||||
key: "actions",
|
||||
name: "Fetch Bill Actions",
|
||||
|
||||
@@ -208,6 +208,10 @@ export interface ApiHealth {
|
||||
govinfo: ApiHealthResult;
|
||||
newsapi: ApiHealthResult;
|
||||
google_news: ApiHealthResult;
|
||||
rep_lookup: ApiHealthResult;
|
||||
redis: ApiHealthResult;
|
||||
smtp: ApiHealthResult;
|
||||
pytrends: ApiHealthResult;
|
||||
}
|
||||
|
||||
export interface AnalysisStats {
|
||||
@@ -224,6 +228,13 @@ export interface AnalysisStats {
|
||||
bills_missing_actions: number;
|
||||
unlabeled_briefs: number;
|
||||
remaining: number;
|
||||
total_members: number;
|
||||
house_count: number;
|
||||
senate_count: number;
|
||||
members_missing_chamber: number;
|
||||
total_votes: number;
|
||||
stanced_bills_total: number;
|
||||
stanced_bills_with_votes: number;
|
||||
}
|
||||
|
||||
export interface NotificationTestResult {
|
||||
@@ -277,6 +288,12 @@ export const adminAPI = {
|
||||
apiClient.post("/api/admin/trigger-member-sync").then((r) => r.data),
|
||||
triggerTrendScores: () =>
|
||||
apiClient.post("/api/admin/trigger-trend-scores").then((r) => r.data),
|
||||
triggerFetchNews: () =>
|
||||
apiClient.post("/api/admin/trigger-fetch-news").then((r) => r.data),
|
||||
triggerFetchVotes: () =>
|
||||
apiClient.post("/api/admin/trigger-fetch-votes").then((r) => r.data),
|
||||
triggerMemberTrendScores: () =>
|
||||
apiClient.post("/api/admin/trigger-member-trend-scores").then((r) => r.data),
|
||||
backfillSponsors: () =>
|
||||
apiClient.post("/api/admin/backfill-sponsors").then((r) => r.data),
|
||||
backfillCitations: () =>
|
||||
|
||||
Reference in New Issue
Block a user