@oneuptime/common 8.0.5239 → 8.0.5283

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 (359) hide show
  1. package/Models/DatabaseModels/Index.ts +4 -2
  2. package/Models/DatabaseModels/OnCallDutyPolicyUserOverride.ts +5 -3
  3. package/Models/DatabaseModels/Project.ts +4 -2
  4. package/Models/DatabaseModels/ProjectSmtpConfig.ts +4 -2
  5. package/Models/DatabaseModels/StatusPageDomain.ts +6 -4
  6. package/Models/DatabaseModels/User.ts +0 -46
  7. package/Models/DatabaseModels/{UserTwoFactorAuth.ts → UserTotpAuth.ts} +16 -16
  8. package/Models/DatabaseModels/UserWebAuthn.ts +244 -0
  9. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +21 -0
  10. package/Server/API/BaseAPI.ts +4 -2
  11. package/Server/API/GlobalConfigAPI.ts +16 -12
  12. package/Server/API/MicrosoftTeamsAPI.ts +1240 -0
  13. package/Server/API/ProjectAPI.ts +4 -2
  14. package/Server/API/ResellerPlanAPI.ts +4 -2
  15. package/Server/API/SlackAPI.ts +54 -48
  16. package/Server/API/StatusPageAPI.ts +5 -3
  17. package/Server/API/UserOnCallLogTimelineAPI.ts +5 -3
  18. package/Server/API/{UserTwoFactorAuthAPI.ts → UserTotpAuthAPI.ts} +20 -20
  19. package/Server/API/UserWebAuthnAPI.ts +103 -0
  20. package/Server/EnvironmentConfig.ts +6 -0
  21. package/Server/Images/MicrosoftTeams/color.png +0 -0
  22. package/Server/Images/MicrosoftTeams/outline.png +0 -0
  23. package/Server/Infrastructure/Postgres/SchemaMigrations/1753131488925-AddEnableCustomSubscriberEmailNotificationFooterText.ts +4 -2
  24. package/Server/Infrastructure/Postgres/SchemaMigrations/1759175457008-MigrationName.ts +27 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1759232954703-MigrationName.ts +25 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1759234532998-MigrationName.ts +15 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  28. package/Server/Infrastructure/Queue.ts +4 -2
  29. package/Server/Infrastructure/SocketIO.ts +4 -2
  30. package/Server/Middleware/ProjectAuthorization.ts +5 -3
  31. package/Server/Middleware/SlackAuthorization.ts +2 -2
  32. package/Server/Middleware/TelemetryIngest.ts +12 -6
  33. package/Server/Services/AlertStateTimelineService.ts +34 -18
  34. package/Server/Services/BillingInvoiceService.ts +8 -4
  35. package/Server/Services/BillingService.ts +13 -9
  36. package/Server/Services/DatabaseService.ts +42 -30
  37. package/Server/Services/IncidentService.ts +5 -3
  38. package/Server/Services/IncidentStateTimelineService.ts +34 -18
  39. package/Server/Services/Index.ts +4 -2
  40. package/Server/Services/MonitorStatusTimelineService.ts +34 -18
  41. package/Server/Services/OnCallDutyPolicyScheduleService.ts +4 -2
  42. package/Server/Services/ProjectService.ts +6 -4
  43. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +26 -14
  44. package/Server/Services/StatusPageService.ts +4 -2
  45. package/Server/Services/UserService.ts +21 -5
  46. package/Server/Services/{UserTwoFactorAuthService.ts → UserTotpAuthService.ts} +26 -7
  47. package/Server/Services/UserWebAuthnService.ts +419 -0
  48. package/Server/Services/WorkspaceNotificationRuleService.ts +257 -77
  49. package/Server/Services/WorkspaceProjectAuthTokenService.ts +2 -2
  50. package/Server/Types/AnalyticsDatabase/ModelPermission.ts +9 -5
  51. package/Server/Types/Database/Permissions/BasePermission.ts +4 -2
  52. package/Server/Types/Database/Permissions/TenantPermission.ts +5 -3
  53. package/Server/Types/Database/QueryHelper.ts +4 -2
  54. package/Server/Types/Markdown.ts +6 -4
  55. package/Server/Types/Workflow/ComponentCode.ts +4 -2
  56. package/Server/Types/Workflow/Components/Conditions/IfElse.ts +5 -3
  57. package/Server/Types/Workflow/Components/JavaScript.ts +5 -3
  58. package/Server/Types/Workflow/TriggerCode.ts +4 -2
  59. package/Server/Utils/AnalyticsDatabase/Statement.ts +4 -2
  60. package/Server/Utils/AnalyticsDatabase/StatementGenerator.ts +21 -11
  61. package/Server/Utils/Browser.ts +6 -4
  62. package/Server/Utils/CodeRepository/GitHub/GitHub.ts +4 -2
  63. package/Server/Utils/LocalFile.ts +14 -0
  64. package/Server/Utils/Monitor/MonitorResource.ts +17 -9
  65. package/Server/Utils/Realtime.ts +4 -2
  66. package/Server/Utils/StartServer.ts +1 -1
  67. package/Server/Utils/Telemetry.ts +15 -9
  68. package/Server/Utils/{TwoFactorAuth.ts → TotpAuth.ts} +2 -2
  69. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.ts +75 -16
  70. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +649 -0
  71. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +237 -0
  72. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +1321 -0
  73. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.ts +155 -0
  74. package/Server/Utils/Workspace/MicrosoftTeams/Actions/OnCallDutyPolicy.ts +119 -0
  75. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +959 -0
  76. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.ts +16 -14
  77. package/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.ts +17 -14
  78. package/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.ts +18 -13
  79. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +2547 -14
  80. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +4 -2
  81. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +4 -2
  82. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +14 -10
  83. package/Server/Utils/Workspace/Slack/Actions/Monitor.ts +4 -2
  84. package/Server/Utils/Workspace/Slack/Actions/OnCallDutyPolicy.ts +4 -2
  85. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +14 -10
  86. package/Server/Utils/Workspace/Slack/Messages/Alert.ts +9 -7
  87. package/Server/Utils/Workspace/Slack/Messages/Incident.ts +9 -7
  88. package/Server/Utils/Workspace/Slack/Messages/Monitor.ts +9 -7
  89. package/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.ts +9 -7
  90. package/Server/Utils/Workspace/Slack/Slack.ts +6 -0
  91. package/Server/Utils/Workspace/Workspace.ts +13 -10
  92. package/Server/Utils/Workspace/WorkspaceBase.ts +9 -0
  93. package/Tests/Server/API/BaseAPI.test.ts +64 -52
  94. package/Tests/Server/Services/BillingService.test.ts +4 -4
  95. package/Tests/Server/Services/TeamMemberService.test.ts +20 -12
  96. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +2 -2
  97. package/Tests/Types/OnCallDutyPolicy/LayerUtil.test.ts +8 -4
  98. package/Tests/UI/Components/DictionaryOfStrings.test.tsx +4 -2
  99. package/Tests/UI/Components/FilePicker.test.tsx +2 -2
  100. package/Tests/Utils/API.test.ts +9 -8
  101. package/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.ts +5 -3
  102. package/Types/Html.ts +5 -3
  103. package/Types/JSONFunctions.ts +5 -5
  104. package/Types/Metrics/MetricsQuery.ts +6 -4
  105. package/Types/Monitor/MonitorType.ts +8 -6
  106. package/Types/OnCallDutyPolicy/Layer.ts +29 -17
  107. package/Types/Phone.ts +5 -3
  108. package/Types/Workspace/NotificationRules/BaseNotificationRule.ts +1 -0
  109. package/Types/Workspace/NotificationRules/CreateChannelNotificationRule.ts +5 -2
  110. package/Types/Workspace/WorkspaceMessagePayload.ts +1 -0
  111. package/Types/Workspace/WorkspaceType.ts +13 -0
  112. package/UI/Components/Charts/Utils/DataPoint.ts +8 -6
  113. package/UI/Components/Detail/Detail.tsx +4 -1
  114. package/UI/Components/FilePicker/FilePicker.tsx +1 -1
  115. package/UI/Components/Forms/Types/Field.ts +4 -2
  116. package/UI/Components/Image/Image.tsx +1 -1
  117. package/UI/Components/JSONTable/JSONTable.tsx +4 -2
  118. package/UI/Components/ModelTable/BaseModelTable.tsx +5 -3
  119. package/UI/Components/SideMenu/SideMenu.tsx +4 -2
  120. package/UI/Components/SideMenu/SideMenuItem.tsx +69 -45
  121. package/UI/Config.ts +3 -0
  122. package/UI/Utils/API/API.ts +5 -3
  123. package/UI/Utils/Countries.ts +5 -3
  124. package/UI/Utils/Login.ts +6 -1
  125. package/Utils/Base64.ts +13 -0
  126. package/Utils/Schema/ModelSchema.ts +4 -2
  127. package/build/dist/Models/DatabaseModels/Index.js +4 -2
  128. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  129. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js +5 -3
  130. package/build/dist/Models/DatabaseModels/OnCallDutyPolicyUserOverride.js.map +1 -1
  131. package/build/dist/Models/DatabaseModels/Project.js +4 -2
  132. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  133. package/build/dist/Models/DatabaseModels/ProjectSmtpConfig.js +4 -2
  134. package/build/dist/Models/DatabaseModels/ProjectSmtpConfig.js.map +1 -1
  135. package/build/dist/Models/DatabaseModels/StatusPageDomain.js +6 -4
  136. package/build/dist/Models/DatabaseModels/StatusPageDomain.js.map +1 -1
  137. package/build/dist/Models/DatabaseModels/User.js +0 -49
  138. package/build/dist/Models/DatabaseModels/User.js.map +1 -1
  139. package/build/dist/Models/DatabaseModels/{UserTwoFactorAuth.js → UserTotpAuth.js} +27 -27
  140. package/build/dist/Models/DatabaseModels/UserTotpAuth.js.map +1 -0
  141. package/build/dist/Models/DatabaseModels/UserWebAuthn.js +270 -0
  142. package/build/dist/Models/DatabaseModels/UserWebAuthn.js.map +1 -0
  143. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  144. package/build/dist/Server/API/BaseAPI.js +4 -2
  145. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  146. package/build/dist/Server/API/GlobalConfigAPI.js +16 -12
  147. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  148. package/build/dist/Server/API/MicrosoftTeamsAPI.js +771 -0
  149. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -0
  150. package/build/dist/Server/API/ProjectAPI.js +4 -2
  151. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  152. package/build/dist/Server/API/ResellerPlanAPI.js +4 -2
  153. package/build/dist/Server/API/ResellerPlanAPI.js.map +1 -1
  154. package/build/dist/Server/API/SlackAPI.js +53 -47
  155. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  156. package/build/dist/Server/API/StatusPageAPI.js +5 -3
  157. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  158. package/build/dist/Server/API/UserOnCallLogTimelineAPI.js +5 -3
  159. package/build/dist/Server/API/UserOnCallLogTimelineAPI.js.map +1 -1
  160. package/build/dist/Server/API/{UserTwoFactorAuthAPI.js → UserTotpAuthAPI.js} +16 -16
  161. package/build/dist/Server/API/UserTotpAuthAPI.js.map +1 -0
  162. package/build/dist/Server/API/UserWebAuthnAPI.js +65 -0
  163. package/build/dist/Server/API/UserWebAuthnAPI.js.map +1 -0
  164. package/build/dist/Server/EnvironmentConfig.js +3 -0
  165. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  166. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1753131488925-AddEnableCustomSubscriberEmailNotificationFooterText.js +4 -2
  167. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1753131488925-AddEnableCustomSubscriberEmailNotificationFooterText.js.map +1 -1
  168. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1759175457008-MigrationName.js +16 -0
  169. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1759175457008-MigrationName.js.map +1 -0
  170. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1759232954703-MigrationName.js +16 -0
  171. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1759232954703-MigrationName.js.map +1 -0
  172. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1759234532998-MigrationName.js +12 -0
  173. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1759234532998-MigrationName.js.map +1 -0
  174. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  175. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  176. package/build/dist/Server/Infrastructure/Queue.js +4 -2
  177. package/build/dist/Server/Infrastructure/Queue.js.map +1 -1
  178. package/build/dist/Server/Infrastructure/SocketIO.js +4 -2
  179. package/build/dist/Server/Infrastructure/SocketIO.js.map +1 -1
  180. package/build/dist/Server/Middleware/ProjectAuthorization.js +5 -3
  181. package/build/dist/Server/Middleware/ProjectAuthorization.js.map +1 -1
  182. package/build/dist/Server/Middleware/SlackAuthorization.js.map +1 -1
  183. package/build/dist/Server/Middleware/TelemetryIngest.js +12 -6
  184. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  185. package/build/dist/Server/Services/AlertStateTimelineService.js +34 -18
  186. package/build/dist/Server/Services/AlertStateTimelineService.js.map +1 -1
  187. package/build/dist/Server/Services/BillingInvoiceService.js +8 -4
  188. package/build/dist/Server/Services/BillingInvoiceService.js.map +1 -1
  189. package/build/dist/Server/Services/BillingService.js +13 -9
  190. package/build/dist/Server/Services/BillingService.js.map +1 -1
  191. package/build/dist/Server/Services/DatabaseService.js +40 -28
  192. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  193. package/build/dist/Server/Services/IncidentService.js +5 -3
  194. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  195. package/build/dist/Server/Services/IncidentStateTimelineService.js +34 -18
  196. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  197. package/build/dist/Server/Services/Index.js +4 -2
  198. package/build/dist/Server/Services/Index.js.map +1 -1
  199. package/build/dist/Server/Services/MonitorStatusTimelineService.js +34 -18
  200. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  201. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +4 -2
  202. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  203. package/build/dist/Server/Services/ProjectService.js +6 -4
  204. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  205. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +26 -14
  206. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  207. package/build/dist/Server/Services/StatusPageService.js +4 -2
  208. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  209. package/build/dist/Server/Services/UserService.js +16 -3
  210. package/build/dist/Server/Services/UserService.js.map +1 -1
  211. package/build/dist/Server/Services/{UserTwoFactorAuthService.js → UserTotpAuthService.js} +22 -8
  212. package/build/dist/Server/Services/UserTotpAuthService.js.map +1 -0
  213. package/build/dist/Server/Services/UserWebAuthnService.js +365 -0
  214. package/build/dist/Server/Services/UserWebAuthnService.js.map +1 -0
  215. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +142 -51
  216. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  217. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js +9 -5
  218. package/build/dist/Server/Types/AnalyticsDatabase/ModelPermission.js.map +1 -1
  219. package/build/dist/Server/Types/Database/Permissions/BasePermission.js +4 -2
  220. package/build/dist/Server/Types/Database/Permissions/BasePermission.js.map +1 -1
  221. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js +5 -3
  222. package/build/dist/Server/Types/Database/Permissions/TenantPermission.js.map +1 -1
  223. package/build/dist/Server/Types/Database/QueryHelper.js +4 -2
  224. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  225. package/build/dist/Server/Types/Markdown.js +6 -4
  226. package/build/dist/Server/Types/Markdown.js.map +1 -1
  227. package/build/dist/Server/Types/Workflow/ComponentCode.js +4 -2
  228. package/build/dist/Server/Types/Workflow/ComponentCode.js.map +1 -1
  229. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js +5 -3
  230. package/build/dist/Server/Types/Workflow/Components/Conditions/IfElse.js.map +1 -1
  231. package/build/dist/Server/Types/Workflow/Components/JavaScript.js +5 -3
  232. package/build/dist/Server/Types/Workflow/Components/JavaScript.js.map +1 -1
  233. package/build/dist/Server/Types/Workflow/TriggerCode.js.map +1 -1
  234. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js +4 -2
  235. package/build/dist/Server/Utils/AnalyticsDatabase/Statement.js.map +1 -1
  236. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js +21 -11
  237. package/build/dist/Server/Utils/AnalyticsDatabase/StatementGenerator.js.map +1 -1
  238. package/build/dist/Server/Utils/Browser.js +6 -4
  239. package/build/dist/Server/Utils/Browser.js.map +1 -1
  240. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js +4 -2
  241. package/build/dist/Server/Utils/CodeRepository/GitHub/GitHub.js.map +1 -1
  242. package/build/dist/Server/Utils/LocalFile.js +16 -0
  243. package/build/dist/Server/Utils/LocalFile.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/MonitorResource.js +17 -9
  245. package/build/dist/Server/Utils/Monitor/MonitorResource.js.map +1 -1
  246. package/build/dist/Server/Utils/Realtime.js +4 -2
  247. package/build/dist/Server/Utils/Realtime.js.map +1 -1
  248. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  249. package/build/dist/Server/Utils/Telemetry.js +6 -4
  250. package/build/dist/Server/Utils/Telemetry.js.map +1 -1
  251. package/build/dist/Server/Utils/{TwoFactorAuth.js → TotpAuth.js} +8 -8
  252. package/build/dist/Server/Utils/TotpAuth.js.map +1 -0
  253. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js +86 -36
  254. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ActionTypes.js.map +1 -1
  255. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +531 -0
  256. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -0
  257. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +206 -0
  258. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -0
  259. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +1102 -0
  260. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -0
  261. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js +136 -0
  262. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js.map +1 -0
  263. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/OnCallDutyPolicy.js +107 -0
  264. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/OnCallDutyPolicy.js.map +1 -0
  265. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +795 -0
  266. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -0
  267. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.js +16 -14
  268. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Alert.js.map +1 -1
  269. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js +16 -14
  270. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/Incident.js.map +1 -1
  271. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.js +15 -13
  272. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Messages/ScheduledMaintenance.js.map +1 -1
  273. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +1982 -13
  274. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  275. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +4 -2
  276. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -1
  277. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +4 -2
  278. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  279. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +14 -10
  280. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  281. package/build/dist/Server/Utils/Workspace/Slack/Actions/Monitor.js +4 -2
  282. package/build/dist/Server/Utils/Workspace/Slack/Actions/Monitor.js.map +1 -1
  283. package/build/dist/Server/Utils/Workspace/Slack/Actions/OnCallDutyPolicy.js +4 -2
  284. package/build/dist/Server/Utils/Workspace/Slack/Actions/OnCallDutyPolicy.js.map +1 -1
  285. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +14 -10
  286. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -1
  287. package/build/dist/Server/Utils/Workspace/Slack/Messages/Alert.js +9 -7
  288. package/build/dist/Server/Utils/Workspace/Slack/Messages/Alert.js.map +1 -1
  289. package/build/dist/Server/Utils/Workspace/Slack/Messages/Incident.js +9 -7
  290. package/build/dist/Server/Utils/Workspace/Slack/Messages/Incident.js.map +1 -1
  291. package/build/dist/Server/Utils/Workspace/Slack/Messages/Monitor.js +9 -7
  292. package/build/dist/Server/Utils/Workspace/Slack/Messages/Monitor.js.map +1 -1
  293. package/build/dist/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.js +9 -7
  294. package/build/dist/Server/Utils/Workspace/Slack/Messages/ScheduledMaintenance.js.map +1 -1
  295. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +5 -0
  296. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  297. package/build/dist/Server/Utils/Workspace/Workspace.js +12 -10
  298. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  299. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  300. package/build/dist/Tests/Server/API/BaseAPI.test.js +59 -47
  301. package/build/dist/Tests/Server/API/BaseAPI.test.js.map +1 -1
  302. package/build/dist/Tests/Server/Services/BillingService.test.js +4 -4
  303. package/build/dist/Tests/Server/Services/BillingService.test.js.map +1 -1
  304. package/build/dist/Tests/Server/Services/TeamMemberService.test.js +20 -12
  305. package/build/dist/Tests/Server/Services/TeamMemberService.test.js.map +1 -1
  306. package/build/dist/Tests/Server/TestingUtils/Services/BillingServiceHelper.js +2 -2
  307. package/build/dist/Tests/Server/TestingUtils/Services/BillingServiceHelper.js.map +1 -1
  308. package/build/dist/Tests/Types/OnCallDutyPolicy/LayerUtil.test.js +8 -4
  309. package/build/dist/Tests/Types/OnCallDutyPolicy/LayerUtil.test.js.map +1 -1
  310. package/build/dist/Tests/UI/Components/DictionaryOfStrings.test.js +4 -2
  311. package/build/dist/Tests/UI/Components/DictionaryOfStrings.test.js.map +1 -1
  312. package/build/dist/Tests/UI/Components/FilePicker.test.js +2 -2
  313. package/build/dist/Tests/UI/Components/FilePicker.test.js.map +1 -1
  314. package/build/dist/Tests/Utils/API.test.js +8 -7
  315. package/build/dist/Tests/Utils/API.test.js.map +1 -1
  316. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js +5 -3
  317. package/build/dist/Types/BaseDatabase/DatabaseCommonInteractionPropsUtil.js.map +1 -1
  318. package/build/dist/Types/Html.js +5 -3
  319. package/build/dist/Types/Html.js.map +1 -1
  320. package/build/dist/Types/JSONFunctions.js +5 -5
  321. package/build/dist/Types/JSONFunctions.js.map +1 -1
  322. package/build/dist/Types/Monitor/MonitorType.js +8 -6
  323. package/build/dist/Types/Monitor/MonitorType.js.map +1 -1
  324. package/build/dist/Types/OnCallDutyPolicy/Layer.js +29 -17
  325. package/build/dist/Types/OnCallDutyPolicy/Layer.js.map +1 -1
  326. package/build/dist/Types/Phone.js +5 -3
  327. package/build/dist/Types/Phone.js.map +1 -1
  328. package/build/dist/Types/Workspace/WorkspaceType.js +9 -0
  329. package/build/dist/Types/Workspace/WorkspaceType.js.map +1 -1
  330. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +8 -6
  331. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  332. package/build/dist/UI/Components/Detail/Detail.js +4 -1
  333. package/build/dist/UI/Components/Detail/Detail.js.map +1 -1
  334. package/build/dist/UI/Components/FilePicker/FilePicker.js +1 -1
  335. package/build/dist/UI/Components/FilePicker/FilePicker.js.map +1 -1
  336. package/build/dist/UI/Components/Image/Image.js +1 -1
  337. package/build/dist/UI/Components/Image/Image.js.map +1 -1
  338. package/build/dist/UI/Components/JSONTable/JSONTable.js.map +1 -1
  339. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  340. package/build/dist/UI/Components/SideMenu/SideMenu.js +4 -2
  341. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  342. package/build/dist/UI/Components/SideMenu/SideMenuItem.js +62 -38
  343. package/build/dist/UI/Components/SideMenu/SideMenuItem.js.map +1 -1
  344. package/build/dist/UI/Config.js +1 -0
  345. package/build/dist/UI/Config.js.map +1 -1
  346. package/build/dist/UI/Utils/API/API.js +5 -3
  347. package/build/dist/UI/Utils/API/API.js.map +1 -1
  348. package/build/dist/UI/Utils/Countries.js.map +1 -1
  349. package/build/dist/UI/Utils/Login.js +6 -1
  350. package/build/dist/UI/Utils/Login.js.map +1 -1
  351. package/build/dist/Utils/Base64.js +12 -0
  352. package/build/dist/Utils/Base64.js.map +1 -0
  353. package/build/dist/Utils/Schema/ModelSchema.js +4 -2
  354. package/build/dist/Utils/Schema/ModelSchema.js.map +1 -1
  355. package/package.json +5 -1
  356. package/build/dist/Models/DatabaseModels/UserTwoFactorAuth.js.map +0 -1
  357. package/build/dist/Server/API/UserTwoFactorAuthAPI.js.map +0 -1
  358. package/build/dist/Server/Services/UserTwoFactorAuthService.js.map +0 -1
  359. package/build/dist/Server/Utils/TwoFactorAuth.js.map +0 -1
@@ -0,0 +1,1321 @@
1
+ import { ExpressRequest, ExpressResponse } from "../../../Express";
2
+ import Response from "../../../Response";
3
+ import MicrosoftTeamsAuthAction, {
4
+ MicrosoftTeamsAction,
5
+ MicrosoftTeamsRequest,
6
+ } from "./Auth";
7
+ import { MicrosoftTeamsIncidentActionType } from "./ActionTypes";
8
+ import logger from "../../../Logger";
9
+ import ObjectID from "../../../../../Types/ObjectID";
10
+ import IncidentService from "../../../../Services/IncidentService";
11
+ import Incident from "../../../../../Models/DatabaseModels/Incident";
12
+ import CaptureSpan from "../../../Telemetry/CaptureSpan";
13
+ import { TurnContext } from "botbuilder";
14
+ import { JSONObject, JSONValue } from "../../../../../Types/JSON";
15
+ import IncidentPublicNoteService from "../../../../Services/IncidentPublicNoteService";
16
+ import IncidentInternalNoteService from "../../../../Services/IncidentInternalNoteService";
17
+ import OnCallDutyPolicyService from "../../../../Services/OnCallDutyPolicyService";
18
+ import IncidentStateService from "../../../../Services/IncidentStateService";
19
+ import UserNotificationEventType from "../../../../../Types/UserNotification/UserNotificationEventType";
20
+ import OnCallDutyPolicy from "../../../../../Models/DatabaseModels/OnCallDutyPolicy";
21
+ import IncidentState from "../../../../../Models/DatabaseModels/IncidentState";
22
+ import IncidentSeverityService from "../../../../Services/IncidentSeverityService";
23
+ import IncidentSeverity from "../../../../../Models/DatabaseModels/IncidentSeverity";
24
+ import MonitorService from "../../../../Services/MonitorService";
25
+ import Monitor from "../../../../../Models/DatabaseModels/Monitor";
26
+ import MonitorStatusService from "../../../../Services/MonitorStatusService";
27
+ import MonitorStatus from "../../../../../Models/DatabaseModels/MonitorStatus";
28
+ import LabelService from "../../../../Services/LabelService";
29
+ import Label from "../../../../../Models/DatabaseModels/Label";
30
+ import SortOrder from "../../../../../Types/BaseDatabase/SortOrder";
31
+ import { LIMIT_PER_PROJECT } from "../../../../../Types/Database/LimitMax";
32
+ import BadDataException from "../../../../../Types/Exception/BadDataException";
33
+ import URL from "../../../../../Types/API/URL";
34
+
35
+ export default class MicrosoftTeamsIncidentActions {
36
+ @CaptureSpan()
37
+ public static isIncidentAction(data: { actionType: string }): boolean {
38
+ // Check if the action is related to incidents
39
+ return (
40
+ data.actionType === MicrosoftTeamsIncidentActionType.AckIncident ||
41
+ data.actionType === MicrosoftTeamsIncidentActionType.ResolveIncident ||
42
+ data.actionType === MicrosoftTeamsIncidentActionType.ViewIncident ||
43
+ data.actionType === MicrosoftTeamsIncidentActionType.IncidentCreated ||
44
+ data.actionType ===
45
+ MicrosoftTeamsIncidentActionType.IncidentStateChanged ||
46
+ data.actionType ===
47
+ MicrosoftTeamsIncidentActionType.ViewAddIncidentNote ||
48
+ data.actionType === MicrosoftTeamsIncidentActionType.SubmitIncidentNote ||
49
+ data.actionType ===
50
+ MicrosoftTeamsIncidentActionType.ExecuteIncidentOnCallPolicy ||
51
+ data.actionType ===
52
+ MicrosoftTeamsIncidentActionType.ViewExecuteIncidentOnCallPolicy ||
53
+ data.actionType ===
54
+ MicrosoftTeamsIncidentActionType.SubmitExecuteIncidentOnCallPolicy ||
55
+ data.actionType ===
56
+ MicrosoftTeamsIncidentActionType.ViewChangeIncidentState ||
57
+ data.actionType ===
58
+ MicrosoftTeamsIncidentActionType.SubmitChangeIncidentState ||
59
+ data.actionType === MicrosoftTeamsIncidentActionType.NewIncident ||
60
+ data.actionType === MicrosoftTeamsIncidentActionType.SubmitNewIncident
61
+ );
62
+ }
63
+
64
+ @CaptureSpan()
65
+ public static async handleIncidentAction(data: {
66
+ teamsRequest: MicrosoftTeamsRequest;
67
+ action: MicrosoftTeamsAction;
68
+ req: ExpressRequest;
69
+ res: ExpressResponse;
70
+ }): Promise<void> {
71
+ const { teamsRequest, action } = data;
72
+
73
+ logger.debug("Handling Microsoft Teams incident action:");
74
+ logger.debug(action);
75
+
76
+ try {
77
+ switch (action.actionType) {
78
+ case MicrosoftTeamsIncidentActionType.AckIncident:
79
+ await this.acknowledgeIncident({
80
+ teamsRequest,
81
+ action,
82
+ });
83
+ break;
84
+
85
+ case MicrosoftTeamsIncidentActionType.ResolveIncident:
86
+ await this.resolveIncident({
87
+ teamsRequest,
88
+ action,
89
+ });
90
+ break;
91
+
92
+ case MicrosoftTeamsIncidentActionType.ViewIncident:
93
+ // This is handled by opening the URL directly
94
+ break;
95
+
96
+ case MicrosoftTeamsIncidentActionType.NewIncident:
97
+ return await this.showNewIncidentCard(data);
98
+
99
+ case MicrosoftTeamsIncidentActionType.SubmitNewIncident:
100
+ /*
101
+ * This is handled by handleBotIncidentAction through bot framework
102
+ * Don't process it here to avoid duplicate messages
103
+ */
104
+ break;
105
+
106
+ default:
107
+ logger.debug("Unhandled incident action: " + action.actionType);
108
+ break;
109
+ }
110
+ } catch (error) {
111
+ logger.error("Error handling Microsoft Teams incident action:");
112
+ logger.error(error);
113
+ }
114
+
115
+ // Send empty response to Teams
116
+ Response.sendTextResponse(data.req, data.res, "");
117
+ }
118
+
119
+ @CaptureSpan()
120
+ private static async acknowledgeIncident(data: {
121
+ teamsRequest: MicrosoftTeamsRequest;
122
+ action: MicrosoftTeamsAction;
123
+ }): Promise<void> {
124
+ const incidentId: string = data.action.actionValue || "";
125
+
126
+ if (!incidentId) {
127
+ logger.error("No incident ID provided for acknowledge action");
128
+ return;
129
+ }
130
+
131
+ logger.debug("Acknowledging incident: " + incidentId);
132
+
133
+ try {
134
+ // Get the incident
135
+ const incident: Incident | null = await IncidentService.findOneBy({
136
+ query: {
137
+ _id: incidentId,
138
+ projectId: data.teamsRequest.projectId,
139
+ },
140
+ select: {
141
+ _id: true,
142
+ projectId: true,
143
+ currentIncidentState: {
144
+ _id: true,
145
+ name: true,
146
+ isAcknowledgedState: true,
147
+ },
148
+ },
149
+ props: {
150
+ isRoot: true,
151
+ },
152
+ });
153
+
154
+ if (!incident) {
155
+ logger.error("Incident not found: " + incidentId);
156
+ return;
157
+ }
158
+
159
+ // Check if already acknowledged
160
+ if (incident.currentIncidentState?.isAcknowledgedState) {
161
+ logger.debug("Incident is already acknowledged");
162
+ return;
163
+ }
164
+
165
+ // Acknowledge the incident
166
+ const oneUptimeUserId: ObjectID =
167
+ await MicrosoftTeamsAuthAction.getOneUptimeUserIdFromTeamsUserId({
168
+ teamsUserId: data.teamsRequest.userId || "",
169
+ projectId: data.teamsRequest.projectId,
170
+ });
171
+
172
+ await IncidentService.acknowledgeIncident(
173
+ new ObjectID(incidentId),
174
+ oneUptimeUserId,
175
+ );
176
+
177
+ logger.debug("Incident acknowledged successfully");
178
+ } catch (error) {
179
+ logger.error("Error acknowledging incident:");
180
+ logger.error(error);
181
+ }
182
+ }
183
+
184
+ @CaptureSpan()
185
+ private static async resolveIncident(data: {
186
+ teamsRequest: MicrosoftTeamsRequest;
187
+ action: MicrosoftTeamsAction;
188
+ }): Promise<void> {
189
+ const incidentId: string = data.action.actionValue || "";
190
+
191
+ if (!incidentId) {
192
+ logger.error("No incident ID provided for resolve action");
193
+ return;
194
+ }
195
+
196
+ logger.debug("Resolving incident: " + incidentId);
197
+
198
+ try {
199
+ // Get the incident
200
+ const incident: Incident | null = await IncidentService.findOneBy({
201
+ query: {
202
+ _id: incidentId,
203
+ projectId: data.teamsRequest.projectId,
204
+ },
205
+ select: {
206
+ _id: true,
207
+ projectId: true,
208
+ currentIncidentState: {
209
+ _id: true,
210
+ name: true,
211
+ isResolvedState: true,
212
+ },
213
+ },
214
+ props: {
215
+ isRoot: true,
216
+ },
217
+ });
218
+
219
+ if (!incident) {
220
+ logger.error("Incident not found: " + incidentId);
221
+ return;
222
+ }
223
+
224
+ // Check if already resolved
225
+ if (incident.currentIncidentState?.isResolvedState) {
226
+ logger.debug("Incident is already resolved");
227
+ return;
228
+ }
229
+
230
+ // Resolve the incident
231
+ const oneUptimeUserId: ObjectID =
232
+ await MicrosoftTeamsAuthAction.getOneUptimeUserIdFromTeamsUserId({
233
+ teamsUserId: data.teamsRequest.userId || "",
234
+ projectId: data.teamsRequest.projectId,
235
+ });
236
+
237
+ await IncidentService.resolveIncident(
238
+ new ObjectID(incidentId),
239
+ oneUptimeUserId,
240
+ );
241
+
242
+ logger.debug("Incident resolved successfully");
243
+ } catch (error) {
244
+ logger.error("Error resolving incident:");
245
+ logger.error(error);
246
+ }
247
+ }
248
+
249
+ @CaptureSpan()
250
+ public static async handleBotIncidentAction(data: {
251
+ actionType: string;
252
+ actionValue: string;
253
+ value: JSONObject;
254
+ projectId: ObjectID;
255
+ oneUptimeUserId: ObjectID;
256
+ turnContext: TurnContext;
257
+ }): Promise<void> {
258
+ const {
259
+ actionType,
260
+ actionValue,
261
+ value,
262
+ projectId,
263
+ oneUptimeUserId,
264
+ turnContext,
265
+ } = data;
266
+
267
+ if (actionType === MicrosoftTeamsIncidentActionType.AckIncident) {
268
+ if (!actionValue) {
269
+ await turnContext.sendActivity(
270
+ "Unable to acknowledge: missing incident id.",
271
+ );
272
+ return;
273
+ }
274
+
275
+ await IncidentService.acknowledgeIncident(
276
+ new ObjectID(actionValue),
277
+ oneUptimeUserId,
278
+ );
279
+ await turnContext.sendActivity("✅ Incident acknowledged.");
280
+ return;
281
+ }
282
+
283
+ if (actionType === MicrosoftTeamsIncidentActionType.ResolveIncident) {
284
+ if (!actionValue) {
285
+ await turnContext.sendActivity(
286
+ "Unable to resolve: missing incident id.",
287
+ );
288
+ return;
289
+ }
290
+
291
+ await IncidentService.resolveIncident(
292
+ new ObjectID(actionValue),
293
+ oneUptimeUserId,
294
+ );
295
+ await turnContext.sendActivity("✅ Incident resolved.");
296
+ return;
297
+ }
298
+
299
+ if (actionType === MicrosoftTeamsIncidentActionType.ViewIncident) {
300
+ if (!actionValue) {
301
+ await turnContext.sendActivity(
302
+ "Unable to view incident: missing incident id.",
303
+ );
304
+ return;
305
+ }
306
+
307
+ const incident: Incident | null = await IncidentService.findOneBy({
308
+ query: {
309
+ _id: actionValue,
310
+ projectId: projectId,
311
+ },
312
+ select: {
313
+ _id: true,
314
+ title: true,
315
+ description: true,
316
+ currentIncidentState: {
317
+ name: true,
318
+ },
319
+ incidentSeverity: {
320
+ name: true,
321
+ },
322
+ createdAt: true,
323
+ },
324
+ props: {
325
+ isRoot: true,
326
+ },
327
+ });
328
+
329
+ if (!incident) {
330
+ await turnContext.sendActivity("Incident not found.");
331
+ return;
332
+ }
333
+
334
+ const message: string = `**Incident Details**\n\n**Title:** ${incident.title}\n**Description:** ${incident.description || "No description"}\n**State:** ${incident.currentIncidentState?.name || "Unknown"}\n**Severity:** ${incident.incidentSeverity?.name || "Unknown"}\n**Created At:** ${incident.createdAt ? new Date(incident.createdAt).toLocaleString() : "Unknown"}`;
335
+
336
+ await turnContext.sendActivity(message);
337
+ return;
338
+ }
339
+
340
+ if (actionType === MicrosoftTeamsIncidentActionType.ViewAddIncidentNote) {
341
+ if (!actionValue) {
342
+ await turnContext.sendActivity(
343
+ "Unable to add note: missing incident id.",
344
+ );
345
+ return;
346
+ }
347
+
348
+ // Send the input card
349
+ const card: JSONObject = this.buildAddIncidentNoteCard(actionValue);
350
+ await turnContext.sendActivity({
351
+ attachments: [
352
+ {
353
+ contentType: "application/vnd.microsoft.card.adaptive",
354
+ content: card,
355
+ },
356
+ ],
357
+ });
358
+ return;
359
+ }
360
+
361
+ if (actionType === MicrosoftTeamsIncidentActionType.SubmitIncidentNote) {
362
+ if (!actionValue) {
363
+ await turnContext.sendActivity(
364
+ "Unable to add note: missing incident id.",
365
+ );
366
+ return;
367
+ }
368
+
369
+ // Check if form data is provided
370
+ const noteType: JSONValue = value["noteType"];
371
+ const note: JSONValue = value["note"];
372
+
373
+ if (noteType && note) {
374
+ // Submit the note
375
+ const incidentId: ObjectID = new ObjectID(actionValue);
376
+
377
+ if (noteType === "public") {
378
+ await IncidentPublicNoteService.addNote({
379
+ incidentId: incidentId,
380
+ note: note.toString(),
381
+ projectId: projectId,
382
+ userId: oneUptimeUserId,
383
+ });
384
+ } else if (noteType === "private") {
385
+ await IncidentInternalNoteService.addNote({
386
+ incidentId: incidentId,
387
+ note: note.toString(),
388
+ projectId: projectId,
389
+ userId: oneUptimeUserId,
390
+ });
391
+ }
392
+
393
+ await turnContext.sendActivity("✅ Note added successfully.");
394
+
395
+ // Hide the form card by deleting it
396
+ if (turnContext.activity.replyToId) {
397
+ await turnContext.deleteActivity(turnContext.activity.replyToId);
398
+ }
399
+
400
+ return;
401
+ }
402
+ await turnContext.sendActivity("Unable to add note: missing note data.");
403
+ return;
404
+ }
405
+
406
+ if (
407
+ actionType ===
408
+ MicrosoftTeamsIncidentActionType.ViewExecuteIncidentOnCallPolicy
409
+ ) {
410
+ if (!actionValue) {
411
+ await turnContext.sendActivity(
412
+ "Unable to execute on-call policy: missing incident id.",
413
+ );
414
+ return;
415
+ }
416
+
417
+ // Send the input card
418
+ const card: JSONObject | null = await this.buildExecuteOnCallPolicyCard(
419
+ actionValue,
420
+ projectId,
421
+ );
422
+ if (!card) {
423
+ await turnContext.sendActivity(
424
+ "No on-call policies found in the project",
425
+ );
426
+ return;
427
+ }
428
+ await turnContext.sendActivity({
429
+ attachments: [
430
+ {
431
+ contentType: "application/vnd.microsoft.card.adaptive",
432
+ content: card,
433
+ },
434
+ ],
435
+ });
436
+ return;
437
+ }
438
+
439
+ if (
440
+ actionType ===
441
+ MicrosoftTeamsIncidentActionType.SubmitExecuteIncidentOnCallPolicy
442
+ ) {
443
+ if (!actionValue) {
444
+ await turnContext.sendActivity(
445
+ "Unable to execute on-call policy: missing incident id.",
446
+ );
447
+ return;
448
+ }
449
+
450
+ // Check if form data is provided
451
+ const onCallPolicyId: JSONValue = value["onCallPolicy"];
452
+
453
+ if (onCallPolicyId) {
454
+ // Execute the policy
455
+ const incidentId: ObjectID = new ObjectID(actionValue);
456
+
457
+ await OnCallDutyPolicyService.executePolicy(
458
+ new ObjectID(onCallPolicyId.toString()),
459
+ {
460
+ triggeredByIncidentId: incidentId,
461
+ userNotificationEventType:
462
+ UserNotificationEventType.IncidentCreated,
463
+ },
464
+ );
465
+
466
+ await turnContext.sendActivity(
467
+ "✅ On-call policy executed successfully.",
468
+ );
469
+
470
+ // Hide the form card by deleting it
471
+ if (turnContext.activity.replyToId) {
472
+ await turnContext.deleteActivity(turnContext.activity.replyToId);
473
+ }
474
+
475
+ return;
476
+ }
477
+ await turnContext.sendActivity(
478
+ "Unable to execute on-call policy: missing policy id.",
479
+ );
480
+ return;
481
+ }
482
+
483
+ if (
484
+ actionType === MicrosoftTeamsIncidentActionType.ViewChangeIncidentState
485
+ ) {
486
+ if (!actionValue) {
487
+ await turnContext.sendActivity(
488
+ "Unable to change incident state: missing incident id.",
489
+ );
490
+ return;
491
+ }
492
+
493
+ // Send the input card
494
+ const card: JSONObject = await this.buildChangeIncidentStateCard(
495
+ actionValue,
496
+ projectId,
497
+ );
498
+ await turnContext.sendActivity({
499
+ attachments: [
500
+ {
501
+ contentType: "application/vnd.microsoft.card.adaptive",
502
+ content: card,
503
+ },
504
+ ],
505
+ });
506
+ return;
507
+ }
508
+
509
+ if (
510
+ actionType === MicrosoftTeamsIncidentActionType.SubmitChangeIncidentState
511
+ ) {
512
+ if (!actionValue) {
513
+ await turnContext.sendActivity(
514
+ "Unable to change incident state: missing incident id.",
515
+ );
516
+ return;
517
+ }
518
+
519
+ // Check if form data is provided
520
+ const incidentStateId: JSONValue = value["incidentState"];
521
+
522
+ if (incidentStateId) {
523
+ // Update the state
524
+ const incidentId: ObjectID = new ObjectID(actionValue);
525
+
526
+ await IncidentService.updateOneById({
527
+ id: incidentId,
528
+ data: {
529
+ currentIncidentStateId: new ObjectID(incidentStateId.toString()),
530
+ },
531
+ props: {
532
+ isRoot: true,
533
+ },
534
+ });
535
+
536
+ await turnContext.sendActivity(
537
+ "✅ Incident state changed successfully.",
538
+ );
539
+
540
+ // Hide the form card by deleting it
541
+ if (turnContext.activity.replyToId) {
542
+ await turnContext.deleteActivity(turnContext.activity.replyToId);
543
+ }
544
+
545
+ return;
546
+ }
547
+ await turnContext.sendActivity(
548
+ "Unable to change incident state: missing state id.",
549
+ );
550
+ return;
551
+ }
552
+
553
+ if (actionType === MicrosoftTeamsIncidentActionType.SubmitNewIncident) {
554
+ // Handle new incident submission
555
+ const title: string = (value["incidentTitle"] as string) || "";
556
+ const description: string =
557
+ (value["incidentDescription"] as string) || "";
558
+ const severityId: string = (value["incidentSeverity"] as string) || "";
559
+ const monitorIds: string = (value["incidentMonitors"] as string) || "";
560
+ const monitorStatusId: string = (value["monitorStatus"] as string) || "";
561
+ const labelIds: string = (value["labels"] as string) || "";
562
+ const onCallPolicyIds: string =
563
+ (value["onCallDutyPolicies"] as string) || "";
564
+
565
+ if (!title || !description || !severityId) {
566
+ await turnContext.sendActivity(
567
+ "Unable to create incident: missing required fields (title, description, or severity).",
568
+ );
569
+ return;
570
+ }
571
+
572
+ try {
573
+ // Create the incident
574
+ const incident: Incident = new Incident();
575
+ incident.title = title;
576
+ incident.description = description;
577
+ incident.projectId = projectId;
578
+ incident.createdByUserId = oneUptimeUserId;
579
+ incident.incidentSeverityId = new ObjectID(severityId);
580
+ incident.rootCause = `Incident created via Microsoft Teams`;
581
+
582
+ // Parse monitors
583
+ if (monitorIds) {
584
+ const monitorIdArray: Array<string> = monitorIds
585
+ .split(",")
586
+ .map((id: string) => {
587
+ return id.trim();
588
+ })
589
+ .filter((id: string) => {
590
+ return id;
591
+ });
592
+ if (monitorIdArray.length > 0) {
593
+ incident.monitors = monitorIdArray.map((id: string) => {
594
+ const monitor: Monitor = new Monitor();
595
+ monitor.id = new ObjectID(id);
596
+ return monitor;
597
+ });
598
+ }
599
+ }
600
+
601
+ // Parse labels
602
+ if (labelIds) {
603
+ const labelIdArray: Array<string> = labelIds
604
+ .split(",")
605
+ .map((id: string) => {
606
+ return id.trim();
607
+ })
608
+ .filter((id: string) => {
609
+ return id;
610
+ });
611
+ if (labelIdArray.length > 0) {
612
+ incident.labels = labelIdArray.map((id: string) => {
613
+ const label: Label = new Label();
614
+ label.id = new ObjectID(id);
615
+ return label;
616
+ });
617
+ }
618
+ }
619
+
620
+ // Parse on-call policies
621
+ if (onCallPolicyIds) {
622
+ const policyIdArray: Array<string> = onCallPolicyIds
623
+ .split(",")
624
+ .map((id: string) => {
625
+ return id.trim();
626
+ })
627
+ .filter((id: string) => {
628
+ return id;
629
+ });
630
+ if (policyIdArray.length > 0) {
631
+ incident.onCallDutyPolicies = policyIdArray.map((id: string) => {
632
+ const policy: OnCallDutyPolicy = new OnCallDutyPolicy();
633
+ policy.id = new ObjectID(id);
634
+ return policy;
635
+ });
636
+ }
637
+ }
638
+
639
+ // Save the incident
640
+ const createdIncident: Incident = await IncidentService.create({
641
+ data: incident,
642
+ props: {
643
+ isRoot: true,
644
+ },
645
+ });
646
+
647
+ logger.debug(
648
+ "Incident created successfully: " + createdIncident.id?.toString(),
649
+ );
650
+
651
+ // Update monitor status if specified
652
+ if (monitorStatusId && monitorIds) {
653
+ const monitorIdArray: Array<string> = monitorIds
654
+ .split(",")
655
+ .map((id: string) => {
656
+ return id.trim();
657
+ })
658
+ .filter((id: string) => {
659
+ return id;
660
+ });
661
+ for (const monitorId of monitorIdArray) {
662
+ await MonitorService.updateOneById({
663
+ id: new ObjectID(monitorId),
664
+ data: {
665
+ currentMonitorStatusId: new ObjectID(monitorStatusId),
666
+ },
667
+ props: {
668
+ isRoot: true,
669
+ },
670
+ });
671
+ }
672
+ }
673
+
674
+ // Hide the form card by deleting it first
675
+ if (turnContext.activity.replyToId) {
676
+ await turnContext.deleteActivity(turnContext.activity.replyToId);
677
+ }
678
+
679
+ // Get the incident link
680
+ const incidentLink: URL =
681
+ await IncidentService.getIncidentLinkInDashboard(
682
+ projectId,
683
+ createdIncident.id!,
684
+ );
685
+
686
+ // Send confirmation message as a new message in the thread
687
+ await turnContext.sendActivity(
688
+ `✅ Incident created successfully!\n\nView incident: ${incidentLink.toString()}`,
689
+ );
690
+
691
+ return;
692
+ } catch (error) {
693
+ logger.error("Error creating incident from Microsoft Teams:");
694
+ logger.error(error);
695
+ await turnContext.sendActivity(
696
+ "❌ Failed to create incident. Please try again.",
697
+ );
698
+ return;
699
+ }
700
+ }
701
+
702
+ // Default fallback for unimplemented actions
703
+ await turnContext.sendActivity(
704
+ "Sorry, but the action " +
705
+ actionType +
706
+ " you requested is not implemented yet.",
707
+ );
708
+ }
709
+
710
+ private static buildAddIncidentNoteCard(incidentId: string): JSONObject {
711
+ return {
712
+ type: "AdaptiveCard",
713
+ $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
714
+ version: "1.5",
715
+ body: [
716
+ {
717
+ type: "TextBlock",
718
+ text: "Add Incident Note",
719
+ size: "Large",
720
+ weight: "Bolder",
721
+ },
722
+ {
723
+ type: "Input.ChoiceSet",
724
+ id: "noteType",
725
+ label: "Note Type",
726
+ style: "compact",
727
+ value: "public",
728
+ choices: [
729
+ {
730
+ title: "Public Note (Will be posted on Status Page)",
731
+ value: "public",
732
+ },
733
+ {
734
+ title: "Private Note (Only visible to team members)",
735
+ value: "private",
736
+ },
737
+ ],
738
+ },
739
+ {
740
+ type: "Input.Text",
741
+ id: "note",
742
+ label: "Note",
743
+ isMultiline: true,
744
+ placeholder: "Please type in plain text or markdown.",
745
+ },
746
+ ],
747
+ actions: [
748
+ {
749
+ type: "Action.Submit",
750
+ title: "Submit",
751
+ data: {
752
+ action: MicrosoftTeamsIncidentActionType.SubmitIncidentNote,
753
+ actionValue: incidentId,
754
+ },
755
+ },
756
+ ],
757
+ };
758
+ }
759
+
760
+ private static async buildExecuteOnCallPolicyCard(
761
+ incidentId: string,
762
+ projectId: ObjectID,
763
+ ): Promise<JSONObject | null> {
764
+ const onCallPolicies: Array<OnCallDutyPolicy> =
765
+ await OnCallDutyPolicyService.findBy({
766
+ query: {
767
+ projectId: projectId,
768
+ },
769
+ select: {
770
+ name: true,
771
+ _id: true,
772
+ },
773
+ props: {
774
+ isRoot: true,
775
+ },
776
+ limit: 50,
777
+ skip: 0,
778
+ });
779
+
780
+ const choices: Array<{ title: string; value: string }> = onCallPolicies
781
+ .map((policy: OnCallDutyPolicy) => {
782
+ return {
783
+ title: policy.name || "",
784
+ value: policy._id?.toString() || "",
785
+ };
786
+ })
787
+ .filter((choice: { title: string; value: string }) => {
788
+ return choice.title && choice.value;
789
+ });
790
+
791
+ if (choices.length === 0) {
792
+ return null;
793
+ }
794
+
795
+ return {
796
+ type: "AdaptiveCard",
797
+ $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
798
+ version: "1.5",
799
+ body: [
800
+ {
801
+ type: "TextBlock",
802
+ text: "Execute On-Call Policy",
803
+ size: "Large",
804
+ weight: "Bolder",
805
+ },
806
+ {
807
+ type: "Input.ChoiceSet",
808
+ id: "onCallPolicy",
809
+ label: "On-Call Policy",
810
+ style: "compact",
811
+ choices: choices,
812
+ },
813
+ ],
814
+ actions: [
815
+ {
816
+ type: "Action.Submit",
817
+ title: "Execute",
818
+ data: {
819
+ action:
820
+ MicrosoftTeamsIncidentActionType.SubmitExecuteIncidentOnCallPolicy,
821
+ actionValue: incidentId,
822
+ },
823
+ },
824
+ ],
825
+ };
826
+ }
827
+
828
+ private static async buildChangeIncidentStateCard(
829
+ incidentId: string,
830
+ projectId: ObjectID,
831
+ ): Promise<JSONObject> {
832
+ const incidentStates: Array<IncidentState> =
833
+ await IncidentStateService.getAllIncidentStates({
834
+ projectId: projectId,
835
+ props: {
836
+ isRoot: true,
837
+ },
838
+ });
839
+
840
+ const choices: Array<{ title: string; value: string }> = incidentStates
841
+ .map((state: IncidentState) => {
842
+ return {
843
+ title: state.name || "",
844
+ value: state._id?.toString() || "",
845
+ };
846
+ })
847
+ .filter((choice: { title: string; value: string }) => {
848
+ return choice.title && choice.value;
849
+ });
850
+
851
+ return {
852
+ type: "AdaptiveCard",
853
+ $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
854
+ version: "1.5",
855
+ body: [
856
+ {
857
+ type: "TextBlock",
858
+ text: "Change Incident State",
859
+ size: "Large",
860
+ weight: "Bolder",
861
+ },
862
+ {
863
+ type: "Input.ChoiceSet",
864
+ id: "incidentState",
865
+ label: "Incident State",
866
+ style: "compact",
867
+ choices: choices,
868
+ },
869
+ ],
870
+ actions: [
871
+ {
872
+ type: "Action.Submit",
873
+ title: "Change",
874
+ data: {
875
+ action: MicrosoftTeamsIncidentActionType.SubmitChangeIncidentState,
876
+ actionValue: incidentId,
877
+ },
878
+ },
879
+ ],
880
+ };
881
+ }
882
+
883
+ @CaptureSpan()
884
+ public static async showNewIncidentCard(data: {
885
+ teamsRequest: MicrosoftTeamsRequest;
886
+ action: MicrosoftTeamsAction;
887
+ req: ExpressRequest;
888
+ res: ExpressResponse;
889
+ }): Promise<void> {
890
+ const { teamsRequest, req, res } = data;
891
+
892
+ logger.debug("Showing new incident card for Microsoft Teams");
893
+
894
+ // Send empty response first
895
+ Response.sendTextResponse(req, res, "");
896
+
897
+ if (!teamsRequest.projectId) {
898
+ logger.error("Project ID not found in Teams request");
899
+ return;
900
+ }
901
+
902
+ // Build the adaptive card with form fields
903
+ const card: JSONObject = await this.buildNewIncidentCard(
904
+ teamsRequest.projectId,
905
+ );
906
+
907
+ /*
908
+ * Send card as a message (note: in real Teams bot, this would be sent via TurnContext)
909
+ * For now, we'll just log it. The actual sending will be done through the bot framework
910
+ */
911
+ logger.debug("New incident card built:");
912
+ logger.debug(JSON.stringify(card, null, 2));
913
+ }
914
+
915
+ @CaptureSpan()
916
+ public static async submitNewIncident(data: {
917
+ teamsRequest: MicrosoftTeamsRequest;
918
+ action: MicrosoftTeamsAction;
919
+ req: ExpressRequest;
920
+ res: ExpressResponse;
921
+ }): Promise<void> {
922
+ const { teamsRequest, req, res } = data;
923
+ const { userId, projectId } = teamsRequest;
924
+
925
+ logger.debug("Submitting new incident from Microsoft Teams");
926
+
927
+ if (!projectId) {
928
+ return Response.sendErrorResponse(
929
+ req,
930
+ res,
931
+ new BadDataException("Invalid Project ID"),
932
+ );
933
+ }
934
+
935
+ if (!userId) {
936
+ return Response.sendErrorResponse(
937
+ req,
938
+ res,
939
+ new BadDataException("Invalid User ID"),
940
+ );
941
+ }
942
+
943
+ // Send early response
944
+ Response.sendTextResponse(req, res, "");
945
+
946
+ // Extract form data from the payload
947
+ const payload: JSONObject = teamsRequest.payload || {};
948
+ const value: JSONObject = (payload["value"] as JSONObject) || {};
949
+
950
+ const title: string = (value["incidentTitle"] as string) || "";
951
+ const description: string = (value["incidentDescription"] as string) || "";
952
+ const severityId: string = (value["incidentSeverity"] as string) || "";
953
+ const monitorIds: string = (value["incidentMonitors"] as string) || "";
954
+ const monitorStatusId: string = (value["monitorStatus"] as string) || "";
955
+ const labelIds: string = (value["labels"] as string) || "";
956
+ const onCallPolicyIds: string =
957
+ (value["onCallDutyPolicies"] as string) || "";
958
+
959
+ if (!title || !description || !severityId) {
960
+ logger.error("Missing required fields for incident creation");
961
+ return;
962
+ }
963
+
964
+ try {
965
+ // Get OneUptime user ID
966
+ const oneUptimeUserId: ObjectID =
967
+ await MicrosoftTeamsAuthAction.getOneUptimeUserIdFromTeamsUserId({
968
+ teamsUserId: userId,
969
+ projectId: projectId,
970
+ });
971
+
972
+ // Create the incident
973
+ const incident: Incident = new Incident();
974
+ incident.title = title;
975
+ incident.description = description;
976
+ incident.projectId = projectId;
977
+ incident.createdByUserId = oneUptimeUserId;
978
+ incident.incidentSeverityId = new ObjectID(severityId);
979
+ incident.rootCause = `Incident created via Microsoft Teams`;
980
+
981
+ // Parse monitors
982
+ if (monitorIds) {
983
+ const monitorIdArray: Array<string> = monitorIds
984
+ .split(",")
985
+ .map((id: string) => {
986
+ return id.trim();
987
+ })
988
+ .filter((id: string) => {
989
+ return id;
990
+ });
991
+ if (monitorIdArray.length > 0) {
992
+ incident.monitors = monitorIdArray.map((id: string) => {
993
+ const monitor: Monitor = new Monitor();
994
+ monitor.id = new ObjectID(id);
995
+ return monitor;
996
+ });
997
+ }
998
+ }
999
+
1000
+ // Parse labels
1001
+ if (labelIds) {
1002
+ const labelIdArray: Array<string> = labelIds
1003
+ .split(",")
1004
+ .map((id: string) => {
1005
+ return id.trim();
1006
+ })
1007
+ .filter((id: string) => {
1008
+ return id;
1009
+ });
1010
+ if (labelIdArray.length > 0) {
1011
+ incident.labels = labelIdArray.map((id: string) => {
1012
+ const label: Label = new Label();
1013
+ label.id = new ObjectID(id);
1014
+ return label;
1015
+ });
1016
+ }
1017
+ }
1018
+
1019
+ // Parse on-call policies
1020
+ if (onCallPolicyIds) {
1021
+ const policyIdArray: Array<string> = onCallPolicyIds
1022
+ .split(",")
1023
+ .map((id: string) => {
1024
+ return id.trim();
1025
+ })
1026
+ .filter((id: string) => {
1027
+ return id;
1028
+ });
1029
+ if (policyIdArray.length > 0) {
1030
+ incident.onCallDutyPolicies = policyIdArray.map((id: string) => {
1031
+ const policy: OnCallDutyPolicy = new OnCallDutyPolicy();
1032
+ policy.id = new ObjectID(id);
1033
+ return policy;
1034
+ });
1035
+ }
1036
+ }
1037
+
1038
+ // Save the incident
1039
+ const createdIncident: Incident = await IncidentService.create({
1040
+ data: incident,
1041
+ props: {
1042
+ isRoot: true,
1043
+ },
1044
+ });
1045
+
1046
+ logger.debug(
1047
+ "Incident created successfully: " + createdIncident.id?.toString(),
1048
+ );
1049
+
1050
+ // Update monitor status if specified
1051
+ if (monitorStatusId && monitorIds) {
1052
+ const monitorIdArray: Array<string> = monitorIds
1053
+ .split(",")
1054
+ .map((id: string) => {
1055
+ return id.trim();
1056
+ })
1057
+ .filter((id: string) => {
1058
+ return id;
1059
+ });
1060
+ for (const monitorId of monitorIdArray) {
1061
+ await MonitorService.updateOneById({
1062
+ id: new ObjectID(monitorId),
1063
+ data: {
1064
+ currentMonitorStatusId: new ObjectID(monitorStatusId),
1065
+ },
1066
+ props: {
1067
+ isRoot: true,
1068
+ },
1069
+ });
1070
+ }
1071
+ }
1072
+
1073
+ logger.debug("New incident created from Microsoft Teams successfully");
1074
+ } catch (error) {
1075
+ logger.error("Error creating incident from Microsoft Teams:");
1076
+ logger.error(error);
1077
+ }
1078
+ }
1079
+
1080
+ public static async buildNewIncidentCard(
1081
+ projectId: ObjectID,
1082
+ ): Promise<JSONObject> {
1083
+ // Fetch severities
1084
+ const severities: Array<IncidentSeverity> =
1085
+ await IncidentSeverityService.findBy({
1086
+ query: {
1087
+ projectId: projectId,
1088
+ },
1089
+ sort: {
1090
+ order: SortOrder.Ascending,
1091
+ },
1092
+ skip: 0,
1093
+ limit: LIMIT_PER_PROJECT,
1094
+ select: {
1095
+ name: true,
1096
+ },
1097
+ props: {
1098
+ isRoot: true,
1099
+ },
1100
+ });
1101
+
1102
+ const severityChoices: Array<{ title: string; value: string }> =
1103
+ severities.map((severity: IncidentSeverity) => {
1104
+ return {
1105
+ title: severity.name || "",
1106
+ value: severity._id?.toString() || "",
1107
+ };
1108
+ });
1109
+
1110
+ // Fetch monitors
1111
+ const monitors: Array<Monitor> = await MonitorService.findBy({
1112
+ query: {
1113
+ projectId: projectId,
1114
+ },
1115
+ select: {
1116
+ name: true,
1117
+ },
1118
+ props: {
1119
+ isRoot: true,
1120
+ },
1121
+ limit: LIMIT_PER_PROJECT,
1122
+ skip: 0,
1123
+ });
1124
+
1125
+ const monitorChoices: Array<{ title: string; value: string }> = monitors
1126
+ .map((monitor: Monitor) => {
1127
+ return {
1128
+ title: monitor.name || "",
1129
+ value: monitor._id?.toString() || "",
1130
+ };
1131
+ })
1132
+ .filter((choice: { title: string; value: string }) => {
1133
+ return choice.title && choice.value;
1134
+ });
1135
+
1136
+ // Fetch monitor statuses
1137
+ const monitorStatuses: Array<MonitorStatus> =
1138
+ await MonitorStatusService.findBy({
1139
+ query: {
1140
+ projectId: projectId,
1141
+ },
1142
+ select: {
1143
+ name: true,
1144
+ },
1145
+ props: {
1146
+ isRoot: true,
1147
+ },
1148
+ sort: {
1149
+ priority: SortOrder.Ascending,
1150
+ },
1151
+ limit: LIMIT_PER_PROJECT,
1152
+ skip: 0,
1153
+ });
1154
+
1155
+ const monitorStatusChoices: Array<{ title: string; value: string }> =
1156
+ monitorStatuses
1157
+ .map((status: MonitorStatus) => {
1158
+ return {
1159
+ title: status.name || "",
1160
+ value: status._id?.toString() || "",
1161
+ };
1162
+ })
1163
+ .filter((choice: { title: string; value: string }) => {
1164
+ return choice.title && choice.value;
1165
+ });
1166
+
1167
+ // Fetch labels
1168
+ const labels: Array<Label> = await LabelService.findBy({
1169
+ query: {
1170
+ projectId: projectId,
1171
+ },
1172
+ select: {
1173
+ name: true,
1174
+ },
1175
+ props: {
1176
+ isRoot: true,
1177
+ },
1178
+ limit: LIMIT_PER_PROJECT,
1179
+ skip: 0,
1180
+ });
1181
+
1182
+ const labelChoices: Array<{ title: string; value: string }> = labels
1183
+ .map((label: Label) => {
1184
+ return {
1185
+ title: label.name || "",
1186
+ value: label._id?.toString() || "",
1187
+ };
1188
+ })
1189
+ .filter((choice: { title: string; value: string }) => {
1190
+ return choice.title && choice.value;
1191
+ });
1192
+
1193
+ // Fetch on-call policies
1194
+ const onCallPolicies: Array<OnCallDutyPolicy> =
1195
+ await OnCallDutyPolicyService.findBy({
1196
+ query: {
1197
+ projectId: projectId,
1198
+ },
1199
+ select: {
1200
+ name: true,
1201
+ },
1202
+ props: {
1203
+ isRoot: true,
1204
+ },
1205
+ limit: LIMIT_PER_PROJECT,
1206
+ skip: 0,
1207
+ });
1208
+
1209
+ const onCallPolicyChoices: Array<{ title: string; value: string }> =
1210
+ onCallPolicies
1211
+ .map((policy: OnCallDutyPolicy) => {
1212
+ return {
1213
+ title: policy.name || "",
1214
+ value: policy._id?.toString() || "",
1215
+ };
1216
+ })
1217
+ .filter((choice: { title: string; value: string }) => {
1218
+ return choice.title && choice.value;
1219
+ });
1220
+
1221
+ // Build the card
1222
+ const bodyElements: Array<JSONObject> = [
1223
+ {
1224
+ type: "TextBlock",
1225
+ text: "Create New Incident",
1226
+ size: "Large",
1227
+ weight: "Bolder",
1228
+ },
1229
+ {
1230
+ type: "Input.Text",
1231
+ id: "incidentTitle",
1232
+ label: "Incident Title",
1233
+ placeholder: "Enter incident title",
1234
+ isRequired: true,
1235
+ },
1236
+ {
1237
+ type: "Input.Text",
1238
+ id: "incidentDescription",
1239
+ label: "Incident Description",
1240
+ placeholder: "Enter incident description",
1241
+ isMultiline: true,
1242
+ isRequired: true,
1243
+ },
1244
+ ];
1245
+
1246
+ // Add severity dropdown if we have severities
1247
+ if (severityChoices.length > 0) {
1248
+ bodyElements.push({
1249
+ type: "Input.ChoiceSet",
1250
+ id: "incidentSeverity",
1251
+ label: "Incident Severity",
1252
+ style: "compact",
1253
+ isRequired: true,
1254
+ choices: severityChoices,
1255
+ });
1256
+ }
1257
+
1258
+ // Add monitor multi-select if we have monitors
1259
+ if (monitorChoices.length > 0) {
1260
+ bodyElements.push({
1261
+ type: "Input.ChoiceSet",
1262
+ id: "incidentMonitors",
1263
+ label: "Affected Monitors (Optional)",
1264
+ style: "compact",
1265
+ isMultiSelect: true,
1266
+ choices: monitorChoices,
1267
+ });
1268
+ }
1269
+
1270
+ // Add monitor status dropdown if we have statuses and monitors
1271
+ if (monitorStatusChoices.length > 0 && monitorChoices.length > 0) {
1272
+ bodyElements.push({
1273
+ type: "Input.ChoiceSet",
1274
+ id: "monitorStatus",
1275
+ label: "Change Monitor Status To (Optional)",
1276
+ style: "compact",
1277
+ choices: monitorStatusChoices,
1278
+ });
1279
+ }
1280
+
1281
+ // Add on-call policy multi-select if we have policies
1282
+ if (onCallPolicyChoices.length > 0) {
1283
+ bodyElements.push({
1284
+ type: "Input.ChoiceSet",
1285
+ id: "onCallDutyPolicies",
1286
+ label: "Execute On-Call Policies (Optional)",
1287
+ style: "compact",
1288
+ isMultiSelect: true,
1289
+ choices: onCallPolicyChoices,
1290
+ });
1291
+ }
1292
+
1293
+ // Add labels multi-select if we have labels
1294
+ if (labelChoices.length > 0) {
1295
+ bodyElements.push({
1296
+ type: "Input.ChoiceSet",
1297
+ id: "labels",
1298
+ label: "Labels (Optional)",
1299
+ style: "compact",
1300
+ isMultiSelect: true,
1301
+ choices: labelChoices,
1302
+ });
1303
+ }
1304
+
1305
+ return {
1306
+ type: "AdaptiveCard",
1307
+ $schema: "http://adaptivecards.io/schemas/adaptive-card.json",
1308
+ version: "1.5",
1309
+ body: bodyElements,
1310
+ actions: [
1311
+ {
1312
+ type: "Action.Submit",
1313
+ title: "Create Incident",
1314
+ data: {
1315
+ action: MicrosoftTeamsIncidentActionType.SubmitNewIncident,
1316
+ },
1317
+ },
1318
+ ],
1319
+ };
1320
+ }
1321
+ }