Timelion visualization renderer (#78540)
* Update styles * Implement toExpressionAst fn * Implement renderer * Update unit tests * Add unit tests * Update types * Remove unused vars * Fix types * Update types * Show error message when no data * Update ExpressionRenderDefinition api * Update renderer when there is no data * Make options component lazy Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
9f5033354d
commit
b692c374a2
|
@ -9,5 +9,5 @@ A user friendly name of the renderer as will be displayed to user in UI.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
displayName: string;
|
||||
displayName?: string;
|
||||
```
|
||||
|
|
|
@ -9,5 +9,5 @@ A user friendly name of the renderer as will be displayed to user in UI.
|
|||
<b>Signature:</b>
|
||||
|
||||
```typescript
|
||||
displayName: string;
|
||||
displayName?: string;
|
||||
```
|
||||
|
|
|
@ -28,7 +28,7 @@ export interface ExpressionRenderDefinition<Config = unknown> {
|
|||
/**
|
||||
* 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
|
||||
|
|
|
@ -429,7 +429,7 @@ export interface ExpressionImage {
|
|||
//
|
||||
// @public (undocumented)
|
||||
export interface ExpressionRenderDefinition<Config = unknown> {
|
||||
displayName: string;
|
||||
displayName?: string;
|
||||
help?: string;
|
||||
name: string;
|
||||
render: (domNode: HTMLElement, config: Config, handlers: IInterpreterRenderHandlers) => void | Promise<void>;
|
||||
|
|
|
@ -401,7 +401,7 @@ export interface ExpressionImage {
|
|||
//
|
||||
// @public (undocumented)
|
||||
export interface ExpressionRenderDefinition<Config = unknown> {
|
||||
displayName: string;
|
||||
displayName?: string;
|
||||
help?: string;
|
||||
name: string;
|
||||
render: (domNode: HTMLElement, config: Config, handlers: IInterpreterRenderHandlers) => void | Promise<void>;
|
||||
|
|
|
@ -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';
|
||||
|
|
|
@ -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: (
|
||||
|
|
21
src/plugins/vis_type_timelion/public/__snapshots__/to_ast.test.ts.snap
generated
Normal file
21
src/plugins/vis_type_timelion/public/__snapshots__/to_ast.test.ts.snap
generated
Normal file
|
@ -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",
|
||||
}
|
||||
`;
|
|
@ -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%;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
.timVis {
|
||||
min-width: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
.timChart {
|
||||
min-width: 100%;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
|
@ -58,3 +58,11 @@
|
|||
white-space: nowrap;
|
||||
font-weight: $euiFontWeightBold;
|
||||
}
|
||||
|
||||
.visEditor--timelion {
|
||||
.visEditorSidebar__timelionOptions {
|
||||
flex: 1 1 auto;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
|
@ -1,2 +1,2 @@
|
|||
@import 'panel';
|
||||
@import 'timelion_vis';
|
||||
@import 'timelion_expression_input';
|
|
@ -19,4 +19,3 @@
|
|||
|
||||
export * from './timelion_expression_input';
|
||||
export * from './timelion_interval';
|
||||
export * from './timelion_vis';
|
||||
|
|
|
@ -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 (
|
||||
<div className="timVis">
|
||||
<ChartComponent
|
||||
applyFilter={props.vis.API.events.applyFilter}
|
||||
seriesList={props.visData.sheet[0]}
|
||||
renderComplete={props.renderComplete}
|
||||
interval={props.vis.getState().params.interval}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export { TimelionVisComponent };
|
|
@ -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 = '<br>';
|
||||
|
||||
function Panel({ interval, seriesList, renderComplete, applyFilter }: PanelProps) {
|
||||
function TimelionVisComponent({
|
||||
interval,
|
||||
seriesList,
|
||||
renderComplete,
|
||||
fireEvent,
|
||||
}: TimelionVisComponentProps) {
|
||||
const kibana = useKibana<TimelionVisDependencies>();
|
||||
const [chart, setChart] = useState(() => cloneDeep(seriesList.list));
|
||||
const [canvasElem, setCanvasElem] = useState<HTMLDivElement>();
|
||||
const [chartElem, setChartElem] = useState<HTMLDivElement>();
|
||||
const [chartElem, setChartElem] = useState<HTMLDivElement | null>(null);
|
||||
|
||||
const [originalColorMap, setOriginalColorMap] = useState(() => new Map<Series, string>());
|
||||
|
||||
|
@ -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 };
|
|
@ -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<TimelionSuccessResponse> {
|
||||
const expression = visParams.expression;
|
||||
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
@import './timelion_vis';
|
||||
@import './timelion_editor';
|
||||
@import './components/index';
|
|
@ -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<CoreStart> {
|
||||
|
@ -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,
|
||||
|
|
|
@ -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<VisParams>;
|
||||
export type TimelionOptionsProps = VisOptionsProps<TimelionVisParams>;
|
||||
|
||||
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 (
|
||||
<EuiPanel className="visEditorSidebar__timelionOptions" paddingSize="s">
|
||||
<TimelionInterval
|
||||
value={stateParams.interval}
|
||||
setValue={setInterval}
|
||||
setValidity={setValidity}
|
||||
/>
|
||||
<TimelionExpressionInput value={stateParams.expression} setValue={setExpressionInput} />
|
||||
</EuiPanel>
|
||||
<KibanaContextProvider services={services}>
|
||||
<EuiPanel className="visEditorSidebar__timelionOptions" paddingSize="s">
|
||||
<TimelionInterval
|
||||
value={stateParams.interval}
|
||||
setValue={setInterval}
|
||||
setValidity={setValidity}
|
||||
/>
|
||||
<TimelionExpressionInput value={stateParams.expression} setValue={setExpressionInput} />
|
||||
</EuiPanel>
|
||||
</KibanaContextProvider>
|
||||
);
|
||||
}
|
||||
|
||||
export { TimelionOptions };
|
||||
// default export required for React.Lazy
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { TimelionOptions as default };
|
||||
|
|
|
@ -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<Render<RenderValue>>;
|
||||
type Output = Promise<Render<TimelionRenderValue>>;
|
||||
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,
|
||||
|
|
|
@ -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<TimelionRenderValue> = (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(
|
||||
<VisualizationContainer showNoResult={showNoResult}>
|
||||
<KibanaContextProvider services={{ ...deps }}>
|
||||
<TimelionVisComponent
|
||||
interval={visParams.interval}
|
||||
seriesList={seriesList}
|
||||
renderComplete={handlers.done}
|
||||
fireEvent={handlers.event}
|
||||
/>
|
||||
</KibanaContextProvider>
|
||||
</VisualizationContainer>,
|
||||
domNode
|
||||
);
|
||||
},
|
||||
});
|
|
@ -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) => (
|
||||
<KibanaContextProvider services={{ ...dependencies }}>
|
||||
<TimelionVisComponent {...props} />
|
||||
</KibanaContextProvider>
|
||||
),
|
||||
},
|
||||
editorConfig: {
|
||||
optionsTemplate: (props: TimelionOptionsProps) => (
|
||||
<KibanaContextProvider services={{ ...dependencies }}>
|
||||
<TimelionOptions {...props} />
|
||||
</KibanaContextProvider>
|
||||
<TimelionOptions services={dependencies} {...props} />
|
||||
),
|
||||
defaultSize: DefaultEditorSize.MEDIUM,
|
||||
},
|
||||
requestHandler: timelionRequestHandler,
|
||||
toExpressionAst,
|
||||
responseHandler: 'none',
|
||||
inspectorAdapters: {},
|
||||
getSupportedTriggers: () => {
|
||||
|
|
|
@ -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<TimelionVisParams>;
|
||||
|
||||
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 <Panel {...props} />;
|
||||
}
|
||||
|
||||
export { ChartComponent };
|
||||
it('should match basic snapshot', () => {
|
||||
const actual = toExpressionAst(vis);
|
||||
expect(actual).toMatchSnapshot();
|
||||
});
|
||||
});
|
37
src/plugins/vis_type_timelion/public/to_ast.ts
Normal file
37
src/plugins/vis_type_timelion/public/to_ast.ts
Normal file
|
@ -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<TimelionVisParams>) => {
|
||||
const timelion = buildExpressionFunction<TimelionExpressionFunctionDefinition>('timelion_vis', {
|
||||
expression: escapeString(vis.params.expression),
|
||||
interval: escapeString(vis.params.interval),
|
||||
});
|
||||
|
||||
const ast = buildExpression([timelion]);
|
||||
|
||||
return ast.toAst();
|
||||
};
|
|
@ -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' "`;
|
||||
|
|
|
@ -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' };
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in a new issue