[8.8] [ResponseOps][Maintenance Windows] Show dates in the selected timezone on the edit form (#158020) (#158075)

# Backport

This will backport the following commits from `main` to `8.8`:
- [[ResponseOps][Maintenance Windows] Show dates in the selected
timezone on the edit form
(#158020)](https://github.com/elastic/kibana/pull/158020)

<!--- Backport version: 8.9.7 -->

### Questions ?
Please refer to the [Backport tool
documentation](https://github.com/sqren/backport)

<!--BACKPORT [{"author":{"name":"Alexi
Doak","email":"109488926+doakalexi@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-05-18T12:10:38Z","message":"[ResponseOps][Maintenance
Windows] Show dates in the selected timezone on the edit form
(#158020)\n\nResolves
https://github.com/elastic/kibana/issues/158013\r\n\r\n##
Summary\r\n\r\nWhen a specific timezone has been set for a schedule, we
will convert\r\nthe time to local time when showing it in a list, table
or overview.\r\nUpdated the edit/create form so that when someone
chooses to edit that\r\nschedule, we will then default to and show the
specific timezone that\r\nwas selected when it was
created.\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n\r\n### To
verify\r\nScenario 1: \r\n\r\n1. Make sure your kibana timezone setting
is set to `'Browser'`\r\n2. Create a maintenance window and set the
timezone to\r\n`America/Los_Angeles` or any timezone that is not your
own\r\n3. Verify that the times match the timezone set and save
<img\r\nwidth=\"1002\" alt=\"Screen Shot 2023-05-17 at 2 47 12
PM\"\r\nsrc=\"4ea15e09-3482-42a5-aa06-2dee7dd8c189\">\r\n4.
Verify on the table that the times match your current timezone
<img\r\nwidth=\"829\" alt=\"Screen Shot 2023-05-17 at 2 51 31
PM\"\r\nsrc=\"29e6f52b-8c40-4133-92fe-0674400a7368\">\r\n5.
Edit and verify that the times match the timezone you set when the
mw\r\nwas created <img width=\"991\" alt=\"Screen Shot 2023-05-17 at 2
52 29
PM\"\r\nsrc=\"9920d569-0e7d-484a-8f08-d5f38a94616d\">\r\n\r\nScenario
2: \r\n\r\n1. Make sure your kibana timezone setting is set to timezone.
I used\r\n`America/Denver`\r\n2. Create a maintenance window and verify
that the times reflect the\r\ntimezone set in adv settings <img
width=\"1000\" alt=\"Screen Shot\r\n2023-05-17 at 2 55 26
PM\"\r\nsrc=\"31f3164e-bb48-4ebe-98db-9bb24254fcd5\">\r\n3.
Verify on the table that the times match adv settings\r\n4. Edit and
verify that the times and the timezone match adv settings\r\n<img
width=\"1001\" alt=\"Screen Shot 2023-05-17 at 2 56 00
PM\"\r\nsrc=\"350ad4bb-9dbb-4265-bd7a-cf6a0cace7f7\">","sha":"212e4df02d91d95f2ab574216fcedbe2c4a09552","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["bug","release_note:skip","Team:ResponseOps","v8.8.0","v8.9.0"],"number":158020,"url":"https://github.com/elastic/kibana/pull/158020","mergeCommit":{"message":"[ResponseOps][Maintenance
Windows] Show dates in the selected timezone on the edit form
(#158020)\n\nResolves
https://github.com/elastic/kibana/issues/158013\r\n\r\n##
Summary\r\n\r\nWhen a specific timezone has been set for a schedule, we
will convert\r\nthe time to local time when showing it in a list, table
or overview.\r\nUpdated the edit/create form so that when someone
chooses to edit that\r\nschedule, we will then default to and show the
specific timezone that\r\nwas selected when it was
created.\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n\r\n### To
verify\r\nScenario 1: \r\n\r\n1. Make sure your kibana timezone setting
is set to `'Browser'`\r\n2. Create a maintenance window and set the
timezone to\r\n`America/Los_Angeles` or any timezone that is not your
own\r\n3. Verify that the times match the timezone set and save
<img\r\nwidth=\"1002\" alt=\"Screen Shot 2023-05-17 at 2 47 12
PM\"\r\nsrc=\"4ea15e09-3482-42a5-aa06-2dee7dd8c189\">\r\n4.
Verify on the table that the times match your current timezone
<img\r\nwidth=\"829\" alt=\"Screen Shot 2023-05-17 at 2 51 31
PM\"\r\nsrc=\"29e6f52b-8c40-4133-92fe-0674400a7368\">\r\n5.
Edit and verify that the times match the timezone you set when the
mw\r\nwas created <img width=\"991\" alt=\"Screen Shot 2023-05-17 at 2
52 29
PM\"\r\nsrc=\"9920d569-0e7d-484a-8f08-d5f38a94616d\">\r\n\r\nScenario
2: \r\n\r\n1. Make sure your kibana timezone setting is set to timezone.
I used\r\n`America/Denver`\r\n2. Create a maintenance window and verify
that the times reflect the\r\ntimezone set in adv settings <img
width=\"1000\" alt=\"Screen Shot\r\n2023-05-17 at 2 55 26
PM\"\r\nsrc=\"31f3164e-bb48-4ebe-98db-9bb24254fcd5\">\r\n3.
Verify on the table that the times match adv settings\r\n4. Edit and
verify that the times and the timezone match adv settings\r\n<img
width=\"1001\" alt=\"Screen Shot 2023-05-17 at 2 56 00
PM\"\r\nsrc=\"350ad4bb-9dbb-4265-bd7a-cf6a0cace7f7\">","sha":"212e4df02d91d95f2ab574216fcedbe2c4a09552"}},"sourceBranch":"main","suggestedTargetBranches":["8.8"],"targetPullRequestStates":[{"branch":"8.8","label":"v8.8.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/158020","number":158020,"mergeCommit":{"message":"[ResponseOps][Maintenance
Windows] Show dates in the selected timezone on the edit form
(#158020)\n\nResolves
https://github.com/elastic/kibana/issues/158013\r\n\r\n##
Summary\r\n\r\nWhen a specific timezone has been set for a schedule, we
will convert\r\nthe time to local time when showing it in a list, table
or overview.\r\nUpdated the edit/create form so that when someone
chooses to edit that\r\nschedule, we will then default to and show the
specific timezone that\r\nwas selected when it was
created.\r\n\r\n\r\n### Checklist\r\n\r\n- [x] [Unit or
functional\r\ntests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)\r\nwere
updated or added to match the most common scenarios\r\n\r\n\r\n### To
verify\r\nScenario 1: \r\n\r\n1. Make sure your kibana timezone setting
is set to `'Browser'`\r\n2. Create a maintenance window and set the
timezone to\r\n`America/Los_Angeles` or any timezone that is not your
own\r\n3. Verify that the times match the timezone set and save
<img\r\nwidth=\"1002\" alt=\"Screen Shot 2023-05-17 at 2 47 12
PM\"\r\nsrc=\"4ea15e09-3482-42a5-aa06-2dee7dd8c189\">\r\n4.
Verify on the table that the times match your current timezone
<img\r\nwidth=\"829\" alt=\"Screen Shot 2023-05-17 at 2 51 31
PM\"\r\nsrc=\"29e6f52b-8c40-4133-92fe-0674400a7368\">\r\n5.
Edit and verify that the times match the timezone you set when the
mw\r\nwas created <img width=\"991\" alt=\"Screen Shot 2023-05-17 at 2
52 29
PM\"\r\nsrc=\"9920d569-0e7d-484a-8f08-d5f38a94616d\">\r\n\r\nScenario
2: \r\n\r\n1. Make sure your kibana timezone setting is set to timezone.
I used\r\n`America/Denver`\r\n2. Create a maintenance window and verify
that the times reflect the\r\ntimezone set in adv settings <img
width=\"1000\" alt=\"Screen Shot\r\n2023-05-17 at 2 55 26
PM\"\r\nsrc=\"31f3164e-bb48-4ebe-98db-9bb24254fcd5\">\r\n3.
Verify on the table that the times match adv settings\r\n4. Edit and
verify that the times and the timezone match adv settings\r\n<img
width=\"1001\" alt=\"Screen Shot 2023-05-17 at 2 56 00
PM\"\r\nsrc=\"350ad4bb-9dbb-4265-bd7a-cf6a0cace7f7\">","sha":"212e4df02d91d95f2ab574216fcedbe2c4a09552"}}]}]
BACKPORT-->

Co-authored-by: Alexi Doak <109488926+doakalexi@users.noreply.github.com>
This commit is contained in:
Kibana Machine 2023-05-18 10:14:26 -04:00 committed by GitHub
parent d6f6c0ce54
commit e0cc912c80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 75 additions and 17 deletions

View file

@ -94,8 +94,8 @@ describe('CreateMaintenanceWindowForm', () => {
const timezoneInput = within(result.getByTestId('timezone-field')).getByTestId('input');
expect(titleInput).toHaveValue('test');
expect(dateInputs[0]).toHaveValue('03/24/2023 12:00 AM');
expect(dateInputs[1]).toHaveValue('03/26/2023 12:00 AM');
expect(dateInputs[0]).toHaveValue('03/23/2023 09:00 PM');
expect(dateInputs[1]).toHaveValue('03/25/2023 09:00 PM');
expect(recurringInput).toBeChecked();
expect(timezoneInput).toHaveTextContent('America/Los_Angeles');
});

View file

@ -108,9 +108,9 @@ export const CreateMaintenanceWindowForm = React.memo<CreateMaintenanceWindowFor
onSubmit: submitMaintenanceWindow,
});
const [{ recurring }] = useFormData<FormProps>({
const [{ recurring, timezone }] = useFormData<FormProps>({
form,
watch: ['recurring'],
watch: ['recurring', 'timezone'],
});
const isRecurring = recurring || false;
const showTimezone = isBrowser || initialValue?.timezone !== undefined;
@ -181,7 +181,13 @@ export const CreateMaintenanceWindowForm = React.memo<CreateMaintenanceWindowFor
},
}}
>
{(fields) => <DatePickerRangeField fields={fields} data-test-subj="date-field" />}
{(fields) => (
<DatePickerRangeField
fields={fields}
timezone={timezone ?? [defaultTimezone]}
data-test-subj="date-field"
/>
)}
</UseMultiFields>
</EuiFlexItem>
{showTimezone ? (

View file

@ -28,7 +28,7 @@ export const DatePickerField: React.FC<DatePickerFieldProps> = React.memo(
const { setFieldValue } = useFormContext();
const [form] = useFormData({ watch: [field.path] });
const selected = getSelected(form, field.path);
const { selected, utcOffset } = getSelected(form, field.path);
const onChange = useCallback(
(currentDate: Moment | null) => {
@ -45,6 +45,7 @@ export const DatePickerField: React.FC<DatePickerFieldProps> = React.memo(
selected={selected}
onChange={onChange}
minDate={today}
utcOffset={utcOffset}
fullWidth
/>
</EuiFormRow>

View file

@ -18,19 +18,28 @@ import { getSelectedForDatePicker as getSelected } from '../../helpers/get_selec
interface DatePickerRangeFieldProps {
fields: { startDate: FieldHook<string, string>; endDate: FieldHook<string, string> };
timezone?: string[];
showTimeSelect?: boolean;
'data-test-subj'?: string;
}
export const DatePickerRangeField: React.FC<DatePickerRangeFieldProps> = React.memo(
({ fields, showTimeSelect = true, ...rest }) => {
({ fields, timezone, showTimeSelect = true, ...rest }) => {
const [today] = useState<Moment>(moment());
const { setFieldValue } = useFormContext();
const [form] = useFormData({ watch: [fields.startDate.path, fields.endDate.path] });
const startDate = getSelected(form, fields.startDate.path);
const endDate = getSelected(form, fields.endDate.path);
const { selected: startDate, utcOffset: startOffset } = getSelected(
form,
fields.startDate.path,
timezone
);
const { selected: endDate, utcOffset: endOffset } = getSelected(
form,
fields.endDate.path,
timezone
);
const onStartDateChange = useCallback(
(currentDate: Moment | null) => {
@ -69,6 +78,7 @@ export const DatePickerRangeField: React.FC<DatePickerRangeFieldProps> = React.m
aria-label="Start date"
showTimeSelect={showTimeSelect}
minDate={today}
utcOffset={startOffset}
/>
}
endDateControl={
@ -80,6 +90,7 @@ export const DatePickerRangeField: React.FC<DatePickerRangeFieldProps> = React.m
aria-label="End date"
showTimeSelect={showTimeSelect}
minDate={today}
utcOffset={endOffset}
/>
}
fullWidth

View file

@ -15,22 +15,43 @@ describe('getSelectedForDatePicker', () => {
test('should return the current date if the form is not initialized', () => {
jest.useFakeTimers().setSystemTime(new Date('2023-03-30T00:00:00.000Z'));
expect(getSelectedForDatePicker({}, 'date').toISOString()).toEqual('2023-03-30T00:00:00.000Z');
const { selected } = getSelectedForDatePicker({}, 'date');
expect(selected.toISOString()).toEqual('2023-03-30T00:00:00.000Z');
});
test('should return the form date if it is valid', () => {
jest.useFakeTimers().setSystemTime(new Date('2023-03-30T00:00:00.000Z'));
expect(
getSelectedForDatePicker({ date: '2023-01-30T00:00:00.000Z' }, 'date').toISOString()
).toEqual('2023-01-30T00:00:00.000Z');
const { selected } = getSelectedForDatePicker({ date: '2023-01-30T00:00:00.000Z' }, 'date');
expect(selected.toISOString()).toEqual('2023-01-30T00:00:00.000Z');
});
test('should return the current date if the form date is not valid', () => {
jest.useFakeTimers().setSystemTime(new Date('2023-03-30T00:00:00.000Z'));
expect(getSelectedForDatePicker({ date: 'test' }, 'date').toISOString()).toEqual(
'2023-03-30T00:00:00.000Z'
const { selected } = getSelectedForDatePicker({ date: 'test' }, 'date');
expect(selected.toISOString()).toEqual('2023-03-30T00:00:00.000Z');
});
test('should return the current date if the form is not initialized and an offset that reflects the timezone', () => {
jest.useFakeTimers().setSystemTime(new Date('2023-03-30T00:00:00.000Z'));
const { selected, utcOffset } = getSelectedForDatePicker({}, 'date', ['America/Denver']);
expect(selected.toISOString()).toEqual('2023-03-30T00:00:00.000Z');
expect(selected.toString()).toEqual('Wed Mar 29 2023 18:00:00 GMT-0600');
expect(utcOffset).toEqual(-360);
});
test('should return the form date if it is valid and an offset that reflects the timezone', () => {
jest.useFakeTimers().setSystemTime(new Date('2023-03-30T00:00:00.000Z'));
const { selected, utcOffset } = getSelectedForDatePicker(
{ date: '2023-05-01T00:00:00.000Z' },
'date',
['America/Denver']
);
expect(selected.toISOString()).toEqual('2023-05-01T00:00:00.000Z');
expect(selected.toString()).toEqual('Sun Apr 30 2023 18:00:00 GMT-0600');
expect(utcOffset).toEqual(-360);
});
});

View file

@ -7,9 +7,15 @@
import { get } from 'lodash';
import moment, { Moment } from 'moment';
import 'moment-timezone';
import { FormData } from '@kbn/es-ui-shared-plugin/static/forms/hook_form_lib';
export function getSelectedForDatePicker(form: FormData, path: string): Moment {
export function getSelectedForDatePicker(
form: FormData,
path: string,
timezone?: string[]
): { selected: Moment; utcOffset: number } {
// parse from a string date to moment() if there is an intitial value
// otherwise just get the current date
const initialValue = get(form, path);
@ -17,5 +23,18 @@ export function getSelectedForDatePicker(form: FormData, path: string): Moment {
if (initialValue && moment(initialValue).isValid()) {
selected = moment(initialValue);
}
return selected;
const utcOffset =
timezone && timezone.length > 0
? moment()
.tz(timezone[0])
.year(selected.year())
.month(selected.month())
.date(selected.date())
.hour(selected.hour())
.minute(selected.minute())
.second(selected.second())
.millisecond(selected.millisecond())
.utcOffset()
: selected.utcOffset();
return { selected: selected.clone().utcOffset(utcOffset), utcOffset };
}