From 2ad86223f2db89637d042b562f351187467ed712 Mon Sep 17 00:00:00 2001 From: Julien Tant Date: Thu, 27 Jun 2024 09:24:53 -0700 Subject: [PATCH] support negative duration --- .../backstage/metrics/metrics_row.tsx | 2 +- .../src/components/formatted_duration.test.tsx | 1 + webapp/src/components/formatted_duration.tsx | 17 +++++++++++++---- 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/webapp/src/components/backstage/metrics/metrics_row.tsx b/webapp/src/components/backstage/metrics/metrics_row.tsx index ed26cfcb1e..6070da176f 100644 --- a/webapp/src/components/backstage/metrics/metrics_row.tsx +++ b/webapp/src/components/backstage/metrics/metrics_row.tsx @@ -68,7 +68,7 @@ const Cell = ({type, value, target}: CellProps) => { let diff = prefix + Math.abs(value - target); if (type === MetricType.MetricDuration) { val =
{formatDuration(valueAsDuration)}
; - diff = prefix + formatDuration(Duration.fromMillis(target).minus(valueAsDuration)); + diff = formatDuration(Duration.fromMillis(target).minus(valueAsDuration)); } return ( diff --git a/webapp/src/components/formatted_duration.test.tsx b/webapp/src/components/formatted_duration.test.tsx index 00a182e3fb..ef0d757932 100644 --- a/webapp/src/components/formatted_duration.test.tsx +++ b/webapp/src/components/formatted_duration.test.tsx @@ -42,6 +42,7 @@ describe('formatDuration', () => { [{months: 1}, '30d', '30 days'], [{months: 2}, '60d', '60 days'], [{years: 2, days: 6, minutes: 12}, '2y, 6d, 12m', '2 years, 6 days, 12 minutes'], + [{days: -1, hours: -2, minutes: -5}, '-1d, 2h, 5m', '-1 day, 2 hours, 5 minutes'], ])('should format %p as %p and %p', (durationObj, expectedNarrow, expectedLong) => { const duration = Duration.fromObject(durationObj); expect(formatDuration(duration)).toEqual(expectedNarrow); diff --git a/webapp/src/components/formatted_duration.tsx b/webapp/src/components/formatted_duration.tsx index 5775e54286..fcfe49f1e1 100644 --- a/webapp/src/components/formatted_duration.tsx +++ b/webapp/src/components/formatted_duration.tsx @@ -30,20 +30,29 @@ interface DurationProps { const UNITS: DurationUnit[] = ['years', 'days', 'hours', 'minutes']; export const formatDuration = (value: Duration, style: FormatStyle = 'narrow', truncate: TruncateBehavior = 'none') => { - if (value.as('seconds') < 60) { - return value + let localValue = value; + + const isNegative = value.toMillis() < 0; + if (isNegative) { + localValue = value.negate(); + } + + if (localValue.as('seconds') < 60) { + const str = localValue .shiftTo('seconds') .mapUnits(Math.floor) .toHuman({unitDisplay: style}); + return isNegative ? `-${str}` : str; } - const duration = value.shiftTo(...UNITS).normalize(); + const duration = localValue.shiftTo(...UNITS).normalize(); const formatUnits = truncate === 'truncate' ? [UNITS.find((unit) => duration.get(unit) > 0)!] : UNITS.filter((unit) => duration.get(unit) > 0); - return duration + const str = duration .shiftTo(...formatUnits) .mapUnits(Math.floor) .toHuman({unitDisplay: style}); + return isNegative ? `-${str}` : str; }; const FormattedDuration = ({from, to = 0, style, truncate}: DurationProps) => {