Uh oh!
There was an error while loading. Please reload this page.
feat(scheduled-tasks): expose Google Calendar-style recurrence options - #5146
Conversation
Add a per-day weekly toggle (repeat on arbitrary weekdays), monthly nth-/last-weekday anchoring, and a yearly frequency to the scheduled task modal, closing the gap with a calendar app's recurrence picker. The recurrence UI compiles to cron, so this is front-end only: croner already speaks the nth/last-weekday (#/#L) syntax, and the display path normalizes #L to cronstrue's L so labels read "last Monday" not "null".
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview UI ( Recurrence model ( Display: Tests cover cron build/parse, occurrence expansion for Reviewed by Cursor Bugbot for commit 9859dfa. Configure here. |
Uh oh!
There was an error while loading. Please reload this page.
Selecting Monthly from the frequency dropdown hard-reset monthlyMode to day-of-month, silently dropping a previously chosen nth-/last-weekday anchor when switching cadence away and back. Preserve the existing mode on reselect, mirroring how the last recurring cadence is restored across the recurring toggle.
waleedlatif1
commented
Jun 20, 2026
waleedlatif1
commented
Jun 20, 2026
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit d4f5bc0. Configure here.
Greptile SummaryThis PR extends the scheduled-task recurrence modal to match a Google Calendar-style recurrence picker: weekly multi-day selection via day-toggle chips, monthly nth/last-weekday anchoring, and a new yearly frequency. All changes are front-end only — the UI compiles to a cron string that croner already understands, so no backend schema or API changes are needed.
Confidence Score: 5/5Safe to merge — all changes are front-end only, compile to cron strings the existing backend already understands, and are well-covered by new unit and integration tests. The recurrence logic is self-contained: it generates and parses cron strings without touching any schema, API route, or scheduling engine. The 5th-occurrence clamp, the recurrence.ts — the weekly Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[User opens Recurrence Section] --> B{Frequency dropdown}
B -->|daily| C[emit: MIN HOUR * * *]
B -->|weekdays| D[emit: MIN HOUR * * 1,2,3,4,5]
B -->|weekly| E[Day-toggle chips]
E --> F[emit: MIN HOUR * * days]
B -->|monthly| G[Monthly mode dropdown]
G -->|day-of-month| H[emit: MIN HOUR DOM * *]
G -->|nth-weekday ordinal <= 4| I{5th occurrence?}
I -->|No| J[emit: MIN HOUR * * WD#N]
I -->|Yes - clamp| K[emit: MIN HOUR * * WD#L]
G -->|last-weekday| K
B -->|yearly| L[emit: MIN HOUR DOM MON *]
B -->|custom| M[pass through raw cron]
N[parseCronToHumanReadable] -->|normalize WD#L to WDL| O[cronstrue display]
J --> N
K --> N
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A[User opens Recurrence Section] --> B{Frequency dropdown}
B -->|daily| C[emit: MIN HOUR * * *]
B -->|weekdays| D[emit: MIN HOUR * * 1,2,3,4,5]
B -->|weekly| E[Day-toggle chips]
E --> F[emit: MIN HOUR * * days]
B -->|monthly| G[Monthly mode dropdown]
G -->|day-of-month| H[emit: MIN HOUR DOM * *]
G -->|nth-weekday ordinal <= 4| I{5th occurrence?}
I -->|No| J[emit: MIN HOUR * * WD#N]
I -->|Yes - clamp| K[emit: MIN HOUR * * WD#L]
G -->|last-weekday| K
B -->|yearly| L[emit: MIN HOUR DOM MON *]
B -->|custom| M[pass through raw cron]
N[parseCronToHumanReadable] -->|normalize WD#L to WDL| O[cronstrue display]
J --> N
K --> N
Reviews (3): Last reviewed commit: "fix(scheduled-tasks): fold 5th-occurrenc..." | Re-trigger Greptile |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
…align weekday-digit parsing Address review edge cases in the monthly recurrence anchors: - The picker no longer offers a fifth weekday (a 5th occurrence is always the month's last), and recurrenceToCron clamps any nth-weekday that resolves to a 5th occurrence to #L — so a launch date drifting to day 29-31 can never emit #5 and silently skip months without one. - cronToRecurrence accepts croner's alternate Sunday digit (7) for the #/#L monthly anchors, matching parseCronToHumanReadable's normalizer; externally-authored 7#L crons now round-trip (canonicalized to 0#L). - #5 crons are left as custom pass-through so their month-skipping behavior is preserved verbatim rather than rewritten.
waleedlatif1
commented
Jun 20, 2026
waleedlatif1
commented
Jun 20, 2026
@cursor review |
There was a problem hiding this comment.
✅ Bugbot reviewed your changes and found no new issues!
Comment @cursor review or bugbot run to trigger another review on this PR
Reviewed by Cursor Bugbot for commit 9859dfa. Configure here.
Summary
Implementation notes
#/#L) syntax — no schema, contract, route, or backend scheduling changesChipModalFieldrows +Chiptoggles (active state), so spacing/typography match the rest of the modalparseCronToHumanReadablenormalizes croner's#Lto cronstrue'sLfor display only (stored cron keeps croner syntax) so labels read "last Monday" instead of "null Monday"Type of Change
Testing
expandOccurrencestest proving croner materializes1#3as the third Monday#/#LpatternsChecklist