Skip to content

Commit 3961876

Browse files
committed
feat: add seconds to cron
1 parent 7eee57e commit 3961876

File tree

1 file changed

+42
-14
lines changed
  • apps/frontend/src/pages/servers/manage/[id]/options/scheduling

1 file changed

+42
-14
lines changed

apps/frontend/src/pages/servers/manage/[id]/options/scheduling/[taskId].vue

Lines changed: 42 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
<section v-if="error" class="universal-card">
66
<h2>An error occurred whilst opening the task editor.</h2>
77
<p>{{ error }}</p>
8-
<!-- TODO: Replace this with a better error visualization. -->
98
</section>
109
<section v-else class="universal-card">
1110
<h2>{{ isNew ? "New scheduled task" : "Editing scheduled task" }}</h2>
@@ -97,11 +96,11 @@
9796
v-model="customCron"
9897
type="text"
9998
class="input input-bordered font-mono"
100-
placeholder="0 9 * * *"
99+
placeholder="0 0 9 * * *"
101100
/>
102101
<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>).
105104
</div>
106105
<div v-else class="text-xs">
107106
{{ humanReadableDescription }}
@@ -144,7 +143,6 @@
144143
:placeholder="`/tellraw @a \u0022Restarting in {}!\u0022`"
145144
class="input input-bordered"
146145
/>
147-
<!-- TODO: Warning interval UI -->
148146
</div>
149147

150148
<div class="mt-6 flex max-w-md gap-2">
@@ -194,7 +192,7 @@ const task = ref<Partial<ServerSchedule | Schedule>>({});
194192
const scheduleType = ref<"daily" | "custom">("daily");
195193
const dayInterval = ref("1");
196194
const selectedTime = ref({ hour: "9", minute: "0" });
197-
const customCron = ref("0 9 * * *");
195+
const customCron = ref("0 0 9 * * *");
198196
const actionKinds: ActionKind[] = ["restart", "game-command"];
199197
200198
const commandValue = computed({
@@ -218,14 +216,14 @@ const cronString = computed(() => {
218216
const hour = selectedTime.value.hour === "" ? "0" : selectedTime.value.hour;
219217
const days = dayInterval.value === "" || Number(dayInterval.value) < 1 ? "1" : dayInterval.value;
220218
if (days === "1") {
221-
return `${minute} ${hour} * * *`;
219+
return `0 ${minute} ${hour} * * *`;
222220
} else {
223-
return `${minute} ${hour} */${days} * *`;
221+
return `0 ${minute} ${hour} */${days} * *`;
224222
}
225223
});
226224
227225
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*$/;
229227
230228
const isValidCron = computed(() => {
231229
const cronToTest = scheduleType.value === "custom" ? customCron.value.trim() : cronString.value;
@@ -236,7 +234,10 @@ const isValidCron = computed(() => {
236234
237235
if (scheduleType.value === "custom") {
238236
try {
239-
cronToString(cronToTest);
237+
const parts = cronToTest.split(/\s+/);
238+
if (parts.length === 6) {
239+
cronToString(parts.slice(1).join(" "));
240+
}
240241
return true;
241242
} catch {
242243
return false;
@@ -250,7 +251,11 @@ const humanReadableDescription = computed<string | undefined>(() => {
250251
if (!isValidCron.value && scheduleType.value === "custom") return undefined;
251252
if (scheduleType.value === "custom") {
252253
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";
254259
} catch {
255260
return "Invalid cron expression";
256261
}
@@ -327,7 +332,30 @@ onBeforeMount(async () => {
327332
task.value = { ...found };
328333
if (task.value.every && typeof task.value.every === "string") {
329334
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) {
331359
const minute = parts[0];
332360
const hour = parts[1];
333361
const dayOfMonth = parts[2];
@@ -342,7 +370,7 @@ onBeforeMount(async () => {
342370
selectedTime.value = { hour, minute };
343371
} else {
344372
scheduleType.value = "custom";
345-
customCron.value = task.value.every;
373+
customCron.value = `0 ${task.value.every}`;
346374
}
347375
} else {
348376
scheduleType.value = "custom";
@@ -369,7 +397,7 @@ onBeforeMount(async () => {
369397
scheduleType.value = "daily";
370398
dayInterval.value = "1";
371399
selectedTime.value = { hour: "9", minute: "0" };
372-
customCron.value = "0 9 * * *";
400+
customCron.value = "0 0 9 * * *";
373401
if (isValidCron.value) {
374402
task.value.every = cronString.value;
375403
}

0 commit comments

Comments
 (0)