From 3048b58158a8023d223351b5dd44d42b0bc57cb7 Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Mon, 1 Jul 2019 01:20:05 -0700 Subject: [PATCH 01/20] [discover] use elastic-charts for histogram --- package.json | 2 +- .../discover/components/histogram/_index.scss | 3 + .../components/histogram/directive.js | 28 + .../components/histogram/histogram.tsx | 264 ++++++++ .../discover/components/histogram/index.js | 20 + .../public/discover/controllers/discover.js | 24 +- .../kibana/public/discover/index.html | 11 +- src/legacy/ui/public/elastic_charts/index.ts | 26 + test/functional/apps/discover/_discover.js | 569 +++++++++--------- .../apps/management/_scripted_fields.js | 29 +- yarn.lock | 8 +- 11 files changed, 658 insertions(+), 326 deletions(-) create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/histogram/_index.scss create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/histogram/directive.js create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx create mode 100644 src/legacy/core_plugins/kibana/public/discover/components/histogram/index.js create mode 100644 src/legacy/ui/public/elastic_charts/index.ts diff --git a/package.json b/package.json index 2d4259d5d18516..a524202fb25aa8 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "@babel/core": "7.4.5", "@babel/polyfill": "7.4.4", "@babel/register": "7.4.4", - "@elastic/charts": "^7.2.1", + "@elastic/charts": "^8.1.1", "@elastic/datemath": "5.0.2", "@elastic/eui": "13.0.0", "@elastic/filesaver": "1.1.2", diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/_index.scss b/src/legacy/core_plugins/kibana/public/discover/components/histogram/_index.scss new file mode 100644 index 00000000000000..8baf8fa44d5bd8 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/histogram/_index.scss @@ -0,0 +1,3 @@ +.dscHistogram__header--partial { + font-weight: $euiFontWeightRegular; +} diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/directive.js b/src/legacy/core_plugins/kibana/public/discover/components/histogram/directive.js new file mode 100644 index 00000000000000..29b7c1d98a78da --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/histogram/directive.js @@ -0,0 +1,28 @@ +/* + * 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 'ngreact'; +import { uiModules } from 'ui/modules'; +import { DiscoverHistogram } from './histogram'; + +import { wrapInI18nContext } from 'ui/i18n'; + +const app = uiModules.get('apps/discover', ['react']); + +app.directive('discoverHistogram', reactDirective => reactDirective(wrapInI18nContext(DiscoverHistogram))); diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx new file mode 100644 index 00000000000000..d1381c7aae4579 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx @@ -0,0 +1,264 @@ +/* + * 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 { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; +import moment from 'moment-timezone'; +import React, { Component } from 'react'; +import PropTypes from 'prop-types'; + +import { + AnnotationDomainTypes, + Axis, + Chart, + HistogramBarSeries, + getAnnotationId, + getAxisId, + getSpecId, + LineAnnotation, + Position, + ScaleType, + Settings, + RectAnnotation, + TooltipValue, +} from '@elastic/charts'; + +import { i18n } from '@kbn/i18n'; + +import { getChartTheme } from 'ui/elastic_charts'; +import chrome from 'ui/chrome'; +// @ts-ignore: path dynamic for kibana +import { timezoneProvider } from 'ui/vis/lib/timezone'; + +export interface DiscoverHistogramProps { + chartData: any; + timefilterUpdateHandler: (ranges: { xaxis: { from: number; to: number } }) => void; +} + +export class DiscoverHistogram extends Component { + static propTypes = { + chartData: PropTypes.object, + timefilterUpdateHandler: PropTypes.func, + }; + + onBrushEnd = (min: number, max: number) => { + const range = { + xaxis: { + from: min, + to: max, + }, + }; + + this.props.timefilterUpdateHandler(range); + }; + + onElementClick = (xInterval: number) => (elementData: any) => { + const startRange = elementData[0].x; + + const range = { + xaxis: { + from: startRange, + to: startRange + xInterval, + }, + }; + + this.props.timefilterUpdateHandler(range); + }; + + formatXValue = (val: string) => { + const xAxisFormat = this.props.chartData.xAxisFormat.params.pattern; + + return moment(val).format(xAxisFormat); + }; + + renderRectAnnotationTooltip = (details?: string) => ( +
+ + + + + {details} + +
+ ); + + renderBarTooltip = (xInterval: number, domainStart: number, domainEnd: number) => ( + headerData: TooltipValue + ): JSX.Element | string => { + const headerDataValue = headerData.value; + const formattedValue = this.formatXValue(headerDataValue); + + const partialDataText = i18n.translate('kbn.discover.histogram.partialData.bucketTooltipText', { + defaultMessage: + 'Part of this bucket may contain partial data. The selected time range does not fully cover it.', + }); + + if (headerDataValue < domainStart || headerDataValue + xInterval > domainEnd) { + return ( + + + + + + {partialDataText} + + +

{formattedValue}

+
+ ); + } + + return formattedValue; + }; + + render() { + const uiSettings = chrome.getUiSettingsClient(); + const timeZone = timezoneProvider(uiSettings)(); + const { chartData } = this.props; + + if (!chartData || !chartData.series[0]) { + return null; + } + + const data = chartData.series[0].values; + + /** + * Deprecation: [interval] on [date_histogram] is deprecated, use [fixed_interval] or [calendar_interval]. + * see https://github.com/elastic/kibana/issues/27410 + * TODO: Once the Discover query has been update, we should change the below to use the new field + */ + const xInterval = chartData.ordered.interval; + + const xValues = chartData.xAxisOrderedValues; + const lastXValue = xValues[xValues.length - 1]; + + const domain = chartData.ordered; + const domainStart = domain.min.valueOf(); + const domainEnd = domain.max.valueOf(); + + const domainMin = data[0].x > domainStart ? domainStart : data[0].x; + const domainMax = domainEnd - xInterval > lastXValue ? domainEnd - xInterval : lastXValue; + + const xDomain = { + min: domainMin, + max: domainMax, + minInterval: xInterval, + }; + + // Domain end of 'now' will be milliseconds behind current time, so we extend time by 1 minute and check if + // the annotation is within this range; if so, the line annotation uses the domainEnd as its value + const now = moment(); + const isAnnotationAtEdge = domainEnd + 60000 > now && now > domainEnd; + const lineAnnotationValue = isAnnotationAtEdge ? domainEnd : now; + + const lineAnnotationData = [ + { + dataValue: lineAnnotationValue, + }, + ]; + + const lineAnnotationStyle = { + line: { + strokeWidth: 2, + stroke: '#c80000', + opacity: 0.3, + }, + }; + + const partialAnnotationText = i18n.translate( + 'kbn.discover.histogram.partialData.annotationText', + { + defaultMessage: + 'This area may contain partial data. The selected time range does not fully cover it.', + } + ); + + const rectAnnotations = [ + { + coordinates: { + x0: domainStart, + }, + details: partialAnnotationText, + }, + { + coordinates: { + x1: domainEnd, + }, + details: partialAnnotationText, + }, + ]; + + const rectAnnotationStyle = { + stroke: 'rgba(0, 0, 0, 0)', + strokeWidth: 1, + opacity: 1, + fill: 'rgba(0, 0, 0, 0.1)', + }; + + const tooltipProps = { + headerFormatter: this.renderBarTooltip(xInterval, domainStart, domainEnd), + }; + + return ( + + + + + + + + + ); + } +} diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/index.js b/src/legacy/core_plugins/kibana/public/discover/components/histogram/index.js new file mode 100644 index 00000000000000..b8fdf067296409 --- /dev/null +++ b/src/legacy/core_plugins/kibana/public/discover/components/histogram/index.js @@ -0,0 +1,20 @@ +/* + * 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 './directive'; diff --git a/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js b/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js index c38652aa8805e4..b938bcb01a38eb 100644 --- a/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js @@ -53,10 +53,10 @@ import { migrateLegacyQuery } from 'ui/utils/migrate_legacy_query'; import { subscribeWithScope } from 'ui/utils/subscribe_with_scope'; import { getFilterGenerator } from 'ui/filter_manager'; import { SavedObjectsClientProvider } from 'ui/saved_objects'; -import { VisualizeLoaderProvider } from 'ui/visualize/loader/visualize_loader'; import { recentlyAccessed } from 'ui/persisted_log'; import { getDocLink } from 'ui/documentation_links'; import '../components/fetch_error'; +import '../components/histogram'; import { getPainlessError } from './get_painless_error'; import { showShareContextMenu, ShareContextMenuExtensionsRegistryProvider } from 'ui/share'; import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing'; @@ -70,6 +70,7 @@ import { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_s import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../breadcrumbs'; import { buildVislibDimensions } from 'ui/visualize/loader/pipeline_helpers/build_pipeline'; import 'ui/capabilities/route_setup'; +import { brushHandler } from '../../../../metrics/public/lib/create_brush_handler'; const fetchStatuses = { UNINITIALIZED: 'uninitialized', @@ -190,8 +191,6 @@ function discoverController( localStorage, uiCapabilities ) { - const visualizeLoader = Private(VisualizeLoaderProvider); - let visualizeHandler; const Vis = Private(VisProvider); const responseHandler = vislibSeriesResponseHandlerProvider().handler; const getUnhashableStates = Private(getUnhashableStatesProvider); @@ -209,6 +208,7 @@ function discoverController( timefilter.disableTimeRangeSelector(); timefilter.disableAutoRefreshSelector(); + $scope.timefilterUpdateHandler = brushHandler(timefilter); $scope.getDocLink = getDocLink; $scope.intervalOptions = intervalOptions; @@ -539,6 +539,7 @@ function discoverController( $scope.updateDataSource() .then(function () { + $scope.$listen(timefilter, 'fetch', $scope.fetch); $scope.$listen(timefilter, 'autoRefreshFetch', $scope.fetch); $scope.$listen(timefilter, 'refreshIntervalUpdate', $scope.updateRefreshInterval); $scope.$listen(timefilter, 'timeUpdate', $scope.updateTime); @@ -743,15 +744,7 @@ function discoverController( .resolve(buildVislibDimensions($scope.vis, { timeRange: $scope.timeRange, searchSource: $scope.searchSource })) .then(resp => responseHandler(tabifiedData, resp)) .then(resp => { - visualizeHandler.render({ - as: 'visualization', - value: { - visType: $scope.vis.type.name, - visData: resp, - visConfig: $scope.vis.params, - params: {}, - } - }); + $scope.histogramData = resp; }); } @@ -927,13 +920,6 @@ function discoverController( $scope.searchSource.setField('aggs', function () { return $scope.vis.getAggConfig().toDsl(); }); - - $timeout(async () => { - const visEl = $element.find('#discoverHistogram')[0]; - visualizeHandler = await visualizeLoader.embedVisualizationWithSavedObject(visEl, visSavedObject, { - autoFetch: false, - }); - }); } function resolveIndexPatternLoading() { diff --git a/src/legacy/core_plugins/kibana/public/discover/index.html b/src/legacy/core_plugins/kibana/public/discover/index.html index e1cdcc3365bdfa..ec4c2176892d22 100644 --- a/src/legacy/core_plugins/kibana/public/discover/index.html +++ b/src/legacy/core_plugins/kibana/public/discover/index.html @@ -153,11 +153,14 @@ -
-
+ ng-show="vis && rows.length !== 0" + chart-data="histogramData" + timefilter-update-handler="timefilterUpdateHandler" + watch-depth="reference" + class="visualization" + >
= 5) { - throw new Error(`expected new duration of ${newDurationHours} hours to be between 1 and 5 hours`); - } - }); + // TODO: update these tests when elastic-charts can support integration tests + // it('should show bars in the correct time zone', async function () { + // const maxTicks = [ + // '2015-09-20 00:00', + // '2015-09-20 12:00', + // '2015-09-21 00:00', + // '2015-09-21 12:00', + // '2015-09-22 00:00', + // '2015-09-22 12:00', + // '2015-09-23 00:00', + // '2015-09-23 12:00' + // ]; + + // for (const tick of await PageObjects.discover.getBarChartXTicks()) { + // if (!maxTicks.includes(tick)) { + // throw new Error(`unexpected x-axis tick "${tick}"`); + // } + // } + // }); + + // it('should modify the time range when a bar is clicked', async function () { + // await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + // await PageObjects.visualize.waitForVisualization(); + // await PageObjects.discover.clickHistogramBar(0); + // await PageObjects.visualize.waitForVisualization(); + // const time = await PageObjects.timePicker.getTimeConfig(); + // expect(time.start).to.be('Sep 20, 2015 @ 00:00:00.000'); + // expect(time.end).to.be('Sep 20, 2015 @ 03:00:00.000'); + // }); + + // it('should modify the time range when the histogram is brushed', async function () { + // await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + // await PageObjects.visualize.waitForVisualization(); + // await PageObjects.discover.brushHistogram(0, 1); + // await PageObjects.visualize.waitForVisualization(); + + // const newDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); + // if (newDurationHours < 1 || newDurationHours >= 5) { + // throw new Error(`expected new duration of ${newDurationHours} hours to be between 1 and 5 hours`); + // } + // }); it('should show correct initial chart interval of Auto', async function () { await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); @@ -171,166 +173,167 @@ export default function ({ getService, getPageObjects }) { expect(actualInterval).to.be(expectedInterval); }); - it('should show correct data for chart interval Hourly', async function () { - await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); - await PageObjects.discover.setChartInterval('Hourly'); - - const expectedBarChartData = [ - 4, - 7, - 16, - 23, - 38, - 87, - 132, - 159, - 248, - 320, - 349, - 376, - 380, - 324, - 293, - 233, - 188, - 125, - 69, - 40, - 28, - 17, - 2, - 3, - 8, - 10, - 12, - 28, - 36, - 84, - 111, - 157, - 229, - 292, - 324, - 373, - 378, - 345, - 306, - 223, - 167, - 124, - 72, - 35, - 22, - 11, - 7, - 1, - 6, - 5, - 12, - 25, - 27, - 76, - 111, - 175, - 228, - 294, - 358, - 372, - 366, - 344, - 276, - 213, - 201, - 113, - 72, - 39, - 36, - 12, - 7, - 3, - ]; - await verifyChartData(expectedBarChartData); - }); - - it('should show correct data for chart interval Daily', async function () { - const chartInterval = 'Daily'; - const expectedBarChartData = [4757, 4614, 4633]; - await PageObjects.discover.setChartInterval(chartInterval); - await retry.try(async () => { - await verifyChartData(expectedBarChartData); - }); - }); - - it('should show correct data for chart interval Weekly', async function () { - const chartInterval = 'Weekly'; - const expectedBarChartData = [4757, 9247]; - - await PageObjects.discover.setChartInterval(chartInterval); - await retry.try(async () => { - await verifyChartData(expectedBarChartData); - }); - }); - - it('browser back button should show previous interval Daily', async function () { - const expectedChartInterval = 'Daily'; - const expectedBarChartData = [4757, 4614, 4633]; - - await browser.goBack(); - await retry.try(async function tryingForTime() { - const actualInterval = await PageObjects.discover.getChartInterval(); - expect(actualInterval).to.be(expectedChartInterval); - }); - await verifyChartData(expectedBarChartData); - }); - - it('should show correct data for chart interval Monthly', async function () { - const chartInterval = 'Monthly'; - const expectedBarChartData = [13129]; - - await PageObjects.discover.setChartInterval(chartInterval); - await verifyChartData(expectedBarChartData); - }); - - it('should show correct data for chart interval Yearly', async function () { - const chartInterval = 'Yearly'; - const expectedBarChartData = [13129]; - - await PageObjects.discover.setChartInterval(chartInterval); - await verifyChartData(expectedBarChartData); - }); - - it('should show correct data for chart interval Auto', async function () { - const chartInterval = 'Auto'; - const expectedBarChartData = [ - 35, - 189, - 694, - 1347, - 1285, - 704, - 176, - 29, - 39, - 189, - 640, - 1276, - 1327, - 663, - 166, - 25, - 30, - 164, - 663, - 1320, - 1270, - 681, - 188, - 27, - ]; - - await PageObjects.discover.setChartInterval(chartInterval); - await verifyChartData(expectedBarChartData); - }); + // TODO: update these test when elastic-charts can support integration tests + // it('should show correct data for chart interval Hourly', async function () { + // await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + // await PageObjects.discover.setChartInterval('Hourly'); + + // const expectedBarChartData = [ + // 4, + // 7, + // 16, + // 23, + // 38, + // 87, + // 132, + // 159, + // 248, + // 320, + // 349, + // 376, + // 380, + // 324, + // 293, + // 233, + // 188, + // 125, + // 69, + // 40, + // 28, + // 17, + // 2, + // 3, + // 8, + // 10, + // 12, + // 28, + // 36, + // 84, + // 111, + // 157, + // 229, + // 292, + // 324, + // 373, + // 378, + // 345, + // 306, + // 223, + // 167, + // 124, + // 72, + // 35, + // 22, + // 11, + // 7, + // 1, + // 6, + // 5, + // 12, + // 25, + // 27, + // 76, + // 111, + // 175, + // 228, + // 294, + // 358, + // 372, + // 366, + // 344, + // 276, + // 213, + // 201, + // 113, + // 72, + // 39, + // 36, + // 12, + // 7, + // 3, + // ]; + // await verifyChartData(expectedBarChartData); + // }); + + // it('should show correct data for chart interval Daily', async function () { + // const chartInterval = 'Daily'; + // const expectedBarChartData = [4757, 4614, 4633]; + // await PageObjects.discover.setChartInterval(chartInterval); + // await retry.try(async () => { + // await verifyChartData(expectedBarChartData); + // }); + // }); + + // it('should show correct data for chart interval Weekly', async function () { + // const chartInterval = 'Weekly'; + // const expectedBarChartData = [4757, 9247]; + + // await PageObjects.discover.setChartInterval(chartInterval); + // await retry.try(async () => { + // await verifyChartData(expectedBarChartData); + // }); + // }); + + // it('browser back button should show previous interval Daily', async function () { + // const expectedChartInterval = 'Daily'; + // const expectedBarChartData = [4757, 4614, 4633]; + + // await browser.goBack(); + // await retry.try(async function tryingForTime() { + // const actualInterval = await PageObjects.discover.getChartInterval(); + // expect(actualInterval).to.be(expectedChartInterval); + // }); + // await verifyChartData(expectedBarChartData); + // }); + + // it('should show correct data for chart interval Monthly', async function () { + // const chartInterval = 'Monthly'; + // const expectedBarChartData = [13129]; + + // await PageObjects.discover.setChartInterval(chartInterval); + // await verifyChartData(expectedBarChartData); + // }); + + // it('should show correct data for chart interval Yearly', async function () { + // const chartInterval = 'Yearly'; + // const expectedBarChartData = [13129]; + + // await PageObjects.discover.setChartInterval(chartInterval); + // await verifyChartData(expectedBarChartData); + // }); + + // it('should show correct data for chart interval Auto', async function () { + // const chartInterval = 'Auto'; + // const expectedBarChartData = [ + // 35, + // 189, + // 694, + // 1347, + // 1285, + // 704, + // 176, + // 29, + // 39, + // 189, + // 640, + // 1276, + // 1327, + // 663, + // 166, + // 25, + // 30, + // 164, + // 663, + // 1320, + // 1270, + // 681, + // 188, + // 27, + // ]; + + // await PageObjects.discover.setChartInterval(chartInterval); + // await verifyChartData(expectedBarChartData); + // }); it('should show Auto chart interval', async function () { const expectedChartInterval = 'Auto'; @@ -344,41 +347,42 @@ export default function ({ getService, getPageObjects }) { expect(isVisible).to.be(false); }); - async function verifyChartData(expectedBarChartData) { - await retry.try(async function tryingForTime() { - const paths = await PageObjects.discover.getBarChartData(); - // the largest bars are over 100 pixels high so this is less than 1% tolerance - const barHeightTolerance = 1; - let stringResults = ''; - let hasFailure = false; - for (let y = 0; y < expectedBarChartData.length; y++) { - stringResults += - y + - ': expected = ' + - expectedBarChartData[y] + - ', actual = ' + - paths[y] + - ', Pass = ' + - (Math.abs(expectedBarChartData[y] - paths[y]) < - barHeightTolerance) + - '\n'; - if ( - Math.abs(expectedBarChartData[y] - paths[y]) > barHeightTolerance - ) { - hasFailure = true; - } - } - if (hasFailure) { - log.debug(stringResults); - log.debug(paths); - } - for (let x = 0; x < expectedBarChartData.length; x++) { - expect( - Math.abs(expectedBarChartData[x] - paths[x]) < barHeightTolerance - ).to.be.ok(); - } - }); - } + // TODO: update this function when elastic-charts can support integration tests + // async function verifyChartData(expectedBarChartData) { + // await retry.try(async function tryingForTime() { + // const paths = await PageObjects.discover.getBarChartData(); + // // the largest bars are over 100 pixels high so this is less than 1% tolerance + // const barHeightTolerance = 1; + // let stringResults = ''; + // let hasFailure = false; + // for (let y = 0; y < expectedBarChartData.length; y++) { + // stringResults += + // y + + // ': expected = ' + + // expectedBarChartData[y] + + // ', actual = ' + + // paths[y] + + // ', Pass = ' + + // (Math.abs(expectedBarChartData[y] - paths[y]) < + // barHeightTolerance) + + // '\n'; + // if ( + // Math.abs(expectedBarChartData[y] - paths[y]) > barHeightTolerance + // ) { + // hasFailure = true; + // } + // } + // if (hasFailure) { + // log.debug(stringResults); + // log.debug(paths); + // } + // for (let x = 0; x < expectedBarChartData.length; x++) { + // expect( + // Math.abs(expectedBarChartData[x] - paths[x]) < barHeightTolerance + // ).to.be.ok(); + // } + // }); + // } }); describe('query #2, which has an empty time range', () => { @@ -443,24 +447,25 @@ export default function ({ getService, getPageObjects }) { await PageObjects.header.awaitKibanaChrome(); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - const maxTicks = [ - '2015-09-20 00:00', - '2015-09-20 12:00', - '2015-09-21 00:00', - '2015-09-21 12:00', - '2015-09-22 00:00', - '2015-09-22 12:00', - '2015-09-23 00:00', - '2015-09-23 12:00' - ]; - - await retry.try(async function () { - for (const tick of await PageObjects.discover.getBarChartXTicks()) { - if (!maxTicks.includes(tick)) { - throw new Error(`unexpected x-axis tick "${tick}"`); - } - } - }); + // TODO: update this test when elastic-charts can support integration tests + // const maxTicks = [ + // '2015-09-20 00:00', + // '2015-09-20 12:00', + // '2015-09-21 00:00', + // '2015-09-21 12:00', + // '2015-09-22 00:00', + // '2015-09-22 12:00', + // '2015-09-23 00:00', + // '2015-09-23 12:00' + // ]; + + // await retry.try(async function () { + // for (const tick of await PageObjects.discover.getBarChartXTicks()) { + // if (!maxTicks.includes(tick)) { + // throw new Error(`unexpected x-axis tick "${tick}"`); + // } + // } + // }); log.debug('check that the newest doc timestamp is now -7 hours from the UTC time in the first test'); const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData.startsWith('Sep 22, 2015 @ 16:50:13.253')).to.be.ok(); diff --git a/test/functional/apps/management/_scripted_fields.js b/test/functional/apps/management/_scripted_fields.js index ec3941264450de..32d410eb240408 100644 --- a/test/functional/apps/management/_scripted_fields.js +++ b/test/functional/apps/management/_scripted_fields.js @@ -129,13 +129,13 @@ export default function ({ getService, getPageObjects }) { const toTime = '2015-09-18 18:31:44.000'; await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName); await retry.try(async function () { await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName); }); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\n18'); @@ -147,7 +147,7 @@ export default function ({ getService, getPageObjects }) { await log.debug('filter by the first value (14) in the expanded scripted field list'); await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName, '14'); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { expect(await PageObjects.discover.getHitCount()).to.be('31'); }); @@ -161,7 +161,7 @@ export default function ({ getService, getPageObjects }) { await filterBar.removeAllFilters(); await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await inspector.open(); await inspector.setTablePageSize(50); await inspector.expectTableData(expectedChartValues); @@ -191,13 +191,13 @@ export default function ({ getService, getPageObjects }) { const toTime = '2015-09-18 18:31:44.000'; await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName2); }); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ngood'); @@ -210,7 +210,7 @@ export default function ({ getService, getPageObjects }) { await log.debug('filter by "bad" in the expanded scripted field list'); await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName2, 'bad'); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { expect(await PageObjects.discover.getHitCount()).to.be('27'); }); @@ -220,7 +220,6 @@ export default function ({ getService, getPageObjects }) { it('should visualize scripted field in vertical bar chart', async function () { await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); await inspector.open(); await inspector.expectTableData([ ['good', '359'], @@ -252,13 +251,13 @@ export default function ({ getService, getPageObjects }) { const toTime = '2015-09-18 18:31:44.000'; await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName2); }); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('Sep 18, 2015 @ 18:20:57.916\ntrue'); @@ -271,7 +270,7 @@ export default function ({ getService, getPageObjects }) { await log.debug('filter by "true" in the expanded scripted field list'); await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName2, 'true'); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { expect(await PageObjects.discover.getHitCount()).to.be('359'); }); @@ -281,7 +280,6 @@ export default function ({ getService, getPageObjects }) { it('should visualize scripted field in vertical bar chart', async function () { await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); await inspector.open(); await inspector.expectTableData([ ['true', '359'], @@ -314,13 +312,13 @@ export default function ({ getService, getPageObjects }) { const toTime = '2015-09-18 07:00:00.000'; await PageObjects.common.navigateToApp('discover'); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.clickFieldListItem(scriptedPainlessFieldName2); await retry.try(async function () { await PageObjects.discover.clickFieldListItemAdd(scriptedPainlessFieldName2); }); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData).to.be('Sep 18, 2015 @ 06:52:55.953\n2015-09-18 07:00'); @@ -332,7 +330,7 @@ export default function ({ getService, getPageObjects }) { await log.debug('filter by "2015-09-17 23:00" in the expanded scripted field list'); await PageObjects.discover.clickFieldListPlusFilter(scriptedPainlessFieldName2, '2015-09-17 23:00'); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); + await retry.try(async function () { expect(await PageObjects.discover.getHitCount()).to.be('1'); }); @@ -342,7 +340,6 @@ export default function ({ getService, getPageObjects }) { it('should visualize scripted field in vertical bar chart', async function () { await PageObjects.discover.clickFieldListItemVisualize(scriptedPainlessFieldName2); await PageObjects.header.waitUntilLoadingHasFinished(); - await PageObjects.visualize.waitForVisualization(); await inspector.open(); await inspector.setTablePageSize(50); await inspector.expectTableData([ diff --git a/yarn.lock b/yarn.lock index 15b0b911e8c632..2670912aa60966 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1584,10 +1584,10 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@elastic/charts@^7.2.1": - version "7.2.1" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-7.2.1.tgz#75e6ed23ebb4014ea1df8ee232905352525ddfca" - integrity sha512-cRvuRkZkMIYFjEJ3igPb3Uqv+aYJnoC+ZYkPdoCHHoiw4Dlwdl3xQVuzJECWoE1oZDcFq/MKjOFFTtFDjm57Ug== +"@elastic/charts@^8.1.1": + version "8.1.1" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-8.1.1.tgz#5b5897cf79aa384ce8bab6f14a7ea8c1f4095077" + integrity sha512-XjypIoWWtdJM3uHQydbEz5JkbXQ34nOMCQzry1p3t+J00o0U03qAyii1/TUn+Zohriis8ta7wnWD8nuwgfI3Iw== dependencies: "@types/d3-shape" "^1.3.1" "@types/luxon" "^1.11.1" From a3f5802d3a8f48c6ca1a6402cda86526e32206a2 Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 24 Jul 2019 14:44:46 -0700 Subject: [PATCH 02/20] [discover] add class accessibility --- .../discover/components/histogram/histogram.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx index d1381c7aae4579..2bdf4a6fa63cb2 100644 --- a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx @@ -51,12 +51,12 @@ export interface DiscoverHistogramProps { } export class DiscoverHistogram extends Component { - static propTypes = { + public static propTypes = { chartData: PropTypes.object, timefilterUpdateHandler: PropTypes.func, }; - onBrushEnd = (min: number, max: number) => { + public onBrushEnd = (min: number, max: number) => { const range = { xaxis: { from: min, @@ -67,7 +67,7 @@ export class DiscoverHistogram extends Component { this.props.timefilterUpdateHandler(range); }; - onElementClick = (xInterval: number) => (elementData: any) => { + public onElementClick = (xInterval: number) => (elementData: any) => { const startRange = elementData[0].x; const range = { @@ -80,13 +80,13 @@ export class DiscoverHistogram extends Component { this.props.timefilterUpdateHandler(range); }; - formatXValue = (val: string) => { + public formatXValue = (val: string) => { const xAxisFormat = this.props.chartData.xAxisFormat.params.pattern; return moment(val).format(xAxisFormat); }; - renderRectAnnotationTooltip = (details?: string) => ( + public renderRectAnnotationTooltip = (details?: string) => (
@@ -97,7 +97,7 @@ export class DiscoverHistogram extends Component {
); - renderBarTooltip = (xInterval: number, domainStart: number, domainEnd: number) => ( + public renderBarTooltip = (xInterval: number, domainStart: number, domainEnd: number) => ( headerData: TooltipValue ): JSX.Element | string => { const headerDataValue = headerData.value; @@ -126,7 +126,7 @@ export class DiscoverHistogram extends Component { return formattedValue; }; - render() { + public render() { const uiSettings = chrome.getUiSettingsClient(); const timeZone = timezoneProvider(uiSettings)(); const { chartData } = this.props; From b19e606036ddb926d92c24cb17344a751b30654d Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 24 Jul 2019 15:35:42 -0700 Subject: [PATCH 03/20] [discover] bump elastic-charts version and specify onElementClick type annotation --- package.json | 2 +- .../public/discover/components/histogram/histogram.tsx | 3 ++- yarn.lock | 8 ++++---- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index a524202fb25aa8..933438072c60ea 100644 --- a/package.json +++ b/package.json @@ -104,7 +104,7 @@ "@babel/core": "7.4.5", "@babel/polyfill": "7.4.4", "@babel/register": "7.4.4", - "@elastic/charts": "^8.1.1", + "@elastic/charts": "^8.1.2", "@elastic/datemath": "5.0.2", "@elastic/eui": "13.0.0", "@elastic/filesaver": "1.1.2", diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx index 2bdf4a6fa63cb2..d26a6d94091b49 100644 --- a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx @@ -27,6 +27,7 @@ import { Axis, Chart, HistogramBarSeries, + GeometryValue, getAnnotationId, getAxisId, getSpecId, @@ -67,7 +68,7 @@ export class DiscoverHistogram extends Component { this.props.timefilterUpdateHandler(range); }; - public onElementClick = (xInterval: number) => (elementData: any) => { + public onElementClick = (xInterval: number) => (elementData: GeometryValue[]) => { const startRange = elementData[0].x; const range = { diff --git a/yarn.lock b/yarn.lock index 2670912aa60966..d4cf780f3ce52f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1584,10 +1584,10 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@elastic/charts@^8.1.1": - version "8.1.1" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-8.1.1.tgz#5b5897cf79aa384ce8bab6f14a7ea8c1f4095077" - integrity sha512-XjypIoWWtdJM3uHQydbEz5JkbXQ34nOMCQzry1p3t+J00o0U03qAyii1/TUn+Zohriis8ta7wnWD8nuwgfI3Iw== +"@elastic/charts@^8.1.2": + version "8.1.2" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-8.1.2.tgz#b661e1d2e2edf907c34b409341fed38febb38b0b" + integrity sha512-JIYldxJDRtBUnA7jm1dMlLQbXEbPPobS5OjYkDMltKT1ei+tDXQZFYYfWb6WrkWMPfUPCofe3vyYRpIT0m92nQ== dependencies: "@types/d3-shape" "^1.3.1" "@types/luxon" "^1.11.1" From eb49a08e395506c868d01cabfbc961c8538669a4 Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 31 Jul 2019 14:18:37 -0700 Subject: [PATCH 04/20] [discover] set chartElement tooltip type to Follow --- .../kibana/public/discover/components/histogram/histogram.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx index d26a6d94091b49..1336f2604552ea 100644 --- a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx @@ -37,6 +37,7 @@ import { Settings, RectAnnotation, TooltipValue, + TooltipType, } from '@elastic/charts'; import { i18n } from '@kbn/i18n'; @@ -213,6 +214,7 @@ export class DiscoverHistogram extends Component { const tooltipProps = { headerFormatter: this.renderBarTooltip(xInterval, domainStart, domainEnd), + type: TooltipType.Follow, }; return ( From ce5c42d6c42bd2e4f64791de32167f5350a4dbdb Mon Sep 17 00:00:00 2001 From: Emma Cunningham Date: Wed, 31 Jul 2019 15:14:55 -0700 Subject: [PATCH 05/20] [discover] use moment methods for now annotation logic --- .../public/discover/components/histogram/histogram.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx index 1336f2604552ea..4bc80bc6142ac2 100644 --- a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx @@ -165,7 +165,10 @@ export class DiscoverHistogram extends Component { // Domain end of 'now' will be milliseconds behind current time, so we extend time by 1 minute and check if // the annotation is within this range; if so, the line annotation uses the domainEnd as its value const now = moment(); - const isAnnotationAtEdge = domainEnd + 60000 > now && now > domainEnd; + const isAnnotationAtEdge = + moment(domainEnd) + .add(60000) + .isAfter(now) && now.isAfter(domainEnd); const lineAnnotationValue = isAnnotationAtEdge ? domainEnd : now; const lineAnnotationData = [ From b78fb2c39f30b4db972c562214dd27826a08d3bc Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Thu, 22 Aug 2019 19:02:52 +0200 Subject: [PATCH 06/20] refactor: move historam inside directive folder --- .../components/histogram/directive.js | 28 ------------------- .../discover/components/histogram/index.js | 20 ------------- .../_histogram.scss} | 0 .../public/discover/directives/_index.scss | 1 + .../histogram => directives}/histogram.tsx | 0 .../public/discover/directives/index.js | 7 ++--- 6 files changed, 4 insertions(+), 52 deletions(-) delete mode 100644 src/legacy/core_plugins/kibana/public/discover/components/histogram/directive.js delete mode 100644 src/legacy/core_plugins/kibana/public/discover/components/histogram/index.js rename src/legacy/core_plugins/kibana/public/discover/{components/histogram/_index.scss => directives/_histogram.scss} (100%) rename src/legacy/core_plugins/kibana/public/discover/{components/histogram => directives}/histogram.tsx (100%) diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/directive.js b/src/legacy/core_plugins/kibana/public/discover/components/histogram/directive.js deleted file mode 100644 index 29b7c1d98a78da..00000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/components/histogram/directive.js +++ /dev/null @@ -1,28 +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 'ngreact'; -import { uiModules } from 'ui/modules'; -import { DiscoverHistogram } from './histogram'; - -import { wrapInI18nContext } from 'ui/i18n'; - -const app = uiModules.get('apps/discover', ['react']); - -app.directive('discoverHistogram', reactDirective => reactDirective(wrapInI18nContext(DiscoverHistogram))); diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/index.js b/src/legacy/core_plugins/kibana/public/discover/components/histogram/index.js deleted file mode 100644 index b8fdf067296409..00000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/components/histogram/index.js +++ /dev/null @@ -1,20 +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 './directive'; diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/_index.scss b/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/components/histogram/_index.scss rename to src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/_index.scss b/src/legacy/core_plugins/kibana/public/discover/directives/_index.scss index 8d092c11a4e1ef..c65243d99c8f49 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/_index.scss +++ b/src/legacy/core_plugins/kibana/public/discover/directives/_index.scss @@ -1 +1,2 @@ @import 'no_results'; +@import 'histogram'; \ No newline at end of file diff --git a/src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/discover/components/histogram/histogram.tsx rename to src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/index.js b/src/legacy/core_plugins/kibana/public/discover/directives/index.js index d13448bbf9c8a1..9a5ea7addad109 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/index.js +++ b/src/legacy/core_plugins/kibana/public/discover/directives/index.js @@ -20,13 +20,10 @@ import 'ngreact'; import { wrapInI18nContext } from 'ui/i18n'; import { uiModules } from 'ui/modules'; - import { DiscoverNoResults } from './no_results'; - import { DiscoverUninitialized } from './uninitialized'; - import { DiscoverUnsupportedIndexPattern } from './unsupported_index_pattern'; - +import { DiscoverHistogram } from './histogram'; import './timechart'; const app = uiModules.get('apps/discover', ['react']); @@ -42,3 +39,5 @@ app.directive('discoverUninitialized', reactDirective => app.directive('discoverUnsupportedIndexPattern', reactDirective => reactDirective(wrapInI18nContext(DiscoverUnsupportedIndexPattern), ['unsupportedType']) ); + +app.directive('discoverHistogram', reactDirective => reactDirective(DiscoverHistogram)); From 1f455c59478d00f1381a74439c8f5edb68e20196 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Thu, 22 Aug 2019 19:05:25 +0200 Subject: [PATCH 07/20] refactor: remove unused timechart directive --- .../public/discover/directives/index.js | 1 - .../public/discover/directives/timechart.js | 51 ------------------- 2 files changed, 52 deletions(-) delete mode 100644 src/legacy/core_plugins/kibana/public/discover/directives/timechart.js diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/index.js b/src/legacy/core_plugins/kibana/public/discover/directives/index.js index 9a5ea7addad109..a6f0ead4f73657 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/index.js +++ b/src/legacy/core_plugins/kibana/public/discover/directives/index.js @@ -24,7 +24,6 @@ import { DiscoverNoResults } from './no_results'; import { DiscoverUninitialized } from './uninitialized'; import { DiscoverUnsupportedIndexPattern } from './unsupported_index_pattern'; import { DiscoverHistogram } from './histogram'; -import './timechart'; const app = uiModules.get('apps/discover', ['react']); diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/timechart.js b/src/legacy/core_plugins/kibana/public/discover/directives/timechart.js deleted file mode 100644 index bb4f3a227d0cba..00000000000000 --- a/src/legacy/core_plugins/kibana/public/discover/directives/timechart.js +++ /dev/null @@ -1,51 +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 VislibProvider from 'ui/vislib'; -import { uiModules } from 'ui/modules'; -uiModules - .get('apps/discover') - .directive('discoverTimechart', function (Private) { - const vislib = Private(VislibProvider); - - return { - restrict: 'E', - scope: { - data: '=' - }, - link: function ($scope, elem) { - - const init = function () { - // This elem should already have a height/width - const myChart = new vislib.Chart(elem[0], { - addLegend: false - }); - - $scope.$watch('data', function (data) { - if (data != null) { - myChart.render(data); - } - }); - }; - - // Start the directive - init(); - } - }; - }); From 5fc881f4c993867e728db894b038e8fba377385d Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Thu, 22 Aug 2019 19:40:12 +0200 Subject: [PATCH 08/20] refactor: remove dependency from tsvb brush handler --- .../public/discover/controllers/discover.js | 10 +++++++--- .../public/discover/directives/histogram.tsx | 16 ++++++---------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js b/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js index 91c45bfa936e94..ccf4a4f46de518 100644 --- a/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/controllers/discover.js @@ -56,7 +56,6 @@ import { SavedObjectsClientProvider } from 'ui/saved_objects'; import { recentlyAccessed } from 'ui/persisted_log'; import { getDocLink } from 'ui/documentation_links'; import '../components/fetch_error'; -import '../components/histogram'; import { getPainlessError } from './get_painless_error'; import { showShareContextMenu, ShareContextMenuExtensionsRegistryProvider } from 'ui/share'; import { getUnhashableStatesProvider } from 'ui/state_management/state_hashing'; @@ -70,7 +69,6 @@ import { SavedObjectSaveModal } from 'ui/saved_objects/components/saved_object_s import { getRootBreadcrumbs, getSavedSearchBreadcrumbs } from '../breadcrumbs'; import { buildVislibDimensions } from 'ui/visualize/loader/pipeline_helpers/build_pipeline'; import 'ui/capabilities/route_setup'; -import { brushHandler } from '../../../../metrics/public/lib/create_brush_handler'; import { addHelpMenuToAppChrome } from '../components/help_menu/help_menu_util'; import { setup as data } from '../../../../../core_plugins/data/public/legacy'; @@ -213,7 +211,13 @@ function discoverController( timefilter.disableTimeRangeSelector(); timefilter.disableAutoRefreshSelector(); - $scope.timefilterUpdateHandler = brushHandler(timefilter); + $scope.timefilterUpdateHandler = (ranges) => { + timefilter.setTime({ + from: moment(ranges.from).toISOString(), + to: moment(ranges.to).toISOString(), + mode: 'absolute', + }); + }; $scope.getDocLink = getDocLink; $scope.intervalOptions = intervalOptions; diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx index 4bc80bc6142ac2..17f958e164fee2 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx @@ -49,7 +49,7 @@ import { timezoneProvider } from 'ui/vis/lib/timezone'; export interface DiscoverHistogramProps { chartData: any; - timefilterUpdateHandler: (ranges: { xaxis: { from: number; to: number } }) => void; + timefilterUpdateHandler: (ranges: { from: number; to: number }) => void; } export class DiscoverHistogram extends Component { @@ -60,10 +60,8 @@ export class DiscoverHistogram extends Component { public onBrushEnd = (min: number, max: number) => { const range = { - xaxis: { - from: min, - to: max, - }, + from: min, + to: max, }; this.props.timefilterUpdateHandler(range); @@ -73,10 +71,8 @@ export class DiscoverHistogram extends Component { const startRange = elementData[0].x; const range = { - xaxis: { - from: startRange, - to: startRange + xInterval, - }, + from: startRange, + to: startRange + xInterval, }; this.props.timefilterUpdateHandler(range); @@ -221,7 +217,7 @@ export class DiscoverHistogram extends Component { }; return ( - + Date: Thu, 22 Aug 2019 19:41:03 +0200 Subject: [PATCH 09/20] refactor: remove unrequired class to fix tooltip overflow --- src/legacy/core_plugins/kibana/public/discover/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/index.html b/src/legacy/core_plugins/kibana/public/discover/index.html index 7f3cddc50ea535..ae6bf340295fc7 100644 --- a/src/legacy/core_plugins/kibana/public/discover/index.html +++ b/src/legacy/core_plugins/kibana/public/discover/index.html @@ -168,7 +168,6 @@ chart-data="histogramData" timefilter-update-handler="timefilterUpdateHandler" watch-depth="reference" - class="visualization" >
From d7d763baadc2d0d0f58da22522123b7cf0ae6aa9 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Mon, 26 Aug 2019 16:42:47 +0200 Subject: [PATCH 10/20] WIP --- .../public/discover/directives/histogram.tsx | 53 ++++++++----------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx index 17f958e164fee2..2a6ab2a10c75ad 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx @@ -84,17 +84,6 @@ export class DiscoverHistogram extends Component { return moment(val).format(xAxisFormat); }; - public renderRectAnnotationTooltip = (details?: string) => ( -
- - - - - {details} - -
- ); - public renderBarTooltip = (xInterval: number, domainStart: number, domainEnd: number) => ( headerData: TooltipValue ): JSX.Element | string => { @@ -109,13 +98,18 @@ export class DiscoverHistogram extends Component { if (headerDataValue < domainStart || headerDataValue + xInterval > domainEnd) { return ( - + {partialDataText} - +

{formattedValue}

); @@ -181,28 +175,21 @@ export class DiscoverHistogram extends Component { }, }; - const partialAnnotationText = i18n.translate( - 'kbn.discover.histogram.partialData.annotationText', - { - defaultMessage: - 'This area may contain partial data. The selected time range does not fully cover it.', - } - ); - - const rectAnnotations = [ - { + const rectAnnotations = []; + if (domainStart !== domainMin) { + rectAnnotations.push({ coordinates: { - x0: domainStart, + x1: domainStart, }, - details: partialAnnotationText, - }, - { + }); + } + if (domainEnd !== domainMax) { + rectAnnotations.push({ coordinates: { - x1: domainEnd, + x0: domainEnd, }, - details: partialAnnotationText, - }, - ]; + }); + } const rectAnnotationStyle = { stroke: 'rgba(0, 0, 0, 0)', @@ -228,6 +215,7 @@ export class DiscoverHistogram extends Component { { position={Position.Bottom} title={chartData.xAxisLabel} tickFormat={this.formatXValue} + ticks={10} /> { annotationId={getAnnotationId('rect-annotation')} zIndex={2} style={rectAnnotationStyle} - renderTooltip={this.renderRectAnnotationTooltip} + hideTooltips={true} /> Date: Tue, 27 Aug 2019 13:13:26 +0200 Subject: [PATCH 11/20] Upgrade elastichart library and change the cursor/crosshair --- package.json | 2 +- .../kibana/public/discover/directives/histogram.tsx | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package.json b/package.json index ac625591be599b..a27cba9587eb94 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "@babel/core": "7.4.5", "@babel/polyfill": "7.4.4", "@babel/register": "7.4.4", - "@elastic/charts": "^10.0.1", + "@elastic/charts": "^11.0.3", "@elastic/datemath": "5.0.2", "@elastic/eui": "13.3.0", "@elastic/filesaver": "1.1.2", diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx index 2a6ab2a10c75ad..55108e70ce67aa 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx @@ -200,7 +200,7 @@ export class DiscoverHistogram extends Component { const tooltipProps = { headerFormatter: this.renderBarTooltip(xInterval, domainStart, domainEnd), - type: TooltipType.Follow, + type: TooltipType.VerticalCursor, }; return ( diff --git a/yarn.lock b/yarn.lock index 484c855af7933f..b9e75517182454 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1584,10 +1584,10 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@elastic/charts@^10.0.1": - version "10.0.1" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-10.0.1.tgz#791a4459960e404ceb644a02138a208398d0419f" - integrity sha512-eRcTfvSPM8RN4tfsuuQA9nc0fNroJRedQMmdeDjRB395KIeOdzD4arFDWU3jgQucB/rQXqa4aROH3I3B4Joouw== +"@elastic/charts@^11.0.3": + version "11.0.3" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-11.0.3.tgz#925dce6d71f6ce538c0ba194b77f3a30df6edd0c" + integrity sha512-0F9fsnMAUFgNZJ132V59kfdYGQJaFGsesTV/I0NJzg1GkF/JFgHD54Tie6AODQXMDmtkPZ0s66eE9QULIO8XEg== dependencies: "@types/d3-shape" "^1.3.1" "@types/luxon" "^1.11.1" From 49bd4f3202f3131281d25b7ef8c6d0efc1aa3edf Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Wed, 28 Aug 2019 01:10:05 -0500 Subject: [PATCH 12/20] upgrade elastic charts library --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index d7f83818ec272f..bc795f5de0b79f 100644 --- a/package.json +++ b/package.json @@ -102,7 +102,7 @@ "dependencies": { "@babel/core": "^7.5.5", "@babel/register": "^7.5.5", - "@elastic/charts": "^11.0.3", + "@elastic/charts": "^11.1.1", "@elastic/datemath": "5.0.2", "@elastic/eui": "13.3.0", "@elastic/filesaver": "1.1.2", diff --git a/yarn.lock b/yarn.lock index 7ebef0b70cae01..f405fde32a84d0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1049,10 +1049,10 @@ debug "^3.1.0" lodash.once "^4.1.1" -"@elastic/charts@^11.0.3": - version "11.0.3" - resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-11.0.3.tgz#925dce6d71f6ce538c0ba194b77f3a30df6edd0c" - integrity sha512-0F9fsnMAUFgNZJ132V59kfdYGQJaFGsesTV/I0NJzg1GkF/JFgHD54Tie6AODQXMDmtkPZ0s66eE9QULIO8XEg== +"@elastic/charts@^11.1.1": + version "11.1.1" + resolved "https://registry.yarnpkg.com/@elastic/charts/-/charts-11.1.1.tgz#32e1b18ec7ede9e3d62c3375284ad31d778017e2" + integrity sha512-zay5cQ39XzoKe0cabL/GCI2W1bjqatT20K/u7ZdHFa+GpazUd1/zjOpsLsKlq31Rr5yWXbc2M2iC4ZUp8n8crg== dependencies: "@types/d3-shape" "^1.3.1" "@types/luxon" "^1.11.1" From 3d3b76f3b951cc4ab70702642fdb01047f123c44 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Wed, 28 Aug 2019 11:56:00 +0200 Subject: [PATCH 13/20] fix(ie11): add fixed width for header text --- .../kibana/public/discover/directives/_histogram.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss b/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss index 8baf8fa44d5bd8..171b76dd334023 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss +++ b/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss @@ -1,3 +1,4 @@ .dscHistogram__header--partial { font-weight: $euiFontWeightRegular; + width: 200px; } From fc17973f4e934b8d3a6d167abe993aa004183506 Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Wed, 28 Aug 2019 18:54:12 +0200 Subject: [PATCH 14/20] fix: annotation colors on dark theme --- .../public/discover/directives/_histogram.scss | 2 +- .../public/discover/directives/histogram.tsx | 15 +++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss b/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss index 171b76dd334023..948f438eea5423 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss +++ b/src/legacy/core_plugins/kibana/public/discover/directives/_histogram.scss @@ -1,4 +1,4 @@ .dscHistogram__header--partial { font-weight: $euiFontWeightRegular; - width: 200px; + min-width: $euiSize * 12; } diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx index 55108e70ce67aa..d29f83d16c8c1a 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx @@ -21,6 +21,8 @@ import { EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; import moment from 'moment-timezone'; import React, { Component } from 'react'; import PropTypes from 'prop-types'; +import lightEuiTheme from '@elastic/eui/dist/eui_theme_light.json'; +import darkEuiTheme from '@elastic/eui/dist/eui_theme_dark.json'; import { AnnotationDomainTypes, @@ -166,12 +168,13 @@ export class DiscoverHistogram extends Component { dataValue: lineAnnotationValue, }, ]; + const isDarkMode = uiSettings.get('theme:darkMode'); const lineAnnotationStyle = { line: { strokeWidth: 2, - stroke: '#c80000', - opacity: 0.3, + stroke: isDarkMode ? darkEuiTheme.euiColorDanger : lightEuiTheme.euiColorDanger, + opacity: 0.7, }, }; @@ -192,10 +195,10 @@ export class DiscoverHistogram extends Component { } const rectAnnotationStyle = { - stroke: 'rgba(0, 0, 0, 0)', - strokeWidth: 1, - opacity: 1, - fill: 'rgba(0, 0, 0, 0.1)', + stroke: isDarkMode ? darkEuiTheme.euiColorLightShade : lightEuiTheme.euiColorDarkShade, + strokeWidth: 0, + opacity: isDarkMode ? 0.6 : 0.2, + fill: isDarkMode ? darkEuiTheme.euiColorLightShade : lightEuiTheme.euiColorDarkShade, }; const tooltipProps = { From aebac5c7119e2fbbd616dc38c383d7e2efe8fbf7 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Tue, 3 Sep 2019 09:51:59 -0500 Subject: [PATCH 15/20] unskip click and brush ui tests --- test/functional/apps/discover/_discover.js | 24 ++++++++----------- test/functional/page_objects/discover_page.js | 15 ++++++------ 2 files changed, 18 insertions(+), 21 deletions(-) diff --git a/test/functional/apps/discover/_discover.js b/test/functional/apps/discover/_discover.js index 4ac160ca7aeb8e..c10acab69cf423 100644 --- a/test/functional/apps/discover/_discover.js +++ b/test/functional/apps/discover/_discover.js @@ -26,7 +26,7 @@ export default function ({ getService, getPageObjects }) { const browser = getService('browser'); const kibanaServer = getService('kibanaServer'); const filterBar = getService('filterBar'); - const PageObjects = getPageObjects(['common', 'discover', 'header', 'visualize', 'timePicker']); + const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker']); const defaultSettings = { defaultIndex: 'logstash-*', }; @@ -142,28 +142,24 @@ export default function ({ getService, getPageObjects }) { } }); - it.skip('should modify the time range when a bar is clicked', async function () { + it('should modify the time range when a bar is clicked', async function () { await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); - await PageObjects.discover.clickHistogramBar(0); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.clickHistogramBar(); const time = await PageObjects.timePicker.getTimeConfig(); - expect(time.start).to.be('Sep 20, 2015 @ 00:00:00.000'); - expect(time.end).to.be('Sep 20, 2015 @ 03:00:00.000'); + expect(time.start).to.be('Sep 21, 2015 @ 09:00:00.000'); + expect(time.end).to.be('Sep 21, 2015 @ 12:00:00.000'); const rowData = await PageObjects.discover.getDocTableIndex(1); - expect(rowData).to.have.string('Sep 20, 2015 @ 02:57:03.761'); + expect(rowData).to.have.string('Sep 21, 2015 @ 11:59:22.316'); }); - it.skip('should modify the time range when the histogram is brushed', async function () { + it('should modify the time range when the histogram is brushed', async function () { await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - await PageObjects.visualize.waitForVisualization(); - await PageObjects.discover.brushHistogram(0, 1); - await PageObjects.visualize.waitForVisualization(); + await PageObjects.discover.brushHistogram(); const newDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); - expect(Math.round(newDurationHours)).to.be(3); + expect(Math.round(newDurationHours)).to.be(108); const rowData = await PageObjects.discover.getDocTableIndex(1); - expect(rowData).to.have.string('Sep 20, 2015 @ 02:56:02.323'); + expect(rowData).to.have.string('Sep 22, 2015 @ 23:50:13.253'); }); it('should show correct initial chart interval of Auto', async function () { diff --git a/test/functional/page_objects/discover_page.js b/test/functional/page_objects/discover_page.js index 6954bed4384789..dafff9525ed92c 100644 --- a/test/functional/page_objects/discover_page.js +++ b/test/functional/page_objects/discover_page.js @@ -116,16 +116,17 @@ export function DiscoverPageProvider({ getService, getPageObjects }) { await testSubjects.click('discoverOpenButton'); } - async clickHistogramBar(i) { - const bars = await find.allByCssSelector(`.series.histogram rect`); - await bars[i].click(); + async clickHistogramBar() { + const el = await find.byCssSelector('.echChart canvas:last-of-type'); + + await browser.clickMouseButton(el, 200, 20); } - async brushHistogram(from, to) { - const bars = await find.allByCssSelector('.series.histogram rect'); + async brushHistogram() { + const el = await find.byCssSelector('.echChart canvas:last-of-type'); await browser.dragAndDrop( - { location: bars[from], offset: { x: 0, y: -5 } }, - { location: bars[to], offset: { x: 0, y: -5 } } + { location: el, offset: { x: 200, y: 20 } }, + { location: el, offset: { x: 400, y: 30 } } ); } From c65a7c301c95f23ad51d25f85a1c4b176aa5bff7 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Wed, 4 Sep 2019 08:41:08 -0500 Subject: [PATCH 16/20] move functional tests to percy ui functional tests were validating chart svg shapes which is not possible with canvas --- test/functional/apps/discover/_discover.js | 271 ------------------ test/functional/page_objects/discover_page.js | 6 - test/visual_regression/config.ts | 2 +- .../services/visual_testing/visual_testing.ts | 8 +- .../tests/discover/chart_visualization.js | 115 ++++++++ .../visual_regression/tests/discover/index.js | 42 +++ 6 files changed, 162 insertions(+), 282 deletions(-) create mode 100644 test/visual_regression/tests/discover/chart_visualization.js create mode 100644 test/visual_regression/tests/discover/index.js diff --git a/test/functional/apps/discover/_discover.js b/test/functional/apps/discover/_discover.js index c10acab69cf423..59e1912b0e54e2 100644 --- a/test/functional/apps/discover/_discover.js +++ b/test/functional/apps/discover/_discover.js @@ -85,63 +85,12 @@ export default function ({ getService, getPageObjects }) { }); }); - // TODO: update this test when elastic-charts can support integration tests - it.skip('should show the correct bar chart', async function () { - const expectedBarChartData = [ - 35, - 189, - 694, - 1347, - 1285, - 704, - 176, - 29, - 39, - 189, - 640, - 1276, - 1327, - 663, - 166, - 25, - 30, - 164, - 663, - 1320, - 1270, - 681, - 188, - 27, - ]; - await verifyChartData(expectedBarChartData); - }); - it('should show correct time range string in chart', async function () { const actualTimeString = await PageObjects.discover.getChartTimespan(); const expectedTimeString = `Sep 19, 2015 @ 06:31:44.000 - Sep 23, 2015 @ 18:31:44.000`; expect(actualTimeString).to.be(expectedTimeString); }); - // TODO: update these tests when elastic-charts can support integration tests - it.skip('should show bars in the correct time zone', async function () { - const maxTicks = [ - '2015-09-20 00:00', - '2015-09-20 12:00', - '2015-09-21 00:00', - '2015-09-21 12:00', - '2015-09-22 00:00', - '2015-09-22 12:00', - '2015-09-23 00:00', - '2015-09-23 12:00' - ]; - - for (const tick of await PageObjects.discover.getBarChartXTicks()) { - if (!maxTicks.includes(tick)) { - throw new Error(`unexpected x-axis tick "${tick}"`); - } - } - }); - it('should modify the time range when a bar is clicked', async function () { await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); await PageObjects.discover.clickHistogramBar(); @@ -171,168 +120,6 @@ export default function ({ getService, getPageObjects }) { expect(actualInterval).to.be(expectedInterval); }); - // TODO: update these test when elastic-charts can support integration tests - it.skip('should show correct data for chart interval Hourly', async function () { - await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); - await PageObjects.discover.setChartInterval('Hourly'); - - const expectedBarChartData = [ - 4, - 7, - 16, - 23, - 38, - 87, - 132, - 159, - 248, - 320, - 349, - 376, - 380, - 324, - 293, - 233, - 188, - 125, - 69, - 40, - 28, - 17, - 2, - 3, - 8, - 10, - 12, - 28, - 36, - 84, - 111, - 157, - 229, - 292, - 324, - 373, - 378, - 345, - 306, - 223, - 167, - 124, - 72, - 35, - 22, - 11, - 7, - 1, - 6, - 5, - 12, - 25, - 27, - 76, - 111, - 175, - 228, - 294, - 358, - 372, - 366, - 344, - 276, - 213, - 201, - 113, - 72, - 39, - 36, - 12, - 7, - 3, - ]; - await verifyChartData(expectedBarChartData); - }); - - it.skip('should show correct data for chart interval Daily', async function () { - const chartInterval = 'Daily'; - const expectedBarChartData = [4757, 4614, 4633]; - await PageObjects.discover.setChartInterval(chartInterval); - await retry.try(async () => { - await verifyChartData(expectedBarChartData); - }); - }); - - it.skip('should show correct data for chart interval Weekly', async function () { - const chartInterval = 'Weekly'; - const expectedBarChartData = [4757, 9247]; - - await PageObjects.discover.setChartInterval(chartInterval); - await retry.try(async () => { - await verifyChartData(expectedBarChartData); - }); - }); - - it.skip('browser back button should show previous interval Daily', async function () { - const expectedChartInterval = 'Daily'; - const expectedBarChartData = [4757, 4614, 4633]; - - await browser.goBack(); - await retry.try(async function tryingForTime() { - const actualInterval = await PageObjects.discover.getChartInterval(); - expect(actualInterval).to.be(expectedChartInterval); - }); - await verifyChartData(expectedBarChartData); - }); - - it.skip('should show correct data for chart interval Monthly', async function () { - const chartInterval = 'Monthly'; - const expectedBarChartData = [13129]; - - await PageObjects.discover.setChartInterval(chartInterval); - await verifyChartData(expectedBarChartData); - }); - - it.skip('should show correct data for chart interval Yearly', async function () { - const chartInterval = 'Yearly'; - const expectedBarChartData = [13129]; - - await PageObjects.discover.setChartInterval(chartInterval); - await verifyChartData(expectedBarChartData); - }); - - it.skip('should show correct data for chart interval Auto', async function () { - const chartInterval = 'Auto'; - const expectedBarChartData = [ - 35, - 189, - 694, - 1347, - 1285, - 704, - 176, - 29, - 39, - 189, - 640, - 1276, - 1327, - 663, - 166, - 25, - 30, - 164, - 663, - 1320, - 1270, - 681, - 188, - 27, - ]; - - await PageObjects.discover.setChartInterval(chartInterval); - await verifyChartData(expectedBarChartData); - }); - it('should show Auto chart interval', async function () { const expectedChartInterval = 'Auto'; @@ -344,43 +131,6 @@ export default function ({ getService, getPageObjects }) { const isVisible = await PageObjects.discover.hasNoResults(); expect(isVisible).to.be(false); }); - - // TODO: update this function when elastic-charts can support integration tests - async function verifyChartData(expectedBarChartData) { - await retry.try(async function tryingForTime() { - const paths = await PageObjects.discover.getBarChartData(); - // the largest bars are over 100 pixels high so this is less than 1% tolerance - const barHeightTolerance = 1; - let stringResults = ''; - let hasFailure = false; - for (let y = 0; y < expectedBarChartData.length; y++) { - stringResults += - y + - ': expected = ' + - expectedBarChartData[y] + - ', actual = ' + - paths[y] + - ', Pass = ' + - (Math.abs(expectedBarChartData[y] - paths[y]) < - barHeightTolerance) + - '\n'; - if ( - Math.abs(expectedBarChartData[y] - paths[y]) > barHeightTolerance - ) { - hasFailure = true; - } - } - if (hasFailure) { - log.debug(stringResults); - log.debug(paths); - } - for (let x = 0; x < expectedBarChartData.length; x++) { - expect( - Math.abs(expectedBarChartData[x] - paths[x]) < barHeightTolerance - ).to.be.ok(); - } - }); - } }); describe('query #2, which has an empty time range', () => { @@ -439,36 +189,15 @@ export default function ({ getService, getPageObjects }) { describe('time zone switch', () => { it('should show bars in the correct time zone after switching', async function () { - await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'America/Phoenix' }); await browser.refresh(); await PageObjects.header.awaitKibanaChrome(); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); - // TODO: update this test when elastic-charts can support integration tests - // const maxTicks = [ - // '2015-09-20 00:00', - // '2015-09-20 12:00', - // '2015-09-21 00:00', - // '2015-09-21 12:00', - // '2015-09-22 00:00', - // '2015-09-22 12:00', - // '2015-09-23 00:00', - // '2015-09-23 12:00' - // ]; - - // await retry.try(async function () { - // for (const tick of await PageObjects.discover.getBarChartXTicks()) { - // if (!maxTicks.includes(tick)) { - // throw new Error(`unexpected x-axis tick "${tick}"`); - // } - // } - // }); log.debug('check that the newest doc timestamp is now -7 hours from the UTC time in the first test'); const rowData = await PageObjects.discover.getDocTableIndex(1); expect(rowData.startsWith('Sep 22, 2015 @ 16:50:13.253')).to.be.ok(); }); - }); }); } diff --git a/test/functional/page_objects/discover_page.js b/test/functional/page_objects/discover_page.js index dafff9525ed92c..b74389e8df503b 100644 --- a/test/functional/page_objects/discover_page.js +++ b/test/functional/page_objects/discover_page.js @@ -134,12 +134,6 @@ export function DiscoverPageProvider({ getService, getPageObjects }) { return await globalNav.getLastBreadcrumb(); } - async getBarChartXTicks() { - const xAxis = await find.byCssSelector('.x.axis.CategoryAxis-1'); - const $ = await xAxis.parseDomContent(); - return $('.tick > text').toArray().map(tick => $(tick).text().trim()); - } - async getBarChartData() { let yAxisLabel = 0; diff --git a/test/visual_regression/config.ts b/test/visual_regression/config.ts index 74f283f74683a8..77450b517dcc6d 100644 --- a/test/visual_regression/config.ts +++ b/test/visual_regression/config.ts @@ -26,7 +26,7 @@ export default async function({ readConfigFile }: FtrConfigProviderContext) { return { ...functionalConfig.getAll(), - testFiles: [require.resolve('./tests/console_app')], + testFiles: [require.resolve('./tests/console_app'), require.resolve('./tests/discover')], services, diff --git a/test/visual_regression/services/visual_testing/visual_testing.ts b/test/visual_regression/services/visual_testing/visual_testing.ts index 2b05f666a3500b..210de4c714d5cb 100644 --- a/test/visual_regression/services/visual_testing/visual_testing.ts +++ b/test/visual_regression/services/visual_testing/visual_testing.ts @@ -27,15 +27,15 @@ import { FtrProviderContext } from '../../ftr_provider_context'; // @ts-ignore internal js that is passed to the browser as is import { takePercySnapshot, takePercySnapshotWithAgent } from './take_percy_snapshot'; +export const DEFAULT_OPTIONS = { + widths: [1200], +}; + export async function VisualTestingProvider({ getService }: FtrProviderContext) { const browser = getService('browser'); const log = getService('log'); const lifecycle = getService('lifecycle'); - const DEFAULT_OPTIONS = { - widths: [1200], - }; - let currentTest: Test | undefined; lifecycle.on('beforeEachTest', (test: Test) => { currentTest = test; diff --git a/test/visual_regression/tests/discover/chart_visualization.js b/test/visual_regression/tests/discover/chart_visualization.js new file mode 100644 index 00000000000000..3f271da16025be --- /dev/null +++ b/test/visual_regression/tests/discover/chart_visualization.js @@ -0,0 +1,115 @@ +/* + * 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'; + +export default function ({ getService, getPageObjects }) { + const log = getService('log'); + const retry = getService('retry'); + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + const kibanaServer = getService('kibanaServer'); + const PageObjects = getPageObjects(['common', 'discover', 'header', 'timePicker']); + const visualTesting = getService('visualTesting'); + const defaultSettings = { + defaultIndex: 'logstash-*', + }; + + describe('discover', function describeIndexTests() { + const fromTime = '2015-09-19 06:31:44.000'; + const toTime = '2015-09-23 18:31:44.000'; + + before(async function () { + log.debug('load kibana index with default index pattern'); + await esArchiver.load('discover'); + + // and load a set of makelogs data + await esArchiver.loadIfNeeded('logstash_functional'); + await kibanaServer.uiSettings.replace(defaultSettings); + log.debug('discover'); + await PageObjects.common.navigateToApp('discover'); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + }); + + describe('query', function () { + this.tags(['skipFirefox']); + + it('should show bars in the correct time zone', async function () { + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Hourly', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); + await PageObjects.discover.setChartInterval('Hourly'); + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Daily', async function () { + await PageObjects.discover.setChartInterval('Daily'); + await retry.try(async () => { + await visualTesting.snapshot(); + }); + }); + + it('should show correct data for chart interval Weekly', async function () { + await PageObjects.discover.setChartInterval('Weekly'); + await retry.try(async () => { + await visualTesting.snapshot(); + }); + }); + + it('browser back button should show previous interval Daily', async function () { + await browser.goBack(); + await retry.try(async function tryingForTime() { + const actualInterval = await PageObjects.discover.getChartInterval(); + expect(actualInterval).to.be('Daily'); + }); + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Monthly', async function () { + await PageObjects.discover.setChartInterval('Monthly'); + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Yearly', async function () { + await PageObjects.discover.setChartInterval('Yearly'); + await visualTesting.snapshot(); + }); + + it('should show correct data for chart interval Auto', async function () { + await PageObjects.discover.setChartInterval('Auto'); + await visualTesting.snapshot(); + }); + }); + + describe('time zone switch', () => { + it('should show bars in the correct time zone after switching', async function () { + await kibanaServer.uiSettings.replace({ 'dateFormat:tz': 'America/Phoenix' }); + await browser.refresh(); + await PageObjects.header.awaitKibanaChrome(); + await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + await retry.try(async function () { + await visualTesting.snapshot(); + }); + }); + + }); + }); +} diff --git a/test/visual_regression/tests/discover/index.js b/test/visual_regression/tests/discover/index.js new file mode 100644 index 00000000000000..ba44fb12eef703 --- /dev/null +++ b/test/visual_regression/tests/discover/index.js @@ -0,0 +1,42 @@ +/* +* 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 { DEFAULT_OPTIONS } from '../../services/visual_testing/visual_testing'; + +// Width must be the same as visual_testing or canvas image widths will get skewed +const [SCREEN_WIDTH] = DEFAULT_OPTIONS.widths || []; + +export default function ({ getService, loadTestFile }) { + const esArchiver = getService('esArchiver'); + const browser = getService('browser'); + + describe('discover app', function () { + this.tags('ciGroup6'); + + before(function () { + return browser.setWindowSize(SCREEN_WIDTH, 1000); + }); + + after(function unloadMakelogs() { + return esArchiver.unload('logstash_functional'); + }); + + loadTestFile(require.resolve('./chart_visualization')); + }); +} From 72cf45686ccdaeeeb13ccc817f0f6276420e4ef2 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Wed, 4 Sep 2019 09:57:40 -0500 Subject: [PATCH 17/20] wait for loading to complete for percy screenshots --- .../tests/discover/chart_visualization.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/visual_regression/tests/discover/chart_visualization.js b/test/visual_regression/tests/discover/chart_visualization.js index 3f271da16025be..ca3def70627d9a 100644 --- a/test/visual_regression/tests/discover/chart_visualization.js +++ b/test/visual_regression/tests/discover/chart_visualization.js @@ -51,6 +51,7 @@ export default function ({ getService, getPageObjects }) { this.tags(['skipFirefox']); it('should show bars in the correct time zone', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); await visualTesting.snapshot(); }); @@ -61,6 +62,7 @@ export default function ({ getService, getPageObjects }) { }); it('should show correct data for chart interval Daily', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); await PageObjects.discover.setChartInterval('Daily'); await retry.try(async () => { await visualTesting.snapshot(); @@ -68,6 +70,7 @@ export default function ({ getService, getPageObjects }) { }); it('should show correct data for chart interval Weekly', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); await PageObjects.discover.setChartInterval('Weekly'); await retry.try(async () => { await visualTesting.snapshot(); @@ -80,20 +83,24 @@ export default function ({ getService, getPageObjects }) { const actualInterval = await PageObjects.discover.getChartInterval(); expect(actualInterval).to.be('Daily'); }); + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); await visualTesting.snapshot(); }); it('should show correct data for chart interval Monthly', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); await PageObjects.discover.setChartInterval('Monthly'); await visualTesting.snapshot(); }); it('should show correct data for chart interval Yearly', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); await PageObjects.discover.setChartInterval('Yearly'); await visualTesting.snapshot(); }); it('should show correct data for chart interval Auto', async function () { + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); await PageObjects.discover.setChartInterval('Auto'); await visualTesting.snapshot(); }); @@ -105,6 +112,7 @@ export default function ({ getService, getPageObjects }) { await browser.refresh(); await PageObjects.header.awaitKibanaChrome(); await PageObjects.timePicker.setAbsoluteRange(fromTime, toTime); + await PageObjects.header.awaitGlobalLoadingIndicatorHidden(); await retry.try(async function () { await visualTesting.snapshot(); }); From a39695966c5e6a197b421a71b31f91534f96b59e Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Mon, 9 Sep 2019 19:08:54 -0500 Subject: [PATCH 18/20] update partial bucket message --- .../kibana/public/discover/directives/histogram.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx index d29f83d16c8c1a..e387355af69556 100644 --- a/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx +++ b/src/legacy/core_plugins/kibana/public/discover/directives/histogram.tsx @@ -94,7 +94,7 @@ export class DiscoverHistogram extends Component { const partialDataText = i18n.translate('kbn.discover.histogram.partialData.bucketTooltipText', { defaultMessage: - 'Part of this bucket may contain partial data. The selected time range does not fully cover it.', + 'The selected time range does not include this entire bucket, it may contain partial data.', }); if (headerDataValue < domainStart || headerDataValue + xInterval > domainEnd) { From 6298388b32cd0857e859e7ddce800e27f51b76c9 Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Mon, 9 Sep 2019 20:24:44 -0500 Subject: [PATCH 19/20] fix merge conflicts and functional test errors --- test/functional/apps/discover/_discover.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/functional/apps/discover/_discover.js b/test/functional/apps/discover/_discover.js index 59e1912b0e54e2..9f37feef781cae 100644 --- a/test/functional/apps/discover/_discover.js +++ b/test/functional/apps/discover/_discover.js @@ -97,7 +97,7 @@ export default function ({ getService, getPageObjects }) { const time = await PageObjects.timePicker.getTimeConfig(); expect(time.start).to.be('Sep 21, 2015 @ 09:00:00.000'); expect(time.end).to.be('Sep 21, 2015 @ 12:00:00.000'); - const rowData = await PageObjects.discover.getDocTableIndex(1); + const rowData = await PageObjects.discover.getDocTableField(1); expect(rowData).to.have.string('Sep 21, 2015 @ 11:59:22.316'); }); @@ -107,7 +107,7 @@ export default function ({ getService, getPageObjects }) { const newDurationHours = await PageObjects.timePicker.getTimeDurationInHours(); expect(Math.round(newDurationHours)).to.be(108); - const rowData = await PageObjects.discover.getDocTableIndex(1); + const rowData = await PageObjects.discover.getDocTableField(1); expect(rowData).to.have.string('Sep 22, 2015 @ 23:50:13.253'); }); From 0141ddb19feba251f2ce9068eae327c625a12d8c Mon Sep 17 00:00:00 2001 From: nickofthyme Date: Tue, 10 Sep 2019 10:44:09 -0500 Subject: [PATCH 20/20] update discover page with changes to broser util function --- test/functional/page_objects/discover_page.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/test/functional/page_objects/discover_page.js b/test/functional/page_objects/discover_page.js index 3ae08454c656a6..52b4c8d931ae21 100644 --- a/test/functional/page_objects/discover_page.js +++ b/test/functional/page_objects/discover_page.js @@ -119,7 +119,10 @@ export function DiscoverPageProvider({ getService, getPageObjects }) { async clickHistogramBar() { const el = await find.byCssSelector('.echChart canvas:last-of-type'); - await browser.clickMouseButton(el, 200, 20); + await browser.getActions() + .move({ x: 200, y: 20, origin: el._webElement }) + .click() + .perform(); } async brushHistogram() {