@oneuptime/common 11.7.3 → 11.7.4

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 (365) hide show
  1. package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +1 -0
  2. package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
  3. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  4. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  5. package/Models/DatabaseModels/Index.ts +5 -0
  6. package/Models/DatabaseModels/LogDropFilter.ts +89 -0
  7. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +13 -3
  8. package/Models/DatabaseModels/RecommendationDismissal.ts +463 -0
  9. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  10. package/Models/DatabaseModels/StatusPageGroup.ts +95 -0
  11. package/Models/DatabaseModels/TraceDropFilter.ts +89 -0
  12. package/Models/DatabaseModels/WorkflowVariable.ts +5 -1
  13. package/Server/API/AlertAPI.ts +32 -17
  14. package/Server/API/BaseAPI.ts +31 -2
  15. package/Server/API/BaseAnalyticsAPI.ts +36 -2
  16. package/Server/API/CommonAPI.ts +57 -0
  17. package/Server/API/IncidentAPI.ts +60 -33
  18. package/Server/API/IncidentEpisodeAPI.ts +31 -16
  19. package/Server/API/MonitorAPI.ts +30 -0
  20. package/Server/API/MonitorTemplateAPI.ts +8 -0
  21. package/Server/API/ProbeAPI.ts +196 -15
  22. package/Server/API/ProjectAPI.ts +79 -1
  23. package/Server/API/ScheduledMaintenanceAPI.ts +33 -18
  24. package/Server/API/StatusPageAPI.ts +74 -37
  25. package/Server/API/WorkspaceNotificationRuleAPI.ts +34 -4
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.ts +527 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.ts +31 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.ts +55 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.ts +53 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  31. package/Server/Services/AlertEpisodeService.ts +47 -0
  32. package/Server/Services/AlertService.ts +125 -0
  33. package/Server/Services/BillingService.ts +98 -0
  34. package/Server/Services/DatabaseService.ts +184 -20
  35. package/Server/Services/IncidentEpisodeService.ts +47 -0
  36. package/Server/Services/IncidentService.ts +123 -0
  37. package/Server/Services/IncidentTemplateService.ts +123 -1
  38. package/Server/Services/Index.ts +2 -0
  39. package/Server/Services/LogDropFilterService.ts +133 -0
  40. package/Server/Services/MonitorProbeService.ts +94 -4
  41. package/Server/Services/MonitorService.ts +48 -43
  42. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +70 -0
  43. package/Server/Services/ProbeService.ts +66 -0
  44. package/Server/Services/ProjectService.ts +131 -7
  45. package/Server/Services/RecommendationDismissalService.ts +52 -0
  46. package/Server/Services/RunbookAgentJobService.ts +68 -7
  47. package/Server/Services/ScheduledMaintenanceService.ts +103 -0
  48. package/Server/Services/ScheduledMaintenanceTemplateService.ts +90 -0
  49. package/Server/Services/StatusPageGroupService.ts +186 -0
  50. package/Server/Services/TraceDropFilterService.ts +133 -0
  51. package/Server/Types/Workflow/Components/API/Delete.ts +12 -0
  52. package/Server/Types/Workflow/Components/API/Get.ts +12 -0
  53. package/Server/Types/Workflow/Components/API/Patch.ts +12 -0
  54. package/Server/Types/Workflow/Components/API/Post.ts +12 -0
  55. package/Server/Types/Workflow/Components/API/Put.ts +13 -0
  56. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +212 -0
  57. package/Server/Utils/DropFilterValidation.ts +127 -0
  58. package/Server/Utils/Errors.ts +5 -0
  59. package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
  60. package/Server/Utils/Monitor/MonitorIncident.ts +31 -2
  61. package/Server/Utils/Telemetry/AppMetrics.ts +31 -0
  62. package/Tests/Models/DatabaseModels/MonitorProbeColumnAccessControl.test.ts +196 -0
  63. package/Tests/Models/RecommendationDismissalModel.test.ts +269 -0
  64. package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +320 -0
  65. package/Tests/Server/API/BaseAnalyticsAPIUpdatePayloadValidation.test.ts +293 -0
  66. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +164 -0
  67. package/Tests/Server/API/ProbeAPI.test.ts +422 -53
  68. package/Tests/Server/API/ProjectAPI.test.ts +180 -0
  69. package/Tests/Server/API/ProjectAPIExtendTrialBillingDisabled.test.ts +138 -0
  70. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +458 -0
  71. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +359 -0
  72. package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +427 -0
  73. package/Tests/Server/Services/BillingServiceExtendTrial.test.ts +439 -0
  74. package/Tests/Server/Services/CrossProjectReferenceWriteGuard.test.ts +810 -0
  75. package/Tests/Server/Services/DatabaseServiceAtomicAddToColumns.test.ts +269 -0
  76. package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +277 -0
  77. package/Tests/Server/Services/DatabaseServiceSortColumnSelect.test.ts +201 -0
  78. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +81 -23
  79. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +398 -0
  80. package/Tests/Server/Services/MonitorProbeDeleteHooks.test.ts +280 -0
  81. package/Tests/Server/Services/MonitorProbeServiceProbeTenancy.test.ts +304 -0
  82. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +262 -0
  83. package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +614 -0
  84. package/Tests/Server/Services/RecommendationDismissalService.test.ts +306 -0
  85. package/Tests/Server/Services/RepairCrossProjectIncidentReferencesMigration.test.ts +528 -0
  86. package/Tests/Server/Services/StatusPageGroupNesting.test.ts +395 -0
  87. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +26 -21
  88. package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +227 -0
  89. package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +285 -0
  90. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +463 -0
  91. package/Tests/Server/Utils/DropFilterValidation.test.ts +269 -0
  92. package/Tests/Server/Utils/Telemetry/SpanUtil.test.ts +94 -0
  93. package/Tests/Types/DateUserTimezone.test.ts +52 -0
  94. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +177 -9
  95. package/Tests/Types/Monitor/MonitorStepDnsMonitor.test.ts +105 -0
  96. package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +131 -0
  97. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +60 -0
  98. package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +82 -0
  99. package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +268 -0
  100. package/Tests/Types/Monitor/MonitorStepMetricMonitor.test.ts +386 -0
  101. package/Tests/Types/Monitor/MonitorStepProfileMonitor.test.ts +185 -0
  102. package/Tests/Types/Monitor/MonitorStepSnmpMonitor.test.ts +156 -0
  103. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +371 -0
  104. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +901 -0
  105. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +607 -0
  106. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +754 -0
  107. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +960 -0
  108. package/Tests/Types/RollingTime/RollingTimeUtil.test.ts +186 -0
  109. package/Tests/Types/Runbook/RunbookStepTimeout.test.ts +410 -0
  110. package/Tests/Types/Telemetry/DropFilterSampling.test.ts +241 -0
  111. package/Tests/Types/Workspace/NotificationRuleConditionUtil.test.ts +353 -0
  112. package/Tests/Types/Workspace/NotificationRuleUtil.test.ts +566 -0
  113. package/Tests/UI/Components/CodeEditor.test.tsx +174 -0
  114. package/Tests/UI/Components/ErrorBoundary.test.tsx +555 -24
  115. package/Tests/UI/Components/InfoCard.test.tsx +358 -0
  116. package/Tests/UI/Components/LogTimeRangePicker.test.tsx +138 -0
  117. package/Tests/UI/Components/Modal.test.tsx +43 -5
  118. package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +397 -0
  119. package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +427 -0
  120. package/Tests/UI/Components/Runbook/StepTimeoutInput.test.tsx +386 -0
  121. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +671 -0
  122. package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +404 -0
  123. package/Tests/UI/Utils/DropdownAlignment.test.ts +306 -0
  124. package/Tests/UI/Utils/TableFilterUrlState.test.ts +292 -0
  125. package/Tests/Utils/Monitor/MonitorSummaryProbeUtil.test.ts +263 -0
  126. package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +583 -0
  127. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +1072 -0
  128. package/Tests/Utils/StatusPage/GroupTree.test.ts +583 -0
  129. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +411 -0
  130. package/Types/Date.ts +15 -6
  131. package/Types/Monitor/KubernetesAlertTemplates.ts +205 -0
  132. package/Types/Monitor/MonitorStep.ts +10 -1
  133. package/Types/Monitor/MonitorStepMetricMonitor.ts +46 -1
  134. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +413 -0
  135. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +168 -0
  136. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +175 -0
  137. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +743 -0
  138. package/Types/Permission.ts +45 -0
  139. package/Types/Recommendation/RecommendationType.ts +20 -0
  140. package/Types/Runbook/RunbookExecutionDeadline.ts +129 -0
  141. package/Types/Runbook/RunbookStepTimeout.ts +202 -0
  142. package/Types/Telemetry/DropFilterSampling.ts +92 -0
  143. package/UI/Components/AI/GenerateFromAIModal.tsx +0 -2
  144. package/UI/Components/Accordion/Accordion.tsx +10 -2
  145. package/UI/Components/BulkUpdate/BulkLabelActions.tsx +0 -1
  146. package/UI/Components/CodeEditor/CodeEditor.tsx +34 -20
  147. package/UI/Components/Date/RangeStartAndEndDateView.tsx +0 -1
  148. package/UI/Components/EditionLabel/EditionLabel.tsx +1 -27
  149. package/UI/Components/Error/PageError.tsx +0 -4
  150. package/UI/Components/ErrorBoundary.tsx +252 -15
  151. package/UI/Components/InfoCard/InfoCard.tsx +58 -1
  152. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +34 -1
  153. package/UI/Components/Modal/Modal.tsx +16 -60
  154. package/UI/Components/ModelFormModal/ModelFormModal.tsx +0 -8
  155. package/UI/Components/ModelTable/BaseModelTable.tsx +116 -67
  156. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +150 -47
  157. package/UI/Components/Runbook/StepTimeoutInput.tsx +173 -0
  158. package/UI/Components/StatusPage/ResourceGroupSection.tsx +231 -0
  159. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +34 -1
  160. package/UI/Utils/DropdownAlignment.ts +162 -0
  161. package/UI/Utils/TableFilterUrlState.ts +59 -20
  162. package/Utils/API.ts +106 -2
  163. package/Utils/Monitor/MonitorSummaryProbeUtil.ts +130 -0
  164. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +434 -0
  165. package/Utils/StatusPage/GroupNestingLayout.ts +343 -0
  166. package/Utils/StatusPage/GroupTree.ts +307 -0
  167. package/Utils/StatusPage/ResourceUptime.ts +90 -17
  168. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
  169. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
  170. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
  171. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
  172. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  173. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  174. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  175. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  176. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  177. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  178. package/build/dist/Models/DatabaseModels/LogDropFilter.js +91 -0
  179. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  180. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +14 -4
  181. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  182. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js +484 -0
  183. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js.map +1 -0
  184. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  185. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/StatusPageGroup.js +94 -0
  187. package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +91 -0
  189. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +5 -1
  191. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  192. package/build/dist/Server/API/AlertAPI.js +22 -13
  193. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  194. package/build/dist/Server/API/BaseAPI.js +22 -1
  195. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  196. package/build/dist/Server/API/BaseAnalyticsAPI.js +24 -1
  197. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  198. package/build/dist/Server/API/CommonAPI.js +42 -0
  199. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  200. package/build/dist/Server/API/IncidentAPI.js +43 -26
  201. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  202. package/build/dist/Server/API/IncidentEpisodeAPI.js +21 -12
  203. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  204. package/build/dist/Server/API/MonitorAPI.js +23 -0
  205. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  206. package/build/dist/Server/API/MonitorTemplateAPI.js +4 -0
  207. package/build/dist/Server/API/MonitorTemplateAPI.js.map +1 -1
  208. package/build/dist/Server/API/ProbeAPI.js +131 -15
  209. package/build/dist/Server/API/ProbeAPI.js.map +1 -1
  210. package/build/dist/Server/API/ProjectAPI.js +62 -3
  211. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  212. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +23 -14
  213. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  214. package/build/dist/Server/API/StatusPageAPI.js +61 -33
  215. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  216. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js +26 -2
  217. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js.map +1 -1
  218. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js +397 -0
  219. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js.map +1 -0
  220. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js +16 -0
  221. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js.map +1 -0
  222. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js +30 -0
  223. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js.map +1 -0
  224. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js +34 -0
  225. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js.map +1 -0
  226. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  227. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  228. package/build/dist/Server/Services/AlertEpisodeService.js +39 -0
  229. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  230. package/build/dist/Server/Services/AlertService.js +95 -0
  231. package/build/dist/Server/Services/AlertService.js.map +1 -1
  232. package/build/dist/Server/Services/BillingService.js +71 -0
  233. package/build/dist/Server/Services/BillingService.js.map +1 -1
  234. package/build/dist/Server/Services/DatabaseService.js +140 -17
  235. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  236. package/build/dist/Server/Services/IncidentEpisodeService.js +39 -0
  237. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  238. package/build/dist/Server/Services/IncidentService.js +100 -0
  239. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  240. package/build/dist/Server/Services/IncidentTemplateService.js +97 -0
  241. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  242. package/build/dist/Server/Services/Index.js +2 -0
  243. package/build/dist/Server/Services/Index.js.map +1 -1
  244. package/build/dist/Server/Services/LogDropFilterService.js +93 -0
  245. package/build/dist/Server/Services/LogDropFilterService.js.map +1 -1
  246. package/build/dist/Server/Services/MonitorProbeService.js +73 -5
  247. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  248. package/build/dist/Server/Services/MonitorService.js +34 -39
  249. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  250. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +71 -0
  251. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  252. package/build/dist/Server/Services/ProbeService.js +64 -0
  253. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  254. package/build/dist/Server/Services/ProjectService.js +103 -7
  255. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  256. package/build/dist/Server/Services/RecommendationDismissalService.js +50 -0
  257. package/build/dist/Server/Services/RecommendationDismissalService.js.map +1 -0
  258. package/build/dist/Server/Services/RunbookAgentJobService.js +63 -5
  259. package/build/dist/Server/Services/RunbookAgentJobService.js.map +1 -1
  260. package/build/dist/Server/Services/ScheduledMaintenanceService.js +83 -0
  261. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  262. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +65 -0
  263. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  264. package/build/dist/Server/Services/StatusPageGroupService.js +136 -0
  265. package/build/dist/Server/Services/StatusPageGroupService.js.map +1 -1
  266. package/build/dist/Server/Services/TraceDropFilterService.js +93 -0
  267. package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -1
  268. package/build/dist/Server/Types/Workflow/Components/API/Delete.js +11 -0
  269. package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
  270. package/build/dist/Server/Types/Workflow/Components/API/Get.js +11 -0
  271. package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
  272. package/build/dist/Server/Types/Workflow/Components/API/Patch.js +11 -0
  273. package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
  274. package/build/dist/Server/Types/Workflow/Components/API/Post.js +11 -0
  275. package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
  276. package/build/dist/Server/Types/Workflow/Components/API/Put.js +12 -0
  277. package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
  278. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +132 -0
  279. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -0
  280. package/build/dist/Server/Utils/DropFilterValidation.js +80 -0
  281. package/build/dist/Server/Utils/DropFilterValidation.js.map +1 -0
  282. package/build/dist/Server/Utils/Errors.js +3 -0
  283. package/build/dist/Server/Utils/Errors.js.map +1 -1
  284. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +30 -12
  285. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  286. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +38 -18
  287. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  288. package/build/dist/Server/Utils/Telemetry/AppMetrics.js +26 -0
  289. package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
  290. package/build/dist/Types/Date.js +14 -4
  291. package/build/dist/Types/Date.js.map +1 -1
  292. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +192 -0
  293. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  294. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  295. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  296. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +32 -1
  297. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
  298. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +294 -0
  299. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -0
  300. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +110 -0
  301. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -0
  302. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +58 -0
  303. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -0
  304. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +451 -0
  305. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -0
  306. package/build/dist/Types/Permission.js +40 -0
  307. package/build/dist/Types/Permission.js.map +1 -1
  308. package/build/dist/Types/Recommendation/RecommendationType.js +21 -0
  309. package/build/dist/Types/Recommendation/RecommendationType.js.map +1 -0
  310. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js +93 -0
  311. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js.map +1 -0
  312. package/build/dist/Types/Runbook/RunbookStepTimeout.js +142 -0
  313. package/build/dist/Types/Runbook/RunbookStepTimeout.js.map +1 -0
  314. package/build/dist/Types/Telemetry/DropFilterSampling.js +75 -0
  315. package/build/dist/Types/Telemetry/DropFilterSampling.js.map +1 -0
  316. package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -2
  317. package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
  318. package/build/dist/UI/Components/Accordion/Accordion.js +9 -2
  319. package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
  320. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +1 -1
  321. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
  322. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +27 -14
  323. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  324. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +1 -1
  325. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -1
  326. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +2 -20
  327. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  328. package/build/dist/UI/Components/Error/PageError.js +1 -3
  329. package/build/dist/UI/Components/Error/PageError.js.map +1 -1
  330. package/build/dist/UI/Components/ErrorBoundary.js +145 -11
  331. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  332. package/build/dist/UI/Components/InfoCard/InfoCard.js +28 -1
  333. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  334. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +13 -2
  335. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  336. package/build/dist/UI/Components/Modal/Modal.js +4 -32
  337. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  338. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  339. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +69 -33
  340. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  341. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +73 -32
  342. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -1
  343. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js +101 -0
  344. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js.map +1 -0
  345. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +73 -0
  346. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -0
  347. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +13 -2
  348. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  349. package/build/dist/UI/Utils/DropdownAlignment.js +98 -0
  350. package/build/dist/UI/Utils/DropdownAlignment.js.map +1 -0
  351. package/build/dist/UI/Utils/TableFilterUrlState.js +48 -15
  352. package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
  353. package/build/dist/Utils/API.js +39 -2
  354. package/build/dist/Utils/API.js.map +1 -1
  355. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js +97 -0
  356. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js.map +1 -0
  357. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +330 -0
  358. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -0
  359. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +280 -0
  360. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -0
  361. package/build/dist/Utils/StatusPage/GroupTree.js +214 -0
  362. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -0
  363. package/build/dist/Utils/StatusPage/ResourceUptime.js +60 -16
  364. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  365. package/package.json +1 -1
@@ -0,0 +1,607 @@
1
+ import MonitorRecommendationCatalog, {
2
+ MonitorRecommendationResourceTypeDefinition,
3
+ } from "../../../../Types/Monitor/Recommendation/MonitorRecommendationCatalog";
4
+ import MonitorRecommendationUtil from "../../../../Types/Monitor/Recommendation/MonitorRecommendationUtil";
5
+ import {
6
+ MonitorRecommendation,
7
+ MonitorRecommendationArgs,
8
+ MonitorRecommendationNotificationMode,
9
+ MonitorRecommendationNotificationSettings,
10
+ } from "../../../../Types/Monitor/Recommendation/MonitorRecommendationTypes";
11
+ import MonitorStep from "../../../../Types/Monitor/MonitorStep";
12
+ import MonitorSteps from "../../../../Types/Monitor/MonitorSteps";
13
+ import MonitorCriteriaInstance from "../../../../Types/Monitor/MonitorCriteriaInstance";
14
+ import { CriteriaIncident } from "../../../../Types/Monitor/CriteriaIncident";
15
+ import { CriteriaAlert } from "../../../../Types/Monitor/CriteriaAlert";
16
+ import ObjectID from "../../../../Types/ObjectID";
17
+
18
+ /*
19
+ * What the Alert / Incident / Both choice on the recommendations create form
20
+ * actually does to a generated monitor.
21
+ *
22
+ * The reason this file exists separately from MonitorRecommendationUtil.test.ts
23
+ * is that `createIncidents` / `createAlerts` are the two flags the monitor
24
+ * evaluator reads to decide whether a threshold breach turns into a record.
25
+ * They are booleans on a criteria instance, they have no UI on the
26
+ * recommendation card, and getting them wrong is invisible until production:
27
+ *
28
+ * - set both on a criteria that has no incidents/alerts to create, and the
29
+ * auto-resolve path counts that criteria as breach-producing, so a
30
+ * recovered monitor never closes the incident it opened;
31
+ * - set neither on the criteria that DOES have them, and the monitor
32
+ * silently watches a threshold and tells nobody;
33
+ * - empty the arrays instead of clearing the flag, and the user's later
34
+ * "actually I do want incidents" costs them re-authoring every title,
35
+ * description and severity by hand.
36
+ *
37
+ * None of those three failures produce an error, a validation failure, or a
38
+ * visible difference on the recommendations page. They only show up the next
39
+ * time something actually breaks.
40
+ */
41
+
42
+ const ONLINE_STATUS_ID: ObjectID = ObjectID.generate();
43
+ const OFFLINE_STATUS_ID: ObjectID = ObjectID.generate();
44
+ const DEFAULT_STATUS_ID: ObjectID = ObjectID.generate();
45
+ const INCIDENT_SEVERITY_ID: ObjectID = ObjectID.generate();
46
+ const ALERT_SEVERITY_ID: ObjectID = ObjectID.generate();
47
+
48
+ function buildArgs(
49
+ overrides?: Partial<MonitorRecommendationArgs>,
50
+ ): MonitorRecommendationArgs {
51
+ return {
52
+ resourceIdentifier: "prod-cluster-01",
53
+ onlineMonitorStatusId: ONLINE_STATUS_ID,
54
+ offlineMonitorStatusId: OFFLINE_STATUS_ID,
55
+ defaultIncidentSeverityId: INCIDENT_SEVERITY_ID,
56
+ defaultAlertSeverityId: ALERT_SEVERITY_ID,
57
+ monitorName: "Test Monitor",
58
+ ...overrides,
59
+ };
60
+ }
61
+
62
+ function getCriteriaInstances(
63
+ monitorStep: MonitorStep,
64
+ ): Array<MonitorCriteriaInstance> {
65
+ return (
66
+ monitorStep.data?.monitorCriteria?.data?.monitorCriteriaInstanceArray || []
67
+ );
68
+ }
69
+
70
+ /*
71
+ * The recovery ("Healthy") criteria is identified structurally — empty
72
+ * incidents AND empty alerts — rather than by its name, because the eight
73
+ * template modules name it inconsistently once a template overrides
74
+ * `criteriaName`. Empty-arrays IS the property that makes flipping a flag on it
75
+ * meaningless-at-best and harmful-at-worst, so it is the right thing to key on.
76
+ */
77
+ function isRecoveryCriteriaInstance(
78
+ criteriaInstance: MonitorCriteriaInstance,
79
+ ): boolean {
80
+ return (
81
+ (criteriaInstance.data?.incidents || []).length === 0 &&
82
+ (criteriaInstance.data?.alerts || []).length === 0
83
+ );
84
+ }
85
+
86
+ function getRecoveryCriteriaInstances(
87
+ monitorStep: MonitorStep,
88
+ ): Array<MonitorCriteriaInstance> {
89
+ return getCriteriaInstances(monitorStep).filter(isRecoveryCriteriaInstance);
90
+ }
91
+
92
+ /*
93
+ * Every criteria instance that ships something to create — the "Unhealthy"
94
+ * ones. Ceph's Monitor Disk template ships two of them (a CRIT tier and a LOW
95
+ * tier), so this is deliberately a list and not a single instance.
96
+ */
97
+ function getBreachCriteriaInstances(
98
+ monitorStep: MonitorStep,
99
+ ): Array<MonitorCriteriaInstance> {
100
+ return getCriteriaInstances(monitorStep).filter(
101
+ (criteriaInstance: MonitorCriteriaInstance) => {
102
+ return !isRecoveryCriteriaInstance(criteriaInstance);
103
+ },
104
+ );
105
+ }
106
+
107
+ function applyMode(data: {
108
+ recommendation: MonitorRecommendation;
109
+ notificationMode: MonitorRecommendationNotificationMode | undefined;
110
+ }): MonitorStep {
111
+ return MonitorRecommendationUtil.applyNotificationSettingsToMonitorStep({
112
+ monitorStep: data.recommendation.getMonitorStep(buildArgs()),
113
+ notificationSettings: { notificationMode: data.notificationMode },
114
+ severity: data.recommendation.severity,
115
+ });
116
+ }
117
+
118
+ const ALL_RECOMMENDATIONS: Array<MonitorRecommendation> =
119
+ MonitorRecommendationCatalog.getAllRecommendations();
120
+
121
+ // One representative recommendation per resource type, for the focused tests.
122
+ const ONE_PER_RESOURCE_TYPE: Array<MonitorRecommendation> =
123
+ MonitorRecommendationCatalog.getResourceTypeDefinitions().map(
124
+ (definition: MonitorRecommendationResourceTypeDefinition) => {
125
+ return definition.getRecommendations()[0]!;
126
+ },
127
+ );
128
+
129
+ const ALL_MODES: Array<MonitorRecommendationNotificationMode> = [
130
+ MonitorRecommendationNotificationMode.Alert,
131
+ MonitorRecommendationNotificationMode.Incident,
132
+ MonitorRecommendationNotificationMode.Both,
133
+ ];
134
+
135
+ describe("MonitorRecommendationNotificationMode", () => {
136
+ describe("the shipped template baseline the modes are measured against", () => {
137
+ /*
138
+ * Everything below this describe block is a statement about how a mode
139
+ * CHANGES the templates. Those statements are only meaningful if the
140
+ * starting point is known, and the starting point lives in eight
141
+ * independently maintained `<X>AlertTemplates.ts` modules that nothing
142
+ * else forces to agree. If one of them ever ships, say, an unhealthy
143
+ * criteria with `createAlerts: false`, then "mode Both leaves both on"
144
+ * would still pass while quietly meaning something different. These two
145
+ * tests are the canary for that.
146
+ */
147
+
148
+ it("has recommendations to test at all", () => {
149
+ // Guards every for-loop in this file against a vacuous pass.
150
+ expect(ALL_RECOMMENDATIONS.length).toBeGreaterThan(0);
151
+ expect(ONE_PER_RESOURCE_TYPE.length).toBe(8);
152
+ });
153
+
154
+ it("ships every unhealthy criteria with createIncidents AND createAlerts true, and both arrays populated", () => {
155
+ for (const recommendation of ALL_RECOMMENDATIONS) {
156
+ const monitorStep: MonitorStep =
157
+ recommendation.getMonitorStep(buildArgs());
158
+
159
+ const breachInstances: Array<MonitorCriteriaInstance> =
160
+ getBreachCriteriaInstances(monitorStep);
161
+
162
+ expect(breachInstances.length).toBeGreaterThan(0);
163
+
164
+ for (const criteriaInstance of breachInstances) {
165
+ expect(criteriaInstance.data?.createIncidents).toBe(true);
166
+ expect(criteriaInstance.data?.createAlerts).toBe(true);
167
+ expect(
168
+ (criteriaInstance.data?.incidents || []).length,
169
+ ).toBeGreaterThan(0);
170
+ expect((criteriaInstance.data?.alerts || []).length).toBeGreaterThan(
171
+ 0,
172
+ );
173
+ }
174
+ }
175
+ });
176
+
177
+ it("ships exactly one recovery criteria per recommendation, with both flags false and both arrays empty", () => {
178
+ for (const recommendation of ALL_RECOMMENDATIONS) {
179
+ const recoveryInstances: Array<MonitorCriteriaInstance> =
180
+ getRecoveryCriteriaInstances(
181
+ recommendation.getMonitorStep(buildArgs()),
182
+ );
183
+
184
+ expect(recoveryInstances.length).toBe(1);
185
+
186
+ expect(recoveryInstances[0]!.data?.createIncidents).toBe(false);
187
+ expect(recoveryInstances[0]!.data?.createAlerts).toBe(false);
188
+ expect(recoveryInstances[0]!.data?.incidents).toEqual([]);
189
+ expect(recoveryInstances[0]!.data?.alerts).toEqual([]);
190
+ }
191
+ });
192
+
193
+ it("ships at least one recommendation with more than one unhealthy criteria", () => {
194
+ /*
195
+ * Ceph's monitor-disk template tiers CRIT and LOW into two unhealthy
196
+ * criteria on one monitor. Without a multi-criteria template in the
197
+ * catalog, "the mode is applied to EVERY unhealthy criteria" below could
198
+ * never fail — a buggy implementation that only touched the first
199
+ * criteria instance would pass every other test in this file.
200
+ */
201
+ const multiCriteriaRecommendations: Array<MonitorRecommendation> =
202
+ ALL_RECOMMENDATIONS.filter((recommendation: MonitorRecommendation) => {
203
+ return (
204
+ getBreachCriteriaInstances(
205
+ recommendation.getMonitorStep(buildArgs()),
206
+ ).length > 1
207
+ );
208
+ });
209
+
210
+ expect(multiCriteriaRecommendations.length).toBeGreaterThan(0);
211
+ });
212
+ });
213
+
214
+ describe("applyNotificationSettingsToMonitorStep — notification mode", () => {
215
+ it("mode Alert leaves alerts on and turns incidents off, on every unhealthy criteria", () => {
216
+ for (const recommendation of ALL_RECOMMENDATIONS) {
217
+ const monitorStep: MonitorStep = applyMode({
218
+ recommendation: recommendation,
219
+ notificationMode: MonitorRecommendationNotificationMode.Alert,
220
+ });
221
+
222
+ for (const criteriaInstance of getBreachCriteriaInstances(
223
+ monitorStep,
224
+ )) {
225
+ expect(criteriaInstance.data?.createAlerts).toBe(true);
226
+ expect(criteriaInstance.data?.createIncidents).toBe(false);
227
+ }
228
+ }
229
+ });
230
+
231
+ it("mode Incident leaves incidents on and turns alerts off, on every unhealthy criteria", () => {
232
+ for (const recommendation of ALL_RECOMMENDATIONS) {
233
+ const monitorStep: MonitorStep = applyMode({
234
+ recommendation: recommendation,
235
+ notificationMode: MonitorRecommendationNotificationMode.Incident,
236
+ });
237
+
238
+ for (const criteriaInstance of getBreachCriteriaInstances(
239
+ monitorStep,
240
+ )) {
241
+ expect(criteriaInstance.data?.createIncidents).toBe(true);
242
+ expect(criteriaInstance.data?.createAlerts).toBe(false);
243
+ }
244
+ }
245
+ });
246
+
247
+ it("mode Both leaves both on, on every unhealthy criteria", () => {
248
+ for (const recommendation of ALL_RECOMMENDATIONS) {
249
+ const monitorStep: MonitorStep = applyMode({
250
+ recommendation: recommendation,
251
+ notificationMode: MonitorRecommendationNotificationMode.Both,
252
+ });
253
+
254
+ for (const criteriaInstance of getBreachCriteriaInstances(
255
+ monitorStep,
256
+ )) {
257
+ expect(criteriaInstance.data?.createIncidents).toBe(true);
258
+ expect(criteriaInstance.data?.createAlerts).toBe(true);
259
+ }
260
+ }
261
+ });
262
+
263
+ it("an absent mode leaves the flags exactly as the template shipped them", () => {
264
+ /*
265
+ * The backwards-compatible path. `notificationMode` is optional, and any
266
+ * caller that predates it — older tests, MonitorRecommendationCreateUtil
267
+ * before the form gained the toggle, any future programmatic caller —
268
+ * passes settings without it. Those callers must keep creating
269
+ * both-incident-and-alert monitors rather than silently inheriting a
270
+ * default someone else picked, so `undefined` is a distinct state from
271
+ * `Both` and not a synonym for it.
272
+ */
273
+ for (const recommendation of ALL_RECOMMENDATIONS) {
274
+ const monitorStep: MonitorStep = applyMode({
275
+ recommendation: recommendation,
276
+ notificationMode: undefined,
277
+ });
278
+
279
+ for (const criteriaInstance of getBreachCriteriaInstances(
280
+ monitorStep,
281
+ )) {
282
+ expect(criteriaInstance.data?.createIncidents).toBe(true);
283
+ expect(criteriaInstance.data?.createAlerts).toBe(true);
284
+ }
285
+ }
286
+ });
287
+
288
+ it("settings that carry no mode at all leave the flags alone too", () => {
289
+ /*
290
+ * Same guarantee as above, reached the other way: a settings object that
291
+ * only sets on-call policies / labels / severities must not disturb the
292
+ * flags as a side effect of the severity or owner writes.
293
+ */
294
+ const settingsWithoutMode: MonitorRecommendationNotificationSettings = {
295
+ onCallPolicyIds: [ObjectID.generate()],
296
+ labelIds: [ObjectID.generate()],
297
+ ownerTeamIds: [ObjectID.generate()],
298
+ ownerUserIds: [ObjectID.generate()],
299
+ };
300
+
301
+ for (const recommendation of ONE_PER_RESOURCE_TYPE) {
302
+ const monitorStep: MonitorStep =
303
+ MonitorRecommendationUtil.applyNotificationSettingsToMonitorStep({
304
+ monitorStep: recommendation.getMonitorStep(buildArgs()),
305
+ notificationSettings: settingsWithoutMode,
306
+ severity: recommendation.severity,
307
+ });
308
+
309
+ for (const criteriaInstance of getBreachCriteriaInstances(
310
+ monitorStep,
311
+ )) {
312
+ expect(criteriaInstance.data?.createIncidents).toBe(true);
313
+ expect(criteriaInstance.data?.createAlerts).toBe(true);
314
+ }
315
+ }
316
+ });
317
+
318
+ it("never marks the recovery criteria as incident- or alert-producing, under ANY mode", () => {
319
+ /*
320
+ * The highest-value assertion in this file, and the one most likely to be
321
+ * broken by an innocent-looking simplification of
322
+ * `applyNotificationModeToCriteriaInstance` (dropping its
323
+ * "only if the array is non-empty" guards reads like dead code).
324
+ *
325
+ * The recovery criteria is what fires when a monitor comes back healthy.
326
+ * `createIncidents: true` on it means the auto-resolve path treats it as
327
+ * a criteria that contributes breaches, so the recovery never resolves
328
+ * the incident the unhealthy criteria opened. The monitor would look
329
+ * correct on the create form, create correctly, alert correctly — and
330
+ * then leave a permanently open incident behind after every recovery,
331
+ * with nothing in the config visibly wrong. `Both` is the dangerous mode
332
+ * here precisely because it is the one that turns everything else on.
333
+ */
334
+ for (const recommendation of ALL_RECOMMENDATIONS) {
335
+ for (const notificationMode of ALL_MODES) {
336
+ const monitorStep: MonitorStep = applyMode({
337
+ recommendation: recommendation,
338
+ notificationMode: notificationMode,
339
+ });
340
+
341
+ const recoveryInstances: Array<MonitorCriteriaInstance> =
342
+ getRecoveryCriteriaInstances(monitorStep);
343
+
344
+ expect(recoveryInstances.length).toBe(1);
345
+
346
+ for (const criteriaInstance of recoveryInstances) {
347
+ expect(criteriaInstance.data?.createIncidents).toBe(false);
348
+ expect(criteriaInstance.data?.createAlerts).toBe(false);
349
+ // Still nothing to create, so the flags stayed meaningful.
350
+ expect(criteriaInstance.data?.incidents).toEqual([]);
351
+ expect(criteriaInstance.data?.alerts).toEqual([]);
352
+ }
353
+ }
354
+ }
355
+ });
356
+
357
+ it("keeps the incident config intact when mode Alert switches incidents off", () => {
358
+ /*
359
+ * Turning a mode off must clear the flag and nothing else. If the
360
+ * implementation instead emptied `incidents`, the switch would be
361
+ * one-way: the user who later opens the monitor's criteria form and
362
+ * flips "Create Incidents" back on would find an empty incident with no
363
+ * title, no description and no severity — and would have to re-author by
364
+ * hand the exact text the template wrote for them.
365
+ */
366
+ for (const recommendation of ONE_PER_RESOURCE_TYPE) {
367
+ const templateStep: MonitorStep =
368
+ recommendation.getMonitorStep(buildArgs());
369
+ const alertOnlyStep: MonitorStep = applyMode({
370
+ recommendation: recommendation,
371
+ notificationMode: MonitorRecommendationNotificationMode.Alert,
372
+ });
373
+
374
+ const templateIncidents: Array<CriteriaIncident> =
375
+ getBreachCriteriaInstances(templateStep).flatMap(
376
+ (criteriaInstance: MonitorCriteriaInstance) => {
377
+ return criteriaInstance.data?.incidents || [];
378
+ },
379
+ );
380
+ const alertOnlyIncidents: Array<CriteriaIncident> =
381
+ getBreachCriteriaInstances(alertOnlyStep).flatMap(
382
+ (criteriaInstance: MonitorCriteriaInstance) => {
383
+ return criteriaInstance.data?.incidents || [];
384
+ },
385
+ );
386
+
387
+ expect(alertOnlyIncidents.length).toBe(templateIncidents.length);
388
+ expect(alertOnlyIncidents.length).toBeGreaterThan(0);
389
+
390
+ alertOnlyIncidents.forEach(
391
+ (incident: CriteriaIncident, index: number) => {
392
+ expect(incident.title).toBe(templateIncidents[index]!.title);
393
+ expect(incident.description).toBe(
394
+ templateIncidents[index]!.description,
395
+ );
396
+ expect(incident.incidentSeverityId).toEqual(INCIDENT_SEVERITY_ID);
397
+ },
398
+ );
399
+ }
400
+ });
401
+
402
+ it("keeps the alert config intact when mode Incident switches alerts off", () => {
403
+ // The mirror image of the test above; the two toggles must behave alike.
404
+ for (const recommendation of ONE_PER_RESOURCE_TYPE) {
405
+ const templateStep: MonitorStep =
406
+ recommendation.getMonitorStep(buildArgs());
407
+ const incidentOnlyStep: MonitorStep = applyMode({
408
+ recommendation: recommendation,
409
+ notificationMode: MonitorRecommendationNotificationMode.Incident,
410
+ });
411
+
412
+ const templateAlerts: Array<CriteriaAlert> = getBreachCriteriaInstances(
413
+ templateStep,
414
+ ).flatMap((criteriaInstance: MonitorCriteriaInstance) => {
415
+ return criteriaInstance.data?.alerts || [];
416
+ });
417
+ const incidentOnlyAlerts: Array<CriteriaAlert> =
418
+ getBreachCriteriaInstances(incidentOnlyStep).flatMap(
419
+ (criteriaInstance: MonitorCriteriaInstance) => {
420
+ return criteriaInstance.data?.alerts || [];
421
+ },
422
+ );
423
+
424
+ expect(incidentOnlyAlerts.length).toBe(templateAlerts.length);
425
+ expect(incidentOnlyAlerts.length).toBeGreaterThan(0);
426
+
427
+ incidentOnlyAlerts.forEach((alert: CriteriaAlert, index: number) => {
428
+ expect(alert.title).toBe(templateAlerts[index]!.title);
429
+ expect(alert.description).toBe(templateAlerts[index]!.description);
430
+ expect(alert.alertSeverityId).toEqual(ALERT_SEVERITY_ID);
431
+ });
432
+ }
433
+ });
434
+
435
+ it("applies the mode alongside on-call policies and severities rather than instead of them", () => {
436
+ /*
437
+ * The mode write and the owner/severity writes happen in the same pass
438
+ * over the criteria instances. A short-circuit in either direction —
439
+ * returning early once the mode is handled, or skipping the mode when
440
+ * other settings are present — would leave half of the create form's
441
+ * choices on the floor.
442
+ */
443
+ const policyId: ObjectID = ObjectID.generate();
444
+ const criticalIncidentSeverityId: ObjectID = ObjectID.generate();
445
+ const warningIncidentSeverityId: ObjectID = ObjectID.generate();
446
+
447
+ for (const recommendation of ONE_PER_RESOURCE_TYPE) {
448
+ const monitorStep: MonitorStep =
449
+ MonitorRecommendationUtil.applyNotificationSettingsToMonitorStep({
450
+ monitorStep: recommendation.getMonitorStep(buildArgs()),
451
+ notificationSettings: {
452
+ notificationMode: MonitorRecommendationNotificationMode.Incident,
453
+ onCallPolicyIds: [policyId],
454
+ incidentSeverityIdBySeverity: {
455
+ Critical: criticalIncidentSeverityId,
456
+ Warning: warningIncidentSeverityId,
457
+ },
458
+ },
459
+ severity: recommendation.severity,
460
+ });
461
+
462
+ const expectedIncidentSeverityId: ObjectID =
463
+ recommendation.severity === "Critical"
464
+ ? criticalIncidentSeverityId
465
+ : warningIncidentSeverityId;
466
+
467
+ for (const criteriaInstance of getBreachCriteriaInstances(
468
+ monitorStep,
469
+ )) {
470
+ expect(criteriaInstance.data?.createIncidents).toBe(true);
471
+ expect(criteriaInstance.data?.createAlerts).toBe(false);
472
+
473
+ for (const incident of criteriaInstance.data?.incidents || []) {
474
+ expect(incident.onCallPolicyIds).toEqual([policyId]);
475
+ expect(incident.incidentSeverityId).toEqual(
476
+ expectedIncidentSeverityId,
477
+ );
478
+ }
479
+ }
480
+ }
481
+ });
482
+
483
+ it("does not throw on a step with no criteria instances", () => {
484
+ /*
485
+ * The mode pass runs before anything reads a criteria instance's arrays.
486
+ * A hand-built or partially-deserialized step must not take the create
487
+ * flow down.
488
+ */
489
+ for (const notificationMode of ALL_MODES) {
490
+ expect(() => {
491
+ MonitorRecommendationUtil.applyNotificationSettingsToMonitorStep({
492
+ monitorStep: new MonitorStep(),
493
+ notificationSettings: { notificationMode: notificationMode },
494
+ severity: "Critical",
495
+ });
496
+ }).not.toThrow();
497
+ }
498
+ });
499
+ });
500
+
501
+ describe("buildMonitorSteps with a notification mode", () => {
502
+ it("threads the mode through to the created monitor's criteria for every resource type", () => {
503
+ /*
504
+ * `buildMonitorSteps` is what the create flow actually calls;
505
+ * `applyNotificationSettingsToMonitorStep` is an implementation detail it
506
+ * happens to expose. If the wiring between them were dropped, every test
507
+ * above would still pass and the shipped feature would do nothing.
508
+ */
509
+ for (const recommendation of ONE_PER_RESOURCE_TYPE) {
510
+ for (const notificationMode of ALL_MODES) {
511
+ const monitorSteps: MonitorSteps =
512
+ MonitorRecommendationUtil.buildMonitorSteps({
513
+ recommendation: recommendation,
514
+ args: buildArgs(),
515
+ defaultMonitorStatusId: DEFAULT_STATUS_ID,
516
+ notificationSettings: { notificationMode: notificationMode },
517
+ });
518
+
519
+ const monitorStep: MonitorStep =
520
+ monitorSteps.data!.monitorStepsInstanceArray[0]!;
521
+
522
+ const expectsIncidents: boolean =
523
+ notificationMode !== MonitorRecommendationNotificationMode.Alert;
524
+ const expectsAlerts: boolean =
525
+ notificationMode !== MonitorRecommendationNotificationMode.Incident;
526
+
527
+ for (const criteriaInstance of getBreachCriteriaInstances(
528
+ monitorStep,
529
+ )) {
530
+ expect(criteriaInstance.data?.createIncidents).toBe(
531
+ expectsIncidents,
532
+ );
533
+ expect(criteriaInstance.data?.createAlerts).toBe(expectsAlerts);
534
+ }
535
+ }
536
+ }
537
+ });
538
+
539
+ it("still passes MonitorSteps.getValidationError under every mode, for every recommendation", () => {
540
+ /*
541
+ * `MonitorSteps.getValidationError` is the same client-side gate the
542
+ * monitor create form runs before POSTing, and it validates the incident
543
+ * and alert payloads regardless of whether their create flag is on. So a
544
+ * mode implementation that "disabled" a side by blanking a title or a
545
+ * severity id instead of clearing the flag would fail here — at submit
546
+ * time in production, with a message about a field the user was never
547
+ * shown, and only for the mode they happened to pick.
548
+ */
549
+ for (const recommendation of ALL_RECOMMENDATIONS) {
550
+ for (const notificationMode of ALL_MODES) {
551
+ const monitorSteps: MonitorSteps =
552
+ MonitorRecommendationUtil.buildMonitorSteps({
553
+ recommendation: recommendation,
554
+ args: buildArgs(),
555
+ defaultMonitorStatusId: DEFAULT_STATUS_ID,
556
+ notificationSettings: { notificationMode: notificationMode },
557
+ });
558
+
559
+ expect(
560
+ MonitorSteps.getValidationError(
561
+ monitorSteps,
562
+ recommendation.monitorType,
563
+ ),
564
+ ).toBeNull();
565
+ }
566
+ }
567
+ });
568
+
569
+ it("builds independent steps, so one monitor's mode does not leak into the next", () => {
570
+ /*
571
+ * The recommendations page creates a batch of monitors in one submit, and
572
+ * `applyNotificationSettingsToMonitorStep` mutates the step it is given.
573
+ * If the template modules ever returned a shared/cached criteria instance
574
+ * instead of a fresh one, choosing Alert for one recommendation would
575
+ * silently rewrite the flags of every monitor built before it in the same
576
+ * batch.
577
+ */
578
+ const recommendation: MonitorRecommendation = ONE_PER_RESOURCE_TYPE[0]!;
579
+
580
+ const incidentOnly: MonitorSteps =
581
+ MonitorRecommendationUtil.buildMonitorSteps({
582
+ recommendation: recommendation,
583
+ args: buildArgs(),
584
+ defaultMonitorStatusId: DEFAULT_STATUS_ID,
585
+ notificationSettings: {
586
+ notificationMode: MonitorRecommendationNotificationMode.Incident,
587
+ },
588
+ });
589
+
590
+ MonitorRecommendationUtil.buildMonitorSteps({
591
+ recommendation: recommendation,
592
+ args: buildArgs(),
593
+ defaultMonitorStatusId: DEFAULT_STATUS_ID,
594
+ notificationSettings: {
595
+ notificationMode: MonitorRecommendationNotificationMode.Alert,
596
+ },
597
+ });
598
+
599
+ for (const criteriaInstance of getBreachCriteriaInstances(
600
+ incidentOnly.data!.monitorStepsInstanceArray[0]!,
601
+ )) {
602
+ expect(criteriaInstance.data?.createIncidents).toBe(true);
603
+ expect(criteriaInstance.data?.createAlerts).toBe(false);
604
+ }
605
+ });
606
+ });
607
+ });