[TSVB] Turn Prettier on (#38106)

* Add the TSVB module to Prettier

* Pretty the TSVB by Prettier
This commit is contained in:
Artyom Gospodarsky 2019-06-11 16:14:22 +03:00 committed by GitHub
parent a33201cf39
commit cac41c3eae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
269 changed files with 4076 additions and 3865 deletions

View file

@ -56,6 +56,7 @@ module.exports = {
'x-pack/plugins/apm/**/*',
'x-pack/plugins/canvas/**/*',
'**/*.{ts,tsx}',
'src/legacy/core_plugins/metrics/**/*.js',
],
plugins: ['prettier'],
rules: Object.assign(

View file

@ -44,17 +44,13 @@ describe('aggLookup', () => {
it('returns options for basic', () => {
const options = createOptions('basic');
expect(options).to.have.length(15);
expect(options.every(opt => isBasicAgg({ type: opt.value }))).to.equal(
true
);
expect(options.every(opt => isBasicAgg({ type: opt.value }))).to.equal(true);
});
it('returns options for pipeline', () => {
const options = createOptions('pipeline');
expect(options).to.have.length(15);
expect(options.every(opt => !isBasicAgg({ type: opt.value }))).to.equal(
true
);
expect(options.every(opt => !isBasicAgg({ type: opt.value }))).to.equal(true);
});
it('returns options for all if given unknown key', () => {

View file

@ -49,20 +49,14 @@ describe('calculateLabel(metric, metrics)', () => {
it('returns formated label for pipeline aggs', () => {
const metric = { id: 2, type: 'derivative', field: 1 };
const metrics = [
{ id: 1, type: 'max', field: 'network.out.bytes' },
metric
];
const metrics = [{ id: 1, type: 'max', field: 'network.out.bytes' }, metric];
const label = calculateLabel(metric, metrics);
expect(label).to.equal('Derivative of Max of network.out.bytes');
});
it('returns formated label for derivative of percentile', () => {
const metric = { id: 2, type: 'derivative', field: '1[50.0]' };
const metrics = [
{ id: 1, type: 'percentile', field: 'network.out.bytes' },
metric
];
const metrics = [{ id: 1, type: 'percentile', field: 'network.out.bytes' }, metric];
const label = calculateLabel(metric, metrics);
expect(label).to.equal('Derivative of Percentile of network.out.bytes (50.0)');
});
@ -72,7 +66,7 @@ describe('calculateLabel(metric, metrics)', () => {
const metrics = [
{ id: 1, type: 'max', field: 'network.out.bytes' },
{ id: 2, type: 'moving_average', field: 1 },
metric
metric,
];
const label = calculateLabel(metric, metrics);
expect(label).to.equal('Derivative of Moving Average of Max of network.out.bytes');
@ -82,10 +76,9 @@ describe('calculateLabel(metric, metrics)', () => {
const metric = { id: 2, type: 'derivative', field: 1 };
const metrics = [
{ id: 1, type: 'max', field: 'network.out.bytes', alias: 'Outbound Traffic' },
metric
metric,
];
const label = calculateLabel(metric, metrics);
expect(label).to.equal('Derivative of Outbound Traffic');
});
});

View file

@ -23,7 +23,9 @@ import { i18n } from '@kbn/i18n';
export const lookup = {
count: i18n.translate('tsvb.aggLookup.countLabel', { defaultMessage: 'Count' }),
calculation: i18n.translate('tsvb.aggLookup.calculationLabel', { defaultMessage: 'Calculation' }),
std_deviation: i18n.translate('tsvb.aggLookup.deviationLabel', { defaultMessage: 'Std. Deviation' }),
std_deviation: i18n.translate('tsvb.aggLookup.deviationLabel', {
defaultMessage: 'Std. Deviation',
}),
variance: i18n.translate('tsvb.aggLookup.varianceLabel', { defaultMessage: 'Variance' }),
sum_of_squares: i18n.translate('tsvb.aggLookup.sumOfSqLabel', { defaultMessage: 'Sum of Sq.' }),
avg: i18n.translate('tsvb.aggLookup.averageLabel', { defaultMessage: 'Average' }),
@ -31,24 +33,44 @@ export const lookup = {
min: i18n.translate('tsvb.aggLookup.minLabel', { defaultMessage: 'Min' }),
sum: i18n.translate('tsvb.aggLookup.sumLabel', { defaultMessage: 'Sum' }),
percentile: i18n.translate('tsvb.aggLookup.percentileLabel', { defaultMessage: 'Percentile' }),
percentile_rank: i18n.translate('tsvb.aggLookup.percentileRankLabel', { defaultMessage: 'Percentile Rank' }),
percentile_rank: i18n.translate('tsvb.aggLookup.percentileRankLabel', {
defaultMessage: 'Percentile Rank',
}),
cardinality: i18n.translate('tsvb.aggLookup.cardinalityLabel', { defaultMessage: 'Cardinality' }),
value_count: i18n.translate('tsvb.aggLookup.valueCountLabel', { defaultMessage: 'Value Count' }),
derivative: i18n.translate('tsvb.aggLookup.derivativeLabel', { defaultMessage: 'Derivative' }),
cumulative_sum: i18n.translate('tsvb.aggLookup.cumulativeSumLabel', { defaultMessage: 'Cumulative Sum' }),
moving_average: i18n.translate('tsvb.aggLookup.movingAverageLabel', { defaultMessage: 'Moving Average' }),
avg_bucket: i18n.translate('tsvb.aggLookup.overallAverageLabel', { defaultMessage: 'Overall Average' }),
cumulative_sum: i18n.translate('tsvb.aggLookup.cumulativeSumLabel', {
defaultMessage: 'Cumulative Sum',
}),
moving_average: i18n.translate('tsvb.aggLookup.movingAverageLabel', {
defaultMessage: 'Moving Average',
}),
avg_bucket: i18n.translate('tsvb.aggLookup.overallAverageLabel', {
defaultMessage: 'Overall Average',
}),
min_bucket: i18n.translate('tsvb.aggLookup.overallMinLabel', { defaultMessage: 'Overall Min' }),
max_bucket: i18n.translate('tsvb.aggLookup.overallMaxLabel', { defaultMessage: 'Overall Max' }),
sum_bucket: i18n.translate('tsvb.aggLookup.overallSumLabel', { defaultMessage: 'Overall Sum' }),
variance_bucket: i18n.translate('tsvb.aggLookup.overallVarianceLabel', { defaultMessage: 'Overall Variance' }),
sum_of_squares_bucket: i18n.translate('tsvb.aggLookup.overallSumOfSqLabel', { defaultMessage: 'Overall Sum of Sq.' }),
std_deviation_bucket: i18n.translate('tsvb.aggLookup.overallStdDeviationLabel', { defaultMessage: 'Overall Std. Deviation' }),
variance_bucket: i18n.translate('tsvb.aggLookup.overallVarianceLabel', {
defaultMessage: 'Overall Variance',
}),
sum_of_squares_bucket: i18n.translate('tsvb.aggLookup.overallSumOfSqLabel', {
defaultMessage: 'Overall Sum of Sq.',
}),
std_deviation_bucket: i18n.translate('tsvb.aggLookup.overallStdDeviationLabel', {
defaultMessage: 'Overall Std. Deviation',
}),
series_agg: i18n.translate('tsvb.aggLookup.seriesAggLabel', { defaultMessage: 'Series Agg' }),
math: i18n.translate('tsvb.aggLookup.mathLabel', { defaultMessage: 'Math' }),
serial_diff: i18n.translate('tsvb.aggLookup.serialDifferenceLabel', { defaultMessage: 'Serial Difference' }),
filter_ratio: i18n.translate('tsvb.aggLookup.filterRatioLabel', { defaultMessage: 'Filter Ratio' }),
positive_only: i18n.translate('tsvb.aggLookup.positiveOnlyLabel', { defaultMessage: 'Positive Only' }),
serial_diff: i18n.translate('tsvb.aggLookup.serialDifferenceLabel', {
defaultMessage: 'Serial Difference',
}),
filter_ratio: i18n.translate('tsvb.aggLookup.filterRatioLabel', {
defaultMessage: 'Filter Ratio',
}),
positive_only: i18n.translate('tsvb.aggLookup.positiveOnlyLabel', {
defaultMessage: 'Positive Only',
}),
static: i18n.translate('tsvb.aggLookup.staticValueLabel', { defaultMessage: 'Static Value' }),
top_hit: i18n.translate('tsvb.aggLookup.topHitLabel', { defaultMessage: 'Top Hit' }),
};
@ -75,15 +97,7 @@ const byType = {
_all: lookup,
pipeline: pipeline,
basic: _.omit(lookup, pipeline),
metrics: _.pick(lookup, [
'count',
'avg',
'min',
'max',
'sum',
'cardinality',
'value_count',
]),
metrics: _.pick(lookup, ['count', 'avg', 'min', 'max', 'sum', 'cardinality', 'value_count']),
};
export function isBasicAgg(item) {
@ -101,9 +115,9 @@ export function createOptions(type = '_all', siblings = []) {
return {
label: disabled
? i18n.translate('tsvb.aggLookup.addPipelineAggDescription', {
defaultMessage: '{label} (use the "+" button to add this pipeline agg)',
values: { label }
})
defaultMessage: '{label} (use the "+" button to add this pipeline agg)',
values: { label },
})
: label,
value,
disabled,

View file

@ -27,5 +27,5 @@ export const basicAggs = [
'variance',
'sum_of_squares',
'value_count',
'cardinality'
'cardinality',
];

View file

@ -37,24 +37,34 @@ const paths = [
];
export function calculateLabel(metric, metrics) {
if (!metric) return i18n.translate('tsvb.calculateLabel.unknownLabel', { defaultMessage: 'Unknown' });
if (!metric)
return i18n.translate('tsvb.calculateLabel.unknownLabel', { defaultMessage: 'Unknown' });
if (metric.alias) return metric.alias;
if (metric.type === 'count') return i18n.translate('tsvb.calculateLabel.countLabel', { defaultMessage: 'Count' });
if (metric.type === 'count')
return i18n.translate('tsvb.calculateLabel.countLabel', { defaultMessage: 'Count' });
if (metric.type === 'calculation') {
return i18n.translate('tsvb.calculateLabel.bucketScriptsLabel', { defaultMessage: 'Bucket Script' });
return i18n.translate('tsvb.calculateLabel.bucketScriptsLabel', {
defaultMessage: 'Bucket Script',
});
}
if (metric.type === 'math') return i18n.translate('tsvb.calculateLabel.mathLabel', { defaultMessage: 'Math' });
if (metric.type === 'math')
return i18n.translate('tsvb.calculateLabel.mathLabel', { defaultMessage: 'Math' });
if (metric.type === 'series_agg') {
return i18n.translate('tsvb.calculateLabel.seriesAggLabel',
{ defaultMessage: 'Series Agg ({metricFunction})', values: { metricFunction: metric.function } }
);
return i18n.translate('tsvb.calculateLabel.seriesAggLabel', {
defaultMessage: 'Series Agg ({metricFunction})',
values: { metricFunction: metric.function },
});
}
if (metric.type === 'filter_ratio') return i18n.translate('tsvb.calculateLabel.filterRatioLabel', { defaultMessage: 'Filter Ratio' });
if (metric.type === 'filter_ratio')
return i18n.translate('tsvb.calculateLabel.filterRatioLabel', {
defaultMessage: 'Filter Ratio',
});
if (metric.type === 'static') {
return i18n.translate('tsvb.calculateLabel.staticValueLabel',
{ defaultMessage: 'Static Value of {metricValue}', values: { metricValue: metric.value } }
);
return i18n.translate('tsvb.calculateLabel.staticValueLabel', {
defaultMessage: 'Static Value of {metricValue}',
values: { metricValue: metric.value },
});
}
if (includes(paths, metric.type)) {
@ -70,18 +80,22 @@ export function calculateLabel(metric, metrics) {
if (matches) {
return i18n.translate('tsvb.calculateLabel.lookupMetricTypeOfTargetWithAdditionalLabel', {
defaultMessage: '{lookupMetricType} of {targetLabel} ({additionalLabel})',
values: { lookupMetricType: lookup[metric.type], targetLabel, additionalLabel: matches[1] }
values: {
lookupMetricType: lookup[metric.type],
targetLabel,
additionalLabel: matches[1],
},
});
}
}
return i18n.translate('tsvb.calculateLabel.lookupMetricTypeOfTargetLabel', {
defaultMessage: '{lookupMetricType} of {targetLabel}',
values: { lookupMetricType: lookup[metric.type], targetLabel }
values: { lookupMetricType: lookup[metric.type], targetLabel },
});
}
return i18n.translate('tsvb.calculateLabel.lookupMetricTypeOfMetricFieldRankLabel', {
defaultMessage: '{lookupMetricType} of {metricField}',
values: { lookupMetricType: lookup[metric.type], metricField: metric.field }
values: { lookupMetricType: lookup[metric.type], metricField: metric.field },
});
}

View file

@ -39,10 +39,7 @@ describe('extractIndexPatterns(vis)', () => {
series_index_pattern: 'example-2-*',
},
],
annotations: [
{ index_pattern: 'notes-*' },
{ index_pattern: 'example-1-*' },
],
annotations: [{ index_pattern: 'notes-*' }, { index_pattern: 'example-1-*' }],
};
});

View file

@ -20,7 +20,7 @@
import { isArray, last } from 'lodash';
const DEFAULT_VALUE = 0;
const extractValue = data => data && data[1] || null;
const extractValue = data => (data && data[1]) || null;
export const getLastValue = (data, defaultValue = DEFAULT_VALUE) => {
if (!isArray(data)) {

View file

@ -40,4 +40,3 @@ describe('getLastValue(data)', () => {
expect(getLastValue(null, '-')).toBe('-');
});
});

View file

@ -21,4 +21,3 @@ import dateMath from '@elastic/datemath';
export const GTE_INTERVAL_RE = new RegExp(`^>=([\\d\\.]+\\s*(${dateMath.units.join('|')}))$`);
export const INTERVAL_STRING_RE = new RegExp(`^([\\d\\.]+)\\s*(${dateMath.units.join('|')})$`);

View file

@ -32,5 +32,5 @@ export const METRIC_TYPES = {
export const EXTENDED_STATS_TYPES = [
METRIC_TYPES.STD_DEVIATION,
METRIC_TYPES.VARIANCE,
METRIC_TYPES.SUM_OF_SQUARES
METRIC_TYPES.SUM_OF_SQUARES,
];

View file

@ -25,7 +25,7 @@ const IS_DARK_THEME = chrome.getUiSettingsClient().get('theme:darkMode');
/**
* Returns true if the color that is passed has low luminosity
*/
const isColorDark = (c) => {
const isColorDark = c => {
return color(c).luminosity() < 0.45;
};
@ -33,7 +33,7 @@ const isColorDark = (c) => {
* Checks to see if the `currentTheme` is dark in luminosity.
* Defaults to checking `theme:darkMode`.
*/
export const isThemeDark = (currentTheme) => {
export const isThemeDark = currentTheme => {
let themeIsDark = currentTheme || IS_DARK_THEME;
// If passing a string, check the luminosity
@ -68,5 +68,3 @@ export const isBackgroundInverted = (backgroundColor, currentTheme) => {
const themeIsDark = isThemeDark(currentTheme);
return backgroundIsDark !== themeIsDark;
};

View file

@ -23,14 +23,12 @@ import { fieldsRoutes } from './server/routes/fields';
import { visDataRoutes } from './server/routes/vis';
import { SearchStrategiesRegister } from './server/lib/search_strategies/search_strategies_register';
export default function (kibana) {
export default function(kibana) {
return new kibana.Plugin({
require: ['kibana', 'elasticsearch'],
uiExports: {
visTypes: [
'plugins/metrics/kbn_vis_types',
],
visTypes: ['plugins/metrics/kbn_vis_types'],
interpreter: ['plugins/metrics/tsvb_fn'],
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
},

View file

@ -86,12 +86,14 @@ export function AddDeleteButtons(props) {
let activatePanelBtn = null;
if (isBoolean(props.isPanelActive)) {
const tooltip = props.isPanelActive ? props.deactivatePanelTooltip : props.activatePanelTooltip;
const tooltip = props.isPanelActive
? props.deactivatePanelTooltip
: props.activatePanelTooltip;
const iconType = props.isPanelActive ? 'eye' : 'eyeClosed';
activatePanelBtn = (
<EuiFlexItem grow={false}>
<EuiToolTip content={tooltip} >
<EuiToolTip content={tooltip}>
<EuiButtonIcon
data-test-subj={`${testSubj}ActivatePanelBtn`}
aria-label={tooltip}
@ -123,12 +125,24 @@ export function AddDeleteButtons(props) {
AddDeleteButtons.defaultProps = {
testSubj: 'Add',
activeTooltip: i18n.translate('tsvb.addDeleteButtons.addButtonDefaultTooltip', { defaultMessage: 'Add' }),
addTooltip: i18n.translate('tsvb.addDeleteButtons.addButtonDefaultTooltip', { defaultMessage: 'Add' }),
deleteTooltip: i18n.translate('tsvb.addDeleteButtons.deleteButtonDefaultTooltip', { defaultMessage: 'Delete' }),
cloneTooltip: i18n.translate('tsvb.addDeleteButtons.cloneButtonDefaultTooltip', { defaultMessage: 'Clone' }),
activatePanelTooltip: i18n.translate('tsvb.addDeleteButtons.reEnableTooltip', { defaultMessage: 'Re-enable' }),
deactivatePanelTooltip: i18n.translate('tsvb.addDeleteButtons.temporarilyDisableTooltip', { defaultMessage: 'Temporarily Disable' }),
activeTooltip: i18n.translate('tsvb.addDeleteButtons.addButtonDefaultTooltip', {
defaultMessage: 'Add',
}),
addTooltip: i18n.translate('tsvb.addDeleteButtons.addButtonDefaultTooltip', {
defaultMessage: 'Add',
}),
deleteTooltip: i18n.translate('tsvb.addDeleteButtons.deleteButtonDefaultTooltip', {
defaultMessage: 'Delete',
}),
cloneTooltip: i18n.translate('tsvb.addDeleteButtons.cloneButtonDefaultTooltip', {
defaultMessage: 'Clone',
}),
activatePanelTooltip: i18n.translate('tsvb.addDeleteButtons.reEnableTooltip', {
defaultMessage: 'Re-enable',
}),
deactivatePanelTooltip: i18n.translate('tsvb.addDeleteButtons.temporarilyDisableTooltip', {
defaultMessage: 'Temporarily Disable',
}),
};
AddDeleteButtons.propTypes = {

View file

@ -26,57 +26,52 @@ import { AddDeleteButtons } from './add_delete_buttons';
describe('AddDeleteButtons', () => {
it('calls onAdd={handleAdd}', () => {
const handleAdd = sinon.spy();
const wrapper = shallowWithIntl(
<AddDeleteButtons onAdd={handleAdd} />
);
wrapper.find('EuiButtonIcon').at(0).simulate('click');
const wrapper = shallowWithIntl(<AddDeleteButtons onAdd={handleAdd} />);
wrapper
.find('EuiButtonIcon')
.at(0)
.simulate('click');
expect(handleAdd.calledOnce).to.equal(true);
});
it('calls onDelete={handleDelete}', () => {
const handleDelete = sinon.spy();
const wrapper = shallowWithIntl(
<AddDeleteButtons onDelete={handleDelete} />
);
wrapper.find('EuiButtonIcon').at(1).simulate('click');
const wrapper = shallowWithIntl(<AddDeleteButtons onDelete={handleDelete} />);
wrapper
.find('EuiButtonIcon')
.at(1)
.simulate('click');
expect(handleDelete.calledOnce).to.equal(true);
});
it('calls onClone={handleClone}', () => {
const handleClone = sinon.spy();
const wrapper = shallowWithIntl(
<AddDeleteButtons onClone={handleClone} />
);
wrapper.find('EuiButtonIcon').at(0).simulate('click');
const wrapper = shallowWithIntl(<AddDeleteButtons onClone={handleClone} />);
wrapper
.find('EuiButtonIcon')
.at(0)
.simulate('click');
expect(handleClone.calledOnce).to.equal(true);
});
it('disableDelete={true}', () => {
const wrapper = shallowWithIntl(
<AddDeleteButtons disableDelete={true} />
);
const wrapper = shallowWithIntl(<AddDeleteButtons disableDelete={true} />);
expect(wrapper.find({ text: 'Delete' })).to.have.length(0);
});
it('disableAdd={true}', () => {
const wrapper = shallowWithIntl(
<AddDeleteButtons disableAdd={true} />
);
const wrapper = shallowWithIntl(<AddDeleteButtons disableAdd={true} />);
expect(wrapper.find({ text: 'Add' })).to.have.length(0);
});
it('should not display clone by default', () => {
const wrapper = shallowWithIntl(
<AddDeleteButtons />
);
const wrapper = shallowWithIntl(<AddDeleteButtons />);
expect(wrapper.find({ text: 'Clone' })).to.have.length(0);
});
it('should not display clone when disableAdd={true}', () => {
const fn = sinon.spy();
const wrapper = shallowWithIntl(
<AddDeleteButtons onClone={fn} disableAdd={true} />
);
const wrapper = shallowWithIntl(<AddDeleteButtons onClone={fn} disableAdd={true} />);
expect(wrapper.find({ text: 'Clone' })).to.have.length(0);
});
});

View file

@ -42,10 +42,7 @@ export function Agg(props) {
};
return (
<div
className={props.className}
style={style}
>
<div className={props.className} style={style}>
<Component
fields={props.fields}
disableDelete={props.disableDelete}

View file

@ -38,21 +38,33 @@ function AggRowUi(props) {
return (
<div className="tvbAggRow">
<EuiFlexGroup data-test-subj="aggRow" gutterSize="s" alignItems="flexStart" responsive={false}>
<EuiFlexGroup
data-test-subj="aggRow"
gutterSize="s"
alignItems="flexStart"
responsive={false}
>
<EuiFlexItem grow={false}>
<EuiIcon className="tvbAggRow__visibilityIcon" type={iconType} color={iconColor} />
</EuiFlexItem>
<EuiFlexItem className="tvbAggRow__children">
{props.children}
</EuiFlexItem>
<EuiFlexItem className="tvbAggRow__children">{props.children}</EuiFlexItem>
<SeriesDragHandler dragHandleProps={props.dragHandleProps} hideDragHandler={props.disableDelete} />
<SeriesDragHandler
dragHandleProps={props.dragHandleProps}
hideDragHandler={props.disableDelete}
/>
<EuiFlexItem grow={false}>
<AddDeleteButtons
testSubj="addMetric"
addTooltip={intl.formatMessage({ id: 'tsvb.aggRow.addMetricButtonTooltip', defaultMessage: 'Add Metric' })}
deleteTooltip={intl.formatMessage({ id: 'tsvb.aggRow.deleteMetricButtonTooltip', defaultMessage: 'Delete Metric' })}
addTooltip={intl.formatMessage({
id: 'tsvb.aggRow.addMetricButtonTooltip',
defaultMessage: 'Add Metric',
})}
deleteTooltip={intl.formatMessage({
id: 'tsvb.aggRow.deleteMetricButtonTooltip',
defaultMessage: 'Delete Metric',
})}
onAdd={props.onAdd}
onDelete={props.onDelete}
disableDelete={props.disableDelete}

View file

@ -30,137 +30,179 @@ const metricAggs = [
value: 'avg',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.cardinalityLabel', { defaultMessage: 'Cardinality' }),
label: i18n.translate('tsvb.aggSelect.metricsAggs.cardinalityLabel', {
defaultMessage: 'Cardinality',
}),
value: 'cardinality',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.countLabel', { defaultMessage: 'Count' }),
value: 'count'
value: 'count',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.filterRatioLabel', { defaultMessage: 'Filter Ratio' }),
value: 'filter_ratio'
label: i18n.translate('tsvb.aggSelect.metricsAggs.filterRatioLabel', {
defaultMessage: 'Filter Ratio',
}),
value: 'filter_ratio',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.maxLabel', { defaultMessage: 'Max' }),
value: 'max'
value: 'max',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.minLabel', { defaultMessage: 'Min' }),
value: 'min'
value: 'min',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.percentileLabel', { defaultMessage: 'Percentile' }),
value: 'percentile'
label: i18n.translate('tsvb.aggSelect.metricsAggs.percentileLabel', {
defaultMessage: 'Percentile',
}),
value: 'percentile',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.percentileRankLabel', { defaultMessage: 'Percentile Rank' }),
value: 'percentile_rank'
label: i18n.translate('tsvb.aggSelect.metricsAggs.percentileRankLabel', {
defaultMessage: 'Percentile Rank',
}),
value: 'percentile_rank',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.staticValueLabel', { defaultMessage: 'Static Value' }),
value: 'static'
label: i18n.translate('tsvb.aggSelect.metricsAggs.staticValueLabel', {
defaultMessage: 'Static Value',
}),
value: 'static',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.stdDeviationLabel', { defaultMessage: 'Std. Deviation' }),
value: 'std_deviation'
label: i18n.translate('tsvb.aggSelect.metricsAggs.stdDeviationLabel', {
defaultMessage: 'Std. Deviation',
}),
value: 'std_deviation',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.sumLabel', { defaultMessage: 'Sum' }),
value: 'sum'
value: 'sum',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.sumOfSquaresLabel', { defaultMessage: 'Sum of Squares' }),
value: 'sum_of_squares'
label: i18n.translate('tsvb.aggSelect.metricsAggs.sumOfSquaresLabel', {
defaultMessage: 'Sum of Squares',
}),
value: 'sum_of_squares',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.topHitLabel', { defaultMessage: 'Top Hit' }),
value: 'top_hit'
value: 'top_hit',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.valueCountLabel', { defaultMessage: 'Value Count' }),
value: 'value_count'
label: i18n.translate('tsvb.aggSelect.metricsAggs.valueCountLabel', {
defaultMessage: 'Value Count',
}),
value: 'value_count',
},
{
label: i18n.translate('tsvb.aggSelect.metricsAggs.varianceLabel', { defaultMessage: 'Variance' }),
value: 'variance'
label: i18n.translate('tsvb.aggSelect.metricsAggs.varianceLabel', {
defaultMessage: 'Variance',
}),
value: 'variance',
},
];
const pipelineAggs = [
{
label: i18n.translate('tsvb.aggSelect.pipelineAggs.bucketScriptLabel', { defaultMessage: 'Bucket Script' }),
value: 'calculation'
label: i18n.translate('tsvb.aggSelect.pipelineAggs.bucketScriptLabel', {
defaultMessage: 'Bucket Script',
}),
value: 'calculation',
},
{
label: i18n.translate('tsvb.aggSelect.pipelineAggs.cumulativeSumLabel', { defaultMessage: 'Cumulative Sum' }),
value: 'cumulative_sum'
label: i18n.translate('tsvb.aggSelect.pipelineAggs.cumulativeSumLabel', {
defaultMessage: 'Cumulative Sum',
}),
value: 'cumulative_sum',
},
{
label: i18n.translate('tsvb.aggSelect.pipelineAggs.derivativeLabel', { defaultMessage: 'Derivative' }),
value: 'derivative'
label: i18n.translate('tsvb.aggSelect.pipelineAggs.derivativeLabel', {
defaultMessage: 'Derivative',
}),
value: 'derivative',
},
{
label: i18n.translate('tsvb.aggSelect.pipelineAggs.movingAverageLabel', { defaultMessage: 'Moving Average' }),
value: 'moving_average'
label: i18n.translate('tsvb.aggSelect.pipelineAggs.movingAverageLabel', {
defaultMessage: 'Moving Average',
}),
value: 'moving_average',
},
{
label: i18n.translate('tsvb.aggSelect.pipelineAggs.positiveOnlyLabel', { defaultMessage: 'Positive Only' }),
value: 'positive_only'
label: i18n.translate('tsvb.aggSelect.pipelineAggs.positiveOnlyLabel', {
defaultMessage: 'Positive Only',
}),
value: 'positive_only',
},
{
label: i18n.translate('tsvb.aggSelect.pipelineAggs.serialDifferenceLabel', { defaultMessage: 'Serial Difference' }),
value: 'serial_diff'
label: i18n.translate('tsvb.aggSelect.pipelineAggs.serialDifferenceLabel', {
defaultMessage: 'Serial Difference',
}),
value: 'serial_diff',
},
];
const siblingAggs = [
{
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallAverageLabel', { defaultMessage: 'Overall Average' }),
value: 'avg_bucket' },
{
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallMaxLabel', { defaultMessage: 'Overall Max' }),
value: 'max_bucket'
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallAverageLabel', {
defaultMessage: 'Overall Average',
}),
value: 'avg_bucket',
},
{
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallMinLabel', { defaultMessage: 'Overall Min' }),
value: 'min_bucket'
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallMaxLabel', {
defaultMessage: 'Overall Max',
}),
value: 'max_bucket',
},
{
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallStdDeviationLabel', { defaultMessage: 'Overall Std. Deviation' }),
value: 'std_deviation_bucket'
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallMinLabel', {
defaultMessage: 'Overall Min',
}),
value: 'min_bucket',
},
{
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallSumLabel', { defaultMessage: 'Overall Sum' }),
value: 'sum_bucket'
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallStdDeviationLabel', {
defaultMessage: 'Overall Std. Deviation',
}),
value: 'std_deviation_bucket',
},
{
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallSumOfSquaresLabel', { defaultMessage: 'Overall Sum of Squares' }),
value: 'sum_of_squares_bucket'
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallSumLabel', {
defaultMessage: 'Overall Sum',
}),
value: 'sum_bucket',
},
{
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallVarianceLabel', { defaultMessage: 'Overall Variance' }),
value: 'variance_bucket'
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallSumOfSquaresLabel', {
defaultMessage: 'Overall Sum of Squares',
}),
value: 'sum_of_squares_bucket',
},
{
label: i18n.translate('tsvb.aggSelect.siblingAggs.overallVarianceLabel', {
defaultMessage: 'Overall Variance',
}),
value: 'variance_bucket',
},
];
const specialAggs = [
{
label: i18n.translate('tsvb.aggSelect.specialAggs.seriesAggLabel', { defaultMessage: 'Series Agg' }),
value: 'series_agg'
label: i18n.translate('tsvb.aggSelect.specialAggs.seriesAggLabel', {
defaultMessage: 'Series Agg',
}),
value: 'series_agg',
},
{
label: i18n.translate('tsvb.aggSelect.specialAggs.mathLabel', { defaultMessage: 'Math' }),
value: 'math'
value: 'math',
},
];
const allAggOptions = [
...metricAggs,
...pipelineAggs,
...siblingAggs,
...specialAggs
];
const allAggOptions = [...metricAggs, ...pipelineAggs, ...siblingAggs, ...specialAggs];
function filterByPanelType(panelType) {
return agg => {
@ -176,9 +218,7 @@ function AggSelectUi(props) {
return value === option.value && isMetricEnabled(option.value, uiRestrictions);
});
let enablePipelines = siblings.some(
s => !!metricAggs.find(m => m.value === s.type)
);
let enablePipelines = siblings.some(s => !!metricAggs.find(m => m.value === s.type));
if (siblings.length <= 1) enablePipelines = false;
@ -186,28 +226,41 @@ function AggSelectUi(props) {
if (panelType === 'metrics') {
options = metricAggs;
} else {
const disableSiblingAggs = agg => ({ ...agg, disabled: !enablePipelines || !isMetricEnabled(agg.value, uiRestrictions) });
const disableSiblingAggs = agg => ({
...agg,
disabled: !enablePipelines || !isMetricEnabled(agg.value, uiRestrictions),
});
options = [
{
label: intl.formatMessage({ id: 'tsvb.aggSelect.aggGroups.metricAggLabel', defaultMessage: 'Metric Aggregations' }),
options: metricAggs
.map(agg => ({ ...agg, disabled: !isMetricEnabled(agg.value, uiRestrictions) })),
label: intl.formatMessage({
id: 'tsvb.aggSelect.aggGroups.metricAggLabel',
defaultMessage: 'Metric Aggregations',
}),
options: metricAggs.map(agg => ({
...agg,
disabled: !isMetricEnabled(agg.value, uiRestrictions),
})),
},
{
label: intl.formatMessage({
id: 'tsvb.aggSelect.aggGroups.parentPipelineAggLabel', defaultMessage: 'Parent Pipeline Aggregations' }),
options: pipelineAggs
.filter(filterByPanelType(panelType))
.map(disableSiblingAggs),
id: 'tsvb.aggSelect.aggGroups.parentPipelineAggLabel',
defaultMessage: 'Parent Pipeline Aggregations',
}),
options: pipelineAggs.filter(filterByPanelType(panelType)).map(disableSiblingAggs),
},
{
label: intl.formatMessage({
id: 'tsvb.aggSelect.aggGroups.siblingPipelineAggLabel', defaultMessage: 'Sibling Pipeline Aggregations' }),
id: 'tsvb.aggSelect.aggGroups.siblingPipelineAggLabel',
defaultMessage: 'Sibling Pipeline Aggregations',
}),
options: siblingAggs.map(disableSiblingAggs),
},
{
label: intl.formatMessage({ id: 'tsvb.aggSelect.aggGroups.specialAggLabel', defaultMessage: 'Special Aggregations' }),
label: intl.formatMessage({
id: 'tsvb.aggSelect.aggGroups.specialAggLabel',
defaultMessage: 'Special Aggregations',
}),
options: specialAggs.map(disableSiblingAggs),
},
];
@ -222,7 +275,10 @@ function AggSelectUi(props) {
<div data-test-subj="aggSelector">
<EuiComboBox
isClearable={false}
placeholder={intl.formatMessage({ id: 'tsvb.aggSelect.selectAggPlaceholder', defaultMessage: 'Select aggregation' })}
placeholder={intl.formatMessage({
id: 'tsvb.aggSelect.selectAggPlaceholder',
defaultMessage: 'Select aggregation',
})}
options={options}
selectedOptions={selectedOptions}
onChange={handleChange}

View file

@ -30,7 +30,6 @@ import { handleAdd, handleDelete } from '../lib/collection_actions';
const DROPPABLE_ID = 'aggs_dnd';
export class Aggs extends PureComponent {
render() {
const { panel, model, fields, uiRestrictions } = this.props;
const list = model.metrics;
@ -38,11 +37,7 @@ export class Aggs extends PureComponent {
const onChange = seriesChangeHandler(this.props, list);
return (
<EuiDroppable
droppableId={`${DROPPABLE_ID}:${model.id}`}
type="MICRO"
spacing="s"
>
<EuiDroppable droppableId={`${DROPPABLE_ID}:${model.id}`} type="MICRO" spacing="s">
{list.map((row, idx) => (
<EuiDraggable
spacing="s"

View file

@ -41,12 +41,13 @@ import {
} from '@elastic/eui';
export class CalculationAgg extends Component {
componentWillMount() {
if (!this.props.model.variables) {
this.props.onChange(_.assign({}, this.props.model, {
variables: [{ id: uuid.v1() }]
}));
this.props.onChange(
_.assign({}, this.props.model, {
variables: [{ id: uuid.v1() }],
})
);
}
}
@ -90,10 +91,7 @@ export class CalculationAgg extends Component {
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('variables')}>
<FormattedMessage
id="tsvb.calculation.variablesLabel"
defaultMessage="Variables"
/>
<FormattedMessage id="tsvb.calculation.variablesLabel" defaultMessage="Variables" />
</EuiFormLabel>
<CalculationVars
id={htmlId('variables')}
@ -107,10 +105,12 @@ export class CalculationAgg extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('painless')}
label={(<FormattedMessage
id="tsvb.calculation.painlessScriptLabel"
defaultMessage="Painless Script"
/>)}
label={
<FormattedMessage
id="tsvb.calculation.painlessScriptLabel"
defaultMessage="Painless Script"
/>
}
fullWidth
helpText={
<div>
@ -119,26 +119,21 @@ export class CalculationAgg extends Component {
defaultMessage="Variables are keys on the {params} object, i.e. {paramsName}. To access the bucket
interval (in milliseconds) use {paramsInterval}."
values={{
params: (<EuiCode>params</EuiCode>),
paramsName: (<EuiCode>params.&lt;name&gt;</EuiCode>),
paramsInterval: (<EuiCode>params._interval</EuiCode>)
params: <EuiCode>params</EuiCode>,
paramsName: <EuiCode>params.&lt;name&gt;</EuiCode>,
paramsInterval: <EuiCode>params._interval</EuiCode>,
}}
/>
</div>
}
>
<EuiTextArea
onChange={handleTextChange('script')}
value={model.script}
fullWidth
/>
<EuiTextArea onChange={handleTextChange('script')} value={model.script} fullWidth />
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
</AggRow>
);
}
}
CalculationAgg.propTypes = {

View file

@ -60,10 +60,7 @@ export function CumulativeSumAgg(props) {
<EuiFlexItem>
<EuiFormRow
id={htmlId('metric')}
label={(<FormattedMessage
id="tsvb.cumulativeSum.metricLabel"
defaultMessage="Metric"
/>)}
label={<FormattedMessage id="tsvb.cumulativeSum.metricLabel" defaultMessage="Metric" />}
>
<MetricSelect
onChange={handleSelectChange('field')}
@ -76,7 +73,6 @@ export function CumulativeSumAgg(props) {
</EuiFlexGroup>
</AggRow>
);
}
CumulativeSumAgg.propTypes = {

View file

@ -59,10 +59,7 @@ export const DerivativeAgg = props => {
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
id="tsvb.derivative.aggregationLabel"
defaultMessage="Aggregation"
/>
<FormattedMessage id="tsvb.derivative.aggregationLabel" defaultMessage="Aggregation" />
</EuiFormLabel>
<AggSelect
id={htmlId('aggregation')}
@ -76,10 +73,7 @@ export const DerivativeAgg = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('metric')}
label={(<FormattedMessage
id="tsvb.derivative.metricLabel"
defaultMessage="Metric"
/>)}
label={<FormattedMessage id="tsvb.derivative.metricLabel" defaultMessage="Metric" />}
fullWidth
>
<MetricSelect
@ -94,18 +88,16 @@ export const DerivativeAgg = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('units')}
label={(<FormattedMessage
id="tsvb.derivative.unitsLabel"
defaultMessage="Units (1s, 1m, etc)"
description="1s and 1m are required values and must not be translated."
/>)}
label={
<FormattedMessage
id="tsvb.derivative.unitsLabel"
defaultMessage="Units (1s, 1m, etc)"
description="1s and 1m are required values and must not be translated."
/>
}
fullWidth
>
<EuiFieldText
onChange={handleTextChange('unit')}
value={model.unit}
fullWidth
/>
<EuiFieldText onChange={handleTextChange('unit')} value={model.unit} fullWidth />
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -19,9 +19,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import {
EuiComboBox,
} from '@elastic/eui';
import { EuiComboBox } from '@elastic/eui';
import { injectI18n } from '@kbn/i18n/react';
import { isFieldEnabled } from '../../lib/check_ui_restrictions';
import { i18n } from '@kbn/i18n';
@ -41,35 +39,39 @@ function FieldSelectUi({
uiRestrictions,
...rest
}) {
if (type === 'count') {
return null;
}
const selectedOptions = [];
const options = Object.values((fields[indexPattern] || []).reduce((acc, field) => {
if (isFieldTypeEnabled(restrict, field.type) && isFieldEnabled(field.name, type, uiRestrictions)) {
const item = {
label: field.name,
value: field.name
};
if (acc[field.type]) {
acc[field.type].options.push(item);
} else {
acc[field.type] = {
options: [item],
label: field.type,
const options = Object.values(
(fields[indexPattern] || []).reduce((acc, field) => {
if (
isFieldTypeEnabled(restrict, field.type) &&
isFieldEnabled(field.name, type, uiRestrictions)
) {
const item = {
label: field.name,
value: field.name,
};
if (acc[field.type]) {
acc[field.type].options.push(item);
} else {
acc[field.type] = {
options: [item],
label: field.type,
};
}
if (value === item.value) {
selectedOptions.push(item);
}
}
if (value === item.value) {
selectedOptions.push(item);
}
}
return acc;
}, {}));
return acc;
}, {})
);
if (onChange && value && !selectedOptions.length) {
onChange();
@ -94,7 +96,7 @@ FieldSelectUi.defaultProps = {
restrict: [],
placeholder: i18n.translate('tsvb.fieldSelect.selectFieldPlaceholder', {
defaultMessage: 'Select field...',
})
}),
};
FieldSelectUi.propTypes = {

View file

@ -39,21 +39,18 @@ import { ES_TYPES } from '../../../common/es_types';
import { METRIC_TYPES } from '../../../common/metric_types';
export const FilterRatioAgg = props => {
const {
series,
fields,
panel
} = props;
const { series, fields, panel } = props;
const handleChange = createChangeHandler(props.onChange, props.model);
const handleSelectChange = createSelectHandler(handleChange);
const handleTextChange = createTextHandler(handleChange);
const indexPattern = series.override_index_pattern && series.series_index_pattern || panel.index_pattern;
const indexPattern =
(series.override_index_pattern && series.series_index_pattern) || panel.index_pattern;
const defaults = {
numerator: '*',
denominator: '*',
metric_agg: 'count'
metric_agg: 'count',
};
const model = { ...defaults, ...props.model };
@ -71,13 +68,9 @@ export const FilterRatioAgg = props => {
dragHandleProps={props.dragHandleProps}
>
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
id="tsvb.filterRatio.aggregationLabel"
defaultMessage="Aggregation"
/>
<FormattedMessage id="tsvb.filterRatio.aggregationLabel" defaultMessage="Aggregation" />
</EuiFormLabel>
<AggSelect
id={htmlId('aggregation')}
@ -91,39 +84,32 @@ export const FilterRatioAgg = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('numerator')}
label={(<FormattedMessage
id="tsvb.filterRatio.numeratorLabel"
defaultMessage="Numerator"
/>)}
label={
<FormattedMessage id="tsvb.filterRatio.numeratorLabel" defaultMessage="Numerator" />
}
>
<EuiFieldText
onChange={handleTextChange('numerator')}
value={model.numerator}
/>
<EuiFieldText onChange={handleTextChange('numerator')} value={model.numerator} />
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
id={htmlId('denominator')}
label={(<FormattedMessage
id="tsvb.filterRatio.denominatorLabel"
defaultMessage="Denominator"
/>)}
label={
<FormattedMessage
id="tsvb.filterRatio.denominatorLabel"
defaultMessage="Denominator"
/>
}
>
<EuiFieldText
onChange={handleTextChange('denominator')}
value={model.denominator}
/>
<EuiFieldText onChange={handleTextChange('denominator')} value={model.denominator} />
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m" />
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('metric')}>
<FormattedMessage
@ -140,14 +126,11 @@ export const FilterRatioAgg = props => {
/>
</EuiFlexItem>
{ model.metric_agg !== 'count' ? (
{model.metric_agg !== 'count' ? (
<EuiFlexItem>
<EuiFormRow
id={htmlId('aggField')}
label={(<FormattedMessage
id="tsvb.filterRatio.fieldLabel"
defaultMessage="Field"
/>)}
label={<FormattedMessage id="tsvb.filterRatio.fieldLabel" defaultMessage="Field" />}
>
<FieldSelect
fields={fields}
@ -158,8 +141,8 @@ export const FilterRatioAgg = props => {
onChange={handleSelectChange('field')}
/>
</EuiFormRow>
</EuiFlexItem>) : null }
</EuiFlexItem>
) : null}
</EuiFlexGroup>
</AggRow>
);

View file

@ -74,10 +74,7 @@ export class MathAgg extends Component {
<EuiFlexGroup direction="column" gutterSize="l">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
id="tsvb.math.aggregationLabel"
defaultMessage="Aggregation"
/>
<FormattedMessage id="tsvb.math.aggregationLabel" defaultMessage="Aggregation" />
</EuiFormLabel>
<AggSelect
id={htmlId('aggregation')}
@ -89,10 +86,7 @@ export class MathAgg extends Component {
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('variables')}>
<FormattedMessage
id="tsvb.math.variablesLabel"
defaultMessage="Variables"
/>
<FormattedMessage id="tsvb.math.variablesLabel" defaultMessage="Variables" />
</EuiFormLabel>
<CalculationVars
id={htmlId('variables')}
@ -107,38 +101,40 @@ export class MathAgg extends Component {
<EuiFlexItem>
<EuiFormRow
id="mathExpressionInput"
label={(<FormattedMessage
id="tsvb.math.expressionLabel"
defaultMessage="Expression"
/>)}
label={
<FormattedMessage id="tsvb.math.expressionLabel" defaultMessage="Expression" />
}
fullWidth
helpText={(<FormattedMessage
id="tsvb.math.expressionDescription"
defaultMessage="This field uses basic math expressions (see {link}) - Variables are keys on the {params} object,
helpText={
<FormattedMessage
id="tsvb.math.expressionDescription"
defaultMessage="This field uses basic math expressions (see {link}) - Variables are keys on the {params} object,
i.e. {paramsName} To access all the data use {paramsValues} for an array of the values and {paramsTimestamps} for
an array of the timestamps. {paramsTimestamp} is available for the current bucket&apos;s timestamp,
{paramsIndex} is available for the current bucket&apos;s index, and {paramsInterval}s available for
an array of the timestamps. {paramsTimestamp} is available for the current bucket's timestamp,
{paramsIndex} is available for the current bucket's index, and {paramsInterval}s available for
the interval in milliseconds."
values={{
link: (
<EuiLink
href="https://github.com/elastic/tinymath/blob/master/docs/functions.md"
target="_blank"
>
<FormattedMessage
id="tsvb.math.expressionDescription.tinyMathLinkText"
defaultMessage="TinyMath"
/>
</EuiLink>),
params: (<EuiCode>params</EuiCode>),
paramsName: (<EuiCode>params.&lt;name&gt;</EuiCode>),
paramsValues: (<EuiCode>params._all.&lt;name&gt;.values</EuiCode>),
paramsTimestamps: (<EuiCode>params._all.&lt;name&gt;.timestamps</EuiCode>),
paramsTimestamp: (<EuiCode>params._timestamp</EuiCode>),
paramsIndex: (<EuiCode>params._index</EuiCode>),
paramsInterval: (<EuiCode>params._interval</EuiCode>)
}}
/>)}
values={{
link: (
<EuiLink
href="https://github.com/elastic/tinymath/blob/master/docs/functions.md"
target="_blank"
>
<FormattedMessage
id="tsvb.math.expressionDescription.tinyMathLinkText"
defaultMessage="TinyMath"
/>
</EuiLink>
),
params: <EuiCode>params</EuiCode>,
paramsName: <EuiCode>params.&lt;name&gt;</EuiCode>,
paramsValues: <EuiCode>params._all.&lt;name&gt;.values</EuiCode>,
paramsTimestamps: <EuiCode>params._all.&lt;name&gt;.timestamps</EuiCode>,
paramsTimestamp: <EuiCode>params._timestamp</EuiCode>,
paramsIndex: <EuiCode>params._index</EuiCode>,
paramsInterval: <EuiCode>params._interval</EuiCode>,
}}
/>
}
>
<EuiTextArea
data-test-subj="mathExpression"

View file

@ -21,9 +21,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import { includes } from 'lodash';
import { injectI18n } from '@kbn/i18n/react';
import {
EuiComboBox,
} from '@elastic/eui';
import { EuiComboBox } from '@elastic/eui';
import { calculateSiblings } from '../lib/calculate_siblings';
import { calculateLabel } from '../../../common/calculate_label';
import { basicAggs } from '../../../common/basic_aggs';
@ -46,11 +44,7 @@ function createTypeFilter(restrict, exclude) {
export function filterRows(includeSiblings) {
return row => {
if (includeSiblings) {
return (
!/^series/.test(row.type) &&
!/^percentile/.test(row.type) &&
row.type !== 'math'
);
return !/^series/.test(row.type) && !/^percentile/.test(row.type) && row.type !== 'math';
}
return (
!/_bucket$/.test(row.type) &&
@ -62,7 +56,19 @@ export function filterRows(includeSiblings) {
}
function MetricSelectUi(props) {
const { additionalOptions, restrict, metric, metrics, onChange, value, exclude, includeSiblings, clearable, intl, ...rest } = props;
const {
additionalOptions,
restrict,
metric,
metrics,
onChange,
value,
exclude,
includeSiblings,
clearable,
intl,
...rest
} = props;
const calculatedMetrics = metrics.filter(createTypeFilter(restrict, exclude));
@ -116,7 +122,10 @@ function MetricSelectUi(props) {
return (
<EuiComboBox
placeholder={intl.formatMessage({ id: 'tsvb.metricSelect.selectMetricPlaceholder', defaultMessage: 'Select metric…' })}
placeholder={intl.formatMessage({
id: 'tsvb.metricSelect.selectMetricPlaceholder',
defaultMessage: 'Select metric…',
})}
options={allOptions}
selectedOptions={selectedOptions}
onChange={onChange}

View file

@ -45,7 +45,7 @@ const MovingAverageAggUi = props => {
settings: '',
minimize: 0,
window: '',
model: 'simple'
model: 'simple',
};
const model = { ...defaults, ...props.model };
const handleChange = createChangeHandler(props.onChange, model);
@ -54,31 +54,42 @@ const MovingAverageAggUi = props => {
const handleNumberChange = createNumberHandler(handleChange);
const modelOptions = [
{
label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.simpleLabel', defaultMessage: 'Simple' }),
value: 'simple'
},
{
label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.linearLabel', defaultMessage: 'Linear' }),
value: 'linear'
label: intl.formatMessage({
id: 'tsvb.movingAverage.modelOptions.simpleLabel',
defaultMessage: 'Simple',
}),
value: 'simple',
},
{
label: intl.formatMessage({
id: 'tsvb.movingAverage.modelOptions.exponentiallyWeightedLabel', defaultMessage: 'Exponentially Weighted' }),
value: 'ewma'
id: 'tsvb.movingAverage.modelOptions.linearLabel',
defaultMessage: 'Linear',
}),
value: 'linear',
},
{
label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.holtLinearLabel', defaultMessage: 'Holt-Linear' }),
value: 'holt'
label: intl.formatMessage({
id: 'tsvb.movingAverage.modelOptions.exponentiallyWeightedLabel',
defaultMessage: 'Exponentially Weighted',
}),
value: 'ewma',
},
{
label: intl.formatMessage({ id: 'tsvb.movingAverage.modelOptions.holtWintersLabel', defaultMessage: 'Holt-Winters' }),
value: 'holt_winters'
}
];
const minimizeOptions = [
{ label: 'True', value: 1 },
{ label: 'False', value: 0 }
label: intl.formatMessage({
id: 'tsvb.movingAverage.modelOptions.holtLinearLabel',
defaultMessage: 'Holt-Linear',
}),
value: 'holt',
},
{
label: intl.formatMessage({
id: 'tsvb.movingAverage.modelOptions.holtWintersLabel',
defaultMessage: 'Holt-Winters',
}),
value: 'holt_winters',
},
];
const minimizeOptions = [{ label: 'True', value: 1 }, { label: 'False', value: 0 }];
const htmlId = htmlIdGenerator();
const selectedModelOption = modelOptions.find(option => {
return model.model === option.value;
@ -115,10 +126,7 @@ const MovingAverageAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('metric')}
label={(<FormattedMessage
id="tsvb.movingAverage.metricLabel"
defaultMessage="Metric"
/>)}
label={<FormattedMessage id="tsvb.movingAverage.metricLabel" defaultMessage="Metric" />}
>
<MetricSelect
onChange={handleSelectChange('field')}
@ -136,14 +144,14 @@ const MovingAverageAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('model')}
label={(<FormattedMessage
id="tsvb.movingAverage.modelLabel"
defaultMessage="Model"
/>)}
label={<FormattedMessage id="tsvb.movingAverage.modelLabel" defaultMessage="Model" />}
>
<EuiComboBox
isClearable={false}
placeholder={intl.formatMessage({ id: 'tsvb.movingAverage.model.selectPlaceholder', defaultMessage: 'Select' })}
placeholder={intl.formatMessage({
id: 'tsvb.movingAverage.model.selectPlaceholder',
defaultMessage: 'Select',
})}
options={modelOptions}
selectedOptions={selectedModelOption ? [selectedModelOption] : []}
onChange={handleSelectChange('model')}
@ -154,10 +162,12 @@ const MovingAverageAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('windowSize')}
label={(<FormattedMessage
id="tsvb.movingAverage.windowSizeLabel"
defaultMessage="Window Size"
/>)}
label={
<FormattedMessage
id="tsvb.movingAverage.windowSizeLabel"
defaultMessage="Window Size"
/>
}
>
{/*
EUITODO: The following input couldn't be converted to EUI because of type mis-match.
@ -174,13 +184,15 @@ const MovingAverageAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('minimize')}
label={(<FormattedMessage
id="tsvb.movingAverage.minimizeLabel"
defaultMessage="Minimize"
/>)}
label={
<FormattedMessage id="tsvb.movingAverage.minimizeLabel" defaultMessage="Minimize" />
}
>
<EuiComboBox
placeholder={intl.formatMessage({ id: 'tsvb.movingAverage.minimize.selectPlaceholder', defaultMessage: 'Select' })}
placeholder={intl.formatMessage({
id: 'tsvb.movingAverage.minimize.selectPlaceholder',
defaultMessage: 'Select',
})}
options={minimizeOptions}
selectedOptions={selectedMinimizeOption ? [selectedMinimizeOption] : []}
onChange={handleSelectChange('minimize')}
@ -191,10 +203,9 @@ const MovingAverageAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('predict')}
label={(<FormattedMessage
id="tsvb.movingAverage.predictLabel"
defaultMessage="Predict"
/>)}
label={
<FormattedMessage id="tsvb.movingAverage.predictLabel" defaultMessage="Predict" />
}
>
{/*
EUITODO: The following input couldn't be converted to EUI because of type mis-match.
@ -216,25 +227,20 @@ const MovingAverageAggUi = props => {
<EuiFormRow
fullWidth
id={htmlId('settings')}
label={(<FormattedMessage
id="tsvb.movingAverage.settingsLabel"
defaultMessage="Settings"
/>)}
label={
<FormattedMessage id="tsvb.movingAverage.settingsLabel" defaultMessage="Settings" />
}
helpText={
<span>
<FormattedMessage
id="tsvb.movingAverage.settingsDescription"
defaultMessage="{keyValue} space-delimited"
values={{ keyValue: (<EuiCode>Key=Value</EuiCode>) }}
values={{ keyValue: <EuiCode>Key=Value</EuiCode> }}
/>
</span>
}
>
<EuiTextArea
onChange={handleTextChange('settings')}
value={model.settings}
fullWidth
/>
<EuiTextArea onChange={handleTextChange('settings')} value={model.settings} fullWidth />
</EuiFormRow>
</EuiFlexItem>
</AggRow>

View file

@ -23,9 +23,6 @@ import _ from 'lodash';
import { AggSelect } from './agg_select';
import { FieldSelect } from './field_select';
import { AggRow } from './agg_row';
import { collectionActions } from '../lib/collection_actions';
import { AddDeleteButtons } from '../add_delete_buttons';
import uuid from 'uuid';
import { createChangeHandler } from '../lib/create_change_handler';
import { createSelectHandler } from '../lib/create_select_handler';
import {
@ -34,186 +31,24 @@ import {
EuiFlexGroup,
EuiFlexItem,
EuiFormLabel,
EuiComboBox,
EuiFieldNumber,
EuiFormRow,
} from '@elastic/eui';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { FormattedMessage } from '@kbn/i18n/react';
import { ES_TYPES } from '../../../common/es_types';
const newPercentile = (opts) => {
return _.assign({ id: uuid.v1(), mode: 'line', shade: 0.2 }, opts);
};
import { Percentiles, newPercentile } from './percentile_ui';
const RESTRICT_FIELDS = [ES_TYPES.NUMBER];
class PercentilesUi extends Component {
handleTextChange(item, name) {
return (e) => {
const handleChange = collectionActions.handleChange.bind(null, this.props);
const part = {};
part[name] = _.get(e, '[0].value', _.get(e, 'target.value'));
handleChange(_.assign({}, item, part));
};
}
renderRow = (row, i, items) => {
const defaults = { value: '', percentile: '', shade: '' };
const model = { ...defaults, ...row };
const { intl, panel } = this.props;
const percentileFieldNumber = (
<EuiFlexItem grow={false}>
<EuiFieldNumber
aria-label={intl.formatMessage({ id: 'tsvb.percentile.percentileAriaLabel', defaultMessage: 'Percentile' })}
placeholder={0}
max={100}
min={0}
step={1}
onChange={this.handleTextChange(model, 'value')}
value={model.value === '' ? '' : Number(model.value)}
/>
</EuiFlexItem>
);
if (panel.type === 'table') {
return percentileFieldNumber;
}
const handleAdd = collectionActions.handleAdd.bind(null, this.props, newPercentile);
const handleDelete = collectionActions.handleDelete.bind(null, this.props, model);
const modeOptions = [
{
label: intl.formatMessage({ id: 'tsvb.percentile.modeOptions.lineLabel', defaultMessage: 'Line' }),
value: 'line'
},
{
label: intl.formatMessage({ id: 'tsvb.percentile.modeOptions.bandLabel', defaultMessage: 'Band' }),
value: 'band'
}
];
const optionsStyle = {};
if (model.mode === 'line') {
optionsStyle.display = 'none';
}
const labelStyle = { marginBottom: 0 };
const htmlId = htmlIdGenerator(model.id);
const selectedModeOption = modeOptions.find(option => {
return model.mode === option.value;
});
return (
<EuiFlexItem key={model.id}>
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="s">
{ percentileFieldNumber }
<EuiFlexItem grow={false}>
<EuiFormLabel style={labelStyle} htmlFor={htmlId('mode')}>
<FormattedMessage
id="tsvb.percentile.modeLabel"
defaultMessage="Mode:"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiComboBox
isClearable={false}
id={htmlId('mode')}
options={modeOptions}
selectedOptions={selectedModeOption ? [selectedModeOption] : []}
onChange={this.handleTextChange(model, 'mode')}
singleSelection={{ asPlainText: true }}
/>
</EuiFlexItem>
<EuiFlexItem style={optionsStyle} grow={false}>
<EuiFormLabel style={labelStyle} htmlFor={htmlId('fillTo')}>
<FormattedMessage
id="tsvb.percentile.fillToLabel"
defaultMessage="Fill to:"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem style={optionsStyle} grow={false}>
<EuiFieldNumber
id={htmlId('fillTo')}
step={1}
onChange={this.handleTextChange(model, 'percentile')}
value={Number(model.percentile)}
/>
</EuiFlexItem>
<EuiFlexItem style={optionsStyle} grow={false}>
<EuiFormLabel style={labelStyle} htmlFor={htmlId('shade')}>
<FormattedMessage
id="tsvb.percentile.shadeLabel"
defaultMessage="Shade (0 to 1):"
/>
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem style={optionsStyle} grow={false}>
<EuiFieldNumber
id={htmlId('shade')}
style={optionsStyle}
step={0.1}
onChange={this.handleTextChange(model, 'shade')}
value={Number(model.shade)}
/>
</EuiFlexItem>
<EuiFlexItem>
<AddDeleteButtons
onAdd={handleAdd}
onDelete={handleDelete}
disableDelete={items.length < 2}
responsive={false}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
);
}
render() {
const { model, name, panel } = this.props;
if (!model[name]) return (<div/>);
let rows;
if (panel.type === 'table') {
rows = this.renderRow(_.last(model[name]));
} else {
rows = model[name].map(this.renderRow);
}
return (
<EuiFlexGroup direction="column" gutterSize="s">
{ rows }
</EuiFlexGroup>
);
}
}
PercentilesUi.defaultProps = {
name: 'percentile'
};
PercentilesUi.propTypes = {
name: PropTypes.string,
model: PropTypes.object,
panel: PropTypes.object,
onChange: PropTypes.func
};
const Percentiles = injectI18n(PercentilesUi);
export class PercentileAgg extends Component { // eslint-disable-line react/no-multi-comp
export class PercentileAgg extends Component {
// eslint-disable-line react/no-multi-comp
componentWillMount() {
if (!this.props.model.percentiles) {
this.props.onChange(_.assign({}, this.props.model, {
percentiles: [newPercentile({ value: 50 })]
}));
this.props.onChange(
_.assign({}, this.props.model, {
percentiles: [newPercentile({ value: 50 })],
})
);
}
}
@ -222,7 +57,8 @@ export class PercentileAgg extends Component { // eslint-disable-line react/no-m
const handleChange = createChangeHandler(this.props.onChange, model);
const handleSelectChange = createSelectHandler(handleChange);
const indexPattern = series.override_index_pattern && series.series_index_pattern || panel.index_pattern;
const indexPattern =
(series.override_index_pattern && series.series_index_pattern) || panel.index_pattern;
const htmlId = htmlIdGenerator();
return (
@ -253,10 +89,7 @@ export class PercentileAgg extends Component { // eslint-disable-line react/no-m
<EuiFlexItem>
<EuiFormRow
id={htmlId('field')}
label={(<FormattedMessage
id="tsvb.percentile.fieldLabel"
defaultMessage="Field"
/>)}
label={<FormattedMessage id="tsvb.percentile.fieldLabel" defaultMessage="Field" />}
>
<FieldSelect
fields={fields}
@ -272,17 +105,10 @@ export class PercentileAgg extends Component { // eslint-disable-line react/no-m
<EuiSpacer size="m" />
<Percentiles
onChange={handleChange}
name="percentiles"
model={model}
panel={panel}
/>
<Percentiles onChange={handleChange} name="percentiles" model={model} panel={panel} />
</AggRow>
);
}
}
PercentileAgg.propTypes = {

View file

@ -31,30 +31,21 @@ import {
import { AddDeleteButtons } from '../../add_delete_buttons';
export const MultiValueRow = ({
model,
onChange,
onDelete,
onAdd,
disableAdd,
disableDelete,
}) => {
export const MultiValueRow = ({ model, onChange, onDelete, onAdd, disableAdd, disableDelete }) => {
const htmlId = htmlIdGenerator();
const onFieldNumberChange = event => onChange({
...model,
value: get(event, 'target.value')
});
const onFieldNumberChange = event =>
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="tsvb.multivalueRow.valueLabel"
defaultMessage="Value:"
/>
<FormattedMessage id="tsvb.multivalueRow.valueLabel" defaultMessage="Value:" />
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
@ -73,7 +64,7 @@ export const MultiValueRow = ({
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer/>
<EuiSpacer />
</div>
);
};
@ -93,4 +84,3 @@ MultiValueRow.propTypes = {
defaultAddValue: PropTypes.string,
disableDelete: PropTypes.bool,
};

View file

@ -45,16 +45,19 @@ export const PercentileRankAgg = props => {
const defaults = { values: [''] };
const model = { ...defaults, ...props.model };
const indexPattern = series.override_index_pattern && series.series_index_pattern || panel.index_pattern;
const indexPattern =
(series.override_index_pattern && series.series_index_pattern) || panel.index_pattern;
const htmlId = htmlIdGenerator();
const isTablePanel = panel.type === 'table';
const handleChange = createChangeHandler(props.onChange, model);
const handleSelectChange = createSelectHandler(handleChange);
const handlePercentileRankValuesChange = (values) => {
handleChange(assign({}, model, {
values,
}));
const handlePercentileRankValuesChange = values => {
handleChange(
assign({}, model, {
values,
})
);
};
return (
@ -85,10 +88,7 @@ export const PercentileRankAgg = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('field')}
label={(<FormattedMessage
id="tsvb.percentileRank.fieldLabel"
defaultMessage="Field"
/>)}
label={<FormattedMessage id="tsvb.percentileRank.fieldLabel" defaultMessage="Field" />}
>
<FieldSelect
fields={fields}
@ -101,7 +101,7 @@ export const PercentileRankAgg = props => {
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer/>
<EuiSpacer />
<PercentileRankValues
disableAdd={isTablePanel}
disableDelete={isTablePanel}

View file

@ -20,9 +20,7 @@ import PropTypes from 'prop-types';
import React from 'react';
import { last } from 'lodash';
import {
EuiFlexGroup,
} from '@elastic/eui';
import { EuiFlexGroup } from '@elastic/eui';
import { MultiValueRow } from './multi_value_row';
export const PercentileRankValues = props => {
@ -34,9 +32,8 @@ export const PercentileRankValues = props => {
onChange(model);
};
const onDeleteValue = ({ id }) => onChange(
model.filter((item, currentIndex) => id !== currentIndex),
);
const onDeleteValue = ({ id }) =>
onChange(model.filter((item, currentIndex) => id !== currentIndex));
const onAddValue = () => onChange([...model, '']);
const renderRow = ({ rowModel, disableDelete, disableAdd }) => (
@ -48,28 +45,32 @@ export const PercentileRankValues = props => {
disableDelete={disableDelete}
disableAdd={disableAdd}
model={rowModel}
/>);
/>
);
return (
<EuiFlexGroup direction="column" responsive={false} gutterSize="xs">
{showOnlyLastRow && renderRow({
rowModel: {
id: model.length - 1,
value: last(model),
},
disableAdd: true,
disableDelete: true
})}
{!showOnlyLastRow && model.map((value, id, array) => (
{showOnlyLastRow &&
renderRow({
rowModel: {
id,
value,
id: model.length - 1,
value: last(model),
},
disableAdd,
disableDelete: disableDelete || array.length < 2,
})))}
disableAdd: true,
disableDelete: true,
})}
{!showOnlyLastRow &&
model.map((value, id, array) =>
renderRow({
rowModel: {
id,
value,
},
disableAdd,
disableDelete: disableDelete || array.length < 2,
})
)}
</EuiFlexGroup>
);
};

View file

@ -0,0 +1,195 @@
/*
* 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 PropTypes from 'prop-types';
import React, { Component } from 'react';
import _ from 'lodash';
import { collectionActions } from '../lib/collection_actions';
import { AddDeleteButtons } from '../add_delete_buttons';
import uuid from 'uuid';
import {
htmlIdGenerator,
EuiFlexGroup,
EuiFlexItem,
EuiFormLabel,
EuiComboBox,
EuiFieldNumber,
} from '@elastic/eui';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
export const newPercentile = opts => {
return _.assign({ id: uuid.v1(), mode: 'line', shade: 0.2 }, opts);
};
class PercentilesUi extends Component {
handleTextChange(item, name) {
return e => {
const handleChange = collectionActions.handleChange.bind(null, this.props);
const part = {};
part[name] = _.get(e, '[0].value', _.get(e, 'target.value'));
handleChange(_.assign({}, item, part));
};
}
renderRow = (row, i, items) => {
const defaults = { value: '', percentile: '', shade: '' };
const model = { ...defaults, ...row };
const { intl, panel } = this.props;
const percentileFieldNumber = (
<EuiFlexItem grow={false}>
<EuiFieldNumber
aria-label={intl.formatMessage({
id: 'tsvb.percentile.percentileAriaLabel',
defaultMessage: 'Percentile',
})}
placeholder={0}
max={100}
min={0}
step={1}
onChange={this.handleTextChange(model, 'value')}
value={model.value === '' ? '' : Number(model.value)}
/>
</EuiFlexItem>
);
if (panel.type === 'table') {
return percentileFieldNumber;
}
const handleAdd = collectionActions.handleAdd.bind(null, this.props, newPercentile);
const handleDelete = collectionActions.handleDelete.bind(null, this.props, model);
const modeOptions = [
{
label: intl.formatMessage({
id: 'tsvb.percentile.modeOptions.lineLabel',
defaultMessage: 'Line',
}),
value: 'line',
},
{
label: intl.formatMessage({
id: 'tsvb.percentile.modeOptions.bandLabel',
defaultMessage: 'Band',
}),
value: 'band',
},
];
const optionsStyle = {};
if (model.mode === 'line') {
optionsStyle.display = 'none';
}
const labelStyle = { marginBottom: 0 };
const htmlId = htmlIdGenerator(model.id);
const selectedModeOption = modeOptions.find(option => {
return model.mode === option.value;
});
return (
<EuiFlexItem key={model.id}>
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="s">
{percentileFieldNumber}
<EuiFlexItem grow={false}>
<EuiFormLabel style={labelStyle} htmlFor={htmlId('mode')}>
<FormattedMessage id="tsvb.percentile.modeLabel" defaultMessage="Mode:" />
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiComboBox
isClearable={false}
id={htmlId('mode')}
options={modeOptions}
selectedOptions={selectedModeOption ? [selectedModeOption] : []}
onChange={this.handleTextChange(model, 'mode')}
singleSelection={{ asPlainText: true }}
/>
</EuiFlexItem>
<EuiFlexItem style={optionsStyle} grow={false}>
<EuiFormLabel style={labelStyle} htmlFor={htmlId('fillTo')}>
<FormattedMessage id="tsvb.percentile.fillToLabel" defaultMessage="Fill to:" />
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem style={optionsStyle} grow={false}>
<EuiFieldNumber
id={htmlId('fillTo')}
step={1}
onChange={this.handleTextChange(model, 'percentile')}
value={Number(model.percentile)}
/>
</EuiFlexItem>
<EuiFlexItem style={optionsStyle} grow={false}>
<EuiFormLabel style={labelStyle} htmlFor={htmlId('shade')}>
<FormattedMessage id="tsvb.percentile.shadeLabel" defaultMessage="Shade (0 to 1):" />
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem style={optionsStyle} grow={false}>
<EuiFieldNumber
id={htmlId('shade')}
style={optionsStyle}
step={0.1}
onChange={this.handleTextChange(model, 'shade')}
value={Number(model.shade)}
/>
</EuiFlexItem>
<EuiFlexItem>
<AddDeleteButtons
onAdd={handleAdd}
onDelete={handleDelete}
disableDelete={items.length < 2}
responsive={false}
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFlexItem>
);
};
render() {
const { model, name, panel } = this.props;
if (!model[name]) return <div />;
let rows;
if (panel.type === 'table') {
rows = this.renderRow(_.last(model[name]));
} else {
rows = model[name].map(this.renderRow);
}
return (
<EuiFlexGroup direction="column" gutterSize="s">
{rows}
</EuiFlexGroup>
);
}
}
PercentilesUi.defaultProps = {
name: 'percentile',
};
PercentilesUi.propTypes = {
name: PropTypes.string,
model: PropTypes.object,
panel: PropTypes.object,
onChange: PropTypes.func,
};
export const Percentiles = injectI18n(PercentilesUi);

View file

@ -65,10 +65,7 @@ export const PositiveOnlyAgg = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('metric')}
label={(<FormattedMessage
id="tsvb.positiveOnly.metricLabel"
defaultMessage="Metric"
/>)}
label={<FormattedMessage id="tsvb.positiveOnly.metricLabel" defaultMessage="Metric" />}
>
<MetricSelect
onChange={handleSelectChange('field')}

View file

@ -51,10 +51,7 @@ export const SerialDiffAgg = props => {
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
id="tsvb.serialDiff.aggregationLabel"
defaultMessage="Aggregation"
/>
<FormattedMessage id="tsvb.serialDiff.aggregationLabel" defaultMessage="Aggregation" />
</EuiFormLabel>
<AggSelect
id={htmlId('aggregation')}
@ -67,10 +64,7 @@ export const SerialDiffAgg = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('metric')}
label={(<FormattedMessage
id="tsvb.serialDiff.metricLabel"
defaultMessage="Metric"
/>)}
label={<FormattedMessage id="tsvb.serialDiff.metricLabel" defaultMessage="Metric" />}
>
<MetricSelect
onChange={handleSelectChange('field')}
@ -83,13 +77,15 @@ export const SerialDiffAgg = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('lag')}
label={(<FormattedMessage
id="tsvb.serialDiff.lagLabel"
defaultMessage="Lag"
description="'Lag' refers to the parameter name of the serial diff translation
label={
<FormattedMessage
id="tsvb.serialDiff.lagLabel"
defaultMessage="Lag"
description="'Lag' refers to the parameter name of the serial diff translation
https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-pipeline-serialdiff-aggregation.html.
This should only be translated if there is a reasaonable word explaining what that parameter does."
/>)}
/>
}
>
{/*
EUITODO: The following input couldn't be converted to EUI because of type mis-match.

View file

@ -44,40 +44,67 @@ function SeriesAggUi(props) {
const functionOptions = [
{
label: intl.formatMessage({ id: 'tsvb.seriesAgg.functionOptions.sumLabel', defaultMessage: 'Sum' }),
value: 'sum'
label: intl.formatMessage({
id: 'tsvb.seriesAgg.functionOptions.sumLabel',
defaultMessage: 'Sum',
}),
value: 'sum',
},
{
label: intl.formatMessage({ id: 'tsvb.seriesAgg.functionOptions.maxLabel', defaultMessage: 'Max' }),
value: 'max'
label: intl.formatMessage({
id: 'tsvb.seriesAgg.functionOptions.maxLabel',
defaultMessage: 'Max',
}),
value: 'max',
},
{
label: intl.formatMessage({ id: 'tsvb.seriesAgg.functionOptions.minLabel', defaultMessage: 'Min' }),
value: 'min'
label: intl.formatMessage({
id: 'tsvb.seriesAgg.functionOptions.minLabel',
defaultMessage: 'Min',
}),
value: 'min',
},
{
label: intl.formatMessage({ id: 'tsvb.seriesAgg.functionOptions.avgLabel', defaultMessage: 'Avg' }),
value: 'mean'
label: intl.formatMessage({
id: 'tsvb.seriesAgg.functionOptions.avgLabel',
defaultMessage: 'Avg',
}),
value: 'mean',
},
{
label: intl.formatMessage({ id: 'tsvb.seriesAgg.functionOptions.overallSumLabel', defaultMessage: 'Overall Sum' }),
value: 'overall_sum'
label: intl.formatMessage({
id: 'tsvb.seriesAgg.functionOptions.overallSumLabel',
defaultMessage: 'Overall Sum',
}),
value: 'overall_sum',
},
{
label: intl.formatMessage({ id: 'tsvb.seriesAgg.functionOptions.overallMaxLabel', defaultMessage: 'Overall Max' }),
value: 'overall_max'
label: intl.formatMessage({
id: 'tsvb.seriesAgg.functionOptions.overallMaxLabel',
defaultMessage: 'Overall Max',
}),
value: 'overall_max',
},
{
label: intl.formatMessage({ id: 'tsvb.seriesAgg.functionOptions.overallMinLabel', defaultMessage: 'Overall Min' }),
value: 'overall_min'
label: intl.formatMessage({
id: 'tsvb.seriesAgg.functionOptions.overallMinLabel',
defaultMessage: 'Overall Min',
}),
value: 'overall_min',
},
{
label: intl.formatMessage({ id: 'tsvb.seriesAgg.functionOptions.overallAvgLabel', defaultMessage: 'Overall Avg' }),
value: 'overall_avg'
label: intl.formatMessage({
id: 'tsvb.seriesAgg.functionOptions.overallAvgLabel',
defaultMessage: 'Overall Avg',
}),
value: 'overall_avg',
},
{
label: intl.formatMessage({ id: 'tsvb.seriesAgg.functionOptions.cumulativeSumLabel', defaultMessage: 'Cumulative Sum' }),
value: 'cumulative_sum'
label: intl.formatMessage({
id: 'tsvb.seriesAgg.functionOptions.cumulativeSumLabel',
defaultMessage: 'Cumulative Sum',
}),
value: 'cumulative_sum',
},
];
const selectedFunctionOption = functionOptions.find(option => {
@ -118,10 +145,7 @@ function SeriesAggUi(props) {
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
id="tsvb.seriesAgg.aggregationLabel"
defaultMessage="Aggregation"
/>
<FormattedMessage id="tsvb.seriesAgg.aggregationLabel" defaultMessage="Aggregation" />
</EuiFormLabel>
<AggSelect
id={htmlId('aggregation')}
@ -134,10 +158,7 @@ function SeriesAggUi(props) {
<EuiFlexItem>
<EuiFormRow
id={htmlId('function')}
label={(<FormattedMessage
id="tsvb.seriesAgg.functionLabel"
defaultMessage="Function"
/>)}
label={<FormattedMessage id="tsvb.seriesAgg.functionLabel" defaultMessage="Function" />}
>
<EuiComboBox
options={functionOptions}
@ -150,7 +171,6 @@ function SeriesAggUi(props) {
</EuiFlexGroup>
</AggRow>
);
}
SeriesAggUi.propTypes = {

View file

@ -61,10 +61,7 @@ export const Static = props => {
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
id="tsvb.static.aggregationLabel"
defaultMessage="Aggregation"
/>
<FormattedMessage id="tsvb.static.aggregationLabel" defaultMessage="Aggregation" />
</EuiFormLabel>
<AggSelect
id={htmlId('aggregation')}
@ -77,10 +74,9 @@ export const Static = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('staticValue')}
label={(<FormattedMessage
id="tsvb.static.staticValuesLabel"
defaultMessage="Static Value"
/>)}
label={
<FormattedMessage id="tsvb.static.staticValuesLabel" defaultMessage="Static Value" />
}
>
<EuiFieldNumber
onChange={handleTextChange('value')}

View file

@ -35,7 +35,8 @@ export function StandardAgg(props) {
const handleSelectChange = createSelectHandler(handleChange);
const restrictFields = model.type === METRIC_TYPES.CARDINALITY ? [] : [ES_TYPES.NUMBER];
const indexPattern = series.override_index_pattern && series.series_index_pattern || panel.index_pattern;
const indexPattern =
(series.override_index_pattern && series.series_index_pattern) || panel.index_pattern;
const htmlId = htmlIdGenerator();
return (
@ -50,10 +51,7 @@ export function StandardAgg(props) {
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
id="tsvb.stdAgg.aggregationLabel"
defaultMessage="Aggregation"
/>
<FormattedMessage id="tsvb.stdAgg.aggregationLabel" defaultMessage="Aggregation" />
</EuiFormLabel>
<AggSelect
id={htmlId('aggregation')}
@ -66,33 +64,26 @@ export function StandardAgg(props) {
/>
</EuiFlexItem>
{
model.type !== 'count'
? (
<EuiFlexItem>
<EuiFormRow
id={htmlId('field')}
label={(<FormattedMessage
id="tsvb.stdAgg.fieldLabel"
defaultMessage="Field"
/>)}
fullWidth
>
<FieldSelect
fields={fields}
type={model.type}
restrict={restrictFields}
indexPattern={indexPattern}
value={model.field}
onChange={handleSelectChange('field')}
uiRestrictions={uiRestrictions}
fullWidth
/>
</EuiFormRow>
</EuiFlexItem>
) : null
}
{model.type !== 'count' ? (
<EuiFlexItem>
<EuiFormRow
id={htmlId('field')}
label={<FormattedMessage id="tsvb.stdAgg.fieldLabel" defaultMessage="Field" />}
fullWidth
>
<FieldSelect
fields={fields}
type={model.type}
restrict={restrictFields}
indexPattern={indexPattern}
value={model.field}
onChange={handleSelectChange('field')}
uiRestrictions={uiRestrictions}
fullWidth
/>
</EuiFormRow>
</EuiFlexItem>
) : null}
</EuiFlexGroup>
</AggRow>
);

View file

@ -46,23 +46,35 @@ const StandardDeviationAggUi = props => {
const modeOptions = [
{
label: intl.formatMessage({ id: 'tsvb.stdDeviation.modeOptions.rawLabel', defaultMessage: 'Raw' }),
value: 'raw'
label: intl.formatMessage({
id: 'tsvb.stdDeviation.modeOptions.rawLabel',
defaultMessage: 'Raw',
}),
value: 'raw',
},
{
label: intl.formatMessage({ id: 'tsvb.stdDeviation.modeOptions.upperBoundLabel', defaultMessage: 'Upper Bound' }),
value: 'upper'
label: intl.formatMessage({
id: 'tsvb.stdDeviation.modeOptions.upperBoundLabel',
defaultMessage: 'Upper Bound',
}),
value: 'upper',
},
{
label: intl.formatMessage({ id: 'tsvb.stdDeviation.modeOptions.lowerBoundLabel', defaultMessage: 'Lower Bound' }),
value: 'lower'
label: intl.formatMessage({
id: 'tsvb.stdDeviation.modeOptions.lowerBoundLabel',
defaultMessage: 'Lower Bound',
}),
value: 'lower',
},
];
if (panel.type !== 'table') {
modeOptions.push({
label: intl.formatMessage({ id: 'tsvb.stdDeviation.modeOptions.boundsBandLabel', defaultMessage: 'Bounds Band' }),
value: 'band'
label: intl.formatMessage({
id: 'tsvb.stdDeviation.modeOptions.boundsBandLabel',
defaultMessage: 'Bounds Band',
}),
value: 'band',
});
}
@ -70,7 +82,8 @@ const StandardDeviationAggUi = props => {
const handleSelectChange = createSelectHandler(handleChange);
const handleTextChange = createTextHandler(handleChange);
const indexPattern = series.override_index_pattern && series.series_index_pattern || panel.index_pattern;
const indexPattern =
(series.override_index_pattern && series.series_index_pattern) || panel.index_pattern;
const htmlId = htmlIdGenerator();
const selectedModeOption = modeOptions.find(option => {
return model.mode === option.value;
@ -104,10 +117,7 @@ const StandardDeviationAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('field')}
label={(<FormattedMessage
id="tsvb.stdDeviation.fieldLabel"
defaultMessage="Field"
/>)}
label={<FormattedMessage id="tsvb.stdDeviation.fieldLabel" defaultMessage="Field" />}
>
<FieldSelect
fields={fields}
@ -122,24 +132,15 @@ const StandardDeviationAggUi = props => {
<EuiFlexItem grow={false}>
<EuiFormRow
id={htmlId('sigma')}
label={(<FormattedMessage
id="tsvb.stdDeviation.sigmaLabel"
defaultMessage="Sigma"
/>)}
label={<FormattedMessage id="tsvb.stdDeviation.sigmaLabel" defaultMessage="Sigma" />}
>
<EuiFieldText
value={model.sigma}
onChange={handleTextChange('sigma')}
/>
<EuiFieldText value={model.sigma} onChange={handleTextChange('sigma')} />
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
id={htmlId('mode')}
label={(<FormattedMessage
id="tsvb.stdDeviation.modeLabel"
defaultMessage="Mode"
/>)}
label={<FormattedMessage id="tsvb.stdDeviation.modeLabel" defaultMessage="Mode" />}
>
<EuiComboBox
options={modeOptions}

View file

@ -52,36 +52,42 @@ const StandardSiblingAggUi = props => {
<EuiFlexItem grow={false}>
<EuiFormRow
id={htmlId('sigma')}
label={(<FormattedMessage
id="tsvb.stdSibling.sigmaLabel"
defaultMessage="Sigma"
/>)}
label={<FormattedMessage id="tsvb.stdSibling.sigmaLabel" defaultMessage="Sigma" />}
>
<EuiFieldText
value={model.sigma}
onChange={handleTextChange('sigma')}
/>
<EuiFieldText value={model.sigma} onChange={handleTextChange('sigma')} />
</EuiFormRow>
</EuiFlexItem>
);
const modeOptions = [
{
label: intl.formatMessage({ id: 'tsvb.stdSibling.modeOptions.rawLabel', defaultMessage: 'Raw' }),
value: 'raw'
label: intl.formatMessage({
id: 'tsvb.stdSibling.modeOptions.rawLabel',
defaultMessage: 'Raw',
}),
value: 'raw',
},
{
label: intl.formatMessage({ id: 'tsvb.stdSibling.modeOptions.upperBoundLabel', defaultMessage: 'Upper Bound' }),
value: 'upper'
label: intl.formatMessage({
id: 'tsvb.stdSibling.modeOptions.upperBoundLabel',
defaultMessage: 'Upper Bound',
}),
value: 'upper',
},
{
label: intl.formatMessage({ id: 'tsvb.stdSibling.modeOptions.lowerBoundLabel', defaultMessage: 'Lower Bound' }),
value: 'lower'
label: intl.formatMessage({
id: 'tsvb.stdSibling.modeOptions.lowerBoundLabel',
defaultMessage: 'Lower Bound',
}),
value: 'lower',
},
{
label: intl.formatMessage({ id: 'tsvb.stdSibling.modeOptions.boundsBandLabel', defaultMessage: 'Bounds Band' }),
value: 'band'
}
label: intl.formatMessage({
id: 'tsvb.stdSibling.modeOptions.boundsBandLabel',
defaultMessage: 'Bounds Band',
}),
value: 'band',
},
];
const selectedModeOption = modeOptions.find(option => {
return model.mode === option.value;
@ -91,10 +97,7 @@ const StandardSiblingAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('mode')}
label={(<FormattedMessage
id="tsvb.stdSibling.modeLabel"
defaultMessage="Mode"
/>)}
label={<FormattedMessage id="tsvb.stdSibling.modeLabel" defaultMessage="Mode" />}
>
<EuiComboBox
options={modeOptions}
@ -119,10 +122,7 @@ const StandardSiblingAggUi = props => {
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
id="tsvb.stdSibling.aggregationLabel"
defaultMessage="Aggregation"
/>
<FormattedMessage id="tsvb.stdSibling.aggregationLabel" defaultMessage="Aggregation" />
</EuiFormLabel>
<AggSelect
id={htmlId('aggregation')}
@ -136,10 +136,7 @@ const StandardSiblingAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('metric')}
label={(<FormattedMessage
id="tsvb.stdSibling.metricLabel"
defaultMessage="Metric"
/>)}
label={<FormattedMessage id="tsvb.stdSibling.metricLabel" defaultMessage="Metric" />}
>
<MetricSelect
onChange={handleSelectChange('field')}
@ -150,8 +147,8 @@ const StandardSiblingAggUi = props => {
/>
</EuiFormRow>
</EuiFlexItem>
{ stdDev.sigma }
{ stdDev.mode }
{stdDev.sigma}
{stdDev.mode}
</EuiFlexGroup>
</AggRow>
);

View file

@ -37,7 +37,7 @@ export function TemporaryUnsupportedAgg(props) {
<FormattedMessage
id="tsvb.unsupportedAgg.aggIsTemporaryUnsupportedDescription"
defaultMessage="The {modelType} aggregation is currently unsupported."
values={{ modelType: (<EuiCode>{props.model.type}</EuiCode>) }}
values={{ modelType: <EuiCode>{props.model.type}</EuiCode> }}
/>
</span>
</EuiTitle>

View file

@ -113,14 +113,15 @@ const TopHitAggUi = props => {
};
const model = { ...defaults, ...props.model };
const indexPattern =
(series.override_index_pattern && series.series_index_pattern) ||
panel.index_pattern;
(series.override_index_pattern && series.series_index_pattern) || panel.index_pattern;
const aggWithOptionsRestrictFields = [
PANEL_TYPES.TABLE,
PANEL_TYPES.METRIC,
PANEL_TYPES.MARKDOWN
].includes(panel.type) ? [ES_TYPES.NUMBER, ES_TYPES.KEYWORD, ES_TYPES.STRING] : [ES_TYPES.NUMBER];
PANEL_TYPES.MARKDOWN,
].includes(panel.type)
? [ES_TYPES.NUMBER, ES_TYPES.KEYWORD, ES_TYPES.STRING]
: [ES_TYPES.NUMBER];
const handleChange = createChangeHandler(props.onChange, model);
const handleSelectChange = createSelectHandler(handleChange);
@ -152,10 +153,7 @@ const TopHitAggUi = props => {
<EuiFlexGroup gutterSize="s">
<EuiFlexItem>
<EuiFormLabel htmlFor={htmlId('aggregation')}>
<FormattedMessage
id="tsvb.topHit.aggregationLabel"
defaultMessage="Aggregation"
/>
<FormattedMessage id="tsvb.topHit.aggregationLabel" defaultMessage="Aggregation" />
</EuiFormLabel>
<AggSelect
id={htmlId('aggregation')}
@ -168,10 +166,7 @@ const TopHitAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('field')}
label={(<FormattedMessage
id="tsvb.topHit.fieldLabel"
defaultMessage="Field"
/>)}
label={<FormattedMessage id="tsvb.topHit.fieldLabel" defaultMessage="Field" />}
>
<FieldSelect
fields={fields}
@ -185,16 +180,13 @@ const TopHitAggUi = props => {
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer size="m"/>
<EuiSpacer size="m" />
<EuiFlexGroup gutterSize="s">
<EuiFlexItem grow={false}>
<EuiFormRow
id={htmlId('size')}
label={(<FormattedMessage
id="tsvb.topHit.sizeLabel"
defaultMessage="Size"
/>)}
label={<FormattedMessage id="tsvb.topHit.sizeLabel" defaultMessage="Size" />}
>
{/*
EUITODO: The following input couldn't be converted to EUI because of type mis-match.
@ -210,10 +202,12 @@ const TopHitAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('agg_with')}
label={(<FormattedMessage
id="tsvb.topHit.aggregateWithLabel"
defaultMessage="Aggregate with"
/>)}
label={
<FormattedMessage
id="tsvb.topHit.aggregateWithLabel"
defaultMessage="Aggregate with"
/>
}
>
<EuiComboBox
isClearable={false}
@ -230,10 +224,7 @@ const TopHitAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('order_by')}
label={(<FormattedMessage
id="tsvb.topHit.orderByLabel"
defaultMessage="Order by"
/>)}
label={<FormattedMessage id="tsvb.topHit.orderByLabel" defaultMessage="Order by" />}
>
<FieldSelect
restrict={ORDER_DATE_RESTRICT_FIELDS}
@ -247,10 +238,7 @@ const TopHitAggUi = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('order')}
label={(<FormattedMessage
id="tsvb.topHit.orderLabel"
defaultMessage="Order"
/>)}
label={<FormattedMessage id="tsvb.topHit.orderLabel" defaultMessage="Order" />}
>
<EuiComboBox
isClearable={false}

View file

@ -37,7 +37,7 @@ export function UnsupportedAgg(props) {
<FormattedMessage
id="tsvb.unsupportedAgg.aggIsNotSupportedDescription"
defaultMessage="The {modelType} aggregation is no longer supported."
values={{ modelType: (<EuiCode>{props.model.type}</EuiCode>) }}
values={{ modelType: <EuiCode>{props.model.type}</EuiCode> }}
/>
</span>
</EuiTitle>

View file

@ -27,14 +27,13 @@ import { EuiFlexGroup, EuiFlexItem, EuiFieldText } from '@elastic/eui';
import { injectI18n } from '@kbn/i18n/react';
class CalculationVarsUi extends Component {
constructor(props) {
super(props);
this.renderRow = this.renderRow.bind(this);
}
handleChange(item, name) {
return (e) => {
return e => {
const handleChange = collectionActions.handleChange.bind(null, this.props);
const part = {};
part[name] = _.get(e, '[0].value', _.get(e, 'target.value'));
@ -46,14 +45,20 @@ class CalculationVarsUi extends Component {
const handleAdd = collectionActions.handleAdd.bind(null, this.props);
const handleDelete = collectionActions.handleDelete.bind(null, this.props, row);
const { intl } = this.props;
return (
return (
<EuiFlexItem key={row.id} data-test-subj="varRow">
<EuiFlexGroup alignItems="center" responsive={false} gutterSize="s">
<EuiFlexItem>
<EuiFieldText
className="tvbAggs__varName"
aria-label={intl.formatMessage({ id: 'tsvb.vars.variableNameAriaLabel', defaultMessage: 'Variable name' })}
placeholder={intl.formatMessage({ id: 'tsvb.vars.variableNamePlaceholder', defaultMessage: 'Variable name' })}
aria-label={intl.formatMessage({
id: 'tsvb.vars.variableNameAriaLabel',
defaultMessage: 'Variable name',
})}
placeholder={intl.formatMessage({
id: 'tsvb.vars.variableNamePlaceholder',
defaultMessage: 'Variable name',
})}
onChange={this.handleChange(row, 'name')}
value={row.name}
/>
@ -82,20 +87,19 @@ class CalculationVarsUi extends Component {
render() {
const { model, name } = this.props;
if (!model[name]) return (<div/>);
if (!model[name]) return <div />;
const rows = model[name].map(this.renderRow);
return (
<EuiFlexGroup direction="column" gutterSize="s">
{ rows }
{rows}
</EuiFlexGroup>
);
}
}
CalculationVarsUi.defaultProps = {
name: 'variables',
includeSiblings: false
includeSiblings: false,
};
CalculationVarsUi.propTypes = {
@ -103,7 +107,7 @@ CalculationVarsUi.propTypes = {
model: PropTypes.object,
name: PropTypes.string,
onChange: PropTypes.func,
includeSiblings: PropTypes.bool
includeSiblings: PropTypes.bool,
};
export const CalculationVars = injectI18n(CalculationVarsUi);

View file

@ -56,7 +56,7 @@ function newAnnotation() {
time_field: '@timestamp',
icon: 'fa-tag',
ignore_global_filters: 1,
ignore_panel_filters: 1
ignore_panel_filters: 1,
};
}
@ -70,7 +70,7 @@ export class AnnotationsEditor extends Component {
}
handleChange(item, name) {
return (e) => {
return e => {
const handleChange = collectionActions.handleChange.bind(null, this.props);
const part = {};
part[name] = _.get(e, '[0].value', _.get(e, 'target.value'));
@ -81,7 +81,7 @@ export class AnnotationsEditor extends Component {
const part = { query_string: filter };
collectionActions.handleChange(this.props, {
...model,
...part
...part,
});
};
renderRow(row) {
@ -89,10 +89,10 @@ export class AnnotationsEditor extends Component {
fields: '',
template: '',
index_pattern: '*',
query_string: { query: '', language: getDefaultQueryLanguage() }
query_string: { query: '', language: getDefaultQueryLanguage() },
};
const model = { ...defaults, ...row };
const handleChange = (part) => {
const handleChange = part => {
const fn = collectionActions.handleChange.bind(null, this.props);
fn(_.assign({}, model, part));
};
@ -102,10 +102,8 @@ export class AnnotationsEditor extends Component {
});
};
const htmlId = htmlIdGenerator(model.id);
const handleAdd = collectionActions.handleAdd
.bind(null, this.props, newAnnotation);
const handleDelete = collectionActions.handleDelete
.bind(null, this.props, model);
const handleAdd = collectionActions.handleAdd.bind(null, this.props, newAnnotation);
const handleDelete = collectionActions.handleDelete.bind(null, this.props, model);
return (
<div className="tvbAnnotationsEditor" key={model.id}>
<EuiFlexGroup responsive={false}>
@ -123,10 +121,12 @@ export class AnnotationsEditor extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('indexPattern')}
label={(<FormattedMessage
id="tsvb.annotationsEditor.indexPatternLabel"
defaultMessage="Index pattern (required)"
/>)}
label={
<FormattedMessage
id="tsvb.annotationsEditor.indexPatternLabel"
defaultMessage="Index pattern (required)"
/>
}
fullWidth
>
<EuiFieldText
@ -139,10 +139,12 @@ export class AnnotationsEditor extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('timeField')}
label={(<FormattedMessage
id="tsvb.annotationsEditor.timeFieldLabel"
defaultMessage="Time field (required)"
/>)}
label={
<FormattedMessage
id="tsvb.annotationsEditor.timeFieldLabel"
defaultMessage="Time field (required)"
/>
}
fullWidth
>
<FieldSelect
@ -163,10 +165,12 @@ export class AnnotationsEditor extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('queryString')}
label={(<FormattedMessage
id="tsvb.annotationsEditor.queryStringLabel"
defaultMessage="Query string"
/>)}
label={
<FormattedMessage
id="tsvb.annotationsEditor.queryStringLabel"
defaultMessage="Query string"
/>
}
fullWidth
>
<QueryBarInput
@ -218,24 +222,25 @@ export class AnnotationsEditor extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('icon')}
label={(<FormattedMessage
id="tsvb.annotationsEditor.iconLabel"
defaultMessage="Icon (required)"
/>)}
label={
<FormattedMessage
id="tsvb.annotationsEditor.iconLabel"
defaultMessage="Icon (required)"
/>
}
>
<IconSelect
value={model.icon}
onChange={this.handleChange(model, 'icon')}
/>
<IconSelect value={model.icon} onChange={this.handleChange(model, 'icon')} />
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
id={htmlId('fields')}
label={(<FormattedMessage
id="tsvb.annotationsEditor.fieldsLabel"
defaultMessage="Fields (required - comma separated paths)"
/>)}
label={
<FormattedMessage
id="tsvb.annotationsEditor.fieldsLabel"
defaultMessage="Fields (required - comma separated paths)"
/>
}
fullWidth
>
<EuiFieldText
@ -248,16 +253,18 @@ export class AnnotationsEditor extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('rowTemplate')}
label={(<FormattedMessage
id="tsvb.annotationsEditor.rowTemplateLabel"
defaultMessage="Row template (required)"
/>)}
label={
<FormattedMessage
id="tsvb.annotationsEditor.rowTemplateLabel"
defaultMessage="Row template (required)"
/>
}
helpText={
<span>
<FormattedMessage
id="tsvb.annotationsEditor.rowTemplateHelpText"
defaultMessage="eg.{rowTemplateExample}"
values={{ rowTemplateExample: (<EuiCode>{'{{field}}'}</EuiCode>) }}
values={{ rowTemplateExample: <EuiCode>{'{{field}}'}</EuiCode> }}
/>
</span>
}
@ -290,8 +297,7 @@ export class AnnotationsEditor extends Component {
const { model } = this.props;
let content;
if (!model.annotations || !model.annotations.length) {
const handleAdd = collectionActions.handleAdd
.bind(null, this.props, newAnnotation);
const handleAdd = collectionActions.handleAdd.bind(null, this.props, newAnnotation);
content = (
<EuiText textAlign="center">
<p>
@ -322,25 +328,21 @@ export class AnnotationsEditor extends Component {
</EuiTitle>
<EuiSpacer size="m" />
{ annotations }
{annotations}
</div>
);
}
return(
<div className="tvbAnnotationsEditor__container">
{ content }
</div>
);
return <div className="tvbAnnotationsEditor__container">{content}</div>;
}
}
AnnotationsEditor.defaultProps = {
name: 'annotations'
name: 'annotations',
};
AnnotationsEditor.propTypes = {
fields: PropTypes.object,
model: PropTypes.object,
name: PropTypes.string,
onChange: PropTypes.func
onChange: PropTypes.func,
};

View file

@ -22,17 +22,16 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { EuiIconTip, } from '@elastic/eui';
import { EuiIconTip } from '@elastic/eui';
import { CustomColorPicker } from './custom_color_picker';
import { injectI18n } from '@kbn/i18n/react';
class ColorPickerUI extends Component {
constructor(props) {
super(props);
this.state = {
displayPicker: false,
color: {}
color: {},
};
this.handleClick = this.handleClick.bind(this);
@ -68,7 +67,7 @@ class ColorPickerUI extends Component {
<button
aria-label={this.props.intl.formatMessage({
id: 'tsvb.colorPicker.notAccessibleAriaLabel',
defaultMessage: 'Color picker, not accessible'
defaultMessage: 'Color picker, not accessible',
})}
className="tvbColorPicker__swatch-empty"
onClick={this.handleClick}
@ -77,11 +76,15 @@ class ColorPickerUI extends Component {
}
return (
<button
aria-label={this.props.intl.formatMessage({
id: 'tsvb.colorPicker.notAccessibleWithValueAriaLabel',
defaultMessage: 'Color picker ({value}), not accessible' }, {
value: this.props.value
})}
aria-label={this.props.intl.formatMessage(
{
id: 'tsvb.colorPicker.notAccessibleWithValueAriaLabel',
defaultMessage: 'Color picker ({value}), not accessible',
},
{
value: this.props.value,
}
)}
style={{ backgroundColor: this.props.value }}
className="tvbColorPicker__swatch"
onClick={this.handleClick}
@ -102,7 +105,7 @@ class ColorPickerUI extends Component {
color="danger"
content={this.props.intl.formatMessage({
id: 'tsvb.colorPicker.clearIconLabel',
defaultMessage: 'Clear'
defaultMessage: 'Clear',
})}
/>
</div>
@ -110,34 +113,24 @@ class ColorPickerUI extends Component {
}
return (
<div className="tvbColorPicker" data-test-subj="tvbColorPicker">
{ swatch }
{ clear }
{
this.state.displayPicker
? (
<div className="tvbColorPicker__popover">
<div
className="tvbColorPicker__cover"
onClick={this.handleClose}
/>
<CustomColorPicker
color={value}
onChangeComplete={this.handleChange}
/>
</div>
) : null
}
{swatch}
{clear}
{this.state.displayPicker ? (
<div className="tvbColorPicker__popover">
<div className="tvbColorPicker__cover" onClick={this.handleClose} />
<CustomColorPicker color={value} onChangeComplete={this.handleChange} />
</div>
) : null}
</div>
);
}
}
ColorPickerUI.propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
disableTrash: PropTypes.bool,
onChange: PropTypes.func
onChange: PropTypes.func,
};
export const ColorPicker = injectI18n(ColorPickerUI);

View file

@ -35,14 +35,13 @@ import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
class ColorRulesUI extends Component {
constructor(props) {
super(props);
this.renderRow = this.renderRow.bind(this);
}
handleChange(item, name, cast = String) {
return (e) => {
return e => {
const handleChange = collectionActions.handleChange.bind(null, this.props);
const part = {};
part[name] = cast(_.get(e, '[0].value', _.get(e, 'target.value')));
@ -59,15 +58,36 @@ class ColorRulesUI extends Component {
const handleDelete = collectionActions.handleDelete.bind(null, this.props, model);
const { intl } = this.props;
const operatorOptions = [
{ label: intl.formatMessage({ id: 'tsvb.colorRules.greaterThanLabel', defaultMessage: '> greater than' }), value: 'gt' },
{
label: intl.formatMessage({ id: 'tsvb.colorRules.greaterThanOrEqualLabel', defaultMessage: '>= greater than or equal' }),
value: 'gte'
label: intl.formatMessage({
id: 'tsvb.colorRules.greaterThanLabel',
defaultMessage: '> greater than',
}),
value: 'gt',
},
{
label: intl.formatMessage({
id: 'tsvb.colorRules.greaterThanOrEqualLabel',
defaultMessage: '>= greater than or equal',
}),
value: 'gte',
},
{
label: intl.formatMessage({
id: 'tsvb.colorRules.lessThanLabel',
defaultMessage: '< less than',
}),
value: 'lt',
},
{
label: intl.formatMessage({
id: 'tsvb.colorRules.lessThanOrEqualLabel',
defaultMessage: '<= less than or equal',
}),
value: 'lte',
},
{ label: intl.formatMessage({ id: 'tsvb.colorRules.lessThanLabel', defaultMessage: '< less than' }), value: 'lt' },
{ label: intl.formatMessage({ id: 'tsvb.colorRules.lessThanOrEqualLabel', defaultMessage: '<= less than or equal' }), value: 'lte' },
];
const handleColorChange = (part) => {
const handleColorChange = part => {
const handleChange = collectionActions.handleChange.bind(null, this.props);
handleChange(_.assign({}, model, part));
};
@ -104,7 +124,14 @@ class ColorRulesUI extends Component {
);
}
return (
<EuiFlexGroup wrap={true} responsive={false} gutterSize="s" key={model.id} alignItems="center" className="tvbColorRules__rule">
<EuiFlexGroup
wrap={true}
responsive={false}
gutterSize="s"
key={model.id}
alignItems="center"
className="tvbColorRules__rule"
>
<EuiFlexItem grow={false}>
<EuiFormLabel style={labelStyle}>
<FormattedMessage
@ -124,7 +151,7 @@ class ColorRulesUI extends Component {
/>
</EuiFlexItem>
{ secondary }
{secondary}
<EuiFlexItem grow={false}>
<EuiFormLabel style={labelStyle} htmlFor={htmlId('ifMetricIs')}>
@ -149,7 +176,10 @@ class ColorRulesUI extends Component {
<EuiFlexItem>
<EuiFieldNumber
aria-label={intl.formatMessage({ id: 'tsvb.colorRules.valueAriaLabel', defaultMessage: 'Value' })}
aria-label={intl.formatMessage({
id: 'tsvb.colorRules.valueAriaLabel',
defaultMessage: 'Value',
})}
value={model.value}
onChange={this.handleChange(model, 'value', Number)}
fullWidth
@ -170,24 +200,23 @@ class ColorRulesUI extends Component {
render() {
const { model, name } = this.props;
if (!model[name]) return (<div/>);
if (!model[name]) return <div />;
const rows = model[name].map(this.renderRow);
return (
<div>
{ rows }
</div>
);
return <div>{rows}</div>;
}
}
ColorRulesUI.defaultProps = {
name: 'color_rules',
primaryName: i18n.translate('tsvb.colorRules.defaultPrimaryNameLabel', { defaultMessage: 'background' }),
primaryName: i18n.translate('tsvb.colorRules.defaultPrimaryNameLabel', {
defaultMessage: 'background',
}),
primaryVarName: 'background_color',
secondaryName: i18n.translate('tsvb.colorRules.defaultSecondaryNameLabel', { defaultMessage: 'text' }),
secondaryName: i18n.translate('tsvb.colorRules.defaultSecondaryNameLabel', {
defaultMessage: 'text',
}),
secondaryVarName: 'color',
hideSecondary: false
hideSecondary: false,
};
ColorRulesUI.propTypes = {
@ -198,7 +227,7 @@ ColorRulesUI.propTypes = {
primaryVarName: PropTypes.string,
secondaryName: PropTypes.string,
secondaryVarName: PropTypes.string,
hideSecondary: PropTypes.bool
hideSecondary: PropTypes.bool,
};
export const ColorRules = injectI18n(ColorRulesUI);

View file

@ -20,7 +20,13 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { ColorWrap as colorWrap, Saturation, Hue, Alpha, Checkboard } from 'react-color/lib/components/common';
import {
ColorWrap as colorWrap,
Saturation,
Hue,
Alpha,
Checkboard,
} from 'react-color/lib/components/common';
import ChromeFields from 'react-color/lib/components/chrome/ChromeFields';
import ChromePointer from 'react-color/lib/components/chrome/ChromePointer';
import ChromePointerCircle from 'react-color/lib/components/chrome/ChromePointerCircle';
@ -47,38 +53,33 @@ class CustomColorPickerUI extends Component {
const styles = {
active: {
background: `rgba(${ rgb.r }, ${ rgb.g }, ${ rgb.b }, ${ rgb.a })`,
background: `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${rgb.a})`,
},
Saturation: {
radius: '2px 2px 0 0 '
radius: '2px 2px 0 0 ',
},
Hue: {
radius: '2px',
},
Alpha: {
radius: '2px',
}
},
};
const handleSwatchChange = (data) => {
const handleSwatchChange = data => {
if (data.hex) {
color.isValidHex(data.hex) && this.props.onChange({
hex: data.hex,
source: 'hex',
});
color.isValidHex(data.hex) &&
this.props.onChange({
hex: data.hex,
source: 'hex',
});
} else {
this.props.onChange(data);
}
};
const swatches = this.props.colors.map((c) => {
return (
<CompactColor
key={c}
color={c}
onClick={handleSwatchChange}
/>
);
const swatches = this.props.colors.map(c => {
return <CompactColor key={c} color={c} onClick={handleSwatchChange} />;
});
return (
@ -93,14 +94,32 @@ class CustomColorPickerUI extends Component {
</div>
<div className="tvbColorPickerPopUp__body">
<div className="tvbColorPickerPopUp__controls">
<div className={this.props.disableAlpha ? 'tvbColorPickerPopUp__color-disableAlpha' : 'tvbColorPickerPopUp__color'}>
<div className={this.props.disableAlpha ? 'tvbColorPickerPopUp__swatch-disableAlpha' : 'tvbColorPickerPopUp__swatch'}>
<div
className={
this.props.disableAlpha
? 'tvbColorPickerPopUp__color-disableAlpha'
: 'tvbColorPickerPopUp__color'
}
>
<div
className={
this.props.disableAlpha
? 'tvbColorPickerPopUp__swatch-disableAlpha'
: 'tvbColorPickerPopUp__swatch'
}
>
<div className="tvbColorPickerPopUp__active" />
<Checkboard />
</div>
</div>
<div className="tvbColorPickerPopUp__toggles">
<div className={this.props.disableAlpha ? 'tvbColorPickerPopUp__hue-disableAlpha' : 'tvbColorPickerPopUp__hue'}>
<div
className={
this.props.disableAlpha
? 'tvbColorPickerPopUp__hue-disableAlpha'
: 'tvbColorPickerPopUp__hue'
}
>
<Hue
style={styles.Hue}
{...this.props}
@ -108,7 +127,13 @@ class CustomColorPickerUI extends Component {
onChange={this.handleChange}
/>
</div>
<div className={this.props.disableAlpha ? 'tvbColorPickerPopUp__alpha-disableAlpha' : 'tvbColorPickerPopUp__alpha'}>
<div
className={
this.props.disableAlpha
? 'tvbColorPickerPopUp__alpha-disableAlpha'
: 'tvbColorPickerPopUp__alpha'
}
>
<Alpha
style={styles.Alpha}
{...this.props}
@ -123,9 +148,7 @@ class CustomColorPickerUI extends Component {
onChange={this.handleChange}
disableAlpha={this.props.disableAlpha}
/>
<div className="tvbColorPickerPopUp__swatches">
{swatches}
</div>
<div className="tvbColorPickerPopUp__swatches">{swatches}</div>
</div>
</div>
);
@ -134,19 +157,49 @@ class CustomColorPickerUI extends Component {
CustomColorPickerUI.defaultProps = {
colors: [
'#4D4D4D', '#999999', '#FFFFFF', '#F44E3B', '#FE9200', '#FCDC00',
'#DBDF00', '#A4DD00', '#68CCCA', '#73D8FF', '#AEA1FF', '#FDA1FF',
'#333333', '#808080', '#cccccc', '#D33115', '#E27300', '#FCC400',
'#B0BC00', '#68BC00', '#16A5A5', '#009CE0', '#7B64FF', '#FA28FF',
'#0F1419', '#666666', '#B3B3B3', '#9F0500', '#C45100', '#FB9E00',
'#808900', '#194D33', '#0C797D', '#0062B1', '#653294', '#AB149E',
'#4D4D4D',
'#999999',
'#FFFFFF',
'#F44E3B',
'#FE9200',
'#FCDC00',
'#DBDF00',
'#A4DD00',
'#68CCCA',
'#73D8FF',
'#AEA1FF',
'#FDA1FF',
'#333333',
'#808080',
'#cccccc',
'#D33115',
'#E27300',
'#FCC400',
'#B0BC00',
'#68BC00',
'#16A5A5',
'#009CE0',
'#7B64FF',
'#FA28FF',
'#0F1419',
'#666666',
'#B3B3B3',
'#9F0500',
'#C45100',
'#FB9E00',
'#808900',
'#194D33',
'#0C797D',
'#0062B1',
'#653294',
'#AB149E',
],
};
CustomColorPickerUI.propTypes = {
color: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
onChangeComplete: PropTypes.func,
onChange: PropTypes.func
onChange: PropTypes.func,
};
export const CustomColorPicker = colorWrap(CustomColorPickerUI);

View file

@ -21,7 +21,13 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import _ from 'lodash';
import {
htmlIdGenerator, EuiComboBox, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiFieldText, EuiLink,
htmlIdGenerator,
EuiComboBox,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiFieldText,
EuiLink,
} from '@elastic/eui';
import { durationOutputOptions, durationInputOptions, isDuration } from './lib/durations';
import { i18n } from '@kbn/i18n';
@ -30,7 +36,6 @@ import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
const DEFAULT_OUTPUT_PRECISION = '2';
class DataFormatPickerUI extends Component {
constructor(props) {
super(props);
@ -50,7 +55,7 @@ class DataFormatPickerUI extends Component {
}
handleCustomChange = () => {
this.props.onChange([{ value: this.custom && this.custom.value || '' }]);
this.props.onChange([{ value: (this.custom && this.custom.value) || '' }]);
};
handleChange = selectedOptions => {
@ -62,16 +67,18 @@ class DataFormatPickerUI extends Component {
this.handleCustomChange();
} else if (selectedOptions[0].value === 'duration') {
const { from, to, decimals } = this.state;
this.props.onChange([{
value: `${from},${to},${decimals}`,
}]);
this.props.onChange([
{
value: `${from},${to},${decimals}`,
},
]);
} else {
this.props.onChange(selectedOptions);
}
};
handleDurationChange(name) {
return (selectedOptions) => {
return selectedOptions => {
if (selectedOptions.length < 1) {
return;
}
@ -83,14 +90,19 @@ class DataFormatPickerUI extends Component {
newValue = selectedOptions[0].value;
}
this.setState({
[name]: newValue,
}, () => {
const { from, to, decimals } = this.state;
this.props.onChange([{
value: `${from},${to},${decimals}`,
}]);
});
this.setState(
{
[name]: newValue,
},
() => {
const { from, to, decimals } = this.state;
this.props.onChange([
{
value: `${from},${to},${decimals}`,
},
]);
}
);
};
}
@ -107,23 +119,38 @@ class DataFormatPickerUI extends Component {
const { intl } = this.props;
const options = [
{
label: intl.formatMessage({ id: 'tsvb.dataFormatPicker.bytesLabel', defaultMessage: 'Bytes' }),
label: intl.formatMessage({
id: 'tsvb.dataFormatPicker.bytesLabel',
defaultMessage: 'Bytes',
}),
value: 'bytes',
},
{
label: intl.formatMessage({ id: 'tsvb.dataFormatPicker.numberLabel', defaultMessage: 'Number' }),
label: intl.formatMessage({
id: 'tsvb.dataFormatPicker.numberLabel',
defaultMessage: 'Number',
}),
value: 'number',
},
{
label: intl.formatMessage({ id: 'tsvb.dataFormatPicker.percentLabel', defaultMessage: 'Percent' }),
label: intl.formatMessage({
id: 'tsvb.dataFormatPicker.percentLabel',
defaultMessage: 'Percent',
}),
value: 'percent',
},
{
label: intl.formatMessage({ id: 'tsvb.dataFormatPicker.durationLabel', defaultMessage: 'Duration' }),
label: intl.formatMessage({
id: 'tsvb.dataFormatPicker.durationLabel',
defaultMessage: 'Duration',
}),
value: 'duration',
},
{
label: intl.formatMessage({ id: 'tsvb.dataFormatPicker.customLabel', defaultMessage: 'Custom' }),
label: intl.formatMessage({
id: 'tsvb.dataFormatPicker.customLabel',
defaultMessage: 'Custom',
}),
value: 'custom',
},
];
@ -153,10 +180,9 @@ class DataFormatPickerUI extends Component {
<EuiFlexItem grow={false}>
<EuiFormRow
id={htmlId('from')}
label={(<FormattedMessage
id="tsvb.dataFormatPicker.fromLabel"
defaultMessage="From"
/>)}
label={
<FormattedMessage id="tsvb.dataFormatPicker.fromLabel" defaultMessage="From" />
}
>
<EuiComboBox
isClearable={false}
@ -170,10 +196,7 @@ class DataFormatPickerUI extends Component {
<EuiFlexItem grow={false}>
<EuiFormRow
id={htmlId('to')}
label={(<FormattedMessage
id="tsvb.dataFormatPicker.toLabel"
defaultMessage="To"
/>)}
label={<FormattedMessage id="tsvb.dataFormatPicker.toLabel" defaultMessage="To" />}
>
<EuiComboBox
isClearable={false}
@ -189,21 +212,22 @@ class DataFormatPickerUI extends Component {
<EuiFlexItem grow={false}>
<EuiFormRow
id={htmlId('decimal')}
label={(<FormattedMessage
id="tsvb.dataFormatPicker.decimalPlacesLabel"
defaultMessage="Decimal places"
/>)}
label={
<FormattedMessage
id="tsvb.dataFormatPicker.decimalPlacesLabel"
defaultMessage="Decimal places"
/>
}
>
<EuiFieldText
defaultValue={decimals}
inputRef={(el) => this.decimals = el}
inputRef={el => (this.decimals = el)}
placeholder={DEFAULT_OUTPUT_PRECISION}
onChange={this.handleDurationChange('decimals')}
/>
</EuiFormRow>
</EuiFlexItem>)
}
</EuiFlexItem>
)}
</EuiFlexGroup>
);
}
@ -211,17 +235,23 @@ class DataFormatPickerUI extends Component {
custom = (
<EuiFlexItem grow={false}>
<EuiFormRow
label={(<FormattedMessage
id="tsvb.dataFormatPicker.formatStringLabel"
defaultMessage="Format string"
/>)}
label={
<FormattedMessage
id="tsvb.dataFormatPicker.formatStringLabel"
defaultMessage="Format string"
/>
}
helpText={
<span>
<FormattedMessage
id="tsvb.dataFormatPicker.formatStringHelpText"
defaultMessage="See {numeralJsLink}"
values={{
numeralJsLink: (<EuiLink href="http://numeraljs.com/#format" target="_BLANK">Numeral.js</EuiLink>),
numeralJsLink: (
<EuiLink href="http://numeraljs.com/#format" target="_BLANK">
Numeral.js
</EuiLink>
),
}}
/>
</span>
@ -229,7 +259,7 @@ class DataFormatPickerUI extends Component {
>
<EuiFieldText
defaultValue={value}
inputRef={(el) => this.custom = el}
inputRef={el => (this.custom = el)}
onChange={this.handleCustomChange}
/>
</EuiFormRow>

View file

@ -50,11 +50,7 @@ export function ErrorComponent(props) {
</div>
);
} else if (reason) {
additionalInfo = (
<div className="tvbError__additional">
{reason}
</div>
);
additionalInfo = <div className="tvbError__additional">{reason}</div>;
}
return (
@ -64,11 +60,12 @@ export function ErrorComponent(props) {
<EuiSpacer size="s" />
{title ||
<FormattedMessage
id="tsvb.error.requestForPanelFailedErrorMessage"
defaultMessage="The request for this panel failed"
/>}
{title || (
<FormattedMessage
id="tsvb.error.requestForPanelFailedErrorMessage"
defaultMessage="The request for this panel failed"
/>
)}
{additionalInfo}
</EuiText>
@ -77,5 +74,5 @@ export function ErrorComponent(props) {
}
ErrorComponent.propTypes = {
error: PropTypes.object
error: PropTypes.object,
};

View file

@ -19,9 +19,7 @@
import PropTypes from 'prop-types';
import React from 'react';
import {
EuiComboBox,
} from '@elastic/eui';
import { EuiComboBox } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
function renderOption(option) {
@ -54,33 +52,76 @@ export function IconSelect(props) {
IconSelect.defaultProps = {
icons: [
{ value: 'fa-asterisk', label: i18n.translate('tsvb.iconSelect.asteriskLabel', { defaultMessage: 'Asterisk' }) },
{ value: 'fa-bell', label: i18n.translate('tsvb.iconSelect.bellLabel', { defaultMessage: 'Bell' }) },
{ value: 'fa-bolt', label: i18n.translate('tsvb.iconSelect.boltLabel', { defaultMessage: 'Bolt' }) },
{ value: 'fa-bomb', label: i18n.translate('tsvb.iconSelect.bombLabel', { defaultMessage: 'Bomb' }) },
{ value: 'fa-bug', label: i18n.translate('tsvb.iconSelect.bugLabel', { defaultMessage: 'Bug' }) },
{ value: 'fa-comment', label: i18n.translate('tsvb.iconSelect.commentLabel', { defaultMessage: 'Comment' }) },
{
value: 'fa-asterisk',
label: i18n.translate('tsvb.iconSelect.asteriskLabel', { defaultMessage: 'Asterisk' }),
},
{
value: 'fa-bell',
label: i18n.translate('tsvb.iconSelect.bellLabel', { defaultMessage: 'Bell' }),
},
{
value: 'fa-bolt',
label: i18n.translate('tsvb.iconSelect.boltLabel', { defaultMessage: 'Bolt' }),
},
{
value: 'fa-bomb',
label: i18n.translate('tsvb.iconSelect.bombLabel', { defaultMessage: 'Bomb' }),
},
{
value: 'fa-bug',
label: i18n.translate('tsvb.iconSelect.bugLabel', { defaultMessage: 'Bug' }),
},
{
value: 'fa-comment',
label: i18n.translate('tsvb.iconSelect.commentLabel', { defaultMessage: 'Comment' }),
},
{
value: 'fa-exclamation-circle',
label: i18n.translate('tsvb.iconSelect.exclamationCircleLabel', { defaultMessage: 'Exclamation Circle' })
label: i18n.translate('tsvb.iconSelect.exclamationCircleLabel', {
defaultMessage: 'Exclamation Circle',
}),
},
{
value: 'fa-exclamation-triangle',
label: i18n.translate('tsvb.iconSelect.exclamationTriangleLabel', { defaultMessage: 'Exclamation Triangle' })
label: i18n.translate('tsvb.iconSelect.exclamationTriangleLabel', {
defaultMessage: 'Exclamation Triangle',
}),
},
{ value: 'fa-fire', label: i18n.translate('tsvb.iconSelect.fireLabel', { defaultMessage: 'Fire' }) },
{ value: 'fa-flag', label: i18n.translate('tsvb.iconSelect.flagLabel', { defaultMessage: 'Flag' }) },
{ value: 'fa-heart', label: i18n.translate('tsvb.iconSelect.heartLabel', { defaultMessage: 'Heart' }) },
{ value: 'fa-map-marker', label: i18n.translate('tsvb.iconSelect.mapMarkerLabel', { defaultMessage: 'Map Marker' }) },
{ value: 'fa-map-pin', label: i18n.translate('tsvb.iconSelect.mapPinLabel', { defaultMessage: 'Map Pin' }) },
{ value: 'fa-star', label: i18n.translate('tsvb.iconSelect.starLabel', { defaultMessage: 'Star' }) },
{ value: 'fa-tag', label: i18n.translate('tsvb.iconSelect.tagLabel', { defaultMessage: 'Tag' }) },
]
{
value: 'fa-fire',
label: i18n.translate('tsvb.iconSelect.fireLabel', { defaultMessage: 'Fire' }),
},
{
value: 'fa-flag',
label: i18n.translate('tsvb.iconSelect.flagLabel', { defaultMessage: 'Flag' }),
},
{
value: 'fa-heart',
label: i18n.translate('tsvb.iconSelect.heartLabel', { defaultMessage: 'Heart' }),
},
{
value: 'fa-map-marker',
label: i18n.translate('tsvb.iconSelect.mapMarkerLabel', { defaultMessage: 'Map Marker' }),
},
{
value: 'fa-map-pin',
label: i18n.translate('tsvb.iconSelect.mapPinLabel', { defaultMessage: 'Map Pin' }),
},
{
value: 'fa-star',
label: i18n.translate('tsvb.iconSelect.starLabel', { defaultMessage: 'Star' }),
},
{
value: 'fa-tag',
label: i18n.translate('tsvb.iconSelect.tagLabel', { defaultMessage: 'Tag' }),
},
],
};
IconSelect.propTypes = {
icons: PropTypes.array,
id: PropTypes.string,
onChange: PropTypes.func,
value: PropTypes.string.isRequired
value: PropTypes.string.isRequired,
};

View file

@ -50,7 +50,7 @@ export const IndexPattern = props => {
default_index_pattern: '',
[indexPatternName]: '*',
[intervalName]: 'auto',
[dropBucketName]: 1
[dropBucketName]: 1,
};
const htmlId = htmlIdGenerator();
@ -63,14 +63,15 @@ export const IndexPattern = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('indexPattern')}
label={(<FormattedMessage
id="tsvb.indexPatternLabel"
defaultMessage="Index pattern"
/>)}
helpText={isDefaultIndexPatternUsed && <FormattedMessage
id="tsvb.indexPattern.searchByDefaultIndex"
defaultMessage="Default index pattern is used. To query all indexes use *"
/>}
label={<FormattedMessage id="tsvb.indexPatternLabel" defaultMessage="Index pattern" />}
helpText={
isDefaultIndexPatternUsed && (
<FormattedMessage
id="tsvb.indexPattern.searchByDefaultIndex"
defaultMessage="Default index pattern is used. To query all indexes use *"
/>
)
}
fullWidth
>
<EuiFieldText
@ -86,10 +87,9 @@ export const IndexPattern = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('timeField')}
label={(<FormattedMessage
id="tsvb.indexPattern.timeFieldLabel"
defaultMessage="Time field"
/>)}
label={
<FormattedMessage id="tsvb.indexPattern.timeFieldLabel" defaultMessage="Time field" />
}
fullWidth
>
<FieldSelect
@ -108,15 +108,16 @@ export const IndexPattern = props => {
<EuiFlexItem grow={false}>
<EuiFormRow
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={
<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."
/>
}
>
<EuiFieldText
disabled={props.disabled}
@ -134,11 +135,7 @@ export const IndexPattern = props => {
/>
</EuiFormLabel>
<EuiSpacer size="s" />
<YesNo
value={model[dropBucketName]}
name={dropBucketName}
onChange={props.onChange}
/>
<YesNo value={model[dropBucketName]} name={dropBucketName} onChange={props.onChange} />
</EuiFlexItem>
</EuiFlexGroup>
</div>
@ -156,5 +153,5 @@ IndexPattern.propTypes = {
onChange: PropTypes.func.isRequired,
prefix: PropTypes.string,
disabled: PropTypes.bool,
className: PropTypes.string
className: PropTypes.string,
};

View file

@ -27,12 +27,12 @@ describe('calculateSiblings(metrics, metric)', () => {
{ id: 2, type: 'derivative', field: 1 },
{ id: 3, type: 'derivative', field: 2 },
{ id: 4, type: 'moving_average', field: 2 },
{ id: 5, type: 'count' }
{ id: 5, type: 'count' },
];
const siblings = calculateSiblings(metrics, { id: 2 });
expect(siblings).to.eql([
{ id: 1, type: 'max', field: 'network.bytes' },
{ id: 5, type: 'count' }
{ id: 5, type: 'count' },
]);
});
});

View file

@ -19,25 +19,20 @@
import sinon from 'sinon';
import { expect } from 'chai';
import {
handleChange,
handleAdd,
handleDelete
} from '../collection_actions';
import { handleChange, handleAdd, handleDelete } from '../collection_actions';
describe('collection actions', () => {
it('handleChange() calls props.onChange() with updated collection', () => {
const fn = sinon.spy();
const props = {
model: { test: [{ id: 1, title: 'foo' }] },
name: 'test',
onChange: fn
onChange: fn,
};
handleChange.call(null, props, { id: 1, title: 'bar' });
expect(fn.calledOnce).to.equal(true);
expect(fn.firstCall.args[0]).to.eql({
test: [{ id: 1, title: 'bar' }]
test: [{ id: 1, title: 'bar' }],
});
});
@ -47,13 +42,13 @@ describe('collection actions', () => {
const props = {
model: { test: [{ id: 1, title: 'foo' }] },
name: 'test',
onChange: fn
onChange: fn,
};
handleAdd.call(null, props, newItemFn);
expect(fn.calledOnce).to.equal(true);
expect(newItemFn.calledOnce).to.equal(true);
expect(fn.firstCall.args[0]).to.eql({
test: [{ id: 1, title: 'foo' }, { id: 2, title: 'example' }]
test: [{ id: 1, title: 'foo' }, { id: 2, title: 'example' }],
});
});
@ -62,16 +57,12 @@ describe('collection actions', () => {
const props = {
model: { test: [{ id: 1, title: 'foo' }] },
name: 'test',
onChange: fn
onChange: fn,
};
handleDelete.call(null, props, { id: 1 });
expect(fn.calledOnce).to.equal(true);
expect(fn.firstCall.args[0]).to.eql({
test: []
test: [],
});
});
});

View file

@ -18,7 +18,5 @@
*/
describe('convertSeriesToVars(series, model)', () => {
it('returns and object', () => {
});
it('returns and object', () => {});
});

View file

@ -22,7 +22,6 @@ import { expect } from 'chai';
import { createNumberHandler } from '../create_number_handler';
describe('createNumberHandler()', () => {
let handleChange;
let changeHandler;
let event;
@ -39,8 +38,7 @@ describe('createNumberHandler()', () => {
expect(event.preventDefault.calledOnce).to.equal(true);
expect(handleChange.calledOnce).to.equal(true);
expect(handleChange.firstCall.args[0]).to.eql({
test: 1
test: 1,
});
});
});

View file

@ -35,8 +35,7 @@ describe('createSelectHandler()', () => {
it('calls handleChange() function with partial', () => {
expect(handleChange.calledOnce).to.equal(true);
expect(handleChange.firstCall.args[0]).to.eql({
test: 'foo'
test: 'foo',
});
});
});

View file

@ -22,7 +22,6 @@ import { expect } from 'chai';
import { createTextHandler } from '../create_text_handler';
describe('createTextHandler()', () => {
let handleChange;
let changeHandler;
let event;
@ -39,9 +38,7 @@ describe('createTextHandler()', () => {
expect(event.preventDefault.calledOnce).to.equal(true);
expect(handleChange.calledOnce).to.equal(true);
expect(handleChange.firstCall.args[0]).to.eql({
test: 'foo'
test: 'foo',
});
});
});

View file

@ -31,5 +31,3 @@ describe('getAxisLabelString(interval)', () => {
expect(getAxisLabelString(7200000)).to.equal('per 2 hours');
});
});

View file

@ -22,14 +22,10 @@ import { expect } from 'chai';
import { reIdSeries } from '../re_id_series';
describe('reIdSeries()', () => {
it('reassign ids for series with just basic metrics', () => {
const series = {
id: uuid.v1(),
metrics: [
{ id: uuid.v1() },
{ id: uuid.v1() }
]
metrics: [{ id: uuid.v1() }, { id: uuid.v1() }],
};
const newSeries = reIdSeries(series);
expect(newSeries).to.not.equal(series);
@ -43,11 +39,8 @@ describe('reIdSeries()', () => {
const firstMetricId = uuid.v1();
const series = {
id: uuid.v1(),
metrics: [
{ id: firstMetricId },
{ id: uuid.v1() }
],
terms_order_by: firstMetricId
metrics: [{ id: firstMetricId }, { id: uuid.v1() }],
terms_order_by: firstMetricId,
};
const newSeries = reIdSeries(series);
expect(newSeries).to.not.equal(series);
@ -62,10 +55,7 @@ describe('reIdSeries()', () => {
const firstMetricId = uuid.v1();
const series = {
id: uuid.v1(),
metrics: [
{ id: firstMetricId },
{ id: uuid.v1(), field: firstMetricId }
]
metrics: [{ id: firstMetricId }, { id: uuid.v1(), field: firstMetricId }],
};
const newSeries = reIdSeries(series);
expect(newSeries).to.not.equal(series);
@ -82,16 +72,13 @@ describe('reIdSeries()', () => {
{
id: uuid.v1(),
type: 'calculation',
variables: [{ id: uuid.v1(), field: firstMetricId }]
}
]
variables: [{ id: uuid.v1(), field: firstMetricId }],
},
],
};
const newSeries = reIdSeries(series);
expect(newSeries).to.not.equal(series);
expect(newSeries.id).to.not.equal(series.id);
expect(newSeries.metrics[1].variables[0].field).to.equal(newSeries.metrics[0].id);
});
});

View file

@ -21,7 +21,6 @@ import { expect } from 'chai';
import { tickFormatter } from '../tick_formatter';
describe('tickFormatter(format, template)', () => {
it('returns a number with two decimal place by default', () => {
const fn = tickFormatter();
expect(fn(1.5556)).to.equal('1.56');
@ -29,17 +28,17 @@ describe('tickFormatter(format, template)', () => {
it('returns a percent with percent formatter', () => {
const config = {
'format:percent:defaultPattern': '0.[00]%'
'format:percent:defaultPattern': '0.[00]%',
};
const fn = tickFormatter('percent', null, (key) => config[key]);
const fn = tickFormatter('percent', null, key => config[key]);
expect(fn(0.5556)).to.equal('55.56%');
});
it('returns a byte formatted string with byte formatter', () => {
const config = {
'format:bytes:defaultPattern': '0.0b'
'format:bytes:defaultPattern': '0.0b',
};
const fn = tickFormatter('bytes', null, (key) => config[key]);
const fn = tickFormatter('bytes', null, key => config[key]);
expect(fn(1500 ^ 10)).to.equal('1.5KB');
});
@ -50,9 +49,9 @@ describe('tickFormatter(format, template)', () => {
it('returns a located string with custom locale setting', () => {
const config = {
'format:number:defaultLocale': 'fr'
'format:number:defaultLocale': 'fr',
};
const fn = tickFormatter('0,0.0', null, (key) => config[key]);
const fn = tickFormatter('0,0.0', null, key => config[key]);
expect(fn(1500)).to.equal('1 500,0');
});
@ -68,9 +67,9 @@ describe('tickFormatter(format, template)', () => {
it('returns formatted value if passed a bad template', () => {
const config = {
'format:number:defaultPattern': '0,0.[00]'
'format:number:defaultPattern': '0,0.[00]',
};
const fn = tickFormatter('number', '{{value', (key) => config[key]);
const fn = tickFormatter('number', '{{value', key => config[key]);
expect(fn(1.5556)).to.equal('1.56');
});
});

View file

@ -20,8 +20,8 @@
import _ from 'lodash';
function getAncestors(siblings, item) {
const ancestors = item.id && [item.id] || [];
siblings.forEach((sib) => {
const ancestors = (item.id && [item.id]) || [];
siblings.forEach(sib => {
if (_.includes(ancestors, sib.field)) {
ancestors.push(sib.id);
}
@ -33,4 +33,3 @@ export const calculateSiblings = (siblings, model) => {
const ancestors = getAncestors(siblings, model);
return siblings.filter(row => !_.includes(ancestors, row.id));
};

View file

@ -28,30 +28,32 @@ export const convertSeriesToVars = (series, model, dateFormat = 'lll', getConfig
series
.filter(row => _.startsWith(row.id, seriesModel.id))
.forEach(row => {
const varName = [
_.snakeCase(row.label),
_.snakeCase(seriesModel.var_name)
].filter(v => v).join('.');
const varName = [_.snakeCase(row.label), _.snakeCase(seriesModel.var_name)]
.filter(v => v)
.join('.');
const formatter = tickFormatter(seriesModel.formatter, seriesModel.value_template, getConfig);
const formatter = tickFormatter(
seriesModel.formatter,
seriesModel.value_template,
getConfig
);
const lastValue = getLastValue(row.data);
const data = {
last: {
raw: lastValue,
formatted: formatter(lastValue)
formatted: formatter(lastValue),
},
data: {
raw: row.data,
formatted: row.data.map(point => {
return [moment(point[0]).format(dateFormat), formatter(point[1])];
})
}
}),
},
};
_.set(variables, varName, data);
_.set(variables, `${_.snakeCase(row.label)}.label`, row.label);
});
});
return variables;
};

View file

@ -20,8 +20,8 @@
import _ from 'lodash';
import { detectIE } from './detect_ie';
export const createNumberHandler = (handleChange) => {
return (name, defaultValue) => (e) => {
export const createNumberHandler = handleChange => {
return (name, defaultValue) => e => {
if (!detectIE() || e.keyCode === 13) e.preventDefault();
const value = Number(_.get(e, 'target.value', defaultValue));

View file

@ -19,11 +19,11 @@
import _ from 'lodash';
export const createSelectHandler = (handleChange) => {
return (name) => (selectedOptions) => {
export const createSelectHandler = handleChange => {
return name => selectedOptions => {
if (_.isFunction(handleChange)) {
return handleChange({
[name]: _.get(selectedOptions, '[0].value', null)
[name]: _.get(selectedOptions, '[0].value', null),
});
}
};

View file

@ -20,8 +20,8 @@
import _ from 'lodash';
import { detectIE } from './detect_ie';
export const createTextHandler = (handleChange) => {
return (name, defaultValue) => (e) => {
export const createTextHandler = handleChange => {
return (name, defaultValue) => e => {
// IE preventDefault breaks input, but we still need top prevent enter from being pressed
if (!detectIE() || e.keyCode === 13) e.preventDefault();

View file

@ -33,4 +33,3 @@ export function createXaxisFormatter(interval, rules, dateFormat) {
return moment(val).format(getFormat(interval, rules, dateFormat));
};
}

View file

@ -21,7 +21,9 @@ import { i18n } from '@kbn/i18n';
const durationBaseOptions = [
{
label: i18n.translate('tsvb.durationOptions.millisecondsLabel', { defaultMessage: 'Milliseconds' }),
label: i18n.translate('tsvb.durationOptions.millisecondsLabel', {
defaultMessage: 'Milliseconds',
}),
value: 'ms',
},
{
@ -64,44 +66,50 @@ export const durationOutputOptions = [
export const durationInputOptions = [
{
label: i18n.translate('tsvb.durationOptions.picosecondsLabel', { defaultMessage: 'Picoseconds' }),
label: i18n.translate('tsvb.durationOptions.picosecondsLabel', {
defaultMessage: 'Picoseconds',
}),
value: 'ps',
},
{
label: i18n.translate('tsvb.durationOptions.nanosecondsLabel', { defaultMessage: 'Nanoseconds' }),
label: i18n.translate('tsvb.durationOptions.nanosecondsLabel', {
defaultMessage: 'Nanoseconds',
}),
value: 'ns',
},
{
label: i18n.translate('tsvb.durationOptions.microsecondsLabel', { defaultMessage: 'Microseconds' }),
label: i18n.translate('tsvb.durationOptions.microsecondsLabel', {
defaultMessage: 'Microseconds',
}),
value: 'us',
},
...durationBaseOptions,
];
export const inputFormats = {
'ps': 'picoseconds',
'ns': 'nanoseconds',
'us': 'microseconds',
'ms': 'milliseconds',
's': 'seconds',
'm': 'minutes',
'h': 'hours',
'd': 'days',
'w': 'weeks',
'M': 'months',
'Y': 'years',
ps: 'picoseconds',
ns: 'nanoseconds',
us: 'microseconds',
ms: 'milliseconds',
s: 'seconds',
m: 'minutes',
h: 'hours',
d: 'days',
w: 'weeks',
M: 'months',
Y: 'years',
};
export const outputFormats = {
'humanize': 'humanize',
'ms': 'asMilliseconds',
's': 'asSeconds',
'm': 'asMinutes',
'h': 'asHours',
'd': 'asDays',
'w': 'asWeeks',
'M': 'asMonths',
'Y': 'asYears',
humanize: 'humanize',
ms: 'asMilliseconds',
s: 'asSeconds',
m: 'asMinutes',
h: 'asHours',
d: 'asDays',
w: 'asWeeks',
M: 'asMonths',
Y: 'asYears',
};
export const isDuration = format => {

View file

@ -23,13 +23,12 @@ export function getAxisLabelString(interval) {
const convertedValue = convertIntervalIntoUnit(interval);
if (convertedValue) {
return i18n.translate('tsvb.axisLabelOptions.axisLabel',
{
defaultMessage: 'per {unitValue} {unitString}',
values: {
unitValue: convertedValue.unitValue,
unitString: convertedValue.unitString,
},
});
return i18n.translate('tsvb.axisLabelOptions.axisLabel', {
defaultMessage: 'per {unitValue} {unitString}',
values: {
unitValue: convertedValue.unitValue,
unitString: convertedValue.unitString,
},
});
}
}

View file

@ -17,7 +17,6 @@
* under the License.
*/
import chrome from 'ui/chrome';
export function getDefaultQueryLanguage() {

View file

@ -32,12 +32,11 @@ export const unitLookup = {
d: i18n.translate('tsvb.getInterval.daysLabel', { defaultMessage: 'days' }),
w: i18n.translate('tsvb.getInterval.weeksLabel', { defaultMessage: 'weeks' }),
M: i18n.translate('tsvb.getInterval.monthsLabel', { defaultMessage: 'months' }),
y: i18n.translate('tsvb.getInterval.yearsLabel', { defaultMessage: 'years' })
y: i18n.translate('tsvb.getInterval.yearsLabel', { defaultMessage: 'years' }),
};
export const convertIntervalIntoUnit = (interval, hasTranslateUnitString = true) => {
const units = pluck(clone(relativeOptions).reverse(), 'value')
.filter(s => /^[smhdwMy]$/.test(s));
const units = pluck(clone(relativeOptions).reverse(), 'value').filter(s => /^[smhdwMy]$/.test(s));
const duration = moment.duration(interval, 'ms');
for (let i = 0; i < units.length; i++) {
@ -46,16 +45,18 @@ export const convertIntervalIntoUnit = (interval, hasTranslateUnitString = true)
if (Math.abs(as) > 1) {
return {
unitValue: Math.round(Math.abs(as)),
unitString: hasTranslateUnitString ? unitLookup[units[i]] : units[i]
unitString: hasTranslateUnitString ? unitLookup[units[i]] : units[i],
};
}
}
};
export const isGteInterval = (interval) => GTE_INTERVAL_RE.test(interval);
export const isGteInterval = interval => GTE_INTERVAL_RE.test(interval);
export const isIntervalValid = (interval) => {
return isString(interval) &&
(interval === AUTO_INTERVAL || INTERVAL_STRING_RE.test(interval) || isGteInterval(interval));
export const isIntervalValid = interval => {
return (
isString(interval) &&
(interval === AUTO_INTERVAL || INTERVAL_STRING_RE.test(interval) || isGteInterval(interval))
);
};
export const getInterval = (visData, model) => {

View file

@ -22,6 +22,6 @@ import uuid from 'uuid';
export const newMetricAggFn = () => {
return {
id: uuid.v1(),
type: 'count'
type: 'count',
};
};

View file

@ -22,18 +22,21 @@ import _ from 'lodash';
import { newMetricAggFn } from './new_metric_agg_fn';
export const newSeriesFn = (obj = {}) => {
return _.assign({
id: uuid.v1(),
color: '#68BC00',
split_mode: 'everything',
metrics: [ newMetricAggFn() ],
separate_axis: 0,
axis_position: 'right',
formatter: 'number',
chart_type: 'line',
line_width: 1,
point_size: 1,
fill: 0.5,
stacked: 'none'
}, obj);
return _.assign(
{
id: uuid.v1(),
color: '#68BC00',
split_mode: 'everything',
metrics: [newMetricAggFn()],
separate_axis: 0,
axis_position: 'right',
formatter: 'number',
chart_type: 'line',
line_width: 1,
point_size: 1,
fill: 0.5,
stacked: 'none',
},
obj
);
};

View file

@ -23,19 +23,21 @@ import _ from 'lodash';
export const reIdSeries = source => {
const series = _.cloneDeep(source);
series.id = uuid.v1();
series.metrics.forEach((metric) => {
series.metrics.forEach(metric => {
const id = uuid.v1();
const metricId = metric.id;
metric.id = id;
if (series.terms_order_by === metricId) series.terms_order_by = id;
series.metrics.filter(r => r.field === metricId).forEach(r => r.field = id);
series.metrics.filter(r => r.type === 'calculation' &&
r.variables.some(v => v.field === metricId))
series.metrics.filter(r => r.field === metricId).forEach(r => (r.field = id));
series.metrics
.filter(r => r.type === 'calculation' && r.variables.some(v => v.field === metricId))
.forEach(r => {
r.variables.filter(v => v.field === metricId).forEach(v => {
v.id = uuid.v1();
v.field = id;
});
r.variables
.filter(v => v.field === metricId)
.forEach(v => {
v.id = uuid.v1();
v.field = id;
});
});
});
return series;

View file

@ -16,11 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
export const reorder = (
list,
startIndex,
endIndex,
) => {
export const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);

View file

@ -38,18 +38,26 @@ export function replaceVars(str, args = {}, vars = {}) {
const badVar = e.message.split(/"/)[1];
e.error = {
caused_by: {
reason: i18n.translate('tsvb.replaceVars.errors.unknownVarDescription',
{ defaultMessage: '{badVar} is an unknown variable', values: { badVar: '{{' + badVar + '}}' } }),
title: i18n.translate('tsvb.replaceVars.errors.unknownVarTitle', { defaultMessage: 'Error processing your markdown' })
}
reason: i18n.translate('tsvb.replaceVars.errors.unknownVarDescription', {
defaultMessage: '{badVar} is an unknown variable',
values: { badVar: '{{' + badVar + '}}' },
}),
title: i18n.translate('tsvb.replaceVars.errors.unknownVarTitle', {
defaultMessage: 'Error processing your markdown',
}),
},
};
} else {
e.error = {
caused_by: {
reason: i18n.translate('tsvb.replaceVars.errors.markdownErrorDescription', {
defaultMessage: 'Please verify you are only using markdown, known variables, and built-in Handlebars expressions' }),
title: i18n.translate('tsvb.replaceVars.errors.markdownErrorTitle', { defaultMessage: 'Error processing your markdown' })
}
defaultMessage:
'Please verify you are only using markdown, known variables, and built-in Handlebars expressions',
}),
title: i18n.translate('tsvb.replaceVars.errors.markdownErrorTitle', {
defaultMessage: 'Error processing your markdown',
}),
},
};
}
return e;

View file

@ -20,10 +20,7 @@
import _ from 'lodash';
import { newMetricAggFn } from './new_metric_agg_fn';
import { isBasicAgg } from '../../../common/agg_lookup';
import {
handleAdd,
handleChange
} from './collection_actions';
import { handleAdd, handleChange } from './collection_actions';
export const seriesChangeHandler = (props, items) => doc => {
// If we only have one sibling and the user changes to a pipeline

View file

@ -45,7 +45,7 @@ export const tickFormatter = (format = '0,0.[00]', template, getConfig = null) =
formatter = new FieldFormat({ pattern: format }, getConfig);
}
}
return (val) => {
return val => {
let value;
if (!isNumber(val)) {
value = val;

View file

@ -30,13 +30,7 @@ import _ from 'lodash';
import 'brace/mode/markdown';
import 'brace/theme/github';
import {
EuiText,
EuiCodeBlock,
EuiSpacer,
EuiTitle,
EuiCodeEditor,
} from '@elastic/eui';
import { EuiText, EuiCodeBlock, EuiSpacer, EuiTitle, EuiCodeEditor } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
@ -47,7 +41,7 @@ export class MarkdownEditor extends Component {
subscription = null;
componentDidMount() {
if(this.props.visData$) {
if (this.props.visData$) {
this.subscription = this.props.visData$.subscribe(visData => {
this.setState({ visData });
});
@ -55,18 +49,18 @@ export class MarkdownEditor extends Component {
}
componentWillUnmount() {
if(this.subscription) {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
handleChange = (value) => {
handleChange = value => {
this.props.onChange({ markdown: value });
}
};
handleOnLoad = (ace) => {
handleOnLoad = ace => {
this.ace = ace;
}
};
handleVarClick(snippet) {
return () => {
@ -158,13 +152,17 @@ export class MarkdownEditor extends Component {
{handlebarLink} on the available expressions."
values={{
handlebarLink: (
<a href="http://handlebarsjs.com/expressions.html" target="_BLANK" rel="noreferrer noopener">
<a
href="http://handlebarsjs.com/expressions.html"
target="_BLANK"
rel="noreferrer noopener"
>
<FormattedMessage
id="tsvb.markdownEditor.howUseVariablesInMarkdownDescription.documentationLinkText"
defaultMessage="Click here for documentation"
/>
</a>
)
),
}}
/>
</p>
@ -173,16 +171,10 @@ export class MarkdownEditor extends Component {
<thead>
<tr>
<th scope="col">
<FormattedMessage
id="tsvb.markdownEditor.nameLabel"
defaultMessage="Name"
/>
<FormattedMessage id="tsvb.markdownEditor.nameLabel" defaultMessage="Name" />
</th>
<th scope="col">
<FormattedMessage
id="tsvb.markdownEditor.valueLabel"
defaultMessage="Value"
/>
<FormattedMessage id="tsvb.markdownEditor.valueLabel" defaultMessage="Value" />
</th>
</tr>
</thead>
@ -190,7 +182,11 @@ export class MarkdownEditor extends Component {
</table>
{rows.length === 0 && (
<EuiTitle size="xxs" className="tsvbMarkdownVariablesTable__noVariables" data-test-subj="tvbMarkdownEditor__noVariables">
<EuiTitle
size="xxs"
className="tsvbMarkdownVariablesTable__noVariables"
data-test-subj="tvbMarkdownEditor__noVariables"
>
<span>
<FormattedMessage
id="tsvb.markdownEditor.noVariablesAvailableDescription"
@ -208,7 +204,7 @@ export class MarkdownEditor extends Component {
id="tsvb.markdownEditor.howToAccessEntireTreeDescription"
defaultMessage="There is also a special variable named {all} which you can use to access the entire tree. This is useful for
creating lists with data from a group by:"
values={{ all: (<code>_all</code>) }}
values={{ all: <code>_all</code> }}
/>
</p>
</EuiText>

View file

@ -33,7 +33,7 @@ const types = {
metric,
top_n: topN,
gauge,
markdown
markdown,
};
export function PanelConfig(props) {
@ -49,7 +49,8 @@ export function PanelConfig(props) {
defaultMessage="Missing panel config for &ldquo;{modelType}&rdquo;"
values={{ modelType: model.type }}
/>
</div>);
</div>
);
}
PanelConfig.propTypes = {

View file

@ -58,8 +58,10 @@ class GaugePanelConfigUi extends Component {
componentWillMount() {
const { model } = this.props;
const parts = {};
if (!model.gauge_color_rules ||
(model.gauge_color_rules && model.gauge_color_rules.length === 0)) {
if (
!model.gauge_color_rules ||
(model.gauge_color_rules && model.gauge_color_rules.length === 0)
) {
parts.gauge_color_rules = [{ id: uuid.v1() }];
}
if (model.gauge_width == null) parts.gauge_width = 10;
@ -80,7 +82,7 @@ class GaugePanelConfigUi extends Component {
filter: { query: '', language: getDefaultQueryLanguage() },
gauge_style: 'circle',
gauge_inner_width: '',
gauge_width: ''
gauge_width: '',
};
const model = { ...defaults, ...this.props.model };
const handleSelectChange = createSelectHandler(this.props.onChange);
@ -88,14 +90,18 @@ class GaugePanelConfigUi extends Component {
const styleOptions = [
{
label: intl.formatMessage({
id: 'tsvb.gauge.styleOptions.circleLabel', defaultMessage: 'Circle' }),
value: 'circle'
id: 'tsvb.gauge.styleOptions.circleLabel',
defaultMessage: 'Circle',
}),
value: 'circle',
},
{
label: intl.formatMessage({
id: 'tsvb.gauge.styleOptions.halfCircleLabel', defaultMessage: 'Half Circle' }),
value: 'half'
}
id: 'tsvb.gauge.styleOptions.halfCircleLabel',
defaultMessage: 'Half Circle',
}),
value: 'half',
},
];
const htmlId = htmlIdGenerator();
const selectedGaugeStyleOption = styleOptions.find(option => {
@ -120,10 +126,7 @@ class GaugePanelConfigUi extends Component {
<EuiPanel>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.gauge.optionsTab.dataLabel"
defaultMessage="Data"
/>
<FormattedMessage id="tsvb.gauge.optionsTab.dataLabel" defaultMessage="Data" />
</span>
</EuiTitle>
<EuiSpacer size="m" />
@ -140,10 +143,12 @@ class GaugePanelConfigUi extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
label={
<FormattedMessage
id="tsvb.gauge.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>
}
fullWidth
>
<QueryBarInput
@ -180,10 +185,7 @@ class GaugePanelConfigUi extends Component {
<EuiPanel>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.gauge.optionsTab.styleLabel"
defaultMessage="Style"
/>
<FormattedMessage id="tsvb.gauge.optionsTab.styleLabel" defaultMessage="Style" />
</span>
</EuiTitle>
<EuiSpacer size="m" />
@ -192,10 +194,12 @@ class GaugePanelConfigUi extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('gaugeMax')}
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.gaugeMaxLabel"
defaultMessage="Gauge max (empty for auto)"
/>)}
label={
<FormattedMessage
id="tsvb.gauge.optionsTab.gaugeMaxLabel"
defaultMessage="Gauge max (empty for auto)"
/>
}
>
{/*
EUITODO: The following input couldn't be converted to EUI because of type mis-match.
@ -213,10 +217,12 @@ class GaugePanelConfigUi extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('gaugeStyle')}
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.gaugeStyleLabel"
defaultMessage="Gauge style"
/>)}
label={
<FormattedMessage
id="tsvb.gauge.optionsTab.gaugeStyleLabel"
defaultMessage="Gauge style"
/>
}
>
<EuiComboBox
isClearable={false}
@ -230,10 +236,12 @@ class GaugePanelConfigUi extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('innerLine')}
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.innerLineWidthLabel"
defaultMessage="Inner line width"
/>)}
label={
<FormattedMessage
id="tsvb.gauge.optionsTab.innerLineWidthLabel"
defaultMessage="Inner line width"
/>
}
>
<EuiFieldNumber
onChange={handleTextChange('gauge_inner_width')}
@ -244,10 +252,12 @@ class GaugePanelConfigUi extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('gaugeLine')}
label={(<FormattedMessage
id="tsvb.gauge.optionsTab.gaugeLineWidthLabel"
defaultMessage="Gauge line width"
/>)}
label={
<FormattedMessage
id="tsvb.gauge.optionsTab.gaugeLineWidthLabel"
defaultMessage="Gauge line width"
/>
}
>
<EuiFieldNumber
onChange={handleTextChange('gauge_width')}
@ -319,19 +329,10 @@ class GaugePanelConfigUi extends Component {
return (
<div>
<EuiTabs size="s">
<EuiTab
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
<FormattedMessage
id="tsvb.gauge.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage id="tsvb.gauge.dataTab.dataButtonLabel" defaultMessage="Data" />
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
>
<EuiTab isSelected={selectedTab === 'options'} onClick={() => this.switchTab('options')}>
<FormattedMessage
id="tsvb.gauge.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"
@ -342,7 +343,6 @@ class GaugePanelConfigUi extends Component {
</div>
);
}
}
GaugePanelConfigUi.propTypes = {

View file

@ -86,24 +86,33 @@ class MarkdownPanelConfigUi extends Component {
const alignOptions = [
{
label: intl.formatMessage({ id: 'tsvb.markdown.alignOptions.topLabel', defaultMessage: 'Top' }),
value: 'top'
label: intl.formatMessage({
id: 'tsvb.markdown.alignOptions.topLabel',
defaultMessage: 'Top',
}),
value: 'top',
},
{
label: intl.formatMessage({ id: 'tsvb.markdown.alignOptions.middleLabel', defaultMessage: 'Middle' }),
value: 'middle'
label: intl.formatMessage({
id: 'tsvb.markdown.alignOptions.middleLabel',
defaultMessage: 'Middle',
}),
value: 'middle',
},
{
label: intl.formatMessage({ id: 'tsvb.markdown.alignOptions.bottomLabel', defaultMessage: 'Bottom' }),
value: 'bottom'
}
label: intl.formatMessage({
id: 'tsvb.markdown.alignOptions.bottomLabel',
defaultMessage: 'Bottom',
}),
value: 'bottom',
},
];
const selectedAlignOption = alignOptions.find(option => {
return model.markdown_vertical_align === option.value;
});
let view;
if (selectedTab === 'markdown') {
view = (<MarkdownEditor {...this.props}/>);
view = <MarkdownEditor {...this.props} />;
} else if (selectedTab === 'data') {
view = (
<SeriesEditor
@ -121,10 +130,7 @@ class MarkdownPanelConfigUi extends Component {
<EuiPanel>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.markdown.optionsTab.dataLabel"
defaultMessage="Data"
/>
<FormattedMessage id="tsvb.markdown.optionsTab.dataLabel" defaultMessage="Data" />
</span>
</EuiTitle>
<EuiSpacer size="m" />
@ -141,15 +147,19 @@ class MarkdownPanelConfigUi extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label={(<FormattedMessage
id="tsvb.markdown.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
label={
<FormattedMessage
id="tsvb.markdown.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>
}
fullWidth
>
<QueryBarInput
query={{
language: model.filter.language ? model.filter.language : getDefaultQueryLanguage(),
language: model.filter.language
? model.filter.language
: getDefaultQueryLanguage(),
query: model.filter.query || '',
}}
onChange={filter => this.props.onChange({ filter })}
@ -181,10 +191,7 @@ class MarkdownPanelConfigUi extends Component {
<EuiPanel>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.markdown.optionsTab.styleLabel"
defaultMessage="Style"
/>
<FormattedMessage id="tsvb.markdown.optionsTab.styleLabel" defaultMessage="Style" />
</span>
</EuiTitle>
<EuiSpacer size="m" />
@ -296,10 +303,7 @@ class MarkdownPanelConfigUi extends Component {
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
<FormattedMessage
id="tsvb.markdown.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
<FormattedMessage id="tsvb.markdown.dataTab.dataButtonLabel" defaultMessage="Data" />
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}

View file

@ -53,9 +53,12 @@ export class MetricPanelConfig extends Component {
componentWillMount() {
const { model } = this.props;
if (!model.background_color_rules || (model.background_color_rules && model.background_color_rules.length === 0)) {
if (
!model.background_color_rules ||
(model.background_color_rules && model.background_color_rules.length === 0)
) {
this.props.onChange({
background_color_rules: [{ id: uuid.v1() }]
background_color_rules: [{ id: uuid.v1() }],
});
}
}
@ -88,10 +91,7 @@ export class MetricPanelConfig extends Component {
<EuiPanel>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.metric.optionsTab.dataLabel"
defaultMessage="Data"
/>
<FormattedMessage id="tsvb.metric.optionsTab.dataLabel" defaultMessage="Data" />
</span>
</EuiTitle>
<EuiSpacer size="m" />
@ -108,10 +108,12 @@ export class MetricPanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label={(<FormattedMessage
id="tsvb.metric.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
label={
<FormattedMessage
id="tsvb.metric.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>
}
fullWidth
>
<QueryBarInput
@ -168,14 +170,8 @@ export class MetricPanelConfig extends Component {
return (
<div>
<EuiTabs size="s">
<EuiTab
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
<FormattedMessage
id="tsvb.metric.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage id="tsvb.metric.dataTab.dataButtonLabel" defaultMessage="Data" />
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
@ -192,7 +188,6 @@ export class MetricPanelConfig extends Component {
</div>
);
}
}
MetricPanelConfig.propTypes = {

View file

@ -67,7 +67,7 @@ export class TablePanelConfig extends Component {
this.setState({ selectedTab });
}
handlePivotChange = (selectedOption) => {
handlePivotChange = selectedOption => {
const { fields, model } = this.props;
const pivotId = get(selectedOption, '[0].value', null);
const field = fields[model.index_pattern].find(field => field.name === pivotId);
@ -75,7 +75,7 @@ export class TablePanelConfig extends Component {
this.props.onChange({
pivot_id: pivotId,
pivot_type: pivotType
pivot_type: pivotType,
});
};
@ -111,10 +111,12 @@ export class TablePanelConfig extends Component {
<EuiFlexItem data-test-subj="groupByField">
<EuiFormRow
id={htmlId('field')}
label={(<FormattedMessage
id="tsvb.table.dataTab.groupByFieldLabel"
defaultMessage="Group by field"
/>)}
label={
<FormattedMessage
id="tsvb.table.dataTab.groupByFieldLabel"
defaultMessage="Group by field"
/>
}
>
<FieldSelect
fields={this.props.fields}
@ -128,10 +130,12 @@ export class TablePanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('pivotLabelInput')}
label={(<FormattedMessage
id="tsvb.table.dataTab.columnLabel"
defaultMessage="Column label"
/>)}
label={
<FormattedMessage
id="tsvb.table.dataTab.columnLabel"
defaultMessage="Column label"
/>
}
fullWidth
>
<EuiFieldText
@ -145,10 +149,9 @@ export class TablePanelConfig extends Component {
<EuiFlexItem grow={false}>
<EuiFormRow
id={htmlId('pivotRowsInput')}
label={(<FormattedMessage
id="tsvb.table.dataTab.rowsLabel"
defaultMessage="Rows"
/>)}
label={
<FormattedMessage id="tsvb.table.dataTab.rowsLabel" defaultMessage="Rows" />
}
>
{/*
EUITODO: The following input couldn't be converted to EUI because of type mis-match.
@ -181,25 +184,24 @@ export class TablePanelConfig extends Component {
<EuiPanel>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.table.optionsTab.dataLabel"
defaultMessage="Data"
/>
<FormattedMessage id="tsvb.table.optionsTab.dataLabel" defaultMessage="Data" />
</span>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFormRow
id={htmlId('drilldownInput')}
label={(<FormattedMessage
id="tsvb.table.optionsTab.itemUrlLabel"
defaultMessage="Item url"
/>)}
label={
<FormattedMessage
id="tsvb.table.optionsTab.itemUrlLabel"
defaultMessage="Item url"
/>
}
helpText={
<span>
<FormattedMessage
id="tsvb.table.optionsTab.itemUrlHelpText"
defaultMessage="This supports mustache templating. {key} is set to the term."
values={{ key: (<EuiCode>{'{{key}}'}</EuiCode>) }}
values={{ key: <EuiCode>{'{{key}}'}</EuiCode> }}
/>
</span>
}
@ -224,15 +226,19 @@ export class TablePanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilterInput')}
label={(<FormattedMessage
id="tsvb.table.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
label={
<FormattedMessage
id="tsvb.table.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>
}
fullWidth
>
<QueryBarInput
query={{
language: model.filter.language ? model.filter.language : getDefaultQueryLanguage(),
language: model.filter.language
? model.filter.language
: getDefaultQueryLanguage(),
query: model.filter.query || '',
}}
onChange={filter => this.props.onChange({ filter })}
@ -265,19 +271,10 @@ export class TablePanelConfig extends Component {
return (
<div>
<EuiTabs size="s">
<EuiTab
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
<FormattedMessage
id="tsvb.table.dataTab.columnsButtonLabel"
defaultMessage="Columns"
/>
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage id="tsvb.table.dataTab.columnsButtonLabel" defaultMessage="Columns" />
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
>
<EuiTab isSelected={selectedTab === 'options'} onClick={() => this.switchTab('options')}>
<FormattedMessage
id="tsvb.table.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"
@ -288,7 +285,6 @@ export class TablePanelConfig extends Component {
</div>
);
}
}
TablePanelConfig.propTypes = {

View file

@ -63,7 +63,7 @@ class TimeseriesPanelConfigUi extends Component {
axis_max: '',
axis_min: '',
legend_position: 'right',
show_grid: 1
show_grid: 1,
};
const model = { ...defaults, ...this.props.model };
const { selectedTab } = this.state;
@ -74,43 +74,64 @@ class TimeseriesPanelConfigUi extends Component {
const positionOptions = [
{
label: intl.formatMessage({ id: 'tsvb.timeseries.positionOptions.rightLabel', defaultMessage: 'Right' }),
value: 'right'
label: intl.formatMessage({
id: 'tsvb.timeseries.positionOptions.rightLabel',
defaultMessage: 'Right',
}),
value: 'right',
},
{
label: intl.formatMessage({ id: 'tsvb.timeseries.positionOptions.leftLabel', defaultMessage: 'Left' }),
value: 'left'
}
label: intl.formatMessage({
id: 'tsvb.timeseries.positionOptions.leftLabel',
defaultMessage: 'Left',
}),
value: 'left',
},
];
const selectedPositionOption = positionOptions.find(option => {
return model.axis_position === option.value;
});
const scaleOptions = [
{
label: intl.formatMessage({ id: 'tsvb.timeseries.scaleOptions.normalLabel', defaultMessage: 'Normal' }),
value: 'normal'
label: intl.formatMessage({
id: 'tsvb.timeseries.scaleOptions.normalLabel',
defaultMessage: 'Normal',
}),
value: 'normal',
},
{
label: intl.formatMessage({ id: 'tsvb.timeseries.scaleOptions.logLabel', defaultMessage: 'Log' }),
value: 'log'
}
label: intl.formatMessage({
id: 'tsvb.timeseries.scaleOptions.logLabel',
defaultMessage: 'Log',
}),
value: 'log',
},
];
const selectedAxisScaleOption = scaleOptions.find(option => {
return model.axis_scale === option.value;
});
const legendPositionOptions = [
{
label: intl.formatMessage({ id: 'tsvb.timeseries.legendPositionOptions.rightLabel', defaultMessage: 'Right' }),
value: 'right'
label: intl.formatMessage({
id: 'tsvb.timeseries.legendPositionOptions.rightLabel',
defaultMessage: 'Right',
}),
value: 'right',
},
{
label: intl.formatMessage({ id: 'tsvb.timeseries.legendPositionOptions.leftLabel', defaultMessage: 'Left' }),
value: 'left'
label: intl.formatMessage({
id: 'tsvb.timeseries.legendPositionOptions.leftLabel',
defaultMessage: 'Left',
}),
value: 'left',
},
{
label: intl.formatMessage({ id: 'tsvb.timeseries.legendPositionOptions.bottomLabel', defaultMessage: 'Bottom' }),
value: 'bottom'
}
label: intl.formatMessage({
id: 'tsvb.timeseries.legendPositionOptions.bottomLabel',
defaultMessage: 'Bottom',
}),
value: 'bottom',
},
];
const selectedLegendPosOption = legendPositionOptions.find(option => {
return model.legend_position === option.value;
@ -142,10 +163,7 @@ class TimeseriesPanelConfigUi extends Component {
<EuiPanel>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.timeseries.optionsTab.dataLabel"
defaultMessage="Data"
/>
<FormattedMessage id="tsvb.timeseries.optionsTab.dataLabel" defaultMessage="Data" />
</span>
</EuiTitle>
<EuiSpacer size="m" />
@ -162,10 +180,12 @@ class TimeseriesPanelConfigUi extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
label={
<FormattedMessage
id="tsvb.timeseries.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>
}
fullWidth
>
<QueryBarInput
@ -214,38 +234,38 @@ class TimeseriesPanelConfigUi extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('axisMin')}
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.axisMinLabel"
defaultMessage="Axis min"
/>)}
label={
<FormattedMessage
id="tsvb.timeseries.optionsTab.axisMinLabel"
defaultMessage="Axis min"
/>
}
>
<EuiFieldText
onChange={handleTextChange('axis_min')}
value={model.axis_min}
/>
<EuiFieldText onChange={handleTextChange('axis_min')} value={model.axis_min} />
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
id={htmlId('axisMax')}
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.axisMaxLabel"
defaultMessage="Axis max"
/>)}
label={
<FormattedMessage
id="tsvb.timeseries.optionsTab.axisMaxLabel"
defaultMessage="Axis max"
/>
}
>
<EuiFieldText
onChange={handleTextChange('axis_max')}
value={model.axis_max}
/>
<EuiFieldText onChange={handleTextChange('axis_max')} value={model.axis_max} />
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
id={htmlId('axisPos')}
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.axisPositionLabel"
defaultMessage="Axis position"
/>)}
label={
<FormattedMessage
id="tsvb.timeseries.optionsTab.axisPositionLabel"
defaultMessage="Axis position"
/>
}
>
<EuiComboBox
isClearable={false}
@ -259,10 +279,12 @@ class TimeseriesPanelConfigUi extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('axisScale')}
label={(<FormattedMessage
id="tsvb.timeseries.optionsTab.axisScaleLabel"
defaultMessage="Axis scale"
/>)}
label={
<FormattedMessage
id="tsvb.timeseries.optionsTab.axisScaleLabel"
defaultMessage="Axis scale"
/>
}
>
<EuiComboBox
isClearable={false}
@ -335,11 +357,7 @@ class TimeseriesPanelConfigUi extends Component {
</EuiFormLabel>
</EuiFlexItem>
<EuiFlexItem>
<YesNo
value={model.show_grid}
name="show_grid"
onChange={this.props.onChange}
/>
<YesNo value={model.show_grid} name="show_grid" onChange={this.props.onChange} />
</EuiFlexItem>
</EuiFlexGroup>
</EuiPanel>
@ -349,19 +367,10 @@ class TimeseriesPanelConfigUi extends Component {
return (
<div>
<EuiTabs size="s">
<EuiTab
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
<FormattedMessage
id="tsvb.timeseries.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage id="tsvb.timeseries.dataTab.dataButtonLabel" defaultMessage="Data" />
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
>
<EuiTab isSelected={selectedTab === 'options'} onClick={() => this.switchTab('options')}>
<FormattedMessage
id="tsvb.timeseries.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"

View file

@ -49,7 +49,6 @@ const { QueryBarInput } = data.query.ui;
const localStorage = new Storage(window.localStorage);
export class TopNPanelConfig extends Component {
constructor(props) {
super(props);
this.state = { selectedTab: 'data' };
@ -70,7 +69,10 @@ export class TopNPanelConfig extends Component {
render() {
const { selectedTab } = this.state;
const defaults = { drilldown_url: '', filter: { query: '', language: getDefaultQueryLanguage() } };
const defaults = {
drilldown_url: '',
filter: { query: '', language: getDefaultQueryLanguage() },
};
const model = { ...defaults, ...this.props.model };
const htmlId = htmlIdGenerator();
const handleTextChange = createTextHandler(this.props.onChange);
@ -92,25 +94,24 @@ export class TopNPanelConfig extends Component {
<EuiPanel>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.topN.optionsTab.dataLabel"
defaultMessage="Data"
/>
<FormattedMessage id="tsvb.topN.optionsTab.dataLabel" defaultMessage="Data" />
</span>
</EuiTitle>
<EuiSpacer size="m" />
<EuiFormRow
id={htmlId('itemUrl')}
label={(<FormattedMessage
id="tsvb.topN.optionsTab.itemUrlLabel"
defaultMessage="Item url"
/>)}
label={
<FormattedMessage
id="tsvb.topN.optionsTab.itemUrlLabel"
defaultMessage="Item url"
/>
}
helpText={
<span>
<FormattedMessage
id="tsvb.topN.optionsTab.itemUrlDescription"
defaultMessage="This supports mustache templating. {key} is set to the term."
values={{ key: (<EuiCode>{'{{key}}'}</EuiCode>) }}
values={{ key: <EuiCode>{'{{key}}'}</EuiCode> }}
/>
</span>
}
@ -135,15 +136,19 @@ export class TopNPanelConfig extends Component {
<EuiFlexItem>
<EuiFormRow
id={htmlId('panelFilter')}
label={(<FormattedMessage
id="tsvb.topN.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>)}
label={
<FormattedMessage
id="tsvb.topN.optionsTab.panelFilterLabel"
defaultMessage="Panel filter"
/>
}
fullWidth
>
<QueryBarInput
query={{
language: model.filter.language ? model.filter.language : getDefaultQueryLanguage(),
language: model.filter.language
? model.filter.language
: getDefaultQueryLanguage(),
query: model.filter.query || '',
}}
onChange={filter => this.props.onChange({ filter })}
@ -175,10 +180,7 @@ export class TopNPanelConfig extends Component {
<EuiPanel>
<EuiTitle size="s">
<span>
<FormattedMessage
id="tsvb.topN.optionsTab.styleLabel"
defaultMessage="Style"
/>
<FormattedMessage id="tsvb.topN.optionsTab.styleLabel" defaultMessage="Style" />
</span>
</EuiTitle>
<EuiSpacer size="m" />
@ -227,19 +229,10 @@ export class TopNPanelConfig extends Component {
return (
<div>
<EuiTabs size="s">
<EuiTab
isSelected={selectedTab === 'data'}
onClick={() => this.switchTab('data')}
>
<FormattedMessage
id="tsvb.topN.dataTab.dataButtonLabel"
defaultMessage="Data"
/>
<EuiTab isSelected={selectedTab === 'data'} onClick={() => this.switchTab('data')}>
<FormattedMessage id="tsvb.topN.dataTab.dataButtonLabel" defaultMessage="Data" />
</EuiTab>
<EuiTab
isSelected={selectedTab === 'options'}
onClick={() => this.switchTab('options')}
>
<EuiTab isSelected={selectedTab === 'options'} onClick={() => this.switchTab('options')}>
<FormattedMessage
id="tsvb.topN.optionsTab.panelOptionsButtonLabel"
defaultMessage="Panel options"
@ -250,7 +243,6 @@ export class TopNPanelConfig extends Component {
</div>
);
}
}
TopNPanelConfig.propTypes = {

View file

@ -51,11 +51,11 @@ export class Series extends Component {
this.visDataSubscription = null;
}
switchTab = (selectedTab) => {
switchTab = selectedTab => {
this.setState({ selectedTab });
};
handleChange = (part) => {
handleChange = part => {
if (this.props.onChange) {
const { model } = this.props;
const doc = assign({}, model, part);
@ -71,7 +71,7 @@ export class Series extends Component {
});
};
toggleVisible = (e) => {
toggleVisible = e => {
e.preventDefault();
this.setState({
@ -81,10 +81,11 @@ export class Series extends Component {
componentDidMount() {
if (this.props.visData$) {
this.visDataSubscription = this.props.visData$
.subscribe(visData => this.setState({
this.visDataSubscription = this.props.visData$.subscribe(visData =>
this.setState({
uiRestrictions: get(visData, 'uiRestrictions'),
}));
})
);
}
}
@ -114,13 +115,15 @@ export class Series extends Component {
dragHandleProps: this.props.dragHandleProps,
indexPatternForQuery: panel.index_pattern || panel.default_index_pattern,
};
return Boolean(Component) ?
(<Component {...params}/>) :
(<FormattedMessage
return Boolean(Component) ? (
<Component {...params} />
) : (
<FormattedMessage
id="tsvb.seriesConfig.missingSeriesComponentDescription"
defaultMessage="Missing Series component for panel type: {panelType}"
values={{ panelType: panel.type }}
/>);
/>
);
}
componentWillUnmount() {

View file

@ -48,31 +48,29 @@ export const SeriesConfig = props => {
const handleSelectChange = createSelectHandler(props.onChange);
const handleTextChange = createTextHandler(props.onChange);
const htmlId = htmlIdGenerator();
const seriesIndexPattern = (props.model.override_index_pattern && props.model.series_index_pattern) ?
props.model.series_index_pattern : props.indexPatternForQuery;
const seriesIndexPattern =
props.model.override_index_pattern && props.model.series_index_pattern
? props.model.series_index_pattern
: props.indexPatternForQuery;
return (
<div className="tvbAggRow">
<DataFormatPicker
onChange={handleSelectChange('formatter')}
value={model.formatter}
/>
<DataFormatPicker onChange={handleSelectChange('formatter')} value={model.formatter} />
<EuiHorizontalRule margin="s" />
<EuiFormRow
id={htmlId('series_filter')}
label={(<FormattedMessage
id="tsvb.seriesConfig.filterLabel"
defaultMessage="Filter"
/>)}
label={<FormattedMessage id="tsvb.seriesConfig.filterLabel" defaultMessage="Filter" />}
fullWidth
>
<QueryBarInput
query={{
language: (model.filter && model.filter.language) ? model.filter.language : getDefaultQueryLanguage(),
query: (model.filter && model.filter.query) ? model.filter.query : ''
language:
model.filter && model.filter.language
? model.filter.language
: getDefaultQueryLanguage(),
query: model.filter && model.filter.query ? model.filter.query : '',
}}
onChange={filter => props.onChange({ filter })}
appName={'VisEditor'}
@ -88,19 +86,18 @@ export const SeriesConfig = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('template')}
label={(<FormattedMessage
id="tsvb.seriesConfig.templateLabel"
defaultMessage="Template"
/>)}
helpText={(
label={
<FormattedMessage id="tsvb.seriesConfig.templateLabel" defaultMessage="Template" />
}
helpText={
<span>
<FormattedMessage
id="tsvb.seriesConfig.templateHelpText"
defaultMessage="eg. {templateExample}"
values={{ templateExample: (<EuiCode>{'{{value}}/s'}</EuiCode>) }}
values={{ templateExample: <EuiCode>{'{{value}}/s'}</EuiCode> }}
/>
</span>
)}
}
fullWidth
>
<EuiFieldText
@ -113,11 +110,13 @@ export const SeriesConfig = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('offsetSeries')}
label={(<FormattedMessage
id="tsvb.seriesConfig.offsetSeriesTimeLabel"
defaultMessage="Offset series time by (1m, 1h, 1w, 1d)"
description="1m, 1h, 1w and 1d are required values and must not be translated."
/>)}
label={
<FormattedMessage
id="tsvb.seriesConfig.offsetSeriesTimeLabel"
defaultMessage="Offset series time by (1m, 1h, 1w, 1d)"
description="1m, 1h, 1w and 1d are required values and must not be translated."
/>
}
>
<EuiFieldText
data-test-subj="offsetTimeSeries"
@ -155,7 +154,6 @@ export const SeriesConfig = props => {
/>
</EuiFlexItem>
</EuiFlexGroup>
</div>
);
};

View file

@ -22,11 +22,7 @@ import React, { Component } from 'react';
import { find } from 'lodash';
import { reIdSeries } from './lib/re_id_series';
import { Series } from './series';
import {
handleAdd,
handleDelete,
handleChange,
} from './lib/collection_actions';
import { handleAdd, handleDelete, handleChange } from './lib/collection_actions';
import { newSeriesFn } from './lib/new_series_fn';
import { EuiDragDropContext, EuiDroppable, EuiDraggable } from '@elastic/eui';
import { reorder } from './lib/reorder';
@ -34,7 +30,6 @@ import { reorder } from './lib/reorder';
const DROPPABLE_ID = 'series_editor_dnd';
export class SeriesEditor extends Component {
handleClone = series => {
const newSeries = reIdSeries(series);
@ -52,10 +47,9 @@ export class SeriesEditor extends Component {
};
getSortFunction = ({ destination, source }) =>
(destination.droppableId === source.droppableId && source.droppableId === DROPPABLE_ID ?
this.sortSeries :
this.sortAggregations
);
destination.droppableId === source.droppableId && source.droppableId === DROPPABLE_ID
? this.sortSeries
: this.sortAggregations;
sortSeries = ({ destination, source }) => {
this.props.onChange({
@ -82,16 +76,11 @@ export class SeriesEditor extends Component {
render() {
const { limit, model, name, fields, colorPicker } = this.props;
const list = model[name]
.filter((val, index) => index < (limit || Infinity));
const list = model[name].filter((val, index) => index < (limit || Infinity));
return (
<EuiDragDropContext onDragEnd={this.sortHandler}>
<EuiDroppable
droppableId={DROPPABLE_ID}
spacing="l"
type="MACRO"
>
<EuiDroppable droppableId={DROPPABLE_ID} spacing="l" type="MACRO">
{list.map((row, idx) => (
<EuiDraggable
spacing="m"
@ -109,7 +98,7 @@ export class SeriesEditor extends Component {
disableDelete={model[name].length < 2}
fields={fields}
onAdd={() => handleAdd(this.props, newSeriesFn)}
onChange={(doc) => handleChange(this.props, doc)}
onChange={doc => handleChange(this.props, doc)}
onClone={() => this.handleClone(row)}
onDelete={() => handleDelete(this.props, row)}
visData$={this.props.visData$}

View file

@ -37,7 +37,6 @@ const SPLIT_MODES = {
};
export class Split extends Component {
componentWillReceiveProps(nextProps) {
const { model } = nextProps;
if (model.split_mode === 'filters' && !model.split_filters) {
@ -48,8 +47,8 @@ export class Split extends Component {
id: uuid.v1(),
filter: {
query: '',
language: getDefaultQueryLanguage()
}
language: getDefaultQueryLanguage(),
},
},
],
});
@ -75,7 +74,8 @@ export class Split extends Component {
render() {
const { model, panel, uiRestrictions } = this.props;
const indexPattern = (model.override_index_pattern && model.series_index_pattern) ||
const indexPattern =
(model.override_index_pattern && model.series_index_pattern) ||
(panel.index_pattern || panel.default_index_pattern);
const splitMode = get(this.props, 'model.split_mode', SPLIT_MODES.EVERYTHING);

View file

@ -24,7 +24,7 @@ import React from 'react';
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
export const SplitByEverything = (props) => {
export const SplitByEverything = props => {
const { onChange, model, uiRestrictions } = props;
const htmlId = htmlIdGenerator();
const handleSelectChange = createSelectHandler(onChange);
@ -33,10 +33,9 @@ export const SplitByEverything = (props) => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('group')}
label={(<FormattedMessage
id="tsvb.splits.everything.groupByLabel"
defaultMessage="Group by"
/>)}
label={
<FormattedMessage id="tsvb.splits.everything.groupByLabel" defaultMessage="Group by" />
}
>
<GroupBySelect
value={model.split_mode}
@ -54,5 +53,3 @@ SplitByEverything.propTypes = {
onChange: PropTypes.func,
uiRestrictions: PropTypes.object,
};

View file

@ -40,10 +40,9 @@ export const SplitByFilter = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('group')}
label={(<FormattedMessage
id="tsvb.splits.filter.groupByLabel"
defaultMessage="Group by"
/>)}
label={
<FormattedMessage id="tsvb.splits.filter.groupByLabel" defaultMessage="Group by" />
}
>
<GroupBySelect
value={model.split_mode}
@ -55,10 +54,12 @@ export const SplitByFilter = props => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('query')}
label={(<FormattedMessage
id="tsvb.splits.filter.queryStringLabel"
defaultMessage="Query string"
/>)}
label={
<FormattedMessage
id="tsvb.splits.filter.queryStringLabel"
defaultMessage="Query string"
/>
}
>
<QueryBarInput
query={{

View file

@ -38,22 +38,24 @@ class FilterItemsUi extends Component {
}
handleChange(item, name) {
return (e) => {
return e => {
const handleChange = collectionActions.handleChange.bind(null, this.props);
handleChange(_.assign({}, item, {
[name]: _.get(e, 'value', _.get(e, 'target.value'))
}));
handleChange(
_.assign({}, item, {
[name]: _.get(e, 'value', _.get(e, 'target.value')),
})
);
};
}
handleQueryChange = (model, filter) => {
const part = { filter };
collectionActions.handleChange(this.props, _.assign({}, model, part));
}
};
renderRow(row, i, items) {
const indexPatterns = this.props.indexPatterns;
const defaults = { filter: '', label: '' };
const model = { ...defaults, ...row };
const handleChange = (part) => {
const handleChange = part => {
const fn = collectionActions.handleChange.bind(null, this.props);
fn(_.assign({}, model, part));
};
@ -63,13 +65,11 @@ class FilterItemsUi extends Component {
id: uuid.v1(),
filter: { language: model.filter.language || getDefaultQueryLanguage(), query: '' },
});
const handleAdd = collectionActions.handleAdd
.bind(null, this.props, newFilter);
const handleDelete = collectionActions.handleDelete
.bind(null, this.props, model);
const handleAdd = collectionActions.handleAdd.bind(null, this.props, newFilter);
const handleDelete = collectionActions.handleDelete.bind(null, this.props, model);
const { intl } = this.props;
return (
return (
<EuiFlexGroup gutterSize="s" className="tvbAggRow" alignItems="center" key={model.id}>
<EuiFlexItem grow={false}>
<ColorPicker
@ -85,7 +85,7 @@ class FilterItemsUi extends Component {
language: model.filter.language || getDefaultQueryLanguage(),
query: model.filter.query || '',
}}
onChange={(query) => this.handleQueryChange(model, query)}
onChange={query => this.handleQueryChange(model, query)}
appName={'VisEditor'}
indexPatterns={[indexPatterns]}
store={localStorage}
@ -93,8 +93,14 @@ class FilterItemsUi extends Component {
</EuiFlexItem>
<EuiFlexItem>
<EuiFieldText
placeholder={intl.formatMessage({ id: 'tsvb.splits.filterItems.labelPlaceholder', defaultMessage: 'Label' })}
aria-label={intl.formatMessage({ id: 'tsvb.splits.filterItems.labelAriaLabel', defaultMessage: 'Label' })}
placeholder={intl.formatMessage({
id: 'tsvb.splits.filterItems.labelPlaceholder',
defaultMessage: 'Label',
})}
aria-label={intl.formatMessage({
id: 'tsvb.splits.filterItems.labelAriaLabel',
defaultMessage: 'Label',
})}
onChange={this.handleChange(model, 'label')}
value={model.label}
fullWidth
@ -114,15 +120,10 @@ class FilterItemsUi extends Component {
render() {
const { model, name } = this.props;
if (!model[name]) return (<div/>);
if (!model[name]) return <div />;
const rows = model[name].map(this.renderRow);
return (
<div>
{ rows }
</div>
);
return <div>{rows}</div>;
}
}
FilterItemsUi.propTypes = {

View file

@ -25,7 +25,7 @@ import React from 'react';
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
export const SplitByFilters = (props) => {
export const SplitByFilters = props => {
const { onChange, model, uiRestrictions, indexPattern } = props;
const htmlId = htmlIdGenerator();
const handleSelectChange = createSelectHandler(onChange);
@ -35,10 +35,9 @@ export const SplitByFilters = (props) => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('group')}
label={(<FormattedMessage
id="tsvb.splits.filters.groupByLabel"
defaultMessage="Group by"
/>)}
label={
<FormattedMessage id="tsvb.splits.filters.groupByLabel" defaultMessage="Group by" />
}
>
<GroupBySelect
value={model.split_mode}
@ -63,5 +62,5 @@ SplitByFilters.propTypes = {
model: PropTypes.object,
onChange: PropTypes.func,
uiRestrictions: PropTypes.object,
indexPatterns: PropTypes.array
indexPatterns: PropTypes.array,
};

View file

@ -19,15 +19,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import {
EuiComboBox,
} from '@elastic/eui';
import { EuiComboBox } from '@elastic/eui';
import { injectI18n } from '@kbn/i18n/react';
import { isGroupByFieldsEnabled } from '../../lib/check_ui_restrictions';
function GroupBySelectUi(props) {
const { intl, uiRestrictions } = props;
const modeOptions = ([
const modeOptions = [
{
label: intl.formatMessage({
id: 'tsvb.splits.groupBySelect.modeOptions.everythingLabel',
@ -36,7 +34,10 @@ function GroupBySelectUi(props) {
value: 'everything',
},
{
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.filterLabel', defaultMessage: 'Filter' }),
label: intl.formatMessage({
id: 'tsvb.splits.groupBySelect.modeOptions.filterLabel',
defaultMessage: 'Filter',
}),
value: 'filter',
},
{
@ -47,10 +48,13 @@ function GroupBySelectUi(props) {
value: 'filters',
},
{
label: intl.formatMessage({ id: 'tsvb.splits.groupBySelect.modeOptions.termsLabel', defaultMessage: 'Terms' }),
label: intl.formatMessage({
id: 'tsvb.splits.groupBySelect.modeOptions.termsLabel',
defaultMessage: 'Terms',
}),
value: 'terms',
},
]).map(field => ({
].map(field => ({
...field,
disabled: !isGroupByFieldsEnabled(field.value, uiRestrictions),
}));

View file

@ -32,14 +32,21 @@ import {
EuiFormRow,
EuiFieldNumber,
EuiComboBox,
EuiFieldText
EuiFieldText,
} from '@elastic/eui';
import { injectI18n, FormattedMessage } from '@kbn/i18n/react';
import { FIELD_TYPES } from '../../../common/field_types';
const DEFAULTS = { terms_direction: 'desc', terms_size: 10, terms_order_by: '_count' };
export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesModel, fields, uiRestrictions }) => {
export const SplitByTermsUI = ({
onChange,
indexPattern,
intl,
model: seriesModel,
fields,
uiRestrictions,
}) => {
const htmlId = htmlIdGenerator();
const handleTextChange = createTextHandler(onChange);
const handleSelectChange = createSelectHandler(onChange);
@ -47,21 +54,30 @@ export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesMode
const { metrics } = model;
const defaultCount = {
value: '_count',
label: intl.formatMessage({ id: 'tsvb.splits.terms.defaultCountLabel', defaultMessage: 'Doc Count (default)' })
label: intl.formatMessage({
id: 'tsvb.splits.terms.defaultCountLabel',
defaultMessage: 'Doc Count (default)',
}),
};
const terms = {
value: '_key',
label: intl.formatMessage({ id: 'tsvb.splits.terms.termsLabel', defaultMessage: 'Terms' })
label: intl.formatMessage({ id: 'tsvb.splits.terms.termsLabel', defaultMessage: 'Terms' }),
};
const dirOptions = [
{
value: 'desc',
label: intl.formatMessage({ id: 'tsvb.splits.terms.dirOptions.descendingLabel', defaultMessage: 'Descending' })
label: intl.formatMessage({
id: 'tsvb.splits.terms.dirOptions.descendingLabel',
defaultMessage: 'Descending',
}),
},
{
value: 'asc',
label: intl.formatMessage({ id: 'tsvb.splits.terms.dirOptions.ascendingLabel', defaultMessage: 'Ascending' })
label: intl.formatMessage({
id: 'tsvb.splits.terms.dirOptions.ascendingLabel',
defaultMessage: 'Ascending',
}),
},
];
const selectedDirectionOption = dirOptions.find(option => {
@ -76,10 +92,9 @@ export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesMode
<EuiFlexItem>
<EuiFormRow
id={htmlId('group')}
label={(<FormattedMessage
id="tsvb.splits.terms.groupByLabel"
defaultMessage="Group by"
/>)}
label={
<FormattedMessage id="tsvb.splits.terms.groupByLabel" defaultMessage="Group by" />
}
>
<GroupBySelect
value={model.split_mode}
@ -91,11 +106,13 @@ export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesMode
<EuiFlexItem>
<EuiFormRow
id={htmlId('by')}
label={(<FormattedMessage
id="tsvb.splits.terms.byLabel"
defaultMessage="By"
description="This labels a field selector allowing the user to chose 'by' which field to group."
/>)}
label={
<FormattedMessage
id="tsvb.splits.terms.byLabel"
defaultMessage="By"
description="This labels a field selector allowing the user to chose 'by' which field to group."
/>
}
>
<FieldSelect
indexPattern={indexPattern}
@ -114,23 +131,27 @@ export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesMode
<EuiFlexItem>
<EuiFormRow
id={htmlId('include')}
label={(<FormattedMessage
id="tsvb.splits.terms.includeLabel"
defaultMessage="Include"
/>)}
label={
<FormattedMessage id="tsvb.splits.terms.includeLabel" defaultMessage="Include" />
}
>
<EuiFieldText value={model.terms_include} onChange={handleTextChange('terms_include')} />
<EuiFieldText
value={model.terms_include}
onChange={handleTextChange('terms_include')}
/>
</EuiFormRow>
</EuiFlexItem>
<EuiFlexItem>
<EuiFormRow
id={htmlId('exclude')}
label={(<FormattedMessage
id="tsvb.splits.terms.excludeLabel"
defaultMessage="Exclude"
/>)}
label={
<FormattedMessage id="tsvb.splits.terms.excludeLabel" defaultMessage="Exclude" />
}
>
<EuiFieldText value={model.terms_exclude} onChange={handleTextChange('terms_exclude')} />
<EuiFieldText
value={model.terms_exclude}
onChange={handleTextChange('terms_exclude')}
/>
</EuiFormRow>
</EuiFlexItem>
</EuiFlexGroup>
@ -140,13 +161,13 @@ export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesMode
<EuiFlexItem>
<EuiFormRow
id={htmlId('top')}
label={(<FormattedMessage
id="tsvb.splits.terms.topLabel"
defaultMessage="Top"
/>)}
label={<FormattedMessage id="tsvb.splits.terms.topLabel" defaultMessage="Top" />}
>
<EuiFieldNumber
placeholder={intl.formatMessage({ id: 'tsvb.splits.terms.sizePlaceholder', defaultMessage: 'Size' })}
placeholder={intl.formatMessage({
id: 'tsvb.splits.terms.sizePlaceholder',
defaultMessage: 'Size',
})}
value={Number(model.terms_size)}
onChange={handleTextChange('terms_size')}
/>
@ -155,10 +176,9 @@ export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesMode
<EuiFlexItem>
<EuiFormRow
id={htmlId('order')}
label={(<FormattedMessage
id="tsvb.splits.terms.orderByLabel"
defaultMessage="Order by"
/>)}
label={
<FormattedMessage id="tsvb.splits.terms.orderByLabel" defaultMessage="Order by" />
}
>
<MetricSelect
metrics={metrics}
@ -173,10 +193,9 @@ export const SplitByTermsUI = ({ onChange, indexPattern, intl, model: seriesMode
<EuiFlexItem>
<EuiFormRow
id={htmlId('direction')}
label={(<FormattedMessage
id="tsvb.splits.terms.directionLabel"
defaultMessage="Direction"
/>)}
label={
<FormattedMessage id="tsvb.splits.terms.directionLabel" defaultMessage="Direction" />
}
>
<EuiComboBox
isClearable={false}

View file

@ -40,12 +40,12 @@ describe('src/legacy/core_plugins/metrics/public/components/splits/terms.test.js
formatMessage: jest.fn(),
},
model: {
terms_field: 'OriginCityName'
terms_field: 'OriginCityName',
},
onChange: jest.fn(),
indexPattern: 'kibana_sample_data_flights',
fields: {
'kibana_sample_data_flights': [
kibana_sample_data_flights: [
{
aggregatable: true,
name: 'OriginCityName',
@ -53,8 +53,8 @@ describe('src/legacy/core_plugins/metrics/public/components/splits/terms.test.js
searchable: true,
type: 'string',
esTypes: ['keyword'],
}
]
},
],
},
};
});

View file

@ -21,11 +21,18 @@ import { createSelectHandler } from '../lib/create_select_handler';
import { GroupBySelect } from './group_by_select';
import PropTypes from 'prop-types';
import React from 'react';
import { htmlIdGenerator, EuiFlexGroup, EuiFlexItem, EuiFormRow, EuiCode, EuiTitle } from '@elastic/eui';
import {
htmlIdGenerator,
EuiFlexGroup,
EuiFlexItem,
EuiFormRow,
EuiCode,
EuiTitle,
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
export const SplitUnsupported = (props) => {
export const SplitUnsupported = props => {
const { onChange, model, uiRestrictions } = props;
const htmlId = htmlIdGenerator();
const handleSelectChange = createSelectHandler(onChange);
@ -34,10 +41,9 @@ export const SplitUnsupported = (props) => {
<EuiFlexItem>
<EuiFormRow
id={htmlId('group')}
label={(<FormattedMessage
id="tsvb.splits.everything.groupByLabel"
defaultMessage="Group by"
/>)}
label={
<FormattedMessage id="tsvb.splits.everything.groupByLabel" defaultMessage="Group by" />
}
>
<GroupBySelect
value={model.split_mode}
@ -52,7 +58,7 @@ export const SplitUnsupported = (props) => {
<FormattedMessage
id="tsvb.unsupportedSplit.splitIsUnsupportedDescription"
defaultMessage="Split by {modelType} is unsupported."
values={{ modelType: (<EuiCode>{model.split_mode}</EuiCode>) }}
values={{ modelType: <EuiCode>{model.split_mode}</EuiCode> }}
/>
</span>
</EuiTitle>
@ -66,5 +72,3 @@ SplitUnsupported.propTypes = {
onChange: PropTypes.func,
uiRestrictions: PropTypes.object,
};

View file

@ -69,7 +69,7 @@ export class VisEditor extends Component {
this.props.vis.updateState();
}, VIS_STATE_DEBOUNCE_DELAY);
isValidKueryQuery = (filterQuery) => {
isValidKueryQuery = filterQuery => {
if (filterQuery && filterQuery.language === 'kuery') {
try {
fromKueryExpression(filterQuery.query, { allowLeadingWildcards: queryOptions });
@ -99,11 +99,12 @@ export class VisEditor extends Component {
if (this.props.isEditorMode) {
const extractedIndexPatterns = extractIndexPatterns(nextModel);
if (!isEqual(this.state.extractedIndexPatterns, extractedIndexPatterns)) {
fetchFields(extractedIndexPatterns)
.then(visFields => this.setState({
fetchFields(extractedIndexPatterns).then(visFields =>
this.setState({
visFields,
extractedIndexPatterns,
}));
})
);
}
}
@ -118,7 +119,7 @@ export class VisEditor extends Component {
this.setState({ dirty: false });
};
handleAutoApplyToggle = (event) => {
handleAutoApplyToggle = event => {
this.setState({ autoApply: event.target.checked });
};
@ -150,7 +151,7 @@ export class VisEditor extends Component {
return (
<div className="tvbEditor" data-test-subj="tvbVisEditor">
<div className="tvbEditor--hideForReporting">
<VisPicker model={model} onChange={this.handleChange}/>
<VisPicker model={model} onChange={this.handleChange} />
</div>
<VisEditorVisualization
dirty={this.state.dirty}

View file

@ -22,7 +22,13 @@ import { get, isEqual } from 'lodash';
import { keyCodes, EuiFlexGroup, EuiFlexItem, EuiButton, EuiText, EuiSwitch } from '@elastic/eui';
import { getVisualizeLoader } from 'ui/visualize/loader/visualize_loader';
import { FormattedMessage, injectI18n } from '@kbn/i18n/react';
import { getInterval, convertIntervalIntoUnit, isIntervalValid, isGteInterval, AUTO_INTERVAL } from './lib/get_interval';
import {
getInterval,
convertIntervalIntoUnit,
isIntervalValid,
isGteInterval,
AUTO_INTERVAL,
} from './lib/get_interval';
import { PANEL_TYPES } from '../../common/panel_types';
const MIN_CHART_HEIGHT = 250;
@ -50,9 +56,9 @@ class VisEditorVisualizationUI extends Component {
this.setState({ dragging: false });
};
handleMouseMove = (event) => {
handleMouseMove = event => {
if (this.state.dragging) {
this.setState((prevState) => ({
this.setState(prevState => ({
height: Math.max(MIN_CHART_HEIGHT, prevState.height + event.movementY),
}));
}
@ -66,13 +72,7 @@ class VisEditorVisualizationUI extends Component {
return;
}
const {
uiState,
timeRange,
appState,
savedObj,
onDataChange,
} = this.props;
const { uiState, timeRange, appState, savedObj, onDataChange } = this.props;
this._handler = loader.embedVisualizationWithSavedObject(this._visEl.current, savedObj, {
listenOnChange: false,
@ -81,7 +81,7 @@ class VisEditorVisualizationUI extends Component {
appState,
});
this._subscription = this._handler.data$.subscribe((data) => {
this._subscription = this._handler.data$.subscribe(data => {
this.setPanelInterval(data.visData);
onDataChange(data);
});
@ -101,11 +101,11 @@ class VisEditorVisualizationUI extends Component {
* We use 15px steps to do the scaling and make sure the chart has at least its
* defined minimum width (MIN_CHART_HEIGHT).
*/
onSizeHandleKeyDown = (ev) => {
onSizeHandleKeyDown = ev => {
const { keyCode } = ev;
if (keyCode === keyCodes.UP || keyCode === keyCodes.DOWN) {
ev.preventDefault();
this.setState((prevState) => {
this.setState(prevState => {
const newHeight = prevState.height + (keyCode === keyCodes.UP ? -15 : 15);
return {
height: Math.max(MIN_CHART_HEIGHT, newHeight),
@ -118,14 +118,16 @@ class VisEditorVisualizationUI extends Component {
const type = get(this.props, 'model.type', '');
const interval = get(this.props, 'model.interval', AUTO_INTERVAL);
return [
PANEL_TYPES.METRIC,
PANEL_TYPES.TOP_N,
PANEL_TYPES.GAUGE,
PANEL_TYPES.MARKDOWN,
PANEL_TYPES.TABLE,
].includes(type) && (interval === AUTO_INTERVAL
|| isGteInterval(interval) || !isIntervalValid(interval));
return (
[
PANEL_TYPES.METRIC,
PANEL_TYPES.TOP_N,
PANEL_TYPES.GAUGE,
PANEL_TYPES.MARKDOWN,
PANEL_TYPES.TABLE,
].includes(type) &&
(interval === AUTO_INTERVAL || isGteInterval(interval) || !isIntervalValid(interval))
);
}
getFormattedPanelInterval() {
@ -159,14 +161,7 @@ class VisEditorVisualizationUI extends Component {
}
render() {
const {
dirty,
autoApply,
title,
description,
onToggleAutoApply,
onCommit,
} = this.props;
const { dirty, autoApply, title, description, onToggleAutoApply, onCommit } = this.props;
const style = { height: this.state.height };
if (this.state.dragging) {
@ -175,68 +170,81 @@ class VisEditorVisualizationUI extends Component {
const panelInterval = this.hasShowPanelIntervalValue() && this.getFormattedPanelInterval();
let applyMessage = (<FormattedMessage
id="tsvb.visEditorVisualization.changesSuccessfullyAppliedMessage"
defaultMessage="The latest changes have been applied."
/>);
let applyMessage = (
<FormattedMessage
id="tsvb.visEditorVisualization.changesSuccessfullyAppliedMessage"
defaultMessage="The latest changes have been applied."
/>
);
if (dirty) {
applyMessage = (<FormattedMessage
id="tsvb.visEditorVisualization.changesHaveNotBeenAppliedMessage"
defaultMessage="The changes to this visualization have not been applied."
/>);
applyMessage = (
<FormattedMessage
id="tsvb.visEditorVisualization.changesHaveNotBeenAppliedMessage"
defaultMessage="The changes to this visualization have not been applied."
/>
);
}
if (autoApply) {
applyMessage = (<FormattedMessage
id="tsvb.visEditorVisualization.changesWillBeAutomaticallyAppliedMessage"
defaultMessage="The changes will be automatically applied."
/>);
applyMessage = (
<FormattedMessage
id="tsvb.visEditorVisualization.changesWillBeAutomaticallyAppliedMessage"
defaultMessage="The changes will be automatically applied."
/>
);
}
const applyButton = (
<EuiFlexGroup className="tvbEditorVisualization__apply" alignItems="center">
<EuiFlexItem grow={true}>
<EuiSwitch
id="tsvbAutoApplyInput"
label={(<FormattedMessage
id="tsvb.visEditorVisualization.autoApplyLabel"
defaultMessage="Auto apply"
/>)}
label={
<FormattedMessage
id="tsvb.visEditorVisualization.autoApplyLabel"
defaultMessage="Auto apply"
/>
}
checked={autoApply}
onChange={onToggleAutoApply}
/>
</EuiFlexItem>
{panelInterval &&
<EuiFlexItem grow={false}>
<EuiText color="default" size="xs">
<p>
<FormattedMessage
id="tsvb.visEditorVisualization.panelInterval"
defaultMessage="Interval: {panelInterval}"
values={{ panelInterval }}
/>
</p>
</EuiText>
</EuiFlexItem>
}
{panelInterval && (
<EuiFlexItem grow={false}>
<EuiText color="default" size="xs">
<p>
<FormattedMessage
id="tsvb.visEditorVisualization.panelInterval"
defaultMessage="Interval: {panelInterval}"
values={{ panelInterval }}
/>
</p>
</EuiText>
</EuiFlexItem>
)}
<EuiFlexItem grow={false}>
<EuiText color={dirty ? 'default' : 'subdued'} size="xs">
<p>
{applyMessage}
</p>
<p>{applyMessage}</p>
</EuiText>
</EuiFlexItem>
{!autoApply &&
<EuiFlexItem grow={false}>
<EuiButton iconType="play" fill size="s" onClick={onCommit} disabled={!dirty} data-test-subj="applyBtn">
<FormattedMessage
id="tsvb.visEditorVisualization.applyChangesLabel"
defaultMessage="Apply changes"
/>
</EuiButton>
</EuiFlexItem>
}
{!autoApply && (
<EuiFlexItem grow={false}>
<EuiButton
iconType="play"
fill
size="s"
onClick={onCommit}
disabled={!dirty}
data-test-subj="applyBtn"
>
<FormattedMessage
id="tsvb.visEditorVisualization.applyChangesLabel"
defaultMessage="Apply changes"
/>
</EuiButton>
</EuiFlexItem>
)}
</EuiFlexGroup>
);
@ -262,7 +270,7 @@ class VisEditorVisualizationUI extends Component {
defaultMessage: 'Press up/down to adjust the chart size',
})}
>
<i className="fa fa-ellipsis-h"/>
<i className="fa fa-ellipsis-h" />
</button>
</div>
</div>

View file

@ -31,8 +31,8 @@ describe('getVisualizeLoader', () => {
const handlerMock = {
update: updateStub,
data$: {
subscribe: () => {}
}
subscribe: () => {},
},
};
const loaderMock = {
embedVisualizationWithSavedObject: () => handlerMock,
@ -41,16 +41,14 @@ describe('getVisualizeLoader', () => {
});
it('should not call _handler.update until getVisualizeLoader returns _handler', async () => {
const wrapper = mountWithIntl(
<VisEditorVisualization />
);
const wrapper = mountWithIntl(<VisEditorVisualization />);
// Set prop to force DOM change and componentDidUpdate to be triggered
wrapper.setProps({
timeRange: {
from: '2019-03-20T20:35:37.637Z',
to: '2019-03-23T18:40:16.486Z'
}
to: '2019-03-23T18:40:16.486Z',
},
});
expect(updateStub).not.toHaveBeenCalled();
@ -62,8 +60,8 @@ describe('getVisualizeLoader', () => {
wrapper.setProps({
timeRange: {
from: 'now/d',
to: 'now/d'
}
to: 'now/d',
},
});
expect(updateStub).toHaveBeenCalled();

Some files were not shown because too many files have changed in this diff Show more