[Search] Fix: serverless search connector types (#218842)

## Summary

Fixes bug introduced by: https://github.com/elastic/kibana/pull/213509
where serverless search & enterprise search could not load list of
available connector types from the connectors plugin. This was caused by
2 things in serverless, 1) the entire plugin was disabled and 2) the
plugin id was renamed.

Updated the `contentConnectors` plugin to have a `ui.enabled` config
value to override just disabling the management UI from being registered
for Serverless Search, while still allowing the plugin to be enabled.
And updated the usages of the `searchConnectors` plugin in
`enteprise_search` & `serverless_search` to account for it being renamed
to `contentConnectors`

Of note this bug would have been caught by FTRs, but they have been
skipped for being
[flakey](https://github.com/elastic/kibana/issues/203462) for some time,
and have proven [hard
fix](https://github.com/elastic/kibana/pull/205971) given the current UX
😔

### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
- [ ] [Flaky Test
Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was
used on any tests changed
This commit is contained in:
Rodney Norris 2025-04-23 15:51:06 -05:00 committed by GitHub
parent f15c96d6e8
commit e04e974134
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 34 additions and 14 deletions

View file

@ -139,4 +139,4 @@ xpack.searchSynonyms.enabled: true
xpack.searchQueryRules.enabled: false
## Search Connectors in stack management
xpack.contentConnectors.enabled: false
xpack.contentConnectors.ui.enabled: false

View file

@ -256,6 +256,7 @@ export default function ({ getService }: PluginFunctionalProviderContext) {
'xpack.cloud.serverless.project_type (string?)',
'xpack.cloud.serverless.orchestrator_target (string?)',
'xpack.cloud.onboarding.default_solution (string?)',
'xpack.contentConnectors.ui.enabled (boolean?)',
'xpack.discoverEnhanced.actions.exploreDataInChart.enabled (boolean?)',
'xpack.discoverEnhanced.actions.exploreDataInContextMenu.enabled (boolean?)',
'xpack.fleet.agents.enabled (boolean?)',

View file

@ -0,0 +1,10 @@
/*
* 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 interface ClientConfigType {
ui: { enabled: boolean };
}

View file

@ -8,6 +8,7 @@
import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public';
import { docLinks } from '@kbn/search-connectors/constants/doc_links';
import { ManagementAppMountParams } from '@kbn/management-plugin/public';
import { type ClientConfigType } from '../common/types/config';
import { getConnectorFullTypes, getConnectorTypes } from '../common/lib/connector_types';
import {
SearchConnectorsPluginSetup,
@ -29,10 +30,12 @@ export class SearchConnectorsPlugin
{
private readonly isServerless: boolean;
private readonly kibanaVersion: string;
private readonly config: ClientConfigType;
constructor(initializerContext: PluginInitializerContext) {
this.isServerless = initializerContext.env.packageInfo.buildFlavor === 'serverless';
this.kibanaVersion = initializerContext.env.packageInfo.version;
this.config = initializerContext.config.get<ClientConfigType>();
}
public setup(
@ -43,7 +46,7 @@ export class SearchConnectorsPlugin
const connectorTypes = getConnectorTypes(core.http.staticAssets);
const kibanaVersion = this.kibanaVersion;
if (this.isServerless === true) {
if (this.config.ui.enabled && this.isServerless === true) {
management.sections.section.data.registerApp({
id: PLUGIN_ID,
title: PLUGIN_NAME,

View file

@ -12,11 +12,17 @@ export * from './types';
const configSchema = schema.object({
enabled: schema.boolean({ defaultValue: true }),
ui: schema.object({
enabled: schema.boolean({ defaultValue: true }),
}),
});
type ConfigType = TypeOf<typeof configSchema>;
export const config: PluginConfigDescriptor<ConfigType> = {
exposeToBrowser: {
ui: true,
},
schema: configSchema,
};

View file

@ -34,7 +34,7 @@
"usageCollection",
"guidedOnboarding",
"console",
"searchConnectors",
"contentConnectors",
"searchNavigation",
"searchPlayground",
"embeddable",

View file

@ -39,6 +39,7 @@ describe('renderApp', () => {
params: coreMock.createAppMountParameters(),
plugins: {
charts: chartPluginMock.createStartContract(),
contentConnectors: searchConnectorsMock.createStart(),
data: dataPluginMock.createStartContract(),
guidedOnboarding: guidedOnboardingMock.createStart(),
indexManagement: {
@ -47,7 +48,6 @@ describe('renderApp', () => {
lens: lensPluginMock.createStartContract(),
licensing: licensingMock.createStart(),
navigation: navigationPluginMock.createStartContract(),
searchConnectors: searchConnectorsMock.createStart(),
security: securityMock.createStart(),
share: sharePluginMock.createStartContract(),
ml: mlPluginMock.createStartContract(),

View file

@ -82,7 +82,7 @@ export const renderApp = (
const store = getContext().store;
const indexMappingComponent = indexManagementPlugin?.getIndexMappingComponent({ history });
const connectorTypes = plugins.searchConnectors?.getConnectorTypes() || [];
const connectorTypes = plugins.contentConnectors?.getConnectorTypes() || [];
const unmountKibanaLogic = mountKibanaLogic({
application,

View file

@ -82,6 +82,7 @@ export interface PluginsStart {
charts?: ChartsPluginStart;
cloud?: CloudSetup & CloudStart;
console?: ConsolePluginStart;
contentConnectors?: SearchConnectorsPluginStart;
data?: DataPublicPluginStart;
fleet?: FleetStart;
guidedOnboarding?: GuidedOnboardingPluginStart;
@ -90,7 +91,6 @@ export interface PluginsStart {
licensing?: LicensingPluginStart;
ml?: MlPluginStart;
navigation: NavigationPublicPluginStart;
searchConnectors?: SearchConnectorsPluginStart;
searchNavigation?: SearchNavigationPluginStart;
searchPlayground?: SearchPlaygroundPluginStart;
security?: SecurityPluginStart;

View file

@ -100,7 +100,7 @@ export class EnterpriseSearchPlugin implements Plugin<void, void, PluginsSetup,
licensing,
guidedOnboarding,
cloud,
searchConnectors,
contentConnectors,
}: PluginsSetup
) {
this.globalConfigService.setup(elasticsearch.legacy.config$, cloud);
@ -317,7 +317,7 @@ export class EnterpriseSearchPlugin implements Plugin<void, void, PluginsSetup,
if (globalSearch) {
globalSearch.registerResultProvider(
getSearchResultProvider(config, searchConnectors?.getConnectorTypes() || [])
getSearchResultProvider(config, contentConnectors?.getConnectorTypes() || [])
);
globalSearch.registerResultProvider(getIndicesSearchResultProvider(http.staticAssets));
globalSearch.registerResultProvider(getConnectorsSearchResultProvider(http.staticAssets));

View file

@ -33,6 +33,7 @@ import type { ConfigType } from '.';
export interface PluginsSetup {
cloud?: CloudSetup;
contentConnectors?: SearchConnectorsPluginSetup;
customIntegrations?: CustomIntegrationsPluginSetup;
features: FeaturesPluginSetup;
globalSearch: GlobalSearchPluginSetup;
@ -40,7 +41,6 @@ export interface PluginsSetup {
licensing: LicensingPluginStart;
logsShared: LogsSharedPluginSetup;
ml?: MlPluginSetup;
searchConnectors?: SearchConnectorsPluginSetup;
security: SecurityPluginSetup;
usageCollection?: UsageCollectionSetup;
}

View file

@ -33,7 +33,7 @@
],
"optionalPlugins": [
"indexManagement",
"searchConnectors",
"contentConnectors",
"searchInferenceEndpoints",
"searchPlayground",
"usageCollection"

View file

@ -8,7 +8,7 @@
import { useKibanaServices } from '../use_kibana';
export const useConnectorTypes = () => {
const { searchConnectors } = useKibanaServices();
const { contentConnectors } = useKibanaServices();
return searchConnectors?.getConnectorTypes() || [];
return contentConnectors?.getConnectorTypes() || [];
};

View file

@ -18,7 +18,7 @@ export interface ServerlessSearchContext {
cloud: CloudStart;
console: ConsolePluginStart;
history: AppMountParameters['history'];
searchConnectors?: SearchConnectorsPluginStart;
contentConnectors?: SearchConnectorsPluginStart;
security: SecurityPluginStart;
share: SharePluginStart;
user?: AuthenticatedUser;

View file

@ -21,7 +21,7 @@ import { searchConnectorsMock } from '@kbn/content-connectors-plugin/public/plug
export const core = coreMock.createStart();
export const services = {
cloud: cloudMock.createStart(),
searchConnectors: searchConnectorsMock.createStart(),
contentConnectors: searchConnectorsMock.createStart(),
share: sharePluginMock.createStartContract(),
userProfile: userProfileMock.createWithSecurity(),
};