From d2a65940f85fba1338438e33c89f07a82c5a0ed0 Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Thu, 26 Jan 2023 17:32:18 +0100 Subject: [PATCH 01/10] [APM] Integrate Alert search bar in alert tab --- .../apm/common/environment_filter_values.ts | 12 ++ .../alerts_table_status_filter.tsx | 73 ----------- .../components/app/alerts_overview/index.tsx | 116 ++++++++++++------ 3 files changed, 88 insertions(+), 113 deletions(-) delete mode 100644 x-pack/plugins/apm/public/components/app/alerts_overview/alerts_table_status_filter.tsx diff --git a/x-pack/plugins/apm/common/environment_filter_values.ts b/x-pack/plugins/apm/common/environment_filter_values.ts index e4779ee9547f0..7c89e4f69a7bd 100644 --- a/x-pack/plugins/apm/common/environment_filter_values.ts +++ b/x-pack/plugins/apm/common/environment_filter_values.ts @@ -55,6 +55,18 @@ export function getEnvironmentEsField(environment: string) { return { [SERVICE_ENVIRONMENT]: environment }; } +export function getEnvironmentKuery(environment: string) { + if ( + !environment || + environment === ENVIRONMENT_NOT_DEFINED_VALUE || + environment === ENVIRONMENT_ALL_VALUE + ) { + return null; + } + + return `${[SERVICE_ENVIRONMENT]}: ${environment} `; +} + // returns the environment url param that should be used // based on the requested environment. If the requested // environment is different from the URL parameter, we'll diff --git a/x-pack/plugins/apm/public/components/app/alerts_overview/alerts_table_status_filter.tsx b/x-pack/plugins/apm/public/components/app/alerts_overview/alerts_table_status_filter.tsx deleted file mode 100644 index 49769de6a6b42..0000000000000 --- a/x-pack/plugins/apm/public/components/app/alerts_overview/alerts_table_status_filter.tsx +++ /dev/null @@ -1,73 +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 { EuiButtonGroup, EuiButtonGroupOptionProps } from '@elastic/eui'; -import { i18n } from '@kbn/i18n'; -import React from 'react'; -import { - ALERT_STATUS_ACTIVE, - ALERT_STATUS_RECOVERED, - ALERT_STATUS, -} from '@kbn/rule-data-utils'; -export const ALL_ALERTS_FILTER = 'ALL_ALERTS_FILTER'; - -export type AlertStatusFilterButton = - | typeof ALERT_STATUS_ACTIVE - | typeof ALERT_STATUS_RECOVERED - | typeof ALL_ALERTS_FILTER; - -export interface AlertStatusFilterProps { - status: AlertStatusFilterButton; - onChange: (id: AlertStatusFilterButton) => void; -} - -const options: EuiButtonGroupOptionProps[] = [ - { - id: ALL_ALERTS_FILTER, - value: '', - label: i18n.translate('xpack.apm.alerts.alertStatusFilter.showAll', { - defaultMessage: 'Show all', - }), - 'data-test-subj': 'alert-status-filter-show-all-button', - }, - { - id: ALERT_STATUS_ACTIVE, - value: `${ALERT_STATUS}: "${ALERT_STATUS_RECOVERED}"`, - label: i18n.translate('xpack.apm.alerts.alertStatusFilter.active', { - defaultMessage: 'Active', - }), - 'data-test-subj': 'alert-status-filter-active-button', - }, - { - id: ALERT_STATUS_RECOVERED, - value: `${ALERT_STATUS}: "${ALERT_STATUS_RECOVERED}"`, - label: i18n.translate('xpack.apm.alerts.alertStatusFilter.recovered', { - defaultMessage: 'Recovered', - }), - 'data-test-subj': 'alert-status-filter-recovered-button', - }, -]; - -export function AlertsTableStatusFilter({ - status, - onChange, -}: AlertStatusFilterProps) { - return ( - onChange(id as AlertStatusFilterButton)} - /> - ); -} diff --git a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx index ad885bed46fa1..0c6580ef68ab1 100644 --- a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx @@ -6,82 +6,118 @@ */ import React, { useState, useMemo } from 'react'; +import { useHistory } from 'react-router'; +import { ObservabilityAlertSearchBar } from '@kbn/observability-plugin/public'; +import { AlertStatus } from '@kbn/observability-plugin/common/typings'; import { EuiPanel, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; -import { ALERT_STATUS } from '@kbn/rule-data-utils'; +import { BoolQuery } from '@kbn/es-query'; import { AlertConsumers } from '@kbn/rule-data-utils'; import { useKibana } from '@kbn/kibana-react-plugin/public'; import { ApmPluginStartDeps } from '../../../plugin'; import { useAnyOfApmParams } from '../../../hooks/use_apm_params'; import { SERVICE_NAME } from '../../../../common/es_fields/apm'; -import { environmentQuery } from '../../../../common/utils/environment_query'; -import { - AlertsTableStatusFilter, - ALL_ALERTS_FILTER, - AlertStatusFilterButton, -} from './alerts_table_status_filter'; +import { getEnvironmentKuery } from '../../../../common/environment_filter_values'; +import { push } from '../../shared/links/url_helpers'; + +export const ALERT_STATUS_ALL = 'all'; export function AlertsOverview() { + const history = useHistory(); const { path: { serviceName }, - query: { environment }, + query: { environment, rangeFrom, rangeTo, kuery }, } = useAnyOfApmParams( '/services/{serviceName}/alerts', '/mobile-services/{serviceName}/alerts' ); const { services } = useKibana(); const [alertStatusFilter, setAlertStatusFilter] = - useState(ALL_ALERTS_FILTER); + useState(ALERT_STATUS_ALL); + const [esQuery, setEsQuery] = useState<{ bool: BoolQuery }>(); const { triggersActionsUi: { getAlertsStateTable: AlertsStateTable, + getAlertsSearchBar: AlertsSearchBar, alertsTableConfigurationRegistry, }, + notifications, + data: { + query: { + timefilter: { timefilter: timeFilterService }, + }, + }, } = services; - const alertQuery = useMemo( - () => ({ - bool: { - filter: [ - { - term: { [SERVICE_NAME]: serviceName }, - }, - ...(alertStatusFilter !== ALL_ALERTS_FILTER - ? [ - { - term: { [ALERT_STATUS]: alertStatusFilter }, - }, - ] - : []), - ...environmentQuery(environment), - ], - }, - }), - [serviceName, alertStatusFilter, environment] - ); + const useToasts = () => notifications!.toasts; + + const apmQueries = useMemo(() => { + const environmentKuery = getEnvironmentKuery(environment); + let query = `${SERVICE_NAME}:${serviceName}`; - const alertStateProps = { - alertsTableConfigurationRegistry, - id: 'service-overview-alerts', - configurationId: AlertConsumers.OBSERVABILITY, - featureIds: [AlertConsumers.APM], - query: alertQuery, - showExpandToDetails: false, - }; + if (environmentKuery) { + query += ` AND ${environmentKuery}`; + } + return [ + { + query, + language: 'kuery', + }, + ]; + }, [serviceName, environment]); return ( - + push(history, { + query: { + rangeFrom, + }, + }) + } + onRangeToChange={(rangeTo) => + push(history, { + query: { + rangeTo, + }, + }) + } + onKueryChange={(kuery) => + push(history, { + query: { + kuery, + }, + }) + } + defaultSearchQueries={apmQueries} + onStatusChange={setAlertStatusFilter} + onEsQueryChange={setEsQuery} + rangeTo={rangeTo} + rangeFrom={rangeFrom} status={alertStatusFilter} - onChange={setAlertStatusFilter} + services={{ timeFilterService, AlertsSearchBar, useToasts }} /> - + {esQuery && ( + + )} From ea7c2c5f9e800a34a83bdbbbadcd2cd1d6ce30e1 Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Thu, 26 Jan 2023 17:41:40 +0100 Subject: [PATCH 02/10] Filter alerts counts with timerage --- .../templates/apm_service_template/index.tsx | 9 ++++++++- .../services/get_services/get_service_alerts.ts | 17 +++++++++++++---- .../plugins/apm/server/routes/services/route.ts | 7 ++++++- 3 files changed, 27 insertions(+), 6 deletions(-) diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index 5a127e768709c..bd52d27b1b7c6 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -213,6 +213,9 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { query: queryFromUrl, } = useApmParams(`/services/{serviceName}/${selectedTab}` as const); + const { rangeFrom, rangeTo } = queryFromUrl; + const { start, end } = useTimeRange({ rangeFrom, rangeTo }); + const { data: serviceAlertsCount = { alertsCount: 0 } } = useFetcher( (callApmApi) => { return callApmApi( @@ -222,11 +225,15 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { path: { serviceName, }, + query: { + start, + end, + }, }, } ); }, - [serviceName] + [serviceName, start, end] ); const query = omit( diff --git a/x-pack/plugins/apm/server/routes/services/get_services/get_service_alerts.ts b/x-pack/plugins/apm/server/routes/services/get_services/get_service_alerts.ts index 989ea8b9a6628..a49bb63146716 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services/get_service_alerts.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services/get_service_alerts.ts @@ -9,7 +9,11 @@ import { AggregationsCardinalityAggregate, AggregationsFilterAggregate, } from '@elastic/elasticsearch/lib/api/types'; -import { kqlQuery } from '@kbn/observability-plugin/server'; +import { + kqlQuery, + termQuery, + rangeQuery, +} from '@kbn/observability-plugin/server'; import { ALERT_RULE_PRODUCER, ALERT_STATUS, @@ -37,23 +41,28 @@ export async function getServicesAlerts({ maxNumServices = MAX_NUMBER_OF_SERVICES, serviceGroup, serviceName, + start, + end, }: { apmAlertsClient: ApmAlertsClient; kuery?: string; maxNumServices?: number; serviceGroup?: ServiceGroup | null; serviceName?: string; + start: number; + end: number; }) { const params = { size: 0, query: { bool: { filter: [ - { term: { [ALERT_RULE_PRODUCER]: 'apm' } }, - { term: { [ALERT_STATUS]: ALERT_STATUS_ACTIVE } }, + ...termQuery(ALERT_RULE_PRODUCER, 'apm'), + ...termQuery(ALERT_STATUS, ALERT_STATUS_ACTIVE), + ...rangeQuery(start, end), ...kqlQuery(kuery), ...serviceGroupQuery(serviceGroup), - ...(serviceName ? [{ term: { [SERVICE_NAME]: serviceName } }] : []), + ...termQuery(SERVICE_NAME, serviceName), ], }, }, diff --git a/x-pack/plugins/apm/server/routes/services/route.ts b/x-pack/plugins/apm/server/routes/services/route.ts index 0f2e40caf8b04..61e7dc608615d 100644 --- a/x-pack/plugins/apm/server/routes/services/route.ts +++ b/x-pack/plugins/apm/server/routes/services/route.ts @@ -1220,6 +1220,7 @@ const serviceAlertsRoute = createApmServerRoute({ path: t.type({ serviceName: t.string, }), + query: rangeRt, }), options: { tags: ['access:apm'] }, handler: async ( @@ -1229,13 +1230,17 @@ const serviceAlertsRoute = createApmServerRoute({ alertsCount: number; }> => { const { params } = resources; - + const { + query: { start, end }, + } = params; const { serviceName } = params.path; const apmAlertsClient = await getApmAlertsClient(resources); const servicesAlerts = await getServicesAlerts({ serviceName, apmAlertsClient, + start, + end, }); return servicesAlerts.length > 0 From 670f08580767032d750685a9eefe2be98c664fc5 Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Thu, 26 Jan 2023 18:03:01 +0100 Subject: [PATCH 03/10] Update translations --- x-pack/plugins/translations/translations/fr-FR.json | 6 +----- x-pack/plugins/translations/translations/ja-JP.json | 6 +----- x-pack/plugins/translations/translations/zh-CN.json | 6 +----- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/x-pack/plugins/translations/translations/fr-FR.json b/x-pack/plugins/translations/translations/fr-FR.json index 637865388ad51..10f83f79092b0 100644 --- a/x-pack/plugins/translations/translations/fr-FR.json +++ b/x-pack/plugins/translations/translations/fr-FR.json @@ -6966,10 +6966,6 @@ "xpack.apm.alerts.action_variables.transactionType": "Type de transaction pour lequel l'alerte est créée", "xpack.apm.alerts.action_variables.triggerValue": "Valeur ayant dépassé le seuil et déclenché l'alerte", "xpack.apm.alerts.action_variables.viewInAppUrl": "Lien vers la vue ou la fonctionnalité d'Elastic qui peut être utilisée pour examiner l'alerte et son contexte de manière plus approfondie", - "xpack.apm.alerts.alertStatusFilter.active": "Actif", - "xpack.apm.alerts.alertStatusFilter.button.legend": "Filtrer par", - "xpack.apm.alerts.alertStatusFilter.recovered": "Récupéré", - "xpack.apm.alerts.alertStatusFilter.showAll": "Afficher tout", "xpack.apm.alerts.anomalySeverity.criticalLabel": "critique", "xpack.apm.alerts.anomalySeverity.majorLabel": "majeur", "xpack.apm.alerts.anomalySeverity.minor": "mineure", @@ -36523,4 +36519,4 @@ "xpack.painlessLab.title": "Painless Lab", "xpack.painlessLab.walkthroughButtonLabel": "Présentation" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/translations/translations/ja-JP.json b/x-pack/plugins/translations/translations/ja-JP.json index eb9e2bb17df15..8a2920d765b32 100644 --- a/x-pack/plugins/translations/translations/ja-JP.json +++ b/x-pack/plugins/translations/translations/ja-JP.json @@ -6956,10 +6956,6 @@ "xpack.apm.alerts.action_variables.transactionType": "アラートが作成されるトランザクションタイプ", "xpack.apm.alerts.action_variables.triggerValue": "しきい値に達し、アラートをトリガーした値", "xpack.apm.alerts.action_variables.viewInAppUrl": "アラートとコンテキストを調査するために使用できる、Elastic内のビューまたは機能へのリンク", - "xpack.apm.alerts.alertStatusFilter.active": "アクティブ", - "xpack.apm.alerts.alertStatusFilter.button.legend": "フィルタリング条件", - "xpack.apm.alerts.alertStatusFilter.recovered": "回復済み", - "xpack.apm.alerts.alertStatusFilter.showAll": "すべて表示", "xpack.apm.alerts.anomalySeverity.criticalLabel": "致命的", "xpack.apm.alerts.anomalySeverity.majorLabel": "メジャー", "xpack.apm.alerts.anomalySeverity.minor": "マイナー", @@ -36491,4 +36487,4 @@ "xpack.painlessLab.title": "Painless Lab", "xpack.painlessLab.walkthroughButtonLabel": "実地検証" } -} \ No newline at end of file +} diff --git a/x-pack/plugins/translations/translations/zh-CN.json b/x-pack/plugins/translations/translations/zh-CN.json index 5468d9820cd69..74f1258797aba 100644 --- a/x-pack/plugins/translations/translations/zh-CN.json +++ b/x-pack/plugins/translations/translations/zh-CN.json @@ -6969,10 +6969,6 @@ "xpack.apm.alerts.action_variables.transactionType": "创建告警的事务类型", "xpack.apm.alerts.action_variables.triggerValue": "超过阈值并触发告警的值", "xpack.apm.alerts.action_variables.viewInAppUrl": "Elastic 中可用于进一步调查告警及其上下文的视图或功能的链接", - "xpack.apm.alerts.alertStatusFilter.active": "活动", - "xpack.apm.alerts.alertStatusFilter.button.legend": "筛选依据", - "xpack.apm.alerts.alertStatusFilter.recovered": "已恢复", - "xpack.apm.alerts.alertStatusFilter.showAll": "全部显示", "xpack.apm.alerts.anomalySeverity.criticalLabel": "紧急", "xpack.apm.alerts.anomalySeverity.majorLabel": "重大", "xpack.apm.alerts.anomalySeverity.minor": "轻微", @@ -36528,4 +36524,4 @@ "xpack.painlessLab.title": "Painless 实验室", "xpack.painlessLab.walkthroughButtonLabel": "指导" } -} \ No newline at end of file +} From 2ff6cf6640afc970121e3d448a4241cd327d0f47 Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Thu, 26 Jan 2023 18:34:11 +0100 Subject: [PATCH 04/10] Fix API tests --- .../apm_api_integration/tests/services/service_alerts.spec.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts b/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts index 1cb9e01a8fe1e..ff44f2d74cdc0 100644 --- a/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts @@ -27,6 +27,10 @@ export default function ServiceAlerts({ getService }: FtrProviderContext) { endpoint: 'GET /internal/apm/services/{serviceName}/alerts_count', params: { path: { serviceName }, + query: { + start, + end, + }, }, }); } From ac5ce293e343d145a57c809f7fc5f6e8e1fafaa4 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 26 Jan 2023 18:08:21 +0000 Subject: [PATCH 05/10] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../plugins/apm/public/components/app/alerts_overview/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx index 0c6580ef68ab1..e469279591f1c 100644 --- a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx @@ -6,7 +6,7 @@ */ import React, { useState, useMemo } from 'react'; -import { useHistory } from 'react-router'; +import { useHistory } from 'react-router-dom'; import { ObservabilityAlertSearchBar } from '@kbn/observability-plugin/public'; import { AlertStatus } from '@kbn/observability-plugin/common/typings'; import { EuiPanel, EuiFlexItem, EuiFlexGroup } from '@elastic/eui'; From aac41ce2d2fc0c7ef31cf2d3e0b87ef225f0f70f Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Fri, 27 Jan 2023 10:14:43 +0100 Subject: [PATCH 06/10] Filter alert counts with enviroment --- .../routing/templates/apm_service_template/index.tsx | 3 ++- .../routes/services/get_services/get_service_alerts.ts | 4 ++++ x-pack/plugins/apm/server/routes/services/route.ts | 5 +++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index bd52d27b1b7c6..fa152cbe49894 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -213,7 +213,7 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { query: queryFromUrl, } = useApmParams(`/services/{serviceName}/${selectedTab}` as const); - const { rangeFrom, rangeTo } = queryFromUrl; + const { rangeFrom, rangeTo, environment } = queryFromUrl; const { start, end } = useTimeRange({ rangeFrom, rangeTo }); const { data: serviceAlertsCount = { alertsCount: 0 } } = useFetcher( @@ -228,6 +228,7 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { query: { start, end, + environment, }, }, } diff --git a/x-pack/plugins/apm/server/routes/services/get_services/get_service_alerts.ts b/x-pack/plugins/apm/server/routes/services/get_services/get_service_alerts.ts index a49bb63146716..16675afc9d74a 100644 --- a/x-pack/plugins/apm/server/routes/services/get_services/get_service_alerts.ts +++ b/x-pack/plugins/apm/server/routes/services/get_services/get_service_alerts.ts @@ -23,6 +23,7 @@ import { import { SERVICE_NAME } from '../../../../common/es_fields/apm'; import { ServiceGroup } from '../../../../common/service_groups'; import { ApmAlertsClient } from '../../../lib/helpers/get_apm_alerts_client'; +import { environmentQuery } from '../../../../common/utils/environment_query'; import { serviceGroupQuery } from '../../../lib/service_group_query'; import { MAX_NUMBER_OF_SERVICES } from './get_services_items'; @@ -43,6 +44,7 @@ export async function getServicesAlerts({ serviceName, start, end, + environment, }: { apmAlertsClient: ApmAlertsClient; kuery?: string; @@ -51,6 +53,7 @@ export async function getServicesAlerts({ serviceName?: string; start: number; end: number; + environment?: string; }) { const params = { size: 0, @@ -63,6 +66,7 @@ export async function getServicesAlerts({ ...kqlQuery(kuery), ...serviceGroupQuery(serviceGroup), ...termQuery(SERVICE_NAME, serviceName), + ...environmentQuery(environment), ], }, }, diff --git a/x-pack/plugins/apm/server/routes/services/route.ts b/x-pack/plugins/apm/server/routes/services/route.ts index 61e7dc608615d..041783beab5b2 100644 --- a/x-pack/plugins/apm/server/routes/services/route.ts +++ b/x-pack/plugins/apm/server/routes/services/route.ts @@ -1220,7 +1220,7 @@ const serviceAlertsRoute = createApmServerRoute({ path: t.type({ serviceName: t.string, }), - query: rangeRt, + query: t.intersection([rangeRt, environmentRt]), }), options: { tags: ['access:apm'] }, handler: async ( @@ -1231,7 +1231,7 @@ const serviceAlertsRoute = createApmServerRoute({ }> => { const { params } = resources; const { - query: { start, end }, + query: { start, end, environment }, } = params; const { serviceName } = params.path; @@ -1239,6 +1239,7 @@ const serviceAlertsRoute = createApmServerRoute({ const servicesAlerts = await getServicesAlerts({ serviceName, apmAlertsClient, + environment, start, end, }); From 4bf78b24d00c5b2d519e970c3f91cf1f9cbae23e Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Fri, 27 Jan 2023 10:15:19 +0100 Subject: [PATCH 07/10] Escape environment value for kuery --- .../apm/common/environment_filter_values.ts | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/x-pack/plugins/apm/common/environment_filter_values.ts b/x-pack/plugins/apm/common/environment_filter_values.ts index 7c89e4f69a7bd..5b6354880cce5 100644 --- a/x-pack/plugins/apm/common/environment_filter_values.ts +++ b/x-pack/plugins/apm/common/environment_filter_values.ts @@ -6,6 +6,7 @@ */ import { i18n } from '@kbn/i18n'; +import { escapeKuery } from '@kbn/es-query'; import { SERVICE_ENVIRONMENT } from './es_fields/apm'; import { Environment } from './environment_rt'; @@ -43,12 +44,16 @@ export const ENVIRONMENT_NOT_DEFINED = { label: getEnvironmentLabel(ENVIRONMENT_NOT_DEFINED_VALUE), }; -export function getEnvironmentEsField(environment: string) { - if ( +function isEnvironmentDefined(environment: string) { + return ( !environment || environment === ENVIRONMENT_NOT_DEFINED_VALUE || environment === ENVIRONMENT_ALL_VALUE - ) { + ); +} + +export function getEnvironmentEsField(environment: string) { + if (isEnvironmentDefined(environment)) { return {}; } @@ -56,15 +61,11 @@ export function getEnvironmentEsField(environment: string) { } export function getEnvironmentKuery(environment: string) { - if ( - !environment || - environment === ENVIRONMENT_NOT_DEFINED_VALUE || - environment === ENVIRONMENT_ALL_VALUE - ) { + if (isEnvironmentDefined(environment)) { return null; } - return `${[SERVICE_ENVIRONMENT]}: ${environment} `; + return `${[SERVICE_ENVIRONMENT]}: ${escapeKuery(environment)} `; } // returns the environment url param that should be used From 042aeb484b0abcf3a63bf43d3aa6749647977716 Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Fri, 27 Jan 2023 11:33:12 +0100 Subject: [PATCH 08/10] Update api tests --- .../tests/services/service_alerts.spec.ts | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts b/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts index ff44f2d74cdc0..a8c92dfdd256e 100644 --- a/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts +++ b/x-pack/test/apm_api_integration/tests/services/service_alerts.spec.ts @@ -22,14 +22,21 @@ export default function ServiceAlerts({ getService }: FtrProviderContext) { const end = Date.now(); const goService = 'synth-go'; - async function getServiceAlerts(serviceName: string) { + async function getServiceAlerts({ + serviceName, + environment, + }: { + serviceName: string; + environment: string; + }) { return apmApiClient.readUser({ endpoint: 'GET /internal/apm/services/{serviceName}/alerts_count', params: { path: { serviceName }, query: { - start, - end, + start: new Date(start).toISOString(), + end: new Date(end + 5 * 60 * 1000).toISOString(), + environment, }, }, }); @@ -125,7 +132,7 @@ export default function ServiceAlerts({ getService }: FtrProviderContext) { }); it('returns the correct number of alerts', async () => { - const response = await getServiceAlerts(goService); + const response = await getServiceAlerts({ serviceName: goService, environment: 'testing' }); expect(response.status).to.be(200); expect(response.body.serviceName).to.be(goService); expect(response.body.alertsCount).to.be(1); @@ -134,7 +141,7 @@ export default function ServiceAlerts({ getService }: FtrProviderContext) { describe('without alerts', () => { it('returns the correct number of alerts', async () => { - const response = await getServiceAlerts(goService); + const response = await getServiceAlerts({ serviceName: goService, environment: 'foo' }); expect(response.status).to.be(200); expect(response.body.serviceName).to.be(goService); expect(response.body.alertsCount).to.be(0); From 9b1027aef823823936df37efab23b051cb38f00d Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Fri, 27 Jan 2023 12:20:35 +0100 Subject: [PATCH 09/10] Replace unit test with e2e to cover the integration of alerts table and search bar --- .../service_overview/alerts_table.cy.ts | 46 +++++ .../app/alerts_overview/index.test.tsx | 170 ------------------ 2 files changed, 46 insertions(+), 170 deletions(-) create mode 100644 x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/alerts_table.cy.ts delete mode 100644 x-pack/plugins/apm/public/components/app/alerts_overview/index.test.tsx diff --git a/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/alerts_table.cy.ts b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/alerts_table.cy.ts new file mode 100644 index 0000000000000..6a5cd12bc7842 --- /dev/null +++ b/x-pack/plugins/apm/ftr_e2e/cypress/e2e/read_only_user/service_overview/alerts_table.cy.ts @@ -0,0 +1,46 @@ +/* + * 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 url from 'url'; +import { synthtrace } from '../../../../synthtrace'; +import { opbeans } from '../../../fixtures/synthtrace/opbeans'; + +const start = '2021-10-10T00:00:00.000Z'; +const end = '2021-10-10T00:15:00.000Z'; + +const serviceOverviewHref = url.format({ + pathname: '/app/apm/services/opbeans-java/alerts', + query: { rangeFrom: start, rangeTo: end }, +}); + +describe('Errors table', () => { + before(() => { + synthtrace.index( + opbeans({ + from: new Date(start).getTime(), + to: new Date(end).getTime(), + }) + ); + }); + + after(() => { + synthtrace.clean(); + }); + + beforeEach(() => { + cy.loginAsViewerUser(); + }); + + it('Alerts table with the search bar is populated', () => { + cy.visitKibana(serviceOverviewHref); + cy.contains('opbeans-java'); + cy.contains('All'); + cy.contains('Active'); + cy.contains('Recovered'); + cy.getByTestSubj('globalQueryBar').should('exist'); + }); +}); diff --git a/x-pack/plugins/apm/public/components/app/alerts_overview/index.test.tsx b/x-pack/plugins/apm/public/components/app/alerts_overview/index.test.tsx deleted file mode 100644 index 270d0ba8c4561..0000000000000 --- a/x-pack/plugins/apm/public/components/app/alerts_overview/index.test.tsx +++ /dev/null @@ -1,170 +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 { render, waitFor, act } from '@testing-library/react'; -import { MemoryRouter } from 'react-router-dom'; -import React, { ReactNode } from 'react'; -import { MockApmPluginContextWrapper } from '../../../context/apm_plugin/mock_apm_plugin_context'; -import * as useApmParamsHooks from '../../../hooks/use_apm_params'; -import { createKibanaReactContext } from '@kbn/kibana-react-plugin/public'; -import { CoreStart } from '@kbn/core/public'; -import { AlertsOverview } from '.'; - -const getAlertsStateTableMock = jest.fn(); - -function Wrapper({ children }: { children?: ReactNode }) { - const KibanaReactContext = createKibanaReactContext({ - triggersActionsUi: { - getAlertsStateTable: getAlertsStateTableMock.mockReturnValue( -
- ), - alertsTableConfigurationRegistry: '', - }, - } as Partial); - - return ( - - - {children} - - - ); -} - -const renderOptions = { wrapper: Wrapper }; - -describe('AlertsTable', () => { - beforeEach(() => { - jest.spyOn(useApmParamsHooks as any, 'useApmParams').mockReturnValue({ - path: { - serviceName: 'opbeans', - }, - query: { - rangeFrom: 'now-24h', - rangeTo: 'now', - environment: 'testing', - }, - }); - jest.clearAllMocks(); - }); - - it('renders alerts table in service overview', async () => { - const { getByTestId } = render(, renderOptions); - - await waitFor(async () => { - expect(getByTestId('alerts-table')).toBeTruthy(); - }); - }); - it('should call alerts table with correct propts', async () => { - act(() => { - render(, renderOptions); - }); - - await waitFor(async () => { - expect(getAlertsStateTableMock).toHaveBeenCalledWith( - { - alertsTableConfigurationRegistry: '', - id: 'service-overview-alerts', - configurationId: 'observability', - featureIds: ['apm'], - query: { - bool: { - filter: [ - { - term: { 'service.name': 'opbeans' }, - }, - { - term: { 'service.environment': 'testing' }, - }, - ], - }, - }, - showExpandToDetails: false, - }, - {} - ); - }); - }); - - it('should call alerts table with active filter', async () => { - const { getByTestId } = render(, renderOptions); - - await act(async () => { - const inputEl = getByTestId('active'); - inputEl.click(); - }); - - await waitFor(async () => { - expect(getAlertsStateTableMock).toHaveBeenLastCalledWith( - { - alertsTableConfigurationRegistry: '', - id: 'service-overview-alerts', - configurationId: 'observability', - featureIds: ['apm'], - query: { - bool: { - filter: [ - { - term: { 'service.name': 'opbeans' }, - }, - { - term: { 'kibana.alert.status': 'active' }, - }, - { - term: { 'service.environment': 'testing' }, - }, - ], - }, - }, - showExpandToDetails: false, - }, - {} - ); - }); - }); - - it('should call alerts table with recovered filter', async () => { - const { getByTestId } = render(, renderOptions); - - await act(async () => { - const inputEl = getByTestId('recovered'); - inputEl.click(); - }); - - await waitFor(async () => { - expect(getAlertsStateTableMock).toHaveBeenLastCalledWith( - { - alertsTableConfigurationRegistry: '', - id: 'service-overview-alerts', - configurationId: 'observability', - featureIds: ['apm'], - query: { - bool: { - filter: [ - { - term: { 'service.name': 'opbeans' }, - }, - { - term: { 'kibana.alert.status': 'recovered' }, - }, - { - term: { 'service.environment': 'testing' }, - }, - ], - }, - }, - showExpandToDetails: false, - }, - {} - ); - }); - }); -}); From 1e899e09de0a3d150c40882f25243fe305700bea Mon Sep 17 00:00:00 2001 From: Kate Patticha Date: Fri, 27 Jan 2023 15:32:01 +0100 Subject: [PATCH 10/10] Address comments --- .../components/app/alerts_overview/index.tsx | 24 +++++-------------- .../templates/apm_service_template/index.tsx | 2 +- 2 files changed, 7 insertions(+), 19 deletions(-) diff --git a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx index e469279591f1c..898762c8350fa 100644 --- a/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx +++ b/x-pack/plugins/apm/public/components/app/alerts_overview/index.tsx @@ -74,26 +74,14 @@ export function AlertsOverview() { - push(history, { - query: { - rangeFrom, - }, - }) + onRangeFromChange={(value) => + push(history, { query: { rangeFrom: value } }) } - onRangeToChange={(rangeTo) => - push(history, { - query: { - rangeTo, - }, - }) + onRangeToChange={(value) => + push(history, { query: { rangeTo: value } }) } - onKueryChange={(kuery) => - push(history, { - query: { - kuery, - }, - }) + onKueryChange={(value) => + push(history, { query: { kuery: value } }) } defaultSearchQueries={apmQueries} onStatusChange={setAlertStatusFilter} diff --git a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx index fa152cbe49894..5e98e40525a67 100644 --- a/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx +++ b/x-pack/plugins/apm/public/components/routing/templates/apm_service_template/index.tsx @@ -234,7 +234,7 @@ function useTabs({ selectedTab }: { selectedTab: Tab['key'] }) { } ); }, - [serviceName, start, end] + [serviceName, start, end, environment] ); const query = omit(