mirror of
https://github.com/hyperdxio/hyperdx
synced 2026-04-21 13:37:15 +00:00
fix: Show alerts on a tile only when dashboard matches (#2048)
## Summary This PR fixes a bug that caused alerts created on other dashboards to be displayed on tiles with IDs that match the other dashboard. This in turn led to failures updating the alert on the "duplicate" dashboard. The included integration test demonstrates the case. ### Screenshots or video ### How to test locally or on Vercel ### References - Linear Issue: Closes HDX-3918 - Related PRs:
This commit is contained in:
parent
b4e1498eb3
commit
59b1f46fd7
4 changed files with 57 additions and 5 deletions
5
.changeset/new-lemons-walk.md
Normal file
5
.changeset/new-lemons-walk.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"@hyperdx/api": patch
|
||||
---
|
||||
|
||||
fix: Show alerts on a tile only when dashboard matches
|
||||
|
|
@ -203,12 +203,14 @@ export const getAlertById = async (
|
|||
});
|
||||
};
|
||||
|
||||
export const getTeamDashboardAlertsByTile = async (teamId: ObjectId) => {
|
||||
export const getTeamDashboardAlertsByDashboardAndTile = async (
|
||||
teamId: ObjectId,
|
||||
) => {
|
||||
const alerts = await Alert.find({
|
||||
source: AlertSource.TILE,
|
||||
team: teamId,
|
||||
}).populate('createdBy', 'email name');
|
||||
return groupBy(alerts, 'tileId');
|
||||
return groupBy(alerts, a => `${a.dashboard?.toString()}:${a.tileId}`);
|
||||
};
|
||||
|
||||
export const getDashboardAlertsByTile = async (
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import {
|
|||
createOrUpdateDashboardAlerts,
|
||||
deleteDashboardAlerts,
|
||||
getDashboardAlertsByTile,
|
||||
getTeamDashboardAlertsByTile,
|
||||
getTeamDashboardAlertsByDashboardAndTile,
|
||||
} from '@/controllers/alerts';
|
||||
import type { ObjectId } from '@/models';
|
||||
import type { AlertDocument, IAlert } from '@/models/alert';
|
||||
|
|
@ -96,7 +96,7 @@ async function syncDashboardAlerts(
|
|||
export async function getDashboards(teamId: ObjectId) {
|
||||
const [_dashboards, alerts] = await Promise.all([
|
||||
Dashboard.find({ team: teamId }),
|
||||
getTeamDashboardAlertsByTile(teamId),
|
||||
getTeamDashboardAlertsByDashboardAndTile(teamId),
|
||||
]);
|
||||
|
||||
const dashboards = _dashboards
|
||||
|
|
@ -105,7 +105,10 @@ export async function getDashboards(teamId: ObjectId) {
|
|||
...d,
|
||||
tiles: d.tiles.map(t => ({
|
||||
...t,
|
||||
config: { ...t.config, alert: alerts[t.id]?.[0] },
|
||||
config: {
|
||||
...t.config,
|
||||
alert: alerts[`${d._id.toString()}:${t.id}`]?.[0],
|
||||
},
|
||||
})),
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -341,6 +341,48 @@ describe('dashboard router', () => {
|
|||
expect(allTilesPostDelete).toEqual(alertsPostDeleteTiles);
|
||||
});
|
||||
|
||||
it('alert on a tile only appears on the dashboard that owns it, not on another dashboard with the same tile ID', async () => {
|
||||
const sharedTileId = new mongoose.Types.ObjectId().toHexString();
|
||||
const mockAlert = makeMockAlert(webhook._id.toString());
|
||||
|
||||
// Create dashboard A with an alert on the tile
|
||||
const dashboardA = await agent
|
||||
.post('/dashboards')
|
||||
.send({
|
||||
name: 'Dashboard A',
|
||||
tiles: [makeTile({ id: sharedTileId, alert: mockAlert })],
|
||||
tags: [],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
// Create dashboard B with a tile that has the same ID, but no alert
|
||||
const dashboardB = await agent
|
||||
.post('/dashboards')
|
||||
.send({
|
||||
name: 'Dashboard B',
|
||||
tiles: [makeTile({ id: sharedTileId })],
|
||||
tags: [],
|
||||
})
|
||||
.expect(200);
|
||||
|
||||
// Fetch all dashboards
|
||||
const dashboards = await agent.get('/dashboards').expect(200);
|
||||
|
||||
const fetchedA = dashboards.body.find(
|
||||
(d: any) => d._id === dashboardA.body.id,
|
||||
);
|
||||
const fetchedB = dashboards.body.find(
|
||||
(d: any) => d._id === dashboardB.body.id,
|
||||
);
|
||||
|
||||
// The alert should appear on dashboard A's tile
|
||||
expect(fetchedA.tiles[0].config.alert).toBeTruthy();
|
||||
expect(fetchedA.tiles[0].config.alert.tileId).toBe(sharedTileId);
|
||||
|
||||
// The alert should NOT appear on dashboard B's tile
|
||||
expect(fetchedB.tiles[0].config.alert).toBeUndefined();
|
||||
});
|
||||
|
||||
it('preserves alert creator when different user updates dashboard', async () => {
|
||||
const mockAlert = makeMockAlert(webhook._id.toString());
|
||||
const currentUser = user;
|
||||
|
|
|
|||
Loading…
Reference in a new issue