5
5
<section v-if =" error" class =" universal-card" >
6
6
<h2 >An error occurred whilst opening the task editor.</h2 >
7
7
<p >{{ error }}</p >
8
- <!-- TODO: Replace this with a better error visualization. -->
9
8
</section >
10
9
<section v-else class =" universal-card" >
11
10
<h2 >{{ isNew ? "New scheduled task" : "Editing scheduled task" }}</h2 >
97
96
v-model =" customCron"
98
97
type =" text"
99
98
class =" input input-bordered font-mono"
100
- placeholder =" 0 9 * * *"
99
+ placeholder =" 0 0 9 * * *"
101
100
/>
102
101
<div v-if =" !isValidCron" class =" text-xs text-brand-red" >
103
- Invalid cron format. Please use 5 space-separated values (e.g., minute hour day month
104
- day-of-week).
102
+ Invalid cron format. Please use 6 space-separated values (e.g.,
103
+ < code >second minute hour day month day -of-week</ code > ).
105
104
</div >
106
105
<div v-else class =" text-xs" >
107
106
{{ humanReadableDescription }}
144
143
:placeholder =" `/tellraw @a \u0022Restarting in {}!\u0022`"
145
144
class =" input input-bordered"
146
145
/>
147
- <!-- TODO: Warning interval UI -->
148
146
</div >
149
147
150
148
<div class =" mt-6 flex max-w-md gap-2" >
@@ -194,7 +192,7 @@ const task = ref<Partial<ServerSchedule | Schedule>>({});
194
192
const scheduleType = ref <" daily" | " custom" >(" daily" );
195
193
const dayInterval = ref (" 1" );
196
194
const selectedTime = ref ({ hour: " 9" , minute: " 0" });
197
- const customCron = ref (" 0 9 * * *" );
195
+ const customCron = ref (" 0 0 9 * * *" );
198
196
const actionKinds: ActionKind [] = [" restart" , " game-command" ];
199
197
200
198
const commandValue = computed ({
@@ -218,14 +216,14 @@ const cronString = computed(() => {
218
216
const hour = selectedTime .value .hour === " " ? " 0" : selectedTime .value .hour ;
219
217
const days = dayInterval .value === " " || Number (dayInterval .value ) < 1 ? " 1" : dayInterval .value ;
220
218
if (days === " 1" ) {
221
- return ` ${minute } ${hour } * * * ` ;
219
+ return ` 0 ${minute } ${hour } * * *` ;
222
220
} else {
223
- return ` ${minute } ${hour } */${days } * * ` ;
221
+ return ` 0 ${minute } ${hour } */${days } * *` ;
224
222
}
225
223
});
226
224
227
225
const CRON_REGEX =
228
- / ^ \s * ([0-9 */,-] + )\s + ([0-9 */,-] + )\s + ([0-9 */,-] + )\s + ([0-9 */,-] + )\s + ([0-9 */,-] + )\s * $ / ;
226
+ / ^ \s * ([0-9 */,-] + )\s + ([0-9 */,-] + )\s + ([0-9 */,-] + )\s + ([0-9 */,-] + )\s + ([0-9 */,-] + )\s + ( [ 0-9 */,-] + ) \s * $ / ;
229
227
230
228
const isValidCron = computed (() => {
231
229
const cronToTest = scheduleType .value === " custom" ? customCron .value .trim () : cronString .value ;
@@ -236,7 +234,10 @@ const isValidCron = computed(() => {
236
234
237
235
if (scheduleType .value === " custom" ) {
238
236
try {
239
- cronToString (cronToTest );
237
+ const parts = cronToTest .split (/ \s + / );
238
+ if (parts .length === 6 ) {
239
+ cronToString (parts .slice (1 ).join (" " ));
240
+ }
240
241
return true ;
241
242
} catch {
242
243
return false ;
@@ -250,7 +251,11 @@ const humanReadableDescription = computed<string | undefined>(() => {
250
251
if (! isValidCron .value && scheduleType .value === " custom" ) return undefined ;
251
252
if (scheduleType .value === " custom" ) {
252
253
try {
253
- return cronToString (customCron .value .trim ());
254
+ const parts = customCron .value .trim ().split (/ \s + / );
255
+ if (parts .length === 6 ) {
256
+ return cronToString (parts .slice (1 ).join (" " ));
257
+ }
258
+ return " Invalid cron expression" ;
254
259
} catch {
255
260
return " Invalid cron expression" ;
256
261
}
@@ -327,7 +332,30 @@ onBeforeMount(async () => {
327
332
task .value = { ... found };
328
333
if (task .value .every && typeof task .value .every === " string" ) {
329
334
const parts = task .value .every .split (/ \s + / );
330
- if (parts .length === 5 ) {
335
+ if (parts .length === 6 ) {
336
+ const second = parts [0 ];
337
+ const minute = parts [1 ];
338
+ const hour = parts [2 ];
339
+ const dayOfMonth = parts [3 ];
340
+
341
+ if (second === " 0" && dayOfMonth .startsWith (" */" )) {
342
+ scheduleType .value = " daily" ;
343
+ dayInterval .value = dayOfMonth .substring (2 );
344
+ selectedTime .value = { hour , minute };
345
+ } else if (
346
+ second === " 0" &&
347
+ dayOfMonth === " *" &&
348
+ parts [4 ] === " *" &&
349
+ parts [5 ] === " *"
350
+ ) {
351
+ scheduleType .value = " daily" ;
352
+ dayInterval .value = " 1" ;
353
+ selectedTime .value = { hour , minute };
354
+ } else {
355
+ scheduleType .value = " custom" ;
356
+ customCron .value = task .value .every ;
357
+ }
358
+ } else if (parts .length === 5 ) {
331
359
const minute = parts [0 ];
332
360
const hour = parts [1 ];
333
361
const dayOfMonth = parts [2 ];
@@ -342,7 +370,7 @@ onBeforeMount(async () => {
342
370
selectedTime .value = { hour , minute };
343
371
} else {
344
372
scheduleType .value = " custom" ;
345
- customCron .value = task .value .every ;
373
+ customCron .value = ` 0 ${ task .value .every } ` ;
346
374
}
347
375
} else {
348
376
scheduleType .value = " custom" ;
@@ -369,7 +397,7 @@ onBeforeMount(async () => {
369
397
scheduleType .value = " daily" ;
370
398
dayInterval .value = " 1" ;
371
399
selectedTime .value = { hour: " 9" , minute: " 0" };
372
- customCron .value = " 0 9 * * *" ;
400
+ customCron .value = " 0 0 9 * * *" ;
373
401
if (isValidCron .value ) {
374
402
task .value .every = cronString .value ;
375
403
}
0 commit comments