Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Replace Discover chart with elastic-charts #43788

Merged
merged 28 commits into from
Sep 10, 2019
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
3048b58
[discover] use elastic-charts for histogram
Jul 1, 2019
a3f5802
[discover] add class accessibility
Jul 24, 2019
b19e606
[discover] bump elastic-charts version and specify onElementClick typ…
Jul 24, 2019
eb49a08
[discover] set chartElement tooltip type to Follow
Jul 31, 2019
ce5c42d
[discover] use moment methods for now annotation logic
Jul 31, 2019
ab1092d
Merge branch 'master' into discover-chart-replace
markov00 Aug 22, 2019
b78fb2c
refactor: move historam inside directive folder
markov00 Aug 22, 2019
1f455c5
refactor: remove unused timechart directive
markov00 Aug 22, 2019
5fc881f
refactor: remove dependency from tsvb brush handler
markov00 Aug 22, 2019
aeaf295
refactor: remove unrequired class to fix tooltip overflow
markov00 Aug 22, 2019
d7d763b
WIP
markov00 Aug 26, 2019
6f9fc20
Upgrade elastichart library and change the cursor/crosshair
markov00 Aug 27, 2019
0b41910
Merge branch 'master' into discover-chart-replace
markov00 Aug 27, 2019
8850f18
Merge branch 'master' into discover-chart-replace
markov00 Aug 27, 2019
49bd4f3
upgrade elastic charts library
nickofthyme Aug 28, 2019
149d687
Merge branch 'master' into discover-chart-replace
markov00 Aug 28, 2019
335fad8
Merge branch 'discover-chart-replace' of github.com:markov00/kibana i…
markov00 Aug 28, 2019
3d3b76f
fix(ie11): add fixed width for header text
markov00 Aug 28, 2019
fc17973
fix: annotation colors on dark theme
markov00 Aug 28, 2019
aebac5c
unskip click and brush ui tests
nickofthyme Sep 3, 2019
f545d6a
Merge branch 'master' into discover-chart-replace
nickofthyme Sep 3, 2019
c65a7c3
move functional tests to percy
nickofthyme Sep 4, 2019
72cf456
wait for loading to complete for percy screenshots
nickofthyme Sep 4, 2019
ff9f75b
Merge branch 'master' into discover-chart-replace
nickofthyme Sep 10, 2019
f9bbb01
Merge branch 'master' into discover-chart-replace
nickofthyme Sep 10, 2019
a396959
update partial bucket message
nickofthyme Sep 10, 2019
6298388
fix merge conflicts and functional test errors
nickofthyme Sep 10, 2019
0141ddb
update discover page with changes to broser util function
nickofthyme Sep 10, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
"dependencies": {
"@babel/core": "^7.5.5",
"@babel/register": "^7.5.5",
"@elastic/charts": "^10.2.0",
"@elastic/charts": "^11.0.3",
"@elastic/datemath": "5.0.2",
"@elastic/eui": "13.3.0",
"@elastic/filesaver": "1.1.2",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ 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';
Expand Down Expand Up @@ -196,8 +195,6 @@ function discoverController(
localStorage,
uiCapabilities
) {
const visualizeLoader = Private(VisualizeLoaderProvider);
let visualizeHandler;
const Vis = Private(VisProvider);
const responseHandler = vislibSeriesResponseHandlerProvider().handler;
const getUnhashableStates = Private(getUnhashableStatesProvider);
Expand All @@ -214,6 +211,13 @@ function discoverController(

timefilter.disableTimeRangeSelector();
timefilter.disableAutoRefreshSelector();
$scope.timefilterUpdateHandler = (ranges) => {
timefilter.setTime({
from: moment(ranges.from).toISOString(),
to: moment(ranges.to).toISOString(),
mode: 'absolute',
});
};

$scope.getDocLink = getDocLink;
$scope.intervalOptions = intervalOptions;
Expand Down Expand Up @@ -791,15 +795,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;
});
}

Expand Down Expand Up @@ -1044,13 +1040,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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.dscHistogram__header--partial {
font-weight: $euiFontWeightRegular;
}
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
@import 'no_results';
@import 'histogram';
Original file line number Diff line number Diff line change
@@ -0,0 +1,255 @@
/*
* 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,
GeometryValue,
getAnnotationId,
getAxisId,
getSpecId,
LineAnnotation,
Position,
ScaleType,
Settings,
RectAnnotation,
TooltipValue,
TooltipType,
} 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: { from: number; to: number }) => void;
}

export class DiscoverHistogram extends Component<DiscoverHistogramProps> {
public static propTypes = {
chartData: PropTypes.object,
timefilterUpdateHandler: PropTypes.func,
};

public onBrushEnd = (min: number, max: number) => {
const range = {
from: min,
to: max,
};

this.props.timefilterUpdateHandler(range);
};

public onElementClick = (xInterval: number) => (elementData: GeometryValue[]) => {
const startRange = elementData[0].x;

const range = {
from: startRange,
to: startRange + xInterval,
};

this.props.timefilterUpdateHandler(range);
};

public formatXValue = (val: string) => {
const xAxisFormat = this.props.chartData.xAxisFormat.params.pattern;

return moment(val).format(xAxisFormat);
};

public 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.',
Copy link
Contributor

@spalger spalger Sep 4, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Part of...partial data" feels a little redundant.

Suggested change
'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.',

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See a396959

});

if (headerDataValue < domainStart || headerDataValue + xInterval > domainEnd) {
return (
<React.Fragment>
<EuiFlexGroup
alignItems="center"
className="dscHistogram__header--partial"
responsive={false}
gutterSize="xs"
>
<EuiFlexItem grow={false}>
<EuiIcon type="iInCircle" />
</EuiFlexItem>
<EuiFlexItem>{partialDataText}</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="xs" />
<p>{formattedValue}</p>
</React.Fragment>
);
}

return formattedValue;
};

public 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 =
moment(domainEnd)
.add(60000)
.isAfter(now) && now.isAfter(domainEnd);
const lineAnnotationValue = isAnnotationAtEdge ? domainEnd : now;

const lineAnnotationData = [
{
dataValue: lineAnnotationValue,
},
];

const lineAnnotationStyle = {
line: {
strokeWidth: 2,
stroke: '#c80000',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This color is hardly visible in dark mode. You'll need to pull our danger color from the compile json theme and check for light or dark theme.
Screen Shot 2019-08-28 at 12 02 48 PM

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in fc17973

opacity: 0.3,
},
};

const rectAnnotations = [];
if (domainStart !== domainMin) {
rectAnnotations.push({
coordinates: {
x1: domainStart,
},
});
}
if (domainEnd !== domainMax) {
rectAnnotations.push({
coordinates: {
x0: domainEnd,
},
});
}

const rectAnnotationStyle = {
stroke: 'rgba(0, 0, 0, 0)',
strokeWidth: 1,
opacity: 1,
fill: 'rgba(0, 0, 0, 0.1)',
dmlemeshko marked this conversation as resolved.
Show resolved Hide resolved
};

const tooltipProps = {
headerFormatter: this.renderBarTooltip(xInterval, domainStart, domainEnd),
type: TooltipType.VerticalCursor,
};

return (
<Chart size="100%">
<Settings
xDomain={xDomain}
onBrushEnd={this.onBrushEnd}
onElementClick={this.onElementClick(xInterval)}
tooltip={tooltipProps}
theme={getChartTheme()}
/>
<Axis
id={getAxisId('discover-histogram-left-axis')}
position={Position.Left}
ticks={5}
title={chartData.yAxisLabel}
/>
<Axis
id={getAxisId('discover-histogram-bottom-axis')}
position={Position.Bottom}
title={chartData.xAxisLabel}
tickFormat={this.formatXValue}
ticks={10}
/>
<LineAnnotation
annotationId={getAnnotationId('line-annotation')}
domainType={AnnotationDomainTypes.XDomain}
dataValues={lineAnnotationData}
hideTooltips={true}
style={lineAnnotationStyle}
/>
<RectAnnotation
dataValues={rectAnnotations}
annotationId={getAnnotationId('rect-annotation')}
zIndex={2}
style={rectAnnotationStyle}
hideTooltips={true}
/>
<HistogramBarSeries
id={getSpecId('discover-histogram')}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor="x"
yAccessors={['y']}
data={data}
timeZone={timeZone}
name={chartData.yAxisLabel}
/>
</Chart>
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +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 './timechart';
import { DiscoverHistogram } from './histogram';

const app = uiModules.get('apps/discover', ['react']);

Expand All @@ -42,3 +38,5 @@ app.directive('discoverUninitialized', reactDirective =>
app.directive('discoverUnsupportedIndexPattern', reactDirective =>
reactDirective(wrapInI18nContext(DiscoverUnsupportedIndexPattern), ['unsupportedType'])
);

app.directive('discoverHistogram', reactDirective => reactDirective(DiscoverHistogram));
10 changes: 6 additions & 4 deletions src/legacy/core_plugins/kibana/public/discover/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -162,11 +162,13 @@

</header>

<div id="discoverHistogram"
ng-show="vis && rows.length !== 0"
<discover-histogram
style="display: flex; height: 200px"
>
</div>
ng-show="vis && rows.length !== 0"
chart-data="histogramData"
timefilter-update-handler="timefilterUpdateHandler"
watch-depth="reference"
></discover-histogram>
</section>

<section
Expand Down
Loading