Integrated keys and column type list get apis in the Add New Table Modal #12
|
|
@ -43,6 +43,7 @@ const AddTableModal = ({
|
|||
onAddTable,
|
||||
schemas = [],
|
||||
existingTables = [],
|
||||
position = 'center', // 'center' | 'bottom-right'
|
||||
tableTypes = [
|
||||
{ value: 'fact', label: 'Fact Table' },
|
||||
{ value: 'dimension', label: 'Dimension Table' },
|
||||
|
|
@ -78,6 +79,14 @@ const AddTableModal = ({
|
|||
const [keys, setKeys] = useState([]);
|
||||
const [relations, setRelations] = useState([]);
|
||||
|
||||
// Key types from API
|
||||
const [keyTypes, setKeyTypes] = useState([]);
|
||||
const [loadingKeyTypes, setLoadingKeyTypes] = useState(false);
|
||||
|
||||
// Column types from API
|
||||
const [columnTypesFromAPI, setColumnTypesFromAPI] = useState([]);
|
||||
const [loadingColumnTypes, setLoadingColumnTypes] = useState(false);
|
||||
|
||||
// Validation and UI state
|
||||
const [errors, setErrors] = useState({});
|
||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||
|
|
@ -90,9 +99,91 @@ const AddTableModal = ({
|
|||
useEffect(() => {
|
||||
if (open) {
|
||||
resetForm();
|
||||
fetchKeyTypes();
|
||||
fetchColumnTypes();
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
// Fetch key types from API
|
||||
const fetchKeyTypes = async () => {
|
||||
setLoadingKeyTypes(true);
|
||||
try {
|
||||
const response = await fetch('https://sandbox.kezel.io/api/qbt_table_key_type_list_get', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
token: "abdhsg",
|
||||
org: "sN05Pjv11qvH"
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (data.status === 200 && data.items) {
|
||||
setKeyTypes(data.items);
|
||||
} else {
|
||||
console.error('Failed to fetch key types:', data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching key types:', error);
|
||||
// Fallback to default key types
|
||||
setKeyTypes([
|
||||
{ kytp: 'PRIMARY', name: 'Primary' },
|
||||
{ kytp: 'FOREIGN', name: 'Foreign' },
|
||||
{ kytp: 'UNIQUE', name: 'Unique' }
|
||||
]);
|
||||
} finally {
|
||||
setLoadingKeyTypes(false);
|
||||
}
|
||||
};
|
||||
|
||||
// Fetch column types from API
|
||||
const fetchColumnTypes = async () => {
|
||||
setLoadingColumnTypes(true);
|
||||
try {
|
||||
const response = await fetch('https://sandbox.kezel.io/api/qbt_column_type_list_get', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
token: "abdhsg",
|
||||
org: "sN05Pjv11qvH"
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (data.status === 200 && data.items) {
|
||||
setColumnTypesFromAPI(data.items);
|
||||
} else {
|
||||
console.error('Failed to fetch column types:', data.message);
|
||||
// Fallback to default column types
|
||||
setColumnTypesFromAPI([
|
||||
{ cltp: 'VARCHAR', name: 'VARCHAR', description: 'Variable-length character string' },
|
||||
{ cltp: 'INT', name: 'INT', description: 'Standard integer value' },
|
||||
{ cltp: 'TEXT', name: 'TEXT', description: 'Variable-length character string for long text' },
|
||||
{ cltp: 'DATE', name: 'DATE', description: 'Date value' },
|
||||
{ cltp: 'TIMESTAMP', name: 'TIMESTAMP', description: 'Timestamp value' },
|
||||
{ cltp: 'BOOLEAN', name: 'BOOLEAN', description: 'Logical boolean value' }
|
||||
]);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error fetching column types:', error);
|
||||
// Fallback to default column types
|
||||
setColumnTypesFromAPI([
|
||||
{ cltp: 'VARCHAR', name: 'VARCHAR', description: 'Variable-length character string' },
|
||||
{ cltp: 'INT', name: 'INT', description: 'Standard integer value' },
|
||||
{ cltp: 'TEXT', name: 'TEXT', description: 'Variable-length character string for long text' },
|
||||
{ cltp: 'DATE', name: 'DATE', description: 'Date value' },
|
||||
{ cltp: 'TIMESTAMP', name: 'TIMESTAMP', description: 'Timestamp value' },
|
||||
{ cltp: 'BOOLEAN', name: 'BOOLEAN', description: 'Logical boolean value' }
|
||||
]);
|
||||
} finally {
|
||||
setLoadingColumnTypes(false);
|
||||
}
|
||||
};
|
||||
|
||||
const resetForm = () => {
|
||||
setFormData({
|
||||
name: '',
|
||||
|
|
@ -103,6 +194,10 @@ const AddTableModal = ({
|
|||
setColumns([]);
|
||||
setKeys([]);
|
||||
setRelations([]);
|
||||
setKeyTypes([]);
|
||||
setLoadingKeyTypes(false);
|
||||
setColumnTypesFromAPI([]);
|
||||
setLoadingColumnTypes(false);
|
||||
setErrors({});
|
||||
setIsSubmitting(false);
|
||||
setKeysViewMode('keys');
|
||||
|
|
@ -126,10 +221,11 @@ const AddTableModal = ({
|
|||
|
||||
// Column management
|
||||
const addColumn = () => {
|
||||
const defaultColumnType = columnTypesFromAPI.length > 0 ? columnTypesFromAPI[0].name : 'VARCHAR';
|
||||
const newColumn = {
|
||||
id: Date.now(),
|
||||
name: '',
|
||||
type: 'VARCHAR(255)',
|
||||
type: defaultColumnType,
|
||||
isPrimaryKey: false,
|
||||
isForeignKey: false,
|
||||
isNullable: true
|
||||
|
|
@ -177,11 +273,12 @@ const AddTableModal = ({
|
|||
|
||||
// Key management
|
||||
const addKey = () => {
|
||||
const defaultKeyType = keyTypes.length > 0 ? keyTypes[0].kytp : 'PRIMARY';
|
||||
const newKey = {
|
||||
id: Date.now(),
|
||||
name: '',
|
||||
columnIds: [], // Changed to array for multi-select
|
||||
keyType: 'PRIMARY', // PRIMARY, FOREIGN, UNIQUE
|
||||
keyType: defaultKeyType, // Use first available key type from API
|
||||
keyColumns: [] // Array of {columnId, sequence} objects
|
||||
};
|
||||
setKeys(prev => [...prev, newKey]);
|
||||
|
|
@ -406,12 +503,16 @@ const AddTableModal = ({
|
|||
columns: columns.map(col => ({
|
||||
name: col.name.trim(),
|
||||
data_type: col.type,
|
||||
is_primary_key: keys.some(key =>
|
||||
key.keyColumns?.some(kc => kc.columnId === col.id) && key.keyType === 'PRIMARY'
|
||||
),
|
||||
is_foreign_key: keys.some(key =>
|
||||
key.keyColumns?.some(kc => kc.columnId === col.id) && key.keyType === 'FOREIGN'
|
||||
),
|
||||
is_primary_key: keys.some(key => {
|
||||
const keyTypeObj = keyTypes.find(kt => kt.kytp === key.keyType);
|
||||
return key.keyColumns?.some(kc => kc.columnId === col.id) &&
|
||||
keyTypeObj?.name?.toLowerCase() === 'primary';
|
||||
}),
|
||||
is_foreign_key: keys.some(key => {
|
||||
const keyTypeObj = keyTypes.find(kt => kt.kytp === key.keyType);
|
||||
return key.keyColumns?.some(kc => kc.columnId === col.id) &&
|
||||
keyTypeObj?.name?.toLowerCase() === 'foreign';
|
||||
}),
|
||||
is_nullable: col.isNullable
|
||||
})),
|
||||
keys: keys.flatMap(key =>
|
||||
|
|
@ -444,14 +545,44 @@ const AddTableModal = ({
|
|||
}
|
||||
};
|
||||
|
||||
// Define positioning styles based on position prop
|
||||
const getDialogStyles = () => {
|
||||
if (position === 'bottom-right') {
|
||||
return {
|
||||
'& .MuiDialog-container': {
|
||||
justifyContent: 'flex-end',
|
||||
alignItems: 'flex-end',
|
||||
padding: '20px',
|
||||
},
|
||||
'& .MuiDialog-paper': {
|
||||
margin: 0,
|
||||
maxWidth: '780px', // Increased by 30% from 600px
|
||||
width: '780px', // Increased by 30% from 600px
|
||||
maxHeight: '80vh',
|
||||
minHeight: '60vh',
|
||||
borderRadius: '12px',
|
||||
boxShadow: '0 8px 32px rgba(0, 0, 0, 0.3)',
|
||||
}
|
||||
};
|
||||
}
|
||||
return {
|
||||
'& .MuiDialog-paper': {
|
||||
minHeight: '80vh',
|
||||
maxHeight: '90vh',
|
||||
maxWidth: '1170px', // Increased by 30% from 900px (lg breakpoint)
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
return (
|
||||
<Dialog
|
||||
open={open}
|
||||
onClose={onClose}
|
||||
maxWidth="lg"
|
||||
fullWidth
|
||||
maxWidth={position === 'bottom-right' ? false : 'lg'}
|
||||
fullWidth={position !== 'bottom-right'}
|
||||
sx={getDialogStyles()}
|
||||
PaperProps={{
|
||||
sx: {
|
||||
sx: position === 'bottom-right' ? {} : {
|
||||
minHeight: '80vh',
|
||||
maxHeight: '90vh'
|
||||
}
|
||||
|
|
@ -467,7 +598,7 @@ const AddTableModal = ({
|
|||
</IconButton>
|
||||
</DialogTitle>
|
||||
|
||||
<DialogContent dividers sx={{ p: 3 }}>
|
||||
<DialogContent dividers sx={{ p: position === 'bottom-right' ? 2 : 3 }}>
|
||||
{errors.submit && (
|
||||
<Alert severity="error" sx={{ mb: 3 }}>
|
||||
{errors.submit}
|
||||
|
|
@ -475,7 +606,7 @@ const AddTableModal = ({
|
|||
)}
|
||||
|
||||
{/* Basic Table Information */}
|
||||
<Paper elevation={1} sx={{ p: 3, mb: 3 }}>
|
||||
<Paper elevation={1} sx={{ p: position === 'bottom-right' ? 2 : 3, mb: position === 'bottom-right' ? 2 : 3 }}>
|
||||
<Typography variant="h6" gutterBottom color="primary">
|
||||
Table Information
|
||||
</Typography>
|
||||
|
|
@ -542,7 +673,7 @@ const AddTableModal = ({
|
|||
</Paper>
|
||||
|
||||
{/* Columns Section */}
|
||||
<Paper elevation={1} sx={{ p: 3, mb: 3 }}>
|
||||
<Paper elevation={1} sx={{ p: position === 'bottom-right' ? 2 : 3, mb: position === 'bottom-right' ? 2 : 3 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
||||
<Typography variant="h6" color="primary">
|
||||
Columns
|
||||
|
|
@ -587,12 +718,30 @@ const AddTableModal = ({
|
|||
value={column.type}
|
||||
onChange={(e) => updateColumn(column.id, 'type', e.target.value)}
|
||||
label="Data Type"
|
||||
disabled={loadingColumnTypes}
|
||||
>
|
||||
{columnTypes.map(type => (
|
||||
{loadingColumnTypes ? (
|
||||
<MenuItem value="">Loading...</MenuItem>
|
||||
) : columnTypesFromAPI.length > 0 ? (
|
||||
columnTypesFromAPI.map(type => (
|
||||
<MenuItem key={type.cltp} value={type.name} title={type.description}>
|
||||
<Box>
|
||||
<Typography variant="body2" component="div">
|
||||
{type.name}
|
||||
</Typography>
|
||||
<Typography variant="caption" color="text.secondary" component="div">
|
||||
{type.description}
|
||||
</Typography>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
))
|
||||
) : (
|
||||
columnTypes.map(type => (
|
||||
<MenuItem key={type} value={type}>
|
||||
{type}
|
||||
</MenuItem>
|
||||
))}
|
||||
))
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</Grid>
|
||||
|
|
@ -624,7 +773,7 @@ const AddTableModal = ({
|
|||
</Paper>
|
||||
|
||||
{/* Keys Section */}
|
||||
<Paper elevation={1} sx={{ p: 3, mb: 3 }}>
|
||||
<Paper elevation={1} sx={{ p: position === 'bottom-right' ? 2 : 3, mb: position === 'bottom-right' ? 2 : 3 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
||||
<Typography variant="h6" color="primary">
|
||||
<KeyIcon style={{ marginRight: '8px', verticalAlign: 'middle' }} />
|
||||
|
|
@ -711,10 +860,17 @@ const AddTableModal = ({
|
|||
updateKey(key.id, 'keyType', e.target.value);
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
disabled={loadingKeyTypes}
|
||||
>
|
||||
<MenuItem value="PRIMARY">Primary Key</MenuItem>
|
||||
<MenuItem value="FOREIGN">Foreign Key</MenuItem>
|
||||
<MenuItem value="UNIQUE">Unique Key</MenuItem>
|
||||
{loadingKeyTypes ? (
|
||||
<MenuItem value="">Loading...</MenuItem>
|
||||
) : (
|
||||
keyTypes.map((keyType) => (
|
||||
<MenuItem key={keyType.kytp} value={keyType.kytp}>
|
||||
{keyType.name} Key
|
||||
</MenuItem>
|
||||
))
|
||||
)}
|
||||
</Select>
|
||||
</FormControl>
|
||||
</TableCell>
|
||||
|
|
@ -854,7 +1010,7 @@ const AddTableModal = ({
|
|||
</Paper>
|
||||
|
||||
{/* Relations Section */}
|
||||
<Paper elevation={1} sx={{ p: 3 }}>
|
||||
<Paper elevation={1} sx={{ p: position === 'bottom-right' ? 2 : 3 }}>
|
||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
||||
<Typography variant="h6" color="primary">
|
||||
<LinkIcon style={{ marginRight: '8px', verticalAlign: 'middle' }} />
|
||||
|
|
@ -965,7 +1121,7 @@ const AddTableModal = ({
|
|||
</Paper>
|
||||
</DialogContent>
|
||||
|
||||
<DialogActions sx={{ p: 3, gap: 1 }}>
|
||||
<DialogActions sx={{ p: position === 'bottom-right' ? 2 : 3, gap: 1 }}>
|
||||
<Button onClick={onClose} variant="outlined">
|
||||
Cancel
|
||||
</Button>
|
||||
|
|
|
|||
|
|
@ -1755,6 +1755,7 @@ const ERDiagramCanvasContent = () => {
|
|||
onAddTable={handleAddTable}
|
||||
schemas={availableSchemas}
|
||||
existingTables={existingTables}
|
||||
position="bottom-right"
|
||||
/>
|
||||
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,65 @@
|
|||
// Test script to verify both API calls
|
||||
async function testKeyTypesAPI() {
|
||||
console.log('🔍 Testing Key Types API...');
|
||||
try {
|
||||
const response = await fetch('https://sandbox.kezel.io/api/qbt_table_key_type_list_get', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
token: "abdhsg",
|
||||
org: "sN05Pjv11qvH"
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (data.status === 200 && data.items) {
|
||||
console.log('✅ Key Types API call successful');
|
||||
console.log('Key types found:', data.items.length);
|
||||
data.items.forEach(item => {
|
||||
console.log(`- ${item.name} (ID: ${item.kytp})`);
|
||||
});
|
||||
} else {
|
||||
console.log('❌ Key Types API call failed:', data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error calling Key Types API:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function testColumnTypesAPI() {
|
||||
console.log('\n🔍 Testing Column Types API...');
|
||||
try {
|
||||
const response = await fetch('https://sandbox.kezel.io/api/qbt_column_type_list_get', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
body: JSON.stringify({
|
||||
token: "abdhsg",
|
||||
org: "sN05Pjv11qvH"
|
||||
})
|
||||
});
|
||||
const data = await response.json();
|
||||
|
||||
if (data.status === 200 && data.items) {
|
||||
console.log('✅ Column Types API call successful');
|
||||
console.log('Column types found:', data.items.length);
|
||||
data.items.forEach(item => {
|
||||
console.log(`- ${item.name} (ID: ${item.cltp}) - ${item.description}`);
|
||||
});
|
||||
} else {
|
||||
console.log('❌ Column Types API call failed:', data.message);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('❌ Error calling Column Types API:', error);
|
||||
}
|
||||
}
|
||||
|
||||
async function runTests() {
|
||||
await testKeyTypesAPI();
|
||||
await testColumnTypesAPI();
|
||||
}
|
||||
|
||||
runTests();
|
||||
Loading…
Reference in New Issue