mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
StateTimeline: Show more precise duration (#44046)
* StateTimeline: Show more precise duration * Add Leon's calculation * Change to 30 days Remove console logs. Add more tests.
This commit is contained in:
parent
ed7552db79
commit
f16047660a
@ -1,15 +1,7 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
DataFrame,
|
||||
FALLBACK_COLOR,
|
||||
formattedValueToString,
|
||||
getDisplayProcessor,
|
||||
getFieldDisplayName,
|
||||
getValueFormat,
|
||||
TimeZone,
|
||||
} from '@grafana/data';
|
||||
import { DataFrame, FALLBACK_COLOR, getDisplayProcessor, getFieldDisplayName, TimeZone } from '@grafana/data';
|
||||
import { SeriesTableRow, useTheme2 } from '@grafana/ui';
|
||||
import { findNextStateIndex } from './utils';
|
||||
import { findNextStateIndex, fmtDuration } from './utils';
|
||||
|
||||
interface StateTimelineTooltipProps {
|
||||
data: DataFrame[];
|
||||
@ -57,7 +49,7 @@ export const StateTimelineTooltip: React.FC<StateTimelineTooltipProps> = ({
|
||||
let durationFragment = null;
|
||||
|
||||
if (nextStateTs) {
|
||||
const duration = nextStateTs && formattedValueToString(getValueFormat('dtdurationms')(nextStateTs - stateTs, 0));
|
||||
const duration = nextStateTs && fmtDuration(nextStateTs - stateTs);
|
||||
durationFragment = (
|
||||
<>
|
||||
<br />
|
||||
|
@ -1,6 +1,12 @@
|
||||
import { ArrayVector, createTheme, FieldType, ThresholdsMode, toDataFrame } from '@grafana/data';
|
||||
import { LegendDisplayMode } from '@grafana/schema';
|
||||
import { findNextStateIndex, getThresholdItems, prepareTimelineFields, prepareTimelineLegendItems } from './utils';
|
||||
import {
|
||||
findNextStateIndex,
|
||||
fmtDuration,
|
||||
getThresholdItems,
|
||||
prepareTimelineFields,
|
||||
prepareTimelineLegendItems,
|
||||
} from './utils';
|
||||
|
||||
const theme = createTheme();
|
||||
|
||||
@ -221,3 +227,35 @@ describe('prepareTimelineLegendItems', () => {
|
||||
expect(result).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('duration', () => {
|
||||
it.each`
|
||||
value | expected
|
||||
${-1} | ${''}
|
||||
${20} | ${'20ms'}
|
||||
${1000} | ${'1s'}
|
||||
${1020} | ${'1s 20ms'}
|
||||
${60000} | ${'1m'}
|
||||
${61020} | ${'1m 1s'}
|
||||
${3600000} | ${'1h'}
|
||||
${6600000} | ${'1h 50m'}
|
||||
${86400000} | ${'1d'}
|
||||
${96640000} | ${'1d 2h'}
|
||||
${604800000} | ${'1w'}
|
||||
${691200000} | ${'1w 1d'}
|
||||
${2419200000} | ${'4w'}
|
||||
${2678400000} | ${'1mo 1d'}
|
||||
${3196800000} | ${'1mo 1w'}
|
||||
${3456000000} | ${'1mo 1w 3d'}
|
||||
${6739200000} | ${'2mo 2w 4d'}
|
||||
${31536000000} | ${'1y'}
|
||||
${31968000000} | ${'1y 5d'}
|
||||
${32140800000} | ${'1y 1w'}
|
||||
${67910400000} | ${'2y 1mo 3w 5d'}
|
||||
${40420800000} | ${'1y 3mo 1w 5d'}
|
||||
${9007199254740991} | ${'285616y 5mo 1d'}
|
||||
`(' function should format $value ms to $expected', ({ value, expected }) => {
|
||||
const result = fmtDuration(value);
|
||||
expect(result).toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
@ -570,3 +570,63 @@ export function findNextStateIndex(field: Field, datapointIdx: number) {
|
||||
|
||||
return end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the precise duration of a time range passed in milliseconds.
|
||||
* This function calculates with 30 days month and 365 days year.
|
||||
* adapted from https://gist.github.com/remino/1563878
|
||||
* @param milliSeconds The duration in milliseconds
|
||||
* @returns A formated string of the duration
|
||||
*/
|
||||
export function fmtDuration(milliSeconds: number): string {
|
||||
if (milliSeconds < 0 || Number.isNaN(milliSeconds)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let yr: number, mo: number, wk: number, d: number, h: number, m: number, s: number, ms: number;
|
||||
|
||||
s = Math.floor(milliSeconds / 1000);
|
||||
m = Math.floor(s / 60);
|
||||
s = s % 60;
|
||||
h = Math.floor(m / 60);
|
||||
m = m % 60;
|
||||
d = Math.floor(h / 24);
|
||||
h = h % 24;
|
||||
|
||||
yr = Math.floor(d / 365);
|
||||
if (yr > 0) {
|
||||
d = d % 365;
|
||||
}
|
||||
|
||||
mo = Math.floor(d / 30);
|
||||
if (mo > 0) {
|
||||
d = d % 30;
|
||||
}
|
||||
|
||||
wk = Math.floor(d / 7);
|
||||
|
||||
if (wk > 0) {
|
||||
d = d % 7;
|
||||
}
|
||||
|
||||
ms = Math.round((milliSeconds % 1000) * 1000) / 1000;
|
||||
|
||||
return (yr > 0
|
||||
? yr + 'y ' + (mo > 0 ? mo + 'mo ' : '') + (wk > 0 ? wk + 'w ' : '') + (d > 0 ? d + 'd ' : '')
|
||||
: mo > 0
|
||||
? mo + 'mo ' + (wk > 0 ? wk + 'w ' : '') + (d > 0 ? d + 'd ' : '')
|
||||
: wk > 0
|
||||
? wk + 'w ' + (d > 0 ? d + 'd ' : '')
|
||||
: d > 0
|
||||
? d + 'd ' + (h > 0 ? h + 'h ' : '')
|
||||
: h > 0
|
||||
? h + 'h ' + (m > 0 ? m + 'm ' : '')
|
||||
: m > 0
|
||||
? m + 'm ' + (s > 0 ? s + 's ' : '')
|
||||
: s > 0
|
||||
? s + 's ' + (ms > 0 ? ms + 'ms ' : '')
|
||||
: ms > 0
|
||||
? ms + 'ms '
|
||||
: '0'
|
||||
).trim();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user