From a6deeb7a8fb77923c16162c786cf9f0e280fc935 Mon Sep 17 00:00:00 2001 From: mohamedhamed-ahmed Date: Wed, 30 Oct 2024 08:43:35 +0000 Subject: [PATCH] [Stream] Fix callout privileges (#198030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit closes https://github.com/elastic/kibana/issues/197044 closes https://github.com/elastic/kibana/issues/197988 ## 📝 Summary The PR targets fixing 3 bugs: 1. The callout shouldn't be shown if `Logs Explorer` isn't available, otherwise the link displayed in the callout will cause a problem. [Fix here](https://github.com/elastic/kibana/pull/198030/files#diff-8c5f793d1bf0d933c73047f31ded8a5a65f91e4f8d5230fc4e40dfb9b245fec1R66) 2. The callout shouldn't be shown if `Logs Explorer` is available but the user doesn't have privilege to access it, otherwise we end up in `Application Not Found` page. [Fix here](https://github.com/elastic/kibana/pull/198030/files#diff-8c5f793d1bf0d933c73047f31ded8a5a65f91e4f8d5230fc4e40dfb9b245fec1R66) 3. The side nav entry for `Logs Explorer` should be hidden if `Logs Explorer` is disabled. [Fix here](https://github.com/elastic/kibana/pull/198030/files#diff-ad4e42fbe4d2a7a99ec5d52fbf127ded12f0efe02a10e3afa0409b40be1f4bcfR397) (cherry picked from commit 5576316abadc4115020f2e22bd823b413c8e98a2) # Conflicts: # x-pack/plugins/observability_solution/infra/public/plugin.ts --- .../components/logs_deprecation_callout.tsx | 26 +++++++---- .../infra/public/plugin.ts | 43 +++++++++++++------ 2 files changed, 48 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx b/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx index 63107f4a4d031..21e61c08d281b 100644 --- a/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx +++ b/x-pack/plugins/observability_solution/infra/public/components/logs_deprecation_callout.tsx @@ -9,13 +9,17 @@ import { EuiCallOut } from '@elastic/eui'; import React from 'react'; import { i18n } from '@kbn/i18n'; import { EuiButton } from '@elastic/eui'; -import { AllDatasetsLocatorParams, ALL_DATASETS_LOCATOR_ID } from '@kbn/deeplinks-observability'; +import { + AllDatasetsLocatorParams, + ALL_DATASETS_LOCATOR_ID, + DatasetLocatorParams, +} from '@kbn/deeplinks-observability'; import { getRouterLinkProps } from '@kbn/router-utils'; import useLocalStorage from 'react-use/lib/useLocalStorage'; import { euiThemeVars } from '@kbn/ui-theme'; import { css } from '@emotion/css'; -import { SharePublicStart } from '@kbn/share-plugin/public/plugin'; +import { LocatorPublic } from '@kbn/share-plugin/common'; import { useKibanaContextForPlugin } from '../hooks/use_kibana'; const pageConfigurations = { @@ -44,14 +48,22 @@ interface LogsDeprecationCalloutProps { export const LogsDeprecationCallout = ({ page }: LogsDeprecationCalloutProps) => { const { - services: { share }, + services: { + share, + application: { + capabilities: { discover, fleet }, + }, + }, } = useKibanaContextForPlugin(); const { dismissalStorageKey, message } = pageConfigurations[page]; const [isDismissed, setDismissed] = useLocalStorage(dismissalStorageKey, false); - if (isDismissed) { + const allDatasetLocator = + share.url.locators.get(ALL_DATASETS_LOCATOR_ID); + + if (isDismissed || !(allDatasetLocator && discover?.show && fleet?.read)) { return null; } @@ -71,7 +83,7 @@ export const LogsDeprecationCallout = ({ page }: LogsDeprecationCalloutProps) => fill data-test-subj="infraLogsDeprecationCalloutTryLogsExplorerButton" color="warning" - {...getLogsExplorerLinkProps(share)} + {...getLogsExplorerLinkProps(allDatasetLocator)} > {i18n.translate('xpack.infra.logsDeprecationCallout.tryLogsExplorerButtonLabel', { defaultMessage: 'Try Logs Explorer', @@ -81,9 +93,7 @@ export const LogsDeprecationCallout = ({ page }: LogsDeprecationCalloutProps) => ); }; -const getLogsExplorerLinkProps = (share: SharePublicStart) => { - const locator = share.url.locators.get(ALL_DATASETS_LOCATOR_ID)!; - +const getLogsExplorerLinkProps = (locator: LocatorPublic) => { return getRouterLinkProps({ href: locator.getRedirectUrl({}), onClick: () => locator.navigate({}), diff --git a/x-pack/plugins/observability_solution/infra/public/plugin.ts b/x-pack/plugins/observability_solution/infra/public/plugin.ts index daaa3510e1660..022db55b2a678 100644 --- a/x-pack/plugins/observability_solution/infra/public/plugin.ts +++ b/x-pack/plugins/observability_solution/infra/public/plugin.ts @@ -13,6 +13,7 @@ import { DEFAULT_APP_CATEGORIES, PluginInitializerContext, AppDeepLinkLocations, + AppStatus, } from '@kbn/core/public'; import { i18n } from '@kbn/i18n'; import { enableInfrastructureHostsView } from '@kbn/observability-plugin/public'; @@ -35,6 +36,7 @@ import { } from '@kbn/observability-shared-plugin/common'; import { OBSERVABILITY_ENABLE_LOGS_STREAM } from '@kbn/management-settings-ids'; import { NavigationEntry } from '@kbn/observability-shared-plugin/public'; +import { OBSERVABILITY_LOGS_EXPLORER_APP_ID } from '@kbn/deeplinks-observability/constants'; import type { InfraPublicConfig } from '../common/plugin_config_types'; import { createInventoryMetricRuleType } from './alerting/inventory'; import { createLogThresholdRuleType } from './alerting/log_threshold'; @@ -145,12 +147,12 @@ export class Plugin implements InfraClientPluginClass { ([ [ { - application: { capabilities }, + application, }, ], isInfrastructureHostsViewEnabled, ]) => { - const { infrastructure, logs } = capabilities; + const { infrastructure, logs } = application.capabilities; return [ ...(logs.show ? [ @@ -158,7 +160,7 @@ export class Plugin implements InfraClientPluginClass { label: logsTitle, sortKey: 200, entries: getLogsNavigationEntries({ - capabilities, + application, config: this.config, routes: logRoutes, }), @@ -408,11 +410,11 @@ export class Plugin implements InfraClientPluginClass { } const getLogsNavigationEntries = ({ - capabilities, + application, config, routes, }: { - capabilities: CoreStart['application']['capabilities']; + application: CoreStart['application']; config: InfraPublicConfig; routes: LogsAppRoutes; }) => { @@ -420,14 +422,16 @@ const getLogsNavigationEntries = ({ if (!config.featureFlags.logsUIEnabled) return entries; - if (capabilities.discover?.show && capabilities.fleet?.read) { - entries.push({ - label: 'Explorer', - app: 'observability-logs-explorer', - path: '/', - isBetaFeature: true, - }); - } + getLogsExplorerAccessibility$(application).subscribe((isAccessible) => { + if (isAccessible) { + entries.push({ + label: 'Explorer', + app: 'observability-logs-explorer', + path: '/', + isBetaFeature: true, + }); + } + }); // Display Stream nav entry when Logs Stream is enabled if (routes.stream) entries.push(createNavEntryFromRoute(routes.stream)); @@ -440,6 +444,19 @@ const getLogsNavigationEntries = ({ return entries; }; +const getLogsExplorerAccessibility$ = (application: CoreStart['application']) => { + const { capabilities, applications$ } = application; + return applications$.pipe( + map( + (apps) => + (apps.get(OBSERVABILITY_LOGS_EXPLORER_APP_ID)?.status ?? AppStatus.inaccessible) === + AppStatus.accessible && + capabilities.discover?.show && + capabilities.fleet?.read + ) + ); +}; + const createNavEntryFromRoute = ({ path, title }: LogsRoute): NavigationEntry => ({ app: 'logs', label: title,