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 && (
-
+
)}