@@ -2,26 +2,59 @@ import {
2
2
DashboardWithoutIdSchema ,
3
3
Tile ,
4
4
} from '@hyperdx/common-utils/dist/types' ;
5
- import { differenceBy , uniq } from 'lodash' ;
5
+ import { uniq } from 'lodash' ;
6
6
import { z } from 'zod' ;
7
7
8
+ import {
9
+ createOrUpdateDashboardAlerts ,
10
+ deleteDashboardAlerts ,
11
+ getDashboardAlertsByTile ,
12
+ getTeamDashboardAlertsByTile ,
13
+ } from '@/controllers/alerts' ;
8
14
import type { ObjectId } from '@/models' ;
9
- import Alert from '@/models/alert' ;
10
15
import Dashboard from '@/models/dashboard' ;
11
- import { tagsSchema } from '@/utils/zod' ;
16
+
17
+ function pickAlertsByTile ( tiles : Tile [ ] ) {
18
+ return tiles . reduce ( ( acc , tile ) => {
19
+ if ( tile . config . alert ) {
20
+ acc [ tile . id ] = tile . config . alert ;
21
+ }
22
+ return acc ;
23
+ } , { } ) ;
24
+ }
12
25
13
26
export async function getDashboards ( teamId : ObjectId ) {
14
- const dashboards = await Dashboard . find ( {
15
- team : teamId ,
16
- } ) ;
27
+ const [ _dashboards , alerts ] = await Promise . all ( [
28
+ Dashboard . find ( { team : teamId } ) ,
29
+ getTeamDashboardAlertsByTile ( teamId ) ,
30
+ ] ) ;
31
+
32
+ const dashboards = _dashboards
33
+ . map ( d => d . toJSON ( ) )
34
+ . map ( d => ( {
35
+ ...d ,
36
+ tiles : d . tiles . map ( t => ( {
37
+ ...t ,
38
+ config : { ...t . config , alert : alerts [ t . id ] ?. [ 0 ] } ,
39
+ } ) ) ,
40
+ } ) ) ;
41
+
17
42
return dashboards ;
18
43
}
19
44
20
45
export async function getDashboard ( dashboardId : string , teamId : ObjectId ) {
21
- return Dashboard . findOne ( {
22
- _id : dashboardId ,
23
- team : teamId ,
24
- } ) ;
46
+ const [ _dashboard , alerts ] = await Promise . all ( [
47
+ Dashboard . findOne ( { _id : dashboardId , team : teamId } ) ,
48
+ getDashboardAlertsByTile ( teamId , dashboardId ) ,
49
+ ] ) ;
50
+
51
+ return {
52
+ ..._dashboard ,
53
+ tiles : _dashboard ?. tiles . map ( t => ( {
54
+ ...t ,
55
+ config : { ...t . config , alert : alerts [ t . id ] ?. [ 0 ] } ,
56
+ } ) ) ,
57
+ } ;
25
58
}
26
59
27
60
export async function createDashboard (
@@ -32,60 +65,33 @@ export async function createDashboard(
32
65
...dashboard ,
33
66
team : teamId ,
34
67
} ) . save ( ) ;
68
+
69
+ await createOrUpdateDashboardAlerts (
70
+ newDashboard . _id ,
71
+ teamId ,
72
+ pickAlertsByTile ( dashboard . tiles ) ,
73
+ ) ;
74
+
35
75
return newDashboard ;
36
76
}
37
77
38
- export async function deleteDashboardAndAlerts (
39
- dashboardId : string ,
40
- teamId : ObjectId ,
41
- ) {
78
+ export async function deleteDashboard ( dashboardId : string , teamId : ObjectId ) {
42
79
const dashboard = await Dashboard . findOneAndDelete ( {
43
80
_id : dashboardId ,
44
81
team : teamId ,
45
82
} ) ;
46
83
if ( dashboard ) {
47
- await Alert . deleteMany ( { dashboard : dashboard . _id } ) ;
84
+ await deleteDashboardAlerts ( dashboardId , teamId ) ;
48
85
}
49
86
}
50
87
51
88
export async function updateDashboard (
52
89
dashboardId : string ,
53
90
teamId : ObjectId ,
54
- {
55
- name,
56
- tiles,
57
- tags,
58
- } : {
59
- name : string ;
60
- tiles : Tile [ ] ;
61
- tags : z . infer < typeof tagsSchema > ;
62
- } ,
91
+ updates : Partial < z . infer < typeof DashboardWithoutIdSchema > > ,
63
92
) {
64
- const updatedDashboard = await Dashboard . findOneAndUpdate (
65
- {
66
- _id : dashboardId ,
67
- team : teamId ,
68
- } ,
69
- {
70
- name,
71
- tiles,
72
- tags : tags && uniq ( tags ) ,
73
- } ,
74
- { new : true } ,
75
- ) ;
93
+ const oldDashboard = await getDashboard ( dashboardId , teamId ) ;
76
94
77
- return updatedDashboard ;
78
- }
79
-
80
- export async function updateDashboardAndAlerts (
81
- dashboardId : string ,
82
- teamId : ObjectId ,
83
- dashboard : z . infer < typeof DashboardWithoutIdSchema > ,
84
- ) {
85
- const oldDashboard = await Dashboard . findOne ( {
86
- _id : dashboardId ,
87
- team : teamId ,
88
- } ) ;
89
95
if ( oldDashboard == null ) {
90
96
throw new Error ( 'Dashboard not found' ) ;
91
97
}
@@ -96,27 +102,42 @@ export async function updateDashboardAndAlerts(
96
102
team : teamId ,
97
103
} ,
98
104
{
99
- ...dashboard ,
100
- tags : dashboard . tags && uniq ( dashboard . tags ) ,
105
+ ...updates ,
106
+ tags : updates . tags && uniq ( updates . tags ) ,
101
107
} ,
102
108
{ new : true } ,
103
109
) ;
104
110
if ( updatedDashboard == null ) {
105
111
throw new Error ( 'Could not update dashboard' ) ;
106
112
}
107
113
108
- // Delete related alerts
109
- const deletedTileIds = differenceBy (
110
- oldDashboard ?. tiles || [ ] ,
111
- updatedDashboard ?. tiles || [ ] ,
112
- 'id' ,
113
- ) . map ( c => c . id ) ;
114
-
115
- if ( deletedTileIds ?. length > 0 ) {
116
- await Alert . deleteMany ( {
117
- dashboard : dashboardId ,
118
- tileId : { $in : deletedTileIds } ,
119
- } ) ;
114
+ // Update related alerts
115
+ // - Delete
116
+ const newAlertIds = new Set (
117
+ updates . tiles ?. map ( t => t . config . alert ?. id ) . filter ( Boolean ) ,
118
+ ) ;
119
+ const deletedAlertIds : string [ ] = [ ] ;
120
+
121
+ if ( oldDashboard . tiles ) {
122
+ for ( const tile of oldDashboard . tiles ) {
123
+ const alertId = tile . config . alert ?. id ;
124
+ if ( alertId && ! newAlertIds . has ( alertId ) ) {
125
+ deletedAlertIds . push ( alertId ) ;
126
+ }
127
+ }
128
+
129
+ if ( deletedAlertIds . length > 0 ) {
130
+ await deleteDashboardAlerts ( dashboardId , teamId , deletedAlertIds ) ;
131
+ }
132
+ }
133
+
134
+ // - Update / Create
135
+ if ( updates . tiles ) {
136
+ await createOrUpdateDashboardAlerts (
137
+ dashboardId ,
138
+ teamId ,
139
+ pickAlertsByTile ( updates . tiles ) ,
140
+ ) ;
120
141
}
121
142
122
143
return updatedDashboard ;
0 commit comments