diff --git a/x-pack/solutions/observability/plugins/synthetics/public/apps/synthetics/components/alerts/status_rule_viz.tsx b/x-pack/solutions/observability/plugins/synthetics/public/apps/synthetics/components/alerts/status_rule_viz.tsx index 141793dde356d..8b8f0277dfd5b 100644 --- a/x-pack/solutions/observability/plugins/synthetics/public/apps/synthetics/components/alerts/status_rule_viz.tsx +++ b/x-pack/solutions/observability/plugins/synthetics/public/apps/synthetics/components/alerts/status_rule_viz.tsx @@ -11,6 +11,7 @@ import { EuiCallOut, EuiFlexGroup, EuiFlexItem, + EuiLoadingSpinner, EuiPopover, EuiPopoverTitle, EuiSpacer, @@ -31,7 +32,7 @@ export const StatusRuleViz = ({ }: { ruleParams: StatusRuleParamsProps['ruleParams']; }) => { - const { data } = useSelector(selectInspectStatusRule); + const { data, loading } = useSelector(selectInspectStatusRule); const dispatch = useDispatch(); const { services: { inspector }, @@ -57,7 +58,7 @@ export const StatusRuleViz = ({ return ( - + {i18n.translate('xpack.synthetics.statusRuleViz.ruleAppliesToFlexItemLabel', { defaultMessage: 'Rule applies to ', @@ -68,17 +69,19 @@ export const StatusRuleViz = ({ isOpen={isPopoverOpen} closePopover={() => setIsPopoverOpen(false)} button={ - setIsPopoverOpen(!isPopoverOpen)} - > - {i18n.translate('xpack.synthetics.statusRuleViz.monitorQueryIdsPopoverButton', { - defaultMessage: - '{total} existing {total, plural, one {monitor} other {monitors}}', - values: { total: data?.monitors.length }, - })} - + loading ? undefined : ( + setIsPopoverOpen(!isPopoverOpen)} + > + {i18n.translate('xpack.synthetics.statusRuleViz.monitorQueryIdsPopoverButton', { + defaultMessage: + '{total} existing {total, plural, one {monitor} other {monitors}}', + values: { total: data?.monitors.length }, + })} + + ) } > @@ -93,6 +96,11 @@ export const StatusRuleViz = ({ + {loading && ( + + + + )} {/* to push detail button to end*/} diff --git a/x-pack/solutions/observability/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.ts b/x-pack/solutions/observability/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.ts index 8e58a66d8ff9d..21d295856ccf1 100644 --- a/x-pack/solutions/observability/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.ts +++ b/x-pack/solutions/observability/plugins/synthetics/server/alert_rules/status_rule/status_rule_executor.ts @@ -36,7 +36,7 @@ import { getUngroupedReasonMessage, } from './message_utils'; import { queryMonitorStatusAlert } from './queries/query_monitor_status_alert'; -import { parseArrayFilters } from '../../routes/common'; +import { parseArrayFilters, parseLocationFilter } from '../../routes/common'; import { SyntheticsServerSetup } from '../../types'; import { SyntheticsEsClient } from '../../lib'; import { processMonitors } from '../../saved_objects/synthetics_monitor/get_all_monitors'; @@ -118,21 +118,34 @@ export class StatusRuleExecutor { return processMonitors([]); } + const locationIds = await parseLocationFilter( + { + savedObjectsClient: this.soClient, + server: this.server, + syntheticsMonitorClient: this.syntheticsMonitorClient, + }, + this.params.locations + ); + const { filtersStr } = parseArrayFilters({ configIds, filter: baseFilter, - tags: this.params?.tags, - locations: this.params?.locations, - monitorTypes: this.params?.monitorTypes, - monitorQueryIds: this.params?.monitorIds, - projects: this.params?.projects, + tags: this.params.tags, + locations: locationIds, + monitorTypes: this.params.monitorTypes, + monitorQueryIds: this.params.monitorIds, + projects: this.params.projects, }); this.monitors = await this.monitorConfigRepository.getAll({ filter: filtersStr, }); - this.debug(`Found ${this.monitors.length} monitors for params ${JSON.stringify(this.params)}`); + this.debug( + `Found ${this.monitors.length} monitors for params ${JSON.stringify( + this.params + )} | parsed location filter is ${JSON.stringify(locationIds)} ` + ); return processMonitors(this.monitors); } diff --git a/x-pack/solutions/observability/plugins/synthetics/server/routes/common.test.ts b/x-pack/solutions/observability/plugins/synthetics/server/routes/common.test.ts index 7e5c0d610e520..ea981697db2e2 100644 --- a/x-pack/solutions/observability/plugins/synthetics/server/routes/common.test.ts +++ b/x-pack/solutions/observability/plugins/synthetics/server/routes/common.test.ts @@ -37,7 +37,7 @@ describe('common utils', () => { schedules: ['schedule1', 'schedule2'], }); expect(filters.filtersStr).toMatchInlineSnapshot( - `"synthetics-monitor.attributes.tags:(\\"tag1\\" OR \\"tag2\\") AND synthetics-monitor.attributes.project_id:(\\"project1\\" OR \\"project2\\") AND synthetics-monitor.attributes.type:(\\"type1\\" OR \\"type2\\") AND synthetics-monitor.attributes.schedule.number:(\\"schedule1\\" OR \\"schedule2\\") AND synthetics-monitor.attributes.id:(\\"query1\\" OR \\"query2\\") AND synthetics-monitor.attributes.config_id:(\\"1\\" OR \\"2\\")"` + `"synthetics-monitor.attributes.tags:(\\"tag1\\" OR \\"tag2\\") AND synthetics-monitor.attributes.project_id:(\\"project1\\" OR \\"project2\\") AND synthetics-monitor.attributes.type:(\\"type1\\" OR \\"type2\\") AND synthetics-monitor.attributes.locations.id:(\\"loc1\\" OR \\"loc2\\") AND synthetics-monitor.attributes.schedule.number:(\\"schedule1\\" OR \\"schedule2\\") AND synthetics-monitor.attributes.id:(\\"query1\\" OR \\"query2\\") AND synthetics-monitor.attributes.config_id:(\\"1\\" OR \\"2\\")"` ); }); }); diff --git a/x-pack/solutions/observability/plugins/synthetics/server/routes/common.ts b/x-pack/solutions/observability/plugins/synthetics/server/routes/common.ts index 0038f3aced8d9..2d453c2ee6b44 100644 --- a/x-pack/solutions/observability/plugins/synthetics/server/routes/common.ts +++ b/x-pack/solutions/observability/plugins/synthetics/server/routes/common.ts @@ -110,29 +110,29 @@ interface Filters { projects?: string | string[]; schedules?: string | string[]; monitorQueryIds?: string | string[]; + configIds?: string | string[]; } export const getMonitorFilters = async (context: RouteContext) => { const { tags, monitorTypes, - locations, filter = '', projects, schedules, monitorQueryIds, + locations: queryLocations, } = context.request.query; - const locationFilter = await parseLocationFilter(context, locations); + const locations = await parseLocationFilter(context, queryLocations); return parseArrayFilters({ filter, tags, monitorTypes, - locations, projects, schedules, monitorQueryIds, - locationFilter, + locations, }); }; @@ -144,17 +144,14 @@ export const parseArrayFilters = ({ monitorTypes, schedules, monitorQueryIds, - locationFilter, -}: Filters & { - locationFilter?: string | string[]; - configIds?: string[]; -}) => { + locations, +}: Filters) => { const filtersStr = [ filter, getSavedObjectKqlFilter({ field: 'tags', values: tags }), getSavedObjectKqlFilter({ field: 'project_id', values: projects }), getSavedObjectKqlFilter({ field: 'type', values: monitorTypes }), - getSavedObjectKqlFilter({ field: 'locations.id', values: locationFilter }), + getSavedObjectKqlFilter({ field: 'locations.id', values: locations }), getSavedObjectKqlFilter({ field: 'schedule.number', values: schedules }), getSavedObjectKqlFilter({ field: 'id', values: monitorQueryIds }), getSavedObjectKqlFilter({ field: 'config_id', values: configIds }), @@ -162,7 +159,7 @@ export const parseArrayFilters = ({ .filter((f) => !!f) .join(' AND '); - return { filtersStr, locationFilter }; + return { filtersStr, locationIds: locations }; }; export const getSavedObjectKqlFilter = ({ @@ -199,12 +196,24 @@ export const getSavedObjectKqlFilter = ({ return `${fieldKey}:"${escapeQuotes(values)}"`; }; -const parseLocationFilter = async (context: RouteContext, locations?: string | string[]) => { +export const parseLocationFilter = async ( + { + syntheticsMonitorClient, + savedObjectsClient, + server, + }: Pick, + locations?: string | string[] +) => { if (!locations || locations?.length === 0) { return; } - const { allLocations } = await getAllLocations(context); + const { allLocations } = await getAllLocations({ + syntheticsMonitorClient, + savedObjectsClient, + server, + excludeAgentPolicies: true, + }); if (Array.isArray(locations)) { return locations diff --git a/x-pack/solutions/observability/plugins/synthetics/server/routes/overview_status/overview_status_service.ts b/x-pack/solutions/observability/plugins/synthetics/server/routes/overview_status/overview_status_service.ts index 4f42f26b11940..abec0dade6f72 100644 --- a/x-pack/solutions/observability/plugins/synthetics/server/routes/overview_status/overview_status_service.ts +++ b/x-pack/solutions/observability/plugins/synthetics/server/routes/overview_status/overview_status_service.ts @@ -36,7 +36,7 @@ export const SUMMARIES_PAGE_SIZE = 5000; export class OverviewStatusService { filterData: { - locationFilter?: string[] | string; + locationIds?: string[] | string; filtersStr?: string; } = {}; constructor( @@ -61,7 +61,7 @@ export class OverviewStatusService { disabledCount, disabledMonitorsCount, projectMonitorsCount, - } = processMonitors(allConfigs, this.filterData?.locationFilter); + } = processMonitors(allConfigs, this.filterData?.locationIds); return { allIds, @@ -91,7 +91,7 @@ export class OverviewStatusService { projects, showFromAllSpaces, } = params; - const { locationFilter } = this.filterData; + const { locationIds } = this.filterData; const getTermFilter = (field: string, value: string | string[] | undefined) => { if (!value || isEmpty(value)) { return []; @@ -120,10 +120,10 @@ export class OverviewStatusService { ...getTermFilter('monitor.project.id', projects), ]; - if (scopeStatusByLocation && !isEmpty(locationFilter) && locationFilter) { + if (scopeStatusByLocation && !isEmpty(locationIds) && locationIds) { filters.push({ terms: { - 'observer.name': locationFilter, + 'observer.name': locationIds, }, }); } @@ -231,7 +231,7 @@ export class OverviewStatusService { const enabledMonitors = monitors.filter((monitor) => monitor.attributes[ConfigKey.ENABLED]); const disabledMonitors = monitors.filter((monitor) => !monitor.attributes[ConfigKey.ENABLED]); - const queryLocIds = this.filterData?.locationFilter; + const queryLocIds = this.filterData?.locationIds; disabledMonitors.forEach((monitor) => { const monitorQueryId = monitor.attributes[ConfigKey.MONITOR_QUERY_ID];