@oneuptime/common 7.0.3652 → 7.0.3668

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (80) hide show
  1. package/Models/DatabaseModels/Alert.ts +19 -0
  2. package/Models/DatabaseModels/Incident.ts +19 -0
  3. package/Models/DatabaseModels/ScheduledMaintenance.ts +19 -0
  4. package/Server/API/BaseAPI.ts +48 -0
  5. package/Server/Infrastructure/Postgres/SchemaMigrations/1739282331053-MigrationName.ts +29 -0
  6. package/Server/Infrastructure/Postgres/SchemaMigrations/1739374537088-MigrationName.ts +29 -0
  7. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +4 -0
  8. package/Server/Services/IncidentService.ts +101 -0
  9. package/Server/Services/MonitorService.ts +43 -0
  10. package/Server/Services/ProjectService.ts +3 -3
  11. package/Server/Services/TeamMemberService.ts +1 -0
  12. package/Server/Services/UserService.ts +6 -1
  13. package/Server/Services/WorkspaceNotificationRuleService.ts +442 -7
  14. package/Server/Services/WorkspaceProjectAuthTokenService.ts +43 -15
  15. package/Server/Types/Workflow/Components/Slack/SendMessageToChannel.ts +1 -1
  16. package/Server/Utils/Slack/Slack.ts +361 -26
  17. package/Types/Workspace/NotificationRules/BaseNotificationRule.ts +9 -0
  18. package/Types/Workspace/NotificationRules/NotificationRuleCondition.ts +23 -32
  19. package/Types/Workspace/NotificationRules/NotificationRuleTypes/AlertNotificationRule.ts +15 -0
  20. package/Types/Workspace/NotificationRules/NotificationRuleTypes/IncidentNotificationRule.ts +15 -0
  21. package/Types/Workspace/NotificationRules/NotificationRuleTypes/MonitorStatusNotificationRule.ts +7 -0
  22. package/Types/Workspace/NotificationRules/NotificationRuleTypes/ScheduledMaintenanceNotificationRule.ts +14 -0
  23. package/Types/Workspace/NotificationRules/NotificationRuleUtil.ts +261 -0
  24. package/Types/Workspace/WorkspaceChannelInvitationPayload.ts +4 -0
  25. package/Types/Workspace/WorkspaceMessagePayload.ts +30 -0
  26. package/build/dist/Models/DatabaseModels/Alert.js +21 -0
  27. package/build/dist/Models/DatabaseModels/Alert.js.map +1 -1
  28. package/build/dist/Models/DatabaseModels/Incident.js +21 -0
  29. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  30. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +21 -0
  31. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  32. package/build/dist/Server/API/BaseAPI.js +34 -2
  33. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  34. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1739282331053-MigrationName.js +16 -0
  35. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1739282331053-MigrationName.js.map +1 -0
  36. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1739374537088-MigrationName.js +16 -0
  37. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1739374537088-MigrationName.js.map +1 -0
  38. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +4 -0
  39. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  40. package/build/dist/Server/Services/IncidentService.js +84 -0
  41. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  42. package/build/dist/Server/Services/MonitorService.js +34 -0
  43. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  44. package/build/dist/Server/Services/ProjectService.js +3 -3
  45. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  46. package/build/dist/Server/Services/TeamMemberService.js +1 -0
  47. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  48. package/build/dist/Server/Services/UserService.js +4 -1
  49. package/build/dist/Server/Services/UserService.js.map +1 -1
  50. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +316 -4
  51. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  52. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +29 -4
  53. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  54. package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js +1 -1
  55. package/build/dist/Server/Types/Workflow/Components/Slack/SendMessageToChannel.js.map +1 -1
  56. package/build/dist/Server/Utils/Slack/Slack.js +227 -18
  57. package/build/dist/Server/Utils/Slack/Slack.js.map +1 -1
  58. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js +20 -21
  59. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleCondition.js.map +1 -1
  60. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/AlertNotificationRule.js +2 -0
  61. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/AlertNotificationRule.js.map +1 -0
  62. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/IncidentNotificationRule.js +2 -0
  63. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/IncidentNotificationRule.js.map +1 -0
  64. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/MonitorStatusNotificationRule.js +2 -0
  65. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/MonitorStatusNotificationRule.js.map +1 -0
  66. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/ScheduledMaintenanceNotificationRule.js +2 -0
  67. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleTypes/ScheduledMaintenanceNotificationRule.js.map +1 -0
  68. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleUtil.js +216 -0
  69. package/build/dist/Types/Workspace/NotificationRules/NotificationRuleUtil.js.map +1 -0
  70. package/build/dist/Types/Workspace/WorkspaceChannelInvitationPayload.js +2 -0
  71. package/build/dist/Types/Workspace/WorkspaceChannelInvitationPayload.js.map +1 -0
  72. package/build/dist/Types/Workspace/WorkspaceMessagePayload.js +2 -0
  73. package/build/dist/Types/Workspace/WorkspaceMessagePayload.js.map +1 -0
  74. package/package.json +2 -2
  75. package/Types/Workspace/NotificationRules/SlackNotificationRule.ts +0 -19
  76. package/Types/Workspace/WorkspaceNotificationPayload.ts +0 -3
  77. package/build/dist/Types/Workspace/NotificationRules/SlackNotificationRule.js +0 -2
  78. package/build/dist/Types/Workspace/NotificationRules/SlackNotificationRule.js.map +0 -1
  79. package/build/dist/Types/Workspace/WorkspaceNotificationPayload.js +0 -2
  80. package/build/dist/Types/Workspace/WorkspaceNotificationPayload.js.map +0 -1
@@ -3,49 +3,342 @@ import HTTPResponse from "Common/Types/API/HTTPResponse";
3
3
  import URL from "Common/Types/API/URL";
4
4
  import { JSONObject } from "Common/Types/JSON";
5
5
  import API from "Common/Utils/API";
6
+ import WorkspaceMessagePayload, {
7
+ WorkspaceMessagePayloadButton,
8
+ WorkspacePayloadButtons,
9
+ WorkspacePayloadHeader,
10
+ WorkspacePayloadMarkdown,
11
+ } from "../../../Types/Workspace/WorkspaceMessagePayload";
12
+ import logger from "../Logger";
13
+ import Dictionary from "../../../Types/Dictionary";
14
+ import BadRequestException from "../../../Types/Exception/BadRequestException";
15
+ import WorkspaceChannelInvitationPayload from "../../../Types/Workspace/WorkspaceChannelInvitationPayload";
16
+
17
+ export interface JobResponse {
18
+ isSuccessful: boolean;
19
+ errorMessage?: string | undefined;
20
+ }
21
+
22
+ export interface SlackChannel {
23
+ id: string;
24
+ name: string;
25
+ }
6
26
 
7
27
  export default class SlackUtil {
8
- public async getTextboxField(data: {
9
- title: string;
10
- placeholder: string;
11
- actionId: string;
12
- initialValue?: string;
13
- }): Promise<JSONObject> {
14
- return {
15
- type: "input",
16
- element: {
17
- type: "plain_text_input",
18
- action_id: data.actionId,
19
- placeholder: {
20
- type: "plain_text",
21
- text: data.placeholder,
28
+ public static async inviteUsersToChannels(data: {
29
+ authToken: string;
30
+ workspaceChannelInvitationPayload: WorkspaceChannelInvitationPayload;
31
+ }): Promise<void> {
32
+ const channelIds: Array<string> = [];
33
+
34
+ for (const channelName of data.workspaceChannelInvitationPayload
35
+ .workspaceChannelNames) {
36
+ const channel: SlackChannel = await this.createChannel({
37
+ authToken: data.authToken,
38
+ channelName: channelName,
39
+ });
40
+
41
+ channelIds.push(channel.id);
42
+ }
43
+
44
+ for (const channelId of channelIds) {
45
+ await this.inviteUsersToChannel({
46
+ authToken: data.authToken,
47
+ channelId: channelId,
48
+ userIds: data.workspaceChannelInvitationPayload.workspaceUserIds,
49
+ });
50
+ }
51
+ }
52
+
53
+ private static async inviteUsersToChannel(data: {
54
+ authToken: string;
55
+ channelId: string;
56
+ userIds: Array<string>;
57
+ }): Promise<void> {
58
+ for (const userId of data.userIds) {
59
+ await this.inviteUserToChannel({
60
+ authToken: data.authToken,
61
+ channelId: data.channelId,
62
+ userId: userId,
63
+ });
64
+ }
65
+ }
66
+
67
+ private static async inviteUserToChannel(data: {
68
+ authToken: string;
69
+ channelId: string;
70
+ userId: string;
71
+ }): Promise<void> {
72
+ const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
73
+ await API.post(
74
+ URL.fromString("https://slack.com/api/conversations.invite"),
75
+ {
76
+ channel: data.channelId,
77
+ users: data.userId,
22
78
  },
23
- initial_value: data.initialValue,
24
- },
25
- label: {
79
+ {
80
+ Authorization: `Bearer ${data.authToken}`,
81
+ },
82
+ );
83
+
84
+ if (response instanceof HTTPErrorResponse) {
85
+ throw response;
86
+ }
87
+
88
+ if ((response.jsonData as JSONObject)?.["ok"] !== true) {
89
+ throw new BadRequestException("Invalid response");
90
+ }
91
+ }
92
+
93
+ public static async createChannelIfDoesNotExist(data: {
94
+ authToken: string;
95
+ channelNamesToCreate: Array<string>;
96
+ }): Promise<Array<string>> {
97
+ // check existing channels and only create if they dont exist.
98
+ const channelIds: Array<string> = [];
99
+ const existingSlackChannels: Dictionary<SlackChannel> =
100
+ await this.getSlackChannels({
101
+ authToken: data.authToken,
102
+ });
103
+
104
+ for (const channelName of data.channelNamesToCreate) {
105
+ if (existingSlackChannels[channelName]) {
106
+ logger.debug(`Channel ${channelName} already exists.`);
107
+
108
+ channelIds.push(existingSlackChannels[channelName]!.id);
109
+
110
+ continue;
111
+ }
112
+
113
+ const channel: SlackChannel = await this.createChannel({
114
+ authToken: data.authToken,
115
+ channelName: channelName,
116
+ });
117
+
118
+ if (channel) {
119
+ channelIds.push(channel.id);
120
+ }
121
+ }
122
+
123
+ return channelIds;
124
+ }
125
+
126
+ public static async getChannelNameFromChannelId(data: {
127
+ authToken: string;
128
+ channelId: string;
129
+ }): Promise<string> {
130
+ const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
131
+ await API.get<JSONObject>(
132
+ URL.fromString("https://slack.com/api/conversations.info"),
133
+ {
134
+ headers: {
135
+ Authorization: `Bearer ${data.authToken}`,
136
+ },
137
+ params: {
138
+ channel: data.channelId,
139
+ },
140
+ },
141
+ );
142
+
143
+ if (response instanceof HTTPErrorResponse) {
144
+ throw response;
145
+ }
146
+
147
+ if (
148
+ !((response.jsonData as JSONObject)?.["channel"] as JSONObject)?.["name"]
149
+ ) {
150
+ throw new Error("Invalid response");
151
+ }
152
+
153
+ return ((response.jsonData as JSONObject)["channel"] as JSONObject)[
154
+ "name"
155
+ ] as string;
156
+ }
157
+
158
+ public static async sendMessage(data: {
159
+ workspaceMessagePayload: WorkspaceMessagePayload;
160
+ authToken: string; // which auth token should we use to send.
161
+ }): Promise<void> {
162
+ logger.debug("Notify Slack");
163
+ logger.debug(data);
164
+
165
+ const blocks: Array<JSONObject> =
166
+ this.getSlackBlocksFromWorkspaceMessagePayload(
167
+ data.workspaceMessagePayload,
168
+ );
169
+
170
+ const existingSlackChannels: Dictionary<SlackChannel> =
171
+ await this.getSlackChannels({
172
+ authToken: data.authToken,
173
+ });
174
+
175
+ const channelIdsToPostTo: Array<string> = [];
176
+
177
+ for (const channelName of data.workspaceMessagePayload.channelNames) {
178
+ // get channel ids from existingSlackChannels. IF channel doesn't exist, create it if createChannelsIfItDoesNotExist is true.
179
+ let channel: SlackChannel | null = null;
180
+
181
+ if (existingSlackChannels[channelName]) {
182
+ channel = existingSlackChannels[channelName]!;
183
+ }
184
+
185
+ if (channel) {
186
+ channelIdsToPostTo.push(channel.id);
187
+ } else {
188
+ logger.debug(`Channel ${channelName} does not exist.`);
189
+ }
190
+ }
191
+
192
+ for (const channelId of channelIdsToPostTo) {
193
+ try {
194
+ // try catch here to prevent failure of one channel to prevent posting to other channels.
195
+ await this.sendPayloadBlocksToChannel({
196
+ authToken: data.authToken,
197
+ channelId: channelId,
198
+ blocks: blocks,
199
+ });
200
+ } catch (e) {
201
+ logger.error(e);
202
+ }
203
+ }
204
+ }
205
+
206
+ public static async sendPayloadBlocksToChannel(data: {
207
+ authToken: string;
208
+ channelId: string;
209
+ blocks: Array<JSONObject>;
210
+ }): Promise<void> {
211
+ const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
212
+ await API.post(
213
+ URL.fromString("https://slack.com/api/chat.postMessage"),
214
+ {
215
+ channel: data.channelId,
216
+ blocks: data.blocks,
217
+ },
218
+ {
219
+ Authorization: `Bearer ${data.authToken}`,
220
+ },
221
+ );
222
+
223
+ if (response instanceof HTTPErrorResponse) {
224
+ throw response;
225
+ }
226
+
227
+ if ((response.jsonData as JSONObject)?.["ok"] !== true) {
228
+ throw new BadRequestException("Invalid response");
229
+ }
230
+ }
231
+
232
+ public static async createChannel(data: {
233
+ authToken: string;
234
+ channelName: string;
235
+ }): Promise<SlackChannel> {
236
+ const response: HTTPResponse<JSONObject> | HTTPErrorResponse =
237
+ await API.post(
238
+ URL.fromString("https://slack.com/api/conversations.create"),
239
+ {
240
+ name: data.channelName,
241
+ },
242
+ {
243
+ Authorization: `Bearer ${data.authToken}`,
244
+ },
245
+ );
246
+
247
+ if (response instanceof HTTPErrorResponse) {
248
+ throw response;
249
+ }
250
+
251
+ if (
252
+ !((response.jsonData as JSONObject)?.["channel"] as JSONObject)?.["id"] ||
253
+ !((response.jsonData as JSONObject)?.["channel"] as JSONObject)?.["name"]
254
+ ) {
255
+ throw new Error("Invalid response");
256
+ }
257
+
258
+ return {
259
+ id: ((response.jsonData as JSONObject)["channel"] as JSONObject)[
260
+ "id"
261
+ ] as string,
262
+ name: ((response.jsonData as JSONObject)["channel"] as JSONObject)[
263
+ "name"
264
+ ] as string,
265
+ };
266
+ }
267
+
268
+ public static getHeaderBlock(data: {
269
+ payloadHeaderBlock: WorkspacePayloadHeader;
270
+ }): JSONObject {
271
+ return {
272
+ type: "header",
273
+ text: {
26
274
  type: "plain_text",
27
- text: data.title,
275
+ text: data.payloadHeaderBlock.text,
28
276
  },
29
277
  };
30
278
  }
31
279
 
32
- public getButtonField(data: {
33
- text: string;
34
- actionId: string;
35
- value: string;
280
+ public static getMarkdownBlock(data: {
281
+ payloadMarkdownBlock: WorkspacePayloadMarkdown;
282
+ }): JSONObject {
283
+ return {
284
+ type: "section",
285
+ text: {
286
+ type: "mrkdwn",
287
+ text: data.payloadMarkdownBlock.text,
288
+ },
289
+ };
290
+ }
291
+
292
+ public static async getSlackChannels(data: {
293
+ authToken: string;
294
+ }): Promise<Dictionary<SlackChannel>> {
295
+ const response: HTTPErrorResponse | HTTPResponse<JSONObject> =
296
+ await API.get<JSONObject>(
297
+ URL.fromString("https://slack.com/api/conversations.list"),
298
+ {
299
+ headers: {
300
+ Authorization: `Bearer ${data.authToken}`,
301
+ },
302
+ },
303
+ );
304
+
305
+ if (response instanceof HTTPErrorResponse) {
306
+ throw response;
307
+ }
308
+
309
+ const channels: Dictionary<SlackChannel> = {};
310
+
311
+ for (const channel of (response.jsonData as JSONObject)[
312
+ "channels"
313
+ ] as Array<JSONObject>) {
314
+ if (!channel["id"] || !channel["name"]) {
315
+ continue;
316
+ }
317
+
318
+ channels[channel["name"].toString()] = {
319
+ id: channel["id"] as string,
320
+ name: channel["name"] as string,
321
+ };
322
+ }
323
+
324
+ return channels;
325
+ }
326
+
327
+ public static getButtonBlock(data: {
328
+ payloadButtonBlock: WorkspaceMessagePayloadButton;
36
329
  }): JSONObject {
37
330
  return {
38
331
  type: "button",
39
332
  text: {
40
333
  type: "plain_text",
41
- text: data.text,
334
+ text: data.payloadButtonBlock.title,
42
335
  },
43
- action_id: data.actionId,
44
- value: data.value,
336
+ value: data.payloadButtonBlock.title,
337
+ action_id: data.payloadButtonBlock.title,
45
338
  };
46
339
  }
47
340
 
48
- public static async sendMessageToChannel(data: {
341
+ public static async sendMessageToChannelViaIncomingWebhook(data: {
49
342
  url: URL;
50
343
  text: string;
51
344
  }): Promise<HTTPResponse<JSONObject> | HTTPErrorResponse> {
@@ -66,4 +359,46 @@ export default class SlackUtil {
66
359
 
67
360
  return apiResult;
68
361
  }
362
+
363
+ private static getSlackBlocksFromWorkspaceMessagePayload(
364
+ data: WorkspaceMessagePayload,
365
+ ): Array<JSONObject> {
366
+ const blocks: Array<JSONObject> = [];
367
+ const buttons: Array<JSONObject> = [];
368
+ for (const block of data.messageBlocks) {
369
+ switch (block._type) {
370
+ case "WorkspacePayloadHeader":
371
+ blocks.push(
372
+ this.getHeaderBlock({
373
+ payloadHeaderBlock: block as WorkspacePayloadHeader,
374
+ }),
375
+ );
376
+ break;
377
+ case "WorkspacePayloadMarkdown":
378
+ blocks.push(
379
+ this.getMarkdownBlock({
380
+ payloadMarkdownBlock: block as WorkspacePayloadMarkdown,
381
+ }),
382
+ );
383
+ break;
384
+ case "WorkspacePayloadButtons":
385
+ for (const button of (block as WorkspacePayloadButtons).buttons) {
386
+ buttons.push(
387
+ this.getButtonBlock({
388
+ payloadButtonBlock: button,
389
+ }),
390
+ );
391
+ }
392
+ blocks.push({
393
+ type: "actions",
394
+ elements: buttons,
395
+ });
396
+ break;
397
+ default:
398
+ logger.error("Unknown block type: " + block._type);
399
+ break;
400
+ }
401
+ }
402
+ return blocks;
403
+ }
69
404
  }
@@ -1,3 +1,12 @@
1
+ import FilterCondition from "../../Filter/FilterCondition";
2
+ import NotificationRuleCondition from "./NotificationRuleCondition";
3
+
1
4
  export default interface BaseNotificationRule {
2
5
  _type: string;
6
+ // filters for notification rule
7
+ filterCondition: FilterCondition; // and OR or. Default is AND
8
+ filters: Array<NotificationRuleCondition>; // if this array is empty then it will be considered as all filters are matched.
9
+
10
+ shouldPostToExistingChannel: boolean;
11
+ existingChannelNames: string; // seperate by comma
3
12
  }
@@ -7,24 +7,23 @@ import Monitor from "../../../Models/DatabaseModels/Monitor";
7
7
  import MonitorStatus from "../../../Models/DatabaseModels/MonitorStatus";
8
8
  import ScheduledMaintenanceState from "../../../Models/DatabaseModels/ScheduledMaintenanceState";
9
9
  import { DropdownOption } from "../../../UI/Components/Dropdown/Dropdown";
10
- import ObjectID from "../../ObjectID";
11
10
  import WorkspaceType from "../WorkspaceType";
12
11
  import NotificationRuleEventType from "./EventType";
13
- import SlackNotificationRule from "./SlackNotificationRule";
12
+ import IncidentNotificationRule from "./NotificationRuleTypes/IncidentNotificationRule";
14
13
 
15
14
  export enum NotificationRuleConditionCheckOn {
16
15
  MonitorName = "Monitor Name",
17
- IncidentName = "Incident Name",
16
+ IncidentTitle = "Incident Title",
18
17
  IncidentDescription = "Incident Description",
19
18
  IncidentSeverity = "Incident Severity",
20
19
  IncidentState = "Incident State",
21
20
  MonitorType = "Monitor Type",
22
21
  MonitorStatus = "Monitor Status",
23
- AlertName = "Alert Name",
22
+ AlertTitle = "Alert Title",
24
23
  AlertDescription = "Alert Description",
25
24
  AlertSeverity = "Alert Severity",
26
25
  AlertState = "Alert State",
27
- ScheduledMaintenanceName = "Scheduled Maintenance Name",
26
+ ScheduledMaintenanceTitle = "Scheduled Maintenance Title",
28
27
  ScheduledMaintenanceDescription = "Scheduled Maintenance Description",
29
28
  ScheduledMaintenanceState = "Scheduled Maintenance State",
30
29
  IncidentLabels = "Incident Labels",
@@ -41,7 +40,7 @@ export enum ConditionType {
41
40
  LessThan = "Less Than",
42
41
  GreaterThanOrEqualTo = "Greater Than Or Equal To",
43
42
  LessThanOrEqualTo = "Less Than Or Equal To",
44
- Contains = "Contains",
43
+ ContainsAny = "Contains Any",
45
44
  NotContains = "Not Contains",
46
45
  StartsWith = "Starts With",
47
46
  EndsWith = "Ends With",
@@ -49,26 +48,18 @@ export enum ConditionType {
49
48
  IsNotEmpty = "Is Not Empty",
50
49
  True = "True",
51
50
  False = "False",
52
-
53
- // could be used for labels.
54
51
  ContainsAll = "Contains All",
55
52
  }
56
53
 
57
54
  export default interface NotificationRuleCondition {
58
55
  checkOn: NotificationRuleConditionCheckOn;
59
56
  conditionType: ConditionType | undefined;
60
- value:
61
- | string
62
- | number
63
- | boolean
64
- | Array<string>
65
- | Array<ObjectID>
66
- | undefined;
57
+ value: string | Array<string> | undefined;
67
58
  }
68
59
 
69
60
  export class NotificationRuleConditionUtil {
70
61
  public static getValidationError(data: {
71
- notificationRule: SlackNotificationRule;
62
+ notificationRule: IncidentNotificationRule;
72
63
  eventType: NotificationRuleEventType;
73
64
  workspaceType: WorkspaceType;
74
65
  }): string | null {
@@ -97,14 +88,14 @@ export class NotificationRuleConditionUtil {
97
88
 
98
89
  if (workspaceType === WorkspaceType.Slack) {
99
90
  if (
100
- !notificationRule.shouldCreateSlackChannel &&
101
- !notificationRule.shouldPostToExistingSlackChannel
91
+ !notificationRule.shouldCreateNewChannel &&
92
+ !notificationRule.shouldPostToExistingChannel
102
93
  ) {
103
94
  return "Please select either create slack channel or post to existing slack channel";
104
95
  }
105
96
 
106
- if (notificationRule.shouldPostToExistingSlackChannel) {
107
- if (!notificationRule.existingSlackChannelName?.trim()) {
97
+ if (notificationRule.shouldPostToExistingChannel) {
98
+ if (!notificationRule.existingChannelNames?.trim()) {
108
99
  return "Existing Slack channel name is required";
109
100
  }
110
101
  }
@@ -262,7 +253,7 @@ export class NotificationRuleConditionUtil {
262
253
  switch (eventType) {
263
254
  case NotificationRuleEventType.Incident:
264
255
  return [
265
- NotificationRuleConditionCheckOn.IncidentName,
256
+ NotificationRuleConditionCheckOn.IncidentTitle,
266
257
  NotificationRuleConditionCheckOn.IncidentDescription,
267
258
  NotificationRuleConditionCheckOn.IncidentSeverity,
268
259
  NotificationRuleConditionCheckOn.IncidentState,
@@ -272,7 +263,7 @@ export class NotificationRuleConditionUtil {
272
263
  ];
273
264
  case NotificationRuleEventType.Alert:
274
265
  return [
275
- NotificationRuleConditionCheckOn.AlertName,
266
+ NotificationRuleConditionCheckOn.AlertTitle,
276
267
  NotificationRuleConditionCheckOn.AlertDescription,
277
268
  NotificationRuleConditionCheckOn.AlertSeverity,
278
269
  NotificationRuleConditionCheckOn.AlertState,
@@ -292,7 +283,7 @@ export class NotificationRuleConditionUtil {
292
283
  ];
293
284
  case NotificationRuleEventType.ScheduledMaintenance:
294
285
  return [
295
- NotificationRuleConditionCheckOn.ScheduledMaintenanceName,
286
+ NotificationRuleConditionCheckOn.ScheduledMaintenanceTitle,
296
287
  NotificationRuleConditionCheckOn.ScheduledMaintenanceDescription,
297
288
  NotificationRuleConditionCheckOn.ScheduledMaintenanceState,
298
289
  NotificationRuleConditionCheckOn.ScheduledMaintenanceLabels,
@@ -309,42 +300,42 @@ export class NotificationRuleConditionUtil {
309
300
  ): Array<ConditionType> {
310
301
  switch (checkOn) {
311
302
  case NotificationRuleConditionCheckOn.MonitorName:
312
- case NotificationRuleConditionCheckOn.IncidentName:
303
+ case NotificationRuleConditionCheckOn.IncidentTitle:
313
304
  case NotificationRuleConditionCheckOn.IncidentDescription:
314
- case NotificationRuleConditionCheckOn.AlertName:
305
+ case NotificationRuleConditionCheckOn.AlertTitle:
315
306
  case NotificationRuleConditionCheckOn.AlertDescription:
316
- case NotificationRuleConditionCheckOn.ScheduledMaintenanceName:
307
+ case NotificationRuleConditionCheckOn.ScheduledMaintenanceTitle:
317
308
  case NotificationRuleConditionCheckOn.ScheduledMaintenanceDescription:
318
309
  return [
319
310
  ConditionType.EqualTo,
320
311
  ConditionType.NotEqualTo,
321
- ConditionType.Contains,
312
+ ConditionType.ContainsAny,
322
313
  ConditionType.NotContains,
323
314
  ConditionType.StartsWith,
324
315
  ConditionType.EndsWith,
325
316
  ];
326
317
  case NotificationRuleConditionCheckOn.IncidentSeverity:
327
318
  case NotificationRuleConditionCheckOn.AlertSeverity:
328
- return [ConditionType.Contains, ConditionType.NotContains];
319
+ return [ConditionType.ContainsAny, ConditionType.NotContains];
329
320
  case NotificationRuleConditionCheckOn.IncidentState:
330
321
  case NotificationRuleConditionCheckOn.AlertState:
331
322
  case NotificationRuleConditionCheckOn.MonitorStatus:
332
323
  case NotificationRuleConditionCheckOn.ScheduledMaintenanceState:
333
- return [ConditionType.Contains, ConditionType.NotContains];
324
+ return [ConditionType.ContainsAny, ConditionType.NotContains];
334
325
  case NotificationRuleConditionCheckOn.MonitorType:
335
- return [ConditionType.Contains, ConditionType.NotContains];
326
+ return [ConditionType.ContainsAny, ConditionType.NotContains];
336
327
  case NotificationRuleConditionCheckOn.AlertLabels:
337
328
  case NotificationRuleConditionCheckOn.IncidentLabels:
338
329
  case NotificationRuleConditionCheckOn.MonitorLabels:
339
330
  case NotificationRuleConditionCheckOn.ScheduledMaintenanceLabels:
340
331
  return [
341
- ConditionType.Contains,
332
+ ConditionType.ContainsAny,
342
333
  ConditionType.NotContains,
343
334
  ConditionType.ContainsAll,
344
335
  ];
345
336
  case NotificationRuleConditionCheckOn.Monitors:
346
337
  return [
347
- ConditionType.Contains,
338
+ ConditionType.ContainsAny,
348
339
  ConditionType.NotContains,
349
340
  ConditionType.ContainsAll,
350
341
  ];
@@ -0,0 +1,15 @@
1
+ import ObjectID from "../../../ObjectID";
2
+ import BaseNotificationRule from "../BaseNotificationRule";
3
+
4
+ export default interface AlertNotificationRule extends BaseNotificationRule {
5
+ _type: "AlertNotificationRule";
6
+
7
+ // if filters match then do:
8
+ shouldCreateNewChannel: boolean;
9
+ inviteTeamsToNewChannel: Array<ObjectID>;
10
+ inviteUsersToNewChannel: Array<ObjectID>;
11
+
12
+ shouldInviteOwnersToNewChannel: boolean;
13
+
14
+ shouldAutomaticallyInviteOnCallUsersToNewChannel: boolean;
15
+ }
@@ -0,0 +1,15 @@
1
+ import ObjectID from "../../../ObjectID";
2
+ import BaseNotificationRule from "../BaseNotificationRule";
3
+
4
+ export default interface IncidentNotificationRule extends BaseNotificationRule {
5
+ _type: "IncidentNotificationRule";
6
+
7
+ // if filters match then do:
8
+ shouldCreateNewChannel: boolean;
9
+ inviteTeamsToNewChannel: Array<ObjectID>;
10
+ inviteUsersToNewChannel: Array<ObjectID>;
11
+
12
+ shouldInviteOwnersToNewChannel: boolean;
13
+
14
+ shouldAutomaticallyInviteOnCallUsersToNewChannel: boolean;
15
+ }
@@ -0,0 +1,7 @@
1
+ import BaseNotificationRule from "../BaseNotificationRule";
2
+
3
+ // This rule is just used to post to existing channels.
4
+ export default interface MonitorStatusNotificationRule
5
+ extends BaseNotificationRule {
6
+ _type: "MonitorStatusNotificationRule";
7
+ }
@@ -0,0 +1,14 @@
1
+ import ObjectID from "../../../ObjectID";
2
+ import BaseNotificationRule from "../BaseNotificationRule";
3
+
4
+ export default interface ScheduledMaintenanceNotificationRule
5
+ extends BaseNotificationRule {
6
+ _type: "ScheduledMaintenanceNotificationRule";
7
+
8
+ // if filters match then do:
9
+ shouldCreateNewChannel: boolean;
10
+ inviteTeamsToNewChannel: Array<ObjectID>;
11
+ inviteUsersToNewChannel: Array<ObjectID>;
12
+
13
+ shouldInviteOwnersToNewChannel: boolean;
14
+ }