diff --git a/src/dev/jest/config.js b/src/dev/jest/config.js index 9321336f0f55e..19251ffb0e566 100644 --- a/src/dev/jest/config.js +++ b/src/dev/jest/config.js @@ -58,6 +58,7 @@ export default { '^ui/(.*)': '/src/legacy/ui/public/$1', '^uiExports/(.*)': '/src/dev/jest/mocks/file_mock.js', '^test_utils/(.*)': '/src/test_utils/public/$1', + '^fixtures/(.*)': '/src/fixtures/$1', '\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '/src/dev/jest/mocks/file_mock.js', '\\.(css|less|scss)$': '/src/dev/jest/mocks/style_mock.js', diff --git a/src/legacy/core_plugins/vis_type_metric/public/__snapshots__/metric_vis_fn.test.ts.snap b/src/legacy/core_plugins/vis_type_metric/public/__snapshots__/metric_vis_fn.test.ts.snap index d0fba4d164dbf..44414cedf966a 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/__snapshots__/metric_vis_fn.test.ts.snap +++ b/src/legacy/core_plugins/vis_type_metric/public/__snapshots__/metric_vis_fn.test.ts.snap @@ -13,7 +13,7 @@ Object { "metrics": undefined, }, "metric": Object { - "colorSchema": "\\"Green to Red\\"", + "colorSchema": "Green to Red", "colorsRange": "{range from=0 to=10000}", "invertColors": false, "labels": Object { diff --git a/src/legacy/core_plugins/vis_type_metric/public/__tests__/metric_vis.js b/src/legacy/core_plugins/vis_type_metric/public/__tests__/metric_vis.js deleted file mode 100644 index f4786123f7b9d..0000000000000 --- a/src/legacy/core_plugins/vis_type_metric/public/__tests__/metric_vis.js +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import $ from 'jquery'; -import ngMock from 'ng_mock'; -import expect from '@kbn/expect'; - -import { Vis } from 'ui/vis'; -import LogstashIndexPatternStubProvider from 'fixtures/stubbed_logstash_index_pattern'; - -import { start as visualizations } from '../../../visualizations/public/np_ready/public/legacy'; - -describe('metric_vis - createMetricVisTypeDefinition', () => { - let setup = null; - let vis; - - beforeEach(ngMock.module('kibana')); - beforeEach( - ngMock.inject(Private => { - setup = () => { - const metricVisType = visualizations.types.get('metric'); - const indexPattern = Private(LogstashIndexPatternStubProvider); - - indexPattern.stubSetFieldFormat('ip', 'url', { - urlTemplate: 'http://ip.info?address={{value}}', - labelTemplate: 'ip[{{value}}]', - }); - - vis = new Vis(indexPattern, { - type: 'metric', - aggs: [{ id: '1', type: 'top_hits', schema: 'metric', params: { field: 'ip' } }], - }); - - vis.params.dimensions = { - metrics: [ - { - accessor: 0, - format: { - id: 'url', - params: { - urlTemplate: 'http://ip.info?address={{value}}', - labelTemplate: 'ip[{{value}}]', - }, - }, - }, - ], - }; - - const el = document.createElement('div'); - const Controller = metricVisType.visualization; - const controller = new Controller(el, vis); - const render = esResponse => { - controller.render(esResponse, vis.params); - }; - - return { el, render }; - }; - }) - ); - - it('renders html value from field formatter', () => { - const { el, render } = setup(); - - const ip = '235.195.237.208'; - render({ - columns: [{ id: 'col-0', name: 'ip' }], - rows: [{ 'col-0': ip }], - }); - - const $link = $(el) - .find('a[href]') - .filter(function() { - return this.href.includes('ip.info'); - }); - - expect($link).to.have.length(1); - expect($link.text()).to.be(`ip[${ip}]`); - }); -}); diff --git a/src/legacy/core_plugins/vis_type_metric/public/__tests__/metric_vis_controller.js b/src/legacy/core_plugins/vis_type_metric/public/__tests__/metric_vis_controller.js deleted file mode 100644 index 367c5f4699937..0000000000000 --- a/src/legacy/core_plugins/vis_type_metric/public/__tests__/metric_vis_controller.js +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import expect from '@kbn/expect'; -import { MetricVisComponent } from '../components/metric_vis_controller'; - -describe('metric_vis - controller', function() { - const vis = { - params: { - metric: { - colorSchema: 'Green to Red', - colorsRange: [{ from: 0, to: 1000 }], - style: {}, - }, - dimensions: { - metrics: [{ accessor: 0 }], - bucket: null, - }, - }, - }; - - let metricController; - - beforeEach(() => { - metricController = new MetricVisComponent({ vis: vis, visParams: vis.params }); - }); - - it('should set the metric label and value', function() { - const metrics = metricController._processTableGroups({ - columns: [{ id: 'col-0', name: 'Count' }], - rows: [{ 'col-0': 4301021 }], - }); - - expect(metrics.length).to.be(1); - expect(metrics[0].label).to.be('Count'); - expect(metrics[0].value).to.be('4301021'); - }); - - it('should support multi-value metrics', function() { - vis.params.dimensions.metrics.push({ accessor: 1 }); - const metrics = metricController._processTableGroups({ - columns: [ - { id: 'col-0', name: '1st percentile of bytes' }, - { id: 'col-1', name: '99th percentile of bytes' }, - ], - rows: [{ 'col-0': 182, 'col-1': 445842.4634666484 }], - }); - - expect(metrics.length).to.be(2); - expect(metrics[0].label).to.be('1st percentile of bytes'); - expect(metrics[0].value).to.be('182'); - expect(metrics[1].label).to.be('99th percentile of bytes'); - expect(metrics[1].value).to.be('445842.4634666484'); - }); -}); diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/__snapshots__/metric_vis_component.test.tsx.snap b/src/legacy/core_plugins/vis_type_metric/public/components/__snapshots__/metric_vis_component.test.tsx.snap new file mode 100644 index 0000000000000..d84424cc6179a --- /dev/null +++ b/src/legacy/core_plugins/vis_type_metric/public/components/__snapshots__/metric_vis_component.test.tsx.snap @@ -0,0 +1,57 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`MetricVisComponent should render correct structure for single metric 1`] = ` +
+ 4301021", + } + } + showLabel={true} + /> +
+`; + +exports[`MetricVisComponent should render correct structure for multi-value metrics 1`] = ` +
+ 182", + } + } + showLabel={true} + /> + 445842.4634666484", + } + } + showLabel={true} + /> +
+`; diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx new file mode 100644 index 0000000000000..901273ccbeb95 --- /dev/null +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx @@ -0,0 +1,93 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { shallow } from 'enzyme'; + +import { MetricVisComponent } from './metric_vis_component'; +import { Vis } from '../legacy_imports'; + +jest.mock('ui/new_platform'); + +type Props = MetricVisComponent['props']; + +const baseVisData = { + columns: [{ id: 'col-0', name: 'Count' }], + rows: [{ 'col-0': 4301021 }], +} as any; + +describe('MetricVisComponent', function() { + const vis: Vis = { + params: { + metric: { + colorSchema: 'Green to Red', + colorsRange: [{ from: 0, to: 1000 }], + style: {}, + labels: { + show: true, + }, + }, + dimensions: { + metrics: [{ accessor: 0 }], + bucket: null, + }, + }, + } as any; + + const getComponent = (propOverrides: Partial = {} as Partial) => { + const props: Props = { + vis, + visParams: vis.params, + visData: baseVisData, + renderComplete: jest.fn(), + ...propOverrides, + }; + + return shallow(); + }; + + it('should render component', () => { + expect(getComponent().exists()).toBe(true); + }); + + it('should render correct structure for single metric', function() { + expect(getComponent()).toMatchSnapshot(); + }); + + it('should render correct structure for multi-value metrics', function() { + const component = getComponent({ + visData: { + columns: [ + { id: 'col-0', name: '1st percentile of bytes' }, + { id: 'col-1', name: '99th percentile of bytes' }, + ], + rows: [{ 'col-0': 182, 'col-1': 445842.4634666484 }], + }, + visParams: { + ...vis.params, + dimensions: { + ...vis.params.dimensions, + metrics: [{ accessor: 0 }, { accessor: 1 }], + }, + }, + } as any); + + expect(component).toMatchSnapshot(); + }); +}); diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_controller.js b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx similarity index 64% rename from src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_controller.js rename to src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx index 17dad6a4cd8cb..f8398f5c83146 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_controller.js +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx @@ -19,20 +19,33 @@ import { last, findIndex, isNaN } from 'lodash'; import React, { Component } from 'react'; + import { isColorDark } from '@elastic/eui'; -import { getHeatmapColors } from 'ui/color_maps'; -import { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; +import { getHeatmapColors, getFormat, Vis } from '../legacy_imports'; import { MetricVisValue } from './metric_vis_value'; +import { FieldFormat, ContentType } from '../../../../../plugins/data/public'; +import { Context } from '../metric_vis_fn'; +import { KibanaDatatable } from '../../../../../plugins/expressions/public'; +import { VisParams, MetricVisMetric } from '../types'; +import { SchemaConfig } from '../../../visualizations/public'; + +interface MetricVisComponentProps { + visParams: VisParams; + visData: Context; + vis: Vis; + renderComplete: () => void; +} -export class MetricVisComponent extends Component { - _getLabels() { +export class MetricVisComponent extends Component { + private getLabels() { const config = this.props.visParams.metric; const isPercentageMode = config.percentageMode; const colorsRange = config.colorsRange; const max = last(colorsRange).to; - const labels = []; - colorsRange.forEach(range => { + const labels: string[] = []; + + colorsRange.forEach((range: any) => { const from = isPercentageMode ? Math.round((100 * range.from) / max) : range.from; const to = isPercentageMode ? Math.round((100 * range.to) / max) : range.to; labels.push(`${from} - ${to}`); @@ -41,13 +54,13 @@ export class MetricVisComponent extends Component { return labels; } - _getColors() { + private getColors() { const config = this.props.visParams.metric; const invertColors = config.invertColors; const colorSchema = config.colorSchema; const colorsRange = config.colorsRange; - const labels = this._getLabels(); - const colors = {}; + const labels = this.getLabels(); + const colors: any = {}; for (let i = 0; i < labels.length; i += 1) { const divider = Math.max(colorsRange.length - 1, 1); const val = invertColors ? 1 - i / divider : i / divider; @@ -56,9 +69,9 @@ export class MetricVisComponent extends Component { return colors; } - _getBucket(val) { + private getBucket(val: number) { const config = this.props.visParams.metric; - let bucket = findIndex(config.colorsRange, range => { + let bucket = findIndex(config.colorsRange, (range: any) => { return range.from <= val && range.to > val; }); @@ -70,59 +83,65 @@ export class MetricVisComponent extends Component { return bucket; } - _getColor(val, labels, colors) { - const bucket = this._getBucket(val); + private getColor(val: number, labels: string[], colors: { [label: string]: string }) { + const bucket = this.getBucket(val); const label = labels[bucket]; return colors[label]; } - _needsLightText(bgColor) { - const color = /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(bgColor); - if (!color) { + private needsLightText(bgColor: string) { + const colors = /rgb\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)/.exec(bgColor); + if (!colors) { return false; } - return isColorDark(parseInt(color[1]), parseInt(color[2]), parseInt(color[3])); + + const [red, green, blue] = colors.slice(1).map(parseInt); + return isColorDark(red, green, blue); } - _getFormattedValue = (fieldFormatter, value, format = 'text') => { + private getFormattedValue = ( + fieldFormatter: FieldFormat, + value: any, + format: ContentType = 'text' + ) => { if (isNaN(value)) return '-'; return fieldFormatter.convert(value, format); }; - _processTableGroups(table) { + private processTableGroups(table: KibanaDatatable) { const config = this.props.visParams.metric; const dimensions = this.props.visParams.dimensions; const isPercentageMode = config.percentageMode; const min = config.colorsRange[0].from; const max = last(config.colorsRange).to; - const colors = this._getColors(); - const labels = this._getLabels(); - const metrics = []; + const colors = this.getColors(); + const labels = this.getLabels(); + const metrics: MetricVisMetric[] = []; - let bucketColumnId; - let bucketFormatter; + let bucketColumnId: string; + let bucketFormatter: FieldFormat; if (dimensions.bucket) { bucketColumnId = table.columns[dimensions.bucket.accessor].id; bucketFormatter = getFormat(dimensions.bucket.format); } - dimensions.metrics.forEach(metric => { + dimensions.metrics.forEach((metric: SchemaConfig) => { const columnIndex = metric.accessor; - const column = table.columns[columnIndex]; + const column = table?.columns[columnIndex]; const formatter = getFormat(metric.format); table.rows.forEach((row, rowIndex) => { let title = column.name; - let value = row[column.id]; - const color = this._getColor(value, labels, colors); + let value: any = row[column.id]; + const color = this.getColor(value, labels, colors); if (isPercentageMode) { value = (value - min) / (max - min); } - value = this._getFormattedValue(formatter, value, 'html'); + value = this.getFormattedValue(formatter, value, 'html'); if (bucketColumnId) { - const bucketValue = this._getFormattedValue(bucketFormatter, row[bucketColumnId]); + const bucketValue = this.getFormattedValue(bucketFormatter, row[bucketColumnId]); title = `${bucketValue} - ${title}`; } @@ -130,11 +149,11 @@ export class MetricVisComponent extends Component { metrics.push({ label: title, - value: value, - color: shouldColor && config.style.labelColor ? color : null, - bgColor: shouldColor && config.style.bgColor ? color : null, - lightText: shouldColor && config.style.bgColor && this._needsLightText(color), - rowIndex: rowIndex, + value, + color: shouldColor && config.style.labelColor ? color : undefined, + bgColor: shouldColor && config.style.bgColor ? color : undefined, + lightText: shouldColor && config.style.bgColor && this.needsLightText(color), + rowIndex, }); }); }); @@ -142,7 +161,7 @@ export class MetricVisComponent extends Component { return metrics; } - _filterBucket = metric => { + private filterBucket = (metric: MetricVisMetric) => { const dimensions = this.props.visParams.dimensions; if (!dimensions.bucket) { return; @@ -155,27 +174,18 @@ export class MetricVisComponent extends Component { }); }; - _renderMetric = (metric, index) => { + private renderMetric = (metric: MetricVisMetric, index: number) => { return ( ); }; - render() { - let metricsHtml; - if (this.props.visData) { - const metrics = this._processTableGroups(this.props.visData); - metricsHtml = metrics.map(this._renderMetric); - } - return
{metricsHtml}
; - } - componentDidMount() { this.props.renderComplete(); } @@ -183,4 +193,13 @@ export class MetricVisComponent extends Component { componentDidUpdate() { this.props.renderComplete(); } + + render() { + let metricsHtml; + if (this.props.visData) { + const metrics = this.processTableGroups(this.props.visData); + metricsHtml = metrics.map(this.renderMetric); + } + return
{metricsHtml}
; + } } diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx index 566618c527019..032f66d92624c 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx @@ -29,7 +29,7 @@ import { import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; -import { VisOptionsProps } from 'ui/vis/editors/default'; +import { VisOptionsProps } from '../legacy_imports'; import { ColorRanges, ColorSchemaOptions, @@ -39,6 +39,7 @@ import { } from '../../../vis_type_vislib/public/components'; import { ColorModes } from '../../../vis_type_vislib/public/utils/collections'; import { MetricVisParam, VisParams } from '../types'; +import { SetColorRangeValue } from '../../../vis_type_vislib/public/components/common/color_ranges'; function MetricVisOptions({ stateParams, @@ -135,7 +136,7 @@ function MetricVisOptions({ diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.test.js b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.test.tsx similarity index 76% rename from src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.test.js rename to src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.test.tsx index 2fc436cb829bd..2ee80e92f129b 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.test.js +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.test.tsx @@ -21,34 +21,32 @@ import { shallow } from 'enzyme'; import { MetricVisValue } from './metric_vis_value'; +const baseMetric = { label: 'Foo', value: 'foo' } as any; + describe('MetricVisValue', () => { it('should be wrapped in EuiKeyboardAccessible if having a click listener', () => { const component = shallow( - {}} /> + {}} /> ); expect(component.find('EuiKeyboardAccessible').exists()).toBe(true); }); it('should not be wrapped in EuiKeyboardAccessible without having a click listener', () => { - const component = shallow( - - ); + const component = shallow(); expect(component.find('EuiKeyboardAccessible').exists()).toBe(false); }); it('should add -isfilterable class if onFilter is provided', () => { const onFilter = jest.fn(); const component = shallow( - + ); component.simulate('click'); expect(component.find('.mtrVis__container-isfilterable')).toHaveLength(1); }); it('should not add -isfilterable class if onFilter is not provided', () => { - const component = shallow( - - ); + const component = shallow(); component.simulate('click'); expect(component.find('.mtrVis__container-isfilterable')).toHaveLength(0); }); @@ -56,9 +54,9 @@ describe('MetricVisValue', () => { it('should call onFilter callback if provided', () => { const onFilter = jest.fn(); const component = shallow( - + ); component.find('.mtrVis__container-isfilterable').simulate('click'); - expect(onFilter).toHaveBeenCalledWith({ label: 'Foo', value: 'foo' }); + expect(onFilter).toHaveBeenCalledWith(baseMetric); }); }); diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.js b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.tsx similarity index 72% rename from src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.js rename to src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.tsx index 0776dd13a9868..79876377c8e44 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.js +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_value.tsx @@ -17,26 +17,36 @@ * under the License. */ -import React, { Component } from 'react'; -import PropTypes from 'prop-types'; +import React, { Component, KeyboardEvent } from 'react'; import classNames from 'classnames'; import { EuiKeyboardAccessible, keyCodes } from '@elastic/eui'; -class MetricVisValue extends Component { +import { MetricVisMetric } from '../types'; + +interface MetricVisValueProps { + metric: MetricVisMetric; + fontSize: number; + onFilter?: (metric: MetricVisMetric) => void; + showLabel?: boolean; +} + +export class MetricVisValue extends Component { onClick = () => { - this.props.onFilter(this.props.metric); + if (this.props.onFilter) { + this.props.onFilter(this.props.metric); + } }; - onKeyPress = e => { - if (e.keyCode === keyCodes.ENTER) { + onKeyPress = (event: KeyboardEvent) => { + if (event.keyCode === keyCodes.ENTER) { this.onClick(); } }; render() { const { fontSize, metric, onFilter, showLabel } = this.props; - const hasFilter = !!onFilter; + const hasFilter = Boolean(onFilter); const metricValueStyle = { fontSize: `${fontSize}pt`, @@ -52,10 +62,10 @@ class MetricVisValue extends Component {
{showLabel &&
{metric.label}
}
@@ -81,12 +91,3 @@ class MetricVisValue extends Component { return metricComponent; } } - -MetricVisValue.propTypes = { - fontSize: PropTypes.number.isRequired, - metric: PropTypes.object.isRequired, - onFilter: PropTypes.func, - showLabel: PropTypes.bool, -}; - -export { MetricVisValue }; diff --git a/src/legacy/core_plugins/vis_type_metric/public/legacy_imports.ts b/src/legacy/core_plugins/vis_type_metric/public/legacy_imports.ts new file mode 100644 index 0000000000000..93dfd76e16b16 --- /dev/null +++ b/src/legacy/core_plugins/vis_type_metric/public/legacy_imports.ts @@ -0,0 +1,27 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +export { Vis, VisParams } from 'ui/vis'; +export { vislibColorMaps, colorSchemas, ColorSchemas } from 'ui/color_maps'; +export { getHeatmapColors } from 'ui/color_maps'; +export { getFormat } from 'ui/visualize/loader/pipeline_helpers/utilities'; +export { VisOptionsProps } from 'ui/vis/editors/default'; +// @ts-ignore +export { Schemas } from 'ui/vis/editors/default/schemas'; +export { AggGroupNames } from 'ui/vis/editors/default'; diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts index 04bff5ccb4655..45110ca113003 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_fn.ts @@ -19,7 +19,7 @@ import { i18n } from '@kbn/i18n'; -import { vislibColorMaps, ColorSchemas } from 'ui/color_maps'; +import { vislibColorMaps, ColorSchemas } from './legacy_imports'; import { ExpressionFunction, KibanaDatatable, @@ -30,13 +30,13 @@ import { import { ColorModes } from '../../vis_type_vislib/public/utils/collections'; import { visType, DimensionsVisParam, VisParams } from './types'; -type Context = KibanaDatatable; +export type Context = KibanaDatatable; const name = 'metricVis'; interface Arguments { - percentage: boolean; - colorScheme: ColorSchemas; + percentageMode: boolean; + colorSchema: ColorSchemas; colorMode: ColorModes; useRanges: boolean; invertColors: boolean; @@ -73,19 +73,19 @@ export const createMetricVisFn = (): ExpressionFunction< defaultMessage: 'Metric visualization', }), args: { - percentage: { + percentageMode: { types: ['boolean'], default: false, - help: i18n.translate('visTypeMetric.function.percentage.help', { + help: i18n.translate('visTypeMetric.function.percentageMode.help', { defaultMessage: 'Shows metric in percentage mode. Requires colorRange to be set.', }), }, - colorScheme: { + colorSchema: { types: ['string'], default: '"Green to Red"', options: Object.values(vislibColorMaps).map((value: any) => value.id), - help: i18n.translate('visTypeMetric.function.colorScheme.help', { - defaultMessage: 'Color scheme to use', + help: i18n.translate('visTypeMetric.function.colorSchema.help', { + defaultMessage: 'Color schema to use', }), }, colorMode: { @@ -174,8 +174,8 @@ export const createMetricVisFn = (): ExpressionFunction< dimensions.bucket = args.bucket; } - if (args.percentage && (!args.colorRange || args.colorRange.length === 0)) { - throw new Error('colorRange must be provided when using percentage'); + if (args.percentageMode && (!args.colorRange || args.colorRange.length === 0)) { + throw new Error('colorRange must be provided when using percentageMode'); } const fontSize = Number.parseInt(args.font.spec.fontSize || '', 10); @@ -188,9 +188,9 @@ export const createMetricVisFn = (): ExpressionFunction< visType, visConfig: { metric: { - percentageMode: args.percentage, + percentageMode: args.percentageMode, useRanges: args.useRanges, - colorSchema: args.colorScheme, + colorSchema: args.colorSchema, metricColorMode: args.colorMode, colorsRange: args.colorRange, labels: { diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts new file mode 100644 index 0000000000000..649959054416c --- /dev/null +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts @@ -0,0 +1,106 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import $ from 'jquery'; + +import { npStart } from 'ui/new_platform'; +// @ts-ignore +import getStubIndexPattern from 'fixtures/stubbed_logstash_index_pattern'; + +import { Vis } from '../../visualizations/public'; +import { UrlFormat } from '../../../../plugins/data/public'; +import { + setup as visualizationsSetup, + start as visualizationsStart, +} from '../../visualizations/public/np_ready/public/legacy'; +import { metricVisTypeDefinition } from './metric_vis_type'; + +jest.mock('ui/new_platform'); + +describe('metric_vis - createMetricVisTypeDefinition', () => { + let vis: Vis; + + beforeAll(() => { + visualizationsSetup.types.createReactVisualization(metricVisTypeDefinition); + (npStart.plugins.data.fieldFormats.getType as jest.Mock).mockImplementation(() => { + return UrlFormat; + }); + }); + + const setup = () => { + const stubIndexPattern = getStubIndexPattern(); + + stubIndexPattern.stubSetFieldFormat('ip', 'url', { + urlTemplate: 'http://ip.info?address={{value}}', + labelTemplate: 'ip[{{value}}]', + }); + + // TODO: remove when Vis is converted to typescript. Only importing Vis as type + // @ts-ignore + vis = new Vis(stubIndexPattern, { + type: 'metric', + aggs: [{ id: '1', type: 'top_hits', schema: 'metric', params: { field: 'ip' } }], + }); + + vis.params.dimensions = { + metrics: [ + { + accessor: 0, + format: { + id: 'url', + params: { + urlTemplate: 'http://ip.info?address={{value}}', + labelTemplate: 'ip[{{value}}]', + }, + }, + }, + ], + }; + + const el = document.createElement('div'); + const metricVisType = visualizationsStart.types.get('metric'); + const Controller = metricVisType.visualization; + const controller = new Controller(el, vis); + const render = (esResponse: any) => { + controller.render(esResponse, vis.params); + }; + + return { el, render }; + }; + + it('renders html value from field formatter', () => { + const { el, render } = setup(); + + const ip = '235.195.237.208'; + render({ + columns: [{ id: 'col-0', name: 'ip' }], + rows: [{ 'col-0': ip }], + }); + + const links = $(el) + .find('a[href]') + .filter(function() { + // @ts-ignore + return this.href.includes('ip.info'); + }); + + expect(links.length).toBe(1); + expect(links.text()).toBe(`ip[${ip}]`); + }); +}); diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts index 9b22423012b36..0d9019ee0579c 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.ts @@ -19,19 +19,12 @@ import { i18n } from '@kbn/i18n'; -// @ts-ignore -import { Schemas } from 'ui/vis/editors/default/schemas'; - -import { AggGroupNames } from 'ui/vis/editors/default'; -import { colorSchemas, ColorSchemas } from 'ui/color_maps'; - -// @ts-ignore -import { MetricVisComponent } from './components/metric_vis_controller'; - +import { MetricVisComponent } from './components/metric_vis_component'; import { MetricVisOptions } from './components/metric_vis_options'; +import { Schemas, AggGroupNames, colorSchemas, ColorSchemas } from './legacy_imports'; import { ColorModes } from '../../vis_type_vislib/public/utils/collections'; -export const metricVisDefinition = { +export const metricVisTypeDefinition = { name: 'metric', title: i18n.translate('visTypeMetric.metricTitle', { defaultMessage: 'Metric' }), icon: 'visMetric', diff --git a/src/legacy/core_plugins/vis_type_metric/public/plugin.ts b/src/legacy/core_plugins/vis_type_metric/public/plugin.ts index f5c152ce888c0..413f846d78991 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/plugin.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/plugin.ts @@ -22,7 +22,7 @@ import { Plugin as ExpressionsPublicPlugin } from '../../../../plugins/expressio import { VisualizationsSetup } from '../../visualizations/public'; import { createMetricVisFn } from './metric_vis_fn'; -import { metricVisDefinition } from './metric_vis_type'; +import { metricVisTypeDefinition } from './metric_vis_type'; /** @internal */ export interface MetricVisPluginSetupDependencies { @@ -40,7 +40,7 @@ export class MetricVisPlugin implements Plugin { public setup(core: CoreSetup, { expressions, visualizations }: MetricVisPluginSetupDependencies) { expressions.registerFunction(createMetricVisFn); - visualizations.types.createReactVisualization(metricVisDefinition); + visualizations.types.createReactVisualization(metricVisTypeDefinition); } public start(core: CoreStart) { diff --git a/src/legacy/core_plugins/vis_type_metric/public/types.ts b/src/legacy/core_plugins/vis_type_metric/public/types.ts index 06ec509f8c4d3..71c1c12b4f8f0 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/types.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/types.ts @@ -17,8 +17,8 @@ * under the License. */ -import { ColorSchemas } from 'ui/color_maps'; -import { RangeValues } from 'ui/vis/editors/default/controls/ranges'; +import { ColorSchemas } from './legacy_imports'; +import { Range } from '../../../../plugins/expressions/public'; import { SchemaConfig } from '../../visualizations/public'; import { ColorModes } from '../../vis_type_vislib/public/utils/collections'; import { Labels, Style } from '../../vis_type_vislib/public/types'; @@ -27,7 +27,7 @@ export const visType = 'metric'; export interface DimensionsVisParam { metrics: SchemaConfig[]; - bucket?: SchemaConfig[]; + bucket?: SchemaConfig; } export interface MetricVisParam { @@ -35,7 +35,7 @@ export interface MetricVisParam { useRanges: boolean; colorSchema: ColorSchemas; metricColorMode: ColorModes; - colorsRange: RangeValues[]; + colorsRange: Range[]; labels: Labels; invertColors: boolean; style: Style; @@ -48,3 +48,12 @@ export interface VisParams { metric: MetricVisParam; type: typeof visType; } + +export interface MetricVisMetric { + value: any; + label: string; + color?: string; + bgColor?: string; + lightText: boolean; + rowIndex: number; +} diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_ranges.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_ranges.tsx index 2bf58de2f93ed..acbb93c8da189 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_ranges.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_ranges.tsx @@ -24,10 +24,12 @@ import { i18n } from '@kbn/i18n'; import { RangeValues, RangesParamEditor } from '../../legacy_imports'; +export type SetColorRangeValue = (paramName: string, value: RangeValues[]) => void; + interface ColorRangesProps { 'data-test-subj'?: string; colorsRange: RangeValues[]; - setValue(paramName: string, value: RangeValues[]): void; + setValue: SetColorRangeValue; setValidity?(isValid: boolean): void; setTouched?(isTouched: boolean): void; } diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx index 71ffb22243a0f..b54d9a5703fcd 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx @@ -27,6 +27,7 @@ import { ColorRanges, ColorSchemaOptions, SwitchOption } from '../../common'; import { GaugeOptionsInternalProps } from '.'; import { ColorSchemaVislibParams } from '../../../types'; import { Gauge } from '../../../gauge'; +import { SetColorRangeValue } from '../../common/color_ranges'; function RangesPanel({ setGaugeValue, @@ -68,7 +69,7 @@ function RangesPanel({ diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx index 7ce38fdcda1c8..d8ca7acda7cbc 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx @@ -36,6 +36,7 @@ import { SetColorSchemaOptionsValue } from '../../common/color_schema'; import { HeatmapVisParams } from '../../../heatmap'; import { ValueAxis } from '../../../types'; import { LabelsPanel } from './labels_panel'; +import { SetColorRangeValue } from '../../common/color_ranges'; function HeatmapOptions(props: VisOptionsProps) { const { stateParams, vis, uiState, setValue, setValidity, setTouched } = props; @@ -171,7 +172,7 @@ function HeatmapOptions(props: VisOptionsProps) { diff --git a/src/legacy/core_plugins/vis_type_vislib/public/index.ts b/src/legacy/core_plugins/vis_type_vislib/public/index.ts index 5abe79daf11fa..3b4bcb6bc3a7e 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/index.ts +++ b/src/legacy/core_plugins/vis_type_vislib/public/index.ts @@ -23,3 +23,5 @@ import { KbnVislibVisTypesPlugin as Plugin } from './plugin'; export function plugin(initializerContext: PluginInitializerContext) { return new Plugin(initializerContext); } + +export { ColorModes } from './utils/collections'; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__snapshots__/build_pipeline.test.ts.snap b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__snapshots__/build_pipeline.test.ts.snap index ddd74628e7940..90c1d4472d5ea 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__snapshots__/build_pipeline.test.ts.snap +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/__snapshots__/build_pipeline.test.ts.snap @@ -8,7 +8,7 @@ exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunct exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles metric function with buckets 1`] = `"metricvis metric={visdimension 0 } metric={visdimension 1 } "`; -exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles metric function with percentage mode should have percentage format 1`] = `"metricvis percentage=true metric={visdimension 0 format='percent' } "`; +exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles metric function with percentage mode should have percentage format 1`] = `"metricvis percentageMode=true metric={visdimension 0 format='percent' } "`; exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles metric function without buckets 1`] = `"metricvis metric={visdimension 0 } metric={visdimension 1 } "`; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts index ab1664d612b35..a3bf98b5e74a3 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts @@ -305,8 +305,8 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = { } let expr = `metricvis `; - expr += prepareValue('percentage', percentageMode); - expr += prepareValue('colorScheme', colorSchema); + expr += prepareValue('percentageMode', percentageMode); + expr += prepareValue('colorSchema', colorSchema); expr += prepareValue('colorMode', metricColorMode); expr += prepareValue('useRanges', useRanges); expr += prepareValue('invertColors', invertColors); diff --git a/test/interpreter_functional/screenshots/baseline/metric_percentage.png b/test/interpreter_functional/screenshots/baseline/metric_percentage_mode.png similarity index 100% rename from test/interpreter_functional/screenshots/baseline/metric_percentage.png rename to test/interpreter_functional/screenshots/baseline/metric_percentage_mode.png diff --git a/test/interpreter_functional/snapshots/baseline/metric_percentage.json b/test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json similarity index 100% rename from test/interpreter_functional/snapshots/baseline/metric_percentage.json rename to test/interpreter_functional/snapshots/baseline/metric_percentage_mode.json diff --git a/test/interpreter_functional/snapshots/session/metric_percentage.json b/test/interpreter_functional/snapshots/session/metric_percentage_mode.json similarity index 100% rename from test/interpreter_functional/snapshots/session/metric_percentage.json rename to test/interpreter_functional/snapshots/session/metric_percentage_mode.json diff --git a/test/interpreter_functional/test_suites/run_pipeline/metric.ts b/test/interpreter_functional/test_suites/run_pipeline/metric.ts index c238bedfa28ce..5f685037d4fad 100644 --- a/test/interpreter_functional/test_suites/run_pipeline/metric.ts +++ b/test/interpreter_functional/test_suites/run_pipeline/metric.ts @@ -81,11 +81,15 @@ export default function({ ).toMatchScreenshot(); }); - it('with percentage option', async () => { + it('with percentageMode option', async () => { const expression = - 'metricVis metric={visdimension 0} percentage=true colorRange={range from=0 to=1000}'; + 'metricVis metric={visdimension 0} percentageMode=true colorRange={range from=0 to=1000}'; await ( - await expectExpression('metric_percentage', expression, dataContext).toMatchSnapshot() + await expectExpression( + 'metric_percentage_mode', + expression, + dataContext + ).toMatchSnapshot() ).toMatchScreenshot(); }); }); diff --git a/tsconfig.json b/tsconfig.json index 8d9e2359ba97f..811b05abeb648 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,8 @@ ], "test_utils/*": [ "src/test_utils/public/*" - ] + ], + "fixtures/*": ["src/fixtures/*"] }, // Support .tsx files and transform JSX into calls to React.createElement "jsx": "react", diff --git a/x-pack/dev-tools/jest/create_jest_config.js b/x-pack/dev-tools/jest/create_jest_config.js index bcdf0e1c62119..ada8a8d725c0e 100644 --- a/x-pack/dev-tools/jest/create_jest_config.js +++ b/x-pack/dev-tools/jest/create_jest_config.js @@ -17,6 +17,7 @@ export function createJestConfig({ kibanaDirectory, xPackKibanaDirectory }) { moduleFileExtensions: ['js', 'json', 'ts', 'tsx'], moduleNameMapper: { '^ui/(.*)': `${kibanaDirectory}/src/legacy/ui/public/$1`, + '^fixtures/(.*)': `${kibanaDirectory}/src/fixtures/$1`, 'uiExports/(.*)': fileMockPath, '^src/core/(.*)': `${kibanaDirectory}/src/core/$1`, '^src/legacy/(.*)': `${kibanaDirectory}/src/legacy/$1`, diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 2686cf368f5c1..f1c2c2a6dd49f 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -3160,12 +3160,12 @@ "visTypeMetric.function.bucket.help": "バケットディメンションの構成です。", "visTypeMetric.function.colorMode.help": "色を変更するメトリックの部分", "visTypeMetric.function.colorRange.help": "別の色が適用される値のグループを指定する範囲オブジェクト。", - "visTypeMetric.function.colorScheme.help": "使用する配色", + "visTypeMetric.function.colorSchema.help": "使用する配色", "visTypeMetric.function.font.help": "フォント設定です。", "visTypeMetric.function.help": "メトリックビジュアライゼーション", "visTypeMetric.function.invertColors.help": "色範囲を反転します", "visTypeMetric.function.metric.help": "メトリックディメンションの構成です。", - "visTypeMetric.function.percentage.help": "パーセンテージモードでメトリックを表示します。colorRange を設定する必要があります。", + "visTypeMetric.function.percentageMode.help": "パーセンテージモードでメトリックを表示します。colorRange を設定する必要があります。", "visTypeMetric.function.showLabels.help": "メトリック値の下にラベルを表示します。", "visTypeMetric.function.subText.help": "メトリックの下に表示するカスタムテキスト", "visTypeMetric.function.useRanges.help": "有効な色範囲です。", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0b54844266442..d55b45225bea8 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -3160,12 +3160,12 @@ "visTypeMetric.function.bucket.help": "存储桶维度配置", "visTypeMetric.function.colorMode.help": "指标的哪部分要上色", "visTypeMetric.function.colorRange.help": "指定应将不同颜色应用到的值组的范围对象。", - "visTypeMetric.function.colorScheme.help": "要使用的颜色方案", + "visTypeMetric.function.colorSchema.help": "要使用的颜色方案", "visTypeMetric.function.font.help": "字体设置。", "visTypeMetric.function.help": "指标可视化", "visTypeMetric.function.invertColors.help": "反转颜色范围", "visTypeMetric.function.metric.help": "指标维度配置", - "visTypeMetric.function.percentage.help": "以百分比模式显示指标。需要设置 colorRange。", + "visTypeMetric.function.percentageMode.help": "以百分比模式显示指标。需要设置 colorRange。", "visTypeMetric.function.showLabels.help": "在指标值下显示标签。", "visTypeMetric.function.subText.help": "要在指标下显示的定制文本", "visTypeMetric.function.useRanges.help": "已启用颜色范围。", diff --git a/x-pack/tsconfig.json b/x-pack/tsconfig.json index 7070e3f5aa493..7d2933f9d9238 100644 --- a/x-pack/tsconfig.json +++ b/x-pack/tsconfig.json @@ -38,7 +38,8 @@ "monitoring/common/*": [ "x-pack/monitoring/common/*" ], - "plugins/*": ["src/legacy/core_plugins/*/public/"] + "plugins/*": ["src/legacy/core_plugins/*/public/"], + "fixtures/*": ["src/fixtures/*"] }, "types": [ "node",