From 2711784ff5c5ae998218d9d6e4b119ba27c54ab9 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Mon, 12 Aug 2024 11:17:53 +0200 Subject: [PATCH 01/20] create new investigation, save, reload --- .../src/field_maps/alert_field_map.ts | 6 ++ .../src/default_alerts_as_data.ts | 4 + .../investigate_app/common/schema/create.ts | 6 +- .../common/schema/investigation.ts | 7 +- .../investigate_app/public/application.tsx | 7 +- .../public/hooks/query_key_factory.ts | 15 ++++ .../public/hooks/use_get_alert_details.tsx | 69 +++++++++++++++++ .../hooks/use_get_investigation_details.tsx | 68 +++++++++++++++++ .../public/pages/details/index.tsx | 71 +++++++++++++++-- .../server/models/investigation.ts | 7 +- .../server/services/create_investigation.ts | 7 +- .../observability/kibana.jsonc | 1 + .../components/header_actions.tsx | 74 ++++++++++++++++++ .../hooks/use_create_investigation.tsx | 47 ++++++++++++ .../hooks/use_update_investigation_ids.tsx | 52 +++++++++++++ .../observability/public/plugin.ts | 2 + .../server/alert_data_client/alerts_client.ts | 26 +++++++ .../rule_registry/server/routes/index.ts | 2 + .../routes/update_alert_investigation_ids.ts | 76 +++++++++++++++++++ 19 files changed, 536 insertions(+), 11 deletions(-) create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx create mode 100644 x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx create mode 100644 x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_create_investigation.tsx create mode 100644 x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_update_investigation_ids.tsx create mode 100644 x-pack/plugins/rule_registry/server/routes/update_alert_investigation_ids.ts diff --git a/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts b/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts index 6893d6b32bd93..fe703a416da17 100644 --- a/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts +++ b/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts @@ -46,6 +46,7 @@ import { EVENT_KIND, EVENT_ORIGINAL, TAGS, + ALERT_INVESTIGATION_IDS, } from '@kbn/rule-data-utils'; import { MultiField } from './types'; @@ -259,6 +260,11 @@ export const alertFieldMap = { array: false, required: false, }, + [ALERT_INVESTIGATION_IDS]: { + type: 'keyword', + array: false, + required: false, + }, } as const; export type AlertFieldMap = typeof alertFieldMap; diff --git a/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts b/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts index 4503679686bab..58731eaae0a16 100644 --- a/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts +++ b/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts @@ -118,6 +118,8 @@ const ALERT_URL = `${ALERT_NAMESPACE}.url` as const; // kibana.alert.rule.uuid - rule ID for rule that generated this alert const ALERT_RULE_UUID = `${ALERT_RULE_NAMESPACE}.uuid` as const; +const ALERT_INVESTIGATION_IDS = `${ALERT_NAMESPACE}.investigation_ids` as const; + const namespaces = { KIBANA_NAMESPACE, ALERT_NAMESPACE, @@ -160,6 +162,7 @@ const fields = { SPACE_IDS, TIMESTAMP, VERSION, + ALERT_INVESTIGATION_IDS, }; export { @@ -204,6 +207,7 @@ export { SPACE_IDS, TIMESTAMP, VERSION, + ALERT_INVESTIGATION_IDS, }; export type DefaultAlertFieldName = ValuesType; diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts b/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts index 050fa67d5cbaf..1b9d6b0257307 100644 --- a/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts +++ b/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts @@ -11,9 +11,13 @@ const createInvestigationParamsSchema = t.type({ body: t.type({ id: t.string, title: t.string, - parameters: t.type({ + params: t.type({ timeRange: t.type({ from: t.number, to: t.number }), }), + origin: t.type({ + type: t.string, + id: t.string, + }), }), }); diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts index 3046a5c4c6d8a..08ee17f140e50 100644 --- a/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts @@ -11,9 +11,14 @@ const investigationResponseSchema = t.type({ title: t.string, createdAt: t.number, createdBy: t.string, - parameters: t.type({ + params: t.type({ timeRange: t.type({ from: t.number, to: t.number }), }), + origin: t.type({ + type: t.string, + id: t.string, + }), + status: t.union([t.literal('ongoing'), t.literal('closed')]), }); type InvestigationResponse = t.OutputOf; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/application.tsx b/x-pack/plugins/observability_solution/investigate_app/public/application.tsx index 9b40b1523fefe..2f182173a1be6 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/application.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/application.tsx @@ -11,6 +11,7 @@ import type { History } from 'history'; import React, { useMemo } from 'react'; import type { Observable } from 'rxjs'; import { RouteRenderer, RouterProvider } from '@kbn/typed-react-router-config'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import type { InvestigateAppStartDependencies } from './types'; import { investigateRouter } from './routes/config'; import { InvestigateAppKibanaContext } from './hooks/use_kibana'; @@ -45,13 +46,17 @@ function Application({ [coreStart, pluginsStart, services] ); + const queryClient = new QueryClient(); + return ( - + + + diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts new file mode 100644 index 0000000000000..0dd56de8d13a8 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts @@ -0,0 +1,15 @@ +/* + * 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. + */ + +export const investigationKeys = { + all: ['investigation'] as const, + list: (params: { page: number; perPage: number }) => + [...investigationKeys.all, 'list', params] as const, + get: ['getInvestigation'] as const, +}; + +export type InvestigationKeys = typeof investigationKeys; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx new file mode 100644 index 0000000000000..7e10cd46afe0f --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx @@ -0,0 +1,69 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; +// import { investigationKeys } from './query_key_factory'; +import { BASE_RAC_ALERTS_API_PATH, EcsFieldsResponse } from '@kbn/rule-registry-plugin/common'; +import { useKibana } from './use_kibana'; + +export interface AlertParams { + id: string; +} + +export interface UseFetchAlertResponse { + isInitialLoading: boolean; + isLoading: boolean; + isRefetching: boolean; + isSuccess: boolean; + isError: boolean; + data: EcsFieldsResponse | undefined; +} + +export function useFetchAlert({ id }: AlertParams): UseFetchAlertResponse { + const { + core: { + http, + notifications: { toasts }, + }, + } = useKibana(); + + const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ + queryKey: ['fetchAlert', id], + queryFn: async ({ signal }) => { + if (id === '') return {}; + return await http.get(BASE_RAC_ALERTS_API_PATH, { + query: { + id, + }, + signal, + }); + }, + cacheTime: 0, + refetchOnWindowFocus: false, + retry: (failureCount, error) => { + if (String(error) === 'Error: Forbidden') { + return false; + } + + return failureCount < 3; + }, + onError: (error: Error) => { + toasts.addError(error, { + title: 'Something went wrong while fetching alert', + }); + }, + }); + + return { + data, + isInitialLoading, + isLoading, + isRefetching, + isSuccess, + isError, + }; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx new file mode 100644 index 0000000000000..5e3e543efe537 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx @@ -0,0 +1,68 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; +import { GetInvestigationResponse } from '../../common/schema/get'; +import { investigationKeys } from './query_key_factory'; +import { useKibana } from './use_kibana'; + +export interface InvestigationListParams { + id: string; +} + +export interface UseFetchInvestigationResponse { + isInitialLoading: boolean; + isLoading: boolean; + isRefetching: boolean; + isSuccess: boolean; + isError: boolean; + data: GetInvestigationResponse | undefined; +} + +export function useFetchInvestigation({ + id, +}: InvestigationListParams): UseFetchInvestigationResponse { + const { + core: { + http, + notifications: { toasts }, + }, + } = useKibana(); + + const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ + queryKey: investigationKeys.get, + queryFn: async ({ signal }) => { + return await http.get(`/api/observability/investigations/${id}`, { + version: '2023-10-31', + signal, + }); + }, + cacheTime: 0, + refetchOnWindowFocus: false, + retry: (failureCount, error) => { + if (String(error) === 'Error: Forbidden') { + return false; + } + + return failureCount < 3; + }, + onError: (error: Error) => { + toasts.addError(error, { + title: 'Something went wrong while fetching Investigation', + }); + }, + }); + + return { + data, + isInitialLoading, + isLoading, + isRefetching, + isSuccess, + isError, + }; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/index.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/index.tsx index e749799749321..8d0c46ec57130 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/index.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/index.tsx @@ -5,30 +5,89 @@ * 2.0. */ -import { EuiButton } from '@elastic/eui'; +import { EuiButton, EuiButtonEmpty, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; +import { ALERT_RULE_CATEGORY } from '@kbn/rule-data-utils/src/default_alerts_as_data'; import { InvestigateView } from '../../components/investigate_view'; import { useKibana } from '../../hooks/use_kibana'; +import { useFetchInvestigation } from '../../hooks/use_get_investigation_details'; +import { useInvestigateParams } from '../../hooks/use_investigate_params'; +import { useFetchAlert } from '../../hooks/use_get_alert_details'; export function InvestigateDetailsPage() { const { + core: { + http: { basePath }, + }, dependencies: { start: { observabilityShared }, }, } = useKibana(); + const { + path: { id }, + } = useInvestigateParams('/{id}'); + const ObservabilityPageTemplate = observabilityShared.navigation.PageTemplate; + const { + data: investigationDetails, + isLoading: isFetchInvestigationLoading, + isError: isFetchInvestigationError, + } = useFetchInvestigation({ id }); + + const alertId = investigationDetails?.origin.id ?? ''; + + const { + data: alertDetails, + isLoading: isFetchAlertLoading, + isError: isFetchAlertError, + } = useFetchAlert({ id: alertId }); + + if (isFetchInvestigationLoading || isFetchAlertLoading) { + return ( +

+ {i18n.translate('xpack.investigateApp.fetchInvestigation.loadingLabel', { + defaultMessage: 'Loading...', + })} +

+ ); + } + + if (isFetchInvestigationError || isFetchAlertError) { + return ( +

+ {i18n.translate('xpack.investigateApp.fetchInvestigation.errorLabel', { + defaultMessage: 'Error while fetching investigation', + })} +

+ ); + } + return ( + {alertDetails && ( + + + {`[Alert] ${alertDetails?.[ALERT_RULE_CATEGORY]} breached`} + + + )} + {investigationDetails &&
{investigationDetails.title}
} + + ), rightSideItems: [ - - {i18n.translate('xpack.investigateApp.investigateDetailsPage.escalateButtonLabel', { + + {i18n.translate('xpack.investigateApp.investigationDetails.escalateButtonLabel', { defaultMessage: 'Escalate', })} , diff --git a/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts index f079d922d1a9d..e54e331302fa7 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts @@ -12,9 +12,14 @@ export const investigationSchema = t.type({ title: t.string, createdAt: t.number, createdBy: t.string, - parameters: t.type({ + params: t.type({ timeRange: t.type({ from: t.number, to: t.number }), }), + origin: t.type({ + type: t.string, + id: t.string, + }), + status: t.union([t.literal('ongoing'), t.literal('closed')]), }); export type Investigation = t.TypeOf; diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts index 9d28136c06f6c..8fd926a3f5638 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts @@ -12,7 +12,12 @@ export async function createInvestigation( params: CreateInvestigationInput, repository: InvestigationRepository ): Promise { - const investigation = { ...params, createdAt: Date.now(), createdBy: 'elastic' }; + const investigation = { + ...params, + createdAt: Date.now(), + createdBy: 'elastic', + status: 'ongoing' as const, + }; await repository.save(investigation); return investigation; diff --git a/x-pack/plugins/observability_solution/observability/kibana.jsonc b/x-pack/plugins/observability_solution/observability/kibana.jsonc index 997b6196def4b..8e97ea707641d 100644 --- a/x-pack/plugins/observability_solution/observability/kibana.jsonc +++ b/x-pack/plugins/observability_solution/observability/kibana.jsonc @@ -51,6 +51,7 @@ "serverless", "guidedOnboarding", "observabilityAIAssistant", + "investigate" ], "requiredBundles": [ "data", diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx index 3d47e34002945..460579750224e 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx @@ -25,13 +25,21 @@ import { ALERT_RULE_UUID, ALERT_STATUS_ACTIVE, ALERT_UUID, + ALERT_INVESTIGATION_IDS, + ALERT_RULE_CATEGORY, + ALERT_START, + ALERT_END, } from '@kbn/rule-data-utils'; +import { v4 as uuidv4 } from 'uuid'; +import { getPaddedAlertTimeRange } from '@kbn/observability-get-padded-alert-time-range-util'; import { useKibana } from '../../../utils/kibana_react'; import { useFetchRule } from '../../../hooks/use_fetch_rule'; import type { TopAlert } from '../../../typings/alerts'; import { paths } from '../../../../common/locators/paths'; import { useBulkUntrackAlerts } from '../hooks/use_bulk_untrack_alerts'; +import { useCreateInvestigation } from '../hooks/use_create_investigation'; +import { useUpdateInvestigationIds } from '../hooks/use_update_investigation_ids'; export interface HeaderActionsProps { alert: TopAlert | null; @@ -52,12 +60,16 @@ export function HeaderActions({ }, triggersActionsUi: { getEditRuleFlyout: EditRuleFlyout, getRuleSnoozeModal: RuleSnoozeModal }, http, + application: { navigateToApp }, + investigate, } = useKibana().services; const { rule, refetch } = useFetchRule({ ruleId: alert?.fields[ALERT_RULE_UUID] || '', }); + const investigationId = alert?.fields[ALERT_INVESTIGATION_IDS] ?? 'new'; + const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [ruleConditionsFlyoutOpen, setRuleConditionsFlyoutOpen] = useState(false); const [snoozeModalOpen, setSnoozeModalOpen] = useState(false); @@ -109,9 +121,71 @@ export function HeaderActions({ setSnoozeModalOpen(true); }; + const { mutateAsync: createInvestigation } = useCreateInvestigation(); + const { mutateAsync: updateInvestigationIds } = useUpdateInvestigationIds(); + + const alertStart = alert?.fields[ALERT_START]; + const alertEnd = alert?.fields[ALERT_END]; + + const createOrOpenInvestigation = async () => { + if (!alert) return; + + if (!alert.fields[ALERT_INVESTIGATION_IDS]) { + const paddedAlertTimeRange = getPaddedAlertTimeRange(alertStart!, alertEnd); + + const investigationResponse = await createInvestigation({ + investigation: { + id: uuidv4(), + title: `Investigate ${alert.fields[ALERT_RULE_CATEGORY]} breached`, + params: { + timeRange: { + from: new Date(paddedAlertTimeRange.from).getTime(), + to: new Date(paddedAlertTimeRange.to).getTime(), + }, + }, + origin: { + type: 'alert', + id: alert.fields[ALERT_UUID] ?? '', + }, + }, + }); + + updateInvestigationIds({ + index: alertIndex ?? '', + alertUuid: alert.fields[ALERT_UUID], + investigationIds: [investigationResponse.id], + }); + + navigateToApp('investigate', { path: `/${investigationResponse.id}`, replace: false }); + } else { + navigateToApp('investigate', { + path: `/${alert?.fields[ALERT_INVESTIGATION_IDS]}`, + replace: false, + }); + } + }; + return ( <> + {investigate && ( + + { + createOrOpenInvestigation(); + }} + fill + data-test-subj="investigate-alert-button" + > + + {i18n.translate('xpack.observability.alertDetails.investigateAlert', { + defaultMessage: + investigationId === 'new' ? 'Start investigation' : 'Ongoing investigation', + })} + + + + )} ; + +export function useCreateInvestigation() { + const { + http, + notifications: { toasts }, + } = useKibana().services; + + return useMutation< + CreateInvestigationResponse, + ServerError, + { investigation: CreateInvestigationInput }, + { previousData?: FindInvestigationsResponse; queryKey?: QueryKey } + >( + ['createInvestigation'], + ({ investigation }) => { + const body = JSON.stringify(investigation); + return http.post(`/api/observability/investigations`, { body }); + }, + { + onError: (error, { investigation }, context) => { + toasts.addError(new Error(error.body?.message ?? error.message), { + title: i18n.translate('xpack.observability.create.errorNotification', { + defaultMessage: 'Something went wrong while creating investigation', + }), + }); + }, + } + ); +} diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_update_investigation_ids.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_update_investigation_ids.tsx new file mode 100644 index 0000000000000..6a0f32eba88b7 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_update_investigation_ids.tsx @@ -0,0 +1,52 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import { useMutation } from '@tanstack/react-query'; +import { BASE_RAC_ALERTS_API_PATH } from '@kbn/alerts-ui-shared/src/common/constants'; +import { useKibana } from '../../../utils/kibana_react'; + +export const useUpdateInvestigationIds = () => { + const { + http, + notifications: { toasts }, + } = useKibana().services; + + const updateInvestigationIds = useMutation< + string, + string, + { index: string; alertUuid: string; investigationIds: string[] } + >( + ['updateInvestigationIds'], + ({ index, alertUuid, investigationIds }) => { + try { + const body = JSON.stringify({ + index, + alertUuid, + investigationIds, + }); + return http.post(`${BASE_RAC_ALERTS_API_PATH}/_update_investigaion_ids`, { body }); + } catch (e) { + throw new Error(`Unable to parse update investigaion ids params: ${e}`); + } + }, + { + onError: (_err, params) => { + toasts.addDanger( + i18n.translate( + 'xpack.observability.alerts.updateInvestigationIds.errorNotification.descriptionText', + { + defaultMessage: 'Failed to update investigaion ids', + } + ) + ); + }, + } + ); + + return updateInvestigationIds; +}; diff --git a/x-pack/plugins/observability_solution/observability/public/plugin.ts b/x-pack/plugins/observability_solution/observability/public/plugin.ts index a97085f0c036d..b2d0e526f3c64 100644 --- a/x-pack/plugins/observability_solution/observability/public/plugin.ts +++ b/x-pack/plugins/observability_solution/observability/public/plugin.ts @@ -70,6 +70,7 @@ import type { NavigationPublicPluginStart } from '@kbn/navigation-plugin/public' import type { PresentationUtilPluginStart } from '@kbn/presentation-util-plugin/public'; import { DataViewFieldEditorStart } from '@kbn/data-view-field-editor-plugin/public'; import { LicenseManagementUIPluginSetup } from '@kbn/license-management-plugin/public'; +import { InvestigatePublicStart } from '@kbn/investigate-plugin/public'; import { observabilityAppId, observabilityFeatureId } from '../common'; import { ALERTS_PATH, @@ -161,6 +162,7 @@ export interface ObservabilityPublicPluginsStart { theme: CoreStart['theme']; dataViewFieldEditor: DataViewFieldEditorStart; toastNotifications: ToastsStart; + investigate?: InvestigatePublicStart; } export type ObservabilityPublicStart = ReturnType; diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts index 4dac5ff413909..69cdf6d8496e2 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts @@ -22,6 +22,7 @@ import { ALERT_END, ALERT_STATUS_ACTIVE, ALERT_CASE_IDS, + ALERT_INVESTIGATION_IDS, MAX_CASES_PER_ALERT, AlertConsumers, } from '@kbn/rule-data-utils'; @@ -114,6 +115,11 @@ interface MgetAndAuditAlert { index: string; } +export interface UpdateInvestigaionOptions { + alert: MgetAndAuditAlert; + investigationIds: string[]; +} + export interface BulkUpdateCasesOptions { alerts: MgetAndAuditAlert[]; caseIds: string[]; @@ -596,6 +602,18 @@ export class AlertsClient { } } + private getAlertInvestigationIdsFieldUpdate( + source: ParsedTechnicalFields | undefined, + investigationIds: string[] + ) { + const uniqueInvestigationIds = new Set([ + ...(source?.[ALERT_INVESTIGATION_IDS] ?? []), + ...investigationIds, + ]); + + return { [ALERT_INVESTIGATION_IDS]: Array.from(uniqueInvestigationIds.values()) }; + } + public async ensureAllAlertsAuthorizedRead({ alerts }: { alerts: MgetAndAuditAlert[] }) { try { await this.ensureAllAlertsAuthorized({ alerts, operation: ReadOperations.Get }); @@ -1245,4 +1263,12 @@ export class AlertsClient { return fields; } + + public async updateInvestigationIds({ alert, investigationIds }: UpdateInvestigaionOptions) { + return this.mgetAlertsAuditOperate({ + alerts: [alert], + operation: WriteOperations.Update, + fieldToUpdate: (source) => this.getAlertInvestigationIdsFieldUpdate(source, investigationIds), + }); + } } diff --git a/x-pack/plugins/rule_registry/server/routes/index.ts b/x-pack/plugins/rule_registry/server/routes/index.ts index ae9f113ee0ac1..4b4ab99897178 100644 --- a/x-pack/plugins/rule_registry/server/routes/index.ts +++ b/x-pack/plugins/rule_registry/server/routes/index.ts @@ -17,6 +17,7 @@ import { getFeatureIdsByRegistrationContexts } from './get_feature_ids_by_regist import { getBrowserFieldsByFeatureId } from './get_browser_fields_by_feature_id'; import { getAlertSummaryRoute } from './get_alert_summary'; import { getAADFieldsByRuleType } from './get_aad_fields_by_rule_type'; +import { updateAlertInvestigationIdsRoute } from './update_alert_investigation_ids'; export function defineRoutes(router: IRouter) { getAlertByIdRoute(router); @@ -29,4 +30,5 @@ export function defineRoutes(router: IRouter) { getBrowserFieldsByFeatureId(router); getAlertSummaryRoute(router); getAADFieldsByRuleType(router); + updateAlertInvestigationIdsRoute(router); } diff --git a/x-pack/plugins/rule_registry/server/routes/update_alert_investigation_ids.ts b/x-pack/plugins/rule_registry/server/routes/update_alert_investigation_ids.ts new file mode 100644 index 0000000000000..065768edc41ed --- /dev/null +++ b/x-pack/plugins/rule_registry/server/routes/update_alert_investigation_ids.ts @@ -0,0 +1,76 @@ +/* + * 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 { IRouter } from '@kbn/core/server'; +import * as t from 'io-ts'; +import { transformError } from '@kbn/securitysolution-es-utils'; + +import { buildRouteValidation } from './utils/route_validation'; +import { RacRequestHandlerContext } from '../types'; +import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; + +export const updateAlertInvestigationIdsRoute = (router: IRouter) => { + router.post( + { + path: `${BASE_RAC_ALERTS_API_PATH}/_update_investigaion_ids`, + validate: { + body: buildRouteValidation( + t.exact( + t.type({ + investigationIds: t.array(t.string), + alertUuid: t.string, + index: t.string, + }) + ) + ), + }, + options: { + tags: ['access:rac'], + }, + }, + async (context, req, response) => { + try { + const racContext = await context.rac; + const alertsClient = await racContext.getAlertsClient(); + const { investigationIds, alertUuid, index } = req.body; + + const updatedAlert = await alertsClient.updateInvestigationIds({ + alert: { id: alertUuid, index }, + investigationIds, + }); + + if (updatedAlert == null) { + return response.notFound({ + body: { message: `alert with id ${alertUuid} and index ${index} not found` }, + }); + } + + return response.ok({ body: { success: true, ...updatedAlert } }); + } catch (exc) { + const err = transformError(exc); + + const contentType = { + 'content-type': 'application/json', + }; + const defaultedHeaders = { + ...contentType, + }; + + return response.customError({ + headers: defaultedHeaders, + statusCode: err.statusCode, + body: { + message: err.message, + attributes: { + success: false, + }, + }, + }); + } + } + ); +}; From 947e5d3a5f88f42cdf804e70170b0d211b1255d5 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Mon, 12 Aug 2024 11:39:08 +0200 Subject: [PATCH 02/20] remove comment --- .../investigate_app/public/hooks/use_get_alert_details.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx index 7e10cd46afe0f..328f70ec76377 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx @@ -6,7 +6,6 @@ */ import { useQuery } from '@tanstack/react-query'; -// import { investigationKeys } from './query_key_factory'; import { BASE_RAC_ALERTS_API_PATH, EcsFieldsResponse } from '@kbn/rule-registry-plugin/common'; import { useKibana } from './use_kibana'; @@ -34,7 +33,6 @@ export function useFetchAlert({ id }: AlertParams): UseFetchAlertResponse { const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ queryKey: ['fetchAlert', id], queryFn: async ({ signal }) => { - if (id === '') return {}; return await http.get(BASE_RAC_ALERTS_API_PATH, { query: { id, From f1c7e9eb9e8bf286073f612dd113db5ff0c02cf1 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Mon, 12 Aug 2024 12:13:04 +0200 Subject: [PATCH 03/20] chnage origin type --- .../investigate_app/common/schema/create.ts | 2 +- .../investigate_app/common/schema/investigation.ts | 2 +- .../investigate_app/server/models/investigation.ts | 2 +- .../public/pages/alert_details/components/header_actions.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts b/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts index 1b9d6b0257307..f6f4654b6cce1 100644 --- a/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts +++ b/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts @@ -15,7 +15,7 @@ const createInvestigationParamsSchema = t.type({ timeRange: t.type({ from: t.number, to: t.number }), }), origin: t.type({ - type: t.string, + type: t.union([t.literal('alert'), t.literal('blank')]), id: t.string, }), }), diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts index 08ee17f140e50..f69632ddb8cee 100644 --- a/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts @@ -15,7 +15,7 @@ const investigationResponseSchema = t.type({ timeRange: t.type({ from: t.number, to: t.number }), }), origin: t.type({ - type: t.string, + type: t.union([t.literal('alert'), t.literal('blank')]), id: t.string, }), status: t.union([t.literal('ongoing'), t.literal('closed')]), diff --git a/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts index e54e331302fa7..14a8c4eba57c4 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts @@ -16,7 +16,7 @@ export const investigationSchema = t.type({ timeRange: t.type({ from: t.number, to: t.number }), }), origin: t.type({ - type: t.string, + type: t.union([t.literal('alert'), t.literal('blank')]), id: t.string, }), status: t.union([t.literal('ongoing'), t.literal('closed')]), diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx index 460579750224e..81ac201f371ed 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx @@ -145,7 +145,7 @@ export function HeaderActions({ }, origin: { type: 'alert', - id: alert.fields[ALERT_UUID] ?? '', + id: alert.fields[ALERT_UUID], }, }, }); From 315932e764489099dc38245e1b1eade6b68a5abe Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Mon, 12 Aug 2024 12:21:31 +0200 Subject: [PATCH 04/20] only show investigation for custom threshold alert --- .../components/header_actions.tsx | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx index 81ac201f371ed..574e0891e8b80 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx @@ -29,6 +29,8 @@ import { ALERT_RULE_CATEGORY, ALERT_START, ALERT_END, + ALERT_RULE_TYPE_ID, + OBSERVABILITY_THRESHOLD_RULE_TYPE_ID, } from '@kbn/rule-data-utils'; import { v4 as uuidv4 } from 'uuid'; @@ -168,24 +170,25 @@ export function HeaderActions({ return ( <> - {investigate && ( - - { - createOrOpenInvestigation(); - }} - fill - data-test-subj="investigate-alert-button" - > - - {i18n.translate('xpack.observability.alertDetails.investigateAlert', { - defaultMessage: - investigationId === 'new' ? 'Start investigation' : 'Ongoing investigation', - })} - - - - )} + {investigate && + alert?.fields[ALERT_RULE_TYPE_ID] === OBSERVABILITY_THRESHOLD_RULE_TYPE_ID && ( + + { + createOrOpenInvestigation(); + }} + fill + data-test-subj="investigate-alert-button" + > + + {i18n.translate('xpack.observability.alertDetails.investigateAlert', { + defaultMessage: + investigationId === 'new' ? 'Start investigation' : 'Ongoing investigation', + })} + + + + )} Date: Mon, 12 Aug 2024 10:42:53 +0000 Subject: [PATCH 05/20] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- .../observability_solution/investigate_app/tsconfig.json | 2 ++ .../plugins/observability_solution/observability/tsconfig.json | 2 ++ 2 files changed, 4 insertions(+) diff --git a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json index b4b586601ebaa..6647b16356984 100644 --- a/x-pack/plugins/observability_solution/investigate_app/tsconfig.json +++ b/x-pack/plugins/observability_solution/investigate_app/tsconfig.json @@ -52,5 +52,7 @@ "@kbn/esql-datagrid", "@kbn/server-route-repository-utils", "@kbn/core-saved-objects-server", + "@kbn/rule-registry-plugin", + "@kbn/rule-data-utils", ], } diff --git a/x-pack/plugins/observability_solution/observability/tsconfig.json b/x-pack/plugins/observability_solution/observability/tsconfig.json index 28f06a81d17c0..90074bf35d264 100644 --- a/x-pack/plugins/observability_solution/observability/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability/tsconfig.json @@ -110,6 +110,8 @@ "@kbn/license-management-plugin", "@kbn/observability-alerting-rule-utils", "@kbn/core-ui-settings-server-mocks", + "@kbn/investigate-app-plugin", + "@kbn/investigate-plugin", ], "exclude": [ "target/**/*" From 6fb3bf690de5c723bf0ebef3cff9387b269a2df1 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 10:42:41 +0200 Subject: [PATCH 06/20] get investigation ids from saved object --- .../common/schema/find_by_alert.ts | 24 ++++++ ...investigate_app_server_route_repository.ts | 17 +++++ .../server/saved_objects/investigation.ts | 7 +- .../services/find_investigation_by_alert.ts | 22 ++++++ .../services/investigation_repository.ts | 21 +++++ .../components/header_actions.tsx | 22 +++--- .../hooks/use_get_investigation_details.tsx | 68 +++++++++++++++++ .../hooks/use_update_investigation_ids.tsx | 52 ------------- .../rule_registry/server/routes/index.ts | 2 - .../routes/update_alert_investigation_ids.ts | 76 ------------------- 10 files changed, 167 insertions(+), 144 deletions(-) create mode 100644 x-pack/plugins/observability_solution/investigate_app/common/schema/find_by_alert.ts create mode 100644 x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts create mode 100644 x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_get_investigation_details.tsx delete mode 100644 x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_update_investigation_ids.tsx delete mode 100644 x-pack/plugins/rule_registry/server/routes/update_alert_investigation_ids.ts diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/find_by_alert.ts b/x-pack/plugins/observability_solution/investigate_app/common/schema/find_by_alert.ts new file mode 100644 index 0000000000000..76091f994492f --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/common/schema/find_by_alert.ts @@ -0,0 +1,24 @@ +/* + * 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 * as t from 'io-ts'; +import { investigationResponseSchema } from './investigation'; + +const findInvestigationsByAlertParamsSchema = t.type({ + path: t.type({ + alertId: t.string, + }), +}); + +const findInvestigationsByAlertResponseSchema = t.array(investigationResponseSchema); + +type FindInvestigationsByAlertParams = t.TypeOf< + typeof findInvestigationsByAlertParamsSchema.props.path +>; // Parsed payload used by the backend +type FindInvestigationsByAlertResponse = t.OutputOf; // Raw response sent to the frontend + +export { findInvestigationsByAlertParamsSchema, findInvestigationsByAlertResponseSchema }; +export type { FindInvestigationsByAlertParams, FindInvestigationsByAlertResponse }; diff --git a/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts b/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts index 7565330316fed..5960aa9778742 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { findInvestigationsByAlertParamsSchema } from '../../common/schema/find_by_alert'; import { findInvestigationsParamsSchema } from '../../common/schema/find'; import { createInvestigationParamsSchema } from '../../common/schema/create'; import { createInvestigation } from '../services/create_investigation'; @@ -13,6 +14,7 @@ import { createInvestigateAppServerRoute } from './create_investigate_app_server import { findInvestigations } from '../services/find_investigations'; import { getInvestigationParamsSchema } from '../../common/schema/get'; import { getInvestigation } from '../services/get_investigation'; +import { findInvestigationsByAlert } from '../services/find_investigation_by_alert'; const createInvestigationRoute = createInvestigateAppServerRoute({ endpoint: 'POST /api/observability/investigations 2023-10-31', @@ -42,6 +44,20 @@ const findInvestigationsRoute = createInvestigateAppServerRoute({ }, }); +const findInvestigationsByAlertRoute = createInvestigateAppServerRoute({ + endpoint: 'GET /api/observability/investigations/alert/{alertId} 2023-10-31', + options: { + tags: [], + }, + params: findInvestigationsByAlertParamsSchema, + handler: async (params) => { + const soClient = (await params.context.core).savedObjects.client; + const repository = investigationRepositoryFactory({ soClient, logger: params.logger }); + + return await findInvestigationsByAlert(params.params.path, repository); + }, +}); + const getInvestigationRoute = createInvestigateAppServerRoute({ endpoint: 'GET /api/observability/investigations/{id} 2023-10-31', options: { @@ -61,6 +77,7 @@ export function getGlobalInvestigateAppServerRouteRepository() { ...createInvestigationRoute, ...findInvestigationsRoute, ...getInvestigationRoute, + ...findInvestigationsByAlertRoute, }; } diff --git a/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts index 47fa9f17749c1..3bf8dde5c70e2 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts @@ -15,12 +15,17 @@ export const investigation: SavedObjectsType = { name: SO_INVESTIGATION_TYPE, hidden: false, namespaceType: 'multiple-isolated', - switchToModelVersionAt: '8.10.0', mappings: { dynamic: false, properties: { id: { type: 'keyword' }, title: { type: 'text' }, + origin: { + properties: { + type: { type: 'keyword' }, + id: { type: 'keyword' }, + }, + }, }, }, management: { diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts new file mode 100644 index 0000000000000..ae093960d9f0e --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts @@ -0,0 +1,22 @@ +/* + * 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 { + FindInvestigationsByAlertParams, + FindInvestigationsByAlertResponse, + findInvestigationsByAlertResponseSchema, +} from '../../common/schema/find_by_alert'; +import { InvestigationRepository } from './investigation_repository'; + +export async function findInvestigationsByAlert( + params: FindInvestigationsByAlertParams, + repository: InvestigationRepository +): Promise { + const investigations = await repository.findByAlertId(params.alertId); + + return findInvestigationsByAlertResponseSchema.encode(investigations); +} diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts index 6d9c5ddbc0d03..96b5e43611cea 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts @@ -14,6 +14,7 @@ import { Paginated, Pagination } from '../models/pagination'; export interface InvestigationRepository { save(investigation: Investigation): Promise; findById(id: string): Promise; + findByAlertId(alertId: string): Promise; deleteById(id: string): Promise; search(pagination: Pagination): Promise>; } @@ -74,6 +75,26 @@ export function investigationRepositoryFactory({ return investigation; }, + async findByAlertId(alertId: string): Promise { + const response = await soClient.find({ + type: SO_INVESTIGATION_TYPE, + filter: `investigation.attributes.origin.id:(${alertId})`, + }); + + if (response.total === 0) { + return []; + } + + const investigations: Investigation[] = []; + + response.saved_objects.forEach((so) => { + const investigation = toInvestigation(so.attributes); + if (investigation !== undefined) investigations.push(investigation); + }); + + return investigations; + }, + async deleteById(id: string): Promise { const response = await soClient.find({ type: SO_INVESTIGATION_TYPE, diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx index 574e0891e8b80..ee668e1a8515d 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx @@ -25,7 +25,6 @@ import { ALERT_RULE_UUID, ALERT_STATUS_ACTIVE, ALERT_UUID, - ALERT_INVESTIGATION_IDS, ALERT_RULE_CATEGORY, ALERT_START, ALERT_END, @@ -41,7 +40,7 @@ import type { TopAlert } from '../../../typings/alerts'; import { paths } from '../../../../common/locators/paths'; import { useBulkUntrackAlerts } from '../hooks/use_bulk_untrack_alerts'; import { useCreateInvestigation } from '../hooks/use_create_investigation'; -import { useUpdateInvestigationIds } from '../hooks/use_update_investigation_ids'; +import { useFetchInvestigationsByAlert } from '../hooks/use_get_investigation_details'; export interface HeaderActionsProps { alert: TopAlert | null; @@ -70,7 +69,9 @@ export function HeaderActions({ ruleId: alert?.fields[ALERT_RULE_UUID] || '', }); - const investigationId = alert?.fields[ALERT_INVESTIGATION_IDS] ?? 'new'; + const { data: investigations } = useFetchInvestigationsByAlert({ + alertId: alert?.fields[ALERT_UUID] ?? '', + }); const [isPopoverOpen, setIsPopoverOpen] = useState(false); const [ruleConditionsFlyoutOpen, setRuleConditionsFlyoutOpen] = useState(false); @@ -124,7 +125,6 @@ export function HeaderActions({ }; const { mutateAsync: createInvestigation } = useCreateInvestigation(); - const { mutateAsync: updateInvestigationIds } = useUpdateInvestigationIds(); const alertStart = alert?.fields[ALERT_START]; const alertEnd = alert?.fields[ALERT_END]; @@ -132,7 +132,7 @@ export function HeaderActions({ const createOrOpenInvestigation = async () => { if (!alert) return; - if (!alert.fields[ALERT_INVESTIGATION_IDS]) { + if (!investigations || investigations.length === 0) { const paddedAlertTimeRange = getPaddedAlertTimeRange(alertStart!, alertEnd); const investigationResponse = await createInvestigation({ @@ -152,16 +152,10 @@ export function HeaderActions({ }, }); - updateInvestigationIds({ - index: alertIndex ?? '', - alertUuid: alert.fields[ALERT_UUID], - investigationIds: [investigationResponse.id], - }); - navigateToApp('investigate', { path: `/${investigationResponse.id}`, replace: false }); } else { navigateToApp('investigate', { - path: `/${alert?.fields[ALERT_INVESTIGATION_IDS]}`, + path: `/${investigations[0].id}`, replace: false, }); } @@ -183,7 +177,9 @@ export function HeaderActions({ {i18n.translate('xpack.observability.alertDetails.investigateAlert', { defaultMessage: - investigationId === 'new' ? 'Start investigation' : 'Ongoing investigation', + !investigations || investigations.length === 0 + ? 'Start investigation' + : 'Ongoing investigation', })} diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_get_investigation_details.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_get_investigation_details.tsx new file mode 100644 index 0000000000000..8b84e96243728 --- /dev/null +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_get_investigation_details.tsx @@ -0,0 +1,68 @@ +/* + * 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 { useQuery } from '@tanstack/react-query'; +import { FindInvestigationsByAlertResponse } from '@kbn/investigate-app-plugin/common/schema/find_by_alert'; +import { useKibana } from '../../../utils/kibana_react'; + +export interface InvestigationsByAlertParams { + alertId: string; +} + +export interface UseFetchInvestigationsByAlertResponse { + isInitialLoading: boolean; + isLoading: boolean; + isRefetching: boolean; + isSuccess: boolean; + isError: boolean; + data: FindInvestigationsByAlertResponse | undefined; +} + +export function useFetchInvestigationsByAlert({ + alertId, +}: InvestigationsByAlertParams): UseFetchInvestigationsByAlertResponse { + const { + http, + notifications: { toasts }, + } = useKibana().services; + + const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ + queryKey: ['fetchInvestigationsByAlert', alertId], + queryFn: async ({ signal }) => { + return await http.get( + `/api/observability/investigations/alert/${alertId}`, + { + version: '2023-10-31', + signal, + } + ); + }, + cacheTime: 0, + refetchOnWindowFocus: false, + retry: (failureCount, error) => { + if (String(error) === 'Error: Forbidden') { + return false; + } + + return failureCount < 3; + }, + onError: (error: Error) => { + toasts.addError(error, { + title: 'Something went wrong while fetching Investigations', + }); + }, + }); + + return { + data, + isInitialLoading, + isLoading, + isRefetching, + isSuccess, + isError, + }; +} diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_update_investigation_ids.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_update_investigation_ids.tsx deleted file mode 100644 index 6a0f32eba88b7..0000000000000 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_update_investigation_ids.tsx +++ /dev/null @@ -1,52 +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 { i18n } from '@kbn/i18n'; -import { useMutation } from '@tanstack/react-query'; -import { BASE_RAC_ALERTS_API_PATH } from '@kbn/alerts-ui-shared/src/common/constants'; -import { useKibana } from '../../../utils/kibana_react'; - -export const useUpdateInvestigationIds = () => { - const { - http, - notifications: { toasts }, - } = useKibana().services; - - const updateInvestigationIds = useMutation< - string, - string, - { index: string; alertUuid: string; investigationIds: string[] } - >( - ['updateInvestigationIds'], - ({ index, alertUuid, investigationIds }) => { - try { - const body = JSON.stringify({ - index, - alertUuid, - investigationIds, - }); - return http.post(`${BASE_RAC_ALERTS_API_PATH}/_update_investigaion_ids`, { body }); - } catch (e) { - throw new Error(`Unable to parse update investigaion ids params: ${e}`); - } - }, - { - onError: (_err, params) => { - toasts.addDanger( - i18n.translate( - 'xpack.observability.alerts.updateInvestigationIds.errorNotification.descriptionText', - { - defaultMessage: 'Failed to update investigaion ids', - } - ) - ); - }, - } - ); - - return updateInvestigationIds; -}; diff --git a/x-pack/plugins/rule_registry/server/routes/index.ts b/x-pack/plugins/rule_registry/server/routes/index.ts index 4b4ab99897178..ae9f113ee0ac1 100644 --- a/x-pack/plugins/rule_registry/server/routes/index.ts +++ b/x-pack/plugins/rule_registry/server/routes/index.ts @@ -17,7 +17,6 @@ import { getFeatureIdsByRegistrationContexts } from './get_feature_ids_by_regist import { getBrowserFieldsByFeatureId } from './get_browser_fields_by_feature_id'; import { getAlertSummaryRoute } from './get_alert_summary'; import { getAADFieldsByRuleType } from './get_aad_fields_by_rule_type'; -import { updateAlertInvestigationIdsRoute } from './update_alert_investigation_ids'; export function defineRoutes(router: IRouter) { getAlertByIdRoute(router); @@ -30,5 +29,4 @@ export function defineRoutes(router: IRouter) { getBrowserFieldsByFeatureId(router); getAlertSummaryRoute(router); getAADFieldsByRuleType(router); - updateAlertInvestigationIdsRoute(router); } diff --git a/x-pack/plugins/rule_registry/server/routes/update_alert_investigation_ids.ts b/x-pack/plugins/rule_registry/server/routes/update_alert_investigation_ids.ts deleted file mode 100644 index 065768edc41ed..0000000000000 --- a/x-pack/plugins/rule_registry/server/routes/update_alert_investigation_ids.ts +++ /dev/null @@ -1,76 +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 { IRouter } from '@kbn/core/server'; -import * as t from 'io-ts'; -import { transformError } from '@kbn/securitysolution-es-utils'; - -import { buildRouteValidation } from './utils/route_validation'; -import { RacRequestHandlerContext } from '../types'; -import { BASE_RAC_ALERTS_API_PATH } from '../../common/constants'; - -export const updateAlertInvestigationIdsRoute = (router: IRouter) => { - router.post( - { - path: `${BASE_RAC_ALERTS_API_PATH}/_update_investigaion_ids`, - validate: { - body: buildRouteValidation( - t.exact( - t.type({ - investigationIds: t.array(t.string), - alertUuid: t.string, - index: t.string, - }) - ) - ), - }, - options: { - tags: ['access:rac'], - }, - }, - async (context, req, response) => { - try { - const racContext = await context.rac; - const alertsClient = await racContext.getAlertsClient(); - const { investigationIds, alertUuid, index } = req.body; - - const updatedAlert = await alertsClient.updateInvestigationIds({ - alert: { id: alertUuid, index }, - investigationIds, - }); - - if (updatedAlert == null) { - return response.notFound({ - body: { message: `alert with id ${alertUuid} and index ${index} not found` }, - }); - } - - return response.ok({ body: { success: true, ...updatedAlert } }); - } catch (exc) { - const err = transformError(exc); - - const contentType = { - 'content-type': 'application/json', - }; - const defaultedHeaders = { - ...contentType, - }; - - return response.customError({ - headers: defaultedHeaders, - statusCode: err.statusCode, - body: { - message: err.message, - attributes: { - success: false, - }, - }, - }); - } - } - ); -}; From b541f88548dbd5749a3c5c6e3007ed62cc22f4ba Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 10:50:04 +0200 Subject: [PATCH 07/20] check alertid not null --- .../investigate_app/public/hooks/use_get_alert_details.tsx | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx index 328f70ec76377..954498e624937 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx @@ -19,7 +19,7 @@ export interface UseFetchAlertResponse { isRefetching: boolean; isSuccess: boolean; isError: boolean; - data: EcsFieldsResponse | undefined; + data: EcsFieldsResponse | undefined | null; } export function useFetchAlert({ id }: AlertParams): UseFetchAlertResponse { @@ -33,6 +33,8 @@ export function useFetchAlert({ id }: AlertParams): UseFetchAlertResponse { const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ queryKey: ['fetchAlert', id], queryFn: async ({ signal }) => { + if (id === '') return null; + return await http.get(BASE_RAC_ALERTS_API_PATH, { query: { id, From a030afe9416ea4ff542d24e31e5476fa37d006b0 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 11:12:38 +0200 Subject: [PATCH 08/20] filter investigations by status --- .../investigate_app/server/saved_objects/investigation.ts | 1 + .../investigate_app/server/services/investigation_repository.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts index 3bf8dde5c70e2..eeb937fb16cfa 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/saved_objects/investigation.ts @@ -26,6 +26,7 @@ export const investigation: SavedObjectsType = { id: { type: 'keyword' }, }, }, + status: { type: 'keyword' }, }, }, management: { diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts index 96b5e43611cea..81d9f81cb2c3b 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts @@ -78,7 +78,7 @@ export function investigationRepositoryFactory({ async findByAlertId(alertId: string): Promise { const response = await soClient.find({ type: SO_INVESTIGATION_TYPE, - filter: `investigation.attributes.origin.id:(${alertId})`, + filter: `investigation.attributes.origin.id:(${alertId}) AND investigation.attributes.status: ongoing`, }); if (response.total === 0) { From 2dad0ce201f0e0decf46e109c2eaa60a873f459c Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 11:17:24 +0200 Subject: [PATCH 09/20] revert aad changes --- .../src/field_maps/alert_field_map.ts | 6 ----- .../src/default_alerts_as_data.ts | 4 --- .../server/alert_data_client/alerts_client.ts | 26 ------------------- 3 files changed, 36 deletions(-) diff --git a/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts b/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts index fe703a416da17..6893d6b32bd93 100644 --- a/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts +++ b/packages/kbn-alerts-as-data-utils/src/field_maps/alert_field_map.ts @@ -46,7 +46,6 @@ import { EVENT_KIND, EVENT_ORIGINAL, TAGS, - ALERT_INVESTIGATION_IDS, } from '@kbn/rule-data-utils'; import { MultiField } from './types'; @@ -260,11 +259,6 @@ export const alertFieldMap = { array: false, required: false, }, - [ALERT_INVESTIGATION_IDS]: { - type: 'keyword', - array: false, - required: false, - }, } as const; export type AlertFieldMap = typeof alertFieldMap; diff --git a/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts b/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts index 58731eaae0a16..4503679686bab 100644 --- a/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts +++ b/packages/kbn-rule-data-utils/src/default_alerts_as_data.ts @@ -118,8 +118,6 @@ const ALERT_URL = `${ALERT_NAMESPACE}.url` as const; // kibana.alert.rule.uuid - rule ID for rule that generated this alert const ALERT_RULE_UUID = `${ALERT_RULE_NAMESPACE}.uuid` as const; -const ALERT_INVESTIGATION_IDS = `${ALERT_NAMESPACE}.investigation_ids` as const; - const namespaces = { KIBANA_NAMESPACE, ALERT_NAMESPACE, @@ -162,7 +160,6 @@ const fields = { SPACE_IDS, TIMESTAMP, VERSION, - ALERT_INVESTIGATION_IDS, }; export { @@ -207,7 +204,6 @@ export { SPACE_IDS, TIMESTAMP, VERSION, - ALERT_INVESTIGATION_IDS, }; export type DefaultAlertFieldName = ValuesType; diff --git a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts index 69cdf6d8496e2..4dac5ff413909 100644 --- a/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts +++ b/x-pack/plugins/rule_registry/server/alert_data_client/alerts_client.ts @@ -22,7 +22,6 @@ import { ALERT_END, ALERT_STATUS_ACTIVE, ALERT_CASE_IDS, - ALERT_INVESTIGATION_IDS, MAX_CASES_PER_ALERT, AlertConsumers, } from '@kbn/rule-data-utils'; @@ -115,11 +114,6 @@ interface MgetAndAuditAlert { index: string; } -export interface UpdateInvestigaionOptions { - alert: MgetAndAuditAlert; - investigationIds: string[]; -} - export interface BulkUpdateCasesOptions { alerts: MgetAndAuditAlert[]; caseIds: string[]; @@ -602,18 +596,6 @@ export class AlertsClient { } } - private getAlertInvestigationIdsFieldUpdate( - source: ParsedTechnicalFields | undefined, - investigationIds: string[] - ) { - const uniqueInvestigationIds = new Set([ - ...(source?.[ALERT_INVESTIGATION_IDS] ?? []), - ...investigationIds, - ]); - - return { [ALERT_INVESTIGATION_IDS]: Array.from(uniqueInvestigationIds.values()) }; - } - public async ensureAllAlertsAuthorizedRead({ alerts }: { alerts: MgetAndAuditAlert[] }) { try { await this.ensureAllAlertsAuthorized({ alerts, operation: ReadOperations.Get }); @@ -1263,12 +1245,4 @@ export class AlertsClient { return fields; } - - public async updateInvestigationIds({ alert, investigationIds }: UpdateInvestigaionOptions) { - return this.mgetAlertsAuditOperate({ - alerts: [alert], - operation: WriteOperations.Update, - fieldToUpdate: (source) => this.getAlertInvestigationIdsFieldUpdate(source, investigationIds), - }); - } } From 2b21a5586b71a414ed171acf64b2160a00ee9c6b Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 11:23:47 +0200 Subject: [PATCH 10/20] pr feedback --- .../investigate_app/public/hooks/query_key_factory.ts | 2 +- .../public/hooks/use_get_investigation_details.tsx | 2 +- .../server/services/create_investigation.ts | 7 ++++++- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts index 0dd56de8d13a8..73a96d0eebe78 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts @@ -9,7 +9,7 @@ export const investigationKeys = { all: ['investigation'] as const, list: (params: { page: number; perPage: number }) => [...investigationKeys.all, 'list', params] as const, - get: ['getInvestigation'] as const, + get: (id: string) => [...investigationKeys.all, id] as const, }; export type InvestigationKeys = typeof investigationKeys; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx index 5e3e543efe537..053192e4320e8 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx @@ -34,7 +34,7 @@ export function useFetchInvestigation({ } = useKibana(); const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ - queryKey: investigationKeys.get, + queryKey: investigationKeys.get(id), queryFn: async ({ signal }) => { return await http.get(`/api/observability/investigations/${id}`, { version: '2023-10-31', diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts index 8fd926a3f5638..12c671cc62286 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts @@ -8,6 +8,11 @@ import { CreateInvestigationInput, CreateInvestigationResponse } from '../../common/schema/create'; import { InvestigationRepository } from './investigation_repository'; +enum InvestigationStatus { + ongoing = 'ongoing', + closed = 'closed', +} + export async function createInvestigation( params: CreateInvestigationInput, repository: InvestigationRepository @@ -16,7 +21,7 @@ export async function createInvestigation( ...params, createdAt: Date.now(), createdBy: 'elastic', - status: 'ongoing' as const, + status: InvestigationStatus.ongoing, }; await repository.save(investigation); From 123345792509b96e55e43cc801c3aa6be2d3c484 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 11:57:31 +0200 Subject: [PATCH 11/20] resolve merge conflicts --- .../public/pages/details/investigation_details_page.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx index cd3ecfcba6abb..4be0ca3051059 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx @@ -16,7 +16,7 @@ import { useInvestigateParams } from '../../hooks/use_investigate_params'; import { useFetchAlert } from '../../hooks/use_get_alert_details'; import { InvestigationDetails } from './components/investigation_details'; -export function InvestigateDetailsPage() { +export function InvestigationDetailsPage() { const { core: { http: { basePath }, From 8cef8a457836b5c467fd6c368726d799b49aecf7 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 12:07:01 +0200 Subject: [PATCH 12/20] update query keys --- .../investigate_app/public/hooks/query_key_factory.ts | 2 +- .../public/hooks/use_get_investigation_details.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts index 73a96d0eebe78..5ce96f5a2061c 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/query_key_factory.ts @@ -9,7 +9,7 @@ export const investigationKeys = { all: ['investigation'] as const, list: (params: { page: number; perPage: number }) => [...investigationKeys.all, 'list', params] as const, - get: (id: string) => [...investigationKeys.all, id] as const, + fetch: (params: { id: string }) => [...investigationKeys.all, 'fetch', params] as const, }; export type InvestigationKeys = typeof investigationKeys; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx index 053192e4320e8..78e57b6517e98 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx @@ -34,7 +34,7 @@ export function useFetchInvestigation({ } = useKibana(); const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ - queryKey: investigationKeys.get(id), + queryKey: investigationKeys.fetch({ id }), queryFn: async ({ signal }) => { return await http.get(`/api/observability/investigations/${id}`, { version: '2023-10-31', From adf4f9365fb67ef73a659b00f26af0c6a91512cf Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 12:10:15 +0200 Subject: [PATCH 13/20] rename --- .../public/pages/alert_details/components/header_actions.tsx | 2 +- ...gation_details.tsx => use_fetch_investigations_by_alert.tsx} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/{use_get_investigation_details.tsx => use_fetch_investigations_by_alert.tsx} (100%) diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx index ee668e1a8515d..1dd58ca128ef9 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx @@ -40,7 +40,7 @@ import type { TopAlert } from '../../../typings/alerts'; import { paths } from '../../../../common/locators/paths'; import { useBulkUntrackAlerts } from '../hooks/use_bulk_untrack_alerts'; import { useCreateInvestigation } from '../hooks/use_create_investigation'; -import { useFetchInvestigationsByAlert } from '../hooks/use_get_investigation_details'; +import { useFetchInvestigationsByAlert } from '../hooks/use_fetch_investigations_by_alert'; export interface HeaderActionsProps { alert: TopAlert | null; diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_get_investigation_details.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx similarity index 100% rename from x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_get_investigation_details.tsx rename to x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx From 5ede1afccd7b23f2d0ba7193151f07a1874ea94d Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 14:18:09 +0200 Subject: [PATCH 14/20] fix tests --- .../pages/alert_details/components/header_actions.test.tsx | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.test.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.test.tsx index b3e28ba222c5a..d484773e0b14a 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.test.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.test.tsx @@ -34,6 +34,10 @@ const mockHttp = { }, }; +const mockNavigateToApp = { + mockNavigateToApp: jest.fn(), +}; + const mockGetEditRuleFlyout = jest.fn(() => (
mocked component
)); @@ -48,6 +52,7 @@ const mockKibana = () => { }, cases: mockCases, http: mockHttp, + application: mockNavigateToApp, }, }); }; From 530de3e96d67b55a3202f48c6f95a4f99a1b5ba8 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 14:30:30 +0200 Subject: [PATCH 15/20] removing ref to investigate to solve circular dependency --- .../plugins/observability_solution/observability/tsconfig.json | 2 -- 1 file changed, 2 deletions(-) diff --git a/x-pack/plugins/observability_solution/observability/tsconfig.json b/x-pack/plugins/observability_solution/observability/tsconfig.json index 90074bf35d264..28f06a81d17c0 100644 --- a/x-pack/plugins/observability_solution/observability/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability/tsconfig.json @@ -110,8 +110,6 @@ "@kbn/license-management-plugin", "@kbn/observability-alerting-rule-utils", "@kbn/core-ui-settings-server-mocks", - "@kbn/investigate-app-plugin", - "@kbn/investigate-plugin", ], "exclude": [ "target/**/*" From 4b6a6809a40eada9f6de5d6d558563f7672c2142 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 13 Aug 2024 12:43:30 +0000 Subject: [PATCH 16/20] [CI] Auto-commit changed files from 'node scripts/lint_ts_projects --fix' --- .../plugins/observability_solution/observability/tsconfig.json | 2 ++ 1 file changed, 2 insertions(+) diff --git a/x-pack/plugins/observability_solution/observability/tsconfig.json b/x-pack/plugins/observability_solution/observability/tsconfig.json index 28f06a81d17c0..90074bf35d264 100644 --- a/x-pack/plugins/observability_solution/observability/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability/tsconfig.json @@ -110,6 +110,8 @@ "@kbn/license-management-plugin", "@kbn/observability-alerting-rule-utils", "@kbn/core-ui-settings-server-mocks", + "@kbn/investigate-app-plugin", + "@kbn/investigate-plugin", ], "exclude": [ "target/**/*" From 1544474c8bc6ebeac600e27e71e445c422341829 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 18:00:12 +0200 Subject: [PATCH 17/20] resolve cyclic dep --- .../observability_solution/investigate/common/index.ts | 10 ++++++++++ .../common/schema/create.ts | 0 .../common/schema/find.ts | 0 .../common/schema/find_by_alert.ts | 0 .../common/schema/get.ts | 0 .../common/schema/investigation.ts | 0 .../public/hooks/use_fetch_investigation_list.ts | 2 +- .../public/hooks/use_get_investigation_details.tsx | 2 +- ...t_global_investigate_app_server_route_repository.ts | 8 ++++---- .../server/services/create_investigation.ts | 5 ++++- .../server/services/find_investigation_by_alert.ts | 4 ++-- .../server/services/find_investigations.ts | 4 ++-- .../server/services/get_investigation.ts | 3 ++- .../alert_details/hooks/use_create_investigation.tsx | 4 ++-- .../hooks/use_fetch_investigations_by_alert.tsx | 2 +- .../observability_solution/observability/tsconfig.json | 1 - 16 files changed, 29 insertions(+), 16 deletions(-) rename x-pack/plugins/observability_solution/{investigate_app => investigate}/common/schema/create.ts (100%) rename x-pack/plugins/observability_solution/{investigate_app => investigate}/common/schema/find.ts (100%) rename x-pack/plugins/observability_solution/{investigate_app => investigate}/common/schema/find_by_alert.ts (100%) rename x-pack/plugins/observability_solution/{investigate_app => investigate}/common/schema/get.ts (100%) rename x-pack/plugins/observability_solution/{investigate_app => investigate}/common/schema/investigation.ts (100%) diff --git a/x-pack/plugins/observability_solution/investigate/common/index.ts b/x-pack/plugins/observability_solution/investigate/common/index.ts index 7846f257f64fe..6a6fa48ca227d 100644 --- a/x-pack/plugins/observability_solution/investigate/common/index.ts +++ b/x-pack/plugins/observability_solution/investigate/common/index.ts @@ -14,3 +14,13 @@ export type { export { mergePlainObjects } from './utils/merge_plain_objects'; export { InvestigateWidgetColumnSpan } from './types'; + +export type { CreateInvestigationInput, CreateInvestigationResponse } from './schema/create'; +export type { GetInvestigationParams } from './schema/get'; +export type { FindInvestigationsResponse } from './schema/find'; +export type { FindInvestigationsByAlertResponse } from './schema/find_by_alert'; + +export { createInvestigationParamsSchema } from './schema/create'; +export { getInvestigationParamsSchema } from './schema/get'; +export { findInvestigationsParamsSchema } from './schema/find'; +export { findInvestigationsByAlertParamsSchema } from './schema/find_by_alert'; diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts b/x-pack/plugins/observability_solution/investigate/common/schema/create.ts similarity index 100% rename from x-pack/plugins/observability_solution/investigate_app/common/schema/create.ts rename to x-pack/plugins/observability_solution/investigate/common/schema/create.ts diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/find.ts b/x-pack/plugins/observability_solution/investigate/common/schema/find.ts similarity index 100% rename from x-pack/plugins/observability_solution/investigate_app/common/schema/find.ts rename to x-pack/plugins/observability_solution/investigate/common/schema/find.ts diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/find_by_alert.ts b/x-pack/plugins/observability_solution/investigate/common/schema/find_by_alert.ts similarity index 100% rename from x-pack/plugins/observability_solution/investigate_app/common/schema/find_by_alert.ts rename to x-pack/plugins/observability_solution/investigate/common/schema/find_by_alert.ts diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/get.ts b/x-pack/plugins/observability_solution/investigate/common/schema/get.ts similarity index 100% rename from x-pack/plugins/observability_solution/investigate_app/common/schema/get.ts rename to x-pack/plugins/observability_solution/investigate/common/schema/get.ts diff --git a/x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts b/x-pack/plugins/observability_solution/investigate/common/schema/investigation.ts similarity index 100% rename from x-pack/plugins/observability_solution/investigate_app/common/schema/investigation.ts rename to x-pack/plugins/observability_solution/investigate/common/schema/investigation.ts diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_list.ts b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_list.ts index a3ca59519211a..fef9ce274d63e 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_list.ts +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_fetch_investigation_list.ts @@ -6,7 +6,7 @@ */ import { useQuery } from '@tanstack/react-query'; -import { FindInvestigationsResponse } from '../../common/schema/find'; +import { FindInvestigationsResponse } from '@kbn/investigate-plugin/common'; import { investigationKeys } from './query_key_factory'; import { useKibana } from './use_kibana'; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx index 78e57b6517e98..d6d53de22f5e9 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx @@ -6,7 +6,7 @@ */ import { useQuery } from '@tanstack/react-query'; -import { GetInvestigationResponse } from '../../common/schema/get'; +import { GetInvestigationResponse } from '@kbn/investigate-plugin/common/schema/get'; import { investigationKeys } from './query_key_factory'; import { useKibana } from './use_kibana'; diff --git a/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts b/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts index 5960aa9778742..9272f25db0491 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts @@ -5,14 +5,14 @@ * 2.0. */ -import { findInvestigationsByAlertParamsSchema } from '../../common/schema/find_by_alert'; -import { findInvestigationsParamsSchema } from '../../common/schema/find'; -import { createInvestigationParamsSchema } from '../../common/schema/create'; +import { findInvestigationsByAlertParamsSchema } from '@kbn/investigate-plugin/common'; +import { createInvestigationParamsSchema } from '@kbn/investigate-plugin/common'; +import { findInvestigationsParamsSchema } from '@kbn/investigate-plugin/common'; +import { getInvestigationParamsSchema } from '@kbn/investigate-plugin/common'; import { createInvestigation } from '../services/create_investigation'; import { investigationRepositoryFactory } from '../services/investigation_repository'; import { createInvestigateAppServerRoute } from './create_investigate_app_server_route'; import { findInvestigations } from '../services/find_investigations'; -import { getInvestigationParamsSchema } from '../../common/schema/get'; import { getInvestigation } from '../services/get_investigation'; import { findInvestigationsByAlert } from '../services/find_investigation_by_alert'; diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts index 12c671cc62286..52b5953fb8095 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/create_investigation.ts @@ -5,7 +5,10 @@ * 2.0. */ -import { CreateInvestigationInput, CreateInvestigationResponse } from '../../common/schema/create'; +import { + CreateInvestigationInput, + CreateInvestigationResponse, +} from '@kbn/investigate-plugin/common'; import { InvestigationRepository } from './investigation_repository'; enum InvestigationStatus { diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts index ae093960d9f0e..d95667c36265d 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts @@ -5,11 +5,11 @@ * 2.0. */ +import { FindInvestigationsByAlertResponse } from '@kbn/investigate-plugin/common'; import { FindInvestigationsByAlertParams, - FindInvestigationsByAlertResponse, findInvestigationsByAlertResponseSchema, -} from '../../common/schema/find_by_alert'; +} from '@kbn/investigate-plugin/common/schema/find_by_alert'; import { InvestigationRepository } from './investigation_repository'; export async function findInvestigationsByAlert( diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts index 2c08125aff734..a55e76857c836 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts @@ -5,11 +5,11 @@ * 2.0. */ +import { FindInvestigationsResponse } from '@kbn/investigate-plugin/common'; import { FindInvestigationsParams, - FindInvestigationsResponse, findInvestigationsResponseSchema, -} from '../../common/schema/find'; +} from '@kbn/investigate-plugin/common/schema/find'; import { InvestigationRepository } from './investigation_repository'; export async function findInvestigations( diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/get_investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/get_investigation.ts index 9bd6025f8e8a2..e57111af99e32 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/get_investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/get_investigation.ts @@ -5,7 +5,8 @@ * 2.0. */ -import { GetInvestigationParams, GetInvestigationResponse } from '../../common/schema/get'; +import { GetInvestigationParams } from '@kbn/investigate-plugin/common'; +import { GetInvestigationResponse } from '@kbn/investigate-plugin/common/schema/get'; import { InvestigationRepository } from './investigation_repository'; export async function getInvestigation( diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_create_investigation.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_create_investigation.tsx index f83544107def4..e41674b2e78be 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_create_investigation.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_create_investigation.tsx @@ -11,8 +11,8 @@ import { i18n } from '@kbn/i18n'; import { CreateInvestigationInput, CreateInvestigationResponse, -} from '@kbn/investigate-app-plugin/common/schema/create'; -import { FindInvestigationsResponse } from '@kbn/investigate-app-plugin/common/schema/find'; +} from '@kbn/investigate-plugin/common'; +import { FindInvestigationsResponse } from '@kbn/investigate-plugin/common'; import { useKibana } from '../../../utils/kibana_react'; type ServerError = IHttpFetchError; diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx index 8b84e96243728..b4147544513dd 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx @@ -6,7 +6,7 @@ */ import { useQuery } from '@tanstack/react-query'; -import { FindInvestigationsByAlertResponse } from '@kbn/investigate-app-plugin/common/schema/find_by_alert'; +import { FindInvestigationsByAlertResponse } from '@kbn/investigate-plugin/common'; import { useKibana } from '../../../utils/kibana_react'; export interface InvestigationsByAlertParams { diff --git a/x-pack/plugins/observability_solution/observability/tsconfig.json b/x-pack/plugins/observability_solution/observability/tsconfig.json index 90074bf35d264..53390c6c2d535 100644 --- a/x-pack/plugins/observability_solution/observability/tsconfig.json +++ b/x-pack/plugins/observability_solution/observability/tsconfig.json @@ -110,7 +110,6 @@ "@kbn/license-management-plugin", "@kbn/observability-alerting-rule-utils", "@kbn/core-ui-settings-server-mocks", - "@kbn/investigate-app-plugin", "@kbn/investigate-plugin", ], "exclude": [ From 34f9331077d31a0f6ce8bc72672df6dd82b542df Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 19:01:48 +0200 Subject: [PATCH 18/20] extend search api --- .../investigate/common/index.ts | 2 -- .../investigate/common/schema/find.ts | 1 + .../common/schema/find_by_alert.ts | 24 ----------------- ...investigate_app_server_route_repository.ts | 17 ------------ .../services/find_investigation_by_alert.ts | 22 ---------------- .../server/services/find_investigations.ts | 9 ++++++- .../services/investigation_repository.ts | 26 +++---------------- .../components/header_actions.tsx | 6 ++--- .../use_fetch_investigations_by_alert.tsx | 16 +++++------- 9 files changed, 22 insertions(+), 101 deletions(-) delete mode 100644 x-pack/plugins/observability_solution/investigate/common/schema/find_by_alert.ts delete mode 100644 x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts diff --git a/x-pack/plugins/observability_solution/investigate/common/index.ts b/x-pack/plugins/observability_solution/investigate/common/index.ts index 6a6fa48ca227d..71585c294f776 100644 --- a/x-pack/plugins/observability_solution/investigate/common/index.ts +++ b/x-pack/plugins/observability_solution/investigate/common/index.ts @@ -18,9 +18,7 @@ export { InvestigateWidgetColumnSpan } from './types'; export type { CreateInvestigationInput, CreateInvestigationResponse } from './schema/create'; export type { GetInvestigationParams } from './schema/get'; export type { FindInvestigationsResponse } from './schema/find'; -export type { FindInvestigationsByAlertResponse } from './schema/find_by_alert'; export { createInvestigationParamsSchema } from './schema/create'; export { getInvestigationParamsSchema } from './schema/get'; export { findInvestigationsParamsSchema } from './schema/find'; -export { findInvestigationsByAlertParamsSchema } from './schema/find_by_alert'; diff --git a/x-pack/plugins/observability_solution/investigate/common/schema/find.ts b/x-pack/plugins/observability_solution/investigate/common/schema/find.ts index dc76a39fce679..ebec4d807b974 100644 --- a/x-pack/plugins/observability_solution/investigate/common/schema/find.ts +++ b/x-pack/plugins/observability_solution/investigate/common/schema/find.ts @@ -9,6 +9,7 @@ import { investigationResponseSchema } from './investigation'; const findInvestigationsParamsSchema = t.partial({ query: t.partial({ + alertId: t.union([t.string, t.undefined]), page: t.string, perPage: t.string, }), diff --git a/x-pack/plugins/observability_solution/investigate/common/schema/find_by_alert.ts b/x-pack/plugins/observability_solution/investigate/common/schema/find_by_alert.ts deleted file mode 100644 index 76091f994492f..0000000000000 --- a/x-pack/plugins/observability_solution/investigate/common/schema/find_by_alert.ts +++ /dev/null @@ -1,24 +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 * as t from 'io-ts'; -import { investigationResponseSchema } from './investigation'; - -const findInvestigationsByAlertParamsSchema = t.type({ - path: t.type({ - alertId: t.string, - }), -}); - -const findInvestigationsByAlertResponseSchema = t.array(investigationResponseSchema); - -type FindInvestigationsByAlertParams = t.TypeOf< - typeof findInvestigationsByAlertParamsSchema.props.path ->; // Parsed payload used by the backend -type FindInvestigationsByAlertResponse = t.OutputOf; // Raw response sent to the frontend - -export { findInvestigationsByAlertParamsSchema, findInvestigationsByAlertResponseSchema }; -export type { FindInvestigationsByAlertParams, FindInvestigationsByAlertResponse }; diff --git a/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts b/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts index 9272f25db0491..f745b46bb54b8 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/routes/get_global_investigate_app_server_route_repository.ts @@ -5,7 +5,6 @@ * 2.0. */ -import { findInvestigationsByAlertParamsSchema } from '@kbn/investigate-plugin/common'; import { createInvestigationParamsSchema } from '@kbn/investigate-plugin/common'; import { findInvestigationsParamsSchema } from '@kbn/investigate-plugin/common'; import { getInvestigationParamsSchema } from '@kbn/investigate-plugin/common'; @@ -14,7 +13,6 @@ import { investigationRepositoryFactory } from '../services/investigation_reposi import { createInvestigateAppServerRoute } from './create_investigate_app_server_route'; import { findInvestigations } from '../services/find_investigations'; import { getInvestigation } from '../services/get_investigation'; -import { findInvestigationsByAlert } from '../services/find_investigation_by_alert'; const createInvestigationRoute = createInvestigateAppServerRoute({ endpoint: 'POST /api/observability/investigations 2023-10-31', @@ -44,20 +42,6 @@ const findInvestigationsRoute = createInvestigateAppServerRoute({ }, }); -const findInvestigationsByAlertRoute = createInvestigateAppServerRoute({ - endpoint: 'GET /api/observability/investigations/alert/{alertId} 2023-10-31', - options: { - tags: [], - }, - params: findInvestigationsByAlertParamsSchema, - handler: async (params) => { - const soClient = (await params.context.core).savedObjects.client; - const repository = investigationRepositoryFactory({ soClient, logger: params.logger }); - - return await findInvestigationsByAlert(params.params.path, repository); - }, -}); - const getInvestigationRoute = createInvestigateAppServerRoute({ endpoint: 'GET /api/observability/investigations/{id} 2023-10-31', options: { @@ -77,7 +61,6 @@ export function getGlobalInvestigateAppServerRouteRepository() { ...createInvestigationRoute, ...findInvestigationsRoute, ...getInvestigationRoute, - ...findInvestigationsByAlertRoute, }; } diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts deleted file mode 100644 index d95667c36265d..0000000000000 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigation_by_alert.ts +++ /dev/null @@ -1,22 +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 { FindInvestigationsByAlertResponse } from '@kbn/investigate-plugin/common'; -import { - FindInvestigationsByAlertParams, - findInvestigationsByAlertResponseSchema, -} from '@kbn/investigate-plugin/common/schema/find_by_alert'; -import { InvestigationRepository } from './investigation_repository'; - -export async function findInvestigationsByAlert( - params: FindInvestigationsByAlertParams, - repository: InvestigationRepository -): Promise { - const investigations = await repository.findByAlertId(params.alertId); - - return findInvestigationsByAlertResponseSchema.encode(investigations); -} diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts index a55e76857c836..0db6f2eb587b8 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/find_investigations.ts @@ -16,7 +16,7 @@ export async function findInvestigations( params: FindInvestigationsParams, repository: InvestigationRepository ): Promise { - const investigations = await repository.search(toPagination(params)); + const investigations = await repository.search(toFilter(params), toPagination(params)); return findInvestigationsResponseSchema.encode(investigations); } @@ -29,3 +29,10 @@ function toPagination(params: FindInvestigationsParams) { perPage: params.perPage ? parseInt(params.perPage, 10) : DEFAULT_PER_PAGE, }; } + +function toFilter(params: FindInvestigationsParams) { + if (params.alertId) { + return `investigation.attributes.origin.id:(${params.alertId}) AND investigation.attributes.status: ongoing`; + } + return ''; +} diff --git a/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts b/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts index 81d9f81cb2c3b..090930351fc14 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/services/investigation_repository.ts @@ -14,9 +14,8 @@ import { Paginated, Pagination } from '../models/pagination'; export interface InvestigationRepository { save(investigation: Investigation): Promise; findById(id: string): Promise; - findByAlertId(alertId: string): Promise; deleteById(id: string): Promise; - search(pagination: Pagination): Promise>; + search(filter: string, pagination: Pagination): Promise>; } export function investigationRepositoryFactory({ @@ -75,26 +74,6 @@ export function investigationRepositoryFactory({ return investigation; }, - async findByAlertId(alertId: string): Promise { - const response = await soClient.find({ - type: SO_INVESTIGATION_TYPE, - filter: `investigation.attributes.origin.id:(${alertId}) AND investigation.attributes.status: ongoing`, - }); - - if (response.total === 0) { - return []; - } - - const investigations: Investigation[] = []; - - response.saved_objects.forEach((so) => { - const investigation = toInvestigation(so.attributes); - if (investigation !== undefined) investigations.push(investigation); - }); - - return investigations; - }, - async deleteById(id: string): Promise { const response = await soClient.find({ type: SO_INVESTIGATION_TYPE, @@ -110,11 +89,12 @@ export function investigationRepositoryFactory({ await soClient.delete(SO_INVESTIGATION_TYPE, response.saved_objects[0].id); }, - async search(pagination: Pagination): Promise> { + async search(filter: string, pagination: Pagination): Promise> { const response = await soClient.find({ type: SO_INVESTIGATION_TYPE, page: pagination.page, perPage: pagination.perPage, + filter, }); return { diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx index 1dd58ca128ef9..c45702b2d8262 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx @@ -132,7 +132,7 @@ export function HeaderActions({ const createOrOpenInvestigation = async () => { if (!alert) return; - if (!investigations || investigations.length === 0) { + if (!investigations || investigations.results.length === 0) { const paddedAlertTimeRange = getPaddedAlertTimeRange(alertStart!, alertEnd); const investigationResponse = await createInvestigation({ @@ -155,7 +155,7 @@ export function HeaderActions({ navigateToApp('investigate', { path: `/${investigationResponse.id}`, replace: false }); } else { navigateToApp('investigate', { - path: `/${investigations[0].id}`, + path: `/${investigations.results[0].id}`, replace: false, }); } @@ -177,7 +177,7 @@ export function HeaderActions({ {i18n.translate('xpack.observability.alertDetails.investigateAlert', { defaultMessage: - !investigations || investigations.length === 0 + !investigations || investigations.results.length === 0 ? 'Start investigation' : 'Ongoing investigation', })} diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx index b4147544513dd..bffff6c166b2d 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/hooks/use_fetch_investigations_by_alert.tsx @@ -6,7 +6,7 @@ */ import { useQuery } from '@tanstack/react-query'; -import { FindInvestigationsByAlertResponse } from '@kbn/investigate-plugin/common'; +import { FindInvestigationsResponse } from '@kbn/investigate-plugin/common'; import { useKibana } from '../../../utils/kibana_react'; export interface InvestigationsByAlertParams { @@ -19,7 +19,7 @@ export interface UseFetchInvestigationsByAlertResponse { isRefetching: boolean; isSuccess: boolean; isError: boolean; - data: FindInvestigationsByAlertResponse | undefined; + data: FindInvestigationsResponse | undefined; } export function useFetchInvestigationsByAlert({ @@ -33,13 +33,11 @@ export function useFetchInvestigationsByAlert({ const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ queryKey: ['fetchInvestigationsByAlert', alertId], queryFn: async ({ signal }) => { - return await http.get( - `/api/observability/investigations/alert/${alertId}`, - { - version: '2023-10-31', - signal, - } - ); + return await http.get('/api/observability/investigations', { + query: { alertId }, + version: '2023-10-31', + signal, + }); }, cacheTime: 0, refetchOnWindowFocus: false, From 8a8a177cb70017e63360864dc8a312ec6450901b Mon Sep 17 00:00:00 2001 From: Bena Kansara <69037875+benakansara@users.noreply.github.com> Date: Tue, 13 Aug 2024 20:01:57 +0200 Subject: [PATCH 19/20] Update x-pack/plugins/observability_solution/investigate/common/schema/find.ts Co-authored-by: Kevin Delemme --- .../observability_solution/investigate/common/schema/find.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/observability_solution/investigate/common/schema/find.ts b/x-pack/plugins/observability_solution/investigate/common/schema/find.ts index ebec4d807b974..4eb9d6f9bf66c 100644 --- a/x-pack/plugins/observability_solution/investigate/common/schema/find.ts +++ b/x-pack/plugins/observability_solution/investigate/common/schema/find.ts @@ -9,7 +9,7 @@ import { investigationResponseSchema } from './investigation'; const findInvestigationsParamsSchema = t.partial({ query: t.partial({ - alertId: t.union([t.string, t.undefined]), + alertId: t.string, page: t.string, perPage: t.string, }), From 5a24c0b2cccf8e1e7cc97ea1d739e683002ef032 Mon Sep 17 00:00:00 2001 From: Bena Kansara Date: Tue, 13 Aug 2024 22:09:48 +0200 Subject: [PATCH 20/20] pr feedback --- .../investigate/common/schema/create.ts | 6 ++---- .../investigate/common/schema/investigation.ts | 6 ++---- .../investigate/common/schema/origin.ts | 17 +++++++++++++++++ .../public/hooks/use_get_alert_details.tsx | 3 +-- .../hooks/use_get_investigation_details.tsx | 4 ++-- .../details/investigation_details_page.tsx | 3 ++- .../server/models/investigation.ts | 6 ++---- .../alert_details/components/header_actions.tsx | 4 ++-- .../hooks/use_fetch_investigations_by_alert.tsx | 2 ++ 9 files changed, 32 insertions(+), 19 deletions(-) create mode 100644 x-pack/plugins/observability_solution/investigate/common/schema/origin.ts diff --git a/x-pack/plugins/observability_solution/investigate/common/schema/create.ts b/x-pack/plugins/observability_solution/investigate/common/schema/create.ts index f6f4654b6cce1..f2ba04de9e88a 100644 --- a/x-pack/plugins/observability_solution/investigate/common/schema/create.ts +++ b/x-pack/plugins/observability_solution/investigate/common/schema/create.ts @@ -6,6 +6,7 @@ */ import * as t from 'io-ts'; import { investigationResponseSchema } from './investigation'; +import { alertOriginSchema, blankOriginSchema } from './origin'; const createInvestigationParamsSchema = t.type({ body: t.type({ @@ -14,10 +15,7 @@ const createInvestigationParamsSchema = t.type({ params: t.type({ timeRange: t.type({ from: t.number, to: t.number }), }), - origin: t.type({ - type: t.union([t.literal('alert'), t.literal('blank')]), - id: t.string, - }), + origin: t.union([alertOriginSchema, blankOriginSchema]), }), }); diff --git a/x-pack/plugins/observability_solution/investigate/common/schema/investigation.ts b/x-pack/plugins/observability_solution/investigate/common/schema/investigation.ts index f69632ddb8cee..23247bba88ab8 100644 --- a/x-pack/plugins/observability_solution/investigate/common/schema/investigation.ts +++ b/x-pack/plugins/observability_solution/investigate/common/schema/investigation.ts @@ -5,6 +5,7 @@ * 2.0. */ import * as t from 'io-ts'; +import { alertOriginSchema, blankOriginSchema } from './origin'; const investigationResponseSchema = t.type({ id: t.string, @@ -14,10 +15,7 @@ const investigationResponseSchema = t.type({ params: t.type({ timeRange: t.type({ from: t.number, to: t.number }), }), - origin: t.type({ - type: t.union([t.literal('alert'), t.literal('blank')]), - id: t.string, - }), + origin: t.union([alertOriginSchema, blankOriginSchema]), status: t.union([t.literal('ongoing'), t.literal('closed')]), }); diff --git a/x-pack/plugins/observability_solution/investigate/common/schema/origin.ts b/x-pack/plugins/observability_solution/investigate/common/schema/origin.ts new file mode 100644 index 0000000000000..1c00f5ad73de8 --- /dev/null +++ b/x-pack/plugins/observability_solution/investigate/common/schema/origin.ts @@ -0,0 +1,17 @@ +/* + * 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 * as t from 'io-ts'; + +const blankOriginSchema = t.type({ type: t.literal('blank') }); +const alertOriginSchema = t.type({ type: t.literal('alert'), id: t.string }); + +type AlertOrigin = t.OutputOf; +type BlankOrigin = t.OutputOf; + +export { alertOriginSchema, blankOriginSchema }; + +export type { AlertOrigin, BlankOrigin }; diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx index 954498e624937..5f3bc3f3c9b6a 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_alert_details.tsx @@ -33,8 +33,6 @@ export function useFetchAlert({ id }: AlertParams): UseFetchAlertResponse { const { isInitialLoading, isLoading, isError, isSuccess, isRefetching, data } = useQuery({ queryKey: ['fetchAlert', id], queryFn: async ({ signal }) => { - if (id === '') return null; - return await http.get(BASE_RAC_ALERTS_API_PATH, { query: { id, @@ -56,6 +54,7 @@ export function useFetchAlert({ id }: AlertParams): UseFetchAlertResponse { title: 'Something went wrong while fetching alert', }); }, + enabled: Boolean(id), }); return { diff --git a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx index d6d53de22f5e9..796d8bc561575 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/hooks/use_get_investigation_details.tsx @@ -10,7 +10,7 @@ import { GetInvestigationResponse } from '@kbn/investigate-plugin/common/schema/ import { investigationKeys } from './query_key_factory'; import { useKibana } from './use_kibana'; -export interface InvestigationListParams { +export interface FetchInvestigationParams { id: string; } @@ -25,7 +25,7 @@ export interface UseFetchInvestigationResponse { export function useFetchInvestigation({ id, -}: InvestigationListParams): UseFetchInvestigationResponse { +}: FetchInvestigationParams): UseFetchInvestigationResponse { const { core: { http, diff --git a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx index 4be0ca3051059..ed749ce925ea1 100644 --- a/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx +++ b/x-pack/plugins/observability_solution/investigate_app/public/pages/details/investigation_details_page.tsx @@ -9,6 +9,7 @@ import { EuiButton, EuiButtonEmpty, EuiText } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import React from 'react'; import { ALERT_RULE_CATEGORY } from '@kbn/rule-data-utils/src/default_alerts_as_data'; +import { AlertOrigin } from '@kbn/investigate-plugin/common/schema/origin'; import { paths } from '../../../common/paths'; import { useKibana } from '../../hooks/use_kibana'; import { useFetchInvestigation } from '../../hooks/use_get_investigation_details'; @@ -38,7 +39,7 @@ export function InvestigationDetailsPage() { isError: isFetchInvestigationError, } = useFetchInvestigation({ id }); - const alertId = investigationDetails?.origin.id ?? ''; + const alertId = investigationDetails ? (investigationDetails.origin as AlertOrigin).id : ''; const { data: alertDetails, diff --git a/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts b/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts index 14a8c4eba57c4..041b1d217c208 100644 --- a/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts +++ b/x-pack/plugins/observability_solution/investigate_app/server/models/investigation.ts @@ -5,6 +5,7 @@ * 2.0. */ +import { alertOriginSchema, blankOriginSchema } from '@kbn/investigate-plugin/common/schema/origin'; import * as t from 'io-ts'; export const investigationSchema = t.type({ @@ -15,10 +16,7 @@ export const investigationSchema = t.type({ params: t.type({ timeRange: t.type({ from: t.number, to: t.number }), }), - origin: t.type({ - type: t.union([t.literal('alert'), t.literal('blank')]), - id: t.string, - }), + origin: t.union([alertOriginSchema, blankOriginSchema]), status: t.union([t.literal('ongoing'), t.literal('closed')]), }); diff --git a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx index c45702b2d8262..6ea43b165fe7a 100644 --- a/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx +++ b/x-pack/plugins/observability_solution/observability/public/pages/alert_details/components/header_actions.tsx @@ -62,7 +62,7 @@ export function HeaderActions({ triggersActionsUi: { getEditRuleFlyout: EditRuleFlyout, getRuleSnoozeModal: RuleSnoozeModal }, http, application: { navigateToApp }, - investigate, + investigate: investigatePlugin, } = useKibana().services; const { rule, refetch } = useFetchRule({ @@ -164,7 +164,7 @@ export function HeaderActions({ return ( <> - {investigate && + {Boolean(investigatePlugin) && alert?.fields[ALERT_RULE_TYPE_ID] === OBSERVABILITY_THRESHOLD_RULE_TYPE_ID && (