From f0c0bee2552cbfd74cde6190c95fa83044f22258 Mon Sep 17 00:00:00 2001 From: Nicolas Chaulet Date: Thu, 21 Nov 2024 15:12:42 -0500 Subject: [PATCH] [Fleet] Fix dashboard link accross multiple space --- .../components/agent_dashboard_link.tsx | 34 ++++++++++- .../components/dashboards_buttons.tsx | 60 ++++++++++++------- .../agents/services/dashboard_helper.test.ts | 38 ++++++++++++ .../agents/services/dashboard_helpers.ts | 32 ++++++++++ 4 files changed, 141 insertions(+), 23 deletions(-) create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helper.test.ts create mode 100644 x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helpers.ts diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.tsx index 6832f81961ddb..c6a7c6b1a7d43 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_dashboard_link.tsx @@ -10,21 +10,49 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { EuiButton, EuiToolTip } from '@elastic/eui'; import styled from 'styled-components'; -import { useGetPackageInfoByKeyQuery, useLink, useDashboardLocator } from '../../../../hooks'; +import type { GetInfoResponse } from '../../../../../../../common/types'; +import { + useGetPackageInfoByKeyQuery, + useLink, + useDashboardLocator, + useFleetStatus, +} from '../../../../hooks'; import type { Agent, AgentPolicy } from '../../../../types'; import { FLEET_ELASTIC_AGENT_PACKAGE, DASHBOARD_LOCATORS_IDS, } from '../../../../../../../common/constants'; +import { getDashboardIdForSpace } from '../../services/dashboard_helpers'; + +function isKibanaAssetsInstalledInSpace(spaceId: string | undefined, res?: GetInfoResponse) { + if (res?.item?.status !== 'installed') { + return false; + } + + const installationInfo = res.item.installationInfo; + + if (!installationInfo || installationInfo.install_status !== 'installed') { + return false; + } + return ( + installationInfo.installed_kibana_space_id === spaceId || + (spaceId && installationInfo.additional_spaces_installed_kibana?.[spaceId]) + ); +} function useAgentDashboardLink(agent: Agent) { const { isLoading, data } = useGetPackageInfoByKeyQuery(FLEET_ELASTIC_AGENT_PACKAGE); + const { spaceId } = useFleetStatus(); - const isInstalled = data?.item.status === 'installed'; + const isInstalled = isKibanaAssetsInstalledInSpace(spaceId, data); const dashboardLocator = useDashboardLocator(); const link = dashboardLocator?.getRedirectUrl({ - dashboardId: DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_AGENT_METRICS, + dashboardId: getDashboardIdForSpace( + spaceId, + data, + DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_AGENT_METRICS + ), query: { language: 'kuery', query: `elastic_agent.id:${agent.id}`, diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/dashboards_buttons.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/dashboards_buttons.tsx index 25c394e2606b0..3e50258071576 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/dashboards_buttons.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/dashboards_buttons.tsx @@ -5,49 +5,69 @@ * 2.0. */ -import React, { useEffect } from 'react'; +import React from 'react'; import { EuiFlexGroup, EuiFlexItem, EuiButtonEmpty } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; +import { useQuery } from '@tanstack/react-query'; -import { DASHBOARD_LOCATORS_IDS } from '../../../../../../../common/constants'; +import { + DASHBOARD_LOCATORS_IDS, + FLEET_ELASTIC_AGENT_PACKAGE, +} from '../../../../../../../common/constants'; -import { useDashboardLocator, useStartServices } from '../../../../hooks'; +import { + useDashboardLocator, + useFleetStatus, + useGetPackageInfoByKeyQuery, + useStartServices, +} from '../../../../hooks'; + +import { getDashboardIdForSpace } from '../../services/dashboard_helpers'; const useDashboardExists = (dashboardId: string) => { - const [dashboardExists, setDashboardExists] = React.useState(false); - const [loading, setLoading] = React.useState(true); const { dashboard: dashboardPlugin } = useStartServices(); - useEffect(() => { - const fetchDashboard = async () => { + const { data, isLoading } = useQuery({ + queryKey: ['dashboard_exists', dashboardId], + queryFn: async () => { try { const findDashboardsService = await dashboardPlugin.findDashboardsService(); const [dashboard] = await findDashboardsService.findByIds([dashboardId]); - setLoading(false); - setDashboardExists(dashboard?.status === 'success'); + return dashboard?.status === 'success'; } catch (e) { - setLoading(false); - setDashboardExists(false); + return false; } - }; - - fetchDashboard(); - }, [dashboardId, dashboardPlugin]); - - return { dashboardExists, loading }; + }, + }); + return { dashboardExists: data ?? false, loading: isLoading }; }; export const DashboardsButtons: React.FunctionComponent = () => { + const { data } = useGetPackageInfoByKeyQuery(FLEET_ELASTIC_AGENT_PACKAGE); + const { spaceId } = useFleetStatus(); + const dashboardLocator = useDashboardLocator(); const getDashboardHref = (dashboardId: string) => { return dashboardLocator?.getRedirectUrl({ dashboardId }) || ''; }; - const { dashboardExists, loading: dashboardLoading } = useDashboardExists( + const elasticAgentOverviewDashboardId = getDashboardIdForSpace( + spaceId, + data, DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_OVERVIEW ); + const elasticAgentInfoDashboardId = getDashboardIdForSpace( + spaceId, + data, + DASHBOARD_LOCATORS_IDS.ELASTIC_AGENT_AGENT_INFO + ); + + const { dashboardExists, loading: dashboardLoading } = useDashboardExists( + elasticAgentOverviewDashboardId + ); + if (dashboardLoading || !dashboardExists) { return null; } @@ -58,7 +78,7 @@ export const DashboardsButtons: React.FunctionComponent = () => { { { + it('return the same id if package is installed in the same space', () => { + expect(() => getDashboardIdForSpace('default', PKG_INFO, 'test-id-1')); + }); + + it('return the destination ID if package is installed in an additionnal space', () => { + expect(() => getDashboardIdForSpace('test', PKG_INFO, 'test-id-1')); + }); +}); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helpers.ts b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helpers.ts new file mode 100644 index 0000000000000..bc46118b93fe3 --- /dev/null +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/services/dashboard_helpers.ts @@ -0,0 +1,32 @@ +/* + * 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 { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; + +import type { GetInfoResponse } from '../../../../../../common'; + +export function getDashboardIdForSpace( + spaceId: string = DEFAULT_SPACE_ID, + res: GetInfoResponse | undefined, + dashboardId: string +) { + if (res?.item?.status !== 'installed') { + return dashboardId; + } + + const installationInfo = res.item.installationInfo; + + if (!installationInfo || installationInfo?.installed_kibana_space_id === spaceId) { + return dashboardId; + } + + return ( + installationInfo.additional_spaces_installed_kibana?.[spaceId]?.find( + ({ originId }) => originId === dashboardId + )?.id ?? dashboardId + ); +}