@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,1816 @@
1
+ import "@testing-library/jest-dom";
2
+ import {
3
+ afterEach,
4
+ beforeEach,
5
+ describe,
6
+ expect,
7
+ jest,
8
+ test,
9
+ } from "@jest/globals";
10
+ import {
11
+ act,
12
+ cleanup,
13
+ fireEvent,
14
+ render,
15
+ RenderResult,
16
+ screen,
17
+ waitFor,
18
+ within,
19
+ } from "@testing-library/react";
20
+ import React from "react";
21
+ import { MemoryRouter } from "react-router-dom";
22
+ import getJestMockFunction, { MockFunction } from "../../MockType";
23
+
24
+ /*
25
+ * IncidentCustomFieldSettingsCard: which incident custom fields are asked
26
+ * for when an incident is created, for an incident template ("Custom Fields
27
+ * on Create") or an incident form ("Questions").
28
+ *
29
+ * Only the network, the permission gate and the translation lookup are
30
+ * stubbed: the card, its modal, the form and its dropdowns are the real
31
+ * ones, so a save is made the way a person makes it - open the dropdown,
32
+ * pick an option, press Save.
33
+ */
34
+
35
+ let mockTranslate: (value: string) => string = (value: string): string => {
36
+ return value;
37
+ };
38
+
39
+ jest.mock("../../../UI/Utils/Translation", () => {
40
+ return {
41
+ __esModule: true,
42
+ default: () => {
43
+ return {
44
+ translateString: (value: string | undefined): string | undefined => {
45
+ return typeof value === "string" && value
46
+ ? mockTranslate(value)
47
+ : value;
48
+ },
49
+ translateValue: (value: unknown): unknown => {
50
+ return typeof value === "string" && value
51
+ ? mockTranslate(value)
52
+ : value;
53
+ },
54
+ };
55
+ },
56
+ };
57
+ });
58
+
59
+ /*
60
+ * A refused request is written as an async function that throws, not as
61
+ * mockRejectedValue: the card's imports load zone.js, whose patched Promise
62
+ * the card's awaits adopt a microtask late, so a rejected one is reported as
63
+ * unhandled although the card catches it. An async function's promise is a
64
+ * native one.
65
+ */
66
+ const getListMock: MockFunction = getJestMockFunction();
67
+ const getItemMock: MockFunction = getJestMockFunction();
68
+ const updateByIdMock: MockFunction = getJestMockFunction();
69
+
70
+ jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
71
+ return {
72
+ __esModule: true,
73
+ default: {
74
+ getList: (...args: Array<unknown>): unknown => {
75
+ return getListMock(...args);
76
+ },
77
+ getItem: (...args: Array<unknown>): unknown => {
78
+ return getItemMock(...args);
79
+ },
80
+ updateById: (...args: Array<unknown>): unknown => {
81
+ return updateByIdMock(...args);
82
+ },
83
+ },
84
+ };
85
+ });
86
+
87
+ import IncidentCustomFieldSettingsCard from "../../../../App/FeatureSet/Dashboard/src/Components/Incident/IncidentCustomFieldSettingsCard";
88
+ import IncidentCustomFieldCreateSettingsCopy from "../../../../App/FeatureSet/Dashboard/src/Components/Incident/IncidentCustomFieldCreateSettingsCopy";
89
+ import IncidentCustomField from "../../../Models/DatabaseModels/IncidentCustomField";
90
+ import IncidentForm from "../../../Models/DatabaseModels/IncidentForm";
91
+ import IncidentTemplate from "../../../Models/DatabaseModels/IncidentTemplate";
92
+ import CustomFieldMappingSourceResource from "../../../Types/CustomField/CustomFieldMappingSourceResource";
93
+ import CustomFieldType from "../../../Types/CustomField/CustomFieldType";
94
+ import { JSONObject } from "../../../Types/JSON";
95
+ import ObjectID from "../../../Types/ObjectID";
96
+ import PermissionGate, {
97
+ ModelAction,
98
+ PermissionGateResult,
99
+ } from "../../../UI/Utils/PermissionGate";
100
+ import ProjectUtil from "../../../UI/Utils/Project";
101
+
102
+ const PROJECT_ID: string = "11111111-1111-4111-8111-111111111111";
103
+ const TEMPLATE_ID: string = "a1b2c3d4-0000-4000-8000-0000000000aa";
104
+ const FORM_ID: string = "f0f0f0f0-0000-4000-8000-0000000000ff";
105
+
106
+ function customField(
107
+ overrides: Partial<IncidentCustomField> & { name: string },
108
+ ): IncidentCustomField {
109
+ const field: IncidentCustomField = new IncidentCustomField();
110
+ field.customFieldType = CustomFieldType.Text;
111
+ Object.assign(field, overrides);
112
+ return field;
113
+ }
114
+
115
+ // Shown and required on its own.
116
+ const IMPACT: IncidentCustomField = customField({
117
+ name: "Impact",
118
+ customFieldType: CustomFieldType.Dropdown,
119
+ dropdownOptions: "Low\nHigh",
120
+ showOnCreate: true,
121
+ isRequiredOnCreate: true,
122
+ sortOrder: 1,
123
+ variableKey: "impact",
124
+ });
125
+ // Shown, not required.
126
+ const DURATION: IncidentCustomField = customField({
127
+ name: "Estimated Duration",
128
+ customFieldType: CustomFieldType.Number,
129
+ showOnCreate: true,
130
+ sortOrder: 2,
131
+ variableKey: "estimated_duration",
132
+ });
133
+ // Not shown on its own.
134
+ const CATEGORY: IncidentCustomField = customField({
135
+ name: "Category",
136
+ sortOrder: 3,
137
+ variableKey: "category",
138
+ });
139
+ // Older than template variable keys: it can have no setting.
140
+ const LEGACY: IncidentCustomField = customField({
141
+ name: "Legacy",
142
+ showOnCreate: true,
143
+ sortOrder: 4,
144
+ });
145
+ // Made by somebody else while an Edit modal is open.
146
+ const ROOT_CAUSE: IncidentCustomField = customField({
147
+ name: "Root Cause",
148
+ sortOrder: 5,
149
+ variableKey: "root_cause",
150
+ });
151
+ // Copied from the monitor field of the same name once there is a monitor.
152
+ const VENDOR: IncidentCustomField = customField({
153
+ name: "Vendor",
154
+ sortOrder: 6,
155
+ variableKey: "vendor",
156
+ mapFromResourceType: CustomFieldMappingSourceResource.Monitor,
157
+ mapFromCustomFieldName: "Vendor",
158
+ });
159
+
160
+ let definitions: Array<IncidentCustomField> | Error = [];
161
+ let storedSettings: JSONObject | null | undefined = undefined;
162
+ let recordFound: boolean = true;
163
+ let gate: PermissionGateResult = { isAllowed: true };
164
+
165
+ function listResult(data: Array<IncidentCustomField>): JSONObject {
166
+ return { data: data, count: data.length, skip: 0, limit: data.length };
167
+ }
168
+
169
+ beforeEach(() => {
170
+ mockTranslate = (value: string): string => {
171
+ return value;
172
+ };
173
+ definitions = [IMPACT, DURATION, CATEGORY, LEGACY];
174
+ storedSettings = undefined;
175
+ recordFound = true;
176
+ gate = { isAllowed: true };
177
+
178
+ getListMock.mockReset();
179
+ getListMock.mockImplementation(async (): Promise<unknown> => {
180
+ if (definitions instanceof Error) {
181
+ throw definitions;
182
+ }
183
+
184
+ return listResult(definitions);
185
+ });
186
+
187
+ getItemMock.mockReset();
188
+ getItemMock.mockImplementation(async (...args: Array<unknown>) => {
189
+ if (!recordFound) {
190
+ return null;
191
+ }
192
+
193
+ const request: { modelType: new () => IncidentTemplate | IncidentForm } =
194
+ args[0] as { modelType: new () => IncidentTemplate | IncidentForm };
195
+ const record: IncidentTemplate | IncidentForm = new request.modelType();
196
+
197
+ if (storedSettings !== undefined) {
198
+ record.customFieldSettings = storedSettings as JSONObject;
199
+ }
200
+
201
+ return record;
202
+ });
203
+
204
+ updateByIdMock.mockReset();
205
+ updateByIdMock.mockResolvedValue({} as never);
206
+
207
+ jest.spyOn(ProjectUtil, "getCurrentProjectId").mockImplementation(() => {
208
+ return new ObjectID(PROJECT_ID);
209
+ });
210
+ jest
211
+ .spyOn(PermissionGate, "check")
212
+ .mockImplementation((): PermissionGateResult => {
213
+ return gate;
214
+ });
215
+ });
216
+
217
+ afterEach(() => {
218
+ cleanup();
219
+ jest.restoreAllMocks();
220
+ });
221
+
222
+ async function renderTemplateCard(
223
+ props: { title?: string; description?: string } = {},
224
+ ): Promise<RenderResult> {
225
+ let result: RenderResult | undefined;
226
+
227
+ await act(async (): Promise<void> => {
228
+ result = render(
229
+ <MemoryRouter>
230
+ <IncidentCustomFieldSettingsCard
231
+ mode="template"
232
+ modelType={IncidentTemplate}
233
+ modelId={new ObjectID(TEMPLATE_ID)}
234
+ {...props}
235
+ />
236
+ </MemoryRouter>,
237
+ );
238
+ });
239
+
240
+ return result!;
241
+ }
242
+
243
+ async function renderFormCard(): Promise<RenderResult> {
244
+ let result: RenderResult | undefined;
245
+
246
+ await act(async (): Promise<void> => {
247
+ result = render(
248
+ <MemoryRouter>
249
+ <IncidentCustomFieldSettingsCard
250
+ mode="form"
251
+ modelType={IncidentForm}
252
+ modelId={new ObjectID(FORM_ID)}
253
+ />
254
+ </MemoryRouter>,
255
+ );
256
+ });
257
+
258
+ return result!;
259
+ }
260
+
261
+ function row(variableKey: string): HTMLElement {
262
+ return screen.getByTestId(`incident-custom-field-setting-${variableKey}`);
263
+ }
264
+
265
+ function settingShownFor(variableKey: string): string {
266
+ return (
267
+ within(row(variableKey)).getByTestId("incident-custom-field-setting-value")
268
+ .textContent || ""
269
+ );
270
+ }
271
+
272
+ function projectDefaultShownFor(variableKey: string): string | null {
273
+ const element: HTMLElement | null = within(row(variableKey)).queryByTestId(
274
+ "incident-custom-field-project-default",
275
+ );
276
+
277
+ return element ? element.textContent || "" : null;
278
+ }
279
+
280
+ function listedKeys(): Array<string> {
281
+ return Array.from(
282
+ document.querySelectorAll<HTMLElement>(
283
+ '[data-testid^="incident-custom-field-setting-"]:not([data-testid="incident-custom-field-setting-value"])',
284
+ ),
285
+ ).map((element: HTMLElement): string => {
286
+ return (element.getAttribute("data-testid") || "").replace(
287
+ "incident-custom-field-setting-",
288
+ "",
289
+ );
290
+ });
291
+ }
292
+
293
+ function editButton(name: string): HTMLElement {
294
+ return screen.getByRole("button", { name: name });
295
+ }
296
+
297
+ // Presses Edit: the modal opens at once, on a loader while it reads.
298
+ async function startEditing(name: string): Promise<HTMLElement> {
299
+ fireEvent.click(editButton(name));
300
+ return await screen.findByRole("dialog");
301
+ }
302
+
303
+ /*
304
+ * Presses Edit, and waits for the modal's read to answer: for its dropdowns,
305
+ * or for the banner saying why there are none.
306
+ */
307
+ async function openEditor(name: string): Promise<HTMLElement> {
308
+ const dialog: HTMLElement = await startEditing(name);
309
+
310
+ await waitFor(() => {
311
+ expect(within(dialog).queryByTestId("component-loader")).toBeNull();
312
+ expect(
313
+ within(dialog).queryAllByRole("combobox").length +
314
+ within(dialog).queryAllByRole("alert").length,
315
+ ).toBeGreaterThan(0);
316
+ });
317
+
318
+ return dialog;
319
+ }
320
+
321
+ function combobox(fieldName: string): HTMLElement {
322
+ return within(screen.getByRole("dialog")).getByRole("combobox", {
323
+ name: new RegExp(`^${fieldName}`),
324
+ });
325
+ }
326
+
327
+ // Opens a field's dropdown and returns the labels of its options.
328
+ function optionsOf(fieldName: string): Array<string> {
329
+ fireEvent.keyDown(combobox(fieldName), {
330
+ key: "ArrowDown",
331
+ code: "ArrowDown",
332
+ });
333
+
334
+ const options: Array<string> = Array.from(
335
+ document.querySelectorAll<HTMLElement>(".ou-select__option"),
336
+ ).map((element: HTMLElement): string => {
337
+ return element.textContent || "";
338
+ });
339
+
340
+ fireEvent.keyDown(combobox(fieldName), { key: "Escape", code: "Escape" });
341
+
342
+ return options;
343
+ }
344
+
345
+ function choose(fieldName: string, label: string): void {
346
+ fireEvent.keyDown(combobox(fieldName), {
347
+ key: "ArrowDown",
348
+ code: "ArrowDown",
349
+ });
350
+
351
+ const option: HTMLElement | undefined = Array.from(
352
+ document.querySelectorAll<HTMLElement>(".ou-select__option"),
353
+ ).find((element: HTMLElement): boolean => {
354
+ return element.textContent === label;
355
+ });
356
+
357
+ expect(option).toBeDefined();
358
+ fireEvent.click(option!);
359
+ }
360
+
361
+ function selectedIn(fieldName: string): string {
362
+ const control: HTMLElement | null = combobox(fieldName).closest(
363
+ ".ou-select__control",
364
+ );
365
+
366
+ return (
367
+ control?.querySelector<HTMLElement>(".ou-select__single-value")
368
+ ?.textContent || ""
369
+ );
370
+ }
371
+
372
+ async function save(): Promise<void> {
373
+ await act(async (): Promise<void> => {
374
+ fireEvent.click(screen.getByTestId("modal-footer-submit-button"));
375
+ });
376
+ }
377
+
378
+ function savedSettings(): JSONObject {
379
+ const request: { data: JSONObject } = updateByIdMock.mock.calls[0]![0] as {
380
+ data: JSONObject;
381
+ };
382
+
383
+ return request.data["customFieldSettings"] as JSONObject;
384
+ }
385
+
386
+ describe("an incident template's Custom Fields on Create card", () => {
387
+ test("lists every field with a template variable key, in order, with its type and setting", async () => {
388
+ storedSettings = { category: "Required", estimated_duration: "Hidden" };
389
+
390
+ await renderTemplateCard();
391
+
392
+ await screen.findByText("Custom Fields on Create");
393
+
394
+ expect(listedKeys()).toEqual(["impact", "estimated_duration", "category"]);
395
+
396
+ expect(within(row("impact")).getByText("Impact")).toBeInTheDocument();
397
+ expect(
398
+ within(row("impact")).getByText("Dropdown (single select)"),
399
+ ).toBeInTheDocument();
400
+ expect(settingShownFor("impact")).toBe("Default (Required)");
401
+
402
+ expect(within(row("estimated_duration")).getByText("Number")).toBeTruthy();
403
+ expect(settingShownFor("estimated_duration")).toBe("Hidden");
404
+
405
+ expect(within(row("category")).getByText("Text")).toBeTruthy();
406
+ expect(settingShownFor("category")).toBe("Required");
407
+
408
+ // A field with no key cannot have a setting, so it is not offered one.
409
+ expect(screen.queryByText("Legacy")).not.toBeInTheDocument();
410
+ });
411
+
412
+ test("Default names what each field does on its own", async () => {
413
+ await renderTemplateCard();
414
+
415
+ await screen.findByText("Custom Fields on Create");
416
+
417
+ expect(settingShownFor("impact")).toBe("Default (Required)");
418
+ expect(settingShownFor("estimated_duration")).toBe("Default (Optional)");
419
+ expect(settingShownFor("category")).toBe("Default (Not Shown)");
420
+ });
421
+
422
+ test("a stored entry that is not a setting reads as Default", async () => {
423
+ storedSettings = { impact: "required", category: 5 } as JSONObject;
424
+
425
+ await renderTemplateCard();
426
+
427
+ await screen.findByText("Custom Fields on Create");
428
+
429
+ expect(settingShownFor("impact")).toBe("Default (Required)");
430
+ expect(settingShownFor("category")).toBe("Default (Not Shown)");
431
+ });
432
+
433
+ test("the fields the template changes stand out from the ones it leaves on Default", async () => {
434
+ storedSettings = { category: "Hidden" };
435
+
436
+ await renderTemplateCard();
437
+
438
+ await screen.findByText("Custom Fields on Create");
439
+
440
+ const changed: HTMLElement = within(row("category")).getByTestId(
441
+ "incident-custom-field-setting-value",
442
+ );
443
+ const leftAlone: HTMLElement = within(row("impact")).getByTestId(
444
+ "incident-custom-field-setting-value",
445
+ );
446
+
447
+ expect(changed.className).toContain("bg-indigo-50");
448
+ expect(leftAlone.className).toContain("bg-gray-50");
449
+ expect(leftAlone.className).not.toContain("bg-indigo-50");
450
+ });
451
+
452
+ test("says what it is for, in the glossary's words", async () => {
453
+ await renderTemplateCard();
454
+
455
+ expect(
456
+ await screen.findByText(
457
+ IncidentCustomFieldCreateSettingsCopy.templateTitle,
458
+ ),
459
+ ).toBeInTheDocument();
460
+ expect(
461
+ screen.getByText(
462
+ IncidentCustomFieldCreateSettingsCopy.templateDescription,
463
+ ),
464
+ ).toBeInTheDocument();
465
+ expect(IncidentCustomFieldCreateSettingsCopy.templateTitle).toBe(
466
+ "Custom Fields on Create",
467
+ );
468
+ expect(IncidentCustomFieldCreateSettingsCopy.templateDescription).toBe(
469
+ "Choose which custom fields the Details step asks for when an incident is declared from this template, and which of them must be filled in. Fields left on Default follow their own Show on Create and Required on Create settings.",
470
+ );
471
+ });
472
+
473
+ test("a title and description given to it replace its own", async () => {
474
+ await renderTemplateCard({
475
+ title: "Asked When Declaring",
476
+ description: "Pick the questions.",
477
+ });
478
+
479
+ expect(await screen.findByText("Asked When Declaring")).toBeTruthy();
480
+ expect(screen.getByText("Pick the questions.")).toBeTruthy();
481
+ expect(screen.queryByText("Custom Fields on Create")).toBeNull();
482
+ });
483
+
484
+ test("reads the project's fields and the template's settings, and nothing more of the template", async () => {
485
+ await renderTemplateCard();
486
+
487
+ await screen.findByText("Custom Fields on Create");
488
+
489
+ expect(getListMock).toHaveBeenCalledTimes(1);
490
+ const listRequest: JSONObject = getListMock.mock.calls[0]![0] as JSONObject;
491
+ expect(listRequest["modelType"]).toBe(IncidentCustomField);
492
+ expect(String((listRequest["query"] as JSONObject)["projectId"])).toBe(
493
+ PROJECT_ID,
494
+ );
495
+
496
+ expect(getItemMock).toHaveBeenCalledTimes(1);
497
+ const itemRequest: JSONObject = getItemMock.mock.calls[0]![0] as JSONObject;
498
+ expect(itemRequest["modelType"]).toBe(IncidentTemplate);
499
+ expect(String(itemRequest["id"])).toBe(TEMPLATE_ID);
500
+ expect(itemRequest["select"]).toEqual({ customFieldSettings: true });
501
+ });
502
+
503
+ test("shows nothing while it loads", async () => {
504
+ getListMock.mockImplementation((): Promise<never> => {
505
+ return new Promise<never>(() => {
506
+ // Never answers.
507
+ });
508
+ });
509
+
510
+ const result: RenderResult = await renderTemplateCard();
511
+
512
+ expect(result.container).toBeEmptyDOMElement();
513
+ });
514
+
515
+ test("shows nothing to a project with no incident custom fields", async () => {
516
+ definitions = [];
517
+
518
+ const result: RenderResult = await renderTemplateCard();
519
+
520
+ await waitFor(() => {
521
+ expect(getItemMock).toHaveBeenCalled();
522
+ });
523
+
524
+ expect(result.container).toBeEmptyDOMElement();
525
+ });
526
+
527
+ test("shows nothing when no field has a template variable key", async () => {
528
+ definitions = [LEGACY];
529
+
530
+ const result: RenderResult = await renderTemplateCard();
531
+
532
+ await waitFor(() => {
533
+ expect(getItemMock).toHaveBeenCalled();
534
+ });
535
+
536
+ expect(result.container).toBeEmptyDOMElement();
537
+ });
538
+
539
+ test("shows nothing when the fields cannot be read - custom fields not on the plan, say", async () => {
540
+ definitions = new Error("Custom fields are not on your plan.");
541
+
542
+ const result: RenderResult = await renderTemplateCard();
543
+
544
+ await waitFor(() => {
545
+ expect(getListMock).toHaveBeenCalled();
546
+ });
547
+
548
+ expect(result.container).toBeEmptyDOMElement();
549
+ expect(
550
+ screen.queryByText("Custom fields are not on your plan."),
551
+ ).toBeNull();
552
+ });
553
+
554
+ test("shows nothing when the template cannot be read, or is gone", async () => {
555
+ getItemMock.mockImplementation(async (): Promise<never> => {
556
+ throw new Error("Forbidden");
557
+ });
558
+
559
+ const failed: RenderResult = await renderTemplateCard();
560
+
561
+ await waitFor(() => {
562
+ expect(getItemMock).toHaveBeenCalled();
563
+ });
564
+
565
+ expect(failed.container).toBeEmptyDOMElement();
566
+
567
+ cleanup();
568
+ getItemMock.mockReset();
569
+ getItemMock.mockResolvedValue(null as never);
570
+
571
+ const missing: RenderResult = await renderTemplateCard();
572
+
573
+ await waitFor(() => {
574
+ expect(getItemMock).toHaveBeenCalled();
575
+ });
576
+
577
+ expect(missing.container).toBeEmptyDOMElement();
578
+ });
579
+
580
+ test("the labels go through the translation lookup", async () => {
581
+ mockTranslate = (value: string): string => {
582
+ return `[de] ${value}`;
583
+ };
584
+
585
+ storedSettings = { category: "Optional" };
586
+
587
+ await renderTemplateCard();
588
+
589
+ expect(
590
+ await screen.findByText("[de] Custom Fields on Create"),
591
+ ).toBeInTheDocument();
592
+ expect(settingShownFor("impact")).toBe("[de] Default (Required)");
593
+ expect(
594
+ within(row("impact")).getByText("[de] Dropdown (single select)"),
595
+ ).toBeInTheDocument();
596
+ expect(projectDefaultShownFor("category")).toBe(
597
+ "[de] Project default: Not Shown",
598
+ );
599
+ // A field's name is the project's own text.
600
+ expect(within(row("impact")).getByText("Impact")).toBeInTheDocument();
601
+ });
602
+
603
+ /*
604
+ * A field the template overrides no longer shows the project's behaviour
605
+ * in its setting, and a viewer cannot open the editor where Default spells
606
+ * it out: whether the template relaxes a field the project requires, or
607
+ * asks one the project leaves out, is said on the card.
608
+ */
609
+ test("a field the template overrides names the project default beside it, for a viewer too", async () => {
610
+ storedSettings = {
611
+ impact: "Optional",
612
+ estimated_duration: "Hidden",
613
+ category: "Required",
614
+ };
615
+ gate = {
616
+ isAllowed: false,
617
+ disabledReason:
618
+ "You do not have permission to update this Incident Template.",
619
+ };
620
+
621
+ await renderTemplateCard();
622
+
623
+ await screen.findByText("Custom Fields on Create");
624
+
625
+ expect(editButton("Edit Custom Fields on Create")).toBeDisabled();
626
+
627
+ // Relaxed: the project requires it.
628
+ expect(settingShownFor("impact")).toBe("Optional");
629
+ expect(projectDefaultShownFor("impact")).toBe("Project default: Required");
630
+
631
+ expect(settingShownFor("estimated_duration")).toBe("Hidden");
632
+ expect(projectDefaultShownFor("estimated_duration")).toBe(
633
+ "Project default: Optional",
634
+ );
635
+
636
+ // Asked: the project leaves it out.
637
+ expect(settingShownFor("category")).toBe("Required");
638
+ expect(projectDefaultShownFor("category")).toBe(
639
+ "Project default: Not Shown",
640
+ );
641
+
642
+ // Still one row per field.
643
+ expect(listedKeys()).toEqual(["impact", "estimated_duration", "category"]);
644
+ });
645
+
646
+ test("a field left on Default says it once, in its setting", async () => {
647
+ storedSettings = { category: "Required", impact: "Default" };
648
+
649
+ await renderTemplateCard();
650
+
651
+ await screen.findByText("Custom Fields on Create");
652
+
653
+ expect(settingShownFor("impact")).toBe("Default (Required)");
654
+ expect(projectDefaultShownFor("impact")).toBeNull();
655
+ expect(projectDefaultShownFor("estimated_duration")).toBeNull();
656
+ expect(projectDefaultShownFor("category")).toBe(
657
+ "Project default: Not Shown",
658
+ );
659
+ });
660
+
661
+ test("a field copied from a monitor has no note on a template, whose Details step leaves it out once there is a monitor", async () => {
662
+ definitions = [IMPACT, VENDOR];
663
+
664
+ await renderTemplateCard();
665
+
666
+ await screen.findByText("Custom Fields on Create");
667
+
668
+ expect(
669
+ document.querySelectorAll(
670
+ '[data-testid="incident-custom-field-question-note"]',
671
+ ),
672
+ ).toHaveLength(0);
673
+
674
+ const dialog: HTMLElement = await openEditor(
675
+ "Edit Custom Fields on Create",
676
+ );
677
+
678
+ expect(
679
+ within(dialog).queryByTestId("incident-custom-field-question-note"),
680
+ ).toBeNull();
681
+ });
682
+
683
+ test("a saved override names the project default at once", async () => {
684
+ await renderTemplateCard();
685
+
686
+ await openEditor("Edit Custom Fields on Create");
687
+
688
+ choose("Impact", "Optional");
689
+
690
+ await save();
691
+
692
+ await waitFor(() => {
693
+ expect(screen.queryByRole("dialog")).toBeNull();
694
+ });
695
+
696
+ expect(settingShownFor("impact")).toBe("Optional");
697
+ expect(projectDefaultShownFor("impact")).toBe("Project default: Required");
698
+ });
699
+ });
700
+
701
+ describe("editing a template's Custom Fields on Create", () => {
702
+ test("offers Default - saying what the field does on its own - Required, Optional and Hidden", async () => {
703
+ await renderTemplateCard();
704
+
705
+ await openEditor("Edit Custom Fields on Create");
706
+
707
+ expect(optionsOf("Impact")).toEqual([
708
+ "Default (Required)",
709
+ "Required",
710
+ "Optional",
711
+ "Hidden",
712
+ ]);
713
+ expect(optionsOf("Category")).toEqual([
714
+ "Default (Not Shown)",
715
+ "Required",
716
+ "Optional",
717
+ "Hidden",
718
+ ]);
719
+ expect(
720
+ within(screen.getByRole("dialog")).queryByRole("combobox", {
721
+ name: /^Legacy/,
722
+ }),
723
+ ).toBeNull();
724
+ });
725
+
726
+ test("each dropdown starts on the field's setting", async () => {
727
+ storedSettings = { category: "Optional" };
728
+
729
+ await renderTemplateCard();
730
+
731
+ await openEditor("Edit Custom Fields on Create");
732
+
733
+ await waitFor(() => {
734
+ expect(selectedIn("Category")).toBe("Optional");
735
+ });
736
+ expect(selectedIn("Impact")).toBe("Default (Required)");
737
+ expect(selectedIn("Estimated Duration")).toBe("Default (Optional)");
738
+ });
739
+
740
+ test("saves only what the template changes, and shows it", async () => {
741
+ storedSettings = { category: "Required" };
742
+
743
+ await renderTemplateCard();
744
+
745
+ await openEditor("Edit Custom Fields on Create");
746
+
747
+ choose("Impact", "Hidden");
748
+ choose("Estimated Duration", "Required");
749
+ // Back to Default: nothing to store for it.
750
+ choose("Category", "Default (Not Shown)");
751
+
752
+ await save();
753
+
754
+ await waitFor(() => {
755
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
756
+ });
757
+
758
+ const request: JSONObject = updateByIdMock.mock.calls[0]![0] as JSONObject;
759
+ expect(request["modelType"]).toBe(IncidentTemplate);
760
+ expect(String(request["id"])).toBe(TEMPLATE_ID);
761
+ expect(request["data"]).toEqual({
762
+ customFieldSettings: { impact: "Hidden", estimated_duration: "Required" },
763
+ });
764
+
765
+ await waitFor(() => {
766
+ expect(screen.queryByRole("dialog")).toBeNull();
767
+ });
768
+
769
+ expect(settingShownFor("impact")).toBe("Hidden");
770
+ expect(settingShownFor("estimated_duration")).toBe("Required");
771
+ expect(settingShownFor("category")).toBe("Default (Not Shown)");
772
+ /*
773
+ * Read when the card loaded, when Edit opened and right before the save.
774
+ * The server stores what it is sent, so nothing is read after it.
775
+ */
776
+ expect(getItemMock).toHaveBeenCalledTimes(3);
777
+ });
778
+
779
+ test("everything back on Default saves an empty object", async () => {
780
+ storedSettings = { impact: "Optional" };
781
+
782
+ await renderTemplateCard();
783
+
784
+ await openEditor("Edit Custom Fields on Create");
785
+
786
+ choose("Impact", "Default (Required)");
787
+
788
+ await save();
789
+
790
+ await waitFor(() => {
791
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
792
+ });
793
+
794
+ expect(savedSettings()).toEqual({});
795
+ });
796
+
797
+ test("keeps the setting of a field it does not list, and drops entries the server would refuse", async () => {
798
+ storedSettings = {
799
+ deleted_field: "Required",
800
+ "Not A Key": "Hidden",
801
+ category: "sometimes",
802
+ };
803
+
804
+ await renderTemplateCard();
805
+
806
+ await openEditor("Edit Custom Fields on Create");
807
+
808
+ choose("Impact", "Optional");
809
+
810
+ await save();
811
+
812
+ await waitFor(() => {
813
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
814
+ });
815
+
816
+ expect(savedSettings()).toEqual({
817
+ deleted_field: "Required",
818
+ impact: "Optional",
819
+ });
820
+ });
821
+
822
+ test("a refused save keeps the modal open, with the reason and the choices just made", async () => {
823
+ updateByIdMock.mockImplementation(async (): Promise<never> => {
824
+ throw new Error("Custom Field Settings must be an object.");
825
+ });
826
+
827
+ await renderTemplateCard();
828
+
829
+ await openEditor("Edit Custom Fields on Create");
830
+
831
+ choose("Impact", "Hidden");
832
+
833
+ await save();
834
+
835
+ expect(
836
+ await screen.findByText("Custom Field Settings must be an object."),
837
+ ).toBeInTheDocument();
838
+ expect(screen.getByRole("dialog")).toBeInTheDocument();
839
+
840
+ await waitFor(() => {
841
+ expect(selectedIn("Impact")).toBe("Hidden");
842
+ });
843
+
844
+ // Nothing was saved, so the card still shows what is stored.
845
+ expect(settingShownFor("impact")).toBe("Default (Required)");
846
+ });
847
+
848
+ test("a retry after a refused save goes through", async () => {
849
+ updateByIdMock.mockImplementationOnce(async (): Promise<never> => {
850
+ throw new Error("Try again.");
851
+ });
852
+
853
+ await renderTemplateCard();
854
+
855
+ await openEditor("Edit Custom Fields on Create");
856
+
857
+ choose("Impact", "Hidden");
858
+
859
+ await save();
860
+
861
+ await screen.findByText("Try again.");
862
+
863
+ await save();
864
+
865
+ await waitFor(() => {
866
+ expect(screen.queryByRole("dialog")).toBeNull();
867
+ });
868
+
869
+ expect(updateByIdMock).toHaveBeenCalledTimes(2);
870
+ expect(
871
+ (updateByIdMock.mock.calls[1]![0] as { data: JSONObject }).data,
872
+ ).toEqual({ customFieldSettings: { impact: "Hidden" } });
873
+ expect(settingShownFor("impact")).toBe("Hidden");
874
+ });
875
+
876
+ test("closing the modal saves nothing", async () => {
877
+ await renderTemplateCard();
878
+
879
+ await openEditor("Edit Custom Fields on Create");
880
+
881
+ choose("Impact", "Hidden");
882
+
883
+ fireEvent.click(screen.getByTestId("modal-footer-close-button"));
884
+
885
+ await waitFor(() => {
886
+ expect(screen.queryByRole("dialog")).toBeNull();
887
+ });
888
+
889
+ expect(updateByIdMock).not.toHaveBeenCalled();
890
+ expect(settingShownFor("impact")).toBe("Default (Required)");
891
+ });
892
+ });
893
+
894
+ /*
895
+ * The page may have been open for a while when somebody presses Edit, and
896
+ * another admin, another tab, the API or Terraform may have changed the
897
+ * settings since. What the modal starts from, and what a save writes, is
898
+ * read again - and a save writes only the dropdowns changed in the modal.
899
+ */
900
+ describe("editing from what is stored now, not what the page loaded", () => {
901
+ test("Edit reads the fields and the settings again, and starts from them", async () => {
902
+ storedSettings = {};
903
+
904
+ await renderTemplateCard();
905
+
906
+ await screen.findByText("Custom Fields on Create");
907
+
908
+ // Another admin hides Impact, and adds a field, after the page loaded.
909
+ storedSettings = { impact: "Hidden" };
910
+ definitions = [
911
+ IMPACT,
912
+ DURATION,
913
+ CATEGORY,
914
+ customField({
915
+ name: "Root Cause",
916
+ sortOrder: 5,
917
+ variableKey: "root_cause",
918
+ }),
919
+ ];
920
+
921
+ await openEditor("Edit Custom Fields on Create");
922
+
923
+ await waitFor(() => {
924
+ expect(selectedIn("Impact")).toBe("Hidden");
925
+ });
926
+ expect(selectedIn("Root Cause")).toBe("Default (Not Shown)");
927
+
928
+ expect(getListMock).toHaveBeenCalledTimes(2);
929
+ expect(getItemMock).toHaveBeenCalledTimes(2);
930
+ const reread: JSONObject = getItemMock.mock.calls[1]![0] as JSONObject;
931
+ expect(reread["modelType"]).toBe(IncidentTemplate);
932
+ expect(String(reread["id"])).toBe(TEMPLATE_ID);
933
+ expect(reread["select"]).toEqual({ customFieldSettings: true });
934
+
935
+ // The card behind the modal shows what was read, too.
936
+ expect(settingShownFor("impact")).toBe("Hidden");
937
+ expect(listedKeys()).toEqual([
938
+ "impact",
939
+ "estimated_duration",
940
+ "category",
941
+ "root_cause",
942
+ ]);
943
+
944
+ choose("Category", "Optional");
945
+
946
+ await save();
947
+
948
+ await waitFor(() => {
949
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
950
+ });
951
+
952
+ // The other admin's Hidden is not put back to Default.
953
+ expect(savedSettings()).toEqual({ impact: "Hidden", category: "Optional" });
954
+ });
955
+
956
+ test("a setting somebody saves while the modal is open is kept, unless this edit changes the same field", async () => {
957
+ await renderTemplateCard();
958
+
959
+ await openEditor("Edit Custom Fields on Create");
960
+
961
+ await waitFor(() => {
962
+ expect(selectedIn("Impact")).toBe("Default (Required)");
963
+ });
964
+
965
+ // Saved by another admin after this modal opened.
966
+ storedSettings = {
967
+ estimated_duration: "Required",
968
+ category: "Hidden",
969
+ impact: "Optional",
970
+ };
971
+
972
+ choose("Impact", "Hidden");
973
+ // Changed, then changed back: this edit has nothing to say about it.
974
+ choose("Category", "Required");
975
+ choose("Category", "Default (Not Shown)");
976
+
977
+ await save();
978
+
979
+ await waitFor(() => {
980
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
981
+ });
982
+
983
+ expect(savedSettings()).toEqual({
984
+ impact: "Hidden",
985
+ estimated_duration: "Required",
986
+ category: "Hidden",
987
+ });
988
+
989
+ await waitFor(() => {
990
+ expect(screen.queryByRole("dialog")).toBeNull();
991
+ });
992
+
993
+ // The card shows what was saved, the other admin's settings included.
994
+ expect(settingShownFor("estimated_duration")).toBe("Required");
995
+ expect(settingShownFor("category")).toBe("Hidden");
996
+ });
997
+
998
+ test("a setting somebody gives a field made while the modal is open is kept", async () => {
999
+ await renderTemplateCard();
1000
+
1001
+ await openEditor("Edit Custom Fields on Create");
1002
+
1003
+ await waitFor(() => {
1004
+ expect(selectedIn("Impact")).toBe("Default (Required)");
1005
+ });
1006
+
1007
+ definitions = [IMPACT, DURATION, CATEGORY, LEGACY, ROOT_CAUSE];
1008
+ storedSettings = { root_cause: "Required" };
1009
+
1010
+ choose("Impact", "Optional");
1011
+
1012
+ await save();
1013
+
1014
+ await waitFor(() => {
1015
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1016
+ });
1017
+
1018
+ expect(savedSettings()).toEqual({
1019
+ root_cause: "Required",
1020
+ impact: "Optional",
1021
+ });
1022
+
1023
+ await waitFor(() => {
1024
+ expect(screen.queryByRole("dialog")).toBeNull();
1025
+ });
1026
+
1027
+ expect(settingShownFor("root_cause")).toBe("Required");
1028
+ });
1029
+
1030
+ /*
1031
+ * A template keeps the settings of fields it does not list - a field made
1032
+ * again gets its setting back - so the stored one stays; only this edit's
1033
+ * change to a field that no longer exists is not written.
1034
+ */
1035
+ test("a change to a field deleted while the modal is open is not written, and the template keeps what it had", async () => {
1036
+ storedSettings = { category: "Optional" };
1037
+
1038
+ await renderTemplateCard();
1039
+
1040
+ await openEditor("Edit Custom Fields on Create");
1041
+
1042
+ await waitFor(() => {
1043
+ expect(selectedIn("Category")).toBe("Optional");
1044
+ });
1045
+
1046
+ definitions = [IMPACT, DURATION, LEGACY];
1047
+
1048
+ choose("Category", "Required");
1049
+ choose("Impact", "Hidden");
1050
+
1051
+ await save();
1052
+
1053
+ await waitFor(() => {
1054
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1055
+ });
1056
+
1057
+ expect(savedSettings()).toEqual({ category: "Optional", impact: "Hidden" });
1058
+ });
1059
+
1060
+ test("while Edit reads, the modal shows a loader and nothing can be saved", async () => {
1061
+ await renderTemplateCard();
1062
+
1063
+ await screen.findByText("Custom Fields on Create");
1064
+
1065
+ let answer: (record: IncidentTemplate) => void = (): void => {};
1066
+
1067
+ getItemMock.mockImplementationOnce((): Promise<IncidentTemplate> => {
1068
+ return new Promise<IncidentTemplate>(
1069
+ (resolve: (record: IncidentTemplate) => void) => {
1070
+ answer = resolve;
1071
+ },
1072
+ );
1073
+ });
1074
+
1075
+ const dialog: HTMLElement = await startEditing(
1076
+ "Edit Custom Fields on Create",
1077
+ );
1078
+
1079
+ expect(within(dialog).getByTestId("component-loader")).toBeInTheDocument();
1080
+ expect(within(dialog).queryByRole("combobox")).toBeNull();
1081
+ expect(screen.getByTestId("modal-footer-submit-button")).toBeDisabled();
1082
+
1083
+ const stored: IncidentTemplate = new IncidentTemplate();
1084
+ stored.customFieldSettings = { impact: "Optional" };
1085
+
1086
+ await act(async (): Promise<void> => {
1087
+ answer(stored);
1088
+ });
1089
+
1090
+ await waitFor(() => {
1091
+ expect(selectedIn("Impact")).toBe("Optional");
1092
+ });
1093
+ expect(screen.getByTestId("modal-footer-submit-button")).not.toBeDisabled();
1094
+ });
1095
+
1096
+ test("when Edit cannot read them, the modal says why, has nothing to save, and Try again reads them again", async () => {
1097
+ await renderTemplateCard();
1098
+
1099
+ await screen.findByText("Custom Fields on Create");
1100
+
1101
+ getItemMock.mockImplementationOnce(async (): Promise<never> => {
1102
+ throw new Error("The server could not be reached.");
1103
+ });
1104
+
1105
+ const dialog: HTMLElement = await openEditor(
1106
+ "Edit Custom Fields on Create",
1107
+ );
1108
+
1109
+ expect(
1110
+ await within(dialog).findByText("The server could not be reached."),
1111
+ ).toBeInTheDocument();
1112
+ // Nothing read, so nothing to choose from.
1113
+ expect(within(dialog).queryByRole("combobox")).toBeNull();
1114
+
1115
+ const button: HTMLElement = screen.getByTestId(
1116
+ "modal-footer-submit-button",
1117
+ );
1118
+
1119
+ expect(button).toHaveTextContent("Try again");
1120
+
1121
+ await act(async (): Promise<void> => {
1122
+ fireEvent.click(button);
1123
+ });
1124
+
1125
+ await waitFor(() => {
1126
+ expect(selectedIn("Impact")).toBe("Default (Required)");
1127
+ });
1128
+ expect(screen.queryByText("The server could not be reached.")).toBeNull();
1129
+ expect(screen.getByTestId("modal-footer-submit-button")).toHaveTextContent(
1130
+ "Save",
1131
+ );
1132
+ expect(getItemMock).toHaveBeenCalledTimes(3);
1133
+ expect(updateByIdMock).not.toHaveBeenCalled();
1134
+ });
1135
+
1136
+ test("a template deleted since the page loaded is named as gone, in the template's words", async () => {
1137
+ await renderTemplateCard();
1138
+
1139
+ await screen.findByText("Custom Fields on Create");
1140
+
1141
+ recordFound = false;
1142
+
1143
+ const dialog: HTMLElement = await openEditor(
1144
+ "Edit Custom Fields on Create",
1145
+ );
1146
+
1147
+ expect(
1148
+ await within(dialog).findByText(
1149
+ IncidentCustomFieldCreateSettingsCopy.templateNotFound,
1150
+ ),
1151
+ ).toBeInTheDocument();
1152
+ expect(IncidentCustomFieldCreateSettingsCopy.templateNotFound).toBe(
1153
+ "This template's custom field settings could not be loaded. The template may have been deleted.",
1154
+ );
1155
+ expect(within(dialog).queryByRole("combobox")).toBeNull();
1156
+ expect(updateByIdMock).not.toHaveBeenCalled();
1157
+ });
1158
+
1159
+ test("a save that cannot read the settings first writes nothing, says why, and keeps the choices", async () => {
1160
+ await renderTemplateCard();
1161
+
1162
+ await openEditor("Edit Custom Fields on Create");
1163
+
1164
+ await waitFor(() => {
1165
+ expect(selectedIn("Impact")).toBe("Default (Required)");
1166
+ });
1167
+
1168
+ choose("Impact", "Hidden");
1169
+
1170
+ getItemMock.mockImplementationOnce(async (): Promise<never> => {
1171
+ throw new Error("The server could not be reached.");
1172
+ });
1173
+
1174
+ await save();
1175
+
1176
+ expect(
1177
+ await screen.findByText("The server could not be reached."),
1178
+ ).toBeInTheDocument();
1179
+ expect(updateByIdMock).not.toHaveBeenCalled();
1180
+
1181
+ await waitFor(() => {
1182
+ expect(selectedIn("Impact")).toBe("Hidden");
1183
+ });
1184
+
1185
+ // Pressed again, it reads, then writes.
1186
+ await save();
1187
+
1188
+ await waitFor(() => {
1189
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1190
+ });
1191
+
1192
+ expect(savedSettings()).toEqual({ impact: "Hidden" });
1193
+ });
1194
+
1195
+ test("a save finding the template gone writes nothing", async () => {
1196
+ await renderTemplateCard();
1197
+
1198
+ await openEditor("Edit Custom Fields on Create");
1199
+
1200
+ await waitFor(() => {
1201
+ expect(selectedIn("Impact")).toBe("Default (Required)");
1202
+ });
1203
+
1204
+ choose("Impact", "Hidden");
1205
+
1206
+ recordFound = false;
1207
+
1208
+ await save();
1209
+
1210
+ expect(
1211
+ await screen.findByText(
1212
+ IncidentCustomFieldCreateSettingsCopy.templateNotFound,
1213
+ ),
1214
+ ).toBeInTheDocument();
1215
+ expect(updateByIdMock).not.toHaveBeenCalled();
1216
+ });
1217
+
1218
+ test("a read that answers after the modal was closed opens nothing", async () => {
1219
+ await renderTemplateCard();
1220
+
1221
+ await screen.findByText("Custom Fields on Create");
1222
+
1223
+ let answer: (record: IncidentTemplate) => void = (): void => {};
1224
+
1225
+ getItemMock.mockImplementationOnce((): Promise<IncidentTemplate> => {
1226
+ return new Promise<IncidentTemplate>(
1227
+ (resolve: (record: IncidentTemplate) => void) => {
1228
+ answer = resolve;
1229
+ },
1230
+ );
1231
+ });
1232
+
1233
+ await startEditing("Edit Custom Fields on Create");
1234
+
1235
+ fireEvent.click(screen.getByTestId("modal-footer-close-button"));
1236
+
1237
+ await waitFor(() => {
1238
+ expect(screen.queryByRole("dialog")).toBeNull();
1239
+ });
1240
+
1241
+ const stored: IncidentTemplate = new IncidentTemplate();
1242
+ stored.customFieldSettings = { impact: "Optional" };
1243
+
1244
+ await act(async (): Promise<void> => {
1245
+ answer(stored);
1246
+ });
1247
+
1248
+ expect(screen.queryByRole("dialog")).toBeNull();
1249
+ // Nor does it change what the card shows.
1250
+ expect(settingShownFor("impact")).toBe("Default (Required)");
1251
+ });
1252
+ });
1253
+
1254
+ describe("who may edit a template's Custom Fields on Create", () => {
1255
+ test("the gate is an update of the template", async () => {
1256
+ await renderTemplateCard();
1257
+
1258
+ await screen.findByText("Custom Fields on Create");
1259
+
1260
+ const call: Array<unknown> = (
1261
+ PermissionGate.check as unknown as {
1262
+ mock: { calls: Array<Array<unknown>> };
1263
+ }
1264
+ ).mock.calls[0]!;
1265
+
1266
+ expect(call[0]).toBeInstanceOf(IncidentTemplate);
1267
+ expect(call[1]).toBe(ModelAction.Update);
1268
+ });
1269
+
1270
+ test("without the permission, the button stays, disabled, and says why", async () => {
1271
+ gate = {
1272
+ isAllowed: false,
1273
+ disabledReason:
1274
+ "You do not have permission to update this Incident Template.",
1275
+ };
1276
+
1277
+ await renderTemplateCard();
1278
+
1279
+ await screen.findByText("Custom Fields on Create");
1280
+
1281
+ const button: HTMLElement = editButton("Edit Custom Fields on Create");
1282
+
1283
+ expect(button).toBeDisabled();
1284
+
1285
+ fireEvent.click(button);
1286
+
1287
+ expect(screen.queryByRole("dialog")).toBeNull();
1288
+ });
1289
+
1290
+ test("while the permissions are unknown, there is no button - the settings still show", async () => {
1291
+ gate = { isAllowed: false };
1292
+
1293
+ await renderTemplateCard();
1294
+
1295
+ await screen.findByText("Custom Fields on Create");
1296
+
1297
+ expect(
1298
+ screen.queryByRole("button", { name: "Edit Custom Fields on Create" }),
1299
+ ).toBeNull();
1300
+ expect(settingShownFor("impact")).toBe("Default (Required)");
1301
+ });
1302
+ });
1303
+
1304
+ describe("an incident form's Questions card", () => {
1305
+ test("lists every field as Not Asked until the form names it", async () => {
1306
+ storedSettings = {
1307
+ impact: "Required",
1308
+ estimated_duration: "Optional",
1309
+ // A form offers no Default, and does not ask a Hidden field.
1310
+ category: "Default",
1311
+ };
1312
+
1313
+ await renderFormCard();
1314
+
1315
+ expect(await screen.findByText("Questions")).toBeInTheDocument();
1316
+ expect(
1317
+ screen.getByText(IncidentCustomFieldCreateSettingsCopy.formDescription),
1318
+ ).toBeInTheDocument();
1319
+
1320
+ expect(listedKeys()).toEqual(["impact", "estimated_duration", "category"]);
1321
+ expect(settingShownFor("impact")).toBe("Required");
1322
+ expect(settingShownFor("estimated_duration")).toBe("Optional");
1323
+ expect(settingShownFor("category")).toBe("Not Asked");
1324
+ });
1325
+
1326
+ /*
1327
+ * The form does not ask such a field while its incident template attaches
1328
+ * monitors - the incident takes the monitor's value - so the card says
1329
+ * so where the question is set, rather than leave an admin wondering why
1330
+ * a Required question is never asked.
1331
+ */
1332
+ test("a field copied from a monitor says it is not asked while the template attaches monitors, on the card and in the editor", async () => {
1333
+ definitions = [IMPACT, VENDOR];
1334
+ storedSettings = { vendor: "Required" };
1335
+
1336
+ await renderFormCard();
1337
+
1338
+ await screen.findByText("Questions");
1339
+
1340
+ expect(
1341
+ within(row("vendor")).getByTestId("incident-custom-field-question-note"),
1342
+ ).toHaveTextContent(
1343
+ IncidentCustomFieldCreateSettingsCopy.formCopiedFromMonitor,
1344
+ );
1345
+ expect(
1346
+ within(row("impact")).queryByTestId(
1347
+ "incident-custom-field-question-note",
1348
+ ),
1349
+ ).toBeNull();
1350
+ // Still one row per field, and still a question the form can ask.
1351
+ expect(listedKeys()).toEqual(["impact", "vendor"]);
1352
+ expect(settingShownFor("vendor")).toBe("Required");
1353
+
1354
+ const dialog: HTMLElement = await openEditor("Edit Questions");
1355
+
1356
+ const notes: Array<HTMLElement> = within(dialog).getAllByTestId(
1357
+ "incident-custom-field-question-note",
1358
+ );
1359
+
1360
+ expect(notes).toHaveLength(1);
1361
+ expect(notes[0]).toHaveTextContent(
1362
+ IncidentCustomFieldCreateSettingsCopy.formCopiedFromMonitor,
1363
+ );
1364
+ // Under its type, which the dropdown still names.
1365
+ expect(within(dialog).getByText("Text")).toBeInTheDocument();
1366
+ expect(optionsOf("Vendor")).toEqual(["Not Asked", "Optional", "Required"]);
1367
+ expect(selectedIn("Vendor")).toBe("Required");
1368
+ });
1369
+
1370
+ test("the note goes through the translation lookup", async () => {
1371
+ mockTranslate = (value: string): string => {
1372
+ return `[de] ${value}`;
1373
+ };
1374
+
1375
+ definitions = [IMPACT, VENDOR];
1376
+
1377
+ await renderFormCard();
1378
+
1379
+ await screen.findByText("[de] Questions");
1380
+
1381
+ expect(
1382
+ within(row("vendor")).getByTestId("incident-custom-field-question-note"),
1383
+ ).toHaveTextContent(
1384
+ `[de] ${IncidentCustomFieldCreateSettingsCopy.formCopiedFromMonitor}`,
1385
+ );
1386
+
1387
+ const dialog: HTMLElement = await openEditor("[de] Edit Questions");
1388
+
1389
+ expect(
1390
+ within(dialog).getByTestId("incident-custom-field-question-note"),
1391
+ ).toHaveTextContent(
1392
+ `[de] ${IncidentCustomFieldCreateSettingsCopy.formCopiedFromMonitor}`,
1393
+ );
1394
+ expect(within(dialog).getByText("[de] Text")).toBeInTheDocument();
1395
+ });
1396
+
1397
+ test("names no project default: a form does not follow the project's switches", async () => {
1398
+ storedSettings = { impact: "Optional", category: "Required" };
1399
+
1400
+ await renderFormCard();
1401
+
1402
+ await screen.findByText("Questions");
1403
+
1404
+ expect(settingShownFor("impact")).toBe("Optional");
1405
+ expect(
1406
+ document.querySelectorAll(
1407
+ '[data-testid="incident-custom-field-project-default"]',
1408
+ ),
1409
+ ).toHaveLength(0);
1410
+ });
1411
+
1412
+ test("a new form asks nothing, whatever the fields' own Show on Create says", async () => {
1413
+ await renderFormCard();
1414
+
1415
+ await screen.findByText("Questions");
1416
+
1417
+ expect(settingShownFor("impact")).toBe("Not Asked");
1418
+ expect(settingShownFor("estimated_duration")).toBe("Not Asked");
1419
+ expect(settingShownFor("category")).toBe("Not Asked");
1420
+
1421
+ for (const variableKey of ["impact", "estimated_duration", "category"]) {
1422
+ expect(
1423
+ within(row(variableKey)).getByTestId(
1424
+ "incident-custom-field-setting-value",
1425
+ ).className,
1426
+ ).toContain("bg-gray-50");
1427
+ }
1428
+ });
1429
+
1430
+ test("reads the form's settings", async () => {
1431
+ await renderFormCard();
1432
+
1433
+ await screen.findByText("Questions");
1434
+
1435
+ const itemRequest: JSONObject = getItemMock.mock.calls[0]![0] as JSONObject;
1436
+ expect(itemRequest["modelType"]).toBe(IncidentForm);
1437
+ expect(String(itemRequest["id"])).toBe(FORM_ID);
1438
+ expect(itemRequest["select"]).toEqual({ customFieldSettings: true });
1439
+ });
1440
+
1441
+ test("shows a loader inside the card while it loads", async () => {
1442
+ getListMock.mockImplementation((): Promise<never> => {
1443
+ return new Promise<never>(() => {
1444
+ // Never answers.
1445
+ });
1446
+ });
1447
+
1448
+ await renderFormCard();
1449
+
1450
+ expect(screen.getByText("Questions")).toBeInTheDocument();
1451
+ expect(screen.getByTestId("component-loader")).toBeInTheDocument();
1452
+ expect(screen.queryByRole("button", { name: "Edit Questions" })).toBeNull();
1453
+ });
1454
+
1455
+ test("with no custom fields yet, says where they are made", async () => {
1456
+ definitions = [];
1457
+
1458
+ await renderFormCard();
1459
+
1460
+ expect(
1461
+ await screen.findByText("No incident custom fields yet"),
1462
+ ).toBeInTheDocument();
1463
+ expect(
1464
+ screen.getByText(
1465
+ "This form can ask for incident custom fields once your project has some. Create them in Incidents > Settings > Custom Fields, then add them to the form here.",
1466
+ ),
1467
+ ).toBeInTheDocument();
1468
+
1469
+ const link: HTMLElement = screen.getByText("Go to Custom Fields");
1470
+ expect(link.closest("a")!.getAttribute("href")).toBe(
1471
+ `/dashboard/${PROJECT_ID}/incidents/settings/custom-fields`,
1472
+ );
1473
+
1474
+ // Nothing to edit.
1475
+ expect(screen.queryByRole("button", { name: "Edit Questions" })).toBeNull();
1476
+ });
1477
+
1478
+ test("fields without a template variable key count as none", async () => {
1479
+ definitions = [LEGACY];
1480
+
1481
+ await renderFormCard();
1482
+
1483
+ expect(
1484
+ await screen.findByText("No incident custom fields yet"),
1485
+ ).toBeInTheDocument();
1486
+ expect(screen.queryByText("Legacy")).toBeNull();
1487
+ });
1488
+
1489
+ test("says why when the fields cannot be read", async () => {
1490
+ definitions = new Error("Custom fields are not on your plan.");
1491
+
1492
+ await renderFormCard();
1493
+
1494
+ expect(
1495
+ await screen.findByText("Custom fields are not on your plan."),
1496
+ ).toBeInTheDocument();
1497
+ expect(screen.getByText("Questions")).toBeInTheDocument();
1498
+ expect(screen.queryByRole("button", { name: "Edit Questions" })).toBeNull();
1499
+ });
1500
+
1501
+ test("says so when the form itself cannot be found", async () => {
1502
+ recordFound = false;
1503
+
1504
+ await renderFormCard();
1505
+
1506
+ expect(
1507
+ await screen.findByText(
1508
+ "This form's questions could not be loaded. The form may have been deleted.",
1509
+ ),
1510
+ ).toBeInTheDocument();
1511
+ expect(screen.queryByRole("button", { name: "Edit Questions" })).toBeNull();
1512
+ });
1513
+ });
1514
+
1515
+ describe("editing an incident form's questions", () => {
1516
+ test("offers Not Asked, Optional and Required, starting on each field's", async () => {
1517
+ storedSettings = { impact: "Required" };
1518
+
1519
+ await renderFormCard();
1520
+
1521
+ const dialog: HTMLElement = await openEditor("Edit Questions");
1522
+
1523
+ expect(within(dialog).getByText("Edit Questions")).toBeInTheDocument();
1524
+ expect(optionsOf("Impact")).toEqual(["Not Asked", "Optional", "Required"]);
1525
+ expect(optionsOf("Category")).toEqual([
1526
+ "Not Asked",
1527
+ "Optional",
1528
+ "Required",
1529
+ ]);
1530
+
1531
+ await waitFor(() => {
1532
+ expect(selectedIn("Impact")).toBe("Required");
1533
+ });
1534
+ expect(selectedIn("Category")).toBe("Not Asked");
1535
+ });
1536
+
1537
+ test("saves only the questions the form asks", async () => {
1538
+ storedSettings = { impact: "Required", category: "Optional" };
1539
+
1540
+ await renderFormCard();
1541
+
1542
+ await openEditor("Edit Questions");
1543
+
1544
+ choose("Estimated Duration", "Optional");
1545
+ choose("Category", "Not Asked");
1546
+
1547
+ await save();
1548
+
1549
+ await waitFor(() => {
1550
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1551
+ });
1552
+
1553
+ const request: JSONObject = updateByIdMock.mock.calls[0]![0] as JSONObject;
1554
+ expect(request["modelType"]).toBe(IncidentForm);
1555
+ expect(String(request["id"])).toBe(FORM_ID);
1556
+ expect(savedSettings()).toEqual({
1557
+ impact: "Required",
1558
+ estimated_duration: "Optional",
1559
+ });
1560
+
1561
+ await waitFor(() => {
1562
+ expect(screen.queryByRole("dialog")).toBeNull();
1563
+ });
1564
+
1565
+ expect(settingShownFor("estimated_duration")).toBe("Optional");
1566
+ expect(settingShownFor("category")).toBe("Not Asked");
1567
+ });
1568
+
1569
+ test("a question another admin removed since the page loaded stays off the form", async () => {
1570
+ storedSettings = { category: "Optional" };
1571
+
1572
+ await renderFormCard();
1573
+
1574
+ await screen.findByText("Questions");
1575
+
1576
+ expect(settingShownFor("category")).toBe("Optional");
1577
+
1578
+ // Another admin takes Category off the form.
1579
+ storedSettings = {};
1580
+
1581
+ await openEditor("Edit Questions");
1582
+
1583
+ await waitFor(() => {
1584
+ expect(selectedIn("Category")).toBe("Not Asked");
1585
+ });
1586
+
1587
+ choose("Impact", "Required");
1588
+
1589
+ await save();
1590
+
1591
+ await waitFor(() => {
1592
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1593
+ });
1594
+
1595
+ expect(savedSettings()).toEqual({ impact: "Required" });
1596
+ });
1597
+
1598
+ test("a question removed while the modal is open stays off the form", async () => {
1599
+ storedSettings = { category: "Optional" };
1600
+
1601
+ await renderFormCard();
1602
+
1603
+ await openEditor("Edit Questions");
1604
+
1605
+ await waitFor(() => {
1606
+ expect(selectedIn("Category")).toBe("Optional");
1607
+ });
1608
+
1609
+ storedSettings = {};
1610
+
1611
+ choose("Impact", "Required");
1612
+
1613
+ await save();
1614
+
1615
+ await waitFor(() => {
1616
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1617
+ });
1618
+
1619
+ expect(savedSettings()).toEqual({ impact: "Required" });
1620
+
1621
+ await waitFor(() => {
1622
+ expect(screen.queryByRole("dialog")).toBeNull();
1623
+ });
1624
+
1625
+ expect(settingShownFor("category")).toBe("Not Asked");
1626
+ });
1627
+
1628
+ test("a form deleted since the page loaded is named as gone", async () => {
1629
+ await renderFormCard();
1630
+
1631
+ await screen.findByText("Questions");
1632
+
1633
+ recordFound = false;
1634
+
1635
+ const dialog: HTMLElement = await openEditor("Edit Questions");
1636
+
1637
+ expect(
1638
+ await within(dialog).findByText(
1639
+ "This form's questions could not be loaded. The form may have been deleted.",
1640
+ ),
1641
+ ).toBeInTheDocument();
1642
+ expect(within(dialog).queryByRole("combobox")).toBeNull();
1643
+ expect(updateByIdMock).not.toHaveBeenCalled();
1644
+ });
1645
+
1646
+ test("drops the question of a field that is gone, so a field made again with its key is not asked at once", async () => {
1647
+ // "customer" was a field the form asked; it has since been deleted.
1648
+ storedSettings = { customer: "Required", impact: "Optional" };
1649
+
1650
+ await renderFormCard();
1651
+
1652
+ await openEditor("Edit Questions");
1653
+
1654
+ choose("Category", "Optional");
1655
+
1656
+ await save();
1657
+
1658
+ await waitFor(() => {
1659
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1660
+ });
1661
+
1662
+ expect(savedSettings()).toEqual({
1663
+ impact: "Optional",
1664
+ category: "Optional",
1665
+ });
1666
+ });
1667
+
1668
+ /*
1669
+ * Somebody else - another admin, the API, Terraform - makes a field while
1670
+ * this modal is open, and asks it on the form. A form keeps the stored
1671
+ * questions of the fields it is saved over and of no other, so Save reads
1672
+ * the fields again: the new field's question is kept, whether this edit
1673
+ * changed something else or nothing at all.
1674
+ */
1675
+ test.each([
1676
+ ["an edit of another field", true],
1677
+ ["a save that changes nothing", false],
1678
+ ])(
1679
+ "a question another admin adds, for a field made while the modal is open, survives %s",
1680
+ async (_label: string, changesImpact: boolean) => {
1681
+ await renderFormCard();
1682
+
1683
+ await openEditor("Edit Questions");
1684
+
1685
+ await waitFor(() => {
1686
+ expect(selectedIn("Impact")).toBe("Not Asked");
1687
+ });
1688
+
1689
+ definitions = [IMPACT, DURATION, CATEGORY, LEGACY, ROOT_CAUSE];
1690
+ storedSettings = { root_cause: "Required" };
1691
+
1692
+ if (changesImpact) {
1693
+ choose("Impact", "Optional");
1694
+ }
1695
+
1696
+ await save();
1697
+
1698
+ await waitFor(() => {
1699
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1700
+ });
1701
+
1702
+ expect(savedSettings()).toEqual(
1703
+ changesImpact
1704
+ ? { root_cause: "Required", impact: "Optional" }
1705
+ : { root_cause: "Required" },
1706
+ );
1707
+
1708
+ await waitFor(() => {
1709
+ expect(screen.queryByRole("dialog")).toBeNull();
1710
+ });
1711
+
1712
+ // The card lists the new field, with the question it was given.
1713
+ expect(settingShownFor("root_cause")).toBe("Required");
1714
+ },
1715
+ );
1716
+
1717
+ /*
1718
+ * Deleting a field takes its question off every form on the server
1719
+ * (IncidentFormService.removeCustomFieldFromQuestions). A change this
1720
+ * modal made to that field's dropdown meanwhile must not put it back: it
1721
+ * would be asked, name and options and all, of the next field that gets
1722
+ * the same key.
1723
+ */
1724
+ test.each([
1725
+ ["the server took its question off the form", {}],
1726
+ [
1727
+ "the question is still stored (the server's clean-up failed)",
1728
+ { category: "Optional" },
1729
+ ],
1730
+ ])(
1731
+ "a question set for a field deleted while the modal is open is not written, when %s",
1732
+ async (_label: string, storedAtSave: JSONObject) => {
1733
+ storedSettings = { category: "Optional" };
1734
+
1735
+ await renderFormCard();
1736
+
1737
+ await openEditor("Edit Questions");
1738
+
1739
+ await waitFor(() => {
1740
+ expect(selectedIn("Category")).toBe("Optional");
1741
+ });
1742
+
1743
+ definitions = [IMPACT, DURATION, LEGACY];
1744
+ storedSettings = storedAtSave;
1745
+
1746
+ choose("Category", "Required");
1747
+ choose("Impact", "Optional");
1748
+
1749
+ await save();
1750
+
1751
+ await waitFor(() => {
1752
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1753
+ });
1754
+
1755
+ expect(savedSettings()).toEqual({ impact: "Optional" });
1756
+
1757
+ await waitFor(() => {
1758
+ expect(screen.queryByRole("dialog")).toBeNull();
1759
+ });
1760
+
1761
+ // The card no longer lists the field that is gone.
1762
+ expect(listedKeys()).toEqual(["impact", "estimated_duration"]);
1763
+ },
1764
+ );
1765
+
1766
+ test("a save that cannot read the fields first writes nothing, says why, and keeps the choices", async () => {
1767
+ await renderFormCard();
1768
+
1769
+ await openEditor("Edit Questions");
1770
+
1771
+ await waitFor(() => {
1772
+ expect(selectedIn("Impact")).toBe("Not Asked");
1773
+ });
1774
+
1775
+ choose("Impact", "Required");
1776
+
1777
+ definitions = new Error("The custom fields could not be read.");
1778
+
1779
+ await save();
1780
+
1781
+ expect(
1782
+ await screen.findByText("The custom fields could not be read."),
1783
+ ).toBeInTheDocument();
1784
+ expect(updateByIdMock).not.toHaveBeenCalled();
1785
+
1786
+ await waitFor(() => {
1787
+ expect(selectedIn("Impact")).toBe("Required");
1788
+ });
1789
+
1790
+ // Pressed again once they can be read, it writes.
1791
+ definitions = [IMPACT, DURATION, CATEGORY, LEGACY];
1792
+
1793
+ await save();
1794
+
1795
+ await waitFor(() => {
1796
+ expect(updateByIdMock).toHaveBeenCalledTimes(1);
1797
+ });
1798
+
1799
+ expect(savedSettings()).toEqual({ impact: "Required" });
1800
+ });
1801
+
1802
+ test("the gate is an update of the form", async () => {
1803
+ await renderFormCard();
1804
+
1805
+ await screen.findByText("Questions");
1806
+
1807
+ const call: Array<unknown> = (
1808
+ PermissionGate.check as unknown as {
1809
+ mock: { calls: Array<Array<unknown>> };
1810
+ }
1811
+ ).mock.calls[0]!;
1812
+
1813
+ expect(call[0]).toBeInstanceOf(IncidentForm);
1814
+ expect(call[1]).toBe(ModelAction.Update);
1815
+ });
1816
+ });