@oneuptime/common 12.0.4 → 12.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/Models/DatabaseModels/AIRun.ts +38 -1
  2. package/Models/DatabaseModels/AlertFeed.ts +30 -0
  3. package/Models/DatabaseModels/Dashboard.ts +28 -0
  4. package/Models/DatabaseModels/Incident.ts +2 -0
  5. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  6. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  7. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  8. package/Models/DatabaseModels/IncidentFeed.ts +30 -0
  9. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  10. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  11. package/Models/DatabaseModels/LogSavedView.ts +33 -0
  12. package/Models/DatabaseModels/Project.ts +231 -9
  13. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  14. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  15. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  16. package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +4 -4
  17. package/Models/DatabaseModels/StatusPage.ts +28 -0
  18. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  19. package/Server/API/AIAgentDataAPI.ts +44 -55
  20. package/Server/API/AIInvestigationAPI.ts +175 -17
  21. package/Server/API/DashboardAPI.ts +10 -10
  22. package/Server/API/StatusPageAPI.ts +38 -19
  23. package/Server/EnvironmentConfig.ts +16 -0
  24. package/Server/Infrastructure/ClickhouseConfig.ts +15 -1
  25. package/Server/Infrastructure/ClickhouseDatabase.ts +1 -1
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.ts +27 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.ts +89 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.ts +27 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.ts +40 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.ts +26 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  32. package/Server/Services/AIRunService.ts +78 -10
  33. package/Server/Services/AIService.ts +94 -22
  34. package/Server/Services/AlertFeedService.ts +5 -0
  35. package/Server/Services/AnalyticsDatabaseService.ts +29 -0
  36. package/Server/Services/DatabaseService.ts +43 -2
  37. package/Server/Services/IncidentFeedService.ts +5 -0
  38. package/Server/Services/LlmLogService.ts +46 -2
  39. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +6 -0
  40. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +4 -0
  41. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +8 -5
  42. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +90 -16
  43. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +2 -0
  44. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +2 -0
  45. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +223 -22
  46. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +25 -24
  47. package/Server/Utils/AI/SRE/ConfidenceSignal.ts +182 -71
  48. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +252 -43
  49. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +25 -24
  50. package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +47 -13
  51. package/Server/Utils/AI/SRE/InvestigationGrader.ts +9 -5
  52. package/Server/Utils/AI/SRE/InvestigationQueue.ts +141 -24
  53. package/Server/Utils/AI/SRE/InvestigationSubjectLock.ts +66 -0
  54. package/Server/Utils/AI/SRE/PostedRootCause.ts +94 -3
  55. package/Server/Utils/AI/SRE/README.md +1 -1
  56. package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +132 -10
  57. package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +24 -0
  58. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +29 -0
  59. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +56 -0
  60. package/Server/Utils/Monitor/MonitorMetricUtil.ts +46 -0
  61. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
  62. package/Server/Utils/PasswordHash.ts +28 -4
  63. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +251 -0
  64. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +747 -0
  65. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +480 -0
  66. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1184 -0
  67. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +500 -0
  68. package/Tests/App/Dashboard/PortMonitorCriteriaFilter.test.ts +93 -0
  69. package/Tests/App/StatusPage/PublicStatusPageAPIErrorHandling.test.ts +117 -0
  70. package/Tests/App/StatusPage/StatusPageModelAPIPolymorphism.test.ts +223 -0
  71. package/Tests/Models/DatabaseModels/PermissionCatalogueCoverage.test.ts +243 -0
  72. package/Tests/Server/API/AIAgentDataFixFromIncidentContext.test.ts +266 -0
  73. package/Tests/Server/API/AIInvestigationAPI.test.ts +594 -0
  74. package/Tests/Server/API/AIInvestigationCreateFixTask.test.ts +80 -0
  75. package/Tests/Server/API/DashboardMasterPasswordAPI.test.ts +172 -1
  76. package/Tests/Server/API/StatusPageMasterPasswordAPI.test.ts +335 -0
  77. package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +59 -5
  78. package/Tests/Server/Services/AIRunHumanVerdict.test.ts +127 -58
  79. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +396 -20
  80. package/Tests/Server/Services/AddMasterPasswordSaltMigration.test.ts +283 -0
  81. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +25 -1
  82. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +45 -35
  83. package/Tests/Server/Services/DatabaseServiceUpdateColumnsWithoutHooks.test.ts +54 -0
  84. package/Tests/Server/Services/FeedAIRunAssociation.test.ts +125 -0
  85. package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +418 -57
  86. package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +173 -14
  87. package/Tests/Server/Services/MasterPasswordScrypt.test.ts +567 -0
  88. package/Tests/Server/Services/SeparateIncidentAlertAiSettingsMigration.test.ts +194 -0
  89. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +37 -4
  90. package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +330 -29
  91. package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +25 -0
  92. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +293 -5
  93. package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +59 -1
  94. package/Tests/Server/Utils/AI/FixFromIncidentAutoTrigger.test.ts +342 -19
  95. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +214 -30
  96. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +2 -0
  97. package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +65 -17
  98. package/Tests/Server/Utils/AI/InvestigationQueueRemediationExecution.test.ts +3 -0
  99. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +313 -20
  100. package/Tests/Server/Utils/AI/PostedRootCause.test.ts +254 -0
  101. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +4 -0
  102. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +2 -0
  103. package/Tests/Server/Utils/AI/SubjectCodeFixRunDedupe.test.ts +44 -0
  104. package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +30 -0
  105. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +212 -0
  106. package/Tests/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.test.ts +401 -0
  107. package/Tests/Server/Utils/Monitor/MonitorMetricUtilPortTimings.test.ts +243 -0
  108. package/Tests/Server/Utils/PasswordHash.test.ts +30 -0
  109. package/Tests/Types/Dashboard/DashboardTemplates.test.ts +111 -0
  110. package/Tests/Types/Monitor/CephMetricCatalog.test.ts +104 -0
  111. package/Tests/Types/Monitor/CriteriaFilter.test.ts +4 -0
  112. package/Tests/Types/Monitor/DockerMetricCatalog.test.ts +109 -0
  113. package/Tests/Types/Monitor/DockerSwarmMetricCatalog.test.ts +118 -0
  114. package/Tests/Types/Monitor/HostMetricCatalog.test.ts +104 -0
  115. package/Tests/Types/Monitor/IotMetricCatalog.test.ts +104 -0
  116. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +118 -0
  117. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +42 -0
  118. package/Tests/Types/Monitor/MonitorStep.test.ts +38 -0
  119. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +75 -0
  120. package/Tests/Types/Monitor/PodmanMetricCatalog.test.ts +109 -0
  121. package/Tests/Types/Monitor/ProxmoxMetricCatalog.test.ts +107 -0
  122. package/Tests/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.test.ts +151 -0
  123. package/Tests/Types/Permission.test.ts +137 -0
  124. package/Tests/Types/Rum/SessionReplayMaskingMode.test.ts +101 -0
  125. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +5 -5
  126. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +3 -5
  127. package/Tests/UI/Components/ErrorBoundary.test.tsx +158 -0
  128. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +74 -0
  129. package/Tests/UI/Components/MoreMenu.test.tsx +756 -0
  130. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +62 -0
  131. package/Tests/UI/Monitor/PortMonitorView.test.tsx +237 -0
  132. package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +91 -0
  133. package/Tests/UI/Utils/DownloadFile.test.ts +103 -0
  134. package/Tests/UI/Utils/ErrorSupportBundle.test.ts +582 -0
  135. package/Tests/UI/Utils/Project.test.ts +31 -0
  136. package/Tests/UI/Utils/StatusPageModelAPIInjection.test.ts +245 -0
  137. package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +820 -0
  138. package/Tests/Utils/Dashboard/DashboardViewConfig.test.ts +329 -0
  139. package/Tests/Utils/Dashboard/GridLayout.test.ts +951 -0
  140. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +117 -0
  141. package/Tests/Utils/RecordingRuleExpression.test.ts +327 -0
  142. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +186 -0
  143. package/Tests/Utils/StatusPage/GroupTree.test.ts +456 -0
  144. package/Tests/Utils/StatusPage/OverviewGroupHierarchyVisibility.test.ts +588 -0
  145. package/Tests/Utils/Telemetry/SavedViewTimeRange.test.ts +244 -0
  146. package/Tests/Utils/Telemetry/TelemetryQueryTimeRange.test.ts +825 -0
  147. package/Types/AI/AIRunCodeFixRecommendation.ts +17 -0
  148. package/Types/AI/CodeFixTaskContext.ts +63 -3
  149. package/Types/AI/CodeFixTaskType.ts +3 -3
  150. package/Types/HashedString.ts +4 -3
  151. package/Types/Monitor/CriteriaFilter.ts +4 -0
  152. package/Types/Monitor/DomainMonitor/DomainLookupMethod.ts +23 -0
  153. package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +7 -0
  154. package/Types/Monitor/MonitorCriteriaInstance.ts +24 -7
  155. package/Types/Monitor/MonitorMetricType.ts +8 -0
  156. package/Types/Monitor/MonitorStep.ts +10 -1
  157. package/Types/Monitor/MonitorStepDomainMonitor.ts +21 -0
  158. package/Types/Monitor/PortMonitor/PortMonitorTimings.ts +10 -0
  159. package/Types/Permission.ts +23 -175
  160. package/Types/Probe/ProbeMonitorResponse.ts +6 -0
  161. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +2 -3
  162. package/UI/Components/ErrorBoundary.tsx +138 -11
  163. package/UI/Components/Feed/FeedItem.tsx +9 -2
  164. package/UI/Components/ModelDetail/CardModelDetail.tsx +0 -12
  165. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  166. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +12 -2
  167. package/UI/Components/MoreMenu/MoreMenu.tsx +285 -97
  168. package/UI/Components/MoreMenu/MoreMenuItem.tsx +8 -5
  169. package/UI/Utils/DownloadFile.ts +16 -8
  170. package/UI/Utils/ErrorSupportBundle.ts +805 -0
  171. package/UI/Utils/ModelAPI/ModelAPI.ts +19 -8
  172. package/UI/Utils/Project.ts +4 -0
  173. package/UI/Utils/StatusPage.ts +8 -2
  174. package/UI/Utils/UseDashboardGridDnd.ts +917 -0
  175. package/Utils/Dashboard/DashboardViewConfig.ts +80 -36
  176. package/Utils/Dashboard/GridLayout.ts +523 -0
  177. package/Utils/Metrics/RecordingRuleExpression.ts +19 -17
  178. package/Utils/Monitor/MonitorMetricType.ts +44 -2
  179. package/Utils/StatusPage/GroupNestingLayout.ts +69 -0
  180. package/Utils/StatusPage/GroupTree.ts +157 -66
  181. package/Utils/StatusPage/ResourceUptime.ts +37 -2
  182. package/Utils/Telemetry/SavedViewTimeRange.ts +114 -0
  183. package/Utils/Telemetry/TelemetryQueryTimeRange.ts +334 -0
  184. package/build/dist/Models/DatabaseModels/AIRun.js +39 -1
  185. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/AlertFeed.js +32 -0
  187. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/Dashboard.js +29 -0
  189. package/build/dist/Models/DatabaseModels/Dashboard.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  191. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  193. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  195. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  196. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  197. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/IncidentFeed.js +32 -0
  199. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  201. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  203. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/LogSavedView.js +33 -0
  205. package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/Project.js +241 -11
  207. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  209. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  211. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  212. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  213. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  214. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +4 -4
  215. package/build/dist/Models/DatabaseModels/StatusPage.js +29 -0
  216. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  218. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  219. package/build/dist/Server/API/AIAgentDataAPI.js +28 -46
  220. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  221. package/build/dist/Server/API/AIInvestigationAPI.js +111 -11
  222. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  223. package/build/dist/Server/API/DashboardAPI.js +8 -5
  224. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  225. package/build/dist/Server/API/StatusPageAPI.js +29 -11
  226. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  227. package/build/dist/Server/EnvironmentConfig.js +14 -0
  228. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  229. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +12 -1
  230. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  231. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +1 -1
  232. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
  233. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js +22 -0
  234. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js.map +1 -0
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js +36 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js.map +1 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js +18 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js.map +1 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js +19 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js.map +1 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js +19 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js.map +1 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  245. package/build/dist/Server/Services/AIRunService.js +58 -12
  246. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  247. package/build/dist/Server/Services/AIService.js +74 -21
  248. package/build/dist/Server/Services/AIService.js.map +1 -1
  249. package/build/dist/Server/Services/AlertFeedService.js +3 -0
  250. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  251. package/build/dist/Server/Services/AnalyticsDatabaseService.js +29 -1
  252. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  253. package/build/dist/Server/Services/DatabaseService.js +21 -2
  254. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  255. package/build/dist/Server/Services/IncidentFeedService.js +3 -0
  256. package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
  257. package/build/dist/Server/Services/LlmLogService.js +22 -1
  258. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  259. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  260. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  261. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +4 -0
  262. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
  263. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +8 -5
  264. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  265. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +63 -24
  266. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  267. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +2 -0
  268. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  269. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +2 -0
  270. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  271. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +156 -28
  272. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  273. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +21 -19
  274. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  275. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +128 -49
  276. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -1
  277. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +170 -31
  278. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -1
  279. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +21 -19
  280. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  281. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +33 -9
  282. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -1
  283. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +9 -5
  284. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -1
  285. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +121 -41
  286. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  287. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js +46 -0
  288. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js.map +1 -0
  289. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js +61 -14
  290. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js.map +1 -1
  291. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +79 -1
  292. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
  293. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +21 -0
  294. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
  295. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +20 -3
  296. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  297. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +43 -0
  298. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
  299. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  300. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  301. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
  302. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  303. package/build/dist/Server/Utils/PasswordHash.js +25 -4
  304. package/build/dist/Server/Utils/PasswordHash.js.map +1 -1
  305. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js +18 -0
  306. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js.map +1 -0
  307. package/build/dist/Types/AI/CodeFixTaskContext.js +23 -3
  308. package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
  309. package/build/dist/Types/AI/CodeFixTaskType.js +3 -3
  310. package/build/dist/Types/HashedString.js +4 -3
  311. package/build/dist/Types/HashedString.js.map +1 -1
  312. package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
  313. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  314. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js +24 -0
  315. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js.map +1 -0
  316. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +24 -7
  317. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  318. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  319. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  320. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  321. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  322. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +15 -0
  323. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
  324. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js +2 -0
  325. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js.map +1 -0
  326. package/build/dist/Types/Permission.js +23 -155
  327. package/build/dist/Types/Permission.js.map +1 -1
  328. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +2 -5
  329. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  330. package/build/dist/UI/Components/ErrorBoundary.js +67 -8
  331. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  332. package/build/dist/UI/Components/Feed/FeedItem.js +2 -2
  333. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  334. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +0 -12
  335. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  336. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  337. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  338. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +12 -2
  339. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  340. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +193 -65
  341. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  342. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +1 -1
  343. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  344. package/build/dist/UI/Utils/DownloadFile.js +15 -8
  345. package/build/dist/UI/Utils/DownloadFile.js.map +1 -1
  346. package/build/dist/UI/Utils/ErrorSupportBundle.js +476 -0
  347. package/build/dist/UI/Utils/ErrorSupportBundle.js.map +1 -0
  348. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -8
  349. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  350. package/build/dist/UI/Utils/Project.js +3 -0
  351. package/build/dist/UI/Utils/Project.js.map +1 -1
  352. package/build/dist/UI/Utils/StatusPage.js +4 -4
  353. package/build/dist/UI/Utils/StatusPage.js.map +1 -1
  354. package/build/dist/UI/Utils/UseDashboardGridDnd.js +551 -0
  355. package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -0
  356. package/build/dist/Utils/Dashboard/DashboardViewConfig.js +42 -26
  357. package/build/dist/Utils/Dashboard/DashboardViewConfig.js.map +1 -1
  358. package/build/dist/Utils/Dashboard/GridLayout.js +338 -0
  359. package/build/dist/Utils/Dashboard/GridLayout.js.map +1 -0
  360. package/build/dist/Utils/Metrics/RecordingRuleExpression.js +19 -17
  361. package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -1
  362. package/build/dist/Utils/Monitor/MonitorMetricType.js +38 -6
  363. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  364. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +46 -0
  365. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -1
  366. package/build/dist/Utils/StatusPage/GroupTree.js +79 -34
  367. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -1
  368. package/build/dist/Utils/StatusPage/ResourceUptime.js +22 -1
  369. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  370. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js +79 -0
  371. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js.map +1 -0
  372. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js +236 -0
  373. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js.map +1 -0
  374. package/package.json +1 -1
@@ -5,7 +5,6 @@ import React, {
5
5
  useEffect,
6
6
  useId,
7
7
  useImperativeHandle,
8
- useRef,
9
8
  useState,
10
9
  } from "react";
11
10
  import IconProp from "../../../Types/Icon/IconProp";
@@ -23,8 +22,18 @@ export interface ComponentProps {
23
22
  triggerClassName?: string | undefined;
24
23
  menuIcon?: IconProp | undefined;
25
24
  text?: string | undefined;
25
+ isDisabled?: boolean | undefined;
26
26
  }
27
27
 
28
+ const isMenuItemDisabled: (item: HTMLElement) => boolean = (
29
+ item: HTMLElement,
30
+ ): boolean => {
31
+ return (
32
+ item.getAttribute("aria-disabled") === "true" ||
33
+ (item instanceof HTMLButtonElement && item.disabled)
34
+ );
35
+ };
36
+
28
37
  const MoreMenu: React.ForwardRefExoticComponent<
29
38
  ComponentProps & React.RefAttributes<unknown>
30
39
  > = forwardRef(
@@ -32,11 +41,53 @@ const MoreMenu: React.ForwardRefExoticComponent<
32
41
  const uniqueId: string = useId();
33
42
  const menuId: string = `menu-${uniqueId}`;
34
43
  const buttonId: string = `menu-button-${uniqueId}`;
44
+ const customTrigger: ReactElement | undefined =
45
+ props.elementToBeShownInsteadOfButton;
46
+ const isNativeButtonTrigger: boolean = Boolean(
47
+ customTrigger && customTrigger.type === "button",
48
+ );
35
49
  const { ref, isComponentVisible, setIsComponentVisible } =
36
50
  useComponentOutsideClick(false);
37
51
  const [focusedIndex, setFocusedIndex] = useState<number>(-1);
38
- const menuItemRefs: React.MutableRefObject<(HTMLDivElement | null)[]> =
39
- useRef<(HTMLDivElement | null)[]>([]);
52
+
53
+ /*
54
+ * Menu sections and dividers are valid top-level children, so the list of
55
+ * keyboard targets cannot be derived from props.children. Read the actual
56
+ * rendered menuitem descendants instead; this also supports arbitrarily
57
+ * nested sections while skipping non-action content.
58
+ */
59
+ const getMenuItems: () => Array<HTMLElement> =
60
+ useCallback((): Array<HTMLElement> => {
61
+ const menuElement: HTMLElement | null =
62
+ ref.current as HTMLElement | null;
63
+
64
+ if (!menuElement) {
65
+ return [];
66
+ }
67
+
68
+ /*
69
+ * Some established callers pass their own button as a menu child
70
+ * (usually wrapped for spacing) instead of MoreMenuItem. Promote that
71
+ * existing interactive element to a menuitem so it remains reachable
72
+ * by roving focus and participates in delegated dismissal. Explicit
73
+ * menuitems and anything nested inside one are left untouched.
74
+ */
75
+ Array.from(
76
+ menuElement.querySelectorAll<HTMLElement>(
77
+ 'button, a[href], [role="button"]',
78
+ ),
79
+ ).forEach((item: HTMLElement) => {
80
+ if (!item.closest('[role="menuitem"]')) {
81
+ item.setAttribute("role", "menuitem");
82
+ }
83
+ });
84
+
85
+ return Array.from(
86
+ menuElement.querySelectorAll<HTMLElement>('[role="menuitem"]'),
87
+ ).filter((item: HTMLElement) => {
88
+ return !isMenuItemDisabled(item);
89
+ });
90
+ }, [ref]);
40
91
 
41
92
  useImperativeHandle(componentRef, () => {
42
93
  return {
@@ -64,19 +115,40 @@ const MoreMenu: React.ForwardRefExoticComponent<
64
115
  }, [isComponentVisible]);
65
116
 
66
117
  useEffect(() => {
67
- if (focusedIndex >= 0 && menuItemRefs.current[focusedIndex]) {
68
- menuItemRefs.current[focusedIndex]?.focus();
118
+ if (props.isDisabled && isComponentVisible) {
119
+ setIsComponentVisible(false);
69
120
  }
70
- }, [focusedIndex]);
121
+ }, [props.isDisabled, isComponentVisible, setIsComponentVisible]);
122
+
123
+ useEffect(() => {
124
+ const menuItems: Array<HTMLElement> = getMenuItems();
125
+
126
+ menuItems.forEach((item: HTMLElement, index: number) => {
127
+ item.tabIndex = index === focusedIndex ? 0 : -1;
128
+ });
129
+
130
+ if (focusedIndex >= 0 && menuItems.length > 0) {
131
+ const safeFocusedIndex: number = Math.min(
132
+ focusedIndex,
133
+ menuItems.length - 1,
134
+ );
135
+
136
+ if (safeFocusedIndex !== focusedIndex) {
137
+ setFocusedIndex(safeFocusedIndex);
138
+ } else {
139
+ menuItems[safeFocusedIndex]?.focus();
140
+ }
141
+ }
142
+ }, [focusedIndex, getMenuItems, isComponentVisible, props.children]);
71
143
 
72
144
  const restoreFocusToTrigger: () => void = useCallback((): void => {
73
145
  /*
74
- * Return focus to the trigger after the menu closes via Escape or item
75
- * selection (WAI-ARIA menu-button pattern). Deferred to the next frame so
76
- * the menu has unmounted, and only reclaimed if focus fell back to
77
- * <body> so we never steal focus that the activated item intentionally
78
- * moved elsewhere (e.g. into a dialog it opened). Not called on
79
- * outside-click dismissal, which should leave focus where the user clicked.
146
+ * Return focus after item selection (WAI-ARIA menu-button pattern).
147
+ * Deferred to the next frame so the menu has unmounted, and only reclaimed
148
+ * if focus fell back to <body> so we never steal focus that the activated
149
+ * item intentionally moved elsewhere (e.g. into a dialog it opened). Escape
150
+ * has a separate unconditional path below; outside-click dismissal leaves
151
+ * focus where the user clicked.
80
152
  */
81
153
  requestAnimationFrame(() => {
82
154
  const activeElement: Element | null = document.activeElement;
@@ -86,50 +158,174 @@ const MoreMenu: React.ForwardRefExoticComponent<
86
158
  });
87
159
  }, [buttonId]);
88
160
 
161
+ const focusTrigger: () => void = useCallback((): void => {
162
+ document.getElementById(buttonId)?.focus();
163
+ }, [buttonId]);
164
+
89
165
  const handleKeyDown: (event: React.KeyboardEvent) => void = useCallback(
90
166
  (event: React.KeyboardEvent): void => {
91
167
  if (!isComponentVisible) {
92
168
  return;
93
169
  }
94
170
 
95
- const itemCount: number = props.children.length;
171
+ if (event.key === "Escape") {
172
+ event.preventDefault();
173
+ setIsComponentVisible(false);
174
+ /*
175
+ * Escape always returns focus to the menu button. Do this immediately:
176
+ * a deferred callback can run before React unmounts the focused menu
177
+ * item and incorrectly decide that focus should be left alone.
178
+ */
179
+ focusTrigger();
180
+ return;
181
+ }
182
+
183
+ if (event.key === "Tab") {
184
+ setIsComponentVisible(false);
185
+ return;
186
+ }
187
+
188
+ const menuItems: Array<HTMLElement> = getMenuItems();
189
+ const itemCount: number = menuItems.length;
190
+
191
+ if (itemCount === 0) {
192
+ return;
193
+ }
194
+
195
+ const activeElement: Element | null = document.activeElement;
196
+ const activeIndex: number = menuItems.findIndex((item: HTMLElement) => {
197
+ return item === activeElement || item.contains(activeElement);
198
+ });
199
+ const currentIndex: number =
200
+ activeIndex >= 0
201
+ ? activeIndex
202
+ : focusedIndex >= 0 && focusedIndex < itemCount
203
+ ? focusedIndex
204
+ : 0;
205
+ const moveFocusToItem: (index: number) => void = (
206
+ index: number,
207
+ ): void => {
208
+ setFocusedIndex(index);
209
+ /*
210
+ * Move DOM focus in the same keyboard event as well as recording the
211
+ * roving index. React may batch consecutive keyboard events, so the
212
+ * next Enter/Space must target the newly selected item immediately.
213
+ */
214
+ menuItems[index]?.focus();
215
+ };
96
216
 
97
217
  switch (event.key) {
98
- case "Escape":
99
- event.preventDefault();
100
- setIsComponentVisible(false);
101
- restoreFocusToTrigger();
102
- break;
103
218
  case "ArrowDown":
104
219
  event.preventDefault();
105
- setFocusedIndex((prev: number) => {
106
- return (prev + 1) % itemCount;
107
- });
220
+ moveFocusToItem((currentIndex + 1) % itemCount);
108
221
  break;
109
222
  case "ArrowUp":
110
223
  event.preventDefault();
111
- setFocusedIndex((prev: number) => {
112
- return (prev - 1 + itemCount) % itemCount;
113
- });
224
+ moveFocusToItem((currentIndex - 1 + itemCount) % itemCount);
114
225
  break;
115
226
  case "Home":
116
227
  event.preventDefault();
117
- setFocusedIndex(0);
228
+ moveFocusToItem(0);
118
229
  break;
119
230
  case "End":
120
231
  event.preventDefault();
121
- setFocusedIndex(itemCount - 1);
232
+ moveFocusToItem(itemCount - 1);
122
233
  break;
234
+ case "Enter":
235
+ case " ": {
236
+ const eventTarget: EventTarget = event.target;
237
+ const menuItem: HTMLElement | undefined = menuItems.find(
238
+ (item: HTMLElement) => {
239
+ return (
240
+ eventTarget instanceof Node &&
241
+ (item === eventTarget || item.contains(eventTarget))
242
+ );
243
+ },
244
+ );
245
+
246
+ if (menuItem) {
247
+ /*
248
+ * Prevent the native button activation from adding a second
249
+ * click, then use the exact focused item as the activation
250
+ * target. Its own handler runs once and the delegated menu click
251
+ * below closes the menu.
252
+ */
253
+ event.preventDefault();
254
+ menuItem.click();
255
+ }
256
+ break;
257
+ }
123
258
  }
124
259
  },
125
260
  [
261
+ focusedIndex,
262
+ focusTrigger,
263
+ getMenuItems,
126
264
  isComponentVisible,
127
- props.children.length,
128
265
  setIsComponentVisible,
129
- restoreFocusToTrigger,
130
266
  ],
131
267
  );
132
268
 
269
+ const handleMenuClick: (event: React.MouseEvent<HTMLDivElement>) => void = (
270
+ event: React.MouseEvent<HTMLDivElement>,
271
+ ): void => {
272
+ const eventTarget: EventTarget = event.target;
273
+
274
+ if (!(eventTarget instanceof Element)) {
275
+ return;
276
+ }
277
+
278
+ const menuItem: Element | null = eventTarget.closest('[role="menuitem"]');
279
+
280
+ if (
281
+ menuItem instanceof HTMLElement &&
282
+ event.currentTarget.contains(menuItem) &&
283
+ !isMenuItemDisabled(menuItem) &&
284
+ isComponentVisible
285
+ ) {
286
+ setIsComponentVisible(false);
287
+ restoreFocusToTrigger();
288
+ }
289
+ };
290
+
291
+ const getNativeButtonTrigger: () => ReactElement | null =
292
+ (): ReactElement | null => {
293
+ if (!customTrigger || !isNativeButtonTrigger) {
294
+ return null;
295
+ }
296
+
297
+ const trigger: ReactElement<
298
+ React.ButtonHTMLAttributes<HTMLButtonElement>
299
+ > = customTrigger as ReactElement<
300
+ React.ButtonHTMLAttributes<HTMLButtonElement>
301
+ >;
302
+ const isTriggerDisabled: boolean = Boolean(
303
+ props.isDisabled || trigger.props.disabled,
304
+ );
305
+
306
+ return React.cloneElement(trigger, {
307
+ id: buttonId,
308
+ type: trigger.props.type || "button",
309
+ className: [trigger.props.className, props.triggerClassName]
310
+ .filter(Boolean)
311
+ .join(" "),
312
+ disabled: isTriggerDisabled,
313
+ "aria-disabled": isTriggerDisabled,
314
+ "aria-label":
315
+ trigger.props["aria-label"] || props.text || "More options",
316
+ "aria-haspopup": "menu",
317
+ "aria-expanded": isComponentVisible,
318
+ "aria-controls": isComponentVisible ? menuId : undefined,
319
+ onClick: (event: React.MouseEvent<HTMLButtonElement>): void => {
320
+ trigger.props.onClick?.(event);
321
+
322
+ if (!event.defaultPrevented && !isTriggerDisabled) {
323
+ setIsComponentVisible(!isDropdownVisible);
324
+ }
325
+ },
326
+ });
327
+ };
328
+
133
329
  return (
134
330
  <div
135
331
  className="relative inline-block text-left"
@@ -141,6 +337,7 @@ const MoreMenu: React.ForwardRefExoticComponent<
141
337
  icon={props.menuIcon || IconProp.More}
142
338
  title={props.text || ""}
143
339
  buttonStyle={ButtonStyleType.OUTLINE}
340
+ disabled={props.isDisabled}
144
341
  onClick={() => {
145
342
  setIsComponentVisible(!isDropdownVisible);
146
343
  }}
@@ -151,51 +348,65 @@ const MoreMenu: React.ForwardRefExoticComponent<
151
348
  />
152
349
  )}
153
350
 
154
- {props.elementToBeShownInsteadOfButton && (
155
- <div
156
- /*
157
- * The id lets the menu's aria-labelledby resolve and lets focus
158
- * return here on close. But the menu-button ARIA (haspopup/expanded/
159
- * label) is only applied when a caller opts in with triggerClassName
160
- * — callers that pass their own element (some already a real
161
- * <button>) keep a bare wrapper to avoid layering redundant button
162
- * semantics on top.
163
- */
164
- id={buttonId}
165
- className={props.triggerClassName}
166
- onClick={() => {
167
- setIsComponentVisible(!isDropdownVisible);
168
- }}
169
- role="button"
170
- tabIndex={0}
171
- aria-label={
172
- props.triggerClassName ? props.text || "More options" : undefined
173
- }
174
- aria-haspopup={props.triggerClassName ? "menu" : undefined}
175
- aria-expanded={
176
- props.triggerClassName ? isComponentVisible : undefined
177
- }
178
- aria-controls={
179
- props.triggerClassName && isComponentVisible ? menuId : undefined
180
- }
181
- onKeyDown={(e: React.KeyboardEvent) => {
351
+ {getNativeButtonTrigger()}
352
+
353
+ {props.elementToBeShownInsteadOfButton &&
354
+ !isNativeButtonTrigger &&
355
+ props.triggerClassName && (
356
+ <button
357
+ id={buttonId}
358
+ type="button"
359
+ className={props.triggerClassName}
360
+ disabled={props.isDisabled}
361
+ onClick={() => {
362
+ setIsComponentVisible(!isDropdownVisible);
363
+ }}
364
+ aria-label={props.text || "More options"}
365
+ aria-haspopup="menu"
366
+ aria-expanded={isComponentVisible}
367
+ aria-controls={isComponentVisible ? menuId : undefined}
368
+ >
369
+ {props.elementToBeShownInsteadOfButton}
370
+ </button>
371
+ )}
372
+
373
+ {props.elementToBeShownInsteadOfButton &&
374
+ !isNativeButtonTrigger &&
375
+ !props.triggerClassName && (
376
+ <div
182
377
  /*
183
- * Only respond to the wrapper's own keys, never a focusable
184
- * child's (e.g. an input inside a custom trigger), so typing
185
- * isn't hijacked.
378
+ * Keep the legacy keyboard-operable wrapper for unstyled custom
379
+ * triggers. Many callers provide a visual <div>, not an interactive
380
+ * element, so dropping this role/tab stop would make their menu
381
+ * mouse-only. Styled custom triggers use the native button above.
186
382
  */
187
- if (
188
- (e.key === "Enter" || e.key === " ") &&
189
- e.target === e.currentTarget
190
- ) {
191
- e.preventDefault();
192
- setIsComponentVisible(!isDropdownVisible);
193
- }
194
- }}
195
- >
196
- {props.elementToBeShownInsteadOfButton}
197
- </div>
198
- )}
383
+ id={buttonId}
384
+ role="button"
385
+ tabIndex={props.isDisabled ? -1 : 0}
386
+ aria-label={props.text || undefined}
387
+ aria-haspopup="menu"
388
+ aria-expanded={isComponentVisible}
389
+ aria-controls={isComponentVisible ? menuId : undefined}
390
+ aria-disabled={Boolean(props.isDisabled)}
391
+ onClick={() => {
392
+ if (!props.isDisabled) {
393
+ setIsComponentVisible(!isDropdownVisible);
394
+ }
395
+ }}
396
+ onKeyDown={(event: React.KeyboardEvent<HTMLDivElement>) => {
397
+ if (
398
+ !props.isDisabled &&
399
+ event.target === event.currentTarget &&
400
+ (event.key === "Enter" || event.key === " ")
401
+ ) {
402
+ event.preventDefault();
403
+ setIsComponentVisible(!isDropdownVisible);
404
+ }
405
+ }}
406
+ >
407
+ {props.elementToBeShownInsteadOfButton}
408
+ </div>
409
+ )}
199
410
 
200
411
  {isComponentVisible && (
201
412
  <div
@@ -205,36 +416,13 @@ const MoreMenu: React.ForwardRefExoticComponent<
205
416
  role="menu"
206
417
  aria-orientation="vertical"
207
418
  aria-labelledby={buttonId}
419
+ onClick={handleMenuClick}
208
420
  >
209
421
  {props.children.map((child: ReactElement, index: number) => {
210
422
  return (
211
- <div
212
- key={index}
213
- ref={(el: HTMLDivElement | null) => {
214
- menuItemRefs.current[index] = el;
215
- }}
216
- role="menuitem"
217
- tabIndex={focusedIndex === index ? 0 : -1}
218
- onClick={() => {
219
- if (isComponentVisible) {
220
- setIsComponentVisible(false);
221
- restoreFocusToTrigger();
222
- }
223
- }}
224
- onKeyDown={(e: React.KeyboardEvent) => {
225
- if (e.key === "Enter" || e.key === " ") {
226
- e.preventDefault();
227
- setIsComponentVisible(false);
228
- // Trigger child click
229
- const clickEvent: MouseEvent = new MouseEvent("click", {
230
- bubbles: true,
231
- });
232
- e.currentTarget.dispatchEvent(clickEvent);
233
- }
234
- }}
235
- >
423
+ <React.Fragment key={child.key || index}>
236
424
  {child}
237
- </div>
425
+ </React.Fragment>
238
426
  );
239
427
  })}
240
428
  </div>
@@ -9,17 +9,20 @@ export interface ComponentProps {
9
9
  rightElement?: Array<ReactElement> | ReactElement | undefined;
10
10
  className?: string | undefined;
11
11
  iconClassName?: string | undefined;
12
- key: string | number;
12
+ isDisabled?: boolean | undefined;
13
13
  }
14
14
 
15
15
  const MoreMenuItem: FunctionComponent<ComponentProps> = (
16
16
  props: ComponentProps,
17
17
  ): ReactElement => {
18
18
  return (
19
- <a
20
- key={props.key || Math.random()}
21
- className={`cursor-pointer group flex items-center px-3 py-2 mx-1 rounded-md text-sm text-gray-700 hover:text-gray-900 hover:bg-indigo-50 transition-colors duration-100 ${props.className}`}
19
+ <button
20
+ type="button"
21
+ className={`group mx-1 flex items-center rounded-md px-3 py-2 text-left text-sm text-gray-700 transition-colors duration-100 enabled:cursor-pointer enabled:hover:bg-indigo-50 enabled:hover:text-gray-900 disabled:cursor-not-allowed disabled:opacity-50 ${props.className || ""}`}
22
22
  role="menuitem"
23
+ tabIndex={-1}
24
+ disabled={props.isDisabled}
25
+ aria-disabled={Boolean(props.isDisabled)}
23
26
  onClick={() => {
24
27
  props.onClick();
25
28
  }}
@@ -34,7 +37,7 @@ const MoreMenuItem: FunctionComponent<ComponentProps> = (
34
37
  <div className="font-medium">{props.text}</div>
35
38
  <div>{props.rightElement}</div>
36
39
  </div>
37
- </a>
40
+ </button>
38
41
  );
39
42
  };
40
43
 
@@ -18,14 +18,22 @@ export default function downloadFile(data: {
18
18
  });
19
19
 
20
20
  const url: string = window.URL.createObjectURL(blob);
21
- const anchor: HTMLAnchorElement = document.createElement("a");
22
- anchor.href = url;
23
- anchor.download = data.filename;
24
- anchor.rel = "noopener";
25
- document.body.appendChild(anchor);
26
- anchor.click();
27
- document.body.removeChild(anchor);
28
- window.URL.revokeObjectURL(url);
21
+ let anchor: HTMLAnchorElement | null = null;
22
+
23
+ try {
24
+ anchor = document.createElement("a");
25
+ anchor.href = url;
26
+ anchor.download = data.filename;
27
+ anchor.rel = "noopener";
28
+ document.body.appendChild(anchor);
29
+ anchor.click();
30
+ } finally {
31
+ if (anchor?.parentNode) {
32
+ anchor.parentNode.removeChild(anchor);
33
+ }
34
+
35
+ window.URL.revokeObjectURL(url);
36
+ }
29
37
  }
30
38
 
31
39
  /*