feat: implement dynamic database management via MySQL driver and API controllers

This commit is contained in:
Ümit Tunç
2026-04-24 12:52:01 +03:00
parent 9fe07a1985
commit 23f8eeb560
8 changed files with 164 additions and 33 deletions
+67 -17
View File
@@ -196,29 +196,63 @@ const MainContent: React.FC = () => {
setDbTab(newValue);
};
const DatabaseOverview = ({ database }: { database: string }) => {
const TechnicalOverview = ({ database, table }: { database: string, table: string | null }) => {
const [meta, setMeta] = useState<any>(null);
const [loadingMeta, setLoadingMeta] = useState(true);
const [truncating, setTruncating] = useState(false);
const fetchMeta = useCallback(async () => {
setLoadingMeta(true);
try {
const res = table
? await SchemaService.getTableMetadata(database, table)
: await SchemaService.getDatabaseMetadata(database);
setMeta(res.data);
} catch (e) {
console.error(e);
} finally {
setLoadingMeta(false);
}
}, [database, table]);
useEffect(() => {
const fetchMeta = async () => {
setLoadingMeta(true);
try {
const res = await SchemaService.getDatabaseMetadata(database);
setMeta(res.data);
} catch (e) {
console.error(e);
} finally {
setLoadingMeta(false);
}
};
fetchMeta();
}, [database]);
}, [fetchMeta]);
const handleTruncate = async () => {
if (!table || !window.confirm(`Are you sure you want to truncate table "${table}"? This will delete all data!`)) return;
setTruncating(true);
try {
await SchemaService.truncateTable(table);
setErrorInfo({
open: true,
title: 'Success',
message: `Table "${table}" has been truncated.`
});
fetchMeta();
} catch (error: any) {
setErrorInfo({
open: true,
title: 'Truncate Error',
message: error.response?.data?.error || error.message
});
} finally {
setTruncating(false);
}
};
if (loadingMeta) return <Box sx={{ display: 'flex', justifyContent: 'center', p: 8 }}><CircularProgress /></Box>;
if (!meta) return <Alert severity="error">Could not load metadata</Alert>;
const stats = [
const stats = table ? [
{ label: 'Engine', value: meta.engine, icon: <Terminal /> },
{ label: 'Rows', value: meta.rows, icon: <TableChart /> },
{ label: 'Collation', value: meta.collation, icon: <CleaningServices /> },
{ label: 'Data Size', value: `${(meta.data_length / 1024 / 1024).toFixed(2)} MB`, icon: <Save /> },
{ label: 'Index Size', value: `${(meta.index_length / 1024 / 1024).toFixed(2)} MB`, icon: <History /> },
{ label: 'Created', value: meta.create_time, icon: <Info /> },
] : [
{ label: 'Character Set', value: meta.charset, icon: <History /> },
{ label: 'Collation', value: meta.collation, icon: <CleaningServices /> },
{ label: 'Tables', value: meta.table_count, icon: <TableChart /> },
@@ -228,7 +262,23 @@ const MainContent: React.FC = () => {
return (
<Box sx={{ p: 1 }}>
<Typography variant="h5" sx={{ fontWeight: 800, mb: 4, letterSpacing: -0.5 }}>Technical Specifications: {database}</Typography>
<Box sx={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', mb: 4 }}>
<Typography variant="h5" sx={{ fontWeight: 800, letterSpacing: -0.5 }}>
Technical Specifications: {table ? `${database}.${table}` : database}
</Typography>
{table && (
<Button
variant="outlined"
color="error"
startIcon={truncating ? <CircularProgress size={16} color="inherit" /> : <CleaningServices />}
onClick={handleTruncate}
disabled={truncating}
sx={{ borderRadius: 2, textTransform: 'none', fontWeight: 700 }}
>
Truncate Table
</Button>
)}
</Box>
<Box sx={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fill, minmax(240px, 1fr))', gap: 3 }}>
{stats.map((stat, i) => (
<Paper key={i} sx={{
@@ -247,7 +297,7 @@ const MainContent: React.FC = () => {
<Typography variant="caption" sx={{ fontWeight: 700, color: 'text.secondary', textTransform: 'uppercase', letterSpacing: 1 }}>{stat.label}</Typography>
<Box sx={{ color: 'primary.main', opacity: 0.5 }}>{stat.icon}</Box>
</Box>
<Typography variant="h5" sx={{ fontWeight: 800 }}>{stat.value}</Typography>
<Typography variant="h5" sx={{ fontWeight: 800 }}>{stat.value || 'N/A'}</Typography>
</Paper>
))}
</Box>
@@ -399,7 +449,7 @@ const MainContent: React.FC = () => {
{dbTab === 'export' && <TransferContent mode="export" />}
{/* Technical Info View */}
{dbTab === 'info' && <DatabaseOverview database={activeDatabase} />}
{dbTab === 'info' && <TechnicalOverview database={activeDatabase} table={activeTable} />}
{/* Custom Alert (Snackbar) */}
<Snackbar open={errorInfo.open} autoHideDuration={10000} onClose={handleCloseError} anchorOrigin={{ vertical: 'bottom', horizontal: 'right' }}>