mirror of
https://github.com/rajnandan1/kener.git
synced 2026-08-07 07:14:56 +00:00
Merge pull request #801 from otherwiseGG/main
feat: added UI support for ordinal weekdays
This commit is contained in:
@@ -28,10 +28,11 @@ FREQ=frequency[;INTERVAL=n][;BYDAY=days][;BYMONTHDAY=day][;COUNT=n][;UNTIL=date]
|
||||
- Default: 1
|
||||
- Integer value: 2 = every other, 3 = every third, etc.
|
||||
|
||||
**BYDAY** (Optional, for WEEKLY)
|
||||
**BYDAY** (Optional, for WEEKLY or MONTHLY with an ordinal prefix)
|
||||
|
||||
- Day codes: `MO`, `TU`, `WE`, `TH`, `FR`, `SA`, `SU`
|
||||
- Multiple days: `MO,WE,FR`
|
||||
- With MONTHLY, prefix a day code with an ordinal to mean "the Nth such weekday of the month": `1WE` (first Wednesday), `1SU` (first Sunday)
|
||||
|
||||
**BYMONTHDAY** (Optional, for MONTHLY)
|
||||
|
||||
@@ -240,6 +241,29 @@ Occurrences:
|
||||
- Continues monthly...
|
||||
```
|
||||
|
||||
#### Nth Day-of-Week of Month (Ordinal BYDAY) {#first-weekday-of-month}
|
||||
|
||||
**RRULE:** `FREQ=MONTHLY;BYDAY=1WE`
|
||||
|
||||
**Description:** Maintenance occurs on the first Wednesday of each month
|
||||
|
||||
**Use Case:** Monthly patch windows tied to a specific weekday
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
Title: Monthly Patch Window
|
||||
Start: June 3, 2026 at 2:30 PM
|
||||
RRULE: FREQ=MONTHLY;BYDAY=1WE
|
||||
Duration: 90 minutes
|
||||
|
||||
Occurrences:
|
||||
- Jun 3, 2026 at 2:30 PM
|
||||
- Jul 1, 2026 at 2:30 PM
|
||||
- Aug 5, 2026 at 2:30 PM
|
||||
- Continues monthly...
|
||||
```
|
||||
|
||||
#### Middle of Month {#middle-of-month}
|
||||
|
||||
**RRULE:** `FREQ=MONTHLY;BYMONTHDAY=15`
|
||||
@@ -362,15 +386,16 @@ Affected Monitors:
|
||||
Title: Monthly Security Updates
|
||||
Description: Critical security patches and system updates
|
||||
Start Date: Sunday, June 4, 2026 at 2:00 AM
|
||||
RRULE: FREQ=MONTHLY;BYMONTHDAY=1
|
||||
RRULE: FREQ=MONTHLY;BYDAY=1SU
|
||||
Duration: 3600 seconds (1 hour)
|
||||
Affected Monitors:
|
||||
- All Servers: MAINTENANCE
|
||||
```
|
||||
|
||||
**Note:** Since RRULE doesn't support "first Sunday", use BYMONTHDAY=1 and choose first occurrence that falls on Sunday, or use BYDAY with ordinal (not supported in Kener UI currently).
|
||||
**Note:** Use ordinal weekday syntax in `BYDAY` for "first X weekday" patterns:
|
||||
|
||||
**Workaround:** Create as weekly and manage manually or use BYMONTHDAY for specific date.
|
||||
- First Sunday: `BYDAY=1SU`
|
||||
- First Wednesday: `BYDAY=1WE`
|
||||
|
||||
### Example 4: Business Hours Backup {#example-backup}
|
||||
|
||||
@@ -469,6 +494,7 @@ Start: 2:00 AM UTC
|
||||
✅ `FREQ=WEEKLY;BYDAY=MO,WE,FR`
|
||||
✅ `FREQ=WEEKLY;INTERVAL=2;BYDAY=SU`
|
||||
✅ `FREQ=MONTHLY;BYMONTHDAY=1`
|
||||
✅ `FREQ=MONTHLY;BYDAY=1WE`
|
||||
✅ `FREQ=MINUTELY;COUNT=1`
|
||||
|
||||
### Invalid RRULEs {#invalid-rrules}
|
||||
@@ -602,6 +628,7 @@ Description: |
|
||||
| Every Sunday | `FREQ=WEEKLY;BYDAY=SU` |
|
||||
| Bi-weekly Mondays | `FREQ=WEEKLY;INTERVAL=2;BYDAY=MO` |
|
||||
| First of month | `FREQ=MONTHLY;BYMONTHDAY=1` |
|
||||
| First Wednesday | `FREQ=MONTHLY;BYDAY=1WE` |
|
||||
| 15th of month | `FREQ=MONTHLY;BYMONTHDAY=15` |
|
||||
| Quarterly | `FREQ=MONTHLY;INTERVAL=3;BYMONTHDAY=1` |
|
||||
|
||||
@@ -619,4 +646,4 @@ Description: |
|
||||
|
||||
- [Creating and Managing Maintenances](/docs/v4/maintenances/creating-managing) - Apply these patterns in the dashboard
|
||||
- [Maintenance Events](/docs/v4/maintenances/events) - Understand how RRULE generates events
|
||||
- [Maintenance Overview](/docs/v4/maintenances/overview) - Learn maintenance fundamentals
|
||||
- [Maintenance Overview](/docs/v4/maintenances/overview) - Learn maintenance fundamentals
|
||||
@@ -28,7 +28,7 @@
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
import { toast } from "svelte-sonner";
|
||||
import { format, formatDistanceToNow, isPast, isFuture, isWithinInterval, addDays } from "date-fns";
|
||||
import { format, formatDistanceToNow, isPast, isFuture, isWithinInterval } from "date-fns";
|
||||
import { rrulestr } from "rrule";
|
||||
import { resolve } from "$app/paths";
|
||||
import clientResolver from "$lib/client/resolver.js";
|
||||
@@ -193,9 +193,16 @@
|
||||
const dtstart = new Date(startDateTimeLocal);
|
||||
const fullRrule = `DTSTART:${dtstart.toISOString().replace(/[-:]/g, "").split(".")[0]}Z\nRRULE:${customRrule}`;
|
||||
const rule = rrulestr(fullRrule);
|
||||
const now = new Date();
|
||||
const windowEnd = addDays(now, 30);
|
||||
const occurrences = rule.between(now, windowEnd, true).slice(0, 5);
|
||||
const occurrences: Date[] = [];
|
||||
let searchFrom = new Date();
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const next = rule.after(searchFrom, i === 0);
|
||||
if (!next) break;
|
||||
occurrences.push(next);
|
||||
searchFrom = next;
|
||||
}
|
||||
|
||||
return occurrences.map((d) => format(d, "EEE, MMM d, yyyy 'at' h:mm a"));
|
||||
} catch (e) {
|
||||
return [];
|
||||
@@ -980,4 +987,4 @@
|
||||
</Button>
|
||||
</Dialog.Footer>
|
||||
</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
</Dialog.Root>
|
||||
Reference in New Issue
Block a user