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
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; 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 StateHistory: FC<RuleStateHistoryProps> = ({ alertId }) => {
const { loading, error, result = [] } = useManagedAlertStateHistory(alertId); const { loading, error, result = [] } = useManagedAlertStateHistory(alertId);
@@ -42,6 +68,7 @@ const StateHistory: FC<RuleStateHistoryProps> = ({ alertId }) => {
]; ];
const items: StateHistoryRow[] = result const items: StateHistoryRow[] = result
.sort(sortStateHistory)
.reduce((acc: StateHistoryRowItem[], item, index) => { .reduce((acc: StateHistoryRowItem[], item, index) => {
acc.push({ acc.push({
id: String(item.id), id: String(item.id),
@@ -123,4 +150,7 @@ function hasMatchingPrecedingState(index: number, items: StateHistoryItem[]): bo
return previousHistoryItem.newState === currentHistoryItem.prevState; return previousHistoryItem.newState === currentHistoryItem.prevState;
} }
export { StateHistory }; export {
StateHistory,
sortStateHistory, // exported for testing.
};