fix: let user choice 'standard' vs 'aws'

Let the user choose between cron format (since help is different)
This commit is contained in:
ShareVB 2024-09-22 12:20:44 +02:00
parent 8754d626e1
commit fa01008dc8
4 changed files with 57 additions and 22 deletions

View file

@ -4,6 +4,7 @@ import { getCronType, getLastExecutionTimes, isCronValid } from './crontab-gener
describe('crontab-generator', () => {
describe('isCronValid', () => {
it('should return true for all valid formats', () => {
// standard format
expect(isCronValid('0 0 * * 1-5')).toBe(true);
expect(isCronValid('23 0-20/2 * * *')).toBe(true);
@ -11,6 +12,24 @@ describe('crontab-generator', () => {
expect(isCronValid('0 11-22 ? * MON-FRI *')).toBe(true);
expect(isCronValid('0 0 ? * 1 *')).toBe(true);
});
it('should check standard format', () => {
// standard format
expect(isCronValid('0 0 * * 1-5', 'standard')).toBe(true);
expect(isCronValid('23 0-20/2 * * *', 'standard')).toBe(true);
// AWS format
expect(isCronValid('0 11-22 ? * MON-FRI *', 'standard')).toBe(false);
expect(isCronValid('0 0 ? * 1 *', 'standard')).toBe(false);
});
it('should check aws format', () => {
// standard format
expect(isCronValid('0 0 * * 1-5', 'aws')).toBe(false);
expect(isCronValid('23 0-20/2 * * *', 'aws')).toBe(false);
// AWS format
expect(isCronValid('0 11-22 ? * MON-FRI *', 'aws')).toBe(true);
expect(isCronValid('0 0 ? * 1 *', 'aws')).toBe(true);
});
it('should return false for all invalid formats', () => {
expect(isCronValid('aert')).toBe(false);
expect(isCronValid('40 *')).toBe(false);

View file

@ -1,6 +1,8 @@
import { parseExpression } from 'cron-parser';
import EventCronParser from 'event-cron-parser';
export type CronType = 'standard' | 'aws';
export function getLastExecutionTimes(cronExpression: string, tz: string | undefined = undefined, count: number = 5) {
if (getCronType(cronExpression) === 'standard') {
const interval = parseExpression(cronExpression, { tz });
@ -22,18 +24,19 @@ export function getLastExecutionTimes(cronExpression: string, tz: string | undef
return [];
}
export function isCronValid(v: string) {
return !!getCronType(v);
export function isCronValid(cronExpression: string, cronType: CronType | 'any' = 'any') {
const expressionCronType = getCronType(cronExpression);
return cronType === 'any' ? !!expressionCronType : expressionCronType === cronType;
}
export function getCronType(v: string) {
export function getCronType(cronExpression: string) {
try {
parseExpression(v);
parseExpression(cronExpression);
return 'standard';
}
catch (_) {
try {
const parsed = new EventCronParser(v);
const parsed = new EventCronParser(cronExpression);
parsed.validate();
return 'aws';
}

View file

@ -2,7 +2,7 @@
import cronstrue from 'cronstrue';
import ctz from 'countries-and-timezones';
import getTimezoneOffset from 'get-timezone-offset';
import { getCronType, getLastExecutionTimes, isCronValid } from './crontab-generator.service';
import { type CronType, getLastExecutionTimes, isCronValid } from './crontab-generator.service';
import { useStyleStore } from '@/stores/style.store';
import { useQueryParamOrStorage } from '@/composable/queryParams';
@ -20,10 +20,13 @@ const cronstrueConfig = reactive({
// getTimezoneOffset(tz.name, now) / 60
const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const allTimezones = Object.values(ctz.getAllTimezones()).map(tz => ({
value: tz.name,
label: `${tz.name === browserTimezone ? 'Browser TZ - ' : ''}${tz.name} (${tz.utcOffset === tz.dstOffset ? tz.utcOffsetStr : `${tz.utcOffsetStr}/${tz.dstOffsetStr}`})`,
}));
const allTimezones = Object.values(ctz.getAllTimezones()).map((tz) => {
const timezoneUTCDSTOffset = tz.utcOffset === tz.dstOffset ? tz.utcOffsetStr : `${tz.utcOffsetStr}/${tz.dstOffsetStr}`;
return {
value: tz.name,
label: `${tz.name === browserTimezone ? 'Browser TZ - ' : ''}${tz.name} (${timezoneUTCDSTOffset})`,
};
});
const currentTimezone = useQueryParamOrStorage({ name: 'tz', storageName: 'crongen:tz', defaultValue: browserTimezone });
watchEffect(() => {
cronstrueConfig.tzOffset = -getTimezoneOffset(currentTimezone.value, new Date()) / 60;
@ -136,19 +139,24 @@ const awsHelpers = [
},
];
const cronType = computed({
get() {
return getCronType(cron.value);
},
set(newCronType) {
const defaultAWSCronExpression = '0 0 ? * 1 *';
const defaultStandardCronExpression = '40 * * * *';
const cronType = ref<CronType>('standard');
watch(cronType,
(newCronType) => {
if (newCronType === 'aws') {
cron.value = '0 0 ? * 1 *';
if (!cron.value || cron.value === defaultStandardCronExpression) {
cron.value = defaultAWSCronExpression;
}
}
else {
cron.value = '40 * * * *';
else if (newCronType === 'standard') {
if (!cron.value || cron.value === defaultAWSCronExpression) {
cron.value = defaultStandardCronExpression;
}
}
},
});
);
const getHelpers = computed(() => {
if (cronType.value === 'aws') {
return awsHelpers;
@ -165,7 +173,7 @@ const cronString = computed(() => {
const cronValidationRules = [
{
validator: (value: string) => isCronValid(value),
validator: (value: string) => isCronValid(value, cronType.value),
message: 'This cron is invalid',
},
];
@ -245,7 +253,7 @@ const executionTimesString = computed(() => {
</c-card>
<c-card>
<pre v-if="cronType === 'standard'">
-- Standard CRON Syntax --
-- Standard CRON Syntax --
[optional] seconds (0 - 59)
| minute (0 - 59)
| | hour (0 - 23)
@ -256,7 +264,7 @@ const executionTimesString = computed(() => {
* * * * * * command</pre>
<pre v-if="cronType === 'aws'">
-- AWS CRON Syntax --
-- AWS CRON Syntax --
minute (0 - 59)
| hour (0 - 23)
| | day of month (1 - 31) OR ? OR L OR W