@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
@@ -77,6 +77,13 @@ const TableRow: TableRowFunction = <T extends GenericObject>(
77
77
  };
78
78
  }, []);
79
79
 
80
+ // The columns this row will actually put on screen.
81
+ const renderedColumns: Array<Column<T>> = (props.columns || []).filter(
82
+ (column: Column<T>) => {
83
+ return !(column.hideOnMobile && isMobile);
84
+ },
85
+ );
86
+
80
87
  type GetRowFunction = (provided?: DraggableProvided) => ReactElement;
81
88
 
82
89
  const getRow: GetRowFunction = (
@@ -339,186 +346,184 @@ const TableRow: TableRowFunction = <T extends GenericObject>(
339
346
  </td>
340
347
  )}
341
348
  {props.columns &&
342
- props.columns
343
- .filter((column: Column<T>) => {
344
- return !(column.hideOnMobile && isMobile);
345
- })
346
- .map((column: Column<T>, i: number) => {
347
- let className: string =
348
- "whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-500 sm:pl-6 align-top";
349
- if (i === props.columns.length - 1) {
350
- className =
351
- "whitespace-nowrap py-4 pl-4 pr-6 text-sm font-medium text-gray-500 sm:pl-6 align-top";
352
- }
353
-
354
- let columnContent: React.ReactNode = null;
355
-
356
- if (column.key && !column.getElement) {
357
- columnContent =
358
- column.type === FieldType.Date ? (
359
- props.item[column.key] ? (
360
- OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
361
- props.item[column.key] as string,
362
- true,
363
- )
364
- ) : (
365
- column.noValueMessage || ""
366
- )
367
- ) : column.type === FieldType.DateTime ? (
368
- props.item[column.key] ? (
369
- OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
370
- props.item[column.key] as string,
371
- false,
372
- )
373
- ) : (
374
- column.noValueMessage || ""
375
- )
376
- ) : column.type === FieldType.USDCents ? (
377
- props.item[column.key] ? (
378
- ((props.item[column.key] as number) || 0) / 100 + " USD"
379
- ) : (
380
- column.noValueMessage || "0 USD"
381
- )
382
- ) : column.type === FieldType.Percent ? (
383
- props.item[column.key] ? (
384
- props.item[column.key] + "%"
385
- ) : (
386
- column.noValueMessage || "0%"
349
+ renderedColumns.map((column: Column<T>, i: number) => {
350
+ let className: string =
351
+ "whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-gray-500 sm:pl-6 align-top";
352
+ /*
353
+ * Compared against the rendered count, not the declared one:
354
+ * with any column filtered out the two differ, and the extra
355
+ * right padding would land on the wrong cell - or on none.
356
+ */
357
+ if (i === renderedColumns.length - 1) {
358
+ className =
359
+ "whitespace-nowrap py-4 pl-4 pr-6 text-sm font-medium text-gray-500 sm:pl-6 align-top";
360
+ }
361
+
362
+ let columnContent: React.ReactNode = null;
363
+
364
+ if (column.key && !column.getElement) {
365
+ columnContent =
366
+ column.type === FieldType.Date ? (
367
+ props.item[column.key] ? (
368
+ OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
369
+ props.item[column.key] as string,
370
+ true,
387
371
  )
388
- ) : column.type === FieldType.Color ? (
389
- props.item[column.key] ? (
390
- <ColorInput value={props.item[column.key] as Color} />
391
- ) : (
392
- column.noValueMessage || "0%"
393
- )
394
- ) : column.type === FieldType.LongText ? (
395
- props.item[column.key] ? (
396
- <LongTextViewer
397
- text={props.item[column.key] as string}
398
- />
399
- ) : (
400
- column.noValueMessage || ""
401
- )
402
- ) : column.type === FieldType.Boolean ? (
403
- props.item[column.key] ? (
404
- <Icon
405
- icon={IconProp.Check}
406
- className={"h-5 w-5 text-gray-500"}
407
- thick={ThickProp.Thick}
408
- />
409
- ) : (
410
- <Icon
411
- icon={IconProp.False}
412
- className={"h-5 w-5 text-gray-500"}
413
- thick={ThickProp.Thick}
414
- />
372
+ ) : (
373
+ column.noValueMessage || ""
374
+ )
375
+ ) : column.type === FieldType.DateTime ? (
376
+ props.item[column.key] ? (
377
+ OneUptimeDate.getDateAsUserFriendlyLocalFormattedString(
378
+ props.item[column.key] as string,
379
+ false,
415
380
  )
416
381
  ) : (
417
- getNestedValue(
418
- props.item,
419
- String(column.key),
420
- )?.toString() ||
421
- column.noValueMessage ||
422
- ""
423
- );
424
- } else if (column.key && column.getElement) {
425
- columnContent = column.getElement(props.item);
426
- }
427
-
428
- const contentWrapperClassName: string = column.contentClassName
429
- ? column.contentClassName
430
- : "";
431
-
432
- const actionsContainerClassName: string =
433
- column.contentClassName
434
- ? `flex justify-end ${column.contentClassName}`
435
- : "flex justify-end";
382
+ column.noValueMessage || ""
383
+ )
384
+ ) : column.type === FieldType.USDCents ? (
385
+ props.item[column.key] ? (
386
+ ((props.item[column.key] as number) || 0) / 100 + " USD"
387
+ ) : (
388
+ column.noValueMessage || "0 USD"
389
+ )
390
+ ) : column.type === FieldType.Percent ? (
391
+ props.item[column.key] ? (
392
+ props.item[column.key] + "%"
393
+ ) : (
394
+ column.noValueMessage || "0%"
395
+ )
396
+ ) : column.type === FieldType.Color ? (
397
+ props.item[column.key] ? (
398
+ <ColorInput value={props.item[column.key] as Color} />
399
+ ) : (
400
+ column.noValueMessage || "0%"
401
+ )
402
+ ) : column.type === FieldType.LongText ? (
403
+ props.item[column.key] ? (
404
+ <LongTextViewer text={props.item[column.key] as string} />
405
+ ) : (
406
+ column.noValueMessage || ""
407
+ )
408
+ ) : column.type === FieldType.Boolean ? (
409
+ props.item[column.key] ? (
410
+ <Icon
411
+ icon={IconProp.Check}
412
+ className={"h-5 w-5 text-gray-500"}
413
+ thick={ThickProp.Thick}
414
+ />
415
+ ) : (
416
+ <Icon
417
+ icon={IconProp.False}
418
+ className={"h-5 w-5 text-gray-500"}
419
+ thick={ThickProp.Thick}
420
+ />
421
+ )
422
+ ) : (
423
+ getNestedValue(
424
+ props.item,
425
+ String(column.key),
426
+ )?.toString() ||
427
+ column.noValueMessage ||
428
+ ""
429
+ );
430
+ } else if (column.key && column.getElement) {
431
+ columnContent = column.getElement(props.item);
432
+ }
433
+
434
+ const contentWrapperClassName: string = column.contentClassName
435
+ ? column.contentClassName
436
+ : "";
437
+
438
+ const actionsContainerClassName: string = column.contentClassName
439
+ ? `flex justify-end ${column.contentClassName}`
440
+ : "flex justify-end";
441
+
442
+ return (
443
+ <td
444
+ key={i}
445
+ className={className}
446
+ style={{
447
+ textAlign:
448
+ column.type === FieldType.Actions ? "right" : "left",
449
+ }}
450
+ onClick={() => {
451
+ if (column.tooltipText) {
452
+ setTooltipModalText(column.tooltipText(props.item));
453
+ }
454
+ }}
455
+ >
456
+ {columnContent !== null && columnContent !== undefined && (
457
+ <div className={contentWrapperClassName}>
458
+ {columnContent}
459
+ </div>
460
+ )}
461
+ {column.type === FieldType.Actions && (
462
+ <div className={actionsContainerClassName}>
463
+ {error && (
464
+ <div className="text-align-left">
465
+ <ConfirmModal
466
+ title={`Error`}
467
+ description={error}
468
+ submitButtonText={"Close"}
469
+ onSubmit={() => {
470
+ return setError("");
471
+ }}
472
+ />
473
+ </div>
474
+ )}
475
+ {props.actionButtons?.map(
476
+ (button: ActionButtonSchema<T>, i: number) => {
477
+ if (
478
+ button.isVisible &&
479
+ !button.isVisible(props.item)
480
+ ) {
481
+ return <div key={i}></div>;
482
+ }
436
483
 
437
- return (
438
- <td
439
- key={i}
440
- className={className}
441
- style={{
442
- textAlign:
443
- column.type === FieldType.Actions ? "right" : "left",
444
- }}
445
- onClick={() => {
446
- if (column.tooltipText) {
447
- setTooltipModalText(column.tooltipText(props.item));
448
- }
449
- }}
450
- >
451
- {columnContent !== null && columnContent !== undefined && (
452
- <div className={contentWrapperClassName}>
453
- {columnContent}
454
- </div>
455
- )}
456
- {column.type === FieldType.Actions && (
457
- <div className={actionsContainerClassName}>
458
- {error && (
459
- <div className="text-align-left">
460
- <ConfirmModal
461
- title={`Error`}
462
- description={error}
463
- submitButtonText={"Close"}
464
- onSubmit={() => {
465
- return setError("");
466
- }}
467
- />
468
- </div>
469
- )}
470
- {props.actionButtons?.map(
471
- (button: ActionButtonSchema<T>, i: number) => {
472
- if (
473
- button.isVisible &&
474
- !button.isVisible(props.item)
475
- ) {
476
- return <div key={i}></div>;
477
- }
478
-
479
- // Hide button on mobile if hideOnMobile is true
480
- if (button.hideOnMobile && isMobile) {
481
- return <div key={i}></div>;
482
- }
483
-
484
- return (
485
- <div key={i}>
486
- <Button
487
- buttonSize={ButtonSize.Small}
488
- title={button.title}
489
- icon={button.icon}
490
- buttonStyle={button.buttonStyleType}
491
- isLoading={isButtonLoading[i]}
492
- onClick={() => {
493
- if (button.onClick) {
494
- isButtonLoading[i] = true;
495
- setIsButtonLoading(isButtonLoading);
484
+ // Hide button on mobile if hideOnMobile is true
485
+ if (button.hideOnMobile && isMobile) {
486
+ return <div key={i}></div>;
487
+ }
496
488
 
497
- button.onClick(
498
- props.item,
499
- () => {
500
- // on action complete
501
- isButtonLoading[i] = false;
502
- setIsButtonLoading(isButtonLoading);
503
- },
504
- (err: Error) => {
505
- isButtonLoading[i] = false;
506
- setIsButtonLoading(isButtonLoading);
507
- setError((err as Error).message);
508
- },
509
- );
510
- }
511
- }}
512
- />
513
- </div>
514
- );
515
- },
516
- )}
517
- </div>
518
- )}
519
- </td>
520
- );
521
- })}
489
+ return (
490
+ <div key={i}>
491
+ <Button
492
+ buttonSize={ButtonSize.Small}
493
+ title={button.title}
494
+ icon={button.icon}
495
+ buttonStyle={button.buttonStyleType}
496
+ isLoading={isButtonLoading[i]}
497
+ onClick={() => {
498
+ if (button.onClick) {
499
+ isButtonLoading[i] = true;
500
+ setIsButtonLoading(isButtonLoading);
501
+
502
+ button.onClick(
503
+ props.item,
504
+ () => {
505
+ // on action complete
506
+ isButtonLoading[i] = false;
507
+ setIsButtonLoading(isButtonLoading);
508
+ },
509
+ (err: Error) => {
510
+ isButtonLoading[i] = false;
511
+ setIsButtonLoading(isButtonLoading);
512
+ setError((err as Error).message);
513
+ },
514
+ );
515
+ }
516
+ }}
517
+ />
518
+ </div>
519
+ );
520
+ },
521
+ )}
522
+ </div>
523
+ )}
524
+ </td>
525
+ );
526
+ })}
522
527
  </tr>
523
528
  {tooltipModalText && (
524
529
  <ConfirmModal
@@ -5,6 +5,8 @@ import { ReactElement } from "react";
5
5
 
6
6
  export default interface Column<T extends GenericObject> {
7
7
  title: string;
8
+ // Stable identity carried over from the ModelTable column, if it had one.
9
+ id?: string | undefined;
8
10
  description?: string | undefined;
9
11
  disableSort?: boolean | undefined;
10
12
  tooltipText?: ((item: T) => string) | undefined;
@@ -14,12 +14,20 @@ import InBetween from "../../../../Types/BaseDatabase/InBetween";
14
14
  import StartAndEndDate, {
15
15
  StartAndEndDateType,
16
16
  } from "../../Date/StartAndEndDate";
17
+ import {
18
+ DropdownHorizontalAlignment,
19
+ getDropdownAlignmentClassName,
20
+ useDropdownHorizontalAlignment,
21
+ } from "../../../Utils/DropdownAlignment";
17
22
 
18
23
  export interface TelemetryTimeRangePickerProps {
19
24
  value: RangeStartAndEndDateTime;
20
25
  onChange: (value: RangeStartAndEndDateTime) => void;
21
26
  }
22
27
 
28
+ // Matches the Tailwind `w-72` on the dropdown below (18rem).
29
+ export const TIME_RANGE_DROPDOWN_WIDTH_IN_PX: number = 288;
30
+
23
31
  const PRESET_OPTIONS: Array<{ range: TimeRange; label: string }> = [
24
32
  { range: TimeRange.PAST_FIVE_MINS, label: "Past 5 Minutes" },
25
33
  { range: TimeRange.PAST_FIFTEEN_MINS, label: "Past 15 Minutes" },
@@ -67,6 +75,20 @@ const TelemetryTimeRangePicker: FunctionComponent<
67
75
  const containerRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
68
76
  null!,
69
77
  );
78
+ const buttonRef: React.RefObject<HTMLButtonElement> =
79
+ useRef<HTMLButtonElement>(null!);
80
+ const dropdownRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
81
+ null!,
82
+ );
83
+
84
+ const alignment: DropdownHorizontalAlignment = useDropdownHorizontalAlignment(
85
+ {
86
+ isOpen: isOpen,
87
+ anchorRef: buttonRef,
88
+ dropdownRef: dropdownRef,
89
+ dropdownWidthInPx: TIME_RANGE_DROPDOWN_WIDTH_IN_PX,
90
+ },
91
+ );
70
92
 
71
93
  useEffect(() => {
72
94
  const handleClickOutside: (e: MouseEvent) => void = (
@@ -117,7 +139,11 @@ const TelemetryTimeRangePicker: FunctionComponent<
117
139
  return (
118
140
  <div ref={containerRef} className="relative">
119
141
  <button
142
+ ref={buttonRef}
120
143
  type="button"
144
+ data-testid="telemetry-time-range-picker-button"
145
+ aria-haspopup="true"
146
+ aria-expanded={isOpen}
121
147
  className={`inline-flex items-center gap-1.5 rounded-md border px-2.5 py-1.5 text-xs font-medium shadow-sm transition-colors ${
122
148
  isOpen
123
149
  ? "border-indigo-300 bg-indigo-50 text-indigo-700"
@@ -136,7 +162,14 @@ const TelemetryTimeRangePicker: FunctionComponent<
136
162
  </button>
137
163
 
138
164
  {isOpen && (
139
- <div className="absolute right-0 top-full z-50 mt-1 w-72 rounded-lg border border-gray-200 bg-white shadow-lg">
165
+ <div
166
+ ref={dropdownRef}
167
+ data-testid="telemetry-time-range-picker-dropdown"
168
+ data-align={alignment}
169
+ className={`absolute ${getDropdownAlignmentClassName(
170
+ alignment,
171
+ )} top-full z-50 mt-1 w-72 max-w-[calc(100vw-1rem)] rounded-lg border border-gray-200 bg-white shadow-lg`}
172
+ >
140
173
  <div className="max-h-64 overflow-y-auto py-1">
141
174
  {PRESET_OPTIONS.map(
142
175
  (option: { range: TimeRange; label: string }) => {
@@ -0,0 +1,162 @@
1
+ import React, { useEffect, useState } from "react";
2
+
3
+ /*
4
+ * Horizontal edge of the trigger that a popup pins itself to.
5
+ * "Left" means the popup grows rightwards from the trigger's left edge
6
+ * (Tailwind `left-0`), "Right" means it grows leftwards from the trigger's
7
+ * right edge (Tailwind `right-0`).
8
+ */
9
+ export enum DropdownHorizontalAlignment {
10
+ Left = "left",
11
+ Right = "right",
12
+ }
13
+
14
+ // Breathing room we keep between a popup and the edge of the viewport.
15
+ export const DEFAULT_DROPDOWN_VIEWPORT_MARGIN_IN_PX: number = 8;
16
+
17
+ export interface DropdownAlignmentInput {
18
+ // Viewport-relative left edge of the trigger, as reported by getBoundingClientRect().
19
+ anchorLeft: number;
20
+ // Viewport-relative right edge of the trigger.
21
+ anchorRight: number;
22
+ // Rendered width of the popup in pixels.
23
+ dropdownWidth: number;
24
+ // Width of the viewport in pixels.
25
+ viewportWidth: number;
26
+ // Optional override for the viewport gutter.
27
+ viewportMargin?: number | undefined;
28
+ }
29
+
30
+ /*
31
+ * Picks the edge a popup should align to so that it stays inside the viewport.
32
+ *
33
+ * Left alignment is preferred because it reads naturally next to the trigger.
34
+ * We only flip to the right edge when left alignment would spill past the right
35
+ * side of the viewport, and we never flip if doing so would spill past the left
36
+ * side by even more (which is what produced the off-screen popup on the metric
37
+ * explorer toolbar, where the trigger sits at the far left of the page).
38
+ */
39
+ export function getDropdownHorizontalAlignment(
40
+ input: DropdownAlignmentInput,
41
+ ): DropdownHorizontalAlignment {
42
+ const margin: number =
43
+ input.viewportMargin === undefined
44
+ ? DEFAULT_DROPDOWN_VIEWPORT_MARGIN_IN_PX
45
+ : input.viewportMargin;
46
+
47
+ /*
48
+ * Before the popup is laid out (or in a non-visual environment) measurements
49
+ * come back as zero. There is nothing to solve for, so keep the default.
50
+ */
51
+ if (
52
+ !Number.isFinite(input.dropdownWidth) ||
53
+ !Number.isFinite(input.viewportWidth) ||
54
+ input.dropdownWidth <= 0 ||
55
+ input.viewportWidth <= 0
56
+ ) {
57
+ return DropdownHorizontalAlignment.Left;
58
+ }
59
+
60
+ // How far a left-aligned popup would poke past the right gutter.
61
+ const leftAlignedOverflow: number =
62
+ input.anchorLeft + input.dropdownWidth - (input.viewportWidth - margin);
63
+
64
+ // How far a right-aligned popup would poke past the left gutter.
65
+ const rightAlignedOverflow: number =
66
+ margin - (input.anchorRight - input.dropdownWidth);
67
+
68
+ if (leftAlignedOverflow <= 0) {
69
+ return DropdownHorizontalAlignment.Left;
70
+ }
71
+
72
+ if (rightAlignedOverflow <= 0) {
73
+ return DropdownHorizontalAlignment.Right;
74
+ }
75
+
76
+ // Neither edge fits. Pick whichever clips the least, preferring left on a tie.
77
+ return leftAlignedOverflow <= rightAlignedOverflow
78
+ ? DropdownHorizontalAlignment.Left
79
+ : DropdownHorizontalAlignment.Right;
80
+ }
81
+
82
+ /*
83
+ * Tailwind positioning class for an alignment. Kept next to the resolver so
84
+ * callers cannot drift out of sync with the enum.
85
+ */
86
+ export function getDropdownAlignmentClassName(
87
+ alignment: DropdownHorizontalAlignment,
88
+ ): string {
89
+ return alignment === DropdownHorizontalAlignment.Right ? "right-0" : "left-0";
90
+ }
91
+
92
+ export interface UseDropdownHorizontalAlignmentOptions {
93
+ // Only measure while the popup is actually on screen.
94
+ isOpen: boolean;
95
+ // The trigger the popup hangs off.
96
+ anchorRef: React.RefObject<HTMLElement>;
97
+ // The popup itself. When it has not been laid out we fall back to the declared width.
98
+ dropdownRef?: React.RefObject<HTMLElement> | undefined;
99
+ // Width the popup is styled to (e.g. 288 for Tailwind `w-72`).
100
+ dropdownWidthInPx: number;
101
+ viewportMargin?: number | undefined;
102
+ }
103
+
104
+ /*
105
+ * Keeps a popup's horizontal alignment in sync with the space available around
106
+ * its trigger. Re-measures when the popup opens and whenever the viewport
107
+ * changes size or scrolls the trigger somewhere new.
108
+ */
109
+ export function useDropdownHorizontalAlignment(
110
+ options: UseDropdownHorizontalAlignmentOptions,
111
+ ): DropdownHorizontalAlignment {
112
+ const [alignment, setAlignment] = useState<DropdownHorizontalAlignment>(
113
+ DropdownHorizontalAlignment.Left,
114
+ );
115
+
116
+ const {
117
+ isOpen,
118
+ anchorRef,
119
+ dropdownRef,
120
+ dropdownWidthInPx,
121
+ viewportMargin,
122
+ }: UseDropdownHorizontalAlignmentOptions = options;
123
+
124
+ useEffect(() => {
125
+ if (!isOpen) {
126
+ return undefined;
127
+ }
128
+
129
+ const measure: () => void = (): void => {
130
+ const anchor: HTMLElement | null = anchorRef.current;
131
+
132
+ if (!anchor || typeof anchor.getBoundingClientRect !== "function") {
133
+ return;
134
+ }
135
+
136
+ const anchorRect: DOMRect = anchor.getBoundingClientRect();
137
+ const measuredWidth: number = dropdownRef?.current?.offsetWidth || 0;
138
+
139
+ setAlignment(
140
+ getDropdownHorizontalAlignment({
141
+ anchorLeft: anchorRect.left,
142
+ anchorRight: anchorRect.right,
143
+ dropdownWidth: measuredWidth > 0 ? measuredWidth : dropdownWidthInPx,
144
+ viewportWidth: window.innerWidth,
145
+ viewportMargin: viewportMargin,
146
+ }),
147
+ );
148
+ };
149
+
150
+ measure();
151
+
152
+ window.addEventListener("resize", measure);
153
+ window.addEventListener("scroll", measure, true);
154
+
155
+ return () => {
156
+ window.removeEventListener("resize", measure);
157
+ window.removeEventListener("scroll", measure, true);
158
+ };
159
+ }, [isOpen, anchorRef, dropdownRef, dropdownWidthInPx, viewportMargin]);
160
+
161
+ return alignment;
162
+ }