From 46a1535f03b643024d2ad82d43894a4f027fe2d9 Mon Sep 17 00:00:00 2001 From: Giorgos Bamparopoulos Date: Fri, 13 Dec 2024 08:53:25 +0000 Subject: [PATCH] [Stack Monitoring] Migrate logs-related components to TypeScript (#203536) ## Summary A recent [bug](https://github.com/elastic/kibana/issues/199902) that affected some of the pages in Stack Monitoring was caused by changes related to the locators of the logs-related apps. The issue wasn't caught by type checks as the affected area in the monitoring plugin was written in JavaScript. The goal of this PR is to migrate the logs-related components to TypeScript. ### Testing The stateful environment deployed by this PR includes logs and metrics for stack monitoring. Please make sure to select a larger time range (e.g. last 14 days). --- .../contexts/external_config_context.tsx | 1 + .../{logs.test.js.snap => logs.test.tsx.snap} | 0 ...ason.test.js.snap => reason.test.tsx.snap} | 0 .../components/logs/{index.js => index.tsx} | 0 .../logs/{logs.test.js => logs.test.tsx} | 2 +- .../components/logs/{logs.js => logs.tsx} | 65 ++++++++++++++----- .../logs/{reason.test.js => reason.test.tsx} | 0 .../components/logs/{reason.js => reason.tsx} | 32 ++++++--- 8 files changed, 71 insertions(+), 29 deletions(-) rename x-pack/plugins/monitoring/public/components/logs/__snapshots__/{logs.test.js.snap => logs.test.tsx.snap} (100%) rename x-pack/plugins/monitoring/public/components/logs/__snapshots__/{reason.test.js.snap => reason.test.tsx.snap} (100%) rename x-pack/plugins/monitoring/public/components/logs/{index.js => index.tsx} (100%) rename x-pack/plugins/monitoring/public/components/logs/{logs.test.js => logs.test.tsx} (98%) rename x-pack/plugins/monitoring/public/components/logs/{logs.js => logs.tsx} (82%) rename x-pack/plugins/monitoring/public/components/logs/{reason.test.js => reason.test.tsx} (100%) rename x-pack/plugins/monitoring/public/components/logs/{reason.js => reason.tsx} (88%) diff --git a/x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx b/x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx index e86262defb65e..45791507fa726 100644 --- a/x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx +++ b/x-pack/plugins/monitoring/public/application/contexts/external_config_context.tsx @@ -14,6 +14,7 @@ export interface ExternalConfig { renderReactApp: boolean; staleStatusThresholdSeconds: number; isCcsEnabled: boolean; + logsIndices: string; } export const ExternalConfigContext = createContext({} as ExternalConfig); diff --git a/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.tsx.snap similarity index 100% rename from x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.js.snap rename to x-pack/plugins/monitoring/public/components/logs/__snapshots__/logs.test.tsx.snap diff --git a/x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap b/x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.tsx.snap similarity index 100% rename from x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.js.snap rename to x-pack/plugins/monitoring/public/components/logs/__snapshots__/reason.test.tsx.snap diff --git a/x-pack/plugins/monitoring/public/components/logs/index.js b/x-pack/plugins/monitoring/public/components/logs/index.tsx similarity index 100% rename from x-pack/plugins/monitoring/public/components/logs/index.js rename to x-pack/plugins/monitoring/public/components/logs/index.tsx diff --git a/x-pack/plugins/monitoring/public/components/logs/logs.test.js b/x-pack/plugins/monitoring/public/components/logs/logs.test.tsx similarity index 98% rename from x-pack/plugins/monitoring/public/components/logs/logs.test.js rename to x-pack/plugins/monitoring/public/components/logs/logs.test.tsx index 50e850400cc06..f103288a24980 100644 --- a/x-pack/plugins/monitoring/public/components/logs/logs.test.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.test.tsx @@ -29,7 +29,7 @@ const sharePlugin = { }, }, }, -}; +} as unknown as ReturnType; const logs = { enabled: true, diff --git a/x-pack/plugins/monitoring/public/components/logs/logs.js b/x-pack/plugins/monitoring/public/components/logs/logs.tsx similarity index 82% rename from x-pack/plugins/monitoring/public/components/logs/logs.js rename to x-pack/plugins/monitoring/public/components/logs/logs.tsx index ab897423ff056..b17129d90eac0 100644 --- a/x-pack/plugins/monitoring/public/components/logs/logs.js +++ b/x-pack/plugins/monitoring/public/components/logs/logs.tsx @@ -8,16 +8,42 @@ import React, { PureComponent, useContext } from 'react'; import { RedirectAppLinks } from '@kbn/shared-ux-link-redirect-app'; import { upperFirst } from 'lodash'; -import { Legacy } from '../../legacy_shims'; import { EuiBasicTable, EuiTitle, EuiSpacer, EuiText, EuiCallOut, EuiLink } from '@elastic/eui'; -import { formatDateTimeLocal } from '../../../common/formatting'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; -import { Reason } from './reason'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { SharePluginStart } from '@kbn/share-plugin/public'; +import { Reason, type IReason } from './reason'; +import { formatDateTimeLocal } from '../../../common/formatting'; +import { Legacy } from '../../legacy_shims'; import { ExternalConfigContext } from '../../application/contexts/external_config_context'; +import { MonitoringStartServices } from '../../types'; + +interface LogsProps { + logs: { + logs?: Array<{ + timestamp: string; + component: string; + level: string; + type: string; + node: string; + message: string; + }>; + enabled: boolean; + limit: number; + reason?: IReason; + }; + nodeId?: string; + indexUuid?: string; + clusterUuid?: string; +} -const getFormattedDateTimeLocal = (timestamp) => { +interface LogsContentProps extends LogsProps { + sharePlugin: SharePluginStart; + logsIndices: string; +} + +const getFormattedDateTimeLocal = (timestamp: number | Date) => { const timezone = Legacy.shims.uiSettings?.get('dateFormat:tz'); return formatDateTimeLocal(timestamp, timezone); }; @@ -51,7 +77,7 @@ const columns = [ field: 'timestamp', name: columnTimestampTitle, width: '12%', - render: (timestamp) => getFormattedDateTimeLocal(timestamp), + render: (timestamp: number | Date) => getFormattedDateTimeLocal(timestamp), }, { field: 'level', @@ -62,7 +88,7 @@ const columns = [ field: 'type', name: columnTypeTitle, width: '10%', - render: (type) => upperFirst(type), + render: (type: string) => upperFirst(type), }, { field: 'message', @@ -81,7 +107,7 @@ const clusterColumns = [ field: 'timestamp', name: columnTimestampTitle, width: '12%', - render: (timestamp) => getFormattedDateTimeLocal(timestamp), + render: (timestamp: number | Date) => getFormattedDateTimeLocal(timestamp), }, { field: 'level', @@ -92,7 +118,7 @@ const clusterColumns = [ field: 'type', name: columnTypeTitle, width: '10%', - render: (type) => upperFirst(type), + render: (type: string) => upperFirst(type), }, { field: 'message', @@ -111,7 +137,13 @@ const clusterColumns = [ }, ]; -function getDiscoverLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndices) { +function getDiscoverLink( + clusterUuid?: string, + nodeId?: string, + indexUuid?: string, + sharePlugin?: SharePluginStart, + logsIndices?: string +) { const params = []; if (clusterUuid) { params.push(`elasticsearch.cluster.uuid:${clusterUuid}`); @@ -124,13 +156,9 @@ function getDiscoverLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndice } const filter = params.join(' and '); - const discoverLocator = sharePlugin.url.locators.get('DISCOVER_APP_LOCATOR'); + const discoverLocator = sharePlugin?.url.locators.get('DISCOVER_APP_LOCATOR'); - if (!discoverLocator) { - return; - } - - const base = discoverLocator.getRedirectUrl({ + const base = discoverLocator?.getRedirectUrl({ dataViewSpec: { id: logsIndices, title: logsIndices, @@ -144,14 +172,15 @@ function getDiscoverLink(clusterUuid, nodeId, indexUuid, sharePlugin, logsIndice return base; } -export const Logs = (props) => { +export const Logs = (props: LogsProps) => { const { services: { share }, - } = useKibana(); + } = useKibana(); const externalConfig = useContext(ExternalConfigContext); return ; }; -export class LogsContent extends PureComponent { + +export class LogsContent extends PureComponent { renderLogs() { const { logs: { enabled, logs }, diff --git a/x-pack/plugins/monitoring/public/components/logs/reason.test.js b/x-pack/plugins/monitoring/public/components/logs/reason.test.tsx similarity index 100% rename from x-pack/plugins/monitoring/public/components/logs/reason.test.js rename to x-pack/plugins/monitoring/public/components/logs/reason.test.tsx diff --git a/x-pack/plugins/monitoring/public/components/logs/reason.js b/x-pack/plugins/monitoring/public/components/logs/reason.tsx similarity index 88% rename from x-pack/plugins/monitoring/public/components/logs/reason.js rename to x-pack/plugins/monitoring/public/components/logs/reason.tsx index 4444c818d5cce..82a4f788df98b 100644 --- a/x-pack/plugins/monitoring/public/components/logs/reason.js +++ b/x-pack/plugins/monitoring/public/components/logs/reason.tsx @@ -12,7 +12,19 @@ import { FormattedMessage } from '@kbn/i18n-react'; import { Legacy } from '../../legacy_shims'; import { Monospace } from '../metricbeat_migration/instruction_steps/components/monospace/monospace'; -export const Reason = ({ reason }) => { +export interface IReason { + indexPatternExists?: boolean; + indexPatternInTimeRangeExists?: boolean; + typeExists?: boolean; + typeExistsAtAnyTime?: boolean; + usingStructuredLogs?: boolean; + clusterExists?: boolean; + nodeExists?: boolean | null; + indexExists?: boolean; + correctIndexName?: boolean; +} + +export const Reason = ({ reason }: { reason?: IReason }) => { const filebeatUrl = Legacy.shims.docLinks.links.filebeat.installation; const elasticsearchUrl = Legacy.shims.docLinks.links.filebeat.elasticsearchModule; const troubleshootUrl = Legacy.shims.docLinks.links.monitoring.troubleshootKibana; @@ -36,7 +48,7 @@ export const Reason = ({ reason }) => { /> ); - if (false === reason.indexPatternExists) { + if (false === reason?.indexPatternExists) { title = i18n.translate('xpack.monitoring.logs.reason.noIndexPatternTitle', { defaultMessage: 'No log data found', }); @@ -56,8 +68,8 @@ export const Reason = ({ reason }) => { /> ); } else if ( - false === reason.indexPatternInTimeRangeExists || - (false === reason.typeExists && reason.typeExistsAtAnyTime) + false === reason?.indexPatternInTimeRangeExists || + (false === reason?.typeExists && reason.typeExistsAtAnyTime) ) { title = i18n.translate('xpack.monitoring.logs.reason.noIndexPatternInTimePeriodTitle', { defaultMessage: 'No logs for the selected time', @@ -68,7 +80,7 @@ export const Reason = ({ reason }) => { defaultMessage="Use the time filter to adjust your timeframe." /> ); - } else if (false === reason.typeExists) { + } else if (false === reason?.typeExists) { title = i18n.translate('xpack.monitoring.logs.reason.noTypeTitle', { defaultMessage: 'No logs for Elasticsearch', }); @@ -87,7 +99,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.usingStructuredLogs) { + } else if (false === reason?.usingStructuredLogs) { title = i18n.translate('xpack.monitoring.logs.reason.notUsingStructuredLogsTitle', { defaultMessage: 'No structured logs found', }); @@ -107,7 +119,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.clusterExists) { + } else if (false === reason?.clusterExists) { title = i18n.translate('xpack.monitoring.logs.reason.noClusterTitle', { defaultMessage: 'No logs for this cluster', }); @@ -126,7 +138,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.nodeExists) { + } else if (false === reason?.nodeExists) { title = i18n.translate('xpack.monitoring.logs.reason.noNodeTitle', { defaultMessage: 'No logs for this Elasticsearch node', }); @@ -145,7 +157,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.indexExists) { + } else if (false === reason?.indexExists) { title = i18n.translate('xpack.monitoring.logs.reason.noIndexTitle', { defaultMessage: 'No logs for this index', }); @@ -164,7 +176,7 @@ export const Reason = ({ reason }) => { }} /> ); - } else if (false === reason.correctIndexName) { + } else if (false === reason?.correctIndexName) { title = i18n.translate('xpack.monitoring.logs.reason.correctIndexNameTitle', { defaultMessage: 'Corrupted filebeat index', });