From e4463943fc30d9b2863bc3d60ade91f8a08e56b5 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 11 Mar 2020 07:52:08 -0700 Subject: [PATCH 01/26] updating vis and savedvis --- .../public/expressions/{vis.js => vis.ts} | 78 +++--- .../expressions/visualization_renderer.tsx | 9 +- .../public/np_ready/public/index.ts | 2 +- .../np_ready/public/legacy/update_status.ts | 35 +-- .../public/np_ready/public/mocks.ts | 2 + .../public/np_ready/public/plugin.ts | 21 +- .../public/saved_visualizations/_saved_vis.ts | 124 +++++----- .../saved_visualization_references.test.ts | 6 +- .../public/np_ready/public/services.ts | 9 + .../public/np_ready/public/types.ts | 34 ++- .../public/np_ready/public/vis.ts | 178 +++++++++++--- .../public/np_ready/public/vis_impl.d.ts | 55 ----- .../public/np_ready/public/vis_impl.js | 223 ------------------ 13 files changed, 315 insertions(+), 461 deletions(-) rename src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/{vis.js => vis.ts} (65%) delete mode 100644 src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts delete mode 100644 src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.js diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/vis.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/vis.ts similarity index 65% rename from src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/vis.js rename to src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/vis.ts index a891140677d60..a3d88502b490a 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/vis.js +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/vis.ts @@ -32,25 +32,46 @@ import _ from 'lodash'; import { PersistedState } from '../../../../../../../plugins/visualizations/public'; import { getTypes } from '../services'; +import { VisType } from '../vis_types'; +import { VisParams } from '../types'; -export class Vis extends EventEmitter { - constructor(visState = { type: 'histogram' }) { +export interface ExprVisState { + title?: string; + type: VisType | string; + params?: VisParams; +} + +export interface ExprVisAPIEvents { + filter: (data: any) => void; + brush: (data: any) => void; +} + +export interface ExprVisAPI { + events: ExprVisAPIEvents; +} + +export class ExprVis extends EventEmitter { + public title: string = ''; + public type?: VisType; + public params: VisParams = {}; + public sessionState: Record = {}; + public API: ExprVisAPI; + public eventsSubject: any; + private uiState: PersistedState; + + constructor(visState: ExprVisState = { type: 'histogram' }) { super(); - this._setUiState(new PersistedState()); + this.uiState = new PersistedState(); this.setState(visState); - // 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. - this.sessionState = {}; - this.API = { events: { - filter: data => { + filter: (data: any) => { if (!this.eventsSubject) return; this.eventsSubject.next({ name: 'filterBucket', data }); }, - brush: data => { + brush: (data: any) => { if (!this.eventsSubject) return; this.eventsSubject.next({ name: 'brush', data }); }, @@ -58,7 +79,7 @@ export class Vis extends EventEmitter { }; } - setState(state) { + setState(state: ExprVisState) { this.title = state.title || ''; const type = state.type || this.type; if (_.isString(type)) { @@ -73,18 +94,14 @@ export class Vis extends EventEmitter { this.params = _.defaultsDeep( {}, _.cloneDeep(state.params || {}), - _.cloneDeep(this.type.visConfig.defaults || {}) + _.cloneDeep(this.type!.visConfig.defaults || {}) ); } - setCurrentState(state) { - this.setState(state); - } - getState() { return { title: this.title, - type: this.type.name, + type: this.type!.name, params: _.cloneDeep(this.params), }; } @@ -98,42 +115,35 @@ export class Vis extends EventEmitter { } isHierarchical() { - if (_.isFunction(this.type.hierarchicalData)) { - return !!this.type.hierarchicalData(this); + if (_.isFunction(this.type!.hierarchicalData)) { + return !!this.type!.hierarchicalData(this); } else { - return !!this.type.hierarchicalData; + return !!this.type!.hierarchicalData; } } hasUiState() { - return !!this.__uiState; + return !!this.uiState; } - /*** - * this should not be used outside of visualize - * @param uiState - * @private - */ - _setUiState(uiState) { - if (uiState instanceof PersistedState) { - this.__uiState = uiState; - } + getUiState() { + 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, val) { + uiStateVal(key: string, val: any) { if (this.hasUiState()) { if (_.isUndefined(val)) { - return this.__uiState.get(key); + return this.uiState.get(key); } - return this.__uiState.set(key, val); + return this.uiState.set(key, val); } return val; } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/visualization_renderer.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/visualization_renderer.tsx index 02a31447d23c1..0fd81c753da24 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/visualization_renderer.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/expressions/visualization_renderer.tsx @@ -20,8 +20,9 @@ import React from 'react'; import { render, unmountComponentAtNode } from 'react-dom'; // @ts-ignore -import { Vis } from './vis'; +import { ExprVis } from './vis'; import { Visualization } from '../components'; +import { VisParams } from '../types'; export const visualization = () => ({ name: 'visualization', @@ -31,9 +32,9 @@ export const visualization = () => ({ const { visData, visConfig, params } = config; const visType = config.visType || visConfig.type; - const vis = new Vis({ - type: visType, - params: visConfig, + const vis = new ExprVis({ + type: visType as string, + params: visConfig as VisParams, }); vis.eventsSubject = { next: handlers.event }; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts index b59eb2277411c..e689adc27fb6d 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/index.ts @@ -39,7 +39,7 @@ export { VisualizationsSetup, VisualizationsStart }; /** @public types */ export { VisTypeAlias, VisType } from './vis_types'; export { VisSavedObject } from './types'; -export { Vis, VisParams, VisState } from './vis'; +export { Vis, VisParams, SerializedVis, SerializedVisData, VisData } from './vis'; import { VisualizeEmbeddableFactory, VisualizeEmbeddable } from './embeddable'; export type VisualizeEmbeddableFactoryContract = PublicContract; export type VisualizeEmbeddableContract = PublicContract; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.ts index 92a9ce8366f4f..cccebd4d6bfa5 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.ts @@ -19,7 +19,7 @@ import { PersistedState } from '../../../../../../../plugins/visualizations/public'; import { calculateObjectHash } from '../../../../../../../plugins/kibana_utils/common'; -import { Vis } from '../vis'; +import { ExprVis } from '../expressions/vis'; enum Status { AGGS = 'aggs', @@ -43,22 +43,10 @@ function hasHashChanged( return oldHash !== valueHash; } -interface Size { - width: number; - height: number; -} - -function hasSizeChanged(size: Size, oldSize?: Size): boolean { - if (!oldSize) { - return true; - } - return oldSize.width !== size.width || oldSize.height !== size.height; -} - function getUpdateStatus( requiresUpdateStatus: T[] = [], obj: any, - param: { vis: Vis; visData: any; uiState: PersistedState } + param: { vis: ExprVis; visData: any; uiState: PersistedState } ): { [reqStats in T]: boolean } { const status = {} as { [reqStats in Status]: boolean }; @@ -76,9 +64,7 @@ function getUpdateStatus( // Calculate all required status updates for this visualization switch (requiredStatus) { case Status.AGGS: - hash = calculateObjectHash(param.vis.aggs); - status.aggs = hasHashChanged(hash, obj._oldStatus, 'aggs'); - obj._oldStatus.aggs = hash; + status.aggs = true; break; case Status.DATA: hash = calculateObjectHash(param.visData); @@ -86,22 +72,13 @@ function getUpdateStatus( obj._oldStatus.data = hash; break; case Status.PARAMS: - hash = calculateObjectHash(param.vis.params); - status.params = hasHashChanged(hash, obj._oldStatus, 'param'); - obj._oldStatus.param = hash; + status.params = true; break; case Status.RESIZE: - const width: number = param.vis.size ? param.vis.size[0] : 0; - const height: number = param.vis.size ? param.vis.size[1] : 0; - const size = { width, height }; - status.resize = hasSizeChanged(size, obj._oldStatus.resize); - obj._oldStatus.resize = size; + status.resize = true; break; case Status.TIME: - const timeRange = param.vis.filters && param.vis.filters.timeRange; - hash = calculateObjectHash(timeRange); - status.time = hasHashChanged(hash, obj._oldStatus, 'time'); - obj._oldStatus.time = hash; + status.time = true; break; case Status.UI_STATE: hash = calculateObjectHash(param.uiState); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts index 4ee727e46f4d6..17f777e4e80e1 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/mocks.ts @@ -41,6 +41,8 @@ const createStartContract = (): VisualizationsStart => ({ savedVisualizationsLoader: {} as any, showNewVisModal: jest.fn(), createVis: jest.fn(), + convertFromSerializedVis: jest.fn(), + convertToSerializedVis: jest.fn(), }); const createInstance = async () => { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts index 953caecefb974..3ade6cee0d4d2 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/plugin.ts @@ -39,6 +39,8 @@ import { setSavedVisualizationsLoader, setTimeFilter, setAggs, + setChrome, + setOverlays, } from './services'; import { VISUALIZE_EMBEDDABLE_TYPE, VisualizeEmbeddableFactory } from './embeddable'; import { ExpressionsSetup, ExpressionsStart } from '../../../../../../plugins/expressions/public'; @@ -48,14 +50,16 @@ import { visualization as visualizationRenderer } from './expressions/visualizat import { DataPublicPluginSetup, DataPublicPluginStart, - IIndexPattern, } from '../../../../../../plugins/data/public'; import { UsageCollectionSetup } from '../../../../../../plugins/usage_collection/public'; import { createSavedVisLoader, SavedVisualizationsLoader } from './saved_visualizations'; -import { VisImpl } from './vis_impl'; +import { SerializedVis, Vis } from './vis'; import { showNewVisModal } from './wizard'; import { UiActionsStart } from '../../../../../../plugins/ui_actions/public'; -import { VisState } from './types'; +import { + convertFromSerializedVis, + convertToSerializedVis, +} from './saved_visualizations/_saved_vis'; /** * Interface for this plugin's returned setup/start contracts. @@ -67,7 +71,9 @@ export type VisualizationsSetup = TypesSetup; export interface VisualizationsStart extends TypesStart { savedVisualizationsLoader: SavedVisualizationsLoader; - createVis: (indexPattern: IIndexPattern, visState?: VisState) => VisImpl; + createVis: (visType: string, visState?: SerializedVis) => Vis; + convertToSerializedVis: typeof convertToSerializedVis; + convertFromSerializedVis: typeof convertFromSerializedVis; showNewVisModal: typeof showNewVisModal; } @@ -138,6 +144,8 @@ export class VisualizationsPlugin setUiActions(uiActions); setTimeFilter(data.query.timefilter.timefilter); setAggs(data.search.aggs); + setOverlays(core.overlays); + setChrome(core.chrome); const savedVisualizationsLoader = createSavedVisLoader({ savedObjectsClient: core.savedObjects.client, indexPatterns: data.indexPatterns, @@ -155,8 +163,9 @@ export class VisualizationsPlugin * @param {IIndexPattern} indexPattern - index pattern to use * @param {VisState} visState - visualization configuration */ - createVis: (indexPattern: IIndexPattern, visState?: VisState) => - new VisImpl(indexPattern, visState), + createVis: (visType: string, visState?: SerializedVis) => new Vis(visType, visState), + convertToSerializedVis, + convertFromSerializedVis, savedVisualizationsLoader, }; } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts index e381a01edef8b..fc0ca40d65495 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/_saved_vis.ts @@ -26,71 +26,76 @@ */ import { createSavedObjectClass, - SavedObject, SavedObjectKibanaServices, } from '../../../../../../../plugins/saved_objects/public'; // @ts-ignore import { updateOldState } from '../legacy/vis_update_state'; import { extractReferences, injectReferences } from './saved_visualization_references'; -import { IIndexPattern } from '../../../../../../../plugins/data/public'; -import { VisSavedObject } from '../types'; -import { VisImpl } from '../vis_impl'; +import { + IIndexPattern, + ISearchSource, + SearchSource, +} from '../../../../../../../plugins/data/public'; +import { ISavedVis, SerializedVis } from '../types'; import { createSavedSearchesLoader } from '../../../../../../../plugins/discover/public'; - -async function _afterEsResp(savedVis: VisSavedObject, services: any) { - await _getLinkedSavedSearch(savedVis, services); - savedVis.searchSource!.setField('size', 0); - savedVis.vis = savedVis.vis ? _updateVis(savedVis) : await _createVis(savedVis); - return savedVis; -} - -async function _getLinkedSavedSearch(savedVis: VisSavedObject, services: any) { - const linkedSearch = !!savedVis.savedSearchId; - const current = savedVis.savedSearch; - - if (linkedSearch && current && current.id === savedVis.savedSearchId) { - return; +import { getChrome, getOverlays, getIndexPatterns, getSavedObjects } from '../services'; + +export const convertToSerializedVis = async (savedVis: ISavedVis): Promise => { + const searchSource = await getSearchSource(savedVis.searchSource!, savedVis.savedSearchId); + + const indexPattern = + savedVis.searchSource && savedVis.searchSource.getField('index') + ? savedVis.searchSource && savedVis.searchSource.getField('index')!.id + : undefined; + + return { + title: savedVis.title, + type: savedVis.visState.type, + description: savedVis.description, + params: savedVis.visState.params, + uiState: JSON.parse(savedVis.uiStateJSON || '{}'), + data: { + indexPattern, + aggs: savedVis.visState.aggs, + searchSource, + }, + }; +}; + +export const convertFromSerializedVis = (vis: SerializedVis): ISavedVis => { + return { + title: vis.title, + description: vis.description, + visState: { + type: vis.type, + aggs: vis.data.aggs, + params: vis.params, + }, + uiStateJSON: JSON.stringify(vis.uiState), + searchSource: vis.data.searchSource!, + savedSearchId: vis.data.searchSource!.getParent() + ? vis.data.searchSource!.getParent()!.getId() + : undefined, + }; +}; + +const getSearchSource = async (inputSearchSource: ISearchSource, savedSearchId?: string) => { + const searchSource = inputSearchSource.createCopy + ? inputSearchSource.createCopy() + : new SearchSource({ ...(inputSearchSource as any).fields }); + if (savedSearchId) { + const savedSearch = await createSavedSearchesLoader({ + savedObjectsClient: getSavedObjects().client, + indexPatterns: getIndexPatterns(), + chrome: getChrome(), + overlays: getOverlays(), + }).get(savedSearchId); + + searchSource.setParent(savedSearch); } - - if (savedVis.savedSearch) { - savedVis.searchSource!.setParent(savedVis.savedSearch.searchSource.getParent()); - savedVis.savedSearch.destroy(); - delete savedVis.savedSearch; - } - const savedSearches = createSavedSearchesLoader(services); - - if (linkedSearch) { - savedVis.savedSearch = await savedSearches.get(savedVis.savedSearchId!); - savedVis.searchSource!.setParent(savedVis.savedSearch!.searchSource); - } -} - -async function _createVis(savedVis: VisSavedObject) { - savedVis.visState = updateOldState(savedVis.visState); - - // visState doesn't yet exist when importing a visualization, so we can't - // assume that exists at this point. If it does exist, then we're not - // importing a visualization, so we want to sync the title. - if (savedVis.visState) { - savedVis.visState.title = savedVis.title; - } - - savedVis.vis = new VisImpl(savedVis.searchSource!.getField('index')!, savedVis.visState); - - savedVis.vis!.savedSearchId = savedVis.savedSearchId; - - return savedVis.vis; -} - -function _updateVis(savedVis: VisSavedObject) { - if (savedVis.vis && savedVis.searchSource) { - savedVis.vis.indexPattern = savedVis.searchSource.getField('index'); - savedVis.visState.title = savedVis.title; - savedVis.vis.setState(savedVis.visState); - savedVis.vis.savedSearchId = savedVis.savedSearchId; - } - return savedVis.vis; -} + searchSource!.setField('size', 0); + return searchSource; +}; export function createSavedVisClass(services: SavedObjectKibanaServices) { const SavedObjectClass = createSavedObjectClass(services); @@ -131,9 +136,6 @@ export function createSavedVisClass(services: SavedObjectKibanaServices) { savedSearchId: opts.savedSearchId, version: 1, }, - afterESResp: (savedObject: SavedObject) => { - return _afterEsResp(savedObject as VisSavedObject, services) as Promise; - }, }); this.showInRecentlyAccessed = true; this.getFullPath = () => { diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.test.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.test.ts index 98af6d99025c2..2e3a4f0f58b27 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.test.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/saved_visualizations/saved_visualization_references.test.ts @@ -18,7 +18,7 @@ */ import { extractReferences, injectReferences } from './saved_visualization_references'; -import { VisSavedObject, VisState } from '../types'; +import { VisSavedObject, SavedVisState } from '../types'; describe('extractReferences', () => { test('extracts nothing if savedSearchId is empty', () => { @@ -140,7 +140,7 @@ Object { }, ], }, - } as unknown) as VisState, + } as unknown) as SavedVisState, } as VisSavedObject; const references = [ { @@ -201,7 +201,7 @@ Object { }, ], }, - } as unknown) as VisState, + } as unknown) as SavedVisState, } as VisSavedObject; expect(() => injectReferences(context, [])).toThrowErrorMatchingInlineSnapshot( `"Could not find index pattern reference \\"control_0_index_pattern\\""` diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts index b2eebe8b5b57d..23cdeae7d15ff 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/services.ts @@ -18,10 +18,13 @@ */ import { + ApplicationStart, Capabilities, + ChromeStart, HttpStart, I18nStart, IUiSettingsClient, + OverlayStart, SavedObjectsStart, } from '../../../../../../core/public'; import { TypesStart } from './vis_types'; @@ -76,3 +79,9 @@ export const [getSavedVisualizationsLoader, setSavedVisualizationsLoader] = crea export const [getAggs, setAggs] = createGetterSetter( 'AggConfigs' ); + +export const [getOverlays, setOverlays] = createGetterSetter('Overlays'); + +export const [getChrome, setChrome] = createGetterSetter('Chrome'); + +export const [getApplication, setApplication] = createGetterSetter('Application'); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/types.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/types.ts index d8e3ccdeb065e..2d0686cca2b81 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/types.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/types.ts @@ -18,21 +18,35 @@ */ import { SavedObject } from '../../../../../../plugins/saved_objects/public'; -import { Vis, VisState, VisParams, VisualizationController } from './vis'; import { ISearchSource } from '../../../../../../plugins/data/public/'; -import { SavedSearch } from '../../../../../../plugins/discover/public'; +import { SerializedVis, Vis, VisParams } from './vis'; -export { Vis, VisState, VisParams, VisualizationController }; +import { Status } from './legacy/update_status'; +import { AggConfigOptions } from '../../../../data/public/search/aggs/agg_config'; -export interface VisSavedObject extends SavedObject { - vis: Vis; - description?: string; - searchSource: ISearchSource; +export { Vis, SerializedVis, VisParams }; + +export interface VisualizationController { + render(visData: any, visParams: any, update: { [key in Status]: boolean }): Promise; + destroy(): void; + isLoaded?(): Promise | void; +} + +export interface SavedVisState { + type: string; + params: VisParams; + aggs: AggConfigOptions[]; +} + +export interface ISavedVis { title: string; + description?: string; + visState: SavedVisState; + searchSource?: ISearchSource; uiStateJSON?: string; - destroy: () => void; savedSearchRefName?: string; savedSearchId?: string; - savedSearch?: SavedSearch; - visState: VisState; } + +// @ts-ignore-next-line +export interface VisSavedObject extends SavedObject, ISavedVis {} diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts index eb262966a4a22..b06602aafe837 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis.ts @@ -17,47 +17,155 @@ * under the License. */ +/** + * @name Vis + * + * @description This class consists of aggs, params, listeners, title, and type. + * - Aggs: Instances of IAggConfig. + * - Params: The settings in the Options tab. + * + * Not to be confused with vislib/vis.js. + */ + +import { EventEmitter } from 'events'; +import _ from 'lodash'; +import { PersistedState } from '../../../../../../../src/plugins/visualizations/public'; +// @ts-ignore +import { updateVisualizationConfig } from './legacy/vis_update'; +import { getTypes, getAggs } from './services'; import { VisType } from './vis_types'; -import { Status } from './legacy/update_status'; -import { IAggConfigs } from '../../../../../../plugins/data/public'; - -export interface Vis { - type: VisType; - getCurrentState: ( - includeDisabled?: boolean - ) => { - title: string; - type: string; - params: VisParams; - aggs: Array<{ [key: string]: any }>; - }; - - /** - * If a visualization based on the saved search, - * the id is necessary for building an expression function in src/plugins/expressions/common/expression_functions/specs/kibana_context.ts - */ - savedSearchId?: string; - - // Since we haven't typed everything here yet, we basically "any" the rest - // of that interface. This should be removed as soon as this type definition - // has been completed. But that way we at least have typing for a couple of - // properties on that type. - [key: string]: any; -} +import { IAggConfigs, IndexPattern, ISearchSource } from '../../../../../../plugins/data/public'; +import { AggConfigOptions } from '../../../../../../plugins/data/public/search/aggs/agg_config'; -export interface VisParams { - [key: string]: any; +export interface SerializedVisData { + expression?: string; + aggs: AggConfigOptions[]; + indexPattern?: string; + searchSource?: ISearchSource; } -export interface VisState { +export interface SerializedVis { title: string; - type: VisType; + description?: string; + type: string; params: VisParams; - aggs: IAggConfigs; + uiState?: any; + data: SerializedVisData; +} + +export interface VisData { + ast?: string; + aggs?: IAggConfigs; + indexPattern?: IndexPattern; + searchSource?: ISearchSource; +} + +export interface VisParams { + [key: string]: any; } -export interface VisualizationController { - render(visData: any, visParams: any, update: { [key in Status]: boolean }): Promise; - destroy(): void; - isLoaded?(): Promise | void; +export class Vis extends EventEmitter { + public readonly type: VisType; + public title: string = ''; + public description: string = ''; + public params: VisParams = {}; + // 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 = {}; + public data: VisData = {}; + + public readonly uiState: PersistedState; + + constructor(visType: string, visState: SerializedVis = {} as any) { + super(); + + this.type = getTypes().get(visType); + if (!this.type) { + throw new Error(`Invalid type "${visType}"`); + } + + this.uiState = new PersistedState(visState.uiState); + + this.setState(visState || {}); + } + + setState(state: SerializedVis) { + this.title = state.title || ''; + this.description = state.description || ''; + + this.params = _.defaults( + {}, + _.cloneDeep(state.params || {}), + _.cloneDeep(this.type.visConfig.defaults || {}) + ); + + // move to migration script + updateVisualizationConfig(state.params, this.params); + + if (state.data.searchSource) { + this.data.searchSource = state.data.searchSource!; + this.data.indexPattern = this.data.searchSource.getField('index'); + } + if (state.data.aggs) { + let configStates = state.data.aggs; + configStates = this.initializeDefaultsFromSchemas(configStates, this.type.schemas.all || []); + if (!this.data.indexPattern) { + if (state.data.aggs.length) { + throw new Error('trying to initialize aggs without index pattern'); + } + return; + } + this.data.aggs = getAggs().createAggConfigs(this.data.indexPattern, configStates); + } + } + + clone() { + return new Vis(this.type.name, this.serialize()); + } + + serialize(): SerializedVis { + const aggs = this.data.aggs ? this.data.aggs.aggs.map(agg => agg.toJSON()) : []; + const indexPattern = this.data.searchSource && this.data.searchSource.getField('index'); + return { + title: this.title, + type: this.type.name, + params: _.cloneDeep(this.params) as any, + uiState: this.uiState.getChanges(), + data: { + aggs: aggs as any, + indexPattern: indexPattern ? indexPattern.id : undefined, + searchSource: this.data.searchSource!.createCopy(), + }, + }; + } + + toAST() { + return this.type.toAST(this.params); + } + + // deprecated + isHierarchical() { + if (_.isFunction(this.type.hierarchicalData)) { + return !!this.type.hierarchicalData(this); + } else { + return !!this.type.hierarchicalData; + } + } + + private initializeDefaultsFromSchemas(configStates: AggConfigOptions[], schemas: any) { + // Set the defaults for any schema which has them. If the defaults + // for some reason has more then the max only set the max number + // of defaults (not sure why a someone define more... + // but whatever). Also if a schema.name is already set then don't + // set anything. + const newConfigs = [...configStates]; + schemas + .filter((schema: any) => Array.isArray(schema.defaults) && schema.defaults.length > 0) + .filter((schema: any) => !configStates.find(agg => agg.schema && agg.schema === schema.name)) + .forEach((schema: any) => { + const defaults = schema.defaults.slice(0, schema.max); + defaults.forEach((d: any) => newConfigs.push(d)); + }); + return newConfigs; + } } diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts deleted file mode 100644 index 0e759c3d9872c..0000000000000 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.d.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Vis, VisState, VisParams } from './vis'; -import { VisType } from './vis_types'; -import { IAggConfig, IIndexPattern } from '../../../../../../plugins/data/public'; -import { Schema } from '../../../../vis_default_editor/public'; - -type InitVisStateType = - | Partial - | Partial & { type: string }> - | string; - -export type VisImplConstructor = new ( - indexPattern: IIndexPattern, - visState?: InitVisStateType -) => VisImpl; - -export declare class VisImpl implements Vis { - constructor(indexPattern: IIndexPattern, visState?: InitVisStateType); - - type: VisType; - getCurrentState: ( - includeDisabled?: boolean - ) => { - title: string; - type: string; - params: VisParams; - aggs: Array<{ [key: string]: any }>; - }; - - private initializeDefaultsFromSchemas(configStates: IAggConfig[], schemas: Schema[]); - - // Since we haven't typed everything here yet, we basically "any" the rest - // of that interface. This should be removed as soon as this type definition - // has been completed. But that way we at least have typing for a couple of - // properties on that type. - [key: string]: any; -} diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.js b/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.js deleted file mode 100644 index abd8f351ae94d..0000000000000 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/vis_impl.js +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Licensed to Elasticsearch B.V. under one or more contributor - * license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright - * ownership. Elasticsearch B.V. licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/** - * @name Vis - * - * @description This class consists of aggs, params, listeners, title, and type. - * - Aggs: Instances of IAggConfig. - * - Params: The settings in the Options tab. - * - * Not to be confused with vislib/vis.js. - */ - -import { EventEmitter } from 'events'; -import _ from 'lodash'; -import { PersistedState } from '../../../../../../../src/plugins/visualizations/public'; -import { updateVisualizationConfig } from './legacy/vis_update'; -import { getTypes, getAggs } from './services'; - -class VisImpl extends EventEmitter { - constructor(indexPattern, visState) { - super(); - visState = visState || {}; - - if (_.isString(visState)) { - visState = { - type: visState, - }; - } - - this.indexPattern = indexPattern; - this._setUiState(new PersistedState()); - this.setCurrentState(visState); - this.setState(this.getCurrentState(), false); - - // 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. - this.sessionState = {}; - - this.API = { - events: { - filter: data => this.eventsSubject.next({ name: 'filterBucket', data }), - brush: data => this.eventsSubject.next({ name: 'brush', data }), - }, - }; - } - - initializeDefaultsFromSchemas(configStates, schemas) { - // Set the defaults for any schema which has them. If the defaults - // for some reason has more then the max only set the max number - // of defaults (not sure why a someone define more... - // but whatever). Also if a schema.name is already set then don't - // set anything. - const newConfigs = [...configStates]; - schemas - .filter(schema => Array.isArray(schema.defaults) && schema.defaults.length > 0) - .filter(schema => !configStates.find(agg => agg.schema && agg.schema === schema.name)) - .forEach(schema => { - const defaults = schema.defaults.slice(0, schema.max); - defaults.forEach(d => newConfigs.push(d)); - }); - return newConfigs; - } - - setCurrentState(state) { - this.title = state.title || ''; - const type = state.type || this.type; - if (_.isString(type)) { - this.type = getTypes().get(type); - if (!this.type) { - throw new Error(`Invalid type "${type}"`); - } - } else { - this.type = type; - } - - this.params = _.defaults( - {}, - _.cloneDeep(state.params || {}), - _.cloneDeep(this.type.visConfig.defaults || {}) - ); - - updateVisualizationConfig(state.params, this.params); - - if (state.aggs || !this.aggs) { - let configStates = state.aggs ? state.aggs.aggs || state.aggs : []; - configStates = this.initializeDefaultsFromSchemas(configStates, this.type.schemas.all || []); - this.aggs = getAggs().createAggConfigs(this.indexPattern, configStates); - } - } - - setState(state, updateCurrentState = true) { - this._state = _.cloneDeep(state); - if (updateCurrentState) { - this.setCurrentState(this._state); - } - } - - setVisType(type) { - this.type.type = type; - } - - updateState() { - this.setState(this.getCurrentState(true)); - this.emit('update'); - } - - forceReload() { - this.emit('reload'); - } - - getCurrentState(includeDisabled) { - return { - title: this.title, - type: this.type.name, - params: _.cloneDeep(this.params), - aggs: this.aggs.aggs - .map(agg => agg.toJSON()) - .filter(agg => includeDisabled || agg.enabled) - .filter(Boolean), - }; - } - - copyCurrentState(includeDisabled = false) { - const state = this.getCurrentState(includeDisabled); - state.aggs = getAggs().createAggConfigs( - this.indexPattern, - state.aggs.aggs || state.aggs, - this.type.schemas.all - ); - return state; - } - - getStateInternal(includeDisabled) { - return { - title: this._state.title, - type: this._state.type, - params: this._state.params, - aggs: this._state.aggs.filter(agg => includeDisabled || agg.enabled), - }; - } - - getEnabledState() { - return this.getStateInternal(false); - } - - getAggConfig() { - return this.aggs.clone({ enabledOnly: true }); - } - - getState() { - return this.getStateInternal(true); - } - - isHierarchical() { - if (_.isFunction(this.type.hierarchicalData)) { - return !!this.type.hierarchicalData(this); - } else { - return !!this.type.hierarchicalData; - } - } - - hasSchemaAgg(schemaName, aggTypeName) { - const aggs = this.aggs.bySchemaName(schemaName) || []; - return aggs.some(function(agg) { - if (!agg.type || !agg.type.name) return false; - return agg.type.name === aggTypeName; - }); - } - - hasUiState() { - return !!this.__uiState; - } - - /*** - * this should not be used outside of visualize - * @param uiState - * @private - */ - _setUiState(uiState) { - if (uiState instanceof PersistedState) { - this.__uiState = uiState; - } - } - - getUiState() { - return this.__uiState; - } - - /** - * Currently this is only used to extract map-specific information - * (e.g. mapZoom, mapCenter). - */ - uiStateVal(key, val) { - if (this.hasUiState()) { - if (_.isUndefined(val)) { - return this.__uiState.get(key); - } - return this.__uiState.set(key, val); - } - return val; - } -} - -VisImpl.prototype.type = 'histogram'; - -export { VisImpl }; From ca104a7d9cb42b4b7600d9fccf509777c6eb5840 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 11 Mar 2020 13:47:06 -0700 Subject: [PATCH 02/26] embeddable --- .../public/components/visualization.tsx | 20 +-- .../public/components/visualization_chart.tsx | 26 ++-- .../public/embeddable/get_index_pattern.ts | 8 +- .../public/embeddable/visualize_embeddable.ts | 126 ++++++------------ .../visualize_embeddable_factory.tsx | 23 ++-- .../np_ready/public/legacy/build_pipeline.ts | 109 ++++++++------- 6 files changed, 125 insertions(+), 187 deletions(-) diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/components/visualization.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/components/visualization.tsx index 33830c45848e4..5296de365daec 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/components/visualization.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/components/visualization.tsx @@ -23,10 +23,9 @@ import { PersistedState } from '../../../../../../../plugins/visualizations/publ import { memoizeLast } from '../legacy/memoize'; import { VisualizationChart } from './visualization_chart'; import { VisualizationNoResults } from './visualization_noresults'; -import { VisualizationRequestError } from './visualization_requesterror'; -import { Vis } from '..'; +import { ExprVis } from '../expressions/vis'; -function shouldShowNoResultsMessage(vis: Vis, visData: any): boolean { +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); @@ -35,17 +34,11 @@ function shouldShowNoResultsMessage(vis: Vis, visData: any): boolean { return Boolean(requiresSearch && isZeroHits && shouldShowMessage); } -function shouldShowRequestErrorMessage(vis: Vis, visData: any): boolean { - const requestError = get(vis, 'requestError'); - const showRequestError = get(vis, 'showRequestError'); - return Boolean(!visData && requestError && showRequestError); -} - interface VisualizationProps { listenOnChange: boolean; onInit?: () => void; uiState: PersistedState; - vis: Vis; + vis: ExprVis; visData: any; visParams: any; } @@ -56,20 +49,17 @@ export class Visualization extends React.Component { constructor(props: VisualizationProps) { super(props); - props.vis._setUiState(props.uiState); + props.vis.setUiState(props.uiState); } public render() { const { vis, visData, visParams, onInit, uiState, listenOnChange } = this.props; const noResults = this.showNoResultsMessage(vis, visData); - const requestError = shouldShowRequestErrorMessage(vis, visData); return (
- {requestError ? ( - - ) : noResults ? ( + {noResults ? ( ) : ( void; uiState: PersistedState; - vis: Vis; + vis: ExprVis; visData: any; visParams: any; listenOnChange: boolean; @@ -40,7 +41,7 @@ class VisualizationChart extends React.Component { private chartDiv = React.createRef(); private containerDiv = React.createRef(); private renderSubject: Rx.Subject<{ - vis: Vis; + vis: ExprVis; visParams: any; visData: any; container: HTMLElement; @@ -54,11 +55,9 @@ class VisualizationChart extends React.Component { const render$ = this.renderSubject.asObservable().pipe(share()); const success$ = render$.pipe( - filter( - ({ vis, visData, container }) => vis && container && (!vis.type.requiresSearch || visData) - ), + filter(({ vis, visData }) => vis && (!vis.type!.requiresSearch || visData)), debounceTime(100), - switchMap(async ({ vis, visData, visParams, container }) => { + 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 @@ -66,15 +65,12 @@ class VisualizationChart extends React.Component { throw new Error('Visualization implementation was not initialized on first render.'); } - vis.size = [container.clientWidth, container.clientHeight]; - const status = getUpdateStatus(vis.type.requiresUpdateStatus, this, this.props); + const status = getUpdateStatus(vis.type!.requiresUpdateStatus, this, this.props); return this.visualization.render(visData, visParams, status); }) ); - const requestError$ = render$.pipe(filter(({ vis }) => vis.requestError)); - - this.renderSubscription = Rx.merge(success$, requestError$).subscribe(() => { + this.renderSubscription = success$.subscribe(() => { if (this.props.onInit) { this.props.onInit(); } @@ -85,10 +81,10 @@ class VisualizationChart extends React.Component { return (

- {this.props.vis.type.title} visualization, not yet accessible + {this.props.vis.type!.title} visualization, not yet accessible

@@ -102,7 +98,7 @@ class VisualizationChart extends React.Component { } const { vis } = this.props; - const Visualization = vis.type.visualization; + const Visualization = vis.type!.visualization; this.visualization = new Visualization(this.chartDiv.current, vis); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/get_index_pattern.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/get_index_pattern.ts index 51d839275fd27..05ce68221eaf0 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/get_index_pattern.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/get_index_pattern.ts @@ -28,18 +28,18 @@ import { getUISettings, getSavedObjects } from '../services'; export async function getIndexPattern( savedVis: VisSavedObject ): Promise { - if (savedVis.vis.type.name !== 'metrics') { - return savedVis.vis.indexPattern; + if (savedVis.visState.type !== 'metrics') { + return savedVis.searchSource!.getField('index'); } const savedObjectsClient = getSavedObjects().client; const defaultIndex = getUISettings().get('defaultIndex'); - if (savedVis.vis.params.index_pattern) { + if (savedVis.visState.params.index_pattern) { const indexPatternObjects = await savedObjectsClient.find({ type: 'index-pattern', fields: ['title', 'fields'], - search: `"${savedVis.vis.params.index_pattern}"`, + search: `"${savedVis.visState.params.index_pattern}"`, searchFields: ['title'], }); const [indexPattern] = indexPatternObjects.savedObjects.map(indexPatterns.getFromSavedObject); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts index c45e6832dc836..183a55df48440 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable.ts @@ -45,13 +45,12 @@ import { PersistedState } from '../../../../../../../plugins/visualizations/publ import { buildPipeline } from '../legacy/build_pipeline'; import { Vis } from '../vis'; import { getExpressions, getUiActions } from '../services'; -import { VisSavedObject } from '../types'; import { VIS_EVENT_TO_TRIGGER } from './events'; const getKeys = (o: T): Array => Object.keys(o) as Array; export interface VisualizeEmbeddableConfiguration { - savedVisualization: VisSavedObject; + vis: Vis; indexPatterns?: IIndexPattern[]; editUrl: string; editable: boolean; @@ -73,7 +72,6 @@ export interface VisualizeInput extends EmbeddableInput { export interface VisualizeOutput extends EmbeddableOutput { editUrl: string; indexPatterns?: IIndexPattern[]; - savedObjectId: string; visTypeName: string; } @@ -81,9 +79,7 @@ type ExpressionLoader = InstanceType; export class VisualizeEmbeddable extends Embeddable { private handler?: ExpressionLoader; - private savedVisualization: VisSavedObject; private appState: { save(): void } | undefined; - private uiState: PersistedState; private timefilter: TimefilterContract; private timeRange?: TimeRange; private query?: Query; @@ -99,49 +95,25 @@ export class VisualizeEmbeddable extends Embeddable { @@ -184,16 +156,16 @@ export class VisualizeEmbeddable extends Embeddable { - this.uiState.set(key, visCustomizations[key]); + this.vis.uiState.set(key, visCustomizations[key]); }); - this.uiState.on('change', this.uiStateChangeHandler); + this.vis.uiState.on('change', this.uiStateChangeHandler); } } else if (!this.appState) { - this.uiState.clearAllKeys(); + this.vis.uiState.clearAllKeys(); } } @@ -227,8 +199,8 @@ export class VisualizeEmbeddable extends Embeddable { + const visTypesWithoutInspector = [ + 'markdown', + 'input_control_vis', + 'metrics', + 'vega', + 'timelion', + ]; + if (visTypesWithoutInspector.includes(this.vis.type.name)) { + return false; + } + return this.getInspectorAdapters(); + }; + /** * * @param {Element} domNode @@ -245,26 +233,6 @@ export class VisualizeEmbeddable extends Embeddable { - const visTypesWithoutInspector = [ - 'markdown', - 'input_control_vis', - 'metrics', - 'vega', - 'timelion', - ]; - if (visTypesWithoutInspector.includes(this.vis.type.name)) { - return false; - } - return this.getInspectorAdapters(); - }; - - this.vis.openInspector = this.openInspector; - const div = document.createElement('div'); div.className = `visualize panel-content panel-content--fullWidth`; domNode.appendChild(div); @@ -277,12 +245,12 @@ export class VisualizeEmbeddable extends Embeddable { // maps hack, remove once esaggs function is cleaned up and ready to accept variables if (event.name === 'bounds') { - const agg = this.vis.getAggConfig().aggs.find((a: any) => { + const agg = this.vis.data.aggs!.aggs.find((a: any) => { return get(a, 'type.dslName') === 'geohash_grid'; }); if ( - agg.params.precision !== event.data.precision || - !_.isEqual(agg.params.boundingBox, event.data.boundingBox) + (agg && agg.params.precision !== event.data.precision) || + (agg && !_.isEqual(agg.params.boundingBox, event.data.boundingBox)) ) { agg.params.boundingBox = event.data.boundingBox; agg.params.precision = event.data.precision; @@ -296,7 +264,7 @@ export class VisualizeEmbeddable extends Embeddable s.unsubscribe()); - this.uiState.off('change', this.uiStateChangeHandler); - this.savedVisualization.vis.removeListener('reload', this.reload); - this.savedVisualization.vis.removeListener('update', this.handleVisUpdate); - this.savedVisualization.destroy(); + this.vis.uiState.off('change', this.uiStateChangeHandler); + if (this.handler) { this.handler.destroy(); this.handler.getElement().remove(); @@ -361,35 +327,25 @@ export class VisualizeEmbeddable extends Embeddable { - if (this.appState) { - this.appState.save(); - } - this.updateHandler(); }; private uiStateChangeHandler = () => { this.updateInput({ - ...this.uiState.toJSON(), + ...this.vis.uiState.toJSON(), }); }; diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable_factory.tsx b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable_factory.tsx index 1cd97115ee10e..805d10f15e4a7 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable_factory.tsx +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/embeddable/visualize_embeddable_factory.tsx @@ -26,9 +26,8 @@ import { ErrorEmbeddable, } from '../../../../../../../plugins/embeddable/public'; import { DisabledLabEmbeddable } from './disabled_lab_embeddable'; -import { getIndexPattern } from './get_index_pattern'; import { VisualizeEmbeddable, VisualizeInput, VisualizeOutput } from './visualize_embeddable'; -import { VisSavedObject } from '../types'; +import { Vis } from '../types'; import { VISUALIZE_EMBEDDABLE_TYPE } from './constants'; import { getCapabilities, @@ -39,6 +38,7 @@ import { getTimeFilter, } from '../services'; import { showNewVisModal } from '../wizard'; +import { convertToSerializedVis } from '../saved_visualizations/_saved_vis'; interface VisualizationAttributes extends SavedObjectAttributes { visState: string; @@ -93,32 +93,32 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory< }); } - public async createFromObject( - savedObject: VisSavedObject, + public createFromObject( + vis: Vis, input: Partial & { id: string }, parent?: Container - ): Promise { + ): VisualizeEmbeddable | ErrorEmbeddable | DisabledLabEmbeddable { const savedVisualizations = getSavedVisualizationsLoader(); try { - const visId = savedObject.id as string; + const visId = input.id as string; const editUrl = visId ? getHttp().basePath.prepend(`/app/kibana${savedVisualizations.urlFor(visId)}`) : ''; const isLabsEnabled = getUISettings().get('visualize:enableLabs'); - if (!isLabsEnabled && savedObject.vis.type.stage === 'experimental') { - return new DisabledLabEmbeddable(savedObject.title, input); + if (!isLabsEnabled && vis.type.stage === 'experimental') { + return new DisabledLabEmbeddable(vis.title, input); } - const indexPattern = await getIndexPattern(savedObject); + const indexPattern = vis.data.indexPattern; const indexPatterns = indexPattern ? [indexPattern] : []; const editable = await this.isEditable(); return new VisualizeEmbeddable( getTimeFilter(), { - savedVisualization: savedObject, + vis, indexPatterns, editUrl, editable, @@ -143,7 +143,8 @@ export class VisualizeEmbeddableFactory extends EmbeddableFactory< try { const savedObject = await savedVisualizations.get(savedObjectId); - return this.createFromObject(savedObject, input, parent); + const vis = new Vis(savedObject.visState.type, await convertToSerializedVis(savedObject)); + return this.createFromObject(vis, input, parent); } catch (e) { console.error(e); // eslint-disable-line no-console return new ErrorEmbeddable(e, input, parent); diff --git a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts index de974e6e969ef..ddf365d7ef384 100644 --- a/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts +++ b/src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/build_pipeline.ts @@ -21,14 +21,13 @@ import { get } from 'lodash'; import moment from 'moment'; import { SerializedFieldFormat } from '../../../../../../../plugins/expressions/public'; import { - fieldFormats, IAggConfig, - ISearchSource, + fieldFormats, search, TimefilterContract, } from '../../../../../../../plugins/data/public'; -const { isDateHistogramBucketAggConfig } = search.aggs; import { Vis, VisParams } from '../types'; +const { isDateHistogramBucketAggConfig } = search.aggs; interface SchemaConfigParams { precision?: number; @@ -59,7 +58,7 @@ export interface Schemas { } type buildVisFunction = ( - visState: ReturnType, + params: VisParams, schemas: Schemas, uiState: any, meta?: { savedObjectId?: string } @@ -139,7 +138,12 @@ const getSchemas = ( const schemas: Schemas = { metric: [], }; - const responseAggs = vis.aggs.getResponseAggs().filter((agg: IAggConfig) => agg.enabled); + + 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) => { @@ -228,9 +232,8 @@ export const prepareDimension = (variable: string, data: any) => { }; const adjustVislibDimensionFormmaters = (vis: Vis, dimensions: { y: any[] }): void => { - const visState = vis.getCurrentState(); - const visConfig = visState.params; - const responseAggs = vis.aggs.getResponseAggs().filter((agg: IAggConfig) => agg.enabled); + const visConfig = vis.params; + const responseAggs = vis.data.aggs!.getResponseAggs().filter((agg: IAggConfig) => agg.enabled); (dimensions.y || []).forEach(yDimension => { const yAgg = responseAggs[yDimension.accessor]; @@ -252,27 +255,26 @@ const adjustVislibDimensionFormmaters = (vis: Vis, dimensions: { y: any[] }): vo }; export const buildPipelineVisFunction: BuildPipelineVisFunction = { - vega: visState => { - return `vega ${prepareString('spec', visState.params.spec)}`; + vega: params => { + return `vega ${prepareString('spec', params.spec)}`; }, - input_control_vis: visState => { - return `input_control_vis ${prepareJson('visConfig', visState.params)}`; + input_control_vis: params => { + return `input_control_vis ${prepareJson('visConfig', params)}`; }, - metrics: (visState, schemas, uiState = {}, meta) => { - const paramsJson = prepareJson('params', visState.params); + metrics: (params, schemas, uiState = {}) => { + const paramsJson = prepareJson('params', params); const uiStateJson = prepareJson('uiState', uiState); - const savedObjectIdParam = prepareString('savedObjectId', meta?.savedObjectId); - const params = [paramsJson, uiStateJson, savedObjectIdParam].filter(param => Boolean(param)); - return `tsvb ${params.join(' ')}`; + const paramsArray = [paramsJson, uiStateJson].filter(param => Boolean(param)); + return `tsvb ${paramsArray.join(' ')}`; }, - timelion: visState => { - const expression = prepareString('expression', visState.params.expression); - const interval = prepareString('interval', visState.params.interval); + timelion: params => { + const expression = prepareString('expression', params.expression); + const interval = prepareString('interval', params.interval); return `timelion_vis ${expression}${interval}`; }, - markdown: visState => { - const { markdown, fontSize, openLinksInNewTab } = visState.params; + markdown: params => { + const { markdown, fontSize, openLinksInNewTab } = params; let escapedMarkdown = ''; if (typeof markdown === 'string' || markdown instanceof String) { escapedMarkdown = escapeString(markdown.toString()); @@ -282,14 +284,14 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = { expr += prepareValue('openLinksInNewTab', openLinksInNewTab); return expr; }, - table: (visState, schemas) => { + table: (params, schemas) => { const visConfig = { - ...visState.params, - ...buildVisConfig.table(schemas, visState.params), + ...params, + ...buildVisConfig.table(schemas, params), }; return `kibana_table ${prepareJson('visConfig', visConfig)}`; }, - metric: (visState, schemas) => { + metric: (params, schemas) => { const { percentageMode, useRanges, @@ -299,11 +301,11 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = { labels, invertColors, style, - } = visState.params.metric; + } = params.metric; const { metrics, bucket } = buildVisConfig.metric(schemas).dimensions; // fix formatter for percentage mode - if (get(visState.params, 'metric.percentageMode') === true) { + if (get(params, 'metric.percentageMode') === true) { metrics.forEach((metric: SchemaConfig) => { metric.format = { id: 'percent' }; }); @@ -335,8 +337,8 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = { return expr; }, - tagcloud: (visState, schemas) => { - const { scale, orientation, minFontSize, maxFontSize, showLabel } = visState.params; + 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); @@ -348,23 +350,23 @@ export const buildPipelineVisFunction: BuildPipelineVisFunction = { return expr; }, - region_map: (visState, schemas) => { + region_map: (params, schemas) => { const visConfig = { - ...visState.params, + ...params, ...buildVisConfig.region_map(schemas), }; return `regionmap ${prepareJson('visConfig', visConfig)}`; }, - tile_map: (visState, schemas) => { + tile_map: (params, schemas) => { const visConfig = { - ...visState.params, + ...params, ...buildVisConfig.tile_map(schemas), }; return `tilemap ${prepareJson('visConfig', visConfig)}`; }, - pie: (visState, schemas) => { + pie: (params, schemas) => { const visConfig = { - ...visState.params, + ...params, ...buildVisConfig.pie(schemas), }; return `kibana_pie ${prepareJson('visConfig', visConfig)}`; @@ -440,7 +442,6 @@ const buildVisConfig: BuildVisConfigFunction = { export const buildVislibDimensions = async ( vis: any, params: { - searchSource: any; timefilter: TimefilterContract; timeRange?: any; abortSignal?: AbortSignal; @@ -460,7 +461,7 @@ export const buildVislibDimensions = async ( splitColumn: schemas.split_column, }; if (schemas.segment) { - const xAgg = vis.aggs.getResponseAggs()[dimensions.x.accessor]; + const xAgg = vis.data.aggs.getResponseAggs()[dimensions.x.accessor]; if (xAgg.type.name === 'date_histogram') { dimensions.x.params.date = true; const { esUnit, esValue } = xAgg.buckets.getInterval(); @@ -472,7 +473,7 @@ export const buildVislibDimensions = async ( } else if (xAgg.type.name === 'histogram') { const intervalParam = xAgg.type.paramByName('interval'); const output = { params: {} as any }; - await intervalParam.modifyAggConfigOnSearchRequestStart(xAgg, params.searchSource, { + await intervalParam.modifyAggConfigOnSearchRequestStart(xAgg, vis.data.searchSource, { abortSignal: params.abortSignal, }); intervalParam.write(xAgg, output); @@ -487,18 +488,14 @@ export const buildVislibDimensions = async ( export const buildPipeline = async ( vis: Vis, params: { - searchSource: ISearchSource; timefilter: TimefilterContract; timeRange?: any; - savedObjectId?: string; } ) => { - const { searchSource } = params; - const { indexPattern } = vis; - const query = searchSource.getField('query'); - const filters = searchSource.getField('filter'); - const visState = vis.getCurrentState(); - const uiState = vis.getUiState(); + const { indexPattern, searchSource } = vis.data; + const query = searchSource!.getField('query'); + const filters = searchSource!.getField('filter'); + const { uiState } = vis; // context let pipeline = `kibana | kibana_context `; @@ -508,18 +505,18 @@ export const buildPipeline = async ( if (filters) { pipeline += prepareJson('filters', filters); } - if (vis.savedSearchId) { - pipeline += prepareString('savedSearchId', vis.savedSearchId); + if (vis.data.searchSource && vis.data.searchSource.getParent()) { + pipeline += prepareString('savedSearchId', vis.data.searchSource.getParent()!.getId()); } pipeline += '| '; // request handler if (vis.type.requestHandler === 'courier') { pipeline += `esaggs - ${prepareString('index', indexPattern.id)} + ${prepareString('index', indexPattern!.id)} metricsAtAllLevels=${vis.isHierarchical()} partialRows=${vis.type.requiresPartialRows || vis.params.showPartialRows || false} - ${prepareJson('aggConfigs', visState.aggs)} | `; + ${prepareJson('aggConfigs', vis.data.aggs!.aggs)} | `; } const schemas = getSchemas(vis, { @@ -527,18 +524,16 @@ export const buildPipeline = async ( timefilter: params.timefilter, }); if (buildPipelineVisFunction[vis.type.name]) { - pipeline += buildPipelineVisFunction[vis.type.name](visState, schemas, uiState, { - savedObjectId: params.savedObjectId, - }); + pipeline += buildPipelineVisFunction[vis.type.name](vis.params, schemas, uiState); } else if (vislibCharts.includes(vis.type.name)) { - const visConfig = visState.params; + const visConfig = vis.params; visConfig.dimensions = await buildVislibDimensions(vis, params); - pipeline += `vislib type='${vis.type.name}' ${prepareJson('visConfig', visState.params)}`; + pipeline += `vislib type='${vis.type.name}' ${prepareJson('visConfig', vis.params)}`; } else if (vis.type.toExpression) { pipeline += await vis.type.toExpression(vis, params); } else { - const visConfig = visState.params; + const visConfig = vis.params; visConfig.dimensions = schemas; pipeline += `visualization type='${vis.type.name}' ${prepareJson('visConfig', visConfig)} From bb803614c62bc45b64008c3a5e6a5ff31c799073 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 11 Mar 2020 13:48:05 -0700 Subject: [PATCH 03/26] discover --- .../discover/np_ready/angular/discover.js | 44 +++++++------------ 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js index 6978781fe6696..8fd1d2b44891f 100644 --- a/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js +++ b/src/legacy/core_plugins/kibana/public/discover/np_ready/angular/discover.js @@ -666,7 +666,7 @@ function discoverController( // no timefield, no vis, nothing to update if (!getTimeField() || !$scope.vis) return; - const buckets = $scope.vis.getAggConfig().byTypeName('buckets'); + const buckets = $scope.vis.data.aggs.byTypeName('buckets'); if (buckets && buckets.length === 1) { $scope.bucketInterval = buckets[0].buckets.getInterval(); @@ -870,11 +870,11 @@ function discoverController( inspectorRequest.stats(getResponseInspectorStats($scope.searchSource, resp)).ok({ json: resp }); if (getTimeField()) { - const tabifiedData = tabifyAggResponse($scope.vis.aggs, resp); + const tabifiedData = tabifyAggResponse($scope.vis.data.aggs, resp); $scope.searchSource.rawResponse = resp; $scope.histogramData = discoverResponseHandler( tabifiedData, - getDimensions($scope.vis.aggs.aggs, $scope.timeRange) + getDimensions($scope.vis.data.aggs.aggs, $scope.timeRange) ); } @@ -1017,41 +1017,27 @@ function discoverController( }, ]; - if ($scope.vis) { - const visState = $scope.vis.getEnabledState(); - visState.aggs = visStateAggs; - - $scope.vis.setState(visState); - return; - } - - const visSavedObject = { - indexPattern: $scope.indexPattern.id, - visState: { - type: 'histogram', - title: savedSearch.title, - params: { - addLegend: false, - addTimeMarker: true, - }, + $scope.vis = visualizations.createVis('histogram', { + title: savedSearch.title, + params: { + addLegend: false, + addTimeMarker: true, + }, + data: { aggs: visStateAggs, + indexPattern: $scope.searchSource.getField('index').id, + searchSource: $scope.searchSource, }, - }; - - $scope.vis = visualizations.createVis( - $scope.searchSource.getField('index'), - visSavedObject.visState - ); - visSavedObject.vis = $scope.vis; + }); $scope.searchSource.onRequestStart((searchSource, options) => { if (!$scope.vis) return; - return $scope.vis.getAggConfig().onSearchRequestStart(searchSource, options); + return $scope.vis.data.aggs.onSearchRequestStart(searchSource, options); }); $scope.searchSource.setField('aggs', function() { if (!$scope.vis) return; - return $scope.vis.getAggConfig().toDsl(); + return $scope.vis.data.aggs.toDsl(); }); } From f4c11a8a43401555404f7b1b1ab222dbde5f022c Mon Sep 17 00:00:00 2001 From: ppisljar Date: Wed, 11 Mar 2020 14:04:41 -0700 Subject: [PATCH 04/26] visualize editor --- .../public/visualize/np_ready/breadcrumbs.ts | 2 +- .../visualize/np_ready/editor/editor.html | 8 +- .../visualize/np_ready/editor/editor.js | 113 +++++++++--------- .../np_ready/editor/visualization.js | 23 ++-- .../np_ready/editor/visualization_editor.js | 16 ++- .../public/visualize/np_ready/legacy_app.js | 56 +++++++-- .../public/visualize/np_ready/types.d.ts | 3 +- .../public/components/agg.test.tsx | 5 +- .../public/components/agg_common_props.ts | 5 +- .../public/components/agg_group.test.tsx | 10 +- .../public/components/agg_group.tsx | 7 +- .../public/components/agg_param_props.ts | 4 +- .../public/components/agg_params.test.tsx | 4 +- .../components/agg_params_helper.test.ts | 4 +- .../public/components/agg_params_helper.ts | 4 +- .../public/components/controls/field.test.tsx | 4 +- .../components/controls/percentiles.test.tsx | 4 +- .../public/components/controls/test_utils.ts | 4 +- .../public/components/sidebar/data_tab.tsx | 4 +- .../public/components/sidebar/sidebar.tsx | 73 +++++------ .../components/sidebar/sidebar_title.tsx | 23 ++-- .../public/components/sidebar/state/index.ts | 31 ++--- .../components/sidebar/state/reducers.ts | 64 +++++++--- .../public/default_editor.tsx | 61 ++-------- .../public/default_editor_controller.tsx | 22 +++- .../public/vis_options_props.tsx | 2 - 26 files changed, 287 insertions(+), 269 deletions(-) diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/breadcrumbs.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/breadcrumbs.ts index c334172805b9f..b6a63d50b205b 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/breadcrumbs.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/breadcrumbs.ts @@ -69,7 +69,7 @@ export function getEditBreadcrumbs($route: any) { return [ ...getLandingBreadcrumbs(), { - text: $route.current.locals.savedVis.title, + text: $route.current.locals.resolved.savedVis.title, }, ]; } diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.html b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.html index 28baf21925cbe..b51953b5416be 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.html +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/editor.html @@ -69,7 +69,8 @@ { - $scope.$apply(); - }; - // This will trigger a digest cycle. This is needed when vis is updated from a global angular like in visualize_embeddable.js. - savedVis.vis.on('apply', _applyVis); + const { vis, savedVis, embeddableHandler } = $route.current.locals.resolved; + // vis is instance of src/legacy/ui/public/vis/vis.js. // SearchSource is a promise-based stream of search results that can inherit from other search sources. - const { vis, searchSource, savedSearch } = savedVis; + const searchSource = vis.data.searchSource; $scope.vis = vis; @@ -123,10 +120,9 @@ function VisualizeAppController( dirty: !savedVis.id, }; - vis.on('dirtyStateChange', ({ isDirty }) => { - vis.dirty = isDirty; - $scope.$digest(); - }); + $scope.dirty = !savedVis.id; + + $scope.embeddableHandler = embeddableHandler; $scope.topNavMenu = [ ...(visualizeCapabilities.save @@ -144,10 +140,10 @@ function VisualizeAppController( ), testId: 'visualizeSaveButton', disableButton() { - return Boolean(vis.dirty); + return Boolean($scope.dirty); }, tooltip() { - if (vis.dirty) { + if ($scope.dirty) { return i18n.translate( 'kbn.visualize.topNavMenu.saveVisualizationDisabledButtonTooltip', { @@ -216,7 +212,7 @@ function VisualizeAppController( }), testId: 'shareTopNavButton', run: anchorElement => { - const hasUnappliedChanges = vis.dirty; + const hasUnappliedChanges = $scope.dirty; const hasUnsavedChanges = $appStatus.dirty; share.toggleShareContextMenu({ anchorElement, @@ -242,17 +238,18 @@ function VisualizeAppController( }), testId: 'openInspectorButton', disableButton() { - return !vis.hasInspector || !vis.hasInspector(); + // todo: needs to use embeddable + return !embeddableHandler.hasInspector || !embeddableHandler.hasInspector(); }, run() { - const inspectorSession = vis.openInspector(); + const inspectorSession = embeddableHandler.openInspector(); // Close the inspector if this scope is destroyed (e.g. because the user navigates away). const removeWatch = $scope.$on('$destroy', () => inspectorSession.close()); // Remove that watch in case the user closes the inspector session herself. inspectorSession.onClose.finally(removeWatch); }, tooltip() { - if (!vis.hasInspector || !vis.hasInspector()) { + if (!embeddableHandler.hasInspector || !embeddableHandler.hasInspector()) { return i18n.translate('kbn.visualize.topNavMenu.openInspectorDisabledButtonTooltip', { defaultMessage: `This visualization doesn't support any inspectors.`, }); @@ -266,7 +263,7 @@ function VisualizeAppController( defaultMessage: 'Refresh', }), run: function() { - vis.forceReload(); + embeddableHandler.reload(); }, testId: 'visualizeRefreshButton', }, @@ -282,17 +279,19 @@ function VisualizeAppController( localStorage.get('kibana.userQueryLanguage') || uiSettings.get('search:queryLanguage'), }; - // Extract visualization state with filtered aggs. You can see these filtered aggs in the URL. - // Consists of things like aggs, params, listeners, title, type, etc. - const savedVisState = vis.getState(); - const stateDefaults = { - uiState: savedVis.uiStateJSON ? JSON.parse(savedVis.uiStateJSON) : {}, - query: searchSource.getOwnField('query') || defaultQuery, - filters: searchSource.getOwnField('filter') || [], - vis: savedVisState, - linked: !!savedVis.savedSearchId, + const visStateToEditorState = () => { + const savedVisState = visualizations.convertFromSerializedVis(vis.serialize()); + return { + uiState: vis.uiState.getChanges(), + query: vis.data.searchSource.getOwnField('query') || defaultQuery, + filters: vis.data.searchSource.getOwnField('filter') || [], + vis: savedVisState.visState, + linked: !!savedVis.savedSearchId, + }; }; + const stateDefaults = visStateToEditorState(); + const { stateContainer, stopStateSync } = useVisualizeAppState({ stateDefaults, kbnUrlStateStorage, @@ -378,8 +377,8 @@ function VisualizeAppController( }; function init() { - if (vis.indexPattern) { - $scope.indexPattern = vis.indexPattern; + if (vis.data.indexPattern) { + $scope.indexPattern = vis.data.indexPattern; } else { indexPatterns.getDefault().then(defaultIndexPattern => { $scope.indexPattern = defaultIndexPattern; @@ -388,14 +387,6 @@ function VisualizeAppController( const initialState = stateContainer.getState(); - $scope.appState = { - // mock implementation of the legacy appState.save() - // this could be even replaced by passing only "updateAppState" callback - save() { - stateContainer.transitions.updateVisState(vis.getState()); - }, - }; - const handleLinkedSearch = linked => { if (linked && !savedVis.savedSearchId && savedSearch) { savedVis.savedSearchId = savedSearch.id; @@ -436,7 +427,7 @@ function VisualizeAppController( $scope.showQueryBarTimePicker = () => { // tsvb loads without an indexPattern initially (TODO investigate). // hide timefilter only if timeFieldName is explicitly undefined. - const hasTimeField = vis.indexPattern ? !!vis.indexPattern.timeFieldName : true; + const hasTimeField = vis.data.indexPattern ? !!vis.data.indexPattern.timeFieldName : true; return vis.type.options.showTimePicker && hasTimeField; }; @@ -451,10 +442,20 @@ function VisualizeAppController( updateSavedQueryFromUrl(state.savedQuery); // if the browser history was changed manually we need to reflect changes in the editor - if (!_.isEqual(vis.getState(), state.vis)) { - vis.setState(state.vis); - vis.forceReload(); - vis.emit('updateEditor'); + if ( + !_.isEqual(visualizations.convertFromSerializedVis(vis.serialize()).visState, state.vis) + ) { + vis.setState({ + params: state.vis.params, + data: { + aggs: state.vis.aggs, + indexPattern: vis.data.indexPattern.id, + searchSouyrce: vis.data.searchSource, + }, + }); + // todo: replace with embeddable + embeddableHandler.reload(); + // vis.emit('updateEditor'); } $appStatus.dirty = true; @@ -507,9 +508,9 @@ function VisualizeAppController( const { query, linked, filters } = stateContainer.getState(); $scope.query = query; handleLinkedSearch(linked); - savedVis.searchSource.setField('query', query); - savedVis.searchSource.setField('filter', filters); - $scope.$broadcast('render'); + vis.data.searchSource.setField('query', query); + vis.data.searchSource.setField('filter', filters); + embeddableHandler.reload(); }; // update the searchSource when filters update @@ -542,8 +543,6 @@ function VisualizeAppController( } savedVis.destroy(); subscriptions.unsubscribe(); - $scope.vis.off('apply', _applyVis); - unsubscribePersisted(); unsubscribeStateUpdates(); @@ -565,7 +564,7 @@ function VisualizeAppController( // If nothing has changed, trigger the fetch manually, otherwise it will happen as a result of the changes if (!isUpdate) { - $scope.vis.forceReload(); + embeddableHandler.reload(); } }; @@ -662,8 +661,6 @@ function VisualizeAppController( } else if (savedVis.id === $route.current.params.id) { chrome.docTitle.change(savedVis.lastSavedTitle); chrome.setBreadcrumbs($injector.invoke(getEditBreadcrumbs)); - savedVis.vis.title = savedVis.title; - savedVis.vis.description = savedVis.description; } else { history.replace({ ...history.location, @@ -695,8 +692,8 @@ function VisualizeAppController( ); } - const unlinkFromSavedSearch = () => { - const searchSourceParent = savedSearch.searchSource; + $scope.unlinkFromSavedSearch = () => { + const searchSourceParent = searchSource.getParent(); const searchSourceGrandparent = searchSourceParent.getParent(); const currentIndex = searchSourceParent.getField('index'); @@ -710,14 +707,16 @@ function VisualizeAppController( toastNotifications.addSuccess( i18n.translate('kbn.visualize.linkedToSearch.unlinkSuccessNotificationText', { - defaultMessage: `Unlinked from saved search '{searchTitle}'`, - values: { - searchTitle: savedSearch.title, - }, + defaultMessage: `Unlinked from saved search`, }) ); }; + $scope.reloadVisualization = () => { + stateContainer.transitions.updateVisState(visStateToEditorState().vis); + embeddableHandler.reload(); + }; + $scope.getAdditionalMessage = () => { return ( '' + @@ -729,8 +728,6 @@ function VisualizeAppController( ); }; - vis.on('unlinkFromSavedSearch', unlinkFromSavedSearch); - addHelpMenuToAppChrome(chrome, docLinks); init(); diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization.js index c8acea168444f..94a62ef34476b 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization.js @@ -17,12 +17,12 @@ * under the License. */ -export function initVisualizationDirective(app, deps) { +export function initVisualizationDirective(app) { app.directive('visualizationEmbedded', function($timeout) { return { restrict: 'E', scope: { - savedObj: '=', + embeddableHandler: '=', uiState: '=?', timeRange: '=', filters: '=', @@ -31,19 +31,10 @@ export function initVisualizationDirective(app, deps) { }, link: function($scope, element) { $scope.renderFunction = async () => { - if (!$scope._handler) { - $scope._handler = await deps.embeddable - .getEmbeddableFactory('visualization') - .createFromObject($scope.savedObj, { - timeRange: $scope.timeRange, - filters: $scope.filters || [], - query: $scope.query, - appState: $scope.appState, - uiState: $scope.uiState, - }); - $scope._handler.render(element[0]); + if (!$scope.embeddableHandler) { + $scope.embeddableHandler.render(element[0]); } else { - $scope._handler.updateInput({ + $scope.embeddableHandler.updateInput({ timeRange: $scope.timeRange, filters: $scope.filters || [], query: $scope.query, @@ -59,8 +50,8 @@ export function initVisualizationDirective(app, deps) { }); $scope.$on('$destroy', () => { - if ($scope._handler) { - $scope._handler.destroy(); + if ($scope.embeddableHandler) { + $scope.embeddableHandler.destroy(); } }); }, diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization_editor.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization_editor.js index f2d9cbe2ad84c..d62ba9a79e7c1 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization_editor.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/editor/visualization_editor.js @@ -22,16 +22,25 @@ export function initVisEditorDirective(app, deps) { return { restrict: 'E', scope: { - savedObj: '=', + vis: '=', uiState: '=?', timeRange: '=', filters: '=', query: '=', appState: '=', + embeddableHandler: '=', + reloadVisualization: '=', + unlinkFromSavedSearch: '=', }, link: function($scope, element) { - const Editor = $scope.savedObj.vis.type.editor || deps.DefaultVisualizationEditor; - const editor = new Editor(element[0], $scope.savedObj); + const Editor = $scope.vis.type.editor || deps.DefaultVisualizationEditor; + const editor = new Editor( + element[0], + $scope.vis, + $scope.embeddableHandler, + $scope.reloadVisualization, + $scope.unlinkFromSavedSearch + ); $scope.renderFunction = () => { editor.render({ @@ -43,7 +52,6 @@ export function initVisEditorDirective(app, deps) { filters: $scope.filters, query: $scope.query, appState: $scope.appState, - linked: !!$scope.savedObj.savedSearchId, }); }; diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js b/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js index 1002f401706cd..d1979dc0829b8 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/legacy_app.js @@ -103,7 +103,7 @@ export function initVisualizeApp(app, deps) { template: editorTemplate, k7Breadcrumbs: getCreateBreadcrumbs, resolve: { - savedVis: function($route, $rootScope, kbnUrl, history) { + resolved: function($route, $rootScope, kbnUrl, history) { const { core, data, savedVisualizations, visualizations, toastNotifications } = deps; const visTypes = visualizations.all(); const visType = find(visTypes, { name: $route.current.params.type }); @@ -121,13 +121,30 @@ export function initVisualizeApp(app, deps) { ); } + const results = {}; + return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl) .then(() => savedVisualizations.get($route.current.params)) - .then(savedVis => { - if (savedVis.vis.type.setup) { - return savedVis.vis.type.setup(savedVis).catch(() => savedVis); + .then(savedObj => { + results.savedVis = savedObj; + return visualizations.convertToSerializedVis(savedObj); + }) + .then(serializedVis => visualizations.createVis(serializedVis.type, serializedVis)) + .then(vis => { + if (vis.type.setup) { + return vis.type.setup(vis).catch(() => vis); } - return savedVis; + results.vis = vis; + return deps.embeddable + .getEmbeddableFactory('visualization') + .createFromObject(results.vis, { + timeRange: data.query.timefilter.timefilter.getTime(), + filters: data.query.filterManager.getFilters(), + }); + }) + .then(embeddableHandler => { + results.embeddableHandler = embeddableHandler; + return results; }) .catch( redirectWhenMissing({ @@ -144,19 +161,34 @@ export function initVisualizeApp(app, deps) { template: editorTemplate, k7Breadcrumbs: getEditBreadcrumbs, resolve: { - savedVis: function($route, $rootScope, kbnUrl, history) { - const { chrome, core, data, savedVisualizations, toastNotifications } = deps; + resolved: function($route, $rootScope, kbnUrl, history) { + const { chrome, core, data, savedVisualizations, visualizations, toastNotifications } = deps; + + const results = {}; + return ensureDefaultIndexPattern(core, data, $rootScope, kbnUrl) .then(() => savedVisualizations.get($route.current.params.id)) .then(savedVis => { chrome.recentlyAccessed.add(savedVis.getFullPath(), savedVis.title, savedVis.id); - return savedVis; + results.savedVis = savedVis; + return visualizations.convertToSerializedVis(savedVis); }) - .then(savedVis => { - if (savedVis.vis.type.setup) { - return savedVis.vis.type.setup(savedVis).catch(() => savedVis); + .then(serializedVis => visualizations.createVis(serializedVis.type, serializedVis)) + .then(vis => { + if (vis.type.setup) { + return vis.type.setup(vis).catch(() => vis); } - return savedVis; + results.vis = vis; + return deps.embeddable + .getEmbeddableFactory('visualization') + .createFromObject(results.vis, { + timeRange: data.query.timefilter.timefilter.getTime(), + filters: data.query.filterManager.getFilters(), + }); + }) + .then(embeddableHandler => { + results.embeddableHandler = embeddableHandler; + return results; }) .catch( redirectWhenMissing({ diff --git a/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts b/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts index 01ce872aeb679..dc78fb79d39b7 100644 --- a/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts +++ b/src/legacy/core_plugins/kibana/public/visualize/np_ready/types.d.ts @@ -29,8 +29,9 @@ import { PersistedState } from 'src/plugins/visualizations/public'; import { LegacyCoreStart } from 'kibana/public'; import { Vis } from 'src/legacy/core_plugins/visualizations/public'; import { VisSavedObject } from '../legacy_imports'; +import { SavedVisState } from '../../../../visualizations/public/np_ready/public/types'; -export type PureVisState = ReturnType; +export type PureVisState = SavedVisState; export interface VisualizeAppState { filters: Filter[]; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx index 22e0ebb3d30dc..9e453c815ca5f 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg.test.tsx @@ -22,13 +22,12 @@ import { mount, shallow } from 'enzyme'; import { act } from 'react-dom/test-utils'; import { IndexPattern } from 'src/plugins/data/public'; -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; - import { IAggType, AggGroupNames } from '../legacy_imports'; import { DefaultEditorAgg, DefaultEditorAggProps } from './agg'; import { DefaultEditorAggParams } from './agg_params'; import { AGGS_ACTION_KEYS } from './agg_group_state'; import { Schema } from '../schemas'; +import { EditorVisState } from './sidebar/state/reducers'; jest.mock('ui/new_platform'); @@ -70,7 +69,7 @@ describe('DefaultEditorAgg component', () => { isLastBucket: false, isRemovable: false, metricAggs: [], - state: { params: {} } as VisState, + state: { params: {} } as EditorVisState, setAggParamValue, setStateParamValue, onAggTypeChange: () => {}, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts index 1a97cc5c4d967..7a34b29d659a0 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_common_props.ts @@ -17,9 +17,10 @@ * under the License. */ -import { VisState, VisParams } from 'src/legacy/core_plugins/visualizations/public'; +import { VisParams } from 'src/legacy/core_plugins/visualizations/public'; import { IAggType, IAggConfig, IAggGroupNames } from '../legacy_imports'; import { Schema } from '../schemas'; +import { EditorVisState } from './sidebar/state/reducers'; type AggId = IAggConfig['id']; type AggParams = IAggConfig['params']; @@ -31,7 +32,7 @@ export interface DefaultEditorCommonProps { formIsTouched: boolean; groupName: IAggGroupNames; metricAggs: IAggConfig[]; - state: VisState; + state: EditorVisState; setAggParamValue: ( aggId: AggId, paramName: T, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx index ec467480539ab..e81bab7b54299 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx @@ -20,12 +20,12 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; import { act } from 'react-dom/test-utils'; -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { IAggConfigs, IAggConfig } from '../legacy_imports'; import { DefaultEditorAggGroup, DefaultEditorAggGroupProps } from './agg_group'; import { DefaultEditorAgg } from './agg'; import { DefaultEditorAggAdd } from './agg_add'; import { Schema } from '../schemas'; +import { EditorVisState } from './sidebar/state/reducers'; jest.mock('@elastic/eui', () => ({ EuiTitle: 'eui-title', @@ -103,9 +103,9 @@ describe('DefaultEditorAgg component', () => { formIsTouched: false, metricAggs: [], groupName: 'metrics', - state: { + state: ({ aggs, - } as VisState, + } as any) as EditorVisState, schemas: [ { name: 'metrics', @@ -158,8 +158,8 @@ describe('DefaultEditorAgg component', () => { }); expect(reorderAggs).toHaveBeenCalledWith( - defaultProps.state.aggs.aggs[0], - defaultProps.state.aggs.aggs[1] + defaultProps.state.data.aggs!.aggs[0], + defaultProps.state.data.aggs!.aggs[1] ); }); diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx index a15a98d4983ce..b524179e889e8 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.tsx @@ -73,9 +73,10 @@ function DefaultEditorAggGroup({ const schemaNames = getSchemasByGroup(schemas, groupName).map(s => s.name); const group: IAggConfig[] = useMemo( () => - state.aggs.aggs.filter((agg: IAggConfig) => agg.schema && schemaNames.includes(agg.schema)) || - [], - [state.aggs.aggs, schemaNames] + state.data.aggs!.aggs.filter( + (agg: IAggConfig) => agg.schema && schemaNames.includes(agg.schema) + ) || [], + [state.data.aggs, schemaNames] ); const stats = { diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts index cdc5a4c8f8a77..6fe925e2952af 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_param_props.ts @@ -18,11 +18,11 @@ */ import { IndexPatternField } from 'src/plugins/data/public'; -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { IAggConfig, AggParam } from '../legacy_imports'; import { ComboBoxGroupedOptions } from '../utils'; import { EditorConfig } from './utils'; import { Schema } from '../schemas'; +import { EditorVisState } from './sidebar/state/reducers'; // NOTE: we cannot export the interface with export { InterfaceName } // as there is currently a bug on babel typescript transform plugin for it @@ -36,7 +36,7 @@ export interface AggParamCommonProps { formIsTouched: boolean; indexedFields?: ComboBoxGroupedOptions; showValidation: boolean; - state: VisState; + state: EditorVisState; value?: T; metricAggs: IAggConfig[]; schemas: Schema[]; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx index d2821566fcb37..21f8f67be0232 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params.test.tsx @@ -20,10 +20,10 @@ import React from 'react'; import { mount, shallow } from 'enzyme'; -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { IndexPattern } from 'src/plugins/data/public'; import { DefaultEditorAggParams, DefaultEditorAggParamsProps } from './agg_params'; import { IAggConfig, AggGroupNames } from '../legacy_imports'; +import { EditorVisState } from './sidebar/state/reducers'; const mockEditorConfig = { useNormalizedEsInterval: { hidden: false, fixedValue: false }, @@ -100,7 +100,7 @@ describe('DefaultEditorAggParams component', () => { formIsTouched: false, indexPattern: {} as IndexPattern, metricAggs: [], - state: {} as VisState, + state: {} as EditorVisState, setAggParamValue, onAggTypeChange, setTouched, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts index 047467750794b..a74dcf1f562b8 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.test.ts @@ -18,7 +18,6 @@ */ import { IndexPattern } from 'src/plugins/data/public'; -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { IAggConfig, IAggType, AggGroupNames, BUCKET_TYPES } from '../legacy_imports'; import { getAggParamsToRender, @@ -28,6 +27,7 @@ import { import { FieldParamEditor, OrderByParamEditor } from './controls'; import { EditorConfig } from './utils'; import { Schema } from '../schemas'; +import { EditorVisState } from './sidebar/state/reducers'; jest.mock('../utils', () => ({ groupAndSortBy: jest.fn(() => ['indexedFields']), @@ -48,7 +48,7 @@ describe('DefaultEditorAggParams helpers', () => { hideCustomLabel: true, } as Schema, ]; - const state = {} as VisState; + const state = {} as EditorVisState; const metricAggs: IAggConfig[] = []; const emptyParams = { basic: [], diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts index 520ff6ffc5ff5..6b28c46577e7f 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_params_helper.ts @@ -20,7 +20,6 @@ import { get, isEmpty } from 'lodash'; import { IndexPattern, IndexPatternField } from 'src/plugins/data/public'; -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { groupAndSortBy, ComboBoxGroupedOptions } from '../utils'; import { AggTypeState, AggParamsState } from './agg_params_state'; import { AggParamEditorProps } from './agg_param_props'; @@ -36,12 +35,13 @@ import { } from '../legacy_imports'; import { EditorConfig } from './utils'; import { Schema, getSchemaByName } from '../schemas'; +import { EditorVisState } from './sidebar/state/reducers'; interface ParamInstanceBase { agg: IAggConfig; editorConfig: EditorConfig; metricAggs: IAggConfig[]; - state: VisState; + state: EditorVisState; schemas: Schema[]; hideCustomLabel?: boolean; } diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx index 186738d0f551c..03050c7b11442 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/field.test.tsx @@ -23,10 +23,10 @@ import { mount, shallow, ReactWrapper } from 'enzyme'; import { EuiComboBoxProps, EuiComboBox } from '@elastic/eui'; import { IndexPatternField } from 'src/plugins/data/public'; -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { ComboBoxGroupedOptions } from '../../utils'; import { FieldParamEditor, FieldParamEditorProps } from './field'; import { IAggConfig } from '../../legacy_imports'; +import { EditorVisState } from '../sidebar/state/reducers'; function callComboBoxOnChange(comp: ReactWrapper, value: any = []) { const comboBoxProps = comp.find(EuiComboBox).props() as EuiComboBoxProps; @@ -79,7 +79,7 @@ describe('FieldParamEditor component', () => { setValue, setValidity, setTouched, - state: {} as VisState, + state: {} as EditorVisState, metricAggs: [] as IAggConfig[], schemas: [], }; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/percentiles.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/controls/percentiles.test.tsx index 0eaf9bcc987c1..1c21bf2161c92 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/percentiles.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/percentiles.test.tsx @@ -20,9 +20,9 @@ import React from 'react'; import { AggParamEditorProps } from '../agg_param_props'; import { IAggConfig } from '../../legacy_imports'; -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { mount } from 'enzyme'; import { PercentilesEditor } from './percentiles'; +import { EditorVisState } from '../sidebar/state/reducers'; describe('PercentilesEditor component', () => { let setValue: jest.Mock; @@ -45,7 +45,7 @@ describe('PercentilesEditor component', () => { setValue, setValidity, setTouched, - state: {} as VisState, + state: {} as EditorVisState, metricAggs: [] as IAggConfig[], schemas: [], }; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts b/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts index 8a21114999cd6..23971d0a070d3 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/controls/test_utils.ts @@ -17,9 +17,9 @@ * under the License. */ -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { IAggConfig, AggParam } from '../../legacy_imports'; import { EditorConfig } from '../utils'; +import { EditorVisState } from '../sidebar/state/reducers'; export const aggParamCommonPropsMock = { agg: {} as IAggConfig, @@ -27,7 +27,7 @@ export const aggParamCommonPropsMock = { editorConfig: {} as EditorConfig, formIsTouched: false, metricAggs: [] as IAggConfig[], - state: {} as VisState, + state: {} as EditorVisState, showValidation: false, schemas: [], }; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx index 1c1f9d57d8b90..34d4f3ca5289f 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/data_tab.tsx @@ -21,7 +21,6 @@ import React, { useMemo, useCallback } from 'react'; import { findLast } from 'lodash'; import { EuiSpacer } from '@elastic/eui'; -import { VisState } from 'src/legacy/core_plugins/visualizations/public'; import { IAggConfig, AggGroupNames, @@ -40,6 +39,7 @@ import { } from './state'; import { AddSchema, ReorderAggs, DefaultEditorAggCommonProps } from '../agg_common_props'; import { ISchemas } from '../../schemas'; +import { EditorVisState } from './state/reducers'; export interface DefaultEditorDataTabProps { dispatch: React.Dispatch; @@ -47,7 +47,7 @@ export interface DefaultEditorDataTabProps { isTabSelected: boolean; metricAggs: IAggConfig[]; schemas: ISchemas; - state: VisState; + state: EditorVisState; setTouched(isTouched: boolean): void; setValidity(modelName: string, value: boolean): void; setStateValue: DefaultEditorAggCommonProps['setStateParamValue']; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/sidebar.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/sidebar.tsx index 1efd8dae8178b..c06ab51373b9d 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/sidebar.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/sidebar.tsx @@ -17,7 +17,7 @@ * under the License. */ -import React, { useMemo, useState, useCallback, KeyboardEventHandler, useEffect } from 'react'; +import React, { useMemo, useState, useCallback, KeyboardEventHandler } from 'react'; import { get, isEqual } from 'lodash'; import { i18n } from '@kbn/i18n'; import { keyCodes, EuiButtonIcon, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; @@ -26,10 +26,9 @@ import { Vis } from 'src/legacy/core_plugins/visualizations/public'; import { AggGroupNames } from '../../legacy_imports'; import { DefaultEditorNavBar, OptionTab } from './navbar'; import { DefaultEditorControls } from './controls'; -import { setStateParamValue, useEditorReducer, useEditorFormState, discardChanges } from './state'; +import { setStateParamValue, useEditorReducer, useEditorFormState } from './state'; import { DefaultEditorAggCommonProps } from '../agg_common_props'; import { SidebarTitle } from './sidebar_title'; -import { PersistedState } from '../../../../../../plugins/visualizations/public'; import { SavedSearch } from '../../../../../../plugins/discover/public'; import { getSchemasByGroup } from '../../schemas'; @@ -37,9 +36,9 @@ interface DefaultEditorSideBarProps { isCollapsed: boolean; onClickCollapse: () => void; optionTabs: OptionTab[]; - uiState: PersistedState; vis: Vis; - isLinkedSearch: boolean; + unlinkFromSavedSearch: any; + reloadVisualization: any; savedSearch?: SavedSearch; } @@ -47,17 +46,27 @@ function DefaultEditorSideBar({ isCollapsed, onClickCollapse, optionTabs, - uiState, vis, - isLinkedSearch, - savedSearch, + unlinkFromSavedSearch, + reloadVisualization, }: DefaultEditorSideBarProps) { const [selectedTab, setSelectedTab] = useState(optionTabs[0].name); const [isDirty, setDirty] = useState(false); - const [state, dispatch] = useEditorReducer(vis); + + const dirtyStateChange = ({ isDirty: dirty }: { isDirty: boolean }) => { + setDirty(dirty); + + if (!dirty) { + resetValidity(); + } + }; + + const [state, dispatch] = useEditorReducer(vis, dirtyStateChange); const { formState, setTouched, setValidity, resetValidity } = useEditorFormState(); - const responseAggs = useMemo(() => state.aggs.getResponseAggs(), [state.aggs]); + const responseAggs = useMemo(() => (state.data.aggs ? state.data.aggs.getResponseAggs() : []), [ + state.data.aggs, + ]); const metricSchemas = getSchemasByGroup(vis.type.schemas.all || [], AggGroupNames.Metrics).map( s => s.name ); @@ -90,17 +99,17 @@ function DefaultEditorSideBar({ const applyChanges = useCallback(() => { if (formState.invalid || !isDirty) { setTouched(true); - return; } - vis.setCurrentState(state); - vis.updateState(); - vis.emit('dirtyStateChange', { - isDirty: false, + vis.setState({ + ...vis.serialize(), + params: state.params, + data: { aggs: state.data.aggs!.aggs.map(agg => agg.toJSON()) as any }, }); + reloadVisualization(); setTouched(false); - }, [vis, state, formState.invalid, setTouched, isDirty]); + }, [reloadVisualization, state, formState.invalid, setTouched, isDirty, vis]); const onSubmit: KeyboardEventHandler = useCallback( event => { @@ -114,27 +123,6 @@ function DefaultEditorSideBar({ [applyChanges] ); - useEffect(() => { - const changeHandler = ({ isDirty: dirty }: { isDirty: boolean }) => { - setDirty(dirty); - - if (!dirty) { - resetValidity(); - } - }; - vis.on('dirtyStateChange', changeHandler); - - return () => vis.off('dirtyStateChange', changeHandler); - }, [resetValidity, vis]); - - // subscribe on external vis changes using browser history, for example press back button - useEffect(() => { - const resetHandler = () => dispatch(discardChanges(vis)); - vis.on('updateEditor', resetHandler); - - return () => vis.off('updateEditor', resetHandler); - }, [dispatch, vis]); - const dataTabProps = { dispatch, formIsTouched: formState.touched, @@ -147,16 +135,17 @@ function DefaultEditorSideBar({ }; const optionTabProps = { - aggs: state.aggs, + aggs: state.data.aggs!, hasHistogramAgg, stateParams: state.params, vis, - uiState, setValue: setStateValue, setValidity: setStateValidity, setTouched, }; + const savedSearch = {}; + return ( <> {vis.type.requiresSearch && ( - + )} {optionTabs.length > 1 && ( diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx index 876404851aed4..dc019d42c6a78 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/sidebar_title.tsx @@ -40,22 +40,23 @@ import { SavedSearch } from '../../../../../../plugins/discover/public'; interface LinkedSearchProps { savedSearch: SavedSearch; vis: Vis; + unlinkFromSavedSearch: any; } interface SidebarTitleProps { - isLinkedSearch: boolean; + unlinkFromSavedSearch: any; savedSearch?: SavedSearch; vis: Vis; } -export function LinkedSearch({ savedSearch, vis }: LinkedSearchProps) { +export function LinkedSearch({ savedSearch, vis, unlinkFromSavedSearch }: LinkedSearchProps) { const [showPopover, setShowPopover] = useState(false); const closePopover = useCallback(() => setShowPopover(false), []); const onClickButtonLink = useCallback(() => setShowPopover(v => !v), []); const onClickUnlikFromSavedSearch = useCallback(() => { setShowPopover(false); - vis.emit('unlinkFromSavedSearch'); - }, [vis]); + unlinkFromSavedSearch(); + }, [unlinkFromSavedSearch]); const linkButtonAriaLabel = i18n.translate( 'visDefaultEditor.sidebar.savedSearch.linkButtonAriaLabel', @@ -151,20 +152,24 @@ export function LinkedSearch({ savedSearch, vis }: LinkedSearchProps) { ); } -function SidebarTitle({ savedSearch, vis, isLinkedSearch }: SidebarTitleProps) { - return isLinkedSearch && savedSearch ? ( - +function SidebarTitle({ savedSearch, vis, unlinkFromSavedSearch }: SidebarTitleProps) { + return savedSearch ? ( + ) : vis.type.options.showIndexSelection ? (

- {vis.indexPattern.title} + {vis.data.indexPattern!.title}

) : ( diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/index.ts b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/index.ts index df5ba3f6121c7..e26182cb4c29d 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/index.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/index.ts @@ -17,42 +17,31 @@ * under the License. */ -import { useEffect, useReducer, useCallback } from 'react'; -import { isEqual } from 'lodash'; +import { useReducer, useCallback } from 'react'; -import { Vis, VisState, VisParams } from 'src/legacy/core_plugins/visualizations/public'; -import { editorStateReducer, initEditorState } from './reducers'; +import { Vis } from 'src/legacy/core_plugins/visualizations/public'; +import { editorStateReducer, EditorVisState, initEditorState } from './reducers'; import { EditorStateActionTypes } from './constants'; -import { EditorAction, updateStateParams } from './actions'; +import { EditorAction } from './actions'; export * from './editor_form_state'; export * from './actions'; -export function useEditorReducer(vis: Vis): [VisState, React.Dispatch] { +export function useEditorReducer( + vis: Vis, + dirtyStateChange: any +): [EditorVisState, React.Dispatch] { const [state, dispatch] = useReducer(editorStateReducer, vis, initEditorState); - useEffect(() => { - const handleVisUpdate = (params: VisParams) => { - if (!isEqual(params, state.params)) { - dispatch(updateStateParams(params)); - } - }; - - // fires when visualization state changes, and we need to copy changes to editorState - vis.on('updateEditorStateParams', handleVisUpdate); - - return () => vis.off('updateEditorStateParams', handleVisUpdate); - }, [vis, state.params]); - const wrappedDispatch = useCallback( (action: EditorAction) => { dispatch(action); - vis.emit('dirtyStateChange', { + dirtyStateChange({ isDirty: action.type !== EditorStateActionTypes.DISCARD_CHANGES, }); }, - [vis] + [dirtyStateChange] ); return [state, wrappedDispatch]; diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts index 73675e75cbe36..c2ab95ea10621 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts +++ b/src/legacy/core_plugins/vis_default_editor/public/components/sidebar/state/reducers.ts @@ -19,33 +19,40 @@ import { cloneDeep } from 'lodash'; -import { Vis, VisState } from 'src/legacy/core_plugins/visualizations/public'; +import { Vis } from 'src/legacy/core_plugins/visualizations/public'; import { createAggConfigs, AggGroupNames } from '../../../legacy_imports'; import { EditorStateActionTypes } from './constants'; import { getEnabledMetricAggsCount } from '../../agg_group_helper'; import { EditorAction } from './actions'; function initEditorState(vis: Vis) { - return vis.copyCurrentState(true); + return { + ...vis.clone(), + }; } -function editorStateReducer(state: VisState, action: EditorAction): VisState { +export type EditorVisState = Pick; + +function editorStateReducer(state: EditorVisState, action: EditorAction): EditorVisState { switch (action.type) { case EditorStateActionTypes.ADD_NEW_AGG: { const { schema } = action.payload; const defaultConfig = - !state.aggs.aggs.find(agg => agg.schema === schema.name) && schema.defaults + !state.data.aggs!.aggs.find(agg => agg.schema === schema.name) && schema.defaults ? (schema as any).defaults.slice(0, schema.max) : { schema: schema.name }; - const aggConfig = state.aggs.createAggConfig(defaultConfig, { + const aggConfig = state.data.aggs!.createAggConfig(defaultConfig, { addToAggConfigs: false, }); aggConfig.brandNew = true; - const newAggs = [...state.aggs.aggs, aggConfig]; + const newAggs = [...state.data.aggs!.aggs, aggConfig]; return { ...state, - aggs: createAggConfigs(state.aggs.indexPattern, newAggs), + data: { + ...state.data, + aggs: createAggConfigs(state.data.indexPattern!, newAggs), + }, }; } @@ -56,7 +63,7 @@ function editorStateReducer(state: VisState, action: EditorAction): VisState { case EditorStateActionTypes.CHANGE_AGG_TYPE: { const { aggId, value } = action.payload; - const newAggs = state.aggs.aggs.map(agg => { + const newAggs = state.data.aggs!.aggs.map(agg => { if (agg.id === aggId) { agg.type = value; @@ -68,14 +75,17 @@ function editorStateReducer(state: VisState, action: EditorAction): VisState { return { ...state, - aggs: createAggConfigs(state.aggs.indexPattern, newAggs), + data: { + ...state.data, + aggs: createAggConfigs(state.data.indexPattern!, newAggs), + }, }; } case EditorStateActionTypes.SET_AGG_PARAM_VALUE: { const { aggId, paramName, value } = action.payload; - const newAggs = state.aggs.aggs.map(agg => { + const newAggs = state.data.aggs!.aggs.map(agg => { if (agg.id === aggId) { const parsedAgg = agg.toJSON(); @@ -93,7 +103,10 @@ function editorStateReducer(state: VisState, action: EditorAction): VisState { return { ...state, - aggs: createAggConfigs(state.aggs.indexPattern, newAggs), + data: { + ...state.data, + aggs: createAggConfigs(state.data.indexPattern!, newAggs), + }, }; } @@ -111,7 +124,7 @@ function editorStateReducer(state: VisState, action: EditorAction): VisState { case EditorStateActionTypes.REMOVE_AGG: { let isMetric = false; - const newAggs = state.aggs.aggs.filter(({ id, schema }) => { + const newAggs = state.data.aggs!.aggs.filter(({ id, schema }) => { if (id === action.payload.aggId) { const schemaDef = action.payload.schemas.find(s => s.name === schema); if (schemaDef && schemaDef.group === AggGroupNames.Metrics) { @@ -134,26 +147,36 @@ function editorStateReducer(state: VisState, action: EditorAction): VisState { return { ...state, - aggs: createAggConfigs(state.aggs.indexPattern, newAggs), + data: { + ...state.data, + aggs: createAggConfigs(state.data.indexPattern!, newAggs), + }, }; } case EditorStateActionTypes.REORDER_AGGS: { const { sourceAgg, destinationAgg } = action.payload; - const destinationIndex = state.aggs.aggs.indexOf(destinationAgg); - const newAggs = [...state.aggs.aggs]; - newAggs.splice(destinationIndex, 0, newAggs.splice(state.aggs.aggs.indexOf(sourceAgg), 1)[0]); + const destinationIndex = state.data.aggs!.aggs.indexOf(destinationAgg); + const newAggs = [...state.data.aggs!.aggs]; + newAggs.splice( + destinationIndex, + 0, + newAggs.splice(state.data.aggs!.aggs.indexOf(sourceAgg), 1)[0] + ); return { ...state, - aggs: createAggConfigs(state.aggs.indexPattern, newAggs), + data: { + ...state.data, + aggs: createAggConfigs(state.data.indexPattern!, newAggs), + }, }; } case EditorStateActionTypes.TOGGLE_ENABLED_AGG: { const { aggId, enabled } = action.payload; - const newAggs = state.aggs.aggs.map(agg => { + const newAggs = state.data.aggs!.aggs.map(agg => { if (agg.id === aggId) { const parsedAgg = agg.toJSON(); @@ -168,7 +191,10 @@ function editorStateReducer(state: VisState, action: EditorAction): VisState { return { ...state, - aggs: createAggConfigs(state.aggs.indexPattern, newAggs), + data: { + ...state.data, + aggs: createAggConfigs(state.data.indexPattern!, newAggs), + }, }; } diff --git a/src/legacy/core_plugins/vis_default_editor/public/default_editor.tsx b/src/legacy/core_plugins/vis_default_editor/public/default_editor.tsx index fa3213d244e7e..def0e8a9a32ac 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/default_editor.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/default_editor.tsx @@ -20,10 +20,6 @@ import React, { useEffect, useRef, useState, useCallback } from 'react'; import { EditorRenderProps } from '../../kibana/public/visualize/np_ready/types'; -import { - VisualizeEmbeddableContract as VisualizeEmbeddable, - VisualizeEmbeddableFactoryContract as VisualizeEmbeddableFactory, -} from '../../visualizations/public/'; import { PanelsContainer, Panel } from '../../../../plugins/kibana_react/public'; import './vis_type_agg_filter'; @@ -33,67 +29,33 @@ import { getInitialWidth } from './editor_size'; function DefaultEditor({ embeddable, - savedObj, + vis, uiState, timeRange, filters, appState, optionTabs, query, - linked, + embeddableHandler, + reloadVisualization, + unlinkFromSavedSearch, }: DefaultEditorControllerState & Omit) { const visRef = useRef(null); - const visHandler = useRef(null); const [isCollapsed, setIsCollapsed] = useState(false); - const [factory, setFactory] = useState(null); - const { vis, savedSearch } = savedObj; const onClickCollapse = useCallback(() => { setIsCollapsed(value => !value); }, []); useEffect(() => { - async function visualize() { - if (!visRef.current || (!visHandler.current && factory)) { - return; - } - - if (!visHandler.current) { - const embeddableFactory = embeddable.getEmbeddableFactory( - 'visualization' - ) as VisualizeEmbeddableFactory; - setFactory(embeddableFactory); - - visHandler.current = (await embeddableFactory.createFromObject(savedObj, { - // should be look through createFromObject interface again because of "id" param - id: '', - uiState, - appState, - timeRange, - filters, - query, - })) as VisualizeEmbeddable; - - visHandler.current.render(visRef.current); - } else { - visHandler.current.updateInput({ - timeRange, - filters, - query, - }); - } + if (!visRef.current) { + return; } - visualize(); - }, [uiState, savedObj, timeRange, filters, appState, query, factory, embeddable]); + embeddableHandler.render(visRef.current); - useEffect(() => { - return () => { - if (visHandler.current) { - visHandler.current.destroy(); - } - }; - }, []); + return () => embeddableHandler.destroy(); + }, [embeddableHandler]); const editorInitialWidth = getInitialWidth(vis.type.editorConfig.defaultSize); @@ -117,9 +79,8 @@ function DefaultEditor({ onClickCollapse={onClickCollapse} optionTabs={optionTabs} vis={vis} - uiState={uiState} - isLinkedSearch={linked} - savedSearch={savedSearch} + unlinkFromSavedSearch={unlinkFromSavedSearch} + reloadVisualization={reloadVisualization} /> diff --git a/src/legacy/core_plugins/vis_default_editor/public/default_editor_controller.tsx b/src/legacy/core_plugins/vis_default_editor/public/default_editor_controller.tsx index db910604eddd1..5219b2a48bf2d 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/default_editor_controller.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/default_editor_controller.tsx @@ -23,7 +23,7 @@ import { i18n } from '@kbn/i18n'; import { I18nProvider } from '@kbn/i18n/react'; import { EditorRenderProps } from 'src/legacy/core_plugins/kibana/public/visualize/np_ready/types'; -import { VisSavedObject } from 'src/legacy/core_plugins/visualizations/public/'; +import { Vis } from 'src/legacy/core_plugins/visualizations/public/'; import { Storage } from '../../../../plugins/kibana_utils/public'; import { KibanaContextProvider } from '../../../../plugins/kibana_react/public'; import { DefaultEditor } from './default_editor'; @@ -32,7 +32,10 @@ import { DefaultEditorDataTab, OptionTab } from './components/sidebar'; const localStorage = new Storage(window.localStorage); export interface DefaultEditorControllerState { - savedObj: VisSavedObject; + vis: Vis; + reloadVisualization: any; + unlinkFromSavedSearch: any; + embeddableHandler: any; optionTabs: OptionTab[]; } @@ -40,9 +43,15 @@ class DefaultEditorController { private el: HTMLElement; private state: DefaultEditorControllerState; - constructor(el: HTMLElement, savedObj: VisSavedObject) { + constructor( + el: HTMLElement, + vis: Vis, + embeddableHandler: any, + reloadVisualization: any, + unlinkFromSavedSearch: any + ) { this.el = el; - const { type: visType } = savedObj.vis; + const { type: visType } = vis; const optionTabs = [ ...(visType.schemas.buckets || visType.schemas.metrics @@ -71,8 +80,11 @@ class DefaultEditorController { ]; this.state = { - savedObj, + vis, optionTabs, + embeddableHandler, + reloadVisualization, + unlinkFromSavedSearch, }; } diff --git a/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx b/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx index 18fbba1b039b5..38693f8cfaeab 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/vis_options_props.tsx @@ -17,7 +17,6 @@ * under the License. */ -import { PersistedState } from '../../../../plugins/visualizations/public'; import { IAggConfigs } from './legacy_imports'; import { Vis } from '../../visualizations/public'; @@ -27,7 +26,6 @@ export interface VisOptionsProps { isTabSelected: boolean; stateParams: VisParamType; vis: Vis; - uiState: PersistedState; setValue(paramName: T, value: VisParamType[T]): void; setValidity(isValid: boolean): void; setTouched(isTouched: boolean): void; From 46972253db637ed193eab4d7294c8a9580257a3a Mon Sep 17 00:00:00 2001 From: ppisljar Date: Thu, 12 Mar 2020 07:52:57 -0700 Subject: [PATCH 05/26] vis types --- .../public/components/metric_vis_component.tsx | 5 +++-- .../public/components/metric_vis_options.tsx | 3 +-- .../vis_type_table/public/vis_controller.ts | 9 +++++---- .../public/components/timelion_vis.tsx | 4 ++-- .../public/components/vis_editor.js | 14 +++++--------- .../components/vis_editor_visualization.js | 13 +++---------- .../public/editor_controller.js | 16 ++++++++++------ .../public/components/common/color_schema.tsx | 12 ++++++------ .../components/options/gauge/ranges_panel.tsx | 3 +-- .../public/components/options/heatmap/index.tsx | 4 ++-- .../components/options/metrics_axes/index.tsx | 2 +- .../options/point_series/point_series.tsx | 4 +++- .../vis_type_vislib/public/vis_controller.tsx | 5 +++-- .../public/vislib/components/legend/legend.tsx | 16 +--------------- 14 files changed, 46 insertions(+), 64 deletions(-) diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx index a93bb618da31f..175458497a05e 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.tsx @@ -27,12 +27,13 @@ import { FieldFormatsContentType, IFieldFormat } from '../../../../../plugins/da import { KibanaDatatable } from '../../../../../plugins/expressions/public'; import { getHeatmapColors } from '../../../../../plugins/charts/public'; import { VisParams, MetricVisMetric } from '../types'; -import { SchemaConfig, Vis } from '../../../visualizations/public'; +import { SchemaConfig } from '../../../visualizations/public'; +import { ExprVis } from '../../../visualizations/public/np_ready/public/expressions/vis'; export interface MetricVisComponentProps { visParams: VisParams; visData: Input; - vis: Vis; + vis: ExprVis; renderComplete: () => void; } diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx index 661f16d6497ba..4e5696d0dc352 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_options.tsx @@ -47,7 +47,6 @@ function MetricVisOptions({ setValidity, setTouched, vis, - uiState, }: VisOptionsProps) { const setMetricValue: ( paramName: T, @@ -163,7 +162,7 @@ function MetricVisOptions({ invertColors={stateParams.metric.invertColors} setValue={setMetricValue as SetColorSchemaOptionsValue} showHelpText={false} - uiState={uiState} + vis={vis} /> diff --git a/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts b/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts index 2d27a99bdd8af..0a00957163705 100644 --- a/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts +++ b/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts @@ -21,10 +21,11 @@ import angular, { IModule, auto, IRootScopeService, IScope, ICompileService } fr import $ from 'jquery'; import { isEqual } from 'lodash'; -import { Vis, VisParams } from '../../visualizations/public'; +import { VisParams } from '../../visualizations/public'; import { npStart } from './legacy_imports'; import { getAngularModule } from './get_inner_angular'; import { initTableVisLegacyModule } from './table_vis_legacy_module'; +import { ExprVis } from '../../visualizations/public/np_ready/public/expressions/vis'; const innerAngularName = 'kibana/table_vis'; @@ -32,12 +33,12 @@ export class TableVisualizationController { private tableVisModule: IModule | undefined; private injector: auto.IInjectorService | undefined; el: JQuery; - vis: Vis; + vis: ExprVis; $rootScope: IRootScopeService | null = null; $scope: (IScope & { [key: string]: any }) | undefined; $compile: ICompileService | undefined; - constructor(domeElement: Element, vis: Vis) { + constructor(domeElement: Element, vis: ExprVis) { this.el = $(domeElement); this.vis = vis; } @@ -93,7 +94,7 @@ export class TableVisualizationController { this.$scope = this.$rootScope.$new(); this.$scope.uiState = this.vis.getUiState(); updateScope(); - this.el.find('div').append(this.$compile(this.vis.type.visConfig.template)(this.$scope)); + this.el.find('div').append(this.$compile(this.vis.type!.visConfig.template)(this.$scope)); this.$scope.$apply(); } else { updateScope(); diff --git a/src/legacy/core_plugins/vis_type_timelion/public/components/timelion_vis.tsx b/src/legacy/core_plugins/vis_type_timelion/public/components/timelion_vis.tsx index 9e11fd5d3f45c..f55d1602ea342 100644 --- a/src/legacy/core_plugins/vis_type_timelion/public/components/timelion_vis.tsx +++ b/src/legacy/core_plugins/vis_type_timelion/public/components/timelion_vis.tsx @@ -20,16 +20,16 @@ import React from 'react'; import { IUiSettingsClient } from 'kibana/public'; -import { Vis } from 'src/legacy/core_plugins/visualizations/public'; import { ChartComponent } from './chart'; import { VisParams } from '../timelion_vis_fn'; import { TimelionSuccessResponse } from '../helpers/timelion_request_handler'; +import { ExprVis } from '../../../visualizations/public/np_ready/public/expressions/vis'; export interface TimelionVisComponentProp { config: IUiSettingsClient; renderComplete(): void; updateStatus: object; - vis: Vis; + vis: ExprVis; visData: TimelionSuccessResponse; visParams: VisParams; } diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js index ff2546f75c51a..90ff25090ef81 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor.js @@ -65,7 +65,7 @@ export class VisEditor extends Component { } get uiState() { - return this.props.vis.getUiState(); + return this.props.vis.uiState; } getConfig = (...args) => { @@ -73,17 +73,12 @@ export class VisEditor extends Component { }; handleUiState = (field, value) => { - this.props.vis.uiStateVal(field, value); + this.props.vis.uiState.set(field, value); }; updateVisState = debounce(() => { this.props.vis.params = this.state.model; - this.props.vis.updateState(); - // This check should be redundant, since this method should only be called when we're in editor - // mode where there's also an appState passed into us. - if (this.props.appState) { - this.props.appState.save(); - } + this.props.reloadVisualization(); }, VIS_STATE_DEBOUNCE_DELAY); isValidKueryQuery = filterQuery => { @@ -184,7 +179,8 @@ export class VisEditor extends Component { dirty={this.state.dirty} autoApply={this.state.autoApply} model={model} - savedObj={this.props.savedObj} + embeddableHandler={this.props.embeddableHandler} + vis={this.props.vis} timeRange={this.props.timeRange} uiState={this.uiState} onCommit={this.handleCommit} diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor_visualization.js b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor_visualization.js index c45a4d68e8aad..fbd17d99be9bf 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor_visualization.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/components/vis_editor_visualization.js @@ -29,7 +29,6 @@ import { AUTO_INTERVAL, } from './lib/get_interval'; import { PANEL_TYPES } from '../../../../../plugins/vis_type_timeseries/common/panel_types'; -import { start as embeddables } from '../../../embeddable_api/public/np_ready/public/legacy'; const MIN_CHART_HEIGHT = 300; @@ -70,15 +69,9 @@ class VisEditorVisualizationUI extends Component { return; } - const { timeRange, savedObj, onDataChange } = this.props; + const { onDataChange, embeddableHandler } = this.props; - this._handler = await embeddables - .getEmbeddableFactory('visualization') - .createFromObject(savedObj, { - vis: {}, - timeRange: timeRange, - filters: [], - }); + this._handler = embeddableHandler; await this._handler.render(this._visEl.current); this._subscription = this._handler.handler.data$.subscribe(data => { @@ -285,7 +278,7 @@ VisEditorVisualizationUI.propTypes = { onCommit: PropTypes.func, uiState: PropTypes.object, onToggleAutoApply: PropTypes.func, - savedObj: PropTypes.object, + embeddableHandler: PropTypes.object, timeRange: PropTypes.object, dirty: PropTypes.bool, autoApply: PropTypes.bool, diff --git a/src/legacy/core_plugins/vis_type_timeseries/public/editor_controller.js b/src/legacy/core_plugins/vis_type_timeseries/public/editor_controller.js index 4d029553145da..2c64403466c43 100644 --- a/src/legacy/core_plugins/vis_type_timeseries/public/editor_controller.js +++ b/src/legacy/core_plugins/vis_type_timeseries/public/editor_controller.js @@ -23,12 +23,15 @@ import { fetchIndexPatternFields } from './lib/fetch_fields'; import { getSavedObjectsClient, getUISettings, getI18n } from './services'; export class EditorController { - constructor(el, savedObj) { + constructor(el, vis, embeddableHandler, reloadVisualization) { this.el = el; + this.embeddableHandler = embeddableHandler; + this.reloadVisualization = reloadVisualization; + this.state = { - savedObj: savedObj, - vis: savedObj.vis, + fields: [], + vis: vis, isLoaded: false, }; } @@ -47,7 +50,7 @@ export class EditorController { this.state.vis.params.default_index_pattern = title; this.state.vis.params.default_timefield = timeFieldName; - this.state.vis.fields = await fetchIndexPatternFields(this.state.vis); + this.state.fields = await fetchIndexPatternFields(this.state.vis); this.state.isLoaded = true; }; @@ -67,13 +70,14 @@ export class EditorController { {}} isEditorMode={true} appState={params.appState} + embeddableHandler={this.embeddableHandler} + reloadVisualization={this.reloadVisualization} /> , this.el diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_schema.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_schema.tsx index 06ce0a2b4af64..e2b9bbc38b96e 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_schema.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/common/color_schema.tsx @@ -36,7 +36,7 @@ export type SetColorSchemaOptionsValue = !!uiState.get('vis.colors')); + const [isCustomColors, setIsCustomColors] = useState(() => !!vis.uiState.get('vis.colors')); useEffect(() => { - uiState.on('colorChanged', () => { + vis.uiState.on('colorChanged', () => { setIsCustomColors(true); }); - }, [uiState]); + }, [vis.uiState]); const resetColorsButton = ( { - uiState.set('vis.colors', null); + vis.uiState.set('vis.colors', null); setIsCustomColors(false); }} > diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx index 7de64e5888096..a68600b63c2ee 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/gauge/ranges_panel.tsx @@ -35,7 +35,6 @@ function RangesPanel({ setValidity, setValue, stateParams, - uiState, vis, }: GaugeOptionsInternalProps) { const setColorSchemaOptions = useCallback( @@ -102,7 +101,7 @@ function RangesPanel({ colorSchema={stateParams.gauge.colorSchema} colorSchemas={vis.type.editorConfig.collections.colorSchemas} invertColors={stateParams.gauge.invertColors} - uiState={uiState} + vis={vis} setValue={setColorSchemaOptions} /> diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx index 452b9ed9bdbb1..a699a926aba96 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/heatmap/index.tsx @@ -39,7 +39,7 @@ import { LabelsPanel } from './labels_panel'; import { SetColorRangeValue } from '../../common/color_ranges'; function HeatmapOptions(props: VisOptionsProps) { - const { stateParams, vis, uiState, setValue, setValidity, setTouched } = props; + const { stateParams, vis, setValue, setValidity, setTouched } = props; const [valueAxis] = stateParams.valueAxes; const isColorsNumberInvalid = stateParams.colorsNumber < 2 || stateParams.colorsNumber > 10; const [isColorRangesValid, setIsColorRangesValid] = useState(false); @@ -108,7 +108,7 @@ function HeatmapOptions(props: VisOptionsProps) { colorSchema={stateParams.colorSchema} colorSchemas={vis.type.editorConfig.collections.colorSchemas} invertColors={stateParams.invertColors} - uiState={uiState} + vis={vis} setValue={setValue as SetColorSchemaOptionsValue} /> diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx index 82b64e4185ed2..14f53e278ded9 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/metrics_axes/index.tsx @@ -299,7 +299,7 @@ function MetricsAxisOptions(props: ValidationVisOptionsProps) }, [stateParams.seriesParams]); useEffect(() => { - vis.setVisType(visType); + vis.setState({ type: visType } as any); }, [vis, visType]); return isTabSelected ? ( diff --git a/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx b/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx index 229c4922145e8..7cc784ce8212b 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/components/options/point_series/point_series.tsx @@ -44,7 +44,9 @@ function PointSeriesOptions(props: ValidationVisOptionsProps) - {vis.hasSchemaAgg('segment', 'date_histogram') ? ( + {vis.data.aggs!.aggs.filter( + agg => agg.schema === 'segment' && agg.type.name === 'date_histogram' + ) ? ( { legendEl: HTMLDivElement; vislibVis: any; - constructor(public el: Element, public vis: Vis) { + constructor(public el: Element, public vis: ExprVis) { this.el = el; this.vis = vis; this.unmount = null; diff --git a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx index d82941b7b8cee..afd974d6d9b40 100644 --- a/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx +++ b/src/legacy/core_plugins/vis_type_vislib/public/vislib/components/legend/legend.tsx @@ -23,22 +23,11 @@ import { compact, uniq, map, every, isUndefined } from 'lodash'; import { i18n } from '@kbn/i18n'; import { EuiPopoverProps, EuiIcon, keyCodes, htmlIdGenerator } from '@elastic/eui'; -import { IAggConfig } from '../../../../../../../plugins/data/public'; +import { createFiltersFromEvent } from '../../../legacy_imports'; import { CUSTOM_LEGEND_VIS_TYPES, LegendItem } from './models'; import { VisLegendItem } from './legend_item'; import { getPieNames } from './pie_utils'; -import { Vis } from '../../../../../visualizations/public'; -import { createFiltersFromEvent, tabifyGetColumns } from '../../../legacy_imports'; - -const getTableAggs = (vis: Vis): IAggConfig[] => { - if (!vis.aggs || !vis.aggs.getResponseAggs) { - return []; - } - const columns = tabifyGetColumns(vis.aggs.getResponseAggs(), !vis.isHierarchical()); - return columns.map(c => c.aggConfig); -}; - export interface VisLegendProps { vis: any; vislibVis: any; @@ -50,7 +39,6 @@ export interface VisLegendProps { export interface VisLegendState { open: boolean; labels: any[]; - tableAggs: any[]; filterableLabels: Set; selectedLabel: string | null; } @@ -66,7 +54,6 @@ export class VisLegend extends PureComponent { this.state = { open, labels: [], - tableAggs: [], filterableLabels: new Set(), selectedLabel: null, }; @@ -200,7 +187,6 @@ export class VisLegend extends PureComponent { this.getColor = this.props.vislibVis.visConfig.data.getColorFunc(); } - this.setState({ tableAggs: getTableAggs(this.props.vis) }); this.setLabels(this.props.visData, vislibVis.visConfigArgs.type); }; From bfa59c72bd2dbc32f84517d0b301ddc751c44e87 Mon Sep 17 00:00:00 2001 From: ppisljar Date: Thu, 12 Mar 2020 12:11:41 -0700 Subject: [PATCH 06/26] fixing jest tests --- .../public/input_control_vis_type.ts | 2 - .../public/vis_controller.tsx | 2 +- .../region_map/public/region_map_type.js | 2 - .../public/region_map_visualization.js | 4 +- .../public/base_maps_visualization.js | 17 +- .../tile_map/public/tile_map_type.js | 2 - .../public/components/agg_group.test.tsx | 6 +- .../components/metric_vis_component.test.tsx | 6 +- .../public/metric_vis_type.test.ts | 15 +- .../public/table_vis_controller.test.ts | 32 +-- .../vis_type_table/public/vis_controller.ts | 3 +- .../components/tag_cloud_visualization.js | 15 +- .../public/tag_cloud_type.ts | 2 - .../vis_type_vega/public/vega_type.ts | 2 - .../public/vega_visualization.js | 11 +- .../__snapshots__/index.test.tsx.snap | 6 +- .../options/metrics_axes/index.test.tsx | 6 +- .../public/components/visualization.test.js | 11 +- .../public/components/visualization_chart.tsx | 4 +- .../public/np_ready/public/index.ts | 1 - .../public/legacy/build_pipeline.test.ts | 234 ++++++++---------- .../public/legacy/update_status.test.js | 102 -------- .../np_ready/public/legacy/update_status.ts | 94 ------- .../public/np_ready/public/types.ts | 4 +- 24 files changed, 163 insertions(+), 420 deletions(-) delete mode 100644 src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.test.js delete mode 100644 src/legacy/core_plugins/visualizations/public/np_ready/public/legacy/update_status.ts diff --git a/src/legacy/core_plugins/input_control_vis/public/input_control_vis_type.ts b/src/legacy/core_plugins/input_control_vis/public/input_control_vis_type.ts index dae6c9abb625e..023e6ebb7125c 100644 --- a/src/legacy/core_plugins/input_control_vis/public/input_control_vis_type.ts +++ b/src/legacy/core_plugins/input_control_vis/public/input_control_vis_type.ts @@ -22,7 +22,6 @@ import { i18n } from '@kbn/i18n'; import { createInputControlVisController } from './vis_controller'; import { getControlsTab } from './components/editor/controls_tab'; import { OptionsTab } from './components/editor/options_tab'; -import { Status } from '../../visualizations/public'; import { InputControlVisDependencies } from './plugin'; import { defaultFeedbackMessage } from '../../../../plugins/kibana_utils/common'; @@ -40,7 +39,6 @@ export function createInputControlVisTypeDefinition(deps: InputControlVisDepende defaultMessage: 'Create interactive controls for easy dashboard manipulation.', }), stage: 'experimental', - requiresUpdateStatus: [Status.PARAMS, Status.TIME], feedbackMessage: defaultFeedbackMessage, visualization: InputControlVisController, visConfig: { diff --git a/src/legacy/core_plugins/input_control_vis/public/vis_controller.tsx b/src/legacy/core_plugins/input_control_vis/public/vis_controller.tsx index 624d000dd8d7a..c0ab235c1b9d1 100644 --- a/src/legacy/core_plugins/input_control_vis/public/vis_controller.tsx +++ b/src/legacy/core_plugins/input_control_vis/public/vis_controller.tsx @@ -54,7 +54,7 @@ export const createInputControlVisController = (deps: InputControlVisDependencie .subscribe(this.queryBarUpdateHandler); } - async render(visData: any, visParams: VisParams, status: any) { + async render(visData: any, visParams: VisParams) { this.visParams = visParams; this.controls = []; this.controls = await this.initControls(); diff --git a/src/legacy/core_plugins/region_map/public/region_map_type.js b/src/legacy/core_plugins/region_map/public/region_map_type.js index a03fbe4b291e2..ffe75dc51664d 100644 --- a/src/legacy/core_plugins/region_map/public/region_map_type.js +++ b/src/legacy/core_plugins/region_map/public/region_map_type.js @@ -21,7 +21,6 @@ import { i18n } from '@kbn/i18n'; import { Schemas } from 'ui/agg_types'; import { mapToLayerWithId } from './util'; import { createRegionMapVisualization } from './region_map_visualization'; -import { Status } from '../../visualizations/public'; import { RegionMapOptions } from './components/region_map_options'; import { truncatedColorSchemas } from '../../../../plugins/charts/public'; @@ -55,7 +54,6 @@ provided base maps, or add your own. Darker colors represent higher values.', showAllShapes: true, //still under consideration }, }, - requiresUpdateStatus: [Status.AGGS, Status.PARAMS, Status.RESIZE, Status.DATA, Status.UI_STATE], visualization, editorConfig: { optionsTemplate: props => , diff --git a/src/legacy/core_plugins/region_map/public/region_map_visualization.js b/src/legacy/core_plugins/region_map/public/region_map_visualization.js index 8b5812052a395..25641ea76809d 100644 --- a/src/legacy/core_plugins/region_map/public/region_map_visualization.js +++ b/src/legacy/core_plugins/region_map/public/region_map_visualization.js @@ -39,8 +39,8 @@ export function createRegionMapVisualization({ serviceSettings, $injector, uiSet this._choroplethLayer = null; } - async render(esResponse, visParams, status) { - await super.render(esResponse, visParams, status); + async render(esResponse, visParams) { + await super.render(esResponse, visParams); if (this._choroplethLayer) { await this._choroplethLayer.whenDataLoaded(); } diff --git a/src/legacy/core_plugins/tile_map/public/base_maps_visualization.js b/src/legacy/core_plugins/tile_map/public/base_maps_visualization.js index ebb0c24243263..d38159c91ef9f 100644 --- a/src/legacy/core_plugins/tile_map/public/base_maps_visualization.js +++ b/src/legacy/core_plugins/tile_map/public/base_maps_visualization.js @@ -63,28 +63,21 @@ export function BaseMapsVisualizationProvider(serviceSettings) { * @param status * @return {Promise} */ - async render(esResponse, visParams, status) { + async render(esResponse, visParams) { if (!this._kibanaMap) { //the visualization has been destroyed; return; } await this._mapIsLoaded; - - if (status.resize) { - this._kibanaMap.resize(); - } - if (status.params || status.aggs) { - this._params = visParams; - await this._updateParams(); - } + this._kibanaMap.resize(); + this._params = visParams; + await this._updateParams(); if (this._hasESResponseChanged(esResponse)) { await this._updateData(esResponse); } - if (status.uiState) { - this._kibanaMap.useUiStateFromVisualization(this.vis); - } + this._kibanaMap.useUiStateFromVisualization(this.vis); await this._whenBaseLayerIsLoaded(); } diff --git a/src/legacy/core_plugins/tile_map/public/tile_map_type.js b/src/legacy/core_plugins/tile_map/public/tile_map_type.js index 544b63abe82c7..44ab29f2511a7 100644 --- a/src/legacy/core_plugins/tile_map/public/tile_map_type.js +++ b/src/legacy/core_plugins/tile_map/public/tile_map_type.js @@ -23,7 +23,6 @@ import { i18n } from '@kbn/i18n'; import { convertToGeoJson } from 'ui/vis/map/convert_to_geojson'; import { Schemas } from 'ui/agg_types'; -import { Status } from '../../visualizations/public'; import { createTileMapVisualization } from './tile_map_visualization'; import { TileMapOptions } from './components/tile_map_options'; import { MapTypes } from './map_types'; @@ -57,7 +56,6 @@ export function createTileMapTypeDefinition(dependencies) { wms: uiSettings.get('visualization:tileMap:WMSdefaults'), }, }, - requiresUpdateStatus: [Status.AGGS, Status.PARAMS, Status.RESIZE, Status.UI_STATE], requiresPartialRows: true, visualization: CoordinateMapsVisualization, responseHandler: convertToGeoJson, diff --git a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx index e81bab7b54299..f802bca90be0a 100644 --- a/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx +++ b/src/legacy/core_plugins/vis_default_editor/public/components/agg_group.test.tsx @@ -103,9 +103,9 @@ describe('DefaultEditorAgg component', () => { formIsTouched: false, metricAggs: [], groupName: 'metrics', - state: ({ - aggs, - } as any) as EditorVisState, + state: { + data: { aggs }, + } as EditorVisState, schemas: [ { name: 'metrics', diff --git a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx index 6a466c9cd0211..7ba4fe017522d 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx +++ b/src/legacy/core_plugins/vis_type_metric/public/components/metric_vis_component.test.tsx @@ -20,12 +20,12 @@ import React from 'react'; import { shallow } from 'enzyme'; -import { Vis } from 'src/legacy/core_plugins/visualizations/public'; import { MetricVisComponent, MetricVisComponentProps } from './metric_vis_component'; // eslint-disable-next-line @kbn/eslint/no-restricted-paths import { npStart } from 'ui/new_platform'; import { fieldFormats } from '../../../../../plugins/data/public'; import { identity } from 'lodash'; +import { ExprVis } from '../../../visualizations/public/np_ready/public/expressions/vis'; jest.mock('ui/new_platform'); @@ -37,7 +37,7 @@ const baseVisData = { } as any; describe('MetricVisComponent', function() { - const vis: Vis = { + const vis: ExprVis = { params: { metric: { colorSchema: 'Green to Red', @@ -57,7 +57,7 @@ describe('MetricVisComponent', function() { const getComponent = (propOverrides: Partial = {} as Partial) => { const props: Props = { vis, - visParams: vis.params, + visParams: vis.params as any, visData: baseVisData, renderComplete: jest.fn(), ...propOverrides, diff --git a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts index 5813465cc3f00..967450d45d49d 100644 --- a/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts +++ b/src/legacy/core_plugins/vis_type_metric/public/metric_vis_type.test.ts @@ -74,11 +74,22 @@ describe('metric_vis - createMetricVisTypeDefinition', () => { labelTemplate: 'ip[{{value}}]', }); + const searchSource = { + getField: (name: string) => { + if (name === 'index') { + return stubIndexPattern; + } + }, + }; + // TODO: remove when Vis is converted to typescript. Only importing Vis as type // @ts-ignore - vis = visualizationsStart.createVis(stubIndexPattern, { + vis = visualizationsStart.createVis('metric', { type: 'metric', - aggs: [{ id: '1', type: 'top_hits', schema: 'metric', params: { field: 'ip' } }], + data: { + searchSource, + aggs: [{ id: '1', type: 'top_hits', schema: 'metric', params: { field: 'ip' } }], + }, }); vis.params.dimensions = { diff --git a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts index 6d4e94c6292a6..269aea4ca3e95 100644 --- a/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts +++ b/src/legacy/core_plugins/vis_type_table/public/table_vis_controller.test.ts @@ -113,20 +113,22 @@ describe('Table Vis - Controller', () => { return ({ type: tableVisTypeDefinition, params: Object.assign({}, tableVisTypeDefinition.visConfig.defaults, params), - aggs: createAggConfigs(stubIndexPattern, [ - { type: 'count', schema: 'metric' }, - { - type: 'range', - schema: 'bucket', - params: { - field: 'bytes', - ranges: [ - { from: 0, to: 1000 }, - { from: 1000, to: 2000 }, - ], + data: { + aggs: createAggConfigs(stubIndexPattern, [ + { type: 'count', schema: 'metric' }, + { + type: 'range', + schema: 'bucket', + params: { + field: 'bytes', + ranges: [ + { from: 0, to: 1000 }, + { from: 1000, to: 2000 }, + ], + }, }, - }, - ]), + ]), + }, } as unknown) as Vis; } @@ -146,11 +148,11 @@ describe('Table Vis - Controller', () => { // basically a parameterized beforeEach function initController(vis: Vis) { - vis.aggs.aggs.forEach((agg: IAggConfig, i: number) => { + vis.data.aggs!.aggs.forEach((agg: IAggConfig, i: number) => { agg.id = 'agg_' + (i + 1); }); - tabifiedResponse = tabifyAggResponse(vis.aggs, oneRangeBucket); + tabifiedResponse = tabifyAggResponse(vis.data.aggs!, oneRangeBucket); $rootScope.vis = vis; $rootScope.visParams = vis.params; $rootScope.uiState = { diff --git a/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts b/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts index 0a00957163705..6a2784f82d0d2 100644 --- a/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts +++ b/src/legacy/core_plugins/vis_type_table/public/vis_controller.ts @@ -61,7 +61,7 @@ export class TableVisualizationController { } } - async render(esResponse: object, visParams: VisParams, status: { [key: string]: boolean }) { + async render(esResponse: object, visParams: VisParams) { this.initLocalAngular(); return new Promise(async (resolve, reject) => { @@ -86,7 +86,6 @@ export class TableVisualizationController { this.$scope.renderComplete = resolve; this.$scope.renderFailed = reject; this.$scope.resize = Date.now(); - this.$scope.updateStatus = status; this.$scope.$apply(); }; diff --git a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js index 114643c9a74e0..04f447bf78d50 100644 --- a/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js +++ b/src/legacy/core_plugins/vis_type_tagcloud/public/components/tag_cloud_visualization.js @@ -79,17 +79,10 @@ export function createTagCloudVisualization({ colors }) { render(