[Vis: Default editor] EUIficate order and size controls (#35134) (#36005)

* EUIficate order and size controls
This commit is contained in:
Daniil Suleiman 2019-05-03 12:02:56 +03:00 committed by GitHub
parent 44ce2203d7
commit 813b6ef8b7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 316 additions and 58 deletions

View file

@ -22,6 +22,7 @@ import { AggParams } from '../agg_params';
import { BaseParamType } from '../param_types/base';
import { FieldParamType } from '../param_types/field';
import { OptionedParamType } from '../param_types/optioned';
import { SelectParamType } from '../param_types/select';
describe('AggParams class', function () {
@ -63,6 +64,19 @@ describe('AggParams class', function () {
expect(aggParams[0]).to.be.a(OptionedParamType);
});
it('Uses the SelectParamType class for params of type "select"', function () {
const params = [
{
name: 'order',
type: 'select'
}
];
const aggParams = new AggParams(params);
expect(aggParams).to.have.length(params.length);
expect(aggParams[0]).to.be.a(SelectParamType);
});
it('Always converts the params to a BaseParamType', function () {
const params = [
{

View file

@ -20,6 +20,7 @@
import { IndexedArray } from '../indexed_array';
import { FieldParamType } from './param_types/field';
import { OptionedParamType } from './param_types/optioned';
import { SelectParamType } from './param_types/select';
import { StringParamType } from './param_types/string';
import { JsonParamType } from './param_types/json';
import { BaseParamType } from './param_types/base';
@ -27,7 +28,9 @@ import { createLegacyClass } from '../utils/legacy_class';
const paramTypeMap = {
field: FieldParamType,
// todo: remove select type and update optioned type after EUIfication of all components;
optioned: (OptionedParamType),
select: SelectParamType,
string: (StringParamType),
json: (JsonParamType),
_default: (BaseParamType)

View file

@ -0,0 +1,27 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React from 'react';
const wrapWithInlineComp = Component => props => (
<div className={`visEditorAggParam--half visEditorAggParam--half-${props.aggParam.name}`}>
<Component {...props} />
</div>);
export { wrapWithInlineComp };

View file

@ -17,10 +17,10 @@
* under the License.
*/
import { i18n } from '@kbn/i18n';
import { SizeParamEditor } from '../controls/size';
import { BucketAggType } from './_bucket_agg_type';
import { createFilterTerms } from './create_filter/terms';
import orderAndSizeTemplate from '../controls/order_and_size.html';
import { i18n } from '@kbn/i18n';
import { isStringType, migrateIncludeExcludeFormat } from './migrate_include_exclude_format';
export const significantTermsBucketAgg = new BucketAggType({
@ -47,7 +47,8 @@ export const significantTermsBucketAgg = new BucketAggType({
},
{
name: 'size',
editor: orderAndSizeTemplate,
editorComponent: SizeParamEditor,
default: '',
},
{
name: 'exclude',

View file

@ -24,7 +24,9 @@ import { AggConfig } from '../../vis/agg_config';
import { Schemas } from '../../vis/editors/default/schemas';
import { createFilterTerms } from './create_filter/terms';
import orderAggTemplate from '../controls/order_agg.html';
import orderAndSizeTemplate from '../controls/order_and_size.html';
import { OrderParamEditor } from '../controls/order';
import { SizeParamEditor } from '../controls/size';
import { wrapWithInlineComp } from './_inline_comp_wrapper';
import { i18n } from '@kbn/i18n';
import { getRequestInspectorStats, getResponseInspectorStats } from '../../courier/utils/courier_inspector_utils';
@ -57,7 +59,7 @@ export const termsBucketAgg = new BucketAggType({
}),
makeLabel: function (agg) {
const params = agg.params;
return agg.getFieldDisplayName() + ': ' + params.order.display;
return agg.getFieldDisplayName() + ': ' + params.order.text;
},
getFormat: function (bucket) {
return {
@ -118,10 +120,6 @@ export const termsBucketAgg = new BucketAggType({
type: 'field',
filterFieldTypes: ['number', 'boolean', 'date', 'ip', 'string']
},
{
name: 'size',
default: 5
},
{
name: 'orderAgg',
type: AggConfig,
@ -204,7 +202,7 @@ export const termsBucketAgg = new BucketAggType({
}
},
write: function (agg, output, aggs) {
const dir = agg.params.order.val;
const dir = agg.params.order.value;
const order = output.params.order = {};
let orderAgg = agg.params.orderAgg || aggs.getResponseAggById(agg.params.orderBy);
@ -241,25 +239,30 @@ export const termsBucketAgg = new BucketAggType({
},
{
name: 'order',
type: 'optioned',
type: 'select',
default: 'desc',
editor: orderAndSizeTemplate,
editorComponent: wrapWithInlineComp(OrderParamEditor),
options: [
{
display: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', {
text: i18n.translate('common.ui.aggTypes.buckets.terms.orderDescendingTitle', {
defaultMessage: 'Descending',
}),
val: 'desc'
value: 'desc'
},
{
display: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', {
text: i18n.translate('common.ui.aggTypes.buckets.terms.orderAscendingTitle', {
defaultMessage: 'Ascending',
}),
val: 'asc'
value: 'asc'
}
],
write: _.noop // prevent default write, it's handled by orderAgg
},
{
name: 'size',
editorComponent: wrapWithInlineComp(SizeParamEditor),
default: 5
},
{
name: 'orderBy',
write: _.noop // prevent default write, it's handled by orderAgg

View file

@ -0,0 +1,65 @@
/*
* 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 { SelectValueProp, SelectParamEditorProps } from '../param_types/select';
function OrderParamEditor({
aggParam,
value,
showValidation,
setValue,
setValidity,
setTouched,
}: AggParamEditorProps<SelectValueProp> & SelectParamEditorProps) {
const label = i18n.translate('common.ui.aggTypes.orderLabel', {
defaultMessage: 'Order',
});
const isValid = !!value;
useEffect(
() => {
setValidity(isValid);
},
[isValid]
);
return (
<EuiFormRow
label={label}
fullWidth={true}
isInvalid={showValidation ? !isValid : false}
className="visEditorSidebar__aggParamFormRow"
>
<EuiSelect
options={aggParam.options.raw}
value={value.value}
onChange={ev => setValue(aggParam.options.byValue[ev.target.value])}
fullWidth={true}
isInvalid={showValidation ? !isValid : false}
onBlur={setTouched}
/>
</EuiFormRow>
);
}
export { OrderParamEditor };

View file

@ -1,36 +0,0 @@
<div>
<div class="visEditorAgg__formRow--flex">
<div ng-if="agg.type.params.byName.order && aggParam.options" class="form-group">
<label
for="visEditorOrderByOrder{{agg.id}}"
i18n-id="common.ui.aggTypes.orderLabel"
i18n-default-message="Order"
></label>
<select
id="visEditorOrderByOrder{{agg.id}}"
name="order"
ng-model="agg.params.order"
required
ng-options="opt as opt.display for opt in aggParam.options"
class="form-control">
</select>
</div>
<div class="form-group">
<label
for="visEditorOrderBySize{{agg.id}}"
i18n-id="common.ui.aggTypes.sizeLabel"
i18n-default-message="Size"
></label>
<input
id="visEditorOrderBySize{{agg.id}}"
name="size"
ng-model="agg.params.size"
required
class="form-control"
type="number"
min="1"
>
</div>
</div>
</div>

View file

@ -0,0 +1,65 @@
/*
* 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 { isUndefined } from 'lodash';
import { AggParamEditorProps } from 'ui/vis/editors/default';
import { EuiFormRow, EuiFieldNumber } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
function SizeParamEditor({
value,
setValue,
showValidation,
setValidity,
setTouched,
}: AggParamEditorProps<number | ''>) {
const label = i18n.translate('common.ui.aggTypes.sizeLabel', {
defaultMessage: 'Size',
});
const isValid = Number(value) > 0;
useEffect(
() => {
setValidity(isValid);
},
[isValid]
);
return (
<EuiFormRow
label={label}
fullWidth={true}
isInvalid={showValidation ? !isValid : false}
className="visEditorSidebar__aggParamFormRow"
>
<EuiFieldNumber
value={isUndefined(value) ? '' : value}
onChange={ev => setValue(ev.target.value === '' ? '' : parseFloat(ev.target.value))}
fullWidth={true}
isInvalid={showValidation ? !isValid : false}
onBlur={setTouched}
min={1}
data-test-subj="sizeParamEditor"
/>
</EuiFormRow>
);
}
export { SizeParamEditor };

View file

@ -0,0 +1,39 @@
/*
* 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 { IndexedArray } from '../../indexed_array';
interface SelectValueProp {
value: string;
text: string;
}
interface SelectOptions extends IndexedArray<SelectValueProp> {
byValue: {
[key: string]: SelectValueProp;
};
}
interface SelectParamEditorProps {
aggParam: {
options: SelectOptions;
};
}
export { SelectValueProp, SelectParamEditorProps };

View file

@ -0,0 +1,69 @@
/*
* 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 { IndexedArray } from '../../indexed_array';
import { BaseParamType } from './base';
import { createLegacyClass } from '../../utils/legacy_class';
createLegacyClass(SelectParamType).inherits(BaseParamType);
function SelectParamType(config) {
SelectParamType.Super.call(this, config);
this.options = new IndexedArray({
index: ['value'],
immutable: true,
initialSet: this.options
});
}
/**
* Serialize a selection to be stored in the database
* @param {object} selected - the option that was selected
* @return {any}
*/
SelectParamType.prototype.serialize = function (selected) {
return selected.value;
};
/**
* Take a value that was serialized to the database and
* return the option that is represents
*
* @param {any} value - the value that was saved
* @return {object}
*/
SelectParamType.prototype.deserialize = function (value) {
return this.options.byValue[value];
};
/**
* Write the aggregation parameter.
*
* @param {AggConfig} aggConfig - the entire configuration for this agg
* @param {object} output - the result of calling write on all of the aggregations
* parameters.
* @param {object} output.params - the final object that will be included as the params
* for the agg
* @return {undefined}
*/
SelectParamType.prototype.write = function (aggConfig, output) {
output.params[this.name] = aggConfig.params[this.name].value;
};
export { SelectParamType };

View file

@ -10,3 +10,12 @@
color: $textColor;
background-color: $backgroundColor;
}
.visEditorAggParam--half {
display: inline-block;
width: calc(50% - #{$euiSizeS / 2});
}
.visEditorAggParam--half-size {
margin-left: $euiSizeS;
}

View file

@ -349,13 +349,13 @@ export default function ({ getService, getPageObjects }) {
await PageObjects.visualize.clickBucket('Split Rows');
await PageObjects.visualize.selectAggregation('Terms');
await PageObjects.visualize.selectField('geo.dest');
await PageObjects.visualize.setSize(3);
await PageObjects.visualize.setSize(3, 3);
await PageObjects.visualize.toggleOpenEditor(3, 'false');
await PageObjects.visualize.clickAddBucket();
await PageObjects.visualize.clickBucket('Split Rows');
await PageObjects.visualize.selectAggregation('Terms');
await PageObjects.visualize.selectField('geo.src');
await PageObjects.visualize.setSize(3);
await PageObjects.visualize.setSize(3, 4);
await PageObjects.visualize.toggleOpenEditor(4, 'false');
await PageObjects.visualize.clickGo();
});

View file

@ -599,10 +599,9 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli
}
}
async setSize(newValue) {
const input = await find.byCssSelector(`vis-editor-agg-params[aria-hidden="false"] input[name="size"]`);
await input.clearValue();
await input.type(String(newValue));
async setSize(newValue, aggId) {
const dataTestSubj = aggId ? `aggregationEditor${aggId} sizeParamEditor` : 'sizeParamEditor';
await testSubjects.setValue(dataTestSubj, String(newValue));
}
async toggleDisabledAgg(agg) {