Refactor TableManagerTab and ColumnManagerTab to use ComponentTreeRenderer

Co-authored-by: johndoe6345789 <224850594+johndoe6345789@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]
2026-01-08 14:02:38 +00:00
parent 4233aadc3f
commit afa910e6b8
3 changed files with 542 additions and 184 deletions

View File

@@ -1,24 +1,8 @@
'use client'; '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 { 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'; import ColumnDialog from './ColumnDialog';
type ColumnManagerTabProps = { type ColumnManagerTabProps = {
@@ -99,106 +83,38 @@ export default function ColumnManagerTab({
setDialogState({ ...dialogState, open: false }); 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 ( return (
<> <>
<Typography variant="h5" gutterBottom> {tree ? (
{feature?.name || 'Column Manager'} <ComponentTreeRenderer tree={tree} data={data} handlers={handlers} />
</Typography> ) : (
<div>Error: Component tree not found</div>
{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>
)}
</>
)} )}
<ColumnDialog <ColumnDialog

View File

@@ -1,20 +1,8 @@
'use client'; '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 { 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 CreateTableDialog from './CreateTableDialog';
import DropTableDialog from './DropTableDialog'; import DropTableDialog from './DropTableDialog';
@@ -40,64 +28,31 @@ export default function TableManagerTab({
const canCreate = feature?.ui.actions.includes('create'); const canCreate = feature?.ui.actions.includes('create');
const canDelete = feature?.ui.actions.includes('delete'); 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 ( return (
<> <>
<Typography variant="h5" gutterBottom> {tree ? (
{feature?.name || 'Table Manager'} <ComponentTreeRenderer tree={tree} data={data} handlers={handlers} />
</Typography> ) : (
<div>Error: Component tree not found</div>
{feature?.description && (
<Typography variant="body2" color="text.secondary" gutterBottom>
{feature.description}
</Typography>
)} )}
<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 <CreateTableDialog
open={openCreateDialog} open={openCreateDialog}
onClose={() => setOpenCreateDialog(false)} onClose={() => setOpenCreateDialog(false)}

View File

@@ -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": { "componentProps": {