diff --git a/src/client/components/common/Breadcrumbs.js b/src/client/components/common/Breadcrumbs.js index 249f96f8..a286dc77 100644 --- a/src/client/components/common/Breadcrumbs.js +++ b/src/client/components/common/Breadcrumbs.js @@ -1,225 +1,249 @@ import { - Box, - ClickAwayListener, - IconButton, - Link, - MenuItem, - Popper, - Typography, + Box, + ClickAwayListener, + IconButton, + Link, + MenuItem, + Popper, + Typography, } from '@mui/material'; -import React, { useMemo } from 'react'; +import React, {useMemo} from 'react'; import Breadcrumbs from '@mui/material/Breadcrumbs'; -import { makeStyles } from '@mui/styles'; +import {makeStyles} from '@mui/styles'; import ArrowRightIcon from '@mui/icons-material/KeyboardArrowRight'; -import ArrowDownIcon from '@mui/icons-material/KeyboardArrowDown'; import MoreHorizIcon from '@mui/icons-material/MoreHoriz'; import vars from '../../assets/styles/variables'; +import {useSelector, useDispatch} from 'react-redux'; +import {closeComposition, openComposition} from "../../redux/actions/general"; +import ModelSingleton from "../../model/ModelSingleton"; -const { dropdownSecBg, breadcrumbLinkColor, breadcrumbTextColor } = vars; + +const {dropdownSecBg, breadcrumbLinkColor, breadcrumbTextColor} = vars; const useStyles = makeStyles(() => ({ - crumb: { - fontWeight: 500, - fontSize: '0.875rem', - lineHeight: '1.25rem', - color: `${breadcrumbLinkColor} !important`, - }, - expand: { - padding: '0.125rem', - borderRadius: '0.25rem', - }, - lastCrumb: { - display: 'flex', - alignItems: 'center', - color: breadcrumbTextColor, - - '& .MuiTypography-root': { - fontWeight: 500, - fontSize: '0.875rem', - lineHeight: '1.25rem', - color: 'inherit', + crumb: { + fontWeight: 500, + fontSize: '0.875rem', + lineHeight: '1.25rem', + color: `${breadcrumbLinkColor} !important`, }, - }, - dropDown: { - width: '8rem', - maxWidth: 'content', - background: dropdownSecBg, - boxShadow: - '0 0.25rem 2.5rem rgba(0, 0, 0, 0.1), 0 1rem 7.5rem rgba(60, 60, 67, 0.2)', - padding: '0.375rem 0.25rem', - borderRadius: '0.5rem', - inset: '1rem auto auto 0 !important', - - '&:before': { - content: '""', - width: 0, - height: 0, - borderStyle: 'solid', - borderWidth: '0 0.75rem 0.75rem 0.75rem', - borderColor: `transparent transparent ${dropdownSecBg} transparent`, - position: 'absolute', - top: '-0.5rem', - left: '3rem', + expand: { + padding: '0.125rem', + borderRadius: '0.25rem', }, - - '& .MuiMenuItem-root': { - fontWeight: 500, - fontSize: '0.875rem', - lineHeight: '1.25rem', - whiteSpace: 'normal', - borderRadius: '0.375rem', - color: breadcrumbLinkColor, - padding: '0.25rem 0.5rem', - - '&:hover': { + lastCrumb: { + display: 'flex', + alignItems: 'center', color: breadcrumbTextColor, - }, + + '& .MuiTypography-root': { + fontWeight: 500, + fontSize: '0.875rem', + lineHeight: '1.25rem', + color: 'inherit', + }, + }, + dropDown: { + width: '8rem', + maxWidth: 'content', + background: dropdownSecBg, + boxShadow: + '0 0.25rem 2.5rem rgba(0, 0, 0, 0.1), 0 1rem 7.5rem rgba(60, 60, 67, 0.2)', + padding: '0.375rem 0.25rem', + borderRadius: '0.5rem', + inset: '1rem auto auto 0 !important', + + '&:before': { + content: '""', + width: 0, + height: 0, + borderStyle: 'solid', + borderWidth: '0 0.75rem 0.75rem 0.75rem', + borderColor: `transparent transparent ${dropdownSecBg} transparent`, + position: 'absolute', + top: '-0.5rem', + left: '3rem', + }, + + '& .MuiMenuItem-root': { + fontWeight: 500, + fontSize: '0.875rem', + lineHeight: '1.25rem', + whiteSpace: 'normal', + borderRadius: '0.375rem', + color: breadcrumbLinkColor, + padding: '0.25rem 0.5rem', + + '&:hover': { + color: breadcrumbTextColor, + }, + }, }, - }, })); const EXPAND_ID = 'expand'; +const HOME_ID = 'home' + +function Crumb({id, text, handleClick, href, last = false}) { + const classes = useStyles(); -function Crumb({ id, text, handleClick, href, last = false }) { - const classes = useStyles(); + if (last) { + return ( + + {text} + + ); + } - if (last) { return ( - - {text} - - + { + event.preventDefault(); + handleClick(); + }} + className={classes.crumb} + > + {text} + ); - } - - return ( - { - event.preventDefault(); - handleClick(); - }} - className={classes.crumb} - > - {text} - - ); } -export const CustomBreadcrumbsWithMenu = ({ breadcrumbs, max = 4}) => { - const classes = useStyles(); - const [anchorEl, setAnchorEl] = React.useState(null); - const [collapsedCrumbs, setCollapsedCrumbs] = React.useState([]); - const open = Boolean(anchorEl); - const collapsed = !!breadcrumbs && breadcrumbs.length > max; - - const handleClick = (event) => { - if (event && anchorEl === null) { - setAnchorEl(event.currentTarget); - } else if (anchorEl !== null) { - setAnchorEl(null); - } - }; +export const CustomBreadcrumbsWithMenu = ({max = 4}) => { + const classes = useStyles(); + const [anchorEl, setAnchorEl] = React.useState(null); + const compositionOpened = useSelector(state => state.general.compositionOpened); + const dispatch = useDispatch(); + const open = Boolean(anchorEl); + + const rawBreadcrumbs = compositionOpened?.getGraphPath() || []; - const handleClose = () => { - setAnchorEl(null); - }; + const breadcrumbs = [{id: HOME_ID, text: 'Home'}].concat( + rawBreadcrumbs.map((item, idx) => ({ + id: item, + text: item, + })) + ); + + const collapsed = !!breadcrumbs && breadcrumbs.length > max; + const collapsedCrumbs = collapsed ? breadcrumbs.slice(1, breadcrumbs.length - (max - 1)) : []; + + const _breadcrumbs = useMemo( + () => { + if (!!breadcrumbs && breadcrumbs.length > 0) { + if (breadcrumbs.length <= max) { + return breadcrumbs; + } - const id = open ? 'simple-popper-9' : undefined; + const firstItemCrumbs = breadcrumbs.slice(0, 1); + const lastFourCrumbs = breadcrumbs.slice(-(max - 1)); - const _breadcrumbs = useMemo( - function getBreadcrumbs() { - if (!!breadcrumbs && breadcrumbs.length > 0) { - if (breadcrumbs.length <= max) { - return breadcrumbs; + return firstItemCrumbs.concat( + [{id: EXPAND_ID}], + lastFourCrumbs + ); + } + + return []; + }, + [breadcrumbs, max] + ); + + + const handleCrumbClick = (id) => { + if (compositionOpened) { + dispatch(closeComposition(compositionOpened)); + } + if (id !== HOME_ID) { + const metaGraph = ModelSingleton.getInstance().getMetaGraph() + dispatch(openComposition(metaGraph.getNodeDFS(id))); } + }; - const firstItemCrumbs = breadcrumbs.slice(0, 1); - const restCrumbs = breadcrumbs.slice(1, breadcrumbs.length - (max - 1)); - const lastFourCrumbs = breadcrumbs.slice(-(max - 1)); - const newBreadCrumbs = firstItemCrumbs.concat( - [{ id: EXPAND_ID }], - lastFourCrumbs - ); - setCollapsedCrumbs(restCrumbs); + const handleClick = (event) => { + if (event && anchorEl === null) { + setAnchorEl(event.currentTarget); + } else if (anchorEl !== null) { + setAnchorEl(null); + } + }; - return newBreadCrumbs; - } + const handleClose = () => { + setAnchorEl(null); + }; - return undefined; - }, - [breadcrumbs, max] - ); - - return ( - - {collapsedCrumbs && collapsedCrumbs.length > 1 && ( - - - - {collapsedCrumbs && collapsedCrumbs.length > 1 - ? collapsedCrumbs.map((crumb) => ( - - {crumb.text} - - )) - : null} - - - - )} - - } - > - {_breadcrumbs && - _breadcrumbs.map((crumb, idx) => { - const index = idx + 1; - - if (crumb.id === EXPAND_ID) { - return ( - - - - - - ); - } + const id = open ? 'simple-popper-9' : undefined; - return ( - - ); - })} - - - ); + return ( + + {collapsedCrumbs && collapsedCrumbs.length > 1 && ( + + + + {collapsedCrumbs && collapsedCrumbs.length > 1 + ? collapsedCrumbs.map((crumb) => ( + + {crumb.text} + + )) + : null} + + + + )} + + } + > + {_breadcrumbs && + _breadcrumbs.map((crumb, idx) => { + const index = idx + 1; + + if (crumb.id === EXPAND_ID) { + return ( + + + + + + ); + } + + return ( + handleCrumbClick(crumb.id)} + /> + ); + })} + + + ); }; diff --git a/src/client/components/common/Header.js b/src/client/components/common/Header.js index f233f6e8..6a5760aa 100644 --- a/src/client/components/common/Header.js +++ b/src/client/components/common/Header.js @@ -24,7 +24,8 @@ const useStyles = makeStyles(() => ({ display: 'flex', alignItems: 'center', border: `1px solid ${headerBorderColor}`, - inset: '1rem auto auto 0 !important', + position: 'relative', + zIndex: 9999, }, leftSection: { @@ -91,18 +92,6 @@ const useStyles = makeStyles(() => ({ }, })); -const breadcrumbs = [ - { id: 'home', text: 'Home' }, - { id: 'breadSubItem1', text: 'breadSubItem1' }, - { id: 'breadSubItem2', text: 'breadSubItem2' }, - { id: 'breadSubItem3', text: 'breadSubItem3' }, - { id: 'breadSubItem4', text: 'breadSubItem4' }, - { id: 'breadSubItem5', text: 'breadSubItem5' }, - { id: 'breadSubItem6', text: 'breadSubItem6' }, - { id: 'breadSubItem7', text: 'breadSubItem7' }, - { id: 'composition2', text: 'Composition 2' }, -]; - const listItems = [ { label: 'Build', value: 'build', soon: false, action: GUIViews.EDIT}, { label: 'Visualise', value: 'visualise', soon: false, action: GUIViews.VIEW}, @@ -127,7 +116,7 @@ const Header = () => { new-logo - + diff --git a/src/client/components/views/editView/mechanisms/GenericMechanism.js b/src/client/components/views/editView/mechanisms/GenericMechanism.js index 7d18838e..085140ac 100644 --- a/src/client/components/views/editView/mechanisms/GenericMechanism.js +++ b/src/client/components/views/editView/mechanisms/GenericMechanism.js @@ -89,6 +89,7 @@ class GenericMechanism extends React.Component { } changeVisibility() { + this.props.model.isExpanded = !this.state.expanded; this.setState({expanded: !this.state.expanded}); } diff --git a/src/client/components/views/editView/mechanisms/InputOutputNode.js b/src/client/components/views/editView/mechanisms/InputOutputNode.js index 4dea3395..b63b688c 100644 --- a/src/client/components/views/editView/mechanisms/InputOutputNode.js +++ b/src/client/components/views/editView/mechanisms/InputOutputNode.js @@ -1,18 +1,21 @@ import * as React from "react"; import { Box, Typography } from "@mui/material"; +import {PortWidget} from "@projectstorm/react-diagrams"; class InputOutputNode extends React.Component { - render() { - const { text, direction } = this.props; - const nodeClass = direction === 'right' ? 'block reverse' : 'block'; + render() { + const { text, direction, engine, port } = this.props; + const nodeClass = direction === 'right' ? 'block reverse' : 'block'; - return ( - - - {text} - - ); - } + return ( + + + + + {text} + + ); + } } export default InputOutputNode; diff --git a/src/client/components/views/editView/mechanisms/MechMetadata.js b/src/client/components/views/editView/mechanisms/MechMetadata.js index 75e2aaa9..de887165 100644 --- a/src/client/components/views/editView/mechanisms/MechMetadata.js +++ b/src/client/components/views/editView/mechanisms/MechMetadata.js @@ -1,108 +1,117 @@ import * as React from "react"; import Box from "@mui/material/Box"; -import { withStyles } from "@mui/styles"; +import {withStyles} from "@mui/styles"; import NodeSelection from "./NodeSelection"; import InputOutputNode from "./InputOutputNode"; -// import TextField from '@mui/material/TextField'; import Typography from "@mui/material/Typography"; -import { PortTypes, PortWidget } from "@metacell/meta-diagram"; +import {PortTypes} from "@metacell/meta-diagram"; import vars from "../../../../assets/styles/variables"; const styles = { - textColor: { - color: vars.functionTextColor - }, - codeColor: { - color: vars.functionCodeColor - } + textColor: { + color: vars.functionTextColor + }, + codeColor: { + color: vars.functionCodeColor + }, }; class MechMetadata extends React.Component { - render() { - const { classes, model, model: { options }, engine, changeVisibility } = this.props; - console.log(classes) - const functionValues = (label, value) => ( - - {label} - {/* {console.log(e)} } - variant="outlined" - style={{ zIndex: 11 }} - /> */} - {value} - - ) - return ( - - {options.selected && ( - - )} - - - - {options.name} - - + constructor() { + super(); + this.elementRef = React.createRef(); + } - - { options.ports.map(port => { - switch (port.getType()) { - case PortTypes.INPUT_PORT: - return ( - - - - ); - default: - return <> - } - })} - + componentDidMount() { + this.forceUpdate() // so that we get the ref to the element + } - + componentDidUpdate(prevProps, prevState, snapshot) { + const parentElement = this.elementRef.current.parentElement; + parentElement.style.clipPath = ''; + parentElement.style.zIndex = 10000; + } - - { - functionValues('Context', '12') - } - { - functionValues('Size', '8.90') - } - { - functionValues('Prefs', '44') - } + render() { + const {classes, model, model: {options}, engine, changeVisibility} = this.props; + const functionValues = (label, value) => ( - Function - - - function - =pnl.Logistic(gain=1.0, bias=-4) + {label} + {value} - + ) + + return ( + + {options.selected && ( + + )} + + + + {options.name} + + - + + {options.ports.map(port => { + switch (port.getType()) { + case PortTypes.INPUT_PORT: + return ( + + ); + default: + return <> + } + })} + - - { options.ports.map(port => { - switch (port.getType()) { - case PortTypes.OUTPUT_PORT: - return ( - - - - ); - default: - return <> - } - })} - - - ); - } + + + + { + functionValues('Context', '12') + } + { + functionValues('Size', '8.90') + } + { + functionValues('Prefs', '44') + } + + Function + + + function + =pnl.Logistic(gain=1.0, + bias=-4) + + + + + + + {options.ports.map(port => { + switch (port.getType()) { + case PortTypes.OUTPUT_PORT: + return ( + + ) + ; + default: + return <> + } + })} + + + ); + } } export default withStyles(styles)(MechMetadata); diff --git a/src/client/components/views/editView/mechanisms/MechSimple.js b/src/client/components/views/editView/mechanisms/MechSimple.js index e5719193..5b658593 100644 --- a/src/client/components/views/editView/mechanisms/MechSimple.js +++ b/src/client/components/views/editView/mechanisms/MechSimple.js @@ -2,7 +2,6 @@ import * as React from "react"; import NodeSelection from "./NodeSelection"; import {Box, Typography} from "@mui/material"; import {PortWidget, PortTypes, CallbackTypes} from "@metacell/meta-diagram"; -import {clipPathBorderSize} from "../../../../../constants"; import {getClipPath} from "../../../../services/clippingService"; import ModelSingleton from "../../../../model/ModelSingleton"; @@ -59,7 +58,7 @@ class MechSimple extends React.Component { getMechClipPath(parentNode) { const {model} = this.props; - return parentNode ? getClipPath(parentNode, model, clipPathBorderSize) : null + return parentNode ? getClipPath(parentNode, model) : null } getListenerID(node) { diff --git a/src/client/components/views/editView/projections/CustomLinkWidget.js b/src/client/components/views/editView/projections/CustomLinkWidget.js index ef607366..9ed59a62 100644 --- a/src/client/components/views/editView/projections/CustomLinkWidget.js +++ b/src/client/components/views/editView/projections/CustomLinkWidget.js @@ -3,11 +3,10 @@ import {DefaultLinkWidget} from '@projectstorm/react-diagrams'; import {projectionLink, projectionLinkArrow} from "../../../../assets/styles/variables"; import ModelSingleton from "../../../../model/ModelSingleton"; import { - updateLinkPoints + getEdgePoint, updateLinkPoints } from "../../../../services/clippingService"; import {CallbackTypes} from "@metacell/meta-diagram"; -const pointlength = 6; /** * CustomLinkArrowWidget is a functional React component that renders a custom arrow for the link. @@ -19,12 +18,13 @@ const pointlength = 6; */ const CustomLinkArrowWidget = (props) => { const {point, previousPoint} = props; + const POINTS_LENGTH = 6; const angle = 90 + (Math.atan2( point.getY() - previousPoint.getY(), - (point.getX() - 10) - (previousPoint.getX() + 10) + (point.getX()) - (previousPoint.getX()) ) * 180) / Math.PI; @@ -32,9 +32,9 @@ const CustomLinkArrowWidget = (props) => { return ( - +