mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Sustainable Kibana Architecture: Remove dependencies between plugins that are related by _App Links_ (#199492)
## Summary This PR introduces a Core API to check whether a given application has been registered. Plugins can use this for their _App Links_, without having to depend on the referenced plugin(s) anymore. This way, we can get rid of some inter-solution dependencies, and categorise plugins more appropriately. --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
parent
560ae9ab30
commit
ad56ec5f1a
23 changed files with 243 additions and 197 deletions
|
@ -26,14 +26,14 @@ import { themeServiceMock } from '@kbn/core-theme-browser-mocks';
|
|||
import { overlayServiceMock } from '@kbn/core-overlays-browser-mocks';
|
||||
import { customBrandingServiceMock } from '@kbn/core-custom-branding-browser-mocks';
|
||||
import { analyticsServiceMock } from '@kbn/core-analytics-browser-mocks';
|
||||
import { MockLifecycle } from './test_helpers/test_types';
|
||||
import type { MockLifecycle } from './test_helpers/test_types';
|
||||
import { ApplicationService } from './application_service';
|
||||
import {
|
||||
App,
|
||||
AppDeepLink,
|
||||
type App,
|
||||
type AppDeepLink,
|
||||
AppStatus,
|
||||
AppUpdater,
|
||||
PublicAppInfo,
|
||||
type AppUpdater,
|
||||
type PublicAppInfo,
|
||||
} from '@kbn/core-application-browser';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { DEFAULT_APP_VISIBILITY } from './utils';
|
||||
|
@ -618,6 +618,26 @@ describe('#start()', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('isAppRegistered', () => {
|
||||
let isAppRegistered: any;
|
||||
beforeEach(async () => {
|
||||
const { register } = service.setup(setupDeps);
|
||||
register(Symbol(), createApp({ id: 'one_app' }));
|
||||
register(Symbol(), createApp({ id: 'another_app', appRoute: '/custom/path' }));
|
||||
|
||||
const start = await service.start(startDeps);
|
||||
isAppRegistered = start.isAppRegistered;
|
||||
});
|
||||
|
||||
it('returns false for unregistered apps', () => {
|
||||
expect(isAppRegistered('oneApp')).toEqual(false);
|
||||
});
|
||||
|
||||
it('returns true for registered apps', () => {
|
||||
expect(isAppRegistered('another_app')).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getUrlForApp', () => {
|
||||
it('creates URL for unregistered appId', async () => {
|
||||
service.setup(setupDeps);
|
||||
|
|
|
@ -327,6 +327,9 @@ export class ApplicationService {
|
|||
takeUntil(this.stop$)
|
||||
),
|
||||
history: this.history!,
|
||||
isAppRegistered: (appId: string): boolean => {
|
||||
return applications$.value.get(appId) !== undefined;
|
||||
},
|
||||
getUrlForApp: (
|
||||
appId,
|
||||
{
|
||||
|
|
|
@ -51,6 +51,7 @@ const createStartContractMock = (): jest.Mocked<ApplicationStart> => {
|
|||
navigateToApp: jest.fn(),
|
||||
navigateToUrl: jest.fn(),
|
||||
getUrlForApp: jest.fn(),
|
||||
isAppRegistered: jest.fn(),
|
||||
};
|
||||
};
|
||||
|
||||
|
@ -92,6 +93,7 @@ const createInternalStartContractMock = (
|
|||
currentActionMenu$: new BehaviorSubject<MountPoint | undefined>(undefined),
|
||||
getComponent: jest.fn(),
|
||||
getUrlForApp: jest.fn(),
|
||||
isAppRegistered: jest.fn(),
|
||||
navigateToApp: jest.fn().mockImplementation((appId) => currentAppId$.next(appId)),
|
||||
navigateToUrl: jest.fn(),
|
||||
history: createHistoryMock(),
|
||||
|
|
|
@ -68,9 +68,12 @@ export interface ApplicationStart {
|
|||
applications$: Observable<ReadonlyMap<string, PublicAppInfo>>;
|
||||
|
||||
/**
|
||||
* Navigate to a given app
|
||||
* Navigate to a given app.
|
||||
* If a plugin is disabled any applications it registers won't be available either.
|
||||
* Before rendering a UI element that a user could use to navigate to another application,
|
||||
* first check if the destination application is actually available using the isAppRegistered API.
|
||||
*
|
||||
* @param appId
|
||||
* @param appId - The identifier of the app to navigate to
|
||||
* @param options - navigation options
|
||||
*/
|
||||
navigateToApp(appId: string, options?: NavigateToAppOptions): Promise<void>;
|
||||
|
@ -114,6 +117,14 @@ export interface ApplicationStart {
|
|||
*/
|
||||
navigateToUrl(url: string, options?: NavigateToUrlOptions): Promise<void>;
|
||||
|
||||
/**
|
||||
* Checks whether a given application is registered.
|
||||
*
|
||||
* @param appId - The identifier of the app to check
|
||||
* @returns true if the given appId is registered in the system, false otherwise.
|
||||
*/
|
||||
isAppRegistered(appId: string): boolean;
|
||||
|
||||
/**
|
||||
* Returns the absolute path (or URL) to a given app, including the global base path.
|
||||
*
|
||||
|
|
|
@ -143,6 +143,7 @@ export function createPluginStartContext<
|
|||
navigateToApp: deps.application.navigateToApp,
|
||||
navigateToUrl: deps.application.navigateToUrl,
|
||||
getUrlForApp: deps.application.getUrlForApp,
|
||||
isAppRegistered: deps.application.isAppRegistered,
|
||||
currentLocation$: deps.application.currentLocation$,
|
||||
},
|
||||
customBranding: deps.customBranding,
|
||||
|
|
|
@ -32,6 +32,7 @@ export const createStartContractMock = (): jest.Mocked<ApplicationStart> => {
|
|||
capabilities,
|
||||
navigateToApp: jest.fn(),
|
||||
navigateToUrl: jest.fn(),
|
||||
isAppRegistered: jest.fn(),
|
||||
getUrlForApp: jest.fn(),
|
||||
};
|
||||
};
|
||||
|
|
|
@ -156,6 +156,7 @@ exports[`SavedObjectsTable should render normally 1`] = `
|
|||
},
|
||||
},
|
||||
"getUrlForApp": [MockFunction],
|
||||
"isAppRegistered": [MockFunction],
|
||||
"navigateToApp": [MockFunction],
|
||||
"navigateToUrl": [MockFunction],
|
||||
},
|
||||
|
|
|
@ -2,9 +2,11 @@
|
|||
"type": "plugin",
|
||||
"id": "@kbn/enterprise-search-plugin",
|
||||
"owner": "@elastic/search-kibana",
|
||||
// Could be categorised as Search in the future, but it currently needs to run in Observability too
|
||||
"group": "platform",
|
||||
"visibility": "shared",
|
||||
// TODO this is currently used from Observability too, must be refactored before solution-specific builds
|
||||
// see x-pack/plugins/observability_solution/observability_ai_assistant_management/public/routes/components/search_connector_tab.tsx
|
||||
// cc sphilipse
|
||||
"group": "search",
|
||||
"visibility": "private",
|
||||
"description": "Adds dashboards for discovering and managing Enterprise Search products.",
|
||||
"plugin": {
|
||||
"id": "enterpriseSearch",
|
||||
|
|
|
@ -80,8 +80,8 @@ export type EnterpriseSearchPublicStart = ReturnType<EnterpriseSearchPlugin['sta
|
|||
|
||||
interface PluginsSetup {
|
||||
cloud?: CloudSetup;
|
||||
licensing: LicensingPluginStart;
|
||||
home?: HomePublicPluginSetup;
|
||||
licensing: LicensingPluginStart;
|
||||
security?: SecurityPluginSetup;
|
||||
share?: SharePluginSetup;
|
||||
}
|
||||
|
@ -98,8 +98,8 @@ export interface PluginsStart {
|
|||
ml?: MlPluginStart;
|
||||
navigation: NavigationPublicPluginStart;
|
||||
searchConnectors?: SearchConnectorsPluginStart;
|
||||
searchPlayground?: SearchPlaygroundPluginStart;
|
||||
searchInferenceEndpoints?: SearchInferenceEndpointsPluginStart;
|
||||
searchPlayground?: SearchPlaygroundPluginStart;
|
||||
security?: SecurityPluginStart;
|
||||
share?: SharePluginStart;
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ export const getApplication = () => {
|
|||
navigateToApp: async (app: string) => {
|
||||
action(`Navigate to: ${app}`);
|
||||
},
|
||||
isAppRegistered: (appId: string) => true,
|
||||
getUrlForApp: (url: string) => url,
|
||||
capabilities: {
|
||||
catalogue: {},
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
"optionalPlugins": [
|
||||
"home",
|
||||
"serverless",
|
||||
"enterpriseSearch"
|
||||
],
|
||||
"requiredBundles": [
|
||||
"kibanaReact",
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
*/
|
||||
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/public';
|
||||
import { ManagementSetup } from '@kbn/management-plugin/public';
|
||||
import { HomePublicPluginSetup } from '@kbn/home-plugin/public';
|
||||
import { ServerlessPluginStart } from '@kbn/serverless/public';
|
||||
import { EnterpriseSearchPublicStart } from '@kbn/enterprise-search-plugin/public';
|
||||
import type { CoreSetup, Plugin, PluginInitializerContext } from '@kbn/core/public';
|
||||
import type { ManagementSetup } from '@kbn/management-plugin/public';
|
||||
import type { HomePublicPluginSetup } from '@kbn/home-plugin/public';
|
||||
import type { ServerlessPluginStart } from '@kbn/serverless/public';
|
||||
|
||||
import type {
|
||||
ObservabilityAIAssistantPublicSetup,
|
||||
|
@ -32,7 +31,6 @@ export interface SetupDependencies {
|
|||
export interface StartDependencies {
|
||||
observabilityAIAssistant: ObservabilityAIAssistantPublicStart;
|
||||
serverless?: ServerlessPluginStart;
|
||||
enterpriseSearch?: EnterpriseSearchPublicStart;
|
||||
}
|
||||
|
||||
export interface ConfigSchema {
|
||||
|
|
|
@ -16,7 +16,7 @@ export const SELECTED_CONNECTOR_LOCAL_STORAGE_KEY =
|
|||
|
||||
export function SearchConnectorTab() {
|
||||
const { application } = useKibana().services;
|
||||
const url = application.getUrlForApp('enterprise_search', { path: '/content/connectors' });
|
||||
const url = application.getUrlForApp('enterpriseSearch', { path: '/content/connectors' });
|
||||
|
||||
return (
|
||||
<>
|
||||
|
|
|
@ -22,9 +22,8 @@ export function SettingsPage() {
|
|||
const { setBreadcrumbs } = useAppContext();
|
||||
const {
|
||||
services: {
|
||||
application: { navigateToApp },
|
||||
application: { navigateToApp, isAppRegistered },
|
||||
serverless,
|
||||
enterpriseSearch,
|
||||
},
|
||||
} = useKibana();
|
||||
|
||||
|
@ -98,7 +97,7 @@ export function SettingsPage() {
|
|||
}
|
||||
),
|
||||
content: <SearchConnectorTab />,
|
||||
disabled: enterpriseSearch == null,
|
||||
disabled: !isAppRegistered('enterpriseSearch'),
|
||||
},
|
||||
];
|
||||
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
"@kbn/core-chrome-browser",
|
||||
"@kbn/observability-ai-assistant-plugin",
|
||||
"@kbn/serverless",
|
||||
"@kbn/enterprise-search-plugin",
|
||||
"@kbn/management-settings-components-field-row",
|
||||
"@kbn/observability-shared-plugin",
|
||||
"@kbn/config-schema",
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
"type": "plugin",
|
||||
"id": "@kbn/search-inference-endpoints",
|
||||
"owner": "@elastic/search-kibana",
|
||||
"group": "platform",
|
||||
"visibility": "shared",
|
||||
// TODO enterpriseSearch depends on it, and Observability has a menu entry for enterpriseSearch
|
||||
// must be refactored / fixed before solution-specific builds
|
||||
// cc sphilipse
|
||||
"group": "search",
|
||||
"visibility": "private",
|
||||
"plugin": {
|
||||
"id": "searchInferenceEndpoints",
|
||||
"server": true,
|
||||
|
|
|
@ -2,9 +2,10 @@
|
|||
"type": "plugin",
|
||||
"id": "@kbn/search-playground",
|
||||
"owner": "@elastic/search-kibana",
|
||||
// @kbn/enterprise-search-plugin (platform) and @kbn/serverless-search (search) depend on it
|
||||
"group": "platform",
|
||||
"visibility": "shared",
|
||||
// TODO @kbn/enterprise-search-plugin (platform) and @kbn/serverless-search (search) depend on it
|
||||
// cc sphilipse
|
||||
"group": "search",
|
||||
"visibility": "private",
|
||||
"plugin": {
|
||||
"id": "searchPlayground",
|
||||
"server": true,
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
"indexManagement",
|
||||
"searchConnectors",
|
||||
"searchInferenceEndpoints",
|
||||
"searchPlayground",
|
||||
"usageCollection"
|
||||
],
|
||||
"requiredBundles": ["kibanaReact"]
|
||||
|
|
|
@ -5,172 +5,179 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import type { NavigationTreeDefinition } from '@kbn/core-chrome-browser';
|
||||
import type { AppDeepLinkId, NavigationTreeDefinition } from '@kbn/core-chrome-browser';
|
||||
import type { ApplicationStart } from '@kbn/core-application-browser';
|
||||
import { i18n } from '@kbn/i18n';
|
||||
import { CONNECTORS_LABEL } from '../common/i18n_string';
|
||||
|
||||
export const navigationTree = (): NavigationTreeDefinition => ({
|
||||
body: [
|
||||
{
|
||||
type: 'navGroup',
|
||||
id: 'search_project_nav',
|
||||
title: 'Elasticsearch',
|
||||
icon: 'logoElasticsearch',
|
||||
defaultIsCollapsed: false,
|
||||
isCollapsible: false,
|
||||
breadcrumbStatus: 'hidden',
|
||||
children: [
|
||||
{
|
||||
id: 'data',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.data', {
|
||||
defaultMessage: 'Data',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.content.indices', {
|
||||
defaultMessage: 'Index Management',
|
||||
}),
|
||||
link: 'management:index_management',
|
||||
breadcrumbStatus:
|
||||
'hidden' /* management sub-pages set their breadcrumbs themselves */,
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return (
|
||||
pathNameSerialized.startsWith(
|
||||
prepend('/app/management/data/index_management/')
|
||||
) ||
|
||||
pathNameSerialized.startsWith(prepend('/app/elasticsearch/indices')) ||
|
||||
pathNameSerialized.startsWith(prepend('/app/elasticsearch/start'))
|
||||
);
|
||||
export const navigationTree = ({ isAppRegistered }: ApplicationStart): NavigationTreeDefinition => {
|
||||
function isAvailable<T>(appId: string, content: T): T[] {
|
||||
return isAppRegistered(appId) ? [content] : [];
|
||||
}
|
||||
|
||||
return {
|
||||
body: [
|
||||
{
|
||||
type: 'navGroup',
|
||||
id: 'search_project_nav',
|
||||
title: 'Elasticsearch',
|
||||
icon: 'logoElasticsearch',
|
||||
defaultIsCollapsed: false,
|
||||
isCollapsible: false,
|
||||
breadcrumbStatus: 'hidden',
|
||||
children: [
|
||||
{
|
||||
id: 'data',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.data', {
|
||||
defaultMessage: 'Data',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.content.indices', {
|
||||
defaultMessage: 'Index Management',
|
||||
}),
|
||||
link: 'management:index_management',
|
||||
breadcrumbStatus:
|
||||
'hidden' /* management sub-pages set their breadcrumbs themselves */,
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return (
|
||||
pathNameSerialized.startsWith(
|
||||
prepend('/app/management/data/index_management/')
|
||||
) ||
|
||||
pathNameSerialized.startsWith(prepend('/app/elasticsearch/indices')) ||
|
||||
pathNameSerialized.startsWith(prepend('/app/elasticsearch/start'))
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
title: CONNECTORS_LABEL,
|
||||
link: 'serverlessConnectors',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'build',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.build', {
|
||||
defaultMessage: 'Build',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
id: 'dev_tools',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.devTools', {
|
||||
defaultMessage: 'Dev Tools',
|
||||
}),
|
||||
link: 'dev_tools',
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return pathNameSerialized.startsWith(prepend('/app/dev_tools'));
|
||||
{
|
||||
title: CONNECTORS_LABEL,
|
||||
link: 'serverlessConnectors',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 'searchPlayground',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.build.searchPlayground', {
|
||||
defaultMessage: 'Playground',
|
||||
}),
|
||||
link: 'searchPlayground',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'relevance',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.relevance', {
|
||||
defaultMessage: 'Relevance',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
id: 'searchInferenceEndpoints',
|
||||
title: i18n.translate(
|
||||
'xpack.serverlessSearch.nav.relevance.searchInferenceEndpoints',
|
||||
{
|
||||
defaultMessage: 'Inference Endpoints',
|
||||
}
|
||||
),
|
||||
link: 'searchInferenceEndpoints',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'analyze',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.analyze', {
|
||||
defaultMessage: 'Analyze',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
link: 'discover',
|
||||
},
|
||||
{
|
||||
link: 'dashboards',
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return pathNameSerialized.startsWith(prepend('/app/dashboards'));
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'build',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.build', {
|
||||
defaultMessage: 'Build',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
id: 'dev_tools',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.devTools', {
|
||||
defaultMessage: 'Dev Tools',
|
||||
}),
|
||||
link: 'dev_tools',
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return pathNameSerialized.startsWith(prepend('/app/dev_tools'));
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'otherTools',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.otherTools', {
|
||||
defaultMessage: 'Other tools',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [{ link: 'maps' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: [
|
||||
{
|
||||
id: 'gettingStarted',
|
||||
type: 'navItem',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', {
|
||||
defaultMessage: 'Getting Started',
|
||||
}),
|
||||
link: 'serverlessElasticsearch',
|
||||
icon: 'launch',
|
||||
},
|
||||
{
|
||||
type: 'navGroup',
|
||||
id: 'project_settings_project_nav',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.projectSettings', {
|
||||
defaultMessage: 'Project settings',
|
||||
}),
|
||||
icon: 'gear',
|
||||
breadcrumbStatus: 'hidden',
|
||||
children: [
|
||||
{
|
||||
link: 'ml:modelManagement',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.trainedModels', {
|
||||
defaultMessage: 'Trained models',
|
||||
}),
|
||||
},
|
||||
{
|
||||
link: 'management',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.mngt', {
|
||||
defaultMessage: 'Management',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkUserAndRoles',
|
||||
cloudLink: 'userAndRoles',
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkDeployment',
|
||||
cloudLink: 'deployment',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.performance', {
|
||||
defaultMessage: 'Performance',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkBilling',
|
||||
cloudLink: 'billingAndSub',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
...isAvailable('searchPlayground', {
|
||||
id: 'searchPlayground',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.build.searchPlayground', {
|
||||
defaultMessage: 'Playground',
|
||||
}),
|
||||
link: 'searchPlayground' as AppDeepLinkId,
|
||||
}),
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'relevance',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.relevance', {
|
||||
defaultMessage: 'Relevance',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
id: 'searchInferenceEndpoints',
|
||||
title: i18n.translate(
|
||||
'xpack.serverlessSearch.nav.relevance.searchInferenceEndpoints',
|
||||
{
|
||||
defaultMessage: 'Inference Endpoints',
|
||||
}
|
||||
),
|
||||
link: 'searchInferenceEndpoints',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'analyze',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.analyze', {
|
||||
defaultMessage: 'Analyze',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [
|
||||
{
|
||||
link: 'discover',
|
||||
},
|
||||
{
|
||||
link: 'dashboards',
|
||||
getIsActive: ({ pathNameSerialized, prepend }) => {
|
||||
return pathNameSerialized.startsWith(prepend('/app/dashboards'));
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'otherTools',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.otherTools', {
|
||||
defaultMessage: 'Other tools',
|
||||
}),
|
||||
spaceBefore: 'm',
|
||||
children: [{ link: 'maps' }],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
footer: [
|
||||
{
|
||||
id: 'gettingStarted',
|
||||
type: 'navItem',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.gettingStarted', {
|
||||
defaultMessage: 'Getting Started',
|
||||
}),
|
||||
link: 'serverlessElasticsearch',
|
||||
icon: 'launch',
|
||||
},
|
||||
{
|
||||
type: 'navGroup',
|
||||
id: 'project_settings_project_nav',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.projectSettings', {
|
||||
defaultMessage: 'Project settings',
|
||||
}),
|
||||
icon: 'gear',
|
||||
breadcrumbStatus: 'hidden',
|
||||
children: [
|
||||
{
|
||||
link: 'ml:modelManagement',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.trainedModels', {
|
||||
defaultMessage: 'Trained models',
|
||||
}),
|
||||
},
|
||||
{
|
||||
link: 'management',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.mngt', {
|
||||
defaultMessage: 'Management',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkUserAndRoles',
|
||||
cloudLink: 'userAndRoles',
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkDeployment',
|
||||
cloudLink: 'deployment',
|
||||
title: i18n.translate('xpack.serverlessSearch.nav.performance', {
|
||||
defaultMessage: 'Performance',
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: 'cloudLinkBilling',
|
||||
cloudLink: 'billingAndSub',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
};
|
||||
|
|
|
@ -148,7 +148,7 @@ export class ServerlessSearchPlugin
|
|||
const { serverless, management, indexManagement, security } = services;
|
||||
serverless.setProjectHome(services.searchIndices.startRoute);
|
||||
|
||||
const navigationTree$ = of(navigationTree());
|
||||
const navigationTree$ = of(navigationTree(core.application));
|
||||
serverless.initNavigation('es', navigationTree$, { dataTestSubj: 'svlSearchSideNav' });
|
||||
|
||||
const extendCardNavDefinitions = serverless.getNavigationCards(
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public';
|
||||
import type { ConsolePluginStart } from '@kbn/console-plugin/public';
|
||||
import type { SearchInferenceEndpointsPluginStart } from '@kbn/search-inference-endpoints/public';
|
||||
import type { SearchPlaygroundPluginStart } from '@kbn/search-playground/public';
|
||||
import type { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public';
|
||||
import type { SecurityPluginStart } from '@kbn/security-plugin/public';
|
||||
import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public';
|
||||
|
@ -37,7 +36,6 @@ export interface ServerlessSearchPluginSetupDependencies {
|
|||
export interface ServerlessSearchPluginStartDependencies {
|
||||
cloud: CloudStart;
|
||||
console: ConsolePluginStart;
|
||||
searchPlayground: SearchPlaygroundPluginStart;
|
||||
searchInferenceEndpoints?: SearchInferenceEndpointsPluginStart;
|
||||
management: ManagementStart;
|
||||
security: SecurityPluginStart;
|
||||
|
|
|
@ -47,7 +47,6 @@
|
|||
"@kbn/search-connectors-plugin",
|
||||
"@kbn/index-management-shared-types",
|
||||
"@kbn/react-kibana-context-render",
|
||||
"@kbn/search-playground",
|
||||
"@kbn/security-api-key-management",
|
||||
"@kbn/search-inference-endpoints",
|
||||
"@kbn/security-plugin-types-common",
|
||||
|
@ -55,5 +54,6 @@
|
|||
"@kbn/core-http-server",
|
||||
"@kbn/logging",
|
||||
"@kbn/security-plugin-types-public",
|
||||
"@kbn/core-application-browser",
|
||||
]
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ export const getDefaultServicesApplication = (
|
|||
navigateToApp: async (app: string) => {
|
||||
action(`Navigate to: ${app}`);
|
||||
},
|
||||
isAppRegistered: (appId: string) => true,
|
||||
getUrlForApp: (url: string) => url,
|
||||
capabilities: getDefaultCapabilities(),
|
||||
applications$: of(applications),
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue