@oneuptime/common 11.7.2 → 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 (414) hide show
  1. package/Models/AnalyticsModels/KubernetesCostAllocation.ts +103 -0
  2. package/Models/DatabaseModels/AlertEpisodeStateTimeline.ts +1 -0
  3. package/Models/DatabaseModels/AlertStateTimeline.ts +1 -0
  4. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  5. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  6. package/Models/DatabaseModels/Index.ts +5 -0
  7. package/Models/DatabaseModels/LogDropFilter.ts +89 -0
  8. package/Models/DatabaseModels/NetworkDeviceDiscoveryScan.ts +13 -3
  9. package/Models/DatabaseModels/RecommendationDismissal.ts +463 -0
  10. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  11. package/Models/DatabaseModels/StatusPageGroup.ts +95 -0
  12. package/Models/DatabaseModels/TableView.ts +40 -0
  13. package/Models/DatabaseModels/TraceDropFilter.ts +89 -0
  14. package/Models/DatabaseModels/WorkflowVariable.ts +5 -1
  15. package/Server/API/AlertAPI.ts +32 -17
  16. package/Server/API/BaseAPI.ts +31 -2
  17. package/Server/API/BaseAnalyticsAPI.ts +36 -2
  18. package/Server/API/CommonAPI.ts +57 -0
  19. package/Server/API/IncidentAPI.ts +60 -33
  20. package/Server/API/IncidentEpisodeAPI.ts +31 -16
  21. package/Server/API/MonitorAPI.ts +30 -0
  22. package/Server/API/MonitorTemplateAPI.ts +8 -0
  23. package/Server/API/ProbeAPI.ts +196 -15
  24. package/Server/API/ProjectAPI.ts +79 -1
  25. package/Server/API/ScheduledMaintenanceAPI.ts +33 -18
  26. package/Server/API/StatusPageAPI.ts +74 -37
  27. package/Server/API/WorkspaceNotificationRuleAPI.ts +34 -4
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.ts +13 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.ts +527 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.ts +31 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.ts +55 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.ts +53 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  34. package/Server/Services/AlertEpisodeService.ts +47 -0
  35. package/Server/Services/AlertService.ts +125 -0
  36. package/Server/Services/BillingService.ts +98 -0
  37. package/Server/Services/DatabaseService.ts +184 -20
  38. package/Server/Services/IncidentEpisodeService.ts +47 -0
  39. package/Server/Services/IncidentService.ts +123 -0
  40. package/Server/Services/IncidentTemplateService.ts +123 -1
  41. package/Server/Services/Index.ts +2 -0
  42. package/Server/Services/LogDropFilterService.ts +133 -0
  43. package/Server/Services/MonitorProbeService.ts +94 -4
  44. package/Server/Services/MonitorService.ts +48 -43
  45. package/Server/Services/NetworkDeviceDiscoveryScanService.ts +70 -0
  46. package/Server/Services/ProbeService.ts +66 -0
  47. package/Server/Services/ProjectService.ts +131 -7
  48. package/Server/Services/RecommendationDismissalService.ts +52 -0
  49. package/Server/Services/RunbookAgentJobService.ts +68 -7
  50. package/Server/Services/ScheduledMaintenanceService.ts +103 -0
  51. package/Server/Services/ScheduledMaintenanceTemplateService.ts +90 -0
  52. package/Server/Services/StatusPageGroupService.ts +186 -0
  53. package/Server/Services/TraceDropFilterService.ts +133 -0
  54. package/Server/Types/Workflow/Components/API/Delete.ts +12 -0
  55. package/Server/Types/Workflow/Components/API/Get.ts +12 -0
  56. package/Server/Types/Workflow/Components/API/Patch.ts +12 -0
  57. package/Server/Types/Workflow/Components/API/Post.ts +12 -0
  58. package/Server/Types/Workflow/Components/API/Put.ts +13 -0
  59. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +212 -0
  60. package/Server/Utils/DropFilterValidation.ts +127 -0
  61. package/Server/Utils/Errors.ts +5 -0
  62. package/Server/Utils/Monitor/MonitorAlert.ts +28 -1
  63. package/Server/Utils/Monitor/MonitorIncident.ts +31 -2
  64. package/Server/Utils/Telemetry/AppMetrics.ts +31 -0
  65. package/Tests/Models/AnalyticsModels/KubernetesCostAllocation.test.ts +16 -0
  66. package/Tests/Models/DatabaseModels/MonitorProbeColumnAccessControl.test.ts +196 -0
  67. package/Tests/Models/RecommendationDismissalModel.test.ts +269 -0
  68. package/Tests/Server/API/BaseAPIUpdatePayloadValidation.test.ts +320 -0
  69. package/Tests/Server/API/BaseAnalyticsAPIUpdatePayloadValidation.test.ts +293 -0
  70. package/Tests/Server/API/CommonAPIAuthGuard.test.ts +164 -0
  71. package/Tests/Server/API/ProbeAPI.test.ts +422 -53
  72. package/Tests/Server/API/ProjectAPI.test.ts +180 -0
  73. package/Tests/Server/API/ProjectAPIExtendTrialBillingDisabled.test.ts +138 -0
  74. package/Tests/Server/API/ProjectScopedCustomRouteAuth.test.ts +458 -0
  75. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +359 -0
  76. package/Tests/Server/Infrastructure/ProcessSignalDelivery.test.ts +427 -0
  77. package/Tests/Server/Services/BillingServiceExtendTrial.test.ts +439 -0
  78. package/Tests/Server/Services/CrossProjectReferenceWriteGuard.test.ts +810 -0
  79. package/Tests/Server/Services/DatabaseServiceAtomicAddToColumns.test.ts +269 -0
  80. package/Tests/Server/Services/DatabaseServiceEmptyUpdate.test.ts +277 -0
  81. package/Tests/Server/Services/DatabaseServiceSortColumnSelect.test.ts +201 -0
  82. package/Tests/Server/Services/DiscoveryScanClaimHookFreeSafety.test.ts +81 -23
  83. package/Tests/Server/Services/DropFilterSaveValidation.test.ts +398 -0
  84. package/Tests/Server/Services/MonitorProbeDeleteHooks.test.ts +280 -0
  85. package/Tests/Server/Services/MonitorProbeServiceProbeTenancy.test.ts +304 -0
  86. package/Tests/Server/Services/NetworkDeviceDiscoveryScanService.test.ts +262 -0
  87. package/Tests/Server/Services/ProjectServiceExtendTrial.test.ts +614 -0
  88. package/Tests/Server/Services/RecommendationDismissalService.test.ts +306 -0
  89. package/Tests/Server/Services/RepairCrossProjectIncidentReferencesMigration.test.ts +528 -0
  90. package/Tests/Server/Services/StatusPageGroupNesting.test.ts +395 -0
  91. package/Tests/Server/TestingUtils/Services/BillingServiceHelper.ts +26 -21
  92. package/Tests/Server/Types/Database/Permissions/WorkflowVariableColumnPermission.test.ts +227 -0
  93. package/Tests/Server/Types/Workflow/Components/ApiComponentErrorPort.test.ts +285 -0
  94. package/Tests/Server/Utils/Database/ProjectScopedReferenceValidator.test.ts +463 -0
  95. package/Tests/Server/Utils/DropFilterValidation.test.ts +269 -0
  96. package/Tests/Server/Utils/Telemetry/SpanUtil.test.ts +94 -0
  97. package/Tests/Types/DateUserTimezone.test.ts +52 -0
  98. package/Tests/Types/JSONFunctions.test.ts +103 -1
  99. package/Tests/Types/Monitor/KubernetesAlertTemplates.test.ts +177 -9
  100. package/Tests/Types/Monitor/MonitorStepDnsMonitor.test.ts +105 -0
  101. package/Tests/Types/Monitor/MonitorStepDnssecMonitor.test.ts +131 -0
  102. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +60 -0
  103. package/Tests/Types/Monitor/MonitorStepExternalStatusPageMonitor.test.ts +82 -0
  104. package/Tests/Types/Monitor/MonitorStepInfrastructureMonitors.test.ts +268 -0
  105. package/Tests/Types/Monitor/MonitorStepMetricMonitor.test.ts +386 -0
  106. package/Tests/Types/Monitor/MonitorStepProfileMonitor.test.ts +185 -0
  107. package/Tests/Types/Monitor/MonitorStepSnmpMonitor.test.ts +156 -0
  108. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +371 -0
  109. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +901 -0
  110. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +607 -0
  111. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.test.ts +754 -0
  112. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +960 -0
  113. package/Tests/Types/RollingTime/RollingTimeUtil.test.ts +186 -0
  114. package/Tests/Types/Runbook/RunbookStepTimeout.test.ts +410 -0
  115. package/Tests/Types/Telemetry/DropFilterSampling.test.ts +241 -0
  116. package/Tests/Types/Workspace/NotificationRuleConditionUtil.test.ts +353 -0
  117. package/Tests/Types/Workspace/NotificationRuleUtil.test.ts +566 -0
  118. package/Tests/UI/Components/CodeEditor.test.tsx +174 -0
  119. package/Tests/UI/Components/ErrorBoundary.test.tsx +555 -24
  120. package/Tests/UI/Components/InfoCard.test.tsx +358 -0
  121. package/Tests/UI/Components/LogTimeRangePicker.test.tsx +138 -0
  122. package/Tests/UI/Components/Modal.test.tsx +43 -5
  123. package/Tests/UI/Components/ModelTable/BaseModelTableColumnCustomization.test.tsx +679 -0
  124. package/Tests/UI/Components/ModelTable/BaseModelTableSearchLabels.test.tsx +397 -0
  125. package/Tests/UI/Components/ModelTable/ColumnCustomizationModal.test.tsx +999 -0
  126. package/Tests/UI/Components/ModelTable/ColumnPreference.test.ts +1678 -0
  127. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +1094 -0
  128. package/Tests/UI/Components/Runbook/StepTimeoutInput.test.tsx +386 -0
  129. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +671 -0
  130. package/Tests/UI/Components/TelemetryTimeRangePicker.test.tsx +404 -0
  131. package/Tests/UI/Utils/DropdownAlignment.test.ts +306 -0
  132. package/Tests/UI/Utils/TableFilterUrlState.test.ts +292 -0
  133. package/Tests/Utils/Monitor/MonitorSummaryProbeUtil.test.ts +263 -0
  134. package/Tests/Utils/NetworkDiscovery/ScanTargetUtil.test.ts +583 -0
  135. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +1072 -0
  136. package/Tests/Utils/StatusPage/GroupTree.test.ts +583 -0
  137. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +411 -0
  138. package/Tests/Utils/UserPreferences.test.ts +563 -0
  139. package/Types/Date.ts +15 -6
  140. package/Types/JSONFunctions.ts +7 -2
  141. package/Types/Kubernetes/KubernetesCostIngest.ts +37 -1
  142. package/Types/Monitor/KubernetesAlertTemplates.ts +205 -0
  143. package/Types/Monitor/MonitorStep.ts +10 -1
  144. package/Types/Monitor/MonitorStepMetricMonitor.ts +46 -1
  145. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +413 -0
  146. package/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.ts +168 -0
  147. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +175 -0
  148. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +743 -0
  149. package/Types/Permission.ts +45 -0
  150. package/Types/Recommendation/RecommendationType.ts +20 -0
  151. package/Types/Runbook/RunbookExecutionDeadline.ts +129 -0
  152. package/Types/Runbook/RunbookStepTimeout.ts +202 -0
  153. package/Types/Telemetry/DropFilterSampling.ts +92 -0
  154. package/UI/Components/AI/GenerateFromAIModal.tsx +0 -2
  155. package/UI/Components/Accordion/Accordion.tsx +10 -2
  156. package/UI/Components/BulkUpdate/BulkLabelActions.tsx +0 -1
  157. package/UI/Components/CodeEditor/CodeEditor.tsx +34 -20
  158. package/UI/Components/Date/RangeStartAndEndDateView.tsx +0 -1
  159. package/UI/Components/EditionLabel/EditionLabel.tsx +1 -27
  160. package/UI/Components/Error/PageError.tsx +0 -4
  161. package/UI/Components/ErrorBoundary.tsx +252 -15
  162. package/UI/Components/InfoCard/InfoCard.tsx +58 -1
  163. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +34 -1
  164. package/UI/Components/MasterPage/MasterPage.tsx +65 -0
  165. package/UI/Components/Modal/Modal.tsx +16 -60
  166. package/UI/Components/ModelFormModal/ModelFormModal.tsx +0 -8
  167. package/UI/Components/ModelTable/BaseModelTable.tsx +503 -71
  168. package/UI/Components/ModelTable/Column.ts +17 -0
  169. package/UI/Components/ModelTable/ColumnCustomizationModal.tsx +523 -0
  170. package/UI/Components/ModelTable/ColumnPreference.ts +482 -0
  171. package/UI/Components/ModelTable/CustomFieldColumns.tsx +326 -0
  172. package/UI/Components/ModelTable/TableView.tsx +24 -2
  173. package/UI/Components/ModelTable/useCustomFieldColumns.ts +150 -0
  174. package/UI/Components/Runbook/StepTimeoutInput.tsx +173 -0
  175. package/UI/Components/SideMenu/SideMenu.tsx +24 -4
  176. package/UI/Components/StatusPage/ResourceGroupSection.tsx +231 -0
  177. package/UI/Components/Table/Table.tsx +14 -1
  178. package/UI/Components/Table/TableRow.tsx +180 -175
  179. package/UI/Components/Table/Types/Column.ts +2 -0
  180. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +34 -1
  181. package/UI/Utils/DropdownAlignment.ts +162 -0
  182. package/UI/Utils/TableFilterUrlState.ts +59 -20
  183. package/Utils/API.ts +106 -2
  184. package/Utils/Monitor/MonitorSummaryProbeUtil.ts +130 -0
  185. package/Utils/NetworkDiscovery/ScanTargetUtil.ts +434 -0
  186. package/Utils/StatusPage/GroupNestingLayout.ts +343 -0
  187. package/Utils/StatusPage/GroupTree.ts +307 -0
  188. package/Utils/StatusPage/ResourceUptime.ts +90 -17
  189. package/Utils/UserPreferences.ts +53 -0
  190. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js +86 -0
  191. package/build/dist/Models/AnalyticsModels/KubernetesCostAllocation.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js +1 -0
  193. package/build/dist/Models/DatabaseModels/AlertEpisodeStateTimeline.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js +1 -0
  195. package/build/dist/Models/DatabaseModels/AlertStateTimeline.js.map +1 -1
  196. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  197. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  199. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  201. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/LogDropFilter.js +91 -0
  203. package/build/dist/Models/DatabaseModels/LogDropFilter.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js +14 -4
  205. package/build/dist/Models/DatabaseModels/NetworkDeviceDiscoveryScan.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js +484 -0
  207. package/build/dist/Models/DatabaseModels/RecommendationDismissal.js.map +1 -0
  208. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  209. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/StatusPageGroup.js +94 -0
  211. package/build/dist/Models/DatabaseModels/StatusPageGroup.js.map +1 -1
  212. package/build/dist/Models/DatabaseModels/TableView.js +40 -0
  213. package/build/dist/Models/DatabaseModels/TableView.js.map +1 -1
  214. package/build/dist/Models/DatabaseModels/TraceDropFilter.js +91 -0
  215. package/build/dist/Models/DatabaseModels/TraceDropFilter.js.map +1 -1
  216. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +5 -1
  217. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  218. package/build/dist/Server/API/AlertAPI.js +22 -13
  219. package/build/dist/Server/API/AlertAPI.js.map +1 -1
  220. package/build/dist/Server/API/BaseAPI.js +22 -1
  221. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  222. package/build/dist/Server/API/BaseAnalyticsAPI.js +24 -1
  223. package/build/dist/Server/API/BaseAnalyticsAPI.js.map +1 -1
  224. package/build/dist/Server/API/CommonAPI.js +42 -0
  225. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  226. package/build/dist/Server/API/IncidentAPI.js +43 -26
  227. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  228. package/build/dist/Server/API/IncidentEpisodeAPI.js +21 -12
  229. package/build/dist/Server/API/IncidentEpisodeAPI.js.map +1 -1
  230. package/build/dist/Server/API/MonitorAPI.js +23 -0
  231. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  232. package/build/dist/Server/API/MonitorTemplateAPI.js +4 -0
  233. package/build/dist/Server/API/MonitorTemplateAPI.js.map +1 -1
  234. package/build/dist/Server/API/ProbeAPI.js +131 -15
  235. package/build/dist/Server/API/ProbeAPI.js.map +1 -1
  236. package/build/dist/Server/API/ProjectAPI.js +62 -3
  237. package/build/dist/Server/API/ProjectAPI.js.map +1 -1
  238. package/build/dist/Server/API/ScheduledMaintenanceAPI.js +23 -14
  239. package/build/dist/Server/API/ScheduledMaintenanceAPI.js.map +1 -1
  240. package/build/dist/Server/API/StatusPageAPI.js +61 -33
  241. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  242. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js +26 -2
  243. package/build/dist/Server/API/WorkspaceNotificationRuleAPI.js.map +1 -1
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js +12 -0
  245. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785241000000-AddColumnsToTableView.js.map +1 -0
  246. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js +397 -0
  247. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences.js.map +1 -0
  248. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js +16 -0
  249. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785329453269-AddParentGroupToStatusPageGroup.js.map +1 -0
  250. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js +30 -0
  251. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785397674289-AddRecommendationDismissalTable.js.map +1 -0
  252. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js +34 -0
  253. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1785405581596-AddDroppedCountersToDropFilters.js.map +1 -0
  254. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  255. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  256. package/build/dist/Server/Services/AlertEpisodeService.js +39 -0
  257. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  258. package/build/dist/Server/Services/AlertService.js +95 -0
  259. package/build/dist/Server/Services/AlertService.js.map +1 -1
  260. package/build/dist/Server/Services/BillingService.js +71 -0
  261. package/build/dist/Server/Services/BillingService.js.map +1 -1
  262. package/build/dist/Server/Services/DatabaseService.js +140 -17
  263. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  264. package/build/dist/Server/Services/IncidentEpisodeService.js +39 -0
  265. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  266. package/build/dist/Server/Services/IncidentService.js +100 -0
  267. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  268. package/build/dist/Server/Services/IncidentTemplateService.js +97 -0
  269. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  270. package/build/dist/Server/Services/Index.js +2 -0
  271. package/build/dist/Server/Services/Index.js.map +1 -1
  272. package/build/dist/Server/Services/LogDropFilterService.js +93 -0
  273. package/build/dist/Server/Services/LogDropFilterService.js.map +1 -1
  274. package/build/dist/Server/Services/MonitorProbeService.js +73 -5
  275. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  276. package/build/dist/Server/Services/MonitorService.js +34 -39
  277. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  278. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js +71 -0
  279. package/build/dist/Server/Services/NetworkDeviceDiscoveryScanService.js.map +1 -1
  280. package/build/dist/Server/Services/ProbeService.js +64 -0
  281. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  282. package/build/dist/Server/Services/ProjectService.js +103 -7
  283. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  284. package/build/dist/Server/Services/RecommendationDismissalService.js +50 -0
  285. package/build/dist/Server/Services/RecommendationDismissalService.js.map +1 -0
  286. package/build/dist/Server/Services/RunbookAgentJobService.js +63 -5
  287. package/build/dist/Server/Services/RunbookAgentJobService.js.map +1 -1
  288. package/build/dist/Server/Services/ScheduledMaintenanceService.js +83 -0
  289. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  290. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +65 -0
  291. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  292. package/build/dist/Server/Services/StatusPageGroupService.js +136 -0
  293. package/build/dist/Server/Services/StatusPageGroupService.js.map +1 -1
  294. package/build/dist/Server/Services/TraceDropFilterService.js +93 -0
  295. package/build/dist/Server/Services/TraceDropFilterService.js.map +1 -1
  296. package/build/dist/Server/Types/Workflow/Components/API/Delete.js +11 -0
  297. package/build/dist/Server/Types/Workflow/Components/API/Delete.js.map +1 -1
  298. package/build/dist/Server/Types/Workflow/Components/API/Get.js +11 -0
  299. package/build/dist/Server/Types/Workflow/Components/API/Get.js.map +1 -1
  300. package/build/dist/Server/Types/Workflow/Components/API/Patch.js +11 -0
  301. package/build/dist/Server/Types/Workflow/Components/API/Patch.js.map +1 -1
  302. package/build/dist/Server/Types/Workflow/Components/API/Post.js +11 -0
  303. package/build/dist/Server/Types/Workflow/Components/API/Post.js.map +1 -1
  304. package/build/dist/Server/Types/Workflow/Components/API/Put.js +12 -0
  305. package/build/dist/Server/Types/Workflow/Components/API/Put.js.map +1 -1
  306. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +132 -0
  307. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -0
  308. package/build/dist/Server/Utils/DropFilterValidation.js +80 -0
  309. package/build/dist/Server/Utils/DropFilterValidation.js.map +1 -0
  310. package/build/dist/Server/Utils/Errors.js +3 -0
  311. package/build/dist/Server/Utils/Errors.js.map +1 -1
  312. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +30 -12
  313. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  314. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +38 -18
  315. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  316. package/build/dist/Server/Utils/Telemetry/AppMetrics.js +26 -0
  317. package/build/dist/Server/Utils/Telemetry/AppMetrics.js.map +1 -1
  318. package/build/dist/Types/Date.js +14 -4
  319. package/build/dist/Types/Date.js.map +1 -1
  320. package/build/dist/Types/JSONFunctions.js +8 -3
  321. package/build/dist/Types/JSONFunctions.js.map +1 -1
  322. package/build/dist/Types/Kubernetes/KubernetesCostIngest.js.map +1 -1
  323. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +192 -0
  324. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  325. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  326. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  327. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js +32 -1
  328. package/build/dist/Types/Monitor/MonitorStepMetricMonitor.js.map +1 -1
  329. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +294 -0
  330. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -0
  331. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js +110 -0
  332. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationSeverityMapper.js.map +1 -0
  333. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +58 -0
  334. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -0
  335. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +451 -0
  336. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -0
  337. package/build/dist/Types/Permission.js +40 -0
  338. package/build/dist/Types/Permission.js.map +1 -1
  339. package/build/dist/Types/Recommendation/RecommendationType.js +21 -0
  340. package/build/dist/Types/Recommendation/RecommendationType.js.map +1 -0
  341. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js +93 -0
  342. package/build/dist/Types/Runbook/RunbookExecutionDeadline.js.map +1 -0
  343. package/build/dist/Types/Runbook/RunbookStepTimeout.js +142 -0
  344. package/build/dist/Types/Runbook/RunbookStepTimeout.js.map +1 -0
  345. package/build/dist/Types/Telemetry/DropFilterSampling.js +75 -0
  346. package/build/dist/Types/Telemetry/DropFilterSampling.js.map +1 -0
  347. package/build/dist/UI/Components/AI/GenerateFromAIModal.js +1 -2
  348. package/build/dist/UI/Components/AI/GenerateFromAIModal.js.map +1 -1
  349. package/build/dist/UI/Components/Accordion/Accordion.js +9 -2
  350. package/build/dist/UI/Components/Accordion/Accordion.js.map +1 -1
  351. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js +1 -1
  352. package/build/dist/UI/Components/BulkUpdate/BulkLabelActions.js.map +1 -1
  353. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +27 -14
  354. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  355. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js +1 -1
  356. package/build/dist/UI/Components/Date/RangeStartAndEndDateView.js.map +1 -1
  357. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +2 -20
  358. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  359. package/build/dist/UI/Components/Error/PageError.js +1 -3
  360. package/build/dist/UI/Components/Error/PageError.js.map +1 -1
  361. package/build/dist/UI/Components/ErrorBoundary.js +145 -11
  362. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  363. package/build/dist/UI/Components/InfoCard/InfoCard.js +28 -1
  364. package/build/dist/UI/Components/InfoCard/InfoCard.js.map +1 -1
  365. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +13 -2
  366. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  367. package/build/dist/UI/Components/MasterPage/MasterPage.js +50 -1
  368. package/build/dist/UI/Components/MasterPage/MasterPage.js.map +1 -1
  369. package/build/dist/UI/Components/Modal/Modal.js +4 -32
  370. package/build/dist/UI/Components/Modal/Modal.js.map +1 -1
  371. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  372. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +308 -40
  373. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  374. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js +230 -0
  375. package/build/dist/UI/Components/ModelTable/ColumnCustomizationModal.js.map +1 -0
  376. package/build/dist/UI/Components/ModelTable/ColumnPreference.js +258 -0
  377. package/build/dist/UI/Components/ModelTable/ColumnPreference.js.map +1 -0
  378. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +168 -0
  379. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -0
  380. package/build/dist/UI/Components/ModelTable/TableView.js +13 -2
  381. package/build/dist/UI/Components/ModelTable/TableView.js.map +1 -1
  382. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +84 -0
  383. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -0
  384. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js +101 -0
  385. package/build/dist/UI/Components/Runbook/StepTimeoutInput.js.map +1 -0
  386. package/build/dist/UI/Components/SideMenu/SideMenu.js +15 -5
  387. package/build/dist/UI/Components/SideMenu/SideMenu.js.map +1 -1
  388. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js +73 -0
  389. package/build/dist/UI/Components/StatusPage/ResourceGroupSection.js.map +1 -0
  390. package/build/dist/UI/Components/Table/Table.js +15 -2
  391. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  392. package/build/dist/UI/Components/Table/TableRow.js +11 -6
  393. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  394. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +13 -2
  395. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  396. package/build/dist/UI/Utils/DropdownAlignment.js +98 -0
  397. package/build/dist/UI/Utils/DropdownAlignment.js.map +1 -0
  398. package/build/dist/UI/Utils/TableFilterUrlState.js +48 -15
  399. package/build/dist/UI/Utils/TableFilterUrlState.js.map +1 -1
  400. package/build/dist/Utils/API.js +39 -2
  401. package/build/dist/Utils/API.js.map +1 -1
  402. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js +97 -0
  403. package/build/dist/Utils/Monitor/MonitorSummaryProbeUtil.js.map +1 -0
  404. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js +330 -0
  405. package/build/dist/Utils/NetworkDiscovery/ScanTargetUtil.js.map +1 -0
  406. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +280 -0
  407. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -0
  408. package/build/dist/Utils/StatusPage/GroupTree.js +214 -0
  409. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -0
  410. package/build/dist/Utils/StatusPage/ResourceUptime.js +60 -16
  411. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  412. package/build/dist/Utils/UserPreferences.js +33 -0
  413. package/build/dist/Utils/UserPreferences.js.map +1 -1
  414. package/package.json +1 -1
@@ -0,0 +1,398 @@
1
+ import LogDropFilterService from "../../../Server/Services/LogDropFilterService";
2
+ import TraceDropFilterService from "../../../Server/Services/TraceDropFilterService";
3
+ import LogDropFilter from "../../../Models/DatabaseModels/LogDropFilter";
4
+ import TraceDropFilter from "../../../Models/DatabaseModels/TraceDropFilter";
5
+ import LogDropFilterAction from "../../../Types/Log/LogDropFilterAction";
6
+ import TraceDropFilterAction from "../../../Types/Trace/TraceDropFilterAction";
7
+ import BadDataException from "../../../Types/Exception/BadDataException";
8
+ import ObjectID from "../../../Types/ObjectID";
9
+ import CreateBy from "../../../Server/Types/Database/CreateBy";
10
+ import UpdateBy from "../../../Server/Types/Database/UpdateBy";
11
+ import { afterEach, describe, expect, it, jest } from "@jest/globals";
12
+
13
+ /*
14
+ * Contract under test — the create/update hooks on both drop-filter services.
15
+ *
16
+ * A drop filter is the only piece of project config that deletes customer
17
+ * data as its normal operation, and two of its fields could be saved in
18
+ * states the engine could not honour:
19
+ *
20
+ * - a blank `filterQuery`, which compiled to "match every record" and so
21
+ * turned the filter into "discard 100% of this project's telemetry",
22
+ * - `action = "sample"` with no percentage, which the engine read as
23
+ * "discard half".
24
+ *
25
+ * Update is the harder half: a request need not name every field, so
26
+ * flipping `action` to "sample" while the stored percentage is null, or
27
+ * blanking `filterQuery` on a row whose action is already "drop", both have
28
+ * to be caught by validating the MERGED row rather than the incoming patch.
29
+ */
30
+
31
+ const FILTER_ID: ObjectID = new ObjectID(
32
+ "11111111-1111-4111-8111-111111111111",
33
+ );
34
+ const PROJECT_ID: ObjectID = new ObjectID(
35
+ "22222222-2222-4222-8222-222222222222",
36
+ );
37
+
38
+ interface StoredRow {
39
+ action: string;
40
+ samplePercentage: number | undefined;
41
+ filterQuery: string;
42
+ }
43
+
44
+ const VALID_QUERY: string = "severityText = 'Debug'";
45
+
46
+ /*
47
+ * Each case runs against both services. They are separate classes over
48
+ * separate tables with their own action enums, and the whole point of sharing
49
+ * the validator is that neither can drift — so every assertion is made twice
50
+ * rather than trusting the log side to speak for the trace side.
51
+ */
52
+ const SUITES: Array<{
53
+ name: string;
54
+ service: any;
55
+ makeModel: () => any;
56
+ sampleAction: string;
57
+ dropAction: string;
58
+ recordNoun: string;
59
+ }> = [
60
+ {
61
+ name: "LogDropFilterService",
62
+ service: LogDropFilterService,
63
+ makeModel: (): LogDropFilter => {
64
+ return new LogDropFilter();
65
+ },
66
+ sampleAction: LogDropFilterAction.Sample,
67
+ dropAction: LogDropFilterAction.Drop,
68
+ recordNoun: "logs",
69
+ },
70
+ {
71
+ name: "TraceDropFilterService",
72
+ service: TraceDropFilterService,
73
+ makeModel: (): TraceDropFilter => {
74
+ return new TraceDropFilter();
75
+ },
76
+ sampleAction: TraceDropFilterAction.Sample,
77
+ dropAction: TraceDropFilterAction.Drop,
78
+ recordNoun: "spans",
79
+ },
80
+ ];
81
+
82
+ describe.each(SUITES)(
83
+ "$name save-time validation",
84
+ ({ service, makeModel, sampleAction, dropAction, recordNoun }: any) => {
85
+ afterEach(() => {
86
+ jest.restoreAllMocks();
87
+ });
88
+
89
+ function createBy(data: {
90
+ action?: string | undefined;
91
+ samplePercentage?: number | undefined;
92
+ filterQuery?: string | undefined;
93
+ }): CreateBy<any> {
94
+ const model: any = makeModel();
95
+ model.name = "Noisy debug logs";
96
+ model.projectId = PROJECT_ID;
97
+ model.action = data.action;
98
+ model.filterQuery = data.filterQuery;
99
+
100
+ if (data.samplePercentage !== undefined) {
101
+ model.samplePercentage = data.samplePercentage;
102
+ }
103
+
104
+ return { data: model, props: { isRoot: true } } as CreateBy<any>;
105
+ }
106
+
107
+ function updateBy(patch: Record<string, unknown>): UpdateBy<any> {
108
+ return {
109
+ query: { _id: FILTER_ID.toString() },
110
+ data: patch,
111
+ props: { isRoot: true },
112
+ } as unknown as UpdateBy<any>;
113
+ }
114
+
115
+ /*
116
+ * The update hook reads the rows the update matches so it can merge the
117
+ * patch over them. This stands in for that read.
118
+ */
119
+ function mockStoredRow(row: StoredRow): jest.SpiedFunction<any> {
120
+ const model: any = makeModel();
121
+ model._id = FILTER_ID.toString();
122
+ model.action = row.action;
123
+ model.filterQuery = row.filterQuery;
124
+ if (row.samplePercentage !== undefined) {
125
+ model.samplePercentage = row.samplePercentage;
126
+ }
127
+
128
+ return jest
129
+ .spyOn(service, "findBy")
130
+ .mockImplementation(async (): Promise<Array<any>> => {
131
+ return [model];
132
+ }) as unknown as jest.SpiedFunction<any>;
133
+ }
134
+
135
+ describe("on create", () => {
136
+ it("accepts a drop filter with a real condition", async () => {
137
+ await expect(
138
+ service.onBeforeCreate(
139
+ createBy({ action: dropAction, filterQuery: VALID_QUERY }),
140
+ ),
141
+ ).resolves.toBeDefined();
142
+ });
143
+
144
+ it("accepts a sample filter with a percentage in range", async () => {
145
+ await expect(
146
+ service.onBeforeCreate(
147
+ createBy({
148
+ action: sampleAction,
149
+ samplePercentage: 10,
150
+ filterQuery: VALID_QUERY,
151
+ }),
152
+ ),
153
+ ).resolves.toBeDefined();
154
+ });
155
+
156
+ it("rejects a blank filter query, which would match everything", async () => {
157
+ for (const blank of ["", " ", "\n\t"]) {
158
+ await expect(
159
+ service.onBeforeCreate(
160
+ createBy({ action: dropAction, filterQuery: blank }),
161
+ ),
162
+ ).rejects.toThrow(BadDataException);
163
+ }
164
+ });
165
+
166
+ it("rejects a missing filter query", async () => {
167
+ await expect(
168
+ service.onBeforeCreate(createBy({ action: dropAction })),
169
+ ).rejects.toThrow(BadDataException);
170
+ });
171
+
172
+ it("names the right record type in the error", async () => {
173
+ await expect(
174
+ service.onBeforeCreate(
175
+ createBy({ action: dropAction, filterQuery: "" }),
176
+ ),
177
+ ).rejects.toThrow(new RegExp(recordNoun));
178
+ });
179
+
180
+ it("rejects a sample filter with no percentage", async () => {
181
+ await expect(
182
+ service.onBeforeCreate(
183
+ createBy({ action: sampleAction, filterQuery: VALID_QUERY }),
184
+ ),
185
+ ).rejects.toThrow(BadDataException);
186
+ });
187
+
188
+ it("rejects a sample percentage outside 1-99", async () => {
189
+ for (const outOfRange of [0, 100, -1, 250]) {
190
+ await expect(
191
+ service.onBeforeCreate(
192
+ createBy({
193
+ action: sampleAction,
194
+ samplePercentage: outOfRange,
195
+ filterQuery: VALID_QUERY,
196
+ }),
197
+ ),
198
+ ).rejects.toThrow(BadDataException);
199
+ }
200
+ });
201
+
202
+ it("does not care about the percentage on a drop filter", async () => {
203
+ await expect(
204
+ service.onBeforeCreate(
205
+ createBy({
206
+ action: dropAction,
207
+ samplePercentage: 0,
208
+ filterQuery: VALID_QUERY,
209
+ }),
210
+ ),
211
+ ).resolves.toBeDefined();
212
+ });
213
+ });
214
+
215
+ describe("on update", () => {
216
+ /*
217
+ * The hook must not pay for a SELECT on writes that cannot break the
218
+ * row — renaming a filter or toggling it off is the common case.
219
+ */
220
+ it("skips the row read entirely when no validated field is touched", async () => {
221
+ const findBy: jest.SpiedFunction<any> = mockStoredRow({
222
+ action: dropAction,
223
+ samplePercentage: undefined,
224
+ filterQuery: VALID_QUERY,
225
+ });
226
+
227
+ await service.onBeforeUpdate(
228
+ updateBy({ name: "Renamed", isEnabled: false, sortOrder: 3 }),
229
+ );
230
+
231
+ expect(findBy).not.toHaveBeenCalled();
232
+ });
233
+
234
+ it("accepts a percentage change that stays in range", async () => {
235
+ mockStoredRow({
236
+ action: sampleAction,
237
+ samplePercentage: 10,
238
+ filterQuery: VALID_QUERY,
239
+ });
240
+
241
+ await expect(
242
+ service.onBeforeUpdate(updateBy({ samplePercentage: 25 })),
243
+ ).resolves.toBeDefined();
244
+ });
245
+
246
+ it("rejects a percentage change that leaves the range", async () => {
247
+ mockStoredRow({
248
+ action: sampleAction,
249
+ samplePercentage: 10,
250
+ filterQuery: VALID_QUERY,
251
+ });
252
+
253
+ await expect(
254
+ service.onBeforeUpdate(updateBy({ samplePercentage: 0 })),
255
+ ).rejects.toThrow(BadDataException);
256
+ });
257
+
258
+ /*
259
+ * The merge case that a patch-only check would miss: the request names
260
+ * only `action`, and the row it lands on has no percentage stored.
261
+ */
262
+ it("rejects flipping to sample when the stored percentage is null", async () => {
263
+ mockStoredRow({
264
+ action: dropAction,
265
+ samplePercentage: undefined,
266
+ filterQuery: VALID_QUERY,
267
+ });
268
+
269
+ await expect(
270
+ service.onBeforeUpdate(updateBy({ action: sampleAction })),
271
+ ).rejects.toThrow(BadDataException);
272
+ });
273
+
274
+ it("allows flipping to sample when the patch supplies the percentage", async () => {
275
+ mockStoredRow({
276
+ action: dropAction,
277
+ samplePercentage: undefined,
278
+ filterQuery: VALID_QUERY,
279
+ });
280
+
281
+ await expect(
282
+ service.onBeforeUpdate(
283
+ updateBy({ action: sampleAction, samplePercentage: 5 }),
284
+ ),
285
+ ).resolves.toBeDefined();
286
+ });
287
+
288
+ it("allows flipping to sample when the stored percentage is already valid", async () => {
289
+ mockStoredRow({
290
+ action: dropAction,
291
+ samplePercentage: 20,
292
+ filterQuery: VALID_QUERY,
293
+ });
294
+
295
+ await expect(
296
+ service.onBeforeUpdate(updateBy({ action: sampleAction })),
297
+ ).resolves.toBeDefined();
298
+ });
299
+
300
+ /*
301
+ * The other merge case: blanking the query on a row that is already a
302
+ * drop filter. The patch alone looks like a harmless text edit.
303
+ */
304
+ it("rejects blanking the filter query on an existing drop filter", async () => {
305
+ mockStoredRow({
306
+ action: dropAction,
307
+ samplePercentage: undefined,
308
+ filterQuery: VALID_QUERY,
309
+ });
310
+
311
+ for (const blank of ["", " "]) {
312
+ await expect(
313
+ service.onBeforeUpdate(updateBy({ filterQuery: blank })),
314
+ ).rejects.toThrow(BadDataException);
315
+ }
316
+ });
317
+
318
+ it("allows replacing the filter query with another real condition", async () => {
319
+ mockStoredRow({
320
+ action: dropAction,
321
+ samplePercentage: undefined,
322
+ filterQuery: VALID_QUERY,
323
+ });
324
+
325
+ await expect(
326
+ service.onBeforeUpdate(
327
+ updateBy({ filterQuery: "body CONTAINS 'healthcheck'" }),
328
+ ),
329
+ ).resolves.toBeDefined();
330
+ });
331
+
332
+ /*
333
+ * A query can match more than one row. Every matched row has to be
334
+ * checked, or a bulk update could break the ones it did not look at.
335
+ */
336
+ it("validates every row the update matches, not just the first", async () => {
337
+ const healthy: any = makeModel();
338
+ healthy._id = FILTER_ID.toString();
339
+ healthy.action = sampleAction;
340
+ healthy.samplePercentage = 10;
341
+ healthy.filterQuery = VALID_QUERY;
342
+
343
+ const wouldBreak: any = makeModel();
344
+ wouldBreak._id = PROJECT_ID.toString();
345
+ wouldBreak.action = dropAction;
346
+ wouldBreak.filterQuery = VALID_QUERY;
347
+ // no samplePercentage stored
348
+
349
+ jest
350
+ .spyOn(service, "findBy")
351
+ .mockImplementation(async (): Promise<Array<any>> => {
352
+ return [healthy, wouldBreak];
353
+ });
354
+
355
+ await expect(
356
+ service.onBeforeUpdate(updateBy({ action: sampleAction })),
357
+ ).rejects.toThrow(BadDataException);
358
+ });
359
+
360
+ it("passes when the update matches no rows at all", async () => {
361
+ jest
362
+ .spyOn(service, "findBy")
363
+ .mockImplementation(async (): Promise<Array<any>> => {
364
+ return [];
365
+ });
366
+
367
+ await expect(
368
+ service.onBeforeUpdate(updateBy({ filterQuery: "" })),
369
+ ).resolves.toBeDefined();
370
+ });
371
+
372
+ /*
373
+ * A raw SQL expression cannot be evaluated here. Skipping is correct;
374
+ * rejecting would break a legitimate caller and validating a
375
+ * stringified function would be nonsense.
376
+ */
377
+ it("skips validation when a validated field is a raw SQL expression", async () => {
378
+ const findBy: jest.SpiedFunction<any> = mockStoredRow({
379
+ action: dropAction,
380
+ samplePercentage: undefined,
381
+ filterQuery: VALID_QUERY,
382
+ });
383
+
384
+ await expect(
385
+ service.onBeforeUpdate(
386
+ updateBy({
387
+ filterQuery: () => {
388
+ return "'x'";
389
+ },
390
+ }),
391
+ ),
392
+ ).resolves.toBeDefined();
393
+
394
+ expect(findBy).not.toHaveBeenCalled();
395
+ });
396
+ });
397
+ },
398
+ );
@@ -0,0 +1,280 @@
1
+ import MonitorProbeService from "../../../Server/Services/MonitorProbeService";
2
+ import MonitorService from "../../../Server/Services/MonitorService";
3
+ import MonitorProbe from "../../../Models/DatabaseModels/MonitorProbe";
4
+ import DeleteBy from "../../../Server/Types/Database/DeleteBy";
5
+ import { OnDelete } from "../../../Server/Types/Database/Hooks";
6
+ import ObjectID from "../../../Types/ObjectID";
7
+ import {
8
+ afterEach,
9
+ beforeEach,
10
+ describe,
11
+ expect,
12
+ it,
13
+ jest,
14
+ } from "@jest/globals";
15
+ import { getJestSpyOn } from "../../Spy";
16
+
17
+ /*
18
+ * https://github.com/OneUptime/oneuptime/issues/2899
19
+ *
20
+ * Monitor > Probes can now remove a probe from a monitor - previously it could
21
+ * only add one, so a probe attached by mistake was permanent.
22
+ *
23
+ * Removing one changes the same aggregate that adding one or toggling
24
+ * isEnabled changes: Monitor.isNoProbeEnabledOnThisMonitor (the "Probes Not
25
+ * Enabled" banner on the monitor page, and the owner notification behind it).
26
+ * MonitorProbeService had create and update hooks for that and no delete hook,
27
+ * so deleting the last probe left the monitor still claiming it was watched.
28
+ *
29
+ * The monitorIds have to be read *before* the delete - afterwards the rows are
30
+ * gone - which is what these tests pin.
31
+ */
32
+
33
+ const MONITOR_ID: ObjectID = new ObjectID(
34
+ "22222222-2222-4222-8222-222222222222",
35
+ );
36
+ const OTHER_MONITOR_ID: ObjectID = new ObjectID(
37
+ "66666666-6666-4666-8666-666666666666",
38
+ );
39
+
40
+ type MakeDeleteByFunction = (
41
+ query: Record<string, unknown>,
42
+ ) => DeleteBy<MonitorProbe>;
43
+
44
+ const makeDeleteBy: MakeDeleteByFunction = (
45
+ query: Record<string, unknown>,
46
+ ): DeleteBy<MonitorProbe> => {
47
+ return {
48
+ query: query as any,
49
+ limit: 10,
50
+ skip: 0,
51
+ props: { isRoot: false },
52
+ } as DeleteBy<MonitorProbe>;
53
+ };
54
+
55
+ type MakeRowFunction = (monitorId: ObjectID | undefined) => MonitorProbe;
56
+
57
+ const makeRow: MakeRowFunction = (
58
+ monitorId: ObjectID | undefined,
59
+ ): MonitorProbe => {
60
+ const monitorProbe: MonitorProbe = new MonitorProbe();
61
+
62
+ if (monitorId) {
63
+ monitorProbe.monitorId = monitorId;
64
+ }
65
+
66
+ return monitorProbe;
67
+ };
68
+
69
+ /*
70
+ * onBeforeDelete / onDeleteSuccess are protected: DatabaseService is what calls
71
+ * them. Reaching them directly is the only way to test them without a database.
72
+ */
73
+ type CallOnBeforeDeleteFunction = (
74
+ deleteBy: DeleteBy<MonitorProbe>,
75
+ ) => Promise<OnDelete<MonitorProbe>>;
76
+
77
+ const callOnBeforeDelete: CallOnBeforeDeleteFunction = (
78
+ deleteBy: DeleteBy<MonitorProbe>,
79
+ ): Promise<OnDelete<MonitorProbe>> => {
80
+ return (MonitorProbeService as any).onBeforeDelete(deleteBy);
81
+ };
82
+
83
+ type CallOnDeleteSuccessFunction = (
84
+ onDelete: OnDelete<MonitorProbe>,
85
+ ) => Promise<OnDelete<MonitorProbe>>;
86
+
87
+ const callOnDeleteSuccess: CallOnDeleteSuccessFunction = (
88
+ onDelete: OnDelete<MonitorProbe>,
89
+ ): Promise<OnDelete<MonitorProbe>> => {
90
+ return (MonitorProbeService as any).onDeleteSuccess(onDelete, []);
91
+ };
92
+
93
+ describe("MonitorProbeService delete hooks", () => {
94
+ let refreshedMonitorIds: Array<string> = [];
95
+ let findByCalls: Array<any> = [];
96
+ let rowsToReturn: Array<MonitorProbe> = [];
97
+
98
+ beforeEach(() => {
99
+ refreshedMonitorIds = [];
100
+ findByCalls = [];
101
+ rowsToReturn = [];
102
+
103
+ getJestSpyOn(MonitorProbeService, "findBy").mockImplementation(
104
+ async (findBy: any): Promise<Array<MonitorProbe>> => {
105
+ findByCalls.push(findBy);
106
+ return rowsToReturn;
107
+ },
108
+ );
109
+
110
+ getJestSpyOn(
111
+ MonitorService,
112
+ "refreshMonitorProbeStatus",
113
+ ).mockImplementation(async (monitorId: any): Promise<void> => {
114
+ refreshedMonitorIds.push(monitorId.toString());
115
+ });
116
+ });
117
+
118
+ afterEach(() => {
119
+ jest.restoreAllMocks();
120
+ });
121
+
122
+ describe("onBeforeDelete", () => {
123
+ it("carries forward the monitors whose rows are about to disappear", async () => {
124
+ rowsToReturn = [makeRow(MONITOR_ID)];
125
+
126
+ const onDelete: OnDelete<MonitorProbe> = await callOnBeforeDelete(
127
+ makeDeleteBy({ monitorId: MONITOR_ID }),
128
+ );
129
+
130
+ expect(
131
+ (onDelete.carryForward.monitorIds as Array<ObjectID>).map(
132
+ (id: ObjectID) => {
133
+ return id.toString();
134
+ },
135
+ ),
136
+ ).toEqual([MONITOR_ID.toString()]);
137
+ });
138
+
139
+ it("looks the rows up with the caller's own delete query", async () => {
140
+ const query: Record<string, unknown> = { monitorId: MONITOR_ID };
141
+
142
+ await callOnBeforeDelete(makeDeleteBy(query));
143
+
144
+ expect(findByCalls).toHaveLength(1);
145
+ expect(findByCalls[0].query).toEqual(query);
146
+ expect(findByCalls[0].select).toEqual({ monitorId: true });
147
+ });
148
+
149
+ it("reads as root, because the caller's scope has not been applied yet", async () => {
150
+ /*
151
+ * DatabaseService narrows the query for permissions *after* this hook
152
+ * runs, so the hook has to be able to see the rows it is asked about.
153
+ */
154
+ await callOnBeforeDelete(makeDeleteBy({ monitorId: MONITOR_ID }));
155
+
156
+ expect(findByCalls[0].props.isRoot).toBe(true);
157
+ });
158
+
159
+ it("passes the delete's own limit and skip so a bulk delete is covered", async () => {
160
+ const deleteBy: DeleteBy<MonitorProbe> = makeDeleteBy({
161
+ monitorId: MONITOR_ID,
162
+ });
163
+ deleteBy.limit = 250;
164
+ deleteBy.skip = 10;
165
+
166
+ await callOnBeforeDelete(deleteBy);
167
+
168
+ expect(findByCalls[0].limit).toBe(250);
169
+ expect(findByCalls[0].skip).toBe(10);
170
+ });
171
+
172
+ it("returns the deleteBy unchanged, so it does not narrow the delete", async () => {
173
+ const deleteBy: DeleteBy<MonitorProbe> = makeDeleteBy({
174
+ monitorId: MONITOR_ID,
175
+ });
176
+
177
+ const onDelete: OnDelete<MonitorProbe> =
178
+ await callOnBeforeDelete(deleteBy);
179
+
180
+ expect(onDelete.deleteBy).toBe(deleteBy);
181
+ });
182
+
183
+ it("drops rows with no monitorId rather than carrying an undefined forward", async () => {
184
+ rowsToReturn = [makeRow(undefined), makeRow(MONITOR_ID)];
185
+
186
+ const onDelete: OnDelete<MonitorProbe> = await callOnBeforeDelete(
187
+ makeDeleteBy({}),
188
+ );
189
+
190
+ expect(onDelete.carryForward.monitorIds).toHaveLength(1);
191
+ });
192
+
193
+ it("carries nothing forward when the delete matches nothing", async () => {
194
+ rowsToReturn = [];
195
+
196
+ const onDelete: OnDelete<MonitorProbe> = await callOnBeforeDelete(
197
+ makeDeleteBy({ monitorId: MONITOR_ID }),
198
+ );
199
+
200
+ expect(onDelete.carryForward.monitorIds).toEqual([]);
201
+ });
202
+ });
203
+
204
+ describe("onDeleteSuccess", () => {
205
+ it("refreshes the monitor, so the 'Probes Not Enabled' banner appears", async () => {
206
+ await callOnDeleteSuccess({
207
+ deleteBy: makeDeleteBy({ monitorId: MONITOR_ID }),
208
+ carryForward: { monitorIds: [MONITOR_ID] },
209
+ });
210
+
211
+ expect(refreshedMonitorIds).toEqual([MONITOR_ID.toString()]);
212
+ });
213
+
214
+ it("refreshes every monitor a bulk delete touched", async () => {
215
+ await callOnDeleteSuccess({
216
+ deleteBy: makeDeleteBy({}),
217
+ carryForward: { monitorIds: [MONITOR_ID, OTHER_MONITOR_ID] },
218
+ });
219
+
220
+ expect(refreshedMonitorIds).toEqual([
221
+ MONITOR_ID.toString(),
222
+ OTHER_MONITOR_ID.toString(),
223
+ ]);
224
+ });
225
+
226
+ it("refreshes a monitor once even when several of its rows went", async () => {
227
+ /*
228
+ * Removing three probes from one monitor is one aggregate to recompute,
229
+ * and refreshMonitorProbeStatus writes to the monitor and can notify its
230
+ * owners.
231
+ */
232
+ await callOnDeleteSuccess({
233
+ deleteBy: makeDeleteBy({ monitorId: MONITOR_ID }),
234
+ carryForward: { monitorIds: [MONITOR_ID, MONITOR_ID, MONITOR_ID] },
235
+ });
236
+
237
+ expect(refreshedMonitorIds).toEqual([MONITOR_ID.toString()]);
238
+ });
239
+
240
+ it("does nothing when nothing was carried forward", async () => {
241
+ await callOnDeleteSuccess({
242
+ deleteBy: makeDeleteBy({}),
243
+ carryForward: { monitorIds: [] },
244
+ });
245
+
246
+ expect(refreshedMonitorIds).toEqual([]);
247
+ });
248
+
249
+ it("survives a carryForward that never ran onBeforeDelete", async () => {
250
+ // props.ignoreHooks makes DatabaseService pass carryForward: [].
251
+ await callOnDeleteSuccess({
252
+ deleteBy: makeDeleteBy({}),
253
+ carryForward: [],
254
+ });
255
+
256
+ expect(refreshedMonitorIds).toEqual([]);
257
+ });
258
+
259
+ it("does not turn a failed status refresh into a failed delete", async () => {
260
+ /*
261
+ * The rows are already gone by the time this runs. Throwing here would
262
+ * report a 500 for a delete that actually succeeded.
263
+ */
264
+ jest.restoreAllMocks();
265
+ getJestSpyOn(
266
+ MonitorService,
267
+ "refreshMonitorProbeStatus",
268
+ ).mockImplementation(async (): Promise<void> => {
269
+ throw new Error("refresh exploded");
270
+ });
271
+
272
+ await expect(
273
+ callOnDeleteSuccess({
274
+ deleteBy: makeDeleteBy({ monitorId: MONITOR_ID }),
275
+ carryForward: { monitorIds: [MONITOR_ID] },
276
+ }),
277
+ ).resolves.toBeDefined();
278
+ });
279
+ });
280
+ });