diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 0000000000000000000000000000000000000000..449fcdee1d48d5902834c23b76cc8f79dea677a5 --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1,4 @@ +#!/bin/sh +. "$(dirname "$0")/_/husky.sh" + +npm test diff --git a/apps/web-graphpolaris/src/components/schema/schema.stories.tsx b/apps/web-graphpolaris/src/components/schema/schema.stories.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4903884709a18860f5ee820fb3f6417a57120d4a --- /dev/null +++ b/apps/web-graphpolaris/src/components/schema/schema.stories.tsx @@ -0,0 +1,45 @@ +import React from 'react'; +import Schema from './schema'; +import { ComponentStory, ComponentMeta } from '@storybook/react'; +import { Provider } from 'react-redux'; +import { configureStore } from '@reduxjs/toolkit'; +import schemaSlice, { + setSchema, +} from 'libs/shared/data-access/store/src/lib/schemaSlice'; + +export default { + /* 👇 The title prop is optional. + * See https://storybook.js.org/docs/react/configure/overview#configure-story-loading + * to learn how to generate automatic titles + */ + title: 'Schema', + component: Schema, + decorators: [ + (story) => ( + <div style={{ padding: '3rem' }}> + <Provider store={Mockstore}>{story()}</Provider> + </div> + ), + ], +} as ComponentMeta<typeof Schema>; + +const Template: ComponentStory<typeof Schema> = (args) => <Schema {...args} />; + +// A super-simple mock of a redux store +const Mockstore = configureStore({ + reducer: { + schema: schemaSlice, + }, +}); + +export const TestWithSchema = Template.bind({}); + +TestWithSchema.play = async () => { + const dispatch = Mockstore.dispatch; + dispatch( + setSchema({ + id: 1, + // mock schema hiero + }) + ); +}; diff --git a/apps/web-graphpolaris/src/components/schema/schema.tsx b/apps/web-graphpolaris/src/components/schema/schema.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fd4b20c916552bac29ead6fbe753ff3f8c1ca7d0 --- /dev/null +++ b/apps/web-graphpolaris/src/components/schema/schema.tsx @@ -0,0 +1,37 @@ +import { useSchema } from '@graphpolaris/shared/data-access/store'; +//import { useEffect } from 'react'; +import ReactFlow from 'react-flow-renderer'; +import styled from 'styled-components'; +import { createReactFlowElements } from '@graphpolaris/schema/schema-usecases'; + +interface Props { + content: string; +} + +const Div = styled.div` + background-color: red; + font: 'Arial'; +`; + +const Schema = (props: Props) => { + const dbschema = useSchema(); + + // In case the schema is updated + // useEffect(() => { + // console.log('update schema useEffect'); + // }, [dbschema]); + + return ( + <Div> + <ReactFlow elements={createReactFlowElements(dbschema)} /> + </Div> + ); +}; + +export default Schema; + +// Fix layout of the schema +// create reactflow elements on xy coords +// connect reactflow elements together + +// maybe ook gelijk instellingen knoppie fixen op alle panels diff --git a/libs/schema/schema-usecases/.babelrc b/libs/schema/schema-usecases/.babelrc new file mode 100644 index 0000000000000000000000000000000000000000..cf7ddd99c615a064ac18eb3109eee4f394ab1faf --- /dev/null +++ b/libs/schema/schema-usecases/.babelrc @@ -0,0 +1,3 @@ +{ + "presets": [["@nrwl/web/babel", { "useBuiltIns": "usage" }]] +} diff --git a/libs/schema/schema-usecases/.eslintrc.json b/libs/schema/schema-usecases/.eslintrc.json new file mode 100644 index 0000000000000000000000000000000000000000..3456be9b9036a42c593c82b050281230e4ca0ae4 --- /dev/null +++ b/libs/schema/schema-usecases/.eslintrc.json @@ -0,0 +1,18 @@ +{ + "extends": ["../../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + } + ] +} diff --git a/libs/schema/schema-usecases/README.md b/libs/schema/schema-usecases/README.md new file mode 100644 index 0000000000000000000000000000000000000000..52ab1f83a954f953decb97a40f2afd07239d9a12 --- /dev/null +++ b/libs/schema/schema-usecases/README.md @@ -0,0 +1,7 @@ +# schema-schema-usecases + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test schema-schema-usecases` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/libs/schema/schema-usecases/jest.config.js b/libs/schema/schema-usecases/jest.config.js new file mode 100644 index 0000000000000000000000000000000000000000..3ce30ca8d9b273a15c9fa74b349d6dd9df8be839 --- /dev/null +++ b/libs/schema/schema-usecases/jest.config.js @@ -0,0 +1,14 @@ +module.exports = { + displayName: 'schema-schema-usecases', + preset: '../../../jest.preset.js', + globals: { + 'ts-jest': { + tsconfig: '<rootDir>/tsconfig.spec.json', + }, + }, + transform: { + '^.+\\.[tj]sx?$': 'ts-jest', + }, + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], + coverageDirectory: '../../../coverage/libs/schema/schema-usecases', +}; diff --git a/libs/schema/schema-usecases/project.json b/libs/schema/schema-usecases/project.json new file mode 100644 index 0000000000000000000000000000000000000000..39846a002e9e098d8027a092f82630812391f264 --- /dev/null +++ b/libs/schema/schema-usecases/project.json @@ -0,0 +1,23 @@ +{ + "root": "libs/schema/schema-usecases", + "sourceRoot": "libs/schema/schema-usecases/src", + "projectType": "library", + "targets": { + "lint": { + "executor": "@nrwl/linter:eslint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/schema/schema-usecases/**/*.ts"] + } + }, + "test": { + "executor": "@nrwl/jest:jest", + "outputs": ["coverage/libs/schema/schema-usecases"], + "options": { + "jestConfig": "libs/schema/schema-usecases/jest.config.js", + "passWithNoTests": true + } + } + }, + "tags": [] +} diff --git a/libs/schema/schema-usecases/src/index.ts b/libs/schema/schema-usecases/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5d984685980c34d4a947c278f84a8ea4b755a323 --- /dev/null +++ b/libs/schema/schema-usecases/src/index.ts @@ -0,0 +1 @@ +export * from './lib/schema-schema-usecases'; diff --git a/libs/schema/schema-usecases/src/lib/schema-schema-usecases.spec.ts b/libs/schema/schema-usecases/src/lib/schema-schema-usecases.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..f2130094ed2bbfa865b7f61af9d6c130eb32dfe2 --- /dev/null +++ b/libs/schema/schema-usecases/src/lib/schema-schema-usecases.spec.ts @@ -0,0 +1,7 @@ +import { schemaSchemaUsecases } from './schema-schema-usecases'; + +describe('schemaSchemaUsecases', () => { + it('should work', () => { + expect(schemaSchemaUsecases()).toEqual('schema-schema-usecases'); + }); +}); diff --git a/libs/schema/schema-usecases/src/lib/schema-schema-usecases.ts b/libs/schema/schema-usecases/src/lib/schema-schema-usecases.ts new file mode 100644 index 0000000000000000000000000000000000000000..0eee56b95528c919e1fc2fdf5a307ee643e55566 --- /dev/null +++ b/libs/schema/schema-usecases/src/lib/schema-schema-usecases.ts @@ -0,0 +1,178 @@ +import Graph from 'graphology'; +import * as cs from 'cytoscape'; +import { setSchema, store } from '@graphpolaris/shared/data-access/store'; +import { Elements, Node, Edge } from 'react-flow-renderer'; + +type CytoNode = { + data: { + id: string; + type: string; + source?: string; + target?: string; + position?: { + x: number; + y: number; + }; + }; +}; + +// Layouts a given schema +export function handleSchemaLayout(graph: Graph): void { + const layout = createSchemaLayout(graph); + + layout.then((cy) => { + cy.cy.elements().forEach((elem) => { + const position = elem.position(); + + graph.setNodeAttribute(elem.id(), 'x', position.x); + graph.setNodeAttribute(elem.id(), 'y', position.y); + }); + + store.dispatch(setSchema(graph)); + }); +} + +// Creates a schema layout (async) +function createSchemaLayout(graph: Graph): Promise<cytoscape.EventObject> { + const cytonodes: CytoNode[] = trimSchema(graph); + + const cy = cs({ + elements: cytonodes, + }); + + const options = { + name: 'cose', + + // Whether to animate while running the layout + // true : Animate continuously as the layout is running + // false : Just show the end result + // 'end' : Animate with the end result, from the initial positions to the end positions + animate: true, + + // Easing of the animation for animate:'end' + animationEasing: undefined, + + // The duration of the animation for animate:'end' + animationDuration: undefined, + + // A function that determines whether the node should be animated + // All nodes animated by default on animate enabled + // Non-animated nodes are positioned immediately when the layout starts + // animateFilter: function (node: any, i: any) { + // return true; + // }, + + // The layout animates only after this many milliseconds for animate:true + // (prevents flashing on fast runs) + animationThreshold: 250, + + // Number of iterations between consecutive screen positions update + refresh: 20, + + // Whether to fit the network view after when done + fit: true, + + // Padding on fit + padding: 60, //30 + + // Constrain layout bounds; { x1, y1, x2, y2 } or { x1, y1, w, h } + boundingBox: undefined, + + // Excludes the label when calculating node bounding boxes for the layout algorithm + nodeDimensionsIncludeLabels: false, + + // Randomize the initial positions of the nodes (true) or use existing positions (false) + randomize: false, + + // Extra spacing between components in non-compound graphs + componentSpacing: 200, // 40 + + // Node repulsion (non overlapping) multiplier + nodeRepulsion: function (node: any) { + return 2048; + }, + + // Node repulsion (overlapping) multiplier + nodeOverlap: 8, //4 + + // Ideal edge (non nested) length + idealEdgeLength: function (edge: any) { + return 32; //32 + }, + + // Divisor to compute edge forces + edgeElasticity: function (edge: any) { + return 32; + }, + + // Nesting factor (multiplier) to compute ideal edge length for nested edges + nestingFactor: 1.2, + + // Gravity force (constant) + gravity: 1, + + // Maximum number of iterations to perform + numIter: 1000, + + // Initial temperature (maximum node displacement) + initialTemp: 1000, + + // Cooling factor (how the temperature is reduced between consecutive iterations + coolingFactor: 0.99, + + // Lower temperature threshold (below this point the layout will end) + minTemp: 1.0, + }; + + const layout = cy.layout(options); + + layout.run(); + + return layout.pon('layoutstop'); +} + +// Takes the schema as input and creates a list of nodes and edges in a format that the layouting algorithm can use. +function trimSchema(graph: Graph): CytoNode[] { + const cytonodes: CytoNode[] = []; + + graph.forEachNode((node) => { + cytonodes.push({ + data: { id: node, type: 'node' }, + }); + }); + + graph.forEachEdge((edge, _attributes, source, target) => { + cytonodes.push({ + data: { id: edge, type: 'edge', source: source, target: target }, + }); + }); + + return cytonodes; +} + +// Takes the schema as an imput and creates basic react flow elements for them. +export function createReactFlowElements(graph: Graph): Elements<Node | Edge> { + const initialElements: Elements<Node | Edge> = []; + + graph.forEachNode((node, attributes) => { + const newNode: Node = { + id: node, + data: { + label: attributes.name, + }, + position: { x: attributes.x, y: attributes.y }, + }; + initialElements.push(newNode); + }); + + graph.forEachEdge((edge, _attributes, source, target) => { + const newEdge: Edge = { + id: edge, + source: source, + target: target, + }; + initialElements.push(newEdge); + }); + + return initialElements; +} diff --git a/libs/schema/schema-usecases/tsconfig.json b/libs/schema/schema-usecases/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..355f7fda9792f1426646744fb60198b3dd36560b --- /dev/null +++ b/libs/schema/schema-usecases/tsconfig.json @@ -0,0 +1,19 @@ +{ + "extends": "../../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + } +} diff --git a/libs/schema/schema-usecases/tsconfig.lib.json b/libs/schema/schema-usecases/tsconfig.lib.json new file mode 100644 index 0000000000000000000000000000000000000000..efdd77fbf5b34f06e8efa8ad8bc87e11a3c1e9af --- /dev/null +++ b/libs/schema/schema-usecases/tsconfig.lib.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "declaration": true, + "types": [] + }, + "include": ["**/*.ts"], + "exclude": ["**/*.spec.ts"] +} diff --git a/libs/schema/schema-usecases/tsconfig.spec.json b/libs/schema/schema-usecases/tsconfig.spec.json new file mode 100644 index 0000000000000000000000000000000000000000..d8716fecfa3b7929f162b71e7a966c579a63c071 --- /dev/null +++ b/libs/schema/schema-usecases/tsconfig.spec.json @@ -0,0 +1,19 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"] + }, + "include": [ + "**/*.test.ts", + "**/*.spec.ts", + "**/*.test.tsx", + "**/*.spec.tsx", + "**/*.test.js", + "**/*.spec.js", + "**/*.test.jsx", + "**/*.spec.jsx", + "**/*.d.ts" + ] +} diff --git a/libs/shared/data-access/store/src/index.ts b/libs/shared/data-access/store/src/index.ts index 8251e55eecd3b36bb67afdcf18acf84aa24127b6..d950f6edcc3298abc1735b463e5f9f3b230b6374 100644 --- a/libs/shared/data-access/store/src/index.ts +++ b/libs/shared/data-access/store/src/index.ts @@ -1,5 +1,7 @@ export * from './lib/store'; export * from './lib/hooks'; + +export { setSchema, readInSchemaFromBackend } from './lib/schemaSlice'; export { selectGraphQueryResult, selectGraphQueryResultLinks, diff --git a/libs/shared/data-access/store/src/lib/schemaSlice.ts b/libs/shared/data-access/store/src/lib/schemaSlice.ts index a8a22e05b4515e1bbdd1462928ef672d67b97dcd..4bd77364d3ee6b620bace763dbbd3dc5776ec2ee 100644 --- a/libs/shared/data-access/store/src/lib/schemaSlice.ts +++ b/libs/shared/data-access/store/src/lib/schemaSlice.ts @@ -42,6 +42,10 @@ export const schemaSlice = createSlice({ // `createSlice` will infer the state type from the `initialState` argument initialState, reducers: { + setSchema: (state, action: PayloadAction<DirectedGraph>) => { + state.graphologySerialized = action.payload.export(); + }, + readInSchemaFromBackend: ( state, action: PayloadAction<SchemaFromBackend> @@ -49,22 +53,44 @@ export const schemaSlice = createSlice({ const { nodes, edges } = action.payload; // Instantiate a directed graph that allows self loops and parallel edges const schema = new DirectedGraph({ allowSelfLoops: true, multi: true }); + + // The graph schema needs a node for each node AND edge. These need then be connected + nodes.forEach((node) => { - schema.addNode(node.name, { attributes: node.attributes }); + schema.addNode(node.name, { + name: node.name, + attributes: node.attributes, + x: 0, + y: 0, + }); }); - edges.forEach((edge) => - schema.addDirectedEdgeWithKey(edge.name, edge.from, edge.to, { + // The name of the edge will be name + from + to, since edge names are not unique + edges.forEach((edge) => { + const edgeID = edge.name + edge.from + edge.to; + + // This node is the actual edge + schema.addNode(edgeID, { + name: edge.name, + attributes: edge.attributes, + from: edge.from, + to: edge.to, collection: edge.collection, - }) - ); + x: 0, + y: 0, + }); + + // These lines are simply for keeping the schema together + schema.addDirectedEdgeWithKey(edgeID + 'f', edge.from, edgeID); + schema.addDirectedEdgeWithKey(edgeID + 't', edgeID, edge.to); + }); state.graphologySerialized = schema.export(); }, }, }); -export const { readInSchemaFromBackend } = schemaSlice.actions; +export const { readInSchemaFromBackend, setSchema } = schemaSlice.actions; // Select the schema and convert it to a graphology object export const selectSchema = (state: RootState) => diff --git a/package.json b/package.json index 64fe528c6b0be6c11047b069b44da5c20b9eb73d..c6242a66fb41451e26472f3ce06b95013c2e02c0 100644 --- a/package.json +++ b/package.json @@ -12,13 +12,16 @@ "dependencies": { "@commitlint/config-conventional": "^16.0.0", "@reduxjs/toolkit": "^1.7.1", + "@types/cytoscape": "^3.19.4", "@types/react-grid-layout": "^1.3.0", "@types/styled-components": "^5.1.21", "core-js": "^3.6.5", + "cytoscape": "^3.21.0", "graphology": "^0.23.2", "graphology-types": "^0.23.0", "react": "17.0.2", "react-dom": "17.0.2", + "react-flow-renderer": "^9.7.4", "react-grid-layout": "^1.3.3", "react-json-view": "^1.21.3", "react-redux": "^7.2.6", @@ -65,7 +68,7 @@ "eslint-plugin-jsx-a11y": "6.5.1", "eslint-plugin-react": "7.27.0", "eslint-plugin-react-hooks": "4.3.0", - "husky": "^7.0.4", + "husky": "^7.0.0", "jest": "27.2.3", "prettier": "^2.5.1", "react-test-renderer": "17.0.2", diff --git a/tsconfig.base.json b/tsconfig.base.json index 5a2caf532de87019c51c475c16870bedb9fb4e9e..ceb128bb72e29ebb3dd7b2eba330e4434828aaae 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -15,6 +15,9 @@ "skipDefaultLibCheck": true, "baseUrl": ".", "paths": { + "@graphpolaris/schema/schema-usecases": [ + "libs/schema/schema-usecases/src/index.ts" + ], "@graphpolaris/shared/data-access/store": [ "libs/shared/data-access/store/src/index.ts" ] diff --git a/workspace.json b/workspace.json index 1a59e05a31f38abe3f9085968e95163374b70590..812b87061e3c4207ad3be294da0f0998e1dd543c 100644 --- a/workspace.json +++ b/workspace.json @@ -1,6 +1,7 @@ { "version": 2, "projects": { + "schema-schema-usecases": "libs/schema/schema-usecases", "shared-data-access-store": "libs/shared/data-access/store", "web-graphpolaris": "apps/web-graphpolaris", "web-graphpolaris-e2e": "apps/web-graphpolaris-e2e" diff --git a/yarn.lock b/yarn.lock index 948c5e10973c321308c4797e1bfc37117c2868d6..43c74ec78ddb241b15776b3335f5453bfcfc0c3b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3973,6 +3973,11 @@ dependencies: "@types/node" "*" +"@types/cytoscape@^3.19.4": + version "3.19.4" + resolved "https://registry.yarnpkg.com/@types/cytoscape/-/cytoscape-3.19.4.tgz#f41214103b80ff3d7d8741bacc32265ed90e45b5" + integrity sha512-0IozTg1vdZrA3nuAK5o9Pa8nl2INUnTaXwcGwoiALDcsD8/TiVnp0Zi+R1IiPRG6edoy0Ya61/3osFLtfkhhmw== + "@types/eslint-scope@^3.7.0": version "3.7.3" resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.3.tgz#125b88504b61e3c8bc6f870882003253005c3224" @@ -6265,6 +6270,11 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +classcat@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/classcat/-/classcat-5.0.3.tgz#38eaa0ec6eb1b10faf101bbcef2afb319c23c17b" + integrity sha512-6dK2ke4VEJZOFx2ZfdDAl5OhEL8lvkl6EHF92IfRePfHxQTqir5NlcNVUv+2idjDqCX2NDc8m8YSAI5NI975ZQ== + clean-css@^4.2.3: version "4.2.4" resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.4.tgz#733bf46eba4e607c6891ea57c24a989356831178" @@ -7305,6 +7315,79 @@ cypress@^9.1.0: untildify "^4.0.0" yauzl "^2.10.0" +cytoscape@^3.21.0: + version "3.21.0" + resolved "https://registry.yarnpkg.com/cytoscape/-/cytoscape-3.21.0.tgz#8a73f6f0f3a44f948e266ac7df9b2eff65e8bd3c" + integrity sha512-xPINMzQNGN4WIog93gYRScT4y/CyZMmqunnhU59/8LynhWwzepJtUydMfvIPuz5TmJ9rSCMdw6rmxhfbb1eofw== + dependencies: + heap "^0.2.6" + lodash.debounce "^4.0.8" + lodash.get "^4.4.2" + lodash.set "^4.3.2" + lodash.topath "^4.5.2" + +"d3-color@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.0.1.tgz#03316e595955d1fcd39d9f3610ad41bb90194d0a" + integrity sha512-6/SlHkDOBLyQSJ1j1Ghs82OIUXpKWlR0hCsw0XrLSQhuUPuCSmLQ1QPH98vpnQxMUQM2/gfAkUEWsupVpd9JGw== + +"d3-dispatch@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== + +"d3-drag@2 - 3": + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" + integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== + dependencies: + d3-dispatch "1 - 3" + d3-selection "3" + +"d3-ease@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + +"d3-interpolate@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + +"d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" + integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== + +"d3-timer@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + +"d3-transition@2 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" + integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== + dependencies: + d3-color "1 - 3" + d3-dispatch "1 - 3" + d3-ease "1 - 3" + d3-interpolate "1 - 3" + d3-timer "1 - 3" + +d3-zoom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" + integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "2 - 3" + d3-transition "2 - 3" + damerau-levenshtein@^1.0.7: version "1.0.8" resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz#b43d286ccbd36bc5b2f7ed41caf2d0aba1f8a6e7" @@ -9533,6 +9616,11 @@ he@^1.2.0: resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +heap@^0.2.6: + version "0.2.7" + resolved "https://registry.yarnpkg.com/heap/-/heap-0.2.7.tgz#1e6adf711d3f27ce35a81fe3b7bd576c2260a8fc" + integrity sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg== + highlight.js@^10.1.1, highlight.js@~10.7.0: version "10.7.3" resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531" @@ -9797,7 +9885,7 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== -husky@^7.0.4: +husky@^7.0.0: version "7.0.4" resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.4.tgz#242048245dc49c8fb1bf0cc7cfb98dd722531535" integrity sha512-vbaCKN2QLtP/vD4yvs6iz6hBEo6wkSzs8HpRah1Z6aGmF2KW5PdYuAd7uX5a+OyBZHBhd+TFLqgjUgytQr4RvQ== @@ -11515,6 +11603,11 @@ lodash.flow@^3.3.0: resolved "https://registry.yarnpkg.com/lodash.flow/-/lodash.flow-3.5.0.tgz#87bf40292b8cf83e4e8ce1a3ae4209e20071675a" integrity sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o= +lodash.get@^4.4.2: + version "4.4.2" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" + integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= + lodash.isequal@^4.0.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0" @@ -11540,6 +11633,16 @@ lodash.once@^4.1.1: resolved "https://registry.yarnpkg.com/lodash.once/-/lodash.once-4.1.1.tgz#0dd3971213c7c56df880977d504c88fb471a97ac" integrity sha1-DdOXEhPHxW34gJd9UEyI+0cal6w= +lodash.set@^4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" + integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= + +lodash.topath@^4.5.2: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.topath/-/lodash.topath-4.5.2.tgz#3616351f3bba61994a0931989660bd03254fd009" + integrity sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak= + lodash.uniq@4.5.0, lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -13685,7 +13788,7 @@ react-dom@17.0.2: object-assign "^4.1.1" scheduler "^0.20.2" -react-draggable@^4.0.0, react-draggable@^4.0.3, react-draggable@^4.4.3: +react-draggable@^4.0.0, react-draggable@^4.0.3, react-draggable@^4.4.3, react-draggable@^4.4.4: version "4.4.4" resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.4.tgz#5b26d9996be63d32d285a426f41055de87e59b2f" integrity sha512-6e0WdcNLwpBx/YIDpoyd2Xb04PB0elrDrulKUgdrIlwuYvxh5Ok9M+F8cljm8kPXXs43PmMzek9RrB1b7mLMqA== @@ -13714,6 +13817,20 @@ react-fast-compare@^3.0.1, react-fast-compare@^3.2.0: resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-3.2.0.tgz#641a9da81b6a6320f270e89724fb45a0b39e43bb" integrity sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA== +react-flow-renderer@^9.7.4: + version "9.7.4" + resolved "https://registry.yarnpkg.com/react-flow-renderer/-/react-flow-renderer-9.7.4.tgz#11394c05ca953b650e2017d056c075fd3df9075c" + integrity sha512-GxHBXzkn8Y+TEG8pul7h6Fjo4cKrT0kW9UQ34OAGZqAnSBLbBsx9W++TF8GiULBbTn3O8o7HtHxux685Op10mQ== + dependencies: + "@babel/runtime" "^7.16.7" + classcat "^5.0.3" + d3-selection "^3.0.0" + d3-zoom "^3.0.0" + fast-deep-equal "^3.1.3" + react-draggable "^4.4.4" + react-redux "^7.2.6" + redux "^4.1.2" + react-grid-layout@^1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/react-grid-layout/-/react-grid-layout-1.3.3.tgz#6d255ae036bb2371a46effd494ca4dd6f7224311"