diff --git a/x-pack/plugins/monitoring/common/constants.js b/x-pack/plugins/monitoring/common/constants.js
index e1f1806026b1a..72edcbb3d68a1 100644
--- a/x-pack/plugins/monitoring/common/constants.js
+++ b/x-pack/plugins/monitoring/common/constants.js
@@ -121,27 +121,6 @@ export const LOGSTASH = {
* Constants used by Logstash Pipeline Viewer code
*/
PIPELINE_VIEWER: {
- GRAPH: {
- EDGES: {
- SVG_CLASS: 'lspvEdge',
- LABEL_RADIUS: 8,
- // This is something we may play with later.
- // 1 seems to be the best value however, without it the edges sometimes make weird loops in complex graphs
- ROUTING_MARGIN_PX: 1,
- ARROW_START: 5
- },
- VERTICES: {
- BORDER_RADIUS_PX: 4,
- MARGIN_PX: 35,
- WIDTH_PX: 320,
- HEIGHT_PX: 85,
-
- /**
- * Vertical distance between vertices, as measured from top-border-to-top-border
- */
- VERTICAL_DISTANCE_PX: 20
- }
- },
ICON: {
HEIGHT_PX: 18,
WIDTH_PX: 18
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/__tests__/index.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/__tests__/index.test.js
deleted file mode 100644
index 5e54be90afce0..0000000000000
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/__tests__/index.test.js
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React from 'react';
-import { shallow } from 'enzyme';
-import { PipelineViewer } from '../index';
-import { DetailDrawer } from '../views/detail_drawer';
-import { Graph } from '../models/graph';
-
-
-describe('PipelineViewer component', () => {
- describe('detail drawer', () => {
- let graph;
- let timeseriesTooltipXValueFormatter;
- let pipelineState;
- let wrapper;
- let vertex;
-
- beforeEach(() => {
- graph = new Graph();
- graph.update({
- vertices: [
- {
- id: 'terminal_logger',
- explicit_id: true,
- type: 'plugin',
- plugin_type: 'input',
- config_name: 'stdin',
- stats: {}
- },
- {
- id: '__QUEUE__',
- explicit_id: false,
- type: 'queue',
- stats: {}
- },
- {
- id: '5y890f3e5c135c037eb40ba88d69b040faaeb954bb10510e95294259ffdd88e8',
- explicit_id: false,
- type: 'plugin',
- plugin_type: 'output',
- config_name: 'elasticsearch',
- stats: {}
- }
- ],
- edges: [
- {
- id: '8f1gae28a11c3d99d1adf44f793763db6b9c61379e0ad518371b49aa67ef902f',
- from: 'terminal_logger',
- to: '__QUEUE__',
- type: 'plain'
- },
- {
- id: '8ue2ae28a11c3d99d1ado9f3epq0bvjd6b9c61379e0ad518371b49aa67ef902f',
- from: '__QUEUE__',
- to: '5y890f3e5c135c037eb40ba88d69b040faaeb954bb10510e95294259ffdd88e8',
- type: 'plain'
- }
- ]
- });
-
- timeseriesTooltipXValueFormatter = () => {};
- pipelineState = {
- config: {
- graph
- }
- };
-
- wrapper = shallow((
-
- ));
-
- vertex = graph.getVertices()[0];
- });
-
- it('creates null vertex state by default', () => {
- expect(
- wrapper.instance().state.detailDrawer
- ).toEqual({ vertex: null });
- });
-
- it('is rendered for newly-selected vertex', () => {
- const component = wrapper.instance();
-
- component.onShowVertexDetails(vertex);
-
- expect(wrapper.find(DetailDrawer).length).toEqual(0);
- expect(component.state.detailDrawer.vertex).toEqual(vertex);
-
- wrapper.update();
-
- expect(wrapper.find(DetailDrawer).length).toEqual(1);
- });
-
- it('is hidden if current vertex is selected again', () => {
- const component = wrapper.instance();
-
- component.onShowVertexDetails(vertex);
-
- wrapper.update();
-
- // showing drawer for selected vertex
- expect(wrapper.find(DetailDrawer).length).toEqual(1);
-
- component.onShowVertexDetails(vertex);
-
- wrapper.update();
-
- // drawer toggled off for second consecutive selection of vertex
- expect(wrapper.find(DetailDrawer).length).toEqual(0);
- expect(component.state.detailDrawer.vertex).toEqual(null);
- });
-
- it('remains visible for new vertex', () => {
- const component = wrapper.instance();
-
- component.onShowVertexDetails(vertex);
-
- wrapper.update();
-
- // showing drawer for first vertex
- expect(wrapper.find(DetailDrawer).length).toEqual(1);
-
- // select different vertex
- const secondVertex = graph.getVertices()[1];
- component.onShowVertexDetails(secondVertex);
-
- wrapper.update();
-
- // still visible for second vertex
- expect(wrapper.find(DetailDrawer).length).toEqual(1);
- expect(component.state.detailDrawer.vertex).toEqual(secondVertex);
- });
- });
-});
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/index.js
index c4748876b85f1..df041e4edfaef 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/index.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/index.js
@@ -4,77 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import React from 'react';
-import { ColaGraph } from './views/cola_graph';
-import { DetailDrawer } from './views/detail_drawer';
-import { PropTypes } from 'prop-types';
-
-export class PipelineViewer extends React.Component {
- constructor() {
- super();
- this.state = {
- detailDrawer: {
- vertex: null
- }
- };
- }
-
- onShowVertexDetails = (vertex) => {
- if (vertex === this.state.detailDrawer.vertex) {
- this.onHideVertexDetails();
- }
- else {
- this.setState({
- detailDrawer: {
- vertex
- }
- });
- }
- }
-
- onHideVertexDetails = () => {
- this.setState({
- detailDrawer: {
- vertex: null
- }
- });
- }
-
- renderDetailDrawer = () => {
- if (!this.state.detailDrawer.vertex) {
- return null;
- }
-
- return (
-
- );
- }
-
- render() {
- const graph = this.props.pipelineState.config.graph;
-
- return (
-
-
- { this.renderDetailDrawer() }
-
- );
- }
-}
-
-PipelineViewer.propTypes = {
- pipelineState: PropTypes.shape({
- config: PropTypes.shape({
- graph: PropTypes.object.isRequired
- })
- }),
- timeseriesTooltipXValueFormatter: PropTypes.func.isRequired
-};
+export { ConfigViewer } from './views/config_viewer';
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js
index c029891684cdf..cfe240436b550 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/boolean_edge.js
@@ -7,7 +7,6 @@
import expect from 'expect.js';
import { BooleanEdge } from '../boolean_edge';
import { Edge } from '../edge';
-import { LOGSTASH } from '../../../../../../../common/constants';
describe('BooleanEdge', () => {
let graph;
@@ -32,10 +31,4 @@ describe('BooleanEdge', () => {
const booleanEdge = new BooleanEdge(graph, edgeJson);
expect(booleanEdge).to.be.a(Edge);
});
-
- it('should have the correct SVG CSS class', () => {
- const booleanEdge = new BooleanEdge(graph, edgeJson);
- const edgeSvgClass = LOGSTASH.PIPELINE_VIEWER.GRAPH.EDGES.SVG_CLASS;
- expect(booleanEdge.svgClass).to.be(`${edgeSvgClass} ${edgeSvgClass}Boolean ${edgeSvgClass}Boolean--true`);
- });
});
\ No newline at end of file
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js
index 9b91b0f2f160c..35249d938f2e5 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge.js
@@ -6,7 +6,6 @@
import expect from 'expect.js';
import { Edge } from '../edge';
-import { LOGSTASH } from '../../../../../../../common/constants';
describe('Edge', () => {
let graph;
@@ -26,20 +25,6 @@ describe('Edge', () => {
};
});
- it('should initialize the webcola representation', () => {
- const edge = new Edge(graph, edgeJson);
- expect(edge.cola).to.eql({
- edge: edge,
- source: 'bar',
- target: 17
- });
- });
-
- it('should have a D3-friendly ID', () => {
- const edge = new Edge(graph, edgeJson);
- expect(edge.htmlAttrId).to.be('myif_myes');
- });
-
it('should have the correct from vertex', () => {
const edge = new Edge(graph, edgeJson);
expect(edge.fromId).to.be('myif');
@@ -51,9 +36,4 @@ describe('Edge', () => {
expect(edge.toId).to.be('myes');
expect(edge.to).to.be(graph.verticesById.myes);
});
-
- it('should have the correct SVG CSS class', () => {
- const edge = new Edge(graph, edgeJson);
- expect(edge.svgClass).to.be(LOGSTASH.PIPELINE_VIEWER.GRAPH.EDGES.SVG_CLASS);
- });
});
\ No newline at end of file
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js
index c0704b4cf80cc..27bc53673f036 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/edge_factory.js
@@ -6,7 +6,7 @@
import expect from 'expect.js';
import { edgeFactory } from '../edge_factory';
-import { PlainEdge } from '../plain_edge';
+import { Edge } from '../edge';
import { BooleanEdge } from '../boolean_edge';
describe('edgeFactory', () => {
@@ -27,9 +27,9 @@ describe('edgeFactory', () => {
};
});
- it('returns a PlainEdge when edge type is plain', () => {
+ it('returns an Edge when edge type is plain', () => {
edgeJson.type = 'plain';
- expect(edgeFactory(graph, edgeJson)).to.be.a(PlainEdge);
+ expect(edgeFactory(graph, edgeJson)).to.be.a(Edge);
});
it('returns a BooleanEdge when edge type is boolean', () => {
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/index.js
index 62e7d11e7c8b2..80a8f6f038697 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/index.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/index.js
@@ -144,16 +144,6 @@ describe('Graph', () => {
});
});
- it('identifies cola representations of vertices correctly', () => {
- const colaVertices = graph.colaVertices;
- expect(colaVertices).to.be.an(Array);
- expect(colaVertices.length).to.be(5);
-
- expect(colaVertices[0]).to.have.property('vertex');
- expect(colaVertices[0]).to.have.property('width');
- expect(colaVertices[0]).to.have.property('height');
- });
-
it('identifies the correct edges', () => {
const edges = graph.edges;
expect(edges).to.be.an(Array);
@@ -163,81 +153,6 @@ describe('Graph', () => {
expect(edge).to.be.an(Edge);
});
});
-
- it('identifies cola representations of edges correctly', () => {
- const colaEdges = graph.colaEdges;
- expect(colaEdges).to.be.an(Array);
- expect(colaEdges.length).to.be(4);
-
- colaEdges.forEach(colaEdge => {
- expect(colaEdge).to.have.property('edge');
- expect(colaEdge).to.have.property('source');
- expect(colaEdge).to.have.property('target');
- });
- });
-
- it('identifies its root vertices correctly', () => {
- const roots = graph.roots;
- expect(roots).to.be.an(Array);
- expect(roots.length).to.be(1);
-
- roots.forEach(root => {
- expect(root).to.be.a(Vertex);
- expect(root.json.id).to.be('my-prefix:my-really-long-named-generator');
- });
- });
-
- it('identifies its leaf vertices correctly', () => {
- const leaves = graph.leaves;
- expect(leaves).to.be.an(Array);
- expect(leaves.length).to.be(2);
-
- leaves.forEach(leaf => {
- expect(leaf).to.be.a(Vertex);
- });
- });
-
- it('identifies the highest vertex rank correctly', () => {
- expect(graph.maxRank).to.be(3);
- });
-
- describe('vertex layout ranking', () => {
- const expectedRanks = [
- ['my-prefix:my-really-long-named-generator'],
- ['my-queue'],
- ['my-if'],
- ['my-grok', 'my-sleep']
- ];
-
- it('should store a 2d array of the vertices in the expected ranks', () => {
- const result = graph.verticesByLayoutRank;
- expectedRanks.forEach((expectedVertexIds, rank) => {
- const resultVertices = result[rank];
- expectedVertexIds.forEach(expectedVertexId => {
- const expectedVertex = graph.getVertexById(expectedVertexId);
- expect(resultVertices).to.contain(expectedVertex);
- });
- });
- });
-
- it('should add a .layoutRank property to each Vertex', () => {
- expectedRanks.forEach((expectedVertexIds, rank) => {
- expectedVertexIds.forEach(expectedVertexId => {
- const vertex = graph.getVertexById(expectedVertexId);
- expect(vertex.layoutRank).to.be(rank);
- });
- });
- });
- });
-
- it('should classify the if triangle correctly', () => {
- expect(graph.triangularIfGroups.length).to.be(1);
- expect(graph.triangularIfGroups[0]).to.eql({
- ifVertex: graph.getVertexById('my-if'),
- trueVertex: graph.getVertexById('my-grok'),
- falseVertex: graph.getVertexById('my-sleep'),
- });
- });
});
describe('assigning pipeline stages', () => {
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/plain_edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/plain_edge.js
deleted file mode 100644
index 1138acc41b528..0000000000000
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/plain_edge.js
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import expect from 'expect.js';
-import { PlainEdge } from '../plain_edge';
-import { Edge } from '../edge';
-import { LOGSTASH } from '../../../../../../../common/constants';
-
-describe('PlainEdge', () => {
- let graph;
- let edgeJson;
-
- beforeEach(() => {
- graph = {
- verticesById: {
- mygenerator: {},
- myqueue: {}
- }
- };
- edgeJson = {
- id: 'abcdef',
- from: 'mygenerator',
- to: 'myqueue'
- };
- });
-
- it('should be an instance of Edge', () => {
- const plainEdge = new PlainEdge(graph, edgeJson);
- expect(plainEdge).to.be.a(Edge);
- });
-
- it('should have the correct SVG CSS class', () => {
- const plainEdge = new PlainEdge(graph, edgeJson);
- const edgeSvgClass = LOGSTASH.PIPELINE_VIEWER.GRAPH.EDGES.SVG_CLASS;
- expect(plainEdge.svgClass).to.be(`${edgeSvgClass} ${edgeSvgClass}Plain`);
- });
-});
\ No newline at end of file
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex.js
index b16ba1f28f0f5..bc29533affd6a 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/__tests__/vertex.js
@@ -6,7 +6,6 @@
import expect from 'expect.js';
import { Graph } from '../';
-import { LOGSTASH } from '../../../../../../../common/constants';
describe('Vertex', () => {
let graph;
@@ -44,16 +43,6 @@ describe('Vertex', () => {
graph.update(graphJson);
});
- it('should initialize the webcola representation', () => {
- const margin = LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.MARGIN_PX;
- const vertex = graph.getVertexById('my-queue');
- expect(vertex.cola).to.eql({
- vertex: vertex,
- width: LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.WIDTH_PX + margin,
- height: LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.HEIGHT_PX + margin
- });
- });
-
it('should update the internal json property when update() is called', () => {
const vertex = graph.getVertexById('my-queue');
const updatedJson = {
@@ -63,18 +52,6 @@ describe('Vertex', () => {
expect(vertex.json).to.eql(updatedJson);
});
- it('should not change the webcola index after update', () => {
- const verticesIds = graph.getVertices().map(v => [v.id, v.colaIndex]);
- graph.update(graphJson);
- verticesIds.forEach(idAndIndex => {
- const [id, colaIndex] = idAndIndex;
- const v = graph.getVertexById(id);
- console.log("MATCH", v.id, id);
- expect(v).not.to.be(undefined);
- expect(v.colaIndex).to.be(colaIndex);
- });
- });
-
it('should have the correct name', () => {
const vertex = graph.getVertexById('my-queue');
expect(vertex.name).to.be('some-name');
@@ -85,20 +62,12 @@ describe('Vertex', () => {
expect(vertex1.id).to.be(vertex1.json.id);
});
- it('should have the correct htmlAttrId', () => {
- const vertex1 = graph.getVertexById('my-prefix:my-really-long-named-generator');
- expect(vertex1.htmlAttrId).to.be('my_prefix_my_really_long_named_generator');
-
- const vertex2 = graph.getVertexById('my-queue');
- expect(vertex2.htmlAttrId).to.be('my_queue');
- });
-
it('should have the correct subtitle', () => {
const vertex1 = graph.getVertexById('my-prefix:my-really-long-named-generator');
- expect(vertex1.subtitle).to.eql({ display: 'my-prefi … enerator', complete: 'my-prefix:my-really-long-named-generator' });
+ expect(vertex1.subtitle).to.eql('my-prefix:my-really-long-named-generator');
const vertex2 = graph.getVertexById('my-queue');
- expect(vertex2.subtitle).to.eql({ display: 'my-queue', complete: 'my-queue' });
+ expect(vertex2.subtitle).to.eql('my-queue');
});
it('should have the correct number of incoming edges', () => {
@@ -169,67 +138,6 @@ describe('Vertex', () => {
expect(vertex5.outgoingVertices.length).to.be(0);
});
- it('should correctly identify as a root vertex', () => {
- const vertex1 = graph.getVertexById('my-prefix:my-really-long-named-generator');
- expect(vertex1.isRoot).to.be(true);
-
- const vertex2 = graph.getVertexById('my-queue');
- expect(vertex2.isRoot).to.be(false);
-
- const vertex3 = graph.getVertexById('my-if');
- expect(vertex3.isRoot).to.be(false);
-
- const vertex4 = graph.getVertexById('my-grok');
- expect(vertex4.isRoot).to.be(false);
-
- const vertex5 = graph.getVertexById('my-sleep');
- expect(vertex5.isRoot).to.be(false);
- });
-
- it('should correctly identify as a leaf vertex', () => {
- const vertex1 = graph.getVertexById('my-prefix:my-really-long-named-generator');
- expect(vertex1.isLeaf).to.be(false);
-
- const vertex2 = graph.getVertexById('my-queue');
- expect(vertex2.isLeaf).to.be(false);
-
- const vertex3 = graph.getVertexById('my-if');
- expect(vertex3.isLeaf).to.be(false);
-
- const vertex4 = graph.getVertexById('my-grok');
- expect(vertex4.isLeaf).to.be(true);
-
- const vertex5 = graph.getVertexById('my-sleep');
- expect(vertex5.isLeaf).to.be(true);
- });
-
- it('should have the correct rank', () => {
- const vertex1 = graph.getVertexById('my-prefix:my-really-long-named-generator');
- expect(vertex1.rank).to.be(0);
-
- const vertex2 = graph.getVertexById('my-queue');
- expect(vertex2.rank).to.be(1);
-
- const vertex3 = graph.getVertexById('my-if');
- expect(vertex3.rank).to.be(2);
-
- const vertex4 = graph.getVertexById('my-grok');
- expect(vertex4.rank).to.be(3);
-
- const vertex5 = graph.getVertexById('my-sleep');
- expect(vertex5.rank).to.be(3);
- });
-
- it('should have the correct source location', () => {
- const vertex = graph.getVertexById('my-grok');
- expect(vertex.sourceLocation).to.be('apc.conf@33:4');
- });
-
- it('should have the correct source text', () => {
- const vertex = graph.getVertexById('my-grok');
- expect(vertex.sourceText).to.be('foobar');
- });
-
it('should have the correct metadata', () => {
const vertex = graph.getVertexById('my-grok');
expect(vertex.meta).to.eql({ source_text: 'foobar', source_line: 33, source_column: 4 });
@@ -243,43 +151,7 @@ describe('Vertex', () => {
expect(vertex2.stats).to.eql({});
});
- it('should correctly identify if it has custom stats', () => {
- const vertex1 = graph.getVertexById('my-sleep');
- expect(vertex1.hasCustomStats).to.be(true);
-
- const vertex2 = graph.getVertexById('my-grok');
- expect(vertex2.hasCustomStats).to.be(false);
- });
-
- it('should correctly report custom stats', () => {
- const vertex1 = graph.getVertexById('my-sleep');
- expect(vertex1.customStats).to.eql({ mystat1: 100 });
-
- const vertex2 = graph.getVertexById('my-grok');
- expect(vertex2.customStats).to.eql({});
- });
-
describe('lineage', () => {
- it('should have the correct ancestors', () => {
- const vertex1 = graph.getVertexById('my-prefix:my-really-long-named-generator');
- expect(vertex1.ancestors()).to.eql({ vertices: [], edges: [] });
-
- const vertex2 = graph.getVertexById('my-queue');
- expect(vertex2.ancestors().vertices.length).to.be(1);
- expect(vertex2.ancestors().edges.length).to.be(1);
-
- const vertex3 = graph.getVertexById('my-if');
- expect(vertex3.ancestors().vertices.length).to.be(2);
- expect(vertex3.ancestors().edges.length).to.be(2);
-
- const vertex4 = graph.getVertexById('my-grok');
- expect(vertex4.ancestors().vertices.length).to.be(3);
- expect(vertex4.ancestors().edges.length).to.be(3);
-
- const vertex5 = graph.getVertexById('my-sleep');
- expect(vertex5.ancestors().vertices.length).to.be(3);
- expect(vertex5.ancestors().edges.length).to.be(3);
- });
it('should have the correct descendants', () => {
const vertex1 = graph.getVertexById('my-prefix:my-really-long-named-generator');
@@ -301,28 +173,6 @@ describe('Vertex', () => {
expect(vertex5.descendants()).to.eql({ vertices: [], edges: [] });
});
- it('should have the correct lineage', () => {
- const vertex1 = graph.getVertexById('my-prefix:my-really-long-named-generator');
- expect(vertex1.lineage().vertices.length).to.be(5);
- expect(vertex1.lineage().edges.length).to.be(4);
-
- const vertex2 = graph.getVertexById('my-queue');
- expect(vertex2.lineage().vertices.length).to.be(5);
- expect(vertex2.lineage().edges.length).to.be(4);
-
- const vertex3 = graph.getVertexById('my-if');
- expect(vertex3.lineage().vertices.length).to.be(5);
- expect(vertex3.lineage().edges.length).to.be(4);
-
- const vertex4 = graph.getVertexById('my-grok');
- expect(vertex4.lineage().vertices.length).to.be(4);
- expect(vertex4.lineage().edges.length).to.be(3);
-
- const vertex5 = graph.getVertexById('my-sleep');
- expect(vertex5.lineage().vertices.length).to.be(4);
- expect(vertex5.lineage().edges.length).to.be(3);
- });
-
describe('it should handle complex topologies correctly', () => {
/**
* I1
@@ -372,23 +222,9 @@ describe('Vertex', () => {
graph = new Graph();
graph.update(complexGraphJson);
});
-
- it('should calculate the lineage correctly', () => {
- const vertex1 = graph.getVertexById('F5');
- expect(vertex1.lineage().vertices.length).to.be(9);
- expect(vertex1.lineage().edges.length).to.be(10);
- });
});
});
- it('should have the correct events per current period', () => {
- const vertex1 = graph.getVertexById('my-sleep');
- expect(vertex1.eventsPerCurrentPeriod).to.be(20);
-
- const vertex2 = graph.getVertexById('my-grok');
- expect(vertex2.eventsPerCurrentPeriod).to.be(null);
- });
-
it('should correctly identify if it has an explicit ID', () => {
const vertex1 = graph.getVertexById('my-prefix:my-really-long-named-generator');
expect(vertex1.hasExplicitId).to.be(false);
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/boolean_edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/boolean_edge.js
index c5debbc11f5d2..017d613fca05b 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/boolean_edge.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/boolean_edge.js
@@ -18,8 +18,4 @@ export class BooleanEdge extends Edge {
get isFalse() {
return this.when === false;
}
-
- get svgClass() {
- return `${super.svgClass} ${super.svgClass}Boolean ${super.svgClass}Boolean--${this.when}`;
- }
}
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge.js
index 7205ffce967ac..1f48720617ff7 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge.js
@@ -4,22 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { LOGSTASH } from '../../../../../../common/constants';
-
export class Edge {
constructor(graph, json) {
this.graph = graph;
this.update(json);
-
- this.cola = this._makeCola();
- }
-
- _makeCola() {
- return {
- edge: this,
- source: this.from.cola,
- target: this.to.cola
- };
}
update(json) {
@@ -30,12 +18,6 @@ export class Edge {
return this.json.id;
}
- get htmlAttrId() {
- // Substitute any non-word characters with an underscore so
- // D3 selections don't interpret them as special selector syntax
- return this.json.id.replace(/\W/, '_');
- }
-
get from() {
return this.graph.verticesById[this.fromId];
}
@@ -51,8 +33,4 @@ export class Edge {
get toId() {
return this.json.to;
}
-
- get svgClass() {
- return LOGSTASH.PIPELINE_VIEWER.GRAPH.EDGES.SVG_CLASS;
- }
}
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js
index d4a5fc7e5f12d..7ddf7cd4f235c 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/edge_factory.js
@@ -4,14 +4,14 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { PlainEdge } from './plain_edge';
+import { Edge } from './edge';
import { BooleanEdge } from './boolean_edge';
export function edgeFactory(graph, edgeJson) {
const type = edgeJson.type;
switch (type) {
case 'plain':
- return new PlainEdge(graph, edgeJson);
+ return new Edge(graph, edgeJson);
case 'boolean':
return new BooleanEdge(graph, edgeJson);
default:
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/if_vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/if_vertex.js
index 39d76ae6f882c..e721d43a7e97c 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/if_vertex.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/if_vertex.js
@@ -26,14 +26,7 @@ export class IfVertex extends Vertex {
}
get subtitle() {
- return {
- complete: this.name,
- display: this.truncateStringForDisplay(this.name, this.displaySubtitleMaxLength)
- };
- }
-
- get displaySubtitleMaxLength() {
- return 39;
+ return this.name;
}
get trueEdge() {
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/index.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/index.js
index 6583a405dfc48..8c6a5c0ea5854 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/index.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/index.js
@@ -7,7 +7,6 @@
import { vertexFactory } from './vertex_factory';
import { edgeFactory } from './edge_factory';
import { QueueVertex } from './queue_vertex';
-import { IfVertex } from './if_vertex';
import { PluginVertex } from './plugin_vertex';
export class Graph {
@@ -24,9 +23,6 @@ export class Graph {
}
getVertices() {
- // We need a stable order for webcola
- // constraints don't work by anything other than index :(
-
// Its safe to cache vertices because vertices are never added or removed from the graph. This is because
// such changes also result in changing the hash of the pipeline, which ends up creating a new graph altogether.
if (this.vertexCache === undefined) {
@@ -35,10 +31,6 @@ export class Graph {
return this.vertexCache;
}
- get inputVertices() {
- return this.getVertices().filter(v => v.isInput);
- }
-
get queueVertex() {
return this.getVertices().find(v => v instanceof QueueVertex);
}
@@ -47,26 +39,10 @@ export class Graph {
return this.getVertices().filter(v => v.isProcessor);
}
- get outputVertices() {
- return this.getVertices().filter(v => v.isOutput);
- }
-
- get ifVertices() {
- return this.getVertices().filter(v => v instanceof IfVertex);
- }
-
- get colaVertices() {
- return this.getVertices().map(v => v.cola);
- }
-
get edges() {
return Object.values(this.edgesById);
}
- get colaEdges() {
- return this.edges.map(e => e.cola);
- }
-
update(jsonRepresentation) {
this.json = jsonRepresentation;
@@ -99,199 +75,9 @@ export class Graph {
}
});
- // These maps are what the vertices use for their .rank and .reverseRank getters
- this.vertexRankById = this._bfs().distances;
-
- // A separate rank algorithm used for formatting purposes
- this.verticesByLayoutRank = this.calculateVerticesByLayoutRank();
-
- // For layout purposes we treat triangular ifs, that is to say
- // 'if' vertices of rank N with both T and F children at rank N+1
- // in special ways to get a clean render.
- this.triangularIfGroups = this.calculateTriangularIfGroups();
-
this.annotateVerticesWithStages();
}
- verticesByRank() {
- const byRank = [];
- Object.values(this.verticesById).forEach(vertex => {
- const rank = vertex.rank;
- if (byRank[rank] === undefined) {
- byRank[rank] = [];
- }
- byRank[rank].push(vertex);
- });
- return byRank;
- }
-
- // Can only be run after layout ranks are calculated!
- calculateTriangularIfGroups() {
- return this.getVertices().filter(v => {
- return v.typeString === 'if' &&
- !v.outgoingVertices.find(outV => outV.layoutRank !== (v.layoutRank + 1));
- }).map(ifV => {
- const trueEdge = ifV.outgoingEdges.filter(e => e.when === true)[0];
- const falseEdge = ifV.outgoingEdges.filter(e => e.when === false)[0];
- const result = { ifVertex: ifV };
- if (trueEdge) {
- result.trueVertex = trueEdge.to;
- }
- if (falseEdge) {
- result.falseVertex = falseEdge.to;
- }
- return result;
- });
- }
-
- calculateVerticesByLayoutRank() {
- // We will mutate this throughout this function
- // to produce our output
- const result = this.verticesByRank();
-
- // Find the rank of a vertex in our output
- // Normally you'd grab that information from `vertex.layoutRank`
- // but since we're recomputing that here we need something directly linked
- // to the intermediate result
- const rankOf = (vertex) => {
- const foundRankVertices = result.find((rankVertices) => {
- return rankVertices.find(v => v === vertex);
- });
- return result.indexOf(foundRankVertices);
- };
-
- // This function is really an engine for applying rules
- // These rules are evaluated in order. Each rule can produce one 'promotion', that is it
- // can specify that a single vertex of rank N be promoted to rank N+1
- // These rules will be repeatedly invoked on a rank's vertices until the rule has no effect
- // which is determined by the rule returning `null`
- const promotionRules = [
- // Our first rule is that vertices that are pointed to by other nodes within the rank, but do
- // not point to other nodes within the rank should be promoted
- // This produces a more desirable layout by mostly eliminating horizontal links, which must
- // cross over other links thus creating a confusing layout most of the time.
- (vertices) => {
- const found = vertices.find((v) => {
- const hasIncomingOfSameRank = v.incomingVertices.find(inV => rankOf(inV) === rankOf(v));
- const hasOutgoingOfSameRank = v.outgoingVertices.find(outV => rankOf(outV) === rankOf(v));
- return hasIncomingOfSameRank && hasOutgoingOfSameRank === undefined;
- });
- if (found) {
- return found;
- }
-
- return null;
- },
- // This rule is quite simple, simply limiting the maximum number of nodes in a rank to 3.
- // Beyond this number the graph becomes too compact, links often start crossing over each other
- // and readability suffers
- (vertices) => {
- if (vertices.length > 3) {
- return vertices[0];
- }
- return null;
- }
- ];
-
- // This is the core of this function, wherein we iterate through the ranks and apply the rules
- for (let rank = 0; rank < result.length; rank++) {
- const vertices = result[rank];
- // Iterate through each rule
- promotionRules.forEach(rule => {
- let ruleConverged = false;
- // Execute each rule against the vertices within the rank until the rule has no more
- // mutations to make
- while(!ruleConverged) {
- const promotedVertex = rule(vertices, result);
- // If the rule has found a vertex to promote
- if (promotedVertex !== null) {
- const promotedIndex = vertices.indexOf(promotedVertex);
- // move the vertex found by the rule from this rank and move it to the next one
- vertices.splice(promotedIndex, 1)[0];
- // We may be making a new rank, if so we'll need to seed it with an empty array
- if (result[rank + 1] === undefined) {
- result[rank + 1] = [];
- }
- result[rank + 1].push(promotedVertex);
- } else {
- ruleConverged = true;
- }
- }
- });
- }
-
- // Set separated rank as a property on each vertex
- for (let rank = 0; rank < result.length; rank++) {
- const rankVertices = result[rank];
- rankVertices.forEach(v => v.layoutRank = rank);
- }
-
- return result;
- }
-
- get roots() {
- return this.getVertices().filter((v) => v.isRoot);
- }
-
- get leaves() {
- return this.getVertices().filter((v) => v.isLeaf);
- }
-
- get maxRank() {
- return Math.max.apply(null, this.getVertices().map(v => v.rank));
- }
-
- _getReverseVerticesByRank() {
- return this.getVertices().reduce((acc, v) => {
- const rank = v.reverseRank;
- if (acc.get(rank) === undefined) {
- acc.set(rank, []);
- }
- acc.get(rank).push(v);
- return acc;
- }, new Map());
- }
-
- _bfs() {
- return this._bfsTraversalUsing(this.roots, 'outgoing');
- }
-
- _reverseBfs() {
- return this._bfsTraversalUsing(this.leaves, 'incoming');
- }
-
- /**
- * Performs a breadth-first or reverse-breadth-first search
- * @param {array} startingVertices Where to start the search - either this.roots (for breadth-first) or this.leaves (for reverse-breadth-first)
- * @param {string} vertexType Either 'outgoing' (for breadth-first) or 'incoming' (for reverse-breadth-first)
- */
- _bfsTraversalUsing(startingVertices, vertexType) {
- const distances = {};
- const parents = {};
- const queue = [];
- const vertexTypePropertyName = `${vertexType}Vertices`;
-
- startingVertices.forEach((v) => {
- distances[v.id] = 0;
- queue.push(v);
- });
- while (queue.length > 0) {
- const currentVertex = queue.shift();
- const currentDistance = distances[currentVertex.id];
-
- currentVertex[vertexTypePropertyName].forEach((vertex) => {
- if (distances[vertex.id] === undefined) {
- distances[vertex.id] = currentDistance + 1;
- parents[vertex.id] = currentVertex;
- queue.push(vertex);
- }
- });
- }
-
- return { distances, parents };
- }
-
-
get startVertices() {
return this.getVertices().filter(v => v.incomingEdges.length === 0);
}
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/plain_edge.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/plain_edge.js
deleted file mode 100644
index f70e734e6e108..0000000000000
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/plain_edge.js
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import { Edge } from './edge';
-
-export class PlainEdge extends Edge {
- get svgClass() {
- return `${super.svgClass} ${super.svgClass}Plain`;
- }
-}
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex.js
index feb80611e64de..82189f697e62c 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/models/graph/vertex.js
@@ -4,43 +4,16 @@
* you may not use this file except in compliance with the Elastic License.
*/
-import { LOGSTASH } from '../../../../../../common/constants';
-
export class Vertex {
constructor(graph, json) {
this.graph = graph;
this.update(json);
-
- // Version of the representation used by webcola
- // this object is a bridge back to here, and also can be mutated by webcola
- // and d3, which like to change objects
- this.cola = this._makeCola();
}
update(json) {
this.json = json;
}
- // Should only be called by the constructor!
- // There is no reason to have > 1 instance of this!
- // There is really no good reason to add any additional fields here
- _makeCola() {
- const margin = LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.MARGIN_PX;
- return {
- vertex: this,
- // The margin size must be added since this is actually the size of the bounding box
- width: LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.WIDTH_PX + margin,
- height: LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.HEIGHT_PX + margin
- };
- }
-
- get colaIndex() {
- if (!this._colaIndex) {
- this._colaIndex = this.graph.getVertices().indexOf(this);
- }
- return this._colaIndex;
- }
-
get name() {
return this.json.config_name;
}
@@ -49,21 +22,8 @@ export class Vertex {
return this.json.id;
}
- get htmlAttrId() {
- // Substitute any non-word characters with an underscore so
- // D3 selections don't interpret them as special selector syntax
- return this.json.id.replace(/\W/g, '_');
- }
-
get subtitle() {
- return {
- complete: this.id,
- display: this.truncateStringForDisplay(this.id, this.displaySubtitleMaxLength)
- };
- }
-
- get displaySubtitleMaxLength() {
- return 19;
+ return this.id;
}
get incomingEdges() {
@@ -82,26 +42,6 @@ export class Vertex {
return this.outgoingEdges.map(e => e.to);
}
- get isRoot() {
- return this.incomingVertices.length === 0;
- }
-
- get isLeaf() {
- return this.outgoingVertices.length === 0;
- }
-
- get rank() {
- return this.graph.vertexRankById[this.id];
- }
-
- get sourceLocation() {
- return `apc.conf@${this.meta.source_line}:${this.meta.source_column}`;
- }
-
- get sourceText() {
- return this.meta.source_text;
- }
-
get meta() {
return this.json.meta;
}
@@ -110,53 +50,6 @@ export class Vertex {
return this.json.stats || {};
}
- get hasCustomStats() {
- return Object.keys(this.customStats).length > 0;
- }
- get customStats() {
- return Object.keys(this.stats)
- .filter(k => !(k.match(/^events\./)))
- .filter(k => k !== 'name')
- .reduce((acc, k) => {
- acc[k] = this.stats[k];
- return acc;
- }, {});
- }
-
- lineage() {
- const ancestors = this.ancestors();
- const descendants = this.descendants();
-
- const vertices = [];
- vertices.push.apply(vertices, ancestors.vertices);
- vertices.push(this);
- vertices.push.apply(vertices, descendants.vertices);
-
- const edges = ancestors.edges.concat(descendants.edges);
-
- return { vertices, edges };
- }
-
- ancestors() {
- const vertices = [];
- const edges = [];
- const pending = [this];
- const seen = {};
- while (pending.length > 0) {
- const vertex = pending.pop();
- vertex.incomingEdges.forEach(edge => {
- edges.push(edge);
- const from = edge.from;
- if (seen[from.id] !== true) {
- vertices.push(from);
- pending.push(from);
- seen[from.id] = true;
- }
- });
- }
- return { vertices, edges };
- }
-
descendants() {
const vertices = [];
const edges = [];
@@ -177,26 +70,7 @@ export class Vertex {
return { vertices, edges };
}
- get eventsPerCurrentPeriod() {
- if (!this.stats.hasOwnProperty('events.in')) {
- return null;
- }
-
- return (this.stats['events.in'].max - this.stats['events.in'].min);
- }
-
get hasExplicitId() {
return Boolean(this.json.explicit_id);
}
-
- truncateStringForDisplay(completeString, maxDisplayLength) {
- if (completeString.length <= maxDisplayLength) {
- return completeString;
- }
-
- const ellipses = ' \u2026 ';
- const eachHalfMaxDisplayLength = Math.floor((maxDisplayLength - ellipses.length) / 2);
-
- return `${completeString.substr(0, eachHalfMaxDisplayLength)}${ellipses}${completeString.substr(-eachHalfMaxDisplayLength)}`;
- }
}
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js
index 74bf9b36e65f2..81e0b9b2e1f32 100644
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js
+++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/detail_drawer.test.js
@@ -167,9 +167,7 @@ describe('DetailDrawer component', () => {
const vertex = {
title: 'if',
typeString: 'if',
- subtitle: {
- complete: '[type] == "apache_log"'
- }
+ subtitle: '[type] == "apache_log"'
};
const component = (
diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/cola_graph.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/cola_graph.js
deleted file mode 100644
index d9aed7251e585..0000000000000
--- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/cola_graph.js
+++ /dev/null
@@ -1,470 +0,0 @@
-/*
- * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
- * or more contributor license agreements. Licensed under the Elastic License;
- * you may not use this file except in compliance with the Elastic License.
- */
-
-import React from 'react';
-import d3 from 'd3';
-import { PluginVertex } from '../models/graph/plugin_vertex';
-import { IfVertex } from '../models/graph/if_vertex';
-import { QueueVertex } from '../models/graph/queue_vertex';
-import {
- enterInputVertex,
- enterProcessorVertex,
- enterIfVertex,
- enterQueueVertex,
- updateInputVertex,
- updateProcessorVertex
-} from './vertex_content_renderer';
-import { LOGSTASH } from '../../../../../common/constants';
-import { makeEdgeBetween, d3adaptor } from 'webcola';
-
-function makeMarker(svgDefs, id, fill) {
- svgDefs.append('marker')
- .attr('id', id)
- .attr('viewBox', '0 -5 10 10')
- .attr('refX', 5)
- .attr('markerWidth', 3)
- .attr('markerHeight', 3)
- .attr('orient', 'auto')
- .append('path')
- .attr('d', 'M0,-5L10,0L0,5L2,0')
- .attr('stroke-width', '0px')
- .attr('fill', fill);
-}
-
-function makeBackground(parentEl) {
- return parentEl
- .append('rect')
- .attr('width', '100%')
- .attr('height', '100%')
- .attr('fill', '#efefef');
-}
-
-function makeGroup(parentEl) {
- return parentEl
- .append('g');
-}
-
-function makeNodes(nodesLayer, colaVertices) {
- const nodes = nodesLayer
- .selectAll('.lspvVertex')
- .data(colaVertices, d => d.vertex.htmlAttrId);
-
- nodes
- .enter()
- .append('g')
- .attr('id', d => `nodeg-${d.vertex.htmlAttrId}`)
- .attr('class', d => `lspvVertex ${d.vertex.typeString}`)
- .attr('width', LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.WIDTH_PX)
- .attr('height', LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.HEIGHT_PX);
-
- nodes
- .append('rect')
- .attr('class', 'lspvVertexBounding')
- .attr('rx', LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.BORDER_RADIUS_PX)
- .attr('ry', LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.BORDER_RADIUS_PX);
-
- return nodes;
-}
-
-function addNodesMouseBehaviors(nodes, onMouseover, onMouseout, onMouseclick) {
- nodes.on('mouseover', onMouseover);
- nodes.on('mouseout', onMouseout);
- nodes.on('click', onMouseclick);
-}
-
-function makeInputNodes(nodes) {
- const inputs = nodes.filter(node => (node.vertex instanceof PluginVertex) && node.vertex.isInput);
- inputs.call(enterInputVertex);
-
- return inputs;
-}
-
-function makeProcessorNodes(nodes) {
- const processors = nodes.filter(node => (node.vertex instanceof PluginVertex) && node.vertex.isProcessor);
- processors.call(enterProcessorVertex);
-
- return processors;
-}
-
-function makeIfNodes(nodes) {
- const ifs = nodes.filter(d => d.vertex instanceof IfVertex);
- ifs.call(enterIfVertex);
-
- return ifs;
-}
-
-function makeQueueNode(nodes) {
- const queue = nodes.filter(d => d.vertex instanceof QueueVertex);
- queue.call(enterQueueVertex);
-
- return queue;
-}
-
-// Line function for drawing paths between nodes
-const lineFunction = d3.svg.line()
- // Null check that handles a bug in webcola where sometimes these values are null for a tick
- .x(d => d ? d.x : null)
- .y(d => d ? d.y : null);
-
-export class ColaGraph extends React.Component {
- constructor() {
- super();
- this.state = {};
-
- this.width = 1000;
- this.height = 1000;
- }
-
- renderGraph(svgEl) {
- this.d3cola = d3adaptor()
- .avoidOverlaps(true)
- .size([this.width, this.height]);
-
- const outer = d3.select(svgEl);
- const background = makeBackground(outer);
-
- const svgDefs = outer.append('defs');
- makeMarker(svgDefs, 'lspvPlainMarker', '#000');
- makeMarker(svgDefs, 'lspvTrueMarker', '#1BAFD2');
- makeMarker(svgDefs, 'lspvFalseMarker', '#EE408A');
-
- // Set initial zoom to 100%. You need both the translate and scale options
- const zoom = d3.behavior.zoom().translate([100, 100]).scale(1);
- const vis = outer
- .append('g')
- .attr('transform', 'translate(0,0) scale(1)');
-
- const redraw = () => {
- vis.attr('transform', `translate(${d3.event.translate}) scale(${d3.event.scale})`);
- };
-
- outer.call(d3.behavior.zoom().on('zoom', redraw));
- background.call(zoom.on('zoom', redraw));
-
- this.nodesLayer = makeGroup(vis);
- this.nodes = makeNodes(this.nodesLayer, this.graph.colaVertices);
-
- this.inputs = makeInputNodes(this.nodes);
- this.processors = makeProcessorNodes(this.nodes);
- this.ifs = makeIfNodes(this.nodes);
- this.queue = makeQueueNode(this.nodes);
-
- addNodesMouseBehaviors(this.nodes, this.onMouseover, this.onMouseout, this.onMouseclick);
-
- this.linksLayer = makeGroup(vis);
-
- const ifTriangleColaGroups = this.graph.triangularIfGroups.map(group => {
- return { leaves: Object.values(group).map(v => v.colaIndex) };
- });
-
- this.d3cola
- .nodes(this.graph.colaVertices)
- .links(this.graph.colaEdges)
- .groups(ifTriangleColaGroups)
- .constraints(this._getConstraints())
- // This number controls the max number of iterations for the layout iteration to
- // solve the constraints. Higher numbers usually wind up in a better layout
- .start(10000);
-
- this.makeLinks();
-
- let tickStart;
- let ticks = 0;
-
- // Minimum amount of time between reflows
- // We want a value that looks interactive but doesn't waste CPU time rendering intermediate results
- const reflowEvery = 1000; // 1s
- // Amount of time to allow the solver to run
- // We want a value that isn't so long that the user gets irritated using the graph due to the CPU being monopolized
- // by the constraint solver
- const maxDuration = 10000; // 10s
- let lastReflow = new Date();
- this.d3cola
- .on('tick', () => {
- const now = new Date();
-
- ticks++;
- if (ticks === 1) {
- tickStart = now;
- }
-
- const elapsedSinceLastReflow = now - lastReflow;
- if (ticks === 1 || elapsedSinceLastReflow >= reflowEvery) {
- this.reflow();
- lastReflow = now;
- }
- const totalElapsed = now - tickStart;
- if (totalElapsed >= maxDuration) {
- this.d3cola.stop();
- this.reflow();
- console.log("Logstash graph visualizer constraint timeout! Rendering will stop here.");
- }
- })
- .on('end', this.reflow);
- }
-
- // Actually render the latest webcola state
- reflow = () => {
- this.setNodeBounds();
- this.routeAndLabelEdges();
- }
-
- setNodeBounds = () => {
- this.nodes.each((d) => d.innerBounds = d.bounds.inflate(-LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.MARGIN_PX));
- this.nodes.attr('transform', (d) => `translate(${d.innerBounds.x}, ${d.innerBounds.y})`);
- this.nodes.select('rect')
- .attr('width', (d) => d.innerBounds.width())
- .attr('height', (d) => d.innerBounds.height());
- }
-
- routeAndLabelEdges = () => {
- this.links.attr('d', (d) => {
- const arrowStart = LOGSTASH.PIPELINE_VIEWER.GRAPH.EDGES.ARROW_START;
- const route = makeEdgeBetween(d.source.innerBounds, d.target.innerBounds, arrowStart);
- return lineFunction([route.sourceIntersection, route.arrowStart]);
- });
- this.routeEdges();
- this.labelEdges();
- }
-
- routeEdges() {
- this.d3cola.prepareEdgeRouting(LOGSTASH.PIPELINE_VIEWER.GRAPH.EDGES.ROUTING_MARGIN_PX);
- this.links.select('path').attr('d', (d) => {
- try {
- return lineFunction(this.d3cola.routeEdge(d));
- } catch (err) {
- console.error('Could not exec line function!', err);
- }
- });
- }
-
- labelEdges() {
- // Use a regular function instead of () => since we want the dom element via `this`,
- // only accessible via d3 setting 'this' AFAIK
- this.booleanLabels.each(function () {
- const path = d3.select(this.parentNode).select('path')[0][0];
- const pathLength = path.getTotalLength();
- if (pathLength === 0) {
- return;
- }
-
- const center = path.getPointAtLength(pathLength / 2);
- const group = d3.select(this);
- group.select('circle')
- .attr('cx', center.x)
- .attr('cy', center.y);
-
- // Offset by to vertically center the text
- const textVerticalOffset = 5;
- group.select('text')
- .attr('x', center.x)
- .attr('y', center.y + textVerticalOffset);
- });
- }
-
- makeLinks() {
- this.links = this.linksLayer.selectAll('.link')
- .data(this.graph.colaEdges);
-
- const linkGroup = this.links.enter()
- .append('g')
- .attr('id', (d) => `lspvEdge-${d.edge.htmlAttrId}`)
- .attr('class', (d) => d.edge.svgClass);
- linkGroup.append('path');
-
- const booleanLinks = linkGroup.filter('.lspvEdgeBoolean');
- this.booleanLabels = booleanLinks
- .append('g')
- .attr('class', 'lspvBooleanLabel');
-
- this.booleanLabels
- .append('circle')
- .attr('r', LOGSTASH.PIPELINE_VIEWER.GRAPH.EDGES.LABEL_RADIUS);
- this.booleanLabels
- .append('text')
- .attr('text-anchor', 'middle') // Position the text on its vertical
- .text(d => d.edge.when ? 'T' : 'F');
- }
-
- updateGraph(nextProps = {}, nextState = {}) {
- this.processors.call(updateProcessorVertex);
- this.inputs.call(updateInputVertex);
-
- this.nodesLayer.selectAll('.lspvVertexBounding-highlighted').classed('lspvVertexBounding-highlighted', false);
- this.nodesLayer.selectAll('.lspvVertex-grayed').classed('lspvVertex-grayed', false);
- this.linksLayer.selectAll('.lspvEdge-grayed').classed('lspvEdge-grayed', false);
-
- const hoverNode = nextState.hoverNode;
- if (hoverNode) {
- const selection = this.nodesLayer
- .selectAll('#nodeg-' + hoverNode.vertex.htmlAttrId)
- .selectAll('rect');
- selection.classed('lspvVertexBounding-highlighted', true);
-
- const lineage = hoverNode.vertex.lineage();
-
- const lineageVertices = lineage.vertices;
- const nonLineageVertices = this.graph.getVertices().filter(v => lineageVertices.indexOf(v) === -1);
- const grayedVertices = this.nodesLayer.selectAll('g.lspvVertex').filter(d => nonLineageVertices.indexOf(d.vertex) >= 0);
- grayedVertices.classed('lspvVertex-grayed', true);
-
- const lineageEdges = lineage.edges;
- const nonLineageEdges = this.graph.edges.filter(e => lineageEdges.indexOf(e) === -1);
- const grayedEdges = this.linksLayer.selectAll('.lspvEdge').filter(d => nonLineageEdges.indexOf(d.edge) >= 0);
- grayedEdges.classed('lspvEdge-grayed', true);
- }
-
- const detailVertex = nextProps.detailVertex;
- if (detailVertex) {
- const selection = this.nodesLayer
- .selectAll('#nodeg-' + detailVertex.htmlAttrId)
- .selectAll('rect');
- selection.classed('lspvVertexBounding-highlighted', true);
- }
- }
-
- onMouseover = (node) => {
- this.setState({ hoverNode: node });
- }
-
- onMouseout = () => {
- this.setState({ hoverNode: null });
- }
-
- onMouseclick = (e) => {
- this.props.onShowVertexDetails(e.vertex);
- }
-
- get graph() {
- return this.props.graph;
- }
-
- _getConstraints() {
- // To understand webcola constraints please read:
- // https://github.com/tgdwyer/WebCola/wiki/Constraints
- const constraints = [];
- const verticesByRank = this.graph.verticesByLayoutRank;
-
- // Lay out triangle groups as... a triangle! That is to say,
- // with an if in the middle and the true on the left and the false on the right
- this.graph.triangularIfGroups.forEach(group => {
- if (group.trueVertex && group.falseVertex) {
- Object.values(group).forEach(v => v.isInTriangleGroup = true);
- constraints.push({
- type: 'alignment',
- axis: 'x',
- offsets: [
- { node: group.ifVertex.colaIndex, offset: 0 },
- // The offsets here are oddly sensitive. If you use lower values than the width of
- // the node the layout gets all crazy and overlappy for reasons I don't understand
- { node: group.trueVertex.colaIndex, offset: -LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.WIDTH_PX },
- { node: group.falseVertex.colaIndex, offset: LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.WIDTH_PX }
- ]
- });
- }
- });
-
- for (let rank = 0; rank < verticesByRank.length; rank++) {
- const vertices = verticesByRank[rank];
-
- // Ensure that nodes of an equal rank are aligned on the y axis.
- constraints.push(
- {
- type: 'alignment',
- axis: 'y',
- offsets: vertices.map(v => {
- return { node: v.colaIndex, offset: 0 };
- })
- }
- );
-
- if (rank > 0) {
- const previousVertices = verticesByRank[rank - 1];
-
- // Prevent sibling nodes from overlapping
- vertices.forEach((vertex, index) => {
- const previousParents = previousVertices.filter(previousVertex => {
- return previousVertex.outgoingVertices.find(v => v === vertex);
- });
-
- const nodeXGap = LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.WIDTH_PX + LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.MARGIN_PX;
- const rightSibling = vertices[index + 1];
- // We don't need to add constraints for nodes in triangle groups since they have
- // a constraint that keeps them separately already
- if (rightSibling && !rightSibling.isInTriangleGroup && !vertex.isInTriangleGroup) {
- constraints.push({
- axis: "x",
- right: vertex.colaIndex,
- left: rightSibling.colaIndex,
- gap: nodeXGap
- });
- }
-
- // Ensure that nodes of rank N that have a single outbound connection to a node of rank N+1
- // are positioned vertically inline
- // We start by checking if the current node has exactly one parent in the previous rank
- // if it has > 1 parent then we don't really know where to put it
- if (previousParents.length === 1) {
- const previousParent = previousParents[0];
- // We further check that the connected parent isn't also connected to other nodes in this rank
- // otherwise the nodes would have to overlap if we aligned them
- if (previousParent.outgoingVertices.filter(v => v.layoutRank === rank).length === 1) {
- constraints.push({
- axis: 'x',
- left: previousParent.colaIndex,
- right: vertex.colaIndex,
- gap: 0,
- equality: true
- });
- }
- }
-
- // Ensure that all nodes of a given rank are at the same exact distance below others
- previousVertices.forEach(previousVertex => {
- constraints.push({
- axis: 'y',
- left: previousVertex.colaIndex,
- right: vertex.colaIndex,
- // Multiplying the gap by two works much better for large graphs giving more space to route edges
- gap: LOGSTASH.PIPELINE_VIEWER.GRAPH.VERTICES.HEIGHT_PX * 2,
- equality: true
- });
- });
- });
- }
- }
-
- return constraints;
- }
-
- render() {
- const viewBox = `0,0,${this.width},${this.height}`;
- return (
-