Vis default editor plugin (#55612)

* Shim the default_editor

* Update paths in vis_default_editor

* Update paths in dependent plugins

* Update the dependent plugins

* Create an entry point

* Wrap the editor with kibana context

* Fix circular re-renders

* Update sub aggs mapping

* Move schemas and agg_groups to agg_types, update jest tests

* Use services from kibana context, other fixes

* Fix useEffect maximum update depth

* Create i18n namesapce for visDefaultEditor, rename translations

* Fix tests

* Resolve paths

* Remove ui/vis/vis_types

* Fix vis import

* Move editor_config_provider to ui/vis
This commit is contained in:
Daniil Suleiman 2020-01-29 17:41:18 +03:00 committed by GitHub
parent c2aff7e2fb
commit 7f63118d6b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
257 changed files with 1352 additions and 1191 deletions

View file

@ -88,6 +88,14 @@ module.exports = {
'react-hooks/exhaustive-deps': 'off',
},
},
{
files: [
'src/legacy/core_plugins/vis_default_editor/public/components/controls/**/*.{ts,tsx}',
],
rules: {
'react-hooks/exhaustive-deps': 'off',
},
},
{
files: ['src/legacy/ui/public/vis/**/*.{js,ts,tsx}'],
rules: {

View file

@ -35,6 +35,7 @@
"tileMap": "src/legacy/core_plugins/tile_map",
"timelion": ["src/legacy/core_plugins/timelion", "src/legacy/core_plugins/vis_type_timelion", "src/plugins/timelion"],
"uiActions": "src/plugins/ui_actions",
"visDefaultEditor": "src/legacy/core_plugins/vis_default_editor",
"visTypeMarkdown": "src/legacy/core_plugins/vis_type_markdown",
"visTypeMetric": "src/legacy/core_plugins/vis_type_metric",
"visTypeTable": "src/legacy/core_plugins/vis_type_table",

View file

@ -30,6 +30,8 @@ import {
EuiSelect,
} from '@elastic/eui';
import { VisOptionsProps } from 'src/legacy/core_plugins/vis_default_editor/public';
import { IIndexPattern } from 'src/plugins/data/public';
import { ControlEditor } from './control_editor';
import {
addControl,
@ -42,8 +44,6 @@ import {
ControlParamsOptions,
} from '../../editor_utils';
import { getLineageMap, getParentCandidates } from '../../lineage';
import { IIndexPattern } from '../../../../../../plugins/data/public';
import { VisOptionsProps } from '../../legacy_imports';
import { InputControlVisDependencies } from '../../plugin';
interface ControlsTabUiState {

View file

@ -21,8 +21,8 @@ import React from 'react';
import { shallow } from 'enzyme';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { Vis } from 'src/legacy/core_plugins/visualizations/public';
import { OptionsTab, OptionsTabProps } from './options_tab';
import { Vis } from '../../legacy_imports';
describe('OptionsTab', () => {
let props: OptionsTabProps;

View file

@ -23,7 +23,7 @@ import { EuiForm, EuiFormRow, EuiSwitch } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiSwitchEvent } from '@elastic/eui';
import { VisOptionsProps } from '../../legacy_imports';
import { VisOptionsProps } from 'src/legacy/core_plugins/vis_default_editor/public';
interface OptionsTabParams {
updateFiltersOnChange: boolean;

View file

@ -22,8 +22,6 @@ import { SearchSource as SearchSourceClass, ISearchSource } from '../../../../pl
export { SearchSourceFields } from '../../../../plugins/data/public';
export { Vis, VisParams } from 'ui/vis';
export { VisOptionsProps } from 'ui/vis/editors/default';
export { ValidatedDualRange } from 'ui/validated_range';
export type SearchSource = Class<ISearchSource>;

View file

@ -21,7 +21,7 @@ import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { I18nStart } from 'kibana/public';
import { Vis, VisParams, SearchSource } from './legacy_imports';
import { SearchSource } from './legacy_imports';
import { InputControlVis } from './components/vis/input_control_vis';
import { getControlFactory } from './control/control_factory';
@ -31,6 +31,7 @@ import { RangeControl } from './control/range_control_factory';
import { ListControl } from './control/list_control_factory';
import { InputControlVisDependencies } from './plugin';
import { FilterManager, esFilters } from '../../../../plugins/data/public';
import { VisParams, Vis } from '../../visualizations/public';
export const createInputControlVisController = (deps: InputControlVisDependencies) => {
return class InputControlVisController {

View file

@ -76,7 +76,6 @@ export { unhashUrl } from '../../../../../plugins/kibana_utils/public';
export { formatMsg, formatStack } from 'ui/notify/lib/index';
// EXPORT types
export { Vis } from 'ui/vis';
export {
IndexPatternsContract,
IIndexPattern,

View file

@ -52,12 +52,12 @@ import {
stateMonitorFactory,
subscribeWithScope,
tabifyAggResponse,
Vis,
SavedObjectSaveModal,
getAngularModule,
ensureDefaultIndexPattern,
registerTimefilterWithGlobalStateFactory,
} from '../../kibana_services';
import { Vis } from '../../../../../visualizations/public';
const {
core,

View file

@ -65,9 +65,9 @@ export { KbnUrlProvider, RedirectWhenMissingProvider } from 'ui/url';
export { absoluteToParsedUrl } from 'ui/url/absolute_to_parsed_url';
export { KibanaParsedUrl } from 'ui/url/kibana_parsed_url';
export { VisType } from 'ui/vis';
export { wrapInI18nContext } from 'ui/i18n';
export { DashboardConstants } from '../dashboard/np_ready/dashboard_constants';
export { VisSavedObject } from '../../../visualizations/public/embeddable/visualize_embeddable';
export { VISUALIZE_EMBEDDABLE_TYPE } from '../../../visualizations/public/embeddable';
export { VisType } from '../../../visualizations/public';

View file

@ -57,7 +57,7 @@ export function initEditorDirective(app, deps) {
};
});
initVisEditorDirective(app);
initVisEditorDirective(app, deps);
initVisualizationDirective(app, deps);
}

View file

@ -17,7 +17,7 @@
* under the License.
*/
export function initVisEditorDirective(app) {
export function initVisEditorDirective(app, deps) {
app.directive('visualizationEditor', function($timeout, getAppState) {
return {
restrict: 'E',
@ -34,6 +34,9 @@ export function initVisEditorDirective(app) {
$scope.renderFunction = () => {
editor.render({
core: deps.core,
data: deps.data,
embeddables: deps.embeddables,
uiState: $scope.uiState,
timeRange: $scope.timeRange,
filters: $scope.filters,

View file

@ -17,11 +17,16 @@
* under the License.
*/
import { TimeRange, Query, esFilters } from 'src/plugins/data/public';
import { TimeRange, Query, esFilters, DataPublicPluginStart } from 'src/plugins/data/public';
import { IEmbeddableStart } from 'src/plugins/embeddable/public';
import { LegacyCoreStart } from 'kibana/public';
import { VisSavedObject, AppState, PersistedState } from '../legacy_imports';
export interface EditorRenderProps {
appState: AppState;
core: LegacyCoreStart;
data: DataPublicPluginStart;
embeddables: IEmbeddableStart;
filters: esFilters.Filter[];
uiState: PersistedState;
timeRange: TimeRange;

View file

@ -22,7 +22,6 @@ import ngMock from 'ng_mock';
import _ from 'lodash';
import ChoroplethLayer from '../choropleth_layer';
import LogstashIndexPatternStubProvider from 'fixtures/stubbed_logstash_index_pattern';
import { Vis } from 'ui/vis';
import { ImageComparator } from 'test_utils/image_comparator';
import worldJson from './world.json';
import EMS_CATALOGUE from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_manifest.json';
@ -40,6 +39,7 @@ import afterdatachangeandresizePng from './afterdatachangeandresize.png';
import aftercolorchangePng from './aftercolorchange.png';
import changestartupPng from './changestartup.png';
import { setup as visualizationsSetup } from '../../../visualizations/public/np_ready/public/legacy';
import { Vis } from '../../../visualizations/public/np_ready/public/vis';
import { createRegionMapVisualization } from '../region_map_visualization';
import { createRegionMapTypeDefinition } from '../region_map_type';

View file

@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { FileLayerField, VectorLayer, ServiceSettings } from 'ui/vis/map/service_settings';
import { VisOptionsProps } from 'ui/vis/editors/default';
import { VisOptionsProps } from 'src/legacy/core_plugins/vis_default_editor/public';
import { NumberInputOption, SelectOption, SwitchOption } from '../../../vis_type_vislib/public';
import { WmsOptions } from '../../../tile_map/public/components/wms_options';
import { RegionMapVisParams } from '../types';

View file

@ -18,7 +18,7 @@
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { Schemas } from 'ui/vis/editors/default/schemas';
import { Schemas } from 'ui/agg_types';
import { mapToLayerWithId } from './util';
import { createRegionMapVisualization } from './region_map_visualization';
import { Status } from '../../visualizations/public';

View file

@ -20,7 +20,6 @@
import expect from '@kbn/expect';
import ngMock from 'ng_mock';
import LogstashIndexPatternStubProvider from 'fixtures/stubbed_logstash_index_pattern';
import { Vis } from 'ui/vis';
import { ImageComparator } from 'test_utils/image_comparator';
import dummyESResponse from './dummy_es_response.json';
import initial from './initial.png';
@ -34,6 +33,7 @@ import EMS_STYLE_ROAD_MAP_BRIGHT from '../../../../ui/public/vis/__tests__/map/e
import EMS_STYLE_ROAD_MAP_DESATURATED from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_desaturated';
import EMS_STYLE_DARK_MAP from '../../../../ui/public/vis/__tests__/map/ems_mocks/sample_style_dark';
import { setup as visualizationsSetup } from '../../../visualizations/public/np_ready/public/legacy';
import { Vis } from '../../../visualizations/public/np_ready/public/vis';
import { createTileMapVisualization } from '../tile_map_visualization';
import { createTileMapTypeDefinition } from '../tile_map_type';

View file

@ -21,7 +21,7 @@ import React, { useEffect } from 'react';
import { EuiPanel, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { VisOptionsProps } from 'ui/vis/editors/default';
import { VisOptionsProps } from 'src/legacy/core_plugins/vis_default_editor/public';
import {
BasicOptions,
RangeOption,

View file

@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { TmsLayer } from 'ui/vis/map/service_settings';
import { Vis } from 'ui/vis';
import { Vis } from '../../../visualizations/public';
import { RegionMapVisParams } from '../../../region_map/public/types';
import { SelectOption, SwitchOption } from '../../../vis_type_vislib/public';
import { WmsInternalOptions } from './wms_internal_options';

View file

@ -20,11 +20,11 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { Schemas } from 'ui/vis/editors/default/schemas';
import { convertToGeoJson } from 'ui/vis/map/convert_to_geojson';
import { Schemas } from 'ui/agg_types';
import { createTileMapVisualization } from './tile_map_visualization';
import { Status } from '../../visualizations/public';
import { createTileMapVisualization } from './tile_map_visualization';
import { TileMapOptions } from './components/tile_map_options';
import { MapTypes } from './map_types';
import { supportsCssFilters } from './css_filters';

View file

@ -17,7 +17,26 @@
* under the License.
*/
import { BaseVisType } from '../../../../core_plugins/visualizations/public/np_ready/public/types/base_vis_type';
import { ReactVisType } from '../../../../core_plugins/visualizations/public/np_ready/public/types/react_vis_type';
import { resolve } from 'path';
import { Legacy } from 'kibana';
export { BaseVisType, ReactVisType };
import { LegacyPluginApi, LegacyPluginInitializer } from '../../../../src/legacy/types';
const vidDefaultEditorPluginInitializer: LegacyPluginInitializer = ({ Plugin }: LegacyPluginApi) =>
new Plugin({
id: 'vis_default_editor',
require: [],
publicDir: resolve(__dirname, 'public'),
uiExports: {
styleSheetPaths: resolve(__dirname, 'public/index.scss'),
},
init: (server: Legacy.Server) => ({}),
config(Joi: any) {
return Joi.object({
enabled: Joi.boolean().default(true),
}).default();
},
} as Legacy.PluginSpecOptions);
// eslint-disable-next-line import/no-default-export
export default vidDefaultEditorPluginInitializer;

View file

@ -0,0 +1,4 @@
{
"name": "vis_default_editor",
"version": "kibana"
}

View file

@ -59,15 +59,6 @@
+ .visEditorSidebar__section {
margin-top: $euiSizeS;
}
label:not([class^='eui']) {
@include __legacyLabelStyles__bad;
display: block;
}
.form-group label {
margin-bottom: $euiSizeS;
}
}
// Collapsible section

View file

@ -19,15 +19,18 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { VisState } from '../../..';
import { AggGroupNames } from '../agg_groups';
import { DefaultEditorAgg, DefaultEditorAggProps } from './agg';
import { act } from 'react-dom/test-utils';
import { IndexPattern } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { AggType, AggGroupNames } from '../legacy_imports';
import { DefaultEditorAgg, DefaultEditorAggProps } from './agg';
import { DefaultEditorAggParams } from './agg_params';
import { AggType } from 'ui/agg_types';
import { IndexPattern } from '../../../../../../../plugins/data/public';
import { AGGS_ACTION_KEYS } from './agg_group_state';
jest.mock('ui/new_platform');
jest.mock('./agg_params', () => ({
DefaultEditorAggParams: () => null,
}));
@ -173,11 +176,11 @@ describe('DefaultEditorAgg component', () => {
it('should add schema component', () => {
defaultProps.agg.schema = {
editorComponent: () => <div className="schemaComponent" />,
name: 'split',
} as any;
const comp = mount(<DefaultEditorAgg {...defaultProps} />);
expect(comp.find('.schemaComponent').exists()).toBeTruthy();
expect(comp.find('RowsOrColumnsControl').exists()).toBeTruthy();
});
describe('agg actions', () => {

View file

@ -28,10 +28,12 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../..';
import { AggConfig } from '../legacy_imports';
import { DefaultEditorAggParams } from './agg_params';
import { DefaultEditorAggCommonProps } from './agg_common_props';
import { AGGS_ACTION_KEYS, AggsAction } from './agg_group_state';
import { RowsOrColumnsControl } from './controls/rows_or_columns';
import { RadiusRatioOptionControl } from './controls/radius_ratio_option';
export interface DefaultEditorAggProps extends DefaultEditorAggCommonProps {
agg: AggConfig;
@ -70,18 +72,27 @@ function DefaultEditorAgg({
const [validState, setValidState] = useState(true);
const showDescription = !isEditorOpen && validState;
const showError = !isEditorOpen && !validState;
const aggName = agg.type?.name;
let disabledParams;
let aggError;
// When a Parent Pipeline agg is selected and this agg is the last bucket.
const isLastBucketAgg = isLastBucket && lastParentPipelineAggTitle && agg.type;
const SchemaComponent = agg.schema.editorComponent;
let SchemaComponent;
if (agg.schema.name === 'split') {
SchemaComponent = RowsOrColumnsControl;
}
if (agg.schema.name === 'radius') {
SchemaComponent = RadiusRatioOptionControl;
}
if (isLastBucketAgg) {
if (['date_histogram', 'histogram'].includes(agg.type.name)) {
if (['date_histogram', 'histogram'].includes(aggName)) {
disabledParams = ['min_doc_count'];
} else {
aggError = i18n.translate('common.ui.aggTypes.metrics.wrongLastBucketTypeErrorMessage', {
aggError = i18n.translate('visDefaultEditor.metrics.wrongLastBucketTypeErrorMessage', {
defaultMessage:
'Last bucket aggregation must be "Date Histogram" or "Histogram" when using "{type}" metric aggregation.',
values: { type: lastParentPipelineAggTitle },
@ -104,16 +115,16 @@ function DefaultEditorAgg({
}
useEffect(() => {
if (isLastBucketAgg && ['date_histogram', 'histogram'].includes(agg.type.name)) {
if (isLastBucketAgg && ['date_histogram', 'histogram'].includes(aggName)) {
setAggParamValue(
agg.id,
'min_doc_count',
// "histogram" agg has an editor for "min_doc_count" param, which accepts boolean
// "date_histogram" agg doesn't have an editor for "min_doc_count" param, it should be set as a numeric value
agg.type.name === 'histogram' ? true : 0
aggName === 'histogram' ? true : 0
);
}
}, [lastParentPipelineAggTitle, isLastBucket, agg.type]);
}, [aggName, isLastBucketAgg, agg.id, setAggParamValue]);
const setTouched = useCallback(
(touched: boolean) => {
@ -123,7 +134,7 @@ function DefaultEditorAgg({
aggId: agg.id,
});
},
[setAggsState]
[agg.id, setAggsState]
);
const setValidity = useCallback(
@ -135,7 +146,7 @@ function DefaultEditorAgg({
});
setValidState(isValid);
},
[setAggsState]
[agg.id, setAggsState]
);
const onToggle = useCallback(
@ -156,7 +167,7 @@ function DefaultEditorAgg({
id: 'hasErrors',
color: 'danger',
type: 'alert',
tooltip: i18n.translate('common.ui.vis.editors.agg.errorsAriaLabel', {
tooltip: i18n.translate('visDefaultEditor.agg.errorsAriaLabel', {
defaultMessage: 'Aggregation has errors',
}),
dataTestSubj: 'hasErrorsAggregationIcon',
@ -170,7 +181,7 @@ function DefaultEditorAgg({
disabled: isDisabled,
type: 'eye',
onClick: () => onToggleEnableAgg(agg.id, false),
tooltip: i18n.translate('common.ui.vis.editors.agg.disableAggButtonTooltip', {
tooltip: i18n.translate('visDefaultEditor.agg.disableAggButtonTooltip', {
defaultMessage: 'Disable aggregation',
}),
dataTestSubj: 'toggleDisableAggregationBtn disable',
@ -182,7 +193,7 @@ function DefaultEditorAgg({
color: 'text',
type: 'eyeClosed',
onClick: () => onToggleEnableAgg(agg.id, true),
tooltip: i18n.translate('common.ui.vis.editors.agg.enableAggButtonTooltip', {
tooltip: i18n.translate('visDefaultEditor.agg.enableAggButtonTooltip', {
defaultMessage: 'Enable aggregation',
}),
dataTestSubj: 'toggleDisableAggregationBtn enable',
@ -192,7 +203,7 @@ function DefaultEditorAgg({
actionIcons.push({
id: 'dragHandle',
type: 'grab',
tooltip: i18n.translate('common.ui.vis.editors.agg.modifyPriorityButtonTooltip', {
tooltip: i18n.translate('visDefaultEditor.agg.modifyPriorityButtonTooltip', {
defaultMessage: 'Modify priority by dragging',
}),
dataTestSubj: 'dragHandleBtn',
@ -204,7 +215,7 @@ function DefaultEditorAgg({
color: 'danger',
type: 'cross',
onClick: () => removeAgg(agg.id),
tooltip: i18n.translate('common.ui.vis.editors.agg.removeDimensionButtonTooltip', {
tooltip: i18n.translate('visDefaultEditor.agg.removeDimensionButtonTooltip', {
defaultMessage: 'Remove dimension',
}),
dataTestSubj: 'removeDimensionBtn',
@ -259,7 +270,7 @@ function DefaultEditorAgg({
buttonClassName="eui-textTruncate"
buttonContentClassName="visEditorSidebar__aggGroupAccordionButtonContent eui-textTruncate"
className="visEditorSidebar__section visEditorSidebar__collapsible visEditorSidebar__collapsible--marginBottom"
aria-label={i18n.translate('common.ui.vis.editors.agg.toggleEditorButtonAriaLabel', {
aria-label={i18n.translate('visDefaultEditor.agg.toggleEditorButtonAriaLabel', {
defaultMessage: 'Toggle {schema} editor',
values: { schema: agg.schema.title },
})}

View file

@ -29,9 +29,7 @@ import {
} from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../..';
import { Schema } from '../schemas';
import { AggGroupNames } from '../agg_groups';
import { AggConfig, AggGroupNames, Schema } from '../legacy_imports';
interface DefaultEditorAggAddProps {
group?: AggConfig[];
@ -64,14 +62,14 @@ function DefaultEditorAggAdd({
data-test-subj={`visEditorAdd_${groupName}`}
onClick={() => setIsPopoverOpen(!isPopoverOpen)}
>
<FormattedMessage id="common.ui.vis.editors.aggAdd.addButtonLabel" defaultMessage="Add" />
<FormattedMessage id="visDefaultEditor.aggAdd.addButtonLabel" defaultMessage="Add" />
</EuiButtonEmpty>
);
const groupNameLabel =
groupName === AggGroupNames.Buckets
? i18n.translate('common.ui.vis.editors.aggAdd.bucketLabel', { defaultMessage: 'bucket' })
: i18n.translate('common.ui.vis.editors.aggAdd.metricLabel', { defaultMessage: 'metric' });
? i18n.translate('visDefaultEditor.aggAdd.bucketLabel', { defaultMessage: 'bucket' })
: i18n.translate('visDefaultEditor.aggAdd.metricLabel', { defaultMessage: 'metric' });
const isSchemaDisabled = (schema: Schema): boolean => {
const count = group.filter(agg => agg.schema.name === schema.name).length;
@ -92,14 +90,14 @@ function DefaultEditorAggAdd({
<EuiPopoverTitle>
{(groupName !== AggGroupNames.Buckets || !stats.count) && (
<FormattedMessage
id="common.ui.vis.editors.aggAdd.addGroupButtonLabel"
id="visDefaultEditor.aggAdd.addGroupButtonLabel"
defaultMessage="Add {groupNameLabel}"
values={{ groupNameLabel }}
/>
)}
{groupName === AggGroupNames.Buckets && stats.count > 0 && (
<FormattedMessage
id="common.ui.vis.editors.aggAdd.addSubGroupButtonLabel"
id="visDefaultEditor.aggAdd.addSubGroupButtonLabel"
defaultMessage="Add sub-{groupNameLabel}"
values={{ groupNameLabel }}
/>

View file

@ -17,10 +17,8 @@
* under the License.
*/
import { AggType } from 'ui/agg_types';
import { AggConfig, VisState, VisParams } from 'ui/vis';
import { AggGroupNames } from '../agg_groups';
import { Schema } from '../schemas';
import { VisState, VisParams } from 'src/legacy/core_plugins/visualizations/public';
import { AggType, AggConfig, AggGroupNames, Schema } from '../legacy_imports';
type AggId = AggConfig['id'];
type AggParams = AggConfig['params'];

View file

@ -20,10 +20,8 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { act } from 'react-dom/test-utils';
import { VisState, AggConfig } from '../../../';
import { Schema } from '../schemas';
import { AggGroupNames } from '../agg_groups';
import { AggConfigs } from '../../../../agg_types/agg_configs';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { AggConfigs, AggConfig, Schema } from '../legacy_imports';
import { DefaultEditorAggGroup, DefaultEditorAggGroupProps } from './agg_group';
import { DefaultEditorAgg } from './agg';
import { DefaultEditorAggAdd } from './agg_add';
@ -37,6 +35,17 @@ jest.mock('@elastic/eui', () => ({
EuiPanel: 'eui-panel',
}));
jest.mock('../legacy_imports', () => ({
aggGroupNamesMap: () => ({
metrics: 'Metrics',
buckets: 'Buckets',
}),
AggGroupNames: {
Metrics: 'metrics',
Buckets: 'buckets',
},
}));
jest.mock('./agg', () => ({
DefaultEditorAgg: () => <div />,
}));
@ -92,7 +101,7 @@ describe('DefaultEditorAgg component', () => {
defaultProps = {
formIsTouched: false,
metricAggs: [],
groupName: AggGroupNames.Metrics,
groupName: 'metrics',
state: {
aggs,
} as VisState,
@ -129,7 +138,7 @@ describe('DefaultEditorAgg component', () => {
});
it('should last bucket has truthy isLastBucket prop', () => {
defaultProps.groupName = AggGroupNames.Buckets;
defaultProps.groupName = 'buckets';
const comp = mount(<DefaultEditorAggGroup {...defaultProps} />);
const lastAgg = comp.find(DefaultEditorAgg).last();
@ -150,7 +159,7 @@ describe('DefaultEditorAgg component', () => {
});
it('should show add button when schemas count is less than max', () => {
defaultProps.groupName = AggGroupNames.Buckets;
defaultProps.groupName = 'buckets';
const comp = shallow(<DefaultEditorAggGroup {...defaultProps} />);
expect(comp.find(DefaultEditorAggAdd).exists()).toBeTruthy();

View file

@ -30,8 +30,7 @@ import {
} from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../../../agg_types/agg_config';
import { aggGroupNamesMap, AggGroupNames } from '../agg_groups';
import { AggConfig, aggGroupNamesMap, AggGroupNames, Schema } from '../legacy_imports';
import { DefaultEditorAgg } from './agg';
import { DefaultEditorAggAdd } from './agg_add';
import { AddSchema, ReorderAggs, DefaultEditorAggCommonProps } from './agg_common_props';
@ -42,7 +41,6 @@ import {
getEnabledMetricAggsCount,
} from './agg_group_helper';
import { aggGroupReducer, initAggsState, AGGS_ACTION_KEYS } from './agg_group_state';
import { Schema } from '../schemas';
export interface DefaultEditorAggGroupProps extends DefaultEditorAggCommonProps {
schemas: Schema[];
@ -73,7 +71,7 @@ function DefaultEditorAggGroup({
// e.g. buckets can have no aggs
const group: AggConfig[] = useMemo(
() => state.aggs.aggs.filter((agg: AggConfig) => agg.schema.group === groupName) || [],
[state.aggs.aggs]
[groupName, state.aggs.aggs]
);
const stats = {
@ -89,7 +87,7 @@ function DefaultEditorAggGroup({
const bucketsError =
lastParentPipelineAggTitle && groupName === AggGroupNames.Buckets && !group.length
? i18n.translate('common.ui.aggTypes.buckets.mustHaveBucketErrorMessage', {
? i18n.translate('visDefaultEditor.buckets.mustHaveBucketErrorMessage', {
defaultMessage: 'Add a bucket with "Date Histogram" or "Histogram" aggregation.',
description: 'Date Histogram and Histogram should not be translated',
})
@ -120,6 +118,9 @@ function DefaultEditorAggGroup({
});
});
}
// adding all of the values to the deps array cause a circular re-render
// the logic should be rewised
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [formIsTouched]);
useEffect(() => {

View file

@ -17,7 +17,7 @@
* under the License.
*/
import { AggConfig } from '../../../../agg_types/agg_config';
import { AggConfig } from '../legacy_imports';
import {
isAggRemovable,
calcAggIsTooLow,

View file

@ -18,7 +18,7 @@
*/
import { findIndex, isEmpty } from 'lodash';
import { AggConfig } from '../../../../agg_types/agg_config';
import { AggConfig } from '../legacy_imports';
import { AggsState } from './agg_group_state';
const isAggRemovable = (agg: AggConfig, group: AggConfig[]) => {

View file

@ -17,7 +17,7 @@
* under the License.
*/
import { AggConfig } from '../../../../agg_types/agg_config';
import { AggConfig } from '../legacy_imports';
export enum AGGS_ACTION_KEYS {
TOUCHED = 'aggsTouched',

View file

@ -75,7 +75,7 @@ function DefaultEditorAggParam<T>(props: DefaultEditorAggParamProps<T>) {
if (aggParam.shouldShow && !aggParam.shouldShow(agg)) {
setValidity(true);
}
}, [agg, agg.params.field]);
}, [agg, agg.params.field, aggParam, setValidity]);
if (aggParam.shouldShow && !aggParam.shouldShow(agg)) {
return null;

View file

@ -17,12 +17,10 @@
* under the License.
*/
import { AggParam } from 'ui/agg_types';
import { AggConfig } from '../../../../agg_types/agg_config';
import { Field } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { AggConfig, AggParam, EditorConfig } from '../legacy_imports';
import { ComboBoxGroupedOptions } from '../utils';
import { EditorConfig } from '../../config/types';
import { VisState } from '../../..';
import { Field } from '../../../../../../../plugins/data/public';
// NOTE: we cannot export the interface with export { InterfaceName }
// as there is currently a bug on babel typescript transform plugin for it

View file

@ -19,10 +19,11 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { AggConfig, VisState } from '../../..';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { IndexPattern } from 'src/plugins/data/public';
import { DefaultEditorAggParams, DefaultEditorAggParamsProps } from './agg_params';
import { AggGroupNames } from '../agg_groups';
import { IndexPattern } from '../../../../../../../plugins/data/public';
import { AggConfig, AggGroupNames } from '../legacy_imports';
const mockEditorConfig = {
useNormalizedEsInterval: { hidden: false, fixedValue: false },
@ -34,15 +35,8 @@ const mockEditorConfig = {
},
};
jest.mock('ui/agg_types', () => ({
aggTypes: {
byType: {
metrics: [],
buckets: [],
},
},
}));
jest.mock('../../config/editor_config_providers', () => ({
jest.mock('ui/new_platform');
jest.mock('ui/vis/config', () => ({
editorConfigProviders: {
getConfigForAgg: jest.fn(() => mockEditorConfig),
},

View file

@ -22,8 +22,15 @@ import { EuiForm, EuiAccordion, EuiSpacer, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import useUnmount from 'react-use/lib/useUnmount';
import { AggConfig } from 'ui/agg_types/';
import { IndexPattern } from '../../../../../../../plugins/data/public';
import { IndexPattern } from 'src/plugins/data/public';
import {
AggConfig,
AggGroupNames,
editorConfigProviders,
FixedParam,
TimeIntervalParam,
EditorParamConfig,
} from '../legacy_imports';
import { DefaultEditorAggSelect } from './agg_select';
import { DefaultEditorAggParam } from './agg_param';
@ -38,9 +45,6 @@ import {
AGG_PARAMS_ACTION_KEYS,
initAggParamsState,
} from './agg_params_state';
import { editorConfigProviders } from '../../config/editor_config_providers';
import { FixedParam, TimeIntervalParam, EditorParamConfig } from '../../config/types';
import { AggGroupNames } from '../agg_groups';
import { DefaultEditorCommonProps } from './agg_common_props';
const FIXED_VALUE_PROP = 'fixedValue';
@ -84,7 +88,7 @@ function DefaultEditorAggParams({
groupName,
]);
const error = aggIsTooLow
? i18n.translate('common.ui.vis.editors.aggParams.errors.aggWrongRunOrderErrorMessage', {
? i18n.translate('visDefaultEditor.aggParams.errors.aggWrongRunOrderErrorMessage', {
defaultMessage: '"{schema}" aggs must run before all other buckets!',
values: { schema: agg.schema.title },
})
@ -160,20 +164,21 @@ function DefaultEditorAggParams({
}
}
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [editorConfig]);
useEffect(() => {
setTouched(false);
}, [agg.type]);
}, [agg.type, setTouched]);
useEffect(() => {
setValidity(isFormValid);
}, [isFormValid, agg.type]);
}, [isFormValid, agg.type, setValidity]);
useEffect(() => {
// when all invalid controls were touched or they are untouched
setTouched(isAllInvalidParamsTouched);
}, [isAllInvalidParamsTouched]);
}, [isAllInvalidParamsTouched, setTouched]);
return (
<EuiForm
@ -218,12 +223,9 @@ function DefaultEditorAggParams({
<EuiAccordion
id="advancedAccordion"
data-test-subj={`advancedParams-${agg.id}`}
buttonContent={i18n.translate(
'common.ui.vis.editors.advancedToggle.advancedLinkLabel',
{
defaultMessage: 'Advanced',
}
)}
buttonContent={i18n.translate('visDefaultEditor.advancedToggle.advancedLinkLabel', {
defaultMessage: 'Advanced',
})}
>
<EuiSpacer size="s" />
{params.advanced.map(param => {

View file

@ -17,27 +17,29 @@
* under the License.
*/
import { AggConfig, VisState } from '../../..';
import { AggType } from 'ui/agg_types';
import { IndexedArray } from 'ui/indexed_array';
import { IndexPattern, Field } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import {
AggConfig,
AggType,
AggGroupNames,
BUCKET_TYPES,
IndexedArray,
EditorConfig,
} from '../legacy_imports';
import {
getAggParamsToRender,
getAggTypeOptions,
isInvalidParamsTouched,
} from './agg_params_helper';
import { EditorConfig } from '../../config/types';
import { IndexPattern, Field } from '../../../../../../../plugins/data/public';
import { FieldParamEditor, OrderByParamEditor } from './controls';
jest.mock('ui/agg_types', () => ({
aggTypes: {
metrics: [],
buckets: [],
},
}));
jest.mock('../utils', () => ({
groupAndSortBy: jest.fn(() => ['indexedFields']),
}));
jest.mock('ui/new_platform');
describe('DefaultEditorAggParams helpers', () => {
describe('getAggParamsToRender', () => {
let agg: AggConfig;
@ -102,6 +104,8 @@ describe('DefaultEditorAggParams helpers', () => {
const filterFieldTypes = ['number', 'boolean', 'date'];
agg = ({
type: {
type: AggGroupNames.Buckets,
name: BUCKET_TYPES.TERMS,
params: [
{
name: 'field',
@ -110,11 +114,9 @@ describe('DefaultEditorAggParams helpers', () => {
getAvailableFields: jest.fn((fields: IndexedArray<Field>) =>
fields.filter(({ type }) => filterFieldTypes.includes(type))
),
editorComponent: jest.fn(),
},
{
name: 'orderBy',
editorComponent: jest.fn(),
},
],
},
@ -139,7 +141,7 @@ describe('DefaultEditorAggParams helpers', () => {
aggParam: agg.type.params[0],
editorConfig,
indexedFields: ['indexedFields'],
paramEditor: agg.type.params[0].editorComponent,
paramEditor: FieldParamEditor,
metricAggs,
state,
value: agg.params.field,
@ -149,7 +151,7 @@ describe('DefaultEditorAggParams helpers', () => {
aggParam: agg.type.params[1],
editorConfig,
indexedFields: [],
paramEditor: agg.type.params[1].editorComponent,
paramEditor: OrderByParamEditor,
metricAggs,
state,
value: agg.params.orderBy,

View file

@ -18,15 +18,23 @@
*/
import { get, isEmpty } from 'lodash';
import { aggTypeFilters } from 'ui/agg_types/filter';
import { aggTypes, AggParam, FieldParamType, AggType } from 'ui/agg_types';
import { aggTypeFieldFilters } from 'ui/agg_types/param_types/filter';
import { AggConfig, VisState } from '../../..';
import { IndexPattern, Field } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { groupAndSortBy, ComboBoxGroupedOptions } from '../utils';
import { EditorConfig } from '../../config/types';
import { AggTypeState, AggParamsState } from './agg_params_state';
import { AggParamEditorProps } from './agg_param_props';
import { IndexPattern, Field } from '../../../../../../../plugins/data/public';
import { aggParamsMap } from './agg_params_map';
import {
aggTypeFilters,
aggTypeFieldFilters,
aggTypes,
AggConfig,
AggParam,
FieldParamType,
AggType,
EditorConfig,
} from '../legacy_imports';
interface ParamInstanceBase {
agg: AggConfig;
@ -79,14 +87,25 @@ function getAggParamsToRender({ agg, editorConfig, metricAggs, state }: ParamIns
const type = param.advanced ? 'advanced' : 'basic';
let paramEditor: ParamInstance['paramEditor'];
if (agg.type.subtype && aggParamsMap[agg.type.subtype]) {
paramEditor = get(aggParamsMap, [agg.type.subtype, param.name]);
} else {
const aggType = agg.type.type;
const aggName = agg.type.name;
const aggParams = get(aggParamsMap, [aggType, aggName], {});
paramEditor = get(aggParams, param.name) || get(aggParamsMap, ['common', param.type]);
}
// show params with an editor component
if (param.editorComponent) {
if (paramEditor) {
params[type].push({
agg,
aggParam: param,
editorConfig,
indexedFields,
paramEditor: param.editorComponent,
paramEditor,
metricAggs,
state,
value: agg.params[param.name],

View file

@ -0,0 +1,106 @@
/*
* 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 * as controls from './controls';
import {
AggGroupNames,
BUCKET_TYPES,
METRIC_TYPES,
siblingPipelineType,
parentPipelineType,
} from '../legacy_imports';
import { wrapWithInlineComp } from './controls/utils';
const buckets = {
[BUCKET_TYPES.DATE_HISTOGRAM]: {
scaleMetricValues: controls.ScaleMetricsParamEditor,
interval: controls.TimeIntervalParamEditor,
drop_partials: controls.DropPartialsParamEditor,
},
[BUCKET_TYPES.DATE_RANGE]: {
ranges: controls.DateRangesParamEditor,
},
[BUCKET_TYPES.FILTERS]: {
filters: controls.FiltersParamEditor,
},
[BUCKET_TYPES.GEOHASH_GRID]: {
autoPrecision: controls.AutoPrecisionParamEditor,
precision: controls.PrecisionParamEditor,
useGeocentroid: controls.UseGeocentroidParamEditor,
isFilteredByCollar: controls.IsFilteredByCollarParamEditor,
},
[BUCKET_TYPES.HISTOGRAM]: {
interval: controls.NumberIntervalParamEditor,
min_doc_count: controls.MinDocCountParamEditor,
has_extended_bounds: controls.HasExtendedBoundsParamEditor,
extended_bounds: controls.ExtendedBoundsParamEditor,
},
[BUCKET_TYPES.IP_RANGE]: {
ipRangeType: controls.IpRangeTypeParamEditor,
ranges: controls.IpRangesParamEditor,
},
[BUCKET_TYPES.RANGE]: {
ranges: controls.RangesControl,
},
[BUCKET_TYPES.SIGNIFICANT_TERMS]: {
size: controls.SizeParamEditor,
},
[BUCKET_TYPES.TERMS]: {
orderBy: controls.OrderByParamEditor,
orderAgg: controls.OrderAggParamEditor,
order: wrapWithInlineComp(controls.OrderParamEditor),
size: wrapWithInlineComp(controls.SizeParamEditor),
otherBucket: controls.OtherBucketParamEditor,
missingBucket: controls.MissingBucketParamEditor,
},
};
const metrics = {
[METRIC_TYPES.TOP_HITS]: {
field: controls.TopFieldParamEditor,
aggregate: wrapWithInlineComp(controls.TopAggregateParamEditor),
size: wrapWithInlineComp(controls.TopSizeParamEditor),
sortField: controls.TopSortFieldParamEditor,
sortOrder: controls.OrderParamEditor,
},
[METRIC_TYPES.PERCENTILES]: {
percents: controls.PercentilesEditor,
},
[METRIC_TYPES.PERCENTILE_RANKS]: {
values: controls.PercentileRanksEditor,
},
};
export const aggParamsMap = {
common: {
string: controls.StringParamEditor,
json: controls.RawJsonParamEditor,
field: controls.FieldParamEditor,
},
[siblingPipelineType]: {
customBucket: controls.SubMetricParamEditor,
customMetric: controls.SubMetricParamEditor,
},
[parentPipelineType]: {
metricAgg: controls.MetricAggParamEditor,
customMetric: controls.SubAggParamEditor,
},
[AggGroupNames.Buckets]: buckets,
[AggGroupNames.Metrics]: metrics,
};

View file

@ -22,10 +22,10 @@ import React, { useEffect, useCallback } from 'react';
import { EuiComboBox, EuiComboBoxOptionProps, EuiFormRow, EuiLink, EuiText } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { AggType } from 'ui/agg_types';
import { documentationLinks } from '../../../../documentation_links/documentation_links';
import { IndexPattern } from 'src/plugins/data/public';
import { AggType, documentationLinks } from '../legacy_imports';
import { ComboBoxGroupedOptions } from '../utils';
import { IndexPattern } from '../../../../../../../plugins/data/public';
import { AGG_TYPE_ACTION_KEYS, AggTypeAction } from './agg_params_state';
interface DefaultEditorAggSelectProps {
@ -57,12 +57,12 @@ function DefaultEditorAggSelect({
const label = isSubAggregation ? (
<FormattedMessage
id="common.ui.vis.defaultEditor.aggSelect.subAggregationLabel"
id="visDefaultEditor.aggSelect.subAggregationLabel"
defaultMessage="Sub aggregation"
/>
) : (
<FormattedMessage
id="common.ui.vis.defaultEditor.aggSelect.aggregationLabel"
id="visDefaultEditor.aggSelect.aggregationLabel"
defaultMessage="Aggregation"
/>
);
@ -76,7 +76,7 @@ function DefaultEditorAggSelect({
<EuiLink href={aggHelpLink} target="_blank" rel="noopener">
<EuiText size="xs">
<FormattedMessage
id="common.ui.vis.defaultEditor.aggSelect.helpLinkLabel"
id="visDefaultEditor.aggSelect.helpLinkLabel"
defaultMessage="{aggTitle} help"
values={{ aggTitle: value ? value.title : '' }}
/>
@ -88,7 +88,7 @@ function DefaultEditorAggSelect({
if (!aggTypeOptions.length) {
errors.push(
i18n.translate('common.ui.vis.defaultEditor.aggSelect.noCompatibleAggsDescription', {
i18n.translate('visDefaultEditor.aggSelect.noCompatibleAggsDescription', {
defaultMessage:
'The index pattern {indexPatternTitle} does not have any aggregatable fields.',
values: {
@ -121,13 +121,13 @@ function DefaultEditorAggSelect({
useEffect(() => {
setValidity(isValid);
}, [isValid]);
}, [isValid, setValidity]);
useEffect(() => {
if (errors.length) {
setTouched();
}
}, [errors.length]);
}, [errors.length, setTouched]);
return (
<EuiFormRow
@ -139,7 +139,7 @@ function DefaultEditorAggSelect({
compressed
>
<EuiComboBox
placeholder={i18n.translate('common.ui.vis.defaultEditor.aggSelect.selectAggPlaceholder', {
placeholder={i18n.translate('visDefaultEditor.aggSelect.selectAggPlaceholder', {
defaultMessage: 'Select an aggregation',
})}
id={`visDefaultEditorAggSelect${id}`}

View file

@ -13,7 +13,7 @@ exports[`SizeParamEditor should init with the default set of props 1`] = `
<React.Fragment>
<FormattedMessage
defaultMessage="Size"
id="common.ui.aggTypes.sizeLabel"
id="visDefaultEditor.controls.sizeLabel"
values={Object {}}
/>
</React.Fragment>

View file

@ -13,7 +13,7 @@ exports[`TopAggregateParamEditor should init with the default set of props 1`] =
<React.Fragment>
<FormattedMessage
defaultMessage="Aggregate with"
id="common.ui.aggTypes.aggregateWithLabel"
id="visDefaultEditor.controls.aggregateWithLabel"
values={Object {}}
/>

View file

@ -17,8 +17,9 @@
* under the License.
*/
import { AggConfig, VisParams } from 'ui/vis';
import { DefaultEditorAggCommonProps } from '../components/agg_common_props';
import { VisParams } from 'src/legacy/core_plugins/visualizations/public';
import { AggConfig } from '../../legacy_imports';
import { DefaultEditorAggCommonProps } from '../agg_common_props';
export interface AggControlProps {
agg: AggConfig;

View file

@ -20,14 +20,14 @@
import React, { FunctionComponent } from 'react';
import { mount, ReactWrapper } from 'enzyme';
import { AggConfig } from 'ui/agg_types';
import { AggConfig } from '../../legacy_imports';
import {
safeMakeLabel,
useAvailableOptions,
useFallbackMetric,
useValidation,
CUSTOM_METRIC,
} from './agg_utils';
} from './utils';
type Callback = () => void;

View file

@ -21,10 +21,10 @@ import React from 'react';
import { EuiSwitch, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
function AutoPrecisionParamEditor({ value = false, setValue }: AggParamEditorProps<boolean>) {
const label = i18n.translate('common.ui.aggTypes.changePrecisionLabel', {
const label = i18n.translate('visDefaultEditor.controls.changePrecisionLabel', {
defaultMessage: 'Change precision on map zoom',
});

View file

@ -20,7 +20,8 @@
import React from 'react';
import { EuiFieldText, EuiFlexItem, EuiIcon } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { Ipv4Address } from '../../../../../../../../plugins/kibana_utils/public';
import { Ipv4Address } from '../../../../../../../plugins/kibana_utils/public';
import { InputList, InputListConfig, InputModel, InputObject, InputItem } from './input_list';
const EMPTY_STRING = '';
@ -59,7 +60,7 @@ function FromToList({ showValidation, onBlur, ...rest }: FromToListProps) {
to: { value: item.to || EMPTY_STRING, model: item.to || EMPTY_STRING, isInvalid: false },
}),
getRemoveBtnAriaLabel: (item: FromToModel) =>
i18n.translate('common.ui.aggTypes.ipRanges.removeRangeAriaLabel', {
i18n.translate('visDefaultEditor.controls.ipRanges.removeRangeAriaLabel', {
defaultMessage: 'Remove the range of {from} to {to}',
values: { from: item.from.value || '*', to: item.to.value || '*' },
}),
@ -78,7 +79,7 @@ function FromToList({ showValidation, onBlur, ...rest }: FromToListProps) {
<>
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.ipRanges.ipRangeFromAriaLabel', {
aria-label={i18n.translate('visDefaultEditor.controls.ipRanges.ipRangeFromAriaLabel', {
defaultMessage: 'IP range from: {value}',
values: { value: item.from.value || '*' },
})}
@ -97,7 +98,7 @@ function FromToList({ showValidation, onBlur, ...rest }: FromToListProps) {
</EuiFlexItem>
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.ipRanges.ipRangeToAriaLabel', {
aria-label={i18n.translate('visDefaultEditor.controls.ipRanges.ipRangeToAriaLabel', {
defaultMessage: 'IP range to: {value}',
values: { value: item.to.value || '*' },
})}

View file

@ -197,7 +197,7 @@ function InputList({ config, list, onChange, setValidity }: InputListProps) {
<EuiFlexItem>
<EuiButtonEmpty iconType="plusInCircleFilled" onClick={onAdd} size="xs">
<FormattedMessage
id="common.ui.aggTypes.ipRanges.addRangeButtonLabel"
id="visDefaultEditor.controls.ipRanges.addRangeButtonLabel"
defaultMessage="Add range"
/>
</EuiButtonEmpty>

View file

@ -20,8 +20,9 @@
import React from 'react';
import { EuiFieldText, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { CidrMask } from '../../../../../agg_types/buckets/lib/cidr_mask';
import { InputList, InputListConfig, InputObject, InputModel, InputItem } from './input_list';
import { CidrMask } from '../../../legacy_imports';
const EMPTY_STRING = '';
@ -56,11 +57,11 @@ function MaskList({ showValidation, onBlur, ...rest }: MaskListProps) {
}),
getRemoveBtnAriaLabel: (item: MaskModel) =>
item.mask.value
? i18n.translate('common.ui.aggTypes.ipRanges.removeCidrMaskButtonAriaLabel', {
? i18n.translate('visDefaultEditor.controls.ipRanges.removeCidrMaskButtonAriaLabel', {
defaultMessage: 'Remove the CIDR mask value of {mask}',
values: { mask: item.mask.value },
})
: i18n.translate('common.ui.aggTypes.ipRanges.removeEmptyCidrMaskButtonAriaLabel', {
: i18n.translate('visDefaultEditor.controls.ipRanges.removeEmptyCidrMaskButtonAriaLabel', {
defaultMessage: 'Remove the CIDR mask default value',
}),
onChangeFn: ({ mask }: MaskModel) => {
@ -73,7 +74,7 @@ function MaskList({ showValidation, onBlur, ...rest }: MaskListProps) {
renderInputRow: ({ mask }: MaskModel, index, onChangeValue) => (
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.ipRanges.cidrMaskAriaLabel', {
aria-label={i18n.translate('visDefaultEditor.controls.ipRanges.cidrMaskAriaLabel', {
defaultMessage: 'CIDR mask: {mask}',
values: { mask: mask.value || '*' },
})}

View file

@ -64,7 +64,7 @@ exports[`NumberList should be rendered with default set of props 1`] = `
>
<FormattedMessage
defaultMessage="Add {unitName}"
id="common.ui.aggTypes.numberList.addUnitButtonLabel"
id="visDefaultEditor.controls.numberList.addUnitButtonLabel"
values={
Object {
"unitName": "value",

View file

@ -34,7 +34,7 @@ import {
getUpdatedModels,
hasInvalidValues,
} from './utils';
import { useValidation } from '../../agg_utils';
import { useValidation } from '../../utils';
export interface NumberListProps {
labelledbyId: string;
@ -72,7 +72,7 @@ function NumberList({
setAscendingError(
isValidOrder
? EMPTY_STRING
: i18n.translate('common.ui.aggTypes.numberList.invalidAscOrderErrorMessage', {
: i18n.translate('visDefaultEditor.controls.numberList.invalidAscOrderErrorMessage', {
defaultMessage: 'The values should be in ascending order.',
})
);
@ -160,7 +160,7 @@ function NumberList({
<EuiFlexItem>
<EuiButtonEmpty iconType="plusInCircleFilled" onClick={onAdd} size="xs">
<FormattedMessage
id="common.ui.aggTypes.numberList.addUnitButtonLabel"
id="visDefaultEditor.controls.numberList.addUnitButtonLabel"
defaultMessage="Add {unitName}"
values={{ unitName }}
/>

View file

@ -54,7 +54,7 @@ function NumberRow({
onChange,
}: NumberRowProps) {
const deleteBtnAriaLabel = i18n.translate(
'common.ui.aggTypes.numberList.removeUnitButtonAriaLabel',
'visDefaultEditor.controls.numberList.removeUnitButtonAriaLabel',
{
defaultMessage: 'Remove the rank value of {value}',
values: { value: model.value },
@ -80,9 +80,12 @@ function NumberRow({
autoFocus={autoFocus}
compressed={true}
isInvalid={isInvalid}
placeholder={i18n.translate('common.ui.aggTypes.numberList.enterValuePlaceholder', {
defaultMessage: 'Enter a value',
})}
placeholder={i18n.translate(
'visDefaultEditor.controls.numberList.enterValuePlaceholder',
{
defaultMessage: 'Enter a value',
}
)}
onChange={onValueChanged}
value={model.value}
fullWidth={true}

View file

@ -51,7 +51,7 @@ function validateValue(value: number | '', numberRange: NumberListRange) {
result.isInvalid = true;
} else if (!numberRange.within(value)) {
result.isInvalid = true;
result.error = i18n.translate('common.ui.aggTypes.numberList.invalidRangeErrorMessage', {
result.error = i18n.translate('visDefaultEditor.controls.numberList.invalidRangeErrorMessage', {
defaultMessage: 'The value should be in the range of {min} to {max}.',
values: { min: numberRange.min, max: numberRange.max },
});

View file

@ -21,7 +21,7 @@ import React from 'react';
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import { DateRangesParamEditor } from './date_ranges';
jest.mock('../../../../documentation_links', () => ({
jest.mock('../../legacy_imports', () => ({
getDocLink: jest.fn(),
}));

View file

@ -36,8 +36,9 @@ import dateMath from '@elastic/datemath';
import { FormattedMessage } from '@kbn/i18n/react';
import { i18n } from '@kbn/i18n';
import { isEqual, omit } from 'lodash';
import { getDocLink } from '../../../../documentation_links';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
import { getDocLink } from '../../legacy_imports';
const FROM_PLACEHOLDER = '\u2212\u221E';
const TO_PLACEHOLDER = '+\u221E';
@ -116,7 +117,7 @@ function DateRangesParamEditor({
<EuiText size="xs">
<EuiLink href={getDocLink('date.dateMath')} target="_blank">
<FormattedMessage
id="common.ui.aggTypes.dateRanges.acceptedDateFormatsLinkText"
id="visDefaultEditor.controls.dateRanges.acceptedDateFormatsLinkText"
defaultMessage="Acceptable date formats"
/>
</EuiLink>
@ -125,7 +126,7 @@ function DateRangesParamEditor({
{ranges.map(({ from, to, id }) => {
const deleteBtnTitle = i18n.translate(
'common.ui.aggTypes.dateRanges.removeRangeButtonAriaLabel',
'visDefaultEditor.controls.dateRanges.removeRangeButtonAriaLabel',
{
defaultMessage: 'Remove the range of {from} to {to}',
values: { from: from || FROM_PLACEHOLDER, to: to || TO_PLACEHOLDER },
@ -138,11 +139,14 @@ function DateRangesParamEditor({
<EuiFlexGroup responsive={false} gutterSize="s" alignItems="center">
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.dateRanges.fromColumnLabel', {
defaultMessage: 'From',
description:
'Beginning of a date range, e.g. *From* 2018-02-26 To 2018-02-28',
})}
aria-label={i18n.translate(
'visDefaultEditor.controls.dateRanges.fromColumnLabel',
{
defaultMessage: 'From',
description:
'Beginning of a date range, e.g. *From* 2018-02-26 To 2018-02-28',
}
)}
compressed
fullWidth={true}
isInvalid={areBothEmpty || !validateDateMath(from)}
@ -156,10 +160,13 @@ function DateRangesParamEditor({
</EuiFlexItem>
<EuiFlexItem>
<EuiFieldText
aria-label={i18n.translate('common.ui.aggTypes.dateRanges.toColumnLabel', {
defaultMessage: 'To',
description: 'End of a date range, e.g. From 2018-02-26 *To* 2018-02-28',
})}
aria-label={i18n.translate(
'visDefaultEditor.controls.dateRanges.toColumnLabel',
{
defaultMessage: 'To',
description: 'End of a date range, e.g. From 2018-02-26 *To* 2018-02-28',
}
)}
compressed
fullWidth={true}
isInvalid={areBothEmpty || !validateDateMath(to)}
@ -187,7 +194,7 @@ function DateRangesParamEditor({
{hasInvalidRange && (
<EuiFormErrorText>
<FormattedMessage
id="common.ui.aggTypes.dateRanges.errorMessage"
id="visDefaultEditor.controls.dateRanges.errorMessage"
defaultMessage="Each range should have at least one valid date."
/>
</EuiFormErrorText>
@ -197,7 +204,7 @@ function DateRangesParamEditor({
<EuiFlexItem>
<EuiButtonEmpty iconType="plusInCircleFilled" onClick={onAddRange} size="xs">
<FormattedMessage
id="common.ui.aggTypes.dateRanges.addRangeButtonLabel"
id="visDefaultEditor.controls.dateRanges.addRangeButtonLabel"
defaultMessage="Add range"
/>
</EuiButtonEmpty>

View file

@ -20,16 +20,16 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { SwitchParamEditor } from './switch';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
function DropPartialsParamEditor(props: AggParamEditorProps<boolean>) {
return (
<SwitchParamEditor
dataTestSubj="dropPartialBucketsCheckbox"
displayLabel={i18n.translate('common.ui.aggTypes.dropPartialBucketsLabel', {
displayLabel={i18n.translate('visDefaultEditor.controls.dropPartialBucketsLabel', {
defaultMessage: 'Drop partial buckets',
})}
displayToolTip={i18n.translate('common.ui.aggTypes.dropPartialBucketsTooltip', {
displayToolTip={i18n.translate('visDefaultEditor.controls.dropPartialBucketsTooltip', {
defaultMessage:
"Remove buckets that span time outside the time range so the histogram doesn't start and end with incomplete buckets.",
})}

View file

@ -21,7 +21,7 @@ import React from 'react';
import { mount, shallow } from 'enzyme';
import { ExtendedBoundsParamEditor, Bounds } from './extended_bounds';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
describe('ExtendedBoundsParamEditor', () => {
let defaultProps: Partial<AggParamEditorProps<Bounds>>;

View file

@ -22,8 +22,9 @@ import React, { ChangeEvent } from 'react';
import { EuiFieldNumber, EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { isUndefined } from 'lodash';
import { useValidation } from './agg_utils';
import { AggParamEditorProps } from '..';
import { useValidation } from './utils';
import { AggParamEditorProps } from '../agg_param_props';
export interface Bounds {
min: number | '';
@ -45,11 +46,11 @@ function ExtendedBoundsParamEditor({
showValidation,
setTouched,
}: AggParamEditorProps<Bounds>) {
const minLabel = i18n.translate('common.ui.aggTypes.extendedBounds.minLabel', {
const minLabel = i18n.translate('visDefaultEditor.controls.extendedBounds.minLabel', {
defaultMessage: 'Min',
});
const maxLabel = i18n.translate('common.ui.aggTypes.extendedBounds.maxLabel', {
const maxLabel = i18n.translate('visDefaultEditor.controls.extendedBounds.maxLabel', {
defaultMessage: 'Max',
});
@ -57,7 +58,7 @@ function ExtendedBoundsParamEditor({
let error;
if (!isValid) {
error = i18n.translate('common.ui.aggTypes.extendedBounds.errorMessage', {
error = i18n.translate('visDefaultEditor.controls.extendedBounds.errorMessage', {
defaultMessage: 'Min should be less than or equal to Max.',
});
}

View file

@ -21,10 +21,12 @@ import React from 'react';
import { act } from 'react-dom/test-utils';
import { mount, shallow, ReactWrapper } from 'enzyme';
import { EuiComboBoxProps, EuiComboBox } from '@elastic/eui';
import { Field } from '../../../../../../../plugins/data/public';
import { ComboBoxGroupedOptions } from '..';
import { Field } from 'src/plugins/data/public';
import { VisState } from 'src/legacy/core_plugins/visualizations/public';
import { ComboBoxGroupedOptions } from '../../utils';
import { FieldParamEditor, FieldParamEditorProps } from './field';
import { AggConfig, VisState } from '../../..';
import { AggConfig } from '../../legacy_imports';
function callComboBoxOnChange(comp: ReactWrapper, value: any = []) {
const comboBoxProps: EuiComboBoxProps<string> = comp.find(EuiComboBox).props();

View file

@ -22,14 +22,16 @@ import React, { useEffect } from 'react';
import { EuiComboBox, EuiComboBoxOptionProps, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../..';
import { Field } from '../../../../../../../plugins/data/public';
import { formatListAsProse, parseCommaSeparatedList } from '../../../../../../utils';
import { AggParam, FieldParamType } from '../../../../agg_types';
import { useValidation } from './agg_utils';
import { AggParamEditorProps, ComboBoxGroupedOptions } from '..';
const label = i18n.translate('common.ui.aggTypes.field.fieldLabel', { defaultMessage: 'Field' });
import { Field } from 'src/plugins/data/public';
import { AggConfig, AggParam, FieldParamType } from '../../legacy_imports';
import { formatListAsProse, parseCommaSeparatedList, useValidation } from './utils';
import { AggParamEditorProps } from '../agg_param_props';
import { ComboBoxGroupedOptions } from '../../utils';
const label = i18n.translate('visDefaultEditor.controls.field.fieldLabel', {
defaultMessage: 'Field',
});
export interface FieldParamEditorProps extends AggParamEditorProps<Field> {
customError?: string;
@ -66,7 +68,7 @@ function FieldParamEditor({
if (!indexedFields.length) {
errors.push(
i18n.translate('common.ui.aggTypes.field.noCompatibleFieldsDescription', {
i18n.translate('visDefaultEditor.controls.field.noCompatibleFieldsDescription', {
defaultMessage:
'The index pattern {indexPatternTitle} does not contain any of the following compatible field types: {fieldTypes}',
values: {
@ -106,7 +108,7 @@ function FieldParamEditor({
>
<EuiComboBox
compressed
placeholder={i18n.translate('common.ui.aggTypes.field.selectFieldPlaceholder', {
placeholder={i18n.translate('visDefaultEditor.controls.field.selectFieldPlaceholder', {
defaultMessage: 'Select a field',
})}
options={indexedFields}

View file

@ -20,12 +20,9 @@
import React, { useState } from 'react';
import { EuiForm, EuiButtonIcon, EuiFieldText, EuiFormRow, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggConfig } from '../../..';
import { npStart } from '../../../../new_platform';
import { Query, QueryStringInput } from '../../../../../../../plugins/data/public';
import { Storage } from '../../../../../../../plugins/kibana_utils/public';
import { KibanaContextProvider } from '../../../../../../../plugins/kibana_react/public';
const localStorage = new Storage(window.localStorage);
import { Query, QueryStringInput } from '../../../../../../plugins/data/public';
import { AggConfig } from '../../legacy_imports';
interface FilterRowProps {
id: string;
@ -53,7 +50,7 @@ function FilterRow({
onRemoveFilter,
}: FilterRowProps) {
const [showCustomLabel, setShowCustomLabel] = useState(false);
const filterLabel = i18n.translate('common.ui.aggTypes.filters.filterLabel', {
const filterLabel = i18n.translate('visDefaultEditor.controls.filters.filterLabel', {
defaultMessage: 'Filter {index}',
values: {
index: arrayIndex + 1,
@ -64,9 +61,12 @@ function FilterRow({
<div>
<EuiButtonIcon
iconType="tag"
aria-label={i18n.translate('common.ui.aggTypes.filters.toggleFilterButtonAriaLabel', {
defaultMessage: 'Toggle filter label',
})}
aria-label={i18n.translate(
'visDefaultEditor.controls.filters.toggleFilterButtonAriaLabel',
{
defaultMessage: 'Toggle filter label',
}
)}
aria-expanded={showCustomLabel}
aria-controls={`visEditorFilterLabel${arrayIndex}`}
onClick={() => setShowCustomLabel(!showCustomLabel)}
@ -75,15 +75,17 @@ function FilterRow({
iconType="trash"
color="danger"
disabled={disableRemove}
aria-label={i18n.translate('common.ui.aggTypes.filters.removeFilterButtonAriaLabel', {
defaultMessage: 'Remove this filter',
})}
aria-label={i18n.translate(
'visDefaultEditor.controls.filters.removeFilterButtonAriaLabel',
{
defaultMessage: 'Remove this filter',
}
)}
onClick={() => onRemoveFilter(id)}
/>
</div>
);
// TODO: KibanaContextProvider should be raised to the top of the vis plugin
return (
<EuiForm>
<EuiFormRow
@ -91,29 +93,20 @@ function FilterRow({
labelAppend={FilterControl}
fullWidth={true}
>
<KibanaContextProvider
services={{
appName: 'filtersAgg',
storage: localStorage,
data: npStart.plugins.data,
...npStart.core,
}}
>
<QueryStringInput
query={value}
indexPatterns={[agg.getIndexPattern()]}
onChange={(query: Query) => onChangeValue(id, query, customLabel)}
disableAutoFocus={!autoFocus}
dataTestSubj={dataTestSubj}
bubbleSubmitEvent={true}
languageSwitcherPopoverAnchorPosition="leftDown"
/>
</KibanaContextProvider>
<QueryStringInput
query={value}
indexPatterns={[agg.getIndexPattern()]}
onChange={(query: Query) => onChangeValue(id, query, customLabel)}
disableAutoFocus={!autoFocus}
dataTestSubj={dataTestSubj}
bubbleSubmitEvent={true}
languageSwitcherPopoverAnchorPosition="leftDown"
/>
</EuiFormRow>
{showCustomLabel ? (
<EuiFormRow
id={`visEditorFilterLabel${arrayIndex}`}
label={i18n.translate('common.ui.aggTypes.filters.definiteFilterLabel', {
label={i18n.translate('visDefaultEditor.controls.filters.definiteFilterLabel', {
defaultMessage: 'Filter {index} label',
description:
"'Filter {index}' represents the name of the filter as a noun, similar to 'label for filter 1'.",
@ -126,7 +119,7 @@ function FilterRow({
>
<EuiFieldText
value={customLabel}
placeholder={i18n.translate('common.ui.aggTypes.filters.labelPlaceholder', {
placeholder={i18n.translate('visDefaultEditor.controls.filters.labelPlaceholder', {
defaultMessage: 'Label',
})}
onChange={ev => onChangeValue(id, value, ev.target.value)}

View file

@ -21,15 +21,15 @@ import React, { useState, useEffect } from 'react';
import { omit, isEqual } from 'lodash';
import { htmlIdGenerator, EuiButton, EuiSpacer } from '@elastic/eui';
import { FormattedMessage } from '@kbn/i18n/react';
import { Query } from 'src/plugins/data/public';
import chrome from '../../../../chrome';
import { useKibana } from '../../../../../../plugins/kibana_react/public';
import { FilterRow } from './filter';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
const generateId = htmlIdGenerator();
const config = chrome.getUiSettingsClient();
export interface FilterValue {
interface FilterValue {
input: Query;
label: string;
id: string;
@ -61,11 +61,13 @@ function FiltersParamEditor({ agg, value = [], setValue }: AggParamEditorProps<F
setFilters(updatedFilters);
};
const { services } = useKibana();
const onAddFilter = () =>
updateFilters([
...filters,
{
input: { query: '', language: config.get('search:queryLanguage') },
input: { query: '', language: services.uiSettings.get('search:queryLanguage') },
label: '',
id: generateId(),
},
@ -111,7 +113,7 @@ function FiltersParamEditor({ agg, value = [], setValue }: AggParamEditorProps<F
data-test-subj="visEditorAddFilterButton"
>
<FormattedMessage
id="common.ui.aggTypes.filters.addFilterButtonLabel"
id="visDefaultEditor.controls.filters.addFilterButtonLabel"
defaultMessage="Add filter"
/>
</EuiButton>

View file

@ -19,9 +19,10 @@
import React, { useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { SwitchParamEditor } from './switch';
import { isType } from '../../../../agg_types/buckets/migrate_include_exclude_format';
import { AggParamEditorProps } from '..';
import { isType } from '../../legacy_imports';
import { AggParamEditorProps } from '../agg_param_props';
function HasExtendedBoundsParamEditor(props: AggParamEditorProps<boolean>) {
useEffect(() => {
@ -30,10 +31,10 @@ function HasExtendedBoundsParamEditor(props: AggParamEditorProps<boolean>) {
return (
<SwitchParamEditor
displayLabel={i18n.translate('common.ui.aggTypes.extendedBoundsLabel', {
displayLabel={i18n.translate('visDefaultEditor.controls.extendedBoundsLabel', {
defaultMessage: 'Extend bounds',
})}
displayToolTip={i18n.translate('common.ui.aggTypes.extendedBoundsTooltip', {
displayToolTip={i18n.translate('visDefaultEditor.controls.extendedBoundsTooltip', {
defaultMessage:
'Min and Max do not filter the results, but rather extend the bounds of the result set.',
})}

View file

@ -0,0 +1,53 @@
/*
* 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.
*/
export { AutoPrecisionParamEditor } from './auto_precision';
export { DateRangesParamEditor } from './date_ranges';
export { DropPartialsParamEditor } from './drop_partials';
export { ExtendedBoundsParamEditor } from './extended_bounds';
export { FieldParamEditor } from './field';
export { FiltersParamEditor } from './filters';
export { HasExtendedBoundsParamEditor } from './has_extended_bounds';
export { IpRangesParamEditor } from './ip_ranges';
export { IpRangeTypeParamEditor } from './ip_range_type';
export { IsFilteredByCollarParamEditor } from './is_filtered_by_collar';
export { MetricAggParamEditor } from './metric_agg';
export { MinDocCountParamEditor } from './min_doc_count';
export { MissingBucketParamEditor } from './missing_bucket';
export { NumberIntervalParamEditor } from './number_interval';
export { OrderByParamEditor } from './order_by';
export { OtherBucketParamEditor } from './other_bucket';
export { OrderAggParamEditor } from './order_agg';
export { PercentilesEditor } from './percentiles';
export { PercentileRanksEditor } from './percentile_ranks';
export { PrecisionParamEditor } from './precision';
export { RangesControl } from './range_control';
export { RawJsonParamEditor } from './raw_json';
export { ScaleMetricsParamEditor } from './scale_metrics';
export { SizeParamEditor } from './size';
export { StringParamEditor } from './string';
export { SubAggParamEditor } from './sub_agg';
export { SubMetricParamEditor } from './sub_metric';
export { TimeIntervalParamEditor } from './time_interval';
export { TopAggregateParamEditor } from './top_aggregate';
export { TopFieldParamEditor } from './top_field';
export { TopSizeParamEditor } from './top_size';
export { TopSortFieldParamEditor } from './top_sort_field';
export { OrderParamEditor } from './order';
export { UseGeocentroidParamEditor } from './use_geocentroid';

View file

@ -21,7 +21,8 @@ import React from 'react';
import { EuiButtonGroup, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
enum IpRangeTypes {
MASK = 'mask',
@ -32,13 +33,13 @@ function IpRangeTypeParamEditor({ agg, value, setValue }: AggParamEditorProps<Ip
const options = [
{
id: `visEditorIpRangeFromToLabel${agg.id}`,
label: i18n.translate('common.ui.aggTypes.ipRanges.fromToButtonLabel', {
label: i18n.translate('visDefaultEditor.controls.ipRanges.fromToButtonLabel', {
defaultMessage: 'From/to',
}),
},
{
id: `visEditorIpRangeCidrLabel${agg.id}`,
label: i18n.translate('common.ui.aggTypes.ipRanges.cidrMasksButtonLabel', {
label: i18n.translate('visDefaultEditor.controls.ipRanges.cidrMasksButtonLabel', {
defaultMessage: 'CIDR masks',
}),
},
@ -56,7 +57,7 @@ function IpRangeTypeParamEditor({ agg, value, setValue }: AggParamEditorProps<Ip
onChange={onClick}
idSelected={value === IpRangeTypes.FROM_TO ? options[0].id : options[1].id}
options={options}
legend={i18n.translate('common.ui.aggTypes.ipRangesAriaLabel', {
legend={i18n.translate('visDefaultEditor.controls.ipRangesAriaLabel', {
defaultMessage: 'IP ranges',
})}
/>

View file

@ -23,7 +23,8 @@ import { EuiFormRow } from '@elastic/eui';
import { FromToList, FromToObject } from './components/from_to_list';
import { MaskList, MaskObject } from './components/mask_list';
import { IpRangeTypes } from './ip_range_type';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
interface IpRange {
fromTo: FromToObject[];
mask: MaskObject[];

View file

@ -20,18 +20,24 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { SwitchParamEditor } from './switch';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
function IsFilteredByCollarParamEditor(props: AggParamEditorProps<boolean>) {
return (
<SwitchParamEditor
displayLabel={i18n.translate('common.ui.aggTypes.onlyRequestDataAroundMapExtentLabel', {
defaultMessage: 'Only request data around map extent',
})}
displayToolTip={i18n.translate('common.ui.aggTypes.onlyRequestDataAroundMapExtentTooltip', {
defaultMessage:
'Apply geo_bounding_box filter aggregation to narrow the subject area to the map view box with collar',
})}
displayLabel={i18n.translate(
'visDefaultEditor.controls.onlyRequestDataAroundMapExtentLabel',
{
defaultMessage: 'Only request data around map extent',
}
)}
displayToolTip={i18n.translate(
'visDefaultEditor.controls.onlyRequestDataAroundMapExtentTooltip',
{
defaultMessage:
'Apply geo_bounding_box filter aggregation to narrow the subject area to the map view box with collar',
}
)}
dataTestSubj="isFilteredByCollarCheckbox"
{...props}
/>

View file

@ -20,11 +20,10 @@
import React from 'react';
import { mount, shallow } from 'enzyme';
import { AggConfig } from 'ui/agg_types';
import { AggConfig } from '../../legacy_imports';
import { DEFAULT_OPTIONS, aggFilter, MetricAggParamEditor } from './metric_agg';
import { AggParamEditorProps } from '..';
jest.mock('./agg_utils', () => ({
jest.mock('./utils', () => ({
useAvailableOptions: jest.fn((aggFilterArray, filteredMetrics, defaultOptions) => [
...filteredMetrics.map(({ id, type }: { id: string; type: { name: string } }) => ({
text: type.name,
@ -36,7 +35,8 @@ jest.mock('./agg_utils', () => ({
useValidation: jest.fn(),
}));
import { useAvailableOptions, useFallbackMetric, useValidation } from './agg_utils';
import { useAvailableOptions, useFallbackMetric, useValidation } from './utils';
import { AggParamEditorProps } from '../agg_param_props';
const agg = {
id: '1',

View file

@ -20,8 +20,9 @@
import React, { useMemo, useCallback } from 'react';
import { EuiFormRow, EuiSelect } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { useAvailableOptions, useFallbackMetric, useValidation } from './agg_utils';
import { AggParamEditorProps } from '..';
import { useAvailableOptions, useFallbackMetric, useValidation } from './utils';
import { AggParamEditorProps } from '../agg_param_props';
const aggFilter = ['!top_hits', '!percentiles', '!percentile_ranks', '!median', '!std_dev'];
const EMPTY_VALUE = 'EMPTY_VALUE';
@ -36,7 +37,7 @@ function MetricAggParamEditor({
setTouched,
metricAggs = [],
}: AggParamEditorProps<string>) {
const label = i18n.translate('common.ui.aggTypes.metricLabel', {
const label = i18n.translate('visDefaultEditor.controls.metricLabel', {
defaultMessage: 'Metric',
});
const isValid = !!value;

View file

@ -21,15 +21,15 @@ import React from 'react';
import { i18n } from '@kbn/i18n';
import { SwitchParamEditor } from './switch';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
function MinDocCountParamEditor(props: AggParamEditorProps<boolean>) {
return (
<SwitchParamEditor
displayLabel={i18n.translate('common.ui.aggTypes.showEmptyBucketsLabel', {
displayLabel={i18n.translate('visDefaultEditor.controls.showEmptyBucketsLabel', {
defaultMessage: 'Show empty buckets',
})}
displayToolTip={i18n.translate('common.ui.aggTypes.showEmptyBucketsTooltip', {
displayToolTip={i18n.translate('visDefaultEditor.controls.showEmptyBucketsTooltip', {
defaultMessage: 'Show all buckets, not only the buckets with results',
})}
{...props}

View file

@ -20,8 +20,9 @@
import React, { useEffect } from 'react';
import { i18n } from '@kbn/i18n';
import { SwitchParamEditor } from './switch';
import { isStringType } from '../../../../agg_types/buckets/migrate_include_exclude_format';
import { AggParamEditorProps } from '..';
import { isStringType } from '../../legacy_imports';
import { AggParamEditorProps } from '../agg_param_props';
function MissingBucketParamEditor(props: AggParamEditorProps<boolean>) {
const fieldTypeIsNotString = !isStringType(props.agg);
@ -35,16 +36,19 @@ function MissingBucketParamEditor(props: AggParamEditorProps<boolean>) {
return (
<SwitchParamEditor
dataTestSubj="missingBucketSwitch"
displayLabel={i18n.translate('common.ui.aggTypes.otherBucket.showMissingValuesLabel', {
displayLabel={i18n.translate('visDefaultEditor.controls.otherBucket.showMissingValuesLabel', {
defaultMessage: 'Show missing values',
})}
displayToolTip={i18n.translate('common.ui.aggTypes.otherBucket.showMissingValuesTooltip', {
defaultMessage:
'Only works for fields of type "string". When enabled, include documents with missing ' +
'values in the search. If this bucket is in the top N, it appears in the chart. ' +
'If not in the top N, and you enable "Group other values in separate bucket", ' +
'Elasticsearch adds the missing values to the "other" bucket.',
})}
displayToolTip={i18n.translate(
'visDefaultEditor.controls.otherBucket.showMissingValuesTooltip',
{
defaultMessage:
'Only works for fields of type "string". When enabled, include documents with missing ' +
'values in the search. If this bucket is in the top N, it appears in the chart. ' +
'If not in the top N, and you enable "Group other values in separate bucket", ' +
'Elasticsearch adds the missing values to the "other" bucket.',
}
)}
disabled={fieldTypeIsNotString}
{...props}
/>

View file

@ -23,19 +23,20 @@ import React, { useEffect, useCallback } from 'react';
import { EuiFieldNumber, EuiFormRow, EuiIconTip } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
const label = (
<>
<FormattedMessage
id="common.ui.aggTypes.numberInterval.minimumIntervalLabel"
id="visDefaultEditor.controls.numberInterval.minimumIntervalLabel"
defaultMessage="Minimum interval"
/>{' '}
<EuiIconTip
position="right"
content={
<FormattedMessage
id="common.ui.aggTypes.numberInterval.minimumIntervalTooltip"
id="visDefaultEditor.controls.numberInterval.minimumIntervalTooltip"
defaultMessage="Interval will be automatically scaled in the event that the provided value creates more buckets than specified by Advanced Setting's {histogramMaxBars}"
values={{ histogramMaxBars: 'histogram:maxBars' }}
/>
@ -86,9 +87,12 @@ function NumberIntervalParamEditor({
onBlur={setTouched}
fullWidth={true}
compressed
placeholder={i18n.translate('common.ui.aggTypes.numberInterval.selectIntervalPlaceholder', {
defaultMessage: 'Enter an interval',
})}
placeholder={i18n.translate(
'visDefaultEditor.controls.numberInterval.selectIntervalPlaceholder',
{
defaultMessage: 'Enter an interval',
}
)}
/>
</EuiFormRow>
);

View file

@ -20,11 +20,9 @@
import React, { useEffect } from 'react';
import { EuiFormRow, EuiSelect } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import {
OptionedValueProp,
OptionedParamEditorProps,
} from '../../../../agg_types/param_types/optioned';
import { AggParamEditorProps } from '..';
import { OptionedValueProp, OptionedParamEditorProps } from '../../legacy_imports';
import { AggParamEditorProps } from '../agg_param_props';
function OrderParamEditor({
aggParam,
@ -34,7 +32,7 @@ function OrderParamEditor({
setValidity,
setTouched,
}: AggParamEditorProps<OptionedValueProp> & OptionedParamEditorProps) {
const label = i18n.translate('common.ui.aggTypes.orderLabel', {
const label = i18n.translate('visDefaultEditor.controls.orderLabel', {
defaultMessage: 'Order',
});
const isValid = !!value;

View file

@ -21,6 +21,8 @@ import React from 'react';
import { mount } from 'enzyme';
import { OrderByParamEditor } from './order_by';
jest.mock('ui/new_platform');
describe('OrderAggParamEditor component', () => {
let setValue: jest.Mock;
let setValidity: jest.Mock;

View file

@ -19,11 +19,11 @@
import React, { useEffect } from 'react';
import { EuiSpacer } from '@elastic/eui';
import { AggParamType } from '../../../../agg_types/param_types/agg';
import { AggConfig } from '../../..';
import { AggParamType, AggConfig, AggGroupNames } from '../../legacy_imports';
import { useSubAggParamsHandlers } from './utils';
import { AggGroupNames } from '../agg_groups';
import { AggParamEditorProps, DefaultEditorAggParams } from '..';
import { AggParamEditorProps } from '../agg_param_props';
import { DefaultEditorAggParams } from '../agg_params';
function OrderAggParamEditor({
agg,

View file

@ -20,38 +20,27 @@
import React, { useEffect } from 'react';
import { EuiFormRow, EuiSelect } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import {
isCompatibleAggregation,
useAvailableOptions,
useFallbackMetric,
useValidation,
} from './agg_utils';
import { AggParamEditorProps } from '..';
} from './utils';
import { AggParamEditorProps } from '../agg_param_props';
import { termsAggFilter } from '../../legacy_imports';
const DEFAULT_VALUE = '_key';
const DEFAULT_OPTIONS = [
{
text: i18n.translate('common.ui.aggTypes.orderAgg.alphabeticalLabel', {
text: i18n.translate('visDefaultEditor.controls.orderAgg.alphabeticalLabel', {
defaultMessage: 'Alphabetical',
}),
value: DEFAULT_VALUE,
},
];
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);
const isCompatibleAgg = isCompatibleAggregation(termsAggFilter);
function OrderByParamEditor({
agg,
@ -62,7 +51,7 @@ function OrderByParamEditor({
setTouched,
metricAggs,
}: AggParamEditorProps<string>) {
const label = i18n.translate('common.ui.aggTypes.orderAgg.orderByLabel', {
const label = i18n.translate('visDefaultEditor.controls.orderAgg.orderByLabel', {
defaultMessage: 'Order by',
});
const isValid = !!value;
@ -82,9 +71,9 @@ function OrderByParamEditor({
}
}, []);
useFallbackMetric(setValue, aggFilter, metricAggs, value, DEFAULT_VALUE);
useFallbackMetric(setValue, termsAggFilter, metricAggs, value, DEFAULT_VALUE);
const options = useAvailableOptions(aggFilter, metricAggs, DEFAULT_OPTIONS);
const options = useAvailableOptions(termsAggFilter, metricAggs, DEFAULT_OPTIONS);
return (
<EuiFormRow label={label} fullWidth isInvalid={showValidation && !isValid} compressed>
@ -102,4 +91,4 @@ function OrderByParamEditor({
);
}
export { OrderByParamEditor, aggFilter };
export { OrderByParamEditor };

View file

@ -19,17 +19,18 @@
import React from 'react';
import { i18n } from '@kbn/i18n';
import { SwitchParamEditor } from './switch';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
function OtherBucketParamEditor(props: AggParamEditorProps<boolean>) {
return (
<SwitchParamEditor
dataTestSubj="otherBucketSwitch"
displayLabel={i18n.translate('common.ui.aggTypes.otherBucket.groupValuesLabel', {
displayLabel={i18n.translate('visDefaultEditor.controls.otherBucket.groupValuesLabel', {
defaultMessage: 'Group other values in separate bucket',
})}
displayToolTip={i18n.translate('common.ui.aggTypes.otherBucket.groupValuesTooltip', {
displayToolTip={i18n.translate('visDefaultEditor.controls.otherBucket.groupValuesTooltip', {
defaultMessage:
'Values not in the top N are grouped in this bucket. ' +
"To include documents with missing values, enable 'Show missing values'.",

View file

@ -17,12 +17,12 @@
* under the License.
*/
import React, { useState } from 'react';
import React, { useState, useCallback } from 'react';
import { EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { NumberList } from './components/number_list';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
function PercentileRanksEditor({
agg,
@ -32,15 +32,18 @@ function PercentileRanksEditor({
setValidity,
setValue,
}: AggParamEditorProps<Array<number | undefined>>) {
const label = i18n.translate('common.ui.aggTypes.percentileRanks.valuesLabel', {
const label = i18n.translate('visDefaultEditor.controls.percentileRanks.valuesLabel', {
defaultMessage: 'Values',
});
const [isValid, setIsValid] = useState(true);
const setModelValidity = (isListValid: boolean) => {
setIsValid(isListValid);
setValidity(isListValid);
};
const setModelValidity = useCallback(
(isListValid: boolean) => {
setIsValid(isListValid);
setValidity(isListValid);
},
[setValidity]
);
return (
<EuiFormRow
@ -56,7 +59,7 @@ function PercentileRanksEditor({
labelledbyId={`visEditorPercentileRanksLabel${agg.id}-legend`}
numberArray={value}
range="[-Infinity,Infinity]"
unitName={i18n.translate('common.ui.aggTypes.percentileRanks.valueUnitNameText', {
unitName={i18n.translate('visDefaultEditor.controls.percentileRanks.valueUnitNameText', {
defaultMessage: 'value',
})}
showValidation={showValidation}

View file

@ -17,12 +17,12 @@
* under the License.
*/
import React, { useState } from 'react';
import React, { useState, useCallback } from 'react';
import { EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { NumberList } from './components/number_list';
import { AggParamEditorProps } from '..';
import { AggParamEditorProps } from '../agg_param_props';
function PercentilesEditor({
agg,
@ -32,15 +32,18 @@ function PercentilesEditor({
setValidity,
setValue,
}: AggParamEditorProps<Array<number | undefined>>) {
const label = i18n.translate('common.ui.aggTypes.percentiles.percentsLabel', {
const label = i18n.translate('visDefaultEditor.controls.percentiles.percentsLabel', {
defaultMessage: 'Percents',
});
const [isValid, setIsValid] = useState(true);
const setModelValidity = (isListValid: boolean) => {
setIsValid(isListValid);
setValidity(isListValid);
};
const setModelValidity = useCallback(
(isListValid: boolean) => {
setIsValid(isListValid);
setValidity(isListValid);
},
[setValidity]
);
return (
<EuiFormRow
@ -56,7 +59,7 @@ function PercentilesEditor({
numberArray={value}
range="[0,100]"
validateAscendingOrder={false}
unitName={i18n.translate('common.ui.aggTypes.percentileRanks.percentUnitNameText', {
unitName={i18n.translate('visDefaultEditor.controls.percentileRanks.percentUnitNameText', {
defaultMessage: 'percent',
})}
showValidation={showValidation}

View file

@ -21,25 +21,25 @@ import React from 'react';
import { EuiRange, EuiFormRow } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import chrome from '../../../../chrome';
import { AggParamEditorProps } from '..';
const config = chrome.getUiSettingsClient();
import { useKibana } from '../../../../../../plugins/kibana_react/public';
import { AggParamEditorProps } from '../agg_param_props';
function PrecisionParamEditor({ agg, value, setValue }: AggParamEditorProps<number>) {
const { services } = useKibana();
const label = i18n.translate('visDefaultEditor.controls.precisionLabel', {
defaultMessage: 'Precision',
});
if (agg.params.autoPrecision) {
return null;
}
const label = i18n.translate('common.ui.aggTypes.precisionLabel', {
defaultMessage: 'Precision',
});
return (
<EuiFormRow label={label} compressed>
<EuiRange
min={1}
max={config.get('visualization:tileMap:maxPrecision')}
max={services.uiSettings.get('visualization:tileMap:maxPrecision')}
value={value || ''}
onChange={(ev: React.ChangeEvent<HTMLInputElement> | React.MouseEvent<HTMLButtonElement>) =>
setValue(Number(ev.currentTarget.value))

View file

@ -21,6 +21,7 @@ import React, { useEffect, useCallback } from 'react';
import { EuiFormRow, EuiIconTip, EuiRange, EuiSpacer } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { AggControlProps } from './agg_control_props';
const DEFAULT_VALUE = 50;
@ -30,11 +31,11 @@ function RadiusRatioOptionControl({ editorStateParams, setStateParamValue }: Agg
const label = (
<>
<FormattedMessage
id="common.ui.vis.defaultEditor.controls.dotSizeRatioLabel"
id="visDefaultEditor.controls.dotSizeRatioLabel"
defaultMessage="Dot size ratio"
/>{' '}
<EuiIconTip
content={i18n.translate('common.ui.vis.defaultEditor.controls.dotSizeRatioHelpText', {
content={i18n.translate('visDefaultEditor.controls.dotSizeRatioHelpText', {
defaultMessage:
'Change the ratio of the radius of the smallest point to the largest point.',
})}

View file

@ -18,9 +18,10 @@
*/
import React from 'react';
import { AggParamEditorProps } from 'ui/vis/editors/default';
import { RangesParamEditor } from '../../vis/editors/default/controls/ranges';
export const RangesEditor = (props: AggParamEditorProps<any>) => (
import { AggParamEditorProps } from '../agg_param_props';
import { RangesParamEditor } from './ranges';
export const RangesControl = (props: AggParamEditorProps<any>) => (
<RangesParamEditor value={props.value} setValue={props.setValue} />
);

View file

@ -139,7 +139,7 @@ function RangesParamEditor({
<>
{ranges.map(({ from, to, id }, index) => {
const deleteBtnTitle = i18n.translate(
'common.ui.aggTypes.ranges.removeRangeButtonAriaLabel',
'visDefaultEditor.controls.ranges.removeRangeButtonAriaLabel',
{
defaultMessage: 'Remove the range of {from} to {to}',
values: {
@ -157,30 +157,36 @@ function RangesParamEditor({
}
const gtePrependLabel = i18n.translate(
'common.ui.aggTypes.ranges.greaterThanOrEqualPrepend',
'visDefaultEditor.controls.ranges.greaterThanOrEqualPrepend',
{
defaultMessage: '\u2265',
}
);
const gteTooltipContent = i18n.translate(
'common.ui.aggTypes.ranges.greaterThanOrEqualTooltip',
'visDefaultEditor.controls.ranges.greaterThanOrEqualTooltip',
{
defaultMessage: 'Greater than or equal to',
}
);
const ltPrependLabel = i18n.translate('common.ui.aggTypes.ranges.lessThanPrepend', {
defaultMessage: '\u003c',
});
const ltTooltipContent = i18n.translate('common.ui.aggTypes.ranges.lessThanTooltip', {
defaultMessage: 'Less than',
});
const ltPrependLabel = i18n.translate(
'visDefaultEditor.controls.ranges.lessThanPrepend',
{
defaultMessage: '\u003c',
}
);
const ltTooltipContent = i18n.translate(
'visDefaultEditor.controls.ranges.lessThanTooltip',
{
defaultMessage: 'Less than',
}
);
return (
<Fragment key={id}>
<EuiFlexGroup gutterSize="s" alignItems="center" responsive={false}>
<EuiFlexItem>
<EuiFieldNumber
aria-label={i18n.translate('common.ui.aggTypes.ranges.fromLabel', {
aria-label={i18n.translate('visDefaultEditor.controls.ranges.fromLabel', {
defaultMessage: 'From',
})}
data-test-subj={`${dataTestSubj}${index}__from`}
@ -202,7 +208,7 @@ function RangesParamEditor({
</EuiFlexItem>
<EuiFlexItem>
<EuiFieldNumber
aria-label={i18n.translate('common.ui.aggTypes.ranges.toLabel', {
aria-label={i18n.translate('visDefaultEditor.controls.ranges.toLabel', {
defaultMessage: 'To',
})}
data-test-subj={`${dataTestSubj}${index}__to`}
@ -246,7 +252,7 @@ function RangesParamEditor({
size="xs"
>
<FormattedMessage
id="common.ui.aggTypes.ranges.addRangeButtonLabel"
id="visDefaultEditor.controls.ranges.addRangeButtonLabel"
defaultMessage="Add range"
/>
</EuiButtonEmpty>

View file

@ -22,8 +22,9 @@ import React, { useEffect } from 'react';
import { EuiFormRow, EuiIconTip, EuiTextArea } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { isValidJson } from '../../../../agg_types/utils';
import { AggParamEditorProps } from '..';
import { isValidJson } from '../../legacy_imports';
import { AggParamEditorProps } from '../agg_param_props';
function RawJsonParamEditor({
agg,
@ -35,10 +36,10 @@ function RawJsonParamEditor({
}: AggParamEditorProps<string>) {
const label = (
<>
<FormattedMessage id="common.ui.aggTypes.jsonInputLabel" defaultMessage="JSON input" />{' '}
<FormattedMessage id="visDefaultEditor.controls.jsonInputLabel" defaultMessage="JSON input" />{' '}
<EuiIconTip
position="right"
content={i18n.translate('common.ui.aggTypes.jsonInputTooltip', {
content={i18n.translate('visDefaultEditor.controls.jsonInputTooltip', {
defaultMessage:
"Any JSON formatted properties you add here will be merged with the elasticsearch aggregation definition for this section. For example 'shard_size' on a terms aggregation.",
})}

View file

@ -33,13 +33,13 @@ function RowsOrColumnsControl({ agg, setAggParamValue }: AggControlProps) {
const options = [
{
id: PARAMS.ROWS,
label: i18n.translate('common.ui.vis.defaultEditor.controls.rowsLabel', {
label: i18n.translate('visDefaultEditor.controls.rowsLabel', {
defaultMessage: 'Rows',
}),
},
{
id: PARAMS.COLUMNS,
label: i18n.translate('common.ui.vis.defaultEditor.controls.columnsLabel', {
label: i18n.translate('visDefaultEditor.controls.columnsLabel', {
defaultMessage: 'Columns',
}),
},
@ -54,7 +54,7 @@ function RowsOrColumnsControl({ agg, setAggParamValue }: AggControlProps) {
<EuiFormRow compressed fullWidth={true}>
<EuiButtonGroup
data-test-subj="visEditorSplitBy"
legend={i18n.translate('common.ui.vis.defaultEditor.controls.splitByLegend', {
legend={i18n.translate('visDefaultEditor.controls.splitByLegend', {
defaultMessage: 'Split chart by rows or columns.',
})}
options={options}

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