@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,528 @@
1
+ import {
2
+ CROSS_PROJECT_REFERENCES,
3
+ CrossProjectReference,
4
+ RepairCrossProjectIncidentReferences1785320000000,
5
+ TIMELINE_FOREIGN_KEYS,
6
+ getClearQuery,
7
+ getRepairQuery,
8
+ } from "../../../Server/Infrastructure/Postgres/SchemaMigrations/1785320000000-RepairCrossProjectIncidentReferences";
9
+ import { RepairCrossProjectMonitorStatusReferences1785240000000 } from "../../../Server/Infrastructure/Postgres/SchemaMigrations/1785240000000-RepairCrossProjectMonitorStatusReferences";
10
+ import SchemaMigrations from "../../../Server/Infrastructure/Postgres/SchemaMigrations/Index";
11
+ import AlertEpisodeStateTimeline from "../../../Models/DatabaseModels/AlertEpisodeStateTimeline";
12
+ import AlertStateTimeline from "../../../Models/DatabaseModels/AlertStateTimeline";
13
+ import IncidentEpisodeStateTimeline from "../../../Models/DatabaseModels/IncidentEpisodeStateTimeline";
14
+ import IncidentStateTimeline from "../../../Models/DatabaseModels/IncidentStateTimeline";
15
+ import ScheduledMaintenanceStateTimeline from "../../../Models/DatabaseModels/ScheduledMaintenanceStateTimeline";
16
+ import { QueryRunner, getMetadataArgsStorage } from "typeorm";
17
+ import type { RelationMetadataArgs } from "typeorm/metadata-args/RelationMetadataArgs";
18
+ import { describe, expect, test } from "@jest/globals";
19
+
20
+ /*
21
+ * Deleting a project answered "This item cannot be deleted because Incident
22
+ * records still reference it": an Incident in project B held project A's
23
+ * IncidentSeverity id, the FK is ON DELETE NO ACTION, and the cascade from
24
+ * project A tripped over it (23503).
25
+ *
26
+ * These tests pin the three pieces that have to hold for that to stay fixed —
27
+ * a regression in any one silently brings the undeletable project back:
28
+ * 1. the reference list covers every ON DELETE NO ACTION column a project
29
+ * delete can trip over (checked against the pinned list below),
30
+ * 2. the migration's SQL contract: repair every reference, clear only the
31
+ * nullable leftovers, and swap exactly the five state-timeline FKs to
32
+ * ON DELETE CASCADE — with down() putting NO ACTION back,
33
+ * 3. the matching @ManyToOne(onDelete: "CASCADE") on those five entities, so
34
+ * a future schema:generate does not emit the swap back as "drift", and
35
+ * the migration's registration in SchemaMigrations/Index.ts (an
36
+ * unregistered migration is dead code and never runs on boot).
37
+ *
38
+ * Pure metadata/mocks — no Postgres connection anywhere.
39
+ */
40
+
41
+ /*
42
+ * Every (table, column) whose FK to a project-scoped state / severity / status
43
+ * was ON DELETE NO ACTION when this migration was written, minus
44
+ * Monitor.currentMonitorStatusId which stays NO ACTION on purpose and was
45
+ * already repaired by RepairCrossProjectMonitorStatusReferences1785240000000.
46
+ */
47
+ const EXPECTED_REFERENCES: Array<string> = [
48
+ "Alert.alertSeverityId",
49
+ "Alert.currentAlertStateId",
50
+ "Alert.monitorStatusWhenThisAlertWasCreatedId",
51
+ "AlertEpisode.alertSeverityId",
52
+ "AlertEpisode.currentAlertStateId",
53
+ "AlertEpisodeStateTimeline.alertStateId",
54
+ "AlertStateTimeline.alertStateId",
55
+ "Incident.changeMonitorStatusToId",
56
+ "Incident.currentIncidentStateId",
57
+ "Incident.incidentSeverityId",
58
+ "IncidentEpisode.currentIncidentStateId",
59
+ "IncidentEpisode.incidentSeverityId",
60
+ "IncidentEpisodeStateTimeline.incidentStateId",
61
+ "IncidentStateTimeline.incidentStateId",
62
+ "IncidentTemplate.changeMonitorStatusToId",
63
+ "IncidentTemplate.incidentSeverityId",
64
+ "IncidentTemplate.initialIncidentStateId",
65
+ "ScheduledMaintenance.changeMonitorStatusToId",
66
+ "ScheduledMaintenance.currentScheduledMaintenanceStateId",
67
+ "ScheduledMaintenanceStateTimeline.scheduledMaintenanceStateId",
68
+ "ScheduledMaintenanceTemplate.changeMonitorStatusToId",
69
+ ];
70
+
71
+ /*
72
+ * The columns the schema declares NOT NULL. A leftover cross-project value can
73
+ * only be cleared on the others, so getting this wrong either leaves rows that
74
+ * still block the delete or writes NULL into a not-null column mid-migration.
75
+ */
76
+ const NOT_NULL_COLUMNS: Array<string> = [
77
+ "Alert.alertSeverityId",
78
+ "Alert.currentAlertStateId",
79
+ "AlertEpisode.currentAlertStateId",
80
+ "AlertEpisodeStateTimeline.alertStateId",
81
+ "AlertStateTimeline.alertStateId",
82
+ "Incident.currentIncidentStateId",
83
+ "Incident.incidentSeverityId",
84
+ "IncidentEpisode.currentIncidentStateId",
85
+ "IncidentEpisodeStateTimeline.incidentStateId",
86
+ "IncidentStateTimeline.incidentStateId",
87
+ "ScheduledMaintenance.currentScheduledMaintenanceStateId",
88
+ "ScheduledMaintenanceStateTimeline.scheduledMaintenanceStateId",
89
+ ];
90
+
91
+ type ModelClass = { new (): unknown };
92
+
93
+ // [entity, the FK column its state relation writes]
94
+ const CASCADING_TIMELINE_RELATIONS: Array<[ModelClass, string]> = [
95
+ [IncidentStateTimeline, "incidentStateId"],
96
+ [IncidentEpisodeStateTimeline, "incidentStateId"],
97
+ [AlertStateTimeline, "alertStateId"],
98
+ [AlertEpisodeStateTimeline, "alertStateId"],
99
+ [ScheduledMaintenanceStateTimeline, "scheduledMaintenanceStateId"],
100
+ ];
101
+
102
+ function recordQueries(): {
103
+ queryRunner: QueryRunner;
104
+ queries: Array<string>;
105
+ } {
106
+ const queries: Array<string> = [];
107
+
108
+ const queryRunner: QueryRunner = {
109
+ query: async (sql: string): Promise<void> => {
110
+ queries.push(sql);
111
+ },
112
+ } as unknown as QueryRunner;
113
+
114
+ return { queryRunner, queries };
115
+ }
116
+
117
+ async function runUp(): Promise<Array<string>> {
118
+ const { queryRunner, queries } = recordQueries();
119
+ await new RepairCrossProjectIncidentReferences1785320000000().up(queryRunner);
120
+ return queries;
121
+ }
122
+
123
+ async function runDown(): Promise<Array<string>> {
124
+ const { queryRunner, queries } = recordQueries();
125
+ await new RepairCrossProjectIncidentReferences1785320000000().down(
126
+ queryRunner,
127
+ );
128
+ return queries;
129
+ }
130
+
131
+ function key(reference: { table: string; column: string }): string {
132
+ return `${reference.table}.${reference.column}`;
133
+ }
134
+
135
+ describe("RepairCrossProjectIncidentReferences migration", () => {
136
+ describe("coverage of the references a project delete trips over", () => {
137
+ test("repairs exactly the known ON DELETE NO ACTION references", async () => {
138
+ expect(CROSS_PROJECT_REFERENCES.map(key).sort()).toEqual(
139
+ EXPECTED_REFERENCES,
140
+ );
141
+ });
142
+
143
+ test("marks nullable exactly where the schema allows NULL", async () => {
144
+ const notNull: Array<string> = CROSS_PROJECT_REFERENCES.filter(
145
+ (reference: { isNullable: boolean }) => {
146
+ return !reference.isNullable;
147
+ },
148
+ )
149
+ .map(key)
150
+ .sort();
151
+
152
+ expect(notNull).toEqual(NOT_NULL_COLUMNS);
153
+ });
154
+
155
+ test("points each reference at the table that actually owns it", async () => {
156
+ for (const reference of CROSS_PROJECT_REFERENCES) {
157
+ if (reference.referencedTable === "MonitorStatus") {
158
+ expect(reference.orderColumn).toBe("priority");
159
+ } else {
160
+ expect(reference.orderColumn).toBe("order");
161
+ }
162
+
163
+ // Severities have no role flags to fall back on; states do.
164
+ if (reference.referencedTable.endsWith("Severity")) {
165
+ expect(reference.roleColumns).toEqual([]);
166
+ } else {
167
+ expect(reference.roleColumns.length).toBeGreaterThan(0);
168
+ }
169
+ }
170
+ });
171
+ });
172
+
173
+ describe("repair query", () => {
174
+ test("only touches rows whose reference belongs to another project", async () => {
175
+ for (const reference of CROSS_PROJECT_REFERENCES) {
176
+ expect(getRepairQuery(reference)).toContain(
177
+ `WHERE c."projectId" IS DISTINCT FROM p."projectId"`,
178
+ );
179
+ }
180
+ });
181
+
182
+ test("never lets a name match cross a role boundary", async () => {
183
+ /*
184
+ * A project may have a custom state literally called "Resolved" that is
185
+ * NOT its resolved state. If a bare name match can win, a resolved
186
+ * incident is silently repointed at a non-resolved state — and the
187
+ * migration is one-way. So every branch that can win before the bare
188
+ * name match must carry the role predicate.
189
+ */
190
+ for (const reference of CROSS_PROJECT_REFERENCES) {
191
+ if (reference.roleColumns.length === 0) {
192
+ continue;
193
+ }
194
+
195
+ const sql: string = getRepairQuery(reference);
196
+ const roleColumn: string = reference.roleColumns[0]!;
197
+
198
+ const nameAndRole: number = sql.indexOf(
199
+ `AND lower(x."name") = lower(b.ref_name)`,
200
+ );
201
+ const bareName: number = sql.indexOf(
202
+ `x."projectId" = b.project_id AND lower(x."name") = lower(b.ref_name)`,
203
+ );
204
+ const firstRole: number = sql.indexOf(
205
+ `x."${roleColumn}" = b.role_${roleColumn}`,
206
+ );
207
+
208
+ expect(nameAndRole).toBeGreaterThan(-1);
209
+ expect(firstRole).toBeGreaterThan(-1);
210
+ expect(bareName).toBeGreaterThan(-1);
211
+
212
+ // Both role-bearing branches are ahead of the bare name match.
213
+ expect(bareName).toBeGreaterThan(nameAndRole);
214
+ expect(bareName).toBeGreaterThan(firstRole);
215
+
216
+ // And the role predicate appears in exactly the two leading branches.
217
+ expect(
218
+ (
219
+ sql.match(
220
+ new RegExp(`x\\."${roleColumn}" = b\\.role_${roleColumn}`, "g"),
221
+ ) || []
222
+ ).length,
223
+ ).toBe(2);
224
+ }
225
+ });
226
+
227
+ test("falls back to nearest order only after every targeted match", async () => {
228
+ for (const reference of CROSS_PROJECT_REFERENCES) {
229
+ const sql: string = getRepairQuery(reference);
230
+
231
+ const byOrder: number = sql.indexOf(
232
+ `abs(x."${reference.orderColumn}" - b.ref_order)`,
233
+ );
234
+ const byName: number = sql.indexOf(
235
+ `lower(x."name") = lower(b.ref_name)`,
236
+ );
237
+
238
+ expect(byName).toBeGreaterThan(-1);
239
+ expect(byOrder).toBeGreaterThan(byName);
240
+ }
241
+ });
242
+
243
+ test("only ever repoints inside the row's own project", async () => {
244
+ for (const reference of CROSS_PROJECT_REFERENCES) {
245
+ const sql: string = getRepairQuery(reference);
246
+ const candidateFilters: number = (
247
+ sql.match(/x\."projectId" = b\.project_id/g) || []
248
+ ).length;
249
+
250
+ // One per branch of the COALESCE ladder.
251
+ expect(candidateFilters).toBe(reference.roleColumns.length > 0 ? 4 : 2);
252
+ }
253
+ });
254
+
255
+ test("leaves the row alone when nothing in its own project matches", async () => {
256
+ for (const reference of CROSS_PROJECT_REFERENCES) {
257
+ expect(getRepairQuery(reference)).toContain(
258
+ `WHERE c."_id" = r.row_id AND r.good_id IS NOT NULL`,
259
+ );
260
+ }
261
+ });
262
+
263
+ test("skips the role branch for severities, which have no role flags", async () => {
264
+ const severityReference: CrossProjectReference =
265
+ CROSS_PROJECT_REFERENCES.find(
266
+ (reference: { referencedTable: string }) => {
267
+ return reference.referencedTable === "IncidentSeverity";
268
+ },
269
+ )!;
270
+
271
+ expect(getRepairQuery(severityReference)).not.toContain("role_");
272
+ });
273
+ });
274
+
275
+ describe("clear query", () => {
276
+ test("clears only the cross-project leftovers", async () => {
277
+ const nullableReference: CrossProjectReference =
278
+ CROSS_PROJECT_REFERENCES.find((reference: { isNullable: boolean }) => {
279
+ return reference.isNullable;
280
+ })!;
281
+
282
+ const sql: string = getClearQuery(nullableReference);
283
+
284
+ expect(sql).toContain(`SET "${nullableReference.column}" = NULL`);
285
+ expect(sql).toContain(`c."projectId" IS DISTINCT FROM p."projectId"`);
286
+ });
287
+ });
288
+
289
+ describe("up()", () => {
290
+ test("raises the statement timeout before the table scans", async () => {
291
+ const queries: Array<string> = await runUp();
292
+
293
+ expect(queries[0]).toContain("SET LOCAL statement_timeout");
294
+ });
295
+
296
+ test("bounds the lock wait before swapping foreign keys", async () => {
297
+ const queries: Array<string> = await runUp();
298
+
299
+ const lockTimeoutAt: number = queries.findIndex((sql: string) => {
300
+ return sql.includes("SET LOCAL lock_timeout");
301
+ });
302
+ const firstAlterAt: number = queries.findIndex((sql: string) => {
303
+ return sql.includes("DROP CONSTRAINT");
304
+ });
305
+
306
+ expect(lockTimeoutAt).toBeGreaterThan(-1);
307
+ expect(firstAlterAt).toBeGreaterThan(lockTimeoutAt);
308
+ });
309
+
310
+ test("drops the raised statement timeout before taking any lock", async () => {
311
+ /*
312
+ * DATABASE_QUERY_TIMEOUT_MS is a client-side deadline no SET can lift.
313
+ * If the client gives up while an ADD CONSTRAINT is still running, the
314
+ * server keeps going and the queued ROLLBACK times out too — holding
315
+ * ACCESS EXCLUSIVE for as long as the raised ceiling allows, long after
316
+ * the deploy already failed. Aborting server-side is the cheaper
317
+ * failure, so the ceiling must be back to default before the DDL.
318
+ */
319
+ const queries: Array<string> = await runUp();
320
+
321
+ const resetAt: number = queries.findIndex((sql: string) => {
322
+ return sql.includes("SET LOCAL statement_timeout = DEFAULT");
323
+ });
324
+ const firstAlterAt: number = queries.findIndex((sql: string) => {
325
+ return sql.includes("DROP CONSTRAINT");
326
+ });
327
+ const lastRepairAt: number = queries.reduce(
328
+ (last: number, sql: string, index: number) => {
329
+ return sql.includes("resolved r") ? index : last;
330
+ },
331
+ -1,
332
+ );
333
+
334
+ expect(resetAt).toBeGreaterThan(lastRepairAt);
335
+ expect(firstAlterAt).toBeGreaterThan(resetAt);
336
+ });
337
+
338
+ test("repairs every reference, and clears only the nullable ones", async () => {
339
+ const queries: Array<string> = await runUp();
340
+
341
+ for (const reference of CROSS_PROJECT_REFERENCES) {
342
+ /*
343
+ * Asserted structurally rather than by comparing against
344
+ * getRepairQuery's own output, which would pass for any SQL the
345
+ * builder happened to emit.
346
+ */
347
+ const repairs: Array<string> = queries.filter((sql: string) => {
348
+ return (
349
+ sql.includes(`UPDATE "${reference.table}" c`) &&
350
+ sql.includes(`SET "${reference.column}" = r.good_id`) &&
351
+ sql.includes(`JOIN "${reference.referencedTable}" p`)
352
+ );
353
+ });
354
+
355
+ expect(repairs).toHaveLength(1);
356
+
357
+ const clears: Array<string> = queries.filter((sql: string) => {
358
+ return (
359
+ sql.includes(`UPDATE "${reference.table}" c`) &&
360
+ sql.includes(`SET "${reference.column}" = NULL`)
361
+ );
362
+ });
363
+
364
+ expect(clears).toHaveLength(reference.isNullable ? 1 : 0);
365
+ }
366
+ });
367
+
368
+ test("counts what it could not repair, for every reference", async () => {
369
+ /*
370
+ * A row survives both the repair and the clear only when its own
371
+ * project has nothing to point at. That keeps the project undeletable,
372
+ * so it must not pass silently — the user would retry the delete and
373
+ * see a byte-identical error with nothing to act on.
374
+ */
375
+ const queries: Array<string> = await runUp();
376
+
377
+ for (const reference of CROSS_PROJECT_REFERENCES) {
378
+ const counts: Array<string> = queries.filter((sql: string) => {
379
+ return (
380
+ sql.includes("count(*)::int AS remaining") &&
381
+ sql.includes(`FROM "${reference.table}" c`) &&
382
+ sql.includes(`p."_id" = c."${reference.column}"`)
383
+ );
384
+ });
385
+
386
+ expect(counts).toHaveLength(1);
387
+ }
388
+ });
389
+
390
+ test("repairs the data before the cascade can sweep it up", async () => {
391
+ /*
392
+ * Order matters: switching the timeline FKs to CASCADE first would let
393
+ * the project delete take another project's timeline history with it,
394
+ * instead of the history staying with the project that owns it.
395
+ */
396
+ const queries: Array<string> = await runUp();
397
+
398
+ const lastRepairAt: number = queries.reduce(
399
+ (last: number, sql: string, index: number) => {
400
+ return sql.includes("resolved r") ? index : last;
401
+ },
402
+ -1,
403
+ );
404
+ const firstAlterAt: number = queries.findIndex((sql: string) => {
405
+ return sql.includes("DROP CONSTRAINT");
406
+ });
407
+
408
+ expect(lastRepairAt).toBeGreaterThan(-1);
409
+ expect(firstAlterAt).toBeGreaterThan(lastRepairAt);
410
+ });
411
+
412
+ test("swaps exactly the five state-timeline foreign keys to CASCADE", async () => {
413
+ const queries: Array<string> = await runUp();
414
+
415
+ const added: Array<string> = queries.filter((sql: string) => {
416
+ return sql.includes("ADD CONSTRAINT");
417
+ });
418
+
419
+ expect(added).toHaveLength(TIMELINE_FOREIGN_KEYS.length);
420
+ expect(TIMELINE_FOREIGN_KEYS).toHaveLength(5);
421
+
422
+ for (const foreignKey of TIMELINE_FOREIGN_KEYS) {
423
+ expect(queries).toContain(
424
+ `ALTER TABLE "${foreignKey.table}" DROP CONSTRAINT "${foreignKey.constraintName}"`,
425
+ );
426
+ expect(queries).toContain(
427
+ `ALTER TABLE "${foreignKey.table}" ADD CONSTRAINT "${foreignKey.constraintName}" FOREIGN KEY ("${foreignKey.column}") REFERENCES "${foreignKey.referencedTable}"("_id") ON DELETE CASCADE ON UPDATE NO ACTION`,
428
+ );
429
+ }
430
+ });
431
+
432
+ test("touches no table outside the ones it declares", async () => {
433
+ const queries: Array<string> = await runUp();
434
+ const declaredTables: Array<string> = CROSS_PROJECT_REFERENCES.map(
435
+ (reference: { table: string }) => {
436
+ return reference.table;
437
+ },
438
+ ).concat(
439
+ CROSS_PROJECT_REFERENCES.map(
440
+ (reference: { referencedTable: string }) => {
441
+ return reference.referencedTable;
442
+ },
443
+ ),
444
+ );
445
+
446
+ for (const sql of queries) {
447
+ for (const table of sql.match(/UPDATE "([A-Za-z]+)"/g) || []) {
448
+ expect(declaredTables).toContain(table.replace(/UPDATE "|"/g, ""));
449
+ }
450
+ }
451
+ });
452
+ });
453
+
454
+ describe("down()", () => {
455
+ test("puts NO ACTION back on every foreign key up() swapped", async () => {
456
+ const queries: Array<string> = await runDown();
457
+
458
+ for (const foreignKey of TIMELINE_FOREIGN_KEYS) {
459
+ expect(queries).toContain(
460
+ `ALTER TABLE "${foreignKey.table}" DROP CONSTRAINT "${foreignKey.constraintName}"`,
461
+ );
462
+ expect(queries).toContain(
463
+ `ALTER TABLE "${foreignKey.table}" ADD CONSTRAINT "${foreignKey.constraintName}" FOREIGN KEY ("${foreignKey.column}") REFERENCES "${foreignKey.referencedTable}"("_id") ON DELETE NO ACTION ON UPDATE NO ACTION`,
464
+ );
465
+ }
466
+ });
467
+
468
+ test("does not try to undo the data repair", async () => {
469
+ const queries: Array<string> = await runDown();
470
+
471
+ expect(
472
+ queries.filter((sql: string) => {
473
+ return sql.trimStart().startsWith("UPDATE ");
474
+ }),
475
+ ).toHaveLength(0);
476
+ });
477
+ });
478
+
479
+ describe("entity metadata", () => {
480
+ test("the five timeline relations declare ON DELETE CASCADE", async () => {
481
+ /*
482
+ * Without this the next `schema:generate` sees the database disagreeing
483
+ * with the entities and emits an ALTER putting NO ACTION back.
484
+ */
485
+ const relations: Array<RelationMetadataArgs> =
486
+ getMetadataArgsStorage().relations;
487
+
488
+ for (const [model, column] of CASCADING_TIMELINE_RELATIONS) {
489
+ const relation: RelationMetadataArgs | undefined = relations.find(
490
+ (candidate: RelationMetadataArgs) => {
491
+ return (
492
+ candidate.target === model &&
493
+ candidate.propertyName === column.replace(/Id$/, "")
494
+ );
495
+ },
496
+ );
497
+
498
+ expect(relation).toBeDefined();
499
+ expect(relation?.options.onDelete).toBe("CASCADE");
500
+ }
501
+ });
502
+ });
503
+
504
+ describe("registration", () => {
505
+ test("is registered so it runs on boot", async () => {
506
+ expect(SchemaMigrations).toContain(
507
+ RepairCrossProjectIncidentReferences1785320000000,
508
+ );
509
+ });
510
+
511
+ test("runs after the migration it builds on", async () => {
512
+ /*
513
+ * It must land after the monitor-status repair, whose cross-project
514
+ * cleanup it assumes. Pinning it to the last slot instead would turn
515
+ * red the moment anyone appends an unrelated migration.
516
+ */
517
+ expect(
518
+ SchemaMigrations.indexOf(
519
+ RepairCrossProjectIncidentReferences1785320000000,
520
+ ),
521
+ ).toBeGreaterThan(
522
+ SchemaMigrations.indexOf(
523
+ RepairCrossProjectMonitorStatusReferences1785240000000,
524
+ ),
525
+ );
526
+ });
527
+ });
528
+ });