Skip to content

Commit

Permalink
Add support for HDR percentiles in TSVB visualizations (#78306)
Browse files Browse the repository at this point in the history
* Add support for HDR percentiles in TSVB visualizations

Closes: #64238

* remove extra console.log

* fix CI

* fix PR comments

* fix layout

* remove legacy injectI18n

* fix localization issues

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 7, 2020
1 parent a8c080b commit 59d83e6
Show file tree
Hide file tree
Showing 12 changed files with 254 additions and 156 deletions.
1 change: 1 addition & 0 deletions src/plugins/vis_type_timeseries/common/vis_schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ export const metricsItems = schema.object({
})
)
),
numberOfSignificantValueDigits: numberOptional,
percentiles: schema.maybe(
schema.arrayOf(
schema.object({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,19 @@ import { FieldSelect } from './field_select';
import { AggRow } from './agg_row';
import { createChangeHandler } from '../lib/create_change_handler';
import { createSelectHandler } from '../lib/create_select_handler';
import { createNumberHandler } from '../lib/create_number_handler';
import {
htmlIdGenerator,
EuiSpacer,
EuiFlexGroup,
EuiFlexGrid,
EuiFlexItem,
EuiFormLabel,
EuiFormRow,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { KBN_FIELD_TYPES } from '../../../../../../plugins/data/public';
import { Percentiles, newPercentile } from './percentile_ui';
import { PercentileHdr } from './percentile_hdr';

const RESTRICT_FIELDS = [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.HISTOGRAM];

Expand All @@ -46,6 +48,8 @@ export function PercentileAgg(props) {

const handleChange = createChangeHandler(props.onChange, model);
const handleSelectChange = createSelectHandler(handleChange);
const handleNumberChange = createNumberHandler(handleChange);

const indexPattern =
(series.override_index_pattern && series.series_index_pattern) || panel.index_pattern;

Expand All @@ -66,7 +70,7 @@ export function PercentileAgg(props) {
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexGrid gutterSize="s" columns={2}>
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
Expand Down Expand Up @@ -103,11 +107,25 @@ export function PercentileAgg(props) {
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>

<EuiSpacer size="m" />

<Percentiles onChange={handleChange} name="percentiles" model={model} panel={panel} />
<EuiFlexItem>
<EuiFormRow
label={
<FormattedMessage
id="visTypeTimeseries.percentile.percents"
defaultMessage="Percents"
/>
}
>
<Percentiles onChange={handleChange} name="percentiles" model={model} panel={panel} />
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<PercentileHdr
value={model.numberOfSignificantValueDigits}
onChange={handleNumberChange('numberOfSignificantValueDigits')}
/>
</EuiFlexItem>
</EuiFlexGrid>
</AggRow>
);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import React from 'react';
import { EuiFieldNumber, EuiFormRow, EuiIconTip } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';

export interface PercentileHdrProps {
value: number | undefined;
onChange: () => void;
}

export const PercentileHdr = ({ value, onChange }: PercentileHdrProps) => (
<EuiFormRow
label={
<>
<FormattedMessage
id="visTypeTimeseries.percentileHdr.numberOfSignificantValueDigits"
defaultMessage="Number of significant value digits (HDR histogram)"
/>{' '}
<EuiIconTip
position="right"
content={
<FormattedMessage
id="visTypeTimeseries.percentileHdr.numberOfSignificantValueDigits.hint"
defaultMessage="HDR Histogram (High Dynamic Range Histogram) is an alternative implementation that can be useful when calculating percentile ranks for latency measurements as it can be faster than the t-digest implementation with the trade-off of a larger memory footprint. Number of significant value digits parameter specifies the resolution of values for the histogram in number of significant digits"
/>
}
type="questionInCircle"
/>
</>
}
>
<EuiFieldNumber min={1} value={value || ''} onChange={onChange} />
</EuiFormRow>
);
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,8 @@
*/
import React, { ChangeEvent } from 'react';
import { get } from 'lodash';
import { FormattedMessage } from '@kbn/i18n/react';
import {
htmlIdGenerator,
EuiFieldNumber,
EuiFlexGroup,
EuiFlexItem,
EuiFormLabel,
EuiSpacer,
} from '@elastic/eui';

import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiPanel } from '@elastic/eui';

import { AddDeleteButtons } from '../../add_delete_buttons';

Expand All @@ -50,26 +43,16 @@ export const MultiValueRow = ({
disableAdd,
disableDelete,
}: MultiValueRowProps) => {
const htmlId = htmlIdGenerator();

const onFieldNumberChange = (event: ChangeEvent<HTMLInputElement>) =>
onChange({
...model,
value: get(event, 'target.value'),
});

return (
<div className="tvbAggRow__multiValueRow">
<EuiFlexGroup responsive={false} alignItems="center">
<EuiFlexItem grow={false}>
<EuiFormLabel htmlFor={htmlId('value')}>
<FormattedMessage
id="visTypeTimeseries.multivalueRow.valueLabel"
defaultMessage="Value:"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiPanel paddingSize="s" className="tvbAggRow__multiValueRow">
<EuiFlexGroup alignItems="center" gutterSize="s">
<EuiFlexItem>
<EuiFieldNumber
value={model.value === '' ? '' : Number(model.value)}
placeholder="0"
Expand All @@ -82,11 +65,11 @@ export const MultiValueRow = ({
onDelete={() => onDelete(model)}
disableDelete={disableDelete}
disableAdd={disableAdd}
responsive={false}
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
</div>
</EuiPanel>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,11 @@
import React from 'react';
import {
htmlIdGenerator,
EuiFlexGroup,
EuiFlexItem,
EuiFormLabel,
EuiFormRow,
EuiSpacer,
EuiFlexGrid,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { AggSelect } from '../agg_select';
Expand All @@ -34,12 +34,16 @@ import { FieldSelect } from '../field_select';
import { createChangeHandler } from '../../lib/create_change_handler';
// @ts-ignore
import { createSelectHandler } from '../../lib/create_select_handler';
// @ts-ignore
import { createNumberHandler } from '../../lib/create_number_handler';

import { AggRow } from '../agg_row';
import { PercentileRankValues } from './percentile_rank_values';

import { IFieldType, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public';
import { MetricsItemsSchema, PanelSchema, SeriesItemsSchema } from '../../../../../common/types';
import { DragHandleProps } from '../../../../types';
import { PercentileHdr } from '../percentile_hdr';

const RESTRICT_FIELDS = [KBN_FIELD_TYPES.NUMBER, KBN_FIELD_TYPES.HISTOGRAM];

Expand Down Expand Up @@ -67,6 +71,7 @@ export const PercentileRankAgg = (props: PercentileRankAggProps) => {
const isTablePanel = panel.type === 'table';
const handleChange = createChangeHandler(props.onChange, model);
const handleSelectChange = createSelectHandler(handleChange);
const handleNumberChange = createNumberHandler(handleChange);

const handlePercentileRankValuesChange = (values: MetricsItemsSchema['values']) => {
handleChange({
Expand All @@ -84,7 +89,7 @@ export const PercentileRankAgg = (props: PercentileRankAggProps) => {
siblings={props.siblings}
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexGrid gutterSize="s" columns={2}>
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
Expand Down Expand Up @@ -121,17 +126,32 @@ export const PercentileRankAgg = (props: PercentileRankAggProps) => {
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer />
{model.values && (
<PercentileRankValues
disableAdd={isTablePanel}
disableDelete={isTablePanel}
showOnlyLastRow={isTablePanel}
model={model.values}
onChange={handlePercentileRankValuesChange}
/>
)}

<EuiFlexItem>
<EuiFormRow
label={
<FormattedMessage
id="visTypeTimeseries.percentileRank.values"
defaultMessage="Values"
/>
}
>
<PercentileRankValues
disableAdd={isTablePanel}
disableDelete={isTablePanel}
showOnlyLastRow={isTablePanel}
model={model.values!}
onChange={handlePercentileRankValuesChange}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<PercentileHdr
value={model.numberOfSignificantValueDigits}
onChange={handleNumberChange('numberOfSignificantValueDigits')}
/>
</EuiFlexItem>
</EuiFlexGrid>
</AggRow>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
import React from 'react';
import { last } from 'lodash';

import { EuiFlexGroup } from '@elastic/eui';
import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { MultiValueRow } from './multi_value_row';

interface PercentileRankValuesProps {
Expand Down Expand Up @@ -52,19 +52,20 @@ export const PercentileRankValues = (props: PercentileRankValuesProps) => {
disableDeleteRow: boolean;
disableAddRow: boolean;
}) => (
<MultiValueRow
key={`percentileRankValue__item${rowModel.id}`}
onAdd={onAddValue}
onChange={onChangeValue}
onDelete={onDeleteValue}
disableDelete={disableDeleteRow}
disableAdd={disableAddRow}
model={rowModel}
/>
<EuiFlexItem key={`percentileRankValue__item${rowModel.id}`}>
<MultiValueRow
onAdd={onAddValue}
onChange={onChangeValue}
onDelete={onDeleteValue}
disableDelete={disableDeleteRow}
disableAdd={disableAddRow}
model={rowModel}
/>
</EuiFlexItem>
);

return (
<EuiFlexGroup direction="column" responsive={false} gutterSize="xs">
<EuiFlexGroup direction="column" gutterSize="s">
{showOnlyLastRow &&
renderRow({
rowModel: {
Expand Down
Loading

0 comments on commit 59d83e6

Please sign in to comment.