Skip to content

feat(scheduling): a clickable schedule picker in the kit replaces the Routines cron box; plain-language summaries, server preview, cron-only until the scheduler lands (#18432) - #18495

Open
mrveiss wants to merge 4 commits into
mainfrom
issue-18432-schedule-picker
Open

mrveiss wants to merge 4 commits into
mainfrom
issue-18432-schedule-picker

Conversation

@mrveiss

@mrveiss mrveiss commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Refs #18432
Refs #18237

Single-issue rationale

This is the frontend half of #18432 (the schedule picker), built against the contract agreed and pinned on #18432. The backend half (scheduler, POST /api/schedules/preview, schedule_spec on routines, company timezone) is separate and unmerged, so #18432 stays open.

Thinking Path

Owner direction: nobody types cron. Schedules are picked by clicking, shown in plain language, and translated to a stored format in the background. The single canonical home is libs/autobot-ui.

The only schedule input that existed was the plain cron box in views/llc/RoutinesView.vue, and the picker replaces it, so there is no second implementation. No new dependency was added.

What Changed

Pure module (libs/autobot-ui/src/schedule/):

  • ScheduleSpec has three kinds: cron (5-field), calendar (RFC 5545 RRULE, no DTSTART) and once.
  • PickerRule is UI-only. Compiling picks the simplest kind that fits. Day 29–31 becomes BYMONTHDAY=28..N;BYSETPOS=-1, so it runs on the last day in shorter months.
  • Parsing back returns null for a spec it can't represent, which displays as "Custom schedule".
  • Summaries are derived, never stored.
  • Advisory nextRuns uses Intl only:
    • An ambiguous time (clocks go back) runs once, at the earlier instant.
    • A nonexistent time (clocks go forward) runs once, shifted forward by the gap. This matches the backend contract.
    • It returns null rather than guess for 6-field cron, L, W or #.

Kit SchedulePicker:

  • Repeats radiogroup, day chips with aria-pressed, time and zone fields, a summary, the next 3 runs, and an expert cron field.
  • The kit holds no strings; the app passes translate and locale.

App (components/schedule/SchedulePickerField.vue, composables/useSchedule.ts):

  • Provides i18n and the preview call (POST /api/schedules/preview through ApiClient; a 404 or error means "unavailable").
  • Wired into Routines. The list shows summaries, never cron.

Gate, so saving never breaks: while the server preview is unavailable, only cron-expressible rules are offered. The calendar and once options are disabled with a translated note.

Payload sets exactly one schedule field (the server rejects both with 422 schedule.conflicting_fields):

  • cron sends cron_schedule, the same as today.
  • calendar and once send schedule_spec.

Existing routine cron is read as {kind:'cron', timezone:'UTC'}, so nothing shifts.

i18n: repeats, summaries, notes and the error codes are in all 11 locales: schedule.invalid_cron, cron_extension_unsupported, invalid_timezone, once_in_past, invalid_rrule and conflicting_fields.

User-visible changes:

  • Routines shows a clickable picker and plain-language summaries instead of a cron text box.
  • Save is disabled while the schedule is invalid.

Not done here:

  • The workflow Schedule trigger and automation setup don't exist in the tree yet. They adopt SchedulePickerField when built.
  • The company timezone field doesn't exist yet (UTC until it does).
  • The Polish and Urdu nth-weekday phrasing may read stiffly and needs native-speaker review.

Verification

  • Kit: 176 tests passed, including 79 for the module (compile, parse, round-trip, summary and DST next-runs) and 21 for the component.
  • App: 32 passed (Routines wiring, useSchedule, and 11-locale key parity with rendering).
  • Ratchets: file size, fragmentation, hardcoded colour, raw palette and i18n untranslated give 145 passed. RoutinesView's ceiling went from 691 to 689; fragmentation went from 5613/9378 to 5612/9377.
  • Pushed with owner-approved AUTOBOT_PREPUSH_ALLOW_UNRUNNABLE=1: the shared installed hook predates feat(shell): Refined UI step 2: top nav and icon cluster, Minimal/Full mode, Appearance settings, one brand mark (#18240) #18373's kit-claim fix.

Model Used

Claude Opus 5.5 (coordinating). A Sonnet subagent did the implementation.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added a schedule picker for routines, with options for recurring and one-off schedules, time zones, upcoming-run previews and advanced cron editing.
    • Routine lists now show readable schedule summaries, and existing schedules can be edited and saved.
    • Added schedule interface translations across 11 languages.
  • Bug Fixes
    • Added schedule validation and clearer error messages. Saving is disabled when a schedule is invalid.

…er, with the server preview and 11-locale strings (#18432)
…ble, one-of payload fields, and the composables split to 30-line functions (#18432)
@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

📝 Walkthrough

Walkthrough

The change adds a shared schedule library and picker for cron, calendar, and one-time schedules. The routines view now displays schedule summaries and saves schedules through shared helpers. Schedule translations and tests cover the picker and its routine integration.

Changes

Schedule picker and routine scheduling

Layer / File(s) Summary
Schedule contracts and conversion
libs/autobot-ui/src/schedule/*, libs/autobot-ui/src/schedule/__tests__/*
Adds schedule types and utilities to parse and compile cron, calendar, and one-time rules; format summaries; handle time zones; and calculate upcoming runs. Tests cover conversion, supported inputs, summaries, and time-zone cases.
Picker state, editing, and previews
libs/autobot-ui/src/components/SchedulePicker.vue, libs/autobot-ui/src/components/ScheduleTimeField.vue, libs/autobot-ui/src/composables/useSchedule*.ts, libs/autobot-ui/src/components/__tests__/SchedulePicker.test.ts, libs/autobot-ui/index.ts
Adds the shared picker, time controls, model and rule state, cron editing, and server and advisory previews. Exports the picker and schedule utilities. Tests cover picker behaviour, validation, previews, and model updates.
Routine integration and schedule translations
autobot-frontend/src/components/schedule/*, autobot-frontend/src/composables/useSchedule.ts, autobot-frontend/src/views/llc/RoutinesView.vue, autobot-frontend/src/i18n/locales/*.json, autobot-frontend/src/views/llc/__tests__/RoutinesView.schedule.test.ts, autobot-frontend/src/components/schedule/__tests__/SchedulePickerField.i18n.test.ts, autobot-frontend/src/composables/__tests__/useSchedule.test.ts, repo_tests/*ratchet*, scripts/frontend_file_size_known_large.py
Adds the app wrapper and helpers, then uses them to display routine schedule summaries and submit cron or schedule_spec payloads. Adds schedule strings across 11 locales and tests for locale coverage, helper outputs, and routine editing. Updates frontend size and fragmentation baselines.

Priority: ➖ Normal

Merge Risk: 🟡 Moderate · up to b74c7

A routine saved with a non-UTC timezone can run at the wrong local time. Fix timezone handling before merging; advisory previews and preview-error reporting also need correction.

Pre-merge checks | Passed 4 | Failed 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 102 functions across 29 files. (15 skippe… Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title clearly describes the main change: replacing the Routines cron box with a shared schedule picker, summaries and server preview. It is detailed but remains relevant and specific.
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.

Full details: Docstring Coverage

Explanation

Docstring coverage is 23.53% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 102 functions across 29 files. (15 skipped: 15 unsupported.)


  • Fix all pre-merge checks with AI
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Commit to this branch
  • Create a new PR

🧪 Generate unit tests (beta)
  • Commit to this branch
  • Create a new PR

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@mrveiss

mrveiss commented Oct 12, 2026

Copy link
Copy Markdown
Owner Author

Review (Sonnet) at b74c74f: approve.

  • Contract: schedulePayload() sends exactly one of cron_schedule/schedule_spec.
  • Cron-only gate: applies while /api/schedules/preview is unavailable (SchedulePicker.vue:78), so saves stay cron-only and an already-saved non-cron value stays selectable.
  • Backend consistency: 5-field cron only, with the backend's 6 error codes mapped and a generic fallback.
  • i18n: the schedule namespace has 83 keys in all 11 locales.
  • Design system: the picker is in the kit, with no hex/rgb/hsl, consumed via the kit export.
  • index.ts: append-only.

LOWs (follow-ups, non-blocking):

  • RoutinesView.vue:96: scheduleValid starts true, so Save can be enabled for a null spec. Disable Save while form.schedule is null.
  • useSchedulePreviewCall's bare catch logs nothing.
  • llc.routines.fieldCron/fieldCronHint look unused now: confirm before any removal.

Queued for the next merge train.

@github-actions

Copy link
Copy Markdown
Contributor

✅ SSOT Configuration Compliance: Passing

🎉 No new hardcoded values of either class — ssot and other both block.

Known backlog in pipeline-scripts/hardcoded_values_baseline.txt is suppressed and tracked in #14371.

@github-actions

Copy link
Copy Markdown
Contributor

Notice: 29 open PRs — past the runaway threshold (25)

This is not a request to defer this PR. The actual limit is the open-PR cap (AUTOBOT_OPEN_PR_CAP, default 40), enforced at pre-push against NEW branches only -- pushing more commits to this PR's own branch is never blocked by it.

This notice only means the count is high enough to be worth a glance for a runaway — something opening PRs in a loop, or a merge pipeline that has stalled so nothing is draining.

Currently open:

If the queue is draining normally, ignore this. Otherwise:

  1. Check whether CI is dispatching at all — see the ci-dispatch-watchdog status on these PRs
  2. Merge the ones whose CI has finished and review has passed: gh pr merge <number> --squash --delete-branch
  3. Look for a loop opening near-identical PRs

Warn-only runaway detector — .github/workflows/pr-queue-gate.yml. It never blocks a merge.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3


ℹ️ Review info
⚙️ Run configuration
  • Configuration used: Repository: mrveiss/AutoBot-AI/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 60719b82-a83f-41de-9bb0-b894586f12a8
📥 Commits

Reviewing files that changed from the base of the PR and between dbd8ac9 and b74c74f.

📒 Files selected for processing (44)
  • autobot-frontend/src/components/schedule/SchedulePickerField.vue
  • autobot-frontend/src/components/schedule/__tests__/SchedulePickerField.i18n.test.ts
  • autobot-frontend/src/composables/__tests__/useSchedule.test.ts
  • autobot-frontend/src/composables/useSchedule.ts
  • autobot-frontend/src/i18n/locales/ar.json
  • autobot-frontend/src/i18n/locales/de.json
  • autobot-frontend/src/i18n/locales/en.json
  • autobot-frontend/src/i18n/locales/es.json
  • autobot-frontend/src/i18n/locales/fa.json
  • autobot-frontend/src/i18n/locales/fr.json
  • autobot-frontend/src/i18n/locales/he.json
  • autobot-frontend/src/i18n/locales/lv.json
  • autobot-frontend/src/i18n/locales/pl.json
  • autobot-frontend/src/i18n/locales/pt.json
  • autobot-frontend/src/i18n/locales/ur.json
  • autobot-frontend/src/views/llc/RoutinesView.vue
  • autobot-frontend/src/views/llc/__tests__/RoutinesView.schedule.test.ts
  • libs/autobot-ui/index.ts
  • libs/autobot-ui/src/components/SchedulePicker.vue
  • libs/autobot-ui/src/components/ScheduleTimeField.vue
  • libs/autobot-ui/src/components/__tests__/SchedulePicker.test.ts
  • libs/autobot-ui/src/composables/useScheduleExpert.ts
  • libs/autobot-ui/src/composables/useScheduleFields.ts
  • libs/autobot-ui/src/composables/useScheduleMessages.ts
  • libs/autobot-ui/src/composables/useSchedulePreview.ts
  • libs/autobot-ui/src/composables/useScheduleState.ts
  • libs/autobot-ui/src/schedule/__tests__/nextRuns.test.ts
  • libs/autobot-ui/src/schedule/__tests__/schedule.test.ts
  • libs/autobot-ui/src/schedule/compile.ts
  • libs/autobot-ui/src/schedule/cronFields.ts
  • libs/autobot-ui/src/schedule/defaults.ts
  • libs/autobot-ui/src/schedule/index.ts
  • libs/autobot-ui/src/schedule/nextRuns.ts
  • libs/autobot-ui/src/schedule/parse.ts
  • libs/autobot-ui/src/schedule/rrule.ts
  • libs/autobot-ui/src/schedule/rruleDays.ts
  • libs/autobot-ui/src/schedule/summary.ts
  • libs/autobot-ui/src/schedule/time.ts
  • libs/autobot-ui/src/schedule/types.ts
  • libs/autobot-ui/src/schedule/zone.ts
  • repo_tests/frontend_file_size_ratchet_baseline.py
  • repo_tests/frontend_file_size_ratchet_test.py
  • repo_tests/frontend_fragmentation_ratchet_test.py
  • scripts/frontend_file_size_known_large.py

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Comment on lines +34 to +42
/**
* Routine payload fragment: EXACTLY ONE of `cron_schedule` / `schedule_spec`.
* A cron spec is today's payload; calendar and once go as `schedule_spec`
* alone. Sending both is a 422 `schedule.conflicting_fields`.
*/
export function schedulePayload(spec: ScheduleSpec | null): Record<string, unknown> {
if (!spec) return {}
return spec.kind === 'cron' ? { cron_schedule: spec.cron } : { schedule_spec: spec }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🔎 Supported by static analysis

🏁 Script executed:

sed -n '28,72p' autobot-frontend/src/composables/useSchedule.ts
sed -n '1,115p' autobot-frontend/src/components/schedule/SchedulePickerField.vue
sed -n '193,240p' libs/autobot-ui/src/components/SchedulePicker.vue
rg -n 'cron_schedule|schedule_spec' autobot-frontend/src/views/llc/RoutinesView.vue | head -45

Repository: mrveiss/AutoBot-AI

Length of output: 6520


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- picker timezone and model flow ---'
rg -n -F --glob '*.vue' --glob '*.ts' -- 'timezone' libs/autobot-ui/src/components/SchedulePicker.vue libs/autobot-ui/src autobot-frontend/src/components/schedule autobot-frontend/src/composables/useSchedule.ts | head -160
printf '%s\n' '--- routine save and schedule bindings ---'
rg -n -F --glob '*.vue' --glob '*.ts' --glob '*.py' -- 'schedulePayload' autobot-frontend/src
rg -n -F --glob '*.vue' --glob '*.ts' --glob '*.py' -- 'cron_schedule' autobot-frontend/src autobot-backend 2>/dev/null | head -220
printf '%s\n' '--- schedule contracts and tests ---'
rg -n -i --glob '*.{py,ts,vue}' -- 'schedule_spec|cron.*timezone|timezone.*cron|RoutinesView|SchedulePicker' autobot-backend autobot-frontend libs 2>/dev/null | head -300

Repository: mrveiss/AutoBot-AI

Length of output: 31103


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- zone list and picker state ---'
rg -n -F --glob '*.ts' --glob '*.vue' -- 'function listZones' libs/autobot-ui/src
sed -n '1,105p' libs/autobot-ui/src/composables/useScheduleState.ts
sed -n '1,100p' libs/autobot-ui/src/components/SchedulePicker.vue
sed -n '1,120p' libs/autobot-ui/src/schedule/zones.ts 2>/dev/null || true
printf '%s\n' '--- routine form and persistence flow ---'
sed -n '250,325p' autobot-frontend/src/views/llc/RoutinesView.vue
sed -n '1,130p' autobot-backend/llc/api/routines.py
sed -n '150,265p' autobot-backend/llc/api/routines.py
printf '%s\n' '--- scheduler and relevant tests ---'
sed -n '70,115p' autobot-backend/llc/scheduler/routine_scheduler.py
sed -n '150,210p' autobot-backend/llc/scheduler/routine_scheduler.py
sed -n '1,130p' autobot-frontend/src/views/llc/__tests__/RoutinesView.schedule.test.ts
sed -n '1,65p' autobot-frontend/src/composables/__tests__/useSchedule.test.ts

Repository: mrveiss/AutoBot-AI

Length of output: 31397


🏁 Script executed:

printf '%s\n' '--- imports and zone-list implementation ---'
sed -n '1,75p' libs/autobot-ui/src/components/SchedulePicker.vue
rg -n -F --glob '*.ts' --glob '*.vue' -- 'listZones' libs/autobot-ui
printf '%s\n' '--- routine save/reload ---'
sed -n '285,320p' autobot-frontend/src/views/llc/RoutinesView.vue
sed -n '1,45p' autobot-frontend/src/composables/useSchedule.ts
printf '%s\n' '--- backend contract and execution ---'
sed -n '45,100p' autobot-backend/llc/api/routines.py
sed -n '155,205p' autobot-backend/llc/api/routines.py
sed -n '215,255p' autobot-backend/llc/api/routines.py
sed -n '90,105p' autobot-backend/llc/scheduler/routine_scheduler.py
sed -n '175,201p' autobot-backend/llc/scheduler/routine_scheduler.py

Repository: mrveiss/AutoBot-AI

Length of output: 15117


🏁 Script executed:

rg -n -F --glob '*.ts' --glob '*.vue' -- 'listZones' libs/autobot-ui/src
rg -n -F --glob '*.ts' --glob '*.vue' -- 'supportedValuesOf' libs/autobot-ui/src
sed -n '1,28p' libs/autobot-ui/src/components/SchedulePicker.vue

Repository: mrveiss/AutoBot-AI

Length of output: 2218


🏁 Script executed:

nl -ba libs/autobot-ui/src/schedule/zone.ts | sed -n '68,90p'

Repository: mrveiss/AutoBot-AI

Length of output: 1036


Persist the selected time zone for cron routines.

The picker offers all IANA time zones, but schedulePayload sends only the cron expression. The selected time zone is discarded.

The routine API stores only cron_schedule. routineSpec reloads it as UTC, and the scheduler evaluates it from UTC. A user who selects a non-UTC zone can therefore see and execute the routine at the wrong local time.

Persist the time zone through the routine API and scheduler, or restrict the routines picker to UTC until that contract is supported.

Comment on lines +45 to +54
export function useSchedulePreviewCall(): SchedulePreviewFn {
const api = useApiClient()
return async (spec, count) => {
try {
return await api.post<PreviewResult>('/api/schedules/preview', { spec, count })
} catch {
return null
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Do not convert every preview failure into "unavailable".

useSchedulePreviewCall catches every error and returns null. The picker then treats a 500, a network timeout and a 404 the same way: it shows the preview as unavailable and enables the cron-only gate. The path instruction for **/*.{ts,vue} requires that "a request that failed must stay distinguishable from one that legitimately returned nothing". Return null only for a 404 (endpoint not deployed). For any other failure, log it or rethrow it. The kit ask() function already converts a rejection into an advisory fallback.

Proposed fix
-    } catch {
-      return null
+    } catch (err) {
+      if (err instanceof Error && /\b404\b/.test(err.message)) return null
+      throw err
     }

As per path instructions: "a caught error that resolves to an empty or default value — a request that failed must stay distinguishable from one that legitimately returned nothing."

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export function useSchedulePreviewCall(): SchedulePreviewFn {
const api = useApiClient()
return async (spec, count) => {
try {
return await api.post<PreviewResult>('/api/schedules/preview', { spec, count })
} catch {
return null
}
}
}
export function useSchedulePreviewCall(): SchedulePreviewFn {
const api = useApiClient()
return async (spec, count) => {
try {
return await api.post<PreviewResult>('/api/schedules/preview', { spec, count })
} catch (err) {
if (err instanceof Error && /\b404\b/.test(err.message)) return null
throw err
}
}
}

Source: Path instructions

Comment on lines +68 to +79
/** Parse exactly five whitespace-separated fields; null for anything else. */
export function parseCron5(cron: string): CronFields | null {
const raw = cron.trim().split(/\s+/)
if (raw.length !== 5) return null
const minute = parseCronField(raw[0], 0, 59)
const hour = parseCronField(raw[1], 0, 23)
const dom = parseCronField(raw[2], 1, 31)
const month = parseCronField(raw[3], 1, 12, MONTH_NAMES, 1)
const dow = parseDow(raw[4])
if (!minute || !hour || !dom || !month || !dow) return null
return { minute, hour, dom, month, dow, domStar: raw[2].startsWith('*'), dowStar: raw[4].startsWith('*'), raw }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🔎 Supported by static analysis

🏁 Script executed:

sed -n '29,79p' libs/autobot-ui/src/schedule/cronFields.ts
sed -n '20,67p' libs/autobot-ui/src/schedule/nextRuns.ts
sed -n '1,65p' libs/autobot-ui/src/schedule/__tests__/nextRuns.test.ts

Repository: mrveiss/AutoBot-AI

Length of output: 6986


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- changed diff ---'
git diff --unified=30 df211d3ba64f9ebcb1db611f33197b9654a1dacd b74c74fd5f419e21d0dabc6d0852e4cc4a539068 -- libs/autobot-ui/src/schedule/cronFields.ts libs/autobot-ui/src/schedule/nextRuns.ts libs/autobot-ui/src/schedule/__tests__
printf '%s\n' '--- cron-related tests and callers ---'
rg -n -F --glob '*.{ts,tsx,vue,py}' -- 'parseCron5' libs app backend . 2>/dev/null || test "$?" -eq 1
rg -n -F --glob '*.{ts,tsx,vue,py}' -- 'nextRuns(' libs app backend . 2>/dev/null || test "$?" -eq 1
printf '%s\n' '--- cron scheduler references ---'
rg -n -i --glob '*.{ts,tsx,vue,py}' -- 'vixie|croniter|cron_schedule|day-of-month|day-of-week|day of month|day of week' . 2>/dev/null || test "$?" -eq 1
printf '%s\n' '--- relevant source excerpts ---'
nl -ba libs/autobot-ui/src/schedule/cronFields.ts | sed -n '1,95p'
nl -ba libs/autobot-ui/src/schedule/nextRuns.ts | sed -n '1,125p'
nl -ba libs/autobot-ui/src/schedule/__tests__/nextRuns.test.ts | sed -n '20,70p'

Repository: mrveiss/AutoBot-AI

Length of output: 41714


🏁 Script executed:

set -o pipefail
printf '%s\n' '--- preview caller and display ---'
rg -n -F --glob '*.{ts,vue}' -- 'useSchedulePreview' autobot-frontend/src libs/autobot-ui
rg -n -F --glob '*.{ts,vue}' -- 'nextRuns' autobot-frontend/src libs/autobot-ui
nl -ba autobot-frontend/src/composables/useSchedulePreview.ts 2>/dev/null | sed -n '1,220p'
rg -n -F --glob 'RoutinesView.vue' -- 'nextRuns' autobot-frontend/src
nl -ba autobot-frontend/src/views/llc/RoutinesView.vue | sed -n '130,360p'
printf '%s\n' '--- backend cron contract and consumers ---'
nl -ba autobot-backend/llc/scheduler/routine_scheduler.py | sed -n '1,215p'
nl -ba autobot-backend/llc/api/routines.py | sed -n '145,265p'
printf '%s\n' '--- tests for preview/display and cron semantics ---'
rg -n -i --glob '*.{ts,py}' -- 'preview|next run|next-run|day.of.month|day.of.week|cron' autobot-frontend/src/views/llc/__tests__ autobot-backend/llc/tests | head -240

Repository: mrveiss/AutoBot-AI

Length of output: 43324


🏁 Script executed:

set -o pipefail
nl -ba libs/autobot-ui/src/composables/useSchedulePreview.ts | sed -n '1,115p'
nl -ba libs/autobot-ui/src/components/SchedulePicker.vue | sed -n '1,90p'
nl -ba libs/autobot-ui/src/components/SchedulePicker.vue | sed -n '185,235p'
nl -ba autobot-frontend/src/components/schedule/SchedulePickerField.vue | sed -n '1,100p'
rg -n -F --glob '*.{ts,vue}' -- 'SchedulePickerField' autobot-frontend/src/views/llc autobot-frontend/src/components

Repository: mrveiss/AutoBot-AI

Length of output: 15727


Treat only * as an unrestricted day field.

parseCronField accepts */2 as a valid restricted day set, but parseCron5 marks it as unrestricted because it starts with *. cronSource then requires both the day-of-month and day-of-week values to match. For 0 9 */2 * MON, the advisory preview therefore omits valid odd dates and Mondays that do not satisfy both conditions. This preview remains visible when the server preview is unavailable.

Suggested fix
-  return { minute, hour, dom, month, dow, domStar: raw[2].startsWith('*'), dowStar: raw[4].startsWith('*'), raw }
+  return { minute, hour, dom, month, dow, domStar: raw[2] === '*', dowStar: raw[4] === '*', raw }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/** Parse exactly five whitespace-separated fields; null for anything else. */
export function parseCron5(cron: string): CronFields | null {
const raw = cron.trim().split(/\s+/)
if (raw.length !== 5) return null
const minute = parseCronField(raw[0], 0, 59)
const hour = parseCronField(raw[1], 0, 23)
const dom = parseCronField(raw[2], 1, 31)
const month = parseCronField(raw[3], 1, 12, MONTH_NAMES, 1)
const dow = parseDow(raw[4])
if (!minute || !hour || !dom || !month || !dow) return null
return { minute, hour, dom, month, dow, domStar: raw[2].startsWith('*'), dowStar: raw[4].startsWith('*'), raw }
}
/** Parse exactly five whitespace-separated fields; null for anything else. */
export function parseCron5(cron: string): CronFields | null {
const raw = cron.trim().split(/\s+/)
if (raw.length !== 5) return null
const minute = parseCronField(raw[0], 0, 59)
const hour = parseCronField(raw[1], 0, 23)
const dom = parseCronField(raw[2], 1, 31)
const month = parseCronField(raw[3], 1, 12, MONTH_NAMES, 1)
const dow = parseDow(raw[4])
if (!minute || !hour || !dom || !month || !dow) return null
return { minute, hour, dom, month, dow, domStar: raw[2] === '*', dowStar: raw[4] === '*', raw }
}

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant