From 19e83b5ff288191b36ee11cd561d90bc04b3a6e8 Mon Sep 17 00:00:00 2001 From: benarmstrongbf Date: Mon, 18 Jan 2021 16:36:40 +0000 Subject: [PATCH 1/7] feat: new tempr map --- package.json | 5 +- src/App.js | 15 +- src/Utilities.js | 1 + src/components/Global/TemprNode.js | 51 +++ src/components/Global/TemprSidebar.js | 28 ++ src/components/Global/index.js | 2 + src/components/Universal/Page.js | 36 +- src/components/Universal/PaginatedTable.js | 197 +++++----- src/components/View/Tempr.js | 5 +- src/components/View/TemprMap.js | 436 ++++++++++++++------- src/styles/App.scss | 20 +- src/styles/layouts/_tempr_map.scss | 56 +++ yarn.lock | 194 +++++++++ 13 files changed, 777 insertions(+), 269 deletions(-) create mode 100644 src/components/Global/TemprNode.js create mode 100644 src/components/Global/TemprSidebar.js create mode 100644 src/styles/layouts/_tempr_map.scss diff --git a/package.json b/package.json index 106fc87ad..154fea739 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "baseui": "^9.14.1", "brace": "^0.11.1", "chart.js": "^2.9.3", + "dagre": "^0.8.5", "graphviz-react": "1.1.1", "leaflet": "^1.5.1", "moment": "^2.24.0", @@ -24,6 +25,7 @@ "react-chartjs-2": "^2.8.0", "react-cookies": "^0.1.1", "react-dom": "^16.11.0", + "react-flow-renderer": "^8.3.6", "react-json-pretty": "^2.1.0", "react-leaflet": "^2.5.0", "react-router-dom": "^5.0.1", @@ -75,7 +77,8 @@ "eslint-plugin-react-hooks": "^1.6.1", "eslint-plugin-standard": "^4.0.0", "husky": "^3.0.2", - "prettier": "^1.18.2" + "prettier": "^1.18.2", + "typescript": "^2.8.0" }, "husky": { "hooks": { diff --git a/src/App.js b/src/App.js index d880d5988..e1cdf29b9 100644 --- a/src/App.js +++ b/src/App.js @@ -134,18 +134,9 @@ class App extends Component { ) : ( - <> - -
- -
-
- -
- -
-
- +
+ +
); }; diff --git a/src/Utilities.js b/src/Utilities.js index b175e680c..9ae899674 100644 --- a/src/Utilities.js +++ b/src/Utilities.js @@ -107,3 +107,4 @@ export function useWindowDimensions() { return windowDimensions; } + diff --git a/src/components/Global/TemprNode.js b/src/components/Global/TemprNode.js new file mode 100644 index 000000000..c6462fa8a --- /dev/null +++ b/src/components/Global/TemprNode.js @@ -0,0 +1,51 @@ +import React, { memo } from 'react'; +import { Handle } from 'react-flow-renderer'; + +const TemprNode = memo(({ data }) => { + const qRes = data.tempr.queueResponse ? 'green' : 'red'; + const qReq = data.tempr.queueRequest ? 'green' : 'red'; + const fs = data.primary ? 'large' : 'small'; + return ( + <> + {data.tempr.temprId ? + ( + console.log('handle onConnect', params)} + /> + ) : ( + console.log('handle onConnect', params)} + /> + ) + + } + { +
+

{data.tempr.name} - {data.tempr.id}

+
+

Queue Response

+

Queue Request

+

{`${data.tempr.endpointType}`}

+
+
+ } + + + + ); +}); + +export { TemprNode }; \ No newline at end of file diff --git a/src/components/Global/TemprSidebar.js b/src/components/Global/TemprSidebar.js new file mode 100644 index 000000000..a7e0cf6fd --- /dev/null +++ b/src/components/Global/TemprSidebar.js @@ -0,0 +1,28 @@ +import React from 'react'; + +const TemprSidebar = props => { + const onDragStart = (event, id) => { + event.dataTransfer.setData('application/reactflow', id); + event.dataTransfer.effectAllowed = 'move'; + }; + + const temprNodes = props.temprs.map(tempr => { + return ( +
onDragStart(event, tempr.id)} draggable> + {tempr.name} +
+ ); + }); + + return ( + <> + + + ); +}; + +export { TemprSidebar }; \ No newline at end of file diff --git a/src/components/Global/index.js b/src/components/Global/index.js index 35c0ab7c5..0f3c287e8 100644 --- a/src/components/Global/index.js +++ b/src/components/Global/index.js @@ -8,7 +8,9 @@ export * from "./TableFilter"; export * from "./Toast"; export * from "./TrueFalseCheckboxes"; export * from "./TemprSelector"; +export * from "./TemprSidebar"; export * from "./TemprForm"; export * from "./TemprPreview"; export * from "./TemprOutputTest"; export * from "./TemprModal"; +export * from "./TemprNode"; diff --git a/src/components/Universal/Page.js b/src/components/Universal/Page.js index 89f29c221..194341089 100644 --- a/src/components/Universal/Page.js +++ b/src/components/Universal/Page.js @@ -4,11 +4,12 @@ import { Link, Prompt } from "react-router-dom"; import { useStyletron } from "baseui"; import { Button, KIND } from "baseui/button"; import { Heading, HeadingLevel } from "baseui/heading"; -import { Block } from 'baseui/block'; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faChevronLeft } from "@fortawesome/free-solid-svg-icons"; +import { useWindowDimensions } from "../../Utilities"; + const Actions = props => { const [css] = useStyletron(); @@ -57,24 +58,29 @@ const Page = props => { padding: theme.sizing.scale800, }); + // eslint-disable-next-line no-unused-vars + const { height, width } = useWindowDimensions(); + const mobileView = width < 651; + return (
{props.alert && } - - - - {props.heading} - - - - - - - {props.heading} - - - + { + mobileView ? ( + + + {props.heading} + + + ) : ( + + + {props.heading} + + + ) + } {props.children}
diff --git a/src/components/Universal/PaginatedTable.js b/src/components/Universal/PaginatedTable.js index 1e5d0757e..762b68db8 100644 --- a/src/components/Universal/PaginatedTable.js +++ b/src/components/Universal/PaginatedTable.js @@ -2,7 +2,7 @@ import React, { useEffect, useState } from "react"; import { withRouter } from "react-router-dom"; import { useQueryParam, NumberParam, ObjectParam } from "use-query-params"; import { Pagination, PaginationMobile, Table } from "."; -import { Block } from 'baseui/block'; +import { useWindowDimensions } from "../../Utilities"; const PaginatedTable = withRouter(props => { const [data, setData] = useState(null); @@ -30,101 +30,110 @@ const PaginatedTable = withRouter(props => { }); }, [page, pageSize, filters, getData]); + // eslint-disable-next-line no-unused-vars + const { height, width } = useWindowDimensions(); + return ( <> - - { - if (filters) { - if (value === "") { - delete filters[colId]; - } else { - filters[colId] = value; - } - setFilters(filters); - } else { - setFilters({ [colId]: value }); - } - }} - /> - { - setPageSize(pageSize); - }} - currentPageSize={pageSize} - updatePageNumber={pageNumber => setPage(pageNumber)} - totalRecords={data ? data.totalRecords : "-"} - numberOfPages={data ? data.numberOfPages : "-"} - currentPage={page || 1} - /> - - -
{ - if (filters) { - if (value === "") { - delete filters[colId]; - } else { - filters[colId] = value; - } - setFilters(filters); - } else { - setFilters({ [colId]: value }); - } - }} - /> - { - setPageSize(pageSize); - }} - currentPageSize={pageSize} - updatePageNumber={pageNumber => setPage(pageNumber)} - totalRecords={data ? data.totalRecords : "-"} - numberOfPages={data ? data.numberOfPages : "-"} - currentPage={page || 1} - /> - - -
{ - if (filters) { - if (value === "") { - delete filters[colId]; - } else { - filters[colId] = value; - } - setFilters(filters); - } else { - setFilters({ [colId]: value }); - } - }} - /> - { - setPageSize(pageSize); - }} - currentPageSize={pageSize} - updatePageNumber={pageNumber => setPage(pageNumber)} - totalRecords={data ? data.totalRecords : "-"} - numberOfPages={data ? data.numberOfPages : "-"} - currentPage={page || 1} - /> - + { + width >= 1100 ? ( + <> +
{ + if (filters) { + if (value === "") { + delete filters[colId]; + } else { + filters[colId] = value; + } + setFilters(filters); + } else { + setFilters({ [colId]: value }); + } + }} + /> + { + setPageSize(pageSize); + }} + currentPageSize={pageSize} + updatePageNumber={pageNumber => setPage(pageNumber)} + totalRecords={data ? data.totalRecords : "-"} + numberOfPages={data ? data.numberOfPages : "-"} + currentPage={page || 1} + /> + + ) : width >= 650 ? ( + <> +
{ + if (filters) { + if (value === "") { + delete filters[colId]; + } else { + filters[colId] = value; + } + setFilters(filters); + } else { + setFilters({ [colId]: value }); + } + }} + /> + { + setPageSize(pageSize); + }} + currentPageSize={pageSize} + updatePageNumber={pageNumber => setPage(pageNumber)} + totalRecords={data ? data.totalRecords : "-"} + numberOfPages={data ? data.numberOfPages : "-"} + currentPage={page || 1} + /> + + ) : ( + <> +
{ + if (filters) { + if (value === "") { + delete filters[colId]; + } else { + filters[colId] = value; + } + setFilters(filters); + } else { + setFilters({ [colId]: value }); + } + }} + /> + { + setPageSize(pageSize); + }} + currentPageSize={pageSize} + updatePageNumber={pageNumber => setPage(pageNumber)} + totalRecords={data ? data.totalRecords : "-"} + numberOfPages={data ? data.numberOfPages : "-"} + currentPage={page || 1} + /> + + ) + } ); }); diff --git a/src/components/View/Tempr.js b/src/components/View/Tempr.js index cfe17edf3..e0e4bd8f0 100644 --- a/src/components/View/Tempr.js +++ b/src/components/View/Tempr.js @@ -1,7 +1,7 @@ import React, { useState, useEffect, memo } from "react"; import { Link } from "react-router-dom"; -import { Button } from "baseui/button"; +import { Button, KIND } from "baseui/button"; import { FormControl } from "baseui/form-control"; import { Textarea } from "baseui/textarea"; @@ -199,7 +199,7 @@ const Tempr = props => { async function getChildren(temprId) { var none = true; if (!blankTempr) { - const ts = await OopCore.getTemprs({temprId: temprId}); + const ts = await OopCore.getTemprs({filter: {temprId: temprId}}); if (ts) { // eslint-disable-next-line no-unused-vars for (const tempr of ts.data) { @@ -410,6 +410,7 @@ const Tempr = props => { $as={Link} to={`${props.location.pathname}/audit-logs`} aria-label={"History"} + kind={(noParents && noChildren) ? KIND.primary : KIND.tertiary} > History diff --git a/src/components/View/TemprMap.js b/src/components/View/TemprMap.js index 3703005a0..94c0f64d3 100644 --- a/src/components/View/TemprMap.js +++ b/src/components/View/TemprMap.js @@ -1,143 +1,295 @@ import React, { useState } from "react"; - import { Redirect } from 'react-router'; -import { - Page, - DataProvider, -} from "../Universal"; +import ReactFlow, { + ReactFlowProvider, + removeElements, + isNode, + Controls, + MiniMap, + getBezierPath, + getMarkerEnd, +} from "react-flow-renderer"; -import { Graphviz } from 'graphviz-react'; +import { TemprSidebar, TemprNode } from "../Global"; +import { DataProvider, Page, InPlaceGifSpinner } from "../Universal"; import OopCore from "../../OopCore"; +import dagre from 'dagre'; + +const dagreGraph = new dagre.graphlib.Graph(); +dagreGraph.setDefaultEdgeLabel(() => ({})); + +const getLayoutedElements = (elements) => { + dagreGraph.setGraph({ rankdir: 'TB' }); + elements.forEach((el) => { + if (isNode(el)) { + dagreGraph.setNode(el.id, { width: 250, height: 80 }); + } else { + dagreGraph.setEdge(el.source, el.target); + } + }); + dagre.layout(dagreGraph); + return elements.map((el) => { + if (isNode(el)) { + const nodeWithPosition = dagreGraph.node(el.id); + el.targetPosition = 'top'; + el.sourcePosition = 'bottom'; + // unfortunately we need this little hack to pass a slighltiy different position + // in order to notify react flow about the change + el.position = { + x: nodeWithPosition.x + Math.random() / 1000, + y: nodeWithPosition.y, + }; + } + return el; + }); +}; + +const ConnectionLine = ({ + sourceX, + sourceY, + sourcePosition, + targetX, + targetY, + targetPosition, + connectionLineType, + connectionLineStyle, +}) => { + return ( + + + + + ); +}; + +const CustomEdge = ({ + id, + sourceX, + sourceY, + targetX, + targetY, + sourcePosition, + targetPosition, + style = {}, + data, + arrowHeadType, + markerEndId, +}) => { + const edgePath = getBezierPath({ sourceX, sourceY, sourcePosition, targetX, targetY, targetPosition }); + const markerEnd = getMarkerEnd(arrowHeadType, markerEndId); + return ( + <> + + data.onClick(id, data.els)} + cx={(sourceX+targetX) / 2} + cy={(sourceY+targetY) / 2} + r="6" + fill="none" + /> + data.onClick(id, data.els)} + x1={((sourceX+targetX) / 2) - 6} + x2={((sourceX+targetX) / 2) + 6} + y1={((sourceY+targetY) / 2) - 6} + y2={((sourceY+targetY) / 2) + 6} + /> + data.onClick(id, data.els)} + x1={((sourceX+targetX) / 2) + 6} + x2={((sourceX+targetX) / 2) - 6} + y1={((sourceY+targetY) / 2) - 6} + y2={((sourceY+targetY) / 2) + 6} + /> + + ); +} const TemprMap = props => { const [noMap, setNoMap] = useState(false); - const [nodes, setNodes] = useState({}); - const [paths, setPaths] = useState([]); const [title, setTitle] = useState(""); + const [loading, setLoading] = useState(false); + const temprOriginPath = "/temprs/" + props.match.params.temprId; + const [reactFlowInstance, setReactFlowInstance] = useState(null); + const [elements, setElements] = useState([]); + const [unusedTemprs, setUnusedTemprs] = useState([]); - const temprOriginPath = '/temprs/' + props.match.params.temprId; + const nodeTypes = { + temprNode: TemprNode, + }; + const edgeTypes = { + custom: CustomEdge, + }; - async function getChildren(temprId) { - const ts = await OopCore.getTemprs({temprId: temprId}); - var none = true; - if (ts) { - // eslint-disable-next-line no-unused-vars - for (const tempr of ts.data) { - if (tempr.temprId === temprId) { - none = false; - break; - } + async function onConnect(params) { + if (params.source !== params.target && + params.targetHandle[0] === 'Y' && + params.sourceHandle.split("-")[0] === 'bottom') { + const newT = await OopCore.updateTempr(params.target, {temprId: params.source}); + if (newT.temprId === parseInt(params.source)) { + refresh(); } } - return none; + }; + + const onElementsRemove = elementsToRemove => { + setElements(els => removeElements(elementsToRemove, els)); + }; + + const onLoad = _reactFlowInstance => { + setReactFlowInstance(_reactFlowInstance); + }; + + const onDragOver = event => { + event.preventDefault(); + event.dataTransfer.dropEffect = "move"; + }; + + async function onDrop(event) { + event.preventDefault(); + + const id = event.dataTransfer.getData("application/reactflow"); + const position = reactFlowInstance.project({ + x: event.clientX - 175, + y: event.clientY - 225, + }); + + setLoading(true); + + const tempr = await OopCore.getTempr(id); + + if (tempr.id) { + const newNode = formatNode(tempr, position); + var newElements = elements.concat(newNode); + const layoutedEls = getLayoutedElements(newElements); + + setElements(layoutedEls); + + var remainingTemprs = unusedTemprs.filter(t => t.id !== id); + + setUnusedTemprs(remainingTemprs); + } + + setLoading(false); }; - async function getParents(temprId) { - const t = await OopCore.getTempr(temprId); - return (!t.temprId); + async function deletePath(edgeId, els) { + var target = parseInt(edgeId.split("-")[1]); + + const newT = await OopCore.updateTempr(target, {temprId: null}); + if (newT.temprId === null) { + refresh(); + } }; - const formatNode = (temprObj) => { - return `${temprObj.id}[shape=plain, fontname=Helvetica, - label=< -
- - - - - - - - -
- ${temprObj.name} - - - - - - - - - - - - -
- -
-
 
- - - - - - - -
 ${temprObj.endpointType}
-
- >]`; + async function refresh() { + setLoading(true); + const response = await getData(props.match.params.temprId); + if (response) { + const layoutedEls = getLayoutedElements(response.nodes); + setElements(layoutedEls); + setUnusedTemprs(response.remainingTemprs); + setLoading(false); + return response; + } else { + setNoMap(true); + return false; + } + } + + const formatNode = (temprObj, pos) => { + const primary = temprObj.id === parseInt(props.match.params.temprId); + const position = pos || { x: 200, y: 50 } + const border = primary ? '2px solid #177692' : '1px solid #777' + return ( + { + id: `${temprObj.id}`, + type: 'temprNode', + data: { tempr: temprObj, primary: primary }, + style: { border: border, borderRadius: '10px', padding: 10, backgroundColor: 'white' }, + position: position, + } + ); + }; + + const formatPath = (sourceId, targetId) => { + return ( + { + id: `${sourceId}-${targetId}`, + source: `${sourceId}`, + target: `${targetId}`, + style: { stroke: '#777', strokeWidth: 1.5 }, + type: 'custom', + data: { onClick: deletePath } + } + ); }; async function getData(temprId) { - var ps = await getParents(temprId); - var cs = await getChildren(temprId); var nodeData = []; var pathData = new Set(); - if (ps && cs) { - return null; - } else { - var tempr = await OopCore.getTempr(temprId); - var children = await OopCore.getTemprs({temprId: temprId}); - var childrenData = []; - for (var i = children.data.length - 1; i >= 0; i--) { - if (children.data[i].temprId === temprId) { - childrenData.push(children.data[i]); - } + var tempr = await OopCore.getTempr(temprId); + var allTemprs = await OopCore.getTemprs({ + filter: { deviceGroupId: tempr.deviceGroupId}, + }); + var children = await OopCore.getTemprs({ + filter: { temprId: temprId}, + }); + var childrenData = children.data; + const titleNode = tempr.name; + while (tempr) { + if (!nodeData[tempr.id]) { + nodeData[tempr.id] = formatNode(tempr); } - const titleNode = tempr.name; - while (tempr) { - if (!nodeData[tempr.id]) { - nodeData[tempr.id] = formatNode(tempr); - } - if (tempr.temprId) { - pathData.add(`${tempr.temprId}->${tempr.id}`); - if (nodeData[tempr.temprId]){ - tempr = null; - } else { - tempr = await OopCore.getTempr(tempr.temprId); - childrenData.push(tempr); - } - } else { + if (tempr.temprId) { + pathData.add(formatPath(tempr.temprId, tempr.id)); + if (nodeData[tempr.temprId]){ tempr = null; + } else { + tempr = await OopCore.getTempr(tempr.temprId); + childrenData.push(tempr); } + } else { + tempr = null; } - while (childrenData.length > 0) { - const c = childrenData.shift(); - if (c.temprId) { - if (!nodeData[c.id]) { - nodeData[c.id] = formatNode(c); - } - pathData.add(`${c.temprId}->${c.id}`); - var new_children = await OopCore.getTemprs({temprId: c.id}); - new_children = new_children.data; - for (var q = new_children.length - 1; q >= 0; q--) { - if (!nodes[new_children[q].id] && new_children[q].temprId === c.id) { - childrenData.push(new_children[q]); - } - } - } + } + while (childrenData.length > 0) { + const c = childrenData.shift(); + if (!nodeData[c.id]) { + nodeData[c.id] = formatNode(c); + pathData.add(formatPath(c.temprId, c.id)); } - const pathArray = [...pathData]; - let response = {nodes:nodeData,paths:pathArray,title:titleNode}; - return (response); + var new_children = await OopCore.getTemprs({ + filter: { temprId: c.id }, + }); + var filtered_children = new_children.data.filter(c => !nodeData[c.id]); + childrenData.push(...filtered_children); } + const pathArray = [...pathData]; + var filteredNodes = nodeData.filter(Boolean); + var remainingTemprs = allTemprs.data.filter(t => !nodeData[t.id]); + filteredNodes.push(...pathArray); + return {title: titleNode, nodes: filteredNodes, remainingTemprs: remainingTemprs}; }; return ( @@ -145,9 +297,10 @@ const TemprMap = props => { getData={() => { return getData(props.match.params.temprId).then(response => { if (response) { - setNodes(response.nodes); - setPaths(response.paths); + const layoutedEls = getLayoutedElements(response.nodes); + setElements(layoutedEls); setTitle(response.title); + setUnusedTemprs(response.remainingTemprs); return response; } else { setNoMap(true); @@ -155,31 +308,46 @@ const TemprMap = props => { } }); }} - renderData={() => (!(noMap) ? - - - - : - )} + renderData={() => + !noMap ? ( + +
+ +
+ {loading ? : ( + + + { + if (n.data.primary) return '#177692'; + return 'black'; + }} + /> + + )} +
+ +
+
+
+ ) : ( + + ) + } /> ); }; diff --git a/src/styles/App.scss b/src/styles/App.scss index fa145f767..80eeb071a 100644 --- a/src/styles/App.scss +++ b/src/styles/App.scss @@ -25,22 +25,19 @@ div[id="root"] { .content { background-color: $oop-grey; flex: 1; - margin-left: 9.5rem; - padding: 9em 2rem 2rem; - .content-wrapper { - background-color: $color-white; - padding: 1.5rem; + @media (min-width: 650px) { + margin-left: 9.5rem; + padding: 9em 2rem 2rem; } - } - .content-mobile { - background-color: $oop-grey; - flex: 1; - padding: 26vh 0.5rem 0.5rem; + @media (max-width: 650px) { + padding: 24vh 0.5rem 0.5rem; + } + .content-wrapper { background-color: $color-white; - padding: 1vmin; + padding: 1.5rem; } } } @@ -70,3 +67,4 @@ a { @import "layouts/table"; @import "layouts/dashboard"; @import "layouts/tempr"; +@import "layouts/tempr_map"; diff --git a/src/styles/layouts/_tempr_map.scss b/src/styles/layouts/_tempr_map.scss new file mode 100644 index 000000000..19d22ccfb --- /dev/null +++ b/src/styles/layouts/_tempr_map.scss @@ -0,0 +1,56 @@ +.dndflow { + flex-direction: column; + display: flex; + height: 500px; + width: 100%; +} + +.dndflow aside { + border-right: 1px solid #eee; + padding: 5px 0px 0px 10px; + font-size: 12px; + background: #fcfcfc; + text-align: center; +} + +.tempr-node { + p { + &[data-baseweb="typo-p3"] { + font-weight: bolder; + } + } +} + +.dndflow aside .description { + margin-bottom: 10px; +} + +.dndflow .dndnode { + height: 20px; + padding: 4px; + border: 1px solid #777; + border-radius: 4px; + margin-bottom: 10px; + margin-right: 10px; + display: flex; + justify-content: center; + align-items: center; + cursor: grab; +} + +.dndflow .reactflow-wrapper { + flex-grow: 1; + height: 100%; + background-color: #e6e8ec; +} + +@media screen and (min-width: 768px) { + .dndflow { + flex-direction: row; + } + + .dndflow aside { + width: 25%; + max-width: 300px; + } +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index bdc824354..6e91950e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -873,6 +873,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.12.5": + version "7.12.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" + integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.3.4", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.2": version "7.6.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.6.2.tgz#c3d6e41b304ef10dcf13777a33e7694ec4a9a6dd" @@ -2795,6 +2802,16 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +classcat@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/classcat/-/classcat-4.1.0.tgz#e8fd8623e5625187b58adf49bb669a13b6c520f4" + integrity sha512-RA8O5oCi1I1CF6rR4cRBROh8MtZzM4w7xKLm0jd+S6UN2G4FIto+9DVOeFc46JEZFN5PVe/EZWLQO1VU/AUH4A== + +classnames@^2.2.5: + version "2.2.6" + resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce" + integrity sha512-JR/iSQOSt+LQIWwrwEzJ9uk0xfN3mTVYMwt1Ir5mUcSN6pU+V4zQFFaJsclJbPuAUQH+yfWef6tm7l1quW3C8Q== + clean-css@4.2.x: version "4.2.1" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17" @@ -3482,11 +3499,21 @@ d3-color@1: resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== +"d3-color@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-2.0.0.tgz#8d625cab42ed9b8f601a1760a389f7ea9189d62e" + integrity sha512-SPXi0TSKPD4g9tw0NMZFnR95XVgUZiBH+uUTqQuDu1OsE2zomHU7ho0FISciaPvosimixwHFl3WHLGabv6dDgQ== + d3-dispatch@1, d3-dispatch@^1.0.3: version "1.0.6" resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58" integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA== +"d3-dispatch@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-2.0.0.tgz#8a18e16f76dd3fcaef42163c97b926aa9b55e7cf" + integrity sha512-S/m2VsXI7gAti2pBoLClFFTMOO1HTtT0j99AuXLoGFKO6deHDdnv6ZGTxSTTUTgO1zVcv82fCOtDjYK4EECmWA== + d3-drag@1: version "1.2.5" resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.5.tgz#2537f451acd39d31406677b7dc77c82f7d988f70" @@ -3495,11 +3522,24 @@ d3-drag@1: d3-dispatch "1" d3-selection "1" +d3-drag@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-2.0.0.tgz#9eaf046ce9ed1c25c88661911c1d5a4d8eb7ea6d" + integrity sha512-g9y9WbMnF5uqB9qKqwIIa/921RYWzlUDv9Jl1/yONQwxbOfszAWTCm8u7HOTgJgRDXiRZN56cHT9pd24dmXs8w== + dependencies: + d3-dispatch "1 - 2" + d3-selection "2" + d3-ease@1: version "1.0.7" resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.7.tgz#9a834890ef8b8ae8c558b2fe55bd57f5993b85e2" integrity sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ== +"d3-ease@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-2.0.0.tgz#fd1762bfca00dae4bacea504b1d628ff290ac563" + integrity sha512-68/n9JWarxXkOWMshcT5IcjbB+agblQUaIsbnXmrzejn2O82n3p2A9R2zEB9HIEFWKFwPAEDDN8gR0VdSAyyAQ== + d3-format@^1.2.0: version "1.4.5" resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4" @@ -3527,6 +3567,13 @@ d3-interpolate@1, d3-interpolate@^1.1.5: dependencies: d3-color "1" +"d3-interpolate@1 - 2": + version "2.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-2.0.1.tgz#98be499cfb8a3b94d4ff616900501a64abc91163" + integrity sha512-c5UhwwTs/yybcmTpAVqwSFl6vrQ8JZJoT5F7xNFK9pymv5C0Ymcc9/LIJHtYIggg/yS9YHw8i8O8tgb9pupjeQ== + dependencies: + d3-color "1 - 2" + d3-path@^1.0.5: version "1.0.9" resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" @@ -3537,11 +3584,21 @@ d3-selection@1, d3-selection@^1.1.0: resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c" integrity sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg== +d3-selection@2, d3-selection@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-2.0.0.tgz#94a11638ea2141b7565f883780dabc7ef6a61066" + integrity sha512-XoGGqhLUN/W14NmaqcO/bb1nqjDAw5WtSYb2X8wiuQWvSZUsUVYsOSkOybUrNvcBjaywBdYPy03eXHMXjk9nZA== + d3-timer@1, d3-timer@^1.0.6: version "1.0.10" resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5" integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw== +"d3-timer@1 - 2": + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-2.0.0.tgz#055edb1d170cfe31ab2da8968deee940b56623e6" + integrity sha512-TO4VLh0/420Y/9dO3+f9abDEFYeCUr2WZRlxJvbp4HPTQcSylXNiL6yZa9FIUvV1yRiFufl1bszTCLDqv9PWNA== + d3-transition@1, d3-transition@^1.1.1: version "1.3.2" resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398" @@ -3554,6 +3611,17 @@ d3-transition@1, d3-transition@^1.1.1: d3-selection "^1.1.0" d3-timer "1" +d3-transition@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-2.0.0.tgz#366ef70c22ef88d1e34105f507516991a291c94c" + integrity sha512-42ltAGgJesfQE3u9LuuBHNbGrI/AJjNL2OAUdclE70UE6Vy239GCBEYD38uBPoLeNsOhFStGpPI0BAOV+HMxog== + dependencies: + d3-color "1 - 2" + d3-dispatch "1 - 2" + d3-ease "1 - 2" + d3-interpolate "1 - 2" + d3-timer "1 - 2" + d3-zoom@^1.5.0: version "1.8.3" resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.8.3.tgz#b6a3dbe738c7763121cd05b8a7795ffe17f4fc0a" @@ -3565,6 +3633,17 @@ d3-zoom@^1.5.0: d3-selection "1" d3-transition "1" +d3-zoom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-2.0.0.tgz#f04d0afd05518becce879d04709c47ecd93fba54" + integrity sha512-fFg7aoaEm9/jf+qfstak0IYpnesZLiMX6GZvXtUSdv8RH2o4E2qeelgdU09eKS6wGuiGMfcnMI0nTIqWzRHGpw== + dependencies: + d3-dispatch "1 - 2" + d3-drag "2" + d3-interpolate "1 - 2" + d3-selection "2" + d3-transition "2" + d@1, d@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/d/-/d-1.0.1.tgz#8698095372d58dbee346ffd0c7093f99f8f9eb5a" @@ -3573,6 +3652,14 @@ d@1, d@^1.0.1: es5-ext "^0.10.50" type "^1.0.1" +dagre@^0.8.5: + version "0.8.5" + resolved "https://registry.yarnpkg.com/dagre/-/dagre-0.8.5.tgz#ba30b0055dac12b6c1fcc247817442777d06afee" + integrity sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw== + dependencies: + graphlib "^2.1.8" + lodash "^4.17.15" + damerau-levenshtein@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.5.tgz#780cf7144eb2e8dbd1c3bb83ae31100ccc31a414" @@ -3955,6 +4042,20 @@ duplexify@^3.4.2, duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" +easy-peasy@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/easy-peasy/-/easy-peasy-4.0.1.tgz#8b3ab1ebb43509a62dc2c37b4269a9141e33d918" + integrity sha512-aTvB48M2ej6dM/wllUm1F7CTWGnYOYh82SHBkvJtOZhJ/9L8Gmg/nIVqDPwJeojOWZe+gbLtpyi8DhN6fPNBYg== + dependencies: + immer "7.0.9" + is-plain-object "^5.0.0" + memoizerific "^1.11.3" + redux "^4.0.5" + redux-thunk "^2.3.0" + symbol-observable "^2.0.3" + ts-toolbelt "^8.0.7" + use-memo-one "^1.1.1" + ecc-jsbn@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" @@ -4557,6 +4658,11 @@ fast-deep-equal@^2.0.1: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= +fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + fast-diff@^1.1.2: version "1.2.0" resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.2.0.tgz#73ee11982d86caaf7959828d519cfe927fac5f03" @@ -5095,6 +5201,13 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.3 resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02" integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q== +graphlib@^2.1.8: + version "2.1.8" + resolved "https://registry.yarnpkg.com/graphlib/-/graphlib-2.1.8.tgz#5761d414737870084c92ec7b5dbcb0592c9d35da" + integrity sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A== + dependencies: + lodash "^4.17.15" + graphviz-react@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/graphviz-react/-/graphviz-react-1.1.1.tgz#688f92f3da08c0fdf0fbae9887ecd0615e545c26" @@ -5508,6 +5621,11 @@ immer@1.10.0: resolved "https://registry.yarnpkg.com/immer/-/immer-1.10.0.tgz#bad67605ba9c810275d91e1c2a47d4582e98286d" integrity sha512-O3sR1/opvCDGLEVcvrGTMtLac8GJ5IwZC4puPrLuRj3l7ICKvkmA0vGuU9OW8mV9WIBRnaxp5GJh9IEAaNOoYg== +immer@7.0.9: + version "7.0.9" + resolved "https://registry.yarnpkg.com/immer/-/immer-7.0.9.tgz#28e7552c21d39dd76feccd2b800b7bc86ee4a62e" + integrity sha512-Vs/gxoM4DqNAYR7pugIxi0Xc8XAun/uy7AQu4fLLqaTBHxjOP9pJ266Q9MWA/ly4z6rAFZbvViOtihxUZ7O28A== + import-cwd@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9" @@ -5911,6 +6029,11 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-promise@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" @@ -6969,6 +7092,11 @@ map-obj@^2.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= +map-or-similar@^1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/map-or-similar/-/map-or-similar-1.5.0.tgz#6de2653174adfb5d9edc33c69d3e92a1b76faf08" + integrity sha1-beJlMXSt+12e3DPGnT6Sobdvrwg= + map-visit@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" @@ -7014,6 +7142,13 @@ mem@^4.0.0: resolved "https://registry.yarnpkg.com/memoize-one/-/memoize-one-5.1.1.tgz#047b6e3199b508eaec03504de71229b8eb1d75c0" integrity sha512-HKeeBpWvqiVJD57ZUAsJNm71eHTykffzcLZVYWiVfQeI1rJtuEaS7hQiEpWfVVk18donPwJEcFKIkCmPJNOhHA== +memoizerific@^1.11.3: + version "1.11.3" + resolved "https://registry.yarnpkg.com/memoizerific/-/memoizerific-1.11.3.tgz#7c87a4646444c32d75438570905f2dbd1b1a805a" + integrity sha1-fIekZGREwy11Q4VwkF8tvRsagFo= + dependencies: + map-or-similar "^1.5.0" + memory-fs@^0.4.0, memory-fs@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" @@ -9261,6 +9396,14 @@ react-dom@^16.11.0: prop-types "^15.6.2" scheduler "^0.17.0" +react-draggable@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.3.tgz#0727f2cae5813e36b0e4962bf11b2f9ef2b406f3" + integrity sha512-jV4TE59MBuWm7gb6Ns3Q1mxX8Azffb7oTtDtBgFkxRvhDp38YAARmRplrj0+XGkhOJB5XziArX+4HUUABtyZ0w== + dependencies: + classnames "^2.2.5" + prop-types "^15.6.0" + react-dropzone@^9.0.0: version "9.0.0" resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-9.0.0.tgz#4f5223cdcb4d3bd8a66e3298c4041eb0c75c4634" @@ -9276,6 +9419,19 @@ react-error-overlay@^6.0.2: resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-6.0.2.tgz#642bd6157c6a4b6e9ca4a816f7ed30b868c47f81" integrity sha512-DHRuRk3K4Lg9obI6J4Y+nKvtwjasYRU9CFL3ud42x9YJG1HbQjSNublapC/WBJOA726gNUbqbj0U2df9+uzspQ== +react-flow-renderer@^8.3.6: + version "8.3.6" + resolved "https://registry.yarnpkg.com/react-flow-renderer/-/react-flow-renderer-8.3.6.tgz#5ac7b909b2c3017842daafa7bf23596b5d344cc4" + integrity sha512-D+06+ObLH3kwALXX21TKZHMPVSdHlPboVjipUaGTiQi4RV09vBvyqJGFWYa3PDffgMlQaYpZjMb0hdOMtIpd+w== + dependencies: + "@babel/runtime" "^7.12.5" + classcat "^4.1.0" + d3-selection "^2.0.0" + d3-zoom "^2.0.0" + easy-peasy "^4.0.1" + fast-deep-equal "^3.1.3" + react-draggable "^4.4.3" + react-focus-lock@^2.2.1: version "2.4.0" resolved "https://registry.yarnpkg.com/react-focus-lock/-/react-focus-lock-2.4.0.tgz#11235eff41f47567288d7ef574e5b006527739d5" @@ -9608,6 +9764,19 @@ redent@^2.0.0: indent-string "^3.0.0" strip-indent "^2.0.0" +redux-thunk@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.3.0.tgz#51c2c19a185ed5187aaa9a2d08b666d0d6467622" + integrity sha512-km6dclyFnmcvxhAcrQV2AkZmPQjzPDjgVlQtR0EQjxZPyJ0BnMf3in1ryuR8A2qU0HldVRfxYXbFSKlI3N7Slw== + +redux@^4.0.5: + version "4.0.5" + resolved "https://registry.yarnpkg.com/redux/-/redux-4.0.5.tgz#4db5de5816e17891de8a80c424232d06f051d93f" + integrity sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w== + dependencies: + loose-envify "^1.4.0" + symbol-observable "^1.2.0" + regenerate-unicode-properties@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e" @@ -10779,6 +10948,16 @@ svgo@^1.0.0, svgo@^1.2.2: unquote "~1.1.1" util.promisify "~1.0.0" +symbol-observable@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804" + integrity sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ== + +symbol-observable@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-2.0.3.tgz#5b521d3d07a43c351055fa43b8355b62d33fd16a" + integrity sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA== + symbol-tree@^3.2.2: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" @@ -11038,6 +11217,11 @@ ts-pnp@^1.1.2: resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.1.4.tgz#ae27126960ebaefb874c6d7fa4729729ab200d90" integrity sha512-1J/vefLC+BWSo+qe8OnJQfWTYRS6ingxjwqmHMqaMxXMj7kFtKLgAaYW3JeX3mktjgUL+etlU8/B4VUAUI9QGw== +ts-toolbelt@^8.0.7: + version "8.0.7" + resolved "https://registry.yarnpkg.com/ts-toolbelt/-/ts-toolbelt-8.0.7.tgz#4dad2928831a811ee17dbdab6eb1919fc0a295bf" + integrity sha512-KICHyKxc5Nu34kyoODrEe2+zvuQQaubTJz7pnC5RQ19TH/Jged1xv+h8LBrouaSD310m75oAljYs59LNHkLDkQ== + tslib@^1.8.1: version "1.10.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" @@ -11102,6 +11286,11 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= +typescript@^2.8.0: + version "2.9.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.9.2.tgz#1cbf61d05d6b96269244eb6a3bce4bd914e0f00c" + integrity sha512-Gr4p6nFNaoufRIY4NMdpQRNmgxVIGMs4Fcu/ujdYk3nAZqk7supzBE9idmvfZIlH/Cuj//dvi+019qEue9lV0w== + uglify-js@3.4.x: version "3.4.10" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f" @@ -11250,6 +11439,11 @@ use-callback-ref@^1.2.1: resolved "https://registry.yarnpkg.com/use-callback-ref/-/use-callback-ref-1.2.4.tgz#d86d1577bfd0b955b6e04aaf5971025f406bea3c" integrity sha512-rXpsyvOnqdScyied4Uglsp14qzag1JIemLeTWGKbwpotWht57hbP78aNT+Q4wdFKQfQibbUX4fb6Qb4y11aVOQ== +use-memo-one@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/use-memo-one/-/use-memo-one-1.1.1.tgz#39e6f08fe27e422a7d7b234b5f9056af313bd22c" + integrity sha512-oFfsyun+bP7RX8X2AskHNTxu+R3QdE/RC5IefMbqptmACAA/gfol1KDD5KRzPsGMa62sWxGZw+Ui43u6x4ddoQ== + use-query-params@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/use-query-params/-/use-query-params-0.4.1.tgz#42fc913cbebbecb54654eed59144ada1f2c2ab16" From 44192f5c86c1439ac590741bf85c49cdaa52bc57 Mon Sep 17 00:00:00 2001 From: benarmstrongbf Date: Mon, 18 Jan 2021 17:20:21 +0000 Subject: [PATCH 2/7] feat: mobile changes for tempr map --- src/components/View/Tempr.js | 2 +- src/components/View/TemprMap.js | 28 ++++++++++++++++++---------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/components/View/Tempr.js b/src/components/View/Tempr.js index e0e4bd8f0..ebdaf60f1 100644 --- a/src/components/View/Tempr.js +++ b/src/components/View/Tempr.js @@ -203,7 +203,7 @@ const Tempr = props => { if (ts) { // eslint-disable-next-line no-unused-vars for (const tempr of ts.data) { - if (tempr.temprId === temprId) { + if (tempr.temprId === parseInt(temprId)) { none = false; break; } diff --git a/src/components/View/TemprMap.js b/src/components/View/TemprMap.js index 94c0f64d3..54c1823a5 100644 --- a/src/components/View/TemprMap.js +++ b/src/components/View/TemprMap.js @@ -15,6 +15,7 @@ import { TemprSidebar, TemprNode } from "../Global"; import { DataProvider, Page, InPlaceGifSpinner } from "../Universal"; import OopCore from "../../OopCore"; +import { useWindowDimensions } from "../../Utilities"; import dagre from 'dagre'; @@ -133,6 +134,9 @@ const TemprMap = props => { const [elements, setElements] = useState([]); const [unusedTemprs, setUnusedTemprs] = useState([]); + const { height, width } = useWindowDimensions(); + const noEdit = width < 1100 || height < 500; + const nodeTypes = { temprNode: TemprNode, }; @@ -233,13 +237,14 @@ const TemprMap = props => { }; const formatPath = (sourceId, targetId) => { - return ( + const type = noEdit ? 'bezier' : 'custom'; + return ( { id: `${sourceId}-${targetId}`, source: `${sourceId}`, target: `${targetId}`, style: { stroke: '#777', strokeWidth: 1.5 }, - type: 'custom', + type: type, data: { onClick: deletePath } } ); @@ -329,18 +334,21 @@ const TemprMap = props => { nodeTypes={nodeTypes} edgeTypes={edgeTypes} connectionLineComponent={ConnectionLine} - > + nodesConnectable={!noEdit} + > - { - if (n.data.primary) return '#177692'; - return 'black'; - }} - /> + {!noEdit && + { + if (n.data.primary) return '#177692'; + return 'black'; + }} + /> + } )} - + {!noEdit && } From a457516c0f31c732becd0046298e16c16c5fcec3 Mon Sep 17 00:00:00 2001 From: benarmstrongbf Date: Tue, 19 Jan 2021 13:38:02 +0000 Subject: [PATCH 3/7] chore: mobile tweaks --- src/components/View/TemprMap.js | 2 +- src/components/View/Temprs.js | 14 ++++++++++++-- 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/View/TemprMap.js b/src/components/View/TemprMap.js index 54c1823a5..45399eb0f 100644 --- a/src/components/View/TemprMap.js +++ b/src/components/View/TemprMap.js @@ -317,7 +317,7 @@ const TemprMap = props => { !noMap ? (
diff --git a/src/components/View/Temprs.js b/src/components/View/Temprs.js index 4a8ef66e5..f83eaf368 100644 --- a/src/components/View/Temprs.js +++ b/src/components/View/Temprs.js @@ -4,7 +4,7 @@ import { Link } from "react-router-dom"; import { Button, KIND } from "baseui/button"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faPlus, faEdit, faHistory } from "@fortawesome/free-solid-svg-icons"; +import { faPlus, faEdit, faHistory, faProjectDiagram } from "@fortawesome/free-solid-svg-icons"; import { useQueryParam, StringParam } from "use-query-params"; import { PaginatedTable, Page } from "../Universal"; @@ -64,6 +64,16 @@ const Temprs = props => { if (columnName === "action") { return ( <> +
- + console.log('handle onConnect', params)} + /> + console.log('handle onConnect', params)} + /> ); }); diff --git a/src/components/Global/index.js b/src/components/Global/index.js index 0f3c287e8..bda380afc 100644 --- a/src/components/Global/index.js +++ b/src/components/Global/index.js @@ -2,6 +2,7 @@ export * from "./DatetimeFilter"; export * from "./HttpTemprTemplate"; export * from "./NavigationItem"; export * from "./NavigationGroup"; +export * from "./OriginNode"; export * from "./PairInput"; export * from "./SiteSelector"; export * from "./TableFilter"; diff --git a/src/components/View/TemprMap.js b/src/components/View/TemprMap.js index 2e2fd0ec8..a2099d272 100644 --- a/src/components/View/TemprMap.js +++ b/src/components/View/TemprMap.js @@ -12,7 +12,7 @@ import ReactFlow, { useStoreState, } from "react-flow-renderer"; -import { TemprSidebar, TemprNode } from "../Global"; +import { TemprSidebar, TemprNode, OriginNode } from "../Global"; import { DataProvider, Page, InPlaceGifSpinner } from "../Universal"; import OopCore from "../../OopCore"; @@ -164,6 +164,7 @@ const TemprMap = props => { const nodeTypes = { temprNode: TemprNode, + originNode: OriginNode, }; const edgeTypes = { @@ -244,6 +245,21 @@ const TemprMap = props => { } } + async function getLinks(temprId) { + var dts = await OopCore.getDeviceTemprs({ + filter: { temprId: temprId }, + "page[size]": -1, + }); + var sts = await OopCore.getScheduleTemprs({ + filter: { temprId: temprId }, + "page[size]": -1, + }); + + var allLinks = dts.data.push(...sts.data); + console.log(allLinks); + return allLinks; + } + async function refresh() { setLoading(true); const response = await getData(props.match.params.temprId); @@ -277,7 +293,29 @@ const TemprMap = props => { }); }; - const formatPath = (sourceId, targetId) => { + const formatOriginNode = (originObj, pos, device) => { + const position = pos || { x: 200, y: 50 }; + const style = device ? { + border: "1px solid #777", + borderRadius: "20px", + padding: 10, + backgroundColor: "white", + } : { + border: "1px solid #777", + borderRadius: "20px", + padding: 10, + backgroundColor: "white", + }; + return ({ + id: `${device ? 'D' : 'S'}${originObj.id}`, + type: "originNode", + data: originObj, + style: style, + position: position, + }); + }; + + const formatPath = (sourceId, targetId, sourceHandle, targetHandle, dtId, stId) => { const type = noEdit ? "bezier" : "custom"; return ( { @@ -286,7 +324,9 @@ const TemprMap = props => { target: `${targetId}`, style: { stroke: '#777', strokeWidth: 1.5 }, type: type, - data: { onClick: deletePath }, + data: { onClick: deletePath, deviceTemprId: dtId, scheduleTemprId: stId }, + sourceHandle: sourceHandle, + targetHandle: targetHandle, } ); }; @@ -295,6 +335,7 @@ const TemprMap = props => { var nodeData = []; var pathData = new Set(); var tempr = await OopCore.getTempr(temprId); + const originalTempr = tempr; var allTemprs = await OopCore.getTemprs({ filter: { deviceGroupId: tempr.deviceGroupId }, }); @@ -337,6 +378,21 @@ const TemprMap = props => { var filteredNodes = nodeData.filter(Boolean); var remainingTemprs = allTemprs.data.filter(t => !nodeData[t.id]); filteredNodes.push(...pathArray); + const devices = await OopCore.getDevices({ + filter: { deviceGroupId: originalTempr.deviceGroupId }, + }); + const deviceNodes = devices.data.map(d => formatOriginNode(d, false, true)); + const schedules = await OopCore.getSchedules(); + const scheduleNodes = schedules.data.map(s => formatOriginNode(s, false, false)); + const newPaths = await Promise.all(nodeData.filter(Boolean).map(t => { + const links = getLinks(t.id); + + })); + console.log(newPaths); + const newP = formatPath(originalTempr.id, 'D22', `DT-${originalTempr.id}`, 'D-22'); + filteredNodes.push(...deviceNodes); + filteredNodes.push(...scheduleNodes); + filteredNodes.push(newP); return { title: titleNode, nodes: filteredNodes, From 960d8df6e69cc17969c6815ebb47701e7cb9d04c Mon Sep 17 00:00:00 2001 From: Ben Armstrong Date: Fri, 5 Feb 2021 16:23:32 +0000 Subject: [PATCH 7/7] feat: adding schedules and devices --- src/components/Global/OriginNode.js | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/components/Global/OriginNode.js diff --git a/src/components/Global/OriginNode.js b/src/components/Global/OriginNode.js new file mode 100644 index 000000000..1f11fa561 --- /dev/null +++ b/src/components/Global/OriginNode.js @@ -0,0 +1,21 @@ +import React, { memo } from "react"; +import { Handle } from "react-flow-renderer"; + +const OriginNode = memo(({ data }) => { + return ( + <> + console.log('handle onConnect', params)} + /> +

+ {data.name} +

+ + ); +}); + +export { OriginNode };