feat: implement dynamic database connection service with MySQL driver and API schema endpoints
This commit is contained in:
@@ -1,59 +1,103 @@
|
||||
import React from 'react';
|
||||
import { Box, Paper, Typography } from '@mui/material';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { Box, Paper, Typography, CircularProgress } from '@mui/material';
|
||||
import DataGrid, {
|
||||
Column,
|
||||
Editing,
|
||||
Scrolling,
|
||||
Paging,
|
||||
FilterRow,
|
||||
HeaderFilter
|
||||
HeaderFilter,
|
||||
SearchPanel,
|
||||
GroupPanel,
|
||||
Export
|
||||
} from 'devextreme-react/data-grid';
|
||||
import { useAppStore } from '../store/useAppStore';
|
||||
import { SchemaService } from '../services/api';
|
||||
|
||||
const MainContent: React.FC = () => {
|
||||
const { activeDatabase } = useAppStore();
|
||||
const { activeTable, activeDatabase } = useAppStore();
|
||||
const [data, setData] = useState<any[]>([]);
|
||||
const [columns, setColumns] = useState<any[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
|
||||
// Mock data for initial UI
|
||||
const dummyData = [
|
||||
{ id: 1, name: 'Users', type: 'BASE TABLE', engine: 'InnoDB', rows: 1500, size: '256 KB' },
|
||||
{ id: 2, name: 'Products', type: 'BASE TABLE', engine: 'InnoDB', rows: 54200, size: '12 MB' },
|
||||
{ id: 3, name: 'Orders', type: 'BASE TABLE', engine: 'InnoDB', rows: 120400, size: '45 MB' },
|
||||
{ id: 4, name: 'Order_Items', type: 'BASE TABLE', engine: 'InnoDB', rows: 450000, size: '120 MB' },
|
||||
];
|
||||
useEffect(() => {
|
||||
const fetchTableData = async () => {
|
||||
if (!activeTable || !activeDatabase) return;
|
||||
|
||||
setLoading(true);
|
||||
try {
|
||||
// Fetch schema for columns
|
||||
const schemaRes = await SchemaService.getTableSchema(activeTable);
|
||||
const cols = schemaRes.data.map((col: any) => ({
|
||||
dataField: col.Field,
|
||||
caption: col.Field,
|
||||
dataType: mapSqlTypeToDxType(col.Type)
|
||||
}));
|
||||
setColumns(cols);
|
||||
|
||||
// Fetch actual data
|
||||
const dataRes = await SchemaService.getTableData(activeTable, activeDatabase);
|
||||
setData(dataRes.data);
|
||||
} catch (error) {
|
||||
console.error('Failed to fetch table data', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchTableData();
|
||||
}, [activeTable, activeDatabase]);
|
||||
|
||||
// Helper to map SQL types to DevExtreme types
|
||||
const mapSqlTypeToDxType = (sqlType: string) => {
|
||||
sqlType = sqlType.toLowerCase();
|
||||
if (sqlType.includes('int') || sqlType.includes('decimal') || sqlType.includes('float')) return 'number';
|
||||
if (sqlType.includes('date') || sqlType.includes('time')) return 'date';
|
||||
if (sqlType.includes('bool')) return 'boolean';
|
||||
return 'string';
|
||||
};
|
||||
|
||||
if (!activeTable) {
|
||||
return (
|
||||
<Box sx={{ flexGrow: 1, p: 3, display: 'flex', alignItems: 'center', justifyContent: 'center', bgcolor: 'background.default' }}>
|
||||
<Typography variant="h6" color="text.secondary">Select a table to view data</Typography>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Box sx={{ flexGrow: 1, p: 3, overflow: 'hidden', display: 'flex', flexDirection: 'column', gap: 2 }}>
|
||||
<Box>
|
||||
<Box sx={{ flexGrow: 1, p: 3, bgcolor: 'background.default', overflow: 'hidden' }}>
|
||||
<Box sx={{ mb: 2, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
|
||||
<Typography variant="h5" sx={{ fontWeight: 700 }}>
|
||||
{activeDatabase ? `Tables in ${activeDatabase}` : 'Welcome to Mariavel'}
|
||||
</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Manage your database tables with high-performance tools.
|
||||
{activeDatabase}.{activeTable}
|
||||
</Typography>
|
||||
</Box>
|
||||
|
||||
<Paper sx={{ flexGrow: 1, p: 0, overflow: 'hidden', borderRadius: 3 }}>
|
||||
<DataGrid
|
||||
dataSource={dummyData}
|
||||
keyExpr="id"
|
||||
showBorders={false}
|
||||
focusedRowEnabled={true}
|
||||
height="100%"
|
||||
width="100%"
|
||||
>
|
||||
<Paging enabled={false} />
|
||||
<Scrolling mode="virtual" />
|
||||
<FilterRow visible={true} />
|
||||
<HeaderFilter visible={true} />
|
||||
<Editing mode="cell" allowUpdating={true} allowDeleting={true} />
|
||||
|
||||
<Column dataField="id" width={50} />
|
||||
<Column dataField="name" caption="Table Name" />
|
||||
<Column dataField="type" />
|
||||
<Column dataField="engine" width={100} />
|
||||
<Column dataField="rows" dataType="number" format="fixedPoint" width={100} />
|
||||
<Column dataField="size" width={100} />
|
||||
</DataGrid>
|
||||
|
||||
<Paper sx={{ height: 'calc(100vh - 180px)', borderRadius: 2, overflow: 'hidden' }}>
|
||||
{loading ? (
|
||||
<Box sx={{ display: 'flex', height: '100%', alignItems: 'center', justifyContent: 'center' }}>
|
||||
<CircularProgress />
|
||||
</Box>
|
||||
) : (
|
||||
<DataGrid
|
||||
dataSource={data}
|
||||
showBorders={true}
|
||||
focusedRowEnabled={true}
|
||||
columnAutoWidth={true}
|
||||
allowColumnReordering={true}
|
||||
rowAlternationEnabled={true}
|
||||
height="100%"
|
||||
>
|
||||
<Scrolling mode="virtual" />
|
||||
<FilterRow visible={true} />
|
||||
<HeaderFilter visible={true} />
|
||||
<SearchPanel visible={true} width={240} placeholder="Search..." />
|
||||
<GroupPanel visible={true} />
|
||||
<Export enabled={true} allowExportSelectedData={true} />
|
||||
|
||||
{columns.map(col => (
|
||||
<Column key={col.dataField} {...col} />
|
||||
))}
|
||||
</DataGrid>
|
||||
)}
|
||||
</Paper>
|
||||
</Box>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user