* feat(snapshot): autosave UX — YES/NO modal when newer + 24h local timestamps Two snapshot-UX threads in one slice: 1. **24-hour timestamps with relative-recent tier** in the Load dialog and snapshot status tooltip. The previous `en-US` 12-hour format produced "12:56 AM" for timestamps just past midnight, which read visually like noon. Now: `just now` / `12 min ago` / `today 14:32` / `yesterday 23:58` / `May 6 14:32`. Centralized in a new `format_time.js` helper so future surfaces stay aligned. 2. **YES/NO choice when an auto-save is newer than the saved version.** Click any preset row in Snapshot → Load and, if the matching `<preset>_autosave/periodic.json` is more recent than the named save's mtime, the confirm dialog upgrades from "Load preset" to a YES/NO question with both timestamps shown side-by-side. YES loads the auto-save, NO loads the older deliberate save (the row clicked), Esc cancels. Standard pre-load auto-save protection still runs on either path. Server-side `/koolook/presets/list` augments root rows with `latestAutosaveMtime` via one extra `stat()` per row — no file read, cheap on large libraries. Aligns the system with the user's mental model: named saves stay deliberate (only updated on Save / Quick Save), and the auto-save is treated as a recovery copy the system surfaces at decision time rather than a parallel save the user has to remember to check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(snapshot): restore-from-auto-save baselines as "auto-saved", not "saved" `doAutosaveRestore` was calling `markStateSaved()` after a successful restore, which baselined the *named-save* fingerprint to the auto-save's content. The dot turned green even though `<preset>.json` on disk still held the OLDER deliberate save — blurring the deliberate-save model the Path C UX deliberately reinforces (named saves only change on Save / Quick Save). New `markStateAutosaved()` export in `snapshot.js` baselines the *periodic* fingerprint instead, so the dot reads "auto-saved" (blue) until the user explicitly commits the restored state via Quick Save or Save. Threaded through `tree.js` → `showLoadSnapshotDialog` via the existing dependency-injection pattern. Toast message also updated to nudge: `Restored auto-save of "Foo" — Quick Save to commit to the named file.` Fixes the regression flagged on the PR #111 review. Applies to BOTH restore call sites (the new YES path AND the long-existing Recovery disclosure) since they share the helper. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
54 lines
2.4 KiB
JavaScript
54 lines
2.4 KiB
JavaScript
// SPDX-FileCopyrightText: 2025-2026 Kforge Labs <https://github.com/malkuthro/ComfyUI-Koolook>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
// =============================================================================
|
|
// Local-timezone timestamp formatter — combined relative + 24-hour absolute.
|
|
//
|
|
// Output cases (in priority order):
|
|
// • <1 min ago → "just now"
|
|
// • <60 min ago → "12 min ago"
|
|
// • same calendar day (local) → "today 14:32"
|
|
// • previous day → "yesterday 23:58"
|
|
// • else, current year → "May 6 14:32"
|
|
// • else → "May 6 2025 14:32"
|
|
//
|
|
// Why 24-hour: the previous `en-US` 12-hour format produced "12:56 AM" for
|
|
// timestamps just past midnight, which reads visually like noon to most
|
|
// people (the US "12 AM = midnight" convention is a known UX trap).
|
|
// Manually building HH:MM from `getHours()` / `getMinutes()` sidesteps the
|
|
// `hour12: false` quirk in some locales (e.g. en-US emitting "24:00").
|
|
//
|
|
// Why "today" / "yesterday" tier: makes the most-relevant cases (recent
|
|
// snapshots, recent autosaves) read at a glance without making the eye
|
|
// parse a full date.
|
|
// =============================================================================
|
|
|
|
const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
|
|
|
|
function _hhmm(d) {
|
|
return String(d.getHours()).padStart(2, "0") + ":" + String(d.getMinutes()).padStart(2, "0");
|
|
}
|
|
|
|
export function formatLocalStamp(d, now = new Date()) {
|
|
if (!(d instanceof Date) || isNaN(d.getTime())) return "";
|
|
const diffMs = now.getTime() - d.getTime();
|
|
const diffMin = Math.floor(diffMs / 60000);
|
|
// Future timestamps (clock skew, browser/server drift): fall through to
|
|
// absolute formatting rather than emitting "-3 min ago".
|
|
if (diffMin >= 0 && diffMin < 1) return "just now";
|
|
if (diffMin >= 1 && diffMin < 60) return diffMin + " min ago";
|
|
|
|
const time = _hhmm(d);
|
|
const startOfToday = new Date(now);
|
|
startOfToday.setHours(0, 0, 0, 0);
|
|
const startOfYesterday = new Date(startOfToday);
|
|
startOfYesterday.setDate(startOfYesterday.getDate() - 1);
|
|
|
|
if (d >= startOfToday) return "today " + time;
|
|
if (d >= startOfYesterday) return "yesterday " + time;
|
|
|
|
const datePart = MONTHS[d.getMonth()] + " " + d.getDate();
|
|
const yearPart = d.getFullYear() !== now.getFullYear() ? " " + d.getFullYear() : "";
|
|
return datePart + yearPart + " " + time;
|
|
}
|