From 8d3ec47df90905a98f1d8d77ce40a8cee07c8b18 Mon Sep 17 00:00:00 2001 From: emekauja Date: Tue, 8 Nov 2022 13:52:58 +0100 Subject: [PATCH] #44 fix: use constant for expand and selected --- src/components/common/Breadcrumbs.js | 11 +- src/components/common/Header.js | 15 +- .../sidebar/TreeView/InstanceTreeView.js | 384 ++++++++++++++++++ 3 files changed, 398 insertions(+), 12 deletions(-) create mode 100644 src/components/views/sidebar/TreeView/InstanceTreeView.js diff --git a/src/components/common/Breadcrumbs.js b/src/components/common/Breadcrumbs.js index 8857d2e8..ecc8da79 100644 --- a/src/components/common/Breadcrumbs.js +++ b/src/components/common/Breadcrumbs.js @@ -77,6 +77,8 @@ const useStyles = makeStyles(() => ({ }, })); +const expand = 'expand'; + function Crumb({ id, text, handleClick, href, last = false }) { const classes = useStyles(); @@ -104,8 +106,6 @@ function Crumb({ id, text, handleClick, href, last = false }) { ); } -const expand = { id: 'expandButton', text: 'expand' }; - export const CustomBreadcrumbsWithMenu = ({ breadcrumbs }) => { const classes = useStyles(); const [anchorEl, setAnchorEl] = React.useState(null); @@ -136,7 +136,10 @@ export const CustomBreadcrumbsWithMenu = ({ breadcrumbs }) => { const restCrumbs = breadcrumbs.slice(1, breadcrumbs.length - 4); const lastFourCrumbs = breadcrumbs.slice(-4); - const newBreadCrumbs = firstItemCrumbs.concat([expand], lastFourCrumbs); + const newBreadCrumbs = firstItemCrumbs.concat( + [{ id: expand }], + lastFourCrumbs + ); setCollapsedCrumbs(restCrumbs); return newBreadCrumbs; @@ -176,7 +179,7 @@ export const CustomBreadcrumbsWithMenu = ({ breadcrumbs }) => { _breadcrumbs.map((crumb, idx) => { const index = idx + 1; - if (crumb.id === 'expandButton') { + if (crumb.id === expand) { return ( { const classes = useStyles(); const [anchorEl, setAnchorEl] = React.useState(null); + const [selected, setSelected] = React.useState('Build'); const open = Boolean(anchorEl); - const handleClick = (event) => { + const handleClick = (event, value) => { if (event) { - setAnchorEl(event.currentTarget); + if (value === 'Composition') { + setAnchorEl(event.currentTarget); + } } }; @@ -162,14 +165,10 @@ const Header = () => { {listItems.map((item) => { return ( { - if (item.label === 'Composition') { - handleClick(e); - } - }} + onClick={(e) => handleClick(e, item.label)} > {item.label} {item.soon && } diff --git a/src/components/views/sidebar/TreeView/InstanceTreeView.js b/src/components/views/sidebar/TreeView/InstanceTreeView.js new file mode 100644 index 00000000..e44f6223 --- /dev/null +++ b/src/components/views/sidebar/TreeView/InstanceTreeView.js @@ -0,0 +1,384 @@ +import React, { useEffect, useState } from 'react'; +import TreeView from '@mui/lab/TreeView'; +import StyledTreeItem from './TreeViewItem'; +import { + FileIcon, + ShapeArrowToolIcon, + CircleIcon, + CloseIcon, + ArrowDropDownIcon, + ArrowRightIcon, +} from './Icons'; +import { + Accordion, + AccordionDetails, + AccordionSummary, + Box, + IconButton, + Popover, + Stack, + Typography, +} from '@mui/material'; +import vars from '../../../../assets/styles/variables'; +import { makeStyles } from '@mui/styles'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; + +export const GRAPH_SOURCE = 'GRAPH'; +export const TREE_SOURCE = 'TREE'; +const { + popperBG, + listSelectedTextColor, + cardBG, + nodeSecLabelColor, + dropdownBorderColor, + dropdownTextColor, + functionTextColor, + functionCodeColor, +} = vars; + +const useStyles = makeStyles(() => ({ + popperHeader: { + padding: '0.5rem', + display: 'flex', + marginBottom: '0.5rem', + justifyContent: 'space-between', + alignItems: 'center', + + '& .MuiBox-root': { + display: 'flex', + alignItems: 'center', + + '& strong': { + display: 'block', + fontWeight: 500, + fontSize: '0.875rem', + lineHeight: '1.25rem', + color: listSelectedTextColor, + paddingLeft: '0.5rem', + }, + + '& span': { + display: 'block', + fontWeight: 500, + fontSize: '0.8125rem', + lineHeight: '1rem', + letterSpacing: '-0.005rem', + color: dropdownTextColor, + }, + }, + }, + block: { + flex: 1, + background: cardBG, + borderRadius: '0.5rem', + + '& label': { + display: 'block', + fontWeight: '400', + fontSize: '0.625rem', + lineHeight: '0.875rem', + color: nodeSecLabelColor, + }, + '& .text': { + maxWidth: 'calc(16.25rem - 3rem)', + fontSize: '0.875rem', + fontWeight: 400, + lineHeight: '1rem', + letterSpacing: '0.005em', + whiteSpace: 'nowrap', + }, + '& .function': { + maxWidth: 'calc(16.25rem - 2rem)', + whiteSpace: 'nowrap', + fontSize: '0.875rem', + fontWeight: 400, + lineHeight: '1rem', + letterSpacing: '0.005em', + + '& .MuiTypography-root': { + marginTop: '0.25rem', + fontSize: '0.875rem', + lineHeight: '1rem', + letterSpacing: '0.005em', + wordBreak: 'break-all', + '& strong': { + fontWeight: 400, + }, + }, + }, + }, + + textColor: { + color: functionTextColor, + }, + codeColor: { + color: functionCodeColor, + }, + seperator: { + width: '0.125rem', + height: '1rem', + borderRadius: '1.25rem', + margin: '0.25rem auto', + }, + accordion: { + background: cardBG, + boxShadow: 'none', + borderRadius: '0.5rem !important', + }, + paddingXS: { + padding: '0.5rem', + }, +})); + +const popperPaperProps = { + style: { + width: '16.25rem', + height: '17.5rem', + padding: '0.5rem', + background: popperBG, + boxShadow: + '0 0.5rem 0.5rem -0.25rem rgba(24, 24, 24, 0.03), 0 1.25rem 1.5rem -0.25rem rgba(24, 24, 24, 0.08', + borderRadius: '0.75rem', + inset: '1rem auto auto 0 !important', + borderWidth: '1px', + borderColor: dropdownBorderColor, + borderStyle: 'solid', + }, +}; + +const initialRightClickStateCreator = () => ({ + mouseX: null, + mouseY: null, +}); + +const InstancesTreeView = (props) => { + const { datasets } = props; + const classes = useStyles(); + + const [right, setRight] = useState(() => initialRightClickStateCreator()); + const open = Boolean(right.mouseY); + + const [selectedNodes, setSelectedNodes] = useState([]); + const [selectedNodeId, setSelectedNodeId] = useState(null); + const [nodes, setNodes] = useState([]); + const [items, setItems] = useState(datasets); + + const onNodeSelect = (e, nodeId) => { + setSelectedNodeId(nodeId); + }; + + const onNodeToggle = (e, nodeIds) => { + // TODO uncommented after proper test + // if (nodeIds.length === 0) { + // return; + // } + + if (nodes.length !== nodeIds.length && nodes[0] === nodeIds[0]) { + var original = [...nodes]; + var newPath = [...nodeIds]; + while (original[0] === newPath[0]) { + original.shift(); + newPath.shift(); + } + nodeIds = original; + } + + setNodes(nodeIds); + }; + + function handleClick(e, nodes_ids) { + if (e.target.className == 'MuiTreeItem-label') setSelectedNodes(nodes_ids); + } + + function onRightClick(event, node) { + event.preventDefault(); + event.stopPropagation(); + if (node.type === 'COMPOSITION') { + setRight({ + mouseX: event.clientX - 360, + mouseY: event.clientY - 8, + }); + } + } + + function onClose() { + setRight(initialRightClickStateCreator()); + } + + // Initialize state in this hook + useEffect(() => { + // Populate tree items state with datasets + if (items.length === 0 && datasets.length > 0) { + setItems(datasets); + } else if (datasets.length > 0 && items.length !== datasets.length) { + // Update datasets, after adding a new dataset + setItems(datasets); + } + }, [datasets, items.length]); + + const getTreeItemsFromData = (treeItems) => { + if (Array.isArray(treeItems) && treeItems.length <= 0) return; + + return treeItems?.map((treeItemData) => { + let items = undefined; + if (treeItemData.items && treeItemData.items.length > 0) { + items = getTreeItemsFromData(treeItemData.items); + } + + const hidden = + !nodes.includes(treeItemData?.id) && + selectedNodeId !== treeItemData?.id && + treeItemData?.type === 'COMPOSITION'; + + const labelIcon = + treeItemData?.type === 'MECHANISM' ? ( + + ) : treeItemData?.type === 'COMPOSITION' ? ( + + ) : ( + + ); + + return ( +