@oneuptime/common 14.0.9 → 14.0.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1146) hide show
  1. package/Models/DatabaseModels/AIConversation.ts +127 -1
  2. package/Models/DatabaseModels/AutoRemediationSuggestion.ts +60 -0
  3. package/Models/DatabaseModels/CephCluster.ts +225 -0
  4. package/Models/DatabaseModels/CloudResource.ts +12 -0
  5. package/Models/DatabaseModels/DatabaseServer.ts +225 -0
  6. package/Models/DatabaseModels/DockerHost.ts +225 -0
  7. package/Models/DatabaseModels/DockerSwarmCluster.ts +225 -0
  8. package/Models/DatabaseModels/GlobalConfig.ts +1 -1
  9. package/Models/DatabaseModels/GlobalOidc.ts +0 -4
  10. package/Models/DatabaseModels/GlobalOidcProject.ts +0 -4
  11. package/Models/DatabaseModels/GlobalSso.ts +0 -4
  12. package/Models/DatabaseModels/GlobalSsoProject.ts +0 -4
  13. package/Models/DatabaseModels/Host.ts +225 -0
  14. package/Models/DatabaseModels/IncidentForm.ts +594 -0
  15. package/Models/DatabaseModels/IncidentFormSubmission.ts +283 -0
  16. package/Models/DatabaseModels/IncidentTemplate.ts +59 -0
  17. package/Models/DatabaseModels/Index.ts +16 -0
  18. package/Models/DatabaseModels/IoTFleet.ts +12 -0
  19. package/Models/DatabaseModels/KubernetesCluster.ts +12 -0
  20. package/Models/DatabaseModels/MessageQueue.ts +1102 -0
  21. package/Models/DatabaseModels/MessageQueueLabelRule.ts +553 -0
  22. package/Models/DatabaseModels/MessageQueueOwnerRule.ts +633 -0
  23. package/Models/DatabaseModels/MessageQueueOwnerTeam.ts +491 -0
  24. package/Models/DatabaseModels/MessageQueueOwnerUser.ts +490 -0
  25. package/Models/DatabaseModels/PodmanHost.ts +225 -0
  26. package/Models/DatabaseModels/Project.ts +59 -0
  27. package/Models/DatabaseModels/ProjectOidc.ts +0 -4
  28. package/Models/DatabaseModels/ProjectSso.ts +0 -4
  29. package/Models/DatabaseModels/ProxmoxCluster.ts +225 -0
  30. package/Models/DatabaseModels/ResourceAiAgent.ts +419 -0
  31. package/Models/DatabaseModels/RumApplication.ts +12 -0
  32. package/Models/DatabaseModels/RunnerJob.ts +144 -0
  33. package/Models/DatabaseModels/ServerlessFunction.ts +12 -0
  34. package/Models/DatabaseModels/Service.ts +12 -0
  35. package/Models/DatabaseModels/StatusPageOidc.ts +0 -4
  36. package/Models/DatabaseModels/StatusPageSso.ts +0 -4
  37. package/Models/DatabaseModels/TeamComplianceSetting.ts +47 -2
  38. package/Models/DatabaseModels/VMwareVCenter.ts +225 -0
  39. package/Server/API/AIChatAPI.ts +13 -114
  40. package/Server/API/AIInvestigationAPI.ts +3 -3
  41. package/Server/API/AIInvestigationConversationAPI.ts +266 -0
  42. package/Server/API/AutoRemediationAPI.ts +392 -1
  43. package/Server/API/IncidentFormAPI.ts +376 -0
  44. package/Server/API/ProjectOIDC.ts +16 -25
  45. package/Server/API/ProjectSSO.ts +16 -24
  46. package/Server/API/ResourceAiAccessAPI.ts +1669 -0
  47. package/Server/API/StatusPageAPI.ts +42 -77
  48. package/Server/Enterprise/EnterpriseEdition.ts +93 -28
  49. package/Server/Enterprise/EnterpriseFeature.ts +25 -3
  50. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +1 -1
  51. package/Server/Enterprise/EnterpriseServerModule.ts +4 -1
  52. package/Server/EnvironmentConfig.ts +1 -1
  53. package/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.ts +423 -0
  54. package/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.ts +129 -0
  55. package/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.ts +52 -0
  56. package/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.ts +75 -0
  57. package/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.ts +477 -0
  58. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  59. package/Server/Infrastructure/Semaphore.ts +22 -0
  60. package/Server/Middleware/IncidentFormRateLimit.ts +847 -0
  61. package/Server/Middleware/TelemetryIngest.ts +15 -5
  62. package/Server/Middleware/UserAuthorization.ts +16 -38
  63. package/Server/Services/AIService.ts +10 -13
  64. package/Server/Services/AnalyticsDatabaseService.ts +45 -1
  65. package/Server/Services/AutoRemediationRuleEngineService.ts +940 -112
  66. package/Server/Services/CephClusterService.ts +109 -1
  67. package/Server/Services/DatabaseServerService.ts +116 -1
  68. package/Server/Services/DockerHostService.ts +109 -1
  69. package/Server/Services/DockerSwarmClusterService.ts +113 -1
  70. package/Server/Services/HostService.ts +126 -4
  71. package/Server/Services/IncidentCustomFieldService.ts +112 -2
  72. package/Server/Services/IncidentEpisodeMemberService.ts +24 -4
  73. package/Server/Services/IncidentEpisodeService.ts +10 -1
  74. package/Server/Services/IncidentFormService.ts +1566 -0
  75. package/Server/Services/IncidentFormSubmissionService.ts +97 -0
  76. package/Server/Services/IncidentGroupingEngineService.ts +45 -8
  77. package/Server/Services/IncidentService.ts +123 -5
  78. package/Server/Services/IncidentTemplateService.ts +22 -0
  79. package/Server/Services/Index.ts +14 -0
  80. package/Server/Services/MessageQueueLabelRuleEngineService.ts +321 -0
  81. package/Server/Services/MessageQueueLabelRuleService.ts +14 -0
  82. package/Server/Services/MessageQueueOwnerRuleEngineService.ts +412 -0
  83. package/Server/Services/MessageQueueOwnerRuleService.ts +14 -0
  84. package/Server/Services/MessageQueueOwnerTeamService.ts +62 -0
  85. package/Server/Services/MessageQueueOwnerUserService.ts +62 -0
  86. package/Server/Services/MessageQueueService.ts +1463 -0
  87. package/Server/Services/MetricRecordingRuleService.ts +47 -0
  88. package/Server/Services/OpenTelemetryIngestService.ts +37 -4
  89. package/Server/Services/PodmanHostService.ts +109 -1
  90. package/Server/Services/ProjectService.ts +0 -59
  91. package/Server/Services/ProxmoxClusterService.ts +110 -1
  92. package/Server/Services/ResourceAiAccessService.ts +1439 -0
  93. package/Server/Services/ResourceAiAgentJobService.ts +202 -0
  94. package/Server/Services/ResourceAiAgentService.ts +2432 -0
  95. package/Server/Services/RunnerJobService.ts +611 -4
  96. package/Server/Services/StatusPagePrivateUserService.ts +1 -4
  97. package/Server/Services/StatusPageService.ts +1 -51
  98. package/Server/Services/TeamComplianceSettingService.ts +163 -42
  99. package/Server/Services/TelemetryUsageBillingService.ts +28 -0
  100. package/Server/Services/TraceRecordingRuleService.ts +33 -0
  101. package/Server/Services/UserNotificationRuleService.ts +8 -1
  102. package/Server/Services/VMwareVCenterService.ts +110 -1
  103. package/Server/Services/WorkspaceNotificationSummaryService.ts +12 -3
  104. package/Server/Types/Database/Permissions/CreatePermission.ts +17 -3
  105. package/Server/Types/Database/Permissions/EditionPermission.ts +140 -38
  106. package/Server/Types/Database/Permissions/OwnerTableRegistry.ts +16 -0
  107. package/Server/Types/Database/Permissions/TablePermission.ts +3 -3
  108. package/Server/Types/Database/Permissions/UpdatePermission.ts +20 -6
  109. package/Server/Utils/AI/Chat/AgentContextCompactor.ts +200 -0
  110. package/Server/Utils/AI/Chat/ChatAgentRunner.ts +307 -48
  111. package/Server/Utils/AI/Chat/ChatRunCancellation.ts +156 -0
  112. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +78 -18
  113. package/Server/Utils/AI/Chat/ObservabilityChatPrompt.ts +1 -1
  114. package/Server/Utils/AI/Chat/ToolOutputPager.ts +322 -0
  115. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +88 -30
  116. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +13 -1
  117. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +0 -32
  118. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +27 -25
  119. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1442 -34
  120. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +968 -34
  121. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +25 -1
  122. package/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.ts +622 -0
  123. package/Server/Utils/AI/ResourceAccess/ResourceAccessContext.ts +271 -0
  124. package/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.ts +45 -0
  125. package/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.ts +964 -0
  126. package/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.ts +333 -0
  127. package/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.ts +882 -0
  128. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +125 -12
  129. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +99 -15
  130. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +99 -15
  131. package/Server/Utils/AI/SRE/InvestigationQueue.ts +16 -19
  132. package/Server/Utils/AI/SRE/InvestigationThread.ts +646 -0
  133. package/Server/Utils/AI/SRE/InvestigationThreadService.ts +715 -0
  134. package/Server/Utils/AI/Toolbox/Serializer.ts +10 -3
  135. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +396 -13
  136. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +35 -2
  137. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +9 -1
  138. package/Server/Utils/EditionEnforcement.ts +19 -202
  139. package/Server/Utils/LLM/LLMService.ts +259 -63
  140. package/Server/Utils/RelaxedScimTeamLocksReport.ts +245 -0
  141. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +25 -0
  142. package/Server/Utils/SameOriginRequest.ts +203 -0
  143. package/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.ts +920 -0
  144. package/Server/Utils/SessionReplay/SessionReplayUsage.ts +84 -6
  145. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +2 -0
  146. package/Server/Utils/Telemetry/EntityRegistry.ts +4 -1
  147. package/Server/Utils/Telemetry/MessageQueueDiscovery.ts +1402 -0
  148. package/Server/Utils/Telemetry/ResourceEntityFilter.ts +4 -1
  149. package/Server/Utils/VendorAssets.ts +3 -3
  150. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +35 -15
  151. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +33 -15
  152. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.ts +21 -1
  153. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +301 -225
  154. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +38 -16
  155. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +389 -175
  156. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +376 -144
  157. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.ts +163 -0
  158. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.ts +396 -0
  159. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.ts +418 -0
  160. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.ts +152 -0
  161. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.ts +251 -0
  162. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.ts +214 -0
  163. package/Tests/App/Accounts/IncidentFormPage.test.tsx +2036 -0
  164. package/Tests/App/Accounts/IncidentFormServerMessages.test.ts +119 -0
  165. package/Tests/App/Accounts/IncidentFormUtils.test.ts +1157 -0
  166. package/Tests/App/Accounts/LoginPasskey.test.tsx +6 -4
  167. package/Tests/App/Accounts/LoginSso.test.tsx +724 -0
  168. package/Tests/App/AdminDashboard/AdminAuthenticationRequireSso.test.tsx +338 -0
  169. package/Tests/App/AdminDashboard/AdminAuthenticationSsoCardLocales.test.tsx +331 -0
  170. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +47 -33
  171. package/Tests/App/AdminDashboard/GlobalSsoOidcPages.test.tsx +1021 -0
  172. package/Tests/App/Dashboard/AffectedResourcesDisplay.test.tsx +876 -78
  173. package/Tests/App/Dashboard/AffectedResourcesSlo.test.tsx +20 -3
  174. package/Tests/App/Dashboard/CephProxmoxVMwareDocumentationCards.test.tsx +359 -0
  175. package/Tests/App/Dashboard/CephSetupGuide.test.ts +961 -0
  176. package/Tests/App/Dashboard/CloudDocumentationCard.test.tsx +381 -95
  177. package/Tests/App/Dashboard/CloudSetupGuide.test.ts +1463 -0
  178. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +267 -12
  179. package/Tests/App/Dashboard/ContainerSetupGuideCards.test.tsx +345 -0
  180. package/Tests/App/Dashboard/CoreListEmptyStates.test.tsx +501 -0
  181. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +0 -1
  182. package/Tests/App/Dashboard/DatabaseDocumentationCard.test.tsx +400 -0
  183. package/Tests/App/Dashboard/DatabaseDocumentationMarkdown.test.ts +23 -6
  184. package/Tests/App/Dashboard/DatabaseSetupGuide.test.ts +1869 -0
  185. package/Tests/App/Dashboard/DatabaseTelemetryScope.test.ts +44 -0
  186. package/Tests/App/Dashboard/DatabaseTelemetryTabs.test.tsx +50 -9
  187. package/Tests/App/Dashboard/DockerSetupGuide.test.ts +899 -0
  188. package/Tests/App/Dashboard/DockerSwarmSetupGuide.test.ts +964 -0
  189. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +141 -7
  190. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +52 -39
  191. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +7 -1
  192. package/Tests/App/Dashboard/GettingStartedTaskRoutes.test.tsx +331 -0
  193. package/Tests/App/Dashboard/HomeOverviewStatsFirstRun.test.tsx +925 -0
  194. package/Tests/App/Dashboard/HostDocumentationCard.test.tsx +225 -0
  195. package/Tests/App/Dashboard/HostSetupGuide.test.ts +1183 -0
  196. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +69 -45
  197. package/Tests/App/Dashboard/IncidentCreateTemplateCustomFieldSettings.test.tsx +745 -0
  198. package/Tests/App/Dashboard/IncidentCreateTemplateOwners.test.tsx +414 -0
  199. package/Tests/App/Dashboard/IncidentCustomFieldCreateSettingsForm.test.ts +1042 -0
  200. package/Tests/App/Dashboard/IncidentCustomFieldSettingsCard.test.tsx +1816 -0
  201. package/Tests/App/Dashboard/IncidentFormPlan.test.ts +89 -0
  202. package/Tests/App/Dashboard/IncidentFormShareLinkCard.test.tsx +846 -0
  203. package/Tests/App/Dashboard/IncidentFormsPages.test.tsx +1324 -0
  204. package/Tests/App/Dashboard/IncidentTemplateCustomFieldSettings.test.tsx +630 -0
  205. package/Tests/App/Dashboard/IncidentsSideMenu.test.tsx +13 -0
  206. package/Tests/App/Dashboard/IncomingEmailMonitorLinkVerifyHint.test.tsx +104 -0
  207. package/Tests/App/Dashboard/InvestigationConversation.test.tsx +1107 -0
  208. package/Tests/App/Dashboard/InvestigationConversationData.test.ts +546 -0
  209. package/Tests/App/Dashboard/InvestigationEvidenceList.test.tsx +170 -5
  210. package/Tests/App/Dashboard/InvestigationInfrastructureTools.test.tsx +506 -0
  211. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +207 -2
  212. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +729 -34
  213. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +9 -21
  214. package/Tests/App/Dashboard/InvestigationReportView.test.tsx +274 -37
  215. package/Tests/App/Dashboard/InvestigationStatusBadge.test.tsx +130 -0
  216. package/Tests/App/Dashboard/IoTDocumentationCard.test.tsx +218 -0
  217. package/Tests/App/Dashboard/IoTSetupGuide.test.ts +1124 -0
  218. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +20 -6
  219. package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +107 -83
  220. package/Tests/App/Dashboard/KubernetesSetupGuide.test.ts +787 -0
  221. package/Tests/App/Dashboard/MessageQueueBreadcrumbs.test.tsx +228 -0
  222. package/Tests/App/Dashboard/MessageQueueBrokerHealth.test.tsx +1538 -0
  223. package/Tests/App/Dashboard/MessageQueueBrokerHealthMetricChart.test.tsx +969 -0
  224. package/Tests/App/Dashboard/MessageQueueBrokerHealthReads.test.ts +889 -0
  225. package/Tests/App/Dashboard/MessageQueueBrokerMetricsReach.test.ts +236 -0
  226. package/Tests/App/Dashboard/MessageQueueDocumentationCard.test.tsx +479 -0
  227. package/Tests/App/Dashboard/MessageQueueListPages.test.tsx +1232 -0
  228. package/Tests/App/Dashboard/MessageQueueMetricDescriptions.test.ts +244 -0
  229. package/Tests/App/Dashboard/MessageQueueMonitorLink.test.ts +952 -0
  230. package/Tests/App/Dashboard/MessageQueueMonitorLinkMonitorCreate.test.tsx +859 -0
  231. package/Tests/App/Dashboard/MessageQueueOverview.test.tsx +1773 -0
  232. package/Tests/App/Dashboard/MessageQueueOverviewPresentation.test.ts +196 -0
  233. package/Tests/App/Dashboard/MessageQueuePresentation.test.ts +799 -0
  234. package/Tests/App/Dashboard/MessageQueueProducersConsumers.test.tsx +680 -0
  235. package/Tests/App/Dashboard/MessageQueueRoutes.test.tsx +383 -0
  236. package/Tests/App/Dashboard/MessageQueueRulePages.test.tsx +278 -0
  237. package/Tests/App/Dashboard/MessageQueueSetupGuide.test.ts +2778 -0
  238. package/Tests/App/Dashboard/MessageQueueSideMenus.test.tsx +273 -0
  239. package/Tests/App/Dashboard/MessageQueueSpanPopulations.test.ts +930 -0
  240. package/Tests/App/Dashboard/MessageQueueSpanStore.ts +351 -0
  241. package/Tests/App/Dashboard/MessageQueueTelemetryScope.test.ts +375 -0
  242. package/Tests/App/Dashboard/MessageQueueTelemetryScopeTabs.test.tsx +668 -0
  243. package/Tests/App/Dashboard/MessageQueueViewPages.test.tsx +685 -0
  244. package/Tests/App/Dashboard/MonitorAndHomeNotOperationalMenus.test.tsx +342 -0
  245. package/Tests/App/Dashboard/MonitorCreateFirstRunDefaults.test.tsx +623 -0
  246. package/Tests/App/Dashboard/MonitorCreateFromMonitorBackedDevice.test.tsx +442 -0
  247. package/Tests/App/Dashboard/MonitorLogsPageViewSummary.test.tsx +814 -0
  248. package/Tests/App/Dashboard/MonitorSetupCardBodies.test.tsx +246 -0
  249. package/Tests/App/Dashboard/NavigationSearchKeywords.test.tsx +8 -0
  250. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +27 -12
  251. package/Tests/App/Dashboard/PlanGatedPage.test.tsx +292 -0
  252. package/Tests/App/Dashboard/PodmanSetupGuide.test.ts +948 -0
  253. package/Tests/App/Dashboard/ProductOrientation.test.tsx +5 -4
  254. package/Tests/App/Dashboard/ProductSettingsSectionCollapsed.test.tsx +266 -0
  255. package/Tests/App/Dashboard/ProxmoxSetupGuide.test.ts +1318 -0
  256. package/Tests/App/Dashboard/RemediationSuggestionCardDescription.test.tsx +209 -0
  257. package/Tests/App/Dashboard/RemediationSuggestionCardResource.test.tsx +317 -0
  258. package/Tests/App/Dashboard/ResourceAiAccessSettingsUtil.test.ts +921 -0
  259. package/Tests/App/Dashboard/ResourceAiAgentAttentionServerParity.test.ts +555 -0
  260. package/Tests/App/Dashboard/ResourceAiAgentInstall.test.ts +860 -0
  261. package/Tests/App/Dashboard/ResourceAiAgentPage.test.tsx +2010 -0
  262. package/Tests/App/Dashboard/ResourceAiAgentStatus.test.ts +1455 -0
  263. package/Tests/App/Dashboard/ResourceAiInsightsPage.test.tsx +931 -0
  264. package/Tests/App/Dashboard/ResourceAiNavigation.test.tsx +575 -0
  265. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +16 -0
  266. package/Tests/App/Dashboard/ResourceConnectionGuideCard.test.tsx +444 -0
  267. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsInfra.test.tsx +798 -0
  268. package/Tests/App/Dashboard/ResourceConnectionGuideOverviewsPlatforms.test.tsx +717 -0
  269. package/Tests/App/Dashboard/ResourceConnectionGuides.test.ts +981 -0
  270. package/Tests/App/Dashboard/ResourceConnectionState.test.ts +132 -0
  271. package/Tests/App/Dashboard/RumDocumentationCard.test.tsx +293 -0
  272. package/Tests/App/Dashboard/RumSessionReplayRetentionSettings.test.tsx +467 -0
  273. package/Tests/App/Dashboard/RumSetupGuide.test.ts +758 -0
  274. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +38 -7
  275. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +25 -0
  276. package/Tests/App/Dashboard/ServerlessDocumentationCard.test.tsx +254 -0
  277. package/Tests/App/Dashboard/ServerlessSetupGuide.test.ts +1074 -0
  278. package/Tests/App/Dashboard/SetupGuide.test.ts +246 -0
  279. package/Tests/App/Dashboard/SetupGuideCard.test.tsx +756 -0
  280. package/Tests/App/Dashboard/SloListSideMenu.test.tsx +120 -0
  281. package/Tests/App/Dashboard/SsoPages.test.tsx +833 -0
  282. package/Tests/App/Dashboard/TelemetryDocumentation.test.tsx +253 -0
  283. package/Tests/App/Dashboard/TelemetryRetentionShells.test.tsx +730 -0
  284. package/Tests/App/Dashboard/VMwareSetupGuide.test.ts +1033 -0
  285. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +87 -7
  286. package/Tests/Models/DatabaseModels/DatabaseServerModels.test.ts +61 -10
  287. package/Tests/Models/DatabaseModels/IncidentFormModel.test.ts +1250 -0
  288. package/Tests/Models/DatabaseModels/MessageQueueModels.test.ts +1983 -0
  289. package/Tests/Models/DatabaseModels/ResourceAiAccessColumns.test.ts +738 -0
  290. package/Tests/Models/DatabaseModels/ResourceAiAgentModel.test.ts +842 -0
  291. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  292. package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +190 -14
  293. package/Tests/Models/IncidentTemplateCustomFieldSettingsColumn.test.ts +291 -0
  294. package/Tests/Server/API/AIInvestigationConversationAPI.test.ts +412 -0
  295. package/Tests/Server/API/AutoRemediationApproveResourceRound.test.ts +835 -0
  296. package/Tests/Server/API/GlobalConfigLicense.test.ts +38 -9
  297. package/Tests/Server/API/IncidentFormAPI.test.ts +942 -0
  298. package/Tests/Server/API/IncidentFormPublicRoutes.test.ts +1653 -0
  299. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -1
  300. package/Tests/Server/API/ResourceAiAccessAPI.test.ts +2730 -0
  301. package/Tests/Server/API/{SsoProviderListingsEdition.test.ts → SsoProviderListings.test.ts} +164 -110
  302. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +76 -54
  303. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +125 -42
  304. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +36 -10
  305. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +51 -9
  306. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +13 -8
  307. package/Tests/Server/Enterprise/SsoInCommunityEdition.test.ts +540 -0
  308. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  309. package/Tests/Server/Infrastructure/Postgres/AddDatabaseServerTablesMigration.test.ts +60 -0
  310. package/Tests/Server/Infrastructure/Postgres/AddIncidentFormsMigration.test.ts +438 -0
  311. package/Tests/Server/Infrastructure/Postgres/AddResourceAiAgentsMigration.test.ts +659 -0
  312. package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleNotificationChannelsMigration.test.ts +255 -0
  313. package/Tests/Server/Infrastructure/Postgres/MessageQueueTablesMigration.test.ts +637 -0
  314. package/Tests/Server/Infrastructure/SemaphoreMutex.test.ts +31 -0
  315. package/Tests/Server/Middleware/IncidentFormRateLimit.test.ts +1630 -0
  316. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +63 -5
  317. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +103 -5
  318. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +19 -1
  319. package/Tests/Server/Middleware/UserAuthorization.test.ts +16 -17
  320. package/Tests/Server/Middleware/UserAuthorizationSsoEnforcement.test.ts +544 -0
  321. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +37 -8
  322. package/Tests/Server/Services/AutoRemediationResourceRuleEngine.test.ts +1279 -0
  323. package/Tests/Server/Services/DatabaseServerService.test.ts +55 -0
  324. package/Tests/Server/Services/GroupTelemetryUsageExcludeNames.test.ts +299 -0
  325. package/Tests/Server/Services/HostServiceFindOrCreateMemo.test.ts +44 -0
  326. package/Tests/Server/Services/IncidentCreatedFeedTitle.test.ts +212 -0
  327. package/Tests/Server/Services/IncidentCustomFieldDeleteFormQuestions.test.ts +297 -0
  328. package/Tests/Server/Services/IncidentFormOwnersCreatedNotification.test.ts +497 -0
  329. package/Tests/Server/Services/IncidentFormPostgres.test.ts +958 -0
  330. package/Tests/Server/Services/IncidentFormPublicForm.test.ts +1260 -0
  331. package/Tests/Server/Services/IncidentFormPublicSubmission.test.ts +2520 -0
  332. package/Tests/Server/Services/IncidentFormRegistration.test.ts +159 -0
  333. package/Tests/Server/Services/IncidentFormService.test.ts +663 -0
  334. package/Tests/Server/Services/IncidentFormSubmissionService.test.ts +430 -0
  335. package/Tests/Server/Services/IncidentFormSubmissionTemplateBranch.test.ts +473 -0
  336. package/Tests/Server/Services/IncidentGroupingTemplateSubstitution.test.ts +81 -0
  337. package/Tests/Server/Services/IncidentTemplateCustomFieldSettings.test.ts +262 -0
  338. package/Tests/Server/Services/IncidentTemplateOwnersOnDeclare.test.ts +566 -0
  339. package/Tests/Server/Services/IncidentTitleMarkdownSinks.test.ts +640 -0
  340. package/Tests/Server/Services/LlmLogServiceTokenAggregateParams.test.ts +3 -3
  341. package/Tests/Server/Services/MessageQueueOwnerServices.test.ts +440 -0
  342. package/Tests/Server/Services/MessageQueueRegistries.test.ts +577 -0
  343. package/Tests/Server/Services/MessageQueueRuleEngines.test.ts +900 -0
  344. package/Tests/Server/Services/MessageQueueService.test.ts +2210 -0
  345. package/Tests/Server/Services/MessageQueueSqlPostgres.test.ts +1271 -0
  346. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +45 -6
  347. package/Tests/Server/Services/OpenTelemetryResourceRetentionMemo.test.ts +28 -1
  348. package/Tests/Server/Services/OpenTelemetryRetentionOverrideEdition.test.ts +474 -0
  349. package/Tests/Server/Services/OpenTelemetryServiceResolutionCache.test.ts +21 -0
  350. package/Tests/Server/Services/OwnerRowUniqueness.test.ts +3 -0
  351. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +0 -1
  352. package/Tests/Server/Services/RecordingRuleReservedMetricName.test.ts +171 -0
  353. package/Tests/Server/Services/ResourceAiAccessChangeAuthorization.test.ts +256 -0
  354. package/Tests/Server/Services/ResourceAiAccessService.test.ts +1373 -0
  355. package/Tests/Server/Services/ResourceAiAgentJobService.test.ts +375 -0
  356. package/Tests/Server/Services/ResourceAiAgentServiceHelpers.test.ts +1114 -0
  357. package/Tests/Server/Services/ResourceAiAgentServiceLifecycle.test.ts +1050 -0
  358. package/Tests/Server/Services/ResourceAiAgentServiceRegister.test.ts +2251 -0
  359. package/Tests/Server/Services/ResourceAiSettingsCreate.test.ts +373 -0
  360. package/Tests/Server/Services/ResourceAiSettingsPermission.test.ts +1042 -0
  361. package/Tests/Server/Services/ResourceServiceDeleteCleansUpAi.test.ts +319 -0
  362. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +56 -6
  363. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -1
  364. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +105 -0
  365. package/Tests/Server/Services/RunnerJobEnqueueResourceCommand.test.ts +986 -0
  366. package/Tests/Server/Services/RunnerJobResourceCommandLane.test.ts +211 -0
  367. package/Tests/Server/Services/RunnerJobResourceCommandTimeoutAndRedaction.test.ts +352 -0
  368. package/Tests/Server/Services/SsoRequirementReads.test.ts +454 -0
  369. package/Tests/Server/Services/SsoRequirementWrites.test.ts +529 -0
  370. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +3 -3
  371. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +107 -89
  372. package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +1068 -176
  373. package/Tests/Server/Services/TeamComplianceSettingService.test.ts +1962 -200
  374. package/Tests/Server/Services/TelemetryUsageBillingSloExclusion.test.ts +218 -0
  375. package/Tests/Server/TestingUtils/Services/FakeRunnerJobCount.ts +145 -0
  376. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +654 -297
  377. package/Tests/Server/Types/Database/Permissions/RetentionOverrideColumns.test.ts +784 -0
  378. package/Tests/Server/Types/Database/Permissions/SsoScalePlanGate.test.ts +418 -0
  379. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +0 -1
  380. package/Tests/Server/Utils/AI/AIInvestigationEngineRunLimits.test.ts +136 -0
  381. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +15 -14
  382. package/Tests/Server/Utils/AI/AgentContextCompactor.test.ts +351 -0
  383. package/Tests/Server/Utils/AI/ChatAgentRunnerSharedThread.test.ts +842 -0
  384. package/Tests/Server/Utils/AI/ChatRunCancellation.test.ts +195 -0
  385. package/Tests/Server/Utils/AI/CodeFixReadiness.test.ts +10 -57
  386. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +20 -24
  387. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +7 -30
  388. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +225 -29
  389. package/Tests/Server/Utils/AI/InvestigationInfrastructureAccessWiring.test.ts +694 -0
  390. package/Tests/Server/Utils/AI/InvestigationInfrastructureReport.test.ts +721 -0
  391. package/Tests/Server/Utils/AI/InvestigationThread.test.ts +580 -0
  392. package/Tests/Server/Utils/AI/InvestigationThreadService.test.ts +801 -0
  393. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +525 -43
  394. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +4 -2
  395. package/Tests/Server/Utils/AI/LLMServiceUnreachableProvider.test.ts +435 -0
  396. package/Tests/Server/Utils/AI/ObservabilityAssistantLimits.test.ts +462 -0
  397. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +94 -1
  398. package/Tests/Server/Utils/AI/RemediationCommandToolsResource.test.ts +1530 -0
  399. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +14 -25
  400. package/Tests/Server/Utils/AI/RemediationExecutionRunnerResourceMode.test.ts +1251 -0
  401. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +117 -0
  402. package/Tests/Server/Utils/AI/RemediationResourceCopyParity.test.ts +463 -0
  403. package/Tests/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.test.ts +1004 -0
  404. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAccessContext.test.ts +266 -0
  405. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.test.ts +1220 -0
  406. package/Tests/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.test.ts +569 -0
  407. package/Tests/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.test.ts +834 -0
  408. package/Tests/Server/Utils/AI/ToolOutputPager.test.ts +382 -0
  409. package/Tests/Server/Utils/AI/ToolResultSerializer.test.ts +23 -4
  410. package/Tests/Server/Utils/AI/Toolbox/LogTools.test.ts +25 -6
  411. package/Tests/Server/Utils/AI/Toolbox/Serializer.test.ts +14 -3
  412. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorResource.test.ts +717 -0
  413. package/Tests/Server/Utils/AutoRemediation/RemediationVerifierResourceFollowUp.test.ts +338 -0
  414. package/Tests/Server/Utils/EditionEnforcement.test.ts +107 -147
  415. package/Tests/Server/Utils/Monitor/Criteria/SessionReplayBudgetTemplateCriteria.test.ts +422 -0
  416. package/Tests/Server/Utils/{CommunityEditionSsoReport.test.ts → RelaxedScimTeamLocksReport.test.ts} +212 -208
  417. package/Tests/Server/Utils/SameOriginRequest.test.ts +372 -0
  418. package/Tests/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.test.ts +1647 -0
  419. package/Tests/Server/Utils/SessionReplay/SessionReplayUsage.test.ts +143 -1
  420. package/Tests/Server/Utils/Telemetry/EntityRegistry.test.ts +20 -0
  421. package/Tests/Server/Utils/Telemetry/MessageQueueDiscovery.test.ts +2590 -0
  422. package/Tests/Server/Utils/Telemetry/MessageQueueSpanQueryTwin.ts +246 -0
  423. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +23 -0
  424. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +33 -3
  425. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsAccountNotLinked.test.ts +1093 -0
  426. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.test.ts +1049 -0
  427. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.test.ts +1676 -0
  428. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCards.test.ts +2884 -0
  429. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.test.ts +2490 -0
  430. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmit.test.ts +2293 -0
  431. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateSubmitServerTimezone.test.ts +386 -0
  432. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.test.ts +1477 -0
  433. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.test.ts +1967 -0
  434. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsStripHtmlTags.test.ts +92 -0
  435. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsSubmittedFormRemoval.test.ts +1819 -0
  436. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.test.ts +1033 -0
  437. package/Tests/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezoneServerZone.test.ts +610 -0
  438. package/Tests/Server/Utils/Workspace/MicrosoftTeamsBotMessageHandling.test.ts +2610 -0
  439. package/Tests/Server/Utils/Workspace/MicrosoftTeamsCreateCommandsEndToEnd.test.ts +4672 -0
  440. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +190 -65
  441. package/Tests/Types/AI/AIAgentRunLimits.test.ts +255 -0
  442. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +10 -4
  443. package/Tests/Types/AutoRemediation/AiRemediationCommandPlanResourceCommand.test.ts +305 -0
  444. package/Tests/Types/Code/JsonSyntax.test.ts +1300 -0
  445. package/Tests/Types/CustomField/CustomFieldCreateSettings.test.ts +1113 -0
  446. package/Tests/Types/CustomField/CustomFieldMappingCatalog.test.ts +91 -0
  447. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +30 -0
  448. package/Tests/Types/Incident/IncidentFormIpAllowlist.test.ts +227 -0
  449. package/Tests/Types/Incident/IncidentFormPublic.test.ts +1916 -0
  450. package/Tests/Types/MessageQueue/MessageQueueEntityKey.test.ts +916 -0
  451. package/Tests/Types/MessageQueue/MessageQueueIdentity.test.ts +567 -0
  452. package/Tests/Types/MessageQueue/MessageQueueManualIdentity.test.ts +686 -0
  453. package/Tests/Types/MessageQueue/MessageQueueMetricCatalog.test.ts +1726 -0
  454. package/Tests/Types/MessageQueue/MessageQueueMetricResolution.test.ts +1758 -0
  455. package/Tests/Types/MessageQueue/MessagingInstrumentationFixtures.test.ts +4686 -0
  456. package/Tests/Types/MessageQueue/MessagingSystem.test.ts +840 -0
  457. package/Tests/Types/MessageQueue/MessagingTelemetryFixtures.ts +3287 -0
  458. package/Tests/Types/MessageQueue/MessagingTelemetryResolver.test.ts +2966 -0
  459. package/Tests/Types/Monitor/MessageQueueAlertTemplates.test.ts +5401 -0
  460. package/Tests/Types/Monitor/MetricEngineFold.ts +154 -0
  461. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +277 -13
  462. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationUtil.test.ts +113 -0
  463. package/Tests/Types/Monitor/RumAlertTemplates.test.ts +773 -2
  464. package/Tests/Types/ResourceAiAgent/AiResourceType.test.ts +419 -0
  465. package/Tests/Types/ResourceAiAgent/ResourceAiAccess.test.ts +519 -0
  466. package/Tests/Types/Runbook/RunbookStepType.test.ts +147 -8
  467. package/Tests/Types/Team/ComplianceRule.test.ts +588 -37
  468. package/Tests/Types/Team/TeamComplianceStatus.test.ts +64 -11
  469. package/Tests/Types/XML.test.ts +51 -0
  470. package/Tests/UI/Components/CodeEditor/CodeEditor.test.tsx +2362 -0
  471. package/Tests/UI/Components/CodeEditor/CodeEditorCommands.test.ts +810 -0
  472. package/Tests/UI/Components/CodeEditor/CodeEditorHighlight.test.ts +338 -0
  473. package/Tests/UI/Components/CodeEditor/CodeEditorLanguages.test.ts +222 -0
  474. package/Tests/UI/Components/CodeEditor/CodeEditorStyles.test.ts +807 -0
  475. package/Tests/UI/Components/CodeEditor/NoMonaco.test.ts +245 -0
  476. package/Tests/UI/Components/CodeEditor/YamlEditor.test.tsx +729 -0
  477. package/Tests/UI/Components/CopyTextButton.test.tsx +76 -0
  478. package/Tests/UI/Components/EditionLabelLapseCopy.ts +51 -14
  479. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +131 -23
  480. package/Tests/UI/Components/ErrorMessageAction.test.tsx +142 -0
  481. package/Tests/UI/Components/FacetSidebarInScope.test.tsx +459 -0
  482. package/Tests/UI/Components/FacetValuesInScope.test.ts +270 -0
  483. package/Tests/UI/Components/Forms/FormFieldCodeEditors.test.tsx +294 -0
  484. package/Tests/UI/Components/Forms/FormFieldMarkdown.test.tsx +126 -0
  485. package/Tests/UI/Components/Forms/FormFieldYaml.test.tsx +22 -75
  486. package/Tests/UI/Components/Forms/ModelFormOnBeforeCreateMiscData.test.tsx +254 -0
  487. package/Tests/UI/Components/Icon.test.tsx +32 -0
  488. package/Tests/UI/Components/Input.test.tsx +31 -0
  489. package/Tests/UI/Components/LockedFilterChipScope.test.tsx +501 -0
  490. package/Tests/UI/Components/MarkdownConverters.test.ts +253 -1
  491. package/Tests/UI/Components/MarkdownEditor.test.tsx +2785 -2
  492. package/Tests/UI/Components/MarkdownEditorHistory.test.ts +243 -0
  493. package/Tests/UI/Components/MarkdownListEditing.test.ts +1118 -0
  494. package/Tests/UI/Components/MarkdownPaste.test.ts +1180 -0
  495. package/Tests/UI/Components/MarkdownViewerCopy.test.tsx +466 -0
  496. package/Tests/UI/Components/MarkdownVisualEditing.test.ts +1089 -0
  497. package/Tests/UI/Components/ModelTable/BaseModelTableEmptyStateAction.test.tsx +623 -0
  498. package/Tests/UI/Components/ResetObjectID.test.tsx +282 -0
  499. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  500. package/Tests/UI/Components/Table/EmptyTableMessage.test.ts +439 -0
  501. package/Tests/UI/Components/Table/TableEmptyState.test.tsx +352 -0
  502. package/Tests/UI/Components/TableRowMobileTitles.test.tsx +78 -0
  503. package/Tests/UI/Components/TextArea.test.tsx +19 -0
  504. package/Tests/UI/Components/Workflow/ModelColumnEditor.render.test.tsx +12 -29
  505. package/Tests/UI/Components/fixtures/MarkdownPasteFixtures.ts +460 -0
  506. package/Tests/UI/EsbuildConfig.test.ts +115 -39
  507. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +4 -4
  508. package/Tests/UI/Monitor/MonitorLogSummaryRender.test.tsx +377 -0
  509. package/Tests/UI/Rum/RecordingHealthDashboard.test.tsx +769 -1
  510. package/Tests/UI/Utils/Breadcrumb/fixtures/RealBreadcrumbTrails.ts +81 -1
  511. package/Tests/UI/Utils/Breadcrumb/fixtures/RealRoutePatterns.ts +17 -0
  512. package/Tests/Utils/AiRemediation/Resource/CephCommandPolicy.test.ts +1653 -0
  513. package/Tests/Utils/AiRemediation/Resource/CephOutputRedaction.test.ts +204 -0
  514. package/Tests/Utils/AiRemediation/Resource/DatabaseCommandPolicy.test.ts +1077 -0
  515. package/Tests/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.test.ts +558 -0
  516. package/Tests/Utils/AiRemediation/Resource/DatabaseQueryRedactor.test.ts +834 -0
  517. package/Tests/Utils/AiRemediation/Resource/DockerCliGrammar.test.ts +747 -0
  518. package/Tests/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.test.ts +1259 -0
  519. package/Tests/Utils/AiRemediation/Resource/DockerOutputRedaction.test.ts +386 -0
  520. package/Tests/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.test.ts +782 -0
  521. package/Tests/Utils/AiRemediation/Resource/GovcCommandPolicy.test.ts +2259 -0
  522. package/Tests/Utils/AiRemediation/Resource/HostCommandPolicy.test.ts +2019 -0
  523. package/Tests/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.test.ts +2497 -0
  524. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicy.test.ts +1305 -0
  525. package/Tests/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.test.ts +585 -0
  526. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactor.test.ts +334 -0
  527. package/Tests/Utils/AiRemediation/Resource/ResourceOutputRedactorCopyParity.test.ts +98 -0
  528. package/Tests/Utils/AiRemediation/Resource/ResourcePolicyImportClosure.test.ts +391 -0
  529. package/Tests/Utils/AiRemediation/ResourceAiAgentPolicyCopyParity.test.ts +497 -0
  530. package/Tests/Utils/LabelRuleImportExport.test.ts +5 -0
  531. package/Tests/Utils/Markdown/DashboardMarkdownRenderer.ts +81 -0
  532. package/Tests/Utils/Markdown/UntrustedMarkdown.test.ts +1339 -0
  533. package/Tests/Utils/Monitor/MonitorLogSummaryUtil.test.ts +862 -0
  534. package/Tests/Utils/SessionReplay/SessionReplayBudgetMetricType.test.ts +383 -0
  535. package/Types/AI/AIAgentRunLimits.ts +146 -0
  536. package/Types/AI/ResourceAiAccessApi.ts +140 -0
  537. package/Types/AI/ResourceAiAccessPermissions.ts +126 -0
  538. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +183 -2
  539. package/Types/Code/CodeType.ts +2 -0
  540. package/Types/Code/JsonSyntax.ts +923 -0
  541. package/Types/CustomField/CustomFieldCreateSettings.ts +549 -0
  542. package/Types/CustomField/CustomFieldMappingCatalog.ts +77 -0
  543. package/Types/CustomField/CustomFieldValueValidator.ts +10 -7
  544. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +1 -1
  545. package/Types/Icon/IconProp.ts +2 -0
  546. package/Types/Incident/IncidentFormIpAllowlist.ts +206 -0
  547. package/Types/Incident/IncidentFormPublic.ts +1145 -0
  548. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +10 -3
  549. package/Types/MessageQueue/MessageQueueIdentity.ts +256 -0
  550. package/Types/MessageQueue/MessageQueueManualIdentity.ts +325 -0
  551. package/Types/MessageQueue/MessageQueueMetricCatalog.ts +1357 -0
  552. package/Types/MessageQueue/MessagingSystem.ts +518 -0
  553. package/Types/MessageQueue/MessagingTelemetryResolver.ts +2311 -0
  554. package/Types/Monitor/MessageQueueAlertTemplates.ts +2128 -0
  555. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +55 -22
  556. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +35 -3
  557. package/Types/Monitor/RumAlertTemplates.ts +351 -4
  558. package/Types/Permission.ts +310 -0
  559. package/Types/ResourceAiAgent/AiResourceType.ts +310 -0
  560. package/Types/ResourceAiAgent/ResourceAiAccess.ts +580 -0
  561. package/Types/Rules/RuleCriteriaFieldRegistry.ts +12 -0
  562. package/Types/Rules/RuleRun.ts +4 -0
  563. package/Types/Rum/SessionReplayBudgetMetricType.ts +47 -0
  564. package/Types/Runbook/RunbookStepType.ts +29 -0
  565. package/Types/Team/ComplianceNotificationChannel.ts +4 -3
  566. package/Types/Team/ComplianceRule.ts +71 -18
  567. package/Types/Team/ComplianceRuleType.ts +2 -2
  568. package/Types/Team/TeamComplianceStatus.ts +6 -2
  569. package/Types/Telemetry/EntityType.ts +16 -0
  570. package/Types/Telemetry/LockedFilterDetail.ts +22 -0
  571. package/Types/Telemetry/TelemetryIngestSurface.ts +14 -2
  572. package/Types/XML.ts +26 -0
  573. package/UI/Components/CodeEditor/CodeEditor.css +379 -0
  574. package/UI/Components/CodeEditor/CodeEditor.tsx +1128 -294
  575. package/UI/Components/CodeEditor/CodeEditorCommands.ts +774 -0
  576. package/UI/Components/CodeEditor/CodeEditorHighlight.ts +106 -0
  577. package/UI/Components/CodeEditor/CodeEditorLanguages.ts +164 -0
  578. package/UI/Components/CodeEditor/YamlEditor.tsx +28 -326
  579. package/UI/Components/CopyTextButton/CopyTextButton.tsx +5 -1
  580. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +6 -25
  581. package/UI/Components/EditionLabel/EditionLabel.tsx +14 -13
  582. package/UI/Components/ErrorMessage/ErrorMessage.tsx +11 -1
  583. package/UI/Components/Forms/Fields/FormField.tsx +8 -0
  584. package/UI/Components/Forms/Types/Field.ts +8 -0
  585. package/UI/Components/Icon/Icon.tsx +18 -0
  586. package/UI/Components/Input/Input.tsx +11 -4
  587. package/UI/Components/LogsViewer/LogsViewer.tsx +4 -0
  588. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +21 -3
  589. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  590. package/UI/Components/Markdown.tsx/MarkdownEditor.tsx +877 -79
  591. package/UI/Components/Markdown.tsx/MarkdownEditorHistory.ts +284 -0
  592. package/UI/Components/Markdown.tsx/MarkdownListEditing.ts +1362 -0
  593. package/UI/Components/Markdown.tsx/MarkdownPaste.ts +1326 -0
  594. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +106 -10
  595. package/UI/Components/Markdown.tsx/MarkdownVisualEditing.ts +1032 -0
  596. package/UI/Components/ModelTable/BaseModelTable.tsx +85 -7
  597. package/UI/Components/ResetObjectID/ResetObjectID.tsx +35 -9
  598. package/UI/Components/Table/EmptyTableMessage.ts +81 -0
  599. package/UI/Components/Table/Table.tsx +50 -21
  600. package/UI/Components/Table/TableRow.tsx +9 -1
  601. package/UI/Components/TelemetryViewer/FacetVisibility.ts +97 -2
  602. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +13 -0
  603. package/UI/Components/TelemetryViewer/components/LockedFilterChip.tsx +214 -7
  604. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +21 -3
  605. package/UI/Components/TextArea/TextArea.tsx +9 -2
  606. package/UI/Components/Workflow/ModelFieldPicker.tsx +10 -12
  607. package/UI/Styles/Theme.css +8 -0
  608. package/UI/esbuild-config.js +2 -32
  609. package/Utils/AI/InvestigationReport.ts +121 -15
  610. package/Utils/AiRemediation/Resource/CephCommandPolicy.ts +1936 -0
  611. package/Utils/AiRemediation/Resource/DatabaseCommandPolicy.ts +166 -0
  612. package/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.ts +1532 -0
  613. package/Utils/AiRemediation/Resource/DatabaseQueryRedactor.ts +1394 -0
  614. package/Utils/AiRemediation/Resource/DockerCliGrammar.ts +1839 -0
  615. package/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.ts +490 -0
  616. package/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.ts +687 -0
  617. package/Utils/AiRemediation/Resource/GovcCommandPolicy.ts +2096 -0
  618. package/Utils/AiRemediation/Resource/HostCommandPolicy.ts +2982 -0
  619. package/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.ts +1679 -0
  620. package/Utils/AiRemediation/Resource/ResourceCommandPolicy.ts +851 -0
  621. package/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.ts +593 -0
  622. package/Utils/AiRemediation/Resource/ResourceOutputRedactor.ts +2812 -0
  623. package/Utils/LabelRuleImportExport.ts +2 -0
  624. package/Utils/Markdown/UntrustedMarkdown.ts +1513 -0
  625. package/Utils/Monitor/IncomingEmailMonitorRequestUtil.ts +41 -0
  626. package/Utils/Monitor/MonitorLogSummaryUtil.ts +212 -0
  627. package/Utils/SessionReplay/SessionReplayBudgetMetricType.ts +184 -0
  628. package/Utils/Telemetry/EntityKey.ts +48 -0
  629. package/build/dist/Models/DatabaseModels/AIConversation.js +125 -1
  630. package/build/dist/Models/DatabaseModels/AIConversation.js.map +1 -1
  631. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  632. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  633. package/build/dist/Models/DatabaseModels/CephCluster.js +231 -0
  634. package/build/dist/Models/DatabaseModels/CephCluster.js.map +1 -1
  635. package/build/dist/Models/DatabaseModels/CloudResource.js +12 -0
  636. package/build/dist/Models/DatabaseModels/CloudResource.js.map +1 -1
  637. package/build/dist/Models/DatabaseModels/DatabaseServer.js +231 -0
  638. package/build/dist/Models/DatabaseModels/DatabaseServer.js.map +1 -1
  639. package/build/dist/Models/DatabaseModels/DockerHost.js +231 -0
  640. package/build/dist/Models/DatabaseModels/DockerHost.js.map +1 -1
  641. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js +231 -0
  642. package/build/dist/Models/DatabaseModels/DockerSwarmCluster.js.map +1 -1
  643. package/build/dist/Models/DatabaseModels/GlobalConfig.js +1 -1
  644. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  645. package/build/dist/Models/DatabaseModels/GlobalOidc.js +0 -4
  646. package/build/dist/Models/DatabaseModels/GlobalOidc.js.map +1 -1
  647. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js +0 -4
  648. package/build/dist/Models/DatabaseModels/GlobalOidcProject.js.map +1 -1
  649. package/build/dist/Models/DatabaseModels/GlobalSso.js +0 -4
  650. package/build/dist/Models/DatabaseModels/GlobalSso.js.map +1 -1
  651. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js +0 -4
  652. package/build/dist/Models/DatabaseModels/GlobalSsoProject.js.map +1 -1
  653. package/build/dist/Models/DatabaseModels/Host.js +231 -0
  654. package/build/dist/Models/DatabaseModels/Host.js.map +1 -1
  655. package/build/dist/Models/DatabaseModels/IncidentForm.js +605 -0
  656. package/build/dist/Models/DatabaseModels/IncidentForm.js.map +1 -0
  657. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js +299 -0
  658. package/build/dist/Models/DatabaseModels/IncidentFormSubmission.js.map +1 -0
  659. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +60 -0
  660. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  661. package/build/dist/Models/DatabaseModels/Index.js +16 -0
  662. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  663. package/build/dist/Models/DatabaseModels/IoTFleet.js +12 -0
  664. package/build/dist/Models/DatabaseModels/IoTFleet.js.map +1 -1
  665. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +12 -0
  666. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  667. package/build/dist/Models/DatabaseModels/MessageQueue.js +1106 -0
  668. package/build/dist/Models/DatabaseModels/MessageQueue.js.map +1 -0
  669. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js +562 -0
  670. package/build/dist/Models/DatabaseModels/MessageQueueLabelRule.js.map +1 -0
  671. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js +643 -0
  672. package/build/dist/Models/DatabaseModels/MessageQueueOwnerRule.js.map +1 -0
  673. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js +506 -0
  674. package/build/dist/Models/DatabaseModels/MessageQueueOwnerTeam.js.map +1 -0
  675. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js +505 -0
  676. package/build/dist/Models/DatabaseModels/MessageQueueOwnerUser.js.map +1 -0
  677. package/build/dist/Models/DatabaseModels/PodmanHost.js +231 -0
  678. package/build/dist/Models/DatabaseModels/PodmanHost.js.map +1 -1
  679. package/build/dist/Models/DatabaseModels/Project.js +61 -0
  680. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  681. package/build/dist/Models/DatabaseModels/ProjectOidc.js +0 -4
  682. package/build/dist/Models/DatabaseModels/ProjectOidc.js.map +1 -1
  683. package/build/dist/Models/DatabaseModels/ProjectSso.js +0 -4
  684. package/build/dist/Models/DatabaseModels/ProjectSso.js.map +1 -1
  685. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js +231 -0
  686. package/build/dist/Models/DatabaseModels/ProxmoxCluster.js.map +1 -1
  687. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js +439 -0
  688. package/build/dist/Models/DatabaseModels/ResourceAiAgent.js.map +1 -0
  689. package/build/dist/Models/DatabaseModels/RumApplication.js +12 -0
  690. package/build/dist/Models/DatabaseModels/RumApplication.js.map +1 -1
  691. package/build/dist/Models/DatabaseModels/RunnerJob.js +145 -0
  692. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  693. package/build/dist/Models/DatabaseModels/ServerlessFunction.js +12 -0
  694. package/build/dist/Models/DatabaseModels/ServerlessFunction.js.map +1 -1
  695. package/build/dist/Models/DatabaseModels/Service.js +12 -0
  696. package/build/dist/Models/DatabaseModels/Service.js.map +1 -1
  697. package/build/dist/Models/DatabaseModels/StatusPageOidc.js +0 -4
  698. package/build/dist/Models/DatabaseModels/StatusPageOidc.js.map +1 -1
  699. package/build/dist/Models/DatabaseModels/StatusPageSso.js +0 -4
  700. package/build/dist/Models/DatabaseModels/StatusPageSso.js.map +1 -1
  701. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +49 -3
  702. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
  703. package/build/dist/Models/DatabaseModels/VMwareVCenter.js +231 -0
  704. package/build/dist/Models/DatabaseModels/VMwareVCenter.js.map +1 -1
  705. package/build/dist/Server/API/AIChatAPI.js +9 -103
  706. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  707. package/build/dist/Server/API/AIInvestigationAPI.js +3 -3
  708. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  709. package/build/dist/Server/API/AIInvestigationConversationAPI.js +162 -0
  710. package/build/dist/Server/API/AIInvestigationConversationAPI.js.map +1 -0
  711. package/build/dist/Server/API/AutoRemediationAPI.js +231 -1
  712. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  713. package/build/dist/Server/API/IncidentFormAPI.js +245 -0
  714. package/build/dist/Server/API/IncidentFormAPI.js.map +1 -0
  715. package/build/dist/Server/API/ProjectOIDC.js +16 -24
  716. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  717. package/build/dist/Server/API/ProjectSSO.js +16 -24
  718. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  719. package/build/dist/Server/API/ResourceAiAccessAPI.js +1119 -0
  720. package/build/dist/Server/API/ResourceAiAccessAPI.js.map +1 -0
  721. package/build/dist/Server/API/StatusPageAPI.js +42 -75
  722. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  723. package/build/dist/Server/Enterprise/EnterpriseEdition.js +79 -25
  724. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -1
  725. package/build/dist/Server/Enterprise/EnterpriseFeature.js +24 -3
  726. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -1
  727. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +1 -1
  728. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -1
  729. package/build/dist/Server/EnvironmentConfig.js +1 -1
  730. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js +168 -0
  731. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796300000000-AddResourceAiAgents.js.map +1 -0
  732. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js +63 -0
  733. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796400000000-AddIncidentForms.js.map +1 -0
  734. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js +41 -0
  735. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796500000000-AddTeamComplianceRuleNotificationChannels.js.map +1 -0
  736. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js +40 -0
  737. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796600000000-AddAIInvestigationConversationAndTimeLimits.js.map +1 -0
  738. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js +183 -0
  739. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796700000000-AddMessageQueueTables.js.map +1 -0
  740. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  741. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  742. package/build/dist/Server/Infrastructure/Semaphore.js +6 -0
  743. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  744. package/build/dist/Server/Middleware/IncidentFormRateLimit.js +559 -0
  745. package/build/dist/Server/Middleware/IncidentFormRateLimit.js.map +1 -0
  746. package/build/dist/Server/Middleware/TelemetryIngest.js +12 -5
  747. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  748. package/build/dist/Server/Middleware/UserAuthorization.js +11 -30
  749. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  750. package/build/dist/Server/Services/AIService.js +10 -13
  751. package/build/dist/Server/Services/AIService.js.map +1 -1
  752. package/build/dist/Server/Services/AnalyticsDatabaseService.js +26 -1
  753. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  754. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +601 -3
  755. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  756. package/build/dist/Server/Services/CephClusterService.js +104 -0
  757. package/build/dist/Server/Services/CephClusterService.js.map +1 -1
  758. package/build/dist/Server/Services/DatabaseServerService.js +99 -0
  759. package/build/dist/Server/Services/DatabaseServerService.js.map +1 -1
  760. package/build/dist/Server/Services/DockerHostService.js +104 -0
  761. package/build/dist/Server/Services/DockerHostService.js.map +1 -1
  762. package/build/dist/Server/Services/DockerSwarmClusterService.js +104 -0
  763. package/build/dist/Server/Services/DockerSwarmClusterService.js.map +1 -1
  764. package/build/dist/Server/Services/HostService.js +114 -2
  765. package/build/dist/Server/Services/HostService.js.map +1 -1
  766. package/build/dist/Server/Services/IncidentCustomFieldService.js +83 -0
  767. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  768. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +8 -4
  769. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  770. package/build/dist/Server/Services/IncidentEpisodeService.js +10 -1
  771. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  772. package/build/dist/Server/Services/IncidentFormService.js +1202 -0
  773. package/build/dist/Server/Services/IncidentFormService.js.map +1 -0
  774. package/build/dist/Server/Services/IncidentFormSubmissionService.js +91 -0
  775. package/build/dist/Server/Services/IncidentFormSubmissionService.js.map +1 -0
  776. package/build/dist/Server/Services/IncidentGroupingEngineService.js +20 -8
  777. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  778. package/build/dist/Server/Services/IncidentService.js +106 -4
  779. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  780. package/build/dist/Server/Services/IncidentTemplateService.js +18 -0
  781. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  782. package/build/dist/Server/Services/Index.js +14 -0
  783. package/build/dist/Server/Services/Index.js.map +1 -1
  784. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js +262 -0
  785. package/build/dist/Server/Services/MessageQueueLabelRuleEngineService.js.map +1 -0
  786. package/build/dist/Server/Services/MessageQueueLabelRuleService.js +13 -0
  787. package/build/dist/Server/Services/MessageQueueLabelRuleService.js.map +1 -0
  788. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js +334 -0
  789. package/build/dist/Server/Services/MessageQueueOwnerRuleEngineService.js.map +1 -0
  790. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js +13 -0
  791. package/build/dist/Server/Services/MessageQueueOwnerRuleService.js.map +1 -0
  792. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js +62 -0
  793. package/build/dist/Server/Services/MessageQueueOwnerTeamService.js.map +1 -0
  794. package/build/dist/Server/Services/MessageQueueOwnerUserService.js +62 -0
  795. package/build/dist/Server/Services/MessageQueueOwnerUserService.js.map +1 -0
  796. package/build/dist/Server/Services/MessageQueueService.js +1140 -0
  797. package/build/dist/Server/Services/MessageQueueService.js.map +1 -0
  798. package/build/dist/Server/Services/MetricRecordingRuleService.js +46 -0
  799. package/build/dist/Server/Services/MetricRecordingRuleService.js.map +1 -1
  800. package/build/dist/Server/Services/OpenTelemetryIngestService.js +25 -4
  801. package/build/dist/Server/Services/OpenTelemetryIngestService.js.map +1 -1
  802. package/build/dist/Server/Services/PodmanHostService.js +104 -0
  803. package/build/dist/Server/Services/PodmanHostService.js.map +1 -1
  804. package/build/dist/Server/Services/ProjectService.js +0 -54
  805. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  806. package/build/dist/Server/Services/ProxmoxClusterService.js +104 -0
  807. package/build/dist/Server/Services/ProxmoxClusterService.js.map +1 -1
  808. package/build/dist/Server/Services/ResourceAiAccessService.js +1028 -0
  809. package/build/dist/Server/Services/ResourceAiAccessService.js.map +1 -0
  810. package/build/dist/Server/Services/ResourceAiAgentJobService.js +173 -0
  811. package/build/dist/Server/Services/ResourceAiAgentJobService.js.map +1 -0
  812. package/build/dist/Server/Services/ResourceAiAgentService.js +1687 -0
  813. package/build/dist/Server/Services/ResourceAiAgentService.js.map +1 -0
  814. package/build/dist/Server/Services/RunnerJobService.js +344 -5
  815. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  816. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -4
  817. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  818. package/build/dist/Server/Services/StatusPageService.js +0 -46
  819. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  820. package/build/dist/Server/Services/TeamComplianceSettingService.js +120 -31
  821. package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
  822. package/build/dist/Server/Services/TelemetryUsageBillingService.js +26 -0
  823. package/build/dist/Server/Services/TelemetryUsageBillingService.js.map +1 -1
  824. package/build/dist/Server/Services/TraceRecordingRuleService.js +37 -0
  825. package/build/dist/Server/Services/TraceRecordingRuleService.js.map +1 -1
  826. package/build/dist/Server/Services/UserNotificationRuleService.js +8 -1
  827. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  828. package/build/dist/Server/Services/VMwareVCenterService.js +104 -0
  829. package/build/dist/Server/Services/VMwareVCenterService.js.map +1 -1
  830. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js +12 -3
  831. package/build/dist/Server/Services/WorkspaceNotificationSummaryService.js.map +1 -1
  832. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +6 -3
  833. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  834. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +109 -37
  835. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  836. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js +16 -0
  837. package/build/dist/Server/Types/Database/Permissions/OwnerTableRegistry.js.map +1 -1
  838. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +3 -3
  839. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +9 -6
  840. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  841. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js +128 -0
  842. package/build/dist/Server/Utils/AI/Chat/AgentContextCompactor.js.map +1 -0
  843. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js +192 -50
  844. package/build/dist/Server/Utils/AI/Chat/ChatAgentRunner.js.map +1 -1
  845. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js +133 -0
  846. package/build/dist/Server/Utils/AI/Chat/ChatRunCancellation.js.map +1 -0
  847. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +53 -13
  848. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  849. package/build/dist/Server/Utils/AI/Chat/ObservabilityChatPrompt.js +1 -1
  850. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js +206 -0
  851. package/build/dist/Server/Utils/AI/Chat/ToolOutputPager.js.map +1 -0
  852. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +53 -26
  853. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
  854. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +4 -2
  855. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
  856. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +1 -29
  857. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  858. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +24 -24
  859. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  860. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1036 -32
  861. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  862. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +661 -41
  863. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  864. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +21 -1
  865. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  866. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js +354 -0
  867. package/build/dist/Server/Utils/AI/ResourceAccess/InfrastructureInvestigationToolkit.js.map +1 -0
  868. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js +160 -0
  869. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessContext.js.map +1 -0
  870. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js +33 -0
  871. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAccessToolNames.js.map +1 -0
  872. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js +640 -0
  873. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiAccessSettings.js.map +1 -0
  874. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js +226 -0
  875. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceAiDeleteCleanup.js.map +1 -0
  876. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js +602 -0
  877. package/build/dist/Server/Utils/AI/ResourceAccess/ResourceCommandJobRunner.js.map +1 -0
  878. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +90 -14
  879. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  880. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +73 -10
  881. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  882. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +73 -10
  883. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  884. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +15 -18
  885. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  886. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js +412 -0
  887. package/build/dist/Server/Utils/AI/SRE/InvestigationThread.js.map +1 -0
  888. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js +495 -0
  889. package/build/dist/Server/Utils/AI/SRE/InvestigationThreadService.js.map +1 -0
  890. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js +10 -3
  891. package/build/dist/Server/Utils/AI/Toolbox/Serializer.js.map +1 -1
  892. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +290 -13
  893. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  894. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +29 -1
  895. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  896. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +9 -1
  897. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  898. package/build/dist/Server/Utils/EditionEnforcement.js +20 -158
  899. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -1
  900. package/build/dist/Server/Utils/LLM/LLMService.js +193 -54
  901. package/build/dist/Server/Utils/LLM/LLMService.js.map +1 -1
  902. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js +160 -0
  903. package/build/dist/Server/Utils/RelaxedScimTeamLocksReport.js.map +1 -0
  904. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +25 -0
  905. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  906. package/build/dist/Server/Utils/SameOriginRequest.js +151 -0
  907. package/build/dist/Server/Utils/SameOriginRequest.js.map +1 -0
  908. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js +627 -0
  909. package/build/dist/Server/Utils/SessionReplay/SessionReplayBudgetMetrics.js.map +1 -0
  910. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js +60 -5
  911. package/build/dist/Server/Utils/SessionReplay/SessionReplayUsage.js.map +1 -1
  912. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +2 -0
  913. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -1
  914. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js +4 -1
  915. package/build/dist/Server/Utils/Telemetry/EntityRegistry.js.map +1 -1
  916. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js +1015 -0
  917. package/build/dist/Server/Utils/Telemetry/MessageQueueDiscovery.js.map +1 -0
  918. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js +4 -1
  919. package/build/dist/Server/Utils/Telemetry/ResourceEntityFilter.js.map +1 -1
  920. package/build/dist/Server/Utils/VendorAssets.js +3 -3
  921. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +19 -15
  922. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  923. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +19 -15
  924. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  925. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js +17 -1
  926. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Auth.js.map +1 -1
  927. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +186 -210
  928. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  929. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +22 -16
  930. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  931. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +233 -167
  932. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  933. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +273 -111
  934. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  935. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js +129 -0
  936. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsActivityDeduplicator.js.map +1 -0
  937. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js +266 -0
  938. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices.js.map +1 -0
  939. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js +258 -0
  940. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCreateCommands.js.map +1 -0
  941. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js +104 -0
  942. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize.js.map +1 -0
  943. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js +183 -0
  944. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsReplies.js.map +1 -0
  945. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js +123 -0
  946. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsTimezone.js.map +1 -0
  947. package/build/dist/Types/AI/AIAgentRunLimits.js +91 -0
  948. package/build/dist/Types/AI/AIAgentRunLimits.js.map +1 -0
  949. package/build/dist/Types/AI/ResourceAiAccessApi.js +30 -0
  950. package/build/dist/Types/AI/ResourceAiAccessApi.js.map +1 -0
  951. package/build/dist/Types/AI/ResourceAiAccessPermissions.js +98 -0
  952. package/build/dist/Types/AI/ResourceAiAccessPermissions.js.map +1 -0
  953. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +116 -29
  954. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  955. package/build/dist/Types/Code/CodeType.js +2 -0
  956. package/build/dist/Types/Code/CodeType.js.map +1 -1
  957. package/build/dist/Types/Code/JsonSyntax.js +604 -0
  958. package/build/dist/Types/Code/JsonSyntax.js.map +1 -0
  959. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js +310 -0
  960. package/build/dist/Types/CustomField/CustomFieldCreateSettings.js.map +1 -0
  961. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js +38 -0
  962. package/build/dist/Types/CustomField/CustomFieldMappingCatalog.js.map +1 -1
  963. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +10 -7
  964. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -1
  965. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +1 -1
  966. package/build/dist/Types/Icon/IconProp.js +2 -0
  967. package/build/dist/Types/Icon/IconProp.js.map +1 -1
  968. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js +119 -0
  969. package/build/dist/Types/Incident/IncidentFormIpAllowlist.js.map +1 -0
  970. package/build/dist/Types/Incident/IncidentFormPublic.js +678 -0
  971. package/build/dist/Types/Incident/IncidentFormPublic.js.map +1 -0
  972. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +10 -3
  973. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
  974. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js +184 -0
  975. package/build/dist/Types/MessageQueue/MessageQueueIdentity.js.map +1 -0
  976. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js +190 -0
  977. package/build/dist/Types/MessageQueue/MessageQueueManualIdentity.js.map +1 -0
  978. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js +1057 -0
  979. package/build/dist/Types/MessageQueue/MessageQueueMetricCatalog.js.map +1 -0
  980. package/build/dist/Types/MessageQueue/MessagingSystem.js +394 -0
  981. package/build/dist/Types/MessageQueue/MessagingSystem.js.map +1 -0
  982. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js +1768 -0
  983. package/build/dist/Types/MessageQueue/MessagingTelemetryResolver.js.map +1 -0
  984. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js +1207 -0
  985. package/build/dist/Types/Monitor/MessageQueueAlertTemplates.js.map +1 -0
  986. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +47 -21
  987. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  988. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +5 -0
  989. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  990. package/build/dist/Types/Monitor/RumAlertTemplates.js +199 -3
  991. package/build/dist/Types/Monitor/RumAlertTemplates.js.map +1 -1
  992. package/build/dist/Types/Permission.js +274 -0
  993. package/build/dist/Types/Permission.js.map +1 -1
  994. package/build/dist/Types/ResourceAiAgent/AiResourceType.js +242 -0
  995. package/build/dist/Types/ResourceAiAgent/AiResourceType.js.map +1 -0
  996. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js +281 -0
  997. package/build/dist/Types/ResourceAiAgent/ResourceAiAccess.js.map +1 -0
  998. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +12 -0
  999. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  1000. package/build/dist/Types/Rules/RuleRun.js +4 -0
  1001. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  1002. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js +45 -0
  1003. package/build/dist/Types/Rum/SessionReplayBudgetMetricType.js.map +1 -0
  1004. package/build/dist/Types/Runbook/RunbookStepType.js +27 -0
  1005. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  1006. package/build/dist/Types/Team/ComplianceNotificationChannel.js +4 -3
  1007. package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -1
  1008. package/build/dist/Types/Team/ComplianceRule.js +48 -14
  1009. package/build/dist/Types/Team/ComplianceRule.js.map +1 -1
  1010. package/build/dist/Types/Team/ComplianceRuleType.js +2 -2
  1011. package/build/dist/Types/Telemetry/EntityType.js +16 -0
  1012. package/build/dist/Types/Telemetry/EntityType.js.map +1 -1
  1013. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +13 -2
  1014. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  1015. package/build/dist/Types/XML.js +23 -0
  1016. package/build/dist/Types/XML.js.map +1 -1
  1017. package/build/dist/UI/Components/CodeEditor/CodeEditor.js +641 -266
  1018. package/build/dist/UI/Components/CodeEditor/CodeEditor.js.map +1 -1
  1019. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js +464 -0
  1020. package/build/dist/UI/Components/CodeEditor/CodeEditorCommands.js.map +1 -0
  1021. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js +69 -0
  1022. package/build/dist/UI/Components/CodeEditor/CodeEditorHighlight.js.map +1 -0
  1023. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js +108 -0
  1024. package/build/dist/UI/Components/CodeEditor/CodeEditorLanguages.js.map +1 -0
  1025. package/build/dist/UI/Components/CodeEditor/YamlEditor.js +14 -186
  1026. package/build/dist/UI/Components/CodeEditor/YamlEditor.js.map +1 -1
  1027. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js +5 -1
  1028. package/build/dist/UI/Components/CopyTextButton/CopyTextButton.js.map +1 -1
  1029. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +5 -14
  1030. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -1
  1031. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +14 -13
  1032. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  1033. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js +1 -1
  1034. package/build/dist/UI/Components/ErrorMessage/ErrorMessage.js.map +1 -1
  1035. package/build/dist/UI/Components/Forms/Fields/FormField.js +8 -3
  1036. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  1037. package/build/dist/UI/Components/Icon/Icon.js +8 -0
  1038. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  1039. package/build/dist/UI/Components/Input/Input.js +11 -3
  1040. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  1041. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +2 -1
  1042. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1043. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +14 -4
  1044. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  1045. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  1046. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  1047. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js +710 -65
  1048. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditor.js.map +1 -1
  1049. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js +238 -0
  1050. package/build/dist/UI/Components/Markdown.tsx/MarkdownEditorHistory.js.map +1 -0
  1051. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js +1028 -0
  1052. package/build/dist/UI/Components/Markdown.tsx/MarkdownListEditing.js.map +1 -0
  1053. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js +1088 -0
  1054. package/build/dist/UI/Components/Markdown.tsx/MarkdownPaste.js.map +1 -0
  1055. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +70 -10
  1056. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  1057. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js +887 -0
  1058. package/build/dist/UI/Components/Markdown.tsx/MarkdownVisualEditing.js.map +1 -0
  1059. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +57 -6
  1060. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1061. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js +7 -5
  1062. package/build/dist/UI/Components/ResetObjectID/ResetObjectID.js.map +1 -1
  1063. package/build/dist/UI/Components/Table/EmptyTableMessage.js +51 -0
  1064. package/build/dist/UI/Components/Table/EmptyTableMessage.js.map +1 -0
  1065. package/build/dist/UI/Components/Table/Table.js +30 -11
  1066. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  1067. package/build/dist/UI/Components/Table/TableRow.js +9 -2
  1068. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  1069. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js +63 -1
  1070. package/build/dist/UI/Components/TelemetryViewer/FacetVisibility.js.map +1 -1
  1071. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +4 -2
  1072. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1073. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js +91 -10
  1074. package/build/dist/UI/Components/TelemetryViewer/components/LockedFilterChip.js.map +1 -1
  1075. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +14 -4
  1076. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  1077. package/build/dist/UI/Components/TextArea/TextArea.js +9 -3
  1078. package/build/dist/UI/Components/TextArea/TextArea.js.map +1 -1
  1079. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js +1 -2
  1080. package/build/dist/UI/Components/Workflow/ModelFieldPicker.js.map +1 -1
  1081. package/build/dist/Utils/AI/InvestigationReport.js +71 -11
  1082. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  1083. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js +1462 -0
  1084. package/build/dist/Utils/AiRemediation/Resource/CephCommandPolicy.js.map +1 -0
  1085. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js +122 -0
  1086. package/build/dist/Utils/AiRemediation/Resource/DatabaseCommandPolicy.js.map +1 -0
  1087. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js +1139 -0
  1088. package/build/dist/Utils/AiRemediation/Resource/DatabaseDiagnosticCatalog.js.map +1 -0
  1089. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js +1060 -0
  1090. package/build/dist/Utils/AiRemediation/Resource/DatabaseQueryRedactor.js.map +1 -0
  1091. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js +1301 -0
  1092. package/build/dist/Utils/AiRemediation/Resource/DockerCliGrammar.js.map +1 -0
  1093. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js +370 -0
  1094. package/build/dist/Utils/AiRemediation/Resource/DockerEngineCommandPolicy.js.map +1 -0
  1095. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js +498 -0
  1096. package/build/dist/Utils/AiRemediation/Resource/DockerSwarmCommandPolicy.js.map +1 -0
  1097. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js +1565 -0
  1098. package/build/dist/Utils/AiRemediation/Resource/GovcCommandPolicy.js.map +1 -0
  1099. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js +2206 -0
  1100. package/build/dist/Utils/AiRemediation/Resource/HostCommandPolicy.js.map +1 -0
  1101. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js +1129 -0
  1102. package/build/dist/Utils/AiRemediation/Resource/ProxmoxCommandPolicy.js.map +1 -0
  1103. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js +565 -0
  1104. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicy.js.map +1 -0
  1105. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js +408 -0
  1106. package/build/dist/Utils/AiRemediation/Resource/ResourceCommandPolicyCore.js.map +1 -0
  1107. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js +1910 -0
  1108. package/build/dist/Utils/AiRemediation/Resource/ResourceOutputRedactor.js.map +1 -0
  1109. package/build/dist/Utils/LabelRuleImportExport.js +2 -0
  1110. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  1111. package/build/dist/Utils/Markdown/UntrustedMarkdown.js +988 -0
  1112. package/build/dist/Utils/Markdown/UntrustedMarkdown.js.map +1 -0
  1113. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js +34 -0
  1114. package/build/dist/Utils/Monitor/IncomingEmailMonitorRequestUtil.js.map +1 -0
  1115. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js +148 -0
  1116. package/build/dist/Utils/Monitor/MonitorLogSummaryUtil.js.map +1 -0
  1117. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js +160 -0
  1118. package/build/dist/Utils/SessionReplay/SessionReplayBudgetMetricType.js.map +1 -0
  1119. package/build/dist/Utils/Telemetry/EntityKey.js +36 -0
  1120. package/build/dist/Utils/Telemetry/EntityKey.js.map +1 -1
  1121. package/package.json +1 -3
  1122. package/Server/Utils/CommunityEditionSsoReport.ts +0 -361
  1123. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +0 -616
  1124. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +0 -217
  1125. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +0 -271
  1126. package/Tests/App/Dashboard/CloudDocumentationMarkdown.test.ts +0 -215
  1127. package/Tests/App/Dashboard/TelemetryResourceRetentionSettings.test.tsx +0 -784
  1128. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +0 -518
  1129. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +0 -419
  1130. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +0 -769
  1131. package/Tests/UI/Components/CodeEditor.test.tsx +0 -638
  1132. package/Tests/UI/Components/MonacoLoader.test.ts +0 -67
  1133. package/Tests/UI/Components/MonacoRuntime.test.ts +0 -121
  1134. package/Tests/UI/Components/Telemetry/TelemetryRetentionConfigForm.test.tsx +0 -329
  1135. package/Tests/UI/Components/YamlEditor.test.tsx +0 -847
  1136. package/UI/Components/CodeEditor/MonacoLoader.ts +0 -36
  1137. package/UI/Components/Telemetry/TelemetryRetentionConfigForm.tsx +0 -319
  1138. package/UI/Components/Telemetry/TelemetryRetentionConfigSummary.tsx +0 -223
  1139. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +0 -223
  1140. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +0 -1
  1141. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js +0 -34
  1142. package/build/dist/UI/Components/CodeEditor/MonacoLoader.js.map +0 -1
  1143. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js +0 -171
  1144. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigForm.js.map +0 -1
  1145. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js +0 -119
  1146. package/build/dist/UI/Components/Telemetry/TelemetryRetentionConfigSummary.js.map +0 -1
@@ -0,0 +1,1676 @@
1
+ import { afterEach, describe, expect, jest, test } from "@jest/globals";
2
+ import type { SpyInstance } from "jest-mock";
3
+ import DatabaseBaseModel from "../../../../../Models/DatabaseModels/DatabaseBaseModel/DatabaseBaseModel";
4
+ import IncidentSeverity from "../../../../../Models/DatabaseModels/IncidentSeverity";
5
+ import Label from "../../../../../Models/DatabaseModels/Label";
6
+ import Monitor from "../../../../../Models/DatabaseModels/Monitor";
7
+ import MonitorStatus from "../../../../../Models/DatabaseModels/MonitorStatus";
8
+ import OnCallDutyPolicy from "../../../../../Models/DatabaseModels/OnCallDutyPolicy";
9
+ import IncidentSeverityService from "../../../../../Server/Services/IncidentSeverityService";
10
+ import LabelService from "../../../../../Server/Services/LabelService";
11
+ import MonitorService from "../../../../../Server/Services/MonitorService";
12
+ import MonitorStatusService from "../../../../../Server/Services/MonitorStatusService";
13
+ import OnCallDutyPolicyService from "../../../../../Server/Services/OnCallDutyPolicyService";
14
+ import MicrosoftTeamsCardChoices, {
15
+ MICROSOFT_TEAMS_MAX_CHOICE_TITLE_LENGTH,
16
+ MICROSOFT_TEAMS_MAX_LABEL_CHOICES,
17
+ MICROSOFT_TEAMS_MAX_MONITOR_CHOICES,
18
+ MICROSOFT_TEAMS_MAX_MONITOR_STATUS_CHOICES,
19
+ MICROSOFT_TEAMS_MAX_ON_CALL_POLICY_CHOICES,
20
+ MICROSOFT_TEAMS_MAX_SEVERITY_CHOICES,
21
+ MicrosoftTeamsCardChoice,
22
+ MicrosoftTeamsCardChoiceList,
23
+ MicrosoftTeamsFittedCard,
24
+ } from "../../../../../Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsCardChoices";
25
+ import { MICROSOFT_TEAMS_CARD_SIZE_BUDGETS_IN_BYTES } from "../../../../../Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsMessageSize";
26
+ import SortOrder from "../../../../../Types/BaseDatabase/SortOrder";
27
+ import { JSONObject } from "../../../../../Types/JSON";
28
+ import ObjectID from "../../../../../Types/ObjectID";
29
+ import PositiveNumber from "../../../../../Types/PositiveNumber";
30
+
31
+ /*
32
+ * Pins MicrosoftTeamsCardChoices: the choice lists behind the Microsoft Teams
33
+ * bot's "create incident" and "create maintenance" forms.
34
+ *
35
+ * Issue #4111: in Teams, both commands answered "Sorry, I encountered an
36
+ * error processing your request. Please try again later." (twice), while
37
+ * "show scheduled maintenance" worked. The two forms listed every monitor,
38
+ * label and on-call policy of the project (up to 10,000 of each) as
39
+ * Input.ChoiceSet choices, and Teams refused the card as too large (HTTP 413
40
+ * MessageSizeTooBig). The lists are now read in name order up to a cap,
41
+ * shortened until the card fits a size budget, and whatever is left off is
42
+ * named on the card so the user knows to add it in OneUptime.
43
+ *
44
+ * Covered here:
45
+ *
46
+ * - toChoices: rows to { title, value } choices, skipping rows without a
47
+ * name or id, trimming names and cutting long ones to 80 characters with an
48
+ * ellipsis. The cut never splits an emoji (it goes through
49
+ * truncateToLength): a name cut where an emoji sits loses the whole emoji,
50
+ * never just half of it, which was a reported production bug.
51
+ * - fitCardToBudget: builds the card once when it fits; otherwise shortens
52
+ * the longest trimmable list by a quarter (at least by one) until it fits,
53
+ * taking turns between lists of the same length. A budget of 0 or less
54
+ * leaves every trimmable list off up front and builds the card once, instead
55
+ * of shortening the lists step by step to nothing. Lists that must be shown
56
+ * whole are never shortened, a card that cannot fit is reported as such,
57
+ * 10,000 choices take few rebuilds at each budget the bot tries, and
58
+ * buildCard always gets the first choices of each list together with the
59
+ * list's real total. Every fitting here is also checked for what must always
60
+ * hold: the card returned is the last one built, the counts returned are the
61
+ * ones it shows, every earlier card was over the budget, and fitsBudget
62
+ * matches the card's size as measured here. A fitting that stops converging
63
+ * fails its own test at once instead of crashing the run (MAX_CARD_BUILDS).
64
+ * - getNotShownNote: the line under a list the card could not show in full.
65
+ * - The card elements both forms share: buildNoteElement (the small print),
66
+ * buildNotShownNoteElement (that line as an element, or null) and
67
+ * buildCreateInOneUptimeAction (the button to the dashboard).
68
+ * - The fetchers: what each one reads (the project, _id and name only, the
69
+ * order, the cap, as root), that the total is counted only when the cap was
70
+ * reached, and that rows become choices the way toChoices makes them, in the
71
+ * order they were read.
72
+ */
73
+
74
+ const PROJECT_ID: ObjectID = new ObjectID(
75
+ "6f1c2d3e-4a5b-4c6d-8e7f-9a0b1c2d3e4f",
76
+ );
77
+
78
+ const INCIDENT_ADD_LATER_HINT: string =
79
+ "You can add them to the incident in OneUptime after it is created.";
80
+
81
+ // Only whole characters: no half of a surrogate pair on its own.
82
+ const WELL_FORMED_UTF16: RegExp =
83
+ /^(?:[^\uD800-\uDFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF])*$/;
84
+
85
+ // A row as the fetchers read it: an id and a name, either of which may be off.
86
+ type NamedRow = {
87
+ _id?: string | undefined;
88
+ name?: string | undefined;
89
+ };
90
+
91
+ type Lists<TKey extends string> = Record<TKey, MicrosoftTeamsCardChoiceList>;
92
+
93
+ afterEach(() => {
94
+ jest.restoreAllMocks();
95
+ });
96
+
97
+ function padded(index: number): string {
98
+ return String(index).padStart(5, "0");
99
+ }
100
+
101
+ // A distinct, well-formed id per row.
102
+ function rowId(index: number): string {
103
+ return `00000000-0000-4000-8000-${String(index).padStart(12, "0")}`;
104
+ }
105
+
106
+ /*
107
+ * Choices that are all the same size, so a card grows by the same number of
108
+ * bytes with every choice it shows.
109
+ */
110
+ function makeChoices(
111
+ prefix: string,
112
+ count: number,
113
+ ): Array<MicrosoftTeamsCardChoice> {
114
+ const choices: Array<MicrosoftTeamsCardChoice> = [];
115
+
116
+ for (let index: number = 0; index < count; index++) {
117
+ choices.push({
118
+ title: `${prefix} ${padded(index)}`,
119
+ value: `${prefix}-${padded(index)}`,
120
+ });
121
+ }
122
+
123
+ return choices;
124
+ }
125
+
126
+ // Choices as toChoices makes them for long names: 80 characters and a UUID.
127
+ function makeLongChoices(
128
+ prefix: string,
129
+ count: number,
130
+ ): Array<MicrosoftTeamsCardChoice> {
131
+ const choices: Array<MicrosoftTeamsCardChoice> = [];
132
+
133
+ for (let index: number = 0; index < count; index++) {
134
+ choices.push({
135
+ title: `${prefix} ${padded(index)} `.padEnd(79, "x") + "…",
136
+ value: rowId(index),
137
+ });
138
+ }
139
+
140
+ return choices;
141
+ }
142
+
143
+ function listOf(
144
+ count: number,
145
+ prefix: string,
146
+ totalCount?: number,
147
+ ): MicrosoftTeamsCardChoiceList {
148
+ return {
149
+ choices: makeChoices(prefix, count),
150
+ totalCount: totalCount ?? count,
151
+ };
152
+ }
153
+
154
+ // A stand-in for an adaptive card: one ChoiceSet per list, with its total.
155
+ function buildTestCard<TKey extends string>(shown: Lists<TKey>): JSONObject {
156
+ const body: Array<JSONObject> = [];
157
+
158
+ for (const key of Object.keys(shown) as Array<TKey>) {
159
+ body.push({
160
+ type: "Input.ChoiceSet",
161
+ id: key,
162
+ choices: shown[key].choices,
163
+ totalCount: shown[key].totalCount,
164
+ });
165
+ }
166
+
167
+ return { type: "AdaptiveCard", version: "1.5", body: body };
168
+ }
169
+
170
+ /*
171
+ * Teams' measure, computed here independently of MicrosoftTeamsMessageSize:
172
+ * the JSON of the card as UTF-16, two bytes a code unit.
173
+ */
174
+ function sizeInBytes(card: JSONObject): number {
175
+ return JSON.stringify(card).length * 2;
176
+ }
177
+
178
+ // The size of the test card showing the first counts[key] of each list.
179
+ function sizeShowing<TKey extends string>(
180
+ lists: Lists<TKey>,
181
+ counts: Record<TKey, number>,
182
+ ): number {
183
+ const shown: Lists<TKey> = {} as Lists<TKey>;
184
+
185
+ for (const key of Object.keys(lists) as Array<TKey>) {
186
+ shown[key] = {
187
+ choices: lists[key].choices.slice(0, counts[key]),
188
+ totalCount: lists[key].totalCount,
189
+ };
190
+ }
191
+
192
+ return sizeInBytes(buildTestCard(shown));
193
+ }
194
+
195
+ /*
196
+ * More cards than any fitting in this file needs (emptying three lists of
197
+ * 10,000 takes 91). Past it the recorder throws, so a fitCardToBudget that no
198
+ * longer converges, or shortens one choice at a time, fails its own test at
199
+ * once. Without the limit such a regression runs the synchronous fitting loop
200
+ * until the process runs out of memory (the recorder keeps every card): jest's
201
+ * timeout cannot stop a loop, and the crash names no test.
202
+ */
203
+ const MAX_CARD_BUILDS: number = 500;
204
+
205
+ /*
206
+ * A budget above 0 that no card fits: the fitting shortens every trimmable
207
+ * list step by step, all the way to nothing. A budget of 0 would leave the
208
+ * lists off in one go instead, so it cannot show the steps.
209
+ */
210
+ const NO_CARD_FITS_BUDGET_IN_BYTES: number = 1;
211
+
212
+ // Every card fitCardToBudget had built, and what it handed buildCard each time.
213
+ interface CardBuilds<TKey extends string> {
214
+ buildCard: (shown: Lists<TKey>) => JSONObject;
215
+ shown: Array<Lists<TKey>>;
216
+ cards: Array<JSONObject>;
217
+ }
218
+
219
+ function recordCardBuilds<TKey extends string>(): CardBuilds<TKey> {
220
+ const shown: Array<Lists<TKey>> = [];
221
+ const cards: Array<JSONObject> = [];
222
+
223
+ return {
224
+ shown: shown,
225
+ cards: cards,
226
+ buildCard: (lists: Lists<TKey>): JSONObject => {
227
+ if (cards.length >= MAX_CARD_BUILDS) {
228
+ throw new Error(
229
+ `fitCardToBudget asked for more than ${MAX_CARD_BUILDS} cards: it is not converging.`,
230
+ );
231
+ }
232
+
233
+ const card: JSONObject = buildTestCard(lists);
234
+ shown.push(lists);
235
+ cards.push(card);
236
+ return card;
237
+ },
238
+ };
239
+ }
240
+
241
+ interface FitRun<TKey extends string> {
242
+ result: MicrosoftTeamsFittedCard<TKey>;
243
+ builds: CardBuilds<TKey>;
244
+ }
245
+
246
+ /*
247
+ * Runs fitCardToBudget with a recording buildCard, then checks what must hold
248
+ * for any lists and budget: the card returned is the last one built, the
249
+ * counts returned are the ones that card shows, every card built before it
250
+ * was over the budget (the fitting stops at the first card that fits), and
251
+ * fitsBudget says whether the card returned is within the budget, measured
252
+ * here rather than by MicrosoftTeamsMessageSize.
253
+ */
254
+ function fit<TKey extends string>(data: {
255
+ lists: Lists<TKey>;
256
+ trimmableKeys: ReadonlyArray<TKey>;
257
+ budgetInBytes: number;
258
+ }): FitRun<TKey> {
259
+ const builds: CardBuilds<TKey> = recordCardBuilds<TKey>();
260
+
261
+ const result: MicrosoftTeamsFittedCard<TKey> =
262
+ MicrosoftTeamsCardChoices.fitCardToBudget<TKey>({
263
+ lists: data.lists,
264
+ trimmableKeys: data.trimmableKeys,
265
+ budgetInBytes: data.budgetInBytes,
266
+ buildCard: builds.buildCard,
267
+ });
268
+
269
+ const lastShown: Lists<TKey> | undefined =
270
+ builds.shown[builds.shown.length - 1];
271
+ expect(lastShown).toBeDefined();
272
+ expect(result.card).toBe(builds.cards[builds.cards.length - 1]);
273
+
274
+ const countsInLastCard: Record<TKey, number> = {} as Record<TKey, number>;
275
+
276
+ for (const key of Object.keys(data.lists) as Array<TKey>) {
277
+ countsInLastCard[key] = lastShown![key].choices.length;
278
+ }
279
+
280
+ expect(result.shownCounts).toStrictEqual(countsInLastCard);
281
+
282
+ for (const card of builds.cards.slice(0, -1)) {
283
+ expect(sizeInBytes(card)).toBeGreaterThan(data.budgetInBytes);
284
+ }
285
+
286
+ expect(result.fitsBudget).toBe(
287
+ sizeInBytes(result.card) <= data.budgetInBytes,
288
+ );
289
+
290
+ return { result: result, builds: builds };
291
+ }
292
+
293
+ // How many choices of each list every build showed, in the order of keys.
294
+ function countsPerBuild<TKey extends string>(
295
+ builds: CardBuilds<TKey>,
296
+ keys: ReadonlyArray<TKey>,
297
+ ): Array<Array<number>> {
298
+ return builds.shown.map((lists: Lists<TKey>): Array<number> => {
299
+ return keys.map((key: TKey): number => {
300
+ return lists[key].choices.length;
301
+ });
302
+ });
303
+ }
304
+
305
+ describe("MicrosoftTeamsCardChoices.toChoices", () => {
306
+ test("turns each row into a choice titled by its name and valued by its id, in row order", () => {
307
+ expect(
308
+ MicrosoftTeamsCardChoices.toChoices([
309
+ { _id: rowId(1), name: "Payments API" },
310
+ { _id: rowId(2), name: "Checkout API" },
311
+ { _id: rowId(3), name: "Auth API" },
312
+ ]),
313
+ ).toStrictEqual([
314
+ { title: "Payments API", value: rowId(1) },
315
+ { title: "Checkout API", value: rowId(2) },
316
+ { title: "Auth API", value: rowId(3) },
317
+ ]);
318
+ });
319
+
320
+ test("gives no choices for no rows", () => {
321
+ expect(MicrosoftTeamsCardChoices.toChoices([])).toStrictEqual([]);
322
+ });
323
+
324
+ test("skips a row whose name is missing, empty or only whitespace", () => {
325
+ expect(
326
+ MicrosoftTeamsCardChoices.toChoices([
327
+ { _id: rowId(1) },
328
+ { _id: rowId(2), name: undefined },
329
+ { _id: rowId(3), name: null as unknown as string },
330
+ { _id: rowId(4), name: "" },
331
+ { _id: rowId(5), name: " " },
332
+ { _id: rowId(6), name: "\t\n " },
333
+ { _id: rowId(7), name: "Checkout API" },
334
+ ]),
335
+ ).toStrictEqual([{ title: "Checkout API", value: rowId(7) }]);
336
+ });
337
+
338
+ test("skips a row whose id is missing or empty", () => {
339
+ expect(
340
+ MicrosoftTeamsCardChoices.toChoices([
341
+ { name: "No id" },
342
+ { _id: undefined, name: "Undefined id" },
343
+ { _id: null as unknown as string, name: "Null id" },
344
+ { _id: "", name: "Empty id" },
345
+ { _id: rowId(5), name: "Checkout API" },
346
+ ]),
347
+ ).toStrictEqual([{ title: "Checkout API", value: rowId(5) }]);
348
+ });
349
+
350
+ test("trims the whitespace around a name and keeps the whitespace inside it", () => {
351
+ expect(
352
+ MicrosoftTeamsCardChoices.toChoices([
353
+ { _id: rowId(1), name: " Checkout API \n" },
354
+ { _id: rowId(2), name: "Checkout API (EU)" },
355
+ ]),
356
+ ).toStrictEqual([
357
+ { title: "Checkout API", value: rowId(1) },
358
+ { title: "Checkout API (EU)", value: rowId(2) },
359
+ ]);
360
+ });
361
+
362
+ test("keeps a name of exactly 80 characters as it is", () => {
363
+ const name: string = "abcdefghij".repeat(8);
364
+ expect(name).toHaveLength(80);
365
+ expect(MICROSOFT_TEAMS_MAX_CHOICE_TITLE_LENGTH).toBe(80);
366
+
367
+ const [choice]: Array<MicrosoftTeamsCardChoice> =
368
+ MicrosoftTeamsCardChoices.toChoices([{ _id: rowId(1), name: name }]);
369
+
370
+ expect(choice).toStrictEqual({ title: name, value: rowId(1) });
371
+ });
372
+
373
+ test("cuts a longer name to its first 79 characters and an ellipsis, 80 in all", () => {
374
+ // 81 characters, and 100 (the most a monitor name column holds).
375
+ const names: Array<string> = [
376
+ "abcdefghij".repeat(8) + "k",
377
+ "abcdefghij".repeat(10),
378
+ ];
379
+
380
+ const choices: Array<MicrosoftTeamsCardChoice> =
381
+ MicrosoftTeamsCardChoices.toChoices(
382
+ names.map((name: string, index: number): NamedRow => {
383
+ return { _id: rowId(index), name: name };
384
+ }),
385
+ );
386
+
387
+ expect(choices).toStrictEqual([
388
+ { title: "abcdefghij".repeat(7) + "abcdefghi…", value: rowId(0) },
389
+ { title: "abcdefghij".repeat(7) + "abcdefghi…", value: rowId(1) },
390
+ ]);
391
+
392
+ for (const choice of choices) {
393
+ expect(choice.title).toHaveLength(80);
394
+ }
395
+ });
396
+
397
+ test("measures a name after trimming it", () => {
398
+ const name: string = "abcdefghij".repeat(8);
399
+
400
+ const [choice]: Array<MicrosoftTeamsCardChoice> =
401
+ MicrosoftTeamsCardChoices.toChoices([
402
+ { _id: rowId(1), name: ` ${name} \n` },
403
+ ]);
404
+
405
+ expect(choice).toStrictEqual({ title: name, value: rowId(1) });
406
+ });
407
+
408
+ test("keeps a whole emoji that ends right at the cut", () => {
409
+ // The emoji is the 78th and 79th code units, the last two the cut keeps.
410
+ const name: string = "a".repeat(77) + "🚀" + " and the rest of the name";
411
+
412
+ const [choice]: Array<MicrosoftTeamsCardChoice> =
413
+ MicrosoftTeamsCardChoices.toChoices([{ _id: rowId(1), name: name }]);
414
+
415
+ expect(choice!.title).toBe("a".repeat(77) + "🚀…");
416
+ expect(choice!.title).toHaveLength(80);
417
+ expect(choice!.title).toMatch(WELL_FORMED_UTF16);
418
+ });
419
+
420
+ test("does not leave half of an emoji before the ellipsis", () => {
421
+ /*
422
+ * The emoji is the 79th and 80th code units, so a cut after 79 code
423
+ * units splits it. A lone surrogate is not a character: it shows as a
424
+ * replacement mark in the dropdown, and it is not valid Unicode for the
425
+ * service that receives the card. MicrosoftTeamsMessageSize.fitTextToBudget
426
+ * keeps text replies free of it for the same reason.
427
+ *
428
+ * A reported production bug: toChoices kept the emoji's first half. It
429
+ * now cuts with truncateToLength, which drops that half.
430
+ */
431
+ const name: string = "a".repeat(78) + "🚀" + " and the rest of the name";
432
+
433
+ const [choice]: Array<MicrosoftTeamsCardChoice> =
434
+ MicrosoftTeamsCardChoices.toChoices([{ _id: rowId(1), name: name }]);
435
+
436
+ expect(choice!.title).toMatch(WELL_FORMED_UTF16);
437
+
438
+ // Only the broken half goes: everything before the emoji is kept.
439
+ expect(choice!.title).toBe("a".repeat(78) + "…");
440
+ });
441
+
442
+ test("cuts a name made only of emoji after the last whole one that fits", () => {
443
+ // 50 emoji, 100 code units: 79 of them hold 39 emoji and half of the 40th.
444
+ const name: string = "🚀".repeat(50);
445
+
446
+ const [choice]: Array<MicrosoftTeamsCardChoice> =
447
+ MicrosoftTeamsCardChoices.toChoices([{ _id: rowId(1), name: name }]);
448
+
449
+ expect(choice!.title).toBe("🚀".repeat(39) + "…");
450
+ expect(choice!.title).toMatch(WELL_FORMED_UTF16);
451
+ });
452
+
453
+ test("reads an id that is an ObjectID through its toString", () => {
454
+ const id: ObjectID = new ObjectID(rowId(42));
455
+ const monitor: Monitor = new Monitor(new ObjectID(rowId(43)));
456
+ monitor.name = "Checkout API";
457
+
458
+ expect(
459
+ MicrosoftTeamsCardChoices.toChoices([
460
+ { _id: id as unknown as string, name: "Payments API" },
461
+ monitor,
462
+ ]),
463
+ ).toStrictEqual([
464
+ { title: "Payments API", value: rowId(42) },
465
+ { title: "Checkout API", value: rowId(43) },
466
+ ]);
467
+ });
468
+ });
469
+
470
+ describe("MicrosoftTeamsCardChoices.fitCardToBudget", () => {
471
+ test("builds the card once, with every choice and every total, when it already fits", () => {
472
+ type Key = "severities" | "monitors" | "labels";
473
+ const lists: Lists<Key> = {
474
+ severities: listOf(4, "s"),
475
+ monitors: listOf(12, "m"),
476
+ labels: listOf(3, "l"),
477
+ };
478
+
479
+ const run: FitRun<Key> = fit<Key>({
480
+ lists: lists,
481
+ trimmableKeys: ["monitors", "labels"],
482
+ budgetInBytes: 40 * 1024,
483
+ });
484
+
485
+ expect(run.builds.cards).toHaveLength(1);
486
+ expect(run.builds.shown[0]).toStrictEqual(lists);
487
+ expect(run.result.card).toBe(run.builds.cards[0]);
488
+ expect(run.result.fitsBudget).toBe(true);
489
+ expect(run.result.shownCounts).toStrictEqual({
490
+ severities: 4,
491
+ monitors: 12,
492
+ labels: 3,
493
+ });
494
+ });
495
+
496
+ test("measures the card as Teams does: a card exactly at the budget fits, one byte over is shortened", () => {
497
+ type Key = "monitors";
498
+
499
+ // ASCII, an accent and an emoji: UTF-16 code units, not UTF-8 bytes or characters.
500
+ const lists: Lists<Key> = {
501
+ monitors: {
502
+ choices: makeChoices("m", 19).concat([
503
+ { title: "Café 🚀 checkout", value: rowId(19) },
504
+ ]),
505
+ totalCount: 20,
506
+ },
507
+ };
508
+ const fullSize: number = sizeShowing(lists, { monitors: 20 });
509
+
510
+ const atBudget: FitRun<Key> = fit<Key>({
511
+ lists: lists,
512
+ trimmableKeys: ["monitors"],
513
+ budgetInBytes: fullSize,
514
+ });
515
+
516
+ expect(atBudget.builds.cards).toHaveLength(1);
517
+ expect(atBudget.result.fitsBudget).toBe(true);
518
+ expect(atBudget.result.shownCounts).toStrictEqual({ monitors: 20 });
519
+
520
+ const overBudget: FitRun<Key> = fit<Key>({
521
+ lists: lists,
522
+ trimmableKeys: ["monitors"],
523
+ budgetInBytes: fullSize - 1,
524
+ });
525
+
526
+ expect(countsPerBuild(overBudget.builds, ["monitors"])).toStrictEqual([
527
+ [20],
528
+ [15],
529
+ ]);
530
+ expect(overBudget.result.fitsBudget).toBe(true);
531
+ expect(overBudget.result.shownCounts).toStrictEqual({ monitors: 15 });
532
+ });
533
+
534
+ test("shortens the longest trimmable list first, whatever order the lists are named in", () => {
535
+ type Key = "labels" | "monitors";
536
+ const lists: Lists<Key> = {
537
+ labels: listOf(10, "l"),
538
+ monitors: listOf(100, "m"),
539
+ };
540
+ const budget: number = sizeShowing(lists, { labels: 10, monitors: 75 });
541
+ const orders: Array<Array<Key>> = [
542
+ ["labels", "monitors"],
543
+ ["monitors", "labels"],
544
+ ];
545
+
546
+ for (const trimmableKeys of orders) {
547
+ const run: FitRun<Key> = fit<Key>({
548
+ lists: lists,
549
+ trimmableKeys: trimmableKeys,
550
+ budgetInBytes: budget,
551
+ });
552
+
553
+ expect(countsPerBuild(run.builds, ["labels", "monitors"])).toStrictEqual([
554
+ [10, 100],
555
+ [10, 75],
556
+ ]);
557
+ expect(run.result.shownCounts).toStrictEqual({
558
+ labels: 10,
559
+ monitors: 75,
560
+ });
561
+ expect(run.result.fitsBudget).toBe(true);
562
+ }
563
+ });
564
+
565
+ test("shortens a list by a quarter at a time, and by at least one", () => {
566
+ type Key = "monitors";
567
+
568
+ // No card fits, so the list is shortened step by step to nothing.
569
+ const run: FitRun<Key> = fit<Key>({
570
+ lists: { monitors: listOf(100, "m") },
571
+ trimmableKeys: ["monitors"],
572
+ budgetInBytes: NO_CARD_FITS_BUDGET_IN_BYTES,
573
+ });
574
+
575
+ expect(countsPerBuild(run.builds, ["monitors"]).flat()).toStrictEqual([
576
+ 100, 75, 56, 42, 31, 23, 17, 12, 9, 6, 4, 3, 2, 1, 0,
577
+ ]);
578
+ expect(run.result.fitsBudget).toBe(false);
579
+ });
580
+
581
+ test("shortens a long list alone until it is no longer the longest, then the lists take turns", () => {
582
+ type Key = "monitors" | "labels";
583
+
584
+ /*
585
+ * No card fits, so both lists are shortened all the way; a tie goes to
586
+ * the list named first.
587
+ */
588
+ const run: FitRun<Key> = fit<Key>({
589
+ lists: { monitors: listOf(40, "m"), labels: listOf(10, "l") },
590
+ trimmableKeys: ["monitors", "labels"],
591
+ budgetInBytes: NO_CARD_FITS_BUDGET_IN_BYTES,
592
+ });
593
+
594
+ expect(countsPerBuild(run.builds, ["monitors", "labels"])).toStrictEqual([
595
+ [40, 10],
596
+ [30, 10],
597
+ [22, 10],
598
+ [16, 10],
599
+ [12, 10],
600
+ [9, 10],
601
+ [9, 7],
602
+ [6, 7],
603
+ [6, 5],
604
+ [4, 5],
605
+ [4, 3],
606
+ [3, 3],
607
+ [2, 3],
608
+ [2, 2],
609
+ [1, 2],
610
+ [1, 1],
611
+ [0, 1],
612
+ [0, 0],
613
+ ]);
614
+ });
615
+
616
+ test("two lists of the same length take turns and end the same length, whichever is named first", () => {
617
+ type Key = "monitors" | "labels";
618
+ const lists: Lists<Key> = {
619
+ monitors: listOf(100, "a"),
620
+ labels: listOf(100, "b"),
621
+ };
622
+ const budget: number = sizeShowing(lists, { monitors: 56, labels: 56 });
623
+
624
+ const monitorsFirst: FitRun<Key> = fit<Key>({
625
+ lists: lists,
626
+ trimmableKeys: ["monitors", "labels"],
627
+ budgetInBytes: budget,
628
+ });
629
+
630
+ expect(
631
+ countsPerBuild(monitorsFirst.builds, ["monitors", "labels"]),
632
+ ).toStrictEqual([
633
+ [100, 100],
634
+ [75, 100],
635
+ [75, 75],
636
+ [56, 75],
637
+ [56, 56],
638
+ ]);
639
+ expect(monitorsFirst.result.shownCounts).toStrictEqual({
640
+ monitors: 56,
641
+ labels: 56,
642
+ });
643
+ expect(monitorsFirst.result.fitsBudget).toBe(true);
644
+
645
+ const labelsFirst: FitRun<Key> = fit<Key>({
646
+ lists: lists,
647
+ trimmableKeys: ["labels", "monitors"],
648
+ budgetInBytes: budget,
649
+ });
650
+
651
+ expect(
652
+ countsPerBuild(labelsFirst.builds, ["monitors", "labels"]),
653
+ ).toStrictEqual([
654
+ [100, 100],
655
+ [100, 75],
656
+ [75, 75],
657
+ [75, 56],
658
+ [56, 56],
659
+ ]);
660
+ expect(labelsFirst.result.shownCounts).toStrictEqual({
661
+ monitors: 56,
662
+ labels: 56,
663
+ });
664
+ });
665
+
666
+ test("never shortens a list that is not trimmable, even when it is the longest", () => {
667
+ type Key = "severities" | "monitors" | "labels";
668
+ const lists: Lists<Key> = {
669
+ severities: listOf(300, "s"),
670
+ monitors: listOf(40, "m"),
671
+ labels: listOf(10, "l"),
672
+ };
673
+
674
+ const run: FitRun<Key> = fit<Key>({
675
+ lists: lists,
676
+ trimmableKeys: ["monitors", "labels"],
677
+ budgetInBytes: sizeShowing(lists, {
678
+ severities: 300,
679
+ monitors: 9,
680
+ labels: 10,
681
+ }),
682
+ });
683
+
684
+ expect(
685
+ countsPerBuild(run.builds, ["severities", "monitors", "labels"]),
686
+ ).toStrictEqual([
687
+ [300, 40, 10],
688
+ [300, 30, 10],
689
+ [300, 22, 10],
690
+ [300, 16, 10],
691
+ [300, 12, 10],
692
+ [300, 9, 10],
693
+ ]);
694
+ expect(run.result.shownCounts).toStrictEqual({
695
+ severities: 300,
696
+ monitors: 9,
697
+ labels: 10,
698
+ });
699
+ expect(run.result.fitsBudget).toBe(true);
700
+ });
701
+
702
+ test("fits by leaving every trimmable list off when only that is small enough", () => {
703
+ type Key = "severities" | "monitors" | "labels";
704
+ const lists: Lists<Key> = {
705
+ severities: listOf(300, "s"),
706
+ monitors: listOf(40, "m"),
707
+ labels: listOf(10, "l"),
708
+ };
709
+ const budget: number = sizeShowing(lists, {
710
+ severities: 300,
711
+ monitors: 0,
712
+ labels: 0,
713
+ });
714
+
715
+ const run: FitRun<Key> = fit<Key>({
716
+ lists: lists,
717
+ trimmableKeys: ["monitors", "labels"],
718
+ budgetInBytes: budget,
719
+ });
720
+
721
+ expect(run.result.shownCounts).toStrictEqual({
722
+ severities: 300,
723
+ monitors: 0,
724
+ labels: 0,
725
+ });
726
+ expect(run.result.fitsBudget).toBe(true);
727
+ expect(sizeInBytes(run.result.card)).toBe(budget);
728
+ });
729
+
730
+ test("says the card does not fit when the lists it must show are too big on their own", () => {
731
+ type Key = "severities" | "monitors" | "labels";
732
+ const lists: Lists<Key> = {
733
+ severities: listOf(300, "s"),
734
+ monitors: listOf(40, "m"),
735
+ labels: listOf(10, "l"),
736
+ };
737
+
738
+ const run: FitRun<Key> = fit<Key>({
739
+ lists: lists,
740
+ trimmableKeys: ["monitors", "labels"],
741
+ budgetInBytes:
742
+ sizeShowing(lists, { severities: 300, monitors: 0, labels: 0 }) - 2,
743
+ });
744
+
745
+ expect(run.result.fitsBudget).toBe(false);
746
+ expect(run.result.shownCounts).toStrictEqual({
747
+ severities: 300,
748
+ monitors: 0,
749
+ labels: 0,
750
+ });
751
+
752
+ // The card returned is the smallest one, built last; nothing is built after it.
753
+ const counts: Array<Array<number>> = countsPerBuild(run.builds, [
754
+ "severities",
755
+ "monitors",
756
+ "labels",
757
+ ]);
758
+ expect(run.result.card).toBe(run.builds.cards[run.builds.cards.length - 1]);
759
+ expect(counts[counts.length - 1]).toStrictEqual([300, 0, 0]);
760
+ expect(counts[counts.length - 2]).not.toStrictEqual([300, 0, 0]);
761
+
762
+ for (const buildCounts of counts) {
763
+ expect(buildCounts[0]).toBe(300);
764
+ }
765
+ });
766
+
767
+ test("with no trimmable list, builds an oversized card once and says it does not fit", () => {
768
+ type Key = "severities" | "monitors";
769
+ const lists: Lists<Key> = {
770
+ severities: listOf(5, "s"),
771
+ monitors: listOf(50, "m"),
772
+ };
773
+
774
+ // A budget of 0 or less has nothing to leave off either.
775
+ for (const budget of [64, 0, -1]) {
776
+ const run: FitRun<Key> = fit<Key>({
777
+ lists: lists,
778
+ trimmableKeys: [],
779
+ budgetInBytes: budget,
780
+ });
781
+
782
+ expect(run.builds.cards).toHaveLength(1);
783
+ expect(run.builds.shown[0]).toStrictEqual(lists);
784
+ expect(run.result.card).toBe(run.builds.cards[0]);
785
+ expect(run.result.fitsBudget).toBe(false);
786
+ expect(run.result.shownCounts).toStrictEqual({
787
+ severities: 5,
788
+ monitors: 50,
789
+ });
790
+ }
791
+ });
792
+
793
+ test("never picks a trimmable list that is already empty: with nothing to shorten, an oversized card is built once", () => {
794
+ /*
795
+ * A project with no monitors and no labels. There is nothing to take off
796
+ * the card, so the fitting must stop at once rather than "shorten" an
797
+ * empty list below zero, which would never end.
798
+ */
799
+ type Key = "severities" | "monitors" | "labels";
800
+ const lists: Lists<Key> = {
801
+ severities: listOf(300, "s"),
802
+ monitors: listOf(0, "m"),
803
+ labels: listOf(0, "l"),
804
+ };
805
+
806
+ const run: FitRun<Key> = fit<Key>({
807
+ lists: lists,
808
+ trimmableKeys: ["monitors", "labels"],
809
+ budgetInBytes: 64,
810
+ });
811
+
812
+ expect(run.builds.cards).toHaveLength(1);
813
+ expect(run.builds.shown[0]).toStrictEqual(lists);
814
+ expect(run.result.fitsBudget).toBe(false);
815
+ expect(run.result.shownCounts).toStrictEqual({
816
+ severities: 300,
817
+ monitors: 0,
818
+ labels: 0,
819
+ });
820
+ });
821
+
822
+ /*
823
+ * Budget 0 is the last one the bot tries, after Teams refused the card
824
+ * twice. The trimmable lists are left off up front, so the card is built
825
+ * once: the card with every choice, the biggest of all, is never built, and
826
+ * no list is shortened step by step to nothing first.
827
+ */
828
+ test.each([0, -1, -40 * 1024])(
829
+ "budget %i leaves every trimmable list off up front, in one build, keeps the others whole and keeps each list's total",
830
+ (budget: number) => {
831
+ type Key =
832
+ | "severities"
833
+ | "monitors"
834
+ | "monitorStatuses"
835
+ | "labels"
836
+ | "onCallDutyPolicies";
837
+ const lists: Lists<Key> = {
838
+ severities: listOf(4, "s"),
839
+ monitors: listOf(250, "m", 10000),
840
+ monitorStatuses: listOf(3, "st"),
841
+ labels: listOf(100, "l", 500),
842
+ onCallDutyPolicies: listOf(7, "p"),
843
+ };
844
+
845
+ const run: FitRun<Key> = fit<Key>({
846
+ lists: lists,
847
+ trimmableKeys: ["monitors", "labels", "onCallDutyPolicies"],
848
+ budgetInBytes: budget,
849
+ });
850
+
851
+ expect(run.builds.cards).toHaveLength(1);
852
+ expect(run.builds.shown[0]).toStrictEqual({
853
+ severities: lists.severities,
854
+ monitors: { choices: [], totalCount: 10000 },
855
+ monitorStatuses: lists.monitorStatuses,
856
+ labels: { choices: [], totalCount: 500 },
857
+ onCallDutyPolicies: { choices: [], totalCount: 7 },
858
+ });
859
+ expect(run.result.card).toBe(run.builds.cards[0]);
860
+
861
+ // No card is 0 bytes, so even the smallest one is over this budget.
862
+ expect(run.result.fitsBudget).toBe(false);
863
+ expect(run.result.shownCounts).toStrictEqual({
864
+ severities: 4,
865
+ monitors: 0,
866
+ monitorStatuses: 3,
867
+ labels: 0,
868
+ onCallDutyPolicies: 0,
869
+ });
870
+ },
871
+ );
872
+
873
+ test("takes few builds for 10,000 monitors at each budget the bot tries, stops at the first card that fits, and ends within it", () => {
874
+ type Key =
875
+ | "severities"
876
+ | "monitors"
877
+ | "monitorStatuses"
878
+ | "labels"
879
+ | "onCallDutyPolicies";
880
+ const lists: Lists<Key> = {
881
+ severities: { choices: makeLongChoices("Severity", 5), totalCount: 5 },
882
+ monitors: {
883
+ choices: makeLongChoices("Monitor", 10000),
884
+ totalCount: 10000,
885
+ },
886
+ monitorStatuses: {
887
+ choices: makeLongChoices("Status", 5),
888
+ totalCount: 5,
889
+ },
890
+ labels: { choices: makeLongChoices("Label", 500), totalCount: 500 },
891
+ onCallDutyPolicies: {
892
+ choices: makeLongChoices("Policy", 200),
893
+ totalCount: 200,
894
+ },
895
+ };
896
+
897
+ // The last budget, 0, leaves the lists off; the tests above cover it.
898
+ const budgets: Array<number> =
899
+ MICROSOFT_TEAMS_CARD_SIZE_BUDGETS_IN_BYTES.filter(
900
+ (budget: number): boolean => {
901
+ return budget > 0;
902
+ },
903
+ );
904
+ expect(budgets).toContain(40 * 1024);
905
+
906
+ for (const budget of budgets) {
907
+ const run: FitRun<Key> = fit<Key>({
908
+ lists: lists,
909
+ trimmableKeys: ["monitors", "labels", "onCallDutyPolicies"],
910
+ budgetInBytes: budget,
911
+ });
912
+
913
+ // One choice at a time would take thousands of builds.
914
+ expect(run.builds.cards.length).toBeLessThan(100);
915
+ expect(run.result.fitsBudget).toBe(true);
916
+ expect(sizeInBytes(run.result.card)).toBeLessThanOrEqual(budget);
917
+ expect(run.result.card).toBe(
918
+ run.builds.cards[run.builds.cards.length - 1],
919
+ );
920
+
921
+ for (const card of run.builds.cards.slice(0, -1)) {
922
+ expect(sizeInBytes(card)).toBeGreaterThan(budget);
923
+ }
924
+
925
+ for (const shown of run.builds.shown) {
926
+ expect(shown.severities.choices).toHaveLength(5);
927
+ expect(shown.monitorStatuses.choices).toHaveLength(5);
928
+ }
929
+
930
+ // Every trimmable list still offers some choices at this budget.
931
+ expect(run.result.shownCounts.monitors).toBeGreaterThan(0);
932
+ expect(run.result.shownCounts.labels).toBeGreaterThan(0);
933
+ expect(run.result.shownCounts.onCallDutyPolicies).toBeGreaterThan(0);
934
+ }
935
+ });
936
+
937
+ test("empties three lists of 10,000 choices in fewer than 100 builds", () => {
938
+ type Key = "monitors" | "labels" | "onCallDutyPolicies";
939
+ const lists: Lists<Key> = {
940
+ monitors: listOf(10000, "m"),
941
+ labels: listOf(10000, "l"),
942
+ onCallDutyPolicies: listOf(10000, "p"),
943
+ };
944
+ const trimmableKeys: Array<Key> = [
945
+ "monitors",
946
+ "labels",
947
+ "onCallDutyPolicies",
948
+ ];
949
+
950
+ const run: FitRun<Key> = fit<Key>({
951
+ lists: lists,
952
+ trimmableKeys: trimmableKeys,
953
+ budgetInBytes: NO_CARD_FITS_BUDGET_IN_BYTES,
954
+ });
955
+
956
+ expect(run.builds.cards.length).toBeLessThan(100);
957
+ expect(run.result.shownCounts).toStrictEqual({
958
+ monitors: 0,
959
+ labels: 0,
960
+ onCallDutyPolicies: 0,
961
+ });
962
+
963
+ // Budget 0 gets to that same card in a single build.
964
+ const atZero: FitRun<Key> = fit<Key>({
965
+ lists: lists,
966
+ trimmableKeys: trimmableKeys,
967
+ budgetInBytes: 0,
968
+ });
969
+
970
+ expect(atZero.builds.cards).toHaveLength(1);
971
+ expect(atZero.result.shownCounts).toStrictEqual(run.result.shownCounts);
972
+ expect(atZero.result.card).toStrictEqual(run.result.card);
973
+ });
974
+
975
+ test("hands buildCard the first choices of every list, in order, with the list's own total", () => {
976
+ type Key = "severities" | "monitors" | "labels";
977
+ const keys: Array<Key> = ["severities", "monitors", "labels"];
978
+ const lists: Lists<Key> = {
979
+ severities: listOf(4, "s"),
980
+ monitors: listOf(250, "m", 10000),
981
+ labels: listOf(100, "l", 500),
982
+ };
983
+
984
+ const run: FitRun<Key> = fit<Key>({
985
+ lists: lists,
986
+ trimmableKeys: ["monitors", "labels"],
987
+ budgetInBytes: 8 * 1024,
988
+ });
989
+
990
+ expect(run.builds.shown.length).toBeGreaterThan(1);
991
+
992
+ for (const shown of run.builds.shown) {
993
+ expect(Object.keys(shown)).toStrictEqual(keys);
994
+
995
+ for (const key of keys) {
996
+ const shownChoices: Array<MicrosoftTeamsCardChoice> =
997
+ shown[key].choices;
998
+
999
+ expect(shown[key].totalCount).toBe(lists[key].totalCount);
1000
+ expect(shownChoices).toStrictEqual(
1001
+ lists[key].choices.slice(0, shownChoices.length),
1002
+ );
1003
+
1004
+ shownChoices.forEach(
1005
+ (choice: MicrosoftTeamsCardChoice, index: number): void => {
1006
+ expect(choice).toBe(lists[key].choices[index]);
1007
+ },
1008
+ );
1009
+ }
1010
+ }
1011
+ });
1012
+
1013
+ test("leaves the lists it was given as they were, so the same choices can be fitted to the next budget", () => {
1014
+ type Key = "severities" | "monitors" | "labels";
1015
+ const newLists: () => Lists<Key> = (): Lists<Key> => {
1016
+ return {
1017
+ severities: listOf(4, "s"),
1018
+ monitors: listOf(250, "m", 10000),
1019
+ labels: listOf(100, "l", 500),
1020
+ };
1021
+ };
1022
+ const lists: Lists<Key> = newLists();
1023
+ const untouched: Lists<Key> = newLists();
1024
+
1025
+ for (const budget of [40 * 1024, 20 * 1024, 0, 20 * 1024]) {
1026
+ const reused: FitRun<Key> = fit<Key>({
1027
+ lists: lists,
1028
+ trimmableKeys: ["monitors", "labels"],
1029
+ budgetInBytes: budget,
1030
+ });
1031
+
1032
+ expect(lists).toStrictEqual(untouched);
1033
+
1034
+ const fresh: FitRun<Key> = fit<Key>({
1035
+ lists: newLists(),
1036
+ trimmableKeys: ["monitors", "labels"],
1037
+ budgetInBytes: budget,
1038
+ });
1039
+
1040
+ expect(reused.result.shownCounts).toStrictEqual(fresh.result.shownCounts);
1041
+ expect(reused.result.card).toStrictEqual(fresh.result.card);
1042
+ }
1043
+ });
1044
+
1045
+ test("gives the same card every time for the same lists and budget", () => {
1046
+ type Key = "severities" | "monitors" | "labels" | "onCallDutyPolicies";
1047
+ const keys: Array<Key> = [
1048
+ "severities",
1049
+ "monitors",
1050
+ "labels",
1051
+ "onCallDutyPolicies",
1052
+ ];
1053
+ const lists: Lists<Key> = {
1054
+ severities: listOf(4, "s"),
1055
+ monitors: listOf(250, "m", 3000),
1056
+ labels: listOf(100, "l", 100),
1057
+ onCallDutyPolicies: listOf(60, "p"),
1058
+ };
1059
+
1060
+ const runs: Array<FitRun<Key>> = [1, 2].map((): FitRun<Key> => {
1061
+ return fit<Key>({
1062
+ lists: lists,
1063
+ trimmableKeys: ["monitors", "labels", "onCallDutyPolicies"],
1064
+ budgetInBytes: 12 * 1024,
1065
+ });
1066
+ });
1067
+
1068
+ expect(countsPerBuild(runs[1]!.builds, keys)).toStrictEqual(
1069
+ countsPerBuild(runs[0]!.builds, keys),
1070
+ );
1071
+ expect(runs[1]!.result.shownCounts).toStrictEqual(
1072
+ runs[0]!.result.shownCounts,
1073
+ );
1074
+ expect(JSON.stringify(runs[1]!.result.card)).toBe(
1075
+ JSON.stringify(runs[0]!.result.card),
1076
+ );
1077
+ });
1078
+ });
1079
+
1080
+ describe("MicrosoftTeamsCardChoices.getNotShownNote", () => {
1081
+ function noteFor(data: {
1082
+ shown: number;
1083
+ totalCount: number;
1084
+ pluralNoun?: string;
1085
+ addLaterHint?: string;
1086
+ }): string | null {
1087
+ return MicrosoftTeamsCardChoices.getNotShownNote({
1088
+ list: {
1089
+ choices: makeChoices("m", data.shown),
1090
+ totalCount: data.totalCount,
1091
+ },
1092
+ pluralNoun: data.pluralNoun ?? "monitors",
1093
+ addLaterHint: data.addLaterHint ?? INCIDENT_ADD_LATER_HINT,
1094
+ });
1095
+ }
1096
+
1097
+ test("is null when the card shows every record", () => {
1098
+ expect(noteFor({ shown: 3, totalCount: 3 })).toBeNull();
1099
+ expect(noteFor({ shown: 250, totalCount: 250 })).toBeNull();
1100
+ });
1101
+
1102
+ test("is null when the project has none", () => {
1103
+ expect(noteFor({ shown: 0, totalCount: 0 })).toBeNull();
1104
+ });
1105
+
1106
+ test("says how many of how many are shown, by name, when some are", () => {
1107
+ expect(noteFor({ shown: 40, totalCount: 250 })).toBe(
1108
+ "Showing the first 40 of 250 monitors, by name. You can add them to the incident in OneUptime after it is created.",
1109
+ );
1110
+ expect(noteFor({ shown: 250, totalCount: 10000 })).toBe(
1111
+ "Showing the first 250 of 10000 monitors, by name. You can add them to the incident in OneUptime after it is created.",
1112
+ );
1113
+ });
1114
+
1115
+ test("says there are too many to list when none are shown", () => {
1116
+ expect(noteFor({ shown: 0, totalCount: 250 })).toBe(
1117
+ "This project has 250 monitors, too many to list in Microsoft Teams. You can add them to the incident in OneUptime after it is created.",
1118
+ );
1119
+ });
1120
+
1121
+ test("takes a total below the number shown as complete", () => {
1122
+ // Records deleted between reading the list and counting it.
1123
+ expect(noteFor({ shown: 250, totalCount: 240 })).toBeNull();
1124
+ expect(noteFor({ shown: 3, totalCount: 0 })).toBeNull();
1125
+ });
1126
+
1127
+ test("uses the noun and the hint it is given", () => {
1128
+ expect(
1129
+ noteFor({
1130
+ shown: 1,
1131
+ totalCount: 2,
1132
+ pluralNoun: "on-call policies",
1133
+ addLaterHint:
1134
+ "You can add them to the event in OneUptime after it is created.",
1135
+ }),
1136
+ ).toBe(
1137
+ "Showing the first 1 of 2 on-call policies, by name. You can add them to the event in OneUptime after it is created.",
1138
+ );
1139
+ });
1140
+ });
1141
+
1142
+ describe("MicrosoftTeamsCardChoices card elements", () => {
1143
+ /*
1144
+ * The small print and the dashboard button of both forms. The incident and
1145
+ * the maintenance form each had a copy of the note element; both now build
1146
+ * them here, so the two forms look the same.
1147
+ */
1148
+ function noteElement(text: string): JSONObject {
1149
+ return {
1150
+ type: "TextBlock",
1151
+ text: text,
1152
+ wrap: true,
1153
+ isSubtle: true,
1154
+ size: "Small",
1155
+ spacing: "Small",
1156
+ };
1157
+ }
1158
+
1159
+ test("buildNoteElement is small, subtle text that wraps, with the text exactly as given", () => {
1160
+ for (const text of [
1161
+ "Start and end times are in America/New_York.",
1162
+ "Showing the first 40 of 250 monitors, by name. _Markdown_ and 🚀 stay as they are.",
1163
+ ]) {
1164
+ expect(MicrosoftTeamsCardChoices.buildNoteElement(text)).toStrictEqual(
1165
+ noteElement(text),
1166
+ );
1167
+ }
1168
+ });
1169
+
1170
+ test("buildNotShownNoteElement is the note element for a list shown in part", () => {
1171
+ expect(
1172
+ MicrosoftTeamsCardChoices.buildNotShownNoteElement({
1173
+ list: { choices: makeChoices("m", 40), totalCount: 250 },
1174
+ pluralNoun: "monitors",
1175
+ addLaterHint: INCIDENT_ADD_LATER_HINT,
1176
+ }),
1177
+ ).toStrictEqual(
1178
+ noteElement(
1179
+ "Showing the first 40 of 250 monitors, by name. You can add them to the incident in OneUptime after it is created.",
1180
+ ),
1181
+ );
1182
+ });
1183
+
1184
+ test("buildNotShownNoteElement is the note element for a list left off", () => {
1185
+ expect(
1186
+ MicrosoftTeamsCardChoices.buildNotShownNoteElement({
1187
+ list: { choices: [], totalCount: 10000 },
1188
+ pluralNoun: "labels",
1189
+ addLaterHint:
1190
+ "You can add them to the event in OneUptime after it is created.",
1191
+ }),
1192
+ ).toStrictEqual(
1193
+ noteElement(
1194
+ "This project has 10000 labels, too many to list in Microsoft Teams. You can add them to the event in OneUptime after it is created.",
1195
+ ),
1196
+ );
1197
+ });
1198
+
1199
+ test("buildNotShownNoteElement is null when the card shows every record, or the project has none", () => {
1200
+ const lists: Array<MicrosoftTeamsCardChoiceList> = [
1201
+ { choices: makeChoices("m", 3), totalCount: 3 },
1202
+ { choices: [], totalCount: 0 },
1203
+ // Records deleted between reading the list and counting it.
1204
+ { choices: makeChoices("m", 250), totalCount: 240 },
1205
+ ];
1206
+
1207
+ for (const list of lists) {
1208
+ expect(
1209
+ MicrosoftTeamsCardChoices.buildNotShownNoteElement({
1210
+ list: list,
1211
+ pluralNoun: "monitors",
1212
+ addLaterHint: INCIDENT_ADD_LATER_HINT,
1213
+ }),
1214
+ ).toBeNull();
1215
+ }
1216
+ });
1217
+
1218
+ test("buildNotShownNoteElement says exactly what getNotShownNote says, whenever it says anything", () => {
1219
+ for (const shown of [0, 1, 40, 250]) {
1220
+ for (const totalCount of [0, 1, 40, 250, 10000]) {
1221
+ const data: {
1222
+ list: MicrosoftTeamsCardChoiceList;
1223
+ pluralNoun: string;
1224
+ addLaterHint: string;
1225
+ } = {
1226
+ list: { choices: makeChoices("m", shown), totalCount: totalCount },
1227
+ pluralNoun: "on-call policies",
1228
+ addLaterHint: INCIDENT_ADD_LATER_HINT,
1229
+ };
1230
+ const note: string | null =
1231
+ MicrosoftTeamsCardChoices.getNotShownNote(data);
1232
+
1233
+ expect(
1234
+ MicrosoftTeamsCardChoices.buildNotShownNoteElement(data),
1235
+ ).toStrictEqual(note === null ? null : noteElement(note));
1236
+ }
1237
+ }
1238
+ });
1239
+
1240
+ test("buildCreateInOneUptimeAction is a button that opens the URL it is given", () => {
1241
+ for (const url of [
1242
+ `https://oneuptime.example.com/dashboard/${PROJECT_ID.toString()}/incidents/create`,
1243
+ `https://oneuptime.example.com/dashboard/${PROJECT_ID.toString()}/scheduled-maintenance-events/create`,
1244
+ ]) {
1245
+ expect(
1246
+ MicrosoftTeamsCardChoices.buildCreateInOneUptimeAction(url),
1247
+ ).toStrictEqual({
1248
+ type: "Action.OpenUrl",
1249
+ title: "Create in OneUptime",
1250
+ url: url,
1251
+ });
1252
+ }
1253
+ });
1254
+ });
1255
+
1256
+ /*
1257
+ * The two reads a fetcher makes, as the tests stub them. Each service is the
1258
+ * same object under this type, so a spy on it replaces the service's method.
1259
+ */
1260
+ interface ChoiceReads {
1261
+ findBy: (findBy: unknown) => Promise<Array<DatabaseBaseModel>>;
1262
+ countBy: (countBy: unknown) => Promise<PositiveNumber>;
1263
+ }
1264
+
1265
+ interface ReadSpies {
1266
+ findBy: SpyInstance<ChoiceReads["findBy"]>;
1267
+ countBy: SpyInstance<ChoiceReads["countBy"]>;
1268
+ }
1269
+
1270
+ interface FetcherCase {
1271
+ method: string;
1272
+ pluralNoun: string;
1273
+ reads: ChoiceReads;
1274
+ newModel: () => DatabaseBaseModel;
1275
+ fetch: (projectId: ObjectID) => Promise<MicrosoftTeamsCardChoiceList>;
1276
+ sort: JSONObject;
1277
+ cap: number;
1278
+ }
1279
+
1280
+ function toModels(
1281
+ newModel: () => DatabaseBaseModel,
1282
+ rows: Array<NamedRow>,
1283
+ ): Array<DatabaseBaseModel> {
1284
+ return rows.map((row: NamedRow): DatabaseBaseModel => {
1285
+ const model: DatabaseBaseModel = newModel();
1286
+
1287
+ if (row._id !== undefined) {
1288
+ model._id = row._id;
1289
+ }
1290
+
1291
+ if (row.name !== undefined) {
1292
+ model.setValue("name", row.name);
1293
+ }
1294
+
1295
+ return model;
1296
+ });
1297
+ }
1298
+
1299
+ function rowsNamed(count: number, noun: string): Array<NamedRow> {
1300
+ const rows: Array<NamedRow> = [];
1301
+
1302
+ for (let index: number = 0; index < count; index++) {
1303
+ rows.push({ _id: rowId(index), name: `${noun} ${padded(index)}` });
1304
+ }
1305
+
1306
+ return rows;
1307
+ }
1308
+
1309
+ function choicesFor(rows: Array<NamedRow>): Array<MicrosoftTeamsCardChoice> {
1310
+ return rows.map((row: NamedRow): MicrosoftTeamsCardChoice => {
1311
+ return { title: row.name!, value: row._id! };
1312
+ });
1313
+ }
1314
+
1315
+ function stubReads(
1316
+ fetcher: FetcherCase,
1317
+ data: { rows: Array<NamedRow>; count?: number },
1318
+ ): ReadSpies {
1319
+ return {
1320
+ findBy: jest
1321
+ .spyOn(fetcher.reads, "findBy")
1322
+ .mockResolvedValue(toModels(fetcher.newModel, data.rows)),
1323
+ countBy: jest
1324
+ .spyOn(fetcher.reads, "countBy")
1325
+ .mockResolvedValue(new PositiveNumber(data.count ?? data.rows.length)),
1326
+ };
1327
+ }
1328
+
1329
+ /*
1330
+ * The one argument a spy was called with. jest-mock records the calls in
1331
+ * arrays of its own realm, so the argument is compared rather than the list
1332
+ * of calls (toStrictEqual also compares constructors).
1333
+ */
1334
+ function onlyArgumentOf(spy: SpyInstance<(data: unknown) => unknown>): unknown {
1335
+ expect(spy).toHaveBeenCalledTimes(1);
1336
+ return spy.mock.calls[0]![0];
1337
+ }
1338
+
1339
+ function expectedFindBy(fetcher: FetcherCase): JSONObject {
1340
+ return {
1341
+ query: { projectId: PROJECT_ID },
1342
+ select: { _id: true, name: true },
1343
+ sort: fetcher.sort,
1344
+ limit: fetcher.cap,
1345
+ skip: 0,
1346
+ props: { isRoot: true },
1347
+ };
1348
+ }
1349
+
1350
+ // Lists the card may shorten: read by name, and counted when the cap is hit.
1351
+ const COUNTED_FETCHERS: Array<FetcherCase> = [
1352
+ {
1353
+ method: "getMonitorChoices",
1354
+ pluralNoun: "monitors",
1355
+ reads: MonitorService as unknown as ChoiceReads,
1356
+ newModel: (): DatabaseBaseModel => {
1357
+ return new Monitor();
1358
+ },
1359
+ fetch: (projectId: ObjectID): Promise<MicrosoftTeamsCardChoiceList> => {
1360
+ return MicrosoftTeamsCardChoices.getMonitorChoices(projectId);
1361
+ },
1362
+ sort: { name: SortOrder.Ascending },
1363
+ cap: 250,
1364
+ },
1365
+ {
1366
+ method: "getLabelChoices",
1367
+ pluralNoun: "labels",
1368
+ reads: LabelService as unknown as ChoiceReads,
1369
+ newModel: (): DatabaseBaseModel => {
1370
+ return new Label();
1371
+ },
1372
+ fetch: (projectId: ObjectID): Promise<MicrosoftTeamsCardChoiceList> => {
1373
+ return MicrosoftTeamsCardChoices.getLabelChoices(projectId);
1374
+ },
1375
+ sort: { name: SortOrder.Ascending },
1376
+ cap: 100,
1377
+ },
1378
+ {
1379
+ method: "getOnCallDutyPolicyChoices",
1380
+ pluralNoun: "on-call policies",
1381
+ reads: OnCallDutyPolicyService as unknown as ChoiceReads,
1382
+ newModel: (): DatabaseBaseModel => {
1383
+ return new OnCallDutyPolicy();
1384
+ },
1385
+ fetch: (projectId: ObjectID): Promise<MicrosoftTeamsCardChoiceList> => {
1386
+ return MicrosoftTeamsCardChoices.getOnCallDutyPolicyChoices(projectId);
1387
+ },
1388
+ sort: { name: SortOrder.Ascending },
1389
+ cap: 100,
1390
+ },
1391
+ ];
1392
+
1393
+ // A list read in an order of its own, which the card must keep.
1394
+ interface OrderedFetcherCase extends FetcherCase {
1395
+ // Names as the database returns them in that order: not by name.
1396
+ namesInReadOrder: Array<string>;
1397
+ }
1398
+
1399
+ // Lists the card always shows whole: read in their own order, never counted.
1400
+ const UNCOUNTED_FETCHERS: Array<OrderedFetcherCase> = [
1401
+ {
1402
+ method: "getIncidentSeverityChoices",
1403
+ pluralNoun: "incident severities",
1404
+ reads: IncidentSeverityService as unknown as ChoiceReads,
1405
+ newModel: (): DatabaseBaseModel => {
1406
+ return new IncidentSeverity();
1407
+ },
1408
+ fetch: (projectId: ObjectID): Promise<MicrosoftTeamsCardChoiceList> => {
1409
+ return MicrosoftTeamsCardChoices.getIncidentSeverityChoices(projectId);
1410
+ },
1411
+ sort: { order: SortOrder.Ascending },
1412
+ cap: 50,
1413
+ namesInReadOrder: ["Critical", "Major", "Minor", "Low"],
1414
+ },
1415
+ {
1416
+ method: "getMonitorStatusChoices",
1417
+ pluralNoun: "monitor statuses",
1418
+ reads: MonitorStatusService as unknown as ChoiceReads,
1419
+ newModel: (): DatabaseBaseModel => {
1420
+ return new MonitorStatus();
1421
+ },
1422
+ fetch: (projectId: ObjectID): Promise<MicrosoftTeamsCardChoiceList> => {
1423
+ return MicrosoftTeamsCardChoices.getMonitorStatusChoices(projectId);
1424
+ },
1425
+ sort: { priority: SortOrder.Ascending },
1426
+ cap: 50,
1427
+ namesInReadOrder: ["Operational", "Degraded", "Offline"],
1428
+ },
1429
+ ];
1430
+
1431
+ // 100 characters, the most a name column holds, and the title it becomes.
1432
+ const LONG_NAME: string = "abcdefghij".repeat(10);
1433
+ const LONG_NAME_TITLE: string = "abcdefghij".repeat(7) + "abcdefghi…";
1434
+
1435
+ describe("MicrosoftTeamsCardChoices fetchers", () => {
1436
+ test("read at most 250 monitors, 100 labels, 100 on-call policies, 50 severities and 50 monitor statuses", () => {
1437
+ expect(MICROSOFT_TEAMS_MAX_MONITOR_CHOICES).toBe(250);
1438
+ expect(MICROSOFT_TEAMS_MAX_LABEL_CHOICES).toBe(100);
1439
+ expect(MICROSOFT_TEAMS_MAX_ON_CALL_POLICY_CHOICES).toBe(100);
1440
+ expect(MICROSOFT_TEAMS_MAX_SEVERITY_CHOICES).toBe(50);
1441
+ expect(MICROSOFT_TEAMS_MAX_MONITOR_STATUS_CHOICES).toBe(50);
1442
+ });
1443
+
1444
+ for (const fetcher of COUNTED_FETCHERS) {
1445
+ describe(fetcher.method, () => {
1446
+ test(`reads the project's ${fetcher.pluralNoun} once: _id and name, by name, at most ${fetcher.cap}, as root`, async () => {
1447
+ const rows: Array<NamedRow> = rowsNamed(3, fetcher.pluralNoun);
1448
+ const spies: ReadSpies = stubReads(fetcher, { rows: rows });
1449
+
1450
+ const list: MicrosoftTeamsCardChoiceList =
1451
+ await fetcher.fetch(PROJECT_ID);
1452
+
1453
+ expect(onlyArgumentOf(spies.findBy)).toStrictEqual(
1454
+ expectedFindBy(fetcher),
1455
+ );
1456
+ expect(spies.countBy).not.toHaveBeenCalled();
1457
+ expect(list).toStrictEqual({
1458
+ choices: choicesFor(rows),
1459
+ totalCount: 3,
1460
+ });
1461
+ });
1462
+
1463
+ test(`counts the project's ${fetcher.pluralNoun} when the cap was reached, and takes that as the total`, async () => {
1464
+ const rows: Array<NamedRow> = rowsNamed(
1465
+ fetcher.cap,
1466
+ fetcher.pluralNoun,
1467
+ );
1468
+ const spies: ReadSpies = stubReads(fetcher, {
1469
+ rows: rows,
1470
+ count: 1234,
1471
+ });
1472
+
1473
+ const list: MicrosoftTeamsCardChoiceList =
1474
+ await fetcher.fetch(PROJECT_ID);
1475
+
1476
+ expect(onlyArgumentOf(spies.findBy)).toStrictEqual(
1477
+ expectedFindBy(fetcher),
1478
+ );
1479
+ expect(onlyArgumentOf(spies.countBy)).toStrictEqual({
1480
+ query: { projectId: PROJECT_ID },
1481
+ props: { isRoot: true },
1482
+ });
1483
+ expect(list.choices).toStrictEqual(choicesFor(rows));
1484
+ expect(list.totalCount).toBe(1234);
1485
+ });
1486
+
1487
+ test("does not count when one fewer than the cap was read", async () => {
1488
+ const rows: Array<NamedRow> = rowsNamed(
1489
+ fetcher.cap - 1,
1490
+ fetcher.pluralNoun,
1491
+ );
1492
+ const spies: ReadSpies = stubReads(fetcher, {
1493
+ rows: rows,
1494
+ count: 1234,
1495
+ });
1496
+
1497
+ const list: MicrosoftTeamsCardChoiceList =
1498
+ await fetcher.fetch(PROJECT_ID);
1499
+
1500
+ expect(spies.countBy).not.toHaveBeenCalled();
1501
+ expect(list.choices).toHaveLength(fetcher.cap - 1);
1502
+ expect(list.totalCount).toBe(fetcher.cap - 1);
1503
+ });
1504
+
1505
+ test("makes choices as toChoices does (no nameless rows, names trimmed, long ones cut), while the total still counts every record read", async () => {
1506
+ const rows: Array<NamedRow> = [
1507
+ { _id: rowId(1), name: "Alpha" },
1508
+ { _id: rowId(2), name: "" },
1509
+ { _id: rowId(3), name: " " },
1510
+ { _id: rowId(4) },
1511
+ { _id: rowId(5), name: " Beta " },
1512
+ { _id: rowId(6), name: LONG_NAME },
1513
+ ];
1514
+ const spies: ReadSpies = stubReads(fetcher, { rows: rows });
1515
+
1516
+ const list: MicrosoftTeamsCardChoiceList =
1517
+ await fetcher.fetch(PROJECT_ID);
1518
+
1519
+ expect(spies.countBy).not.toHaveBeenCalled();
1520
+ expect(list).toStrictEqual({
1521
+ choices: [
1522
+ { title: "Alpha", value: rowId(1) },
1523
+ { title: "Beta", value: rowId(5) },
1524
+ { title: LONG_NAME_TITLE, value: rowId(6) },
1525
+ ],
1526
+ totalCount: 6,
1527
+ });
1528
+ });
1529
+
1530
+ test("judges the cap on the rows read, so it still counts when some of them had no name", async () => {
1531
+ /*
1532
+ * As many rows as the cap, one of them without a name: fewer choices
1533
+ * than the cap, but the read was cut off, so there may be more.
1534
+ */
1535
+ const rows: Array<NamedRow> = rowsNamed(
1536
+ fetcher.cap,
1537
+ fetcher.pluralNoun,
1538
+ );
1539
+ rows[0] = { _id: rowId(0) };
1540
+ const spies: ReadSpies = stubReads(fetcher, {
1541
+ rows: rows,
1542
+ count: 1234,
1543
+ });
1544
+
1545
+ const list: MicrosoftTeamsCardChoiceList =
1546
+ await fetcher.fetch(PROJECT_ID);
1547
+
1548
+ expect(onlyArgumentOf(spies.countBy)).toStrictEqual({
1549
+ query: { projectId: PROJECT_ID },
1550
+ props: { isRoot: true },
1551
+ });
1552
+ expect(list.choices).toStrictEqual(choicesFor(rows.slice(1)));
1553
+ expect(list.totalCount).toBe(1234);
1554
+ });
1555
+
1556
+ test("fails when the list or its count cannot be read", async () => {
1557
+ stubReads(fetcher, { rows: [] }).findBy.mockRejectedValue(
1558
+ new Error("connection refused"),
1559
+ );
1560
+
1561
+ await expect(fetcher.fetch(PROJECT_ID)).rejects.toThrow(
1562
+ "connection refused",
1563
+ );
1564
+
1565
+ jest.restoreAllMocks();
1566
+
1567
+ stubReads(fetcher, {
1568
+ rows: rowsNamed(fetcher.cap, fetcher.pluralNoun),
1569
+ }).countBy.mockRejectedValue(new Error("count timed out"));
1570
+
1571
+ await expect(fetcher.fetch(PROJECT_ID)).rejects.toThrow(
1572
+ "count timed out",
1573
+ );
1574
+ });
1575
+ });
1576
+ }
1577
+
1578
+ for (const fetcher of UNCOUNTED_FETCHERS) {
1579
+ describe(fetcher.method, () => {
1580
+ test(`reads the project's ${fetcher.pluralNoun} once: _id and name, in their own order, at most ${fetcher.cap}, as root`, async () => {
1581
+ const rows: Array<NamedRow> = rowsNamed(4, fetcher.pluralNoun);
1582
+ const spies: ReadSpies = stubReads(fetcher, { rows: rows });
1583
+
1584
+ const list: MicrosoftTeamsCardChoiceList =
1585
+ await fetcher.fetch(PROJECT_ID);
1586
+
1587
+ expect(onlyArgumentOf(spies.findBy)).toStrictEqual(
1588
+ expectedFindBy(fetcher),
1589
+ );
1590
+ expect(spies.countBy).not.toHaveBeenCalled();
1591
+ expect(list).toStrictEqual({
1592
+ choices: choicesFor(rows),
1593
+ totalCount: 4,
1594
+ });
1595
+ });
1596
+
1597
+ test("never counts, even when the cap was reached: the total is the choices read", async () => {
1598
+ const rows: Array<NamedRow> = rowsNamed(
1599
+ fetcher.cap,
1600
+ fetcher.pluralNoun,
1601
+ );
1602
+ const spies: ReadSpies = stubReads(fetcher, {
1603
+ rows: rows,
1604
+ count: 1234,
1605
+ });
1606
+
1607
+ const list: MicrosoftTeamsCardChoiceList =
1608
+ await fetcher.fetch(PROJECT_ID);
1609
+
1610
+ expect(spies.countBy).not.toHaveBeenCalled();
1611
+ expect(list.choices).toStrictEqual(choicesFor(rows));
1612
+ expect(list.totalCount).toBe(fetcher.cap);
1613
+ });
1614
+
1615
+ test("keeps the rows in the order they were read, not by name", async () => {
1616
+ const names: Array<string> = fetcher.namesInReadOrder;
1617
+
1618
+ // The premise: sorting these by name would change their order.
1619
+ const byName: Array<string> = [...names].sort(
1620
+ (left: string, right: string): number => {
1621
+ return left.localeCompare(right);
1622
+ },
1623
+ );
1624
+ expect(byName).not.toStrictEqual(names);
1625
+
1626
+ const rows: Array<NamedRow> = names.map(
1627
+ (name: string, index: number): NamedRow => {
1628
+ return { _id: rowId(index), name: name };
1629
+ },
1630
+ );
1631
+ stubReads(fetcher, { rows: rows });
1632
+
1633
+ const list: MicrosoftTeamsCardChoiceList =
1634
+ await fetcher.fetch(PROJECT_ID);
1635
+
1636
+ expect(list).toStrictEqual({
1637
+ choices: choicesFor(rows),
1638
+ totalCount: names.length,
1639
+ });
1640
+ });
1641
+
1642
+ test("makes choices as toChoices does (no nameless rows, names trimmed, long ones cut), and the total is the choices kept", async () => {
1643
+ const rows: Array<NamedRow> = [
1644
+ { _id: rowId(1), name: "Critical" },
1645
+ { _id: rowId(2), name: " " },
1646
+ { _id: rowId(3) },
1647
+ { _id: rowId(4), name: " Minor\n" },
1648
+ { _id: rowId(5), name: LONG_NAME },
1649
+ ];
1650
+ stubReads(fetcher, { rows: rows });
1651
+
1652
+ const list: MicrosoftTeamsCardChoiceList =
1653
+ await fetcher.fetch(PROJECT_ID);
1654
+
1655
+ expect(list).toStrictEqual({
1656
+ choices: [
1657
+ { title: "Critical", value: rowId(1) },
1658
+ { title: "Minor", value: rowId(4) },
1659
+ { title: LONG_NAME_TITLE, value: rowId(5) },
1660
+ ],
1661
+ totalCount: 3,
1662
+ });
1663
+ });
1664
+
1665
+ test("fails when the list cannot be read", async () => {
1666
+ stubReads(fetcher, { rows: [] }).findBy.mockRejectedValue(
1667
+ new Error("connection refused"),
1668
+ );
1669
+
1670
+ await expect(fetcher.fetch(PROJECT_ID)).rejects.toThrow(
1671
+ "connection refused",
1672
+ );
1673
+ });
1674
+ });
1675
+ }
1676
+ });