diff --git a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderdefinition.displayname.md b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderdefinition.displayname.md index 9d5f7609ee6cd2..a957ecd63f0430 100644 --- a/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderdefinition.displayname.md +++ b/docs/development/plugins/expressions/public/kibana-plugin-plugins-expressions-public.expressionrenderdefinition.displayname.md @@ -9,5 +9,5 @@ A user friendly name of the renderer as will be displayed to user in UI. Signature: ```typescript -displayName: string; +displayName?: string; ``` diff --git a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionrenderdefinition.displayname.md b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionrenderdefinition.displayname.md index e936e25cee6cad..8ae5aa2f1790ec 100644 --- a/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionrenderdefinition.displayname.md +++ b/docs/development/plugins/expressions/server/kibana-plugin-plugins-expressions-server.expressionrenderdefinition.displayname.md @@ -9,5 +9,5 @@ A user friendly name of the renderer as will be displayed to user in UI. Signature: ```typescript -displayName: string; +displayName?: string; ``` diff --git a/src/plugins/expressions/common/expression_renderers/types.ts b/src/plugins/expressions/common/expression_renderers/types.ts index 7b3e812eafedd4..b760e7b32a7d2b 100644 --- a/src/plugins/expressions/common/expression_renderers/types.ts +++ b/src/plugins/expressions/common/expression_renderers/types.ts @@ -28,7 +28,7 @@ export interface ExpressionRenderDefinition { /** * A user friendly name of the renderer as will be displayed to user in UI. */ - displayName: string; + displayName?: string; /** * Help text as will be displayed to user. A sentence or few about what this diff --git a/src/plugins/expressions/public/public.api.md b/src/plugins/expressions/public/public.api.md index 162f0ef6824f5b..5c0fd8ab1a5729 100644 --- a/src/plugins/expressions/public/public.api.md +++ b/src/plugins/expressions/public/public.api.md @@ -429,7 +429,7 @@ export interface ExpressionImage { // // @public (undocumented) export interface ExpressionRenderDefinition { - displayName: string; + displayName?: string; help?: string; name: string; render: (domNode: HTMLElement, config: Config, handlers: IInterpreterRenderHandlers) => void | Promise; diff --git a/src/plugins/expressions/server/server.api.md b/src/plugins/expressions/server/server.api.md index 6ac251ea005b44..d8872ee4160174 100644 --- a/src/plugins/expressions/server/server.api.md +++ b/src/plugins/expressions/server/server.api.md @@ -401,7 +401,7 @@ export interface ExpressionImage { // // @public (undocumented) export interface ExpressionRenderDefinition { - displayName: string; + displayName?: string; help?: string; name: string; render: (domNode: HTMLElement, config: Config, handlers: IInterpreterRenderHandlers) => void | Promise; diff --git a/src/plugins/timelion/public/index.scss b/src/plugins/timelion/public/index.scss index 6bf7133287c51c..f39e0c18a28706 100644 --- a/src/plugins/timelion/public/index.scss +++ b/src/plugins/timelion/public/index.scss @@ -10,3 +10,9 @@ @import './app'; @import './base'; @import './directives/index'; + +// these styles is needed to be loaded here explicitly if the timelion visualization was not opened in browser +// styles for timelion visualization are lazy loaded only while a vis is opened +// this will duplicate styles only if both Timelion app and timelion visualization are loaded +// could be left here as it is since the Timelion app is deprecated +@import '../../vis_type_timelion/public/components/index.scss'; diff --git a/src/plugins/vis_type_tagcloud/public/tag_cloud_vis_renderer.tsx b/src/plugins/vis_type_tagcloud/public/tag_cloud_vis_renderer.tsx index d37aa5f6fe409a..b433ed9cbed218 100644 --- a/src/plugins/vis_type_tagcloud/public/tag_cloud_vis_renderer.tsx +++ b/src/plugins/vis_type_tagcloud/public/tag_cloud_vis_renderer.tsx @@ -25,7 +25,6 @@ import { ExpressionRenderDefinition } from '../../expressions/common/expression_ import { TagCloudVisDependencies } from './plugin'; import { TagCloudVisRenderValue } from './tag_cloud_fn'; -// @ts-ignore const TagCloudChart = lazy(() => import('./components/tag_cloud_chart')); export const getTagCloudVisRenderer: ( diff --git a/src/plugins/vis_type_timelion/public/__snapshots__/to_ast.test.ts.snap b/src/plugins/vis_type_timelion/public/__snapshots__/to_ast.test.ts.snap new file mode 100644 index 00000000000000..9e32a6c4ae17cb --- /dev/null +++ b/src/plugins/vis_type_timelion/public/__snapshots__/to_ast.test.ts.snap @@ -0,0 +1,21 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`timelion vis toExpressionAst function should match basic snapshot 1`] = ` +Object { + "chain": Array [ + Object { + "arguments": Object { + "expression": Array [ + ".es(*)", + ], + "interval": Array [ + "auto", + ], + }, + "function": "timelion_vis", + "type": "function", + }, + ], + "type": "expression", +} +`; diff --git a/src/plugins/vis_type_timelion/public/_timelion_editor.scss b/src/plugins/vis_type_timelion/public/_timelion_editor.scss deleted file mode 100644 index a9331930a86ffa..00000000000000 --- a/src/plugins/vis_type_timelion/public/_timelion_editor.scss +++ /dev/null @@ -1,15 +0,0 @@ -.visEditor--timelion { - vis-options-react-wrapper, - .visEditorSidebar__options, - .visEditorSidebar__timelionOptions { - flex: 1 1 auto; - display: flex; - flex-direction: column; - } - - .visEditor__sidebar { - @include euiBreakpoint('xs', 's', 'm') { - width: 100%; - } - } -} diff --git a/src/plugins/vis_type_timelion/public/_timelion_vis.scss b/src/plugins/vis_type_timelion/public/_timelion_vis.scss deleted file mode 100644 index e7175bf3c0c2aa..00000000000000 --- a/src/plugins/vis_type_timelion/public/_timelion_vis.scss +++ /dev/null @@ -1,12 +0,0 @@ -.timVis { - min-width: 100%; - display: flex; - flex-direction: column; - - .timChart { - min-width: 100%; - flex: 1; - display: flex; - flex-direction: column; - } -} diff --git a/src/plugins/vis_type_timelion/public/components/_panel.scss b/src/plugins/vis_type_timelion/public/components/_timelion_vis.scss similarity index 88% rename from src/plugins/vis_type_timelion/public/components/_panel.scss rename to src/plugins/vis_type_timelion/public/components/_timelion_vis.scss index c4d591bc82cad9..6729d400523cd8 100644 --- a/src/plugins/vis_type_timelion/public/components/_panel.scss +++ b/src/plugins/vis_type_timelion/public/components/_timelion_vis.scss @@ -58,3 +58,11 @@ white-space: nowrap; font-weight: $euiFontWeightBold; } + +.visEditor--timelion { + .visEditorSidebar__timelionOptions { + flex: 1 1 auto; + display: flex; + flex-direction: column; + } +} diff --git a/src/plugins/vis_type_timelion/public/components/_index.scss b/src/plugins/vis_type_timelion/public/components/index.scss similarity index 60% rename from src/plugins/vis_type_timelion/public/components/_index.scss rename to src/plugins/vis_type_timelion/public/components/index.scss index 707c9dafebe2b7..a541c66e6e9139 100644 --- a/src/plugins/vis_type_timelion/public/components/_index.scss +++ b/src/plugins/vis_type_timelion/public/components/index.scss @@ -1,2 +1,2 @@ -@import 'panel'; +@import 'timelion_vis'; @import 'timelion_expression_input'; diff --git a/src/plugins/vis_type_timelion/public/components/index.ts b/src/plugins/vis_type_timelion/public/components/index.ts index c70caab8dd70cf..8d7d32a3ba2627 100644 --- a/src/plugins/vis_type_timelion/public/components/index.ts +++ b/src/plugins/vis_type_timelion/public/components/index.ts @@ -19,4 +19,3 @@ export * from './timelion_expression_input'; export * from './timelion_interval'; -export * from './timelion_vis'; diff --git a/src/plugins/vis_type_timelion/public/components/timelion_vis.tsx b/src/plugins/vis_type_timelion/public/components/timelion_vis.tsx deleted file mode 100644 index aa594c749b600e..00000000000000 --- a/src/plugins/vis_type_timelion/public/components/timelion_vis.tsx +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import React from 'react'; - -import { IUiSettingsClient } from 'kibana/public'; -import { ChartComponent } from './chart'; -import { VisParams } from '../timelion_vis_fn'; -import { TimelionSuccessResponse } from '../helpers/timelion_request_handler'; -import { ExprVis } from '../../../visualizations/public'; - -export interface TimelionVisComponentProp { - config: IUiSettingsClient; - renderComplete(): void; - updateStatus: object; - vis: ExprVis; - visData: TimelionSuccessResponse; - visParams: VisParams; -} - -function TimelionVisComponent(props: TimelionVisComponentProp) { - return ( -
- -
- ); -} - -export { TimelionVisComponent }; diff --git a/src/plugins/vis_type_timelion/public/components/panel.tsx b/src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx similarity index 90% rename from src/plugins/vis_type_timelion/public/components/panel.tsx rename to src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx index 9c30a6b75d6dbc..a7b623ac8680c6 100644 --- a/src/plugins/vis_type_timelion/public/components/panel.tsx +++ b/src/plugins/vis_type_timelion/public/components/timelion_vis_component.tsx @@ -21,7 +21,9 @@ import React, { useState, useEffect, useMemo, useCallback } from 'react'; import $ from 'jquery'; import moment from 'moment-timezone'; import { debounce, compact, get, each, cloneDeep, last, map } from 'lodash'; +import { useResizeObserver } from '@elastic/eui'; +import { IInterpreterRenderHandlers } from 'src/plugins/expressions'; import { useKibana } from '../../../kibana_react/public'; import '../flot'; import { DEFAULT_TIME_FORMAT } from '../../common/lib'; @@ -38,18 +40,19 @@ import { Series, Sheet } from '../helpers/timelion_request_handler'; import { tickFormatters } from '../helpers/tick_formatters'; import { generateTicksProvider } from '../helpers/tick_generator'; import { TimelionVisDependencies } from '../plugin'; -import { ExprVisAPIEvents } from '../../../visualizations/public'; + +import './index.scss'; interface CrosshairPlot extends jquery.flot.plot { setCrosshair: (pos: Position) => void; clearCrosshair: () => void; } -interface PanelProps { - applyFilter: ExprVisAPIEvents['applyFilter']; +interface TimelionVisComponentProps { + fireEvent: IInterpreterRenderHandlers['event']; interval: string; seriesList: Sheet; - renderComplete(): void; + renderComplete: IInterpreterRenderHandlers['done']; } interface Position { @@ -75,11 +78,16 @@ const DEBOUNCE_DELAY = 50; // ensure legend is the same height with or without a caption so legend items do not move around const emptyCaption = '
'; -function Panel({ interval, seriesList, renderComplete, applyFilter }: PanelProps) { +function TimelionVisComponent({ + interval, + seriesList, + renderComplete, + fireEvent, +}: TimelionVisComponentProps) { const kibana = useKibana(); const [chart, setChart] = useState(() => cloneDeep(seriesList.list)); const [canvasElem, setCanvasElem] = useState(); - const [chartElem, setChartElem] = useState(); + const [chartElem, setChartElem] = useState(null); const [originalColorMap, setOriginalColorMap] = useState(() => new Map()); @@ -191,7 +199,7 @@ function Panel({ interval, seriesList, renderComplete, applyFilter }: PanelProps interval, kibana.services.timefilter, kibana.services.uiSettings, - chartElem && chartElem.clientWidth, + chartElem?.clientWidth, grid ); const updatedSeries = buildSeriesData(chartValue, options); @@ -216,12 +224,14 @@ function Panel({ interval, seriesList, renderComplete, applyFilter }: PanelProps updateCaption(newPlot.getData()); } }, - [canvasElem, chartElem, renderComplete, kibana.services, interval, updateCaption] + [canvasElem, chartElem?.clientWidth, renderComplete, kibana.services, interval, updateCaption] ); + const dimensions = useResizeObserver(chartElem); + useEffect(() => { updatePlot(chart, seriesList.render && seriesList.render.grid); - }, [chart, updatePlot, seriesList.render]); + }, [chart, updatePlot, seriesList.render, dimensions]); useEffect(() => { const colorsSet: Array<[Series, string]> = []; @@ -349,21 +359,24 @@ function Panel({ interval, seriesList, renderComplete, applyFilter }: PanelProps const plotSelectedHandler = useCallback( (event: JQuery.TriggeredEvent, ranges: Ranges) => { - applyFilter({ - timeFieldName: '*', - filters: [ - { - range: { - '*': { - gte: ranges.xaxis.from, - lte: ranges.xaxis.to, + fireEvent({ + name: 'applyFilter', + data: { + timeFieldName: '*', + filters: [ + { + range: { + '*': { + gte: ranges.xaxis.from, + lte: ranges.xaxis.to, + }, }, }, - }, - ], + ], + }, }); }, - [applyFilter] + [fireEvent] ); useEffect(() => { @@ -396,4 +409,6 @@ function Panel({ interval, seriesList, renderComplete, applyFilter }: PanelProps ); } -export { Panel }; +// default export required for React.Lazy +// eslint-disable-next-line import/no-default-export +export { TimelionVisComponent as default }; diff --git a/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts b/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts index 3442f84599fb82..975d12a152d89d 100644 --- a/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts +++ b/src/plugins/vis_type_timelion/public/helpers/timelion_request_handler.ts @@ -19,10 +19,10 @@ import { i18n } from '@kbn/i18n'; import { KIBANA_CONTEXT_NAME } from 'src/plugins/expressions/public'; -import { VisParams } from '../../../visualizations/public'; import { TimeRange, Filter, esQuery, Query } from '../../../data/public'; import { TimelionVisDependencies } from '../plugin'; import { getTimezone } from './get_timezone'; +import { TimelionVisParams } from '../timelion_vis_fn'; interface Stats { cacheCount: number; @@ -77,7 +77,7 @@ export function getTimelionRequestHandler({ timeRange: TimeRange; filters: Filter[]; query: Query; - visParams: VisParams; + visParams: TimelionVisParams; }): Promise { const expression = visParams.expression; diff --git a/src/plugins/vis_type_timelion/public/index.scss b/src/plugins/vis_type_timelion/public/index.scss deleted file mode 100644 index 00e9a885209610..00000000000000 --- a/src/plugins/vis_type_timelion/public/index.scss +++ /dev/null @@ -1,3 +0,0 @@ -@import './timelion_vis'; -@import './timelion_editor'; -@import './components/index'; diff --git a/src/plugins/vis_type_timelion/public/plugin.ts b/src/plugins/vis_type_timelion/public/plugin.ts index e2c7efec34c7f3..bb8fb6b298a077 100644 --- a/src/plugins/vis_type_timelion/public/plugin.ts +++ b/src/plugins/vis_type_timelion/public/plugin.ts @@ -39,8 +39,8 @@ import { getTimelionVisDefinition } from './timelion_vis_type'; import { setIndexPatterns, setSavedObjectsClient } from './helpers/plugin_services'; import { ConfigSchema } from '../config'; -import './index.scss'; import { getArgValueSuggestions } from './helpers/arg_value_suggestions'; +import { getTimelionVisRenderer } from './timelion_vis_renderer'; /** @internal */ export interface TimelionVisDependencies extends Partial { @@ -93,7 +93,8 @@ export class TimelionVisPlugin }; expressions.registerFunction(() => getTimelionVisualizationConfig(dependencies)); - visualizations.createReactVisualization(getTimelionVisDefinition(dependencies)); + expressions.registerRenderer(getTimelionVisRenderer(dependencies)); + visualizations.createBaseVisualization(getTimelionVisDefinition(dependencies)); return { isUiEnabled: this.initializerContext.config.get().ui.enabled, diff --git a/src/plugins/vis_type_timelion/public/timelion_options.tsx b/src/plugins/vis_type_timelion/public/timelion_options.tsx index dfe017d3a273f5..1ef8088c7a7143 100644 --- a/src/plugins/vis_type_timelion/public/timelion_options.tsx +++ b/src/plugins/vis_type_timelion/public/timelion_options.tsx @@ -21,30 +21,45 @@ import React, { useCallback } from 'react'; import { EuiPanel } from '@elastic/eui'; import { VisOptionsProps } from 'src/plugins/vis_default_editor/public'; -import { VisParams } from './timelion_vis_fn'; +import { KibanaContextProvider } from '../../kibana_react/public'; + +import { TimelionVisParams } from './timelion_vis_fn'; import { TimelionInterval, TimelionExpressionInput } from './components'; +import { TimelionVisDependencies } from './plugin'; -export type TimelionOptionsProps = VisOptionsProps; +export type TimelionOptionsProps = VisOptionsProps; -function TimelionOptions({ stateParams, setValue, setValidity }: TimelionOptionsProps) { - const setInterval = useCallback((value: VisParams['interval']) => setValue('interval', value), [ - setValue, - ]); +function TimelionOptions({ + services, + stateParams, + setValue, + setValidity, +}: TimelionOptionsProps & { + services: TimelionVisDependencies; +}) { + const setInterval = useCallback( + (value: TimelionVisParams['interval']) => setValue('interval', value), + [setValue] + ); const setExpressionInput = useCallback( - (value: VisParams['expression']) => setValue('expression', value), + (value: TimelionVisParams['expression']) => setValue('expression', value), [setValue] ); return ( - - - - + + + + + + ); } -export { TimelionOptions }; +// default export required for React.Lazy +// eslint-disable-next-line import/no-default-export +export { TimelionOptions as default }; diff --git a/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts b/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts index d3c6ca5d90371d..a0cd410e197ff0 100644 --- a/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts +++ b/src/plugins/vis_type_timelion/public/timelion_vis_fn.ts @@ -24,29 +24,39 @@ import { KibanaContext, Render, } from 'src/plugins/expressions/public'; -import { getTimelionRequestHandler } from './helpers/timelion_request_handler'; +import { + getTimelionRequestHandler, + TimelionSuccessResponse, +} from './helpers/timelion_request_handler'; import { TIMELION_VIS_NAME } from './timelion_vis_type'; import { TimelionVisDependencies } from './plugin'; import { Filter, Query, TimeRange } from '../../data/common'; type Input = KibanaContext | null; -type Output = Promise>; +type Output = Promise>; interface Arguments { expression: string; interval: string; } -interface RenderValue { - visData: Input; +export interface TimelionRenderValue { + visData: TimelionSuccessResponse; visType: 'timelion'; - visParams: VisParams; + visParams: TimelionVisParams; } -export type VisParams = Arguments; +export type TimelionVisParams = Arguments; + +export type TimelionExpressionFunctionDefinition = ExpressionFunctionDefinition< + 'timelion_vis', + Input, + Arguments, + Output +>; export const getTimelionVisualizationConfig = ( dependencies: TimelionVisDependencies -): ExpressionFunctionDefinition<'timelion_vis', Input, Arguments, Output> => ({ +): TimelionExpressionFunctionDefinition => ({ name: 'timelion_vis', type: 'render', inputTypes: ['kibana_context', 'null'], @@ -82,7 +92,7 @@ export const getTimelionVisualizationConfig = ( return { type: 'render', - as: 'visualization', + as: 'timelion_vis', value: { visParams, visType: TIMELION_VIS_NAME, diff --git a/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx b/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx new file mode 100644 index 00000000000000..13a279138a8e4b --- /dev/null +++ b/src/plugins/vis_type_timelion/public/timelion_vis_renderer.tsx @@ -0,0 +1,65 @@ +/* + * 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, { lazy } from 'react'; +import { render, unmountComponentAtNode } from 'react-dom'; + +import { ExpressionRenderDefinition } from 'src/plugins/expressions'; +import { KibanaContextProvider } from '../../kibana_react/public'; +import { VisualizationContainer } from '../../visualizations/public'; +import { TimelionVisDependencies } from './plugin'; +import { TimelionRenderValue } from './timelion_vis_fn'; +// @ts-ignore +const TimelionVisComponent = lazy(() => import('./components/timelion_vis_component')); + +export const getTimelionVisRenderer: ( + deps: TimelionVisDependencies +) => ExpressionRenderDefinition = (deps) => ({ + name: 'timelion_vis', + displayName: 'Timelion visualization', + reuseDomNode: true, + render: (domNode, { visData, visParams }, handlers) => { + handlers.onDestroy(() => { + unmountComponentAtNode(domNode); + }); + + const [seriesList] = visData.sheet; + const showNoResult = !seriesList || !seriesList.list.length; + + if (showNoResult) { + // send the render complete event when there is no data to show + // to notify that a chart is updated + handlers.done(); + } + + render( + + + + + , + domNode + ); + }, +}); diff --git a/src/plugins/vis_type_timelion/public/timelion_vis_type.tsx b/src/plugins/vis_type_timelion/public/timelion_vis_type.tsx index 8fdde175708e0e..a5425478e46acf 100644 --- a/src/plugins/vis_type_timelion/public/timelion_vis_type.tsx +++ b/src/plugins/vis_type_timelion/public/timelion_vis_type.tsx @@ -17,18 +17,19 @@ * under the License. */ -import React from 'react'; +import React, { lazy } from 'react'; import { i18n } from '@kbn/i18n'; -import { KibanaContextProvider } from '../../kibana_react/public'; import { DefaultEditorSize } from '../../vis_default_editor/public'; import { getTimelionRequestHandler } from './helpers/timelion_request_handler'; -import { TimelionVisComponent, TimelionVisComponentProp } from './components'; -import { TimelionOptions, TimelionOptionsProps } from './timelion_options'; +import { TimelionOptionsProps } from './timelion_options'; import { TimelionVisDependencies } from './plugin'; +import { toExpressionAst } from './to_ast'; import { VIS_EVENT_TO_TRIGGER } from '../../visualizations/public'; +const TimelionOptions = lazy(() => import('./timelion_options')); + export const TIMELION_VIS_NAME = 'timelion'; export function getTimelionVisDefinition(dependencies: TimelionVisDependencies) { @@ -48,21 +49,15 @@ export function getTimelionVisDefinition(dependencies: TimelionVisDependencies) expression: '.es(*)', interval: 'auto', }, - component: (props: TimelionVisComponentProp) => ( - - - - ), }, editorConfig: { optionsTemplate: (props: TimelionOptionsProps) => ( - - - + ), defaultSize: DefaultEditorSize.MEDIUM, }, requestHandler: timelionRequestHandler, + toExpressionAst, responseHandler: 'none', inspectorAdapters: {}, getSupportedTriggers: () => { diff --git a/src/plugins/vis_type_timelion/public/components/chart.tsx b/src/plugins/vis_type_timelion/public/to_ast.test.ts similarity index 60% rename from src/plugins/vis_type_timelion/public/components/chart.tsx rename to src/plugins/vis_type_timelion/public/to_ast.test.ts index 15a376d4e96386..8a9d4b83f94d20 100644 --- a/src/plugins/vis_type_timelion/public/components/chart.tsx +++ b/src/plugins/vis_type_timelion/public/to_ast.test.ts @@ -17,25 +17,24 @@ * under the License. */ -import React from 'react'; +import { Vis } from 'src/plugins/visualizations/public'; +import { TimelionVisParams } from './timelion_vis_fn'; +import { toExpressionAst } from './to_ast'; -import { Sheet } from '../helpers/timelion_request_handler'; -import { Panel } from './panel'; -import { ExprVisAPIEvents } from '../../../visualizations/public'; +describe('timelion vis toExpressionAst function', () => { + let vis: Vis; -interface ChartComponentProp { - applyFilter: ExprVisAPIEvents['applyFilter']; - interval: string; - renderComplete(): void; - seriesList: Sheet; -} + beforeEach(() => { + vis = { + params: { + expression: '.es(*)', + interval: 'auto', + }, + } as any; + }); -function ChartComponent(props: ChartComponentProp) { - if (!props.seriesList) { - return null; - } - - return ; -} - -export { ChartComponent }; + it('should match basic snapshot', () => { + const actual = toExpressionAst(vis); + expect(actual).toMatchSnapshot(); + }); +}); diff --git a/src/plugins/vis_type_timelion/public/to_ast.ts b/src/plugins/vis_type_timelion/public/to_ast.ts new file mode 100644 index 00000000000000..7044bbf4e58318 --- /dev/null +++ b/src/plugins/vis_type_timelion/public/to_ast.ts @@ -0,0 +1,37 @@ +/* + * 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 { buildExpression, buildExpressionFunction } from '../../expressions/public'; +import { Vis } from '../../visualizations/public'; +import { TimelionExpressionFunctionDefinition, TimelionVisParams } from './timelion_vis_fn'; + +const escapeString = (data: string): string => { + return data.replace(/\\/g, `\\\\`).replace(/'/g, `\\'`); +}; + +export const toExpressionAst = (vis: Vis) => { + const timelion = buildExpressionFunction('timelion_vis', { + expression: escapeString(vis.params.expression), + interval: escapeString(vis.params.interval), + }); + + const ast = buildExpression([timelion]); + + return ast.toAst(); +}; diff --git a/src/plugins/visualizations/public/legacy/__snapshots__/build_pipeline.test.ts.snap b/src/plugins/visualizations/public/legacy/__snapshots__/build_pipeline.test.ts.snap index 654ac78cdaa022..c0c37e2262f9c6 100644 --- a/src/plugins/visualizations/public/legacy/__snapshots__/build_pipeline.test.ts.snap +++ b/src/plugins/visualizations/public/legacy/__snapshots__/build_pipeline.test.ts.snap @@ -24,6 +24,4 @@ exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunct exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles tile_map function 1`] = `"tilemap visConfig='{\\"metric\\":{},\\"dimensions\\":{\\"metric\\":{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},\\"geohash\\":1,\\"geocentroid\\":3}}' "`; -exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles timelion function 1`] = `"timelion_vis expression='foo' interval='bar' "`; - exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles vega function 1`] = `"vega spec='this is a test' "`; diff --git a/src/plugins/visualizations/public/legacy/build_pipeline.test.ts b/src/plugins/visualizations/public/legacy/build_pipeline.test.ts index 8cac76726b13b0..a1fea45f517816 100644 --- a/src/plugins/visualizations/public/legacy/build_pipeline.test.ts +++ b/src/plugins/visualizations/public/legacy/build_pipeline.test.ts @@ -117,12 +117,6 @@ describe('visualize loader pipeline helpers: build pipeline', () => { expect(actual).toMatchSnapshot(); }); - it('handles timelion function', () => { - const params = { expression: 'foo', interval: 'bar' }; - const actual = buildPipelineVisFunction.timelion(params, schemasDef, uiState); - expect(actual).toMatchSnapshot(); - }); - describe('handles table function', () => { it('without splits or buckets', () => { const params = { foo: 'bar' }; diff --git a/src/plugins/visualizations/public/legacy/build_pipeline.ts b/src/plugins/visualizations/public/legacy/build_pipeline.ts index dcc384a191858f..79e1c1cca2155a 100644 --- a/src/plugins/visualizations/public/legacy/build_pipeline.ts +++ b/src/plugins/visualizations/public/legacy/build_pipeline.ts @@ -263,11 +263,6 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = { const paramsArray = [paramsJson, uiStateJson].filter((param) => Boolean(param)); return `tsvb ${paramsArray.join(' ')}`; }, - timelion: (params) => { - const expression = prepareString('expression', params.expression); - const interval = prepareString('interval', params.interval); - return `timelion_vis ${expression}${interval}`; - }, table: (params, schemas) => { const visConfig = { ...params,