Integrated the api endpoint for fetching the relations between tables
This commit is contained in:
parent
886056e2f6
commit
ddfd2879d4
|
|
@ -534,8 +534,7 @@ const AddTableModal = ({
|
||||||
// Call the parent component's add table function
|
// Call the parent component's add table function
|
||||||
await onAddTable(tableData);
|
await onAddTable(tableData);
|
||||||
|
|
||||||
// Close modal and reset form
|
// Reset form (modal will be closed by parent component)
|
||||||
onClose();
|
|
||||||
resetForm();
|
resetForm();
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error adding table:', error);
|
console.error('Error adding table:', error);
|
||||||
|
|
|
||||||
|
|
@ -551,6 +551,7 @@ const ERDiagramCanvasContent = () => {
|
||||||
SCHEMA_LIST: `${API_BASE_URL}/qbt_schema_list_get`,
|
SCHEMA_LIST: `${API_BASE_URL}/qbt_schema_list_get`,
|
||||||
TABLE_LIST: `${API_BASE_URL}/qbt_table_list_get`,
|
TABLE_LIST: `${API_BASE_URL}/qbt_table_list_get`,
|
||||||
COLUMN_LIST: `${API_BASE_URL}/qbt_column_list_get`,
|
COLUMN_LIST: `${API_BASE_URL}/qbt_column_list_get`,
|
||||||
|
DATASOURCE_KEY_LIST: `${API_BASE_URL}/qbt_datasource_key_list_get`,
|
||||||
SCHEMA_CREATE: `${API_BASE_URL}/qbt_schema_create`,
|
SCHEMA_CREATE: `${API_BASE_URL}/qbt_schema_create`,
|
||||||
SCHEMA_DELETE: `${API_BASE_URL}/qbt_schema_delete`,
|
SCHEMA_DELETE: `${API_BASE_URL}/qbt_schema_delete`,
|
||||||
SCHEMA_UPDATE: `${API_BASE_URL}/qbt_schema_update`,
|
SCHEMA_UPDATE: `${API_BASE_URL}/qbt_schema_update`,
|
||||||
|
|
@ -773,6 +774,61 @@ const ERDiagramCanvasContent = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Function to fetch relationships/foreign keys from the API
|
||||||
|
const fetchRelationships = async (dbSlug) => {
|
||||||
|
try {
|
||||||
|
console.log(`Fetching relationships for database: ${dbSlug}`);
|
||||||
|
const response = await axios.post(
|
||||||
|
ENDPOINTS.DATASOURCE_KEY_LIST,
|
||||||
|
{
|
||||||
|
token: token,
|
||||||
|
org: orgSlug,
|
||||||
|
con: dbSlug
|
||||||
|
},
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
console.log(`Relationships response for database ${dbSlug}:`, response.data);
|
||||||
|
|
||||||
|
let relationships = [];
|
||||||
|
if (response.data.status === 200 && Array.isArray(response.data.items)) {
|
||||||
|
relationships = response.data.items.map((item, index) => {
|
||||||
|
// Extract source and destination information
|
||||||
|
const source = item.source?.[0];
|
||||||
|
const destination = item.destination?.[0];
|
||||||
|
|
||||||
|
if (source && destination) {
|
||||||
|
return {
|
||||||
|
id: `relationship-${index}`,
|
||||||
|
sourceTable: source.table_slug,
|
||||||
|
sourceSchema: source.schema_slug,
|
||||||
|
sourceColumn: source.column_slug,
|
||||||
|
sourceKeyName: source.key_name,
|
||||||
|
targetTable: destination.table_slug,
|
||||||
|
targetSchema: destination.schema_slug,
|
||||||
|
targetColumn: destination.column_slug,
|
||||||
|
targetKeyName: destination.key_name,
|
||||||
|
relationship_type: '1:N' // Default relationship type, can be enhanced later
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}).filter(Boolean); // Remove null entries
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Number of relationships found for database ${dbSlug}: ${relationships.length}`);
|
||||||
|
console.log('Parsed relationships:', relationships);
|
||||||
|
return relationships;
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error fetching relationships for database ${dbSlug}:`, error);
|
||||||
|
// Return empty array on error to prevent breaking the diagram
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Function to fetch complete database structure with schemas, tables, and columns
|
// Function to fetch complete database structure with schemas, tables, and columns
|
||||||
const fetchCompleteDatabase = async (dbSlug) => {
|
const fetchCompleteDatabase = async (dbSlug) => {
|
||||||
try {
|
try {
|
||||||
|
|
@ -828,48 +884,8 @@ const ERDiagramCanvasContent = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate dummy ER relationship data based on single database structure
|
|
||||||
const generateDummyERData = (database) => {
|
|
||||||
const erData = [];
|
|
||||||
|
|
||||||
if (database.schemas && database.schemas.length > 0) {
|
|
||||||
database.schemas.forEach(schema => {
|
|
||||||
if (schema.tables && schema.tables.length > 0) {
|
|
||||||
// Create relationships between tables in the same schema
|
|
||||||
for (let i = 0; i < schema.tables.length - 1; i++) {
|
|
||||||
const sourceTable = schema.tables[i];
|
|
||||||
const targetTable = schema.tables[i + 1];
|
|
||||||
|
|
||||||
// Create a dummy relationship with varied types
|
|
||||||
const relationshipTypes = ['1:N', '1:1', 'N:M'];
|
|
||||||
const randomType = relationshipTypes[Math.floor(Math.random() * relationshipTypes.length)];
|
|
||||||
|
|
||||||
erData.push({
|
|
||||||
source_column_set: [
|
|
||||||
{
|
|
||||||
table_id: sourceTable.id,
|
|
||||||
column_name: sourceTable.columns?.[0]?.name || 'id',
|
|
||||||
table_name: sourceTable.name,
|
|
||||||
schema_name: schema.sch
|
|
||||||
}
|
|
||||||
],
|
|
||||||
destination_column_set: [
|
|
||||||
{
|
|
||||||
table_id: targetTable.id,
|
|
||||||
column_name: `${sourceTable.name}_id`,
|
|
||||||
table_name: targetTable.name,
|
|
||||||
schema_name: schema.sch
|
|
||||||
}
|
|
||||||
],
|
|
||||||
relationship_type: randomType
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return erData;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Fetch databases and generate ER diagram using real API
|
// Fetch databases and generate ER diagram using real API
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -898,6 +914,9 @@ const ERDiagramCanvasContent = () => {
|
||||||
// Fetch complete structure (schemas, tables, columns) for the selected database
|
// Fetch complete structure (schemas, tables, columns) for the selected database
|
||||||
const schemasWithTables = await fetchCompleteDatabase(targetDatabase.con);
|
const schemasWithTables = await fetchCompleteDatabase(targetDatabase.con);
|
||||||
|
|
||||||
|
// Fetch relationships for the selected database
|
||||||
|
const relationships = await fetchRelationships(targetDatabase.con);
|
||||||
|
|
||||||
// Create the complete database object using actual API data
|
// Create the complete database object using actual API data
|
||||||
const completeDatabase = {
|
const completeDatabase = {
|
||||||
id: targetDatabase.id,
|
id: targetDatabase.id,
|
||||||
|
|
@ -906,7 +925,8 @@ const ERDiagramCanvasContent = () => {
|
||||||
description: targetDatabase.description || `Database: ${targetDatabase.name}`,
|
description: targetDatabase.description || `Database: ${targetDatabase.name}`,
|
||||||
service: selectedService?.name,
|
service: selectedService?.name,
|
||||||
dataSource: selectedDataSource?.name,
|
dataSource: selectedDataSource?.name,
|
||||||
schemas: schemasWithTables
|
schemas: schemasWithTables,
|
||||||
|
relationships: relationships
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log('Complete database structure:', completeDatabase);
|
console.log('Complete database structure:', completeDatabase);
|
||||||
|
|
@ -1002,6 +1022,14 @@ const ERDiagramCanvasContent = () => {
|
||||||
}
|
}
|
||||||
}, [nodes, isLoading, fitView]);
|
}, [nodes, isLoading, fitView]);
|
||||||
|
|
||||||
|
// Regenerate diagram when selectedDatabase changes (including after adding new table)
|
||||||
|
useEffect(() => {
|
||||||
|
if (selectedDatabase && selectedDatabase.schemas) {
|
||||||
|
console.log('Selected database changed, regenerating diagram...');
|
||||||
|
generateERDiagram(selectedDatabase);
|
||||||
|
}
|
||||||
|
}, [selectedDatabase]);
|
||||||
|
|
||||||
// Auto-alignment layout calculator
|
// Auto-alignment layout calculator
|
||||||
const calculateOptimalLayout = (databaseData) => {
|
const calculateOptimalLayout = (databaseData) => {
|
||||||
const layouts = [];
|
const layouts = [];
|
||||||
|
|
@ -1075,7 +1103,7 @@ const ERDiagramCanvasContent = () => {
|
||||||
key_type: key.key_type,
|
key_type: key.key_type,
|
||||||
key_columns: [{
|
key_columns: [{
|
||||||
column_name: key.column_name,
|
column_name: key.column_name,
|
||||||
sequence: key.sequence
|
sequence: key.sequence || 1
|
||||||
}]
|
}]
|
||||||
}))
|
}))
|
||||||
};
|
};
|
||||||
|
|
@ -1105,10 +1133,9 @@ const ERDiagramCanvasContent = () => {
|
||||||
created_at: new Date().toISOString()
|
created_at: new Date().toISOString()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add the table to existing tables list
|
console.log('Table created successfully via API:', newTable);
|
||||||
setExistingTables(prev => [...prev, newTable]);
|
|
||||||
|
|
||||||
// Update the current database structure and regenerate the diagram
|
// Update the current database structure immediately
|
||||||
const updatedDatabase = { ...selectedDatabase };
|
const updatedDatabase = { ...selectedDatabase };
|
||||||
const schemaIndex = updatedDatabase.schemas.findIndex(s => s.sch === tableData.schema);
|
const schemaIndex = updatedDatabase.schemas.findIndex(s => s.sch === tableData.schema);
|
||||||
|
|
||||||
|
|
@ -1118,14 +1145,51 @@ const ERDiagramCanvasContent = () => {
|
||||||
}
|
}
|
||||||
updatedDatabase.schemas[schemaIndex].tables.push(newTable);
|
updatedDatabase.schemas[schemaIndex].tables.push(newTable);
|
||||||
|
|
||||||
|
console.log(`Added table "${newTable.name}" to schema "${tableData.schema}"`);
|
||||||
|
console.log('Updated database structure:', updatedDatabase);
|
||||||
|
|
||||||
// Update the selected database state
|
// Update the selected database state
|
||||||
setSelectedDatabase(updatedDatabase);
|
setSelectedDatabase(updatedDatabase);
|
||||||
|
|
||||||
// Regenerate the ER diagram with the new table
|
// Update databases list
|
||||||
generateERDiagram(updatedDatabase);
|
setDatabases(prevDatabases => {
|
||||||
|
return prevDatabases.map(db => {
|
||||||
|
if (db.id === selectedDatabase?.id) {
|
||||||
|
return updatedDatabase;
|
||||||
|
}
|
||||||
|
return db;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
console.log('Table added successfully:', newTable);
|
// Regenerate the ER diagram with the new table immediately
|
||||||
|
console.log('Scheduling diagram regeneration...');
|
||||||
|
setTimeout(() => {
|
||||||
|
console.log('Regenerating diagram with updated database...');
|
||||||
|
generateERDiagram(updatedDatabase);
|
||||||
|
}, 100);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Update existing tables list for the modal
|
||||||
|
setExistingTables(prev => [...prev, newTable]);
|
||||||
|
|
||||||
|
// Close the modal immediately after successful creation
|
||||||
|
setIsAddTableModalOpen(false);
|
||||||
|
|
||||||
|
console.log('Table added successfully and modal closed');
|
||||||
|
|
||||||
|
// Force a small delay to ensure all state updates are processed and then fit view
|
||||||
|
setTimeout(() => {
|
||||||
|
if (fitView) {
|
||||||
|
fitView({
|
||||||
|
padding: 0.1,
|
||||||
|
includeHiddenNodes: false,
|
||||||
|
minZoom: 0.15,
|
||||||
|
maxZoom: 0.8,
|
||||||
|
duration: 800
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, 500);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new Error(response.data.message || 'Failed to create table');
|
throw new Error(response.data.message || 'Failed to create table');
|
||||||
}
|
}
|
||||||
|
|
@ -1133,6 +1197,9 @@ const ERDiagramCanvasContent = () => {
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error adding table:', error);
|
console.error('Error adding table:', error);
|
||||||
|
|
||||||
|
// Always close the modal on error to prevent it from being stuck
|
||||||
|
setIsAddTableModalOpen(false);
|
||||||
|
|
||||||
// Check if it's an API error
|
// Check if it's an API error
|
||||||
if (error.response) {
|
if (error.response) {
|
||||||
const errorMessage = error.response.data?.message || `API Error: ${error.response.status}`;
|
const errorMessage = error.response.data?.message || `API Error: ${error.response.status}`;
|
||||||
|
|
@ -1147,16 +1214,22 @@ const ERDiagramCanvasContent = () => {
|
||||||
|
|
||||||
// Generate ER diagram with Database Wrapper structure
|
// Generate ER diagram with Database Wrapper structure
|
||||||
const generateERDiagram = (database) => {
|
const generateERDiagram = (database) => {
|
||||||
const newNodes = [];
|
console.log('🔄 Starting ER diagram generation...');
|
||||||
const newEdges = [];
|
console.log('Database received:', database?.name);
|
||||||
|
console.log('Total schemas:', database?.schemas?.length);
|
||||||
|
|
||||||
// Generate dummy relationships
|
const newNodes = [];
|
||||||
const relationships = generateDummyERData(database);
|
const newEdges = []; // No edges - removing all connections
|
||||||
|
|
||||||
// Process the selected database
|
// Process the selected database
|
||||||
console.log('Generating ER diagram for database:', database?.name);
|
console.log('Generating ER diagram for database:', database?.name);
|
||||||
console.log('Total schemas in database:', database?.schemas?.length);
|
console.log('Total schemas in database:', database?.schemas?.length);
|
||||||
console.log('Schema details:', database?.schemas?.map(s => ({ name: s.name, sch: s.sch, tableCount: s.tables?.length || 0 })));
|
console.log('Schema details:', database?.schemas?.map(s => ({
|
||||||
|
name: s.name,
|
||||||
|
sch: s.sch,
|
||||||
|
tableCount: s.tables?.length || 0,
|
||||||
|
tableNames: s.tables?.map(t => t.name) || []
|
||||||
|
})));
|
||||||
|
|
||||||
if (database && database.schemas && database.schemas.length > 0) {
|
if (database && database.schemas && database.schemas.length > 0) {
|
||||||
// Calculate database wrapper dimensions
|
// Calculate database wrapper dimensions
|
||||||
|
|
@ -1316,16 +1389,21 @@ const ERDiagramCanvasContent = () => {
|
||||||
console.warn(`Table "${table.name}" position (${tableX}, ${tableY}) exceeds schema bounds (${schemaLayout.width}x${schemaLayout.height})`);
|
console.warn(`Table "${table.name}" position (${tableX}, ${tableY}) exceeds schema bounds (${schemaLayout.width}x${schemaLayout.height})`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add primary key and foreign key indicators to columns
|
// Add primary key and foreign key indicators to columns based on relationships
|
||||||
const enhancedColumns = (table.columns || []).map((col, colIndex) => ({
|
const enhancedColumns = (table.columns || []).map((col, colIndex) => {
|
||||||
...col,
|
// Check if this column is a foreign key based on relationships
|
||||||
is_primary_key: colIndex === 0, // First column as primary key
|
const isForeignKey = database.relationships?.some(rel =>
|
||||||
is_foreign_key: relationships.some(rel =>
|
rel.targetTable === table.tbl &&
|
||||||
rel.destination_column_set.some(dest =>
|
rel.targetSchema === schemaLayout.schema.sch &&
|
||||||
dest.column_name === col.name && dest.table_name === table.name
|
rel.targetColumn === col.col
|
||||||
)
|
) || false;
|
||||||
)
|
|
||||||
}));
|
return {
|
||||||
|
...col,
|
||||||
|
is_primary_key: col.is_primary_key || colIndex === 0, // Use existing or first column as primary key
|
||||||
|
is_foreign_key: isForeignKey
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
newNodes.push({
|
newNodes.push({
|
||||||
id: tableId,
|
id: tableId,
|
||||||
|
|
@ -1358,38 +1436,80 @@ const ERDiagramCanvasContent = () => {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create edges for relationships
|
// Create relationship edges based on API data
|
||||||
relationships.forEach((rel, index) => {
|
if (database.relationships && database.relationships.length > 0) {
|
||||||
const sourceTableId = `table-${rel.source_column_set[0]?.table_id || `${rel.source_column_set[0]?.schema_name}-${rel.source_column_set[0]?.table_name}`}`;
|
console.log('Creating relationship edges:', database.relationships.length);
|
||||||
const targetTableId = `table-${rel.destination_column_set[0]?.table_id || `${rel.destination_column_set[0]?.schema_name}-${rel.destination_column_set[0]?.table_name}`}`;
|
|
||||||
|
|
||||||
// Check if both nodes exist
|
database.relationships.forEach((relationship, index) => {
|
||||||
const sourceExists = newNodes.some(node => node.id === sourceTableId);
|
// Find source and target table nodes
|
||||||
const targetExists = newNodes.some(node => node.id === targetTableId);
|
const sourceTableId = `table-${database.slug}-${relationship.sourceSchema}-${relationship.sourceTable}`;
|
||||||
|
const targetTableId = `table-${database.slug}-${relationship.targetSchema}-${relationship.targetTable}`;
|
||||||
|
|
||||||
if (sourceExists && targetExists) {
|
// Check if both source and target tables exist in the nodes
|
||||||
newEdges.push({
|
const sourceNode = newNodes.find(node =>
|
||||||
id: `relationship-${index}`,
|
node.type === 'erTable' &&
|
||||||
type: 'erRelationship',
|
(node.id === sourceTableId ||
|
||||||
source: sourceTableId,
|
node.id.includes(relationship.sourceTable) &&
|
||||||
target: targetTableId,
|
node.data?.schema === relationship.sourceSchema)
|
||||||
data: {
|
);
|
||||||
relationship_type: rel.relationship_type,
|
|
||||||
source_column: rel.source_column_set[0]?.column_name,
|
const targetNode = newNodes.find(node =>
|
||||||
target_column: rel.destination_column_set[0]?.column_name
|
node.type === 'erTable' &&
|
||||||
},
|
(node.id === targetTableId ||
|
||||||
style: {
|
node.id.includes(relationship.targetTable) &&
|
||||||
stroke: '#8a2be2',
|
node.data?.schema === relationship.targetSchema)
|
||||||
strokeWidth: 2
|
);
|
||||||
},
|
|
||||||
animated: false
|
if (sourceNode && targetNode) {
|
||||||
});
|
const edgeId = `edge-${relationship.id || index}`;
|
||||||
}
|
|
||||||
});
|
console.log(`Creating edge: ${sourceNode.id} -> ${targetNode.id}`);
|
||||||
|
console.log(`Relationship: ${relationship.sourceTable}.${relationship.sourceColumn} -> ${relationship.targetTable}.${relationship.targetColumn}`);
|
||||||
|
|
||||||
|
newEdges.push({
|
||||||
|
id: edgeId,
|
||||||
|
source: sourceNode.id,
|
||||||
|
target: targetNode.id,
|
||||||
|
type: 'erRelationship',
|
||||||
|
data: {
|
||||||
|
relationship_type: relationship.relationship_type || '1:N',
|
||||||
|
source_column: relationship.sourceColumn,
|
||||||
|
target_column: relationship.targetColumn,
|
||||||
|
source_key_name: relationship.sourceKeyName,
|
||||||
|
target_key_name: relationship.targetKeyName
|
||||||
|
},
|
||||||
|
style: {
|
||||||
|
stroke: '#8a2be2',
|
||||||
|
strokeWidth: 2,
|
||||||
|
},
|
||||||
|
markerEnd: {
|
||||||
|
type: MarkerType.ArrowClosed,
|
||||||
|
color: '#8a2be2',
|
||||||
|
},
|
||||||
|
animated: false,
|
||||||
|
selectable: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
console.warn(`Could not find nodes for relationship: ${relationship.sourceTable} -> ${relationship.targetTable}`);
|
||||||
|
console.warn(`Source node found: ${!!sourceNode}, Target node found: ${!!targetNode}`);
|
||||||
|
console.warn(`Looking for source ID: ${sourceTableId}, target ID: ${targetTableId}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`Created ${newEdges.length} relationship edges out of ${database.relationships.length} relationships`);
|
||||||
|
} else {
|
||||||
|
console.log('No relationships found in database data');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('📊 Setting nodes and edges...');
|
||||||
|
console.log('New nodes count:', newNodes.length);
|
||||||
|
console.log('New edges count:', newEdges.length);
|
||||||
|
|
||||||
setNodes(newNodes);
|
setNodes(newNodes);
|
||||||
setEdges(newEdges);
|
setEdges(newEdges);
|
||||||
|
|
||||||
|
console.log('✅ ER diagram generation completed');
|
||||||
|
|
||||||
// Update available schemas and existing tables for the modal
|
// Update available schemas and existing tables for the modal
|
||||||
if (database && database.schemas) {
|
if (database && database.schemas) {
|
||||||
setAvailableSchemas(database.schemas);
|
setAvailableSchemas(database.schemas);
|
||||||
|
|
@ -1424,23 +1544,7 @@ const ERDiagramCanvasContent = () => {
|
||||||
}, 300);
|
}, 300);
|
||||||
};
|
};
|
||||||
|
|
||||||
const onConnect = useCallback(
|
// onConnect removed - no connections allowed between tables
|
||||||
(params) => setEdges((eds) => addEdge({
|
|
||||||
...params,
|
|
||||||
type: 'erRelationship',
|
|
||||||
data: {
|
|
||||||
relationship_type: '1:N',
|
|
||||||
source_column: 'id',
|
|
||||||
target_column: 'foreign_key_id'
|
|
||||||
},
|
|
||||||
style: {
|
|
||||||
stroke: '#8a2be2',
|
|
||||||
strokeWidth: 2
|
|
||||||
},
|
|
||||||
animated: true
|
|
||||||
}, eds)),
|
|
||||||
[setEdges]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleAddClick = () => {
|
const handleAddClick = () => {
|
||||||
setShowAddMenu(!showAddMenu);
|
setShowAddMenu(!showAddMenu);
|
||||||
|
|
@ -1513,14 +1617,8 @@ const ERDiagramCanvasContent = () => {
|
||||||
edges={edges}
|
edges={edges}
|
||||||
onNodesChange={onNodesChange}
|
onNodesChange={onNodesChange}
|
||||||
onEdgesChange={onEdgesChange}
|
onEdgesChange={onEdgesChange}
|
||||||
onConnect={onConnect}
|
|
||||||
nodeTypes={nodeTypes}
|
nodeTypes={nodeTypes}
|
||||||
edgeTypes={edgeTypes}
|
edgeTypes={edgeTypes}
|
||||||
connectionLineStyle={{
|
|
||||||
stroke: '#8a2be2',
|
|
||||||
strokeWidth: 2,
|
|
||||||
}}
|
|
||||||
connectionLineType="bezier"
|
|
||||||
fitView
|
fitView
|
||||||
fitViewOptions={{
|
fitViewOptions={{
|
||||||
padding: 0.15,
|
padding: 0.15,
|
||||||
|
|
@ -1611,38 +1709,7 @@ const ERDiagramCanvasContent = () => {
|
||||||
</div>
|
</div>
|
||||||
</Panel>
|
</Panel>
|
||||||
|
|
||||||
{/* Relationship Legend Panel */}
|
|
||||||
<Panel position="bottom-left">
|
|
||||||
<div style={{
|
|
||||||
background: 'rgba(26, 26, 26, 0.9)',
|
|
||||||
padding: '12px 16px',
|
|
||||||
borderRadius: '8px',
|
|
||||||
border: '1px solid rgba(138, 43, 226, 0.3)',
|
|
||||||
color: '#fff',
|
|
||||||
fontSize: '12px',
|
|
||||||
backdropFilter: 'blur(5px)',
|
|
||||||
minWidth: '200px'
|
|
||||||
}}>
|
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '8px' }}>
|
|
||||||
<FaLink style={{ color: '#8a2be2' }} />
|
|
||||||
<strong>Relationship Types</strong>
|
|
||||||
</div>
|
|
||||||
<div style={{ fontSize: '11px', lineHeight: '1.4' }}>
|
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>
|
|
||||||
<span style={{ color: '#8a2be2' }}>→</span>
|
|
||||||
<span><strong>1:N</strong> - One to Many</span>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>
|
|
||||||
<span style={{ color: '#8a2be2' }}>→</span>
|
|
||||||
<span><strong>1:1</strong> - One to One</span>
|
|
||||||
</div>
|
|
||||||
<div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>
|
|
||||||
<span style={{ color: '#8a2be2' }}>↔</span>
|
|
||||||
<span><strong>N:M</strong> - Many to Many</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Panel>
|
|
||||||
</ReactFlow>
|
</ReactFlow>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue