+
Import Content
+
+ Import posts, quips, or beacons from direct R2 links or CSV data.
+
+
+ {/* Author + Type */}
+
+
+
+ setAuthorId(e.target.value)}
+ className="w-full px-3 py-2 border border-warm-300 rounded-lg text-sm font-mono focus:ring-2 focus:ring-brand-500 focus:border-brand-500"
+ placeholder="UUID of the user who owns these posts"
+ />
+
+
+
+
+
+
+
+ {/* Input mode + flags */}
+
+
+
+
+
+
+
+
+
+
+
+ {/* Shared body (links mode) */}
+ {inputMode === 'links' && (
+
+
+ setSharedBody(e.target.value)}
+ className="w-full px-3 py-2 border border-warm-300 rounded-lg text-sm focus:ring-2 focus:ring-brand-500 focus:border-brand-500"
+ placeholder="Optional caption for all imported items"
+ />
+
+ )}
+
+ {/* Main input */}
+
+
+
+
+
+ {itemCount} item(s) detected
+
+
+ {/* Import button */}
+
+
+ {/* Result */}
+ {result && (
+
+ {result.error && !result.success ? (
+
+ ) : (
+
+
+
+ {result.message}
+
+
+ Success: {result.success} | Failures: {result.failures}
+
+
+ {result.errors?.length > 0 && (
+
+
Errors:
+ {result.errors.map((err: string, i: number) => (
+
• {err}
+ ))}
+
+ )}
+
+ {result.created?.length > 0 && (
+
+
+
Post IDs:
+
+
+
+ {result.created.slice(0, 20).map((id: string) => (
+
{id}
+ ))}
+ {result.created.length > 20 && (
+
...and {result.created.length - 20} more
+ )}
+
+
+ )}
+
+ )}
+
+ )}
+
+ );
+}
diff --git a/admin/src/components/Sidebar.tsx b/admin/src/components/Sidebar.tsx
index 4ec08e0..0efd65e 100644
--- a/admin/src/components/Sidebar.tsx
+++ b/admin/src/components/Sidebar.tsx
@@ -6,7 +6,7 @@ import { useAuth } from '@/lib/auth';
import { cn } from '@/lib/utils';
import {
LayoutDashboard, Users, FileText, Shield, Scale, Flag,
- Settings, Activity, LogOut, ChevronLeft, ChevronRight, Sliders, FolderTree, HardDrive, AtSign, Brain, ScrollText,
+ Settings, Activity, LogOut, ChevronLeft, ChevronRight, Sliders, FolderTree, HardDrive, AtSign, Brain, ScrollText, Wrench,
} from 'lucide-react';
import { useState } from 'react';
@@ -22,6 +22,7 @@ const navItems = [
{ href: '/usernames', label: 'Usernames', icon: AtSign },
{ href: '/ai-moderation', label: 'AI Moderation', icon: Brain },
{ href: '/ai-audit-log', label: 'AI Audit Log', icon: ScrollText },
+ { href: '/content-tools', label: 'Content Tools', icon: Wrench },
{ href: '/storage', label: 'Storage', icon: HardDrive },
{ href: '/system', label: 'System Health', icon: Activity },
{ href: '/settings', label: 'Settings', icon: Settings },
diff --git a/admin/src/lib/api.ts b/admin/src/lib/api.ts
index 4d92cc0..15bb535 100644
--- a/admin/src/lib/api.ts
+++ b/admin/src/lib/api.ts
@@ -375,6 +375,48 @@ class ApiClient {
async exportAITrainingData() {
return this.request