diff --git a/frontend/src/pages/InternalAdminPage.tsx b/frontend/src/pages/InternalAdminPage.tsx index 9a68681..74172d5 100644 --- a/frontend/src/pages/InternalAdminPage.tsx +++ b/frontend/src/pages/InternalAdminPage.tsx @@ -42,10 +42,12 @@ import { type InternalAdminContact, type InternalAdminOverview, type InternalAdminUser, + getDatabaseStats, + type DatabaseStats, } from '@/services/api'; import { useAuthStore } from '@/stores/authStore'; -type AdminTab = 'overview' | 'users' | 'tools' | 'ratings' | 'contacts' | 'system'; +type AdminTab = 'overview' | 'users' | 'tools' | 'ratings' | 'contacts' | 'system' | 'database'; type Lang = 'ar' | 'en'; const TRANSLATIONS: Record> = { @@ -75,6 +77,7 @@ const TRANSLATIONS: Record> = { tabRatings: 'Ratings & Reviews', tabContacts: 'Inbox', tabSystem: 'System Health', + tabDatabase: 'Database', // Overview cards totalUsers: 'Total users', filesProcessed: 'Files processed', @@ -216,6 +219,7 @@ const TRANSLATIONS: Record> = { tabRatings: 'التقييمات والمراجعات', tabContacts: 'صندوق الوارد', tabSystem: 'صحة النظام', + tabDatabase: 'قاعدة البيانات', // Overview cards totalUsers: 'إجمالي المستخدمين', filesProcessed: 'الملفات المعالجة', @@ -396,6 +400,9 @@ export default function InternalAdminPage() { // Plan interest state const [planInterest, setPlanInterest] = useState(null); + // Database state + const [databaseStats, setDatabaseStats] = useState(null); + // Language const [lang, setLang] = useState(() => (localStorage.getItem('admin-lang') as Lang) ?? 'en'); const isRtl = lang === 'ar'; @@ -423,6 +430,7 @@ export default function InternalAdminPage() { { key: 'ratings', label: t('tabRatings'), icon: Star }, { key: 'contacts', label: t('tabContacts'), icon: Inbox }, { key: 'system', label: t('tabSystem'), icon: ShieldCheck }, + { key: 'database', label: t('tabDatabase'), icon: Database }, ]; useEffect(() => { @@ -486,6 +494,11 @@ export default function InternalAdminPage() { setPlanInterest(pi); break; } + case 'database': { + const dbStats = await getDatabaseStats(); + setDatabaseStats(dbStats); + break; + } } } catch (e) { const msg = e instanceof Error ? e.message : t('loadError'); @@ -1398,6 +1411,76 @@ export default function InternalAdminPage() { ); } + // ====================== DATABASE TAB ====================== + + function renderDatabaseTab() { + if (!databaseStats) return null; + + return ( + <> +
+
+
+
+

Database Type

+

{databaseStats.database_type}

+
+ +
+
+
+
+
+

Total Tables

+

{databaseStats.table_count}

+
+ +
+
+
+
+
+

Total Rows

+

+ {databaseStats.tables.reduce((sum, t) => sum + t.row_count, 0).toLocaleString()} +

+
+ +
+
+
+ +
+

Tables

+
+ + + + + + {databaseStats.tables[0]?.total_size_kb !== undefined && ( + + )} + + + + {databaseStats.tables.map((table) => ( + + + + {table.total_size_kb !== undefined && ( + + )} + + ))} + +
Table NameRow CountSize (KB)
{table.table_name}{table.row_count.toLocaleString()}{table.total_size_kb.toLocaleString()} KB
+
+
+ + ); + } + // ====================== MAIN RENDER ====================== return ( @@ -1566,6 +1649,7 @@ export default function InternalAdminPage() { {activeTab === 'ratings' && renderRatingsTab()} {activeTab === 'contacts' && renderContactsTab()} {activeTab === 'system' && renderSystemTab()} + {activeTab === 'database' && renderDatabaseTab()} )} diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index fdc42b2..a7e4091 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -876,6 +876,18 @@ export interface AdminSystemHealth { tasks_last_1h: number; failures_last_1h: number; database_size_mb: number; + database_type: string; +} + +export interface DatabaseStats { + database_type: string; + tables: Array<{ + table_name: string; + row_count: number; + total_size_kb?: number; + data_size_kb?: number; + }>; + table_count: number; } export async function getAdminRatingsDetail(page = 1, perPage = 20, tool = ''): Promise { @@ -905,6 +917,11 @@ export async function getAdminSystemHealth(): Promise { return response.data; } +export async function getDatabaseStats(): Promise { + const response = await api.get('/internal/admin/database-stats'); + return response.data; +} + // --- Account / Usage / API Keys --- export interface UsageSummary {