From 1065df6e1bd6afa0e23057af4c50824f981e6c06 Mon Sep 17 00:00:00 2001 From: Devika Date: Mon, 23 Jun 2025 09:27:28 +0530 Subject: [PATCH] ER Diagram changes-- Adding new relations --- src/components/AddTableModal.jsx | 4 +- src/components/ERDiagramCanvas.jsx | 185 ++++++++++++++++++++------ src/components/ERDiagramCanvas.scss | 118 ++++++++++++++++ src/components/children/Pipelines.jsx | 7 + 4 files changed, 272 insertions(+), 42 deletions(-) diff --git a/src/components/AddTableModal.jsx b/src/components/AddTableModal.jsx index 5b99162..2284fa1 100644 --- a/src/components/AddTableModal.jsx +++ b/src/components/AddTableModal.jsx @@ -1074,7 +1074,7 @@ const AddTableModal = ({ - + {/* Relation Type - + */} removeRelation(relation.id)} diff --git a/src/components/ERDiagramCanvas.jsx b/src/components/ERDiagramCanvas.jsx index 6247b34..46ad2a2 100644 --- a/src/components/ERDiagramCanvas.jsx +++ b/src/components/ERDiagramCanvas.jsx @@ -74,14 +74,44 @@ const ERTableNode = ({ data, id }) => {
    - {data.columns && data.columns.map((column, index) => ( -
  • - {column.is_primary_key && } - {column.is_foreign_key && } - {column.name} - {column.data_type} -
  • - ))} + {data.columns && data.columns.map((column, index) => { + // Determine the column's role in relationships + const isSourceKey = column.is_source_key; + const isForeignKey = column.is_foreign_key; + const isPrimaryKey = column.is_primary_key; + + // 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 ( +
  • + {isPrimaryKey && } + {isForeignKey && } + {isSourceKey && !isPrimaryKey && } + {column.name} + {column.data_type} + {/* Show relationship info on hover */} + {column.relationship_info && column.relationship_info.length > 0 && ( +
    + {column.relationship_info.map((rel, relIndex) => ( +
    + {isSourceKey ? `→ ${rel.targetTable}.${rel.targetColumn}` : `← ${rel.sourceTable}.${rel.sourceColumn}`} +
    + ))} +
    + )} +
  • + ); + })}
); @@ -578,25 +608,27 @@ const ERDiagramCanvasContent = () => { { id: 1, name: "accounts", + tbl: "accounts", // Add tbl field for consistency table_type: "dimension", columns: [ - { name: "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_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: "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: "account_id", col: "account_id", data_type: "INTEGER", is_primary_key: true, 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", col: "account_name", data_type: "VARCHAR(100)", 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", col: "balance", data_type: "DECIMAL(15,2)", 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, name: "transactions", + tbl: "transactions", // Add tbl field for consistency table_type: "fact", columns: [ - { name: "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: "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: "transaction_id", col: "transaction_id", data_type: "INTEGER", is_primary_key: true, is_foreign_key: false }, + { name: "account_id", col: "account_id", data_type: "INTEGER", is_primary_key: false, is_foreign_key: true }, + { name: "transaction_date", col: "transaction_date", data_type: "DATE", 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, name: "customers", + tbl: "customers", // Add tbl field for consistency table_type: "dimension", columns: [ - { name: "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: "email", data_type: "VARCHAR(100)", is_primary_key: false, is_foreign_key: false } + { name: "customer_id", col: "customer_id", data_type: "INTEGER", is_primary_key: true, is_foreign_key: false }, + { name: "customer_name", col: "customer_name", 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('Database received:', database?.name); 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 newEdges = []; // No edges - removing all connections + const newEdges = []; // Will be populated with relationship edges // Process the selected database console.log('Generating ER diagram for database:', database?.name); @@ -1370,6 +1429,12 @@ const ERDiagramCanvasContent = () => { schemaLayout.schema.tables.forEach((table, tableIndex) => { 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) const tableX = tableStartX + (currentCol * tableSpacing); const tableY = tableStartY + (currentRow * tableRowSpacing); @@ -1391,17 +1456,63 @@ const ERDiagramCanvasContent = () => { // Add primary key and foreign key indicators to columns based on relationships const enhancedColumns = (table.columns || []).map((col, colIndex) => { - // Check if this column is a foreign key based on relationships - const isForeignKey = database.relationships?.some(rel => - rel.targetTable === table.tbl && - rel.targetSchema === schemaLayout.schema.sch && - rel.targetColumn === col.col - ) || false; + // Get table identifier - use table_slug from API or fallback to name + const tableSlug = table.tbl || table.table_slug || table.name; + // Get schema identifier + const schemaSlug = schemaLayout.schema.sch || schemaLayout.schema.schema_slug || schemaLayout.schema.name; + // Get column identifier - use column_slug from the column data + 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 { ...col, 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); database.relationships.forEach((relationship, index) => { - // Find source and target table nodes - 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 + // Find source and target table nodes by matching table names and schemas const sourceNode = newNodes.find(node => node.type === 'erTable' && - (node.id === sourceTableId || - node.id.includes(relationship.sourceTable) && - node.data?.schema === relationship.sourceSchema) + node.data?.schema === relationship.sourceSchema && + (node.data?.name === relationship.sourceTable || node.data?.tbl === relationship.sourceTable) ); const targetNode = newNodes.find(node => node.type === 'erTable' && - (node.id === targetTableId || - node.id.includes(relationship.targetTable) && - node.data?.schema === relationship.targetSchema) + node.data?.schema === relationship.targetSchema && + (node.data?.name === relationship.targetTable || node.data?.tbl === relationship.targetTable) ); if (sourceNode && targetNode) { diff --git a/src/components/ERDiagramCanvas.scss b/src/components/ERDiagramCanvas.scss index 8c76b7a..d4279b1 100644 --- a/src/components/ERDiagramCanvas.scss +++ b/src/components/ERDiagramCanvas.scss @@ -265,6 +265,124 @@ 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 .er-relationship-edge { stroke: #8a2be2; diff --git a/src/components/children/Pipelines.jsx b/src/components/children/Pipelines.jsx index e69de29..147cf23 100644 --- a/src/components/children/Pipelines.jsx +++ b/src/components/children/Pipelines.jsx @@ -0,0 +1,7 @@ +export const Pipelines=()=>{ + return( +
+ Pipelines +
+ ) +} \ No newline at end of file -- 2.40.1