mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Vislib visualization renderer (#80744)
This commit is contained in:
parent
5752b7a8dd
commit
e0b6b0ba5c
69 changed files with 4227 additions and 679 deletions
|
@ -45,7 +45,9 @@ export const TagCloudChart = ({
|
|||
const visController = useRef<any>(null);
|
||||
|
||||
useEffect(() => {
|
||||
visController.current = new TagCloudVisualization(chartDiv.current, colors, fireEvent);
|
||||
if (chartDiv.current) {
|
||||
visController.current = new TagCloudVisualization(chartDiv.current, colors, fireEvent);
|
||||
}
|
||||
return () => {
|
||||
visController.current.destroy();
|
||||
visController.current = null;
|
||||
|
|
|
@ -42,12 +42,6 @@ export const getTimelionVisRenderer: (
|
|||
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 handlers={handlers} showNoResult={showNoResult}>
|
||||
<KibanaContextProvider services={{ ...deps }}>
|
||||
|
|
|
@ -2,12 +2,9 @@
|
|||
|
||||
exports[`interpreter/functions#pie returns an object with the correct structure 1`] = `
|
||||
Object {
|
||||
"as": "visualization",
|
||||
"as": "vislib_vis",
|
||||
"type": "render",
|
||||
"value": Object {
|
||||
"params": Object {
|
||||
"listenOnChange": true,
|
||||
},
|
||||
"visConfig": Object {
|
||||
"addLegend": true,
|
||||
"addTooltip": true,
|
||||
|
|
22
src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap
generated
Normal file
22
src/plugins/vis_type_vislib/public/__snapshots__/to_ast.test.ts.snap
generated
Normal file
|
@ -0,0 +1,22 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`vislib vis toExpressionAst function should match basic snapshot 1`] = `
|
||||
Object {
|
||||
"addArgument": [Function],
|
||||
"arguments": Object {
|
||||
"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\\":{}}]}}",
|
||||
],
|
||||
},
|
||||
"getArgument": [Function],
|
||||
"name": "vislib_vis",
|
||||
"removeArgument": [Function],
|
||||
"replaceArgument": [Function],
|
||||
"toAst": [Function],
|
||||
"toString": [Function],
|
||||
"type": "expression_function_builder",
|
||||
}
|
||||
`;
|
19
src/plugins/vis_type_vislib/public/__snapshots__/to_ast_pie.test.ts.snap
generated
Normal file
19
src/plugins/vis_type_vislib/public/__snapshots__/to_ast_pie.test.ts.snap
generated
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`vislib pie vis toExpressionAst function should match basic snapshot 1`] = `
|
||||
Object {
|
||||
"addArgument": [Function],
|
||||
"arguments": Object {
|
||||
"visConfig": Array [
|
||||
"{\\"type\\":\\"pie\\",\\"addTooltip\\":true,\\"addLegend\\":true,\\"legendPosition\\":\\"right\\",\\"isDonut\\":true,\\"labels\\":{\\"show\\":true,\\"values\\":true,\\"last_level\\":true,\\"truncate\\":100},\\"dimensions\\":{\\"metric\\":{\\"accessor\\":0,\\"format\\":{\\"id\\":\\"number\\"},\\"params\\":{}},\\"buckets\\":[{\\"accessor\\":1,\\"format\\":{\\"id\\":\\"terms\\",\\"params\\":{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\",\\"parsedUrl\\":{\\"origin\\":\\"http://localhost:5801\\",\\"pathname\\":\\"/app/visualize\\",\\"basePath\\":\\"\\"}}},\\"params\\":{}}]}}",
|
||||
],
|
||||
},
|
||||
"getArgument": [Function],
|
||||
"name": "vislib_pie_vis",
|
||||
"removeArgument": [Function],
|
||||
"replaceArgument": [Function],
|
||||
"toAst": [Function],
|
||||
"toString": [Function],
|
||||
"type": "expression_function_builder",
|
||||
}
|
||||
`;
|
|
@ -37,22 +37,20 @@ import {
|
|||
getConfigCollections,
|
||||
} from './utils/collections';
|
||||
import { getAreaOptionTabs, countLabel } from './utils/common_config';
|
||||
import { createVislibVisController } from './vis_controller';
|
||||
import { VisTypeVislibDependencies } from './plugin';
|
||||
import { Rotates } from '../../charts/public';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
export const createAreaVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
|
||||
export const areaVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
name: 'area',
|
||||
title: i18n.translate('visTypeVislib.area.areaTitle', { defaultMessage: 'Area' }),
|
||||
icon: 'visArea',
|
||||
description: i18n.translate('visTypeVislib.area.areaDescription', {
|
||||
defaultMessage: 'Emphasize the quantity beneath a line chart',
|
||||
}),
|
||||
visualization: createVislibVisController(deps),
|
||||
getSupportedTriggers: () => {
|
||||
return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush];
|
||||
},
|
||||
getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush],
|
||||
toExpressionAst,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
type: 'area',
|
||||
|
@ -131,9 +129,6 @@ export const createAreaVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
|
|||
labels: {},
|
||||
},
|
||||
},
|
||||
events: {
|
||||
brush: { disabled: false },
|
||||
},
|
||||
editorConfig: {
|
||||
collections: getConfigCollections(),
|
||||
optionTabs: getAreaOptionTabs(),
|
||||
|
@ -190,4 +185,4 @@ export const createAreaVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
|
|||
},
|
||||
]),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -60,4 +60,6 @@ function GaugeOptions(props: VisOptionsProps<GaugeVisParams>) {
|
|||
);
|
||||
}
|
||||
|
||||
export { GaugeOptions };
|
||||
// default export required for React.Lazy
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { GaugeOptions as default };
|
||||
|
|
|
@ -185,4 +185,6 @@ function HeatmapOptions(props: VisOptionsProps<HeatmapVisParams>) {
|
|||
);
|
||||
}
|
||||
|
||||
export { HeatmapOptions };
|
||||
// default export required for React.Lazy
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { HeatmapOptions as default };
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* 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 { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { ValidationVisOptionsProps } from '../common';
|
||||
import { GaugeVisParams } from '../../gauge';
|
||||
import { PieVisParams } from '../../pie';
|
||||
import { BasicVislibParams } from '../../types';
|
||||
import { HeatmapVisParams } from '../../heatmap';
|
||||
|
||||
const GaugeOptionsLazy = lazy(() => import('./gauge'));
|
||||
const PieOptionsLazy = lazy(() => import('./pie'));
|
||||
const PointSeriesOptionsLazy = lazy(() => import('./point_series'));
|
||||
const HeatmapOptionsLazy = lazy(() => import('./heatmap'));
|
||||
const MetricsAxisOptionsLazy = lazy(() => import('./metrics_axes'));
|
||||
|
||||
export const GaugeOptions = (props: VisOptionsProps<GaugeVisParams>) => (
|
||||
<GaugeOptionsLazy {...props} />
|
||||
);
|
||||
|
||||
export const PieOptions = (props: VisOptionsProps<PieVisParams>) => <PieOptionsLazy {...props} />;
|
||||
|
||||
export const PointSeriesOptions = (props: ValidationVisOptionsProps<BasicVislibParams>) => (
|
||||
<PointSeriesOptionsLazy {...props} />
|
||||
);
|
||||
|
||||
export const HeatmapOptions = (props: VisOptionsProps<HeatmapVisParams>) => (
|
||||
<HeatmapOptionsLazy {...props} />
|
||||
);
|
||||
|
||||
export const MetricsAxisOptions = (props: ValidationVisOptionsProps<BasicVislibParams>) => (
|
||||
<MetricsAxisOptionsLazy {...props} />
|
||||
);
|
|
@ -21,7 +21,7 @@ import React from 'react';
|
|||
import { mount, shallow } from 'enzyme';
|
||||
|
||||
import { IAggConfig, IAggType } from 'src/plugins/data/public';
|
||||
import { MetricsAxisOptions } from './index';
|
||||
import MetricsAxisOptions from './index';
|
||||
import { BasicVislibParams, SeriesParam, ValueAxis } from '../../../types';
|
||||
import { ValidationVisOptionsProps } from '../../common';
|
||||
import { Positions } from '../../../utils/collections';
|
||||
|
|
|
@ -325,4 +325,6 @@ function MetricsAxisOptions(props: ValidationVisOptionsProps<BasicVislibParams>)
|
|||
) : null;
|
||||
}
|
||||
|
||||
export { MetricsAxisOptions };
|
||||
// default export required for React.Lazy
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { MetricsAxisOptions as default };
|
||||
|
|
|
@ -99,4 +99,6 @@ function PieOptions(props: VisOptionsProps<PieVisParams>) {
|
|||
);
|
||||
}
|
||||
|
||||
export { PieOptions };
|
||||
// default export required for React.Lazy
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { PieOptions as default };
|
||||
|
|
|
@ -17,4 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { PointSeriesOptions } from './point_series';
|
||||
// default export required for React.Lazy
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { PointSeriesOptions as default } from './point_series';
|
||||
|
|
|
@ -24,8 +24,9 @@ import { AggGroupNames } from '../../data/public';
|
|||
import { GaugeOptions } from './components/options';
|
||||
import { getGaugeCollections, Alignments, GaugeTypes } from './utils/collections';
|
||||
import { ColorModes, ColorSchemas, ColorSchemaParams, Labels, Style } from '../../charts/public';
|
||||
import { createVislibVisController } from './vis_controller';
|
||||
import { VisTypeVislibDependencies } from './plugin';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
export interface Gauge extends ColorSchemaParams {
|
||||
backStyle: 'Full';
|
||||
|
@ -55,7 +56,7 @@ export interface GaugeVisParams {
|
|||
gauge: Gauge;
|
||||
}
|
||||
|
||||
export const createGaugeVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
|
||||
export const gaugeVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
name: 'gauge',
|
||||
title: i18n.translate('visTypeVislib.gauge.gaugeTitle', { defaultMessage: 'Gauge' }),
|
||||
icon: 'visGauge',
|
||||
|
@ -63,6 +64,7 @@ export const createGaugeVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
|
|||
defaultMessage:
|
||||
"Gauges indicate the status of a metric. Use it to show how a metric's value relates to reference threshold values.",
|
||||
}),
|
||||
toExpressionAst,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
type: 'gauge',
|
||||
|
@ -109,7 +111,6 @@ export const createGaugeVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
|
|||
},
|
||||
},
|
||||
},
|
||||
visualization: createVislibVisController(deps),
|
||||
editorConfig: {
|
||||
collections: getGaugeCollections(),
|
||||
optionsTemplate: GaugeOptions,
|
||||
|
@ -145,4 +146,4 @@ export const createGaugeVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
|
|||
]),
|
||||
},
|
||||
useCustomNoDataScreen: true,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -21,20 +21,21 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { GaugeOptions } from './components/options';
|
||||
import { getGaugeCollections, GaugeTypes } from './utils/collections';
|
||||
import { createVislibVisController } from './vis_controller';
|
||||
import { VisTypeVislibDependencies } from './plugin';
|
||||
import { ColorModes, ColorSchemas } from '../../charts/public';
|
||||
import { AggGroupNames } from '../../data/public';
|
||||
import { Schemas } from '../../vis_default_editor/public';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
export const createGoalVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
|
||||
export const goalVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
name: 'goal',
|
||||
title: i18n.translate('visTypeVislib.goal.goalTitle', { defaultMessage: 'Goal' }),
|
||||
icon: 'visGoal',
|
||||
description: i18n.translate('visTypeVislib.goal.goalDescription', {
|
||||
defaultMessage: 'A goal chart indicates how close you are to your final goal.',
|
||||
}),
|
||||
visualization: createVislibVisController(deps),
|
||||
toExpressionAst,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
addTooltip: true,
|
||||
|
@ -110,4 +111,4 @@ export const createGoalVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
|
|||
]),
|
||||
},
|
||||
useCustomNoDataScreen: true,
|
||||
});
|
||||
};
|
||||
|
|
|
@ -23,12 +23,11 @@ import { RangeValues, Schemas } from '../../vis_default_editor/public';
|
|||
import { AggGroupNames } from '../../data/public';
|
||||
import { AxisTypes, getHeatmapCollections, Positions, ScaleTypes } from './utils/collections';
|
||||
import { HeatmapOptions } from './components/options';
|
||||
import { createVislibVisController } from './vis_controller';
|
||||
import { TimeMarker } from './vislib/visualizations/time_marker';
|
||||
import { CommonVislibParams, ValueAxis } from './types';
|
||||
import { VisTypeVislibDependencies } from './plugin';
|
||||
import { BasicVislibParams, CommonVislibParams, ValueAxis } from './types';
|
||||
import { ColorSchemas, ColorSchemaParams } from '../../charts/public';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
|
||||
export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaParams {
|
||||
type: 'heatmap';
|
||||
|
@ -42,17 +41,15 @@ export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaParams
|
|||
times: TimeMarker[];
|
||||
}
|
||||
|
||||
export const createHeatmapVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
|
||||
export const heatmapVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
name: 'heatmap',
|
||||
title: i18n.translate('visTypeVislib.heatmap.heatmapTitle', { defaultMessage: 'Heat Map' }),
|
||||
icon: 'heatmap',
|
||||
description: i18n.translate('visTypeVislib.heatmap.heatmapDescription', {
|
||||
defaultMessage: 'Shade cells within a matrix',
|
||||
}),
|
||||
getSupportedTriggers: () => {
|
||||
return [VIS_EVENT_TO_TRIGGER.filter];
|
||||
},
|
||||
visualization: createVislibVisController(deps),
|
||||
getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter],
|
||||
toExpressionAst,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
type: 'heatmap',
|
||||
|
@ -86,9 +83,6 @@ export const createHeatmapVisTypeDefinition = (deps: VisTypeVislibDependencies)
|
|||
],
|
||||
},
|
||||
},
|
||||
events: {
|
||||
brush: { disabled: false },
|
||||
},
|
||||
editorConfig: {
|
||||
collections: getHeatmapCollections(),
|
||||
optionsTemplate: HeatmapOptions,
|
||||
|
@ -142,4 +136,4 @@ export const createHeatmapVisTypeDefinition = (deps: VisTypeVislibDependencies)
|
|||
},
|
||||
]),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -36,12 +36,12 @@ import {
|
|||
getConfigCollections,
|
||||
} from './utils/collections';
|
||||
import { getAreaOptionTabs, countLabel } from './utils/common_config';
|
||||
import { createVislibVisController } from './vis_controller';
|
||||
import { VisTypeVislibDependencies } from './plugin';
|
||||
import { Rotates } from '../../charts/public';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { BasicVislibParams } from './types';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
|
||||
export const createHistogramVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
|
||||
export const histogramVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
name: 'histogram',
|
||||
title: i18n.translate('visTypeVislib.histogram.histogramTitle', {
|
||||
defaultMessage: 'Vertical Bar',
|
||||
|
@ -50,10 +50,8 @@ export const createHistogramVisTypeDefinition = (deps: VisTypeVislibDependencies
|
|||
description: i18n.translate('visTypeVislib.histogram.histogramDescription', {
|
||||
defaultMessage: 'Assign a continuous variable to each axis',
|
||||
}),
|
||||
visualization: createVislibVisController(deps),
|
||||
getSupportedTriggers: () => {
|
||||
return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush];
|
||||
},
|
||||
getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush],
|
||||
toExpressionAst,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
type: 'histogram',
|
||||
|
@ -133,9 +131,6 @@ export const createHistogramVisTypeDefinition = (deps: VisTypeVislibDependencies
|
|||
},
|
||||
},
|
||||
},
|
||||
events: {
|
||||
brush: { disabled: false },
|
||||
},
|
||||
editorConfig: {
|
||||
collections: getConfigCollections(),
|
||||
optionTabs: getAreaOptionTabs(),
|
||||
|
@ -192,4 +187,4 @@ export const createHistogramVisTypeDefinition = (deps: VisTypeVislibDependencies
|
|||
},
|
||||
]),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -34,12 +34,12 @@ import {
|
|||
getConfigCollections,
|
||||
} from './utils/collections';
|
||||
import { getAreaOptionTabs, countLabel } from './utils/common_config';
|
||||
import { createVislibVisController } from './vis_controller';
|
||||
import { VisTypeVislibDependencies } from './plugin';
|
||||
import { Rotates } from '../../charts/public';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { BasicVislibParams } from './types';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
|
||||
export const createHorizontalBarVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
|
||||
export const horizontalBarVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
name: 'horizontal_bar',
|
||||
title: i18n.translate('visTypeVislib.horizontalBar.horizontalBarTitle', {
|
||||
defaultMessage: 'Horizontal Bar',
|
||||
|
@ -48,10 +48,8 @@ export const createHorizontalBarVisTypeDefinition = (deps: VisTypeVislibDependen
|
|||
description: i18n.translate('visTypeVislib.horizontalBar.horizontalBarDescription', {
|
||||
defaultMessage: 'Assign a continuous variable to each axis',
|
||||
}),
|
||||
visualization: createVislibVisController(deps),
|
||||
getSupportedTriggers: () => {
|
||||
return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush];
|
||||
},
|
||||
getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush],
|
||||
toExpressionAst,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
type: 'histogram',
|
||||
|
@ -130,9 +128,6 @@ export const createHorizontalBarVisTypeDefinition = (deps: VisTypeVislibDependen
|
|||
},
|
||||
},
|
||||
},
|
||||
events: {
|
||||
brush: { disabled: false },
|
||||
},
|
||||
editorConfig: {
|
||||
collections: getConfigCollections(),
|
||||
optionTabs: getAreaOptionTabs(),
|
||||
|
@ -189,4 +184,4 @@ export const createHorizontalBarVisTypeDefinition = (deps: VisTypeVislibDependen
|
|||
},
|
||||
]),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -1 +1 @@
|
|||
@import './vislib/index'
|
||||
@import './vislib/index';
|
||||
|
|
|
@ -35,22 +35,20 @@ import {
|
|||
getConfigCollections,
|
||||
} from './utils/collections';
|
||||
import { getAreaOptionTabs, countLabel } from './utils/common_config';
|
||||
import { createVislibVisController } from './vis_controller';
|
||||
import { VisTypeVislibDependencies } from './plugin';
|
||||
import { Rotates } from '../../charts/public';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
export const createLineVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
|
||||
export const lineVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
name: 'line',
|
||||
title: i18n.translate('visTypeVislib.line.lineTitle', { defaultMessage: 'Line' }),
|
||||
icon: 'visLine',
|
||||
description: i18n.translate('visTypeVislib.line.lineDescription', {
|
||||
defaultMessage: 'Emphasize trends',
|
||||
}),
|
||||
visualization: createVislibVisController(deps),
|
||||
getSupportedTriggers: () => {
|
||||
return [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush];
|
||||
},
|
||||
getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter, VIS_EVENT_TO_TRIGGER.brush],
|
||||
toExpressionAst,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
type: 'line',
|
||||
|
@ -129,9 +127,6 @@ export const createLineVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
|
|||
},
|
||||
},
|
||||
},
|
||||
events: {
|
||||
brush: { disabled: false },
|
||||
},
|
||||
editorConfig: {
|
||||
collections: getConfigCollections(),
|
||||
optionTabs: getAreaOptionTabs(),
|
||||
|
@ -182,4 +177,4 @@ export const createLineVisTypeDefinition = (deps: VisTypeVislibDependencies) =>
|
|||
},
|
||||
]),
|
||||
},
|
||||
});
|
||||
};
|
||||
|
|
|
@ -23,14 +23,12 @@ import { AggGroupNames } from '../../data/public';
|
|||
import { Schemas } from '../../vis_default_editor/public';
|
||||
import { PieOptions } from './components/options';
|
||||
import { getPositions, Positions } from './utils/collections';
|
||||
import { createVislibVisController } from './vis_controller';
|
||||
import { CommonVislibParams } from './types';
|
||||
import { VisTypeVislibDependencies } from './plugin';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { toExpressionAst } from './to_ast_pie';
|
||||
|
||||
export interface PieVisParams extends CommonVislibParams {
|
||||
type: 'pie';
|
||||
addLegend: boolean;
|
||||
isDonut: boolean;
|
||||
labels: {
|
||||
show: boolean;
|
||||
|
@ -40,17 +38,15 @@ export interface PieVisParams extends CommonVislibParams {
|
|||
};
|
||||
}
|
||||
|
||||
export const createPieVisTypeDefinition = (deps: VisTypeVislibDependencies) => ({
|
||||
export const pieVisTypeDefinition: BaseVisTypeOptions<PieVisParams> = {
|
||||
name: 'pie',
|
||||
title: i18n.translate('visTypeVislib.pie.pieTitle', { defaultMessage: 'Pie' }),
|
||||
icon: 'visPie',
|
||||
description: i18n.translate('visTypeVislib.pie.pieDescription', {
|
||||
defaultMessage: 'Compare parts of a whole',
|
||||
}),
|
||||
visualization: createVislibVisController(deps),
|
||||
getSupportedTriggers: () => {
|
||||
return [VIS_EVENT_TO_TRIGGER.filter];
|
||||
},
|
||||
getSupportedTriggers: () => [VIS_EVENT_TO_TRIGGER.filter],
|
||||
toExpressionAst,
|
||||
visConfig: {
|
||||
defaults: {
|
||||
type: 'pie',
|
||||
|
@ -108,4 +104,4 @@ export const createPieVisTypeDefinition = (deps: VisTypeVislibDependencies) => (
|
|||
},
|
||||
hierarchicalData: true,
|
||||
responseHandler: 'vislib_slices',
|
||||
});
|
||||
};
|
||||
|
|
|
@ -18,27 +18,35 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressions/public';
|
||||
|
||||
// @ts-ignore
|
||||
import { vislibSlicesResponseHandler } from './vislib/response_handler';
|
||||
import { PieVisParams } from './pie';
|
||||
import { vislibVisName } from './vis_type_vislib_vis_fn';
|
||||
|
||||
export const vislibPieName = 'vislib_pie_vis';
|
||||
|
||||
interface Arguments {
|
||||
visConfig: string;
|
||||
}
|
||||
|
||||
type VisParams = Required<Arguments>;
|
||||
|
||||
interface RenderValue {
|
||||
visConfig: VisParams;
|
||||
visData: unknown;
|
||||
visType: string;
|
||||
visConfig: PieVisParams;
|
||||
}
|
||||
|
||||
export const createPieVisFn = (): ExpressionFunctionDefinition<
|
||||
'kibana_pie',
|
||||
export type VisTypeVislibPieExpressionFunctionDefinition = ExpressionFunctionDefinition<
|
||||
typeof vislibPieName,
|
||||
Datatable,
|
||||
Arguments,
|
||||
Render<RenderValue>
|
||||
> => ({
|
||||
name: 'kibana_pie',
|
||||
>;
|
||||
|
||||
export const createPieVisFn = (): VisTypeVislibPieExpressionFunctionDefinition => ({
|
||||
name: vislibPieName,
|
||||
type: 'render',
|
||||
inputTypes: ['datatable'],
|
||||
help: i18n.translate('visTypeVislib.functions.pie.help', {
|
||||
|
@ -48,23 +56,20 @@ export const createPieVisFn = (): ExpressionFunctionDefinition<
|
|||
visConfig: {
|
||||
types: ['string'],
|
||||
default: '"{}"',
|
||||
help: '',
|
||||
help: 'vislib pie vis config',
|
||||
},
|
||||
},
|
||||
fn(input, args) {
|
||||
const visConfig = JSON.parse(args.visConfig);
|
||||
const convertedData = vislibSlicesResponseHandler(input, visConfig.dimensions);
|
||||
const visConfig = JSON.parse(args.visConfig) as PieVisParams;
|
||||
const visData = vislibSlicesResponseHandler(input, visConfig.dimensions);
|
||||
|
||||
return {
|
||||
type: 'render',
|
||||
as: 'visualization',
|
||||
as: vislibVisName,
|
||||
value: {
|
||||
visData: convertedData,
|
||||
visType: 'pie',
|
||||
visData,
|
||||
visConfig,
|
||||
params: {
|
||||
listenOnChange: true,
|
||||
},
|
||||
visType: 'pie',
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
|
@ -17,40 +17,20 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import './index.scss';
|
||||
|
||||
import {
|
||||
CoreSetup,
|
||||
CoreStart,
|
||||
Plugin,
|
||||
IUiSettingsClient,
|
||||
PluginInitializerContext,
|
||||
} from 'kibana/public';
|
||||
import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from 'kibana/public';
|
||||
|
||||
import { VisTypeXyPluginSetup } from 'src/plugins/vis_type_xy/public';
|
||||
import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public';
|
||||
import { VisualizationsSetup } from '../../visualizations/public';
|
||||
import { BaseVisTypeOptions, VisualizationsSetup } from '../../visualizations/public';
|
||||
import { createVisTypeVislibVisFn } from './vis_type_vislib_vis_fn';
|
||||
import { createPieVisFn } from './pie_fn';
|
||||
import {
|
||||
createHistogramVisTypeDefinition,
|
||||
createLineVisTypeDefinition,
|
||||
createPieVisTypeDefinition,
|
||||
createAreaVisTypeDefinition,
|
||||
createHeatmapVisTypeDefinition,
|
||||
createHorizontalBarVisTypeDefinition,
|
||||
createGaugeVisTypeDefinition,
|
||||
createGoalVisTypeDefinition,
|
||||
} from './vis_type_vislib_vis_types';
|
||||
import { visLibVisTypeDefinitions, pieVisTypeDefinition } from './vis_type_vislib_vis_types';
|
||||
import { ChartsPluginSetup } from '../../charts/public';
|
||||
import { DataPublicPluginStart } from '../../data/public';
|
||||
import { setFormatService, setDataActions, setKibanaLegacy } from './services';
|
||||
import { KibanaLegacyStart } from '../../kibana_legacy/public';
|
||||
|
||||
export interface VisTypeVislibDependencies {
|
||||
uiSettings: IUiSettingsClient;
|
||||
charts: ChartsPluginSetup;
|
||||
}
|
||||
import { setFormatService, setDataActions } from './services';
|
||||
import { getVislibVisRenderer } from './vis_renderer';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
/** @internal */
|
||||
export interface VisTypeVislibPluginSetupDependencies {
|
||||
|
@ -66,54 +46,37 @@ export interface VisTypeVislibPluginStartDependencies {
|
|||
kibanaLegacy: KibanaLegacyStart;
|
||||
}
|
||||
|
||||
type VisTypeVislibCoreSetup = CoreSetup<VisTypeVislibPluginStartDependencies, void>;
|
||||
export type VisTypeVislibCoreSetup = CoreSetup<VisTypeVislibPluginStartDependencies, void>;
|
||||
|
||||
/** @internal */
|
||||
export class VisTypeVislibPlugin implements Plugin<void, void> {
|
||||
export class VisTypeVislibPlugin
|
||||
implements
|
||||
Plugin<void, void, VisTypeVislibPluginSetupDependencies, VisTypeVislibPluginStartDependencies> {
|
||||
constructor(public initializerContext: PluginInitializerContext) {}
|
||||
|
||||
public async setup(
|
||||
core: VisTypeVislibCoreSetup,
|
||||
{ expressions, visualizations, charts, visTypeXy }: VisTypeVislibPluginSetupDependencies
|
||||
) {
|
||||
const visualizationDependencies: Readonly<VisTypeVislibDependencies> = {
|
||||
uiSettings: core.uiSettings,
|
||||
charts,
|
||||
};
|
||||
const vislibTypes = [
|
||||
createHistogramVisTypeDefinition,
|
||||
createLineVisTypeDefinition,
|
||||
createPieVisTypeDefinition,
|
||||
createAreaVisTypeDefinition,
|
||||
createHeatmapVisTypeDefinition,
|
||||
createHorizontalBarVisTypeDefinition,
|
||||
createGaugeVisTypeDefinition,
|
||||
createGoalVisTypeDefinition,
|
||||
];
|
||||
const vislibFns = [createVisTypeVislibVisFn(), createPieVisFn()];
|
||||
|
||||
// if visTypeXy plugin is disabled it's config will be undefined
|
||||
if (!visTypeXy) {
|
||||
const convertedTypes: any[] = [];
|
||||
const convertedTypes: Array<BaseVisTypeOptions<BasicVislibParams>> = [];
|
||||
const convertedFns: any[] = [];
|
||||
|
||||
// Register legacy vislib types that have been converted
|
||||
convertedFns.forEach(expressions.registerFunction);
|
||||
convertedTypes.forEach((vis) =>
|
||||
visualizations.createBaseVisualization(vis(visualizationDependencies))
|
||||
);
|
||||
convertedTypes.forEach(visualizations.createBaseVisualization);
|
||||
expressions.registerRenderer(getVislibVisRenderer(core, charts));
|
||||
}
|
||||
|
||||
// Register non-converted types
|
||||
vislibFns.forEach(expressions.registerFunction);
|
||||
vislibTypes.forEach((vis) =>
|
||||
visualizations.createBaseVisualization(vis(visualizationDependencies))
|
||||
);
|
||||
visLibVisTypeDefinitions.forEach(visualizations.createBaseVisualization);
|
||||
visualizations.createBaseVisualization(pieVisTypeDefinition);
|
||||
expressions.registerRenderer(getVislibVisRenderer(core, charts));
|
||||
[createVisTypeVislibVisFn(), createPieVisFn()].forEach(expressions.registerFunction);
|
||||
}
|
||||
|
||||
public start(core: CoreStart, { data, kibanaLegacy }: VisTypeVislibPluginStartDependencies) {
|
||||
public start(core: CoreStart, { data }: VisTypeVislibPluginStartDependencies) {
|
||||
setFormatService(data.fieldFormats);
|
||||
setDataActions(data.actions);
|
||||
setKibanaLegacy(kibanaLegacy);
|
||||
}
|
||||
}
|
||||
|
|
3307
src/plugins/vis_type_vislib/public/sample_vis.test.mocks.ts
Normal file
3307
src/plugins/vis_type_vislib/public/sample_vis.test.mocks.ts
Normal file
File diff suppressed because one or more lines are too long
|
@ -19,7 +19,6 @@
|
|||
|
||||
import { createGetterSetter } from '../../kibana_utils/public';
|
||||
import { DataPublicPluginStart } from '../../data/public';
|
||||
import { KibanaLegacyStart } from '../../kibana_legacy/public';
|
||||
|
||||
export const [getDataActions, setDataActions] = createGetterSetter<
|
||||
DataPublicPluginStart['actions']
|
||||
|
@ -28,7 +27,3 @@ export const [getDataActions, setDataActions] = createGetterSetter<
|
|||
export const [getFormatService, setFormatService] = createGetterSetter<
|
||||
DataPublicPluginStart['fieldFormats']
|
||||
>('vislib data.fieldFormats');
|
||||
|
||||
export const [getKibanaLegacy, setKibanaLegacy] = createGetterSetter<KibanaLegacyStart>(
|
||||
'vislib kibanalegacy'
|
||||
);
|
||||
|
|
60
src/plugins/vis_type_vislib/public/to_ast.test.ts
Normal file
60
src/plugins/vis_type_vislib/public/to_ast.test.ts
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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 { Vis } from '../../visualizations/public';
|
||||
import { buildExpression } from '../../expressions/public';
|
||||
|
||||
import { BasicVislibParams } from './types';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { sampleAreaVis } from './sample_vis.test.mocks';
|
||||
|
||||
jest.mock('../../expressions/public', () => ({
|
||||
...(jest.requireActual('../../expressions/public') as any),
|
||||
buildExpression: jest.fn().mockImplementation(() => ({
|
||||
toAst: () => ({
|
||||
type: 'expression',
|
||||
chain: [],
|
||||
}),
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('./to_ast_esaggs', () => ({
|
||||
getEsaggsFn: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('vislib vis toExpressionAst function', () => {
|
||||
let vis: Vis<BasicVislibParams>;
|
||||
|
||||
const params = {
|
||||
timefilter: {},
|
||||
timeRange: {},
|
||||
abortSignal: {},
|
||||
} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
vis = sampleAreaVis as any;
|
||||
});
|
||||
|
||||
it('should match basic snapshot', () => {
|
||||
toExpressionAst(vis, params);
|
||||
const [, builtExpression] = (buildExpression as jest.Mock).mock.calls[0][0];
|
||||
|
||||
expect(builtExpression).toMatchSnapshot();
|
||||
});
|
||||
});
|
103
src/plugins/vis_type_vislib/public/to_ast.ts
Normal file
103
src/plugins/vis_type_vislib/public/to_ast.ts
Normal file
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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 moment from 'moment';
|
||||
|
||||
import { VisToExpressionAst, getVisSchemas } from '../../visualizations/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||
|
||||
import { vislibVisName, VisTypeVislibExpressionFunctionDefinition } from './vis_type_vislib_vis_fn';
|
||||
import { BasicVislibParams } from './types';
|
||||
import {
|
||||
DateHistogramParams,
|
||||
Dimensions,
|
||||
HistogramParams,
|
||||
} from './vislib/helpers/point_series/point_series';
|
||||
import { getEsaggsFn } from './to_ast_esaggs';
|
||||
|
||||
export const toExpressionAst: VisToExpressionAst<BasicVislibParams> = async (vis, params) => {
|
||||
const schemas = getVisSchemas(vis, params);
|
||||
const dimensions: Dimensions = {
|
||||
x: schemas.segment ? schemas.segment[0] : null,
|
||||
y: schemas.metric,
|
||||
z: schemas.radius,
|
||||
width: schemas.width,
|
||||
series: schemas.group,
|
||||
splitRow: schemas.split_row,
|
||||
splitColumn: schemas.split_column,
|
||||
};
|
||||
|
||||
const responseAggs = vis.data.aggs?.getResponseAggs() ?? [];
|
||||
|
||||
if (dimensions.x) {
|
||||
const xAgg = responseAggs[dimensions.x.accessor] as any;
|
||||
if (xAgg.type.name === 'date_histogram') {
|
||||
(dimensions.x.params as DateHistogramParams).date = true;
|
||||
const { esUnit, esValue } = xAgg.buckets.getInterval();
|
||||
(dimensions.x.params as DateHistogramParams).intervalESUnit = esUnit;
|
||||
(dimensions.x.params as DateHistogramParams).intervalESValue = esValue;
|
||||
(dimensions.x.params as DateHistogramParams).interval = moment
|
||||
.duration(esValue, esUnit)
|
||||
.asMilliseconds();
|
||||
(dimensions.x.params as DateHistogramParams).format = xAgg.buckets.getScaledDateFormat();
|
||||
(dimensions.x.params as DateHistogramParams).bounds = xAgg.buckets.getBounds();
|
||||
} else if (xAgg.type.name === 'histogram') {
|
||||
const intervalParam = xAgg.type.paramByName('interval');
|
||||
const output = { params: {} as any };
|
||||
await intervalParam.modifyAggConfigOnSearchRequestStart(xAgg, vis.data.searchSource, {
|
||||
abortSignal: params.abortSignal,
|
||||
});
|
||||
intervalParam.write(xAgg, output);
|
||||
(dimensions.x.params as HistogramParams).interval = output.params.interval;
|
||||
}
|
||||
}
|
||||
|
||||
const visConfig = { ...vis.params };
|
||||
|
||||
(dimensions.y || []).forEach((yDimension) => {
|
||||
const yAgg = responseAggs.filter(({ enabled }) => enabled)[yDimension.accessor];
|
||||
const seriesParam = (visConfig.seriesParams || []).find((param) => param.data.id === yAgg.id);
|
||||
if (seriesParam) {
|
||||
const usedValueAxis = (visConfig.valueAxes || []).find(
|
||||
(valueAxis) => valueAxis.id === seriesParam.valueAxis
|
||||
);
|
||||
if (usedValueAxis?.scale.mode === 'percentage') {
|
||||
yDimension.format = { id: 'percent' };
|
||||
}
|
||||
}
|
||||
if (visConfig?.gauge?.percentageMode === true) {
|
||||
yDimension.format = { id: 'percent' };
|
||||
}
|
||||
});
|
||||
|
||||
visConfig.dimensions = dimensions;
|
||||
|
||||
const configStr = JSON.stringify(visConfig).replace(/\\/g, `\\\\`).replace(/'/g, `\\'`);
|
||||
const visTypeXy = buildExpressionFunction<VisTypeVislibExpressionFunctionDefinition>(
|
||||
vislibVisName,
|
||||
{
|
||||
type: vis.type.name,
|
||||
visConfig: configStr,
|
||||
}
|
||||
);
|
||||
|
||||
const ast = buildExpression([getEsaggsFn(vis), visTypeXy]);
|
||||
|
||||
return ast.toAst();
|
||||
};
|
|
@ -17,8 +17,24 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { GaugeOptions } from './gauge';
|
||||
export { PieOptions } from './pie';
|
||||
export { PointSeriesOptions } from './point_series';
|
||||
export { HeatmapOptions } from './heatmap';
|
||||
export { MetricsAxisOptions } from './metrics_axes';
|
||||
import { Vis } from '../../visualizations/public';
|
||||
import { buildExpressionFunction } from '../../expressions/public';
|
||||
import { EsaggsExpressionFunctionDefinition } from '../../data/public';
|
||||
|
||||
import { PieVisParams } from './pie';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
/**
|
||||
* Get esaggs expressions function
|
||||
* TODO: replace this with vis.data.aggs!.toExpressionAst();
|
||||
* @param vis
|
||||
*/
|
||||
export function getEsaggsFn(vis: Vis<PieVisParams> | Vis<BasicVislibParams>) {
|
||||
return buildExpressionFunction<EsaggsExpressionFunctionDefinition>('esaggs', {
|
||||
index: vis.data.indexPattern!.id!,
|
||||
metricsAtAllLevels: vis.isHierarchical(),
|
||||
partialRows: false,
|
||||
aggConfigs: JSON.stringify(vis.data.aggs!.aggs),
|
||||
includeFormatHints: false,
|
||||
});
|
||||
}
|
60
src/plugins/vis_type_vislib/public/to_ast_pie.test.ts
Normal file
60
src/plugins/vis_type_vislib/public/to_ast_pie.test.ts
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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 { Vis } from '../../visualizations/public';
|
||||
import { buildExpression } from '../../expressions/public';
|
||||
|
||||
import { PieVisParams } from './pie';
|
||||
import { samplePieVis } from './sample_vis.test.mocks';
|
||||
import { toExpressionAst } from './to_ast_pie';
|
||||
|
||||
jest.mock('../../expressions/public', () => ({
|
||||
...(jest.requireActual('../../expressions/public') as any),
|
||||
buildExpression: jest.fn().mockImplementation(() => ({
|
||||
toAst: () => ({
|
||||
type: 'expression',
|
||||
chain: [],
|
||||
}),
|
||||
})),
|
||||
}));
|
||||
|
||||
jest.mock('./to_ast_esaggs', () => ({
|
||||
getEsaggsFn: jest.fn(),
|
||||
}));
|
||||
|
||||
describe('vislib pie vis toExpressionAst function', () => {
|
||||
let vis: Vis<PieVisParams>;
|
||||
|
||||
const params = {
|
||||
timefilter: {},
|
||||
timeRange: {},
|
||||
abortSignal: {},
|
||||
} as any;
|
||||
|
||||
beforeEach(() => {
|
||||
vis = samplePieVis as any;
|
||||
});
|
||||
|
||||
it('should match basic snapshot', () => {
|
||||
toExpressionAst(vis, params);
|
||||
const [, builtExpression] = (buildExpression as jest.Mock).mock.calls[0][0];
|
||||
|
||||
expect(builtExpression).toMatchSnapshot();
|
||||
});
|
||||
});
|
50
src/plugins/vis_type_vislib/public/to_ast_pie.ts
Normal file
50
src/plugins/vis_type_vislib/public/to_ast_pie.ts
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* 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 { getVisSchemas, VisToExpressionAst } from '../../visualizations/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||
|
||||
import { PieVisParams } from './pie';
|
||||
import { vislibPieName, VisTypeVislibPieExpressionFunctionDefinition } from './pie_fn';
|
||||
import { getEsaggsFn } from './to_ast_esaggs';
|
||||
|
||||
export const toExpressionAst: VisToExpressionAst<PieVisParams> = async (vis, params) => {
|
||||
const schemas = getVisSchemas(vis, params);
|
||||
const visConfig = {
|
||||
...vis.params,
|
||||
dimensions: {
|
||||
metric: schemas.metric[0],
|
||||
buckets: schemas.segment,
|
||||
splitRow: schemas.split_row,
|
||||
splitColumn: schemas.split_column,
|
||||
},
|
||||
};
|
||||
|
||||
const configStr = JSON.stringify(visConfig).replace(/\\/g, `\\\\`).replace(/'/g, `\\'`);
|
||||
const visTypePie = buildExpressionFunction<VisTypeVislibPieExpressionFunctionDefinition>(
|
||||
vislibPieName,
|
||||
{
|
||||
visConfig: configStr,
|
||||
}
|
||||
);
|
||||
|
||||
const ast = buildExpression([getEsaggsFn(vis), visTypePie]);
|
||||
|
||||
return ast.toAst();
|
||||
};
|
|
@ -29,10 +29,13 @@ import {
|
|||
ThresholdLineStyles,
|
||||
} from './utils/collections';
|
||||
import { Labels, Style } from '../../charts/public';
|
||||
import { Dimensions } from './vislib/helpers/point_series/point_series';
|
||||
|
||||
export interface CommonVislibParams {
|
||||
addTooltip: boolean;
|
||||
addLegend: boolean;
|
||||
legendPosition: Positions;
|
||||
dimensions: Dimensions;
|
||||
}
|
||||
|
||||
export interface Scale {
|
||||
|
@ -87,6 +90,9 @@ export interface BasicVislibParams extends CommonVislibParams {
|
|||
labels: Labels;
|
||||
thresholdLine: ThresholdLine;
|
||||
valueAxes: ValueAxis[];
|
||||
gauge?: {
|
||||
percentageMode: boolean;
|
||||
};
|
||||
grid: {
|
||||
categoryLines: boolean;
|
||||
valueAxis?: string;
|
||||
|
|
|
@ -20,127 +20,147 @@
|
|||
import $ from 'jquery';
|
||||
import React, { RefObject } from 'react';
|
||||
|
||||
import { Positions } from './utils/collections';
|
||||
import { VisTypeVislibDependencies } from './plugin';
|
||||
import { mountReactNode } from '../../../core/public/utils';
|
||||
import { ChartsPluginSetup } from '../../charts/public';
|
||||
import { PersistedState } from '../../visualizations/public';
|
||||
import { IInterpreterRenderHandlers } from '../../expressions/public';
|
||||
|
||||
import { VisTypeVislibCoreSetup } from './plugin';
|
||||
import { VisLegend, CUSTOM_LEGEND_VIS_TYPES } from './vislib/components/legend';
|
||||
import { VisParams, ExprVis } from '../../visualizations/public';
|
||||
import { getKibanaLegacy } from './services';
|
||||
import { BasicVislibParams } from './types';
|
||||
import { PieVisParams } from './pie';
|
||||
|
||||
const legendClassName = {
|
||||
top: 'visLib--legend-top',
|
||||
bottom: 'visLib--legend-bottom',
|
||||
left: 'visLib--legend-left',
|
||||
right: 'visLib--legend-right',
|
||||
top: 'vislib--legend-top',
|
||||
bottom: 'vislib--legend-bottom',
|
||||
left: 'vislib--legend-left',
|
||||
right: 'vislib--legend-right',
|
||||
};
|
||||
|
||||
export const createVislibVisController = (deps: VisTypeVislibDependencies) => {
|
||||
export type VislibVisController = InstanceType<ReturnType<typeof createVislibVisController>>;
|
||||
|
||||
export const createVislibVisController = (
|
||||
core: VisTypeVislibCoreSetup,
|
||||
charts: ChartsPluginSetup
|
||||
) => {
|
||||
return class VislibVisController {
|
||||
unmount: (() => void) | null = null;
|
||||
visParams?: VisParams;
|
||||
private removeListeners?: () => void;
|
||||
private unmountLegend?: () => void;
|
||||
|
||||
legendRef: RefObject<VisLegend>;
|
||||
container: HTMLDivElement;
|
||||
chartEl: HTMLDivElement;
|
||||
legendEl: HTMLDivElement;
|
||||
vislibVis: any;
|
||||
vislibVis?: any;
|
||||
|
||||
constructor(public el: Element, public vis: ExprVis) {
|
||||
constructor(public el: HTMLDivElement) {
|
||||
this.el = el;
|
||||
this.vis = vis;
|
||||
this.unmount = null;
|
||||
this.legendRef = React.createRef();
|
||||
|
||||
// vis mount point
|
||||
this.container = document.createElement('div');
|
||||
this.container.className = 'visLib';
|
||||
this.container.className = 'vislib';
|
||||
this.el.appendChild(this.container);
|
||||
|
||||
// chart mount point
|
||||
this.chartEl = document.createElement('div');
|
||||
this.chartEl.className = 'visLib__chart';
|
||||
this.chartEl.className = 'vislib__chart';
|
||||
this.container.appendChild(this.chartEl);
|
||||
|
||||
// legend mount point
|
||||
this.legendEl = document.createElement('div');
|
||||
this.legendEl.className = 'visLib__legend';
|
||||
this.legendEl.className = 'vislib__legend';
|
||||
this.container.appendChild(this.legendEl);
|
||||
}
|
||||
|
||||
render(esResponse: any, visParams: VisParams): Promise<void> {
|
||||
async render(
|
||||
esResponse: any,
|
||||
visParams: BasicVislibParams | PieVisParams,
|
||||
handlers: IInterpreterRenderHandlers
|
||||
): Promise<void> {
|
||||
if (this.vislibVis) {
|
||||
this.destroy();
|
||||
this.destroy(false);
|
||||
}
|
||||
|
||||
getKibanaLegacy().loadFontAwesome();
|
||||
// Used in functional tests to know when chart is loaded by type
|
||||
this.chartEl.dataset.vislibChartType = visParams.type;
|
||||
|
||||
return new Promise(async (resolve) => {
|
||||
if (this.el.clientWidth === 0 || this.el.clientHeight === 0) {
|
||||
return resolve();
|
||||
}
|
||||
if (this.el.clientWidth === 0 || this.el.clientHeight === 0) {
|
||||
handlers.done();
|
||||
return;
|
||||
}
|
||||
|
||||
// @ts-expect-error
|
||||
const { Vis: Vislib } = await import('./vislib/vis');
|
||||
const [, { kibanaLegacy }] = await core.getStartServices();
|
||||
kibanaLegacy.loadFontAwesome();
|
||||
|
||||
this.vislibVis = new Vislib(this.chartEl, visParams, deps);
|
||||
this.vislibVis.on('brush', this.vis.API.events.brush);
|
||||
this.vislibVis.on('click', this.vis.API.events.filter);
|
||||
this.vislibVis.on('renderComplete', resolve);
|
||||
// @ts-expect-error
|
||||
const { Vis: Vislib } = await import('./vislib/vis');
|
||||
const { uiState, event: fireEvent } = handlers;
|
||||
|
||||
this.vislibVis.initVisConfig(esResponse, this.vis.getUiState());
|
||||
this.vislibVis = new Vislib(this.chartEl, visParams, core, charts);
|
||||
this.vislibVis.on('brush', fireEvent);
|
||||
this.vislibVis.on('click', fireEvent);
|
||||
this.vislibVis.on('renderComplete', handlers.done);
|
||||
this.removeListeners = () => {
|
||||
this.vislibVis.off('brush', fireEvent);
|
||||
this.vislibVis.off('click', fireEvent);
|
||||
};
|
||||
|
||||
if (visParams.addLegend) {
|
||||
$(this.container)
|
||||
.attr('class', (i, cls) => {
|
||||
return cls.replace(/visLib--legend-\S+/g, '');
|
||||
})
|
||||
.addClass((legendClassName as any)[visParams.legendPosition]);
|
||||
this.vislibVis.initVisConfig(esResponse, uiState);
|
||||
|
||||
this.mountLegend(esResponse, visParams.legendPosition);
|
||||
}
|
||||
if (visParams.addLegend) {
|
||||
$(this.container)
|
||||
.attr('class', (i, cls) => {
|
||||
return cls.replace(/vislib--legend-\S+/g, '');
|
||||
})
|
||||
.addClass((legendClassName as any)[visParams.legendPosition]);
|
||||
|
||||
this.vislibVis.render(esResponse, this.vis.getUiState());
|
||||
this.mountLegend(esResponse, visParams, fireEvent, uiState);
|
||||
}
|
||||
|
||||
// refreshing the legend after the chart is rendered.
|
||||
// this is necessary because some visualizations
|
||||
// provide data necessary for the legend only after a render cycle.
|
||||
if (
|
||||
visParams.addLegend &&
|
||||
CUSTOM_LEGEND_VIS_TYPES.includes(this.vislibVis.visConfigArgs.type)
|
||||
) {
|
||||
this.unmountLegend();
|
||||
this.mountLegend(esResponse, visParams.legendPosition);
|
||||
this.vislibVis.render(esResponse, this.vis.getUiState());
|
||||
}
|
||||
});
|
||||
this.vislibVis.render(esResponse, uiState);
|
||||
|
||||
// refreshing the legend after the chart is rendered.
|
||||
// this is necessary because some visualizations
|
||||
// provide data necessary for the legend only after a render cycle.
|
||||
if (
|
||||
visParams.addLegend &&
|
||||
CUSTOM_LEGEND_VIS_TYPES.includes(this.vislibVis.visConfigArgs.type)
|
||||
) {
|
||||
this.unmountLegend?.();
|
||||
this.mountLegend(esResponse, visParams, fireEvent, uiState);
|
||||
this.vislibVis.render(esResponse, uiState);
|
||||
}
|
||||
}
|
||||
|
||||
mountLegend(visData: any, position: Positions) {
|
||||
this.unmount = mountReactNode(
|
||||
mountLegend(
|
||||
visData: unknown,
|
||||
{ legendPosition, addLegend }: BasicVislibParams | PieVisParams,
|
||||
fireEvent: IInterpreterRenderHandlers['event'],
|
||||
uiState?: PersistedState
|
||||
) {
|
||||
this.unmountLegend = mountReactNode(
|
||||
<VisLegend
|
||||
ref={this.legendRef}
|
||||
vis={this.vis}
|
||||
vislibVis={this.vislibVis}
|
||||
visData={visData}
|
||||
position={position}
|
||||
uiState={this.vis.getUiState()}
|
||||
uiState={uiState}
|
||||
fireEvent={fireEvent}
|
||||
addLegend={addLegend}
|
||||
position={legendPosition}
|
||||
/>
|
||||
)(this.legendEl);
|
||||
}
|
||||
|
||||
unmountLegend() {
|
||||
if (this.unmount) {
|
||||
this.unmount();
|
||||
}
|
||||
}
|
||||
destroy(clearElement = true) {
|
||||
this.unmountLegend?.();
|
||||
|
||||
destroy() {
|
||||
if (this.unmount) {
|
||||
this.unmount();
|
||||
if (clearElement) {
|
||||
this.el.innerHTML = '';
|
||||
}
|
||||
|
||||
if (this.vislibVis) {
|
||||
this.vislibVis.off('brush', this.vis.API.events.brush);
|
||||
this.vislibVis.off('click', this.vis.API.events.filter);
|
||||
this.removeListeners?.();
|
||||
this.vislibVis.destroy();
|
||||
delete this.vislibVis;
|
||||
}
|
||||
|
|
61
src/plugins/vis_type_vislib/public/vis_renderer.tsx
Normal file
61
src/plugins/vis_type_vislib/public/vis_renderer.tsx
Normal file
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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 '../../expressions/public';
|
||||
import { VisualizationContainer } from '../../visualizations/public';
|
||||
import { ChartsPluginSetup } from '../../charts/public';
|
||||
|
||||
import { VisTypeVislibCoreSetup } from './plugin';
|
||||
import { VislibRenderValue, vislibVisName } from './vis_type_vislib_vis_fn';
|
||||
|
||||
function shouldShowNoResultsMessage(visData: any, visType: string): boolean {
|
||||
if (['goal', 'gauge'].includes(visType)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const rows: object[] | undefined = visData?.rows;
|
||||
const isZeroHits = visData?.hits === 0 || (rows && !rows.length);
|
||||
|
||||
return Boolean(isZeroHits);
|
||||
}
|
||||
|
||||
const VislibWrapper = lazy(() => import('./vis_wrapper'));
|
||||
|
||||
export const getVislibVisRenderer: (
|
||||
core: VisTypeVislibCoreSetup,
|
||||
charts: ChartsPluginSetup
|
||||
) => ExpressionRenderDefinition<VislibRenderValue> = (core, charts) => ({
|
||||
name: vislibVisName,
|
||||
reuseDomNode: true,
|
||||
render: async (domNode, config, handlers) => {
|
||||
const showNoResult = shouldShowNoResultsMessage(config.visData, config.visType);
|
||||
|
||||
handlers.onDestroy(() => unmountComponentAtNode(domNode));
|
||||
|
||||
render(
|
||||
<VisualizationContainer handlers={handlers} showNoResult={showNoResult}>
|
||||
<VislibWrapper {...config} core={core} charts={charts} handlers={handlers} />
|
||||
</VisualizationContainer>,
|
||||
domNode
|
||||
);
|
||||
},
|
||||
});
|
|
@ -18,29 +18,35 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { ExpressionFunctionDefinition, Datatable, Render } from '../../expressions/public';
|
||||
|
||||
// @ts-ignore
|
||||
import { vislibSeriesResponseHandler } from './vislib/response_handler';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
export const vislibVisName = 'vislib_vis';
|
||||
|
||||
interface Arguments {
|
||||
type: string;
|
||||
visConfig: string;
|
||||
}
|
||||
|
||||
type VisParams = Required<Arguments>;
|
||||
|
||||
interface RenderValue {
|
||||
export interface VislibRenderValue {
|
||||
visData: any;
|
||||
visType: string;
|
||||
visConfig: VisParams;
|
||||
visConfig: BasicVislibParams;
|
||||
}
|
||||
|
||||
export const createVisTypeVislibVisFn = (): ExpressionFunctionDefinition<
|
||||
'vislib',
|
||||
export type VisTypeVislibExpressionFunctionDefinition = ExpressionFunctionDefinition<
|
||||
typeof vislibVisName,
|
||||
Datatable,
|
||||
Arguments,
|
||||
Render<RenderValue>
|
||||
> => ({
|
||||
name: 'vislib',
|
||||
Render<VislibRenderValue>
|
||||
>;
|
||||
|
||||
export const createVisTypeVislibVisFn = (): VisTypeVislibExpressionFunctionDefinition => ({
|
||||
name: vislibVisName,
|
||||
type: 'render',
|
||||
inputTypes: ['datatable'],
|
||||
help: i18n.translate('visTypeVislib.functions.vislib.help', {
|
||||
|
@ -55,23 +61,21 @@ export const createVisTypeVislibVisFn = (): ExpressionFunctionDefinition<
|
|||
visConfig: {
|
||||
types: ['string'],
|
||||
default: '"{}"',
|
||||
help: '',
|
||||
help: 'vislib vis config',
|
||||
},
|
||||
},
|
||||
fn(context, args) {
|
||||
const visConfigParams = JSON.parse(args.visConfig);
|
||||
const convertedData = vislibSeriesResponseHandler(context, visConfigParams.dimensions);
|
||||
const visType = args.type;
|
||||
const visConfig = JSON.parse(args.visConfig) as BasicVislibParams;
|
||||
const visData = vislibSeriesResponseHandler(context, visConfig.dimensions);
|
||||
|
||||
return {
|
||||
type: 'render',
|
||||
as: 'visualization',
|
||||
as: vislibVisName,
|
||||
value: {
|
||||
visData: convertedData,
|
||||
visType: args.type,
|
||||
visConfig: visConfigParams,
|
||||
params: {
|
||||
listenOnChange: true,
|
||||
},
|
||||
visData,
|
||||
visConfig,
|
||||
visType,
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
|
@ -17,11 +17,22 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
export { createHistogramVisTypeDefinition } from './histogram';
|
||||
export { createLineVisTypeDefinition } from './line';
|
||||
export { createPieVisTypeDefinition } from './pie';
|
||||
export { createAreaVisTypeDefinition } from './area';
|
||||
export { createHeatmapVisTypeDefinition } from './heatmap';
|
||||
export { createHorizontalBarVisTypeDefinition } from './horizontal_bar';
|
||||
export { createGaugeVisTypeDefinition } from './gauge';
|
||||
export { createGoalVisTypeDefinition } from './goal';
|
||||
import { histogramVisTypeDefinition } from './histogram';
|
||||
import { lineVisTypeDefinition } from './line';
|
||||
import { areaVisTypeDefinition } from './area';
|
||||
import { heatmapVisTypeDefinition } from './heatmap';
|
||||
import { horizontalBarVisTypeDefinition } from './horizontal_bar';
|
||||
import { gaugeVisTypeDefinition } from './gauge';
|
||||
import { goalVisTypeDefinition } from './goal';
|
||||
|
||||
export { pieVisTypeDefinition } from './pie';
|
||||
|
||||
export const visLibVisTypeDefinitions = [
|
||||
histogramVisTypeDefinition,
|
||||
lineVisTypeDefinition,
|
||||
areaVisTypeDefinition,
|
||||
heatmapVisTypeDefinition,
|
||||
horizontalBarVisTypeDefinition,
|
||||
gaugeVisTypeDefinition,
|
||||
goalVisTypeDefinition,
|
||||
];
|
||||
|
|
89
src/plugins/vis_type_vislib/public/vis_wrapper.tsx
Normal file
89
src/plugins/vis_type_vislib/public/vis_wrapper.tsx
Normal file
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* 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, { useEffect, useMemo, useRef } from 'react';
|
||||
import { EuiResizeObserver } from '@elastic/eui';
|
||||
import { debounce } from 'lodash';
|
||||
|
||||
import { IInterpreterRenderHandlers } from '../../expressions/public';
|
||||
import { ChartsPluginSetup } from '../../charts/public';
|
||||
|
||||
import { VislibRenderValue } from './vis_type_vislib_vis_fn';
|
||||
import { createVislibVisController, VislibVisController } from './vis_controller';
|
||||
import { VisTypeVislibCoreSetup } from './plugin';
|
||||
|
||||
import './index.scss';
|
||||
|
||||
type VislibWrapperProps = VislibRenderValue & {
|
||||
core: VisTypeVislibCoreSetup;
|
||||
charts: ChartsPluginSetup;
|
||||
handlers: IInterpreterRenderHandlers;
|
||||
};
|
||||
|
||||
const VislibWrapper = ({ core, charts, visData, visConfig, handlers }: VislibWrapperProps) => {
|
||||
const chartDiv = useRef<HTMLDivElement>(null);
|
||||
const visController = useRef<VislibVisController | null>(null);
|
||||
|
||||
const updateChart = useMemo(
|
||||
() =>
|
||||
debounce(() => {
|
||||
if (visController.current) {
|
||||
visController.current.render(visData, visConfig, handlers);
|
||||
}
|
||||
}, 100),
|
||||
[visConfig, visData, handlers]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (chartDiv.current) {
|
||||
const Controller = createVislibVisController(core, charts);
|
||||
visController.current = new Controller(chartDiv.current);
|
||||
}
|
||||
return () => {
|
||||
visController.current?.destroy();
|
||||
visController.current = null;
|
||||
};
|
||||
}, [core, charts, handlers]);
|
||||
|
||||
useEffect(updateChart, [updateChart]);
|
||||
|
||||
useEffect(() => {
|
||||
if (handlers.uiState) {
|
||||
handlers.uiState.on('change', updateChart);
|
||||
|
||||
return () => {
|
||||
handlers.uiState?.off('change', updateChart);
|
||||
};
|
||||
}
|
||||
}, [handlers.uiState, updateChart]);
|
||||
|
||||
return (
|
||||
<EuiResizeObserver onResize={updateChart}>
|
||||
{(resizeRef) => (
|
||||
<div className="vislib__wrapper" ref={resizeRef}>
|
||||
<div className="vislib__container" ref={chartDiv} />
|
||||
</div>
|
||||
)}
|
||||
</EuiResizeObserver>
|
||||
);
|
||||
};
|
||||
|
||||
// default export required for React.Lazy
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export { VislibWrapper as default };
|
|
@ -1,27 +1,29 @@
|
|||
.visLib {
|
||||
.vislib {
|
||||
flex: 1 1 0;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: auto;
|
||||
|
||||
&.visLib--legend-left {
|
||||
&.vislib--legend-left {
|
||||
flex-direction: row-reverse;
|
||||
}
|
||||
|
||||
&.visLib--legend-right {
|
||||
&.vislib--legend-right {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
&.visLib--legend-top {
|
||||
&.vislib--legend-top {
|
||||
flex-direction: column-reverse;
|
||||
}
|
||||
|
||||
&.visLib--legend-bottom {
|
||||
&.vislib--legend-bottom {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
|
||||
.visLib__chart {
|
||||
.vislib__chart,
|
||||
.vislib__wrapper,
|
||||
.vislib__container {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
min-height: 0;
|
||||
|
|
|
@ -13,6 +13,7 @@ $visLegendLineHeight: $euiSize;
|
|||
left: 0;
|
||||
display: flex;
|
||||
padding: $euiSizeXS;
|
||||
margin: $euiSizeS;
|
||||
background-color: $euiColorEmptyShade;
|
||||
transition: opacity $euiAnimSpeedFast $euiAnimSlightResistance, background-color $euiAnimSpeedFast $euiAnimSlightResistance $euiAnimSpeedExtraSlow;
|
||||
|
||||
|
@ -33,13 +34,13 @@ $visLegendLineHeight: $euiSize;
|
|||
height: 100%;
|
||||
}
|
||||
|
||||
.visLib--legend-left {
|
||||
.vislib--legend-left {
|
||||
.visLegend__list {
|
||||
margin-bottom: $euiSizeL;
|
||||
}
|
||||
}
|
||||
|
||||
.visLib--legend-bottom {
|
||||
.vislib--legend-bottom {
|
||||
.visLegend__list {
|
||||
margin-left: $euiSizeL;
|
||||
}
|
||||
|
@ -64,8 +65,8 @@ $visLegendLineHeight: $euiSize;
|
|||
}
|
||||
}
|
||||
|
||||
.visLib--legend-top &,
|
||||
.visLib--legend-bottom & {
|
||||
.vislib--legend-top &,
|
||||
.vislib--legend-bottom & {
|
||||
width: auto;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
|
|
|
@ -41,16 +41,8 @@ jest.mock('../../../services', () => ({
|
|||
}),
|
||||
}));
|
||||
|
||||
const vis = {
|
||||
params: {
|
||||
addLegend: true,
|
||||
},
|
||||
API: {
|
||||
events: {
|
||||
filter: jest.fn(),
|
||||
},
|
||||
},
|
||||
};
|
||||
const fireEvent = jest.fn();
|
||||
|
||||
const vislibVis = {
|
||||
handler: {
|
||||
highlight: jest.fn(),
|
||||
|
@ -96,14 +88,15 @@ const uiState = {
|
|||
set: jest.fn().mockImplementation((key, value) => mockState.set(key, value)),
|
||||
emit: jest.fn(),
|
||||
setSilent: jest.fn(),
|
||||
};
|
||||
} as any;
|
||||
|
||||
const getWrapper = async (props?: Partial<VisLegendProps>) => {
|
||||
const wrapper = mount(
|
||||
<I18nProvider>
|
||||
<VisLegend
|
||||
addLegend
|
||||
position="top"
|
||||
vis={vis}
|
||||
fireEvent={fireEvent}
|
||||
vislibVis={vislibVis}
|
||||
visData={visData}
|
||||
uiState={uiState}
|
||||
|
@ -188,8 +181,7 @@ describe('VisLegend Component', () => {
|
|||
});
|
||||
|
||||
it('should work with no handlers set', () => {
|
||||
const newVis = {
|
||||
...vis,
|
||||
const newProps = {
|
||||
vislibVis: {
|
||||
...vislibVis,
|
||||
handler: null,
|
||||
|
@ -197,7 +189,7 @@ describe('VisLegend Component', () => {
|
|||
};
|
||||
|
||||
expect(async () => {
|
||||
wrapper = await getWrapper({ vis: newVis });
|
||||
wrapper = await getWrapper(newProps);
|
||||
const first = getLegendItems(wrapper).first();
|
||||
first.simulate('focus');
|
||||
first.simulate('blur');
|
||||
|
@ -216,8 +208,11 @@ describe('VisLegend Component', () => {
|
|||
const filterGroup = wrapper.find(EuiButtonGroup).first();
|
||||
filterGroup.getElement().props.onChange('filterIn');
|
||||
|
||||
expect(vis.API.events.filter).toHaveBeenCalledWith({ data: ['valuesA'], negate: false });
|
||||
expect(vis.API.events.filter).toHaveBeenCalledTimes(1);
|
||||
expect(fireEvent).toHaveBeenCalledWith({
|
||||
name: 'filterBucket',
|
||||
data: { data: ['valuesA'], negate: false },
|
||||
});
|
||||
expect(fireEvent).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should filter in when clicked', () => {
|
||||
|
@ -226,8 +221,11 @@ describe('VisLegend Component', () => {
|
|||
const filterGroup = wrapper.find(EuiButtonGroup).first();
|
||||
filterGroup.getElement().props.onChange('filterOut');
|
||||
|
||||
expect(vis.API.events.filter).toHaveBeenCalledWith({ data: ['valuesA'], negate: true });
|
||||
expect(vis.API.events.filter).toHaveBeenCalledTimes(1);
|
||||
expect(fireEvent).toHaveBeenCalledWith({
|
||||
name: 'filterBucket',
|
||||
data: { data: ['valuesA'], negate: true },
|
||||
});
|
||||
expect(fireEvent).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -23,16 +23,21 @@ import { compact, uniqBy, map, every, isUndefined } from 'lodash';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { EuiPopoverProps, EuiIcon, keys, htmlIdGenerator } from '@elastic/eui';
|
||||
|
||||
import { PersistedState } from '../../../../../visualizations/public';
|
||||
import { IInterpreterRenderHandlers } from '../../../../../expressions/public';
|
||||
|
||||
import { getDataActions } from '../../../services';
|
||||
import { CUSTOM_LEGEND_VIS_TYPES, LegendItem } from './models';
|
||||
import { VisLegendItem } from './legend_item';
|
||||
import { getPieNames } from './pie_utils';
|
||||
import { BasicVislibParams } from '../../../types';
|
||||
|
||||
export interface VisLegendProps {
|
||||
vis: any;
|
||||
vislibVis: any;
|
||||
visData: any;
|
||||
uiState: any;
|
||||
visData: unknown;
|
||||
uiState?: PersistedState;
|
||||
fireEvent: IInterpreterRenderHandlers['event'];
|
||||
addLegend: BasicVislibParams['addLegend'];
|
||||
position: 'top' | 'bottom' | 'left' | 'right';
|
||||
}
|
||||
|
||||
|
@ -49,7 +54,10 @@ export class VisLegend extends PureComponent<VisLegendProps, VisLegendState> {
|
|||
|
||||
constructor(props: VisLegendProps) {
|
||||
super(props);
|
||||
const open = props.uiState.get('vis.legendOpen', true);
|
||||
|
||||
// TODO: Check when this bwc can safely be removed
|
||||
const bwcLegendStateDefault = props.addLegend ?? true;
|
||||
const open = props.uiState?.get('vis.legendOpen', bwcLegendStateDefault) as boolean;
|
||||
|
||||
this.state = {
|
||||
open,
|
||||
|
@ -64,13 +72,9 @@ export class VisLegend extends PureComponent<VisLegendProps, VisLegendState> {
|
|||
}
|
||||
|
||||
toggleLegend = () => {
|
||||
const bwcAddLegend = this.props.vis.params.addLegend;
|
||||
const bwcLegendStateDefault = bwcAddLegend == null ? true : bwcAddLegend;
|
||||
const newOpen = !this.props.uiState.get('vis.legendOpen', bwcLegendStateDefault);
|
||||
this.setState({ open: newOpen });
|
||||
// open should be applied on template before we update uiState
|
||||
setTimeout(() => {
|
||||
this.props.uiState.set('vis.legendOpen', newOpen);
|
||||
const newOpen = !this.state.open;
|
||||
this.setState({ open: newOpen }, () => {
|
||||
this.props.uiState?.set('vis.legendOpen', newOpen);
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -79,17 +83,23 @@ export class VisLegend extends PureComponent<VisLegendProps, VisLegendState> {
|
|||
return;
|
||||
}
|
||||
|
||||
const colors = this.props.uiState.get('vis.colors') || {};
|
||||
const colors = this.props.uiState?.get('vis.colors') || {};
|
||||
if (colors[label] === color) delete colors[label];
|
||||
else colors[label] = color;
|
||||
this.props.uiState.setSilent('vis.colors', null);
|
||||
this.props.uiState.set('vis.colors', colors);
|
||||
this.props.uiState.emit('colorChanged');
|
||||
this.props.uiState?.setSilent('vis.colors', null);
|
||||
this.props.uiState?.set('vis.colors', colors);
|
||||
this.props.uiState?.emit('colorChanged');
|
||||
this.refresh();
|
||||
};
|
||||
|
||||
filter = ({ values: data }: LegendItem, negate: boolean) => {
|
||||
this.props.vis.API.events.filter({ data, negate });
|
||||
this.props.fireEvent({
|
||||
name: 'filterBucket',
|
||||
data: {
|
||||
data,
|
||||
negate,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
canFilter = async (item: LegendItem): Promise<boolean> => {
|
||||
|
@ -172,11 +182,8 @@ export class VisLegend extends PureComponent<VisLegendProps, VisLegendState> {
|
|||
return;
|
||||
} // make sure vislib is defined at this point
|
||||
|
||||
if (
|
||||
this.props.uiState.get('vis.legendOpen') == null &&
|
||||
this.props.vis.params.addLegend != null
|
||||
) {
|
||||
this.setState({ open: this.props.vis.params.addLegend });
|
||||
if (this.props.uiState?.get('vis.legendOpen') == null && this.props.addLegend != null) {
|
||||
this.setState({ open: this.props.addLegend });
|
||||
}
|
||||
|
||||
if (vislibVis.visConfig) {
|
||||
|
|
|
@ -33,11 +33,11 @@ export function initXAxis(chart: Chart, table: Table) {
|
|||
chart.xAxisLabel = title;
|
||||
|
||||
if ('interval' in params) {
|
||||
const { interval } = params;
|
||||
if ('date' in params) {
|
||||
const { intervalESUnit, intervalESValue } = params;
|
||||
|
||||
chart.ordered = {
|
||||
interval: moment.duration(interval),
|
||||
interval: moment.duration(intervalESValue, intervalESUnit as any),
|
||||
intervalESUnit,
|
||||
intervalESValue,
|
||||
};
|
||||
|
|
|
@ -28,7 +28,7 @@ import { Column, Table } from '../../types';
|
|||
|
||||
export interface DateHistogramParams {
|
||||
date: boolean;
|
||||
interval: string;
|
||||
interval: number | string;
|
||||
intervalESValue: number;
|
||||
intervalESUnit: string;
|
||||
format: string;
|
||||
|
@ -57,6 +57,9 @@ export interface Dimensions {
|
|||
y: Dimension[];
|
||||
z?: Dimension[];
|
||||
series?: Dimension | Dimension[];
|
||||
width?: Dimension[];
|
||||
splitRow?: Dimension[];
|
||||
splitColumn?: Dimension[];
|
||||
}
|
||||
export interface Aspect {
|
||||
accessor: Column['id'];
|
||||
|
|
|
@ -1,17 +0,0 @@
|
|||
.visError {
|
||||
flex: 1 1 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
text-align: center;
|
||||
|
||||
// From ML
|
||||
.top { align-self: flex-start; }
|
||||
.bottom { align-self: flex-end; }
|
||||
}
|
||||
|
||||
// Prevent large request errors from overflowing the container
|
||||
.visError--request {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
|
@ -1,4 +1,3 @@
|
|||
@import './alerts';
|
||||
@import './handler';
|
||||
@import './layout/index';
|
||||
|
||||
|
|
|
@ -182,7 +182,6 @@ export class Dispatch {
|
|||
const data = d.input || d;
|
||||
|
||||
return {
|
||||
e: d3.event,
|
||||
data: isSlices ? this._pieClickResponse(data) : this._seriesClickResponse(data),
|
||||
};
|
||||
}
|
||||
|
@ -423,7 +422,6 @@ export class Dispatch {
|
|||
*/
|
||||
createBrush(xScale, svg) {
|
||||
const self = this;
|
||||
const visConfig = self.handler.visConfig;
|
||||
const { width, height } = svg.node().getBBox();
|
||||
const isHorizontal = self.handler.categoryAxes[0].axisConfig.isHorizontal();
|
||||
|
||||
|
@ -449,8 +447,6 @@ export class Dispatch {
|
|||
|
||||
return self.emit('brush', {
|
||||
range,
|
||||
config: visConfig,
|
||||
e: d3.event,
|
||||
data,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -46,10 +46,10 @@ const markdownIt = new MarkdownIt({
|
|||
* create the visualization
|
||||
*/
|
||||
export class Handler {
|
||||
constructor(vis, visConfig, deps) {
|
||||
constructor(vis, visConfig, uiSettings) {
|
||||
this.el = visConfig.get('el');
|
||||
this.ChartClass = chartTypes[visConfig.get('type')];
|
||||
this.deps = deps;
|
||||
this.uiSettings = uiSettings;
|
||||
this.charts = [];
|
||||
|
||||
this.vis = vis;
|
||||
|
@ -91,12 +91,18 @@ export class Handler {
|
|||
const xRaw = _.get(eventPayload.data, 'series[0].values[0].xRaw');
|
||||
if (!xRaw) return; // not sure if this is possible?
|
||||
return self.vis.emit(eventType, {
|
||||
table: xRaw.table,
|
||||
range: eventPayload.range,
|
||||
column: xRaw.column,
|
||||
name: 'brush',
|
||||
data: {
|
||||
table: xRaw.table,
|
||||
range: eventPayload.range,
|
||||
column: xRaw.column,
|
||||
},
|
||||
});
|
||||
case 'click':
|
||||
return self.vis.emit(eventType, eventPayload);
|
||||
return self.vis.emit(eventType, {
|
||||
name: 'filterBucket',
|
||||
data: eventPayload,
|
||||
});
|
||||
}
|
||||
};
|
||||
});
|
||||
|
@ -164,7 +170,7 @@ export class Handler {
|
|||
let loadedCount = 0;
|
||||
const chartSelection = selection.selectAll('.chart');
|
||||
chartSelection.each(function (chartData) {
|
||||
const chart = new self.ChartClass(self, this, chartData, self.deps);
|
||||
const chart = new self.ChartClass(self, this, chartData, self.uiSettings);
|
||||
|
||||
self.vis.eventNames().forEach(function (event) {
|
||||
self.enable(event, chart);
|
||||
|
@ -222,7 +228,7 @@ export class Handler {
|
|||
// class name needs `chart` in it for the polling checkSize function
|
||||
// to continuously call render on resize
|
||||
.attr('class', 'visError chart error')
|
||||
.attr('data-test-subj', 'visLibVisualizeError');
|
||||
.attr('data-test-subj', 'vislibVisualizeError');
|
||||
|
||||
div.append('h4').text(markdownIt.renderInline(message));
|
||||
|
||||
|
|
|
@ -157,7 +157,7 @@ dateHistogramArray.forEach(function (data, i) {
|
|||
const args = Array.from(arguments);
|
||||
expect(args.length).toBe(2);
|
||||
expect(args[0]).toBe('click');
|
||||
expect(args[1]).toBe(event);
|
||||
expect(args[1].data).toBe(event);
|
||||
done();
|
||||
};
|
||||
|
||||
|
|
|
@ -50,7 +50,6 @@ export class VisConfig {
|
|||
return _.get(this._values, property, defaults);
|
||||
} else {
|
||||
throw new Error(`Accessing invalid config property: ${property}`);
|
||||
return defaults;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,13 +35,14 @@ import { DIMMING_OPACITY_SETTING, HEATMAP_MAX_BUCKETS_SETTING } from '../../comm
|
|||
* @param config {Object} Parameters that define the chart type and chart options
|
||||
*/
|
||||
export class Vis extends EventEmitter {
|
||||
constructor(element, visConfigArgs, deps) {
|
||||
constructor(element, visConfigArgs, core, charts) {
|
||||
super();
|
||||
this.element = element.get ? element.get(0) : element;
|
||||
this.visConfigArgs = _.cloneDeep(visConfigArgs);
|
||||
this.visConfigArgs.dimmingOpacity = deps.uiSettings.get(DIMMING_OPACITY_SETTING);
|
||||
this.visConfigArgs.heatmapMaxBuckets = deps.uiSettings.get(HEATMAP_MAX_BUCKETS_SETTING);
|
||||
this.deps = deps;
|
||||
this.visConfigArgs.dimmingOpacity = core.uiSettings.get(DIMMING_OPACITY_SETTING);
|
||||
this.visConfigArgs.heatmapMaxBuckets = core.uiSettings.get(HEATMAP_MAX_BUCKETS_SETTING);
|
||||
this.charts = charts;
|
||||
this.uiSettings = core.uiSettings;
|
||||
}
|
||||
|
||||
hasLegend() {
|
||||
|
@ -56,7 +57,7 @@ export class Vis extends EventEmitter {
|
|||
this.data,
|
||||
this.uiState,
|
||||
this.element,
|
||||
this.deps.charts.colors.createColorLookupFunction.bind(this.deps.charts.colors)
|
||||
this.charts.colors.createColorLookupFunction.bind(this.charts.colors)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -78,7 +79,7 @@ export class Vis extends EventEmitter {
|
|||
|
||||
this.initVisConfig(data, uiState);
|
||||
|
||||
this.handler = new Handler(this, this.visConfig, this.deps);
|
||||
this.handler = new Handler(this, this.visConfig, this.uiSettings);
|
||||
this._runOnHandler('render');
|
||||
}
|
||||
|
||||
|
|
|
@ -39,13 +39,13 @@ import {
|
|||
* @param chartData {Object} Elasticsearch query results for this specific chart
|
||||
*/
|
||||
export class Chart {
|
||||
constructor(handler, element, chartData, deps) {
|
||||
constructor(handler, element, chartData, uiSettings) {
|
||||
this.handler = handler;
|
||||
this.chartEl = element;
|
||||
this.chartData = chartData;
|
||||
this.tooltips = [];
|
||||
|
||||
const events = (this.events = new Dispatch(handler, deps.uiSettings));
|
||||
const events = (this.events = new Dispatch(handler, uiSettings));
|
||||
|
||||
const fieldFormatter = getFormatService().deserialize(
|
||||
this.handler.data.get('tooltipFormatter')
|
||||
|
|
|
@ -53,20 +53,10 @@ afterEach(function () {
|
|||
count = 0;
|
||||
});
|
||||
|
||||
const getDeps = () => {
|
||||
const mockUiSettings = coreMock.createSetup().uiSettings;
|
||||
const charts = chartPluginMock.createStartContract();
|
||||
|
||||
return {
|
||||
uiSettings: mockUiSettings,
|
||||
charts: charts,
|
||||
};
|
||||
};
|
||||
|
||||
export function getVis(visLibParams, element) {
|
||||
export function getVis(vislibParams, element) {
|
||||
return new Vis(
|
||||
element || $visCanvas.new(),
|
||||
_.defaults({}, visLibParams || {}, {
|
||||
_.defaults({}, vislibParams || {}, {
|
||||
addTooltip: true,
|
||||
addLegend: true,
|
||||
defaultYExtents: false,
|
||||
|
@ -74,6 +64,7 @@ export function getVis(visLibParams, element) {
|
|||
yAxis: {},
|
||||
type: 'histogram',
|
||||
}),
|
||||
getDeps()
|
||||
coreMock.createSetup(),
|
||||
chartPluginMock.createStartContract()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import { getVis } from './_vis_fixture';
|
|||
describe('Vislib Gauge Chart Test Suite', function () {
|
||||
let vis;
|
||||
let chartEl;
|
||||
const visLibParams = {
|
||||
const vislibParams = {
|
||||
type: 'gauge',
|
||||
addTooltip: true,
|
||||
addLegend: false,
|
||||
|
@ -71,7 +71,7 @@ describe('Vislib Gauge Chart Test Suite', function () {
|
|||
};
|
||||
|
||||
function generateVis(opts = {}) {
|
||||
const config = _.defaultsDeep({}, opts, visLibParams);
|
||||
const config = _.defaultsDeep({}, opts, vislibParams);
|
||||
if (vis) {
|
||||
vis.destroy();
|
||||
$('.visChart').remove();
|
||||
|
|
|
@ -42,8 +42,8 @@ const defaults = {
|
|||
* @param chartData {Object} Elasticsearch query results for this specific chart
|
||||
*/
|
||||
export class PieChart extends Chart {
|
||||
constructor(handler, chartEl, chartData, deps) {
|
||||
super(handler, chartEl, chartData, deps);
|
||||
constructor(handler, chartEl, chartData, uiSettings) {
|
||||
super(handler, chartEl, chartData, uiSettings);
|
||||
const charts = this.handler.data.getVisData();
|
||||
this._validatePieData(charts);
|
||||
this._attr = _.defaults(handler.visConfig.get('chart', {}), defaults);
|
||||
|
|
|
@ -40,7 +40,7 @@ let mockedSVGElementGetBBox;
|
|||
let mockedSVGElementGetComputedTextLength;
|
||||
|
||||
describe('No global chart settings', function () {
|
||||
const visLibParams1 = {
|
||||
const vislibParams1 = {
|
||||
el: '<div class=chart1></div>',
|
||||
type: 'pie',
|
||||
addLegend: true,
|
||||
|
@ -58,7 +58,7 @@ describe('No global chart settings', function () {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
chart1 = getVis(visLibParams1);
|
||||
chart1 = getVis(vislibParams1);
|
||||
mockUiState = getMockUiState();
|
||||
});
|
||||
|
||||
|
@ -153,7 +153,7 @@ describe('Vislib PieChart Class Test Suite', function () {
|
|||
describe('Vislib PieChart Class Test Suite for ' + names[i] + ' data', function () {
|
||||
const mockPieData = pieChartMockData[aggItem];
|
||||
|
||||
const visLibParams = {
|
||||
const vislibParams = {
|
||||
type: 'pie',
|
||||
addLegend: true,
|
||||
addTooltip: true,
|
||||
|
@ -161,7 +161,7 @@ describe('Vislib PieChart Class Test Suite', function () {
|
|||
let vis;
|
||||
|
||||
beforeEach(async () => {
|
||||
vis = getVis(visLibParams);
|
||||
vis = getVis(vislibParams);
|
||||
const mockUiState = getMockUiState();
|
||||
vis.render(mockPieData, mockUiState);
|
||||
});
|
||||
|
|
|
@ -40,10 +40,10 @@ const touchdownTmpl = _.template(touchdownTmplHtml);
|
|||
* @param chartData {Object} Elasticsearch query results for this specific chart
|
||||
*/
|
||||
export class PointSeries extends Chart {
|
||||
constructor(handler, chartEl, chartData, deps) {
|
||||
super(handler, chartEl, chartData, deps);
|
||||
constructor(handler, chartEl, chartData, uiSettings) {
|
||||
super(handler, chartEl, chartData, uiSettings);
|
||||
|
||||
this.deps = deps;
|
||||
this.uiSettings = uiSettings;
|
||||
this.handler = handler;
|
||||
this.chartData = chartData;
|
||||
this.chartEl = chartEl;
|
||||
|
@ -246,7 +246,13 @@ export class PointSeries extends Chart {
|
|||
if (!seriArgs.show) return;
|
||||
const SeriClass =
|
||||
seriTypes[seriArgs.type || self.handler.visConfig.get('chart.type')] || seriTypes.line;
|
||||
const series = new SeriClass(self.handler, svg, data.series[i], seriArgs, self.deps);
|
||||
const series = new SeriClass(
|
||||
self.handler,
|
||||
svg,
|
||||
data.series[i],
|
||||
seriArgs,
|
||||
self.uiSettings
|
||||
);
|
||||
series.events = self.events;
|
||||
svg.call(series.draw());
|
||||
self.series.push(series);
|
||||
|
|
|
@ -43,8 +43,8 @@ const defaults = {
|
|||
* chart
|
||||
*/
|
||||
export class AreaChart extends PointSeries {
|
||||
constructor(handler, chartEl, chartData, seriesConfigArgs, deps) {
|
||||
super(handler, chartEl, chartData, seriesConfigArgs, deps);
|
||||
constructor(handler, chartEl, chartData, seriesConfigArgs, core) {
|
||||
super(handler, chartEl, chartData, seriesConfigArgs, core);
|
||||
|
||||
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
||||
this.isOverlapping = this.seriesConfig.mode !== 'stacked';
|
||||
|
|
|
@ -38,7 +38,7 @@ const dataTypesArray = {
|
|||
stackedSeries: import('../../../fixtures/mock_data/date_histogram/_stacked_series'),
|
||||
};
|
||||
|
||||
const visLibParams = {
|
||||
const vislibParams = {
|
||||
type: 'area',
|
||||
addLegend: true,
|
||||
addTooltip: true,
|
||||
|
@ -61,7 +61,7 @@ _.forOwn(dataTypesArray, function (dataType, dataTypeName) {
|
|||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
vis = getVis(visLibParams);
|
||||
vis = getVis(vislibParams);
|
||||
mockUiState = getMockUiState();
|
||||
vis.on('brush', _.noop);
|
||||
vis.render(await dataType, mockUiState);
|
||||
|
|
|
@ -57,8 +57,8 @@ function datumWidth(defaultWidth, datum, nextDatum, scale, gutterWidth, groupCou
|
|||
* @param chartData {Object} Elasticsearch query results for this specific chart
|
||||
*/
|
||||
export class ColumnChart extends PointSeries {
|
||||
constructor(handler, chartEl, chartData, seriesConfigArgs, deps) {
|
||||
super(handler, chartEl, chartData, seriesConfigArgs, deps);
|
||||
constructor(handler, chartEl, chartData, seriesConfigArgs, core) {
|
||||
super(handler, chartEl, chartData, seriesConfigArgs, core);
|
||||
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
||||
this.labelOptions = _.defaults(handler.visConfig.get('labels', {}), defaults.showLabel);
|
||||
}
|
||||
|
|
|
@ -62,7 +62,7 @@ dataTypesArray.forEach(function (dataType) {
|
|||
describe('Vislib Column Chart Test Suite for ' + name + ' Data', function () {
|
||||
let vis;
|
||||
let mockUiState;
|
||||
const visLibParams = {
|
||||
const vislibParams = {
|
||||
type: 'histogram',
|
||||
addLegend: true,
|
||||
addTooltip: true,
|
||||
|
@ -81,7 +81,7 @@ dataTypesArray.forEach(function (dataType) {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vis = getVis(visLibParams);
|
||||
vis = getVis(vislibParams);
|
||||
mockUiState = getMockUiState();
|
||||
vis.on('brush', _.noop);
|
||||
vis.render(data, mockUiState);
|
||||
|
@ -261,7 +261,7 @@ dataTypesArray.forEach(function (dataType) {
|
|||
describe('stackData method - data set with zeros in percentage mode', function () {
|
||||
let vis;
|
||||
let mockUiState;
|
||||
const visLibParams = {
|
||||
const vislibParams = {
|
||||
type: 'histogram',
|
||||
addLegend: true,
|
||||
addTooltip: true,
|
||||
|
@ -276,7 +276,7 @@ describe('stackData method - data set with zeros in percentage mode', function (
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vis = getVis(visLibParams);
|
||||
vis = getVis(vislibParams);
|
||||
mockUiState = getMockUiState();
|
||||
vis.on('brush', _.noop);
|
||||
});
|
||||
|
@ -320,7 +320,7 @@ describe('stackData method - data set with zeros in percentage mode', function (
|
|||
describe('datumWidth - split chart data set with holes', function () {
|
||||
let vis;
|
||||
let mockUiState;
|
||||
const visLibParams = {
|
||||
const vislibParams = {
|
||||
type: 'histogram',
|
||||
addLegend: true,
|
||||
addTooltip: true,
|
||||
|
@ -335,7 +335,7 @@ describe('datumWidth - split chart data set with holes', function () {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vis = getVis(visLibParams);
|
||||
vis = getVis(vislibParams);
|
||||
mockUiState = getMockUiState();
|
||||
vis.on('brush', _.noop);
|
||||
vis.render(rowsSeriesWithHoles, mockUiState);
|
||||
|
@ -366,7 +366,7 @@ describe('datumWidth - split chart data set with holes', function () {
|
|||
describe('datumWidth - monthly interval', function () {
|
||||
let vis;
|
||||
let mockUiState;
|
||||
const visLibParams = {
|
||||
const vislibParams = {
|
||||
type: 'histogram',
|
||||
addLegend: true,
|
||||
addTooltip: true,
|
||||
|
@ -384,7 +384,7 @@ describe('datumWidth - monthly interval', function () {
|
|||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vis = getVis(visLibParams);
|
||||
vis = getVis(vislibParams);
|
||||
mockUiState = getMockUiState();
|
||||
vis.on('brush', _.noop);
|
||||
vis.render(seriesMonthlyInterval, mockUiState);
|
||||
|
|
|
@ -71,7 +71,7 @@ describe('Vislib Heatmap Chart Test Suite', function () {
|
|||
describe('for ' + name + ' Data', function () {
|
||||
let vis;
|
||||
let mockUiState;
|
||||
const visLibParams = {
|
||||
const vislibParams = {
|
||||
type: 'heatmap',
|
||||
addLegend: true,
|
||||
addTooltip: true,
|
||||
|
@ -84,7 +84,7 @@ describe('Vislib Heatmap Chart Test Suite', function () {
|
|||
};
|
||||
|
||||
function generateVis(opts = {}) {
|
||||
const config = _.defaultsDeep({}, opts, visLibParams);
|
||||
const config = _.defaultsDeep({}, opts, vislibParams);
|
||||
vis = getVis(config);
|
||||
mockUiState = getMockUiState();
|
||||
vis.on('brush', _.noop);
|
||||
|
|
|
@ -42,8 +42,8 @@ const defaults = {
|
|||
* @param chartData {Object} Elasticsearch query results for this specific chart
|
||||
*/
|
||||
export class LineChart extends PointSeries {
|
||||
constructor(handler, chartEl, chartData, seriesConfigArgs, deps) {
|
||||
super(handler, chartEl, chartData, seriesConfigArgs, deps);
|
||||
constructor(handler, chartEl, chartData, seriesConfigArgs, core) {
|
||||
super(handler, chartEl, chartData, seriesConfigArgs, core);
|
||||
this.seriesConfig = _.defaults(seriesConfigArgs || {}, defaults);
|
||||
}
|
||||
|
||||
|
|
|
@ -71,14 +71,14 @@ describe('Vislib Line Chart', function () {
|
|||
let mockUiState;
|
||||
|
||||
beforeEach(() => {
|
||||
const visLibParams = {
|
||||
const vislibParams = {
|
||||
type: 'line',
|
||||
addLegend: true,
|
||||
addTooltip: true,
|
||||
drawLinesBetweenPoints: true,
|
||||
};
|
||||
|
||||
vis = getVis(visLibParams);
|
||||
vis = getVis(vislibParams);
|
||||
mockUiState = getMockUiState();
|
||||
vis.render(data, mockUiState);
|
||||
vis.on('brush', _.noop);
|
||||
|
|
|
@ -70,10 +70,10 @@
|
|||
flex-direction: column;
|
||||
}
|
||||
|
||||
.visChart__spinner {
|
||||
.visChart__spinner, .visError {
|
||||
display: flex;
|
||||
flex: 1 1 auto;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ export {
|
|||
ISavedVis,
|
||||
VisSavedObject,
|
||||
VisResponseValue,
|
||||
VisToExpressionAst,
|
||||
} from './types';
|
||||
export { ExprVisAPIEvents } from './expressions/vis';
|
||||
export { VisualizationListItem } from './vis_types/vis_type_alias_registry';
|
||||
|
|
|
@ -6,8 +6,6 @@ exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunct
|
|||
|
||||
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles metrics/tsvb function 1`] = `"tsvb params='{\\"foo\\":\\"bar\\"}' uiState='{}' "`;
|
||||
|
||||
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles pie function 1`] = `"kibana_pie visConfig='{\\"dimensions\\":{\\"metric\\":{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},\\"buckets\\":[1,2]}}' "`;
|
||||
|
||||
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles region_map function with buckets 1`] = `"regionmap visConfig='{\\"metric\\":{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},\\"bucket\\":1}' "`;
|
||||
|
||||
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles region_map function without buckets 1`] = `"regionmap visConfig='{\\"metric\\":{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}}' "`;
|
||||
|
|
|
@ -21,14 +21,12 @@ import {
|
|||
prepareJson,
|
||||
prepareString,
|
||||
buildPipelineVisFunction,
|
||||
buildVislibDimensions,
|
||||
buildPipeline,
|
||||
SchemaConfig,
|
||||
Schemas,
|
||||
} from './build_pipeline';
|
||||
import { Vis } from '..';
|
||||
import { dataPluginMock } from '../../../../plugins/data/public/mocks';
|
||||
import { IndexPattern, IAggConfigs } from '../../../../plugins/data/public';
|
||||
import { parseExpression } from '../../../expressions/common';
|
||||
|
||||
describe('visualize loader pipeline helpers: build pipeline', () => {
|
||||
|
@ -136,15 +134,6 @@ describe('visualize loader pipeline helpers: build pipeline', () => {
|
|||
const actual = buildPipelineVisFunction.tile_map(params, schemas, uiState);
|
||||
expect(actual).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('handles pie function', () => {
|
||||
const schemas = {
|
||||
...schemasDef,
|
||||
segment: [1, 2],
|
||||
};
|
||||
const actual = buildPipelineVisFunction.pie({}, schemas, uiState);
|
||||
expect(actual).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildPipeline', () => {
|
||||
|
@ -174,157 +163,4 @@ describe('visualize loader pipeline helpers: build pipeline', () => {
|
|||
expect(expression).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildVislibDimensions', () => {
|
||||
const dataStart = dataPluginMock.createStartContract();
|
||||
|
||||
let aggs: IAggConfigs;
|
||||
let vis: Vis;
|
||||
let params: any;
|
||||
|
||||
beforeEach(() => {
|
||||
aggs = dataStart.search.aggs.createAggConfigs({} as IndexPattern, [
|
||||
{
|
||||
id: '0',
|
||||
enabled: true,
|
||||
type: 'count',
|
||||
schema: 'metric',
|
||||
params: {},
|
||||
},
|
||||
]);
|
||||
|
||||
params = {
|
||||
searchSource: null,
|
||||
timefilter: dataStart.query.timefilter.timefilter,
|
||||
timeRange: null,
|
||||
};
|
||||
});
|
||||
|
||||
describe('test y dimension format for histogram chart', () => {
|
||||
beforeEach(() => {
|
||||
vis = {
|
||||
// @ts-ignore
|
||||
type: {
|
||||
name: 'histogram',
|
||||
},
|
||||
params: {
|
||||
seriesParams: [
|
||||
{
|
||||
data: { id: '0' },
|
||||
valueAxis: 'axis-y',
|
||||
},
|
||||
],
|
||||
valueAxes: [
|
||||
{
|
||||
id: 'axis-y',
|
||||
scale: {
|
||||
mode: 'normal',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
data: {
|
||||
aggs,
|
||||
searchSource: {} as any,
|
||||
},
|
||||
isHierarchical: () => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('with one numeric metric in regular moder', async () => {
|
||||
const dimensions = await buildVislibDimensions(vis, params);
|
||||
const expected = { id: 'number' };
|
||||
const actual = dimensions.y[0].format;
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('with one numeric metric in percentage mode', async () => {
|
||||
vis.params.valueAxes[0].scale.mode = 'percentage';
|
||||
const dimensions = await buildVislibDimensions(vis, params);
|
||||
const expected = { id: 'percent' };
|
||||
const actual = dimensions.y[0].format;
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('with two numeric metrics, mixed normal and percent mode should have corresponding formatters', async () => {
|
||||
aggs.createAggConfig({
|
||||
id: '5',
|
||||
enabled: true,
|
||||
type: 'count',
|
||||
schema: 'metric',
|
||||
params: {},
|
||||
});
|
||||
|
||||
vis.params = {
|
||||
seriesParams: [
|
||||
{
|
||||
data: { id: '0' },
|
||||
valueAxis: 'axis-y-1',
|
||||
},
|
||||
{
|
||||
data: { id: '5' },
|
||||
valueAxis: 'axis-y-2',
|
||||
},
|
||||
],
|
||||
valueAxes: [
|
||||
{
|
||||
id: 'axis-y-1',
|
||||
scale: {
|
||||
mode: 'normal',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'axis-y-2',
|
||||
scale: {
|
||||
mode: 'percentage',
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const dimensions = await buildVislibDimensions(vis, params);
|
||||
const expectedY1 = { id: 'number' };
|
||||
const expectedY2 = { id: 'percent' };
|
||||
expect(dimensions.y[0].format).toEqual(expectedY1);
|
||||
expect(dimensions.y[1].format).toEqual(expectedY2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('test y dimension format for gauge chart', () => {
|
||||
beforeEach(() => {
|
||||
vis = {
|
||||
// @ts-ignore
|
||||
type: {
|
||||
name: 'gauge',
|
||||
},
|
||||
params: { gauge: {} },
|
||||
data: {
|
||||
aggs,
|
||||
searchSource: {} as any,
|
||||
},
|
||||
isHierarchical: () => {
|
||||
return false;
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('with percentageMode = false', async () => {
|
||||
vis.params.gauge.percentageMode = false;
|
||||
const dimensions = await buildVislibDimensions(vis, params);
|
||||
const expected = { id: 'number' };
|
||||
const actual = dimensions.y[0].format;
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
|
||||
it('with percentageMode = true', async () => {
|
||||
vis.params.gauge.percentageMode = true;
|
||||
const dimensions = await buildVislibDimensions(vis, params);
|
||||
const expected = { id: 'percent' };
|
||||
const actual = dimensions.y[0].format;
|
||||
expect(actual).toEqual(expected);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import moment from 'moment';
|
||||
import { formatExpression, SerializedFieldFormat } from '../../../../plugins/expressions/public';
|
||||
import { IAggConfig, search, TimefilterContract } from '../../../../plugins/data/public';
|
||||
import { Vis, VisParams } from '../types';
|
||||
|
@ -76,16 +74,6 @@ export interface BuildPipelineParams {
|
|||
abortSignal?: AbortSignal;
|
||||
}
|
||||
|
||||
const vislibCharts: string[] = [
|
||||
'area',
|
||||
'gauge',
|
||||
'goal',
|
||||
'heatmap',
|
||||
'histogram',
|
||||
'horizontal_bar',
|
||||
'line',
|
||||
];
|
||||
|
||||
export const getSchemas = <TVisParams>(
|
||||
vis: Vis<TVisParams>,
|
||||
{ timeRange, timefilter }: BuildPipelineParams
|
||||
|
@ -230,29 +218,6 @@ export const prepareDimension = (variable: string, data: any) => {
|
|||
return expr;
|
||||
};
|
||||
|
||||
const adjustVislibDimensionFormmaters = (vis: Vis, dimensions: { y: any[] }): void => {
|
||||
const visConfig = vis.params;
|
||||
const responseAggs = vis.data.aggs!.getResponseAggs().filter((agg: IAggConfig) => agg.enabled);
|
||||
|
||||
(dimensions.y || []).forEach((yDimension) => {
|
||||
const yAgg = responseAggs[yDimension.accessor];
|
||||
const seriesParam = (visConfig.seriesParams || []).find(
|
||||
(param: any) => param.data.id === yAgg.id
|
||||
);
|
||||
if (seriesParam) {
|
||||
const usedValueAxis = (visConfig.valueAxes || []).find(
|
||||
(valueAxis: any) => valueAxis.id === seriesParam.valueAxis
|
||||
);
|
||||
if (get(usedValueAxis, 'scale.mode') === 'percentage') {
|
||||
yDimension.format = { id: 'percent' };
|
||||
}
|
||||
}
|
||||
if (get(visConfig, 'gauge.percentageMode') === true) {
|
||||
yDimension.format = { id: 'percent' };
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const buildPipelineVisFunction: BuildPipelineVisFunction = {
|
||||
input_control_vis: (params) => {
|
||||
return `input_control_vis ${prepareJson('visConfig', params)}`;
|
||||
|
@ -278,13 +243,6 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = {
|
|||
};
|
||||
return `tilemap ${prepareJson('visConfig', visConfig)}`;
|
||||
},
|
||||
pie: (params, schemas) => {
|
||||
const visConfig = {
|
||||
...params,
|
||||
...buildVisConfig.pie(schemas),
|
||||
};
|
||||
return `kibana_pie ${prepareJson('visConfig', visConfig)}`;
|
||||
},
|
||||
};
|
||||
|
||||
const buildVisConfig: BuildVisConfigFunction = {
|
||||
|
@ -305,55 +263,6 @@ const buildVisConfig: BuildVisConfigFunction = {
|
|||
};
|
||||
return visConfig;
|
||||
},
|
||||
pie: (schemas) => {
|
||||
const visConfig = {} as any;
|
||||
visConfig.dimensions = {
|
||||
metric: schemas.metric[0],
|
||||
buckets: schemas.segment,
|
||||
splitRow: schemas.split_row,
|
||||
splitColumn: schemas.split_column,
|
||||
};
|
||||
return visConfig;
|
||||
},
|
||||
};
|
||||
|
||||
export const buildVislibDimensions = async (vis: any, params: BuildPipelineParams) => {
|
||||
const schemas = getSchemas(vis, {
|
||||
timeRange: params.timeRange,
|
||||
timefilter: params.timefilter,
|
||||
});
|
||||
const dimensions = {
|
||||
x: schemas.segment ? schemas.segment[0] : null,
|
||||
y: schemas.metric,
|
||||
z: schemas.radius,
|
||||
width: schemas.width,
|
||||
series: schemas.group,
|
||||
splitRow: schemas.split_row,
|
||||
splitColumn: schemas.split_column,
|
||||
};
|
||||
if (schemas.segment) {
|
||||
const xAgg = vis.data.aggs.getResponseAggs()[dimensions.x.accessor];
|
||||
if (xAgg.type.name === 'date_histogram') {
|
||||
dimensions.x.params.date = true;
|
||||
const { esUnit, esValue } = xAgg.buckets.getInterval();
|
||||
dimensions.x.params.interval = moment.duration(esValue, esUnit);
|
||||
dimensions.x.params.intervalESValue = esValue;
|
||||
dimensions.x.params.intervalESUnit = esUnit;
|
||||
dimensions.x.params.format = xAgg.buckets.getScaledDateFormat();
|
||||
dimensions.x.params.bounds = xAgg.buckets.getBounds();
|
||||
} else if (xAgg.type.name === 'histogram') {
|
||||
const intervalParam = xAgg.type.paramByName('interval');
|
||||
const output = { params: {} as any };
|
||||
await intervalParam.modifyAggConfigOnSearchRequestStart(xAgg, vis.data.searchSource, {
|
||||
abortSignal: params.abortSignal,
|
||||
});
|
||||
intervalParam.write(xAgg, output);
|
||||
dimensions.x.params.interval = output.params.interval;
|
||||
}
|
||||
}
|
||||
|
||||
adjustVislibDimensionFormmaters(vis, dimensions);
|
||||
return dimensions;
|
||||
};
|
||||
|
||||
export const buildPipeline = async (vis: Vis, params: BuildPipelineParams) => {
|
||||
|
@ -396,11 +305,6 @@ export const buildPipeline = async (vis: Vis, params: BuildPipelineParams) => {
|
|||
schemas,
|
||||
uiState
|
||||
);
|
||||
} else if (vislibCharts.includes(vis.type.name)) {
|
||||
const visConfig = { ...vis.params };
|
||||
visConfig.dimensions = await buildVislibDimensions(vis, params);
|
||||
|
||||
pipeline += `vislib type='${vis.type.name}' ${prepareJson('visConfig', visConfig)}`;
|
||||
} else {
|
||||
const visConfig = { ...vis.params };
|
||||
visConfig.dimensions = schemas;
|
||||
|
|
|
@ -76,4 +76,4 @@ export interface VisToExpressionAstParams {
|
|||
export type VisToExpressionAst<TVisParams = VisParams> = (
|
||||
vis: Vis<TVisParams>,
|
||||
params: VisToExpressionAstParams
|
||||
) => ExpressionAstExpression;
|
||||
) => Promise<ExpressionAstExpression> | ExpressionAstExpression;
|
||||
|
|
|
@ -218,7 +218,7 @@ export function VisualizeChartPageProvider({ getService, getPageObjects }: FtrPr
|
|||
}
|
||||
|
||||
public async expectError() {
|
||||
await testSubjects.existOrFail('visLibVisualizeError');
|
||||
await testSubjects.existOrFail('vislibVisualizeError');
|
||||
}
|
||||
|
||||
public async getVisualizationRenderingCount() {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue