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

5
components.d.ts vendored
View file

@ -135,13 +135,18 @@ declare module '@vue/runtime-core' {
NConfigProvider: typeof import('naive-ui')['NConfigProvider'] NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDivider: typeof import('naive-ui')['NDivider'] NDivider: typeof import('naive-ui')['NDivider']
NEllipsis: typeof import('naive-ui')['NEllipsis'] NEllipsis: typeof import('naive-ui')['NEllipsis']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
NH1: typeof import('naive-ui')['NH1'] NH1: typeof import('naive-ui')['NH1']
NH3: typeof import('naive-ui')['NH3'] NH3: typeof import('naive-ui')['NH3']
NIcon: typeof import('naive-ui')['NIcon'] NIcon: typeof import('naive-ui')['NIcon']
NLayout: typeof import('naive-ui')['NLayout'] NLayout: typeof import('naive-ui')['NLayout']
NLayoutSider: typeof import('naive-ui')['NLayoutSider'] NLayoutSider: typeof import('naive-ui')['NLayoutSider']
NMenu: typeof import('naive-ui')['NMenu'] NMenu: typeof import('naive-ui')['NMenu']
NRadio: typeof import('naive-ui')['NRadio']
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NSpace: typeof import('naive-ui')['NSpace'] NSpace: typeof import('naive-ui')['NSpace']
NSwitch: typeof import('naive-ui')['NSwitch']
NTable: typeof import('naive-ui')['NTable'] NTable: typeof import('naive-ui')['NTable']
NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default'] NumeronymGenerator: typeof import('./src/tools/numeronym-generator/numeronym-generator.vue')['default']
OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default'] OtpCodeGeneratorAndValidator: typeof import('./src/tools/otp-code-generator-and-validator/otp-code-generator-and-validator.vue')['default']

View file

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

View file

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

View file

@ -2,7 +2,7 @@
import cronstrue from 'cronstrue'; import cronstrue from 'cronstrue';
import ctz from 'countries-and-timezones'; import ctz from 'countries-and-timezones';
import getTimezoneOffset from 'get-timezone-offset'; 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 { useStyleStore } from '@/stores/style.store';
import { useQueryParamOrStorage } from '@/composable/queryParams'; import { useQueryParamOrStorage } from '@/composable/queryParams';
@ -20,10 +20,13 @@ const cronstrueConfig = reactive({
// getTimezoneOffset(tz.name, now) / 60 // getTimezoneOffset(tz.name, now) / 60
const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone; const browserTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
const allTimezones = Object.values(ctz.getAllTimezones()).map(tz => ({ const allTimezones = Object.values(ctz.getAllTimezones()).map((tz) => {
const timezoneUTCDSTOffset = tz.utcOffset === tz.dstOffset ? tz.utcOffsetStr : `${tz.utcOffsetStr}/${tz.dstOffsetStr}`;
return {
value: tz.name, value: tz.name,
label: `${tz.name === browserTimezone ? 'Browser TZ - ' : ''}${tz.name} (${tz.utcOffset === tz.dstOffset ? tz.utcOffsetStr : `${tz.utcOffsetStr}/${tz.dstOffsetStr}`})`, label: `${tz.name === browserTimezone ? 'Browser TZ - ' : ''}${tz.name} (${timezoneUTCDSTOffset})`,
})); };
});
const currentTimezone = useQueryParamOrStorage({ name: 'tz', storageName: 'crongen:tz', defaultValue: browserTimezone }); const currentTimezone = useQueryParamOrStorage({ name: 'tz', storageName: 'crongen:tz', defaultValue: browserTimezone });
watchEffect(() => { watchEffect(() => {
cronstrueConfig.tzOffset = -getTimezoneOffset(currentTimezone.value, new Date()) / 60; cronstrueConfig.tzOffset = -getTimezoneOffset(currentTimezone.value, new Date()) / 60;
@ -136,19 +139,24 @@ const awsHelpers = [
}, },
]; ];
const cronType = computed({ const defaultAWSCronExpression = '0 0 ? * 1 *';
get() { const defaultStandardCronExpression = '40 * * * *';
return getCronType(cron.value); const cronType = ref<CronType>('standard');
}, watch(cronType,
set(newCronType) { (newCronType) => {
if (newCronType === 'aws') { if (newCronType === 'aws') {
cron.value = '0 0 ? * 1 *'; if (!cron.value || cron.value === defaultStandardCronExpression) {
cron.value = defaultAWSCronExpression;
}
}
else if (newCronType === 'standard') {
if (!cron.value || cron.value === defaultAWSCronExpression) {
cron.value = defaultStandardCronExpression;
} }
else {
cron.value = '40 * * * *';
} }
}, },
}); );
const getHelpers = computed(() => { const getHelpers = computed(() => {
if (cronType.value === 'aws') { if (cronType.value === 'aws') {
return awsHelpers; return awsHelpers;
@ -165,7 +173,7 @@ const cronString = computed(() => {
const cronValidationRules = [ const cronValidationRules = [
{ {
validator: (value: string) => isCronValid(value), validator: (value: string) => isCronValid(value, cronType.value),
message: 'This cron is invalid', message: 'This cron is invalid',
}, },
]; ];