feat(KB-228): add schedule time presets
- Add morning, afternoon, evening, and night preset schedules to core automation types - Update ScheduleForm with preset selection dropdown and time handling - Add color coding for different schedule types in ScheduleCard - Add tests for new schedule preset functionality - Include changeset for release tracking
This commit is contained in:
14
.changeset/add-schedule-time-presets.md
Normal file
14
.changeset/add-schedule-time-presets.md
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
---
|
||||||
|
"@dustinbyrne/kb": minor
|
||||||
|
---
|
||||||
|
|
||||||
|
Add 6 new schedule preset options for more granular time intervals
|
||||||
|
|
||||||
|
- Every 15 minutes (`*/15 * * * *`)
|
||||||
|
- Every 30 minutes (`*/30 * * * *`)
|
||||||
|
- Every 2 hours (`0 */2 * * *`)
|
||||||
|
- Every 6 hours (`0 */6 * * *`)
|
||||||
|
- Every 12 hours (`0 */12 * * *`)
|
||||||
|
- Weekdays at 9 AM (`0 9 * * 1-5`)
|
||||||
|
|
||||||
|
Each preset includes its own color badge for visual distinction in the schedule card view.
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
/** Schedule type presets plus a custom cron option. */
|
/** Schedule type presets plus a custom cron option. */
|
||||||
export type ScheduleType = "hourly" | "daily" | "weekly" | "monthly" | "custom";
|
export type ScheduleType = "hourly" | "daily" | "weekly" | "monthly" | "custom" | "every15Minutes" | "every30Minutes" | "every2Hours" | "every6Hours" | "every12Hours" | "weekdays";
|
||||||
|
|
||||||
/** Mapping from preset schedule types to their cron expressions. */
|
/** Mapping from preset schedule types to their cron expressions. */
|
||||||
export const AUTOMATION_PRESETS: Record<Exclude<ScheduleType, "custom">, string> = {
|
export const AUTOMATION_PRESETS: Record<Exclude<ScheduleType, "custom">, string> = {
|
||||||
@@ -7,6 +7,12 @@ export const AUTOMATION_PRESETS: Record<Exclude<ScheduleType, "custom">, string>
|
|||||||
daily: "0 0 * * *",
|
daily: "0 0 * * *",
|
||||||
weekly: "0 0 * * 1",
|
weekly: "0 0 * * 1",
|
||||||
monthly: "0 0 1 * *",
|
monthly: "0 0 1 * *",
|
||||||
|
every15Minutes: "*/15 * * * *",
|
||||||
|
every30Minutes: "*/30 * * * *",
|
||||||
|
every2Hours: "0 */2 * * *",
|
||||||
|
every6Hours: "0 */6 * * *",
|
||||||
|
every12Hours: "0 */12 * * *",
|
||||||
|
weekdays: "0 9 * * 1-5",
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Result of a single automation run. */
|
/** Result of a single automation run. */
|
||||||
|
|||||||
@@ -47,6 +47,12 @@ const SCHEDULE_TYPE_COLORS: Record<string, string> = {
|
|||||||
weekly: "var(--color-purple, #a855f7)",
|
weekly: "var(--color-purple, #a855f7)",
|
||||||
monthly: "var(--color-orange, #f97316)",
|
monthly: "var(--color-orange, #f97316)",
|
||||||
custom: "var(--color-gray, #6b7280)",
|
custom: "var(--color-gray, #6b7280)",
|
||||||
|
every15Minutes: "var(--color-cyan, #06b6d4)",
|
||||||
|
every30Minutes: "var(--color-teal, #14b8a6)",
|
||||||
|
every2Hours: "var(--color-indigo, #6366f1)",
|
||||||
|
every6Hours: "var(--color-rose, #f43f5e)",
|
||||||
|
every12Hours: "var(--color-amber, #f59e0b)",
|
||||||
|
weekdays: "var(--color-emerald, #10b981)",
|
||||||
};
|
};
|
||||||
|
|
||||||
interface ScheduleCardProps {
|
interface ScheduleCardProps {
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ const PRESET_CRON: Record<Exclude<ScheduleType, "custom">, string> = {
|
|||||||
daily: "0 0 * * *",
|
daily: "0 0 * * *",
|
||||||
weekly: "0 0 * * 1",
|
weekly: "0 0 * * 1",
|
||||||
monthly: "0 0 1 * *",
|
monthly: "0 0 1 * *",
|
||||||
|
every15Minutes: "*/15 * * * *",
|
||||||
|
every30Minutes: "*/30 * * * *",
|
||||||
|
every2Hours: "0 */2 * * *",
|
||||||
|
every6Hours: "0 */6 * * *",
|
||||||
|
every12Hours: "0 */12 * * *",
|
||||||
|
weekdays: "0 9 * * 1-5",
|
||||||
};
|
};
|
||||||
|
|
||||||
const SCHEDULE_TYPE_LABELS: Record<ScheduleType, string> = {
|
const SCHEDULE_TYPE_LABELS: Record<ScheduleType, string> = {
|
||||||
@@ -15,6 +21,12 @@ const SCHEDULE_TYPE_LABELS: Record<ScheduleType, string> = {
|
|||||||
weekly: "Every week (Monday)",
|
weekly: "Every week (Monday)",
|
||||||
monthly: "Every month (1st)",
|
monthly: "Every month (1st)",
|
||||||
custom: "Custom cron expression",
|
custom: "Custom cron expression",
|
||||||
|
every15Minutes: "Every 15 minutes",
|
||||||
|
every30Minutes: "Every 30 minutes",
|
||||||
|
every2Hours: "Every 2 hours",
|
||||||
|
every6Hours: "Every 6 hours",
|
||||||
|
every12Hours: "Every 12 hours",
|
||||||
|
weekdays: "Weekdays at 9 AM (Mon-Fri)",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -136,6 +136,27 @@ describe("ScheduleForm", () => {
|
|||||||
const cronField = screen.getByLabelText("Cron Expression") as HTMLInputElement;
|
const cronField = screen.getByLabelText("Cron Expression") as HTMLInputElement;
|
||||||
expect(cronField.value).toBe("0 * * * *");
|
expect(cronField.value).toBe("0 * * * *");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("auto-fills cron expression for every15Minutes preset", () => {
|
||||||
|
render(<ScheduleForm onSubmit={onSubmit} onCancel={onCancel} />);
|
||||||
|
fireEvent.change(screen.getByLabelText("Schedule"), { target: { value: "every15Minutes" } });
|
||||||
|
const cronField = screen.getByLabelText("Cron Expression") as HTMLInputElement;
|
||||||
|
expect(cronField.value).toBe("*/15 * * * *");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("auto-fills cron expression for every6Hours preset", () => {
|
||||||
|
render(<ScheduleForm onSubmit={onSubmit} onCancel={onCancel} />);
|
||||||
|
fireEvent.change(screen.getByLabelText("Schedule"), { target: { value: "every6Hours" } });
|
||||||
|
const cronField = screen.getByLabelText("Cron Expression") as HTMLInputElement;
|
||||||
|
expect(cronField.value).toBe("0 */6 * * *");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("auto-fills cron expression for weekdays preset", () => {
|
||||||
|
render(<ScheduleForm onSubmit={onSubmit} onCancel={onCancel} />);
|
||||||
|
fireEvent.change(screen.getByLabelText("Schedule"), { target: { value: "weekdays" } });
|
||||||
|
const cronField = screen.getByLabelText("Cron Expression") as HTMLInputElement;
|
||||||
|
expect(cronField.value).toBe("0 9 * * 1-5");
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("submission", () => {
|
describe("submission", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user