'use client'; import { useState, useEffect } from 'react'; import { inventoryApi } from '@/lib/api'; import PageShell from '@/components/PageShell'; import StatCard from '@/components/StatCard'; import { Shield, ShieldAlert, UserPlus, User, Trash2, Tag, Plus, AlertTriangle, LogOut, HardDrive, Download, RotateCcw, FileText, Upload, Brain, Globe, Edit2, Server, Wifi, WifiOff, Clock, History, Database, Layers, X, ChevronDown } from 'lucide-react'; import { toast } from 'react-hot-toast'; import { cn } from '@/lib/utils'; export default function AdminPage() { const [users, setUsers] = useState([]); const [categories, setCategories] = useState([]); const [loading, setLoading] = useState(true); // LDAP Config State const [ldapConfig, setLdapConfig] = useState({ ldap_enabled: false, server_uri: 'ldap://192.168.84.107:3890', base_dn: 'dc=example,dc=com', user_template: 'cn={username},ou=people,dc=example,dc=com', groups_dn: 'ou=groups', use_tls: false, role_mappings: [] }); const [testingLdap, setTestingLdap] = useState(false); // Edit States const [editingUser, setEditingUser] = useState(null); const [editUserForm, setEditUserForm] = useState({ username: '', password: '', role: 'user' }); const [editingCategory, setEditingCategory] = useState(null); const [editCatForm, setEditCatForm] = useState({ name: '', description: '' }); // DB Management State const [backups, setBackups] = useState([]); const [dbStats, setDbStats] = useState({ backup_count: 0, total_size_bytes: 0 }); const [dbSettings, setDbSettings] = useState({ retention_count: 10, schedule_hour: 3, schedule_freq_days: 1 }); const [isBackingUp, setIsBackingUp] = useState(false); const [isImporting, setIsImporting] = useState(false); // AI Prompt State const [aiPrompt, setAiPrompt] = useState(""); const [isSavingPrompt, setIsSavingPrompt] = useState(false); useEffect(() => { loadData(); }, []); const loadData = async () => { setLoading(true); try { const [u, c, l, b, s, st] = await Promise.all([ inventoryApi.getUsers(), inventoryApi.getCategories(), inventoryApi.getLdapConfig(), inventoryApi.getDbBackups(), inventoryApi.getDbStats(), inventoryApi.getDbSettings() ]); setUsers(u); setCategories(c); if (l && l.server_uri) setLdapConfig(l); setBackups(b); setDbStats(s); setDbSettings(st); const p = await inventoryApi.getAiPrompt(); setAiPrompt(p.value); } catch (err: any) { console.error(err); toast.error("Failed to load admin data"); } finally { setLoading(false); } }; const handleAddUser = async () => { const name = prompt("Enter new username:"); if (!name) return; const pwd = prompt("Enter password for " + name + ":"); if (!pwd) return; try { await inventoryApi.createUser({ username: name, password: pwd, role: 'user' }); toast.success("User created successfully"); loadData(); } catch (err: any) { toast.error("Failed to create user"); } }; const handleDeleteUser = async (id: number, username: string) => { if (username === 'Admin') return; if (!confirm(`Delete user ${username}?`)) return; try { await inventoryApi.deleteUser(id); toast.success("User removed"); loadData(); } catch (err: any) { toast.error("Delete failed"); } }; const handleAddCategory = async () => { const name = prompt("New category name:"); if (!name) return; const desc = prompt("Description (optional):"); try { await inventoryApi.createCategory({ name, description: desc }); toast.success("Category added"); loadData(); } catch (err: any) { toast.error("Failed to add category"); } }; const handleUpdateCategorySubmit = async () => { if (!editingCategory) return; try { await inventoryApi.updateCategory(editingCategory.id, editCatForm); toast.success("Category updated"); setEditingCategory(null); loadData(); } catch (err: any) { toast.error("Update failed"); } }; const handleDeleteCategory = async (id: number, name: string) => { if (!confirm(`Delete category ${name}?`)) return; try { await inventoryApi.deleteCategory(id); toast.success("Category removed"); loadData(); } catch (err: any) { toast.error(err.response?.data?.detail || "Delete failed"); } }; const handleUpdateUserSubmit = async () => { if (!editingUser) return; try { const payload: any = { username: editUserForm.username, role: editUserForm.role }; if (editUserForm.password) payload.password = editUserForm.password; await inventoryApi.updateUser(editingUser.id, payload); toast.success("User updated successfully"); setEditingUser(null); loadData(); } catch (err: any) { toast.error("Update failed"); } }; const handleLogout = () => { import('@/lib/auth').then(m => m.clearAuth()); window.location.href = '/login'; }; const handleCreateBackup = async () => { setIsBackingUp(true); try { await inventoryApi.triggerBackup(); toast.success("Snapshot created successfully"); loadData(); } catch (err: any) { toast.error("Backup failed"); } finally { setIsBackingUp(false); } }; const handleRestore = async (filename: string) => { if (!confirm(`DANGEROUS: Restore database from ${filename}? Current data will be replaced. A rollback snapshot will be created automatically.`)) return; const loadingToast = toast.loading("Restoring database..."); try { await inventoryApi.restoreDatabase(filename); toast.success("Database restored! Reloading system...", { id: loadingToast }); setTimeout(() => window.location.reload(), 2000); } catch (err: any) { toast.error("Restore failed", { id: loadingToast }); } }; const handleUpdateDbSettings = async (newSettings: any) => { try { await inventoryApi.updateDbSettings(newSettings); toast.success("System policy updated"); setDbSettings(newSettings); } catch (err: any) { toast.error("Failed to update settings"); } }; const handleUpdatePrompt = async () => { setIsSavingPrompt(true); try { await inventoryApi.updateAiPrompt(aiPrompt); toast.success("AI Extraction Prompt updated"); } catch (err: any) { toast.error("Failed to update AI prompt"); } finally { setIsSavingPrompt(false); } }; const handleExportDb = async () => { try { const blob = await inventoryApi.exportDb(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `inventory_backup_${new Date().toISOString().split('T')[0]}.db`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); toast.success("Database exported successfully"); } catch (err: any) { toast.error("Export failed"); } }; const handleImportDb = async (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (!file) return; if (!confirm("DANGEROUS: You are about to REPLACE the entire database with this file. All current data will be lost. Proceed?")) { e.target.value = ''; return; } setIsImporting(true); const formData = new FormData(); formData.append('file', file); const loadingToast = toast.loading("Importing database..."); try { await inventoryApi.importDb(formData); toast.success("Database imported! Reloading system...", { id: loadingToast }); setTimeout(() => window.location.reload(), 2000); } catch (err: any) { toast.error("Import failed: " + (err.response?.data?.detail || err.message), { id: loadingToast }); } finally { setIsImporting(false); e.target.value = ''; } }; const handleUpdateLdap = async () => { setLoading(true); try { await inventoryApi.updateLdapConfig(ldapConfig); toast.success("Enterprise configuration updated"); } catch (err: any) { toast.error("Failed to update LDAP config"); } finally { setLoading(false); } }; const handleTestLdap = async () => { setTestingLdap(true); try { const res = await inventoryApi.testLdapConnection(ldapConfig); if (res.status === 'success') { toast.success(res.message || "LDAP Connection Successful!"); } else { toast.error(`LDAP Error: ${res.message || "Unknown error"}`); } } catch (err: any) { toast.error(`Connection failed: ${err.response?.data?.detail || err.message}`); } finally { setTestingLdap(false); } }; const formatSize = (bytes: number) => { if (bytes === 0) return '0 B'; const k = 1024; const sizes = ['B', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(1)) + ' ' + sizes[i]; }; return (

System Admin

Enterprise Control Center

{/* User Management Section */}

User Accounts

Manage local and network synchronized identities

{/* Local Users Group */}

Local Users

{loading ? (
Loading...
) : ( users.filter(u => (u.origin || 'local') === 'local').map(u => (
{u.role === 'admin' ? : }

{u.username}

{u.role}
{u.username !== 'Admin' && ( )}
)) )}
{/* enterprise Users Group */} {users.some(u => u.origin === 'ldap') && (

Enterprise Users (LDAP)

{users.filter(u => u.origin === 'ldap').map(u => (

{u.username}

Ldap Profile {u.role}
Cached Profile
))}
)}
{/* Enterprise Integration (LDAP) Section */}

Enterprise Integration

Configure directory services and single sign-on synchronization

Offline Only LDAP Active
setLdapConfig({ ...ldapConfig, server_uri: e.target.value })} className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3 pl-10 pr-4 text-sm text-white outline-none focus:border-indigo-500/30 transition-all font-mono" />
setLdapConfig({ ...ldapConfig, base_dn: e.target.value })} className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3 px-4 text-sm text-white outline-none focus:border-indigo-500/30 transition-all font-mono" />
setLdapConfig({ ...ldapConfig, user_template: e.target.value })} className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3 px-4 text-sm text-white outline-none focus:border-indigo-500/30 transition-all font-mono" />
setLdapConfig({ ...ldapConfig, groups_dn: e.target.value })} className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3 px-4 text-sm text-white outline-none focus:border-indigo-500/30 transition-all font-mono" />
m.role === 'admin')?.group || ''} onChange={(e) => { const newMappings = [...(ldapConfig.role_mappings || [])]; const idx = newMappings.findIndex((m: any) => m.role === 'admin'); if (idx >= 0) newMappings[idx] = { ...newMappings[idx], group: e.target.value }; else newMappings.push({ role: 'admin', group: e.target.value }); setLdapConfig({ ...ldapConfig, role_mappings: newMappings }); }} className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3 px-4 text-sm text-white outline-none focus:border-indigo-500/30 transition-all font-mono" />
m.role === 'user')?.group || ''} onChange={(e) => { const newMappings = [...(ldapConfig.role_mappings || [])]; const idx = newMappings.findIndex((m: any) => m.role === 'user'); if (idx >= 0) newMappings[idx] = { ...newMappings[idx], group: e.target.value }; else newMappings.push({ role: 'user', group: e.target.value }); setLdapConfig({ ...ldapConfig, role_mappings: newMappings }); }} className="w-full bg-slate-950 border border-slate-800 rounded-2xl py-3 px-4 text-sm text-white outline-none focus:border-indigo-500/30 transition-all font-mono" />

Synchronization Shield

Enabling LDAP will allow users from your network domain to log in using their enterprise credentials. Local account passwords will still function as a fail-safe backup.

LDAPS / TLS Encryption
{ldapConfig.use_tls && (
Ignore Certificate Validation (Self-signed)
)}
{/* AI Configuration Section */}

AI Vision Intelligence

Configure extraction prompts and heuristic models