mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-07-28 06:39:01 +03:00
Miscellaneous fixes (0.18 beta) (#23809)
* fix calendars greying out the current day after midnight The cutoff for disabling future days was computed with setHours(getHours() + 24, -1, 0, 0), which is not "24 hours from now" but tomorrow at the current hour minus one minute. Between 00:00 and 00:59 that lands back on today, and react-day-picker matches range matchers by calendar day, so today itself was disabled, leaving the export dialog's start time stuck on the previous day. TimezoneAwareCalendar also added the configured timezone's raw UTC offset instead of its difference from the browser's, widening the broken window to several hours in negative-offset zones and letting future days through in positive-offset ones. Derive the current date in the display timezone once, then build each cutoff in the space its calendar uses: ReviewActivityCalendar passes timeZone to react-day-picker so its day cells are TZDate and need a real instant, while TimezoneAwareCalendar is handed pre-shifted dates and needs a local one. Also corrects the today prop, which was off by the browser's offset, and the truthiness check that treated a configured timezone of UTC as unset. * pin react-zoom-pan-pinch to 3.6.1 3.7.0 attaches a ResizeObserver to the transform wrapper and content unconditionally and clamps the pan position into the current bounds on every resize. The history player hides itself with display:none while scrubbing and while a new hour of recordings loads, so the observer measures it as 0x0, collapses the bounds to zero, and snaps a zoomed in view back to the top left corner. Zoom scale survives, only the position is lost. That observer was only created for centerOnInit in 3.4.4 through 3.6.1 and 4.0.0 reverted it again, so 3.7.0 is the only affected release. The caret is what picked it up during the React 19 upgrade, so pin the version exactly. Reported in #23807
This commit is contained in:
Generated
+4
-4
@@ -73,7 +73,7 @@
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-router-dom": "^6.30.3",
|
||||
"react-swipeable": "^7.0.2",
|
||||
"react-zoom-pan-pinch": "^3.7.0",
|
||||
"react-zoom-pan-pinch": "3.6.1",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"scroll-into-view-if-needed": "^3.1.0",
|
||||
"sonner": "^2.0.7",
|
||||
@@ -12354,9 +12354,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/react-zoom-pan-pinch": {
|
||||
"version": "3.7.0",
|
||||
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.7.0.tgz",
|
||||
"integrity": "sha512-UmReVZ0TxlKzxSbYiAj+LeGRW8s8LraAFTXRAxzMYnNRgGPsxCudwZKVkjvGmjtx7SW/hZamt69NUmGf4xrkXA==",
|
||||
"version": "3.6.1",
|
||||
"resolved": "https://registry.npmjs.org/react-zoom-pan-pinch/-/react-zoom-pan-pinch-3.6.1.tgz",
|
||||
"integrity": "sha512-SdPqdk7QDSV7u/WulkFOi+cnza8rEZ0XX4ZpeH7vx3UZEg7DoyuAy3MCmm+BWv/idPQL2Oe73VoC0EhfCN+sZQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8",
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@
|
||||
"react-markdown": "^9.0.1",
|
||||
"react-router-dom": "^6.30.3",
|
||||
"react-swipeable": "^7.0.2",
|
||||
"react-zoom-pan-pinch": "^3.7.0",
|
||||
"react-zoom-pan-pinch": "3.6.1",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"scroll-into-view-if-needed": "^3.1.0",
|
||||
"sonner": "^2.0.7",
|
||||
|
||||
@@ -20,6 +20,26 @@ function formatCalendarDay(day: Date): string {
|
||||
return `${y}-${m}-${d}`;
|
||||
}
|
||||
|
||||
function getTodayInTimezone(timezone?: string): {
|
||||
year: number;
|
||||
month: number;
|
||||
day: number;
|
||||
offset: number;
|
||||
} {
|
||||
const now = new Date();
|
||||
const offset = Math.round(getUTCOffset(now, timezone));
|
||||
|
||||
// shifting by the offset makes the UTC getters read the timezone's wall clock
|
||||
const wallClock = new Date(now.getTime() + offset * 60000);
|
||||
|
||||
return {
|
||||
year: wallClock.getUTCFullYear(),
|
||||
month: wallClock.getUTCMonth(),
|
||||
day: wallClock.getUTCDate(),
|
||||
offset,
|
||||
};
|
||||
}
|
||||
|
||||
type ReviewActivityCalendarProps = {
|
||||
reviewSummary?: ReviewSummary;
|
||||
recordingsSummary?: RecordingsSummary;
|
||||
@@ -37,12 +57,14 @@ export default function ReviewActivityCalendar({
|
||||
const [weekStartsOn] = useUserPersistence("weekStartsOn", 0);
|
||||
|
||||
const disabledDates = useMemo(() => {
|
||||
const tomorrow = new Date();
|
||||
tomorrow.setHours(tomorrow.getHours() + 24, -1, 0, 0);
|
||||
const future = new Date();
|
||||
future.setFullYear(tomorrow.getFullYear() + 10);
|
||||
return { from: tomorrow, to: future };
|
||||
}, []);
|
||||
// day cells are TZDate in `timezone`, so the cutoff must be a real instant
|
||||
const { year, month, day, offset } = getTodayInTimezone(timezone);
|
||||
// midday: ranges match by calendar day, so this dodges DST edges
|
||||
const from = new Date(Date.UTC(year, month, day + 1, 12) - offset * 60000);
|
||||
const to = new Date(from);
|
||||
to.setFullYear(from.getFullYear() + 10);
|
||||
return { from, to };
|
||||
}, [timezone]);
|
||||
|
||||
const modifiers = useMemo(() => {
|
||||
const recordingsSet = new Set<string>();
|
||||
@@ -182,48 +204,25 @@ export function TimezoneAwareCalendar({
|
||||
};
|
||||
}, [recordingsSummary]);
|
||||
|
||||
const timezoneOffset = useMemo(
|
||||
() =>
|
||||
timezone ? Math.round(getUTCOffset(new Date(), timezone)) : undefined,
|
||||
// callers pre-shift dates so the local clock reads `timezone`, so boundaries
|
||||
// are built in local time rather than as instants
|
||||
const { year, month, day } = useMemo(
|
||||
() => getTodayInTimezone(timezone),
|
||||
[timezone],
|
||||
);
|
||||
|
||||
const disabledDates = useMemo(() => {
|
||||
const tomorrow = new Date();
|
||||
// midday: ranges match by calendar day, so this dodges DST edges
|
||||
const from = new Date(year, month, day + 1, 12);
|
||||
const to = new Date(from);
|
||||
to.setFullYear(from.getFullYear() + 10);
|
||||
return { from, to };
|
||||
}, [year, month, day]);
|
||||
|
||||
if (timezoneOffset) {
|
||||
tomorrow.setHours(
|
||||
tomorrow.getHours() + 24,
|
||||
tomorrow.getMinutes() + timezoneOffset,
|
||||
0,
|
||||
0,
|
||||
);
|
||||
} else {
|
||||
tomorrow.setHours(tomorrow.getHours() + 24, -1, 0, 0);
|
||||
}
|
||||
|
||||
const future = new Date();
|
||||
future.setFullYear(tomorrow.getFullYear() + 10);
|
||||
return { from: tomorrow, to: future };
|
||||
}, [timezoneOffset]);
|
||||
|
||||
const today = useMemo(() => {
|
||||
if (!timezoneOffset) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const date = new Date();
|
||||
const utc = Date.UTC(
|
||||
date.getUTCFullYear(),
|
||||
date.getUTCMonth(),
|
||||
date.getUTCDate(),
|
||||
date.getUTCHours(),
|
||||
date.getUTCMinutes(),
|
||||
date.getUTCSeconds(),
|
||||
);
|
||||
const todayUtc = new Date(utc);
|
||||
todayUtc.setMinutes(todayUtc.getMinutes() + timezoneOffset, 0, 0);
|
||||
return todayUtc;
|
||||
}, [timezoneOffset]);
|
||||
const today = useMemo(
|
||||
() => new Date(year, month, day, 12),
|
||||
[year, month, day],
|
||||
);
|
||||
|
||||
return (
|
||||
<Calendar
|
||||
|
||||
Reference in New Issue
Block a user