Unified Alerting: Stable order for state history annotations (#47674)

This change sorts the State History list returned by the backend by the
id in addition to the timeEnd and time fields by which it is
already sorted. This results in a stable view of the State History
table.

Fixes #45873

Signed-off-by: Joe Blubaugh <joe.blubaugh@grafana.com>
This commit is contained in:
Joe Blubaugh 2022-04-18 10:42:45 +08:00 committed by GitHub
parent 5e11af0121
commit 516c8b60ee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 71 additions and 1 deletions

View File

@ -0,0 +1,40 @@
import { StateHistoryItem } from 'app/types/unified-alerting';
import { sortStateHistory } from './StateHistory';
describe(sortStateHistory, () => {
describe('should stably sort', () => {
describe('when timeEnd is different', () => {
it('should not sort by rule id', () => {
let data: StateHistoryItem[] = [
{ timeEnd: 23, time: 22, id: 1 } as StateHistoryItem,
{ timeEnd: 22, time: 21, id: 3 } as StateHistoryItem,
{ timeEnd: 22, time: 22, id: 2 } as StateHistoryItem,
{ timeEnd: 24, id: 3 } as StateHistoryItem,
];
data.sort(sortStateHistory);
expect(data[0].timeEnd).toBe(24);
expect(data[1].timeEnd).toBe(23);
expect(data[2].time).toBe(22);
expect(data[3].id).toBe(3);
});
});
describe('when only the rule id is different', () => {
it('should sort by rule id', () => {
let data: StateHistoryItem[] = [
{ timeEnd: 23, time: 22, id: 1 } as StateHistoryItem,
{ timeEnd: 23, time: 22, id: 3 } as StateHistoryItem,
{ timeEnd: 23, time: 22, id: 2 } as StateHistoryItem,
{ timeEnd: 23, time: 22, id: 6 } as StateHistoryItem,
];
data.sort(sortStateHistory);
expect(data[0].id).toBe(6);
expect(data[1].id).toBe(3);
expect(data[2].id).toBe(2);
expect(data[3].id).toBe(1);
});
});
});
});

View File

@ -24,6 +24,32 @@ interface RuleStateHistoryProps {
alertId: string;
}
function sortStateHistory(a: StateHistoryItem, b: StateHistoryItem): number {
const compareDesc = (a: number, b: number): number => {
// Larger numbers first.
if (a > b) {
return -1;
}
if (b > a) {
return 1;
}
return 0;
};
const endNeq = compareDesc(a.timeEnd, b.timeEnd);
if (endNeq) {
return endNeq;
}
const timeNeq = compareDesc(a.time, b.time);
if (timeNeq) {
return timeNeq;
}
return compareDesc(a.id, b.id);
}
const StateHistory: FC<RuleStateHistoryProps> = ({ alertId }) => {
const { loading, error, result = [] } = useManagedAlertStateHistory(alertId);
@ -42,6 +68,7 @@ const StateHistory: FC<RuleStateHistoryProps> = ({ alertId }) => {
];
const items: StateHistoryRow[] = result
.sort(sortStateHistory)
.reduce((acc: StateHistoryRowItem[], item, index) => {
acc.push({
id: String(item.id),
@ -123,4 +150,7 @@ function hasMatchingPrecedingState(index: number, items: StateHistoryItem[]): bo
return previousHistoryItem.newState === currentHistoryItem.prevState;
}
export { StateHistory };
export {
StateHistory,
sortStateHistory, // exported for testing.
};