Clean up TSVB type client code to conform to the schema (#68519)
* Clean up TSVB type client code to conform to the schema Part of #57342 * Replace FieldDescriptor with IFieldType, add UIRestrictions interface * Replace expect from chai with @kbn/expect, remove unnecessary type * Add TimeseriesUIRestrictions type and refactor add_delete_buttons.test * Replace some types with MetricsItemsSchema['values'] to avoid duplications Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
42b87c0154
commit
2b72de5231
25
src/plugins/vis_type_timeseries/common/types.ts
Normal file
25
src/plugins/vis_type_timeseries/common/types.ts
Normal file
|
@ -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<typeof seriesItems>;
|
||||
export type MetricsItemsSchema = TypeOf<typeof metricsItems>;
|
||||
export type PanelSchema = TypeOf<typeof panel>;
|
|
@ -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<string, UIRestrictions>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -44,6 +53,6 @@ export const RESTRICTIONS_KEYS = {
|
|||
* @constant
|
||||
* @public
|
||||
*/
|
||||
export const DEFAULT_UI_RESTRICTION = {
|
||||
export const DEFAULT_UI_RESTRICTION: UIRestrictions = {
|
||||
'*': true,
|
||||
};
|
|
@ -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({
|
|
@ -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(<AddDeleteButtons onAdd={handleAdd} />);
|
||||
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(<AddDeleteButtons onDelete={handleDelete} />);
|
||||
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(<AddDeleteButtons onClone={handleClone} />);
|
||||
wrapper.find('EuiButtonIcon').at(0).simulate('click');
|
||||
expect(handleClone.calledOnce).to.equal(true);
|
||||
expect(handleClone).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('disableDelete={true}', () => {
|
||||
const wrapper = shallowWithIntl(<AddDeleteButtons disableDelete={true} />);
|
||||
expect(wrapper.find({ text: 'Delete' })).to.have.length(0);
|
||||
expect(wrapper.find({ text: 'Delete' })).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('disableAdd={true}', () => {
|
||||
const wrapper = shallowWithIntl(<AddDeleteButtons disableAdd={true} />);
|
||||
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(<AddDeleteButtons />);
|
||||
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(<AddDeleteButtons onClone={fn} disableAdd={true} />);
|
||||
expect(wrapper.find({ text: 'Clone' })).to.have.length(0);
|
||||
expect(wrapper.find({ text: 'Clone' })).toHaveLength(0);
|
||||
});
|
||||
});
|
|
@ -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,
|
||||
};
|
|
@ -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<HTMLElement> {
|
||||
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) {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
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,
|
||||
};
|
|
@ -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) {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
AggRow.propTypes = {
|
||||
disableDelete: PropTypes.bool,
|
||||
model: PropTypes.object,
|
||||
onAdd: PropTypes.func,
|
||||
onDelete: PropTypes.func,
|
||||
siblings: PropTypes.array,
|
||||
dragHandleProps: PropTypes.object,
|
||||
};
|
|
@ -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) {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
AggSelectUi.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
panelType: PropTypes.string,
|
||||
siblings: PropTypes.array,
|
||||
value: PropTypes.string,
|
||||
uiRestrictions: PropTypes.object,
|
||||
};
|
||||
|
||||
export const AggSelect = injectI18n(AggSelectUi);
|
|
@ -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<AggsProps> {
|
||||
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,
|
||||
};
|
|
@ -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<HTMLInputElement>) =>
|
||||
onChange({
|
||||
...model,
|
||||
value: get(event, 'target.value'),
|
||||
|
@ -54,7 +72,7 @@ export const MultiValueRow = ({ model, onChange, onDelete, onAdd, disableAdd, di
|
|||
<EuiFlexItem grow={false}>
|
||||
<EuiFieldNumber
|
||||
value={model.value === '' ? '' : Number(model.value)}
|
||||
placeholder={0}
|
||||
placeholder="0"
|
||||
onChange={onFieldNumberChange}
|
||||
/>
|
||||
</EuiFlexItem>
|
||||
|
@ -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,
|
||||
};
|
|
@ -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) => {
|
|||
</EuiFlexItem>
|
||||
</EuiFlexGroup>
|
||||
<EuiSpacer />
|
||||
<PercentileRankValues
|
||||
disableAdd={isTablePanel}
|
||||
disableDelete={isTablePanel}
|
||||
showOnlyLastRow={isTablePanel}
|
||||
model={model.values}
|
||||
onChange={handlePercentileRankValuesChange}
|
||||
/>
|
||||
{model.values && (
|
||||
<PercentileRankValues
|
||||
disableAdd={isTablePanel}
|
||||
disableDelete={isTablePanel}
|
||||
showOnlyLastRow={isTablePanel}
|
||||
model={model.values}
|
||||
onChange={handlePercentileRankValuesChange}
|
||||
/>
|
||||
)}
|
||||
</AggRow>
|
||||
);
|
||||
};
|
||||
|
||||
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,
|
||||
};
|
|
@ -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<string | null>;
|
||||
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;
|
||||
}) => (
|
||||
<MultiValueRow
|
||||
key={`percentileRankValue__item${rowModel.id}`}
|
||||
onAdd={onAddValue}
|
||||
onChange={onChangeValue}
|
||||
onDelete={onDeleteValue}
|
||||
disableDelete={disableDelete}
|
||||
disableAdd={disableAdd}
|
||||
disableDelete={disableDeleteRow}
|
||||
disableAdd={disableAddRow}
|
||||
model={rowModel}
|
||||
/>
|
||||
);
|
||||
|
@ -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,
|
||||
})
|
||||
)}
|
||||
</EuiFlexGroup>
|
||||
);
|
||||
};
|
||||
|
||||
PercentileRankValues.propTypes = {
|
||||
model: PropTypes.array,
|
||||
onChange: PropTypes.func,
|
||||
disableDelete: PropTypes.bool,
|
||||
disableAdd: PropTypes.bool,
|
||||
showOnlyLastRow: PropTypes.bool,
|
||||
};
|
|
@ -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';
|
||||
|
||||
export function TemporaryUnsupportedAgg(props) {
|
||||
interface TemporaryUnsupportedAggProps {
|
||||
disableDelete: boolean;
|
||||
model: MetricsItemsSchema;
|
||||
siblings: MetricsItemsSchema[];
|
||||
dragHandleProps: DragHandleProps;
|
||||
onAdd: () => void;
|
||||
onDelete: () => void;
|
||||
}
|
||||
|
||||
export function TemporaryUnsupportedAgg(props: TemporaryUnsupportedAggProps) {
|
||||
return (
|
||||
<AggRow
|
||||
disableDelete={props.disableDelete}
|
|
@ -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';
|
||||
|
||||
export function UnsupportedAgg(props) {
|
||||
interface UnsupportedAggProps {
|
||||
disableDelete: boolean;
|
||||
model: MetricsItemsSchema;
|
||||
siblings: MetricsItemsSchema[];
|
||||
dragHandleProps: DragHandleProps;
|
||||
onAdd: () => void;
|
||||
onDelete: () => void;
|
||||
}
|
||||
|
||||
export function UnsupportedAgg(props: UnsupportedAggProps) {
|
||||
return (
|
||||
<AggRow
|
||||
disableDelete={props.disableDelete}
|
|
@ -18,8 +18,9 @@
|
|||
*/
|
||||
|
||||
import uuid from 'uuid';
|
||||
import { MetricsItemsSchema } from '../../../../common/types';
|
||||
|
||||
export const newMetricAggFn = () => {
|
||||
export const newMetricAggFn = (): MetricsItemsSchema => {
|
||||
return {
|
||||
id: uuid.v1(),
|
||||
type: 'count',
|
|
@ -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<SeriesDragHandlerProps> {
|
||||
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,
|
||||
};
|
29
src/plugins/vis_type_timeseries/public/types.ts
Normal file
29
src/plugins/vis_type_timeseries/public/types.ts
Normal file
|
@ -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> = T extends React.ComponentType<infer ComponentProps> ? ComponentProps : never;
|
||||
type FirstArgumentOf<Func> = Func extends (arg1: infer FirstArgument, ...rest: any[]) => any
|
||||
? FirstArgument
|
||||
: never;
|
||||
export type DragHandleProps = FirstArgumentOf<
|
||||
Exclude<PropsOf<typeof EuiDraggable>['children'], React.ReactElement>
|
||||
>['dragHandleProps'];
|
|
@ -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' });
|
||||
|
|
Loading…
Reference in a new issue