@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,583 @@
1
+ import StatusPageGroupTreeUtil, {
2
+ StatusPageGroupTreeNode,
3
+ } from "../../../Utils/StatusPage/GroupTree";
4
+ import ObjectID from "../../../Types/ObjectID";
5
+ import StatusPageGroup from "../../../Models/DatabaseModels/StatusPageGroup";
6
+ import { describe, expect, test } from "@jest/globals";
7
+
8
+ /*
9
+ * Contract under test - status page groups nest, and every read path on the
10
+ * status page walks that tree:
11
+ *
12
+ * - children / roots / descendants / ancestors are derived from a single
13
+ * nullable parent pointer,
14
+ * - siblings come back in `order`,
15
+ * - and no shape of bad data (self parent, missing parent, a cycle written
16
+ * straight to the database) may drop a group from the tree or hang the
17
+ * walk. A dropped group is a resource silently missing from a customer's
18
+ * status page, so every helper is exercised against those shapes too.
19
+ */
20
+
21
+ const CORPORATE: ObjectID = new ObjectID(
22
+ "11111111-1111-4111-8111-111111111111",
23
+ );
24
+ const REGION_ONE: ObjectID = new ObjectID(
25
+ "22222222-2222-4222-8222-222222222222",
26
+ );
27
+ const REGION_TWO: ObjectID = new ObjectID(
28
+ "33333333-3333-4333-8333-333333333333",
29
+ );
30
+ const MARKET: ObjectID = new ObjectID("44444444-4444-4444-8444-444444444444");
31
+ const UNIT: ObjectID = new ObjectID("55555555-5555-4555-8555-555555555555");
32
+ const MISSING: ObjectID = new ObjectID("99999999-9999-4999-8999-999999999999");
33
+
34
+ function makeGroup(data: {
35
+ id: ObjectID;
36
+ name: string;
37
+ parentId?: ObjectID | undefined;
38
+ order?: number | undefined;
39
+ }): StatusPageGroup {
40
+ const group: StatusPageGroup = new StatusPageGroup();
41
+ group._id = data.id.toString();
42
+ group.name = data.name;
43
+
44
+ if (data.parentId) {
45
+ group.parentStatusPageGroupId = data.parentId;
46
+ }
47
+
48
+ if (data.order !== undefined) {
49
+ group.order = data.order;
50
+ }
51
+
52
+ return group;
53
+ }
54
+
55
+ /*
56
+ * Corporate
57
+ * Region 1000
58
+ * Market 1001
59
+ * Unit 0152
60
+ * Region 2000
61
+ */
62
+ function makeHierarchy(): Array<StatusPageGroup> {
63
+ return [
64
+ makeGroup({ id: CORPORATE, name: "Corporate", order: 1 }),
65
+ makeGroup({
66
+ id: REGION_ONE,
67
+ name: "Region 1000",
68
+ parentId: CORPORATE,
69
+ order: 2,
70
+ }),
71
+ makeGroup({
72
+ id: MARKET,
73
+ name: "Market 1001",
74
+ parentId: REGION_ONE,
75
+ order: 3,
76
+ }),
77
+ makeGroup({ id: UNIT, name: "Unit 0152", parentId: MARKET, order: 4 }),
78
+ makeGroup({
79
+ id: REGION_TWO,
80
+ name: "Region 2000",
81
+ parentId: CORPORATE,
82
+ order: 5,
83
+ }),
84
+ ];
85
+ }
86
+
87
+ function namesOf(groups: Array<StatusPageGroup>): Array<string> {
88
+ return groups.map((group: StatusPageGroup) => {
89
+ return group.name || "";
90
+ });
91
+ }
92
+
93
+ describe("StatusPageGroupTreeUtil", () => {
94
+ describe("getParentId", () => {
95
+ test("returns null for a top level group", () => {
96
+ const group: StatusPageGroup = makeGroup({
97
+ id: CORPORATE,
98
+ name: "Corporate",
99
+ });
100
+
101
+ expect(StatusPageGroupTreeUtil.getParentId(group)).toBeNull();
102
+ });
103
+
104
+ test("returns the parent id when nested", () => {
105
+ const group: StatusPageGroup = makeGroup({
106
+ id: REGION_ONE,
107
+ name: "Region 1000",
108
+ parentId: CORPORATE,
109
+ });
110
+
111
+ expect(StatusPageGroupTreeUtil.getParentId(group)).toBe(
112
+ CORPORATE.toString(),
113
+ );
114
+ });
115
+
116
+ test("treats a group that points at itself as a top level group", () => {
117
+ const group: StatusPageGroup = makeGroup({
118
+ id: CORPORATE,
119
+ name: "Corporate",
120
+ parentId: CORPORATE,
121
+ });
122
+
123
+ expect(StatusPageGroupTreeUtil.getParentId(group)).toBeNull();
124
+ });
125
+ });
126
+
127
+ describe("getChildGroups", () => {
128
+ test("returns only direct children, not grandchildren", () => {
129
+ const groups: Array<StatusPageGroup> = makeHierarchy();
130
+
131
+ const children: Array<StatusPageGroup> =
132
+ StatusPageGroupTreeUtil.getChildGroups({
133
+ statusPageGroupId: CORPORATE.toString(),
134
+ statusPageGroups: groups,
135
+ });
136
+
137
+ expect(namesOf(children)).toEqual(["Region 1000", "Region 2000"]);
138
+ });
139
+
140
+ test("returns children of a leaf as an empty array", () => {
141
+ expect(
142
+ StatusPageGroupTreeUtil.getChildGroups({
143
+ statusPageGroupId: UNIT.toString(),
144
+ statusPageGroups: makeHierarchy(),
145
+ }),
146
+ ).toHaveLength(0);
147
+ });
148
+
149
+ test("null asks for the groups with no parent", () => {
150
+ const roots: Array<StatusPageGroup> =
151
+ StatusPageGroupTreeUtil.getChildGroups({
152
+ statusPageGroupId: null,
153
+ statusPageGroups: makeHierarchy(),
154
+ });
155
+
156
+ expect(namesOf(roots)).toEqual(["Corporate"]);
157
+ });
158
+
159
+ test("siblings come back in `order`, not in insertion order", () => {
160
+ const groups: Array<StatusPageGroup> = [
161
+ makeGroup({ id: CORPORATE, name: "Corporate", order: 1 }),
162
+ makeGroup({
163
+ id: REGION_TWO,
164
+ name: "Region 2000",
165
+ parentId: CORPORATE,
166
+ order: 9,
167
+ }),
168
+ makeGroup({
169
+ id: REGION_ONE,
170
+ name: "Region 1000",
171
+ parentId: CORPORATE,
172
+ order: 2,
173
+ }),
174
+ ];
175
+
176
+ expect(
177
+ namesOf(
178
+ StatusPageGroupTreeUtil.getChildGroups({
179
+ statusPageGroupId: CORPORATE.toString(),
180
+ statusPageGroups: groups,
181
+ }),
182
+ ),
183
+ ).toEqual(["Region 1000", "Region 2000"]);
184
+ });
185
+
186
+ test("groups without an order keep their incoming position, after ordered ones", () => {
187
+ const groups: Array<StatusPageGroup> = [
188
+ makeGroup({ id: CORPORATE, name: "Corporate", order: 1 }),
189
+ makeGroup({ id: REGION_TWO, name: "Unordered", parentId: CORPORATE }),
190
+ makeGroup({
191
+ id: REGION_ONE,
192
+ name: "Ordered",
193
+ parentId: CORPORATE,
194
+ order: 4,
195
+ }),
196
+ ];
197
+
198
+ expect(
199
+ namesOf(
200
+ StatusPageGroupTreeUtil.getChildGroups({
201
+ statusPageGroupId: CORPORATE.toString(),
202
+ statusPageGroups: groups,
203
+ }),
204
+ ),
205
+ ).toEqual(["Ordered", "Unordered"]);
206
+ });
207
+ });
208
+
209
+ describe("getRootGroups", () => {
210
+ test("returns only the top of the hierarchy", () => {
211
+ expect(
212
+ namesOf(
213
+ StatusPageGroupTreeUtil.getRootGroups({
214
+ statusPageGroups: makeHierarchy(),
215
+ }),
216
+ ),
217
+ ).toEqual(["Corporate"]);
218
+ });
219
+
220
+ test("a flat list of groups is all roots", () => {
221
+ const groups: Array<StatusPageGroup> = [
222
+ makeGroup({ id: CORPORATE, name: "A", order: 1 }),
223
+ makeGroup({ id: REGION_ONE, name: "B", order: 2 }),
224
+ ];
225
+
226
+ expect(
227
+ StatusPageGroupTreeUtil.getRootGroups({ statusPageGroups: groups }),
228
+ ).toHaveLength(2);
229
+ });
230
+
231
+ /*
232
+ * A group whose parent was not fetched (or no longer exists) must still be
233
+ * rendered somewhere, so it is promoted rather than hidden.
234
+ */
235
+ test("a group whose parent is not in the list is promoted to a root", () => {
236
+ const orphan: StatusPageGroup = makeGroup({
237
+ id: REGION_ONE,
238
+ name: "Orphan",
239
+ parentId: MISSING,
240
+ order: 2,
241
+ });
242
+
243
+ const groups: Array<StatusPageGroup> = [
244
+ makeGroup({ id: CORPORATE, name: "Corporate", order: 1 }),
245
+ orphan,
246
+ ];
247
+
248
+ expect(
249
+ namesOf(
250
+ StatusPageGroupTreeUtil.getRootGroups({ statusPageGroups: groups }),
251
+ ),
252
+ ).toEqual(["Corporate", "Orphan"]);
253
+ });
254
+
255
+ test("an empty list has no roots", () => {
256
+ expect(
257
+ StatusPageGroupTreeUtil.getRootGroups({ statusPageGroups: [] }),
258
+ ).toHaveLength(0);
259
+ });
260
+ });
261
+
262
+ describe("getDescendantGroups", () => {
263
+ test("returns the whole subtree, excluding the group itself", () => {
264
+ const groups: Array<StatusPageGroup> = makeHierarchy();
265
+
266
+ const descendants: Array<StatusPageGroup> =
267
+ StatusPageGroupTreeUtil.getDescendantGroups({
268
+ statusPageGroup: groups[0]!,
269
+ statusPageGroups: groups,
270
+ });
271
+
272
+ expect(namesOf(descendants).sort()).toEqual([
273
+ "Market 1001",
274
+ "Region 1000",
275
+ "Region 2000",
276
+ "Unit 0152",
277
+ ]);
278
+ });
279
+
280
+ test("returns nothing for a leaf", () => {
281
+ const groups: Array<StatusPageGroup> = makeHierarchy();
282
+
283
+ expect(
284
+ StatusPageGroupTreeUtil.getDescendantGroups({
285
+ statusPageGroup: groups[3]!,
286
+ statusPageGroups: groups,
287
+ }),
288
+ ).toHaveLength(0);
289
+ });
290
+
291
+ test("does not loop forever on a cycle written straight to the database", () => {
292
+ // A -> B -> A
293
+ const a: StatusPageGroup = makeGroup({
294
+ id: CORPORATE,
295
+ name: "A",
296
+ parentId: REGION_ONE,
297
+ order: 1,
298
+ });
299
+ const b: StatusPageGroup = makeGroup({
300
+ id: REGION_ONE,
301
+ name: "B",
302
+ parentId: CORPORATE,
303
+ order: 2,
304
+ });
305
+
306
+ const descendants: Array<StatusPageGroup> =
307
+ StatusPageGroupTreeUtil.getDescendantGroups({
308
+ statusPageGroup: a,
309
+ statusPageGroups: [a, b],
310
+ });
311
+
312
+ expect(namesOf(descendants)).toEqual(["B"]);
313
+ });
314
+ });
315
+
316
+ describe("getGroupAndDescendants", () => {
317
+ test("includes the group itself first", () => {
318
+ const groups: Array<StatusPageGroup> = makeHierarchy();
319
+
320
+ const subtree: Array<StatusPageGroup> =
321
+ StatusPageGroupTreeUtil.getGroupAndDescendants({
322
+ statusPageGroup: groups[1]!,
323
+ statusPageGroups: groups,
324
+ });
325
+
326
+ expect(namesOf(subtree)).toEqual([
327
+ "Region 1000",
328
+ "Market 1001",
329
+ "Unit 0152",
330
+ ]);
331
+ });
332
+
333
+ test("a group with no hierarchy supplied covers only itself", () => {
334
+ const group: StatusPageGroup = makeGroup({
335
+ id: CORPORATE,
336
+ name: "Corporate",
337
+ });
338
+
339
+ expect(
340
+ StatusPageGroupTreeUtil.getGroupAndDescendants({
341
+ statusPageGroup: group,
342
+ statusPageGroups: [group],
343
+ }),
344
+ ).toHaveLength(1);
345
+ });
346
+ });
347
+
348
+ describe("getAncestorGroups", () => {
349
+ test("returns the chain to the root, closest parent first", () => {
350
+ const groups: Array<StatusPageGroup> = makeHierarchy();
351
+
352
+ expect(
353
+ namesOf(
354
+ StatusPageGroupTreeUtil.getAncestorGroups({
355
+ statusPageGroup: groups[3]!,
356
+ statusPageGroups: groups,
357
+ }),
358
+ ),
359
+ ).toEqual(["Market 1001", "Region 1000", "Corporate"]);
360
+ });
361
+
362
+ test("a root has no ancestors", () => {
363
+ const groups: Array<StatusPageGroup> = makeHierarchy();
364
+
365
+ expect(
366
+ StatusPageGroupTreeUtil.getAncestorGroups({
367
+ statusPageGroup: groups[0]!,
368
+ statusPageGroups: groups,
369
+ }),
370
+ ).toHaveLength(0);
371
+ });
372
+
373
+ test("stops at a missing parent instead of throwing", () => {
374
+ const orphan: StatusPageGroup = makeGroup({
375
+ id: REGION_ONE,
376
+ name: "Orphan",
377
+ parentId: MISSING,
378
+ });
379
+
380
+ expect(
381
+ StatusPageGroupTreeUtil.getAncestorGroups({
382
+ statusPageGroup: orphan,
383
+ statusPageGroups: [orphan],
384
+ }),
385
+ ).toHaveLength(0);
386
+ });
387
+
388
+ test("stops at a cycle instead of looping forever", () => {
389
+ const a: StatusPageGroup = makeGroup({
390
+ id: CORPORATE,
391
+ name: "A",
392
+ parentId: REGION_ONE,
393
+ });
394
+ const b: StatusPageGroup = makeGroup({
395
+ id: REGION_ONE,
396
+ name: "B",
397
+ parentId: CORPORATE,
398
+ });
399
+
400
+ expect(
401
+ namesOf(
402
+ StatusPageGroupTreeUtil.getAncestorGroups({
403
+ statusPageGroup: a,
404
+ statusPageGroups: [a, b],
405
+ }),
406
+ ),
407
+ ).toEqual(["B"]);
408
+ });
409
+ });
410
+
411
+ describe("getDepth", () => {
412
+ test("counts levels from the top", () => {
413
+ const groups: Array<StatusPageGroup> = makeHierarchy();
414
+
415
+ expect(
416
+ StatusPageGroupTreeUtil.getDepth({
417
+ statusPageGroup: groups[0]!,
418
+ statusPageGroups: groups,
419
+ }),
420
+ ).toBe(0);
421
+
422
+ expect(
423
+ StatusPageGroupTreeUtil.getDepth({
424
+ statusPageGroup: groups[3]!,
425
+ statusPageGroups: groups,
426
+ }),
427
+ ).toBe(3);
428
+ });
429
+ });
430
+
431
+ describe("isDescendantOf", () => {
432
+ test("is true for a grandchild", () => {
433
+ const groups: Array<StatusPageGroup> = makeHierarchy();
434
+
435
+ expect(
436
+ StatusPageGroupTreeUtil.isDescendantOf({
437
+ statusPageGroup: groups[3]!,
438
+ possibleAncestorId: CORPORATE.toString(),
439
+ statusPageGroups: groups,
440
+ }),
441
+ ).toBe(true);
442
+ });
443
+
444
+ test("is false across branches", () => {
445
+ const groups: Array<StatusPageGroup> = makeHierarchy();
446
+
447
+ expect(
448
+ StatusPageGroupTreeUtil.isDescendantOf({
449
+ statusPageGroup: groups[4]!,
450
+ possibleAncestorId: REGION_ONE.toString(),
451
+ statusPageGroups: groups,
452
+ }),
453
+ ).toBe(false);
454
+ });
455
+
456
+ test("a group is not a descendant of itself", () => {
457
+ const groups: Array<StatusPageGroup> = makeHierarchy();
458
+
459
+ expect(
460
+ StatusPageGroupTreeUtil.isDescendantOf({
461
+ statusPageGroup: groups[0]!,
462
+ possibleAncestorId: CORPORATE.toString(),
463
+ statusPageGroups: groups,
464
+ }),
465
+ ).toBe(false);
466
+ });
467
+ });
468
+
469
+ describe("buildTree", () => {
470
+ test("nests each level under its parent and records depth", () => {
471
+ const tree: Array<StatusPageGroupTreeNode> =
472
+ StatusPageGroupTreeUtil.buildTree({
473
+ statusPageGroups: makeHierarchy(),
474
+ });
475
+
476
+ expect(tree).toHaveLength(1);
477
+
478
+ const corporate: StatusPageGroupTreeNode = tree[0]!;
479
+ expect(corporate.group.name).toBe("Corporate");
480
+ expect(corporate.depth).toBe(0);
481
+ expect(
482
+ corporate.children.map((node: StatusPageGroupTreeNode) => {
483
+ return node.group.name;
484
+ }),
485
+ ).toEqual(["Region 1000", "Region 2000"]);
486
+
487
+ const regionOne: StatusPageGroupTreeNode = corporate.children[0]!;
488
+ expect(regionOne.depth).toBe(1);
489
+ expect(regionOne.children[0]!.group.name).toBe("Market 1001");
490
+ expect(regionOne.children[0]!.depth).toBe(2);
491
+ expect(regionOne.children[0]!.children[0]!.group.name).toBe("Unit 0152");
492
+ expect(regionOne.children[0]!.children[0]!.depth).toBe(3);
493
+ });
494
+
495
+ test("every group appears exactly once", () => {
496
+ const groups: Array<StatusPageGroup> = makeHierarchy();
497
+
498
+ const seen: Array<string> = [];
499
+
500
+ const visit: (nodes: Array<StatusPageGroupTreeNode>) => void = (
501
+ nodes: Array<StatusPageGroupTreeNode>,
502
+ ): void => {
503
+ for (const node of nodes) {
504
+ seen.push(node.group.name || "");
505
+ visit(node.children);
506
+ }
507
+ };
508
+
509
+ visit(StatusPageGroupTreeUtil.buildTree({ statusPageGroups: groups }));
510
+
511
+ expect(seen).toHaveLength(groups.length);
512
+ expect(new Set(seen).size).toBe(groups.length);
513
+ });
514
+
515
+ /*
516
+ * Groups caught in a cycle are reachable from no root. They must still be
517
+ * shown - dropping them would silently hide monitors from the page.
518
+ */
519
+ test("promotes groups stuck in a cycle to the top level rather than dropping them", () => {
520
+ const a: StatusPageGroup = makeGroup({
521
+ id: CORPORATE,
522
+ name: "A",
523
+ parentId: REGION_ONE,
524
+ order: 1,
525
+ });
526
+ const b: StatusPageGroup = makeGroup({
527
+ id: REGION_ONE,
528
+ name: "B",
529
+ parentId: CORPORATE,
530
+ order: 2,
531
+ });
532
+
533
+ const tree: Array<StatusPageGroupTreeNode> =
534
+ StatusPageGroupTreeUtil.buildTree({ statusPageGroups: [a, b] });
535
+
536
+ const seen: Array<string> = [];
537
+
538
+ const visit: (nodes: Array<StatusPageGroupTreeNode>) => void = (
539
+ nodes: Array<StatusPageGroupTreeNode>,
540
+ ): void => {
541
+ for (const node of nodes) {
542
+ seen.push(node.group.name || "");
543
+ visit(node.children);
544
+ }
545
+ };
546
+
547
+ visit(tree);
548
+
549
+ expect(seen.sort()).toEqual(["A", "B"]);
550
+ });
551
+
552
+ test("an orphan renders at the top level", () => {
553
+ const orphan: StatusPageGroup = makeGroup({
554
+ id: REGION_ONE,
555
+ name: "Orphan",
556
+ parentId: MISSING,
557
+ order: 2,
558
+ });
559
+ const root: StatusPageGroup = makeGroup({
560
+ id: CORPORATE,
561
+ name: "Corporate",
562
+ order: 1,
563
+ });
564
+
565
+ const tree: Array<StatusPageGroupTreeNode> =
566
+ StatusPageGroupTreeUtil.buildTree({
567
+ statusPageGroups: [root, orphan],
568
+ });
569
+
570
+ expect(
571
+ tree.map((node: StatusPageGroupTreeNode) => {
572
+ return node.group.name;
573
+ }),
574
+ ).toEqual(["Corporate", "Orphan"]);
575
+ });
576
+
577
+ test("an empty list builds an empty tree", () => {
578
+ expect(
579
+ StatusPageGroupTreeUtil.buildTree({ statusPageGroups: [] }),
580
+ ).toHaveLength(0);
581
+ });
582
+ });
583
+ });