Adjusted context to hopefully reflect accurate timezones relative to browser.
All checks were successful
Deploy Frontend / deploy (push) Successful in 40s

This commit is contained in:
Bailey Taylor
2025-10-08 08:03:54 +08:00
parent ac2c3ce6a9
commit 67334a65d8
5 changed files with 52 additions and 8 deletions

17
package-lock.json generated
View File

@@ -310,6 +310,7 @@
"resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz",
"integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -353,6 +354,7 @@
"resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.0.tgz",
"integrity": "sha512-XxfOnXFffatap2IyCeJyNov3kiDQWoR08gPUQxvbL7fxKryGBKUZUkG6Hz48DZwVrJSVh9sJboyV1Ds4OW6SgA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.18.3",
"@emotion/babel-plugin": "^11.13.5",
@@ -1201,6 +1203,7 @@
"resolved": "https://registry.npmjs.org/@mui/material/-/material-7.0.2.tgz",
"integrity": "sha512-rjJlJ13+3LdLfobRplkXbjIFEIkn6LgpetgU/Cs3Xd8qINCCQK9qXQIjjQ6P0FXFTPFzEVMj0VgBR1mN+FhOcA==",
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/runtime": "^7.27.0",
"@mui/core-downloads-tracker": "^7.0.2",
@@ -1980,6 +1983,7 @@
"resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz",
"integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
"license": "MIT",
"peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.3",
"json-schema-traverse": "^1.0.0",
@@ -2487,6 +2491,7 @@
"integrity": "sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==",
"devOptional": true,
"license": "MIT",
"peer": true,
"dependencies": {
"undici-types": "~6.19.2"
}
@@ -2508,6 +2513,7 @@
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.12.tgz",
"integrity": "sha512-V6Ar115dBDrjbtXSrS+/Oruobc+qVbbUxDFC1RSbRqLt5SYvxxyIDrSC85RWml54g+jfNeEMZhEj7wW07ONQhA==",
"license": "MIT",
"peer": true,
"dependencies": {
"csstype": "^3.0.2"
}
@@ -2517,6 +2523,7 @@
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz",
"integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==",
"license": "MIT",
"peer": true,
"peerDependencies": {
"@types/react": "^19.0.0"
}
@@ -2575,6 +2582,7 @@
"integrity": "sha512-8C0+jlNJOwQso2GapCVWWfW/rzaq7Lbme+vGUFKE31djwNncIpgXD7Cd4weEsDdkoZDjH0lwwr3QDQFuyrMg9g==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "8.29.0",
"@typescript-eslint/types": "8.29.0",
@@ -3106,6 +3114,7 @@
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz",
"integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==",
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3576,6 +3585,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"caniuse-lite": "^1.0.30001688",
"electron-to-chromium": "^1.5.73",
@@ -4353,6 +4363,7 @@
"integrity": "sha512-jV7AbNoFPAY1EkFYpLq5bslU9NLNO8xnEeQXwErNibVryjk67wHVmddTBilc5srIttJDBrB0eMHKZBFbSIABCw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.12.1",
@@ -4527,6 +4538,7 @@
"integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@rtsao/scc": "^1.1.0",
"array-includes": "^3.1.8",
@@ -6977,6 +6989,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.8",
"picocolors": "^1.1.1",
@@ -7077,6 +7090,7 @@
"resolved": "https://registry.npmjs.org/react/-/react-19.1.0.tgz",
"integrity": "sha512-FS+XFBNvn3GTAWq26joslQgWNoFu08F4kl0J4CgdNKADkdSGXQyTCnKteIAJy96Br6YbpEU1LSzV5dYtjMkMDg==",
"license": "MIT",
"peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -7086,6 +7100,7 @@
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.0.tgz",
"integrity": "sha512-Xs1hdnE+DyKgeHJeJznQmYMIBG3TKIHJJT95Q58nHLSrElKlGQqDTR2HQ9fx5CN/Gk6Vh/kupBTDLU11/nDk/g==",
"license": "MIT",
"peer": true,
"dependencies": {
"scheduler": "^0.26.0"
},
@@ -7966,6 +7981,7 @@
"integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==",
"dev": true,
"license": "MIT",
"peer": true,
"engines": {
"node": ">=12"
},
@@ -8225,6 +8241,7 @@
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz",
"integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==",
"license": "Apache-2.0",
"peer": true,
"bin": {
"tsc": "bin/tsc",
"tsserver": "bin/tsserver"

View File

@@ -32,14 +32,24 @@ const ONLINE_THRESHOLD_MINUTES = 1440;
function getStatusColor(lastCheckedIn: string) {
const lastSeen = parseISO(lastCheckedIn);
// Parse UTC timestamp and treat it correctly as UTC
const lastSeen = new Date(lastCheckedIn + 'Z'); // Add Z to indicate UTC
const minutesAgo = (Date.now() - lastSeen.getTime()) / 1000 / 60;
return minutesAgo < ONLINE_THRESHOLD_MINUTES ? 'green' : 'grey';
}
function formatRelativeTime(lastCheckedIn: string) {
try {
return formatDistanceToNowStrict(parseISO(lastCheckedIn), { addSuffix: true });
// Parse UTC timestamp and treat it correctly as UTC
const lastSeen = new Date(lastCheckedIn + 'Z'); // Add Z to indicate UTC
// Debug: Log what we're getting vs what we should get
//const wrongWay = new Date(lastCheckedIn); // Without Z - treats as local
//console.log(`🕒 DEBUG: "${lastCheckedIn}"`);
//console.log(`🕒 Wrong way (as local): ${wrongWay.toLocaleString()} -> ${formatDistanceToNowStrict(wrongWay, { addSuffix: true })}`);
//console.log(`🕒 Right way (as UTC): ${lastSeen.toLocaleString()} -> ${formatDistanceToNowStrict(lastSeen, { addSuffix: true })}`);
return formatDistanceToNowStrict(lastSeen, { addSuffix: true });
} catch {
return 'Unknown';
}
@@ -56,7 +66,7 @@ const DeviceListSidebar: React.FC<DeviceListSidebarProps> = ({
onTogglePin,
}) => {
const [sortAsc, setSortAsc] = React.useState(true);
const [searchQuery, setSearchQuery] = React.useState('');
const [searchQuery, setSearchQuery] = React.useState('');

View File

@@ -81,11 +81,12 @@ export default function DeviceTableSection({ initialDevices }: Props) {
const formatLastCheckedIn = (isoString: string): string => {
const date = new Date(isoString);
// Parse as UTC by adding 'Z' if not present
const date = new Date(isoString + (isoString.includes('Z') || isoString.includes('+') ? '' : 'Z'));
const now = new Date();
const diffMs = now.getTime() - date.getTime();
const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
const formatted = date.toLocaleString('en-AU', {
day: '2-digit',
month: '2-digit',
@@ -94,7 +95,7 @@ export default function DeviceTableSection({ initialDevices }: Props) {
minute: '2-digit',
hour12: true,
});
return `${formatted} (${diffHours} hours ago)`;
};

View File

@@ -127,7 +127,16 @@ export default function DevicesClient() {
const formatBootTime = (timestamp: string) => {
try {
const parsed = parseISO(timestamp);
// Handle timestamp - could be UTC or already have timezone info
let parsed: Date;
if (timestamp.includes('+') || timestamp.endsWith('Z')) {
// Already has timezone info, parse directly
parsed = new Date(timestamp);
} else {
// Assume UTC, add Z to indicate UTC
parsed = new Date(timestamp + 'Z');
}
const formattedDate = format(parsed, 'EEEE do MMMM yyyy');
const relative = formatDistanceToNowStrict(parsed, { addSuffix: true });
return `${formattedDate} (${relative})`;

View File

@@ -7,6 +7,13 @@ import { DetailedDevice } from '@/types/devices';
import { disableConsoleInProd } from '@/lib/disableConsole';
disableConsoleInProd();
// Helper function to convert UTC timestamps to local time
const convertUtcToLocal = (utcString: string | null): string | null => {
if (!utcString) return null;
// Add 'Z' to indicate it's UTC, then convert to local time
return new Date(utcString + 'Z').toLocaleString();
};
interface DriveInfo {
@@ -125,7 +132,7 @@ export const DeviceProvider = ({
console.log('✅ Software fetched:', softwareRes.data);
console.groupEnd();
// STEP 1: Set basic data
// STEP 1: Set basic data (keep original UTC timestamps for calculations)
setDevices(devicesRes.data.devices);
setDeviceVulns(devicesRes.data.vulnerabilitiesByDevice);
setCachedSoftware(softwareRes.data);