Merge pull request 'Added HierarchicalBreadcrumb in the Data Mappings SCreen' (#13) from develop into main

Reviewed-on: #13
This commit is contained in:
Devika Vellikkunnathillam 2025-06-19 06:52:32 +00:00
commit 65f51880e9
4 changed files with 253 additions and 39 deletions

View File

@ -922,7 +922,6 @@ const AddTableModal = ({
</TableCell> </TableCell>
<TableCell>Column Name</TableCell> <TableCell>Column Name</TableCell>
<TableCell>Sequence</TableCell> <TableCell>Sequence</TableCell>
<TableCell width="100">Actions</TableCell>
</TableRow> </TableRow>
</TableHead> </TableHead>
<TableBody> <TableBody>
@ -962,17 +961,6 @@ const AddTableModal = ({
<Typography variant="body2" color="text.secondary">-</Typography> <Typography variant="body2" color="text.secondary">-</Typography>
)} )}
</TableCell> </TableCell>
<TableCell>
{isSelected && (
<IconButton
size="small"
color="error"
onClick={() => removeColumnFromKey(selectedKeyForColumns, column.id)}
>
<DeleteIcon />
</IconButton>
)}
</TableCell>
</TableRow> </TableRow>
); );
})} })}
@ -991,9 +979,6 @@ const AddTableModal = ({
- -
</Typography> </Typography>
</TableCell> </TableCell>
<TableCell>
<AddIcon style={{ color: '#ccc' }} />
</TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> </Table>

View File

@ -129,12 +129,15 @@ const generateCustomStyles = () => {
}; };
// Import icons from react-icons // Import icons from react-icons
import { FaTable, FaArrowRight, FaExchangeAlt, FaFilter, FaCode, FaSync, FaCalculator, FaChartLine, FaEdit, FaTrash } from 'react-icons/fa'; import { FaTable, FaArrowRight, FaExchangeAlt, FaFilter, FaCode, FaSync, FaCalculator, FaChartLine, FaEdit, FaTrash, FaChevronDown } from 'react-icons/fa';
import { BiSolidData, BiTransfer } from 'react-icons/bi'; import { BiSolidData, BiTransfer } from 'react-icons/bi';
import { AiFillFolder } from 'react-icons/ai'; import { AiFillFolder } from 'react-icons/ai';
import { TbTransform } from 'react-icons/tb'; import { TbTransform } from 'react-icons/tb';
import { CustomDatabaseIcon, CustomDocumentIcon, CustomDimensionIcon, CustomProcessIcon, CustomSchemaIcon } from './CustomIcons'; import { CustomDatabaseIcon, CustomDocumentIcon, CustomDimensionIcon, CustomProcessIcon, CustomSchemaIcon } from './CustomIcons';
// Import Material-UI components for breadcrumb
import { Breadcrumbs, Link, Typography, Menu, MenuItem, ListItemIcon, ListItemText } from '@mui/material';
// Import API data // Import API data
import mockApiData, { useApiData, createSchema, deleteSchema, updateSchema, createTable, updateTable, deleteTable, createColumn, updateColumn, deleteColumn, fetchColumns } from './mockData'; import mockApiData, { useApiData, createSchema, deleteSchema, updateSchema, createTable, updateTable, deleteTable, createColumn, updateColumn, deleteColumn, fetchColumns } from './mockData';
@ -1450,6 +1453,132 @@ const DataflowCanvas = ({ dbSlug, hasSchemas = true }) => {
<div>Loading data from API...</div> <div>Loading data from API...</div>
</div> </div>
); );
// Hierarchical Breadcrumb Component
const HierarchicalBreadcrumb = () => {
const [dataMappingsMenuAnchor, setDataMappingsMenuAnchor] = useState(null);
const [selectedView, setSelectedView] = useState('Data Flow View');
const handleDataMappingsClick = (event) => {
setDataMappingsMenuAnchor(event.currentTarget);
};
const handleDataMappingsClose = () => {
setDataMappingsMenuAnchor(null);
};
const handleViewSelect = (view) => {
setSelectedView(view);
setDataMappingsMenuAnchor(null);
// Handle navigation based on selected view
if (view === 'Pipelines') {
// Add logic to switch to Pipelines view
console.log('Switching to Pipelines view');
// You can add navigation logic here
} else {
// Data Flow View is the current view
console.log('Staying in Data Flow View');
}
};
return (
<>
<div style={{
marginBottom: '16px',
padding: '8px 0'
}}>
<Breadcrumbs
aria-label="breadcrumb"
separator=""
sx={{
'& .MuiBreadcrumbs-separator': {
color: 'black',
margin: '0 8px',
},
fontSize: '14px',
}}
>
<Link
underline="hover"
color="black"
href="#"
onClick={(e) => e.preventDefault()}
sx={{ fontWeight: 500 }}
>
Qubit
</Link>
{/* Data Mappings Dropdown */}
<div
style={{
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
color: '#023020',
fontWeight: 500
}}
onClick={handleDataMappingsClick}
>
<Typography
color="#023020"
sx={{ fontWeight: 500, cursor: 'pointer' }}
>
Data Mappings
</Typography>
<FaChevronDown
style={{
marginLeft: '4px',
fontSize: '12px',
transform: dataMappingsMenuAnchor ? 'rotate(180deg)' : 'rotate(0deg)',
transition: 'transform 0.2s ease'
}}
/>
</div>
{/* Selected View */}
<Typography color="#301934">{selectedView}</Typography>
</Breadcrumbs>
</div>
{/* Data Mappings Menu */}
<Menu
anchorEl={dataMappingsMenuAnchor}
open={Boolean(dataMappingsMenuAnchor)}
onClose={handleDataMappingsClose}
PaperProps={{
sx: {
mt: 1,
minWidth: 180,
'& .MuiMenuItem-root': {
px: 2,
py: 1,
},
},
}}
>
<MenuItem
onClick={() => handleViewSelect('Data Flow View')}
selected={selectedView === 'Data Flow View'}
>
<ListItemIcon>
<FaExchangeAlt size={16} />
</ListItemIcon>
<ListItemText primary="Data Flow View" />
</MenuItem>
<MenuItem
onClick={() => handleViewSelect('Pipelines')}
selected={selectedView === 'Pipelines'}
>
<ListItemIcon>
<FaArrowRight size={16} />
</ListItemIcon>
<ListItemText primary="Pipelines" />
</MenuItem>
</Menu>
</>
);
};
// Log error but continue with mockApiData as fallback // Log error but continue with mockApiData as fallback
useEffect(() => { useEffect(() => {
@ -1458,13 +1587,6 @@ const DataflowCanvas = ({ dbSlug, hasSchemas = true }) => {
} }
}, [error]); }, [error]);
// Create a loading component
// const LoadingComponent = () => (
// <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', height: '100%' }}>
// <div>Loading data from API...</div>
// </div>
// );
// Log error but continue with mockApiData as fallback // Log error but continue with mockApiData as fallback
useEffect(() => { useEffect(() => {
if (error) { if (error) {
@ -3245,7 +3367,7 @@ const DataflowCanvas = ({ dbSlug, hasSchemas = true }) => {
<div style={{ <div style={{
padding: '10px 15px', padding: '10px 15px',
background: 'linear-gradient(90deg, #00a99d, #52c41a)', background: 'linear-gradient(90deg, #00a99d, #52c41a)',
color: 'white', color: 'black',
display: 'flex', display: 'flex',
alignItems: 'center', alignItems: 'center',
justifyContent: 'space-between', justifyContent: 'space-between',
@ -3257,8 +3379,9 @@ const DataflowCanvas = ({ dbSlug, hasSchemas = true }) => {
<path d="M19.8845 24.789C17.0714 24.789 14.2465 24.0672 12.912 22.5097C12.8725 22.683 12.8462 22.8607 12.8462 23.0493V25.8844C12.8462 28.3962 16.4937 29.5392 19.8845 29.5392C23.2753 29.5392 26.9228 28.3962 26.9228 25.8844V23.0493C26.9228 22.8607 26.8964 22.6837 26.8569 22.5104C25.5217 24.068 22.6976 24.7904 19.8837 24.7904L19.8845 24.789ZM19.8845 19.3083C17.0714 19.3083 14.2465 18.5865 12.9127 17.0289C12.8706 17.2053 12.8486 17.3858 12.8469 17.5671V20.4022C12.8469 22.9133 16.4937 24.0563 19.8845 24.0563C23.2753 24.0563 26.9228 22.9133 26.9228 20.4015V17.5657C26.9228 17.3778 26.8964 17.2001 26.8569 17.0268C25.5217 18.5843 22.6976 19.3068 19.8837 19.3068L19.8845 19.3083ZM19.8845 8.42944C16.4937 8.42944 12.8462 9.57385 12.8462 12.0857V14.9208C12.8462 17.4326 16.4937 18.5755 19.8845 18.5755C23.2753 18.5755 26.9228 17.4333 26.9228 14.9215V12.0864C26.9228 9.57458 23.2753 8.43017 19.8845 8.43017V8.42944ZM19.8845 14.2794C16.8059 14.2794 14.3087 13.2974 14.3087 12.0857C14.3087 10.8747 16.8052 9.89194 19.8845 9.89194C22.9638 9.89194 25.4603 10.8747 25.4603 12.0857C25.4603 13.2981 22.9638 14.2794 19.8845 14.2794Z" fill="white"/> <path d="M19.8845 24.789C17.0714 24.789 14.2465 24.0672 12.912 22.5097C12.8725 22.683 12.8462 22.8607 12.8462 23.0493V25.8844C12.8462 28.3962 16.4937 29.5392 19.8845 29.5392C23.2753 29.5392 26.9228 28.3962 26.9228 25.8844V23.0493C26.9228 22.8607 26.8964 22.6837 26.8569 22.5104C25.5217 24.068 22.6976 24.7904 19.8837 24.7904L19.8845 24.789ZM19.8845 19.3083C17.0714 19.3083 14.2465 18.5865 12.9127 17.0289C12.8706 17.2053 12.8486 17.3858 12.8469 17.5671V20.4022C12.8469 22.9133 16.4937 24.0563 19.8845 24.0563C23.2753 24.0563 26.9228 22.9133 26.9228 20.4015V17.5657C26.9228 17.3778 26.8964 17.2001 26.8569 17.0268C25.5217 18.5843 22.6976 19.3068 19.8837 19.3068L19.8845 19.3083ZM19.8845 8.42944C16.4937 8.42944 12.8462 9.57385 12.8462 12.0857V14.9208C12.8462 17.4326 16.4937 18.5755 19.8845 18.5755C23.2753 18.5755 26.9228 17.4333 26.9228 14.9215V12.0864C26.9228 9.57458 23.2753 8.43017 19.8845 8.43017V8.42944ZM19.8845 14.2794C16.8059 14.2794 14.3087 13.2974 14.3087 12.0857C14.3087 10.8747 16.8052 9.89194 19.8845 9.89194C22.9638 9.89194 25.4603 10.8747 25.4603 12.0857C25.4603 13.2981 22.9638 14.2794 19.8845 14.2794Z" fill="white"/>
</svg> </svg>
<div> <div>
<h2 style={{ margin: 0, fontSize: '18px' }}>{selectedDatabase.name} Database</h2> <h2 style={{ margin: 0, fontSize: '18px', color: 'black' }}>{selectedDatabase.name} Database</h2>
<div style={{ fontSize: '12px', opacity: 0.9 }}>Data Flow View</div> {/* <div style={{ fontSize: '12px', opacity: 0.9 }}>Data Flow View</div> */}
<HierarchicalBreadcrumb />
</div> </div>
</div> </div>
<div> <div>

View File

@ -64,12 +64,15 @@ const generateCustomStyles = () => {
}; };
// Import icons from react-icons // Import icons from react-icons
import { FaDatabase, FaTable, FaArrowRight, FaExchangeAlt } from 'react-icons/fa'; import { FaDatabase, FaTable, FaArrowRight, FaExchangeAlt, FaChevronDown } from 'react-icons/fa';
import { BiSolidData } from 'react-icons/bi'; import { BiSolidData } from 'react-icons/bi';
import { AiFillFolder } from 'react-icons/ai'; import { AiFillFolder } from 'react-icons/ai';
import { BsFileEarmarkSpreadsheet } from 'react-icons/bs'; import { BsFileEarmarkSpreadsheet } from 'react-icons/bs';
import { CustomProcessIcon, CustomSchemaIcon } from './CustomIcons'; import { CustomProcessIcon, CustomSchemaIcon } from './CustomIcons';
// Import Material-UI components for breadcrumb
import { Breadcrumbs, Link, Typography, Menu, MenuItem, ListItemIcon, ListItemText } from '@mui/material';
// Import mock data // Import mock data
import mockApiData from './mockData'; import mockApiData from './mockData';
@ -533,6 +536,24 @@ const DataflowCanvas = () => {
const [showTableForm, setShowTableForm] = useState(false); const [showTableForm, setShowTableForm] = useState(false);
const [selectedTableForEdit, setSelectedTableForEdit] = useState(null); const [selectedTableForEdit, setSelectedTableForEdit] = useState(null);
// Breadcrumb state
const [serviceMenuAnchor, setServiceMenuAnchor] = useState(null);
const [selectedService, setSelectedService] = useState('Data Mappings');
// Breadcrumb handlers
const handleServiceClick = (event) => {
setServiceMenuAnchor(event.currentTarget);
};
const handleServiceClose = () => {
setServiceMenuAnchor(null);
};
const handleServiceSelect = (service) => {
setSelectedService(service);
setServiceMenuAnchor(null);
};
// Get the React Flow instance // Get the React Flow instance
const reactFlowInstance = useReactFlow(); const reactFlowInstance = useReactFlow();
@ -1210,8 +1231,104 @@ const DataflowCanvas = () => {
}; };
}, []); }, []);
// Debug log to verify component is rendering
console.log('DataflowCanvas rendering with selectedService:', selectedService);
return ( return (
<div style={{ width: '100%', height: '100vh' }}> <div style={{ width: '100%', height: '100vh' }}>
{/* Breadcrumb */}
<div style={{
position: 'fixed',
top: '20px',
left: '20px',
zIndex: 9999,
background: 'rgba(255, 255, 255, 0.98)',
padding: '12px 16px',
borderRadius: '8px',
boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
backdropFilter: 'blur(8px)',
border: '1px solid rgba(0, 0, 0, 0.1)'
}}>
<Breadcrumbs
aria-label="breadcrumb"
separator=""
sx={{
'& .MuiBreadcrumbs-separator': {
color: '#666',
margin: '0 8px',
},
fontSize: '14px',
}}
>
<Link
underline="hover"
color="primary"
href="#"
onClick={(e) => e.preventDefault()}
sx={{ fontWeight: 500 }}
>
Qubit
</Link>
{/* Data Mappings/Pipelines Dropdown */}
<div
style={{
display: 'flex',
alignItems: 'center',
cursor: 'pointer',
color: '#1976d2',
fontWeight: 500
}}
onClick={handleServiceClick}
>
<Typography
color="primary"
sx={{ fontWeight: 500, cursor: 'pointer' }}
>
{selectedService}
</Typography>
<FaChevronDown
style={{
marginLeft: '4px',
fontSize: '12px',
transform: serviceMenuAnchor ? 'rotate(180deg)' : 'rotate(0deg)',
transition: 'transform 0.2s ease'
}}
/>
</div>
</Breadcrumbs>
</div>
{/* Services Menu */}
<Menu
anchorEl={serviceMenuAnchor}
open={Boolean(serviceMenuAnchor)}
onClose={handleServiceClose}
PaperProps={{
sx: {
mt: 1,
minWidth: 180,
'& .MuiMenuItem-root': {
px: 2,
py: 1,
},
},
}}
>
<MenuItem onClick={() => handleServiceSelect('Data Mappings')}>
<ListItemIcon>
<FaExchangeAlt size={16} />
</ListItemIcon>
<ListItemText primary="Data Mappings" />
</MenuItem>
<MenuItem onClick={() => handleServiceSelect('Pipelines')}>
<ListItemIcon>
<FaArrowRight size={16} />
</ListItemIcon>
<ListItemText primary="Pipelines" />
</MenuItem>
</Menu>
<ReactFlow <ReactFlow
nodes={nodes} nodes={nodes}
edges={edges} edges={edges}
@ -1294,7 +1411,7 @@ const DataflowCanvas = () => {
// Wrap with ReactFlowProvider // Wrap with ReactFlowProvider
const DataflowCanvasWithProvider = () => ( const DataflowCanvasWithProvider = () => (
<ReactFlowProvider> <ReactFlowProvider>
<DataflowCanvasUpdated /> <DataflowCanvas />
</ReactFlowProvider> </ReactFlowProvider>
); );

View File

@ -1104,17 +1104,6 @@ const ServiceNode = ({ data = {} }) => {
}} }}
onClick={() => data.onToggle && data.onToggle(data.id)} onClick={() => data.onToggle && data.onToggle(data.id)}
> >
{data.expanded ? (
<>
<span>Collapse Connections</span>
<FaChevronUp size={10} />
</>
) : (
<>
<span>Expand Connections</span>
<FaChevronDown size={10} />
</>
)}
</button> </button>
</div> </div>