diff --git a/examples/discover_extender/public/plugin.tsx b/examples/discover_extender/public/plugin.tsx index ea8256a8bbc27..9cd01e43c8dbb 100644 --- a/examples/discover_extender/public/plugin.tsx +++ b/examples/discover_extender/public/plugin.tsx @@ -29,8 +29,8 @@ export class DiscoverExtenderPlugin implements Plugin { start(core: CoreStart, plugins: DiscoverExtenderStartPlugins) { const { discover } = plugins; - discover.registerExtensions('default', ({ extensions }) => { - extensions.set({ + discover.customize('default', ({ customizations }) => { + customizations.set({ id: 'top_nav', defaultMenu: { options: { order: 100 }, @@ -58,7 +58,7 @@ export class DiscoverExtenderPlugin implements Plugin { return () => { // eslint-disable-next-line no-console - console.log('Cleaning up Document explorer extensions'); + console.log('Cleaning up Document explorer customizations'); }; }); @@ -70,8 +70,8 @@ export class DiscoverExtenderPlugin implements Plugin { isOptionsOpen = false; }; - discover.registerExtensions('extender', async ({ extensions, stateContainer }) => { - extensions.set({ + discover.customize('extender', async ({ customizations, stateContainer }) => { + customizations.set({ id: 'top_nav', defaultMenu: { options: { disabled: true }, @@ -154,7 +154,7 @@ export class DiscoverExtenderPlugin implements Plugin { ], }); - extensions.set({ + customizations.set({ id: 'search_bar', CustomDataViewPicker: () => { const [isPopoverOpen, setIsPopoverOpen] = useState(false); @@ -204,7 +204,7 @@ export class DiscoverExtenderPlugin implements Plugin { }, }); - extensions.set({ + customizations.set({ id: 'field_popover', CustomBottomButton: () => ( { // eslint-disable-next-line no-console - console.log('Cleaning up Logs explorer extensions'); + console.log('Cleaning up Logs explorer customizations'); }; }); } diff --git a/src/plugins/discover/public/application/discover_router.tsx b/src/plugins/discover/public/application/discover_router.tsx index c7a87b4996f92..8fafbed030937 100644 --- a/src/plugins/discover/public/application/discover_router.tsx +++ b/src/plugins/discover/public/application/discover_router.tsx @@ -18,12 +18,12 @@ import { DiscoverMainRoute } from './main'; import { NotFoundRoute } from './not_found'; import { DiscoverServices } from '../build_services'; import { ViewAlertRoute } from './view_alert'; -import type { RegisterExtensions } from '../extensions/types'; -import type { DiscoverProfileRegistry } from '../extensions/profile_registry'; +import type { CustomizationCallback } from '../customizations/types'; +import type { DiscoverProfileRegistry } from '../customizations/profile_registry'; interface DiscoverRoutesProps { prefix?: string; - registerExtensions: RegisterExtensions[]; + customizationCallbacks: CustomizationCallback[]; isDev: boolean; } @@ -70,14 +70,18 @@ interface CustomDiscoverRoutesProps { const CustomDiscoverRoutes = ({ profileRegistry, ...props }: CustomDiscoverRoutesProps) => { const { profile } = useParams<{ profile: string }>(); - const registerExtensions = useMemo( - () => profileRegistry.get(profile)?.registerExtensions, + const customizationCallbacks = useMemo( + () => profileRegistry.get(profile)?.customizationCallbacks, [profile, profileRegistry] ); - if (registerExtensions) { + if (customizationCallbacks) { return ( - + ); } @@ -97,8 +101,8 @@ export const DiscoverRouter = ({ profileRegistry, ...routeProps }: DiscoverRouterProps) => { - const registerDefaultExtensions = useMemo( - () => profileRegistry.get('default')?.registerExtensions ?? [], + const customizationCallbacks = useMemo( + () => profileRegistry.get('default')?.customizationCallbacks ?? [], [profileRegistry] ); @@ -111,7 +115,7 @@ export const DiscoverRouter = ({ - + diff --git a/src/plugins/discover/public/application/index.tsx b/src/plugins/discover/public/application/index.tsx index a4262593ccc5a..b8a24be2b2fcc 100644 --- a/src/plugins/discover/public/application/index.tsx +++ b/src/plugins/discover/public/application/index.tsx @@ -11,7 +11,7 @@ import { i18n } from '@kbn/i18n'; import { toMountPoint, wrapWithTheme } from '@kbn/kibana-react-plugin/public'; import { DiscoverRouter } from './discover_router'; import { DiscoverServices } from '../build_services'; -import type { DiscoverProfileRegistry } from '../extensions/profile_registry'; +import type { DiscoverProfileRegistry } from '../customizations/profile_registry'; export interface RenderAppProps { element: HTMLElement; diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx index 3d496f4a8e529..895a499d94f27 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx @@ -44,7 +44,7 @@ import { getRawRecordType } from '../../utils/get_raw_record_type'; import { DiscoverGridFlyout } from '../../../../components/discover_grid/discover_grid_flyout'; import { DocViewer } from '../../../../services/doc_views/components/doc_viewer'; import { useSavedSearchInitial } from '../../services/discover_state_provider'; -import { useDiscoverExtension } from '../../../../extensions/extension_provider'; +import { useDiscoverCustomization } from '../../../../customizations/customization_provider'; const containerStyles = css` position: relative; @@ -179,8 +179,8 @@ function DiscoverDocumentsComponent({ [isPlainRecord, uiSettings, dataView.timeFieldName] ); - const dataGridExtension = useDiscoverExtension('data_grid'); - const defaultControlColumns = dataGridExtension?.defaultLeadingControlColumns; + const dataGridCustomization = useDiscoverCustomization('data_grid'); + const defaultControlColumns = dataGridCustomization?.defaultLeadingControlColumns; const controlColumnIds = useMemo(() => { const ids: string[] = []; @@ -190,8 +190,8 @@ function DiscoverDocumentsComponent({ }, [defaultControlColumns?.expand?.disabled, defaultControlColumns?.select?.disabled]); const customControlColumns = useMemo( - () => dataGridExtension?.getLeadingControlColumns?.(), - [dataGridExtension] + () => dataGridCustomization?.getLeadingControlColumns?.(), + [dataGridCustomization] ); if (isDataViewLoading || (isEmptyDataResult && isDataLoading)) { diff --git a/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx b/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx index 0018c35f20447..ce1382d9e0e5e 100644 --- a/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx +++ b/src/plugins/discover/public/application/main/components/sidebar/discover_field.tsx @@ -25,7 +25,7 @@ import { DragDrop } from '@kbn/dom-drag-drop'; import { DiscoverFieldStats } from './discover_field_stats'; import { PLUGIN_ID } from '../../../../../common'; import { getUiActions } from '../../../../kibana_services'; -import { useDiscoverExtension } from '../../../../extensions/extension_provider'; +import { useDiscoverCustomization } from '../../../../customizations/customization_provider'; interface GetCommonFieldItemButtonPropsParams { field: DataViewField; @@ -258,7 +258,7 @@ function DiscoverFieldComponent({ [field.name] ); - const fieldPopoverExtension = useDiscoverExtension('field_popover'); + const fieldPopoverCustomization = useDiscoverCustomization('field_popover'); const renderPopover = () => { return ( diff --git a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx index b033561495acd..b7607d565b461 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/discover_topnav.tsx @@ -17,7 +17,7 @@ import { getTopNavLinks } from './get_top_nav_links'; import { getHeaderActionMenuMounter } from '../../../../kibana_services'; import { DiscoverStateContainer } from '../../services/discover_state'; import { onSaveSearch } from './on_save_search'; -import { useDiscoverExtension } from '../../../../extensions/extension_provider'; +import { useDiscoverCustomization } from '../../../../customizations/customization_provider'; export interface DiscoverTopNavProps { onOpenInspector: () => void; @@ -109,7 +109,7 @@ export const DiscoverTopNav = ({ }); }, [dataViewEditor, stateContainer]); - const topNavExtension = useDiscoverExtension('top_nav'); + const topNavCustomization = useDiscoverCustomization('top_nav'); const topNavMenu = useMemo( () => getTopNavLinks({ @@ -120,7 +120,7 @@ export const DiscoverTopNav = ({ isPlainRecord, adHocDataViews, persistDataView, - topNavExtension, + topNavCustomization, }), [ adHocDataViews, @@ -130,7 +130,7 @@ export const DiscoverTopNav = ({ persistDataView, services, stateContainer, - topNavExtension, + topNavCustomization, ] ); @@ -198,7 +198,7 @@ export const DiscoverTopNav = ({ [services, stateContainer] ); - const searchBarExtension = useDiscoverExtension('search_bar'); + const searchBarCustomization = useDiscoverCustomization('search_bar'); return ( + searchBarCustomization?.CustomDataViewPicker ? ( + ) : undefined } dataViewPickerComponentProps={ - searchBarExtension?.CustomDataViewPicker ? undefined : dataViewPickerProps + searchBarCustomization?.CustomDataViewPicker ? undefined : dataViewPickerProps } displayStyle="detached" textBasedLanguageModeErrors={ diff --git a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx index 2fd0e54b34f40..4b6b215216bc8 100644 --- a/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx +++ b/src/plugins/discover/public/application/main/components/top_nav/get_top_nav_links.tsx @@ -17,7 +17,7 @@ import { onSaveSearch } from './on_save_search'; import { DiscoverStateContainer } from '../../services/discover_state'; import { openOptionsPopover } from './open_options_popover'; import { openAlertsPopover } from './open_alerts_popover'; -import type { TopNavExtension } from '../../../../extensions'; +import type { TopNavCustomization } from '../../../../customizations'; /** * Helper function to build the top nav links @@ -30,7 +30,7 @@ export const getTopNavLinks = ({ isPlainRecord, persistDataView, adHocDataViews, - topNavExtension, + topNavCustomization, }: { dataView: DataView; services: DiscoverServices; @@ -39,7 +39,7 @@ export const getTopNavLinks = ({ isPlainRecord: boolean; adHocDataViews: DataView[]; persistDataView: (dataView: DataView) => Promise; - topNavExtension: TopNavExtension | undefined; + topNavCustomization: TopNavCustomization | undefined; }): TopNavMenuData[] => { const options = { id: 'options', @@ -200,8 +200,8 @@ export const getTopNavLinks = ({ }, }; - const defaultMenu = topNavExtension?.defaultMenu; - const entries = topNavExtension?.getMenuItems?.() ?? []; + const defaultMenu = topNavCustomization?.defaultMenu; + const entries = topNavCustomization?.getMenuItems?.() ?? []; if (services.capabilities.advancedSettings.save && !defaultMenu?.options?.disabled) { entries.push({ data: options, order: defaultMenu?.options?.order ?? 100 }); diff --git a/src/plugins/discover/public/application/main/discover_main_route.tsx b/src/plugins/discover/public/application/main/discover_main_route.tsx index 90de868f00e82..492cbc9ba745d 100644 --- a/src/plugins/discover/public/application/main/discover_main_route.tsx +++ b/src/plugins/discover/public/application/main/discover_main_route.tsx @@ -29,10 +29,10 @@ import { getScopedHistory, getUrlTracker } from '../../kibana_services'; import { useAlertResultsToast } from './hooks/use_alert_results_toast'; import { DiscoverMainProvider } from './services/discover_state_provider'; import { - DiscoverExtensionProvider, - useDiscoverExtensionRegistry, -} from '../../extensions/extension_provider'; -import type { RegisterExtensions } from '../../extensions/types'; + DiscoverCustomizationProvider, + useDiscoverCustomizationService, +} from '../../customizations/customization_provider'; +import type { CustomizationCallback } from '../../customizations/types'; const DiscoverMainAppMemoized = memo(DiscoverMainApp); @@ -41,11 +41,11 @@ interface DiscoverLandingParams { } export interface MainRouteProps { - registerExtensions: RegisterExtensions[]; + customizationCallbacks: CustomizationCallback[]; isDev: boolean; } -export function DiscoverMainRoute({ registerExtensions, isDev }: MainRouteProps) { +export function DiscoverMainRoute({ customizationCallbacks, isDev }: MainRouteProps) { const history = useHistory(); const services = useDiscoverServices(); const { @@ -63,7 +63,10 @@ export function DiscoverMainRoute({ registerExtensions, isDev }: MainRouteProps) services, }) ); - const extensionRegistry = useDiscoverExtensionRegistry({ registerExtensions, stateContainer }); + const customizationService = useDiscoverCustomizationService({ + customizationCallbacks, + stateContainer, + }); const [error, setError] = useState(); const [loading, setLoading] = useState(true); const [hasESData, setHasESData] = useState(false); @@ -252,15 +255,15 @@ export function DiscoverMainRoute({ registerExtensions, isDev }: MainRouteProps) return ; } - if (loading || !extensionRegistry) { + if (loading || !customizationService) { return ; } return ( - + - + ); } diff --git a/src/plugins/discover/public/customizations/customization_provider.ts b/src/plugins/discover/public/customizations/customization_provider.ts new file mode 100644 index 0000000000000..95c21daa5f9b8 --- /dev/null +++ b/src/plugins/discover/public/customizations/customization_provider.ts @@ -0,0 +1,63 @@ +/* + * 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 { createContext, useContext, useState } from 'react'; +import useObservable from 'react-use/lib/useObservable'; +import { isFunction } from 'lodash'; +import useEffectOnce from 'react-use/lib/useEffectOnce'; +import { + createCustomizationService, + DiscoverCustomizationId, + DiscoverCustomizationService, +} from '.'; +import type { DiscoverStateContainer } from '../application/main/services/discover_state'; +import type { CustomizationCallback } from './types'; + +const customizationContext = createContext( + createCustomizationService() +); + +export const DiscoverCustomizationProvider = customizationContext.Provider; + +export const useDiscoverCustomizationService = ({ + customizationCallbacks, + stateContainer, +}: { + customizationCallbacks: CustomizationCallback[]; + stateContainer: DiscoverStateContainer; +}) => { + const [customizationService, setCustomizationService] = useState(); + + useEffectOnce(() => { + const customizations = createCustomizationService(); + const callbacks = customizationCallbacks.map((callback) => + Promise.resolve(callback({ customizations, stateContainer })) + ); + const initialize = () => Promise.all(callbacks).then((result) => result.filter(isFunction)); + + initialize().then(() => { + setCustomizationService(customizations); + }); + + return () => { + initialize().then((cleanups) => { + cleanups.forEach((cleanup) => cleanup()); + }); + }; + }); + + return customizationService; +}; + +export const useDiscoverCustomization$ = ( + id: TCustomizationId +) => useContext(customizationContext).get$(id); + +export const useDiscoverCustomization = ( + id: TCustomizationId +) => useObservable(useDiscoverCustomization$(id)); diff --git a/src/plugins/discover/public/customizations/customization_service.ts b/src/plugins/discover/public/customizations/customization_service.ts new file mode 100644 index 0000000000000..729eb070589cc --- /dev/null +++ b/src/plugins/discover/public/customizations/customization_service.ts @@ -0,0 +1,82 @@ +/* + * 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 { filter, map, Observable, startWith, Subject } from 'rxjs'; +import type { + DataGridCustomization, + FieldPopoverCustomization, + SearchBarCustomization, + TopNavCustomization, +} from './customization_types'; + +export type DiscoverCustomization = + | DataGridCustomization + | FieldPopoverCustomization + | SearchBarCustomization + | TopNavCustomization; + +export type DiscoverCustomizationId = DiscoverCustomization['id']; + +export interface DiscoverCustomizationService { + set: (customization: DiscoverCustomization) => void; + get$: ( + id: TCustomizationId + ) => Observable | undefined>; + enable: (id: DiscoverCustomizationId) => void; + disable: (id: DiscoverCustomizationId) => void; +} + +interface CustomizationEntry { + customization: DiscoverCustomization; + enabled: boolean; +} + +export const createCustomizationService = (): DiscoverCustomizationService => { + const update$ = new Subject(); + const customizations = new Map(); + + return { + set: (customization) => { + const entry = customizations.get(customization.id); + customizations.set(customization.id, { + customization, + enabled: entry?.enabled ?? true, + }); + update$.next(customization.id); + }, + + get$: (id: TCustomizationId) => { + return update$.pipe( + startWith(id), + filter((currentId) => currentId === id), + map(() => { + const entry = customizations.get(id); + if (entry && entry.enabled) { + return entry.customization as Extract; + } + }) + ); + }, + + enable: (id) => { + const entry = customizations.get(id); + if (entry && !entry.enabled) { + entry.enabled = true; + update$.next(entry.customization.id); + } + }, + + disable: (id) => { + const entry = customizations.get(id); + if (entry && entry.enabled) { + entry.enabled = false; + update$.next(entry.customization.id); + } + }, + }; +}; diff --git a/src/plugins/discover/public/extensions/extension_types/data_grid_extension.ts b/src/plugins/discover/public/customizations/customization_types/data_grid_customization.ts similarity index 94% rename from src/plugins/discover/public/extensions/extension_types/data_grid_extension.ts rename to src/plugins/discover/public/customizations/customization_types/data_grid_customization.ts index 149f7789c354e..a86be9fae142d 100644 --- a/src/plugins/discover/public/extensions/extension_types/data_grid_extension.ts +++ b/src/plugins/discover/public/customizations/customization_types/data_grid_customization.ts @@ -17,7 +17,7 @@ export interface DefaultLeadingControlColumns { select?: DefaultLeadingControlColumn; } -export interface DataGridExtension { +export interface DataGridCustomization { id: 'data_grid'; defaultLeadingControlColumns?: DefaultLeadingControlColumns; getLeadingControlColumns?: () => EuiDataGridControlColumn[]; diff --git a/src/plugins/discover/public/extensions/extension_types/field_popover_extension.ts b/src/plugins/discover/public/customizations/customization_types/field_popover_customization.ts similarity index 91% rename from src/plugins/discover/public/extensions/extension_types/field_popover_extension.ts rename to src/plugins/discover/public/customizations/customization_types/field_popover_customization.ts index 18c1c168287fa..fd65e2e120dac 100644 --- a/src/plugins/discover/public/extensions/extension_types/field_popover_extension.ts +++ b/src/plugins/discover/public/customizations/customization_types/field_popover_customization.ts @@ -8,7 +8,7 @@ import type { ComponentType } from 'react'; -export interface FieldPopoverExtension { +export interface FieldPopoverCustomization { id: 'field_popover'; disableDefaultBottomButton?: boolean; CustomBottomButton?: ComponentType; diff --git a/src/plugins/discover/public/extensions/extension_types/index.ts b/src/plugins/discover/public/customizations/customization_types/index.ts similarity index 66% rename from src/plugins/discover/public/extensions/extension_types/index.ts rename to src/plugins/discover/public/customizations/customization_types/index.ts index e96917e27367b..470344842c311 100644 --- a/src/plugins/discover/public/extensions/extension_types/index.ts +++ b/src/plugins/discover/public/customizations/customization_types/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -export * from './data_grid_extension'; -export * from './field_popover_extension'; -export * from './search_bar_extension'; -export * from './top_nav_extension'; +export * from './data_grid_customization'; +export * from './field_popover_customization'; +export * from './search_bar_customization'; +export * from './top_nav_customization'; diff --git a/src/plugins/discover/public/extensions/extension_types/search_bar_extension.ts b/src/plugins/discover/public/customizations/customization_types/search_bar_customization.ts similarity index 91% rename from src/plugins/discover/public/extensions/extension_types/search_bar_extension.ts rename to src/plugins/discover/public/customizations/customization_types/search_bar_customization.ts index b923ef71eb9a3..8117781a95c93 100644 --- a/src/plugins/discover/public/extensions/extension_types/search_bar_extension.ts +++ b/src/plugins/discover/public/customizations/customization_types/search_bar_customization.ts @@ -8,7 +8,7 @@ import type { ComponentType } from 'react'; -export interface SearchBarExtension { +export interface SearchBarCustomization { id: 'search_bar'; CustomDataViewPicker?: ComponentType; } diff --git a/src/plugins/discover/public/extensions/extension_types/top_nav_extension.ts b/src/plugins/discover/public/customizations/customization_types/top_nav_customization.ts similarity index 96% rename from src/plugins/discover/public/extensions/extension_types/top_nav_extension.ts rename to src/plugins/discover/public/customizations/customization_types/top_nav_customization.ts index a138316dd6f60..45288c6a248fb 100644 --- a/src/plugins/discover/public/extensions/extension_types/top_nav_extension.ts +++ b/src/plugins/discover/public/customizations/customization_types/top_nav_customization.ts @@ -28,7 +28,7 @@ export interface TopNavMenuItem { order: number; } -export interface TopNavExtension { +export interface TopNavCustomization { id: 'top_nav'; defaultMenu?: TopNavDefaultMenu; getMenuItems?: () => TopNavMenuItem[]; diff --git a/src/plugins/discover/public/extensions/index.ts b/src/plugins/discover/public/customizations/index.ts similarity index 81% rename from src/plugins/discover/public/extensions/index.ts rename to src/plugins/discover/public/customizations/index.ts index ad125a998ba0d..78f922c3a5eac 100644 --- a/src/plugins/discover/public/extensions/index.ts +++ b/src/plugins/discover/public/customizations/index.ts @@ -6,5 +6,5 @@ * Side Public License, v 1. */ -export * from './extension_types'; -export * from './extension_registry'; +export * from './customization_types'; +export * from './customization_service'; diff --git a/src/plugins/discover/public/extensions/profile_aware_locator.ts b/src/plugins/discover/public/customizations/profile_aware_locator.ts similarity index 100% rename from src/plugins/discover/public/extensions/profile_aware_locator.ts rename to src/plugins/discover/public/customizations/profile_aware_locator.ts diff --git a/src/plugins/discover/public/extensions/profile_registry.ts b/src/plugins/discover/public/customizations/profile_registry.ts similarity index 88% rename from src/plugins/discover/public/extensions/profile_registry.ts rename to src/plugins/discover/public/customizations/profile_registry.ts index c1aa440d188e6..236cd991f08b1 100644 --- a/src/plugins/discover/public/extensions/profile_registry.ts +++ b/src/plugins/discover/public/customizations/profile_registry.ts @@ -6,11 +6,11 @@ * Side Public License, v 1. */ -import type { RegisterExtensions } from './types'; +import type { CustomizationCallback } from './types'; export interface DiscoverProfile { name: string; - registerExtensions: RegisterExtensions[]; + customizationCallbacks: CustomizationCallback[]; } export interface DiscoverProfileRegistry { diff --git a/src/plugins/discover/public/extensions/types.ts b/src/plugins/discover/public/customizations/types.ts similarity index 68% rename from src/plugins/discover/public/extensions/types.ts rename to src/plugins/discover/public/customizations/types.ts index e4ccd1fde8620..7c7088306f585 100644 --- a/src/plugins/discover/public/extensions/types.ts +++ b/src/plugins/discover/public/customizations/types.ts @@ -7,13 +7,13 @@ */ import type { DiscoverStateContainer } from '../application/main/services/discover_state'; -import type { DiscoverExtensionRegistry } from './extension_registry'; +import type { DiscoverCustomizationService } from './customization_service'; -export interface RegisterExtensionsContext { - extensions: DiscoverExtensionRegistry; +export interface CustomizationCallbackContext { + customizations: DiscoverCustomizationService; stateContainer: DiscoverStateContainer; } -export type RegisterExtensions = ( - options: RegisterExtensionsContext +export type CustomizationCallback = ( + options: CustomizationCallbackContext ) => void | (() => void) | Promise void)>; diff --git a/src/plugins/discover/public/extensions/extension_provider.ts b/src/plugins/discover/public/extensions/extension_provider.ts deleted file mode 100644 index 5fcaf1e20cf56..0000000000000 --- a/src/plugins/discover/public/extensions/extension_provider.ts +++ /dev/null @@ -1,55 +0,0 @@ -/* - * 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 { createContext, useContext, useState } from 'react'; -import useObservable from 'react-use/lib/useObservable'; -import { isFunction } from 'lodash'; -import useEffectOnce from 'react-use/lib/useEffectOnce'; -import { createExtensionRegistry, DiscoverExtensionId, DiscoverExtensionRegistry } from '.'; -import type { DiscoverStateContainer } from '../application/main/services/discover_state'; -import type { RegisterExtensions } from './types'; - -const extensionContext = createContext(createExtensionRegistry()); - -export const DiscoverExtensionProvider = extensionContext.Provider; - -export const useDiscoverExtensionRegistry = ({ - registerExtensions, - stateContainer, -}: { - registerExtensions: RegisterExtensions[]; - stateContainer: DiscoverStateContainer; -}) => { - const [extensionRegistry, setExtensionRegistry] = useState(); - - useEffectOnce(() => { - const extensions = createExtensionRegistry(); - const registrations = registerExtensions.map((register) => - Promise.resolve(register({ extensions, stateContainer })) - ); - const initialize = () => Promise.all(registrations).then((result) => result.filter(isFunction)); - - initialize().then(() => { - setExtensionRegistry(extensions); - }); - - return () => { - initialize().then((cleanups) => { - cleanups.forEach((cleanup) => cleanup()); - }); - }; - }); - - return extensionRegistry; -}; - -export const useDiscoverExtension$ = (id: TExtensionId) => - useContext(extensionContext).get$(id); - -export const useDiscoverExtension = (id: TExtensionId) => - useObservable(useDiscoverExtension$(id)); diff --git a/src/plugins/discover/public/extensions/extension_registry.ts b/src/plugins/discover/public/extensions/extension_registry.ts deleted file mode 100644 index 1a8f3335454eb..0000000000000 --- a/src/plugins/discover/public/extensions/extension_registry.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * 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 { filter, map, Observable, startWith, Subject } from 'rxjs'; -import type { - DataGridExtension, - FieldPopoverExtension, - SearchBarExtension, - TopNavExtension, -} from './extension_types'; - -export type DiscoverExtension = - | DataGridExtension - | FieldPopoverExtension - | SearchBarExtension - | TopNavExtension; - -export type DiscoverExtensionId = DiscoverExtension['id']; - -export interface DiscoverExtensionRegistry { - set: (extension: DiscoverExtension) => void; - get$: ( - id: TExtensionId - ) => Observable | undefined>; - enable: (id: DiscoverExtensionId) => void; - disable: (id: DiscoverExtensionId) => void; -} - -interface DiscoverExtensionRegistration { - extension: DiscoverExtension; - enabled: boolean; -} - -export const createExtensionRegistry = (): DiscoverExtensionRegistry => { - const update$ = new Subject(); - const registrations = new Map(); - - return { - set: (extension) => { - const registration = registrations.get(extension.id); - registrations.set(extension.id, { extension, enabled: registration?.enabled ?? true }); - update$.next(extension.id); - }, - - get$: (id: TExtensionId) => { - return update$.pipe( - startWith(id), - filter((currentId) => currentId === id), - map(() => { - const registration = registrations.get(id); - if (registration && registration.enabled) { - return registration.extension as Extract; - } - }) - ); - }, - - enable: (id) => { - const registration = registrations.get(id); - if (registration && !registration.enabled) { - registration.enabled = true; - update$.next(registration.extension.id); - } - }, - - disable: (id) => { - const registration = registrations.get(id); - if (registration && registration.enabled) { - registration.enabled = false; - update$.next(registration.extension.id); - } - }, - }; -}; diff --git a/src/plugins/discover/public/plugin.tsx b/src/plugins/discover/public/plugin.tsx index 150a378c2cf2c..f114578c8f4de 100644 --- a/src/plugins/discover/public/plugin.tsx +++ b/src/plugins/discover/public/plugin.tsx @@ -71,9 +71,9 @@ import { DiscoverSingleDocLocatorDefinition, } from './application/doc/locator'; import { DiscoverAppLocator, DiscoverAppLocatorDefinition } from '../common'; -import type { RegisterExtensions } from './extensions/types'; -import { createProfileRegistry } from './extensions/profile_registry'; -import { ProfileAwareLocator } from './extensions/profile_aware_locator'; +import type { CustomizationCallback } from './customizations/types'; +import { createProfileRegistry } from './customizations/profile_registry'; +import { ProfileAwareLocator } from './customizations/profile_aware_locator'; const DocViewerLegacyTable = React.lazy( () => import('./services/doc_views/components/doc_viewer_table/legacy') @@ -158,7 +158,7 @@ export interface DiscoverStart { * ``` */ readonly locator: undefined | DiscoverAppLocator; - readonly registerExtensions: (profileName: string, register: RegisterExtensions) => void; + readonly customize: (profileName: string, callback: CustomizationCallback) => void; } /** @@ -409,12 +409,12 @@ export class DiscoverPlugin return { locator: this.locator, - registerExtensions: (profileName: string, register: RegisterExtensions) => { + customize: (profileName: string, callback: CustomizationCallback) => { const profile = this.profileRegistry.get(profileName) ?? { name: profileName, - registerExtensions: [], + customizationCallbacks: [], }; - profile.registerExtensions.push(register); + profile.customizationCallbacks.push(callback); this.profileRegistry.set(profile); }, };