diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/collapsible_statement.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/collapsible_statement.test.js.snap new file mode 100644 index 0000000000000..a6d4a6a4d5b64 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/collapsible_statement.test.js.snap @@ -0,0 +1,32 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`CollapsibleStatement component renders child components 1`] = ` + + + + +
+ child element +
+
+`; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/metric.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/metric.test.js.snap new file mode 100644 index 0000000000000..c06d81902cb14 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/metric.test.js.snap @@ -0,0 +1,36 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Metric component does not render warning badge when no warning present 1`] = ` + + + + 220 + + + +`; + +exports[`Metric component renders warning badge 1`] = ` + + + 220 + + +`; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/pipeline_viewer.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/pipeline_viewer.test.js.snap new file mode 100644 index 0000000000000..e6c6161f588ee --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/pipeline_viewer.test.js.snap @@ -0,0 +1,177 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PipelineViewer component passes expected props 1`] = ` + + + + + + + + + + + +`; + +exports[`PipelineViewer component renders DetailDrawer when selected vertex is not null 1`] = ` + + + + + + + + + + + + +`; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/plugin_statement.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/plugin_statement.test.js.snap new file mode 100644 index 0000000000000..a4ce0c7b20bcc --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/plugin_statement.test.js.snap @@ -0,0 +1,429 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`PluginStatement component adds warning highlight for cpu time 1`] = ` + + + + + + + mutate + + + + + + mutatePlugin + + + + + + + + + + + + +`; + +exports[`PluginStatement component adds warning highlight for event millis 1`] = ` + + + + + + + mutate + + + + + + mutatePlugin + + + + + + + + + + + + +`; + +exports[`PluginStatement component does not render explicit id field if no id is specified 1`] = ` + + + + + + + stdin + + + + + + + + + + + +`; + +exports[`PluginStatement component renders input metrics and explicit id fields 1`] = ` + + + + + + + stdin + + + + + + standardInput + + + + + + + + + + +`; + +exports[`PluginStatement component renders processor statement metrics 1`] = ` + + + + + + + mutate + + + + + + mutatePlugin + + + + + + + + + + + + +`; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/queue.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/queue.test.js.snap new file mode 100644 index 0000000000000..ab90393a81969 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/queue.test.js.snap @@ -0,0 +1,19 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Queue component renders default elements 1`] = ` +
+ + + + Queue metrics not available + +
+`; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement.test.js.snap new file mode 100644 index 0000000000000..3e6699c31ce6c --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement.test.js.snap @@ -0,0 +1,164 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`Statement component renders a CollapsibleStatement with else body for non-IfElement 1`] = ` +
  • +
    + + + + + else + + + + +
  • +`; + +exports[`Statement component renders a CollapsibleStatement with if body for branch model 1`] = ` +
  • +
    + + + + + if + + + + + + + +
  • +`; + +exports[`Statement component renders a PluginStatement component for plugin model 1`] = ` +
  • +
    + +
  • +`; + +exports[`Statement component renders spacers for element with depth > 0 1`] = ` +
  • +
    +
    +
    +
    + + + + + else + + + + +
  • +`; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list.test.js.snap new file mode 100644 index 0000000000000..3314faba55156 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list.test.js.snap @@ -0,0 +1,36 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StatementList renders nested elements as expected 1`] = ` + +`; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list_heading.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list_heading.test.js.snap new file mode 100644 index 0000000000000..d553a4c4c173f --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_list_heading.test.js.snap @@ -0,0 +1,35 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StatementListHeading component renders title and icon type 1`] = ` + + + + + + +

    + Filters +

    +
    +
    +
    +`; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_section.test.js.snap b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_section.test.js.snap new file mode 100644 index 0000000000000..59af548f267fd --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/__snapshots__/statement_section.test.js.snap @@ -0,0 +1,28 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`StatementSection component renders heading text, correct icon type, and elements for StatementSection 1`] = ` +
    + + + +
    +`; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/collapsible_statement.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/collapsible_statement.test.js new file mode 100644 index 0000000000000..f759f879ab790 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/collapsible_statement.test.js @@ -0,0 +1,54 @@ +/* + * 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 { CollapsibleStatement } from '../collapsible_statement'; +import { shallow } from 'enzyme'; +import { EuiButtonIcon } from '@elastic/eui'; + +describe('CollapsibleStatement component', () => { + let props; + let collapse; + let expand; + + beforeEach(() => { + collapse = jest.fn(); + expand = jest.fn(); + props = { + collapse, + expand, + id: 'statementId', + isCollapsed: false, + }; + }); + + it('renders child components', () => { + const child =
    child element
    ; + + const wrapper = shallow( + {child} + ); + + expect(wrapper).toMatchSnapshot(); + }); + + it('calls collapse if component is expanded', () => { + const wrapper = shallow(); + + wrapper.find(EuiButtonIcon).simulate('click'); + expect(collapse).toHaveBeenCalledTimes(1); + expect(collapse).toHaveBeenCalledWith('statementId'); + }); + + it('calls expand if component is collapsed', () => { + props.isCollapsed = true; + const wrapper = shallow(); + + wrapper.find(EuiButtonIcon).simulate('click'); + expect(expand).toHaveBeenCalledTimes(1); + expect(expand).toHaveBeenCalledWith('statementId'); + }); +}); 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 81e0b9b2e1f32..a20bc9a6c1abe 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 @@ -19,15 +19,10 @@ describe('DetailDrawer component', () => { test('shows vertex title', () => { const vertex = { - title: 'grok' + title: 'grok', }; - const component = ( - - ); + const component = ; const renderedComponent = shallow(component); expect(renderedComponent).toMatchSnapshot(); }); @@ -43,46 +38,34 @@ describe('DetailDrawer component', () => { id: 'parse_apache_logline', stats: { events_in: { - data: [ - [ 1516131120000, 200 ], - [ 1516131180000, 203 ] - ], + data: [[1516131120000, 200], [1516131180000, 203]], timeRange: { min: 1516131138639, - max: 1516135440463 - } + max: 1516135440463, + }, }, events_out: { - data: [ - [ 1516131120000, 199 ], - [ 1516131180000, 200 ] - ], + data: [[1516131120000, 199], [1516131180000, 200]], timeRange: { min: 1516131138639, - max: 1516135440463 - } + max: 1516135440463, + }, }, millis_per_event: { - data: [ - [ 1516131120000, 0.21 ], - [ 1516131180000, 0.23 ] - ], + data: [[1516131120000, 0.21], [1516131180000, 0.23]], timeRange: { min: 1516131138639, - max: 1516135440463 - } - } + max: 1516135440463, + }, + }, }, eventsPerSecond: { - data: [ - [ 1516131120000, 32 ], - [ 1516131180000, 36 ] - ], + data: [[1516131120000, 32], [1516131180000, 36]], timeRange: { min: 1516131138639, - max: 1516135440463 - } - } + max: 1516135440463, + }, + }, }; const component = ( @@ -107,46 +90,34 @@ describe('DetailDrawer component', () => { id: 'foobarbazqux', stats: { events_in: { - data: [ - [ 1516131120000, 200 ], - [ 1516131180000, 203 ] - ], + data: [[1516131120000, 200], [1516131180000, 203]], timeRange: { min: 1516131138639, - max: 1516135440463 - } + max: 1516135440463, + }, }, events_out: { - data: [ - [ 1516131120000, 199 ], - [ 1516131180000, 200 ] - ], + data: [[1516131120000, 199], [1516131180000, 200]], timeRange: { min: 1516131138639, - max: 1516135440463 - } + max: 1516135440463, + }, }, millis_per_event: { - data: [ - [ 1516131120000, 0.21 ], - [ 1516131180000, 0.23 ] - ], + data: [[1516131120000, 0.21], [1516131180000, 0.23]], timeRange: { min: 1516131138639, - max: 1516135440463 - } - } + max: 1516135440463, + }, + }, }, eventsPerSecond: { - data: [ - [ 1516131120000, 32 ], - [ 1516131180000, 36 ] - ], + data: [[1516131120000, 32], [1516131180000, 36]], timeRange: { min: 1516131138639, - max: 1516135440463 - } - } + max: 1516135440463, + }, + }, }; const component = ( @@ -167,7 +138,7 @@ describe('DetailDrawer component', () => { const vertex = { title: 'if', typeString: 'if', - subtitle: '[type] == "apache_log"' + subtitle: '[type] == "apache_log"', }; const component = ( @@ -186,7 +157,7 @@ describe('DetailDrawer component', () => { test('shows basic info and no stats for queue', () => { const vertex = { title: 'queue', - typeString: 'queue' + typeString: 'queue', }; const component = ( diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/metric.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/metric.test.js new file mode 100644 index 0000000000000..c623074317c54 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/metric.test.js @@ -0,0 +1,34 @@ +/* + * 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 { Metric } from '../metric'; +import { shallow } from 'enzyme'; + +describe('Metric component', () => { + let metric; + + beforeEach(() => { + metric = { + className: 'metricClass', + warning: true, + value: '220', + }; + }); + + it('renders warning badge', () => { + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); + + it('does not render warning badge when no warning present', () => { + metric.warning = false; + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js new file mode 100644 index 0000000000000..6bc2e4adda271 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/pipeline_viewer.test.js @@ -0,0 +1,85 @@ +/* + * 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 { PipelineViewer } from '../pipeline_viewer'; +import { shallow } from 'enzyme'; +import { get } from 'lodash'; + +describe('PipelineViewer component', () => { + let pipeline; + let component; + + beforeEach(() => { + pipeline = { + inputs: [ + { + depth: 0, + id: 'standardInput', + parentId: null, + }, + ], + filters: [ + { + depth: 0, + id: 'mutate', + parentId: null, + }, + ], + outputs: [ + { + depth: 0, + id: 'elasticsearch', + parentId: null, + }, + ], + queue: { + id: '__QUEUE__', + hasExplicitId: false, + stats: [], + meta: null, + }, + }; + + component = ; + }); + + it('passes expected props', () => { + const renderedComponent = shallow(component); + + expect(renderedComponent).toMatchSnapshot(); + }); + + it('changes selected vertex', () => { + const vertex = { id: 'stdin' }; + + const instance = shallow(component).instance(); + instance.onShowVertexDetails(vertex); + + expect(get(instance, 'state.detailDrawer.vertex')).toBe(vertex); + }); + + it('toggles selected vertex on second pass', () => { + const vertex = { id: 'stdin' }; + + const instance = shallow(component).instance(); + instance.onShowVertexDetails(vertex); + instance.onShowVertexDetails(vertex); + + expect(get(instance, 'state.detailDrawer.vertex')).toBeNull(); + }); + + it('renders DetailDrawer when selected vertex is not null', () => { + const vertex = { id: 'stdin' }; + + const wrapper = shallow(component); + const instance = wrapper.instance(); + instance.onShowVertexDetails(vertex); + wrapper.update(); + + expect(wrapper).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/plugin_statement.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/plugin_statement.test.js new file mode 100644 index 0000000000000..f0e2eecca70f5 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/plugin_statement.test.js @@ -0,0 +1,102 @@ +/* + * 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 { PluginStatement } from '../plugin_statement'; +import { shallow } from 'enzyme'; + +import { EuiButtonEmpty, EuiBadge } from '@elastic/eui'; + +describe('PluginStatement component', () => { + let props; + let onShowVertexDetails; + let isSlow; + let isTimeConsuming; + let processorStatement; + + beforeEach(() => { + onShowVertexDetails = jest.fn(); + props = { + statement: { + hasExplicitId: true, + id: 'standardInput', + name: 'stdin', + pluginType: 'input', + vertex: { + latestEventsPerSecond: 125, + }, + }, + onShowVertexDetails, + }; + + isSlow = jest.fn().mockImplementation(() => false); + isTimeConsuming = jest.fn().mockImplementation(() => false); + processorStatement = { + hasExplicitId: true, + id: 'mutatePlugin', + name: 'mutate', + pluginType: 'filter', + vertex: { + latestMillisPerEvent: 100, + latestEventsPerSecond: 120, + percentOfTotalProcessorTime: 25, + isSlow, + isTimeConsuming, + }, + }; + }); + + const render = props => shallow(); + + it('renders input metrics and explicit id fields', () => { + expect(render(props)).toMatchSnapshot(); + }); + + it('does not render explicit id field if no id is specified', () => { + props.statement.id = 'dcbb2c37b4fedd3d7b852b5052f03dw3fbe1545a'; + props.statement.hasExplicitId = false; + expect(render(props)).toMatchSnapshot(); + }); + + it('renders processor statement metrics', () => { + props.statement = processorStatement; + expect(render(props)).toMatchSnapshot(); + expect(isSlow).toHaveBeenCalledTimes(1); + expect(isTimeConsuming).toHaveBeenCalledTimes(1); + }); + + it('adds warning highlight for cpu time', () => { + props.statement = processorStatement; + props.statement.vertex.isTimeConsuming = jest + .fn() + .mockImplementation(() => true); + expect(render(props)).toMatchSnapshot(); + }); + + it('adds warning highlight for event millis', () => { + props.statement = processorStatement; + props.statement.vertex.isSlow = jest.fn().mockImplementation(() => true); + expect(render(props)).toMatchSnapshot(); + }); + + it('handles name button click', () => { + const { vertex } = props.statement; + const wrapper = render(props); + wrapper.find(EuiButtonEmpty).simulate('click'); + + expect(onShowVertexDetails).toHaveBeenCalledTimes(1); + expect(onShowVertexDetails).toHaveBeenCalledWith(vertex); + }); + + it('handles id badge click', () => { + const { vertex } = props.statement; + const wrapper = render(props); + wrapper.find(EuiBadge).simulate('click'); + + expect(onShowVertexDetails).toHaveBeenCalledTimes(1); + expect(onShowVertexDetails).toHaveBeenCalledWith(vertex); + }); +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/queue.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/queue.test.js new file mode 100644 index 0000000000000..2d107ed77d664 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/queue.test.js @@ -0,0 +1,15 @@ +/* + * 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 { Queue } from '../queue'; +import { shallow } from 'enzyme'; + +describe('Queue component', () => { + it('renders default elements', () => { + expect(shallow()).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement.test.js new file mode 100644 index 0000000000000..88f2ae861da11 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement.test.js @@ -0,0 +1,90 @@ +/* + * 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 { Statement } from '../statement'; +import { PluginStatement } from '../../models/pipeline/plugin_statement'; +import { PluginStatement as PluginStatementComponent } from '../plugin_statement'; +import { IfElement } from '../../models/list/if_element'; +import { CollapsibleStatement } from '../collapsible_statement'; +import { shallow } from 'enzyme'; +import { EuiButtonEmpty } from '@elastic/eui'; + +describe('Statement component', () => { + let props; + let pluginStatement; + let branchElement; + let collapse; + let expand; + let onShowVertexDetails; + + beforeEach(() => { + collapse = jest.fn(); + expand = jest.fn(); + onShowVertexDetails = jest.fn(); + props = { + collapse, + element: { + depth: 0, + id: 'mutate2', + statement: {}, + }, + expand, + isCollapsed: false, + onShowVertexDetails, + }; + pluginStatement = new PluginStatement({ + hasExplicitId: true, + id: 'mutate2', + latestEventsPerSecond: 23, + meta: null, + name: 'mutate', + pluginType: 'filter', + stats: [], + }); + branchElement = new IfElement( + { + id: 'ifStatement', + name: 'ifStatement', + }, + 0, + null + ); + }); + + it('renders a PluginStatement component for plugin model', () => { + props.element.statement = pluginStatement; + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + expect(wrapper.find(PluginStatementComponent)).toHaveLength(1); + }); + + it('renders spacers for element with depth > 0', () => { + props.element.depth = 2; + expect(shallow()).toMatchSnapshot(); + }); + + it('renders a CollapsibleStatement with if body for branch model', () => { + props.element = branchElement; + const wrapper = shallow(); + + expect(wrapper).toMatchSnapshot(); + expect(wrapper.find(CollapsibleStatement)).toHaveLength(1); + }); + + it('renders a CollapsibleStatement with else body for non-IfElement', () => { + expect(shallow()).toMatchSnapshot(); + }); + + it(`selects the element's vertex when the name is clicked`, () => { + props.element = branchElement; + const wrapper = shallow(); + + wrapper.find(EuiButtonEmpty).simulate('click'); + expect(onShowVertexDetails).toHaveBeenCalledTimes(1); + }); +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list.test.js new file mode 100644 index 0000000000000..e3f3e3cd9a63f --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list.test.js @@ -0,0 +1,64 @@ +/* + * 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 { StatementList } from '../statement_list'; +import { Statement } from '../statement'; +import { shallow } from 'enzyme'; + +describe('StatementList', () => { + let props; + let onShowVertexDetails; + + beforeEach(() => { + onShowVertexDetails = jest.fn(); + props = { + elements: [ + { + id: 'mutateIf', + parentId: null, + depth: 0, + }, + { + id: 'mutate', + parentId: 'mutateIf', + depth: 1, + }, + ], + onShowVertexDetails, + }; + }); + + const render = props => shallow(); + + it('renders nested elements as expected', () => { + const wrapper = render(props); + expect(wrapper).toMatchSnapshot(); + expect(wrapper.find(Statement).length).toBe(2); + }); + + it('renders children elements when parent is collapsed', () => { + const wrapper = render(props); + const instance = wrapper.instance(); + instance.collapse('mutateIf'); + wrapper.update(); + + expect(wrapper.find(Statement).length).toBe(1); + }); + + it('renders children after expanding collapsed elements', () => { + const wrapper = render(props); + const instance = wrapper.instance(); + + instance.collapse('mutateIf'); + wrapper.update(); + expect(wrapper.find(Statement).length).toBe(1); + + instance.expand('mutateIf'); + wrapper.update(); + expect(wrapper.find(Statement).length).toBe(2); + }); +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list_heading.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list_heading.test.js new file mode 100644 index 0000000000000..e4d68901ff544 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_list_heading.test.js @@ -0,0 +1,24 @@ +/* + * 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 { StatementListHeading } from '../statement_list_heading'; +import { shallow } from 'enzyme'; + +describe('StatementListHeading component', () => { + let props; + + beforeEach(() => { + props = { + iconType: 'logstashInput', + title: 'Filters', + }; + }); + + it('renders title and icon type', () => { + expect(shallow()).toMatchSnapshot(); + }); +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_section.test.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_section.test.js new file mode 100644 index 0000000000000..679c60ee8eaab --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/__test__/statement_section.test.js @@ -0,0 +1,43 @@ +/* + * 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 { StatementSection } from '../statement_section'; +import { shallow } from 'enzyme'; + +describe('StatementSection component', () => { + let props; + let onShowVertexDetails; + + beforeEach(() => { + onShowVertexDetails = jest.fn(); + props = { + elements: [ + { + id: 'standardInput', + parentId: null, + }, + { + id: 'fileInput', + parentId: null, + }, + ], + headingText: 'Inputs', + iconType: 'logstashInput', + onShowVertexDetails, + }; + }); + + it('renders heading text, correct icon type, and elements for StatementSection', () => { + expect(shallow()).toMatchSnapshot(); + }); + + it('renders nothing if elements array is empty', () => { + props.elements = []; + const wrapper = shallow(); + expect(wrapper.instance()).toBe(null); + }); +}); diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/collapsible_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/collapsible_statement.js index df6d46f1e45ba..b1fe7aa65a051 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/collapsible_statement.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/collapsible_statement.js @@ -7,23 +7,14 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { - EuiButtonIcon, - EuiFlexGroup, - EuiFlexItem -} from '@elastic/eui'; +import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; function getToggleIconType(isCollapsed) { return isCollapsed ? 'arrowRight' : 'arrowDown'; } export function CollapsibleStatement(props) { - const { - collapse, - expand, - id, - isCollapsed - } = props; + const { collapse, expand, id, isCollapsed } = props; const toggleClicked = () => { if (isCollapsed) { @@ -40,10 +31,7 @@ export function CollapsibleStatement(props) { alignItems="center" className="pipelineViewer__statement" > - + - - {value} - + {value} ); } return ( - + {stylizedValue} ); @@ -49,4 +36,5 @@ export function Metric({ className, value, warning }) { Metric.propTypes = { className: PropTypes.string.isRequired, value: PropTypes.string.isRequired, + warning: PropTypes.bool, }; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/plugin_statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/plugin_statement.js index 34727ccc7adae..28d4ab89857e1 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/plugin_statement.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/plugin_statement.js @@ -16,13 +16,13 @@ import { formatMetric } from '../../../../lib/format_number'; import { Metric } from './metric'; function getInputStatementMetrics({ latestEventsPerSecond }) { - return [( + return [ - )]; + />, + ]; } function getProcessorStatementMetrics(processorVertex) { @@ -33,29 +33,28 @@ function getProcessorStatementMetrics(processorVertex) { } = processorVertex; return [ - ( - - ), - ( - - ), - ( - - ) + , + , + , ]; } @@ -66,45 +65,36 @@ function renderPluginStatementMetrics(pluginType, vertex) { } export function PluginStatement({ - statement: { - hasExplicitId, - id, - name, - pluginType, - vertex - }, - onShowVertexDetails + statement: { hasExplicitId, id, name, pluginType, vertex }, + onShowVertexDetails, }) { const statementMetrics = renderPluginStatementMetrics(pluginType, vertex); - const onNameButtonClick = () => { onShowVertexDetails(vertex); }; + const onNameButtonClick = () => { + onShowVertexDetails(vertex); + }; return ( - + {name} - { - hasExplicitId && + {hasExplicitId && ( - } + )} - { - statementMetrics && + {statementMetrics && ( - - {statementMetrics} - + {statementMetrics} - } + )} ); } PluginStatement.propTypes = { + onShowVertexDetails: PropTypes.func.isRequired, statement: PropTypes.shape({ hasExplicitId: PropTypes.bool.isRequired, id: PropTypes.string.isRequired, name: PropTypes.string.isRequired, pluginType: PropTypes.string.isRequired, - vertex: PropTypes.object.isRequired, + vertex: PropTypes.shape({ + latestEventsPerSecond: PropTypes.number.isRequired, + latestMillisPerEvent: PropTypes.number, + percentOfTotalProcessorTime: PropTypes.number, + }).isRequired, }).isRequired, - onShowVertexDetails: PropTypes.func.isRequired, }; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/queue.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/queue.js index 79a6995670eec..d384b67fc34c4 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/queue.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/queue.js @@ -11,10 +11,7 @@ import { EuiSpacer, EuiText } from '@elastic/eui'; export function Queue() { return (
    - + Queue metrics not available diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement.js index 0b231b7b00799..dc281bead4cda 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement.js @@ -6,10 +6,7 @@ import React from 'react'; import PropTypes from 'prop-types'; -import { - EuiButtonEmpty, - EuiCodeBlock, - EuiFlexItem } from '@elastic/eui'; +import { EuiButtonEmpty, EuiCodeBlock, EuiFlexItem } from '@elastic/eui'; import { PluginStatement as PluginStatementModel } from '../models/pipeline/plugin_statement'; import { CollapsibleStatement } from './collapsible_statement'; import { IfElement } from '../models/list/if_element'; @@ -17,10 +14,7 @@ import { PluginStatement } from './plugin_statement'; function renderStatementName(name, onVertexSelected) { return ( - + + - - {condition} - - - ) + {condition} + + , ]; } -function getStatementBody( - isIf, - statement, - vertex, - onShowVertexDetails -) { - const showVertexDetailsClicked = () => { onShowVertexDetails(vertex); }; +function getStatementBody(isIf, statement, vertex, onShowVertexDetails) { + const showVertexDetailsClicked = () => { + onShowVertexDetails(vertex); + }; return isIf ? renderIfStatement(statement, showVertexDetailsClicked) @@ -69,7 +55,9 @@ function getStatementBody( function renderNestingSpacers(depth) { const spacers = []; for (let i = 0; i < depth; i += 1) { - spacers.push(
    ); + spacers.push( +
    + ); } return spacers; } @@ -80,11 +68,11 @@ function renderStatement({ element: { id, statement, - statement: { vertex } + statement: { vertex }, }, expand, isCollapsed, - onShowVertexDetails + onShowVertexDetails, }) { if (statement instanceof PluginStatementModel) { return ( @@ -132,9 +120,9 @@ Statement.propTypes = { element: PropTypes.shape({ depth: PropTypes.number.isRequired, id: PropTypes.string.isRequired, - statement: PropTypes.object.isRequired + statement: PropTypes.object.isRequired, }).isRequired, expand: PropTypes.func.isRequired, isCollapsed: PropTypes.bool.isRequired, - onShowVertexDetails: PropTypes.func.isRequired + onShowVertexDetails: PropTypes.func.isRequired, }; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list.js new file mode 100644 index 0000000000000..6c84ab59dff57 --- /dev/null +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_list.js @@ -0,0 +1,93 @@ +/* + * 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 PropTypes from 'prop-types'; + +import { Statement } from './statement'; + +function getCollapsedChildIds(elements, collapsedIds) { + const collapsedChildIds = new Set(); + elements.forEach(({ id, parentId }) => { + if (collapsedIds.has(parentId) || collapsedChildIds.has(parentId)) { + collapsedChildIds.add(id); + } + }); + return collapsedChildIds; +} + +export class StatementList extends React.PureComponent { + constructor(props) { + super(props); + + this.state = { + collapsedIds: new Set(), + collapsedChildIds: new Set(), + }; + } + + expand = elementId => { + const collapsedIds = new Set(this.state.collapsedIds); + collapsedIds.delete(elementId); + this.updateCollapsedElement(collapsedIds); + }; + + collapse = elementId => { + const collapsedIds = new Set(this.state.collapsedIds); + collapsedIds.add(elementId); + this.updateCollapsedElement(collapsedIds); + }; + + updateCollapsedElement = collapsedIds => { + const { elements } = this.props; + const collapsedChildIds = getCollapsedChildIds(elements, collapsedIds); + + this.setState({ + collapsedIds, + collapsedChildIds, + }); + }; + + elementIsCollapsed = elementId => this.state.collapsedIds.has(elementId); + + renderStatement = element => { + const { id, parentId } = element; + const { onShowVertexDetails } = this.props; + + return this.state.collapsedIds.has(parentId) || + this.state.collapsedChildIds.has(parentId) ? null : ( + + ); + }; + + render() { + const { elements } = this.props; + + return ( +
      + {elements.map(this.renderStatement)} +
    + ); + } +} + +StatementList.propTypes = { + elements: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + // top-level elements have null parentId + parentId: PropTypes.string, + }) + ).isRequired, + onShowVertexDetails: PropTypes.func.isRequired, +}; diff --git a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_section.js b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_section.js index 57cdf164c12be..0bf9a50791d8a 100644 --- a/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_section.js +++ b/x-pack/plugins/monitoring/public/components/logstash/pipeline_viewer/views/statement_section.js @@ -7,23 +7,22 @@ import React from 'react'; import PropTypes from 'prop-types'; import { StatementListHeading } from './statement_list_heading'; -import { Statement } from './statement'; import { EuiSpacer } from '@elastic/eui'; +import { StatementList } from './statement_list'; export function StatementSection({ iconType, headingText, elements, - onShowVertexDetails + onShowVertexDetails, }) { - if (!elements.length) { return null; } + if (!elements.length) { + return null; + } return (
    - + { - if (collapsedIds.has(parentId) || collapsedChildIds.has(parentId)) { - collapsedChildIds.add(id); - } - }); - return collapsedChildIds; -} - -class StatementList extends React.PureComponent { - constructor(props) { - super(props); - - this.state = { - collapsedIds: new Set(), - collapsedChildIds: new Set() - }; - } - - expand = elementId => { - const collapsedIds = new Set(this.state.collapsedIds); - collapsedIds.delete(elementId); - this.updateCollapsedElement(collapsedIds); - } - - collapse = elementId => { - const collapsedIds = new Set(this.state.collapsedIds); - collapsedIds.add(elementId); - this.updateCollapsedElement(collapsedIds); - } - - updateCollapsedElement = collapsedIds => { - const { elements } = this.props; - const collapsedChildIds = getCollapsedChildIds(elements, collapsedIds); - - this.setState({ - collapsedIds, - collapsedChildIds - }); - } - - elementIsCollapsed = elementId => this.state.collapsedIds.has(elementId); - - renderStatement = element => { - const { id, parentId } = element; - const { onShowVertexDetails } = this.props; - - return this.state.collapsedIds.has(parentId) || this.state.collapsedChildIds.has(parentId) - ? null - : ( - - ); - } - - render() { - const { elements } = this.props; - - return ( -
      - { - elements.map(this.renderStatement) - } -
    - ); - } -} - -StatementList.propTypes = { +StatementSection.propTypes = { elements: PropTypes.arrayOf( PropTypes.shape({ id: PropTypes.string.isRequired, // top-level elements have null parentId - parentId: PropTypes.string + parentId: PropTypes.string, }) ).isRequired, + headingText: PropTypes.string.isRequired, + iconType: PropTypes.string.isRequired, onShowVertexDetails: PropTypes.func.isRequired, };