mirror of
https://github.com/johndoe6345789/postgres.git
synced 2026-04-24 13:55:00 +00:00
Refactor TableManagerTab and ColumnManagerTab to use ComponentTreeRenderer
Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
@@ -1,24 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import EditIcon from '@mui/icons-material/Edit';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
MenuItem,
|
||||
Paper,
|
||||
Select,
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableContainer,
|
||||
TableHead,
|
||||
TableRow,
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { getDataTypes, getFeatureById } from '@/utils/featureConfig';
|
||||
import { getComponentTree, getDataTypes, getFeatureById } from '@/utils/featureConfig';
|
||||
import ComponentTreeRenderer from '@/utils/ComponentTreeRenderer';
|
||||
import ColumnDialog from './ColumnDialog';
|
||||
|
||||
type ColumnManagerTabProps = {
|
||||
@@ -99,106 +83,38 @@ export default function ColumnManagerTab({
|
||||
setDialogState({ ...dialogState, open: false });
|
||||
};
|
||||
|
||||
const handleTableChange = (event: any) => {
|
||||
setSelectedTable(event.target.value);
|
||||
};
|
||||
|
||||
// Get component tree from features.json
|
||||
const tree = getComponentTree('ColumnManagerTab');
|
||||
|
||||
// Prepare data for the component tree
|
||||
const data = {
|
||||
feature,
|
||||
tables,
|
||||
selectedTable,
|
||||
tableSchema,
|
||||
canAdd,
|
||||
canModify,
|
||||
canDelete,
|
||||
};
|
||||
|
||||
// Define handlers for the component tree
|
||||
const handlers = {
|
||||
handleTableChange,
|
||||
openAddDialog: () => openDialog('add'),
|
||||
openModifyDialog: () => openDialog('modify'),
|
||||
openDropDialog: () => openDialog('drop'),
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
{feature?.name || 'Column Manager'}
|
||||
</Typography>
|
||||
|
||||
{feature?.description && (
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
{feature.description}
|
||||
</Typography>
|
||||
)}
|
||||
|
||||
<Paper sx={{ p: 2, mt: 2, mb: 2 }}>
|
||||
<Typography variant="subtitle1" gutterBottom>
|
||||
Select a table to manage its columns:
|
||||
</Typography>
|
||||
<Select
|
||||
fullWidth
|
||||
value={selectedTable}
|
||||
onChange={e => setSelectedTable(e.target.value)}
|
||||
displayEmpty
|
||||
>
|
||||
<MenuItem value="">
|
||||
<em>Select a table</em>
|
||||
</MenuItem>
|
||||
{tables.map(table => (
|
||||
<MenuItem key={table.table_name} value={table.table_name}>
|
||||
{table.table_name}
|
||||
</MenuItem>
|
||||
))}
|
||||
</Select>
|
||||
</Paper>
|
||||
|
||||
{selectedTable && (
|
||||
<>
|
||||
<Box sx={{ mb: 2 }}>
|
||||
{canAdd && (
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => openDialog('add')}
|
||||
sx={{ mr: 2 }}
|
||||
>
|
||||
Add Column
|
||||
</Button>
|
||||
)}
|
||||
{canModify && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
startIcon={<EditIcon />}
|
||||
onClick={() => openDialog('modify')}
|
||||
sx={{ mr: 2 }}
|
||||
>
|
||||
Modify Column
|
||||
</Button>
|
||||
)}
|
||||
{canDelete && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
startIcon={<DeleteIcon />}
|
||||
onClick={() => openDialog('drop')}
|
||||
>
|
||||
Drop Column
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
{tableSchema && (
|
||||
<Paper sx={{ mt: 2 }}>
|
||||
<Box sx={{ p: 2 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Current Columns for {selectedTable}
|
||||
</Typography>
|
||||
<TableContainer>
|
||||
<Table size="small">
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell><strong>Column Name</strong></TableCell>
|
||||
<TableCell><strong>Data Type</strong></TableCell>
|
||||
<TableCell><strong>Nullable</strong></TableCell>
|
||||
<TableCell><strong>Default</strong></TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{tableSchema.columns?.map((col: any) => (
|
||||
<TableRow key={col.column_name}>
|
||||
<TableCell>{col.column_name}</TableCell>
|
||||
<TableCell>{col.data_type}</TableCell>
|
||||
<TableCell>{col.is_nullable}</TableCell>
|
||||
<TableCell>{col.column_default || 'NULL'}</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Box>
|
||||
</Paper>
|
||||
)}
|
||||
</>
|
||||
{tree ? (
|
||||
<ComponentTreeRenderer tree={tree} data={data} handlers={handlers} />
|
||||
) : (
|
||||
<div>Error: Component tree not found</div>
|
||||
)}
|
||||
|
||||
<ColumnDialog
|
||||
|
||||
@@ -1,20 +1,8 @@
|
||||
'use client';
|
||||
|
||||
import AddIcon from '@mui/icons-material/Add';
|
||||
import DeleteIcon from '@mui/icons-material/Delete';
|
||||
import TableChartIcon from '@mui/icons-material/TableChart';
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
List,
|
||||
ListItem,
|
||||
ListItemIcon,
|
||||
ListItemText,
|
||||
Paper,
|
||||
Typography,
|
||||
} from '@mui/material';
|
||||
import { useState } from 'react';
|
||||
import { getDataTypes, getFeatureById } from '@/utils/featureConfig';
|
||||
import { getComponentTree, getDataTypes, getFeatureById } from '@/utils/featureConfig';
|
||||
import ComponentTreeRenderer from '@/utils/ComponentTreeRenderer';
|
||||
import CreateTableDialog from './CreateTableDialog';
|
||||
import DropTableDialog from './DropTableDialog';
|
||||
|
||||
@@ -40,64 +28,31 @@ export default function TableManagerTab({
|
||||
const canCreate = feature?.ui.actions.includes('create');
|
||||
const canDelete = feature?.ui.actions.includes('delete');
|
||||
|
||||
// Get component tree from features.json
|
||||
const tree = getComponentTree('TableManagerTab');
|
||||
|
||||
// Prepare data for the component tree
|
||||
const data = {
|
||||
feature,
|
||||
tables,
|
||||
canCreate,
|
||||
canDelete,
|
||||
};
|
||||
|
||||
// Define handlers for the component tree
|
||||
const handlers = {
|
||||
openCreateDialog: () => setOpenCreateDialog(true),
|
||||
openDropDialog: () => setOpenDropDialog(true),
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Typography variant="h5" gutterBottom>
|
||||
{feature?.name || 'Table Manager'}
|
||||
</Typography>
|
||||
|
||||
{feature?.description && (
|
||||
<Typography variant="body2" color="text.secondary" gutterBottom>
|
||||
{feature.description}
|
||||
</Typography>
|
||||
{tree ? (
|
||||
<ComponentTreeRenderer tree={tree} data={data} handlers={handlers} />
|
||||
) : (
|
||||
<div>Error: Component tree not found</div>
|
||||
)}
|
||||
|
||||
<Box sx={{ mt: 2, mb: 2 }}>
|
||||
{canCreate && (
|
||||
<Button
|
||||
variant="contained"
|
||||
startIcon={<AddIcon />}
|
||||
onClick={() => setOpenCreateDialog(true)}
|
||||
sx={{ mr: 2 }}
|
||||
>
|
||||
Create Table
|
||||
</Button>
|
||||
)}
|
||||
{canDelete && (
|
||||
<Button
|
||||
variant="outlined"
|
||||
color="error"
|
||||
startIcon={<DeleteIcon />}
|
||||
onClick={() => setOpenDropDialog(true)}
|
||||
>
|
||||
Drop Table
|
||||
</Button>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Paper sx={{ mt: 2 }}>
|
||||
<Box sx={{ p: 2 }}>
|
||||
<Typography variant="h6" gutterBottom>
|
||||
Existing Tables
|
||||
</Typography>
|
||||
<List>
|
||||
{tables.map(table => (
|
||||
<ListItem key={table.table_name}>
|
||||
<ListItemIcon>
|
||||
<TableChartIcon />
|
||||
</ListItemIcon>
|
||||
<ListItemText primary={table.table_name} />
|
||||
</ListItem>
|
||||
))}
|
||||
{tables.length === 0 && (
|
||||
<ListItem>
|
||||
<ListItemText primary="No tables found" />
|
||||
</ListItem>
|
||||
)}
|
||||
</List>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
||||
<CreateTableDialog
|
||||
open={openCreateDialog}
|
||||
onClose={() => setOpenCreateDialog(false)}
|
||||
|
||||
@@ -1474,6 +1474,493 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"ConstraintManagerTab": {
|
||||
"component": "Box",
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "h5",
|
||||
"gutterBottom": true,
|
||||
"text": "{{feature.name}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Typography",
|
||||
"condition": "feature.description",
|
||||
"props": {
|
||||
"variant": "body2",
|
||||
"color": "text.secondary",
|
||||
"gutterBottom": true,
|
||||
"text": "{{feature.description}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Paper",
|
||||
"props": {
|
||||
"sx": { "p": 2, "mb": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "FormControl",
|
||||
"props": {
|
||||
"fullWidth": true
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "InputLabel",
|
||||
"props": {
|
||||
"text": "Select Table"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Select",
|
||||
"props": {
|
||||
"value": "{{selectedTable}}",
|
||||
"label": "Select Table",
|
||||
"onChange": "handleTableChange"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "MenuItem",
|
||||
"forEach": "tables",
|
||||
"props": {
|
||||
"value": "{{table.table_name}}",
|
||||
"text": "{{table.table_name}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "Box",
|
||||
"condition": "selectedTable && canAdd",
|
||||
"props": {
|
||||
"sx": { "mb": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Button",
|
||||
"condition": "canAdd",
|
||||
"props": {
|
||||
"variant": "contained",
|
||||
"startIcon": "Add",
|
||||
"onClick": "openAddDialog",
|
||||
"text": "Add Constraint"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "Paper",
|
||||
"condition": "constraints && constraints.length > 0",
|
||||
"props": {
|
||||
"sx": { "mt": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "TableContainer",
|
||||
"children": [
|
||||
{
|
||||
"component": "Table",
|
||||
"props": {
|
||||
"size": "small"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "TableHead",
|
||||
"children": [
|
||||
{
|
||||
"component": "TableRow",
|
||||
"children": [
|
||||
{
|
||||
"component": "TableCell",
|
||||
"props": {
|
||||
"text": "Constraint Name"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "TableCell",
|
||||
"props": {
|
||||
"text": "Type"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "TableCell",
|
||||
"props": {
|
||||
"text": "Definition"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "TableCell",
|
||||
"condition": "canDelete",
|
||||
"props": {
|
||||
"text": "Actions"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "TableBody",
|
||||
"children": [
|
||||
{
|
||||
"component": "TableRow",
|
||||
"forEach": "constraints",
|
||||
"children": [
|
||||
{
|
||||
"component": "TableCell",
|
||||
"props": {
|
||||
"text": "{{constraint.constraint_name}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "TableCell",
|
||||
"props": {
|
||||
"text": "{{constraint.constraint_type}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "TableCell",
|
||||
"props": {
|
||||
"text": "{{constraint.definition || '-'}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "TableCell",
|
||||
"condition": "canDelete",
|
||||
"children": [
|
||||
{
|
||||
"component": "IconButton",
|
||||
"props": {
|
||||
"size": "small",
|
||||
"color": "error",
|
||||
"onClick": "handleDeleteConstraint"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"text": "🗑️"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"IndexManagerTab": {
|
||||
"component": "Box",
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "h5",
|
||||
"gutterBottom": true,
|
||||
"text": "{{feature.name}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Typography",
|
||||
"condition": "feature.description",
|
||||
"props": {
|
||||
"variant": "body2",
|
||||
"color": "text.secondary",
|
||||
"gutterBottom": true,
|
||||
"text": "{{feature.description}}"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Paper",
|
||||
"props": {
|
||||
"sx": { "p": 2, "mb": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "FormControl",
|
||||
"props": {
|
||||
"fullWidth": true
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "InputLabel",
|
||||
"props": {
|
||||
"text": "Select Table"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Select",
|
||||
"props": {
|
||||
"value": "{{selectedTable}}",
|
||||
"label": "Select Table",
|
||||
"onChange": "handleTableChange"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "MenuItem",
|
||||
"forEach": "tables",
|
||||
"props": {
|
||||
"value": "{{table.table_name}}",
|
||||
"text": "{{table.table_name}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "Box",
|
||||
"condition": "selectedTable",
|
||||
"props": {
|
||||
"sx": { "mb": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Button",
|
||||
"props": {
|
||||
"variant": "contained",
|
||||
"startIcon": "Add",
|
||||
"onClick": "openCreateDialog",
|
||||
"text": "Create Index"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "Paper",
|
||||
"condition": "indexes && indexes.length > 0",
|
||||
"props": {
|
||||
"sx": { "mt": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Box",
|
||||
"props": {
|
||||
"sx": { "p": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "h6",
|
||||
"gutterBottom": true,
|
||||
"text": "Existing Indexes"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "List",
|
||||
"children": [
|
||||
{
|
||||
"component": "ListItem",
|
||||
"forEach": "indexes",
|
||||
"children": [
|
||||
{
|
||||
"component": "ListItemIcon",
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"text": "⚡"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "ListItemText",
|
||||
"props": {
|
||||
"primary": "{{index.indexname}}",
|
||||
"secondary": "{{index.indexdef}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"QueryBuilderTab": {
|
||||
"component": "Box",
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "h5",
|
||||
"gutterBottom": true,
|
||||
"text": "Query Builder"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "body2",
|
||||
"color": "text.secondary",
|
||||
"gutterBottom": true,
|
||||
"text": "Build and execute SELECT queries visually"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Paper",
|
||||
"props": {
|
||||
"sx": { "p": 2, "mb": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "FormControl",
|
||||
"props": {
|
||||
"fullWidth": true,
|
||||
"sx": { "mb": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "InputLabel",
|
||||
"props": {
|
||||
"text": "Select Table"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Select",
|
||||
"props": {
|
||||
"value": "{{selectedTable}}",
|
||||
"label": "Select Table",
|
||||
"onChange": "handleTableChange"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "MenuItem",
|
||||
"forEach": "tables",
|
||||
"props": {
|
||||
"value": "{{table.table_name}}",
|
||||
"text": "{{table.table_name}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "Box",
|
||||
"condition": "selectedTable",
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "subtitle2",
|
||||
"gutterBottom": true,
|
||||
"text": "Select Columns"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Box",
|
||||
"props": {
|
||||
"sx": { "display": "flex", "flexWrap": "wrap", "gap": 1, "mb": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Chip",
|
||||
"forEach": "availableColumns",
|
||||
"props": {
|
||||
"label": "{{column}}",
|
||||
"onClick": "handleColumnToggle",
|
||||
"color": "{{selectedColumns.includes(column) ? 'primary' : 'default'}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "Box",
|
||||
"props": {
|
||||
"sx": { "mt": 2, "display": "flex", "gap": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Button",
|
||||
"props": {
|
||||
"variant": "contained",
|
||||
"startIcon": "PlayArrow",
|
||||
"onClick": "handleExecuteQuery",
|
||||
"disabled": "{{!selectedTable || selectedColumns.length === 0}}",
|
||||
"text": "Execute Query"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Button",
|
||||
"props": {
|
||||
"variant": "outlined",
|
||||
"onClick": "handleReset",
|
||||
"text": "Reset"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "Paper",
|
||||
"condition": "generatedQuery",
|
||||
"props": {
|
||||
"sx": { "p": 2, "mb": 2, "backgroundColor": "#f5f5f5" }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "subtitle2",
|
||||
"gutterBottom": true,
|
||||
"text": "Generated SQL"
|
||||
}
|
||||
},
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "body2",
|
||||
"sx": { "fontFamily": "monospace", "whiteSpace": "pre-wrap" },
|
||||
"text": "{{generatedQuery}}"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"component": "Box",
|
||||
"condition": "result",
|
||||
"props": {
|
||||
"sx": { "mt": 2 }
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"component": "Typography",
|
||||
"props": {
|
||||
"variant": "h6",
|
||||
"gutterBottom": true,
|
||||
"text": "Query Results ({{result.rows?.length || 0}} rows)"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"componentProps": {
|
||||
|
||||
Reference in New Issue
Block a user