feat: implement database management service layer and frontend SQL import/export utility
This commit is contained in:
@@ -38,22 +38,23 @@ const TransferContent: React.FC<TransferContentProps> = ({ mode = 'both' }) => {
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
|
||||
const handleExport = async () => {
|
||||
const handleExport = async (onlyStructure: boolean = false) => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
setSuccess(null);
|
||||
try {
|
||||
const response = await SchemaService.exportDatabase(activeDatabase || undefined, activeTable || undefined);
|
||||
const response = await SchemaService.exportDatabase(activeDatabase || undefined, activeTable || undefined, undefined, onlyStructure);
|
||||
const url = window.URL.createObjectURL(new Blob([response.data]));
|
||||
const link = document.createElement('a');
|
||||
link.href = url;
|
||||
const suffix = onlyStructure ? '-schema' : '';
|
||||
const filename = activeTable
|
||||
? `${activeTable}-${new Date().toISOString().split('T')[0]}.sql`
|
||||
: `backup-${activeDatabase || 'all'}-${new Date().toISOString().split('T')[0]}.sql`;
|
||||
? `${activeTable}${suffix}-${new Date().toISOString().split('T')[0]}.sql`
|
||||
: `backup-${activeDatabase || 'all'}${suffix}-${new Date().toISOString().split('T')[0]}.sql`;
|
||||
link.setAttribute('download', filename);
|
||||
document.body.appendChild(link);
|
||||
link.click();
|
||||
setSuccess(`${activeTable ? 'Table' : 'Database'} exported successfully!`);
|
||||
setSuccess(`${activeTable ? 'Table' : 'Database'} ${onlyStructure ? 'structure' : ''} exported successfully!`);
|
||||
} catch (err: any) {
|
||||
setError('Export failed: ' + (err.response?.data?.error || err.message));
|
||||
} finally {
|
||||
@@ -138,22 +139,35 @@ const TransferContent: React.FC<TransferContentProps> = ({ mode = 'both' }) => {
|
||||
<TableCell sx={{ py: 3 }}>
|
||||
<Typography variant="h6" sx={{ fontWeight: 700, mb: 0.5 }}>Export {activeTable ? 'Table' : 'Database'}</Typography>
|
||||
<Typography variant="body2" color="text.secondary">
|
||||
Create a full backup of the current {activeTable ? 'table' : 'database'}: <br/>
|
||||
Create a backup of the current {activeTable ? 'table' : 'database'}: <br/>
|
||||
<Box component="span" sx={{ color: 'primary.main', fontWeight: 600 }}>
|
||||
{activeTable ? `${activeDatabase}.${activeTable}` : (activeDatabase || 'All Databases')}
|
||||
</Box>
|
||||
</Typography>
|
||||
</TableCell>
|
||||
<TableCell align="right" sx={{ py: 3 }}>
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<CloudDownload />}
|
||||
onClick={handleExport}
|
||||
disabled={loading}
|
||||
sx={{ borderRadius: 2, px: 3, py: 1, fontWeight: 700, minWidth: 160 }}
|
||||
>
|
||||
Start Export
|
||||
</Button>
|
||||
<Stack direction="row" spacing={1} justifyContent="flex-end">
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="primary"
|
||||
startIcon={<CloudDownload />}
|
||||
onClick={() => handleExport(true)}
|
||||
disabled={loading}
|
||||
sx={{ borderRadius: 2, px: 2, py: 1, fontWeight: 700 }}
|
||||
>
|
||||
Export Structure
|
||||
</Button>
|
||||
<Button
|
||||
variant="contained"
|
||||
color="primary"
|
||||
startIcon={<CloudDownload />}
|
||||
onClick={() => handleExport(false)}
|
||||
disabled={loading}
|
||||
sx={{ borderRadius: 2, px: 2, py: 1, fontWeight: 700 }}
|
||||
>
|
||||
Full Export
|
||||
</Button>
|
||||
</Stack>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
|
||||
@@ -39,10 +39,11 @@ export const SchemaService = {
|
||||
bulkAction: (data: { tables: string[], action: string, database: string }) => api.post('/schema/bulk-action', data),
|
||||
batchUpdate: (table: string, changes: any[]) => api.post(`/schema/${table}/batch-update`, { changes }),
|
||||
executeQuery: (query: string) => api.post('/schema/execute', { query }),
|
||||
exportDatabase: (database?: string, table?: string, filters?: any) => api.post('/schema/export', {
|
||||
exportDatabase: (database?: string, table?: string, filters?: any, structureOnly: boolean = false) => api.post('/schema/export', {
|
||||
database,
|
||||
table,
|
||||
filters: filters ? JSON.stringify(filters) : undefined
|
||||
filters: filters ? JSON.stringify(filters) : undefined,
|
||||
structureOnly
|
||||
}, { responseType: 'blob' }),
|
||||
importDatabase: (formData: FormData) => api.post('/schema/import', formData, {
|
||||
headers: { 'Content-Type': 'multipart/form-data' }
|
||||
|
||||
Reference in New Issue
Block a user