fix(studio): human readable formatting for total consumed times (#39011)

* fix: human readable formatting for total consumed times

* chore: accidental turkish spelling of performance

* fix: imports for renamed utils file

* feat: add tests for formatDuration util
This commit is contained in:
kemal.earth
2025-09-25 15:35:54 +01:00
committed by GitHub
parent e01699cce5
commit 90976b7988
4 changed files with 56 additions and 24 deletions

View File

@@ -11,6 +11,7 @@ import {
QUERY_PERFORMANCE_COLUMNS,
QUERY_PERFORMANCE_REPORT_TYPES,
} from './QueryPerformance.constants'
import { formatDuration } from './QueryPerformance.utils'
interface QueryDetailProps {
reportType: QUERY_PERFORMANCE_REPORT_TYPES
@@ -41,22 +42,6 @@ export const QueryDetail = ({ selectedRow, onClickViewSuggestion }: QueryDetailP
const [isExpanded, setIsExpanded] = useState(false)
const formatDuration = (seconds: number) => {
const dur = dayjs.duration(seconds, 'seconds')
const minutes = Math.floor(dur.asMinutes())
const remainingSeconds = dur.seconds() + dur.milliseconds() / 1000
const parts = []
if (minutes > 0) parts.push(`${minutes}m`)
if (remainingSeconds > 0) {
const formattedSeconds = remainingSeconds.toFixed(2)
parts.push(`${formattedSeconds}s`)
}
return parts.join(' ')
}
return (
<QueryPanelContainer>
<QueryPanelSection className="pt-2 border-b relative">
@@ -146,10 +131,10 @@ export const QueryDetail = ({ selectedRow, onClickViewSuggestion }: QueryDetailP
<span
className={cn(
'tabular-nums',
formatDuration(rawValue / 1000) === '0.00s' && 'text-foreground-lighter'
formatDuration(totalTime) === '0.00s' && 'text-foreground-lighter'
)}
>
{formatDuration(totalTime / 1000)}
{formatDuration(totalTime)}
</span>
</p>
) : (

View File

@@ -0,0 +1,24 @@
import { describe, it, expect } from 'vitest'
import { formatDuration } from './QueryPerformance.utils'
describe('formatDuration', () => {
it('should format seconds', () => {
expect(formatDuration(1000)).toBe('1.00s')
expect(formatDuration(30000)).toBe('30.00s')
})
it('should format minutes and seconds', () => {
expect(formatDuration(60000)).toBe('1m')
expect(formatDuration(125000)).toBe('2m 5s')
})
it('should format hours, minutes and seconds', () => {
expect(formatDuration(3600000)).toBe('1h')
expect(formatDuration(3661000)).toBe('1h 1m 1s')
})
it('should format days, hours, minutes and seconds', () => {
expect(formatDuration(86400000)).toBe('1d')
expect(formatDuration(90061000)).toBe('1d 1h 1m 1s')
})
})

View File

@@ -0,0 +1,26 @@
import dayjs from 'dayjs'
import duration from 'dayjs/plugin/duration'
dayjs.extend(duration)
export const formatDuration = (milliseconds: number) => {
const duration = dayjs.duration(milliseconds, 'milliseconds')
const days = Math.floor(duration.asDays())
const hours = duration.hours()
const minutes = duration.minutes()
const seconds = duration.seconds()
const totalSeconds = duration.asSeconds()
if (totalSeconds < 60) {
return `${totalSeconds.toFixed(2)}s`
}
const parts = []
if (days > 0) parts.push(`${days}d`)
if (hours > 0) parts.push(`${hours}h`)
if (minutes > 0) parts.push(`${minutes}m`)
if (seconds > 0) parts.push(`${seconds}s`)
return parts.length > 0 ? parts.join(' ') : '0s'
}

View File

@@ -32,6 +32,7 @@ import {
QUERY_PERFORMANCE_ROLE_DESCRIPTION,
} from './QueryPerformance.constants'
import { useQueryPerformanceSort } from './hooks/useQueryPerformanceSort'
import { formatDuration } from './QueryPerformance.utils'
interface QueryPerformanceGridProps {
queryPerformanceQuery: DbQueryHook<any>
@@ -173,14 +174,10 @@ export const QueryPerformanceGrid = ({ queryPerformanceQuery }: QueryPerformance
<span className="text-muted">/</span>
<span
className={cn(
(totalTime / 1000).toFixed(2) === '0.00' && 'text-foreground-lighter'
formatDuration(totalTime) === '0.00s' && 'text-foreground-lighter'
)}
>
{(totalTime / 1000).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2,
})}
s
{formatDuration(totalTime)}
</span>
</span>
) : (