From 1adb8f733bd70f2a1fc029e07b4ffaa22efb02f5 Mon Sep 17 00:00:00 2001 From: Aditya Thebe Date: Fri, 24 Apr 2026 20:54:23 +0545 Subject: [PATCH 1/3] feat: QoL tooltip for Age component while we were debugging timestamps for notification, it was immediately apparent what timezone those timestamps were in. --- src/ui/Age/Age.tsx | 107 ++++++++++++++++++++++++++++----------------- 1 file changed, 67 insertions(+), 40 deletions(-) diff --git a/src/ui/Age/Age.tsx b/src/ui/Age/Age.tsx index 9d15554640..f6fdc12bfb 100644 --- a/src/ui/Age/Age.tsx +++ b/src/ui/Age/Age.tsx @@ -2,7 +2,12 @@ import clsx from "clsx"; import dayjs from "dayjs"; import LocalizedFormat from "dayjs/plugin/localizedFormat"; import TimezonePlugin from "dayjs/plugin/timezone"; -import { Tooltip } from "react-tooltip"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger +} from "@flanksource-ui/components/ui/tooltip"; import { isEmpty } from "../../utils/date"; import { datetimePreferenceAtom, @@ -48,22 +53,22 @@ export default function Age({ datetimePreference, suffix ); + + if (datetimePreference === "timestamp") { + return {formattedDate}; + } + return ( - <> - - {formattedDate} - - - {datetimePreference !== "timestamp" && ( - - )} - + + + + {formattedDate} + + + {getFullTimestampTooltip(_from)} + + + ); } @@ -73,34 +78,41 @@ export default function Age({ if (duration.asMilliseconds() < 1000) { return ( - <> - - {duration.asMilliseconds()}ms - - - + + + + {duration.asMilliseconds()}ms + + + {getFullTimestampTooltip(_from)} + + + ); } return ( - <> - - {_from.local().to(_to, !suffix)} - - - + + + + + {_from.local().to(_to, !suffix)} + + + +
+
+
From
+ {getFullTimestampTooltip(_from)} +
+
+
To
+ {getFullTimestampTooltip(_to)} +
+
+
+
+
); } @@ -111,6 +123,21 @@ export function formatDateForTooltip( return formatDayjs(datetime, displayTimezone, "timestamp", false); } +function getFullTimestampTooltip(datetime: dayjs.Dayjs) { + const browserTimezoneOffset = datetime.local().format("Z"); + const browserTimestamp = datetime.local().format("YYYY-MM-DD HH:mm:ss"); + const utcTimestamp = datetime.tz("UTC").format("YYYY-MM-DD HH:mm:ss"); + + return ( +
+
+ {browserTimestamp} {browserTimezoneOffset} +
+
{utcTimestamp} UTC
+
+ ); +} + export function formatDayjs( datetime: dayjs.Dayjs, displayTimezone: string, From f6b324cbb9052f4c87304d37ba788685ead6a083 Mon Sep 17 00:00:00 2001 From: Aditya Thebe Date: Fri, 24 Apr 2026 21:07:31 +0545 Subject: [PATCH 2/3] show ago as well --- src/ui/Age/Age.tsx | 53 ++++++++++++++++++++++++++++++++-------------- 1 file changed, 37 insertions(+), 16 deletions(-) diff --git a/src/ui/Age/Age.tsx b/src/ui/Age/Age.tsx index f6fdc12bfb..8840b765b5 100644 --- a/src/ui/Age/Age.tsx +++ b/src/ui/Age/Age.tsx @@ -64,8 +64,8 @@ export default function Age({ {formattedDate} - - {getFullTimestampTooltip(_from)} + +
@@ -83,8 +83,8 @@ export default function Age({ {duration.asMilliseconds()}ms - - {getFullTimestampTooltip(_from)} + +
@@ -99,15 +99,19 @@ export default function Age({ {_from.local().to(_to, !suffix)} - -
+ +
-
From
- {getFullTimestampTooltip(_from)} +
+ From +
+
-
-
To
- {getFullTimestampTooltip(_to)} +
+
+ To +
+
@@ -123,17 +127,34 @@ export function formatDateForTooltip( return formatDayjs(datetime, displayTimezone, "timestamp", false); } -function getFullTimestampTooltip(datetime: dayjs.Dayjs) { +function FullTimestampTooltip({ datetime }: { datetime: dayjs.Dayjs }) { + return ( +
+ +
+ ); +} + +function FullTimestampRows({ datetime }: { datetime: dayjs.Dayjs }) { const browserTimezoneOffset = datetime.local().format("Z"); const browserTimestamp = datetime.local().format("YYYY-MM-DD HH:mm:ss"); const utcTimestamp = datetime.tz("UTC").format("YYYY-MM-DD HH:mm:ss"); return ( -
-
- {browserTimestamp} {browserTimezoneOffset} +
+
+ + {browserTimezoneOffset} + + {browserTimestamp} +
+
+ UTC + {utcTimestamp} +
+
+ {datetime.fromNow()}
-
{utcTimestamp} UTC
); } From 1960e5038b1de48e598fc678f5afc18a705b9101 Mon Sep 17 00:00:00 2001 From: Aditya Thebe Date: Fri, 24 Apr 2026 21:10:38 +0545 Subject: [PATCH 3/3] improve relative time format --- src/ui/Age/Age.tsx | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/ui/Age/Age.tsx b/src/ui/Age/Age.tsx index 8840b765b5..459fe24962 100644 --- a/src/ui/Age/Age.tsx +++ b/src/ui/Age/Age.tsx @@ -142,6 +142,7 @@ function FullTimestampRows({ datetime }: { datetime: dayjs.Dayjs }) { return (
+
{formatRelativeLong(datetime)}
{browserTimezoneOffset} @@ -152,13 +153,35 @@ function FullTimestampRows({ datetime }: { datetime: dayjs.Dayjs }) { UTC {utcTimestamp}
-
- {datetime.fromNow()} -
); } +function formatRelativeLong(datetime: dayjs.Dayjs) { + const now = dayjs(); + const diffSeconds = datetime.diff(now, "second"); + const absSeconds = Math.abs(diffSeconds); + + const units: Array<{ unit: Intl.RelativeTimeFormatUnit; seconds: number }> = [ + { unit: "year", seconds: 365 * 24 * 60 * 60 }, + { unit: "month", seconds: 30 * 24 * 60 * 60 }, + { unit: "day", seconds: 24 * 60 * 60 }, + { unit: "hour", seconds: 60 * 60 }, + { unit: "minute", seconds: 60 }, + { unit: "second", seconds: 1 } + ]; + + const selected = + units.find(({ seconds }) => absSeconds >= seconds) ?? + units[units.length - 1]; + const value = Math.round(diffSeconds / selected.seconds); + + return new Intl.RelativeTimeFormat("en", { + numeric: "always", + style: "long" + }).format(value, selected.unit); +} + export function formatDayjs( datetime: dayjs.Dayjs, displayTimezone: string,