mirror of
https://github.com/multica-ai/multica.git
synced 2026-07-28 05:46:58 +02:00
Replace the free-form trigger-config form with a structured schedule editor built on an orthogonal cron model: separate frequency, time, and day-of-week/day-of-month dimensions map to and from cron expressions via a dedicated grammar and mapping layer, with validation and a human-readable describe() summary. The grammar suite drives the editor against a combinatorially generated corpus of 51,755 distinct cron expressions - every token form of every field, crossed - each judged against a reference robfig/cron v3 parser. Add a server-side /autopilot/cron-preview endpoint (plus schema and React Query hook) so the editor shows upcoming run times, and echo wildcard-carrying cron lists correctly instead of collapsing them. Supporting pieces: timezone-aware formatting helper, segmented-toggle and debounced-value utilities, a reworked time-input, and refreshed en/ja/ko/zh-Hans locale strings.
32 lines
1.3 KiB
TypeScript
32 lines
1.3 KiB
TypeScript
/** Render an instant on the schedule's clock, not the reader's: an autopilot
|
|
* that says "18:00 (America/Los_Angeles)" must not print its next run as 09:00
|
|
* to a reader in UTC+8. The wording — month name, 12- or 24-hour dial — is the
|
|
* reader's locale.
|
|
*
|
|
* Two things can go wrong, and neither may take a page down:
|
|
* - a zone this browser's ICU data does not carry (an autopilot saved from a
|
|
* newer build, opened in an older packaged desktop one) → local time: wrong by
|
|
* an offset, but still a time of day, which a raw ISO string is not;
|
|
* - a timestamp that is not a date at all (backend drift) → the string itself.
|
|
* Intl throws on an invalid Date, so this is checked before formatting, not
|
|
* caught after: a catch would only run the same throwing call again. */
|
|
export function formatInTimeZone(
|
|
iso: string,
|
|
timeZone: string | undefined,
|
|
locale: string,
|
|
): string {
|
|
const at = new Date(iso);
|
|
if (Number.isNaN(at.getTime())) return iso;
|
|
const options: Intl.DateTimeFormatOptions = {
|
|
month: "short",
|
|
day: "numeric",
|
|
hour: "2-digit",
|
|
minute: "2-digit",
|
|
};
|
|
try {
|
|
return new Intl.DateTimeFormat(locale, { ...options, timeZone }).format(at);
|
|
} catch {
|
|
return new Intl.DateTimeFormat(locale, options).format(at);
|
|
}
|
|
}
|