From 23a372010f4dd134b05e6b3119b6887a14694130 Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Thu, 18 May 2017 14:33:11 +0200 Subject: [PATCH 01/10] Replace vivagraph with sigma --- package.json | 2 +- .../epl-sup-tree/components/DiffManager.js | 38 ++ .../epl-sup-tree/components/SupTree.js | 380 ++------------ ui/src/plugins/epl-sup-tree/reducer.js | 89 +++- yarn.lock | 474 +++++++++++++----- 5 files changed, 521 insertions(+), 462 deletions(-) create mode 100644 ui/src/plugins/epl-sup-tree/components/DiffManager.js diff --git a/package.json b/package.json index 43a83de..78ad832 100644 --- a/package.json +++ b/package.json @@ -67,10 +67,10 @@ "react-redux": "^5.0.2", "react-router-dom": "^4.0.0", "react-router-redux": "next", + "react-sigma": "^1.2.17", "react-virtualized": "^9.0.4", "recharts": "^0.21.2", "redux": "^3.6.0", - "vivagraphjs": "^0.8.2", "vizceral-react": "4.4.0" }, "scripts": { diff --git a/ui/src/plugins/epl-sup-tree/components/DiffManager.js b/ui/src/plugins/epl-sup-tree/components/DiffManager.js new file mode 100644 index 0000000..051f3bf --- /dev/null +++ b/ui/src/plugins/epl-sup-tree/components/DiffManager.js @@ -0,0 +1,38 @@ +// @flow +import React, { Component } from 'react'; + +export function embedProps(elements: mixed, extraProps: any) { + return React.Children.map(elements, element => + React.cloneElement(element, extraProps) + ); +} + +class DiffManager extends Component { + constructor(props: any) { + super(props); + const { nodes, edges } = props.graph; + nodes.forEach(node => props.sigma.graph.addNode(node)); + edges.forEach(edge => props.sigma.graph.addEdge(edge)); + } + + componentWillReceiveProps(props: any) { + const { nodes, edges } = props.graph; + console.log(props); + nodes.forEach(node => props.sigma.graph.addNode(node)); + edges.forEach(edge => props.sigma.graph.addEdge(edge)); + // TODO: create list of old and new (nodes, edges) + // TODO: remove old, add new (nodes, edges) + console.log(props.sigma); + // props.sigma.startForceAtlas2(); + } + + render() { + return ( +
+ {embedProps(this.props.children, { sigma: this.props.sigma })} +
+ ); + } +} + +export default DiffManager; diff --git a/ui/src/plugins/epl-sup-tree/components/SupTree.js b/ui/src/plugins/epl-sup-tree/components/SupTree.js index b9a786b..220b883 100644 --- a/ui/src/plugins/epl-sup-tree/components/SupTree.js +++ b/ui/src/plugins/epl-sup-tree/components/SupTree.js @@ -1,352 +1,62 @@ // @flow import React, { Component } from 'react'; import { connect } from 'react-redux'; -import Viva from 'vivagraphjs'; -import difference from 'lodash/difference'; -import { Motion, spring } from 'react-motion'; -import { ListGroup, ListGroupItem } from 'react-bootstrap'; +// import difference from 'lodash/difference'; +// import { Motion, spring } from 'react-motion'; +// import { ListGroup, ListGroupItem } from 'react-bootstrap'; + +// import { send } from '../../../sockets'; +import { + Sigma, + EdgeShapes, + // SigmaEnableWebGL, + NodeShapes, + RelativeSize, + ForceAtlas2, + RandomizeNodePositions +} from 'react-sigma'; + +import DiffManager from './DiffManager'; +import ForceLink from 'react-sigma/lib/ForceLink'; -import { send } from '../../../sockets'; import './SupTree.css'; -const COLORS = { - supervisor: '#227A50', - worker: '#1F79B7' -}; - class SupTree extends Component { div: any; - state: { - graphics: any, - graph: any, - layout: any, - renderer: any, - events: any, - - collapse: boolean, - height: Array, - selected: { id: string, color: number, type: string }, - appsNodes: Array<*>, - apps: Array, - first: boolean, - all: Array - }; - - constructor(props: any) { - super(props); - this.state = { - graphics: null, - graph: null, - layout: null, - renderer: null, - events: null, - - collapse: false, - height: [50, 50], - selected: { id: 'Applications', color: 0, type: '' }, - appsNodes: [], - apps: [], - all: [], - first: true - }; - } - - componentDidMount() { - const graph = Viva.Graph.graph(); - const graphics = Viva.Graph.View.webglGraphics(); - - graphics - .node(node => { - const size = node.data && node.data.type === 'worker' ? 10 : 15; - const color = node.data && COLORS.hasOwnProperty(node.data.type) - ? COLORS[node.data.type] - : '#000'; - - return Viva.Graph.View.webglSquare(size, color); - }) - .link(link => { - return Viva.Graph.View.webglLine('#808080'); - }); - - const layout = Viva.Graph.Layout.forceDirected(graph, { - springLength: 1, - springCoeff: 0.0001, - dragCoeff: 0.1, - gravity: -0.5 - }); - - const renderer = Viva.Graph.View.renderer(graph, { - container: this.div, - graphics, - layout, - prerender: 1200 - }); - - const events = Viva.Graph.webglInputEvents(graphics, graph); - - events.click(({ id }) => this.selectNode(id)); - - setTimeout(() => { - this.setState({ renderer, graph, graphics, layout, events }, () => - this.propagateGraph() - ); - }, 0); - } - - selectNode(id: string, center: ?boolean) { - const { layout, renderer, selected, graphics } = this.state; - - const oldNode = graphics.getNodeUI(selected.id); - if (oldNode) { - oldNode.color = selected.color; - } - - const node = graphics.getNodeUI(id); - const color = node.color; - node.color = 0xdf307dff; - - if (center) { - const { x, y } = layout.getNodePosition(id); - renderer.moveTo(x, y); - } - - send('epl_st_EPL', id); - this.setState({ selected: { id, color, type: node.node.data.type } }); - } - - mapChild(child, parent) { - const { all, graph } = this.state; - - if (all.indexOf(child.id) < 0) { - graph.addNode(child.id, { ...child }); - graph.addLink(child.id, parent.id); - } - - return [child.id].concat( - child.children.reduce((acc, a) => acc.concat(this.mapChild(a, child)), []) - ); - } - - propagateGraph(p) { - const props = p || this.props; - - if (!this.state.graph) return; - - const { all } = this.state; + componentDidMount() {} - let appsNodes = []; //this.state.appsNodes; - - const list = Object.keys(props.tree).reduce((acc, app) => { - const parent = props.tree[app]; - if (Object.keys(parent).length) { - if (all.indexOf(parent.id) < 0) { - const app = this.state.graph.addNode(parent.id, { ...parent }); - if (!this.state.appsNodes.includes(app)) { - appsNodes.push(app); - } - } - - return acc - .concat(parent.id) - .concat( - parent.children.reduce( - (acc, child) => acc.concat(this.mapChild(child, parent)), - [] - ) - ); - } - - return acc; - }, []); - - if (this.state.first && Object.keys(props.tree).length) { - this.state.renderer.run(); - this.setState({ first: false }); - } - - // simple diffing to remove non existing nodes - difference(all, list).forEach(id => this.state.graph.removeNode(id)); - - appsNodes.forEach(app => this.state.layout.pinNode(app, true)); - this.setState({ - appsNodes, - apps: Object.keys(props.tree), - all: list - }); - } - - componentWillReceiveProps(props) { - this.propagateGraph(props); - } - - handleAppClick(app: string, id: string) { - this.toggleTree(id, this.state.apps.includes(app)); - this.setState(({ apps }) => { - if (apps.includes(app)) { - const index = apps.indexOf(app); - return { apps: [...apps.slice(0, index), ...apps.slice(index + 1)] }; - } else { - return { apps: [...apps, app].sort() }; - } - }); - } - - changeColorNode(color: number, hide: boolean): number { - // set to 00 - transparent - // set to ff - solid - return parseInt(color.toString(16).slice(0, 6) + (hide ? '00' : 'ff'), 16); - } - - changeColorLink(color: number, hide: boolean): number { - if (hide) { - return parseInt(color.toString(16).slice(0, 6) + '00', 16); - } else { - return parseInt('808080ff', 16); - } - } - - toggleTree(id: string, hide: boolean) { - const node = this.state.graphics.getNodeUI(id); - if (node) { - node.color = this.changeColorNode(node.color, hide); - node.node.links.forEach(({ id }) => { - const link = this.state.graphics.getLinkUI(id); - link.color = this.changeColorLink(link.color, hide); - }); - node.node.data.children.forEach(n => this.toggleTree(n.id, hide)); - } - } - - selectAll = () => { - this.setState((state, { tree }) => ({ - apps: Object.keys(tree).map(app => { - this.toggleTree(tree[app].id, false); - return app; - }) - })); - }; - - clearAll = () => { - this.state.apps.forEach(a => this.toggleTree(this.props.tree[a].id, true)); - this.setState({ apps: [] }); - }; - - toggleCollapse = () => { - this.setState(({ collapse, hEnd, hStart }) => ({ - collapse: !collapse, - height: collapse ? [50, 0] : [0, 50] - })); - }; + componentWillReceiveProps(props) {} render() { return (
- - {this.state.first && -
-
-
-
-
-
-
- Creating graph -
-
} - -
(this.div = node)} /> -
- -
-

- {this.state.selected.id} -

- -
- - ( -
- - {!this.state.first && -
- - - - - - - {Object.keys(this.props.tree).map( - (app, key) => - (Object.keys(this.props.tree[app]).length - ? - - this.handleAppClick( - app, - this.props.tree[app].id - )} - /> - - this.selectNode( - this.props.tree[app].id, - true - )} - > - {app} - - - : - - {app} - - ) - )} - -
} - -
-
-                    
-                      {this.props.nodeInfo &&
-                        JSON.stringify(this.props.nodeInfo, null, 2)}
-                    
-                  
-
-
- )} - /> -
+ + + + + + {/* */} + + + +
); } diff --git a/ui/src/plugins/epl-sup-tree/reducer.js b/ui/src/plugins/epl-sup-tree/reducer.js index 16896b4..0d8d96b 100644 --- a/ui/src/plugins/epl-sup-tree/reducer.js +++ b/ui/src/plugins/epl-sup-tree/reducer.js @@ -1,20 +1,93 @@ // @flow import { combineReducers } from 'redux'; -import * as t from './actionTypes'; +import * as type from './actionTypes'; -const treeReducer = (state: any = {}, action: any) => { - if (action.type === t.UPDATE_APPS_INFO) { - return action.data; +const COLORS = { + supervisor: '#227A50', + worker: '#1F79B7' +}; + +const SIZE = { + supervisor: 8, + worker: 0.1 +}; + +const INITIAL_STATE = { nodes: [], edges: [] }; + +function mapNode(node) { + const { nodes, edges } = (node.children || []).reduce(( + { nodes, edges }, + node + ) => { + const c = mapNode(node); + return { + nodes: nodes.concat(c.nodes), + edges: edges.concat(c.edges) + }; + }, { nodes: [], edges: [] }); + + return { + nodes: (node.children || []) + .map(n => ({ + label: node.id, + x: Math.random() * 100, + y: Math.random() * 100, + size: SIZE[node.type], + color: COLORS[n.type], + id: n.id + })) + .concat(nodes), + edges: (node.children || []) + .map(c => ({ + id: `f${node.id}t${c.id}`, + color: 'rgba(157,165,180, 100)', + size: 0.1, + source: node.id, + target: c.id + })) + .concat(edges) + }; +} + +function treeReducer(state: any = INITIAL_STATE, action: any) { + if (action.type === type.UPDATE_APPS_INFO) { + console.log(action.data); + const d = Object.keys(action.data).reduce( + ({ nodes, edges }, key) => { + const node = action.data[key]; + const c = mapNode(node); + const n = node.type + ? [ + ...nodes, + { + label: node.id, + x: Math.random() * 100, + y: Math.random() * 100, + size: SIZE[node.type], + color: COLORS[node.type], + id: node.id + } + ].concat(c.nodes) + : nodes; + + const e = edges.concat(c.edges); + + return { nodes: n, edges: e }; + }, + { nodes: [], edges: [] } + ); + console.log(d); + return d; } return state; -}; +} -const nodeInfoReducer = (state: any = null, action: any) => { - if (action.type === t.UPDATE_NODE_INFO) { +function nodeInfoReducer(state: any = null, action: any) { + if (action.type === type.UPDATE_NODE_INFO) { return action.info; } return state; -}; +} export default combineReducers({ tree: treeReducer, diff --git a/yarn.lock b/yarn.lock index 5ef8cb5..0a3d851 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,6 +17,12 @@ accepts@~1.3.3: mime-types "~2.1.11" negotiator "0.6.1" +acorn-dynamic-import@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" + dependencies: + acorn "^4.0.3" + acorn-globals@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf" @@ -33,19 +39,15 @@ acorn@^3.0.0, acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^4.0.4: +acorn@^4.0.3, acorn@^4.0.4: version "4.0.11" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.11.tgz#edcda3bd937e7556410d42ed5860f67399c794c0" -acorn@^5.0.1: +acorn@^5.0.0, acorn@^5.0.1: version "5.0.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" -add-event-listener@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/add-event-listener/-/add-event-listener-0.0.1.tgz#a76229ebc64c8aefae204a16273a2f255abea2d0" - -ajv-keywords@^1.0.0: +ajv-keywords@^1.0.0, ajv-keywords@^1.1.1: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" @@ -172,6 +174,14 @@ asap@~2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.5.tgz#522765b50c3510490e52d7dcfe085ef9ba96958f" +asn1.js@^4.0.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" @@ -206,7 +216,7 @@ async@^1.3.0, async@^1.4.0, async@^1.5.0: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" -async@^2.0.1, async@^2.1.4: +async@^2.0.1, async@^2.1.2, async@^2.1.4: version "2.3.0" resolved "https://registry.yarnpkg.com/async/-/async-2.3.0.tgz#1013d1051047dd320fe24e494d5c66ecaf6147d9" dependencies: @@ -955,6 +965,10 @@ bluebird@^3.4.6, bluebird@^3.5.0: version "3.5.0" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + boolbase@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" @@ -984,6 +998,10 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + browser-resolve@^1.11.2: version "1.11.2" resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" @@ -996,6 +1014,51 @@ browserify-aes@0.4.0: dependencies: inherits "^2.0.1" +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a" + dependencies: + buffer-xor "^1.0.2" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + inherits "^2.0.1" + +browserify-cipher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + browserify-zlib@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" @@ -1019,7 +1082,11 @@ buffer-shims@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" -buffer@^4.9.0: +buffer-xor@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.3.0, buffer@^4.9.0: version "4.9.1" resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" dependencies: @@ -1127,7 +1194,7 @@ chalk@1.1.3, chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chokidar@^1.0.0: +chokidar@^1.0.0, chokidar@^1.4.3: version "1.6.1" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" dependencies: @@ -1150,6 +1217,12 @@ ci-info@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.0.0.tgz#dc5285f2b4e251821683681c381c3388f46ec534" +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07" + dependencies: + inherits "^2.0.1" + circular-json@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" @@ -1424,6 +1497,33 @@ cosmiconfig@^2.1.0, cosmiconfig@^2.1.1: parse-json "^2.2.0" require-from-string "^1.1.0" +create-ecdh@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.6" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + create-react-class@^15.5.1: version "15.5.2" resolved "https://registry.yarnpkg.com/create-react-class/-/create-react-class-15.5.2.tgz#6a8758348df660b88326a0e764d569f274aad681" @@ -1468,6 +1568,21 @@ crypto-browserify@3.3.0: ripemd160 "0.2.0" sha.js "2.2.6" +crypto-browserify@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + css-color-names@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -1718,6 +1833,13 @@ depd@1.1.0, depd@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + destroy@~1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" @@ -1738,6 +1860,14 @@ diff@^3.0.0: version "3.2.0" resolved "https://registry.yarnpkg.com/diff/-/diff-3.2.0.tgz#c9ce393a4b7cbd0b058a725c93df299027868ff9" +diffie-hellman@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + doctrine@1.3.x, doctrine@^1.2.2: version "1.3.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.3.0.tgz#13e75682b55518424276f7c173783456ef913d26" @@ -1819,6 +1949,18 @@ elegant-spinner@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/elegant-spinner/-/elegant-spinner-1.0.1.tgz#db043521c95d7e303fd8f345bedc3349cfb0729e" +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + elm-format@^0.6.1-alpha: version "0.6.1-alpha" resolved "https://registry.yarnpkg.com/elm-format/-/elm-format-0.6.1-alpha.tgz#daeffe95238cb8ce0d7fc6afb5047bcdd14ad7d7" @@ -1858,6 +2000,15 @@ encoding@^0.1.11: dependencies: iconv-lite "~0.4.13" +enhanced-resolve@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + object-assign "^4.0.1" + tapable "^0.2.5" + enhanced-resolve@~0.9.0: version "0.9.1" resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" @@ -2130,6 +2281,12 @@ eventsource@0.1.6, eventsource@^0.1.3: dependencies: original ">=0.0.5" +evp_bytestokey@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53" + dependencies: + create-hash "^1.1.1" + exec-sh@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.2.0.tgz#14f75de3f20d286ef933099b2ce50a90359cef10" @@ -2519,10 +2676,6 @@ getpass@^0.1.1: dependencies: assert-plus "^1.0.0" -gintersect@0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/gintersect/-/gintersect-0.1.0.tgz#9a8cb6a80b7d6e955ac33515495b1212627b1816" - glob-base@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" @@ -2650,6 +2803,18 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + dependencies: + inherits "^2.0.1" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573" + dependencies: + inherits "^2.0.1" + hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" @@ -2673,6 +2838,14 @@ history@^4.5.1, history@^4.6.0: value-equal "^0.2.0" warning "^3.0.0" +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" @@ -2880,6 +3053,10 @@ interpret@^0.6.4: version "0.6.6" resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" +interpret@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" + invariant@^2.0.0, invariant@^2.1.0, invariant@^2.2.0, invariant@^2.2.1, invariant@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" @@ -3402,7 +3579,7 @@ jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" -json-loader@0.5.4: +json-loader@0.5.4, json-loader@^0.5.4: version "0.5.4" resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de" @@ -3424,7 +3601,7 @@ json3@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.2.tgz#3c0434743df93e2f5c42aee7b19bcb483575f4e1" -json5@^0.5.0: +json5@^0.5.0, json5@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" @@ -3562,6 +3739,10 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" +loader-runner@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + loader-utils@0.2.x, loader-utils@^0.2.11, loader-utils@^0.2.15, loader-utils@^0.2.16, loader-utils@^0.2.3, loader-utils@^0.2.7, loader-utils@~0.2.2, loader-utils@~0.2.5: version "0.2.17" resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" @@ -3757,16 +3938,16 @@ memory-fs@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" -memory-fs@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20" +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" dependencies: errno "^0.1.3" readable-stream "^2.0.1" -memory-fs@~0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" +memory-fs@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.3.0.tgz#7bcc6b629e3a43e871d7e29aca6ae8a7f15cbb20" dependencies: errno "^0.1.3" readable-stream "^2.0.1" @@ -3801,6 +3982,13 @@ micromatch@^2.1.5, micromatch@^2.3.11: parse-glob "^3.0.4" regex-cache "^0.4.2" +miller-rabin@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + "mime-db@>= 1.27.0 < 2", mime-db@~1.27.0: version "1.27.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" @@ -3819,6 +4007,14 @@ mime@1.3.4, mime@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" +minimalistic-assert@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + "minimatch@2 || 3", minimatch@3.0.3, minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" @@ -3879,75 +4075,6 @@ negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" -ngraph.centrality@0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/ngraph.centrality/-/ngraph.centrality-0.1.3.tgz#6ca07b4179aff007d8498edef256688b37d8769d" - -ngraph.events@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/ngraph.events/-/ngraph.events-0.0.3.tgz#38f55316f3d207ad631ff94f6622ca8f2c0e87d0" - -ngraph.expose@0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/ngraph.expose/-/ngraph.expose-0.0.0.tgz#746c34903a3848c45d033b14bc64619ea85fe5aa" - -ngraph.forcelayout@0.0.21: - version "0.0.21" - resolved "https://registry.yarnpkg.com/ngraph.forcelayout/-/ngraph.forcelayout-0.0.21.tgz#7df63e14e1b742d833a97d35ccd6a14f022c2643" - dependencies: - ngraph.physics.simulator "0.0.11" - -ngraph.fromjson@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/ngraph.fromjson/-/ngraph.fromjson-0.1.7.tgz#5571270ac8fe103eb16844146e8948ad42219c73" - dependencies: - ngraph.graph "0.0.11" - -ngraph.generators@0.0.15: - version "0.0.15" - resolved "https://registry.yarnpkg.com/ngraph.generators/-/ngraph.generators-0.0.15.tgz#1a09c7e92d883d78bc816c06c2f6640b45f4cff2" - dependencies: - ngraph.graph "0.0.11" - ngraph.random "0.0.1" - -ngraph.graph@0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/ngraph.graph/-/ngraph.graph-0.0.11.tgz#9f10a7267ef5977439ac507bafcba7f4ed728401" - dependencies: - ngraph.events "0.0.3" - -ngraph.merge@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/ngraph.merge/-/ngraph.merge-0.0.1.tgz#e4e80ce37581a3c96b17d545e3a43c85434b9025" - -ngraph.physics.primitives@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/ngraph.physics.primitives/-/ngraph.physics.primitives-0.0.7.tgz#5dc9e179ba1f92e6dec774b01cd68914120b795b" - -ngraph.physics.simulator@0.0.11: - version "0.0.11" - resolved "https://registry.yarnpkg.com/ngraph.physics.simulator/-/ngraph.physics.simulator-0.0.11.tgz#4de130cf1de30163f8852ed5f5a27b2c9b985a34" - dependencies: - ngraph.expose "0.0.0" - ngraph.merge "0.0.1" - ngraph.physics.primitives "0.0.7" - ngraph.quadtreebh "0.0.3" - ngraph.random "0.0.1" - -ngraph.quadtreebh@0.0.3: - version "0.0.3" - resolved "https://registry.yarnpkg.com/ngraph.quadtreebh/-/ngraph.quadtreebh-0.0.3.tgz#9aee2a0931b19780d34ad83616e96a2536751295" - dependencies: - ngraph.random "0.0.1" - -ngraph.random@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/ngraph.random/-/ngraph.random-0.0.1.tgz#c008e2ebbfdffaf17ed10e4bbc913e567166bcf8" - -ngraph.tojson@0.1.3: - version "0.1.3" - resolved "https://registry.yarnpkg.com/ngraph.tojson/-/ngraph.tojson-0.1.3.tgz#72152af3306c001797bb7cc92930e921ba7beb3a" - no-case@^2.2.0: version "2.3.1" resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.1.tgz#7aeba1c73a52184265554b7dc03baf720df80081" @@ -4014,6 +4141,34 @@ node-libs-browser@^0.7.0: util "^0.10.3" vm-browserify "0.0.4" +node-libs-browser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.1.4" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "0.0.1" + os-browserify "^0.2.0" + path-browserify "0.0.0" + process "^0.11.0" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.0.5" + stream-browserify "^2.0.1" + stream-http "^2.3.1" + string_decoder "^0.10.25" + timers-browserify "^2.0.2" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + node-notifier@^4.6.1: version "4.6.1" resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-4.6.1.tgz#056d14244f3dcc1ceadfe68af9cff0c5473a33f3" @@ -4256,6 +4411,16 @@ param-case@2.1.x: dependencies: no-case "^2.2.0" +parse-asn1@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -4327,6 +4492,16 @@ pbkdf2-compat@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz#b6e0c8fa99494d94e0511575802a59a5c142f288" +pbkdf2@^3.0.3: + version "3.0.12" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + performance-now@^0.2.0, performance-now@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" @@ -4720,6 +4895,16 @@ pseudomap@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" +public-encrypt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + "pullstream@>= 0.4.1 < 1": version "0.4.1" resolved "https://registry.yarnpkg.com/pullstream/-/pullstream-0.4.1.tgz#d6fb3bf5aed697e831150eb1002c25a3f8ae1314" @@ -4781,6 +4966,10 @@ randomatic@^1.1.3: is-number "^2.0.2" kind-of "^3.0.2" +randombytes@^2.0.0, randombytes@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec" + range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" @@ -4830,7 +5019,7 @@ react-dev-utils@^0.5.0: sockjs-client "1.0.1" strip-ansi "3.0.1" -react-dom@^15.4.2: +react-dom@^15.4.1, react-dom@^15.4.2: version "15.5.3" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.5.3.tgz#2ee127ce942df55da53111ae303316e68072b5c5" dependencies: @@ -4912,6 +5101,15 @@ react-router@^4.0.0: path-to-regexp "^1.5.3" warning "^3.0.0" +react-sigma@^1.2.17: + version "1.2.17" + resolved "https://registry.yarnpkg.com/react-sigma/-/react-sigma-1.2.17.tgz#dd7422bc8bd2dea16108692e9d82768d4b7610a2" + dependencies: + react "^15.4.1" + react-dom "^15.4.1" + webpack "^2.2.1" + whatwg-fetch "^2.0.1" + react-smooth@0.1.20: version "0.1.20" resolved "https://registry.yarnpkg.com/react-smooth/-/react-smooth-0.1.20.tgz#0527eb60d0ee529e98720127aea5d3fbd2e59fb7" @@ -4930,7 +5128,7 @@ react-virtualized@^9.0.4: loose-envify "^1.3.0" prop-types "^15.5.4" -react@^15.4.2: +react@^15.4.1, react@^15.4.2: version "15.5.3" resolved "https://registry.yarnpkg.com/react/-/react-15.5.3.tgz#84055382c025dec4e3b902bb61a8697cc79c1258" dependencies: @@ -5282,6 +5480,13 @@ ripemd160@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" + run-async@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -5384,6 +5589,12 @@ sha.js@2.2.6: version "2.2.6" resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.2.6.tgz#17ddeddc5f722fb66501658895461977867315ba" +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.8" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f" + dependencies: + inherits "^2.0.1" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -5406,12 +5617,6 @@ signal-exit@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -simplesvg@0.0.10: - version "0.0.10" - resolved "https://registry.yarnpkg.com/simplesvg/-/simplesvg-0.0.10.tgz#37d2ec18de2c154dd9b69f79e8ad20bf1e1e5fdd" - dependencies: - add-event-listener "0.0.1" - slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" @@ -5471,6 +5676,10 @@ source-list-map@^0.1.4, source-list-map@~0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" +source-list-map@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1" + source-map-support@^0.4.2: version "0.4.14" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.14.tgz#9d4463772598b86271b4f523f6c1f4e02a7d6aef" @@ -5679,6 +5888,10 @@ tapable@^0.1.8, tapable@~0.1.8: version "0.1.10" resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" +tapable@^0.2.5, tapable@~0.2.5: + version "0.2.6" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d" + tar-pack@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" @@ -5820,7 +6033,7 @@ ua-parser-js@^0.7.9: version "0.7.12" resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.12.tgz#04c81a99bdd5dc52263ea29d24c6bf8d4818a4bb" -uglify-js@^2.6, uglify-js@~2.8.22: +uglify-js@^2.6, uglify-js@^2.8.5, uglify-js@~2.8.22: version "2.8.22" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.22.tgz#d54934778a8da14903fa29a326fb24c0ab51a1a0" dependencies: @@ -5974,22 +6187,6 @@ verror@1.3.6: dependencies: extsprintf "1.0.2" -vivagraphjs@^0.8.2: - version "0.8.2" - resolved "https://registry.yarnpkg.com/vivagraphjs/-/vivagraphjs-0.8.2.tgz#a9692ad9134086becc56045e626b84c5af8aee85" - dependencies: - gintersect "0.1.0" - ngraph.centrality "0.1.3" - ngraph.events "0.0.3" - ngraph.forcelayout "0.0.21" - ngraph.fromjson "0.1.7" - ngraph.generators "0.0.15" - ngraph.graph "0.0.11" - ngraph.merge "0.0.1" - ngraph.random "0.0.1" - ngraph.tojson "0.1.3" - simplesvg "0.0.10" - vizceral-react@4.4.0: version "4.4.0" resolved "https://registry.yarnpkg.com/vizceral-react/-/vizceral-react-4.4.0.tgz#6bec1219d31bf547bbdfb963d0443992b042ea22" @@ -6038,6 +6235,14 @@ watchpack@^0.2.1: chokidar "^1.0.0" graceful-fs "^4.1.2" +watchpack@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87" + dependencies: + async "^2.1.2" + chokidar "^1.4.3" + graceful-fs "^4.1.2" + webidl-conversions@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" @@ -6094,6 +6299,13 @@ webpack-sources@^0.1.0: source-list-map "~0.1.7" source-map "~0.5.3" +webpack-sources@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb" + dependencies: + source-list-map "^1.1.1" + source-map "~0.5.3" + webpack@1.14.0: version "1.14.0" resolved "https://registry.yarnpkg.com/webpack/-/webpack-1.14.0.tgz#54f1ffb92051a328a5b2057d6ae33c289462c823" @@ -6114,6 +6326,32 @@ webpack@1.14.0: watchpack "^0.2.1" webpack-core "~0.6.9" +webpack@^2.2.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.5.1.tgz#61742f0cf8af555b87460a9cd8bba2f1e3ee2fce" + dependencies: + acorn "^5.0.0" + acorn-dynamic-import "^2.0.0" + ajv "^4.7.0" + ajv-keywords "^1.1.1" + async "^2.1.2" + enhanced-resolve "^3.0.0" + interpret "^1.0.0" + json-loader "^0.5.4" + json5 "^0.5.1" + loader-runner "^2.3.0" + loader-utils "^0.2.16" + memory-fs "~0.4.1" + mkdirp "~0.5.0" + node-libs-browser "^2.0.0" + source-map "^0.5.3" + supports-color "^3.1.0" + tapable "~0.2.5" + uglify-js "^2.8.5" + watchpack "^1.3.1" + webpack-sources "^0.2.3" + yargs "^6.0.0" + websocket-driver@>=0.3.6, websocket-driver@>=0.5.1: version "0.6.5" resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.6.5.tgz#5cb2556ceb85f4373c6d8238aa691c8454e13a36" @@ -6130,7 +6368,7 @@ whatwg-encoding@^1.0.1: dependencies: iconv-lite "0.4.13" -whatwg-fetch@2.0.2, whatwg-fetch@>=0.10.0: +whatwg-fetch@2.0.2, whatwg-fetch@>=0.10.0, whatwg-fetch@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.2.tgz#fe294d1d89e36c5be8b3195057f2e4bc74fc980e" @@ -6227,7 +6465,7 @@ yargs-parser@^4.2.0: dependencies: camelcase "^3.0.0" -yargs@^6.3.0, yargs@^6.5.0: +yargs@^6.0.0, yargs@^6.3.0, yargs@^6.5.0: version "6.6.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" dependencies: From f2e6d00a67647f9f82aae29e955439e81474ea87 Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Tue, 23 May 2017 20:58:58 +0200 Subject: [PATCH 02/10] Handle graph differencing --- .../epl-sup-tree/components/DiffManager.js | 31 +++++++++--- .../epl-sup-tree/components/SupTree.js | 49 ++++++++++--------- ui/src/plugins/epl-sup-tree/reducer.js | 15 +++--- 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/ui/src/plugins/epl-sup-tree/components/DiffManager.js b/ui/src/plugins/epl-sup-tree/components/DiffManager.js index 051f3bf..01a9fbe 100644 --- a/ui/src/plugins/epl-sup-tree/components/DiffManager.js +++ b/ui/src/plugins/epl-sup-tree/components/DiffManager.js @@ -1,5 +1,6 @@ // @flow import React, { Component } from 'react'; +import differenceBy from 'lodash/differenceBy'; export function embedProps(elements: mixed, extraProps: any) { return React.Children.map(elements, element => @@ -10,25 +11,39 @@ export function embedProps(elements: mixed, extraProps: any) { class DiffManager extends Component { constructor(props: any) { super(props); + this.state = { key: Math.random() }; const { nodes, edges } = props.graph; nodes.forEach(node => props.sigma.graph.addNode(node)); edges.forEach(edge => props.sigma.graph.addEdge(edge)); + props.sigma.startForceAtlas2(); } componentWillReceiveProps(props: any) { const { nodes, edges } = props.graph; - console.log(props); - nodes.forEach(node => props.sigma.graph.addNode(node)); - edges.forEach(edge => props.sigma.graph.addEdge(edge)); - // TODO: create list of old and new (nodes, edges) - // TODO: remove old, add new (nodes, edges) - console.log(props.sigma); - // props.sigma.startForceAtlas2(); + const sigma = props.sigma.graph; + + // REMOVE OLD + differenceBy(this.props.graph.edges, edges, 'id').forEach(e => + sigma.dropEdge(e.id) + ); + differenceBy(this.props.graph.nodes, nodes, 'id').forEach(n => + sigma.dropNode(n.id) + ); + + // ADD NEW + const newNodes = differenceBy(nodes, this.props.graph.nodes, 'id'); + newNodes.forEach(n => sigma.addNode(n)); + const newEdges = differenceBy(edges, this.props.graph.edges, 'id'); + newEdges.forEach(e => sigma.addEdge(e)); + + // NOTE: We have to radnomize key to force ForceLink update + if (newEdges.length + newNodes.length > 0) + this.setState({ key: Math.random() }); } render() { return ( -
+
{embedProps(this.props.children, { sigma: this.props.sigma })}
); diff --git a/ui/src/plugins/epl-sup-tree/components/SupTree.js b/ui/src/plugins/epl-sup-tree/components/SupTree.js index 220b883..d94142f 100644 --- a/ui/src/plugins/epl-sup-tree/components/SupTree.js +++ b/ui/src/plugins/epl-sup-tree/components/SupTree.js @@ -1,24 +1,14 @@ // @flow import React, { Component } from 'react'; import { connect } from 'react-redux'; -// import difference from 'lodash/difference'; // import { Motion, spring } from 'react-motion'; // import { ListGroup, ListGroupItem } from 'react-bootstrap'; // import { send } from '../../../sockets'; -import { - Sigma, - EdgeShapes, - // SigmaEnableWebGL, - NodeShapes, - RelativeSize, - ForceAtlas2, - RandomizeNodePositions -} from 'react-sigma'; - -import DiffManager from './DiffManager'; +import { Sigma } from 'react-sigma'; import ForceLink from 'react-sigma/lib/ForceLink'; +import DiffManager from './DiffManager'; import './SupTree.css'; class SupTree extends Component { @@ -31,30 +21,43 @@ class SupTree extends Component { render() { return (
+ + {this.props.tree.nodes.length === 0 && +
+
+
+
+
+
+
+ Creating graph +
+
} + - - - - {/* */} - - + randomize="locally" + alignNodeSiblings + timeout={this.props.tree.nodes.length * 50} + />
diff --git a/ui/src/plugins/epl-sup-tree/reducer.js b/ui/src/plugins/epl-sup-tree/reducer.js index 0d8d96b..002e457 100644 --- a/ui/src/plugins/epl-sup-tree/reducer.js +++ b/ui/src/plugins/epl-sup-tree/reducer.js @@ -8,7 +8,7 @@ const COLORS = { }; const SIZE = { - supervisor: 8, + supervisor: 5, worker: 0.1 }; @@ -30,17 +30,18 @@ function mapNode(node) { nodes: (node.children || []) .map(n => ({ label: node.id, - x: Math.random() * 100, - y: Math.random() * 100, + x: 0, // Math.random(), + y: 0, // Math.random(), size: SIZE[node.type], color: COLORS[n.type], - id: n.id + id: n.id, + shape: 'square' })) .concat(nodes), edges: (node.children || []) .map(c => ({ id: `f${node.id}t${c.id}`, - color: 'rgba(157,165,180, 100)', + color: '#9da5b4', // '#63666A', // '#21252b', size: 0.1, source: node.id, target: c.id @@ -61,8 +62,8 @@ function treeReducer(state: any = INITIAL_STATE, action: any) { ...nodes, { label: node.id, - x: Math.random() * 100, - y: Math.random() * 100, + x: 0, // Math.random(), + y: 0, // Math.random(), size: SIZE[node.type], color: COLORS[node.type], id: node.id From cd548ce038241f6c9c9df5cd626eb32294d67993 Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Fri, 26 May 2017 17:46:29 +0200 Subject: [PATCH 03/10] Create PluginWrapper component --- package.json | 1 + ui/src/core/components/Loader.css | 59 +++++++++++++++ ui/src/core/components/Loader.js | 23 ++++++ ui/src/core/components/PluginWrapper.js | 37 ++++++++++ ui/src/core/components/styled.js | 11 +++ .../epl-sup-tree/components/DiffManager.js | 15 ++-- .../epl-sup-tree/components/SupTree.css | 64 ----------------- .../epl-sup-tree/components/SupTree.js | 28 ++------ ui/src/plugins/epl-sup-tree/reducer.js | 4 +- yarn.lock | 71 ++++++++++++++++++- 10 files changed, 218 insertions(+), 95 deletions(-) create mode 100644 ui/src/core/components/Loader.css create mode 100644 ui/src/core/components/Loader.js create mode 100644 ui/src/core/components/PluginWrapper.js create mode 100644 ui/src/core/components/styled.js diff --git a/package.json b/package.json index 78ad832..aec6966 100644 --- a/package.json +++ b/package.json @@ -71,6 +71,7 @@ "react-virtualized": "^9.0.4", "recharts": "^0.21.2", "redux": "^3.6.0", + "styled-components": "^2.0.0", "vizceral-react": "4.4.0" }, "scripts": { diff --git a/ui/src/core/components/Loader.css b/ui/src/core/components/Loader.css new file mode 100644 index 0000000..08da8c8 --- /dev/null +++ b/ui/src/core/components/Loader.css @@ -0,0 +1,59 @@ +.loader { + z-index: 1; + background-color: #282c34; + position: absolute; + left: 60px; + right: 0; + top: 0; + bottom: 30px; +} + +.loader > div { + position: absolute; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); +} + +/* loader animation */ + +.spinner { + margin: 0px auto 10px; + width: 70px; + text-align: center; +} + +.spinner > div { + width: 18px; + height: 18px; + background-color: #9da5b4; + border-radius: 100%; + display: inline-block; + -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; + animation: sk-bouncedelay 1.4s infinite ease-in-out both; +} + +.spinner .bounce1 { + -webkit-animation-delay: -0.32s; + animation-delay: -0.32s; +} + +.spinner .bounce2 { + -webkit-animation-delay: -0.16s; + animation-delay: -0.16s; +} + +@-webkit-keyframes sk-bouncedelay { + 0%, 80%, 100% { -webkit-transform: scale(0) } + 40% { -webkit-transform: scale(1.0) } +} + +@keyframes sk-bouncedelay { + 0%, 80%, 100% { + -webkit-transform: scale(0); + transform: scale(0); + } 40% { + -webkit-transform: scale(1.0); + transform: scale(1.0); + } +} diff --git a/ui/src/core/components/Loader.js b/ui/src/core/components/Loader.js new file mode 100644 index 0000000..f1421d7 --- /dev/null +++ b/ui/src/core/components/Loader.js @@ -0,0 +1,23 @@ +// @flow +import React from 'react'; + +import './Loader.css'; + +type Props = { + text: string +}; + +const Loader = ({ text }: Props) => ( +
+
+
+
+
+
+
+ {text} +
+
+); + +export default Loader; diff --git a/ui/src/core/components/PluginWrapper.js b/ui/src/core/components/PluginWrapper.js new file mode 100644 index 0000000..5c37a93 --- /dev/null +++ b/ui/src/core/components/PluginWrapper.js @@ -0,0 +1,37 @@ +// @flow +import React, { Component } from 'react'; + +import Loader from './Loader'; +import { Container, Content } from './styled'; + +// const SidePanel = () => null; + +type Props = { + className?: string, + loading?: boolean, + loaderText?: string, + children?: React$Element<*> +}; + +class PluginWrapper extends Component { + props: Props; + + static defaultProps = { + className: '', + loaderText: 'Loading...', + loading: false + }; + + render() { + if (this.props.loading) return ; + return ( + + + {this.props.children} + + + ); + } +} + +export default PluginWrapper; diff --git a/ui/src/core/components/styled.js b/ui/src/core/components/styled.js new file mode 100644 index 0000000..5855217 --- /dev/null +++ b/ui/src/core/components/styled.js @@ -0,0 +1,11 @@ +import styled from 'styled-components'; + +export const Container = styled.div` + width: 100%; + height: 100%; +`; + +export const Content = styled.div` + width: 100%; + height: 100%; +`; diff --git a/ui/src/plugins/epl-sup-tree/components/DiffManager.js b/ui/src/plugins/epl-sup-tree/components/DiffManager.js index 01a9fbe..d5ce100 100644 --- a/ui/src/plugins/epl-sup-tree/components/DiffManager.js +++ b/ui/src/plugins/epl-sup-tree/components/DiffManager.js @@ -2,7 +2,7 @@ import React, { Component } from 'react'; import differenceBy from 'lodash/differenceBy'; -export function embedProps(elements: mixed, extraProps: any) { +function embedProps(elements: mixed, extraProps: any) { return React.Children.map(elements, element => React.cloneElement(element, extraProps) ); @@ -12,10 +12,13 @@ class DiffManager extends Component { constructor(props: any) { super(props); this.state = { key: Math.random() }; - const { nodes, edges } = props.graph; - nodes.forEach(node => props.sigma.graph.addNode(node)); - edges.forEach(edge => props.sigma.graph.addEdge(edge)); - props.sigma.startForceAtlas2(); + } + + componentDidMount() { + const { nodes, edges } = this.props.graph; + nodes.forEach(node => this.props.sigma.graph.addNode(node)); + edges.forEach(edge => this.props.sigma.graph.addEdge(edge)); + this.setState({ key: Math.random() }); } componentWillReceiveProps(props: any) { @@ -36,12 +39,12 @@ class DiffManager extends Component { const newEdges = differenceBy(edges, this.props.graph.edges, 'id'); newEdges.forEach(e => sigma.addEdge(e)); - // NOTE: We have to radnomize key to force ForceLink update if (newEdges.length + newNodes.length > 0) this.setState({ key: Math.random() }); } render() { + // NOTE: We have to radnomize key to force ForceLink update return (
{embedProps(this.props.children, { sigma: this.props.sigma })} diff --git a/ui/src/plugins/epl-sup-tree/components/SupTree.css b/ui/src/plugins/epl-sup-tree/components/SupTree.css index bd22b71..1b5757f 100644 --- a/ui/src/plugins/epl-sup-tree/components/SupTree.css +++ b/ui/src/plugins/epl-sup-tree/components/SupTree.css @@ -1,8 +1,3 @@ -.SupTree { - width: 100%; - height: 100%; -} - .SupTree .graph { height: 100%; width: 70%; @@ -78,68 +73,9 @@ width: 100%; } -.SupTree .loader { - z-index: 1; - background-color: #282c34; - position: absolute; - left: 60px; - right: 0; - top: 0; - bottom: 30px; -} - -.SupTree .loader > div { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); -} .SupTree .node-info { width: 100%; overflow-y: scroll; height: calc(50%); } - -/* loader animation */ - -.spinner { - margin: 0px auto 10px; - width: 70px; - text-align: center; -} - -.spinner > div { - width: 18px; - height: 18px; - background-color: #9da5b4; - border-radius: 100%; - display: inline-block; - -webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both; - animation: sk-bouncedelay 1.4s infinite ease-in-out both; -} - -.spinner .bounce1 { - -webkit-animation-delay: -0.32s; - animation-delay: -0.32s; -} - -.spinner .bounce2 { - -webkit-animation-delay: -0.16s; - animation-delay: -0.16s; -} - -@-webkit-keyframes sk-bouncedelay { - 0%, 80%, 100% { -webkit-transform: scale(0) } - 40% { -webkit-transform: scale(1.0) } -} - -@keyframes sk-bouncedelay { - 0%, 80%, 100% { - -webkit-transform: scale(0); - transform: scale(0); - } 40% { - -webkit-transform: scale(1.0); - transform: scale(1.0); - } -} diff --git a/ui/src/plugins/epl-sup-tree/components/SupTree.js b/ui/src/plugins/epl-sup-tree/components/SupTree.js index d94142f..5e8978b 100644 --- a/ui/src/plugins/epl-sup-tree/components/SupTree.js +++ b/ui/src/plugins/epl-sup-tree/components/SupTree.js @@ -1,6 +1,7 @@ // @flow import React, { Component } from 'react'; import { connect } from 'react-redux'; +import PluginWrapper from '../../../core/components/PluginWrapper'; // import { Motion, spring } from 'react-motion'; // import { ListGroup, ListGroupItem } from 'react-bootstrap'; @@ -12,28 +13,13 @@ import DiffManager from './DiffManager'; import './SupTree.css'; class SupTree extends Component { - div: any; - - componentDidMount() {} - - componentWillReceiveProps(props) {} - render() { return ( -
- - {this.props.tree.nodes.length === 0 && -
-
-
-
-
-
-
- Creating graph -
-
} - + -
+ ); } } diff --git a/ui/src/plugins/epl-sup-tree/reducer.js b/ui/src/plugins/epl-sup-tree/reducer.js index 002e457..d6a56e2 100644 --- a/ui/src/plugins/epl-sup-tree/reducer.js +++ b/ui/src/plugins/epl-sup-tree/reducer.js @@ -52,7 +52,7 @@ function mapNode(node) { function treeReducer(state: any = INITIAL_STATE, action: any) { if (action.type === type.UPDATE_APPS_INFO) { - console.log(action.data); + // console.log(action.data); const d = Object.keys(action.data).reduce( ({ nodes, edges }, key) => { const node = action.data[key]; @@ -77,7 +77,7 @@ function treeReducer(state: any = INITIAL_STATE, action: any) { }, { nodes: [], edges: [] } ); - console.log(d); + // console.log(d); return d; } return state; diff --git a/yarn.lock b/yarn.lock index 0a3d851..75d8cb8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -983,6 +983,10 @@ bootstrap@3: version "3.3.7" resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.3.7.tgz#5a389394549f23330875a3b150656574f8a9eb71" +bowser@^1.0.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/bowser/-/bowser-1.7.0.tgz#169de4018711f994242bff9a8009e77a1f35e003" + brace-expansion@^1.0.0: version "1.1.7" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" @@ -1094,6 +1098,13 @@ buffer@^4.3.0, buffer@^4.9.0: ieee754 "^1.1.4" isarray "^1.0.0" +buffer@^5.0.3: + version "5.0.6" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.0.6.tgz#2ea669f7eec0b6eda05b08f8b5ff661b28573588" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + buffers@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb" @@ -1583,6 +1594,10 @@ crypto-browserify@^3.11.0: public-encrypt "^4.0.0" randombytes "^2.0.0" +css-color-keywords@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/css-color-keywords/-/css-color-keywords-1.0.0.tgz#fea2616dc676b2962686b3af8dbdbe180b244e05" + css-color-names@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" @@ -1629,6 +1644,14 @@ css-selector-tokenizer@^0.7.0: fastparse "^1.1.1" regexpu-core "^1.0.0" +css-to-react-native@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/css-to-react-native/-/css-to-react-native-2.0.4.tgz#cf4cc407558b3474d4ba8be1a2cd3b6ce713101b" + dependencies: + css-color-keywords "^1.0.0" + fbjs "^0.8.5" + postcss-value-parser "^3.3.0" + css-what@2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" @@ -2408,7 +2431,7 @@ fb-watchman@^1.8.0, fb-watchman@^1.9.0: dependencies: bser "1.0.2" -fbjs@^0.8.4, fbjs@^0.8.9: +fbjs@^0.8.4, fbjs@^0.8.5, fbjs@^0.8.9: version "0.8.12" resolved "https://registry.yarnpkg.com/fbjs/-/fbjs-0.8.12.tgz#10b5d92f76d45575fd63a217d4ea02bea2f8ed04" dependencies: @@ -2850,7 +2873,7 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" -hoist-non-react-statics@^1.0.3: +hoist-non-react-statics@^1.0.3, hoist-non-react-statics@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-1.2.0.tgz#aa448cf0986d55cc40773b17174b7dd066cb7cfb" @@ -2970,6 +2993,10 @@ husky@^0.13.3: is-ci "^1.0.9" normalize-path "^1.0.0" +hyphenate-style-name@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/hyphenate-style-name/-/hyphenate-style-name-1.0.2.tgz#31160a36930adaf1fc04c6074f7eb41465d4ec4b" + iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" @@ -3031,6 +3058,13 @@ ini@~1.3.0: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" +inline-style-prefixer@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/inline-style-prefixer/-/inline-style-prefixer-2.0.5.tgz#c153c7e88fd84fef5c602e95a8168b2770671fe7" + dependencies: + bowser "^1.0.0" + hyphenate-style-name "^1.0.1" + inquirer@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" @@ -3139,6 +3173,10 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-function@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -3186,6 +3224,12 @@ is-plain-obj@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" +is-plain-object@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.1.tgz#4d7ca539bc9db9b737b8acb612f2318ef92f294f" + dependencies: + isobject "^1.0.0" + is-posix-bracket@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" @@ -3238,6 +3282,10 @@ isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" +isobject@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-1.0.2.tgz#f0f9b8ce92dd540fa0740882e3835a2e022ec78a" + isobject@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" @@ -5843,6 +5891,25 @@ style-loader@0.13.1: dependencies: loader-utils "^0.2.7" +styled-components@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/styled-components/-/styled-components-2.0.0.tgz#0906652b77647e7400ca7e5a6d8d45eba6fa77ec" + dependencies: + buffer "^5.0.3" + css-to-react-native "^2.0.3" + fbjs "^0.8.9" + hoist-non-react-statics "^1.2.0" + inline-style-prefixer "^2.0.5" + is-function "^1.0.1" + is-plain-object "^2.0.1" + prop-types "^15.5.4" + stylis "^2.0.0" + supports-color "^3.2.3" + +stylis@^2.0.0: + version "2.0.12" + resolved "https://registry.yarnpkg.com/stylis/-/stylis-2.0.12.tgz#547253055d170f2a7ac2f6d09365d70635f2bec6" + supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" From 74321e521778e7b25a08d35a16ca4ca67abdea39 Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Fri, 26 May 2017 18:46:35 +0200 Subject: [PATCH 04/10] Add PluginWrapper pane splitting --- package.json | 1 + ui/src/App.css | 2 +- ui/src/core/components/PluginWrapper.js | 34 +++++++++++++++++++++---- ui/src/core/components/SidePanel.js | 19 ++++++++++++++ ui/src/core/components/styled.js | 23 +++++++++++++++++ yarn.lock | 30 +++++++++++++++++++++- 6 files changed, 102 insertions(+), 7 deletions(-) create mode 100644 ui/src/core/components/SidePanel.js diff --git a/package.json b/package.json index aec6966..4635667 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "react-measure": "^1.4.5", "react-motion": "^0.4.7", "react-redux": "^5.0.2", + "react-reflex": "^2.0.0", "react-router-dom": "^4.0.0", "react-router-redux": "next", "react-sigma": "^1.2.17", diff --git a/ui/src/App.css b/ui/src/App.css index b457fd1..348a616 100644 --- a/ui/src/App.css +++ b/ui/src/App.css @@ -11,9 +11,9 @@ margin-left: 60px; } - ::-webkit-scrollbar { width: 5px; + height: 5px; } ::-webkit-scrollbar-track { diff --git a/ui/src/core/components/PluginWrapper.js b/ui/src/core/components/PluginWrapper.js index 5c37a93..204698d 100644 --- a/ui/src/core/components/PluginWrapper.js +++ b/ui/src/core/components/PluginWrapper.js @@ -1,11 +1,13 @@ // @flow import React, { Component } from 'react'; +import { ReflexContainer, ReflexSplitter, ReflexElement } from 'react-reflex'; + +import 'react-reflex/styles.css'; import Loader from './Loader'; +import SidePanel from './SidePanel'; import { Container, Content } from './styled'; -// const SidePanel = () => null; - type Props = { className?: string, loading?: boolean, @@ -16,6 +18,8 @@ type Props = { class PluginWrapper extends Component { props: Props; + state = { panel: false }; + static defaultProps = { className: '', loaderText: 'Loading...', @@ -24,11 +28,31 @@ class PluginWrapper extends Component { render() { if (this.props.loading) return ; + + const { panel } = this.state; + return ( - - {this.props.children} - + + + + {this.props.children} + + + + {panel && + } + + {panel && + + + } + + ); } diff --git a/ui/src/core/components/SidePanel.js b/ui/src/core/components/SidePanel.js new file mode 100644 index 0000000..915fe25 --- /dev/null +++ b/ui/src/core/components/SidePanel.js @@ -0,0 +1,19 @@ +// @flow +import React, { Component } from 'react'; + +import { SidePanelContainer } from './styled'; + +class SidePanel extends Component { + render() { + return ( + +
+ bello world +
+ {this.props.children} +
+ ); + } +} + +export default SidePanel; diff --git a/ui/src/core/components/styled.js b/ui/src/core/components/styled.js index 5855217..8284efc 100644 --- a/ui/src/core/components/styled.js +++ b/ui/src/core/components/styled.js @@ -3,9 +3,32 @@ import styled from 'styled-components'; export const Container = styled.div` width: 100%; height: 100%; + + + ${/* .reflex-splitter { + background: #000; + opacity: .2; + z-index: 1; + box-sizing: border-box; + background-clip: padding-box; + width: 11px; + transition: all 2s ease; + margin: 0 -5px; + border-left: 5px solid black; + border-right: 5px solid black; + cursor: col-resize; + } + .reflex-splitter:hover { + border-left: 5px solid rgba(0, 0, 0, 0.5); + border-right: 5px solid rgba(0, 0, 0, 0.5); + } */ ''} `; export const Content = styled.div` width: 100%; height: 100%; `; + +export const SidePanelContainer = styled.div` + +`; diff --git a/yarn.lock b/yarn.lock index 75d8cb8..7ad5404 100644 --- a/yarn.lock +++ b/yarn.lock @@ -855,7 +855,7 @@ babel-runtime@6.22.0: core-js "^2.4.0" regenerator-runtime "^0.10.0" -babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0: +babel-runtime@^6.11.6, babel-runtime@^6.18.0, babel-runtime@^6.20.0, babel-runtime@^6.22.0, babel-runtime@^6.23.0: version "6.23.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" dependencies: @@ -3897,6 +3897,10 @@ lodash.pickby@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.pickby/-/lodash.pickby-4.6.0.tgz#7dea21d8c18d7703a27c704c15d3b84a67e33aff" +lodash.throttle@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" + lodash.uniq@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" @@ -4928,6 +4932,13 @@ prop-types@^15.0.0, prop-types@^15.5.2, prop-types@^15.5.4, prop-types@~15.5.0: dependencies: fbjs "^0.8.9" +prop-types@^15.5.8: + version "15.5.10" + resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.5.10.tgz#2797dfc3126182e3a95e3dfbb2e893ddd7456154" + dependencies: + fbjs "^0.8.9" + loose-envify "^1.3.1" + proxy-addr@~1.1.3: version "1.1.4" resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" @@ -5087,6 +5098,14 @@ react-measure@^1.4.5: get-node-dimensions "^1.2.0" resize-observer-polyfill "^1.4.1" +react-measure@^1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-1.4.7.tgz#a1d2ca0dcfef04978b7ac263a765dcb6a0936fdb" + dependencies: + get-node-dimensions "^1.2.0" + prop-types "^15.5.4" + resize-observer-polyfill "^1.4.1" + react-motion@^0.4.7: version "0.4.7" resolved "https://registry.yarnpkg.com/react-motion/-/react-motion-0.4.7.tgz#f77331ec7920bdb0d0cfc37eb6ffa10571bf42c7" @@ -5121,6 +5140,15 @@ react-redux@^5.0.2: loose-envify "^1.1.0" prop-types "^15.0.0" +react-reflex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/react-reflex/-/react-reflex-2.0.0.tgz#2ae624ff8253f14fdbfb7a146c9f486d0928c9a5" + dependencies: + babel-runtime "^6.23.0" + lodash.throttle "^4.1.1" + prop-types "^15.5.8" + react-measure "^1.4.7" + react-resize-detector@0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/react-resize-detector/-/react-resize-detector-0.3.3.tgz#ca07443072324843586666d9443a6356da7c0501" From 30dacf4318aaa297c4e3c0fee069f5da1d5a4029 Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Fri, 26 May 2017 21:23:02 +0200 Subject: [PATCH 05/10] Visualize selected node --- ui/src/core/components/PluginWrapper.js | 57 ++++--- ui/src/core/components/SidePanel.js | 3 - .../epl-sup-tree/components/DiffManager.js | 66 ++++++++- .../epl-sup-tree/components/SidePanel.js | 140 ++++++++++++++++++ .../epl-sup-tree/components/SupTree.js | 28 ++-- .../plugins/epl-sup-tree/components/styled.js | 1 + ui/src/plugins/epl-sup-tree/constants.js | 6 + ui/src/plugins/epl-sup-tree/reducer.js | 18 +-- 8 files changed, 272 insertions(+), 47 deletions(-) create mode 100644 ui/src/plugins/epl-sup-tree/components/SidePanel.js create mode 100644 ui/src/plugins/epl-sup-tree/components/styled.js create mode 100644 ui/src/plugins/epl-sup-tree/constants.js diff --git a/ui/src/core/components/PluginWrapper.js b/ui/src/core/components/PluginWrapper.js index 204698d..716fccf 100644 --- a/ui/src/core/components/PluginWrapper.js +++ b/ui/src/core/components/PluginWrapper.js @@ -9,6 +9,7 @@ import SidePanel from './SidePanel'; import { Container, Content } from './styled'; type Props = { + sidePanel?: React$Element<*>, className?: string, loading?: boolean, loaderText?: string, @@ -16,9 +17,14 @@ type Props = { }; class PluginWrapper extends Component { - props: Props; + state: { panel: boolean }; - state = { panel: false }; + constructor(props: Props) { + super(props); + this.state = { + panel: props.sidePanel ? true : false + }; + } static defaultProps = { className: '', @@ -27,30 +33,43 @@ class PluginWrapper extends Component { }; render() { - if (this.props.loading) return ; + if (this.props.loading) { + return ; + } + + const content = ( + + {this.props.children} + + ); - const { panel } = this.state; + // NOTE: when no side panel we don;t need Relfex + if (!this.state.panel) { + return ( + + {content} + + ); + } return ( - - - {this.props.children} - + + {content} - {panel && - } - - {panel && - - - } + + + + + {this.props.sidePanel} + + diff --git a/ui/src/core/components/SidePanel.js b/ui/src/core/components/SidePanel.js index 915fe25..3ba6e7f 100644 --- a/ui/src/core/components/SidePanel.js +++ b/ui/src/core/components/SidePanel.js @@ -7,9 +7,6 @@ class SidePanel extends Component { render() { return ( -
- bello world -
{this.props.children}
); diff --git a/ui/src/plugins/epl-sup-tree/components/DiffManager.js b/ui/src/plugins/epl-sup-tree/components/DiffManager.js index d5ce100..0b9c172 100644 --- a/ui/src/plugins/epl-sup-tree/components/DiffManager.js +++ b/ui/src/plugins/epl-sup-tree/components/DiffManager.js @@ -2,6 +2,8 @@ import React, { Component } from 'react'; import differenceBy from 'lodash/differenceBy'; +import { SELECTED } from '../constants'; + function embedProps(elements: mixed, extraProps: any) { return React.Children.map(elements, element => React.cloneElement(element, extraProps) @@ -16,12 +18,13 @@ class DiffManager extends Component { componentDidMount() { const { nodes, edges } = this.props.graph; - nodes.forEach(node => this.props.sigma.graph.addNode(node)); - edges.forEach(edge => this.props.sigma.graph.addEdge(edge)); + const sigma = this.props.sigma.graph; + nodes.forEach(n => sigma.addNode(n)); + edges.forEach(e => sigma.addEdge(e)); this.setState({ key: Math.random() }); } - componentWillReceiveProps(props: any) { + componentWillReceiveProps({ selected, ...props }: any) { const { nodes, edges } = props.graph; const sigma = props.sigma.graph; @@ -35,16 +38,69 @@ class DiffManager extends Component { // ADD NEW const newNodes = differenceBy(nodes, this.props.graph.nodes, 'id'); - newNodes.forEach(n => sigma.addNode(n)); + newNodes.forEach(e => sigma.addNode(e)); const newEdges = differenceBy(edges, this.props.graph.edges, 'id'); newEdges.forEach(e => sigma.addEdge(e)); + if (this.props.selected !== props.selected) { + // clear old selected node + this.updateNode( + this.props.selected, + '', + this.props.graph.nodes, + this.props.graph.edges, + this.props.sigma.graph + ); + // show new selected node + this.updateNode(selected, SELECTED, nodes, edges, sigma); + } + if (newEdges.length + newNodes.length > 0) this.setState({ key: Math.random() }); + + props.sigma.refresh(); } + updateNode = ( + id: string, + // NOTE: empty sring will clear color + color: string, + nodes: Array<*>, + edges: Array<*>, + sigma: any + ) => { + const fn = n => n.id === id; + const selectedNode = nodes.find(fn); + const graphSelectedNode = sigma.nodes().find(fn); + + if (selectedNode && graphSelectedNode) { + const position = { + x: graphSelectedNode.x, + y: graphSelectedNode.y + }; + + const connectedEdges = edges.filter( + e => e.source === id || e.target === id + ); + + connectedEdges.forEach(e => sigma.dropEdge(e.id)); + + sigma.dropNode(id).addNode( + color + ? { + ...selectedNode, + ...position, + color + } + : { ...selectedNode, ...position } + ); + + connectedEdges.forEach(e => sigma.addEdge(e)); + } + }; + render() { - // NOTE: We have to radnomize key to force ForceLink update + // NOTE: We have to randomize key to force ForceLink update return (
{embedProps(this.props.children, { sigma: this.props.sigma })} diff --git a/ui/src/plugins/epl-sup-tree/components/SidePanel.js b/ui/src/plugins/epl-sup-tree/components/SidePanel.js new file mode 100644 index 0000000..5343b83 --- /dev/null +++ b/ui/src/plugins/epl-sup-tree/components/SidePanel.js @@ -0,0 +1,140 @@ +// @flow +import React, { Component } from 'react'; +import { connect } from 'react-redux'; +import { Motion, spring } from 'react-motion'; +import { ListGroup, ListGroupItem } from 'react-bootstrap'; + +import { COLORS } from '../constants'; + +type Props = {}; + +class SidePanel extends Component { + state: { + collapse: boolean, + height: Array + }; + + constructor(props: Props) { + super(props); + this.state = { + collapse: false, + height: [50, 50] + // motion stuff + // currently selected node + }; + } + + toggleCollapse = () => { + this.setState(({ collapse }) => ({ + collapse: !collapse, + height: collapse ? [50, 0] : [0, 50] + })); + }; + + selectAll = () => { + // TODO: show all apps + }; + + clearAll = () => { + // TODO: hide all apps + }; + + handleAppClick = () => { + // TODO: toggle application + }; + + selectNode = () => { + // TODO: change color of selected application + }; + + render() { + return ( +
+ +
+

+ {this.state.selected.id} +

+ +
+ + ( +
+ +
+ + + + + + + {Object.keys(this.props.tree).map( + (app, key) => + (Object.keys(this.props.tree[app]).length + ? + + this.handleAppClick( + app, + this.props.tree[app].id + )} + /> + + this.selectNode(this.props.tree[app].id, true)} + > + {app} + + + : + + {app} + + ) + )} + +
+ +
+
+                  
+                    {this.props.nodeInfo &&
+                      JSON.stringify(this.props.nodeInfo, null, 2)}
+                  
+                
+
+
+ )} + /> +
+ ); + } +} + +export default connect( + state => ({ + nodeInfo: state.eplSupTree.nodeInfo + }), + {} +)(SidePanel); diff --git a/ui/src/plugins/epl-sup-tree/components/SupTree.js b/ui/src/plugins/epl-sup-tree/components/SupTree.js index 5e8978b..8513807 100644 --- a/ui/src/plugins/epl-sup-tree/components/SupTree.js +++ b/ui/src/plugins/epl-sup-tree/components/SupTree.js @@ -2,17 +2,27 @@ import React, { Component } from 'react'; import { connect } from 'react-redux'; import PluginWrapper from '../../../core/components/PluginWrapper'; -// import { Motion, spring } from 'react-motion'; -// import { ListGroup, ListGroupItem } from 'react-bootstrap'; -// import { send } from '../../../sockets'; -import { Sigma } from 'react-sigma'; +import { send } from '../../../sockets'; +import { + Sigma, + // eslint-disable-next-line no-unused-vars + SigmaEnableWebGL +} from 'react-sigma'; import ForceLink from 'react-sigma/lib/ForceLink'; +// import SidePanel from './SidePanel'; import DiffManager from './DiffManager'; import './SupTree.css'; class SupTree extends Component { + state = { selected: '' }; + + handleNodeClick = ({ data }) => { + this.setState({ selected: data.node.id }); + send('epl_st_EPL', data.node.id); + }; + render() { return ( - + @@ -53,8 +64,7 @@ class SupTree extends Component { export default connect( state => ({ - tree: state.eplSupTree.tree, - nodeInfo: state.eplSupTree.nodeInfo + tree: state.eplSupTree.tree }), {} )(SupTree); diff --git a/ui/src/plugins/epl-sup-tree/components/styled.js b/ui/src/plugins/epl-sup-tree/components/styled.js new file mode 100644 index 0000000..4f210a9 --- /dev/null +++ b/ui/src/plugins/epl-sup-tree/components/styled.js @@ -0,0 +1 @@ +import styled from 'styled-components'; diff --git a/ui/src/plugins/epl-sup-tree/constants.js b/ui/src/plugins/epl-sup-tree/constants.js new file mode 100644 index 0000000..6f40860 --- /dev/null +++ b/ui/src/plugins/epl-sup-tree/constants.js @@ -0,0 +1,6 @@ +export const COLORS = { + supervisor: '#227A50', + worker: '#1F79B7' +}; + +export const SELECTED = '#df307d'; diff --git a/ui/src/plugins/epl-sup-tree/reducer.js b/ui/src/plugins/epl-sup-tree/reducer.js index d6a56e2..1fb7bf9 100644 --- a/ui/src/plugins/epl-sup-tree/reducer.js +++ b/ui/src/plugins/epl-sup-tree/reducer.js @@ -1,15 +1,11 @@ // @flow import { combineReducers } from 'redux'; import * as type from './actionTypes'; - -const COLORS = { - supervisor: '#227A50', - worker: '#1F79B7' -}; +import { COLORS } from './constants'; const SIZE = { supervisor: 5, - worker: 0.1 + worker: 3 }; const INITIAL_STATE = { nodes: [], edges: [] }; @@ -29,11 +25,12 @@ function mapNode(node) { return { nodes: (node.children || []) .map(n => ({ - label: node.id, + label: n.id, x: 0, // Math.random(), y: 0, // Math.random(), - size: SIZE[node.type], + size: SIZE[n.type], color: COLORS[n.type], + type: n.type, id: n.id, shape: 'square' })) @@ -52,7 +49,6 @@ function mapNode(node) { function treeReducer(state: any = INITIAL_STATE, action: any) { if (action.type === type.UPDATE_APPS_INFO) { - // console.log(action.data); const d = Object.keys(action.data).reduce( ({ nodes, edges }, key) => { const node = action.data[key]; @@ -61,10 +57,11 @@ function treeReducer(state: any = INITIAL_STATE, action: any) { ? [ ...nodes, { - label: node.id, + label: key, // node.id, x: 0, // Math.random(), y: 0, // Math.random(), size: SIZE[node.type], + type: node.type, color: COLORS[node.type], id: node.id } @@ -77,7 +74,6 @@ function treeReducer(state: any = INITIAL_STATE, action: any) { }, { nodes: [], edges: [] } ); - // console.log(d); return d; } return state; From 2d2a0f61f39050f7dd2c716bd6e34da490f2b50e Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Fri, 26 May 2017 22:36:41 +0200 Subject: [PATCH 06/10] Add application toggle --- ui/src/App.css | 4 + ui/src/core/components/PluginWrapper.js | 4 +- ui/src/core/components/styled.js | 19 ----- ui/src/plugins/epl-sup-tree/actionTypes.js | 3 +- ui/src/plugins/epl-sup-tree/actions.js | 16 +++- .../epl-sup-tree/components/SidePanel.js | 81 +++++++++++-------- .../epl-sup-tree/components/SupTree.css | 22 ++--- .../epl-sup-tree/components/SupTree.js | 37 ++++++--- ui/src/plugins/epl-sup-tree/reducer.js | 43 +++++++++- 9 files changed, 139 insertions(+), 90 deletions(-) diff --git a/ui/src/App.css b/ui/src/App.css index 348a616..a582335 100644 --- a/ui/src/App.css +++ b/ui/src/App.css @@ -11,6 +11,10 @@ margin-left: 60px; } +button, a { + outline: none; +} + ::-webkit-scrollbar { width: 5px; height: 5px; diff --git a/ui/src/core/components/PluginWrapper.js b/ui/src/core/components/PluginWrapper.js index 716fccf..7194d88 100644 --- a/ui/src/core/components/PluginWrapper.js +++ b/ui/src/core/components/PluginWrapper.js @@ -38,7 +38,7 @@ class PluginWrapper extends Component { } const content = ( - + {this.props.children} ); @@ -53,7 +53,7 @@ class PluginWrapper extends Component { } return ( - + {content} diff --git a/ui/src/core/components/styled.js b/ui/src/core/components/styled.js index 8284efc..eec249b 100644 --- a/ui/src/core/components/styled.js +++ b/ui/src/core/components/styled.js @@ -3,25 +3,6 @@ import styled from 'styled-components'; export const Container = styled.div` width: 100%; height: 100%; - - - ${/* .reflex-splitter { - background: #000; - opacity: .2; - z-index: 1; - box-sizing: border-box; - background-clip: padding-box; - width: 11px; - transition: all 2s ease; - margin: 0 -5px; - border-left: 5px solid black; - border-right: 5px solid black; - cursor: col-resize; - } - .reflex-splitter:hover { - border-left: 5px solid rgba(0, 0, 0, 0.5); - border-right: 5px solid rgba(0, 0, 0, 0.5); - } */ ''} `; export const Content = styled.div` diff --git a/ui/src/plugins/epl-sup-tree/actionTypes.js b/ui/src/plugins/epl-sup-tree/actionTypes.js index f991ea1..b64e053 100644 --- a/ui/src/plugins/epl-sup-tree/actionTypes.js +++ b/ui/src/plugins/epl-sup-tree/actionTypes.js @@ -1,5 +1,6 @@ // @flow export const UPDATE_APPS_INFO = 'epl-sup-tree/UPDATE_APPS_INFO'; - export const UPDATE_NODE_INFO = 'epl-sup-tree/UPDATE_NODE_INFO'; +export const SELECT_APPS = 'epl-sup-tree/SELECT_APP'; +export const CLEAR_APPS = 'epl-sup-tree/CLEAR_APPS'; diff --git a/ui/src/plugins/epl-sup-tree/actions.js b/ui/src/plugins/epl-sup-tree/actions.js index adaba76..c7ec0d6 100644 --- a/ui/src/plugins/epl-sup-tree/actions.js +++ b/ui/src/plugins/epl-sup-tree/actions.js @@ -1,12 +1,22 @@ // @flow -import * as t from './actionTypes'; +import * as type from './actionTypes'; export const updateAppsInfo = (data: any) => ({ - type: t.UPDATE_APPS_INFO, + type: type.UPDATE_APPS_INFO, data }); export const updateNodeInfo = (info: any) => ({ - type: t.UPDATE_NODE_INFO, + type: type.UPDATE_NODE_INFO, info }); + +export const selectApps = (apps: Array) => ({ + type: type.SELECT_APPS, + apps +}); + +export const clearApps = (apps: Array) => ({ + type: type.CLEAR_APPS, + apps +}); diff --git a/ui/src/plugins/epl-sup-tree/components/SidePanel.js b/ui/src/plugins/epl-sup-tree/components/SidePanel.js index 5343b83..a958c5c 100644 --- a/ui/src/plugins/epl-sup-tree/components/SidePanel.js +++ b/ui/src/plugins/epl-sup-tree/components/SidePanel.js @@ -4,12 +4,18 @@ import { connect } from 'react-redux'; import { Motion, spring } from 'react-motion'; import { ListGroup, ListGroupItem } from 'react-bootstrap'; +import { send } from '../../../sockets'; import { COLORS } from '../constants'; -type Props = {}; +type Props = { + selected: string, + apps: Array<*>, + nodeInfo?: string +}; class SidePanel extends Component { state: { + apps: Array<*>, collapse: boolean, height: Array }; @@ -19,8 +25,6 @@ class SidePanel extends Component { this.state = { collapse: false, height: [50, 50] - // motion stuff - // currently selected node }; } @@ -32,19 +36,24 @@ class SidePanel extends Component { }; selectAll = () => { - // TODO: show all apps + this.props.selectApps(this.props.apps); }; clearAll = () => { - // TODO: hide all apps + this.props.clearApps(this.props.apps); }; - handleAppClick = () => { - // TODO: toggle application + selectNode = (id: string) => { + send('epl_st_EPL', id); }; - selectNode = () => { - // TODO: change color of selected application + handleAppClick = (id: string) => { + const app = this.props.apps.find(app => app.id === id); + if (app.selected) { + this.props.clearApps([app]); + } else { + this.props.selectApps([app]); + } }; render() { @@ -55,10 +64,10 @@ class SidePanel extends Component {

- {this.state.selected.id} + {this.props.selected}

@@ -67,8 +76,7 @@ class SidePanel extends Component { defaultStyle={{ height: this.state.height[0] }} style={{ height: spring(this.state.height[1]) }} children={({ height }) => ( -
- +
- {Object.keys(this.props.tree).map( - (app, key) => - (Object.keys(this.props.tree[app]).length - ? + {this.props.apps.map( + ({ name, selected, id }) => + (id + ? - this.handleAppClick( - app, - this.props.tree[app].id - )} + checked={selected} + onChange={() => this.handleAppClick(id)} /> - this.selectNode(this.props.tree[app].id, true)} + onClick={() => this.selectNode(id)} > - {app} + {name} - : + : - {app} + {name} ) )} @@ -132,9 +141,13 @@ class SidePanel extends Component { } } -export default connect( - state => ({ - nodeInfo: state.eplSupTree.nodeInfo - }), - {} -)(SidePanel); +import * as actions from '../actions'; + +export default connect(state => { + const nodeInfo = state.eplSupTree.nodeInfo; + return { + nodeInfo, + selected: nodeInfo ? nodeInfo.id : 'Applications', + apps: state.eplSupTree.apps + }; +}, actions)(SidePanel); diff --git a/ui/src/plugins/epl-sup-tree/components/SupTree.css b/ui/src/plugins/epl-sup-tree/components/SupTree.css index 1b5757f..be92d6d 100644 --- a/ui/src/plugins/epl-sup-tree/components/SupTree.css +++ b/ui/src/plugins/epl-sup-tree/components/SupTree.css @@ -1,21 +1,13 @@ -.SupTree .graph { - height: 100%; - width: 70%; - float: left; - overflow: hidden; -} - .SupTree .side-panel { - width: 30%; - border-left: 1px solid #21252b; + background-color: #21252b; + width: 100%; height: 100%; - float: right; box-sizing: border-box; overflow-x: hidden; } .SupTree .head { - border-bottom: 1px solid #21252b; + border-bottom: 1px solid #181a1f; height: 40px; padding: 10px 0; } @@ -41,7 +33,7 @@ border: none; border-radius: 0px; color: inherit; - background-color: #282c34; + background-color: #181a1f; } .SupTree ul { @@ -50,7 +42,7 @@ } .SupTree .application-link { - border: 1px solid #21252b; + border: 1px solid #181a1f; background-color: #333842; padding: 5px; font-size: 17px; @@ -58,8 +50,7 @@ .SupTree .application-link button { width: 50%; - background-color: #282c34; - border: 1px solid #21252b; + background-color: #181a1f;; } .SupTree a { @@ -73,7 +64,6 @@ width: 100%; } - .SupTree .node-info { width: 100%; overflow-y: scroll; diff --git a/ui/src/plugins/epl-sup-tree/components/SupTree.js b/ui/src/plugins/epl-sup-tree/components/SupTree.js index 8513807..ae2dfc1 100644 --- a/ui/src/plugins/epl-sup-tree/components/SupTree.js +++ b/ui/src/plugins/epl-sup-tree/components/SupTree.js @@ -7,28 +7,40 @@ import { send } from '../../../sockets'; import { Sigma, // eslint-disable-next-line no-unused-vars - SigmaEnableWebGL + SigmaEnableWebGL, + Filter } from 'react-sigma'; import ForceLink from 'react-sigma/lib/ForceLink'; -// import SidePanel from './SidePanel'; +import SidePanel from './SidePanel'; import DiffManager from './DiffManager'; import './SupTree.css'; class SupTree extends Component { - state = { selected: '' }; + state = { filterKey: Math.random() }; handleNodeClick = ({ data }) => { - this.setState({ selected: data.node.id }); send('epl_st_EPL', data.node.id); }; + nodeFilter = ({ app }) => { + const application = this.props.apps.find(a => a.name === app); + return application.selected; + }; + + componentWillReceiveProps(nextProps: any) { + if (this.props.apps !== nextProps.apps) { + this.setState({ filterKey: Math.random() }); + } + } + render() { return ( } > - + + @@ -62,9 +75,11 @@ class SupTree extends Component { } } -export default connect( - state => ({ - tree: state.eplSupTree.tree - }), - {} -)(SupTree); +export default connect(state => { + const info = state.eplSupTree.nodeInfo; + return { + apps: state.eplSupTree.apps, + tree: state.eplSupTree.tree, + selected: info ? info.id : '' + }; +}, {})(SupTree); diff --git a/ui/src/plugins/epl-sup-tree/reducer.js b/ui/src/plugins/epl-sup-tree/reducer.js index 1fb7bf9..e191004 100644 --- a/ui/src/plugins/epl-sup-tree/reducer.js +++ b/ui/src/plugins/epl-sup-tree/reducer.js @@ -1,5 +1,6 @@ // @flow import { combineReducers } from 'redux'; + import * as type from './actionTypes'; import { COLORS } from './constants'; @@ -10,12 +11,12 @@ const SIZE = { const INITIAL_STATE = { nodes: [], edges: [] }; -function mapNode(node) { +function mapNode(node: any, app: string) { const { nodes, edges } = (node.children || []).reduce(( { nodes, edges }, node ) => { - const c = mapNode(node); + const c = mapNode(node, app); return { nodes: nodes.concat(c.nodes), edges: edges.concat(c.edges) @@ -25,6 +26,7 @@ function mapNode(node) { return { nodes: (node.children || []) .map(n => ({ + app, label: n.id, x: 0, // Math.random(), y: 0, // Math.random(), @@ -52,12 +54,13 @@ function treeReducer(state: any = INITIAL_STATE, action: any) { const d = Object.keys(action.data).reduce( ({ nodes, edges }, key) => { const node = action.data[key]; - const c = mapNode(node); + const c = mapNode(node, key); const n = node.type ? [ ...nodes, { - label: key, // node.id, + app: key, + label: key, x: 0, // Math.random(), y: 0, // Math.random(), size: SIZE[node.type], @@ -86,7 +89,39 @@ function nodeInfoReducer(state: any = null, action: any) { return state; } +function appsReducer(state: Array<*> = [], action: any) { + if (action.type === type.UPDATE_APPS_INFO) { + return Object.keys(action.data).reduce((acc, key) => { + const app = action.data[key]; + const old = state.find(a => a.name === key); + return acc.concat({ + id: app.id, + name: key, + selected: old ? old.selected : true + }); + }, []); + } + + if (action.type === type.SELECT_APPS) { + const apps = action.apps; + return state.map(app => ({ + ...app, + selected: apps.includes(app) ? true : app.selected + })); + } + if (action.type === type.CLEAR_APPS) { + const apps = action.apps; + return state.map(app => ({ + ...app, + selected: apps.includes(app) ? false : app.selected + })); + } + + return state; +} + export default combineReducers({ + apps: appsReducer, tree: treeReducer, nodeInfo: nodeInfoReducer }); From 1e21ae98e5b672d508d9d80276e2bdb2af447685 Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Mon, 29 May 2017 21:52:49 +0200 Subject: [PATCH 07/10] Fix flow annotations --- .flowconfig | 9 +++++---- ui/src/plugins/epl-sup-tree/components/DiffManager.js | 4 ++++ ui/src/plugins/epl-sup-tree/components/SidePanel.js | 1 - 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.flowconfig b/.flowconfig index 6691d66..9f217ec 100644 --- a/.flowconfig +++ b/.flowconfig @@ -1,10 +1,11 @@ [ignore] -/node_modules/fbjs/.* -/node_modules/find-elm-dependencies/.* -/node_modules/elm-webpack-loader/.* +.*/node_modules/fbjs/.* +.*/node_modules/find-elm-dependencies/.* +.*/node_modules/elm-webpack-loader/.* +.*/node_modules/styled-components/.* [include] [libs] -[options] \ No newline at end of file +[options] diff --git a/ui/src/plugins/epl-sup-tree/components/DiffManager.js b/ui/src/plugins/epl-sup-tree/components/DiffManager.js index 0b9c172..9665c98 100644 --- a/ui/src/plugins/epl-sup-tree/components/DiffManager.js +++ b/ui/src/plugins/epl-sup-tree/components/DiffManager.js @@ -11,6 +11,10 @@ function embedProps(elements: mixed, extraProps: any) { } class DiffManager extends Component { + state: { + key: number + }; + constructor(props: any) { super(props); this.state = { key: Math.random() }; diff --git a/ui/src/plugins/epl-sup-tree/components/SidePanel.js b/ui/src/plugins/epl-sup-tree/components/SidePanel.js index a958c5c..e4526ef 100644 --- a/ui/src/plugins/epl-sup-tree/components/SidePanel.js +++ b/ui/src/plugins/epl-sup-tree/components/SidePanel.js @@ -15,7 +15,6 @@ type Props = { class SidePanel extends Component { state: { - apps: Array<*>, collapse: boolean, height: Array }; From 42c8272b5be6e1b1db2f5edfcc83c0f7291c4ca1 Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Mon, 29 May 2017 23:21:42 +0200 Subject: [PATCH 08/10] Center camera on node click --- ui/src/plugins/epl-sup-tree/actionTypes.js | 1 + ui/src/plugins/epl-sup-tree/actions.js | 6 +++ .../epl-sup-tree/components/DiffManager.js | 44 ++++++++++++++----- .../epl-sup-tree/components/SupTree.js | 25 +++++++---- ui/src/plugins/epl-sup-tree/reducer.js | 12 +++++ 5 files changed, 68 insertions(+), 20 deletions(-) diff --git a/ui/src/plugins/epl-sup-tree/actionTypes.js b/ui/src/plugins/epl-sup-tree/actionTypes.js index b64e053..b26d4c1 100644 --- a/ui/src/plugins/epl-sup-tree/actionTypes.js +++ b/ui/src/plugins/epl-sup-tree/actionTypes.js @@ -4,3 +4,4 @@ export const UPDATE_APPS_INFO = 'epl-sup-tree/UPDATE_APPS_INFO'; export const UPDATE_NODE_INFO = 'epl-sup-tree/UPDATE_NODE_INFO'; export const SELECT_APPS = 'epl-sup-tree/SELECT_APP'; export const CLEAR_APPS = 'epl-sup-tree/CLEAR_APPS'; +export const CENTER = 'epl-sup-tree/CENTER'; diff --git a/ui/src/plugins/epl-sup-tree/actions.js b/ui/src/plugins/epl-sup-tree/actions.js index c7ec0d6..b1621ab 100644 --- a/ui/src/plugins/epl-sup-tree/actions.js +++ b/ui/src/plugins/epl-sup-tree/actions.js @@ -20,3 +20,9 @@ export const clearApps = (apps: Array) => ({ type: type.CLEAR_APPS, apps }); + +export const center = (x: number, y: number) => ({ + type: type.CENTER, + x, + y +}); diff --git a/ui/src/plugins/epl-sup-tree/components/DiffManager.js b/ui/src/plugins/epl-sup-tree/components/DiffManager.js index 9665c98..92eb0ac 100644 --- a/ui/src/plugins/epl-sup-tree/components/DiffManager.js +++ b/ui/src/plugins/epl-sup-tree/components/DiffManager.js @@ -1,6 +1,7 @@ // @flow import React, { Component } from 'react'; import differenceBy from 'lodash/differenceBy'; +import get from 'lodash/get'; import { SELECTED } from '../constants'; @@ -12,12 +13,16 @@ function embedProps(elements: mixed, extraProps: any) { class DiffManager extends Component { state: { - key: number + key: number, + center: { x: number, y: number } }; constructor(props: any) { super(props); - this.state = { key: Math.random() }; + this.state = { + key: Math.random(), + center: { x: 0, y: 0 } + }; } componentDidMount() { @@ -30,24 +35,24 @@ class DiffManager extends Component { componentWillReceiveProps({ selected, ...props }: any) { const { nodes, edges } = props.graph; - const sigma = props.sigma.graph; + const sigmaGraph = props.sigma.graph; // REMOVE OLD differenceBy(this.props.graph.edges, edges, 'id').forEach(e => - sigma.dropEdge(e.id) + sigmaGraph.dropEdge(e.id) ); differenceBy(this.props.graph.nodes, nodes, 'id').forEach(n => - sigma.dropNode(n.id) + sigmaGraph.dropNode(n.id) ); // ADD NEW const newNodes = differenceBy(nodes, this.props.graph.nodes, 'id'); - newNodes.forEach(e => sigma.addNode(e)); + newNodes.forEach(e => sigmaGraph.addNode(e)); const newEdges = differenceBy(edges, this.props.graph.edges, 'id'); - newEdges.forEach(e => sigma.addEdge(e)); + newEdges.forEach(e => sigmaGraph.addEdge(e)); - if (this.props.selected !== props.selected) { - // clear old selected node + if (selected && this.props.selected !== selected) { + // CLEAR OLD SELECTED NODE this.updateNode( this.props.selected, '', @@ -55,8 +60,25 @@ class DiffManager extends Component { this.props.graph.edges, this.props.sigma.graph ); - // show new selected node - this.updateNode(selected, SELECTED, nodes, edges, sigma); + + // SHOW NEW SELECTED NODE + this.updateNode(selected, SELECTED, nodes, edges, sigmaGraph); + + // CENTER ON NODE + const node = sigmaGraph.nodes().find(node => node.id === selected); + const { x, y } = props.sigma.camera.graphPosition(node.x, node.y); + // eslint-disable-next-line + sigma.misc.animation.camera( + props.sigma.camera, + { + // NOTE: this is far from being nice but it works + // I hope it won't break in future + x: x / 5, + y: y / 5, + ratio: 1 + }, + { duration: props.sigma.settings('animationsTime') || 300 } + ); } if (newEdges.length + newNodes.length > 0) diff --git a/ui/src/plugins/epl-sup-tree/components/SupTree.js b/ui/src/plugins/epl-sup-tree/components/SupTree.js index ae2dfc1..7516d8b 100644 --- a/ui/src/plugins/epl-sup-tree/components/SupTree.js +++ b/ui/src/plugins/epl-sup-tree/components/SupTree.js @@ -17,7 +17,9 @@ import DiffManager from './DiffManager'; import './SupTree.css'; class SupTree extends Component { - state = { filterKey: Math.random() }; + state = { + filterKey: Math.random() + }; handleNodeClick = ({ data }) => { send('epl_st_EPL', data.node.id); @@ -75,11 +77,16 @@ class SupTree extends Component { } } -export default connect(state => { - const info = state.eplSupTree.nodeInfo; - return { - apps: state.eplSupTree.apps, - tree: state.eplSupTree.tree, - selected: info ? info.id : '' - }; -}, {})(SupTree); +import * as actions from '../actions'; + +export default connect( + state => { + const info = state.eplSupTree.nodeInfo; + return { + apps: state.eplSupTree.apps, + tree: state.eplSupTree.tree, + selected: info ? info.id : '' + }; + }, + { center: actions.center } +)(SupTree); diff --git a/ui/src/plugins/epl-sup-tree/reducer.js b/ui/src/plugins/epl-sup-tree/reducer.js index e191004..313a84e 100644 --- a/ui/src/plugins/epl-sup-tree/reducer.js +++ b/ui/src/plugins/epl-sup-tree/reducer.js @@ -120,7 +120,19 @@ function appsReducer(state: Array<*> = [], action: any) { return state; } +function centerReducer( + state: { x: number, y: number } = { x: 0, y: 0 }, + action: any +) { + if (action.type === type.CENTER) { + const { x, y } = action; + return { x, y }; + } + return state; +} + export default combineReducers({ + center: centerReducer, apps: appsReducer, tree: treeReducer, nodeInfo: nodeInfoReducer From 71a3ef3ec4d28e069e421fdc51f3eedd48f48cd5 Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Mon, 29 May 2017 23:29:12 +0200 Subject: [PATCH 09/10] Add FlowFixMe --- .flowconfig | 1 + ui/src/plugins/epl-sup-tree/components/DiffManager.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.flowconfig b/.flowconfig index 9f217ec..cea5fd4 100644 --- a/.flowconfig +++ b/.flowconfig @@ -9,3 +9,4 @@ [libs] [options] +suppress_comment= \\(.\\|\n\\)*\\$FlowFixMe diff --git a/ui/src/plugins/epl-sup-tree/components/DiffManager.js b/ui/src/plugins/epl-sup-tree/components/DiffManager.js index 92eb0ac..f8208db 100644 --- a/ui/src/plugins/epl-sup-tree/components/DiffManager.js +++ b/ui/src/plugins/epl-sup-tree/components/DiffManager.js @@ -67,7 +67,7 @@ class DiffManager extends Component { // CENTER ON NODE const node = sigmaGraph.nodes().find(node => node.id === selected); const { x, y } = props.sigma.camera.graphPosition(node.x, node.y); - // eslint-disable-next-line + // $FlowFixMe sigma.misc.animation.camera( props.sigma.camera, { From 6ca7b9b6b9d2ae7478a00f3ad0cd7fe047a528dd Mon Sep 17 00:00:00 2001 From: Tomasz Cichocinski Date: Tue, 30 May 2017 12:22:52 +0200 Subject: [PATCH 10/10] Fix compilation --- ui/src/plugins/epl-sup-tree/components/DiffManager.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui/src/plugins/epl-sup-tree/components/DiffManager.js b/ui/src/plugins/epl-sup-tree/components/DiffManager.js index f8208db..2dd93a0 100644 --- a/ui/src/plugins/epl-sup-tree/components/DiffManager.js +++ b/ui/src/plugins/epl-sup-tree/components/DiffManager.js @@ -67,6 +67,7 @@ class DiffManager extends Component { // CENTER ON NODE const node = sigmaGraph.nodes().find(node => node.id === selected); const { x, y } = props.sigma.camera.graphPosition(node.x, node.y); + /* eslint-disable */ // $FlowFixMe sigma.misc.animation.camera( props.sigma.camera, @@ -79,6 +80,7 @@ class DiffManager extends Component { }, { duration: props.sigma.settings('animationsTime') || 300 } ); + /* eslint-enable */ } if (newEdges.length + newNodes.length > 0)