diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d76ed31b2b2b1..477a10c5700e2 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -574,6 +574,7 @@ packages/kbn-server-http-tools @elastic/kibana-core packages/kbn-server-route-repository @elastic/apm-ui x-pack/plugins/serverless @elastic/appex-sharedux packages/serverless/project_switcher @elastic/appex-sharedux +x-pack/plugins/serverless_search @elastic/appex-sharedux packages/serverless/storybook/config @elastic/appex-sharedux packages/serverless/types @elastic/appex-sharedux test/plugin_functional/plugins/session_notifications @elastic/kibana-core diff --git a/config/serverless.es.yml b/config/serverless.es.yml index dfbff923489a0..c52efbccad0aa 100644 --- a/config/serverless.es.yml +++ b/config/serverless.es.yml @@ -1,2 +1,15 @@ +# Search Project Config + +## Disable APM and Uptime, enable Enterprise Search +xpack.apm.enabled: false +xpack.uptime.enabled: false +enterpriseSearch.enabled: true + +## Enable the Serverless Search plugin +xpack.serverless.search.enabled: true + +## Set the home route uiSettings.overrides.defaultRoute: /app/enterprise_search/content/search_indices + +## Set the dev project switcher current type xpack.serverless.plugin.developer.projectSwitcher.currentType: 'search' diff --git a/docs/developer/plugin-list.asciidoc b/docs/developer/plugin-list.asciidoc index 412a9e8b5569e..1b180664a53a7 100644 --- a/docs/developer/plugin-list.asciidoc +++ b/docs/developer/plugin-list.asciidoc @@ -710,6 +710,10 @@ Kibana. | +|{kib-repo}blob/{branch}/x-pack/plugins/serverless_search/README.mdx[serverlessSearch] +|This plugin contains configuration and code used to create a Serverless Search project. It leverages universal configuration and other APIs in the serverless plugin to configure Kibana. + + |{kib-repo}blob/{branch}/x-pack/plugins/session_view/README.md[sessionView] |Session View is meant to provide a visualization into what is going on in a particular Linux environment where the agent is running. It looks likes a terminal emulator; however, it is a tool for introspecting process activity and understanding user and service behaviour in your Linux servers and infrastructure. It is a time-ordered series of process executions displayed in a tree over time. diff --git a/package.json b/package.json index c43034fb928df..2b0c02da49e3b 100644 --- a/package.json +++ b/package.json @@ -576,6 +576,7 @@ "@kbn/server-route-repository": "link:packages/kbn-server-route-repository", "@kbn/serverless": "link:x-pack/plugins/serverless", "@kbn/serverless-project-switcher": "link:packages/serverless/project_switcher", + "@kbn/serverless-search": "link:x-pack/plugins/serverless_search", "@kbn/serverless-types": "link:packages/serverless/types", "@kbn/session-notifications-plugin": "link:test/plugin_functional/plugins/session_notifications", "@kbn/session-view-plugin": "link:x-pack/plugins/session_view", diff --git a/packages/kbn-optimizer/limits.yml b/packages/kbn-optimizer/limits.yml index af6396c11e063..28662cf58dba5 100644 --- a/packages/kbn-optimizer/limits.yml +++ b/packages/kbn-optimizer/limits.yml @@ -116,6 +116,7 @@ pageLoadAssetSize: security: 65433 securitySolution: 66738 serverless: 16573 + serverlessSearch: 17548 sessionView: 77750 share: 71239 snapshotRestore: 79032 diff --git a/tsconfig.base.json b/tsconfig.base.json index f333d6f58b34f..38320467c3198 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1142,6 +1142,8 @@ "@kbn/serverless/*": ["x-pack/plugins/serverless/*"], "@kbn/serverless-project-switcher": ["packages/serverless/project_switcher"], "@kbn/serverless-project-switcher/*": ["packages/serverless/project_switcher/*"], + "@kbn/serverless-search": ["x-pack/plugins/serverless_search"], + "@kbn/serverless-search/*": ["x-pack/plugins/serverless_search/*"], "@kbn/serverless-storybook-config": ["packages/serverless/storybook/config"], "@kbn/serverless-storybook-config/*": ["packages/serverless/storybook/config/*"], "@kbn/serverless-types": ["packages/serverless/types"], diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/hooks.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/hooks.mock.ts index ce21fd08f180a..77e40a9094d7c 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/hooks.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/hooks.mock.ts @@ -36,8 +36,8 @@ export const mockAllActions = { */ jest.mock('kea', () => ({ ...(jest.requireActual('kea') as object), - useValues: jest.fn(() => ({ ...mockAllValues })), useActions: jest.fn(() => ({ ...mockAllActions })), + useValues: jest.fn(() => ({ ...mockAllValues })), })); /** diff --git a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts index 9c1b0575694c4..d79ebb3530ce2 100644 --- a/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts +++ b/x-pack/plugins/enterprise_search/public/applications/__mocks__/kea_logic/kibana_logic.mock.ts @@ -35,6 +35,7 @@ export const mockKibanaValues = { guidedOnboarding: {}, history: mockHistory, isCloud: false, + isSidebarEnabled: true, lens: { EmbeddableComponent: jest.fn(), stateHelperApi: jest.fn().mockResolvedValue({ diff --git a/x-pack/plugins/enterprise_search/public/applications/index.test.tsx b/x-pack/plugins/enterprise_search/public/applications/index.test.tsx index c9d14e6d67006..010b8a0fb4bb1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/index.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/index.test.tsx @@ -27,8 +27,8 @@ import { renderApp, renderHeaderActions } from '.'; describe('renderApp', () => { const kibanaDeps = { - params: coreMock.createAppMountParameters(), core: coreMock.createStart(), + params: coreMock.createAppMountParameters(), plugins: { charts: chartPluginMock.createStartContract(), data: dataPluginMock.createStartContract(), diff --git a/x-pack/plugins/enterprise_search/public/applications/index.tsx b/x-pack/plugins/enterprise_search/public/applications/index.tsx index 40c3d8bdaf105..6c07c49292df1 100644 --- a/x-pack/plugins/enterprise_search/public/applications/index.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/index.tsx @@ -37,10 +37,26 @@ import { mountLicensingLogic } from './shared/licensing'; export const renderApp = ( App: React.FC, - { params, core, plugins }: { params: AppMountParameters; core: CoreStart; plugins: PluginsStart }, + { + params, + core, + plugins, + isSidebarEnabled = true, + }: { + core: CoreStart; + isSidebarEnabled: boolean; + params: AppMountParameters; + plugins: PluginsStart; + }, { config, data }: { config: ClientConfigType; data: ClientData } ) => { - const { publicUrl, errorConnectingMessage, ...initialData } = data; + const { access, features, publicUrl, errorConnectingMessage, readOnlyMode, ...initialData } = + data; + const { history } = params; + const { application, chrome, http, uiSettings } = core; + const { capabilities, navigateToUrl } = application; + const { charts, cloud, guidedOnboarding, lens, security } = plugins; + const entCloudHost = getCloudEnterpriseSearchHost(plugins.cloud); externalUrl.enterpriseSearchUrl = publicUrl || entCloudHost || config.host || ''; @@ -48,44 +64,46 @@ export const renderApp = ( hasAppSearchAccess: false, hasWorkplaceSearchAccess: false, }; - const productAccess = data.access || noProductAccess; - const productFeatures = data.features ?? { ...DEFAULT_PRODUCT_FEATURES }; + + const productAccess = access || noProductAccess; + const productFeatures = features ?? { ...DEFAULT_PRODUCT_FEATURES }; const EmptyContext: FC = ({ children }) => <>{children}; - const CloudContext = plugins.cloud?.CloudContextProvider || EmptyContext; + const CloudContext = cloud?.CloudContextProvider || EmptyContext; resetContext({ createStore: true }); const store = getContext().store; const unmountKibanaLogic = mountKibanaLogic({ - application: core.application, - capabilities: core.application.capabilities, + application, + capabilities, + charts, + cloud, config, data: plugins.data, - lens: plugins.lens, + guidedOnboarding, + history, + isSidebarEnabled, + lens, + navigateToUrl, productAccess, productFeatures, - charts: plugins.charts, - cloud: plugins.cloud, - uiSettings: core.uiSettings, - guidedOnboarding: plugins.guidedOnboarding, - history: params.history, - navigateToUrl: core.application.navigateToUrl, - security: plugins.security, - setBreadcrumbs: core.chrome.setBreadcrumbs, - setChromeIsVisible: core.chrome.setIsVisible, - setDocTitle: core.chrome.docTitle.change, renderHeaderActions: (HeaderActions) => params.setHeaderActionMenu((el) => renderHeaderActions(HeaderActions, store, el)), + security, + setBreadcrumbs: chrome.setBreadcrumbs, + setChromeIsVisible: chrome.setIsVisible, + setDocTitle: chrome.docTitle.change, + uiSettings, }); const unmountLicensingLogic = mountLicensingLogic({ - license$: plugins.licensing.license$, canManageLicense: core.application.capabilities.management?.stack?.license_management, + license$: plugins.licensing.license$, }); const unmountHttpLogic = mountHttpLogic({ - http: core.http, errorConnectingMessage, - readOnlyMode: initialData.readOnlyMode, + http, + readOnlyMode, }); const unmountFlashMessagesLogic = mountFlashMessagesLogic(); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts index b7d264ba43e99..df35a2f651363 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts +++ b/x-pack/plugins/enterprise_search/public/applications/shared/kibana/kibana_logic.ts @@ -33,27 +33,26 @@ type RequiredFieldsOnly = { }; interface KibanaLogicProps { application: ApplicationStart; - config: ClientConfigType; - productAccess: ProductAccess; - productFeatures: ProductFeatures; - // Kibana core capabilities: Capabilities; + charts: ChartsPluginStart; + cloud?: CloudSetup; + config: ClientConfigType; data: DataPublicPluginStart; + guidedOnboarding: GuidedOnboardingPluginStart; history: ScopedHistory; + isSidebarEnabled: boolean; lens: LensPublicStart; navigateToUrl: RequiredFieldsOnly; + productAccess: ProductAccess; + productFeatures: ProductFeatures; + renderHeaderActions(HeaderActions: FC): void; + security: SecurityPluginStart; setBreadcrumbs(crumbs: ChromeBreadcrumb[]): void; setChromeIsVisible(isVisible: boolean): void; setDocTitle(title: string): void; - renderHeaderActions(HeaderActions: FC): void; - // Required plugins - charts: ChartsPluginStart; - guidedOnboarding: GuidedOnboardingPluginStart; - security: SecurityPluginStart; uiSettings: IUiSettingsClient; - // Optional plugins - cloud?: CloudSetup; } + export interface KibanaValues extends Omit { cloud: Partial; data: DataPublicPluginStart; @@ -73,6 +72,7 @@ export const KibanaLogic = kea>({ data: [props.data, {}], guidedOnboarding: [props.guidedOnboarding, {}], history: [props.history, {}], + isSidebarEnabled: [props.isSidebarEnabled, {}], lens: [props.lens, {}], navigateToUrl: [ (url: string, options?: CreateHrefOptions) => { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx index dcb343a2beec4..a8a484b166707 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.test.tsx @@ -35,7 +35,11 @@ describe('useEnterpriseSearchContentNav', () => { it('returns an array of top-level Enterprise Search nav items', () => { const fullProductAccess: ProductAccess = DEFAULT_PRODUCT_ACCESS; - setMockValues({ productAccess: fullProductAccess, productFeatures: DEFAULT_PRODUCT_FEATURES }); + setMockValues({ + isSidebarEnabled: true, + productAccess: fullProductAccess, + productFeatures: DEFAULT_PRODUCT_FEATURES, + }); expect(useEnterpriseSearchNav()).toEqual([ { @@ -48,9 +52,9 @@ describe('useEnterpriseSearchContentNav', () => { name: 'Elasticsearch', }, { + href: '/app/enterprise_search/search_experiences', id: 'searchExperiences', name: 'Search Experiences', - href: '/app/enterprise_search/search_experiences', }, ], name: 'Overview', @@ -74,12 +78,11 @@ describe('useEnterpriseSearchContentNav', () => { }, { id: 'applications', - name: 'Applications', items: [ { + href: '/app/enterprise_search/content/engines', id: 'searchApplications', name: 'Search Applications', - href: '/app/enterprise_search/content/engines', }, { href: '/app/enterprise_search/analytics', @@ -87,6 +90,7 @@ describe('useEnterpriseSearchContentNav', () => { name: 'Behavioral Analytics', }, ], + name: 'Applications', }, { id: 'standaloneExperiences', @@ -114,7 +118,11 @@ describe('useEnterpriseSearchContentNav', () => { hasWorkplaceSearchAccess: false, }; - setMockValues({ productAccess: noProductAccess, productFeatures: DEFAULT_PRODUCT_FEATURES }); + setMockValues({ + isSidebarEnabled: true, + productAccess: noProductAccess, + productFeatures: DEFAULT_PRODUCT_FEATURES, + }); mockKibanaValues.uiSettings.get.mockReturnValue(false); const esNav = useEnterpriseSearchNav(); @@ -130,6 +138,7 @@ describe('useEnterpriseSearchContentNav', () => { }; setMockValues({ + isSidebarEnabled: true, productAccess: workplaceSearchProductAccess, productFeatures: DEFAULT_PRODUCT_FEATURES, }); @@ -157,6 +166,7 @@ describe('useEnterpriseSearchContentNav', () => { }; setMockValues({ + isSidebarEnabled: true, productAccess: appSearchProductAccess, productFeatures: DEFAULT_PRODUCT_FEATURES, }); @@ -183,6 +193,7 @@ describe('useEnterpriseSearchEngineNav', () => { jest.clearAllMocks(); mockKibanaValues.uiSettings.get.mockReturnValue(true); setMockValues({ + isSidebarEnabled: true, productAccess: DEFAULT_PRODUCT_ACCESS, productFeatures: DEFAULT_PRODUCT_FEATURES, }); @@ -200,9 +211,9 @@ describe('useEnterpriseSearchEngineNav', () => { name: 'Elasticsearch', }, { + href: '/app/enterprise_search/search_experiences', id: 'searchExperiences', name: 'Search Experiences', - href: '/app/enterprise_search/search_experiences', }, ], name: 'Overview', @@ -225,12 +236,11 @@ describe('useEnterpriseSearchEngineNav', () => { }, { id: 'applications', - name: 'Applications', items: [ { + href: '/app/enterprise_search/content/engines', id: 'searchApplications', name: 'Search Applications', - href: '/app/enterprise_search/content/engines', }, { href: '/app/enterprise_search/analytics', @@ -238,6 +248,7 @@ describe('useEnterpriseSearchEngineNav', () => { name: 'Behavioral Analytics', }, ], + name: 'Applications', }, { id: 'standaloneExperiences', @@ -346,9 +357,9 @@ describe('useEnterpriseSearchAnalyticsNav', () => { name: 'Elasticsearch', }, { + href: '/app/enterprise_search/search_experiences', id: 'searchExperiences', name: 'Search Experiences', - href: '/app/enterprise_search/search_experiences', }, ], name: 'Overview', @@ -366,7 +377,6 @@ describe('useEnterpriseSearchAnalyticsNav', () => { }, { id: 'applications', - name: 'Applications', items: [ { href: '/app/enterprise_search/content/engines', @@ -379,6 +389,7 @@ describe('useEnterpriseSearchAnalyticsNav', () => { name: 'Behavioral Analytics', }, ], + name: 'Applications', }, { id: 'standaloneExperiences', @@ -400,7 +411,9 @@ describe('useEnterpriseSearchAnalyticsNav', () => { beforeEach(() => { jest.clearAllMocks(); - setMockValues({}); + setMockValues({ + isSidebarEnabled: true, + }); }); it('returns basic nav all params are empty', () => { diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx index 7fbc354ff725f..2063021dc5323 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/nav.tsx @@ -30,7 +30,8 @@ import { KibanaLogic } from '../kibana'; import { generateNavLink } from './nav_link_helpers'; export const useEnterpriseSearchNav = () => { - const { productAccess, productFeatures } = useValues(KibanaLogic); + const { isSidebarEnabled, productAccess, productFeatures } = useValues(KibanaLogic); + if (!isSidebarEnabled) return undefined; const navItems: Array> = [ { @@ -174,6 +175,7 @@ export const useEnterpriseSearchNav = () => { export const useEnterpriseSearchEngineNav = (engineName?: string, isEmptyState?: boolean) => { const navItems = useEnterpriseSearchNav(); + if (!navItems) return undefined; if (!engineName) return navItems; const applicationsItem = navItems.find((item) => item.id === 'applications'); if (!applicationsItem || !applicationsItem.items) return navItems; @@ -255,6 +257,9 @@ export const useEnterpriseSearchAnalyticsNav = ( } ) => { const navItems = useEnterpriseSearchNav(); + + if (!navItems) return undefined; + const applicationsNav = navItems.find((item) => item.id === 'applications'); const analyticsNav = applicationsNav?.items?.find((item) => item.id === 'analyticsCollections'); diff --git a/x-pack/plugins/enterprise_search/public/applications/shared/layout/page_template.tsx b/x-pack/plugins/enterprise_search/public/applications/shared/layout/page_template.tsx index 4793d11b56c76..333d4d5f33b9a 100644 --- a/x-pack/plugins/enterprise_search/public/applications/shared/layout/page_template.tsx +++ b/x-pack/plugins/enterprise_search/public/applications/shared/layout/page_template.tsx @@ -35,13 +35,13 @@ import './page_template.scss'; export type PageTemplateProps = KibanaPageTemplateProps & { customPageSections?: boolean; // If false, automatically wraps children in an EuiPageSection + emptyState?: React.ReactNode; hideFlashMessages?: boolean; isLoading?: boolean; - emptyState?: React.ReactNode; - setPageChrome?: React.ReactNode; // Used by product-specific page templates pageChrome?: BreadcrumbTrail; pageViewTelemetry?: string; + setPageChrome?: React.ReactNode; }; export const EnterpriseSearchPageTemplateWrapper: React.FC = ({ @@ -73,7 +73,11 @@ export const EnterpriseSearchPageTemplateWrapper: React.FC = ), }} isEmptyState={isEmptyState && !isLoading} - solutionNav={solutionNav ? { icon: 'logoEnterpriseSearch', ...solutionNav } : undefined} + solutionNav={ + solutionNav && solutionNav.items + ? { icon: 'logoEnterpriseSearch', ...solutionNav } + : undefined + } > {setPageChrome} {readOnlyMode && ( diff --git a/x-pack/plugins/enterprise_search/public/index.ts b/x-pack/plugins/enterprise_search/public/index.ts index b24616fc4b3d8..8dc84c6934e42 100644 --- a/x-pack/plugins/enterprise_search/public/index.ts +++ b/x-pack/plugins/enterprise_search/public/index.ts @@ -12,3 +12,5 @@ import { EnterpriseSearchPlugin } from './plugin'; export const plugin = (initializerContext: PluginInitializerContext) => { return new EnterpriseSearchPlugin(initializerContext); }; + +export type { EnterpriseSearchPublicSetup, EnterpriseSearchPublicStart } from './plugin'; diff --git a/x-pack/plugins/enterprise_search/public/plugin.ts b/x-pack/plugins/enterprise_search/public/plugin.ts index 0c732495ab416..c4612fa27a428 100644 --- a/x-pack/plugins/enterprise_search/public/plugin.ts +++ b/x-pack/plugins/enterprise_search/public/plugin.ts @@ -38,10 +38,13 @@ import { ClientConfigType, InitialAppData } from '../common/types'; import { docLinks } from './applications/shared/doc_links'; export interface ClientData extends InitialAppData { - publicUrl?: string; errorConnectingMessage?: string; + publicUrl?: string; } +export type EnterpriseSearchPublicSetup = ReturnType; +export type EnterpriseSearchPublicStart = ReturnType; + interface PluginsSetup { cloud?: CloudSetup; home?: HomePublicPluginSetup; @@ -49,8 +52,8 @@ interface PluginsSetup { } export interface PluginsStart { - cloud?: CloudSetup & CloudStart; charts: ChartsPluginStart; + cloud?: CloudSetup & CloudStart; data: DataPublicPluginStart; guidedOnboarding: GuidedOnboardingPluginStart; lens: LensPublicStart; @@ -60,23 +63,63 @@ export interface PluginsStart { export class EnterpriseSearchPlugin implements Plugin { private config: ClientConfigType; - private hasInitialized: boolean = false; - private data: ClientData = {} as ClientData; constructor(initializerContext: PluginInitializerContext) { this.config = initializerContext.config.get(); } + private data: ClientData = {} as ClientData; + + private async getInitialData(http: HttpSetup) { + if (!this.config.host && this.config.canDeployEntSearch) return; // No API to call + if (this.hasInitialized) return; // We've already made an initial call + + try { + this.data = await http.get('/internal/enterprise_search/config_data'); + this.hasInitialized = true; + } catch (e) { + this.data.errorConnectingMessage = `${e.response.status} ${e.message}`; + } + } + + private async getKibanaDeps( + core: CoreSetup, + params: AppMountParameters, + cloudSetup?: CloudSetup + ) { + // Helper for using start dependencies on mount (instead of setup dependencies) + // and for grouping Kibana-related args together (vs. plugin-specific args) + const [coreStart, pluginsStart] = await core.getStartServices(); + const cloud = + cloudSetup && (pluginsStart as PluginsStart).cloud + ? { ...cloudSetup, ...(pluginsStart as PluginsStart).cloud } + : undefined; + const plugins = { ...pluginsStart, cloud } as PluginsStart; + + coreStart.chrome + .getChromeStyle$() + .subscribe((style) => (this.isSidebarEnabled = style === 'classic')); + + return { core: coreStart, isSidebarEnabled: this.isSidebarEnabled, params, plugins }; + } + + private getPluginData() { + // Small helper for grouping plugin data related args together + return { config: this.config, data: this.data, isSidebarEnabled: this.isSidebarEnabled }; + } + + private hasInitialized: boolean = false; + private isSidebarEnabled = true; + public setup(core: CoreSetup, plugins: PluginsSetup) { const { cloud } = plugins; const { config } = this; core.application.register({ - id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID, - title: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAV_TITLE, - euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, appRoute: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, + id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID, mount: async (params: AppMountParameters) => { const kibanaDeps = await this.getKibanaDeps(core, params, cloud); const { chrome, http } = kibanaDeps.core; @@ -92,14 +135,14 @@ export class EnterpriseSearchPlugin implements Plugin { return renderApp(EnterpriseSearchOverview, kibanaDeps, pluginData); }, + title: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAV_TITLE, }); core.application.register({ - id: ENTERPRISE_SEARCH_CONTENT_PLUGIN.ID, - title: ENTERPRISE_SEARCH_CONTENT_PLUGIN.NAV_TITLE, - euiIconType: ENTERPRISE_SEARCH_CONTENT_PLUGIN.LOGO, appRoute: ENTERPRISE_SEARCH_CONTENT_PLUGIN.URL, category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + euiIconType: ENTERPRISE_SEARCH_CONTENT_PLUGIN.LOGO, + id: ENTERPRISE_SEARCH_CONTENT_PLUGIN.ID, mount: async (params: AppMountParameters) => { const kibanaDeps = await this.getKibanaDeps(core, params, cloud); const { chrome, http } = kibanaDeps.core; @@ -115,16 +158,14 @@ export class EnterpriseSearchPlugin implements Plugin { return renderApp(EnterpriseSearchContent, kibanaDeps, pluginData); }, + title: ENTERPRISE_SEARCH_CONTENT_PLUGIN.NAV_TITLE, }); core.application.register({ - id: ANALYTICS_PLUGIN.ID, - title: ANALYTICS_PLUGIN.NAME, - euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, - searchable: true, - navLinkStatus: AppNavLinkStatus.default, appRoute: ANALYTICS_PLUGIN.URL, category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, + id: ANALYTICS_PLUGIN.ID, mount: async (params: AppMountParameters) => { const kibanaDeps = await this.getKibanaDeps(core, params, cloud); const { chrome, http } = kibanaDeps.core; @@ -138,14 +179,16 @@ export class EnterpriseSearchPlugin implements Plugin { return renderApp(Analytics, kibanaDeps, pluginData); }, + navLinkStatus: AppNavLinkStatus.default, + searchable: true, + title: ANALYTICS_PLUGIN.NAME, }); core.application.register({ - id: ELASTICSEARCH_PLUGIN.ID, - title: ELASTICSEARCH_PLUGIN.NAME, - euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, appRoute: ELASTICSEARCH_PLUGIN.URL, category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, + id: ELASTICSEARCH_PLUGIN.ID, mount: async (params: AppMountParameters) => { const kibanaDeps = await this.getKibanaDeps(core, params, cloud); const { chrome, http } = kibanaDeps.core; @@ -159,15 +202,15 @@ export class EnterpriseSearchPlugin implements Plugin { return renderApp(Elasticsearch, kibanaDeps, pluginData); }, + title: ELASTICSEARCH_PLUGIN.NAME, }); if (config.canDeployEntSearch) { core.application.register({ - id: APP_SEARCH_PLUGIN.ID, - title: APP_SEARCH_PLUGIN.NAME, - euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, appRoute: APP_SEARCH_PLUGIN.URL, category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, + id: APP_SEARCH_PLUGIN.ID, mount: async (params: AppMountParameters) => { const kibanaDeps = await this.getKibanaDeps(core, params, cloud); const { chrome, http } = kibanaDeps.core; @@ -181,14 +224,14 @@ export class EnterpriseSearchPlugin implements Plugin { return renderApp(AppSearch, kibanaDeps, pluginData); }, + title: APP_SEARCH_PLUGIN.NAME, }); core.application.register({ - id: WORKPLACE_SEARCH_PLUGIN.ID, - title: WORKPLACE_SEARCH_PLUGIN.NAME, - euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, appRoute: WORKPLACE_SEARCH_PLUGIN.URL, category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, + id: WORKPLACE_SEARCH_PLUGIN.ID, mount: async (params: AppMountParameters) => { const kibanaDeps = await this.getKibanaDeps(core, params, cloud); const { chrome, http } = kibanaDeps.core; @@ -205,15 +248,15 @@ export class EnterpriseSearchPlugin implements Plugin { return renderApp(WorkplaceSearch, kibanaDeps, pluginData); }, + title: WORKPLACE_SEARCH_PLUGIN.NAME, }); } core.application.register({ - id: SEARCH_EXPERIENCES_PLUGIN.ID, - title: SEARCH_EXPERIENCES_PLUGIN.NAME, - euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, appRoute: SEARCH_EXPERIENCES_PLUGIN.URL, category: DEFAULT_APP_CATEGORIES.enterpriseSearch, + euiIconType: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.LOGO, + id: SEARCH_EXPERIENCES_PLUGIN.ID, mount: async (params: AppMountParameters) => { const kibanaDeps = await this.getKibanaDeps(core, params, cloud); const { chrome, http } = kibanaDeps.core; @@ -227,68 +270,69 @@ export class EnterpriseSearchPlugin implements Plugin { return renderApp(SearchExperiences, kibanaDeps, pluginData); }, + title: SEARCH_EXPERIENCES_PLUGIN.NAME, }); if (plugins.home) { plugins.home.featureCatalogue.registerSolution({ - id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID, - title: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAME, - icon: 'logoEnterpriseSearch', description: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.DESCRIPTION, - path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, + icon: 'logoEnterpriseSearch', + id: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.ID, order: 100, + path: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.URL, + title: ENTERPRISE_SEARCH_OVERVIEW_PLUGIN.NAME, }); plugins.home.featureCatalogue.register({ - id: ANALYTICS_PLUGIN.ID, - title: ANALYTICS_PLUGIN.NAME, - icon: 'appAnalytics', + category: 'data', description: ANALYTICS_PLUGIN.DESCRIPTION, + icon: 'appAnalytics', + id: ANALYTICS_PLUGIN.ID, path: ANALYTICS_PLUGIN.URL, - category: 'data', showOnHomePage: false, + title: ANALYTICS_PLUGIN.NAME, }); if (config.canDeployEntSearch) { plugins.home.featureCatalogue.register({ - id: APP_SEARCH_PLUGIN.ID, - title: APP_SEARCH_PLUGIN.NAME, - icon: 'appSearchApp', + category: 'data', description: APP_SEARCH_PLUGIN.DESCRIPTION, + icon: 'appSearchApp', + id: APP_SEARCH_PLUGIN.ID, path: APP_SEARCH_PLUGIN.URL, - category: 'data', showOnHomePage: false, + title: APP_SEARCH_PLUGIN.NAME, }); plugins.home.featureCatalogue.register({ - id: WORKPLACE_SEARCH_PLUGIN.ID, - title: WORKPLACE_SEARCH_PLUGIN.NAME, - icon: 'workplaceSearchApp', + category: 'data', description: WORKPLACE_SEARCH_PLUGIN.DESCRIPTION, + icon: 'workplaceSearchApp', + id: WORKPLACE_SEARCH_PLUGIN.ID, path: WORKPLACE_SEARCH_PLUGIN.URL, - category: 'data', showOnHomePage: false, + title: WORKPLACE_SEARCH_PLUGIN.NAME, }); } plugins.home.featureCatalogue.register({ - id: ELASTICSEARCH_PLUGIN.ID, - title: ELASTICSEARCH_PLUGIN.NAME, - icon: 'appElasticsearch', + category: 'data', description: ELASTICSEARCH_PLUGIN.DESCRIPTION, + icon: 'appElasticsearch', + id: ELASTICSEARCH_PLUGIN.ID, path: ELASTICSEARCH_PLUGIN.URL, - category: 'data', showOnHomePage: false, + title: ELASTICSEARCH_PLUGIN.NAME, }); plugins.home.featureCatalogue.register({ - id: SEARCH_EXPERIENCES_PLUGIN.ID, - title: SEARCH_EXPERIENCES_PLUGIN.NAME, - icon: 'logoEnterpriseSearch', + category: 'data', description: SEARCH_EXPERIENCES_PLUGIN.DESCRIPTION, + icon: 'logoEnterpriseSearch', + id: SEARCH_EXPERIENCES_PLUGIN.ID, path: SEARCH_EXPERIENCES_PLUGIN.URL, - category: 'data', showOnHomePage: false, + title: SEARCH_EXPERIENCES_PLUGIN.NAME, }); } } @@ -300,38 +344,4 @@ export class EnterpriseSearchPlugin implements Plugin { } public stop() {} - - private async getKibanaDeps( - core: CoreSetup, - params: AppMountParameters, - cloudSetup?: CloudSetup - ) { - // Helper for using start dependencies on mount (instead of setup dependencies) - // and for grouping Kibana-related args together (vs. plugin-specific args) - const [coreStart, pluginsStart] = await core.getStartServices(); - const cloud = - cloudSetup && (pluginsStart as PluginsStart).cloud - ? { ...cloudSetup, ...(pluginsStart as PluginsStart).cloud } - : undefined; - const plugins = { ...pluginsStart, cloud } as PluginsStart; - - return { params, core: coreStart, plugins }; - } - - private getPluginData() { - // Small helper for grouping plugin data related args together - return { config: this.config, data: this.data }; - } - - private async getInitialData(http: HttpSetup) { - if (!this.config.host && this.config.canDeployEntSearch) return; // No API to call - if (this.hasInitialized) return; // We've already made an initial call - - try { - this.data = await http.get('/internal/enterprise_search/config_data'); - this.hasInitialized = true; - } catch (e) { - this.data.errorConnectingMessage = `${e.response.status} ${e.message}`; - } - } } diff --git a/x-pack/plugins/serverless_search/.gitignore b/x-pack/plugins/serverless_search/.gitignore new file mode 100644 index 0000000000000..c3dca1b96fcc2 --- /dev/null +++ b/x-pack/plugins/serverless_search/.gitignore @@ -0,0 +1,2 @@ +/build +/target diff --git a/x-pack/plugins/serverless_search/README.mdx b/x-pack/plugins/serverless_search/README.mdx new file mode 100755 index 0000000000000..0b89338e5cae5 --- /dev/null +++ b/x-pack/plugins/serverless_search/README.mdx @@ -0,0 +1,3 @@ +# Serverless Search project plugin + +This plugin contains configuration and code used to create a Serverless Search project. It leverages universal configuration and other APIs in the [`serverless`](../serverless/README.mdx) plugin to configure Kibana. \ No newline at end of file diff --git a/x-pack/plugins/serverless_search/common/index.ts b/x-pack/plugins/serverless_search/common/index.ts new file mode 100644 index 0000000000000..539748f2cea38 --- /dev/null +++ b/x-pack/plugins/serverless_search/common/index.ts @@ -0,0 +1,9 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const PLUGIN_ID = 'serverlessSearch'; +export const PLUGIN_NAME = 'serverlessSearch'; diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc new file mode 100644 index 0000000000000..b548823567ce0 --- /dev/null +++ b/x-pack/plugins/serverless_search/kibana.jsonc @@ -0,0 +1,23 @@ +{ + "type": "plugin", + "id": "@kbn/serverless-search", + "owner": "@elastic/appex-sharedux", + "description": "Serverless customizations for search.", + "plugin": { + "id": "serverlessSearch", + "server": true, + "browser": true, + "configPath": [ + "xpack", + "serverless", + "search" + ], + "requiredPlugins": [ + "serverless", + "enterpriseSearch", + "management" + ], + "optionalPlugins": [], + "requiredBundles": [] + } +} diff --git a/x-pack/plugins/serverless_search/package.json b/x-pack/plugins/serverless_search/package.json new file mode 100644 index 0000000000000..b7820231076ee --- /dev/null +++ b/x-pack/plugins/serverless_search/package.json @@ -0,0 +1,11 @@ +{ + "name": "@kbn/serverless-search", + "version": "1.0.0", + "license": "Elastic License 2.0", + "private": true, + "scripts": { + "build": "yarn plugin-helpers build", + "plugin-helpers": "node ../../../scripts/plugin_helpers", + "kbn": "node ../../../scripts/kbn" + } +} diff --git a/x-pack/plugins/serverless_search/public/index.ts b/x-pack/plugins/serverless_search/public/index.ts new file mode 100644 index 0000000000000..5031ccc61d1ac --- /dev/null +++ b/x-pack/plugins/serverless_search/public/index.ts @@ -0,0 +1,16 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ServerlessSearchPlugin } from './plugin'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. +export function plugin() { + return new ServerlessSearchPlugin(); +} + +export type { ServerlessSearchPluginSetup, ServerlessSearchPluginStart } from './types'; diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts new file mode 100644 index 0000000000000..62a83cff6f477 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -0,0 +1,34 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { + ServerlessSearchPluginSetup, + ServerlessSearchPluginSetupDependencies, + ServerlessSearchPluginStart, + ServerlessSearchPluginStartDependencies, +} from './types'; + +export class ServerlessSearchPlugin + implements Plugin +{ + public setup( + _core: CoreSetup, + _setupDeps: ServerlessSearchPluginSetupDependencies + ): ServerlessSearchPluginSetup { + return {}; + } + + public start( + _core: CoreStart, + _startDeps: ServerlessSearchPluginStartDependencies + ): ServerlessSearchPluginStart { + return {}; + } + + public stop() {} +} diff --git a/x-pack/plugins/serverless_search/public/types.ts b/x-pack/plugins/serverless_search/public/types.ts new file mode 100644 index 0000000000000..ad66e6df85c74 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/types.ts @@ -0,0 +1,31 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; +import { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public'; +import { + EnterpriseSearchPublicSetup, + EnterpriseSearchPublicStart, +} from '@kbn/enterprise-search-plugin/public'; + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface ServerlessSearchPluginSetup {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface ServerlessSearchPluginStart {} + +export interface ServerlessSearchPluginSetupDependencies { + enterpriseSearch: EnterpriseSearchPublicSetup; + management: ManagementSetup; + serverless: ServerlessPluginSetup; +} + +export interface ServerlessSearchPluginStartDependencies { + enterpriseSearch: EnterpriseSearchPublicStart; + management: ManagementStart; + serverless: ServerlessPluginStart; +} diff --git a/x-pack/plugins/serverless_search/server/config.ts b/x-pack/plugins/serverless_search/server/config.ts new file mode 100644 index 0000000000000..546c594aaabfb --- /dev/null +++ b/x-pack/plugins/serverless_search/server/config.ts @@ -0,0 +1,23 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; +import { PluginConfigDescriptor } from '@kbn/core/server'; + +export * from './types'; + +const configSchema = schema.object({ + enabled: schema.boolean({ defaultValue: false }), +}); + +type ConfigType = TypeOf; + +export const config: PluginConfigDescriptor = { + schema: configSchema, +}; + +export type ServerlessSearchConfig = TypeOf; diff --git a/x-pack/plugins/serverless_search/server/index.ts b/x-pack/plugins/serverless_search/server/index.ts new file mode 100644 index 0000000000000..90e0b170d4a71 --- /dev/null +++ b/x-pack/plugins/serverless_search/server/index.ts @@ -0,0 +1,20 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PluginInitializerContext } from '@kbn/core/server'; + +import { ServerlessSearchPlugin } from './plugin'; +export { config } from './config'; + +// This exports static code and TypeScript types, +// as well as, Kibana Platform `plugin()` initializer. + +export function plugin(initializerContext: PluginInitializerContext) { + return new ServerlessSearchPlugin(initializerContext); +} + +export type { ServerlessSearchPluginSetup, ServerlessSearchPluginStart } from './types'; diff --git a/x-pack/plugins/serverless_search/server/plugin.ts b/x-pack/plugins/serverless_search/server/plugin.ts new file mode 100644 index 0000000000000..99d9bf01da0df --- /dev/null +++ b/x-pack/plugins/serverless_search/server/plugin.ts @@ -0,0 +1,26 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { PluginInitializerContext, Plugin } from '@kbn/core/server'; + +import { ServerlessSearchPluginSetup, ServerlessSearchPluginStart } from './types'; + +export class ServerlessSearchPlugin + implements Plugin +{ + constructor(_initializerContext: PluginInitializerContext) {} + + public setup() { + return {}; + } + + public start() { + return {}; + } + + public stop() {} +} diff --git a/x-pack/plugins/serverless_search/server/types.ts b/x-pack/plugins/serverless_search/server/types.ts new file mode 100644 index 0000000000000..6011e2eb60fa0 --- /dev/null +++ b/x-pack/plugins/serverless_search/server/types.ts @@ -0,0 +1,11 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface ServerlessSearchPluginSetup {} +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface ServerlessSearchPluginStart {} diff --git a/x-pack/plugins/serverless_search/tsconfig.json b/x-pack/plugins/serverless_search/tsconfig.json new file mode 100644 index 0000000000000..c8150e5a71926 --- /dev/null +++ b/x-pack/plugins/serverless_search/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "target/types" + }, + "include": [ + "index.ts", + "common/**/*.ts", + "public/**/*.ts", + "public/**/*.tsx", + "server/**/*.ts", + "../../../typings/**/*" + ], + "exclude": [ + "target/**/*" + ], + "kbn_references": [ + "@kbn/core", + "@kbn/config-schema", + "@kbn/enterprise-search-plugin", + "@kbn/management-plugin", + "@kbn/serverless", + ] +} diff --git a/yarn.lock b/yarn.lock index d8fe1cb566adc..4bdf5d8cfedf1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5025,6 +5025,10 @@ version "0.0.0" uid "" +"@kbn/serverless-search@link:x-pack/plugins/serverless_search": + version "0.0.0" + uid "" + "@kbn/serverless@link:x-pack/plugins/serverless": version "0.0.0" uid ""