diff --git a/src/plugins/vis_type_timeseries/common/types.ts b/src/plugins/vis_type_timeseries/common/types.ts new file mode 100644 index 00000000000000..4520069244527b --- /dev/null +++ b/src/plugins/vis_type_timeseries/common/types.ts @@ -0,0 +1,25 @@ +/* + * Licensed to Elasticsearch B.V. under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch B.V. licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { TypeOf } from '@kbn/config-schema'; +import { metricsItems, panel, seriesItems } from './vis_schema'; + +export type SeriesItemsSchema = TypeOf; +export type MetricsItemsSchema = TypeOf; +export type PanelSchema = TypeOf; diff --git a/src/plugins/vis_type_timeseries/common/ui_restrictions.js b/src/plugins/vis_type_timeseries/common/ui_restrictions.ts similarity index 73% rename from src/plugins/vis_type_timeseries/common/ui_restrictions.js rename to src/plugins/vis_type_timeseries/common/ui_restrictions.ts index 96726d51e4a7c9..4508735f39ff90 100644 --- a/src/plugins/vis_type_timeseries/common/ui_restrictions.js +++ b/src/plugins/vis_type_timeseries/common/ui_restrictions.ts @@ -22,21 +22,30 @@ * @constant * @public */ -export const RESTRICTIONS_KEYS = { +export enum RESTRICTIONS_KEYS { /** * Key for getting the white listed group by fields from the UIRestrictions object. */ - WHITE_LISTED_GROUP_BY_FIELDS: 'whiteListedGroupByFields', + WHITE_LISTED_GROUP_BY_FIELDS = 'whiteListedGroupByFields', /** * Key for getting the white listed metrics from the UIRestrictions object. */ - WHITE_LISTED_METRICS: 'whiteListedMetrics', + WHITE_LISTED_METRICS = 'whiteListedMetrics', /** * Key for getting the white listed Time Range modes from the UIRestrictions object. */ - WHITE_LISTED_TIMERANGE_MODES: 'whiteListedTimerangeModes', + WHITE_LISTED_TIMERANGE_MODES = 'whiteListedTimerangeModes', +} + +export interface UIRestrictions { + '*': boolean; + [restriction: string]: boolean; +} + +export type TimeseriesUIRestrictions = { + [key in RESTRICTIONS_KEYS]: Record; }; /** @@ -44,6 +53,6 @@ export const RESTRICTIONS_KEYS = { * @constant * @public */ -export const DEFAULT_UI_RESTRICTION = { +export const DEFAULT_UI_RESTRICTION: UIRestrictions = { '*': true, }; diff --git a/src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts b/src/plugins/vis_type_timeseries/common/vis_schema.ts similarity index 73% rename from src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts rename to src/plugins/vis_type_timeseries/common/vis_schema.ts index bf2ea8651c5a2c..7161c197b69409 100644 --- a/src/plugins/vis_type_timeseries/server/routes/post_vis_schema.ts +++ b/src/plugins/vis_type_timeseries/common/vis_schema.ts @@ -76,7 +76,7 @@ const gaugeColorRulesItems = schema.object({ operator: stringOptionalNullable, value: schema.maybe(schema.nullable(schema.number())), }); -const metricsItems = schema.object({ +export const metricsItems = schema.object({ field: stringOptionalNullable, id: stringRequired, metric_agg: stringOptionalNullable, @@ -133,7 +133,7 @@ const splitFiltersItems = schema.object({ label: stringOptionalNullable, }); -const seriesItems = schema.object({ +export const seriesItems = schema.object({ aggregate_by: stringOptionalNullable, aggregate_function: stringOptionalNullable, axis_position: stringRequired, @@ -195,66 +195,66 @@ const seriesItems = schema.object({ var_name: stringOptionalNullable, }); +export const panel = schema.object({ + annotations: schema.maybe(schema.arrayOf(annotationsItems)), + axis_formatter: stringRequired, + axis_position: stringRequired, + axis_scale: stringRequired, + axis_min: stringOrNumberOptionalNullable, + axis_max: stringOrNumberOptionalNullable, + bar_color_rules: schema.maybe(arrayNullable), + background_color: stringOptionalNullable, + background_color_rules: schema.maybe(schema.arrayOf(backgroundColorRulesItems)), + default_index_pattern: stringOptionalNullable, + default_timefield: stringOptionalNullable, + drilldown_url: stringOptionalNullable, + drop_last_bucket: numberIntegerOptional, + filter: schema.nullable( + schema.oneOf([ + stringOptionalNullable, + schema.object({ + language: stringOptionalNullable, + query: stringOptionalNullable, + }), + ]) + ), + gauge_color_rules: schema.maybe(schema.arrayOf(gaugeColorRulesItems)), + gauge_width: schema.nullable(schema.oneOf([stringOptionalNullable, numberOptional])), + gauge_inner_color: stringOptionalNullable, + gauge_inner_width: stringOrNumberOptionalNullable, + gauge_style: stringOptionalNullable, + gauge_max: stringOrNumberOptionalNullable, + id: stringRequired, + ignore_global_filters: numberOptional, + ignore_global_filter: numberOptional, + index_pattern: stringRequired, + interval: stringRequired, + isModelInvalid: schema.maybe(schema.boolean()), + legend_position: stringOptionalNullable, + markdown: stringOptionalNullable, + markdown_scrollbars: numberIntegerOptional, + markdown_openLinksInNewTab: numberIntegerOptional, + markdown_vertical_align: stringOptionalNullable, + markdown_less: stringOptionalNullable, + markdown_css: stringOptionalNullable, + pivot_id: stringOptionalNullable, + pivot_label: stringOptionalNullable, + pivot_type: stringOptionalNullable, + pivot_rows: stringOptionalNullable, + series: schema.arrayOf(seriesItems), + show_grid: numberIntegerRequired, + show_legend: numberIntegerRequired, + tooltip_mode: schema.maybe( + schema.oneOf([schema.literal('show_all'), schema.literal('show_focused')]) + ), + time_field: stringOptionalNullable, + time_range_mode: stringOptionalNullable, + type: stringRequired, +}); + export const visPayloadSchema = schema.object({ filters: arrayNullable, - panels: schema.arrayOf( - schema.object({ - annotations: schema.maybe(schema.arrayOf(annotationsItems)), - axis_formatter: stringRequired, - axis_position: stringRequired, - axis_scale: stringRequired, - axis_min: stringOrNumberOptionalNullable, - axis_max: stringOrNumberOptionalNullable, - bar_color_rules: schema.maybe(arrayNullable), - background_color: stringOptionalNullable, - background_color_rules: schema.maybe(schema.arrayOf(backgroundColorRulesItems)), - default_index_pattern: stringOptionalNullable, - default_timefield: stringOptionalNullable, - drilldown_url: stringOptionalNullable, - drop_last_bucket: numberIntegerOptional, - filter: schema.nullable( - schema.oneOf([ - stringOptionalNullable, - schema.object({ - language: stringOptionalNullable, - query: stringOptionalNullable, - }), - ]) - ), - gauge_color_rules: schema.maybe(schema.arrayOf(gaugeColorRulesItems)), - gauge_width: schema.nullable(schema.oneOf([stringOptionalNullable, numberOptional])), - gauge_inner_color: stringOptionalNullable, - gauge_inner_width: stringOrNumberOptionalNullable, - gauge_style: stringOptionalNullable, - gauge_max: stringOrNumberOptionalNullable, - id: stringRequired, - ignore_global_filters: numberOptional, - ignore_global_filter: numberOptional, - index_pattern: stringRequired, - interval: stringRequired, - isModelInvalid: schema.maybe(schema.boolean()), - legend_position: stringOptionalNullable, - markdown: stringOptionalNullable, - markdown_scrollbars: numberIntegerOptional, - markdown_openLinksInNewTab: numberIntegerOptional, - markdown_vertical_align: stringOptionalNullable, - markdown_less: stringOptionalNullable, - markdown_css: stringOptionalNullable, - pivot_id: stringOptionalNullable, - pivot_label: stringOptionalNullable, - pivot_type: stringOptionalNullable, - pivot_rows: stringOptionalNullable, - series: schema.arrayOf(seriesItems), - show_grid: numberIntegerRequired, - show_legend: numberIntegerRequired, - tooltip_mode: schema.maybe( - schema.oneOf([schema.literal('show_all'), schema.literal('show_focused')]) - ), - time_field: stringOptionalNullable, - time_range_mode: stringOptionalNullable, - type: stringRequired, - }) - ), + panels: schema.arrayOf(panel), // general query: schema.nullable(schema.arrayOf(queryObject)), state: schema.object({ diff --git a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.js b/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.tsx similarity index 77% rename from src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.js rename to src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.tsx index 7afa71d6ba38ff..0fb3e80344e2bf 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.js +++ b/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.test.tsx @@ -18,51 +18,49 @@ */ import React from 'react'; -import { expect } from 'chai'; import { shallowWithIntl } from 'test_utils/enzyme_helpers'; -import sinon from 'sinon'; import { AddDeleteButtons } from './add_delete_buttons'; describe('AddDeleteButtons', () => { it('calls onAdd={handleAdd}', () => { - const handleAdd = sinon.spy(); + const handleAdd = jest.fn(); const wrapper = shallowWithIntl(); wrapper.find('EuiButtonIcon').at(0).simulate('click'); - expect(handleAdd.calledOnce).to.equal(true); + expect(handleAdd).toHaveBeenCalled(); }); it('calls onDelete={handleDelete}', () => { - const handleDelete = sinon.spy(); + const handleDelete = jest.fn(); const wrapper = shallowWithIntl(); wrapper.find('EuiButtonIcon').at(1).simulate('click'); - expect(handleDelete.calledOnce).to.equal(true); + expect(handleDelete).toHaveBeenCalled(); }); it('calls onClone={handleClone}', () => { - const handleClone = sinon.spy(); + const handleClone = jest.fn(); const wrapper = shallowWithIntl(); wrapper.find('EuiButtonIcon').at(0).simulate('click'); - expect(handleClone.calledOnce).to.equal(true); + expect(handleClone).toHaveBeenCalled(); }); it('disableDelete={true}', () => { const wrapper = shallowWithIntl(); - expect(wrapper.find({ text: 'Delete' })).to.have.length(0); + expect(wrapper.find({ text: 'Delete' })).toHaveLength(0); }); it('disableAdd={true}', () => { const wrapper = shallowWithIntl(); - expect(wrapper.find({ text: 'Add' })).to.have.length(0); + expect(wrapper.find({ text: 'Add' })).toHaveLength(0); }); it('should not display clone by default', () => { const wrapper = shallowWithIntl(); - expect(wrapper.find({ text: 'Clone' })).to.have.length(0); + expect(wrapper.find({ text: 'Clone' })).toHaveLength(0); }); it('should not display clone when disableAdd={true}', () => { - const fn = sinon.spy(); + const fn = jest.fn(); const wrapper = shallowWithIntl(); - expect(wrapper.find({ text: 'Clone' })).to.have.length(0); + expect(wrapper.find({ text: 'Clone' })).toHaveLength(0); }); }); diff --git a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.js b/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.tsx similarity index 87% rename from src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.js rename to src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.tsx index 798d16947c3d9c..7502de1cb1aa49 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.js +++ b/src/plugins/vis_type_timeseries/public/application/components/add_delete_buttons.tsx @@ -17,13 +17,29 @@ * under the License. */ -import PropTypes from 'prop-types'; -import React from 'react'; -import { EuiToolTip, EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import React, { MouseEvent } from 'react'; +import { EuiButtonIcon, EuiFlexGroup, EuiFlexItem, EuiToolTip } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { isBoolean } from 'lodash'; -export function AddDeleteButtons(props) { +interface AddDeleteButtonsProps { + addTooltip: string; + deleteTooltip: string; + cloneTooltip: string; + activatePanelTooltip: string; + deactivatePanelTooltip: string; + isPanelActive?: boolean; + disableAdd?: boolean; + disableDelete?: boolean; + responsive?: boolean; + testSubj: string; + togglePanelActivation?: () => void; + onClone?: () => void; + onAdd?: () => void; + onDelete?: (event: MouseEvent) => void; +} + +export function AddDeleteButtons(props: AddDeleteButtonsProps) { const { testSubj } = props; const createDelete = () => { if (props.disableDelete) { @@ -147,19 +163,3 @@ AddDeleteButtons.defaultProps = { } ), }; - -AddDeleteButtons.propTypes = { - addTooltip: PropTypes.string, - deleteTooltip: PropTypes.string, - cloneTooltip: PropTypes.string, - activatePanelTooltip: PropTypes.string, - deactivatePanelTooltip: PropTypes.string, - togglePanelActivation: PropTypes.func, - isPanelActive: PropTypes.bool, - disableAdd: PropTypes.bool, - disableDelete: PropTypes.bool, - onClone: PropTypes.func, - onAdd: PropTypes.func, - onDelete: PropTypes.func, - responsive: PropTypes.bool, -}; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg.tsx similarity index 70% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg.js rename to src/plugins/vis_type_timeseries/public/application/components/aggs/agg.tsx index d547f64f13f672..e5236c3833b19b 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg.tsx @@ -17,15 +17,33 @@ * under the License. */ -import PropTypes from 'prop-types'; -import React from 'react'; +import React, { HTMLAttributes } from 'react'; +// @ts-ignore import { aggToComponent } from '../lib/agg_to_component'; +// @ts-ignore +import { isMetricEnabled } from '../../lib/check_ui_restrictions'; import { UnsupportedAgg } from './unsupported_agg'; import { TemporaryUnsupportedAgg } from './temporary_unsupported_agg'; +import { MetricsItemsSchema, PanelSchema, SeriesItemsSchema } from '../../../../common/types'; +import { DragHandleProps } from '../../../types'; +import { TimeseriesUIRestrictions } from '../../../../common/ui_restrictions'; +import { IFieldType } from '../../../../../data/common/index_patterns/fields'; -import { isMetricEnabled } from '../../lib/check_ui_restrictions'; +interface AggProps extends HTMLAttributes { + disableDelete: boolean; + fields: IFieldType[]; + model: MetricsItemsSchema; + panel: PanelSchema; + series: SeriesItemsSchema; + siblings: MetricsItemsSchema[]; + uiRestrictions: TimeseriesUIRestrictions; + dragHandleProps: DragHandleProps; + onAdd: () => void; + onChange: () => void; + onDelete: () => void; +} -export function Agg(props) { +export function Agg(props: AggProps) { const { model, uiRestrictions } = props; let Component = aggToComponent[model.type]; @@ -59,17 +77,3 @@ export function Agg(props) { ); } - -Agg.propTypes = { - disableDelete: PropTypes.bool, - fields: PropTypes.object, - model: PropTypes.object, - onAdd: PropTypes.func, - onChange: PropTypes.func, - onDelete: PropTypes.func, - panel: PropTypes.object, - series: PropTypes.object, - siblings: PropTypes.array, - uiRestrictions: PropTypes.object, - dragHandleProps: PropTypes.object, -}; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.tsx similarity index 86% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.js rename to src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.tsx index a2f1640904dd02..0363ba486a7753 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_row.tsx @@ -17,15 +17,26 @@ * under the License. */ -import PropTypes from 'prop-types'; import React from 'react'; import { last } from 'lodash'; -import { AddDeleteButtons } from '../add_delete_buttons'; import { EuiIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; -import { SeriesDragHandler } from '../series_drag_handler'; import { i18n } from '@kbn/i18n'; +import { AddDeleteButtons } from '../add_delete_buttons'; +import { SeriesDragHandler } from '../series_drag_handler'; +import { MetricsItemsSchema } from '../../../../common/types'; +import { DragHandleProps } from '../../../types'; -export function AggRow(props) { +interface AggRowProps { + disableDelete: boolean; + model: MetricsItemsSchema; + siblings: MetricsItemsSchema[]; + dragHandleProps: DragHandleProps; + children: React.ReactNode; + onAdd: () => void; + onDelete: () => void; +} + +export function AggRow(props: AggRowProps) { let iconType = 'eyeClosed'; let iconColor = 'subdued'; const lastSibling = last(props.siblings); @@ -71,12 +82,3 @@ export function AggRow(props) { ); } - -AggRow.propTypes = { - disableDelete: PropTypes.bool, - model: PropTypes.object, - onAdd: PropTypes.func, - onDelete: PropTypes.func, - siblings: PropTypes.array, - dragHandleProps: PropTypes.object, -}; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.tsx similarity index 88% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.js rename to src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.tsx index 7ff6b6eb566922..6fa1a2adaa08e9 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/agg_select.tsx @@ -17,14 +17,17 @@ * under the License. */ -import PropTypes from 'prop-types'; import React from 'react'; -import { EuiComboBox } from '@elastic/eui'; +import { EuiComboBox, EuiComboBoxOptionOption } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; -import { injectI18n } from '@kbn/i18n/react'; +// @ts-ignore import { isMetricEnabled } from '../../lib/check_ui_restrictions'; +import { MetricsItemsSchema } from '../../../../common/types'; +import { TimeseriesUIRestrictions } from '../../../../common/ui_restrictions'; -const metricAggs = [ +type AggSelectOption = EuiComboBoxOptionOption; + +const metricAggs: AggSelectOption[] = [ { label: i18n.translate('visTypeTimeseries.aggSelect.metricsAggs.averageLabel', { defaultMessage: 'Average', @@ -123,7 +126,7 @@ const metricAggs = [ }, ]; -const pipelineAggs = [ +const pipelineAggs: AggSelectOption[] = [ { label: i18n.translate('visTypeTimeseries.aggSelect.pipelineAggs.bucketScriptLabel', { defaultMessage: 'Bucket Script', @@ -162,7 +165,7 @@ const pipelineAggs = [ }, ]; -const siblingAggs = [ +const siblingAggs: AggSelectOption[] = [ { label: i18n.translate('visTypeTimeseries.aggSelect.siblingAggs.overallAverageLabel', { defaultMessage: 'Overall Average', @@ -207,7 +210,7 @@ const siblingAggs = [ }, ]; -const specialAggs = [ +const specialAggs: AggSelectOption[] = [ { label: i18n.translate('visTypeTimeseries.aggSelect.specialAggs.seriesAggLabel', { defaultMessage: 'Series Agg', @@ -224,14 +227,23 @@ const specialAggs = [ const allAggOptions = [...metricAggs, ...pipelineAggs, ...siblingAggs, ...specialAggs]; -function filterByPanelType(panelType) { - return (agg) => { +function filterByPanelType(panelType: string) { + return (agg: AggSelectOption) => { if (panelType === 'table') return agg.value !== 'series_agg'; return true; }; } -function AggSelectUi(props) { +interface AggSelectUiProps { + id: string; + panelType: string; + siblings: MetricsItemsSchema[]; + value: string; + uiRestrictions?: TimeseriesUIRestrictions; + onChange: (currentlySelectedOptions: AggSelectOption[]) => void; +} + +export function AggSelect(props: AggSelectUiProps) { const { siblings, panelType, value, onChange, uiRestrictions, ...rest } = props; const selectedOptions = allAggOptions.filter((option) => { @@ -242,11 +254,11 @@ function AggSelectUi(props) { if (siblings.length <= 1) enablePipelines = false; - let options; + let options: EuiComboBoxOptionOption[]; if (panelType === 'metrics') { options = metricAggs; } else { - const disableSiblingAggs = (agg) => ({ + const disableSiblingAggs = (agg: AggSelectOption) => ({ ...agg, disabled: !enablePipelines || !isMetricEnabled(agg.value, uiRestrictions), }); @@ -282,9 +294,9 @@ function AggSelectUi(props) { ]; } - const handleChange = (selectedOptions) => { - if (!selectedOptions || selectedOptions.length <= 0) return; - onChange(selectedOptions); + const handleChange = (currentlySelectedOptions: AggSelectOption[]) => { + if (!currentlySelectedOptions || currentlySelectedOptions.length <= 0) return; + onChange(currentlySelectedOptions); }; return ( @@ -303,13 +315,3 @@ function AggSelectUi(props) { ); } - -AggSelectUi.propTypes = { - onChange: PropTypes.func, - panelType: PropTypes.string, - siblings: PropTypes.array, - value: PropTypes.string, - uiRestrictions: PropTypes.object, -}; - -export const AggSelect = injectI18n(AggSelectUi); diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/aggs.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/aggs.tsx similarity index 83% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/aggs.js rename to src/plugins/vis_type_timeseries/public/application/components/aggs/aggs.tsx index 772b62b14f8112..af3e42a59612b6 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/aggs.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/aggs.tsx @@ -18,18 +18,29 @@ */ import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; import { EuiDraggable, EuiDroppable } from '@elastic/eui'; import { Agg } from './agg'; -import { newMetricAggFn } from '../lib/new_metric_agg_fn'; +// @ts-ignore import { seriesChangeHandler } from '../lib/series_change_handler'; +// @ts-ignore import { handleAdd, handleDelete } from '../lib/collection_actions'; +import { newMetricAggFn } from '../lib/new_metric_agg_fn'; +import { PanelSchema, SeriesItemsSchema } from '../../../../common/types'; +import { TimeseriesUIRestrictions } from '../../../../common/ui_restrictions'; +import { IFieldType } from '../../../../../data/common/index_patterns/fields'; const DROPPABLE_ID = 'aggs_dnd'; -export class Aggs extends PureComponent { +export interface AggsProps { + panel: PanelSchema; + model: SeriesItemsSchema; + fields: IFieldType[]; + uiRestrictions: TimeseriesUIRestrictions; +} + +export class Aggs extends PureComponent { render() { const { panel, model, fields, uiRestrictions } = this.props; const list = model.metrics; @@ -68,12 +79,3 @@ export class Aggs extends PureComponent { ); } } - -Aggs.propTypes = { - name: PropTypes.string.isRequired, - fields: PropTypes.object.isRequired, - model: PropTypes.object.isRequired, - onChange: PropTypes.func.isRequired, - panel: PropTypes.object.isRequired, - dragHandleProps: PropTypes.object, -}; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.tsx similarity index 79% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.js rename to src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.tsx index fd64559cc1ec22..ef8876a19b1a65 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/multi_value_row.tsx @@ -16,8 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -import PropTypes from 'prop-types'; -import React from 'react'; +import React, { ChangeEvent } from 'react'; import { get } from 'lodash'; import { FormattedMessage } from '@kbn/i18n/react'; import { @@ -31,10 +30,29 @@ import { import { AddDeleteButtons } from '../../add_delete_buttons'; -export const MultiValueRow = ({ model, onChange, onDelete, onAdd, disableAdd, disableDelete }) => { +interface MultiValueRowProps { + model: { + id: number; + value: string; + }; + disableAdd: boolean; + disableDelete: boolean; + onChange: ({ value, id }: { id: number; value: string }) => void; + onDelete: (model: { id: number; value: string }) => void; + onAdd: () => void; +} + +export const MultiValueRow = ({ + model, + onChange, + onDelete, + onAdd, + disableAdd, + disableDelete, +}: MultiValueRowProps) => { const htmlId = htmlIdGenerator(); - const onFieldNumberChange = (event) => + const onFieldNumberChange = (event: ChangeEvent) => onChange({ ...model, value: get(event, 'target.value'), @@ -54,7 +72,7 @@ export const MultiValueRow = ({ model, onChange, onDelete, onAdd, disableAdd, di @@ -78,12 +96,3 @@ MultiValueRow.defaultProps = { value: '', }, }; - -MultiValueRow.propTypes = { - model: PropTypes.object, - onChange: PropTypes.func, - onDelete: PropTypes.func, - onAdd: PropTypes.func, - defaultAddValue: PropTypes.string, - disableDelete: PropTypes.bool, -}; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank.tsx similarity index 75% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank.js rename to src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank.tsx index c8af4089ed7837..a16f5aeefc49c5 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank.tsx @@ -17,16 +17,7 @@ * under the License. */ -import PropTypes from 'prop-types'; import React from 'react'; -import { assign } from 'lodash'; -import { AggSelect } from '../agg_select'; -import { FieldSelect } from '../field_select'; -import { AggRow } from '../agg_row'; -import { createChangeHandler } from '../../lib/create_change_handler'; -import { createSelectHandler } from '../../lib/create_select_handler'; -import { PercentileRankValues } from './percentile_rank_values'; - import { htmlIdGenerator, EuiFlexGroup, @@ -36,11 +27,36 @@ import { EuiSpacer, } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; -import { KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { AggSelect } from '../agg_select'; +// @ts-ignore +import { FieldSelect } from '../field_select'; +// @ts-ignore +import { createChangeHandler } from '../../lib/create_change_handler'; +// @ts-ignore +import { createSelectHandler } from '../../lib/create_select_handler'; +import { AggRow } from '../agg_row'; +import { PercentileRankValues } from './percentile_rank_values'; + +import { IFieldType, KBN_FIELD_TYPES } from '../../../../../../../plugins/data/public'; +import { MetricsItemsSchema, PanelSchema, SeriesItemsSchema } from '../../../../../common/types'; +import { DragHandleProps } from '../../../../types'; const RESTRICT_FIELDS = [KBN_FIELD_TYPES.NUMBER]; -export const PercentileRankAgg = (props) => { +interface PercentileRankAggProps { + disableDelete: boolean; + fields: IFieldType[]; + model: MetricsItemsSchema; + panel: PanelSchema; + series: SeriesItemsSchema; + siblings: MetricsItemsSchema[]; + dragHandleProps: DragHandleProps; + onAdd(): void; + onChange(): void; + onDelete(): void; +} + +export const PercentileRankAgg = (props: PercentileRankAggProps) => { const { series, panel, fields } = props; const defaults = { values: [''] }; const model = { ...defaults, ...props.model }; @@ -52,12 +68,11 @@ export const PercentileRankAgg = (props) => { const handleChange = createChangeHandler(props.onChange, model); const handleSelectChange = createSelectHandler(handleChange); - const handlePercentileRankValuesChange = (values) => { - handleChange( - assign({}, model, { - values, - }) - ); + const handlePercentileRankValuesChange = (values: MetricsItemsSchema['values']) => { + handleChange({ + ...model, + values, + }); }; return ( @@ -108,25 +123,15 @@ export const PercentileRankAgg = (props) => { - + {model.values && ( + + )} ); }; - -PercentileRankAgg.propTypes = { - disableDelete: PropTypes.bool, - fields: PropTypes.object, - model: PropTypes.object, - onAdd: PropTypes.func, - onChange: PropTypes.func, - onDelete: PropTypes.func, - panel: PropTypes.object, - series: PropTypes.object, - siblings: PropTypes.array, -}; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.tsx similarity index 67% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.js rename to src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.tsx index 6d52eb9e3515c6..b66d79d67f4277 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/percentile_rank/percentile_rank_values.tsx @@ -16,34 +16,49 @@ * specific language governing permissions and limitations * under the License. */ -import PropTypes from 'prop-types'; import React from 'react'; import { last } from 'lodash'; import { EuiFlexGroup } from '@elastic/eui'; import { MultiValueRow } from './multi_value_row'; -export const PercentileRankValues = (props) => { +interface PercentileRankValuesProps { + model: Array; + disableDelete: boolean; + disableAdd: boolean; + showOnlyLastRow: boolean; + onChange: (values: any[]) => void; +} + +export const PercentileRankValues = (props: PercentileRankValuesProps) => { const model = props.model || []; const { onChange, disableAdd, disableDelete, showOnlyLastRow } = props; - const onChangeValue = ({ value, id }) => { + const onChangeValue = ({ value, id }: { value: string; id: number }) => { model[id] = value; onChange(model); }; - const onDeleteValue = ({ id }) => + const onDeleteValue = ({ id }: { id: number }) => onChange(model.filter((item, currentIndex) => id !== currentIndex)); const onAddValue = () => onChange([...model, '']); - const renderRow = ({ rowModel, disableDelete, disableAdd }) => ( + const renderRow = ({ + rowModel, + disableDeleteRow, + disableAddRow, + }: { + rowModel: { id: number; value: string }; + disableDeleteRow: boolean; + disableAddRow: boolean; + }) => ( ); @@ -54,10 +69,10 @@ export const PercentileRankValues = (props) => { renderRow({ rowModel: { id: model.length - 1, - value: last(model), + value: last(model) || '', }, - disableAdd: true, - disableDelete: true, + disableAddRow: true, + disableDeleteRow: true, })} {!showOnlyLastRow && @@ -65,20 +80,12 @@ export const PercentileRankValues = (props) => { renderRow({ rowModel: { id, - value, + value: value || '', }, - disableAdd, - disableDelete: disableDelete || array.length < 2, + disableAddRow: disableAdd, + disableDeleteRow: disableDelete || array.length < 2, }) )} ); }; - -PercentileRankValues.propTypes = { - model: PropTypes.array, - onChange: PropTypes.func, - disableDelete: PropTypes.bool, - disableAdd: PropTypes.bool, - showOnlyLastRow: PropTypes.bool, -}; diff --git a/src/plugins/vis_type_timeseries/public/application/components/aggs/temporary_unsupported_agg.js b/src/plugins/vis_type_timeseries/public/application/components/aggs/temporary_unsupported_agg.tsx similarity index 79% rename from src/plugins/vis_type_timeseries/public/application/components/aggs/temporary_unsupported_agg.js rename to src/plugins/vis_type_timeseries/public/application/components/aggs/temporary_unsupported_agg.tsx index bae0491d978a28..d10c7ea7a7e36e 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/aggs/temporary_unsupported_agg.js +++ b/src/plugins/vis_type_timeseries/public/application/components/aggs/temporary_unsupported_agg.tsx @@ -17,12 +17,23 @@ * under the License. */ -import { AggRow } from './agg_row'; import React from 'react'; import { EuiCode, EuiTitle } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n/react'; +import { AggRow } from './agg_row'; +import { MetricsItemsSchema } from '../../../../common/types'; +import { DragHandleProps } from '../../../types'; + +interface TemporaryUnsupportedAggProps { + disableDelete: boolean; + model: MetricsItemsSchema; + siblings: MetricsItemsSchema[]; + dragHandleProps: DragHandleProps; + onAdd: () => void; + onDelete: () => void; +} -export function TemporaryUnsupportedAgg(props) { +export function TemporaryUnsupportedAgg(props: TemporaryUnsupportedAggProps) { return ( void; + onDelete: () => void; +} -export function UnsupportedAgg(props) { +export function UnsupportedAgg(props: UnsupportedAggProps) { return ( { +export const newMetricAggFn = (): MetricsItemsSchema => { return { id: uuid.v1(), type: 'count', diff --git a/src/plugins/vis_type_timeseries/public/application/components/series_drag_handler.js b/src/plugins/vis_type_timeseries/public/application/components/series_drag_handler.tsx similarity index 85% rename from src/plugins/vis_type_timeseries/public/application/components/series_drag_handler.js rename to src/plugins/vis_type_timeseries/public/application/components/series_drag_handler.tsx index f978348a5e45cc..73293a0d330fdb 100644 --- a/src/plugins/vis_type_timeseries/public/application/components/series_drag_handler.js +++ b/src/plugins/vis_type_timeseries/public/application/components/series_drag_handler.tsx @@ -18,11 +18,20 @@ */ import React, { PureComponent } from 'react'; -import PropTypes from 'prop-types'; import { EuiFlexItem, EuiToolTip, EuiIcon } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { DragHandleProps } from '../../types'; + +interface SeriesDragHandlerProps { + hideDragHandler: boolean; + dragHandleProps: DragHandleProps; +} + +export class SeriesDragHandler extends PureComponent { + static defaultProps = { + hideDragHandler: true, + }; -export class SeriesDragHandler extends PureComponent { render() { const { dragHandleProps, hideDragHandler } = this.props; @@ -49,12 +58,3 @@ export class SeriesDragHandler extends PureComponent { ); } } - -SeriesDragHandler.defaultProps = { - hideDragHandler: true, -}; - -SeriesDragHandler.propTypes = { - hideDragHandler: PropTypes.bool, - dragHandleProps: PropTypes.object.isRequired, -}; diff --git a/src/plugins/vis_type_timeseries/public/types.ts b/src/plugins/vis_type_timeseries/public/types.ts new file mode 100644 index 00000000000000..338118dcdc5aa1 --- /dev/null +++ b/src/plugins/vis_type_timeseries/public/types.ts @@ -0,0 +1,29 @@ +/* + * 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 { EuiDraggable } from '@elastic/eui'; + +type PropsOf = T extends React.ComponentType ? ComponentProps : never; +type FirstArgumentOf = Func extends (arg1: infer FirstArgument, ...rest: any[]) => any + ? FirstArgument + : never; +export type DragHandleProps = FirstArgumentOf< + Exclude['children'], React.ReactElement> +>['dragHandleProps']; diff --git a/src/plugins/vis_type_timeseries/server/routes/vis.ts b/src/plugins/vis_type_timeseries/server/routes/vis.ts index 744020b5838827..48efd4398e4d41 100644 --- a/src/plugins/vis_type_timeseries/server/routes/vis.ts +++ b/src/plugins/vis_type_timeseries/server/routes/vis.ts @@ -20,7 +20,7 @@ import { IRouter, KibanaRequest } from 'kibana/server'; import { schema } from '@kbn/config-schema'; import { getVisData, GetVisDataOptions } from '../lib/get_vis_data'; -import { visPayloadSchema } from './post_vis_schema'; +import { visPayloadSchema } from '../../common/vis_schema'; import { Framework, ValidationTelemetryServiceSetup } from '../index'; const escapeHatch = schema.object({}, { unknowns: 'allow' });