From 5fcc495ae9875b94d0d7748bf0c078445c74e1ca Mon Sep 17 00:00:00 2001 From: Shahzad Date: Mon, 23 Sep 2024 15:09:13 +0200 Subject: [PATCH] [Synthetics] Remove extra overview route (#192449) ## Summary Remove extra overview route !! ### Testing Test overview page with filters and paging etc image --------- Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com> --- .../common/constants/synthetics/rest_api.ts | 1 - .../runtime_types/alert_rules/common.ts | 47 ++ .../monitor_management/monitor_types.ts | 26 - .../synthetics_overview_status.ts | 34 +- .../e2e/synthetics/journeys/detail_flyout.ts | 7 +- .../journeys/overview_sorting.journey.ts | 1 - .../common/components/add_to_dashboard.tsx | 6 + .../hooks/use_can_use_public_loc_id.ts | 15 +- .../hooks/use_overview_status.ts | 4 +- .../overview/actions_popover.test.tsx | 30 +- .../overview/overview/actions_popover.tsx | 10 +- .../grid_by_group/grid_group_item.tsx | 10 +- .../grid_by_group/grid_items_by_group.tsx | 44 +- .../use_filtered_group_monitors.ts | 9 +- .../overview/overview/metric_item.tsx | 18 +- .../overview/metric_item/metric_item_body.tsx | 12 +- .../overview/overview/metric_item_icon.tsx | 6 +- .../overview/monitor_detail_flyout.tsx | 19 +- .../overview/overview/overview_grid.tsx | 57 +- .../overview/overview_pagination_info.tsx | 8 +- .../overview/overview/sort_fields.tsx | 5 +- .../monitors_page/overview/overview_page.tsx | 37 +- .../hooks/use_location_name.test.tsx | 12 +- .../synthetics/hooks/use_location_name.tsx | 12 +- .../hooks/use_monitor_enable_handler.tsx | 3 +- .../use_monitors_sorted_by_status.test.tsx | 375 ++++------ .../hooks/use_monitors_sorted_by_status.tsx | 141 ++-- .../hooks/use_status_by_location_overview.ts | 3 +- .../synthetics/state/monitor_list/effects.ts | 2 - .../apps/synthetics/state/overview/actions.ts | 11 - .../apps/synthetics/state/overview/api.ts | 53 +- .../synthetics/state/overview/effects.test.ts | 17 +- .../apps/synthetics/state/overview/effects.ts | 37 +- .../apps/synthetics/state/overview/index.ts | 51 +- .../apps/synthetics/state/overview/models.ts | 7 +- .../synthetics/state/overview/selectors.ts | 1 - .../synthetics/state/overview_status/api.ts | 22 +- .../synthetics/state/overview_status/index.ts | 40 +- .../state/overview_status/selectors.ts | 4 +- .../apps/synthetics/state/root_effect.ts | 8 +- .../__mocks__/synthetics_store.mock.ts | 8 - .../server/alert_rules/common.test.ts | 15 +- .../synthetics/server/alert_rules/common.ts | 2 +- .../status_rule/monitor_status_rule.ts | 4 +- .../status_rule/query_monitor_status_alert.ts | 31 +- .../status_rule/status_rule_executor.ts | 40 +- .../alert_rules/tls_rule/tls_rule_executor.ts | 4 +- .../synthetics/server/lib.ts | 2 +- .../server/queries/query_monitor_status.ts | 62 +- .../synthetics/server/routes/index.ts | 6 +- .../routes/monitor_cruds/get_monitor.ts | 59 +- .../overview_status/overview_status.test.ts | 685 ++++++++++++++---- .../routes/overview_status/overview_status.ts | 25 +- .../get_all_monitors.test.ts | 6 +- .../synthetics_monitor/get_all_monitors.ts | 6 +- .../apis/synthetics/get_monitor_overview.ts | 211 ------ .../api_integration/apis/synthetics/index.ts | 1 - 57 files changed, 1111 insertions(+), 1261 deletions(-) delete mode 100644 x-pack/test/api_integration/apis/synthetics/get_monitor_overview.ts diff --git a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts index ac3e4154b6683..5608e2fe7f5e2 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/constants/synthetics/rest_api.ts @@ -23,7 +23,6 @@ export enum SYNTHETICS_API_URLS { SYNTHETICS_PROJECT_APIKEY = '/internal/synthetics/service/api_key', SYNTHETICS_HAS_INTEGRATION_MONITORS = '/internal/synthetics/fleet/has_integration_monitors', - SYNTHETICS_OVERVIEW = '/internal/synthetics/overview', PINGS = '/internal/synthetics/pings', MONITOR_STATUS_HEATMAP = '/internal/synthetics/ping_heatmap', OVERVIEW_TRENDS = '/internal/synthetics/overview_trends', diff --git a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/alert_rules/common.ts b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/alert_rules/common.ts index 6f7009f89aa8b..790ce35264752 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/alert_rules/common.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/alert_rules/common.ts @@ -6,6 +6,7 @@ */ import * as t from 'io-ts'; +import { OverviewPingCodec } from '../monitor_management/synthetics_overview_status'; export const SyntheticsCommonStateCodec = t.intersection([ t.partial({ @@ -36,3 +37,49 @@ export const SyntheticsMonitorStatusAlertStateCodec = t.type({ export type SyntheticsMonitorStatusAlertState = t.TypeOf< typeof SyntheticsMonitorStatusAlertStateCodec >; + +export const AlertStatusMetaDataCodec = t.interface({ + monitorQueryId: t.string, + configId: t.string, + status: t.string, + locationId: t.string, + timestamp: t.string, + ping: OverviewPingCodec, +}); + +export const StaleAlertStatusMetaDataCodec = t.intersection([ + AlertStatusMetaDataCodec, + t.partial({ + isDeleted: t.boolean, + isLocationRemoved: t.boolean, + }), +]); + +export const AlertPendingStatusMetaDataCodec = t.intersection([ + t.interface({ + monitorQueryId: t.string, + configId: t.string, + status: t.string, + locationId: t.string, + }), + t.partial({ + timestamp: t.string, + ping: OverviewPingCodec, + }), +]); + +export const AlertStatusCodec = t.interface({ + up: t.number, + down: t.number, + pending: t.number, + upConfigs: t.record(t.string, AlertStatusMetaDataCodec), + downConfigs: t.record(t.string, AlertStatusMetaDataCodec), + pendingConfigs: t.record(t.string, AlertPendingStatusMetaDataCodec), + enabledMonitorQueryIds: t.array(t.string), + staleDownConfigs: t.record(t.string, StaleAlertStatusMetaDataCodec), +}); + +export type AlertPendingStatusMetaData = t.TypeOf; +export type StaleDownConfig = t.TypeOf; +export type AlertStatusMetaData = t.TypeOf; +export type AlertOverviewStatus = t.TypeOf; diff --git a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/monitor_types.ts b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/monitor_types.ts index 426b66597c7d8..7246ba2d9bac6 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/monitor_types.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/monitor_types.ts @@ -383,30 +383,6 @@ export const MonitorManagementListResultCodec = t.type({ syncErrors: t.union([ServiceLocationErrors, t.null]), }); -export const MonitorOverviewItemCodec = t.intersection([ - t.interface({ - name: t.string, - id: t.string, - configId: t.string, - location: MonitorServiceLocationCodec, - isEnabled: t.boolean, - isStatusAlertEnabled: t.boolean, - type: t.string, - tags: t.array(t.string), - schedule: t.string, - }), - t.partial({ - status: t.string, - projectId: t.string, - }), -]); - -export const MonitorOverviewResultCodec = t.type({ - total: t.number, - allMonitorIds: t.array(t.string), - monitors: t.array(MonitorOverviewItemCodec), -}); - export const SyntheticsMonitorWithSecretsCodec = t.intersection([ EncryptedSyntheticsMonitorCodec, t.interface({ @@ -431,8 +407,6 @@ export type EncryptedSyntheticsSavedMonitor = t.TypeOf; export type MonitorDefaults = t.TypeOf; export type MonitorManagementListResult = t.TypeOf; -export type MonitorOverviewItem = t.TypeOf; -export type MonitorOverviewResult = t.TypeOf; export type Secret = (typeof secretKeys)[number]; export type SyntheticsMonitorWithSecrets = Omit< t.TypeOf, diff --git a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts index 7e8a1257e6428..46a421ea98270 100644 --- a/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts +++ b/x-pack/plugins/observability_solution/synthetics/common/runtime_types/monitor_management/synthetics_overview_status.ts @@ -30,25 +30,25 @@ export const OverviewPingCodec = t.intersection([ }), ]); -export const OverviewStatusMetaDataCodec = t.interface({ - monitorQueryId: t.string, - configId: t.string, - status: t.string, - locationId: t.string, - timestamp: t.string, - ping: OverviewPingCodec, -}); - -export const OverviewPendingStatusMetaDataCodec = t.intersection([ +export const OverviewStatusMetaDataCodec = t.intersection([ t.interface({ monitorQueryId: t.string, configId: t.string, status: t.string, locationId: t.string, + locationLabel: t.string, + name: t.string, + schedule: t.string, + isEnabled: t.boolean, + tags: t.array(t.string), + isStatusAlertEnabled: t.boolean, + type: t.string, }), t.partial({ - timestamp: t.string, + projectId: t.string, + updated_at: t.string, ping: OverviewPingCodec, + timestamp: t.string, }), ]); @@ -62,21 +62,13 @@ export const OverviewStatusCodec = t.interface({ disabledCount: t.number, upConfigs: t.record(t.string, OverviewStatusMetaDataCodec), downConfigs: t.record(t.string, OverviewStatusMetaDataCodec), - pendingConfigs: t.record(t.string, OverviewPendingStatusMetaDataCodec), + pendingConfigs: t.record(t.string, OverviewStatusMetaDataCodec), enabledMonitorQueryIds: t.array(t.string), disabledMonitorQueryIds: t.array(t.string), allIds: t.array(t.string), }); -export const OverviewStatusStateCodec = t.intersection([ - OverviewStatusCodec, - t.interface({ - allConfigs: t.record(t.string, OverviewStatusMetaDataCodec), - }), -]); - export type OverviewPing = t.TypeOf; export type OverviewStatus = t.TypeOf; -export type OverviewStatusState = t.TypeOf; +export type OverviewStatusState = t.TypeOf; export type OverviewStatusMetaData = t.TypeOf; -export type OverviewPendingStatusMetaData = t.TypeOf; diff --git a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/detail_flyout.ts b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/detail_flyout.ts index 5159792f9217a..830d5d859bbc7 100644 --- a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/detail_flyout.ts +++ b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/detail_flyout.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { expect, journey, step } from '@elastic/synthetics'; +import { before, expect, journey, step } from '@elastic/synthetics'; +import { cleanTestMonitors } from './services/add_monitor'; import { syntheticsAppPageProvider } from '../page_objects/synthetics_app'; journey('TestMonitorDetailFlyout', async ({ page, params }) => { @@ -13,6 +14,10 @@ journey('TestMonitorDetailFlyout', async ({ page, params }) => { const monitorName = 'test-flyout-http-monitor'; const locationId = 'us_central'; + before(async () => { + await cleanTestMonitors(params); + }); + step('Go to monitor-management', async () => { await syntheticsApp.navigateToAddMonitor(); }); diff --git a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/overview_sorting.journey.ts b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/overview_sorting.journey.ts index 66515cbe910bc..67ce82624f518 100644 --- a/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/overview_sorting.journey.ts +++ b/x-pack/plugins/observability_solution/synthetics/e2e/synthetics/journeys/overview_sorting.journey.ts @@ -36,7 +36,6 @@ journey('OverviewSorting', async ({ page, params }) => { await page.waitForSelector(`[data-test-subj="syntheticsOverviewGridItem"]`); await page.click('[data-test-subj="syntheticsOverviewSortButton"]'); await page.click('button:has-text("Alphabetical")'); - await page.waitForSelector(`[data-test-subj="syntheticsOverviewMonitorsLoading"]`); await page.waitForSelector(`text=${testMonitor1}`); await page.waitForSelector(`text=${testMonitor2}`); await page.waitForSelector(`text=${testMonitor3}`); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/add_to_dashboard.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/add_to_dashboard.tsx index 2a910855aa245..d8b2d624c51ba 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/add_to_dashboard.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/common/components/add_to_dashboard.tsx @@ -90,6 +90,12 @@ export const AddToDashboard = ({ data-test-subj="syntheticsEmbeddablePanelWrapperButton" iconType="boxesHorizontal" onClick={() => setIsPopoverOpen(!isPopoverOpen)} + aria-label={i18n.translate( + 'xpack.synthetics.embeddablePanelWrapper.shareButtonAriaLabel', + { + defaultMessage: 'Add to dashboard', + } + )} /> } isOpen={isPopoverOpen} diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_can_use_public_loc_id.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_can_use_public_loc_id.ts index d51ae7d42da34..8aa1cd4416f1f 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_can_use_public_loc_id.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_can_use_public_loc_id.ts @@ -7,18 +7,21 @@ import { useSelector } from 'react-redux'; import { useKibana } from '@kbn/kibana-react-plugin/public'; +import { selectServiceLocationsState } from '../../../state'; +import { selectOverviewStatus } from '../../../state/overview_status'; import { useEnablement } from '../../../hooks'; -import { selectOverviewState } from '../../../state'; export const useCanUsePublicLocById = (configId: string) => { - const { - data: { monitors }, - } = useSelector(selectOverviewState); + const { allConfigs } = useSelector(selectOverviewStatus); const { isServiceAllowed } = useEnablement(); - const hasManagedLocation = monitors?.filter( - (mon) => mon.configId === configId && mon.location.isServiceManaged + const { locations: allLocations } = useSelector(selectServiceLocationsState); + + const listIds = allLocations?.filter((loc) => loc.isServiceManaged).map((loc) => loc.id) ?? []; + + const hasManagedLocation = allConfigs?.filter( + (mon) => mon.configId === configId && listIds.includes(mon.locationId) ); const canUsePublicLocations = diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_overview_status.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_overview_status.ts index 562d651cf819b..da86b130af692 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_overview_status.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/hooks/use_overview_status.ts @@ -18,7 +18,7 @@ import { export function useOverviewStatus({ scopeStatusByLocation }: { scopeStatusByLocation: boolean }) { const pageState = useSelector(selectOverviewPageState); - const { status, error, loaded, loading } = useSelector(selectOverviewStatus); + const { status, error, loaded, loading, allConfigs } = useSelector(selectOverviewStatus); const { lastRefresh } = useSyntheticsRefreshContext(); @@ -38,5 +38,7 @@ export function useOverviewStatus({ scopeStatusByLocation }: { scopeStatusByLoca status, error, loading, + loaded, + allConfigs: allConfigs ?? [], }; } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.test.tsx index f3c4571db100f..2f3936360402e 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.test.tsx @@ -14,10 +14,10 @@ import * as monitorDetailLocatorModule from '../../../../hooks/use_monitor_detai import * as monitorEnableHandlerModule from '../../../../hooks/use_monitor_enable_handler'; import * as enablementHook from '../../../../hooks/use_enablement'; import { FETCH_STATUS } from '@kbn/observability-shared-plugin/public'; -import { MonitorOverviewItem } from '../types'; +import { OverviewStatusMetaData } from '../types'; describe('ActionsPopover', () => { - let testMonitor: MonitorOverviewItem; + let testMonitor: OverviewStatusMetaData; beforeEach(() => { jest.spyOn(enablementHook, 'useEnablement').mockReturnValue({ @@ -32,19 +32,17 @@ describe('ActionsPopover', () => { }); testMonitor = { - location: { - id: 'us_central', - isServiceManaged: true, - }, + locationId: 'us_central', isEnabled: true, isStatusAlertEnabled: true, name: 'Monitor 1', - id: 'somelongstring', configId: '1lkjelre', type: 'browser', tags: [], schedule: '120', - }; + monitorQueryId: '123', + status: 'up', + } as any; }); afterEach(() => { @@ -58,7 +56,7 @@ describe('ActionsPopover', () => { isPopoverOpen={false} setIsPopoverOpen={jest.fn()} monitor={testMonitor} - locationId={testMonitor.location.id} + locationId={testMonitor.locationId} /> ); expect(getByLabelText('Open actions menu')); @@ -74,7 +72,7 @@ describe('ActionsPopover', () => { isPopoverOpen={isPopoverOpen} setIsPopoverOpen={setIsPopoverOpen} monitor={testMonitor} - locationId={testMonitor.location.id} + locationId={testMonitor.locationId} /> ); const popoverButton = getByLabelText('Open actions menu'); @@ -94,7 +92,7 @@ describe('ActionsPopover', () => { isPopoverOpen={isPopoverOpen} setIsPopoverOpen={setIsPopoverOpen} monitor={testMonitor} - locationId={testMonitor.location.id} + locationId={testMonitor.locationId} /> ); const popoverButton = getByLabelText('Open actions menu'); @@ -115,7 +113,7 @@ describe('ActionsPopover', () => { isPopoverOpen={true} setIsPopoverOpen={jest.fn()} monitor={testMonitor} - locationId={testMonitor.location.id} + locationId={testMonitor.locationId} /> ); @@ -132,7 +130,7 @@ describe('ActionsPopover', () => { isPopoverOpen={true} setIsPopoverOpen={jest.fn()} monitor={testMonitor} - locationId={testMonitor.location.id} + locationId={testMonitor.locationId} /> ); @@ -151,7 +149,7 @@ describe('ActionsPopover', () => { isPopoverOpen={true} setIsPopoverOpen={jest.fn()} monitor={testMonitor} - locationId={testMonitor.location.id} + locationId={testMonitor.locationId} /> ); expect(getByTestId('actionsPopoverGoToMonitor')?.getAttribute('href')).toBe( @@ -172,7 +170,7 @@ describe('ActionsPopover', () => { position="relative" setIsPopoverOpen={jest.fn()} monitor={testMonitor} - locationId={testMonitor.location.id} + locationId={testMonitor.locationId} /> ); const enableButton = getByText('Disable monitor (all locations)'); @@ -194,7 +192,7 @@ describe('ActionsPopover', () => { setIsPopoverOpen={jest.fn()} monitor={{ ...testMonitor, isEnabled: false }} position="relative" - locationId={testMonitor.location.id} + locationId={testMonitor.locationId} /> ); const enableButton = getByText('Enable monitor (all locations)'); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.tsx index e1b50220b4f6e..32c0bbb4fd0f4 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/actions_popover.tsx @@ -29,7 +29,7 @@ import { manualTestRunInProgressSelector, } from '../../../../state/manual_test_runs'; import { useMonitorAlertEnable } from '../../../../hooks/use_monitor_alert_enable'; -import { ConfigKey, MonitorOverviewItem } from '../../../../../../../common/runtime_types'; +import { ConfigKey, OverviewStatusMetaData } from '../../../../../../../common/runtime_types'; import { useCanEditSynthetics } from '../../../../../../hooks/use_capabilities'; import { useMonitorEnableHandler, useLocationName, useEnablement } from '../../../../hooks'; import { setFlyoutConfig } from '../../../../state/overview/actions'; @@ -65,7 +65,7 @@ const Container = styled.div` interface Props { isPopoverOpen: boolean; isInspectView?: boolean; - monitor: MonitorOverviewItem; + monitor: OverviewStatusMetaData; setIsPopoverOpen: React.Dispatch>; position: PopoverPosition; iconHasPanel?: boolean; @@ -112,7 +112,7 @@ export function ActionsPopover({ const detailUrl = useMonitorDetailLocator({ configId: monitor.configId, - locationId: locationId ?? monitor.location.id, + locationId: locationId ?? monitor.locationId, }); const editUrl = useEditMonitorLocator({ configId: monitor.configId }); @@ -168,8 +168,8 @@ export function ActionsPopover({ setFlyoutConfig({ configId: monitor.configId, location: locationName, - id: monitor.id, - locationId: monitor.location.id, + id: monitor.configId, + locationId: monitor.locationId, }) ); setIsPopoverOpen(false); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_group_item.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_group_item.tsx index 5b024f3c70331..f9f0a417e065e 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_group_item.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_group_item.tsx @@ -20,12 +20,12 @@ import React, { useState } from 'react'; import { i18n } from '@kbn/i18n'; import { useSelector } from 'react-redux'; import { useKey } from 'react-use'; +import { FlyoutParamProps } from '../types'; import { OverviewLoader } from '../overview_loader'; import { useFilteredGroupMonitors } from './use_filtered_group_monitors'; -import { MonitorOverviewItem } from '../../types'; +import { OverviewStatusMetaData } from '../../types'; import { selectOverviewStatus } from '../../../../../state/overview_status'; import { MetricItem } from '../metric_item'; -import { FlyoutParamProps } from '../types'; const PER_ROW = 4; const DEFAULT_ROW_SIZE = 2; @@ -39,7 +39,7 @@ export const GroupGridItem = ({ setFlyoutConfigCallback, }: { loaded: boolean; - groupMonitors: MonitorOverviewItem[]; + groupMonitors: OverviewStatusMetaData[]; groupLabel: string; fullScreenGroup: string; setFullScreenGroup: (group: string) => void; @@ -51,7 +51,7 @@ export const GroupGridItem = ({ const downMonitors = groupMonitors.filter((monitor) => { const downConfigs = overviewStatus?.downConfigs; if (downConfigs) { - return downConfigs[`${monitor.configId}-${monitor.location?.id}`]?.status === 'down'; + return downConfigs[`${monitor.configId}-${monitor.locationId}`]?.status === 'down'; } }); @@ -161,7 +161,7 @@ export const GroupGridItem = ({ > {visibleMonitors.map((monitor) => ( diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_items_by_group.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_items_by_group.tsx index ad7d406d76946..1951e0744c9e8 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_items_by_group.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/grid_by_group/grid_items_by_group.tsx @@ -17,17 +17,14 @@ import { } from '../../../../../utils/filters/filter_fields'; import { useFilters } from '../../../common/monitor_filters/use_filters'; import { GroupGridItem } from './grid_group_item'; -import { ConfigKey, MonitorOverviewItem } from '../../../../../../../../common/runtime_types'; +import { ConfigKey } from '../../../../../../../../common/runtime_types'; import { selectOverviewState, selectServiceLocationsState } from '../../../../../state'; import { FlyoutParamProps } from '../types'; +import { selectOverviewStatus } from '../../../../../state/overview_status'; export const GridItemsByGroup = ({ - loaded, - currentMonitors, setFlyoutConfigCallback, }: { - loaded: boolean; - currentMonitors: MonitorOverviewItem[]; setFlyoutConfigCallback: (params: FlyoutParamProps) => void; }) => { const [fullScreenGroup, setFullScreenGroup] = useState(''); @@ -35,6 +32,8 @@ export const GridItemsByGroup = ({ groupBy: { field: groupField, order: groupOrder }, } = useSelector(selectOverviewState); + const { allConfigs, loaded } = useSelector(selectOverviewStatus); + const { locations: allLocations } = useSelector(selectServiceLocationsState); const data = useFilters(); @@ -50,7 +49,7 @@ export const GridItemsByGroup = ({ values: getSyntheticsFilterDisplayValues(locations, 'locations', allLocations), otherValues: { label: 'Without any location', - items: currentMonitors.filter((monitor) => get(monitor, 'locations', []).length === 0), + items: allConfigs?.filter((monitor) => get(monitor, 'locations', []).length === 0), }, }; @@ -62,7 +61,7 @@ export const GridItemsByGroup = ({ values: getSyntheticsFilterDisplayValues(monitorTypes, 'monitorTypes', allLocations), otherValues: { label: 'Invalid monitor type', - items: currentMonitors.filter((monitor) => !get(monitor, ConfigKey.MONITOR_TYPE)), + items: allConfigs?.filter((monitor) => !get(monitor, ConfigKey.MONITOR_TYPE)), }, }; break; @@ -73,7 +72,7 @@ export const GridItemsByGroup = ({ values: getSyntheticsFilterDisplayValues(locations, 'locations', allLocations), otherValues: { label: 'Without any location', - items: currentMonitors.filter((monitor) => !get(monitor, 'location')), + items: allConfigs?.filter((monitor) => !get(monitor, 'location')), }, }; break; @@ -84,7 +83,7 @@ export const GridItemsByGroup = ({ values: getSyntheticsFilterDisplayValues(tags, 'tags', allLocations), otherValues: { label: 'Without any tags', - items: currentMonitors.filter((monitor) => get(monitor, 'tags', []).length === 0), + items: allConfigs?.filter((monitor) => get(monitor, 'tags', []).length === 0), }, }; break; @@ -95,7 +94,7 @@ export const GridItemsByGroup = ({ values: getSyntheticsFilterDisplayValues(projects, 'projects', allLocations), otherValues: { label: 'UI Monitors', - items: currentMonitors.filter((monitor) => !Boolean(monitor.projectId)), + items: allConfigs?.filter((monitor) => !Boolean(monitor.projectId)), }, }; break; @@ -111,17 +110,18 @@ export const GridItemsByGroup = ({ return ( <> {selectedValues.map((groupItem) => { - const filteredMonitors = currentMonitors.filter((monitor) => { - const value = get(monitor, selectedGroup.key); - if (Array.isArray(value)) { - return value.includes(groupItem.label); - } - if (selectedGroup.key === ConfigKey.MONITOR_TYPE) { - const typeKey = invert(monitorTypeKeyLabelMap)[groupItem.label]; - return get(monitor, selectedGroup.key) === typeKey; - } - return get(monitor, selectedGroup.key) === groupItem.label; - }); + const filteredMonitors = + allConfigs?.filter((monitor) => { + const value = get(monitor, selectedGroup.key); + if (Array.isArray(value)) { + return value.includes(groupItem.label); + } + if (selectedGroup.key === ConfigKey.MONITOR_TYPE) { + const typeKey = invert(monitorTypeKeyLabelMap)[groupItem.label]; + return get(monitor, selectedGroup.key) === typeKey; + } + return get(monitor, selectedGroup.key) === groupItem.label; + }) ?? []; return ( <> @@ -138,7 +138,7 @@ export const GridItemsByGroup = ({ ); })} - {selectedGroup.otherValues.items.length > 0 && ( + {selectedGroup.otherValues.items?.length && ( { const { status: overviewStatus } = useSelector(selectOverviewStatus); const { statusFilter } = useGetUrlParams(); @@ -27,10 +27,9 @@ export const useFilteredGroupMonitors = ({ return groupMonitors.filter((monitor) => { const locationLabel = - locations.find((location) => location.id === monitor.location.id)?.label ?? - monitor.location.id; + locations.find((location) => location.id === monitor.locationId)?.label ?? monitor.locationId; - const status = getConfigStatusByLocation(overviewStatus, monitor.id, locationLabel); + const status = getConfigStatusByLocation(overviewStatus, monitor.configId, locationLabel); if (statusFilter === 'up' && status.status === 'up') { return true; } else if (statusFilter === 'down' && status.status === 'down') { diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx index 4f8a97c6b8915..5136494159a3b 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item.tsx @@ -23,7 +23,7 @@ import { } from '../../../../state'; import { useLocationName, useStatusByLocationOverview } from '../../../../hooks'; import { formatDuration } from '../../../../utils/formatting'; -import { MonitorOverviewItem } from '../../../../../../../common/runtime_types'; +import { OverviewStatusMetaData } from '../../../../../../../common/runtime_types'; import { ActionsPopover } from './actions_popover'; import { hideTestNowFlyoutAction, @@ -60,17 +60,17 @@ export const MetricItem = ({ onClick, style, }: { - monitor: MonitorOverviewItem; + monitor: OverviewStatusMetaData; style?: React.CSSProperties; onClick: (params: { id: string; configId: string; location: string; locationId: string }) => void; }) => { - const trendData = useSelector(selectOverviewTrends)[monitor.configId + monitor.location.id]; + const trendData = useSelector(selectOverviewTrends)[monitor.configId + monitor.locationId]; const [isPopoverOpen, setIsPopoverOpen] = useState(false); const isErrorPopoverOpen = useSelector(selectErrorPopoverState); const locationName = useLocationName(monitor); const { status, timestamp, ping, configIdByLocation } = useStatusByLocationOverview({ configId: monitor.configId, - locationId: monitor.location.id, + locationId: monitor.locationId, }); const theme = useTheme(); @@ -80,7 +80,7 @@ export const MetricItem = ({ return (
{configIdByLocation && ( diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item/metric_item_body.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item/metric_item_body.tsx index 6976d84892ca6..839e1d6b82779 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item/metric_item_body.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item/metric_item_body.tsx @@ -11,9 +11,9 @@ import { TagsList } from '@kbn/observability-shared-plugin/public'; import { EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui'; import { MonitorTypeBadge } from '../../../../common/components/monitor_type_badge'; import * as labels from '../../../management/monitor_list_table/labels'; -import { ConfigKey, MonitorOverviewItem } from '../../../../../../../../common/runtime_types'; +import { OverviewStatusMetaData } from '../../../../../../../../common/runtime_types'; -export const MetricItemBody = ({ monitor }: { monitor: MonitorOverviewItem }) => { +export const MetricItemBody = ({ monitor }: { monitor: OverviewStatusMetaData }) => { const tags = monitor.tags; const history = useHistory(); @@ -23,13 +23,11 @@ export const MetricItemBody = ({ monitor }: { monitor: MonitorOverviewItem }) => { history.push({ - search: `monitorTypes=${encodeURIComponent( - JSON.stringify([monitor[ConfigKey.MONITOR_TYPE]]) - )}`, + search: `monitorTypes=${encodeURIComponent(JSON.stringify([monitor.type]))}`, }); }} /> diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item_icon.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item_icon.tsx index 8945726bc443b..f932b74d07ba9 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item_icon.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/metric_item_icon.tsx @@ -28,7 +28,7 @@ import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { useRef } from 'react'; import { selectErrorPopoverState, toggleErrorPopoverOpen } from '../../../../state'; import { useErrorDetailsLink } from '../../../common/links/error_details_link'; -import { MonitorOverviewItem, OverviewPing } from '../../../../../../../common/runtime_types'; +import { OverviewPing, OverviewStatusMetaData } from '../../../../../../../common/runtime_types'; import { isTestRunning, manualTestRunSelector } from '../../../../state/manual_test_runs'; import { useDateFormat } from '../../../../../../hooks/use_date_format'; @@ -47,7 +47,7 @@ export const MetricItemIcon = ({ timestamp, configIdByLocation, }: { - monitor: MonitorOverviewItem; + monitor: OverviewStatusMetaData; status: string; configIdByLocation: string; timestamp?: string; @@ -69,7 +69,7 @@ export const MetricItemIcon = ({ const errorLink = useErrorDetailsLink({ configId: monitor.configId, stateId: ping?.state?.id!, - locationId: monitor.location.id, + locationId: monitor.locationId, }); const euiShadow = useEuiShadow('s'); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.tsx index cf2f6cb97d82e..8c07b3e0cad2d 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/monitor_detail_flyout.tsx @@ -30,6 +30,7 @@ import { useKibana } from '@kbn/kibana-react-plugin/public'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { useTheme, FETCH_STATUS, useFetcher } from '@kbn/observability-shared-plugin/public'; +import { useOverviewStatus } from '../../hooks/use_overview_status'; import { MonitorDetailsPanel } from '../../../common/components/monitor_details_panel'; import { ClientPluginsStart } from '../../../../../../plugin'; import { LocationsStatus, useStatusByLocation } from '../../../../hooks/use_status_by_location'; @@ -37,12 +38,11 @@ import { MonitorEnabled } from '../../management/monitor_list_table/monitor_enab import { ActionsPopover } from './actions_popover'; import { selectMonitorUpsertStatus, - selectOverviewState, selectServiceLocationsState, setFlyoutConfig, } from '../../../../state'; import { useMonitorDetail } from '../../../../hooks/use_monitor_detail'; -import { ConfigKey, EncryptedSyntheticsMonitor, MonitorOverviewItem } from '../types'; +import { ConfigKey, EncryptedSyntheticsMonitor, OverviewStatusMetaData } from '../types'; import { useMonitorDetailLocator } from '../../../../hooks/use_monitor_detail_locator'; import { MonitorStatus } from '../../../common/components/monitor_status'; import { MonitorLocationSelect } from '../../../common/components/monitor_location_select'; @@ -218,14 +218,17 @@ export function LoadingState() { export function MonitorDetailFlyout(props: Props) { const { id, configId, onLocationChange, locationId } = props; - const { - data: { monitors }, - } = useSelector(selectOverviewState); - const monitor: MonitorOverviewItem | undefined = useMemo(() => { - const overviewItem = monitors.filter(({ id: overviewItemId }) => overviewItemId === id)[0]; + const { status: overviewStatus } = useOverviewStatus({ scopeStatusByLocation: true }); + + const monitor: OverviewStatusMetaData | undefined = useMemo(() => { + const allConfigs = Object.values({ + ...(overviewStatus?.upConfigs ?? {}), + ...(overviewStatus?.downConfigs ?? {}), + }); + const overviewItem = allConfigs.find((ov) => ov.configId === configId); if (overviewItem) return overviewItem; - }, [id, monitors]); + }, [overviewStatus?.upConfigs, overviewStatus?.downConfigs, configId]); const setLocation = useCallback( (location: string, locationIdT: string) => diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.tsx index ec453ba30c973..e4918d1d4c07d 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/overview_grid.tsx @@ -18,19 +18,19 @@ import { EuiAutoSizer, EuiAutoSize, } from '@elastic/eui'; +import { OverviewStatusMetaData } from '../../../../../../../common/runtime_types'; +import { quietFetchOverviewStatusAction } from '../../../../state/overview_status'; import type { TrendRequest } from '../../../../../../../common/types'; import { SYNTHETICS_MONITORS_EMBEDDABLE } from '../../../../../embeddables/constants'; import { AddToDashboard } from '../../../common/components/add_to_dashboard'; import { useOverviewStatus } from '../../hooks/use_overview_status'; import { GridItemsByGroup } from './grid_by_group/grid_items_by_group'; import { GroupFields } from './grid_by_group/group_fields'; +import { selectOverviewState, setFlyoutConfig } from '../../../../state/overview'; +import { useMonitorsSortedByStatus } from '../../../../hooks/use_monitors_sorted_by_status'; import { - fetchMonitorOverviewAction, - quietFetchOverviewAction, refreshOverviewTrends, - selectOverviewState, selectOverviewTrends, - setFlyoutConfig, trendStatsBatch, } from '../../../../state/overview'; import { OverviewLoader } from './overview_loader'; @@ -41,8 +41,6 @@ import { MonitorDetailFlyout } from './monitor_detail_flyout'; import { useSyntheticsRefreshContext } from '../../../../contexts'; import { MetricItem } from './metric_item'; import { FlyoutParamProps } from './types'; -import { MonitorOverviewItem } from '../types'; -import { useMonitorsSortedByStatus } from '../../../../hooks/use_monitors_sorted_by_status'; const ITEM_HEIGHT = 172; const ROW_COUNT = 4; @@ -52,35 +50,28 @@ const LIST_THRESHOLD = 12; interface ListItem { configId: string; - location: { id: string }; + locationId: string; } export const OverviewGrid = memo(() => { - const { status } = useOverviewStatus({ scopeStatusByLocation: true }); - const monitorsSortedByStatus: MonitorOverviewItem[] = - useMonitorsSortedByStatus().monitorsSortedByStatus; + const { status, allConfigs, loaded } = useOverviewStatus({ + scopeStatusByLocation: true, + }); + const monitorsSortedByStatus: OverviewStatusMetaData[] = useMonitorsSortedByStatus(); const { - data: { monitors }, flyoutConfig, - loaded, pageState, groupBy: { field: groupField }, } = useSelector(selectOverviewState); const trendData = useSelector(selectOverviewTrends); const { perPage } = pageState; - const [page, setPage] = useState(1); const [maxItem, setMaxItem] = useState(0); const [currentIndex, setCurrentIndex] = useState(0); const dispatch = useDispatch(); - // fetch overview for all other page state changes - useEffect(() => { - dispatch(fetchMonitorOverviewAction.get(pageState)); - }, [dispatch, pageState]); - const setFlyoutConfigCallback = useCallback( (params: FlyoutParamProps) => dispatch(setFlyoutConfig(params)), [dispatch] @@ -88,7 +79,7 @@ export const OverviewGrid = memo(() => { const hideFlyout = useCallback(() => dispatch(setFlyoutConfig(null)), [dispatch]); const { lastRefresh } = useSyntheticsRefreshContext(); const forceRefreshCallback = useCallback( - () => dispatch(quietFetchOverviewAction.get(pageState)), + () => dispatch(quietFetchOverviewStatusAction.get({ pageState })), [dispatch, pageState] ); @@ -97,10 +88,10 @@ export const OverviewGrid = memo(() => { const batch: TrendRequest[] = []; const chunk = monitorsSortedByStatus.slice(0, (maxItem + 1) * ROW_COUNT); for (const item of chunk) { - if (trendData[item.configId + item.location.id] === undefined) { + if (trendData[item.configId + item.locationId] === undefined) { batch.push({ configId: item.configId, - locationId: item.location.id, + locationId: item.locationId, schedule: item.schedule, }); } @@ -141,18 +132,14 @@ export const OverviewGrid = memo(() => { wrap={true} > - + - setPage(1)} /> + @@ -166,12 +153,10 @@ export const OverviewGrid = memo(() => { {({ width }: EuiAutoSize) => ( - listItems[idx].every((m) => !!trendData[m.configId + m.location.id]) + listItems[idx].every((m) => !!trendData[m.configId + m.locationId]) } itemCount={listItems.length} - loadMoreItems={(_start: number, stop: number) => - setMaxItem(Math.max(maxItem, stop)) - } + loadMoreItems={(_, stop: number) => setMaxItem(Math.max(maxItem, stop))} minimumBatchSize={MIN_BATCH_SIZE} threshold={LIST_THRESHOLD} > @@ -226,11 +211,7 @@ export const OverviewGrid = memo(() => { ) ) : ( - + )} @@ -241,12 +222,12 @@ export const OverviewGrid = memo(() => { <> - {monitorsSortedByStatus.length === monitors.length && ( + {monitorsSortedByStatus.length === allConfigs.length && ( {SHOWING_ALL_MONITORS_LABEL} )} - {monitorsSortedByStatus.length === monitors.length && + {monitorsSortedByStatus.length === allConfigs.length && monitorsSortedByStatus.length > perPage && ( { - const { loaded } = useSelector(selectOverviewState); + const { loaded } = useSelector(selectOverviewStatus); return loaded && total !== undefined ? ( diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/sort_fields.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/sort_fields.tsx index 4d1341a805435..03fa4ddc2316d 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/sort_fields.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview/sort_fields.tsx @@ -15,16 +15,13 @@ import { ConfigKey } from '../../../../../../../common/runtime_types'; import { selectOverviewState, setOverviewPageStateAction } from '../../../../state/overview'; import { SortMenu } from './sort_menu'; -export const SortFields = ({ onSortChange }: { onSortChange?: () => void }) => { +export const SortFields = () => { const { pageState: { sortOrder, sortField }, } = useSelector(selectOverviewState); const dispatch = useDispatch(); const { asc, desc, label } = getOrderContent(sortField); const handleSortChange = (payloadAction: PayloadAction) => { - if (onSortChange) { - onSortChange(); - } dispatch(payloadAction); }; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx index da28ccc325ca3..17df81619469e 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/components/monitors_page/overview/overview_page.tsx @@ -15,15 +15,8 @@ import { DisabledCallout } from '../management/disabled_callout'; import { FilterGroup } from '../common/monitor_filters/filter_group'; import { OverviewAlerts } from './overview/overview_alerts'; import { useEnablement } from '../../../hooks'; -import { useSyntheticsRefreshContext } from '../../../contexts/synthetics_refresh_context'; -import { - fetchMonitorOverviewAction, - quietFetchOverviewAction, - selectOverviewState, - selectServiceLocationsState, -} from '../../../state'; +import { selectServiceLocationsState } from '../../../state'; import { getServiceLocations } from '../../../state/service_locations'; - import { GETTING_STARTED_ROUTE, MONITORS_ROUTE } from '../../../../../../common/constants'; import { useMonitorList } from '../hooks/use_monitor_list'; @@ -43,7 +36,6 @@ export const OverviewPage: React.FC = () => { const dispatch = useDispatch(); - const { lastRefresh } = useSyntheticsRefreshContext(); const { search } = useLocation(); const { loading: locationsLoading, locationsLoaded } = useSelector(selectServiceLocationsState); @@ -59,11 +51,7 @@ export const OverviewPage: React.FC = () => { const { isEnabled, loading: enablementLoading } = useEnablement(); - const { - loaded: overviewLoaded, - data: { monitors }, - pageState, - } = useSelector(selectOverviewState); + const { allConfigs, loaded: overviewLoaded } = useSelector(selectOverviewStatus); const { loading: monitorsLoading, @@ -72,23 +60,6 @@ export const OverviewPage: React.FC = () => { absoluteTotal, } = useMonitorList(); - // fetch overview for all other page state changes - useEffect(() => { - if (!overviewLoaded) { - dispatch(fetchMonitorOverviewAction.get(pageState)); - } - // change only needs to be triggered on pageState change - }, [dispatch, pageState, overviewLoaded]); - - // fetch overview for refresh - useEffect(() => { - if (monitorsLoaded) { - dispatch(quietFetchOverviewAction.get(pageState)); - } - // for page state change we don't want quite fetch, see above fetch ^^ - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [dispatch, lastRefresh]); - const hasNoMonitors = !search && !enablementLoading && monitorsLoaded && absoluteTotal === 0; if (hasNoMonitors && !monitorsLoading && isEnabled) { @@ -99,7 +70,7 @@ export const OverviewPage: React.FC = () => { return ; } - const noMonitorFound = monitorsLoaded && overviewLoaded && monitors?.length === 0; + const hasMonitors = !(monitorsLoaded && overviewLoaded && allConfigs?.length === 0); return ( <> @@ -117,7 +88,7 @@ export const OverviewPage: React.FC = () => { - {!noMonitorFound ? ( + {hasMonitors ? ( <> diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_location_name.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_location_name.test.tsx index f798880608bcc..0a92712d282a5 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_location_name.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_location_name.test.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { renderHook } from '@testing-library/react-hooks'; import { useLocationName } from './use_location_name'; import { WrappedHelper } from '../utils/testing'; -import { MonitorOverviewItem } from '../../../../common/runtime_types'; +import { OverviewStatusMetaData } from '../../../../common/runtime_types'; describe('useLocationName', () => { beforeEach(() => { @@ -48,8 +48,8 @@ describe('useLocationName', () => { const { result } = renderHook( () => useLocationName({ - location: { id: 'us_central' }, - } as MonitorOverviewItem), + locationId: 'us_central', + } as OverviewStatusMetaData), { wrapper: WrapperWithState } ); expect(result.current).toEqual('US Central'); @@ -88,10 +88,10 @@ describe('useLocationName', () => { const { result } = renderHook( () => useLocationName({ - location: { id: 'us_west' }, - } as MonitorOverviewItem), + locationId: 'us_central_qa', + } as OverviewStatusMetaData), { wrapper: WrapperWithState } ); - expect(result.current).toEqual('us_west'); + expect(result.current).toEqual('us_central_qa'); }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_location_name.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_location_name.tsx index b25112b15bb10..25cd25a8804a5 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_location_name.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_location_name.tsx @@ -7,10 +7,10 @@ import { useMemo, useEffect } from 'react'; import { useSelector, useDispatch } from 'react-redux'; -import { MonitorOverviewItem } from '../../../../common/runtime_types'; +import { OverviewStatusMetaData } from '../../../../common/runtime_types'; import { selectServiceLocationsState, getServiceLocations } from '../state'; -export function useLocationName(monitor: MonitorOverviewItem) { +export function useLocationName(monitor: OverviewStatusMetaData) { const dispatch = useDispatch(); const { locationsLoaded, locations } = useSelector(selectServiceLocationsState); useEffect(() => { @@ -18,14 +18,14 @@ export function useLocationName(monitor: MonitorOverviewItem) { dispatch(getServiceLocations()); } }); - const locationId = monitor?.location.id; + const locationId = monitor?.locationId; return useMemo(() => { - if (!locationsLoaded || monitor.location.label) { - return monitor.location.label ?? monitor.location.id; + if (!locationsLoaded || monitor.locationLabel) { + return monitor.locationLabel ?? monitor.locationId; } else { const location = locations.find((loc) => loc.id === locationId); - return location?.label ?? (monitor.location.label || monitor.location.id); + return location?.label ?? (monitor.locationLabel || monitor.locationId); } }, [locationsLoaded, locations, locationId, monitor]); } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitor_enable_handler.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitor_enable_handler.tsx index 90df1b5baff58..a1759a3e7b3cd 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitor_enable_handler.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitor_enable_handler.tsx @@ -8,8 +8,9 @@ import { FETCH_STATUS } from '@kbn/observability-shared-plugin/public'; import { useCallback, useEffect, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; +import { fetchUpsertMonitorAction } from '../state/monitor_list/actions'; import { ConfigKey } from '../components/monitors_page/overview/types'; -import { fetchUpsertMonitorAction, selectMonitorUpsertStatuses } from '../state'; +import { selectMonitorUpsertStatuses } from '../state'; export interface EnableStateMonitorLabels { failureLabel: string; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.test.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.test.tsx index ad4133dd28e2b..a8f3dee54f07d 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.test.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.test.tsx @@ -55,109 +55,58 @@ describe('useMonitorsSortedByStatus', () => { sortOrder, sortField: 'name.keyword', }, - data: { - total: 0, - allMonitorIds: [], - monitors: [ - { - configId: 'test-monitor-1', - id: 'test-monitor-1', - name: 'Test monitor 1', - location: location1, - isEnabled: false, - }, - { - configId: 'test-monitor-1', - id: 'test-monitor-1', - name: 'Test monitor 1', - location: location2, - isEnabled: true, - }, - { - configId: 'test-monitor-2', - id: 'test-monitor-2', - name: 'Test monitor 2', - location: location1, - isEnabled: true, - }, - { - configId: 'test-monitor-2', - id: 'test-monitor-2', - name: 'Test monitor 2', - location: location2, - isEnabled: true, - }, - { - configId: 'test-monitor-3', - id: 'test-monitor-3', - name: 'Test monitor 3', - location: location1, - isEnabled: true, - }, - { - configId: 'test-monitor-3', - id: 'test-monitor-3', - name: 'Test monitor 3', - location: location2, - isEnabled: true, - }, - { - configId: 'test-monitor-4', - id: 'test-monitor-4', - name: 'Test monitor 4', - location: location1, - isEnabled: true, - }, - ], - }, - error: null, - loaded: false, - loading: false, }, overviewStatus: { status: { upConfigs: { - [`test-monitor-1-${location2.id}`]: { - configId: 'test-monitor-1', - monitorQueryId: 'test-monitor-1', + [`test-monitor-up-1-${location2.id}`]: { + configId: 'test-monitor-up-1', locationId: location2.id, + name: 'test-monitor-up-1', }, - [`test-monitor-2-${location2.id}`]: { - configId: 'test-monitor-2', - monitorQueryId: 'test-monitor-2', + [`test-monitor-up-2-${location2.id}`]: { + configId: 'test-monitor-up-2', locationId: location2.id, + name: 'test-monitor-up-2', }, [`test-monitor-3-${location2.id}`]: { configId: 'test-monitor-3', - monitorQueryId: 'test-monitor-3', locationId: location2.id, + name: 'test-monitor-3', }, }, downConfigs: { - [`test-monitor-1-${location1.id}`]: { - configId: 'test-monitor-1', - monitorQueryId: 'test-monitor-1', + [`test-monitor-down-1-${location1.id}`]: { + configId: 'test-monitor-down-1', locationId: location1.id, + name: 'test-monitor-down-1', }, - [`test-monitor-2-${location1.id}`]: { - configId: 'test-monitor-2', - monitorQueryId: 'test-monitor-2', + [`test-monitor-down-2-${location1.id}`]: { + configId: 'test-monitor-down-2', locationId: location1.id, + name: 'test-monitor-down-2', }, [`test-monitor-3${location1.id}`]: { configId: 'test-monitor-3', - monitorQueryId: 'test-monitor-3', locationId: location1.id, + name: 'test-monitor-3', }, }, pendingConfigs: { [`test-monitor-4-${location1.id}`]: { configId: 'test-monitor-4', - monitorQueryId: 'test-monitor-4', locationId: location1.id, + name: 'test-monitor-4', }, }, }, + disabledConfigs: { + [`test-monitor-disabled-1-${location1.id}`]: { + configId: 'test-monitor-disabled-1', + locationId: location1.id, + name: 'test-monitor-disabled-1', + }, + } as any, }, }} > @@ -170,64 +119,50 @@ describe('useMonitorsSortedByStatus', () => { const { result } = renderHook(() => useMonitorsSortedByStatus(), { wrapper: WrapperWithState, }); - expect(result.current).toEqual({ - monitorsSortedByStatus: [ - { - configId: 'test-monitor-2', - id: 'test-monitor-2', - name: 'Test monitor 2', - location: location1, - isEnabled: true, + expect(result.current).toMatchInlineSnapshot(` + Array [ + Object { + "configId": "test-monitor-3", + "locationId": "us_central", + "name": "test-monitor-3", }, - { - configId: 'test-monitor-3', - id: 'test-monitor-3', - name: 'Test monitor 3', - location: location1, - isEnabled: true, + Object { + "configId": "test-monitor-3", + "locationId": "us_east", + "name": "test-monitor-3", }, - { - configId: 'test-monitor-1', - id: 'test-monitor-1', - name: 'Test monitor 1', - location: location2, - isEnabled: true, + Object { + "configId": "test-monitor-4", + "locationId": "us_central", + "name": "test-monitor-4", }, - { - configId: 'test-monitor-2', - id: 'test-monitor-2', - name: 'Test monitor 2', - location: location2, - isEnabled: true, + Object { + "configId": "test-monitor-disabled-1", + "locationId": "us_central", + "name": "test-monitor-disabled-1", }, - { - configId: 'test-monitor-3', - id: 'test-monitor-3', - name: 'Test monitor 3', - location: location2, - isEnabled: true, + Object { + "configId": "test-monitor-down-1", + "locationId": "us_central", + "name": "test-monitor-down-1", }, - { - configId: 'test-monitor-1', - id: 'test-monitor-1', - name: 'Test monitor 1', - location: location1, - isEnabled: false, + Object { + "configId": "test-monitor-down-2", + "locationId": "us_central", + "name": "test-monitor-down-2", }, - { - configId: 'test-monitor-4', - id: 'test-monitor-4', - name: 'Test monitor 4', - location: location1, - isEnabled: true, + Object { + "configId": "test-monitor-up-1", + "locationId": "us_east", + "name": "test-monitor-up-1", }, - ], - downMonitors: { - 'test-monitor-1': ['us_central'], - 'test-monitor-2': ['us_central'], - 'test-monitor-3': ['us_central'], - }, - }); + Object { + "configId": "test-monitor-up-2", + "locationId": "us_east", + "name": "test-monitor-up-2", + }, + ] + `); }); it('returns monitors up first when sort order is desc', () => { @@ -236,64 +171,50 @@ describe('useMonitorsSortedByStatus', () => { {children} ), }); - expect(result.current).toEqual({ - monitorsSortedByStatus: [ - { - configId: 'test-monitor-1', - id: 'test-monitor-1', - name: 'Test monitor 1', - location: location2, - isEnabled: true, + expect(result.current).toMatchInlineSnapshot(` + Array [ + Object { + "configId": "test-monitor-up-2", + "locationId": "us_east", + "name": "test-monitor-up-2", }, - { - configId: 'test-monitor-2', - id: 'test-monitor-2', - name: 'Test monitor 2', - location: location2, - isEnabled: true, + Object { + "configId": "test-monitor-up-1", + "locationId": "us_east", + "name": "test-monitor-up-1", }, - { - configId: 'test-monitor-3', - id: 'test-monitor-3', - name: 'Test monitor 3', - location: location2, - isEnabled: true, + Object { + "configId": "test-monitor-down-2", + "locationId": "us_central", + "name": "test-monitor-down-2", }, - { - configId: 'test-monitor-2', - id: 'test-monitor-2', - name: 'Test monitor 2', - location: location1, - isEnabled: true, + Object { + "configId": "test-monitor-down-1", + "locationId": "us_central", + "name": "test-monitor-down-1", }, - { - configId: 'test-monitor-3', - id: 'test-monitor-3', - name: 'Test monitor 3', - location: location1, - isEnabled: true, + Object { + "configId": "test-monitor-disabled-1", + "locationId": "us_central", + "name": "test-monitor-disabled-1", }, - { - configId: 'test-monitor-1', - id: 'test-monitor-1', - name: 'Test monitor 1', - location: location1, - isEnabled: false, + Object { + "configId": "test-monitor-4", + "locationId": "us_central", + "name": "test-monitor-4", }, - { - configId: 'test-monitor-4', - id: 'test-monitor-4', - name: 'Test monitor 4', - location: location1, - isEnabled: true, + Object { + "configId": "test-monitor-3", + "locationId": "us_central", + "name": "test-monitor-3", }, - ], - downMonitors: { - 'test-monitor-1': ['us_central'], - 'test-monitor-2': ['us_central'], - 'test-monitor-3': ['us_central'], - }, - }); + Object { + "configId": "test-monitor-3", + "locationId": "us_east", + "name": "test-monitor-3", + }, + ] + `); }); it('returns only up monitors when statusFilter is down', () => { @@ -306,36 +227,25 @@ describe('useMonitorsSortedByStatus', () => { {children} ), }); - expect(result.current).toEqual({ - monitorsSortedByStatus: [ - { - configId: 'test-monitor-1', - id: 'test-monitor-1', - name: 'Test monitor 1', - location: location2, - isEnabled: true, + expect(result.current).toMatchInlineSnapshot(` + Array [ + Object { + "configId": "test-monitor-up-2", + "locationId": "us_east", + "name": "test-monitor-up-2", }, - { - configId: 'test-monitor-2', - id: 'test-monitor-2', - name: 'Test monitor 2', - location: location2, - isEnabled: true, + Object { + "configId": "test-monitor-up-1", + "locationId": "us_east", + "name": "test-monitor-up-1", }, - { - configId: 'test-monitor-3', - id: 'test-monitor-3', - name: 'Test monitor 3', - location: location2, - isEnabled: true, + Object { + "configId": "test-monitor-3", + "locationId": "us_east", + "name": "test-monitor-3", }, - ], - downMonitors: { - 'test-monitor-1': ['us_central'], - 'test-monitor-2': ['us_central'], - 'test-monitor-3': ['us_central'], - }, - }); + ] + `); }); it('returns only down monitors when statusFilter is down', () => { @@ -348,29 +258,25 @@ describe('useMonitorsSortedByStatus', () => { {children} ), }); - expect(result.current).toEqual({ - monitorsSortedByStatus: [ - { - configId: 'test-monitor-2', - id: 'test-monitor-2', - name: 'Test monitor 2', - location: location1, - isEnabled: true, + expect(result.current).toMatchInlineSnapshot(` + Array [ + Object { + "configId": "test-monitor-down-2", + "locationId": "us_central", + "name": "test-monitor-down-2", }, - { - configId: 'test-monitor-3', - id: 'test-monitor-3', - name: 'Test monitor 3', - location: location1, - isEnabled: true, + Object { + "configId": "test-monitor-down-1", + "locationId": "us_central", + "name": "test-monitor-down-1", }, - ], - downMonitors: { - 'test-monitor-1': ['us_central'], - 'test-monitor-2': ['us_central'], - 'test-monitor-3': ['us_central'], - }, - }); + Object { + "configId": "test-monitor-3", + "locationId": "us_central", + "name": "test-monitor-3", + }, + ] + `); }); it('returns only disabled monitors when statusFilter is down', () => { @@ -383,21 +289,14 @@ describe('useMonitorsSortedByStatus', () => { {children} ), }); - expect(result.current).toEqual({ - monitorsSortedByStatus: [ - { - configId: 'test-monitor-1', - id: 'test-monitor-1', - name: 'Test monitor 1', - location: location1, - isEnabled: false, + expect(result.current).toMatchInlineSnapshot(` + Array [ + Object { + "configId": "test-monitor-disabled-1", + "locationId": "us_central", + "name": "test-monitor-disabled-1", }, - ], - downMonitors: { - 'test-monitor-1': ['us_central'], - 'test-monitor-2': ['us_central'], - 'test-monitor-3': ['us_central'], - }, - }); + ] + `); }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx index c0a59c31a8760..e0eda611689c8 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_monitors_sorted_by_status.tsx @@ -5,113 +5,72 @@ * 2.0. */ -import { useMemo, useRef } from 'react'; +import { useMemo } from 'react'; import { useSelector } from 'react-redux'; +import moment from 'moment'; +import { OverviewStatusMetaData } from '../../../../common/runtime_types'; import { selectOverviewStatus } from '../state/overview_status'; -import { MonitorOverviewItem } from '../../../../common/runtime_types'; import { selectOverviewState } from '../state/overview'; import { useGetUrlParams } from './use_url_params'; -export function useMonitorsSortedByStatus(): { - monitorsSortedByStatus: MonitorOverviewItem[]; - downMonitors: Record | null; -} { +export function useMonitorsSortedByStatus(): OverviewStatusMetaData[] { const { statusFilter } = useGetUrlParams(); - const { status } = useSelector(selectOverviewStatus); + const { status, disabledConfigs } = useSelector(selectOverviewStatus); const { - pageState: { sortOrder }, - data: { monitors }, + pageState: { sortOrder, sortField }, } = useSelector(selectOverviewState); - const downMonitors = useRef | null>(null); - - const monitorsSortedByStatus = useMemo(() => { + return useMemo(() => { if (!status) { - return { - down: [], - up: [], - disabled: [], - pending: [], - }; + return []; } - const { downConfigs, pendingConfigs } = status; - const downMonitorMap: Record = {}; - Object.values(downConfigs).forEach(({ locationId, configId }) => { - if (downMonitorMap[configId]) { - downMonitorMap[configId].push(locationId); - } else { - downMonitorMap[configId] = [locationId]; - } - }); + let result: OverviewStatusMetaData[] = []; - const orderedDownMonitors: MonitorOverviewItem[] = []; - const orderedUpMonitors: MonitorOverviewItem[] = []; - const orderedDisabledMonitors: MonitorOverviewItem[] = []; - const orderedPendingMonitors: MonitorOverviewItem[] = []; + const { downConfigs, pendingConfigs, upConfigs } = status; - monitors.forEach((monitor) => { - if (!monitor.isEnabled) { - orderedDisabledMonitors.push(monitor); - } else if ( - monitor.configId in downMonitorMap && - downMonitorMap[monitor.configId].includes(monitor.location.id) - ) { - orderedDownMonitors.push(monitor); - } else if (pendingConfigs?.[`${monitor.configId}-${monitor.location.id}`]) { - orderedPendingMonitors.push(monitor); - } else { - orderedUpMonitors.push(monitor); + if (statusFilter) { + switch (statusFilter) { + case 'down': + result = Object.values(downConfigs) as OverviewStatusMetaData[]; + break; + case 'up': + result = Object.values(upConfigs) as OverviewStatusMetaData[]; + break; + case 'disabled': + result = Object.values(disabledConfigs ?? {}) as OverviewStatusMetaData[]; + break; + case 'pending': + result = Object.values(pendingConfigs) as OverviewStatusMetaData[]; + break; + default: + break; } - }); - downMonitors.current = downMonitorMap; + } else { + const upAndDownMonitors = + sortOrder === 'asc' + ? [...Object.values(downConfigs), ...Object.values(upConfigs)] + : [...Object.values(upConfigs), ...Object.values(downConfigs)]; - return { - down: orderedDownMonitors, - up: orderedUpMonitors, - disabled: orderedDisabledMonitors, - pending: orderedPendingMonitors, - }; - }, [monitors, downMonitors, status]); - - return useMemo(() => { - switch (statusFilter) { - case 'down': - return { - monitorsSortedByStatus: monitorsSortedByStatus.down, - downMonitors: downMonitors.current, - }; - case 'up': - return { - monitorsSortedByStatus: monitorsSortedByStatus.up, - downMonitors: downMonitors.current, - }; - case 'disabled': - return { - monitorsSortedByStatus: monitorsSortedByStatus.disabled, - downMonitors: downMonitors.current, - }; - case 'pending': - return { - monitorsSortedByStatus: monitorsSortedByStatus.pending, - downMonitors: downMonitors.current, - }; - default: - break; - } - const upAndDownMonitors = - sortOrder === 'asc' - ? [...monitorsSortedByStatus.down, ...monitorsSortedByStatus.up] - : [...monitorsSortedByStatus.up, ...monitorsSortedByStatus.down]; - - return { - monitorsSortedByStatus: [ + result = [ ...upAndDownMonitors, - ...monitorsSortedByStatus.disabled, - ...monitorsSortedByStatus.pending, - ], - downMonitors: downMonitors.current, - }; - }, [downMonitors, monitorsSortedByStatus, sortOrder, statusFilter]); + ...Object.values(disabledConfigs ?? {}), + ...Object.values(pendingConfigs), + ] as OverviewStatusMetaData[]; + } + switch (sortField) { + case 'name.keyword': + result = result.sort((a, b) => a.name.localeCompare(b.name)); + return sortOrder === 'asc' ? result : result.reverse(); + case 'status': + return result; + case 'updated_at': + result = result.sort((a, b) => { + return moment(a.updated_at).diff(moment(b.updated_at)); + }); + return sortOrder === 'asc' ? result : result.reverse(); + } + return result; + }, [disabledConfigs, sortField, sortOrder, status, statusFilter]); } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_status_by_location_overview.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_status_by_location_overview.ts index f7c5b57984a4b..a184bfa488944 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_status_by_location_overview.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/hooks/use_status_by_location_overview.ts @@ -29,9 +29,8 @@ export const getConfigStatusByLocation = ( if (!status) { return { status: 'unknown' }; } - const allConfigs = status.allConfigs; const configIdByLocation = `${configId}-${locationId}`; - const config = allConfigs[configIdByLocation]; + const config = status.upConfigs[configIdByLocation] || status.downConfigs[configIdByLocation]; return { configIdByLocation, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/monitor_list/effects.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/monitor_list/effects.ts index 0772a0a57c6e5..ac142d7c52055 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/monitor_list/effects.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/monitor_list/effects.ts @@ -12,7 +12,6 @@ import { enableDefaultAlertingAction } from '../alert_rules'; import { ConfigKey, EncryptedSyntheticsSavedMonitor } from '../../../../../common/runtime_types'; import { kibanaService } from '../../../../utils/kibana_service'; import { MonitorOverviewPageState } from '../overview'; -import { quietFetchOverviewAction } from '../overview/actions'; import { selectOverviewState } from '../overview/selectors'; import { fetchEffectFactory, sendErrorToast, sendSuccessToast } from '../utils/fetch_effect'; import { serializeHttpFetchError } from '../utils/http_error'; @@ -98,7 +97,6 @@ export function* upsertMonitorEffect() { if (action.payload.shouldQuietFetchAfterSuccess !== false) { const monitorState = yield select(selectOverviewState); if (hasPageState(monitorState)) { - yield put(quietFetchOverviewAction.get(monitorState.pageState)); yield put( quietFetchOverviewStatusAction.get({ pageState: monitorState.pageState, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/actions.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/actions.ts index d7970f720e803..96f9eed019769 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/actions.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/actions.ts @@ -13,12 +13,6 @@ import type { MonitorOverviewPageState, MonitorOverviewState, } from './models'; -import { MonitorOverviewResult } from '../../../../../common/runtime_types'; - -export const fetchMonitorOverviewAction = createAsyncAction< - MonitorOverviewPageState, - MonitorOverviewResult ->('fetchMonitorOverviewAction'); export const setOverviewPageStateAction = createAction>( 'setOverviewPageStateAction' @@ -30,11 +24,6 @@ export const setOverviewGroupByAction = createAction('setFlyoutConfig'); export const toggleErrorPopoverOpen = createAction('setErrorPopoverOpen'); -export const quietFetchOverviewAction = createAsyncAction< - MonitorOverviewPageState, - MonitorOverviewResult ->('quietFetchOverviewAction'); - export const refreshOverviewTrends = createAsyncAction( 'refreshOverviewTrendStats' ); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/api.ts index 2a8e782013651..4f5315d5c862f 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/api.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/api.ts @@ -5,60 +5,9 @@ * 2.0. */ -import { SYNTHETICS_API_URLS } from '../../../../../common/constants'; -import { - MonitorOverviewResult, - MonitorOverviewResultCodec, - FetchMonitorOverviewQueryArgs, - OverviewStatus, - OverviewStatusCodec, -} from '../../../../../common/runtime_types'; import type { TrendRequest, TrendTable } from '../../../../../common/types'; import { apiService } from '../../../../utils/api_service'; -import type { MonitorOverviewPageState } from './models'; - -function toMonitorOverviewQueryArgs( - pageState: MonitorOverviewPageState -): FetchMonitorOverviewQueryArgs { - return { - sortField: pageState.sortField, - sortOrder: pageState.sortOrder, - ...toStatusOverviewQueryArgs(pageState), - }; -} - -export function toStatusOverviewQueryArgs( - pageState: MonitorOverviewPageState -): FetchMonitorOverviewQueryArgs { - return { - query: pageState.query, - tags: pageState.tags, - locations: pageState.locations, - projects: pageState.projects, - schedules: pageState.schedules, - monitorTypes: pageState.monitorTypes, - monitorQueryIds: pageState.monitorQueryIds, - searchFields: [], - }; -} - -export const fetchMonitorOverview = async ( - pageState: MonitorOverviewPageState -): Promise => { - const params = toMonitorOverviewQueryArgs(pageState); - return apiService.get( - SYNTHETICS_API_URLS.SYNTHETICS_OVERVIEW, - params, - MonitorOverviewResultCodec - ); -}; - -export const fetchOverviewStatus = async ( - pageState: MonitorOverviewPageState -): Promise => { - const params = toStatusOverviewQueryArgs(pageState); - return apiService.get(SYNTHETICS_API_URLS.OVERVIEW_STATUS, params, OverviewStatusCodec); -}; +import { SYNTHETICS_API_URLS } from '../../../../../common/constants'; export const fetchOverviewTrendStats = async (monitors: TrendRequest[]): Promise => monitors.length ? apiService.post(SYNTHETICS_API_URLS.OVERVIEW_TRENDS, monitors) : {}; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.test.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.test.ts index 4a44b2d56c11c..d6c466c0b7a46 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.test.ts @@ -11,7 +11,8 @@ import { GetTrendPayload, TrendKey, TrendRequest, TrendTable } from '../../../.. import { TRENDS_CHUNK_SIZE, fetchTrendEffect, refreshTrends } from './effects'; import { trendStatsBatch } from './actions'; import { fetchOverviewTrendStats as trendsApi } from './api'; -import { selectOverviewState, selectOverviewTrends } from '.'; +import { selectOverviewTrends } from '.'; +import { selectOverviewStatus } from '../overview_status'; const TEST_TRENDS_LENGTH = 80; @@ -78,8 +79,8 @@ describe('overview effects', () => { }); it('selects the overview state', (selectResult) => { - expect(selectResult).toEqual(select(selectOverviewState)); - return { data: { monitors: [] } }; + expect(selectResult).toEqual(select(selectOverviewStatus)); + return { allConfigs: {} }; }); it('skips the API if the data is null', (result) => { @@ -162,13 +163,11 @@ describe('overview effects', () => { }); it('selects the overview state', (selectResults) => { - expect(selectResults).toEqual(select(selectOverviewState)); + expect(selectResults).toEqual(select(selectOverviewStatus)); return { - data: { - monitors: [ - { configId: 'monitor1', schedule: '3' }, - { configId: 'monitor3', schedule: '3' }, - ], + allConfigs: { + monitor1: { configId: 'monitor1', schedule: '3' }, + monitor3: { configId: 'monitor3', schedule: '3' }, }, }; }); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.ts index 591527435afb8..119bf217599cf 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/effects.ts @@ -5,30 +5,12 @@ * 2.0. */ -import { debounce, call, takeLeading, takeEvery, put, select } from 'redux-saga/effects'; +import { call, takeLeading, takeEvery, put, select } from 'redux-saga/effects'; +import { OverviewStatusStateReducer, selectOverviewStatus } from '../overview_status'; import type { OverviewTrend, TrendTable } from '../../../../../common/types'; -import { fetchEffectFactory } from '../utils/fetch_effect'; -import { selectOverviewState, selectOverviewTrends } from './selectors'; -import { - fetchMonitorOverviewAction, - quietFetchOverviewAction, - refreshOverviewTrends, - trendStatsBatch, -} from './actions'; -import { fetchMonitorOverview, fetchOverviewTrendStats as trendsApi } from './api'; -import { MonitorOverviewState } from '.'; - -export function* fetchMonitorOverviewEffect() { - yield debounce( - 200, // Only take the latest while ignoring any intermediate triggers - [fetchMonitorOverviewAction.get, quietFetchOverviewAction.get], - fetchEffectFactory( - fetchMonitorOverview, - fetchMonitorOverviewAction.success, - fetchMonitorOverviewAction.fail - ) - ); -} +import { selectOverviewTrends } from './selectors'; +import { refreshOverviewTrends, trendStatsBatch } from './actions'; +import { fetchOverviewTrendStats as trendsApi } from './api'; export const TRENDS_CHUNK_SIZE = 50; @@ -55,7 +37,9 @@ export function* fetchOverviewTrendStats() { export function* refreshTrends(): Generator { const existingTrends: TrendTable = yield select(selectOverviewTrends); - const overviewState: MonitorOverviewState = yield select(selectOverviewState); + const { allConfigs }: OverviewStatusStateReducer = yield select(selectOverviewStatus); + + const monitorConfigs = Object.values(allConfigs ?? {}); const keys = Object.keys(existingTrends); while (keys.length) { @@ -65,7 +49,7 @@ export function* refreshTrends(): Generator { (key: string) => existingTrends[key] !== null && existingTrends[key] !== 'loading' && - overviewState.data.monitors.some( + monitorConfigs.some( ({ configId }) => configId === (existingTrends[key] as OverviewTrend)!.configId ) ) @@ -74,8 +58,7 @@ export function* refreshTrends(): Generator { return { configId: trend.configId, locationId: trend.locationId, - schedule: overviewState.data.monitors.find(({ configId }) => configId === trend.configId)! - .schedule, + schedule: monitorConfigs.find(({ configId }) => configId === trend.configId)!.schedule, }; }); if (chunk.length) { diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/index.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/index.ts index fef85b1cbeb9d..6d0a07f16aed6 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/index.ts @@ -6,27 +6,17 @@ */ import { createReducer } from '@reduxjs/toolkit'; -import { isStatusEnabled } from '../../../../../common/runtime_types/monitor_management/alert_config'; import { MonitorOverviewState } from './models'; import { - fetchMonitorOverviewAction, - quietFetchOverviewAction, setFlyoutConfig, setOverviewGroupByAction, setOverviewPageStateAction, toggleErrorPopoverOpen, trendStatsBatch, } from './actions'; -import { enableMonitorAlertAction } from '../monitor_list/actions'; -import { ConfigKey } from '../../components/monitor_add_edit/types'; const initialState: MonitorOverviewState = { - data: { - total: 0, - allMonitorIds: [], - monitors: [], - }, pageState: { perPage: 16, sortOrder: 'asc', @@ -35,36 +25,16 @@ const initialState: MonitorOverviewState = { trendStats: {}, groupBy: { field: 'none', order: 'asc' }, flyoutConfig: null, - loading: false, - loaded: false, - error: null, isErrorPopoverOpen: null, }; export const monitorOverviewReducer = createReducer(initialState, (builder) => { builder - .addCase(fetchMonitorOverviewAction.get, (state, action) => { - state.loading = true; - state.loaded = false; - }) - .addCase(quietFetchOverviewAction.get, (state, action) => { - state.loading = true; - }) - .addCase(fetchMonitorOverviewAction.success, (state, action) => { - state.data = action.payload; - state.loading = false; - state.loaded = true; - }) - .addCase(fetchMonitorOverviewAction.fail, (state, action) => { - state.loading = false; - state.error = action.payload; - }) .addCase(setOverviewPageStateAction, (state, action) => { state.pageState = { ...state.pageState, ...action.payload, }; - state.loaded = false; }) .addCase(setOverviewGroupByAction, (state, action) => { state.groupBy = { @@ -75,24 +45,7 @@ export const monitorOverviewReducer = createReducer(initialState, (builder) => { .addCase(setFlyoutConfig, (state, action) => { state.flyoutConfig = action.payload; }) - .addCase(enableMonitorAlertAction.success, (state, action) => { - const monitorObject = action.payload; - if (!('errors' in monitorObject)) { - const isStatusAlertEnabled = isStatusEnabled(monitorObject[ConfigKey.ALERT_CONFIG]); - state.data.monitors = state.data.monitors.map((monitor) => { - if ( - monitor.id === monitorObject[ConfigKey.CONFIG_ID] || - monitor.id === monitorObject[ConfigKey.MONITOR_QUERY_ID] - ) { - return { - ...monitor, - isStatusAlertEnabled, - }; - } - return monitor; - }); - } - }) + .addCase(toggleErrorPopoverOpen, (state, action) => { state.isErrorPopoverOpen = action.payload; }) @@ -124,6 +77,4 @@ export const monitorOverviewReducer = createReducer(initialState, (builder) => { export * from './models'; export * from './actions'; -export * from './effects'; export * from './selectors'; -export { fetchMonitorOverview } from './api'; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/models.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/models.ts index 0dbc2100c2fee..132167a3631d7 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/models.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/models.ts @@ -7,9 +7,8 @@ import type { TrendTable } from '../../../../../common/types'; import type { MonitorListSortField } from '../../../../../common/runtime_types/monitor_management/sort_field'; -import { ConfigKey, MonitorOverviewResult } from '../../../../../common/runtime_types'; +import { ConfigKey } from '../../../../../common/runtime_types'; -import { IHttpSerializedFetchError } from '../utils/http_error'; import { MonitorFilterState } from '../monitor_list'; export interface MonitorOverviewPageState extends MonitorFilterState { @@ -27,12 +26,8 @@ export type MonitorOverviewFlyoutConfig = { export interface MonitorOverviewState { flyoutConfig: MonitorOverviewFlyoutConfig; - data: MonitorOverviewResult; pageState: MonitorOverviewPageState; - loading: boolean; - loaded: boolean; isErrorPopoverOpen?: string | null; - error: IHttpSerializedFetchError | null; groupBy: GroupByState; trendStats: TrendTable; } diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/selectors.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/selectors.ts index 98286a3da118f..657d273c2d29c 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/selectors.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview/selectors.ts @@ -11,7 +11,6 @@ import { SyntheticsAppState } from '../root_reducer'; export const selectOverviewState = (state: SyntheticsAppState) => state.overview; export const selectOverviewPageState = (state: SyntheticsAppState) => state.overview.pageState; -export const selectOverviewDataState = createSelector(selectOverviewState, (state) => state.data); export const selectErrorPopoverState = createSelector( selectOverviewState, (state) => state.isErrorPopoverOpen diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/api.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/api.ts index 84fc548a64878..9ebbd8d67fc01 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/api.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/api.ts @@ -7,9 +7,27 @@ import { MonitorOverviewPageState } from '..'; import { SYNTHETICS_API_URLS } from '../../../../../common/constants'; -import { OverviewStatus, OverviewStatusCodec } from '../../../../../common/runtime_types'; +import { + FetchMonitorOverviewQueryArgs, + OverviewStatus, + OverviewStatusCodec, +} from '../../../../../common/runtime_types'; import { apiService } from '../../../../utils/api_service'; -import { toStatusOverviewQueryArgs } from '../overview/api'; + +export function toStatusOverviewQueryArgs( + pageState: MonitorOverviewPageState +): FetchMonitorOverviewQueryArgs { + return { + query: pageState.query, + tags: pageState.tags, + locations: pageState.locations, + projects: pageState.projects, + schedules: pageState.schedules, + monitorTypes: pageState.monitorTypes, + monitorQueryIds: pageState.monitorQueryIds, + searchFields: [], + }; +} export const fetchOverviewStatus = async ({ pageState, diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/index.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/index.ts index 69b735302ee75..6d00d5929fef1 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/index.ts @@ -7,7 +7,13 @@ import { createReducer } from '@reduxjs/toolkit'; -import { OverviewStatusState } from '../../../../../common/runtime_types'; +import { enableMonitorAlertAction } from '../monitor_list/actions'; +import { isStatusEnabled } from '../../../../../common/runtime_types/monitor_management/alert_config'; +import { + ConfigKey, + OverviewStatusMetaData, + OverviewStatusState, +} from '../../../../../common/runtime_types'; import { IHttpSerializedFetchError } from '..'; import { clearOverviewStatusErrorAction, @@ -19,6 +25,9 @@ export interface OverviewStatusStateReducer { loading: boolean; loaded: boolean; status: OverviewStatusState | null; + allConfigs?: OverviewStatusMetaData[]; + disabledConfigs?: OverviewStatusMetaData[]; + sortedByStatus?: OverviewStatusMetaData[]; error: IHttpSerializedFetchError | null; } @@ -39,10 +48,13 @@ export const overviewStatusReducer = createReducer(initialState, (builder) => { state.loading = true; }) .addCase(fetchOverviewStatusAction.success, (state, action) => { - state.status = { - ...action.payload, - allConfigs: { ...action.payload.upConfigs, ...action.payload.downConfigs }, - }; + state.status = action.payload; + state.allConfigs = Object.values({ + ...action.payload.upConfigs, + ...action.payload.downConfigs, + ...action.payload.pendingConfigs, + }); + state.disabledConfigs = state.allConfigs.filter((monitor) => !monitor.isEnabled); state.loaded = true; state.loading = false; }) @@ -50,6 +62,24 @@ export const overviewStatusReducer = createReducer(initialState, (builder) => { state.error = action.payload; state.loading = false; }) + .addCase(enableMonitorAlertAction.success, (state, action) => { + const monitorObject = action.payload; + if (!('errors' in monitorObject)) { + const isStatusAlertEnabled = isStatusEnabled(monitorObject[ConfigKey.ALERT_CONFIG]); + state.allConfigs = state.allConfigs?.map((monitor) => { + if ( + monitor.configId === monitorObject[ConfigKey.CONFIG_ID] || + monitor.monitorQueryId === monitorObject[ConfigKey.MONITOR_QUERY_ID] + ) { + return { + ...monitor, + isStatusAlertEnabled, + }; + } + return monitor; + }); + } + }) .addCase(clearOverviewStatusErrorAction, (state) => { state.error = null; }); diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/selectors.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/selectors.ts index c23eed413d107..a81da97916f72 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/selectors.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/overview_status/selectors.ts @@ -7,6 +7,4 @@ import { SyntheticsAppState } from '../root_reducer'; -export const selectOverviewStatus = ({ - overviewStatus: { status, error, loaded, loading }, -}: SyntheticsAppState) => ({ status, error, loaded, loading }); +export const selectOverviewStatus = ({ overviewStatus }: SyntheticsAppState) => overviewStatus; diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts index 80a3144aef511..1a565fe772aa6 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/state/root_effect.ts @@ -33,15 +33,12 @@ import { upsertMonitorEffect, fetchMonitorFiltersEffect, } from './monitor_list'; -import { - fetchMonitorOverviewEffect, - fetchOverviewTrendStats, - refreshOverviewTrendStats, -} from './overview'; + import { fetchServiceLocationsEffect } from './service_locations'; import { browserJourneyEffects, fetchJourneyStepsEffect } from './browser_journey'; import { fetchOverviewStatusEffect } from './overview_status'; import { fetchMonitorStatusHeatmap, quietFetchMonitorStatusHeatmap } from './status_heatmap'; +import { fetchOverviewTrendStats, refreshOverviewTrendStats } from './overview/effects'; export const rootEffect = function* root(): Generator { yield all([ @@ -51,7 +48,6 @@ export const rootEffect = function* root(): Generator { fork(fetchServiceLocationsEffect), fork(fetchMonitorListEffect), fork(fetchSyntheticsMonitorEffect), - fork(fetchMonitorOverviewEffect), fork(browserJourneyEffects), fork(fetchOverviewStatusEffect), fork(fetchNetworkEventsEffect), diff --git a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts index aa52c54c21b78..2849fa1628924 100644 --- a/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts +++ b/x-pack/plugins/observability_solution/synthetics/public/apps/synthetics/utils/testing/__mocks__/synthetics_store.mock.ts @@ -99,14 +99,6 @@ export const mockState: SyntheticsAppState = { sortField: 'name.keyword', }, trendStats: {}, - data: { - total: 0, - allMonitorIds: [], - monitors: [], - }, - error: null, - loaded: false, - loading: false, flyoutConfig: null, groupBy: { field: 'none', diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts index 47221ff7020d5..787d35c99b675 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.test.ts @@ -6,8 +6,11 @@ */ import { IBasePath } from '@kbn/core/server'; import { updateState, setRecoveredAlertsContext } from './common'; -import { SyntheticsCommonState } from '../../common/runtime_types/alert_rules/common'; -import { StaleDownConfig } from './status_rule/status_rule_executor'; +import { + AlertOverviewStatus, + StaleDownConfig, + SyntheticsCommonState, +} from '../../common/runtime_types/alert_rules/common'; const dateFormat = 'MMM D, YYYY @ HH:mm:ss.SSS'; @@ -193,7 +196,7 @@ describe('setRecoveredAlertsContext', () => { publicBaseUrl: 'https://localhost:5601', } as IBasePath; - const upConfigs = { + const upConfigs: AlertOverviewStatus['upConfigs'] = { [idWithLocation]: { configId, monitorQueryId: 'stale-config', @@ -237,7 +240,7 @@ describe('setRecoveredAlertsContext', () => { setAlertData: jest.fn(), isTrackedAlert: jest.fn(), }; - const staleDownConfigs = { + const staleDownConfigs: Record = { [idWithLocation]: { configId, monitorQueryId: 'stale-config', @@ -311,7 +314,7 @@ describe('setRecoveredAlertsContext', () => { setAlertData: jest.fn(), isTrackedAlert: jest.fn(), }; - const staleDownConfigs = { + const staleDownConfigs: Record = { [idWithLocation]: { configId, monitorQueryId: 'stale-config', @@ -385,7 +388,7 @@ describe('setRecoveredAlertsContext', () => { setAlertData: jest.fn(), isTrackedAlert: jest.fn(), }; - const staleDownConfigs = { + const staleDownConfigs: Record = { [idWithLocation]: { configId, monitorQueryId: 'stale-config', diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts index 20c84109b0be1..27f051ff2e9c9 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/common.ts @@ -31,12 +31,12 @@ import { StatusCheckFilters } from '../../common/runtime_types'; import { SyntheticsEsClient } from '../lib'; import { getMonitorSummary } from './status_rule/message_utils'; import { + AlertOverviewStatus, SyntheticsCommonState, SyntheticsCommonStateCodec, } from '../../common/runtime_types/alert_rules/common'; import { getSyntheticsErrorRouteFromMonitorId } from '../../common/utils/get_synthetics_monitor_url'; import { ALERT_DETAILS_URL, RECOVERY_REASON } from './action_variables'; -import { AlertOverviewStatus } from './status_rule/status_rule_executor'; import type { MonitorSummaryStatusRule } from './status_rule/types'; export const updateState = ( diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts index c823abe7d083f..3ca5aeb94af58 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/monitor_status_rule.ts @@ -20,10 +20,10 @@ import { syntheticsRuleFieldMap } from '../../../common/rules/synthetics_rule_fi import { SyntheticsPluginsSetupDependencies, SyntheticsServerSetup } from '../../types'; import { DOWN_LABEL, getMonitorAlertDocument, getMonitorSummary } from './message_utils'; import { + AlertOverviewStatus, SyntheticsCommonState, SyntheticsMonitorStatusAlertState, } from '../../../common/runtime_types/alert_rules/common'; -import { OverviewStatus } from '../../../common/runtime_types'; import { StatusRuleExecutor } from './status_rule_executor'; import { StatusRulePramsSchema, StatusRuleParams } from '../../../common/rules/status_rule'; import { @@ -105,7 +105,7 @@ export const registerSyntheticsStatusCheckRule = ( ); const { downConfigs, staleDownConfigs, upConfigs } = await statusRule.getDownChecks( - ruleState.meta?.downConfigs as OverviewStatus['downConfigs'] + ruleState.meta?.downConfigs as AlertOverviewStatus['downConfigs'] ); Object.entries(downConfigs).forEach(([idWithLocation, { ping, configId }]) => { diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/query_monitor_status_alert.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/query_monitor_status_alert.ts index 1433c45d1becf..9c8e2fa1fa21b 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/query_monitor_status_alert.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/query_monitor_status_alert.ts @@ -9,13 +9,13 @@ import pMap from 'p-map'; import times from 'lodash/times'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { cloneDeep, intersection } from 'lodash'; -import { createEsParams, SyntheticsEsClient } from '../../lib'; import { - OverviewPendingStatusMetaData, - OverviewPing, - OverviewStatus, - OverviewStatusMetaData, -} from '../../../common/runtime_types'; + AlertOverviewStatus, + AlertPendingStatusMetaData, + AlertStatusMetaData, +} from '../../../common/runtime_types/alert_rules/common'; +import { createEsParams, SyntheticsEsClient } from '../../lib'; +import { OverviewPing } from '../../../common/runtime_types'; import { FINAL_SUMMARY_FILTER } from '../../../common/constants/client_defaults'; const DEFAULT_MAX_ES_BUCKET_SIZE = 10000; @@ -40,25 +40,15 @@ export async function queryMonitorStatusForAlert( monitorQueryIds: string[], monitorLocationsMap: Record, monitorQueryIdToConfigIdMap: Record -): Promise< - Omit< - OverviewStatus, - | 'disabledCount' - | 'allMonitorsCount' - | 'disabledMonitorsCount' - | 'projectMonitorsCount' - | 'disabledMonitorQueryIds' - | 'allIds' - > -> { +): Promise { const idSize = Math.trunc(DEFAULT_MAX_ES_BUCKET_SIZE / monitorLocationIds.length || 1); const pageCount = Math.ceil(monitorQueryIds.length / idSize); let up = 0; let down = 0; - const upConfigs: Record = {}; - const downConfigs: Record = {}; + const upConfigs: Record = {}; + const downConfigs: Record = {}; const monitorsWithoutData = new Map(Object.entries(cloneDeep(monitorLocationsMap))); - const pendingConfigs: Record = {}; + const pendingConfigs: Record = {}; await pMap( times(pageCount), @@ -214,5 +204,6 @@ export async function queryMonitorStatusForAlert( downConfigs, pendingConfigs, enabledMonitorQueryIds: monitorQueryIds, + staleDownConfigs: {}, }; } diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts index c947c0db131eb..691176fad6e74 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/status_rule/status_rule_executor.ts @@ -10,6 +10,7 @@ import { SavedObjectsFindResult, } from '@kbn/core-saved-objects-api-server'; import { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { AlertOverviewStatus } from '../../../common/runtime_types/alert_rules/common'; import { queryMonitorStatusForAlert } from './query_monitor_status_alert'; import { SyntheticsServerSetup } from '../../types'; import { SyntheticsEsClient } from '../../lib'; @@ -19,26 +20,11 @@ import { processMonitors, } from '../../saved_objects/synthetics_monitor/get_all_monitors'; import { StatusRuleParams } from '../../../common/rules/status_rule'; -import { - ConfigKey, - EncryptedSyntheticsMonitorAttributes, - OverviewStatus, - OverviewStatusMetaData, -} from '../../../common/runtime_types'; +import { ConfigKey, EncryptedSyntheticsMonitorAttributes } from '../../../common/runtime_types'; import { SyntheticsMonitorClient } from '../../synthetics_service/synthetics_monitor/synthetics_monitor_client'; import { monitorAttributes } from '../../../common/types/saved_objects'; import { AlertConfigKey } from '../../../common/constants/monitor_management'; -export interface StaleDownConfig extends OverviewStatusMetaData { - isDeleted?: boolean; - isLocationRemoved?: boolean; -} - -export interface AlertOverviewStatus - extends Omit { - staleDownConfigs: Record; -} - export class StatusRuleExecutor { previousStartedAt: Date | null; params: StatusRuleParams; @@ -76,7 +62,7 @@ export class StatusRuleExecutor { allIds, enabledMonitorQueryIds, monitorLocationIds, - monitorLocationMap, + monitorLocationsMap, projectMonitorsCount, monitorQueryIdToConfigIdMap, } = processMonitors(this.monitors); @@ -85,21 +71,19 @@ export class StatusRuleExecutor { enabledMonitorQueryIds, monitorLocationIds, allIds, - monitorLocationMap, + monitorLocationsMap, projectMonitorsCount, monitorQueryIdToConfigIdMap, }; } async getDownChecks( - prevDownConfigs: OverviewStatus['downConfigs'] = {} + prevDownConfigs: AlertOverviewStatus['downConfigs'] = {} ): Promise { const { monitorLocationIds, enabledMonitorQueryIds, - allIds, - monitorLocationMap, - projectMonitorsCount, + monitorLocationsMap, monitorQueryIdToConfigIdMap, } = await this.getMonitors(); const from = this.previousStartedAt @@ -115,7 +99,7 @@ export class StatusRuleExecutor { from, }, enabledMonitorQueryIds, - monitorLocationMap, + monitorLocationsMap, monitorQueryIdToConfigIdMap ); @@ -133,10 +117,6 @@ export class StatusRuleExecutor { return { ...currentStatus, staleDownConfigs, - projectMonitorsCount, - allMonitorsCount: allIds.length, - disabledMonitorsCount: allIds.length - enabledMonitorQueryIds.length, - allIds, }; } const staleDownConfigs = this.markDeletedConfigs(prevDownConfigs); @@ -149,14 +129,10 @@ export class StatusRuleExecutor { up: 0, pending: 0, enabledMonitorQueryIds, - allMonitorsCount: allIds.length, - disabledMonitorsCount: allIds.length, - projectMonitorsCount, - allIds, }; } - markDeletedConfigs(downConfigs: OverviewStatus['downConfigs']) { + markDeletedConfigs(downConfigs: AlertOverviewStatus['downConfigs']) { const monitors = this.monitors; const staleDownConfigs: AlertOverviewStatus['staleDownConfigs'] = {}; Object.keys(downConfigs).forEach((locPlusId) => { diff --git a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts index 4c5766b34738f..2ed465257d0c6 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/alert_rules/tls_rule/tls_rule_executor.ts @@ -71,7 +71,7 @@ export class TLSRuleExecutor { allIds, enabledMonitorQueryIds, monitorLocationIds, - monitorLocationMap, + monitorLocationsMap, projectMonitorsCount, monitorQueryIdToConfigIdMap, } = processMonitors(this.monitors); @@ -80,7 +80,7 @@ export class TLSRuleExecutor { enabledMonitorQueryIds, monitorLocationIds, allIds, - monitorLocationMap, + monitorLocationsMap, projectMonitorsCount, monitorQueryIdToConfigIdMap, }; diff --git a/x-pack/plugins/observability_solution/synthetics/server/lib.ts b/x-pack/plugins/observability_solution/synthetics/server/lib.ts index 7aff6a6ab08e0..22f5661ca532f 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/lib.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/lib.ts @@ -166,7 +166,7 @@ export class SyntheticsEsClient { } return { - responses: res.body.responses as unknown as Array< + responses: res.body?.responses as unknown as Array< InferSearchResponseOf >, }; diff --git a/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts b/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts index e2302ed638102..4c3072ffce50f 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/queries/query_monitor_status.ts @@ -8,10 +8,14 @@ import times from 'lodash/times'; import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; import { cloneDeep, intersection } from 'lodash'; +import { SavedObjectsFindResult } from '@kbn/core-saved-objects-api-server'; import { MsearchMultisearchBody } from '@elastic/elasticsearch/lib/api/types'; + +import { isStatusEnabled } from '../../common/runtime_types/monitor_management/alert_config'; import { FINAL_SUMMARY_FILTER } from '../../common/constants/client_defaults'; import { - OverviewPendingStatusMetaData, + ConfigKey, + EncryptedSyntheticsMonitorAttributes, OverviewPing, OverviewStatus, OverviewStatusMetaData, @@ -34,17 +38,15 @@ const fields = [ ]; const getStatusQuery = ({ + idSize, idsToQuery, range, monitorLocationIds, - idSize, }: { idSize: number; monitorLocationIds: string[]; range: { from: string; to: string }; idsToQuery: string[]; - monitorLocationsMap: Record; - monitorQueryIdToConfigIdMap: Record; }) => { const params = createEsParams({ body: { @@ -126,14 +128,23 @@ type OverviewStatusResponse = Omit< | 'allIds' >; -export async function queryMonitorStatus( - esClient: SyntheticsEsClient, - monitorLocationIds: string[], - range: { from: string; to: string }, - monitorQueryIds: string[], - monitorLocationsMap: Record, - monitorQueryIdToConfigIdMap: Record -): Promise { +export async function queryMonitorStatus({ + esClient, + monitorLocationIds, + range, + monitorQueryIds, + monitorLocationsMap, + monitorQueryIdToConfigIdMap, + monitors, +}: { + esClient: SyntheticsEsClient; + monitorLocationIds: string[]; + range: { from: string; to: string }; + monitorQueryIds: string[]; + monitorLocationsMap: Record; + monitorQueryIdToConfigIdMap: Record; + monitors: Array>; +}): Promise { const idSize = Math.trunc(DEFAULT_MAX_ES_BUCKET_SIZE / monitorLocationIds.length || 1); const pageCount = Math.ceil(monitorQueryIds.length / idSize); let up = 0; @@ -141,7 +152,7 @@ export async function queryMonitorStatus( const upConfigs: Record = {}; const downConfigs: Record = {}; const monitorsWithoutData = new Map(Object.entries(cloneDeep(monitorLocationsMap))); - const pendingConfigs: Record = {}; + const pendingConfigs: Record = {}; const queries: MsearchMultisearchBody[] = times(pageCount).map((i) => { const idsToQuery = (monitorQueryIds as string[]).slice(i * idSize, i * idSize + idSize); @@ -150,8 +161,6 @@ export async function queryMonitorStatus( monitorLocationIds, range, idsToQuery, - monitorLocationsMap, - monitorQueryIdToConfigIdMap, }).body; }); @@ -167,6 +176,8 @@ export async function queryMonitorStatus( return { location: locationName, ping }; }); + const monitor = monitors.find((m) => m.attributes[ConfigKey.MONITOR_QUERY_ID] === queryId)!; + // discard any locations that are not in the monitorLocationsMap for the given monitor as well as those which are // in monitorLocationsMap but not in listOfLocations const monLocations = monitorLocationsMap?.[queryId]; @@ -189,6 +200,15 @@ export async function queryMonitorStatus( monitorQueryId, locationId: monLocation, timestamp: ping['@timestamp'], + locationLabel: ping.observer.geo!.name!, + name: monitor.attributes[ConfigKey.NAME], + schedule: monitor.attributes[ConfigKey.SCHEDULE].number, + tags: monitor.attributes[ConfigKey.TAGS], + isEnabled: monitor.attributes[ConfigKey.ENABLED], + type: monitor.attributes[ConfigKey.MONITOR_TYPE], + projectId: monitor.attributes[ConfigKey.PROJECT_ID], + isStatusAlertEnabled: isStatusEnabled(monitor.attributes[ConfigKey.ALERT_CONFIG]), + updated_at: monitor.updated_at, }; if (downCount > 0) { @@ -219,12 +239,24 @@ export async function queryMonitorStatus( // identify the remaining monitors without data, to determine pending monitors for (const [queryId, locs] of monitorsWithoutData) { + const monitor = monitors.find((m) => m.attributes[ConfigKey.MONITOR_QUERY_ID] === queryId)!; locs.forEach((loc) => { pendingConfigs[`${monitorQueryIdToConfigIdMap[queryId]}-${loc}`] = { configId: `${monitorQueryIdToConfigIdMap[queryId]}`, monitorQueryId: queryId, status: 'unknown', locationId: loc, + locationLabel: monitor.attributes[ConfigKey.LOCATIONS]?.find( + (location) => location.id === loc + )?.label!, + name: monitor.attributes[ConfigKey.NAME], + schedule: monitor.attributes[ConfigKey.SCHEDULE].number, + tags: monitor.attributes[ConfigKey.TAGS], + isEnabled: monitor.attributes[ConfigKey.ENABLED], + type: monitor.attributes[ConfigKey.MONITOR_TYPE], + projectId: monitor.attributes[ConfigKey.PROJECT_ID], + isStatusAlertEnabled: isStatusEnabled(monitor.attributes[ConfigKey.ALERT_CONFIG]), + updated_at: monitor.updated_at, }; }); } diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts index 8e62964c2d833..75aaf9f49c4d3 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/index.ts @@ -33,10 +33,7 @@ import { disableSyntheticsRoute, getSyntheticsEnablementRoute, } from './synthetics_service/enablement'; -import { - getSyntheticsMonitorOverviewRoute, - getSyntheticsMonitorRoute, -} from './monitor_cruds/get_monitor'; +import { getSyntheticsMonitorRoute } from './monitor_cruds/get_monitor'; import { deleteSyntheticsMonitorProjectRoute } from './monitor_cruds/delete_monitor_project'; import { getSyntheticsProjectMonitorsRoute } from './monitor_cruds/get_monitor_project'; import { runOnceSyntheticsMonitorRoute } from './synthetics_service/run_once_monitor'; @@ -70,7 +67,6 @@ export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ getServiceLocationsRoute, getSyntheticsProjectMonitorsRoute, getAllSyntheticsMonitorRoute, - getSyntheticsMonitorOverviewRoute, installIndexTemplatesRoute, runOnceSyntheticsMonitorRoute, testNowMonitorRoute, diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/get_monitor.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/get_monitor.ts index e7623da98cfb4..69e7491a86b2b 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/get_monitor.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/monitor_cruds/get_monitor.ts @@ -7,17 +7,11 @@ import { schema } from '@kbn/config-schema'; import { SavedObjectsErrorHelpers } from '@kbn/core/server'; import { SyntheticsRestApiRouteFactory } from '../types'; -import { getAllMonitors } from '../../saved_objects/synthetics_monitor/get_all_monitors'; import { syntheticsMonitorType } from '../../../common/types/saved_objects'; import { isStatusEnabled } from '../../../common/runtime_types/monitor_management/alert_config'; -import { - ConfigKey, - EncryptedSyntheticsMonitorAttributes, - MonitorOverviewItem, -} from '../../../common/runtime_types'; +import { ConfigKey, EncryptedSyntheticsMonitorAttributes } from '../../../common/runtime_types'; import { SYNTHETICS_API_URLS } from '../../../common/constants'; import { getMonitorNotFoundResponse } from '../synthetics_service/service_errors'; -import { getMonitorFilters, MonitorsQuery, QuerySchema, SEARCH_FIELDS } from '../common'; import { mapSavedObjectToMonitor } from './helper'; import { getSyntheticsMonitor } from '../../queries/get_monitor'; @@ -82,57 +76,6 @@ export const getSyntheticsMonitorRoute: SyntheticsRestApiRouteFactory = () => ({ }, }); -export const getSyntheticsMonitorOverviewRoute: SyntheticsRestApiRouteFactory = () => ({ - method: 'GET', - path: SYNTHETICS_API_URLS.SYNTHETICS_OVERVIEW, - validate: { - query: QuerySchema, - }, - handler: async (routeContext): Promise => { - const { request, savedObjectsClient } = routeContext; - - const { - sortField, - sortOrder, - query, - locations: queriedLocations, - } = request.query as MonitorsQuery; - - const { filtersStr } = await getMonitorFilters({ - ...request.query, - context: routeContext, - }); - - const allMonitorConfigs = await getAllMonitors({ - sortOrder, - filter: filtersStr, - soClient: savedObjectsClient, - sortField: sortField === 'status' ? `${ConfigKey.NAME}.keyword` : sortField, - search: query ? `${query}*` : undefined, - searchFields: SEARCH_FIELDS, - }); - - const allMonitorIds: string[] = []; - let total = 0; - const allMonitors: MonitorOverviewItem[] = []; - - for (const { attributes } of allMonitorConfigs) { - const configId = attributes[ConfigKey.CONFIG_ID]; - allMonitorIds.push(configId); - - const monitorConfigsPerLocation = getOverviewConfigsPerLocation(attributes, queriedLocations); - allMonitors.push(...monitorConfigsPerLocation); - total += monitorConfigsPerLocation.length; - } - - return { - monitors: allMonitors, - total, - allMonitorIds, - }; - }, -}); - export function getOverviewConfigsPerLocation( attributes: EncryptedSyntheticsMonitorAttributes, queriedLocations?: string | string[] diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts index cca1e8141f3c9..084070fd95595 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.test.ts @@ -105,6 +105,37 @@ describe('current status route', () => { }); }); + const testMonitors = [ + { + attributes: { + id: 'id1', + type: 'browser', + enabled: true, + name: 'test monitor 1', + project_id: 'project-id', + tags: ['tag-1', 'tag-2'], + schedule: { + number: '1', + unit: 'm', + }, + }, + }, + { + attributes: { + id: 'id2', + enabled: true, + type: 'browser', + name: 'test monitor 2', + project_id: 'project-id', + tags: ['tag-1', 'tag-2'], + schedule: { + number: '1', + unit: 'm', + }, + }, + }, + ]; + describe('queryMonitorStatus', () => { it('parses expected agg fields', async () => { const { esClient, syntheticsEsClient } = getUptimeESMockClient(); @@ -214,52 +245,145 @@ describe('current status route', () => { took: 605, }); expect( - await queryMonitorStatus( - syntheticsEsClient, - ['Europe - Germany', 'Asia/Pacific - Japan'], - { from: 'now-1d', to: 'now' }, - ['id1', 'id2'], - { id1: ['Asia/Pacific - Japan'], id2: ['Europe - Germany', 'Asia/Pacific - Japan'] }, - { + await queryMonitorStatus({ + esClient: syntheticsEsClient, + monitorLocationIds: ['Europe - Germany', 'Asia/Pacific - Japan'], + range: { from: 'now-1d', to: 'now' }, + monitorQueryIds: ['id1', 'id2'], + monitorLocationsMap: { + id1: ['Asia/Pacific - Japan'], + id2: ['Europe - Germany', 'Asia/Pacific - Japan'], + }, + monitorQueryIdToConfigIdMap: { id1: 'id1', id2: 'id2', - } - ) - ).toEqual({ - pending: 0, - down: 1, - enabledMonitorQueryIds: ['id1', 'id2'], - up: 2, - upConfigs: { - 'id1-Asia/Pacific - Japan': { - configId: 'id1', - monitorQueryId: 'id1', - locationId: 'Asia/Pacific - Japan', - status: 'up', - ping: expect.any(Object), - timestamp: expect.any(String), }, - 'id2-Asia/Pacific - Japan': { - configId: 'id2', - monitorQueryId: 'id2', - locationId: 'Asia/Pacific - Japan', - status: 'up', - ping: expect.any(Object), - timestamp: expect.any(String), + monitors: testMonitors as any, + }) + ).toMatchInlineSnapshot(` + Object { + "down": 1, + "downConfigs": Object { + "id2-Europe - Germany": Object { + "configId": "id2", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Europe - Germany", + "locationLabel": "Europe - Germany", + "monitorQueryId": "id2", + "name": "test monitor 2", + "ping": Object { + "@timestamp": "2022-09-15T16:19:16.724Z", + "config_id": "id2", + "monitor": Object { + "id": "id2", + "status": "down", + }, + "observer": Object { + "geo": Object { + "name": "Europe - Germany", + }, + }, + "summary": Object { + "down": 1, + "up": 0, + }, + }, + "projectId": "project-id", + "schedule": "1", + "status": "down", + "tags": Array [ + "tag-1", + "tag-2", + ], + "timestamp": "2022-09-15T16:19:16.724Z", + "type": "browser", + "updated_at": undefined, + }, }, - }, - downConfigs: { - 'id2-Europe - Germany': { - configId: 'id2', - monitorQueryId: 'id2', - locationId: 'Europe - Germany', - status: 'down', - ping: expect.any(Object), - timestamp: expect.any(String), + "enabledMonitorQueryIds": Array [ + "id1", + "id2", + ], + "pending": 0, + "pendingConfigs": Object {}, + "up": 2, + "upConfigs": Object { + "id1-Asia/Pacific - Japan": Object { + "configId": "id1", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Asia/Pacific - Japan", + "locationLabel": "Asia/Pacific - Japan", + "monitorQueryId": "id1", + "name": "test monitor 1", + "ping": Object { + "@timestamp": "2022-09-15T16:08:16.724Z", + "config_id": "id1", + "monitor": Object { + "id": "id1", + "status": "up", + }, + "observer": Object { + "geo": Object { + "name": "Asia/Pacific - Japan", + }, + }, + "summary": Object { + "down": 0, + "up": 1, + }, + }, + "projectId": "project-id", + "schedule": "1", + "status": "up", + "tags": Array [ + "tag-1", + "tag-2", + ], + "timestamp": "2022-09-15T16:08:16.724Z", + "type": "browser", + "updated_at": undefined, + }, + "id2-Asia/Pacific - Japan": Object { + "configId": "id2", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Asia/Pacific - Japan", + "locationLabel": "Asia/Pacific - Japan", + "monitorQueryId": "id2", + "name": "test monitor 2", + "ping": Object { + "@timestamp": "2022-09-15T16:09:16.724Z", + "config_id": "id2", + "monitor": Object { + "id": "id2", + "status": "up", + }, + "observer": Object { + "geo": Object { + "name": "Asia/Pacific - Japan", + }, + }, + "summary": Object { + "down": 0, + "up": 1, + }, + }, + "projectId": "project-id", + "schedule": "1", + "status": "up", + "tags": Array [ + "tag-1", + "tag-2", + ], + "timestamp": "2022-09-15T16:09:16.724Z", + "type": "browser", + "updated_at": undefined, + }, }, - }, - pendingConfigs: {}, - }); + } + `); }); it('handles limits with multiple requests', async () => { @@ -382,52 +506,149 @@ describe('current status route', () => { 'Asia/Pacific - Japan', ]; expect( - await queryMonitorStatus( - syntheticsEsClient, - [...concernedLocations, ...times(9997).map((n) => 'Europe - Germany' + n)], - { from: 'now-24h', to: 'now' }, - ['id1', 'id2'], - { id1: [concernedLocations[0]], id2: [concernedLocations[1], concernedLocations[2]] }, - { + await queryMonitorStatus({ + esClient: syntheticsEsClient, + monitorLocationIds: [ + ...concernedLocations, + ...times(9997).map((n) => 'Europe - Germany' + n), + ], + + range: { from: 'now-24h', to: 'now' }, + monitorQueryIds: ['id1', 'id2'], + monitorLocationsMap: { + id1: [concernedLocations[0]], + id2: [concernedLocations[1], concernedLocations[2]], + }, + monitorQueryIdToConfigIdMap: { id1: 'id1', id2: 'id2', - } - ) - ).toEqual({ - pending: 0, - down: 1, - enabledMonitorQueryIds: ['id1', 'id2'], - up: 2, - upConfigs: { - 'id1-Asia/Pacific - Japan': { - configId: 'id1', - monitorQueryId: 'id1', - locationId: 'Asia/Pacific - Japan', - status: 'up', - ping: expect.any(Object), - timestamp: expect.any(String), }, - 'id2-Asia/Pacific - Japan': { - configId: 'id2', - monitorQueryId: 'id2', - locationId: 'Asia/Pacific - Japan', - status: 'up', - ping: expect.any(Object), - timestamp: expect.any(String), + monitors: testMonitors as any, + }) + ).toMatchInlineSnapshot(` + Object { + "down": 1, + "downConfigs": Object { + "id2-Europe - Germany": Object { + "configId": "id2", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Europe - Germany", + "locationLabel": "Europe - Germany", + "monitorQueryId": "id2", + "name": "test monitor 2", + "ping": Object { + "@timestamp": "2022-09-15T16:19:16.724Z", + "config_id": "id2", + "monitor": Object { + "id": "id2", + "status": "down", + }, + "observer": Object { + "geo": Object { + "name": "Europe - Germany", + }, + }, + "summary": Object { + "down": 1, + "up": 0, + }, + }, + "projectId": "project-id", + "schedule": "1", + "status": "down", + "tags": Array [ + "tag-1", + "tag-2", + ], + "timestamp": "2022-09-15T16:19:16.724Z", + "type": "browser", + "updated_at": undefined, + }, }, - }, - downConfigs: { - 'id2-Europe - Germany': { - configId: 'id2', - monitorQueryId: 'id2', - locationId: 'Europe - Germany', - status: 'down', - ping: expect.any(Object), - timestamp: expect.any(String), + "enabledMonitorQueryIds": Array [ + "id1", + "id2", + ], + "pending": 0, + "pendingConfigs": Object {}, + "up": 2, + "upConfigs": Object { + "id1-Asia/Pacific - Japan": Object { + "configId": "id1", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Asia/Pacific - Japan", + "locationLabel": "Asia/Pacific - Japan", + "monitorQueryId": "id1", + "name": "test monitor 1", + "ping": Object { + "@timestamp": "2022-09-15T16:08:16.724Z", + "config_id": "id1", + "monitor": Object { + "id": "id1", + "status": "up", + }, + "observer": Object { + "geo": Object { + "name": "Asia/Pacific - Japan", + }, + }, + "summary": Object { + "down": 0, + "up": 1, + }, + }, + "projectId": "project-id", + "schedule": "1", + "status": "up", + "tags": Array [ + "tag-1", + "tag-2", + ], + "timestamp": "2022-09-15T16:08:16.724Z", + "type": "browser", + "updated_at": undefined, + }, + "id2-Asia/Pacific - Japan": Object { + "configId": "id2", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Asia/Pacific - Japan", + "locationLabel": "Asia/Pacific - Japan", + "monitorQueryId": "id2", + "name": "test monitor 2", + "ping": Object { + "@timestamp": "2022-09-15T16:09:16.724Z", + "config_id": "id2", + "monitor": Object { + "id": "id2", + "status": "up", + }, + "observer": Object { + "geo": Object { + "name": "Asia/Pacific - Japan", + }, + }, + "summary": Object { + "down": 0, + "up": 1, + }, + }, + "projectId": "project-id", + "schedule": "1", + "status": "up", + "tags": Array [ + "tag-1", + "tag-2", + ], + "timestamp": "2022-09-15T16:09:16.724Z", + "type": "browser", + "updated_at": undefined, + }, }, - }, - pendingConfigs: {}, - }); + } + `); expect(esClient.msearch).toHaveBeenCalledTimes(1); // These assertions are to ensure that we are paginating through the IDs we use for filtering expect( @@ -548,84 +769,254 @@ describe('current status route', () => { took: 605, }); expect( - await queryMonitorStatus( - syntheticsEsClient, - ['Europe - Germany', 'Asia/Pacific - Japan'], - { from: 'now-12h', to: 'now' }, - ['id1', 'id2', 'project-monitor-id', 'id4'], - { + await queryMonitorStatus({ + esClient: syntheticsEsClient, + monitorLocationIds: ['Europe - Germany', 'Asia/Pacific - Japan'], + range: { from: 'now-12h', to: 'now' }, + monitorQueryIds: ['id1', 'id2', 'project-monitor-id', 'id4'], + monitorLocationsMap: { id1: ['Asia/Pacific - Japan'], id2: ['Europe - Germany', 'Asia/Pacific - Japan'], 'project-monitor-id': ['Europe - Germany', 'Asia/Pacific - Japan'], id4: ['Europe - Germany', 'Asia/Pacific - Japan'], }, - { + monitorQueryIdToConfigIdMap: { id1: 'id1', id2: 'id2', 'project-monitor-id': 'id3', id4: 'id4', - } - ) - ).toEqual({ - pending: 4, - down: 1, - enabledMonitorQueryIds: ['id1', 'id2', 'project-monitor-id', 'id4'], - up: 2, - upConfigs: { - 'id1-Asia/Pacific - Japan': { - configId: 'id1', - monitorQueryId: 'id1', - locationId: 'Asia/Pacific - Japan', - status: 'up', - ping: expect.any(Object), - timestamp: expect.any(String), - }, - 'id2-Asia/Pacific - Japan': { - configId: 'id2', - monitorQueryId: 'id2', - locationId: 'Asia/Pacific - Japan', - status: 'up', - ping: expect.any(Object), - timestamp: expect.any(String), }, - }, - downConfigs: { - 'id2-Europe - Germany': { - configId: 'id2', - monitorQueryId: 'id2', - locationId: 'Europe - Germany', - status: 'down', - ping: expect.any(Object), - timestamp: expect.any(String), - }, - }, - pendingConfigs: { - 'id3-Asia/Pacific - Japan': { - configId: 'id3', - locationId: 'Asia/Pacific - Japan', - monitorQueryId: 'project-monitor-id', - status: 'unknown', - }, - 'id3-Europe - Germany': { - configId: 'id3', - locationId: 'Europe - Germany', - monitorQueryId: 'project-monitor-id', - status: 'unknown', + monitors: [ + ...testMonitors, + { + attributes: { + id: 'id4', + enabled: true, + type: 'browser', + name: 'test monitor 4', + project_id: 'project-id', + tags: ['tag-1', 'tag-2'], + schedule: { + number: '1', + unit: 'm', + }, + }, + }, + { + attributes: { + id: 'project-monitor-id', + enabled: true, + type: 'browser', + name: 'test monitor 3', + project_id: 'project-id', + tags: ['tag-1', 'tag-2'], + schedule: { + number: '1', + unit: 'm', + }, + }, + }, + ] as any, + }) + ).toMatchInlineSnapshot(` + Object { + "down": 1, + "downConfigs": Object { + "id2-Europe - Germany": Object { + "configId": "id2", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Europe - Germany", + "locationLabel": "Europe - Germany", + "monitorQueryId": "id2", + "name": "test monitor 2", + "ping": Object { + "@timestamp": "2022-09-15T16:19:16.724Z", + "config_id": "id2", + "monitor": Object { + "id": "id2", + "status": "down", + }, + "observer": Object { + "geo": Object { + "name": "Europe - Germany", + }, + }, + "summary": Object { + "down": 1, + "up": 0, + }, + }, + "projectId": "project-id", + "schedule": "1", + "status": "down", + "tags": Array [ + "tag-1", + "tag-2", + ], + "timestamp": "2022-09-15T16:19:16.724Z", + "type": "browser", + "updated_at": undefined, + }, }, - 'id4-Asia/Pacific - Japan': { - configId: 'id4', - locationId: 'Asia/Pacific - Japan', - monitorQueryId: 'id4', - status: 'unknown', + "enabledMonitorQueryIds": Array [ + "id1", + "id2", + "project-monitor-id", + "id4", + ], + "pending": 4, + "pendingConfigs": Object { + "id3-Asia/Pacific - Japan": Object { + "configId": "id3", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Asia/Pacific - Japan", + "locationLabel": undefined, + "monitorQueryId": "project-monitor-id", + "name": "test monitor 3", + "projectId": "project-id", + "schedule": "1", + "status": "unknown", + "tags": Array [ + "tag-1", + "tag-2", + ], + "type": "browser", + "updated_at": undefined, + }, + "id3-Europe - Germany": Object { + "configId": "id3", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Europe - Germany", + "locationLabel": undefined, + "monitorQueryId": "project-monitor-id", + "name": "test monitor 3", + "projectId": "project-id", + "schedule": "1", + "status": "unknown", + "tags": Array [ + "tag-1", + "tag-2", + ], + "type": "browser", + "updated_at": undefined, + }, + "id4-Asia/Pacific - Japan": Object { + "configId": "id4", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Asia/Pacific - Japan", + "locationLabel": undefined, + "monitorQueryId": "id4", + "name": "test monitor 4", + "projectId": "project-id", + "schedule": "1", + "status": "unknown", + "tags": Array [ + "tag-1", + "tag-2", + ], + "type": "browser", + "updated_at": undefined, + }, + "id4-Europe - Germany": Object { + "configId": "id4", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Europe - Germany", + "locationLabel": undefined, + "monitorQueryId": "id4", + "name": "test monitor 4", + "projectId": "project-id", + "schedule": "1", + "status": "unknown", + "tags": Array [ + "tag-1", + "tag-2", + ], + "type": "browser", + "updated_at": undefined, + }, }, - 'id4-Europe - Germany': { - configId: 'id4', - locationId: 'Europe - Germany', - monitorQueryId: 'id4', - status: 'unknown', + "up": 2, + "upConfigs": Object { + "id1-Asia/Pacific - Japan": Object { + "configId": "id1", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Asia/Pacific - Japan", + "locationLabel": "Asia/Pacific - Japan", + "monitorQueryId": "id1", + "name": "test monitor 1", + "ping": Object { + "@timestamp": "2022-09-15T16:08:16.724Z", + "config_id": "id1", + "monitor": Object { + "id": "id1", + "status": "up", + }, + "observer": Object { + "geo": Object { + "name": "Asia/Pacific - Japan", + }, + }, + "summary": Object { + "down": 0, + "up": 1, + }, + }, + "projectId": "project-id", + "schedule": "1", + "status": "up", + "tags": Array [ + "tag-1", + "tag-2", + ], + "timestamp": "2022-09-15T16:08:16.724Z", + "type": "browser", + "updated_at": undefined, + }, + "id2-Asia/Pacific - Japan": Object { + "configId": "id2", + "isEnabled": true, + "isStatusAlertEnabled": false, + "locationId": "Asia/Pacific - Japan", + "locationLabel": "Asia/Pacific - Japan", + "monitorQueryId": "id2", + "name": "test monitor 2", + "ping": Object { + "@timestamp": "2022-09-15T16:09:16.724Z", + "config_id": "id2", + "monitor": Object { + "id": "id2", + "status": "up", + }, + "observer": Object { + "geo": Object { + "name": "Asia/Pacific - Japan", + }, + }, + "summary": Object { + "down": 0, + "up": 1, + }, + }, + "projectId": "project-id", + "schedule": "1", + "status": "up", + "tags": Array [ + "tag-1", + "tag-2", + ], + "timestamp": "2022-09-15T16:09:16.724Z", + "type": "browser", + "updated_at": undefined, + }, }, - }, - }); + } + `); }); }); diff --git a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.ts b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.ts index d114955fc9213..9fff3710fc6a8 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/routes/overview_status/overview_status.ts @@ -8,7 +8,7 @@ import { intersection } from 'lodash'; import datemath, { Unit } from '@kbn/datemath'; import moment from 'moment'; import { RouteContext, SyntheticsRestApiRouteFactory } from '../types'; -import { ConfigKey } from '../../../common/runtime_types'; +import { ConfigKey, OverviewStatusState } from '../../../common/runtime_types'; import { getAllMonitors, processMonitors, @@ -63,6 +63,10 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue ConfigKey.CONFIG_ID, ConfigKey.SCHEDULE, ConfigKey.MONITOR_SOURCE_TYPE, + ConfigKey.MONITOR_TYPE, + ConfigKey.NAME, + ConfigKey.TAGS, + ConfigKey.PROJECT_ID, ], }); @@ -73,7 +77,7 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue disabledCount, maxPeriod, monitorLocationIds, - monitorLocationMap, + monitorLocationsMap, disabledMonitorsCount, projectMonitorsCount, monitorQueryIdToConfigIdMap, @@ -90,14 +94,15 @@ export async function getStatus(context: RouteContext, params: OverviewStatusQue to: 'now', }; - const { up, down, pending, upConfigs, downConfigs, pendingConfigs } = await queryMonitorStatus( - syntheticsEsClient, - listOfLocationAfterFilter, + const { up, down, pending, upConfigs, downConfigs, pendingConfigs } = await queryMonitorStatus({ range, - enabledMonitorQueryIds, - monitorLocationMap, - monitorQueryIdToConfigIdMap - ); + monitors: allMonitors, + monitorLocationsMap, + monitorQueryIdToConfigIdMap, + esClient: syntheticsEsClient, + monitorLocationIds: listOfLocationAfterFilter, + monitorQueryIds: enabledMonitorQueryIds, + }); return { allIds, @@ -122,7 +127,7 @@ export const createGetCurrentStatusRoute: SyntheticsRestApiRouteFactory = () => validate: { query: OverviewStatusSchema, }, - handler: async (routeContext): Promise => { + handler: async (routeContext): Promise => { const { request } = routeContext; const params = request.query as OverviewStatusQuery; diff --git a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts index 313063662f9d4..a7941befae182 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.test.ts @@ -27,7 +27,7 @@ describe('processMonitors', () => { disabledMonitorQueryIds: ['test-project-id-default'], monitorLocationIds: ['us_central_qa', 'us_central_staging', 'us_central'], maxPeriod: 600000, - monitorLocationMap: { + monitorLocationsMap: { '7f796001-a795-4c0b-afdb-3ce74edea775': [ 'us_central_qa', 'us_central', @@ -63,7 +63,7 @@ describe('processMonitors', () => { disabledMonitorQueryIds: ['test-project-id-default'], monitorLocationIds: ['us_central_qa', 'us_central_staging', 'us_central'], maxPeriod: 600000, - monitorLocationMap: { + monitorLocationsMap: { '7f796001-a795-4c0b-afdb-3ce74edea775': [ 'us_central_qa', 'us_central', @@ -137,7 +137,7 @@ describe('processMonitors', () => { disabledMonitorQueryIds: ['test-project-id-default'], monitorLocationIds: ['us_central_qa', 'us_central_staging', 'us_central'], maxPeriod: 600000, - monitorLocationMap: { + monitorLocationsMap: { '7f796001-a795-4c0b-afdb-3ce74edea775': [ 'us_central_qa', 'us_central', diff --git a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts index e19bc529695ae..e5cafe323a5b6 100644 --- a/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts +++ b/x-pack/plugins/observability_solution/synthetics/server/saved_objects/synthetics_monitor/get_all_monitors.ts @@ -71,7 +71,7 @@ export const processMonitors = ( let projectMonitorsCount = 0; const allIds: string[] = []; let listOfLocationsSet = new Set(); - const monitorLocationMap: Record = {}; + const monitorLocationsMap: Record = {}; const monitorQueryIdToConfigIdMap: Record = {}; for (const monitor of allMonitors) { @@ -97,7 +97,7 @@ export const processMonitors = ( } else { enabledMonitorQueryIds.push(attrs[ConfigKey.MONITOR_QUERY_ID]); - monitorLocationMap[attrs[ConfigKey.MONITOR_QUERY_ID]] = queryLocations + monitorLocationsMap[attrs[ConfigKey.MONITOR_QUERY_ID]] = queryLocations ? intersection(monitorLocations, queryLocations) : monitorLocations; listOfLocationsSet = new Set([...listOfLocationsSet, ...monitorLocations]); @@ -112,7 +112,7 @@ export const processMonitors = ( enabledMonitorQueryIds, disabledMonitorQueryIds, disabledCount, - monitorLocationMap, + monitorLocationsMap, disabledMonitorsCount, projectMonitorsCount, monitorLocationIds: [...listOfLocationsSet], diff --git a/x-pack/test/api_integration/apis/synthetics/get_monitor_overview.ts b/x-pack/test/api_integration/apis/synthetics/get_monitor_overview.ts deleted file mode 100644 index 7f6ba0964dc1c..0000000000000 --- a/x-pack/test/api_integration/apis/synthetics/get_monitor_overview.ts +++ /dev/null @@ -1,211 +0,0 @@ -/* - * 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 { v4 as uuidv4 } from 'uuid'; -import { - ConfigKey, - MonitorFields, - MonitorOverviewItem, - EncryptedSyntheticsSavedMonitor, -} from '@kbn/synthetics-plugin/common/runtime_types'; -import { SYNTHETICS_API_URLS } from '@kbn/synthetics-plugin/common/constants'; -import expect from '@kbn/expect'; -import { FtrProviderContext } from '../../ftr_provider_context'; -import { getFixtureJson } from './helper/get_fixture_json'; -import { LOCAL_LOCATION } from './get_filters'; - -export default function ({ getService }: FtrProviderContext) { - describe('GetMonitorsOverview', function () { - this.tags('skipCloud'); - - const supertest = getService('supertest'); - const kibanaServer = getService('kibanaServer'); - const security = getService('security'); - - const username = 'admin'; - const roleName = `synthetics_admin`; - const password = `${username}-password`; - const SPACE_ID = `test-space-${uuidv4()}`; - const SPACE_NAME = `test-space-name ${uuidv4()}`; - - let _monitors: MonitorFields[]; - let monitors: MonitorFields[]; - - const deleteMonitor = async (id: string) => { - try { - await supertest - .delete(`/s/${SPACE_ID}${SYNTHETICS_API_URLS.SYNTHETICS_MONITORS}`) - .set('kbn-xsrf', 'true') - .send({ - ids: [id], - }) - .expect(200); - } catch (e) { - // eslint-disable-next-line no-console - console.error(e); - } - }; - - const saveMonitor = async (monitor: MonitorFields) => { - const res = await supertest - .post(`/s/${SPACE_ID}${SYNTHETICS_API_URLS.SYNTHETICS_MONITORS}`) - .set('kbn-xsrf', 'true') - .send(monitor); - - expect(res.status).eql(200, JSON.stringify(res.body)); - - return res.body as EncryptedSyntheticsSavedMonitor; - }; - - before(async () => { - await supertest - .put(SYNTHETICS_API_URLS.SYNTHETICS_ENABLEMENT) - .set('kbn-xsrf', 'true') - .expect(200); - await kibanaServer.spaces.create({ id: SPACE_ID, name: SPACE_NAME }); - await security.role.create(roleName, { - kibana: [ - { - feature: { - uptime: ['all'], - }, - spaces: ['*'], - }, - ], - }); - await security.user.create(username, { - password, - roles: [roleName], - full_name: 'a kibana user', - }); - - await kibanaServer.savedObjects.cleanStandardList(); - - _monitors = [getFixtureJson('http_monitor')]; - }); - - beforeEach(() => { - monitors = []; - for (let i = 0; i < 20; i++) { - monitors.push({ - ..._monitors[0], - name: `${_monitors[0].name} ${i}`, - }); - } - }); - - after(async () => { - await kibanaServer.spaces.delete(SPACE_ID); - await security.user.delete(username); - await security.role.delete(roleName); - }); - - it('returns the correct response', async () => { - let savedMonitors: EncryptedSyntheticsSavedMonitor[] = []; - try { - savedMonitors = await Promise.all(monitors.map(saveMonitor)); - - const apiResponse = await supertest.get( - `/s/${SPACE_ID}${SYNTHETICS_API_URLS.SYNTHETICS_OVERVIEW}` - ); - - expect(apiResponse.body.total).eql(monitors.length); - expect(apiResponse.body.allMonitorIds.sort()).eql( - savedMonitors.map((monitor) => monitor.id).sort() - ); - expect(apiResponse.body.monitors.length).eql(20); - } finally { - await Promise.all( - savedMonitors.map((monitor) => { - return deleteMonitor(monitor.id); - }) - ); - } - }); - - it('accepts search queries', async () => { - let savedMonitors: EncryptedSyntheticsSavedMonitor[] = []; - try { - savedMonitors = await Promise.all(monitors.map(saveMonitor)); - - const apiResponse = await supertest - .get(`/s/${SPACE_ID}${SYNTHETICS_API_URLS.SYNTHETICS_OVERVIEW}`) - .query({ - query: '19', - }); - - expect(apiResponse.body.total).eql(1); - expect(apiResponse.body.allMonitorIds.sort()).eql( - savedMonitors - .filter((monitor) => monitor.name.includes('19')) - .map((monitor) => monitor.id) - ); - expect(apiResponse.body.monitors.length).eql(1); - } finally { - await Promise.all( - savedMonitors.map((monitor) => { - return deleteMonitor(monitor.id); - }) - ); - } - }); - - it('returns the correct response for customHeartbeatId', async () => { - let savedMonitors: EncryptedSyntheticsSavedMonitor[] = []; - const customHeartbeatId = 'example_custom_heartbeat_id'; - try { - savedMonitors = await Promise.all( - [ - { ...monitors[0], name: 'test monitor a' }, - { - ...monitors[1], - custom_heartbeat_id: 'example_custom_heartbeat_id', - name: 'test monitor b', - }, - ].map(saveMonitor) - ); - - const apiResponse = await supertest - .get(`/s/${SPACE_ID}${SYNTHETICS_API_URLS.SYNTHETICS_OVERVIEW}`) - .query({ sortField: 'status' }); - - const expected: MonitorOverviewItem[] = [ - { - id: savedMonitors[0][ConfigKey.MONITOR_QUERY_ID], - configId: savedMonitors[0].config_id, - name: 'test monitor a', - location: LOCAL_LOCATION, - isEnabled: true, - isStatusAlertEnabled: true, - tags: ['tag1', 'tag2'], - type: 'http', - schedule: '5', - }, - { - id: savedMonitors[1][ConfigKey.MONITOR_QUERY_ID], - configId: savedMonitors[1].config_id, - name: 'test monitor b', - location: LOCAL_LOCATION, - isEnabled: true, - isStatusAlertEnabled: true, - tags: ['tag1', 'tag2'], - type: 'http', - schedule: '5', - }, - ]; - - expect(apiResponse.body.monitors).eql(expected); - expect(savedMonitors[1][ConfigKey.MONITOR_QUERY_ID]).eql(customHeartbeatId); - } finally { - await Promise.all( - savedMonitors.map((monitor) => { - return deleteMonitor(monitor.config_id); - }) - ); - } - }); - }); -} diff --git a/x-pack/test/api_integration/apis/synthetics/index.ts b/x-pack/test/api_integration/apis/synthetics/index.ts index f570255bef8f2..a8b39893570c2 100644 --- a/x-pack/test/api_integration/apis/synthetics/index.ts +++ b/x-pack/test/api_integration/apis/synthetics/index.ts @@ -22,7 +22,6 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./get_filters')); loadTestFile(require.resolve('./enable_default_alerting')); loadTestFile(require.resolve('./get_monitor')); - loadTestFile(require.resolve('./get_monitor_overview')); loadTestFile(require.resolve('./add_monitor')); loadTestFile(require.resolve('./add_monitor_project')); loadTestFile(require.resolve('./get_monitor_project'));