@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
@@ -1,8 +1,6 @@
1
1
  import Navigation from "../../Utils/Navigation";
2
2
  import { ButtonStyleType } from "../Button/Button";
3
- import { IconType } from "../Icon/Icon";
4
3
  import Modal from "../Modal/Modal";
5
- import IconProp from "../../../Types/Icon/IconProp";
6
4
  import React, { FunctionComponent, ReactElement } from "react";
7
5
 
8
6
  export interface ComponentProps {
@@ -22,8 +20,6 @@ const PageError: FunctionComponent<ComponentProps> = (
22
20
  return (
23
21
  <Modal
24
22
  title={props.title || "Oops, something went wrong."}
25
- icon={IconProp.Alert}
26
- iconType={IconType.Danger}
27
23
  onSubmit={() => {
28
24
  Navigation.reload();
29
25
  }}
@@ -1,30 +1,246 @@
1
- import React, { FunctionComponent, ReactElement } from "react";
2
- import { ErrorBoundary as NativeErrorBoundary } from "react-error-boundary";
1
+ import React, { FunctionComponent, ReactElement, ReactNode } from "react";
2
+ import {
3
+ ErrorBoundary as NativeErrorBoundary,
4
+ FallbackProps,
5
+ } from "react-error-boundary";
3
6
 
4
7
  export interface ComponentProps {
5
- children?: ReactElement;
8
+ children?: ReactNode;
9
+ /**
10
+ * When this value changes the boundary clears its error and re-renders its
11
+ * children. Pass the current route (pathname) so navigating away from a page
12
+ * that crashed recovers the app instead of stranding the user on the
13
+ * fallback until they reload.
14
+ */
15
+ resetKey?: string | undefined;
16
+ /** Notified for every caught error. Used by tests and by callers that report. */
17
+ onError?: ((error: Error) => void) | undefined;
6
18
  }
7
19
 
8
- const Fallback: FunctionComponent = () => {
20
+ /**
21
+ * A code-split chunk that fails to download throws during render, and — with
22
+ * no boundary above it — takes the entire React tree down with it. This is the
23
+ * usual cause of an app that "sometimes" goes blank: a user holds a tab open
24
+ * across a deploy, the hashed chunk filenames they were served no longer
25
+ * exist, and the next lazy route they visit 404s.
26
+ *
27
+ * Browsers word this failure differently, hence the list.
28
+ */
29
+ const CHUNK_LOAD_ERROR_PATTERNS: Array<RegExp> = [
30
+ /Loading chunk \S+ failed/i,
31
+ /Loading CSS chunk \S+ failed/i,
32
+ /ChunkLoadError/i,
33
+ /Failed to fetch dynamically imported module/i,
34
+ /error loading dynamically imported module/i,
35
+ /Importing a module script failed/i,
36
+ /Unable to preload CSS/i,
37
+ ];
38
+
39
+ /** sessionStorage key holding the timestamp of the last chunk-error reload. */
40
+ export const CHUNK_LOAD_RELOAD_STORAGE_KEY: string =
41
+ "oneuptime-chunk-load-reload-at";
42
+
43
+ /**
44
+ * If a reload does not fix the chunk error, reloading again will not either.
45
+ * Only auto-reload when the last attempt is older than this, so a genuinely
46
+ * missing asset degrades to the fallback UI instead of a reload loop.
47
+ */
48
+ export const CHUNK_LOAD_RELOAD_COOLDOWN_IN_MS: number = 30 * 1000;
49
+
50
+ export type IsChunkLoadErrorFunction = (error: unknown) => boolean;
51
+
52
+ export const isChunkLoadError: IsChunkLoadErrorFunction = (
53
+ error: unknown,
54
+ ): boolean => {
55
+ if (!error) {
56
+ return false;
57
+ }
58
+
59
+ const name: string =
60
+ typeof (error as Error).name === "string" ? (error as Error).name : "";
61
+ const message: string =
62
+ typeof (error as Error).message === "string"
63
+ ? (error as Error).message
64
+ : String(error);
65
+
66
+ const text: string = `${name} ${message}`;
67
+
68
+ return CHUNK_LOAD_ERROR_PATTERNS.some((pattern: RegExp) => {
69
+ return pattern.test(text);
70
+ });
71
+ };
72
+
73
+ export type HasRecentlyReloadedFunction = (now: number) => boolean;
74
+
75
+ /**
76
+ * sessionStorage is unavailable in some privacy modes and throws on access, so
77
+ * every read/write here is best-effort. Failing to read is treated as "we have
78
+ * not reloaded yet" — one extra reload is better than a permanently broken page.
79
+ */
80
+ export const hasRecentlyReloadedForChunkLoadError: HasRecentlyReloadedFunction =
81
+ (now: number): boolean => {
82
+ try {
83
+ const lastReloadedAt: string | null = window.sessionStorage.getItem(
84
+ CHUNK_LOAD_RELOAD_STORAGE_KEY,
85
+ );
86
+
87
+ if (!lastReloadedAt) {
88
+ return false;
89
+ }
90
+
91
+ const lastReloadedAtInMs: number = Number(lastReloadedAt);
92
+
93
+ if (!Number.isFinite(lastReloadedAtInMs)) {
94
+ return false;
95
+ }
96
+
97
+ return now - lastReloadedAtInMs < CHUNK_LOAD_RELOAD_COOLDOWN_IN_MS;
98
+ } catch {
99
+ return false;
100
+ }
101
+ };
102
+
103
+ export type MarkChunkLoadErrorReloadFunction = (now: number) => void;
104
+
105
+ export const markChunkLoadErrorReload: MarkChunkLoadErrorReloadFunction = (
106
+ now: number,
107
+ ): void => {
108
+ try {
109
+ window.sessionStorage.setItem(
110
+ CHUNK_LOAD_RELOAD_STORAGE_KEY,
111
+ now.toString(),
112
+ );
113
+ } catch {
114
+ // Storage is unavailable. The reload still happens, it just is not rate limited.
115
+ }
116
+ };
117
+
118
+ export type ReloadPageFunction = () => void;
119
+
120
+ export const reloadPage: ReloadPageFunction = (): void => {
121
+ window.location.reload();
122
+ };
123
+
124
+ /**
125
+ * Recover from a stale-bundle error by reloading once. Returns true when a
126
+ * reload was triggered, so the caller knows the fallback is only transient.
127
+ */
128
+ export type HandleChunkLoadErrorFunction = (error: unknown) => boolean;
129
+
130
+ export const handleChunkLoadError: HandleChunkLoadErrorFunction = (
131
+ error: unknown,
132
+ ): boolean => {
133
+ if (!isChunkLoadError(error)) {
134
+ return false;
135
+ }
136
+
137
+ const now: number = Date.now();
138
+
139
+ if (hasRecentlyReloadedForChunkLoadError(now)) {
140
+ return false;
141
+ }
142
+
143
+ markChunkLoadErrorReload(now);
144
+ reloadPage();
145
+
146
+ return true;
147
+ };
148
+
149
+ export const Fallback: FunctionComponent<FallbackProps> = (
150
+ props: FallbackProps,
151
+ ): ReactElement => {
152
+ const errorMessage: string =
153
+ props.error && typeof props.error.message === "string"
154
+ ? props.error.message
155
+ : "";
156
+
9
157
  return (
10
158
  <div
11
- id="app-loading"
159
+ role="alert"
160
+ data-testid="error-boundary-fallback"
12
161
  style={{
13
- position: "fixed",
14
- top: "0",
15
- bottom: "0",
16
- left: "0",
17
- right: "0",
162
+ minHeight: "60vh",
163
+ width: "100%",
164
+ padding: "2rem",
18
165
  backgroundColor: "var(--ou-background-primary, #fdfdfd)",
19
166
  color: "var(--ou-text-primary, #111827)",
20
- zIndex: "999",
21
167
  display: "flex",
22
168
  justifyContent: "center",
23
169
  alignItems: "center",
170
+ textAlign: "center",
24
171
  }}
25
172
  >
26
- <div>
27
- An unexpected error has occurred. Please reload the page to continue
173
+ <div style={{ maxWidth: "32rem" }}>
174
+ <div style={{ fontWeight: 600, marginBottom: "0.5rem" }}>
175
+ An unexpected error has occurred. Please reload the page to continue
176
+ </div>
177
+ <div
178
+ style={{
179
+ fontSize: "0.875rem",
180
+ color: "var(--ou-text-secondary, #6b7280)",
181
+ marginBottom: "1.25rem",
182
+ }}
183
+ >
184
+ The rest of the app is still working. You can retry this page or
185
+ reload to start fresh.
186
+ </div>
187
+ <div
188
+ style={{
189
+ display: "flex",
190
+ gap: "0.75rem",
191
+ justifyContent: "center",
192
+ }}
193
+ >
194
+ <button
195
+ type="button"
196
+ data-testid="error-boundary-try-again"
197
+ onClick={() => {
198
+ props.resetErrorBoundary();
199
+ }}
200
+ style={{
201
+ padding: "0.5rem 1rem",
202
+ borderRadius: "0.375rem",
203
+ border: "1px solid var(--ou-border-primary, #d1d5db)",
204
+ backgroundColor: "transparent",
205
+ color: "inherit",
206
+ cursor: "pointer",
207
+ }}
208
+ >
209
+ Try again
210
+ </button>
211
+ <button
212
+ type="button"
213
+ data-testid="error-boundary-reload"
214
+ onClick={() => {
215
+ reloadPage();
216
+ }}
217
+ style={{
218
+ padding: "0.5rem 1rem",
219
+ borderRadius: "0.375rem",
220
+ border: "1px solid transparent",
221
+ backgroundColor: "var(--ou-brand-primary, #4f46e5)",
222
+ color: "#ffffff",
223
+ cursor: "pointer",
224
+ }}
225
+ >
226
+ Reload page
227
+ </button>
228
+ </div>
229
+ {errorMessage ? (
230
+ <div
231
+ data-testid="error-boundary-error-message"
232
+ style={{
233
+ marginTop: "1.25rem",
234
+ fontSize: "0.75rem",
235
+ color: "var(--ou-text-secondary, #6b7280)",
236
+ wordBreak: "break-word",
237
+ }}
238
+ >
239
+ {errorMessage}
240
+ </div>
241
+ ) : (
242
+ <></>
243
+ )}
28
244
  </div>
29
245
  </div>
30
246
  );
@@ -32,9 +248,30 @@ const Fallback: FunctionComponent = () => {
32
248
 
33
249
  const ErrorBoundary: FunctionComponent<ComponentProps> = (
34
250
  props: ComponentProps,
35
- ) => {
251
+ ): ReactElement => {
252
+ type OnErrorFunction = (error: Error) => void;
253
+
254
+ const onError: OnErrorFunction = (error: Error): void => {
255
+ /*
256
+ * Surface the error. Without this the only trace of a crash is the blank
257
+ * screen itself, because the boundary swallows what React would otherwise
258
+ * rethrow to window.onerror (and therefore to RUM).
259
+ */
260
+ // eslint-disable-next-line no-console
261
+ console.error("Uncaught error rendering the app:", error);
262
+
263
+ // A stale bundle recovers by reloading, so do that instead of blaming the user.
264
+ handleChunkLoadError(error);
265
+
266
+ props.onError?.(error);
267
+ };
268
+
36
269
  return (
37
- <NativeErrorBoundary FallbackComponent={Fallback}>
270
+ <NativeErrorBoundary
271
+ FallbackComponent={Fallback}
272
+ onError={onError}
273
+ resetKeys={[props.resetKey]}
274
+ >
38
275
  {props.children}
39
276
  </NativeErrorBoundary>
40
277
  );
@@ -7,15 +7,72 @@ export interface ComponentProps {
7
7
  className?: string;
8
8
  textClassName?: string;
9
9
  onClick?: (() => void) | undefined;
10
+ /*
11
+ * Only meaningful alongside `onClick`: renders the card as a pressed toggle
12
+ * — outlined, and announced as such. Used by summary strips where clicking a
13
+ * tile narrows the table below it, so the tile has to show which subset the
14
+ * user is looking at.
15
+ *
16
+ * Leave it undefined on a card that navigates instead of toggling. Most
17
+ * clickable InfoCards in the product are one-way links, and announcing one
18
+ * as an unpressed toggle promises a state that activating it never produces.
19
+ */
20
+ isSelected?: boolean | undefined;
21
+ // Announced in place of the title when the card is clickable.
22
+ ariaLabel?: string | undefined;
10
23
  }
11
24
 
12
25
  const InfoCard: FunctionComponent<ComponentProps> = (
13
26
  props: ComponentProps,
14
27
  ): ReactElement => {
28
+ const isClickable: boolean = Boolean(props.onClick);
29
+
30
+ /*
31
+ * A selected card swaps its border rather than adding one: Tailwind emits
32
+ * both border-color utilities at the same specificity, so stacking them
33
+ * leaves the winner up to stylesheet order.
34
+ */
35
+ const borderClassName: string =
36
+ isClickable && props.isSelected
37
+ ? "border-indigo-500 ring-1 ring-indigo-500"
38
+ : "border-gray-200";
39
+
15
40
  return (
16
41
  <div
17
42
  onClick={props.onClick}
18
- className={`rounded-xl bg-white border border-gray-200 shadow-sm hover:shadow-md transition-shadow duration-200 p-5 ${props.onClick ? "cursor-pointer" : ""} ${props.className || ""}`}
43
+ /*
44
+ * Click handlers on a div are invisible to the keyboard and to screen
45
+ * readers. Everything below turns a clickable card into a real toggle
46
+ * button; a card with no handler is left as the plain container it is.
47
+ */
48
+ role={isClickable ? "button" : undefined}
49
+ tabIndex={isClickable ? 0 : undefined}
50
+ /*
51
+ * Gated on the prop being supplied, not merely on clickability: the
52
+ * cards that were already clickable before toggles existed (the Home
53
+ * overview stats, the Kubernetes and Proxmox summaries) all navigate,
54
+ * and `aria-pressed="false"` would announce each of them as a toggle
55
+ * that is currently off — a state activating it never reaches.
56
+ */
57
+ aria-pressed={
58
+ isClickable && props.isSelected !== undefined
59
+ ? Boolean(props.isSelected)
60
+ : undefined
61
+ }
62
+ aria-label={isClickable ? props.ariaLabel : undefined}
63
+ onKeyDown={
64
+ isClickable
65
+ ? (event: React.KeyboardEvent<HTMLDivElement>) => {
66
+ if (event.key !== "Enter" && event.key !== " ") {
67
+ return;
68
+ }
69
+ // Space scrolls the page unless the default is taken away.
70
+ event.preventDefault();
71
+ props.onClick?.();
72
+ }
73
+ : undefined
74
+ }
75
+ className={`rounded-xl bg-white border ${borderClassName} shadow-sm hover:shadow-md transition-shadow duration-200 p-5 ${isClickable ? "cursor-pointer focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2" : ""} ${props.className || ""}`}
19
76
  >
20
77
  <div className="mb-2">
21
78
  <FieldLabelElement title={props.title} />
@@ -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 LogTimeRangePickerProps {
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 LOG_TIME_RANGE_DROPDOWN_WIDTH_IN_PX: number = 288;
30
+
23
31
  // Preset options to show in the dropdown (ordered for log investigation use)
24
32
  const PRESET_OPTIONS: Array<{ range: TimeRange; label: string }> = [
25
33
  { range: TimeRange.PAST_FIVE_MINS, label: "Past 5 Minutes" },
@@ -68,6 +76,20 @@ const LogTimeRangePicker: FunctionComponent<LogTimeRangePickerProps> = (
68
76
  const containerRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
69
77
  null!,
70
78
  );
79
+ const buttonRef: React.RefObject<HTMLButtonElement> =
80
+ useRef<HTMLButtonElement>(null!);
81
+ const dropdownRef: React.RefObject<HTMLDivElement> = useRef<HTMLDivElement>(
82
+ null!,
83
+ );
84
+
85
+ const alignment: DropdownHorizontalAlignment = useDropdownHorizontalAlignment(
86
+ {
87
+ isOpen: isOpen,
88
+ anchorRef: buttonRef,
89
+ dropdownRef: dropdownRef,
90
+ dropdownWidthInPx: LOG_TIME_RANGE_DROPDOWN_WIDTH_IN_PX,
91
+ },
92
+ );
71
93
 
72
94
  // Close on click outside
73
95
  useEffect(() => {
@@ -120,7 +142,11 @@ const LogTimeRangePicker: FunctionComponent<LogTimeRangePickerProps> = (
120
142
  return (
121
143
  <div ref={containerRef} className="relative">
122
144
  <button
145
+ ref={buttonRef}
123
146
  type="button"
147
+ data-testid="log-time-range-picker-button"
148
+ aria-haspopup="true"
149
+ aria-expanded={isOpen}
124
150
  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 ${
125
151
  isOpen
126
152
  ? "border-indigo-300 bg-indigo-50 text-indigo-700"
@@ -139,7 +165,14 @@ const LogTimeRangePicker: FunctionComponent<LogTimeRangePickerProps> = (
139
165
  </button>
140
166
 
141
167
  {isOpen && (
142
- <div className="absolute right-0 top-full z-50 mt-1 w-72 rounded-lg border border-gray-200 bg-white shadow-lg">
168
+ <div
169
+ ref={dropdownRef}
170
+ data-testid="log-time-range-picker-dropdown"
171
+ data-align={alignment}
172
+ className={`absolute ${getDropdownAlignmentClassName(
173
+ alignment,
174
+ )} top-full z-50 mt-1 w-72 max-w-[calc(100vw-1rem)] rounded-lg border border-gray-200 bg-white shadow-lg`}
175
+ >
143
176
  {/* Preset options */}
144
177
  <div className="max-h-64 overflow-y-auto py-1">
145
178
  {PRESET_OPTIONS.map(
@@ -27,6 +27,70 @@ const MasterPage: FunctionComponent<ComponentProps> = (
27
27
  props: ComponentProps,
28
28
  ): ReactElement => {
29
29
  const [isOnline, setIsOnline] = React.useState(true);
30
+ const topSectionRef: React.RefObject<HTMLDivElement> =
31
+ React.useRef<HTMLDivElement>(null);
32
+
33
+ /*
34
+ * Publish the sticky top section's height as --app-header-height so anything
35
+ * that sticks underneath it (the side menu, for example) can offset itself by
36
+ * the real header instead of guessing and ending up tucked behind it. The
37
+ * height is not a constant — it changes when the navbar is hidden, when the
38
+ * header wraps on narrow viewports and when top alerts appear — so keep it in
39
+ * sync rather than measuring once.
40
+ */
41
+ React.useLayoutEffect(() => {
42
+ const setHeaderHeight: (height: number) => void = (
43
+ height: number,
44
+ ): void => {
45
+ document.documentElement.style.setProperty(
46
+ "--app-header-height",
47
+ `${height}px`,
48
+ );
49
+ };
50
+
51
+ const element: HTMLDivElement | null = topSectionRef.current;
52
+
53
+ if (!element || props.makeTopSectionUnstick) {
54
+ // Nothing is overlaying the content, so no offset is needed.
55
+ setHeaderHeight(0);
56
+ return undefined;
57
+ }
58
+
59
+ const measure: () => void = (): void => {
60
+ setHeaderHeight(element.offsetHeight);
61
+ };
62
+
63
+ measure();
64
+
65
+ /*
66
+ * ResizeObserver is missing in jsdom and in older browsers, so fall back to
67
+ * resize events there — less precise, but the header only really changes
68
+ * height when the viewport does.
69
+ */
70
+ if (typeof ResizeObserver === "undefined") {
71
+ window.addEventListener("resize", measure);
72
+
73
+ return () => {
74
+ window.removeEventListener("resize", measure);
75
+ document.documentElement.style.removeProperty("--app-header-height");
76
+ };
77
+ }
78
+
79
+ const observer: ResizeObserver = new ResizeObserver(measure);
80
+ observer.observe(element);
81
+
82
+ return () => {
83
+ observer.disconnect();
84
+ document.documentElement.style.removeProperty("--app-header-height");
85
+ };
86
+ }, [
87
+ props.makeTopSectionUnstick,
88
+ props.hideHeader,
89
+ props.isLoading,
90
+ props.error,
91
+ props.disableMainContentWrapper,
92
+ isOnline,
93
+ ]);
30
94
 
31
95
  if (props.isLoading) {
32
96
  return (
@@ -62,6 +126,7 @@ const MasterPage: FunctionComponent<ComponentProps> = (
62
126
  </a>
63
127
  )}
64
128
  <div
129
+ ref={topSectionRef}
65
130
  className={props.makeTopSectionUnstick ? "" : "sticky top-0 z-10"}
66
131
  >
67
132
  <TopSection
@@ -1,6 +1,6 @@
1
1
  import { ButtonStyleType } from "../Button/Button";
2
2
  import ButtonType from "../Button/ButtonTypes";
3
- import Icon, { IconType, SizeProp, ThickProp } from "../Icon/Icon";
3
+ import Icon from "../Icon/Icon";
4
4
  import Loader, { LoaderType } from "../Loader/Loader";
5
5
  import ModalBody from "./ModalBody";
6
6
  import ModalFooter from "./ModalFooter";
@@ -35,8 +35,6 @@ export interface ComponentProps {
35
35
  disableSubmitButton?: undefined | boolean;
36
36
  error?: string | undefined;
37
37
  isBodyLoading?: boolean | undefined;
38
- icon?: IconProp | undefined;
39
- iconType?: IconType | undefined;
40
38
  modalWidth?: ModalWidth | undefined;
41
39
  rightElement?: ReactElement | undefined;
42
40
  closeButtonText?: string | undefined;
@@ -172,28 +170,6 @@ const Modal: FunctionComponent<ComponentProps> = (
172
170
  };
173
171
  }, []);
174
172
 
175
- let iconBgColor: string = "bg-indigo-50";
176
- let iconColor: string = "text-indigo-600";
177
- let iconRingColor: string = "ring-indigo-100";
178
-
179
- if (props.iconType === IconType.Info) {
180
- iconBgColor = "bg-indigo-50";
181
- iconColor = "text-indigo-600";
182
- iconRingColor = "ring-indigo-100";
183
- } else if (props.iconType === IconType.Warning) {
184
- iconBgColor = "bg-yellow-50";
185
- iconColor = "text-yellow-700";
186
- iconRingColor = "ring-yellow-100";
187
- } else if (props.iconType === IconType.Success) {
188
- iconBgColor = "bg-green-50";
189
- iconColor = "text-green-600";
190
- iconRingColor = "ring-green-100";
191
- } else if (props.iconType === IconType.Danger) {
192
- iconBgColor = "bg-red-50";
193
- iconColor = "text-red-600";
194
- iconRingColor = "ring-red-100";
195
- }
196
-
197
173
  let modalWidthClassName: string = "sm:max-w-lg md:max-w-lg";
198
174
 
199
175
  if (props.modalWidth === ModalWidth.Medium) {
@@ -224,46 +200,26 @@ const Modal: FunctionComponent<ComponentProps> = (
224
200
  >
225
201
  <div className="relative flex shrink-0 flex-col gap-4 rounded-t-2xl border-b border-gray-100 bg-white px-5 py-4 sm:flex-row sm:items-start sm:justify-between sm:gap-6 sm:rounded-t-xl sm:px-6">
226
202
  <div
227
- className={`flex min-w-0 flex-1 items-start gap-3 ${
203
+ className={`min-w-0 flex-1 ${
228
204
  props.onClose ? "pr-9 sm:pr-0" : ""
229
205
  }`}
230
206
  >
231
- {props.icon && (
232
- <div
233
- className={`flex h-9 w-9 flex-shrink-0 items-center justify-center rounded-lg ${iconBgColor} ring-1 ring-inset ${iconRingColor}`}
234
- data-testid="icon"
207
+ <h3
208
+ data-testid="modal-title"
209
+ className="text-base font-semibold leading-6 tracking-tight text-gray-900"
210
+ id={titleId}
211
+ >
212
+ {translatedTitle}
213
+ </h3>
214
+ {translatedDescription && (
215
+ <p
216
+ id={descriptionId}
217
+ data-testid="modal-description"
218
+ className="mt-0.5 text-sm leading-5 text-gray-500"
235
219
  >
236
- <Icon
237
- thick={ThickProp.Thick}
238
- type={
239
- props.iconType === undefined
240
- ? IconType.Info
241
- : props.iconType
242
- }
243
- className={`${iconColor} h-5 w-5`}
244
- icon={props.icon}
245
- size={SizeProp.Five}
246
- />
247
- </div>
220
+ {translatedDescription}
221
+ </p>
248
222
  )}
249
- <div className="min-w-0 flex-1">
250
- <h3
251
- data-testid="modal-title"
252
- className="text-base font-semibold leading-6 tracking-tight text-gray-900"
253
- id={titleId}
254
- >
255
- {translatedTitle}
256
- </h3>
257
- {translatedDescription && (
258
- <p
259
- id={descriptionId}
260
- data-testid="modal-description"
261
- className="mt-0.5 text-sm leading-5 text-gray-500"
262
- >
263
- {translatedDescription}
264
- </p>
265
- )}
266
- </div>
267
223
  </div>
268
224
  {props.rightElement && (
269
225
  <div
@@ -7,10 +7,8 @@ import ModelForm, {
7
7
  ComponentProps as ModelFormComponentProps,
8
8
  } from "../Forms/ModelForm";
9
9
  import FormValues from "../Forms/Types/FormValues";
10
- import { IconType } from "../Icon/Icon";
11
10
  import Modal, { ModalWidth } from "../Modal/Modal";
12
11
  import BaseModel from "../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
13
- import IconProp from "../../../Types/Icon/IconProp";
14
12
  import { JSONObject } from "../../../Types/JSON";
15
13
  import ObjectID from "../../../Types/ObjectID";
16
14
  import React, { MutableRefObject, ReactElement, useRef, useState } from "react";
@@ -33,12 +31,6 @@ export interface ComponentProps<TBaseModel extends BaseModel> {
33
31
  | ((item: TBaseModel, miscDataProps: JSONObject) => Promise<TBaseModel>)
34
32
  | undefined;
35
33
  footer?: ReactElement | undefined;
36
- /*
37
- * A header icon (rendered in a colored circle) to make the modal feel
38
- * purpose-built. Forwarded to the underlying <Modal> via the props spread.
39
- */
40
- icon?: IconProp | undefined;
41
- iconType?: IconType | undefined;
42
34
  formRef?: undefined | MutableRefObject<FormProps<FormValues<TBaseModel>>>;
43
35
  }
44
36