Skip to content

Commit

Permalink
[Maps] convert MetricsEditor to TS (#76727)
Browse files Browse the repository at this point in the history
* [Maps] convert MetricsEditor to TS

* fix jest test

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
  • Loading branch information
nreese and elasticmachine committed Sep 9, 2020
1 parent 1f73e02 commit 0e7125f
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 97 deletions.
2 changes: 1 addition & 1 deletion x-pack/plugins/maps/public/components/_index.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
@import 'action_select';
@import 'metric_editors';
@import 'metrics_editor/metric_editors';
@import './geometry_filter';
@import 'tooltip_selector/tooltip_selector';

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions x-pack/plugins/maps/public/components/metrics_editor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License;
* you may not use this file except in compliance with the Elastic License.
*/

export { MetricsEditor } from './metrics_editor';
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
* you may not use this file except in compliance with the Elastic License.
*/

import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import React, { ChangeEvent, Fragment } from 'react';
import { i18n } from '@kbn/i18n';

import { EuiFieldText, EuiFormRow } from '@elastic/eui';
import { EuiButtonEmpty, EuiComboBoxOptionOption, EuiFieldText, EuiFormRow } from '@elastic/eui';

import { MetricSelect, METRIC_AGGREGATION_VALUES } from './metric_select';
import { SingleFieldSelect } from './single_field_select';
import { AGG_TYPE } from '../../common/constants';
import { getTermsFields } from '../index_pattern_util';
import { FormattedMessage } from '@kbn/i18n/react';
import { MetricSelect } from './metric_select';
import { SingleFieldSelect } from '../single_field_select';
import { AggDescriptor } from '../../../common/descriptor_types';
import { AGG_TYPE } from '../../../common/constants';
import { getTermsFields } from '../../index_pattern_util';
import { IFieldType } from '../../../../../../src/plugins/data/public';

function filterFieldsForAgg(fields, aggType) {
function filterFieldsForAgg(fields: IFieldType[], aggType: AGG_TYPE) {
if (!fields) {
return [];
}
Expand All @@ -34,8 +36,27 @@ function filterFieldsForAgg(fields, aggType) {
});
}

export function MetricEditor({ fields, metricsFilter, metric, onChange, removeButton }) {
const onAggChange = (metricAggregationType) => {
interface Props {
metric: AggDescriptor;
fields: IFieldType[];
onChange: (metric: AggDescriptor) => void;
onRemove: () => void;
metricsFilter?: (metricOption: EuiComboBoxOptionOption<AGG_TYPE>) => boolean;
showRemoveButton: boolean;
}

export function MetricEditor({
fields,
metricsFilter,
metric,
onChange,
showRemoveButton,
onRemove,
}: Props) {
const onAggChange = (metricAggregationType?: AGG_TYPE) => {
if (!metricAggregationType) {
return;
}
const newMetricProps = {
...metric,
type: metricAggregationType,
Expand All @@ -54,13 +75,16 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu

onChange(newMetricProps);
};
const onFieldChange = (fieldName) => {
const onFieldChange = (fieldName?: string) => {
if (!fieldName) {
return;
}
onChange({
...metric,
field: fieldName,
});
};
const onLabelChange = (e) => {
const onLabelChange = (e: ChangeEvent<HTMLInputElement>) => {
onChange({
...metric,
label: e.target.value,
Expand All @@ -80,7 +104,7 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu
placeholder={i18n.translate('xpack.maps.metricsEditor.selectFieldPlaceholder', {
defaultMessage: 'Select field',
})}
value={metric.field}
value={metric.field ? metric.field : null}
onChange={onFieldChange}
fields={filterFieldsForAgg(fields, metric.type)}
isClearable={false}
Expand Down Expand Up @@ -108,6 +132,28 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu
);
}

let removeButton;
if (showRemoveButton) {
removeButton = (
<div className="mapMetricEditorPanel__metricRemoveButton">
<EuiButtonEmpty
iconType="trash"
size="xs"
color="danger"
onClick={onRemove}
aria-label={i18n.translate('xpack.maps.metricsEditor.deleteMetricAriaLabel', {
defaultMessage: 'Delete metric',
})}
>
<FormattedMessage
id="xpack.maps.metricsEditor.deleteMetricButtonLabel"
defaultMessage="Delete metric"
/>
</EuiButtonEmpty>
</div>
);
}

return (
<Fragment>
<EuiFormRow
Expand All @@ -130,14 +176,3 @@ export function MetricEditor({ fields, metricsFilter, metric, onChange, removeBu
</Fragment>
);
}

MetricEditor.propTypes = {
metric: PropTypes.shape({
type: PropTypes.oneOf(METRIC_AGGREGATION_VALUES),
field: PropTypes.string,
label: PropTypes.string,
}),
fields: PropTypes.array,
onChange: PropTypes.func.isRequired,
metricsFilter: PropTypes.func,
};
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,9 @@
*/

import React from 'react';
import PropTypes from 'prop-types';
import { i18n } from '@kbn/i18n';
import { EuiComboBox } from '@elastic/eui';
import { AGG_TYPE } from '../../common/constants';
import { EuiComboBox, EuiComboBoxOptionOption, EuiComboBoxProps } from '@elastic/eui';
import { AGG_TYPE } from '../../../common/constants';

const AGG_OPTIONS = [
{
Expand Down Expand Up @@ -55,17 +54,19 @@ const AGG_OPTIONS = [
},
];

export const METRIC_AGGREGATION_VALUES = AGG_OPTIONS.map(({ value }) => {
return value;
});
type Props = Omit<EuiComboBoxProps<AGG_TYPE>, 'onChange'> & {
value: AGG_TYPE;
onChange: (aggType: AGG_TYPE) => void;
metricsFilter?: (metricOption: EuiComboBoxOptionOption<AGG_TYPE>) => boolean;
};

export function MetricSelect({ value, onChange, metricsFilter, ...rest }) {
function onAggChange(selectedOptions) {
export function MetricSelect({ value, onChange, metricsFilter, ...rest }: Props) {
function onAggChange(selectedOptions: Array<EuiComboBoxOptionOption<AGG_TYPE>>) {
if (selectedOptions.length === 0) {
return;
}

const aggType = selectedOptions[0].value;
const aggType = selectedOptions[0].value!;
onChange(aggType);
}

Expand All @@ -87,9 +88,3 @@ export function MetricSelect({ value, onChange, metricsFilter, ...rest }) {
/>
);
}

MetricSelect.propTypes = {
metricsFilter: PropTypes.func,
value: PropTypes.oneOf(METRIC_AGGREGATION_VALUES),
onChange: PropTypes.func.isRequired,
};
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import React from 'react';
import { shallow } from 'enzyme';
import { MetricsEditor } from './metrics_editor';
import { AGG_TYPE } from '../../common/constants';
import { AGG_TYPE } from '../../../common/constants';

const defaultProps = {
metrics: [
Expand All @@ -19,15 +19,14 @@ const defaultProps = {
fields: [],
onChange: () => {},
allowMultipleMetrics: true,
metricsFilter: () => {},
};

test('should render metrics editor', async () => {
test('should render metrics editor', () => {
const component = shallow(<MetricsEditor {...defaultProps} />);
expect(component).toMatchSnapshot();
});

test('should add default count metric when metrics is empty array', async () => {
test('should add default count metric when metrics is empty array', () => {
const component = shallow(<MetricsEditor {...defaultProps} metrics={[]} />);
expect(component).toMatchSnapshot();
});
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,60 @@
*/

import React, { Fragment } from 'react';
import PropTypes from 'prop-types';
import { i18n } from '@kbn/i18n';
import { FormattedMessage } from '@kbn/i18n/react';
import { EuiButtonEmpty, EuiSpacer, EuiTextAlign } from '@elastic/eui';
import { EuiButtonEmpty, EuiComboBoxOptionOption, EuiSpacer, EuiTextAlign } from '@elastic/eui';
import { MetricEditor } from './metric_editor';
import { DEFAULT_METRIC } from '../classes/sources/es_agg_source';
// @ts-expect-error
import { DEFAULT_METRIC } from '../../classes/sources/es_agg_source';
import { IFieldType } from '../../../../../../src/plugins/data/public';
import { AggDescriptor } from '../../../common/descriptor_types';
import { AGG_TYPE } from '../../../common/constants';

export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics, metricsFilter }) {
interface Props {
allowMultipleMetrics: boolean;
metrics: AggDescriptor[];
fields: IFieldType[];
onChange: (metrics: AggDescriptor[]) => void;
metricsFilter?: (metricOption: EuiComboBoxOptionOption<AGG_TYPE>) => boolean;
}

export function MetricsEditor({
fields,
metrics = [DEFAULT_METRIC],
onChange,
allowMultipleMetrics = true,
metricsFilter,
}: Props) {
function renderMetrics() {
// There was a bug in 7.8 that initialized metrics to [].
// This check is needed to handle any saved objects created before the bug was patched.
const nonEmptyMetrics = metrics.length === 0 ? [DEFAULT_METRIC] : metrics;
return nonEmptyMetrics.map((metric, index) => {
const onMetricChange = (metric) => {
onChange([...metrics.slice(0, index), metric, ...metrics.slice(index + 1)]);
const onMetricChange = (updatedMetric: AggDescriptor) => {
onChange([...metrics.slice(0, index), updatedMetric, ...metrics.slice(index + 1)]);
};

const onRemove = () => {
onChange([...metrics.slice(0, index), ...metrics.slice(index + 1)]);
};

let removeButton;
if (index > 0) {
removeButton = (
<div className="mapMetricEditorPanel__metricRemoveButton">
<EuiButtonEmpty
iconType="trash"
size="xs"
color="danger"
onClick={onRemove}
aria-label={i18n.translate('xpack.maps.metricsEditor.deleteMetricAriaLabel', {
defaultMessage: 'Delete metric',
})}
>
<FormattedMessage
id="xpack.maps.metricsEditor.deleteMetricButtonLabel"
defaultMessage="Delete metric"
/>
</EuiButtonEmpty>
</div>
);
}
return (
<div key={index} className="mapMetricEditorPanel__metricEditor">
<MetricEditor
onChange={onMetricChange}
metric={metric}
fields={fields}
metricsFilter={metricsFilter}
removeButton={removeButton}
showRemoveButton={index > 0}
onRemove={onRemove}
/>
</div>
);
});
}

function addMetric() {
onChange([...metrics, {}]);
onChange([...metrics, { type: AGG_TYPE.AVG }]);
}

function renderAddMetricButton() {
Expand All @@ -71,7 +67,7 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics,
}

return (
<>
<Fragment>
<EuiSpacer size="xs" />
<EuiTextAlign textAlign="center">
<EuiButtonEmpty onClick={addMetric} size="xs" iconType="plusInCircleFilled">
Expand All @@ -81,7 +77,7 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics,
/>
</EuiButtonEmpty>
</EuiTextAlign>
</>
</Fragment>
);
}

Expand All @@ -93,16 +89,3 @@ export function MetricsEditor({ fields, metrics, onChange, allowMultipleMetrics,
</Fragment>
);
}

MetricsEditor.propTypes = {
metrics: PropTypes.array,
fields: PropTypes.array,
onChange: PropTypes.func.isRequired,
allowMultipleMetrics: PropTypes.bool,
metricsFilter: PropTypes.func,
};

MetricsEditor.defaultProps = {
metrics: [DEFAULT_METRIC],
allowMultipleMetrics: true,
};
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,6 @@
* you may not use this file except in compliance with the Elastic License.
*/

jest.mock('../../../../components/metric_editor', () => ({
MetricsEditor: () => {
return <div>mockMetricsEditor</div>;
},
}));

import React from 'react';
import { shallow } from 'enzyme';
import { MetricsExpression } from './metrics_expression';
Expand Down

0 comments on commit 0e7125f

Please sign in to comment.