From 1676432b6197358988f59585a7c225c35cb4fb93 Mon Sep 17 00:00:00 2001
From: Alexi Doak <109488926+doakalexi@users.noreply.github.com>
Date: Thu, 20 Apr 2023 17:24:34 -0400
Subject: [PATCH] [ResponseOps][Window Maintenance] Add the upcoming events
popover to the maintenance window table (#154978)
Resolves https://github.com/elastic/kibana/issues/154815
## Summary
Adding upcoming popover
### Checklist
- [ ] Any text added follows [EUI's writing
guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses
sentence case text and includes [i18n
support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md)
- [ ] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios
---------
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Lisa Cawley
---
.../components/maintenance_windows_list.tsx | 16 ++-
.../upcoming_events_popover.test.tsx | 67 +++++++++
.../components/upcoming_events_popover.tsx | 127 ++++++++++++++++++
...rt_from_maintenance_window_to_form.test.ts | 4 +-
.../helpers/convert_to_rrule.test.ts | 4 +-
.../helpers/convert_to_rrule.ts | 3 +-
.../pages/maintenance_windows/translations.ts | 4 +
7 files changed, 219 insertions(+), 6 deletions(-)
create mode 100644 x-pack/plugins/alerting/public/pages/maintenance_windows/components/upcoming_events_popover.test.tsx
create mode 100644 x-pack/plugins/alerting/public/pages/maintenance_windows/components/upcoming_events_popover.tsx
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/maintenance_windows_list.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/maintenance_windows_list.tsx
index 33a36a2bc0dea..9d4fc521c3f66 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/maintenance_windows_list.tsx
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/maintenance_windows_list.tsx
@@ -12,12 +12,15 @@ import {
EuiBasicTableColumn,
EuiButton,
useEuiBackgroundColor,
+ EuiFlexGroup,
+ EuiFlexItem,
SearchFilterConfig,
} from '@elastic/eui';
import { css } from '@emotion/react';
import { MaintenanceWindowFindResponse, SortDirection } from '../types';
import * as i18n from '../translations';
import { useEditMaintenanceWindowsNavigation } from '../../../hooks/use_navigation';
+import { UpcomingEventsPopover } from './upcoming_events_popover';
import { StatusColor, STATUS_DISPLAY, STATUS_SORT } from '../constants';
import { MaintenanceWindowStatus } from '../../../../common';
import { StatusFilter } from './status_filter';
@@ -61,7 +64,18 @@ const columns: Array> = [
field: 'eventStartTime',
name: i18n.TABLE_START_TIME,
dataType: 'date',
- render: (startDate: string) => formatDate(startDate, 'MM/DD/YY HH:mm A'),
+ render: (startDate: string, item: MaintenanceWindowFindResponse) => {
+ return (
+
+ {formatDate(startDate, 'MM/DD/YY HH:mm A')}
+ {item.events.length > 1 ? (
+
+
+
+ ) : null}
+
+ );
+ },
sortable: true,
},
{
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/upcoming_events_popover.test.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/upcoming_events_popover.test.tsx
new file mode 100644
index 0000000000000..574bb7d1f7549
--- /dev/null
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/upcoming_events_popover.test.tsx
@@ -0,0 +1,67 @@
+/*
+ * 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 { fireEvent } from '@testing-library/react';
+import * as React from 'react';
+import { AppMockRenderer, createAppMockRenderer } from '../../../lib/test_utils';
+import { UpcomingEventsPopover } from './upcoming_events_popover';
+import { MaintenanceWindowStatus } from '../../../../common';
+
+describe('rule_actions_popover', () => {
+ let appMockRenderer: AppMockRenderer;
+
+ beforeEach(() => {
+ jest.clearAllMocks();
+ appMockRenderer = createAppMockRenderer();
+ });
+
+ it('renders the top 3 events', () => {
+ const result = appMockRenderer.render(
+
+ );
+
+ const popoverButton = result.getByTestId('upcoming-events-icon-button');
+ expect(popoverButton).toBeInTheDocument();
+ fireEvent.click(popoverButton);
+
+ expect(result.getByTestId('upcoming-events-popover-title')).toBeInTheDocument();
+ expect(result.getByTestId('upcoming-events-popover-title')).toHaveTextContent(
+ 'Repeats every Friday'
+ );
+ expect(result.getAllByTestId('upcoming-events-popover-item').length).toBe(3);
+ });
+});
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/components/upcoming_events_popover.tsx b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/upcoming_events_popover.tsx
new file mode 100644
index 0000000000000..a20907a2e1236
--- /dev/null
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/components/upcoming_events_popover.tsx
@@ -0,0 +1,127 @@
+/*
+ * 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 React, { useCallback, useMemo, useState } from 'react';
+import moment from 'moment';
+import { findIndex } from 'lodash';
+import {
+ EuiButtonIcon,
+ EuiFlexGroup,
+ EuiFlexItem,
+ EuiHorizontalRule,
+ EuiIcon,
+ EuiPopover,
+ EuiPopoverTitle,
+ EuiSpacer,
+ EuiText,
+ formatDate,
+} from '@elastic/eui';
+import * as i18n from '../translations';
+import { recurringSummary } from '../helpers/recurring_summary';
+import { getPresets } from '../helpers/get_presets';
+import { MaintenanceWindowFindResponse } from '../types';
+import { convertFromMaintenanceWindowToForm } from '../helpers/convert_from_maintenance_window_to_form';
+
+interface UpcomingEventsPopoverProps {
+ maintenanceWindowFindResponse: MaintenanceWindowFindResponse;
+}
+
+export const UpcomingEventsPopover: React.FC = React.memo(
+ ({ maintenanceWindowFindResponse }) => {
+ const [isPopoverOpen, setIsPopoverOpen] = useState(false);
+
+ const onButtonClick = useCallback(() => {
+ setIsPopoverOpen((open) => !open);
+ }, []);
+ const closePopover = useCallback(() => {
+ setIsPopoverOpen(false);
+ }, []);
+
+ const { startDate, recurringSchedule, topEvents, presets } = useMemo(() => {
+ const maintenanceWindow = convertFromMaintenanceWindowToForm(maintenanceWindowFindResponse);
+ const date = moment(maintenanceWindow.startDate);
+ const currentEventIndex = findIndex(
+ maintenanceWindowFindResponse.events,
+ (event) =>
+ event.gte === maintenanceWindowFindResponse.eventStartTime &&
+ event.lte === maintenanceWindowFindResponse.eventEndTime
+ );
+ return {
+ startDate: date,
+ recurringSchedule: maintenanceWindow.recurringSchedule,
+ topEvents: maintenanceWindowFindResponse.events.slice(
+ currentEventIndex + 1,
+ currentEventIndex + 4
+ ),
+ presets: getPresets(date),
+ };
+ }, [maintenanceWindowFindResponse]);
+
+ return (
+
+ }
+ isOpen={isPopoverOpen}
+ closePopover={closePopover}
+ anchorPosition="downCenter"
+ >
+
+ {i18n.CREATE_FORM_RECURRING_SUMMARY_PREFIX(
+ recurringSummary(startDate, recurringSchedule, presets)
+ )}
+
+
+
+
+ {i18n.UPCOMING}
+
+
+
+ {topEvents.map((event, index) => (
+
+
+
+
+
+
+
+ {formatDate(event.gte, 'MM/DD/YY HH:mm A')}
+
+
+
+ {index < topEvents.length - 1 ? (
+
+ ) : null}
+
+ ))}
+
+
+ );
+ }
+);
+UpcomingEventsPopover.displayName = 'UpcomingEventsPopover';
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_from_maintenance_window_to_form.test.ts b/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_from_maintenance_window_to_form.test.ts
index fd2627d2478f1..c892f7db66729 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_from_maintenance_window_to_form.test.ts
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_from_maintenance_window_to_form.test.ts
@@ -194,7 +194,7 @@ describe('convertFromMaintenanceWindowToForm', () => {
tzid: 'UTC',
freq: RRuleFrequency.YEARLY,
interval: 1,
- bymonth: [2],
+ bymonth: [3],
bymonthday: [22],
},
});
@@ -307,7 +307,7 @@ describe('convertFromMaintenanceWindowToForm', () => {
tzid: 'UTC',
freq: RRuleFrequency.YEARLY,
interval: 3,
- bymonth: [2],
+ bymonth: [3],
bymonthday: [22],
},
});
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_to_rrule.test.ts b/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_to_rrule.test.ts
index 737bb47f4aa33..7eaecba5169b8 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_to_rrule.test.ts
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_to_rrule.test.ts
@@ -121,7 +121,7 @@ describe('convertToRRule', () => {
tzid: 'UTC',
freq: RRuleFrequency.YEARLY,
interval: 1,
- bymonth: [2],
+ bymonth: [3],
bymonthday: [22],
});
});
@@ -209,7 +209,7 @@ describe('convertToRRule', () => {
tzid: 'UTC',
freq: RRuleFrequency.YEARLY,
interval: 3,
- bymonth: [2],
+ bymonth: [3],
bymonthday: [22],
});
});
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_to_rrule.ts b/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_to_rrule.ts
index b284e50579deb..90706165c717b 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_to_rrule.ts
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/helpers/convert_to_rrule.ts
@@ -68,7 +68,8 @@ export const convertToRRule = (
}
if (frequency === Frequency.YEARLY) {
- rRule.bymonth = [startDate.month()];
+ // rRule expects 1 based indexing for months
+ rRule.bymonth = [startDate.month() + 1];
rRule.bymonthday = [startDate.date()];
}
diff --git a/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts b/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts
index 1b3317d9182b2..30b83963cc5b7 100644
--- a/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts
+++ b/x-pack/plugins/alerting/public/pages/maintenance_windows/translations.ts
@@ -468,3 +468,7 @@ export const EXPERIMENTAL_DESCRIPTION = i18n.translate(
'This functionality is in technical preview and may be changed or removed completely in a future release. Elastic will take a best effort approach to fix any issues, but features in technical preview are not subject to the support SLA of official GA features.',
}
);
+
+export const UPCOMING = i18n.translate('xpack.alerting.maintenanceWindows.upcoming', {
+ defaultMessage: 'Upcoming',
+});