Alerting: Allow future relative time (#89405)

This commit is contained in:
Gilles De Mey 2024-07-09 13:18:24 +02:00 committed by GitHub
parent d8137083d9
commit b7910ade97
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 64 additions and 20 deletions

View File

@ -40,6 +40,17 @@ describe('utils', () => {
display: 'now-100m to now-5m', display: 'now-100m to now-5m',
}); });
}); });
it('should be able to work with future values', () => {
const relativeTimeRange = { from: 600, to: -600 };
const timeOption = mapRelativeTimeRangeToOption(relativeTimeRange);
expect(timeOption).toEqual({
from: 'now-10m',
to: 'now+10m',
display: 'now-10m to now+10m',
});
});
}); });
describe('mapOptionToRelativeTimeRange', () => { describe('mapOptionToRelativeTimeRange', () => {
@ -56,6 +67,13 @@ describe('utils', () => {
expect(relativeTimeRange).toEqual({ from: 86400, to: 43200 }); expect(relativeTimeRange).toEqual({ from: 86400, to: 43200 });
}); });
it('should map future dates', () => {
const timeOption = { from: 'now-10m', to: 'now+10m', display: 'asdfasdf' };
const relativeTimeRange = mapOptionToRelativeTimeRange(timeOption);
expect(relativeTimeRange).toEqual({ from: 600, to: -600 });
});
}); });
describe('isRelativeFormat', () => { describe('isRelativeFormat', () => {
@ -83,6 +101,10 @@ describe('utils', () => {
expect(isRelativeFormat('now-53w')).toBe(true); expect(isRelativeFormat('now-53w')).toBe(true);
}); });
it('should consider now+10m as a relative format', () => {
expect(isRelativeFormat('now+10m')).toBe(true);
});
it('should consider 123123123 as a relative format', () => { it('should consider 123123123 as a relative format', () => {
expect(isRelativeFormat('123123123')).toBe(false); expect(isRelativeFormat('123123123')).toBe(false);
}); });
@ -99,6 +121,11 @@ describe('utils', () => {
expect(result.isValid).toBe(true); expect(result.isValid).toBe(true);
}); });
it('should consider now+10m as a valid relative format', () => {
const result = isRangeValid('now+10m');
expect(result.isValid).toBe(true);
});
it('should consider now-90000000d as an invalid relative format', () => { it('should consider now-90000000d as an invalid relative format', () => {
const result = isRangeValid('now-90000000d'); const result = isRangeValid('now-90000000d');
expect(result.isValid).toBe(false); expect(result.isValid).toBe(false);

View File

@ -1,6 +1,6 @@
import { RelativeTimeRange, TimeOption } from '@grafana/data'; import { RelativeTimeRange, TimeOption } from '@grafana/data';
const regex = /^now$|^now\-(\d{1,10})([wdhms])$/; const regex = /^now$|^now(\-|\+)(\d{1,10})([wdhms])$/;
export const mapOptionToRelativeTimeRange = (option: TimeOption): RelativeTimeRange | undefined => { export const mapOptionToRelativeTimeRange = (option: TimeOption): RelativeTimeRange | undefined => {
return { return {
@ -48,18 +48,19 @@ export const isRelativeFormat = (format: string): boolean => {
const relativeToSeconds = (relative: string): number => { const relativeToSeconds = (relative: string): number => {
const match = regex.exec(relative); const match = regex.exec(relative);
if (!match || match.length !== 3) { if (!match || match.length !== 4) {
return 0; return 0;
} }
const [, value, unit] = match; const [, sign, value, unit] = match;
const parsed = parseInt(value, 10); const parsed = parseInt(value, 10);
if (isNaN(parsed)) { if (isNaN(parsed)) {
return 0; return 0;
} }
return parsed * units[unit]; const seconds = parsed * units[unit];
return sign === '+' ? seconds * -1 : seconds;
}; };
const units: Record<string, number> = { const units: Record<string, number> = {
@ -71,25 +72,41 @@ const units: Record<string, number> = {
}; };
const secondsToRelativeFormat = (seconds: number): string => { const secondsToRelativeFormat = (seconds: number): string => {
if (seconds <= 0) { if (seconds === 0) {
return 'now'; return 'now';
} }
if (seconds >= units.w && seconds % units.w === 0) { const absoluteSeconds = Math.abs(seconds);
return `now-${seconds / units.w}w`; if (seconds < 0) {
return `now+${formatDuration(absoluteSeconds)}`;
} }
if (seconds >= units.d && seconds % units.d === 0) { return `now-${formatDuration(absoluteSeconds)}`;
return `now-${seconds / units.d}d`;
}
if (seconds >= units.h && seconds % units.h === 0) {
return `now-${seconds / units.h}h`;
}
if (seconds >= units.m && seconds % units.m === 0) {
return `now-${seconds / units.m}m`;
}
return `now-${seconds}s`;
}; };
/**
* Formats the given duration in seconds into a human-readable string representation.
*
* @param seconds - The duration in seconds.
* @returns The formatted duration string.
*/
function formatDuration(seconds: number): string {
const units = [
{ unit: 'w', value: 7 * 24 * 60 * 60 },
{ unit: 'd', value: 24 * 60 * 60 },
{ unit: 'h', value: 60 * 60 },
{ unit: 'm', value: 60 },
{ unit: 's', value: 1 },
];
for (const { unit, value } of units) {
if (seconds % value === 0) {
const quotient = seconds / value;
return `${quotient}${unit}`;
}
}
// If no perfect division, use the least significant unit
const leastSignificant = units[units.length - 1];
return `${seconds}${leastSignificant.unit}`;
}