92 lines
2.8 KiB
TypeScript
92 lines
2.8 KiB
TypeScript
|
|
'use client';
|
||
|
|
|
||
|
|
import { ChevronDown } from 'lucide-react';
|
||
|
|
|
||
|
|
interface Preset {
|
||
|
|
label: string;
|
||
|
|
expr: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
interface PresetGroup {
|
||
|
|
label: string;
|
||
|
|
items: Preset[];
|
||
|
|
}
|
||
|
|
|
||
|
|
const PRESET_GROUPS: PresetGroup[] = [
|
||
|
|
{
|
||
|
|
label: 'Common',
|
||
|
|
items: [
|
||
|
|
{ label: 'Every minute', expr: '* * * * *' },
|
||
|
|
{ label: 'Every 5 min', expr: '*/5 * * * *' },
|
||
|
|
{ label: 'Every 15 min', expr: '*/15 * * * *' },
|
||
|
|
{ label: 'Every 30 min', expr: '*/30 * * * *' },
|
||
|
|
{ label: 'Every hour', expr: '0 * * * *' },
|
||
|
|
{ label: 'Every 6 hours', expr: '0 */6 * * *' },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Daily',
|
||
|
|
items: [
|
||
|
|
{ label: 'Midnight', expr: '0 0 * * *' },
|
||
|
|
{ label: '6 AM', expr: '0 6 * * *' },
|
||
|
|
{ label: '9 AM', expr: '0 9 * * *' },
|
||
|
|
{ label: 'Noon', expr: '0 12 * * *' },
|
||
|
|
{ label: 'Twice daily', expr: '0 6,18 * * *' },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Weekly',
|
||
|
|
items: [
|
||
|
|
{ label: 'Weekdays 9 AM', expr: '0 9 * * 1-5' },
|
||
|
|
{ label: 'Monday 9 AM', expr: '0 9 * * 1' },
|
||
|
|
{ label: 'Friday 5 PM', expr: '0 17 * * 5' },
|
||
|
|
{ label: 'Sunday 0 AM', expr: '0 0 * * 0' },
|
||
|
|
{ label: 'Weekends 9 AM', expr: '0 9 * * 0,6' },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
{
|
||
|
|
label: 'Periodic',
|
||
|
|
items: [
|
||
|
|
{ label: 'Monthly 1st', expr: '0 0 1 * *' },
|
||
|
|
{ label: '1st & 15th', expr: '0 0 1,15 * *' },
|
||
|
|
{ label: 'Quarterly', expr: '0 0 1 */3 *' },
|
||
|
|
{ label: 'Bi-annual', expr: '0 0 1 1,7 *' },
|
||
|
|
{ label: 'January 1st', expr: '0 0 1 1 *' },
|
||
|
|
],
|
||
|
|
},
|
||
|
|
];
|
||
|
|
|
||
|
|
interface CronPresetsProps {
|
||
|
|
onSelect: (expr: string) => void;
|
||
|
|
current: string;
|
||
|
|
}
|
||
|
|
|
||
|
|
export function CronPresets({ onSelect, current }: CronPresetsProps) {
|
||
|
|
const allExprs = PRESET_GROUPS.flatMap(g => g.items.map(i => i.expr));
|
||
|
|
const isPreset = allExprs.includes(current);
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="relative">
|
||
|
|
<select
|
||
|
|
value={isPreset ? current : ''}
|
||
|
|
onChange={(e) => { if (e.target.value) onSelect(e.target.value); }}
|
||
|
|
className="w-full appearance-none bg-muted/20 border border-border/30 rounded-lg px-3 py-1.5 pr-8 text-xs font-mono text-muted-foreground focus:border-primary/50 focus:outline-none transition-colors cursor-pointer hover:border-border/50"
|
||
|
|
>
|
||
|
|
<option value="" disabled>
|
||
|
|
{isPreset ? '' : 'Quick preset…'}
|
||
|
|
</option>
|
||
|
|
{PRESET_GROUPS.map((group) => (
|
||
|
|
<optgroup key={group.label} label={group.label}>
|
||
|
|
{group.items.map((preset) => (
|
||
|
|
<option key={preset.expr} value={preset.expr}>
|
||
|
|
{preset.label}
|
||
|
|
</option>
|
||
|
|
))}
|
||
|
|
</optgroup>
|
||
|
|
))}
|
||
|
|
</select>
|
||
|
|
<ChevronDown className="absolute right-2.5 top-1/2 -translate-y-1/2 w-3 h-3 pointer-events-none text-muted-foreground/40" />
|
||
|
|
</div>
|
||
|
|
);
|
||
|
|
}
|