diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/area.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/area.js index 3def90db90974..1b27b74611063 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/area.js +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/area.js @@ -20,12 +20,25 @@ import { VisFactoryProvider } from 'ui/vis/vis_factory'; import { i18n } from '@kbn/i18n'; import { Schemas } from 'ui/vis/editors/default/schemas'; -import { PointSeriesOptions } from './components/options'; -import { getLegendPositions, LegendPositions } from './utils/legend_positions'; +import { AggGroupNames } from 'ui/vis/editors/default'; +import { + Positions, + ChartTypes, + ChartModes, + InterpolationModes, + AxisTypes, + ScaleTypes, + AxisModes, + Rotates, + ThresholdLineStyles, + getConfigCollections, +} from './utils/collections'; +import { getAreaOptionTabs, getCountLabel } from './utils/common_config'; import { palettes } from '@elastic/eui/lib/services'; export default function PointSeriesVisType(Private) { const VisFactory = Private(VisFactoryProvider); + const countLabel = getCountLabel(); return VisFactory.createVislibVisualization({ name: 'area', @@ -42,12 +55,12 @@ export default function PointSeriesVisType(Private) { categoryAxes: [ { id: 'CategoryAxis-1', - type: 'category', - position: 'bottom', + type: AxisTypes.CATEGORY, + position: Positions.BOTTOM, show: true, style: {}, scale: { - type: 'linear' + type: ScaleTypes.LINEAR, }, labels: { show: true, @@ -61,93 +74,62 @@ export default function PointSeriesVisType(Private) { { id: 'ValueAxis-1', name: 'LeftAxis-1', - type: 'value', - position: 'left', + type: AxisTypes.VALUE, + position: Positions.LEFT, show: true, style: {}, scale: { - type: 'linear', - mode: 'normal' + type: ScaleTypes.LINEAR, + mode: AxisModes.NORMAL, }, labels: { show: true, - rotate: 0, + rotate: Rotates.HORIZONTAL, filter: false, truncate: 100 }, title: { - text: 'Count' + text: countLabel } } ], - seriesParams: [{ - show: 'true', - type: 'area', - mode: 'stacked', - data: { - label: 'Count', - id: '1' - }, - drawLinesBetweenPoints: true, - showCircles: true, - interpolate: 'linear', - valueAxis: 'ValueAxis-1' - }], + seriesParams: [ + { + show: true, + type: ChartTypes.AREA, + mode: ChartModes.STACKED, + data: { + label: countLabel, + id: '1' + }, + drawLinesBetweenPoints: true, + lineWidth: 2, + showCircles: true, + interpolate: InterpolationModes.LINEAR, + valueAxis: 'ValueAxis-1', + } + ], addTooltip: true, addLegend: true, - legendPosition: LegendPositions.RIGHT, + legendPosition: Positions.RIGHT, times: [], addTimeMarker: false, thresholdLine: { show: false, value: 10, width: 1, - style: 'full', + style: ThresholdLineStyles.FULL, color: palettes.euiPaletteColorBlind.colors[9] }, labels: {} }, }, editorConfig: { - collections: { - legendPositions: getLegendPositions(), - positions: ['top', 'left', 'right', 'bottom'], - chartTypes: [{ - value: 'line', - text: 'line' - }, { - value: 'area', - text: 'area' - }, { - value: 'histogram', - text: 'bar' - }], - axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'], - scaleTypes: ['linear', 'log', 'square root'], - chartModes: ['normal', 'stacked'], - interpolationModes: [{ - value: 'linear', - text: 'straight', - }, { - value: 'cardinal', - text: 'smoothed', - }, { - value: 'step-after', - text: 'stepped', - }], - }, - optionTabs: [ - { - name: 'advanced', - title: 'Metrics & Axes', - editor: '
' + - '
' - }, - { name: 'options', title: 'Panel Settings', editor: PointSeriesOptions }, - ], + collections: getConfigCollections(), + optionTabs: getAreaOptionTabs(), schemas: new Schemas([ { - group: 'metrics', + group: AggGroupNames.Metrics, name: 'metric', title: i18n.translate('kbnVislibVisTypes.area.metricsTitle', { defaultMessage: 'Y-axis' }), aggFilter: ['!geo_centroid', '!geo_bounds'], @@ -157,7 +139,7 @@ export default function PointSeriesVisType(Private) { ] }, { - group: 'metrics', + group: AggGroupNames.Metrics, name: 'radius', title: i18n.translate('kbnVislibVisTypes.area.radiusTitle', { defaultMessage: 'Dot size' }), min: 0, @@ -165,7 +147,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'segment', title: i18n.translate('kbnVislibVisTypes.area.segmentTitle', { defaultMessage: 'X-axis' }), min: 0, @@ -173,7 +155,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'group', title: i18n.translate('kbnVislibVisTypes.area.groupTitle', { defaultMessage: 'Split series' }), min: 0, @@ -181,7 +163,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'split', title: i18n.translate('kbnVislibVisTypes.area.splitTitle', { defaultMessage: 'Split chart' }), min: 0, diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/index.ts b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/index.ts index 50ac0752e8d1f..458fa1347dc71 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/index.ts +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/index.ts @@ -24,3 +24,4 @@ export { SelectOption } from './select'; export { SwitchOption } from './switch'; export { TextInputOption } from './text_input'; export { TruncateLabelsOption } from './truncate_labels'; +export { ValidationWrapper, ValidationVisOptionsProps } from './validation_wrapper'; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/number_input.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/number_input.tsx index 3f305a1ca7ae9..9a7a39bc8f559 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/number_input.tsx +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/number_input.tsx @@ -21,16 +21,23 @@ import React from 'react'; import { EuiFormRow, EuiFieldNumber } from '@elastic/eui'; interface NumberInputOptionProps { + disabled?: boolean; + error?: string[]; + isInvalid?: boolean; label?: React.ReactNode; max?: number; min?: number; - step?: string | number; paramName: ParamName; + step?: number; value?: number | ''; + 'data-test-subj'?: string; setValue: (paramName: ParamName, value: number | '') => void; } function NumberInputOption({ + disabled, + error, + isInvalid, label, max, min, @@ -38,11 +45,15 @@ function NumberInputOption({ step, value = '', setValue, + 'data-test-subj': dataTestSubj, }: NumberInputOptionProps) { return ( - + { +interface SelectOptionProps { disabled?: boolean; helpText?: React.ReactNode; id?: string; @@ -34,7 +34,7 @@ interface SelectOptionProps({ +function SelectOption({ disabled, helpText, id, @@ -57,7 +57,7 @@ function SelectOption setValue(paramName, ev.target.value as ValidParamValues)} fullWidth={true} /> diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/switch.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/switch.tsx index a1ef887a8bd5a..c3ce535fa3c18 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/switch.tsx +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/switch.tsx @@ -27,6 +27,7 @@ interface SwitchOptionProps { tooltip?: string; disabled?: boolean; value?: boolean; + noStyle?: boolean; paramName: ParamName; setValue: (paramName: ParamName, value: boolean) => void; } @@ -36,12 +37,13 @@ function SwitchOption({ tooltip, label, disabled, + noStyle = false, paramName, value = false, setValue, }: SwitchOptionProps) { return ( -
+
{ label?: React.ReactNode; paramName: ParamName; value?: string; + 'data-test-subj'?: string; setValue: (paramName: ParamName, value: string) => void; } function TextInputOption({ + 'data-test-subj': dataTestSubj, disabled, helpText, label, @@ -41,6 +43,7 @@ function TextInputOption({ setValue(paramName, ev.target.value)} diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/truncate_labels.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/truncate_labels.tsx index 9e5c25783d493..465339f129f85 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/truncate_labels.tsx +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/truncate_labels.tsx @@ -22,11 +22,12 @@ import { i18n } from '@kbn/i18n'; import { EuiFormRow, EuiFieldNumber } from '@elastic/eui'; interface TruncateLabelsOptionProps { + disabled?: boolean; value: number | null; setValue: (paramName: 'truncate', value: null | number) => void; } -function TruncateLabelsOption({ value, setValue }: TruncateLabelsOptionProps) { +function TruncateLabelsOption({ disabled, value, setValue }: TruncateLabelsOptionProps) { const onChange = (ev: ChangeEvent) => setValue('truncate', ev.target.value === '' ? null : parseFloat(ev.target.value)); @@ -35,10 +36,15 @@ function TruncateLabelsOption({ value, setValue }: TruncateLabelsOptionProps) { label={i18n.translate('kbnVislibVisTypes.controls.truncateLabel', { defaultMessage: 'Truncate', })} - fullWidth={true} + fullWidth compressed > - + ); } diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/validation_wrapper.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/validation_wrapper.tsx new file mode 100644 index 0000000000000..a3a41d2249b32 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/common/validation_wrapper.tsx @@ -0,0 +1,62 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useEffect, useState, useCallback } from 'react'; +import { VisOptionsProps } from 'ui/vis/editors/default'; + +export interface ValidationVisOptionsProps extends VisOptionsProps { + setMultipleValidity(paramName: string, isValid: boolean): void; +} + +interface ValidationWrapperProps extends VisOptionsProps { + component: React.ComponentType>; +} + +interface Item { + valid: boolean; +} + +function ValidationWrapper({ + component: Component, + ...rest +}: ValidationWrapperProps) { + const [panelState, setPanelState] = useState({} as { [key: string]: Item }); + const isPanelValid = Object.values(panelState).every(item => item.valid); + const { setValidity } = rest; + + const setValidityHandler = useCallback( + (paramName: string, isValid: boolean) => { + setPanelState({ + ...panelState, + [paramName]: { + valid: isValid, + }, + }); + }, + [panelState] + ); + + useEffect(() => { + setValidity(isPanelValid); + }, [isPanelValid]); + + return ; +} + +export { ValidationWrapper }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/index.ts b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/index.ts index 63fd215b65acf..65a22dff0676b 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/index.ts +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/index.ts @@ -20,3 +20,4 @@ export { GaugeOptions } from './gauge'; export { PieOptions } from './pie'; export { PointSeriesOptions } from './point_series'; +export { MetricsAxisOptions } from './metrics_axes'; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/category_axis_panel.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/category_axis_panel.tsx new file mode 100644 index 0000000000000..0e64d2659ca6f --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/category_axis_panel.tsx @@ -0,0 +1,96 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback } from 'react'; +import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { VisOptionsProps } from 'ui/vis/editors/default'; +import { BasicVislibParams, Axis } from '../../../types'; +import { SelectOption, SwitchOption } from '../../common'; +import { LabelOptions } from './label_options'; +import { Positions } from '../../../utils/collections'; + +interface CategoryAxisPanelProps extends VisOptionsProps { + axis: Axis; + onPositionChanged: (position: Positions) => void; + setCategoryAxis: (value: Axis) => void; +} + +function CategoryAxisPanel(props: CategoryAxisPanelProps) { + const { axis, onPositionChanged, vis, setCategoryAxis } = props; + + const setAxis = useCallback( + (paramName: T, value: Axis[T]) => { + const updatedAxis = { + ...axis, + [paramName]: value, + }; + setCategoryAxis(updatedAxis); + }, + [setCategoryAxis] + ); + + const setPosition = useCallback( + (paramName: 'position', value: Axis['position']) => { + setAxis(paramName, value); + onPositionChanged(value); + }, + [setAxis, onPositionChanged] + ); + + return ( + + +

+ +

+
+ + + + + + + {axis.show && } +
+ ); +} + +export { CategoryAxisPanel }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/chart_options.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/chart_options.tsx new file mode 100644 index 0000000000000..9a81a1de1c0d6 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/chart_options.tsx @@ -0,0 +1,137 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useMemo, useCallback } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { VisOptionsProps } from 'ui/vis/editors/default'; +import { BasicVislibParams, SeriesParam, ValueAxis } from '../../../types'; +import { ChartTypes } from '../../../utils/collections'; +import { SelectOption } from '../../common'; +import { LineOptions } from './line_options'; +import { SetParamByIndex, ChangeValueAxis } from './'; + +export type SetChart = (paramName: T, value: SeriesParam[T]) => void; + +interface ChartOptionsParams extends VisOptionsProps { + chart: SeriesParam; + index: number; + changeValueAxis: ChangeValueAxis; + setParamByIndex: SetParamByIndex; +} + +function ChartOptions({ + chart, + index, + stateParams, + vis, + changeValueAxis, + setParamByIndex, +}: ChartOptionsParams) { + const setChart: SetChart = useCallback( + (paramName, value) => { + setParamByIndex('seriesParams', index, paramName, value); + }, + [setParamByIndex, index] + ); + + const setValueAxis = useCallback( + (paramName, value) => { + changeValueAxis(index, paramName, value); + }, + [changeValueAxis, index] + ); + + const valueAxesOptions = useMemo( + () => [ + ...stateParams.valueAxes.map(({ id, name }: ValueAxis) => ({ + text: name, + value: id, + })), + { + text: i18n.translate('kbnVislibVisTypes.controls.pointSeries.series.newAxisLabel', { + defaultMessage: 'New axis…', + }), + value: 'new', + }, + ], + [stateParams.valueAxes] + ); + + return ( + <> + + + + + + + + + + + + {chart.type === ChartTypes.AREA && ( + + )} + + {chart.type === ChartTypes.LINE && ( + + )} + + ); +} + +export { ChartOptions }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/custom_extents_options.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/custom_extents_options.tsx new file mode 100644 index 0000000000000..999341bdd6098 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/custom_extents_options.tsx @@ -0,0 +1,140 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState, useCallback } from 'react'; +import { i18n } from '@kbn/i18n'; + +import { ValueAxis } from '../../../types'; +import { NumberInputOption, SwitchOption } from '../../common'; +import { YExtents } from './y_extents'; +import { SetScale } from './value_axis_options'; + +interface CustomExtentsOptionsProps { + axis: ValueAxis; + setMultipleValidity(paramName: string, isValid: boolean): void; + setValueAxis(paramName: T, value: ValueAxis[T]): void; + setValueAxisScale: SetScale; +} + +function CustomExtentsOptions({ + axis, + setMultipleValidity, + setValueAxis, + setValueAxisScale, +}: CustomExtentsOptionsProps) { + const [isBoundsMarginValid, setIsBoundsMarginValid] = useState(true); + const invalidBoundsMarginMessage = i18n.translate( + 'kbnVislibVisTypes.controls.pointSeries.valueAxes.scaleToDataBounds.minNeededBoundsMargin', + { defaultMessage: 'Bounds margin must be greater than or equal to 0.' } + ); + + const setBoundsMargin = useCallback( + (paramName: 'boundsMargin', value: number | '') => { + const isValid = value === '' ? true : value >= 0; + setIsBoundsMarginValid(isValid); + setMultipleValidity('boundsMargin', isValid); + + setValueAxisScale(paramName, value); + }, + [setMultipleValidity, setValueAxisScale] + ); + + const onDefaultYExtentsChange = useCallback( + (paramName: 'defaultYExtents', value: boolean) => { + const scale = { ...axis.scale, [paramName]: value }; + if (!scale.defaultYExtents) { + delete scale.boundsMargin; + setMultipleValidity('boundsMargin', true); + } + setValueAxis('scale', scale); + }, + [setValueAxis, axis.scale] + ); + + const onSetYExtentsChange = useCallback( + (paramName: 'setYExtents', value: boolean) => { + const scale = { ...axis.scale, [paramName]: value }; + if (!scale.setYExtents) { + delete scale.min; + delete scale.max; + } + setValueAxis('scale', scale); + }, + [setValueAxis, axis.scale] + ); + + return ( + <> + + + {axis.scale.defaultYExtents && ( + <> + + + )} + + + + {axis.scale.setYExtents && ( + + )} + + ); +} + +export { CustomExtentsOptions }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/index.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/index.tsx new file mode 100644 index 0000000000000..05797b8dde5b2 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/index.tsx @@ -0,0 +1,307 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useState, useEffect, useCallback, useMemo } from 'react'; +import { cloneDeep, uniq, get } from 'lodash'; +import { EuiSpacer } from '@elastic/eui'; + +import { AggConfig } from 'ui/vis'; +import { BasicVislibParams, ValueAxis, SeriesParam, Axis } from '../../../types'; +import { ValidationVisOptionsProps } from '../../common'; +import { SeriesPanel } from './series_panel'; +import { CategoryAxisPanel } from './category_axis_panel'; +import { ValueAxesPanel } from './value_axes_panel'; +import { + makeSerie, + isAxisHorizontal, + countNextAxisNumber, + getUpdatedAxisName, + mapPositionOpposite, + mapPosition, +} from './utils'; + +export type SetParamByIndex =

( + axesName: 'valueAxes' | 'seriesParams', + index: number, + paramName: P | O, + value: ValueAxis[P] | SeriesParam[O] +) => void; + +export type ChangeValueAxis = ( + index: number, + paramName: 'valueAxis', + selectedValueAxis: string +) => void; + +const VALUE_AXIS_PREFIX = 'ValueAxis-'; + +function MetricsAxisOptions(props: ValidationVisOptionsProps) { + const { stateParams, setValue, aggs, aggsLabels, setVisType, vis } = props; + + const [isCategoryAxisHorizontal, setIsCategoryAxisHorizontal] = useState(true); + + const setParamByIndex: SetParamByIndex = useCallback( + (axesName, index, paramName, value) => { + const items = stateParams[axesName]; + const array = [...items] as typeof items; + + array[index] = { + ...array[index], + [paramName]: value, + }; + + setValue(axesName, array); + }, + [stateParams, setValue] + ); + + const setCategoryAxis = useCallback( + (value: Axis) => { + const categoryAxes = [...stateParams.categoryAxes]; + categoryAxes[0] = value; + setValue('categoryAxes', categoryAxes); + }, + [setValue, stateParams.categoryAxes] + ); + + // stores previous aggs' custom labels + const [lastCustomLabels, setLastCustomLabels] = useState({} as { [key: string]: string }); + // stores previous aggs' field and type + const [lastSeriesAgg, setLastSeriesAgg] = useState({} as { + [key: string]: { type: string; field: string }; + }); + + const updateAxisTitle = () => { + const axes = cloneDeep(stateParams.valueAxes); + let isAxesChanged = false; + const lastLabels = { ...lastCustomLabels }; + const lastMatchingSeriesAgg = { ...lastSeriesAgg }; + + stateParams.valueAxes.forEach((axis, axisNumber) => { + let newCustomLabel = ''; + const matchingSeries: AggConfig[] = []; + + stateParams.seriesParams.forEach((series, seriesIndex) => { + if ((axisNumber === 0 && !series.valueAxis) || series.valueAxis === axis.id) { + const aggByIndex = aggs.bySchemaName('metric')[seriesIndex]; + matchingSeries.push(aggByIndex); + } + }); + + if (matchingSeries.length === 1) { + // if several series matches to the axis, axis title is set according to the first serie. + newCustomLabel = matchingSeries[0].makeLabel(); + } + + if (lastCustomLabels[axis.id] !== newCustomLabel && newCustomLabel !== '') { + const lastSeriesAggType = get(lastSeriesAgg, `${matchingSeries[0].id}.type`); + const lastSeriesAggField = get(lastSeriesAgg, `${matchingSeries[0].id}.field`); + const matchingSeriesAggType = get(matchingSeries, '[0]type.name', ''); + const matchingSeriesAggField = get(matchingSeries, '[0]params.field.name', ''); + + const aggTypeIsChanged = lastSeriesAggType !== matchingSeriesAggType; + const aggFieldIsChanged = lastSeriesAggField !== matchingSeriesAggField; + + lastMatchingSeriesAgg[matchingSeries[0].id] = { + type: matchingSeriesAggType, + field: matchingSeriesAggField, + }; + lastLabels[axis.id] = newCustomLabel; + + if ( + aggTypeIsChanged || + aggFieldIsChanged || + axis.title.text === '' || + lastCustomLabels[axis.id] === axis.title.text + ) { + // Override axis title with new custom label + axes[axisNumber] = { ...axes[axisNumber], title: { ...axis, text: newCustomLabel } }; + isAxesChanged = true; + } + } + }); + + if (isAxesChanged) { + setValue('valueAxes', axes); + } + + setLastSeriesAgg(lastMatchingSeriesAgg); + setLastCustomLabels(lastLabels); + }; + + const onValueAxisPositionChanged = useCallback( + (index: number, value: ValueAxis['position']) => { + const valueAxes = [...stateParams.valueAxes]; + const name = getUpdatedAxisName(value, valueAxes); + + valueAxes[index] = { + ...valueAxes[index], + name, + position: value, + }; + setValue('valueAxes', valueAxes); + }, + [stateParams.valueAxes, getUpdatedAxisName, setValue] + ); + + const onCategoryAxisPositionChanged = useCallback( + (chartPosition: Axis['position']) => { + const isChartHorizontal = isAxisHorizontal(chartPosition); + setIsCategoryAxisHorizontal(isAxisHorizontal(chartPosition)); + + stateParams.valueAxes.forEach((axis, index) => { + if (isAxisHorizontal(axis.position) === isChartHorizontal) { + const position = mapPosition(axis.position); + onValueAxisPositionChanged(index, position); + } + }); + }, + [stateParams.valueAxes, onValueAxisPositionChanged] + ); + + const addValueAxis = useCallback(() => { + const nextAxisIdNumber = stateParams.valueAxes.reduce( + countNextAxisNumber(VALUE_AXIS_PREFIX), + 1 + ); + + const newAxis = cloneDeep(stateParams.valueAxes[0]); + newAxis.id = VALUE_AXIS_PREFIX + nextAxisIdNumber; + newAxis.position = mapPositionOpposite(newAxis.position); + newAxis.name = getUpdatedAxisName(newAxis.position, stateParams.valueAxes); + + setValue('valueAxes', [...stateParams.valueAxes, newAxis]); + return newAxis; + }, [stateParams.valueAxes, setValue]); + + const removeValueAxis = useCallback( + (axis: ValueAxis) => { + const newValueAxes = stateParams.valueAxes.filter(valAxis => valAxis.id !== axis.id); + + setValue('valueAxes', newValueAxes); + + let isSeriesUpdated = false; + const series = stateParams.seriesParams.map(ser => { + if (axis.id === ser.valueAxis) { + isSeriesUpdated = true; + return { ...ser, valueAxis: newValueAxes[0].id }; + } + return ser; + }); + + if (isSeriesUpdated) { + // if seriesParams have valueAxis equals to removed one, then we reset it to the first valueAxis + setValue('seriesParams', series); + } + + if (stateParams.grid.valueAxis === axis.id) { + // reset Y-axis grid lines setting + setValue('grid', { ...stateParams.grid, valueAxis: undefined }); + } + }, + [stateParams.seriesParams, stateParams.valueAxes, setValue] + ); + + const changeValueAxis: ChangeValueAxis = useCallback( + (index, paramName, selectedValueAxis) => { + let newValueAxis = selectedValueAxis; + if (selectedValueAxis === 'new') { + const axis = addValueAxis(); + newValueAxis = axis.id; + } + + setParamByIndex('seriesParams', index, paramName, newValueAxis); + + updateAxisTitle(); + }, + [addValueAxis, setParamByIndex] + ); + + const metrics = useMemo(() => { + const schemaName = vis.type.schemas.metrics[0].name; + return aggs.bySchemaName(schemaName); + }, [vis.type.schemas.metrics[0].name, aggs, aggsLabels]); + + const firstValueAxesId = stateParams.valueAxes[0].id; + + useEffect(() => { + const updatedSeries = metrics.map(agg => { + const params = stateParams.seriesParams.find(param => param.data.id === agg.id); + const label = agg.makeLabel(); + + // update labels for existing params or create new one + if (params) { + return { + ...params, + data: { + ...params.data, + label, + }, + }; + } else { + const series = makeSerie( + agg.id, + label, + firstValueAxesId, + stateParams.seriesParams[stateParams.seriesParams.length - 1] + ); + return series; + } + }); + + setValue('seriesParams', updatedSeries); + }, [aggsLabels, metrics, firstValueAxesId]); + + const visType = useMemo(() => { + const types = uniq(stateParams.seriesParams.map(({ type }) => type)); + return types.length === 1 ? types[0] : 'histogram'; + }, [stateParams.seriesParams]); + + useEffect(() => { + setVisType(visType); + }, [visType]); + + useEffect(() => { + updateAxisTitle(); + }, [aggsLabels]); + + return ( + <> + + + + + + + ); +} + +export { MetricsAxisOptions }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/label_options.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/label_options.tsx new file mode 100644 index 0000000000000..62ad2601f0e33 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/label_options.tsx @@ -0,0 +1,124 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback } from 'react'; +import { EuiTitle, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { VisOptionsProps } from 'ui/vis/editors/default'; +import { BasicVislibParams, Axis } from '../../../types'; +import { SelectOption, SwitchOption, TruncateLabelsOption } from '../../common'; +import { rotateOptions } from '../../../utils/collections'; + +interface LabelOptionsProps extends VisOptionsProps { + axis: Axis; + axesName: 'categoryAxes' | 'valueAxes'; + index: number; +} + +function LabelOptions({ stateParams, setValue, axis, axesName, index }: LabelOptionsProps) { + const setAxisLabel = useCallback( + (paramName: T, value: Axis['labels'][T]) => { + const axes = [...stateParams[axesName]]; + axes[index] = { + ...axes[index], + labels: { + ...axes[index].labels, + [paramName]: value, + }, + }; + setValue(axesName, axes); + }, + [axesName, index, setValue, stateParams] + ); + + const setAxisLabelRotate = useCallback( + (paramName: 'rotate', value: Axis['labels']['rotate']) => { + setAxisLabel(paramName, Number(value)); + }, + [setAxisLabel] + ); + + return ( + <> + +

+ +

+ + + + + + + + + + + + + + + + ); +} + +export { LabelOptions }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/line_options.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/line_options.tsx new file mode 100644 index 0000000000000..eb1ed014e7e96 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/line_options.tsx @@ -0,0 +1,94 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; + +import { Vis } from 'ui/vis'; +import { SeriesParam } from '../../../types'; +import { NumberInputOption, SelectOption, SwitchOption } from '../../common'; +import { SetChart } from './chart_options'; + +interface LineOptionsParams { + chart: SeriesParam; + vis: Vis; + setChart: SetChart; +} + +function LineOptions({ chart, vis, setChart }: LineOptionsParams) { + const setLineWidth = useCallback( + (paramName: 'lineWidth', value: number | '') => { + setChart(paramName, value === '' ? undefined : value); + }, + [setChart] + ); + + return ( + <> + + + + + + + + + + + + + + ); +} + +export { LineOptions }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/series_panel.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/series_panel.tsx new file mode 100644 index 0000000000000..816b0bfeda598 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/series_panel.tsx @@ -0,0 +1,77 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { EuiPanel, EuiTitle, EuiSpacer, EuiAccordion } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { VisOptionsProps } from 'ui/vis/editors/default'; +import { BasicVislibParams } from '../../../types'; +import { ChartOptions } from './chart_options'; +import { SetParamByIndex, ChangeValueAxis } from './'; + +interface SeriesPanelProps extends VisOptionsProps { + changeValueAxis: ChangeValueAxis; + setParamByIndex: SetParamByIndex; +} + +function SeriesPanel(props: SeriesPanelProps) { + const { stateParams } = props; + + return ( + + +

+ +

+
+ + + {stateParams.seriesParams.map((chart, index) => ( + + <> + + + + + + ))} +
+ ); +} + +export { SeriesPanel }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/utils.ts b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/utils.ts new file mode 100644 index 0000000000000..7144b0ad4902e --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/utils.ts @@ -0,0 +1,111 @@ +/* + * 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 { capitalize } from 'lodash'; + +import { BasicVislibParams, ValueAxis, SeriesParam } from '../../../types'; +import { ChartModes, ChartTypes, InterpolationModes, Positions } from '../../../utils/collections'; + +const makeSerie = ( + id: string, + label: string, + defaultValueAxis: ValueAxis['id'], + lastSerie?: SeriesParam +): SeriesParam => { + const data = { id, label }; + const defaultSerie = { + show: true, + mode: ChartModes.NORMAL, + type: ChartTypes.LINE, + drawLinesBetweenPoints: true, + showCircles: true, + interpolate: InterpolationModes.LINEAR, + lineWidth: 2, + valueAxis: defaultValueAxis, + data, + }; + return lastSerie ? { ...lastSerie, data } : defaultSerie; +}; + +const isAxisHorizontal = (position: Positions) => + [Positions.TOP, Positions.BOTTOM].includes(position); + +const RADIX = 10; + +function countNextAxisNumber(axisName: string, axisProp: 'id' | 'name' = 'id') { + return (value: number, axis: ValueAxis) => { + const nameLength = axisName.length; + if (axis[axisProp].substr(0, nameLength) === axisName) { + const num = parseInt(axis[axisProp].substr(nameLength), RADIX); + if (num >= value) { + value = num + 1; + } + } + return value; + }; +} + +const AXIS_PREFIX = 'Axis-'; + +const getUpdatedAxisName = ( + axisPosition: ValueAxis['position'], + valueAxes: BasicVislibParams['valueAxes'] +) => { + const axisName = capitalize(axisPosition) + AXIS_PREFIX; + const nextAxisNameNumber = valueAxes.reduce(countNextAxisNumber(axisName, 'name'), 1); + + return `${axisName}${nextAxisNameNumber}`; +}; + +function mapPositionOpposite(position: Positions) { + switch (position) { + case Positions.BOTTOM: + return Positions.TOP; + case Positions.TOP: + return Positions.BOTTOM; + case Positions.LEFT: + return Positions.RIGHT; + case Positions.RIGHT: + return Positions.LEFT; + default: + throw new Error('Invalid legend position.'); + } +} + +function mapPosition(position: Positions) { + switch (position) { + case Positions.BOTTOM: + return Positions.LEFT; + case Positions.TOP: + return Positions.RIGHT; + case Positions.LEFT: + return Positions.BOTTOM; + case Positions.RIGHT: + return Positions.TOP; + } +} + +export { + makeSerie, + isAxisHorizontal, + countNextAxisNumber, + getUpdatedAxisName, + mapPositionOpposite, + mapPosition, +}; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/value_axes_panel.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/value_axes_panel.tsx new file mode 100644 index 0000000000000..2ae54f9e09337 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/value_axes_panel.tsx @@ -0,0 +1,162 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback, useMemo } from 'react'; +import { + EuiPanel, + EuiTitle, + EuiSpacer, + EuiAccordion, + EuiFlexGroup, + EuiFlexItem, + EuiButtonIcon, + EuiToolTip, +} from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { BasicVislibParams, ValueAxis } from '../../../types'; +import { ValueAxisOptions } from './value_axis_options'; +import { SetParamByIndex } from './'; +import { ValidationVisOptionsProps } from '../../common'; + +interface ValueAxesPanelProps extends ValidationVisOptionsProps { + isCategoryAxisHorizontal: boolean; + addValueAxis: () => ValueAxis; + removeValueAxis: (axis: ValueAxis) => void; + onValueAxisPositionChanged: (index: number, value: ValueAxis['position']) => void; + setParamByIndex: SetParamByIndex; +} + +function ValueAxesPanel(props: ValueAxesPanelProps) { + const { stateParams, addValueAxis, removeValueAxis } = props; + + const getSeries = useCallback( + (axis: ValueAxis) => { + const isFirst = stateParams.valueAxes[0].id === axis.id; + const series = stateParams.seriesParams.filter( + serie => serie.valueAxis === axis.id || (isFirst && !serie.valueAxis) + ); + return series.map(serie => serie.data.label).join(', '); + }, + [stateParams.valueAxes, stateParams.seriesParams] + ); + + const removeButtonTooltip = useMemo( + () => + i18n.translate('kbnVislibVisTypes.controls.pointSeries.valueAxes.removeButtonTooltip', { + defaultMessage: 'Remove Y-axis', + }), + [] + ); + + const renderRemoveButton = useCallback( + (axis: ValueAxis) => ( + + removeValueAxis(axis)} + aria-label={removeButtonTooltip} + /> + + ), + [removeValueAxis] + ); + + const addButtonTooltip = useMemo( + () => + i18n.translate('kbnVislibVisTypes.controls.pointSeries.valueAxes.addButtonTooltip', { + defaultMessage: 'Add Y-axis', + }), + [] + ); + + const getButtonContent = useCallback( + (axis: ValueAxis) => { + const description = getSeries(axis); + + return ( + <> + {axis.name}{' '} + + <>{description} + + + ); + }, + [getSeries] + ); + return ( + + + + +

+ +

+
+
+ + + + + +
+ + + + {stateParams.valueAxes.map((axis, index) => ( + + <> + + + + + ))} +
+ ); +} + +export { ValueAxesPanel }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/value_axis_options.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/value_axis_options.tsx new file mode 100644 index 0000000000000..00b3f719a49de --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/value_axis_options.tsx @@ -0,0 +1,219 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useCallback, useMemo } from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiSpacer, EuiAccordion, EuiHorizontalRule } from '@elastic/eui'; + +import { BasicVislibParams, ValueAxis } from '../../../types'; +import { Positions } from '../../../utils/collections'; +import { + SelectOption, + SwitchOption, + TextInputOption, + ValidationVisOptionsProps, +} from '../../common'; +import { LabelOptions } from './label_options'; +import { CustomExtentsOptions } from './custom_extents_options'; +import { isAxisHorizontal } from './utils'; +import { SetParamByIndex } from './'; + +export type SetScale = ( + paramName: T, + value: ValueAxis['scale'][T] +) => void; + +export interface ValueAxisOptionsParams extends ValidationVisOptionsProps { + axis: ValueAxis; + index: number; + isCategoryAxisHorizontal: boolean; + onValueAxisPositionChanged: (index: number, value: ValueAxis['position']) => void; + setParamByIndex: SetParamByIndex; +} + +function ValueAxisOptions(props: ValueAxisOptionsParams) { + const { + axis, + index, + isCategoryAxisHorizontal, + stateParams, + vis, + onValueAxisPositionChanged, + setParamByIndex, + } = props; + + const setValueAxis = useCallback( + (paramName: T, value: ValueAxis[T]) => + setParamByIndex('valueAxes', index, paramName, value), + [setParamByIndex, index] + ); + + const setValueAxisTitle = useCallback( + (paramName: T, value: ValueAxis['title'][T]) => { + const title = { + ...stateParams.valueAxes[index].title, + [paramName]: value, + }; + + setParamByIndex('valueAxes', index, 'title', title); + }, + [setParamByIndex, index, stateParams.valueAxes] + ); + + const setValueAxisScale: SetScale = useCallback( + (paramName, value) => { + const scale = { + ...stateParams.valueAxes[index].scale, + [paramName]: value, + }; + + setParamByIndex('valueAxes', index, 'scale', scale); + }, + [setParamByIndex, index, stateParams.valueAxes] + ); + + const onPositionChanged = useCallback( + (paramName: 'position', value: ValueAxis['position']) => { + onValueAxisPositionChanged(index, value); + }, + [index, onValueAxisPositionChanged] + ); + + const isPositionDisabled = useCallback( + (position: Positions) => { + if (isCategoryAxisHorizontal) { + return isAxisHorizontal(position); + } + return [Positions.LEFT, Positions.RIGHT].includes(position); + }, + [isCategoryAxisHorizontal] + ); + + const positions = useMemo( + () => + vis.type.editorConfig.collections.positions.map( + (position: { text: string; value: Positions }) => ({ + ...position, + disabled: isPositionDisabled(position.value), + }) + ), + [vis.type.editorConfig.collections.positions, isPositionDisabled] + ); + + return ( + <> + + + + + + + + + + + {axis.show ? ( + <> + + + + + + ) : ( + + )} + + + + + <> + + + + + + ); +} + +export { ValueAxisOptions }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/y_extents.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/y_extents.tsx new file mode 100644 index 0000000000000..29b986367d72a --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/metrics_axes/y_extents.tsx @@ -0,0 +1,120 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React, { useEffect, useCallback } from 'react'; +import { EuiFlexGroup, EuiFlexItem, EuiFormRow } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; + +import { Scale } from '../../../types'; +import { ScaleTypes } from '../../../utils/collections'; +import { NumberInputOption } from '../../common'; +import { SetScale } from './value_axis_options'; + +const rangeError = i18n.translate( + 'kbnVislibVisTypes.controls.pointSeries.valueAxes.minErrorMessage', + { defaultMessage: 'Min should be less than Max.' } +); +const minError = i18n.translate( + 'kbnVislibVisTypes.controls.pointSeries.valueAxes.minNeededScaleText', + { + defaultMessage: 'Min must exceed 0 when a log scale is selected.', + } +); + +function areExtentsValid(min: number | null = null, max: number | null = null): boolean { + if (min === null || max === null) { + return true; + } + + return max > min; +} + +function isNullOrUndefined(value?: number | null): value is null | undefined { + return value === null || value === undefined; +} + +interface YExtentsProps { + scale: Scale; + setScale: SetScale; + setMultipleValidity: (paramName: string, isValid: boolean) => void; +} + +function YExtents({ scale, setScale, setMultipleValidity }: YExtentsProps) { + const { min, max, type } = scale; + const errors = []; + + if (!areExtentsValid(min, max)) { + errors.push(rangeError); + } + + if (type === ScaleTypes.LOG && (isNullOrUndefined(min) || min <= 0)) { + errors.push(minError); + } + + const isValid = !errors.length; + + const setExtents = useCallback( + (paramName, value) => { + setScale(paramName, value === '' ? null : value); + }, + [setScale] + ); + + useEffect(() => { + setMultipleValidity('yExtents', isValid); + + return () => setMultipleValidity('yExtents', true); + }, [isValid]); + + return ( + + <> + + + + + + + + + + + ); +} + +export { YExtents }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/point_series/grid_options.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/point_series/grid_panel.tsx similarity index 84% rename from src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/point_series/grid_options.tsx rename to src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/point_series/grid_panel.tsx index d155ad938bf48..6493fdd59868f 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/point_series/grid_options.tsx +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/point_series/grid_panel.tsx @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import React, { useMemo, useEffect } from 'react'; +import React, { useMemo, useEffect, useCallback } from 'react'; import { EuiPanel, EuiTitle } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n/react'; @@ -25,15 +25,14 @@ import { VisOptionsProps } from 'ui/vis/editors/default'; import { SelectOption, SwitchOption } from '../../common'; import { BasicVislibParams, ValueAxis } from '../../../types'; -function GridOptions({ - stateParams, - setValue, - hasHistogramAgg, -}: VisOptionsProps) { - const setGrid = ( - paramName: T, - value: BasicVislibParams['grid'][T] - ) => setValue('grid', { ...stateParams.grid, [paramName]: value }); +function GridPanel({ stateParams, setValue, hasHistogramAgg }: VisOptionsProps) { + const setGrid = useCallback( + ( + paramName: T, + value: BasicVislibParams['grid'][T] + ) => setValue('grid', { ...stateParams.grid, [paramName]: value }), + [stateParams.grid, setValue] + ); const options = useMemo( () => [ @@ -48,7 +47,7 @@ function GridOptions({ value: '', }, ], - [stateParams.valueAxes.map(({ id }: ValueAxis) => id)] + [stateParams.valueAxes] ); useEffect(() => { @@ -71,7 +70,7 @@ function GridOptions({ ) { const { stateParams, setValue, vis } = props; - const options = [ - { - value: 'full', - text: i18n.translate('kbnVislibVisTypes.editors.pointSeries.thresholdLine.style.full', { - defaultMessage: 'Full', - }), - }, - { - value: 'dashed', - text: i18n.translate('kbnVislibVisTypes.editors.pointSeries.thresholdLine.style.dashed', { - defaultMessage: 'Dashed', - }), - }, - { - value: 'dot-dashed', - text: i18n.translate('kbnVislibVisTypes.editors.pointSeries.thresholdLine.style.dotdashed', { - defaultMessage: 'Dot-dashed', - }), - }, - ] as const; return ( <> @@ -100,91 +81,11 @@ function PointSeriesOptions(props: VisOptionsProps) { - + - - -

- -

-
- - - - setValue('thresholdLine', { ...stateParams.thresholdLine, [paramName]: value }) - } - /> - - {stateParams.thresholdLine.show && ( - <> - - setValue('thresholdLine', { ...stateParams.thresholdLine, [paramName]: value || 0 }) - } - /> - - - setValue('thresholdLine', { ...stateParams.thresholdLine, [paramName]: value || 1 }) - } - /> - - - setValue('thresholdLine', { ...stateParams.thresholdLine, [paramName]: value }) - } - /> - - - { - setValue('thresholdLine', { ...stateParams.thresholdLine, color: value }); - }} - /> - - - )} -
+ {stateParams.thresholdLine && } ); } diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/point_series/threshold_panel.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/point_series/threshold_panel.tsx new file mode 100644 index 0000000000000..331b81dc65321 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/components/options/point_series/threshold_panel.tsx @@ -0,0 +1,126 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +import React, { useCallback } from 'react'; +import { EuiPanel, EuiTitle, EuiColorPicker, EuiFormRow, EuiSpacer } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; + +import { VisOptionsProps } from 'ui/vis/editors/default'; +import { NumberInputOption, SelectOption, SwitchOption } from '../../common'; +import { BasicVislibParams } from '../../../types'; + +function ThresholdPanel({ stateParams, setValue, vis }: VisOptionsProps) { + const setThresholdLine = useCallback( + ( + paramName: T, + value: BasicVislibParams['thresholdLine'][T] + ) => setValue('thresholdLine', { ...stateParams.thresholdLine, [paramName]: value }), + [stateParams.thresholdLine, setValue] + ); + + const setThresholdLineColor = useCallback( + (value: BasicVislibParams['thresholdLine']['color']) => setThresholdLine('color', value), + [setThresholdLine] + ); + + return ( + + +

+ +

+
+ + + + + {stateParams.thresholdLine.show && ( + <> + + + + + + + + + + + )} +
+ ); +} + +export { ThresholdPanel }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/category_axis.html b/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/category_axis.html deleted file mode 100644 index 0d6f804ef87ae..0000000000000 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/category_axis.html +++ /dev/null @@ -1,134 +0,0 @@ -
-
-
-
- - -
- -
- -
-
- -
- -
- -
-
- - - -
- - - - - - - - - - - -
- -
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
-
- -
diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/category_axis.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/category_axis.js deleted file mode 100644 index 3b31ad8c1fb78..0000000000000 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/category_axis.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { uiModules } from 'ui/modules'; -import vislibValueAxesTemplate from './category_axis.html'; -const module = uiModules.get('kibana'); - -module.directive('vislibCategoryAxis', function () { - return { - restrict: 'E', - template: vislibValueAxesTemplate, - replace: true, - link: function ($scope) { - $scope.rotateOptions = [ - { name: 'horizontal', value: 0 }, - { name: 'vertical', value: 90 }, - { name: 'angled', value: 75 }, - ]; - } - }; -}); diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/index.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/index.js deleted file mode 100644 index 87289e9aa410d..0000000000000 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/index.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import './value_axes.js'; -import './category_axis.js'; -import './series.js'; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/series.html b/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/series.html deleted file mode 100644 index d96c1b73e8551..0000000000000 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/series.html +++ /dev/null @@ -1,156 +0,0 @@ -
-
-
-
- -
-
-
- - - - - {{chart.data.label}} - -
-
- -
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
-
- -
- -
-
-
-
-
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
-
-
diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/series.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/series.js deleted file mode 100644 index 6b0b5511ca47a..0000000000000 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/series.js +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; -import { uiModules } from 'ui/modules'; -import vislibSeriesTemplate from './series.html'; -import { safeMakeLabel } from 'ui/agg_types/agg_utils'; - -const module = uiModules.get('kibana'); - -module.directive('vislibSeries', function () { - return { - restrict: 'E', - template: vislibSeriesTemplate, - replace: true, - link: function ($scope) { - function makeSerie(id, label) { - const last = $scope.series[$scope.series.length - 1]; - return { - show: true, - mode: last ? last.mode : 'normal', - type: last ? last.type : 'line', - drawLinesBetweenPoints: last ? last.drawLinesBetweenPoints : true, - showCircles: last ? last.showCircles : true, - interpolate: last ? last.interpolate : 'linear', - lineWidth: last ? last.lineWidth : 2, - data: { - id: id, - label: label - }, - valueAxis: last ? last.valueAxis : $scope.editorState.params.valueAxes[0].id - }; - } - - $scope.series = $scope.editorState.params.seriesParams; - $scope.$watch(() => { - return $scope.editorState.aggs.aggs.map(agg => { - return safeMakeLabel(agg); - }).join(); - }, () => { - const schemaTitle = $scope.vis.type.schemas.metrics[0].title; - - const metrics = $scope.editorState.aggs.aggs.filter(agg => { - const isMetric = agg.type && agg.type.type === 'metrics'; - return isMetric && agg.schema.title === schemaTitle; - }); - - // update labels for existing params or create new one - $scope.editorState.params.seriesParams = metrics.map(agg => { - const params = $scope.editorState.params.seriesParams.find(param => param.data.id === agg.id); - if (params) { - params.data.label = agg.makeLabel(); - return params; - } else { - const series = makeSerie(agg.id, agg.makeLabel()); - return series; - } - }); - }); - - $scope.$watch(() => { - return $scope.editorState.params.seriesParams.map(series => series.type).join(); - }, () => { - const types = _.uniq(_.map($scope.editorState.params.seriesParams, 'type')); - $scope.vis.type.type = types.length === 1 ? types[0] : 'histogram'; - }); - - $scope.$watch('editorState.params.valueAxes.length', () => { - $scope.editorState.params.seriesParams.forEach(series => { - if (!$scope.editorState.params.valueAxes.find(axis => axis.id === series.valueAxis)) { - series.valueAxis = $scope.editorState.params.valueAxes[0].id; - } - }); - }); - - $scope.changeValueAxis = (index) => { - const series = $scope.editorState.params.seriesParams[index]; - if (series.valueAxis === 'new') { - const axis = $scope.addValueAxis(); - series.valueAxis = axis.id; - } - $scope.updateAxisTitle(); - }; - } - }; -}); diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/value_axes.html b/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/value_axes.html deleted file mode 100644 index 5b316bd2ef420..0000000000000 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/value_axes.html +++ /dev/null @@ -1,350 +0,0 @@ -
-
-
- - -
- -
-
-
- - - - - {{axis.name}} - -
- -
{{getSeriesShort(axis)}}
- - -
- -
- - -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- - - -
- - - - - - - - - - -
- - -
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- -
- -
- -
-
- - - -
- -
- -
- -
-
- -
-
- -
- -
-
-
- -
-
- -
- -
- -
-
- -
-
- -
- -
-
- -
- -
- -
-
-
- -
-
- -
-
-
-
-
diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/value_axes.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/value_axes.js deleted file mode 100644 index bc790306dc2d3..0000000000000 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/controls/point_series/value_axes.js +++ /dev/null @@ -1,205 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import _ from 'lodash'; -import { uiModules } from 'ui/modules'; -import vislibValueAxesTemplate from './value_axes.html'; -import { safeMakeLabel } from 'ui/agg_types/agg_utils'; - -const module = uiModules.get('kibana'); - -module.directive('vislibValueAxes', function () { - return { - restrict: 'E', - template: vislibValueAxesTemplate, - replace: true, - link: function ($scope) { - let isCategoryAxisHorizontal = true; - - function mapPosition(position) { - switch (position) { - case 'bottom': return 'left'; - case 'top': return 'right'; - case 'left': return 'bottom'; - case 'right': return 'top'; - } - } - - function mapPositionOpposite(position) { - switch (position) { - case 'bottom': return 'top'; - case 'top': return 'bottom'; - case 'left': return 'right'; - case 'right': return 'left'; - } - } - - $scope.rotateOptions = [ - { name: 'horizontal', value: 0 }, - { name: 'vertical', value: 90 }, - { name: 'angled', value: 75 }, - ]; - - $scope.$watch('editorState.params.categoryAxes[0].position', position => { - isCategoryAxisHorizontal = ['top', 'bottom'].includes(position); - $scope.editorState.params.valueAxes.forEach(axis => { - const axisIsHorizontal = ['top', 'bottom'].includes(axis.position); - if (axisIsHorizontal === isCategoryAxisHorizontal) { - axis.position = mapPosition(axis.position); - $scope.updateAxisName(axis); - } - }); - }); - - $scope.getSeries = function (axis) { - const isFirst = $scope.editorState.params.valueAxes[0] === axis; - const series = $scope.editorState.params.seriesParams.filter(series => - (series.valueAxis === axis.id || (isFirst && !series.valueAxis)) - ); - return series.map(series => series.data.label).join(', '); - }; - - $scope.getSeriesShort = function (axis) { - const maxStringLength = 30; - return $scope.getSeries(axis).substring(0, maxStringLength); - }; - - $scope.isPositionDisabled = function (position) { - if (isCategoryAxisHorizontal) { - return ['top', 'bottom'].includes(position); - } - return ['left', 'right'].includes(position); - }; - - $scope.addValueAxis = function () { - const firstAxis = $scope.editorState.params.valueAxes[0]; - const newAxis = _.cloneDeep(firstAxis); - newAxis.id = 'ValueAxis-' + $scope.editorState.params.valueAxes.reduce((value, axis) => { - if (axis.id.substr(0, 10) === 'ValueAxis-') { - const num = parseInt(axis.id.substr(10)); - if (num >= value) value = num + 1; - } - return value; - }, 1); - - newAxis.position = mapPositionOpposite(firstAxis.position); - const axisName = _.capitalize(newAxis.position) + 'Axis-'; - newAxis.name = axisName + $scope.editorState.params.valueAxes.reduce((value, axis) => { - if (axis.name.substr(0, axisName.length) === axisName) { - const num = parseInt(axis.name.substr(axisName.length)); - if (num >= value) value = num + 1; - } - return value; - }, 1); - - $scope.editorState.params.valueAxes.push(newAxis); - return newAxis; - }; - - $scope.removeValueAxis = function (axis) { - if ($scope.editorState.params.valueAxes.length > 1) { - _.remove($scope.editorState.params.valueAxes, function (valAxis) { - return valAxis.id === axis.id; - }); - } - }; - - $scope.updateExtents = function (axis) { - if (!axis.scale.setYExtents) { - delete axis.scale.min; - delete axis.scale.max; - } - }; - - $scope.updateBoundsMargin = function (axis) { - if (!axis.scale.defaultYExtents) { - delete axis.scale.boundsMargin; - } - }; - - $scope.updateAxisName = function (axis) { - const axisName = _.capitalize(axis.position) + 'Axis-'; - axis.name = axisName + $scope.editorState.params.valueAxes.reduce((value, axis) => { - if (axis.name.substr(0, axisName.length) === axisName) { - const num = parseInt(axis.name.substr(axisName.length)); - if (num >= value) value = num + 1; - } - return value; - }, 1); - }; - - const lastCustomLabels = {}; - // We track these so we can know when the agg is changed - let lastMatchingSeriesAggType = ''; - let lastMatchingSeriesAggField = ''; - $scope.updateAxisTitle = function () { - $scope.editorState.params.valueAxes.forEach((axis, axisNumber) => { - let newCustomLabel = ''; - const isFirst = axisNumber === 0; - const matchingSeries = []; - $scope.editorState.params.seriesParams.forEach((series, i) => { - const isMatchingSeries = (isFirst && !series.valueAxis) || (series.valueAxis === axis.id); - if (isMatchingSeries) { - let seriesNumber = 0; - $scope.editorState.aggs.aggs.forEach(agg => { - if (agg.schema.name === 'metric') { - if (seriesNumber === i) matchingSeries.push(agg); - seriesNumber++; - } - }); - } - }); - - if (matchingSeries.length === 1) { - newCustomLabel = matchingSeries[0].makeLabel(); - } - - const matchingSeriesAggType = _.get(matchingSeries, '[0]type.name', ''); - const matchingSeriesAggField = _.get(matchingSeries, '[0]params.field.name', ''); - - if (lastCustomLabels[axis.id] !== newCustomLabel && newCustomLabel !== '') { - const isFirstRender = Object.keys(lastCustomLabels).length === 0; - const aggTypeIsChanged = lastMatchingSeriesAggType !== matchingSeriesAggType; - const aggFieldIsChanged = lastMatchingSeriesAggField !== matchingSeriesAggField; - const aggIsChanged = aggTypeIsChanged || aggFieldIsChanged; - const axisTitleIsEmpty = axis.title.text === ''; - const lastCustomLabelMatchesAxisTitle = lastCustomLabels[axis.id] === axis.title.text; - - if (!isFirstRender && (aggIsChanged || axisTitleIsEmpty || lastCustomLabelMatchesAxisTitle)) { - axis.title.text = newCustomLabel; // Override axis title with new custom label - } - - lastCustomLabels[axis.id] = newCustomLabel; - } - - lastMatchingSeriesAggType = matchingSeriesAggType; - lastMatchingSeriesAggField = matchingSeriesAggField; - }); - }; - - $scope.$watch(() => { - return $scope.editorState.aggs.aggs.map(agg => { - return safeMakeLabel(agg); - }).join(); - }, () => { - $scope.updateAxisTitle(); - }); - } - }; -}); diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/editors/__tests__/point_series.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/editors/__tests__/point_series.js deleted file mode 100644 index f2157496b4649..0000000000000 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/editors/__tests__/point_series.js +++ /dev/null @@ -1,176 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import angular from 'angular'; -import _ from 'lodash'; -import expect from '@kbn/expect'; -import ngMock from 'ng_mock'; -import $ from 'jquery'; -import FixturesStubbedLogstashIndexPatternProvider from 'fixtures/stubbed_logstash_index_pattern'; -import LineVisTypeProvider from '../../line'; -import { VisProvider } from 'ui/vis'; -import { AggConfig } from 'ui/vis/agg_config'; - -describe('point series editor', function () { - let $parentScope; - let $container; - let $elem; - let lineVisType; - let Vis; - let indexPattern; - - function makeConfig() { - return { - type: 'line', - params: lineVisType.visConfig.defaults, - aggs: [ - { type: 'count', schema: 'metric', params: { field: 'bytes' } }, - { type: 'terms', schema: 'segment', params: { field: 'machine.os' } }, - ], - listeners: { click: _.noop } - }; - } - - beforeEach(ngMock.module('kibana')); - beforeEach(ngMock.inject(function ($rootScope, $compile, Private) { - lineVisType = Private(LineVisTypeProvider); - Vis = Private(VisProvider); - indexPattern = Private(FixturesStubbedLogstashIndexPatternProvider); - $parentScope = $rootScope; - $parentScope.vis = new Vis(indexPattern, makeConfig()); - $parentScope.editorState = { - params: $parentScope.vis.params, - aggs: $parentScope.vis.aggs, - }; - $parentScope.savedVis = {}; - - // share the scope - //_.defaults($parentScope, $rootScope, Object.getPrototypeOf($rootScope)); - - $container = $(document.createElement('div')) - .appendTo('body'); - // make the element - $elem = angular.element('
' + - '
'); - $container.append($elem); - - // compile the html - $compile($elem)($parentScope); - - // Digest everything - $elem.scope().$digest(); - })); - - afterEach(function () { - $container.remove(); - }); - - it('should show correct series', function () { - expect($parentScope.editorState.params.seriesParams.length).to.be(1); - expect($parentScope.editorState.params.seriesParams[0].data.label).to.be('Count'); - }); - - it('should update series when new agg is added', function () { - const aggConfig = new AggConfig($parentScope.vis.aggs, { type: 'avg', schema: 'metric', params: { field: 'bytes' } }); - $parentScope.vis.aggs.aggs.push(aggConfig); - $parentScope.$digest(); - expect($parentScope.editorState.params.seriesParams.length).to.be(2); - }); - - it('should only allow left and right value axis position when category axis is horizontal', function () { - expect($parentScope.isPositionDisabled('top')).to.be(true); - expect($parentScope.isPositionDisabled('bottom')).to.be(true); - expect($parentScope.isPositionDisabled('left')).to.be(false); - expect($parentScope.isPositionDisabled('right')).to.be(false); - }); - - it('should only allow top and bottom value axis position when category axis is vertical', function () { - $parentScope.editorState.params.categoryAxes[0].position = 'left'; - $parentScope.$digest(); - expect($parentScope.editorState.params.valueAxes[0].position).to.be('bottom'); - expect($parentScope.isPositionDisabled('top')).to.be(false); - expect($parentScope.isPositionDisabled('bottom')).to.be(false); - expect($parentScope.isPositionDisabled('left')).to.be(true); - expect($parentScope.isPositionDisabled('right')).to.be(true); - }); - - it('should add value axis', function () { - $parentScope.addValueAxis(); - expect($parentScope.editorState.params.valueAxes.length).to.be(2); - }); - - it('should remove value axis', function () { - $parentScope.addValueAxis(); - $parentScope.removeValueAxis({ id: 'ValueAxis-2' }); - expect($parentScope.editorState.params.valueAxes.length).to.be(1); - }); - - it('should not allow to remove the last value axis', function () { - $parentScope.removeValueAxis({ id: 'ValueAxis-1' }); - expect($parentScope.editorState.params.valueAxes.length).to.be(1); - }); - - it('should set the value axis title if its not set', function () { - $parentScope.updateAxisTitle(); - expect($parentScope.editorState.params.valueAxes[0].title.text).to.equal('Count'); - }); - - it('should not update the value axis title if custom title was set', function () { - $parentScope.editorState.params.valueAxes[0].title.text = 'Custom Title'; - $parentScope.updateAxisTitle(); - expect($parentScope.editorState.params.valueAxes[0].title.text).to.equal('Custom Title'); - }); - - it('should set the custom title to match the value axis label when only one agg exists for that axis', function () { - $parentScope.editorState.aggs.aggs[0].params.customLabel = 'Custom Label'; - $parentScope.updateAxisTitle(); - expect($parentScope.editorState.params.valueAxes[0].title.text).to.equal('Custom Label'); - }); - - it('should not set the custom title to match the value axis label when more than one agg exists for that axis', function () { - const aggConfig = new AggConfig($parentScope.vis.aggs, { type: 'avg', schema: 'metric', params: { field: 'bytes' } }); - $parentScope.vis.aggs.aggs.push(aggConfig); - $parentScope.$digest(); - $parentScope.editorState.aggs.aggs[0].params.customLabel = 'Custom Label'; - $parentScope.updateAxisTitle(); - expect($parentScope.editorState.params.valueAxes[0].title.text).to.equal('Count'); - }); - - it('should not overwrite the custom title with the value axis label if the custom title has been changed', function () { - $parentScope.editorState.params.valueAxes[0].title.text = 'Custom Title'; - $parentScope.editorState.aggs.aggs[0].params.customLabel = 'Custom Label'; - $parentScope.updateAxisTitle(); - expect($parentScope.editorState.params.valueAxes[0].title.text).to.equal('Custom Title'); - }); - - it('should overwrite the custom title when the agg type changes', function () { - const aggConfig = new AggConfig($parentScope.vis.aggs, { type: 'avg', schema: 'metric', params: { field: 'bytes' } }); - - $parentScope.editorState.params.valueAxes[0].title.text = 'Custom Title'; - $parentScope.editorState.aggs.aggs[0].params.customLabel = 'Custom Label'; - $parentScope.updateAxisTitle(); - - $parentScope.vis.aggs.aggs.push(aggConfig); - $parentScope.vis.aggs.aggs.shift(); - $parentScope.$digest(); - $parentScope.updateAxisTitle(); - - expect($parentScope.editorState.params.valueAxes[0].title.text).to.equal('Average bytes'); - }); -}); diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/histogram.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/histogram.js index c809f0f024ebd..19960d730005f 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/histogram.js +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/histogram.js @@ -20,12 +20,24 @@ import { VisFactoryProvider } from 'ui/vis/vis_factory'; import { i18n } from '@kbn/i18n'; import { Schemas } from 'ui/vis/editors/default/schemas'; -import { PointSeriesOptions } from './components/options'; -import { getLegendPositions, LegendPositions } from './utils/legend_positions'; +import { AggGroupNames } from 'ui/vis/editors/default'; +import { + Positions, + ChartTypes, + ChartModes, + AxisTypes, + ScaleTypes, + AxisModes, + Rotates, + ThresholdLineStyles, + getConfigCollections, +} from './utils/collections'; +import { getAreaOptionTabs, getCountLabel } from './utils/common_config'; import { palettes } from '@elastic/eui/lib/services'; export default function PointSeriesVisType(Private) { const VisFactory = Private(VisFactoryProvider); + const countLabel = getCountLabel(); return VisFactory.createVislibVisualization({ name: 'histogram', @@ -43,12 +55,12 @@ export default function PointSeriesVisType(Private) { categoryAxes: [ { id: 'CategoryAxis-1', - type: 'category', - position: 'bottom', + type: AxisTypes.CATEGORY, + position: Positions.BOTTOM, show: true, style: {}, scale: { - type: 'linear' + type: ScaleTypes.LINEAR, }, labels: { show: true, @@ -62,42 +74,43 @@ export default function PointSeriesVisType(Private) { { id: 'ValueAxis-1', name: 'LeftAxis-1', - type: 'value', - position: 'left', + type: AxisTypes.VALUE, + position: Positions.LEFT, show: true, style: {}, scale: { - type: 'linear', - mode: 'normal' + type: ScaleTypes.LINEAR, + mode: AxisModes.NORMAL, }, labels: { show: true, - rotate: 0, + rotate: Rotates.HORIZONTAL, filter: false, truncate: 100 }, title: { - text: 'Count' + text: countLabel, } } ], seriesParams: [ { - show: 'true', - type: 'histogram', - mode: 'stacked', + show: true, + type: ChartTypes.HISTOGRAM, + mode: ChartModes.STACKED, data: { - label: 'Count', + label: countLabel, id: '1' }, valueAxis: 'ValueAxis-1', drawLinesBetweenPoints: true, + lineWidth: 2, showCircles: true } ], addTooltip: true, addLegend: true, - legendPosition: LegendPositions.RIGHT, + legendPosition: Positions.RIGHT, times: [], addTimeMarker: false, labels: { @@ -107,51 +120,17 @@ export default function PointSeriesVisType(Private) { show: false, value: 10, width: 1, - style: 'full', + style: ThresholdLineStyles.FULL, color: palettes.euiPaletteColorBlind.colors[9] } }, }, editorConfig: { - collections: { - legendPositions: getLegendPositions(), - positions: ['top', 'left', 'right', 'bottom'], - chartTypes: [{ - value: 'line', - text: 'line' - }, { - value: 'area', - text: 'area' - }, { - value: 'histogram', - text: 'bar' - }], - axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'], - scaleTypes: ['linear', 'log', 'square root'], - chartModes: ['normal', 'stacked'], - interpolationModes: [{ - value: 'linear', - text: 'straight', - }, { - value: 'cardinal', - text: 'smoothed', - }, { - value: 'step-after', - text: 'stepped', - }], - }, - optionTabs: [ - { - name: 'advanced', - title: 'Metrics & Axes', - editor: '
' + - '
' - }, - { name: 'options', title: 'Panel Settings', editor: PointSeriesOptions }, - ], + collections: getConfigCollections(), + optionTabs: getAreaOptionTabs(), schemas: new Schemas([ { - group: 'metrics', + group: AggGroupNames.Metrics, name: 'metric', title: i18n.translate('kbnVislibVisTypes.histogram.metricTitle', { defaultMessage: 'Y-axis' }), min: 1, @@ -161,7 +140,7 @@ export default function PointSeriesVisType(Private) { ] }, { - group: 'metrics', + group: AggGroupNames.Metrics, name: 'radius', title: i18n.translate('kbnVislibVisTypes.histogram.radiusTitle', { defaultMessage: 'Dot size' }), min: 0, @@ -169,7 +148,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'segment', title: i18n.translate('kbnVislibVisTypes.histogram.segmentTitle', { defaultMessage: 'X-axis' }), min: 0, @@ -177,7 +156,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'group', title: i18n.translate('kbnVislibVisTypes.histogram.groupTitle', { defaultMessage: 'Split series' }), min: 0, @@ -185,7 +164,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'split', title: i18n.translate('kbnVislibVisTypes.histogram.splitTitle', { defaultMessage: 'Split chart' }), min: 0, diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/horizontal_bar.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/horizontal_bar.js index 0bb23862e1ebc..eb18bb763aa3d 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/horizontal_bar.js +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/horizontal_bar.js @@ -20,11 +20,24 @@ import { VisFactoryProvider } from 'ui/vis/vis_factory'; import { i18n } from '@kbn/i18n'; import { Schemas } from 'ui/vis/editors/default/schemas'; -import { PointSeriesOptions } from './components/options'; -import { getLegendPositions, LegendPositions } from './utils/legend_positions'; +import { AggGroupNames } from 'ui/vis/editors/default'; +import { + Positions, + ChartTypes, + ChartModes, + AxisTypes, + ScaleTypes, + AxisModes, + Rotates, + ThresholdLineStyles, + getConfigCollections, +} from './utils/collections'; +import { getAreaOptionTabs, getCountLabel } from './utils/common_config'; +import { palettes } from '@elastic/eui/lib/services'; export default function PointSeriesVisType(Private) { const VisFactory = Private(VisFactoryProvider); + const countLabel = getCountLabel(); return VisFactory.createVislibVisualization({ name: 'horizontal_bar', @@ -42,17 +55,17 @@ export default function PointSeriesVisType(Private) { categoryAxes: [ { id: 'CategoryAxis-1', - type: 'category', - position: 'left', + type: AxisTypes.CATEGORY, + position: Positions.LEFT, show: true, style: { }, scale: { - type: 'linear' + type: ScaleTypes.LINEAR, }, labels: { show: true, - rotate: 0, + rotate: Rotates.HORIZONTAL, filter: false, truncate: 200 }, @@ -63,86 +76,60 @@ export default function PointSeriesVisType(Private) { { id: 'ValueAxis-1', name: 'LeftAxis-1', - type: 'value', - position: 'bottom', + type: AxisTypes.VALUE, + position: Positions.BOTTOM, show: true, style: { }, scale: { - type: 'linear', - mode: 'normal' + type: ScaleTypes.LINEAR, + mode: AxisModes.NORMAL, }, labels: { show: true, - rotate: 75, + rotate: Rotates.ANGLED, filter: true, truncate: 100 }, title: { - text: 'Count' + text: countLabel, } } ], seriesParams: [{ show: true, - type: 'histogram', - mode: 'normal', + type: ChartTypes.HISTOGRAM, + mode: ChartModes.NORMAL, data: { - label: 'Count', + label: countLabel, id: '1' }, valueAxis: 'ValueAxis-1', drawLinesBetweenPoints: true, + lineWidth: 2, showCircles: true }], addTooltip: true, addLegend: true, - legendPosition: LegendPositions.RIGHT, + legendPosition: Positions.RIGHT, times: [], addTimeMarker: false, labels: {}, + thresholdLine: { + show: false, + value: 10, + width: 1, + style: ThresholdLineStyles.FULL, + color: palettes.euiPaletteColorBlind.colors[9] + }, }, }, editorConfig: { - collections: { - legendPositions: getLegendPositions(), - positions: ['top', 'left', 'right', 'bottom'], - chartTypes: [{ - value: 'line', - text: 'line' - }, { - value: 'area', - text: 'area' - }, { - value: 'histogram', - text: 'bar' - }], - axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'], - scaleTypes: ['linear', 'log', 'square root'], - chartModes: ['normal', 'stacked'], - interpolationModes: [{ - value: 'linear', - text: 'straight', - }, { - value: 'cardinal', - text: 'smoothed', - }, { - value: 'step-after', - text: 'stepped', - }], - }, - optionTabs: [ - { - name: 'advanced', - title: 'Metrics & Axes', - editor: '
' + - '
' - }, - { name: 'options', title: 'Panel Settings', editor: PointSeriesOptions }, - ], + collections: getConfigCollections(), + optionTabs: getAreaOptionTabs(), schemas: new Schemas([ { - group: 'metrics', + group: AggGroupNames.Metrics, name: 'metric', title: i18n.translate('kbnVislibVisTypes.horizontalBar.metricTitle', { defaultMessage: 'Y-axis' }), min: 1, @@ -152,7 +139,7 @@ export default function PointSeriesVisType(Private) { ] }, { - group: 'metrics', + group: AggGroupNames.Metrics, name: 'radius', title: i18n.translate('kbnVislibVisTypes.horizontalBar.radiusTitle', { defaultMessage: 'Dot size' }), min: 0, @@ -160,7 +147,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'segment', title: i18n.translate('kbnVislibVisTypes.horizontalBar.segmentTitle', { defaultMessage: 'X-axis' }), min: 0, @@ -168,7 +155,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'group', title: i18n.translate('kbnVislibVisTypes.horizontalBar.groupTitle', { defaultMessage: 'Split series' }), min: 0, @@ -176,7 +163,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'split', title: i18n.translate('kbnVislibVisTypes.horizontalBar.splitTitle', { defaultMessage: 'Split chart' }), min: 0, diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/line.js b/src/legacy/core_plugins/kbn_vislib_vis_types/public/line.js index 6358800033399..15b640ebc4c85 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/line.js +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/line.js @@ -20,13 +20,25 @@ import { VisFactoryProvider } from 'ui/vis/vis_factory'; import { i18n } from '@kbn/i18n'; import { Schemas } from 'ui/vis/editors/default/schemas'; -import { PointSeriesOptions } from './components/options'; -import { getLegendPositions, LegendPositions } from './utils/legend_positions'; +import { AggGroupNames } from 'ui/vis/editors/default'; +import { + Positions, + ChartTypes, + ChartModes, + AxisTypes, + ScaleTypes, + AxisModes, + Rotates, + ThresholdLineStyles, + InterpolationModes, + getConfigCollections, +} from './utils/collections'; import { palettes } from '@elastic/eui/lib/services'; - +import { getAreaOptionTabs, getCountLabel } from './utils/common_config'; export default function PointSeriesVisType(Private) { const VisFactory = Private(VisFactoryProvider); + const countLabel = getCountLabel(); return VisFactory.createVislibVisualization({ name: 'line', @@ -42,12 +54,12 @@ export default function PointSeriesVisType(Private) { categoryAxes: [ { id: 'CategoryAxis-1', - type: 'category', - position: 'bottom', + type: AxisTypes.CATEGORY, + position: Positions.BOTTOM, show: true, style: {}, scale: { - type: 'linear' + type: ScaleTypes.LINEAR, }, labels: { show: true, @@ -61,42 +73,44 @@ export default function PointSeriesVisType(Private) { { id: 'ValueAxis-1', name: 'LeftAxis-1', - type: 'value', - position: 'left', + type: AxisTypes.VALUE, + position: Positions.LEFT, show: true, style: {}, scale: { - type: 'linear', - mode: 'normal' + type: ScaleTypes.LINEAR, + mode: AxisModes.NORMAL, }, labels: { show: true, - rotate: 0, + rotate: Rotates.HORIZONTAL, filter: false, truncate: 100 }, title: { - text: 'Count' + text: countLabel, } } ], seriesParams: [ { - show: 'true', - type: 'line', - mode: 'normal', + show: true, + type: ChartTypes.LINE, + mode: ChartModes.NORMAL, data: { - label: 'Count', + label: countLabel, id: '1' }, valueAxis: 'ValueAxis-1', drawLinesBetweenPoints: true, + lineWidth: 2, + interpolate: InterpolationModes.LINEAR, showCircles: true } ], addTooltip: true, addLegend: true, - legendPosition: LegendPositions.RIGHT, + legendPosition: Positions.RIGHT, times: [], addTimeMarker: false, labels: {}, @@ -104,51 +118,17 @@ export default function PointSeriesVisType(Private) { show: false, value: 10, width: 1, - style: 'full', + style: ThresholdLineStyles.FULL, color: palettes.euiPaletteColorBlind.colors[9] } }, }, editorConfig: { - collections: { - legendPositions: getLegendPositions(), - positions: ['top', 'left', 'right', 'bottom'], - chartTypes: [{ - value: 'line', - text: 'line' - }, { - value: 'area', - text: 'area' - }, { - value: 'histogram', - text: 'bar' - }], - axisModes: ['normal', 'percentage', 'wiggle', 'silhouette'], - scaleTypes: ['linear', 'log', 'square root'], - chartModes: ['normal', 'stacked'], - interpolationModes: [{ - value: 'linear', - text: 'straight', - }, { - value: 'cardinal', - text: 'smoothed', - }, { - value: 'step-after', - text: 'stepped', - }], - }, - optionTabs: [ - { - name: 'advanced', - title: 'Metrics & Axes', - editor: '
' + - '
' - }, - { name: 'options', title: 'Panel Settings', editor: PointSeriesOptions }, - ], + collections: getConfigCollections(), + optionTabs: getAreaOptionTabs(), schemas: new Schemas([ { - group: 'metrics', + group: AggGroupNames.Metrics, name: 'metric', title: i18n.translate('kbnVislibVisTypes.line.metricTitle', { defaultMessage: 'Y-axis' }), min: 1, @@ -158,7 +138,7 @@ export default function PointSeriesVisType(Private) { ] }, { - group: 'metrics', + group: AggGroupNames.Metrics, name: 'radius', title: i18n.translate('kbnVislibVisTypes.line.radiusTitle', { defaultMessage: 'Dot size' }), min: 0, @@ -166,7 +146,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['count', 'avg', 'sum', 'min', 'max', 'cardinality', 'top_hits'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'segment', title: i18n.translate('kbnVislibVisTypes.line.segmentTitle', { defaultMessage: 'X-axis' }), min: 0, @@ -174,7 +154,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'group', title: i18n.translate('kbnVislibVisTypes.line.groupTitle', { defaultMessage: 'Split series' }), min: 0, @@ -182,7 +162,7 @@ export default function PointSeriesVisType(Private) { aggFilter: ['!geohash_grid', '!geotile_grid', '!filter'] }, { - group: 'buckets', + group: AggGroupNames.Buckets, name: 'split', title: i18n.translate('kbnVislibVisTypes.line.splitTitle', { defaultMessage: 'Split chart' }), min: 0, diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/types.ts b/src/legacy/core_plugins/kbn_vislib_vis_types/public/types.ts index 90bd577828cd8..6cad6e47ce8b3 100644 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/types.ts +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/types.ts @@ -17,40 +17,77 @@ * under the License. */ -import { LegendPositions } from './utils/legend_positions'; +import { + Positions, + ChartModes, + ChartTypes, + AxisModes, + InterpolationModes, + Rotates, + ScaleTypes, + ThresholdLineStyles, +} from './utils/collections'; export interface CommonVislibParams { addTooltip: boolean; - legendPosition: LegendPositions; + legendPosition: Positions; } interface Labels { filter: boolean; - rotate?: number; + rotate?: Rotates; show: boolean; - truncate: number; + truncate: number | null; } + +export interface Scale { + boundsMargin?: number | ''; + defaultYExtents?: boolean; + max?: number | null; + min?: number | null; + mode?: AxisModes; + setYExtents?: boolean; + type: ScaleTypes; +} + interface ThresholdLine { show: boolean; value: number; width: number; - style: 'full' | 'dashed' | 'dot-dashed'; + style: ThresholdLineStyles; color: string; } -export interface ValueAxis { + +export interface Axis { id: string; labels: Labels; - name: string; - position: LegendPositions; - scale: { type: string }; + position: Positions; + scale: Scale; show: boolean; style: object; title: { text: string }; type: string; } +export interface ValueAxis extends Axis { + name: string; +} + +export interface SeriesParam { + data: { label: string; id: string }; + drawLinesBetweenPoints: boolean; + interpolate: InterpolationModes; + lineWidth?: number; + mode: ChartModes; + show: boolean; + showCircles: boolean; + type: ChartTypes; + valueAxis: string; +} + export interface BasicVislibParams extends CommonVislibParams { addTimeMarker: boolean; + categoryAxes: Axis[]; orderBucketsBySum?: boolean; labels: Labels; thresholdLine: ThresholdLine; @@ -59,4 +96,5 @@ export interface BasicVislibParams extends CommonVislibParams { categoryLines: boolean; valueAxis?: string; }; + seriesParams: SeriesParam[]; } diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/utils/collections.ts b/src/legacy/core_plugins/kbn_vislib_vis_types/public/utils/collections.ts new file mode 100644 index 0000000000000..b8300dc42e4b7 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/utils/collections.ts @@ -0,0 +1,261 @@ +/* + * 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 { i18n } from '@kbn/i18n'; + +export enum Positions { + RIGHT = 'right', + LEFT = 'left', + TOP = 'top', + BOTTOM = 'bottom', +} + +const positions = [ + { + text: i18n.translate('kbnVislibVisTypes.legendPositions.topText', { + defaultMessage: 'Top', + }), + value: Positions.TOP, + }, + { + text: i18n.translate('kbnVislibVisTypes.legendPositions.leftText', { + defaultMessage: 'Left', + }), + value: Positions.LEFT, + }, + { + text: i18n.translate('kbnVislibVisTypes.legendPositions.rightText', { + defaultMessage: 'Right', + }), + value: Positions.RIGHT, + }, + { + text: i18n.translate('kbnVislibVisTypes.legendPositions.bottomText', { + defaultMessage: 'Bottom', + }), + value: Positions.BOTTOM, + }, +]; + +export enum ChartTypes { + LINE = 'line', + AREA = 'area', + HISTOGRAM = 'histogram', +} + +const chartTypes = [ + { + text: i18n.translate('kbnVislibVisTypes.chartTypes.lineText', { + defaultMessage: 'Line', + }), + value: ChartTypes.LINE, + }, + { + text: i18n.translate('kbnVislibVisTypes.chartTypes.areaText', { + defaultMessage: 'Area', + }), + value: ChartTypes.AREA, + }, + { + text: i18n.translate('kbnVislibVisTypes.chartTypes.barText', { + defaultMessage: 'Bar', + }), + value: ChartTypes.HISTOGRAM, + }, +]; + +export enum ChartModes { + NORMAL = 'normal', + STACKED = 'stacked', +} + +const chartModes = [ + { + text: i18n.translate('kbnVislibVisTypes.chartModes.normalText', { + defaultMessage: 'Normal', + }), + value: ChartModes.NORMAL, + }, + { + text: i18n.translate('kbnVislibVisTypes.chartModes.stackedText', { + defaultMessage: 'Stacked', + }), + value: ChartModes.STACKED, + }, +]; + +export enum InterpolationModes { + LINEAR = 'linear', + CARDINAL = 'cardinal', + STEP_AFTER = 'step-after', +} + +const interpolationModes = [ + { + text: i18n.translate('kbnVislibVisTypes.interpolationModes.straightText', { + defaultMessage: 'Straight', + }), + value: InterpolationModes.LINEAR, + }, + { + text: i18n.translate('kbnVislibVisTypes.interpolationModes.smoothedText', { + defaultMessage: 'Smoothed', + }), + value: InterpolationModes.CARDINAL, + }, + { + text: i18n.translate('kbnVislibVisTypes.interpolationModes.steppedText', { + defaultMessage: 'Stepped', + }), + value: InterpolationModes.STEP_AFTER, + }, +]; + +export enum AxisTypes { + CATEGORY = 'category', + VALUE = 'value', +} + +export enum ScaleTypes { + LINEAR = 'linear', + LOG = 'log', + SQUARE_ROOT = 'square root', +} + +const scaleTypes = [ + { + text: i18n.translate('kbnVislibVisTypes.scaleTypes.linearText', { + defaultMessage: 'Linear', + }), + value: ScaleTypes.LINEAR, + }, + { + text: i18n.translate('kbnVislibVisTypes.scaleTypes.logText', { + defaultMessage: 'Log', + }), + value: ScaleTypes.LOG, + }, + { + text: i18n.translate('kbnVislibVisTypes.scaleTypes.squareRootText', { + defaultMessage: 'Square root', + }), + value: ScaleTypes.SQUARE_ROOT, + }, +]; + +export enum AxisModes { + NORMAL = 'normal', + PERCENTAGE = 'percentage', + WIGGLE = 'wiggle', + SILHOUETTE = 'silhouette', +} + +const axisModes = [ + { + text: i18n.translate('kbnVislibVisTypes.axisModes.normalText', { + defaultMessage: 'Normal', + }), + value: AxisModes.NORMAL, + }, + { + text: i18n.translate('kbnVislibVisTypes.axisModes.percentageText', { + defaultMessage: 'Percentage', + }), + value: AxisModes.PERCENTAGE, + }, + { + text: i18n.translate('kbnVislibVisTypes.axisModes.wiggleText', { + defaultMessage: 'Wiggle', + }), + value: AxisModes.WIGGLE, + }, + { + text: i18n.translate('kbnVislibVisTypes.axisModes.silhouetteText', { + defaultMessage: 'Silhouette', + }), + value: AxisModes.SILHOUETTE, + }, +]; + +export enum Rotates { + HORIZONTAL = 0, + VERTICAL = 90, + ANGLED = 75, +} + +export enum ThresholdLineStyles { + FULL = 'full', + DASHED = 'dashed', + DOT_DASHED = 'dot-dashed', +} + +const thresholdLineStyles = [ + { + value: ThresholdLineStyles.FULL, + text: i18n.translate('kbnVislibVisTypes.thresholdLine.style.fullText', { + defaultMessage: 'Full', + }), + }, + { + value: ThresholdLineStyles.DASHED, + text: i18n.translate('kbnVislibVisTypes.thresholdLine.style.dashedText', { + defaultMessage: 'Dashed', + }), + }, + { + value: ThresholdLineStyles.DOT_DASHED, + text: i18n.translate('kbnVislibVisTypes.thresholdLine.style.dotdashedText', { + defaultMessage: 'Dot-dashed', + }), + }, +]; + +const rotateOptions = [ + { + text: i18n.translate('kbnVislibVisTypes.categoryAxis.rotate.horizontalText', { + defaultMessage: 'Horizontal', + }), + value: Rotates.HORIZONTAL, + }, + { + text: i18n.translate('kbnVislibVisTypes.categoryAxis.rotate.verticalText', { + defaultMessage: 'Vertical', + }), + value: Rotates.VERTICAL, + }, + { + text: i18n.translate('kbnVislibVisTypes.categoryAxis.rotate.angledText', { + defaultMessage: 'Angled', + }), + value: Rotates.ANGLED, + }, +]; + +const getConfigCollections = () => ({ + legendPositions: positions, + positions, + chartTypes, + axisModes, + scaleTypes, + chartModes, + interpolationModes, + thresholdLineStyles, +}); + +export { getConfigCollections, rotateOptions }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/utils/common_config.tsx b/src/legacy/core_plugins/kbn_vislib_vis_types/public/utils/common_config.tsx new file mode 100644 index 0000000000000..fdec24a002c07 --- /dev/null +++ b/src/legacy/core_plugins/kbn_vislib_vis_types/public/utils/common_config.tsx @@ -0,0 +1,54 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import React from 'react'; +import { VisOptionsProps } from 'ui/vis/editors/default'; +import { i18n } from '@kbn/i18n'; +import { PointSeriesOptions, MetricsAxisOptions } from '../components/options'; +import { ValidationWrapper } from '../components/common'; +import { BasicVislibParams } from '../types'; + +function getAreaOptionTabs() { + return [ + { + name: 'advanced', + title: i18n.translate('kbnVislibVisTypes.area.tabs.metricsAxesTitle', { + defaultMessage: 'Metrics & axes', + }), + editor: (props: VisOptionsProps) => ( + + ), + }, + { + name: 'options', + title: i18n.translate('kbnVislibVisTypes.area.tabs.panelSettingsTitle', { + defaultMessage: 'Panel settings', + }), + editor: PointSeriesOptions, + }, + ]; +} + +function getCountLabel() { + return i18n.translate('kbnVislibVisTypes.area.countText', { + defaultMessage: 'Count', + }); +} + +export { getAreaOptionTabs, getCountLabel }; diff --git a/src/legacy/core_plugins/kbn_vislib_vis_types/public/utils/legend_positions.ts b/src/legacy/core_plugins/kbn_vislib_vis_types/public/utils/legend_positions.ts deleted file mode 100644 index ffe70eba19b39..0000000000000 --- a/src/legacy/core_plugins/kbn_vislib_vis_types/public/utils/legend_positions.ts +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { i18n } from '@kbn/i18n'; - -export enum LegendPositions { - RIGHT = 'right', - LEFT = 'left', - TOP = 'top', - BOTTOM = 'bottom', -} - -const getLegendPositions = () => [ - { - text: i18n.translate('kbnVislibVisTypes.legendPositions.topText', { - defaultMessage: 'Top', - }), - value: LegendPositions.TOP, - }, - { - text: i18n.translate('kbnVislibVisTypes.legendPositions.leftText', { - defaultMessage: 'Left', - }), - value: LegendPositions.LEFT, - }, - { - text: i18n.translate('kbnVislibVisTypes.legendPositions.rightText', { - defaultMessage: 'Right', - }), - value: LegendPositions.RIGHT, - }, - { - text: i18n.translate('kbnVislibVisTypes.legendPositions.bottomText', { - defaultMessage: 'Bottom', - }), - value: LegendPositions.BOTTOM, - }, -]; - -export { getLegendPositions }; diff --git a/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx b/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx index 56742eaec5203..9749c7fa8e2f9 100644 --- a/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx +++ b/src/legacy/core_plugins/region_map/public/components/region_map_options.tsx @@ -200,6 +200,7 @@ function RegionMapOptions(props: RegionMapOptionsProps) { label={i18n.translate('regionMap.visParams.outlineWeightLabel', { defaultMessage: 'Border thickness', })} + min={0} paramName="outlineWeight" value={stateParams.outlineWeight} setValue={setValue} diff --git a/src/legacy/ui/public/vis/editors/default/_sidebar.scss b/src/legacy/ui/public/vis/editors/default/_sidebar.scss index 4efee6168a0f8..5d0026ec3d884 100644 --- a/src/legacy/ui/public/vis/editors/default/_sidebar.scss +++ b/src/legacy/ui/public/vis/editors/default/_sidebar.scss @@ -165,11 +165,6 @@ margin-left: $euiSizeS; } -.visEditorSidebar__collapsibleTitleDescription { - flex: 1 1 0; - @include euiTextTruncate; -} - // // FORMS // @@ -183,11 +178,6 @@ @include __legacySelectStyles__bad; } -.visEditorSidebar__formTitle { - @include euiTitle('xxs'); - margin: $euiSizeS 0; -} - .visEditorSidebar__formRow { display: flex; align-items: center; diff --git a/src/legacy/ui/public/vis/editors/default/agg_group.js b/src/legacy/ui/public/vis/editors/default/agg_group.js index 5a683454a9c1a..e99c8dea3a91d 100644 --- a/src/legacy/ui/public/vis/editors/default/agg_group.js +++ b/src/legacy/ui/public/vis/editors/default/agg_group.js @@ -40,6 +40,7 @@ uiModules 'groupName', 'formIsTouched', 'lastParentPipelineAggTitle', + 'currentTab', ]) ) .directive('visEditorAggGroup', function () { @@ -50,6 +51,7 @@ uiModules template: function () { return ` @@ -70,17 +75,35 @@ uiModules } }; + $scope.setVisType = (type) => { + $scope.vis.type.type = type; + }; + + // since aggs reference isn't changed when an agg is updated, we need somehow to let React component know about it + $scope.aggsLabels = ''; + + $scope.$watch(() => { + return $scope.editorState.aggs.aggs.map(agg => { + return safeMakeLabel(agg); + }).join(); + }, value => { + $scope.aggsLabels = value; + }); + const comp = typeof $scope.editor === 'string' ? $scope.editor : ` `; const $editor = $compile(comp)($scope); diff --git a/src/legacy/ui/public/vis/editors/default/vis_options_props.tsx b/src/legacy/ui/public/vis/editors/default/vis_options_props.tsx index d850e34029cb4..b9573de58845f 100644 --- a/src/legacy/ui/public/vis/editors/default/vis_options_props.tsx +++ b/src/legacy/ui/public/vis/editors/default/vis_options_props.tsx @@ -23,11 +23,13 @@ import { Vis } from './../..'; export interface VisOptionsProps { aggs: AggConfigs; + aggsLabels: string; hasHistogramAgg: boolean; stateParams: VisParamType; vis: Vis; uiState: PersistedState; setValue(paramName: T, value: VisParamType[T]): void; setValidity(isValid: boolean): void; + setVisType(type: string): void; setTouched(isTouched: boolean): void; } diff --git a/src/legacy/ui/public/vis/vis_types/vislib_vis_type.js b/src/legacy/ui/public/vis/vis_types/vislib_vis_type.js index 73eb375da769a..97fa8fc85f634 100644 --- a/src/legacy/ui/public/vis/vis_types/vislib_vis_type.js +++ b/src/legacy/ui/public/vis/vis_types/vislib_vis_type.js @@ -19,7 +19,6 @@ import 'plugins/kbn_vislib_vis_types/controls/line_interpolation_option'; import 'plugins/kbn_vislib_vis_types/controls/heatmap_options'; -import 'plugins/kbn_vislib_vis_types/controls/point_series'; import { CUSTOM_LEGEND_VIS_TYPES } from './vislib_vis_legend'; import { BaseVisType } from './base_vis_type'; import VislibProvider from '../../vislib'; diff --git a/test/functional/apps/visualize/_point_series_options.js b/test/functional/apps/visualize/_point_series_options.js index 61ea45cdc2e02..d175acbd6c02e 100644 --- a/test/functional/apps/visualize/_point_series_options.js +++ b/test/functional/apps/visualize/_point_series_options.js @@ -58,7 +58,7 @@ export default function ({ getService, getPageObjects }) { log.debug('adding axis'); await pointSeriesVis.clickAddAxis(); // set average count to use second value axis - await pointSeriesVis.toggleCollapsibleTitle('Average machine.ram'); + await PageObjects.visualize.toggleAccordion('visEditorSeriesAccordion3'); log.debug('Average memory value axis - ValueAxis-2'); await pointSeriesVis.setSeriesAxis(1, 'ValueAxis-2'); await PageObjects.visualize.waitForVisualizationRenderingStabilized(); @@ -107,8 +107,7 @@ export default function ({ getService, getPageObjects }) { describe('multiple chart types', function () { it('should change average series type to histogram', async function () { - await pointSeriesVis.toggleCollapsibleTitle('RightAxis-1'); - await pointSeriesVis.setSeriesType(1, 'bar'); + await pointSeriesVis.setSeriesType(1, 'histogram'); await PageObjects.visualize.clickGo(); const length = await pointSeriesVis.getHistogramSeries(); expect(length).to.be(1); diff --git a/test/functional/page_objects/point_series_page.js b/test/functional/page_objects/point_series_page.js index 371913f87fde7..20672cc9e972c 100644 --- a/test/functional/page_objects/point_series_page.js +++ b/test/functional/page_objects/point_series_page.js @@ -24,11 +24,11 @@ export function PointSeriesPageProvider({ getService }) { class PointSeriesVis { async clickOptions() { - return await find.clickByPartialLinkText('Panel Settings'); + return await find.clickByPartialLinkText('Panel settings'); } async clickAxisOptions() { - return await find.clickByPartialLinkText('Metrics & Axes'); + return await find.clickByPartialLinkText('Metrics & axes'); } async clickAddAxis() { @@ -36,7 +36,7 @@ export function PointSeriesPageProvider({ getService }) { } async setAxisTitle(title, { index = 0 } = {}) { - return await find.setValue(`#valueAxisTitle${index}`, title); + return await testSubjects.setValue(`valueAxisTitle${index}`, title); } async getValueAxesCount() { @@ -103,11 +103,11 @@ export function PointSeriesPageProvider({ getService }) { } async setValueAxisPosition(axis, position) { - await find.clickByCssSelector(`select#valueAxisPosition${axis} option[label="${position}"]`); + await find.clickByCssSelector(`select#valueAxisPosition${axis} option[value="${position}"]`); } async setCategoryAxisPosition(newValue) { - await find.clickByCssSelector(`select#categoryAxisPosition option[label="${newValue}"]`); + await find.clickByCssSelector(`select#categoryAxisPosition option[value="${newValue}"]`); } async setSeriesAxis(series, axis) { @@ -115,7 +115,7 @@ export function PointSeriesPageProvider({ getService }) { } async setSeriesType(series, type) { - await find.clickByCssSelector(`select#seriesType${series} option[label="${type}"]`); + await find.clickByCssSelector(`select#seriesType${series} option[value="${type}"]`); } } diff --git a/test/functional/page_objects/visualize_page.js b/test/functional/page_objects/visualize_page.js index 7886fcae2e5ff..d4b5c820a0d5b 100644 --- a/test/functional/page_objects/visualize_page.js +++ b/test/functional/page_objects/visualize_page.js @@ -481,11 +481,15 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli async toggleOpenEditor(index, toState = 'true') { // index, see selectYAxisAggregation - const toggle = await find.byCssSelector(`button[aria-controls="visEditorAggAccordion${index}"]`); + await this.toggleAccordion(`visEditorAggAccordion${index}`, toState); + } + + async toggleAccordion(id, toState = 'true') { + const toggle = await find.byCssSelector(`button[aria-controls="${id}"]`); const toggleOpen = await toggle.getAttribute('aria-expanded'); - log.debug(`toggle ${index} expand = ${toggleOpen}`); + log.debug(`toggle ${id} expand = ${toggleOpen}`); if (toggleOpen !== toState) { - log.debug(`toggle ${index} click()`); + log.debug(`toggle ${id} click()`); await toggle.click(); } } @@ -514,34 +518,13 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli customLabel.type(label); } - async setAxisExtents(min, max, axis = 'LeftAxis-1') { - const axisOptions = await find.byCssSelector(`div[aria-label="Toggle ${axis} options"]`); - const isOpen = await axisOptions.getAttribute('aria-expanded'); - if (isOpen === 'false') { - log.debug(`click to open ${axis} options`); - await axisOptions.click(); - } - // it would be nice to get the correct axis by name like "LeftAxis-1" - // instead of an incremented index, but this link isn't under the div above - const advancedLink = - await find.byCssSelector(`#axisOptionsValueAxis-1 .visEditorSidebar__advancedLinkIcon`); - - const advancedLinkState = await advancedLink.getAttribute('type'); - if (advancedLinkState.includes('arrowRight')) { - await advancedLink.moveMouseTo(); - log.debug('click advancedLink'); - await advancedLink.click(); - } - const checkbox = await find.byCssSelector('input[ng-model="axis.scale.setYExtents"]'); - const checkboxState = await checkbox.getAttribute('class'); - if (checkboxState.includes('ng-empty')) { - await checkbox.moveMouseTo(); - await checkbox.click(); - } - const maxField = await find.byCssSelector('[ng-model="axis.scale.max"]'); - await maxField.type(max); - const minField = await find.byCssSelector('[ng-model="axis.scale.min"]'); - await minField.type(min); + async setAxisExtents(min, max, axisId = 'ValueAxis-1') { + await this.toggleAccordion(`yAxisAccordion${axisId}`); + await this.toggleAccordion(`yAxisOptionsAccordion${axisId}`); + + await testSubjects.click('yAxisSetYExtents'); + await testSubjects.setValue('yAxisYExtentsMax', max); + await testSubjects.setValue('yAxisYExtentsMin', min); } @@ -699,18 +682,18 @@ export function VisualizePageProvider({ getService, getPageObjects, updateBaseli } async selectChartMode(mode) { - const selector = await find.byCssSelector(`#seriesMode0 > option[label="${mode}"]`); + const selector = await find.byCssSelector(`#seriesMode0 > option[value="${mode}"]`); await selector.click(); } async selectYAxisScaleType(axisId, scaleType) { const selectElement = await testSubjects.find(`scaleSelectYAxis-${axisId}`); - const selector = await selectElement.findByCssSelector(`option[label="${scaleType}"]`); + const selector = await selectElement.findByCssSelector(`option[value="${scaleType}"]`); await selector.click(); } async selectYAxisMode(mode) { - const selector = await find.byCssSelector(`#valueAxisMode0 > option[label="${mode}"]`); + const selector = await find.byCssSelector(`#valueAxisMode0 > option[value="${mode}"]`); await selector.click(); } diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 8320298fca25a..8139dacd1bcdf 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -2501,14 +2501,9 @@ "kbnVislibVisTypes.controls.heatmapOptions.specifiedRangeNumberWarningMessage": "{icon}{required} 範囲を最低 1 つ指定する必要があります。", "kbnVislibVisTypes.controls.heatmapOptions.toLabel": "終了:", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.filterLabelsLabel": "フィルターラベル", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.hideAdvancedOptionsLabel": "高度なオプションを非表示", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.labelsTitle": "ラベル", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.positionLabel": "配置", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.rotateLabel": "回転", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.showAdvancedOptionsLabel": "高度なオプションを表示", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.showLabel": "表示", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.showLabelsLabel": "ラベルを表示", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.truncateLabel": "切り捨て", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.xAxisTitle": "X 軸", "kbnVislibVisTypes.controls.pointSeries.gridAxis.dontShowLabel": "非表示", "kbnVislibVisTypes.controls.pointSeries.gridAxis.gridText": "グリッド", @@ -2520,27 +2515,17 @@ "kbnVislibVisTypes.controls.pointSeries.series.metricsTitle": "メトリック", "kbnVislibVisTypes.controls.pointSeries.series.modeLabel": "モード", "kbnVislibVisTypes.controls.pointSeries.series.newAxisLabel": "新規軸…", - "kbnVislibVisTypes.controls.pointSeries.series.showCirclesLabel": "円を表示", "kbnVislibVisTypes.controls.pointSeries.series.showLineLabel": "線を表示", "kbnVislibVisTypes.controls.pointSeries.series.valueAxisLabel": "値軸", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.customExtentsTitle": "カスタム範囲", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.filterLabelsLabel": "フィルターラベル", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.hideAdvancedOptionsLabel": "高度なオプションを非表示", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.labelsTitle": "ラベル", "kbnVislibVisTypes.controls.pointSeries.valueAxes.maxLabel": "最高", "kbnVislibVisTypes.controls.pointSeries.valueAxes.minLabel": "最低", "kbnVislibVisTypes.controls.pointSeries.valueAxes.minNeededScaleText": "ログスケールが選択されている場合、最低値は 0 よりも大きいものである必要があります", "kbnVislibVisTypes.controls.pointSeries.valueAxes.modeLabel": "モード", "kbnVislibVisTypes.controls.pointSeries.valueAxes.positionLabel": "配置", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.rotateLabel": "回転", "kbnVislibVisTypes.controls.pointSeries.valueAxes.scaleToDataBoundsLabel": "データバウンドに合わせる", "kbnVislibVisTypes.controls.pointSeries.valueAxes.scaleTypeLabel": "スケールタイプ", "kbnVislibVisTypes.controls.pointSeries.valueAxes.setAxisExtentsLabel": "軸の範囲の設定", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.showAdvancedOptionsLabel": "高度なオプションを表示", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.showLabel": "表示", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.showLabelsLabel": "ラベルを表示", "kbnVislibVisTypes.controls.pointSeries.valueAxes.titleLabel": "タイトル", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.truncateLabel": "切り捨て", "kbnVislibVisTypes.controls.pointSeries.valueAxes.yAxisTitle": "Y 軸", "kbnVislibVisTypes.editors.heatmap.basicSettingsTitle": "基本設定", "kbnVislibVisTypes.editors.heatmap.heatmapSettingsTitle": "ヒートマップ設定", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index b666233c45a9b..56049d7ccbf3e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -2502,14 +2502,9 @@ "kbnVislibVisTypes.controls.heatmapOptions.specifiedRangeNumberWarningMessage": "{icon} {required}您必须指定至少一个范围。", "kbnVislibVisTypes.controls.heatmapOptions.toLabel": "到", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.filterLabelsLabel": "筛选标签", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.hideAdvancedOptionsLabel": "隐藏高级选项", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.labelsTitle": "标签", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.positionLabel": "位置", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.rotateLabel": "旋转", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.showAdvancedOptionsLabel": "显示高级选项", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.showLabel": "显示", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.showLabelsLabel": "显示标签", - "kbnVislibVisTypes.controls.pointSeries.categoryAxis.truncateLabel": "截断", "kbnVislibVisTypes.controls.pointSeries.categoryAxis.xAxisTitle": "X 轴", "kbnVislibVisTypes.controls.pointSeries.gridAxis.dontShowLabel": "不显示", "kbnVislibVisTypes.controls.pointSeries.gridAxis.gridText": "网格", @@ -2521,27 +2516,17 @@ "kbnVislibVisTypes.controls.pointSeries.series.metricsTitle": "指标", "kbnVislibVisTypes.controls.pointSeries.series.modeLabel": "模式", "kbnVislibVisTypes.controls.pointSeries.series.newAxisLabel": "新建轴…...", - "kbnVislibVisTypes.controls.pointSeries.series.showCirclesLabel": "显示为圆圈", "kbnVislibVisTypes.controls.pointSeries.series.showLineLabel": "显示为线条", "kbnVislibVisTypes.controls.pointSeries.series.valueAxisLabel": "值轴", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.customExtentsTitle": "定制范围", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.filterLabelsLabel": "筛选标签", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.hideAdvancedOptionsLabel": "隐藏高级选项", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.labelsTitle": "标签", "kbnVislibVisTypes.controls.pointSeries.valueAxes.maxLabel": "最大值", "kbnVislibVisTypes.controls.pointSeries.valueAxes.minLabel": "最小值", "kbnVislibVisTypes.controls.pointSeries.valueAxes.minNeededScaleText": "如果选择了对数刻度,最小值必须大于 0", "kbnVislibVisTypes.controls.pointSeries.valueAxes.modeLabel": "模式", "kbnVislibVisTypes.controls.pointSeries.valueAxes.positionLabel": "位置", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.rotateLabel": "旋转", "kbnVislibVisTypes.controls.pointSeries.valueAxes.scaleToDataBoundsLabel": "缩放到数据边界", "kbnVislibVisTypes.controls.pointSeries.valueAxes.scaleTypeLabel": "缩放类型", "kbnVislibVisTypes.controls.pointSeries.valueAxes.setAxisExtentsLabel": "设置轴范围", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.showAdvancedOptionsLabel": "显示高级选项", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.showLabel": "显示", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.showLabelsLabel": "显示标签", "kbnVislibVisTypes.controls.pointSeries.valueAxes.titleLabel": "标题", - "kbnVislibVisTypes.controls.pointSeries.valueAxes.truncateLabel": "截断", "kbnVislibVisTypes.controls.pointSeries.valueAxes.yAxisTitle": "Y 轴", "kbnVislibVisTypes.editors.heatmap.basicSettingsTitle": "基本设置", "kbnVislibVisTypes.editors.heatmap.heatmapSettingsTitle": "热图设置",