mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 09:19:04 -04:00
* [Vis: Default editor] EUIficate Sub agg control (#37979) * EUIficate metric agg control * Fix translation errors * Display agg error underneath the last bucket agg form control * Update functional test * Update error message * Update parent_pipeline_agg_controller.js * Fix validation when metricAgg is invalid * Show error message when a filed is selected * Delete _terms_helper.tsx * Remove extra empty line * Update parent_pipeline_agg_helper.js * Update selector for test * Remove unused translation
This commit is contained in:
parent
ccfdd2e182
commit
2cfca17418
16 changed files with 198 additions and 198 deletions
|
@ -17,37 +17,23 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { AggConfig } from 'ui/vis';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
const aggFilter = [
|
||||
'!top_hits',
|
||||
'!percentiles',
|
||||
'!median',
|
||||
'!std_dev',
|
||||
'!derivative',
|
||||
'!moving_avg',
|
||||
'!serial_diff',
|
||||
'!cumulative_sum',
|
||||
'!avg_bucket',
|
||||
'!max_bucket',
|
||||
'!min_bucket',
|
||||
'!sum_bucket',
|
||||
];
|
||||
|
||||
// Returns true if the agg is compatible with the terms bucket
|
||||
function isCompatibleAgg(agg: AggConfig) {
|
||||
return !aggFilter.includes(`!${agg.type.name}`);
|
||||
}
|
||||
import { AggConfig } from '../vis/agg_config';
|
||||
|
||||
function safeMakeLabel(agg: AggConfig) {
|
||||
try {
|
||||
return agg.makeLabel();
|
||||
} catch (e) {
|
||||
return i18n.translate('common.ui.aggTypes.buckets.terms.aggNotValidLabel', {
|
||||
return i18n.translate('common.ui.aggTypes.aggNotValidLabel', {
|
||||
defaultMessage: '- agg not valid -',
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export { aggFilter, isCompatibleAgg, safeMakeLabel };
|
||||
function isCompatibleAggregation(aggFilter: string[]) {
|
||||
return (agg: AggConfig) => {
|
||||
return !aggFilter.includes(`!${agg.type.name}`);
|
||||
};
|
||||
}
|
||||
|
||||
export { safeMakeLabel, isCompatibleAggregation };
|
|
@ -27,10 +27,9 @@ import { createFilterTerms } from './create_filter/terms';
|
|||
import { wrapWithInlineComp } from './_inline_comp_wrapper';
|
||||
import { buildOtherBucketAgg, mergeOtherBucketAggResponse, updateMissingBucket } from './_terms_other_bucket_helper';
|
||||
import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format';
|
||||
import { aggFilter } from './_terms_helper';
|
||||
import orderAggTemplate from '../controls/order_agg.html';
|
||||
import { OrderParamEditor } from '../controls/order';
|
||||
import { OrderAggParamEditor } from '../controls/order_agg';
|
||||
import { OrderAggParamEditor, aggFilter } from '../controls/order_agg';
|
||||
import { SizeParamEditor } from '../controls/size';
|
||||
import { MissingBucketParamEditor } from '../controls/missing_bucket';
|
||||
import { OtherBucketParamEditor } from '../controls/other_bucket';
|
||||
|
|
109
src/legacy/ui/public/agg_types/controls/metric_agg.tsx
Normal file
109
src/legacy/ui/public/agg_types/controls/metric_agg.tsx
Normal file
|
@ -0,0 +1,109 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, { useEffect } from 'react';
|
||||
import { EuiFormRow, EuiSelect } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AggParamEditorProps } from 'ui/vis/editors/default';
|
||||
import { safeMakeLabel, isCompatibleAggregation } from '../agg_utils';
|
||||
|
||||
const aggFilter = ['!top_hits', '!percentiles', '!percentile_ranks', '!median', '!std_dev'];
|
||||
const isCompatibleAgg = isCompatibleAggregation(aggFilter);
|
||||
const EMPTY_VALUE = 'EMPTY_VALUE';
|
||||
|
||||
function MetricAggParamEditor({
|
||||
agg,
|
||||
value,
|
||||
showValidation,
|
||||
setValue,
|
||||
setValidity,
|
||||
setTouched,
|
||||
responseValueAggs,
|
||||
}: AggParamEditorProps<string>) {
|
||||
const label = i18n.translate('common.ui.aggTypes.metricLabel', {
|
||||
defaultMessage: 'Metric',
|
||||
});
|
||||
const isValid = !!value;
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
setValidity(isValid);
|
||||
},
|
||||
[isValid]
|
||||
);
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (responseValueAggs && value && value !== 'custom') {
|
||||
// ensure that metricAgg is set to a valid agg
|
||||
const respAgg = responseValueAggs
|
||||
.filter(isCompatibleAgg)
|
||||
.find(aggregation => aggregation.id === value);
|
||||
|
||||
if (!respAgg) {
|
||||
setValue();
|
||||
}
|
||||
}
|
||||
},
|
||||
[responseValueAggs]
|
||||
);
|
||||
|
||||
const options = responseValueAggs
|
||||
? responseValueAggs
|
||||
.filter(respAgg => respAgg.type.name !== agg.type.name)
|
||||
.map(respAgg => ({
|
||||
text: i18n.translate('common.ui.aggTypes.definiteMetricLabel', {
|
||||
defaultMessage: 'Metric: {safeMakeLabel}',
|
||||
values: {
|
||||
safeMakeLabel: safeMakeLabel(respAgg),
|
||||
},
|
||||
}),
|
||||
value: respAgg.id,
|
||||
disabled: !isCompatibleAgg(respAgg),
|
||||
}))
|
||||
: [];
|
||||
|
||||
options.push({
|
||||
text: i18n.translate('common.ui.aggTypes.customMetricLabel', {
|
||||
defaultMessage: 'Custom metric',
|
||||
}),
|
||||
value: 'custom',
|
||||
disabled: false,
|
||||
});
|
||||
|
||||
if (!value) {
|
||||
options.unshift({ text: '', value: EMPTY_VALUE, disabled: false });
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFormRow label={label} fullWidth={true} isInvalid={showValidation ? !isValid : false}>
|
||||
<EuiSelect
|
||||
options={options}
|
||||
value={value || EMPTY_VALUE}
|
||||
onChange={ev => setValue(ev.target.value)}
|
||||
fullWidth={true}
|
||||
isInvalid={showValidation ? !isValid : false}
|
||||
onBlur={setTouched}
|
||||
data-test-subj={`visEditorSubAggMetric${agg.id}`}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
export { MetricAggParamEditor };
|
|
@ -21,7 +21,23 @@ import React, { useEffect } from 'react';
|
|||
import { EuiFormRow, EuiSelect } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AggParamEditorProps } from 'ui/vis/editors/default';
|
||||
import { safeMakeLabel, isCompatibleAgg } from '../buckets/_terms_helper';
|
||||
import { safeMakeLabel, isCompatibleAggregation } from '../agg_utils';
|
||||
|
||||
const aggFilter = [
|
||||
'!top_hits',
|
||||
'!percentiles',
|
||||
'!median',
|
||||
'!std_dev',
|
||||
'!derivative',
|
||||
'!moving_avg',
|
||||
'!serial_diff',
|
||||
'!cumulative_sum',
|
||||
'!avg_bucket',
|
||||
'!max_bucket',
|
||||
'!min_bucket',
|
||||
'!sum_bucket',
|
||||
];
|
||||
const isCompatibleAgg = isCompatibleAggregation(aggFilter);
|
||||
|
||||
function OrderAggParamEditor({
|
||||
agg,
|
||||
|
@ -116,4 +132,4 @@ function OrderAggParamEditor({
|
|||
);
|
||||
}
|
||||
|
||||
export { OrderAggParamEditor };
|
||||
export { OrderAggParamEditor, aggFilter };
|
||||
|
|
|
@ -1,43 +1,8 @@
|
|||
<div ng-controller="aggParam.controller">
|
||||
<div class="form-group">
|
||||
<label
|
||||
for="visEditorSubAggMetric{{agg.id}}"
|
||||
i18n-id="common.ui.aggTypes.metricLabel"
|
||||
i18n-default-message="Metric"
|
||||
></label>
|
||||
<select
|
||||
id="visEditorSubAggMetric{{agg.id}}"
|
||||
name="metricAgg"
|
||||
ng-model="agg.params.metricAgg"
|
||||
agg="agg"
|
||||
required
|
||||
validate-agg
|
||||
class="form-control">
|
||||
<option
|
||||
ng-repeat="respAgg in responseValueAggs track by respAgg.id"
|
||||
value="{{respAgg.id}}"
|
||||
ng-if="respAgg.type.name !== agg.type.name"
|
||||
ng-disabled="isDisabledAgg(respAgg)"
|
||||
ng-selected="agg.params.metricAgg === respAgg.id"
|
||||
i18n-id="common.ui.aggTypes.definiteMetricLabel"
|
||||
i18n-default-message="metric: {safeMakeLabel}"
|
||||
i18n-values="{ safeMakeLabel: safeMakeLabel(respAgg) }"
|
||||
></option>
|
||||
<option
|
||||
value="custom"
|
||||
ng-selected="agg.params.metricAgg === 'custom'"
|
||||
i18n-id="common.ui.aggTypes.customMetricLabel"
|
||||
i18n-default-message="Custom Metric"
|
||||
></option>
|
||||
</select>
|
||||
</div>
|
||||
<div ng-if="agg.params.metricAgg === 'custom'" class="visEditorAgg__subAgg">
|
||||
<ng-form name="customMetricForm">
|
||||
<vis-editor-agg-params
|
||||
index-pattern="agg.getIndexPattern()"
|
||||
agg="agg.params.customMetric"
|
||||
group-name="'metrics'">
|
||||
</vis-editor-agg-params>
|
||||
</ng-form>
|
||||
</div>
|
||||
<div ng-controller="aggParam.controller" ng-show="agg.params.metricAgg === 'custom'" class="visEditorAgg__subAgg">
|
||||
<vis-editor-agg-params
|
||||
index-pattern="agg.getIndexPattern()"
|
||||
agg="agg.params.customMetric"
|
||||
ng-if="agg.params.metricAgg === 'custom'"
|
||||
group-name="'metrics'">
|
||||
</vis-editor-agg-params>
|
||||
</div>
|
||||
|
|
|
@ -28,7 +28,7 @@ function TopFieldParamEditor(props: AggParamEditorProps<FieldParamType>) {
|
|||
const compatibleAggs = getCompatibleAggs(props.agg, props.visName);
|
||||
let customError;
|
||||
|
||||
if (!compatibleAggs.length) {
|
||||
if (props.value && !compatibleAggs.length) {
|
||||
customError = i18n.translate('common.ui.aggTypes.aggregateWith.noAggsErrorTooltip', {
|
||||
defaultMessage: 'The chosen field has no compatible aggregations.',
|
||||
});
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import { uiModules } from '../../modules';
|
||||
|
||||
uiModules
|
||||
.get('kibana')
|
||||
.directive('validateAgg', function () {
|
||||
return {
|
||||
restrict: 'A',
|
||||
require: 'ngModel',
|
||||
scope: {
|
||||
'ngModel': '=',
|
||||
'agg': '='
|
||||
},
|
||||
link: function ($scope, elem, attr, ngModel) {
|
||||
function validateAgg(aggValue) {
|
||||
if (aggValue == null || aggValue === 'custom') {
|
||||
ngModel.$setValidity('aggInput', true);
|
||||
return aggValue;
|
||||
}
|
||||
|
||||
try {
|
||||
$scope.agg.params.customMetric = null;
|
||||
$scope.agg.params.metricAgg = aggValue;
|
||||
$scope.agg.makeLabel();
|
||||
ngModel.$setValidity('aggInput', true);
|
||||
} catch (e) {
|
||||
ngModel.$setValidity('aggInput', false);
|
||||
}
|
||||
|
||||
return aggValue;
|
||||
}
|
||||
|
||||
// From User
|
||||
ngModel.$parsers.unshift(validateAgg);
|
||||
|
||||
// To user
|
||||
ngModel.$formatters.unshift(validateAgg);
|
||||
}
|
||||
};
|
||||
});
|
|
@ -17,7 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import './directives/validate_agg';
|
||||
import './agg_params';
|
||||
import { IndexedArray } from '../indexed_array';
|
||||
import { countMetricAgg } from './metrics/count';
|
||||
|
|
|
@ -18,33 +18,22 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import { safeMakeLabel } from './safe_make_label';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
const parentPipelineAggController = function ($scope) {
|
||||
|
||||
$scope.safeMakeLabel = safeMakeLabel;
|
||||
|
||||
$scope.$watch('responseValueAggs', updateOrderAgg);
|
||||
$scope.$watch('agg.params.metricAgg', updateOrderAgg);
|
||||
|
||||
$scope.$on('$destroy', function () {
|
||||
const lastBucket = _.findLast($scope.state.aggs, agg => agg.type.type === 'buckets');
|
||||
if ($scope.aggForm && $scope.aggForm.agg) {
|
||||
$scope.aggForm.agg.$setValidity('bucket', true);
|
||||
}
|
||||
const lastBucket = _.findLast($scope.state.aggs, agg => agg.type && agg.type.type === 'buckets');
|
||||
|
||||
if (lastBucket && lastBucket.error) {
|
||||
delete lastBucket.error;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.isDisabledAgg = function (agg) {
|
||||
const invalidAggs = ['top_hits', 'percentiles', 'percentile_ranks', 'median', 'std_dev'];
|
||||
return Boolean(invalidAggs.find(invalidAgg => invalidAgg === agg.type.name));
|
||||
};
|
||||
|
||||
function checkBuckets() {
|
||||
const lastBucket = _.findLast($scope.state.aggs, agg => agg.type.type === 'buckets');
|
||||
const lastBucket = _.findLast($scope.state.aggs, agg => agg.type && agg.type.type === 'buckets');
|
||||
const bucketHasType = lastBucket && lastBucket.type;
|
||||
const bucketIsHistogram = bucketHasType && ['date_histogram', 'histogram'].includes(lastBucket.type.name);
|
||||
const canUseAggregation = lastBucket && bucketIsHistogram;
|
||||
|
@ -52,16 +41,13 @@ const parentPipelineAggController = function ($scope) {
|
|||
// remove errors on all buckets
|
||||
_.each($scope.state.aggs, agg => { if (agg.error) delete agg.error; });
|
||||
|
||||
if ($scope.aggForm.agg) {
|
||||
$scope.aggForm.agg.$setValidity('bucket', canUseAggregation);
|
||||
}
|
||||
if (canUseAggregation) {
|
||||
lastBucket.params.min_doc_count = (lastBucket.type.name === 'histogram') ? 1 : 0;
|
||||
} else {
|
||||
if (lastBucket) {
|
||||
const type = $scope.agg.type.title;
|
||||
lastBucket.error = i18n.translate('common.ui.aggTypes.metrics.wrongLastBucketTypeErrorMessage', {
|
||||
defaultMessage: 'Last bucket aggregation must be "Date Histogram" or "Histogram" when using "{type}" metric aggregation!',
|
||||
defaultMessage: 'Last bucket aggregation must be "Date Histogram" or "Histogram" when using "{type}" metric aggregation.',
|
||||
values: { type },
|
||||
description: 'Date Histogram and Histogram should not be translated'
|
||||
});
|
||||
|
@ -79,9 +65,6 @@ const parentPipelineAggController = function ($scope) {
|
|||
|
||||
// we aren't creating a custom aggConfig
|
||||
if (metricAgg !== 'custom') {
|
||||
if (!$scope.state.aggs.find(agg => agg.id === metricAgg)) {
|
||||
params.metricAgg = null;
|
||||
}
|
||||
params.customMetric = null;
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
*/
|
||||
|
||||
import metricAggTemplate from '../../controls/sub_agg.html';
|
||||
import { MetricAggParamEditor } from '../../controls/metric_agg';
|
||||
import _ from 'lodash';
|
||||
import { AggConfig } from '../../../vis/agg_config';
|
||||
import { Schemas } from '../../../vis/editors/default/schemas';
|
||||
|
@ -46,8 +47,15 @@ const parentPipelineAggHelper = {
|
|||
}),
|
||||
params: function () {
|
||||
return [
|
||||
{
|
||||
name: 'metricAgg',
|
||||
editorComponent: MetricAggParamEditor,
|
||||
default: 'custom',
|
||||
write: parentPipelineAggWriter
|
||||
},
|
||||
{
|
||||
name: 'customMetric',
|
||||
editor: metricAggTemplate,
|
||||
type: AggConfig,
|
||||
default: null,
|
||||
serialize: function (customMetric) {
|
||||
|
@ -64,18 +72,12 @@ const parentPipelineAggHelper = {
|
|||
return metricAgg;
|
||||
},
|
||||
modifyAggConfigOnSearchRequestStart: forwardModifyAggConfigOnSearchRequestStart('customMetric'),
|
||||
write: _.noop
|
||||
write: _.noop,
|
||||
controller: parentPipelineAggController
|
||||
},
|
||||
{
|
||||
name: 'buckets_path',
|
||||
write: _.noop
|
||||
},
|
||||
{
|
||||
name: 'metricAgg',
|
||||
editor: metricAggTemplate,
|
||||
default: 'custom',
|
||||
controller: parentPipelineAggController,
|
||||
write: parentPipelineAggWriter
|
||||
}
|
||||
];
|
||||
},
|
||||
|
|
|
@ -13,12 +13,6 @@
|
|||
style="display: none;">
|
||||
</div>
|
||||
|
||||
<div ng-if="agg.error" class="form-group">
|
||||
<p class="visEditorAggParam__error ng-binding">
|
||||
{{agg.error}}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div ng-if="agg.schema.deprecate" class="form-group">
|
||||
<p ng-show="agg.schema.deprecateMessage" class="visEditorAggParam__error">
|
||||
{{ agg.schema.deprecateMessage }}
|
||||
|
|
|
@ -31,7 +31,7 @@ uiModules
|
|||
['setValidity', { watchDepth: 'reference' }],
|
||||
['setValue', { watchDepth: 'reference' }],
|
||||
'aggHelpLink',
|
||||
'isSelectInvalid',
|
||||
'showValidation',
|
||||
'isSubAggregation',
|
||||
'value',
|
||||
]))
|
||||
|
@ -46,7 +46,7 @@ uiModules
|
|||
agg="agg"
|
||||
agg-help-link="aggHelpLink"
|
||||
agg-type-options="aggTypeOptions"
|
||||
is-select-invalid="isSelectInvalid"
|
||||
show-validation="showValidation"
|
||||
is-sub-aggregation="isSubAggregation"
|
||||
value="paramValue"
|
||||
set-validity="setValidity"
|
||||
|
@ -61,51 +61,40 @@ uiModules
|
|||
$scope.$bind('isSubAggregation', attr.isSubAggregation);
|
||||
},
|
||||
post: function ($scope, $el, attr, ngModelCtrl) {
|
||||
let _isSelectInvalid = false;
|
||||
$scope.showValidation = false;
|
||||
|
||||
$scope.$watch('agg.type', (value) => {
|
||||
// Whenever the value of the parameter changed (e.g. by a reset or actually by calling)
|
||||
// we store the new value in $scope.paramValue, which will be passed as a new value to the react component.
|
||||
$scope.paramValue = value;
|
||||
|
||||
$scope.setValidity(true);
|
||||
$scope.isSelectInvalid = false;
|
||||
});
|
||||
|
||||
$scope.$watch(() => {
|
||||
// The model can become touched either onBlur event or when the form is submitted.
|
||||
return ngModelCtrl.$touched;
|
||||
}, (value) => {
|
||||
if (value === true) {
|
||||
showValidation();
|
||||
if (value) {
|
||||
$scope.showValidation = true;
|
||||
}
|
||||
}, true);
|
||||
|
||||
$scope.onChange = (value) => {
|
||||
if (!value) {
|
||||
// We prevent to make the field empty.
|
||||
return;
|
||||
}
|
||||
$scope.paramValue = value;
|
||||
// This is obviously not a good code quality, but without using scope binding (which we can't see above)
|
||||
// to bind function values, this is right now the best temporary fix, until all of this will be gone.
|
||||
$scope.$parent.onAggTypeChange($scope.agg, value);
|
||||
|
||||
$scope.showValidation = true;
|
||||
ngModelCtrl.$setDirty();
|
||||
};
|
||||
|
||||
$scope.setTouched = () => {
|
||||
ngModelCtrl.$setTouched();
|
||||
showValidation();
|
||||
$scope.showValidation = true;
|
||||
};
|
||||
|
||||
$scope.setValidity = (isValid) => {
|
||||
_isSelectInvalid = !isValid;
|
||||
ngModelCtrl.$setValidity(`agg${$scope.agg.id}`, isValid);
|
||||
};
|
||||
|
||||
function showValidation() {
|
||||
$scope.isSelectInvalid = _isSelectInvalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
import { get, has } from 'lodash';
|
||||
import React, { useEffect } from 'react';
|
||||
|
||||
import { EuiComboBox, EuiFormRow, EuiLink } from '@elastic/eui';
|
||||
import { EuiComboBox, EuiComboBoxOptionProps, EuiFormRow, EuiLink } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { AggType } from 'ui/agg_types';
|
||||
|
@ -30,7 +30,7 @@ import { ComboBoxGroupedOption } from '../default_editor_utils';
|
|||
interface DefaultEditorAggSelectProps {
|
||||
agg: AggConfig;
|
||||
aggTypeOptions: AggType[];
|
||||
isSelectInvalid: boolean;
|
||||
showValidation: boolean;
|
||||
isSubAggregation: boolean;
|
||||
value: AggType;
|
||||
setValidity: (isValid: boolean) => void;
|
||||
|
@ -43,7 +43,7 @@ function DefaultEditorAggSelect({
|
|||
value,
|
||||
setValue,
|
||||
aggTypeOptions,
|
||||
isSelectInvalid,
|
||||
showValidation,
|
||||
isSubAggregation,
|
||||
setTouched,
|
||||
setValidity,
|
||||
|
@ -93,23 +93,43 @@ function DefaultEditorAggSelect({
|
|||
},
|
||||
})
|
||||
);
|
||||
setTouched();
|
||||
}
|
||||
|
||||
if (agg.error) {
|
||||
errors.push(agg.error);
|
||||
}
|
||||
|
||||
const isValid = !!value && !errors.length && !agg.error;
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
// The selector will be invalid when the value is empty.
|
||||
setValidity(!!value);
|
||||
setValidity(isValid);
|
||||
},
|
||||
[value]
|
||||
[isValid]
|
||||
);
|
||||
|
||||
useEffect(
|
||||
() => {
|
||||
if (errors.length) {
|
||||
setTouched();
|
||||
}
|
||||
},
|
||||
[errors.length]
|
||||
);
|
||||
|
||||
const onChange = (options: EuiComboBoxOptionProps[]) => {
|
||||
const selectedOption = get(options, '0.value');
|
||||
if (selectedOption) {
|
||||
setValue(selectedOption);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<EuiFormRow
|
||||
label={label}
|
||||
labelAppend={helpLink}
|
||||
error={errors}
|
||||
isInvalid={isSelectInvalid}
|
||||
isInvalid={showValidation ? !isValid : false}
|
||||
fullWidth={true}
|
||||
className="visEditorAggSelect__formRow"
|
||||
>
|
||||
|
@ -123,10 +143,10 @@ function DefaultEditorAggSelect({
|
|||
selectedOptions={selectedOptions}
|
||||
singleSelection={{ asPlainText: true }}
|
||||
onBlur={setTouched}
|
||||
onChange={options => setValue(get(options, '0.value'))}
|
||||
onChange={onChange}
|
||||
data-test-subj="defaultEditorAggSelect"
|
||||
isClearable={false}
|
||||
isInvalid={isSelectInvalid}
|
||||
isInvalid={showValidation ? !isValid : false}
|
||||
fullWidth={true}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
|
|
|
@ -1226,7 +1226,7 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli
|
|||
}
|
||||
|
||||
async getBucketErrorMessage() {
|
||||
const error = await find.byCssSelector('.visEditorAggParam__error');
|
||||
const error = await find.byCssSelector('[group-name="buckets"] [data-test-subj="defaultEditorAggSelect"] + .euiFormErrorText');
|
||||
const errorMessage = await error.getProperty('innerText');
|
||||
log.debug(errorMessage);
|
||||
return errorMessage;
|
||||
|
|
|
@ -107,7 +107,6 @@
|
|||
"common.ui.aggTypes.buckets.significantTerms.includeLabel": "含める",
|
||||
"common.ui.aggTypes.buckets.significantTermsLabel": "{fieldName} のトップ {size} の珍しいアイテム",
|
||||
"common.ui.aggTypes.buckets.significantTermsTitle": "Significant Terms",
|
||||
"common.ui.aggTypes.buckets.terms.aggNotValidLabel": "- 無効な集約 -",
|
||||
"common.ui.aggTypes.buckets.terms.excludeLabel": "除外",
|
||||
"common.ui.aggTypes.buckets.terms.includeLabel": "含める",
|
||||
"common.ui.aggTypes.buckets.terms.missingBucketLabel": "欠測値",
|
||||
|
@ -210,7 +209,6 @@
|
|||
"common.ui.aggTypes.metrics.topHitTitle": "トップヒット",
|
||||
"common.ui.aggTypes.metrics.uniqueCountLabel": "{field} のユニークカウント",
|
||||
"common.ui.aggTypes.metrics.uniqueCountTitle": "ユニークカウント",
|
||||
"common.ui.aggTypes.metrics.wrongLastBucketTypeErrorMessage": "「{type}」メトリック集約を使用する場合、最後のバケットアグリゲーションは「Date Histogram」または「Histogram」でなければなりません!",
|
||||
"common.ui.aggTypes.numberInterval.minimumIntervalLabel": "最低間隔",
|
||||
"common.ui.aggTypes.numberInterval.minimumIntervalTooltip": "入力された値により高度な設定の {histogramMaxBars} で指定されたよりも多くのバケットが作成される場合、間隔は自動的にスケーリングされます。",
|
||||
"common.ui.aggTypes.numberInterval.selectIntervalPlaceholder": "間隔を入力",
|
||||
|
|
|
@ -106,7 +106,6 @@
|
|||
"common.ui.aggTypes.buckets.significantTerms.includeLabel": "包括",
|
||||
"common.ui.aggTypes.buckets.significantTermsLabel": "{fieldName} 中排名前 {size} 的罕见词",
|
||||
"common.ui.aggTypes.buckets.significantTermsTitle": "重要词",
|
||||
"common.ui.aggTypes.buckets.terms.aggNotValidLabel": "- 聚合无效 -",
|
||||
"common.ui.aggTypes.buckets.terms.excludeLabel": "排除",
|
||||
"common.ui.aggTypes.buckets.terms.includeLabel": "包括",
|
||||
"common.ui.aggTypes.buckets.terms.missingBucketLabel": "缺失",
|
||||
|
@ -209,7 +208,6 @@
|
|||
"common.ui.aggTypes.metrics.topHitTitle": "最高命中结果",
|
||||
"common.ui.aggTypes.metrics.uniqueCountLabel": "“{field}” 的唯一计数",
|
||||
"common.ui.aggTypes.metrics.uniqueCountTitle": "唯一计数",
|
||||
"common.ui.aggTypes.metrics.wrongLastBucketTypeErrorMessage": "使用 “{type}” 指标聚合时,上一存储桶聚合必须是“Date Histogram”或“Histogram”!",
|
||||
"common.ui.aggTypes.numberInterval.minimumIntervalLabel": "最小时间间隔",
|
||||
"common.ui.aggTypes.numberInterval.minimumIntervalTooltip": "提供的值创建的存储桶数目大于“高级设置”的 {histogramMaxBars} 指定的数目时,将自动缩放时间间隔",
|
||||
"common.ui.aggTypes.numberInterval.selectIntervalPlaceholder": "输入时间间隔",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue