diff --git a/.i18nrc.json b/.i18nrc.json index 7d7685b5c1ef1b..e0acda70cc3480 100644 --- a/.i18nrc.json +++ b/.i18nrc.json @@ -26,6 +26,7 @@ "src/legacy/core_plugins/management", "src/plugins/management" ], + "advancedSettings": "src/plugins/advanced_settings", "kibana_react": "src/legacy/core_plugins/kibana_react", "kibana-react": "src/plugins/kibana_react", "kibana_utils": "src/plugins/kibana_utils", diff --git a/rfcs/text/0006_management_section_service.md b/rfcs/text/0006_management_section_service.md index d9781e85cd8a99..1a52e85a4ff167 100644 --- a/rfcs/text/0006_management_section_service.md +++ b/rfcs/text/0006_management_section_service.md @@ -257,15 +257,7 @@ Current public contracts owned by the legacy service: ```js // ui/management/index interface API { - PAGE_TITLE_COMPONENT: string; // actually related to advanced settings? - PAGE_SUBTITLE_COMPONENT: string; // actually related to advanced settings? - PAGE_FOOTER_COMPONENT: string; // actually related to advanced settings? SidebarNav: React.FC; - registerSettingsComponent: ( - id: string, - component: string | React.FC, - allowOverride: boolean - ) => void; management: new ManagementSection(); MANAGEMENT_BREADCRUMB: { text: string; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/__snapshots__/advanced_settings.test.tsx.snap b/src/legacy/core_plugins/kibana/public/management/sections/settings/__snapshots__/advanced_settings.test.tsx.snap index 4814432c832e2f..e76435fdb73b2d 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/__snapshots__/advanced_settings.test.tsx.snap +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/__snapshots__/advanced_settings.test.tsx.snap @@ -6,7 +6,7 @@ exports[`AdvancedSettings should render read-only when saving is disabled 1`] = gutterSize="none" > - + - + @@ -139,7 +139,7 @@ exports[`AdvancedSettings should render read-only when saving is disabled 1`] = } showNoResultsMessage={true} /> - - + - + @@ -322,7 +322,7 @@ exports[`AdvancedSettings should render specific setting if given setting key 1` } showNoResultsMessage={true} /> - ({ npStart: mockConfig(), @@ -215,6 +217,22 @@ function mockConfig() { core: { uiSettings: config, }, + plugins: { + advancedSettings: { + component: { + register: jest.fn(), + get: () => { + const foo: React.ComponentType = () =>
Hello
; + foo.displayName = 'foo_component'; + return foo; + }, + componentType: { + PAGE_TITLE_COMPONENT: 'page_title_component', + PAGE_SUBTITLE_COMPONENT: 'page_subtitle_component', + }, + }, + }, + }, }; } diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/advanced_settings.tsx b/src/legacy/core_plugins/kibana/public/management/sections/settings/advanced_settings.tsx index 569ef73f2b4536..c995b391d3d2dc 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/advanced_settings.tsx +++ b/src/legacy/core_plugins/kibana/public/management/sections/settings/advanced_settings.tsx @@ -31,14 +31,6 @@ import { getAriaName, toEditableConfig, DEFAULT_CATEGORY } from './lib'; import { FieldSetting, IQuery } from './types'; -import { - registerDefaultComponents, - PAGE_TITLE_COMPONENT, - PAGE_SUBTITLE_COMPONENT, - PAGE_FOOTER_COMPONENT, -} from './components/default_component_registry'; -import { getSettingsComponent } from './components/component_registry'; - interface AdvancedSettingsProps { queryText: string; enableSaving: boolean; @@ -75,8 +67,6 @@ export class AdvancedSettings extends Component diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/__snapshots__/component_registry.test.tsx.snap b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/__snapshots__/component_registry.test.tsx.snap deleted file mode 100644 index 070b3870570616..00000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/__snapshots__/component_registry.test.tsx.snap +++ /dev/null @@ -1,5 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`getSettingsComponent should throw an error when requesting a component that does not exist 1`] = `"Component not found with id does not exist"`; - -exports[`registerSettingsComponent should disallow registering a component with a duplicate id 1`] = `"Component with id test2 is already registered."`; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.test.tsx b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.test.tsx deleted file mode 100644 index 24e9e5dd3809c8..00000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.test.tsx +++ /dev/null @@ -1,82 +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 React, { FunctionComponent } from 'react'; -import { - tryRegisterSettingsComponent, - registerSettingsComponent, - getSettingsComponent, -} from './component_registry'; - -describe('tryRegisterSettingsComponent', () => { - it('should allow a component to be registered', () => { - const component = () =>
; - expect(tryRegisterSettingsComponent('tryTest1', component)).toEqual(true); - }); - - it('should return false if the component is already registered, and not allow an override', () => { - const component = () =>
; - expect(tryRegisterSettingsComponent('tryTest2', component)).toEqual(true); - - const updatedComponent = () =>
; - expect(tryRegisterSettingsComponent('tryTest2', updatedComponent)).toEqual(false); - expect(getSettingsComponent('tryTest2')).toBe(component); - }); -}); - -describe('registerSettingsComponent', () => { - it('should allow a component to be registered', () => { - const component = () =>
; - registerSettingsComponent('test', component); - }); - - it('should disallow registering a component with a duplicate id', () => { - const component = () =>
; - registerSettingsComponent('test2', component); - expect(() => registerSettingsComponent('test2', () => )).toThrowErrorMatchingSnapshot(); - }); - - it('should allow a component to be overriden', () => { - const component = () =>
; - registerSettingsComponent('test3', component); - - const anotherComponent = () => ; - registerSettingsComponent('test3', anotherComponent, true); - - expect(getSettingsComponent('test3')).toBe(anotherComponent); - }); - - it('should set a displayName for the component', () => { - const component = () =>
; - registerSettingsComponent('display_name_component', component); - expect((component as FunctionComponent).displayName).toEqual('display_name_component'); - }); -}); - -describe('getSettingsComponent', () => { - it('should allow a component to be retrieved', () => { - const component = () =>
; - registerSettingsComponent('test4', component); - expect(getSettingsComponent('test4')).toBe(component); - }); - - it('should throw an error when requesting a component that does not exist', () => { - expect(() => getSettingsComponent('does not exist')).toThrowErrorMatchingSnapshot(); - }); -}); diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.ts b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.ts deleted file mode 100644 index b58180c498edfe..00000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/component_registry.ts +++ /dev/null @@ -1,83 +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 { ComponentType } from 'react'; - -type Id = string; -const registry: Record | undefined>> = {}; - -/** - * Attempts to register the provided component. - * If a component with that ID is already registered, then the registration fails. - * - * @param {*} id the id of the component to register - * @param {*} component the component - */ -export function tryRegisterSettingsComponent( - id: Id, - component: ComponentType | undefined> -) { - if (id in registry) { - return false; - } - - registerSettingsComponent(id, component); - return true; -} - -/** - * Attempts to register the provided component, with the ability to optionally allow - * the component to override an existing one. - * - * If the intent is to override, then `allowOverride` must be set to true, otherwise an exception is thrown. - * - * @param {*} id the id of the component to register - * @param {*} component the component - * @param {*} allowOverride (default: false) - optional flag to allow this component to override a previously registered component - */ -export function registerSettingsComponent( - id: Id, - component: ComponentType | undefined>, - allowOverride = false -) { - if (!allowOverride && id in registry) { - throw new Error(`Component with id ${id} is already registered.`); - } - - // Setting a display name if one does not already exist. - // This enhances the snapshots, as well as the debugging experience. - if (!component.displayName) { - component.displayName = id; - } - - registry[id] = component; -} - -/** - * Retrieve a registered component by its ID. - * If the component does not exist, then an exception is thrown. - * - * @param {*} id the ID of the component to retrieve - */ -export function getSettingsComponent(id: Id): ComponentType | undefined> { - if (!(id in registry)) { - throw new Error(`Component not found with id ${id}`); - } - return registry[id]; -} diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.tsx b/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.tsx deleted file mode 100644 index ff3f75b79baefc..00000000000000 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.test.tsx +++ /dev/null @@ -1,44 +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 React from 'react'; -import { registerDefaultComponents, PAGE_TITLE_COMPONENT } from './default_component_registry'; -import { getSettingsComponent, registerSettingsComponent } from './component_registry'; -import { PageTitle } from './page_title'; - -describe('default_component_registry', () => { - it('should register default components with the registry', () => { - registerDefaultComponents(); - expect(getSettingsComponent(PAGE_TITLE_COMPONENT)).toEqual(PageTitle); - }); - - it('should be able to call "registerDefaultComponents" several times without throwing', () => { - registerDefaultComponents(); - registerDefaultComponents(); - registerDefaultComponents(); - }); - - it('should not override components if they are already registered', () => { - const newComponent = () =>
; - registerSettingsComponent(PAGE_TITLE_COMPONENT, newComponent, true); - registerDefaultComponents(); - - expect(getSettingsComponent(PAGE_TITLE_COMPONENT)).toEqual(newComponent); - }); -}); diff --git a/src/legacy/core_plugins/telemetry/public/views/management/management.js b/src/legacy/core_plugins/telemetry/public/views/management/management.js index 796caf1c8cfe6d..7032775e391bb1 100644 --- a/src/legacy/core_plugins/telemetry/public/views/management/management.js +++ b/src/legacy/core_plugins/telemetry/public/views/management/management.js @@ -19,7 +19,7 @@ import React from 'react'; import routes from 'ui/routes'; -import { registerSettingsComponent, PAGE_FOOTER_COMPONENT } from 'ui/management'; +import { npSetup } from 'ui/new_platform'; import { TelemetryOptInProvider } from '../../services'; import { TelemetryForm } from '../../components'; @@ -27,6 +27,7 @@ routes.defaults(/\/management/, { resolve: { telemetryManagementSection: function(Private) { const telemetryOptInProvider = Private(TelemetryOptInProvider); + const componentRegistry = npSetup.plugins.advancedSettings.component; const Component = props => ( ); - registerSettingsComponent(PAGE_FOOTER_COMPONENT, Component, true); + componentRegistry.register( + componentRegistry.componentType.PAGE_FOOTER_COMPONENT, + Component, + true + ); }, }, }); diff --git a/src/legacy/ui/public/management/index.d.ts b/src/legacy/ui/public/management/index.d.ts index 7880e1d5d02957..529efd36623a3a 100644 --- a/src/legacy/ui/public/management/index.d.ts +++ b/src/legacy/ui/public/management/index.d.ts @@ -18,15 +18,7 @@ */ declare module 'ui/management' { - export const PAGE_TITLE_COMPONENT: string; - export const PAGE_SUBTITLE_COMPONENT: string; - export const PAGE_FOOTER_COMPONENT: string; export const SidebarNav: React.FC; - export function registerSettingsComponent( - id: string, - component: string | React.FC, - allowOverride: boolean - ): void; export const management: any; // TODO - properly provide types export const MANAGEMENT_BREADCRUMB: { text: string; diff --git a/src/legacy/ui/public/management/index.js b/src/legacy/ui/public/management/index.js index b2f1946dbc59cb..25d3678c5dbbaf 100644 --- a/src/legacy/ui/public/management/index.js +++ b/src/legacy/ui/public/management/index.js @@ -17,12 +17,6 @@ * under the License. */ -export { - PAGE_TITLE_COMPONENT, - PAGE_SUBTITLE_COMPONENT, - PAGE_FOOTER_COMPONENT, -} from '../../../core_plugins/kibana/public/management/sections/settings/components/default_component_registry'; -export { registerSettingsComponent } from '../../../core_plugins/kibana/public/management/sections/settings/components/component_registry'; export { MANAGEMENT_BREADCRUMB } from './breadcrumbs'; import { npStart } from 'ui/new_platform'; export const management = npStart.plugins.management.legacy; diff --git a/src/legacy/ui/public/new_platform/__mocks__/helpers.ts b/src/legacy/ui/public/new_platform/__mocks__/helpers.ts index 439ac9b5713dfa..cf24b0e9675fac 100644 --- a/src/legacy/ui/public/new_platform/__mocks__/helpers.ts +++ b/src/legacy/ui/public/new_platform/__mocks__/helpers.ts @@ -29,6 +29,7 @@ import { managementPluginMock } from '../../../../../plugins/management/public/m import { usageCollectionPluginMock } from '../../../../../plugins/usage_collection/public/mocks'; import { kibanaLegacyPluginMock } from '../../../../../plugins/kibana_legacy/public/mocks'; import { chartPluginMock } from '../../../../../plugins/charts/public/mocks'; +import { advancedSettingsMock } from '../../../../../plugins/advanced_settings/public/mocks'; /* eslint-enable @kbn/eslint/no-restricted-paths */ export const pluginsMock = { @@ -41,6 +42,7 @@ export const pluginsMock = { expressions: expressionsPluginMock.createSetupContract(), uiActions: uiActionsPluginMock.createSetupContract(), usageCollection: usageCollectionPluginMock.createSetupContract(), + advancedSettings: advancedSettingsMock.createSetupContract(), kibana_legacy: kibanaLegacyPluginMock.createSetupContract(), }), createStart: () => ({ @@ -52,6 +54,7 @@ export const pluginsMock = { expressions: expressionsPluginMock.createStartContract(), uiActions: uiActionsPluginMock.createStartContract(), management: managementPluginMock.createStartContract(), + advancedSettings: advancedSettingsMock.createStartContract(), kibana_legacy: kibanaLegacyPluginMock.createStartContract(), }), }; diff --git a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js index c2c8b5a0fae7a7..7f4f67ebb06d39 100644 --- a/src/legacy/ui/public/new_platform/new_platform.karma_mock.js +++ b/src/legacy/ui/public/new_platform/new_platform.karma_mock.js @@ -20,6 +20,7 @@ import sinon from 'sinon'; import { getFieldFormatsRegistry } from '../../../../test_utils/public/stub_field_formats'; import { METRIC_TYPE } from '@kbn/analytics'; +import { ComponentRegistry } from '../../../../../src/plugins/advanced_settings/public/'; const mockObservable = () => { return { @@ -58,6 +59,12 @@ const mockCore = { export const npSetup = { core: mockCore, plugins: { + advancedSettings: { + component: { + register: sinon.fake(), + componentType: ComponentRegistry.componentType, + }, + }, usageCollection: { allowTrackUserAgent: sinon.fake(), reportUiStats: sinon.fake(), diff --git a/src/legacy/ui/public/new_platform/new_platform.ts b/src/legacy/ui/public/new_platform/new_platform.ts index 2ade98ec54efd0..62abe2eb9b5bae 100644 --- a/src/legacy/ui/public/new_platform/new_platform.ts +++ b/src/legacy/ui/public/new_platform/new_platform.ts @@ -32,6 +32,10 @@ import { DevToolsSetup, DevToolsStart } from '../../../../plugins/dev_tools/publ import { KibanaLegacySetup, KibanaLegacyStart } from '../../../../plugins/kibana_legacy/public'; import { HomePublicPluginSetup, HomePublicPluginStart } from '../../../../plugins/home/public'; import { SharePluginSetup, SharePluginStart } from '../../../../plugins/share/public'; +import { + AdvancedSettingsSetup, + AdvancedSettingsStart, +} from '../../../../plugins/advanced_settings/public'; import { ManagementSetup, ManagementStart } from '../../../../plugins/management/public'; import { BfetchPublicSetup, BfetchPublicStart } from '../../../../plugins/bfetch/public'; import { UsageCollectionSetup } from '../../../../plugins/usage_collection/public'; @@ -54,6 +58,7 @@ export interface PluginsSetup { kibana_legacy: KibanaLegacySetup; share: SharePluginSetup; usageCollection: UsageCollectionSetup; + advancedSettings: AdvancedSettingsSetup; management: ManagementSetup; } @@ -71,6 +76,7 @@ export interface PluginsStart { kibana_legacy: KibanaLegacyStart; share: SharePluginStart; management: ManagementStart; + advancedSettings: AdvancedSettingsStart; } export const npSetup = { diff --git a/src/plugins/advanced_settings/kibana.json b/src/plugins/advanced_settings/kibana.json new file mode 100644 index 00000000000000..5fc1e916ae45f8 --- /dev/null +++ b/src/plugins/advanced_settings/kibana.json @@ -0,0 +1,7 @@ +{ + "id": "advancedSettings", + "version": "kibana", + "server": false, + "ui": true, + "requiredPlugins": [] +} diff --git a/src/plugins/advanced_settings/public/component_registry/__snapshots__/component_registry.test.tsx.snap b/src/plugins/advanced_settings/public/component_registry/__snapshots__/component_registry.test.tsx.snap new file mode 100644 index 00000000000000..1d6cc882cb344d --- /dev/null +++ b/src/plugins/advanced_settings/public/component_registry/__snapshots__/component_registry.test.tsx.snap @@ -0,0 +1,3 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`ComponentRegistry register should disallow registering a component with a duplicate id 1`] = `"Component with id advanced_settings_page_title is already registered."`; diff --git a/src/plugins/advanced_settings/public/component_registry/component_registry.test.tsx b/src/plugins/advanced_settings/public/component_registry/component_registry.test.tsx new file mode 100644 index 00000000000000..3b722e9517fdb2 --- /dev/null +++ b/src/plugins/advanced_settings/public/component_registry/component_registry.test.tsx @@ -0,0 +1,90 @@ +/* + * 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 React from 'react'; +import { ComponentRegistry } from './component_registry'; + +describe('ComponentRegistry', () => { + describe('register', () => { + it('should allow a component to be registered', () => { + const component = () =>
; + new ComponentRegistry().setup.register( + ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, + component + ); + }); + + it('should disallow registering a component with a duplicate id', () => { + const registry = new ComponentRegistry(); + const component = () =>
; + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + expect(() => + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, () => ( + + )) + ).toThrowErrorMatchingSnapshot(); + }); + + it('should allow a component to be overriden', () => { + const registry = new ComponentRegistry(); + const component = () =>
; + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + + const anotherComponent = () => ; + registry.setup.register( + ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, + anotherComponent, + true + ); + + expect(registry.start.get(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT)).toBe( + anotherComponent + ); + }); + }); + + describe('get', () => { + it('should allow a component to be retrieved', () => { + const registry = new ComponentRegistry(); + const component = () =>
; + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + expect(registry.start.get(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT)).toBe( + component + ); + }); + }); + + it('should set a displayName for the component if one does not exist', () => { + const component: React.ComponentType = () =>
; + const registry = new ComponentRegistry(); + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + + expect(component.displayName).toEqual(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT); + }); + + it('should not set a displayName for the component if one already exists', () => { + const component: React.ComponentType = () =>
; + component.displayName = ''; + const registry = new ComponentRegistry(); + + registry.setup.register(ComponentRegistry.componentType.PAGE_TITLE_COMPONENT, component); + + expect(component.displayName).toEqual(''); + }); +}); diff --git a/src/plugins/advanced_settings/public/component_registry/component_registry.ts b/src/plugins/advanced_settings/public/component_registry/component_registry.ts new file mode 100644 index 00000000000000..cc61798e84cb7b --- /dev/null +++ b/src/plugins/advanced_settings/public/component_registry/component_registry.ts @@ -0,0 +1,91 @@ +/* + * 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 { ComponentType } from 'react'; +import { PageTitle } from './page_title'; +import { PageSubtitle } from './page_subtitle'; +import { PageFooter } from './page_footer'; + +type Id = + | 'advanced_settings_page_title' + | 'advanced_settings_page_subtitle' + | 'advanced_settings_page_footer'; + +const componentType: { [key: string]: Id } = { + PAGE_TITLE_COMPONENT: 'advanced_settings_page_title' as Id, + PAGE_SUBTITLE_COMPONENT: 'advanced_settings_page_subtitle' as Id, + PAGE_FOOTER_COMPONENT: 'advanced_settings_page_footer' as Id, +}; + +type RegistryComponent = ComponentType | undefined>; + +export class ComponentRegistry { + static readonly componentType = componentType; + static readonly defaultRegistry: Record = { + advanced_settings_page_title: PageTitle, + advanced_settings_page_subtitle: PageSubtitle, + advanced_settings_page_footer: PageFooter, + }; + + registry: { [key in Id]?: RegistryComponent } = {}; + + /** + * Attempts to register the provided component, with the ability to optionally allow + * the component to override an existing one. + * + * If the intent is to override, then `allowOverride` must be set to true, otherwise an exception is thrown. + * + * @param {*} id the id of the component to register + * @param {*} component the component + * @param {*} allowOverride (default: false) - optional flag to allow this component to override a previously registered component + */ + private register(id: Id, component: RegistryComponent, allowOverride = false) { + if (!allowOverride && id in this.registry) { + throw new Error(`Component with id ${id} is already registered.`); + } + + // Setting a display name if one does not already exist. + // This enhances the snapshots, as well as the debugging experience. + if (!component.displayName) { + component.displayName = id; + } + + this.registry[id] = component; + } + + /** + * Retrieve a registered component by its ID. + * If the component does not exist, then an exception is thrown. + * + * @param {*} id the ID of the component to retrieve + */ + private get(id: Id): RegistryComponent { + return this.registry[id] || ComponentRegistry.defaultRegistry[id]; + } + + setup = { + componentType: ComponentRegistry.componentType, + register: this.register.bind(this), + }; + + start = { + componentType: ComponentRegistry.componentType, + get: this.get.bind(this), + }; +} diff --git a/src/plugins/advanced_settings/public/component_registry/index.ts b/src/plugins/advanced_settings/public/component_registry/index.ts new file mode 100644 index 00000000000000..79c9248e0c2a9e --- /dev/null +++ b/src/plugins/advanced_settings/public/component_registry/index.ts @@ -0,0 +1,20 @@ +/* + * 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. + */ + +export { ComponentRegistry } from './component_registry'; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/__snapshots__/page_footer.test.tsx.snap b/src/plugins/advanced_settings/public/component_registry/page_footer/__snapshots__/page_footer.test.tsx.snap similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/__snapshots__/page_footer.test.tsx.snap rename to src/plugins/advanced_settings/public/component_registry/page_footer/__snapshots__/page_footer.test.tsx.snap diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/index.ts b/src/plugins/advanced_settings/public/component_registry/page_footer/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/index.ts rename to src/plugins/advanced_settings/public/component_registry/page_footer/index.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.test.tsx b/src/plugins/advanced_settings/public/component_registry/page_footer/page_footer.test.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.test.tsx rename to src/plugins/advanced_settings/public/component_registry/page_footer/page_footer.test.tsx diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.ts b/src/plugins/advanced_settings/public/component_registry/page_footer/page_footer.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_footer/page_footer.ts rename to src/plugins/advanced_settings/public/component_registry/page_footer/page_footer.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/__snapshots__/page_subtitle.test.tsx.snap b/src/plugins/advanced_settings/public/component_registry/page_subtitle/__snapshots__/page_subtitle.test.tsx.snap similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/__snapshots__/page_subtitle.test.tsx.snap rename to src/plugins/advanced_settings/public/component_registry/page_subtitle/__snapshots__/page_subtitle.test.tsx.snap diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/index.ts b/src/plugins/advanced_settings/public/component_registry/page_subtitle/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/index.ts rename to src/plugins/advanced_settings/public/component_registry/page_subtitle/index.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.test.tsx b/src/plugins/advanced_settings/public/component_registry/page_subtitle/page_subtitle.test.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.test.tsx rename to src/plugins/advanced_settings/public/component_registry/page_subtitle/page_subtitle.test.tsx diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.ts b/src/plugins/advanced_settings/public/component_registry/page_subtitle/page_subtitle.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_subtitle/page_subtitle.ts rename to src/plugins/advanced_settings/public/component_registry/page_subtitle/page_subtitle.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/__snapshots__/page_title.test.tsx.snap b/src/plugins/advanced_settings/public/component_registry/page_title/__snapshots__/page_title.test.tsx.snap similarity index 85% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/__snapshots__/page_title.test.tsx.snap rename to src/plugins/advanced_settings/public/component_registry/page_title/__snapshots__/page_title.test.tsx.snap index 8dd4e501067b5e..10b799a986b84d 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/__snapshots__/page_title.test.tsx.snap +++ b/src/plugins/advanced_settings/public/component_registry/page_title/__snapshots__/page_title.test.tsx.snap @@ -7,7 +7,7 @@ exports[`PageTitle should render normally 1`] = ` > diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/index.ts b/src/plugins/advanced_settings/public/component_registry/page_title/index.ts similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/index.ts rename to src/plugins/advanced_settings/public/component_registry/page_title/index.ts diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.test.tsx b/src/plugins/advanced_settings/public/component_registry/page_title/page_title.test.tsx similarity index 100% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.test.tsx rename to src/plugins/advanced_settings/public/component_registry/page_title/page_title.test.tsx diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.tsx b/src/plugins/advanced_settings/public/component_registry/page_title/page_title.tsx similarity index 91% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.tsx rename to src/plugins/advanced_settings/public/component_registry/page_title/page_title.tsx index cb807302c2380b..18d9c60d331bb9 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/page_title/page_title.tsx +++ b/src/plugins/advanced_settings/public/component_registry/page_title/page_title.tsx @@ -25,7 +25,7 @@ export const PageTitle = () => { return (

- +

); diff --git a/src/plugins/advanced_settings/public/index.ts b/src/plugins/advanced_settings/public/index.ts new file mode 100644 index 00000000000000..13be36e671f752 --- /dev/null +++ b/src/plugins/advanced_settings/public/index.ts @@ -0,0 +1,27 @@ +/* + * 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 { PluginInitializerContext } from 'kibana/public'; +import { AdvancedSettingsPlugin } from './plugin'; +export { AdvancedSettingsSetup, AdvancedSettingsStart } from './types'; +export { ComponentRegistry } from './component_registry'; + +export function plugin(initializerContext: PluginInitializerContext) { + return new AdvancedSettingsPlugin(); +} diff --git a/src/plugins/advanced_settings/public/mocks.ts b/src/plugins/advanced_settings/public/mocks.ts new file mode 100644 index 00000000000000..e147f57101aae1 --- /dev/null +++ b/src/plugins/advanced_settings/public/mocks.ts @@ -0,0 +1,33 @@ +/* + * 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 { ComponentRegistry } from './component_registry'; + +const register = jest.fn(); +const get = jest.fn(); +const componentType = ComponentRegistry.componentType; + +export const advancedSettingsMock = { + createSetupContract() { + return { register, componentType }; + }, + createStartContract() { + return { get, componentType }; + }, +}; diff --git a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.ts b/src/plugins/advanced_settings/public/plugin.ts similarity index 54% rename from src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.ts rename to src/plugins/advanced_settings/public/plugin.ts index 80b2f2e79b9c77..692e515ca4e5ed 100644 --- a/src/legacy/core_plugins/kibana/public/management/sections/settings/components/default_component_registry.ts +++ b/src/plugins/advanced_settings/public/plugin.ts @@ -17,17 +17,23 @@ * under the License. */ -import { tryRegisterSettingsComponent } from './component_registry'; -import { PageTitle } from './page_title'; -import { PageSubtitle } from './page_subtitle'; -import { PageFooter } from './page_footer'; +import { CoreSetup, CoreStart, Plugin } from 'kibana/public'; +import { ComponentRegistry } from './component_registry'; +import { AdvancedSettingsSetup, AdvancedSettingsStart } from './types'; -export const PAGE_TITLE_COMPONENT = 'advanced_settings_page_title'; -export const PAGE_SUBTITLE_COMPONENT = 'advanced_settings_page_subtitle'; -export const PAGE_FOOTER_COMPONENT = 'advanced_settings_page_footer'; +const component = new ComponentRegistry(); -export function registerDefaultComponents() { - tryRegisterSettingsComponent(PAGE_TITLE_COMPONENT, PageTitle); - tryRegisterSettingsComponent(PAGE_SUBTITLE_COMPONENT, PageSubtitle); - tryRegisterSettingsComponent(PAGE_FOOTER_COMPONENT, PageFooter); +export class AdvancedSettingsPlugin + implements Plugin { + public setup(core: CoreSetup) { + return { + component: component.setup, + }; + } + + public start(core: CoreStart) { + return { + component: component.start, + }; + } } diff --git a/src/plugins/advanced_settings/public/types.ts b/src/plugins/advanced_settings/public/types.ts new file mode 100644 index 00000000000000..a9b965c3c22dee --- /dev/null +++ b/src/plugins/advanced_settings/public/types.ts @@ -0,0 +1,27 @@ +/* + * 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 { ComponentRegistry } from './component_registry'; + +export interface AdvancedSettingsSetup { + component: ComponentRegistry['setup']; +} +export interface AdvancedSettingsStart { + component: ComponentRegistry['start']; +} diff --git a/x-pack/legacy/plugins/spaces/public/advanced_settings/advanced_settings_service.test.tsx b/x-pack/legacy/plugins/spaces/public/advanced_settings/advanced_settings_service.test.tsx index aa3c6acf262361..3c6b2332bbbdc9 100644 --- a/x-pack/legacy/plugins/spaces/public/advanced_settings/advanced_settings_service.test.tsx +++ b/x-pack/legacy/plugins/spaces/public/advanced_settings/advanced_settings_service.test.tsx @@ -5,33 +5,30 @@ */ import { AdvancedSettingsService } from './advanced_settings_service'; -jest.mock('ui/management', () => { - return { - PAGE_TITLE_COMPONENT: 'page_title_component', - PAGE_SUBTITLE_COMPONENT: 'page_subtitle_component', - }; -}); +import { advancedSettingsMock } from '../../../../../../src/plugins/advanced_settings/public/mocks'; + +const componentRegistryMock = advancedSettingsMock.createSetupContract(); describe('Advanced Settings Service', () => { describe('#setup', () => { it('registers space-aware components to augment the advanced settings screen', () => { const deps = { getActiveSpace: jest.fn().mockResolvedValue({ id: 'foo', name: 'foo-space' }), - registerSettingsComponent: jest.fn(), + componentRegistry: componentRegistryMock, }; const advancedSettingsService = new AdvancedSettingsService(); advancedSettingsService.setup(deps); - expect(deps.registerSettingsComponent).toHaveBeenCalledTimes(2); - expect(deps.registerSettingsComponent).toHaveBeenCalledWith( - 'page_title_component', + expect(deps.componentRegistry.register).toHaveBeenCalledTimes(2); + expect(deps.componentRegistry.register).toHaveBeenCalledWith( + componentRegistryMock.componentType.PAGE_TITLE_COMPONENT, expect.any(Function), true ); - expect(deps.registerSettingsComponent).toHaveBeenCalledWith( - 'page_subtitle_component', + expect(deps.componentRegistry.register).toHaveBeenCalledWith( + componentRegistryMock.componentType.PAGE_SUBTITLE_COMPONENT, expect.any(Function), true ); diff --git a/x-pack/legacy/plugins/spaces/public/advanced_settings/advanced_settings_service.tsx b/x-pack/legacy/plugins/spaces/public/advanced_settings/advanced_settings_service.tsx index 9c6c2fcc2cddac..a1552add18f2de 100644 --- a/x-pack/legacy/plugins/spaces/public/advanced_settings/advanced_settings_service.tsx +++ b/x-pack/legacy/plugins/spaces/public/advanced_settings/advanced_settings_service.tsx @@ -4,25 +4,29 @@ * you may not use this file except in compliance with the Elastic License. */ import React from 'react'; -import { PAGE_TITLE_COMPONENT, PAGE_SUBTITLE_COMPONENT } from 'ui/management'; import { Space } from '../../common/model/space'; import { AdvancedSettingsTitle, AdvancedSettingsSubtitle } from './components'; +import { AdvancedSettingsSetup } from '../../../../../../src/plugins/advanced_settings/public'; interface SetupDeps { getActiveSpace: () => Promise; - registerSettingsComponent: ( - id: string, - component: string | React.FC, - allowOverride: boolean - ) => void; + componentRegistry: AdvancedSettingsSetup['component']; } export class AdvancedSettingsService { - public setup({ getActiveSpace, registerSettingsComponent }: SetupDeps) { + public setup({ getActiveSpace, componentRegistry }: SetupDeps) { const PageTitle = () => ; const SubTitle = () => ; - registerSettingsComponent(PAGE_TITLE_COMPONENT, PageTitle, true); - registerSettingsComponent(PAGE_SUBTITLE_COMPONENT, SubTitle, true); + componentRegistry.register( + componentRegistry.componentType.PAGE_TITLE_COMPONENT, + PageTitle, + true + ); + componentRegistry.register( + componentRegistry.componentType.PAGE_SUBTITLE_COMPONENT, + SubTitle, + true + ); } } diff --git a/x-pack/legacy/plugins/spaces/public/legacy.ts b/x-pack/legacy/plugins/spaces/public/legacy.ts index 1dffbd26617144..200cae5498595d 100644 --- a/x-pack/legacy/plugins/spaces/public/legacy.ts +++ b/x-pack/legacy/plugins/spaces/public/legacy.ts @@ -4,7 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -import { registerSettingsComponent } from 'ui/management'; import { npSetup, npStart } from 'ui/new_platform'; import { setup as managementSetup } from '../../../../../src/legacy/core_plugins/management/public/legacy'; import { plugin } from '.'; @@ -16,9 +15,7 @@ const spacesPlugin: SpacesPlugin = plugin(); const pluginsSetup: PluginsSetup = { home: npSetup.plugins.home, management: managementSetup, - __managementLegacyCompat: { - registerSettingsComponent, - }, + advancedSettings: npSetup.plugins.advancedSettings, }; const pluginsStart: PluginsStart = { diff --git a/x-pack/legacy/plugins/spaces/public/plugin.tsx b/x-pack/legacy/plugins/spaces/public/plugin.tsx index 1ddb69a5b595cc..e6271ac3a0a702 100644 --- a/x-pack/legacy/plugins/spaces/public/plugin.tsx +++ b/x-pack/legacy/plugins/spaces/public/plugin.tsx @@ -8,6 +8,7 @@ import { CoreSetup, CoreStart, Plugin } from 'src/core/public'; import { HomePublicPluginSetup } from 'src/plugins/home/public'; import { ManagementSetup } from 'src/legacy/core_plugins/management/public'; import { ManagementStart } from 'src/plugins/management/public'; +import { AdvancedSettingsSetup } from 'src/plugins/advanced_settings/public'; import { SpacesManager } from './spaces_manager'; import { initSpacesNavControl } from './nav_control'; import { createSpacesFeatureCatalogueEntry } from './create_feature_catalogue_entry'; @@ -22,13 +23,7 @@ export interface SpacesPluginStart { export interface PluginsSetup { home?: HomePublicPluginSetup; management: ManagementSetup; - __managementLegacyCompat: { - registerSettingsComponent: ( - id: string, - component: string | React.FC, - allowOverride: boolean - ) => void; - }; + advancedSettings: AdvancedSettingsSetup; } export interface PluginsStart { @@ -53,7 +48,7 @@ export class SpacesPlugin implements Plugin this.spacesManager.getActiveSpace(), - registerSettingsComponent: plugins.__managementLegacyCompat.registerSettingsComponent, + componentRegistry: plugins.advancedSettings.component, }); if (plugins.home) { diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 74fbbdd5f967b6..a2ebb3f44d3334 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -1624,7 +1624,7 @@ "kbn.management.settings.form.clearSearchResultText": "(検索結果を消去)", "kbn.management.settings.form.noSearchResultText": "設定が見つかりませんでした {clearSearch}", "kbn.management.settings.form.searchResultText": "検索用語により {settingsCount} 件の設定が非表示になっています {clearSearch}", - "kbn.management.settings.pageTitle": "設定", + "advancedSettings.pageTitle": "設定", "kbn.management.settings.searchBar.unableToParseQueryErrorMessage": "クエリをパースできません", "kbn.management.settings.searchBarAriaLabel": "高度な設定を検索", "kbn.management.settings.sectionLabel": "高度な設定", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 97c4ea7d9f5a9b..8518f39a815879 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -1624,7 +1624,7 @@ "kbn.management.settings.form.clearSearchResultText": "(清除搜索)", "kbn.management.settings.form.noSearchResultText": "未找到设置{clearSearch}", "kbn.management.settings.form.searchResultText": "搜索词隐藏了 {settingsCount} 个设置{clearSearch}", - "kbn.management.settings.pageTitle": "设置", + "advancedSettings.pageTitle": "设置", "kbn.management.settings.searchBar.unableToParseQueryErrorMessage": "无法解析查询", "kbn.management.settings.searchBarAriaLabel": "搜索高级设置", "kbn.management.settings.sectionLabel": "高级设置",