diff --git a/x-pack/plugins/observability_solution/apm/kibana.jsonc b/x-pack/plugins/observability_solution/apm/kibana.jsonc
index c6a53232aaec0..0e305bc449c0e 100644
--- a/x-pack/plugins/observability_solution/apm/kibana.jsonc
+++ b/x-pack/plugins/observability_solution/apm/kibana.jsonc
@@ -45,6 +45,7 @@
"ml",
"security",
"spaces",
+ "serverless",
"taskManager",
"usageCollection",
"customIntegrations", // Move this to requiredPlugins after completely migrating from the Tutorials Home App
diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/breadcrumb/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/breadcrumb/index.tsx
index d6afe4a7c1d19..24c4b7e88fb1b 100644
--- a/x-pack/plugins/observability_solution/apm/public/components/app/breadcrumb/index.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/components/app/breadcrumb/index.tsx
@@ -11,16 +11,22 @@ import { useBreadcrumb } from '../../../context/breadcrumbs/use_breadcrumb';
export const Breadcrumb = ({
title,
href,
+ omitOnServerless = false,
children,
}: {
title: string;
href: string;
+ omitOnServerless?: boolean;
children: React.ReactElement;
}) => {
const { core } = useApmPluginContext();
+
useBreadcrumb(
() => ({ title, href: core.http.basePath.prepend('/app/apm' + href) }),
- [core.http.basePath, href, title]
+ [core.http.basePath, href, title],
+ {
+ omitOnServerless,
+ }
);
return children;
diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/dependency_detail_view/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/dependency_detail_view/index.tsx
index 5f6542fc7fe15..64ba12d64c06d 100644
--- a/x-pack/plugins/observability_solution/apm/public/components/app/dependency_detail_view/index.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/components/app/dependency_detail_view/index.tsx
@@ -69,7 +69,10 @@ export function DependencyDetailView({ children }: { children: React.ReactChild
rangeTo,
refreshInterval,
refreshPaused,
- ]
+ ],
+ {
+ omitRootOnServerless: true,
+ }
);
return {children};
}
diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx
index 63a7bf42c6650..ef7ea348d37f7 100644
--- a/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/components/app/dependency_operation_detail_view/index.tsx
@@ -50,7 +50,12 @@ export function DependencyOperationDetailView() {
},
} = useApmParams('/dependencies/operation');
- useDependencyDetailOperationsBreadcrumb();
+ useDependencyDetailOperationsBreadcrumb({
+ title: spanName,
+ href: router.link('/dependencies/operation', {
+ query,
+ }),
+ });
const { start, end } = useTimeRange({ rangeFrom, rangeTo });
diff --git a/x-pack/plugins/observability_solution/apm/public/components/app/trace_overview/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/app/trace_overview/index.tsx
index 9304dc298a2d6..40b079b684498 100644
--- a/x-pack/plugins/observability_solution/apm/public/components/app/trace_overview/index.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/components/app/trace_overview/index.tsx
@@ -96,7 +96,7 @@ export function TraceOverview({ children }: { children: React.ReactElement }) {
: [];
return (
-
+
@@ -95,7 +96,7 @@ const apmRoutes = {
// this route fails on navigation unless it's defined before home
'/service-groups': {
element: (
-
+
({
return {
[path]: {
element: (
-
-
- {element}
-
-
+
+ {element}
+
),
params: t.type({
query: t.type({ serviceGroup: t.string }),
diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/home/page_template.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/home/page_template.tsx
index e003de27d982d..1e5508bceb4ed 100644
--- a/x-pack/plugins/observability_solution/apm/public/components/routing/home/page_template.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/components/routing/home/page_template.tsx
@@ -38,7 +38,7 @@ export function page<
return {
[path]: {
element: (
-
+
;
diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/settings/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/settings/index.tsx
index 1cb7d7ec9ede1..e8f03da90c4c6 100644
--- a/x-pack/plugins/observability_solution/apm/public/components/routing/settings/index.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/components/routing/settings/index.tsx
@@ -52,6 +52,7 @@ export const settingsRoute = {
title={i18n.translate('xpack.apm.views.listSettings.title', {
defaultMessage: 'Settings',
})}
+ omitOnServerless
>
diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/entities/logs_service_template/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/entities/logs_service_template/index.tsx
index 1588b6ffafece..5b2b95ef41624 100644
--- a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/entities/logs_service_template/index.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/entities/logs_service_template/index.tsx
@@ -82,7 +82,10 @@ function TemplateWithContext({ title, children, selectedTabKey, searchBarOptions
]
: []),
],
- [query, router, selectedTab, serviceName, servicesLink]
+ [query, router, selectedTab, serviceName, servicesLink],
+ {
+ omitRootOnServerless: true,
+ }
);
return (
diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/mobile_service_template/index.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/mobile_service_template/index.tsx
index d9069c7d9f2f2..0c6a1f4176ec5 100644
--- a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/mobile_service_template/index.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/mobile_service_template/index.tsx
@@ -92,7 +92,10 @@ function TemplateWithContext({ title, children, selectedTabKey, searchBarOptions
]
: []),
],
- [query, router, selectedTab, serviceName, servicesLink]
+ [query, router, selectedTab, serviceName, servicesLink],
+ {
+ omitRootOnServerless: true,
+ }
);
return (
diff --git a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/service_group_template.tsx b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/service_group_template.tsx
index 0617e900c601f..67695c6485006 100644
--- a/x-pack/plugins/observability_solution/apm/public/components/routing/templates/service_group_template.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/components/routing/templates/service_group_template.tsx
@@ -26,13 +26,15 @@ import { useEntityManagerEnablementContext } from '../../../context/entity_manag
export function ServiceGroupTemplate({
pageTitle,
pageHeader,
+ pagePath,
children,
environmentFilter = true,
serviceGroupContextTab,
...pageTemplateProps
}: {
- pageTitle?: React.ReactNode;
+ pageTitle: string;
pageHeader?: EuiPageHeaderProps;
+ pagePath: string;
children: React.ReactNode;
environmentFilter?: boolean;
serviceGroupContextTab: ServiceGroupContextTab['key'];
@@ -81,34 +83,44 @@ export function ServiceGroupTemplate({
);
const tabs = useTabs(serviceGroupContextTab);
- const selectedTab = tabs?.find(({ isSelected }) => isSelected);
+ const selectedTab = tabs.find(({ isSelected }) => isSelected);
+
+ // this is only used for building the breadcrumbs for the service group page
useBreadcrumb(
- () => [
- {
- title: i18n.translate('xpack.apm.serviceGroups.breadcrumb.title', {
- defaultMessage: 'Services',
- }),
- href: serviceGroupsLink,
- },
- ...(selectedTab
+ () =>
+ !serviceGroupName
? [
- ...(serviceGroupName
+ {
+ title: pageTitle,
+ href: pagePath,
+ },
+ ]
+ : [
+ {
+ title: i18n.translate('xpack.apm.serviceGroups.breadcrumb.title', {
+ defaultMessage: 'Services',
+ }),
+ href: serviceGroupsLink,
+ },
+ {
+ title: serviceGroupName,
+ href: router.link('/services', { query }),
+ },
+ ...(selectedTab
? [
{
- title: serviceGroupName,
- href: router.link('/services', { query }),
- },
+ title: selectedTab.breadcrumbLabel || selectedTab.label,
+ href: selectedTab.href,
+ } as { title: string; href: string },
]
: []),
- {
- title: selectedTab.breadcrumbLabel || selectedTab.label,
- href: selectedTab.href,
- } as { title: string; href: string },
- ]
- : []),
- ],
- [query, router, selectedTab, serviceGroupName, serviceGroupsLink]
+ ],
+ [pagePath, pageTitle, query, router, selectedTab, serviceGroupName, serviceGroupsLink],
+ {
+ omitRootOnServerless: true,
+ }
);
+
return (
(undef
export function BreadcrumbsContextProvider({ children }: { children: React.ReactElement }) {
const [, forceUpdate] = useState({});
+ const {
+ services: { serverless },
+ } = useKibana();
const breadcrumbs = useMemo(() => {
return new Map();
@@ -72,7 +76,7 @@ export function BreadcrumbsContextProvider({ children }: { children: React.React
};
});
- useBreadcrumbs(formattedBreadcrumbs);
+ useBreadcrumbs(formattedBreadcrumbs, { serverless });
return {children};
}
diff --git a/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/use_breadcrumb.ts b/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/use_breadcrumb.ts
index 5e3fb08b8f276..a6b80fd088bff 100644
--- a/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/use_breadcrumb.ts
+++ b/x-pack/plugins/observability_solution/apm/public/context/breadcrumbs/use_breadcrumb.ts
@@ -9,8 +9,16 @@ import { useCurrentRoute } from '@kbn/typed-react-router-config';
import { useContext, useEffect, useRef } from 'react';
import { castArray } from 'lodash';
import { Breadcrumb, BreadcrumbsContext } from './context';
+import { useKibanaEnvironmentContext } from '../kibana_environment_context/use_kibana_environment_context';
+
+export function useBreadcrumb(
+ callback: () => Breadcrumb | Breadcrumb[],
+ fnDeps: any[],
+ options?: { omitRootOnServerless?: boolean; omitOnServerless?: boolean }
+) {
+ const { isServerlessEnv } = useKibanaEnvironmentContext();
+ const { omitRootOnServerless = false, omitOnServerless = false } = options || {};
-export function useBreadcrumb(callback: () => Breadcrumb | Breadcrumb[], fnDeps: any[]) {
const api = useContext(BreadcrumbsContext);
if (!api) {
@@ -22,6 +30,10 @@ export function useBreadcrumb(callback: () => Breadcrumb | Breadcrumb[], fnDeps:
const matchedRoute = useRef(match?.route);
useEffect(() => {
+ if (isServerlessEnv && omitOnServerless) {
+ return;
+ }
+
if (matchedRoute.current && matchedRoute.current !== match?.route) {
api.unset(matchedRoute.current);
}
@@ -29,7 +41,14 @@ export function useBreadcrumb(callback: () => Breadcrumb | Breadcrumb[], fnDeps:
matchedRoute.current = match?.route;
if (matchedRoute.current) {
- api.set(matchedRoute.current, castArray(callback()));
+ const breadcrumbs = castArray(callback());
+
+ api.set(
+ matchedRoute.current,
+ isServerlessEnv && omitRootOnServerless && breadcrumbs.length >= 1
+ ? breadcrumbs.slice(1)
+ : breadcrumbs
+ );
}
return () => {
diff --git a/x-pack/plugins/observability_solution/apm/public/context/kibana_environment_context/kibana_environment_context.tsx b/x-pack/plugins/observability_solution/apm/public/context/kibana_environment_context/kibana_environment_context.tsx
index acf974d4d2dae..61c7f1e5e7ff1 100644
--- a/x-pack/plugins/observability_solution/apm/public/context/kibana_environment_context/kibana_environment_context.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/context/kibana_environment_context/kibana_environment_context.tsx
@@ -4,7 +4,7 @@
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/
-
+import React from 'react';
import { createContext } from 'react';
export interface KibanaEnvContext {
@@ -14,3 +14,17 @@ export interface KibanaEnvContext {
}
export const KibanaEnvironmentContext = createContext({});
+
+export function KibanaEnvironmentContextProvider({
+ children,
+ kibanaEnvironment,
+}: {
+ kibanaEnvironment: KibanaEnvContext;
+ children: React.ReactElement;
+}) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/x-pack/plugins/observability_solution/apm/public/context/kibana_environment_context/use_kibana_environment_context.tsx b/x-pack/plugins/observability_solution/apm/public/context/kibana_environment_context/use_kibana_environment_context.tsx
index 5f3830a5524f0..fbdbe1073cf8c 100644
--- a/x-pack/plugins/observability_solution/apm/public/context/kibana_environment_context/use_kibana_environment_context.tsx
+++ b/x-pack/plugins/observability_solution/apm/public/context/kibana_environment_context/use_kibana_environment_context.tsx
@@ -5,35 +5,9 @@
* 2.0.
*/
-import { useMemo, createElement, FC, PropsWithChildren } from 'react';
-import { KibanaEnvironmentContext, type KibanaEnvContext } from './kibana_environment_context';
+import { useContext } from 'react';
+import { KibanaEnvironmentContext } from './kibana_environment_context';
-export const useKibanaEnvironmentContextProvider = ({
- kibanaVersion,
- isCloudEnv,
- isServerlessEnv,
-}: KibanaEnvContext) => {
- const value = useMemo(
- () => ({
- kibanaVersion,
- isCloudEnv,
- isServerlessEnv,
- }),
- [kibanaVersion, isCloudEnv, isServerlessEnv]
- );
-
- const Provider: FC<
- PropsWithChildren<{
- kibanaEnvironment?: KibanaEnvContext;
- }>
- > = ({ kibanaEnvironment = {}, children }) => {
- const newProvider = createElement(KibanaEnvironmentContext.Provider, {
- value: { ...kibanaEnvironment, ...value },
- children,
- });
-
- return newProvider;
- };
-
- return Provider;
+export const useKibanaEnvironmentContext = () => {
+ return useContext(KibanaEnvironmentContext);
};
diff --git a/x-pack/plugins/observability_solution/apm/public/hooks/use_dependency_detail_operations_breadcrumb.ts b/x-pack/plugins/observability_solution/apm/public/hooks/use_dependency_detail_operations_breadcrumb.ts
index 5a0516531f443..197e03845a953 100644
--- a/x-pack/plugins/observability_solution/apm/public/hooks/use_dependency_detail_operations_breadcrumb.ts
+++ b/x-pack/plugins/observability_solution/apm/public/hooks/use_dependency_detail_operations_breadcrumb.ts
@@ -6,11 +6,15 @@
*/
import { i18n } from '@kbn/i18n';
+import { castArray } from 'lodash';
import { useBreadcrumb } from '../context/breadcrumbs/use_breadcrumb';
import { useAnyOfApmParams } from './use_apm_params';
import { useApmRouter } from './use_apm_router';
+import { Breadcrumb } from '../context/breadcrumbs/context';
-export function useDependencyDetailOperationsBreadcrumb() {
+export function useDependencyDetailOperationsBreadcrumb(
+ extraBreadCrumbs: Breadcrumb | Breadcrumb[] = []
+) {
const {
query: {
dependencyName,
@@ -45,12 +49,14 @@ export function useDependencyDetailOperationsBreadcrumb() {
},
}),
},
+ ...castArray(extraBreadCrumbs),
],
[
apmRouter,
comparisonEnabled,
dependencyName,
environment,
+ extraBreadCrumbs,
kuery,
rangeFrom,
rangeTo,
diff --git a/x-pack/plugins/observability_solution/apm/public/plugin.ts b/x-pack/plugins/observability_solution/apm/public/plugin.ts
index c45d8f7abba64..9524f328755c0 100644
--- a/x-pack/plugins/observability_solution/apm/public/plugin.ts
+++ b/x-pack/plugins/observability_solution/apm/public/plugin.ts
@@ -69,6 +69,7 @@ import type { IUiSettingsClient } from '@kbn/core-ui-settings-browser';
import { from } from 'rxjs';
import { map } from 'rxjs';
import type { CloudSetup } from '@kbn/cloud-plugin/public';
+import type { ServerlessPluginStart } from '@kbn/serverless/public';
import type { ConfigSchema } from '.';
import { registerApmRuleTypes } from './components/alerting/rule_types/register_apm_rule_types';
import { registerEmbeddables } from './embeddable/register_embeddables';
@@ -134,6 +135,7 @@ export interface ApmPluginStartDeps {
fieldFormats?: FieldFormatsStart;
security?: SecurityPluginStart;
spaces?: SpacesPluginStart;
+ serverless?: ServerlessPluginStart;
dataViews: DataViewsPublicPluginStart;
unifiedSearch: UnifiedSearchPublicPluginStart;
storage: IStorageWrapper;
diff --git a/x-pack/plugins/observability_solution/apm/tsconfig.json b/x-pack/plugins/observability_solution/apm/tsconfig.json
index a31ddcca0bdce..7de9609dbbafe 100644
--- a/x-pack/plugins/observability_solution/apm/tsconfig.json
+++ b/x-pack/plugins/observability_solution/apm/tsconfig.json
@@ -128,6 +128,7 @@
"@kbn/core-analytics-browser",
"@kbn/apm-types",
"@kbn/entities-schema",
+ "@kbn/serverless",
"@kbn/aiops-log-rate-analysis",
"@kbn/router-utils"
],
diff --git a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/index.tsx b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/index.tsx
index 392420ee547f8..c4061f05ce91b 100644
--- a/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/index.tsx
+++ b/x-pack/plugins/observability_solution/exploratory_view/public/components/shared/exploratory_view/index.tsx
@@ -60,7 +60,7 @@ export function ExploratoryViewPage({
}),
},
],
- app
+ { app }
);
const kbnUrlStateStorage = useSessionStorage
diff --git a/x-pack/plugins/observability_solution/observability/public/pages/annotations/annotations.tsx b/x-pack/plugins/observability_solution/observability/public/pages/annotations/annotations.tsx
index d0c6723f4f438..f601b4ff99a3f 100644
--- a/x-pack/plugins/observability_solution/observability/public/pages/annotations/annotations.tsx
+++ b/x-pack/plugins/observability_solution/observability/public/pages/annotations/annotations.tsx
@@ -22,20 +22,24 @@ export const ANNOTATIONS_PAGE_ID = 'annotations-container';
export function AnnotationsPage() {
const {
http: { basePath },
+ serverless,
} = useKibana().services;
const { ObservabilityPageTemplate } = usePluginContext();
const checkPrivileges = useAnnotationsPrivileges();
- useBreadcrumbs([
- {
- href: basePath.prepend(paths.observability.annotations),
- text: i18n.translate('xpack.observability.breadcrumbs.annotationsLinkText', {
- defaultMessage: 'Annotations',
- }),
- deepLinkId: 'observability-overview',
- },
- ]);
+ useBreadcrumbs(
+ [
+ {
+ href: basePath.prepend(paths.observability.annotations),
+ text: i18n.translate('xpack.observability.breadcrumbs.annotationsLinkText', {
+ defaultMessage: 'Annotations',
+ }),
+ deepLinkId: 'observability-overview',
+ },
+ ],
+ { serverless }
+ );
return (
{
const params = useQueryParams();
+ const { app, breadcrumbsAppendExtension, serverless } = options ?? {};
const {
services: {
- chrome: { docTitle, setBreadcrumbs, setBreadcrumbsAppendExtension },
+ chrome: { docTitle, setBreadcrumbs: chromeSetBreadcrumbs, setBreadcrumbsAppendExtension },
application: { getUrlForApp, navigateToUrl },
},
} = useKibana<{
@@ -54,6 +59,11 @@ export const useBreadcrumbs = (
const setTitle = docTitle.change;
const appPath = getUrlForApp(app?.id ?? 'observability-overview') ?? '';
+ const setBreadcrumbs = useMemo(
+ () => serverless?.setBreadcrumbs ?? chromeSetBreadcrumbs,
+ [serverless, chromeSetBreadcrumbs]
+ );
+
useEffect(() => {
if (breadcrumbsAppendExtension) {
setBreadcrumbsAppendExtension(breadcrumbsAppendExtension);
@@ -66,22 +76,34 @@ export const useBreadcrumbs = (
}, [breadcrumbsAppendExtension, setBreadcrumbsAppendExtension]);
useEffect(() => {
- const breadcrumbs = [
- {
- text:
- app?.label ??
- i18n.translate('xpack.observabilityShared.breadcrumbs.observabilityLinkText', {
- defaultMessage: 'Observability',
- }),
- href: appPath + '/overview',
- },
- ...extraCrumbs,
- ];
+ const breadcrumbs = serverless
+ ? extraCrumbs
+ : [
+ {
+ text:
+ app?.label ??
+ i18n.translate('xpack.observabilityShared.breadcrumbs.observabilityLinkText', {
+ defaultMessage: 'Observability',
+ }),
+ href: appPath + '/overview',
+ },
+ ...extraCrumbs,
+ ];
+
if (setBreadcrumbs) {
setBreadcrumbs(addClickHandlers(breadcrumbs, navigateToUrl));
}
if (setTitle) {
setTitle(getTitleFromBreadCrumbs(breadcrumbs));
}
- }, [app?.label, appPath, extraCrumbs, navigateToUrl, params, setBreadcrumbs, setTitle]);
+ }, [
+ app?.label,
+ appPath,
+ extraCrumbs,
+ navigateToUrl,
+ params,
+ serverless,
+ setBreadcrumbs,
+ setTitle,
+ ]);
};
diff --git a/x-pack/plugins/observability_solution/observability_shared/tsconfig.json b/x-pack/plugins/observability_solution/observability_shared/tsconfig.json
index 371807ecdd5a2..6453bae28d999 100644
--- a/x-pack/plugins/observability_solution/observability_shared/tsconfig.json
+++ b/x-pack/plugins/observability_solution/observability_shared/tsconfig.json
@@ -43,6 +43,7 @@
"@kbn/core-chrome-browser",
"@kbn/rule-data-utils",
"@kbn/es-query",
+ "@kbn/serverless",
],
"exclude": ["target/**/*"]
}