Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: display next execution time for scheduled executions after time passes #961

Merged
merged 1 commit into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import {act, render} from '@testing-library/react';
import parser from 'cron-parser';

import NextExecution from './NextExecution';

describe('organisms', () => {
describe('SettingsScheduling', () => {
describe('NextExecution', () => {
beforeEach(() => {
jest.useFakeTimers('modern').setSystemTime(new Date('2023-11-24T10:03:33'));
});

const expression = parser.parseExpression('*/1 * * * *');

it('should display error', () => {
const result = render(<NextExecution error />);
expect(result.container.textContent).toEqual('Invalid cron format');
});

it('should display information about no schedule', () => {
const result = render(<NextExecution />);
expect(result.container.textContent).toEqual('Not scheduled');
});

it('should display time', () => {
const result = render(<NextExecution expression={expression} />);
expect(result.container.textContent).toEqual('in 27 seconds');
});

it('should show now when the time is very near', () => {
const result = render(<NextExecution expression={expression} />);
act(() => {
jest.advanceTimersByTime(26999);
});
expect(result.container.textContent).toEqual('now');
});

it('should iterate with next value after queue passed', () => {
const result = render(<NextExecution expression={expression} />);
act(() => {
jest.advanceTimersByTime(30000);
});
expect(result.container.textContent).toEqual('in 57 seconds');
});
});
});
});
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
import {useState} from 'react';
import {useInterval} from 'react-use';
import {memo} from 'react';
import {useInterval, useUpdate} from 'react-use';

import parser from 'cron-parser';
import {formatDuration, intervalToDuration} from 'date-fns';

type NextExecutionProps = {
value: string | Date;
expression?: parser.CronExpression;
error?: boolean;
};

const NextExecution: React.FC<NextExecutionProps> = props => {
const {value} = props;
const [duration, setDuration] = useState('Not scheduled');
const getDuration = (expression?: parser.CronExpression, error?: boolean) => {
if (error) {
return 'Invalid cron format';
}
if (!expression) {
return 'Not scheduled';
}
const start = new Date();
expression.reset(start);
const end = expression?.next().toDate();
const duration = formatDuration(intervalToDuration({start, end}));
return duration ? `in ${duration}` : 'now';
};

useInterval(() => {
if (typeof value === 'string') {
setDuration(value);
return;
}
const NextExecution: React.FC<NextExecutionProps> = ({expression, error}) => {
const duration = getDuration(expression, error);
const update = useUpdate();

setDuration(`in ${formatDuration(intervalToDuration({start: new Date(), end: value}))}`);
}, 1000);
useInterval(update, 1000);

return <>{duration}</>;
};

export default NextExecution;
export default memo(NextExecution);
Original file line number Diff line number Diff line change
Expand Up @@ -75,17 +75,14 @@ const Schedule: React.FC<ScheduleProps> = ({label, useUpdateEntity}) => {
setWasTouched(true);
};

const [nextExecution, isValidFormat] = useMemo(() => {
const [cronExpression, isValidFormat] = useMemo(() => {
if (!cronString) {
return ['Not scheduled', true];
return [undefined, true];
}

try {
const nextDate = parser.parseExpression(cronString).next().toDate();

return [nextDate, true];
return [parser.parseExpression(cronString), true];
} catch (e) {
return ['Invalid cron format', false];
return [undefined, false];
}
}, [cronString]);

Expand Down Expand Up @@ -158,7 +155,7 @@ const Schedule: React.FC<ScheduleProps> = ({label, useUpdateEntity}) => {
<StyledColumn>
<Text className="middle regular">Next Execution</Text>
<Text style={{color: Colors.slate400}} className="middle regular">
<NextExecution value={nextExecution} />
<NextExecution expression={cronExpression} error={!isValidFormat} />
</Text>
</StyledColumn>
</StyledRow>
Expand Down
Loading