From 1a395fadf639f1ee05ba3f983fcfdf4117d54ee6 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Thu, 21 Mar 2019 12:15:06 -0700 Subject: [PATCH 1/3] visdata interpreter function --- .../interpreter/public/functions/index.js | 3 +- .../interpreter/public/functions/vis_data.js | 49 +++++++++++++++++++ .../request_handlers/request_handlers.d.ts | 1 + .../loader/embedded_visualize_handler.ts | 8 ++- .../visualize/loader/visualize_data_loader.ts | 4 ++ .../visualize/loader/visualize_loader.ts | 19 +++++++ x-pack/plugins/canvas/public/app.js | 1 + 7 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 src/legacy/core_plugins/interpreter/public/functions/vis_data.js diff --git a/src/legacy/core_plugins/interpreter/public/functions/index.js b/src/legacy/core_plugins/interpreter/public/functions/index.js index 307b67f68b57c..d0e6342bee0ca 100644 --- a/src/legacy/core_plugins/interpreter/public/functions/index.js +++ b/src/legacy/core_plugins/interpreter/public/functions/index.js @@ -34,8 +34,9 @@ import { kibanaTable } from './table'; import { tagcloud } from './tagcloud'; import { vislib } from './vislib'; import { visualization } from './visualization'; +import { visdata } from './vis_data'; export const functions = [ clog, esaggs, kibana, kibanaContext, vega, timelionVis, tsvb, kibanaMarkdown, inputControlVis, - metric, kibanaPie, regionmap, tilemap, kibanaTable, tagcloud, vislib, visualization + metric, kibanaPie, regionmap, tilemap, kibanaTable, tagcloud, vislib, visualization, visdata ]; diff --git a/src/legacy/core_plugins/interpreter/public/functions/vis_data.js b/src/legacy/core_plugins/interpreter/public/functions/vis_data.js new file mode 100644 index 0000000000000..8e2d228e38c1d --- /dev/null +++ b/src/legacy/core_plugins/interpreter/public/functions/vis_data.js @@ -0,0 +1,49 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { getVisualizeLoader } from 'ui/visualize/loader'; + +export const visdata = () => ({ + name: 'visdata', + type: 'datatable', + help: i18n.translate('interpreter.functions.visualization.help', { + defaultMessage: 'Loads saved visualization data' + }), + args: { + id: { + types: ['string'], + }, + }, + async fn(context, args) { + const loader = await getVisualizeLoader(); + const handler = await loader.loadById(args.id); + const data = await handler.fetch(true, true); + + if (!data.rows || !data.columns) throw('visualization datasource does not return table'); + + return { + type: 'datatable', + rows: data.rows, + columns: data.columns.map(column => ({ + name: column.id, + })), + }; + } +}); diff --git a/src/legacy/ui/public/vis/request_handlers/request_handlers.d.ts b/src/legacy/ui/public/vis/request_handlers/request_handlers.d.ts index 697072a0de084..3adb3dde12bfa 100644 --- a/src/legacy/ui/public/vis/request_handlers/request_handlers.d.ts +++ b/src/legacy/ui/public/vis/request_handlers/request_handlers.d.ts @@ -26,6 +26,7 @@ import { AggConfigs } from '../agg_configs'; import { Vis } from '../vis'; export interface RequestHandlerParams { + tableOnly?: boolean; searchSource: SearchSource; aggs: AggConfigs; timeRange?: TimeRange; diff --git a/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.ts b/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.ts index 5d1ae2611742b..1c8302e49b2f9 100644 --- a/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.ts +++ b/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.ts @@ -53,6 +53,7 @@ interface EmbeddedVisualizeHandlerParams extends VisualizeLoaderParams { Private: IPrivate; queryFilter: any; autoFetch?: boolean; + autoRender?: boolean; } const RENDER_COMPLETE_EVENT = 'render_complete'; @@ -201,7 +202,9 @@ export class EmbeddedVisualizeHandler { this.dataSubject = new Rx.Subject(); this.data$ = this.dataSubject.asObservable().pipe(share()); - this.render(); + if (params.autoRender !== false) { + this.render(); + } } /** @@ -425,9 +428,10 @@ export class EmbeddedVisualizeHandler { this.fetchAndRender(); }; - private fetch = (forceFetch: boolean = false) => { + private fetch = (forceFetch: boolean = false, tableOnly: boolean = false) => { this.dataLoaderParams.aggs = this.vis.getAggConfig(); this.dataLoaderParams.forceFetch = forceFetch; + this.dataLoaderParams.tableOnly = tableOnly; this.dataLoaderParams.inspectorAdapters = this.inspectorAdapters; this.vis.filters = { timeRange: this.dataLoaderParams.timeRange }; diff --git a/src/legacy/ui/public/visualize/loader/visualize_data_loader.ts b/src/legacy/ui/public/visualize/loader/visualize_data_loader.ts index 63d64bf4c0b1c..fb478c1014925 100644 --- a/src/legacy/ui/public/visualize/loader/visualize_data_loader.ts +++ b/src/legacy/ui/public/visualize/loader/visualize_data_loader.ts @@ -88,6 +88,10 @@ export class VisualizeDataLoader { filters: filters.concat(savedFilters).filter(f => !f.meta.disabled), }); + if (params.tableOnly) { + return requestHandlerResponse; + } + // No need to call the response handler when there have been no data nor has there been changes // in the vis-state (response handler does not depend on uiState) const canSkipResponseHandler = diff --git a/src/legacy/ui/public/visualize/loader/visualize_loader.ts b/src/legacy/ui/public/visualize/loader/visualize_loader.ts index ee08ae3cd85a0..f9d46fe34715b 100644 --- a/src/legacy/ui/public/visualize/loader/visualize_loader.ts +++ b/src/legacy/ui/public/visualize/loader/visualize_loader.ts @@ -83,6 +83,25 @@ export class VisualizeLoader { return this.renderVis(el, savedObj, params); } + public async loadById(savedVisualizationId: string, params: VisualizeLoaderParams) { + return new Promise((resolve, reject) => { + this.savedVisualizations.get(savedVisualizationId).then((savedObj: VisSavedObject) => { + const handlerParams = { + ...params, + // lets add query filter angular service to the params + queryFilter: this.Private(FilterBarQueryFilterProvider), + // lets add Private to the params, we'll need to pass it to visualize later + Private: this.Private, + autoRender: false, + }; + + const element = document.createElement('div'); + const handler = new EmbeddedVisualizeHandler(element, savedObj, handlerParams); + resolve(handler); + }, reject); + }); + } + /** * Returns a promise, that resolves to a list of all saved visualizations. * diff --git a/x-pack/plugins/canvas/public/app.js b/x-pack/plugins/canvas/public/app.js index b43f55fea891f..7593ef56c811f 100644 --- a/x-pack/plugins/canvas/public/app.js +++ b/x-pack/plugins/canvas/public/app.js @@ -20,6 +20,7 @@ import 'uiExports/visEditorTypes'; import 'uiExports/savedObjectTypes'; import 'uiExports/spyModes'; import 'uiExports/fieldFormats'; +import 'uiExports/search'; // load application code import './lib/load_expression_types'; From 2a81d4bf379fa31d39ba120ca2e0ec1ed90e5617 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Thu, 21 Mar 2019 12:43:42 -0700 Subject: [PATCH 2/3] adding timerange option --- .../interpreter/public/functions/vis_data.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/legacy/core_plugins/interpreter/public/functions/vis_data.js b/src/legacy/core_plugins/interpreter/public/functions/vis_data.js index 8e2d228e38c1d..d94f270e6fb0d 100644 --- a/src/legacy/core_plugins/interpreter/public/functions/vis_data.js +++ b/src/legacy/core_plugins/interpreter/public/functions/vis_data.js @@ -30,10 +30,20 @@ export const visdata = () => ({ id: { types: ['string'], }, + from: { + types: ['string'], + }, + to: { + types: ['string'], + } }, async fn(context, args) { const loader = await getVisualizeLoader(); const handler = await loader.loadById(args.id); + handler.dataLoaderParams.timeRange = { + from: args.from, + to: args.to, + }; const data = await handler.fetch(true, true); if (!data.rows || !data.columns) throw('visualization datasource does not return table'); From 8765ac9d863085ef16749385efaec800010927e8 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Mon, 25 Mar 2019 02:58:29 -0700 Subject: [PATCH 3/3] using filter context to get time range --- .../interpreter/public/functions/vis_data.js | 36 ++++++++++++------- .../loader/embedded_visualize_handler.ts | 14 ++++++-- 2 files changed, 36 insertions(+), 14 deletions(-) diff --git a/src/legacy/core_plugins/interpreter/public/functions/vis_data.js b/src/legacy/core_plugins/interpreter/public/functions/vis_data.js index d94f270e6fb0d..ba3a772115f67 100644 --- a/src/legacy/core_plugins/interpreter/public/functions/vis_data.js +++ b/src/legacy/core_plugins/interpreter/public/functions/vis_data.js @@ -26,27 +26,39 @@ export const visdata = () => ({ help: i18n.translate('interpreter.functions.visualization.help', { defaultMessage: 'Loads saved visualization data' }), + context: { + types: ['filter'], + }, args: { id: { types: ['string'], }, - from: { - types: ['string'], - }, - to: { - types: ['string'], - } }, async fn(context, args) { const loader = await getVisualizeLoader(); const handler = await loader.loadById(args.id); - handler.dataLoaderParams.timeRange = { - from: args.from, - to: args.to, - }; - const data = await handler.fetch(true, true); + if (context.and.find(f => f.type === 'time')) { + const timeFilter = context.and.find(f => f.type === 'time'); + handler.dataLoaderParams.timeRange = { + from: timeFilter.from, + to: timeFilter.to, + }; + } + + let data; + + try { + data = await handler.fetch(true, true, false); + } catch (e) { + const negativeTimeIntervalMsg = 'Zero or negative time interval not supported'; + if (e.message.includes(negativeTimeIntervalMsg)) { + const errorMessage = `visualization requires time range. prepend expression with + 'filters | ' and add time picker to workpad`; + throw new Error(errorMessage); + } + } - if (!data.rows || !data.columns) throw('visualization datasource does not return table'); + if (!data.rows || !data.columns) throw new Error('visualization datasource does not return table'); return { type: 'datatable', diff --git a/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.ts b/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.ts index 1c8302e49b2f9..079a6daf6ef68 100644 --- a/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.ts +++ b/src/legacy/ui/public/visualize/loader/embedded_visualize_handler.ts @@ -428,7 +428,11 @@ export class EmbeddedVisualizeHandler { this.fetchAndRender(); }; - private fetch = (forceFetch: boolean = false, tableOnly: boolean = false) => { + private fetch = ( + forceFetch: boolean = false, + tableOnly: boolean = false, + handleErrors = true + ) => { this.dataLoaderParams.aggs = this.vis.getAggConfig(); this.dataLoaderParams.forceFetch = forceFetch; this.dataLoaderParams.tableOnly = tableOnly; @@ -454,7 +458,13 @@ export class EmbeddedVisualizeHandler { } return data; }) - .catch(this.handleDataLoaderError); + .catch(e => { + if (handleErrors) { + this.handleDataLoaderError(e); + } else { + throw e; + } + }); }; /**