[Enterprise Search] Create search results provider (#155641)
## Summary This adds a global search provider for Enterprise Search results, returning the web crawler and connectors. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
120
x-pack/plugins/enterprise_search/common/connectors/connectors.ts
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
|
||||
export interface ConnectorServerSideDefinition {
|
||||
iconPath: string;
|
||||
isBeta: boolean;
|
||||
isNative: boolean;
|
||||
keywords: string[];
|
||||
name: string;
|
||||
serviceType: string;
|
||||
}
|
||||
|
||||
export const CONNECTOR_DEFINITIONS: ConnectorServerSideDefinition[] = [
|
||||
{
|
||||
iconPath: 'mongodb.svg',
|
||||
isBeta: false,
|
||||
isNative: true,
|
||||
keywords: ['mongo', 'mongodb', 'database', 'nosql', 'connector'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.mongodb.name', {
|
||||
defaultMessage: 'MongoDB',
|
||||
}),
|
||||
serviceType: 'mongodb',
|
||||
},
|
||||
{
|
||||
iconPath: 'mysql.svg',
|
||||
isBeta: false,
|
||||
isNative: true,
|
||||
keywords: ['mysql', 'sql', 'database', 'connector'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.mysql.name', {
|
||||
defaultMessage: 'MySQL',
|
||||
}),
|
||||
serviceType: 'mysql',
|
||||
},
|
||||
{
|
||||
iconPath: 'azure_blob_storage.svg',
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
keywords: ['cloud', 'azure', 'blob', 's3', 'connector'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.azureBlob.name', {
|
||||
defaultMessage: 'Azure Blob Storage',
|
||||
}),
|
||||
serviceType: 'azure_blob_storage',
|
||||
},
|
||||
{
|
||||
iconPath: 'google_cloud_storage.svg',
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
keywords: ['google', 'cloud', 'blob', 's3', 'connector'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.googleCloud.name', {
|
||||
defaultMessage: 'Google Cloud Storage',
|
||||
}),
|
||||
serviceType: 'google_cloud_storage',
|
||||
},
|
||||
{
|
||||
iconPath: 'mssql.svg',
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
keywords: ['mssql', 'microsoft', 'sql', 'database', 'connector'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.microsoftSQL.name', {
|
||||
defaultMessage: 'Microsoft SQL',
|
||||
}),
|
||||
serviceType: 'mssql',
|
||||
},
|
||||
{
|
||||
iconPath: 'network_drive.svg',
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
keywords: ['network', 'drive', 'file', 'directory', 'connector'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.networkDrive.name', {
|
||||
defaultMessage: 'Network drive',
|
||||
}),
|
||||
serviceType: 'network_drive',
|
||||
},
|
||||
{
|
||||
iconPath: 'oracle.svg',
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
keywords: ['oracle', 'sql', 'database', 'connector'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.oracle.name', {
|
||||
defaultMessage: 'Oracle',
|
||||
}),
|
||||
serviceType: 'oracle',
|
||||
},
|
||||
{
|
||||
iconPath: 'postgresql.svg',
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
keywords: ['postgresql', 'sql', 'database', 'connector'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.postgresql.name', {
|
||||
defaultMessage: 'Postgresql',
|
||||
}),
|
||||
serviceType: 'postgresql',
|
||||
},
|
||||
{
|
||||
iconPath: 's3.svg',
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
keywords: ['s3', 'cloud', 'amazon', 'connector'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.s3.name', {
|
||||
defaultMessage: 'S3',
|
||||
}),
|
||||
serviceType: 's3',
|
||||
},
|
||||
{
|
||||
iconPath: 'custom.svg',
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
keywords: ['custom', 'connector', 'code'],
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.customConnector.name', {
|
||||
defaultMessage: 'Customized connector',
|
||||
}),
|
||||
serviceType: '',
|
||||
},
|
||||
];
|
|
@ -26,6 +26,7 @@
|
|||
],
|
||||
"optionalPlugins": [
|
||||
"customIntegrations",
|
||||
"globalSearch",
|
||||
"home",
|
||||
"ml",
|
||||
"spaces",
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
import { INGESTION_METHOD_IDS } from '../../../../../common/constants';
|
||||
|
||||
import connectorLogo from '../../../../assets/enterprise_search_features/connector.svg';
|
||||
import connectorLogo from '../../../../assets/source_icons/connector.svg';
|
||||
|
||||
import crawlerLogo from '../../../../assets/enterprise_search_features/crawler.svg';
|
||||
import crawlerLogo from '../../../../assets/source_icons/crawler.svg';
|
||||
|
||||
import { UNIVERSAL_LANGUAGE_VALUE } from './constants';
|
||||
import { LanguageForOptimization } from './types';
|
||||
|
|
|
@ -5,137 +5,83 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
|
||||
import { CONNECTOR_ICONS } from '../../../../../assets/source_icons/native_connector_icons';
|
||||
import { CONNECTOR_DEFINITIONS } from '../../../../../../common/connectors/connectors';
|
||||
|
||||
import { docLinks } from '../../../../shared/doc_links';
|
||||
import { CONNECTOR_ICONS } from '../../../../shared/icons/connector_icons';
|
||||
|
||||
import { ConnectorDefinition } from './types';
|
||||
import { ConnectorClientSideDefinition } from './types';
|
||||
|
||||
export const CONNECTORS: ConnectorDefinition[] = [
|
||||
{
|
||||
docsUrl: docLinks.connectorsMongoDB,
|
||||
externalAuthDocsUrl: 'https://www.mongodb.com/docs/atlas/app-services/authentication/',
|
||||
externalDocsUrl: 'https://www.mongodb.com/docs/',
|
||||
icon: CONNECTOR_ICONS.mongodb,
|
||||
isBeta: false,
|
||||
isNative: true,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.mongodb.name', {
|
||||
defaultMessage: 'MongoDB',
|
||||
}),
|
||||
serviceType: 'mongodb',
|
||||
},
|
||||
{
|
||||
docsUrl: docLinks.connectorsMySQL,
|
||||
externalDocsUrl: 'https://dev.mysql.com/doc/',
|
||||
icon: CONNECTOR_ICONS.mysql,
|
||||
isBeta: false,
|
||||
isNative: true,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.mysql.name', {
|
||||
defaultMessage: 'MySQL',
|
||||
}),
|
||||
serviceType: 'mysql',
|
||||
},
|
||||
{
|
||||
export const CONNECTORS_DICT: Record<string, ConnectorClientSideDefinition> = {
|
||||
azure_blob_storage: {
|
||||
docsUrl: docLinks.connectorsAzureBlobStorage,
|
||||
externalAuthDocsUrl: 'https://learn.microsoft.com/azure/storage/common/authorize-data-access',
|
||||
externalDocsUrl: 'https://learn.microsoft.com/azure/storage/blobs/',
|
||||
icon: CONNECTOR_ICONS.azure_blob_storage,
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.azureBlob.name', {
|
||||
defaultMessage: 'Azure Blob Storage',
|
||||
}),
|
||||
serviceType: 'azure_blob_storage',
|
||||
},
|
||||
{
|
||||
custom: {
|
||||
docsUrl: docLinks.connectors,
|
||||
externalAuthDocsUrl: '',
|
||||
externalDocsUrl: '',
|
||||
icon: CONNECTOR_ICONS.custom,
|
||||
},
|
||||
google_cloud_storage: {
|
||||
docsUrl: docLinks.connectorsGoogleCloudStorage,
|
||||
externalAuthDocsUrl: 'https://cloud.google.com/storage/docs/authentication',
|
||||
externalDocsUrl: 'https://cloud.google.com/storage/docs',
|
||||
icon: CONNECTOR_ICONS.google_cloud_storage,
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.googleCloud.name', {
|
||||
defaultMessage: 'Google Cloud Storage',
|
||||
}),
|
||||
serviceType: 'google_cloud_storage',
|
||||
},
|
||||
{
|
||||
mongodb: {
|
||||
docsUrl: docLinks.connectorsMongoDB,
|
||||
externalAuthDocsUrl: 'https://www.mongodb.com/docs/atlas/app-services/authentication/',
|
||||
externalDocsUrl: 'https://www.mongodb.com/docs/',
|
||||
icon: CONNECTOR_ICONS.mongodb,
|
||||
},
|
||||
mssql: {
|
||||
docsUrl: docLinks.connectorsMicrosoftSQL,
|
||||
externalAuthDocsUrl:
|
||||
'https://learn.microsoft.com/sql/relational-databases/security/authentication-access/getting-started-with-database-engine-permissions',
|
||||
externalDocsUrl: 'https://learn.microsoft.com/sql/',
|
||||
icon: CONNECTOR_ICONS.microsoft_sql,
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.microsoftSQL.name', {
|
||||
defaultMessage: 'Microsoft SQL',
|
||||
}),
|
||||
serviceType: 'mssql',
|
||||
},
|
||||
{
|
||||
mysql: {
|
||||
docsUrl: docLinks.connectorsMySQL,
|
||||
externalDocsUrl: 'https://dev.mysql.com/doc/',
|
||||
icon: CONNECTOR_ICONS.mysql,
|
||||
},
|
||||
network_drive: {
|
||||
docsUrl: docLinks.connectorsNetworkDrive,
|
||||
externalAuthDocsUrl: '',
|
||||
externalDocsUrl: '',
|
||||
icon: CONNECTOR_ICONS.network_drive,
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.networkDrive.name', {
|
||||
defaultMessage: 'Network drive',
|
||||
}),
|
||||
serviceType: 'network_drive',
|
||||
},
|
||||
{
|
||||
oracle: {
|
||||
docsUrl: docLinks.connectorsOracle,
|
||||
externalAuthDocsUrl:
|
||||
'https://docs.oracle.com/en/database/oracle/oracle-database/19/dbseg/index.html',
|
||||
externalDocsUrl: 'https://docs.oracle.com/database/oracle/oracle-database/',
|
||||
icon: CONNECTOR_ICONS.oracle,
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.oracle.name', {
|
||||
defaultMessage: 'Oracle',
|
||||
}),
|
||||
serviceType: 'oracle',
|
||||
},
|
||||
{
|
||||
postgresql: {
|
||||
docsUrl: docLinks.connectorsPostgreSQL,
|
||||
externalAuthDocsUrl: 'https://www.postgresql.org/docs/15/auth-methods.html',
|
||||
externalDocsUrl: 'https://www.postgresql.org/docs/',
|
||||
icon: CONNECTOR_ICONS.postgresql,
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.postgresql.name', {
|
||||
defaultMessage: 'Postgresql',
|
||||
}),
|
||||
serviceType: 'postgresql',
|
||||
},
|
||||
{
|
||||
s3: {
|
||||
docsUrl: docLinks.connectorsS3,
|
||||
externalAuthDocsUrl: 'https://docs.aws.amazon.com/s3/index.html',
|
||||
externalDocsUrl: '',
|
||||
icon: CONNECTOR_ICONS.amazon_s3,
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.s3.name', {
|
||||
defaultMessage: 'S3',
|
||||
}),
|
||||
serviceType: 's3',
|
||||
},
|
||||
{
|
||||
docsUrl: docLinks.connectors,
|
||||
externalAuthDocsUrl: '',
|
||||
externalDocsUrl: '',
|
||||
icon: CONNECTOR_ICONS.custom,
|
||||
isBeta: true,
|
||||
isNative: false,
|
||||
name: i18n.translate('xpack.enterpriseSearch.content.nativeConnectors.customConnector.name', {
|
||||
defaultMessage: 'Custom connector',
|
||||
}),
|
||||
serviceType: '',
|
||||
},
|
||||
];
|
||||
};
|
||||
|
||||
export const CONNECTORS = CONNECTOR_DEFINITIONS.map((connector) => ({
|
||||
...connector,
|
||||
...(connector.serviceType && CONNECTORS_DICT[connector.serviceType]
|
||||
? CONNECTORS_DICT[connector.serviceType]
|
||||
: CONNECTORS_DICT.custom),
|
||||
}));
|
||||
|
||||
export const CUSTOM_CONNECTORS = CONNECTORS.filter(({ isNative }) => !isNative);
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
export interface ConnectorDefinition {
|
||||
import { ConnectorServerSideDefinition } from '../../../../../../common/connectors/connectors';
|
||||
|
||||
export interface ConnectorClientSideDefinition {
|
||||
docsUrl?: string;
|
||||
externalAuthDocsUrl?: string;
|
||||
externalDocsUrl: string;
|
||||
icon: string;
|
||||
isBeta: boolean;
|
||||
isNative: boolean;
|
||||
name: string;
|
||||
serviceType: string;
|
||||
}
|
||||
|
||||
export type ConnectorDefinition = ConnectorClientSideDefinition & ConnectorServerSideDefinition;
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* 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 azure_blob_storage from '../../../assets/source_icons/azure_blob_storage.svg';
|
||||
import custom from '../../../assets/source_icons/custom.svg';
|
||||
import google_cloud_storage from '../../../assets/source_icons/google_cloud_storage.svg';
|
||||
import mongodb from '../../../assets/source_icons/mongodb.svg';
|
||||
import microsoft_sql from '../../../assets/source_icons/mssql.svg';
|
||||
import mysql from '../../../assets/source_icons/mysql.svg';
|
||||
import network_drive from '../../../assets/source_icons/network_drive.svg';
|
||||
import oracle from '../../../assets/source_icons/oracle.svg';
|
||||
import postgresql from '../../../assets/source_icons/postgresql.svg';
|
||||
import amazon_s3 from '../../../assets/source_icons/s3.svg';
|
||||
|
||||
export const CONNECTOR_ICONS = {
|
||||
amazon_s3,
|
||||
azure_blob_storage,
|
||||
custom,
|
||||
google_cloud_storage,
|
||||
microsoft_sql,
|
||||
mongodb,
|
||||
mysql,
|
||||
network_drive,
|
||||
oracle,
|
||||
postgresql,
|
||||
};
|
Before Width: | Height: | Size: 864 B After Width: | Height: | Size: 864 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0; you may not use this file except in compliance with the Elastic License
|
||||
* 2.0.
|
||||
*/
|
||||
|
||||
import amazon_s3 from './amazon_s3.svg';
|
||||
import azure_blob_storage from './azure_blob_storage.svg';
|
||||
import custom from './custom.svg';
|
||||
import google_cloud_storage from './google_cloud_storage.svg';
|
||||
import microsoft_sql from './microsoft_sql.svg';
|
||||
import mongodb from './mongodb.svg';
|
||||
import mysql from './mysql.svg';
|
||||
import network_drive from './network_drive.svg';
|
||||
import oracle from './oracle.svg';
|
||||
import postgresql from './postgresql.svg';
|
||||
|
||||
export const CONNECTOR_ICONS = {
|
||||
amazon_s3,
|
||||
azure_blob_storage,
|
||||
custom,
|
||||
google_cloud_storage,
|
||||
microsoft_sql,
|
||||
mongodb,
|
||||
mysql,
|
||||
network_drive,
|
||||
oracle,
|
||||
postgresql,
|
||||
};
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
@ -588,9 +588,7 @@ export const registerEnterpriseSearchIntegrations = (
|
|||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: http.basePath.prepend(
|
||||
'/plugins/enterpriseSearch/assets/source_icons/microsoft_sql.svg'
|
||||
),
|
||||
src: http.basePath.prepend('/plugins/enterpriseSearch/assets/source_icons/mssql.svg'),
|
||||
},
|
||||
],
|
||||
shipper: 'enterprise_search',
|
||||
|
@ -651,7 +649,7 @@ export const registerEnterpriseSearchIntegrations = (
|
|||
icons: [
|
||||
{
|
||||
type: 'svg',
|
||||
src: http.basePath.prepend('/plugins/enterpriseSearch/assets/source_icons/amazon_s3.svg'),
|
||||
src: http.basePath.prepend('/plugins/enterpriseSearch/assets/source_icons/s3.svg'),
|
||||
},
|
||||
],
|
||||
shipper: 'enterprise_search',
|
||||
|
|
|
@ -18,6 +18,7 @@ import {
|
|||
import { CustomIntegrationsPluginSetup } from '@kbn/custom-integrations-plugin/server';
|
||||
import { DataPluginStart } from '@kbn/data-plugin/server/plugin';
|
||||
import { PluginSetupContract as FeaturesPluginSetup } from '@kbn/features-plugin/server';
|
||||
import { GlobalSearchPluginSetup } from '@kbn/global-search-plugin/server';
|
||||
import type { GuidedOnboardingPluginSetup } from '@kbn/guided-onboarding-plugin/server';
|
||||
import { InfraPluginSetup } from '@kbn/infra-plugin/server';
|
||||
import type { MlPluginSetup } from '@kbn/ml-plugin/server';
|
||||
|
@ -76,31 +77,34 @@ import { workplaceSearchTelemetryType } from './saved_objects/workplace_search/t
|
|||
|
||||
import { uiSettings as enterpriseSearchUISettings } from './ui_settings';
|
||||
|
||||
import { getSearchResultProvider } from './utils/search_result_provider';
|
||||
|
||||
import { ConfigType } from '.';
|
||||
|
||||
interface PluginsSetup {
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
security: SecurityPluginSetup;
|
||||
features: FeaturesPluginSetup;
|
||||
infra: InfraPluginSetup;
|
||||
customIntegrations?: CustomIntegrationsPluginSetup;
|
||||
ml?: MlPluginSetup;
|
||||
features: FeaturesPluginSetup;
|
||||
globalSearch: GlobalSearchPluginSetup;
|
||||
guidedOnboarding: GuidedOnboardingPluginSetup;
|
||||
infra: InfraPluginSetup;
|
||||
ml?: MlPluginSetup;
|
||||
security: SecurityPluginSetup;
|
||||
usageCollection?: UsageCollectionSetup;
|
||||
}
|
||||
|
||||
interface PluginsStart {
|
||||
spaces?: SpacesPluginStart;
|
||||
security: SecurityPluginStart;
|
||||
data: DataPluginStart;
|
||||
security: SecurityPluginStart;
|
||||
spaces?: SpacesPluginStart;
|
||||
}
|
||||
|
||||
export interface RouteDependencies {
|
||||
router: IRouter;
|
||||
config: ConfigType;
|
||||
log: Logger;
|
||||
enterpriseSearchRequestHandler: IEnterpriseSearchRequestHandler;
|
||||
getSavedObjectsService?(): SavedObjectsServiceStart;
|
||||
log: Logger;
|
||||
ml?: MlPluginSetup;
|
||||
router: IRouter;
|
||||
}
|
||||
|
||||
export class EnterpriseSearchPlugin implements Plugin {
|
||||
|
@ -118,6 +122,7 @@ export class EnterpriseSearchPlugin implements Plugin {
|
|||
usageCollection,
|
||||
security,
|
||||
features,
|
||||
globalSearch,
|
||||
infra,
|
||||
customIntegrations,
|
||||
ml,
|
||||
|
@ -284,6 +289,14 @@ export class EnterpriseSearchPlugin implements Plugin {
|
|||
if (config.hasNativeConnectors) {
|
||||
guidedOnboarding.registerGuideConfig(databaseSearchGuideId, databaseSearchGuideConfig);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register our integrations in the global search bar
|
||||
*/
|
||||
|
||||
if (globalSearch) {
|
||||
globalSearch.registerResultProvider(getSearchResultProvider(http.basePath, config));
|
||||
}
|
||||
}
|
||||
|
||||
public start() {}
|
||||
|
|
|
@ -0,0 +1,196 @@
|
|||
/*
|
||||
* 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 { NEVER } from 'rxjs';
|
||||
import { TestScheduler } from 'rxjs/testing';
|
||||
|
||||
import { ENTERPRISE_SEARCH_CONTENT_PLUGIN } from '../../common/constants';
|
||||
|
||||
import { getSearchResultProvider } from './search_result_provider';
|
||||
|
||||
const getTestScheduler = () => {
|
||||
return new TestScheduler((actual, expected) => {
|
||||
return expect(actual).toEqual(expected);
|
||||
});
|
||||
};
|
||||
|
||||
describe('Enterprise Search search provider', () => {
|
||||
const basePathMock = {
|
||||
prepend: (input: string) => `/kbn${input}`,
|
||||
} as any;
|
||||
|
||||
const crawlerResult = {
|
||||
icon: '/kbn/plugins/enterpriseSearch/assets/source_icons/crawler.svg',
|
||||
id: 'elastic-crawler',
|
||||
score: 75,
|
||||
title: 'Elastic Web Crawler',
|
||||
type: 'Enterprise Search',
|
||||
url: {
|
||||
path: `${ENTERPRISE_SEARCH_CONTENT_PLUGIN.URL}/search_indices/new_index/crawler`,
|
||||
prependBasePath: true,
|
||||
},
|
||||
};
|
||||
|
||||
const mongoResult = {
|
||||
icon: '/kbn/plugins/enterpriseSearch/assets/source_icons/mongodb.svg',
|
||||
id: 'mongodb',
|
||||
score: 75,
|
||||
title: 'MongoDB',
|
||||
type: 'Enterprise Search',
|
||||
url: {
|
||||
path: `${ENTERPRISE_SEARCH_CONTENT_PLUGIN.URL}/search_indices/new_index/connector?service_type=mongodb`,
|
||||
prependBasePath: true,
|
||||
},
|
||||
};
|
||||
|
||||
const searchResultProvider = getSearchResultProvider(basePathMock, {
|
||||
hasConnectors: true,
|
||||
hasWebCrawler: true,
|
||||
} as any);
|
||||
|
||||
beforeEach(() => {});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
describe('find', () => {
|
||||
it('returns formatted results', () => {
|
||||
getTestScheduler().run(({ expectObservable }) => {
|
||||
expectObservable(
|
||||
searchResultProvider.find(
|
||||
{ term: 'crawler' },
|
||||
{ aborted$: NEVER, maxResults: 100, preference: '' },
|
||||
{} as any
|
||||
)
|
||||
).toBe('(a|)', {
|
||||
a: [crawlerResult],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns everything on empty string', () => {
|
||||
getTestScheduler().run(({ expectObservable }) => {
|
||||
expectObservable(
|
||||
searchResultProvider.find(
|
||||
{ term: '' },
|
||||
{ aborted$: NEVER, maxResults: 100, preference: '' },
|
||||
{} as any
|
||||
)
|
||||
).toBe('(a|)', {
|
||||
a: expect.arrayContaining([
|
||||
{ ...crawlerResult, score: 80 },
|
||||
{ ...mongoResult, score: 80 },
|
||||
]),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('respect maximum results', () => {
|
||||
getTestScheduler().run(({ expectObservable }) => {
|
||||
expectObservable(
|
||||
searchResultProvider.find(
|
||||
{ term: '' },
|
||||
{ aborted$: NEVER, maxResults: 1, preference: '' },
|
||||
{} as any
|
||||
)
|
||||
).toBe('(a|)', {
|
||||
a: [{ ...crawlerResult, score: 80 }],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('omits crawler if config has crawler disabled', () => {
|
||||
const searchProvider = getSearchResultProvider(basePathMock, {
|
||||
hasConnectors: true,
|
||||
hasWebCrawler: false,
|
||||
} as any);
|
||||
getTestScheduler().run(({ expectObservable }) => {
|
||||
expectObservable(
|
||||
searchProvider.find(
|
||||
{ term: '' },
|
||||
{ aborted$: NEVER, maxResults: 100, preference: '' },
|
||||
{} as any
|
||||
)
|
||||
).toBe('(a|)', {
|
||||
a: expect.not.arrayContaining([{ ...crawlerResult, score: 80 }]),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('omits connectors if config has connectors disabled', () => {
|
||||
const searchProvider = getSearchResultProvider(basePathMock, {
|
||||
hasConnectors: false,
|
||||
hasWebCrawler: true,
|
||||
} as any);
|
||||
getTestScheduler().run(({ expectObservable }) => {
|
||||
expectObservable(
|
||||
searchProvider.find(
|
||||
{ term: '' },
|
||||
{ aborted$: NEVER, maxResults: 100, preference: '' },
|
||||
{} as any
|
||||
)
|
||||
).toBe('(a|)', {
|
||||
a: expect.not.arrayContaining([{ mongoResult, score: 80 }]),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('returns nothing if tag is specified', () => {
|
||||
getTestScheduler().run(({ expectObservable }) => {
|
||||
expectObservable(
|
||||
searchResultProvider.find(
|
||||
{ tags: ['tag'], term: '' },
|
||||
{ aborted$: NEVER, maxResults: 1, preference: '' },
|
||||
{} as any
|
||||
)
|
||||
).toBe('(a|)', {
|
||||
a: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
it('returns nothing if unknown type is specified', () => {
|
||||
getTestScheduler().run(({ expectObservable }) => {
|
||||
expectObservable(
|
||||
searchResultProvider.find(
|
||||
{ term: '', types: ['tag'] },
|
||||
{ aborted$: NEVER, maxResults: 1, preference: '' },
|
||||
{} as any
|
||||
)
|
||||
).toBe('(a|)', {
|
||||
a: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
it('returns results for integrations tag', () => {
|
||||
getTestScheduler().run(({ expectObservable }) => {
|
||||
expectObservable(
|
||||
searchResultProvider.find(
|
||||
{ term: 'crawler', types: ['integration'] },
|
||||
{ aborted$: NEVER, maxResults: 1, preference: '' },
|
||||
{} as any
|
||||
)
|
||||
).toBe('(a|)', {
|
||||
a: [crawlerResult],
|
||||
});
|
||||
});
|
||||
});
|
||||
it('returns results for enterprise search tag', () => {
|
||||
getTestScheduler().run(({ expectObservable }) => {
|
||||
expectObservable(
|
||||
searchResultProvider.find(
|
||||
{ term: 'crawler', types: ['enterprise search'] },
|
||||
{ aborted$: NEVER, maxResults: 1, preference: '' },
|
||||
{} as any
|
||||
)
|
||||
).toBe('(a|)', {
|
||||
a: [crawlerResult],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
* 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 { from, takeUntil } from 'rxjs';
|
||||
|
||||
import { IBasePath } from '@kbn/core-http-server';
|
||||
import { GlobalSearchResultProvider } from '@kbn/global-search-plugin/server';
|
||||
|
||||
import { ConfigType } from '..';
|
||||
import { CONNECTOR_DEFINITIONS } from '../../common/connectors/connectors';
|
||||
import {
|
||||
ENTERPRISE_SEARCH_CONNECTOR_CRAWLER_SERVICE_TYPE,
|
||||
ENTERPRISE_SEARCH_CONTENT_PLUGIN,
|
||||
} from '../../common/constants';
|
||||
|
||||
export function toSearchResult({
|
||||
basePath,
|
||||
iconPath,
|
||||
name,
|
||||
score,
|
||||
serviceType,
|
||||
}: {
|
||||
basePath: IBasePath;
|
||||
iconPath: string;
|
||||
name: string;
|
||||
score: number;
|
||||
serviceType: string;
|
||||
}) {
|
||||
return {
|
||||
icon: iconPath
|
||||
? basePath.prepend(`/plugins/enterpriseSearch/assets/source_icons/${iconPath}`)
|
||||
: 'logoEnterpriseSearch',
|
||||
id: serviceType,
|
||||
score,
|
||||
title: name,
|
||||
type: 'Enterprise Search',
|
||||
url: {
|
||||
path: `${ENTERPRISE_SEARCH_CONTENT_PLUGIN.URL}/search_indices/new_index/${
|
||||
serviceType === ENTERPRISE_SEARCH_CONNECTOR_CRAWLER_SERVICE_TYPE
|
||||
? 'crawler'
|
||||
: `connector?service_type=${serviceType}`
|
||||
}`,
|
||||
prependBasePath: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
export function getSearchResultProvider(
|
||||
basePath: IBasePath,
|
||||
config: ConfigType
|
||||
): GlobalSearchResultProvider {
|
||||
return {
|
||||
find: ({ term, types, tags }, { aborted$, maxResults }) => {
|
||||
if (
|
||||
tags ||
|
||||
(types && !(types.includes('integration') || types.includes('enterprise search')))
|
||||
) {
|
||||
return from([[]]);
|
||||
}
|
||||
const result = [
|
||||
...(config.hasWebCrawler
|
||||
? [
|
||||
{
|
||||
iconPath: 'crawler.svg',
|
||||
keywords: ['crawler', 'web', 'website', 'internet', 'google'],
|
||||
name: 'Elastic Web Crawler',
|
||||
serviceType: ENTERPRISE_SEARCH_CONNECTOR_CRAWLER_SERVICE_TYPE,
|
||||
},
|
||||
]
|
||||
: []),
|
||||
...(config.hasConnectors ? CONNECTOR_DEFINITIONS : []),
|
||||
]
|
||||
.map(({ iconPath, keywords, name, serviceType }) => {
|
||||
let score = 0;
|
||||
const searchTerm = (term || '').toLowerCase();
|
||||
const searchName = name.toLowerCase();
|
||||
if (!searchTerm) {
|
||||
score = 80;
|
||||
} else if (searchName === searchTerm) {
|
||||
score = 100;
|
||||
} else if (searchName.startsWith(searchTerm)) {
|
||||
score = 90;
|
||||
} else if (searchName.includes(searchTerm)) {
|
||||
score = 75;
|
||||
} else if (serviceType === searchTerm) {
|
||||
score = 65;
|
||||
} else if (keywords.some((keyword) => keyword.includes(searchTerm))) {
|
||||
score = 50;
|
||||
}
|
||||
return toSearchResult({ basePath, iconPath, name, score, serviceType });
|
||||
})
|
||||
.filter(({ score }) => score > 0)
|
||||
.slice(0, maxResults);
|
||||
return from([result]).pipe(takeUntil(aborted$));
|
||||
},
|
||||
getSearchableTypes: () => ['enterprise search', 'integration'],
|
||||
id: 'enterpriseSearch',
|
||||
};
|
||||
}
|
|
@ -59,5 +59,6 @@
|
|||
"@kbn/field-types",
|
||||
"@kbn/core-elasticsearch-server-mocks",
|
||||
"@kbn/shared-ux-link-redirect-app",
|
||||
"@kbn/global-search-plugin",
|
||||
]
|
||||
}
|
||||
|
|