@oneuptime/common 12.0.4 → 12.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (374) hide show
  1. package/Models/DatabaseModels/AIRun.ts +38 -1
  2. package/Models/DatabaseModels/AlertFeed.ts +30 -0
  3. package/Models/DatabaseModels/Dashboard.ts +28 -0
  4. package/Models/DatabaseModels/Incident.ts +2 -0
  5. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  6. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  7. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  8. package/Models/DatabaseModels/IncidentFeed.ts +30 -0
  9. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  10. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  11. package/Models/DatabaseModels/LogSavedView.ts +33 -0
  12. package/Models/DatabaseModels/Project.ts +231 -9
  13. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  14. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  15. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  16. package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +4 -4
  17. package/Models/DatabaseModels/StatusPage.ts +28 -0
  18. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  19. package/Server/API/AIAgentDataAPI.ts +44 -55
  20. package/Server/API/AIInvestigationAPI.ts +175 -17
  21. package/Server/API/DashboardAPI.ts +10 -10
  22. package/Server/API/StatusPageAPI.ts +38 -19
  23. package/Server/EnvironmentConfig.ts +16 -0
  24. package/Server/Infrastructure/ClickhouseConfig.ts +15 -1
  25. package/Server/Infrastructure/ClickhouseDatabase.ts +1 -1
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.ts +27 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.ts +89 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.ts +27 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.ts +40 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.ts +26 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  32. package/Server/Services/AIRunService.ts +78 -10
  33. package/Server/Services/AIService.ts +94 -22
  34. package/Server/Services/AlertFeedService.ts +5 -0
  35. package/Server/Services/AnalyticsDatabaseService.ts +29 -0
  36. package/Server/Services/DatabaseService.ts +43 -2
  37. package/Server/Services/IncidentFeedService.ts +5 -0
  38. package/Server/Services/LlmLogService.ts +46 -2
  39. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +6 -0
  40. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +4 -0
  41. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +8 -5
  42. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +90 -16
  43. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +2 -0
  44. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +2 -0
  45. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +223 -22
  46. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +25 -24
  47. package/Server/Utils/AI/SRE/ConfidenceSignal.ts +182 -71
  48. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +252 -43
  49. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +25 -24
  50. package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +47 -13
  51. package/Server/Utils/AI/SRE/InvestigationGrader.ts +9 -5
  52. package/Server/Utils/AI/SRE/InvestigationQueue.ts +141 -24
  53. package/Server/Utils/AI/SRE/InvestigationSubjectLock.ts +66 -0
  54. package/Server/Utils/AI/SRE/PostedRootCause.ts +94 -3
  55. package/Server/Utils/AI/SRE/README.md +1 -1
  56. package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +132 -10
  57. package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +24 -0
  58. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +29 -0
  59. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +56 -0
  60. package/Server/Utils/Monitor/MonitorMetricUtil.ts +46 -0
  61. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
  62. package/Server/Utils/PasswordHash.ts +28 -4
  63. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +251 -0
  64. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +747 -0
  65. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +480 -0
  66. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1184 -0
  67. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +500 -0
  68. package/Tests/App/Dashboard/PortMonitorCriteriaFilter.test.ts +93 -0
  69. package/Tests/App/StatusPage/PublicStatusPageAPIErrorHandling.test.ts +117 -0
  70. package/Tests/App/StatusPage/StatusPageModelAPIPolymorphism.test.ts +223 -0
  71. package/Tests/Models/DatabaseModels/PermissionCatalogueCoverage.test.ts +243 -0
  72. package/Tests/Server/API/AIAgentDataFixFromIncidentContext.test.ts +266 -0
  73. package/Tests/Server/API/AIInvestigationAPI.test.ts +594 -0
  74. package/Tests/Server/API/AIInvestigationCreateFixTask.test.ts +80 -0
  75. package/Tests/Server/API/DashboardMasterPasswordAPI.test.ts +172 -1
  76. package/Tests/Server/API/StatusPageMasterPasswordAPI.test.ts +335 -0
  77. package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +59 -5
  78. package/Tests/Server/Services/AIRunHumanVerdict.test.ts +127 -58
  79. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +396 -20
  80. package/Tests/Server/Services/AddMasterPasswordSaltMigration.test.ts +283 -0
  81. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +25 -1
  82. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +45 -35
  83. package/Tests/Server/Services/DatabaseServiceUpdateColumnsWithoutHooks.test.ts +54 -0
  84. package/Tests/Server/Services/FeedAIRunAssociation.test.ts +125 -0
  85. package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +418 -57
  86. package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +173 -14
  87. package/Tests/Server/Services/MasterPasswordScrypt.test.ts +567 -0
  88. package/Tests/Server/Services/SeparateIncidentAlertAiSettingsMigration.test.ts +194 -0
  89. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +37 -4
  90. package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +330 -29
  91. package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +25 -0
  92. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +293 -5
  93. package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +59 -1
  94. package/Tests/Server/Utils/AI/FixFromIncidentAutoTrigger.test.ts +342 -19
  95. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +214 -30
  96. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +2 -0
  97. package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +65 -17
  98. package/Tests/Server/Utils/AI/InvestigationQueueRemediationExecution.test.ts +3 -0
  99. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +313 -20
  100. package/Tests/Server/Utils/AI/PostedRootCause.test.ts +254 -0
  101. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +4 -0
  102. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +2 -0
  103. package/Tests/Server/Utils/AI/SubjectCodeFixRunDedupe.test.ts +44 -0
  104. package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +30 -0
  105. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +212 -0
  106. package/Tests/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.test.ts +401 -0
  107. package/Tests/Server/Utils/Monitor/MonitorMetricUtilPortTimings.test.ts +243 -0
  108. package/Tests/Server/Utils/PasswordHash.test.ts +30 -0
  109. package/Tests/Types/Dashboard/DashboardTemplates.test.ts +111 -0
  110. package/Tests/Types/Monitor/CephMetricCatalog.test.ts +104 -0
  111. package/Tests/Types/Monitor/CriteriaFilter.test.ts +4 -0
  112. package/Tests/Types/Monitor/DockerMetricCatalog.test.ts +109 -0
  113. package/Tests/Types/Monitor/DockerSwarmMetricCatalog.test.ts +118 -0
  114. package/Tests/Types/Monitor/HostMetricCatalog.test.ts +104 -0
  115. package/Tests/Types/Monitor/IotMetricCatalog.test.ts +104 -0
  116. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +118 -0
  117. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +42 -0
  118. package/Tests/Types/Monitor/MonitorStep.test.ts +38 -0
  119. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +75 -0
  120. package/Tests/Types/Monitor/PodmanMetricCatalog.test.ts +109 -0
  121. package/Tests/Types/Monitor/ProxmoxMetricCatalog.test.ts +107 -0
  122. package/Tests/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.test.ts +151 -0
  123. package/Tests/Types/Permission.test.ts +137 -0
  124. package/Tests/Types/Rum/SessionReplayMaskingMode.test.ts +101 -0
  125. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +5 -5
  126. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +3 -5
  127. package/Tests/UI/Components/ErrorBoundary.test.tsx +158 -0
  128. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +74 -0
  129. package/Tests/UI/Components/MoreMenu.test.tsx +756 -0
  130. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +62 -0
  131. package/Tests/UI/Monitor/PortMonitorView.test.tsx +237 -0
  132. package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +91 -0
  133. package/Tests/UI/Utils/DownloadFile.test.ts +103 -0
  134. package/Tests/UI/Utils/ErrorSupportBundle.test.ts +582 -0
  135. package/Tests/UI/Utils/Project.test.ts +31 -0
  136. package/Tests/UI/Utils/StatusPageModelAPIInjection.test.ts +245 -0
  137. package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +820 -0
  138. package/Tests/Utils/Dashboard/DashboardViewConfig.test.ts +329 -0
  139. package/Tests/Utils/Dashboard/GridLayout.test.ts +951 -0
  140. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +117 -0
  141. package/Tests/Utils/RecordingRuleExpression.test.ts +327 -0
  142. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +186 -0
  143. package/Tests/Utils/StatusPage/GroupTree.test.ts +456 -0
  144. package/Tests/Utils/StatusPage/OverviewGroupHierarchyVisibility.test.ts +588 -0
  145. package/Tests/Utils/Telemetry/SavedViewTimeRange.test.ts +244 -0
  146. package/Tests/Utils/Telemetry/TelemetryQueryTimeRange.test.ts +825 -0
  147. package/Types/AI/AIRunCodeFixRecommendation.ts +17 -0
  148. package/Types/AI/CodeFixTaskContext.ts +63 -3
  149. package/Types/AI/CodeFixTaskType.ts +3 -3
  150. package/Types/HashedString.ts +4 -3
  151. package/Types/Monitor/CriteriaFilter.ts +4 -0
  152. package/Types/Monitor/DomainMonitor/DomainLookupMethod.ts +23 -0
  153. package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +7 -0
  154. package/Types/Monitor/MonitorCriteriaInstance.ts +24 -7
  155. package/Types/Monitor/MonitorMetricType.ts +8 -0
  156. package/Types/Monitor/MonitorStep.ts +10 -1
  157. package/Types/Monitor/MonitorStepDomainMonitor.ts +21 -0
  158. package/Types/Monitor/PortMonitor/PortMonitorTimings.ts +10 -0
  159. package/Types/Permission.ts +23 -175
  160. package/Types/Probe/ProbeMonitorResponse.ts +6 -0
  161. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +2 -3
  162. package/UI/Components/ErrorBoundary.tsx +138 -11
  163. package/UI/Components/Feed/FeedItem.tsx +9 -2
  164. package/UI/Components/ModelDetail/CardModelDetail.tsx +0 -12
  165. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  166. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +12 -2
  167. package/UI/Components/MoreMenu/MoreMenu.tsx +285 -97
  168. package/UI/Components/MoreMenu/MoreMenuItem.tsx +8 -5
  169. package/UI/Utils/DownloadFile.ts +16 -8
  170. package/UI/Utils/ErrorSupportBundle.ts +805 -0
  171. package/UI/Utils/ModelAPI/ModelAPI.ts +19 -8
  172. package/UI/Utils/Project.ts +4 -0
  173. package/UI/Utils/StatusPage.ts +8 -2
  174. package/UI/Utils/UseDashboardGridDnd.ts +917 -0
  175. package/Utils/Dashboard/DashboardViewConfig.ts +80 -36
  176. package/Utils/Dashboard/GridLayout.ts +523 -0
  177. package/Utils/Metrics/RecordingRuleExpression.ts +19 -17
  178. package/Utils/Monitor/MonitorMetricType.ts +44 -2
  179. package/Utils/StatusPage/GroupNestingLayout.ts +69 -0
  180. package/Utils/StatusPage/GroupTree.ts +157 -66
  181. package/Utils/StatusPage/ResourceUptime.ts +37 -2
  182. package/Utils/Telemetry/SavedViewTimeRange.ts +114 -0
  183. package/Utils/Telemetry/TelemetryQueryTimeRange.ts +334 -0
  184. package/build/dist/Models/DatabaseModels/AIRun.js +39 -1
  185. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/AlertFeed.js +32 -0
  187. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/Dashboard.js +29 -0
  189. package/build/dist/Models/DatabaseModels/Dashboard.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  191. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  193. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  195. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  196. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  197. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/IncidentFeed.js +32 -0
  199. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  201. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  203. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/LogSavedView.js +33 -0
  205. package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/Project.js +241 -11
  207. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  209. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  211. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  212. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  213. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  214. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +4 -4
  215. package/build/dist/Models/DatabaseModels/StatusPage.js +29 -0
  216. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  218. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  219. package/build/dist/Server/API/AIAgentDataAPI.js +28 -46
  220. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  221. package/build/dist/Server/API/AIInvestigationAPI.js +111 -11
  222. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  223. package/build/dist/Server/API/DashboardAPI.js +8 -5
  224. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  225. package/build/dist/Server/API/StatusPageAPI.js +29 -11
  226. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  227. package/build/dist/Server/EnvironmentConfig.js +14 -0
  228. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  229. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +12 -1
  230. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  231. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +1 -1
  232. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
  233. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js +22 -0
  234. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js.map +1 -0
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js +36 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js.map +1 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js +18 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js.map +1 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js +19 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js.map +1 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js +19 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js.map +1 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  245. package/build/dist/Server/Services/AIRunService.js +58 -12
  246. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  247. package/build/dist/Server/Services/AIService.js +74 -21
  248. package/build/dist/Server/Services/AIService.js.map +1 -1
  249. package/build/dist/Server/Services/AlertFeedService.js +3 -0
  250. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  251. package/build/dist/Server/Services/AnalyticsDatabaseService.js +29 -1
  252. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  253. package/build/dist/Server/Services/DatabaseService.js +21 -2
  254. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  255. package/build/dist/Server/Services/IncidentFeedService.js +3 -0
  256. package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
  257. package/build/dist/Server/Services/LlmLogService.js +22 -1
  258. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  259. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  260. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  261. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +4 -0
  262. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
  263. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +8 -5
  264. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  265. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +63 -24
  266. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  267. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +2 -0
  268. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  269. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +2 -0
  270. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  271. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +156 -28
  272. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  273. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +21 -19
  274. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  275. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +128 -49
  276. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -1
  277. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +170 -31
  278. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -1
  279. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +21 -19
  280. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  281. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +33 -9
  282. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -1
  283. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +9 -5
  284. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -1
  285. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +121 -41
  286. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  287. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js +46 -0
  288. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js.map +1 -0
  289. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js +61 -14
  290. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js.map +1 -1
  291. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +79 -1
  292. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
  293. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +21 -0
  294. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
  295. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +20 -3
  296. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  297. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +43 -0
  298. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
  299. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  300. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  301. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
  302. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  303. package/build/dist/Server/Utils/PasswordHash.js +25 -4
  304. package/build/dist/Server/Utils/PasswordHash.js.map +1 -1
  305. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js +18 -0
  306. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js.map +1 -0
  307. package/build/dist/Types/AI/CodeFixTaskContext.js +23 -3
  308. package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
  309. package/build/dist/Types/AI/CodeFixTaskType.js +3 -3
  310. package/build/dist/Types/HashedString.js +4 -3
  311. package/build/dist/Types/HashedString.js.map +1 -1
  312. package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
  313. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  314. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js +24 -0
  315. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js.map +1 -0
  316. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +24 -7
  317. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  318. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  319. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  320. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  321. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  322. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +15 -0
  323. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
  324. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js +2 -0
  325. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js.map +1 -0
  326. package/build/dist/Types/Permission.js +23 -155
  327. package/build/dist/Types/Permission.js.map +1 -1
  328. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +2 -5
  329. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  330. package/build/dist/UI/Components/ErrorBoundary.js +67 -8
  331. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  332. package/build/dist/UI/Components/Feed/FeedItem.js +2 -2
  333. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  334. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +0 -12
  335. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  336. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  337. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  338. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +12 -2
  339. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  340. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +193 -65
  341. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  342. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +1 -1
  343. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  344. package/build/dist/UI/Utils/DownloadFile.js +15 -8
  345. package/build/dist/UI/Utils/DownloadFile.js.map +1 -1
  346. package/build/dist/UI/Utils/ErrorSupportBundle.js +476 -0
  347. package/build/dist/UI/Utils/ErrorSupportBundle.js.map +1 -0
  348. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -8
  349. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  350. package/build/dist/UI/Utils/Project.js +3 -0
  351. package/build/dist/UI/Utils/Project.js.map +1 -1
  352. package/build/dist/UI/Utils/StatusPage.js +4 -4
  353. package/build/dist/UI/Utils/StatusPage.js.map +1 -1
  354. package/build/dist/UI/Utils/UseDashboardGridDnd.js +551 -0
  355. package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -0
  356. package/build/dist/Utils/Dashboard/DashboardViewConfig.js +42 -26
  357. package/build/dist/Utils/Dashboard/DashboardViewConfig.js.map +1 -1
  358. package/build/dist/Utils/Dashboard/GridLayout.js +338 -0
  359. package/build/dist/Utils/Dashboard/GridLayout.js.map +1 -0
  360. package/build/dist/Utils/Metrics/RecordingRuleExpression.js +19 -17
  361. package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -1
  362. package/build/dist/Utils/Monitor/MonitorMetricType.js +38 -6
  363. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  364. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +46 -0
  365. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -1
  366. package/build/dist/Utils/StatusPage/GroupTree.js +79 -34
  367. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -1
  368. package/build/dist/Utils/StatusPage/ResourceUptime.js +22 -1
  369. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  370. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js +79 -0
  371. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js.map +1 -0
  372. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js +236 -0
  373. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js.map +1 -0
  374. package/package.json +1 -1
@@ -0,0 +1,747 @@
1
+ import EventStatusPanel, {
2
+ ComponentProps,
3
+ EventStateAction,
4
+ EventStateItem,
5
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/EventView/EventStatusPanel";
6
+ import { ButtonStyleType } from "../../../UI/Components/Button/Button";
7
+ import "@testing-library/jest-dom";
8
+ import {
9
+ cleanup,
10
+ fireEvent,
11
+ render,
12
+ screen,
13
+ within,
14
+ } from "@testing-library/react";
15
+ import React from "react";
16
+ import { afterEach, describe, expect, jest, test } from "@jest/globals";
17
+ import getJestMockFunction, { MockFunction } from "../../MockType";
18
+ import { Black, Red500 } from "../../../Types/BrandColors";
19
+ import Color from "../../../Types/Color";
20
+ import IconProp from "../../../Types/Icon/IconProp";
21
+
22
+ jest.mock("react-i18next", () => {
23
+ return {
24
+ useTranslation: () => {
25
+ return {
26
+ t: (key: string, options?: { defaultValue?: string }): string => {
27
+ if (key === "Resolve translation key") {
28
+ return "Résoudre";
29
+ }
30
+
31
+ return options?.defaultValue ?? key;
32
+ },
33
+ };
34
+ },
35
+ };
36
+ });
37
+
38
+ /*
39
+ * Incident, alert, and scheduled-maintenance detail pages all render their
40
+ * state controls through EventStatusPanel. This suite deliberately exercises
41
+ * that shared component through a real JSDOM render: the visual hierarchy is
42
+ * only useful if the controls remain native buttons, the overflow exposes the
43
+ * states that are not already visible, and both layouts keep the same
44
+ * accessible action group.
45
+ */
46
+
47
+ const CREATED_COLOR: Color = new Color("#64748b");
48
+ const ACKNOWLEDGED_COLOR: Color = new Color("#f59e0b");
49
+ const INVESTIGATING_COLOR: Color = new Color("#0ea5e9");
50
+ const RESOLVED_COLOR: Color = new Color("#10b981");
51
+
52
+ type MakeStateFunction = (
53
+ id: string,
54
+ name: string,
55
+ color?: Color | undefined,
56
+ ) => EventStateItem;
57
+
58
+ const makeState: MakeStateFunction = (
59
+ id: string,
60
+ name: string,
61
+ color?: Color | undefined,
62
+ ): EventStateItem => {
63
+ return {
64
+ id: id,
65
+ name: name,
66
+ color: color || CREATED_COLOR,
67
+ };
68
+ };
69
+
70
+ type DefaultStatesFunction = () => Array<EventStateItem>;
71
+
72
+ const defaultStates: DefaultStatesFunction = (): Array<EventStateItem> => {
73
+ return [
74
+ makeState("created", "Created", CREATED_COLOR),
75
+ makeState("acknowledged", "Acknowledged", ACKNOWLEDGED_COLOR),
76
+ makeState("investigating", "Investigating", INVESTIGATING_COLOR),
77
+ makeState("resolved", "Resolved", RESOLVED_COLOR),
78
+ ];
79
+ };
80
+
81
+ type DefaultActionsFunction = () => Array<EventStateAction>;
82
+
83
+ const defaultActions: DefaultActionsFunction = (): Array<EventStateAction> => {
84
+ return [
85
+ {
86
+ stateId: "acknowledged",
87
+ label: "Acknowledge",
88
+ icon: IconProp.Check,
89
+ buttonStyle: ButtonStyleType.PRIMARY,
90
+ id: "incident-acknowledge-btn",
91
+ },
92
+ {
93
+ stateId: "resolved",
94
+ label: "Resolve",
95
+ icon: IconProp.CheckCircle,
96
+ buttonStyle: ButtonStyleType.DANGER,
97
+ id: "incident-resolve-btn",
98
+ },
99
+ ];
100
+ };
101
+
102
+ interface RenderedPanel {
103
+ actionClicks: Array<string>;
104
+ stateSelections: Array<string>;
105
+ }
106
+
107
+ type RenderPanelFunction = (
108
+ overrides?: Partial<ComponentProps> | undefined,
109
+ ) => RenderedPanel;
110
+
111
+ const renderPanel: RenderPanelFunction = (
112
+ overrides?: Partial<ComponentProps> | undefined,
113
+ ): RenderedPanel => {
114
+ const actionClicks: Array<string> = [];
115
+ const stateSelections: Array<string> = [];
116
+
117
+ const props: ComponentProps = {
118
+ states: defaultStates(),
119
+ identifier: "INC-42",
120
+ currentStateId: "created",
121
+ actions: defaultActions(),
122
+ onActionClick: (stateId: string): void => {
123
+ actionClicks.push(stateId);
124
+ },
125
+ onStateSelect: (stateId: string): void => {
126
+ stateSelections.push(stateId);
127
+ },
128
+ ...overrides,
129
+ };
130
+
131
+ render(<EventStatusPanel {...props} />);
132
+
133
+ return {
134
+ actionClicks: actionClicks,
135
+ stateSelections: stateSelections,
136
+ };
137
+ };
138
+
139
+ type GetActionGroupFunction = () => HTMLElement;
140
+
141
+ const getActionGroup: GetActionGroupFunction = (): HTMLElement => {
142
+ return screen.getByRole("group", { name: "Event actions" });
143
+ };
144
+
145
+ type GetMoreActionsTriggerFunction = () => HTMLElement;
146
+
147
+ const getMoreActionsTrigger: GetMoreActionsTriggerFunction =
148
+ (): HTMLElement => {
149
+ return screen.getByRole("button", { name: "More actions" });
150
+ };
151
+
152
+ type OpenMenuFunction = () => HTMLElement;
153
+
154
+ const openMenu: OpenMenuFunction = (): HTMLElement => {
155
+ fireEvent.click(getMoreActionsTrigger());
156
+ return screen.getByRole("menu");
157
+ };
158
+
159
+ type GetMenuChoicesFunction = (menu: HTMLElement) => Array<HTMLElement>;
160
+
161
+ /*
162
+ * MoreMenu historically wrapped a MoreMenuSection in one menuitem and put
163
+ * the actual choices beneath it. Taking only leaf menuitems lets this test
164
+ * describe the user-selectable states and remains valid if that redundant
165
+ * wrapper is later removed.
166
+ */
167
+ const getMenuChoices: GetMenuChoicesFunction = (
168
+ menu: HTMLElement,
169
+ ): Array<HTMLElement> => {
170
+ return Array.from(
171
+ menu.querySelectorAll<HTMLElement>('[role="menuitem"]'),
172
+ ).filter((element: HTMLElement) => {
173
+ return !element.querySelector('[role="menuitem"]');
174
+ });
175
+ };
176
+
177
+ type GetMenuChoiceFunction = (menu: HTMLElement, name: string) => HTMLElement;
178
+
179
+ const getMenuChoice: GetMenuChoiceFunction = (
180
+ menu: HTMLElement,
181
+ name: string,
182
+ ): HTMLElement => {
183
+ const choice: HTMLElement | undefined = getMenuChoices(menu).find(
184
+ (element: HTMLElement) => {
185
+ return element.textContent?.trim() === name;
186
+ },
187
+ );
188
+
189
+ if (!choice) {
190
+ throw new Error(`Menu choice "${name}" was not rendered.`);
191
+ }
192
+
193
+ return choice;
194
+ };
195
+
196
+ type MenuChoiceNamesFunction = (menu: HTMLElement) => Array<string>;
197
+
198
+ const menuChoiceNames: MenuChoiceNamesFunction = (
199
+ menu: HTMLElement,
200
+ ): Array<string> => {
201
+ return getMenuChoices(menu).map((element: HTMLElement) => {
202
+ return element.textContent?.trim() || "";
203
+ });
204
+ };
205
+
206
+ afterEach(() => {
207
+ cleanup();
208
+ });
209
+
210
+ describe("EventStatusPanel action buttons", () => {
211
+ test("renders actions as native, fixed-height buttons in caller order", () => {
212
+ renderPanel();
213
+
214
+ const group: HTMLElement = getActionGroup();
215
+ const acknowledge: HTMLElement = within(group).getByRole("button", {
216
+ name: "Acknowledge",
217
+ });
218
+ const resolve: HTMLElement = within(group).getByRole("button", {
219
+ name: "Resolve",
220
+ });
221
+ const more: HTMLElement = within(group).getByRole("button", {
222
+ name: "More actions",
223
+ });
224
+
225
+ expect(acknowledge.tagName).toBe("BUTTON");
226
+ expect(resolve.tagName).toBe("BUTTON");
227
+ expect(acknowledge).toHaveAttribute("type", "button");
228
+ expect(resolve).toHaveAttribute("type", "button");
229
+ expect(acknowledge).toHaveClass("h-9");
230
+ expect(resolve).toHaveClass("h-9");
231
+
232
+ const controls: Array<HTMLElement> = within(group).getAllByRole("button");
233
+ expect(controls).toEqual([acknowledge, resolve, more]);
234
+ });
235
+
236
+ test("translates action labels and keeps the full label available when truncated", () => {
237
+ renderPanel({
238
+ actions: [
239
+ {
240
+ stateId: "resolved",
241
+ label: "Resolve translation key",
242
+ buttonStyle: ButtonStyleType.PRIMARY,
243
+ },
244
+ ],
245
+ });
246
+
247
+ const translatedAction: HTMLElement = screen.getByRole("button", {
248
+ name: "Résoudre",
249
+ });
250
+
251
+ expect(translatedAction).toHaveAttribute("title", "Résoudre");
252
+ expect(
253
+ screen.queryByRole("button", { name: "Resolve translation key" }),
254
+ ).not.toBeInTheDocument();
255
+ });
256
+
257
+ test("preserves stable DOM ids and reports the clicked state id", () => {
258
+ const rendered: RenderedPanel = renderPanel();
259
+
260
+ const acknowledge: HTMLElement = screen.getByRole("button", {
261
+ name: "Acknowledge",
262
+ });
263
+ const resolve: HTMLElement = screen.getByRole("button", {
264
+ name: "Resolve",
265
+ });
266
+
267
+ expect(acknowledge).toHaveAttribute("id", "incident-acknowledge-btn");
268
+ expect(resolve).toHaveAttribute("id", "incident-resolve-btn");
269
+
270
+ fireEvent.click(acknowledge);
271
+ fireEvent.click(resolve);
272
+
273
+ expect(rendered.actionClicks).toEqual(["acknowledged", "resolved"]);
274
+ });
275
+
276
+ test("uses a solid indigo hierarchy for the primary action", () => {
277
+ renderPanel();
278
+
279
+ const acknowledge: HTMLElement = screen.getByRole("button", {
280
+ name: "Acknowledge",
281
+ });
282
+
283
+ expect(acknowledge).toHaveClass("bg-indigo-600", "text-white");
284
+ expect(acknowledge).not.toHaveClass("bg-white", "text-gray-700");
285
+ expect(acknowledge).not.toHaveAttribute("style");
286
+ expect(acknowledge.className).not.toContain("var(--btn");
287
+ });
288
+
289
+ test.each([ButtonStyleType.OUTLINE, ButtonStyleType.DANGER])(
290
+ "renders non-primary style %s as the same neutral outline hierarchy",
291
+ (buttonStyle: ButtonStyleType) => {
292
+ renderPanel({
293
+ actions: [
294
+ {
295
+ stateId: "resolved",
296
+ label: "Secondary action",
297
+ buttonStyle: buttonStyle,
298
+ },
299
+ ],
300
+ });
301
+
302
+ const button: HTMLElement = screen.getByRole("button", {
303
+ name: "Secondary action",
304
+ });
305
+
306
+ expect(button).toHaveClass(
307
+ "h-9",
308
+ "border-gray-300",
309
+ "bg-white",
310
+ "text-gray-700",
311
+ );
312
+ expect(button).not.toHaveClass(
313
+ "bg-indigo-600",
314
+ "bg-red-600",
315
+ "bg-green-600",
316
+ );
317
+ expect(button).not.toHaveAttribute("style");
318
+ },
319
+ );
320
+
321
+ test("renders the requested action icons and leaves iconless actions clean", () => {
322
+ renderPanel({
323
+ actions: [
324
+ ...defaultActions(),
325
+ {
326
+ stateId: "investigating",
327
+ label: "Escalate",
328
+ buttonStyle: ButtonStyleType.OUTLINE,
329
+ },
330
+ ],
331
+ });
332
+
333
+ const acknowledge: HTMLElement = screen.getByRole("button", {
334
+ name: "Acknowledge",
335
+ });
336
+ const resolve: HTMLElement = screen.getByRole("button", {
337
+ name: "Resolve",
338
+ });
339
+ const escalate: HTMLElement = screen.getByRole("button", {
340
+ name: "Escalate",
341
+ });
342
+
343
+ const acknowledgeIcon: SVGElement | null = acknowledge.querySelector("svg");
344
+ const resolveIcon: SVGElement | null = resolve.querySelector("svg");
345
+
346
+ expect(acknowledgeIcon).toHaveClass("h-4", "w-4");
347
+ expect(resolveIcon).toHaveClass("h-4", "w-4");
348
+ expect(acknowledgeIcon?.innerHTML).not.toEqual(resolveIcon?.innerHTML);
349
+ expect(escalate.querySelector("svg")).toBeNull();
350
+ });
351
+
352
+ test("uses the same native presentation when an action has no color", () => {
353
+ renderPanel({
354
+ actions: [
355
+ {
356
+ stateId: "acknowledged",
357
+ label: "Colorless primary",
358
+ buttonStyle: ButtonStyleType.PRIMARY,
359
+ },
360
+ {
361
+ stateId: "resolved",
362
+ label: "Colorless secondary",
363
+ buttonStyle: ButtonStyleType.OUTLINE,
364
+ },
365
+ ],
366
+ });
367
+
368
+ const primary: HTMLElement = screen.getByRole("button", {
369
+ name: "Colorless primary",
370
+ });
371
+ const secondary: HTMLElement = screen.getByRole("button", {
372
+ name: "Colorless secondary",
373
+ });
374
+
375
+ expect(primary.tagName).toBe("BUTTON");
376
+ expect(primary).toHaveClass("h-9", "bg-indigo-600", "text-white");
377
+ expect(secondary.tagName).toBe("BUTTON");
378
+ expect(secondary).toHaveClass(
379
+ "h-9",
380
+ "border-gray-300",
381
+ "bg-white",
382
+ "text-gray-700",
383
+ );
384
+ expect(primary).not.toHaveAttribute("style");
385
+ expect(secondary).not.toHaveAttribute("style");
386
+ });
387
+ });
388
+
389
+ describe("EventStatusPanel overflow states", () => {
390
+ test("excludes the current and visible-action states, preserves order, and deduplicates alternatives", () => {
391
+ renderPanel({
392
+ states: [
393
+ makeState("created", "Created"),
394
+ makeState("acknowledged", "Acknowledged"),
395
+ makeState("investigating", "Investigating"),
396
+ makeState("investigating", "Duplicate investigating"),
397
+ makeState("monitoring", "Monitoring"),
398
+ makeState("resolved", "Resolved"),
399
+ ],
400
+ currentStateId: "created",
401
+ });
402
+
403
+ const menu: HTMLElement = openMenu();
404
+
405
+ expect(menuChoiceNames(menu)).toEqual(["Investigating", "Monitoring"]);
406
+ expect(within(menu).queryByText("Created")).not.toBeInTheDocument();
407
+ expect(within(menu).queryByText("Acknowledged")).not.toBeInTheDocument();
408
+ expect(within(menu).queryByText("Resolved")).not.toBeInTheDocument();
409
+ expect(
410
+ within(menu).queryByText("Duplicate investigating"),
411
+ ).not.toBeInTheDocument();
412
+ });
413
+
414
+ test("reports the selected alternative state and closes the menu", () => {
415
+ const rendered: RenderedPanel = renderPanel();
416
+ const menu: HTMLElement = openMenu();
417
+
418
+ fireEvent.click(getMenuChoice(menu, "Investigating"));
419
+
420
+ expect(rendered.stateSelections).toEqual(["investigating"]);
421
+ expect(screen.queryByRole("menu")).not.toBeInTheDocument();
422
+ });
423
+
424
+ test("uses the supplied overflow section title", () => {
425
+ renderPanel({ moreMenuTitle: "Move incident to" });
426
+
427
+ const menu: HTMLElement = openMenu();
428
+
429
+ expect(within(menu).getByText("MOVE INCIDENT TO")).toBeInTheDocument();
430
+ });
431
+
432
+ test("does not render overflow without a selection callback", () => {
433
+ renderPanel({ onStateSelect: undefined });
434
+
435
+ expect(
436
+ screen.queryByRole("button", { name: "More actions" }),
437
+ ).not.toBeInTheDocument();
438
+ });
439
+
440
+ test("does not render overflow when every other state already has a visible action", () => {
441
+ renderPanel({
442
+ states: [
443
+ makeState("created", "Created"),
444
+ makeState("acknowledged", "Acknowledged"),
445
+ makeState("resolved", "Resolved"),
446
+ ],
447
+ });
448
+
449
+ expect(
450
+ screen.queryByRole("button", { name: "More actions" }),
451
+ ).not.toBeInTheDocument();
452
+ });
453
+
454
+ test("does not render overflow when the current state is the only state", () => {
455
+ renderPanel({
456
+ states: [makeState("created", "Created")],
457
+ actions: [],
458
+ });
459
+
460
+ expect(
461
+ screen.queryByRole("button", { name: "More actions" }),
462
+ ).not.toBeInTheDocument();
463
+ });
464
+
465
+ test("does not offer backward transitions from an intermediate state", () => {
466
+ renderPanel({
467
+ currentStateId: "acknowledged",
468
+ actions: [
469
+ {
470
+ stateId: "resolved",
471
+ label: "Resolve",
472
+ buttonStyle: ButtonStyleType.PRIMARY,
473
+ },
474
+ ],
475
+ });
476
+
477
+ const menu: HTMLElement = openMenu();
478
+
479
+ expect(menuChoiceNames(menu)).toEqual(["Investigating"]);
480
+ expect(within(menu).queryByText("Created")).not.toBeInTheDocument();
481
+ });
482
+
483
+ test("does not render invalid backward transitions after resolution", () => {
484
+ renderPanel({ currentStateId: "resolved", actions: [] });
485
+
486
+ expect(
487
+ screen.queryByRole("button", { name: "More actions" }),
488
+ ).not.toBeInTheDocument();
489
+ });
490
+
491
+ test("still renders overflow when alternatives exist but there are no visible actions", () => {
492
+ renderPanel({ actions: [] });
493
+
494
+ expect(getMoreActionsTrigger()).toBeInTheDocument();
495
+ expect(menuChoiceNames(openMenu())).toEqual([
496
+ "Acknowledged",
497
+ "Investigating",
498
+ "Resolved",
499
+ ]);
500
+ });
501
+
502
+ test("keeps recovery alternatives available when the current state is missing", () => {
503
+ renderPanel({ currentStateId: "removed-state" });
504
+
505
+ expect(menuChoiceNames(openMenu())).toEqual(["Created", "Investigating"]);
506
+ });
507
+ });
508
+
509
+ describe("EventStatusPanel disabled behavior", () => {
510
+ test("disables every visible action and suppresses action callbacks", () => {
511
+ const rendered: RenderedPanel = renderPanel({ isDisabled: true });
512
+ const acknowledge: HTMLElement = screen.getByRole("button", {
513
+ name: "Acknowledge",
514
+ });
515
+ const resolve: HTMLElement = screen.getByRole("button", {
516
+ name: "Resolve",
517
+ });
518
+
519
+ expect(acknowledge).toBeDisabled();
520
+ expect(resolve).toBeDisabled();
521
+
522
+ fireEvent.click(acknowledge);
523
+ fireEvent.click(resolve);
524
+
525
+ expect(rendered.actionClicks).toEqual([]);
526
+ });
527
+
528
+ test("makes overflow accessibly disabled and prevents mouse or keyboard opening", () => {
529
+ const rendered: RenderedPanel = renderPanel({ isDisabled: true });
530
+ const trigger: HTMLElement = getMoreActionsTrigger();
531
+
532
+ expect(trigger.tagName).toBe("BUTTON");
533
+ expect(trigger).toBeDisabled();
534
+
535
+ fireEvent.click(trigger);
536
+ fireEvent.keyDown(trigger, { key: "Enter", code: "Enter" });
537
+ fireEvent.keyDown(trigger, { key: " ", code: "Space" });
538
+
539
+ expect(screen.queryByRole("menu")).not.toBeInTheDocument();
540
+ expect(rendered.stateSelections).toEqual([]);
541
+ });
542
+ });
543
+
544
+ describe("EventStatusPanel action-group layout", () => {
545
+ test("labels one responsive wrapping group for every action control", () => {
546
+ renderPanel();
547
+
548
+ const group: HTMLElement = getActionGroup();
549
+
550
+ expect(group).toHaveAttribute("aria-label", "Event actions");
551
+ expect(group).toHaveClass(
552
+ "flex",
553
+ "w-full",
554
+ "flex-wrap",
555
+ "justify-end",
556
+ "md:w-auto",
557
+ );
558
+ expect(within(group).getByRole("button", { name: "Acknowledge" })).toBe(
559
+ screen.getByRole("button", { name: "Acknowledge" }),
560
+ );
561
+ expect(within(group).getByRole("button", { name: "Resolve" })).toBe(
562
+ screen.getByRole("button", { name: "Resolve" }),
563
+ );
564
+ expect(within(group).getByRole("button", { name: "More actions" })).toBe(
565
+ screen.getByRole("button", { name: "More actions" }),
566
+ );
567
+ });
568
+
569
+ test("keeps the overflow control aligned to the fixed action height", () => {
570
+ renderPanel();
571
+
572
+ expect(getMoreActionsTrigger()).toHaveClass("h-9", "w-9");
573
+ });
574
+
575
+ test("constrains long state-action labels before truncating them", () => {
576
+ renderPanel({
577
+ actions: [
578
+ {
579
+ stateId: "acknowledged",
580
+ label: "A very long custom scheduled maintenance state label",
581
+ buttonStyle: ButtonStyleType.PRIMARY,
582
+ },
583
+ ],
584
+ });
585
+
586
+ const button: HTMLElement = screen.getByRole("button", {
587
+ name: "A very long custom scheduled maintenance state label",
588
+ });
589
+
590
+ expect(button).toHaveClass("min-w-[7rem]", "max-w-full", "sm:max-w-64");
591
+ expect(button.querySelector("span")).toHaveClass("truncate");
592
+ });
593
+ });
594
+
595
+ describe("EventStatusPanel header layouts", () => {
596
+ test("puts the title, identifier badge, and action group in the header layout", () => {
597
+ renderPanel({ title: "Database connection failures" });
598
+
599
+ const heading: HTMLElement = screen.getByRole("heading", {
600
+ level: 2,
601
+ name: "Database connection failures",
602
+ });
603
+ const identifier: HTMLElement = screen.getByTitle("Number");
604
+ const group: HTMLElement = getActionGroup();
605
+ const headingBlock: HTMLElement = heading.parentElement as HTMLElement;
606
+ const headerRow: HTMLElement = headingBlock.parentElement as HTMLElement;
607
+
608
+ expect(identifier).toHaveTextContent("INC-42");
609
+ expect(identifier).toHaveClass("bg-gray-100", "uppercase");
610
+ expect(headerRow).toHaveClass("md:items-start", "md:justify-between");
611
+ expect(headerRow).toContainElement(group);
612
+ expect(headerRow).not.toContainElement(screen.getByTestId("pill"));
613
+ });
614
+
615
+ test("uses the compact inline metadata layout when no title is supplied", () => {
616
+ renderPanel();
617
+
618
+ const identifier: HTMLElement = screen.getByTitle("Number");
619
+ const group: HTMLElement = getActionGroup();
620
+ const compactRow: HTMLElement = group.parentElement as HTMLElement;
621
+
622
+ expect(screen.queryByRole("heading", { level: 2 })).not.toBeInTheDocument();
623
+ expect(identifier).toHaveTextContent("INC-42");
624
+ expect(identifier).toHaveClass("text-sm", "font-semibold");
625
+ expect(identifier).not.toHaveClass("bg-gray-100", "uppercase");
626
+ expect(compactRow).toHaveClass("md:items-center", "md:justify-between");
627
+ expect(compactRow).toContainElement(identifier);
628
+ expect(compactRow).toContainElement(screen.getByTestId("pill"));
629
+ });
630
+
631
+ test("falls back to black when hydrated current-state color is absent", () => {
632
+ renderPanel({
633
+ states: [
634
+ {
635
+ id: "created",
636
+ name: "Created",
637
+ // Older API payloads can omit this despite the model-level type.
638
+ color: undefined as unknown as Color,
639
+ },
640
+ ],
641
+ actions: [],
642
+ });
643
+
644
+ expect(screen.getByTestId("pill")).toHaveStyle({
645
+ backgroundColor: "#000000",
646
+ });
647
+ });
648
+ });
649
+
650
+ describe("EventStatusPanel header notice", () => {
651
+ test("renders a notice inside the titled header card", () => {
652
+ render(
653
+ <EventStatusPanel
654
+ title="Database latency"
655
+ identifier="INC-42"
656
+ states={[]}
657
+ actions={[]}
658
+ onActionClick={() => {}}
659
+ headerNotice={
660
+ <div data-testid="header-notice">AI is investigating</div>
661
+ }
662
+ />,
663
+ );
664
+
665
+ const notice: HTMLElement = screen.getByTestId("header-notice");
666
+ expect(notice).toHaveTextContent("AI is investigating");
667
+ expect(notice.parentElement).toHaveClass("mt-3");
668
+ expect(screen.getByText("Database latency")).toBeInTheDocument();
669
+ expect(screen.getByText("INC-42")).toBeInTheDocument();
670
+ });
671
+
672
+ test("adds no empty notice spacing when the optional content is absent", () => {
673
+ const { container } = render(
674
+ <EventStatusPanel
675
+ title="Database latency"
676
+ states={[]}
677
+ actions={[]}
678
+ onActionClick={() => {}}
679
+ />,
680
+ );
681
+
682
+ expect(container.querySelector(".mt-3")).toBeNull();
683
+ });
684
+
685
+ test("keeps existing metadata, state progress, and actions intact beside the notice", () => {
686
+ const onActionClick: MockFunction = getJestMockFunction();
687
+ render(
688
+ <EventStatusPanel
689
+ title="Database latency"
690
+ states={[
691
+ { id: "created", name: "Created", color: CREATED_COLOR },
692
+ {
693
+ id: "acknowledged",
694
+ name: "Acknowledged",
695
+ color: ACKNOWLEDGED_COLOR,
696
+ },
697
+ ]}
698
+ currentStateId="created"
699
+ severity={{ name: "Critical", color: Red500 }}
700
+ isPrivate={true}
701
+ durationPrefix="Ongoing for"
702
+ durationStartsAt={new Date("2026-08-07T10:00:00.000Z")}
703
+ durationEndsAt={new Date("2026-08-07T10:05:00.000Z")}
704
+ actions={[
705
+ {
706
+ stateId: "acknowledged",
707
+ label: "Acknowledge",
708
+ icon: IconProp.Check,
709
+ buttonStyle: ButtonStyleType.PRIMARY,
710
+ },
711
+ ]}
712
+ onActionClick={onActionClick}
713
+ headerNotice={
714
+ <div data-testid="header-notice">AI is investigating</div>
715
+ }
716
+ />,
717
+ );
718
+
719
+ expect(screen.getAllByText("Created").length).toBeGreaterThan(0);
720
+ expect(screen.getByText("Acknowledged")).toBeInTheDocument();
721
+ expect(screen.getByText("Critical")).toBeInTheDocument();
722
+ expect(screen.getByText("Private")).toBeInTheDocument();
723
+ expect(screen.getByText("Ongoing for")).toBeInTheDocument();
724
+
725
+ fireEvent.click(screen.getByRole("button", { name: "Acknowledge" }));
726
+ expect(onActionClick).toHaveBeenCalledWith("acknowledged");
727
+ });
728
+
729
+ test("leaves compact consumers unchanged", () => {
730
+ render(
731
+ <EventStatusPanel
732
+ identifier="#7"
733
+ states={[{ id: "created", name: "Created", color: Black }]}
734
+ currentStateId="created"
735
+ actions={[]}
736
+ onActionClick={() => {}}
737
+ headerNotice={
738
+ <div data-testid="header-notice">AI is investigating</div>
739
+ }
740
+ />,
741
+ );
742
+
743
+ expect(screen.getByText("#7")).toBeInTheDocument();
744
+ expect(screen.getByText("Created")).toBeInTheDocument();
745
+ expect(screen.queryByTestId("header-notice")).not.toBeInTheDocument();
746
+ });
747
+ });