mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
* Convert to typescript * Move related files directly into plugin * Implement toExpressionAst * Remove build_pipeline dedicated fn * Async import converter * Create a custom renderer * Move function directly into plugin * Update tests * Move files directly into related plugins * Remove ExprVis instance usage in maps visualizations * Use uiState updates * Fix minor issues * Update expression builder * Update styles * Create wrapper component * Update rendering * Create region map expression renderer * Fix tests and types * Fix initial render * Remove resize subscription * Fix custom visualization expression * Update region map expression in tests * Update files structure * Remove ReactVisController * Remove base visualization renderer * Remove extra vis properties * Use requiresSearch flag for agg based vis * Update types * Remove visualization expression function * Create toExpressionAst function * Update custom visualization example * Update interpreter functional tests * Enhance VisTypeDefinition interface * Enhance visualization types * Update license Co-authored-by: Alexey Antonov <alexwizp@gmail.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Alexey Antonov <alexwizp@gmail.com> Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
2916bd9d8c
commit
3f81a0b16a
140 changed files with 751 additions and 1889 deletions
|
@ -29,8 +29,6 @@ beforeEach(() => {
|
|||
name: 'test',
|
||||
title: 'test',
|
||||
visualization: null,
|
||||
requestHandler: 'test',
|
||||
responseHandler: 'test',
|
||||
stage: 'beta',
|
||||
requiresSearch: false,
|
||||
hidden: false,
|
||||
|
|
|
@ -19,7 +19,7 @@ import {
|
|||
EuiSelect,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { IIndexPattern } from 'src/plugins/data/public';
|
||||
import { ControlEditor } from './control_editor';
|
||||
import {
|
||||
|
@ -40,7 +40,7 @@ interface ControlsTabUiState {
|
|||
type: CONTROL_TYPES;
|
||||
}
|
||||
|
||||
export type ControlsTabProps = VisOptionsProps<InputControlVisParams> & {
|
||||
export type ControlsTabProps = VisEditorOptionsProps<InputControlVisParams> & {
|
||||
deps: InputControlVisDependencies;
|
||||
};
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import React, { lazy } from 'react';
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { InputControlVisDependencies } from '../../plugin';
|
||||
import { InputControlVisParams } from '../../types';
|
||||
|
||||
|
@ -15,9 +15,9 @@ const ControlsTab = lazy(() => import('./controls_tab'));
|
|||
const OptionsTab = lazy(() => import('./options_tab'));
|
||||
|
||||
export const getControlsTab = (deps: InputControlVisDependencies) => (
|
||||
props: VisOptionsProps<InputControlVisParams>
|
||||
props: VisEditorOptionsProps<InputControlVisParams>
|
||||
) => <ControlsTab {...props} deps={deps} />;
|
||||
|
||||
export const OptionsTabLazy = (props: VisOptionsProps<InputControlVisParams>) => (
|
||||
export const OptionsTabLazy = (props: VisEditorOptionsProps<InputControlVisParams>) => (
|
||||
<OptionsTab {...props} />
|
||||
);
|
||||
|
|
|
@ -12,10 +12,10 @@ import { EuiForm, EuiFormRow, EuiSwitch } from '@elastic/eui';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { EuiSwitchEvent } from '@elastic/eui';
|
||||
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { InputControlVisParams } from '../../types';
|
||||
|
||||
export type OptionsTabProps = VisOptionsProps<InputControlVisParams>;
|
||||
export type OptionsTabProps = VisEditorOptionsProps<InputControlVisParams>;
|
||||
|
||||
class OptionsTab extends PureComponent<OptionsTabProps> {
|
||||
handleUpdateFiltersChange = (event: EuiSwitchEvent) => {
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { VisGroups, BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { VisGroups, VisTypeDefinition } from '../../visualizations/public';
|
||||
import { getControlsTab, OptionsTabLazy } from './components/editor';
|
||||
import { InputControlVisDependencies } from './plugin';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
|
@ -15,7 +15,7 @@ import { InputControlVisParams } from './types';
|
|||
|
||||
export function createInputControlVisTypeDefinition(
|
||||
deps: InputControlVisDependencies
|
||||
): BaseVisTypeOptions<InputControlVisParams> {
|
||||
): VisTypeDefinition<InputControlVisParams> {
|
||||
const ControlsTab = getControlsTab(deps);
|
||||
|
||||
return {
|
||||
|
@ -56,7 +56,6 @@ export function createInputControlVisTypeDefinition(
|
|||
],
|
||||
},
|
||||
inspectorAdapters: {},
|
||||
requestHandler: 'none',
|
||||
toExpressionAst,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import React, { lazy } from 'react';
|
||||
import { IServiceSettings } from 'src/plugins/maps_legacy/public';
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { RegionMapVisParams } from '../region_map_types';
|
||||
|
||||
const RegionMapOptions = lazy(() => import('./region_map_options'));
|
||||
|
||||
export const createRegionMapOptions = (getServiceSettings: () => Promise<IServiceSettings>) => (
|
||||
props: VisOptionsProps<RegionMapVisParams>
|
||||
props: VisEditorOptionsProps<RegionMapVisParams>
|
||||
) => <RegionMapOptions {...props} getServiceSettings={getServiceSettings} />;
|
||||
|
|
|
@ -10,7 +10,7 @@ import React, { useCallback, useMemo } from 'react';
|
|||
import { EuiIcon, EuiLink, EuiPanel, EuiSpacer, EuiText, EuiTitle } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { FileLayerField, VectorLayer, IServiceSettings } from '../../../maps_legacy/public';
|
||||
import { SelectOption, SwitchOption, NumberInputOption } from '../../../vis_default_editor/public';
|
||||
import { WmsOptions } from '../../../maps_legacy/public';
|
||||
|
@ -28,7 +28,7 @@ const mapFieldForOption = ({ description, name }: FileLayerField) => ({
|
|||
|
||||
export type RegionMapOptionsProps = {
|
||||
getServiceSettings: () => Promise<IServiceSettings>;
|
||||
} & VisOptionsProps<RegionMapVisParams>;
|
||||
} & VisEditorOptionsProps<RegionMapVisParams>;
|
||||
|
||||
function RegionMapOptions(props: RegionMapOptionsProps) {
|
||||
const { getServiceSettings, stateParams, vis, setValue } = props;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { VisTypeDefinition } from '../../visualizations/public';
|
||||
import { truncatedColorSchemas } from '../../charts/public';
|
||||
import { ORIGIN } from '../../maps_legacy/public';
|
||||
|
||||
|
@ -23,7 +23,7 @@ export function createRegionMapTypeDefinition({
|
|||
uiSettings,
|
||||
regionmapsConfig,
|
||||
getServiceSettings,
|
||||
}: RegionMapVisualizationDependencies): BaseVisTypeOptions<RegionMapVisParams> {
|
||||
}: RegionMapVisualizationDependencies): VisTypeDefinition<RegionMapVisParams> {
|
||||
return {
|
||||
name: 'region_map',
|
||||
getInfoMessage: getDeprecationMessage,
|
||||
|
@ -139,5 +139,6 @@ provided base maps, or add your own. Darker colors represent higher values.',
|
|||
|
||||
return vis;
|
||||
},
|
||||
requiresSearch: true,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ import {
|
|||
IndexPatternLoadExpressionFunctionDefinition,
|
||||
} from '../../data/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||
import { getVisSchemas, Vis, BuildPipelineParams } from '../../visualizations/public';
|
||||
import { getVisSchemas, VisToExpressionAst } from '../../visualizations/public';
|
||||
import { RegionMapExpressionFunctionDefinition } from './region_map_fn';
|
||||
import { RegionMapVisConfig, RegionMapVisParams } from './region_map_types';
|
||||
|
||||
export const toExpressionAst = (vis: Vis<RegionMapVisParams>, params: BuildPipelineParams) => {
|
||||
export const toExpressionAst: VisToExpressionAst<RegionMapVisParams> = (vis, params) => {
|
||||
const esaggs = buildExpressionFunction<EsaggsExpressionFunctionDefinition>('esaggs', {
|
||||
index: buildExpression([
|
||||
buildExpressionFunction<IndexPatternLoadExpressionFunctionDefinition>('indexPatternLoad', {
|
||||
|
|
|
@ -10,8 +10,8 @@ import React, { useEffect } from 'react';
|
|||
import { EuiPanel, EuiSpacer } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import {
|
||||
VisOptionsProps,
|
||||
BasicOptions,
|
||||
SelectOption,
|
||||
SwitchOption,
|
||||
|
@ -21,7 +21,7 @@ import { WmsOptions } from '../../../maps_legacy/public';
|
|||
import { TileMapVisParams } from '../types';
|
||||
import { MapTypes } from '../utils/map_types';
|
||||
|
||||
export type TileMapOptionsProps = VisOptionsProps<TileMapVisParams>;
|
||||
export type TileMapOptionsProps = VisEditorOptionsProps<TileMapVisParams>;
|
||||
|
||||
function TileMapOptions(props: TileMapOptionsProps) {
|
||||
const { stateParams, setValue, vis } = props;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { BaseVisTypeOptions } from 'src/plugins/visualizations/public';
|
||||
import { VisTypeDefinition } from 'src/plugins/visualizations/public';
|
||||
import { truncatedColorSchemas } from '../../charts/public';
|
||||
|
||||
// @ts-expect-error
|
||||
|
@ -21,7 +21,7 @@ import { MapTypes } from './utils/map_types';
|
|||
|
||||
export function createTileMapTypeDefinition(
|
||||
dependencies: TileMapVisualizationDependencies
|
||||
): BaseVisTypeOptions<TileMapVisParams> {
|
||||
): VisTypeDefinition<TileMapVisParams> {
|
||||
const { uiSettings, getServiceSettings } = dependencies;
|
||||
|
||||
return {
|
||||
|
@ -147,5 +147,6 @@ export function createTileMapTypeDefinition(
|
|||
}
|
||||
return vis;
|
||||
},
|
||||
requiresSearch: true,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -11,11 +11,11 @@ import {
|
|||
IndexPatternLoadExpressionFunctionDefinition,
|
||||
} from '../../data/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||
import { getVisSchemas, Vis, BuildPipelineParams } from '../../visualizations/public';
|
||||
import { getVisSchemas, VisToExpressionAst } from '../../visualizations/public';
|
||||
import { TileMapExpressionFunctionDefinition } from './tile_map_fn';
|
||||
import { TileMapVisConfig, TileMapVisParams } from './types';
|
||||
|
||||
export const toExpressionAst = (vis: Vis<TileMapVisParams>, params: BuildPipelineParams) => {
|
||||
export const toExpressionAst: VisToExpressionAst<TileMapVisParams> = (vis, params) => {
|
||||
const esaggs = buildExpressionFunction<EsaggsExpressionFunctionDefinition>('esaggs', {
|
||||
index: buildExpression([
|
||||
buildExpressionFunction<IndexPatternLoadExpressionFunctionDefinition>('indexPatternLoad', {
|
||||
|
|
|
@ -50,7 +50,6 @@ describe('DefaultEditorGroup helpers', () => {
|
|||
min: 0,
|
||||
max: 3,
|
||||
aggFilter: [],
|
||||
editor: false,
|
||||
params: [],
|
||||
defaults: null,
|
||||
mustBeFirst: true,
|
||||
|
@ -62,7 +61,6 @@ describe('DefaultEditorGroup helpers', () => {
|
|||
min: 2,
|
||||
max: 3,
|
||||
aggFilter: [],
|
||||
editor: false,
|
||||
params: [],
|
||||
defaults: null,
|
||||
},
|
||||
|
|
|
@ -10,7 +10,7 @@ import React from 'react';
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { VisOptionsProps } from '../../vis_options_props';
|
||||
import { VisEditorOptionsProps } from '../../../../visualizations/public';
|
||||
import { SwitchOption } from './switch';
|
||||
import { SelectOption } from './select';
|
||||
|
||||
|
@ -23,7 +23,7 @@ function BasicOptions<VisParams extends BasicOptionsParams>({
|
|||
stateParams,
|
||||
setValue,
|
||||
vis,
|
||||
}: VisOptionsProps<VisParams>) {
|
||||
}: VisEditorOptionsProps<VisParams>) {
|
||||
return (
|
||||
<>
|
||||
<SelectOption
|
||||
|
|
|
@ -12,7 +12,7 @@ import { EuiLink, EuiText } from '@elastic/eui';
|
|||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { ColorSchemaParams, ColorSchema } from 'src/plugins/charts/public';
|
||||
import { VisOptionsProps } from '../../vis_options_props';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { SelectOption } from './select';
|
||||
import { SwitchOption } from './switch';
|
||||
|
||||
|
@ -24,7 +24,7 @@ export type SetColorSchemaOptionsValue = <T extends keyof ColorSchemaParams>(
|
|||
interface ColorSchemaOptionsProps extends ColorSchemaParams {
|
||||
disabled?: boolean;
|
||||
colorSchemas: ColorSchema[];
|
||||
uiState: VisOptionsProps['uiState'];
|
||||
uiState: VisEditorOptionsProps['uiState'];
|
||||
setValue: SetColorSchemaOptionsValue;
|
||||
showHelpText?: boolean;
|
||||
}
|
||||
|
|
|
@ -9,13 +9,12 @@
|
|||
import { useCallback, useState } from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { Vis } from '../../../../visualizations/public';
|
||||
import { Vis, VisEditorOptionsProps } from '../../../../visualizations/public';
|
||||
|
||||
import { VisOptionsProps } from '../../vis_options_props';
|
||||
import { DefaultEditorDataTab, DefaultEditorDataTabProps } from './data_tab';
|
||||
|
||||
export interface OptionTab {
|
||||
editor: React.ComponentType<VisOptionsProps | DefaultEditorDataTabProps>;
|
||||
editor: React.ComponentType<VisEditorOptionsProps | DefaultEditorDataTabProps>;
|
||||
name: string;
|
||||
title: string;
|
||||
isSelected?: boolean;
|
||||
|
|
|
@ -16,7 +16,6 @@ export { PalettePicker } from './components/controls/palette_picker';
|
|||
export * from './components/options';
|
||||
export { RangesParamEditor, RangeValues } from './components/controls/ranges';
|
||||
export * from './editor_size';
|
||||
export * from './vis_options_props';
|
||||
export * from './utils';
|
||||
|
||||
export const plugin = (context: PluginInitializerContext) => {
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { Vis, PersistedState } from 'src/plugins/visualizations/public';
|
||||
import { IAggConfigs } from 'src/plugins/data/public';
|
||||
|
||||
export interface VisOptionsProps<VisParamType = unknown> {
|
||||
aggs: IAggConfigs;
|
||||
hasHistogramAgg: boolean;
|
||||
isTabSelected: boolean;
|
||||
stateParams: VisParamType;
|
||||
vis: Vis;
|
||||
uiState: PersistedState;
|
||||
setValue<T extends keyof VisParamType>(paramName: T, value: VisParamType[T]): void;
|
||||
setValidity(isValid: boolean): void;
|
||||
setTouched(isTouched: boolean): void;
|
||||
}
|
|
@ -9,7 +9,7 @@
|
|||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { MarkdownVisParams } from './types';
|
||||
import { MarkdownOptions } from './markdown_options';
|
||||
|
||||
|
@ -21,7 +21,7 @@ describe('MarkdownOptions', () => {
|
|||
openLinksInNewTab: false,
|
||||
},
|
||||
setValue: jest.fn(),
|
||||
} as unknown) as VisOptionsProps<MarkdownVisParams>;
|
||||
} as unknown) as VisEditorOptionsProps<MarkdownVisParams>;
|
||||
|
||||
it('should match snapshot', () => {
|
||||
const comp = shallow(<MarkdownOptions {...props} />);
|
||||
|
|
|
@ -18,10 +18,10 @@ import {
|
|||
} from '@elastic/eui';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { MarkdownVisParams } from './types';
|
||||
|
||||
function MarkdownOptions({ stateParams, setValue }: VisOptionsProps<MarkdownVisParams>) {
|
||||
function MarkdownOptions({ stateParams, setValue }: VisEditorOptionsProps<MarkdownVisParams>) {
|
||||
const onMarkdownUpdate = useCallback(
|
||||
({ target: { value } }: React.ChangeEvent<HTMLTextAreaElement>) => setValue('markdown', value),
|
||||
[setValue]
|
||||
|
|
|
@ -11,10 +11,11 @@ import { i18n } from '@kbn/i18n';
|
|||
import { MarkdownOptions } from './markdown_options';
|
||||
import { SettingsOptions } from './settings_options_lazy';
|
||||
import { DefaultEditorSize } from '../../vis_default_editor/public';
|
||||
import { VisGroups } from '../../visualizations/public';
|
||||
import { VisGroups, VisTypeDefinition } from '../../visualizations/public';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { MarkdownVisParams } from './types';
|
||||
|
||||
export const markdownVisDefinition = {
|
||||
export const markdownVisDefinition: VisTypeDefinition<MarkdownVisParams> = {
|
||||
name: 'markdown',
|
||||
title: 'Markdown',
|
||||
isAccessible: true,
|
||||
|
@ -58,7 +59,5 @@ export const markdownVisDefinition = {
|
|||
showTimePicker: false,
|
||||
showFilterBar: false,
|
||||
},
|
||||
requestHandler: 'none',
|
||||
responseHandler: 'none',
|
||||
inspectorAdapters: {},
|
||||
};
|
||||
|
|
|
@ -10,10 +10,11 @@ import React from 'react';
|
|||
import { EuiPanel } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { VisOptionsProps, SwitchOption, RangeOption } from '../../vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { SwitchOption, RangeOption } from '../../vis_default_editor/public';
|
||||
import { MarkdownVisParams } from './types';
|
||||
|
||||
function SettingsOptions({ stateParams, setValue }: VisOptionsProps<MarkdownVisParams>) {
|
||||
function SettingsOptions({ stateParams, setValue }: VisEditorOptionsProps<MarkdownVisParams>) {
|
||||
return (
|
||||
<EuiPanel paddingSize="s">
|
||||
<RangeOption
|
||||
|
|
|
@ -9,8 +9,9 @@
|
|||
import { VisToExpressionAst } from '../../visualizations/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||
import { MarkdownVisExpressionFunctionDefinition } from './markdown_fn';
|
||||
import { MarkdownVisParams } from './types';
|
||||
|
||||
export const toExpressionAst: VisToExpressionAst = (vis) => {
|
||||
export const toExpressionAst: VisToExpressionAst<MarkdownVisParams> = (vis) => {
|
||||
const { markdown, fontSize, openLinksInNewTab } = vis.params;
|
||||
|
||||
const markdownVis = buildExpressionFunction<MarkdownVisExpressionFunctionDefinition>(
|
||||
|
|
|
@ -5,9 +5,6 @@ Object {
|
|||
"as": "metric_vis",
|
||||
"type": "render",
|
||||
"value": Object {
|
||||
"params": Object {
|
||||
"listenOnChange": true,
|
||||
},
|
||||
"visConfig": Object {
|
||||
"dimensions": Object {
|
||||
"metrics": undefined,
|
||||
|
|
|
@ -37,6 +37,9 @@ Object {
|
|||
"percentageMode": Array [
|
||||
true,
|
||||
],
|
||||
"showLabels": Array [
|
||||
false,
|
||||
],
|
||||
},
|
||||
"function": "metricVis",
|
||||
"type": "function",
|
||||
|
@ -79,7 +82,11 @@ Object {
|
|||
"type": "function",
|
||||
},
|
||||
Object {
|
||||
"arguments": Object {},
|
||||
"arguments": Object {
|
||||
"showLabels": Array [
|
||||
false,
|
||||
],
|
||||
},
|
||||
"function": "metricVis",
|
||||
"type": "function",
|
||||
},
|
||||
|
|
|
@ -18,10 +18,10 @@ import {
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import {
|
||||
ColorRanges,
|
||||
SetColorRangeValue,
|
||||
VisOptionsProps,
|
||||
SwitchOption,
|
||||
SetColorSchemaOptionsValue,
|
||||
ColorSchemaOptions,
|
||||
|
@ -37,7 +37,7 @@ function MetricVisOptions({
|
|||
setTouched,
|
||||
vis,
|
||||
uiState,
|
||||
}: VisOptionsProps<VisParams>) {
|
||||
}: VisEditorOptionsProps<VisParams>) {
|
||||
const setMetricValue: <T extends keyof MetricVisParam>(
|
||||
paramName: T,
|
||||
value: MetricVisParam[T]
|
||||
|
|
|
@ -39,7 +39,6 @@ export interface MetricVisRenderValue {
|
|||
visType: typeof visType;
|
||||
visData: Input;
|
||||
visConfig: Pick<VisParams, 'metric' | 'dimensions'>;
|
||||
params: any;
|
||||
}
|
||||
|
||||
export type MetricVisExpressionFunctionDefinition = ExpressionFunctionDefinition<
|
||||
|
@ -194,9 +193,6 @@ export const createMetricVisFn = (): MetricVisExpressionFunctionDefinition => ({
|
|||
},
|
||||
dimensions,
|
||||
},
|
||||
params: {
|
||||
listenOnChange: true,
|
||||
},
|
||||
},
|
||||
};
|
||||
},
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { MetricVisOptions } from './components/metric_vis_options';
|
||||
import { ColorSchemas, colorSchemas, ColorMode } from '../../charts/public';
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { VisTypeDefinition } from '../../visualizations/public';
|
||||
import { AggGroupNames } from '../../data/public';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { VisParams } from './types';
|
||||
|
||||
export const createMetricVisTypeDefinition = (): BaseVisTypeOptions => ({
|
||||
export const createMetricVisTypeDefinition = (): VisTypeDefinition<VisParams> => ({
|
||||
name: 'metric',
|
||||
title: i18n.translate('visTypeMetric.metricTitle', { defaultMessage: 'Metric' }),
|
||||
icon: 'visMetric',
|
||||
|
@ -110,4 +111,5 @@ export const createMetricVisTypeDefinition = (): BaseVisTypeOptions => ({
|
|||
},
|
||||
],
|
||||
},
|
||||
requiresSearch: true,
|
||||
});
|
||||
|
|
|
@ -6,14 +6,17 @@
|
|||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { TimefilterContract } from 'src/plugins/data/public';
|
||||
import { Vis } from 'src/plugins/visualizations/public';
|
||||
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { Vis } from '../../visualizations/public';
|
||||
import { VisParams } from './types';
|
||||
|
||||
describe('metric vis toExpressionAst function', () => {
|
||||
let vis: Vis;
|
||||
let vis: Vis<VisParams>;
|
||||
|
||||
beforeEach(() => {
|
||||
vis = {
|
||||
vis = ({
|
||||
isHierarchical: () => false,
|
||||
type: {},
|
||||
params: {
|
||||
|
@ -26,18 +29,22 @@ describe('metric vis toExpressionAst function', () => {
|
|||
aggs: [],
|
||||
} as any,
|
||||
},
|
||||
} as any;
|
||||
} as unknown) as Vis<VisParams>;
|
||||
});
|
||||
|
||||
it('without params', () => {
|
||||
vis.params = { metric: {} };
|
||||
const actual = toExpressionAst(vis, {});
|
||||
vis.params = { metric: {} } as VisParams;
|
||||
const actual = toExpressionAst(vis, {
|
||||
timefilter: {} as TimefilterContract,
|
||||
});
|
||||
expect(actual).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('with percentage mode should have percentage format', () => {
|
||||
vis.params = { metric: { percentageMode: true } };
|
||||
const actual = toExpressionAst(vis, {});
|
||||
vis.params = { metric: { percentageMode: true } } as VisParams;
|
||||
const actual = toExpressionAst(vis, {
|
||||
timefilter: {} as TimefilterContract,
|
||||
});
|
||||
expect(actual).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { getVisSchemas, SchemaConfig, Vis } from '../../visualizations/public';
|
||||
import { getVisSchemas, SchemaConfig, VisToExpressionAst } from '../../visualizations/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||
import { MetricVisExpressionFunctionDefinition } from './metric_vis_fn';
|
||||
import {
|
||||
EsaggsExpressionFunctionDefinition,
|
||||
IndexPatternLoadExpressionFunctionDefinition,
|
||||
} from '../../data/public';
|
||||
import { VisParams } from './types';
|
||||
|
||||
const prepareDimension = (params: SchemaConfig) => {
|
||||
const visdimension = buildExpressionFunction('visdimension', { accessor: params.accessor });
|
||||
|
@ -26,7 +27,7 @@ const prepareDimension = (params: SchemaConfig) => {
|
|||
return buildExpression([visdimension]);
|
||||
};
|
||||
|
||||
export const toExpressionAst = (vis: Vis, params: any) => {
|
||||
export const toExpressionAst: VisToExpressionAst<VisParams> = (vis, params) => {
|
||||
const esaggs = buildExpressionFunction<EsaggsExpressionFunctionDefinition>('esaggs', {
|
||||
index: buildExpression([
|
||||
buildExpressionFunction<IndexPatternLoadExpressionFunctionDefinition>('indexPatternLoad', {
|
||||
|
@ -34,7 +35,7 @@ export const toExpressionAst = (vis: Vis, params: any) => {
|
|||
}),
|
||||
]),
|
||||
metricsAtAllLevels: vis.isHierarchical(),
|
||||
partialRows: vis.params.showPartialRows || false,
|
||||
partialRows: false,
|
||||
aggs: vis.data.aggs!.aggs.map((agg) => buildExpression(agg.toExpressionAst())),
|
||||
});
|
||||
|
||||
|
@ -65,7 +66,7 @@ export const toExpressionAst = (vis: Vis, params: any) => {
|
|||
colorMode: metricColorMode,
|
||||
useRanges,
|
||||
invertColors,
|
||||
showLabels: labels && labels.show,
|
||||
showLabels: labels?.show ?? false,
|
||||
});
|
||||
|
||||
if (style) {
|
||||
|
|
|
@ -12,13 +12,9 @@ import { EuiIconTip, EuiPanel } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { search } from '../../../data/public';
|
||||
import {
|
||||
SwitchOption,
|
||||
SelectOption,
|
||||
NumberInputOption,
|
||||
VisOptionsProps,
|
||||
} from '../../../vis_default_editor/public';
|
||||
import { SwitchOption, SelectOption, NumberInputOption } from '../../../vis_default_editor/public';
|
||||
import { TableVisParams } from '../../common';
|
||||
import { totalAggregations } from './utils';
|
||||
|
||||
|
@ -29,7 +25,7 @@ function TableOptions({
|
|||
stateParams,
|
||||
setValidity,
|
||||
setValue,
|
||||
}: VisOptionsProps<TableVisParams>) {
|
||||
}: VisEditorOptionsProps<TableVisParams>) {
|
||||
const percentageColumns = useMemo(
|
||||
() => [
|
||||
{
|
||||
|
|
|
@ -8,12 +8,13 @@
|
|||
|
||||
import React, { lazy, Suspense } from 'react';
|
||||
import { EuiLoadingSpinner } from '@elastic/eui';
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { TableVisParams } from '../../common';
|
||||
|
||||
const TableOptionsComponent = lazy(() => import('./table_vis_options'));
|
||||
|
||||
export const TableOptions = (props: VisOptionsProps<TableVisParams>) => (
|
||||
export const TableOptions = (props: VisEditorOptionsProps<TableVisParams>) => (
|
||||
<Suspense fallback={<EuiLoadingSpinner />}>
|
||||
<TableOptionsComponent {...props} />
|
||||
</Suspense>
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AggGroupNames } from '../../../data/public';
|
||||
import { BaseVisTypeOptions } from '../../../visualizations/public';
|
||||
import { VisTypeDefinition } from '../../../visualizations/public';
|
||||
|
||||
import { TableOptions } from '../components/table_vis_options_lazy';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '../../../visualizations/public';
|
||||
import { TableVisParams, VIS_TYPE_TABLE } from '../../common';
|
||||
import { toExpressionAst } from '../to_ast';
|
||||
|
||||
export const tableVisLegacyTypeDefinition: BaseVisTypeOptions<TableVisParams> = {
|
||||
export const tableVisLegacyTypeDefinition: VisTypeDefinition<TableVisParams> = {
|
||||
name: VIS_TYPE_TABLE,
|
||||
title: i18n.translate('visTypeTable.tableVisTitle', {
|
||||
defaultMessage: 'Data table',
|
||||
|
@ -81,4 +81,5 @@ export const tableVisLegacyTypeDefinition: BaseVisTypeOptions<TableVisParams> =
|
|||
},
|
||||
toExpressionAst,
|
||||
hierarchicalData: (vis) => vis.params.showPartialRows || vis.params.showMetricsAtAllLevels,
|
||||
requiresSearch: true,
|
||||
};
|
||||
|
|
|
@ -7,15 +7,14 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AggGroupNames } from '../../data/public';
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
|
||||
import { AggGroupNames } from '../../data/public';
|
||||
import { VIS_EVENT_TO_TRIGGER, VisTypeDefinition } from '../../visualizations/public';
|
||||
import { TableVisParams, VIS_TYPE_TABLE } from '../common';
|
||||
import { TableOptions } from './components/table_vis_options_lazy';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
|
||||
export const tableVisTypeDefinition: BaseVisTypeOptions<TableVisParams> = {
|
||||
export const tableVisTypeDefinition: VisTypeDefinition<TableVisParams> = {
|
||||
name: VIS_TYPE_TABLE,
|
||||
title: i18n.translate('visTypeTable.tableVisTitle', {
|
||||
defaultMessage: 'Data table',
|
||||
|
@ -78,4 +77,5 @@ export const tableVisTypeDefinition: BaseVisTypeOptions<TableVisParams> = {
|
|||
},
|
||||
toExpressionAst,
|
||||
hierarchicalData: (vis) => vis.params.showPartialRows || vis.params.showMetricsAtAllLevels,
|
||||
requiresSearch: true,
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
IndexPatternLoadExpressionFunctionDefinition,
|
||||
} from '../../data/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||
import { getVisSchemas, Vis, BuildPipelineParams } from '../../visualizations/public';
|
||||
import { getVisSchemas, VisToExpressionAst } from '../../visualizations/public';
|
||||
import { TableVisParams } from '../common';
|
||||
import { TableExpressionFunctionDefinition } from './table_vis_fn';
|
||||
import { TableVisConfig } from './types';
|
||||
|
@ -41,7 +41,7 @@ const buildTableVisConfig = (
|
|||
return visConfig;
|
||||
};
|
||||
|
||||
export const toExpressionAst = (vis: Vis<TableVisParams>, params: BuildPipelineParams) => {
|
||||
export const toExpressionAst: VisToExpressionAst<TableVisParams> = (vis, params) => {
|
||||
const esaggs = buildExpressionFunction<EsaggsExpressionFunctionDefinition>('esaggs', {
|
||||
index: buildExpression([
|
||||
buildExpressionFunction<IndexPatternLoadExpressionFunctionDefinition>('indexPatternLoad', {
|
||||
|
|
|
@ -9,11 +9,12 @@
|
|||
import React from 'react';
|
||||
import { EuiPanel } from '@elastic/eui';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { VisOptionsProps, SelectOption, SwitchOption } from '../../../vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { SelectOption, SwitchOption } from '../../../vis_default_editor/public';
|
||||
import { ValidatedDualRange } from '../../../kibana_react/public';
|
||||
import { TagCloudVisParams } from '../types';
|
||||
|
||||
function TagCloudOptions({ stateParams, setValue, vis }: VisOptionsProps<TagCloudVisParams>) {
|
||||
function TagCloudOptions({ stateParams, setValue, vis }: VisEditorOptionsProps<TagCloudVisParams>) {
|
||||
const handleFontSizeChange = ([minFontSize, maxFontSize]: [string | number, string | number]) => {
|
||||
setValue('minFontSize', Number(minFontSize));
|
||||
setValue('maxFontSize', Number(maxFontSize));
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { AggGroupNames } from '../../data/public';
|
||||
import { VIS_EVENT_TO_TRIGGER } from '../../visualizations/public';
|
||||
|
||||
import { TagCloudOptions } from './components/tag_cloud_options';
|
||||
|
@ -78,7 +79,7 @@ export const tagCloudVisTypeDefinition = {
|
|||
optionsTemplate: TagCloudOptions,
|
||||
schemas: [
|
||||
{
|
||||
group: 'metrics',
|
||||
group: AggGroupNames.Metrics,
|
||||
name: 'metric',
|
||||
title: i18n.translate('visTypeTagCloud.vis.schemas.metricTitle', {
|
||||
defaultMessage: 'Tag size',
|
||||
|
@ -96,7 +97,7 @@ export const tagCloudVisTypeDefinition = {
|
|||
defaults: [{ schema: 'metric', type: 'count' }],
|
||||
},
|
||||
{
|
||||
group: 'buckets',
|
||||
group: AggGroupNames.Buckets,
|
||||
name: 'segment',
|
||||
title: i18n.translate('visTypeTagCloud.vis.schemas.segmentTitle', {
|
||||
defaultMessage: 'Tags',
|
||||
|
@ -107,4 +108,5 @@ export const tagCloudVisTypeDefinition = {
|
|||
},
|
||||
],
|
||||
},
|
||||
requiresSearch: true,
|
||||
};
|
||||
|
|
|
@ -11,7 +11,7 @@ import {
|
|||
IndexPatternLoadExpressionFunctionDefinition,
|
||||
} from '../../data/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||
import { getVisSchemas, SchemaConfig, Vis, BuildPipelineParams } from '../../visualizations/public';
|
||||
import { getVisSchemas, SchemaConfig, VisToExpressionAst } from '../../visualizations/public';
|
||||
import { TagcloudExpressionFunctionDefinition } from './tag_cloud_fn';
|
||||
import { TagCloudVisParams } from './types';
|
||||
|
||||
|
@ -26,7 +26,7 @@ const prepareDimension = (params: SchemaConfig) => {
|
|||
return buildExpression([visdimension]);
|
||||
};
|
||||
|
||||
export const toExpressionAst = (vis: Vis<TagCloudVisParams>, params: BuildPipelineParams) => {
|
||||
export const toExpressionAst: VisToExpressionAst<TagCloudVisParams> = (vis, params) => {
|
||||
const esaggs = buildExpressionFunction<EsaggsExpressionFunctionDefinition>('esaggs', {
|
||||
index: buildExpression([
|
||||
buildExpressionFunction<IndexPatternLoadExpressionFunctionDefinition>('indexPatternLoad', {
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { EuiPanel } from '@elastic/eui';
|
||||
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { KibanaContextProvider } from '../../kibana_react/public';
|
||||
|
||||
import { TimelionVisParams } from './timelion_vis_fn';
|
||||
|
@ -18,7 +18,7 @@ import { TimelionVisDependencies } from './plugin';
|
|||
|
||||
import './timelion_options.scss';
|
||||
|
||||
export type TimelionOptionsProps = VisOptionsProps<TimelionVisParams>;
|
||||
export type TimelionOptionsProps = VisEditorOptionsProps<TimelionVisParams>;
|
||||
|
||||
function TimelionOptions({
|
||||
services,
|
||||
|
|
|
@ -10,7 +10,6 @@ import React, { lazy } from 'react';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { DefaultEditorSize } from '../../vis_default_editor/public';
|
||||
import { getTimelionRequestHandler } from './helpers/timelion_request_handler';
|
||||
import { TimelionOptionsProps } from './timelion_options';
|
||||
import { TimelionVisDependencies } from './plugin';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
|
@ -22,8 +21,6 @@ const TimelionOptions = lazy(() => import('./timelion_options'));
|
|||
export const TIMELION_VIS_NAME = 'timelion';
|
||||
|
||||
export function getTimelionVisDefinition(dependencies: TimelionVisDependencies) {
|
||||
const timelionRequestHandler = getTimelionRequestHandler(dependencies);
|
||||
|
||||
// return the visType object, which kibana will use to display and configure new
|
||||
// Vis object of this type.
|
||||
return {
|
||||
|
@ -45,9 +42,7 @@ export function getTimelionVisDefinition(dependencies: TimelionVisDependencies)
|
|||
),
|
||||
defaultSize: DefaultEditorSize.MEDIUM,
|
||||
},
|
||||
requestHandler: timelionRequestHandler,
|
||||
toExpressionAst,
|
||||
responseHandler: 'none',
|
||||
inspectorAdapters: {},
|
||||
getSupportedTriggers: () => {
|
||||
return [VIS_EVENT_TO_TRIGGER.applyFilter];
|
||||
|
@ -57,5 +52,6 @@ export function getTimelionVisDefinition(dependencies: TimelionVisDependencies)
|
|||
showQueryBar: false,
|
||||
showFilterBar: false,
|
||||
},
|
||||
requiresSearch: true,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ import hjson from 'hjson';
|
|||
import 'brace/mode/hjson';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { getNotifications } from '../services';
|
||||
import { VisParams } from '../vega_fn';
|
||||
import { VegaHelpMenu } from './vega_help_menu';
|
||||
|
@ -55,7 +55,7 @@ function format(
|
|||
}
|
||||
}
|
||||
|
||||
function VegaVisEditor({ stateParams, setValue }: VisOptionsProps<VisParams>) {
|
||||
function VegaVisEditor({ stateParams, setValue }: VisEditorOptionsProps<VisParams>) {
|
||||
const onChange = useCallback(
|
||||
(value: string) => {
|
||||
setValue('spec', value);
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
|
||||
import React, { lazy } from 'react';
|
||||
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { VisParams } from '../vega_fn';
|
||||
|
||||
const VegaVisEditor = lazy(() => import('./vega_vis_editor'));
|
||||
|
||||
export const VegaVisEditorComponent = (props: VisOptionsProps<VisParams>) => (
|
||||
export const VegaVisEditorComponent = (props: VisEditorOptionsProps<VisParams>) => (
|
||||
<VegaVisEditor {...props} />
|
||||
);
|
||||
|
|
|
@ -84,7 +84,7 @@ export class VegaPlugin implements Plugin<Promise<void>, void> {
|
|||
expressions.registerFunction(() => createVegaFn(visualizationDependencies));
|
||||
expressions.registerRenderer(getVegaVisRenderer(visualizationDependencies));
|
||||
|
||||
visualizations.createBaseVisualization(createVegaTypeDefinition(visualizationDependencies));
|
||||
visualizations.createBaseVisualization(createVegaTypeDefinition());
|
||||
}
|
||||
|
||||
public start(core: CoreStart, { data }: VegaPluginStartDependencies) {
|
||||
|
|
|
@ -8,16 +8,13 @@
|
|||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { parse } from 'hjson';
|
||||
import type { BaseVisTypeOptions } from 'src/plugins/visualizations/public';
|
||||
|
||||
import { DefaultEditorSize } from '../../vis_default_editor/public';
|
||||
import type { VegaVisualizationDependencies } from './plugin';
|
||||
import { VIS_EVENT_TO_TRIGGER, VisGroups, VisTypeDefinition } from '../../visualizations/public';
|
||||
|
||||
import { createVegaRequestHandler } from './vega_request_handler';
|
||||
import { getDefaultSpec } from './default_spec';
|
||||
import { extractIndexPatternsFromSpec } from './lib/extract_index_pattern';
|
||||
import { createInspectorAdapters } from './vega_inspector';
|
||||
import { VIS_EVENT_TO_TRIGGER, VisGroups } from '../../visualizations/public';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { getInfoMessage } from './components/experimental_map_vis_info';
|
||||
import { VegaVisEditorComponent } from './components/vega_vis_editor_lazy';
|
||||
|
@ -25,11 +22,7 @@ import { VegaVisEditorComponent } from './components/vega_vis_editor_lazy';
|
|||
import type { VegaSpec } from './data_model/types';
|
||||
import type { VisParams } from './vega_fn';
|
||||
|
||||
export const createVegaTypeDefinition = (
|
||||
dependencies: VegaVisualizationDependencies
|
||||
): BaseVisTypeOptions<VisParams> => {
|
||||
const requestHandler = createVegaRequestHandler(dependencies);
|
||||
|
||||
export const createVegaTypeDefinition = (): VisTypeDefinition<VisParams> => {
|
||||
return {
|
||||
name: 'vega',
|
||||
title: 'Vega',
|
||||
|
@ -52,7 +45,6 @@ export const createVegaTypeDefinition = (
|
|||
enableAutoApply: true,
|
||||
defaultSize: DefaultEditorSize.MEDIUM,
|
||||
},
|
||||
requestHandler,
|
||||
toExpressionAst,
|
||||
options: {
|
||||
showIndexSelection: false,
|
||||
|
@ -73,5 +65,9 @@ export const createVegaTypeDefinition = (
|
|||
return [];
|
||||
},
|
||||
inspectorAdapters: createInspectorAdapters,
|
||||
/**
|
||||
* This is necessary for showing actions bar in top of vega editor
|
||||
*/
|
||||
requiresSearch: true,
|
||||
};
|
||||
};
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
*/
|
||||
|
||||
import { xyVisTypes } from '../../vis_type_xy/public';
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { VisTypeDefinition } from '../../visualizations/public';
|
||||
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
export const areaVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
...(xyVisTypes.area() as BaseVisTypeOptions<BasicVislibParams>),
|
||||
export const areaVisTypeDefinition = {
|
||||
...xyVisTypes.area(),
|
||||
toExpressionAst,
|
||||
visualization: undefined,
|
||||
};
|
||||
} as VisTypeDefinition<BasicVislibParams>;
|
||||
|
|
|
@ -9,20 +9,20 @@
|
|||
import React, { useCallback } from 'react';
|
||||
import { EuiSpacer } from '@elastic/eui';
|
||||
|
||||
import { VisOptionsProps } from 'src/plugins/vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { GaugeVisParams } from '../../../gauge';
|
||||
import { RangesPanel } from './ranges_panel';
|
||||
import { StylePanel } from './style_panel';
|
||||
import { LabelsPanel } from './labels_panel';
|
||||
|
||||
export type GaugeOptionsInternalProps = VisOptionsProps<GaugeVisParams> & {
|
||||
export type GaugeOptionsInternalProps = VisEditorOptionsProps<GaugeVisParams> & {
|
||||
setGaugeValue: <T extends keyof GaugeVisParams['gauge']>(
|
||||
paramName: T,
|
||||
value: GaugeVisParams['gauge'][T]
|
||||
) => void;
|
||||
};
|
||||
|
||||
function GaugeOptions(props: VisOptionsProps<GaugeVisParams>) {
|
||||
function GaugeOptions(props: VisEditorOptionsProps<GaugeVisParams>) {
|
||||
const { stateParams, setValue } = props;
|
||||
|
||||
const setGaugeValue: GaugeOptionsInternalProps['setGaugeValue'] = useCallback(
|
||||
|
|
|
@ -12,9 +12,9 @@ import { EuiPanel, EuiSpacer, EuiTitle } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { ValueAxis } from '../../../../../vis_type_xy/public';
|
||||
import {
|
||||
VisOptionsProps,
|
||||
BasicOptions,
|
||||
SelectOption,
|
||||
SwitchOption,
|
||||
|
@ -28,7 +28,7 @@ import {
|
|||
import { HeatmapVisParams } from '../../../heatmap';
|
||||
import { LabelsPanel } from './labels_panel';
|
||||
|
||||
function HeatmapOptions(props: VisOptionsProps<HeatmapVisParams>) {
|
||||
function HeatmapOptions(props: VisEditorOptionsProps<HeatmapVisParams>) {
|
||||
const { stateParams, vis, uiState, setValue, setValidity, setTouched } = props;
|
||||
const [valueAxis] = stateParams.valueAxes;
|
||||
const isColorsNumberInvalid = stateParams.colorsNumber < 2 || stateParams.colorsNumber > 10;
|
||||
|
|
|
@ -12,7 +12,8 @@ import { EuiColorPicker, EuiFormRow, EuiPanel, EuiSpacer, EuiTitle } from '@elas
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { VisOptionsProps, SwitchOption } from '../../../../../vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { SwitchOption } from '../../../../../vis_default_editor/public';
|
||||
import { ValueAxis } from '../../../../../vis_type_xy/public';
|
||||
|
||||
import { HeatmapVisParams } from '../../../heatmap';
|
||||
|
@ -21,7 +22,7 @@ const VERTICAL_ROTATION = 270;
|
|||
|
||||
interface LabelsPanelProps {
|
||||
valueAxis: ValueAxis;
|
||||
setValue: VisOptionsProps<HeatmapVisParams>['setValue'];
|
||||
setValue: VisEditorOptionsProps<HeatmapVisParams>['setValue'];
|
||||
}
|
||||
|
||||
function LabelsPanel({ valueAxis, setValue }: LabelsPanelProps) {
|
||||
|
|
|
@ -8,8 +8,7 @@
|
|||
|
||||
import React, { lazy } from 'react';
|
||||
|
||||
import { VisOptionsProps } from '../../../../vis_default_editor/public';
|
||||
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { GaugeVisParams } from '../../gauge';
|
||||
import { PieVisParams } from '../../pie';
|
||||
import { HeatmapVisParams } from '../../heatmap';
|
||||
|
@ -18,12 +17,14 @@ const GaugeOptionsLazy = lazy(() => import('./gauge'));
|
|||
const PieOptionsLazy = lazy(() => import('./pie'));
|
||||
const HeatmapOptionsLazy = lazy(() => import('./heatmap'));
|
||||
|
||||
export const GaugeOptions = (props: VisOptionsProps<GaugeVisParams>) => (
|
||||
export const GaugeOptions = (props: VisEditorOptionsProps<GaugeVisParams>) => (
|
||||
<GaugeOptionsLazy {...props} />
|
||||
);
|
||||
|
||||
export const PieOptions = (props: VisOptionsProps<PieVisParams>) => <PieOptionsLazy {...props} />;
|
||||
export const PieOptions = (props: VisEditorOptionsProps<PieVisParams>) => (
|
||||
<PieOptionsLazy {...props} />
|
||||
);
|
||||
|
||||
export const HeatmapOptions = (props: VisOptionsProps<HeatmapVisParams>) => (
|
||||
export const HeatmapOptions = (props: VisEditorOptionsProps<HeatmapVisParams>) => (
|
||||
<HeatmapOptionsLazy {...props} />
|
||||
);
|
||||
|
|
|
@ -12,12 +12,13 @@ import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui';
|
|||
import { i18n } from '@kbn/i18n';
|
||||
import { FormattedMessage } from '@kbn/i18n/react';
|
||||
|
||||
import { BasicOptions, SwitchOption, VisOptionsProps } from '../../../../vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { BasicOptions, SwitchOption } from '../../../../vis_default_editor/public';
|
||||
import { TruncateLabelsOption } from '../../../../vis_type_xy/public';
|
||||
|
||||
import { PieVisParams } from '../../pie';
|
||||
|
||||
function PieOptions(props: VisOptionsProps<PieVisParams>) {
|
||||
function PieOptions(props: VisEditorOptionsProps<PieVisParams>) {
|
||||
const { stateParams, setValue } = props;
|
||||
const setLabels = <T extends keyof PieVisParams['labels']>(
|
||||
paramName: T,
|
||||
|
|
|
@ -11,9 +11,9 @@ import { i18n } from '@kbn/i18n';
|
|||
import { ColorMode, ColorSchemas, ColorSchemaParams, Labels, Style } from '../../charts/public';
|
||||
import { RangeValues } from '../../vis_default_editor/public';
|
||||
import { AggGroupNames } from '../../data/public';
|
||||
import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../visualizations/public';
|
||||
import { VisTypeDefinition, VIS_EVENT_TO_TRIGGER } from '../../visualizations/public';
|
||||
|
||||
import { Alignment, GaugeType, BasicVislibParams, VislibChartType } from './types';
|
||||
import { Alignment, GaugeType, VislibChartType } from './types';
|
||||
import { getGaugeCollections } from './editor';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { GaugeOptions } from './editor/components';
|
||||
|
@ -46,7 +46,7 @@ export interface GaugeVisParams {
|
|||
gauge: Gauge;
|
||||
}
|
||||
|
||||
export const gaugeVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
export const gaugeVisTypeDefinition: VisTypeDefinition<GaugeVisParams> = {
|
||||
name: 'gauge',
|
||||
title: i18n.translate('visTypeVislib.gauge.gaugeTitle', { defaultMessage: 'Gauge' }),
|
||||
icon: 'visGauge',
|
||||
|
@ -135,5 +135,5 @@ export const gaugeVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
|||
},
|
||||
],
|
||||
},
|
||||
useCustomNoDataScreen: true,
|
||||
requiresSearch: true,
|
||||
};
|
||||
|
|
|
@ -10,13 +10,14 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { AggGroupNames } from '../../data/public';
|
||||
import { ColorMode, ColorSchemas } from '../../charts/public';
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { VisTypeDefinition } from '../../visualizations/public';
|
||||
|
||||
import { getGaugeCollections, GaugeOptions } from './editor';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { GaugeType, BasicVislibParams } from './types';
|
||||
import { GaugeType } from './types';
|
||||
import { GaugeVisParams } from './gauge';
|
||||
|
||||
export const goalVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
export const goalVisTypeDefinition: VisTypeDefinition<GaugeVisParams> = {
|
||||
name: 'goal',
|
||||
title: i18n.translate('visTypeVislib.goal.goalTitle', { defaultMessage: 'Goal' }),
|
||||
icon: 'visGoal',
|
||||
|
@ -98,5 +99,5 @@ export const goalVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
|||
},
|
||||
],
|
||||
},
|
||||
useCustomNoDataScreen: true,
|
||||
requiresSearch: true,
|
||||
};
|
||||
|
|
|
@ -12,12 +12,12 @@ import { Position } from '@elastic/charts';
|
|||
import { RangeValues } from '../../vis_default_editor/public';
|
||||
import { AggGroupNames } from '../../data/public';
|
||||
import { ColorSchemas, ColorSchemaParams } from '../../charts/public';
|
||||
import { VIS_EVENT_TO_TRIGGER, BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { VIS_EVENT_TO_TRIGGER, VisTypeDefinition } from '../../visualizations/public';
|
||||
import { ValueAxis, ScaleType, AxisType } from '../../vis_type_xy/public';
|
||||
|
||||
import { HeatmapOptions, getHeatmapCollections } from './editor';
|
||||
import { TimeMarker } from './vislib/visualizations/time_marker';
|
||||
import { CommonVislibParams, BasicVislibParams, VislibChartType } from './types';
|
||||
import { CommonVislibParams, VislibChartType } from './types';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
|
||||
export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaParams {
|
||||
|
@ -32,7 +32,7 @@ export interface HeatmapVisParams extends CommonVislibParams, ColorSchemaParams
|
|||
times: TimeMarker[];
|
||||
}
|
||||
|
||||
export const heatmapVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
export const heatmapVisTypeDefinition: VisTypeDefinition<HeatmapVisParams> = {
|
||||
name: 'heatmap',
|
||||
title: i18n.translate('visTypeVislib.heatmap.heatmapTitle', { defaultMessage: 'Heat map' }),
|
||||
icon: 'heatmap',
|
||||
|
@ -127,4 +127,5 @@ export const heatmapVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
|||
},
|
||||
],
|
||||
},
|
||||
requiresSearch: true,
|
||||
};
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
*/
|
||||
|
||||
import { xyVisTypes } from '../../vis_type_xy/public';
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { VisTypeDefinition } from '../../visualizations/public';
|
||||
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
export const histogramVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
...(xyVisTypes.histogram() as BaseVisTypeOptions<BasicVislibParams>),
|
||||
export const histogramVisTypeDefinition = {
|
||||
...xyVisTypes.histogram(),
|
||||
toExpressionAst,
|
||||
visualization: undefined,
|
||||
};
|
||||
} as VisTypeDefinition<BasicVislibParams>;
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
*/
|
||||
|
||||
import { xyVisTypes } from '../../vis_type_xy/public';
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { VisTypeDefinition } from '../../visualizations/public';
|
||||
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
export const horizontalBarVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
...(xyVisTypes.horizontalBar() as BaseVisTypeOptions<BasicVislibParams>),
|
||||
export const horizontalBarVisTypeDefinition = {
|
||||
...xyVisTypes.horizontalBar(),
|
||||
toExpressionAst,
|
||||
visualization: undefined,
|
||||
};
|
||||
} as VisTypeDefinition<BasicVislibParams>;
|
||||
|
|
|
@ -7,13 +7,12 @@
|
|||
*/
|
||||
|
||||
import { xyVisTypes } from '../../vis_type_xy/public';
|
||||
import { BaseVisTypeOptions } from '../../visualizations/public';
|
||||
import { VisTypeDefinition } from '../../visualizations/public';
|
||||
|
||||
import { toExpressionAst } from './to_ast';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
export const lineVisTypeDefinition: BaseVisTypeOptions<BasicVislibParams> = {
|
||||
...(xyVisTypes.line() as BaseVisTypeOptions<BasicVislibParams>),
|
||||
export const lineVisTypeDefinition = {
|
||||
...xyVisTypes.line(),
|
||||
toExpressionAst,
|
||||
visualization: undefined,
|
||||
};
|
||||
} as VisTypeDefinition<BasicVislibParams>;
|
||||
|
|
|
@ -10,7 +10,7 @@ import { i18n } from '@kbn/i18n';
|
|||
import { Position } from '@elastic/charts';
|
||||
|
||||
import { AggGroupNames } from '../../data/public';
|
||||
import { BaseVisTypeOptions, VIS_EVENT_TO_TRIGGER } from '../../visualizations/public';
|
||||
import { VisTypeDefinition, VIS_EVENT_TO_TRIGGER } from '../../visualizations/public';
|
||||
import { getPositions } from '../../vis_type_xy/public';
|
||||
|
||||
import { CommonVislibParams } from './types';
|
||||
|
@ -28,7 +28,7 @@ export interface PieVisParams extends CommonVislibParams {
|
|||
};
|
||||
}
|
||||
|
||||
export const pieVisTypeDefinition: BaseVisTypeOptions<PieVisParams> = {
|
||||
export const pieVisTypeDefinition: VisTypeDefinition<PieVisParams> = {
|
||||
name: 'pie',
|
||||
title: i18n.translate('visTypeVislib.pie.pieTitle', { defaultMessage: 'Pie' }),
|
||||
icon: 'visPie',
|
||||
|
@ -93,5 +93,5 @@ export const pieVisTypeDefinition: BaseVisTypeOptions<PieVisParams> = {
|
|||
],
|
||||
},
|
||||
hierarchicalData: true,
|
||||
responseHandler: 'vislib_slices',
|
||||
requiresSearch: true,
|
||||
};
|
||||
|
|
|
@ -8,7 +8,12 @@
|
|||
|
||||
import moment from 'moment';
|
||||
|
||||
import { VisToExpressionAst, getVisSchemas } from '../../visualizations/public';
|
||||
import {
|
||||
Vis,
|
||||
VisToExpressionAstParams,
|
||||
getVisSchemas,
|
||||
VisParams,
|
||||
} from '../../visualizations/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
|
||||
import type { Dimensions, DateHistogramParams, HistogramParams } from '../../vis_type_xy/public';
|
||||
import { BUCKET_TYPES } from '../../data/public';
|
||||
|
@ -17,7 +22,10 @@ import { vislibVisName, VisTypeVislibExpressionFunctionDefinition } from './vis_
|
|||
import { BasicVislibParams, VislibChartType } from './types';
|
||||
import { getEsaggsFn } from './to_ast_esaggs';
|
||||
|
||||
export const toExpressionAst: VisToExpressionAst<BasicVislibParams> = async (vis, params) => {
|
||||
export const toExpressionAst = async <TVisParams extends VisParams>(
|
||||
vis: Vis<TVisParams>,
|
||||
params: VisToExpressionAstParams
|
||||
) => {
|
||||
const schemas = getVisSchemas(vis, params);
|
||||
const dimensions: Dimensions = {
|
||||
x: schemas.segment ? schemas.segment[0] : null,
|
||||
|
@ -58,9 +66,11 @@ export const toExpressionAst: VisToExpressionAst<BasicVislibParams> = async (vis
|
|||
|
||||
(dimensions.y || []).forEach((yDimension) => {
|
||||
const yAgg = responseAggs.filter(({ enabled }) => enabled)[yDimension.accessor];
|
||||
const seriesParam = (visConfig.seriesParams || []).find((param) => param.data.id === yAgg.id);
|
||||
const seriesParam = ((visConfig.seriesParams as BasicVislibParams['seriesParams']) || []).find(
|
||||
(param) => param.data.id === yAgg.id
|
||||
);
|
||||
if (seriesParam) {
|
||||
const usedValueAxis = (visConfig.valueAxes || []).find(
|
||||
const usedValueAxis = ((visConfig.valueAxes as BasicVislibParams['valueAxes']) || []).find(
|
||||
(valueAxis) => valueAxis.id === seriesParam.valueAxis
|
||||
);
|
||||
if (usedValueAxis?.scale.mode === 'percentage') {
|
||||
|
@ -72,13 +82,11 @@ export const toExpressionAst: VisToExpressionAst<BasicVislibParams> = async (vis
|
|||
}
|
||||
});
|
||||
|
||||
visConfig.dimensions = dimensions;
|
||||
|
||||
const visTypeVislib = buildExpressionFunction<VisTypeVislibExpressionFunctionDefinition>(
|
||||
vislibVisName,
|
||||
{
|
||||
type: vis.type.name as Exclude<VislibChartType, 'pie'>,
|
||||
visConfig: JSON.stringify(visConfig),
|
||||
visConfig: JSON.stringify({ ...visConfig, dimensions }),
|
||||
}
|
||||
);
|
||||
|
||||
|
|
|
@ -13,16 +13,13 @@ import {
|
|||
IndexPatternLoadExpressionFunctionDefinition,
|
||||
} from '../../data/public';
|
||||
|
||||
import { PieVisParams } from './pie';
|
||||
import { BasicVislibParams } from './types';
|
||||
|
||||
/**
|
||||
* Get esaggs expressions function
|
||||
* TODO: replace this with vis.data.aggs!.toExpressionAst();
|
||||
* https://github.com/elastic/kibana/issues/61768
|
||||
* @param vis
|
||||
*/
|
||||
export function getEsaggsFn(vis: Vis<PieVisParams> | Vis<BasicVislibParams>) {
|
||||
export function getEsaggsFn<T>(vis: Vis<T>) {
|
||||
return buildExpressionFunction<EsaggsExpressionFunctionDefinition>('esaggs', {
|
||||
index: buildExpression([
|
||||
buildExpressionFunction<IndexPatternLoadExpressionFunctionDefinition>('indexPatternLoad', {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { VisTypeDefinition } from 'src/plugins/visualizations/public';
|
||||
import { histogramVisTypeDefinition } from './histogram';
|
||||
import { lineVisTypeDefinition } from './line';
|
||||
import { areaVisTypeDefinition } from './area';
|
||||
|
@ -16,7 +17,7 @@ import { goalVisTypeDefinition } from './goal';
|
|||
|
||||
export { pieVisTypeDefinition } from './pie';
|
||||
|
||||
export const visLibVisTypeDefinitions = [
|
||||
export const visLibVisTypeDefinitions: Array<VisTypeDefinition<any>> = [
|
||||
histogramVisTypeDefinition,
|
||||
lineVisTypeDefinition,
|
||||
areaVisTypeDefinition,
|
||||
|
@ -26,7 +27,7 @@ export const visLibVisTypeDefinitions = [
|
|||
goalVisTypeDefinition,
|
||||
];
|
||||
|
||||
export const convertedTypeDefinitions = [
|
||||
export const convertedTypeDefinitions: Array<VisTypeDefinition<any>> = [
|
||||
heatmapVisTypeDefinition,
|
||||
gaugeVisTypeDefinition,
|
||||
goalVisTypeDefinition,
|
||||
|
|
|
@ -143,39 +143,38 @@ export const getRotateOptions = () => [
|
|||
},
|
||||
];
|
||||
|
||||
export const getFittingFunctions = () =>
|
||||
[
|
||||
{
|
||||
value: Fit.None,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.none', {
|
||||
defaultMessage: 'Hide (Do not fill gaps)',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: Fit.Zero,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.zero', {
|
||||
defaultMessage: 'Zero (Fill gaps with zeros)',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: Fit.Linear,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.linear', {
|
||||
defaultMessage: 'Linear (Fill gaps with a line)',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: Fit.Carry,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.carry', {
|
||||
defaultMessage: 'Last (Fill gaps with the last value)',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: Fit.Lookahead,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.lookahead', {
|
||||
defaultMessage: 'Next (Fill gaps with the next value)',
|
||||
}),
|
||||
},
|
||||
] as const;
|
||||
export const getFittingFunctions = () => [
|
||||
{
|
||||
value: Fit.None,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.none', {
|
||||
defaultMessage: 'Hide (Do not fill gaps)',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: Fit.Zero,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.zero', {
|
||||
defaultMessage: 'Zero (Fill gaps with zeros)',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: Fit.Linear,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.linear', {
|
||||
defaultMessage: 'Linear (Fill gaps with a line)',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: Fit.Carry,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.carry', {
|
||||
defaultMessage: 'Last (Fill gaps with the last value)',
|
||||
}),
|
||||
},
|
||||
{
|
||||
value: Fit.Lookahead,
|
||||
text: i18n.translate('visTypeXy.fittingFunctionsTitle.lookahead', {
|
||||
defaultMessage: 'Next (Fill gaps with the next value)',
|
||||
}),
|
||||
},
|
||||
];
|
||||
|
||||
export const getConfigCollections = () => ({
|
||||
legendPositions: getPositions(),
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
import React from 'react';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { VisOptionsProps } from '../../../vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from '../../../visualizations/public';
|
||||
|
||||
import { VisParams } from '../types';
|
||||
import { MetricsAxisOptions, PointSeriesOptions } from './components/options';
|
||||
|
@ -22,7 +22,7 @@ export function getOptionTabs(showElasticChartsOptions = false) {
|
|||
title: i18n.translate('visTypeXy.area.tabs.metricsAxesTitle', {
|
||||
defaultMessage: 'Metrics & axes',
|
||||
}),
|
||||
editor: (props: VisOptionsProps<VisParams>) => (
|
||||
editor: (props: VisEditorOptionsProps<VisParams>) => (
|
||||
<ValidationWrapper {...props} component={MetricsAxisOptions} />
|
||||
),
|
||||
},
|
||||
|
@ -31,7 +31,7 @@ export function getOptionTabs(showElasticChartsOptions = false) {
|
|||
title: i18n.translate('visTypeXy.area.tabs.panelSettingsTitle', {
|
||||
defaultMessage: 'Panel settings',
|
||||
}),
|
||||
editor: (props: VisOptionsProps<VisParams>) => (
|
||||
editor: (props: VisEditorOptionsProps<VisParams>) => (
|
||||
<ValidationWrapper
|
||||
{...props}
|
||||
extraProps={{
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
|
||||
import React, { useEffect, useState, useCallback } from 'react';
|
||||
|
||||
import { VisOptionsProps } from '../../../../../vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from '../../../../../visualizations/public';
|
||||
|
||||
export interface ValidationVisOptionsProps<T, E = unknown> extends VisOptionsProps<T> {
|
||||
export interface ValidationVisOptionsProps<T, E = unknown> extends VisEditorOptionsProps<T> {
|
||||
setMultipleValidity(paramName: string, isValid: boolean): void;
|
||||
extraProps?: E;
|
||||
}
|
||||
|
||||
interface ValidationWrapperProps<T, E> extends VisOptionsProps<T> {
|
||||
interface ValidationWrapperProps<T, E> extends VisEditorOptionsProps<T> {
|
||||
component: React.ComponentType<ValidationVisOptionsProps<T, E>>;
|
||||
extraProps?: E;
|
||||
}
|
||||
|
|
|
@ -13,11 +13,8 @@ import { FormattedMessage } from '@kbn/i18n/react';
|
|||
import { EuiPanel, EuiTitle, EuiSpacer } from '@elastic/eui';
|
||||
import { Position } from '@elastic/charts';
|
||||
|
||||
import {
|
||||
SelectOption,
|
||||
SwitchOption,
|
||||
VisOptionsProps,
|
||||
} from '../../../../../../vis_default_editor/public';
|
||||
import { VisEditorOptionsProps } from 'src/plugins/visualizations/public';
|
||||
import { SelectOption, SwitchOption } from '../../../../../../vis_default_editor/public';
|
||||
|
||||
import { LabelOptions, SetAxisLabel } from './label_options';
|
||||
import { CategoryAxis } from '../../../../types';
|
||||
|
@ -26,7 +23,7 @@ export interface CategoryAxisPanelProps {
|
|||
axis: CategoryAxis;
|
||||
onPositionChanged: (position: Position) => void;
|
||||
setCategoryAxis: (value: CategoryAxis) => void;
|
||||
vis: VisOptionsProps['vis'];
|
||||
vis: VisEditorOptionsProps['vis'];
|
||||
}
|
||||
|
||||
function CategoryAxisPanel({
|
||||
|
|
|
@ -106,10 +106,7 @@ export const samplePieVis = {
|
|||
},
|
||||
},
|
||||
hidden: false,
|
||||
requestHandler: 'courier',
|
||||
responseHandler: 'vislib_slices',
|
||||
hierarchicalData: true,
|
||||
useCustomNoDataScreen: false,
|
||||
},
|
||||
title: '[Flights] Airline Carrier',
|
||||
description: '',
|
||||
|
@ -126,7 +123,6 @@ export const samplePieVis = {
|
|||
truncate: 100,
|
||||
},
|
||||
},
|
||||
sessionState: {},
|
||||
data: {
|
||||
searchSource: {
|
||||
id: 'data_source1',
|
||||
|
@ -1622,10 +1618,7 @@ export const sampleAreaVis = {
|
|||
},
|
||||
},
|
||||
hidden: false,
|
||||
requestHandler: 'courier',
|
||||
responseHandler: 'none',
|
||||
hierarchicalData: false,
|
||||
useCustomNoDataScreen: false,
|
||||
},
|
||||
title: '[eCommerce] Sales by Category',
|
||||
description: '',
|
||||
|
@ -1762,7 +1755,6 @@ export const sampleAreaVis = {
|
|||
],
|
||||
},
|
||||
},
|
||||
sessionState: {},
|
||||
data: {
|
||||
searchSource: {
|
||||
id: 'data_source1',
|
||||
|
|
|
@ -6,16 +6,11 @@
|
|||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { BaseVisTypeOptions } from '../../../visualizations/public';
|
||||
import { VisTypeDefinition } from '../../../visualizations/public';
|
||||
import { ChartType } from '../../common';
|
||||
|
||||
import { VisParams } from './param';
|
||||
|
||||
export type VisTypeNames = ChartType | 'horizontal_bar';
|
||||
|
||||
export type XyVisTypeDefinition = BaseVisTypeOptions<VisParams> & {
|
||||
name: VisTypeNames;
|
||||
visConfig: {
|
||||
defaults: Omit<VisParams, 'dimensions'>;
|
||||
};
|
||||
};
|
||||
export type XyVisTypeDefinition = VisTypeDefinition<VisParams>;
|
||||
|
|
|
@ -181,4 +181,5 @@ export const getAreaVisTypeDefinition = (
|
|||
},
|
||||
],
|
||||
},
|
||||
requiresSearch: true,
|
||||
});
|
||||
|
|
|
@ -184,4 +184,5 @@ export const getHistogramVisTypeDefinition = (
|
|||
},
|
||||
],
|
||||
},
|
||||
requiresSearch: true,
|
||||
});
|
||||
|
|
|
@ -183,4 +183,5 @@ export const getHorizontalBarVisTypeDefinition = (
|
|||
},
|
||||
],
|
||||
},
|
||||
requiresSearch: true,
|
||||
});
|
||||
|
|
|
@ -175,4 +175,5 @@ export const getLineVisTypeDefinition = (
|
|||
},
|
||||
],
|
||||
},
|
||||
requiresSearch: true,
|
||||
});
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`VisualizationRequestError should render according to snapshot 1`] = `
|
||||
<div
|
||||
class="visError"
|
||||
>
|
||||
<div
|
||||
class="euiText euiText--extraSmall"
|
||||
>
|
||||
<div
|
||||
class="euiTextColor euiTextColor--subdued"
|
||||
>
|
||||
<span
|
||||
color="danger"
|
||||
data-euiicon-type="alert"
|
||||
/>
|
||||
<div
|
||||
class="euiSpacer euiSpacer--s"
|
||||
/>
|
||||
Request error
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
`;
|
|
@ -15,48 +15,6 @@
|
|||
position: relative;
|
||||
padding: $euiSizeS;
|
||||
flex: 1 1 100%;
|
||||
|
||||
/**
|
||||
* 1. Expand to fill the container but accept being squeezed smaller by the spy, even so small
|
||||
* that it disappears entirely.
|
||||
*/
|
||||
.visChart__container {
|
||||
@include euiScrollBar;
|
||||
min-height: 0;
|
||||
flex: 1 1 0; /* 1 */
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
overflow: auto;
|
||||
transition: opacity .01s;
|
||||
|
||||
// IE11 Hack
|
||||
//
|
||||
// Normally we would just set flex: 1 1 0%, which works as expected in IE11.
|
||||
// Unfortunately, a recent bug in Firefox causes this rule to be ignored, so we
|
||||
// have to use an IE-specific hack instead.
|
||||
@include internetExplorerOnly() {
|
||||
flex: 1 0;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
|
||||
// SASSTODO: Can't find exact usage
|
||||
.loading {
|
||||
opacity: .5;
|
||||
}
|
||||
|
||||
// SASSTODO: Can't find exact usage
|
||||
.spinner {
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
z-index: 20;
|
||||
opacity: .5;
|
||||
}
|
||||
}
|
||||
|
||||
.visChart {
|
||||
|
|
|
@ -6,6 +6,4 @@
|
|||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
export { Visualization } from './visualization';
|
||||
export { VisualizationContainer } from './visualization_container';
|
||||
export { VisualizationNoResults } from './visualization_noresults';
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
import React from 'react';
|
||||
import { render, mount } from 'enzyme';
|
||||
import { Visualization } from './visualization';
|
||||
|
||||
let renderPromise;
|
||||
class VisualizationStub {
|
||||
constructor(el, vis) {
|
||||
this.el = el;
|
||||
this.vis = vis;
|
||||
}
|
||||
|
||||
render() {
|
||||
renderPromise = new Promise((resolve) => {
|
||||
this.el.innerText = this.vis.params.markdown;
|
||||
resolve();
|
||||
});
|
||||
|
||||
return renderPromise;
|
||||
}
|
||||
}
|
||||
|
||||
describe('<Visualization/>', () => {
|
||||
const visData = {
|
||||
hits: 1,
|
||||
};
|
||||
|
||||
const uiState = {
|
||||
on: () => {},
|
||||
off: () => {},
|
||||
set: () => {},
|
||||
};
|
||||
|
||||
let vis;
|
||||
|
||||
beforeEach(() => {
|
||||
vis = {
|
||||
setUiState: function (uiState) {
|
||||
this.uiState = uiState;
|
||||
},
|
||||
getUiState: function () {
|
||||
return this.uiState;
|
||||
},
|
||||
params: {},
|
||||
type: {
|
||||
title: 'new vis',
|
||||
requiresSearch: true,
|
||||
useCustomNoDataScreen: false,
|
||||
visualization: VisualizationStub,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('should display no result message when length of data is 0', () => {
|
||||
const data = { rows: [] };
|
||||
const wrapper = render(
|
||||
<Visualization vis={vis} visData={data} listenOnChange={true} uiState={uiState} />
|
||||
);
|
||||
expect(wrapper.text()).toBe('No results found');
|
||||
});
|
||||
|
||||
it('should render chart when data is present', () => {
|
||||
const wrapper = render(
|
||||
<Visualization vis={vis} visData={visData} uiState={uiState} listenOnChange={true} />
|
||||
);
|
||||
expect(wrapper.text()).not.toBe('No results found');
|
||||
});
|
||||
|
||||
it('should call onInit when rendering no data', () => {
|
||||
const spy = jest.fn();
|
||||
const noData = { hits: 0 };
|
||||
mount(
|
||||
<Visualization
|
||||
vis={vis}
|
||||
visData={noData}
|
||||
uiState={uiState}
|
||||
listenOnChange={false}
|
||||
onInit={spy}
|
||||
/>
|
||||
);
|
||||
expect(spy).toHaveBeenCalled();
|
||||
});
|
||||
});
|
|
@ -1,73 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import React from 'react';
|
||||
import { PersistedState } from '../../../../plugins/visualizations/public';
|
||||
import { memoizeLast } from '../legacy/memoize';
|
||||
import { VisualizationChart } from './visualization_chart';
|
||||
import { VisualizationNoResults } from './visualization_noresults';
|
||||
import { ExprVis } from '../expressions/vis';
|
||||
|
||||
function shouldShowNoResultsMessage(vis: ExprVis, visData: any): boolean {
|
||||
const requiresSearch = get(vis, 'type.requiresSearch');
|
||||
const rows: object[] | undefined = get(visData, 'rows');
|
||||
const isZeroHits = get(visData, 'hits') === 0 || (rows && !rows.length);
|
||||
const shouldShowMessage = !get(vis, 'type.useCustomNoDataScreen');
|
||||
|
||||
return Boolean(requiresSearch && isZeroHits && shouldShowMessage);
|
||||
}
|
||||
|
||||
interface VisualizationProps {
|
||||
listenOnChange: boolean;
|
||||
onInit?: () => void;
|
||||
uiState: PersistedState;
|
||||
vis: ExprVis;
|
||||
visData: any;
|
||||
visParams: any;
|
||||
}
|
||||
|
||||
export class Visualization extends React.Component<VisualizationProps> {
|
||||
private showNoResultsMessage = memoizeLast(shouldShowNoResultsMessage);
|
||||
|
||||
constructor(props: VisualizationProps) {
|
||||
super(props);
|
||||
|
||||
props.vis.setUiState(props.uiState);
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { vis, visData, visParams, onInit, uiState, listenOnChange } = this.props;
|
||||
|
||||
const noResults = this.showNoResultsMessage(vis, visData);
|
||||
|
||||
return (
|
||||
<div className="visualization">
|
||||
{noResults ? (
|
||||
<VisualizationNoResults onInit={onInit} />
|
||||
) : (
|
||||
<VisualizationChart
|
||||
vis={vis}
|
||||
visData={visData}
|
||||
visParams={visParams}
|
||||
onInit={onInit}
|
||||
uiState={uiState}
|
||||
listenOnChange={listenOnChange}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public shouldComponentUpdate(nextProps: VisualizationProps): boolean {
|
||||
if (nextProps.uiState !== this.props.uiState) {
|
||||
throw new Error('Changing uiState on <Visualization/> is not supported!');
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
|
@ -1,56 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
import React from 'react';
|
||||
import { render, mount } from 'enzyme';
|
||||
import { VisualizationChart } from './visualization_chart';
|
||||
|
||||
let renderPromise;
|
||||
|
||||
class VisualizationStub {
|
||||
constructor(el, vis) {
|
||||
this.el = el;
|
||||
this.vis = vis;
|
||||
}
|
||||
|
||||
render() {
|
||||
renderPromise = new Promise((resolve) => {
|
||||
this.el.textContent = this.vis.params.markdown;
|
||||
resolve();
|
||||
});
|
||||
|
||||
return renderPromise;
|
||||
}
|
||||
}
|
||||
|
||||
describe('<VisualizationChart/>', () => {
|
||||
const vis = {
|
||||
type: {
|
||||
title: 'Test Visualization',
|
||||
visualization: VisualizationStub,
|
||||
},
|
||||
params: {
|
||||
markdown:
|
||||
'This is a test of the [markdown](http://daringfireball.net/projects/markdown) vis.',
|
||||
},
|
||||
};
|
||||
|
||||
it('should render initial html', () => {
|
||||
const wrapper = render(<VisualizationChart vis={vis} listenOnChange={true} />);
|
||||
expect(wrapper.text()).toBe('');
|
||||
});
|
||||
|
||||
it('should render visualization', async () => {
|
||||
const wrapper = mount(<VisualizationChart vis={vis} />);
|
||||
jest.runAllTimers();
|
||||
await renderPromise;
|
||||
expect(wrapper.find('.visChart').text()).toMatch(/markdown/);
|
||||
});
|
||||
});
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import * as Rx from 'rxjs';
|
||||
import { debounceTime, filter, share, switchMap } from 'rxjs/operators';
|
||||
import { PersistedState } from '../../../../plugins/visualizations/public';
|
||||
import { VisualizationController } from '../types';
|
||||
import { ResizeChecker } from '../../../../plugins/kibana_utils/public';
|
||||
import { ExprVis } from '../expressions/vis';
|
||||
|
||||
interface VisualizationChartProps {
|
||||
onInit?: () => void;
|
||||
uiState: PersistedState;
|
||||
vis: ExprVis;
|
||||
visData: any;
|
||||
visParams: any;
|
||||
listenOnChange: boolean;
|
||||
}
|
||||
|
||||
class VisualizationChart extends React.Component<VisualizationChartProps> {
|
||||
private resizeChecker?: ResizeChecker;
|
||||
private visualization?: VisualizationController;
|
||||
private chartDiv = React.createRef<HTMLDivElement>();
|
||||
private containerDiv = React.createRef<HTMLDivElement>();
|
||||
private renderSubject: Rx.Subject<{
|
||||
vis: ExprVis;
|
||||
visParams: any;
|
||||
visData: any;
|
||||
}>;
|
||||
private renderSubscription: Rx.Subscription;
|
||||
|
||||
constructor(props: VisualizationChartProps) {
|
||||
super(props);
|
||||
|
||||
this.renderSubject = new Rx.Subject();
|
||||
const render$ = this.renderSubject.asObservable().pipe(share());
|
||||
|
||||
const success$ = render$.pipe(
|
||||
filter(({ vis, visData }) => vis && (!vis.type.requiresSearch || visData)),
|
||||
debounceTime(100),
|
||||
switchMap(async ({ vis, visData, visParams }) => {
|
||||
if (!this.visualization) {
|
||||
// This should never happen, since we only should trigger another rendering
|
||||
// after this component has mounted and thus the visualization implementation
|
||||
// has been initialized
|
||||
throw new Error('Visualization implementation was not initialized on first render.');
|
||||
}
|
||||
|
||||
return this.visualization.render(visData, visParams);
|
||||
})
|
||||
);
|
||||
|
||||
this.renderSubscription = success$.subscribe(() => {
|
||||
if (this.props.onInit) {
|
||||
this.props.onInit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div className="visChart__container kbn-resetFocusState" tabIndex={0} ref={this.containerDiv}>
|
||||
<div className="visChart" ref={this.chartDiv} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
if (!this.chartDiv.current || !this.containerDiv.current) {
|
||||
throw new Error('chartDiv and currentDiv reference should always be present.');
|
||||
}
|
||||
|
||||
const { vis } = this.props;
|
||||
const Visualization = vis.type.visualization;
|
||||
|
||||
if (!Visualization) {
|
||||
throw new Error(
|
||||
'Tried to use VisualizationChart component with a vis without visualization property.'
|
||||
);
|
||||
}
|
||||
|
||||
this.visualization = new Visualization(this.chartDiv.current, vis);
|
||||
|
||||
// We know that containerDiv.current will never be null, since we will always
|
||||
// have rendered and the div is always rendered into the tree (i.e. not
|
||||
// inside any condition).
|
||||
this.resizeChecker = new ResizeChecker(this.containerDiv.current);
|
||||
this.resizeChecker.on('resize', () => this.startRenderVisualization());
|
||||
|
||||
if (this.props.listenOnChange) {
|
||||
this.props.uiState.on('change', this.onUiStateChanged);
|
||||
}
|
||||
|
||||
this.startRenderVisualization();
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
this.startRenderVisualization();
|
||||
}
|
||||
|
||||
public componentWillUnmount() {
|
||||
if (this.renderSubscription) {
|
||||
this.renderSubscription.unsubscribe();
|
||||
}
|
||||
if (this.resizeChecker) {
|
||||
this.resizeChecker.destroy();
|
||||
}
|
||||
if (this.visualization) {
|
||||
this.visualization.destroy();
|
||||
}
|
||||
}
|
||||
|
||||
private onUiStateChanged = () => {
|
||||
this.startRenderVisualization();
|
||||
};
|
||||
|
||||
private startRenderVisualization(): void {
|
||||
if (this.containerDiv.current && this.chartDiv.current) {
|
||||
this.renderSubject.next({
|
||||
vis: this.props.vis,
|
||||
visData: this.props.visData,
|
||||
visParams: this.props.visParams,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { VisualizationChart };
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render } from 'enzyme';
|
||||
import { VisualizationRequestError } from './visualization_requesterror';
|
||||
|
||||
describe('VisualizationRequestError', () => {
|
||||
it('should render according to snapshot', () => {
|
||||
const wrapper = render(<VisualizationRequestError error="Request error" />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should set html when error is an object', () => {
|
||||
const wrapper = render(<VisualizationRequestError error={{ message: 'Request error' }} />);
|
||||
expect(wrapper.text()).toBe('Request error');
|
||||
});
|
||||
|
||||
it('should set html when error is a string', () => {
|
||||
const wrapper = render(<VisualizationRequestError error="Request error" />);
|
||||
expect(wrapper.text()).toBe('Request error');
|
||||
});
|
||||
});
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EuiIcon, EuiSpacer, EuiText } from '@elastic/eui';
|
||||
import React from 'react';
|
||||
import { SearchError } from '../../../../plugins/data/public';
|
||||
|
||||
interface VisualizationRequestErrorProps {
|
||||
onInit?: () => void;
|
||||
error: SearchError | string;
|
||||
}
|
||||
|
||||
export class VisualizationRequestError extends React.Component<VisualizationRequestErrorProps> {
|
||||
private containerDiv = React.createRef<HTMLDivElement>();
|
||||
|
||||
public render() {
|
||||
const { error } = this.props;
|
||||
const errorMessage = typeof error === 'string' ? error : error.message;
|
||||
|
||||
return (
|
||||
<div className="visError" ref={this.containerDiv}>
|
||||
<EuiText size="xs" color="subdued">
|
||||
<EuiIcon type="alert" size="m" color="danger" />
|
||||
|
||||
<EuiSpacer size="s" />
|
||||
|
||||
{errorMessage}
|
||||
</EuiText>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this.afterRender();
|
||||
}
|
||||
|
||||
public componentDidUpdate() {
|
||||
this.afterRender();
|
||||
}
|
||||
|
||||
private afterRender() {
|
||||
if (this.props.onInit) {
|
||||
this.props.onInit();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,10 +8,6 @@
|
|||
@include euiScrollBar; /* 2 */
|
||||
}
|
||||
|
||||
.visualization .visChart__container {
|
||||
overflow: visible; /* 1 */
|
||||
}
|
||||
|
||||
.visLegend__toggle {
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-left-radius: 0;
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { VisSavedObject } from '../types';
|
||||
import type { IndexPattern } from '../../../../plugins/data/public';
|
||||
import { getIndexPatterns } from '../services';
|
||||
|
||||
export async function getIndexPattern(
|
||||
savedVis: VisSavedObject
|
||||
): Promise<IndexPattern | undefined | null> {
|
||||
if (savedVis.visState.type !== 'metrics') {
|
||||
return savedVis.searchSource!.getField('index');
|
||||
}
|
||||
|
||||
const indexPatternsClient = getIndexPatterns();
|
||||
|
||||
return savedVis.visState.params.index_pattern
|
||||
? (await indexPatternsClient.find(`"${savedVis.visState.params.index_pattern}"`))[0]
|
||||
: await indexPatternsClient.getDefault();
|
||||
}
|
45
src/plugins/visualizations/public/embeddable/to_ast.ts
Normal file
45
src/plugins/visualizations/public/embeddable/to_ast.ts
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ExpressionFunctionKibana, ExpressionFunctionKibanaContext } from '../../../data/public';
|
||||
import { buildExpression, buildExpressionFunction } from '../../../expressions/public';
|
||||
|
||||
import { VisToExpressionAst } from '../types';
|
||||
|
||||
/**
|
||||
* Creates an ast expression for a visualization based on kibana context (query, filters, timerange)
|
||||
* including a saved search if the visualization is based on it.
|
||||
* The expression also includes particular visualization expression ast if presented.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export const toExpressionAst: VisToExpressionAst = async (vis, params) => {
|
||||
const { savedSearchId, searchSource } = vis.data;
|
||||
const query = searchSource?.getField('query');
|
||||
const filters = searchSource?.getField('filter');
|
||||
|
||||
const kibana = buildExpressionFunction<ExpressionFunctionKibana>('kibana', {});
|
||||
const kibanaContext = buildExpressionFunction<ExpressionFunctionKibanaContext>('kibana_context', {
|
||||
q: query && JSON.stringify(query),
|
||||
filters: filters && JSON.stringify(filters),
|
||||
savedSearchId,
|
||||
});
|
||||
|
||||
const ast = buildExpression([kibana, kibanaContext]);
|
||||
const expression = ast.toAst();
|
||||
|
||||
if (!vis.type.toExpressionAst) {
|
||||
throw new Error('Visualization type definition should have toExpressionAst function defined');
|
||||
}
|
||||
|
||||
const visExpressionAst = await vis.type.toExpressionAst(vis, params);
|
||||
// expand the expression chain with a particular visualization expression chain, if it exists
|
||||
expression.chain.push(...visExpressionAst.chain);
|
||||
|
||||
return expression;
|
||||
};
|
|
@ -32,8 +32,8 @@ import {
|
|||
IExpressionLoaderParams,
|
||||
ExpressionsStart,
|
||||
ExpressionRenderError,
|
||||
ExpressionAstExpression,
|
||||
} from '../../../../plugins/expressions/public';
|
||||
import { buildPipeline } from '../legacy/build_pipeline';
|
||||
import { Vis, SerializedVis } from '../vis';
|
||||
import { getExpressions, getUiActions } from '../services';
|
||||
import { VIS_EVENT_TO_TRIGGER } from './events';
|
||||
|
@ -41,6 +41,7 @@ import { VisualizeEmbeddableFactoryDeps } from './visualize_embeddable_factory';
|
|||
import { SavedObjectAttributes } from '../../../../core/types';
|
||||
import { SavedVisualizationsLoader } from '../saved_visualizations';
|
||||
import { VisSavedObject } from '../types';
|
||||
import { toExpressionAst } from './to_ast';
|
||||
|
||||
const getKeys = <T extends {}>(o: T): Array<keyof T> => Object.keys(o) as Array<keyof T>;
|
||||
|
||||
|
@ -94,7 +95,7 @@ export class VisualizeEmbeddable
|
|||
private syncColors?: boolean;
|
||||
private visCustomizations?: Pick<VisualizeInput, 'vis' | 'table'>;
|
||||
private subscriptions: Subscription[] = [];
|
||||
private expression: string = '';
|
||||
private expression?: ExpressionAstExpression;
|
||||
private vis: Vis;
|
||||
private domNode: any;
|
||||
public readonly type = VISUALIZE_EMBEDDABLE_TYPE;
|
||||
|
@ -382,7 +383,7 @@ export class VisualizeEmbeddable
|
|||
}
|
||||
this.abortController = new AbortController();
|
||||
const abortController = this.abortController;
|
||||
this.expression = await buildPipeline(this.vis, {
|
||||
this.expression = await toExpressionAst(this.vis, {
|
||||
timefilter: this.timefilter,
|
||||
timeRange: this.timeRange,
|
||||
abortSignal: this.abortController!.signal,
|
||||
|
|
|
@ -74,12 +74,12 @@ export class VisualizeEmbeddableFactory
|
|||
type: 'visualization',
|
||||
getIconForSavedObject: (savedObject) => {
|
||||
return (
|
||||
getTypes().get(JSON.parse(savedObject.attributes.visState).type).icon || 'visualizeApp'
|
||||
getTypes().get(JSON.parse(savedObject.attributes.visState).type)?.icon || 'visualizeApp'
|
||||
);
|
||||
},
|
||||
getTooltipForSavedObject: (savedObject) => {
|
||||
return `${savedObject.attributes.title} (${
|
||||
getTypes().get(JSON.parse(savedObject.attributes.visState).type).title
|
||||
getTypes().get(JSON.parse(savedObject.attributes.visState).type)?.title
|
||||
})`;
|
||||
},
|
||||
showSavedObject: (savedObject) => {
|
||||
|
|
|
@ -1,157 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @name Vis
|
||||
*
|
||||
* @description This class consists of aggs, params, listeners, title, and type.
|
||||
* - Aggs: Instances of AggConfig.
|
||||
* - Params: The settings in the Options tab.
|
||||
*
|
||||
* Not to be confused with vislib/vis.js.
|
||||
*/
|
||||
|
||||
import { EventEmitter } from 'events';
|
||||
import _ from 'lodash';
|
||||
import { VisParams, PersistedState } from '../../../../plugins/visualizations/public';
|
||||
|
||||
import { getTypes } from '../services';
|
||||
import { VisType } from '../vis_types';
|
||||
|
||||
export interface ExprVisState {
|
||||
title?: string;
|
||||
type: VisType<unknown> | string;
|
||||
params?: VisParams;
|
||||
}
|
||||
|
||||
export interface ExprVisAPIEvents {
|
||||
filter: (data: any) => void;
|
||||
brush: (data: any) => void;
|
||||
applyFilter: (data: any) => void;
|
||||
}
|
||||
|
||||
export interface ExprVisAPI {
|
||||
events: ExprVisAPIEvents;
|
||||
}
|
||||
|
||||
export class ExprVis extends EventEmitter {
|
||||
public title: string = '';
|
||||
public type: VisType<unknown>;
|
||||
public params: VisParams = {};
|
||||
public sessionState: Record<string, any> = {};
|
||||
public API: ExprVisAPI;
|
||||
public eventsSubject: any;
|
||||
private uiState: PersistedState;
|
||||
|
||||
constructor(visState: ExprVisState = { type: 'histogram' }) {
|
||||
super();
|
||||
|
||||
this.type = this.getType(visState.type);
|
||||
this.uiState = new PersistedState();
|
||||
this.setState(visState);
|
||||
|
||||
this.API = {
|
||||
events: {
|
||||
filter: (data: any) => {
|
||||
if (!this.eventsSubject) return;
|
||||
this.eventsSubject.next({
|
||||
name: 'filterBucket',
|
||||
data: data.data
|
||||
? {
|
||||
data: data.data,
|
||||
negate: data.negate,
|
||||
}
|
||||
: { data: [data] },
|
||||
});
|
||||
},
|
||||
brush: (data: any) => {
|
||||
if (!this.eventsSubject) return;
|
||||
this.eventsSubject.next({ name: 'brush', data });
|
||||
},
|
||||
applyFilter: (data: any) => {
|
||||
if (!this.eventsSubject) return;
|
||||
this.eventsSubject.next({ name: 'applyFilter', data });
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
private getType(type: string | VisType<unknown>) {
|
||||
if (_.isString(type)) {
|
||||
const newType = getTypes().get(type);
|
||||
if (!newType) {
|
||||
throw new Error(`Invalid type "${type}"`);
|
||||
}
|
||||
return newType;
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
setState(state: ExprVisState) {
|
||||
this.title = state.title || '';
|
||||
if (state.type) {
|
||||
this.type = this.getType(state.type);
|
||||
}
|
||||
this.params = _.defaultsDeep(
|
||||
{},
|
||||
_.cloneDeep(state.params || {}),
|
||||
_.cloneDeep(this.type.visConfig.defaults || {})
|
||||
);
|
||||
}
|
||||
|
||||
getState() {
|
||||
return {
|
||||
title: this.title,
|
||||
type: this.type.name,
|
||||
params: _.cloneDeep(this.params),
|
||||
};
|
||||
}
|
||||
|
||||
updateState() {
|
||||
this.emit('update');
|
||||
}
|
||||
|
||||
forceReload() {
|
||||
this.emit('reload');
|
||||
}
|
||||
|
||||
isHierarchical() {
|
||||
if (_.isFunction(this.type.hierarchicalData)) {
|
||||
return !!this.type.hierarchicalData(this);
|
||||
} else {
|
||||
return !!this.type.hierarchicalData;
|
||||
}
|
||||
}
|
||||
|
||||
hasUiState() {
|
||||
return !!this.uiState;
|
||||
}
|
||||
|
||||
getUiState() {
|
||||
return this.uiState;
|
||||
}
|
||||
|
||||
setUiState(state: PersistedState) {
|
||||
this.uiState = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently this is only used to extract map-specific information
|
||||
* (e.g. mapZoom, mapCenter).
|
||||
*/
|
||||
uiStateVal(key: string, val: any) {
|
||||
if (this.hasUiState()) {
|
||||
if (_.isUndefined(val)) {
|
||||
return this.uiState.get(key);
|
||||
}
|
||||
return this.uiState.set(key, val);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { VisResponseValue, PersistedState } from '../../../../plugins/visualizations/public';
|
||||
import { ExpressionFunctionDefinition, Render } from '../../../../plugins/expressions/public';
|
||||
import { getTypes, getIndexPatterns, getFilterManager, getSearch } from '../services';
|
||||
|
||||
interface Arguments {
|
||||
index?: string | null;
|
||||
metricsAtAllLevels?: boolean;
|
||||
partialRows?: boolean;
|
||||
type?: string;
|
||||
schemas?: string;
|
||||
visConfig?: string;
|
||||
uiState?: string;
|
||||
aggConfigs?: string;
|
||||
}
|
||||
|
||||
export type ExpressionFunctionVisualization = ExpressionFunctionDefinition<
|
||||
'visualization',
|
||||
any,
|
||||
Arguments,
|
||||
Promise<Render<VisResponseValue>>
|
||||
>;
|
||||
|
||||
export const visualization = (): ExpressionFunctionVisualization => ({
|
||||
name: 'visualization',
|
||||
type: 'render',
|
||||
help: i18n.translate('visualizations.functions.visualization.help', {
|
||||
defaultMessage: 'A simple visualization',
|
||||
}),
|
||||
args: {
|
||||
// TODO: Below `help` keys should be internationalized once this function
|
||||
// TODO: is moved to visualizations plugin.
|
||||
index: {
|
||||
types: ['string', 'null'],
|
||||
default: null,
|
||||
help: 'Index',
|
||||
},
|
||||
metricsAtAllLevels: {
|
||||
types: ['boolean'],
|
||||
default: false,
|
||||
help: 'Metrics levels',
|
||||
},
|
||||
partialRows: {
|
||||
types: ['boolean'],
|
||||
default: false,
|
||||
help: 'Partial rows',
|
||||
},
|
||||
type: {
|
||||
types: ['string'],
|
||||
default: '',
|
||||
help: 'Type',
|
||||
},
|
||||
schemas: {
|
||||
types: ['string'],
|
||||
default: '"{}"',
|
||||
help: 'Schemas',
|
||||
},
|
||||
visConfig: {
|
||||
types: ['string'],
|
||||
default: '"{}"',
|
||||
help: 'Visualization configuration',
|
||||
},
|
||||
uiState: {
|
||||
types: ['string'],
|
||||
default: '"{}"',
|
||||
help: 'User interface state',
|
||||
},
|
||||
aggConfigs: {
|
||||
types: ['string'],
|
||||
default: '"{}"',
|
||||
help: 'Aggregation configurations',
|
||||
},
|
||||
},
|
||||
async fn(input, args, { inspectorAdapters }) {
|
||||
const visConfigParams = args.visConfig ? JSON.parse(args.visConfig) : {};
|
||||
const schemas = args.schemas ? JSON.parse(args.schemas) : {};
|
||||
const visType = getTypes().get(args.type || 'histogram') as any;
|
||||
const indexPattern = args.index ? await getIndexPatterns().get(args.index) : null;
|
||||
|
||||
const uiStateParams = args.uiState ? JSON.parse(args.uiState) : {};
|
||||
const uiState = new PersistedState(uiStateParams);
|
||||
|
||||
const aggConfigsState = args.aggConfigs ? JSON.parse(args.aggConfigs) : [];
|
||||
const aggs = indexPattern
|
||||
? getSearch().aggs.createAggConfigs(indexPattern, aggConfigsState)
|
||||
: undefined;
|
||||
|
||||
if (typeof visType.requestHandler === 'function') {
|
||||
input = await visType.requestHandler({
|
||||
partialRows: args.partialRows,
|
||||
metricsAtAllLevels: args.metricsAtAllLevels,
|
||||
index: indexPattern,
|
||||
visParams: visConfigParams,
|
||||
timeRange: get(input, 'timeRange', null),
|
||||
query: get(input, 'query', null),
|
||||
filters: get(input, 'filters', null),
|
||||
uiState,
|
||||
inspectorAdapters,
|
||||
queryFilter: getFilterManager(),
|
||||
aggs,
|
||||
});
|
||||
}
|
||||
|
||||
if (typeof visType.responseHandler === 'function') {
|
||||
if (input.columns) {
|
||||
// assign schemas to aggConfigs
|
||||
input.columns.forEach((column: any) => {
|
||||
if (column.aggConfig) {
|
||||
column.aggConfig.aggConfigs.schemas = visType.schemas.all;
|
||||
}
|
||||
});
|
||||
|
||||
Object.keys(schemas).forEach((key) => {
|
||||
schemas[key].forEach((i: any) => {
|
||||
if (input.columns[i] && input.columns[i].aggConfig) {
|
||||
input.columns[i].aggConfig.schema = key;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
input = await visType.responseHandler(input, visConfigParams.dimensions);
|
||||
}
|
||||
|
||||
return {
|
||||
type: 'render',
|
||||
as: 'visualization',
|
||||
value: {
|
||||
visData: input,
|
||||
visType: args.type || '',
|
||||
visConfig: visConfigParams,
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
// @ts-ignore
|
||||
import { ExprVis } from './vis';
|
||||
import { Visualization } from '../components';
|
||||
import { VisParams } from '../types';
|
||||
|
||||
export const visualization = () => ({
|
||||
name: 'visualization',
|
||||
displayName: 'visualization',
|
||||
reuseDomNode: true,
|
||||
render: async (domNode: HTMLElement, config: any, handlers: any) => {
|
||||
const { visData, visConfig, params } = config;
|
||||
const visType = config.visType || visConfig.type;
|
||||
|
||||
const vis = new ExprVis({
|
||||
title: config.title,
|
||||
type: visType as string,
|
||||
params: visConfig as VisParams,
|
||||
});
|
||||
|
||||
vis.eventsSubject = { next: handlers.event };
|
||||
|
||||
const uiState = handlers.uiState || vis.getUiState();
|
||||
|
||||
handlers.onDestroy(() => {
|
||||
unmountComponentAtNode(domNode);
|
||||
});
|
||||
|
||||
const listenOnChange = params ? params.listenOnChange : false;
|
||||
render(
|
||||
<Visualization
|
||||
vis={vis}
|
||||
visData={visData}
|
||||
visParams={vis.params}
|
||||
uiState={uiState}
|
||||
listenOnChange={listenOnChange}
|
||||
onInit={handlers.done}
|
||||
/>,
|
||||
domNode
|
||||
);
|
||||
},
|
||||
});
|
|
@ -10,7 +10,6 @@ import { PublicContract } from '@kbn/utility-types';
|
|||
import { PluginInitializerContext } from 'src/core/public';
|
||||
import { VisualizationsPlugin, VisualizationsSetup, VisualizationsStart } from './plugin';
|
||||
import { VisualizeEmbeddableFactory, VisualizeEmbeddable } from './embeddable';
|
||||
import { ExprVis as ExprVisClass } from './expressions/vis';
|
||||
|
||||
export function plugin(initializerContext: PluginInitializerContext) {
|
||||
return new VisualizationsPlugin(initializerContext);
|
||||
|
@ -20,39 +19,27 @@ export function plugin(initializerContext: PluginInitializerContext) {
|
|||
export { Vis } from './vis';
|
||||
export { TypesService } from './vis_types/types_service';
|
||||
export { VISUALIZE_EMBEDDABLE_TYPE, VIS_EVENT_TO_TRIGGER } from './embeddable';
|
||||
export { VisualizationContainer, VisualizationNoResults } from './components';
|
||||
export { getSchemas as getVisSchemas } from './legacy/build_pipeline';
|
||||
export { VisualizationContainer } from './components';
|
||||
export { getVisSchemas } from './vis_schemas';
|
||||
|
||||
/** @public types */
|
||||
export { VisualizationsSetup, VisualizationsStart };
|
||||
export { VisGroups } from './vis_types';
|
||||
export type {
|
||||
VisTypeAlias,
|
||||
VisType,
|
||||
BaseVisTypeOptions,
|
||||
ReactVisTypeOptions,
|
||||
Schema,
|
||||
ISchemas,
|
||||
} from './vis_types';
|
||||
export type { VisTypeAlias, VisTypeDefinition, Schema, ISchemas } from './vis_types';
|
||||
export { SerializedVis, SerializedVisData, VisData } from './vis';
|
||||
export type VisualizeEmbeddableFactoryContract = PublicContract<VisualizeEmbeddableFactory>;
|
||||
export type VisualizeEmbeddableContract = PublicContract<VisualizeEmbeddable>;
|
||||
export { VisualizeInput } from './embeddable';
|
||||
export type ExprVis = ExprVisClass;
|
||||
export { SchemaConfig, BuildPipelineParams } from './legacy/build_pipeline';
|
||||
// @ts-ignore
|
||||
export { SchemaConfig } from './vis_schemas';
|
||||
export { updateOldState } from './legacy/vis_update_state';
|
||||
export { PersistedState } from './persisted_state';
|
||||
export {
|
||||
VisualizationControllerConstructor,
|
||||
VisualizationController,
|
||||
ISavedVis,
|
||||
VisSavedObject,
|
||||
VisResponseValue,
|
||||
VisToExpressionAst,
|
||||
VisParams,
|
||||
VisToExpressionAstParams,
|
||||
VisEditorOptionsProps,
|
||||
} from './types';
|
||||
export { ExprVisAPIEvents } from './expressions/vis';
|
||||
export { VisualizationListItem, VisualizationStage } from './vis_types/vis_type_alias_registry';
|
||||
export { VISUALIZE_ENABLE_LABS_SETTING } from '../common/constants';
|
||||
export { SavedVisState } from '../common';
|
||||
export { SavedVisState, VisParams } from '../common';
|
||||
|
|
|
@ -1,3 +0,0 @@
|
|||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`visualize loader pipeline helpers: build pipeline buildPipeline calls toExpression on vis_type if it exists 1`] = `"kibana | kibana_context | test"`;
|
|
@ -1,86 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { prepareJson, prepareString, buildPipeline } from './build_pipeline';
|
||||
import { Vis } from '..';
|
||||
import { dataPluginMock } from '../../../../plugins/data/public/mocks';
|
||||
import { parseExpression } from '../../../expressions/common';
|
||||
|
||||
describe('visualize loader pipeline helpers: build pipeline', () => {
|
||||
describe('prepareJson', () => {
|
||||
it('returns a correctly formatted key/value string', () => {
|
||||
const expected = `foo='{}' `; // trailing space is expected
|
||||
const actual = prepareJson('foo', {});
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
it('stringifies provided data', () => {
|
||||
const expected = `foo='{\"well\":\"hello\",\"there\":{\"friend\":true}}' `;
|
||||
const actual = prepareJson('foo', { well: 'hello', there: { friend: true } });
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
it('escapes single quotes', () => {
|
||||
const expected = `foo='{\"well\":\"hello \\'hi\\'\",\"there\":{\"friend\":true}}' `;
|
||||
const actual = prepareJson('foo', { well: `hello 'hi'`, there: { friend: true } });
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
it('returns empty string if data is undefined', () => {
|
||||
const actual = prepareJson('foo', undefined);
|
||||
expect(actual).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('prepareString', () => {
|
||||
it('returns a correctly formatted key/value string', () => {
|
||||
const expected = `foo='bar' `; // trailing space is expected
|
||||
const actual = prepareString('foo', 'bar');
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
it('escapes single quotes', () => {
|
||||
const expected = `foo='\\'bar\\'' `;
|
||||
const actual = prepareString('foo', `'bar'`);
|
||||
expect(actual).toBe(expected);
|
||||
});
|
||||
|
||||
it('returns empty string if data is undefined', () => {
|
||||
const actual = prepareString('foo', undefined);
|
||||
expect(actual).toBe('');
|
||||
});
|
||||
});
|
||||
|
||||
describe('buildPipeline', () => {
|
||||
const dataStart = dataPluginMock.createStartContract();
|
||||
|
||||
it('calls toExpression on vis_type if it exists', async () => {
|
||||
const vis = ({
|
||||
getState: () => {},
|
||||
isHierarchical: () => false,
|
||||
data: {
|
||||
aggs: {
|
||||
getResponseAggs: () => [],
|
||||
},
|
||||
searchSource: {
|
||||
getField: jest.fn(),
|
||||
getParent: jest.fn(),
|
||||
},
|
||||
},
|
||||
// @ts-ignore
|
||||
type: {
|
||||
toExpressionAst: () => parseExpression('test'),
|
||||
},
|
||||
} as unknown) as Vis;
|
||||
const expression = await buildPipeline(vis, {
|
||||
timefilter: dataStart.query.timefilter.timefilter,
|
||||
});
|
||||
expect(expression).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -1,253 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import {
|
||||
buildExpression,
|
||||
formatExpression,
|
||||
SerializedFieldFormat,
|
||||
} from '../../../../plugins/expressions/public';
|
||||
import { IAggConfig, search, TimefilterContract } from '../../../../plugins/data/public';
|
||||
import { Vis } from '../types';
|
||||
const { isDateHistogramBucketAggConfig } = search.aggs;
|
||||
|
||||
interface SchemaConfigParams {
|
||||
precision?: number;
|
||||
useGeocentroid?: boolean;
|
||||
}
|
||||
|
||||
export interface SchemaConfig {
|
||||
accessor: number;
|
||||
label: string;
|
||||
format: SerializedFieldFormat;
|
||||
params: SchemaConfigParams;
|
||||
aggType: string;
|
||||
}
|
||||
|
||||
export interface Schemas {
|
||||
metric: SchemaConfig[];
|
||||
bucket?: SchemaConfig[];
|
||||
geo_centroid?: any[];
|
||||
group?: any[];
|
||||
params?: any[];
|
||||
radius?: any[];
|
||||
segment?: any[];
|
||||
split_column?: SchemaConfig[];
|
||||
split_row?: SchemaConfig[];
|
||||
width?: any[];
|
||||
// catch all for schema name
|
||||
[key: string]: any[] | undefined;
|
||||
}
|
||||
export interface BuildPipelineParams {
|
||||
timefilter: TimefilterContract;
|
||||
timeRange?: any;
|
||||
abortSignal?: AbortSignal;
|
||||
}
|
||||
|
||||
export const getSchemas = <TVisParams>(
|
||||
vis: Vis<TVisParams>,
|
||||
{ timeRange, timefilter }: BuildPipelineParams
|
||||
): Schemas => {
|
||||
const createSchemaConfig = (accessor: number, agg: IAggConfig): SchemaConfig => {
|
||||
if (isDateHistogramBucketAggConfig(agg)) {
|
||||
agg.params.timeRange = timeRange;
|
||||
const bounds =
|
||||
agg.params.timeRange && agg.fieldIsTimeField()
|
||||
? timefilter.calculateBounds(agg.params.timeRange)
|
||||
: undefined;
|
||||
agg.buckets.setBounds(bounds);
|
||||
agg.buckets.setInterval(agg.params.interval);
|
||||
}
|
||||
|
||||
const hasSubAgg = [
|
||||
'derivative',
|
||||
'moving_avg',
|
||||
'serial_diff',
|
||||
'cumulative_sum',
|
||||
'sum_bucket',
|
||||
'avg_bucket',
|
||||
'min_bucket',
|
||||
'max_bucket',
|
||||
].includes(agg.type.name);
|
||||
|
||||
const formatAgg = hasSubAgg
|
||||
? agg.params.customMetric || agg.aggConfigs.getRequestAggById(agg.params.metricAgg)
|
||||
: agg;
|
||||
|
||||
const params: SchemaConfigParams = {};
|
||||
|
||||
if (agg.type.name === 'geohash_grid') {
|
||||
params.precision = agg.params.precision;
|
||||
params.useGeocentroid = agg.params.useGeocentroid;
|
||||
}
|
||||
|
||||
const label = agg.makeLabel && agg.makeLabel();
|
||||
|
||||
return {
|
||||
accessor,
|
||||
format: formatAgg.toSerializedFieldFormat(),
|
||||
params,
|
||||
label,
|
||||
aggType: agg.type.name,
|
||||
};
|
||||
};
|
||||
|
||||
let cnt = 0;
|
||||
const schemas: Schemas = {
|
||||
metric: [],
|
||||
};
|
||||
|
||||
if (!vis.data.aggs) {
|
||||
return schemas;
|
||||
}
|
||||
|
||||
const responseAggs = vis.data.aggs.getResponseAggs().filter((agg: IAggConfig) => agg.enabled);
|
||||
const isHierarchical = vis.isHierarchical();
|
||||
const metrics = responseAggs.filter((agg: IAggConfig) => agg.type.type === 'metrics');
|
||||
responseAggs.forEach((agg: IAggConfig) => {
|
||||
let skipMetrics = false;
|
||||
let schemaName = agg.schema;
|
||||
if (!schemaName) {
|
||||
if (agg.type.name === 'geo_centroid') {
|
||||
schemaName = 'geo_centroid';
|
||||
} else {
|
||||
cnt++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (schemaName === 'split') {
|
||||
// TODO: We should check if there's a better way then casting to `any` here
|
||||
schemaName = `split_${(vis.params as any).row ? 'row' : 'column'}`;
|
||||
skipMetrics = responseAggs.length - metrics.length > 1;
|
||||
}
|
||||
if (!schemas[schemaName]) {
|
||||
schemas[schemaName] = [];
|
||||
}
|
||||
if (!isHierarchical || agg.type.type !== 'metrics') {
|
||||
schemas[schemaName]!.push(createSchemaConfig(cnt++, agg));
|
||||
}
|
||||
if (isHierarchical && (agg.type.type !== 'metrics' || metrics.length === responseAggs.length)) {
|
||||
metrics.forEach((metric: any) => {
|
||||
const schemaConfig = createSchemaConfig(cnt++, metric);
|
||||
if (!skipMetrics) {
|
||||
schemas.metric.push(schemaConfig);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return schemas;
|
||||
};
|
||||
|
||||
export const prepareJson = (variable: string, data?: object): string => {
|
||||
if (data === undefined) {
|
||||
return '';
|
||||
}
|
||||
return `${variable}='${JSON.stringify(data).replace(/\\/g, `\\\\`).replace(/'/g, `\\'`)}' `;
|
||||
};
|
||||
|
||||
export const escapeString = (data: string): string => {
|
||||
return data.replace(/\\/g, `\\\\`).replace(/'/g, `\\'`);
|
||||
};
|
||||
|
||||
export const prepareString = (variable: string, data?: string): string => {
|
||||
if (data === undefined) {
|
||||
return '';
|
||||
}
|
||||
return `${variable}='${escapeString(data)}' `;
|
||||
};
|
||||
|
||||
export const prepareValue = (variable: string, data: any, raw: boolean = false) => {
|
||||
if (data === undefined) {
|
||||
return '';
|
||||
}
|
||||
if (raw) {
|
||||
return `${variable}=${data} `;
|
||||
}
|
||||
switch (typeof data) {
|
||||
case 'string':
|
||||
return prepareString(variable, data);
|
||||
case 'object':
|
||||
return prepareJson(variable, data);
|
||||
default:
|
||||
return `${variable}=${data} `;
|
||||
}
|
||||
};
|
||||
|
||||
export const prepareDimension = (variable: string, data: any) => {
|
||||
if (data === undefined) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let expr = `${variable}={visdimension ${data.accessor} `;
|
||||
if (data.format) {
|
||||
expr += prepareValue('format', data.format.id);
|
||||
expr += prepareJson('formatParams', data.format.params);
|
||||
}
|
||||
expr += '} ';
|
||||
|
||||
return expr;
|
||||
};
|
||||
|
||||
export const buildPipeline = async (vis: Vis, params: BuildPipelineParams) => {
|
||||
const { indexPattern, searchSource } = vis.data;
|
||||
const query = searchSource!.getField('query');
|
||||
const filters = searchSource!.getField('filter');
|
||||
const { uiState, title } = vis;
|
||||
|
||||
// context
|
||||
let pipeline = `kibana | kibana_context `;
|
||||
if (query) {
|
||||
pipeline += prepareJson('query', query);
|
||||
}
|
||||
if (filters) {
|
||||
pipeline += prepareJson('filters', filters);
|
||||
}
|
||||
if (vis.data.savedSearchId) {
|
||||
pipeline += prepareString('savedSearchId', vis.data.savedSearchId);
|
||||
}
|
||||
pipeline += '| ';
|
||||
|
||||
if (vis.type.toExpressionAst) {
|
||||
const visAst = await vis.type.toExpressionAst(vis, params);
|
||||
pipeline += formatExpression(visAst);
|
||||
} else {
|
||||
// request handler
|
||||
if (vis.type.requestHandler === 'courier') {
|
||||
pipeline += `esaggs
|
||||
index={indexPatternLoad ${prepareString('id', indexPattern!.id)}}
|
||||
metricsAtAllLevels=${vis.isHierarchical()}
|
||||
partialRows=${vis.params.showPartialRows || false} `;
|
||||
if (vis.data.aggs) {
|
||||
vis.data.aggs.aggs.forEach((agg) => {
|
||||
const ast = agg.toExpressionAst();
|
||||
if (ast) {
|
||||
pipeline += `aggs={${buildExpression(ast).toString()}} `;
|
||||
}
|
||||
});
|
||||
}
|
||||
pipeline += `| `;
|
||||
} else {
|
||||
const schemas = getSchemas(vis, params);
|
||||
const visConfig = { ...vis.params };
|
||||
visConfig.dimensions = schemas;
|
||||
visConfig.title = title;
|
||||
pipeline += `visualization type='${vis.type.name}'
|
||||
${prepareJson('visConfig', visConfig)}
|
||||
${prepareJson('uiState', uiState)}
|
||||
metricsAtAllLevels=${vis.isHierarchical()}
|
||||
partialRows=${vis.params.showPartialRows || false} `;
|
||||
if (indexPattern) {
|
||||
pipeline += `${prepareString('index', indexPattern.id)} `;
|
||||
if (vis.data.aggs) {
|
||||
pipeline += `${prepareJson('aggConfigs', vis.data.aggs!.aggs)}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return pipeline;
|
||||
};
|
|
@ -22,7 +22,6 @@ import { savedObjectsPluginMock } from '../../../plugins/saved_objects/public/mo
|
|||
|
||||
const createSetupContract = (): VisualizationsSetup => ({
|
||||
createBaseVisualization: jest.fn(),
|
||||
createReactVisualization: jest.fn(),
|
||||
registerAlias: jest.fn(),
|
||||
hideTypes: jest.fn(),
|
||||
});
|
||||
|
|
|
@ -20,15 +20,12 @@ import { TypesService, TypesSetup, TypesStart } from './vis_types';
|
|||
import {
|
||||
setUISettings,
|
||||
setTypes,
|
||||
setI18n,
|
||||
setApplication,
|
||||
setCapabilities,
|
||||
setHttp,
|
||||
setIndexPatterns,
|
||||
setSearch,
|
||||
setSavedObjects,
|
||||
setUsageCollector,
|
||||
setFilterManager,
|
||||
setExpressions,
|
||||
setUiActions,
|
||||
setSavedVisualizationsLoader,
|
||||
|
@ -47,8 +44,6 @@ import {
|
|||
} from './embeddable';
|
||||
import { ExpressionsSetup, ExpressionsStart } from '../../expressions/public';
|
||||
import { EmbeddableSetup, EmbeddableStart } from '../../embeddable/public';
|
||||
import { visualization as visualizationFunction } from './expressions/visualization_function';
|
||||
import { visualization as visualizationRenderer } from './expressions/visualization_renderer';
|
||||
import { range as rangeExpressionFunction } from './expression_functions/range';
|
||||
import { visDimension as visDimensionExpressionFunction } from './expression_functions/vis_dimension';
|
||||
import { DataPublicPluginSetup, DataPublicPluginStart } from '../../../plugins/data/public';
|
||||
|
@ -138,8 +133,6 @@ export class VisualizationsPlugin
|
|||
setUISettings(core.uiSettings);
|
||||
setUsageCollector(usageCollection);
|
||||
|
||||
expressions.registerFunction(visualizationFunction);
|
||||
expressions.registerRenderer(visualizationRenderer);
|
||||
expressions.registerFunction(rangeExpressionFunction);
|
||||
expressions.registerFunction(visDimensionExpressionFunction);
|
||||
const embeddableFactory = new VisualizeEmbeddableFactory({ start });
|
||||
|
@ -155,7 +148,6 @@ export class VisualizationsPlugin
|
|||
{ data, expressions, uiActions, embeddable, dashboard, savedObjects }: VisualizationsStartDeps
|
||||
): VisualizationsStart {
|
||||
const types = this.types.start();
|
||||
setI18n(core.i18n);
|
||||
setTypes(types);
|
||||
setEmbeddable(embeddable);
|
||||
setApplication(core.application);
|
||||
|
@ -163,9 +155,7 @@ export class VisualizationsPlugin
|
|||
setHttp(core.http);
|
||||
setSavedObjects(core.savedObjects);
|
||||
setDocLinks(core.docLinks);
|
||||
setIndexPatterns(data.indexPatterns);
|
||||
setSearch(data.search);
|
||||
setFilterManager(data.query.filterManager);
|
||||
setExpressions(expressions);
|
||||
setUiActions(uiActions);
|
||||
setTimeFilter(data.query.timefilter.timefilter);
|
||||
|
|
|
@ -11,7 +11,6 @@ import {
|
|||
Capabilities,
|
||||
ChromeStart,
|
||||
HttpStart,
|
||||
I18nStart,
|
||||
IUiSettingsClient,
|
||||
OverlayStart,
|
||||
SavedObjectsStart,
|
||||
|
@ -19,12 +18,7 @@ import {
|
|||
} from '../../../core/public';
|
||||
import { TypesStart } from './vis_types';
|
||||
import { createGetterSetter } from '../../../plugins/kibana_utils/public';
|
||||
import {
|
||||
DataPublicPluginStart,
|
||||
FilterManager,
|
||||
IndexPatternsContract,
|
||||
TimefilterContract,
|
||||
} from '../../../plugins/data/public';
|
||||
import { DataPublicPluginStart, TimefilterContract } from '../../../plugins/data/public';
|
||||
import { UsageCollectionSetup } from '../../../plugins/usage_collection/public';
|
||||
import { ExpressionsStart } from '../../../plugins/expressions/public';
|
||||
import { UiActionsStart } from '../../../plugins/ui_actions/public';
|
||||
|
@ -48,20 +42,10 @@ export const [getSavedObjects, setSavedObjects] = createGetterSetter<SavedObject
|
|||
|
||||
export const [getTypes, setTypes] = createGetterSetter<TypesStart>('Types');
|
||||
|
||||
export const [getI18n, setI18n] = createGetterSetter<I18nStart>('I18n');
|
||||
|
||||
export const [getDocLinks, setDocLinks] = createGetterSetter<DocLinksStart>('DocLinks');
|
||||
|
||||
export const [getFilterManager, setFilterManager] = createGetterSetter<FilterManager>(
|
||||
'FilterManager'
|
||||
);
|
||||
|
||||
export const [getTimeFilter, setTimeFilter] = createGetterSetter<TimefilterContract>('TimeFilter');
|
||||
|
||||
export const [getIndexPatterns, setIndexPatterns] = createGetterSetter<IndexPatternsContract>(
|
||||
'IndexPatterns'
|
||||
);
|
||||
|
||||
export const [getSearch, setSearch] = createGetterSetter<DataPublicPluginStart['search']>('Search');
|
||||
|
||||
export const [getUsageCollector, setUsageCollector] = createGetterSetter<UsageCollectionSetup>(
|
||||
|
|
|
@ -7,26 +7,27 @@
|
|||
*/
|
||||
|
||||
import { SavedObject } from '../../../plugins/saved_objects/public';
|
||||
import { SearchSourceFields, TimefilterContract } from '../../../plugins/data/public';
|
||||
import {
|
||||
AggConfigOptions,
|
||||
IAggConfigs,
|
||||
SearchSourceFields,
|
||||
TimefilterContract,
|
||||
} from '../../../plugins/data/public';
|
||||
import { ExpressionAstExpression } from '../../expressions/public';
|
||||
|
||||
import { SerializedVis, Vis } from './vis';
|
||||
import { ExprVis } from './expressions/vis';
|
||||
import { SavedVisState, VisParams } from '../common/types';
|
||||
import { PersistedState } from './persisted_state';
|
||||
import { VisParams } from '../common';
|
||||
|
||||
export { Vis, SerializedVis, VisParams };
|
||||
|
||||
export interface VisualizationController {
|
||||
render(visData: any, visParams: any): Promise<void>;
|
||||
destroy(): void;
|
||||
isLoaded?(): Promise<void> | void;
|
||||
export interface SavedVisState {
|
||||
title: string;
|
||||
type: string;
|
||||
params: VisParams;
|
||||
aggs: AggConfigOptions[];
|
||||
}
|
||||
|
||||
export type VisualizationControllerConstructor = new (
|
||||
el: HTMLElement,
|
||||
vis: ExprVis
|
||||
) => VisualizationController;
|
||||
|
||||
export interface ISavedVis {
|
||||
id?: string;
|
||||
title: string;
|
||||
|
@ -40,13 +41,6 @@ export interface ISavedVis {
|
|||
|
||||
export interface VisSavedObject extends SavedObject, ISavedVis {}
|
||||
|
||||
export interface VisResponseValue {
|
||||
visType: string;
|
||||
visData: object;
|
||||
visConfig: object;
|
||||
params?: object;
|
||||
}
|
||||
|
||||
export interface VisToExpressionAstParams {
|
||||
timefilter: TimefilterContract;
|
||||
timeRange?: any;
|
||||
|
@ -57,3 +51,15 @@ export type VisToExpressionAst<TVisParams = VisParams> = (
|
|||
vis: Vis<TVisParams>,
|
||||
params: VisToExpressionAstParams
|
||||
) => Promise<ExpressionAstExpression> | ExpressionAstExpression;
|
||||
|
||||
export interface VisEditorOptionsProps<VisParamType = unknown> {
|
||||
aggs: IAggConfigs;
|
||||
hasHistogramAgg: boolean;
|
||||
isTabSelected: boolean;
|
||||
stateParams: VisParamType;
|
||||
vis: Vis;
|
||||
uiState: PersistedState;
|
||||
setValue<T extends keyof VisParamType>(paramName: T, value: VisParamType[T]): void;
|
||||
setValidity(isValid: boolean): void;
|
||||
setTouched(isTouched: boolean): void;
|
||||
}
|
||||
|
|
|
@ -22,7 +22,6 @@ import { i18n } from '@kbn/i18n';
|
|||
|
||||
import { PersistedState } from './persisted_state';
|
||||
import { getTypes, getAggs, getSearch, getSavedSearchLoader } from './services';
|
||||
import { VisType } from './vis_types';
|
||||
import {
|
||||
IAggConfigs,
|
||||
IndexPattern,
|
||||
|
@ -30,6 +29,7 @@ import {
|
|||
AggConfigOptions,
|
||||
SearchSourceFields,
|
||||
} from '../../../plugins/data/public';
|
||||
import { BaseVisType } from './vis_types';
|
||||
import { VisParams } from '../common/types';
|
||||
|
||||
export interface SerializedVisData {
|
||||
|
@ -71,14 +71,11 @@ const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?:
|
|||
type PartialVisState = Assign<SerializedVis, { data: Partial<SerializedVisData> }>;
|
||||
|
||||
export class Vis<TVisParams = VisParams> {
|
||||
public readonly type: VisType<TVisParams>;
|
||||
public readonly type: BaseVisType<TVisParams>;
|
||||
public readonly id?: string;
|
||||
public title: string = '';
|
||||
public description: string = '';
|
||||
public params: TVisParams;
|
||||
// Session state is for storing information that is transitory, and will not be saved with the visualization.
|
||||
// For instance, map bounds, which depends on the view port, browser window size, etc.
|
||||
public sessionState: Record<string, any> = {};
|
||||
public data: VisData = {};
|
||||
|
||||
public readonly uiState: PersistedState;
|
||||
|
|
136
src/plugins/visualizations/public/vis_schemas.ts
Normal file
136
src/plugins/visualizations/public/vis_schemas.ts
Normal file
|
@ -0,0 +1,136 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* and the Server Side Public License, v 1; you may not use this file except in
|
||||
* compliance with, at your election, the Elastic License or the Server Side
|
||||
* Public License, v 1.
|
||||
*/
|
||||
|
||||
import { SerializedFieldFormat } from '../../expressions/public';
|
||||
import { IAggConfig, search } from '../../data/public';
|
||||
|
||||
import { Vis, VisToExpressionAstParams } from './types';
|
||||
|
||||
const { isDateHistogramBucketAggConfig } = search.aggs;
|
||||
|
||||
interface SchemaConfigParams {
|
||||
precision?: number;
|
||||
useGeocentroid?: boolean;
|
||||
}
|
||||
|
||||
export interface SchemaConfig {
|
||||
accessor: number;
|
||||
label: string;
|
||||
format: SerializedFieldFormat;
|
||||
params: SchemaConfigParams;
|
||||
aggType: string;
|
||||
}
|
||||
|
||||
export interface Schemas {
|
||||
metric: SchemaConfig[];
|
||||
bucket?: SchemaConfig[];
|
||||
geo_centroid?: any[];
|
||||
group?: any[];
|
||||
params?: any[];
|
||||
radius?: any[];
|
||||
segment?: any[];
|
||||
split_column?: SchemaConfig[];
|
||||
split_row?: SchemaConfig[];
|
||||
width?: any[];
|
||||
// catch all for schema name
|
||||
[key: string]: any[] | undefined;
|
||||
}
|
||||
|
||||
export const getVisSchemas = <TVisParams>(
|
||||
vis: Vis<TVisParams>,
|
||||
{ timeRange, timefilter }: VisToExpressionAstParams
|
||||
): Schemas => {
|
||||
const createSchemaConfig = (accessor: number, agg: IAggConfig): SchemaConfig => {
|
||||
if (isDateHistogramBucketAggConfig(agg)) {
|
||||
agg.params.timeRange = timeRange;
|
||||
const bounds =
|
||||
agg.params.timeRange && agg.fieldIsTimeField()
|
||||
? timefilter.calculateBounds(agg.params.timeRange)
|
||||
: undefined;
|
||||
agg.buckets.setBounds(bounds);
|
||||
agg.buckets.setInterval(agg.params.interval);
|
||||
}
|
||||
|
||||
const hasSubAgg = [
|
||||
'derivative',
|
||||
'moving_avg',
|
||||
'serial_diff',
|
||||
'cumulative_sum',
|
||||
'sum_bucket',
|
||||
'avg_bucket',
|
||||
'min_bucket',
|
||||
'max_bucket',
|
||||
].includes(agg.type.name);
|
||||
|
||||
const formatAgg = hasSubAgg
|
||||
? agg.params.customMetric || agg.aggConfigs.getRequestAggById(agg.params.metricAgg)
|
||||
: agg;
|
||||
|
||||
const params: SchemaConfigParams = {};
|
||||
|
||||
if (agg.type.name === 'geohash_grid') {
|
||||
params.precision = agg.params.precision;
|
||||
params.useGeocentroid = agg.params.useGeocentroid;
|
||||
}
|
||||
|
||||
const label = agg.makeLabel && agg.makeLabel();
|
||||
|
||||
return {
|
||||
accessor,
|
||||
format: formatAgg.toSerializedFieldFormat(),
|
||||
params,
|
||||
label,
|
||||
aggType: agg.type.name,
|
||||
};
|
||||
};
|
||||
|
||||
let cnt = 0;
|
||||
const schemas: Schemas = {
|
||||
metric: [],
|
||||
};
|
||||
|
||||
if (!vis.data.aggs) {
|
||||
return schemas;
|
||||
}
|
||||
|
||||
const responseAggs = vis.data.aggs.getResponseAggs().filter((agg: IAggConfig) => agg.enabled);
|
||||
const isHierarchical = vis.isHierarchical();
|
||||
const metrics = responseAggs.filter((agg: IAggConfig) => agg.type.type === 'metrics');
|
||||
responseAggs.forEach((agg: IAggConfig) => {
|
||||
let skipMetrics = false;
|
||||
let schemaName = agg.schema;
|
||||
if (!schemaName) {
|
||||
if (agg.type.name === 'geo_centroid') {
|
||||
schemaName = 'geo_centroid';
|
||||
} else {
|
||||
cnt++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (schemaName === 'split') {
|
||||
// TODO: We should check if there's a better way then casting to `any` here
|
||||
schemaName = `split_${(vis.params as any).row ? 'row' : 'column'}`;
|
||||
skipMetrics = responseAggs.length - metrics.length > 1;
|
||||
}
|
||||
if (!schemas[schemaName]) {
|
||||
schemas[schemaName] = [];
|
||||
}
|
||||
if (!isHierarchical || agg.type.type !== 'metrics') {
|
||||
schemas[schemaName]!.push(createSchemaConfig(cnt++, agg));
|
||||
}
|
||||
if (isHierarchical && (agg.type.type !== 'metrics' || metrics.length === responseAggs.length)) {
|
||||
metrics.forEach((metric: any) => {
|
||||
const schemaConfig = createSchemaConfig(cnt++, metric);
|
||||
if (!skipMetrics) {
|
||||
schemas.metric.push(schemaConfig);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
return schemas;
|
||||
};
|
|
@ -16,7 +16,16 @@ describe('BaseVisType', () => {
|
|||
name: 'test',
|
||||
title: 'test',
|
||||
description: 'test',
|
||||
visualization: {} as any,
|
||||
visConfig: {
|
||||
defaults: {},
|
||||
},
|
||||
toExpressionAst: () => ({
|
||||
type: 'expression',
|
||||
chain: [],
|
||||
}),
|
||||
editorConfig: {
|
||||
editor: 'custom',
|
||||
},
|
||||
});
|
||||
}).toThrow();
|
||||
});
|
||||
|
|
|
@ -9,54 +9,9 @@
|
|||
import { defaultsDeep } from 'lodash';
|
||||
|
||||
import { VisParams } from '../types';
|
||||
import { VisType, VisTypeOptions, VisGroups } from './types';
|
||||
import { VisTypeDefinition, VisTypeOptions, VisGroups } from './types';
|
||||
import { Schemas } from './schemas';
|
||||
|
||||
interface CommonBaseVisTypeOptions<TVisParams>
|
||||
extends Pick<
|
||||
VisType<TVisParams>,
|
||||
| 'description'
|
||||
| 'getInfoMessage'
|
||||
| 'getSupportedTriggers'
|
||||
| 'hierarchicalData'
|
||||
| 'icon'
|
||||
| 'image'
|
||||
| 'inspectorAdapters'
|
||||
| 'name'
|
||||
| 'requestHandler'
|
||||
| 'responseHandler'
|
||||
| 'setup'
|
||||
| 'title'
|
||||
>,
|
||||
Pick<
|
||||
Partial<VisType<TVisParams>>,
|
||||
| 'editorConfig'
|
||||
| 'hidden'
|
||||
| 'stage'
|
||||
| 'getUsedIndexPattern'
|
||||
| 'useCustomNoDataScreen'
|
||||
| 'visConfig'
|
||||
| 'group'
|
||||
| 'titleInWizard'
|
||||
| 'note'
|
||||
> {
|
||||
options?: Partial<VisType<TVisParams>['options']>;
|
||||
}
|
||||
|
||||
interface ExpressionBaseVisTypeOptions<TVisParams> extends CommonBaseVisTypeOptions<TVisParams> {
|
||||
toExpressionAst: VisType<TVisParams>['toExpressionAst'];
|
||||
visualization?: undefined;
|
||||
}
|
||||
|
||||
interface VisualizationBaseVisTypeOptions<TVisParams> extends CommonBaseVisTypeOptions<TVisParams> {
|
||||
toExpressionAst?: undefined;
|
||||
visualization: VisType<TVisParams>['visualization'];
|
||||
}
|
||||
|
||||
export type BaseVisTypeOptions<TVisParams = VisParams> =
|
||||
| ExpressionBaseVisTypeOptions<TVisParams>
|
||||
| VisualizationBaseVisTypeOptions<TVisParams>;
|
||||
|
||||
const defaultOptions: VisTypeOptions = {
|
||||
showTimePicker: true,
|
||||
showQueryBar: true,
|
||||
|
@ -65,7 +20,7 @@ const defaultOptions: VisTypeOptions = {
|
|||
hierarchicalData: false, // we should get rid of this i guess ?
|
||||
};
|
||||
|
||||
export class BaseVisType<TVisParams = VisParams> implements VisType<TVisParams> {
|
||||
export class BaseVisType<TVisParams = VisParams> {
|
||||
public readonly name;
|
||||
public readonly title;
|
||||
public readonly description;
|
||||
|
@ -76,23 +31,20 @@ export class BaseVisType<TVisParams = VisParams> implements VisType<TVisParams>
|
|||
public readonly stage;
|
||||
public readonly group;
|
||||
public readonly titleInWizard;
|
||||
public readonly options;
|
||||
public readonly visualization;
|
||||
public readonly options: VisTypeOptions;
|
||||
public readonly visConfig;
|
||||
public readonly editorConfig;
|
||||
public hidden;
|
||||
public readonly requestHandler;
|
||||
public readonly responseHandler;
|
||||
public readonly requiresSearch;
|
||||
public readonly hierarchicalData;
|
||||
public readonly setup;
|
||||
public readonly getUsedIndexPattern;
|
||||
public readonly useCustomNoDataScreen;
|
||||
public readonly inspectorAdapters;
|
||||
public readonly toExpressionAst;
|
||||
public readonly getInfoMessage;
|
||||
public readonly schemas;
|
||||
|
||||
constructor(opts: BaseVisTypeOptions<TVisParams>) {
|
||||
constructor(opts: VisTypeDefinition<TVisParams>) {
|
||||
if (!opts.icon && !opts.image) {
|
||||
throw new Error('vis_type must define its icon or image');
|
||||
}
|
||||
|
@ -104,7 +56,6 @@ export class BaseVisType<TVisParams = VisParams> implements VisType<TVisParams>
|
|||
this.title = opts.title;
|
||||
this.icon = opts.icon;
|
||||
this.image = opts.image;
|
||||
this.visualization = opts.visualization;
|
||||
this.visConfig = defaultsDeep({}, opts.visConfig, { defaults: {} });
|
||||
this.editorConfig = defaultsDeep({}, opts.editorConfig, { collections: {} });
|
||||
this.options = defaultsDeep({}, opts.options, defaultOptions);
|
||||
|
@ -112,20 +63,14 @@ export class BaseVisType<TVisParams = VisParams> implements VisType<TVisParams>
|
|||
this.group = opts.group ?? VisGroups.AGGBASED;
|
||||
this.titleInWizard = opts.titleInWizard ?? '';
|
||||
this.hidden = opts.hidden ?? false;
|
||||
this.requestHandler = opts.requestHandler ?? 'courier';
|
||||
this.responseHandler = opts.responseHandler ?? 'none';
|
||||
this.requiresSearch = opts.requiresSearch ?? false;
|
||||
this.setup = opts.setup;
|
||||
this.hierarchicalData = opts.hierarchicalData ?? false;
|
||||
this.getUsedIndexPattern = opts.getUsedIndexPattern;
|
||||
this.useCustomNoDataScreen = opts.useCustomNoDataScreen ?? false;
|
||||
this.inspectorAdapters = opts.inspectorAdapters;
|
||||
this.toExpressionAst = opts.toExpressionAst;
|
||||
this.getInfoMessage = opts.getInfoMessage;
|
||||
|
||||
this.schemas = new Schemas(this.editorConfig?.schemas ?? []);
|
||||
}
|
||||
|
||||
public get requiresSearch(): boolean {
|
||||
return this.requestHandler !== 'none';
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,5 @@
|
|||
export * from './types_service';
|
||||
export { Schemas } from './schemas';
|
||||
export { VisGroups } from './types';
|
||||
export type { VisType, ISchemas, Schema } from './types';
|
||||
export type { BaseVisTypeOptions } from './base_vis_type';
|
||||
export type { ReactVisTypeOptions } from './react_vis_type';
|
||||
export { BaseVisType } from './base_vis_type';
|
||||
export type { VisTypeDefinition, ISchemas, Schema } from './types';
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue