mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Embeddables as Building Blocks] Controls API (#140739)
Added control group API and renderer component
This commit is contained in:
parent
fcea2e7d4d
commit
c8a0376eaf
15 changed files with 274 additions and 54 deletions
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import uuid from 'uuid';
|
||||
import useLifecycles from 'react-use/lib/useLifecycles';
|
||||
import React, { useEffect, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { IEmbeddable } from '@kbn/embeddable-plugin/public';
|
||||
|
||||
import { pluginServices } from '../services';
|
||||
import { getDefaultControlGroupInput } from '../../common';
|
||||
import { ControlGroupInput, ControlGroupOutput, CONTROL_GROUP_TYPE } from './types';
|
||||
import { ControlGroupContainer } from './embeddable/control_group_container';
|
||||
|
||||
export interface ControlGroupRendererProps {
|
||||
input?: Partial<Pick<ControlGroupInput, 'viewMode' | 'executionContext'>>;
|
||||
onEmbeddableLoad: (controlGroupContainer: ControlGroupContainer) => void;
|
||||
}
|
||||
|
||||
export const ControlGroupRenderer = ({ input, onEmbeddableLoad }: ControlGroupRendererProps) => {
|
||||
const controlsRoot = useRef(null);
|
||||
const [controlGroupContainer, setControlGroupContainer] = useState<ControlGroupContainer>();
|
||||
|
||||
const id = useMemo(() => uuid.v4(), []);
|
||||
|
||||
/**
|
||||
* Use Lifecycles to load initial control group container
|
||||
*/
|
||||
useLifecycles(
|
||||
() => {
|
||||
const { embeddable } = pluginServices.getServices();
|
||||
|
||||
(async () => {
|
||||
const container = (await embeddable
|
||||
.getEmbeddableFactory<
|
||||
ControlGroupInput,
|
||||
ControlGroupOutput,
|
||||
IEmbeddable<ControlGroupInput, ControlGroupOutput>
|
||||
>(CONTROL_GROUP_TYPE)
|
||||
?.create({ id, ...getDefaultControlGroupInput(), ...input })) as ControlGroupContainer;
|
||||
|
||||
if (controlsRoot.current) {
|
||||
container.render(controlsRoot.current);
|
||||
}
|
||||
setControlGroupContainer(container);
|
||||
onEmbeddableLoad(container);
|
||||
})();
|
||||
},
|
||||
() => {
|
||||
controlGroupContainer?.destroy();
|
||||
}
|
||||
);
|
||||
|
||||
/**
|
||||
* Update embeddable input when props input changes
|
||||
*/
|
||||
useEffect(() => {
|
||||
let updateCanceled = false;
|
||||
(async () => {
|
||||
// check if applying input from props would result in any changes to the embeddable input
|
||||
const isInputEqual = await controlGroupContainer?.getExplicitInputIsEqual({
|
||||
...controlGroupContainer?.getInput(),
|
||||
...input,
|
||||
});
|
||||
if (!controlGroupContainer || isInputEqual || updateCanceled) return;
|
||||
controlGroupContainer.updateInput({ ...input });
|
||||
})();
|
||||
|
||||
return () => {
|
||||
updateCanceled = true;
|
||||
};
|
||||
}, [controlGroupContainer, input]);
|
||||
|
||||
return <div ref={controlsRoot} />;
|
||||
};
|
||||
|
||||
// required for dynamic import using React.lazy()
|
||||
// eslint-disable-next-line import/no-default-export
|
||||
export default ControlGroupRenderer;
|
|
@ -9,10 +9,6 @@
|
|||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
export const ControlGroupStrings = {
|
||||
getEmbeddableTitle: () =>
|
||||
i18n.translate('controls.controlGroup.title', {
|
||||
defaultMessage: 'Control group',
|
||||
}),
|
||||
getControlButtonTitle: () =>
|
||||
i18n.translate('controls.controlGroup.toolbarButtonTitle', {
|
||||
defaultMessage: 'Controls',
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React, { useEffect, useMemo, useState } from 'react';
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import useMount from 'react-use/lib/useMount';
|
||||
|
||||
import {
|
||||
|
@ -36,7 +36,6 @@ import {
|
|||
EuiTextColor,
|
||||
} from '@elastic/eui';
|
||||
import { DataViewListItem, DataView, DataViewField } from '@kbn/data-views-plugin/common';
|
||||
import { IFieldSubTypeMulti } from '@kbn/es-query';
|
||||
import {
|
||||
LazyDataViewPicker,
|
||||
LazyFieldPicker,
|
||||
|
@ -53,6 +52,7 @@ import {
|
|||
} from '../../types';
|
||||
import { CONTROL_WIDTH_OPTIONS } from './editor_constants';
|
||||
import { pluginServices } from '../../services';
|
||||
import { loadFieldRegistryFromDataViewId } from './data_control_editor_tools';
|
||||
interface EditControlProps {
|
||||
embeddable?: ControlEmbeddable<DataControlInput>;
|
||||
isCreate: boolean;
|
||||
|
@ -97,7 +97,7 @@ export const ControlEditor = ({
|
|||
}: EditControlProps) => {
|
||||
const {
|
||||
dataViews: { getIdsWithTitle, getDefaultId, get },
|
||||
controls: { getControlTypes, getControlFactory },
|
||||
controls: { getControlFactory },
|
||||
} = pluginServices.getServices();
|
||||
const [state, setState] = useState<ControlEditorState>({
|
||||
dataViewListItems: [],
|
||||
|
@ -112,49 +112,14 @@ export const ControlEditor = ({
|
|||
embeddable ? embeddable.getInput().fieldName : undefined
|
||||
);
|
||||
|
||||
const doubleLinkFields = (dataView: DataView) => {
|
||||
// double link the parent-child relationship specifically for case-sensitivity support for options lists
|
||||
const fieldRegistry: DataControlFieldRegistry = {};
|
||||
|
||||
for (const field of dataView.fields.getAll()) {
|
||||
if (!fieldRegistry[field.name]) {
|
||||
fieldRegistry[field.name] = { field, compatibleControlTypes: [] };
|
||||
const [fieldRegistry, setFieldRegistry] = useState<DataControlFieldRegistry>();
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
if (state.selectedDataView?.id) {
|
||||
setFieldRegistry(await loadFieldRegistryFromDataViewId(state.selectedDataView.id));
|
||||
}
|
||||
const parentFieldName = (field.subType as IFieldSubTypeMulti)?.multi?.parent;
|
||||
if (parentFieldName) {
|
||||
fieldRegistry[field.name].parentFieldName = parentFieldName;
|
||||
|
||||
const parentField = dataView.getFieldByName(parentFieldName);
|
||||
if (!fieldRegistry[parentFieldName] && parentField) {
|
||||
fieldRegistry[parentFieldName] = { field: parentField, compatibleControlTypes: [] };
|
||||
}
|
||||
fieldRegistry[parentFieldName].childFieldName = field.name;
|
||||
}
|
||||
}
|
||||
return fieldRegistry;
|
||||
};
|
||||
|
||||
const fieldRegistry = useMemo(() => {
|
||||
if (!state.selectedDataView) return;
|
||||
const newFieldRegistry: DataControlFieldRegistry = doubleLinkFields(state.selectedDataView);
|
||||
|
||||
const controlFactories = getControlTypes().map(
|
||||
(controlType) => getControlFactory(controlType) as IEditableControlFactory
|
||||
);
|
||||
state.selectedDataView.fields.map((dataViewField) => {
|
||||
for (const factory of controlFactories) {
|
||||
if (factory.isFieldCompatible) {
|
||||
factory.isFieldCompatible(newFieldRegistry[dataViewField.name]);
|
||||
}
|
||||
}
|
||||
|
||||
if (newFieldRegistry[dataViewField.name]?.compatibleControlTypes.length === 0) {
|
||||
delete newFieldRegistry[dataViewField.name];
|
||||
}
|
||||
});
|
||||
|
||||
return newFieldRegistry;
|
||||
}, [state.selectedDataView, getControlFactory, getControlTypes]);
|
||||
})();
|
||||
}, [state.selectedDataView]);
|
||||
|
||||
useMount(() => {
|
||||
let mounted = true;
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { IFieldSubTypeMulti } from '@kbn/es-query';
|
||||
import { DataView } from '@kbn/data-views-plugin/common';
|
||||
|
||||
import { pluginServices } from '../../services';
|
||||
import { DataControlFieldRegistry, IEditableControlFactory } from '../../types';
|
||||
|
||||
const dataControlFieldRegistryCache: { [key: string]: DataControlFieldRegistry } = {};
|
||||
|
||||
const doubleLinkFields = (dataView: DataView) => {
|
||||
// double link the parent-child relationship specifically for case-sensitivity support for options lists
|
||||
const fieldRegistry: DataControlFieldRegistry = {};
|
||||
|
||||
for (const field of dataView.fields.getAll()) {
|
||||
if (!fieldRegistry[field.name]) {
|
||||
fieldRegistry[field.name] = { field, compatibleControlTypes: [] };
|
||||
}
|
||||
const parentFieldName = (field.subType as IFieldSubTypeMulti)?.multi?.parent;
|
||||
if (parentFieldName) {
|
||||
fieldRegistry[field.name].parentFieldName = parentFieldName;
|
||||
|
||||
const parentField = dataView.getFieldByName(parentFieldName);
|
||||
if (!fieldRegistry[parentFieldName] && parentField) {
|
||||
fieldRegistry[parentFieldName] = { field: parentField, compatibleControlTypes: [] };
|
||||
}
|
||||
fieldRegistry[parentFieldName].childFieldName = field.name;
|
||||
}
|
||||
}
|
||||
return fieldRegistry;
|
||||
};
|
||||
|
||||
export const loadFieldRegistryFromDataViewId = async (
|
||||
dataViewId: string
|
||||
): Promise<DataControlFieldRegistry> => {
|
||||
if (dataControlFieldRegistryCache[dataViewId]) {
|
||||
return dataControlFieldRegistryCache[dataViewId];
|
||||
}
|
||||
const {
|
||||
dataViews,
|
||||
controls: { getControlTypes, getControlFactory },
|
||||
} = pluginServices.getServices();
|
||||
const dataView = await dataViews.get(dataViewId);
|
||||
|
||||
const newFieldRegistry: DataControlFieldRegistry = doubleLinkFields(dataView);
|
||||
|
||||
const controlFactories = getControlTypes().map(
|
||||
(controlType) => getControlFactory(controlType) as IEditableControlFactory
|
||||
);
|
||||
dataView.fields.map((dataViewField) => {
|
||||
for (const factory of controlFactories) {
|
||||
if (factory.isFieldCompatible) {
|
||||
factory.isFieldCompatible(newFieldRegistry[dataViewField.name]);
|
||||
}
|
||||
}
|
||||
|
||||
if (newFieldRegistry[dataViewField.name]?.compatibleControlTypes.length === 0) {
|
||||
delete newFieldRegistry[dataViewField.name];
|
||||
}
|
||||
});
|
||||
dataControlFieldRegistryCache[dataViewId] = newFieldRegistry;
|
||||
|
||||
return newFieldRegistry;
|
||||
};
|
|
@ -9,7 +9,7 @@
|
|||
import { skip, debounceTime, distinctUntilChanged } from 'rxjs/operators';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { Filter, uniqFilters } from '@kbn/es-query';
|
||||
import { compareFilters, COMPARE_ALL_OPTIONS, Filter, uniqFilters } from '@kbn/es-query';
|
||||
import { BehaviorSubject, merge, Subject, Subscription } from 'rxjs';
|
||||
import { EuiContextMenuPanel } from '@elastic/eui';
|
||||
|
||||
|
@ -39,10 +39,11 @@ import { ControlGroupStrings } from '../control_group_strings';
|
|||
import { EditControlGroup } from '../editor/edit_control_group';
|
||||
import { ControlGroup } from '../component/control_group_component';
|
||||
import { controlGroupReducers } from '../state/control_group_reducers';
|
||||
import { ControlEmbeddable, ControlInput, ControlOutput } from '../../types';
|
||||
import { ControlEmbeddable, ControlInput, ControlOutput, DataControlInput } from '../../types';
|
||||
import { CreateControlButton, CreateControlButtonTypes } from '../editor/create_control';
|
||||
import { CreateTimeSliderControlButton } from '../editor/create_time_slider_control';
|
||||
import { TIME_SLIDER_CONTROL } from '../../time_slider';
|
||||
import { loadFieldRegistryFromDataViewId } from '../editor/data_control_editor_tools';
|
||||
|
||||
let flyoutRef: OverlayRef | undefined;
|
||||
export const setFlyoutRef = (newRef: OverlayRef | undefined) => {
|
||||
|
@ -70,6 +71,9 @@ export class ControlGroupContainer extends Container<
|
|||
typeof controlGroupReducers
|
||||
>;
|
||||
|
||||
public onFiltersPublished$: Subject<Filter[]>;
|
||||
public onControlRemoved$: Subject<string>;
|
||||
|
||||
public setLastUsedDataViewId = (lastUsedDataViewId: string) => {
|
||||
this.lastUsedDataViewId = lastUsedDataViewId;
|
||||
};
|
||||
|
@ -87,6 +91,27 @@ export class ControlGroupContainer extends Container<
|
|||
flyoutRef = undefined;
|
||||
}
|
||||
|
||||
public async addDataControlFromField({
|
||||
uuid,
|
||||
dataViewId,
|
||||
fieldName,
|
||||
title,
|
||||
}: {
|
||||
uuid?: string;
|
||||
dataViewId: string;
|
||||
fieldName: string;
|
||||
title?: string;
|
||||
}) {
|
||||
const fieldRegistry = await loadFieldRegistryFromDataViewId(dataViewId);
|
||||
const field = fieldRegistry[fieldName];
|
||||
return this.addNewEmbeddable(field.compatibleControlTypes[0], {
|
||||
id: uuid,
|
||||
dataViewId,
|
||||
fieldName,
|
||||
title: title ?? fieldName,
|
||||
} as DataControlInput);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a button that allows controls to be created externally using the embeddable
|
||||
* @param buttonType Controls the button styling
|
||||
|
@ -185,6 +210,8 @@ export class ControlGroupContainer extends Container<
|
|||
);
|
||||
|
||||
this.recalculateFilters$ = new Subject();
|
||||
this.onFiltersPublished$ = new Subject<Filter[]>();
|
||||
this.onControlRemoved$ = new Subject<string>();
|
||||
|
||||
// build redux embeddable tools
|
||||
this.reduxEmbeddableTools = reduxEmbeddablePackage.createTools<
|
||||
|
@ -249,6 +276,10 @@ export class ControlGroupContainer extends Container<
|
|||
return Object.keys(this.getInput().panels).length;
|
||||
};
|
||||
|
||||
public updateFilterContext = (filters: Filter[]) => {
|
||||
this.updateInput({ filters });
|
||||
};
|
||||
|
||||
private recalculateFilters = () => {
|
||||
const allFilters: Filter[] = [];
|
||||
let timeslice;
|
||||
|
@ -259,7 +290,11 @@ export class ControlGroupContainer extends Container<
|
|||
timeslice = childOutput.timeslice;
|
||||
}
|
||||
});
|
||||
this.updateOutput({ filters: uniqFilters(allFilters), timeslice });
|
||||
// if filters are different, publish them
|
||||
if (!compareFilters(this.output.filters ?? [], allFilters ?? [], COMPARE_ALL_OPTIONS)) {
|
||||
this.updateOutput({ filters: uniqFilters(allFilters), timeslice });
|
||||
this.onFiltersPublished$.next(allFilters);
|
||||
}
|
||||
};
|
||||
|
||||
private recalculateDataViews = () => {
|
||||
|
@ -304,6 +339,7 @@ export class ControlGroupContainer extends Container<
|
|||
order: currentOrder - 1,
|
||||
};
|
||||
}
|
||||
this.onControlRemoved$.next(idToRemove);
|
||||
return newPanels;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,12 +14,12 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { Container, EmbeddableFactoryDefinition } from '@kbn/embeddable-plugin/public';
|
||||
import { lazyLoadReduxEmbeddablePackage } from '@kbn/presentation-util-plugin/public';
|
||||
import { EmbeddablePersistableStateService } from '@kbn/embeddable-plugin/common';
|
||||
|
||||
import { ControlGroupInput, CONTROL_GROUP_TYPE } from '../types';
|
||||
import { ControlGroupStrings } from '../control_group_strings';
|
||||
import {
|
||||
createControlGroupExtract,
|
||||
createControlGroupInject,
|
||||
|
@ -40,7 +40,9 @@ export class ControlGroupContainerFactory implements EmbeddableFactoryDefinition
|
|||
public isEditable = async () => false;
|
||||
|
||||
public readonly getDisplayName = () => {
|
||||
return ControlGroupStrings.getEmbeddableTitle();
|
||||
return i18n.translate('controls.controlGroup.title', {
|
||||
defaultMessage: 'Control group',
|
||||
});
|
||||
};
|
||||
|
||||
public getDefaultInput(): Partial<ControlGroupInput> {
|
||||
|
|
|
@ -6,8 +6,13 @@
|
|||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
|
||||
export type { ControlGroupContainer } from './embeddable/control_group_container';
|
||||
export type { ControlGroupInput, ControlGroupOutput } from './types';
|
||||
|
||||
export { CONTROL_GROUP_TYPE } from './types';
|
||||
export { ControlGroupContainerFactory } from './embeddable/control_group_container_factory';
|
||||
|
||||
export type { ControlGroupRendererProps } from './control_group_renderer';
|
||||
export const LazyControlGroupRenderer = React.lazy(() => import('./control_group_renderer'));
|
||||
|
|
|
@ -51,6 +51,7 @@ export {
|
|||
} from './range_slider';
|
||||
|
||||
export { LazyControlsCallout, type CalloutProps } from './controls_callout';
|
||||
export { LazyControlGroupRenderer, type ControlGroupRendererProps } from './control_group';
|
||||
|
||||
export function plugin() {
|
||||
return new ControlsPlugin();
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { PluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { embeddablePluginMock } from '@kbn/embeddable-plugin/public/mocks';
|
||||
import { ControlsEmbeddableService } from './types';
|
||||
|
||||
export type EmbeddableServiceFactory = PluginServiceFactory<ControlsEmbeddableService>;
|
||||
export const embeddableServiceFactory: EmbeddableServiceFactory = () => {
|
||||
const { doStart } = embeddablePluginMock.createInstance();
|
||||
const start = doStart();
|
||||
return { getEmbeddableFactory: start.getEmbeddableFactory };
|
||||
};
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { KibanaPluginServiceFactory } from '@kbn/presentation-util-plugin/public';
|
||||
import { ControlsEmbeddableService } from './types';
|
||||
import { ControlsPluginStartDeps } from '../../types';
|
||||
|
||||
export type EmbeddableServiceFactory = KibanaPluginServiceFactory<
|
||||
ControlsEmbeddableService,
|
||||
ControlsPluginStartDeps
|
||||
>;
|
||||
|
||||
export const embeddableServiceFactory: EmbeddableServiceFactory = ({ startPlugins }) => {
|
||||
return {
|
||||
getEmbeddableFactory: startPlugins.embeddable.getEmbeddableFactory,
|
||||
};
|
||||
};
|
13
src/plugins/controls/public/services/embeddable/types.ts
Normal file
13
src/plugins/controls/public/services/embeddable/types.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { EmbeddableStart } from '@kbn/embeddable-plugin/public';
|
||||
|
||||
export interface ControlsEmbeddableService {
|
||||
getEmbeddableFactory: EmbeddableStart['getEmbeddableFactory'];
|
||||
}
|
|
@ -23,6 +23,7 @@ import { themeServiceFactory } from './theme/theme.story';
|
|||
|
||||
import { optionsListServiceFactory } from './options_list/options_list.story';
|
||||
import { controlsServiceFactory } from './controls/controls.story';
|
||||
import { embeddableServiceFactory } from './embeddable/embeddable.story';
|
||||
|
||||
export const providers: PluginServiceProviders<ControlsServices> = {
|
||||
dataViews: new PluginServiceProvider(dataViewsServiceFactory),
|
||||
|
@ -32,6 +33,7 @@ export const providers: PluginServiceProviders<ControlsServices> = {
|
|||
overlays: new PluginServiceProvider(overlaysServiceFactory),
|
||||
settings: new PluginServiceProvider(settingsServiceFactory),
|
||||
theme: new PluginServiceProvider(themeServiceFactory),
|
||||
embeddable: new PluginServiceProvider(embeddableServiceFactory),
|
||||
|
||||
controls: new PluginServiceProvider(controlsServiceFactory),
|
||||
optionsList: new PluginServiceProvider(optionsListServiceFactory),
|
||||
|
|
|
@ -25,8 +25,10 @@ import { settingsServiceFactory } from './settings/settings.story';
|
|||
import { unifiedSearchServiceFactory } from './unified_search/unified_search.story';
|
||||
import { themeServiceFactory } from './theme/theme.story';
|
||||
import { registry as stubRegistry } from './plugin_services.story';
|
||||
import { embeddableServiceFactory } from './embeddable/embeddable.story';
|
||||
|
||||
export const providers: PluginServiceProviders<ControlsServices> = {
|
||||
embeddable: new PluginServiceProvider(embeddableServiceFactory),
|
||||
controls: new PluginServiceProvider(controlsServiceFactory),
|
||||
data: new PluginServiceProvider(dataServiceFactory),
|
||||
dataViews: new PluginServiceProvider(dataViewsServiceFactory),
|
||||
|
|
|
@ -25,6 +25,7 @@ import { optionsListServiceFactory } from './options_list/options_list_service';
|
|||
import { settingsServiceFactory } from './settings/settings_service';
|
||||
import { unifiedSearchServiceFactory } from './unified_search/unified_search_service';
|
||||
import { themeServiceFactory } from './theme/theme_service';
|
||||
import { embeddableServiceFactory } from './embeddable/embeddable_service';
|
||||
|
||||
export const providers: PluginServiceProviders<
|
||||
ControlsServices,
|
||||
|
@ -38,6 +39,7 @@ export const providers: PluginServiceProviders<
|
|||
overlays: new PluginServiceProvider(overlaysServiceFactory),
|
||||
settings: new PluginServiceProvider(settingsServiceFactory),
|
||||
theme: new PluginServiceProvider(themeServiceFactory),
|
||||
embeddable: new PluginServiceProvider(embeddableServiceFactory),
|
||||
unifiedSearch: new PluginServiceProvider(unifiedSearchServiceFactory),
|
||||
};
|
||||
|
||||
|
|
|
@ -15,11 +15,13 @@ import { ControlsHTTPService } from './http/types';
|
|||
import { ControlsOptionsListService } from './options_list/types';
|
||||
import { ControlsSettingsService } from './settings/types';
|
||||
import { ControlsThemeService } from './theme/types';
|
||||
import { ControlsEmbeddableService } from './embeddable/types';
|
||||
|
||||
export interface ControlsServices {
|
||||
// dependency services
|
||||
dataViews: ControlsDataViewsService;
|
||||
overlays: ControlsOverlaysService;
|
||||
embeddable: ControlsEmbeddableService;
|
||||
data: ControlsDataService;
|
||||
unifiedSearch: ControlsUnifiedSearchService;
|
||||
http: ControlsHTTPService;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue