feat(channel): add auto-schedule feature to channels with background scheduler

This commit is contained in:
2026-03-13 02:27:27 +01:00
parent dfd8f52a53
commit 1fc473342d
14 changed files with 161 additions and 6 deletions

View File

@@ -72,6 +72,7 @@ const channelFormSchema = z.object({
cooldown_generations: z.number().int().min(0).nullable().optional(),
min_available_ratio: z.number().min(0, "Must be ≥ 0").max(1, "Must be ≤ 1"),
}),
auto_schedule: z.boolean(),
});
type FieldErrors = Record<string, string | undefined>;
@@ -676,6 +677,7 @@ interface EditChannelSheetProps {
timezone: string;
schedule_config: { blocks: ProgrammingBlock[] };
recycle_policy: RecyclePolicy;
auto_schedule: boolean;
},
) => void;
isPending: boolean;
@@ -699,6 +701,7 @@ export function EditChannelSheet({
cooldown_generations: null,
min_available_ratio: 0.1,
});
const [autoSchedule, setAutoSchedule] = useState(false);
const [selectedBlockId, setSelectedBlockId] = useState<string | null>(null);
const [fieldErrors, setFieldErrors] = useState<FieldErrors>({});
@@ -709,6 +712,7 @@ export function EditChannelSheet({
setTimezone(channel.timezone);
setBlocks(channel.schedule_config.blocks);
setRecyclePolicy(channel.recycle_policy);
setAutoSchedule(channel.auto_schedule);
setSelectedBlockId(null);
setFieldErrors({});
}
@@ -719,7 +723,7 @@ export function EditChannelSheet({
if (!channel) return;
const result = channelFormSchema.safeParse({
name, description, timezone, blocks, recycle_policy: recyclePolicy,
name, description, timezone, blocks, recycle_policy: recyclePolicy, auto_schedule: autoSchedule,
});
if (!result.success) {
@@ -734,6 +738,7 @@ export function EditChannelSheet({
timezone,
schedule_config: { blocks },
recycle_policy: recyclePolicy,
auto_schedule: autoSchedule,
});
};
@@ -799,6 +804,24 @@ export function EditChannelSheet({
className="w-full resize-none rounded-md border border-zinc-700 bg-zinc-800 px-3 py-2 text-sm text-zinc-100 placeholder:text-zinc-600 focus:border-zinc-500 focus:outline-none"
/>
</Field>
<label className="flex items-center justify-between gap-3 cursor-pointer rounded-md border border-zinc-700 bg-zinc-800/50 px-3 py-2.5">
<div>
<p className="text-sm text-zinc-200">Auto-generate schedule</p>
<p className="text-[11px] text-zinc-600">Automatically regenerate when the schedule is about to expire</p>
</div>
<button
type="button"
role="switch"
aria-checked={autoSchedule}
onClick={() => setAutoSchedule((v) => !v)}
className={`relative inline-flex h-5 w-9 shrink-0 rounded-full border-2 border-transparent transition-colors focus:outline-none ${autoSchedule ? "bg-zinc-300" : "bg-zinc-700"}`}
>
<span
className={`pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow-sm transition-transform ${autoSchedule ? "translate-x-4" : "translate-x-0"}`}
/>
</button>
</label>
</section>
{/* Programming blocks */}