Skip to content

Commit

Permalink
[8.x] [Search][Fix] Inference Endpoints deep link & Side Nav acce…
Browse files Browse the repository at this point in the history
…ss (elastic#197461) (elastic#197547)

# Backport

This will backport the following commits from `main` to `8.x`:
- [[Search][Fix] Inference Endpoints deep link & Side Nav access
(elastic#197461)](elastic#197461)

<!--- Backport version: 9.4.3 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Rodney
Norris","email":"[email protected]"},"sourceCommit":{"committedDate":"2024-10-23T23:44:23Z","message":"[Search][Fix]
Inference Endpoints deep link & Side Nav access
(elastic#197461)","sha":"a124493b8c5aa1dc71c4cf8f2caf134c4355987f","branchLabelMapping":{"^v9.0.0$":"main","^v8.17.0$":"8.x","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","v9.0.0","Team:Search","backport:prev-major","v8.16.0","v8.17.0"],"title":"[Search][Fix]
Inference Endpoints deep link & Side Nav
access","number":197461,"url":"https://github.com/elastic/kibana/pull/197461","mergeCommit":{"message":"[Search][Fix]
Inference Endpoints deep link & Side Nav access
(elastic#197461)","sha":"a124493b8c5aa1dc71c4cf8f2caf134c4355987f"}},"sourceBranch":"main","suggestedTargetBranches":["8.16","8.x"],"targetPullRequestStates":[{"branch":"main","label":"v9.0.0","branchLabelMappingKey":"^v9.0.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/197461","number":197461,"mergeCommit":{"message":"[Search][Fix]
Inference Endpoints deep link & Side Nav access
(elastic#197461)","sha":"a124493b8c5aa1dc71c4cf8f2caf134c4355987f"}},{"branch":"8.16","label":"v8.16.0","branchLabelMappingKey":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"8.x","label":"v8.17.0","branchLabelMappingKey":"^v8.17.0$","isSourceBranch":false,"state":"NOT_CREATED"}]}]
BACKPORT-->

Co-authored-by: Rodney Norris <[email protected]>
  • Loading branch information
kibanamachine and TattdCodeMonkey authored Oct 24, 2024
1 parent 19590f9 commit 324b7bf
Show file tree
Hide file tree
Showing 9 changed files with 151 additions and 23 deletions.
2 changes: 1 addition & 1 deletion packages/deeplinks/search/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

export const ENTERPRISE_SEARCH_APP_ID = 'enterpriseSearch';
export const ENTERPRISE_SEARCH_CONTENT_APP_ID = 'enterpriseSearchContent';
export const ENTERPRISE_SEARCH_RELEVANCE_APP_ID = 'enterpriseSearchRelevance';
export const ENTERPRISE_SEARCH_RELEVANCE_APP_ID = 'searchInferenceEndpoints';
export const ENTERPRISE_SEARCH_APPLICATIONS_APP_ID = 'enterpriseSearchApplications';
export const ENTERPRISE_SEARCH_ANALYTICS_APP_ID = 'enterpriseSearchAnalytics';
export const ENTERPRISE_SEARCH_APPSEARCH_APP_ID = 'appSearch';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export const applicationUsageSchema = {
canvas: commonSchema,
enterpriseSearch: commonSchema,
enterpriseSearchContent: commonSchema,
enterpriseSearchRelevance: commonSchema,
searchInferenceEndpoints: commonSchema,
enterpriseSearchAnalytics: commonSchema,
enterpriseSearchApplications: commonSchema,
enterpriseSearchAISearch: commonSchema,
Expand Down
2 changes: 1 addition & 1 deletion src/plugins/telemetry/schema/oss_plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -2098,7 +2098,7 @@
}
}
},
"enterpriseSearchRelevance": {
"searchInferenceEndpoints": {
"properties": {
"appId": {
"type": "keyword",
Expand Down
96 changes: 96 additions & 0 deletions x-pack/plugins/enterprise_search/common/utils/licensing.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* 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 type { ILicense } from '@kbn/licensing-plugin/public';

import { hasEnterpriseLicense } from './licensing';

describe('licensing utils', () => {
const baseLicense: ILicense = {
isActive: true,
type: 'trial',
isAvailable: true,
signature: 'fake',
toJSON: jest.fn(),
getUnavailableReason: jest.fn().mockReturnValue(undefined),
hasAtLeast: jest.fn().mockReturnValue(false),
check: jest.fn().mockReturnValue({ state: 'valid' }),
getFeature: jest.fn().mockReturnValue({ isAvailable: false, isEnabled: false }),
};
describe('hasEnterpriseLicense', () => {
let license: ILicense;
beforeEach(() => {
jest.resetAllMocks();
license = {
...baseLicense,
};
});
it('returns true for active enterprise license', () => {
license.type = 'enterprise';

expect(hasEnterpriseLicense(license)).toEqual(true);
});
it('returns true for active trial license', () => {
expect(hasEnterpriseLicense(license)).toEqual(true);
});
it('returns false for active basic license', () => {
license.type = 'basic';

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for active gold license', () => {
license.type = 'gold';

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for active platinum license', () => {
license.type = 'platinum';

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive enterprise license', () => {
license.type = 'enterprise';
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive trial license', () => {
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive basic license', () => {
license.type = 'basic';
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive gold license', () => {
license.type = 'gold';
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for inactive platinum license', () => {
license.type = 'platinum';
license.isActive = false;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for active license is missing type', () => {
delete license.type;

expect(hasEnterpriseLicense(license)).toEqual(false);
});
it('returns false for null license', () => {
expect(hasEnterpriseLicense(null)).toEqual(false);
});
it('returns false for undefined license', () => {
expect(hasEnterpriseLicense(undefined)).toEqual(false);
});
});
});
16 changes: 16 additions & 0 deletions x-pack/plugins/enterprise_search/common/utils/licensing.ts
Original file line number Diff line number Diff line change
@@ -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 type { ILicense } from '@kbn/licensing-plugin/public';

/* hasEnterpriseLicense return if the given license is an active `enterprise` or `trial` license
*/
export function hasEnterpriseLicense(license: ILicense | null | undefined): boolean {
if (license === undefined || license === null) return false;
const qualifyingLicenses = ['enterprise', 'trial'];
return license.isActive && qualifyingLicenses.includes(license?.type ?? '');
}
2 changes: 1 addition & 1 deletion x-pack/plugins/enterprise_search/public/navigation_tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const getNavigationTreeDefinition = ({
}),
},
{
children: [{ link: 'enterpriseSearchRelevance:inferenceEndpoints' }],
children: [{ link: 'searchInferenceEndpoints:inferenceEndpoints' }],
id: 'relevance',
title: i18n.translate('xpack.enterpriseSearch.searchNav.relevance', {
defaultMessage: 'Relevance',
Expand Down
21 changes: 19 additions & 2 deletions x-pack/plugins/enterprise_search/public/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
PluginInitializerContext,
DEFAULT_APP_CATEGORIES,
AppDeepLink,
type AppUpdater,
AppStatus,
} from '@kbn/core/public';
import { DataPublicPluginStart } from '@kbn/data-plugin/public';

Expand Down Expand Up @@ -53,8 +55,8 @@ import {
SEARCH_RELEVANCE_PLUGIN,
} from '../common/constants';
import { registerLocators } from '../common/locators';

import { ClientConfigType, InitialAppData } from '../common/types';
import { hasEnterpriseLicense } from '../common/utils/licensing';

import { ENGINES_PATH } from './applications/app_search/routes';
import { SEARCH_APPLICATIONS_PATH, PLAYGROUND_PATH } from './applications/applications/routes';
Expand Down Expand Up @@ -134,7 +136,7 @@ const contentLinks: AppDeepLink[] = [

const relevanceLinks: AppDeepLink[] = [
{
id: 'searchInferenceEndpoints',
id: 'inferenceEndpoints',
path: `/${INFERENCE_ENDPOINTS_PATH}`,
title: i18n.translate(
'xpack.enterpriseSearch.navigation.relevanceInferenceEndpointsLinkLabel',
Expand Down Expand Up @@ -180,6 +182,7 @@ const appSearchLinks: AppDeepLink[] = [

export class EnterpriseSearchPlugin implements Plugin {
private config: ClientConfigType;
private enterpriseLicenseAppUpdater$ = new BehaviorSubject<AppUpdater>(() => ({}));

constructor(initializerContext: PluginInitializerContext) {
this.config = initializerContext.config.get<ClientConfigType>();
Expand Down Expand Up @@ -440,6 +443,8 @@ export class EnterpriseSearchPlugin implements Plugin {
deepLinks: relevanceLinks,
euiIconType: SEARCH_RELEVANCE_PLUGIN.LOGO,
id: SEARCH_RELEVANCE_PLUGIN.ID,
status: AppStatus.inaccessible,
updater$: this.enterpriseLicenseAppUpdater$,
mount: async (params: AppMountParameters) => {
const kibanaDeps = await this.getKibanaDeps(core, params, cloud);
const { chrome, http } = kibanaDeps.core;
Expand Down Expand Up @@ -615,6 +620,18 @@ export class EnterpriseSearchPlugin implements Plugin {
);
});

plugins.licensing?.license$.subscribe((license) => {
if (hasEnterpriseLicense(license)) {
this.enterpriseLicenseAppUpdater$.next(() => ({
status: AppStatus.accessible,
}));
} else {
this.enterpriseLicenseAppUpdater$.next(() => ({
status: AppStatus.inaccessible,
}));
}
});

// Return empty start contract rather than void in order for plugins
// that depend on the enterprise search plugin to determine whether it is enabled or not
return {};
Expand Down
32 changes: 16 additions & 16 deletions x-pack/test/functional_search/tests/solution_navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ export default function searchSolutionNavigation({
await solutionNavigation.sidenav.expectLinkExists({ text: 'Playground' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Search applications' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Behavioral Analytics' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Inference Endpoints' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'App Search' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Workplace Search' });
await solutionNavigation.sidenav.expectLinkExists({ text: 'Other tools' });
Expand Down Expand Up @@ -184,20 +185,19 @@ export default function searchSolutionNavigation({

// check Relevance
// > Inference Endpoints
// TODO: FTRs don't have enterprise license, so inference endpoints not shown
// await solutionNavigation.sidenav.clickLink({
// deepLinkId: 'enterpriseSearchRelevance:inferenceEndpoints',
// });
// await solutionNavigation.sidenav.expectLinkActive({
// deepLinkId: 'enterpriseSearchRelevance:inferenceEndpoints',
// });
// await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Relevance' });
// await solutionNavigation.breadcrumbs.expectBreadcrumbExists({
// text: 'Inference Endpoints',
// });
// await solutionNavigation.breadcrumbs.expectBreadcrumbExists({
// deepLinkId: 'enterpriseSearchRelevance:inferenceEndpoints',
// });
await solutionNavigation.sidenav.clickLink({
deepLinkId: 'searchInferenceEndpoints:inferenceEndpoints',
});
await solutionNavigation.sidenav.expectLinkActive({
deepLinkId: 'searchInferenceEndpoints:inferenceEndpoints',
});
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({ text: 'Relevance' });
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({
text: 'Inference Endpoints',
});
await solutionNavigation.breadcrumbs.expectBreadcrumbExists({
deepLinkId: 'searchInferenceEndpoints:inferenceEndpoints',
});

// check Enterprise Search
// > App Search
Expand Down Expand Up @@ -296,8 +296,8 @@ export default function searchSolutionNavigation({
'enterpriseSearchApplications:playground',
'enterpriseSearchApplications:searchApplications',
'enterpriseSearchAnalytics',
// 'relevance',
// 'enterpriseSearchRelevance:inferenceEndpoints',
'relevance',
'searchInferenceEndpoints:inferenceEndpoints',
'entsearch',
'appSearch:engines',
'workplaceSearch',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ export default function catalogueTests({ getService }: FtrProviderContext) {
'enterpriseSearchVectorSearch',
'enterpriseSearchSemanticSearch',
'enterpriseSearchElasticsearch',
'enterpriseSearchRelevance',
'searchInferenceEndpoints',
'appSearch',
'observabilityAIAssistant',
Expand Down

0 comments on commit 324b7bf

Please sign in to comment.