From 5c3527d8a63deefd4fc3ef2d4b5e7381f6c34422 Mon Sep 17 00:00:00 2001 From: Uladzislau Lasitsa Date: Tue, 18 May 2021 15:28:10 +0300 Subject: [PATCH] [XY axis] Improve expression with explicit params (#98897) * Removed visconfig and using explicit params instead in xy_plugin * Fix CI * Fix i18n * Fix unit test * Fix some remarks * move expressions into separate chunk * fix CI * Update label.ts Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Alexey Antonov --- .../public/__snapshots__/to_ast.test.ts.snap | 2 +- src/plugins/vis_type_xy/common/index.ts | 13 +- .../public/__snapshots__/to_ast.test.ts.snap | 63 +++- .../public/editor/common_config.tsx | 6 +- .../expression_functions/category_axis.ts | 116 ++++++++ .../public/expression_functions/index.ts | 18 ++ .../public/expression_functions/label.ts | 89 ++++++ .../expression_functions/series_param.ts | 128 ++++++++ .../expression_functions/threshold_line.ts | 86 ++++++ .../expression_functions/time_marker.ts | 82 ++++++ .../public/expression_functions/value_axis.ts | 79 +++++ .../public/expression_functions/vis_scale.ts | 98 +++++++ .../expression_functions/xy_dimension.ts | 85 ++++++ .../public/expression_functions/xy_vis_fn.ts | 273 ++++++++++++++++++ src/plugins/vis_type_xy/public/plugin.ts | 17 +- .../public/sample_vis.test.mocks.ts | 6 + src/plugins/vis_type_xy/public/to_ast.test.ts | 2 +- src/plugins/vis_type_xy/public/to_ast.ts | 148 +++++++++- .../vis_type_xy/public/types/config.ts | 2 +- .../vis_type_xy/public/types/constants.ts | 89 +++--- src/plugins/vis_type_xy/public/types/index.ts | 2 +- src/plugins/vis_type_xy/public/types/param.ts | 65 ++++- .../utils/render_all_series.test.mocks.ts | 8 +- .../vis_type_xy/public/vis_renderer.tsx | 9 +- src/plugins/vis_type_xy/public/xy_vis_fn.ts | 77 ----- 25 files changed, 1389 insertions(+), 174 deletions(-) create mode 100644 src/plugins/vis_type_xy/public/expression_functions/category_axis.ts create mode 100644 src/plugins/vis_type_xy/public/expression_functions/index.ts create mode 100644 src/plugins/vis_type_xy/public/expression_functions/label.ts create mode 100644 src/plugins/vis_type_xy/public/expression_functions/series_param.ts create mode 100644 src/plugins/vis_type_xy/public/expression_functions/threshold_line.ts create mode 100644 src/plugins/vis_type_xy/public/expression_functions/time_marker.ts create mode 100644 src/plugins/vis_type_xy/public/expression_functions/value_axis.ts create mode 100644 src/plugins/vis_type_xy/public/expression_functions/vis_scale.ts create mode 100644 src/plugins/vis_type_xy/public/expression_functions/xy_dimension.ts create mode 100644 src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts delete mode 100644 src/plugins/vis_type_xy/public/xy_vis_fn.ts diff --git a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap index c3ffc0dd08412d..3ca2834a54fca2 100644 --- a/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap @@ -8,7 +8,7 @@ Object { "area", ], "visConfig": Array [ - "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", + "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"palette\\":{\\"name\\":\\"default\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", ], }, "getArgument": [Function], diff --git a/src/plugins/vis_type_xy/common/index.ts b/src/plugins/vis_type_xy/common/index.ts index 903adb53eb403e..a80946f7c62fa3 100644 --- a/src/plugins/vis_type_xy/common/index.ts +++ b/src/plugins/vis_type_xy/common/index.ts @@ -6,17 +6,14 @@ * Side Public License, v 1. */ -import { $Values } from '@kbn/utility-types'; - /** * Type of charts able to render */ -export const ChartType = Object.freeze({ - Line: 'line' as const, - Area: 'area' as const, - Histogram: 'histogram' as const, -}); -export type ChartType = $Values; +export enum ChartType { + Line = 'line', + Area = 'area', + Histogram = 'histogram', +} /** * Type of xy visualizations diff --git a/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap index e6665c26a28150..7c21e699216bc3 100644 --- a/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap +++ b/src/plugins/vis_type_xy/public/__snapshots__/to_ast.test.ts.snap @@ -4,11 +4,70 @@ exports[`xy vis toExpressionAst function should match basic snapshot 1`] = ` Object { "addArgument": [Function], "arguments": Object { + "addLegend": Array [ + true, + ], + "addTimeMarker": Array [ + false, + ], + "addTooltip": Array [ + true, + ], + "categoryAxes": Array [ + Object { + "toAst": [Function], + }, + ], + "chartType": Array [ + "area", + ], + "gridCategoryLines": Array [ + false, + ], + "labels": Array [ + Object { + "toAst": [Function], + }, + ], + "legendPosition": Array [ + "top", + ], + "palette": Array [ + "default", + ], + "seriesDimension": Array [ + Object { + "toAst": [Function], + }, + ], + "seriesParams": Array [ + Object { + "toAst": [Function], + }, + ], + "thresholdLine": Array [ + Object { + "toAst": [Function], + }, + ], + "times": Array [], "type": Array [ "area", ], - "visConfig": Array [ - "{\\"type\\":\\"area\\",\\"grid\\":{\\"categoryLines\\":false,\\"style\\":{\\"color\\":\\"#eee\\"}},\\"categoryAxes\\":[{\\"id\\":\\"CategoryAxis-1\\",\\"type\\":\\"category\\",\\"position\\":\\"bottom\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\"},\\"labels\\":{\\"show\\":true,\\"truncate\\":100},\\"title\\":{}}],\\"valueAxes\\":[{\\"id\\":\\"ValueAxis-1\\",\\"name\\":\\"LeftAxis-1\\",\\"type\\":\\"value\\",\\"position\\":\\"left\\",\\"show\\":true,\\"style\\":{},\\"scale\\":{\\"type\\":\\"linear\\",\\"mode\\":\\"normal\\"},\\"labels\\":{\\"show\\":true,\\"rotate\\":0,\\"filter\\":false,\\"truncate\\":100},\\"title\\":{\\"text\\":\\"Sum of total_quantity\\"}}],\\"seriesParams\\":[{\\"show\\":\\"true\\",\\"type\\":\\"area\\",\\"mode\\":\\"stacked\\",\\"data\\":{\\"label\\":\\"Sum of total_quantity\\",\\"id\\":\\"1\\"},\\"drawLinesBetweenPoints\\":true,\\"showCircles\\":true,\\"interpolate\\":\\"linear\\",\\"valueAxis\\":\\"ValueAxis-1\\"}],\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"top\\",\\"times\\":[],\\"addTimeMarker\\":false,\\"thresholdLine\\":{\\"show\\":false,\\"value\\":10,\\"width\\":1,\\"style\\":\\"full\\",\\"color\\":\\"#E7664C\\"},\\"labels\\":{},\\"dimensions\\":{\\"x\\":{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"date\\",\\"params\\":{\\"pattern\\":\\"HH:mm:ss.SSS\\"}},\\"params\\":{}},\\"y\\":[{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\",\\"params\\":{\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}],\\"series\\":[{\\"accessor\\":2,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}", + "valueAxes": Array [ + Object { + "toAst": [Function], + }, + ], + "xDimension": Array [ + Object { + "toAst": [Function], + }, + ], + "yDimension": Array [ + Object { + "toAst": [Function], + }, ], }, "getArgument": [Function], diff --git a/src/plugins/vis_type_xy/public/editor/common_config.tsx b/src/plugins/vis_type_xy/public/editor/common_config.tsx index 1e4ac7df0082c7..1815d9cfc429da 100644 --- a/src/plugins/vis_type_xy/public/editor/common_config.tsx +++ b/src/plugins/vis_type_xy/public/editor/common_config.tsx @@ -9,11 +9,11 @@ import React from 'react'; import { i18n } from '@kbn/i18n'; -import { VisEditorOptionsProps } from '../../../visualizations/public'; +import type { VisEditorOptionsProps } from '../../../visualizations/public'; -import { VisParams } from '../types'; +import type { VisParams } from '../types'; import { MetricsAxisOptions, PointSeriesOptions } from './components/options'; -import { ValidationWrapper } from './components/common'; +import { ValidationWrapper } from './components/common/validation_wrapper'; export function getOptionTabs(showElasticChartsOptions = false) { return [ diff --git a/src/plugins/vis_type_xy/public/expression_functions/category_axis.ts b/src/plugins/vis_type_xy/public/expression_functions/category_axis.ts new file mode 100644 index 00000000000000..30215d8feb8a30 --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/category_axis.ts @@ -0,0 +1,116 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import type { + ExpressionFunctionDefinition, + Datatable, + ExpressionValueBoxed, +} from '../../../expressions/public'; +import type { CategoryAxis } from '../types'; +import type { ExpressionValueScale } from './vis_scale'; +import type { ExpressionValueLabel } from './label'; + +export interface Arguments extends Omit { + title?: string; + scale: ExpressionValueScale; + labels: ExpressionValueLabel; +} + +export type ExpressionValueCategoryAxis = ExpressionValueBoxed< + 'category_axis', + { + id: CategoryAxis['id']; + show: CategoryAxis['show']; + position: CategoryAxis['position']; + axisType: CategoryAxis['type']; + title: { + text?: string; + }; + labels: CategoryAxis['labels']; + scale: CategoryAxis['scale']; + } +>; + +export const categoryAxis = (): ExpressionFunctionDefinition< + 'categoryaxis', + Datatable | null, + Arguments, + ExpressionValueCategoryAxis +> => ({ + name: 'categoryaxis', + help: i18n.translate('visTypeXy.function.categoryAxis.help', { + defaultMessage: 'Generates category axis object', + }), + type: 'category_axis', + args: { + id: { + types: ['string'], + help: i18n.translate('visTypeXy.function.categoryAxis.id.help', { + defaultMessage: 'Id of category axis', + }), + required: true, + }, + show: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.categoryAxis.show.help', { + defaultMessage: 'Show the category axis', + }), + required: true, + }, + position: { + types: ['string'], + help: i18n.translate('visTypeXy.function.categoryAxis.position.help', { + defaultMessage: 'Position of the category axis', + }), + required: true, + }, + type: { + types: ['string'], + help: i18n.translate('visTypeXy.function.categoryAxis.type.help', { + defaultMessage: 'Type of the category axis. Can be category or value', + }), + required: true, + }, + title: { + types: ['string'], + help: i18n.translate('visTypeXy.function.categoryAxis.title.help', { + defaultMessage: 'Title of the category axis', + }), + }, + scale: { + types: ['vis_scale'], + help: i18n.translate('visTypeXy.function.categoryAxis.scale.help', { + defaultMessage: 'Scale config', + }), + }, + labels: { + types: ['label'], + help: i18n.translate('visTypeXy.function.categoryAxis.labels.help', { + defaultMessage: 'Axis label config', + }), + }, + }, + fn: (context, args) => { + return { + type: 'category_axis', + id: args.id, + show: args.show, + position: args.position, + axisType: args.type, + title: { + text: args.title, + }, + scale: { + ...args.scale, + type: args.scale.scaleType, + }, + labels: args.labels, + }; + }, +}); diff --git a/src/plugins/vis_type_xy/public/expression_functions/index.ts b/src/plugins/vis_type_xy/public/expression_functions/index.ts new file mode 100644 index 00000000000000..4e7db57ee65d75 --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/index.ts @@ -0,0 +1,18 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +export { visTypeXyVisFn } from './xy_vis_fn'; + +export { categoryAxis, ExpressionValueCategoryAxis } from './category_axis'; +export { timeMarker, ExpressionValueTimeMarker } from './time_marker'; +export { valueAxis, ExpressionValueValueAxis } from './value_axis'; +export { seriesParam, ExpressionValueSeriesParam } from './series_param'; +export { thresholdLine, ExpressionValueThresholdLine } from './threshold_line'; +export { label, ExpressionValueLabel } from './label'; +export { visScale, ExpressionValueScale } from './vis_scale'; +export { xyDimension, ExpressionValueXYDimension } from './xy_dimension'; diff --git a/src/plugins/vis_type_xy/public/expression_functions/label.ts b/src/plugins/vis_type_xy/public/expression_functions/label.ts new file mode 100644 index 00000000000000..934278d13cff02 --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/label.ts @@ -0,0 +1,89 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import type { Labels } from '../../../charts/public'; +import type { + ExpressionFunctionDefinition, + Datatable, + ExpressionValueBoxed, +} from '../../../expressions/public'; + +export type ExpressionValueLabel = ExpressionValueBoxed< + 'label', + { + color?: Labels['color']; + filter?: Labels['filter']; + overwriteColor?: Labels['overwriteColor']; + rotate?: Labels['rotate']; + show?: Labels['show']; + truncate?: Labels['truncate']; + } +>; + +export const label = (): ExpressionFunctionDefinition< + 'label', + Datatable | null, + Labels, + ExpressionValueLabel +> => ({ + name: 'label', + help: i18n.translate('visTypeXy.function.label.help', { + defaultMessage: 'Generates label object', + }), + type: 'label', + args: { + color: { + types: ['string'], + help: i18n.translate('visTypeXy.function.label.color.help', { + defaultMessage: 'Color of label', + }), + }, + filter: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.label.filter.help', { + defaultMessage: 'Hides overlapping labels and duplicates on axis', + }), + }, + overwriteColor: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.label.overwriteColor.help', { + defaultMessage: 'Overwrite color', + }), + }, + rotate: { + types: ['number'], + help: i18n.translate('visTypeXy.function.label.rotate.help', { + defaultMessage: 'Rotate angle', + }), + }, + show: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.label.show.help', { + defaultMessage: 'Show label', + }), + }, + truncate: { + types: ['number', 'null'], + help: i18n.translate('visTypeXy.function.label.truncate.help', { + defaultMessage: 'The number of symbols before truncating', + }), + }, + }, + fn: (context, args) => { + return { + type: 'label', + color: args.color, + filter: args.hasOwnProperty('filter') ? args.filter : undefined, + overwriteColor: args.overwriteColor, + rotate: args.rotate, + show: args.show, + truncate: args.truncate, + }; + }, +}); diff --git a/src/plugins/vis_type_xy/public/expression_functions/series_param.ts b/src/plugins/vis_type_xy/public/expression_functions/series_param.ts new file mode 100644 index 00000000000000..402187cea65866 --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/series_param.ts @@ -0,0 +1,128 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import type { + ExpressionFunctionDefinition, + Datatable, + ExpressionValueBoxed, +} from '../../../expressions/public'; +import type { SeriesParam } from '../types'; + +export interface Arguments extends Omit { + label: string; + id: string; +} + +export type ExpressionValueSeriesParam = ExpressionValueBoxed< + 'series_param', + { + data: { label: string; id: string }; + drawLinesBetweenPoints?: boolean; + interpolate?: SeriesParam['interpolate']; + lineWidth?: number; + mode: SeriesParam['mode']; + show: boolean; + showCircles: boolean; + seriesParamType: SeriesParam['type']; + valueAxis: string; + } +>; + +export const seriesParam = (): ExpressionFunctionDefinition< + 'seriesparam', + Datatable, + Arguments, + ExpressionValueSeriesParam +> => ({ + name: 'seriesparam', + help: i18n.translate('visTypeXy.function.seriesparam.help', { + defaultMessage: 'Generates series param object', + }), + type: 'series_param', + inputTypes: ['datatable'], + args: { + label: { + types: ['string'], + help: i18n.translate('visTypeXy.function.seriesParam.label.help', { + defaultMessage: 'Name of series param', + }), + required: true, + }, + id: { + types: ['string'], + help: i18n.translate('visTypeXy.function.seriesParam.id.help', { + defaultMessage: 'Id of series param', + }), + required: true, + }, + drawLinesBetweenPoints: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.seriesParam.drawLinesBetweenPoints.help', { + defaultMessage: 'Draw lines between points', + }), + }, + interpolate: { + types: ['string'], + help: i18n.translate('visTypeXy.function.seriesParam.interpolate.help', { + defaultMessage: 'Interpolate mode. Can be linear, cardinal or step-after', + }), + }, + show: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.seriesParam.show.help', { + defaultMessage: 'Show param', + }), + required: true, + }, + lineWidth: { + types: ['number'], + help: i18n.translate('visTypeXy.function.seriesParam.lineWidth.help', { + defaultMessage: 'Width of line', + }), + }, + mode: { + types: ['string'], + help: i18n.translate('visTypeXy.function.seriesParam.mode.help', { + defaultMessage: 'Chart mode. Can be stacked or percentage', + }), + }, + showCircles: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.seriesParam.showCircles.help', { + defaultMessage: 'Show circles', + }), + }, + type: { + types: ['string'], + help: i18n.translate('visTypeXy.function.seriesParam.type.help', { + defaultMessage: 'Chart type. Can be line, area or histogram', + }), + }, + valueAxis: { + types: ['string'], + help: i18n.translate('visTypeXy.function.seriesParam.valueAxis.help', { + defaultMessage: 'Name of value axis', + }), + }, + }, + fn: (context, args) => { + return { + type: 'series_param', + data: { label: args.label, id: args.id }, + drawLinesBetweenPoints: args.drawLinesBetweenPoints, + interpolate: args.interpolate, + lineWidth: args.lineWidth, + mode: args.mode, + show: args.show, + showCircles: args.showCircles, + seriesParamType: args.type, + valueAxis: args.valueAxis, + }; + }, +}); diff --git a/src/plugins/vis_type_xy/public/expression_functions/threshold_line.ts b/src/plugins/vis_type_xy/public/expression_functions/threshold_line.ts new file mode 100644 index 00000000000000..8c01e375039850 --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/threshold_line.ts @@ -0,0 +1,86 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import type { + ExpressionFunctionDefinition, + Datatable, + ExpressionValueBoxed, +} from '../../../expressions/public'; +import type { ThresholdLine } from '../types'; + +export type ExpressionValueThresholdLine = ExpressionValueBoxed< + 'threshold_line', + { + show: ThresholdLine['show']; + value: ThresholdLine['value']; + width: ThresholdLine['width']; + style: ThresholdLine['style']; + color: ThresholdLine['color']; + } +>; + +export const thresholdLine = (): ExpressionFunctionDefinition< + 'thresholdline', + Datatable | null, + ThresholdLine, + ExpressionValueThresholdLine +> => ({ + name: 'thresholdline', + help: i18n.translate('visTypeXy.function.thresholdLine.help', { + defaultMessage: 'Generates threshold line object', + }), + type: 'threshold_line', + args: { + show: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.thresholdLine.show.help', { + defaultMessage: 'Show threshould line', + }), + required: true, + }, + value: { + types: ['number', 'null'], + help: i18n.translate('visTypeXy.function.thresholdLine.value.help', { + defaultMessage: 'Threshold value', + }), + required: true, + }, + width: { + types: ['number', 'null'], + help: i18n.translate('visTypeXy.function.thresholdLine.width.help', { + defaultMessage: 'Width of threshold line', + }), + required: true, + }, + style: { + types: ['string'], + help: i18n.translate('visTypeXy.function.thresholdLine.style.help', { + defaultMessage: 'Style of threshold line. Can be full, dashed or dot-dashed', + }), + required: true, + }, + color: { + types: ['string'], + help: i18n.translate('visTypeXy.function.thresholdLine.color.help', { + defaultMessage: 'Color of threshold line', + }), + required: true, + }, + }, + fn: (context, args) => { + return { + type: 'threshold_line', + show: args.show, + value: args.value, + width: args.width, + style: args.style, + color: args.color, + }; + }, +}); diff --git a/src/plugins/vis_type_xy/public/expression_functions/time_marker.ts b/src/plugins/vis_type_xy/public/expression_functions/time_marker.ts new file mode 100644 index 00000000000000..3d9f609292c003 --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/time_marker.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import type { + ExpressionFunctionDefinition, + Datatable, + ExpressionValueBoxed, +} from '../../../expressions/public'; +import type { TimeMarker } from '../types'; + +export type ExpressionValueTimeMarker = ExpressionValueBoxed< + 'time_marker', + { + time: string; + class?: string; + color?: string; + opacity?: number; + width?: number; + } +>; + +export const timeMarker = (): ExpressionFunctionDefinition< + 'timemarker', + Datatable | null, + TimeMarker, + ExpressionValueTimeMarker +> => ({ + name: 'timemarker', + help: i18n.translate('visTypeXy.function.timemarker.help', { + defaultMessage: 'Generates time marker object', + }), + type: 'time_marker', + args: { + time: { + types: ['string'], + help: i18n.translate('visTypeXy.function.timeMarker.time.help', { + defaultMessage: 'Exact Time', + }), + required: true, + }, + class: { + types: ['string'], + help: i18n.translate('visTypeXy.function.timeMarker.class.help', { + defaultMessage: 'Css class name', + }), + }, + color: { + types: ['string'], + help: i18n.translate('visTypeXy.function.timeMarker.color.help', { + defaultMessage: 'Color of time marker', + }), + }, + opacity: { + types: ['number'], + help: i18n.translate('visTypeXy.function.timeMarker.opacity.help', { + defaultMessage: 'Opacity of time marker', + }), + }, + width: { + types: ['number'], + help: i18n.translate('visTypeXy.function.timeMarker.width.help', { + defaultMessage: 'Width of time marker', + }), + }, + }, + fn: (context, args) => { + return { + type: 'time_marker', + time: args.time, + class: args.class, + color: args.color, + opacity: args.opacity, + width: args.width, + }; + }, +}); diff --git a/src/plugins/vis_type_xy/public/expression_functions/value_axis.ts b/src/plugins/vis_type_xy/public/expression_functions/value_axis.ts new file mode 100644 index 00000000000000..510ec9bc605d23 --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/value_axis.ts @@ -0,0 +1,79 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import type { ExpressionValueCategoryAxis } from './category_axis'; +import type { CategoryAxis } from '../types'; +import type { + ExpressionFunctionDefinition, + Datatable, + ExpressionValueBoxed, +} from '../../../expressions/public'; + +interface Arguments { + name: string; + axisParams: ExpressionValueCategoryAxis; +} + +export type ExpressionValueValueAxis = ExpressionValueBoxed< + 'value_axis', + { + name: string; + id: string; + show: boolean; + position: CategoryAxis['position']; + axisType: CategoryAxis['type']; + title: { + text?: string; + }; + labels: CategoryAxis['labels']; + scale: CategoryAxis['scale']; + } +>; + +export const valueAxis = (): ExpressionFunctionDefinition< + 'valueaxis', + Datatable | null, + Arguments, + ExpressionValueValueAxis +> => ({ + name: 'valueaxis', + help: i18n.translate('visTypeXy.function.valueaxis.help', { + defaultMessage: 'Generates value axis object', + }), + type: 'value_axis', + args: { + name: { + types: ['string'], + help: i18n.translate('visTypeXy.function.valueAxis.name.help', { + defaultMessage: 'Name of value axis', + }), + required: true, + }, + axisParams: { + types: ['category_axis'], + help: i18n.translate('visTypeXy.function.valueAxis.axisParams.help', { + defaultMessage: 'Value axis params', + }), + required: true, + }, + }, + fn: (context, args) => { + return { + type: 'value_axis', + name: args.name, + id: args.axisParams.id, + show: args.axisParams.show, + position: args.axisParams.position, + axisType: args.axisParams.axisType, + title: args.axisParams.title, + scale: args.axisParams.scale, + labels: args.axisParams.labels, + }; + }, +}); diff --git a/src/plugins/vis_type_xy/public/expression_functions/vis_scale.ts b/src/plugins/vis_type_xy/public/expression_functions/vis_scale.ts new file mode 100644 index 00000000000000..fadf3d80a6e81a --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/vis_scale.ts @@ -0,0 +1,98 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import type { + ExpressionFunctionDefinition, + Datatable, + ExpressionValueBoxed, +} from '../../../expressions/public'; +import type { Scale } from '../types'; + +export type ExpressionValueScale = ExpressionValueBoxed< + 'vis_scale', + { + boundsMargin?: Scale['boundsMargin']; + defaultYExtents?: Scale['defaultYExtents']; + max?: Scale['max']; + min?: Scale['min']; + mode?: Scale['mode']; + setYExtents?: Scale['setYExtents']; + scaleType: Scale['type']; + } +>; + +export const visScale = (): ExpressionFunctionDefinition< + 'visscale', + Datatable | null, + Scale, + ExpressionValueScale +> => ({ + name: 'visscale', + help: i18n.translate('visTypeXy.function.scale.help', { + defaultMessage: 'Generates scale object', + }), + type: 'vis_scale', + args: { + boundsMargin: { + types: ['number', 'string'], + help: i18n.translate('visTypeXy.function.scale.boundsMargin.help', { + defaultMessage: 'Margin of bounds', + }), + }, + defaultYExtents: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.scale.defaultYExtents.help', { + defaultMessage: 'Flag which allows to scale to data bounds', + }), + }, + setYExtents: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.scale.setYExtents.help', { + defaultMessage: 'Flag which allows to set your own extents', + }), + }, + max: { + types: ['number', 'null'], + help: i18n.translate('visTypeXy.function.scale.max.help', { + defaultMessage: 'Max value', + }), + }, + min: { + types: ['number', 'null'], + help: i18n.translate('visTypeXy.function.scale.min.help', { + defaultMessage: 'Min value', + }), + }, + mode: { + types: ['string'], + help: i18n.translate('visTypeXy.function.scale.mode.help', { + defaultMessage: 'Scale mode. Can be normal, percentage, wiggle or silhouette', + }), + }, + type: { + types: ['string'], + help: i18n.translate('visTypeXy.function.scale.type.help', { + defaultMessage: 'Scale type. Can be linear, log or square root', + }), + required: true, + }, + }, + fn: (context, args) => { + return { + type: 'vis_scale', + boundsMargin: args.boundsMargin, + defaultYExtents: args.defaultYExtents, + setYExtents: args.setYExtents, + max: args.max, + min: args.min, + mode: args.mode, + scaleType: args.type, + }; + }, +}); diff --git a/src/plugins/vis_type_xy/public/expression_functions/xy_dimension.ts b/src/plugins/vis_type_xy/public/expression_functions/xy_dimension.ts new file mode 100644 index 00000000000000..ecbc3640c035b1 --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/xy_dimension.ts @@ -0,0 +1,85 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; +import type { ExpressionValueVisDimension } from '../../../visualizations/public'; +import type { + ExpressionFunctionDefinition, + Datatable, + ExpressionValueBoxed, +} from '../../../expressions/public'; +import type { Dimension } from '../types'; + +interface Arguments { + visDimension: ExpressionValueVisDimension; + params: string; + aggType: string; + label: string; +} + +export type ExpressionValueXYDimension = ExpressionValueBoxed< + 'xy_dimension', + { + label: string; + aggType: string; + params: Dimension['params']; + accessor: number; + format: Dimension['format']; + } +>; + +export const xyDimension = (): ExpressionFunctionDefinition< + 'xydimension', + Datatable | null, + Arguments, + ExpressionValueXYDimension +> => ({ + name: 'xydimension', + help: i18n.translate('visTypeXy.function.xydimension.help', { + defaultMessage: 'Generates xy dimension object', + }), + type: 'xy_dimension', + args: { + visDimension: { + types: ['vis_dimension'], + help: i18n.translate('visTypeXy.function.xyDimension.visDimension.help', { + defaultMessage: 'Dimension object config', + }), + required: true, + }, + label: { + types: ['string'], + help: i18n.translate('visTypeXy.function.xyDimension.label.help', { + defaultMessage: 'Label', + }), + }, + aggType: { + types: ['string'], + help: i18n.translate('visTypeXy.function.xyDimension.aggType.help', { + defaultMessage: 'Aggregation type', + }), + }, + params: { + types: ['string'], + default: '"{}"', + help: i18n.translate('visTypeXy.function.xyDimension.params.help', { + defaultMessage: 'Params', + }), + }, + }, + fn: (context, args) => { + return { + type: 'xy_dimension', + label: args.label, + aggType: args.aggType, + params: JSON.parse(args.params!), + accessor: args.visDimension.accessor as number, + format: args.visDimension.format, + }; + }, +}); diff --git a/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts new file mode 100644 index 00000000000000..b8b8c0e8b8cca8 --- /dev/null +++ b/src/plugins/vis_type_xy/public/expression_functions/xy_vis_fn.ts @@ -0,0 +1,273 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0 and the Server Side Public License, v 1; you may not use this file except + * in compliance with, at your election, the Elastic License 2.0 or the Server + * Side Public License, v 1. + */ + +import { i18n } from '@kbn/i18n'; + +import type { ExpressionFunctionDefinition, Datatable, Render } from '../../../expressions/public'; +import type { ChartType } from '../../common'; +import type { VisParams, XYVisConfig } from '../types'; + +export const visName = 'xy_vis'; +export interface RenderValue { + visData: Datatable; + visType: ChartType; + visConfig: VisParams; + syncColors: boolean; +} + +export type VisTypeXyExpressionFunctionDefinition = ExpressionFunctionDefinition< + typeof visName, + Datatable, + XYVisConfig, + Render +>; + +export const visTypeXyVisFn = (): VisTypeXyExpressionFunctionDefinition => ({ + name: visName, + type: 'render', + context: { + types: ['datatable'], + }, + help: i18n.translate('visTypeXy.functions.help', { + defaultMessage: 'XY visualization', + }), + args: { + type: { + types: ['string'], + default: '""', + help: 'xy vis type', + }, + chartType: { + types: ['string'], + help: i18n.translate('visTypeXy.function.args.args.chartType.help', { + defaultMessage: 'Type of a chart. Can be line, area or histogram', + }), + }, + addTimeMarker: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.args.addTimeMarker.help', { + defaultMessage: 'Show time marker', + }), + }, + addLegend: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.args.addLegend.help', { + defaultMessage: 'Show chart legend', + }), + }, + addTooltip: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.args.addTooltip.help', { + defaultMessage: 'Show tooltip on hover', + }), + }, + legendPosition: { + types: ['string'], + help: i18n.translate('visTypeXy.function.args.legendPosition.help', { + defaultMessage: 'Position the legend on top, bottom, left, right of the chart', + }), + }, + categoryAxes: { + types: ['category_axis'], + help: i18n.translate('visTypeXy.function.args.categoryAxes.help', { + defaultMessage: 'Category axis config', + }), + multi: true, + }, + thresholdLine: { + types: ['threshold_line'], + help: i18n.translate('visTypeXy.function.args.thresholdLine.help', { + defaultMessage: 'Threshold line config', + }), + }, + labels: { + types: ['label'], + help: i18n.translate('visTypeXy.function.args.labels.help', { + defaultMessage: 'Chart labels config', + }), + }, + orderBucketsBySum: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.args.orderBucketsBySum.help', { + defaultMessage: 'Order buckets by sum', + }), + }, + seriesParams: { + types: ['series_param'], + help: i18n.translate('visTypeXy.function.args.seriesParams.help', { + defaultMessage: 'Series param config', + }), + multi: true, + }, + valueAxes: { + types: ['value_axis'], + help: i18n.translate('visTypeXy.function.args.valueAxes.help', { + defaultMessage: 'Value axis config', + }), + multi: true, + }, + radiusRatio: { + types: ['number'], + help: i18n.translate('visTypeXy.function.args.radiusRatio.help', { + defaultMessage: 'Dot size ratio', + }), + }, + gridCategoryLines: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.args.gridCategoryLines.help', { + defaultMessage: 'Show grid category lines in chart', + }), + }, + gridValueAxis: { + types: ['string'], + help: i18n.translate('visTypeXy.function.args.gridValueAxis.help', { + defaultMessage: 'Name of value axis for which we show grid', + }), + }, + isVislibVis: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.args.isVislibVis.help', { + defaultMessage: + 'Flag to indicate old vislib visualizations. Used for backwards compatibility including colors', + }), + }, + detailedTooltip: { + types: ['boolean'], + help: i18n.translate('visTypeXy.function.args.detailedTooltip.help', { + defaultMessage: 'Show detailed tooltip', + }), + }, + fittingFunction: { + types: ['string'], + help: i18n.translate('visTypeXy.function.args.fittingFunction.help', { + defaultMessage: 'Name of fitting function', + }), + }, + times: { + types: ['time_marker'], + help: i18n.translate('visTypeXy.function.args.times.help', { + defaultMessage: 'Time marker config', + }), + multi: true, + }, + palette: { + types: ['string'], + help: i18n.translate('visTypeXy.function.args.palette.help', { + defaultMessage: 'Defines the chart palette name', + }), + }, + xDimension: { + types: ['xy_dimension', 'null'], + help: i18n.translate('visTypeXy.function.args.xDimension.help', { + defaultMessage: 'X axis dimension config', + }), + }, + yDimension: { + types: ['xy_dimension'], + help: i18n.translate('visTypeXy.function.args.yDimension.help', { + defaultMessage: 'Y axis dimension config', + }), + multi: true, + }, + zDimension: { + types: ['xy_dimension'], + help: i18n.translate('visTypeXy.function.args.zDimension.help', { + defaultMessage: 'Z axis dimension config', + }), + multi: true, + }, + widthDimension: { + types: ['xy_dimension'], + help: i18n.translate('visTypeXy.function.args.widthDimension.help', { + defaultMessage: 'Width dimension config', + }), + multi: true, + }, + seriesDimension: { + types: ['xy_dimension'], + help: i18n.translate('visTypeXy.function.args.seriesDimension.help', { + defaultMessage: 'Series dimension config', + }), + multi: true, + }, + splitRowDimension: { + types: ['xy_dimension'], + help: i18n.translate('visTypeXy.function.args.splitRowDimension.help', { + defaultMessage: 'Split by row dimension config', + }), + multi: true, + }, + splitColumnDimension: { + types: ['xy_dimension'], + help: i18n.translate('visTypeXy.function.args.splitColumnDimension.help', { + defaultMessage: 'Split by column dimension config', + }), + multi: true, + }, + }, + fn(context, args, handlers) { + const visType = args.chartType; + const visConfig = { + type: args.chartType, + addLegend: args.addLegend, + addTooltip: args.addTooltip, + legendPosition: args.legendPosition, + addTimeMarker: args.addTimeMarker, + categoryAxes: args.categoryAxes.map((categoryAxis) => ({ + ...categoryAxis, + type: categoryAxis.axisType, + })), + orderBucketsBySum: args.orderBucketsBySum, + labels: args.labels, + thresholdLine: args.thresholdLine, + valueAxes: args.valueAxes.map((valueAxis) => ({ ...valueAxis, type: valueAxis.axisType })), + grid: { + categoryLines: args.gridCategoryLines, + valueAxis: args.gridValueAxis, + }, + seriesParams: args.seriesParams.map((seriesParam) => ({ + ...seriesParam, + type: seriesParam.seriesParamType, + })), + radiusRatio: args.radiusRatio, + times: args.times, + isVislibVis: args.isVislibVis, + detailedTooltip: args.detailedTooltip, + palette: { + type: 'palette', + name: args.palette, + }, + fittingFunction: args.fittingFunction, + dimensions: { + x: args.xDimension, + y: args.yDimension, + z: args.zDimension, + width: args.widthDimension, + series: args.seriesDimension, + splitRow: args.splitRowDimension, + splitColumn: args.splitColumnDimension, + }, + } as VisParams; + + if (handlers?.inspectorAdapters?.tables) { + handlers.inspectorAdapters.tables.logDatatable('default', context); + } + + return { + type: 'render', + as: visName, + value: { + context, + visType, + visConfig, + visData: context, + syncColors: handlers?.isSyncColorsEnabled?.() ?? false, + }, + }; + }, +}); diff --git a/src/plugins/vis_type_xy/public/plugin.ts b/src/plugins/vis_type_xy/public/plugin.ts index d414da8f6dc978..7bdb4f78bc631d 100644 --- a/src/plugins/vis_type_xy/public/plugin.ts +++ b/src/plugins/vis_type_xy/public/plugin.ts @@ -12,8 +12,6 @@ import { VisualizationsSetup, VisualizationsStart } from '../../visualizations/p import { ChartsPluginSetup } from '../../charts/public'; import { DataPublicPluginStart } from '../../data/public'; import { UsageCollectionSetup } from '../../usage_collection/public'; - -import { createVisTypeXyVisFn } from './xy_vis_fn'; import { setDataActions, setFormatService, @@ -23,10 +21,13 @@ import { setPalettesService, setTrackUiMetric, } from './services'; + import { visTypesDefinitions } from './vis_types'; import { LEGACY_CHARTS_LIBRARY } from '../common'; import { xyVisRenderer } from './vis_renderer'; +import * as expressionFunctions from './expression_functions'; + // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface VisTypeXyPluginSetup {} // eslint-disable-next-line @typescript-eslint/no-empty-interface @@ -66,8 +67,18 @@ export class VisTypeXyPlugin setUISettings(core.uiSettings); setThemeService(charts.theme); setPalettesService(charts.palettes); - [createVisTypeXyVisFn].forEach(expressions.registerFunction); + expressions.registerRenderer(xyVisRenderer); + expressions.registerFunction(expressionFunctions.visTypeXyVisFn); + expressions.registerFunction(expressionFunctions.categoryAxis); + expressions.registerFunction(expressionFunctions.timeMarker); + expressions.registerFunction(expressionFunctions.valueAxis); + expressions.registerFunction(expressionFunctions.seriesParam); + expressions.registerFunction(expressionFunctions.thresholdLine); + expressions.registerFunction(expressionFunctions.label); + expressions.registerFunction(expressionFunctions.visScale); + expressions.registerFunction(expressionFunctions.xyDimension); + visTypesDefinitions.forEach(visualizations.createBaseVisualization); } diff --git a/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts b/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts index c425eb71117e85..e15f9c42077020 100644 --- a/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts +++ b/src/plugins/vis_type_xy/public/sample_vis.test.mocks.ts @@ -1414,6 +1414,9 @@ export const sampleAreaVis = { color: '#E7664C', }, labels: {}, + palette: { + name: 'default', + }, }, }, editorConfig: { @@ -1575,6 +1578,9 @@ export const sampleAreaVis = { style: 'full', color: '#E7664C', }, + palette: { + name: 'default', + }, labels: {}, dimensions: { x: { diff --git a/src/plugins/vis_type_xy/public/to_ast.test.ts b/src/plugins/vis_type_xy/public/to_ast.test.ts index 22e2d5f1cd9cc8..4437986eff5f74 100644 --- a/src/plugins/vis_type_xy/public/to_ast.test.ts +++ b/src/plugins/vis_type_xy/public/to_ast.test.ts @@ -42,7 +42,7 @@ describe('xy vis toExpressionAst function', () => { it('should match basic snapshot', () => { toExpressionAst(vis, params); - const [, builtExpression] = (buildExpression as jest.Mock).mock.calls[0][0]; + const [, builtExpression] = (buildExpression as jest.Mock).mock.calls.pop()[0]; expect(builtExpression).toMatchSnapshot(); }); diff --git a/src/plugins/vis_type_xy/public/to_ast.ts b/src/plugins/vis_type_xy/public/to_ast.ts index 84331af3a53295..c0a0ee566a4453 100644 --- a/src/plugins/vis_type_xy/public/to_ast.ts +++ b/src/plugins/vis_type_xy/public/to_ast.ts @@ -11,13 +11,122 @@ import moment from 'moment'; import { VisToExpressionAst, getVisSchemas } from '../../visualizations/public'; import { buildExpression, buildExpressionFunction } from '../../expressions/public'; import { BUCKET_TYPES } from '../../data/public'; +import { Labels } from '../../charts/public'; -import { DateHistogramParams, Dimensions, HistogramParams, VisParams } from './types'; -import { visName, VisTypeXyExpressionFunctionDefinition } from './xy_vis_fn'; +import { + DateHistogramParams, + Dimensions, + Dimension, + HistogramParams, + VisParams, + CategoryAxis, + SeriesParam, + ThresholdLine, + ValueAxis, + Scale, + TimeMarker, +} from './types'; +import { visName, VisTypeXyExpressionFunctionDefinition } from './expression_functions/xy_vis_fn'; import { XyVisType } from '../common'; import { getEsaggsFn } from './to_ast_esaggs'; import { TimeRangeBounds } from '../../data/common'; +const prepareLabel = (data: Labels) => { + const label = buildExpressionFunction('label', { + ...data, + }); + + return buildExpression([label]); +}; + +const prepareScale = (data: Scale) => { + const scale = buildExpressionFunction('visscale', { + ...data, + }); + + return buildExpression([scale]); +}; + +const prepareThresholdLine = (data: ThresholdLine) => { + const thresholdLine = buildExpressionFunction('thresholdline', { + ...data, + }); + + return buildExpression([thresholdLine]); +}; + +const prepareTimeMarker = (data: TimeMarker) => { + const timeMarker = buildExpressionFunction('timemarker', { + ...data, + }); + + return buildExpression([timeMarker]); +}; + +const prepareCategoryAxis = (data: CategoryAxis) => { + const categoryAxis = buildExpressionFunction('categoryaxis', { + id: data.id, + show: data.show, + position: data.position, + type: data.type, + title: data.title.text, + scale: prepareScale(data.scale), + labels: prepareLabel(data.labels), + }); + + return buildExpression([categoryAxis]); +}; + +const prepareValueAxis = (data: ValueAxis) => { + const categoryAxis = buildExpressionFunction('valueaxis', { + name: data.name, + axisParams: prepareCategoryAxis({ + ...data, + }), + }); + + return buildExpression([categoryAxis]); +}; + +const prepareSeriesParam = (data: SeriesParam) => { + const seriesParam = buildExpressionFunction('seriesparam', { + label: data.data.label, + id: data.data.id, + drawLinesBetweenPoints: data.drawLinesBetweenPoints, + interpolate: data.interpolate, + lineWidth: data.lineWidth, + mode: data.mode, + show: data.show, + showCircles: data.showCircles, + type: data.type, + valueAxis: data.valueAxis, + }); + + return buildExpression([seriesParam]); +}; + +const prepareVisDimension = (data: Dimension) => { + const visDimension = buildExpressionFunction('visdimension', { accessor: data.accessor }); + + if (data.format) { + visDimension.addArgument('format', data.format.id); + visDimension.addArgument('formatParams', JSON.stringify(data.format.params)); + } + + return buildExpression([visDimension]); +}; + +const prepareXYDimension = (data: Dimension) => { + const xyDimension = buildExpressionFunction('xydimension', { + params: JSON.stringify(data.params), + aggType: data.aggType, + label: data.label, + visDimension: prepareVisDimension(data), + }); + + return buildExpression([xyDimension]); +}; + export const toExpressionAst: VisToExpressionAst = async (vis, params) => { const schemas = getVisSchemas(vis, params); const dimensions: Dimensions = { @@ -62,15 +171,13 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params } } - const visConfig = { ...vis.params }; - (dimensions.y || []).forEach((yDimension) => { const yAgg = responseAggs[yDimension.accessor]; - const seriesParam = (visConfig.seriesParams || []).find( + const seriesParam = (vis.params.seriesParams || []).find( (param: any) => param.data.id === yAgg.id ); if (seriesParam) { - const usedValueAxis = (visConfig.valueAxes || []).find( + const usedValueAxis = (vis.params.valueAxes || []).find( (valueAxis: any) => valueAxis.id === seriesParam.valueAxis ); if (usedValueAxis?.scale.mode === 'percentage') { @@ -79,11 +186,34 @@ export const toExpressionAst: VisToExpressionAst = async (vis, params } }); - visConfig.dimensions = dimensions; - const visTypeXy = buildExpressionFunction(visName, { type: vis.type.name as XyVisType, - visConfig: JSON.stringify(visConfig), + chartType: vis.params.type, + addTimeMarker: vis.params.addTimeMarker, + addLegend: vis.params.addLegend, + addTooltip: vis.params.addTooltip, + legendPosition: vis.params.legendPosition, + orderBucketsBySum: vis.params.orderBucketsBySum, + categoryAxes: vis.params.categoryAxes.map(prepareCategoryAxis), + valueAxes: vis.params.valueAxes.map(prepareValueAxis), + seriesParams: vis.params.seriesParams.map(prepareSeriesParam), + labels: prepareLabel(vis.params.labels), + thresholdLine: prepareThresholdLine(vis.params.thresholdLine), + gridCategoryLines: vis.params.grid.categoryLines, + gridValueAxis: vis.params.grid.valueAxis, + radiusRatio: vis.params.radiusRatio, + isVislibVis: vis.params.isVislibVis, + detailedTooltip: vis.params.detailedTooltip, + fittingFunction: vis.params.fittingFunction, + times: vis.params.times.map(prepareTimeMarker), + palette: vis.params.palette.name, + xDimension: dimensions.x ? prepareXYDimension(dimensions.x) : null, + yDimension: dimensions.y.map(prepareXYDimension), + zDimension: dimensions.z?.map(prepareXYDimension), + widthDimension: dimensions.width?.map(prepareXYDimension), + seriesDimension: dimensions.series?.map(prepareXYDimension), + splitRowDimension: dimensions.splitRow?.map(prepareXYDimension), + splitColumnDimension: dimensions.splitColumn?.map(prepareXYDimension), }); const ast = buildExpression([getEsaggsFn(vis), visTypeXy]); diff --git a/src/plugins/vis_type_xy/public/types/config.ts b/src/plugins/vis_type_xy/public/types/config.ts index d5c5bfe004191b..f025a36a82410a 100644 --- a/src/plugins/vis_type_xy/public/types/config.ts +++ b/src/plugins/vis_type_xy/public/types/config.ts @@ -20,7 +20,7 @@ import { YDomainRange, } from '@elastic/charts'; -import { Dimension, Scale, ThresholdLine } from './param'; +import type { Dimension, Scale, ThresholdLine } from './param'; export interface Column { id: string | null; diff --git a/src/plugins/vis_type_xy/public/types/constants.ts b/src/plugins/vis_type_xy/public/types/constants.ts index 5c2f23b76aa961..05ed0783d4c686 100644 --- a/src/plugins/vis_type_xy/public/types/constants.ts +++ b/src/plugins/vis_type_xy/public/types/constants.ts @@ -6,52 +6,43 @@ * Side Public License, v 1. */ -import { $Values } from '@kbn/utility-types'; - -export const ChartMode = Object.freeze({ - Normal: 'normal' as const, - Stacked: 'stacked' as const, -}); -export type ChartMode = $Values; - -export const InterpolationMode = Object.freeze({ - Linear: 'linear' as const, - Cardinal: 'cardinal' as const, - StepAfter: 'step-after' as const, -}); -export type InterpolationMode = $Values; - -export const AxisType = Object.freeze({ - Category: 'category' as const, - Value: 'value' as const, -}); -export type AxisType = $Values; - -export const ScaleType = Object.freeze({ - Linear: 'linear' as const, - Log: 'log' as const, - SquareRoot: 'square root' as const, -}); -export type ScaleType = $Values; - -export const AxisMode = Object.freeze({ - Normal: 'normal' as const, - Percentage: 'percentage' as const, - Wiggle: 'wiggle' as const, - Silhouette: 'silhouette' as const, -}); -export type AxisMode = $Values; - -export const ThresholdLineStyle = Object.freeze({ - Full: 'full' as const, - Dashed: 'dashed' as const, - DotDashed: 'dot-dashed' as const, -}); -export type ThresholdLineStyle = $Values; - -export const ColorMode = Object.freeze({ - Background: 'Background' as const, - Labels: 'Labels' as const, - None: 'None' as const, -}); -export type ColorMode = $Values; +export enum ChartMode { + Normal = 'normal', + Stacked = 'stacked', +} + +export enum InterpolationMode { + Linear = 'linear', + Cardinal = 'cardinal', + StepAfter = 'step-after', +} + +export enum AxisType { + Category = 'category', + Value = 'value', +} + +export enum ScaleType { + Linear = 'linear', + Log = 'log', + SquareRoot = 'square root', +} + +export enum AxisMode { + Normal = 'normal', + Percentage = 'percentage', + Wiggle = 'wiggle', + Silhouette = 'silhouette', +} + +export enum ThresholdLineStyle { + Full = 'full', + Dashed = 'dashed', + DotDashed = 'dot-dashed', +} + +export enum ColorMode { + Background = 'Background', + Labels = 'Labels', + None = 'None', +} diff --git a/src/plugins/vis_type_xy/public/types/index.ts b/src/plugins/vis_type_xy/public/types/index.ts index d612e9fcf5f6fd..6abbdfabaa9563 100644 --- a/src/plugins/vis_type_xy/public/types/index.ts +++ b/src/plugins/vis_type_xy/public/types/index.ts @@ -9,4 +9,4 @@ export * from './constants'; export * from './config'; export * from './param'; -export * from './vis_type'; +export type { VisTypeNames, XyVisTypeDefinition } from './vis_type'; diff --git a/src/plugins/vis_type_xy/public/types/param.ts b/src/plugins/vis_type_xy/public/types/param.ts index 69b6daf077a329..f90899620126aa 100644 --- a/src/plugins/vis_type_xy/public/types/param.ts +++ b/src/plugins/vis_type_xy/public/types/param.ts @@ -6,13 +6,21 @@ * Side Public License, v 1. */ -import { Fit, Position } from '@elastic/charts'; - -import { Style, Labels, PaletteOutput } from '../../../charts/public'; -import { SchemaConfig } from '../../../visualizations/public'; - -import { ChartType } from '../../common'; -import { +import type { Fit, Position } from '@elastic/charts'; +import type { Style, Labels, PaletteOutput } from '../../../charts/public'; +import type { SchemaConfig } from '../../../visualizations/public'; +import type { ChartType, XyVisType } from '../../common'; +import type { + ExpressionValueCategoryAxis, + ExpressionValueSeriesParam, + ExpressionValueValueAxis, + ExpressionValueLabel, + ExpressionValueThresholdLine, + ExpressionValueTimeMarker, + ExpressionValueXYDimension, +} from '../expression_functions'; + +import type { ChartMode, AxisMode, AxisType, @@ -47,7 +55,7 @@ export interface CategoryAxis { * remove with vis_type_vislib * https://github.com/elastic/kibana/issues/56143 */ - style: Partial