From e3a22f3d3c75a2a2c49b32395820d0080ece31ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alejandro=20Fern=C3=A1ndez=20G=C3=B3mez?= Date: Tue, 23 Nov 2021 14:46:04 +0100 Subject: [PATCH] [Unified observability] Refine typing for the data checks in the overview page (#117994) Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com> --- .../components/app/empty_sections/index.tsx | 15 +--- .../components/app/section/alerts/index.tsx | 70 ++++++++++++++++--- .../public/context/has_data_context.test.tsx | 23 +++--- .../public/context/has_data_context.tsx | 9 +-- .../public/pages/overview/index.tsx | 7 +- 5 files changed, 77 insertions(+), 47 deletions(-) diff --git a/x-pack/plugins/observability/public/components/app/empty_sections/index.tsx b/x-pack/plugins/observability/public/components/app/empty_sections/index.tsx index 21aaba99ac5dc..fdb6752ad8e7e 100644 --- a/x-pack/plugins/observability/public/components/app/empty_sections/index.tsx +++ b/x-pack/plugins/observability/public/components/app/empty_sections/index.tsx @@ -8,7 +8,6 @@ import { EuiFlexGrid, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import React, { useContext } from 'react'; import { ThemeContext } from 'styled-components'; -import { Alert } from '../../../../../alerting/common'; import { FETCH_STATUS } from '../../../hooks/use_fetcher'; import { useHasData } from '../../../hooks/use_has_data'; import { usePluginContext } from '../../../hooks/use_plugin_context'; @@ -21,17 +20,9 @@ export function EmptySections() { const { hasDataMap } = useHasData(); const appEmptySections = getEmptySections({ core }).filter(({ id }) => { - if (id === 'alert') { - const { status, hasData: alerts } = hasDataMap.alert || {}; - return ( - status === FETCH_STATUS.FAILURE || - (status === FETCH_STATUS.SUCCESS && (alerts as Alert[]).length === 0) - ); - } else { - const app = hasDataMap[id]; - if (app) { - return app.status === FETCH_STATUS.FAILURE || !app.hasData; - } + const app = hasDataMap[id]; + if (app) { + return app.status === FETCH_STATUS.FAILURE || !app.hasData; } return false; }); diff --git a/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx b/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx index cf3ac2b6c7be5..1c5ffb902bfa2 100644 --- a/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx +++ b/x-pack/plugins/observability/public/components/app/section/alerts/index.tsx @@ -16,14 +16,18 @@ import { EuiSpacer, EuiTitle, EuiButton, + EuiLoadingSpinner, + EuiCallOut, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; +import { FormattedMessage } from '@kbn/i18n/react'; import moment from 'moment'; -import React, { useState } from 'react'; +import React, { useState, useMemo } from 'react'; import { EuiSelect } from '@elastic/eui'; import { uniqBy } from 'lodash'; -import { Alert } from '../../../../../../alerting/common'; import { usePluginContext } from '../../../../hooks/use_plugin_context'; +import { FETCH_STATUS, useFetcher } from '../../../../hooks/use_fetcher'; +import { getObservabilityAlerts } from '../../../../services/get_observability_alerts'; import { paths } from '../../../../config'; const ALL_TYPES = 'ALL_TYPES'; @@ -34,20 +38,64 @@ const allTypes = { }), }; -interface Props { - alerts: Alert[]; -} - -export function AlertsSection({ alerts }: Props) { +export function AlertsSection() { const { config, core } = usePluginContext(); const [filter, setFilter] = useState(ALL_TYPES); const manageLink = config.unsafe.alertingExperience.enabled ? core.http.basePath.prepend(paths.observability.alerts) : core.http.basePath.prepend(paths.management.rules); - const filterOptions = uniqBy(alerts, (alert) => alert.consumer).map(({ consumer }) => ({ - value: consumer, - text: consumer, - })); + + const { data, status } = useFetcher(() => { + return getObservabilityAlerts({ core }); + }, [core]); + + const alerts = useMemo(() => data ?? [], [data]); + + const filterOptions = useMemo(() => { + if (!alerts) { + return []; + } + return uniqBy(alerts, (alert) => alert.consumer).map(({ consumer }) => ({ + value: consumer, + text: consumer, + })); + }, [alerts]); + + const isError = status === FETCH_STATUS.FAILURE; + const isLoading = status !== FETCH_STATUS.SUCCESS && !isError; + + if (isLoading) { + return ( + + + + + + ); + } + + if (isError) { + return ( + + + +

+ +

+
+
+
+ ); + } return (
diff --git a/x-pack/plugins/observability/public/context/has_data_context.test.tsx b/x-pack/plugins/observability/public/context/has_data_context.test.tsx index 1eb4108b12181..f5eb80fdf0342 100644 --- a/x-pack/plugins/observability/public/context/has_data_context.test.tsx +++ b/x-pack/plugins/observability/public/context/has_data_context.test.tsx @@ -96,7 +96,7 @@ describe('HasDataContextProvider', () => { infra_logs: { hasData: undefined, status: 'success' }, infra_metrics: { hasData: undefined, status: 'success' }, ux: { hasData: undefined, status: 'success' }, - alert: { hasData: [], status: 'success' }, + alert: { hasData: false, status: 'success' }, }, hasAnyData: false, isAllRequestsComplete: true, @@ -152,7 +152,7 @@ describe('HasDataContextProvider', () => { hasData: false, status: 'success', }, - alert: { hasData: [], status: 'success' }, + alert: { hasData: false, status: 'success' }, }, hasAnyData: false, isAllRequestsComplete: true, @@ -210,7 +210,7 @@ describe('HasDataContextProvider', () => { indices: 'apm-*', status: 'success', }, - alert: { hasData: [], status: 'success' }, + alert: { hasData: false, status: 'success' }, }, hasAnyData: true, isAllRequestsComplete: true, @@ -272,7 +272,7 @@ describe('HasDataContextProvider', () => { indices: 'apm-*', status: 'success', }, - alert: { hasData: [], status: 'success' }, + alert: { hasData: false, status: 'success' }, }, hasAnyData: true, isAllRequestsComplete: true, @@ -315,7 +315,7 @@ describe('HasDataContextProvider', () => { infra_logs: { hasData: undefined, status: 'success' }, infra_metrics: { hasData: undefined, status: 'success' }, ux: { hasData: undefined, status: 'success' }, - alert: { hasData: [], status: 'success' }, + alert: { hasData: false, status: 'success' }, }, hasAnyData: true, isAllRequestsComplete: true, @@ -364,7 +364,7 @@ describe('HasDataContextProvider', () => { infra_logs: { hasData: undefined, status: 'success' }, infra_metrics: { hasData: undefined, status: 'success' }, ux: { hasData: undefined, status: 'success' }, - alert: { hasData: [], status: 'success' }, + alert: { hasData: false, status: 'success' }, }, hasAnyData: false, isAllRequestsComplete: true, @@ -429,7 +429,7 @@ describe('HasDataContextProvider', () => { indices: 'apm-*', status: 'success', }, - alert: { hasData: [], status: 'success' }, + alert: { hasData: false, status: 'success' }, }, hasAnyData: true, isAllRequestsComplete: true, @@ -498,7 +498,7 @@ describe('HasDataContextProvider', () => { infra_logs: { hasData: undefined, status: 'failure' }, infra_metrics: { hasData: undefined, status: 'failure' }, ux: { hasData: undefined, status: 'failure' }, - alert: { hasData: [], status: 'success' }, + alert: { hasData: false, status: 'success' }, }, hasAnyData: false, isAllRequestsComplete: true, @@ -527,7 +527,7 @@ describe('HasDataContextProvider', () => { } as PluginContextValue); }); - it('returns all alerts available', async () => { + it('returns if alerts are available', async () => { const { result, waitForNextUpdate } = renderHook(() => useHasData(), { wrapper }); expect(result.current).toEqual({ hasDataMap: {}, @@ -549,10 +549,7 @@ describe('HasDataContextProvider', () => { infra_metrics: { hasData: undefined, status: 'success' }, ux: { hasData: undefined, status: 'success' }, alert: { - hasData: [ - { id: 2, consumer: 'apm' }, - { id: 3, consumer: 'uptime' }, - ], + hasData: true, status: 'success', }, }, diff --git a/x-pack/plugins/observability/public/context/has_data_context.tsx b/x-pack/plugins/observability/public/context/has_data_context.tsx index b6a45784a53b4..891c21a5b1eca 100644 --- a/x-pack/plugins/observability/public/context/has_data_context.tsx +++ b/x-pack/plugins/observability/public/context/has_data_context.tsx @@ -9,7 +9,6 @@ import { isEmpty, uniqueId } from 'lodash'; import React, { createContext, useEffect, useState } from 'react'; import { useRouteMatch } from 'react-router-dom'; import { asyncForEach } from '@kbn/std'; -import { Alert } from '../../../alerting/common'; import { getDataHandler } from '../data_handler'; import { FETCH_STATUS } from '../hooks/use_fetcher'; import { usePluginContext } from '../hooks/use_plugin_context'; @@ -24,7 +23,7 @@ export type HasDataMap = Record< DataContextApps, { status: FETCH_STATUS; - hasData?: boolean | Alert[]; + hasData?: boolean; indices?: string | ApmIndicesConfig; serviceName?: string; } @@ -123,7 +122,7 @@ export function HasDataContextProvider({ children }: { children: React.ReactNode setHasDataMap((prevState) => ({ ...prevState, alert: { - hasData: alerts, + hasData: alerts.length > 0, status: FETCH_STATUS.SUCCESS, }, })); @@ -148,9 +147,7 @@ export function HasDataContextProvider({ children }: { children: React.ReactNode const hasAnyData = (Object.keys(hasDataMap) as ObservabilityFetchDataPlugins[]).some((app) => { const appHasData = hasDataMap[app]?.hasData; - return ( - appHasData === true || (Array.isArray(appHasData) && (appHasData as Alert[])?.length > 0) - ); + return appHasData === true; }); return ( diff --git a/x-pack/plugins/observability/public/pages/overview/index.tsx b/x-pack/plugins/observability/public/pages/overview/index.tsx index b817a83d59e0d..7100a0552876d 100644 --- a/x-pack/plugins/observability/public/pages/overview/index.tsx +++ b/x-pack/plugins/observability/public/pages/overview/index.tsx @@ -9,7 +9,6 @@ import { EuiFlexGroup, EuiFlexItem, EuiSpacer, EuiPanel } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { useTrackPageview } from '../..'; -import { Alert } from '../../../../alerting/common'; import { EmptySections } from '../../components/app/empty_sections'; import { ObservabilityHeaderMenu } from '../../components/app/header'; import { NewsFeed } from '../../components/app/news_feed'; @@ -72,8 +71,6 @@ export function OverviewPage({ routeParams }: Props) { docsLink: core.docLinks.links.observability.guide, }); - const alerts = (hasDataMap.alert?.hasData as Alert[]) || []; - const { refreshInterval = 10000, refreshPaused = true } = routeParams.query; const bucketSize = calculateBucketSize({ @@ -118,10 +115,10 @@ export function OverviewPage({ routeParams }: Props) { {!!newsFeed?.items?.length && } - {!!alerts.length && ( + {hasDataMap?.alert?.hasData && ( - + )}