ER Diagram changes-- Adding new relations #16

Merged
vdevika merged 1 commits from develop into main 2025-06-23 03:59:25 +00:00
4 changed files with 272 additions and 42 deletions
Showing only changes of commit 1065df6e1b - Show all commits

View File

@ -1074,7 +1074,7 @@ const AddTableModal = ({
</Select> </Select>
</FormControl> </FormControl>
</Grid> </Grid>
<Grid item xs={12} md={2}> {/* <Grid item xs={12} md={2}>
<FormControl fullWidth size="small"> <FormControl fullWidth size="small">
<InputLabel>Relation Type</InputLabel> <InputLabel>Relation Type</InputLabel>
<Select <Select
@ -1087,7 +1087,7 @@ const AddTableModal = ({
<MenuItem value="N:M">Many to Many</MenuItem> <MenuItem value="N:M">Many to Many</MenuItem>
</Select> </Select>
</FormControl> </FormControl>
</Grid> </Grid> */}
<Grid item xs={12} md={1}> <Grid item xs={12} md={1}>
<IconButton <IconButton
onClick={() => removeRelation(relation.id)} onClick={() => removeRelation(relation.id)}

View File

@ -74,14 +74,44 @@ const ERTableNode = ({ data, id }) => {
</div> </div>
<ul className="er-column-list"> <ul className="er-column-list">
{data.columns && data.columns.map((column, index) => ( {data.columns && data.columns.map((column, index) => {
<li key={index} className="er-column-item"> // Determine the column's role in relationships
{column.is_primary_key && <FaKey className="er-primary-key" />} const isSourceKey = column.is_source_key;
{column.is_foreign_key && <FaLink className="er-foreign-key" />} const isForeignKey = column.is_foreign_key;
<span className="er-column-name">{column.name}</span> const isPrimaryKey = column.is_primary_key;
<span className="er-column-type">{column.data_type}</span>
</li> // Create CSS classes for highlighting - ONLY based on API relationship data
))} let columnClasses = "er-column-item";
if (isSourceKey) columnClasses += " er-source-key";
if (isForeignKey) columnClasses += " er-foreign-key-highlight";
// Debug logging for CSS classes - only for actual relationships
if (isSourceKey || isForeignKey) {
console.log(`🎨 Column ${column.name} classes: ${columnClasses}`);
console.log(`🎨 isSourceKey: ${isSourceKey}, isForeignKey: ${isForeignKey}`);
console.log(`Column data:`, column);
}
return (
<li key={index} className={columnClasses}>
{isPrimaryKey && <FaKey className="er-primary-key" />}
{isForeignKey && <FaLink className="er-foreign-key" />}
{isSourceKey && !isPrimaryKey && <FaKey className="er-source-key-icon" />}
<span className="er-column-name">{column.name}</span>
<span className="er-column-type">{column.data_type}</span>
{/* Show relationship info on hover */}
{column.relationship_info && column.relationship_info.length > 0 && (
<div className="er-relationship-tooltip">
{column.relationship_info.map((rel, relIndex) => (
<div key={relIndex} className="er-relationship-info">
{isSourceKey ? `${rel.targetTable}.${rel.targetColumn}` : `${rel.sourceTable}.${rel.sourceColumn}`}
</div>
))}
</div>
)}
</li>
);
})}
</ul> </ul>
</div> </div>
); );
@ -578,25 +608,27 @@ const ERDiagramCanvasContent = () => {
{ {
id: 1, id: 1,
name: "accounts", name: "accounts",
tbl: "accounts", // Add tbl field for consistency
table_type: "dimension", table_type: "dimension",
columns: [ columns: [
{ name: "account_id", data_type: "INTEGER", is_primary_key: true, is_foreign_key: false }, { name: "account_id", col: "account_id", data_type: "INTEGER", is_primary_key: true, is_foreign_key: false },
{ name: "account_number", data_type: "VARCHAR(20)", is_primary_key: false, is_foreign_key: false }, { name: "account_number", col: "account_number", data_type: "VARCHAR(20)", is_primary_key: false, is_foreign_key: false },
{ name: "account_name", data_type: "VARCHAR(100)", is_primary_key: false, is_foreign_key: false }, { name: "account_name", col: "account_name", data_type: "VARCHAR(100)", is_primary_key: false, is_foreign_key: false },
{ name: "account_type", data_type: "VARCHAR(50)", is_primary_key: false, is_foreign_key: false }, { name: "account_type", col: "account_type", data_type: "VARCHAR(50)", is_primary_key: false, is_foreign_key: false },
{ name: "balance", data_type: "DECIMAL(15,2)", is_primary_key: false, is_foreign_key: false }, { name: "balance", col: "balance", data_type: "DECIMAL(15,2)", is_primary_key: false, is_foreign_key: false },
{ name: "created_date", data_type: "TIMESTAMP", is_primary_key: false, is_foreign_key: false } { name: "created_date", col: "created_date", data_type: "TIMESTAMP", is_primary_key: false, is_foreign_key: false }
] ]
}, },
{ {
id: 2, id: 2,
name: "transactions", name: "transactions",
tbl: "transactions", // Add tbl field for consistency
table_type: "fact", table_type: "fact",
columns: [ columns: [
{ name: "transaction_id", data_type: "INTEGER", is_primary_key: true, is_foreign_key: false }, { name: "transaction_id", col: "transaction_id", data_type: "INTEGER", is_primary_key: true, is_foreign_key: false },
{ name: "account_id", data_type: "INTEGER", is_primary_key: false, is_foreign_key: true }, { name: "account_id", col: "account_id", data_type: "INTEGER", is_primary_key: false, is_foreign_key: true },
{ name: "transaction_date", data_type: "DATE", is_primary_key: false, is_foreign_key: false }, { name: "transaction_date", col: "transaction_date", data_type: "DATE", is_primary_key: false, is_foreign_key: false },
{ name: "amount", data_type: "DECIMAL(12,2)", is_primary_key: false, is_foreign_key: false } { name: "amount", col: "amount", data_type: "DECIMAL(12,2)", is_primary_key: false, is_foreign_key: false }
] ]
} }
] ]
@ -608,15 +640,30 @@ const ERDiagramCanvasContent = () => {
{ {
id: 3, id: 3,
name: "customers", name: "customers",
tbl: "customers", // Add tbl field for consistency
table_type: "dimension", table_type: "dimension",
columns: [ columns: [
{ name: "customer_id", data_type: "INTEGER", is_primary_key: true, is_foreign_key: false }, { name: "customer_id", col: "customer_id", data_type: "INTEGER", is_primary_key: true, is_foreign_key: false },
{ name: "customer_name", data_type: "VARCHAR(100)", is_primary_key: false, is_foreign_key: false }, { name: "customer_name", col: "customer_name", data_type: "VARCHAR(100)", is_primary_key: false, is_foreign_key: false },
{ name: "email", data_type: "VARCHAR(100)", is_primary_key: false, is_foreign_key: false } { name: "email", col: "email", data_type: "VARCHAR(100)", is_primary_key: false, is_foreign_key: false }
] ]
} }
] ]
} }
],
relationships: [
{
id: "relationship-1",
sourceTable: "accounts",
sourceSchema: "FINANCE_MART",
sourceColumn: "account_id",
sourceKeyName: "pk_accounts",
targetTable: "transactions",
targetSchema: "FINANCE_MART",
targetColumn: "account_id",
targetKeyName: "fk_transactions_account",
relationship_type: "1:N"
}
] ]
}; };
@ -1217,9 +1264,21 @@ const ERDiagramCanvasContent = () => {
console.log('🔄 Starting ER diagram generation...'); console.log('🔄 Starting ER diagram generation...');
console.log('Database received:', database?.name); console.log('Database received:', database?.name);
console.log('Total schemas:', database?.schemas?.length); console.log('Total schemas:', database?.schemas?.length);
console.log('Relationships received:', database?.relationships?.length);
console.log('Relationship details:', database?.relationships);
// Debug each relationship in detail
if (database?.relationships && database.relationships.length > 0) {
database.relationships.forEach((rel, index) => {
console.log(`🔗 Relationship ${index + 1}:`);
console.log(` Source: ${rel.sourceSchema}.${rel.sourceTable}.${rel.sourceColumn}`);
console.log(` Target: ${rel.targetSchema}.${rel.targetTable}.${rel.targetColumn}`);
console.log(` Type: ${rel.relationship_type}`);
});
}
const newNodes = []; const newNodes = [];
const newEdges = []; // No edges - removing all connections const newEdges = []; // Will be populated with relationship edges
// 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);
@ -1370,6 +1429,12 @@ const ERDiagramCanvasContent = () => {
schemaLayout.schema.tables.forEach((table, tableIndex) => { schemaLayout.schema.tables.forEach((table, tableIndex) => {
const tableId = `table-${table.id || `${database.slug}-${schemaLayout.schema.sch}-${table.name}`}`; const tableId = `table-${table.id || `${database.slug}-${schemaLayout.schema.sch}-${table.name}`}`;
// Debug table structure
if (tableIndex === 0) {
console.log(`📋 Sample table structure:`, table);
console.log(`📋 Sample column structure:`, table.columns?.[0]);
}
// Calculate table position within schema (relative to schema, not absolute) // Calculate table position within schema (relative to schema, not absolute)
const tableX = tableStartX + (currentCol * tableSpacing); const tableX = tableStartX + (currentCol * tableSpacing);
const tableY = tableStartY + (currentRow * tableRowSpacing); const tableY = tableStartY + (currentRow * tableRowSpacing);
@ -1391,17 +1456,63 @@ const ERDiagramCanvasContent = () => {
// Add primary key and foreign key indicators to columns based on relationships // 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) => {
// Check if this column is a foreign key based on relationships // Get table identifier - use table_slug from API or fallback to name
const isForeignKey = database.relationships?.some(rel => const tableSlug = table.tbl || table.table_slug || table.name;
rel.targetTable === table.tbl && // Get schema identifier
rel.targetSchema === schemaLayout.schema.sch && const schemaSlug = schemaLayout.schema.sch || schemaLayout.schema.schema_slug || schemaLayout.schema.name;
rel.targetColumn === col.col // Get column identifier - use column_slug from the column data
) || false; const columnSlug = col.col || col.column_slug || col.name;
// Check if this column is a foreign key (target/destination of a relationship)
const isForeignKey = database.relationships?.some(rel => {
const matchesTable = rel.targetTable === tableSlug;
const matchesSchema = rel.targetSchema === schemaSlug;
const matchesColumn = rel.targetColumn === columnSlug;
return matchesTable && matchesSchema && matchesColumn;
}) || false;
// Check if this column is a source key (source of a relationship)
const isSourceKey = database.relationships?.some(rel => {
const matchesTable = rel.sourceTable === tableSlug;
const matchesSchema = rel.sourceSchema === schemaSlug;
const matchesColumn = rel.sourceColumn === columnSlug;
return matchesTable && matchesSchema && matchesColumn;
}) || false;
// Debug logging for relationship matching
if (database.relationships && database.relationships.length > 0) {
// Only log for the first few columns to avoid spam
if (colIndex < 3) {
console.log(`🔍 Checking column: table=${tableSlug}, schema=${schemaSlug}, column=${columnSlug}`);
console.log(`🔍 Available relationships:`, database.relationships.map(r =>
`${r.sourceSchema}.${r.sourceTable}.${r.sourceColumn} -> ${r.targetSchema}.${r.targetTable}.${r.targetColumn}`
));
}
if (isForeignKey || isSourceKey) {
console.log(`🔗 MATCH FOUND! Column ${tableSlug}.${columnSlug} - isSourceKey: ${isSourceKey}, isForeignKey: ${isForeignKey}`);
// Find the matching relationship for more details
const matchingRel = database.relationships.find(rel =>
(rel.targetTable === tableSlug && rel.targetSchema === schemaSlug && rel.targetColumn === columnSlug) ||
(rel.sourceTable === tableSlug && rel.sourceSchema === schemaSlug && rel.sourceColumn === columnSlug)
);
console.log(`🔗 Matching relationship:`, matchingRel);
}
}
return { return {
...col, ...col,
is_primary_key: col.is_primary_key || colIndex === 0, // Use existing or first column as primary key is_primary_key: col.is_primary_key || colIndex === 0, // Use existing or first column as primary key
is_foreign_key: isForeignKey is_foreign_key: isForeignKey,
is_source_key: isSourceKey,
relationship_info: database.relationships?.filter(rel => {
const isTarget = rel.targetTable === tableSlug && rel.targetSchema === schemaSlug && rel.targetColumn === columnSlug;
const isSource = rel.sourceTable === tableSlug && rel.sourceSchema === schemaSlug && rel.sourceColumn === columnSlug;
return isTarget || isSource;
}) || []
}; };
}); });
@ -1441,23 +1552,17 @@ const ERDiagramCanvasContent = () => {
console.log('Creating relationship edges:', database.relationships.length); console.log('Creating relationship edges:', database.relationships.length);
database.relationships.forEach((relationship, index) => { database.relationships.forEach((relationship, index) => {
// Find source and target table nodes // Find source and target table nodes by matching table names and schemas
const sourceTableId = `table-${database.slug}-${relationship.sourceSchema}-${relationship.sourceTable}`;
const targetTableId = `table-${database.slug}-${relationship.targetSchema}-${relationship.targetTable}`;
// Check if both source and target tables exist in the nodes
const sourceNode = newNodes.find(node => const sourceNode = newNodes.find(node =>
node.type === 'erTable' && node.type === 'erTable' &&
(node.id === sourceTableId || node.data?.schema === relationship.sourceSchema &&
node.id.includes(relationship.sourceTable) && (node.data?.name === relationship.sourceTable || node.data?.tbl === relationship.sourceTable)
node.data?.schema === relationship.sourceSchema)
); );
const targetNode = newNodes.find(node => const targetNode = newNodes.find(node =>
node.type === 'erTable' && node.type === 'erTable' &&
(node.id === targetTableId || node.data?.schema === relationship.targetSchema &&
node.id.includes(relationship.targetTable) && (node.data?.name === relationship.targetTable || node.data?.tbl === relationship.targetTable)
node.data?.schema === relationship.targetSchema)
); );
if (sourceNode && targetNode) { if (sourceNode && targetNode) {

View File

@ -265,6 +265,124 @@
color: #8a2be2; color: #8a2be2;
} }
.er-source-key-icon {
color: #52c41a;
}
// Highlighting for relationship keys - SOURCE KEY (Teal)
.er-column-item.er-source-key {
background: linear-gradient(90deg, rgba(0, 150, 136, 0.4), rgba(0, 150, 136, 0.15)) !important;
border-left: 6px solid #009688 !important;
border-right: 3px solid rgba(0, 150, 136, 0.5) !important;
box-shadow: inset 0 0 20px rgba(0, 150, 136, 0.2), 0 3px 10px rgba(0, 150, 136, 0.3) !important;
position: relative !important;
&:before {
content: "SOURCE" !important;
position: absolute !important;
right: 8px !important;
top: 3px !important;
font-size: 9px !important;
color: #009688 !important;
font-weight: bold !important;
opacity: 0.8 !important;
background: rgba(255, 255, 255, 0.9) !important;
padding: 1px 3px !important;
border-radius: 2px !important;
}
&:hover {
background: linear-gradient(90deg, rgba(0, 150, 136, 0.5), rgba(0, 150, 136, 0.2)) !important;
box-shadow: inset 0 0 25px rgba(0, 150, 136, 0.3), 0 5px 15px rgba(0, 150, 136, 0.4) !important;
}
.er-column-name {
color: #009688 !important;
font-weight: 900 !important;
text-shadow: 0 1px 4px rgba(0, 150, 136, 0.5) !important;
font-size: 15px !important;
}
.er-column-type {
background: rgba(0, 150, 136, 0.4) !important;
color: #00695c !important;
border: 1px solid rgba(0, 150, 136, 0.6) !important;
font-weight: 700 !important;
}
}
// Highlighting for relationship keys - FOREIGN KEY (Same Teal as Source)
.er-column-item.er-foreign-key-highlight {
background: linear-gradient(90deg, rgba(0, 150, 136, 0.4), rgba(0, 150, 136, 0.15)) !important;
border-left: 6px solid #009688 !important;
border-right: 3px solid rgba(0, 150, 136, 0.5) !important;
box-shadow: inset 0 0 20px rgba(0, 150, 136, 0.2), 0 3px 10px rgba(0, 150, 136, 0.3) !important;
position: relative !important;
&:before {
content: "TARGET" !important;
position: absolute !important;
right: 8px !important;
top: 3px !important;
font-size: 9px !important;
color: #009688 !important;
font-weight: bold !important;
opacity: 0.8 !important;
background: rgba(255, 255, 255, 0.9) !important;
padding: 1px 3px !important;
border-radius: 2px !important;
}
&:hover {
background: linear-gradient(90deg, rgba(0, 150, 136, 0.5), rgba(0, 150, 136, 0.2)) !important;
box-shadow: inset 0 0 25px rgba(0, 150, 136, 0.3), 0 5px 15px rgba(0, 150, 136, 0.4) !important;
}
.er-column-name {
color: #009688 !important;
font-weight: 900 !important;
text-shadow: 0 1px 4px rgba(0, 150, 136, 0.5) !important;
font-size: 15px !important;
}
.er-column-type {
background: rgba(0, 150, 136, 0.4) !important;
color: #00695c !important;
border: 1px solid rgba(0, 150, 136, 0.6) !important;
font-weight: 700 !important;
}
}
// Relationship tooltip
.er-relationship-tooltip {
position: absolute;
right: 10px;
top: 50%;
transform: translateY(-50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 4px 8px;
border-radius: 4px;
font-size: 10px;
white-space: nowrap;
opacity: 0;
pointer-events: none;
transition: opacity 0.2s ease;
z-index: 1000;
}
.er-column-item:hover .er-relationship-tooltip {
opacity: 1;
}
.er-relationship-info {
margin-bottom: 2px;
&:last-child {
margin-bottom: 0;
}
}
// Relationship edge styles // Relationship edge styles
.er-relationship-edge { .er-relationship-edge {
stroke: #8a2be2; stroke: #8a2be2;

View File

@ -0,0 +1,7 @@
export const Pipelines=()=>{
return(
<div>
Pipelines
</div>
)
}