@oneuptime/common 14.0.9 → 14.0.11

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 (1146) hide show
  1. package/Models/DatabaseModels/AIConversation.ts +127 -1
  2. package/Models/DatabaseModels/AutoRemediationSuggestion.ts +60 -0
  3. package/Models/DatabaseModels/CephCluster.ts +225 -0
  4. package/Models/DatabaseModels/CloudResource.ts +12 -0
  5. package/Models/DatabaseModels/DatabaseServer.ts +225 -0
  6. package/Models/DatabaseModels/DockerHost.ts +225 -0
  7. package/Models/DatabaseModels/DockerSwarmCluster.ts +225 -0
  8. package/Models/DatabaseModels/GlobalConfig.ts +1 -1
  9. package/Models/DatabaseModels/GlobalOidc.ts +0 -4
  10. package/Models/DatabaseModels/GlobalOidcProject.ts +0 -4
  11. package/Models/DatabaseModels/GlobalSso.ts +0 -4
  12. package/Models/DatabaseModels/GlobalSsoProject.ts +0 -4
  13. package/Models/DatabaseModels/Host.ts +225 -0
  14. package/Models/DatabaseModels/IncidentForm.ts +594 -0
  15. package/Models/DatabaseModels/IncidentFormSubmission.ts +283 -0
  16. package/Models/DatabaseModels/IncidentTemplate.ts +59 -0
  17. package/Models/DatabaseModels/Index.ts +16 -0
  18. package/Models/DatabaseModels/IoTFleet.ts +12 -0
  19. package/Models/DatabaseModels/KubernetesCluster.ts +12 -0
  20. package/Models/DatabaseModels/MessageQueue.ts +1102 -0
  21. package/Models/DatabaseModels/MessageQueueLabelRule.ts +553 -0
  22. package/Models/DatabaseModels/MessageQueueOwnerRule.ts +633 -0
  23. package/Models/DatabaseModels/MessageQueueOwnerTeam.ts +491 -0
  24. package/Models/DatabaseModels/MessageQueueOwnerUser.ts +490 -0
  25. package/Models/DatabaseModels/PodmanHost.ts +225 -0
  26. package/Models/DatabaseModels/Project.ts +59 -0
  27. package/Models/DatabaseModels/ProjectOidc.ts +0 -4
  28. package/Models/DatabaseModels/ProjectSso.ts +0 -4
  29. package/Models/DatabaseModels/ProxmoxCluster.ts +225 -0
  30. package/Models/DatabaseModels/ResourceAiAgent.ts +419 -0
  31. package/Models/DatabaseModels/RumApplication.ts +12 -0
  32. package/Models/DatabaseModels/RunnerJob.ts +144 -0
  33. package/Models/DatabaseModels/ServerlessFunction.ts +12 -0
  34. package/Models/DatabaseModels/Service.ts +12 -0
  35. package/Models/DatabaseModels/StatusPageOidc.ts +0 -4
  36. package/Models/DatabaseModels/StatusPageSso.ts +0 -4
  37. package/Models/DatabaseModels/TeamComplianceSetting.ts +47 -2
  38. package/Models/DatabaseModels/VMwareVCenter.ts +225 -0
  39. package/Server/API/AIChatAPI.ts +13 -114
  40. package/Server/API/AIInvestigationAPI.ts +3 -3
  41. package/Server/API/AIInvestigationConversationAPI.ts +266 -0
  42. package/Server/API/AutoRemediationAPI.ts +392 -1
  43. package/Server/API/IncidentFormAPI.ts +376 -0
  44. package/Server/API/ProjectOIDC.ts +16 -25
  45. package/Server/API/ProjectSSO.ts +16 -24
  46. package/Server/API/ResourceAiAccessAPI.ts +1669 -0
  47. package/Server/API/StatusPageAPI.ts +42 -77
  48. package/Server/Enterprise/EnterpriseEdition.ts +93 -28
  49. package/Server/Enterprise/EnterpriseFeature.ts +25 -3
  50. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +1 -1
  51. package/Server/Enterprise/EnterpriseServerModule.ts +4 -1
  52. package/Server/EnvironmentConfig.ts +1 -1
  53. package/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.ts +423 -0
  54. package/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.ts +129 -0
  55. package/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.ts +52 -0
  56. package/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.ts +75 -0
  57. package/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.ts +477 -0
  58. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  59. package/Server/Infrastructure/Semaphore.ts +22 -0
  60. package/Server/Middleware/IncidentFormRateLimit.ts +847 -0
  61. package/Server/Middleware/TelemetryIngest.ts +15 -5
  62. package/Server/Middleware/UserAuthorization.ts +16 -38
  63. package/Server/Services/AIService.ts +10 -13
  64. package/Server/Services/AnalyticsDatabaseService.ts +45 -1
  65. package/Server/Services/AutoRemediationRuleEngineService.ts +940 -112
  66. package/Server/Services/CephClusterService.ts +109 -1
  67. package/Server/Services/DatabaseServerService.ts +116 -1
  68. package/Server/Services/DockerHostService.ts +109 -1
  69. package/Server/Services/DockerSwarmClusterService.ts +113 -1
  70. package/Server/Services/HostService.ts +126 -4
  71. package/Server/Services/IncidentCustomFieldService.ts +112 -2
  72. package/Server/Services/IncidentEpisodeMemberService.ts +24 -4
  73. package/Server/Services/IncidentEpisodeService.ts +10 -1
  74. package/Server/Services/IncidentFormService.ts +1566 -0
  75. package/Server/Services/IncidentFormSubmissionService.ts +97 -0
  76. package/Server/Services/IncidentGroupingEngineService.ts +45 -8
  77. package/Server/Services/IncidentService.ts +123 -5
  78. package/Server/Services/IncidentTemplateService.ts +22 -0
  79. package/Server/Services/Index.ts +14 -0
  80. package/Server/Services/MessageQueueLabelRuleEngineService.ts +321 -0
  81. package/Server/Services/MessageQueueLabelRuleService.ts +14 -0
  82. package/Server/Services/MessageQueueOwnerRuleEngineService.ts +412 -0
  83. package/Server/Services/MessageQueueOwnerRuleService.ts +14 -0
  84. package/Server/Services/MessageQueueOwnerTeamService.ts +62 -0
  85. package/Server/Services/MessageQueueOwnerUserService.ts +62 -0
  86. package/Server/Services/MessageQueueService.ts +1463 -0
  87. package/Server/Services/MetricRecordingRuleService.ts +47 -0
  88. package/Server/Services/OpenTelemetryIngestService.ts +37 -4
  89. package/Server/Services/PodmanHostService.ts +109 -1
  90. package/Server/Services/ProjectService.ts +0 -59
  91. package/Server/Services/ProxmoxClusterService.ts +110 -1
  92. package/Server/Services/ResourceAiAccessService.ts +1439 -0
  93. package/Server/Services/ResourceAiAgentJobService.ts +202 -0
  94. package/Server/Services/ResourceAiAgentService.ts +2432 -0
  95. package/Server/Services/RunnerJobService.ts +611 -4
  96. package/Server/Services/StatusPagePrivateUserService.ts +1 -4
  97. package/Server/Services/StatusPageService.ts +1 -51
  98. package/Server/Services/TeamComplianceSettingService.ts +163 -42
  99. package/Server/Services/TelemetryUsageBillingService.ts +28 -0
  100. package/Server/Services/TraceRecordingRuleService.ts +33 -0
  101. package/Server/Services/UserNotificationRuleService.ts +8 -1
  102. package/Server/Services/VMwareVCenterService.ts +110 -1
  103. package/Server/Services/WorkspaceNotificationSummaryService.ts +12 -3
  104. package/Server/Types/Database/Permissions/CreatePermission.ts +17 -3
  105. package/Server/Types/Database/Permissions/EditionPermission.ts +140 -38
  106. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +16 -0
  107. package/Server/Types/Database/Permissions/TablePermission.ts +3 -3
  108. package/Server/Types/Database/Permissions/UpdatePermission.ts +20 -6
  109. package/Server/Utils/AI/Chat/AgentContextCompactor.ts +200 -0
  110. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +307 -48
  111. package/Server/Utils/AI/Chat/ChatRunCancellation.ts +156 -0
  112. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +78 -18
  113. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  114. package/Server/Utils/AI/Chat/ToolOutputPager.ts +322 -0
  115. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +88 -30
  116. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +13 -1
  117. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +0 -32
  118. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +27 -25
  119. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1442 -34
  120. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +968 -34
  121. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +25 -1
  122. package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +622 -0
  123. package/Server/Utils/AI/ResourceAccess/ResourceAccessContext.ts +271 -0
  124. package/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.ts +45 -0
  125. package/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.ts +964 -0
  126. package/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.ts +333 -0
  127. package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +882 -0
  128. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +125 -12
  129. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +99 -15
  130. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +99 -15
  131. package/Server/Utils/AI/SRE/InvestigationQueue.ts +16 -19
  132. package/Server/Utils/AI/SRE/InvestigationThread.ts +646 -0
  133. package/Server/Utils/AI/SRE/InvestigationThreadService.ts +715 -0
  134. package/Server/Utils/AI/Toolbox/Serializer.ts +10 -3
  135. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +396 -13
  136. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +35 -2
  137. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +9 -1
  138. package/Server/Utils/EditionEnforcement.ts +19 -202
  139. package/Server/Utils/LLM/LLMService.ts +259 -63
  140. package/Server/Utils/RelaxedScimTeamLocksReport.ts +245 -0
  141. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
  142. package/Server/Utils/SameOriginRequest.ts +203 -0
  143. package/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.ts +920 -0
  144. package/Server/Utils/SessionReplay/SessionReplayUsage.ts +84 -6
  145. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
  146. package/Server/Utils/Telemetry/EntityRegistry.ts +4 -1
  147. package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +1402 -0
  148. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +4 -1
  149. package/Server/Utils/VendorAssets.ts +3 -3
  150. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +35 -15
  151. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +33 -15
  152. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +21 -1
  153. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +301 -225
  154. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +38 -16
  155. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +389 -175
  156. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +376 -144
  157. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.ts +163 -0
  158. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.ts +396 -0
  159. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.ts +418 -0
  160. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.ts +152 -0
  161. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.ts +251 -0
  162. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.ts +214 -0
  163. package/Tests/App/Accounts/IncidentFormPage.test.tsx +2036 -0
  164. package/Tests/App/Accounts/IncidentFormServerMessages.test.ts +119 -0
  165. package/Tests/App/Accounts/IncidentFormUtils.test.ts +1157 -0
  166. package/Tests/App/Accounts/LoginPasskey.test.tsx +6 -4
  167. package/Tests/App/Accounts/LoginSso.test.tsx +724 -0
  168. package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +338 -0
  169. package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +331 -0
  170. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +47 -33
  171. package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +1021 -0
  172. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +876 -78
  173. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +20 -3
  174. package/Tests/App/Dashboard/CephProxmoxVMwareDocumentationCards.test.tsx +359 -0
  175. package/Tests/App/Dashboard/CephSetupGuide.test.ts +961 -0
  176. package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +381 -95
  177. package/Tests/App/Dashboard/CloudSetupGuide.test.ts +1463 -0
  178. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +267 -12
  179. package/Tests/App/Dashboard/ContainerSetupGuideCards.test.tsx +345 -0
  180. package/Tests/App/Dashboard/CoreListEmptyStates.test.tsx +501 -0
  181. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +0 -1
  182. package/Tests/App/Dashboard/DatabaseDocumentationCard.test.tsx +400 -0
  183. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +23 -6
  184. package/Tests/App/Dashboard/DatabaseSetupGuide.test.ts +1869 -0
  185. package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +44 -0
  186. package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +50 -9
  187. package/Tests/App/Dashboard/DockerSetupGuide.test.ts +899 -0
  188. package/Tests/App/Dashboard/DockerSwarmSetupGuide.test.ts +964 -0
  189. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +141 -7
  190. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +52 -39
  191. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +7 -1
  192. package/Tests/App/Dashboard/GettingStartedTaskRoutes.test.tsx +331 -0
  193. package/Tests/App/Dashboard/HomeOverviewStatsFirstRun.test.tsx +925 -0
  194. package/Tests/App/Dashboard/HostDocumentationCard.test.tsx +225 -0
  195. package/Tests/App/Dashboard/HostSetupGuide.test.ts +1183 -0
  196. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +69 -45
  197. package/Tests/App/Dashboard/IncidentCreateTemplateCustomFieldSettings.test.tsx +745 -0
  198. package/Tests/App/Dashboard/IncidentCreateTemplateOwners.test.tsx +414 -0
  199. package/Tests/App/Dashboard/IncidentCustomFieldCreateSettingsForm.test.ts +1042 -0
  200. package/Tests/App/Dashboard/IncidentCustomFieldSettingsCard.test.tsx +1816 -0
  201. package/Tests/App/Dashboard/IncidentFormPlan.test.ts +89 -0
  202. package/Tests/App/Dashboard/IncidentFormShareLinkCard.test.tsx +846 -0
  203. package/Tests/App/Dashboard/IncidentFormsPages.test.tsx +1324 -0
  204. package/Tests/App/Dashboard/IncidentTemplateCustomFieldSettings.test.tsx +630 -0
  205. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +13 -0
  206. package/Tests/App/Dashboard/IncomingEmailMonitorLinkVerifyHint.test.tsx +104 -0
  207. package/Tests/App/Dashboard/InvestigationConversation.test.tsx +1107 -0
  208. package/Tests/App/Dashboard/InvestigationConversationData.test.ts +546 -0
  209. package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +170 -5
  210. package/Tests/App/Dashboard/InvestigationInfrastructureTools.test.tsx +506 -0
  211. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +207 -2
  212. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +729 -34
  213. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +9 -21
  214. package/Tests/App/Dashboard/InvestigationReportView.test.tsx +274 -37
  215. package/Tests/App/Dashboard/InvestigationStatusBadge.test.tsx +130 -0
  216. package/Tests/App/Dashboard/IoTDocumentationCard.test.tsx +218 -0
  217. package/Tests/App/Dashboard/IoTSetupGuide.test.ts +1124 -0
  218. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +20 -6
  219. package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +107 -83
  220. package/Tests/App/Dashboard/KubernetesSetupGuide.test.ts +787 -0
  221. package/Tests/App/Dashboard/MessageQueueBreadcrumbs.test.tsx +228 -0
  222. package/Tests/App/Dashboard/MessageQueueBrokerHealth.test.tsx +1538 -0
  223. package/Tests/App/Dashboard/MessageQueueBrokerHealthMetricChart.test.tsx +969 -0
  224. package/Tests/App/Dashboard/MessageQueueBrokerHealthReads.test.ts +889 -0
  225. package/Tests/App/Dashboard/MessageQueueBrokerMetricsReach.test.ts +236 -0
  226. package/Tests/App/Dashboard/MessageQueueDocumentationCard.test.tsx +479 -0
  227. package/Tests/App/Dashboard/MessageQueueListPages.test.tsx +1232 -0
  228. package/Tests/App/Dashboard/MessageQueueMetricDescriptions.test.ts +244 -0
  229. package/Tests/App/Dashboard/MessageQueueMonitorLink.test.ts +952 -0
  230. package/Tests/App/Dashboard/MessageQueueMonitorLinkMonitorCreate.test.tsx +859 -0
  231. package/Tests/App/Dashboard/MessageQueueOverview.test.tsx +1773 -0
  232. package/Tests/App/Dashboard/MessageQueueOverviewPresentation.test.ts +196 -0
  233. package/Tests/App/Dashboard/MessageQueuePresentation.test.ts +799 -0
  234. package/Tests/App/Dashboard/MessageQueueProducersConsumers.test.tsx +680 -0
  235. package/Tests/App/Dashboard/MessageQueueRoutes.test.tsx +383 -0
  236. package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +278 -0
  237. package/Tests/App/Dashboard/MessageQueueSetupGuide.test.ts +2778 -0
  238. package/Tests/App/Dashboard/MessageQueueSideMenus.test.tsx +273 -0
  239. package/Tests/App/Dashboard/MessageQueueSpanPopulations.test.ts +930 -0
  240. package/Tests/App/Dashboard/MessageQueueSpanStore.ts +351 -0
  241. package/Tests/App/Dashboard/MessageQueueTelemetryScope.test.ts +375 -0
  242. package/Tests/App/Dashboard/MessageQueueTelemetryScopeTabs.test.tsx +668 -0
  243. package/Tests/App/Dashboard/MessageQueueViewPages.test.tsx +685 -0
  244. package/Tests/App/Dashboard/MonitorAndHomeNotOperationalMenus.test.tsx +342 -0
  245. package/Tests/App/Dashboard/MonitorCreateFirstRunDefaults.test.tsx +623 -0
  246. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +442 -0
  247. package/Tests/App/Dashboard/MonitorLogsPageViewSummary.test.tsx +814 -0
  248. package/Tests/App/Dashboard/MonitorSetupCardBodies.test.tsx +246 -0
  249. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +8 -0
  250. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +27 -12
  251. package/Tests/App/Dashboard/PlanGatedPage.test.tsx +292 -0
  252. package/Tests/App/Dashboard/PodmanSetupGuide.test.ts +948 -0
  253. package/Tests/App/Dashboard/ProductOrientation.test.tsx +5 -4
  254. package/Tests/App/Dashboard/ProductSettingsSectionCollapsed.test.tsx +266 -0
  255. package/Tests/App/Dashboard/ProxmoxSetupGuide.test.ts +1318 -0
  256. package/Tests/App/Dashboard/RemediationSuggestionCardDescription.test.tsx +209 -0
  257. package/Tests/App/Dashboard/RemediationSuggestionCardResource.test.tsx +317 -0
  258. package/Tests/App/Dashboard/ResourceAiAccessSettingsUtil.test.ts +921 -0
  259. package/Tests/App/Dashboard/ResourceAiAgentAttentionServerParity.test.ts +555 -0
  260. package/Tests/App/Dashboard/ResourceAiAgentInstall.test.ts +860 -0
  261. package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +2010 -0
  262. package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +1455 -0
  263. package/Tests/App/Dashboard/ResourceAiInsightsPage.test.tsx +931 -0
  264. package/Tests/App/Dashboard/ResourceAiNavigation.test.tsx +575 -0
  265. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +16 -0
  266. package/Tests/App/Dashboard/ResourceConnectionGuideCard.test.tsx +444 -0
  267. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsInfra.test.tsx +798 -0
  268. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsPlatforms.test.tsx +717 -0
  269. package/Tests/App/Dashboard/ResourceConnectionGuides.test.ts +981 -0
  270. package/Tests/App/Dashboard/ResourceConnectionState.test.ts +132 -0
  271. package/Tests/App/Dashboard/RumDocumentationCard.test.tsx +293 -0
  272. package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +467 -0
  273. package/Tests/App/Dashboard/RumSetupGuide.test.ts +758 -0
  274. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +38 -7
  275. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +25 -0
  276. package/Tests/App/Dashboard/ServerlessDocumentationCard.test.tsx +254 -0
  277. package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1074 -0
  278. package/Tests/App/Dashboard/SetupGuide.test.ts +246 -0
  279. package/Tests/App/Dashboard/SetupGuideCard.test.tsx +756 -0
  280. package/Tests/App/Dashboard/SloListSideMenu.test.tsx +120 -0
  281. package/Tests/App/Dashboard/SsoPages.test.tsx +833 -0
  282. package/Tests/App/Dashboard/TelemetryDocumentation.test.tsx +253 -0
  283. package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +730 -0
  284. package/Tests/App/Dashboard/VMwareSetupGuide.test.ts +1033 -0
  285. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +87 -7
  286. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +61 -10
  287. package/Tests/Models/DatabaseModels/IncidentFormModel.test.ts +1250 -0
  288. package/Tests/Models/DatabaseModels/MessageQueueModels.test.ts +1983 -0
  289. package/Tests/Models/DatabaseModels/ResourceAiAccessColumns.test.ts +738 -0
  290. package/Tests/Models/DatabaseModels/ResourceAiAgentModel.test.ts +842 -0
  291. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  292. package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +190 -14
  293. package/Tests/Models/IncidentTemplateCustomFieldSettingsColumn.test.ts +291 -0
  294. package/Tests/Server/API/AIInvestigationConversationAPI.test.ts +412 -0
  295. package/Tests/Server/API/AutoRemediationApproveResourceRound.test.ts +835 -0
  296. package/Tests/Server/API/GlobalConfigLicense.test.ts +38 -9
  297. package/Tests/Server/API/IncidentFormAPI.test.ts +942 -0
  298. package/Tests/Server/API/IncidentFormPublicRoutes.test.ts +1653 -0
  299. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -1
  300. package/Tests/Server/API/ResourceAiAccessAPI.test.ts +2730 -0
  301. package/Tests/Server/API/{SsoProviderListingsEdition.test.ts → SsoProviderListings.test.ts} +164 -110
  302. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +76 -54
  303. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +125 -42
  304. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +36 -10
  305. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +51 -9
  306. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +13 -8
  307. package/Tests/Server/Enterprise/SsoInCommunityEdition.test.ts +540 -0
  308. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  309. package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +60 -0
  310. package/Tests/Server/Infrastructure/Postgres/AddIncidentFormsMigration.test.ts +438 -0
  311. package/Tests/Server/Infrastructure/Postgres/AddResourceAiAgentsMigration.test.ts +659 -0
  312. package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleNotificationChannelsMigration.test.ts +255 -0
  313. package/Tests/Server/Infrastructure/Postgres/MessageQueueTablesMigration.test.ts +637 -0
  314. package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +31 -0
  315. package/Tests/Server/Middleware/IncidentFormRateLimit.test.ts +1630 -0
  316. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +63 -5
  317. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +103 -5
  318. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +19 -1
  319. package/Tests/Server/Middleware/UserAuthorization.test.ts +16 -17
  320. package/Tests/Server/Middleware/UserAuthorizationSsoEnforcement.test.ts +544 -0
  321. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +37 -8
  322. package/Tests/Server/Services/AutoRemediationResourceRuleEngine.test.ts +1279 -0
  323. package/Tests/Server/Services/DatabaseServerService.test.ts +55 -0
  324. package/Tests/Server/Services/GroupTelemetryUsageExcludeNames.test.ts +299 -0
  325. package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +44 -0
  326. package/Tests/Server/Services/IncidentCreatedFeedTitle.test.ts +212 -0
  327. package/Tests/Server/Services/IncidentCustomFieldDeleteFormQuestions.test.ts +297 -0
  328. package/Tests/Server/Services/IncidentFormOwnersCreatedNotification.test.ts +497 -0
  329. package/Tests/Server/Services/IncidentFormPostgres.test.ts +958 -0
  330. package/Tests/Server/Services/IncidentFormPublicForm.test.ts +1260 -0
  331. package/Tests/Server/Services/IncidentFormPublicSubmission.test.ts +2520 -0
  332. package/Tests/Server/Services/IncidentFormRegistration.test.ts +159 -0
  333. package/Tests/Server/Services/IncidentFormService.test.ts +663 -0
  334. package/Tests/Server/Services/IncidentFormSubmissionService.test.ts +430 -0
  335. package/Tests/Server/Services/IncidentFormSubmissionTemplateBranch.test.ts +473 -0
  336. package/Tests/Server/Services/IncidentGroupingTemplateSubstitution.test.ts +81 -0
  337. package/Tests/Server/Services/IncidentTemplateCustomFieldSettings.test.ts +262 -0
  338. package/Tests/Server/Services/IncidentTemplateOwnersOnDeclare.test.ts +566 -0
  339. package/Tests/Server/Services/IncidentTitleMarkdownSinks.test.ts +640 -0
  340. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +3 -3
  341. package/Tests/Server/Services/MessageQueueOwnerServices.test.ts +440 -0
  342. package/Tests/Server/Services/MessageQueueRegistries.test.ts +577 -0
  343. package/Tests/Server/Services/MessageQueueRuleEngines.test.ts +900 -0
  344. package/Tests/Server/Services/MessageQueueService.test.ts +2210 -0
  345. package/Tests/Server/Services/MessageQueueSqlPostgres.test.ts +1271 -0
  346. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +45 -6
  347. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
  348. package/Tests/Server/Services/OpenTelemetryRetentionOverrideEdition.test.ts +474 -0
  349. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +21 -0
  350. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +3 -0
  351. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +0 -1
  352. package/Tests/Server/Services/RecordingRuleReservedMetricName.test.ts +171 -0
  353. package/Tests/Server/Services/ResourceAiAccessChangeAuthorization.test.ts +256 -0
  354. package/Tests/Server/Services/ResourceAiAccessService.test.ts +1373 -0
  355. package/Tests/Server/Services/ResourceAiAgentJobService.test.ts +375 -0
  356. package/Tests/Server/Services/ResourceAiAgentServiceHelpers.test.ts +1114 -0
  357. package/Tests/Server/Services/ResourceAiAgentServiceLifecycle.test.ts +1050 -0
  358. package/Tests/Server/Services/ResourceAiAgentServiceRegister.test.ts +2251 -0
  359. package/Tests/Server/Services/ResourceAiSettingsCreate.test.ts +373 -0
  360. package/Tests/Server/Services/ResourceAiSettingsPermission.test.ts +1042 -0
  361. package/Tests/Server/Services/ResourceServiceDeleteCleansUpAi.test.ts +319 -0
  362. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +56 -6
  363. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -1
  364. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +105 -0
  365. package/Tests/Server/Services/RunnerJobEnqueueResourceCommand.test.ts +986 -0
  366. package/Tests/Server/Services/RunnerJobResourceCommandLane.test.ts +211 -0
  367. package/Tests/Server/Services/RunnerJobResourceCommandTimeoutAndRedaction.test.ts +352 -0
  368. package/Tests/Server/Services/SsoRequirementReads.test.ts +454 -0
  369. package/Tests/Server/Services/SsoRequirementWrites.test.ts +529 -0
  370. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
  371. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +107 -89
  372. package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +1068 -176
  373. package/Tests/Server/Services/TeamComplianceSettingService.test.ts +1962 -200
  374. package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +218 -0
  375. package/Tests/Server/TestingUtils/Services/FakeRunnerJobCount.ts +145 -0
  376. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +654 -297
  377. package/Tests/Server/Types/Database/Permissions/RetentionOverrideColumns.test.ts +784 -0
  378. package/Tests/Server/Types/Database/Permissions/SsoScalePlanGate.test.ts +418 -0
  379. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +0 -1
  380. package/Tests/Server/Utils/AI/AIInvestigationEngineRunLimits.test.ts +136 -0
  381. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +15 -14
  382. package/Tests/Server/Utils/AI/AgentContextCompactor.test.ts +351 -0
  383. package/Tests/Server/Utils/AI/ChatAgentRunnerSharedThread.test.ts +842 -0
  384. package/Tests/Server/Utils/AI/ChatRunCancellation.test.ts +195 -0
  385. package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +10 -57
  386. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +20 -24
  387. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +7 -30
  388. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +225 -29
  389. package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +694 -0
  390. package/Tests/Server/Utils/AI/InvestigationInfrastructureReport.test.ts +721 -0
  391. package/Tests/Server/Utils/AI/InvestigationThread.test.ts +580 -0
  392. package/Tests/Server/Utils/AI/InvestigationThreadService.test.ts +801 -0
  393. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +525 -43
  394. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +4 -2
  395. package/Tests/Server/Utils/AI/LLMServiceUnreachableProvider.test.ts +435 -0
  396. package/Tests/Server/Utils/AI/ObservabilityAssistantLimits.test.ts +462 -0
  397. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +94 -1
  398. package/Tests/Server/Utils/AI/RemediationCommandToolsResource.test.ts +1530 -0
  399. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +14 -25
  400. package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +1251 -0
  401. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +117 -0
  402. package/Tests/Server/Utils/AI/RemediationResourceCopyParity.test.ts +463 -0
  403. package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +1004 -0
  404. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAccessContext.test.ts +266 -0
  405. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.test.ts +1220 -0
  406. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.test.ts +569 -0
  407. package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +834 -0
  408. package/Tests/Server/Utils/AI/ToolOutputPager.test.ts +382 -0
  409. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +23 -4
  410. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +25 -6
  411. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +14 -3
  412. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorResource.test.ts +717 -0
  413. package/Tests/Server/Utils/AutoRemediation/RemediationVerifierResourceFollowUp.test.ts +338 -0
  414. package/Tests/Server/Utils/EditionEnforcement.test.ts +107 -147
  415. package/Tests/Server/Utils/Monitor/Criteria/SessionReplayBudgetTemplateCriteria.test.ts +422 -0
  416. package/Tests/Server/Utils/{CommunityEditionSsoReport.test.ts → RelaxedScimTeamLocksReport.test.ts} +212 -208
  417. package/Tests/Server/Utils/SameOriginRequest.test.ts +372 -0
  418. package/Tests/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.test.ts +1647 -0
  419. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +143 -1
  420. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +20 -0
  421. package/Tests/Server/Utils/Telemetry/MessageQueueDiscovery.test.ts +2590 -0
  422. package/Tests/Server/Utils/Telemetry/MessageQueueSpanQueryTwin.ts +246 -0
  423. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +23 -0
  424. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +33 -3
  425. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsAccountNotLinked.test.ts +1093 -0
  426. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.test.ts +1049 -0
  427. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.test.ts +1676 -0
  428. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCards.test.ts +2884 -0
  429. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.test.ts +2490 -0
  430. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmit.test.ts +2293 -0
  431. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmitServerTimezone.test.ts +386 -0
  432. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.test.ts +1477 -0
  433. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.test.ts +1967 -0
  434. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsStripHtmlTags.test.ts +92 -0
  435. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsSubmittedFormRemoval.test.ts +1819 -0
  436. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.test.ts +1033 -0
  437. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezoneServerZone.test.ts +610 -0
  438. package/Tests/Server/Utils/Workspace/MicrosoftTeamsBotMessageHandling.test.ts +2610 -0
  439. package/Tests/Server/Utils/Workspace/MicrosoftTeamsCreateCommandsEndToEnd.test.ts +4672 -0
  440. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +190 -65
  441. package/Tests/Types/AI/AIAgentRunLimits.test.ts +255 -0
  442. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +10 -4
  443. package/Tests/Types/AutoRemediation/AiRemediationCommandPlanResourceCommand.test.ts +305 -0
  444. package/Tests/Types/Code/JsonSyntax.test.ts +1300 -0
  445. package/Tests/Types/CustomField/CustomFieldCreateSettings.test.ts +1113 -0
  446. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +91 -0
  447. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +30 -0
  448. package/Tests/Types/Incident/IncidentFormIpAllowlist.test.ts +227 -0
  449. package/Tests/Types/Incident/IncidentFormPublic.test.ts +1916 -0
  450. package/Tests/Types/MessageQueue/MessageQueueEntityKey.test.ts +916 -0
  451. package/Tests/Types/MessageQueue/MessageQueueIdentity.test.ts +567 -0
  452. package/Tests/Types/MessageQueue/MessageQueueManualIdentity.test.ts +686 -0
  453. package/Tests/Types/MessageQueue/MessageQueueMetricCatalog.test.ts +1726 -0
  454. package/Tests/Types/MessageQueue/MessageQueueMetricResolution.test.ts +1758 -0
  455. package/Tests/Types/MessageQueue/MessagingInstrumentationFixtures.test.ts +4686 -0
  456. package/Tests/Types/MessageQueue/MessagingSystem.test.ts +840 -0
  457. package/Tests/Types/MessageQueue/MessagingTelemetryFixtures.ts +3287 -0
  458. package/Tests/Types/MessageQueue/MessagingTelemetryResolver.test.ts +2966 -0
  459. package/Tests/Types/Monitor/MessageQueueAlertTemplates.test.ts +5401 -0
  460. package/Tests/Types/Monitor/MetricEngineFold.ts +154 -0
  461. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +277 -13
  462. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +113 -0
  463. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +773 -2
  464. package/Tests/Types/ResourceAiAgent/AiResourceType.test.ts +419 -0
  465. package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +519 -0
  466. package/Tests/Types/Runbook/RunbookStepType.test.ts +147 -8
  467. package/Tests/Types/Team/ComplianceRule.test.ts +588 -37
  468. package/Tests/Types/Team/TeamComplianceStatus.test.ts +64 -11
  469. package/Tests/Types/XML.test.ts +51 -0
  470. package/Tests/UI/Components/CodeEditor/CodeEditor.test.tsx +2362 -0
  471. package/Tests/UI/Components/CodeEditor/CodeEditorCommands.test.ts +810 -0
  472. package/Tests/UI/Components/CodeEditor/CodeEditorHighlight.test.ts +338 -0
  473. package/Tests/UI/Components/CodeEditor/CodeEditorLanguages.test.ts +222 -0
  474. package/Tests/UI/Components/CodeEditor/CodeEditorStyles.test.ts +807 -0
  475. package/Tests/UI/Components/CodeEditor/NoMonaco.test.ts +245 -0
  476. package/Tests/UI/Components/CodeEditor/YamlEditor.test.tsx +729 -0
  477. package/Tests/UI/Components/CopyTextButton.test.tsx +76 -0
  478. package/Tests/UI/Components/EditionLabelLapseCopy.ts +51 -14
  479. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +131 -23
  480. package/Tests/UI/Components/ErrorMessageAction.test.tsx +142 -0
  481. package/Tests/UI/Components/FacetSidebarInScope.test.tsx +459 -0
  482. package/Tests/UI/Components/FacetValuesInScope.test.ts +270 -0
  483. package/Tests/UI/Components/Forms/FormFieldCodeEditors.test.tsx +294 -0
  484. package/Tests/UI/Components/Forms/FormFieldMarkdown.test.tsx +126 -0
  485. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +22 -75
  486. package/Tests/UI/Components/Forms/ModelFormOnBeforeCreateMiscData.test.tsx +254 -0
  487. package/Tests/UI/Components/Icon.test.tsx +32 -0
  488. package/Tests/UI/Components/Input.test.tsx +31 -0
  489. package/Tests/UI/Components/LockedFilterChipScope.test.tsx +501 -0
  490. package/Tests/UI/Components/MarkdownConverters.test.ts +253 -1
  491. package/Tests/UI/Components/MarkdownEditor.test.tsx +2785 -2
  492. package/Tests/UI/Components/MarkdownEditorHistory.test.ts +243 -0
  493. package/Tests/UI/Components/MarkdownListEditing.test.ts +1118 -0
  494. package/Tests/UI/Components/MarkdownPaste.test.ts +1180 -0
  495. package/Tests/UI/Components/MarkdownViewerCopy.test.tsx +466 -0
  496. package/Tests/UI/Components/MarkdownVisualEditing.test.ts +1089 -0
  497. package/Tests/UI/Components/ModelTable/BaseModelTableEmptyStateAction.test.tsx +623 -0
  498. package/Tests/UI/Components/ResetObjectID.test.tsx +282 -0
  499. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  500. package/Tests/UI/Components/Table/EmptyTableMessage.test.ts +439 -0
  501. package/Tests/UI/Components/Table/TableEmptyState.test.tsx +352 -0
  502. package/Tests/UI/Components/TableRowMobileTitles.test.tsx +78 -0
  503. package/Tests/UI/Components/TextArea.test.tsx +19 -0
  504. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +12 -29
  505. package/Tests/UI/Components/fixtures/MarkdownPasteFixtures.ts +460 -0
  506. package/Tests/UI/EsbuildConfig.test.ts +115 -39
  507. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +4 -4
  508. package/Tests/UI/Monitor/MonitorLogSummaryRender.test.tsx +377 -0
  509. package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +769 -1
  510. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +81 -1
  511. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +17 -0
  512. package/Tests/Utils/AiRemediation/Resource/CephCommandPolicy.test.ts +1653 -0
  513. package/Tests/Utils/AiRemediation/Resource/CephOutputRedaction.test.ts +204 -0
  514. package/Tests/Utils/AiRemediation/Resource/DatabaseCommandPolicy.test.ts +1077 -0
  515. package/Tests/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.test.ts +558 -0
  516. package/Tests/Utils/AiRemediation/Resource/DatabaseQueryRedactor.test.ts +834 -0
  517. package/Tests/Utils/AiRemediation/Resource/DockerCliGrammar.test.ts +747 -0
  518. package/Tests/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.test.ts +1259 -0
  519. package/Tests/Utils/AiRemediation/Resource/DockerOutputRedaction.test.ts +386 -0
  520. package/Tests/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.test.ts +782 -0
  521. package/Tests/Utils/AiRemediation/Resource/GovcCommandPolicy.test.ts +2259 -0
  522. package/Tests/Utils/AiRemediation/Resource/HostCommandPolicy.test.ts +2019 -0
  523. package/Tests/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.test.ts +2497 -0
  524. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicy.test.ts +1305 -0
  525. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.test.ts +585 -0
  526. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactor.test.ts +334 -0
  527. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactorCopyParity.test.ts +98 -0
  528. package/Tests/Utils/AiRemediation/Resource/ResourcePolicyImportClosure.test.ts +391 -0
  529. package/Tests/Utils/AiRemediation/ResourceAiAgentPolicyCopyParity.test.ts +497 -0
  530. package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
  531. package/Tests/Utils/Markdown/DashboardMarkdownRenderer.ts +81 -0
  532. package/Tests/Utils/Markdown/UntrustedMarkdown.test.ts +1339 -0
  533. package/Tests/Utils/Monitor/MonitorLogSummaryUtil.test.ts +862 -0
  534. package/Tests/Utils/SessionReplay/SessionReplayBudgetMetricType.test.ts +383 -0
  535. package/Types/AI/AIAgentRunLimits.ts +146 -0
  536. package/Types/AI/ResourceAiAccessApi.ts +140 -0
  537. package/Types/AI/ResourceAiAccessPermissions.ts +126 -0
  538. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +183 -2
  539. package/Types/Code/CodeType.ts +2 -0
  540. package/Types/Code/JsonSyntax.ts +923 -0
  541. package/Types/CustomField/CustomFieldCreateSettings.ts +549 -0
  542. package/Types/CustomField/CustomFieldMappingCatalog.ts +77 -0
  543. package/Types/CustomField/CustomFieldValueValidator.ts +10 -7
  544. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +1 -1
  545. package/Types/Icon/IconProp.ts +2 -0
  546. package/Types/Incident/IncidentFormIpAllowlist.ts +206 -0
  547. package/Types/Incident/IncidentFormPublic.ts +1145 -0
  548. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +10 -3
  549. package/Types/MessageQueue/MessageQueueIdentity.ts +256 -0
  550. package/Types/MessageQueue/MessageQueueManualIdentity.ts +325 -0
  551. package/Types/MessageQueue/MessageQueueMetricCatalog.ts +1357 -0
  552. package/Types/MessageQueue/MessagingSystem.ts +518 -0
  553. package/Types/MessageQueue/MessagingTelemetryResolver.ts +2311 -0
  554. package/Types/Monitor/MessageQueueAlertTemplates.ts +2128 -0
  555. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +55 -22
  556. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +35 -3
  557. package/Types/Monitor/RumAlertTemplates.ts +351 -4
  558. package/Types/Permission.ts +310 -0
  559. package/Types/ResourceAiAgent/AiResourceType.ts +310 -0
  560. package/Types/ResourceAiAgent/ResourceAiAccess.ts +580 -0
  561. package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
  562. package/Types/Rules/RuleRun.ts +4 -0
  563. package/Types/Rum/SessionReplayBudgetMetricType.ts +47 -0
  564. package/Types/Runbook/RunbookStepType.ts +29 -0
  565. package/Types/Team/ComplianceNotificationChannel.ts +4 -3
  566. package/Types/Team/ComplianceRule.ts +71 -18
  567. package/Types/Team/ComplianceRuleType.ts +2 -2
  568. package/Types/Team/TeamComplianceStatus.ts +6 -2
  569. package/Types/Telemetry/EntityType.ts +16 -0
  570. package/Types/Telemetry/LockedFilterDetail.ts +22 -0
  571. package/Types/Telemetry/TelemetryIngestSurface.ts +14 -2
  572. package/Types/XML.ts +26 -0
  573. package/UI/Components/CodeEditor/CodeEditor.css +379 -0
  574. package/UI/Components/CodeEditor/CodeEditor.tsx +1128 -294
  575. package/UI/Components/CodeEditor/CodeEditorCommands.ts +774 -0
  576. package/UI/Components/CodeEditor/CodeEditorHighlight.ts +106 -0
  577. package/UI/Components/CodeEditor/CodeEditorLanguages.ts +164 -0
  578. package/UI/Components/CodeEditor/YamlEditor.tsx +28 -326
  579. package/UI/Components/CopyTextButton/CopyTextButton.tsx +5 -1
  580. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +6 -25
  581. package/UI/Components/EditionLabel/EditionLabel.tsx +14 -13
  582. package/UI/Components/ErrorMessage/ErrorMessage.tsx +11 -1
  583. package/UI/Components/Forms/Fields/FormField.tsx +8 -0
  584. package/UI/Components/Forms/Types/Field.ts +8 -0
  585. package/UI/Components/Icon/Icon.tsx +18 -0
  586. package/UI/Components/Input/Input.tsx +11 -4
  587. package/UI/Components/LogsViewer/LogsViewer.tsx +4 -0
  588. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +21 -3
  589. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  590. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +877 -79
  591. package/UI/Components/Markdown.tsx/MarkdownEditorHistory.ts +284 -0
  592. package/UI/Components/Markdown.tsx/MarkdownListEditing.ts +1362 -0
  593. package/UI/Components/Markdown.tsx/MarkdownPaste.ts +1326 -0
  594. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +106 -10
  595. package/UI/Components/Markdown.tsx/MarkdownVisualEditing.ts +1032 -0
  596. package/UI/Components/ModelTable/BaseModelTable.tsx +85 -7
  597. package/UI/Components/ResetObjectID/ResetObjectID.tsx +35 -9
  598. package/UI/Components/Table/EmptyTableMessage.ts +81 -0
  599. package/UI/Components/Table/Table.tsx +50 -21
  600. package/UI/Components/Table/TableRow.tsx +9 -1
  601. package/UI/Components/TelemetryViewer/FacetVisibility.ts +97 -2
  602. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +13 -0
  603. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +214 -7
  604. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +21 -3
  605. package/UI/Components/TextArea/TextArea.tsx +9 -2
  606. package/UI/Components/Workflow/ModelFieldPicker.tsx +10 -12
  607. package/UI/Styles/Theme.css +8 -0
  608. package/UI/esbuild-config.js +2 -32
  609. package/Utils/AI/InvestigationReport.ts +121 -15
  610. package/Utils/AiRemediation/Resource/CephCommandPolicy.ts +1936 -0
  611. package/Utils/AiRemediation/Resource/DatabaseCommandPolicy.ts +166 -0
  612. package/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.ts +1532 -0
  613. package/Utils/AiRemediation/Resource/DatabaseQueryRedactor.ts +1394 -0
  614. package/Utils/AiRemediation/Resource/DockerCliGrammar.ts +1839 -0
  615. package/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.ts +490 -0
  616. package/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.ts +687 -0
  617. package/Utils/AiRemediation/Resource/GovcCommandPolicy.ts +2096 -0
  618. package/Utils/AiRemediation/Resource/HostCommandPolicy.ts +2982 -0
  619. package/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.ts +1679 -0
  620. package/Utils/AiRemediation/Resource/ResourceCommandPolicy.ts +851 -0
  621. package/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.ts +593 -0
  622. package/Utils/AiRemediation/Resource/ResourceOutputRedactor.ts +2812 -0
  623. package/Utils/LabelRuleImportExport.ts +2 -0
  624. package/Utils/Markdown/UntrustedMarkdown.ts +1513 -0
  625. package/Utils/Monitor/IncomingEmailMonitorRequestUtil.ts +41 -0
  626. package/Utils/Monitor/MonitorLogSummaryUtil.ts +212 -0
  627. package/Utils/SessionReplay/SessionReplayBudgetMetricType.ts +184 -0
  628. package/Utils/Telemetry/EntityKey.ts +48 -0
  629. package/build/dist/Models/DatabaseModels/AIConversation.js +125 -1
  630. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
  631. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  632. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  633. package/build/dist/Models/DatabaseModels/CephCluster.js +231 -0
  634. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  635. package/build/dist/Models/DatabaseModels/CloudResource.js +12 -0
  636. package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
  637. package/build/dist/Models/DatabaseModels/DatabaseServer.js +231 -0
  638. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
  639. package/build/dist/Models/DatabaseModels/DockerHost.js +231 -0
  640. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  641. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +231 -0
  642. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
  643. package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
  644. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  645. package/build/dist/Models/DatabaseModels/GlobalOidc.js +0 -4
  646. package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
  647. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +0 -4
  648. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  649. package/build/dist/Models/DatabaseModels/GlobalSso.js +0 -4
  650. package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
  651. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +0 -4
  652. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  653. package/build/dist/Models/DatabaseModels/Host.js +231 -0
  654. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  655. package/build/dist/Models/DatabaseModels/IncidentForm.js +605 -0
  656. package/build/dist/Models/DatabaseModels/IncidentForm.js.map +1 -0
  657. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js +299 -0
  658. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js.map +1 -0
  659. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +60 -0
  660. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  661. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  662. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  663. package/build/dist/Models/DatabaseModels/IoTFleet.js +12 -0
  664. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  665. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +12 -0
  666. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  667. package/build/dist/Models/DatabaseModels/MessageQueue.js +1106 -0
  668. package/build/dist/Models/DatabaseModels/MessageQueue.js.map +1 -0
  669. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js +562 -0
  670. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js.map +1 -0
  671. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js +643 -0
  672. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js.map +1 -0
  673. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js +506 -0
  674. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js.map +1 -0
  675. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js +505 -0
  676. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js.map +1 -0
  677. package/build/dist/Models/DatabaseModels/PodmanHost.js +231 -0
  678. package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
  679. package/build/dist/Models/DatabaseModels/Project.js +61 -0
  680. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  681. package/build/dist/Models/DatabaseModels/ProjectOidc.js +0 -4
  682. package/build/dist/Models/DatabaseModels/ProjectOidc.js.map +1 -1
  683. package/build/dist/Models/DatabaseModels/ProjectSso.js +0 -4
  684. package/build/dist/Models/DatabaseModels/ProjectSso.js.map +1 -1
  685. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +231 -0
  686. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  687. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js +439 -0
  688. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js.map +1 -0
  689. package/build/dist/Models/DatabaseModels/RumApplication.js +12 -0
  690. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  691. package/build/dist/Models/DatabaseModels/RunnerJob.js +145 -0
  692. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  693. package/build/dist/Models/DatabaseModels/ServerlessFunction.js +12 -0
  694. package/build/dist/Models/DatabaseModels/ServerlessFunction.js.map +1 -1
  695. package/build/dist/Models/DatabaseModels/Service.js +12 -0
  696. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  697. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +0 -4
  698. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  699. package/build/dist/Models/DatabaseModels/StatusPageSso.js +0 -4
  700. package/build/dist/Models/DatabaseModels/StatusPageSso.js.map +1 -1
  701. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +49 -3
  702. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
  703. package/build/dist/Models/DatabaseModels/VMwareVCenter.js +231 -0
  704. package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
  705. package/build/dist/Server/API/AIChatAPI.js +9 -103
  706. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  707. package/build/dist/Server/API/AIInvestigationAPI.js +3 -3
  708. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  709. package/build/dist/Server/API/AIInvestigationConversationAPI.js +162 -0
  710. package/build/dist/Server/API/AIInvestigationConversationAPI.js.map +1 -0
  711. package/build/dist/Server/API/AutoRemediationAPI.js +231 -1
  712. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  713. package/build/dist/Server/API/IncidentFormAPI.js +245 -0
  714. package/build/dist/Server/API/IncidentFormAPI.js.map +1 -0
  715. package/build/dist/Server/API/ProjectOIDC.js +16 -24
  716. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  717. package/build/dist/Server/API/ProjectSSO.js +16 -24
  718. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  719. package/build/dist/Server/API/ResourceAiAccessAPI.js +1119 -0
  720. package/build/dist/Server/API/ResourceAiAccessAPI.js.map +1 -0
  721. package/build/dist/Server/API/StatusPageAPI.js +42 -75
  722. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  723. package/build/dist/Server/Enterprise/EnterpriseEdition.js +79 -25
  724. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -1
  725. package/build/dist/Server/Enterprise/EnterpriseFeature.js +24 -3
  726. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -1
  727. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +1 -1
  728. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -1
  729. package/build/dist/Server/EnvironmentConfig.js +1 -1
  730. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js +168 -0
  731. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js.map +1 -0
  732. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js +63 -0
  733. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js.map +1 -0
  734. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js +41 -0
  735. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js.map +1 -0
  736. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js +40 -0
  737. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js.map +1 -0
  738. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js +183 -0
  739. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js.map +1 -0
  740. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  741. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  742. package/build/dist/Server/Infrastructure/Semaphore.js +6 -0
  743. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  744. package/build/dist/Server/Middleware/IncidentFormRateLimit.js +559 -0
  745. package/build/dist/Server/Middleware/IncidentFormRateLimit.js.map +1 -0
  746. package/build/dist/Server/Middleware/TelemetryIngest.js +12 -5
  747. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  748. package/build/dist/Server/Middleware/UserAuthorization.js +11 -30
  749. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  750. package/build/dist/Server/Services/AIService.js +10 -13
  751. package/build/dist/Server/Services/AIService.js.map +1 -1
  752. package/build/dist/Server/Services/AnalyticsDatabaseService.js +26 -1
  753. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  754. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +601 -3
  755. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  756. package/build/dist/Server/Services/CephClusterService.js +104 -0
  757. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  758. package/build/dist/Server/Services/DatabaseServerService.js +99 -0
  759. package/build/dist/Server/Services/DatabaseServerService.js.map +1 -1
  760. package/build/dist/Server/Services/DockerHostService.js +104 -0
  761. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  762. package/build/dist/Server/Services/DockerSwarmClusterService.js +104 -0
  763. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  764. package/build/dist/Server/Services/HostService.js +114 -2
  765. package/build/dist/Server/Services/HostService.js.map +1 -1
  766. package/build/dist/Server/Services/IncidentCustomFieldService.js +83 -0
  767. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  768. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +8 -4
  769. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  770. package/build/dist/Server/Services/IncidentEpisodeService.js +10 -1
  771. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  772. package/build/dist/Server/Services/IncidentFormService.js +1202 -0
  773. package/build/dist/Server/Services/IncidentFormService.js.map +1 -0
  774. package/build/dist/Server/Services/IncidentFormSubmissionService.js +91 -0
  775. package/build/dist/Server/Services/IncidentFormSubmissionService.js.map +1 -0
  776. package/build/dist/Server/Services/IncidentGroupingEngineService.js +20 -8
  777. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  778. package/build/dist/Server/Services/IncidentService.js +106 -4
  779. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  780. package/build/dist/Server/Services/IncidentTemplateService.js +18 -0
  781. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  782. package/build/dist/Server/Services/Index.js +14 -0
  783. package/build/dist/Server/Services/Index.js.map +1 -1
  784. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js +262 -0
  785. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js.map +1 -0
  786. package/build/dist/Server/Services/MessageQueueLabelRuleService.js +13 -0
  787. package/build/dist/Server/Services/MessageQueueLabelRuleService.js.map +1 -0
  788. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js +334 -0
  789. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js.map +1 -0
  790. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js +13 -0
  791. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js.map +1 -0
  792. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js +62 -0
  793. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js.map +1 -0
  794. package/build/dist/Server/Services/MessageQueueOwnerUserService.js +62 -0
  795. package/build/dist/Server/Services/MessageQueueOwnerUserService.js.map +1 -0
  796. package/build/dist/Server/Services/MessageQueueService.js +1140 -0
  797. package/build/dist/Server/Services/MessageQueueService.js.map +1 -0
  798. package/build/dist/Server/Services/MetricRecordingRuleService.js +46 -0
  799. package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -1
  800. package/build/dist/Server/Services/OpenTelemetryIngestService.js +25 -4
  801. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  802. package/build/dist/Server/Services/PodmanHostService.js +104 -0
  803. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  804. package/build/dist/Server/Services/ProjectService.js +0 -54
  805. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  806. package/build/dist/Server/Services/ProxmoxClusterService.js +104 -0
  807. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  808. package/build/dist/Server/Services/ResourceAiAccessService.js +1028 -0
  809. package/build/dist/Server/Services/ResourceAiAccessService.js.map +1 -0
  810. package/build/dist/Server/Services/ResourceAiAgentJobService.js +173 -0
  811. package/build/dist/Server/Services/ResourceAiAgentJobService.js.map +1 -0
  812. package/build/dist/Server/Services/ResourceAiAgentService.js +1687 -0
  813. package/build/dist/Server/Services/ResourceAiAgentService.js.map +1 -0
  814. package/build/dist/Server/Services/RunnerJobService.js +344 -5
  815. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  816. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -4
  817. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  818. package/build/dist/Server/Services/StatusPageService.js +0 -46
  819. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  820. package/build/dist/Server/Services/TeamComplianceSettingService.js +120 -31
  821. package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
  822. package/build/dist/Server/Services/TelemetryUsageBillingService.js +26 -0
  823. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  824. package/build/dist/Server/Services/TraceRecordingRuleService.js +37 -0
  825. package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -1
  826. package/build/dist/Server/Services/UserNotificationRuleService.js +8 -1
  827. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  828. package/build/dist/Server/Services/VMwareVCenterService.js +104 -0
  829. package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
  830. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +12 -3
  831. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
  832. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +6 -3
  833. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  834. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +109 -37
  835. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  836. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +16 -0
  837. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  838. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +3 -3
  839. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +9 -6
  840. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  841. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js +128 -0
  842. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js.map +1 -0
  843. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +192 -50
  844. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  845. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js +133 -0
  846. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js.map +1 -0
  847. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +53 -13
  848. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  849. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  850. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js +206 -0
  851. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js.map +1 -0
  852. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +53 -26
  853. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
  854. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +4 -2
  855. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
  856. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +1 -29
  857. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  858. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +24 -24
  859. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  860. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1036 -32
  861. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  862. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +661 -41
  863. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  864. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +21 -1
  865. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  866. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +354 -0
  867. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -0
  868. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js +160 -0
  869. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js.map +1 -0
  870. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js +33 -0
  871. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js.map +1 -0
  872. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js +640 -0
  873. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js.map +1 -0
  874. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js +226 -0
  875. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js.map +1 -0
  876. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +602 -0
  877. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -0
  878. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +90 -14
  879. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  880. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +73 -10
  881. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  882. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +73 -10
  883. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  884. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +15 -18
  885. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  886. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js +412 -0
  887. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js.map +1 -0
  888. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js +495 -0
  889. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js.map +1 -0
  890. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +10 -3
  891. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
  892. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +290 -13
  893. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  894. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +29 -1
  895. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  896. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +9 -1
  897. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  898. package/build/dist/Server/Utils/EditionEnforcement.js +20 -158
  899. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -1
  900. package/build/dist/Server/Utils/LLM/LLMService.js +193 -54
  901. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  902. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js +160 -0
  903. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js.map +1 -0
  904. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
  905. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  906. package/build/dist/Server/Utils/SameOriginRequest.js +151 -0
  907. package/build/dist/Server/Utils/SameOriginRequest.js.map +1 -0
  908. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js +627 -0
  909. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js.map +1 -0
  910. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js +60 -5
  911. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js.map +1 -1
  912. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
  913. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
  914. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -1
  915. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  916. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +1015 -0
  917. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -0
  918. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +4 -1
  919. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  920. package/build/dist/Server/Utils/VendorAssets.js +3 -3
  921. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +19 -15
  922. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  923. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +19 -15
  924. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  925. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +17 -1
  926. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -1
  927. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +186 -210
  928. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  929. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +22 -16
  930. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  931. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +233 -167
  932. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  933. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +273 -111
  934. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  935. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js +129 -0
  936. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js.map +1 -0
  937. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js +266 -0
  938. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js.map +1 -0
  939. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js +258 -0
  940. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js.map +1 -0
  941. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js +104 -0
  942. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js.map +1 -0
  943. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js +183 -0
  944. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js.map +1 -0
  945. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js +123 -0
  946. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js.map +1 -0
  947. package/build/dist/Types/AI/AIAgentRunLimits.js +91 -0
  948. package/build/dist/Types/AI/AIAgentRunLimits.js.map +1 -0
  949. package/build/dist/Types/AI/ResourceAiAccessApi.js +30 -0
  950. package/build/dist/Types/AI/ResourceAiAccessApi.js.map +1 -0
  951. package/build/dist/Types/AI/ResourceAiAccessPermissions.js +98 -0
  952. package/build/dist/Types/AI/ResourceAiAccessPermissions.js.map +1 -0
  953. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +116 -29
  954. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  955. package/build/dist/Types/Code/CodeType.js +2 -0
  956. package/build/dist/Types/Code/CodeType.js.map +1 -1
  957. package/build/dist/Types/Code/JsonSyntax.js +604 -0
  958. package/build/dist/Types/Code/JsonSyntax.js.map +1 -0
  959. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js +310 -0
  960. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js.map +1 -0
  961. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +38 -0
  962. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -1
  963. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +10 -7
  964. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -1
  965. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +1 -1
  966. package/build/dist/Types/Icon/IconProp.js +2 -0
  967. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  968. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js +119 -0
  969. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js.map +1 -0
  970. package/build/dist/Types/Incident/IncidentFormPublic.js +678 -0
  971. package/build/dist/Types/Incident/IncidentFormPublic.js.map +1 -0
  972. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +10 -3
  973. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
  974. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js +184 -0
  975. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js.map +1 -0
  976. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js +190 -0
  977. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js.map +1 -0
  978. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js +1057 -0
  979. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js.map +1 -0
  980. package/build/dist/Types/MessageQueue/MessagingSystem.js +394 -0
  981. package/build/dist/Types/MessageQueue/MessagingSystem.js.map +1 -0
  982. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js +1768 -0
  983. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js.map +1 -0
  984. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js +1207 -0
  985. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js.map +1 -0
  986. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +47 -21
  987. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  988. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +5 -0
  989. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  990. package/build/dist/Types/Monitor/RumAlertTemplates.js +199 -3
  991. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  992. package/build/dist/Types/Permission.js +274 -0
  993. package/build/dist/Types/Permission.js.map +1 -1
  994. package/build/dist/Types/ResourceAiAgent/AiResourceType.js +242 -0
  995. package/build/dist/Types/ResourceAiAgent/AiResourceType.js.map +1 -0
  996. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +281 -0
  997. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -0
  998. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +12 -0
  999. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  1000. package/build/dist/Types/Rules/RuleRun.js +4 -0
  1001. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  1002. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js +45 -0
  1003. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js.map +1 -0
  1004. package/build/dist/Types/Runbook/RunbookStepType.js +27 -0
  1005. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  1006. package/build/dist/Types/Team/ComplianceNotificationChannel.js +4 -3
  1007. package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -1
  1008. package/build/dist/Types/Team/ComplianceRule.js +48 -14
  1009. package/build/dist/Types/Team/ComplianceRule.js.map +1 -1
  1010. package/build/dist/Types/Team/ComplianceRuleType.js +2 -2
  1011. package/build/dist/Types/Telemetry/EntityType.js +16 -0
  1012. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  1013. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +13 -2
  1014. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  1015. package/build/dist/Types/XML.js +23 -0
  1016. package/build/dist/Types/XML.js.map +1 -1
  1017. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +641 -266
  1018. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  1019. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js +464 -0
  1020. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js.map +1 -0
  1021. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js +69 -0
  1022. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js.map +1 -0
  1023. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js +108 -0
  1024. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js.map +1 -0
  1025. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +14 -186
  1026. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -1
  1027. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  1028. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  1029. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +5 -14
  1030. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -1
  1031. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +14 -13
  1032. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  1033. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +1 -1
  1034. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  1035. package/build/dist/UI/Components/Forms/Fields/FormField.js +8 -3
  1036. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  1037. package/build/dist/UI/Components/Icon/Icon.js +8 -0
  1038. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  1039. package/build/dist/UI/Components/Input/Input.js +11 -3
  1040. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  1041. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +2 -1
  1042. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1043. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +14 -4
  1044. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  1045. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  1046. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  1047. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +710 -65
  1048. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
  1049. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js +238 -0
  1050. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js.map +1 -0
  1051. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js +1028 -0
  1052. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js.map +1 -0
  1053. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js +1088 -0
  1054. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js.map +1 -0
  1055. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +70 -10
  1056. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  1057. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js +887 -0
  1058. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js.map +1 -0
  1059. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +57 -6
  1060. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1061. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +7 -5
  1062. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
  1063. package/build/dist/UI/Components/Table/EmptyTableMessage.js +51 -0
  1064. package/build/dist/UI/Components/Table/EmptyTableMessage.js.map +1 -0
  1065. package/build/dist/UI/Components/Table/Table.js +30 -11
  1066. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  1067. package/build/dist/UI/Components/Table/TableRow.js +9 -2
  1068. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  1069. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +63 -1
  1070. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -1
  1071. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +4 -2
  1072. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1073. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +91 -10
  1074. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
  1075. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +14 -4
  1076. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  1077. package/build/dist/UI/Components/TextArea/TextArea.js +9 -3
  1078. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  1079. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js +1 -2
  1080. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js.map +1 -1
  1081. package/build/dist/Utils/AI/InvestigationReport.js +71 -11
  1082. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  1083. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js +1462 -0
  1084. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js.map +1 -0
  1085. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js +122 -0
  1086. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js.map +1 -0
  1087. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js +1139 -0
  1088. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js.map +1 -0
  1089. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js +1060 -0
  1090. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js.map +1 -0
  1091. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js +1301 -0
  1092. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js.map +1 -0
  1093. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js +370 -0
  1094. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js.map +1 -0
  1095. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js +498 -0
  1096. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js.map +1 -0
  1097. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js +1565 -0
  1098. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js.map +1 -0
  1099. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js +2206 -0
  1100. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js.map +1 -0
  1101. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js +1129 -0
  1102. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js.map +1 -0
  1103. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js +565 -0
  1104. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js.map +1 -0
  1105. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js +408 -0
  1106. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js.map +1 -0
  1107. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js +1910 -0
  1108. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js.map +1 -0
  1109. package/build/dist/Utils/LabelRuleImportExport.js +2 -0
  1110. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  1111. package/build/dist/Utils/Markdown/UntrustedMarkdown.js +988 -0
  1112. package/build/dist/Utils/Markdown/UntrustedMarkdown.js.map +1 -0
  1113. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js +34 -0
  1114. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js.map +1 -0
  1115. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js +148 -0
  1116. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js.map +1 -0
  1117. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js +160 -0
  1118. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js.map +1 -0
  1119. package/build/dist/Utils/Telemetry/EntityKey.js +36 -0
  1120. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  1121. package/package.json +1 -3
  1122. package/Server/Utils/CommunityEditionSsoReport.ts +0 -361
  1123. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +0 -616
  1124. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +0 -217
  1125. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +0 -271
  1126. package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +0 -215
  1127. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +0 -784
  1128. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +0 -518
  1129. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +0 -419
  1130. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +0 -769
  1131. package/Tests/UI/Components/CodeEditor.test.tsx +0 -638
  1132. package/Tests/UI/Components/MonacoLoader.test.ts +0 -67
  1133. package/Tests/UI/Components/MonacoRuntime.test.ts +0 -121
  1134. package/Tests/UI/Components/Telemetry/TelemetryRetentionConfigForm.test.tsx +0 -329
  1135. package/Tests/UI/Components/YamlEditor.test.tsx +0 -847
  1136. package/UI/Components/CodeEditor/MonacoLoader.ts +0 -36
  1137. package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -319
  1138. package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +0 -223
  1139. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +0 -223
  1140. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +0 -1
  1141. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +0 -34
  1142. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +0 -1
  1143. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +0 -171
  1144. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +0 -1
  1145. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +0 -119
  1146. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js.map +0 -1
@@ -0,0 +1,2036 @@
1
+ // Must stay the first import: the client's URLs are built from HOST on load.
2
+ import { DASHBOARD_ORIGIN } from "../../UI/Utils/API/DashboardHost";
3
+ import FakeAxiosServer, {
4
+ FakeReply,
5
+ FakeTransport,
6
+ SentRequest,
7
+ settle,
8
+ } from "../../UI/Utils/API/FakeAxiosServer";
9
+ import "@testing-library/jest-dom";
10
+ import {
11
+ afterEach,
12
+ beforeEach,
13
+ describe,
14
+ expect,
15
+ jest,
16
+ test,
17
+ } from "@jest/globals";
18
+ import {
19
+ act,
20
+ cleanup,
21
+ fireEvent,
22
+ render,
23
+ screen,
24
+ waitFor,
25
+ within,
26
+ } from "@testing-library/react";
27
+ import axios from "axios";
28
+ import { SpyInstance } from "jest-mock";
29
+ import React from "react";
30
+ import { MemoryRouter, Route, Routes } from "react-router-dom";
31
+ import HTTPMethod from "../../../Types/API/HTTPMethod";
32
+ import CustomFieldType from "../../../Types/CustomField/CustomFieldType";
33
+ import OneUptimeDate from "../../../Types/Date";
34
+ import {
35
+ INCIDENT_FORM_PAGE_HEADER,
36
+ INCIDENT_FORM_PAGE_HEADER_VALUE,
37
+ IncidentFormFieldSetting,
38
+ PublicIncidentForm,
39
+ } from "../../../Types/Incident/IncidentFormPublic";
40
+ import { JSONObject } from "../../../Types/JSON";
41
+ import Email from "../../../Types/Email";
42
+ import ObjectID from "../../../Types/ObjectID";
43
+ import Navigation from "../../../UI/Utils/Navigation";
44
+ import User from "../../../UI/Utils/User";
45
+ import i18n from "../../../../App/FeatureSet/Accounts/src/Utils/i18n";
46
+ import IncidentFormPage from "../../../../App/FeatureSet/Accounts/src/Pages/IncidentForm";
47
+
48
+ jest.mock("axios", () => {
49
+ // Keep the real helpers (axios.isAxiosError, AxiosError) and fake only the call.
50
+ return Object.assign(jest.fn(), jest.requireActual("axios"));
51
+ });
52
+
53
+ /*
54
+ * The captcha settings of this install, switched per test (setCaptcha). They
55
+ * are getters over state the mock itself owns, because the page reads them
56
+ * as it renders - and because this factory runs while the imports above are
57
+ * still loading, before anything declared in this file exists.
58
+ */
59
+ interface MockCaptchaSettings {
60
+ enabled: boolean;
61
+ siteKey: string;
62
+ }
63
+
64
+ jest.mock("../../../UI/Config", () => {
65
+ const actual: Record<string, unknown> = jest.requireActual(
66
+ "../../../UI/Config",
67
+ ) as Record<string, unknown>;
68
+
69
+ const settings: MockCaptchaSettings = { enabled: false, siteKey: "" };
70
+
71
+ const mocked: Record<string, unknown> = {
72
+ ...actual,
73
+ __esModule: true,
74
+ mockCaptchaSettings: settings,
75
+ };
76
+
77
+ Object.defineProperty(mocked, "CAPTCHA_ENABLED", {
78
+ enumerable: true,
79
+ get: (): boolean => {
80
+ return settings.enabled;
81
+ },
82
+ });
83
+
84
+ Object.defineProperty(mocked, "CAPTCHA_SITE_KEY", {
85
+ enumerable: true,
86
+ get: (): string => {
87
+ return settings.siteKey;
88
+ },
89
+ });
90
+
91
+ return mocked;
92
+ });
93
+
94
+ type SetCaptchaFunction = (enabled: boolean, siteKey: string) => void;
95
+
96
+ const setCaptcha: SetCaptchaFunction = (
97
+ enabled: boolean,
98
+ siteKey: string,
99
+ ): void => {
100
+ const settings: MockCaptchaSettings = (
101
+ jest.requireMock("../../../UI/Config") as {
102
+ mockCaptchaSettings: MockCaptchaSettings;
103
+ }
104
+ ).mockCaptchaSettings;
105
+
106
+ settings.enabled = enabled;
107
+ settings.siteKey = siteKey;
108
+ };
109
+
110
+ /*
111
+ * hCaptcha itself loads a script from the network. The stand-in keeps the
112
+ * part of its contract the page relies on: a reset signal clears the token
113
+ * (as the real widget does, on mount and on every new signal), and solving
114
+ * the challenge hands one over - numbered by the reset it was solved after,
115
+ * so a test can tell a fresh token from a spent one.
116
+ */
117
+ interface MockCaptchaProps {
118
+ siteKey: string;
119
+ resetSignal?: number | undefined;
120
+ error?: string | undefined;
121
+ onTokenChange?: ((token: string) => void) | undefined;
122
+ }
123
+
124
+ const MockCaptcha: (props: MockCaptchaProps) => React.ReactElement = (
125
+ props: MockCaptchaProps,
126
+ ): React.ReactElement => {
127
+ const signal: number = props.resetSignal || 0;
128
+
129
+ React.useEffect(() => {
130
+ props.onTokenChange?.("");
131
+ }, [signal]);
132
+
133
+ return (
134
+ <div
135
+ data-testid="captcha"
136
+ data-site-key={props.siteKey}
137
+ data-reset-signal={String(signal)}
138
+ >
139
+ <button
140
+ type="button"
141
+ onClick={() => {
142
+ props.onTokenChange?.(`captcha-token-${signal}`);
143
+ }}
144
+ >
145
+ Solve captcha
146
+ </button>
147
+ {props.error ? <span>{props.error}</span> : <></>}
148
+ </div>
149
+ );
150
+ };
151
+
152
+ jest.mock("../../../UI/Components/Captcha/Captcha", () => {
153
+ return {
154
+ __esModule: true,
155
+ default: (props: MockCaptchaProps): React.ReactElement => {
156
+ return <MockCaptcha {...props} />;
157
+ },
158
+ };
159
+ });
160
+
161
+ /*
162
+ * THE PAGE ANYBODY WITH AN INCIDENT FORM'S LINK OPENS.
163
+ *
164
+ * These drive the real page, the real form and fields, the real
165
+ * IncidentFormAPI and BaseAPI and the core client, with a scripted server
166
+ * where axios would reach the network. The server answers only what each
167
+ * test expects, so a session refresh, a logout request or a second read
168
+ * that should not have happened fails the test naming the request.
169
+ *
170
+ * What is pinned:
171
+ * - the page reads the form behind the link and asks exactly its questions:
172
+ * the title always, the description as the form says, the severity only
173
+ * when the form offers a choice, each custom field it asks, the reporter's
174
+ * details, and a captcha only when the server wants one and this install
175
+ * can draw one;
176
+ * - no Markdown editor on it can upload an image - that needs a signed-in
177
+ * user, and a reporter may be none;
178
+ * - what it sends is the answers and nothing else, custom field answers
179
+ * under each field's name;
180
+ * - every refusal is said on the page, next to the form, and none of them
181
+ * navigates, refreshes a session or signs anybody out - a visitor who is
182
+ * also signed in to OneUptime on this host keeps their session.
183
+ */
184
+
185
+ const mockedAxios: FakeTransport = axios as unknown as FakeTransport;
186
+
187
+ const SHARE_KEY: string = "8a4f2c1e-3b5d-4c6e-9f70-1a2b3c4d5e6f";
188
+
189
+ const FORM_URL: string = `${DASHBOARD_ORIGIN}/api/incident-form/public/${SHARE_KEY}`;
190
+
191
+ const SUBMIT_URL: string = `${FORM_URL}/submit`;
192
+
193
+ const CRITICAL_ID: string = "c1c1c1c1-0000-4000-8000-000000000001";
194
+ const MINOR_ID: string = "c1c1c1c1-0000-4000-8000-000000000002";
195
+
196
+ const NOT_AVAILABLE: string =
197
+ "This form is not available. It may have been turned off, or the link may be out of date.";
198
+ const NETWORK_NOT_ALLOWED: string =
199
+ "This form can only be opened from an allowed network.";
200
+ const TOO_MANY_SUBMISSIONS: string =
201
+ "Too many submissions from your network. Please wait a few minutes and try again.";
202
+ const FORM_BUSY: string =
203
+ "This form is receiving too many reports right now. Please try again later.";
204
+ const TOO_MANY_REQUESTS: string = "Too many requests. Please try again later.";
205
+ const CAPTCHA_FAILED: string = "Captcha verification failed. Please try again.";
206
+ const REPORTS_UNAVAILABLE: string =
207
+ "Reports cannot be accepted right now. Please try again in a few minutes.";
208
+ const SUBMIT_FAILED: string =
209
+ "Your report could not be submitted. Please try again in a few minutes.";
210
+ const LOAD_FAILED: string =
211
+ "This form could not be loaded. Please try again in a few minutes.";
212
+
213
+ /*
214
+ * A form that asks everything it can: an optional description, a choice of
215
+ * severity, one field of every type - and one called "title", which must not
216
+ * become the title's answer.
217
+ */
218
+ const FULL_FORM: PublicIncidentForm = {
219
+ name: "Report a Problem",
220
+ description: "Tell us what is **broken**.",
221
+ descriptionSetting: IncidentFormFieldSetting.Optional,
222
+ isReporterDetailsRequired: true,
223
+ severities: [
224
+ { _id: CRITICAL_ID, name: "Critical", color: "#ff0000" },
225
+ { _id: MINOR_ID, name: "Minor" },
226
+ ],
227
+ defaultIncidentSeverityId: MINOR_ID,
228
+ customFields: [
229
+ {
230
+ name: "Impact",
231
+ description: "Who is affected?",
232
+ customFieldType: CustomFieldType.Text,
233
+ isRequired: true,
234
+ },
235
+ {
236
+ name: "Users Affected",
237
+ customFieldType: CustomFieldType.Number,
238
+ isRequired: false,
239
+ },
240
+ {
241
+ name: "Acknowledged",
242
+ customFieldType: CustomFieldType.Boolean,
243
+ isRequired: true,
244
+ },
245
+ {
246
+ name: "Region",
247
+ customFieldType: CustomFieldType.Dropdown,
248
+ dropdownOptions: "EU\nUS",
249
+ isRequired: false,
250
+ },
251
+ {
252
+ name: "Services",
253
+ customFieldType: CustomFieldType.MultiSelectDropdown,
254
+ dropdownOptions: "API\nWeb",
255
+ isRequired: false,
256
+ },
257
+ {
258
+ name: "Started On",
259
+ customFieldType: CustomFieldType.Date,
260
+ isRequired: false,
261
+ },
262
+ {
263
+ name: "Started At",
264
+ customFieldType: CustomFieldType.DateTime,
265
+ isRequired: false,
266
+ },
267
+ {
268
+ name: "Details",
269
+ customFieldType: CustomFieldType.LongText,
270
+ isRequired: false,
271
+ },
272
+ {
273
+ name: "Notes",
274
+ customFieldType: CustomFieldType.Markdown,
275
+ isRequired: false,
276
+ },
277
+ {
278
+ name: "title",
279
+ customFieldType: CustomFieldType.Text,
280
+ isRequired: false,
281
+ },
282
+ ],
283
+ isCaptchaRequired: false,
284
+ };
285
+
286
+ // The smallest form there is: a title, and the reporter's details.
287
+ const MINIMAL_FORM: PublicIncidentForm = {
288
+ name: "Minimal",
289
+ descriptionSetting: IncidentFormFieldSetting.Hidden,
290
+ isReporterDetailsRequired: true,
291
+ customFields: [],
292
+ isCaptchaRequired: false,
293
+ };
294
+
295
+ let server: FakeAxiosServer;
296
+
297
+ let navigateSpy: SpyInstance<typeof Navigation.navigate>;
298
+
299
+ let logoutSpy: SpyInstance<typeof User.logout>;
300
+
301
+ type SentRequestsFunction = () => Array<string>;
302
+
303
+ const sentRequests: SentRequestsFunction = (): Array<string> => {
304
+ return server.sent.map((request: SentRequest): string => {
305
+ return `${request.method.toUpperCase()} ${request.url}`;
306
+ });
307
+ };
308
+
309
+ type ServeFormFunction = (reply: FakeReply) => void;
310
+
311
+ const serveForm: ServeFormFunction = (reply: FakeReply): void => {
312
+ server.on(HTTPMethod.GET, FORM_URL, [reply]);
313
+ };
314
+
315
+ type ServeSubmitFunction = (reply: FakeReply) => void;
316
+
317
+ const serveSubmit: ServeSubmitFunction = (reply: FakeReply): void => {
318
+ server.on(HTTPMethod.POST, SUBMIT_URL, [reply]);
319
+ };
320
+
321
+ type SubmittedBodiesFunction = () => Array<JSONObject>;
322
+
323
+ const submittedBodies: SubmittedBodiesFunction = (): Array<JSONObject> => {
324
+ return server
325
+ .requestsTo(HTTPMethod.POST, SUBMIT_URL)
326
+ .map((request: SentRequest): JSONObject => {
327
+ return request.data as JSONObject;
328
+ });
329
+ };
330
+
331
+ type FlushFunction = () => Promise<void>;
332
+
333
+ // Lets every answered request, and the renders it causes, finish.
334
+ const flush: FlushFunction = async (): Promise<void> => {
335
+ for (let round: number = 0; round < 5; round++) {
336
+ await act(async () => {
337
+ await settle();
338
+ });
339
+ }
340
+ };
341
+
342
+ type RenderPageFunction = (shareKey?: string) => Promise<void>;
343
+
344
+ const renderPage: RenderPageFunction = async (
345
+ shareKey: string = SHARE_KEY,
346
+ ): Promise<void> => {
347
+ await act(async () => {
348
+ render(
349
+ <MemoryRouter initialEntries={[`/accounts/incident-form/${shareKey}`]}>
350
+ <Routes>
351
+ <Route
352
+ path="/accounts/incident-form/:shareKey"
353
+ element={<IncidentFormPage />}
354
+ />
355
+ </Routes>
356
+ </MemoryRouter>,
357
+ );
358
+ });
359
+
360
+ await flush();
361
+ };
362
+
363
+ type RenderFormFunction = (form: PublicIncidentForm) => Promise<void>;
364
+
365
+ // Serves the form, opens the page, and waits for its first question.
366
+ const renderForm: RenderFormFunction = async (
367
+ form: PublicIncidentForm,
368
+ ): Promise<void> => {
369
+ serveForm({ status: 200, data: form as unknown as JSONObject });
370
+
371
+ await renderPage();
372
+
373
+ await screen.findByTestId("incident-form-title");
374
+ };
375
+
376
+ type TypeFunction = (element: HTMLElement, value: string) => void;
377
+
378
+ const typeInto: TypeFunction = (element: HTMLElement, value: string): void => {
379
+ fireEvent.change(element, { target: { value: value } });
380
+ };
381
+
382
+ type TypeMarkdownFunction = (editable: HTMLElement, html: string) => void;
383
+
384
+ /*
385
+ * The visual Markdown editor reads what was typed from its own HTML on each
386
+ * input event, which is how a browser reports typing into it.
387
+ */
388
+ const typeMarkdown: TypeMarkdownFunction = (
389
+ editable: HTMLElement,
390
+ html: string,
391
+ ): void => {
392
+ editable.innerHTML = html;
393
+ fireEvent.input(editable);
394
+ };
395
+
396
+ type ElementFunction = () => HTMLElement;
397
+
398
+ const descriptionEditor: ElementFunction = (): HTMLElement => {
399
+ return within(screen.getByTestId("incident-form-description")).getByRole(
400
+ "textbox",
401
+ );
402
+ };
403
+
404
+ type PickOptionFunction = (combobox: HTMLElement, optionText: string) => void;
405
+
406
+ // react-select opens on ArrowDown; its options are portalled to document.body.
407
+ const pickOption: PickOptionFunction = (
408
+ combobox: HTMLElement,
409
+ optionText: string,
410
+ ): void => {
411
+ fireEvent.keyDown(combobox, { key: "ArrowDown" });
412
+ const option: HTMLElement = screen.getByRole("option", { name: optionText });
413
+ fireEvent.mouseDown(option);
414
+ fireEvent.click(option);
415
+ };
416
+
417
+ type SubmitFunction = () => Promise<void>;
418
+
419
+ const submit: SubmitFunction = async (): Promise<void> => {
420
+ await act(async () => {
421
+ fireEvent.click(screen.getByRole("button", { name: "Submit" }));
422
+ });
423
+
424
+ await flush();
425
+ };
426
+
427
+ type FillRequiredFunction = () => void;
428
+
429
+ // The answers MINIMAL_FORM requires, and nothing else.
430
+ const fillMinimalForm: FillRequiredFunction = (): void => {
431
+ typeInto(screen.getByTestId("incident-form-title"), "Checkout is down");
432
+ typeInto(screen.getByTestId("incident-form-reporter-name"), "Ada Lovelace");
433
+ typeInto(
434
+ screen.getByTestId("incident-form-reporter-email"),
435
+ "ada@example.com",
436
+ );
437
+ };
438
+
439
+ type ExpectNoSideEffectsFunction = () => void;
440
+
441
+ /*
442
+ * Whatever went wrong, the page said so itself: nothing navigated, nobody
443
+ * was signed out, and no request was made beyond the ones the test served.
444
+ */
445
+ const expectNoNavigationOrLogout: ExpectNoSideEffectsFunction = (): void => {
446
+ expect(navigateSpy).not.toHaveBeenCalled();
447
+ expect(logoutSpy).not.toHaveBeenCalled();
448
+ };
449
+
450
+ beforeEach(() => {
451
+ window.localStorage.clear();
452
+ setCaptcha(false, "");
453
+ server = new FakeAxiosServer(mockedAxios);
454
+
455
+ navigateSpy = jest
456
+ .spyOn(Navigation, "navigate")
457
+ .mockImplementation((): void => {});
458
+
459
+ logoutSpy = jest.spyOn(User, "logout").mockImplementation((): void => {});
460
+ });
461
+
462
+ afterEach(async () => {
463
+ cleanup();
464
+ await settle();
465
+ mockedAxios.mockReset();
466
+ jest.restoreAllMocks();
467
+ window.localStorage.clear();
468
+ document.title = "";
469
+
470
+ if (i18n.language !== "en") {
471
+ await act(async () => {
472
+ await i18n.changeLanguage("en");
473
+ });
474
+ }
475
+ });
476
+
477
+ describe("the page reads the form behind its link", () => {
478
+ test("one GET, through the page's own client, with an empty tenant", async () => {
479
+ await renderForm(FULL_FORM);
480
+
481
+ expect(sentRequests()).toEqual([`GET ${FORM_URL}`]);
482
+
483
+ const headers: Record<string, string> = server.sent[0]!.headers;
484
+
485
+ expect(headers["tenantid"]).toBe("");
486
+ expect(Object.keys(headers)).not.toContain("apikey");
487
+ // The server reads a form only for a request that says it is this page's.
488
+ expect(headers[INCIDENT_FORM_PAGE_HEADER]).toBe(
489
+ INCIDENT_FORM_PAGE_HEADER_VALUE,
490
+ );
491
+ });
492
+
493
+ test("the form's name is the heading, and its description is shown as Markdown", async () => {
494
+ await renderForm(FULL_FORM);
495
+
496
+ expect(
497
+ screen.getByRole("heading", { level: 1, name: "Report a Problem" }),
498
+ ).toBeInTheDocument();
499
+
500
+ const about: HTMLElement = screen.getByTestId("incident-form-about");
501
+
502
+ await waitFor(() => {
503
+ expect(within(about).getByTestId("react-markdown")).toHaveTextContent(
504
+ "Tell us what is **broken**.",
505
+ );
506
+ });
507
+ });
508
+
509
+ test("a form without a description shows none", async () => {
510
+ await renderForm(MINIMAL_FORM);
511
+
512
+ expect(screen.queryByTestId("incident-form-about")).toBeNull();
513
+ });
514
+
515
+ test("the tab is named after the form, and named back on the way out", async () => {
516
+ document.title = "OneUptime Accounts";
517
+
518
+ await renderForm(FULL_FORM);
519
+
520
+ expect(document.title).toBe("Report a Problem");
521
+
522
+ cleanup();
523
+
524
+ expect(document.title).toBe("OneUptime Accounts");
525
+ });
526
+
527
+ test("a form that cannot be opened leaves the tab's name alone", async () => {
528
+ document.title = "OneUptime Accounts";
529
+ serveForm({ status: 404, data: { error: NOT_AVAILABLE } });
530
+
531
+ await renderPage();
532
+
533
+ expect(
534
+ screen.getByTestId("incident-form-load-failure"),
535
+ ).toBeInTheDocument();
536
+ expect(document.title).toBe("OneUptime Accounts");
537
+ });
538
+
539
+ test("while the form loads, the page shows a loader and no form", async () => {
540
+ let releaseForm: () => void = (): void => {};
541
+ const gate: Promise<void> = new Promise<void>((resolve: () => void) => {
542
+ releaseForm = resolve;
543
+ });
544
+
545
+ serveForm({
546
+ status: 200,
547
+ data: MINIMAL_FORM as unknown as JSONObject,
548
+ gate: gate,
549
+ });
550
+
551
+ await renderPage();
552
+
553
+ expect(screen.queryByTestId("incident-form-title")).toBeNull();
554
+ expect(screen.queryByRole("heading", { level: 1 })).toBeNull();
555
+
556
+ releaseForm();
557
+ await flush();
558
+
559
+ expect(screen.getByTestId("incident-form-title")).toBeInTheDocument();
560
+ });
561
+ });
562
+
563
+ describe("the questions are the form's", () => {
564
+ test("the title is always asked, required, with its help text and limit", async () => {
565
+ await renderForm(MINIMAL_FORM);
566
+
567
+ expect(screen.getByLabelText(/^Title/)).toBe(
568
+ screen.getByTestId("incident-form-title"),
569
+ );
570
+ expect(
571
+ screen.getByText("A short summary of what is wrong."),
572
+ ).toBeInTheDocument();
573
+
574
+ typeInto(screen.getByTestId("incident-form-title"), "x".repeat(501));
575
+ await submit();
576
+
577
+ expect(
578
+ screen.getByText("Title cannot be more than 500 characters."),
579
+ ).toBeInTheDocument();
580
+ expect(submittedBodies()).toEqual([]);
581
+ });
582
+
583
+ test("every custom field type is drawn with its own input", async () => {
584
+ await renderForm(FULL_FORM);
585
+
586
+ expect(screen.getByLabelText(/^Impact/)).toHaveAttribute("type", "text");
587
+ expect(screen.getByText("Who is affected?")).toBeInTheDocument();
588
+ expect(screen.getByLabelText(/^Users Affected/)).toHaveAttribute(
589
+ "type",
590
+ "number",
591
+ );
592
+ expect(
593
+ screen.getByRole("switch", { name: /Acknowledged/ }),
594
+ ).toBeInTheDocument();
595
+ expect(
596
+ screen.getByRole("combobox", { name: /^Region/ }),
597
+ ).toBeInTheDocument();
598
+ expect(
599
+ screen.getByRole("combobox", { name: /^Services/ }),
600
+ ).toBeInTheDocument();
601
+ expect(screen.getByLabelText(/^Started On/)).toHaveAttribute(
602
+ "type",
603
+ "date",
604
+ );
605
+ expect(screen.getByLabelText(/^Started At/)).toHaveAttribute(
606
+ "type",
607
+ "datetime-local",
608
+ );
609
+ expect(screen.getByLabelText(/^Details/).tagName).toBe("TEXTAREA");
610
+ expect(screen.getByRole("textbox", { name: /^Notes/ })).toHaveAttribute(
611
+ "contenteditable",
612
+ "true",
613
+ );
614
+ // The field called "title" is its own input, not the title's.
615
+ expect(screen.getByLabelText(/^title/)).not.toBe(
616
+ screen.getByTestId("incident-form-title"),
617
+ );
618
+ });
619
+
620
+ test("required and optional follow the form", async () => {
621
+ await renderForm(FULL_FORM);
622
+
623
+ const labelOf: (text: RegExp) => string = (text: RegExp): string => {
624
+ return screen.getByText(text, { selector: "label *" }).closest("label")!
625
+ .textContent as string;
626
+ };
627
+
628
+ // Required: no "(Optional)" next to the label.
629
+ expect(labelOf(/^Title/)).not.toContain("(Optional)");
630
+ expect(labelOf(/^Impact/)).not.toContain("(Optional)");
631
+ expect(labelOf(/^Acknowledged/)).not.toContain("(Optional)");
632
+ expect(labelOf(/^Your Name/)).not.toContain("(Optional)");
633
+ expect(labelOf(/^Your Email/)).not.toContain("(Optional)");
634
+
635
+ expect(labelOf(/^Description/)).toContain("(Optional)");
636
+ expect(labelOf(/^Severity/)).toContain("(Optional)");
637
+ expect(labelOf(/^Users Affected/)).toContain("(Optional)");
638
+ expect(labelOf(/^Notes/)).toContain("(Optional)");
639
+ });
640
+
641
+ test("a Required description must be written, and a blank one is refused in the browser", async () => {
642
+ await renderForm({
643
+ ...MINIMAL_FORM,
644
+ descriptionSetting: IncidentFormFieldSetting.Required,
645
+ });
646
+
647
+ fillMinimalForm();
648
+ await submit();
649
+
650
+ expect(screen.getByText("Description is required.")).toBeInTheDocument();
651
+
652
+ typeMarkdown(descriptionEditor(), "<p> </p>");
653
+ await submit();
654
+
655
+ expect(submittedBodies()).toEqual([]);
656
+ });
657
+
658
+ test("a Hidden description is not asked, and not sent", async () => {
659
+ serveSubmit({ status: 200, data: {} });
660
+
661
+ await renderForm(MINIMAL_FORM);
662
+
663
+ expect(screen.queryByTestId("incident-form-description")).toBeNull();
664
+
665
+ fillMinimalForm();
666
+ await submit();
667
+
668
+ expect(submittedBodies()).toHaveLength(1);
669
+ expect(Object.keys(submittedBodies()[0]!["data"] as JSONObject)).toEqual([
670
+ "title",
671
+ "reporterName",
672
+ "reporterEmail",
673
+ ]);
674
+ });
675
+
676
+ test("the severity is only asked when the form offers a choice", async () => {
677
+ await renderForm(MINIMAL_FORM);
678
+
679
+ expect(screen.queryByTestId("incident-form-severity")).toBeNull();
680
+ expect(screen.queryByRole("combobox", { name: /^Severity/ })).toBeNull();
681
+ });
682
+
683
+ test("the offered severities are listed in order, the form's own preselected", async () => {
684
+ await renderForm(FULL_FORM);
685
+
686
+ const severity: HTMLElement = screen.getByRole("combobox", {
687
+ name: /^Severity/,
688
+ });
689
+
690
+ // The form's own severity is what is showing.
691
+ expect(severity.closest(".ou-select__control")).toHaveTextContent("Minor");
692
+
693
+ fireEvent.keyDown(severity, { key: "ArrowDown" });
694
+
695
+ const options: Array<string> = screen
696
+ .getAllByRole("option")
697
+ .map((option: HTMLElement): string => {
698
+ return option.textContent || "";
699
+ });
700
+
701
+ expect(options).toEqual(["Critical", "Minor"]);
702
+ });
703
+
704
+ test("reporter details are optional when the form says so", async () => {
705
+ serveSubmit({ status: 200, data: {} });
706
+
707
+ await renderForm({ ...MINIMAL_FORM, isReporterDetailsRequired: false });
708
+
709
+ typeInto(screen.getByTestId("incident-form-title"), "Checkout is down");
710
+ await submit();
711
+
712
+ expect(submittedBodies()).toEqual([
713
+ { data: { title: "Checkout is down" } },
714
+ ]);
715
+ });
716
+
717
+ test("required reporter details are asked for, and the email must be one", async () => {
718
+ await renderForm(MINIMAL_FORM);
719
+
720
+ typeInto(screen.getByTestId("incident-form-title"), "Checkout is down");
721
+ await submit();
722
+
723
+ expect(screen.getByText("Your Name is required.")).toBeInTheDocument();
724
+ expect(screen.getByText("Your Email is required.")).toBeInTheDocument();
725
+
726
+ typeInto(screen.getByTestId("incident-form-reporter-name"), " ");
727
+ typeInto(
728
+ screen.getByTestId("incident-form-reporter-email"),
729
+ "not-an-email",
730
+ );
731
+ await submit();
732
+
733
+ expect(screen.getByText("Your Name is required.")).toBeInTheDocument();
734
+ expect(screen.getByText("Email is not valid.")).toBeInTheDocument();
735
+ expect(submittedBodies()).toEqual([]);
736
+ });
737
+
738
+ /*
739
+ * The form's own email check finds an address anywhere in the text; the
740
+ * server wants the whole answer to be one address. What it would refuse -
741
+ * in English, after the captcha answer was spent - is refused here first.
742
+ */
743
+ test.each([
744
+ ["with a trailing dot", "ada@example.com."],
745
+ ["as Outlook copies it", "Ada Lovelace <ada@example.com>"],
746
+ ["as a list", "ada@example.com, bob@example.com"],
747
+ ["as a mailto link", "mailto:ada@example.com"],
748
+ ])(
749
+ "an email %s is refused in the browser, before the captcha is spent",
750
+ async (_case: string, email: string) => {
751
+ setCaptcha(true, "site-key-1");
752
+
753
+ await renderForm({ ...MINIMAL_FORM, isCaptchaRequired: true });
754
+
755
+ fillMinimalForm();
756
+ typeInto(screen.getByTestId("incident-form-reporter-email"), email);
757
+ fireEvent.click(screen.getByRole("button", { name: "Solve captcha" }));
758
+ await submit();
759
+
760
+ expect(screen.getByText("Email is not valid.")).toBeInTheDocument();
761
+ expect(submittedBodies()).toEqual([]);
762
+ expect(screen.getByTestId("captcha")).toHaveAttribute(
763
+ "data-reset-signal",
764
+ "0",
765
+ );
766
+ },
767
+ );
768
+
769
+ test("in German, an email the server would refuse is refused in German", async () => {
770
+ await act(async () => {
771
+ await i18n.changeLanguage("de");
772
+ });
773
+
774
+ serveForm({ status: 200, data: MINIMAL_FORM as unknown as JSONObject });
775
+ await renderPage();
776
+
777
+ fillMinimalForm();
778
+ typeInto(
779
+ screen.getByTestId("incident-form-reporter-email"),
780
+ "Ada Lovelace <ada@example.com>",
781
+ );
782
+
783
+ await act(async () => {
784
+ fireEvent.click(screen.getByRole("button", { name: "Senden" }));
785
+ });
786
+ await flush();
787
+
788
+ expect(screen.getByText("E-Mail ist ungültig.")).toBeInTheDocument();
789
+ expect(submittedBodies()).toEqual([]);
790
+ });
791
+
792
+ test("an ordinary address, in any case, is sent", async () => {
793
+ serveSubmit({ status: 200, data: {} });
794
+
795
+ await renderForm(MINIMAL_FORM);
796
+
797
+ fillMinimalForm();
798
+ typeInto(
799
+ screen.getByTestId("incident-form-reporter-email"),
800
+ "Ada.Lovelace+reports@Mail.Example.co.uk",
801
+ );
802
+ await submit();
803
+
804
+ expect(screen.queryByText("Email is not valid.")).toBeNull();
805
+ expect(submittedBodies()).toHaveLength(1);
806
+ expect((submittedBodies()[0]!["data"] as JSONObject)["reporterEmail"]).toBe(
807
+ "ada.lovelace+reports@mail.example.co.uk",
808
+ );
809
+ });
810
+
811
+ test("a title of nothing but spaces is refused in the browser", async () => {
812
+ await renderForm(MINIMAL_FORM);
813
+
814
+ fillMinimalForm();
815
+ typeInto(screen.getByTestId("incident-form-title"), " ");
816
+ await submit();
817
+
818
+ expect(screen.getByText("Title is required.")).toBeInTheDocument();
819
+ expect(submittedBodies()).toEqual([]);
820
+ });
821
+
822
+ /*
823
+ * The server cleans every text answer before it asks whether there is
824
+ * one, so an answer of nothing but spaces - or line breaks, or a pasted
825
+ * tab - is refused there: in English, after a captcha answer was spent.
826
+ * The browser refuses it first, in the reporter's language.
827
+ */
828
+ test("a required custom text answer of nothing but spaces is refused in the browser", async () => {
829
+ await renderForm({
830
+ ...MINIMAL_FORM,
831
+ customFields: [
832
+ {
833
+ name: "Impact",
834
+ customFieldType: CustomFieldType.Text,
835
+ isRequired: true,
836
+ },
837
+ {
838
+ name: "Details",
839
+ customFieldType: CustomFieldType.LongText,
840
+ isRequired: true,
841
+ },
842
+ {
843
+ name: "Notes",
844
+ customFieldType: CustomFieldType.Markdown,
845
+ isRequired: true,
846
+ },
847
+ ],
848
+ });
849
+
850
+ fillMinimalForm();
851
+ typeInto(screen.getByLabelText(/^Impact/), " ");
852
+ typeInto(screen.getByLabelText(/^Details/), " \n\t ");
853
+
854
+ // Typed in the editor's source mode, which sends what was typed.
855
+ fireEvent.click(screen.getByTitle("Switch to markdown source"));
856
+ typeInto(screen.getByRole("textbox", { name: /^Notes/ }), " ");
857
+
858
+ await submit();
859
+
860
+ expect(screen.getByText("Impact is required.")).toBeInTheDocument();
861
+ expect(screen.getByText("Details is required.")).toBeInTheDocument();
862
+ expect(screen.getByText("Notes is required.")).toBeInTheDocument();
863
+ expect(submittedBodies()).toEqual([]);
864
+ });
865
+
866
+ test("in German, with a captcha, the refusal is German and the captcha answer is not spent", async () => {
867
+ setCaptcha(true, "site-key-1");
868
+
869
+ await act(async () => {
870
+ await i18n.changeLanguage("de");
871
+ });
872
+
873
+ serveForm({
874
+ status: 200,
875
+ data: {
876
+ ...MINIMAL_FORM,
877
+ isCaptchaRequired: true,
878
+ customFields: [
879
+ {
880
+ name: "Impact",
881
+ customFieldType: CustomFieldType.Text,
882
+ isRequired: true,
883
+ },
884
+ ],
885
+ } as unknown as JSONObject,
886
+ });
887
+ await renderPage();
888
+
889
+ fillMinimalForm();
890
+ typeInto(screen.getByLabelText(/^Impact/), " ");
891
+ fireEvent.click(screen.getByRole("button", { name: "Solve captcha" }));
892
+
893
+ await act(async () => {
894
+ fireEvent.click(screen.getByRole("button", { name: "Senden" }));
895
+ });
896
+ await flush();
897
+
898
+ expect(screen.getByText("Impact ist erforderlich.")).toBeInTheDocument();
899
+ expect(submittedBodies()).toEqual([]);
900
+ expect(screen.getByTestId("captcha")).toHaveAttribute(
901
+ "data-reset-signal",
902
+ "0",
903
+ );
904
+ });
905
+
906
+ test("an optional custom text answer of spaces is simply no answer", async () => {
907
+ serveSubmit({ status: 200, data: {} });
908
+
909
+ await renderForm({
910
+ ...MINIMAL_FORM,
911
+ customFields: [
912
+ {
913
+ name: "Impact",
914
+ customFieldType: CustomFieldType.Text,
915
+ isRequired: false,
916
+ },
917
+ ],
918
+ });
919
+
920
+ fillMinimalForm();
921
+ typeInto(screen.getByLabelText(/^Impact/), " ");
922
+ await submit();
923
+
924
+ expect(screen.queryByText("Impact is required.")).toBeNull();
925
+ expect(submittedBodies()).toHaveLength(1);
926
+ });
927
+
928
+ test("a required custom field and a required yes/no are asked for", async () => {
929
+ await renderForm(FULL_FORM);
930
+
931
+ typeInto(screen.getByTestId("incident-form-title"), "Checkout is down");
932
+ await submit();
933
+
934
+ expect(screen.getByText("Impact is required.")).toBeInTheDocument();
935
+ // Never touched: it has no answer at all yet.
936
+ expect(screen.getByText("Acknowledged is required.")).toBeInTheDocument();
937
+
938
+ // Ticked and unticked again: an answer, and the wrong one.
939
+ const acknowledged: HTMLElement = screen.getByRole("switch", {
940
+ name: /Acknowledged/,
941
+ });
942
+
943
+ fireEvent.click(acknowledged);
944
+ fireEvent.click(acknowledged);
945
+ await submit();
946
+
947
+ expect(
948
+ screen.getByText("Acknowledged must be checked."),
949
+ ).toBeInTheDocument();
950
+ expect(submittedBodies()).toEqual([]);
951
+ });
952
+ });
953
+
954
+ describe("no Markdown editor on the page can upload an image", () => {
955
+ test("not the description's, and not a Markdown custom field's", async () => {
956
+ await renderForm(FULL_FORM);
957
+
958
+ // Both editors are there...
959
+ expect(screen.getByTestId("incident-form-description")).toBeInTheDocument();
960
+ expect(screen.getByRole("textbox", { name: /^Notes/ })).toBeInTheDocument();
961
+
962
+ // ...and neither offers an image.
963
+ expect(screen.queryAllByTitle("Image")).toEqual([]);
964
+ expect(document.querySelectorAll('input[type="file"]')).toHaveLength(0);
965
+ });
966
+ });
967
+
968
+ describe("the captcha", () => {
969
+ test("is shown when the server asks for one and this install can draw one", async () => {
970
+ setCaptcha(true, "site-key-1");
971
+
972
+ await renderForm({ ...MINIMAL_FORM, isCaptchaRequired: true });
973
+
974
+ expect(screen.getByTestId("captcha")).toHaveAttribute(
975
+ "data-site-key",
976
+ "site-key-1",
977
+ );
978
+ expect(screen.getByText("Human Verification")).toBeInTheDocument();
979
+ });
980
+
981
+ test.each([
982
+ ["the form does not ask for one", true, "site-key-1", false],
983
+ ["captcha is turned off here", false, "site-key-1", true],
984
+ ["there is no site key", true, "", true],
985
+ ])(
986
+ "is not shown when %s",
987
+ async (
988
+ _case: string,
989
+ enabled: boolean,
990
+ siteKey: string,
991
+ isCaptchaRequired: boolean,
992
+ ) => {
993
+ setCaptcha(enabled, siteKey);
994
+
995
+ await renderForm({ ...MINIMAL_FORM, isCaptchaRequired });
996
+
997
+ expect(screen.queryByTestId("captcha")).toBeNull();
998
+ expect(screen.queryByText("Human Verification")).toBeNull();
999
+ },
1000
+ );
1001
+
1002
+ test("must be solved, its token is sent, and a failed submit gets a fresh challenge", async () => {
1003
+ setCaptcha(true, "site-key-1");
1004
+
1005
+ await renderForm({ ...MINIMAL_FORM, isCaptchaRequired: true });
1006
+
1007
+ fillMinimalForm();
1008
+ await submit();
1009
+
1010
+ expect(
1011
+ screen.getByText("Human Verification is required."),
1012
+ ).toBeInTheDocument();
1013
+ expect(submittedBodies()).toEqual([]);
1014
+
1015
+ // Solved: the token rides with the answers.
1016
+ serveSubmit({ status: 400, data: { error: CAPTCHA_FAILED } });
1017
+ fireEvent.click(screen.getByRole("button", { name: "Solve captcha" }));
1018
+ await submit();
1019
+
1020
+ expect(submittedBodies()).toHaveLength(1);
1021
+ expect(submittedBodies()[0]!["captchaToken"]).toBe("captcha-token-0");
1022
+ expect(screen.getByTestId("incident-form-submit-error")).toHaveTextContent(
1023
+ CAPTCHA_FAILED,
1024
+ );
1025
+
1026
+ // The token is spent: a new challenge, and the old answer is gone.
1027
+ expect(screen.getByTestId("captcha")).toHaveAttribute(
1028
+ "data-reset-signal",
1029
+ "1",
1030
+ );
1031
+
1032
+ await submit();
1033
+
1034
+ expect(submittedBodies()).toHaveLength(1);
1035
+ expect(
1036
+ screen.getByText("Human Verification is required."),
1037
+ ).toBeInTheDocument();
1038
+
1039
+ serveSubmit({ status: 200, data: { incidentNumber: "INC-7" } });
1040
+ fireEvent.click(screen.getByRole("button", { name: "Solve captcha" }));
1041
+ await submit();
1042
+
1043
+ expect(submittedBodies()).toHaveLength(2);
1044
+ expect(submittedBodies()[1]!["captchaToken"]).toBe("captcha-token-1");
1045
+ expect(screen.getByTestId("incident-form-success")).toBeInTheDocument();
1046
+ });
1047
+
1048
+ test("any failed submit resets it - answers refused, not only the captcha", async () => {
1049
+ setCaptcha(true, "site-key-1");
1050
+
1051
+ await renderForm({ ...MINIMAL_FORM, isCaptchaRequired: true });
1052
+
1053
+ serveSubmit({ status: 500, data: { error: "Server Error" } });
1054
+ fillMinimalForm();
1055
+ fireEvent.click(screen.getByRole("button", { name: "Solve captcha" }));
1056
+ await submit();
1057
+
1058
+ expect(screen.getByTestId("captcha")).toHaveAttribute(
1059
+ "data-reset-signal",
1060
+ "1",
1061
+ );
1062
+ });
1063
+
1064
+ test("with no captcha, no token is sent at all", async () => {
1065
+ serveSubmit({ status: 200, data: {} });
1066
+
1067
+ await renderForm(MINIMAL_FORM);
1068
+
1069
+ fillMinimalForm();
1070
+ await submit();
1071
+
1072
+ expect(Object.keys(submittedBodies()[0]!)).toEqual(["data"]);
1073
+ });
1074
+ });
1075
+
1076
+ describe("what the page sends", () => {
1077
+ test("the answers, each custom field under its name - and nothing else", async () => {
1078
+ serveSubmit({ status: 200, data: { incidentNumber: "INC-42" } });
1079
+
1080
+ await renderForm(FULL_FORM);
1081
+
1082
+ typeInto(
1083
+ screen.getByTestId("incident-form-title"),
1084
+ " Checkout is down ",
1085
+ );
1086
+ typeMarkdown(
1087
+ descriptionEditor(),
1088
+ "<p>Payments fail with <strong>500</strong></p>",
1089
+ );
1090
+ pickOption(screen.getByRole("combobox", { name: /^Severity/ }), "Critical");
1091
+ typeInto(screen.getByLabelText(/^Impact/), "Every customer");
1092
+ typeInto(screen.getByLabelText(/^Users Affected/), "0");
1093
+ fireEvent.click(screen.getByRole("switch", { name: /Acknowledged/ }));
1094
+ pickOption(screen.getByRole("combobox", { name: /^Region/ }), "EU");
1095
+ pickOption(screen.getByRole("combobox", { name: /^Services/ }), "API");
1096
+ typeInto(screen.getByLabelText(/^Started On/), "2026-09-29");
1097
+ typeInto(screen.getByLabelText(/^Details/), "Line one\nLine two");
1098
+ typeMarkdown(
1099
+ screen.getByRole("textbox", { name: /^Notes/ }),
1100
+ "<p>See <em>logs</em></p>",
1101
+ );
1102
+ typeInto(screen.getByLabelText(/^title/), "Not the title");
1103
+ typeInto(
1104
+ screen.getByTestId("incident-form-reporter-name"),
1105
+ " Ada Lovelace ",
1106
+ );
1107
+ typeInto(
1108
+ screen.getByTestId("incident-form-reporter-email"),
1109
+ "Ada@Example.com",
1110
+ );
1111
+
1112
+ await submit();
1113
+
1114
+ expect(submittedBodies()).toEqual([
1115
+ {
1116
+ data: {
1117
+ title: "Checkout is down",
1118
+ description: "Payments fail with **500**",
1119
+ incidentSeverityId: CRITICAL_ID,
1120
+ reporterName: "Ada Lovelace",
1121
+ reporterEmail: "ada@example.com",
1122
+ customFields: {
1123
+ Impact: "Every customer",
1124
+ "Users Affected": "0",
1125
+ Acknowledged: true,
1126
+ Region: "EU",
1127
+ Services: ["API"],
1128
+ "Started On": OneUptimeDate.toString(
1129
+ OneUptimeDate.fromDateTimeLocalString("2026-09-29"),
1130
+ ),
1131
+ Details: "Line one\nLine two",
1132
+ Notes: "See *logs*",
1133
+ title: "Not the title",
1134
+ },
1135
+ },
1136
+ },
1137
+ ]);
1138
+ });
1139
+
1140
+ test("the form's own severity is sent when the reporter leaves it", async () => {
1141
+ serveSubmit({ status: 200, data: {} });
1142
+
1143
+ await renderForm({ ...FULL_FORM, customFields: [] });
1144
+
1145
+ fillMinimalForm();
1146
+ await submit();
1147
+
1148
+ expect(
1149
+ (submittedBodies()[0]!["data"] as JSONObject)["incidentSeverityId"],
1150
+ ).toBe(MINOR_ID);
1151
+ });
1152
+
1153
+ test("with no severity preselected and none picked, none is sent", async () => {
1154
+ serveSubmit({ status: 200, data: {} });
1155
+
1156
+ const form: PublicIncidentForm = { ...FULL_FORM, customFields: [] };
1157
+ delete form.defaultIncidentSeverityId;
1158
+
1159
+ await renderForm(form);
1160
+
1161
+ fillMinimalForm();
1162
+ await submit();
1163
+
1164
+ expect(
1165
+ Object.keys(submittedBodies()[0]!["data"] as JSONObject),
1166
+ ).not.toContain("incidentSeverityId");
1167
+ });
1168
+
1169
+ test("an unticked optional yes/no is an answer: No", async () => {
1170
+ serveSubmit({ status: 200, data: {} });
1171
+
1172
+ await renderForm({
1173
+ ...MINIMAL_FORM,
1174
+ customFields: [
1175
+ {
1176
+ name: "Customer Facing",
1177
+ customFieldType: CustomFieldType.Boolean,
1178
+ isRequired: false,
1179
+ },
1180
+ ],
1181
+ });
1182
+
1183
+ fillMinimalForm();
1184
+ await submit();
1185
+
1186
+ expect(
1187
+ (submittedBodies()[0]!["data"] as JSONObject)["customFields"],
1188
+ ).toEqual({ "Customer Facing": false });
1189
+ });
1190
+
1191
+ test("a submit that is still in flight cannot be sent twice", async () => {
1192
+ let releaseSubmit: () => void = (): void => {};
1193
+ const gate: Promise<void> = new Promise<void>((resolve: () => void) => {
1194
+ releaseSubmit = resolve;
1195
+ });
1196
+
1197
+ serveSubmit({ status: 200, data: {}, gate: gate });
1198
+
1199
+ await renderForm(MINIMAL_FORM);
1200
+
1201
+ fillMinimalForm();
1202
+ await submit();
1203
+
1204
+ /*
1205
+ * The button is disabled while the report is on its way, but Enter in a
1206
+ * text field still submits the form - the page must not send it again.
1207
+ */
1208
+ await act(async () => {
1209
+ fireEvent.keyDown(screen.getByTestId("incident-form-title"), {
1210
+ key: "Enter",
1211
+ });
1212
+ });
1213
+ await flush();
1214
+
1215
+ expect(submittedBodies()).toHaveLength(1);
1216
+
1217
+ releaseSubmit();
1218
+ await flush();
1219
+
1220
+ expect(screen.getByTestId("incident-form-success")).toBeInTheDocument();
1221
+ });
1222
+ });
1223
+
1224
+ describe("after the report is sent", () => {
1225
+ test("the thank-you screen names the incident and shows the form's message", async () => {
1226
+ serveSubmit({
1227
+ status: 200,
1228
+ data: {
1229
+ incidentNumber: "INC-42",
1230
+ successMessage: "We are **on it**.",
1231
+ },
1232
+ });
1233
+
1234
+ await renderForm(MINIMAL_FORM);
1235
+
1236
+ fillMinimalForm();
1237
+ await submit();
1238
+
1239
+ const success: HTMLElement = screen.getByTestId("incident-form-success");
1240
+
1241
+ expect(
1242
+ within(success).getByRole("heading", {
1243
+ name: "Thank you — your report was submitted.",
1244
+ }),
1245
+ ).toBeInTheDocument();
1246
+ expect(
1247
+ screen.getByTestId("incident-form-incident-number"),
1248
+ ).toHaveTextContent("Your report is incident INC-42.");
1249
+
1250
+ await waitFor(() => {
1251
+ expect(
1252
+ within(screen.getByTestId("incident-form-success-message")).getByTestId(
1253
+ "react-markdown",
1254
+ ),
1255
+ ).toHaveTextContent("We are **on it**.");
1256
+ });
1257
+
1258
+ // Still under the form's name; the form itself is gone.
1259
+ expect(
1260
+ screen.getByRole("heading", { level: 1, name: "Minimal" }),
1261
+ ).toBeInTheDocument();
1262
+ expect(screen.queryByTestId("incident-form-title")).toBeNull();
1263
+ expect(window.scrollTo).toHaveBeenCalledWith(0, 0);
1264
+ });
1265
+
1266
+ test("a project without a prefix gets its incident as #42", async () => {
1267
+ serveSubmit({ status: 200, data: { incidentNumber: "#42" } });
1268
+
1269
+ await renderForm(MINIMAL_FORM);
1270
+
1271
+ fillMinimalForm();
1272
+ await submit();
1273
+
1274
+ expect(
1275
+ screen.getByTestId("incident-form-incident-number"),
1276
+ ).toHaveTextContent("Your report is incident #42.");
1277
+ });
1278
+
1279
+ test("with no number and no message, it simply says thank you", async () => {
1280
+ serveSubmit({ status: 200, data: {} });
1281
+
1282
+ await renderForm(MINIMAL_FORM);
1283
+
1284
+ fillMinimalForm();
1285
+ await submit();
1286
+
1287
+ expect(screen.getByTestId("incident-form-success")).toBeInTheDocument();
1288
+ expect(screen.queryByTestId("incident-form-incident-number")).toBeNull();
1289
+ expect(screen.queryByTestId("incident-form-success-message")).toBeNull();
1290
+ });
1291
+
1292
+ /*
1293
+ * The form, and the Submit button that had focus, are gone. Unless focus
1294
+ * moves to what replaced them, it falls to <body> and a screen reader user
1295
+ * hears nothing - not that the report went through, not its number.
1296
+ */
1297
+ test("focus moves to the thank-you heading, which is read out with the incident number", async () => {
1298
+ serveSubmit({ status: 200, data: { incidentNumber: "INC-42" } });
1299
+
1300
+ await renderForm(MINIMAL_FORM);
1301
+
1302
+ // Nothing takes focus on arrival: the reporter reads the form first.
1303
+ expect(document.body).toHaveFocus();
1304
+
1305
+ fillMinimalForm();
1306
+ screen.getByRole("button", { name: "Submit" }).focus();
1307
+ await submit();
1308
+
1309
+ const heading: HTMLElement = within(
1310
+ screen.getByTestId("incident-form-success"),
1311
+ ).getByRole("heading", { name: "Thank you — your report was submitted." });
1312
+
1313
+ expect(heading).toHaveFocus();
1314
+ expect(heading).toHaveAccessibleDescription(
1315
+ "Your report is incident INC-42.",
1316
+ );
1317
+ });
1318
+
1319
+ test("with no incident number, the heading still takes focus, with nothing read out after it", async () => {
1320
+ serveSubmit({ status: 200, data: {} });
1321
+
1322
+ await renderForm(MINIMAL_FORM);
1323
+
1324
+ fillMinimalForm();
1325
+ screen.getByRole("button", { name: "Submit" }).focus();
1326
+ await submit();
1327
+
1328
+ const heading: HTMLElement = within(
1329
+ screen.getByTestId("incident-form-success"),
1330
+ ).getByRole("heading", { name: "Thank you — your report was submitted." });
1331
+
1332
+ expect(heading).toHaveFocus();
1333
+ expect(heading).not.toHaveAttribute("aria-describedby");
1334
+ });
1335
+
1336
+ test("another report starts with focus on its first question", async () => {
1337
+ serveSubmit({ status: 200, data: { incidentNumber: "INC-42" } });
1338
+
1339
+ await renderForm(MINIMAL_FORM);
1340
+
1341
+ fillMinimalForm();
1342
+ await submit();
1343
+
1344
+ const another: HTMLElement = screen.getByTestId(
1345
+ "incident-form-submit-another",
1346
+ );
1347
+
1348
+ another.focus();
1349
+
1350
+ await act(async () => {
1351
+ fireEvent.click(another);
1352
+ });
1353
+ await flush();
1354
+
1355
+ expect(screen.getByTestId("incident-form-title")).toHaveFocus();
1356
+ });
1357
+
1358
+ test("another report starts from an empty form, without reading it again", async () => {
1359
+ serveSubmit({ status: 200, data: { incidentNumber: "INC-42" } });
1360
+
1361
+ await renderForm(MINIMAL_FORM);
1362
+
1363
+ fillMinimalForm();
1364
+ await submit();
1365
+
1366
+ await act(async () => {
1367
+ fireEvent.click(screen.getByTestId("incident-form-submit-another"));
1368
+ });
1369
+ await flush();
1370
+
1371
+ expect(screen.getByTestId("incident-form-title")).toHaveValue("");
1372
+ expect(screen.getByTestId("incident-form-reporter-email")).toHaveValue("");
1373
+ expect(screen.queryByTestId("incident-form-submit-error")).toBeNull();
1374
+
1375
+ // The form was read once; nothing else was asked of the server.
1376
+ expect(sentRequests()).toEqual([`GET ${FORM_URL}`, `POST ${SUBMIT_URL}`]);
1377
+
1378
+ serveSubmit({ status: 200, data: { incidentNumber: "INC-43" } });
1379
+ fillMinimalForm();
1380
+ await submit();
1381
+
1382
+ expect(
1383
+ screen.getByTestId("incident-form-incident-number"),
1384
+ ).toHaveTextContent("Your report is incident INC-43.");
1385
+ });
1386
+ });
1387
+
1388
+ describe("a form that cannot be opened says why, on the page", () => {
1389
+ test.each([
1390
+ ["404", { status: 404, data: { error: NOT_AVAILABLE } }, NOT_AVAILABLE],
1391
+ [
1392
+ "404 with a body that is not the server's",
1393
+ { status: 404, data: { error: "Route not found" } },
1394
+ NOT_AVAILABLE,
1395
+ ],
1396
+ [
1397
+ "403",
1398
+ { status: 403, data: { error: NETWORK_NOT_ALLOWED } },
1399
+ NETWORK_NOT_ALLOWED,
1400
+ ],
1401
+ ])(
1402
+ "%s: no way to try again, because trying again changes nothing",
1403
+ async (_case: string, reply: FakeReply, message: string) => {
1404
+ serveForm(reply);
1405
+
1406
+ await renderPage();
1407
+
1408
+ const failure: HTMLElement = screen.getByTestId(
1409
+ "incident-form-load-failure",
1410
+ );
1411
+
1412
+ expect(
1413
+ within(failure).getByRole("heading", { level: 1 }),
1414
+ ).toHaveTextContent(message);
1415
+ expect(screen.queryByTestId("incident-form-try-again")).toBeNull();
1416
+ expect(sentRequests()).toEqual([`GET ${FORM_URL}`]);
1417
+ expectNoNavigationOrLogout();
1418
+ },
1419
+ );
1420
+
1421
+ test.each([
1422
+ [
1423
+ "429 with Retry-After",
1424
+ {
1425
+ status: 429,
1426
+ data: { message: TOO_MANY_REQUESTS },
1427
+ headers: { "retry-after": "120" },
1428
+ },
1429
+ TOO_MANY_REQUESTS,
1430
+ "You can try again in 2 minutes.",
1431
+ ],
1432
+ [
1433
+ "429 with no Retry-After",
1434
+ { status: 429, data: { message: TOO_MANY_REQUESTS } },
1435
+ TOO_MANY_REQUESTS,
1436
+ null,
1437
+ ],
1438
+ [
1439
+ "429 from something that is not the form's limiter",
1440
+ { status: 429, data: { message: "Slow down" } },
1441
+ TOO_MANY_REQUESTS,
1442
+ null,
1443
+ ],
1444
+ [
1445
+ "500",
1446
+ { status: 500, data: { error: "Server Error" } },
1447
+ LOAD_FAILED,
1448
+ null,
1449
+ ],
1450
+ [
1451
+ "502 from a proxy, as HTML",
1452
+ {
1453
+ status: 502,
1454
+ data: "<html>Bad Gateway</html>" as unknown as JSONObject,
1455
+ },
1456
+ LOAD_FAILED,
1457
+ null,
1458
+ ],
1459
+ [
1460
+ "no answer at all",
1461
+ { networkErrorCode: "ECONNREFUSED" },
1462
+ LOAD_FAILED,
1463
+ null,
1464
+ ],
1465
+ [
1466
+ "a 200 that is not a form",
1467
+ { status: 200, data: "<html>Welcome</html>" as unknown as JSONObject },
1468
+ LOAD_FAILED,
1469
+ null,
1470
+ ],
1471
+ [
1472
+ "401 - which the routes never answer, but a proxy might",
1473
+ { status: 401, data: { message: "Unauthorized" } },
1474
+ LOAD_FAILED,
1475
+ null,
1476
+ ],
1477
+ [
1478
+ "405",
1479
+ { status: 405, data: { message: "Tenant not found" } },
1480
+ LOAD_FAILED,
1481
+ null,
1482
+ ],
1483
+ ])(
1484
+ "%s: says so, and offers to try again",
1485
+ async (
1486
+ _case: string,
1487
+ reply: FakeReply,
1488
+ message: string,
1489
+ retryAfter: string | null,
1490
+ ) => {
1491
+ serveForm(reply);
1492
+
1493
+ await renderPage();
1494
+
1495
+ const failure: HTMLElement = screen.getByTestId(
1496
+ "incident-form-load-failure",
1497
+ );
1498
+
1499
+ expect(
1500
+ within(failure).getByRole("heading", { level: 1 }),
1501
+ ).toHaveTextContent(message);
1502
+
1503
+ if (retryAfter) {
1504
+ expect(failure).toHaveTextContent(retryAfter);
1505
+ } else {
1506
+ expect(failure).not.toHaveTextContent("You can try again");
1507
+ }
1508
+
1509
+ expect(screen.getByTestId("incident-form-try-again")).toBeInTheDocument();
1510
+ // One request: no session refresh, no logout request, no retry loop.
1511
+ expect(sentRequests()).toEqual([`GET ${FORM_URL}`]);
1512
+ expectNoNavigationOrLogout();
1513
+ },
1514
+ );
1515
+
1516
+ test("Try again reads the form again", async () => {
1517
+ serveForm({ status: 503, data: { message: "Unavailable" } });
1518
+
1519
+ await renderPage();
1520
+
1521
+ serveForm({ status: 200, data: MINIMAL_FORM as unknown as JSONObject });
1522
+
1523
+ await act(async () => {
1524
+ fireEvent.click(screen.getByTestId("incident-form-try-again"));
1525
+ });
1526
+ await flush();
1527
+
1528
+ expect(screen.getByTestId("incident-form-title")).toBeInTheDocument();
1529
+ expect(sentRequests()).toEqual([`GET ${FORM_URL}`, `GET ${FORM_URL}`]);
1530
+ });
1531
+
1532
+ /*
1533
+ * "Try again" leaves with the failure it was on, and whatever loads next
1534
+ * starts at its heading - the form's name, or what went wrong this time -
1535
+ * rather than leaving focus on <body>.
1536
+ */
1537
+ test("after Try again, focus is on the heading of the form that loaded", async () => {
1538
+ serveForm({ status: 503, data: { message: "Unavailable" } });
1539
+
1540
+ await renderPage();
1541
+
1542
+ // A form that fails on arrival takes no focus: nothing had it.
1543
+ expect(document.body).toHaveFocus();
1544
+
1545
+ serveForm({ status: 200, data: MINIMAL_FORM as unknown as JSONObject });
1546
+
1547
+ const tryAgain: HTMLElement = screen.getByTestId("incident-form-try-again");
1548
+
1549
+ tryAgain.focus();
1550
+
1551
+ await act(async () => {
1552
+ fireEvent.click(tryAgain);
1553
+ });
1554
+ await flush();
1555
+
1556
+ expect(
1557
+ screen.getByRole("heading", { level: 1, name: "Minimal" }),
1558
+ ).toHaveFocus();
1559
+ });
1560
+
1561
+ test("after a Try again that fails again, focus is on the new failure", async () => {
1562
+ serveForm({ status: 503, data: { message: "Unavailable" } });
1563
+
1564
+ await renderPage();
1565
+
1566
+ serveForm({ status: 429, data: { message: TOO_MANY_REQUESTS } });
1567
+
1568
+ const tryAgain: HTMLElement = screen.getByTestId("incident-form-try-again");
1569
+
1570
+ tryAgain.focus();
1571
+
1572
+ await act(async () => {
1573
+ fireEvent.click(tryAgain);
1574
+ });
1575
+ await flush();
1576
+
1577
+ const heading: HTMLElement = within(
1578
+ screen.getByTestId("incident-form-load-failure"),
1579
+ ).getByRole("heading", { level: 1 });
1580
+
1581
+ expect(heading).toHaveTextContent(TOO_MANY_REQUESTS);
1582
+ expect(heading).toHaveFocus();
1583
+ });
1584
+
1585
+ test.each([
1586
+ ["a word", "not-a-key"],
1587
+ ["a path that climbs out of the route", "..%2F..%2Fuser%2Fget-list"],
1588
+ ["a key with the submit route glued on", `${SHARE_KEY}%2Fsubmit`],
1589
+ ["a key that is almost a UUID", `${SHARE_KEY}0`],
1590
+ ])(
1591
+ "%s is not a link to a form, and the page never asks the server about it",
1592
+ async (_case: string, shareKey: string) => {
1593
+ await renderPage(shareKey);
1594
+
1595
+ expect(
1596
+ within(screen.getByTestId("incident-form-load-failure")).getByRole(
1597
+ "heading",
1598
+ { level: 1 },
1599
+ ),
1600
+ ).toHaveTextContent(NOT_AVAILABLE);
1601
+ expect(sentRequests()).toEqual([]);
1602
+ },
1603
+ );
1604
+
1605
+ test("an upper-case key is the same key", async () => {
1606
+ serveForm({ status: 200, data: MINIMAL_FORM as unknown as JSONObject });
1607
+
1608
+ await renderPage(SHARE_KEY.toUpperCase());
1609
+
1610
+ expect(screen.getByTestId("incident-form-title")).toBeInTheDocument();
1611
+ expect(sentRequests()).toEqual([`GET ${FORM_URL}`]);
1612
+ });
1613
+ });
1614
+
1615
+ describe("a report that is refused says why, next to the form", () => {
1616
+ test.each([
1617
+ [
1618
+ "400 with the answers it refused",
1619
+ {
1620
+ status: 400,
1621
+ data: { error: "Impact is required. Title is required." },
1622
+ },
1623
+ "Impact is required. Title is required.",
1624
+ null,
1625
+ ],
1626
+ [
1627
+ "400 about the captcha",
1628
+ { status: 400, data: { error: CAPTCHA_FAILED } },
1629
+ CAPTCHA_FAILED,
1630
+ null,
1631
+ ],
1632
+ [
1633
+ "400 that does not say why",
1634
+ { status: 400, data: {} },
1635
+ SUBMIT_FAILED,
1636
+ null,
1637
+ ],
1638
+ [
1639
+ "403",
1640
+ { status: 403, data: { error: NETWORK_NOT_ALLOWED } },
1641
+ NETWORK_NOT_ALLOWED,
1642
+ null,
1643
+ ],
1644
+ [
1645
+ "404",
1646
+ { status: 404, data: { error: NOT_AVAILABLE } },
1647
+ NOT_AVAILABLE,
1648
+ null,
1649
+ ],
1650
+ [
1651
+ "429 for this network",
1652
+ {
1653
+ status: 429,
1654
+ data: { message: TOO_MANY_SUBMISSIONS },
1655
+ headers: { "Retry-After": "900" },
1656
+ },
1657
+ TOO_MANY_SUBMISSIONS,
1658
+ "You can try again in 15 minutes.",
1659
+ ],
1660
+ [
1661
+ "429 for the whole form",
1662
+ {
1663
+ status: 429,
1664
+ data: { message: FORM_BUSY },
1665
+ headers: { "retry-after": "3600" },
1666
+ },
1667
+ FORM_BUSY,
1668
+ "You can try again in 1 hour.",
1669
+ ],
1670
+ [
1671
+ "429 without the limiter's words",
1672
+ { status: 429, data: {} },
1673
+ TOO_MANY_SUBMISSIONS,
1674
+ null,
1675
+ ],
1676
+ [
1677
+ "500 when the incident could not be declared",
1678
+ { status: 500, data: { error: SUBMIT_FAILED } },
1679
+ SUBMIT_FAILED,
1680
+ null,
1681
+ ],
1682
+ [
1683
+ "500 with the server's generic words",
1684
+ { status: 500, data: { error: "Server Error" } },
1685
+ SUBMIT_FAILED,
1686
+ null,
1687
+ ],
1688
+ [
1689
+ "503 when submits are refused",
1690
+ { status: 503, data: { message: REPORTS_UNAVAILABLE } },
1691
+ REPORTS_UNAVAILABLE,
1692
+ null,
1693
+ ],
1694
+ [
1695
+ "no answer at all",
1696
+ { networkErrorCode: "ECONNRESET" },
1697
+ SUBMIT_FAILED,
1698
+ null,
1699
+ ],
1700
+ ])(
1701
+ "%s",
1702
+ async (
1703
+ _case: string,
1704
+ reply: FakeReply,
1705
+ message: string,
1706
+ retryAfter: string | null,
1707
+ ) => {
1708
+ serveSubmit(reply);
1709
+
1710
+ await renderForm(MINIMAL_FORM);
1711
+
1712
+ fillMinimalForm();
1713
+ await submit();
1714
+
1715
+ const error: HTMLElement = screen.getByTestId(
1716
+ "incident-form-submit-error",
1717
+ );
1718
+
1719
+ expect(error).toHaveTextContent(message);
1720
+
1721
+ if (retryAfter) {
1722
+ expect(error).toHaveTextContent(retryAfter);
1723
+ } else {
1724
+ expect(error).not.toHaveTextContent("You can try again");
1725
+ }
1726
+
1727
+ // The report is still there to send again.
1728
+ expect(screen.getByTestId("incident-form-title")).toHaveValue(
1729
+ "Checkout is down",
1730
+ );
1731
+ expect(screen.queryByTestId("incident-form-success")).toBeNull();
1732
+
1733
+ expect(sentRequests()).toEqual([`GET ${FORM_URL}`, `POST ${SUBMIT_URL}`]);
1734
+ expectNoNavigationOrLogout();
1735
+ },
1736
+ );
1737
+
1738
+ test("sending it again clears the last refusal", async () => {
1739
+ serveSubmit({ status: 503, data: { message: REPORTS_UNAVAILABLE } });
1740
+ serveSubmit({ status: 200, data: { incidentNumber: "INC-9" } });
1741
+
1742
+ await renderForm(MINIMAL_FORM);
1743
+
1744
+ fillMinimalForm();
1745
+ await submit();
1746
+
1747
+ expect(
1748
+ screen.getByTestId("incident-form-submit-error"),
1749
+ ).toBeInTheDocument();
1750
+
1751
+ await submit();
1752
+
1753
+ expect(screen.queryByTestId("incident-form-submit-error")).toBeNull();
1754
+ expect(
1755
+ screen.getByTestId("incident-form-incident-number"),
1756
+ ).toHaveTextContent("INC-9");
1757
+ });
1758
+
1759
+ test("a server message that quotes a field is shown as it came, never looked up", async () => {
1760
+ const quoted: string =
1761
+ '"{{field}} is required." holds a number, but was sent "x".';
1762
+
1763
+ serveSubmit({ status: 400, data: { error: quoted } });
1764
+
1765
+ await renderForm(MINIMAL_FORM);
1766
+
1767
+ fillMinimalForm();
1768
+ await submit();
1769
+
1770
+ expect(screen.getByTestId("incident-form-submit-error")).toHaveTextContent(
1771
+ quoted,
1772
+ );
1773
+ });
1774
+ });
1775
+
1776
+ describe("a visitor who is signed in to OneUptime on this host", () => {
1777
+ const USER_ID: ObjectID = new ObjectID(
1778
+ "33333333-3333-4333-8333-333333333333",
1779
+ );
1780
+
1781
+ beforeEach(() => {
1782
+ User.setUserId(USER_ID);
1783
+ User.setEmail(new Email("grace@example.com"));
1784
+
1785
+ // What the page must leave alone.
1786
+ expect(User.isLoggedIn()).toBe(true);
1787
+ });
1788
+
1789
+ test("is still signed in after the form's routes refuse with a 401", async () => {
1790
+ serveForm({ status: 401, data: { message: "Unauthorized" } });
1791
+
1792
+ await renderPage();
1793
+
1794
+ expect(User.isLoggedIn()).toBe(true);
1795
+ expect(User.getUserId().toString()).toBe(USER_ID.toString());
1796
+ // Not even a refresh was tried: the only request is the form's.
1797
+ expect(sentRequests()).toEqual([`GET ${FORM_URL}`]);
1798
+ expectNoNavigationOrLogout();
1799
+ });
1800
+
1801
+ test("is still signed in after a submit refused with a 401, a 403 or a 405", async () => {
1802
+ serveSubmit({ status: 401, data: { message: "Unauthorized" } });
1803
+ serveSubmit({ status: 403, data: { error: NETWORK_NOT_ALLOWED } });
1804
+ serveSubmit({ status: 405, data: { message: "Tenant not found" } });
1805
+
1806
+ await renderForm(MINIMAL_FORM);
1807
+
1808
+ fillMinimalForm();
1809
+ await submit();
1810
+ await submit();
1811
+ await submit();
1812
+
1813
+ expect(User.isLoggedIn()).toBe(true);
1814
+ expect(sentRequests()).toEqual([
1815
+ `GET ${FORM_URL}`,
1816
+ `POST ${SUBMIT_URL}`,
1817
+ `POST ${SUBMIT_URL}`,
1818
+ `POST ${SUBMIT_URL}`,
1819
+ ]);
1820
+ expectNoNavigationOrLogout();
1821
+ });
1822
+
1823
+ test("reports through the same form as anybody else", async () => {
1824
+ serveSubmit({ status: 200, data: { incidentNumber: "INC-1" } });
1825
+
1826
+ await renderForm(MINIMAL_FORM);
1827
+
1828
+ fillMinimalForm();
1829
+ await submit();
1830
+
1831
+ expect(screen.getByTestId("incident-form-success")).toBeInTheDocument();
1832
+ expect(User.isLoggedIn()).toBe(true);
1833
+ });
1834
+ });
1835
+
1836
+ describe("the page speaks the reporter's language", () => {
1837
+ test("in Persian, its questions, the server's refusals and the wait", async () => {
1838
+ await act(async () => {
1839
+ await i18n.changeLanguage("fa");
1840
+ });
1841
+
1842
+ serveSubmit({
1843
+ status: 429,
1844
+ data: { message: TOO_MANY_SUBMISSIONS },
1845
+ headers: { "retry-after": "900" },
1846
+ });
1847
+
1848
+ serveForm({ status: 200, data: MINIMAL_FORM as unknown as JSONObject });
1849
+ await renderPage();
1850
+
1851
+ // The page's own copy is nested; a sentence is its own (flat) key.
1852
+ const fa: (key: string) => string = (key: string): string => {
1853
+ return i18n.t(key);
1854
+ };
1855
+
1856
+ const faSentence: (sentence: string) => string = (
1857
+ sentence: string,
1858
+ ): string => {
1859
+ return i18n.t(sentence, { keySeparator: false, nsSeparator: false });
1860
+ };
1861
+
1862
+ expect(fa("incidentForm.title")).toBe("عنوان");
1863
+ expect(
1864
+ screen.getByLabelText(new RegExp(`^${fa("incidentForm.title")}`)),
1865
+ ).toBe(screen.getByTestId("incident-form-title"));
1866
+ expect(
1867
+ screen.getByText(fa("incidentForm.titleDescription")),
1868
+ ).toBeInTheDocument();
1869
+ expect(
1870
+ screen.getByRole("button", { name: fa("common.submit") }),
1871
+ ).toBeInTheDocument();
1872
+
1873
+ fillMinimalForm();
1874
+ await act(async () => {
1875
+ fireEvent.click(
1876
+ screen.getByRole("button", { name: fa("common.submit") }),
1877
+ );
1878
+ });
1879
+ await flush();
1880
+
1881
+ const error: HTMLElement = screen.getByTestId("incident-form-submit-error");
1882
+
1883
+ expect(faSentence(TOO_MANY_SUBMISSIONS)).not.toBe(TOO_MANY_SUBMISSIONS);
1884
+ expect(error).toHaveTextContent(faSentence(TOO_MANY_SUBMISSIONS));
1885
+ // "in 15 minutes", worded and numbered in Persian.
1886
+ expect(error).toHaveTextContent("۱۵ دقیقه بعد");
1887
+ });
1888
+
1889
+ test("in German, a required question left empty is asked for in German", async () => {
1890
+ await act(async () => {
1891
+ await i18n.changeLanguage("de");
1892
+ });
1893
+
1894
+ serveForm({ status: 200, data: MINIMAL_FORM as unknown as JSONObject });
1895
+ await renderPage();
1896
+
1897
+ await act(async () => {
1898
+ fireEvent.click(screen.getByRole("button", { name: "Senden" }));
1899
+ });
1900
+ await flush();
1901
+
1902
+ expect(screen.getByText("Titel ist erforderlich.")).toBeInTheDocument();
1903
+ expect(screen.getByText("Ihr Name ist erforderlich.")).toBeInTheDocument();
1904
+ });
1905
+
1906
+ /*
1907
+ * An empty Markdown box says what to type in it, in each of its two modes:
1908
+ * "content" in the visual editor, "markdown" in the source box. The
1909
+ * editor looks those words up in the page's language itself, so the page
1910
+ * hands it none - the description's box and each Markdown question's
1911
+ * alike. A placeholder handed over would be shown in both modes.
1912
+ */
1913
+ const MARKDOWN_BOXES_FORM: PublicIncidentForm = {
1914
+ ...MINIMAL_FORM,
1915
+ descriptionSetting: IncidentFormFieldSetting.Optional,
1916
+ customFields: [
1917
+ {
1918
+ name: "Notes",
1919
+ customFieldType: CustomFieldType.Markdown,
1920
+ isRequired: false,
1921
+ },
1922
+ ],
1923
+ };
1924
+
1925
+ type NotesBoxFunction = () => HTMLElement;
1926
+
1927
+ const notesBox: NotesBoxFunction = (): HTMLElement => {
1928
+ return screen.getByRole("textbox", { name: /^Notes/ });
1929
+ };
1930
+
1931
+ type SwitchToSourceFunction = () => void;
1932
+
1933
+ // Every Markdown box on the page, into its source mode.
1934
+ const switchEveryMarkdownBoxToSource: SwitchToSourceFunction = (): void => {
1935
+ const switches: Array<HTMLElement> = screen.getAllByTitle(
1936
+ "Switch to markdown source",
1937
+ );
1938
+
1939
+ expect(switches).toHaveLength(2);
1940
+
1941
+ for (const button of switches) {
1942
+ fireEvent.click(button);
1943
+ }
1944
+ };
1945
+
1946
+ test("in German, every Markdown box says what to type in German, in both its modes", async () => {
1947
+ await act(async () => {
1948
+ await i18n.changeLanguage("de");
1949
+ });
1950
+
1951
+ serveForm({
1952
+ status: 200,
1953
+ data: MARKDOWN_BOXES_FORM as unknown as JSONObject,
1954
+ });
1955
+ await renderPage();
1956
+
1957
+ const flatKey: { keySeparator: false; nsSeparator: false } = {
1958
+ keySeparator: false,
1959
+ nsSeparator: false,
1960
+ };
1961
+ const visualPlaceholder: string = i18n.t(
1962
+ "Type your content here...",
1963
+ flatKey,
1964
+ );
1965
+ const sourcePlaceholder: string = i18n.t(
1966
+ "Type your markdown here...",
1967
+ flatKey,
1968
+ );
1969
+
1970
+ expect(visualPlaceholder).toBe("Geben Sie hier Ihren Inhalt ein...");
1971
+ expect(sourcePlaceholder).toBe("Geben Sie hier Ihr Markdown ein...");
1972
+
1973
+ expect(descriptionEditor()).toHaveAttribute(
1974
+ "data-placeholder",
1975
+ visualPlaceholder,
1976
+ );
1977
+ expect(notesBox()).toHaveAttribute("data-placeholder", visualPlaceholder);
1978
+
1979
+ switchEveryMarkdownBoxToSource();
1980
+
1981
+ // The source box says "markdown", as the Accounts locale words it.
1982
+ expect(descriptionEditor()).toHaveAttribute(
1983
+ "placeholder",
1984
+ sourcePlaceholder,
1985
+ );
1986
+ expect(notesBox()).toHaveAttribute("placeholder", sourcePlaceholder);
1987
+ expect(screen.getAllByText("Hilfe zur Formatierung").length).toBe(2);
1988
+ });
1989
+
1990
+ test("in English, the Markdown boxes keep the editor's own words, in both its modes", async () => {
1991
+ await renderForm(MARKDOWN_BOXES_FORM);
1992
+
1993
+ expect(descriptionEditor()).toHaveAttribute(
1994
+ "data-placeholder",
1995
+ "Type your content here...",
1996
+ );
1997
+ expect(notesBox()).toHaveAttribute(
1998
+ "data-placeholder",
1999
+ "Type your content here...",
2000
+ );
2001
+
2002
+ switchEveryMarkdownBoxToSource();
2003
+
2004
+ expect(descriptionEditor()).toHaveAttribute(
2005
+ "placeholder",
2006
+ "Type your markdown here...",
2007
+ );
2008
+ expect(notesBox()).toHaveAttribute(
2009
+ "placeholder",
2010
+ "Type your markdown here...",
2011
+ );
2012
+ });
2013
+
2014
+ test("switching language mid-report relabels the form and keeps the answers", async () => {
2015
+ await renderForm(MINIMAL_FORM);
2016
+
2017
+ typeInto(screen.getByTestId("incident-form-title"), "Checkout is down");
2018
+
2019
+ expect(screen.getByLabelText(/^Title/)).toBe(
2020
+ screen.getByTestId("incident-form-title"),
2021
+ );
2022
+
2023
+ await act(async () => {
2024
+ await i18n.changeLanguage("de");
2025
+ });
2026
+ await flush();
2027
+
2028
+ expect(screen.getByLabelText(/^Titel/)).toBe(
2029
+ screen.getByTestId("incident-form-title"),
2030
+ );
2031
+ expect(screen.getByTestId("incident-form-title")).toHaveValue(
2032
+ "Checkout is down",
2033
+ );
2034
+ expect(screen.getByRole("button", { name: "Senden" })).toBeInTheDocument();
2035
+ });
2036
+ });