From c665348884d0f87cca531032a9d63b251983523c Mon Sep 17 00:00:00 2001 From: MariaAga Date: Tue, 3 Dec 2024 12:24:43 +0000 Subject: [PATCH] Fixes #38059 - job wizard limit starts at to future only --- webpack/JobWizard/JobWizard.js | 46 +++++++++++++------ webpack/JobWizard/StartsBeforeErrorAlert.js | 15 ++++++ .../__tests__/AdvancedFields.test.js | 2 +- .../steps/Schedule/ScheduleRecurring.js | 8 ++-- .../JobWizard/steps/Schedule/ScheduleType.js | 2 +- .../steps/Schedule/__tests__/Schedule.test.js | 2 +- .../JobWizard/steps/form/DateTimePicker.js | 13 ++++++ webpack/JobWizard/steps/form/Formatter.js | 1 + 8 files changed, 70 insertions(+), 19 deletions(-) diff --git a/webpack/JobWizard/JobWizard.js b/webpack/JobWizard/JobWizard.js index 9f329ecd3..42ea09445 100644 --- a/webpack/JobWizard/JobWizard.js +++ b/webpack/JobWizard/JobWizard.js @@ -36,7 +36,10 @@ import { useValidation } from './validation'; import { useAutoFill } from './autofill'; import { submit } from './submit'; import { generateDefaultDescription } from './JobWizardHelpers'; -import { StartsBeforeErrorAlert } from './StartsBeforeErrorAlert'; +import { + StartsBeforeErrorAlert, + StartsAtErrorAlert, +} from './StartsBeforeErrorAlert'; import { Footer } from './Footer'; import './JobWizard.scss'; @@ -203,22 +206,37 @@ export const JobWizard = ({ rerunData }) => { }, [rerunData, jobTemplateID, dispatch]); const [isStartsBeforeError, setIsStartsBeforeError] = useState(false); + const [isStartsAtError, setIsStartsAtError] = useState(false); useEffect(() => { - const updateStartsBeforeError = () => { - setIsStartsBeforeError( - scheduleValue.scheduleType === SCHEDULE_TYPES.FUTURE && - new Date().getTime() >= new Date(scheduleValue.startsBefore).getTime() - ); + const updateStartsError = () => { + if (scheduleValue.scheduleType === SCHEDULE_TYPES.FUTURE) { + setIsStartsAtError( + !!scheduleValue?.startsAt?.length && + new Date().getTime() >= new Date(scheduleValue.startsAt).getTime() + ); + setIsStartsBeforeError( + !!scheduleValue?.startsBefore?.length && + new Date().getTime() >= + new Date(scheduleValue.startsBefore).getTime() + ); + } else if (scheduleValue.scheduleType === SCHEDULE_TYPES.RECURRING) { + setIsStartsAtError( + !!scheduleValue?.startsAt?.length && + new Date().getTime() >= new Date(scheduleValue.startsAt).getTime() + ); + setIsStartsBeforeError(false); + } else { + setIsStartsAtError(false); + setIsStartsBeforeError(false); + } }; - let interval; - if (scheduleValue.scheduleType === SCHEDULE_TYPES.FUTURE) { - updateStartsBeforeError(); - interval = setInterval(updateStartsBeforeError, 5000); - } + updateStartsError(); + const interval = setInterval(updateStartsError, 5000); + return () => { interval && clearInterval(interval); }; - }, [scheduleValue.scheduleType, scheduleValue.startsBefore]); + }, [scheduleValue]); const [valid, setValid] = useValidation({ advancedValues, @@ -432,7 +450,8 @@ export const JobWizard = ({ rerunData }) => { valid.advanced && valid.schedule && !isSubmitting && - !isStartsBeforeError, + !isStartsBeforeError && + !isStartsAtError, }, ]; const location = useForemanLocation(); @@ -456,6 +475,7 @@ export const JobWizard = ({ rerunData }) => { return ( <> {isStartsBeforeError && } + {isStartsAtError && } history.goBack()} navAriaLabel="Run Job steps" diff --git a/webpack/JobWizard/StartsBeforeErrorAlert.js b/webpack/JobWizard/StartsBeforeErrorAlert.js index 117417553..1efbd8e7a 100644 --- a/webpack/JobWizard/StartsBeforeErrorAlert.js +++ b/webpack/JobWizard/StartsBeforeErrorAlert.js @@ -16,3 +16,18 @@ export const StartsBeforeErrorAlert = () => ( ); + +export const StartsAtErrorAlert = () => ( + <> + + {__( + 'Please go back to "Schedule" - "Future execution" or "Recurring execution" step to fix the error' + )} + + + +); diff --git a/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js b/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js index 850b6e617..3bcbd4338 100644 --- a/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js +++ b/webpack/JobWizard/steps/AdvancedFields/__tests__/AdvancedFields.test.js @@ -399,7 +399,7 @@ describe('AdvancedFields', () => { target: { value: 'some search' }, }); - jest.runAllTimers(); + jest.advanceTimersByTime(10000); }); expect(newStore.getActions()).toMatchSnapshot('resource search'); }); diff --git a/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js b/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js index 0b88ecba3..db1cf982a 100644 --- a/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js +++ b/webpack/JobWizard/steps/Schedule/ScheduleRecurring.js @@ -51,7 +51,7 @@ export const ScheduleRecurring = ({ if (isNeverEnds) setValidEnd(true); else if (!ends) setValidEnd(true); else if ( - !startsAt.length && + !startsAt?.length && new Date().getTime() <= new Date(ends).getTime() ) setValidEnd(true); @@ -63,7 +63,7 @@ export const ScheduleRecurring = ({ if (!validEnd || !repeatValid) { wrappedSetValid(false); - } else if (isFuture && startsAt.length) { + } else if (isFuture && startsAt?.length) { wrappedSetValid(true); } else if (!isFuture) { wrappedSetValid(true); @@ -111,7 +111,9 @@ export const ScheduleRecurring = ({ onChange={() => setScheduleValue(current => ({ ...current, - startsAt: new Date().toISOString(), + startsAt: new Date( + new Date().getTime() + 60000 + ).toISOString(), // 1 minute in the future isFuture: true, })) } diff --git a/webpack/JobWizard/steps/Schedule/ScheduleType.js b/webpack/JobWizard/steps/Schedule/ScheduleType.js index 1fdc55966..77862c1f4 100644 --- a/webpack/JobWizard/steps/Schedule/ScheduleType.js +++ b/webpack/JobWizard/steps/Schedule/ScheduleType.js @@ -49,7 +49,7 @@ export const ScheduleType = ({ onChange={() => { setScheduleValue(current => ({ ...current, - startsAt: new Date().toISOString(), + startsAt: new Date(new Date().getTime() + 60000).toISOString(), // 1 minute in the future scheduleType: SCHEDULE_TYPES.FUTURE, repeatType: repeatTypes.noRepeat, })); diff --git a/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js b/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js index 96c50976c..d25247093 100644 --- a/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js +++ b/webpack/JobWizard/steps/Schedule/__tests__/Schedule.test.js @@ -329,7 +329,7 @@ describe('Schedule', () => { fireEvent.click( screen.getByRole('button', { name: 'Recurring execution' }) ); - jest.runAllTimers(); + jest.advanceTimersByTime(1000); }); expect(screen.queryAllByText('Recurring execution')).toHaveLength(3); diff --git a/webpack/JobWizard/steps/form/DateTimePicker.js b/webpack/JobWizard/steps/form/DateTimePicker.js index b4dc314e4..bbe362f95 100644 --- a/webpack/JobWizard/steps/form/DateTimePicker.js +++ b/webpack/JobWizard/steps/form/DateTimePicker.js @@ -22,6 +22,7 @@ export const DateTimePicker = ({ ariaLabel, allowEmpty, includeSeconds, + isFutureOnly, }) => { const [validated, setValidated] = useState(); const dateFormat = date => @@ -87,6 +88,15 @@ export const DateTimePicker = ({ setValidated(ValidatedOptions.error); } }; + const validateFuture = date => { + if ( + isFutureOnly && + date.setHours(1, 0, 0, 0) < new Date().setHours(0, 0, 0, 0) + ) { + return __('Date must be in the future'); + } + return ''; + }; return ( <> { isRequired={required} >