Compare commits
No commits in common. "bf355dd40e3f6c80b58ce2e3462ce3330e478741" and "270407a187c469791aacf49db9b291a828b08c04" have entirely different histories.
bf355dd40e
...
270407a187
|
|
@ -43,7 +43,6 @@ const AddTableModal = ({
|
||||||
onAddTable,
|
onAddTable,
|
||||||
schemas = [],
|
schemas = [],
|
||||||
existingTables = [],
|
existingTables = [],
|
||||||
position = 'center', // 'center' | 'bottom-right'
|
|
||||||
tableTypes = [
|
tableTypes = [
|
||||||
{ value: 'fact', label: 'Fact Table' },
|
{ value: 'fact', label: 'Fact Table' },
|
||||||
{ value: 'dimension', label: 'Dimension Table' },
|
{ value: 'dimension', label: 'Dimension Table' },
|
||||||
|
|
@ -78,14 +77,6 @@ const AddTableModal = ({
|
||||||
const [columns, setColumns] = useState([]);
|
const [columns, setColumns] = useState([]);
|
||||||
const [keys, setKeys] = useState([]);
|
const [keys, setKeys] = useState([]);
|
||||||
const [relations, setRelations] = 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
|
// Validation and UI state
|
||||||
const [errors, setErrors] = useState({});
|
const [errors, setErrors] = useState({});
|
||||||
|
|
@ -99,91 +90,9 @@ const AddTableModal = ({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
resetForm();
|
resetForm();
|
||||||
fetchKeyTypes();
|
|
||||||
fetchColumnTypes();
|
|
||||||
}
|
}
|
||||||
}, [open]);
|
}, [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 = () => {
|
const resetForm = () => {
|
||||||
setFormData({
|
setFormData({
|
||||||
name: '',
|
name: '',
|
||||||
|
|
@ -194,10 +103,6 @@ const AddTableModal = ({
|
||||||
setColumns([]);
|
setColumns([]);
|
||||||
setKeys([]);
|
setKeys([]);
|
||||||
setRelations([]);
|
setRelations([]);
|
||||||
setKeyTypes([]);
|
|
||||||
setLoadingKeyTypes(false);
|
|
||||||
setColumnTypesFromAPI([]);
|
|
||||||
setLoadingColumnTypes(false);
|
|
||||||
setErrors({});
|
setErrors({});
|
||||||
setIsSubmitting(false);
|
setIsSubmitting(false);
|
||||||
setKeysViewMode('keys');
|
setKeysViewMode('keys');
|
||||||
|
|
@ -221,11 +126,10 @@ const AddTableModal = ({
|
||||||
|
|
||||||
// Column management
|
// Column management
|
||||||
const addColumn = () => {
|
const addColumn = () => {
|
||||||
const defaultColumnType = columnTypesFromAPI.length > 0 ? columnTypesFromAPI[0].name : 'VARCHAR';
|
|
||||||
const newColumn = {
|
const newColumn = {
|
||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
name: '',
|
name: '',
|
||||||
type: defaultColumnType,
|
type: 'VARCHAR(255)',
|
||||||
isPrimaryKey: false,
|
isPrimaryKey: false,
|
||||||
isForeignKey: false,
|
isForeignKey: false,
|
||||||
isNullable: true
|
isNullable: true
|
||||||
|
|
@ -273,12 +177,11 @@ const AddTableModal = ({
|
||||||
|
|
||||||
// Key management
|
// Key management
|
||||||
const addKey = () => {
|
const addKey = () => {
|
||||||
const defaultKeyType = keyTypes.length > 0 ? keyTypes[0].kytp : 'PRIMARY';
|
|
||||||
const newKey = {
|
const newKey = {
|
||||||
id: Date.now(),
|
id: Date.now(),
|
||||||
name: '',
|
name: '',
|
||||||
columnIds: [], // Changed to array for multi-select
|
columnIds: [], // Changed to array for multi-select
|
||||||
keyType: defaultKeyType, // Use first available key type from API
|
keyType: 'PRIMARY', // PRIMARY, FOREIGN, UNIQUE
|
||||||
keyColumns: [] // Array of {columnId, sequence} objects
|
keyColumns: [] // Array of {columnId, sequence} objects
|
||||||
};
|
};
|
||||||
setKeys(prev => [...prev, newKey]);
|
setKeys(prev => [...prev, newKey]);
|
||||||
|
|
@ -503,16 +406,12 @@ const AddTableModal = ({
|
||||||
columns: columns.map(col => ({
|
columns: columns.map(col => ({
|
||||||
name: col.name.trim(),
|
name: col.name.trim(),
|
||||||
data_type: col.type,
|
data_type: col.type,
|
||||||
is_primary_key: keys.some(key => {
|
is_primary_key: keys.some(key =>
|
||||||
const keyTypeObj = keyTypes.find(kt => kt.kytp === key.keyType);
|
key.keyColumns?.some(kc => kc.columnId === col.id) && key.keyType === 'PRIMARY'
|
||||||
return key.keyColumns?.some(kc => kc.columnId === col.id) &&
|
),
|
||||||
keyTypeObj?.name?.toLowerCase() === 'primary';
|
is_foreign_key: keys.some(key =>
|
||||||
}),
|
key.keyColumns?.some(kc => kc.columnId === col.id) && key.keyType === 'FOREIGN'
|
||||||
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
|
is_nullable: col.isNullable
|
||||||
})),
|
})),
|
||||||
keys: keys.flatMap(key =>
|
keys: keys.flatMap(key =>
|
||||||
|
|
@ -545,44 +444,14 @@ 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 (
|
return (
|
||||||
<Dialog
|
<Dialog
|
||||||
open={open}
|
open={open}
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
maxWidth={position === 'bottom-right' ? false : 'lg'}
|
maxWidth="lg"
|
||||||
fullWidth={position !== 'bottom-right'}
|
fullWidth
|
||||||
sx={getDialogStyles()}
|
|
||||||
PaperProps={{
|
PaperProps={{
|
||||||
sx: position === 'bottom-right' ? {} : {
|
sx: {
|
||||||
minHeight: '80vh',
|
minHeight: '80vh',
|
||||||
maxHeight: '90vh'
|
maxHeight: '90vh'
|
||||||
}
|
}
|
||||||
|
|
@ -598,7 +467,7 @@ const AddTableModal = ({
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</DialogTitle>
|
</DialogTitle>
|
||||||
|
|
||||||
<DialogContent dividers sx={{ p: position === 'bottom-right' ? 2 : 3 }}>
|
<DialogContent dividers sx={{ p: 3 }}>
|
||||||
{errors.submit && (
|
{errors.submit && (
|
||||||
<Alert severity="error" sx={{ mb: 3 }}>
|
<Alert severity="error" sx={{ mb: 3 }}>
|
||||||
{errors.submit}
|
{errors.submit}
|
||||||
|
|
@ -606,7 +475,7 @@ const AddTableModal = ({
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Basic Table Information */}
|
{/* Basic Table Information */}
|
||||||
<Paper elevation={1} sx={{ p: position === 'bottom-right' ? 2 : 3, mb: position === 'bottom-right' ? 2 : 3 }}>
|
<Paper elevation={1} sx={{ p: 3, mb: 3 }}>
|
||||||
<Typography variant="h6" gutterBottom color="primary">
|
<Typography variant="h6" gutterBottom color="primary">
|
||||||
Table Information
|
Table Information
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
@ -673,7 +542,7 @@ const AddTableModal = ({
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Columns Section */}
|
{/* Columns Section */}
|
||||||
<Paper elevation={1} sx={{ p: position === 'bottom-right' ? 2 : 3, mb: position === 'bottom-right' ? 2 : 3 }}>
|
<Paper elevation={1} sx={{ p: 3, mb: 3 }}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
||||||
<Typography variant="h6" color="primary">
|
<Typography variant="h6" color="primary">
|
||||||
Columns
|
Columns
|
||||||
|
|
@ -718,30 +587,12 @@ const AddTableModal = ({
|
||||||
value={column.type}
|
value={column.type}
|
||||||
onChange={(e) => updateColumn(column.id, 'type', e.target.value)}
|
onChange={(e) => updateColumn(column.id, 'type', e.target.value)}
|
||||||
label="Data Type"
|
label="Data Type"
|
||||||
disabled={loadingColumnTypes}
|
|
||||||
>
|
>
|
||||||
{loadingColumnTypes ? (
|
{columnTypes.map(type => (
|
||||||
<MenuItem value="">Loading...</MenuItem>
|
<MenuItem key={type} value={type}>
|
||||||
) : columnTypesFromAPI.length > 0 ? (
|
{type}
|
||||||
columnTypesFromAPI.map(type => (
|
</MenuItem>
|
||||||
<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>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
@ -773,7 +624,7 @@ const AddTableModal = ({
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Keys Section */}
|
{/* Keys Section */}
|
||||||
<Paper elevation={1} sx={{ p: position === 'bottom-right' ? 2 : 3, mb: position === 'bottom-right' ? 2 : 3 }}>
|
<Paper elevation={1} sx={{ p: 3, mb: 3 }}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
||||||
<Typography variant="h6" color="primary">
|
<Typography variant="h6" color="primary">
|
||||||
<KeyIcon style={{ marginRight: '8px', verticalAlign: 'middle' }} />
|
<KeyIcon style={{ marginRight: '8px', verticalAlign: 'middle' }} />
|
||||||
|
|
@ -860,17 +711,10 @@ const AddTableModal = ({
|
||||||
updateKey(key.id, 'keyType', e.target.value);
|
updateKey(key.id, 'keyType', e.target.value);
|
||||||
}}
|
}}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
disabled={loadingKeyTypes}
|
|
||||||
>
|
>
|
||||||
{loadingKeyTypes ? (
|
<MenuItem value="PRIMARY">Primary Key</MenuItem>
|
||||||
<MenuItem value="">Loading...</MenuItem>
|
<MenuItem value="FOREIGN">Foreign Key</MenuItem>
|
||||||
) : (
|
<MenuItem value="UNIQUE">Unique Key</MenuItem>
|
||||||
keyTypes.map((keyType) => (
|
|
||||||
<MenuItem key={keyType.kytp} value={keyType.kytp}>
|
|
||||||
{keyType.name} Key
|
|
||||||
</MenuItem>
|
|
||||||
))
|
|
||||||
)}
|
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
</TableCell>
|
</TableCell>
|
||||||
|
|
@ -1010,7 +854,7 @@ const AddTableModal = ({
|
||||||
</Paper>
|
</Paper>
|
||||||
|
|
||||||
{/* Relations Section */}
|
{/* Relations Section */}
|
||||||
<Paper elevation={1} sx={{ p: position === 'bottom-right' ? 2 : 3 }}>
|
<Paper elevation={1} sx={{ p: 3 }}>
|
||||||
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
<Box sx={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', mb: 2 }}>
|
||||||
<Typography variant="h6" color="primary">
|
<Typography variant="h6" color="primary">
|
||||||
<LinkIcon style={{ marginRight: '8px', verticalAlign: 'middle' }} />
|
<LinkIcon style={{ marginRight: '8px', verticalAlign: 'middle' }} />
|
||||||
|
|
@ -1121,7 +965,7 @@ const AddTableModal = ({
|
||||||
</Paper>
|
</Paper>
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
|
|
||||||
<DialogActions sx={{ p: position === 'bottom-right' ? 2 : 3, gap: 1 }}>
|
<DialogActions sx={{ p: 3, gap: 1 }}>
|
||||||
<Button onClick={onClose} variant="outlined">
|
<Button onClick={onClose} variant="outlined">
|
||||||
Cancel
|
Cancel
|
||||||
</Button>
|
</Button>
|
||||||
|
|
|
||||||
|
|
@ -1755,7 +1755,6 @@ const ERDiagramCanvasContent = () => {
|
||||||
onAddTable={handleAddTable}
|
onAddTable={handleAddTable}
|
||||||
schemas={availableSchemas}
|
schemas={availableSchemas}
|
||||||
existingTables={existingTables}
|
existingTables={existingTables}
|
||||||
position="bottom-right"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
65
test_api.js
65
test_api.js
|
|
@ -1,65 +0,0 @@
|
||||||
// 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