[Visualize] Remove circular deps between KibanaApp team plugins (#87994)

* [Visualize] Remove circular deps between KibanaApp team plugins

Part of #84750

* Update use_vis_byvalue.ts

* Update use_saved_vis_instance.ts

* add types

* fix CI

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Alexey Antonov 2021-01-13 11:25:23 +03:00 committed by GitHub
parent ba05b7b007
commit 703ac93ecd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 138 additions and 113 deletions

View file

@ -23,11 +23,8 @@ import 'brace/mode/json';
import React, { useEffect, useRef, useState, useCallback } from 'react';
import { EventEmitter } from 'events';
import {
Vis,
VisualizeEmbeddableContract,
EditorRenderProps,
} from 'src/plugins/visualizations/public';
import { Vis, VisualizeEmbeddableContract } from 'src/plugins/visualizations/public';
import { EditorRenderProps } from 'src/plugins/visualize/public';
import { KibanaContextProvider, PanelsContainer, Panel } from '../../kibana_react/public';
import { Storage } from '../../kibana_utils/public';

View file

@ -22,12 +22,8 @@ import { render, unmountComponentAtNode } from 'react-dom';
import { EventEmitter } from 'events';
import { EuiErrorBoundary, EuiLoadingChart } from '@elastic/eui';
import {
Vis,
IEditorController,
EditorRenderProps,
VisualizeEmbeddableContract,
} from 'src/plugins/visualizations/public';
import { Vis, VisualizeEmbeddableContract } from 'src/plugins/visualizations/public';
import { IEditorController, EditorRenderProps } from 'src/plugins/visualize/public';
// @ts-ignore
const DefaultEditor = lazy(() => import('./default_editor'));

View file

@ -30,7 +30,7 @@ export class VisDefaultEditorPlugin
implements Plugin<void, void, VisDefaultEditorSetupDependencies, {}> {
public setup(core: CoreSetup, { visualize }: VisDefaultEditorSetupDependencies) {
if (visualize) {
visualize.setDefaultEditor(DefaultEditorController);
visualize.visEditorsRegistry.registerDefault(DefaultEditorController);
}
}

View file

@ -4,7 +4,7 @@
"kibanaVersion": "kibana",
"server": true,
"ui": true,
"requiredPlugins": ["charts", "data", "expressions", "visualizations"],
"requiredPlugins": ["charts", "data", "expressions", "visualizations", "visualize"],
"optionalPlugins": ["usageCollection"],
"requiredBundles": ["kibanaUtils", "kibanaReact"]
}

View file

@ -22,6 +22,8 @@ import { render, unmountComponentAtNode } from 'react-dom';
import { getUISettings, getI18n } from '../services';
import { VisEditor } from './components/vis_editor_lazy';
export const TSVB_EDITOR_NAME = 'tsvbEditor';
export class EditorController {
constructor(el, vis, eventEmitter, embeddableHandler) {
this.el = el;

View file

@ -18,5 +18,5 @@
*/
// @ts-ignore
export { EditorController } from './editor_controller';
export { EditorController, TSVB_EDITOR_NAME } from './editor_controller';
export * from './lib';

View file

@ -19,7 +19,7 @@
import { i18n } from '@kbn/i18n';
import { EditorController } from './application';
import { TSVB_EDITOR_NAME } from './application';
import { PANEL_TYPES } from '../common/panel_types';
import { toExpressionAst } from './to_ast';
import { VIS_EVENT_TO_TRIGGER, VisGroups, VisParams } from '../../visualizations/public';
@ -70,7 +70,9 @@ export const metricsVisDefinition = {
tooltip_mode: 'show_all',
},
},
editor: EditorController,
editorConfig: {
editor: TSVB_EDITOR_NAME,
},
options: {
showQueryBar: false,
showFilterBar: false,

View file

@ -22,6 +22,8 @@ import './application/index.scss';
import { PluginInitializerContext, CoreSetup, CoreStart, Plugin } from 'kibana/public';
import { Plugin as ExpressionsPublicPlugin } from '../../expressions/public';
import { VisualizationsSetup } from '../../visualizations/public';
import { VisualizePluginSetup } from '../../visualize/public';
import { EditorController, TSVB_EDITOR_NAME } from './application';
import { createMetricsFn } from './metrics_fn';
import { metricsVisDefinition } from './metrics_type';
@ -43,6 +45,7 @@ export interface MetricsPluginSetupDependencies {
expressions: ReturnType<ExpressionsPublicPlugin['setup']>;
visualizations: VisualizationsSetup;
charts: ChartsPluginSetup;
visualize: VisualizePluginSetup;
}
/** @internal */
@ -60,8 +63,9 @@ export class MetricsPlugin implements Plugin<Promise<void>, void> {
public async setup(
core: CoreSetup,
{ expressions, visualizations, charts }: MetricsPluginSetupDependencies
{ expressions, visualizations, charts, visualize }: MetricsPluginSetupDependencies
) {
visualize.visEditorsRegistry.register(TSVB_EDITOR_NAME, EditorController);
expressions.registerFunction(createMetricsFn);
expressions.registerRenderer(
getTimeseriesVisRenderer({

View file

@ -44,9 +44,6 @@ export type {
ReactVisTypeOptions,
Schema,
ISchemas,
VisEditorConstructor,
IEditorController,
EditorRenderProps,
} from './vis_types';
export { VisParams, SerializedVis, SerializedVisData, VisData } from './vis';
export type VisualizeEmbeddableFactoryContract = PublicContract<VisualizeEmbeddableFactory>;

View file

@ -27,7 +27,6 @@ interface CommonBaseVisTypeOptions<TVisParams>
extends Pick<
VisType<TVisParams>,
| 'description'
| 'editor'
| 'getInfoMessage'
| 'getSupportedTriggers'
| 'hierarchicalData'
@ -91,7 +90,6 @@ export class BaseVisType<TVisParams = VisParams> implements VisType<TVisParams>
public readonly options;
public readonly visualization;
public readonly visConfig;
public readonly editor;
public readonly editorConfig;
public hidden;
public readonly requestHandler;
@ -119,7 +117,6 @@ export class BaseVisType<TVisParams = VisParams> implements VisType<TVisParams>
this.image = opts.image;
this.visualization = opts.visualization;
this.visConfig = defaultsDeep({}, opts.visConfig, { defaults: {} });
this.editor = opts.editor;
this.editorConfig = defaultsDeep({}, opts.editorConfig, { collections: {} });
this.options = defaultsDeep({}, opts.options, defaultOptions);
this.stage = opts.stage ?? 'production';

View file

@ -20,13 +20,6 @@
export * from './types_service';
export { Schemas } from './schemas';
export { VisGroups } from './types';
export type {
VisType,
ISchemas,
Schema,
IEditorController,
VisEditorConstructor,
EditorRenderProps,
} from './types';
export type { VisType, ISchemas, Schema } from './types';
export type { BaseVisTypeOptions } from './base_vis_type';
export type { ReactVisTypeOptions } from './react_vis_type';

View file

@ -16,24 +16,11 @@
* specific language governing permissions and limitations
* under the License.
*/
import { EventEmitter } from 'events';
import { IconType } from '@elastic/eui';
import React, { ReactNode } from 'react';
import { Adapters } from 'src/plugins/inspector';
import { CoreStart } from 'src/core/public';
import { SavedObject } from 'src/plugins/saved_objects/public';
import {
IndexPattern,
AggGroupNames,
AggParam,
AggGroupName,
DataPublicPluginStart,
Filter,
TimeRange,
Query,
} from '../../../data/public';
import { IndexPattern, AggGroupNames, AggParam, AggGroupName } from '../../../data/public';
import { Vis, VisParams, VisToExpressionAst, VisualizationControllerConstructor } from '../types';
import { PersistedState, VisualizeEmbeddableContract } from '../index';
export interface VisTypeOptions {
showTimePicker: boolean;
@ -152,40 +139,7 @@ export interface VisType<TVisParams = unknown> {
readonly options: VisTypeOptions;
/**
* The editor that should be used to edit visualizations of this type.
* If this is not specified the default visualize editor will be used (and should be configured via schemas)
* and editorConfig.
*/
readonly editor?: VisEditorConstructor;
// TODO: The following types still need to be refined properly.
readonly editorConfig: Record<string, any>;
readonly visConfig: Record<string, any>;
}
export type VisEditorConstructor = new (
element: HTMLElement,
vis: Vis,
eventEmitter: EventEmitter,
embeddableHandler: VisualizeEmbeddableContract
) => IEditorController;
export interface IEditorController {
render(props: EditorRenderProps): Promise<void> | void;
destroy(): void;
}
export interface EditorRenderProps {
core: CoreStart;
data: DataPublicPluginStart;
filters: Filter[];
timeRange: TimeRange;
query?: Query;
savedSearch?: SavedObject;
uiState: PersistedState;
/**
* Flag to determine if visualiztion is linked to the saved search
*/
linked: boolean;
}

View file

@ -18,13 +18,14 @@
*/
import { History } from 'history';
import { Query, Filter, DataPublicPluginStart } from 'src/plugins/data/public';
import { Query, Filter, DataPublicPluginStart, TimeRange } from 'src/plugins/data/public';
import {
SavedVisState,
VisualizationsStart,
Vis,
VisualizeEmbeddableContract,
VisSavedObject,
PersistedState,
} from 'src/plugins/visualizations/public';
import {
CoreStart,
@ -44,6 +45,7 @@ import { SharePluginStart } from 'src/plugins/share/public';
import { SavedObjectsStart, SavedObject } from 'src/plugins/saved_objects/public';
import { EmbeddableStart, EmbeddableStateTransfer } from 'src/plugins/embeddable/public';
import { UrlForwardingStart } from 'src/plugins/url_forwarding/public';
import { EventEmitter } from 'events';
import { DashboardStart } from '../../../dashboard/public';
import type { SavedObjectsTaggingApi } from '../../../saved_objects_tagging_oss/public';
@ -119,3 +121,29 @@ export interface ByValueVisInstance {
}
export type VisualizeEditorVisInstance = SavedVisInstance | ByValueVisInstance;
export type VisEditorConstructor = new (
element: HTMLElement,
vis: Vis,
eventEmitter: EventEmitter,
embeddableHandler: VisualizeEmbeddableContract
) => IEditorController;
export interface IEditorController {
render(props: EditorRenderProps): Promise<void> | void;
destroy(): void;
}
export interface EditorRenderProps {
core: CoreStart;
data: DataPublicPluginStart;
filters: Filter[];
timeRange: TimeRange;
query?: Query;
savedSearch?: SavedObject;
uiState: PersistedState;
/**
* Flag to determine if visualiztion is linked to the saved search
*/
linked: boolean;
}

View file

@ -22,7 +22,7 @@ import { EventEmitter } from 'events';
import { useEditorUpdates } from './use_editor_updates';
import { VisualizeServices, VisualizeAppStateContainer, SavedVisInstance } from '../../types';
import type { IEditorController } from '../../../../../visualizations/public';
import type { IEditorController } from '../../types';
import { visualizeAppStateStub } from '../stubs';
import { createVisualizeServicesMock } from '../mocks';

View file

@ -26,8 +26,8 @@ import {
VisualizeAppState,
VisualizeAppStateContainer,
VisualizeEditorVisInstance,
IEditorController,
} from '../../types';
import type { IEditorController } from '../../../../../visualizations/public';
export const useEditorUpdates = (
services: VisualizeServices,

View file

@ -26,7 +26,8 @@ import { redirectWhenMissing } from '../../../../../kibana_utils/public';
import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
import { VisualizeServices } from '../../types';
import { VisualizeConstants } from '../../visualize_constants';
import { setDefaultEditor } from '../../../services';
import { setVisEditorsRegistry } from '../../../services';
import { createVisEditorsRegistry } from '../../../vis_editors_registry';
import { createEmbeddableStateTransferMock } from '../../../../../embeddable/public/mocks';
const mockDefaultEditorControllerDestroy = jest.fn();
@ -75,10 +76,14 @@ describe('useSavedVisInstance', () => {
const eventEmitter = new EventEmitter();
beforeEach(() => {
setDefaultEditor(
const registry = createVisEditorsRegistry();
registry.registerDefault(
jest.fn().mockImplementation(() => ({ destroy: mockDefaultEditorControllerDestroy }))
);
setVisEditorsRegistry(registry);
mockServices = ({
...coreStartMock,
toastNotifications,

View file

@ -26,10 +26,9 @@ import { redirectWhenMissing } from '../../../../../kibana_utils/public';
import { getVisualizationInstance } from '../get_visualization_instance';
import { getEditBreadcrumbs, getCreateBreadcrumbs } from '../breadcrumbs';
import { SavedVisInstance, VisualizeServices } from '../../types';
import { SavedVisInstance, VisualizeServices, IEditorController } from '../../types';
import { VisualizeConstants } from '../../visualize_constants';
import { getDefaultEditor } from '../../../services';
import type { IEditorController } from '../../../../../visualizations/public';
import { getVisEditorsRegistry } from '../../../services';
/**
* This effect is responsible for instantiating a saved vis or creating a new one
@ -123,13 +122,16 @@ export const useSavedVisInstance = (
// do not create editor in embeded mode
if (visEditorRef.current) {
if (isChromeVisible) {
const Editor = vis.type.editor || getDefaultEditor();
visEditorController = new Editor(
visEditorRef.current,
vis,
eventEmitter,
embeddableHandler
);
const Editor = getVisEditorsRegistry().get(vis.type.editorConfig?.editor);
if (Editor) {
visEditorController = new Editor(
visEditorRef.current,
vis,
eventEmitter,
embeddableHandler
);
}
} else {
embeddableHandler.render(visEditorRef.current);
}

View file

@ -20,11 +20,10 @@
import { EventEmitter } from 'events';
import { useEffect, useRef, useState } from 'react';
import { VisualizeInput } from 'src/plugins/visualizations/public';
import { ByValueVisInstance, VisualizeServices } from '../../types';
import type { IEditorController } from '../../../../../visualizations/public';
import { ByValueVisInstance, VisualizeServices, IEditorController } from '../../types';
import { getVisualizationInstanceFromInput } from '../get_visualization_instance';
import { getEditBreadcrumbs } from '../breadcrumbs';
import { getDefaultEditor } from '../../../services';
import { getVisEditorsRegistry } from '../../../services';
export const useVisByValue = (
services: VisualizeServices,
@ -51,14 +50,18 @@ export const useVisByValue = (
}
const byValueVisInstance = await getVisualizationInstanceFromInput(services, valueInput);
const { embeddableHandler, vis } = byValueVisInstance;
let visEditorController;
const Editor = vis.type.editor || getDefaultEditor();
const visEditorController = new Editor(
visEditorRef.current,
vis,
eventEmitter,
embeddableHandler
);
const Editor = getVisEditorsRegistry().get(vis.type.editorConfig?.editor);
if (Editor) {
visEditorController = new Editor(
visEditorRef.current,
vis,
eventEmitter,
embeddableHandler
);
}
const originatingAppName = originatingApp
? stateTransferService.getAppNameFromId(originatingApp)

View file

@ -22,6 +22,8 @@ import { VisualizePlugin, VisualizePluginSetup } from './plugin';
export { VisualizeConstants } from './application/visualize_constants';
export { IEditorController, EditorRenderProps } from './application/types';
export { VisualizePluginSetup };
export const plugin = (context: PluginInitializerContext) => {

View file

@ -41,7 +41,7 @@ import { DataPublicPluginStart, DataPublicPluginSetup, esFilters } from '../../d
import { NavigationPublicPluginStart as NavigationStart } from '../../navigation/public';
import { SharePluginStart, SharePluginSetup } from '../../share/public';
import { UrlForwardingSetup, UrlForwardingStart } from '../../url_forwarding/public';
import { VisualizationsStart, VisEditorConstructor } from '../../visualizations/public';
import { VisualizationsStart } from '../../visualizations/public';
import { VisualizeConstants } from './application/visualize_constants';
import { FeatureCatalogueCategory, HomePublicPluginSetup } from '../../home/public';
import { VisualizeServices } from './application/types';
@ -57,10 +57,11 @@ import {
setIndexPatterns,
setQueryService,
setShareService,
setDefaultEditor,
setVisEditorsRegistry,
} from './services';
import { visualizeFieldAction } from './actions/visualize_field_action';
import { createVisualizeUrlGenerator } from './url_generator';
import { createVisEditorsRegistry, VisEditorsRegistry } from './vis_editors_registry';
export interface VisualizePluginStartDependencies {
data: DataPublicPluginStart;
@ -83,7 +84,7 @@ export interface VisualizePluginSetupDependencies {
}
export interface VisualizePluginSetup {
setDefaultEditor: (editor: VisEditorConstructor) => void;
visEditorsRegistry: VisEditorsRegistry;
}
export class VisualizePlugin
@ -98,6 +99,8 @@ export class VisualizePlugin
private stopUrlTracking: (() => void) | undefined = undefined;
private currentHistory: ScopedHistory | undefined = undefined;
private readonly visEditorsRegistry = createVisEditorsRegistry();
constructor(private initializerContext: PluginInitializerContext) {}
public async setup(
@ -244,13 +247,12 @@ export class VisualizePlugin
}
return {
setDefaultEditor: (editor) => {
setDefaultEditor(editor);
},
visEditorsRegistry: this.visEditorsRegistry,
} as VisualizePluginSetup;
}
public start(core: CoreStart, plugins: VisualizePluginStartDependencies) {
setVisEditorsRegistry(this.visEditorsRegistry);
setApplication(core.application);
setIndexPatterns(plugins.data.indexPatterns);
setQueryService(plugins.data.query);

View file

@ -20,8 +20,8 @@
import { ApplicationStart, IUiSettingsClient } from '../../../core/public';
import { createGetterSetter } from '../../../plugins/kibana_utils/public';
import { IndexPatternsContract, DataPublicPluginStart } from '../../../plugins/data/public';
import { VisEditorConstructor } from '../../../plugins/visualizations/public';
import { SharePluginStart } from '../../../plugins/share/public';
import { VisEditorsRegistry } from './vis_editors_registry';
export const [getUISettings, setUISettings] = createGetterSetter<IUiSettingsClient>('UISettings');
@ -33,9 +33,10 @@ export const [getIndexPatterns, setIndexPatterns] = createGetterSetter<IndexPatt
'IndexPatterns'
);
export const [getDefaultEditor, setDefaultEditor] = createGetterSetter<VisEditorConstructor>(
'DefaultEditor'
);
export const [
getVisEditorsRegistry,
setVisEditorsRegistry,
] = createGetterSetter<VisEditorsRegistry>('VisEditorsRegistry');
export const [getQueryService, setQueryService] = createGetterSetter<
DataPublicPluginStart['query']

View file

@ -0,0 +1,40 @@
/*
* 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 { VisEditorConstructor } from './application/types';
const DEFAULT_NAME = 'default';
export const createVisEditorsRegistry = () => {
const map = new Map<string, VisEditorConstructor>();
return {
registerDefault: (editor: VisEditorConstructor) => {
map.set(DEFAULT_NAME, editor);
},
register: (name: string, editor: VisEditorConstructor) => {
if (name) {
map.set(name, editor);
}
},
get: (name: string) => map.get(name || DEFAULT_NAME),
};
};
export type VisEditorsRegistry = ReturnType<typeof createVisEditorsRegistry>;