From b60fdcef8a156ba1e2ff4c9b57d4384f9fe6016e Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Fri, 9 Sep 2022 14:56:02 -0500 Subject: [PATCH 01/20] Add all_namespaces prop to global logs api --- .../alerting/common/execution_log_types.ts | 1 + .../lib/get_execution_log_aggregation.ts | 5 +++++ .../routes/get_global_execution_logs.ts | 3 +++ .../server/rules_client/rules_client.ts | 20 ++++++++++++------- .../event_log/server/event_log_client.ts | 5 +++-- x-pack/plugins/event_log/server/types.ts | 3 ++- 6 files changed, 27 insertions(+), 10 deletions(-) diff --git a/x-pack/plugins/alerting/common/execution_log_types.ts b/x-pack/plugins/alerting/common/execution_log_types.ts index 41406bb6c9dc1..34becd7de5c85 100644 --- a/x-pack/plugins/alerting/common/execution_log_types.ts +++ b/x-pack/plugins/alerting/common/execution_log_types.ts @@ -49,6 +49,7 @@ export interface IExecutionLog { schedule_delay_ms: number; timed_out: boolean; rule_id: string; + space_ids: string[]; } export interface IExecutionErrors { diff --git a/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.ts b/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.ts index 14d67807a86af..e702763342906 100644 --- a/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.ts +++ b/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.ts @@ -17,6 +17,7 @@ import { IExecutionLog, IExecutionLogResult } from '../../common'; const DEFAULT_MAX_BUCKETS_LIMIT = 1000; // do not retrieve more than this number of executions const RULE_ID_FIELD = 'rule.id'; +const SPACE_ID_FIELD = 'kibana.space_ids'; const PROVIDER_FIELD = 'event.provider'; const START_FIELD = 'event.start'; const ACTION_FIELD = 'event.action'; @@ -265,6 +266,7 @@ export function getExecutionLogAggregation({ ERROR_MESSAGE_FIELD, VERSION_FIELD, RULE_ID_FIELD, + SPACE_ID_FIELD, ], }, }, @@ -336,6 +338,8 @@ function formatExecutionLogAggBucket(bucket: IExecutionUuidAggBucket): IExecutio const version = outcomeAndMessage ? outcomeAndMessage?.kibana?.version ?? '' : ''; const ruleId = outcomeAndMessage ? outcomeAndMessage?.rule?.id ?? '' : ''; + const spaceIds = outcomeAndMessage ? outcomeAndMessage?.kibana?.space_ids ?? [] : []; + return { id: bucket?.key ?? '', timestamp: bucket?.ruleExecution?.executeStartTime.value_as_string ?? '', @@ -355,6 +359,7 @@ function formatExecutionLogAggBucket(bucket: IExecutionUuidAggBucket): IExecutio schedule_delay_ms: scheduleDelayUs / Millis2Nanos, timed_out: timedOut, rule_id: ruleId, + space_ids: spaceIds, }; } diff --git a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts index 4695e5e7bdf89..859cbfaa8424d 100644 --- a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts +++ b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts @@ -38,18 +38,21 @@ const querySchema = schema.object({ per_page: schema.number({ defaultValue: 10, min: 1 }), page: schema.number({ defaultValue: 1, min: 1 }), sort: sortFieldsSchema, + all_namespaces: schema.maybe(schema.boolean()), }); const rewriteReq: RewriteRequestCase = ({ date_start: dateStart, date_end: dateEnd, per_page: perPage, + all_namespaces: allNamespaces, ...rest }) => ({ ...rest, dateStart, dateEnd, perPage, + allNamespaces, }); export const getGlobalExecutionLogRoute = ( diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index f0cf88615047d..56653b04b24ad 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -372,6 +372,7 @@ export interface GetGlobalExecutionLogParams { page: number; perPage: number; sort: estypes.Sort; + allNamespaces?: boolean; } export interface GetActionErrorLogByIdParams { @@ -891,6 +892,7 @@ export class RulesClient { page, perPage, sort, + allNamespaces, }: GetGlobalExecutionLogParams): Promise { this.logger.debug(`getGlobalExecutionLogWithAuth(): getting global execution log`); @@ -941,18 +943,22 @@ export class RulesClient { perPage, sort, }), - } + }, + allNamespaces ); const formattedResult = formatExecutionLogResult(aggResult); - const ruleIds = [...new Set(formattedResult.data.map((l) => l.rule_id))].filter( - Boolean - ) as string[]; + const ruleIds = [ + ...new Set(formattedResult.data.map((l) => [l.rule_id, l.space_ids])), + ].filter(Boolean) as Array<[string, string[]]>; const ruleNameIdEntries = await Promise.all( - ruleIds.map(async (id) => { + ruleIds.map(async ([id, spaceIds]) => { try { - const result = await this.get({ id }); - return [id, result.name]; + if (this.spaceId === spaceIds[0]) { + const result = await this.get({ id }); + return [id, result.name]; + } + return [id, spaceIds[0]]; } catch (e) { return [id, id]; } diff --git a/x-pack/plugins/event_log/server/event_log_client.ts b/x-pack/plugins/event_log/server/event_log_client.ts index e23b5f137eef1..9c22dfd41e13f 100644 --- a/x-pack/plugins/event_log/server/event_log_client.ts +++ b/x-pack/plugins/event_log/server/event_log_client.ts @@ -142,7 +142,8 @@ export class EventLogClient implements IEventLogClient { public async aggregateEventsWithAuthFilter( type: string, authFilter: KueryNode, - options?: AggregateOptionsType + options?: AggregateOptionsType, + allNamespaces?: boolean ) { if (!authFilter) { throw new Error('No authorization filter defined!'); @@ -158,7 +159,7 @@ export class EventLogClient implements IEventLogClient { return await this.esContext.esAdapter.aggregateEventsWithAuthFilter({ index: this.esContext.esNames.indexPattern, - namespace: await this.getNamespace(), + namespace: allNamespaces ? undefined : await this.getNamespace(), type, authFilter, aggregateOptions: { ...aggregateOptions, aggs } as AggregateOptionsType, diff --git a/x-pack/plugins/event_log/server/types.ts b/x-pack/plugins/event_log/server/types.ts index d610a8bff9c2a..26ce4d1da0161 100644 --- a/x-pack/plugins/event_log/server/types.ts +++ b/x-pack/plugins/event_log/server/types.ts @@ -66,7 +66,8 @@ export interface IEventLogClient { aggregateEventsWithAuthFilter( type: string, authFilter: KueryNode, - options?: Partial + options?: Partial, + allNamespaces?: boolean ): Promise; } From ff24cc0f3cc7829bb2c7bc9e824f195dbf8b6761 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Fri, 14 Oct 2022 17:28:24 -0500 Subject: [PATCH 02/20] Display space column and disable link on inactive spaces --- .../server/rules_client/rules_client.ts | 7 ++- .../server/es/cluster_client_adapter.ts | 2 +- .../public/application/constants/index.ts | 1 + .../components/rule_event_log_data_grid.tsx | 45 +++++++++++++++++- .../rule_event_log_list_cell_renderer.tsx | 37 +++++++++++++-- .../components/rule_event_log_list_table.tsx | 46 ++++++++++++------- 6 files changed, 112 insertions(+), 26 deletions(-) diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 44ddeded926cc..a6a09320bc60e 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -398,6 +398,7 @@ export interface GetGlobalExecutionKPIParams { dateStart: string; dateEnd?: string; filter?: string; + allNamespaces?: boolean; } export interface GetGlobalExecutionLogParams { @@ -931,7 +932,7 @@ export class RulesClient { page, perPage, sort, - allNamespaces, + allNamespaces = true, }: GetGlobalExecutionLogParams): Promise { this.logger.debug(`getGlobalExecutionLogWithAuth(): getting global execution log`); @@ -1069,6 +1070,7 @@ export class RulesClient { dateStart, dateEnd, filter, + allNamespaces = true, }: GetGlobalExecutionKPIParams) { this.logger.debug(`getGlobalExecutionLogWithAuth(): getting global execution log`); @@ -1114,7 +1116,8 @@ export class RulesClient { start: parsedDateStart.toISOString(), end: parsedDateEnd.toISOString(), aggs: getExecutionKPIAggregation(filter), - } + }, + allNamespaces ); return formatExecutionKPIResult(aggResult); diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index e807899d6290b..bbecc2aae4cdd 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -468,7 +468,7 @@ export function getQueryBodyWithAuthFilter( const { namespace, type, authFilter } = opts; const { start, end, filter } = queryOptions ?? {}; - const namespaceQuery = getNamespaceQuery(namespace); + const namespaceQuery = namespace ? getNamespaceQuery(namespace) : undefined; let dslFilterQuery: estypes.QueryDslBoolQuery['filter']; try { const filterKueryNode = filter ? fromKueryExpression(filter) : null; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts b/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts index 19d3b038c6350..a8b15215632c1 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/constants/index.ts @@ -44,6 +44,7 @@ export const DEFAULT_RULE_INTERVAL = '1m'; export const RULE_EXECUTION_LOG_COLUMN_IDS = [ 'rule_id', 'rule_name', + 'space_ids', 'id', 'timestamp', 'execution_duration', diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx index 0f6dcc13b1667..8b499d828c2d9 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useMemo, useCallback } from 'react'; +import React, { useMemo, useCallback, useEffect } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { @@ -60,6 +60,7 @@ export interface RuleEventLogDataGrid { pageSizeOptions?: number[]; selectedRunLog?: IExecutionLog; showRuleNameAndIdColumns?: boolean; + showSpaceColumns?: boolean; onChangeItemsPerPage: (pageSize: number) => void; onChangePage: (pageIndex: number) => void; onFilterChange: (filter: string[]) => void; @@ -162,6 +163,7 @@ export const RuleEventLogDataGrid = (props: RuleEventLogDataGrid) => { visibleColumns, selectedRunLog, showRuleNameAndIdColumns = false, + showSpaceColumns = false, setVisibleColumns, setSortingColumns, onChangeItemsPerPage, @@ -215,6 +217,25 @@ export const RuleEventLogDataGrid = (props: RuleEventLogDataGrid) => { }, ] : []), + ...(showSpaceColumns + ? [ + { + id: 'space_ids', + displayAsText: i18n.translate( + 'xpack.triggersActionsUI.sections.ruleDetails.eventLogColumn.ruleName', + { + defaultMessage: 'Space', + } + ), + isSortable: getIsColumnSortable('space_ids'), + actions: { + showSortAsc: false, + showSortDesc: false, + showHide: false, + }, + }, + ] + : []), { id: 'id', displayAsText: i18n.translate( @@ -429,9 +450,27 @@ export const RuleEventLogDataGrid = (props: RuleEventLogDataGrid) => { isSortable: getIsColumnSortable('timed_out'), }, ], - [getPaginatedRowIndex, onFlyoutOpen, onFilterChange, showRuleNameAndIdColumns, logs] + [ + getPaginatedRowIndex, + onFlyoutOpen, + onFilterChange, + showRuleNameAndIdColumns, + showSpaceColumns, + logs, + ] ); + useEffect(() => { + if (showSpaceColumns && !visibleColumns.includes('space_ids')) { + const ruleNameIndex = visibleColumns.findIndex((c) => c === 'rule_name'); + const newVisibleColumns = [...visibleColumns]; + newVisibleColumns.splice(ruleNameIndex + 1, 0, 'space_ids'); + setVisibleColumns(newVisibleColumns); + } else if (!showSpaceColumns && visibleColumns.includes('space_ids')) { + setVisibleColumns(visibleColumns.filter((c) => c !== 'space_ids')); + } + }, [showSpaceColumns, setVisibleColumns, visibleColumns]); + const columnVisibilityProps = useMemo( () => ({ visibleColumns, @@ -560,6 +599,7 @@ export const RuleEventLogDataGrid = (props: RuleEventLogDataGrid) => { const actionErrors = logs[pagedRowIndex]?.num_errored_actions || (0 as number); const version = logs?.[pagedRowIndex]?.version; const ruleId = runLog?.rule_id; + const spaceIds = runLog?.space_ids; if (columnId === 'num_errored_actions' && runLog) { return ( @@ -592,6 +632,7 @@ export const RuleEventLogDataGrid = (props: RuleEventLogDataGrid) => { version={version} dateFormat={dateFormat} ruleId={ruleId} + spaceIds={spaceIds} /> diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index 0f6e0477642b3..696ed272fbb6d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -5,13 +5,15 @@ * 2.0. */ -import React, { useCallback } from 'react'; +import React, { useCallback, useState, useEffect, useMemo } from 'react'; import moment from 'moment'; +import { SpacesData } from '@kbn/spaces-plugin/public'; import { EuiLink } from '@elastic/eui'; import { RuleAlertingOutcome } from '@kbn/alerting-plugin/common'; import { useHistory } from 'react-router-dom'; import { routeToRuleDetails } from '../../../constants'; import { formatRuleAlertCount } from '../../../../common/lib/format_rule_alert_count'; +import { useKibana } from '../../../../common/lib/kibana'; import { RuleEventLogListStatus } from './rule_event_log_list_status'; import { RuleDurationFormat } from '../../rules_list/components/rule_duration_format'; import { @@ -27,15 +29,34 @@ export type ColumnId = typeof RULE_EXECUTION_LOG_COLUMN_IDS[number]; interface RuleEventLogListCellRendererProps { columnId: ColumnId; version?: string; - value?: string; + value?: string | string[]; dateFormat?: string; ruleId?: string; + spaceIds?: string[]; } export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRendererProps) => { - const { columnId, value, version, dateFormat = DEFAULT_DATE_FORMAT, ruleId } = props; + const { columnId, value, version, dateFormat = DEFAULT_DATE_FORMAT, ruleId, spaceIds } = props; + const [spacesData, setSpacesData] = useState(undefined); + const { spaces } = useKibana().services; + const spacesService = spaces?.ui.useSpaces(); + + useEffect(() => { + if (columnId === 'rule_name' || columnId === 'space_ids') { + (async () => { + const result = await spacesService?.spacesDataPromise; + setSpacesData(result); + })(); + } + }, [spaces, columnId, spacesService, setSpacesData]); + const history = useHistory(); + const activeSpace = useMemo( + () => spacesData?.spacesMap.get(spacesData?.activeSpaceId), + [spacesData] + ); + const onClickRuleName = useCallback( () => ruleId && history.push(routeToRuleDetails.replace(':ruleId', ruleId)), [ruleId, history] @@ -54,15 +75,21 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer } if (columnId === 'rule_name' && ruleId) { + if (activeSpace && !spaceIds?.includes(activeSpace.id)) return <>{value}; return {value}; } + if (columnId === 'space_ids') { + if (activeSpace && value.includes(activeSpace.id)) return <>{activeSpace.name}; + if (spacesData) return <>{spacesData.spacesMap.get(value[0])?.name ?? value[0]}; + } + if (RULE_EXECUTION_LOG_ALERT_COUNT_COLUMNS.includes(columnId)) { - return <>{formatRuleAlertCount(value, version)}; + return <>{formatRuleAlertCount(value as string, version)}; } if (RULE_EXECUTION_LOG_DURATION_COLUMNS.includes(columnId)) { - return ; + return ; } return <>{value}; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx index 58cd6447ca737..c1abaf334d833 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx @@ -20,6 +20,7 @@ import { OnTimeChangeProps, } from '@elastic/eui'; import { IExecutionLog } from '@kbn/alerting-plugin/common'; +import { SpacesContextProps } from '@kbn/spaces-plugin/public'; import { useKibana } from '../../../../common/lib/kibana'; import { RULE_EXECUTION_DEFAULT_INITIAL_VISIBLE_COLUMNS, @@ -38,6 +39,8 @@ import { withBulkRuleOperations, } from '../../common/components/with_bulk_rule_api_operations'; +const getEmptyFunctionComponent: React.FC = ({ children }) => <>{children}; + const getParsedDate = (date: string) => { if (date.includes('now')) { return datemath.parse(date)?.format() || date; @@ -84,6 +87,7 @@ export type RuleEventLogListCommonProps = { overrideLoadExecutionLogAggregations?: RuleApis['loadExecutionLogAggregations']; overrideLoadGlobalExecutionLogAggregations?: RuleApis['loadGlobalExecutionLogAggregations']; hasRuleNames?: boolean; + hasSpaceNames?: boolean; } & Pick; export type RuleEventLogListTableProps = @@ -106,9 +110,16 @@ export const RuleEventLogListTable = ( overrideLoadExecutionLogAggregations, initialPageSize = 10, hasRuleNames = false, + hasSpaceNames = true, } = props; - const { uiSettings, notifications } = useKibana().services; + const { uiSettings, notifications, spaces } = useKibana().services; + + // eslint-disable-next-line react-hooks/exhaustive-deps + const SpacesContextWrapper = useCallback( + spaces ? spaces.ui.components.getSpacesContextProvider : getEmptyFunctionComponent, + [spaces] + ); const [searchText, setSearchText] = useState(''); const [search, setSearch] = useState(''); @@ -299,21 +310,24 @@ export const RuleEventLogListTable = ( {isLoading && ( )} - + + + ); }; From c64bacab8acca1a09c8ac29ccf96d22c35d5e71e Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 17 Oct 2022 12:35:49 -0500 Subject: [PATCH 03/20] Add ability to link across spaces --- .../server/rules_client/rules_client.ts | 4 +-- .../load_execution_log_aggregations.ts | 7 +++- .../logs_list/components/logs_list.tsx | 1 + .../rule_event_log_list_cell_renderer.tsx | 24 +++++++++++--- .../components/rule_event_log_list_table.tsx | 32 ++++++++++++++++--- 5 files changed, 57 insertions(+), 11 deletions(-) diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index a6a09320bc60e..5d13265972fdf 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -932,7 +932,7 @@ export class RulesClient { page, perPage, sort, - allNamespaces = true, + allNamespaces, }: GetGlobalExecutionLogParams): Promise { this.logger.debug(`getGlobalExecutionLogWithAuth(): getting global execution log`); @@ -1070,7 +1070,7 @@ export class RulesClient { dateStart, dateEnd, filter, - allNamespaces = true, + allNamespaces, }: GetGlobalExecutionKPIParams) { this.logger.debug(`getGlobalExecutionLogWithAuth(): getting global execution log`); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts index bf5e529499b42..59341fc9e0222 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts @@ -59,7 +59,10 @@ export interface LoadExecutionLogAggregationsProps { sort?: SortField[]; } -export type LoadGlobalExecutionLogAggregationsProps = Omit; +export type LoadGlobalExecutionLogAggregationsProps = Omit< + LoadExecutionLogAggregationsProps, + 'id' +> & { allNamespaces?: boolean }; export const loadExecutionLogAggregations = async ({ id, @@ -103,6 +106,7 @@ export const loadGlobalExecutionLogAggregations = async ({ perPage = 10, page = 0, sort = [], + allNamespaces = false, }: LoadGlobalExecutionLogAggregationsProps & { http: HttpSetup }) => { const sortField: any[] = sort; const filter = getFilter({ outcomeFilter, message }); @@ -119,6 +123,7 @@ export const loadGlobalExecutionLogAggregations = async ({ // whereas data grid sorts are 0 indexed. page: page + 1, sort: sortField.length ? JSON.stringify(sortField) : undefined, + all_namespaces: allNamespaces, }, } ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/logs_list/components/logs_list.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/logs_list/components/logs_list.tsx index 79e617ee05a49..404457af8fd01 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/logs_list/components/logs_list.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/logs_list/components/logs_list.tsx @@ -20,6 +20,7 @@ export const LogsList = () => { refreshToken: 0, initialPageSize: 50, hasRuleNames: true, + hasAllSpaceSwitch: true, localStorageKey: GLOBAL_EVENT_LOG_LIST_STORAGE_KEY, }); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index 696ed272fbb6d..646805a02d104 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -57,11 +57,27 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer [spacesData] ); - const onClickRuleName = useCallback( - () => ruleId && history.push(routeToRuleDetails.replace(':ruleId', ruleId)), - [ruleId, history] + const ruleOnDifferentSpace = useMemo( + () => activeSpace && !spaceIds?.includes(activeSpace.id), + [activeSpace, spaceIds] ); + const onClickRuleName = useCallback(() => { + if (!ruleId) return; + const ruleRoute = routeToRuleDetails.replace(':ruleId', ruleId); + if (ruleOnDifferentSpace) { + const [linkedSpaceId] = spaceIds ?? []; + const spacePath = linkedSpaceId !== 'default' ? `/s/${linkedSpaceId}` : ''; + const historyPathname = history.location.pathname; + const newPathname = `${spacePath}${window.location.pathname + .replace(/^\/s\/([^/])+/, '') + .replace(historyPathname, ruleRoute)}`; + window.location.pathname = newPathname; + return; + } + history.push(ruleRoute); + }, [ruleId, history, ruleOnDifferentSpace, spaceIds]); + if (typeof value === 'undefined') { return null; } @@ -75,7 +91,7 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer } if (columnId === 'rule_name' && ruleId) { - if (activeSpace && !spaceIds?.includes(activeSpace.id)) return <>{value}; + // if (ruleOnDifferentSpace) return <>{value}; return {value}; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx index c1abaf334d833..86500c1518a73 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx @@ -18,6 +18,7 @@ import { Pagination, EuiSuperDatePicker, OnTimeChangeProps, + EuiSwitch, } from '@elastic/eui'; import { IExecutionLog } from '@kbn/alerting-plugin/common'; import { SpacesContextProps } from '@kbn/spaces-plugin/public'; @@ -69,6 +70,13 @@ const getDefaultColumns = (columns: string[]) => { return [...LOCKED_COLUMNS, ...columnsWithoutLockedColumn]; }; +const ALL_SPACES_LABEL = i18n.translate( + 'xpack.triggersActionsUI.ruleEventLogList.showAllSpacesToggle', + { + defaultMessage: 'Show rules from all spaces', + } +); + const updateButtonProps = { iconOnly: true, fill: false, @@ -87,7 +95,7 @@ export type RuleEventLogListCommonProps = { overrideLoadExecutionLogAggregations?: RuleApis['loadExecutionLogAggregations']; overrideLoadGlobalExecutionLogAggregations?: RuleApis['loadGlobalExecutionLogAggregations']; hasRuleNames?: boolean; - hasSpaceNames?: boolean; + hasAllSpaceSwitch?: boolean; } & Pick; export type RuleEventLogListTableProps = @@ -110,7 +118,7 @@ export const RuleEventLogListTable = ( overrideLoadExecutionLogAggregations, initialPageSize = 10, hasRuleNames = false, - hasSpaceNames = true, + hasAllSpaceSwitch = false, } = props; const { uiSettings, notifications, spaces } = useKibana().services; @@ -128,6 +136,7 @@ export const RuleEventLogListTable = ( const [internalRefreshToken, setInternalRefreshToken] = useState( refreshToken ); + const [showFromAllSpaces, setShowFromAllSpaces] = useState(false); // Data grid states const [logs, setLogs] = useState(); @@ -208,6 +217,7 @@ export const RuleEventLogListTable = ( dateEnd: getParsedDate(dateEnd), page: pagination.pageIndex, perPage: pagination.pageSize, + allNamespaces: showFromAllSpaces, }); setLogs(result.data); setPagination({ @@ -301,6 +311,10 @@ export const RuleEventLogListTable = ( [search, setSearchText] ); + const onShowAllSpacesChange = useCallback(() => { + setShowFromAllSpaces(!showFromAllSpaces); + }, [showFromAllSpaces, setShowFromAllSpaces]); + const renderList = () => { if (!logs) { return ; @@ -319,7 +333,7 @@ export const RuleEventLogListTable = ( dateFormat={dateFormat} selectedRunLog={selectedRunLog} showRuleNameAndIdColumns={hasRuleNames} - showSpaceColumns={hasSpaceNames} + showSpaceColumns={showFromAllSpaces} onChangeItemsPerPage={onChangeItemsPerPage} onChangePage={onChangePage} onFlyoutOpen={onFlyoutOpen} @@ -343,6 +357,7 @@ export const RuleEventLogListTable = ( pagination.pageIndex, pagination.pageSize, searchText, + showFromAllSpaces, ]); useEffect(() => { @@ -364,7 +379,7 @@ export const RuleEventLogListTable = ( return ( - + ( updateButtonProps={updateButtonProps} /> + {hasAllSpaceSwitch && ( + + + + )} From d9795925ee06f4a4506e06937126f677566a0734 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 17 Oct 2022 12:38:21 -0500 Subject: [PATCH 04/20] Fix allNamespace query on default space --- x-pack/plugins/event_log/server/es/cluster_client_adapter.ts | 2 +- x-pack/plugins/event_log/server/event_log_client.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index bbecc2aae4cdd..2f7d9c9ee70fe 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -468,7 +468,7 @@ export function getQueryBodyWithAuthFilter( const { namespace, type, authFilter } = opts; const { start, end, filter } = queryOptions ?? {}; - const namespaceQuery = namespace ? getNamespaceQuery(namespace) : undefined; + const namespaceQuery = namespace !== '*' ? getNamespaceQuery(namespace) : undefined; let dslFilterQuery: estypes.QueryDslBoolQuery['filter']; try { const filterKueryNode = filter ? fromKueryExpression(filter) : null; diff --git a/x-pack/plugins/event_log/server/event_log_client.ts b/x-pack/plugins/event_log/server/event_log_client.ts index 9c22dfd41e13f..a05d2830027ca 100644 --- a/x-pack/plugins/event_log/server/event_log_client.ts +++ b/x-pack/plugins/event_log/server/event_log_client.ts @@ -159,7 +159,7 @@ export class EventLogClient implements IEventLogClient { return await this.esContext.esAdapter.aggregateEventsWithAuthFilter({ index: this.esContext.esNames.indexPattern, - namespace: allNamespaces ? undefined : await this.getNamespace(), + namespace: allNamespaces ? '*' : await this.getNamespace(), type, authFilter, aggregateOptions: { ...aggregateOptions, aggs } as AggregateOptionsType, From 30fcaf5ec2f5d26e2966e30497e1d5701582e2b4 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 17 Oct 2022 15:16:06 -0500 Subject: [PATCH 05/20] Fix KPI and link space switch to permissions --- .../server/routes/get_global_execution_kpi.ts | 5 +- .../routes/get_global_execution_logs.ts | 8 +- .../alerting/server/routes/lib/index.ts | 1 + .../server/routes/lib/rewrite_namespaces.ts | 11 +++ .../server/rules_client/rules_client.ts | 12 +-- .../server/es/cluster_client_adapter.ts | 14 ++-- .../event_log/server/event_log_client.ts | 4 +- x-pack/plugins/event_log/server/types.ts | 2 +- .../load_execution_log_aggregations.ts | 6 +- .../load_global_execution_kpi_aggregations.ts | 3 + .../rule_event_log_list_cell_renderer.tsx | 18 +---- .../components/rule_event_log_list_kpi.tsx | 5 +- .../components/rule_event_log_list_table.tsx | 80 ++++++++++++------- .../public/common/lib/kibana/index.ts | 1 + .../common/lib/kibana/use_spaces_data.tsx | 24 ++++++ 15 files changed, 127 insertions(+), 67 deletions(-) create mode 100644 x-pack/plugins/alerting/server/routes/lib/rewrite_namespaces.ts create mode 100644 x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/use_spaces_data.tsx diff --git a/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts b/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts index 29937cc3d8c98..2aec9d998a9e6 100644 --- a/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts +++ b/x-pack/plugins/alerting/server/routes/get_global_execution_kpi.ts @@ -7,7 +7,7 @@ import { IRouter } from '@kbn/core/server'; import { schema } from '@kbn/config-schema'; import { AlertingRequestHandlerContext, INTERNAL_BASE_ALERTING_API_PATH } from '../types'; -import { RewriteRequestCase, verifyAccessAndContext } from './lib'; +import { RewriteRequestCase, verifyAccessAndContext, rewriteNamespaces } from './lib'; import { GetGlobalExecutionKPIParams } from '../rules_client'; import { ILicenseState } from '../lib'; @@ -15,14 +15,17 @@ const querySchema = schema.object({ date_start: schema.string(), date_end: schema.maybe(schema.string()), filter: schema.maybe(schema.string()), + namespaces: schema.maybe(schema.arrayOf(schema.string())), }); const rewriteReq: RewriteRequestCase = ({ date_start: dateStart, date_end: dateEnd, + namespaces, ...rest }) => ({ ...rest, + namespaces: rewriteNamespaces(namespaces), dateStart, dateEnd, }); diff --git a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts index 859cbfaa8424d..e08ec1ac5bcb8 100644 --- a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts +++ b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.ts @@ -9,7 +9,7 @@ import { IRouter } from '@kbn/core/server'; import { schema } from '@kbn/config-schema'; import { ILicenseState } from '../lib'; import { GetGlobalExecutionLogParams } from '../rules_client'; -import { RewriteRequestCase, verifyAccessAndContext } from './lib'; +import { RewriteRequestCase, verifyAccessAndContext, rewriteNamespaces } from './lib'; import { AlertingRequestHandlerContext, INTERNAL_BASE_ALERTING_API_PATH } from '../types'; const sortOrderSchema = schema.oneOf([schema.literal('asc'), schema.literal('desc')]); @@ -38,21 +38,21 @@ const querySchema = schema.object({ per_page: schema.number({ defaultValue: 10, min: 1 }), page: schema.number({ defaultValue: 1, min: 1 }), sort: sortFieldsSchema, - all_namespaces: schema.maybe(schema.boolean()), + namespaces: schema.maybe(schema.arrayOf(schema.string())), }); const rewriteReq: RewriteRequestCase = ({ date_start: dateStart, date_end: dateEnd, per_page: perPage, - all_namespaces: allNamespaces, + namespaces, ...rest }) => ({ ...rest, + namespaces: rewriteNamespaces(namespaces), dateStart, dateEnd, perPage, - allNamespaces, }); export const getGlobalExecutionLogRoute = ( diff --git a/x-pack/plugins/alerting/server/routes/lib/index.ts b/x-pack/plugins/alerting/server/routes/lib/index.ts index e772f091bb059..90d903ada6eed 100644 --- a/x-pack/plugins/alerting/server/routes/lib/index.ts +++ b/x-pack/plugins/alerting/server/routes/lib/index.ts @@ -19,3 +19,4 @@ export type { export { verifyAccessAndContext } from './verify_access_and_context'; export { countUsageOfPredefinedIds } from './count_usage_of_predefined_ids'; export { rewriteRule } from './rewrite_rule'; +export { rewriteNamespaces } from './rewrite_namespaces'; diff --git a/x-pack/plugins/alerting/server/routes/lib/rewrite_namespaces.ts b/x-pack/plugins/alerting/server/routes/lib/rewrite_namespaces.ts new file mode 100644 index 0000000000000..5339b41526efe --- /dev/null +++ b/x-pack/plugins/alerting/server/routes/lib/rewrite_namespaces.ts @@ -0,0 +1,11 @@ +/* + * 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 rewriteNamespaces = (namespaces?: Array) => + namespaces + ? namespaces.map((id: string | undefined) => (id === 'default' ? undefined : id)) + : undefined; diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 5d13265972fdf..8046756982be4 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -398,7 +398,7 @@ export interface GetGlobalExecutionKPIParams { dateStart: string; dateEnd?: string; filter?: string; - allNamespaces?: boolean; + namespaces?: Array; } export interface GetGlobalExecutionLogParams { @@ -408,7 +408,7 @@ export interface GetGlobalExecutionLogParams { page: number; perPage: number; sort: estypes.Sort; - allNamespaces?: boolean; + namespaces?: Array; } export interface GetActionErrorLogByIdParams { @@ -932,7 +932,7 @@ export class RulesClient { page, perPage, sort, - allNamespaces, + namespaces, }: GetGlobalExecutionLogParams): Promise { this.logger.debug(`getGlobalExecutionLogWithAuth(): getting global execution log`); @@ -984,7 +984,7 @@ export class RulesClient { sort, }), }, - allNamespaces + namespaces ); return formatExecutionLogResult(aggResult); @@ -1070,7 +1070,7 @@ export class RulesClient { dateStart, dateEnd, filter, - allNamespaces, + namespaces, }: GetGlobalExecutionKPIParams) { this.logger.debug(`getGlobalExecutionLogWithAuth(): getting global execution log`); @@ -1117,7 +1117,7 @@ export class RulesClient { end: parsedDateEnd.toISOString(), aggs: getExecutionKPIAggregation(filter), }, - allNamespaces + namespaces ); return formatExecutionKPIResult(aggResult); diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index 2f7d9c9ee70fe..ded9f4ae31cd9 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -52,7 +52,7 @@ interface QueryOptionsEventsBySavedObjectFilter { export interface AggregateEventsWithAuthFilter { index: string; - namespace: string | undefined; + namespaces: Array; type: string; authFilter: KueryNode; aggregateOptions: AggregateOptionsType; @@ -465,10 +465,10 @@ export function getQueryBodyWithAuthFilter( opts: AggregateEventsWithAuthFilter, queryOptions: QueryOptionsType ) { - const { namespace, type, authFilter } = opts; + const { namespaces, type, authFilter } = opts; const { start, end, filter } = queryOptions ?? {}; - const namespaceQuery = namespace !== '*' ? getNamespaceQuery(namespace) : undefined; + const namespaceQuery = namespaces.map((namespace) => getNamespaceQuery(namespace)); let dslFilterQuery: estypes.QueryDslBoolQuery['filter']; try { const filterKueryNode = filter ? fromKueryExpression(filter) : null; @@ -501,8 +501,12 @@ export function getQueryBodyWithAuthFilter( }, }, }, - // @ts-expect-error undefined is not assignable as QueryDslTermQuery value - namespaceQuery, + { + bool: { + // @ts-expect-error undefined is not assignable as QueryDslTermQuery value + should: namespaceQuery, + }, + }, ]; const musts: estypes.QueryDslQueryContainer[] = [ diff --git a/x-pack/plugins/event_log/server/event_log_client.ts b/x-pack/plugins/event_log/server/event_log_client.ts index a05d2830027ca..1fc82c24d9f17 100644 --- a/x-pack/plugins/event_log/server/event_log_client.ts +++ b/x-pack/plugins/event_log/server/event_log_client.ts @@ -143,7 +143,7 @@ export class EventLogClient implements IEventLogClient { type: string, authFilter: KueryNode, options?: AggregateOptionsType, - allNamespaces?: boolean + namespaces?: Array ) { if (!authFilter) { throw new Error('No authorization filter defined!'); @@ -159,7 +159,7 @@ export class EventLogClient implements IEventLogClient { return await this.esContext.esAdapter.aggregateEventsWithAuthFilter({ index: this.esContext.esNames.indexPattern, - namespace: allNamespaces ? '*' : await this.getNamespace(), + namespaces: namespaces ?? [await this.getNamespace()], type, authFilter, aggregateOptions: { ...aggregateOptions, aggs } as AggregateOptionsType, diff --git a/x-pack/plugins/event_log/server/types.ts b/x-pack/plugins/event_log/server/types.ts index 26ce4d1da0161..91955a3a78297 100644 --- a/x-pack/plugins/event_log/server/types.ts +++ b/x-pack/plugins/event_log/server/types.ts @@ -67,7 +67,7 @@ export interface IEventLogClient { type: string, authFilter: KueryNode, options?: Partial, - allNamespaces?: boolean + namespaces?: Array ): Promise; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts index 59341fc9e0222..ed4b48f31ecf2 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts @@ -62,7 +62,7 @@ export interface LoadExecutionLogAggregationsProps { export type LoadGlobalExecutionLogAggregationsProps = Omit< LoadExecutionLogAggregationsProps, 'id' -> & { allNamespaces?: boolean }; +> & { namespaces?: Array }; export const loadExecutionLogAggregations = async ({ id, @@ -106,7 +106,7 @@ export const loadGlobalExecutionLogAggregations = async ({ perPage = 10, page = 0, sort = [], - allNamespaces = false, + namespaces, }: LoadGlobalExecutionLogAggregationsProps & { http: HttpSetup }) => { const sortField: any[] = sort; const filter = getFilter({ outcomeFilter, message }); @@ -123,7 +123,7 @@ export const loadGlobalExecutionLogAggregations = async ({ // whereas data grid sorts are 0 indexed. page: page + 1, sort: sortField.length ? JSON.stringify(sortField) : undefined, - all_namespaces: allNamespaces, + namespaces: namespaces ? JSON.stringify(namespaces) : namespaces, }, } ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_global_execution_kpi_aggregations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_global_execution_kpi_aggregations.ts index 332e14ad4383f..7052257d1fc87 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_global_execution_kpi_aggregations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_global_execution_kpi_aggregations.ts @@ -16,6 +16,7 @@ export interface LoadGlobalExecutionKPIAggregationsProps { message?: string; dateStart: string; dateEnd?: string; + namespaces?: Array; } export const loadGlobalExecutionKPIAggregations = ({ @@ -25,6 +26,7 @@ export const loadGlobalExecutionKPIAggregations = ({ message, dateStart, dateEnd, + namespaces, }: LoadGlobalExecutionKPIAggregationsProps & { http: HttpSetup }) => { const filter = getFilter({ outcomeFilter, message }); @@ -33,6 +35,7 @@ export const loadGlobalExecutionKPIAggregations = ({ filter: filter.length ? filter.join(' and ') : undefined, date_start: dateStart, date_end: dateEnd, + namespaces: namespaces ? JSON.stringify(namespaces) : namespaces, }, }); }; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index 646805a02d104..36417d9189c8a 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -5,15 +5,14 @@ * 2.0. */ -import React, { useCallback, useState, useEffect, useMemo } from 'react'; +import React, { useCallback, useMemo } from 'react'; import moment from 'moment'; -import { SpacesData } from '@kbn/spaces-plugin/public'; import { EuiLink } from '@elastic/eui'; import { RuleAlertingOutcome } from '@kbn/alerting-plugin/common'; import { useHistory } from 'react-router-dom'; import { routeToRuleDetails } from '../../../constants'; import { formatRuleAlertCount } from '../../../../common/lib/format_rule_alert_count'; -import { useKibana } from '../../../../common/lib/kibana'; +import { useSpacesData } from '../../../../common/lib/kibana'; import { RuleEventLogListStatus } from './rule_event_log_list_status'; import { RuleDurationFormat } from '../../rules_list/components/rule_duration_format'; import { @@ -37,18 +36,7 @@ interface RuleEventLogListCellRendererProps { export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRendererProps) => { const { columnId, value, version, dateFormat = DEFAULT_DATE_FORMAT, ruleId, spaceIds } = props; - const [spacesData, setSpacesData] = useState(undefined); - const { spaces } = useKibana().services; - const spacesService = spaces?.ui.useSpaces(); - - useEffect(() => { - if (columnId === 'rule_name' || columnId === 'space_ids') { - (async () => { - const result = await spacesService?.spacesDataPromise; - setSpacesData(result); - })(); - } - }, [spaces, columnId, spacesService, setSpacesData]); + const spacesData = useSpacesData(); const history = useHistory(); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_kpi.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_kpi.tsx index 970390359f0d7..0696f857261ec 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_kpi.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_kpi.tsx @@ -84,6 +84,7 @@ export type RuleEventLogListKPIProps = { outcomeFilter?: string[]; message?: string; refreshToken?: number; + namespaces?: Array; } & Pick; export const RuleEventLogListKPI = (props: RuleEventLogListKPIProps) => { @@ -94,6 +95,7 @@ export const RuleEventLogListKPI = (props: RuleEventLogListKPIProps) => { outcomeFilter, message, refreshToken, + namespaces, loadExecutionKPIAggregations, loadGlobalExecutionKPIAggregations, } = props; @@ -122,6 +124,7 @@ export const RuleEventLogListKPI = (props: RuleEventLogListKPIProps) => { dateEnd: getParsedDate(dateEnd), outcomeFilter, message, + ...(namespaces ? { namespaces } : {}), }); setKpi(newKpi); } catch (e) { @@ -136,7 +139,7 @@ export const RuleEventLogListKPI = (props: RuleEventLogListKPIProps) => { useEffect(() => { loadKPIs(); // eslint-disable-next-line react-hooks/exhaustive-deps - }, [ruleId, dateStart, dateEnd, outcomeFilter, message]); + }, [ruleId, dateStart, dateEnd, outcomeFilter, message, namespaces]); useEffect(() => { if (isInitialized.current) { diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx index 86500c1518a73..9e9dbf72e48ac 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx @@ -22,7 +22,7 @@ import { } from '@elastic/eui'; import { IExecutionLog } from '@kbn/alerting-plugin/common'; import { SpacesContextProps } from '@kbn/spaces-plugin/public'; -import { useKibana } from '../../../../common/lib/kibana'; +import { useKibana, useSpacesData } from '../../../../common/lib/kibana'; import { RULE_EXECUTION_DEFAULT_INITIAL_VISIBLE_COLUMNS, GLOBAL_EXECUTION_DEFAULT_INITIAL_VISIBLE_COLUMNS, @@ -121,13 +121,7 @@ export const RuleEventLogListTable = ( hasAllSpaceSwitch = false, } = props; - const { uiSettings, notifications, spaces } = useKibana().services; - - // eslint-disable-next-line react-hooks/exhaustive-deps - const SpacesContextWrapper = useCallback( - spaces ? spaces.ui.components.getSpacesContextProvider : getEmptyFunctionComponent, - [spaces] - ); + const { uiSettings, notifications } = useKibana().services; const [searchText, setSearchText] = useState(''); const [search, setSearch] = useState(''); @@ -173,6 +167,20 @@ export const RuleEventLogListTable = ( ); }); + const spacesData = useSpacesData(); + const accessibleSpaceIds = useMemo( + () => (spacesData ? [...spacesData.spacesMap.values()].map((e) => e.id) : []), + [spacesData] + ); + const areMultipleSpacesAccessible = useMemo( + () => accessibleSpaceIds.length > 1, + [accessibleSpaceIds] + ); + const namespaces = useMemo( + () => (showFromAllSpaces && spacesData ? accessibleSpaceIds : undefined), + [showFromAllSpaces, spacesData, accessibleSpaceIds] + ); + const isInitialized = useRef(false); const isOnLastPage = useMemo(() => { @@ -217,7 +225,7 @@ export const RuleEventLogListTable = ( dateEnd: getParsedDate(dateEnd), page: pagination.pageIndex, perPage: pagination.pageSize, - allNamespaces: showFromAllSpaces, + namespaces, }); setLogs(result.data); setPagination({ @@ -324,24 +332,22 @@ export const RuleEventLogListTable = ( {isLoading && ( )} - - - + ); }; @@ -407,7 +413,7 @@ export const RuleEventLogListTable = ( updateButtonProps={updateButtonProps} /> - {hasAllSpaceSwitch && ( + {hasAllSpaceSwitch && areMultipleSpacesAccessible && ( ( outcomeFilter={filter} message={searchText} refreshToken={internalRefreshToken} + namespaces={namespaces} /> @@ -451,7 +458,22 @@ export const RuleEventLogListTable = ( ); }; -export const RuleEventLogListTableWithApi = withBulkRuleOperations(RuleEventLogListTable); +const RuleEventLogListTableWithSpaces: React.FC = (props) => { + const { spaces } = useKibana().services; + + // eslint-disable-next-line react-hooks/exhaustive-deps + const SpacesContextWrapper = useCallback( + spaces ? spaces.ui.components.getSpacesContextProvider : getEmptyFunctionComponent, + [spaces] + ); + return ( + + + + ); +}; + +export const RuleEventLogListTableWithApi = withBulkRuleOperations(RuleEventLogListTableWithSpaces); // eslint-disable-next-line import/no-default-export export { RuleEventLogListTableWithApi as default }; diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/index.ts b/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/index.ts index 3970993a0c732..de8f3b63d1c5c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/index.ts @@ -6,3 +6,4 @@ */ export * from './kibana_react'; +export * from './use_spaces_data'; diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/use_spaces_data.tsx b/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/use_spaces_data.tsx new file mode 100644 index 0000000000000..54f2baafa21c3 --- /dev/null +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/use_spaces_data.tsx @@ -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 { useState, useEffect } from 'react'; +import { SpacesData } from '@kbn/spaces-plugin/public'; +import { useKibana } from './kibana_react'; + +export const useSpacesData = () => { + const { spaces } = useKibana().services; + const [spacesData, setSpacesData] = useState(undefined); + const spacesService = spaces?.ui.useSpaces(); + + useEffect(() => { + (async () => { + const result = await spacesService?.spacesDataPromise; + setSpacesData(result); + })(); + }, [spaces, spacesService, setSpacesData]); + return spacesData; +}; From c1b68c74a69838999e08329a54f8be002b57da4b Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 17 Oct 2022 15:43:00 -0500 Subject: [PATCH 06/20] Open alternate space rules in new tab --- .../components/rule_event_log_list_cell_renderer.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index 36417d9189c8a..97066be7fe1fe 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -60,7 +60,8 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer const newPathname = `${spacePath}${window.location.pathname .replace(/^\/s\/([^/])+/, '') .replace(historyPathname, ruleRoute)}`; - window.location.pathname = newPathname; + const newUrl = window.location.href.replace(window.location.pathname, newPathname); + window.open(newUrl, '_blank'); return; } history.push(ruleRoute); From 99dd96050e51f10ee63cc8f9c35079ca4f5f9ebf Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 17 Oct 2022 16:35:22 -0500 Subject: [PATCH 07/20] Fix Jest 11 --- .../server/es/cluster_client_adapter.test.ts | 90 +++++++++++++------ .../server/es/cluster_client_adapter.ts | 6 +- 2 files changed, 67 insertions(+), 29 deletions(-) diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts index ea3e98e599ab5..a7a9e8bd0867a 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.test.ts @@ -779,7 +779,7 @@ describe('aggregateEventsWithAuthFilter', () => { }); const options: AggregateEventsWithAuthFilter = { index: 'index-name', - namespace: 'namespace', + namespaces: ['namespace'], type: 'saved-object-type', aggregateOptions: DEFAULT_OPTIONS as AggregateOptionsType, authFilter: fromKueryExpression('test:test'), @@ -1515,7 +1515,7 @@ describe('getQueryBody', () => { describe('getQueryBodyWithAuthFilter', () => { const options = { index: 'index-name', - namespace: undefined, + namespaces: undefined, type: 'saved-object-type', authFilter: fromKueryExpression('test:test'), }; @@ -1559,11 +1559,17 @@ describe('getQueryBodyWithAuthFilter', () => { }, { bool: { - must_not: { - exists: { - field: 'kibana.saved_objects.namespace', + should: [ + { + bool: { + must_not: { + exists: { + field: 'kibana.saved_objects.namespace', + }, + }, + }, }, - }, + ], }, }, ], @@ -1580,7 +1586,7 @@ describe('getQueryBodyWithAuthFilter', () => { expect( getQueryBodyWithAuthFilter( logger, - { ...options, namespace: 'namespace' } as AggregateEventsWithAuthFilter, + { ...options, namespaces: ['namespace'] } as AggregateEventsWithAuthFilter, {} ) ).toEqual({ @@ -1619,10 +1625,16 @@ describe('getQueryBodyWithAuthFilter', () => { }, }, { - term: { - 'kibana.saved_objects.namespace': { - value: 'namespace', - }, + bool: { + should: [ + { + term: { + 'kibana.saved_objects.namespace': { + value: 'namespace', + }, + }, + }, + ], }, }, ], @@ -1713,11 +1725,17 @@ describe('getQueryBodyWithAuthFilter', () => { }, { bool: { - must_not: { - exists: { - field: 'kibana.saved_objects.namespace', + should: [ + { + bool: { + must_not: { + exists: { + field: 'kibana.saved_objects.namespace', + }, + }, + }, }, - }, + ], }, }, ], @@ -1772,11 +1790,17 @@ describe('getQueryBodyWithAuthFilter', () => { }, { bool: { - must_not: { - exists: { - field: 'kibana.saved_objects.namespace', + should: [ + { + bool: { + must_not: { + exists: { + field: 'kibana.saved_objects.namespace', + }, + }, + }, }, - }, + ], }, }, ], @@ -1838,11 +1862,17 @@ describe('getQueryBodyWithAuthFilter', () => { }, { bool: { - must_not: { - exists: { - field: 'kibana.saved_objects.namespace', + should: [ + { + bool: { + must_not: { + exists: { + field: 'kibana.saved_objects.namespace', + }, + }, + }, }, - }, + ], }, }, ], @@ -1905,11 +1935,17 @@ describe('getQueryBodyWithAuthFilter', () => { }, { bool: { - must_not: { - exists: { - field: 'kibana.saved_objects.namespace', + should: [ + { + bool: { + must_not: { + exists: { + field: 'kibana.saved_objects.namespace', + }, + }, + }, }, - }, + ], }, }, ], diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index ded9f4ae31cd9..63d4e21e50f8d 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -52,7 +52,7 @@ interface QueryOptionsEventsBySavedObjectFilter { export interface AggregateEventsWithAuthFilter { index: string; - namespaces: Array; + namespaces?: Array; type: string; authFilter: KueryNode; aggregateOptions: AggregateOptionsType; @@ -468,7 +468,9 @@ export function getQueryBodyWithAuthFilter( const { namespaces, type, authFilter } = opts; const { start, end, filter } = queryOptions ?? {}; - const namespaceQuery = namespaces.map((namespace) => getNamespaceQuery(namespace)); + const namespaceQuery = (namespaces ?? [undefined]).map((namespace) => + getNamespaceQuery(namespace) + ); let dslFilterQuery: estypes.QueryDslBoolQuery['filter']; try { const filterKueryNode = filter ? fromKueryExpression(filter) : null; From e0f83b143fc1bc8cfb6059f2321908db730bdd25 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 17 Oct 2022 16:49:40 -0500 Subject: [PATCH 08/20] Fix Jest 1 --- .../public/common/lib/kibana/__mocks__/index.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/__mocks__/index.ts b/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/__mocks__/index.ts index 6772eacc2aaed..e7c8215fd4625 100644 --- a/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/__mocks__/index.ts +++ b/x-pack/plugins/triggers_actions_ui/public/common/lib/kibana/__mocks__/index.ts @@ -31,3 +31,4 @@ export const useCurrentUser = jest.fn(); export const withKibana = jest.fn(createWithKibanaMock()); export const KibanaContextProvider = jest.fn(createKibanaContextProviderMock()); export const useGetUserSavedObjectPermissions = jest.fn(); +export const useSpacesData = jest.fn(); From b336fe4f653f1423dfd3540e0755cf8eca7ae407 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 18 Oct 2022 10:42:03 -0500 Subject: [PATCH 09/20] Fix Jest 4 and 10 --- .../server/lib/get_execution_log_aggregation.test.ts | 11 +++++++++++ .../server/routes/get_global_execution_logs.test.ts | 2 ++ .../server/routes/get_rule_execution_log.test.ts | 2 ++ .../rules_client/tests/get_execution_log.test.ts | 4 ++++ .../plugins/event_log/server/event_log_client.test.ts | 2 +- 5 files changed, 20 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.test.ts b/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.test.ts index ee05e3cda32f6..6a57baaacef27 100644 --- a/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.test.ts +++ b/x-pack/plugins/alerting/server/lib/get_execution_log_aggregation.test.ts @@ -280,6 +280,7 @@ describe('getExecutionLogAggregation', () => { 'error.message', 'kibana.version', 'rule.id', + 'kibana.space_ids', 'rule.name', 'kibana.alerting.outcome', ], @@ -486,6 +487,7 @@ describe('getExecutionLogAggregation', () => { 'error.message', 'kibana.version', 'rule.id', + 'kibana.space_ids', 'rule.name', 'kibana.alerting.outcome', ], @@ -692,6 +694,7 @@ describe('getExecutionLogAggregation', () => { 'error.message', 'kibana.version', 'rule.id', + 'kibana.space_ids', 'rule.name', 'kibana.alerting.outcome', ], @@ -954,6 +957,7 @@ describe('formatExecutionLogResult', () => { schedule_delay_ms: 3074, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: [], }, { id: '41b2755e-765a-4044-9745-b03875d5e79a', @@ -976,6 +980,7 @@ describe('formatExecutionLogResult', () => { schedule_delay_ms: 3126, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: [], }, ], }); @@ -1203,6 +1208,7 @@ describe('formatExecutionLogResult', () => { schedule_delay_ms: 3074, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: [], }, { id: '41b2755e-765a-4044-9745-b03875d5e79a', @@ -1225,6 +1231,7 @@ describe('formatExecutionLogResult', () => { schedule_delay_ms: 3126, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: [], }, ], }); @@ -1444,6 +1451,7 @@ describe('formatExecutionLogResult', () => { schedule_delay_ms: 3074, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: [], }, { id: '41b2755e-765a-4044-9745-b03875d5e79a', @@ -1466,6 +1474,7 @@ describe('formatExecutionLogResult', () => { schedule_delay_ms: 3126, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: [], }, ], }); @@ -1690,6 +1699,7 @@ describe('formatExecutionLogResult', () => { schedule_delay_ms: 3126, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: [], }, { id: '61bb867b-661a-471f-bf92-23471afa10b3', @@ -1712,6 +1722,7 @@ describe('formatExecutionLogResult', () => { schedule_delay_ms: 3133, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: [], }, ], }); diff --git a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.test.ts b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.test.ts index 43b08ed0787e2..3ee2b0d1816ba 100644 --- a/x-pack/plugins/alerting/server/routes/get_global_execution_logs.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_global_execution_logs.test.ts @@ -47,6 +47,7 @@ describe('getRuleExecutionLogRoute', () => { schedule_delay_ms: 3126, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule-name', + space_ids: ['namespace'], }, { id: '41b2755e-765a-4044-9745-b03875d5e79a', @@ -69,6 +70,7 @@ describe('getRuleExecutionLogRoute', () => { schedule_delay_ms: 3008, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule-name', + space_ids: ['namespace'], }, ], }; diff --git a/x-pack/plugins/alerting/server/routes/get_rule_execution_log.test.ts b/x-pack/plugins/alerting/server/routes/get_rule_execution_log.test.ts index 048da6cbabeb3..eb22a6429809a 100644 --- a/x-pack/plugins/alerting/server/routes/get_rule_execution_log.test.ts +++ b/x-pack/plugins/alerting/server/routes/get_rule_execution_log.test.ts @@ -48,6 +48,7 @@ describe('getRuleExecutionLogRoute', () => { schedule_delay_ms: 3126, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: ['namespace'], }, { id: '41b2755e-765a-4044-9745-b03875d5e79a', @@ -70,6 +71,7 @@ describe('getRuleExecutionLogRoute', () => { schedule_delay_ms: 3008, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule_name', + space_ids: ['namespace'], }, ], }; diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts index 83b85f4879cff..ffc40cd705abd 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_execution_log.test.ts @@ -385,6 +385,7 @@ describe('getExecutionLogForRule()', () => { schedule_delay_ms: 3126, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule-name', + space_ids: [], }, { id: '41b2755e-765a-4044-9745-b03875d5e79a', @@ -407,6 +408,7 @@ describe('getExecutionLogForRule()', () => { schedule_delay_ms: 3345, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule-name', + space_ids: [], }, ], }); @@ -719,6 +721,7 @@ describe('getGlobalExecutionLogWithAuth()', () => { schedule_delay_ms: 3126, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule-name', + space_ids: [], }, { id: '41b2755e-765a-4044-9745-b03875d5e79a', @@ -741,6 +744,7 @@ describe('getGlobalExecutionLogWithAuth()', () => { schedule_delay_ms: 3345, rule_id: 'a348a740-9e2c-11ec-bd64-774ed95c43ef', rule_name: 'rule-name', + space_ids: [], }, ], }); diff --git a/x-pack/plugins/event_log/server/event_log_client.test.ts b/x-pack/plugins/event_log/server/event_log_client.test.ts index 5e4fd08819fb3..b91ef3ef43836 100644 --- a/x-pack/plugins/event_log/server/event_log_client.test.ts +++ b/x-pack/plugins/event_log/server/event_log_client.test.ts @@ -256,7 +256,7 @@ describe('EventLogStart', () => { }); expect(esContext.esAdapter.aggregateEventsWithAuthFilter).toHaveBeenCalledWith({ index: esContext.esNames.indexPattern, - namespace: undefined, + namespaces: [undefined], type: 'saved-object-type', authFilter: testAuthFilter, aggregateOptions: { From a0619bc8de9056cb7bf795d7d599120140161a9c Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Tue, 18 Oct 2022 13:27:24 -0500 Subject: [PATCH 10/20] Fix i18n --- .../rule_details/components/rule_event_log_data_grid.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx index 8b499d828c2d9..e508f2473f250 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx @@ -222,7 +222,7 @@ export const RuleEventLogDataGrid = (props: RuleEventLogDataGrid) => { { id: 'space_ids', displayAsText: i18n.translate( - 'xpack.triggersActionsUI.sections.ruleDetails.eventLogColumn.ruleName', + 'xpack.triggersActionsUI.sections.ruleDetails.eventLogColumn.spaceIds', { defaultMessage: 'Space', } From 57b38daac360b0b526f85d7f3b0c7f4f011eb2f7 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Thu, 20 Oct 2022 11:57:10 -0500 Subject: [PATCH 11/20] Move space column visibility out of data grid --- .../load_execution_log_aggregations.ts | 2 +- .../components/rule_event_log_data_grid.tsx | 22 +++++-------------- .../rule_event_log_list_cell_renderer.tsx | 1 - .../components/rule_event_log_list_table.tsx | 14 ++++++++++-- 4 files changed, 18 insertions(+), 21 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts index ed4b48f31ecf2..671a1edce467d 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_execution_log_aggregations.ts @@ -123,7 +123,7 @@ export const loadGlobalExecutionLogAggregations = async ({ // whereas data grid sorts are 0 indexed. page: page + 1, sort: sortField.length ? JSON.stringify(sortField) : undefined, - namespaces: namespaces ? JSON.stringify(namespaces) : namespaces, + namespaces: namespaces ? JSON.stringify(namespaces) : undefined, }, } ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx index e508f2473f250..20f3612f3a41b 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_data_grid.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useMemo, useCallback, useEffect } from 'react'; +import React, { useMemo, useCallback } from 'react'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; import { @@ -460,24 +460,12 @@ export const RuleEventLogDataGrid = (props: RuleEventLogDataGrid) => { ] ); - useEffect(() => { - if (showSpaceColumns && !visibleColumns.includes('space_ids')) { - const ruleNameIndex = visibleColumns.findIndex((c) => c === 'rule_name'); - const newVisibleColumns = [...visibleColumns]; - newVisibleColumns.splice(ruleNameIndex + 1, 0, 'space_ids'); - setVisibleColumns(newVisibleColumns); - } else if (!showSpaceColumns && visibleColumns.includes('space_ids')) { - setVisibleColumns(visibleColumns.filter((c) => c !== 'space_ids')); - } - }, [showSpaceColumns, setVisibleColumns, visibleColumns]); - - const columnVisibilityProps = useMemo( - () => ({ + const columnVisibilityProps = useMemo(() => { + return { visibleColumns, setVisibleColumns, - }), - [visibleColumns, setVisibleColumns] - ); + }; + }, [visibleColumns, setVisibleColumns]); const sortingProps = useMemo( () => ({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index 97066be7fe1fe..64fff133fedac 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -80,7 +80,6 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer } if (columnId === 'rule_name' && ruleId) { - // if (ruleOnDifferentSpace) return <>{value}; return {value}; } diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx index 9e9dbf72e48ac..639ec1dd6a264 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx @@ -320,8 +320,18 @@ export const RuleEventLogListTable = ( ); const onShowAllSpacesChange = useCallback(() => { - setShowFromAllSpaces(!showFromAllSpaces); - }, [showFromAllSpaces, setShowFromAllSpaces]); + setShowFromAllSpaces((prev) => !prev); + const nextShowFromAllSpaces = !showFromAllSpaces; + + if (nextShowFromAllSpaces && !visibleColumns.includes('space_ids')) { + const ruleNameIndex = visibleColumns.findIndex((c) => c === 'rule_name'); + const newVisibleColumns = [...visibleColumns]; + newVisibleColumns.splice(ruleNameIndex + 1, 0, 'space_ids'); + setVisibleColumns(newVisibleColumns); + } else if (!nextShowFromAllSpaces && visibleColumns.includes('space_ids')) { + setVisibleColumns(visibleColumns.filter((c) => c !== 'space_ids')); + } + }, [setShowFromAllSpaces, showFromAllSpaces, visibleColumns]); const renderList = () => { if (!logs) { From 5a185a8d4f43cea6092dbeeabb82b24fe7a673d1 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Wed, 26 Oct 2022 16:57:43 -0500 Subject: [PATCH 12/20] Add test for link routing --- ...rule_event_log_list_cell_renderer.test.tsx | 66 ++++++++++++++++++- .../rule_event_log_list_cell_renderer.tsx | 24 +++++-- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx index de9cd783c1ff6..def434830bd93 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx @@ -7,7 +7,7 @@ import React from 'react'; import moment from 'moment'; -import { EuiIcon } from '@elastic/eui'; +import { EuiIcon, EuiLink } from '@elastic/eui'; import { shallow, mount } from 'enzyme'; import { RuleEventLogListCellRenderer, @@ -16,7 +16,44 @@ import { import { RuleEventLogListStatus } from './rule_event_log_list_status'; import { RuleDurationFormat } from '../../rules_list/components/rule_duration_format'; +jest.mock('react-router-dom', () => ({ + useHistory: () => ({ + location: { + pathname: '/logs', + }, + }), +})); + +jest.mock('../../../../common/lib/kibana', () => ({ + useSpacesData: () => ({ + spacesMap: new Map([ + ['space1', { id: 'space1' }], + ['space2', { id: 'space2' }], + ]), + activeSpaceId: 'space1', + }), +})); + describe('rule_event_log_list_cell_renderer', () => { + const savedLocation = window.location; + beforeAll(() => { + // @ts-ignore Mocking window.location + delete window.location; + // @ts-ignore + window.location = Object.assign( + new URL('https://localhost/app/management/insightsAndAlerting/triggersActions/logs'), + { + ancestorOrigins: '', + assign: jest.fn(), + reload: jest.fn(), + replace: jest.fn(), + } + ); + }); + afterAll(() => { + window.location = savedLocation; + }); + it('renders primitive values correctly', () => { const wrapper = mount(); @@ -67,4 +104,31 @@ describe('rule_event_log_list_cell_renderer', () => { expect(wrapper.find(RuleEventLogListStatus).text()).toEqual('newOutcome'); expect(wrapper.find(EuiIcon).props().color).toEqual('gray'); }); + + it('links to rules on the correct space', () => { + const wrapper1 = shallow( + + ); + //@ts-ignore data-href is not a native EuiLink prop + expect(wrapper1.find(EuiLink).props()['data-href']).toEqual('/rule/1'); + const wrapper2 = shallow( + + ); + //@ts-ignore data-href is not a native EuiLink prop + expect(wrapper2.find(EuiLink).props()['data-href']).toEqual( + '/s/space2/app/management/insightsAndAlerting/triggersActions/rule/1' + ); + + window.location = savedLocation; + }); }); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index 64fff133fedac..a798466bccea0 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -50,8 +50,8 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer [activeSpace, spaceIds] ); - const onClickRuleName = useCallback(() => { - if (!ruleId) return; + const ruleNamePathname = useMemo(() => { + if (!ruleId) return ''; const ruleRoute = routeToRuleDetails.replace(':ruleId', ruleId); if (ruleOnDifferentSpace) { const [linkedSpaceId] = spaceIds ?? []; @@ -60,12 +60,20 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer const newPathname = `${spacePath}${window.location.pathname .replace(/^\/s\/([^/])+/, '') .replace(historyPathname, ruleRoute)}`; - const newUrl = window.location.href.replace(window.location.pathname, newPathname); + return newPathname; + } + return ruleRoute; + }, [ruleId, ruleOnDifferentSpace, history, spaceIds]); + + const onClickRuleName = useCallback(() => { + if (!ruleId) return; + if (ruleOnDifferentSpace) { + const newUrl = window.location.href.replace(window.location.pathname, ruleNamePathname); window.open(newUrl, '_blank'); return; } - history.push(ruleRoute); - }, [ruleId, history, ruleOnDifferentSpace, spaceIds]); + history.push(ruleNamePathname); + }, [ruleNamePathname, history, ruleOnDifferentSpace]); if (typeof value === 'undefined') { return null; @@ -80,7 +88,11 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer } if (columnId === 'rule_name' && ruleId) { - return {value}; + return ( + + {value} + + ); } if (columnId === 'space_ids') { From 90d1bc8deff1140e3021a3c28c0e0e4278f715f3 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Thu, 27 Oct 2022 20:57:50 +0000 Subject: [PATCH 13/20] [CI] Auto-commit changed files from 'node scripts/eslint --no-cache --fix' --- .../components/rule_event_log_list_cell_renderer.test.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx index def434830bd93..4070df17e33e5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx @@ -114,7 +114,7 @@ describe('rule_event_log_list_cell_renderer', () => { spaceIds={['space1']} /> ); - //@ts-ignore data-href is not a native EuiLink prop + // @ts-ignore data-href is not a native EuiLink prop expect(wrapper1.find(EuiLink).props()['data-href']).toEqual('/rule/1'); const wrapper2 = shallow( { spaceIds={['space2']} /> ); - //@ts-ignore data-href is not a native EuiLink prop + // @ts-ignore data-href is not a native EuiLink prop expect(wrapper2.find(EuiLink).props()['data-href']).toEqual( '/s/space2/app/management/insightsAndAlerting/triggersActions/rule/1' ); From eeff02c9c42ac4f427ffb7ea09f6330284a64bf3 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Fri, 28 Oct 2022 12:45:00 -0500 Subject: [PATCH 14/20] Add auth and space access to action error log --- .../server/routes/get_action_error_log.ts | 11 ++- .../server/rules_client/rules_client.ts | 76 +++++++++++++++++++ .../server/es/cluster_client_adapter.ts | 62 ++++++++++++++- .../event_log/server/event_log_client.ts | 25 ++++++ x-pack/plugins/event_log/server/types.ts | 7 ++ .../lib/rule_api/load_action_error_log.ts | 6 ++ .../rule_action_error_log_flyout.tsx | 26 ++++++- .../components/rule_error_log.tsx | 6 +- .../rule_event_log_list_cell_renderer.tsx | 2 +- .../components/rule_event_log_list_table.tsx | 5 ++ 10 files changed, 218 insertions(+), 8 deletions(-) diff --git a/x-pack/plugins/alerting/server/routes/get_action_error_log.ts b/x-pack/plugins/alerting/server/routes/get_action_error_log.ts index c833b65e34bb0..7e8028cad7f16 100644 --- a/x-pack/plugins/alerting/server/routes/get_action_error_log.ts +++ b/x-pack/plugins/alerting/server/routes/get_action_error_log.ts @@ -34,15 +34,19 @@ const querySchema = schema.object({ per_page: schema.number({ defaultValue: 10, min: 1 }), page: schema.number({ defaultValue: 1, min: 1 }), sort: sortFieldsSchema, + namespace: schema.maybe(schema.string()), + with_auth: schema.maybe(schema.boolean()), }); const rewriteReq: RewriteRequestCase = ({ date_start: dateStart, date_end: dateEnd, per_page: perPage, + namespace, ...rest }) => ({ ...rest, + namespace, dateStart, dateEnd, perPage, @@ -64,8 +68,13 @@ export const getActionErrorLogRoute = ( verifyAccessAndContext(licenseState, async function (context, req, res) { const rulesClient = (await context.alerting).getRulesClient(); const { id } = req.params; + const withAuth = req.query.with_auth; + const rewrittenReq = rewriteReq({ id, ...req.query }); + const getter = ( + withAuth ? rulesClient.getActionErrorLogWithAuth : rulesClient.getActionErrorLog + ).bind(rulesClient); return res.ok({ - body: await rulesClient.getActionErrorLog(rewriteReq({ id, ...req.query })), + body: await getter(rewrittenReq), }); }) ) diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 88a7b64c62a1e..905c9d41f8ca7 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -440,6 +440,7 @@ export interface GetActionErrorLogByIdParams { page: number; perPage: number; sort: estypes.Sort; + namespace?: string; } interface ScheduleTaskOptions { @@ -1087,6 +1088,81 @@ export class RulesClient { } } + public async getActionErrorLogWithAuth({ + id, + dateStart, + dateEnd, + filter, + page, + perPage, + sort, + namespace, + }: GetActionErrorLogByIdParams): Promise { + this.logger.debug(`getActionErrorLogWithAuth(): getting action error logs for rule ${id}`); + + let authorizationTuple; + try { + authorizationTuple = await this.authorization.getFindAuthorizationFilter( + AlertingAuthorizationEntity.Alert, + { + type: AlertingAuthorizationFilterType.KQL, + fieldNames: { + ruleTypeId: 'kibana.alert.rule.rule_type_id', + consumer: 'kibana.alert.rule.consumer', + }, + } + ); + } catch (error) { + this.auditLogger?.log( + ruleAuditEvent({ + action: RuleAuditAction.GET_ACTION_ERROR_LOG, + error, + }) + ); + throw error; + } + + this.auditLogger?.log( + ruleAuditEvent({ + action: RuleAuditAction.GET_ACTION_ERROR_LOG, + savedObject: { type: 'alert', id }, + }) + ); + + const defaultFilter = + 'event.provider:actions AND ((event.action:execute AND (event.outcome:failure OR kibana.alerting.status:warning)) OR (event.action:execute-timeout))'; + + // default duration of instance summary is 60 * rule interval + const dateNow = new Date(); + const parsedDateStart = parseDate(dateStart, 'dateStart', dateNow); + const parsedDateEnd = parseDate(dateEnd, 'dateEnd', dateNow); + + const eventLogClient = await this.getEventLogClient(); + + try { + const errorResult = await eventLogClient.findEventsWithAuthFilter( + 'alert', + [id], + authorizationTuple.filter as KueryNode, + namespace, + { + start: parsedDateStart.toISOString(), + end: parsedDateEnd.toISOString(), + page, + per_page: perPage, + filter: filter ? `(${defaultFilter}) AND (${filter})` : defaultFilter, + sort: convertEsSortToEventLogSort(sort), + } + ); + return formatExecutionErrorsResult(errorResult); + } catch (err) { + this.logger.debug( + `rulesClient.getActionErrorLog(): error searching event log for rule ${id}: ${err.message}` + ); + throw err; + } + } + public async getGlobalExecutionKpiWithAuth({ dateStart, dateEnd, diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index 63d4e21e50f8d..6a95f91d9fec5 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -50,6 +50,14 @@ interface QueryOptionsEventsBySavedObjectFilter { legacyIds?: string[]; } +interface QueryOptionsEventsWithAuthFilter { + index: string; + namespace: string | undefined; + type: string; + ids: string[]; + authFilter: KueryNode; +} + export interface AggregateEventsWithAuthFilter { index: string; namespaces?: Array; @@ -58,6 +66,10 @@ export interface AggregateEventsWithAuthFilter { aggregateOptions: AggregateOptionsType; } +export type FindEventsOptionsWithAuthFilter = QueryOptionsEventsWithAuthFilter & { + findOptions: FindOptionsType; +}; + export type FindEventsOptionsBySavedObjectFilter = QueryOptionsEventsBySavedObjectFilter & { findOptions: FindOptionsType; }; @@ -389,6 +401,50 @@ export class ClusterClientAdapter { + const { index, type, ids, findOptions } = queryOptions; + const { page, per_page: perPage, sort } = findOptions; + + const esClient = await this.elasticsearchClientPromise; + + const query = getQueryBodyWithAuthFilter( + this.logger, + { ...queryOptions, namespaces: [queryOptions.namespace] }, + pick(queryOptions.findOptions, ['start', 'end', 'filter']) + ); + + const body: estypes.SearchRequest['body'] = { + size: perPage, + from: (page - 1) * perPage, + query, + ...(sort + ? { sort: sort.map((s) => ({ [s.sort_field]: { order: s.sort_order } })) as estypes.Sort } + : {}), + }; + + try { + const { + hits: { hits, total }, + } = await esClient.search({ + index, + track_total_hits: true, + body, + }); + return { + page, + per_page: perPage, + total: isNumber(total) ? total : total!.value, + data: hits.map((hit) => hit._source), + }; + } catch (err) { + throw new Error( + `querying for Event Log by for type "${type}" and ids "${ids}" failed with: ${err.message}` + ); + } + } + public async aggregateEventsBySavedObjects( queryOptions: AggregateEventsOptionsBySavedObjectFilter ): Promise { @@ -462,7 +518,11 @@ export class ClusterClientAdapter + ): Promise { + if (!authFilter) { + throw new Error('No authorization filter defined!'); + } + + const findOptions = queryOptionsSchema.validate(options ?? {}); + + return await this.esContext.esAdapter.queryEventsWithAuthFilter({ + index: this.esContext.esNames.indexPattern, + namespace: namespace + ? this.spacesService?.spaceIdToNamespace(namespace) + : await this.getNamespace(), + type, + ids, + findOptions, + authFilter, + }); + } + public async aggregateEventsBySavedObjectIds( type: string, ids: string[], diff --git a/x-pack/plugins/event_log/server/types.ts b/x-pack/plugins/event_log/server/types.ts index 91955a3a78297..07a7e7ed2f7e2 100644 --- a/x-pack/plugins/event_log/server/types.ts +++ b/x-pack/plugins/event_log/server/types.ts @@ -57,6 +57,13 @@ export interface IEventLogClient { options?: Partial, legacyIds?: string[] ): Promise; + findEventsWithAuthFilter( + type: string, + ids: string[], + authFilter: KueryNode, + namespace: string | undefined, + options?: Partial + ): Promise; aggregateEventsBySavedObjectIds( type: string, ids: string[], diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.ts index 10f2879085cd0..7bfef44335a4c 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.ts @@ -28,6 +28,8 @@ export interface LoadActionErrorLogProps { perPage?: number; page?: number; sort?: SortField[]; + namespace?: string; + withAuth?: boolean; } const SORT_MAP: Record = { @@ -60,6 +62,8 @@ export const loadActionErrorLog = ({ perPage = 10, page = 0, sort, + namespace, + withAuth = false, }: LoadActionErrorLogProps & { http: HttpSetup }) => { const renamedSort = getRenamedSort(sort); const filter = getFilter({ runId, message }); @@ -76,6 +80,8 @@ export const loadActionErrorLog = ({ // whereas data grid sorts are 0 indexed. page: page + 1, sort: renamedSort.length ? JSON.stringify(renamedSort) : undefined, + namespace, + with_auth: withAuth, }, } ); diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_action_error_log_flyout.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_action_error_log_flyout.tsx index 8c46e3574560c..9a14d995e4126 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_action_error_log_flyout.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_action_error_log_flyout.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React from 'react'; +import React, { useMemo } from 'react'; import { FormattedMessage } from '@kbn/i18n-react'; import { EuiTitle, @@ -28,17 +28,29 @@ export interface RuleActionErrorLogFlyoutProps { runLog: IExecutionLog; refreshToken?: number; onClose: () => void; + activeSpaceId?: string; } export const RuleActionErrorLogFlyout = (props: RuleActionErrorLogFlyoutProps) => { - const { runLog, refreshToken, onClose } = props; + const { runLog, refreshToken, onClose, activeSpaceId } = props; const { euiTheme } = useEuiTheme(); - const { id, rule_id: ruleId, message, num_errored_actions: totalErrors } = runLog; + const { + id, + rule_id: ruleId, + message, + num_errored_actions: totalErrors, + space_ids: spaceIds, + } = runLog; const isFlyoutPush = useIsWithinBreakpoints(['xl']); + const logFromDifferentSpace = useMemo( + () => Boolean(activeSpaceId && !spaceIds?.includes(activeSpaceId)), + [activeSpaceId, spaceIds] + ); + return ( - + diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx index 7c14b17f8d12b..e07dd0ce5f6ed 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx @@ -63,11 +63,13 @@ export type RuleErrorLogProps = { ruleId: string; runId?: string; refreshToken?: number; + spaceId?: string; + logFromDifferentSpace?: boolean; requestRefresh?: () => Promise; } & Pick; export const RuleErrorLog = (props: RuleErrorLogProps) => { - const { ruleId, runId, loadActionErrorLog, refreshToken } = props; + const { ruleId, runId, loadActionErrorLog, refreshToken, spaceId, logFromDifferentSpace } = props; const { uiSettings, notifications } = useKibana().services; @@ -138,6 +140,8 @@ export const RuleErrorLog = (props: RuleErrorLogProps) => { page: pagination.pageIndex, perPage: pagination.pageSize, sort: formattedSort, + namespace: spaceId, + withAuth: logFromDifferentSpace, }); setLogs(result.errors); setPagination({ diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index a798466bccea0..4ff25350de2fe 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -73,7 +73,7 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer return; } history.push(ruleNamePathname); - }, [ruleNamePathname, history, ruleOnDifferentSpace]); + }, [ruleNamePathname, history, ruleOnDifferentSpace, ruleId]); if (typeof value === 'undefined') { return null; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx index 639ec1dd6a264..1ea613e20055f 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_table.tsx @@ -180,6 +180,10 @@ export const RuleEventLogListTable = ( () => (showFromAllSpaces && spacesData ? accessibleSpaceIds : undefined), [showFromAllSpaces, spacesData, accessibleSpaceIds] ); + const activeSpace = useMemo( + () => spacesData?.spacesMap.get(spacesData?.activeSpaceId), + [spacesData] + ); const isInitialized = useRef(false); @@ -462,6 +466,7 @@ export const RuleEventLogListTable = ( runLog={selectedRunLog} refreshToken={refreshToken} onClose={onFlyoutClose} + activeSpaceId={activeSpace?.id} /> )} From c964fd89dfb80ffed539bff7b7431ac2e9dda696 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Fri, 28 Oct 2022 16:52:29 -0500 Subject: [PATCH 15/20] Add test for getActionErrorLogWithAuth, fix types, consts --- .../server/rules_client/rules_client.ts | 17 +++--- .../tests/get_action_error_log.test.ts | 61 +++++++++++++++++++ .../server/es/cluster_client_adapter.ts | 12 ++-- .../event_log/server/event_log_client.mock.ts | 1 + 4 files changed, 78 insertions(+), 13 deletions(-) diff --git a/x-pack/plugins/alerting/server/rules_client/rules_client.ts b/x-pack/plugins/alerting/server/rules_client/rules_client.ts index 905c9d41f8ca7..bd4f9deb36b5d 100644 --- a/x-pack/plugins/alerting/server/rules_client/rules_client.ts +++ b/x-pack/plugins/alerting/server/rules_client/rules_client.ts @@ -461,6 +461,9 @@ const MAX_RULES_NUMBER_FOR_BULK_OPERATION = 10000; const API_KEY_GENERATE_CONCURRENCY = 50; const RULE_TYPE_CHECKS_CONCURRENCY = 50; +const actionErrorLogDefaultFilter = + 'event.provider:actions AND ((event.action:execute AND (event.outcome:failure OR kibana.alerting.status:warning)) OR (event.action:execute-timeout))'; + const alertingAuthorizationFilterOpts: AlertingAuthorizationFilterOpts = { type: AlertingAuthorizationFilterType.KQL, fieldNames: { ruleTypeId: 'alert.attributes.alertTypeId', consumer: 'alert.attributes.consumer' }, @@ -1055,9 +1058,6 @@ export class RulesClient { }) ); - const defaultFilter = - 'event.provider:actions AND ((event.action:execute AND (event.outcome:failure OR kibana.alerting.status:warning)) OR (event.action:execute-timeout))'; - // default duration of instance summary is 60 * rule interval const dateNow = new Date(); const parsedDateStart = parseDate(dateStart, 'dateStart', dateNow); @@ -1074,7 +1074,9 @@ export class RulesClient { end: parsedDateEnd.toISOString(), page, per_page: perPage, - filter: filter ? `(${defaultFilter}) AND (${filter})` : defaultFilter, + filter: filter + ? `(${actionErrorLogDefaultFilter}) AND (${filter})` + : actionErrorLogDefaultFilter, sort: convertEsSortToEventLogSort(sort), }, rule.legacyId !== null ? [rule.legacyId] : undefined @@ -1129,9 +1131,6 @@ export class RulesClient { }) ); - const defaultFilter = - 'event.provider:actions AND ((event.action:execute AND (event.outcome:failure OR kibana.alerting.status:warning)) OR (event.action:execute-timeout))'; - // default duration of instance summary is 60 * rule interval const dateNow = new Date(); const parsedDateStart = parseDate(dateStart, 'dateStart', dateNow); @@ -1150,7 +1149,9 @@ export class RulesClient { end: parsedDateEnd.toISOString(), page, per_page: perPage, - filter: filter ? `(${defaultFilter}) AND (${filter})` : defaultFilter, + filter: filter + ? `(${actionErrorLogDefaultFilter}) AND (${filter})` + : actionErrorLogDefaultFilter, sort: convertEsSortToEventLogSort(sort), } ); diff --git a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts index 3a18634b4f5db..6b635abe5d7f0 100644 --- a/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts +++ b/x-pack/plugins/alerting/server/rules_client/tests/get_action_error_log.test.ts @@ -8,6 +8,7 @@ import { RulesClient, ConstructorOptions, GetActionErrorLogByIdParams } from '../rules_client'; import { savedObjectsClientMock, loggingSystemMock } from '@kbn/core/server/mocks'; import { taskManagerMock } from '@kbn/task-manager-plugin/server/mocks'; +import { fromKueryExpression } from '@kbn/es-query'; import { ruleTypeRegistryMock } from '../../rule_type_registry.mock'; import { alertingAuthorizationMock } from '../../authorization/alerting_authorization.mock'; import { encryptedSavedObjectsMock } from '@kbn/encrypted-saved-objects-plugin/server/mocks'; @@ -574,3 +575,63 @@ describe('getActionErrorLog()', () => { }); }); }); + +describe('getActionErrorLogWithAuth()', () => { + let rulesClient: RulesClient; + + beforeEach(() => { + rulesClient = new RulesClient(rulesClientParams); + }); + + test('returns the expected return values when called', async () => { + const ruleSO = getRuleSavedObject({}); + authorization.getFindAuthorizationFilter.mockResolvedValue({ + filter: fromKueryExpression('*'), + ensureRuleTypeIsAuthorized() {}, + }); + unsecuredSavedObjectsClient.get.mockResolvedValueOnce(ruleSO); + eventLogClient.findEventsWithAuthFilter.mockResolvedValueOnce(findResults); + + const result = await rulesClient.getActionErrorLogWithAuth(getActionErrorLogParams()); + expect(result).toEqual({ + totalErrors: 5, + errors: [ + { + id: '08d9b0f5-0b41-47c9-951f-a666b5788ddc', + timestamp: '2022-03-23T17:37:07.106Z', + type: 'actions', + message: + 'action execution failure: .server-log:9e67b8b0-9e2c-11ec-bd64-774ed95c43ef: s - an error occurred while running the action executor: something funky with the server log', + }, + { + id: '08d9b0f5-0b41-47c9-951f-a666b5788ddc', + timestamp: '2022-03-23T17:37:07.102Z', + type: 'actions', + message: + 'action execution failure: .server-log:9e67b8b0-9e2c-11ec-bd64-774ed95c43ef: s - an error occurred while running the action executor: something funky with the server log', + }, + { + id: '08d9b0f5-0b41-47c9-951f-a666b5788ddc', + timestamp: '2022-03-23T17:37:07.098Z', + type: 'actions', + message: + 'action execution failure: .server-log:9e67b8b0-9e2c-11ec-bd64-774ed95c43ef: s - an error occurred while running the action executor: something funky with the server log', + }, + { + id: '08d9b0f5-0b41-47c9-951f-a666b5788ddc', + timestamp: '2022-03-23T17:37:07.096Z', + type: 'actions', + message: + 'action execution failure: .server-log:9e67b8b0-9e2c-11ec-bd64-774ed95c43ef: s - an error occurred while running the action executor: something funky with the server log', + }, + { + id: '08d9b0f5-0b41-47c9-951f-a666b5788ddc', + timestamp: '2022-03-23T17:37:07.086Z', + type: 'actions', + message: + 'action execution failure: .server-log:9e67b8b0-9e2c-11ec-bd64-774ed95c43ef: s - an error occurred while running the action executor: something funky with the server log', + }, + ], + }); + }); +}); diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts index 6a95f91d9fec5..0d38895dbd800 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.ts @@ -82,6 +82,12 @@ export interface AggregateEventsBySavedObjectResult { aggregations: Record | undefined; } +type GetQueryBodyWithAuthFilterOpts = + | (FindEventsOptionsWithAuthFilter & { + namespaces: AggregateEventsWithAuthFilter['namespaces']; + }) + | AggregateEventsWithAuthFilter; + // eslint-disable-next-line @typescript-eslint/no-explicit-any type AliasAny = any; @@ -518,11 +524,7 @@ export class ClusterClientAdapter { const mock: jest.Mocked = { findEventsBySavedObjectIds: jest.fn(), + findEventsWithAuthFilter: jest.fn(), aggregateEventsBySavedObjectIds: jest.fn(), aggregateEventsWithAuthFilter: jest.fn(), }; From e192495477fdf229b07da88bb900033d78543bba Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Fri, 28 Oct 2022 17:55:16 -0500 Subject: [PATCH 16/20] Fix undefined spaceids error --- .../rule_details/components/rule_action_error_log_flyout.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_action_error_log_flyout.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_action_error_log_flyout.tsx index 9a14d995e4126..aa914e2818c03 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_action_error_log_flyout.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_action_error_log_flyout.tsx @@ -41,7 +41,7 @@ export const RuleActionErrorLogFlyout = (props: RuleActionErrorLogFlyoutProps) = rule_id: ruleId, message, num_errored_actions: totalErrors, - space_ids: spaceIds, + space_ids: spaceIds = [], } = runLog; const isFlyoutPush = useIsWithinBreakpoints(['xl']); From ce620aa64e922e38722aafd36262b2d2e452ea37 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Fri, 28 Oct 2022 18:33:27 -0500 Subject: [PATCH 17/20] Fix base path support --- .../rule_event_log_list_cell_renderer.test.tsx | 11 ++++++++++- .../components/rule_event_log_list_cell_renderer.tsx | 11 ++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx index 4070df17e33e5..08362962890e5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.test.tsx @@ -32,6 +32,15 @@ jest.mock('../../../../common/lib/kibana', () => ({ ]), activeSpaceId: 'space1', }), + useKibana: () => ({ + services: { + http: { + basePath: { + get: () => '/basePath', + }, + }, + }, + }), })); describe('rule_event_log_list_cell_renderer', () => { @@ -126,7 +135,7 @@ describe('rule_event_log_list_cell_renderer', () => { ); // @ts-ignore data-href is not a native EuiLink prop expect(wrapper2.find(EuiLink).props()['data-href']).toEqual( - '/s/space2/app/management/insightsAndAlerting/triggersActions/rule/1' + '/basePath/s/space2/app/management/insightsAndAlerting/triggersActions/rule/1' ); window.location = savedLocation; diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index 4ff25350de2fe..07b4005f5a469 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -12,7 +12,7 @@ import { RuleAlertingOutcome } from '@kbn/alerting-plugin/common'; import { useHistory } from 'react-router-dom'; import { routeToRuleDetails } from '../../../constants'; import { formatRuleAlertCount } from '../../../../common/lib/format_rule_alert_count'; -import { useSpacesData } from '../../../../common/lib/kibana'; +import { useKibana, useSpacesData } from '../../../../common/lib/kibana'; import { RuleEventLogListStatus } from './rule_event_log_list_status'; import { RuleDurationFormat } from '../../rules_list/components/rule_duration_format'; import { @@ -37,6 +37,7 @@ interface RuleEventLogListCellRendererProps { export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRendererProps) => { const { columnId, value, version, dateFormat = DEFAULT_DATE_FORMAT, ruleId, spaceIds } = props; const spacesData = useSpacesData(); + const { http } = useKibana().services; const history = useHistory(); @@ -55,10 +56,14 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer const ruleRoute = routeToRuleDetails.replace(':ruleId', ruleId); if (ruleOnDifferentSpace) { const [linkedSpaceId] = spaceIds ?? []; + const basePath = http.basePath.get(); const spacePath = linkedSpaceId !== 'default' ? `/s/${linkedSpaceId}` : ''; const historyPathname = history.location.pathname; - const newPathname = `${spacePath}${window.location.pathname - .replace(/^\/s\/([^/])+/, '') + const newPathname = `${basePath.replace( + `/s/${activeSpace!.id}`, + '' + )}${spacePath}${window.location.pathname + .replace(basePath, '') .replace(historyPathname, ruleRoute)}`; return newPathname; } From de8d6410cbc643316fe17593570945db618f2374 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 31 Oct 2022 10:51:50 -0500 Subject: [PATCH 18/20] Fix types and jest --- .../plugins/event_log/server/es/cluster_client_adapter.mock.ts | 1 + .../application/lib/rule_api/load_action_error_log.test.ts | 2 ++ .../components/rule_event_log_list_cell_renderer.tsx | 2 +- 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts b/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts index 3cb1b8d12c0b1..adf1ecf0f7881 100644 --- a/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts +++ b/x-pack/plugins/event_log/server/es/cluster_client_adapter.mock.ts @@ -24,6 +24,7 @@ const createClusterClientMock = () => { getExistingIndexAliases: jest.fn(), setIndexAliasToHidden: jest.fn(), queryEventsBySavedObjects: jest.fn(), + queryEventsWithAuthFilter: jest.fn(), aggregateEventsBySavedObjects: jest.fn(), aggregateEventsWithAuthFilter: jest.fn(), shutdown: jest.fn(), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.test.ts b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.test.ts index 56de4f5c4c890..de273fbf394e5 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.test.ts +++ b/x-pack/plugins/triggers_actions_ui/public/application/lib/rule_api/load_action_error_log.test.ts @@ -118,9 +118,11 @@ describe('loadActionErrorLog', () => { "date_end": "2022-03-23T16:17:53.482Z", "date_start": "2022-03-23T16:17:53.482Z", "filter": "(message: \\"test\\" OR error.message: \\"test\\") and kibana.alert.rule.execution.uuid: 123", + "namespace": undefined, "page": 1, "per_page": 10, "sort": "[{\\"@timestamp\\":{\\"order\\":\\"asc\\"}}]", + "with_auth": false, }, }, ] diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index 07b4005f5a469..1cf12f03c84ff 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -68,7 +68,7 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer return newPathname; } return ruleRoute; - }, [ruleId, ruleOnDifferentSpace, history, spaceIds]); + }, [ruleId, ruleOnDifferentSpace, history, activeSpace, http.basePath, spaceIds]); const onClickRuleName = useCallback(() => { if (!ruleId) return; From 64e94425d0f916aa9051a26fbbcb326f40af4add Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 31 Oct 2022 12:47:31 -0500 Subject: [PATCH 19/20] Fix types and jest --- x-pack/plugins/alerting/server/rules_client.mock.ts | 1 + .../sections/rule_details/components/rule_error_log.tsx | 1 + .../components/rule_event_log_list_cell_renderer.tsx | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/alerting/server/rules_client.mock.ts b/x-pack/plugins/alerting/server/rules_client.mock.ts index aa29e64d2f460..46a6c36bdea2a 100644 --- a/x-pack/plugins/alerting/server/rules_client.mock.ts +++ b/x-pack/plugins/alerting/server/rules_client.mock.ts @@ -34,6 +34,7 @@ const createRulesClientMock = () => { getGlobalExecutionKpiWithAuth: jest.fn(), getGlobalExecutionLogWithAuth: jest.fn(), getActionErrorLog: jest.fn(), + getActionErrorLogWithAuth: jest.fn(), getSpaceId: jest.fn(), bulkEdit: jest.fn(), bulkDeleteRules: jest.fn(), diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx index e07dd0ce5f6ed..7de8fcd2c8327 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx @@ -150,6 +150,7 @@ export const RuleErrorLog = (props: RuleErrorLogProps) => { }); setActualTotalItemCount(result.totalErrors); } catch (e) { + console.log('ERROR', e); notifications.toasts.addDanger({ title: API_FAILED_MESSAGE, text: e.body.message, diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx index 1cf12f03c84ff..bcca56ad0027e 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_event_log_list_cell_renderer.tsx @@ -68,7 +68,7 @@ export const RuleEventLogListCellRenderer = (props: RuleEventLogListCellRenderer return newPathname; } return ruleRoute; - }, [ruleId, ruleOnDifferentSpace, history, activeSpace, http.basePath, spaceIds]); + }, [ruleId, ruleOnDifferentSpace, history, activeSpace, http, spaceIds]); const onClickRuleName = useCallback(() => { if (!ruleId) return; From cc99097c5f85f4e9d199943e65ecb842513f8107 Mon Sep 17 00:00:00 2001 From: Zacqary Xeper Date: Mon, 31 Oct 2022 12:55:13 -0500 Subject: [PATCH 20/20] Remove consolelog --- .../sections/rule_details/components/rule_error_log.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx index 7de8fcd2c8327..e07dd0ce5f6ed 100644 --- a/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx +++ b/x-pack/plugins/triggers_actions_ui/public/application/sections/rule_details/components/rule_error_log.tsx @@ -150,7 +150,6 @@ export const RuleErrorLog = (props: RuleErrorLogProps) => { }); setActualTotalItemCount(result.totalErrors); } catch (e) { - console.log('ERROR', e); notifications.toasts.addDanger({ title: API_FAILED_MESSAGE, text: e.body.message,