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

[TSVB] Introducing Timerange Data Mode for Metric Style Visualizations #37185

Merged
merged 55 commits into from
Jul 18, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
b550ac5
Add Time Range input to Panel on TSVB
gospodarsky May 27, 2019
6c16088
Disable YesNo Component
gospodarsky May 28, 2019
43417b2
Remove redundant translations
gospodarsky May 28, 2019
c62e794
Merge branch 'master' into tsvb-timerange-support
gospodarsky May 28, 2019
827c5f1
Merge branch 'master' into tsvb-timerange-support
gospodarsky May 29, 2019
55fa941
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
alexwizp May 31, 2019
83dc9a2
Merge branch 'tsvb-timerange-support' of github.com:Avinar-24/kibana …
gospodarsky May 31, 2019
a038ae0
add timerange_data_modes
alexwizp May 31, 2019
dcab081
Fix reviews
gospodarsky May 31, 2019
f960833
Merge branch 'tsvb-timerange-support' of github.com:Avinar-24/kibana …
gospodarsky May 31, 2019
9434074
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jun 3, 2019
3c14949
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
alexwizp Jun 3, 2019
bb67b94
BE part
alexwizp May 31, 2019
e949012
Merge branch 'tsvb-timerange-support' of github.com:Avinar-24/kibana …
gospodarsky Jun 3, 2019
52199ed
add new ui restriction
alexwizp Jun 3, 2019
79041e3
add new ui restriction - ui part
alexwizp Jun 3, 2019
ddb2c3c
Merge branch 'tsvb-timerange-support' of github.com:Avinar-24/kibana …
gospodarsky Jun 3, 2019
a16138d
override index pattern issue
alexwizp Jun 3, 2019
4e3641b
Merge branch 'tsvb-timerange-support' of github.com:Avinar-24/kibana …
gospodarsky Jun 3, 2019
3579ed1
Take TIME_RANGE_MODE_KEY out
gospodarsky Jun 3, 2019
3b28918
Make TimeRange more stable
gospodarsky Jun 3, 2019
8a98c04
Small improvements
gospodarsky Jun 3, 2019
7ac69f4
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jun 4, 2019
bf7fd27
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jun 4, 2019
f34af4c
Small improvements - BE part
alexwizp Jun 4, 2019
746010f
Small improvements - BE part
alexwizp Jun 4, 2019
81feaee
Small improvements - BE part
alexwizp Jun 4, 2019
454fdd6
Merge branch 'tsvb-timerange-support' of github.com:Avinar-24/kibana …
gospodarsky Jun 4, 2019
31fcc11
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jun 4, 2019
e557771
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jun 5, 2019
d1760d4
Bind uiRestrictions to UI of the Time Range
gospodarsky Jun 5, 2019
ee4a5ab
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jun 6, 2019
1079560
Get rid of context consumers
gospodarsky Jun 6, 2019
4ab2cf6
Remove console.log
gospodarsky Jun 6, 2019
cd2df21
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jun 6, 2019
d9acdca
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jun 7, 2019
2c1206c
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jun 10, 2019
c9960fb
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jun 12, 2019
3493ead
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jun 17, 2019
597ba08
Merge branch 'tsvb-timerange-support' of github.com:Avinar-24/kibana …
gospodarsky Jun 17, 2019
a960436
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jun 20, 2019
3e5372a
Add translation and refactor a little
gospodarsky Jun 20, 2019
4b13246
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jun 24, 2019
282f561
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jun 27, 2019
e6db7d0
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jul 1, 2019
57664e7
Merge branch 'tsvb-timerange-support' of github.com:Avinar-24/kibana …
gospodarsky Jul 1, 2019
5e8dad5
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jul 4, 2019
fe891f0
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jul 5, 2019
b55c54a
Pretty Panel config
gospodarsky Jul 5, 2019
f9f7210
Merge branch 'master' into tsvb-timerange-support
gospodarsky Jul 8, 2019
5d6c494
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jul 11, 2019
3645f82
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jul 12, 2019
f9195fc
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jul 15, 2019
12b0c7f
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jul 16, 2019
be8587a
Merge remote-tracking branch 'upstream/master' into tsvb-timerange-su…
gospodarsky Jul 18, 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
44 changes: 44 additions & 0 deletions src/legacy/core_plugins/metrics/common/timerange_data_modes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 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.
*/

/**
* Time Range data modes.
* @constant
* @public
*/
export const TIME_RANGE_DATA_MODES = {
/**
* Entire timerange mode will match all the documents selected in the
* timerange timepicker
*/
ENTIRE_TIME_RANGE: 'entire_time_range',

/**
* Last value mode will match only the documents for the specified interval
* from the end of the timerange.
*/
LAST_VALUE: 'last_value',
};

/**
* Key for getting the Time Range mode from the Panel configuration object.
* @constant
* @public
*/
export const TIME_RANGE_MODE_KEY = 'time_range_mode';
49 changes: 49 additions & 0 deletions src/legacy/core_plugins/metrics/common/ui_restrictions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/*
* 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.
*/

/**
* UI Restrictions keys
* @constant
* @public
*/
export const RESTRICTIONS_KEYS = {
/**
* Key for getting the white listed group by fields from the UIRestrictions object.
*/
WHITE_LISTED_GROUP_BY_FIELDS: 'whiteListedGroupByFields',

/**
* Key for getting the white listed metrics from the UIRestrictions object.
*/
WHITE_LISTED_METRICS: 'whiteListedMetrics',

/**
* Key for getting the white listed Time Range modes from the UIRestrictions object.
*/
WHITE_LISTED_TIMERANGE_MODES: 'whiteListedTimerangeModes',
};

/**
* Default value for the UIRestriction
* @constant
* @public
*/
export const DEFAULT_UI_RESTRICTION = {
'*': true,
};
149 changes: 103 additions & 46 deletions src/legacy/core_plugins/metrics/public/components/index_pattern.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,9 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiFormLabel,
EuiSpacer,
EuiComboBox,
EuiText,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';

import { FieldSelect } from './aggs/field_select';
import { createSelectHandler } from './lib/create_select_handler';
import { createTextHandler } from './lib/create_text_handler';
Expand All @@ -42,6 +40,11 @@ import {
isAutoInterval,
AUTO_INTERVAL,
} from './lib/get_interval';
import { i18n } from '@kbn/i18n';
import { TIME_RANGE_DATA_MODES, TIME_RANGE_MODE_KEY } from '../../common/timerange_data_modes';
import { PANEL_TYPES } from '../../common/panel_types';
import { isTimerangeModeEnabled } from '../lib/check_ui_restrictions';
import { UIRestrictionsContext } from '../contexts/ui_restriction_context';

const RESTRICT_FIELDS = [ES_TYPES.DATE];

Expand All @@ -56,75 +59,126 @@ const validateIntervalValue = intervalValue => {
return validateReInterval(intervalValue);
};

export const IndexPattern = props => {
const { fields, prefix } = props;
const handleSelectChange = createSelectHandler(props.onChange);
const handleTextChange = createTextHandler(props.onChange);
const htmlId = htmlIdGenerator();

const isEntireTimeRangeActive = (model, isTimeSeries) =>
!isTimeSeries && model[TIME_RANGE_MODE_KEY] === TIME_RANGE_DATA_MODES.ENTIRE_TIME_RANGE;

export const IndexPattern = ({ fields, prefix, onChange, disabled, model: _model }) => {
const handleSelectChange = createSelectHandler(onChange);
const handleTextChange = createTextHandler(onChange);
const timeFieldName = `${prefix}time_field`;
const indexPatternName = `${prefix}index_pattern`;
const intervalName = `${prefix}interval`;
const dropBucketName = `${prefix}drop_last_bucket`;
const updateControlValidity = useContext(FormValidationContext);
const uiRestrictions = useContext(UIRestrictionsContext);

const timeRangeOptions = [
{
label: i18n.translate('tsvb.indexPattern.timeRange.lastValue', {
defaultMessage: 'Last value',
}),
value: TIME_RANGE_DATA_MODES.LAST_VALUE,
disabled: !isTimerangeModeEnabled(TIME_RANGE_DATA_MODES.LAST_VALUE, uiRestrictions),
},
{
label: i18n.translate('tsvb.indexPattern.timeRange.entireTimeRange', {
defaultMessage: 'Entire time range',
}),
value: TIME_RANGE_DATA_MODES.ENTIRE_TIME_RANGE,
disabled: !isTimerangeModeEnabled(TIME_RANGE_DATA_MODES.ENTIRE_TIME_RANGE, uiRestrictions),
},
];

const defaults = {
default_index_pattern: '',
[indexPatternName]: '*',
[intervalName]: AUTO_INTERVAL,
[dropBucketName]: 1,
[TIME_RANGE_MODE_KEY]: timeRangeOptions[0].value,
};

const htmlId = htmlIdGenerator();
const model = { ...defaults, ...props.model };
const model = { ...defaults, ..._model };
const isDefaultIndexPatternUsed = model.default_index_pattern && !model[indexPatternName];
const intervalValidation = validateIntervalValue(model[intervalName]);
const selectedTimeRangeOption = timeRangeOptions.find(
({ value }) => model[TIME_RANGE_MODE_KEY] === value
);
const isTimeSeries = model.type === PANEL_TYPES.TIMESERIES;

updateControlValidity(intervalName, intervalValidation.isValid);

return (
<div className={props.className}>
<EuiFlexGroup responsive={false} wrap={true}>
<div className="index-pattern">
{!isTimeSeries && (
<EuiFlexGroup>
<EuiFlexItem>
<EuiFormRow
id={htmlId('timeRange')}
label={i18n.translate('tsvb.indexPattern.timeRange.label', {
defaultMessage: 'Data timerange mode',
})}
>
<EuiComboBox
isClearable={false}
placeholder={i18n.translate('tsvb.indexPattern.timeRange.selectTimeRange', {
defaultMessage: 'Select',
})}
options={timeRangeOptions}
selectedOptions={selectedTimeRangeOption ? [selectedTimeRangeOption] : []}
onChange={handleSelectChange(TIME_RANGE_MODE_KEY)}
singleSelection={{ asPlainText: true }}
isDisabled={disabled}
/>
</EuiFormRow>
<EuiText size="xs" style={{ margin: 0 }}>
{i18n.translate('tsvb.indexPattern.timeRange.hint', {
defaultMessage: `This setting controls the timespan used for matching documents.
"Entire timerange" will match all the documents selected in the timepicker.
"Last value" will match only the documents for the specified interval from the end of the timerange.`,
})}
</EuiText>
</EuiFlexItem>
</EuiFlexGroup>
)}
<EuiFlexGroup>
<EuiFlexItem>
<EuiFormRow
id={htmlId('indexPattern')}
label={<FormattedMessage id="tsvb.indexPatternLabel" defaultMessage="Index pattern" />}
label={i18n.translate('tsvb.indexPatternLabel', { defaultMessage: 'Index pattern' })}
helpText={
isDefaultIndexPatternUsed && (
<FormattedMessage
id="tsvb.indexPattern.searchByDefaultIndex"
defaultMessage="Default index pattern is used. To query all indexes use *"
/>
)
isDefaultIndexPatternUsed &&
i18n.translate('tsvb.indexPattern.searchByDefaultIndex', {
defaultMessage: 'Default index pattern is used. To query all indexes use *',
})
}
fullWidth
>
<EuiFieldText
data-test-subj="metricsIndexPatternInput"
disabled={props.disabled}
disabled={disabled}
placeholder={model.default_index_pattern}
onChange={handleTextChange(indexPatternName, '*')}
value={model[indexPatternName]}
fullWidth
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
id={htmlId('timeField')}
label={
<FormattedMessage id="tsvb.indexPattern.timeFieldLabel" defaultMessage="Time field" />
}
fullWidth
label={i18n.translate('tsvb.indexPattern.timeFieldLabel', {
defaultMessage: 'Time field',
})}
>
<FieldSelect
data-test-subj="metricsIndexPatternFieldsSelect"
restrict={RESTRICT_FIELDS}
value={model[timeFieldName]}
disabled={props.disabled}
disabled={disabled}
onChange={handleSelectChange(timeFieldName)}
indexPattern={model[indexPatternName]}
fields={fields}
placeholder={isDefaultIndexPatternUsed ? model.default_timefield : undefined}
fullWidth
/>
</EuiFormRow>
</EuiFlexItem>
Expand All @@ -133,35 +187,38 @@ export const IndexPattern = props => {
isInvalid={!intervalValidation.isValid}
error={intervalValidation.errorMessage}
id={htmlId('interval')}
label={
<FormattedMessage id="tsvb.indexPattern.intervalLabel" defaultMessage="Interval" />
}
helpText={
<FormattedMessage
id="tsvb.indexPattern.intervalHelpText"
defaultMessage="Examples: auto, 1m, 1d, 7d, 1y, >=1m"
description="auto, 1m, 1d, 7d, 1y, >=1m are required values and must not be translated."
/>
}
label={i18n.translate('tsvb.indexPattern.intervalLabel', {
defaultMessage: 'Interval',
})}
helpText={i18n.translate('tsvb.indexPattern.intervalHelpText', {
defaultMessage: 'Examples: auto, 1m, 1d, 7d, 1y, >=1m',
description:
'auto, 1m, 1d, 7d, 1y, >=1m are required values and must not be translated.',
})}
>
<EuiFieldText
isInvalid={!intervalValidation.isValid}
disabled={props.disabled}
disabled={disabled || isEntireTimeRangeActive(model, isTimeSeries)}
onChange={handleTextChange(intervalName, AUTO_INTERVAL)}
value={model[intervalName]}
placeholder={AUTO_INTERVAL}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiFormLabel>
<FormattedMessage
id="tsvb.indexPattern.dropLastBucketLabel"
defaultMessage="Drop last bucket?"
<EuiFormRow
id={htmlId('dropLastBucket')}
label={i18n.translate('tsvb.indexPattern.dropLastBucketLabel', {
defaultMessage: 'Drop last bucket?',
})}
>
<YesNo
value={model[dropBucketName]}
name={dropBucketName}
onChange={onChange}
disabled={disabled || isEntireTimeRangeActive(model, isTimeSeries)}
/>
</EuiFormLabel>
<EuiSpacer size="s" />
<YesNo value={model[dropBucketName]} name={dropBucketName} onChange={props.onChange} />
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
import PropTypes from 'prop-types';
import React, { useState, useEffect } from 'react';
import { get } from 'lodash';
import { TimeseriesPanelConfig as timeseries } from './panel_config/timeseries';
import { MetricPanelConfig as metric } from './panel_config/metric';
import { TopNPanelConfig as topN } from './panel_config/top_n';
Expand All @@ -26,6 +27,7 @@ import { GaugePanelConfig as gauge } from './panel_config/gauge';
import { MarkdownPanelConfig as markdown } from './panel_config/markdown';
import { FormattedMessage } from '@kbn/i18n/react';
import { FormValidationContext } from '../contexts/form_validation_context';
import { UIRestrictionsContext } from '../contexts/ui_restriction_context';

const types = {
timeseries,
Expand All @@ -43,19 +45,32 @@ export function PanelConfig(props) {
const { model } = props;
const Component = types[model.type];
const [formValidationResults] = useState({});
const [uiRestrictions, setUIRestrictions] = useState(null);

useEffect(() => {
model.isModelInvalid = !checkModelValidity(formValidationResults);
});

useEffect(() => {
const visDataSubscription = props.visData$.subscribe(visData =>
setUIRestrictions(get(visData, 'uiRestrictions', null))
);

return function cleanup() {
visDataSubscription.unsubscribe();
};
}, [props.visData$]);

const updateControlValidity = (controlKey, isControlValid) => {
formValidationResults[controlKey] = isControlValid;
};

if (Component) {
return (
<FormValidationContext.Provider value={updateControlValidity}>
<Component {...props} />
<UIRestrictionsContext.Provider value={uiRestrictions}>
<Component {...props} />
</UIRestrictionsContext.Provider>
</FormValidationContext.Provider>
);
}
Expand Down
Loading