mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
* EUIficate schema editors * Fix types * Fix comments and functional tests * Add percentage to a tooltip * Remove extra ts-ignore
This commit is contained in:
parent
d178af0cfd
commit
4e0a2f4691
15 changed files with 248 additions and 126 deletions
|
@ -1,10 +0,0 @@
|
|||
<div>
|
||||
<label>
|
||||
Dot size ratio
|
||||
<icon-tip
|
||||
content="'Change the ratio of the radius of the smallest point to the largest point'"
|
||||
position="'right'"
|
||||
></icon-tip>
|
||||
</label>
|
||||
<input type="range" step="2" min="1" max="100" class="form-control" ng-model="editorState.params.radiusRatio" />
|
||||
</div>
|
|
@ -1,20 +0,0 @@
|
|||
<div class="form-group">
|
||||
<div class="kuiButtonGroup">
|
||||
<button
|
||||
type="button"
|
||||
class="kuiButton kuiButton--basic kuiButton--small"
|
||||
ng-model="agg.params.row"
|
||||
data-test-subj="splitBy-row"
|
||||
btn-radio="true">
|
||||
Rows
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="kuiButton kuiButton--basic kuiButton--small"
|
||||
ng-model="agg.params.row"
|
||||
data-test-subj="splitBy-column"
|
||||
btn-radio="false">
|
||||
Columns
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
|
@ -44,12 +44,6 @@ uiModules
|
|||
$scope.groupNameLabel = aggGroupNameMaps()[$scope.groupName];
|
||||
$scope.$bind('group', 'state.aggs.bySchemaGroup["' + $scope.groupName + '"]');
|
||||
$scope.$bind('schemas', 'vis.type.schemas["' + $scope.groupName + '"]');
|
||||
// We use `editorState` to access the state of the editor in the options panels.
|
||||
// There are some aggregations (dot size metric) that needs to set parameters on the
|
||||
// editorState too. Since we have the editor state here available as `state`, we're just
|
||||
// binding it to the same name `editorState` so the controls look the same if they are in
|
||||
// the data tab or within any other options tab.
|
||||
$scope.$bind('editorState', 'state');
|
||||
|
||||
$scope.$watchMulti([
|
||||
'schemas',
|
||||
|
|
|
@ -106,7 +106,7 @@ uiModules
|
|||
|
||||
$scope.onChange = (value) => {
|
||||
$scope.paramValue = value;
|
||||
$scope.onParamChange($scope.agg, $scope.aggParam.name, value);
|
||||
$scope.onParamChange($scope.agg.params, $scope.aggParam.name, value);
|
||||
$scope.showValidation = true;
|
||||
ngModelCtrl.$setDirty();
|
||||
};
|
||||
|
|
|
@ -27,6 +27,14 @@
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<vis-agg-control-react-wrapper
|
||||
ng-if="agg.schema.editorComponent"
|
||||
agg-params="agg.params"
|
||||
component="agg.schema.editorComponent"
|
||||
editor-state-params="state.params"
|
||||
set-value="onParamChange"
|
||||
/>
|
||||
|
||||
<vis-agg-select
|
||||
agg="agg"
|
||||
is-sub-aggregation="isSubAggregation"
|
||||
|
|
|
@ -27,6 +27,7 @@ import { editorConfigProviders } from '../config/editor_config_providers';
|
|||
import advancedToggleHtml from './advanced_toggle.html';
|
||||
import './agg_param';
|
||||
import './agg_select';
|
||||
import './controls/agg_controls';
|
||||
import aggParamsTemplate from './agg_params.html';
|
||||
import { groupAggregationsBy } from './default_editor_utils';
|
||||
|
||||
|
@ -64,9 +65,10 @@ uiModules
|
|||
}
|
||||
};
|
||||
|
||||
$scope.onParamChange = (agg, paramName, value) => {
|
||||
if(agg.params[paramName] !== value) {
|
||||
agg.params[paramName] = value;
|
||||
// params could be either agg.params or state.params
|
||||
$scope.onParamChange = (params, paramName, value) => {
|
||||
if(params[paramName] !== value) {
|
||||
params[paramName] = value;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -95,19 +97,6 @@ uiModules
|
|||
updateEditorConfig();
|
||||
$scope.$watchCollection('agg.params', updateEditorConfig);
|
||||
|
||||
// this will contain the controls for the schema (rows or columns?), which are unrelated to
|
||||
// controls for the agg, which is why they are first
|
||||
addSchemaEditor();
|
||||
|
||||
function addSchemaEditor() {
|
||||
const $schemaEditor = $('<div>').addClass('schemaEditors form-group').appendTo($el);
|
||||
|
||||
if ($scope.agg.schema.editor) {
|
||||
$schemaEditor.append($scope.agg.schema.editor);
|
||||
$compile($schemaEditor)($scope.$new());
|
||||
}
|
||||
}
|
||||
|
||||
// params for the selected agg, these are rebuilt every time the agg in $aggSelect changes
|
||||
let $aggParamEditors; // container for agg type param editors
|
||||
let $aggParamEditorsScope;
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// aggParams and editorStateParams should be described while EUIficate agg_params.js
|
||||
export interface AggControlProps<T> {
|
||||
aggParams: any;
|
||||
editorStateParams: any;
|
||||
setValue(params: any, paramName: string, value: T): void;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { AggControlProps } from './agg_control_props';
|
||||
|
||||
interface AggControlReactWrapperProps<T> extends AggControlProps<T> {
|
||||
component: React.FunctionComponent<AggControlProps<T>>;
|
||||
}
|
||||
|
||||
function AggControlReactWrapper({
|
||||
component: Component,
|
||||
...rest
|
||||
}: AggControlReactWrapperProps<boolean | number>) {
|
||||
return <Component {...rest} />;
|
||||
}
|
||||
|
||||
export { AggControlReactWrapper };
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* 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 { wrapInI18nContext } from 'ui/i18n';
|
||||
import { uiModules } from '../../../../modules';
|
||||
import { AggControlReactWrapper } from './agg_control_react_wrapper';
|
||||
|
||||
uiModules
|
||||
.get('app/visualize')
|
||||
.directive('visAggControlReactWrapper', reactDirective => reactDirective(wrapInI18nContext(AggControlReactWrapper), [
|
||||
['aggParams', { watchDepth: 'collection' }],
|
||||
['editorStateParams', { watchDepth: 'collection' }],
|
||||
['component', { wrapApply: false }],
|
||||
'setValue'
|
||||
]));
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
* 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, EuiIconTip, EuiRange } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { AggControlProps } from './agg_control_props';
|
||||
|
||||
const DEFAULT_VALUE = 50;
|
||||
const PARAM_NAME = 'radiusRatio';
|
||||
|
||||
function RadiusRatioOptionControl({ editorStateParams, setValue }: AggControlProps<number>) {
|
||||
const label = (
|
||||
<>
|
||||
<FormattedMessage
|
||||
id="common.ui.vis.defaultEditor.controls.dotSizeRatioLabel"
|
||||
defaultMessage="Dot size ratio"
|
||||
/>{' '}
|
||||
<EuiIconTip
|
||||
content={i18n.translate('common.ui.vis.defaultEditor.controls.dotSizeRatioHelpText', {
|
||||
defaultMessage:
|
||||
'Change the ratio of the radius of the smallest point to the largest point.',
|
||||
})}
|
||||
position="right"
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (!editorStateParams.radiusRatio) {
|
||||
setValue(editorStateParams, PARAM_NAME, DEFAULT_VALUE);
|
||||
}
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<EuiFormRow fullWidth={true} label={label}>
|
||||
{
|
||||
// @ts-ignore: valueAppend does not exist in EuiRange prop types
|
||||
<EuiRange
|
||||
compressed
|
||||
fullWidth={true}
|
||||
min={1}
|
||||
max={100}
|
||||
value={editorStateParams.radiusRatio || DEFAULT_VALUE}
|
||||
onChange={e => setValue(editorStateParams, PARAM_NAME, parseFloat(e.target.value))}
|
||||
showRange
|
||||
showValue
|
||||
valueAppend="%"
|
||||
/>
|
||||
}
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
export { RadiusRatioOptionControl };
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Licensed to Elasticsearch B.V. under one or more contributor
|
||||
* license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright
|
||||
* ownership. Elasticsearch B.V. licenses this file to you under
|
||||
* the Apache License, Version 2.0 (the "License"); you may
|
||||
* not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { EuiButtonGroup, EuiFormRow } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AggControlProps } from './agg_control_props';
|
||||
|
||||
const PARAMS = {
|
||||
NAME: 'row',
|
||||
ROWS: 'visEditorSplitBy__true',
|
||||
COLUMNS: 'visEditorSplitBy__false',
|
||||
};
|
||||
|
||||
function RowsOrColumnsControl({ aggParams, setValue }: AggControlProps<boolean>) {
|
||||
const idSelected = `visEditorSplitBy__${aggParams.row}`;
|
||||
const options = [
|
||||
{
|
||||
id: PARAMS.ROWS,
|
||||
label: i18n.translate('common.ui.vis.defaultEditor.controls.rowsLabel', {
|
||||
defaultMessage: 'Rows',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: PARAMS.COLUMNS,
|
||||
label: i18n.translate('common.ui.vis.defaultEditor.controls.columnsLabel', {
|
||||
defaultMessage: 'Columns',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<EuiFormRow className="visEditorSidebar__aggParamFormRow" fullWidth={true}>
|
||||
<EuiButtonGroup
|
||||
data-test-subj="visEditorSplitBy"
|
||||
legend={i18n.translate('common.ui.vis.defaultEditor.controls.splitByLegend', {
|
||||
defaultMessage: 'Split chart by rows or columns.',
|
||||
})}
|
||||
options={options}
|
||||
isFullWidth={true}
|
||||
idSelected={idSelected}
|
||||
onChange={optionId => setValue(aggParams, PARAMS.NAME, optionId === PARAMS.ROWS)}
|
||||
/>
|
||||
</EuiFormRow>
|
||||
);
|
||||
}
|
||||
|
||||
export { RowsOrColumnsControl };
|
|
@ -18,11 +18,10 @@
|
|||
*/
|
||||
|
||||
import _ from 'lodash';
|
||||
import '../directives/buttons';
|
||||
import { IndexedArray } from '../../../indexed_array';
|
||||
import { AggParams } from '../../../agg_types/agg_params';
|
||||
import rowsOrColumnsHtml from 'plugins/kbn_vislib_vis_types/controls/rows_or_columns.html';
|
||||
import radiusRatioOptionHtml from 'plugins/kbn_vislib_vis_types/controls/radius_ratio_option.html';
|
||||
import { RowsOrColumnsControl } from './controls/rows_or_columns';
|
||||
import { RadiusRatioOptionControl } from './controls/radius_ratio_option';
|
||||
|
||||
class Schemas {
|
||||
constructor(schemas) {
|
||||
|
@ -38,9 +37,9 @@ class Schemas {
|
|||
default: true
|
||||
}
|
||||
];
|
||||
schema.editor = rowsOrColumnsHtml;
|
||||
schema.editorComponent = RowsOrColumnsControl;
|
||||
} else if (schema.name === 'radius') {
|
||||
schema.editor = radiusRatioOptionHtml;
|
||||
schema.editorComponent = RadiusRatioOptionControl;
|
||||
}
|
||||
|
||||
_.defaults(schema, {
|
||||
|
|
|
@ -1,60 +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 angular from 'angular';
|
||||
import { uiModules } from 'ui/modules';
|
||||
const module = uiModules.get('kibana');
|
||||
|
||||
module.constant('buttonConfig', {
|
||||
activeClass: 'active',
|
||||
toggleEvent: 'click'
|
||||
});
|
||||
|
||||
module.controller('ButtonsController', ['buttonConfig', function (buttonConfig) {
|
||||
this.activeClass = buttonConfig.activeClass || 'active';
|
||||
this.toggleEvent = buttonConfig.toggleEvent || 'click';
|
||||
}]);
|
||||
|
||||
module.directive('btnRadio', function () {
|
||||
return {
|
||||
require: ['btnRadio', 'ngModel'],
|
||||
controller: 'ButtonsController',
|
||||
link: function (scope, element, attrs, ctrls) {
|
||||
const buttonsCtrl = ctrls[0];
|
||||
const ngModelCtrl = ctrls[1];
|
||||
|
||||
//model -> UI
|
||||
ngModelCtrl.$render = function () {
|
||||
element.toggleClass(buttonsCtrl.activeClass, angular.equals(ngModelCtrl.$modelValue, scope.$eval(attrs.btnRadio)));
|
||||
};
|
||||
|
||||
//ui->model
|
||||
element.bind(buttonsCtrl.toggleEvent, function () {
|
||||
const isActive = element.hasClass(buttonsCtrl.activeClass);
|
||||
|
||||
if (!isActive || angular.isDefined(attrs.uncheckable)) {
|
||||
scope.$apply(function () {
|
||||
ngModelCtrl.$setViewValue(isActive ? null : scope.$eval(attrs.btnRadio));
|
||||
ngModelCtrl.$render();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
|
@ -45,7 +45,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
log.debug('Field = extension');
|
||||
await PageObjects.visualize.selectField('extension.raw');
|
||||
log.debug('switch from Rows to Columns');
|
||||
await PageObjects.visualize.clickColumns();
|
||||
await PageObjects.visualize.clickSplitDirection('Columns');
|
||||
await PageObjects.visualize.clickGo();
|
||||
};
|
||||
|
||||
|
|
|
@ -999,10 +999,6 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli
|
|||
return await markdown.getVisibleText();
|
||||
}
|
||||
|
||||
async clickColumns() {
|
||||
await find.clickByCssSelector('div.schemaEditors > div > div > button:nth-child(2)');
|
||||
}
|
||||
|
||||
async getVisualizationRenderingCount() {
|
||||
const visualizationLoader = await testSubjects.find('visualizationLoader');
|
||||
const renderingCount = await visualizationLoader.getAttribute('data-rendering-count');
|
||||
|
@ -1232,9 +1228,9 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli
|
|||
}
|
||||
|
||||
async clickSplitDirection(direction) {
|
||||
const activeParamPanel = await find.byCssSelector('vis-editor-agg-params[aria-hidden="false"]');
|
||||
const button = await testSubjects.findDescendant(`splitBy-${direction}`, activeParamPanel);
|
||||
await button.click();
|
||||
const control = await testSubjects.find('visEditorSplitBy');
|
||||
const radioBtn = await control.findByCssSelector(`[title="${direction}"]`);
|
||||
await radioBtn.click();
|
||||
}
|
||||
|
||||
async countNestedTables() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue