From 9a8ccdc7246236700816619583c076f8f3bdbf11 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Sat, 10 Jun 2023 14:13:25 +0100 Subject: [PATCH 01/30] [ML] Integrating into serverless kibana --- .../plugins/ml/common/types/capabilities.ts | 26 ++++++++++--- x-pack/plugins/ml/public/application/app.tsx | 19 +++++++--- .../components/ml_page/ml_page.tsx | 20 ++++++---- .../ml/public/application/routing/router.tsx | 1 + x-pack/plugins/ml/public/plugin.ts | 10 ++++- .../lib/capabilities/capabilities_switcher.ts | 28 ++++++++++---- x-pack/plugins/ml/server/plugin.ts | 36 ++++++++++++++++-- x-pack/plugins/ml/server/routes/filters.ts | 35 ++++++++---------- .../plugins/ml/server/routes/job_service.ts | 2 +- x-pack/plugins/ml/server/types.ts | 2 + .../serverless_observability/public/plugin.ts | 1 + .../serverless_observability/public/types.ts | 2 + .../serverless_observability/server/plugin.ts | 20 ++++++++-- .../serverless_observability/server/types.ts | 9 +++++ x-pack/plugins/serverless_search/kibana.jsonc | 17 +++++---- .../serverless_search/public/plugin.ts | 1 + .../plugins/serverless_search/public/types.ts | 2 + .../serverless_search/server/plugin.ts | 37 ++++++++++++++----- .../plugins/serverless_search/server/types.ts | 10 +++++ .../plugins/serverless_security/kibana.jsonc | 7 ++-- .../serverless_security/public/plugin.ts | 2 + .../serverless_security/public/types.ts | 2 + .../serverless_security/server/plugin.ts | 2 + .../serverless_security/server/types.ts | 2 + 24 files changed, 219 insertions(+), 74 deletions(-) diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index 1ab797403c103..831db963e3120 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -18,6 +18,12 @@ export const apmUserMlCapabilities = { canGetJobs: false, }; +export const featureMlCapabilities = { + isADEnabled: true, + isDFAEnabled: true, + isNLPEnabled: true, +}; + export const userMlCapabilities = { // Anomaly Detection canGetJobs: false, @@ -78,9 +84,10 @@ export const adminMlCapabilities = { canStartStopTrainedModels: false, }; +export type FeatureMlCapabilities = typeof featureMlCapabilities; export type UserMlCapabilities = typeof userMlCapabilities; export type AdminMlCapabilities = typeof adminMlCapabilities; -export type MlCapabilities = UserMlCapabilities & AdminMlCapabilities; +export type MlCapabilities = FeatureMlCapabilities & UserMlCapabilities & AdminMlCapabilities; export type MlCapabilitiesKey = keyof MlCapabilities; export const basicLicenseMlCapabilities = [ @@ -91,6 +98,7 @@ export const basicLicenseMlCapabilities = [ export function getDefaultCapabilities(): MlCapabilities { return { + ...featureMlCapabilities, ...userMlCapabilities, ...adminMlCapabilities, }; @@ -99,8 +107,13 @@ export function getDefaultCapabilities(): MlCapabilities { export function getPluginPrivileges() { const apmUserMlCapabilitiesKeys = Object.keys(apmUserMlCapabilities); const userMlCapabilitiesKeys = Object.keys(userMlCapabilities); + const featureMlCapabilitiesKeys = Object.keys(featureMlCapabilities); const adminMlCapabilitiesKeys = Object.keys(adminMlCapabilities); - const allMlCapabilitiesKeys = [...adminMlCapabilitiesKeys, ...userMlCapabilitiesKeys]; + const allMlCapabilitiesKeys = [ + ...featureMlCapabilitiesKeys, + ...adminMlCapabilitiesKeys, + ...userMlCapabilitiesKeys, + ]; const savedObjects = [ 'index-pattern', @@ -141,10 +154,13 @@ export function getPluginPrivileges() { }, user: { ...privilege, - api: ['fileUpload:analyzeFile', ...userMlCapabilitiesKeys.map((k) => `ml:${k}`)], + api: [ + 'fileUpload:analyzeFile', + ...[...featureMlCapabilitiesKeys, ...userMlCapabilitiesKeys].map((k) => `ml:${k}`), + ], catalogue: [PLUGIN_ID], management: { insightsAndAlerting: [] }, - ui: userMlCapabilitiesKeys, + ui: [...featureMlCapabilitiesKeys, ...userMlCapabilitiesKeys], savedObject: { all: [], read: savedObjects, @@ -166,7 +182,7 @@ export function getPluginPrivileges() { all: [], read: [ML_JOB_SAVED_OBJECT_TYPE], }, - api: apmUserMlCapabilitiesKeys.map((k) => `ml:${k}`), + api: apmUserMlCapabilitiesKeys.map((k) => `ml:${k}`), // should this include feature keys?!!!!!!!!!!!!!!!!!!!!!!! ui: apmUserMlCapabilitiesKeys, }, }; diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index 068fc1454a981..354ad68f6777f 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -10,7 +10,7 @@ import './_index.scss'; import ReactDOM from 'react-dom'; import { pick } from 'lodash'; -import { AppMountParameters, CoreStart, HttpStart } from '@kbn/core/public'; +import type { AppMountParameters, CoreStart, HttpStart } from '@kbn/core/public'; import type { UsageCollectionSetup } from '@kbn/usage-collection-plugin/public'; import { DatePickerContextProvider } from '@kbn/ml-date-picker'; @@ -32,6 +32,7 @@ import { mlUsageCollectionProvider } from './services/usage_collection'; import { MlRouter } from './routing'; import { mlApiServicesProvider } from './services/ml_api_service'; import { HttpService } from './services/http_service'; +import type { PageDependencies } from './routing/router'; export type MlDependencies = Omit< MlSetupDependencies, @@ -43,6 +44,7 @@ interface AppProps { coreStart: CoreStart; deps: MlDependencies; appMountParams: AppMountParameters; + navMenuEnabled: boolean; } const localStorage = new Storage(window.localStorage); @@ -73,7 +75,7 @@ export interface MlServicesContext { export type MlGlobalServices = ReturnType; -const App: FC = ({ coreStart, deps, appMountParams }) => { +const App: FC = ({ coreStart, deps, appMountParams, navMenuEnabled }) => { const redirectToMlAccessDeniedPage = async () => { // access maybe be denied due to an expired license, so check the license status first // if the license has expired, redirect to the license management page @@ -90,13 +92,14 @@ const App: FC = ({ coreStart, deps, appMountParams }) => { await coreStart.application.navigateToUrl(await redirectPage); }; - const pageDeps = { + const pageDeps: PageDependencies = { history: appMountParams.history, setHeaderActionMenu: appMountParams.setHeaderActionMenu, dataViewsContract: deps.data.dataViews, config: coreStart.uiSettings!, setBreadcrumbs: coreStart.chrome!.setBreadcrumbs, redirectToMlAccessDeniedPage, + navMenuEnabled, }; const services = { @@ -159,7 +162,8 @@ const App: FC = ({ coreStart, deps, appMountParams }) => { export const renderApp = ( coreStart: CoreStart, deps: MlDependencies, - appMountParams: AppMountParameters + appMountParams: AppMountParameters, + navMenuEnabled: boolean ) => { setDependencyCache({ timefilter: deps.data.query.timefilter, @@ -190,7 +194,12 @@ export const renderApp = ( const mlLicense = setLicenseCache(deps.licensing, coreStart.application, () => ReactDOM.render( - , + , appMountParams.element ) ); diff --git a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx index 477a411935636..7ca6d776099c9 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx @@ -113,6 +113,8 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps } }, [activeRoute]); + const sideNavItems = useSideNavItems(activeRoute); + return ( = React.memo(({ pageDeps className={'ml-app'} data-test-subj={'mlApp'} restrictWidth={false} - solutionNav={{ - name: i18n.translate('xpack.ml.plugin.title', { - defaultMessage: 'Machine Learning', - }), - icon: 'machineLearningApp', - items: useSideNavItems(activeRoute), - }} + solutionNav={ + pageDeps.navMenuEnabled + ? { + name: i18n.translate('xpack.ml.plugin.title', { + defaultMessage: 'Machine Learning', + }), + icon: 'machineLearningApp', + items: sideNavItems, + } + : undefined + } pageHeader={{ pageTitle: , rightSideItems, diff --git a/x-pack/plugins/ml/public/application/routing/router.tsx b/x-pack/plugins/ml/public/application/routing/router.tsx index 725ab790200ba..7a440109a2322 100644 --- a/x-pack/plugins/ml/public/application/routing/router.tsx +++ b/x-pack/plugins/ml/public/application/routing/router.tsx @@ -65,6 +65,7 @@ export interface PageDependencies { dataViewsContract: DataViewsContract; setBreadcrumbs: ChromeStart['setBreadcrumbs']; redirectToMlAccessDeniedPage: () => Promise; + navMenuEnabled: boolean; } export const PageLoader: FC<{ context: MlContextValue }> = ({ context, children }) => { diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index f8362b3a92353..a66dc26b60cf8 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -99,6 +99,8 @@ export class MlPlugin implements Plugin { private locator: undefined | MlLocator; + private navMenuEnabled = true; + constructor(private initializerContext: PluginInitializerContext) {} setup(core: MlCoreSetup, pluginsSetup: MlSetupDependencies) { @@ -142,7 +144,8 @@ export class MlPlugin implements Plugin { savedObjectsManagement: pluginsStart.savedObjectsManagement, savedSearch: pluginsStart.savedSearch, }, - params + params, + this.navMenuEnabled ); }, }); @@ -213,8 +216,13 @@ export class MlPlugin implements Plugin { } }); + const setNavMenuEnabled = (enabled: boolean) => { + this.navMenuEnabled = enabled; + }; + return { locator: this.locator, + setNavMenuEnabled, }; } diff --git a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts index bc90437e8fcc6..005e7181ebe9d 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts @@ -11,16 +11,22 @@ import { CapabilitiesSwitcher, CoreSetup, Logger } from '@kbn/core/server'; import { ILicense } from '@kbn/licensing-plugin/common/types'; import { isFullLicense, isMinimumLicense, isMlEnabled } from '../../../common/license'; import { MlCapabilities, basicLicenseMlCapabilities } from '../../../common/types/capabilities'; +import { MlFeatures } from '../../types'; export const setupCapabilitiesSwitcher = ( coreSetup: CoreSetup, license$: Observable, + enabledFeatures: MlFeatures, logger: Logger ) => { - coreSetup.capabilities.registerSwitcher(getSwitcher(license$, logger)); + coreSetup.capabilities.registerSwitcher(getSwitcher(license$, logger, enabledFeatures)); }; -function getSwitcher(license$: Observable, logger: Logger): CapabilitiesSwitcher { +function getSwitcher( + license$: Observable, + logger: Logger, + enabledFeatures: MlFeatures +): CapabilitiesSwitcher { return async (request, capabilities) => { const isAnonymousRequest = !request.route.options.authRequired; if (isAnonymousRequest) { @@ -31,14 +37,14 @@ function getSwitcher(license$: Observable, logger: Logger): Capabiliti const license = await firstValueFrom(license$); const mlEnabled = isMlEnabled(license); + const originalCapabilities = capabilities.ml as MlCapabilities; + const mlCaps = cloneDeep(originalCapabilities); + // full license, leave capabilities as they were if (mlEnabled && isFullLicense(license)) { - return {}; + return { ml: applyEnabledFeatures(mlCaps, enabledFeatures) }; } - const originalCapabilities = capabilities.ml as MlCapabilities; - const mlCaps = cloneDeep(originalCapabilities); - // not full licence, switch off all capabilities Object.keys(mlCaps).forEach((k) => { mlCaps[k as keyof MlCapabilities] = false; @@ -49,10 +55,18 @@ function getSwitcher(license$: Observable, logger: Logger): Capabiliti basicLicenseMlCapabilities.forEach((c) => (mlCaps[c] = originalCapabilities[c])); } - return { ml: mlCaps }; + return { ml: applyEnabledFeatures(mlCaps, enabledFeatures) }; } catch (e) { logger.debug(`Error updating capabilities for ML based on licensing: ${e}`); return {}; } }; } + +function applyEnabledFeatures(mlCaps: MlCapabilities, enabledFeatures: MlFeatures) { + mlCaps.isADEnabled = enabledFeatures.ad; + mlCaps.isDFAEnabled = enabledFeatures.dfa; + mlCaps.isNLPEnabled = enabledFeatures.nlp; + mlCaps.canCloseJob = false; + return mlCaps; +} diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index db150f7c42f32..1919ed5faf81f 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -26,7 +26,7 @@ import { FieldFormatsStart } from '@kbn/field-formats-plugin/server'; import type { HomeServerPluginSetup } from '@kbn/home-plugin/server'; import { jsonSchemaRoutes } from './routes/json_schema'; import { notificationsRoutes } from './routes/notifications'; -import type { PluginsSetup, PluginsStart, RouteInitialization } from './types'; +import type { MlFeatures, PluginsSetup, PluginsStart, RouteInitialization } from './types'; import { PLUGIN_ID } from '../common/constants/app'; import type { MlCapabilities } from '../common/types/capabilities'; @@ -73,7 +73,13 @@ import { CASE_ATTACHMENT_TYPE_ID_ANOMALY_EXPLORER_CHARTS, } from '../common/constants/cases'; -export type MlPluginSetup = SharedServices; +type SetFeatureEnabled = (features: MlFeatures) => void; + +interface MlSetup { + setFeaturesEnabled: SetFeatureEnabled; +} + +export type MlPluginSetup = SharedServices & MlSetup; export type MlPluginStart = void; export class MlServerPlugin @@ -93,6 +99,11 @@ export class MlServerPlugin private isMlReady: Promise; private setMlReady: () => void = () => {}; private savedObjectsSyncService: SavedObjectsSyncService; + private enabledFeatures: MlFeatures = { + ad: true, + dfa: true, + nlp: true, + }; constructor(ctx: PluginInitializerContext) { this.log = ctx.logger.get(); @@ -149,7 +160,12 @@ export class MlServerPlugin registerKibanaSettings(coreSetup); // initialize capabilities switcher to add license filter to ml capabilities - setupCapabilitiesSwitcher(coreSetup, plugins.licensing.license$, this.log); + setupCapabilitiesSwitcher( + coreSetup, + plugins.licensing.license$, + this.enabledFeatures, + this.log + ); setupSavedObjects(coreSetup.savedObjects); this.savedObjectsSyncService.registerSyncTask( plugins.taskManager, @@ -269,7 +285,19 @@ export class MlServerPlugin }); } - return sharedServicesProviders; + const setFeaturesEnabled = (features: MlFeatures) => { + if (features.ad !== undefined) { + this.enabledFeatures.ad = features.ad; + } + if (features.dfa !== undefined) { + this.enabledFeatures.dfa = features.dfa; + } + if (features.nlp !== undefined) { + this.enabledFeatures.nlp = features.nlp; + } + }; + + return { ...sharedServicesProviders, setFeaturesEnabled }; } public start(coreStart: CoreStart, plugins: PluginsStart): MlPluginStart { diff --git a/x-pack/plugins/ml/server/routes/filters.ts b/x-pack/plugins/ml/server/routes/filters.ts index 72bebe59529fd..82a3ff0be0082 100644 --- a/x-pack/plugins/ml/server/routes/filters.ts +++ b/x-pack/plugins/ml/server/routes/filters.ts @@ -55,31 +55,26 @@ export function filtersRoutes({ router, routeGuard }: RouteInitialization) { * @apiSuccess {Boolean} success * @apiSuccess {Object[]} filters list of filters */ - router.versioned - .get({ + router.get( + { path: `${ML_INTERNAL_BASE_PATH}/filters`, - access: 'internal', + validate: {}, options: { tags: ['access:ml:canGetFilters'], }, - }) - .addVersion( - { - version: '1', - validate: false, - }, - routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => { - try { - const resp = await getAllFilters(mlClient); + }, + routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => { + try { + const resp = await getAllFilters(mlClient); - return response.ok({ - body: resp, - }); - } catch (e) { - return response.customError(wrapError(e)); - } - }) - ); + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); /** * @apiGroup Filters diff --git a/x-pack/plugins/ml/server/routes/job_service.ts b/x-pack/plugins/ml/server/routes/job_service.ts index cb8bbebd95d31..982396f34b1eb 100644 --- a/x-pack/plugins/ml/server/routes/job_service.ts +++ b/x-pack/plugins/ml/server/routes/job_service.ts @@ -298,7 +298,7 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { path: `${ML_INTERNAL_BASE_PATH}/jobs/jobs_summary`, access: 'internal', options: { - tags: ['access:ml:canGetJobs'], + tags: ['access:ml:canCloseJob'], }, }) .addVersion( diff --git a/x-pack/plugins/ml/server/types.ts b/x-pack/plugins/ml/server/types.ts index d054a2289be50..df4770e6867bc 100644 --- a/x-pack/plugins/ml/server/types.ts +++ b/x-pack/plugins/ml/server/types.ts @@ -81,3 +81,5 @@ export interface RouteInitialization { mlLicense: MlLicense; routeGuard: RouteGuard; } + +export type MlFeatures = Record<'ad' | 'dfa' | 'nlp', boolean>; diff --git a/x-pack/plugins/serverless_observability/public/plugin.ts b/x-pack/plugins/serverless_observability/public/plugin.ts index 56304cfdb623d..63a2ad9559b2f 100644 --- a/x-pack/plugins/serverless_observability/public/plugin.ts +++ b/x-pack/plugins/serverless_observability/public/plugin.ts @@ -21,6 +21,7 @@ export class ServerlessObservabilityPlugin _core: CoreSetup, _setupDeps: ServerlessObservabilityPluginSetupDependencies ): ServerlessObservabilityPluginSetup { + _setupDeps.ml.setNavMenuEnabled(false); return {}; } diff --git a/x-pack/plugins/serverless_observability/public/types.ts b/x-pack/plugins/serverless_observability/public/types.ts index 417a9c1701c84..ba587011fc1e6 100644 --- a/x-pack/plugins/serverless_observability/public/types.ts +++ b/x-pack/plugins/serverless_observability/public/types.ts @@ -10,6 +10,7 @@ import { ObservabilitySharedPluginSetup, ObservabilitySharedPluginStart, } from '@kbn/observability-shared-plugin/public'; +import type { MlPluginSetup } from '@kbn/ml-plugin/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessObservabilityPluginSetup {} @@ -20,6 +21,7 @@ export interface ServerlessObservabilityPluginStart {} export interface ServerlessObservabilityPluginSetupDependencies { observabilityShared: ObservabilitySharedPluginSetup; serverless: ServerlessPluginSetup; + ml: MlPluginSetup; } export interface ServerlessObservabilityPluginStartDependencies { diff --git a/x-pack/plugins/serverless_observability/server/plugin.ts b/x-pack/plugins/serverless_observability/server/plugin.ts index 8b28ba2b0a4ac..7f706d7da5803 100644 --- a/x-pack/plugins/serverless_observability/server/plugin.ts +++ b/x-pack/plugins/serverless_observability/server/plugin.ts @@ -5,16 +5,28 @@ * 2.0. */ -import { PluginInitializerContext, Plugin } from '@kbn/core/server'; +import { PluginInitializerContext, Plugin, CoreSetup } from '@kbn/core/server'; -import { ServerlessObservabilityPluginSetup, ServerlessObservabilityPluginStart } from './types'; +import { + ServerlessObservabilityPluginSetup, + ServerlessObservabilityPluginStart, + SetupDependencies, + StartDependencies, +} from './types'; export class ServerlessObservabilityPlugin - implements Plugin + implements + Plugin< + ServerlessObservabilityPluginSetup, + ServerlessObservabilityPluginStart, + SetupDependencies, + StartDependencies + > { constructor(_initializerContext: PluginInitializerContext) {} - public setup() { + public setup(_coreSetup: CoreSetup, pluginsSetup: SetupDependencies) { + pluginsSetup.ml.setFeaturesEnabled({ ad: true, dfa: false, nlp: false }); return {}; } diff --git a/x-pack/plugins/serverless_observability/server/types.ts b/x-pack/plugins/serverless_observability/server/types.ts index f8a587103e886..5ebad2274b9a5 100644 --- a/x-pack/plugins/serverless_observability/server/types.ts +++ b/x-pack/plugins/serverless_observability/server/types.ts @@ -5,7 +5,16 @@ * 2.0. */ +import type { MlPluginSetup } from '@kbn/ml-plugin/server'; + // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessObservabilityPluginSetup {} // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessObservabilityPluginStart {} + +// eslint-disable-next-line @typescript-eslint/no-empty-interface +export interface StartDependencies {} + +export interface SetupDependencies { + ml: MlPluginSetup; +} diff --git a/x-pack/plugins/serverless_search/kibana.jsonc b/x-pack/plugins/serverless_search/kibana.jsonc index 95484ec54dc43..a8c6b8c3b77ee 100644 --- a/x-pack/plugins/serverless_search/kibana.jsonc +++ b/x-pack/plugins/serverless_search/kibana.jsonc @@ -9,18 +9,19 @@ "browser": true, "configPath": ["xpack", "serverless", "search"], "requiredPlugins": [ - "serverless", "cloud", - "management", - "security", - "share", - "devTools", "console", - "searchprofiler", + "dashboard", + "devTools", + "discover", "grokdebugger", + "management", + "ml", "painlessLab", - "discover", - "dashboard", + "searchprofiler", + "security", + "serverless", + "share", "visualizations" ], "optionalPlugins": [], diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts index 18644b72f426c..d65207b422a28 100644 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -43,6 +43,7 @@ export class ServerlessSearchPlugin return await renderApp(element, coreStart, { userProfile, ...services }); }, }); + _setupDeps.ml.setNavMenuEnabled(false); return {}; } diff --git a/x-pack/plugins/serverless_search/public/types.ts b/x-pack/plugins/serverless_search/public/types.ts index 5b984289e2bd7..01f77f5aaf515 100644 --- a/x-pack/plugins/serverless_search/public/types.ts +++ b/x-pack/plugins/serverless_search/public/types.ts @@ -10,6 +10,7 @@ import { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public' import { SecurityPluginStart } from '@kbn/security-plugin/public'; import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; import { SharePluginStart } from '@kbn/share-plugin/public'; +import type { MlPluginSetup } from '@kbn/ml-plugin/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessSearchPluginSetup {} @@ -21,6 +22,7 @@ export interface ServerlessSearchPluginSetupDependencies { cloud: CloudSetup; management: ManagementSetup; serverless: ServerlessPluginSetup; + ml: MlPluginSetup; } export interface ServerlessSearchPluginStartDependencies { diff --git a/x-pack/plugins/serverless_search/server/plugin.ts b/x-pack/plugins/serverless_search/server/plugin.ts index caa53bcf0adb0..0e8e4c11a49f9 100644 --- a/x-pack/plugins/serverless_search/server/plugin.ts +++ b/x-pack/plugins/serverless_search/server/plugin.ts @@ -5,16 +5,24 @@ * 2.0. */ -import { IRouter, Logger, PluginInitializerContext, Plugin, CoreSetup } from '@kbn/core/server'; -import { SecurityPluginStart } from '@kbn/security-plugin/server'; +import type { + IRouter, + Logger, + PluginInitializerContext, + Plugin, + CoreSetup, +} from '@kbn/core/server'; +import type { SecurityPluginStart } from '@kbn/security-plugin/server'; import { registerApiKeyRoutes } from './routes/api_key_routes'; -import { ServerlessSearchConfig } from './config'; -import { ServerlessSearchPluginSetup, ServerlessSearchPluginStart } from './types'; +import type { ServerlessSearchConfig } from './config'; +import { + ServerlessSearchPluginSetup, + ServerlessSearchPluginStart, + SetupDependencies, + StartDependencies, +} from './types'; -interface StartDependencies { - security: SecurityPluginStart; -} export interface RouteDependencies { logger: Logger; router: IRouter; @@ -22,7 +30,13 @@ export interface RouteDependencies { } export class ServerlessSearchPlugin - implements Plugin + implements + Plugin< + ServerlessSearchPluginSetup, + ServerlessSearchPluginStart, + SetupDependencies, + StartDependencies + > { // @ts-ignore config is not used for now private readonly config: ServerlessSearchConfig; @@ -34,7 +48,10 @@ export class ServerlessSearchPlugin this.logger = initializerContext.logger.get(); } - public setup({ getStartServices, http }: CoreSetup) { + public setup( + { getStartServices, http }: CoreSetup, + pluginsSetup: SetupDependencies + ) { const router = http.createRouter(); getStartServices().then(([, { security }]) => { this.security = security; @@ -42,6 +59,8 @@ export class ServerlessSearchPlugin registerApiKeyRoutes(dependencies); }); + + pluginsSetup.ml.setFeaturesEnabled({ ad: false, dfa: false, nlp: true }); return {}; } diff --git a/x-pack/plugins/serverless_search/server/types.ts b/x-pack/plugins/serverless_search/server/types.ts index 6011e2eb60fa0..8e8f7f15a8124 100644 --- a/x-pack/plugins/serverless_search/server/types.ts +++ b/x-pack/plugins/serverless_search/server/types.ts @@ -5,7 +5,17 @@ * 2.0. */ +import type { SecurityPluginStart } from '@kbn/security-plugin/server'; +import type { MlPluginSetup } from '@kbn/ml-plugin/server'; + // 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 StartDependencies { + security: SecurityPluginStart; +} +export interface SetupDependencies { + ml: MlPluginSetup; +} diff --git a/x-pack/plugins/serverless_security/kibana.jsonc b/x-pack/plugins/serverless_security/kibana.jsonc index 4b614dc11e4b5..f1f66a43daed9 100644 --- a/x-pack/plugins/serverless_security/kibana.jsonc +++ b/x-pack/plugins/serverless_security/kibana.jsonc @@ -13,14 +13,15 @@ "security" ], "requiredPlugins": [ - "serverless", + "kibanaReact", + "ml", "security", "securitySolution", - "kibanaReact" + "serverless" ], "optionalPlugins": [ "essSecurity" ], "requiredBundles": [] } -} \ No newline at end of file +} diff --git a/x-pack/plugins/serverless_security/public/plugin.ts b/x-pack/plugins/serverless_security/public/plugin.ts index 9b22f39833201..f3dc0cb1b1a83 100644 --- a/x-pack/plugins/serverless_security/public/plugin.ts +++ b/x-pack/plugins/serverless_security/public/plugin.ts @@ -37,6 +37,8 @@ export class ServerlessSecurityPlugin setupDeps: ServerlessSecurityPluginSetupDependencies ): ServerlessSecurityPluginSetup { registerUpsellings(setupDeps.securitySolution.upselling, this.config.productTypes); + + setupDeps.ml.setNavMenuEnabled(false); return {}; } diff --git a/x-pack/plugins/serverless_security/public/types.ts b/x-pack/plugins/serverless_security/public/types.ts index 3954183cc9749..bccd1998c6ab3 100644 --- a/x-pack/plugins/serverless_security/public/types.ts +++ b/x-pack/plugins/serverless_security/public/types.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { MlPluginSetup } from '@kbn/ml-plugin/public'; import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public'; import type { PluginSetup as SecuritySolutionPluginSetup, @@ -23,6 +24,7 @@ export interface ServerlessSecurityPluginSetupDependencies { security: SecurityPluginSetup; securitySolution: SecuritySolutionPluginSetup; serverless: ServerlessPluginSetup; + ml: MlPluginSetup; } export interface ServerlessSecurityPluginStartDependencies { diff --git a/x-pack/plugins/serverless_security/server/plugin.ts b/x-pack/plugins/serverless_security/server/plugin.ts index 6cf98846bcd23..c9d819e5a9af2 100644 --- a/x-pack/plugins/serverless_security/server/plugin.ts +++ b/x-pack/plugins/serverless_security/server/plugin.ts @@ -41,6 +41,8 @@ export class ServerlessSecurityPlugin pluginsSetup.securitySolution.setAppFeatures(getProductAppFeatures(this.config.productTypes)); } + pluginsSetup.ml.setFeaturesEnabled({ ad: true, dfa: true, nlp: false }); + return {}; } diff --git a/x-pack/plugins/serverless_security/server/types.ts b/x-pack/plugins/serverless_security/server/types.ts index 6756351c9bf6e..2cadb19ba09ad 100644 --- a/x-pack/plugins/serverless_security/server/types.ts +++ b/x-pack/plugins/serverless_security/server/types.ts @@ -13,6 +13,7 @@ import { } from '@kbn/security-solution-plugin/server'; import type { EssSecurityPluginSetup } from '@kbn/ess-security/server'; +import type { MlPluginSetup } from '@kbn/ml-plugin/server'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessSecurityPluginSetup {} @@ -24,6 +25,7 @@ export interface ServerlessSecurityPluginSetupDependencies { securitySolution: SecuritySolutionPluginSetup; features: PluginSetupContract; essSecurity: EssSecurityPluginSetup; + ml: MlPluginSetup; } export interface ServerlessSecurityPluginStartDependencies { From c11e1616986875227fec0607571b3f99281b4edc Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Sat, 10 Jun 2023 14:21:20 +0100 Subject: [PATCH 02/30] removing temp debugging code --- .../lib/capabilities/capabilities_switcher.ts | 1 - x-pack/plugins/ml/server/routes/filters.ts | 35 +++++++++++-------- .../plugins/ml/server/routes/job_service.ts | 2 +- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts index 005e7181ebe9d..8ef4ea9e3b8e0 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts @@ -67,6 +67,5 @@ function applyEnabledFeatures(mlCaps: MlCapabilities, enabledFeatures: MlFeature mlCaps.isADEnabled = enabledFeatures.ad; mlCaps.isDFAEnabled = enabledFeatures.dfa; mlCaps.isNLPEnabled = enabledFeatures.nlp; - mlCaps.canCloseJob = false; return mlCaps; } diff --git a/x-pack/plugins/ml/server/routes/filters.ts b/x-pack/plugins/ml/server/routes/filters.ts index 82a3ff0be0082..72bebe59529fd 100644 --- a/x-pack/plugins/ml/server/routes/filters.ts +++ b/x-pack/plugins/ml/server/routes/filters.ts @@ -55,26 +55,31 @@ export function filtersRoutes({ router, routeGuard }: RouteInitialization) { * @apiSuccess {Boolean} success * @apiSuccess {Object[]} filters list of filters */ - router.get( - { + router.versioned + .get({ path: `${ML_INTERNAL_BASE_PATH}/filters`, - validate: {}, + access: 'internal', options: { tags: ['access:ml:canGetFilters'], }, - }, - routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => { - try { - const resp = await getAllFilters(mlClient); - - return response.ok({ - body: resp, - }); - } catch (e) { - return response.customError(wrapError(e)); - } }) - ); + .addVersion( + { + version: '1', + validate: false, + }, + routeGuard.fullLicenseAPIGuard(async ({ mlClient, response }) => { + try { + const resp = await getAllFilters(mlClient); + + return response.ok({ + body: resp, + }); + } catch (e) { + return response.customError(wrapError(e)); + } + }) + ); /** * @apiGroup Filters diff --git a/x-pack/plugins/ml/server/routes/job_service.ts b/x-pack/plugins/ml/server/routes/job_service.ts index 982396f34b1eb..cb8bbebd95d31 100644 --- a/x-pack/plugins/ml/server/routes/job_service.ts +++ b/x-pack/plugins/ml/server/routes/job_service.ts @@ -298,7 +298,7 @@ export function jobServiceRoutes({ router, routeGuard }: RouteInitialization) { path: `${ML_INTERNAL_BASE_PATH}/jobs/jobs_summary`, access: 'internal', options: { - tags: ['access:ml:canCloseJob'], + tags: ['access:ml:canGetJobs'], }, }) .addVersion( From ae9b242e333ccfc553eb3aa7f9ad9cd0154585b7 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Sat, 10 Jun 2023 13:25:53 +0000 Subject: [PATCH 03/30] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- x-pack/plugins/serverless_observability/tsconfig.json | 1 + x-pack/plugins/serverless_search/tsconfig.json | 1 + x-pack/plugins/serverless_security/tsconfig.json | 1 + 3 files changed, 3 insertions(+) diff --git a/x-pack/plugins/serverless_observability/tsconfig.json b/x-pack/plugins/serverless_observability/tsconfig.json index 7972b5ccced81..e6badd0c4c072 100644 --- a/x-pack/plugins/serverless_observability/tsconfig.json +++ b/x-pack/plugins/serverless_observability/tsconfig.json @@ -21,5 +21,6 @@ "@kbn/observability-shared-plugin", "@kbn/kibana-react-plugin", "@kbn/shared-ux-chrome-navigation", + "@kbn/ml-plugin", ] } diff --git a/x-pack/plugins/serverless_search/tsconfig.json b/x-pack/plugins/serverless_search/tsconfig.json index c9cd5562ff562..5d5d9c8d70b21 100644 --- a/x-pack/plugins/serverless_search/tsconfig.json +++ b/x-pack/plugins/serverless_search/tsconfig.json @@ -27,5 +27,6 @@ "@kbn/security-plugin", "@kbn/cloud-plugin", "@kbn/share-plugin", + "@kbn/ml-plugin", ] } diff --git a/x-pack/plugins/serverless_security/tsconfig.json b/x-pack/plugins/serverless_security/tsconfig.json index 64e6c6cb48ed2..e7d5353f2b0fe 100644 --- a/x-pack/plugins/serverless_security/tsconfig.json +++ b/x-pack/plugins/serverless_security/tsconfig.json @@ -29,5 +29,6 @@ "@kbn/shared-ux-page-kibana-template", "@kbn/features-plugin", "@kbn/ess-security", + "@kbn/ml-plugin", ] } From 186450e67e6afece9cfcee00c1b2779e820c23d0 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Sat, 10 Jun 2023 14:37:26 +0100 Subject: [PATCH 04/30] adding type keyword --- .../plugins/serverless_observability/public/plugin.ts | 4 ++-- .../plugins/serverless_observability/public/types.ts | 4 ++-- .../plugins/serverless_observability/server/plugin.ts | 4 ++-- x-pack/plugins/serverless_search/public/plugin.ts | 4 ++-- x-pack/plugins/serverless_search/public/types.ts | 10 +++++----- x-pack/plugins/serverless_search/server/plugin.ts | 2 +- x-pack/plugins/serverless_security/public/plugin.ts | 4 ++-- x-pack/plugins/serverless_security/server/plugin.ts | 6 +++--- x-pack/plugins/serverless_security/server/types.ts | 2 +- 9 files changed, 20 insertions(+), 20 deletions(-) diff --git a/x-pack/plugins/serverless_observability/public/plugin.ts b/x-pack/plugins/serverless_observability/public/plugin.ts index 63a2ad9559b2f..9f9d3c89de1f4 100644 --- a/x-pack/plugins/serverless_observability/public/plugin.ts +++ b/x-pack/plugins/serverless_observability/public/plugin.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { getObservabilitySideNavComponent } from './components/side_navigation'; -import { +import type { ServerlessObservabilityPluginSetup, ServerlessObservabilityPluginStart, ServerlessObservabilityPluginSetupDependencies, diff --git a/x-pack/plugins/serverless_observability/public/types.ts b/x-pack/plugins/serverless_observability/public/types.ts index ba587011fc1e6..d20d46d7ec9c5 100644 --- a/x-pack/plugins/serverless_observability/public/types.ts +++ b/x-pack/plugins/serverless_observability/public/types.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; -import { +import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; +import type { ObservabilitySharedPluginSetup, ObservabilitySharedPluginStart, } from '@kbn/observability-shared-plugin/public'; diff --git a/x-pack/plugins/serverless_observability/server/plugin.ts b/x-pack/plugins/serverless_observability/server/plugin.ts index 7f706d7da5803..ae7bcd8baa064 100644 --- a/x-pack/plugins/serverless_observability/server/plugin.ts +++ b/x-pack/plugins/serverless_observability/server/plugin.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { PluginInitializerContext, Plugin, CoreSetup } from '@kbn/core/server'; +import type { PluginInitializerContext, Plugin, CoreSetup } from '@kbn/core/server'; -import { +import type { ServerlessObservabilityPluginSetup, ServerlessObservabilityPluginStart, SetupDependencies, diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts index d65207b422a28..68963e654ec66 100644 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import type { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { createServerlessSearchSideNavComponent as createComponent } from './layout/nav'; import { docLinks } from '../common/doc_links'; -import { +import type { ServerlessSearchPluginSetup, ServerlessSearchPluginSetupDependencies, ServerlessSearchPluginStart, diff --git a/x-pack/plugins/serverless_search/public/types.ts b/x-pack/plugins/serverless_search/public/types.ts index 01f77f5aaf515..688da36403437 100644 --- a/x-pack/plugins/serverless_search/public/types.ts +++ b/x-pack/plugins/serverless_search/public/types.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; -import { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public'; -import { SecurityPluginStart } from '@kbn/security-plugin/public'; -import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; -import { SharePluginStart } from '@kbn/share-plugin/public'; +import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/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'; +import type { SharePluginStart } from '@kbn/share-plugin/public'; import type { MlPluginSetup } from '@kbn/ml-plugin/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/x-pack/plugins/serverless_search/server/plugin.ts b/x-pack/plugins/serverless_search/server/plugin.ts index 0e8e4c11a49f9..6f0acd68502a6 100644 --- a/x-pack/plugins/serverless_search/server/plugin.ts +++ b/x-pack/plugins/serverless_search/server/plugin.ts @@ -16,7 +16,7 @@ import type { SecurityPluginStart } from '@kbn/security-plugin/server'; import { registerApiKeyRoutes } from './routes/api_key_routes'; import type { ServerlessSearchConfig } from './config'; -import { +import type { ServerlessSearchPluginSetup, ServerlessSearchPluginStart, SetupDependencies, diff --git a/x-pack/plugins/serverless_security/public/plugin.ts b/x-pack/plugins/serverless_security/public/plugin.ts index f3dc0cb1b1a83..249741a9639ce 100644 --- a/x-pack/plugins/serverless_security/public/plugin.ts +++ b/x-pack/plugins/serverless_security/public/plugin.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; +import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; import { getSecurityGetStartedComponent } from './components/get_started'; import { getSecuritySideNavComponent } from './components/side_navigation'; -import { +import type { ServerlessSecurityPluginSetup, ServerlessSecurityPluginStart, ServerlessSecurityPluginSetupDependencies, diff --git a/x-pack/plugins/serverless_security/server/plugin.ts b/x-pack/plugins/serverless_security/server/plugin.ts index c9d819e5a9af2..aae5106d9a0d2 100644 --- a/x-pack/plugins/serverless_security/server/plugin.ts +++ b/x-pack/plugins/serverless_security/server/plugin.ts @@ -5,11 +5,11 @@ * 2.0. */ -import { PluginInitializerContext, Plugin, CoreSetup } from '@kbn/core/server'; -import { ServerlessSecurityConfig } from './config'; +import type { PluginInitializerContext, Plugin, CoreSetup } from '@kbn/core/server'; +import type { ServerlessSecurityConfig } from './config'; import { getProductAppFeatures } from '../common/pli/pli_features'; -import { +import type { ServerlessSecurityPluginSetup, ServerlessSecurityPluginStart, ServerlessSecurityPluginSetupDependencies, diff --git a/x-pack/plugins/serverless_security/server/types.ts b/x-pack/plugins/serverless_security/server/types.ts index 2cadb19ba09ad..9cd615265338d 100644 --- a/x-pack/plugins/serverless_security/server/types.ts +++ b/x-pack/plugins/serverless_security/server/types.ts @@ -7,7 +7,7 @@ import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; import type { PluginSetupContract, PluginStartContract } from '@kbn/features-plugin/server'; -import { +import type { PluginSetup as SecuritySolutionPluginSetup, PluginStart as SecuritySolutionPluginStart, } from '@kbn/security-solution-plugin/server'; From a1661d480e7e3ff297405564f29eea5fa25afa00 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 13 Jun 2023 15:47:04 +0100 Subject: [PATCH 05/30] updating navigation menus for es and observability --- packages/shared-ux/chrome/navigation/index.ts | 1 + .../chrome/navigation/src/ui/index.ts | 2 +- .../navigation/src/ui/nav_tree_presets/ml.ts | 8 +- .../components/ml_page/ml_page.tsx | 2 + .../model_management/model_actions.tsx | 2 +- .../serverless_observability/kibana.jsonc | 2 +- .../components/side_navigation/index.tsx | 9 +- .../public/components/side_navigation/ml.ts | 119 ++++++++++++++++++ .../serverless_search/public/layout/ml.ts | 104 +++++++++++++++ .../serverless_search/public/layout/nav.tsx | 11 +- 10 files changed, 249 insertions(+), 11 deletions(-) create mode 100644 x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts create mode 100644 x-pack/plugins/serverless_search/public/layout/ml.ts diff --git a/packages/shared-ux/chrome/navigation/index.ts b/packages/shared-ux/chrome/navigation/index.ts index 13034398065a5..a2d704b0c0963 100644 --- a/packages/shared-ux/chrome/navigation/index.ts +++ b/packages/shared-ux/chrome/navigation/index.ts @@ -16,6 +16,7 @@ export type { NavigationGroupPreset, NavigationTreeDefinition, NodeDefinition, + NodeDefinitionWithChildren, ProjectNavigationDefinition, RecentlyAccessedDefinition, RootNavigationItemDefinition, diff --git a/packages/shared-ux/chrome/navigation/src/ui/index.ts b/packages/shared-ux/chrome/navigation/src/ui/index.ts index f0c63fda8e27f..8e454a6f339e8 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/index.ts +++ b/packages/shared-ux/chrome/navigation/src/ui/index.ts @@ -10,7 +10,7 @@ export { Navigation } from './components'; export { DefaultNavigation } from './default_navigation'; -export { getPresets } from './nav_tree_presets'; +export { getPresets, type NodeDefinitionWithChildren } from './nav_tree_presets'; export type { CloudLinkDefinition, diff --git a/packages/shared-ux/chrome/navigation/src/ui/nav_tree_presets/ml.ts b/packages/shared-ux/chrome/navigation/src/ui/nav_tree_presets/ml.ts index ba3b7e0645d67..b6f255e734aa6 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/nav_tree_presets/ml.ts +++ b/packages/shared-ux/chrome/navigation/src/ui/nav_tree_presets/ml.ts @@ -29,7 +29,8 @@ export type ID = | 'data_view' | 'aiops_labs' | 'explain_log_rate_spikes' - | 'log_pattern_analysis'; + | 'log_pattern_analysis' + | 'change_point_detection'; export const ml: NodeDefinitionWithChildren = { id: 'sharedux:ml', @@ -145,6 +146,11 @@ export const ml: NodeDefinitionWithChildren = { title: 'Log pattern analysis', href: '/app/ml/aiops/log_categorization_index_select', }, + { + id: 'change_point_detection', + title: 'Change Point Detection', + href: '/app/ml/aiops/change_point_detection_index_select', + }, ], }, ], diff --git a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx index 7ca6d776099c9..24cb7a2d03337 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx @@ -128,6 +128,8 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps className={'ml-app'} data-test-subj={'mlApp'} restrictWidth={false} + // forcing the background to white when in serverless + css={pageDeps.navMenuEnabled ? {} : { background: '#FFF' }} solutionNav={ pageDeps.navMenuEnabled ? { diff --git a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx index 1868ae0b8d85b..09ba11f56c747 100644 --- a/x-pack/plugins/ml/public/application/model_management/model_actions.tsx +++ b/x-pack/plugins/ml/public/application/model_management/model_actions.tsx @@ -80,7 +80,7 @@ export function useModelActions({ cluster: ['manage_ingest_pipelines'], }) .then((result) => { - const canManagePipelines = result.cluster.manage_ingest_pipelines; + const canManagePipelines = result.cluster?.manage_ingest_pipelines; if (isMounted) { setCanManageIngestPipelines(canManagePipelines); } diff --git a/x-pack/plugins/serverless_observability/kibana.jsonc b/x-pack/plugins/serverless_observability/kibana.jsonc index 3c493b23f5155..1ace753ce346f 100644 --- a/x-pack/plugins/serverless_observability/kibana.jsonc +++ b/x-pack/plugins/serverless_observability/kibana.jsonc @@ -8,7 +8,7 @@ "server": true, "browser": true, "configPath": ["xpack", "serverless", "observability"], - "requiredPlugins": ["serverless", "observabilityShared", "kibanaReact"], + "requiredPlugins": ["serverless", "observabilityShared", "kibanaReact", "ml"], "optionalPlugins": [], "requiredBundles": [] } diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index 7dadce3cdf1d4..1ae34d53d4791 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -5,15 +5,16 @@ * 2.0. */ -import { CoreStart } from '@kbn/core/public'; -import { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { CoreStart } from '@kbn/core/public'; +import type { ServerlessPluginStart } from '@kbn/serverless/public'; import { DefaultNavigation, NavigationKibanaProvider, - NavigationTreeDefinition, + type NavigationTreeDefinition, getPresets, } from '@kbn/shared-ux-chrome-navigation'; import React from 'react'; +import { ml } from './ml'; const navigationTree: NavigationTreeDefinition = { body: [ @@ -108,7 +109,7 @@ const navigationTree: NavigationTreeDefinition = { }, { type: 'navGroup', - ...getPresets('ml'), + ...ml, }, ], footer: [ diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts b/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts new file mode 100644 index 0000000000000..975a91706114a --- /dev/null +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts @@ -0,0 +1,119 @@ +/* + * 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 { NodeDefinitionWithChildren } from '@kbn/shared-ux-chrome-navigation'; + +export type ID = + | 'sharedux:ml' + | 'root' + | 'overview' + | 'notifications' + | 'anomaly_detection' + | 'jobs' + | 'explorer' + | 'single_metric_viewer' + | 'settings' + | 'data_frame_analytics' + | 'results_explorer' + | 'analytics_map' + | 'model_management' + | 'trained_models' + | 'nodes' + | 'data_visualizer' + | 'file' + | 'data_view' + | 'aiops_labs' + | 'explain_log_rate_spikes' + | 'log_pattern_analysis' + | 'change_point_detection'; + +export const ml: NodeDefinitionWithChildren = { + id: 'sharedux:ml', + title: 'Machine learning', + icon: 'indexMapping', + children: [ + { + title: '', + id: 'root', + children: [ + // { + // id: 'overview', + // title: 'Overview', + // href: '/app/ml/overview', + // }, + { + id: 'notifications', + title: 'Notifications', + href: '/app/ml/notifications', + }, + ], + }, + { + title: 'Anomaly detection', + id: 'anomaly_detection', + children: [ + { + id: 'jobs', + title: 'Jobs', + href: '/app/ml/jobs', + }, + { + id: 'explorer', + title: 'Anomaly explorer', + href: '/app/ml/explorer', + }, + { + id: 'single_metric_viewer', + title: 'Single metric viewer', + href: '/app/ml/timeseriesexplorer', + }, + { + id: 'settings', + title: 'Settings', + href: '/app/ml/settings', + }, + ], + }, + { + id: 'data_visualizer', + title: 'Data visualizer', + children: [ + { + id: 'file', + title: 'File', + href: '/app/ml/filedatavisualizer', + }, + { + id: 'data_view', + title: 'Data view', + href: '/app/ml/datavisualizer_index_select', + }, + ], + }, + { + id: 'aiops_labs', + title: 'AIOps labs', + children: [ + { + id: 'explain_log_rate_spikes', + title: 'Explain log rate spikes', + href: '/app/ml/aiops/explain_log_rate_spikes_index_select', + }, + { + id: 'log_pattern_analysis', + title: 'Log pattern analysis', + href: '/app/ml/aiops/log_categorization_index_select', + }, + { + id: 'change_point_detection', + title: 'Change Point Detection', + href: '/app/ml/aiops/change_point_detection_index_select', + }, + ], + }, + ], +}; diff --git a/x-pack/plugins/serverless_search/public/layout/ml.ts b/x-pack/plugins/serverless_search/public/layout/ml.ts new file mode 100644 index 0000000000000..32b048d57be32 --- /dev/null +++ b/x-pack/plugins/serverless_search/public/layout/ml.ts @@ -0,0 +1,104 @@ +/* + * 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 { NodeDefinitionWithChildren } from '@kbn/shared-ux-chrome-navigation'; + +export type ID = + | 'sharedux:ml' + | 'root' + | 'overview' + | 'notifications' + | 'anomaly_detection' + | 'jobs' + | 'explorer' + | 'single_metric_viewer' + | 'settings' + | 'data_frame_analytics' + | 'results_explorer' + | 'analytics_map' + | 'model_management' + | 'trained_models' + | 'nodes' + | 'data_visualizer' + | 'file' + | 'data_view' + | 'aiops_labs' + | 'explain_log_rate_spikes' + | 'log_pattern_analysis' + | 'change_point_detection'; + +export const ml: NodeDefinitionWithChildren = { + id: 'sharedux:ml', + title: 'Machine learning', + icon: 'indexMapping', + children: [ + { + title: '', + id: 'root', + children: [ + // { + // id: 'overview', + // title: 'Overview', + // href: '/app/ml/overview', + // }, + { + id: 'notifications', + title: 'Notifications', + href: '/app/ml/notifications', + }, + ], + }, + { + id: 'model_management', + title: 'Model management', + children: [ + { + id: 'trained_models', + title: 'Trained models', + href: '/app/ml/trained_models', + }, + ], + }, + { + id: 'data_visualizer', + title: 'Data visualizer', + children: [ + { + id: 'file', + title: 'File', + href: '/app/ml/filedatavisualizer', + }, + { + id: 'data_view', + title: 'Data view', + href: '/app/ml/datavisualizer_index_select', + }, + ], + }, + { + id: 'aiops_labs', + title: 'AIOps labs', + children: [ + { + id: 'explain_log_rate_spikes', + title: 'Explain log rate spikes', + href: '/app/ml/aiops/explain_log_rate_spikes_index_select', + }, + { + id: 'log_pattern_analysis', + title: 'Log pattern analysis', + href: '/app/ml/aiops/log_categorization_index_select', + }, + { + id: 'change_point_detection', + title: 'Change Point Detection', + href: '/app/ml/aiops/change_point_detection_index_select', + }, + ], + }, + ], +}; diff --git a/x-pack/plugins/serverless_search/public/layout/nav.tsx b/x-pack/plugins/serverless_search/public/layout/nav.tsx index 409c46ba68490..2a86aa5847b61 100644 --- a/x-pack/plugins/serverless_search/public/layout/nav.tsx +++ b/x-pack/plugins/serverless_search/public/layout/nav.tsx @@ -5,16 +5,17 @@ * 2.0. */ -import { CoreStart } from '@kbn/core/public'; +import type { CoreStart } from '@kbn/core/public'; import { DefaultNavigation, NavigationKibanaProvider, - NavigationTreeDefinition, + type NavigationTreeDefinition, getPresets, } from '@kbn/shared-ux-chrome-navigation'; import React from 'react'; import { i18n } from '@kbn/i18n'; -import { ServerlessPluginStart } from '@kbn/serverless/public'; +import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import { ml } from './ml'; const devTools = getPresets('devtools'); @@ -121,6 +122,10 @@ const navigationTree: NavigationTreeDefinition = { }, ], }, + { + type: 'navGroup', + ...ml, + }, ], }; From 5ad8f6170c0f74d739090bf0e9db4c413ed93941 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 13 Jun 2023 17:03:13 +0100 Subject: [PATCH 06/30] updating capabilities switcher --- .../plugins/ml/common/types/capabilities.ts | 51 ++++++++++++++++++- .../lib/capabilities/capabilities_switcher.ts | 19 ++++++- 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index 15890021d05d7..766a958a2f061 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -92,11 +92,11 @@ export type AdminMlCapabilities = typeof adminMlCapabilities; export type MlCapabilities = FeatureMlCapabilities & UserMlCapabilities & AdminMlCapabilities; export type MlCapabilitiesKey = keyof MlCapabilities; -export const basicLicenseMlCapabilities = [ +export const basicLicenseMlCapabilities: MlCapabilitiesKey[] = [ 'canFindFileStructure', 'canGetFieldInfo', 'canGetMlInfo', -] as Array; +]; export function getDefaultCapabilities(): MlCapabilities { return { @@ -198,3 +198,50 @@ export interface MlCapabilitiesResponse { } export type ResolveMlCapabilities = (request: KibanaRequest) => Promise; + +interface FeatureCapabilities { + ad: MlCapabilitiesKey[]; + dfa: MlCapabilitiesKey[]; + nlp: MlCapabilitiesKey[]; +} + +export const featureCapabilities: FeatureCapabilities = { + ad: [ + 'canGetJobs', + 'canGetDatafeeds', + 'canGetCalendars', + 'canGetAnnotations', + 'canCreateAnnotation', + 'canDeleteAnnotation', + 'canCreateJob', + 'canDeleteJob', + 'canOpenJob', + 'canCloseJob', + 'canResetJob', + 'canUpdateJob', + 'canForecastJob', + 'canCreateDatafeed', + 'canDeleteDatafeed', + 'canStartStopDatafeed', + 'canUpdateDatafeed', + 'canPreviewDatafeed', + 'canGetFilters', + 'canCreateCalendar', + 'canDeleteCalendar', + 'canCreateFilter', + 'canDeleteFilter', + ], + dfa: [ + 'canGetDataFrameAnalytics', + 'canCreateDataFrameAnalytics', + 'canDeleteDataFrameAnalytics', + 'canStartStopDataFrameAnalytics', + ], + nlp: [ + 'canGetTrainedModels', + 'canTestTrainedModels', + 'canCreateTrainedModels', + 'canDeleteTrainedModels', + 'canStartStopTrainedModels', + ], +}; diff --git a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts index 8ef4ea9e3b8e0..095e64a46aed7 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts @@ -10,7 +10,11 @@ import { firstValueFrom, Observable } from 'rxjs'; import { CapabilitiesSwitcher, CoreSetup, Logger } from '@kbn/core/server'; import { ILicense } from '@kbn/licensing-plugin/common/types'; import { isFullLicense, isMinimumLicense, isMlEnabled } from '../../../common/license'; -import { MlCapabilities, basicLicenseMlCapabilities } from '../../../common/types/capabilities'; +import { + MlCapabilities, + basicLicenseMlCapabilities, + featureCapabilities, +} from '../../../common/types/capabilities'; import { MlFeatures } from '../../types'; export const setupCapabilitiesSwitcher = ( @@ -45,7 +49,7 @@ function getSwitcher( return { ml: applyEnabledFeatures(mlCaps, enabledFeatures) }; } - // not full licence, switch off all capabilities + // not full license, switch off all capabilities Object.keys(mlCaps).forEach((k) => { mlCaps[k as keyof MlCapabilities] = false; }); @@ -67,5 +71,16 @@ function applyEnabledFeatures(mlCaps: MlCapabilities, enabledFeatures: MlFeature mlCaps.isADEnabled = enabledFeatures.ad; mlCaps.isDFAEnabled = enabledFeatures.dfa; mlCaps.isNLPEnabled = enabledFeatures.nlp; + + if (enabledFeatures.ad === false) { + featureCapabilities.ad.forEach((c) => (mlCaps[c] = false)); + } + if (enabledFeatures.dfa === false) { + featureCapabilities.dfa.forEach((c) => (mlCaps[c] = false)); + } + if (enabledFeatures.nlp === false) { + featureCapabilities.nlp.forEach((c) => (mlCaps[c] = false)); + } + return mlCaps; } From 8b70ee044960f3a0b1a43af42c4faf894d623fe8 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 13 Jun 2023 17:09:46 +0100 Subject: [PATCH 07/30] correcting icon --- .../shared-ux/chrome/navigation/src/ui/nav_tree_presets/ml.ts | 2 +- .../public/components/side_navigation/ml.ts | 2 +- x-pack/plugins/serverless_search/public/layout/ml.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/shared-ux/chrome/navigation/src/ui/nav_tree_presets/ml.ts b/packages/shared-ux/chrome/navigation/src/ui/nav_tree_presets/ml.ts index b6f255e734aa6..da8f97a583eff 100644 --- a/packages/shared-ux/chrome/navigation/src/ui/nav_tree_presets/ml.ts +++ b/packages/shared-ux/chrome/navigation/src/ui/nav_tree_presets/ml.ts @@ -35,7 +35,7 @@ export type ID = export const ml: NodeDefinitionWithChildren = { id: 'sharedux:ml', title: 'Machine learning', - icon: 'indexMapping', + icon: 'machineLearningApp', children: [ { title: '', diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts b/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts index 975a91706114a..4879fbcad76ce 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts @@ -34,7 +34,7 @@ export type ID = export const ml: NodeDefinitionWithChildren = { id: 'sharedux:ml', title: 'Machine learning', - icon: 'indexMapping', + icon: 'machineLearningApp', children: [ { title: '', diff --git a/x-pack/plugins/serverless_search/public/layout/ml.ts b/x-pack/plugins/serverless_search/public/layout/ml.ts index 32b048d57be32..c376ffb75403d 100644 --- a/x-pack/plugins/serverless_search/public/layout/ml.ts +++ b/x-pack/plugins/serverless_search/public/layout/ml.ts @@ -34,7 +34,7 @@ export type ID = export const ml: NodeDefinitionWithChildren = { id: 'sharedux:ml', title: 'Machine learning', - icon: 'indexMapping', + icon: 'machineLearningApp', children: [ { title: '', From 9509dba10de7b0e2331e0213a2f73887e267e36c Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 14 Jun 2023 13:16:29 +0100 Subject: [PATCH 08/30] registering deeplinks based on features --- packages/default-nav/ml/default_navigation.ts | 22 +- packages/shared-ux/chrome/navigation/index.ts | 1 - .../chrome/navigation/src/ui/index.ts | 2 +- x-pack/plugins/ml/public/plugin.ts | 3 +- .../register_search_links.ts | 6 +- .../search_deep_links.ts | 462 +++++++++++------- .../components/side_navigation/index.tsx | 3 +- .../public/components/side_navigation/ml.ts | 119 ----- .../serverless_search/public/layout/ml.ts | 104 ---- .../serverless_search/public/layout/nav.tsx | 3 +- 10 files changed, 292 insertions(+), 433 deletions(-) delete mode 100644 x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts delete mode 100644 x-pack/plugins/serverless_search/public/layout/ml.ts diff --git a/packages/default-nav/ml/default_navigation.ts b/packages/default-nav/ml/default_navigation.ts index 166307439ca8f..0a371d8051717 100644 --- a/packages/default-nav/ml/default_navigation.ts +++ b/packages/default-nav/ml/default_navigation.ts @@ -23,9 +23,9 @@ export type MlNodeDefinition = NodeDefinitionWithChildren { } if (mlEnabled) { - registerSearchLinks(this.appUpdater$, fullLicense); + registerSearchLinks(this.appUpdater$, fullLicense, capabilities.ml as MlCapabilities); if (fullLicense) { registerEmbeddables(pluginsSetup.embeddable, core); diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts index a25d7e24a7274..8fce0d36fa630 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts @@ -10,10 +10,12 @@ import { BehaviorSubject } from 'rxjs'; import { AppUpdater } from '@kbn/core/public'; import { getDeepLinks } from './search_deep_links'; +import { MlCapabilities } from '../../shared'; export function registerSearchLinks( appUpdater: BehaviorSubject, - isFullLicense: boolean + isFullLicense: boolean, + mlCapabilities: MlCapabilities ) { appUpdater.next(() => ({ keywords: [ @@ -21,6 +23,6 @@ export function registerSearchLinks( defaultMessage: 'ML', }), ], - deepLinks: getDeepLinks(isFullLicense), + deepLinks: getDeepLinks(isFullLicense, mlCapabilities), })); } diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index d892c949b1d52..926929ba500c6 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -8,203 +8,285 @@ import { i18n } from '@kbn/i18n'; import type { LinkId } from '@kbn/deeplinks-ml'; -import type { AppDeepLink } from '@kbn/core/public'; +import { AppDeepLink, AppNavLinkStatus } from '@kbn/core/public'; import { ML_PAGES } from '../../../common/constants/locator'; +import { MlCapabilities } from '../../shared'; -const OVERVIEW_LINK_DEEP_LINK: AppDeepLink = { - id: 'overview', - title: i18n.translate('xpack.ml.deepLink.overview', { - defaultMessage: 'Overview', - }), - path: `/${ML_PAGES.OVERVIEW}`, -}; - -const ANOMALY_DETECTION_DEEP_LINK: AppDeepLink = { - id: 'anomalyDetection', - title: i18n.translate('xpack.ml.deepLink.anomalyDetection', { - defaultMessage: 'Anomaly Detection', - }), - path: `/${ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE}`, - deepLinks: [ - { - id: 'anomalyExplorer', - title: i18n.translate('xpack.ml.deepLink.anomalyExplorer', { - defaultMessage: 'Anomaly explorer', - }), - path: `/${ML_PAGES.ANOMALY_EXPLORER}`, - }, - { - id: 'singleMetricViewer', - title: i18n.translate('xpack.ml.deepLink.singleMetricViewer', { - defaultMessage: 'Single metric viewer', - }), - path: `/${ML_PAGES.SINGLE_METRIC_VIEWER}`, - }, - ], -}; - -const DATA_FRAME_ANALYTICS_DEEP_LINK: AppDeepLink = { - id: 'dataFrameAnalytics', - title: i18n.translate('xpack.ml.deepLink.dataFrameAnalytics', { - defaultMessage: 'Data Frame Analytics', - }), - path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE}`, - deepLinks: [ - { - id: 'resultExplorer', - title: i18n.translate('xpack.ml.deepLink.resultExplorer', { - defaultMessage: 'Results explorer', - }), - path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_EXPLORATION}`, - }, - { - id: 'analyticsMap', - title: i18n.translate('xpack.ml.deepLink.analyticsMap', { - defaultMessage: 'Analytics map', - }), - path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_MAP}`, - }, - ], -}; - -const AIOPS_DEEP_LINK: AppDeepLink = { - id: 'aiOps', - title: i18n.translate('xpack.ml.deepLink.aiOps', { - defaultMessage: 'AIOps', - }), - // Default to the index select page for the explain log rate spikes since we don't have an AIops overview page - path: `/${ML_PAGES.AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT}`, - deepLinks: [ - { - id: 'explainLogRateSpikes', - title: i18n.translate('xpack.ml.deepLink.explainLogRateSpikes', { - defaultMessage: 'Explain Log Rate Spikes', - }), - path: `/${ML_PAGES.AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT}`, - }, - { - id: 'logPatternAnalysis', - title: i18n.translate('xpack.ml.deepLink.logPatternAnalysis', { - defaultMessage: 'Log Pattern Analysis', - }), - path: `/${ML_PAGES.AIOPS_LOG_CATEGORIZATION_INDEX_SELECT}`, - }, - { - id: 'changePointDetections', - title: i18n.translate('xpack.ml.deepLink.changePointDetection', { - defaultMessage: 'Change Point Detection', - }), - path: `/${ML_PAGES.AIOPS_CHANGE_POINT_DETECTION_INDEX_SELECT}`, - }, - ], -}; - -const MODEL_MANAGEMENT_DEEP_LINK: AppDeepLink = { - id: 'modelManagement', - title: i18n.translate('xpack.ml.deepLink.modelManagement', { - defaultMessage: 'Model Management', - }), - path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, - deepLinks: [ - { - id: 'nodesOverview', - title: i18n.translate('xpack.ml.deepLink.trainedModels', { - defaultMessage: 'Trained Models', - }), - path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, - }, - { - id: 'nodes', - title: i18n.translate('xpack.ml.deepLink.nodes', { - defaultMessage: 'Nodes', - }), - path: `/${ML_PAGES.NODES}`, - }, - ], -}; - -const MEMORY_USAGE_DEEP_LINK: AppDeepLink = { - id: 'memoryUsage', - title: i18n.translate('xpack.ml.deepLink.memoryUsage', { - defaultMessage: 'Memory Usage', - }), - path: `/${ML_PAGES.MEMORY_USAGE}`, -}; - -const DATA_VISUALIZER_DEEP_LINK: AppDeepLink = { - id: 'dataVisualizer', - title: i18n.translate('xpack.ml.deepLink.dataVisualizer', { - defaultMessage: 'Data Visualizer', - }), - path: `/${ML_PAGES.DATA_VISUALIZER}`, -}; - -const FILE_UPLOAD_DEEP_LINK: AppDeepLink = { - id: 'fileUpload', - title: i18n.translate('xpack.ml.deepLink.fileUpload', { - defaultMessage: 'File Upload', - }), - keywords: ['CSV', 'JSON'], - path: `/${ML_PAGES.DATA_VISUALIZER_FILE}`, -}; - -const INDEX_DATA_VISUALIZER_DEEP_LINK: AppDeepLink = { - id: 'indexDataVisualizer', - title: i18n.translate('xpack.ml.deepLink.indexDataVisualizer', { - defaultMessage: 'Index Data Visualizer', - }), - path: `/${ML_PAGES.DATA_VISUALIZER_INDEX_SELECT}`, -}; - -const SETTINGS_DEEP_LINK: AppDeepLink = { - id: 'settings', - title: i18n.translate('xpack.ml.deepLink.settings', { - defaultMessage: 'Settings', - }), - path: `/${ML_PAGES.SETTINGS}`, - deepLinks: [ - { - id: 'calendarSettings', - title: i18n.translate('xpack.ml.deepLink.calendarSettings', { - defaultMessage: 'Calendars', - }), - path: `/${ML_PAGES.CALENDARS_MANAGE}`, - }, - { - id: 'filterListsSettings', - title: i18n.translate('xpack.ml.deepLink.filterListsSettings', { - defaultMessage: 'Filter Lists', - }), - path: `/${ML_PAGES.SETTINGS}`, // Link to settings page as read only users cannot view filter lists. - }, - ], -}; - -const NOTIFICATIONS_DEEP_LINK: AppDeepLink = { - id: 'notifications', - title: i18n.translate('xpack.ml.deepLink.notifications', { - defaultMessage: 'Notifications', - }), - path: `/${ML_PAGES.NOTIFICATIONS}`, -}; - -export function getDeepLinks(isFullLicense: boolean) { +function getOverviewLinkDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'overview', + title: i18n.translate('xpack.ml.deepLink.overview', { + defaultMessage: 'Overview', + }), + path: `/${ML_PAGES.OVERVIEW}`, + navLinkStatus: + mlCapabilities.isADEnabled && mlCapabilities.isDFAEnabled && mlCapabilities.isNLPEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }; +} + +function getAnomalyDetectionDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'anomalyDetection', + title: i18n.translate('xpack.ml.deepLink.anomalyDetection', { + defaultMessage: 'Anomaly Detection', + }), + path: `/${ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE}`, + navLinkStatus: mlCapabilities.isADEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + deepLinks: [ + { + id: 'anomalyExplorer', + title: i18n.translate('xpack.ml.deepLink.anomalyExplorer', { + defaultMessage: 'Anomaly explorer', + }), + path: `/${ML_PAGES.ANOMALY_EXPLORER}`, + navLinkStatus: mlCapabilities.isADEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + { + id: 'singleMetricViewer', + title: i18n.translate('xpack.ml.deepLink.singleMetricViewer', { + defaultMessage: 'Single metric viewer', + }), + path: `/${ML_PAGES.SINGLE_METRIC_VIEWER}`, + navLinkStatus: mlCapabilities.isADEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + ], + }; +} + +function getDataFrameAnalyticsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'dataFrameAnalytics', + title: i18n.translate('xpack.ml.deepLink.dataFrameAnalytics', { + defaultMessage: 'Data Frame Analytics', + }), + path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE}`, + navLinkStatus: mlCapabilities.isDFAEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + deepLinks: [ + { + id: 'resultExplorer', + title: i18n.translate('xpack.ml.deepLink.resultExplorer', { + defaultMessage: 'Results explorer', + }), + path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_EXPLORATION}`, + navLinkStatus: mlCapabilities.isDFAEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + { + id: 'analyticsMap', + title: i18n.translate('xpack.ml.deepLink.analyticsMap', { + defaultMessage: 'Analytics map', + }), + path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_MAP}`, + navLinkStatus: mlCapabilities.isDFAEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + ], + }; +} + +function getAiopsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'aiOps', + title: i18n.translate('xpack.ml.deepLink.aiOps', { + defaultMessage: 'AIOps', + }), + // Default to the index select page for the explain log rate spikes since we don't have an AIops overview page + path: `/${ML_PAGES.AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT}`, + navLinkStatus: mlCapabilities.canUseAiops ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + deepLinks: [ + { + id: 'explainLogRateSpikes', + title: i18n.translate('xpack.ml.deepLink.explainLogRateSpikes', { + defaultMessage: 'Explain Log Rate Spikes', + }), + path: `/${ML_PAGES.AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT}`, + navLinkStatus: mlCapabilities.canUseAiops + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + { + id: 'logPatternAnalysis', + title: i18n.translate('xpack.ml.deepLink.logPatternAnalysis', { + defaultMessage: 'Log Pattern Analysis', + }), + path: `/${ML_PAGES.AIOPS_LOG_CATEGORIZATION_INDEX_SELECT}`, + navLinkStatus: mlCapabilities.canUseAiops + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + { + id: 'changePointDetections', + title: i18n.translate('xpack.ml.deepLink.changePointDetection', { + defaultMessage: 'Change Point Detection', + }), + path: `/${ML_PAGES.AIOPS_CHANGE_POINT_DETECTION_INDEX_SELECT}`, + navLinkStatus: mlCapabilities.canUseAiops + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + ], + }; +} + +function getModelManagementDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'modelManagement', + title: i18n.translate('xpack.ml.deepLink.modelManagement', { + defaultMessage: 'Model Management', + }), + path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, + navLinkStatus: mlCapabilities.isNLPEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + deepLinks: [ + { + id: 'nodesOverview', + title: i18n.translate('xpack.ml.deepLink.trainedModels', { + defaultMessage: 'Trained Models', + }), + path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, + navLinkStatus: mlCapabilities.isNLPEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + { + id: 'nodes', + title: i18n.translate('xpack.ml.deepLink.nodes', { + defaultMessage: 'Nodes', + }), + path: `/${ML_PAGES.NODES}`, + navLinkStatus: mlCapabilities.isNLPEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + ], + }; +} + +function getMemoryUsageDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'memoryUsage', + title: i18n.translate('xpack.ml.deepLink.memoryUsage', { + defaultMessage: 'Memory Usage', + }), + path: `/${ML_PAGES.MEMORY_USAGE}`, + navLinkStatus: + mlCapabilities.isADEnabled && mlCapabilities.isDFAEnabled && mlCapabilities.isNLPEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }; +} + +function getDataVisualizerDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'dataVisualizer', + title: i18n.translate('xpack.ml.deepLink.dataVisualizer', { + defaultMessage: 'Data Visualizer', + }), + path: `/${ML_PAGES.DATA_VISUALIZER}`, + navLinkStatus: + mlCapabilities.isADEnabled && mlCapabilities.isDFAEnabled && mlCapabilities.isNLPEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }; +} + +function getFileUploadDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'fileUpload', + title: i18n.translate('xpack.ml.deepLink.fileUpload', { + defaultMessage: 'File Upload', + }), + keywords: ['CSV', 'JSON'], + path: `/${ML_PAGES.DATA_VISUALIZER_FILE}`, + navLinkStatus: + mlCapabilities.isADEnabled && mlCapabilities.isDFAEnabled && mlCapabilities.isNLPEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }; +} + +function getIndexDataVisualizerDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'indexDataVisualizer', + title: i18n.translate('xpack.ml.deepLink.indexDataVisualizer', { + defaultMessage: 'Index Data Visualizer', + }), + path: `/${ML_PAGES.DATA_VISUALIZER_INDEX_SELECT}`, + navLinkStatus: + mlCapabilities.isADEnabled && mlCapabilities.isDFAEnabled && mlCapabilities.isNLPEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }; +} + +function getSettingsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'settings', + title: i18n.translate('xpack.ml.deepLink.settings', { + defaultMessage: 'Settings', + }), + path: `/${ML_PAGES.SETTINGS}`, + navLinkStatus: mlCapabilities.isADEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + deepLinks: [ + { + id: 'calendarSettings', + title: i18n.translate('xpack.ml.deepLink.calendarSettings', { + defaultMessage: 'Calendars', + }), + path: `/${ML_PAGES.CALENDARS_MANAGE}`, + navLinkStatus: mlCapabilities.isADEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + { + id: 'filterListsSettings', + title: i18n.translate('xpack.ml.deepLink.filterListsSettings', { + defaultMessage: 'Filter Lists', + }), + path: `/${ML_PAGES.SETTINGS}`, // Link to settings page as read only users cannot view filter lists. + navLinkStatus: mlCapabilities.isADEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, + }, + ], + }; +} + +function getNotificationsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + return { + id: 'notifications', + title: i18n.translate('xpack.ml.deepLink.notifications', { + defaultMessage: 'Notifications', + }), + path: `/${ML_PAGES.NOTIFICATIONS}`, + navLinkStatus: AppNavLinkStatus.visible, + }; +} + +export function getDeepLinks(isFullLicense: boolean, mlCapabilities: MlCapabilities) { const deepLinks: Array> = [ - DATA_VISUALIZER_DEEP_LINK, - FILE_UPLOAD_DEEP_LINK, - INDEX_DATA_VISUALIZER_DEEP_LINK, + getDataVisualizerDeepLink(mlCapabilities), + getFileUploadDeepLink(mlCapabilities), + getIndexDataVisualizerDeepLink(mlCapabilities), ]; if (isFullLicense === true) { deepLinks.push( - OVERVIEW_LINK_DEEP_LINK, - ANOMALY_DETECTION_DEEP_LINK, - DATA_FRAME_ANALYTICS_DEEP_LINK, - MODEL_MANAGEMENT_DEEP_LINK, - MEMORY_USAGE_DEEP_LINK, - SETTINGS_DEEP_LINK, - AIOPS_DEEP_LINK, - NOTIFICATIONS_DEEP_LINK + getOverviewLinkDeepLink(mlCapabilities), + getAnomalyDetectionDeepLink(mlCapabilities), + getDataFrameAnalyticsDeepLink(mlCapabilities), + getModelManagementDeepLink(mlCapabilities), + getMemoryUsageDeepLink(mlCapabilities), + getSettingsDeepLink(mlCapabilities), + getAiopsDeepLink(mlCapabilities), + getNotificationsDeepLink(mlCapabilities) ); } diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index 3b5d0dc1c91f4..fa6b7e222cb12 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -15,7 +15,6 @@ import { } from '@kbn/shared-ux-chrome-navigation'; import React from 'react'; import { i18n } from '@kbn/i18n'; -import { ml } from './ml'; const navigationTree: NavigationTreeDefinition = { body: [ @@ -103,7 +102,7 @@ const navigationTree: NavigationTreeDefinition = { }, { type: 'navGroup', - ...ml, + ...getPresets('ml'), }, ], footer: [ diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts b/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts deleted file mode 100644 index 4879fbcad76ce..0000000000000 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/ml.ts +++ /dev/null @@ -1,119 +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 { NodeDefinitionWithChildren } from '@kbn/shared-ux-chrome-navigation'; - -export type ID = - | 'sharedux:ml' - | 'root' - | 'overview' - | 'notifications' - | 'anomaly_detection' - | 'jobs' - | 'explorer' - | 'single_metric_viewer' - | 'settings' - | 'data_frame_analytics' - | 'results_explorer' - | 'analytics_map' - | 'model_management' - | 'trained_models' - | 'nodes' - | 'data_visualizer' - | 'file' - | 'data_view' - | 'aiops_labs' - | 'explain_log_rate_spikes' - | 'log_pattern_analysis' - | 'change_point_detection'; - -export const ml: NodeDefinitionWithChildren = { - id: 'sharedux:ml', - title: 'Machine learning', - icon: 'machineLearningApp', - children: [ - { - title: '', - id: 'root', - children: [ - // { - // id: 'overview', - // title: 'Overview', - // href: '/app/ml/overview', - // }, - { - id: 'notifications', - title: 'Notifications', - href: '/app/ml/notifications', - }, - ], - }, - { - title: 'Anomaly detection', - id: 'anomaly_detection', - children: [ - { - id: 'jobs', - title: 'Jobs', - href: '/app/ml/jobs', - }, - { - id: 'explorer', - title: 'Anomaly explorer', - href: '/app/ml/explorer', - }, - { - id: 'single_metric_viewer', - title: 'Single metric viewer', - href: '/app/ml/timeseriesexplorer', - }, - { - id: 'settings', - title: 'Settings', - href: '/app/ml/settings', - }, - ], - }, - { - id: 'data_visualizer', - title: 'Data visualizer', - children: [ - { - id: 'file', - title: 'File', - href: '/app/ml/filedatavisualizer', - }, - { - id: 'data_view', - title: 'Data view', - href: '/app/ml/datavisualizer_index_select', - }, - ], - }, - { - id: 'aiops_labs', - title: 'AIOps labs', - children: [ - { - id: 'explain_log_rate_spikes', - title: 'Explain log rate spikes', - href: '/app/ml/aiops/explain_log_rate_spikes_index_select', - }, - { - id: 'log_pattern_analysis', - title: 'Log pattern analysis', - href: '/app/ml/aiops/log_categorization_index_select', - }, - { - id: 'change_point_detection', - title: 'Change Point Detection', - href: '/app/ml/aiops/change_point_detection_index_select', - }, - ], - }, - ], -}; diff --git a/x-pack/plugins/serverless_search/public/layout/ml.ts b/x-pack/plugins/serverless_search/public/layout/ml.ts deleted file mode 100644 index c376ffb75403d..0000000000000 --- a/x-pack/plugins/serverless_search/public/layout/ml.ts +++ /dev/null @@ -1,104 +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 { NodeDefinitionWithChildren } from '@kbn/shared-ux-chrome-navigation'; - -export type ID = - | 'sharedux:ml' - | 'root' - | 'overview' - | 'notifications' - | 'anomaly_detection' - | 'jobs' - | 'explorer' - | 'single_metric_viewer' - | 'settings' - | 'data_frame_analytics' - | 'results_explorer' - | 'analytics_map' - | 'model_management' - | 'trained_models' - | 'nodes' - | 'data_visualizer' - | 'file' - | 'data_view' - | 'aiops_labs' - | 'explain_log_rate_spikes' - | 'log_pattern_analysis' - | 'change_point_detection'; - -export const ml: NodeDefinitionWithChildren = { - id: 'sharedux:ml', - title: 'Machine learning', - icon: 'machineLearningApp', - children: [ - { - title: '', - id: 'root', - children: [ - // { - // id: 'overview', - // title: 'Overview', - // href: '/app/ml/overview', - // }, - { - id: 'notifications', - title: 'Notifications', - href: '/app/ml/notifications', - }, - ], - }, - { - id: 'model_management', - title: 'Model management', - children: [ - { - id: 'trained_models', - title: 'Trained models', - href: '/app/ml/trained_models', - }, - ], - }, - { - id: 'data_visualizer', - title: 'Data visualizer', - children: [ - { - id: 'file', - title: 'File', - href: '/app/ml/filedatavisualizer', - }, - { - id: 'data_view', - title: 'Data view', - href: '/app/ml/datavisualizer_index_select', - }, - ], - }, - { - id: 'aiops_labs', - title: 'AIOps labs', - children: [ - { - id: 'explain_log_rate_spikes', - title: 'Explain log rate spikes', - href: '/app/ml/aiops/explain_log_rate_spikes_index_select', - }, - { - id: 'log_pattern_analysis', - title: 'Log pattern analysis', - href: '/app/ml/aiops/log_categorization_index_select', - }, - { - id: 'change_point_detection', - title: 'Change Point Detection', - href: '/app/ml/aiops/change_point_detection_index_select', - }, - ], - }, - ], -}; diff --git a/x-pack/plugins/serverless_search/public/layout/nav.tsx b/x-pack/plugins/serverless_search/public/layout/nav.tsx index 2b5a82a38b488..962960810fabd 100644 --- a/x-pack/plugins/serverless_search/public/layout/nav.tsx +++ b/x-pack/plugins/serverless_search/public/layout/nav.tsx @@ -15,7 +15,6 @@ import { import React from 'react'; import { i18n } from '@kbn/i18n'; import type { ServerlessPluginStart } from '@kbn/serverless/public'; -import { ml } from './ml'; const navigationTree: NavigationTreeDefinition = { body: [ @@ -103,7 +102,7 @@ const navigationTree: NavigationTreeDefinition = { }, { type: 'navGroup', - ...ml, + ...getPresets('ml'), }, ], }; From ccca70899b8baba2e216a4766fdd5d0a3682be6d Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 14 Jun 2023 13:46:59 +0100 Subject: [PATCH 09/30] fixing types --- x-pack/plugins/ml/public/mocks.ts | 1 + x-pack/plugins/ml/server/plugin.ts | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/ml/public/mocks.ts b/x-pack/plugins/ml/public/mocks.ts index 13f8952dbad21..5883efca2fc02 100644 --- a/x-pack/plugins/ml/public/mocks.ts +++ b/x-pack/plugins/ml/public/mocks.ts @@ -11,6 +11,7 @@ import { MlPluginSetup, MlPluginStart } from './plugin'; const createSetupContract = (): jest.Mocked => { return { locator: sharePluginMock.createLocator(), + setNavMenuEnabled: jest.fn(), }; }; diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index 1919ed5faf81f..7bafcf28f0ff8 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -73,10 +73,10 @@ import { CASE_ATTACHMENT_TYPE_ID_ANOMALY_EXPLORER_CHARTS, } from '../common/constants/cases'; -type SetFeatureEnabled = (features: MlFeatures) => void; +type SetFeaturesEnabled = (features: MlFeatures) => void; interface MlSetup { - setFeaturesEnabled: SetFeatureEnabled; + setFeaturesEnabled: SetFeaturesEnabled; } export type MlPluginSetup = SharedServices & MlSetup; From 1bd3ffb43ba627ed944f913893f0d0cbbd65f9cc Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Wed, 14 Jun 2023 14:42:23 +0100 Subject: [PATCH 10/30] disabling notifications --- packages/default-nav/ml/default_navigation.ts | 6 +++--- .../register_search_links/search_deep_links.ts | 5 ++++- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/packages/default-nav/ml/default_navigation.ts b/packages/default-nav/ml/default_navigation.ts index 0a371d8051717..5eb99482fd68c 100644 --- a/packages/default-nav/ml/default_navigation.ts +++ b/packages/default-nav/ml/default_navigation.ts @@ -34,9 +34,9 @@ export const defaultNavigation: MlNodeDefinition = { { link: 'ml:overview', }, - // { - // link: 'ml:notifications', - // }, + { + link: 'ml:notifications', + }, ], }, { diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index 926929ba500c6..fe0d25f8cc40f 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -266,7 +266,10 @@ function getNotificationsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink Date: Wed, 14 Jun 2023 16:59:58 +0100 Subject: [PATCH 11/30] fixing types --- .../routes/enterprise_search/indices.test.ts | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts index e80d9ed37d916..d3193b1855d6b 100644 --- a/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts +++ b/x-pack/plugins/enterprise_search/server/routes/enterprise_search/indices.test.ts @@ -8,9 +8,8 @@ import { MockRouter, mockDependencies } from '../../__mocks__'; import { RequestHandlerContext } from '@kbn/core/server'; -import { MlTrainedModels } from '@kbn/ml-plugin/server'; -import { SharedServices } from '@kbn/ml-plugin/server/shared_services'; +import type { MlPluginSetup, MlTrainedModels } from '@kbn/ml-plugin/server'; import { ErrorCode } from '../../../common/types/error_codes'; @@ -168,7 +167,7 @@ describe('Enterprise Search Managed Indices', () => { }); describe('GET /internal/enterprise_search/indices/{indexName}/ml_inference/pipeline_processors', () => { - let mockMl: SharedServices; + let mockMl: MlPluginSetup; let mockTrainedModelsProvider: MlTrainedModels; beforeEach(() => { @@ -195,7 +194,7 @@ describe('Enterprise Search Managed Indices', () => { mockMl = { trainedModelsProvider: () => Promise.resolve(mockTrainedModelsProvider), - } as unknown as jest.Mocked; + } as unknown as jest.Mocked; registerIndexRoutes({ ...mockDependencies, @@ -1069,7 +1068,7 @@ describe('Enterprise Search Managed Indices', () => { describe('GET /internal/enterprise_search/pipelines/ml_inference', () => { let mockTrainedModelsProvider: MlTrainedModels; - let mockMl: SharedServices; + let mockMl: MlPluginSetup; beforeEach(() => { const context = { @@ -1095,7 +1094,7 @@ describe('Enterprise Search Managed Indices', () => { mockMl = { trainedModelsProvider: () => Promise.resolve(mockTrainedModelsProvider), - } as unknown as jest.Mocked; + } as unknown as jest.Mocked; registerIndexRoutes({ ...mockDependencies, @@ -1134,7 +1133,7 @@ describe('Enterprise Search Managed Indices', () => { }); describe('POST /internal/enterprise_search/ml/models/{modelName}', () => { - let mockMl: SharedServices; + let mockMl: MlPluginSetup; let mockTrainedModelsProvider: MlTrainedModels; beforeEach(() => { @@ -1156,7 +1155,7 @@ describe('Enterprise Search Managed Indices', () => { mockMl = { trainedModelsProvider: () => Promise.resolve(mockTrainedModelsProvider), - } as unknown as jest.Mocked; + } as unknown as jest.Mocked; registerIndexRoutes({ ...mockDependencies, @@ -1198,7 +1197,7 @@ describe('Enterprise Search Managed Indices', () => { }); describe('POST /internal/enterprise_search/ml/models/{modelName}/deploy', () => { - let mockMl: SharedServices; + let mockMl: MlPluginSetup; let mockTrainedModelsProvider: MlTrainedModels; beforeEach(() => { @@ -1220,7 +1219,7 @@ describe('Enterprise Search Managed Indices', () => { mockMl = { trainedModelsProvider: () => Promise.resolve(mockTrainedModelsProvider), - } as unknown as jest.Mocked; + } as unknown as jest.Mocked; registerIndexRoutes({ ...mockDependencies, @@ -1262,7 +1261,7 @@ describe('Enterprise Search Managed Indices', () => { }); describe('GET /internal/enterprise_search/ml/models/{modelName}', () => { - let mockMl: SharedServices; + let mockMl: MlPluginSetup; let mockTrainedModelsProvider: MlTrainedModels; beforeEach(() => { @@ -1283,7 +1282,7 @@ describe('Enterprise Search Managed Indices', () => { mockMl = { trainedModelsProvider: () => Promise.resolve(mockTrainedModelsProvider), - } as unknown as jest.Mocked; + } as unknown as jest.Mocked; registerIndexRoutes({ ...mockDependencies, From f1e7ff8c3618212f5037f0e99e558691c099a188 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 19 Jun 2023 20:54:56 +0100 Subject: [PATCH 12/30] fixing mocked nav --- .../src/default_navigation.test.helpers.ts | 24 ++++++++++++++----- 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/packages/shared-ux/chrome/navigation/mocks/src/default_navigation.test.helpers.ts b/packages/shared-ux/chrome/navigation/mocks/src/default_navigation.test.helpers.ts index f850b79a588c7..64d051dc31ef4 100644 --- a/packages/shared-ux/chrome/navigation/mocks/src/default_navigation.test.helpers.ts +++ b/packages/shared-ux/chrome/navigation/mocks/src/default_navigation.test.helpers.ts @@ -67,8 +67,8 @@ export const defaultAnalyticsNavGroup = { export const defaultMlNavGroup = { id: 'rootNav:ml', - title: 'Machine learning', - icon: 'indexMapping', + title: 'Machine Learning', + icon: 'machineLearningApp', path: ['rootNav:ml'], children: [ { @@ -159,7 +159,7 @@ export const defaultMlNavGroup = { }, { id: 'data_frame_analytics', - title: 'Data frame analytics', + title: 'Data Frame Analytics', path: ['rootNav:ml', 'data_frame_analytics'], children: [ { @@ -202,7 +202,7 @@ export const defaultMlNavGroup = { }, { id: 'model_management', - title: 'Model management', + title: 'Model Management', path: ['rootNav:ml', 'model_management'], children: [ { @@ -233,7 +233,7 @@ export const defaultMlNavGroup = { }, { id: 'data_visualizer', - title: 'Data visualizer', + title: 'Data Visualizer', path: ['rootNav:ml', 'data_visualizer'], children: [ { @@ -268,7 +268,7 @@ export const defaultMlNavGroup = { path: ['rootNav:ml', 'aiops_labs'], children: [ { - title: 'Explain log rate spikes', + title: 'Deeplink ml:explainLogRateSpikes', id: 'ml:explainLogRateSpikes', path: ['rootNav:ml', 'aiops_labs', 'ml:explainLogRateSpikes'], deepLink: { @@ -291,6 +291,18 @@ export const defaultMlNavGroup = { url: '/mocked/ml:logPatternAnalysis', }, }, + { + id: 'ml:changePointDetections', + path: ['rootNav:ml', 'aiops_labs', 'ml:changePointDetections'], + title: 'Deeplink ml:changePointDetections', + deepLink: { + id: 'ml:changePointDetections', + title: 'Deeplink ml:changePointDetections', + href: 'http://mocked/ml:changePointDetections', + baseUrl: '/mocked', + url: '/mocked/ml:changePointDetections', + }, + }, ], }, ], From 98385e392d9e8e017fc0bb35e03ffb15a55ce6cf Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 19 Jun 2023 21:03:45 +0100 Subject: [PATCH 13/30] fixing capabilities tests --- .../capabilities/check_capabilities.test.ts | 26 ++++++++++++++++++- .../apis/ml/system/capabilities.ts | 8 +++++- .../apis/ml/system/space_capabilities.ts | 14 +++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts index 93e22c7e099ce..b66af28faff26 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/check_capabilities.test.ts @@ -47,7 +47,7 @@ describe('check_capabilities', () => { ); const { capabilities } = await getCapabilities(); const count = Object.keys(capabilities).length; - expect(count).toBe(39); + expect(count).toBe(42); }); }); @@ -105,6 +105,10 @@ describe('check_capabilities', () => { expect(capabilities.canCreateTrainedModels).toBe(false); expect(capabilities.canDeleteTrainedModels).toBe(false); expect(capabilities.canStartStopTrainedModels).toBe(false); + + expect(capabilities.isADEnabled).toBe(true); + expect(capabilities.isDFAEnabled).toBe(true); + expect(capabilities.isNLPEnabled).toBe(true); }); test('full capabilities', async () => { @@ -160,6 +164,10 @@ describe('check_capabilities', () => { expect(capabilities.canCreateTrainedModels).toBe(true); expect(capabilities.canDeleteTrainedModels).toBe(true); expect(capabilities.canStartStopTrainedModels).toBe(true); + + expect(capabilities.isADEnabled).toBe(true); + expect(capabilities.isDFAEnabled).toBe(true); + expect(capabilities.isNLPEnabled).toBe(true); }); test('upgrade in progress with full capabilities', async () => { @@ -215,6 +223,10 @@ describe('check_capabilities', () => { expect(capabilities.canCreateTrainedModels).toBe(false); expect(capabilities.canDeleteTrainedModels).toBe(false); expect(capabilities.canStartStopTrainedModels).toBe(false); + + expect(capabilities.isADEnabled).toBe(true); + expect(capabilities.isDFAEnabled).toBe(true); + expect(capabilities.isNLPEnabled).toBe(true); }); test('upgrade in progress with partial capabilities', async () => { @@ -270,6 +282,10 @@ describe('check_capabilities', () => { expect(capabilities.canCreateTrainedModels).toBe(false); expect(capabilities.canDeleteTrainedModels).toBe(false); expect(capabilities.canStartStopTrainedModels).toBe(false); + + expect(capabilities.isADEnabled).toBe(true); + expect(capabilities.isDFAEnabled).toBe(true); + expect(capabilities.isNLPEnabled).toBe(true); }); test('full capabilities, ml disabled in space', async () => { @@ -325,6 +341,10 @@ describe('check_capabilities', () => { expect(capabilities.canCreateTrainedModels).toBe(false); expect(capabilities.canDeleteTrainedModels).toBe(false); expect(capabilities.canStartStopTrainedModels).toBe(false); + + expect(capabilities.isADEnabled).toBe(true); + expect(capabilities.isDFAEnabled).toBe(true); + expect(capabilities.isNLPEnabled).toBe(true); }); }); @@ -381,5 +401,9 @@ describe('check_capabilities', () => { expect(capabilities.canCreateTrainedModels).toBe(false); expect(capabilities.canDeleteTrainedModels).toBe(false); expect(capabilities.canStartStopTrainedModels).toBe(false); + + expect(capabilities.isADEnabled).toBe(true); + expect(capabilities.isDFAEnabled).toBe(true); + expect(capabilities.isNLPEnabled).toBe(true); }); }); diff --git a/x-pack/test/api_integration/apis/ml/system/capabilities.ts b/x-pack/test/api_integration/apis/ml/system/capabilities.ts index 814ebb7fbaa21..dcfeba197026c 100644 --- a/x-pack/test/api_integration/apis/ml/system/capabilities.ts +++ b/x-pack/test/api_integration/apis/ml/system/capabilities.ts @@ -12,7 +12,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; import { getCommonRequestHeader } from '../../../../functional/services/ml/common_api'; import { USER } from '../../../../functional/services/ml/security_common'; -const NUMBER_OF_CAPABILITIES = 39; +const NUMBER_OF_CAPABILITIES = 42; export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertestWithoutAuth'); @@ -93,6 +93,9 @@ export default ({ getService }: FtrProviderContext) => { canCreateTrainedModels: false, canDeleteTrainedModels: false, canStartStopTrainedModels: false, + isADEnabled: true, + isDFAEnabled: true, + isNLPEnabled: true, }); }); @@ -139,6 +142,9 @@ export default ({ getService }: FtrProviderContext) => { canCreateTrainedModels: true, canDeleteTrainedModels: true, canStartStopTrainedModels: true, + isADEnabled: true, + isDFAEnabled: true, + isNLPEnabled: true, }); }); }); diff --git a/x-pack/test/api_integration/apis/ml/system/space_capabilities.ts b/x-pack/test/api_integration/apis/ml/system/space_capabilities.ts index c746c6d316efa..f2c62a19886a0 100644 --- a/x-pack/test/api_integration/apis/ml/system/space_capabilities.ts +++ b/x-pack/test/api_integration/apis/ml/system/space_capabilities.ts @@ -15,7 +15,7 @@ import { USER } from '../../../../functional/services/ml/security_common'; const idSpaceWithMl = 'space_with_ml'; const idSpaceNoMl = 'space_no_ml'; -const NUMBER_OF_CAPABILITIES = 39; +const NUMBER_OF_CAPABILITIES = 42; export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertestWithoutAuth'); @@ -122,6 +122,9 @@ export default ({ getService }: FtrProviderContext) => { canCreateTrainedModels: false, canDeleteTrainedModels: false, canStartStopTrainedModels: false, + isADEnabled: true, + isDFAEnabled: true, + isNLPEnabled: true, }); }); @@ -167,6 +170,9 @@ export default ({ getService }: FtrProviderContext) => { canCreateTrainedModels: false, canDeleteTrainedModels: false, canStartStopTrainedModels: false, + isADEnabled: true, + isDFAEnabled: true, + isNLPEnabled: true, }); }); @@ -212,6 +218,9 @@ export default ({ getService }: FtrProviderContext) => { canCreateTrainedModels: true, canDeleteTrainedModels: true, canStartStopTrainedModels: true, + isADEnabled: true, + isDFAEnabled: true, + isNLPEnabled: true, }); }); @@ -257,6 +266,9 @@ export default ({ getService }: FtrProviderContext) => { canCreateTrainedModels: false, canDeleteTrainedModels: false, canStartStopTrainedModels: false, + isADEnabled: true, + isDFAEnabled: true, + isNLPEnabled: true, }); }); }); From fb48d6d9867ba7d11e5b2d7b88c5df98d33ba749 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 26 Jun 2023 10:04:28 +0100 Subject: [PATCH 14/30] filtering notifications based on type --- .../components/notifications_list.tsx | 10 +++--- .../search_deep_links.ts | 5 +-- .../notifications_service_provider.ts | 33 +++++++++++++------ x-pack/plugins/ml/server/plugin.ts | 1 + .../plugins/ml/server/routes/notifications.ts | 14 ++++++-- x-pack/plugins/ml/server/types.ts | 1 + 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/ml/public/application/notifications/components/notifications_list.tsx b/x-pack/plugins/ml/public/application/notifications/components/notifications_list.tsx index 7b08bcec0331f..4c04333b71e61 100644 --- a/x-pack/plugins/ml/public/application/notifications/components/notifications_list.tsx +++ b/x-pack/plugins/ml/public/application/notifications/components/notifications_list.tsx @@ -73,10 +73,12 @@ export const NotificationsList: FC = () => { const timeRange = useTimeRangeUpdates(); useMount(function setTimeRangeOnMount() { - timeFilter.setTime({ - from: moment(latestRequestedAt).toISOString(), - to: 'now', - }); + if (latestRequestedAt !== null) { + timeFilter.setTime({ + from: moment(latestRequestedAt).toISOString(), + to: 'now', + }); + } }); const [isLoading, setIsLoading] = useState(true); diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index fe0d25f8cc40f..926929ba500c6 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -266,10 +266,7 @@ function getNotificationsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink; +} + export class NotificationsService { constructor( private readonly scopedClusterClient: IScopedClusterClient, - private readonly mlSavedObjectService: MLSavedObjectService + private readonly mlSavedObjectService: MLSavedObjectService, + private readonly enabledFeatures: MlFeatures ) {} private getDefaultCountResponse() { @@ -42,17 +49,23 @@ export class NotificationsService { */ private async _getEntityIdsPerType() { const [adJobIds, dfaJobIds, modelIds] = await Promise.all([ - this.mlSavedObjectService.getAnomalyDetectionJobIds(), - this.mlSavedObjectService.getDataFrameAnalyticsJobIds(), - this.mlSavedObjectService.getTrainedModelsIds(), + this.enabledFeatures.ad ? this.mlSavedObjectService.getAnomalyDetectionJobIds() : [], + this.enabledFeatures.dfa ? this.mlSavedObjectService.getDataFrameAnalyticsJobIds() : [], + this.enabledFeatures.nlp ? this.mlSavedObjectService.getTrainedModelsIds() : [], ]); + const idsPerType: EntityIdsPerType[] = [{ type: 'system' }]; + + if (this.enabledFeatures.ad) { + idsPerType.push({ type: 'anomaly_detector', ids: adJobIds }); + } + if (this.enabledFeatures.dfa) { + idsPerType.push({ type: 'data_frame_analytics', ids: dfaJobIds }); + } + if (this.enabledFeatures.ad) { + idsPerType.push({ type: 'inference', ids: modelIds as string[] }); + } - return [ - { type: 'anomaly_detector', ids: adJobIds }, - { type: 'data_frame_analytics', ids: dfaJobIds }, - { type: 'inference', ids: modelIds }, - { type: 'system' }, - ].filter((v) => v.ids === undefined || v.ids.length > 0); + return idsPerType.filter((v) => v.ids === undefined || v.ids.length > 0); } /** diff --git a/x-pack/plugins/ml/server/plugin.ts b/x-pack/plugins/ml/server/plugin.ts index 7bafcf28f0ff8..bb6fc5460761b 100644 --- a/x-pack/plugins/ml/server/plugin.ts +++ b/x-pack/plugins/ml/server/plugin.ts @@ -224,6 +224,7 @@ export class MlServerPlugin coreSetup.getStartServices ), mlLicense: this.mlLicense, + enabledFeatures: this.enabledFeatures, }; annotationRoutes(routeInit, plugins.security); diff --git a/x-pack/plugins/ml/server/routes/notifications.ts b/x-pack/plugins/ml/server/routes/notifications.ts index 8e67136e83ddd..6924145e31e9e 100644 --- a/x-pack/plugins/ml/server/routes/notifications.ts +++ b/x-pack/plugins/ml/server/routes/notifications.ts @@ -14,7 +14,7 @@ import { import { wrapError } from '../client/error_wrapper'; import { RouteInitialization } from '../types'; -export function notificationsRoutes({ router, routeGuard }: RouteInitialization) { +export function notificationsRoutes({ router, routeGuard, enabledFeatures }: RouteInitialization) { /** * @apiGroup Notifications * @@ -46,7 +46,11 @@ export function notificationsRoutes({ router, routeGuard }: RouteInitialization) routeGuard.fullLicenseAPIGuard( async ({ client, request, response, mlSavedObjectService }) => { try { - const notificationsService = new NotificationsService(client, mlSavedObjectService); + const notificationsService = new NotificationsService( + client, + mlSavedObjectService, + enabledFeatures + ); const results = await notificationsService.searchMessages(request.query); @@ -91,7 +95,11 @@ export function notificationsRoutes({ router, routeGuard }: RouteInitialization) routeGuard.fullLicenseAPIGuard( async ({ client, mlSavedObjectService, request, response }) => { try { - const notificationsService = new NotificationsService(client, mlSavedObjectService); + const notificationsService = new NotificationsService( + client, + mlSavedObjectService, + enabledFeatures + ); const results = await notificationsService.countMessages(request.query); diff --git a/x-pack/plugins/ml/server/types.ts b/x-pack/plugins/ml/server/types.ts index df4770e6867bc..4bca1336ae0b9 100644 --- a/x-pack/plugins/ml/server/types.ts +++ b/x-pack/plugins/ml/server/types.ts @@ -80,6 +80,7 @@ export interface RouteInitialization { router: IRouter; mlLicense: MlLicense; routeGuard: RouteGuard; + enabledFeatures: MlFeatures; } export type MlFeatures = Record<'ad' | 'dfa' | 'nlp', boolean>; From 7976b22e1396d9b324a23ba639e05fb79ca816b2 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 26 Jun 2023 11:40:11 +0100 Subject: [PATCH 15/30] adding missing import --- x-pack/plugins/serverless_search/public/plugin.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts index 63f738ffc3941..87694e5795271 100644 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -6,6 +6,7 @@ */ import type { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { i18n } from '@kbn/i18n'; import { createServerlessSearchSideNavComponent as createComponent } from './layout/nav'; import { docLinks } from '../common/doc_links'; import type { From 3d8f891143b2754dbf8caab29d477697f42b3236 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 26 Jun 2023 14:07:21 +0100 Subject: [PATCH 16/30] removing comment --- x-pack/plugins/ml/common/types/capabilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/ml/common/types/capabilities.ts b/x-pack/plugins/ml/common/types/capabilities.ts index 766a958a2f061..c6bf7e9e1c7e5 100644 --- a/x-pack/plugins/ml/common/types/capabilities.ts +++ b/x-pack/plugins/ml/common/types/capabilities.ts @@ -184,7 +184,7 @@ export function getPluginPrivileges() { all: [], read: [ML_JOB_SAVED_OBJECT_TYPE], }, - api: apmUserMlCapabilitiesKeys.map((k) => `ml:${k}`), // should this include feature keys?!!!!!!!!!!!!!!!!!!!!!!! + api: apmUserMlCapabilitiesKeys.map((k) => `ml:${k}`), ui: apmUserMlCapabilitiesKeys, }, }; From f1934cdddc1fa2669b2e3f09fae88165837ce3a7 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 26 Jun 2023 14:11:59 +0100 Subject: [PATCH 17/30] updating comment --- .../ml/public/application/components/ml_page/ml_page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx index 4d01dca53d622..21b8a04eaea42 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx @@ -126,7 +126,7 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps className={'ml-app'} data-test-subj={'mlApp'} restrictWidth={false} - // forcing the background to white when in serverless + // forcing the background to white navigation is disabled css={pageDeps.navMenuEnabled ? {} : { background: '#FFF' }} solutionNav={ pageDeps.navMenuEnabled From 4c4feb715eab31d8bd73d82f8744124bf9cf6969 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 26 Jun 2023 14:28:57 +0100 Subject: [PATCH 18/30] type keyword --- x-pack/plugins/ml/public/plugin.ts | 6 +++--- .../register_search_links/register_search_links.ts | 4 ++-- .../register_search_links/search_deep_links.ts | 4 ++-- .../ml/server/lib/capabilities/capabilities_switcher.ts | 8 ++++---- x-pack/plugins/ml/server/routes/notifications.ts | 2 +- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index 04f043d5fb2db..de100bcc6cb61 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -25,7 +25,7 @@ import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/pu import type { SpacesPluginStart } from '@kbn/spaces-plugin/public'; import type { LensPublicStart } from '@kbn/lens-plugin/public'; -import { AppStatus, AppUpdater, DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; +import { AppStatus, type AppUpdater, DEFAULT_APP_CATEGORIES } from '@kbn/core/public'; import type { UiActionsSetup, UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { LicenseManagementUIPluginSetup } from '@kbn/license-management-plugin/public'; @@ -47,12 +47,12 @@ import type { ChartsPluginStart } from '@kbn/charts-plugin/public'; import type { CasesUiSetup, CasesUiStart } from '@kbn/cases-plugin/public'; import type { SavedSearchPublicPluginStart } from '@kbn/saved-search-plugin/public'; import { registerManagementSection } from './application/management'; -import { MlLocatorDefinition, MlLocator } from './locator'; +import { MlLocatorDefinition, type MlLocator } from './locator'; import { setDependencyCache } from './application/util/dependency_cache'; import { registerFeature } from './register_feature'; import { isFullLicense, isMlEnabled } from '../common/license'; import { PLUGIN_ICON_SOLUTION, PLUGIN_ID } from '../common/constants/app'; -import { MlCapabilities } from './shared'; +import type { MlCapabilities } from './shared'; export interface MlStartDependencies { data: DataPublicPluginStart; diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts index 8fce0d36fa630..35c37c56ecdff 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/register_search_links.ts @@ -8,9 +8,9 @@ import { i18n } from '@kbn/i18n'; import { BehaviorSubject } from 'rxjs'; -import { AppUpdater } from '@kbn/core/public'; +import type { AppUpdater } from '@kbn/core/public'; import { getDeepLinks } from './search_deep_links'; -import { MlCapabilities } from '../../shared'; +import type { MlCapabilities } from '../../shared'; export function registerSearchLinks( appUpdater: BehaviorSubject, diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index 926929ba500c6..bfcb149b3d201 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -8,9 +8,9 @@ import { i18n } from '@kbn/i18n'; import type { LinkId } from '@kbn/deeplinks-ml'; -import { AppDeepLink, AppNavLinkStatus } from '@kbn/core/public'; +import { type AppDeepLink, AppNavLinkStatus } from '@kbn/core/public'; import { ML_PAGES } from '../../../common/constants/locator'; -import { MlCapabilities } from '../../shared'; +import type { MlCapabilities } from '../../shared'; function getOverviewLinkDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { return { diff --git a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts index 095e64a46aed7..ebb7964c46af5 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts @@ -7,15 +7,15 @@ import { cloneDeep } from 'lodash'; import { firstValueFrom, Observable } from 'rxjs'; -import { CapabilitiesSwitcher, CoreSetup, Logger } from '@kbn/core/server'; -import { ILicense } from '@kbn/licensing-plugin/common/types'; +import type { CapabilitiesSwitcher, CoreSetup, Logger } from '@kbn/core/server'; +import type { ILicense } from '@kbn/licensing-plugin/common/types'; import { isFullLicense, isMinimumLicense, isMlEnabled } from '../../../common/license'; import { - MlCapabilities, + type MlCapabilities, basicLicenseMlCapabilities, featureCapabilities, } from '../../../common/types/capabilities'; -import { MlFeatures } from '../../types'; +import type { MlFeatures } from '../../types'; export const setupCapabilitiesSwitcher = ( coreSetup: CoreSetup, diff --git a/x-pack/plugins/ml/server/routes/notifications.ts b/x-pack/plugins/ml/server/routes/notifications.ts index 6924145e31e9e..f9c64543dd042 100644 --- a/x-pack/plugins/ml/server/routes/notifications.ts +++ b/x-pack/plugins/ml/server/routes/notifications.ts @@ -12,7 +12,7 @@ import { getNotificationsQuerySchema, } from './schemas/notifications_schema'; import { wrapError } from '../client/error_wrapper'; -import { RouteInitialization } from '../types'; +import type { RouteInitialization } from '../types'; export function notificationsRoutes({ router, routeGuard, enabledFeatures }: RouteInitialization) { /** From fcdac6da0a2cdc0eaa8daefa9595109132efc33a Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Mon, 26 Jun 2023 14:53:19 +0100 Subject: [PATCH 19/30] page access checks --- .../ml/public/application/routing/routes/notifications.tsx | 2 +- .../register_search_links/search_deep_links.ts | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/ml/public/application/routing/routes/notifications.tsx b/x-pack/plugins/ml/public/application/routing/routes/notifications.tsx index 3915d1a0d5c7f..b52f42d4df952 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/notifications.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/notifications.tsx @@ -42,7 +42,7 @@ export const notificationsRouteFactory = ( }); const PageWrapper: FC = () => { - const { context } = useRouteResolver('full', ['canGetJobs'], { + const { context } = useRouteResolver('full', ['canGetMlInfo'], { getMlNodeCount, loadMlServerInfo, }); diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index bfcb149b3d201..3b56396e477c4 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -161,9 +161,10 @@ function getModelManagementDeepLink(mlCapabilities: MlCapabilities): AppDeepLink defaultMessage: 'Nodes', }), path: `/${ML_PAGES.NODES}`, - navLinkStatus: mlCapabilities.isNLPEnabled - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus: + mlCapabilities.isADEnabled && mlCapabilities.isDFAEnabled && mlCapabilities.isNLPEnabled + ? AppNavLinkStatus.visible + : AppNavLinkStatus.hidden, }, ], }; From 8f4e744df95954be50b562cbb3fff61a386d46d5 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 27 Jun 2023 13:47:48 +0100 Subject: [PATCH 20/30] removing nav menu shared function --- x-pack/plugins/ml/public/application/app.tsx | 14 +++----------- .../application/components/ml_page/ml_page.tsx | 12 +++++++++--- .../ml/public/application/routing/router.tsx | 1 - x-pack/plugins/ml/public/plugin.ts | 10 +--------- .../public/components/side_navigation/index.tsx | 6 +++--- .../serverless_observability/public/plugin.ts | 5 ++--- .../serverless_observability/public/types.ts | 6 ++---- x-pack/plugins/serverless_search/public/plugin.ts | 5 ++--- x-pack/plugins/serverless_search/public/types.ts | 12 +++++------- .../plugins/serverless_security/public/plugin.ts | 6 ++---- x-pack/plugins/serverless_security/public/types.ts | 2 -- 11 files changed, 29 insertions(+), 50 deletions(-) diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index 28e46c9d447ce..1b0fe7f3d4d38 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -46,7 +46,6 @@ interface AppProps { coreStart: CoreStart; deps: MlDependencies; appMountParams: AppMountParameters; - navMenuEnabled: boolean; } const localStorage = new Storage(window.localStorage); @@ -80,12 +79,11 @@ export interface MlServicesContext { export type MlGlobalServices = ReturnType; -const App: FC = ({ coreStart, deps, appMountParams, navMenuEnabled }) => { +const App: FC = ({ coreStart, deps, appMountParams }) => { const pageDeps: PageDependencies = { history: appMountParams.history, setHeaderActionMenu: appMountParams.setHeaderActionMenu, setBreadcrumbs: coreStart.chrome!.setBreadcrumbs, - navMenuEnabled, }; const services = useMemo(() => { @@ -165,8 +163,7 @@ const App: FC = ({ coreStart, deps, appMountParams, navMenuEnabled }) export const renderApp = ( coreStart: CoreStart, deps: MlDependencies, - appMountParams: AppMountParameters, - navMenuEnabled: boolean + appMountParams: AppMountParameters ) => { setDependencyCache({ timefilter: deps.data.query.timefilter, @@ -195,12 +192,7 @@ export const renderApp = ( appMountParams.onAppLeave((actions) => actions.default()); ReactDOM.render( - , + , appMountParams.element ); diff --git a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx index 21b8a04eaea42..4ef018e794946 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx @@ -52,13 +52,14 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps const { services: { http: { basePath }, - mlServices: { httpService }, + mlServices: { httpService, mlCapabilities }, }, } = useMlKibana(); const headerPortalNode = useMemo(() => createHtmlPortalNode(), []); const [isHeaderMounted, setIsHeaderMounted] = useState(false); const [isLoading, setIsLoading] = useState(false); + const [navMenuEnabled, setNavMenuEnabled] = useState(true); useEffect(() => { const subscriptions = new Subscription(); @@ -68,6 +69,11 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps setIsLoading(v !== 0); }) ); + subscriptions.add( + mlCapabilities.capabilities$.subscribe((v) => { + setNavMenuEnabled(v.isADEnabled && v.isDFAEnabled && v.isNLPEnabled); + }) + ); return function cleanup() { subscriptions.unsubscribe(); @@ -127,9 +133,9 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps data-test-subj={'mlApp'} restrictWidth={false} // forcing the background to white navigation is disabled - css={pageDeps.navMenuEnabled ? {} : { background: '#FFF' }} + css={navMenuEnabled ? {} : { background: '#FFF' }} solutionNav={ - pageDeps.navMenuEnabled + navMenuEnabled ? { name: i18n.translate('xpack.ml.plugin.title', { defaultMessage: 'Machine Learning', diff --git a/x-pack/plugins/ml/public/application/routing/router.tsx b/x-pack/plugins/ml/public/application/routing/router.tsx index 1af26351452c2..a8092e5929deb 100644 --- a/x-pack/plugins/ml/public/application/routing/router.tsx +++ b/x-pack/plugins/ml/public/application/routing/router.tsx @@ -57,7 +57,6 @@ export interface PageDependencies { history: AppMountParameters['history']; setHeaderActionMenu: AppMountParameters['setHeaderActionMenu']; setBreadcrumbs: ChromeStart['setBreadcrumbs']; - navMenuEnabled: boolean; } export const PageLoader: FC<{ context: RouteResolverContext }> = ({ context, children }) => { diff --git a/x-pack/plugins/ml/public/plugin.ts b/x-pack/plugins/ml/public/plugin.ts index de100bcc6cb61..f9f3b6d22b0fc 100644 --- a/x-pack/plugins/ml/public/plugin.ts +++ b/x-pack/plugins/ml/public/plugin.ts @@ -100,8 +100,6 @@ export class MlPlugin implements Plugin { private locator: undefined | MlLocator; - private navMenuEnabled = true; - constructor(private initializerContext: PluginInitializerContext) {} setup(core: MlCoreSetup, pluginsSetup: MlSetupDependencies) { @@ -145,8 +143,7 @@ export class MlPlugin implements Plugin { savedObjectsManagement: pluginsStart.savedObjectsManagement, savedSearch: pluginsStart.savedSearch, }, - params, - this.navMenuEnabled + params ); }, }); @@ -217,13 +214,8 @@ export class MlPlugin implements Plugin { } }); - const setNavMenuEnabled = (enabled: boolean) => { - this.navMenuEnabled = enabled; - }; - return { locator: this.locator, - setNavMenuEnabled, }; } diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index 524a03cdd2c8f..0cd61be6e9526 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -5,12 +5,12 @@ * 2.0. */ -import type { CoreStart } from '@kbn/core/public'; -import type { ServerlessPluginStart } from '@kbn/serverless/public'; +import { CoreStart } from '@kbn/core/public'; +import { ServerlessPluginStart } from '@kbn/serverless/public'; import { DefaultNavigation, NavigationKibanaProvider, - type NavigationTreeDefinition, + NavigationTreeDefinition, getPresets, } from '@kbn/shared-ux-chrome-navigation'; import React from 'react'; diff --git a/x-pack/plugins/serverless_observability/public/plugin.ts b/x-pack/plugins/serverless_observability/public/plugin.ts index d52af7bb82696..ee774980f7c29 100644 --- a/x-pack/plugins/serverless_observability/public/plugin.ts +++ b/x-pack/plugins/serverless_observability/public/plugin.ts @@ -5,9 +5,9 @@ * 2.0. */ -import type { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { getObservabilitySideNavComponent } from './components/side_navigation'; -import type { +import { ServerlessObservabilityPluginSetup, ServerlessObservabilityPluginStart, ServerlessObservabilityPluginSetupDependencies, @@ -21,7 +21,6 @@ export class ServerlessObservabilityPlugin _core: CoreSetup, _setupDeps: ServerlessObservabilityPluginSetupDependencies ): ServerlessObservabilityPluginSetup { - _setupDeps.ml.setNavMenuEnabled(false); return {}; } diff --git a/x-pack/plugins/serverless_observability/public/types.ts b/x-pack/plugins/serverless_observability/public/types.ts index d20d46d7ec9c5..417a9c1701c84 100644 --- a/x-pack/plugins/serverless_observability/public/types.ts +++ b/x-pack/plugins/serverless_observability/public/types.ts @@ -5,12 +5,11 @@ * 2.0. */ -import type { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; -import type { +import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; +import { ObservabilitySharedPluginSetup, ObservabilitySharedPluginStart, } from '@kbn/observability-shared-plugin/public'; -import type { MlPluginSetup } from '@kbn/ml-plugin/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessObservabilityPluginSetup {} @@ -21,7 +20,6 @@ export interface ServerlessObservabilityPluginStart {} export interface ServerlessObservabilityPluginSetupDependencies { observabilityShared: ObservabilitySharedPluginSetup; serverless: ServerlessPluginSetup; - ml: MlPluginSetup; } export interface ServerlessObservabilityPluginStartDependencies { diff --git a/x-pack/plugins/serverless_search/public/plugin.ts b/x-pack/plugins/serverless_search/public/plugin.ts index 87694e5795271..5287d23712a47 100644 --- a/x-pack/plugins/serverless_search/public/plugin.ts +++ b/x-pack/plugins/serverless_search/public/plugin.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; +import { AppMountParameters, CoreSetup, CoreStart, Plugin } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { createServerlessSearchSideNavComponent as createComponent } from './layout/nav'; import { docLinks } from '../common/doc_links'; -import type { +import { ServerlessSearchPluginSetup, ServerlessSearchPluginSetupDependencies, ServerlessSearchPluginStart, @@ -63,7 +63,6 @@ export class ServerlessSearchPlugin return await renderApp(element, coreStart, { userProfile, ...services }); }, }); - _setupDeps.ml.setNavMenuEnabled(false); return {}; } diff --git a/x-pack/plugins/serverless_search/public/types.ts b/x-pack/plugins/serverless_search/public/types.ts index 688da36403437..5b984289e2bd7 100644 --- a/x-pack/plugins/serverless_search/public/types.ts +++ b/x-pack/plugins/serverless_search/public/types.ts @@ -5,12 +5,11 @@ * 2.0. */ -import type { CloudSetup, CloudStart } from '@kbn/cloud-plugin/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'; -import type { SharePluginStart } from '@kbn/share-plugin/public'; -import type { MlPluginSetup } from '@kbn/ml-plugin/public'; +import { CloudSetup, CloudStart } from '@kbn/cloud-plugin/public'; +import { ManagementSetup, ManagementStart } from '@kbn/management-plugin/public'; +import { SecurityPluginStart } from '@kbn/security-plugin/public'; +import { ServerlessPluginSetup, ServerlessPluginStart } from '@kbn/serverless/public'; +import { SharePluginStart } from '@kbn/share-plugin/public'; // eslint-disable-next-line @typescript-eslint/no-empty-interface export interface ServerlessSearchPluginSetup {} @@ -22,7 +21,6 @@ export interface ServerlessSearchPluginSetupDependencies { cloud: CloudSetup; management: ManagementSetup; serverless: ServerlessPluginSetup; - ml: MlPluginSetup; } export interface ServerlessSearchPluginStartDependencies { diff --git a/x-pack/plugins/serverless_security/public/plugin.ts b/x-pack/plugins/serverless_security/public/plugin.ts index 7ac4224bf940e..f0729330de4af 100644 --- a/x-pack/plugins/serverless_security/public/plugin.ts +++ b/x-pack/plugins/serverless_security/public/plugin.ts @@ -5,11 +5,11 @@ * 2.0. */ -import type { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; +import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/public'; import { getSecurityGetStartedComponent } from './components/get_started'; import { getSecuritySideNavComponent } from './components/side_navigation'; -import type { +import { ServerlessSecurityPluginSetup, ServerlessSecurityPluginStart, ServerlessSecurityPluginSetupDependencies, @@ -38,8 +38,6 @@ export class ServerlessSecurityPlugin setupDeps: ServerlessSecurityPluginSetupDependencies ): ServerlessSecurityPluginSetup { registerUpsellings(setupDeps.securitySolution.upselling, this.config.productTypes); - - setupDeps.ml.setNavMenuEnabled(false); return {}; } diff --git a/x-pack/plugins/serverless_security/public/types.ts b/x-pack/plugins/serverless_security/public/types.ts index bccd1998c6ab3..3954183cc9749 100644 --- a/x-pack/plugins/serverless_security/public/types.ts +++ b/x-pack/plugins/serverless_security/public/types.ts @@ -5,7 +5,6 @@ * 2.0. */ -import type { MlPluginSetup } from '@kbn/ml-plugin/public'; import type { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/public'; import type { PluginSetup as SecuritySolutionPluginSetup, @@ -24,7 +23,6 @@ export interface ServerlessSecurityPluginSetupDependencies { security: SecurityPluginSetup; securitySolution: SecuritySolutionPluginSetup; serverless: ServerlessPluginSetup; - ml: MlPluginSetup; } export interface ServerlessSecurityPluginStartDependencies { From 99195a68f0dfd38861d8fa594038e1bf1d080631 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 27 Jun 2023 13:56:57 +0100 Subject: [PATCH 21/30] removing old isServerless function --- x-pack/plugins/ml/public/application/app.tsx | 7 ------- .../contexts/kibana/use_is_serverless.ts | 14 -------------- 2 files changed, 21 deletions(-) delete mode 100644 x-pack/plugins/ml/public/application/contexts/kibana/use_is_serverless.ts diff --git a/x-pack/plugins/ml/public/application/app.tsx b/x-pack/plugins/ml/public/application/app.tsx index 1b0fe7f3d4d38..559ec601da4d7 100644 --- a/x-pack/plugins/ml/public/application/app.tsx +++ b/x-pack/plugins/ml/public/application/app.tsx @@ -50,12 +50,6 @@ interface AppProps { const localStorage = new Storage(window.localStorage); -// temporary function to hardcode the serverless state -// this will be replaced by the true serverless information from kibana -export function isServerless() { - return false; -} - /** * Provides global services available across the entire ML app. */ @@ -67,7 +61,6 @@ export function getMlGlobalServices(httpStart: HttpStart, usageCollection?: Usag httpService, mlApiServices, mlUsageCollection: mlUsageCollectionProvider(usageCollection), - isServerless, mlCapabilities: new MlCapabilitiesService(mlApiServices), mlLicense: new MlLicense(), }; diff --git a/x-pack/plugins/ml/public/application/contexts/kibana/use_is_serverless.ts b/x-pack/plugins/ml/public/application/contexts/kibana/use_is_serverless.ts deleted file mode 100644 index 120ae02b8d466..0000000000000 --- a/x-pack/plugins/ml/public/application/contexts/kibana/use_is_serverless.ts +++ /dev/null @@ -1,14 +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 { useMemo } from 'react'; -import { useMlKibana } from './kibana_context'; - -export const useIsServerless = () => { - const isServerless = useMlKibana().services.mlServices.isServerless; - return useMemo(() => isServerless(), [isServerless]); -}; From 4206474b81fe8548db10d3015823f2a33c4dce64 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 27 Jun 2023 14:16:11 +0100 Subject: [PATCH 22/30] removing old isServerless hook --- .../components/ml_page/ml_page.tsx | 26 ++++++++++++------- .../memory_usage/memory_usage_page.tsx | 10 ++++--- .../application/overview/overview_page.tsx | 4 +-- 3 files changed, 24 insertions(+), 16 deletions(-) diff --git a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx index 4ef018e794946..1ce97588b5726 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx @@ -20,7 +20,7 @@ import { DatePickerWrapper } from '@kbn/ml-date-picker'; import * as routes from '../../routing/routes'; import { MlPageWrapper } from '../../routing/ml_page_wrapper'; -import { useMlKibana, useNavigateToPath } from '../../contexts/kibana'; +import { useCurrentThemeVars, useMlKibana, useNavigateToPath } from '../../contexts/kibana'; import { MlRoute, PageDependencies } from '../../routing/router'; import { useActiveRoute } from '../../routing/use_active_route'; import { useDocTitle } from '../../routing/use_doc_title'; @@ -28,6 +28,7 @@ import { useDocTitle } from '../../routing/use_doc_title'; import { MlPageHeaderRenderer } from '../page_header/page_header'; import { useSideNavItems } from './side_nav'; +import { usePermissionCheck } from '../../capabilities/check_capabilities'; const ML_APP_SELECTOR = '[data-test-subj="mlApp"]'; @@ -52,14 +53,25 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps const { services: { http: { basePath }, - mlServices: { httpService, mlCapabilities }, + mlServices: { httpService }, }, } = useMlKibana(); + const { euiTheme } = useCurrentThemeVars(); const headerPortalNode = useMemo(() => createHtmlPortalNode(), []); const [isHeaderMounted, setIsHeaderMounted] = useState(false); const [isLoading, setIsLoading] = useState(false); - const [navMenuEnabled, setNavMenuEnabled] = useState(true); + + const [isADEnabled, isDFAEnabled, isNLPEnabled] = usePermissionCheck([ + 'isADEnabled', + 'isDFAEnabled', + 'isNLPEnabled', + ]); + + const navMenuEnabled = useMemo( + () => isADEnabled && isDFAEnabled && isNLPEnabled, + [isADEnabled, isDFAEnabled, isNLPEnabled] + ); useEffect(() => { const subscriptions = new Subscription(); @@ -69,12 +81,6 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps setIsLoading(v !== 0); }) ); - subscriptions.add( - mlCapabilities.capabilities$.subscribe((v) => { - setNavMenuEnabled(v.isADEnabled && v.isDFAEnabled && v.isNLPEnabled); - }) - ); - return function cleanup() { subscriptions.unsubscribe(); }; @@ -133,7 +139,7 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps data-test-subj={'mlApp'} restrictWidth={false} // forcing the background to white navigation is disabled - css={navMenuEnabled ? {} : { background: '#FFF' }} + css={navMenuEnabled ? {} : { background: euiTheme.euiPageBackgroundColor }} solutionNav={ navMenuEnabled ? { diff --git a/x-pack/plugins/ml/public/application/memory_usage/memory_usage_page.tsx b/x-pack/plugins/ml/public/application/memory_usage/memory_usage_page.tsx index 24e3dbab771b5..9fe3261aec74c 100644 --- a/x-pack/plugins/ml/public/application/memory_usage/memory_usage_page.tsx +++ b/x-pack/plugins/ml/public/application/memory_usage/memory_usage_page.tsx @@ -12,8 +12,8 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { NodesList } from './nodes_overview'; import { MlPageHeader } from '../components/page_header'; import { MemoryPage, JobMemoryTreeMap } from './memory_tree_map'; -import { useIsServerless } from '../contexts/kibana/use_is_serverless'; import { SavedObjectsWarning } from '../components/saved_objects_warning'; +import { usePermissionCheck } from '../capabilities/check_capabilities'; enum TAB { NODES, @@ -21,9 +21,13 @@ enum TAB { } export const MemoryUsagePage: FC = () => { - const serverless = useIsServerless(); const [selectedTab, setSelectedTab] = useState(TAB.NODES); useTimefilter({ timeRangeSelector: false, autoRefreshSelector: true }); + const [isADEnabled, isDFAEnabled, isNLPEnabled] = usePermissionCheck([ + 'isADEnabled', + 'isDFAEnabled', + 'isNLPEnabled', + ]); const refresh = useCallback(() => { mlTimefilterRefresh$.next({ @@ -46,7 +50,7 @@ export const MemoryUsagePage: FC = () => { - {serverless ? ( + {isADEnabled && isDFAEnabled && isNLPEnabled ? ( ) : ( <> diff --git a/x-pack/plugins/ml/public/application/overview/overview_page.tsx b/x-pack/plugins/ml/public/application/overview/overview_page.tsx index 6772125bb9532..aad0dc45a3548 100644 --- a/x-pack/plugins/ml/public/application/overview/overview_page.tsx +++ b/x-pack/plugins/ml/public/application/overview/overview_page.tsx @@ -27,7 +27,6 @@ import { useMlKibana, useMlLink } from '../contexts/kibana'; import { NodesList } from '../memory_usage/nodes_overview'; import { MlPageHeader } from '../components/page_header'; import { PageTitle } from '../components/page_title'; -import { useIsServerless } from '../contexts/kibana/use_is_serverless'; import { getMlNodesCount } from '../ml_nodes_check/check_ml_nodes'; export const overviewPanelDefaultState = Object.freeze({ @@ -37,7 +36,6 @@ export const overviewPanelDefaultState = Object.freeze({ }); export const OverviewPage: FC = () => { - const serverless = useIsServerless(); const [canViewMlNodes, canCreateJob] = usePermissionCheck(['canViewMlNodes', 'canCreateJob']); const disableCreateAnomalyDetectionJob = !canCreateJob || !mlNodesAvailable(); @@ -83,7 +81,7 @@ export const OverviewPage: FC = () => { /> - {canViewMlNodes && serverless === false ? ( + {canViewMlNodes ? ( <> Date: Tue, 27 Jun 2023 14:27:59 +0100 Subject: [PATCH 23/30] fixing background color --- .../ml/public/application/components/ml_page/ml_page.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx index 1ce97588b5726..3d208ec78169e 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx @@ -138,8 +138,8 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps className={'ml-app'} data-test-subj={'mlApp'} restrictWidth={false} - // forcing the background to white navigation is disabled - css={navMenuEnabled ? {} : { background: euiTheme.euiPageBackgroundColor }} + // forcing the background color when navigation is disabled + css={navMenuEnabled ? {} : { background: euiTheme.euiColorEmptyShade }} solutionNav={ navMenuEnabled ? { From 4b97c8e0009aebbe725a036bd318e0bf9b554adf Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 27 Jun 2023 14:39:59 +0100 Subject: [PATCH 24/30] removing background color overrides --- .../ml/public/application/components/ml_page/ml_page.tsx | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx index 3d208ec78169e..6c981351d5f63 100644 --- a/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx +++ b/x-pack/plugins/ml/public/application/components/ml_page/ml_page.tsx @@ -6,7 +6,7 @@ */ import React, { createContext, FC, useEffect, useMemo, useState } from 'react'; -import { createHtmlPortalNode, HtmlPortalNode } from 'react-reverse-portal'; +import { createHtmlPortalNode, type HtmlPortalNode } from 'react-reverse-portal'; import { Redirect } from 'react-router-dom'; import { Routes, Route } from '@kbn/shared-ux-router'; import { Subscription } from 'rxjs'; @@ -20,8 +20,8 @@ import { DatePickerWrapper } from '@kbn/ml-date-picker'; import * as routes from '../../routing/routes'; import { MlPageWrapper } from '../../routing/ml_page_wrapper'; -import { useCurrentThemeVars, useMlKibana, useNavigateToPath } from '../../contexts/kibana'; -import { MlRoute, PageDependencies } from '../../routing/router'; +import { useMlKibana, useNavigateToPath } from '../../contexts/kibana'; +import type { MlRoute, PageDependencies } from '../../routing/router'; import { useActiveRoute } from '../../routing/use_active_route'; import { useDocTitle } from '../../routing/use_doc_title'; @@ -56,7 +56,6 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps mlServices: { httpService }, }, } = useMlKibana(); - const { euiTheme } = useCurrentThemeVars(); const headerPortalNode = useMemo(() => createHtmlPortalNode(), []); const [isHeaderMounted, setIsHeaderMounted] = useState(false); @@ -138,8 +137,6 @@ export const MlPage: FC<{ pageDeps: PageDependencies }> = React.memo(({ pageDeps className={'ml-app'} data-test-subj={'mlApp'} restrictWidth={false} - // forcing the background color when navigation is disabled - css={navMenuEnabled ? {} : { background: euiTheme.euiColorEmptyShade }} solutionNav={ navMenuEnabled ? { From 35eeb663f7625ad0c9cd03fe528380aed7b4d8f7 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Tue, 27 Jun 2023 15:00:27 +0100 Subject: [PATCH 25/30] fixing mock --- x-pack/plugins/ml/public/mocks.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/ml/public/mocks.ts b/x-pack/plugins/ml/public/mocks.ts index 5883efca2fc02..13f8952dbad21 100644 --- a/x-pack/plugins/ml/public/mocks.ts +++ b/x-pack/plugins/ml/public/mocks.ts @@ -11,7 +11,6 @@ import { MlPluginSetup, MlPluginStart } from './plugin'; const createSetupContract = (): jest.Mocked => { return { locator: sharePluginMock.createLocator(), - setNavMenuEnabled: jest.fn(), }; }; From c29461ae8a78500890a6fb0ca638aa51a449d80b Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Thu, 29 Jun 2023 09:44:54 +0100 Subject: [PATCH 26/30] fixing links when not in serverless --- .../search_deep_links.ts | 100 +++++++----------- 1 file changed, 40 insertions(+), 60 deletions(-) diff --git a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts index 3b56396e477c4..38e48db3787af 100644 --- a/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts +++ b/x-pack/plugins/ml/public/register_helper/register_search_links/search_deep_links.ts @@ -12,6 +12,19 @@ import { type AppDeepLink, AppNavLinkStatus } from '@kbn/core/public'; import { ML_PAGES } from '../../../common/constants/locator'; import type { MlCapabilities } from '../../shared'; +function getNavStatus( + mlCapabilities: MlCapabilities, + statusIfServerless: boolean +): AppNavLinkStatus | undefined { + if (mlCapabilities.isADEnabled && mlCapabilities.isDFAEnabled && mlCapabilities.isNLPEnabled) { + // if all features are enabled we can assume that we are not running in serverless mode. + // returning default will not add the link to the nav menu, but the link will be registered for searching + return AppNavLinkStatus.default; + } + + return statusIfServerless ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden; +} + function getOverviewLinkDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { return { id: 'overview', @@ -19,21 +32,19 @@ function getOverviewLinkDeepLink(mlCapabilities: MlCapabilities): AppDeepLink
  • { + const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.isADEnabled); return { id: 'anomalyDetection', title: i18n.translate('xpack.ml.deepLink.anomalyDetection', { defaultMessage: 'Anomaly Detection', }), path: `/${ML_PAGES.ANOMALY_DETECTION_JOBS_MANAGE}`, - navLinkStatus: mlCapabilities.isADEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + navLinkStatus, deepLinks: [ { id: 'anomalyExplorer', @@ -41,9 +52,7 @@ function getAnomalyDetectionDeepLink(mlCapabilities: MlCapabilities): AppDeepLin defaultMessage: 'Anomaly explorer', }), path: `/${ML_PAGES.ANOMALY_EXPLORER}`, - navLinkStatus: mlCapabilities.isADEnabled - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus, }, { id: 'singleMetricViewer', @@ -51,22 +60,21 @@ function getAnomalyDetectionDeepLink(mlCapabilities: MlCapabilities): AppDeepLin defaultMessage: 'Single metric viewer', }), path: `/${ML_PAGES.SINGLE_METRIC_VIEWER}`, - navLinkStatus: mlCapabilities.isADEnabled - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus, }, ], }; } function getDataFrameAnalyticsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.isDFAEnabled); return { id: 'dataFrameAnalytics', title: i18n.translate('xpack.ml.deepLink.dataFrameAnalytics', { defaultMessage: 'Data Frame Analytics', }), path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_JOBS_MANAGE}`, - navLinkStatus: mlCapabilities.isDFAEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + navLinkStatus, deepLinks: [ { id: 'resultExplorer', @@ -74,9 +82,7 @@ function getDataFrameAnalyticsDeepLink(mlCapabilities: MlCapabilities): AppDeepL defaultMessage: 'Results explorer', }), path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_EXPLORATION}`, - navLinkStatus: mlCapabilities.isDFAEnabled - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus, }, { id: 'analyticsMap', @@ -84,15 +90,14 @@ function getDataFrameAnalyticsDeepLink(mlCapabilities: MlCapabilities): AppDeepL defaultMessage: 'Analytics map', }), path: `/${ML_PAGES.DATA_FRAME_ANALYTICS_MAP}`, - navLinkStatus: mlCapabilities.isDFAEnabled - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus, }, ], }; } function getAiopsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.canUseAiops); return { id: 'aiOps', title: i18n.translate('xpack.ml.deepLink.aiOps', { @@ -100,7 +105,7 @@ function getAiopsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { }), // Default to the index select page for the explain log rate spikes since we don't have an AIops overview page path: `/${ML_PAGES.AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT}`, - navLinkStatus: mlCapabilities.canUseAiops ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + navLinkStatus, deepLinks: [ { id: 'explainLogRateSpikes', @@ -108,9 +113,7 @@ function getAiopsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { defaultMessage: 'Explain Log Rate Spikes', }), path: `/${ML_PAGES.AIOPS_EXPLAIN_LOG_RATE_SPIKES_INDEX_SELECT}`, - navLinkStatus: mlCapabilities.canUseAiops - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus, }, { id: 'logPatternAnalysis', @@ -118,9 +121,7 @@ function getAiopsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { defaultMessage: 'Log Pattern Analysis', }), path: `/${ML_PAGES.AIOPS_LOG_CATEGORIZATION_INDEX_SELECT}`, - navLinkStatus: mlCapabilities.canUseAiops - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus, }, { id: 'changePointDetections', @@ -128,22 +129,21 @@ function getAiopsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { defaultMessage: 'Change Point Detection', }), path: `/${ML_PAGES.AIOPS_CHANGE_POINT_DETECTION_INDEX_SELECT}`, - navLinkStatus: mlCapabilities.canUseAiops - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus, }, ], }; } function getModelManagementDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.isNLPEnabled); return { id: 'modelManagement', title: i18n.translate('xpack.ml.deepLink.modelManagement', { defaultMessage: 'Model Management', }), path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, - navLinkStatus: mlCapabilities.isNLPEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + navLinkStatus, deepLinks: [ { id: 'nodesOverview', @@ -151,9 +151,7 @@ function getModelManagementDeepLink(mlCapabilities: MlCapabilities): AppDeepLink defaultMessage: 'Trained Models', }), path: `/${ML_PAGES.TRAINED_MODELS_MANAGE}`, - navLinkStatus: mlCapabilities.isNLPEnabled - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus, }, { id: 'nodes', @@ -161,10 +159,7 @@ function getModelManagementDeepLink(mlCapabilities: MlCapabilities): AppDeepLink defaultMessage: 'Nodes', }), path: `/${ML_PAGES.NODES}`, - navLinkStatus: - mlCapabilities.isADEnabled && mlCapabilities.isDFAEnabled && mlCapabilities.isNLPEnabled - ? AppNavLinkStatus.visible - : AppNavLinkStatus.hidden, + navLinkStatus: getNavStatus(mlCapabilities, false), }, ], }; @@ -177,10 +172,7 @@ function getMemoryUsageDeepLink(mlCapabilities: MlCapabilities): AppDeepLink { + const navLinkStatus = getNavStatus(mlCapabilities, mlCapabilities.isADEnabled); return { id: 'settings', title: i18n.translate('xpack.ml.deepLink.settings', { defaultMessage: 'Settings', }), path: `/${ML_PAGES.SETTINGS}`, - navLinkStatus: mlCapabilities.isADEnabled ? AppNavLinkStatus.visible : AppNavLinkStatus.hidden, + navLinkStatus, deepLinks: [ { id: 'calendarSettings', @@ -242,9 +226,7 @@ function getSettingsDeepLink(mlCapabilities: MlCapabilities): AppDeepLink Date: Thu, 29 Jun 2023 10:31:15 +0100 Subject: [PATCH 27/30] adding ml back into oblt menu --- .../public/components/side_navigation/index.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index 23987f7d86e95..5684770a08f68 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -94,6 +94,10 @@ const navigationTree: NavigationTreeDefinition = { }, ], }, + { + type: 'navGroup', + ...getPresets('ml'), + }, ], footer: [ { From 3a7eae13415e0a6f36583eacf1b6a6929038baca Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Thu, 29 Jun 2023 12:52:19 +0100 Subject: [PATCH 28/30] removing ml section from oblt --- .../public/components/side_navigation/index.tsx | 4 ---- 1 file changed, 4 deletions(-) diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index 5684770a08f68..23987f7d86e95 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -94,10 +94,6 @@ const navigationTree: NavigationTreeDefinition = { }, ], }, - { - type: 'navGroup', - ...getPresets('ml'), - }, ], footer: [ { From 82a51a71339a83a1785a45536dba3b62cc41e8e0 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Thu, 29 Jun 2023 15:26:35 +0100 Subject: [PATCH 29/30] adjusting overview page --- .../overview/components/content.tsx | 20 +++++++++++++------ .../application/routing/routes/overview.tsx | 2 +- .../lib/capabilities/capabilities_switcher.ts | 2 ++ 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/ml/public/application/overview/components/content.tsx b/x-pack/plugins/ml/public/application/overview/components/content.tsx index 992a64015e7e4..15998b9f58b93 100644 --- a/x-pack/plugins/ml/public/application/overview/components/content.tsx +++ b/x-pack/plugins/ml/public/application/overview/components/content.tsx @@ -13,6 +13,7 @@ import { AnalyticsPanel } from './analytics_panel'; import { AnomalyTimelineService } from '../../services/anomaly_timeline_service'; import { mlResultsServiceProvider } from '../../services/results_service'; import { useMlKibana } from '../../contexts/kibana'; +import { usePermissionCheck } from '../../capabilities/check_capabilities'; interface Props { createAnomalyDetectionJobDisabled: boolean; @@ -32,6 +33,8 @@ export const OverviewContent: FC = ({ }, } = useMlKibana(); + const [isADEnabled, isDFAEnabled] = usePermissionCheck(['isADEnabled', 'isDFAEnabled']); + const timefilter = useTimefilter(); const [anomalyTimelineService, setAnomalyTimelineService] = useState(); @@ -49,12 +52,17 @@ export const OverviewContent: FC = ({ return ( <> - - - + {isADEnabled ? ( + <> + + + + ) : null} + + {isDFAEnabled ? : null} ); }; diff --git a/x-pack/plugins/ml/public/application/routing/routes/overview.tsx b/x-pack/plugins/ml/public/application/routing/routes/overview.tsx index 3dec773e24a1f..33346b0d0fe72 100644 --- a/x-pack/plugins/ml/public/application/routing/routes/overview.tsx +++ b/x-pack/plugins/ml/public/application/routing/routes/overview.tsx @@ -42,7 +42,7 @@ export const overviewRouteFactory = ( }); const PageWrapper: FC = () => { - const { context } = useRouteResolver('full', ['canGetJobs'], { + const { context } = useRouteResolver('full', ['canGetMlInfo'], { getMlNodeCount, loadMlServerInfo, }); diff --git a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts index ebb7964c46af5..c43423eb872cc 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts @@ -72,6 +72,8 @@ function applyEnabledFeatures(mlCaps: MlCapabilities, enabledFeatures: MlFeature mlCaps.isDFAEnabled = enabledFeatures.dfa; mlCaps.isNLPEnabled = enabledFeatures.nlp; + mlCaps.canViewMlNodes = mlCaps.isADEnabled && mlCaps.isDFAEnabled && mlCaps.isNLPEnabled; + if (enabledFeatures.ad === false) { featureCapabilities.ad.forEach((c) => (mlCaps[c] = false)); } From 61a237073118d8502fc47f4d3079b3ffdb016601 Mon Sep 17 00:00:00 2001 From: James Gowdy Date: Thu, 29 Jun 2023 16:58:20 +0100 Subject: [PATCH 30/30] fixing canViewMlNodes value for viewer users --- .../ml/server/lib/capabilities/capabilities_switcher.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts index c43423eb872cc..2be5bd877552a 100644 --- a/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts +++ b/x-pack/plugins/ml/server/lib/capabilities/capabilities_switcher.ts @@ -72,7 +72,8 @@ function applyEnabledFeatures(mlCaps: MlCapabilities, enabledFeatures: MlFeature mlCaps.isDFAEnabled = enabledFeatures.dfa; mlCaps.isNLPEnabled = enabledFeatures.nlp; - mlCaps.canViewMlNodes = mlCaps.isADEnabled && mlCaps.isDFAEnabled && mlCaps.isNLPEnabled; + mlCaps.canViewMlNodes = + mlCaps.canViewMlNodes && mlCaps.isADEnabled && mlCaps.isDFAEnabled && mlCaps.isNLPEnabled; if (enabledFeatures.ad === false) { featureCapabilities.ad.forEach((c) => (mlCaps[c] = false));