From 5c0744d5d1df239b343421791e7cf5dde577aec8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=9Cmit=20Tun=C3=A7?= Date: Fri, 24 Apr 2026 12:59:55 +0300 Subject: [PATCH] feat: implement backend database management API and frontend service integration --- .../Http/Controllers/Api/SchemaController.php | 11 +++ backend/app/Services/DatabaseService.php | 8 ++ backend/routes/api.php | 1 + frontend/src/components/MainContent.tsx | 83 ++++++++++++++++++- frontend/src/services/api.ts | 1 + 5 files changed, 101 insertions(+), 3 deletions(-) diff --git a/backend/app/Http/Controllers/Api/SchemaController.php b/backend/app/Http/Controllers/Api/SchemaController.php index 9b4a9c4..65dc5cd 100644 --- a/backend/app/Http/Controllers/Api/SchemaController.php +++ b/backend/app/Http/Controllers/Api/SchemaController.php @@ -176,4 +176,15 @@ class SchemaController extends Controller return Response::json(['error' => $e->getMessage()], 400); } } + + public function tablesMetadata(Request $request, $database) + { + try { + $request->merge(['database' => $database]); + $this->initializeDriver($request); + return Response::json($this->databaseService->getTablesMetadata($database)); + } catch (\Exception $e) { + return Response::json(['error' => $e->getMessage()], 400); + } + } } diff --git a/backend/app/Services/DatabaseService.php b/backend/app/Services/DatabaseService.php index e49eb6b..935fcfb 100644 --- a/backend/app/Services/DatabaseService.php +++ b/backend/app/Services/DatabaseService.php @@ -138,4 +138,12 @@ class DatabaseService { return $this->getDriver()->truncateTable($table); } + + /** + * Get metadata for all tables in a database. + */ + public function getTablesMetadata(string $database): array + { + return $this->getDriver()->getTablesMetadata($database); + } } diff --git a/backend/routes/api.php b/backend/routes/api.php index 1a0dea1..a23df24 100644 --- a/backend/routes/api.php +++ b/backend/routes/api.php @@ -12,6 +12,7 @@ Route::prefix('schema')->group(function () { Route::get('/databases', [SchemaController::class, 'databases']); Route::get('/tables/{database}', [SchemaController::class, 'tables']); Route::get('/metadata/{database}', [SchemaController::class, 'metadata']); + Route::get('/metadata/{database}/tables', [SchemaController::class, 'tablesMetadata']); Route::get('/metadata/{database}/{table}', [SchemaController::class, 'tableMetadata']); Route::post('/truncate/{table}', [SchemaController::class, 'truncate']); Route::get('/{table}', [SchemaController::class, 'schema']); diff --git a/frontend/src/components/MainContent.tsx b/frontend/src/components/MainContent.tsx index 561ac22..552aeba 100644 --- a/frontend/src/components/MainContent.tsx +++ b/frontend/src/components/MainContent.tsx @@ -325,6 +325,83 @@ const MainContent: React.FC = () => { ); }; + const DatabaseTablesGrid = ({ database }: { database: string }) => { + const [tableRows, setTableRows] = useState([]); + const [loading, setLoading] = useState(true); + const { setActiveTable } = useAppStore(); + + useEffect(() => { + const fetchTablesMeta = async () => { + setLoading(true); + try { + const res = await SchemaService.getTablesMetadata(database); + setTableRows(res.data.map((r: any, i: number) => ({ id: r.name || i, ...r }))); + } catch (e) { + console.error(e); + } finally { + setLoading(false); + } + }; + fetchTablesMeta(); + }, [database]); + + const columns: GridColDef[] = [ + { + field: 'name', + headerName: 'Table Name', + flex: 1, + minWidth: 200, + renderCell: (params) => ( + + ) + }, + { field: 'engine', headerName: 'Engine', width: 120 }, + { field: 'rows', headerName: 'Rows', type: 'number', width: 120 }, + { + field: 'data_length', + headerName: 'Data Size', + width: 130, + valueFormatter: (value) => `${(Number(value) / 1024 / 1024).toFixed(2)} MB` + }, + { + field: 'index_length', + headerName: 'Index Size', + width: 130, + valueFormatter: (value) => `${(Number(value) / 1024 / 1024).toFixed(2)} MB` + }, + { field: 'collation', headerName: 'Collation', width: 180 }, + { field: 'comment', headerName: 'Comment', flex: 1, minWidth: 150 }, + ]; + + return ( + + + + ); + }; + return ( {/* Database Navigation Tabs */} @@ -365,9 +442,9 @@ const MainContent: React.FC = () => { {dbTab === 'tables' && ( {!activeTable ? ( - - - Select a table from the explorer to view data + + Database Tables: {activeDatabase} + ) : ( <> diff --git a/frontend/src/services/api.ts b/frontend/src/services/api.ts index c8a16d4..16d1fe2 100644 --- a/frontend/src/services/api.ts +++ b/frontend/src/services/api.ts @@ -26,6 +26,7 @@ export const SchemaService = { getDatabases: () => api.get('/schema/databases'), getTables: (db: string) => api.get(`/schema/tables/${db}`, { params: { database: db } }), getDatabaseMetadata: (db: string) => api.get(`/schema/metadata/${db}`, { params: { database: db } }), + getTablesMetadata: (db: string) => api.get(`/schema/metadata/${db}/tables`, { params: { database: db } }), getTableMetadata: (db: string, table: string) => api.get(`/schema/metadata/${db}/${table}`, { params: { database: db } }), getTableSchema: (table: string, database?: string) => api.get(`/schema/${table}`, { params: { database } }), getTableData: (table: string, params: any) => api.get(`/schema/${table}/data`, { params }),