From c85fd474a6272087fdfb45086d280a75725861c7 Mon Sep 17 00:00:00 2001 From: Cristina Amico Date: Wed, 10 Jul 2024 17:17:31 +0200 Subject: [PATCH] [Fleet] Display view in logs button when logs app is available (#187871) Closes https://github.com/elastic/kibana/issues/185711 ## Summary This change fixes https://github.com/elastic/kibana/issues/185711, but while working on that I also realised that we should move away from using hardcoded urls. So this PR does two things: - Displays the button only when the user has `authz.fleet.readAgents` privilege - Refactors the button functionality to use the new locators that take care of linking to the observability logs/discover app ### Why the refactor While testing this button, I noticed that the functionality was broken in some cases, that's because we were manually routing the urls to Logs UI/Discover apps based if we are in serverless or not. I found a PR that already implements this functionality: https://github.com/elastic/kibana/pull/155156 I also found https://github.com/elastic/kibana/pull/154145 that takes care of the redirect to the correct app. So I'm replacing the current manual functionality with these utilities so that `getLogsLocatorsFromUrlService` takes care of where the open in logs button should link. ### ESS https://github.com/elastic/kibana/assets/16084106/3f0760c9-3afb-4793-a3af-317f625b36d7 https://github.com/elastic/kibana/assets/16084106/3436cf5a-36c9-425d-a114-e116ddaa1a03 ### Serverless https://github.com/elastic/kibana/assets/16084106/84176f09-96a4-4932-9508-5f7682d03aae --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Co-authored-by: Elastic Machine (cherry picked from commit 696bb88d7c33eebfeabec6064ea8a97a2e2bb1bb) --- .../fleet/common/constants/locators.ts | 1 + .../components/agent_logs/agent_logs.test.tsx | 49 +++++++---- .../components/agent_logs/agent_logs.tsx | 10 +-- .../agent_logs/view_logs_button.tsx | 84 +++++++------------ .../agent_activity_flyout/index.test.tsx | 26 +++++- .../components/view_errors.test.tsx | 75 ++++++++++++----- .../components/view_errors.tsx | 23 +++-- .../public/custom_logs_assets_extension.tsx | 1 + .../plugins/fleet/public/hooks/use_locator.ts | 4 + x-pack/plugins/fleet/tsconfig.json | 1 - .../translations/translations/fr-FR.json | 1 - .../translations/translations/ja-JP.json | 1 - .../translations/translations/zh-CN.json | 1 - 13 files changed, 165 insertions(+), 112 deletions(-) diff --git a/x-pack/plugins/fleet/common/constants/locators.ts b/x-pack/plugins/fleet/common/constants/locators.ts index daa00bcae46e0..cca0687a172d8 100644 --- a/x-pack/plugins/fleet/common/constants/locators.ts +++ b/x-pack/plugins/fleet/common/constants/locators.ts @@ -8,6 +8,7 @@ export const LOCATORS_IDS = { APM_LOCATOR: 'APM_LOCATOR', DASHBOARD_APP: 'DASHBOARD_APP_LOCATOR', + DISCOVER_APP_LOCATOR: 'DISCOVER_APP_LOCATOR', } as const; // Dashboards ids diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx index 7824b8abd2a5c..78e32727212c9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.test.tsx @@ -12,8 +12,6 @@ import { createFleetTestRendererMock } from '../../../../../../../mock'; import { AgentLogsUI } from './agent_logs'; -jest.mock('../../../../../../../hooks/use_authz'); - jest.mock('@kbn/kibana-utils-plugin/public', () => { return { ...jest.requireActual('@kbn/kibana-utils-plugin/public'), @@ -28,6 +26,13 @@ jest.mock('@kbn/logs-shared-plugin/public', () => { LogStream: () =>
, }; }); +jest.mock('@kbn/logs-shared-plugin/common', () => { + return { + getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({ + logsLocator: { getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') }, + }), + }; +}); jest.mock('@kbn/shared-ux-link-redirect-app', () => { return { @@ -52,6 +57,13 @@ jest.mock('../../../../../hooks', () => { ...jest.requireActual('../../../../../hooks'), useLink: jest.fn(), useStartServices: jest.fn(), + useAuthz: jest.fn(), + useDiscoverLocator: jest.fn().mockImplementation(() => { + return { + id: 'DISCOVER_APP_LOCATOR', + getRedirectUrl: jest.fn().mockResolvedValue('app/discover/logs/someview'), + }; + }), }; }); @@ -62,6 +74,7 @@ describe('AgentLogsUI', () => { jest.mocked(useAuthz).mockReturnValue({ fleet: { allAgents: true, + readAgents: true, }, } as any); }); @@ -100,34 +113,36 @@ describe('AgentLogsUI', () => { }, }, }, - http: { - basePath: { - prepend: (url: string) => 'http://localhost:5620' + url, + share: { + url: { + locators: { + get: () => ({ + useUrl: () => 'https://locator.url', + }), + }, }, }, - cloud: { - isServerlessEnabled, - }, }); }; - it('should render Open in Logs UI if capabilities not set', () => { + it('should render Open in Logs button if privileges are set', () => { mockStartServices(); const result = renderComponent(); expect(result.getByTestId('viewInLogsBtn')).toHaveAttribute( 'href', - `http://localhost:5620/app/logs/stream?logPosition=(end%3A'2023-20-04T14%3A20%3A00.340Z'%2Cstart%3A'2023-20-04T14%3A00%3A00.340Z'%2CstreamLive%3A!f)&logFilter=(expression%3A'elastic_agent.id%3Aagent1%20and%20(data_stream.dataset%3Aelastic_agent)%20and%20(log.level%3Ainfo%20or%20log.level%3Aerror)'%2Ckind%3Akuery)` + `https://discover-redirect-url` ); }); - it('should render Open in Discover if serverless enabled', () => { - mockStartServices(true); + it('should not render Open in Logs button if privileges are not set', () => { + jest.mocked(useAuthz).mockReturnValue({ + fleet: { + readAgents: false, + }, + } as any); + mockStartServices(); const result = renderComponent(); - const viewInDiscover = result.getByTestId('viewInDiscoverBtn'); - expect(viewInDiscover).toHaveAttribute( - 'href', - `http://localhost:5620/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:'2023-20-04T14:00:00.340Z',to:'2023-20-04T14:20:00.340Z'))&_a=(columns:!(event.dataset,message),index:'logs-*',query:(language:kuery,query:'elastic_agent.id:agent1 and (data_stream.dataset:elastic_agent) and (log.level:info or log.level:error)'))` - ); + expect(result.queryByTestId('viewInLogsBtn')).not.toBeInTheDocument(); }); it('should show log level dropdown with correct value', () => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx index 34cc206967d62..5a9bfecd22144 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/agent_logs.tsx @@ -35,7 +35,7 @@ import { LogLevelFilter } from './filter_log_level'; import { LogQueryBar } from './query_bar'; import { buildQuery } from './build_query'; import { SelectLogLevel } from './select_log_level'; -import { ViewLogsButton } from './view_logs_button'; +import { ViewLogsButton, getFormattedRange } from './view_logs_button'; const WrapperFlexGroup = styled(EuiFlexGroup)` height: 100%; @@ -112,9 +112,8 @@ const AgentPolicyLogsNotEnabledCallout: React.FunctionComponent<{ agentPolicy: A export const AgentLogsUI: React.FunctionComponent = memo( ({ agent, agentPolicy, state }) => { - const { data, application, cloud } = useStartServices(); + const { data, application } = useStartServices(); const { update: updateState } = AgentLogsUrlStateHelper.useTransitions(); - const isLogsUIAvailable = !cloud?.isServerlessEnabled; // Util to convert date expressions (returned by datepicker) to timestamps (used by LogStream) const getDateRangeTimestamps = useCallback( @@ -321,10 +320,9 @@ export const AgentLogsUI: React.FunctionComponent = memo( }} > diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx index 762c34ad7bc36..7b859596987c0 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_details_page/components/agent_logs/view_logs_button.tsx @@ -5,81 +5,61 @@ * 2.0. */ -import url from 'url'; -import { stringify } from 'querystring'; - import React, { useMemo } from 'react'; -import { encode } from '@kbn/rison'; import { EuiButton } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; -import { useStartServices } from '../../../../../hooks'; +import { getLogsLocatorsFromUrlService } from '@kbn/logs-shared-plugin/common'; + +import moment from 'moment'; + +import { useDiscoverLocator, useStartServices, useAuthz } from '../../../../../hooks'; interface ViewLogsProps { - viewInLogs: boolean; logStreamQuery: string; - startTime: string; - endTime: string; + startTime: number; + endTime: number; } +export const getFormattedRange = (date: string) => new Date(date).getTime(); + /* - Button that takes to the Logs view Ui when that is available, otherwise fallback to the Discover UI - The urls are built using same logStreamQuery (provided by a prop), startTime and endTime, ensuring that they'll both will target same log lines + Button that takes to the Logs view UI or the Discover logs, depending on what's available + If none is available, don't display the button at all */ export const ViewLogsButton: React.FunctionComponent = ({ - viewInLogs, logStreamQuery, startTime, endTime, }) => { - const { http } = useStartServices(); + const discoverLocator = useDiscoverLocator(); - // Generate URL to pass page state to Logs UI - const viewInLogsUrl = useMemo( - () => - http.basePath.prepend( - url.format({ - pathname: '/app/logs/stream', - search: stringify({ - logPosition: encode({ - start: startTime, - end: endTime, - streamLive: false, - }), - logFilter: encode({ - expression: logStreamQuery, - kind: 'kuery', - }), - }), - }) - ), - [http.basePath, startTime, endTime, logStreamQuery] - ); + const { share } = useStartServices(); + const { logsLocator } = getLogsLocatorsFromUrlService(share.url); + const authz = useAuthz(); - const viewInDiscoverUrl = useMemo(() => { - const index = 'logs-*'; - const query = encode({ - query: logStreamQuery, - language: 'kuery', + const logsUrl = useMemo(() => { + const now = moment().toISOString(); + const oneDayAgo = moment().subtract(1, 'day').toISOString(); + const defaultStartTime = getFormattedRange(oneDayAgo); + const defaultEndTime = getFormattedRange(now); + + return logsLocator.getRedirectUrl({ + time: endTime ? endTime : defaultEndTime, + timeRange: { + startTime: startTime ? startTime : defaultStartTime, + endTime: endTime ? endTime : defaultEndTime, + }, + filter: logStreamQuery, }); - return http.basePath.prepend( - `/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:'${startTime}',to:'${endTime}'))&_a=(columns:!(event.dataset,message),index:'${index}',query:${query})` - ); - }, [logStreamQuery, http.basePath, startTime, endTime]); + }, [endTime, logStreamQuery, logsLocator, startTime]); - return viewInLogs ? ( - + return authz.fleet.readAgents && (logsLocator || discoverLocator) ? ( + - ) : ( - - - - ); + ) : null; }; diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/index.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/index.test.tsx index 433cd687208fc..c649b3829a41e 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/index.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/agent_activity_flyout/index.test.tsx @@ -11,7 +11,7 @@ import { act, render, fireEvent } from '@testing-library/react'; import { IntlProvider } from 'react-intl'; import { useActionStatus } from '../../hooks'; -import { useGetAgentPolicies, useStartServices } from '../../../../../hooks'; +import { useGetAgentPolicies, useStartServices, useAuthz } from '../../../../../hooks'; import { AgentActivityFlyout } from '.'; @@ -25,6 +25,15 @@ jest.mock('@kbn/shared-ux-link-redirect-app', () => ({ const mockUseActionStatus = useActionStatus as jest.Mock; const mockUseGetAgentPolicies = useGetAgentPolicies as jest.Mock; const mockUseStartServices = useStartServices as jest.Mock; +const mockedUseAuthz = useAuthz as jest.Mock; + +jest.mock('@kbn/logs-shared-plugin/common', () => { + return { + getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({ + logsLocator: { getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') }, + }), + }; +}); describe('AgentActivityFlyout', () => { const mockOnClose = jest.fn(); @@ -65,7 +74,22 @@ describe('AgentActivityFlyout', () => { docLinks: { links: { fleet: { upgradeElasticAgent: 'https://elastic.co' } } }, application: { navigateToUrl: jest.fn() }, http: { basePath: { prepend: jest.fn() } }, + share: { + url: { + locators: { + get: () => ({ + useUrl: () => 'https://locator.url', + }), + }, + }, + }, }); + mockedUseAuthz.mockReturnValue({ + fleet: { + readAgents: true, + allAgents: true, + }, + } as any); }); beforeEach(() => { diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.test.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.test.tsx index b5018f812da4e..e8f73eae3a2b9 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.test.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.test.tsx @@ -12,7 +12,7 @@ import { I18nProvider } from '@kbn/i18n-react'; import type { ActionStatus } from '../../../../../../../common/types'; -import { useStartServices } from '../../../../hooks'; +import { useStartServices, useAuthz } from '../../../../hooks'; import { ViewErrors } from './view_errors'; @@ -21,6 +21,13 @@ jest.mock('../../../../hooks', () => { ...jest.requireActual('../../../../hooks'), useLink: jest.fn(), useStartServices: jest.fn(), + useAuthz: jest.fn(), + useDiscoverLocator: jest.fn().mockImplementation(() => { + return { + id: 'DISCOVER_APP_LOCATOR', + getRedirectUrl: jest.fn().mockResolvedValue('app/discover/logs/someview'), + }; + }), }; }); @@ -32,6 +39,14 @@ jest.mock('@kbn/shared-ux-link-redirect-app', () => ({ }, })); +jest.mock('@kbn/logs-shared-plugin/common', () => { + return { + getLogsLocatorsFromUrlService: jest.fn().mockReturnValue({ + logsLocator: { getRedirectUrl: jest.fn(() => 'https://discover-redirect-url') }, + }), + }; +}); + const mockStartServices = (isServerlessEnabled?: boolean) => { mockUseStartServices.mockReturnValue({ application: {}, @@ -47,18 +62,27 @@ const mockStartServices = (isServerlessEnabled?: boolean) => { }, }, }, - http: { - basePath: { - prepend: (url: string) => 'http://localhost:5620' + url, + share: { + url: { + locators: { + get: () => ({ + useUrl: () => 'https://locator.url', + }), + }, }, }, - cloud: { - isServerlessEnabled, - }, }); }; describe('ViewErrors', () => { + beforeEach(() => { + jest.mocked(useAuthz).mockReturnValue({ + fleet: { + allAgents: true, + readAgents: true, + }, + } as any); + }); const renderComponent = (action: ActionStatus) => { return render( @@ -67,7 +91,7 @@ describe('ViewErrors', () => { ); }; - it('should render error message with btn to Logs view if serverless not enabled', () => { + it('should render error message with btn to Logs view', () => { mockStartServices(); const result = renderComponent({ actionId: 'action1', @@ -82,15 +106,32 @@ describe('ViewErrors', () => { const errorText = result.getByTestId('errorText'); expect(errorText.textContent).toEqual('Agent agent1 is not upgradeable'); + }); + + it('should render open in Logs button if correct privileges are set', () => { + mockStartServices(); + const result = renderComponent({ + actionId: 'action1', + latestErrors: [ + { + agentId: 'agent1', + error: 'Agent agent1 is not upgradeable', + timestamp: '2023-03-06T14:51:24.709Z', + }, + ], + } as any); const viewErrorBtn = result.getByTestId('viewInLogsBtn'); - expect(viewErrorBtn.getAttribute('href')).toEqual( - `http://localhost:5620/app/logs/stream?logPosition=(end%3A'2023-03-06T14%3A56%3A24.709Z'%2Cstart%3A'2023-03-06T14%3A46%3A24.709Z'%2CstreamLive%3A!f)&logFilter=(expression%3A'elastic_agent.id%3Aagent1%20and%20(data_stream.dataset%3Aelastic_agent)%20and%20(log.level%3Aerror)'%2Ckind%3Akuery)` - ); + expect(viewErrorBtn.getAttribute('href')).toEqual(`https://discover-redirect-url`); }); - it('should render error message with btn to Discover view if serverless enabled', () => { - mockStartServices(true); + it('should not render open in Logs button if privileges are not set', () => { + jest.mocked(useAuthz).mockReturnValue({ + fleet: { + readAgents: false, + }, + } as any); + mockStartServices(); const result = renderComponent({ actionId: 'action1', latestErrors: [ @@ -102,12 +143,6 @@ describe('ViewErrors', () => { ], } as any); - const errorText = result.getByTestId('errorText'); - expect(errorText.textContent).toEqual('Agent agent1 is not upgradeable'); - - const viewErrorBtn = result.getByTestId('viewInDiscoverBtn'); - expect(viewErrorBtn.getAttribute('href')).toEqual( - `http://localhost:5620/app/discover#/?_g=(filters:!(),refreshInterval:(pause:!t,value:60000),time:(from:'2023-03-06T14:46:24.709Z',to:'2023-03-06T14:56:24.709Z'))&_a=(columns:!(event.dataset,message),index:'logs-*',query:(language:kuery,query:'elastic_agent.id:agent1 and (data_stream.dataset:elastic_agent) and (log.level:error)'))` - ); + expect(result.queryByTestId('viewInLogsBtn')).not.toBeInTheDocument(); }); }); diff --git a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx index 4d43c9a60a618..e73d7778d1405 100644 --- a/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx +++ b/x-pack/plugins/fleet/public/applications/fleet/sections/agents/agent_list_page/components/view_errors.tsx @@ -17,7 +17,10 @@ import { i18n } from '@kbn/i18n'; import type { ActionErrorResult } from '../../../../../../../common/types'; import { buildQuery } from '../../agent_details_page/components/agent_logs/build_query'; -import { ViewLogsButton } from '../../agent_details_page/components/agent_logs/view_logs_button'; +import { + ViewLogsButton, + getFormattedRange, +} from '../../agent_details_page/components/agent_logs/view_logs_button'; import type { ActionStatus } from '../../../../types'; import { useStartServices } from '../../../../hooks'; @@ -30,11 +33,12 @@ const TruncatedEuiText = styled(EuiText)` export const ViewErrors: React.FunctionComponent<{ action: ActionStatus }> = ({ action }) => { const coreStart = useStartServices(); - const isLogsUIAvailable = !coreStart.cloud?.isServerlessEnabled; - const getLogsButton = (agentId: string, timestamp: string, viewInLogs: boolean) => { - const startTime = moment(timestamp).subtract(5, 'm').toISOString(); - const endTime = moment(timestamp).add(5, 'm').toISOString(); + const getLogsButton = (agentId: string, timestamp: string) => { + const start = moment(timestamp).subtract(5, 'm').toISOString(); + const end = moment(timestamp).add(5, 'm').toISOString(); + const startTime = getFormattedRange(start); + const endTime = getFormattedRange(end); const logStreamQuery = buildQuery({ agentId, @@ -43,12 +47,7 @@ export const ViewErrors: React.FunctionComponent<{ action: ActionStatus }> = ({ userQuery: '', }); return ( - + ); }; @@ -86,7 +85,7 @@ export const ViewErrors: React.FunctionComponent<{ action: ActionStatus }> = ({ const errorItem = (action.latestErrors ?? []).find((item) => item.agentId === agentId); return ( - {getLogsButton(agentId, errorItem!.timestamp, !!isLogsUIAvailable)} + {getLogsButton(agentId, errorItem!.timestamp)} ); }, diff --git a/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx b/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx index 26668c4062981..09a101ef85b8f 100644 --- a/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx +++ b/x-pack/plugins/fleet/public/custom_logs_assets_extension.tsx @@ -17,6 +17,7 @@ export const CustomLogsAssetsExtension: PackageAssetsComponent = () => { const { http, cloud } = useStartServices(); const isLogsUIAvailable = !cloud?.isServerlessEnabled; // if logs ui is not available, link to discover + // TODO: move away from hardcoded link and use locators instead const logStreamUrl = isLogsUIAvailable ? http.basePath.prepend('/app/logs/stream') : http.basePath.prepend('/app/discover'); diff --git a/x-pack/plugins/fleet/public/hooks/use_locator.ts b/x-pack/plugins/fleet/public/hooks/use_locator.ts index a3fed97679456..25a673b694670 100644 --- a/x-pack/plugins/fleet/public/hooks/use_locator.ts +++ b/x-pack/plugins/fleet/public/hooks/use_locator.ts @@ -21,3 +21,7 @@ export function useLocator( export function useDashboardLocator() { return useLocator(LOCATORS_IDS.DASHBOARD_APP); } + +export function useDiscoverLocator() { + return useLocator(LOCATORS_IDS.DISCOVER_APP_LOCATOR); +} diff --git a/x-pack/plugins/fleet/tsconfig.json b/x-pack/plugins/fleet/tsconfig.json index 8986527bed977..b45bd90010b42 100644 --- a/x-pack/plugins/fleet/tsconfig.json +++ b/x-pack/plugins/fleet/tsconfig.json @@ -64,7 +64,6 @@ "@kbn/utility-types-jest", "@kbn/es-query", "@kbn/ui-theme", - "@kbn/rison", "@kbn/config-schema", "@kbn/telemetry-plugin", "@kbn/task-manager-plugin", diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 00eb8d11923b2..76b86d0e4ebcf 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -17675,7 +17675,6 @@ "xpack.fleet.agentLogs.downloadLink": "télécharger", "xpack.fleet.agentLogs.logDisabledCallOutTitle": "La collecte de logs est désactivée", "xpack.fleet.agentLogs.logLevelSelectText": "Niveau du log", - "xpack.fleet.agentLogs.openInDiscoverUiLinkText": "Ouvrir dans Discover", "xpack.fleet.agentLogs.openInLogsUiLinkText": "Ouvrir dans Logs", "xpack.fleet.agentLogs.searchPlaceholderText": "Rechercher dans les logs…", "xpack.fleet.agentLogs.selectLogLevel.errorTitleText": "Erreur lors de la mise à jour du niveau de logging de l'agent", diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index 7778a86693d86..b804c21299587 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -17653,7 +17653,6 @@ "xpack.fleet.agentLogs.downloadLink": "ダウンロード", "xpack.fleet.agentLogs.logDisabledCallOutTitle": "ログ収集は無効です", "xpack.fleet.agentLogs.logLevelSelectText": "ログレベル", - "xpack.fleet.agentLogs.openInDiscoverUiLinkText": "Discoverで開く", "xpack.fleet.agentLogs.openInLogsUiLinkText": "ログで開く", "xpack.fleet.agentLogs.searchPlaceholderText": "ログを検索…", "xpack.fleet.agentLogs.selectLogLevel.errorTitleText": "エージェントログレベルの更新エラー", diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 0257b4d2830a4..a99b98be1df3e 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -17682,7 +17682,6 @@ "xpack.fleet.agentLogs.downloadLink": "下载", "xpack.fleet.agentLogs.logDisabledCallOutTitle": "日志收集已禁用", "xpack.fleet.agentLogs.logLevelSelectText": "日志级别", - "xpack.fleet.agentLogs.openInDiscoverUiLinkText": "在 Discover 中打开", "xpack.fleet.agentLogs.openInLogsUiLinkText": "在日志中打开", "xpack.fleet.agentLogs.searchPlaceholderText": "搜索日志……", "xpack.fleet.agentLogs.selectLogLevel.errorTitleText": "更新代理日志记录级别时出错",