Add a Date & Time setting and fix inconsistent date formats app-wide
Different tables used different date formats: Servers & Tasks used a fixed "YYYY-MM-DD HH:mm:ss" (24h), while Audit Log, DNS, Integrations (Tailscale/Semaphore), and Users called plain .toLocaleString() with no options, which renders using the browser's own locale — different per browser/OS, and inconsistent with the other pages' fixed format. - New Settings -> Date & Time page: pick date order (YYYY-MM-DD, DD/MM/YYYY, MM/DD/YYYY) and 12h vs 24h clock, with a live preview. - utils/date.ts's formatDateTime() now reads these settings instead of being hardcoded to sv-SE/24h; the setting is fetched once at app startup (alongside /api/me) via a new non-secret GET /api/settings/display (any signed-in user, same rationale as the badge-color endpoints) and applied immediately on save too, without needing a page reload. - Switched every remaining raw new Date(...).toLocaleString() call (Audit Log, DNS zone sync time, Tailscale/Semaphore last-seen, Users' last login) over to the shared formatter, so every table now renders dates identically. Verified the formatter's date-order x 12h logic against all six combinations plus the midnight/noon 12h edge cases, and the settings endpoints end-to-end (defaults, partial updates, validation rejection, audit logging) against the real dev server. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f7357141eb
commit
f92f8de96e
12 files changed
+206
-17
No files matched your search
+50
-10
@@ -1,12 +1,52 @@
|
||||
/** Formats a date as "YYYY-MM-DD HH:mm:ss" on a 24-hour clock. */
|
||||
import type { DateFormat, TimeFormat } from "../api/client";
|
||||
|
||||
export interface DateTimeSettings {
|
||||
dateFormat: DateFormat;
|
||||
timeFormat: TimeFormat;
|
||||
}
|
||||
|
||||
let current: DateTimeSettings = { dateFormat: "ymd", timeFormat: "24h" };
|
||||
|
||||
/** Called once at app startup (and whenever the setting is changed) so every formatDateTime() call site picks it up without prop-drilling. */
|
||||
export function setDateTimeSettings(settings: DateTimeSettings): void {
|
||||
current = settings;
|
||||
}
|
||||
|
||||
function pad(n: number): string {
|
||||
return String(n).padStart(2, "0");
|
||||
}
|
||||
|
||||
/** Formats a date using the app-wide date/time display settings (defaults to "YYYY-MM-DD HH:mm:ss" on a 24-hour clock). */
|
||||
export function formatDateTime(date: Date): string {
|
||||
return date.toLocaleString("sv-SE", {
|
||||
year: "numeric",
|
||||
month: "2-digit",
|
||||
day: "2-digit",
|
||||
hour: "2-digit",
|
||||
minute: "2-digit",
|
||||
second: "2-digit",
|
||||
hour12: false,
|
||||
});
|
||||
const year = date.getFullYear();
|
||||
const month = pad(date.getMonth() + 1);
|
||||
const day = pad(date.getDate());
|
||||
|
||||
let datePart: string;
|
||||
switch (current.dateFormat) {
|
||||
case "dmy":
|
||||
datePart = `${day}/${month}/${year}`;
|
||||
break;
|
||||
case "mdy":
|
||||
datePart = `${month}/${day}/${year}`;
|
||||
break;
|
||||
case "ymd":
|
||||
default:
|
||||
datePart = `${year}-${month}-${day}`;
|
||||
break;
|
||||
}
|
||||
|
||||
const minutes = pad(date.getMinutes());
|
||||
const seconds = pad(date.getSeconds());
|
||||
let timePart: string;
|
||||
if (current.timeFormat === "12h") {
|
||||
const hour24 = date.getHours();
|
||||
const period = hour24 >= 12 ? "PM" : "AM";
|
||||
const hour12 = hour24 % 12 || 12;
|
||||
timePart = `${hour12}:${minutes}:${seconds} ${period}`;
|
||||
} else {
|
||||
timePart = `${pad(date.getHours())}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
return `${datePart} ${timePart}`;
|
||||
}
|
||||
Reference in new issue
Block a user