@oneuptime/common 12.0.4 → 12.0.5

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 (374) hide show
  1. package/Models/DatabaseModels/AIRun.ts +38 -1
  2. package/Models/DatabaseModels/AlertFeed.ts +30 -0
  3. package/Models/DatabaseModels/Dashboard.ts +28 -0
  4. package/Models/DatabaseModels/Incident.ts +2 -0
  5. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  6. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  7. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  8. package/Models/DatabaseModels/IncidentFeed.ts +30 -0
  9. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  10. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  11. package/Models/DatabaseModels/LogSavedView.ts +33 -0
  12. package/Models/DatabaseModels/Project.ts +231 -9
  13. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  14. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  15. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  16. package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +4 -4
  17. package/Models/DatabaseModels/StatusPage.ts +28 -0
  18. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  19. package/Server/API/AIAgentDataAPI.ts +44 -55
  20. package/Server/API/AIInvestigationAPI.ts +175 -17
  21. package/Server/API/DashboardAPI.ts +10 -10
  22. package/Server/API/StatusPageAPI.ts +38 -19
  23. package/Server/EnvironmentConfig.ts +16 -0
  24. package/Server/Infrastructure/ClickhouseConfig.ts +15 -1
  25. package/Server/Infrastructure/ClickhouseDatabase.ts +1 -1
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.ts +27 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.ts +89 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.ts +27 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.ts +40 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.ts +26 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  32. package/Server/Services/AIRunService.ts +78 -10
  33. package/Server/Services/AIService.ts +94 -22
  34. package/Server/Services/AlertFeedService.ts +5 -0
  35. package/Server/Services/AnalyticsDatabaseService.ts +29 -0
  36. package/Server/Services/DatabaseService.ts +43 -2
  37. package/Server/Services/IncidentFeedService.ts +5 -0
  38. package/Server/Services/LlmLogService.ts +46 -2
  39. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +6 -0
  40. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +4 -0
  41. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +8 -5
  42. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +90 -16
  43. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +2 -0
  44. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +2 -0
  45. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +223 -22
  46. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +25 -24
  47. package/Server/Utils/AI/SRE/ConfidenceSignal.ts +182 -71
  48. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +252 -43
  49. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +25 -24
  50. package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +47 -13
  51. package/Server/Utils/AI/SRE/InvestigationGrader.ts +9 -5
  52. package/Server/Utils/AI/SRE/InvestigationQueue.ts +141 -24
  53. package/Server/Utils/AI/SRE/InvestigationSubjectLock.ts +66 -0
  54. package/Server/Utils/AI/SRE/PostedRootCause.ts +94 -3
  55. package/Server/Utils/AI/SRE/README.md +1 -1
  56. package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +132 -10
  57. package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +24 -0
  58. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +29 -0
  59. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +56 -0
  60. package/Server/Utils/Monitor/MonitorMetricUtil.ts +46 -0
  61. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
  62. package/Server/Utils/PasswordHash.ts +28 -4
  63. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +251 -0
  64. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +747 -0
  65. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +480 -0
  66. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1184 -0
  67. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +500 -0
  68. package/Tests/App/Dashboard/PortMonitorCriteriaFilter.test.ts +93 -0
  69. package/Tests/App/StatusPage/PublicStatusPageAPIErrorHandling.test.ts +117 -0
  70. package/Tests/App/StatusPage/StatusPageModelAPIPolymorphism.test.ts +223 -0
  71. package/Tests/Models/DatabaseModels/PermissionCatalogueCoverage.test.ts +243 -0
  72. package/Tests/Server/API/AIAgentDataFixFromIncidentContext.test.ts +266 -0
  73. package/Tests/Server/API/AIInvestigationAPI.test.ts +594 -0
  74. package/Tests/Server/API/AIInvestigationCreateFixTask.test.ts +80 -0
  75. package/Tests/Server/API/DashboardMasterPasswordAPI.test.ts +172 -1
  76. package/Tests/Server/API/StatusPageMasterPasswordAPI.test.ts +335 -0
  77. package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +59 -5
  78. package/Tests/Server/Services/AIRunHumanVerdict.test.ts +127 -58
  79. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +396 -20
  80. package/Tests/Server/Services/AddMasterPasswordSaltMigration.test.ts +283 -0
  81. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +25 -1
  82. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +45 -35
  83. package/Tests/Server/Services/DatabaseServiceUpdateColumnsWithoutHooks.test.ts +54 -0
  84. package/Tests/Server/Services/FeedAIRunAssociation.test.ts +125 -0
  85. package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +418 -57
  86. package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +173 -14
  87. package/Tests/Server/Services/MasterPasswordScrypt.test.ts +567 -0
  88. package/Tests/Server/Services/SeparateIncidentAlertAiSettingsMigration.test.ts +194 -0
  89. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +37 -4
  90. package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +330 -29
  91. package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +25 -0
  92. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +293 -5
  93. package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +59 -1
  94. package/Tests/Server/Utils/AI/FixFromIncidentAutoTrigger.test.ts +342 -19
  95. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +214 -30
  96. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +2 -0
  97. package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +65 -17
  98. package/Tests/Server/Utils/AI/InvestigationQueueRemediationExecution.test.ts +3 -0
  99. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +313 -20
  100. package/Tests/Server/Utils/AI/PostedRootCause.test.ts +254 -0
  101. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +4 -0
  102. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +2 -0
  103. package/Tests/Server/Utils/AI/SubjectCodeFixRunDedupe.test.ts +44 -0
  104. package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +30 -0
  105. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +212 -0
  106. package/Tests/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.test.ts +401 -0
  107. package/Tests/Server/Utils/Monitor/MonitorMetricUtilPortTimings.test.ts +243 -0
  108. package/Tests/Server/Utils/PasswordHash.test.ts +30 -0
  109. package/Tests/Types/Dashboard/DashboardTemplates.test.ts +111 -0
  110. package/Tests/Types/Monitor/CephMetricCatalog.test.ts +104 -0
  111. package/Tests/Types/Monitor/CriteriaFilter.test.ts +4 -0
  112. package/Tests/Types/Monitor/DockerMetricCatalog.test.ts +109 -0
  113. package/Tests/Types/Monitor/DockerSwarmMetricCatalog.test.ts +118 -0
  114. package/Tests/Types/Monitor/HostMetricCatalog.test.ts +104 -0
  115. package/Tests/Types/Monitor/IotMetricCatalog.test.ts +104 -0
  116. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +118 -0
  117. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +42 -0
  118. package/Tests/Types/Monitor/MonitorStep.test.ts +38 -0
  119. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +75 -0
  120. package/Tests/Types/Monitor/PodmanMetricCatalog.test.ts +109 -0
  121. package/Tests/Types/Monitor/ProxmoxMetricCatalog.test.ts +107 -0
  122. package/Tests/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.test.ts +151 -0
  123. package/Tests/Types/Permission.test.ts +137 -0
  124. package/Tests/Types/Rum/SessionReplayMaskingMode.test.ts +101 -0
  125. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +5 -5
  126. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +3 -5
  127. package/Tests/UI/Components/ErrorBoundary.test.tsx +158 -0
  128. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +74 -0
  129. package/Tests/UI/Components/MoreMenu.test.tsx +756 -0
  130. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +62 -0
  131. package/Tests/UI/Monitor/PortMonitorView.test.tsx +237 -0
  132. package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +91 -0
  133. package/Tests/UI/Utils/DownloadFile.test.ts +103 -0
  134. package/Tests/UI/Utils/ErrorSupportBundle.test.ts +582 -0
  135. package/Tests/UI/Utils/Project.test.ts +31 -0
  136. package/Tests/UI/Utils/StatusPageModelAPIInjection.test.ts +245 -0
  137. package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +820 -0
  138. package/Tests/Utils/Dashboard/DashboardViewConfig.test.ts +329 -0
  139. package/Tests/Utils/Dashboard/GridLayout.test.ts +951 -0
  140. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +117 -0
  141. package/Tests/Utils/RecordingRuleExpression.test.ts +327 -0
  142. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +186 -0
  143. package/Tests/Utils/StatusPage/GroupTree.test.ts +456 -0
  144. package/Tests/Utils/StatusPage/OverviewGroupHierarchyVisibility.test.ts +588 -0
  145. package/Tests/Utils/Telemetry/SavedViewTimeRange.test.ts +244 -0
  146. package/Tests/Utils/Telemetry/TelemetryQueryTimeRange.test.ts +825 -0
  147. package/Types/AI/AIRunCodeFixRecommendation.ts +17 -0
  148. package/Types/AI/CodeFixTaskContext.ts +63 -3
  149. package/Types/AI/CodeFixTaskType.ts +3 -3
  150. package/Types/HashedString.ts +4 -3
  151. package/Types/Monitor/CriteriaFilter.ts +4 -0
  152. package/Types/Monitor/DomainMonitor/DomainLookupMethod.ts +23 -0
  153. package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +7 -0
  154. package/Types/Monitor/MonitorCriteriaInstance.ts +24 -7
  155. package/Types/Monitor/MonitorMetricType.ts +8 -0
  156. package/Types/Monitor/MonitorStep.ts +10 -1
  157. package/Types/Monitor/MonitorStepDomainMonitor.ts +21 -0
  158. package/Types/Monitor/PortMonitor/PortMonitorTimings.ts +10 -0
  159. package/Types/Permission.ts +23 -175
  160. package/Types/Probe/ProbeMonitorResponse.ts +6 -0
  161. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +2 -3
  162. package/UI/Components/ErrorBoundary.tsx +138 -11
  163. package/UI/Components/Feed/FeedItem.tsx +9 -2
  164. package/UI/Components/ModelDetail/CardModelDetail.tsx +0 -12
  165. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  166. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +12 -2
  167. package/UI/Components/MoreMenu/MoreMenu.tsx +285 -97
  168. package/UI/Components/MoreMenu/MoreMenuItem.tsx +8 -5
  169. package/UI/Utils/DownloadFile.ts +16 -8
  170. package/UI/Utils/ErrorSupportBundle.ts +805 -0
  171. package/UI/Utils/ModelAPI/ModelAPI.ts +19 -8
  172. package/UI/Utils/Project.ts +4 -0
  173. package/UI/Utils/StatusPage.ts +8 -2
  174. package/UI/Utils/UseDashboardGridDnd.ts +917 -0
  175. package/Utils/Dashboard/DashboardViewConfig.ts +80 -36
  176. package/Utils/Dashboard/GridLayout.ts +523 -0
  177. package/Utils/Metrics/RecordingRuleExpression.ts +19 -17
  178. package/Utils/Monitor/MonitorMetricType.ts +44 -2
  179. package/Utils/StatusPage/GroupNestingLayout.ts +69 -0
  180. package/Utils/StatusPage/GroupTree.ts +157 -66
  181. package/Utils/StatusPage/ResourceUptime.ts +37 -2
  182. package/Utils/Telemetry/SavedViewTimeRange.ts +114 -0
  183. package/Utils/Telemetry/TelemetryQueryTimeRange.ts +334 -0
  184. package/build/dist/Models/DatabaseModels/AIRun.js +39 -1
  185. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/AlertFeed.js +32 -0
  187. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/Dashboard.js +29 -0
  189. package/build/dist/Models/DatabaseModels/Dashboard.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  191. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  193. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  195. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.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/IncidentFeed.js +32 -0
  199. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  201. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  203. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/LogSavedView.js +33 -0
  205. package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/Project.js +241 -11
  207. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  209. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  211. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  212. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  213. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  214. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +4 -4
  215. package/build/dist/Models/DatabaseModels/StatusPage.js +29 -0
  216. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  218. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  219. package/build/dist/Server/API/AIAgentDataAPI.js +28 -46
  220. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  221. package/build/dist/Server/API/AIInvestigationAPI.js +111 -11
  222. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  223. package/build/dist/Server/API/DashboardAPI.js +8 -5
  224. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  225. package/build/dist/Server/API/StatusPageAPI.js +29 -11
  226. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  227. package/build/dist/Server/EnvironmentConfig.js +14 -0
  228. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  229. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +12 -1
  230. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  231. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +1 -1
  232. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
  233. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js +22 -0
  234. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js.map +1 -0
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js +36 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js.map +1 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js +18 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js.map +1 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js +19 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js.map +1 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js +19 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js.map +1 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  245. package/build/dist/Server/Services/AIRunService.js +58 -12
  246. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  247. package/build/dist/Server/Services/AIService.js +74 -21
  248. package/build/dist/Server/Services/AIService.js.map +1 -1
  249. package/build/dist/Server/Services/AlertFeedService.js +3 -0
  250. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  251. package/build/dist/Server/Services/AnalyticsDatabaseService.js +29 -1
  252. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  253. package/build/dist/Server/Services/DatabaseService.js +21 -2
  254. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  255. package/build/dist/Server/Services/IncidentFeedService.js +3 -0
  256. package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
  257. package/build/dist/Server/Services/LlmLogService.js +22 -1
  258. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  259. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  260. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  261. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +4 -0
  262. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
  263. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +8 -5
  264. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  265. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +63 -24
  266. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  267. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +2 -0
  268. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  269. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +2 -0
  270. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  271. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +156 -28
  272. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  273. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +21 -19
  274. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  275. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +128 -49
  276. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -1
  277. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +170 -31
  278. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -1
  279. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +21 -19
  280. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  281. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +33 -9
  282. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -1
  283. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +9 -5
  284. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -1
  285. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +121 -41
  286. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  287. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js +46 -0
  288. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js.map +1 -0
  289. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js +61 -14
  290. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js.map +1 -1
  291. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +79 -1
  292. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
  293. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +21 -0
  294. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
  295. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +20 -3
  296. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  297. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +43 -0
  298. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
  299. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  300. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  301. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
  302. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  303. package/build/dist/Server/Utils/PasswordHash.js +25 -4
  304. package/build/dist/Server/Utils/PasswordHash.js.map +1 -1
  305. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js +18 -0
  306. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js.map +1 -0
  307. package/build/dist/Types/AI/CodeFixTaskContext.js +23 -3
  308. package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
  309. package/build/dist/Types/AI/CodeFixTaskType.js +3 -3
  310. package/build/dist/Types/HashedString.js +4 -3
  311. package/build/dist/Types/HashedString.js.map +1 -1
  312. package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
  313. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  314. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js +24 -0
  315. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js.map +1 -0
  316. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +24 -7
  317. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  318. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  319. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  320. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  321. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  322. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +15 -0
  323. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
  324. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js +2 -0
  325. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js.map +1 -0
  326. package/build/dist/Types/Permission.js +23 -155
  327. package/build/dist/Types/Permission.js.map +1 -1
  328. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +2 -5
  329. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  330. package/build/dist/UI/Components/ErrorBoundary.js +67 -8
  331. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  332. package/build/dist/UI/Components/Feed/FeedItem.js +2 -2
  333. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  334. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +0 -12
  335. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  336. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  337. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  338. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +12 -2
  339. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  340. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +193 -65
  341. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  342. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +1 -1
  343. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  344. package/build/dist/UI/Utils/DownloadFile.js +15 -8
  345. package/build/dist/UI/Utils/DownloadFile.js.map +1 -1
  346. package/build/dist/UI/Utils/ErrorSupportBundle.js +476 -0
  347. package/build/dist/UI/Utils/ErrorSupportBundle.js.map +1 -0
  348. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -8
  349. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  350. package/build/dist/UI/Utils/Project.js +3 -0
  351. package/build/dist/UI/Utils/Project.js.map +1 -1
  352. package/build/dist/UI/Utils/StatusPage.js +4 -4
  353. package/build/dist/UI/Utils/StatusPage.js.map +1 -1
  354. package/build/dist/UI/Utils/UseDashboardGridDnd.js +551 -0
  355. package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -0
  356. package/build/dist/Utils/Dashboard/DashboardViewConfig.js +42 -26
  357. package/build/dist/Utils/Dashboard/DashboardViewConfig.js.map +1 -1
  358. package/build/dist/Utils/Dashboard/GridLayout.js +338 -0
  359. package/build/dist/Utils/Dashboard/GridLayout.js.map +1 -0
  360. package/build/dist/Utils/Metrics/RecordingRuleExpression.js +19 -17
  361. package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -1
  362. package/build/dist/Utils/Monitor/MonitorMetricType.js +38 -6
  363. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  364. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +46 -0
  365. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -1
  366. package/build/dist/Utils/StatusPage/GroupTree.js +79 -34
  367. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -1
  368. package/build/dist/Utils/StatusPage/ResourceUptime.js +22 -1
  369. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  370. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js +79 -0
  371. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js.map +1 -0
  372. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js +236 -0
  373. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js.map +1 -0
  374. package/package.json +1 -1
@@ -0,0 +1,588 @@
1
+ import StatusPageGroupNestingLayoutUtil, {
2
+ StatusPageGroupRollupKind,
3
+ } from "../../../Utils/StatusPage/GroupNestingLayout";
4
+ import StatusPageGroupTreeUtil, {
5
+ StatusPageGroupTreeIndex,
6
+ StatusPageGroupTreeNode,
7
+ } from "../../../Utils/StatusPage/GroupTree";
8
+ import StatusPageResourceUptimeUtil from "../../../Utils/StatusPage/ResourceUptime";
9
+ import { Green } from "../../../Types/BrandColors";
10
+ import ObjectID from "../../../Types/ObjectID";
11
+ import UptimePrecision from "../../../Types/StatusPage/UptimePrecision";
12
+ import MonitorStatus from "../../../Models/DatabaseModels/MonitorStatus";
13
+ import MonitorStatusTimeline from "../../../Models/DatabaseModels/MonitorStatusTimeline";
14
+ import Monitor from "../../../Models/DatabaseModels/Monitor";
15
+ import StatusPageGroup from "../../../Models/DatabaseModels/StatusPageGroup";
16
+ import StatusPageResource from "../../../Models/DatabaseModels/StatusPageResource";
17
+ import { describe, expect, test } from "@jest/globals";
18
+
19
+ /*
20
+ * Regression suite for the reported failure: an operator built a complete
21
+ * status page hierarchy - Corporate Unit -> Region -> Market -> Site, over
22
+ * fifteen hundred groups, every one of them with its parent set and every one
23
+ * of them visible in the dashboard's Groups list - and the public overview
24
+ * page rendered nothing. It stayed empty until the first monitor was attached
25
+ * to one of the groups.
26
+ *
27
+ * The page was gating its entire resources-and-groups block on there being at
28
+ * least one status page resource, so with no monitors yet there was nothing to
29
+ * pass the gate and the hierarchy never got drawn. The "all clear" empty state
30
+ * underneath it was reading the same count, so the visitor was told the page
31
+ * had nothing on it.
32
+ *
33
+ * These tests drive the decisions the page makes rather than the page itself -
34
+ * the page component lives in the status page frontend, which has no DOM test
35
+ * environment, so the decisions were moved into StatusPageGroupNestingLayoutUtil
36
+ * where they can be pinned down. Each one is exercised at the size the bug was
37
+ * filed at, because "renders three groups" is not the claim that failed.
38
+ */
39
+
40
+ const CORPORATE_UNITS: number = 6;
41
+ const REGIONS_PER_UNIT: number = 5;
42
+ const MARKETS_PER_REGION: number = 5;
43
+ const SITES_PER_MARKET: number = 10;
44
+
45
+ interface Hierarchy {
46
+ groups: Array<StatusPageGroup>;
47
+ units: Array<StatusPageGroup>;
48
+ regions: Array<StatusPageGroup>;
49
+ markets: Array<StatusPageGroup>;
50
+ sites: Array<StatusPageGroup>;
51
+ }
52
+
53
+ function makeGroup(data: {
54
+ id: string;
55
+ name: string;
56
+ parentId?: string | undefined;
57
+ order: number;
58
+ }): StatusPageGroup {
59
+ const group: StatusPageGroup = new StatusPageGroup();
60
+ group._id = new ObjectID(data.id).toString();
61
+ group.name = data.name;
62
+ group.order = data.order;
63
+ group.showCurrentStatus = true;
64
+ group.showUptimePercent = true;
65
+ group.uptimePercentPrecision = UptimePrecision.ONE_DECIMAL;
66
+
67
+ if (data.parentId) {
68
+ group.parentStatusPageGroupId = new ObjectID(data.parentId);
69
+ }
70
+
71
+ return group;
72
+ }
73
+
74
+ /*
75
+ * The shape from the report: four levels, every group parented, nothing
76
+ * orphaned. Built once per test so a test that mutates a group cannot leak
77
+ * into the next one.
78
+ */
79
+ function makeHierarchy(): Hierarchy {
80
+ const groups: Array<StatusPageGroup> = [];
81
+ const units: Array<StatusPageGroup> = [];
82
+ const regions: Array<StatusPageGroup> = [];
83
+ const markets: Array<StatusPageGroup> = [];
84
+ const sites: Array<StatusPageGroup> = [];
85
+
86
+ let order: number = 0;
87
+
88
+ for (let u: number = 0; u < CORPORATE_UNITS; u++) {
89
+ const unitId: string = `unit-${u}`;
90
+ const unit: StatusPageGroup = makeGroup({
91
+ id: unitId,
92
+ name: `Corporate Unit ${u}`,
93
+ order: order++,
94
+ });
95
+ units.push(unit);
96
+ groups.push(unit);
97
+
98
+ for (let r: number = 0; r < REGIONS_PER_UNIT; r++) {
99
+ const regionId: string = `${unitId}-region-${r}`;
100
+ const region: StatusPageGroup = makeGroup({
101
+ id: regionId,
102
+ name: `Region ${u}-${r}`,
103
+ parentId: unitId,
104
+ order: order++,
105
+ });
106
+ regions.push(region);
107
+ groups.push(region);
108
+
109
+ for (let m: number = 0; m < MARKETS_PER_REGION; m++) {
110
+ const marketId: string = `${regionId}-market-${m}`;
111
+ const market: StatusPageGroup = makeGroup({
112
+ id: marketId,
113
+ name: `Market ${u}-${r}-${m}`,
114
+ parentId: regionId,
115
+ order: order++,
116
+ });
117
+ markets.push(market);
118
+ groups.push(market);
119
+
120
+ for (let s: number = 0; s < SITES_PER_MARKET; s++) {
121
+ const site: StatusPageGroup = makeGroup({
122
+ id: `${marketId}-site-${s}`,
123
+ name: `Site ${u}-${r}-${m}-${s}`,
124
+ parentId: marketId,
125
+ order: order++,
126
+ });
127
+ sites.push(site);
128
+ groups.push(site);
129
+ }
130
+ }
131
+ }
132
+ }
133
+
134
+ return { groups, units, regions, markets, sites };
135
+ }
136
+
137
+ function operationalStatus(): MonitorStatus {
138
+ const status: MonitorStatus = new MonitorStatus();
139
+ status._id = new ObjectID("status-operational").toString();
140
+ status.name = "Operational";
141
+ status.priority = 1;
142
+ status.color = Green;
143
+ return status;
144
+ }
145
+
146
+ /* A monitor attached to a group - what the reporter had to add before anything appeared. */
147
+ function attachMonitor(data: {
148
+ group: StatusPageGroup;
149
+ monitorId: string;
150
+ monitorStatusId: string;
151
+ }): StatusPageResource {
152
+ const monitor: Monitor = new Monitor();
153
+ monitor._id = new ObjectID(data.monitorId).toString();
154
+ monitor.currentMonitorStatusId = new ObjectID(data.monitorStatusId);
155
+
156
+ const resource: StatusPageResource = new StatusPageResource();
157
+ resource._id = new ObjectID(`resource-${data.monitorId}`).toString();
158
+ resource.monitorId = new ObjectID(data.monitorId);
159
+ resource.monitor = monitor;
160
+ resource.statusPageGroupId = new ObjectID(data.group._id!);
161
+ resource.displayName = `Monitor for ${data.group.name}`;
162
+ resource.showUptimePercent = true;
163
+ resource.showCurrentStatus = true;
164
+ resource.uptimePercentPrecision = UptimePrecision.ONE_DECIMAL;
165
+
166
+ return resource;
167
+ }
168
+
169
+ function flatten(
170
+ nodes: Array<StatusPageGroupTreeNode>,
171
+ ): Array<StatusPageGroupTreeNode> {
172
+ return nodes.flatMap((node: StatusPageGroupTreeNode) => {
173
+ return [node, ...flatten(node.children)];
174
+ });
175
+ }
176
+
177
+ /* What the overview page decides, given a payload. */
178
+ function overviewDecisions(data: {
179
+ statusPageResources: Array<StatusPageResource>;
180
+ resourceGroups: Array<StatusPageGroup>;
181
+ }): { rendersHierarchy: boolean; rendersEmptyState: boolean } {
182
+ return {
183
+ rendersHierarchy:
184
+ StatusPageGroupNestingLayoutUtil.shouldRenderResourcesSection({
185
+ statusPageResourceCount: data.statusPageResources.length,
186
+ statusPageGroupCount: data.resourceGroups.length,
187
+ }),
188
+ rendersEmptyState:
189
+ StatusPageGroupNestingLayoutUtil.shouldRenderOverviewEmptyState({
190
+ statusPageResourceCount: data.statusPageResources.length,
191
+ statusPageGroupCount: data.resourceGroups.length,
192
+ activeIncidentCount: 0,
193
+ activeEpisodeCount: 0,
194
+ activeScheduledMaintenanceCount: 0,
195
+ activeAnnouncementCount: 0,
196
+ }),
197
+ };
198
+ }
199
+
200
+ describe("status page overview, group hierarchy with no monitors yet", () => {
201
+ test("the fixture is the hierarchy from the report", () => {
202
+ const hierarchy: Hierarchy = makeHierarchy();
203
+
204
+ expect(hierarchy.groups.length).toBeGreaterThan(1500);
205
+ expect(hierarchy.units).toHaveLength(CORPORATE_UNITS);
206
+ expect(hierarchy.sites).toHaveLength(
207
+ CORPORATE_UNITS *
208
+ REGIONS_PER_UNIT *
209
+ MARKETS_PER_REGION *
210
+ SITES_PER_MARKET,
211
+ );
212
+
213
+ // every group below the top has its parent set, which is what the report said.
214
+ for (const group of hierarchy.groups) {
215
+ const isUnit: boolean = hierarchy.units.includes(group);
216
+ expect(Boolean(group.parentStatusPageGroupId)).toBe(!isUnit);
217
+ }
218
+ });
219
+
220
+ /* The bug, stated as directly as it can be. */
221
+ test("the hierarchy renders with no status page resources at all", () => {
222
+ const hierarchy: Hierarchy = makeHierarchy();
223
+
224
+ expect(
225
+ overviewDecisions({
226
+ statusPageResources: [],
227
+ resourceGroups: hierarchy.groups,
228
+ }),
229
+ ).toEqual({ rendersHierarchy: true, rendersEmptyState: false });
230
+ });
231
+
232
+ test("every created group reaches the rendered tree", () => {
233
+ const hierarchy: Hierarchy = makeHierarchy();
234
+
235
+ const nodes: Array<StatusPageGroupTreeNode> = flatten(
236
+ StatusPageGroupTreeUtil.buildTree({
237
+ statusPageGroups: hierarchy.groups,
238
+ }),
239
+ );
240
+
241
+ expect(nodes).toHaveLength(hierarchy.groups.length);
242
+
243
+ const renderedIds: Set<string> = new Set<string>(
244
+ nodes.map((node: StatusPageGroupTreeNode) => {
245
+ return node.group._id!;
246
+ }),
247
+ );
248
+
249
+ for (const group of hierarchy.groups) {
250
+ expect(renderedIds.has(group._id!)).toBe(true);
251
+ }
252
+ });
253
+
254
+ test("the tree keeps the four levels the operator built", () => {
255
+ const hierarchy: Hierarchy = makeHierarchy();
256
+
257
+ const depthById: Map<string, number> = new Map<string, number>();
258
+
259
+ for (const node of flatten(
260
+ StatusPageGroupTreeUtil.buildTree({ statusPageGroups: hierarchy.groups }),
261
+ )) {
262
+ depthById.set(node.group._id!, node.depth);
263
+ }
264
+
265
+ const depthsOf: (groups: Array<StatusPageGroup>) => Set<number> = (
266
+ groups: Array<StatusPageGroup>,
267
+ ): Set<number> => {
268
+ return new Set<number>(
269
+ groups.map((group: StatusPageGroup) => {
270
+ return depthById.get(group._id!)!;
271
+ }),
272
+ );
273
+ };
274
+
275
+ expect(depthsOf(hierarchy.units)).toEqual(new Set([0]));
276
+ expect(depthsOf(hierarchy.regions)).toEqual(new Set([1]));
277
+ expect(depthsOf(hierarchy.markets)).toEqual(new Set([2]));
278
+ expect(depthsOf(hierarchy.sites)).toEqual(new Set([3]));
279
+ });
280
+
281
+ /*
282
+ * A group draws something at every level: the levels that hold other groups
283
+ * draw their sub groups, and the leaves draw their (empty) resource list,
284
+ * which is where the "no resources in this group" message belongs. What must
285
+ * not happen is a level that draws nothing at all.
286
+ */
287
+ test("every level of the tree draws something", () => {
288
+ const hierarchy: Hierarchy = makeHierarchy();
289
+
290
+ for (const node of flatten(
291
+ StatusPageGroupTreeUtil.buildTree({ statusPageGroups: hierarchy.groups }),
292
+ )) {
293
+ const rendersOwnResources: boolean =
294
+ StatusPageGroupNestingLayoutUtil.shouldRenderOwnResources({
295
+ ownResourceCount: 0,
296
+ subGroupCount: node.children.length,
297
+ });
298
+
299
+ expect(rendersOwnResources || node.children.length > 0).toBe(true);
300
+ }
301
+ });
302
+
303
+ /*
304
+ * A group with nothing under it must not claim a number it cannot compute.
305
+ * The uptime rollup is what the group header shows, and 0% on an empty group
306
+ * would read as an outage.
307
+ */
308
+ /*
309
+ * The page publishes availability. A hierarchy with no monitors attached to
310
+ * it yet knows nothing about availability, and every group claiming to be
311
+ * Operational would be fifteen hundred false statements.
312
+ */
313
+ test("no group claims to be operational while the page has no monitors", () => {
314
+ const hierarchy: Hierarchy = makeHierarchy();
315
+ const index: StatusPageGroupTreeIndex = StatusPageGroupTreeUtil.buildIndex({
316
+ statusPageGroups: hierarchy.groups,
317
+ });
318
+
319
+ for (const group of hierarchy.groups) {
320
+ const resourcesInSubtree: Array<StatusPageResource> =
321
+ StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants(
322
+ {
323
+ statusPageGroup: group,
324
+ statusPageResources: [],
325
+ allStatusPageGroups: hierarchy.groups,
326
+ statusPageGroupTreeIndex: index,
327
+ },
328
+ );
329
+
330
+ expect(
331
+ StatusPageGroupNestingLayoutUtil.getRollupKind({
332
+ showUptimePercent: Boolean(group.showUptimePercent),
333
+ showCurrentStatus: Boolean(group.showCurrentStatus),
334
+ isCurrentlyDown: false,
335
+ uptimePercent: null,
336
+ resourceCountInSubtree: resourcesInSubtree.length,
337
+ }),
338
+ ).toBe(StatusPageGroupRollupKind.None);
339
+ }
340
+ });
341
+
342
+ test("an empty group reports no uptime percent rather than zero", () => {
343
+ const hierarchy: Hierarchy = makeHierarchy();
344
+ const index: StatusPageGroupTreeIndex = StatusPageGroupTreeUtil.buildIndex({
345
+ statusPageGroups: hierarchy.groups,
346
+ });
347
+
348
+ for (const group of [
349
+ hierarchy.units[0]!,
350
+ hierarchy.regions[0]!,
351
+ hierarchy.sites[0]!,
352
+ ]) {
353
+ expect(
354
+ StatusPageResourceUptimeUtil.calculateAvgUptimePercentOfStatusPageGroup(
355
+ {
356
+ statusPageGroup: group,
357
+ monitorStatusTimelines: [],
358
+ precision: UptimePrecision.ONE_DECIMAL,
359
+ downtimeMonitorStatuses: [],
360
+ statusPageResources: [],
361
+ monitorsInGroup: {},
362
+ allStatusPageGroups: hierarchy.groups,
363
+ statusPageGroupTreeIndex: index,
364
+ },
365
+ ),
366
+ ).toBeNull();
367
+ }
368
+ });
369
+ });
370
+
371
+ describe("status page overview, once the first monitor is added", () => {
372
+ /*
373
+ * The reporter's workaround. Adding one monitor used to be what made the
374
+ * whole page appear; it must now change nothing about whether the hierarchy
375
+ * is drawn, only what the groups above that monitor report.
376
+ */
377
+ test("the hierarchy still renders, and still holds every group", () => {
378
+ const hierarchy: Hierarchy = makeHierarchy();
379
+ const deepestSite: StatusPageGroup = hierarchy.sites[0]!;
380
+
381
+ const resources: Array<StatusPageResource> = [
382
+ attachMonitor({
383
+ group: deepestSite,
384
+ monitorId: "monitor-1",
385
+ monitorStatusId: "status-operational",
386
+ }),
387
+ ];
388
+
389
+ expect(
390
+ overviewDecisions({
391
+ statusPageResources: resources,
392
+ resourceGroups: hierarchy.groups,
393
+ }),
394
+ ).toEqual({ rendersHierarchy: true, rendersEmptyState: false });
395
+
396
+ expect(
397
+ flatten(
398
+ StatusPageGroupTreeUtil.buildTree({
399
+ statusPageGroups: hierarchy.groups,
400
+ }),
401
+ ),
402
+ ).toHaveLength(hierarchy.groups.length);
403
+ });
404
+
405
+ /*
406
+ * The point of nesting: a monitor on a site rolls all the way up to the
407
+ * corporate unit that contains it, and does not leak into a sibling branch.
408
+ */
409
+ test("one monitor rolls up through its own branch only", () => {
410
+ const hierarchy: Hierarchy = makeHierarchy();
411
+ const site: StatusPageGroup = hierarchy.sites[0]!;
412
+
413
+ const resource: StatusPageResource = attachMonitor({
414
+ group: site,
415
+ monitorId: "monitor-1",
416
+ monitorStatusId: "status-operational",
417
+ });
418
+
419
+ const timeline: MonitorStatusTimeline = new MonitorStatusTimeline();
420
+ timeline.monitorId = new ObjectID("monitor-1");
421
+ timeline.monitorStatusId = new ObjectID("status-operational");
422
+ timeline.startsAt = new Date(Date.UTC(2024, 0, 1));
423
+ timeline.endsAt = new Date(Date.UTC(2024, 0, 8));
424
+
425
+ const index: StatusPageGroupTreeIndex = StatusPageGroupTreeUtil.buildIndex({
426
+ statusPageGroups: hierarchy.groups,
427
+ });
428
+
429
+ const ancestors: Array<StatusPageGroup> =
430
+ StatusPageGroupTreeUtil.getAncestorGroups({
431
+ statusPageGroup: site,
432
+ statusPageGroups: hierarchy.groups,
433
+ index: index,
434
+ });
435
+
436
+ expect(ancestors).toHaveLength(3);
437
+
438
+ for (const ancestor of [site, ...ancestors]) {
439
+ expect(
440
+ StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants(
441
+ {
442
+ statusPageGroup: ancestor,
443
+ statusPageResources: [resource],
444
+ allStatusPageGroups: hierarchy.groups,
445
+ statusPageGroupTreeIndex: index,
446
+ },
447
+ ),
448
+ ).toEqual([resource]);
449
+ }
450
+
451
+ // a sibling branch sees nothing.
452
+ const otherUnit: StatusPageGroup = hierarchy.units[1]!;
453
+
454
+ expect(
455
+ StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants({
456
+ statusPageGroup: otherUnit,
457
+ statusPageResources: [resource],
458
+ allStatusPageGroups: hierarchy.groups,
459
+ statusPageGroupTreeIndex: index,
460
+ }),
461
+ ).toEqual([]);
462
+ });
463
+
464
+ test("the rolled up status of a branch is the status of the monitor under it", () => {
465
+ const hierarchy: Hierarchy = makeHierarchy();
466
+ const site: StatusPageGroup = hierarchy.sites[0]!;
467
+ const unit: StatusPageGroup = hierarchy.units[0]!;
468
+
469
+ const resource: StatusPageResource = attachMonitor({
470
+ group: site,
471
+ monitorId: "monitor-1",
472
+ monitorStatusId: "status-operational",
473
+ });
474
+
475
+ const index: StatusPageGroupTreeIndex = StatusPageGroupTreeUtil.buildIndex({
476
+ statusPageGroups: hierarchy.groups,
477
+ });
478
+
479
+ expect(
480
+ StatusPageResourceUptimeUtil.getCurrentStatusPageGroupStatus({
481
+ statusPageGroup: unit,
482
+ monitorStatusTimelines: [],
483
+ statusPageResources: [resource],
484
+ monitorStatuses: [operationalStatus()],
485
+ monitorGroupCurrentStatuses: {},
486
+ allStatusPageGroups: hierarchy.groups,
487
+ statusPageGroupTreeIndex: index,
488
+ }).name,
489
+ ).toBe("Operational");
490
+ });
491
+ });
492
+
493
+ describe("status page overview, pages that really are empty", () => {
494
+ test("no groups and no resources still shows the empty state", () => {
495
+ expect(
496
+ overviewDecisions({ statusPageResources: [], resourceGroups: [] }),
497
+ ).toEqual({ rendersHierarchy: false, rendersEmptyState: true });
498
+ });
499
+
500
+ test("resources with no groups renders the way it always did", () => {
501
+ const resource: StatusPageResource = new StatusPageResource();
502
+ resource._id = new ObjectID("resource-ungrouped").toString();
503
+
504
+ expect(
505
+ overviewDecisions({
506
+ statusPageResources: [resource],
507
+ resourceGroups: [],
508
+ }),
509
+ ).toEqual({ rendersHierarchy: true, rendersEmptyState: false });
510
+ });
511
+ });
512
+
513
+ describe("the shared tree index is an optimisation, not a behaviour change", () => {
514
+ test("subtree resources are the same with and without one", () => {
515
+ const hierarchy: Hierarchy = makeHierarchy();
516
+
517
+ const resources: Array<StatusPageResource> = [
518
+ attachMonitor({
519
+ group: hierarchy.sites[0]!,
520
+ monitorId: "monitor-1",
521
+ monitorStatusId: "status-operational",
522
+ }),
523
+ attachMonitor({
524
+ group: hierarchy.markets[0]!,
525
+ monitorId: "monitor-2",
526
+ monitorStatusId: "status-operational",
527
+ }),
528
+ ];
529
+
530
+ const index: StatusPageGroupTreeIndex = StatusPageGroupTreeUtil.buildIndex({
531
+ statusPageGroups: hierarchy.groups,
532
+ });
533
+
534
+ for (const group of [
535
+ hierarchy.units[0]!,
536
+ hierarchy.regions[0]!,
537
+ hierarchy.markets[0]!,
538
+ hierarchy.sites[0]!,
539
+ hierarchy.units[1]!,
540
+ ]) {
541
+ expect(
542
+ StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants(
543
+ {
544
+ statusPageGroup: group,
545
+ statusPageResources: resources,
546
+ allStatusPageGroups: hierarchy.groups,
547
+ statusPageGroupTreeIndex: index,
548
+ },
549
+ ),
550
+ ).toEqual(
551
+ StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants(
552
+ {
553
+ statusPageGroup: group,
554
+ statusPageResources: resources,
555
+ allStatusPageGroups: hierarchy.groups,
556
+ },
557
+ ),
558
+ );
559
+ }
560
+ });
561
+
562
+ /*
563
+ * An index describes one list of groups. A caller that supplies one but no
564
+ * group list is asking about a single group in isolation, and answering from
565
+ * the index would pull in a subtree that caller never asked for.
566
+ */
567
+ test("an index is ignored when no group list is supplied", () => {
568
+ const hierarchy: Hierarchy = makeHierarchy();
569
+
570
+ const resourceOnSite: StatusPageResource = attachMonitor({
571
+ group: hierarchy.sites[0]!,
572
+ monitorId: "monitor-1",
573
+ monitorStatusId: "status-operational",
574
+ });
575
+
576
+ const index: StatusPageGroupTreeIndex = StatusPageGroupTreeUtil.buildIndex({
577
+ statusPageGroups: hierarchy.groups,
578
+ });
579
+
580
+ expect(
581
+ StatusPageResourceUptimeUtil.getResourcesInStatusPageGroupAndDescendants({
582
+ statusPageGroup: hierarchy.units[0]!,
583
+ statusPageResources: [resourceOnSite],
584
+ statusPageGroupTreeIndex: index,
585
+ }),
586
+ ).toEqual([]);
587
+ });
588
+ });