Cookbook scheduler: reuse the standard calendar event card + auto-create Cookbook calendar

Drop the custom Schedule modal in favor of opening the calendar's existing event-creation form pre-filled with the model's name + cookbook YAML in the description. The user lands in the same event editor they already know from regular calendar use, just pointed at the auto-created "Cookbook" calendar.

Backend:
  - POST /api/cookbook/schedule/ensure-calendar — idempotent: creates a calendar named "Cookbook" if one doesn't exist for the current user, saves its href into cookbook_schedule_calendar_href, flips cookbook_scheduler_enabled on. Verifies the saved href against /api/calendar/calendars on every call so a manually-deleted calendar self-heals.

Frontend:
  - calendar.js: expose window.cookbookOpenScheduleForm(draft) which opens the calendar modal (if not open), calls _showEventForm, then pre-fills summary / description / rrule / calendar dropdown. Force-expands the "Add details" section so the user can see which calendar it's heading into.
  - cookbookSchedule.js: Schedule-button click now calls ensure-calendar, builds the cookbook: YAML block, and routes to window.cookbookOpenScheduleForm instead of openModal(). The legacy custom modal stays as a fallback for the case where calendar.js hasn't loaded.

UX tweak:
  - cookbookServe.js: replace the standalone "Schedule…" text button with a small icon-only button (clock SVG) glued to the right edge of Launch. The pair forms one visual unit — Launch on the left, schedule-now on the right — sharing a thin divider. CSS handles the rounded corners + divider.
This commit is contained in:
pewdiepie-archdaemon
2026-06-05 02:52:07 +09:00
parent 4ed48baf68
commit b98ee04e2f
5 changed files with 178 additions and 11 deletions
+48 -6
View File
@@ -201,16 +201,18 @@
}
// Click-binding: any .hwfit-serve-schedule button inside a serve
// panel opens the modal with the panel's current config.
document.addEventListener("click", (e) => {
// panel routes to the STANDARD calendar event-creation form, with the
// model's name pre-filled as the event title and a `cookbook:` YAML
// block in the description. The event lands on the auto-created
// "Cookbook" calendar so the reconciler picks it up. The custom
// openModal() above is kept as a fallback in case the calendar
// module hasn't loaded.
document.addEventListener("click", async (e) => {
const btn = e.target.closest && e.target.closest(".hwfit-serve-schedule");
if (!btn) return;
e.preventDefault();
e.stopPropagation();
// Reach into the serve panel to read current config. cookbookServe.js
// stores the active config on the panel root via data attributes
// that we read here without coupling further.
const panel = btn.closest("[data-cookbook-serve-panel]") || btn.closest(".doclib-card-expanded") || btn.closest(".doclib-card");
const ds = panel ? panel.dataset || {} : {};
const config = {
@@ -221,7 +223,47 @@
host: ds.host || "",
port: ds.port ? Number(ds.port) : undefined,
};
openModal(config);
// Ensure the Cookbook calendar exists and is configured. Returns
// the href to feed into the event form.
btn.disabled = true;
let calHref = "";
try {
const r = await fetch("/api/cookbook/schedule/ensure-calendar", {
method: "POST", credentials: "same-origin",
});
if (r.ok) {
const data = await r.json();
calHref = data.href || "";
}
} catch (_) {}
btn.disabled = false;
// Build the cookbook: YAML block that goes into the event description.
// The reconciler parses this to know HOW to launch when the window
// opens. If only the title is set, the reconciler title-matches
// against saved presets.
const yamlLines = ["cookbook:"];
for (const k of ["preset", "repo_id", "cmd", "host", "port"]) {
if (config[k]) yamlLines.push(` ${k}: ${config[k]}`);
}
if (yamlLines.length === 1 && config.title) {
yamlLines.push(` preset: ${config.title}`);
}
const draft = {
summary: config.title,
description: yamlLines.join("\n"),
rrule: "FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR", // default: weekdays
calendar_href: calHref,
};
if (typeof window.cookbookOpenScheduleForm === "function") {
window.cookbookOpenScheduleForm(draft);
} else {
// Fallback to the legacy in-house modal if the calendar module
// hasn't loaded for some reason.
openModal(config);
}
});
// Reveal Schedule buttons once we confirm the feature is enabled.