diff --git a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts
index 87318e6c95fe..06866afc65ca 100644
--- a/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts
+++ b/src/plugins/kibana_usage_collection/server/collectors/application_usage/schema.ts
@@ -152,6 +152,7 @@ export const applicationUsageSchema = {
fleet: commonSchema,
integrations: commonSchema,
ingestManager: commonSchema,
+ inventory: commonSchema,
lens: commonSchema,
maps: commonSchema,
ml: commonSchema,
diff --git a/src/plugins/telemetry/schema/oss_plugins.json b/src/plugins/telemetry/schema/oss_plugins.json
index 37507c50e832..82e766601878 100644
--- a/src/plugins/telemetry/schema/oss_plugins.json
+++ b/src/plugins/telemetry/schema/oss_plugins.json
@@ -4194,6 +4194,137 @@
}
}
},
+ "inventory": {
+ "properties": {
+ "appId": {
+ "type": "keyword",
+ "_meta": {
+ "description": "The application being tracked"
+ }
+ },
+ "viewId": {
+ "type": "keyword",
+ "_meta": {
+ "description": "Always `main`"
+ }
+ },
+ "clicks_total": {
+ "type": "long",
+ "_meta": {
+ "description": "General number of clicks in the application since we started counting them"
+ }
+ },
+ "clicks_7_days": {
+ "type": "long",
+ "_meta": {
+ "description": "General number of clicks in the application over the last 7 days"
+ }
+ },
+ "clicks_30_days": {
+ "type": "long",
+ "_meta": {
+ "description": "General number of clicks in the application over the last 30 days"
+ }
+ },
+ "clicks_90_days": {
+ "type": "long",
+ "_meta": {
+ "description": "General number of clicks in the application over the last 90 days"
+ }
+ },
+ "minutes_on_screen_total": {
+ "type": "float",
+ "_meta": {
+ "description": "Minutes the application is active and on-screen since we started counting them."
+ }
+ },
+ "minutes_on_screen_7_days": {
+ "type": "float",
+ "_meta": {
+ "description": "Minutes the application is active and on-screen over the last 7 days"
+ }
+ },
+ "minutes_on_screen_30_days": {
+ "type": "float",
+ "_meta": {
+ "description": "Minutes the application is active and on-screen over the last 30 days"
+ }
+ },
+ "minutes_on_screen_90_days": {
+ "type": "float",
+ "_meta": {
+ "description": "Minutes the application is active and on-screen over the last 90 days"
+ }
+ },
+ "views": {
+ "type": "array",
+ "items": {
+ "properties": {
+ "appId": {
+ "type": "keyword",
+ "_meta": {
+ "description": "The application being tracked"
+ }
+ },
+ "viewId": {
+ "type": "keyword",
+ "_meta": {
+ "description": "The application view being tracked"
+ }
+ },
+ "clicks_total": {
+ "type": "long",
+ "_meta": {
+ "description": "General number of clicks in the application sub view since we started counting them"
+ }
+ },
+ "clicks_7_days": {
+ "type": "long",
+ "_meta": {
+ "description": "General number of clicks in the active application sub view over the last 7 days"
+ }
+ },
+ "clicks_30_days": {
+ "type": "long",
+ "_meta": {
+ "description": "General number of clicks in the active application sub view over the last 30 days"
+ }
+ },
+ "clicks_90_days": {
+ "type": "long",
+ "_meta": {
+ "description": "General number of clicks in the active application sub view over the last 90 days"
+ }
+ },
+ "minutes_on_screen_total": {
+ "type": "float",
+ "_meta": {
+ "description": "Minutes the application sub view is active and on-screen since we started counting them."
+ }
+ },
+ "minutes_on_screen_7_days": {
+ "type": "float",
+ "_meta": {
+ "description": "Minutes the application is active and on-screen active application sub view over the last 7 days"
+ }
+ },
+ "minutes_on_screen_30_days": {
+ "type": "float",
+ "_meta": {
+ "description": "Minutes the application is active and on-screen active application sub view over the last 30 days"
+ }
+ },
+ "minutes_on_screen_90_days": {
+ "type": "float",
+ "_meta": {
+ "description": "Minutes the application is active and on-screen active application sub view over the last 90 days"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
"lens": {
"properties": {
"appId": {
diff --git a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts
index e7c75652c7d0..32ff06d1b3c6 100644
--- a/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts
+++ b/x-pack/plugins/observability_solution/apm/ftr_e2e/cypress/e2e/deep_links.cy.ts
@@ -16,7 +16,7 @@ describe('APM deep links', () => {
.type('APM', { force: true, delay: 100 })
.focus();
cy.contains('APM');
- cy.contains('APM / Services');
+ cy.contains('APM / Service Inventory');
cy.contains('APM / Service groups');
cy.contains('APM / Traces');
cy.contains('APM / Service Map');
@@ -33,7 +33,7 @@ describe('APM deep links', () => {
.should('be.visible')
.type('APM', { force: true, delay: 100 });
// navigates to services page
- cy.contains('APM / Services').click({ force: true });
+ cy.contains('APM / Service Inventory').click({ force: true });
cy.url().should('include', '/apm/services');
cy.getByTestSubj('nav-search-input')
diff --git a/x-pack/plugins/observability_solution/apm/public/plugin.ts b/x-pack/plugins/observability_solution/apm/public/plugin.ts
index c429fdaeb9ec..f58b9d6d4096 100644
--- a/x-pack/plugins/observability_solution/apm/public/plugin.ts
+++ b/x-pack/plugins/observability_solution/apm/public/plugin.ts
@@ -156,7 +156,7 @@ const applicationsTitle = i18n.translate('xpack.apm.navigation.rootTitle', {
});
const servicesTitle = i18n.translate('xpack.apm.navigation.servicesTitle', {
- defaultMessage: 'Services',
+ defaultMessage: 'Service Inventory',
});
const serviceGroupsTitle = i18n.translate('xpack.apm.navigation.serviceGroupsTitle', {
diff --git a/x-pack/plugins/observability_solution/inventory/kibana.jsonc b/x-pack/plugins/observability_solution/inventory/kibana.jsonc
index 524b59d37cc3..f60cf36183b2 100644
--- a/x-pack/plugins/observability_solution/inventory/kibana.jsonc
+++ b/x-pack/plugins/observability_solution/inventory/kibana.jsonc
@@ -12,13 +12,13 @@
"entityManager",
"inference",
"dataViews",
+ "share",
+ "features",
"unifiedSearch",
"data",
"share"
],
- "requiredBundles": [
- "kibanaReact"
- ],
+ "requiredBundles": ["kibanaReact"],
"optionalPlugins": [],
"extraPublicDirs": []
}
diff --git a/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/index.tsx b/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/index.tsx
index c2734d664355..29a6ac31348b 100644
--- a/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/index.tsx
+++ b/x-pack/plugins/observability_solution/inventory/public/components/inventory_page_template/index.tsx
@@ -4,10 +4,10 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import React from 'react';
-import { EuiEmptyPrompt, EuiLoadingLogo } from '@elastic/eui';
+import { EuiFlexGroup, EuiFlexItem, EuiEmptyPrompt, EuiLoadingLogo } from '@elastic/eui';
+import { TechnicalPreviewBadge } from '@kbn/observability-shared-plugin/public';
import { useKibana } from '../../hooks/use_kibana';
import { SearchBar } from '../search_bar';
import { getEntityManagerEnablement } from './no_data_config';
@@ -16,11 +16,18 @@ import { Welcome } from '../entity_enablement/welcome_modal';
import { useInventoryAbortableAsync } from '../../hooks/use_inventory_abortable_async';
import { EmptyState } from '../empty_states/empty_state';
-const pageTitle = {
- pageTitle: i18n.translate('xpack.inventory.inventoryPageHeaderLabel', {
- defaultMessage: 'Inventory',
- }),
-};
+const pageTitle = (
+
+
+ {i18n.translate('xpack.inventory.inventoryPageHeaderLabel', {
+ defaultMessage: 'Inventory',
+ })}
+
+
+
+
+
+);
export function InventoryPageTemplate({ children }: { children: React.ReactNode }) {
const {
@@ -52,7 +59,11 @@ export function InventoryPageTemplate({ children }: { children: React.ReactNode
if (isEnablementLoading || hasDataLoading) {
return (
-
+
} />
);
@@ -60,12 +71,14 @@ export function InventoryPageTemplate({ children }: { children: React.ReactNode
return (
{value.hasData ? (
diff --git a/x-pack/plugins/observability_solution/inventory/public/plugin.ts b/x-pack/plugins/observability_solution/inventory/public/plugin.ts
index 6f05d4594d15..c02a57b45f69 100644
--- a/x-pack/plugins/observability_solution/inventory/public/plugin.ts
+++ b/x-pack/plugins/observability_solution/inventory/public/plugin.ts
@@ -12,6 +12,7 @@ import {
DEFAULT_APP_CATEGORIES,
Plugin,
PluginInitializerContext,
+ AppStatus,
} from '@kbn/core/public';
import { INVENTORY_APP_ID } from '@kbn/deeplinks-observability/constants';
import { i18n } from '@kbn/i18n';
@@ -49,33 +50,39 @@ export class InventoryPlugin
pluginsSetup: InventorySetupDependencies
): InventoryPublicSetup {
const inventoryAPIClient = createCallInventoryAPI(coreSetup);
- this.telemetry.setup({ analytics: coreSetup.analytics });
-
- pluginsSetup.observabilityShared.navigation.registerSections(
- from(coreSetup.getStartServices()).pipe(
- map(([coreStart, pluginsStart]) => {
- return [
- {
- label: '',
- sortKey: 101,
- entries: [
- {
- label: i18n.translate('xpack.inventory.inventoryLinkTitle', {
- defaultMessage: 'Inventory',
- }),
- app: INVENTORY_APP_ID,
- path: '/',
- matchPath(currentPath: string) {
- return ['/', ''].some((testPath) => currentPath.startsWith(testPath));
- },
- },
- ],
- },
- ];
- })
- )
+ const isEntityCentricExperienceSettingEnabled = coreSetup.uiSettings.get(
+ 'observability:entityCentricExperience',
+ true
);
+ if (isEntityCentricExperienceSettingEnabled) {
+ pluginsSetup.observabilityShared.navigation.registerSections(
+ from(coreSetup.getStartServices()).pipe(
+ map(([coreStart, pluginsStart]) => {
+ return [
+ {
+ label: '',
+ sortKey: 300,
+ entries: [
+ {
+ label: i18n.translate('xpack.inventory.inventoryLinkTitle', {
+ defaultMessage: 'Inventory',
+ }),
+ app: INVENTORY_APP_ID,
+ path: '/',
+ matchPath(currentPath: string) {
+ return ['/', ''].some((testPath) => currentPath.startsWith(testPath));
+ },
+ isTechnicalPreview: true,
+ },
+ ],
+ },
+ ];
+ })
+ )
+ );
+ }
+ this.telemetry.setup({ analytics: coreSetup.analytics });
const telemetry = this.telemetry.start();
coreSetup.application.register({
@@ -86,17 +93,11 @@ export class InventoryPlugin
euiIconType: 'logoObservability',
appRoute: '/app/observability/inventory',
category: DEFAULT_APP_CATEGORIES.observability,
- visibleIn: ['sideNav'],
- order: 8001,
- deepLinks: [
- {
- id: 'inventory',
- title: i18n.translate('xpack.inventory.inventoryDeepLinkTitle', {
- defaultMessage: 'Inventory',
- }),
- path: '/',
- },
- ],
+ visibleIn: ['sideNav', 'globalSearch'],
+ order: 8200,
+ status: isEntityCentricExperienceSettingEnabled
+ ? AppStatus.accessible
+ : AppStatus.inaccessible,
mount: async (appMountParameters: AppMountParameters) => {
// Load application bundle and Get start services
const [{ renderApp }, [coreStart, pluginsStart]] = await Promise.all([
diff --git a/x-pack/plugins/observability_solution/inventory/server/config.ts b/x-pack/plugins/observability_solution/inventory/server/config.ts
index 2d6d7604b40e..36f19bd6579a 100644
--- a/x-pack/plugins/observability_solution/inventory/server/config.ts
+++ b/x-pack/plugins/observability_solution/inventory/server/config.ts
@@ -8,7 +8,7 @@
import { schema, type TypeOf } from '@kbn/config-schema';
export const config = schema.object({
- enabled: schema.boolean({ defaultValue: false }),
+ enabled: schema.boolean({ defaultValue: true }),
});
export type InventoryConfig = TypeOf;
diff --git a/x-pack/plugins/observability_solution/inventory/server/feature.ts b/x-pack/plugins/observability_solution/inventory/server/feature.ts
new file mode 100644
index 000000000000..2b3f2e92a44d
--- /dev/null
+++ b/x-pack/plugins/observability_solution/inventory/server/feature.ts
@@ -0,0 +1,64 @@
+/*
+ * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
+ * or more contributor license agreements. Licensed under the Elastic License
+ * 2.0; you may not use this file except in compliance with the Elastic License
+ * 2.0.
+ */
+
+import { i18n } from '@kbn/i18n';
+import { DEFAULT_APP_CATEGORIES } from '@kbn/core/server';
+import { KibanaFeatureScope } from '@kbn/features-plugin/common';
+
+const INVENTORY_SERVER_FEATURE_ID = 'inventory';
+
+export const INVENTORY_SERVER_FEATURE = {
+ id: INVENTORY_SERVER_FEATURE_ID,
+ name: i18n.translate('xpack.inventory.featureRegistry.inventoryFeatureName', {
+ defaultMessage: 'Inventory',
+ }),
+ order: 1000,
+ category: DEFAULT_APP_CATEGORIES.observability,
+ scope: [KibanaFeatureScope.Spaces, KibanaFeatureScope.Security],
+ app: [INVENTORY_SERVER_FEATURE_ID],
+ catalogue: [INVENTORY_SERVER_FEATURE_ID],
+ alerting: [],
+ // see x-pack/plugins/features/common/feature_kibana_privileges.ts
+ privileges: {
+ all: {
+ app: [INVENTORY_SERVER_FEATURE_ID],
+ api: [INVENTORY_SERVER_FEATURE_ID],
+ catalogue: [INVENTORY_SERVER_FEATURE_ID],
+ savedObject: {
+ all: [],
+ read: [],
+ },
+ alerting: {
+ alert: {
+ all: [],
+ },
+ rule: {
+ all: [],
+ },
+ },
+ ui: ['show', 'save'],
+ },
+ read: {
+ app: [INVENTORY_SERVER_FEATURE_ID],
+ api: [INVENTORY_SERVER_FEATURE_ID],
+ catalogue: [INVENTORY_SERVER_FEATURE_ID],
+ savedObject: {
+ all: [],
+ read: [],
+ },
+ alerting: {
+ alert: {
+ read: [],
+ },
+ rule: {
+ read: [],
+ },
+ },
+ ui: ['show'],
+ },
+ },
+};
diff --git a/x-pack/plugins/observability_solution/inventory/server/plugin.ts b/x-pack/plugins/observability_solution/inventory/server/plugin.ts
index 1ac928b72cdb..642dd12769fb 100644
--- a/x-pack/plugins/observability_solution/inventory/server/plugin.ts
+++ b/x-pack/plugins/observability_solution/inventory/server/plugin.ts
@@ -17,6 +17,7 @@ import type {
InventorySetupDependencies,
InventoryStartDependencies,
} from './types';
+import { INVENTORY_SERVER_FEATURE } from './feature';
export class InventoryPlugin
implements
@@ -55,6 +56,9 @@ export class InventoryPlugin
}) as unknown as InventoryRouteHandlerResources['plugins'],
},
});
+
+ pluginsSetup.features.registerKibanaFeature(INVENTORY_SERVER_FEATURE);
+
return {};
}
diff --git a/x-pack/plugins/observability_solution/inventory/server/types.ts b/x-pack/plugins/observability_solution/inventory/server/types.ts
index a58bd62fe57a..05f75561674c 100644
--- a/x-pack/plugins/observability_solution/inventory/server/types.ts
+++ b/x-pack/plugins/observability_solution/inventory/server/types.ts
@@ -13,6 +13,7 @@ import type {
DataViewsServerPluginSetup,
DataViewsServerPluginStart,
} from '@kbn/data-views-plugin/server';
+import { FeaturesPluginSetup } from '@kbn/features-plugin/server';
/* eslint-disable @typescript-eslint/no-empty-interface*/
export interface ConfigSchema {}
@@ -21,6 +22,7 @@ export interface InventorySetupDependencies {
entityManager: EntityManagerServerPluginSetup;
inference: InferenceServerSetup;
dataViews: DataViewsServerPluginSetup;
+ features: FeaturesPluginSetup;
}
export interface InventoryStartDependencies {
diff --git a/x-pack/plugins/observability_solution/inventory/tsconfig.json b/x-pack/plugins/observability_solution/inventory/tsconfig.json
index c4b6b55d41f4..163e87108bf7 100644
--- a/x-pack/plugins/observability_solution/inventory/tsconfig.json
+++ b/x-pack/plugins/observability_solution/inventory/tsconfig.json
@@ -16,7 +16,6 @@
"kbn_references": [
"@kbn/core",
"@kbn/logging",
- "@kbn/config-schema",
"@kbn/observability-shared-plugin",
"@kbn/server-route-repository",
"@kbn/shared-ux-link-redirect-app",
@@ -40,7 +39,9 @@
"@kbn/data-plugin",
"@kbn/core-analytics-browser",
"@kbn/core-http-browser",
+ "@kbn/shared-svg",
+ "@kbn/features-plugin",
"@kbn/es-query",
- "@kbn/shared-svg"
+ "@kbn/config-schema"
]
}
diff --git a/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts b/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts
index 309d2f226430..353f1258fc7b 100644
--- a/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts
+++ b/x-pack/plugins/observability_solution/observability/public/navigation_tree.ts
@@ -67,9 +67,6 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) {
{
link: 'slo',
},
- {
- link: 'inventory',
- },
{
id: 'aiMl',
title: i18n.translate('xpack.observability.obltNav.ml.aiAndMlGroupTitle', {
@@ -132,6 +129,10 @@ export function createNavTree(pluginsStart: ObservabilityPublicPluginsStart) {
},
],
},
+ {
+ link: 'inventory',
+ spaceBefore: 'm',
+ },
{
id: 'apm',
title: i18n.translate('xpack.observability.obltNav.applications', {
diff --git a/x-pack/plugins/serverless_observability/public/navigation_tree.ts b/x-pack/plugins/serverless_observability/public/navigation_tree.ts
index 135c687655e2..e3c61ec0b29e 100644
--- a/x-pack/plugins/serverless_observability/public/navigation_tree.ts
+++ b/x-pack/plugins/serverless_observability/public/navigation_tree.ts
@@ -121,6 +121,7 @@ export const navigationTree: NavigationTreeDefinition = {
},
],
},
+ { link: 'inventory', spaceBefore: 'm' },
{
id: 'apm',
title: i18n.translate('xpack.serverlessObservability.nav.applications', {
diff --git a/x-pack/test/api_integration/apis/features/features/features.ts b/x-pack/test/api_integration/apis/features/features/features.ts
index d6602c0ce8cb..895bfcb851bd 100644
--- a/x-pack/test/api_integration/apis/features/features/features.ts
+++ b/x-pack/test/api_integration/apis/features/features/features.ts
@@ -120,6 +120,7 @@ export default function ({ getService }: FtrProviderContext) {
'canvas',
'generalCases',
'infrastructure',
+ 'inventory',
'logs',
'maintenanceWindow',
'maps',
@@ -168,6 +169,7 @@ export default function ({ getService }: FtrProviderContext) {
'canvas',
'generalCases',
'infrastructure',
+ 'inventory',
'logs',
'maintenanceWindow',
'maps',
diff --git a/x-pack/test/api_integration/apis/security/privileges.ts b/x-pack/test/api_integration/apis/security/privileges.ts
index a809d0837abc..8db8c08b1672 100644
--- a/x-pack/test/api_integration/apis/security/privileges.ts
+++ b/x-pack/test/api_integration/apis/security/privileges.ts
@@ -140,6 +140,7 @@ export default function ({ getService }: FtrProviderContext) {
maintenanceWindow: ['all', 'read', 'minimal_all', 'minimal_read'],
guidedOnboardingFeature: ['all', 'read', 'minimal_all', 'minimal_read'],
aiAssistantManagementSelection: ['all', 'read', 'minimal_all', 'minimal_read'],
+ inventory: ['all', 'read', 'minimal_all', 'minimal_read'],
},
reserved: ['fleet-setup', 'ml_user', 'ml_admin', 'ml_apm_user', 'monitoring'],
};
diff --git a/x-pack/test/api_integration/apis/security/privileges_basic.ts b/x-pack/test/api_integration/apis/security/privileges_basic.ts
index 59829c673e40..a82ecc2aa4fd 100644
--- a/x-pack/test/api_integration/apis/security/privileges_basic.ts
+++ b/x-pack/test/api_integration/apis/security/privileges_basic.ts
@@ -58,6 +58,7 @@ export default function ({ getService }: FtrProviderContext) {
maintenanceWindow: ['all', 'read', 'minimal_all', 'minimal_read'],
guidedOnboardingFeature: ['all', 'read', 'minimal_all', 'minimal_read'],
aiAssistantManagementSelection: ['all', 'read', 'minimal_all', 'minimal_read'],
+ inventory: ['all', 'read', 'minimal_all', 'minimal_read'],
},
global: ['all', 'read'],
space: ['all', 'read'],
@@ -226,6 +227,7 @@ export default function ({ getService }: FtrProviderContext) {
maintenanceWindow: ['all', 'read', 'minimal_all', 'minimal_read'],
guidedOnboardingFeature: ['all', 'read', 'minimal_all', 'minimal_read'],
aiAssistantManagementSelection: ['all', 'read', 'minimal_all', 'minimal_read'],
+ inventory: ['all', 'read', 'minimal_all', 'minimal_read'],
},
reserved: ['fleet-setup', 'ml_user', 'ml_admin', 'ml_apm_user', 'monitoring'],
};
diff --git a/x-pack/test/spaces_api_integration/spaces_only/telemetry/telemetry.ts b/x-pack/test/spaces_api_integration/spaces_only/telemetry/telemetry.ts
index d39c58bd2b6e..98b3c8835459 100644
--- a/x-pack/test/spaces_api_integration/spaces_only/telemetry/telemetry.ts
+++ b/x-pack/test/spaces_api_integration/spaces_only/telemetry/telemetry.ts
@@ -75,6 +75,7 @@ export default function ({ getService }: FtrProviderContext) {
uptime: 0,
slo: 0,
infrastructure: 0,
+ inventory: 0,
logs: 0,
monitoring: 0,
apm: 0,