Files
windmill/frontend/src/lib/components/TimeAgo.svelte
T
Guilhemandclaude[bot] 7385726741 fix(frontend): Improve flow detail page (#7647)
* improve flow detail page

* Do not display seconds for last edit

* expand graph when possible

* nit

* make flowGraph min height reactive

* Add flow graph tab when chat mode enabled

* improve script detail layout

* nit

* nit

* Update frontend/src/lib/components/TimeAgo.svelte

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Update frontend/src/lib/components/TimeAgo.svelte

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Update frontend/src/lib/components/TimeAgo.svelte

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* Update frontend/src/lib/components/TimeAgo.svelte

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>

* nit

---------

Co-authored-by: claude[bot] <209825114+claude[bot]@users.noreply.github.com>
2026-01-22 15:55:18 +00:00

143 lines
3.5 KiB
Svelte

<script lang="ts">
import { getDbClockNow } from '$lib/forLater'
import { displayDate } from '$lib/utils'
import { onMount, untrack } from 'svelte'
interface Props {
date: string
agoOnlyIfRecent?: boolean
noDate?: boolean
isRecent?: boolean
noSeconds?: boolean
}
let {
date,
agoOnlyIfRecent = false,
noDate = false,
isRecent = $bindable(true),
noSeconds = false
}: Props = $props()
let computedTimeAgo: string | undefined = $state(undefined)
let interval
onMount(() => {
// Update every minute for noSeconds mode, every second for regular mode
const intervalMs = noSeconds ? 60000 : 1000
interval = setInterval(() => {
computeDate()
if (!isRecent) {
clearInterval(interval)
interval = undefined
}
}, intervalMs)
// Add explicit cleanup
return () => {
interval && clearInterval(interval)
}
})
async function computeDate() {
computedTimeAgo = await displayDaysAgo(date)
}
function isToday(someDate: Date): boolean {
const today = getDbClockNow()
return (
someDate.getDate() == today.getDate() &&
someDate.getMonth() == today.getMonth() &&
someDate.getFullYear() == today.getFullYear()
)
}
function daysAgo(someDate: Date): number {
const today = getDbClockNow()
return Math.floor((today.getTime() - someDate.getTime()) / 86400000)
}
function secondsAgo(date: Date) {
return Math.max(0, Math.floor((getDbClockNow().getTime() - date.getTime()) / 1000))
}
function minutesAgo(date: Date) {
return Math.floor(secondsAgo(date) / 60)
}
function hoursAgo(date: Date) {
return Math.floor(minutesAgo(date) / 60)
}
function isLessThanMonthAgo(date: Date): boolean {
const today = getDbClockNow()
const monthAgo = new Date(today)
monthAgo.setMonth(monthAgo.getMonth() - 1)
return date.getTime() >= monthAgo.getTime()
}
async function displayDaysAgo(dateString: string): Promise<string> {
const date = new Date(dateString)
// New noSeconds mode
if (noSeconds) {
const mins = minutesAgo(date)
const hours = hoursAgo(date)
const dAgo = daysAgo(date)
// If less than an hour ago -> "x min ago"
if (mins < 60) {
return `${mins} min${mins !== 1 ? 's' : ''} ago`
}
// If less than a day ago -> "x hours ago"
else if (hours < 24) {
isRecent = false
return `${hours} hour${hours !== 1 ? 's' : ''} ago`
}
// If less than a month ago -> "x days ago"
else if (isLessThanMonthAgo(date)) {
return `${dAgo} day${dAgo !== 1 ? 's' : ''} ago`
}
// If more than a month ago -> "the mm/dd/year"
else {
const month = (date.getMonth() + 1).toString().padStart(2, '0')
const day = date.getDate().toString().padStart(2, '0')
const year = date.getFullYear()
return `the ${month}/${day}/${year}`
}
}
// Original mode
const nbSecondsAgo = secondsAgo(date)
if (nbSecondsAgo < 600) {
return `${nbSecondsAgo}s ago`
} else if (isToday(date)) {
isRecent = false
return `today at ${date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`
} else {
isRecent = false
let dAgo = daysAgo(date)
if (dAgo == 0) {
return `yesterday at ${date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' })}`
} else if (dAgo > 7 && !noDate) {
return `${dAgo + 1} days ago at ${date.toLocaleTimeString([], {
hour: '2-digit',
minute: '2-digit'
})}`
} else {
return displayDate(dateString, false, !noDate)
}
}
}
$effect(() => {
date && untrack(() => computeDate())
})
</script>
{#if computedTimeAgo && (!agoOnlyIfRecent || isRecent)}
{computedTimeAgo}
{:else}
{displayDate(date)}
{/if}