@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
@@ -4,6 +4,7 @@ import IconProp from "../../../Types/Icon/IconProp";
4
4
  import TinyFormDocumentation from "../TinyFormDocumentation/TinyFormDocumentation";
5
5
  import { FILE_URL } from "../../Config";
6
6
  import API from "../../Utils/API/API";
7
+ import useTranslateValue from "../../Utils/Translation";
7
8
  import ModelAPI from "../../Utils/ModelAPI/ModelAPI";
8
9
  import CommonURL from "../../../Types/API/URL";
9
10
  import HTTPResponse from "../../../Types/API/HTTPResponse";
@@ -11,12 +12,32 @@ import MimeType from "../../../Types/File/MimeType";
11
12
  import FileModel from "../../../Models/DatabaseModels/File";
12
13
  import DOMPurify from "dompurify";
13
14
  import { htmlToMarkdown, markdownToHtml } from "./MarkdownConverters";
15
+ import {
16
+ indentMarkdownLines,
17
+ isInFencedCodeBlock,
18
+ liftListItems,
19
+ MarkdownListKind,
20
+ MarkdownTextEdit,
21
+ outdentMarkdownLines,
22
+ sinkListItems,
23
+ stripTextListMarkers,
24
+ toggleMarkdownList,
25
+ } from "./MarkdownListEditing";
26
+ import MarkdownEditorHistory from "./MarkdownEditorHistory";
27
+ import { clipboardToMarkdown } from "./MarkdownPaste";
28
+ import {
29
+ deleteSelectionForInsert,
30
+ insertBlocksAtCaret,
31
+ isCaretOnEmptyLine,
32
+ moveCaretIntoEmptyListAhead,
33
+ } from "./MarkdownVisualEditing";
14
34
  import React, {
15
35
  FunctionComponent,
16
36
  ReactElement,
17
37
  useState,
18
38
  useRef,
19
39
  useEffect,
40
+ useId,
20
41
  } from "react";
21
42
 
22
43
  export interface ComponentProps {
@@ -32,6 +53,13 @@ export interface ComponentProps {
32
53
  disableSpellCheck?: boolean | undefined;
33
54
  dataTestId?: string | undefined;
34
55
  ariaLabelledby?: string | undefined;
56
+ /*
57
+ * Default: true. Inline images upload to the File API, which needs a
58
+ * signed-in user, so a form open to anyone (no OneUptime account) sets
59
+ * this to false: the Image button is hidden and pasted or dropped image
60
+ * files are ignored rather than failing to upload.
61
+ */
62
+ allowImageUpload?: boolean | undefined;
35
63
  }
36
64
 
37
65
  type EditorMode = "wysiwyg" | "markdown";
@@ -77,6 +105,175 @@ const sanitizeHtml: (html: string) => string = (html: string): string => {
77
105
  });
78
106
  };
79
107
 
108
+ const RE_SINGLE_PARAGRAPH: RegExp = /^<p>([\s\S]*)<\/p>$/;
109
+ const RE_LINE_BREAKS: RegExp = /\r\n?/g;
110
+ const RE_SHOWN_CHARACTER: RegExp = /\S/;
111
+ const RE_BLANKS_AT_END: RegExp = /[ \t]*$/;
112
+ const RE_BLANKS_AT_START: RegExp = /^[ \t]*/;
113
+ // A list item's line, up to its marker: its indentation is group 1.
114
+ const RE_LIST_ITEM_LINE: RegExp = /^([ \t]*)(?:[-*+]|\d{1,9}[.)])(?=[ \t]|$)/;
115
+ // A list item's line holding nothing but its marker (and a task's box).
116
+ const RE_BARE_LIST_MARKER_LINE: RegExp =
117
+ /^[ \t]*(?:[-*+]|\d{1,9}[.)])(?:[ \t]+\[[ xX]\])?[ \t]*$/;
118
+ const RE_STARTS_WITH_LIST_ITEM: RegExp = /^(?:[-*+]|\d{1,9}[.)])[ \t]/;
119
+
120
+ /*
121
+ * The inside of `html` when it is exactly one paragraph -- which is what
122
+ * markdownToHtml makes of a word, a sentence or an image -- and null for
123
+ * anything else.
124
+ */
125
+ const singleParagraphContents: (html: string) => string | null = (
126
+ html: string,
127
+ ): string | null => {
128
+ const inner: string | undefined = html.match(RE_SINGLE_PARAGRAPH)?.[1];
129
+ if (inner === undefined || inner.includes("</p>")) {
130
+ return null;
131
+ }
132
+ return inner;
133
+ };
134
+
135
+ /*
136
+ * Markdown made of blocks -- a fenced code block, a list, a heading, more
137
+ * than one paragraph -- pasted into the middle of a line of the markdown
138
+ * source goes on lines of its own, with a blank line between it and the
139
+ * text either side of it on that line: the split the visual editor makes
140
+ * for a block. Put in the middle of the line as it was, a code block's
141
+ * closing fence had the rest of the line after it, which made it an opening
142
+ * fence instead -- the block never closed, and everything after it in the
143
+ * note rendered as code. The spaces at the split go, as in the visual
144
+ * editor. Returns the text to insert, having widened the textarea's
145
+ * selection over those spaces.
146
+ */
147
+ const onLinesOfItsOwn: (
148
+ textarea: HTMLTextAreaElement,
149
+ markdown: string,
150
+ ) => string = (textarea: HTMLTextAreaElement, markdown: string): string => {
151
+ if (
152
+ !RE_SHOWN_CHARACTER.test(markdown) ||
153
+ singleParagraphContents(markdownToHtml(markdown)) !== null
154
+ ) {
155
+ return markdown;
156
+ }
157
+ const value: string = textarea.value;
158
+ const start: number = textarea.selectionStart;
159
+ const end: number = textarea.selectionEnd;
160
+ const lineStart: number = value.lastIndexOf("\n", start - 1) + 1;
161
+ const lineEndAt: number = value.indexOf("\n", end);
162
+ const lineEnd: number = lineEndAt === -1 ? value.length : lineEndAt;
163
+ const before: string = value.slice(lineStart, start);
164
+ const after: string = value.slice(end, lineEnd);
165
+ const textBefore: boolean = RE_SHOWN_CHARACTER.test(before);
166
+ const textAfter: boolean = RE_SHOWN_CHARACTER.test(after);
167
+ if (!textBefore && !textAfter) {
168
+ return markdown;
169
+ }
170
+ const spacesBefore: number = textBefore
171
+ ? (before.match(RE_BLANKS_AT_END)?.[0] || "").length
172
+ : 0;
173
+ const spacesAfter: number = textAfter
174
+ ? (after.match(RE_BLANKS_AT_START)?.[0] || "").length
175
+ : 0;
176
+ const itemLine: RegExpMatchArray | null = before.match(RE_LIST_ITEM_LINE);
177
+ if (itemLine && RE_STARTS_WITH_LIST_ITEM.test(markdown)) {
178
+ /*
179
+ * A list pasted on the line of a list item joins that item's list, as
180
+ * in the visual editor: its items go on the lines after the item, at
181
+ * its indentation -- or in its place when the caret sits after nothing
182
+ * but its marker, a "- " typed to start the list. After a blank line
183
+ * they were a list of their own; after the bare marker, a list nested
184
+ * in an empty item: "- - a", two bullets.
185
+ */
186
+ const indent: string = itemLine[1] || "";
187
+ const items: string = markdown
188
+ .split("\n")
189
+ .map((line: string): string => {
190
+ return line ? `${indent}${line}` : line;
191
+ })
192
+ .join("\n");
193
+ if (RE_BARE_LIST_MARKER_LINE.test(before)) {
194
+ /*
195
+ * Only the item's marker (and task box) is before the caret. An empty
196
+ * item is replaced by the pasted items; an item with text keeps its
197
+ * own marker and task box, and the pasted items go in before it, as in
198
+ * the visual editor. Deciding on what is before the caret alone turned
199
+ * "- [x] |rolled back deploy" into a paragraph: the marker and the tick
200
+ * went, and the item's text was left on a line of its own.
201
+ */
202
+ textarea.setSelectionRange(lineStart, end + spacesAfter);
203
+ return textAfter ? `${items}\n${before}` : items;
204
+ }
205
+ textarea.setSelectionRange(start - spacesBefore, end + spacesAfter);
206
+ return `\n${items}${textAfter ? "\n\n" : ""}`;
207
+ }
208
+ textarea.setSelectionRange(start - spacesBefore, end + spacesAfter);
209
+ return `${textBefore ? "\n\n" : ""}${markdown}${textAfter ? "\n\n" : ""}`;
210
+ };
211
+
212
+ const RE_MARKUP: RegExp = /<[a-z!/]/i;
213
+
214
+ // The text of `html` when it holds no markup at all, else null.
215
+ const textOfMarkupFreeHtml: (html: string) => string | null = (
216
+ html: string,
217
+ ): string | null => {
218
+ if (RE_MARKUP.test(html)) {
219
+ return null;
220
+ }
221
+ // Only entities to decode; a <template> parses them without running anything.
222
+ const template: HTMLTemplateElement = document.createElement("template");
223
+ template.innerHTML = html;
224
+ return template.content.textContent || "";
225
+ };
226
+
227
+ /*
228
+ * Tab and Shift+Tab without other modifiers indent and outdent list items.
229
+ * A keypress that is still composing (an IME) is left alone.
230
+ */
231
+ const isListIndentKey: (event: React.KeyboardEvent<HTMLElement>) => boolean = (
232
+ event: React.KeyboardEvent<HTMLElement>,
233
+ ): boolean => {
234
+ return (
235
+ event.key === "Tab" &&
236
+ !event.ctrlKey &&
237
+ !event.metaKey &&
238
+ !event.altKey &&
239
+ !event.nativeEvent.isComposing
240
+ );
241
+ };
242
+
243
+ type HistoryStep = "undo" | "redo";
244
+
245
+ /*
246
+ * Ctrl+Z (Cmd+Z on a Mac) is undo; Ctrl+Shift+Z, Cmd+Shift+Z and Ctrl+Y are
247
+ * redo. A keypress that is still composing is left alone.
248
+ */
249
+ const historyStepOfKey: (
250
+ event: React.KeyboardEvent<HTMLElement>,
251
+ ) => HistoryStep | null = (
252
+ event: React.KeyboardEvent<HTMLElement>,
253
+ ): HistoryStep | null => {
254
+ if (
255
+ !(event.ctrlKey || event.metaKey) ||
256
+ event.altKey ||
257
+ event.nativeEvent.isComposing
258
+ ) {
259
+ return null;
260
+ }
261
+ const key: string = event.key.toLowerCase();
262
+ if (key === "z") {
263
+ return event.shiftKey ? "redo" : "undo";
264
+ }
265
+ if (key === "y" && !event.shiftKey) {
266
+ return "redo";
267
+ }
268
+ return null;
269
+ };
270
+
271
+ type MarkdownTextEditor = (
272
+ text: string,
273
+ selectionStart: number,
274
+ selectionEnd: number,
275
+ ) => MarkdownTextEdit | null;
276
+
80
277
  interface ToolbarButtonProps {
81
278
  icon: IconProp;
82
279
  title: string;
@@ -116,6 +313,33 @@ const ToolbarButton: FunctionComponent<ToolbarButtonProps> = ({
116
313
  const MarkdownEditor: FunctionComponent<ComponentProps> = (
117
314
  props: ComponentProps,
118
315
  ): ReactElement => {
316
+ const allowImageUpload: boolean = props.allowImageUpload !== false;
317
+ /*
318
+ * The error message is tied to the field -- in either mode -- and
319
+ * announced when it appears, as Input's and TextArea's are. It was a bare
320
+ * paragraph: a required description left empty was neither announced nor
321
+ * tied to the editor, so to a screen reader the form did nothing.
322
+ */
323
+ const errorId: string = `markdown-editor-error-${useId()}`;
324
+ /*
325
+ * The words the editor always shows of its own -- an empty field's
326
+ * placeholder and the heading of its formatting help -- are looked up in
327
+ * the page's locale, as FieldLabel's "(Optional)" is: on the public
328
+ * incident form, translated all round, they were the only English left.
329
+ * The English text is the key, and an app whose locale has no entry for
330
+ * it shows the English.
331
+ */
332
+ const { translateString } = useTranslateValue();
333
+ const visualPlaceholder: string =
334
+ props.placeholder ||
335
+ (translateString("Type your content here...") ??
336
+ "Type your content here...");
337
+ const sourcePlaceholder: string =
338
+ props.placeholder ||
339
+ (translateString("Type your markdown here...") ??
340
+ "Type your markdown here...");
341
+ const helpTitle: string =
342
+ translateString("Formatting help") ?? "Formatting help";
119
343
  const [text, setText] = useState<string>(props.initialValue || "");
120
344
  const [mode, setMode] = useState<EditorMode>("wysiwyg");
121
345
  const [isDraggingOver, setIsDraggingOver] = useState<boolean>(false);
@@ -134,6 +358,16 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
134
358
  const textRef: React.MutableRefObject<string> = useRef<string>(
135
359
  props.initialValue || "",
136
360
  );
361
+ /*
362
+ * The visual editor's own edits -- list moves, inserts made by hand --
363
+ * which the browser's undo stack never hears of (see
364
+ * MarkdownEditorHistory).
365
+ */
366
+ const [history] = useState<MarkdownEditorHistory>(
367
+ (): MarkdownEditorHistory => {
368
+ return new MarkdownEditorHistory();
369
+ },
370
+ );
137
371
 
138
372
  useEffect(() => {
139
373
  if (
@@ -145,6 +379,11 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
145
379
  }
146
380
  }, [props.initialValue]);
147
381
 
382
+ // A new editable in each mode: records about the old one's nodes are no use.
383
+ useEffect(() => {
384
+ history.clear();
385
+ }, [mode]);
386
+
148
387
  /*
149
388
  * Sync markdown -> contenteditable when entering WYSIWYG, when text
150
389
  * changes from outside, or after async image-upload swaps. Skip when
@@ -168,6 +407,7 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
168
407
  const html: string = sanitizeHtml(markdownToHtml(text));
169
408
  if (editable.innerHTML !== html) {
170
409
  editable.innerHTML = html;
410
+ history.clear();
171
411
  }
172
412
  }, [mode, text]);
173
413
 
@@ -191,6 +431,92 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
191
431
  }
192
432
  };
193
433
 
434
+ /*
435
+ * An edit the visual editor makes to its DOM itself, recorded so that
436
+ * Ctrl+Z takes it back. Returns what `edit` returns: whether it changed
437
+ * anything.
438
+ */
439
+ const editEditableByHand: (
440
+ edit: (editable: HTMLDivElement) => boolean,
441
+ ) => boolean = (edit: (editable: HTMLDivElement) => boolean): boolean => {
442
+ const editable: HTMLDivElement | null = editableRef.current;
443
+ if (!editable) {
444
+ return false;
445
+ }
446
+ return history.record(editable, (): boolean => {
447
+ return edit(editable);
448
+ });
449
+ };
450
+
451
+ /*
452
+ * Undo or redo of the editor's own edits; false (and nothing done) when
453
+ * the last thing to undo is the browser's -- typing, say -- so the
454
+ * browser does it.
455
+ */
456
+ const stepEditableHistory: (step: HistoryStep) => boolean = (
457
+ step: HistoryStep,
458
+ ): boolean => {
459
+ const editable: HTMLDivElement | null = editableRef.current;
460
+ if (!editable) {
461
+ return false;
462
+ }
463
+ const stepped: boolean =
464
+ step === "undo" ? history.undo(editable) : history.redo(editable);
465
+ if (stepped) {
466
+ syncFromEditable();
467
+ }
468
+ return stepped;
469
+ };
470
+
471
+ /*
472
+ * Typing, a paste the browser makes, an execCommand: each is newer
473
+ * history in the browser's own undo stack. The editor's own records wait
474
+ * behind it -- each applies again once the browser's undo has put the
475
+ * editor back as that edit left it -- but what they would redo is gone,
476
+ * as the browser's own redo is. The browser's undo and redo themselves
477
+ * leave both be.
478
+ */
479
+ const handleEditableInput: (
480
+ event: React.FormEvent<HTMLDivElement>,
481
+ ) => void = (event: React.FormEvent<HTMLDivElement>): void => {
482
+ const inputType: string =
483
+ (event.nativeEvent as InputEvent | undefined)?.inputType || "";
484
+ if (inputType !== "historyUndo" && inputType !== "historyRedo") {
485
+ history.clearRedo();
486
+ }
487
+ syncFromEditable();
488
+ };
489
+
490
+ /*
491
+ * Undo and redo from the browser's Edit menu or context menu arrive with
492
+ * no key press, as a native beforeinput event -- which React's
493
+ * onBeforeInput is not -- so it is listened for on the element itself.
494
+ * The ref keeps the listener on the latest render's handlers.
495
+ */
496
+ const beforeInputRef: React.MutableRefObject<(event: InputEvent) => void> =
497
+ useRef<(event: InputEvent) => void>((): void => {});
498
+ beforeInputRef.current = (event: InputEvent): void => {
499
+ if (
500
+ (event.inputType === "historyUndo" && stepEditableHistory("undo")) ||
501
+ (event.inputType === "historyRedo" && stepEditableHistory("redo"))
502
+ ) {
503
+ event.preventDefault();
504
+ }
505
+ };
506
+ useEffect(() => {
507
+ const editable: HTMLDivElement | null = editableRef.current;
508
+ if (mode !== "wysiwyg" || !editable) {
509
+ return undefined;
510
+ }
511
+ const listener: (event: Event) => void = (event: Event): void => {
512
+ beforeInputRef.current(event as InputEvent);
513
+ };
514
+ editable.addEventListener("beforeinput", listener);
515
+ return () => {
516
+ editable.removeEventListener("beforeinput", listener);
517
+ };
518
+ }, [mode]);
519
+
194
520
  const insertTextAtCursor: (textToInsert: string) => void = (
195
521
  textToInsert: string,
196
522
  ): void => {
@@ -235,17 +561,79 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
235
561
  syncFromEditable();
236
562
  return;
237
563
  }
238
- range.deleteContents();
239
- const fragment: DocumentFragment = range.createContextualFragment(html);
240
- const lastNode: ChildNode | null = fragment.lastChild;
241
- range.insertNode(fragment);
242
- if (lastNode) {
243
- const newRange: Range = document.createRange();
244
- newRange.setStartAfter(lastNode);
245
- newRange.collapse(true);
564
+ // Chromium's caret just before a list it has just made goes into its item.
565
+ if (moveCaretIntoEmptyListAhead(editable, range)) {
246
566
  selection.removeAllRanges();
247
- selection.addRange(newRange);
567
+ selection.addRange(range);
248
568
  }
569
+ /*
570
+ * A single paragraph goes in as its contents, so text pasted into the
571
+ * middle of a line joins that line. Inserted whole, the <p> landed
572
+ * inside the paragraph the caret was in and the serializer wrote it out
573
+ * as three: pasting "big " into "hello world" saved
574
+ * "hello \n\nbig \n\nworld", and an uploading image's placeholder split
575
+ * its line the same way. Straight into the editor itself -- empty, or
576
+ * between two blocks -- the paragraph is kept.
577
+ */
578
+ const contents: string =
579
+ range.startContainer === editable
580
+ ? html
581
+ : singleParagraphContents(html) ?? html;
582
+ /*
583
+ * execCommand puts the insert on the browser's undo stack. Plain words
584
+ * go in with insertText, as if typed. Blocks go in with insertHTML only
585
+ * onto an empty line: anywhere else in a line, Chromium and Safari fold
586
+ * the first block into that line -- a <pre> became a monospace <span> of
587
+ * the paragraph, and a code block pasted after "Run:" saved as
588
+ * "Run:npm install" -- so there the line is split at the caret by hand
589
+ * and the blocks go in between its halves. Words with formatting go in
590
+ * by hand too: Chromium's and Firefox's insertHTML turn the spaces around
591
+ * an inline insert into non-breaking ones, which then ended up in the
592
+ * saved markdown. jsdom has no execCommand and a browser may refuse the
593
+ * command, so the insert by hand is the fallback as well.
594
+ */
595
+ const inline: boolean = contents !== html;
596
+ const plainText: string | null = inline
597
+ ? textOfMarkupFreeHtml(contents)
598
+ : null;
599
+ let command: string | null = null;
600
+ if (plainText !== null) {
601
+ command = "insertText";
602
+ } else if (!inline && isCaretOnEmptyLine(editable, range)) {
603
+ command = "insertHTML";
604
+ }
605
+ if (command && typeof document.execCommand === "function") {
606
+ try {
607
+ if (document.execCommand(command, false, plainText ?? contents)) {
608
+ syncFromEditable();
609
+ return;
610
+ }
611
+ } catch {
612
+ // Fall through to the insert by hand.
613
+ }
614
+ }
615
+ editEditableByHand((): boolean => {
616
+ deleteSelectionForInsert(editable, range);
617
+ const fragment: DocumentFragment =
618
+ range.createContextualFragment(contents);
619
+ let caret: Range | null = null;
620
+ if (inline) {
621
+ const lastNode: ChildNode | null = fragment.lastChild;
622
+ range.insertNode(fragment);
623
+ if (lastNode) {
624
+ caret = document.createRange();
625
+ caret.setStartAfter(lastNode);
626
+ caret.collapse(true);
627
+ }
628
+ } else {
629
+ caret = insertBlocksAtCaret(editable, range, fragment);
630
+ }
631
+ if (caret) {
632
+ selection.removeAllRanges();
633
+ selection.addRange(caret);
634
+ }
635
+ return true;
636
+ });
249
637
  syncFromEditable();
250
638
  };
251
639
 
@@ -406,39 +794,158 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
406
794
  return files;
407
795
  };
408
796
 
797
+ /*
798
+ * Text for the source textarea. execCommand("insertText") types it the
799
+ * way a native paste would, so Ctrl+Z undoes it; where the browser has no
800
+ * such command (jsdom) it is spliced into the value instead.
801
+ */
802
+ const insertTextInTextarea: (textToInsert: string) => void = (
803
+ textToInsert: string,
804
+ ): void => {
805
+ const textarea: HTMLTextAreaElement | null = textareaRef.current;
806
+ if (textarea && typeof document.execCommand === "function") {
807
+ textarea.focus();
808
+ try {
809
+ if (document.execCommand("insertText", false, textToInsert)) {
810
+ return;
811
+ }
812
+ } catch {
813
+ // Fall back to splicing the value.
814
+ }
815
+ }
816
+ insertTextAtCursor(textToInsert);
817
+ };
818
+
819
+ /*
820
+ * Markdown mode. Rich clipboard content (a Word list, a copied note) is
821
+ * converted to markdown source, and a file on the clipboard uploads as
822
+ * before. When the conversion gives back exactly the plain text, the
823
+ * browser's own paste inserts the same thing, so it is left to it.
824
+ */
409
825
  const handleTextareaPaste: (
410
826
  e: React.ClipboardEvent<HTMLTextAreaElement>,
411
827
  ) => void = (e: React.ClipboardEvent<HTMLTextAreaElement>): void => {
412
- const images: Array<File> = extractImagesFromClipboard(
413
- e.clipboardData?.items || null,
828
+ const clipboardData: DataTransfer | null = e.clipboardData;
829
+ if (!clipboardData) {
830
+ return;
831
+ }
832
+ /*
833
+ * Inside a fenced code block the text goes in as it is, the browser's
834
+ * own paste (which keeps it on the undo stack) -- as in the visual
835
+ * editor's code blocks. Converted there, a command copied from a docs
836
+ * page came in as its own ``` fence, which closed the block around it,
837
+ * and CLI output had its "1)" and "•" lines rewritten as list items. A
838
+ * clipboard with no text, only an image, still uploads below.
839
+ */
840
+ const textarea: HTMLTextAreaElement = e.currentTarget;
841
+ if (
842
+ clipboardData.getData("text/plain") &&
843
+ isInFencedCodeBlock(textarea.value, textarea.selectionStart)
844
+ ) {
845
+ return;
846
+ }
847
+ const images: Array<File> = allowImageUpload
848
+ ? extractImagesFromClipboard(clipboardData.items || null)
849
+ : [];
850
+ const markdown: string | null = clipboardToMarkdown(clipboardData, {
851
+ hasImageFiles: images.length > 0,
852
+ });
853
+ if (markdown === null) {
854
+ if (images.length > 0) {
855
+ e.preventDefault();
856
+ void handleImageFiles(images);
857
+ }
858
+ return;
859
+ }
860
+ const plain: string = (clipboardData.getData("text/plain") || "").replace(
861
+ RE_LINE_BREAKS,
862
+ "\n",
414
863
  );
415
- if (images.length === 0) {
864
+ if (markdown === plain) {
416
865
  return;
417
866
  }
418
867
  e.preventDefault();
419
- void handleImageFiles(images);
868
+ insertTextInTextarea(onLinesOfItsOwn(textarea, markdown));
869
+ };
870
+
871
+ // The code block the caret is in, if it is in one.
872
+ const codeBlockAtSelection: () => HTMLElement | null =
873
+ (): HTMLElement | null => {
874
+ const editable: HTMLDivElement | null = editableRef.current;
875
+ const selection: Selection | null = window.getSelection();
876
+ if (!editable || !selection || selection.rangeCount === 0) {
877
+ return null;
878
+ }
879
+ let node: Node | null = selection.getRangeAt(0).startContainer;
880
+ while (node && node !== editable) {
881
+ if (node.nodeName.toLowerCase() === "pre") {
882
+ return node as HTMLElement;
883
+ }
884
+ node = node.parentNode;
885
+ }
886
+ return null;
887
+ };
888
+
889
+ const insertPlainTextInEditable: (value: string) => void = (
890
+ value: string,
891
+ ): void => {
892
+ const editable: HTMLDivElement | null = editableRef.current;
893
+ const selection: Selection | null = window.getSelection();
894
+ if (!editable || !selection || selection.rangeCount === 0) {
895
+ return;
896
+ }
897
+ const range: Range = selection.getRangeAt(0);
898
+ editEditableByHand((): boolean => {
899
+ deleteSelectionForInsert(editable, range);
900
+ const textNode: Text = document.createTextNode(value);
901
+ range.insertNode(textNode);
902
+ const after: Range = document.createRange();
903
+ after.setStartAfter(textNode);
904
+ after.collapse(true);
905
+ selection.removeAllRanges();
906
+ selection.addRange(after);
907
+ return true;
908
+ });
909
+ syncFromEditable();
420
910
  };
421
911
 
912
+ /*
913
+ * Visual mode. The browser's own paste would bring the source's markup in
914
+ * with it -- styles, classes, elements markdown cannot hold -- so the paste
915
+ * is always handled here: converted to markdown (the clipboard's HTML
916
+ * first, so a Word or Outlook list keeps its nesting, then its plain text)
917
+ * and rendered back. Image files upload when there is no text to paste.
918
+ * Inside a code block the plain text goes in as it is.
919
+ */
422
920
  const handleEditablePaste: (
423
921
  e: React.ClipboardEvent<HTMLDivElement>,
424
922
  ) => void = (e: React.ClipboardEvent<HTMLDivElement>): void => {
425
- const images: Array<File> = extractImagesFromClipboard(
426
- e.clipboardData?.items || null,
427
- );
428
- if (images.length > 0) {
429
- e.preventDefault();
430
- void handleImageFiles(images);
923
+ const clipboardData: DataTransfer | null = e.clipboardData;
924
+ if (!clipboardData) {
431
925
  return;
432
926
  }
433
- /*
434
- * Force plain-text paste so users don't import arbitrary styled HTML
435
- * (which our markdown serializer can't faithfully round-trip).
436
- */
437
- const plain: string | undefined = e.clipboardData?.getData("text/plain");
438
- if (plain !== undefined) {
439
- e.preventDefault();
440
- const html: string = sanitizeHtml(markdownToHtml(plain));
441
- insertHtmlAtCursorInEditable(html);
927
+ e.preventDefault();
928
+ if (codeBlockAtSelection()) {
929
+ const plain: string = clipboardData.getData("text/plain") || "";
930
+ if (plain) {
931
+ insertPlainTextInEditable(plain.replace(RE_LINE_BREAKS, "\n"));
932
+ }
933
+ return;
934
+ }
935
+ const images: Array<File> = allowImageUpload
936
+ ? extractImagesFromClipboard(clipboardData.items || null)
937
+ : [];
938
+ const markdown: string | null = clipboardToMarkdown(clipboardData, {
939
+ hasImageFiles: images.length > 0,
940
+ });
941
+ if (markdown !== null) {
942
+ if (markdown) {
943
+ insertMarkdownAtCursor(markdown);
944
+ }
945
+ return;
946
+ }
947
+ if (images.length > 0) {
948
+ void handleImageFiles(images);
442
949
  }
443
950
  };
444
951
 
@@ -463,6 +970,17 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
463
970
  return;
464
971
  }
465
972
  e.preventDefault();
973
+ if (!allowImageUpload) {
974
+ /*
975
+ * Refuse the drop outright. Left to itself the browser would drop the
976
+ * file in anyway -- Firefox inlines an image as a data: URL -- or
977
+ * navigate away to it.
978
+ */
979
+ if (e.dataTransfer) {
980
+ e.dataTransfer.dropEffect = "none";
981
+ }
982
+ return;
983
+ }
466
984
  if (!isDraggingOver) {
467
985
  setIsDraggingOver(true);
468
986
  }
@@ -482,6 +1000,9 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
482
1000
  }
483
1001
  e.preventDefault();
484
1002
  setIsDraggingOver(false);
1003
+ if (!allowImageUpload) {
1004
+ return;
1005
+ }
485
1006
  const fileList: FileList | null = e.dataTransfer?.files || null;
486
1007
  if (!fileList || fileList.length === 0) {
487
1008
  return;
@@ -491,6 +1012,9 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
491
1012
  };
492
1013
 
493
1014
  const handleImageButtonClick: () => void = (): void => {
1015
+ if (!allowImageUpload) {
1016
+ return;
1017
+ }
494
1018
  fileInputRef.current?.click();
495
1019
  };
496
1020
 
@@ -627,10 +1151,120 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
627
1151
  }
628
1152
  };
629
1153
 
1154
+ /*
1155
+ * Puts an edit into the source textarea, selection included. Only the
1156
+ * stretch that changed is replaced, with execCommand("insertText") where
1157
+ * the browser has it, so Ctrl+Z undoes an indent like any typing; without
1158
+ * it (jsdom) the value is set directly.
1159
+ */
1160
+ const applyTextareaEdit: (edit: MarkdownTextEdit) => void = (
1161
+ edit: MarkdownTextEdit,
1162
+ ): void => {
1163
+ const textarea: HTMLTextAreaElement | null = textareaRef.current;
1164
+ if (!textarea) {
1165
+ return;
1166
+ }
1167
+ const current: string = textarea.value;
1168
+ let start: number = 0;
1169
+ while (
1170
+ start < current.length &&
1171
+ start < edit.text.length &&
1172
+ current.charAt(start) === edit.text.charAt(start)
1173
+ ) {
1174
+ start++;
1175
+ }
1176
+ let oldEnd: number = current.length;
1177
+ let newEnd: number = edit.text.length;
1178
+ while (
1179
+ oldEnd > start &&
1180
+ newEnd > start &&
1181
+ current.charAt(oldEnd - 1) === edit.text.charAt(newEnd - 1)
1182
+ ) {
1183
+ oldEnd--;
1184
+ newEnd--;
1185
+ }
1186
+ textarea.focus();
1187
+ let applied: boolean = false;
1188
+ if (typeof document.execCommand === "function") {
1189
+ textarea.setSelectionRange(start, oldEnd);
1190
+ try {
1191
+ applied = document.execCommand(
1192
+ "insertText",
1193
+ false,
1194
+ edit.text.slice(start, newEnd),
1195
+ );
1196
+ } catch {
1197
+ applied = false;
1198
+ }
1199
+ }
1200
+ if (!applied || textarea.value !== edit.text) {
1201
+ textarea.value = edit.text;
1202
+ }
1203
+ if (textRef.current !== edit.text) {
1204
+ handleChange(edit.text);
1205
+ }
1206
+ textarea.setSelectionRange(edit.selectionStart, edit.selectionEnd);
1207
+ };
1208
+
1209
+ // Runs a source edit on the textarea's text and selection; false if it changed nothing.
1210
+ const editTextarea: (editor: MarkdownTextEditor) => boolean = (
1211
+ editor: MarkdownTextEditor,
1212
+ ): boolean => {
1213
+ const textarea: HTMLTextAreaElement | null = textareaRef.current;
1214
+ if (!textarea) {
1215
+ return false;
1216
+ }
1217
+ const edit: MarkdownTextEdit | null = editor(
1218
+ textarea.value,
1219
+ textarea.selectionStart,
1220
+ textarea.selectionEnd,
1221
+ );
1222
+ if (!edit) {
1223
+ return false;
1224
+ }
1225
+ applyTextareaEdit(edit);
1226
+ return true;
1227
+ };
1228
+
1229
+ const toggleListInTextarea: (kind: MarkdownListKind) => void = (
1230
+ kind: MarkdownListKind,
1231
+ ): void => {
1232
+ editTextarea(
1233
+ (source: string, selectionStart: number, selectionEnd: number) => {
1234
+ return toggleMarkdownList(source, selectionStart, selectionEnd, kind);
1235
+ },
1236
+ );
1237
+ };
1238
+
1239
+ /*
1240
+ * Indent or outdent the list items at the selection in the visual editor;
1241
+ * false (and nothing changed) when the selection is not on an item that
1242
+ * can move. The items are moved by hand, so the move is recorded for
1243
+ * Ctrl+Z: it undid the typing before an indent and left the indent.
1244
+ */
1245
+ const shiftListItemsInEditable: (outdent: boolean) => boolean = (
1246
+ outdent: boolean,
1247
+ ): boolean => {
1248
+ const changed: boolean = editEditableByHand(
1249
+ (editable: HTMLDivElement): boolean => {
1250
+ return outdent ? liftListItems(editable) : sinkListItems(editable);
1251
+ },
1252
+ );
1253
+ if (changed) {
1254
+ syncFromEditable();
1255
+ }
1256
+ return changed;
1257
+ };
1258
+
630
1259
  // WYSIWYG-mode toolbar helpers (operate on the contenteditable DOM).
631
- const execEditable: (command: string, value?: string) => void = (
1260
+ const execEditable: (
632
1261
  command: string,
633
1262
  value?: string,
1263
+ afterCommand?: (editable: HTMLDivElement) => void,
1264
+ ) => void = (
1265
+ command: string,
1266
+ value?: string,
1267
+ afterCommand?: (editable: HTMLDivElement) => void,
634
1268
  ): void => {
635
1269
  const editable: HTMLDivElement | null = editableRef.current;
636
1270
  if (!editable) {
@@ -647,9 +1281,26 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
647
1281
  } catch {
648
1282
  // Ignore — older command names occasionally throw in some browsers.
649
1283
  }
1284
+ if (afterCommand) {
1285
+ afterCommand(editable);
1286
+ }
650
1287
  syncFromEditable();
651
1288
  };
652
1289
 
1290
+ /*
1291
+ * The list buttons. execCommand turns the selected lines into items but
1292
+ * keeps whatever text they started with, so a line pasted from Word as
1293
+ * "•\tService down" showed the list's bullet and its own; the leftover
1294
+ * markers are stripped from the items it made.
1295
+ */
1296
+ const makeListInEditable: (command: string) => void = (
1297
+ command: string,
1298
+ ): void => {
1299
+ execEditable(command, undefined, (editable: HTMLDivElement): void => {
1300
+ stripTextListMarkers(editable);
1301
+ });
1302
+ };
1303
+
653
1304
  const wrapSelectionInEditable: (
654
1305
  tagName: string,
655
1306
  fallbackText: string,
@@ -668,12 +1319,15 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
668
1319
  const selected: string = selection.toString() || fallbackText;
669
1320
  const wrapper: HTMLElement = document.createElement(tagName);
670
1321
  wrapper.textContent = selected;
671
- range.deleteContents();
672
- range.insertNode(wrapper);
673
- const newRange: Range = document.createRange();
674
- newRange.selectNodeContents(wrapper);
675
- selection.removeAllRanges();
676
- selection.addRange(newRange);
1322
+ editEditableByHand((): boolean => {
1323
+ deleteSelectionForInsert(editable, range);
1324
+ range.insertNode(wrapper);
1325
+ const newRange: Range = document.createRange();
1326
+ newRange.selectNodeContents(wrapper);
1327
+ selection.removeAllRanges();
1328
+ selection.addRange(newRange);
1329
+ return true;
1330
+ });
677
1331
  syncFromEditable();
678
1332
  };
679
1333
 
@@ -703,14 +1357,52 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
703
1357
  if (hasSelection) {
704
1358
  execEditable("createLink", url);
705
1359
  } else {
1360
+ /*
1361
+ * Wrapped in a paragraph, so a link put into a line goes in as that
1362
+ * line's own inline content (insertHtmlAtCursorInEditable unwraps a
1363
+ * single paragraph). A bare <a> was taken for a block: it split the
1364
+ * line, and "See " plus the link saved as two paragraphs. Into the
1365
+ * empty editor the paragraph goes in whole.
1366
+ */
706
1367
  insertHtmlAtCursorInEditable(
707
- `<a href="${url.replace(/"/g, "&quot;")}">${url.replace(/</g, "&lt;")}</a>`,
1368
+ `<p><a href="${url.replace(/"/g, "&quot;")}">${url.replace(/</g, "&lt;")}</a></p>`,
708
1369
  );
709
1370
  }
710
1371
  };
711
1372
 
1373
+ /*
1374
+ * The Code Block button. As in the markdown source, the new block's
1375
+ * placeholder is selected, so what is typed next replaces it inside the
1376
+ * block. Left to themselves, browsers put the caret at the end of the
1377
+ * placeholder (Chromium, Safari) or on the line below the block (Firefox).
1378
+ * The empty line after the block (a <br> keeps it a line a caret can sit
1379
+ * on) is where writing carries on below it.
1380
+ */
712
1381
  const insertWysiwygCodeBlock: () => void = (): void => {
713
- insertHtmlAtCursorInEditable("<pre><code>code block</code></pre><p></p>");
1382
+ const editable: HTMLDivElement | null = editableRef.current;
1383
+ if (!editable) {
1384
+ return;
1385
+ }
1386
+ const existing: Set<Element> = new Set<Element>(
1387
+ Array.from(editable.querySelectorAll("pre")),
1388
+ );
1389
+ insertHtmlAtCursorInEditable(
1390
+ "<pre><code>code block</code></pre><p><br></p>",
1391
+ );
1392
+ const added: Array<Element> = Array.from(
1393
+ editable.querySelectorAll("pre"),
1394
+ ).filter((pre: Element): boolean => {
1395
+ return !existing.has(pre);
1396
+ });
1397
+ const block: Element | undefined = added[added.length - 1];
1398
+ const selection: Selection | null = window.getSelection();
1399
+ if (!block || !selection) {
1400
+ return;
1401
+ }
1402
+ const placeholder: Range = document.createRange();
1403
+ placeholder.selectNodeContents(block.querySelector("code") || block);
1404
+ selection.removeAllRanges();
1405
+ selection.addRange(placeholder);
714
1406
  };
715
1407
 
716
1408
  const insertWysiwygTable: () => void = (): void => {
@@ -719,7 +1411,7 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
719
1411
  "<tbody>" +
720
1412
  "<tr><td>Cell 1</td><td>Cell 2</td><td>Cell 3</td></tr>" +
721
1413
  "<tr><td>Cell 4</td><td>Cell 5</td><td>Cell 6</td></tr>" +
722
- "</tbody></table><p></p>";
1414
+ "</tbody></table><p><br></p>";
723
1415
  insertHtmlAtCursorInEditable(html);
724
1416
  };
725
1417
 
@@ -734,6 +1426,8 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
734
1426
  unorderedList: () => void;
735
1427
  orderedList: () => void;
736
1428
  taskList: () => void;
1429
+ indent: () => void;
1430
+ outdent: () => void;
737
1431
  link: () => void;
738
1432
  image: () => void;
739
1433
  code: () => void;
@@ -786,21 +1480,37 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
786
1480
  },
787
1481
  unorderedList: () => {
788
1482
  if (mode === "wysiwyg") {
789
- return execEditable("insertUnorderedList");
1483
+ return makeListInEditable("insertUnorderedList");
790
1484
  }
791
- return insertAtLineStart("- ");
1485
+ return toggleListInTextarea("bullet");
792
1486
  },
793
1487
  orderedList: () => {
794
1488
  if (mode === "wysiwyg") {
795
- return execEditable("insertOrderedList");
1489
+ return makeListInEditable("insertOrderedList");
796
1490
  }
797
- return insertAtLineStart("1. ");
1491
+ return toggleListInTextarea("ordered");
798
1492
  },
799
1493
  taskList: () => {
800
1494
  if (mode === "wysiwyg") {
801
1495
  return insertWysiwygTaskList();
802
1496
  }
803
- return insertAtLineStart("- [ ] ");
1497
+ return toggleListInTextarea("task");
1498
+ },
1499
+ indent: () => {
1500
+ if (mode === "wysiwyg") {
1501
+ editableRef.current?.focus();
1502
+ shiftListItemsInEditable(false);
1503
+ return;
1504
+ }
1505
+ editTextarea(indentMarkdownLines);
1506
+ },
1507
+ outdent: () => {
1508
+ if (mode === "wysiwyg") {
1509
+ editableRef.current?.focus();
1510
+ shiftListItemsInEditable(true);
1511
+ return;
1512
+ }
1513
+ editTextarea(outdentMarkdownLines);
804
1514
  },
805
1515
  link: () => {
806
1516
  if (mode === "wysiwyg") {
@@ -873,6 +1583,16 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
873
1583
  const handleEditableKeyDown: (
874
1584
  e: React.KeyboardEvent<HTMLDivElement>,
875
1585
  ) => void = (e: React.KeyboardEvent<HTMLDivElement>): void => {
1586
+ /*
1587
+ * Ctrl+Z right after an edit the editor made itself -- a list move, an
1588
+ * insert made by hand -- takes that edit back, and Ctrl+Shift+Z makes
1589
+ * it again. Otherwise the key is the browser's, as always.
1590
+ */
1591
+ const historyStep: HistoryStep | null = historyStepOfKey(e);
1592
+ if (historyStep && stepEditableHistory(historyStep)) {
1593
+ e.preventDefault();
1594
+ return;
1595
+ }
876
1596
  if (e.ctrlKey || e.metaKey) {
877
1597
  switch (e.key) {
878
1598
  case "b":
@@ -887,6 +1607,41 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
887
1607
  break;
888
1608
  }
889
1609
  }
1610
+ /*
1611
+ * Tab indents a list item and Shift+Tab outdents it -- but the key is
1612
+ * only taken when that actually moved something. On a list's first
1613
+ * item, a top-level item, or outside a list, Tab keeps moving focus to
1614
+ * the next field (and Shift+Tab to the previous one), so the editor is
1615
+ * never a keyboard trap. The event is not stopped either: the note
1616
+ * composer handles its own keys where they bubble to.
1617
+ */
1618
+ if (isListIndentKey(e) && shiftListItemsInEditable(e.shiftKey)) {
1619
+ e.preventDefault();
1620
+ }
1621
+ };
1622
+
1623
+ const handleTextareaKeyDown: (
1624
+ e: React.KeyboardEvent<HTMLTextAreaElement>,
1625
+ ) => void = (e: React.KeyboardEvent<HTMLTextAreaElement>): void => {
1626
+ if (e.ctrlKey || e.metaKey) {
1627
+ switch (e.key) {
1628
+ case "b":
1629
+ e.preventDefault();
1630
+ formatActions.bold();
1631
+ break;
1632
+ case "i":
1633
+ e.preventDefault();
1634
+ formatActions.italic();
1635
+ break;
1636
+ }
1637
+ }
1638
+ // The same Tab rule as the visual editor's, on the markdown lines.
1639
+ if (
1640
+ isListIndentKey(e) &&
1641
+ editTextarea(e.shiftKey ? outdentMarkdownLines : indentMarkdownLines)
1642
+ ) {
1643
+ e.preventDefault();
1644
+ }
890
1645
  };
891
1646
 
892
1647
  return (
@@ -899,6 +1654,9 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
899
1654
  .oneuptime-wysiwyg p { margin: 0.5rem 0; }
900
1655
  .oneuptime-wysiwyg ul, .oneuptime-wysiwyg ol { margin: 0.5rem 0 0.5rem 1.5rem; }
901
1656
  .oneuptime-wysiwyg ul { list-style-type: disc; }
1657
+ /* Nested bullets step through circle and square, as MarkdownViewer draws them. */
1658
+ .oneuptime-wysiwyg ul ul, .oneuptime-wysiwyg ol ul { list-style-type: circle; }
1659
+ .oneuptime-wysiwyg ul ul ul, .oneuptime-wysiwyg ul ol ul, .oneuptime-wysiwyg ol ul ul, .oneuptime-wysiwyg ol ol ul { list-style-type: square; }
902
1660
  .oneuptime-wysiwyg ol { list-style-type: decimal; }
903
1661
  .oneuptime-wysiwyg ul.task-list, .oneuptime-wysiwyg ul.task-list li { list-style: none; margin-left: 0; }
904
1662
  .oneuptime-wysiwyg ul.task-list li { padding-left: 0; }
@@ -1006,6 +1764,21 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
1006
1764
  title="Task List"
1007
1765
  onClick={formatActions.taskList}
1008
1766
  />
1767
+ <ToolbarButton
1768
+ icon={IconProp.Indent}
1769
+ title={`Indent (${KeyboardKeyUtil.getDisplayLabel([
1770
+ KeyboardKey.Tab,
1771
+ ])})`}
1772
+ onClick={formatActions.indent}
1773
+ />
1774
+ <ToolbarButton
1775
+ icon={IconProp.Outdent}
1776
+ title={`Outdent (${KeyboardKeyUtil.getDisplayLabel([
1777
+ KeyboardKey.Shift,
1778
+ KeyboardKey.Tab,
1779
+ ])})`}
1780
+ onClick={formatActions.outdent}
1781
+ />
1009
1782
  </div>
1010
1783
 
1011
1784
  <div className="w-px h-6 bg-gray-300" />
@@ -1017,11 +1790,13 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
1017
1790
  title="Link"
1018
1791
  onClick={formatActions.link}
1019
1792
  />
1020
- <ToolbarButton
1021
- icon={IconProp.Image}
1022
- title="Image"
1023
- onClick={formatActions.image}
1024
- />
1793
+ {allowImageUpload && (
1794
+ <ToolbarButton
1795
+ icon={IconProp.Image}
1796
+ title="Image"
1797
+ onClick={formatActions.image}
1798
+ />
1799
+ )}
1025
1800
  <ToolbarButton
1026
1801
  icon={IconProp.Code}
1027
1802
  title="Code"
@@ -1106,14 +1881,16 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
1106
1881
 
1107
1882
  {/* Editor Area */}
1108
1883
  <div className="relative">
1109
- <input
1110
- ref={fileInputRef}
1111
- type="file"
1112
- accept="image/*"
1113
- multiple
1114
- className="hidden"
1115
- onChange={handleFileInputChange}
1116
- />
1884
+ {allowImageUpload && (
1885
+ <input
1886
+ ref={fileInputRef}
1887
+ type="file"
1888
+ accept="image/*"
1889
+ multiple
1890
+ className="hidden"
1891
+ onChange={handleFileInputChange}
1892
+ />
1893
+ )}
1117
1894
  {mode === "wysiwyg" ? (
1118
1895
  <>
1119
1896
  <div
@@ -1121,15 +1898,15 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
1121
1898
  role="textbox"
1122
1899
  aria-multiline="true"
1123
1900
  aria-labelledby={props.ariaLabelledby}
1901
+ aria-invalid={props.error ? "true" : undefined}
1902
+ aria-describedby={props.error ? errorId : undefined}
1124
1903
  contentEditable
1125
1904
  suppressContentEditableWarning
1126
1905
  spellCheck={props.disableSpellCheck !== true}
1127
- data-placeholder={
1128
- props.placeholder || "Type your content here..."
1129
- }
1906
+ data-placeholder={visualPlaceholder}
1130
1907
  tabIndex={props.tabIndex}
1131
1908
  className={wysiwygClassName}
1132
- onInput={syncFromEditable}
1909
+ onInput={handleEditableInput}
1133
1910
  onPaste={handleEditablePaste}
1134
1911
  onDragOver={handleDragOver}
1135
1912
  onDragEnter={handleDragOver}
@@ -1169,7 +1946,9 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
1169
1946
  ref={textareaRef}
1170
1947
  autoFocus={false}
1171
1948
  aria-labelledby={props.ariaLabelledby}
1172
- placeholder={props.placeholder || "Type your markdown here..."}
1949
+ aria-invalid={props.error ? "true" : undefined}
1950
+ aria-describedby={props.error ? errorId : undefined}
1951
+ placeholder={sourcePlaceholder}
1173
1952
  className={`${className} rounded-t-none min-h-32 ${
1174
1953
  isDraggingOver
1175
1954
  ? "ring-2 ring-indigo-400 ring-offset-1 border-indigo-400"
@@ -1195,20 +1974,7 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
1195
1974
  props.onBlur();
1196
1975
  }
1197
1976
  }}
1198
- onKeyDown={(e: React.KeyboardEvent<HTMLTextAreaElement>) => {
1199
- if (e.ctrlKey || e.metaKey) {
1200
- switch (e.key) {
1201
- case "b":
1202
- e.preventDefault();
1203
- formatActions.bold();
1204
- break;
1205
- case "i":
1206
- e.preventDefault();
1207
- formatActions.italic();
1208
- break;
1209
- }
1210
- }
1211
- }}
1977
+ onKeyDown={handleTextareaKeyDown}
1212
1978
  tabIndex={props.tabIndex}
1213
1979
  rows={10}
1214
1980
  />
@@ -1233,11 +1999,13 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
1233
1999
 
1234
2000
  {/* Error Message */}
1235
2001
  {props.error && (
1236
- <p className="mt-1 text-sm text-red-400">{props.error}</p>
2002
+ <p id={errorId} role="alert" className="mt-1 text-sm text-red-400">
2003
+ {props.error}
2004
+ </p>
1237
2005
  )}
1238
2006
 
1239
2007
  {/* Help Text */}
1240
- <TinyFormDocumentation title="Formatting help">
2008
+ <TinyFormDocumentation title={helpTitle}>
1241
2009
  <>
1242
2010
  <div>
1243
2011
  Type directly in the visual editor — use the toolbar to format.
@@ -1246,9 +2014,39 @@ const MarkdownEditor: FunctionComponent<ComponentProps> = (
1246
2014
  Switch to <strong>Markdown</strong> to view or edit the raw source.
1247
2015
  </div>
1248
2016
  <div>
1249
- Tip: paste, drag &amp; drop, or click the image button to upload
1250
- screenshots inline.
2017
+ In a list, press{" "}
2018
+ <strong>
2019
+ {KeyboardKeyUtil.getDisplayLabel([KeyboardKey.Tab])}
2020
+ </strong>{" "}
2021
+ to indent an item and{" "}
2022
+ <strong>
2023
+ {KeyboardKeyUtil.getDisplayLabel([
2024
+ KeyboardKey.Shift,
2025
+ KeyboardKey.Tab,
2026
+ ])}
2027
+ </strong>{" "}
2028
+ to outdent it, or use the Indent and Outdent buttons. Outside a
2029
+ list, {KeyboardKeyUtil.getDisplayLabel([KeyboardKey.Tab])} moves to
2030
+ the next field.
2031
+ </div>
2032
+ <div>
2033
+ Pasting keeps lists, links and formatting from Word, Outlook, web
2034
+ pages and other notes. To paste plain text instead, press{" "}
2035
+ <strong>
2036
+ {KeyboardKeyUtil.getDisplayLabel([
2037
+ KeyboardKey.Mod,
2038
+ KeyboardKey.Shift,
2039
+ "V",
2040
+ ])}
2041
+ </strong>
2042
+ .
1251
2043
  </div>
2044
+ {allowImageUpload && (
2045
+ <div>
2046
+ Tip: paste, drag &amp; drop, or click the image button to upload
2047
+ screenshots inline.
2048
+ </div>
2049
+ )}
1252
2050
  </>
1253
2051
  </TinyFormDocumentation>
1254
2052
  </div>