@oneuptime/common 14.0.10 → 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 (837) hide show
  1. package/Models/DatabaseModels/AIConversation.ts +127 -1
  2. package/Models/DatabaseModels/CephCluster.ts +12 -0
  3. package/Models/DatabaseModels/CloudResource.ts +12 -0
  4. package/Models/DatabaseModels/DatabaseServer.ts +12 -0
  5. package/Models/DatabaseModels/DockerHost.ts +12 -0
  6. package/Models/DatabaseModels/DockerSwarmCluster.ts +12 -0
  7. package/Models/DatabaseModels/GlobalOidc.ts +0 -4
  8. package/Models/DatabaseModels/GlobalOidcProject.ts +0 -4
  9. package/Models/DatabaseModels/GlobalSso.ts +0 -4
  10. package/Models/DatabaseModels/GlobalSsoProject.ts +0 -4
  11. package/Models/DatabaseModels/Host.ts +12 -0
  12. package/Models/DatabaseModels/IncidentForm.ts +594 -0
  13. package/Models/DatabaseModels/IncidentFormSubmission.ts +283 -0
  14. package/Models/DatabaseModels/IncidentTemplate.ts +59 -0
  15. package/Models/DatabaseModels/Index.ts +14 -0
  16. package/Models/DatabaseModels/IoTFleet.ts +12 -0
  17. package/Models/DatabaseModels/KubernetesCluster.ts +12 -0
  18. package/Models/DatabaseModels/MessageQueue.ts +1102 -0
  19. package/Models/DatabaseModels/MessageQueueLabelRule.ts +553 -0
  20. package/Models/DatabaseModels/MessageQueueOwnerRule.ts +633 -0
  21. package/Models/DatabaseModels/MessageQueueOwnerTeam.ts +491 -0
  22. package/Models/DatabaseModels/MessageQueueOwnerUser.ts +490 -0
  23. package/Models/DatabaseModels/PodmanHost.ts +12 -0
  24. package/Models/DatabaseModels/Project.ts +59 -0
  25. package/Models/DatabaseModels/ProjectOidc.ts +0 -4
  26. package/Models/DatabaseModels/ProjectSso.ts +0 -4
  27. package/Models/DatabaseModels/ProxmoxCluster.ts +12 -0
  28. package/Models/DatabaseModels/RumApplication.ts +12 -0
  29. package/Models/DatabaseModels/ServerlessFunction.ts +12 -0
  30. package/Models/DatabaseModels/Service.ts +12 -0
  31. package/Models/DatabaseModels/StatusPageOidc.ts +0 -4
  32. package/Models/DatabaseModels/StatusPageSso.ts +0 -4
  33. package/Models/DatabaseModels/TeamComplianceSetting.ts +47 -2
  34. package/Models/DatabaseModels/VMwareVCenter.ts +12 -0
  35. package/Server/API/AIChatAPI.ts +13 -114
  36. package/Server/API/AIInvestigationAPI.ts +3 -3
  37. package/Server/API/AIInvestigationConversationAPI.ts +266 -0
  38. package/Server/API/IncidentFormAPI.ts +376 -0
  39. package/Server/API/ProjectOIDC.ts +16 -25
  40. package/Server/API/ProjectSSO.ts +16 -24
  41. package/Server/API/StatusPageAPI.ts +42 -77
  42. package/Server/Enterprise/EnterpriseEdition.ts +93 -28
  43. package/Server/Enterprise/EnterpriseFeature.ts +25 -3
  44. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +1 -1
  45. package/Server/Enterprise/EnterpriseServerModule.ts +4 -1
  46. package/Server/EnvironmentConfig.ts +1 -1
  47. package/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.ts +129 -0
  48. package/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.ts +52 -0
  49. package/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.ts +75 -0
  50. package/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.ts +477 -0
  51. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +8 -0
  52. package/Server/Middleware/IncidentFormRateLimit.ts +847 -0
  53. package/Server/Middleware/UserAuthorization.ts +16 -38
  54. package/Server/Services/AIService.ts +10 -13
  55. package/Server/Services/IncidentCustomFieldService.ts +112 -2
  56. package/Server/Services/IncidentEpisodeMemberService.ts +24 -4
  57. package/Server/Services/IncidentEpisodeService.ts +10 -1
  58. package/Server/Services/IncidentFormService.ts +1566 -0
  59. package/Server/Services/IncidentFormSubmissionService.ts +97 -0
  60. package/Server/Services/IncidentGroupingEngineService.ts +45 -8
  61. package/Server/Services/IncidentService.ts +123 -5
  62. package/Server/Services/IncidentTemplateService.ts +22 -0
  63. package/Server/Services/Index.ts +14 -0
  64. package/Server/Services/MessageQueueLabelRuleEngineService.ts +321 -0
  65. package/Server/Services/MessageQueueLabelRuleService.ts +14 -0
  66. package/Server/Services/MessageQueueOwnerRuleEngineService.ts +412 -0
  67. package/Server/Services/MessageQueueOwnerRuleService.ts +14 -0
  68. package/Server/Services/MessageQueueOwnerTeamService.ts +62 -0
  69. package/Server/Services/MessageQueueOwnerUserService.ts +62 -0
  70. package/Server/Services/MessageQueueService.ts +1463 -0
  71. package/Server/Services/OpenTelemetryIngestService.ts +37 -4
  72. package/Server/Services/ProjectService.ts +0 -59
  73. package/Server/Services/StatusPagePrivateUserService.ts +1 -4
  74. package/Server/Services/StatusPageService.ts +1 -51
  75. package/Server/Services/TeamComplianceSettingService.ts +163 -42
  76. package/Server/Services/UserNotificationRuleService.ts +8 -1
  77. package/Server/Services/WorkspaceNotificationSummaryService.ts +12 -3
  78. package/Server/Types/Database/Permissions/CreatePermission.ts +17 -3
  79. package/Server/Types/Database/Permissions/EditionPermission.ts +140 -38
  80. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +16 -0
  81. package/Server/Types/Database/Permissions/TablePermission.ts +3 -3
  82. package/Server/Types/Database/Permissions/UpdatePermission.ts +20 -6
  83. package/Server/Utils/AI/Chat/AgentContextCompactor.ts +200 -0
  84. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +307 -48
  85. package/Server/Utils/AI/Chat/ChatRunCancellation.ts +156 -0
  86. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +78 -18
  87. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  88. package/Server/Utils/AI/Chat/ToolOutputPager.ts +322 -0
  89. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +88 -30
  90. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +13 -1
  91. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +0 -32
  92. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +27 -25
  93. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +7 -1
  94. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +34 -14
  95. package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +69 -24
  96. package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +9 -0
  97. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +53 -10
  98. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +27 -10
  99. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +27 -10
  100. package/Server/Utils/AI/SRE/InvestigationQueue.ts +16 -19
  101. package/Server/Utils/AI/SRE/InvestigationThread.ts +646 -0
  102. package/Server/Utils/AI/SRE/InvestigationThreadService.ts +715 -0
  103. package/Server/Utils/AI/Toolbox/Serializer.ts +10 -3
  104. package/Server/Utils/EditionEnforcement.ts +19 -202
  105. package/Server/Utils/LLM/LLMService.ts +259 -63
  106. package/Server/Utils/RelaxedScimTeamLocksReport.ts +245 -0
  107. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
  108. package/Server/Utils/SameOriginRequest.ts +203 -0
  109. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
  110. package/Server/Utils/Telemetry/EntityRegistry.ts +4 -1
  111. package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +1402 -0
  112. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +4 -1
  113. package/Server/Utils/VendorAssets.ts +3 -3
  114. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +3 -1
  115. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +3 -1
  116. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +10 -1
  117. package/Tests/App/Accounts/IncidentFormPage.test.tsx +2036 -0
  118. package/Tests/App/Accounts/IncidentFormServerMessages.test.ts +119 -0
  119. package/Tests/App/Accounts/IncidentFormUtils.test.ts +1157 -0
  120. package/Tests/App/Accounts/LoginPasskey.test.tsx +6 -4
  121. package/Tests/App/Accounts/LoginSso.test.tsx +724 -0
  122. package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +338 -0
  123. package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +331 -0
  124. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +47 -33
  125. package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +1021 -0
  126. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +876 -78
  127. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +20 -3
  128. package/Tests/App/Dashboard/CephProxmoxVMwareDocumentationCards.test.tsx +359 -0
  129. package/Tests/App/Dashboard/CephSetupGuide.test.ts +961 -0
  130. package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +381 -95
  131. package/Tests/App/Dashboard/CloudSetupGuide.test.ts +1463 -0
  132. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +174 -12
  133. package/Tests/App/Dashboard/ContainerSetupGuideCards.test.tsx +345 -0
  134. package/Tests/App/Dashboard/CoreListEmptyStates.test.tsx +501 -0
  135. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +0 -1
  136. package/Tests/App/Dashboard/DatabaseDocumentationCard.test.tsx +400 -0
  137. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +5 -0
  138. package/Tests/App/Dashboard/DatabaseSetupGuide.test.ts +1869 -0
  139. package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +44 -0
  140. package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +50 -9
  141. package/Tests/App/Dashboard/DockerSetupGuide.test.ts +899 -0
  142. package/Tests/App/Dashboard/DockerSwarmSetupGuide.test.ts +964 -0
  143. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +141 -7
  144. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +52 -39
  145. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +7 -1
  146. package/Tests/App/Dashboard/GettingStartedTaskRoutes.test.tsx +331 -0
  147. package/Tests/App/Dashboard/HomeOverviewStatsFirstRun.test.tsx +925 -0
  148. package/Tests/App/Dashboard/HostDocumentationCard.test.tsx +225 -0
  149. package/Tests/App/Dashboard/HostSetupGuide.test.ts +1183 -0
  150. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +69 -45
  151. package/Tests/App/Dashboard/IncidentCreateTemplateCustomFieldSettings.test.tsx +745 -0
  152. package/Tests/App/Dashboard/IncidentCreateTemplateOwners.test.tsx +414 -0
  153. package/Tests/App/Dashboard/IncidentCustomFieldCreateSettingsForm.test.ts +1042 -0
  154. package/Tests/App/Dashboard/IncidentCustomFieldSettingsCard.test.tsx +1816 -0
  155. package/Tests/App/Dashboard/IncidentFormPlan.test.ts +89 -0
  156. package/Tests/App/Dashboard/IncidentFormShareLinkCard.test.tsx +846 -0
  157. package/Tests/App/Dashboard/IncidentFormsPages.test.tsx +1324 -0
  158. package/Tests/App/Dashboard/IncidentTemplateCustomFieldSettings.test.tsx +630 -0
  159. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +13 -0
  160. package/Tests/App/Dashboard/IncomingEmailMonitorLinkVerifyHint.test.tsx +104 -0
  161. package/Tests/App/Dashboard/InvestigationConversation.test.tsx +1107 -0
  162. package/Tests/App/Dashboard/InvestigationConversationData.test.ts +546 -0
  163. package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +170 -5
  164. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +207 -2
  165. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +729 -34
  166. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +9 -21
  167. package/Tests/App/Dashboard/InvestigationReportView.test.tsx +274 -37
  168. package/Tests/App/Dashboard/InvestigationStatusBadge.test.tsx +130 -0
  169. package/Tests/App/Dashboard/IoTDocumentationCard.test.tsx +218 -0
  170. package/Tests/App/Dashboard/IoTSetupGuide.test.ts +1124 -0
  171. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +20 -6
  172. package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +107 -83
  173. package/Tests/App/Dashboard/KubernetesSetupGuide.test.ts +787 -0
  174. package/Tests/App/Dashboard/MessageQueueBreadcrumbs.test.tsx +228 -0
  175. package/Tests/App/Dashboard/MessageQueueBrokerHealth.test.tsx +1538 -0
  176. package/Tests/App/Dashboard/MessageQueueBrokerHealthMetricChart.test.tsx +969 -0
  177. package/Tests/App/Dashboard/MessageQueueBrokerHealthReads.test.ts +889 -0
  178. package/Tests/App/Dashboard/MessageQueueBrokerMetricsReach.test.ts +236 -0
  179. package/Tests/App/Dashboard/MessageQueueDocumentationCard.test.tsx +479 -0
  180. package/Tests/App/Dashboard/MessageQueueListPages.test.tsx +1232 -0
  181. package/Tests/App/Dashboard/MessageQueueMetricDescriptions.test.ts +244 -0
  182. package/Tests/App/Dashboard/MessageQueueMonitorLink.test.ts +952 -0
  183. package/Tests/App/Dashboard/MessageQueueMonitorLinkMonitorCreate.test.tsx +859 -0
  184. package/Tests/App/Dashboard/MessageQueueOverview.test.tsx +1773 -0
  185. package/Tests/App/Dashboard/MessageQueueOverviewPresentation.test.ts +196 -0
  186. package/Tests/App/Dashboard/MessageQueuePresentation.test.ts +799 -0
  187. package/Tests/App/Dashboard/MessageQueueProducersConsumers.test.tsx +680 -0
  188. package/Tests/App/Dashboard/MessageQueueRoutes.test.tsx +383 -0
  189. package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +278 -0
  190. package/Tests/App/Dashboard/MessageQueueSetupGuide.test.ts +2778 -0
  191. package/Tests/App/Dashboard/MessageQueueSideMenus.test.tsx +273 -0
  192. package/Tests/App/Dashboard/MessageQueueSpanPopulations.test.ts +930 -0
  193. package/Tests/App/Dashboard/MessageQueueSpanStore.ts +351 -0
  194. package/Tests/App/Dashboard/MessageQueueTelemetryScope.test.ts +375 -0
  195. package/Tests/App/Dashboard/MessageQueueTelemetryScopeTabs.test.tsx +668 -0
  196. package/Tests/App/Dashboard/MessageQueueViewPages.test.tsx +685 -0
  197. package/Tests/App/Dashboard/MonitorAndHomeNotOperationalMenus.test.tsx +342 -0
  198. package/Tests/App/Dashboard/MonitorCreateFirstRunDefaults.test.tsx +623 -0
  199. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +442 -0
  200. package/Tests/App/Dashboard/MonitorLogsPageViewSummary.test.tsx +814 -0
  201. package/Tests/App/Dashboard/MonitorSetupCardBodies.test.tsx +246 -0
  202. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +8 -0
  203. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +27 -12
  204. package/Tests/App/Dashboard/PlanGatedPage.test.tsx +292 -0
  205. package/Tests/App/Dashboard/PodmanSetupGuide.test.ts +948 -0
  206. package/Tests/App/Dashboard/ProductOrientation.test.tsx +5 -4
  207. package/Tests/App/Dashboard/ProductSettingsSectionCollapsed.test.tsx +266 -0
  208. package/Tests/App/Dashboard/ProxmoxSetupGuide.test.ts +1318 -0
  209. package/Tests/App/Dashboard/ResourceAiAgentAttentionServerParity.test.ts +555 -0
  210. package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +298 -9
  211. package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +453 -0
  212. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +16 -0
  213. package/Tests/App/Dashboard/ResourceConnectionGuideCard.test.tsx +444 -0
  214. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsInfra.test.tsx +798 -0
  215. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsPlatforms.test.tsx +717 -0
  216. package/Tests/App/Dashboard/ResourceConnectionGuides.test.ts +981 -0
  217. package/Tests/App/Dashboard/ResourceConnectionState.test.ts +132 -0
  218. package/Tests/App/Dashboard/RumDocumentationCard.test.tsx +293 -0
  219. package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +467 -0
  220. package/Tests/App/Dashboard/RumSetupGuide.test.ts +758 -0
  221. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +25 -0
  222. package/Tests/App/Dashboard/ServerlessDocumentationCard.test.tsx +254 -0
  223. package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1074 -0
  224. package/Tests/App/Dashboard/SetupGuide.test.ts +246 -0
  225. package/Tests/App/Dashboard/SetupGuideCard.test.tsx +756 -0
  226. package/Tests/App/Dashboard/SloListSideMenu.test.tsx +120 -0
  227. package/Tests/App/Dashboard/SsoPages.test.tsx +833 -0
  228. package/Tests/App/Dashboard/TelemetryDocumentation.test.tsx +253 -0
  229. package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +730 -0
  230. package/Tests/App/Dashboard/VMwareSetupGuide.test.ts +1033 -0
  231. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +87 -7
  232. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +28 -9
  233. package/Tests/Models/DatabaseModels/IncidentFormModel.test.ts +1250 -0
  234. package/Tests/Models/DatabaseModels/MessageQueueModels.test.ts +1983 -0
  235. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  236. package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +190 -14
  237. package/Tests/Models/IncidentTemplateCustomFieldSettingsColumn.test.ts +291 -0
  238. package/Tests/Server/API/AIInvestigationConversationAPI.test.ts +412 -0
  239. package/Tests/Server/API/GlobalConfigLicense.test.ts +38 -9
  240. package/Tests/Server/API/IncidentFormAPI.test.ts +942 -0
  241. package/Tests/Server/API/IncidentFormPublicRoutes.test.ts +1653 -0
  242. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -1
  243. package/Tests/Server/API/{SsoProviderListingsEdition.test.ts → SsoProviderListings.test.ts} +164 -110
  244. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +76 -54
  245. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +125 -42
  246. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +36 -10
  247. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +51 -9
  248. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +13 -8
  249. package/Tests/Server/Enterprise/SsoInCommunityEdition.test.ts +540 -0
  250. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  251. package/Tests/Server/Infrastructure/Postgres/AddIncidentFormsMigration.test.ts +438 -0
  252. package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleNotificationChannelsMigration.test.ts +255 -0
  253. package/Tests/Server/Infrastructure/Postgres/MessageQueueTablesMigration.test.ts +637 -0
  254. package/Tests/Server/Middleware/IncidentFormRateLimit.test.ts +1630 -0
  255. package/Tests/Server/Middleware/UserAuthorization.test.ts +16 -17
  256. package/Tests/Server/Middleware/UserAuthorizationSsoEnforcement.test.ts +544 -0
  257. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +37 -8
  258. package/Tests/Server/Services/IncidentCreatedFeedTitle.test.ts +212 -0
  259. package/Tests/Server/Services/IncidentCustomFieldDeleteFormQuestions.test.ts +297 -0
  260. package/Tests/Server/Services/IncidentFormOwnersCreatedNotification.test.ts +497 -0
  261. package/Tests/Server/Services/IncidentFormPostgres.test.ts +958 -0
  262. package/Tests/Server/Services/IncidentFormPublicForm.test.ts +1260 -0
  263. package/Tests/Server/Services/IncidentFormPublicSubmission.test.ts +2520 -0
  264. package/Tests/Server/Services/IncidentFormRegistration.test.ts +159 -0
  265. package/Tests/Server/Services/IncidentFormService.test.ts +663 -0
  266. package/Tests/Server/Services/IncidentFormSubmissionService.test.ts +430 -0
  267. package/Tests/Server/Services/IncidentFormSubmissionTemplateBranch.test.ts +473 -0
  268. package/Tests/Server/Services/IncidentGroupingTemplateSubstitution.test.ts +81 -0
  269. package/Tests/Server/Services/IncidentTemplateCustomFieldSettings.test.ts +262 -0
  270. package/Tests/Server/Services/IncidentTemplateOwnersOnDeclare.test.ts +566 -0
  271. package/Tests/Server/Services/IncidentTitleMarkdownSinks.test.ts +640 -0
  272. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +3 -3
  273. package/Tests/Server/Services/MessageQueueOwnerServices.test.ts +440 -0
  274. package/Tests/Server/Services/MessageQueueRegistries.test.ts +577 -0
  275. package/Tests/Server/Services/MessageQueueRuleEngines.test.ts +900 -0
  276. package/Tests/Server/Services/MessageQueueService.test.ts +2210 -0
  277. package/Tests/Server/Services/MessageQueueSqlPostgres.test.ts +1271 -0
  278. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
  279. package/Tests/Server/Services/OpenTelemetryRetentionOverrideEdition.test.ts +474 -0
  280. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +21 -0
  281. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +3 -0
  282. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +0 -1
  283. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +56 -6
  284. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -1
  285. package/Tests/Server/Services/SsoRequirementReads.test.ts +454 -0
  286. package/Tests/Server/Services/SsoRequirementWrites.test.ts +529 -0
  287. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
  288. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +107 -89
  289. package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +1068 -176
  290. package/Tests/Server/Services/TeamComplianceSettingService.test.ts +1962 -200
  291. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +654 -297
  292. package/Tests/Server/Types/Database/Permissions/RetentionOverrideColumns.test.ts +784 -0
  293. package/Tests/Server/Types/Database/Permissions/SsoScalePlanGate.test.ts +418 -0
  294. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +0 -1
  295. package/Tests/Server/Utils/AI/AIInvestigationEngineRunLimits.test.ts +136 -0
  296. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +15 -14
  297. package/Tests/Server/Utils/AI/AgentContextCompactor.test.ts +351 -0
  298. package/Tests/Server/Utils/AI/ChatAgentRunnerSharedThread.test.ts +842 -0
  299. package/Tests/Server/Utils/AI/ChatRunCancellation.test.ts +195 -0
  300. package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +10 -57
  301. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +20 -24
  302. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +7 -30
  303. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +225 -29
  304. package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +266 -25
  305. package/Tests/Server/Utils/AI/InvestigationThread.test.ts +580 -0
  306. package/Tests/Server/Utils/AI/InvestigationThreadService.test.ts +801 -0
  307. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +525 -43
  308. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +4 -2
  309. package/Tests/Server/Utils/AI/LLMServiceUnreachableProvider.test.ts +435 -0
  310. package/Tests/Server/Utils/AI/ObservabilityAssistantLimits.test.ts +462 -0
  311. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +14 -25
  312. package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +2 -0
  313. package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +297 -15
  314. package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +10 -6
  315. package/Tests/Server/Utils/AI/ToolOutputPager.test.ts +382 -0
  316. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +23 -4
  317. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +25 -6
  318. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +14 -3
  319. package/Tests/Server/Utils/EditionEnforcement.test.ts +107 -147
  320. package/Tests/Server/Utils/{CommunityEditionSsoReport.test.ts → RelaxedScimTeamLocksReport.test.ts} +212 -208
  321. package/Tests/Server/Utils/SameOriginRequest.test.ts +372 -0
  322. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +20 -0
  323. package/Tests/Server/Utils/Telemetry/MessageQueueDiscovery.test.ts +2590 -0
  324. package/Tests/Server/Utils/Telemetry/MessageQueueSpanQueryTwin.ts +246 -0
  325. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +23 -0
  326. package/Tests/Types/AI/AIAgentRunLimits.test.ts +255 -0
  327. package/Tests/Types/Code/JsonSyntax.test.ts +1300 -0
  328. package/Tests/Types/CustomField/CustomFieldCreateSettings.test.ts +1113 -0
  329. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +91 -0
  330. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +30 -0
  331. package/Tests/Types/Incident/IncidentFormIpAllowlist.test.ts +227 -0
  332. package/Tests/Types/Incident/IncidentFormPublic.test.ts +1916 -0
  333. package/Tests/Types/MessageQueue/MessageQueueEntityKey.test.ts +916 -0
  334. package/Tests/Types/MessageQueue/MessageQueueIdentity.test.ts +567 -0
  335. package/Tests/Types/MessageQueue/MessageQueueManualIdentity.test.ts +686 -0
  336. package/Tests/Types/MessageQueue/MessageQueueMetricCatalog.test.ts +1726 -0
  337. package/Tests/Types/MessageQueue/MessageQueueMetricResolution.test.ts +1758 -0
  338. package/Tests/Types/MessageQueue/MessagingInstrumentationFixtures.test.ts +4686 -0
  339. package/Tests/Types/MessageQueue/MessagingSystem.test.ts +840 -0
  340. package/Tests/Types/MessageQueue/MessagingTelemetryFixtures.ts +3287 -0
  341. package/Tests/Types/MessageQueue/MessagingTelemetryResolver.test.ts +2966 -0
  342. package/Tests/Types/Monitor/MessageQueueAlertTemplates.test.ts +5401 -0
  343. package/Tests/Types/Monitor/MetricEngineFold.ts +154 -0
  344. package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +5 -3
  345. package/Tests/Types/Team/ComplianceRule.test.ts +588 -37
  346. package/Tests/Types/Team/TeamComplianceStatus.test.ts +64 -11
  347. package/Tests/Types/XML.test.ts +51 -0
  348. package/Tests/UI/Components/CodeEditor/CodeEditor.test.tsx +2362 -0
  349. package/Tests/UI/Components/CodeEditor/CodeEditorCommands.test.ts +810 -0
  350. package/Tests/UI/Components/CodeEditor/CodeEditorHighlight.test.ts +338 -0
  351. package/Tests/UI/Components/CodeEditor/CodeEditorLanguages.test.ts +222 -0
  352. package/Tests/UI/Components/CodeEditor/CodeEditorStyles.test.ts +807 -0
  353. package/Tests/UI/Components/CodeEditor/NoMonaco.test.ts +245 -0
  354. package/Tests/UI/Components/CodeEditor/YamlEditor.test.tsx +729 -0
  355. package/Tests/UI/Components/CopyTextButton.test.tsx +76 -0
  356. package/Tests/UI/Components/EditionLabelLapseCopy.ts +51 -14
  357. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +131 -23
  358. package/Tests/UI/Components/ErrorMessageAction.test.tsx +142 -0
  359. package/Tests/UI/Components/FacetSidebarInScope.test.tsx +459 -0
  360. package/Tests/UI/Components/FacetValuesInScope.test.ts +270 -0
  361. package/Tests/UI/Components/Forms/FormFieldCodeEditors.test.tsx +294 -0
  362. package/Tests/UI/Components/Forms/FormFieldMarkdown.test.tsx +126 -0
  363. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +22 -75
  364. package/Tests/UI/Components/Forms/ModelFormOnBeforeCreateMiscData.test.tsx +254 -0
  365. package/Tests/UI/Components/Icon.test.tsx +32 -0
  366. package/Tests/UI/Components/Input.test.tsx +31 -0
  367. package/Tests/UI/Components/LockedFilterChipScope.test.tsx +501 -0
  368. package/Tests/UI/Components/MarkdownConverters.test.ts +253 -1
  369. package/Tests/UI/Components/MarkdownEditor.test.tsx +2785 -2
  370. package/Tests/UI/Components/MarkdownEditorHistory.test.ts +243 -0
  371. package/Tests/UI/Components/MarkdownListEditing.test.ts +1118 -0
  372. package/Tests/UI/Components/MarkdownPaste.test.ts +1180 -0
  373. package/Tests/UI/Components/MarkdownViewerCopy.test.tsx +466 -0
  374. package/Tests/UI/Components/MarkdownVisualEditing.test.ts +1089 -0
  375. package/Tests/UI/Components/ModelTable/BaseModelTableEmptyStateAction.test.tsx +623 -0
  376. package/Tests/UI/Components/ResetObjectID.test.tsx +282 -0
  377. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  378. package/Tests/UI/Components/Table/EmptyTableMessage.test.ts +439 -0
  379. package/Tests/UI/Components/Table/TableEmptyState.test.tsx +352 -0
  380. package/Tests/UI/Components/TableRowMobileTitles.test.tsx +78 -0
  381. package/Tests/UI/Components/TextArea.test.tsx +19 -0
  382. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +12 -29
  383. package/Tests/UI/Components/fixtures/MarkdownPasteFixtures.ts +460 -0
  384. package/Tests/UI/EsbuildConfig.test.ts +115 -39
  385. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +4 -4
  386. package/Tests/UI/Monitor/MonitorLogSummaryRender.test.tsx +377 -0
  387. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +81 -1
  388. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +17 -0
  389. package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
  390. package/Tests/Utils/Markdown/DashboardMarkdownRenderer.ts +81 -0
  391. package/Tests/Utils/Markdown/UntrustedMarkdown.test.ts +1339 -0
  392. package/Tests/Utils/Monitor/MonitorLogSummaryUtil.test.ts +862 -0
  393. package/Types/AI/AIAgentRunLimits.ts +146 -0
  394. package/Types/Code/CodeType.ts +2 -0
  395. package/Types/Code/JsonSyntax.ts +923 -0
  396. package/Types/CustomField/CustomFieldCreateSettings.ts +549 -0
  397. package/Types/CustomField/CustomFieldMappingCatalog.ts +77 -0
  398. package/Types/CustomField/CustomFieldValueValidator.ts +10 -7
  399. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +1 -1
  400. package/Types/Icon/IconProp.ts +2 -0
  401. package/Types/Incident/IncidentFormIpAllowlist.ts +206 -0
  402. package/Types/Incident/IncidentFormPublic.ts +1145 -0
  403. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +10 -3
  404. package/Types/MessageQueue/MessageQueueIdentity.ts +256 -0
  405. package/Types/MessageQueue/MessageQueueManualIdentity.ts +325 -0
  406. package/Types/MessageQueue/MessageQueueMetricCatalog.ts +1357 -0
  407. package/Types/MessageQueue/MessagingSystem.ts +518 -0
  408. package/Types/MessageQueue/MessagingTelemetryResolver.ts +2311 -0
  409. package/Types/Monitor/MessageQueueAlertTemplates.ts +2128 -0
  410. package/Types/Permission.ts +310 -0
  411. package/Types/ResourceAiAgent/ResourceAiAccess.ts +10 -4
  412. package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
  413. package/Types/Rules/RuleRun.ts +4 -0
  414. package/Types/Team/ComplianceNotificationChannel.ts +4 -3
  415. package/Types/Team/ComplianceRule.ts +71 -18
  416. package/Types/Team/ComplianceRuleType.ts +2 -2
  417. package/Types/Team/TeamComplianceStatus.ts +6 -2
  418. package/Types/Telemetry/EntityType.ts +16 -0
  419. package/Types/Telemetry/LockedFilterDetail.ts +22 -0
  420. package/Types/XML.ts +26 -0
  421. package/UI/Components/CodeEditor/CodeEditor.css +379 -0
  422. package/UI/Components/CodeEditor/CodeEditor.tsx +1128 -294
  423. package/UI/Components/CodeEditor/CodeEditorCommands.ts +774 -0
  424. package/UI/Components/CodeEditor/CodeEditorHighlight.ts +106 -0
  425. package/UI/Components/CodeEditor/CodeEditorLanguages.ts +164 -0
  426. package/UI/Components/CodeEditor/YamlEditor.tsx +28 -326
  427. package/UI/Components/CopyTextButton/CopyTextButton.tsx +5 -1
  428. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +6 -25
  429. package/UI/Components/EditionLabel/EditionLabel.tsx +14 -13
  430. package/UI/Components/ErrorMessage/ErrorMessage.tsx +11 -1
  431. package/UI/Components/Forms/Fields/FormField.tsx +8 -0
  432. package/UI/Components/Forms/Types/Field.ts +8 -0
  433. package/UI/Components/Icon/Icon.tsx +18 -0
  434. package/UI/Components/Input/Input.tsx +11 -4
  435. package/UI/Components/LogsViewer/LogsViewer.tsx +4 -0
  436. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +21 -3
  437. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  438. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +877 -79
  439. package/UI/Components/Markdown.tsx/MarkdownEditorHistory.ts +284 -0
  440. package/UI/Components/Markdown.tsx/MarkdownListEditing.ts +1362 -0
  441. package/UI/Components/Markdown.tsx/MarkdownPaste.ts +1326 -0
  442. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +106 -10
  443. package/UI/Components/Markdown.tsx/MarkdownVisualEditing.ts +1032 -0
  444. package/UI/Components/ModelTable/BaseModelTable.tsx +85 -7
  445. package/UI/Components/ResetObjectID/ResetObjectID.tsx +35 -9
  446. package/UI/Components/Table/EmptyTableMessage.ts +81 -0
  447. package/UI/Components/Table/Table.tsx +50 -21
  448. package/UI/Components/Table/TableRow.tsx +9 -1
  449. package/UI/Components/TelemetryViewer/FacetVisibility.ts +97 -2
  450. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +13 -0
  451. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +214 -7
  452. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +21 -3
  453. package/UI/Components/TextArea/TextArea.tsx +9 -2
  454. package/UI/Components/Workflow/ModelFieldPicker.tsx +10 -12
  455. package/UI/Styles/Theme.css +8 -0
  456. package/UI/esbuild-config.js +2 -32
  457. package/Utils/LabelRuleImportExport.ts +2 -0
  458. package/Utils/Markdown/UntrustedMarkdown.ts +1513 -0
  459. package/Utils/Monitor/IncomingEmailMonitorRequestUtil.ts +41 -0
  460. package/Utils/Monitor/MonitorLogSummaryUtil.ts +212 -0
  461. package/Utils/Telemetry/EntityKey.ts +48 -0
  462. package/build/dist/Models/DatabaseModels/AIConversation.js +125 -1
  463. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
  464. package/build/dist/Models/DatabaseModels/CephCluster.js +12 -0
  465. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  466. package/build/dist/Models/DatabaseModels/CloudResource.js +12 -0
  467. package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
  468. package/build/dist/Models/DatabaseModels/DatabaseServer.js +12 -0
  469. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
  470. package/build/dist/Models/DatabaseModels/DockerHost.js +12 -0
  471. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  472. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +12 -0
  473. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
  474. package/build/dist/Models/DatabaseModels/GlobalOidc.js +0 -4
  475. package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
  476. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +0 -4
  477. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  478. package/build/dist/Models/DatabaseModels/GlobalSso.js +0 -4
  479. package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
  480. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +0 -4
  481. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  482. package/build/dist/Models/DatabaseModels/Host.js +12 -0
  483. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  484. package/build/dist/Models/DatabaseModels/IncidentForm.js +605 -0
  485. package/build/dist/Models/DatabaseModels/IncidentForm.js.map +1 -0
  486. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js +299 -0
  487. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js.map +1 -0
  488. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +60 -0
  489. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  490. package/build/dist/Models/DatabaseModels/Index.js +14 -0
  491. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  492. package/build/dist/Models/DatabaseModels/IoTFleet.js +12 -0
  493. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  494. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +12 -0
  495. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  496. package/build/dist/Models/DatabaseModels/MessageQueue.js +1106 -0
  497. package/build/dist/Models/DatabaseModels/MessageQueue.js.map +1 -0
  498. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js +562 -0
  499. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js.map +1 -0
  500. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js +643 -0
  501. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js.map +1 -0
  502. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js +506 -0
  503. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js.map +1 -0
  504. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js +505 -0
  505. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js.map +1 -0
  506. package/build/dist/Models/DatabaseModels/PodmanHost.js +12 -0
  507. package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
  508. package/build/dist/Models/DatabaseModels/Project.js +61 -0
  509. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  510. package/build/dist/Models/DatabaseModels/ProjectOidc.js +0 -4
  511. package/build/dist/Models/DatabaseModels/ProjectOidc.js.map +1 -1
  512. package/build/dist/Models/DatabaseModels/ProjectSso.js +0 -4
  513. package/build/dist/Models/DatabaseModels/ProjectSso.js.map +1 -1
  514. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +12 -0
  515. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  516. package/build/dist/Models/DatabaseModels/RumApplication.js +12 -0
  517. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  518. package/build/dist/Models/DatabaseModels/ServerlessFunction.js +12 -0
  519. package/build/dist/Models/DatabaseModels/ServerlessFunction.js.map +1 -1
  520. package/build/dist/Models/DatabaseModels/Service.js +12 -0
  521. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  522. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +0 -4
  523. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  524. package/build/dist/Models/DatabaseModels/StatusPageSso.js +0 -4
  525. package/build/dist/Models/DatabaseModels/StatusPageSso.js.map +1 -1
  526. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +49 -3
  527. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
  528. package/build/dist/Models/DatabaseModels/VMwareVCenter.js +12 -0
  529. package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
  530. package/build/dist/Server/API/AIChatAPI.js +9 -103
  531. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  532. package/build/dist/Server/API/AIInvestigationAPI.js +3 -3
  533. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  534. package/build/dist/Server/API/AIInvestigationConversationAPI.js +162 -0
  535. package/build/dist/Server/API/AIInvestigationConversationAPI.js.map +1 -0
  536. package/build/dist/Server/API/IncidentFormAPI.js +245 -0
  537. package/build/dist/Server/API/IncidentFormAPI.js.map +1 -0
  538. package/build/dist/Server/API/ProjectOIDC.js +16 -24
  539. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  540. package/build/dist/Server/API/ProjectSSO.js +16 -24
  541. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  542. package/build/dist/Server/API/StatusPageAPI.js +42 -75
  543. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  544. package/build/dist/Server/Enterprise/EnterpriseEdition.js +79 -25
  545. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -1
  546. package/build/dist/Server/Enterprise/EnterpriseFeature.js +24 -3
  547. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -1
  548. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +1 -1
  549. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -1
  550. package/build/dist/Server/EnvironmentConfig.js +1 -1
  551. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js +63 -0
  552. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js.map +1 -0
  553. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js +41 -0
  554. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js.map +1 -0
  555. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js +40 -0
  556. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js.map +1 -0
  557. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js +183 -0
  558. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js.map +1 -0
  559. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +8 -0
  560. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  561. package/build/dist/Server/Middleware/IncidentFormRateLimit.js +559 -0
  562. package/build/dist/Server/Middleware/IncidentFormRateLimit.js.map +1 -0
  563. package/build/dist/Server/Middleware/UserAuthorization.js +11 -30
  564. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  565. package/build/dist/Server/Services/AIService.js +10 -13
  566. package/build/dist/Server/Services/AIService.js.map +1 -1
  567. package/build/dist/Server/Services/IncidentCustomFieldService.js +83 -0
  568. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  569. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +8 -4
  570. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  571. package/build/dist/Server/Services/IncidentEpisodeService.js +10 -1
  572. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  573. package/build/dist/Server/Services/IncidentFormService.js +1202 -0
  574. package/build/dist/Server/Services/IncidentFormService.js.map +1 -0
  575. package/build/dist/Server/Services/IncidentFormSubmissionService.js +91 -0
  576. package/build/dist/Server/Services/IncidentFormSubmissionService.js.map +1 -0
  577. package/build/dist/Server/Services/IncidentGroupingEngineService.js +20 -8
  578. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  579. package/build/dist/Server/Services/IncidentService.js +106 -4
  580. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  581. package/build/dist/Server/Services/IncidentTemplateService.js +18 -0
  582. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  583. package/build/dist/Server/Services/Index.js +14 -0
  584. package/build/dist/Server/Services/Index.js.map +1 -1
  585. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js +262 -0
  586. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js.map +1 -0
  587. package/build/dist/Server/Services/MessageQueueLabelRuleService.js +13 -0
  588. package/build/dist/Server/Services/MessageQueueLabelRuleService.js.map +1 -0
  589. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js +334 -0
  590. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js.map +1 -0
  591. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js +13 -0
  592. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js.map +1 -0
  593. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js +62 -0
  594. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js.map +1 -0
  595. package/build/dist/Server/Services/MessageQueueOwnerUserService.js +62 -0
  596. package/build/dist/Server/Services/MessageQueueOwnerUserService.js.map +1 -0
  597. package/build/dist/Server/Services/MessageQueueService.js +1140 -0
  598. package/build/dist/Server/Services/MessageQueueService.js.map +1 -0
  599. package/build/dist/Server/Services/OpenTelemetryIngestService.js +25 -4
  600. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  601. package/build/dist/Server/Services/ProjectService.js +0 -54
  602. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  603. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -4
  604. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  605. package/build/dist/Server/Services/StatusPageService.js +0 -46
  606. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  607. package/build/dist/Server/Services/TeamComplianceSettingService.js +120 -31
  608. package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
  609. package/build/dist/Server/Services/UserNotificationRuleService.js +8 -1
  610. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  611. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +12 -3
  612. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
  613. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +6 -3
  614. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  615. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +109 -37
  616. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  617. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +16 -0
  618. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  619. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +3 -3
  620. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +9 -6
  621. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  622. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js +128 -0
  623. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js.map +1 -0
  624. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +192 -50
  625. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  626. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js +133 -0
  627. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js.map +1 -0
  628. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +53 -13
  629. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  630. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  631. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js +206 -0
  632. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js.map +1 -0
  633. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +53 -26
  634. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
  635. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +4 -2
  636. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
  637. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +1 -29
  638. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  639. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +24 -24
  640. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  641. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +7 -2
  642. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  643. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +29 -14
  644. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  645. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +38 -14
  646. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -1
  647. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +2 -0
  648. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -1
  649. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +40 -10
  650. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  651. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +19 -7
  652. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  653. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +19 -7
  654. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  655. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +15 -18
  656. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  657. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js +412 -0
  658. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js.map +1 -0
  659. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js +495 -0
  660. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js.map +1 -0
  661. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +10 -3
  662. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
  663. package/build/dist/Server/Utils/EditionEnforcement.js +20 -158
  664. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -1
  665. package/build/dist/Server/Utils/LLM/LLMService.js +193 -54
  666. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  667. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js +160 -0
  668. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js.map +1 -0
  669. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
  670. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  671. package/build/dist/Server/Utils/SameOriginRequest.js +151 -0
  672. package/build/dist/Server/Utils/SameOriginRequest.js.map +1 -0
  673. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
  674. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
  675. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -1
  676. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  677. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +1015 -0
  678. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -0
  679. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +4 -1
  680. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  681. package/build/dist/Server/Utils/VendorAssets.js +3 -3
  682. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +3 -1
  683. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  684. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +3 -1
  685. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  686. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +10 -1
  687. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  688. package/build/dist/Types/AI/AIAgentRunLimits.js +91 -0
  689. package/build/dist/Types/AI/AIAgentRunLimits.js.map +1 -0
  690. package/build/dist/Types/Code/CodeType.js +2 -0
  691. package/build/dist/Types/Code/CodeType.js.map +1 -1
  692. package/build/dist/Types/Code/JsonSyntax.js +604 -0
  693. package/build/dist/Types/Code/JsonSyntax.js.map +1 -0
  694. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js +310 -0
  695. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js.map +1 -0
  696. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +38 -0
  697. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -1
  698. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +10 -7
  699. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -1
  700. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +1 -1
  701. package/build/dist/Types/Icon/IconProp.js +2 -0
  702. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  703. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js +119 -0
  704. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js.map +1 -0
  705. package/build/dist/Types/Incident/IncidentFormPublic.js +678 -0
  706. package/build/dist/Types/Incident/IncidentFormPublic.js.map +1 -0
  707. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +10 -3
  708. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
  709. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js +184 -0
  710. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js.map +1 -0
  711. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js +190 -0
  712. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js.map +1 -0
  713. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js +1057 -0
  714. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js.map +1 -0
  715. package/build/dist/Types/MessageQueue/MessagingSystem.js +394 -0
  716. package/build/dist/Types/MessageQueue/MessagingSystem.js.map +1 -0
  717. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js +1768 -0
  718. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js.map +1 -0
  719. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js +1207 -0
  720. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js.map +1 -0
  721. package/build/dist/Types/Permission.js +274 -0
  722. package/build/dist/Types/Permission.js.map +1 -1
  723. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +10 -4
  724. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -1
  725. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +12 -0
  726. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  727. package/build/dist/Types/Rules/RuleRun.js +4 -0
  728. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  729. package/build/dist/Types/Team/ComplianceNotificationChannel.js +4 -3
  730. package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -1
  731. package/build/dist/Types/Team/ComplianceRule.js +48 -14
  732. package/build/dist/Types/Team/ComplianceRule.js.map +1 -1
  733. package/build/dist/Types/Team/ComplianceRuleType.js +2 -2
  734. package/build/dist/Types/Telemetry/EntityType.js +16 -0
  735. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  736. package/build/dist/Types/XML.js +23 -0
  737. package/build/dist/Types/XML.js.map +1 -1
  738. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +641 -266
  739. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  740. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js +464 -0
  741. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js.map +1 -0
  742. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js +69 -0
  743. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js.map +1 -0
  744. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js +108 -0
  745. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js.map +1 -0
  746. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +14 -186
  747. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -1
  748. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  749. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  750. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +5 -14
  751. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -1
  752. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +14 -13
  753. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  754. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +1 -1
  755. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  756. package/build/dist/UI/Components/Forms/Fields/FormField.js +8 -3
  757. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  758. package/build/dist/UI/Components/Icon/Icon.js +8 -0
  759. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  760. package/build/dist/UI/Components/Input/Input.js +11 -3
  761. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  762. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +2 -1
  763. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  764. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +14 -4
  765. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  766. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  767. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  768. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +710 -65
  769. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
  770. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js +238 -0
  771. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js.map +1 -0
  772. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js +1028 -0
  773. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js.map +1 -0
  774. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js +1088 -0
  775. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js.map +1 -0
  776. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +70 -10
  777. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  778. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js +887 -0
  779. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js.map +1 -0
  780. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +57 -6
  781. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  782. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +7 -5
  783. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
  784. package/build/dist/UI/Components/Table/EmptyTableMessage.js +51 -0
  785. package/build/dist/UI/Components/Table/EmptyTableMessage.js.map +1 -0
  786. package/build/dist/UI/Components/Table/Table.js +30 -11
  787. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  788. package/build/dist/UI/Components/Table/TableRow.js +9 -2
  789. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  790. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +63 -1
  791. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -1
  792. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +4 -2
  793. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  794. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +91 -10
  795. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
  796. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +14 -4
  797. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  798. package/build/dist/UI/Components/TextArea/TextArea.js +9 -3
  799. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  800. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js +1 -2
  801. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js.map +1 -1
  802. package/build/dist/Utils/LabelRuleImportExport.js +2 -0
  803. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  804. package/build/dist/Utils/Markdown/UntrustedMarkdown.js +988 -0
  805. package/build/dist/Utils/Markdown/UntrustedMarkdown.js.map +1 -0
  806. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js +34 -0
  807. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js.map +1 -0
  808. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js +148 -0
  809. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js.map +1 -0
  810. package/build/dist/Utils/Telemetry/EntityKey.js +36 -0
  811. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  812. package/package.json +1 -3
  813. package/Server/Utils/CommunityEditionSsoReport.ts +0 -361
  814. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +0 -616
  815. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +0 -217
  816. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +0 -271
  817. package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +0 -215
  818. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +0 -784
  819. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +0 -518
  820. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +0 -419
  821. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +0 -769
  822. package/Tests/UI/Components/CodeEditor.test.tsx +0 -638
  823. package/Tests/UI/Components/MonacoLoader.test.ts +0 -67
  824. package/Tests/UI/Components/MonacoRuntime.test.ts +0 -121
  825. package/Tests/UI/Components/Telemetry/TelemetryRetentionConfigForm.test.tsx +0 -329
  826. package/Tests/UI/Components/YamlEditor.test.tsx +0 -847
  827. package/UI/Components/CodeEditor/MonacoLoader.ts +0 -36
  828. package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -319
  829. package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +0 -223
  830. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +0 -223
  831. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +0 -1
  832. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +0 -34
  833. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +0 -1
  834. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +0 -171
  835. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +0 -1
  836. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +0 -119
  837. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js.map +0 -1
@@ -1,49 +1,134 @@
1
- import Editor from "@monaco-editor/react";
2
- import configureMonacoLoader from "./MonacoLoader";
1
+ import "./CodeEditor.css";
2
+ import {
3
+ EditorState,
4
+ IndentUnit,
5
+ LineColumn,
6
+ TextEdit,
7
+ applyTextEdit,
8
+ backspace,
9
+ countLines,
10
+ detectIndentUnit,
11
+ getLineColumn,
12
+ indent,
13
+ indentLines,
14
+ lineEndOf,
15
+ lineStartOf,
16
+ newLine,
17
+ outdent,
18
+ spacesIndent,
19
+ toggleLineComment,
20
+ typeCharacter,
21
+ } from "./CodeEditorCommands";
22
+ import { escapeHtml, highlightCode } from "./CodeEditorHighlight";
23
+ import { CodeLanguage, getCodeLanguage } from "./CodeEditorLanguages";
24
+ import Icon from "../Icon/Icon";
3
25
  import CodeType from "../../../Types/Code/CodeType";
4
- import MarkdownUtil from "../../Utils/Markdown";
5
- import { Theme, useTheme } from "../../Utils/Theme";
26
+ import {
27
+ JsonSyntaxCheckResult,
28
+ checkJsonSyntax,
29
+ describeJsonSyntaxError,
30
+ findJsonSyntaxError,
31
+ formatJson,
32
+ } from "../../../Types/Code/JsonSyntax";
33
+ import {
34
+ YamlSyntaxCheckResult,
35
+ checkYamlSyntax,
36
+ describeYamlSyntaxError,
37
+ } from "../../../Types/Code/YamlSyntax";
38
+ import IconProp from "../../../Types/Icon/IconProp";
6
39
  import React, {
7
40
  FunctionComponent,
8
41
  ReactElement,
9
42
  useEffect,
43
+ useId,
44
+ useLayoutEffect,
10
45
  useMemo,
11
46
  useRef,
12
47
  useState,
13
48
  } from "react";
14
49
 
15
- configureMonacoLoader();
16
-
17
50
  export interface ComponentProps {
51
+ type: CodeType;
52
+ /** The controlled value. Wins over `initialValue` whenever it is set. */
53
+ value?: string | undefined;
54
+ /** Seeds an editor that is not given `value`. */
18
55
  initialValue?: undefined | string;
19
- onClick?: undefined | (() => void);
20
- placeholder?: undefined | string;
21
- className?: undefined | string;
22
56
  onChange?: undefined | ((value: string) => void);
23
- readOnly?: boolean | undefined;
24
- type: CodeType;
25
57
  onFocus?: (() => void) | undefined;
26
58
  onBlur?: (() => void) | undefined;
59
+ onClick?: undefined | (() => void);
60
+ /** Shown dimmed in the empty editor. Never becomes document text. */
61
+ placeholder?: undefined | string;
62
+ /**
63
+ * Sample code for an empty editor: shown dimmed and highlighted in place of
64
+ * the document, and offered by an "Insert example" button.
65
+ */
66
+ example?: string | undefined;
67
+ /** One short line of guidance in the toolbar. */
68
+ hint?: string | undefined;
69
+ error?: string | undefined;
70
+ readOnly?: boolean | undefined;
71
+ className?: undefined | string;
27
72
  dataTestId?: string | undefined;
28
73
  tabIndex?: number | undefined;
29
- error?: string | undefined;
30
- value?: string | undefined;
74
+ /** Id of the textarea, for a <label htmlFor>. */
75
+ id?: string | undefined;
76
+ /** The line number gutter. On for everything but wrapped prose. */
31
77
  showLineNumbers?: boolean | undefined;
32
78
  disableSpellCheck?: boolean | undefined;
33
79
  ariaLabelledby?: string | undefined;
34
80
  /** Ids of the elements describing this control (hint, status, error). */
35
81
  ariaDescribedby?: string | undefined;
36
- /** Marks the control invalid to assistive technology. */
82
+ /**
83
+ * Marks the control invalid to assistive technology. Implied by `error`;
84
+ * for a caller that reports the problem somewhere else.
85
+ */
37
86
  ariaInvalid?: boolean | undefined;
38
- /** CSS height handed to Monaco. Defaults to "30vh". */
87
+ /**
88
+ * A fixed CSS height for the text area. Without it the editor grows with
89
+ * its content from `minLines` up to `maxHeight`, then scrolls.
90
+ */
39
91
  height?: string | undefined;
92
+ minLines?: number | undefined;
93
+ maxHeight?: string | undefined;
94
+ /** JSON only: the field is read with JSON5, so judge it by JSON5's rules. */
95
+ allowJSON5?: boolean | undefined;
40
96
  }
41
97
 
98
+ /*
99
+ * These two have to match .ou-code-editor's --ou-code-line-height and
100
+ * --ou-code-padding-y in CodeEditor.css: the gutter's click target and the
101
+ * current-line band are placed with them.
102
+ */
103
+ export const CODE_EDITOR_LINE_HEIGHT_PX: number = 20;
104
+ export const CODE_EDITOR_PADDING_Y_PX: number = 10;
105
+ export const CODE_EDITOR_PADDING_X_PX: number = 12;
106
+
107
+ // Columns a tab advances to, as `tab-size` in CodeEditor.css draws it.
108
+ const TAB_SIZE: number = 4;
109
+
110
+ // Characters in the hidden run the character width is measured from.
111
+ const MEASURE_LENGTH: number = 32;
112
+
113
+ export const CODE_EDITOR_DEFAULT_MIN_LINES: number = 5;
114
+ export const CODE_EDITOR_DEFAULT_MAX_HEIGHT: string = "min(60vh, 30rem)";
115
+
116
+ /** How long the document sits still before it is checked again. */
117
+ export const CODE_EDITOR_VALIDATION_DEBOUNCE_MS: number = 250;
118
+
119
+ const FALLBACK_INDENT: IndentUnit = spacesIndent(2);
120
+
42
121
  /*
43
122
  * Callers hand us `any` through Form's currentValues, so a non-string can
44
- * still reach a prop typed as string.
123
+ * still reach a prop typed as string. Line breaks are normalised because a
124
+ * textarea's value always reads back with "\n": keeping "\r\n" here would
125
+ * put the highlighted layer one character per line out of step with it.
45
126
  */
46
- function toEditorText(value: string | undefined): string {
127
+ type ToEditorTextFunction = (value: string | undefined) => string;
128
+
129
+ export const toEditorText: ToEditorTextFunction = (
130
+ value: string | undefined,
131
+ ): string => {
47
132
  if (value === undefined || value === null) {
48
133
  return "";
49
134
  }
@@ -52,366 +137,1115 @@ function toEditorText(value: string | undefined): string {
52
137
  return JSON.stringify(value, null, 4);
53
138
  }
54
139
 
55
- return value;
140
+ return value.replace(/\r\n?/g, "\n");
141
+ };
142
+
143
+ type SetNativeValueFunction = (
144
+ textarea: HTMLTextAreaElement,
145
+ value: string,
146
+ ) => void;
147
+
148
+ /*
149
+ * Through the prototype's setter, not `textarea.value =`: React watches the
150
+ * instance property to know what it last rendered, and a write through it
151
+ * would make the input event below look like no change at all.
152
+ */
153
+ const setNativeValue: SetNativeValueFunction = (
154
+ textarea: HTMLTextAreaElement,
155
+ value: string,
156
+ ): void => {
157
+ const descriptor: PropertyDescriptor | undefined =
158
+ Object.getOwnPropertyDescriptor(Object.getPrototypeOf(textarea), "value");
159
+
160
+ if (descriptor?.set) {
161
+ descriptor.set.call(textarea, value);
162
+ } else {
163
+ textarea.value = value;
164
+ }
165
+ };
166
+
167
+ export type ApplyEditToTextareaFunction = (
168
+ textarea: HTMLTextAreaElement,
169
+ edit: TextEdit,
170
+ ) => void;
171
+
172
+ /**
173
+ * Make `edit` in the textarea the way typing would, so it lands on the
174
+ * browser's own undo stack as one step. execCommand is deprecated but is
175
+ * still the only way to do that, in every browser; where it is missing
176
+ * (jsdom) or declines, the value is written directly and an input event
177
+ * fired, which keeps React in step at the cost of that one undo entry.
178
+ */
179
+ export const applyEditToTextarea: ApplyEditToTextareaFunction = (
180
+ textarea: HTMLTextAreaElement,
181
+ edit: TextEdit,
182
+ ): void => {
183
+ const expected: string = applyTextEdit(textarea.value, edit);
184
+
185
+ if (edit.from !== edit.to || edit.insert !== "") {
186
+ textarea.setSelectionRange(edit.from, edit.to);
187
+
188
+ let applied: boolean = false;
189
+
190
+ try {
191
+ if (typeof document.execCommand === "function") {
192
+ applied =
193
+ edit.insert === ""
194
+ ? document.execCommand("delete", false)
195
+ : document.execCommand("insertText", false, edit.insert);
196
+ }
197
+ } catch {
198
+ applied = false;
199
+ }
200
+
201
+ if (!applied || textarea.value !== expected) {
202
+ setNativeValue(textarea, expected);
203
+ textarea.dispatchEvent(new Event("input", { bubbles: true }));
204
+ }
205
+ }
206
+
207
+ textarea.setSelectionRange(edit.selectionStart, edit.selectionEnd);
208
+ };
209
+
210
+ interface SelectionShape {
211
+ start: number;
212
+ end: number;
213
+ /** The end the caret is on. */
214
+ active: number;
215
+ }
216
+
217
+ interface GutterSegment {
218
+ text: string;
219
+ className?: string | undefined;
220
+ }
221
+
222
+ type BuildGutterFunction = (
223
+ lineCount: number,
224
+ marks: Map<number, string>,
225
+ ) => Array<GutterSegment>;
226
+
227
+ /*
228
+ * The gutter is one run of text - "1\n2\n3..." - so a long document costs
229
+ * a handful of nodes, not one per line. Only the lines that look different
230
+ * (the current line, a line with a syntax error) are split out.
231
+ */
232
+ const buildGutter: BuildGutterFunction = (
233
+ lineCount: number,
234
+ marks: Map<number, string>,
235
+ ): Array<GutterSegment> => {
236
+ const segments: Array<GutterSegment> = [];
237
+ let buffer: string = "";
238
+
239
+ for (let line: number = 1; line <= lineCount; line++) {
240
+ const className: string | undefined = marks.get(line);
241
+ const separator: string = line < lineCount ? "\n" : "";
242
+
243
+ if (className) {
244
+ if (buffer) {
245
+ segments.push({ text: buffer });
246
+ }
247
+
248
+ segments.push({ text: String(line), className });
249
+ buffer = separator;
250
+ continue;
251
+ }
252
+
253
+ buffer += String(line) + separator;
254
+ }
255
+
256
+ if (buffer) {
257
+ segments.push({ text: buffer });
258
+ }
259
+
260
+ return segments;
261
+ };
262
+
263
+ const MODIFIER_KEYS: Array<string> = ["Shift", "Control", "Alt", "Meta"];
264
+
265
+ /*
266
+ * Heard on the way in, through aria-describedby: Tab indents here, so the way
267
+ * out has to be announced rather than discovered.
268
+ */
269
+ export const CODE_EDITOR_KEYS_HINT: string =
270
+ "Tab inserts indentation. To move focus out of the editor, press Escape, then Tab.";
271
+
272
+ type StatusTone = "error" | "valid" | "invalid" | "neutral";
273
+
274
+ interface StatusShape {
275
+ tone: StatusTone;
276
+ icon: IconProp;
277
+ message: string;
56
278
  }
57
279
 
280
+ /*
281
+ * Light-theme values, one step darker than the obvious choice so the 12px
282
+ * status text clears 4.5:1 on bg-gray-50. Theme.css remaps these classes
283
+ * under html.dark.
284
+ */
285
+ const STATUS_TONE_CLASS: Record<StatusTone, string> = {
286
+ error: "text-red-700",
287
+ invalid: "text-amber-700",
288
+ valid: "text-green-700",
289
+ neutral: "text-gray-500",
290
+ };
291
+
292
+ const TOOLBAR_BUTTON_CLASS: string =
293
+ "inline-flex shrink-0 items-center gap-1 rounded px-2 py-1 text-xs font-medium text-gray-600 transition-colors hover:bg-gray-200 hover:text-gray-900 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 disabled:cursor-not-allowed disabled:opacity-40";
294
+
295
+ /**
296
+ * A code editor for form fields: a native textarea over a highlighted copy
297
+ * of its text, with line numbers, auto-indentation, bracket pairing, a
298
+ * status bar that says whether JSON or YAML parses (and where it does not),
299
+ * and Format / Copy actions. It renders on the first paint, has no runtime
300
+ * to download, and edits with the browser's own caret, selection, undo and
301
+ * find - which is also what makes it work with a phone keyboard and a screen
302
+ * reader.
303
+ */
58
304
  const CodeEditor: FunctionComponent<ComponentProps> = (
59
305
  props: ComponentProps,
60
306
  ): ReactElement => {
61
- let className: string = "";
307
+ const language: CodeLanguage = getCodeLanguage(props.type);
308
+ const readOnly: boolean = Boolean(props.readOnly);
309
+
310
+ const [text, setText] = useState<string>(() => {
311
+ return toEditorText(props.value ?? props.initialValue);
312
+ });
62
313
 
63
- const [placeholder, setPlaceholder] = useState<string>("");
64
- const [helpText, setHelpText] = useState<string | ReactElement>("");
65
- const editorRef: React.MutableRefObject<any> = useRef<any>(null);
66
- const theme: Theme = useTheme();
314
+ // The latest text, for effects that must not re-run on every keystroke.
315
+ const textRef: React.MutableRefObject<string> = useRef<string>(text);
67
316
 
68
317
  /*
69
- * `value` is the controlled prop; `initialValue` only seeds an uncontrolled
70
- * editor. Both used to be synced from their own useEffect, and because
71
- * effects run in declaration order the `initialValue` one ran last on mount
72
- * and reset the state to "" - so a caller that passed only `value` mounted
73
- * an empty editor even though it had text to show. Seed the state on the
74
- * first render and keep the precedence in a single effect.
318
+ * Checked on a timer, so a half-typed line is not judged the instant it is
319
+ * typed and a long document is not re-parsed on every keystroke.
75
320
  */
76
- const [value, setValue] = useState<string>(() => {
77
- return toEditorText(props.value ?? props.initialValue);
321
+ const [checkedText, setCheckedText] = useState<string>(text);
322
+
323
+ const [selection, setSelection] = useState<SelectionShape>({
324
+ start: 0,
325
+ end: 0,
326
+ active: 0,
78
327
  });
328
+ const [isFocused, setIsFocused] = useState<boolean>(false);
329
+
330
+ /*
331
+ * Tab indents, so it cannot also move focus - a keyboard trap unless there
332
+ * is a way out (WCAG 2.1.2). Escape releases the next Tab to the browser.
333
+ */
334
+ const [tabMovesFocus, setTabMovesFocus] = useState<boolean>(false);
335
+ const tabMovesFocusRef: React.MutableRefObject<boolean> =
336
+ useRef<boolean>(false);
337
+
338
+ const [copied, setCopied] = useState<boolean>(false);
339
+ const copyResetTimer: React.MutableRefObject<ReturnType<
340
+ typeof setTimeout
341
+ > | null> = useRef<ReturnType<typeof setTimeout> | null>(null);
342
+
343
+ const textareaRef: React.MutableRefObject<HTMLTextAreaElement | null> =
344
+ useRef<HTMLTextAreaElement | null>(null);
345
+ const scrollerRef: React.MutableRefObject<HTMLDivElement | null> =
346
+ useRef<HTMLDivElement | null>(null);
347
+ const gutterRef: React.MutableRefObject<HTMLDivElement | null> =
348
+ useRef<HTMLDivElement | null>(null);
349
+ const measureRef: React.MutableRefObject<HTMLSpanElement | null> =
350
+ useRef<HTMLSpanElement | null>(null);
79
351
 
352
+ const instanceId: string = useId();
353
+ const keysHintId: string = `${instanceId}-code-keys`;
354
+ const statusId: string = `${instanceId}-code-status`;
355
+ const hintId: string = `${instanceId}-code-hint`;
356
+
357
+ /*
358
+ * `value` is the controlled prop; `initialValue` only seeds an editor that
359
+ * is not given one. Seeded on the first render above and kept in step in
360
+ * one effect: two effects, one per prop, ran in declaration order on mount
361
+ * and the `initialValue` one blanked an editor that was only given `value`.
362
+ */
80
363
  useEffect(() => {
81
- setValue(
82
- toEditorText(
83
- props.value === undefined ? props.initialValue : props.value,
84
- ),
364
+ const next: string = toEditorText(
365
+ props.value === undefined ? props.initialValue : props.value,
85
366
  );
367
+
368
+ if (next === textRef.current) {
369
+ return;
370
+ }
371
+
372
+ // Replaced from outside (a sample inserted, a record loaded): judge it now.
373
+ textRef.current = next;
374
+ setText(next);
375
+ setCheckedText(next);
86
376
  }, [props.value, props.initialValue]);
87
377
 
88
378
  useEffect(() => {
89
- if (props.placeholder) {
90
- if (props.type === CodeType.Markdown) {
91
- setHelpText(MarkdownUtil.getMarkdownCheatsheet(props.placeholder));
92
- }
379
+ if (!language.validator) {
380
+ return undefined;
381
+ }
93
382
 
94
- if (props.type === CodeType.HTML) {
95
- setHelpText(`${props.placeholder}. This is in HTML`);
96
- }
383
+ const timer: ReturnType<typeof setTimeout> = setTimeout(() => {
384
+ setCheckedText(text);
385
+ }, CODE_EDITOR_VALIDATION_DEBOUNCE_MS);
97
386
 
98
- if (props.type === CodeType.JavaScript) {
99
- setPlaceholder(
100
- `/* ${props.placeholder}
101
-
102
-
103
- This is in JavaScript.
104
-
105
- */`,
106
- );
107
- }
387
+ return () => {
388
+ clearTimeout(timer);
389
+ };
390
+ }, [text, language.validator]);
108
391
 
109
- if (props.type === CodeType.JSON) {
110
- setHelpText(`${props.placeholder}`);
392
+ useEffect(() => {
393
+ return () => {
394
+ if (copyResetTimer.current) {
395
+ clearTimeout(copyResetTimer.current);
111
396
  }
397
+ };
398
+ }, []);
112
399
 
113
- if (props.type === CodeType.CSS) {
114
- setPlaceholder(`/* ${props.placeholder}. This is in CSS. */`);
400
+ const indentUnit: IndentUnit = useMemo(() => {
401
+ return detectIndentUnit(text, FALLBACK_INDENT, language.allowTabs);
402
+ }, [text, language.allowTabs]);
403
+
404
+ const syntax: JsonSyntaxCheckResult | YamlSyntaxCheckResult | null =
405
+ useMemo(() => {
406
+ if (language.validator === "json") {
407
+ return checkJsonSyntax(checkedText, { allowJSON5: props.allowJSON5 });
115
408
  }
116
409
 
117
- /*
118
- * Help text, never `setPlaceholder`: whatever setPlaceholder holds is
119
- * rendered into `defaultValue` below, i.e. it becomes real document
120
- * text. The JS and CSS arms above get away with it because they wrap
121
- * the hint in a comment; an unwrapped YAML hint would be content the
122
- * user can accidentally save, and the server would reject it.
123
- */
124
- if (props.type === CodeType.YAML) {
125
- setHelpText(`${props.placeholder}`);
410
+ if (language.validator === "yaml") {
411
+ return checkYamlSyntax(checkedText);
126
412
  }
413
+
414
+ return null;
415
+ }, [checkedText, language.validator, props.allowJSON5]);
416
+
417
+ // Format rewrites only strict JSON, placeholders and all, never JSON5.
418
+ const canFormat: boolean = useMemo(() => {
419
+ return (
420
+ language.canFormat &&
421
+ !readOnly &&
422
+ checkedText.trim() !== "" &&
423
+ findJsonSyntaxError(checkedText) === null
424
+ );
425
+ }, [language.canFormat, readOnly, checkedText]);
426
+
427
+ const highlightedHtml: string = useMemo(() => {
428
+ return highlightCode(text, language.grammar, {
429
+ showTabs: language.showTabs,
430
+ });
431
+ }, [text, language.grammar, language.showTabs]);
432
+
433
+ const example: string = (props.example || "")
434
+ .replace(/^\s*\n/, "")
435
+ .replace(/\s+$/, "");
436
+
437
+ const ghostHtml: string | null = useMemo(() => {
438
+ if (text !== "") {
439
+ return null;
127
440
  }
128
- }, [props.placeholder, props.type]);
129
441
 
130
- if (!props.className) {
131
- className =
132
- "block w-full rounded-md border border-gray-300 bg-white py-2 pl-3 pr-3 text-sm placeholder-gray-500 focus:border-indigo-500 focus:text-gray-900 focus:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-indigo-500 sm:text-sm";
133
- } else {
134
- className = props.className;
135
- }
442
+ if (props.placeholder) {
443
+ return `<span class="ou-code-editor__placeholder">${escapeHtml(
444
+ props.placeholder,
445
+ )}</span>`;
446
+ }
136
447
 
137
- if (props.error) {
138
- className =
139
- "block w-full rounded-md border bg-white py-2 pl-3 pr-3 text-sm placeholder-gray-500 focus:border-red-500 focus:text-gray-900 focus:placeholder-gray-400 focus:outline-none focus:ring-2 focus:ring-red-500 sm:text-sm border-red-300 pr-10 text-red-900 placeholder-red-300 focus:border-red-500 focus:outline-none focus:ring-red-500";
140
- }
448
+ if (example) {
449
+ return `<span class="ou-code-editor__example">${highlightCode(
450
+ example,
451
+ language.grammar,
452
+ )}</span>`;
453
+ }
454
+
455
+ return null;
456
+ }, [text, props.placeholder, example, language.grammar]);
457
+
458
+ const lineCount: number = useMemo(() => {
459
+ return countLines(text);
460
+ }, [text]);
461
+
462
+ const cursor: LineColumn = getLineColumn(text, selection.active);
463
+ const selectedCharacters: number = Math.abs(selection.end - selection.start);
141
464
 
142
- const isYaml: boolean = props.type === CodeType.YAML;
465
+ const errorLine: number | null =
466
+ syntax &&
467
+ !syntax.isValid &&
468
+ syntax.line !== null &&
469
+ syntax.line <= lineCount
470
+ ? syntax.line
471
+ : null;
143
472
 
144
- type GetInputAreaFunction = (editor: any) => HTMLTextAreaElement | null;
473
+ const showGutter: boolean = language.wrap
474
+ ? false
475
+ : props.showLineNumbers !== false;
476
+
477
+ const showActiveLine: boolean =
478
+ isFocused && !readOnly && selectedCharacters === 0;
479
+
480
+ const gutterSegments: Array<GutterSegment> = useMemo(() => {
481
+ const marks: Map<number, string> = new Map<number, string>();
482
+
483
+ if (showActiveLine) {
484
+ marks.set(cursor.line, "ou-code-editor__gutter-active");
485
+ }
486
+
487
+ if (errorLine !== null) {
488
+ marks.set(errorLine, "ou-code-editor__gutter-error");
489
+ }
490
+
491
+ return buildGutter(lineCount, marks);
492
+ }, [lineCount, showActiveLine, cursor.line, errorLine]);
145
493
 
146
494
  /*
147
- * Monaco's real focusable control. The wrapper <div> this component returns
148
- * has no role, and ARIA forbids naming a role=generic element - so every
149
- * accessibility attribute has to land here instead.
495
+ * Keep the caret in view. The textarea never scrolls - it is exactly as
496
+ * big as its text - so the scroller around it has to, and browsers do not
497
+ * agree on doing that for a caret inside a textarea: Firefox leaves the
498
+ * end of the document off-screen after Ctrl+End, and Chromium parks a
499
+ * caret at column 1 underneath the sticky line numbers. Lines have a fixed
500
+ * height and the font is monospaced, so where the caret is is arithmetic.
501
+ * (Wrapped prose is left to the browser: a wrapped line has no fixed row.)
150
502
  */
151
- const getInputArea: GetInputAreaFunction = (
152
- editor: any,
153
- ): HTMLTextAreaElement | null => {
154
- const domNode: HTMLElement | null = editor?.getDomNode?.() || null;
503
+ useLayoutEffect(() => {
504
+ const scroller: HTMLDivElement | null = scrollerRef.current;
505
+ const textarea: HTMLTextAreaElement | null = textareaRef.current;
155
506
 
156
- if (!domNode) {
157
- return null;
507
+ if (!isFocused || language.wrap || !scroller || !textarea) {
508
+ return;
509
+ }
510
+
511
+ const value: string = textarea.value;
512
+ const position: number = Math.min(selection.active, value.length);
513
+ const line: number = getLineColumn(value, position).line;
514
+
515
+ const top: number =
516
+ CODE_EDITOR_PADDING_Y_PX + (line - 1) * CODE_EDITOR_LINE_HEIGHT_PX;
517
+ const bottom: number = top + CODE_EDITOR_LINE_HEIGHT_PX;
518
+
519
+ if (top < scroller.scrollTop) {
520
+ scroller.scrollTop = Math.max(0, top - CODE_EDITOR_PADDING_Y_PX);
521
+ } else if (bottom > scroller.scrollTop + scroller.clientHeight) {
522
+ scroller.scrollTop =
523
+ bottom + CODE_EDITOR_PADDING_Y_PX - scroller.clientHeight;
524
+ }
525
+
526
+ const characterWidth: number =
527
+ (measureRef.current?.getBoundingClientRect().width || 0) / MEASURE_LENGTH;
528
+
529
+ if (characterWidth <= 0) {
530
+ return;
531
+ }
532
+
533
+ let columns: number = 0;
534
+
535
+ for (const character of value.slice(
536
+ lineStartOf(value, position),
537
+ position,
538
+ )) {
539
+ columns =
540
+ character === "\t"
541
+ ? columns + TAB_SIZE - (columns % TAB_SIZE)
542
+ : columns + 1;
543
+ }
544
+
545
+ const gutterWidth: number = gutterRef.current?.offsetWidth || 0;
546
+ const margin: number = 2 * characterWidth;
547
+ const x: number =
548
+ gutterWidth + CODE_EDITOR_PADDING_X_PX + columns * characterWidth;
549
+
550
+ if (x < scroller.scrollLeft + gutterWidth + CODE_EDITOR_PADDING_X_PX) {
551
+ scroller.scrollLeft = Math.max(
552
+ 0,
553
+ x - gutterWidth - CODE_EDITOR_PADDING_X_PX - margin,
554
+ );
555
+ } else if (x + margin > scroller.scrollLeft + scroller.clientWidth) {
556
+ scroller.scrollLeft = x + margin - scroller.clientWidth;
557
+ }
558
+ }, [selection, text, isFocused, language.wrap]);
559
+
560
+ type CaptureSelectionFunction = () => void;
561
+
562
+ const captureSelection: CaptureSelectionFunction = (): void => {
563
+ const textarea: HTMLTextAreaElement | null = textareaRef.current;
564
+
565
+ if (!textarea) {
566
+ return;
158
567
  }
159
568
 
160
- return domNode.querySelector("textarea");
569
+ const start: number = textarea.selectionStart;
570
+ const end: number = textarea.selectionEnd;
571
+ const active: number =
572
+ textarea.selectionDirection === "backward" ? start : end;
573
+
574
+ setSelection((previous: SelectionShape) => {
575
+ if (
576
+ previous.start === start &&
577
+ previous.end === end &&
578
+ previous.active === active
579
+ ) {
580
+ return previous;
581
+ }
582
+
583
+ return { start, end, active };
584
+ });
161
585
  };
162
586
 
163
- type ApplyAriaFunction = (editor: any) => void;
587
+ type SetTabMovesFocusFunction = (value: boolean) => void;
164
588
 
165
- const applyAria: ApplyAriaFunction = (editor: any): void => {
166
- const inputArea: HTMLTextAreaElement | null = getInputArea(editor);
589
+ const setTabRelease: SetTabMovesFocusFunction = (value: boolean): void => {
590
+ tabMovesFocusRef.current = value;
591
+ setTabMovesFocus(value);
592
+ };
167
593
 
168
- if (!inputArea) {
594
+ type RunEditFunction = (edit: TextEdit | null) => void;
595
+
596
+ const runEdit: RunEditFunction = (edit: TextEdit | null): void => {
597
+ const textarea: HTMLTextAreaElement | null = textareaRef.current;
598
+
599
+ if (!edit || !textarea) {
169
600
  return;
170
601
  }
171
602
 
172
- /*
173
- * aria-labelledby wins over the aria-label Monaco puts here itself
174
- * ("Editor content"), so the field's own label names the editor.
175
- */
176
- if (props.ariaLabelledby) {
177
- inputArea.setAttribute("aria-labelledby", props.ariaLabelledby);
178
- } else {
179
- inputArea.removeAttribute("aria-labelledby");
603
+ applyEditToTextarea(textarea, edit);
604
+ captureSelection();
605
+ };
606
+
607
+ type ReadStateFunction = () => EditorState;
608
+
609
+ const readState: ReadStateFunction = (): EditorState => {
610
+ const textarea: HTMLTextAreaElement = textareaRef.current!;
611
+
612
+ return {
613
+ text: textarea.value,
614
+ selectionStart: textarea.selectionStart,
615
+ selectionEnd: textarea.selectionEnd,
616
+ };
617
+ };
618
+
619
+ type ReplaceDocumentFunction = (replacement: string) => void;
620
+
621
+ // Through the textarea, so Undo brings the previous document back.
622
+ const replaceDocument: ReplaceDocumentFunction = (
623
+ replacement: string,
624
+ ): void => {
625
+ const textarea: HTMLTextAreaElement | null = textareaRef.current;
626
+
627
+ if (!textarea || replacement === textarea.value) {
628
+ return;
180
629
  }
181
630
 
182
- if (props.ariaDescribedby) {
183
- inputArea.setAttribute("aria-describedby", props.ariaDescribedby);
184
- } else {
185
- inputArea.removeAttribute("aria-describedby");
631
+ textarea.focus();
632
+ runEdit({
633
+ from: 0,
634
+ to: textarea.value.length,
635
+ insert: replacement,
636
+ selectionStart: 0,
637
+ selectionEnd: 0,
638
+ });
639
+
640
+ if (scrollerRef.current) {
641
+ scrollerRef.current.scrollTop = 0;
642
+ scrollerRef.current.scrollLeft = 0;
643
+ }
644
+ };
645
+
646
+ type HandleFormatFunction = () => void;
647
+
648
+ const handleFormat: HandleFormatFunction = (): void => {
649
+ const formatted: string | null = formatJson(
650
+ textareaRef.current?.value ?? text,
651
+ indentUnit.text,
652
+ );
653
+
654
+ if (formatted !== null) {
655
+ replaceDocument(formatted);
186
656
  }
657
+ };
658
+
659
+ type HandleCopyFunction = () => void;
660
+
661
+ const handleCopy: HandleCopyFunction = (): void => {
662
+ const textarea: HTMLTextAreaElement | null = textareaRef.current;
663
+ const content: string = textarea?.value ?? text;
664
+ const clipboard: Clipboard | undefined =
665
+ typeof navigator !== "undefined" ? navigator.clipboard : undefined;
666
+
667
+ if (clipboard && typeof clipboard.writeText === "function") {
668
+ void Promise.resolve(clipboard.writeText(content)).catch(() => {
669
+ /* A denied clipboard permission is not worth an error state. */
670
+ });
671
+ } else if (textarea && typeof document.execCommand === "function") {
672
+ // No async clipboard outside a secure context (plain-HTTP installs).
673
+ const { selectionStart, selectionEnd } = textarea;
674
+
675
+ textarea.focus();
676
+ textarea.select();
677
+
678
+ try {
679
+ document.execCommand("copy");
680
+ } catch {
681
+ /* Nothing more to try. */
682
+ }
187
683
 
188
- if (props.ariaInvalid) {
189
- inputArea.setAttribute("aria-invalid", "true");
684
+ textarea.setSelectionRange(selectionStart, selectionEnd);
190
685
  } else {
191
- inputArea.removeAttribute("aria-invalid");
686
+ return;
192
687
  }
688
+
689
+ setCopied(true);
690
+
691
+ if (copyResetTimer.current) {
692
+ clearTimeout(copyResetTimer.current);
693
+ }
694
+
695
+ copyResetTimer.current = setTimeout(() => {
696
+ setCopied(false);
697
+ }, 2000);
193
698
  };
194
699
 
195
- type ApplyModelOptionsFunction = (editor: any) => void;
700
+ type HandleKeyDownFunction = (
701
+ event: React.KeyboardEvent<HTMLTextAreaElement>,
702
+ ) => void;
703
+
704
+ const handleKeyDown: HandleKeyDownFunction = (
705
+ event: React.KeyboardEvent<HTMLTextAreaElement>,
706
+ ): void => {
707
+ // Leave composition (IME input) entirely to the browser.
708
+ if (event.nativeEvent.isComposing || event.keyCode === 229) {
709
+ return;
710
+ }
711
+
712
+ const key: string = event.key;
713
+ const command: boolean = event.ctrlKey || event.metaKey;
714
+
715
+ if (key === "Escape") {
716
+ /*
717
+ * Only the first Escape is ours. A second one is left alone, so a
718
+ * dialog around the editor still closes on Escape, Escape.
719
+ */
720
+ if (!readOnly && !tabMovesFocusRef.current) {
721
+ event.preventDefault();
722
+ setTabRelease(true);
723
+ }
196
724
 
197
- /*
198
- * Per-model, not per-editor and emphatically not global: a literal tab is
199
- * illegal as YAML indentation, and Monaco's model defaults are four spaces
200
- * with indentation detected from the initial content - so a rule pasted in
201
- * tab-indented would keep emitting tabs the parser rejects.
202
- */
203
- const applyModelOptions: ApplyModelOptionsFunction = (editor: any): void => {
204
- if (!isYaml) {
205
725
  return;
206
726
  }
207
727
 
208
- const model: any = editor?.getModel?.();
728
+ if (key === "Tab") {
729
+ if (readOnly || tabMovesFocusRef.current || command || event.altKey) {
730
+ return;
731
+ }
209
732
 
210
- if (!model || typeof model.updateOptions !== "function") {
733
+ event.preventDefault();
734
+ runEdit(
735
+ event.shiftKey
736
+ ? outdent(readState(), indentUnit)
737
+ : indent(readState(), indentUnit),
738
+ );
211
739
  return;
212
740
  }
213
741
 
214
- model.updateOptions({ tabSize: 2, insertSpaces: true });
215
- };
742
+ if (!MODIFIER_KEYS.includes(key) && tabMovesFocusRef.current) {
743
+ setTabRelease(false);
744
+ }
216
745
 
217
- /*
218
- * Markdown is prose, so it follows the caller's preference. YAML is code:
219
- * red squiggles under every key name in a Sigma rule are pure noise, so
220
- * spell check is off for it regardless of what the caller asked for.
221
- */
222
- const shouldSpellCheck: boolean = isYaml ? false : !props.disableSpellCheck;
223
- const managesSpellCheck: boolean = props.type === CodeType.Markdown || isYaml;
746
+ if (readOnly) {
747
+ return;
748
+ }
749
+
750
+ if (key === "Enter" && !command && !event.altKey) {
751
+ event.preventDefault();
752
+ runEdit(newLine(readState(), indentUnit, language.rules));
753
+ return;
754
+ }
755
+
756
+ if (key === "Backspace" && !command && !event.altKey) {
757
+ const edit: TextEdit | null = backspace(
758
+ readState(),
759
+ indentUnit,
760
+ language.rules,
761
+ );
762
+
763
+ if (edit) {
764
+ event.preventDefault();
765
+ runEdit(edit);
766
+ }
767
+
768
+ return;
769
+ }
770
+
771
+ if (command && !event.altKey && (key === "/" || event.code === "Slash")) {
772
+ const edit: TextEdit | null = toggleLineComment(
773
+ readState(),
774
+ language.rules,
775
+ );
224
776
 
225
- type ApplySpellCheckFunction = (editor: any) => void;
777
+ if (edit) {
778
+ event.preventDefault();
779
+ runEdit(edit);
780
+ }
781
+
782
+ return;
783
+ }
226
784
 
227
- const applySpellCheck: ApplySpellCheckFunction = (editor: any): void => {
228
- if (!editor || !managesSpellCheck) {
785
+ if (
786
+ command &&
787
+ !event.altKey &&
788
+ !event.shiftKey &&
789
+ (key === "]" || key === "[")
790
+ ) {
791
+ event.preventDefault();
792
+ runEdit(
793
+ key === "]"
794
+ ? indentLines(readState(), indentUnit)
795
+ : outdent(readState(), indentUnit),
796
+ );
229
797
  return;
230
798
  }
231
799
 
232
- const domNode: HTMLElement | null = editor.getDomNode();
800
+ // Shift+Alt+F, as in VS Code. By code: Alt changes the key on a Mac.
801
+ if (event.shiftKey && event.altKey && !command && event.code === "KeyF") {
802
+ if (canFormat) {
803
+ event.preventDefault();
804
+ handleFormat();
805
+ }
233
806
 
234
- if (!domNode) {
235
807
  return;
236
808
  }
237
809
 
238
- const textareaElement: HTMLTextAreaElement | null =
239
- domNode.querySelector("textarea");
810
+ /*
811
+ * A printable character. Ctrl+Alt is AltGr on Windows, which is how a
812
+ * German keyboard types a bracket, so only Ctrl or Cmd alone is a
813
+ * shortcut.
814
+ */
815
+ const isShortcut: boolean =
816
+ event.metaKey || (event.ctrlKey && !event.altKey);
240
817
 
241
- if (textareaElement) {
242
- textareaElement.spellcheck = shouldSpellCheck;
818
+ if (key.length === 1 && !isShortcut) {
819
+ const edit: TextEdit | null = typeCharacter(
820
+ readState(),
821
+ key,
822
+ language.rules,
823
+ );
824
+
825
+ if (edit) {
826
+ event.preventDefault();
827
+ runEdit(edit);
828
+ }
243
829
  }
244
830
  };
245
831
 
246
- // Handle spell check configuration for Monaco Editor
247
- useEffect(() => {
248
- applySpellCheck(editorRef.current);
249
- applyModelOptions(editorRef.current);
250
- // eslint-disable-next-line
251
- }, [props.disableSpellCheck, props.type]);
832
+ type HandleGutterMouseDownFunction = (
833
+ event: React.MouseEvent<HTMLDivElement>,
834
+ ) => void;
252
835
 
253
- useEffect(() => {
254
- applyAria(editorRef.current);
255
- // eslint-disable-next-line
256
- }, [props.ariaLabelledby, props.ariaDescribedby, props.ariaInvalid]);
836
+ // A click on a line number selects that line, as in every other editor.
837
+ const handleGutterMouseDown: HandleGutterMouseDownFunction = (
838
+ event: React.MouseEvent<HTMLDivElement>,
839
+ ): void => {
840
+ const textarea: HTMLTextAreaElement | null = textareaRef.current;
841
+
842
+ if (!textarea || event.button !== 0) {
843
+ return;
844
+ }
845
+
846
+ event.preventDefault();
847
+
848
+ const bounds: DOMRect = event.currentTarget.getBoundingClientRect();
849
+ const line: number = Math.min(
850
+ lineCount,
851
+ Math.max(
852
+ 1,
853
+ Math.floor(
854
+ (event.clientY - bounds.top - CODE_EDITOR_PADDING_Y_PX) /
855
+ CODE_EDITOR_LINE_HEIGHT_PX,
856
+ ) + 1,
857
+ ),
858
+ );
859
+
860
+ const value: string = textarea.value;
861
+ let start: number = 0;
862
+
863
+ for (let current: number = 1; current < line; current++) {
864
+ start = value.indexOf("\n", start) + 1;
865
+ }
866
+
867
+ const end: number = lineEndOf(value, start);
868
+
869
+ textarea.focus();
870
+ textarea.setSelectionRange(start, end < value.length ? end + 1 : end);
871
+ captureSelection();
872
+ };
873
+
874
+ const status: StatusShape | null = useMemo(() => {
875
+ // Only once the check has caught up: a half-typed line is not an error yet.
876
+ const settled: boolean = !language.validator || checkedText === text;
877
+
878
+ if (props.error && settled) {
879
+ return { tone: "error", icon: IconProp.Error, message: props.error };
880
+ }
881
+
882
+ if (!syntax) {
883
+ return null;
884
+ }
885
+
886
+ if (checkedText.trim() === "") {
887
+ return {
888
+ tone: "neutral",
889
+ icon: IconProp.Info,
890
+ message: "Nothing entered yet.",
891
+ };
892
+ }
893
+
894
+ // Nobody parsed it, so nothing may be claimed about it.
895
+ if (syntax.wasSkipped) {
896
+ return {
897
+ tone: "neutral",
898
+ icon: IconProp.Info,
899
+ message: "Contains template expressions — syntax not checked.",
900
+ };
901
+ }
902
+
903
+ if (syntax.isValid) {
904
+ const lines: number = countLines(checkedText);
905
+
906
+ return {
907
+ tone: "valid",
908
+ icon: IconProp.CheckCircle,
909
+ message: `Valid ${language.label} · ${lines} ${
910
+ lines === 1 ? "line" : "lines"
911
+ }`,
912
+ };
913
+ }
257
914
 
258
- /*
259
- * Memoised: @monaco-editor/react calls editor.updateOptions() whenever this
260
- * object's identity changes, so an inline literal reconfigured the editor on
261
- * every parent re-render - which for the indentation options below would
262
- * reset them mid-keystroke.
263
- */
264
- const editorOptions: Record<string, unknown> = useMemo(() => {
265
915
  return {
266
- acceptSuggestionOnCommitCharacter: false,
267
- acceptSuggestionOnEnter: "off",
268
- accessibilitySupport: "auto",
269
- fontSize: 14,
270
- automaticLayout: true,
271
- codeLens: false,
272
- colorDecorators: true,
273
- contextmenu: false,
274
- cursorBlinking: "blink",
275
- tabIndex: props.tabIndex || 0,
276
- minimap: { enabled: false },
277
- cursorStyle: "line",
278
- disableLayerHinting: false,
279
- disableMonospaceOptimizations: false,
280
- dragAndDrop: false,
281
- fixedOverflowWidgets: false,
282
- folding: true,
283
- foldingStrategy: "auto",
284
- fontLigatures: false,
285
- formatOnPaste: false,
286
- formatOnType: false,
287
-
288
- hideCursorInOverviewRuler: false,
289
- links: true,
290
- mouseWheelZoom: false,
291
- multiCursorMergeOverlapping: true,
292
- multiCursorModifier: "alt",
293
- overviewRulerBorder: true,
294
- overviewRulerLanes: 2,
295
- quickSuggestions: false,
296
- quickSuggestionsDelay: 100,
297
- readOnly: props.readOnly || false,
298
- renderControlCharacters: false,
299
- /*
300
- * Long scalars - a URL, a base64 blob, a Sigma `condition:` line - run
301
- * off the right edge, and with wordWrap off for code there is no other
302
- * way to reach them. Wrapping YAML instead is not an option: the
303
- * indentation IS the syntax, and a wrapped line reads as a deeper one.
304
- */
305
- scrollbar: {
306
- horizontal: isYaml ? "auto" : "hidden",
307
- },
308
- renderLineHighlight: "all",
309
- suggestOnTriggerCharacters: false,
310
- /*
311
- * In YAML whitespace is the syntax. Rendering it at the boundaries makes
312
- * the indentation depth countable and, more importantly, makes a literal
313
- * tab visible - tabs are illegal as YAML indentation and are otherwise
314
- * indistinguishable from spaces.
315
- */
316
- renderWhitespace: isYaml ? "boundary" : "none",
317
- revealHorizontalRightPadding: 30,
318
- roundedSelection: true,
319
- rulers: [],
320
- scrollBeyondLastColumn: 5,
321
- // Half a short editor as blank runway is wasted space in a form field.
322
- scrollBeyondLastLine: !isYaml,
323
- selectOnLineNumbers: true,
324
- /*
325
- * Every YAML parse error - ours and the server's - is reported as a
326
- * line and column, so the gutter is what makes the message actionable.
327
- */
328
- lineNumbers: props.showLineNumbers || isYaml ? "on" : "off",
329
- selectionClipboard: true,
330
- selectionHighlight: true,
331
- showFoldingControls: "mouseover",
332
- smoothScrolling: false,
333
- wordBasedSuggestions: "off",
334
- wordWrap: props.type === CodeType.Markdown ? "on" : "off",
335
- tabCompletion: "off",
336
- // The YAML chrome owns the padding, so the editor supplies its own.
337
- padding: isYaml ? { top: 10, bottom: 10 } : undefined,
338
- /*
339
- * tabSize / insertSpaces / detectIndentation deliberately do NOT belong
340
- * here. They are IGlobalEditorOptions: monaco's standalone editor pipes
341
- * whatever it is constructed with through updateConfigurationService,
342
- * which writes every registered `editor.*` key into a PROCESS-WIDE
343
- * config service - and those three are exactly the ones ModelService
344
- * reads back, pushing them onto every model on the page. Setting them
345
- * here would mean the last editor to mount dictates the indentation of
346
- * all the others. They are applied to this editor's own model instead,
347
- * in applyModelOptions below.
348
- */
916
+ tone: "invalid",
917
+ icon: IconProp.Alert,
918
+ message:
919
+ language.validator === "json"
920
+ ? describeJsonSyntaxError(syntax as JsonSyntaxCheckResult)
921
+ : describeYamlSyntaxError(syntax as YamlSyntaxCheckResult),
349
922
  };
350
- }, [
351
- props.tabIndex,
352
- props.readOnly,
353
- props.showLineNumbers,
354
- props.type,
355
- isYaml,
356
- ]);
923
+ }, [props.error, syntax, checkedText, text, language]);
924
+
925
+ const isEmpty: boolean = text === "";
926
+ const showExampleButton: boolean = Boolean(example) && isEmpty && !readOnly;
927
+
928
+ const spellCheck: boolean = language.spellCheckFollowsCaller
929
+ ? !props.disableSpellCheck
930
+ : false;
931
+
932
+ const describedBy: string =
933
+ [
934
+ props.ariaDescribedby,
935
+ props.hint ? hintId : null,
936
+ readOnly ? null : keysHintId,
937
+ status ? statusId : null,
938
+ ]
939
+ .filter(Boolean)
940
+ .join(" ") || "";
941
+
942
+ const rootClassName: string = [
943
+ "ou-code-editor overflow-hidden rounded-md border bg-white shadow-sm transition-shadow",
944
+ props.error
945
+ ? "border-red-300 focus-within:border-red-500 focus-within:ring-1 focus-within:ring-red-500"
946
+ : "border-gray-300 focus-within:border-indigo-500 focus-within:ring-1 focus-within:ring-indigo-500",
947
+ language.wrap ? "ou-code-editor--wrap" : "",
948
+ readOnly ? "ou-code-editor--readonly" : "",
949
+ props.className || "",
950
+ ]
951
+ .filter(Boolean)
952
+ .join(" ");
953
+
954
+ const minHeight: number =
955
+ (props.minLines ?? CODE_EDITOR_DEFAULT_MIN_LINES) *
956
+ CODE_EDITOR_LINE_HEIGHT_PX +
957
+ 2 * CODE_EDITOR_PADDING_Y_PX;
958
+
959
+ const scrollerStyle: React.CSSProperties = props.height
960
+ ? { height: props.height }
961
+ : { maxHeight: props.maxHeight || CODE_EDITOR_DEFAULT_MAX_HEIGHT };
357
962
 
358
963
  return (
359
964
  <div
965
+ className={rootClassName}
360
966
  data-testid={props.dataTestId}
361
- aria-labelledby={props.ariaLabelledby}
362
- onClick={() => {
363
- if (props.onClick) {
364
- props.onClick();
365
- }
366
- if (props.onFocus) {
367
- props.onFocus();
368
- }
369
- }}
967
+ data-code-type={props.type}
968
+ onClick={props.onClick}
370
969
  >
371
- {helpText && (
372
- <p className="bg-gray-50 text-gray-500 p-3 mt-2 mb-2 rounded text-base text-sm">
373
- {" "}
374
- {helpText}{" "}
375
- </p>
376
- )}
970
+ <div className="flex items-center justify-between gap-3 border-b border-gray-200 bg-gray-50 py-1 pl-3 pr-1.5">
971
+ <div className="flex min-w-0 items-center gap-2">
972
+ <span
973
+ data-testid="code-editor-language"
974
+ className="inline-flex shrink-0 items-center rounded border border-indigo-100 bg-indigo-50 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-indigo-700"
975
+ >
976
+ {language.label}
977
+ </span>
978
+ {readOnly && (
979
+ <span
980
+ data-testid="code-editor-read-only"
981
+ className="inline-flex shrink-0 items-center gap-1 text-xs text-gray-500"
982
+ >
983
+ <Icon icon={IconProp.Lock} className="h-3 w-3" />
984
+ Read-only
985
+ </span>
986
+ )}
987
+ {props.hint && (
988
+ <span
989
+ id={hintId}
990
+ data-testid="code-editor-hint"
991
+ className="truncate text-xs text-gray-500"
992
+ >
993
+ {props.hint}
994
+ </span>
995
+ )}
996
+ </div>
997
+
998
+ <div className="flex shrink-0 items-center gap-0.5">
999
+ {showExampleButton && (
1000
+ <button
1001
+ type="button"
1002
+ data-testid="code-editor-example-button"
1003
+ className={TOOLBAR_BUTTON_CLASS}
1004
+ onClick={() => {
1005
+ replaceDocument(example);
1006
+ }}
1007
+ >
1008
+ <Icon icon={IconProp.Code} className="h-3.5 w-3.5" />
1009
+ Insert example
1010
+ </button>
1011
+ )}
1012
+ {language.canFormat && !readOnly && (
1013
+ <button
1014
+ type="button"
1015
+ data-testid="code-editor-format-button"
1016
+ title={
1017
+ canFormat
1018
+ ? "Format the document (Shift+Alt+F)"
1019
+ : "Format is available once the document is valid JSON"
1020
+ }
1021
+ disabled={!canFormat}
1022
+ className={TOOLBAR_BUTTON_CLASS}
1023
+ onClick={handleFormat}
1024
+ >
1025
+ <Icon icon={IconProp.Indent} className="h-3.5 w-3.5" />
1026
+ Format
1027
+ </button>
1028
+ )}
1029
+ <button
1030
+ type="button"
1031
+ data-testid="code-editor-copy-button"
1032
+ aria-label={
1033
+ copied
1034
+ ? `${language.label} copied to clipboard`
1035
+ : `Copy ${language.label} to clipboard`
1036
+ }
1037
+ disabled={isEmpty}
1038
+ className={TOOLBAR_BUTTON_CLASS}
1039
+ onClick={handleCopy}
1040
+ >
1041
+ <Icon
1042
+ icon={copied ? IconProp.Check : IconProp.Copy}
1043
+ className="h-3.5 w-3.5"
1044
+ />
1045
+ {copied ? "Copied" : "Copy"}
1046
+ </button>
1047
+ </div>
1048
+ </div>
1049
+
1050
+ <div
1051
+ ref={scrollerRef}
1052
+ data-testid="code-editor-scroller"
1053
+ className="ou-code-editor__scroller"
1054
+ style={scrollerStyle}
1055
+ >
1056
+ <div className="ou-code-editor__content">
1057
+ {showGutter && (
1058
+ <div
1059
+ ref={gutterRef}
1060
+ aria-hidden="true"
1061
+ data-testid="code-editor-gutter"
1062
+ className="ou-code-editor__gutter"
1063
+ style={{
1064
+ minWidth: `calc(${String(lineCount).length + 1}ch + 22px)`,
1065
+ }}
1066
+ onMouseDown={handleGutterMouseDown}
1067
+ >
1068
+ {gutterSegments.map((segment: GutterSegment, index: number) => {
1069
+ return segment.className ? (
1070
+ <span key={index} className={segment.className}>
1071
+ {segment.text}
1072
+ </span>
1073
+ ) : (
1074
+ <React.Fragment key={index}>{segment.text}</React.Fragment>
1075
+ );
1076
+ })}
1077
+ </div>
1078
+ )}
1079
+
1080
+ <div className="ou-code-editor__code" style={{ minHeight }}>
1081
+ <span
1082
+ ref={measureRef}
1083
+ aria-hidden="true"
1084
+ className="ou-code-editor__measure"
1085
+ >
1086
+ {"0".repeat(MEASURE_LENGTH)}
1087
+ </span>
1088
+ {showActiveLine && !language.wrap && (
1089
+ <div
1090
+ aria-hidden="true"
1091
+ data-testid="code-editor-active-line"
1092
+ className="ou-code-editor__active-line"
1093
+ style={{
1094
+ top:
1095
+ CODE_EDITOR_PADDING_Y_PX +
1096
+ (cursor.line - 1) * CODE_EDITOR_LINE_HEIGHT_PX,
1097
+ }}
1098
+ />
1099
+ )}
1100
+
1101
+ {/*
1102
+ * A div, not a <pre>: the HTML parser drops a newline straight
1103
+ * after <pre>, and one character missing here shifts every line
1104
+ * under the textarea.
1105
+ */}
1106
+ <div
1107
+ aria-hidden="true"
1108
+ data-testid="code-editor-highlight"
1109
+ className="ou-code-editor__layer ou-code-editor__highlight"
1110
+ dangerouslySetInnerHTML={{
1111
+ /*
1112
+ * The trailing newline gives a document that ends in one the
1113
+ * empty last line the textarea shows; a final line break on
1114
+ * its own draws nothing.
1115
+ */
1116
+ __html: (ghostHtml ?? highlightedHtml) + "\n",
1117
+ }}
1118
+ />
377
1119
 
378
- <Editor
379
- theme={theme === Theme.Dark ? "vs-dark" : "light"}
380
- defaultLanguage={props.type}
381
- /*
382
- * `defaultLanguage` is applied only when the model is created, so a
383
- * caller that swaps CodeType after mount keeps the old grammar.
384
- * `language` is the prop that drives setModelLanguage afterwards.
385
- */
386
- language={props.type}
387
- height={props.height || "30vh"}
388
- value={value}
389
- onChange={(code: string | undefined) => {
390
- if (code === undefined) {
391
- code = "";
392
- }
393
-
394
- setValue(code);
395
- if (props.onBlur) {
396
- props.onBlur();
397
- }
398
- if (props.onChange) {
399
- props.onChange(code);
400
- }
401
- }}
402
- onMount={(editor: any, _monaco: any) => {
403
- editorRef.current = editor;
404
- applySpellCheck(editor);
405
- applyModelOptions(editor);
406
- applyAria(editor);
407
- }}
408
- defaultValue={value || placeholder || ""}
409
- className={className}
410
- options={editorOptions}
411
- />
412
- {props.error && (
413
- <p className="mt-1 text-sm text-red-400">{props.error}</p>
1120
+ <textarea
1121
+ ref={textareaRef}
1122
+ id={props.id}
1123
+ data-testid="code-editor-input"
1124
+ className="ou-code-editor__layer ou-code-editor__input"
1125
+ value={text}
1126
+ readOnly={readOnly}
1127
+ tabIndex={props.tabIndex}
1128
+ placeholder={props.placeholder}
1129
+ wrap={language.wrap ? "soft" : "off"}
1130
+ spellCheck={spellCheck}
1131
+ autoCapitalize="off"
1132
+ autoComplete="off"
1133
+ autoCorrect="off"
1134
+ data-gramm="false"
1135
+ data-gramm_editor="false"
1136
+ data-enable-grammarly="false"
1137
+ /*
1138
+ * A fallback name only: aria-label outranks a <label for> as
1139
+ * well as aria-labelledby, so it would hide either one.
1140
+ */
1141
+ aria-label={
1142
+ props.ariaLabelledby || props.id
1143
+ ? undefined
1144
+ : `${language.label} editor`
1145
+ }
1146
+ aria-labelledby={props.ariaLabelledby}
1147
+ aria-describedby={describedBy || undefined}
1148
+ aria-invalid={props.ariaInvalid || props.error ? true : undefined}
1149
+ onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) => {
1150
+ const next: string = event.target.value;
1151
+
1152
+ textRef.current = next;
1153
+ setText(next);
1154
+ captureSelection();
1155
+
1156
+ if (props.onChange) {
1157
+ props.onChange(next);
1158
+ }
1159
+ }}
1160
+ onKeyDown={handleKeyDown}
1161
+ onSelect={captureSelection}
1162
+ onKeyUp={captureSelection}
1163
+ onMouseUp={captureSelection}
1164
+ onFocus={() => {
1165
+ setIsFocused(true);
1166
+ setTabRelease(false);
1167
+ captureSelection();
1168
+
1169
+ if (props.onFocus) {
1170
+ props.onFocus();
1171
+ }
1172
+ }}
1173
+ onBlur={() => {
1174
+ setIsFocused(false);
1175
+ setTabRelease(false);
1176
+
1177
+ if (props.onBlur) {
1178
+ props.onBlur();
1179
+ }
1180
+ }}
1181
+ onScroll={(event: React.UIEvent<HTMLTextAreaElement>) => {
1182
+ /*
1183
+ * The textarea is always exactly as big as its text, and the
1184
+ * scroller around it does the scrolling. Should it ever scroll
1185
+ * itself, its glyphs would slide off the colours under them.
1186
+ */
1187
+ const target: HTMLTextAreaElement = event.currentTarget;
1188
+
1189
+ if (target.scrollTop !== 0 || target.scrollLeft !== 0) {
1190
+ target.scrollTop = 0;
1191
+ target.scrollLeft = 0;
1192
+ }
1193
+ }}
1194
+ />
1195
+ </div>
1196
+ </div>
1197
+ </div>
1198
+
1199
+ <div className="flex items-center justify-between gap-3 border-t border-gray-200 bg-gray-50 px-3 py-1 text-xs">
1200
+ <div
1201
+ id={statusId}
1202
+ data-testid="code-editor-status"
1203
+ role="status"
1204
+ aria-live="polite"
1205
+ className={`flex min-w-0 items-center gap-1.5 ${
1206
+ status ? STATUS_TONE_CLASS[status.tone] : "text-gray-500"
1207
+ }`}
1208
+ >
1209
+ {status && (
1210
+ <>
1211
+ <Icon icon={status.icon} className="h-3.5 w-3.5 shrink-0" />
1212
+ <span className="min-w-0 break-words">{status.message}</span>
1213
+ </>
1214
+ )}
1215
+ </div>
1216
+
1217
+ <div
1218
+ data-testid="code-editor-cursor"
1219
+ className="flex shrink-0 items-center gap-2 tabular-nums text-gray-500"
1220
+ >
1221
+ {tabMovesFocus && isFocused && (
1222
+ <span
1223
+ data-testid="code-editor-tab-released"
1224
+ className="rounded border border-gray-200 bg-white px-1.5 text-gray-600"
1225
+ >
1226
+ Tab moves focus
1227
+ </span>
1228
+ )}
1229
+ <span>
1230
+ Ln {cursor.line}, Col {cursor.column}
1231
+ {selectedCharacters > 0 ? ` (${selectedCharacters} selected)` : ""}
1232
+ </span>
1233
+ </div>
1234
+ </div>
1235
+
1236
+ {!readOnly && (
1237
+ <span id={keysHintId} className="sr-only">
1238
+ {CODE_EDITOR_KEYS_HINT}
1239
+ </span>
414
1240
  )}
1241
+
1242
+ {/*
1243
+ * The copy button's own name changes, but a button name is not a live
1244
+ * region - nothing would speak the confirmation. This does.
1245
+ */}
1246
+ <span role="status" aria-live="polite" className="sr-only">
1247
+ {copied ? `${language.label} copied to clipboard` : ""}
1248
+ </span>
415
1249
  </div>
416
1250
  );
417
1251
  };