-
Notifications
You must be signed in to change notification settings - Fork 0
feat(ui): Add dedicated cron jobs management page #38
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Add CronJobsView.vue with full CRUD for scheduled tasks - Support both command and backup task types - Add search, filter by deployment/type, and pagination - Show execution history with output/error details - Add route /cron-jobs and navigation in System group - Uses existing schedulerApi endpoints (no agent changes) Signed-off-by: nfebe <fenn25.fn@gmail.com>
Add comprehensive test suite covering view structure, data loading, filtering, pagination, modal interactions, task actions, execution history, and form validation. Signed-off-by: nfebe <fenn25.fn@gmail.com>
Deploying flatrun-ui with
|
| Latest commit: |
d73c475
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://932ada10.flatrun-ui.pages.dev |
| Branch Preview URL: | https://feature-cron-jobs-page.flatrun-ui.pages.dev |
Code Review Summary✨ This PR introduces a new 🚀 Key Improvements
💡 Minor Suggestions
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review complete. See the overview comment for a summary.
- Add CronJobForm interface for form object - Replace magic numbers with named constants for pagination and API limits (PAGE_SIZE, RECENT_EXECUTIONS_LIMIT, TASK_HISTORY_LIMIT)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Review complete. See the overview comment for a summary.
| const cronToHuman = (expr: string): string => { | ||
| const parts = expr.split(" "); | ||
| if (parts.length !== 5) return "Invalid cron expression"; | ||
|
|
||
| const [minute, hour, dayOfMonth, month, dayOfWeek] = parts; | ||
|
|
||
| if (minute === "0" && hour === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | ||
| return "Every hour"; | ||
| } | ||
| if (minute === "*" && hour === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | ||
| return "Every minute"; | ||
| } | ||
| if (dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | ||
| if (minute !== "*" && hour !== "*") { | ||
| return `Daily at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; | ||
| } | ||
| if (minute !== "*" && hour === "*") { | ||
| return `Hourly at minute ${minute}`; | ||
| } | ||
| } | ||
| if (dayOfWeek === "0" && dayOfMonth === "*" && month === "*") { | ||
| return `Weekly on Sunday at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; | ||
| } | ||
| if (dayOfMonth === "1" && month === "*" && dayOfWeek === "*") { | ||
| return `Monthly on the 1st at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; | ||
| } | ||
|
|
||
| return expr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cronToHuman function can be enhanced to provide more explicit human-readable descriptions for common cron patterns, especially those involving */N (e.g., "every 5 minutes"). The current implementation might return the raw cron string for such patterns or provide a less precise description like "Hourly at minute */5". Refining the logic to prioritize these common expressions will improve user experience.
| const cronToHuman = (expr: string): string => { | |
| const parts = expr.split(" "); | |
| if (parts.length !== 5) return "Invalid cron expression"; | |
| const [minute, hour, dayOfMonth, month, dayOfWeek] = parts; | |
| if (minute === "0" && hour === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | |
| return "Every hour"; | |
| } | |
| if (minute === "*" && hour === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | |
| return "Every minute"; | |
| } | |
| if (dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | |
| if (minute !== "*" && hour !== "*") { | |
| return `Daily at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; | |
| } | |
| if (minute !== "*" && hour === "*") { | |
| return `Hourly at minute ${minute}`; | |
| } | |
| } | |
| if (dayOfWeek === "0" && dayOfMonth === "*" && month === "*") { | |
| return `Weekly on Sunday at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; | |
| } | |
| if (dayOfMonth === "1" && month === "*" && dayOfWeek === "*") { | |
| return `Monthly on the 1st at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; | |
| } | |
| return expr; | |
| const cronToHuman = (expr: string): string => { | |
| const parts = expr.split(" "); | |
| if (parts.length !== 5) return "Invalid cron expression"; | |
| const [minute, hour, dayOfMonth, month, dayOfWeek] = parts; | |
| // Every minute | |
| if (minute === "*" && hour === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | |
| return "Every minute"; | |
| } | |
| // Every N minutes | |
| if (minute.startsWith("*/") && hour === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | |
| const interval = parseInt(minute.substring(2)); | |
| if (!isNaN(interval) && interval > 0) return `Every ${interval} minutes`; | |
| } | |
| // Every hour (at minute 0) | |
| if (minute === "0" && hour === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | |
| return "Every hour"; | |
| } | |
| // Every N hours (at minute 0) | |
| if (minute === "0" && hour.startsWith("*/") && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | |
| const interval = parseInt(hour.substring(2)); | |
| if (!isNaN(interval) && interval > 0) return `Every ${interval} hours`; | |
| } | |
| // Hourly at specific minute | |
| if (hour === "*" && dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | |
| return `Hourly at minute ${minute}`; | |
| } | |
| // Daily at specific time | |
| if (dayOfMonth === "*" && month === "*" && dayOfWeek === "*") { | |
| return `Daily at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; | |
| } | |
| // Weekly on Sunday at specific time | |
| if (dayOfWeek === "0" && dayOfMonth === "*" && month === "*") { | |
| return `Weekly on Sunday at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; | |
| } | |
| // Monthly on the 1st at specific time | |
| if (dayOfMonth === "1" && month === "*" && dayOfWeek === "*") { | |
| return `Monthly on the 1st at ${hour.padStart(2, "0")}:${minute.padStart(2, "0")}`; | |
| } | |
| return expr; | |
| }; |
No description provided.