[7.x] TypeScript cleanup in visualizations plugin (#78428) | Implement tagcloud renderer (#77910) | Fix types (#78619) (#78666)

* TypeScript cleanup in visualizations plugin (#78428)

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

* Implement tagcloud renderer (#77910)

* Implement toExpressionAst for tagcloud

* Implement tagcloud vis renderer

* Use resize observer

* Use common no data message

* Update build_pipeline.test

* Update tag cloud tests

* Revert "Use common no data message"

This reverts commit fddf019575.

* Update interpreter functional tests

* Add tests for toExpressionAst fn

* Use throttled chart update

* Update renderer

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>

* Fix types (#78619)

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: Daniil Suleiman <31325372+sulemanof@users.noreply.github.com>
This commit is contained in:
Tim Roes 2020-09-29 15:23:00 +02:00 committed by GitHub
parent 0b3c39e64f
commit 1d48afc530
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
43 changed files with 740 additions and 359 deletions

View file

@ -19,12 +19,15 @@
import { i18n } from '@kbn/i18n';
import { BaseVisTypeOptions } from 'src/plugins/visualizations/public';
import { createInputControlVisController } from './vis_controller';
import { getControlsTab } from './components/editor/controls_tab';
import { OptionsTab } from './components/editor/options_tab';
import { InputControlVisDependencies } from './plugin';
export function createInputControlVisTypeDefinition(deps: InputControlVisDependencies) {
export function createInputControlVisTypeDefinition(
deps: InputControlVisDependencies
): BaseVisTypeOptions {
const InputControlVisController = createInputControlVisController(deps);
const ControlsTab = getControlsTab(deps);

View file

@ -31,12 +31,12 @@ import { RangeControl } from './control/range_control_factory';
import { ListControl } from './control/list_control_factory';
import { InputControlVisDependencies } from './plugin';
import { FilterManager, Filter } from '../../data/public';
import { VisParams, Vis } from '../../visualizations/public';
import { VisParams, ExprVis } from '../../visualizations/public';
export const createInputControlVisController = (deps: InputControlVisDependencies) => {
return class InputControlVisController {
private I18nContext?: I18nStart['Context'];
private isLoaded = false;
private _isLoaded = false;
controls: Array<RangeControl | ListControl>;
queryBarUpdateHandler: () => void;
@ -45,7 +45,7 @@ export const createInputControlVisController = (deps: InputControlVisDependencie
timeFilterSubscription: Subscription;
visParams?: VisParams;
constructor(public el: Element, public vis: Vis) {
constructor(public el: Element, public vis: ExprVis) {
this.controls = [];
this.queryBarUpdateHandler = this.updateControlsFromKbn.bind(this);
@ -58,7 +58,7 @@ export const createInputControlVisController = (deps: InputControlVisDependencie
.getTimeUpdate$()
.subscribe(() => {
if (this.visParams?.useTimeFilter) {
this.isLoaded = false;
this._isLoaded = false;
}
});
}
@ -68,11 +68,11 @@ export const createInputControlVisController = (deps: InputControlVisDependencie
const [{ i18n }] = await deps.core.getStartServices();
this.I18nContext = i18n.Context;
}
if (!this.isLoaded || !isEqual(visParams, this.visParams)) {
if (!this._isLoaded || !isEqual(visParams, this.visParams)) {
this.visParams = visParams;
this.controls = [];
this.controls = await this.initControls();
this.isLoaded = true;
this._isLoaded = true;
}
this.drawVis();
}

View file

@ -18,13 +18,14 @@
*/
import { i18n } from '@kbn/i18n';
import { BaseVisTypeOptions } from 'src/plugins/visualizations/public';
import { MetricVisOptions } from './components/metric_vis_options';
import { ColorSchemas, colorSchemas, ColorModes } from '../../charts/public';
import { AggGroupNames } from '../../data/public';
import { Schemas } from '../../vis_default_editor/public';
import { toExpressionAst } from './to_ast';
export const createMetricVisTypeDefinition = () => ({
export const createMetricVisTypeDefinition = (): BaseVisTypeOptions => ({
name: 'metric',
title: i18n.translate('visTypeMetric.metricTitle', { defaultMessage: 'Metric' }),
icon: 'visMetric',

View file

@ -120,7 +120,7 @@ describe('Table Vis - Controller', () => {
function getRangeVis(params?: object) {
return ({
type: tableVisTypeDefinition,
params: Object.assign({}, tableVisTypeDefinition.visConfig.defaults, params),
params: Object.assign({}, tableVisTypeDefinition.visConfig?.defaults, params),
data: {
aggs: createAggConfigs(stubIndexPattern, [
{ type: 'count', schema: 'metric' },

View file

@ -20,7 +20,7 @@ import { CoreSetup, PluginInitializerContext } from 'kibana/public';
import { i18n } from '@kbn/i18n';
import { AggGroupNames } from '../../data/public';
import { Schemas } from '../../vis_default_editor/public';
import { Vis } from '../../visualizations/public';
import { BaseVisTypeOptions, Vis } from '../../visualizations/public';
import { tableVisResponseHandler } from './table_vis_response_handler';
// @ts-ignore
import tableVisTemplate from './table_vis.html';
@ -28,9 +28,11 @@ import { TableOptions } from './components/table_vis_options_lazy';
import { getTableVisualizationControllerClass } from './vis_controller';
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
export function getTableVisTypeDefinition(core: CoreSetup, context: PluginInitializerContext) {
export function getTableVisTypeDefinition(
core: CoreSetup,
context: PluginInitializerContext
): BaseVisTypeOptions {
return {
type: 'table',
name: 'table',
title: i18n.translate('visTypeTable.tableVisTitle', {
defaultMessage: 'Data Table',

View file

@ -64,7 +64,7 @@ export function getTableVisualizationControllerClass(
}
}
async render(esResponse: object, visParams: VisParams) {
async render(esResponse: object, visParams: VisParams): Promise<void> {
getKibanaLegacy().loadFontAwesome();
await this.initLocalAngular();

View file

@ -2,25 +2,9 @@
exports[`interpreter/functions#tagcloud returns an object with the correct structure 1`] = `
Object {
"as": "visualization",
"as": "tagloud_vis",
"type": "render",
"value": Object {
"params": Object {
"listenOnChange": true,
},
"visConfig": Object {
"maxFontSize": 72,
"metric": Object {
"accessor": 0,
"format": Object {
"id": "number",
},
},
"minFontSize": 18,
"orientation": "single",
"scale": "linear",
"showLabel": true,
},
"visData": Object {
"columns": Array [
Object {
@ -35,6 +19,19 @@ Object {
],
"type": "kibana_datatable",
},
"visParams": Object {
"maxFontSize": 72,
"metric": Object {
"accessor": 0,
"format": Object {
"id": "number",
},
},
"minFontSize": 18,
"orientation": "single",
"scale": "linear",
"showLabel": true,
},
"visType": "tagcloud",
},
}

View file

@ -0,0 +1,171 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`tagcloud vis toExpressionAst function should match snapshot params fulfilled 1`] = `
Object {
"chain": Array [
Object {
"arguments": Object {
"aggConfigs": Array [
"[]",
],
"includeFormatHints": Array [
false,
],
"index": Array [
"123",
],
"metricsAtAllLevels": Array [
false,
],
"partialRows": Array [
false,
],
},
"function": "esaggs",
"type": "function",
},
Object {
"arguments": Object {
"bucket": Array [
Object {
"chain": Array [
Object {
"arguments": Object {
"accessor": Array [
0,
],
"format": Array [
"terms",
],
"formatParams": Array [
"{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\"}",
],
},
"function": "visdimension",
"type": "function",
},
],
"type": "expression",
},
],
"maxFontSize": Array [
15,
],
"metric": Array [
Object {
"chain": Array [
Object {
"arguments": Object {
"accessor": Array [
1,
],
"format": Array [
"number",
],
},
"function": "visdimension",
"type": "function",
},
],
"type": "expression",
},
],
"minFontSize": Array [
5,
],
"orientation": Array [
"single",
],
"scale": Array [
"linear",
],
"showLabel": Array [
true,
],
},
"function": "tagcloud",
"type": "function",
},
],
"type": "expression",
}
`;
exports[`tagcloud vis toExpressionAst function should match snapshot without params 1`] = `
Object {
"chain": Array [
Object {
"arguments": Object {
"aggConfigs": Array [
"[]",
],
"includeFormatHints": Array [
false,
],
"index": Array [
"123",
],
"metricsAtAllLevels": Array [
false,
],
"partialRows": Array [
false,
],
},
"function": "esaggs",
"type": "function",
},
Object {
"arguments": Object {
"bucket": Array [
Object {
"chain": Array [
Object {
"arguments": Object {
"accessor": Array [
0,
],
"format": Array [
"terms",
],
"formatParams": Array [
"{\\"id\\":\\"string\\",\\"otherBucketLabel\\":\\"Other\\",\\"missingBucketLabel\\":\\"Missing\\"}",
],
},
"function": "visdimension",
"type": "function",
},
],
"type": "expression",
},
],
"metric": Array [
Object {
"chain": Array [
Object {
"arguments": Object {
"accessor": Array [
1,
],
"format": Array [
"number",
],
},
"function": "visdimension",
"type": "function",
},
],
"type": "expression",
},
],
"showLabel": Array [
false,
],
},
"function": "tagcloud",
"type": "function",
},
],
"type": "expression",
}
`;

View file

@ -1,14 +0,0 @@
.tgcVis {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.tgcVisLabel {
width: 100%;
text-align: center;
font-weight: $euiFontWeightBold;
}

View file

@ -28,7 +28,7 @@ export class Label extends Component {
render() {
return (
<div
className="tgcVisLabel"
className="tgcChart__label"
style={{ display: this.state.shouldShowLabel ? 'block' : 'none' }}
>
{this.state.label}

View file

@ -0,0 +1,26 @@
// Prefix all styles with "tgc" to avoid conflicts.
// Examples
// tgcChart
// tgcChart__legend
// tgcChart__legend--small
// tgcChart__legend-isLoading
.tgcChart__container, .tgcChart__wrapper {
flex: 1 1 0;
display: flex;
}
.tgcChart {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
overflow: hidden;
}
.tgcChart__label {
width: 100%;
text-align: center;
font-weight: $euiFontWeightBold;
}

View file

@ -0,0 +1,84 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React, { useEffect, useMemo, useRef } from 'react';
import { EuiResizeObserver } from '@elastic/eui';
import { throttle } from 'lodash';
import { TagCloudVisDependencies } from '../plugin';
import { TagCloudVisRenderValue } from '../tag_cloud_fn';
// @ts-ignore
import { TagCloudVisualization } from './tag_cloud_visualization';
import './tag_cloud.scss';
type TagCloudChartProps = TagCloudVisDependencies &
TagCloudVisRenderValue & {
fireEvent: (event: any) => void;
renderComplete: () => void;
};
export const TagCloudChart = ({
colors,
visData,
visParams,
fireEvent,
renderComplete,
}: TagCloudChartProps) => {
const chartDiv = useRef<HTMLDivElement>(null);
const visController = useRef<any>(null);
useEffect(() => {
visController.current = new TagCloudVisualization(chartDiv.current, colors, fireEvent);
return () => {
visController.current.destroy();
visController.current = null;
};
}, [colors, fireEvent]);
useEffect(() => {
if (visController.current) {
visController.current.render(visData, visParams).then(renderComplete);
}
}, [visData, visParams, renderComplete]);
const updateChartSize = useMemo(
() =>
throttle(() => {
if (visController.current) {
visController.current.render().then(renderComplete);
}
}, 300),
[renderComplete]
);
return (
<EuiResizeObserver onResize={updateChartSize}>
{(resizeRef) => (
<div className="tgcChart__wrapper" ref={resizeRef}>
<div className="tgcChart__container" ref={chartDiv} />
</div>
)}
</EuiResizeObserver>
);
};
// default export required for React.Lazy
// eslint-disable-next-line import/no-default-export
export { TagCloudChart as default };

View file

@ -32,126 +32,138 @@ import d3 from 'd3';
const MAX_TAG_COUNT = 200;
export function createTagCloudVisualization({ colors }) {
const colorScale = d3.scale.ordinal().range(colors.seedColors);
return class TagCloudVisualization {
constructor(node, vis) {
this._containerNode = node;
export class TagCloudVisualization {
constructor(node, colors, fireEvent) {
this._containerNode = node;
const cloudRelativeContainer = document.createElement('div');
cloudRelativeContainer.classList.add('tgcVis');
cloudRelativeContainer.setAttribute('style', 'position: relative');
const cloudContainer = document.createElement('div');
cloudContainer.classList.add('tgcVis');
cloudContainer.setAttribute('data-test-subj', 'tagCloudVisualization');
this._containerNode.classList.add('visChart--vertical');
cloudRelativeContainer.appendChild(cloudContainer);
this._containerNode.appendChild(cloudRelativeContainer);
const cloudRelativeContainer = document.createElement('div');
cloudRelativeContainer.classList.add('tgcChart');
cloudRelativeContainer.setAttribute('style', 'position: relative');
const cloudContainer = document.createElement('div');
cloudContainer.classList.add('tgcChart');
cloudContainer.setAttribute('data-test-subj', 'tagCloudVisualization');
this._containerNode.classList.add('visChart--vertical');
cloudRelativeContainer.appendChild(cloudContainer);
this._containerNode.appendChild(cloudRelativeContainer);
this._vis = vis;
this._truncated = false;
this._tagCloud = new TagCloud(cloudContainer, colorScale);
this._tagCloud.on('select', (event) => {
if (!this._visParams.bucket) {
return;
}
this._vis.API.events.filter({
table: event.meta.data,
column: 0,
row: event.meta.rowIndex,
});
});
this._renderComplete$ = Rx.fromEvent(this._tagCloud, 'renderComplete');
this._feedbackNode = document.createElement('div');
this._containerNode.appendChild(this._feedbackNode);
this._feedbackMessage = React.createRef();
render(
<I18nProvider>
<FeedbackMessage ref={this._feedbackMessage} />
</I18nProvider>,
this._feedbackNode
);
this._labelNode = document.createElement('div');
this._containerNode.appendChild(this._labelNode);
this._label = React.createRef();
render(<Label ref={this._label} />, this._labelNode);
}
async render(data, visParams) {
this._updateParams(visParams);
this._updateData(data);
this._resize();
await this._renderComplete$.pipe(take(1)).toPromise();
if (data.columns.length !== 2) {
this._feedbackMessage.current.setState({
shouldShowTruncate: false,
shouldShowIncomplete: false,
});
this._truncated = false;
this._tagCloud = new TagCloud(cloudContainer, d3.scale.ordinal().range(colors.seedColors));
this._tagCloud.on('select', (event) => {
if (!this._visParams.bucket) {
return;
}
fireEvent({
name: 'filterBucket',
data: {
data: [
{
table: event.meta.data,
column: 0,
row: event.meta.rowIndex,
},
],
},
});
});
this._renderComplete$ = Rx.fromEvent(this._tagCloud, 'renderComplete');
this._feedbackNode = document.createElement('div');
this._containerNode.appendChild(this._feedbackNode);
this._feedbackMessage = React.createRef();
render(
<I18nProvider>
<FeedbackMessage ref={this._feedbackMessage} />
</I18nProvider>,
this._feedbackNode
);
this._labelNode = document.createElement('div');
this._containerNode.appendChild(this._labelNode);
this._label = React.createRef();
render(<Label ref={this._label} />, this._labelNode);
}
async render(data, visParams) {
if (data && visParams) {
this._updateParams(visParams);
this._updateData(data);
}
this._resize();
await this._renderComplete$.pipe(take(1)).toPromise();
if (data && data.columns.length !== 2 && this._feedbackMessage.current) {
this._feedbackMessage.current.setState({
shouldShowTruncate: false,
shouldShowIncomplete: false,
});
return;
}
if (data && this._label.current) {
this._label.current.setState({
label: `${data.columns[0].name} - ${data.columns[1].name}`,
shouldShowLabel: visParams.showLabel,
});
}
if (this._feedbackMessage.current) {
this._feedbackMessage.current.setState({
shouldShowTruncate: this._truncated,
shouldShowIncomplete: this._tagCloud.getStatus() === TagCloud.STATUS.INCOMPLETE,
});
}
}
destroy() {
this._tagCloud.destroy();
unmountComponentAtNode(this._feedbackNode);
unmountComponentAtNode(this._labelNode);
destroy() {
this._tagCloud.destroy();
unmountComponentAtNode(this._feedbackNode);
unmountComponentAtNode(this._labelNode);
}
_updateData(data) {
if (!data || !data.rows.length) {
this._tagCloud.setData([]);
return;
}
_updateData(data) {
if (!data || !data.rows.length) {
this._tagCloud.setData([]);
return;
}
const bucket = this._visParams.bucket;
const metric = this._visParams.metric;
const bucketFormatter = bucket ? getFormatService().deserialize(bucket.format) : null;
const tagColumn = bucket ? data.columns[bucket.accessor].id : -1;
const metricColumn = data.columns[metric.accessor].id;
const tags = data.rows.map((row, rowIndex) => {
const tag = row[tagColumn] === undefined ? 'all' : row[tagColumn];
const metric = row[metricColumn];
return {
displayText: bucketFormatter ? bucketFormatter.convert(tag, 'text') : tag,
rawText: tag,
value: metric,
meta: {
data: data,
rowIndex: rowIndex,
},
};
});
const bucket = this._visParams.bucket;
const metric = this._visParams.metric;
const bucketFormatter = bucket ? getFormatService().deserialize(bucket.format) : null;
const tagColumn = bucket ? data.columns[bucket.accessor].id : -1;
const metricColumn = data.columns[metric.accessor].id;
const tags = data.rows.map((row, rowIndex) => {
const tag = row[tagColumn] === undefined ? 'all' : row[tagColumn];
const metric = row[metricColumn];
return {
displayText: bucketFormatter ? bucketFormatter.convert(tag, 'text') : tag,
rawText: tag,
value: metric,
meta: {
data: data,
rowIndex: rowIndex,
},
};
});
if (tags.length > MAX_TAG_COUNT) {
tags.length = MAX_TAG_COUNT;
this._truncated = true;
} else {
this._truncated = false;
}
this._tagCloud.setData(tags);
if (tags.length > MAX_TAG_COUNT) {
tags.length = MAX_TAG_COUNT;
this._truncated = true;
} else {
this._truncated = false;
}
_updateParams(visParams) {
this._visParams = visParams;
this._tagCloud.setOptions(visParams);
}
this._tagCloud.setData(tags);
}
_resize() {
this._tagCloud.resize();
}
};
_updateParams(visParams) {
this._visParams = visParams;
this._tagCloud.setOptions(visParams);
}
_resize() {
this._tagCloud.resize();
}
}

View file

@ -19,8 +19,7 @@
import 'jest-canvas-mock';
import { createTagCloudVisTypeDefinition } from '../tag_cloud_type';
import { createTagCloudVisualization } from './tag_cloud_visualization';
import { TagCloudVisualization } from './tag_cloud_visualization';
import { setFormatService } from '../services';
import { dataPluginMock } from '../../../data/public/mocks';
import { setHTMLElementOffset, setSVGElementGetBBox } from '../../../../test_utils/public';
@ -29,7 +28,7 @@ const seedColors = ['#00a69b', '#57c17b', '#6f87d8', '#663db8', '#bc52bc', '#9e3
describe('TagCloudVisualizationTest', () => {
let domNode;
let vis;
let visParams;
let SVGElementGetBBoxSpyInstance;
let HTMLElementOffsetMockInstance;
@ -52,11 +51,6 @@ describe('TagCloudVisualizationTest', () => {
{ 'col-0': 'BR', 'col-1': 3 },
],
};
const TagCloudVisualization = createTagCloudVisualization({
colors: {
seedColors,
},
});
const originTransformSVGElement = window.SVGElement.prototype.transform;
@ -82,67 +76,44 @@ describe('TagCloudVisualizationTest', () => {
describe('TagCloudVisualization - basics', () => {
beforeEach(async () => {
const visType = createTagCloudVisTypeDefinition({ colors: seedColors });
setupDOM(512, 512);
vis = {
type: visType,
params: {
bucket: { accessor: 0, format: {} },
metric: { accessor: 0, format: {} },
scale: 'linear',
orientation: 'single',
},
data: {},
visParams = {
bucket: { accessor: 0, format: {} },
metric: { accessor: 0, format: {} },
scale: 'linear',
orientation: 'single',
};
});
test('simple draw', async () => {
const tagcloudVisualization = new TagCloudVisualization(domNode, vis);
await tagcloudVisualization.render(dummyTableGroup, vis.params, {
resize: false,
params: true,
aggs: true,
data: true,
uiState: false,
const tagcloudVisualization = new TagCloudVisualization(domNode, {
seedColors,
});
await tagcloudVisualization.render(dummyTableGroup, visParams);
const svgNode = domNode.querySelector('svg');
expect(svgNode.outerHTML).toMatchSnapshot();
});
test('with resize', async () => {
const tagcloudVisualization = new TagCloudVisualization(domNode, vis);
await tagcloudVisualization.render(dummyTableGroup, vis.params, {
resize: false,
params: true,
aggs: true,
data: true,
uiState: false,
const tagcloudVisualization = new TagCloudVisualization(domNode, {
seedColors,
});
await tagcloudVisualization.render(dummyTableGroup, visParams);
await tagcloudVisualization.render(dummyTableGroup, vis.params, {
resize: true,
params: false,
aggs: false,
data: false,
uiState: false,
});
await tagcloudVisualization.render(dummyTableGroup, visParams);
const svgNode = domNode.querySelector('svg');
expect(svgNode.outerHTML).toMatchSnapshot();
});
test('with param change', async function () {
const tagcloudVisualization = new TagCloudVisualization(domNode, vis);
await tagcloudVisualization.render(dummyTableGroup, vis.params, {
resize: false,
params: true,
aggs: true,
data: true,
uiState: false,
const tagcloudVisualization = new TagCloudVisualization(domNode, {
seedColors,
});
await tagcloudVisualization.render(dummyTableGroup, visParams);
SVGElementGetBBoxSpyInstance.mockRestore();
SVGElementGetBBoxSpyInstance = setSVGElementGetBBox(256, 368);
@ -150,15 +121,9 @@ describe('TagCloudVisualizationTest', () => {
HTMLElementOffsetMockInstance.mockRestore();
HTMLElementOffsetMockInstance = setHTMLElementOffset(256, 386);
vis.params.orientation = 'right angled';
vis.params.minFontSize = 70;
await tagcloudVisualization.render(dummyTableGroup, vis.params, {
resize: true,
params: true,
aggs: false,
data: false,
uiState: false,
});
visParams.orientation = 'right angled';
visParams.minFontSize = 70;
await tagcloudVisualization.render(dummyTableGroup, visParams);
const svgNode = domNode.querySelector('svg');
expect(svgNode.outerHTML).toMatchSnapshot();

View file

@ -1,8 +0,0 @@
// Prefix all styles with "tgc" to avoid conflicts.
// Examples
// tgcChart
// tgcChart__legend
// tgcChart__legend--small
// tgcChart__legend-isLoading
@import './tag_cloud';

View file

@ -23,12 +23,11 @@ import { VisualizationsSetup } from '../../visualizations/public';
import { ChartsPluginSetup } from '../../charts/public';
import { createTagCloudFn } from './tag_cloud_fn';
import { createTagCloudVisTypeDefinition } from './tag_cloud_type';
import { tagCloudVisTypeDefinition } from './tag_cloud_type';
import { DataPublicPluginStart } from '../../data/public';
import { setFormatService } from './services';
import { ConfigSchema } from '../config';
import './index.scss';
import { getTagCloudVisRenderer } from './tag_cloud_vis_renderer';
/** @internal */
export interface TagCloudPluginSetupDependencies {
@ -63,9 +62,8 @@ export class TagCloudPlugin implements Plugin<void, void> {
colors: charts.colors,
};
expressions.registerFunction(createTagCloudFn);
visualizations.createBaseVisualization(
createTagCloudVisTypeDefinition(visualizationDependencies)
);
expressions.registerRenderer(getTagCloudVisRenderer(visualizationDependencies));
visualizations.createBaseVisualization(tagCloudVisTypeDefinition);
}
public start(core: CoreStart, { data }: TagCloudVisPluginStartDependencies) {

View file

@ -26,22 +26,23 @@ const name = 'tagcloud';
interface Arguments extends TagCloudVisParams {
metric: any; // these aren't typed yet
bucket: any; // these aren't typed yet
bucket?: any; // these aren't typed yet
}
interface RenderValue {
export interface TagCloudVisRenderValue {
visType: typeof name;
visData: KibanaDatatable;
visConfig: Arguments;
params: any;
visParams: Arguments;
}
export const createTagCloudFn = (): ExpressionFunctionDefinition<
export type TagcloudExpressionFunctionDefinition = ExpressionFunctionDefinition<
typeof name,
KibanaDatatable,
Arguments,
Render<RenderValue>
> => ({
Render<TagCloudVisRenderValue>
>;
export const createTagCloudFn = (): TagcloudExpressionFunctionDefinition => ({
name,
type: 'render',
inputTypes: ['kibana_datatable'],
@ -95,7 +96,7 @@ export const createTagCloudFn = (): ExpressionFunctionDefinition<
},
},
fn(input, args) {
const visConfig = {
const visParams = {
scale: args.scale,
orientation: args.orientation,
minFontSize: args.minFontSize,
@ -105,19 +106,16 @@ export const createTagCloudFn = (): ExpressionFunctionDefinition<
} as Arguments;
if (args.bucket !== undefined) {
visConfig.bucket = args.bucket;
visParams.bucket = args.bucket;
}
return {
type: 'render',
as: 'visualization',
as: 'tagloud_vis',
value: {
visData: input,
visType: name,
visConfig,
params: {
listenOnChange: true,
},
visParams,
},
};
},

View file

@ -20,15 +20,12 @@
import { i18n } from '@kbn/i18n';
import { Schemas } from '../../vis_default_editor/public';
import { VIS_EVENT_TO_TRIGGER } from '../../visualizations/public';
import { TagCloudOptions } from './components/tag_cloud_options';
import { VIS_EVENT_TO_TRIGGER } from '../../../plugins/visualizations/public';
import { toExpressionAst } from './to_ast';
// @ts-ignore
import { createTagCloudVisualization } from './components/tag_cloud_visualization';
import { TagCloudVisDependencies } from './plugin';
export const createTagCloudVisTypeDefinition = (deps: TagCloudVisDependencies) => ({
export const tagCloudVisTypeDefinition = {
name: 'tagcloud',
title: i18n.translate('visTypeTagCloud.vis.tagCloudTitle', { defaultMessage: 'Tag Cloud' }),
icon: 'visTagCloud',
@ -47,7 +44,7 @@ export const createTagCloudVisTypeDefinition = (deps: TagCloudVisDependencies) =
showLabel: true,
},
},
visualization: createTagCloudVisualization(deps),
toExpressionAst,
editorConfig: {
collections: {
scales: [
@ -123,5 +120,4 @@ export const createTagCloudVisTypeDefinition = (deps: TagCloudVisDependencies) =
},
]),
},
useCustomNoDataScreen: true,
});
};

View file

@ -0,0 +1,54 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import React, { lazy } from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { VisualizationContainer } from '../../visualizations/public';
import { ExpressionRenderDefinition } from '../../expressions/common/expression_renderers';
import { TagCloudVisDependencies } from './plugin';
import { TagCloudVisRenderValue } from './tag_cloud_fn';
// @ts-ignore
const TagCloudChart = lazy(() => import('./components/tag_cloud_chart'));
export const getTagCloudVisRenderer: (
deps: TagCloudVisDependencies
) => ExpressionRenderDefinition<TagCloudVisRenderValue> = ({ colors }) => ({
name: 'tagloud_vis',
displayName: 'Tag Cloud visualization',
reuseDomNode: true,
render: async (domNode, config, handlers) => {
handlers.onDestroy(() => {
unmountComponentAtNode(domNode);
});
render(
<VisualizationContainer>
<TagCloudChart
{...config}
colors={colors}
renderComplete={handlers.done}
fireEvent={handlers.event}
/>
</VisualizationContainer>,
domNode
);
},
});

View file

@ -0,0 +1,84 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { Vis } from 'src/plugins/visualizations/public';
import { toExpressionAst } from './to_ast';
import { TagCloudVisParams } from './types';
const mockSchemas = {
metric: [{ accessor: 1, format: { id: 'number' }, params: {}, label: 'Count', aggType: 'count' }],
segment: [
{
accessor: 0,
format: {
id: 'terms',
params: {
id: 'string',
otherBucketLabel: 'Other',
missingBucketLabel: 'Missing',
},
},
params: {},
label: 'products.product_name.keyword: Descending',
aggType: 'terms',
},
],
};
jest.mock('../../visualizations/public', () => ({
getVisSchemas: () => mockSchemas,
}));
describe('tagcloud vis toExpressionAst function', () => {
let vis: Vis<TagCloudVisParams>;
beforeEach(() => {
vis = {
isHierarchical: () => false,
type: {},
params: {
showLabel: false,
},
data: {
indexPattern: { id: '123' },
aggs: {
getResponseAggs: () => [],
aggs: [],
},
},
} as any;
});
it('should match snapshot without params', () => {
const actual = toExpressionAst(vis, {} as any);
expect(actual).toMatchSnapshot();
});
it('should match snapshot params fulfilled', () => {
vis.params = {
scale: 'linear',
orientation: 'single',
minFontSize: 5,
maxFontSize: 15,
showLabel: true,
};
const actual = toExpressionAst(vis, {} as any);
expect(actual).toMatchSnapshot();
});
});

View file

@ -0,0 +1,60 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { EsaggsExpressionFunctionDefinition } from '../../data/common/search/expressions';
import { buildExpression, buildExpressionFunction } from '../../expressions/public';
import { getVisSchemas, SchemaConfig, Vis, BuildPipelineParams } from '../../visualizations/public';
import { TagcloudExpressionFunctionDefinition } from './tag_cloud_fn';
import { TagCloudVisParams } from './types';
const prepareDimension = (params: SchemaConfig) => {
const visdimension = buildExpressionFunction('visdimension', { accessor: params.accessor });
if (params.format) {
visdimension.addArgument('format', params.format.id);
visdimension.addArgument('formatParams', JSON.stringify(params.format.params));
}
return buildExpression([visdimension]);
};
export const toExpressionAst = (vis: Vis<TagCloudVisParams>, params: BuildPipelineParams) => {
const esaggs = buildExpressionFunction<EsaggsExpressionFunctionDefinition>('esaggs', {
index: vis.data.indexPattern!.id!,
metricsAtAllLevels: vis.isHierarchical(),
partialRows: vis.type.requiresPartialRows || false,
aggConfigs: JSON.stringify(vis.data.aggs!.aggs),
includeFormatHints: false,
});
const schemas = getVisSchemas(vis, params);
const tagcloud = buildExpressionFunction<TagcloudExpressionFunctionDefinition>('tagcloud', {
...vis.params,
metric: prepareDimension(schemas.metric[0]),
});
if (schemas.segment) {
tagcloud.addArgument('bucket', prepareDimension(schemas.segment[0]));
}
const ast = buildExpression([esaggs, tagcloud]);
return ast.toAst();
};

View file

@ -68,7 +68,7 @@ export const createVislibVisController = (deps: VisTypeVislibDependencies) => {
this.container.appendChild(this.legendEl);
}
render(esResponse: any, visParams: VisParams) {
render(esResponse: any, visParams: VisParams): Promise<void> {
if (this.vislibVis) {
this.destroy();
}

View file

@ -36,13 +36,13 @@ export { getSchemas as getVisSchemas } from './legacy/build_pipeline';
/** @public types */
export { VisualizationsSetup, VisualizationsStart };
export { VisTypeAlias, VisType } from './vis_types';
export { VisTypeAlias, VisType, BaseVisTypeOptions, ReactVisTypeOptions } from './vis_types';
export { VisParams, 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 } from './legacy/build_pipeline';
export { SchemaConfig, BuildPipelineParams } from './legacy/build_pipeline';
// @ts-ignore
export { updateOldState } from './legacy/vis_update_state';
export { PersistedState } from './persisted_state';

View file

@ -22,12 +22,6 @@ exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunct
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles table function without splits or buckets 1`] = `"kibana_table visConfig='{\\"foo\\":\\"bar\\",\\"dimensions\\":{\\"metrics\\":[{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},{\\"accessor\\":1,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"}],\\"buckets\\":[]}}' "`;
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles tagcloud function with boolean param showLabel 1`] = `"tagcloud metric={visdimension 0} showLabel=false "`;
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles tagcloud function with buckets 1`] = `"tagcloud metric={visdimension 0} bucket={visdimension 1 } "`;
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles tagcloud function without buckets 1`] = `"tagcloud metric={visdimension 0} "`;
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles tile_map function 1`] = `"tilemap visConfig='{\\"metric\\":{},\\"dimensions\\":{\\"metric\\":{\\"accessor\\":0,\\"label\\":\\"\\",\\"format\\":{},\\"params\\":{},\\"aggType\\":\\"\\"},\\"geohash\\":1,\\"geocentroid\\":3}}' "`;
exports[`visualize loader pipeline helpers: build pipeline buildPipelineVisFunction handles timelion function 1`] = `"timelion_vis expression='foo' interval='bar' "`;

View file

@ -201,28 +201,6 @@ describe('visualize loader pipeline helpers: build pipeline', () => {
});
});
describe('handles tagcloud function', () => {
it('without buckets', () => {
const actual = buildPipelineVisFunction.tagcloud({}, schemasDef, uiState);
expect(actual).toMatchSnapshot();
});
it('with buckets', () => {
const schemas = {
...schemasDef,
segment: [{ accessor: 1 }],
};
const actual = buildPipelineVisFunction.tagcloud({}, schemas, uiState);
expect(actual).toMatchSnapshot();
});
it('with boolean param showLabel', () => {
const params = { showLabel: false };
const actual = buildPipelineVisFunction.tagcloud(params, schemasDef, uiState);
expect(actual).toMatchSnapshot();
});
});
describe('handles region_map function', () => {
it('without buckets', () => {
const params = { metric: {} };

View file

@ -70,6 +70,12 @@ interface BuildVisConfigFunction {
[key: string]: buildVisConfigFunction;
}
export interface BuildPipelineParams {
timefilter: TimefilterContract;
timeRange?: any;
abortSignal?: AbortSignal;
}
const vislibCharts: string[] = [
'area',
'gauge',
@ -80,14 +86,7 @@ const vislibCharts: string[] = [
'line',
];
export const getSchemas = (
vis: Vis,
opts: {
timeRange?: any;
timefilter: TimefilterContract;
}
): Schemas => {
const { timeRange, timefilter } = opts;
export const getSchemas = (vis: Vis, { timeRange, timefilter }: BuildPipelineParams): Schemas => {
const createSchemaConfig = (accessor: number, agg: IAggConfig): SchemaConfig => {
if (isDateHistogramBucketAggConfig(agg)) {
agg.params.timeRange = timeRange;
@ -276,19 +275,6 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = {
};
return `kibana_table ${prepareJson('visConfig', visConfig)}`;
},
tagcloud: (params, schemas) => {
const { scale, orientation, minFontSize, maxFontSize, showLabel } = params;
const { metric, bucket } = buildVisConfig.tagcloud(schemas);
let expr = `tagcloud metric={visdimension ${metric.accessor}} `;
expr += prepareValue('scale', scale);
expr += prepareValue('orientation', orientation);
expr += prepareValue('minFontSize', minFontSize);
expr += prepareValue('maxFontSize', maxFontSize);
expr += prepareValue('showLabel', showLabel);
expr += prepareDimension('bucket', bucket);
return expr;
},
region_map: (params, schemas) => {
const visConfig = {
...params,
@ -333,14 +319,6 @@ const buildVisConfig: BuildVisConfigFunction = {
}
return visConfig;
},
tagcloud: (schemas) => {
const visConfig = {} as any;
visConfig.metric = schemas.metric[0];
if (schemas.segment) {
visConfig.bucket = schemas.segment[0];
}
return visConfig;
},
region_map: (schemas) => {
const visConfig = {} as any;
visConfig.metric = schemas.metric[0];
@ -370,14 +348,7 @@ const buildVisConfig: BuildVisConfigFunction = {
},
};
export const buildVislibDimensions = async (
vis: any,
params: {
timefilter: TimefilterContract;
timeRange?: any;
abortSignal?: AbortSignal;
}
) => {
export const buildVislibDimensions = async (vis: any, params: BuildPipelineParams) => {
const schemas = getSchemas(vis, {
timeRange: params.timeRange,
timefilter: params.timefilter,
@ -416,14 +387,7 @@ export const buildVislibDimensions = async (
return dimensions;
};
export const buildPipeline = async (
vis: Vis,
params: {
timefilter: TimefilterContract;
timeRange?: any;
abortSignal?: AbortSignal;
}
) => {
export const buildPipeline = async (vis: Vis, params: BuildPipelineParams) => {
const { indexPattern, searchSource } = vis.data;
const query = searchSource!.getField('query');
const filters = searchSource!.getField('filter');
@ -455,10 +419,8 @@ export const buildPipeline = async (
${prepareJson('aggConfigs', vis.data.aggs!.aggs)} | `;
}
const schemas = getSchemas(vis, {
timeRange: params.timeRange,
timefilter: params.timefilter,
});
const schemas = getSchemas(vis, params);
if (buildPipelineVisFunction[vis.type.name]) {
pipeline += buildPipelineVisFunction[vis.type.name](
{ title, ...vis.params },

View file

@ -17,6 +17,7 @@
* under the License.
*/
import { ExpressionAstExpression } from 'src/plugins/expressions';
import { SavedObject } from '../../../plugins/saved_objects/public';
import {
AggConfigOptions,
@ -24,6 +25,7 @@ import {
TimefilterContract,
} from '../../../plugins/data/public';
import { SerializedVis, Vis, VisParams } from './vis';
import { ExprVis } from './expressions/vis';
export { Vis, SerializedVis, VisParams };
@ -35,7 +37,7 @@ export interface VisualizationController {
export type VisualizationControllerConstructor = new (
el: HTMLElement,
vis: Vis
vis: ExprVis
) => VisualizationController;
export interface SavedVisState {
@ -71,4 +73,7 @@ export interface VisToExpressionAstParams {
abortSignal?: AbortSignal;
}
export type VisToExpressionAst = (vis: Vis, params: VisToExpressionAstParams) => string;
export type VisToExpressionAst<TVisParams = VisParams> = (
vis: Vis<TVisParams>,
params: VisToExpressionAstParams
) => ExpressionAstExpression;

View file

@ -83,12 +83,12 @@ const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?:
type PartialVisState = Assign<SerializedVis, { data: Partial<SerializedVisData> }>;
export class Vis {
export class Vis<TVisParams = VisParams> {
public readonly type: VisType;
public readonly id?: string;
public title: string = '';
public description: string = '';
public params: VisParams = {};
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> = {};

View file

@ -19,12 +19,12 @@
import _ from 'lodash';
import { ReactElement } from 'react';
import { VisToExpressionAst, VisualizationControllerConstructor } from '../types';
import { VisParams, VisToExpressionAst, VisualizationControllerConstructor } from '../types';
import { TriggerContextMapping } from '../../../ui_actions/public';
import { Adapters } from '../../../inspector/public';
import { Vis } from '../vis';
export interface BaseVisTypeOptions {
interface CommonBaseVisTypeOptions {
name: string;
title: string;
description?: string;
@ -33,7 +33,6 @@ export interface BaseVisTypeOptions {
image?: string;
stage?: 'experimental' | 'beta' | 'production';
options?: Record<string, any>;
visualization: VisualizationControllerConstructor | undefined;
visConfig?: Record<string, any>;
editor?: any;
editorConfig?: Record<string, any>;
@ -44,12 +43,25 @@ export interface BaseVisTypeOptions {
setup?: unknown;
useCustomNoDataScreen?: boolean;
inspectorAdapters?: Adapters | (() => Adapters);
toExpressionAst?: VisToExpressionAst;
isDeprecated?: boolean;
getDeprecationMessage?: (vis: Vis) => ReactElement<any>;
}
export class BaseVisType {
interface ExpressionBaseVisTypeOptions<TVisParams> extends CommonBaseVisTypeOptions {
toExpressionAst: VisToExpressionAst<TVisParams>;
visualization?: undefined;
}
interface VisualizationBaseVisTypeOptions extends CommonBaseVisTypeOptions {
toExpressionAst?: undefined;
visualization: VisualizationControllerConstructor | undefined;
}
export type BaseVisTypeOptions<TVisParams = VisParams> =
| ExpressionBaseVisTypeOptions<TVisParams>
| VisualizationBaseVisTypeOptions;
export class BaseVisType<TVisParams = VisParams> {
name: string;
title: string;
description: string;
@ -71,11 +83,11 @@ export class BaseVisType {
setup?: unknown;
useCustomNoDataScreen: boolean;
inspectorAdapters?: Adapters | (() => Adapters);
toExpressionAst?: VisToExpressionAst;
toExpressionAst?: VisToExpressionAst<TVisParams>;
isDeprecated: boolean;
getDeprecationMessage?: (vis: Vis) => ReactElement<any>;
constructor(opts: BaseVisTypeOptions) {
constructor(opts: BaseVisTypeOptions<TVisParams>) {
if (!opts.icon && !opts.image) {
throw new Error('vis_type must define its icon or image');
}

View file

@ -18,3 +18,5 @@
*/
export * from './types_service';
export type { BaseVisTypeOptions } from './base_vis_type';
export type { ReactVisTypeOptions } from './react_vis_type';

View file

@ -19,17 +19,12 @@
import React from 'react';
import { render, unmountComponentAtNode } from 'react-dom';
import { Vis, VisualizationController } from '../types';
import { VisualizationController } from '../types';
import { getI18n, getUISettings } from '../services';
import { ExprVis } from '../expressions/vis';
export class ReactVisController implements VisualizationController {
private el: HTMLElement;
private vis: Vis;
constructor(element: HTMLElement, vis: Vis) {
this.el = element;
this.vis = vis;
}
constructor(private element: HTMLElement, private vis: ExprVis) {}
public render(visData: any, visParams: any): Promise<void> {
const I18nContext = getI18n().Context;
@ -51,12 +46,12 @@ export class ReactVisController implements VisualizationController {
renderComplete={resolve}
/>
</I18nContext>,
this.el
this.element
);
});
}
public destroy() {
unmountComponentAtNode(this.el);
unmountComponentAtNode(this.element);
}
}

View file

@ -20,8 +20,14 @@
import { BaseVisType, BaseVisTypeOptions } from './base_vis_type';
import { ReactVisController } from './react_vis_controller';
export type ReactVisTypeOptions = Omit<BaseVisTypeOptions, 'visualization' | 'toExpressionAst'>;
/**
* This class should only be used for visualizations not using the `toExpressionAst` with a custom renderer.
* If you implement a custom renderer you should just mount a react component inside this.
*/
export class ReactVisType extends BaseVisType {
constructor(opts: Omit<BaseVisTypeOptions, 'visualization'>) {
constructor(opts: ReactVisTypeOptions) {
super({
...opts,
visualization: ReactVisController,

View file

@ -19,10 +19,8 @@
import { IconType } from '@elastic/eui';
import { visTypeAliasRegistry, VisTypeAlias } from './vis_type_alias_registry';
// @ts-ignore
import { BaseVisType } from './base_vis_type';
// @ts-ignore
import { ReactVisType } from './react_vis_type';
import { BaseVisType, BaseVisTypeOptions } from './base_vis_type';
import { ReactVisType, ReactVisTypeOptions } from './react_vis_type';
import { TriggerContextMapping } from '../../../ui_actions/public';
export interface VisType {
@ -71,17 +69,17 @@ export class TypesService {
return {
/**
* registers a visualization type
* @param {VisType} config - visualization type definition
* @param config - visualization type definition
*/
createBaseVisualization: (config: any) => {
createBaseVisualization: <TVisParams>(config: BaseVisTypeOptions<TVisParams>): void => {
const vis = new BaseVisType(config);
registerVisualization(() => vis);
},
/**
* registers a visualization which uses react for rendering
* @param {VisType} config - visualization type definition
* @param config - visualization type definition
*/
createReactVisualization: (config: any) => {
createReactVisualization: (config: ReactVisTypeOptions): void => {
const vis = new ReactVisType(config);
registerVisualization(() => vis);
},

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visType":"tagcloud"}}

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"bucket":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":1,"format":{"id":"number","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":40,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":20,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"single","scale":"linear","showLabel":true},"visType":"tagcloud"}}

View file

@ -1 +1 @@
{"as":"visualization","type":"render","value":{"params":{"listenOnChange":true},"visConfig":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visType":"tagcloud"}}
{"as":"tagloud_vis","type":"render","value":{"visData":{"columns":[{"id":"col-0-2","meta":{"aggConfigParams":{"field":"response.raw","missingBucket":false,"missingBucketLabel":"Missing","order":"desc","orderBy":"1","otherBucket":false,"otherBucketLabel":"Other","size":4},"indexPatternId":"logstash-*","type":"terms"},"name":"response.raw: Descending"},{"id":"col-1-1","meta":{"aggConfigParams":{},"indexPatternId":"logstash-*","type":"count"},"name":"Count"}],"rows":[{"col-0-2":"200","col-1-1":12891},{"col-0-2":"404","col-1-1":696},{"col-0-2":"503","col-1-1":417}],"type":"kibana_datatable"},"visParams":{"bucket":{"accessor":1,"format":{"id":"string","params":{}},"type":"vis_dimension"},"maxFontSize":72,"metric":{"accessor":0,"format":{"id":"string","params":{}},"type":"vis_dimension"},"minFontSize":18,"orientation":"multiple","scale":"log","showLabel":true},"visType":"tagcloud"}}