fix: stop counted schedules being rewritten as one-offs on save (#29263)

* fix: stop labelling a counted schedule as a one-off

The schedule label treated any rule whose text contained COUNT=1 as a single run, so counts such as 10, 12 and 14 were shown as "Once" together with the date of the first run, on the automations list and on the automation page alike. The label now matches a count of exactly one.

This covers the two places that render the label. The schedule editor reads the count the same way and changes separately. Rules that carry a start date still fall through to the raw rule text, exactly as they already did without a count; that parsing gap changes separately too.

Verified in a browser against the same build without these lines: ten ordinary schedules render identically in both places, and a genuine single-run schedule is still labelled as one.

* fix: stop counted schedules being rewritten as one-offs on save

The schedule editor decides that a rule is a one-off by looking for the text COUNT=1 anywhere in it. A rule that runs ten times carries COUNT=10, which contains that text, so opening such an automation shows it as a single run and saving writes a genuine one-off rule back. One open and save is enough to silently turn a ten run schedule into a one run schedule, with whatever date happened to sit in the rule. The check now requires that no further digit follows, the same test the two schedule labels already use.

The same screens also failed to read counted rules at all. Both label helpers and the editor parser split the stored rule on semicolons after stripping the RRULE prefix, so when the rule carries a DTSTART line the first piece is that whole line and the frequency is never found. The automations list then printed the raw rule text where a human label belongs, and the editor fell back to a plain daily schedule, quietly discarding the weekly or monthly settings on the next save. All three sites now drop the DTSTART part before splitting. They split on whitespace, so the newline form and the space separated form are both handled, matching how the backend already strips it.
This commit is contained in:
Classic298
2026-08-30 22:12:43 +02:00
committed by GitHub
parent b8f279b8fb
commit 0e65c65cc7
3 changed files with 13 additions and 4 deletions

View File

@@ -95,7 +95,7 @@
};
const formatSchedule = (rrule: string): string => {
if (rrule.includes('COUNT=1')) {
if (/COUNT=1(?!\d)/.test(rrule)) {
const match = rrule.match(/DTSTART:(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})/);
if (match) {
const d = new Date(`${match[1]}-${match[2]}-${match[3]}T${match[4]}:${match[5]}`);
@@ -109,6 +109,9 @@
const parts: Record<string, string> = {};
rrule
.split(/\s+/)
.filter((line) => !line.toUpperCase().startsWith('DTSTART'))
.join('')
.replace('RRULE:', '')
.split(';')
.forEach((part) => {

View File

@@ -106,7 +106,7 @@
export const parseRrule = (s: string) => {
// Detect ONCE (COUNT=1 with DTSTART)
if (s.includes('COUNT=1')) {
if (/COUNT=1(?!\d)/.test(s)) {
frequency = 'ONCE';
const match = s.match(/DTSTART:(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})/);
if (match) {
@@ -116,7 +116,10 @@
return;
}
const parts: Record<string, string> = {};
s.replace('RRULE:', '')
s.split(/\s+/)
.filter((line) => !line.toUpperCase().startsWith('DTSTART'))
.join('')
.replace('RRULE:', '')
.split(';')
.forEach((p) => {
const [k, v] = p.split('=');

View File

@@ -307,7 +307,7 @@
const formatRRule = (rrule: string): string => {
// Detect one-time schedule (ONCE)
if (rrule.includes('COUNT=1')) {
if (/COUNT=1(?!\d)/.test(rrule)) {
const match = rrule.match(/DTSTART:(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})/);
if (match) {
const d = new Date(`${match[1]}-${match[2]}-${match[3]}T${match[4]}:${match[5]}`);
@@ -317,6 +317,9 @@
}
const parts: Record<string, string> = {};
rrule
.split(/\s+/)
.filter((line) => !line.toUpperCase().startsWith('DTSTART'))
.join('')
.replace('RRULE:', '')
.split(';')
.forEach((p) => {