@oneuptime/common 14.0.0 → 14.0.2

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 (1270) hide show
  1. package/Models/DatabaseModels/AlertEpisodeMember.ts +8 -1
  2. package/Models/DatabaseModels/AutoRemediationSuggestion.ts +63 -0
  3. package/Models/DatabaseModels/IncidentEpisodeMember.ts +8 -1
  4. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +9 -2
  5. package/Models/DatabaseModels/IncidentPublicNote.ts +9 -2
  6. package/Models/DatabaseModels/Index.ts +4 -0
  7. package/Models/DatabaseModels/KubernetesCluster.ts +429 -0
  8. package/Models/DatabaseModels/Monitor.ts +48 -0
  9. package/Models/DatabaseModels/Runner.ts +5 -4
  10. package/Models/DatabaseModels/RunnerJob.ts +66 -0
  11. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +10 -2
  12. package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
  13. package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
  14. package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
  15. package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
  16. package/Models/DatabaseModels/WorkflowVariable.ts +479 -2
  17. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +79 -25
  18. package/Server/API/AIInvestigationAPI.ts +341 -0
  19. package/Server/API/AutoRemediationAPI.ts +184 -2
  20. package/Server/API/CommonAPI.ts +70 -0
  21. package/Server/API/KubernetesClusterAiAccessAPI.ts +793 -0
  22. package/Server/API/MicrosoftTeamsAPI.ts +770 -315
  23. package/Server/API/MonitorAPI.ts +140 -0
  24. package/Server/API/OnCallScheduleTimelineAPI.ts +5 -21
  25. package/Server/API/SlackAPI.ts +447 -99
  26. package/Server/API/StatusPageAPI.ts +146 -26
  27. package/Server/API/TelemetryAPI.ts +216 -5
  28. package/Server/API/UserTwoFactorBackupCodeAPI.ts +1 -0
  29. package/Server/API/WorkflowVariableAPI.ts +156 -0
  30. package/Server/Infrastructure/GlobalCache.ts +35 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.ts +97 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.ts +129 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.ts +25 -0
  36. package/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.ts +20 -0
  37. package/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.ts +38 -0
  38. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +14 -0
  39. package/Server/Middleware/MasterAdminAuthorization.ts +28 -0
  40. package/Server/Middleware/TelemetryIngest.ts +47 -2
  41. package/Server/Middleware/UserAuthorization.ts +56 -2
  42. package/Server/Services/AIAgentService.ts +1 -0
  43. package/Server/Services/AccessTokenService.ts +121 -48
  44. package/Server/Services/AlertEpisodeMemberService.ts +9 -0
  45. package/Server/Services/AlertEpisodeService.ts +14 -1
  46. package/Server/Services/AlertService.ts +134 -22
  47. package/Server/Services/AutoRemediationRuleEngineService.ts +968 -39
  48. package/Server/Services/AutoRemediationRuleService.ts +118 -0
  49. package/Server/Services/BillingService.ts +1 -0
  50. package/Server/Services/DatabaseService.ts +10 -0
  51. package/Server/Services/InboundEmail/Providers/SendGridInboundProvider.ts +16 -22
  52. package/Server/Services/IncidentEpisodeMemberService.ts +9 -0
  53. package/Server/Services/IncidentEpisodePublicNoteService.ts +66 -0
  54. package/Server/Services/IncidentEpisodeRoleMemberService.ts +27 -0
  55. package/Server/Services/IncidentEpisodeService.ts +14 -1
  56. package/Server/Services/IncidentGroupingEngineService.ts +11 -0
  57. package/Server/Services/IncidentMemberService.ts +21 -0
  58. package/Server/Services/IncidentPublicNoteService.ts +63 -0
  59. package/Server/Services/IncidentService.ts +120 -20
  60. package/Server/Services/IncidentStateTimelineService.ts +15 -0
  61. package/Server/Services/IncidentTemplateService.ts +83 -3
  62. package/Server/Services/Index.ts +4 -0
  63. package/Server/Services/KubernetesClusterAiAccessService.ts +1943 -0
  64. package/Server/Services/KubernetesClusterService.ts +1570 -1
  65. package/Server/Services/LogAggregationService.ts +14 -6
  66. package/Server/Services/MonitorService.ts +654 -54
  67. package/Server/Services/MonitorStatusTimelineService.ts +639 -2
  68. package/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.ts +2 -0
  69. package/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.ts +2 -0
  70. package/Server/Services/OnCallDutyPolicyEscalationRuleUserService.ts +2 -0
  71. package/Server/Services/OnCallDutyPolicyScheduleService.ts +3 -0
  72. package/Server/Services/OnCallNotificationAlertingService.ts +36 -12
  73. package/Server/Services/OnCallSetupReminderService.ts +1 -0
  74. package/Server/Services/ProbeService.ts +7 -1
  75. package/Server/Services/ProjectService.ts +11 -1
  76. package/Server/Services/RunbookCredentialService.ts +26 -1
  77. package/Server/Services/RunbookSecretService.ts +36 -0
  78. package/Server/Services/RunnerJobService.ts +941 -23
  79. package/Server/Services/RunnerService.ts +439 -6
  80. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +66 -0
  81. package/Server/Services/ScheduledMaintenanceService.ts +124 -19
  82. package/Server/Services/ScheduledMaintenanceTemplateService.ts +82 -3
  83. package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
  84. package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
  85. package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
  86. package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
  87. package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
  88. package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
  89. package/Server/Services/ServiceLevelObjectiveService.ts +42 -1
  90. package/Server/Services/StatusPagePrivateUserService.ts +1 -0
  91. package/Server/Services/StatusPageService.ts +301 -74
  92. package/Server/Services/StatusPageSubscriberService.ts +4 -0
  93. package/Server/Services/TeamMemberService.ts +309 -7
  94. package/Server/Services/TraceAggregationService.ts +10 -6
  95. package/Server/Services/UserEmailService.ts +1 -0
  96. package/Server/Services/UserNotificationMethodAdminService.ts +1 -0
  97. package/Server/Services/UserNotificationRuleAdminService.ts +1 -0
  98. package/Server/Services/UserNotificationRuleService.ts +4 -0
  99. package/Server/Services/UserService.ts +122 -1
  100. package/Server/Services/WorkflowVariableService.ts +593 -8
  101. package/Server/Services/WorkspaceNotificationRuleService.ts +588 -8
  102. package/Server/Services/WorkspaceProjectAuthTokenService.ts +170 -1
  103. package/Server/Types/Database/QueryHelper.ts +22 -0
  104. package/Server/Types/Markdown.ts +502 -27
  105. package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
  106. package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +182 -0
  107. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +525 -0
  108. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +854 -0
  109. package/Server/Utils/AI/CodeFix/CodeFixAgentAuth.ts +22 -2
  110. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +1916 -307
  111. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +1601 -74
  112. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +139 -7
  113. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +58 -1
  114. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +54 -1
  115. package/Server/Utils/AI/Toolbox/AIActionTools.ts +14 -6
  116. package/Server/Utils/AI/Toolbox/ResourceTools.ts +4 -2
  117. package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
  118. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +1341 -150
  119. package/Server/Utils/AutoRemediation/RemediationVerifier.ts +375 -4
  120. package/Server/Utils/Database/AffectedResourceRelations.ts +127 -0
  121. package/Server/Utils/Database/ProjectScopedReferenceValidator.ts +240 -1
  122. package/Server/Utils/EmailRollup/EmailRollupFlushRunner.ts +1 -0
  123. package/Server/Utils/Monitor/AffectedResourceList.ts +31 -73
  124. package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
  125. package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
  126. package/Server/Utils/Monitor/MonitorAlert.ts +83 -9
  127. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +181 -136
  128. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +5 -1
  129. package/Server/Utils/Monitor/MonitorIncident.ts +104 -9
  130. package/Server/Utils/Monitor/MonitorPayloadRedaction.ts +124 -7
  131. package/Server/Utils/Monitor/ProbeMonitorsNotification.ts +407 -0
  132. package/Server/Utils/Monitor/RootCauseList.ts +139 -0
  133. package/Server/Utils/OnCall/OnCallShiftReminderRunner.ts +1 -0
  134. package/Server/Utils/PushNotificationUtil.ts +45 -0
  135. package/Server/Utils/Rules/OwnerRuleAssignment.ts +40 -3
  136. package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
  137. package/Server/Utils/Runbook/RunbookExecutePermission.ts +56 -6
  138. package/Server/Utils/SessionReplay/SessionReplayReadService.ts +223 -33
  139. package/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.ts +559 -0
  140. package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
  141. package/Server/Utils/StartServer.ts +4 -3
  142. package/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.ts +528 -0
  143. package/Server/Utils/TwoFactorBackupCodeNotification.ts +1 -0
  144. package/Server/Utils/UserPermission/UserPermission.ts +16 -0
  145. package/Server/Utils/Workflow/OAuth2TokenClient.ts +704 -0
  146. package/Server/Utils/Workflow/WorkflowVariableOAuthToken.ts +318 -0
  147. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.ts +47 -7
  148. package/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.ts +57 -16
  149. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.ts +193 -214
  150. package/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.ts +57 -13
  151. package/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.ts +54 -17
  152. package/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.ts +179 -161
  153. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +281 -167
  154. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.ts +114 -0
  155. package/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.ts +895 -0
  156. package/Server/Utils/Workspace/Slack/Actions/ActionTypes.ts +7 -9
  157. package/Server/Utils/Workspace/Slack/Actions/Alert.ts +96 -227
  158. package/Server/Utils/Workspace/Slack/Actions/AlertEpisode.ts +93 -214
  159. package/Server/Utils/Workspace/Slack/Actions/Auth.ts +30 -3
  160. package/Server/Utils/Workspace/Slack/Actions/Authorization.ts +99 -0
  161. package/Server/Utils/Workspace/Slack/Actions/Incident.ts +117 -283
  162. package/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.ts +101 -196
  163. package/Server/Utils/Workspace/Slack/Actions/ReactionNote.ts +329 -0
  164. package/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.ts +111 -287
  165. package/Server/Utils/Workspace/Slack/Slack.ts +86 -17
  166. package/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  167. package/Server/Utils/Workspace/Workspace.ts +171 -54
  168. package/Server/Utils/Workspace/WorkspaceActionAuthorization.ts +252 -0
  169. package/Server/Utils/Workspace/WorkspaceBase.ts +39 -0
  170. package/Server/Utils/Workspace/WorkspaceOAuthState.ts +280 -0
  171. package/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.ts +96 -0
  172. package/Server/Utils/Workspace/WorkspaceReactionNote.ts +620 -0
  173. package/Tests/App/Dashboard/AttributesJSONDashboardSurfaces.test.tsx +496 -0
  174. package/Tests/App/Dashboard/AutoRemediationRulesTableCommandRunners.test.tsx +152 -0
  175. package/Tests/App/Dashboard/BreadcrumbCoverage.test.tsx +32 -0
  176. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +794 -0
  177. package/Tests/App/Dashboard/CreateOAuthWorkflowVariableModal.test.tsx +840 -0
  178. package/Tests/App/Dashboard/CreateWorkflowModal.test.tsx +653 -0
  179. package/Tests/App/Dashboard/DatabaseMonitorStepForm.test.tsx +197 -0
  180. package/Tests/App/Dashboard/DatabaseMonitorView.test.tsx +376 -0
  181. package/Tests/App/Dashboard/DisabledWarningRobustness.test.tsx +262 -0
  182. package/Tests/App/Dashboard/EventNotes.test.tsx +2080 -0
  183. package/Tests/App/Dashboard/EventNotesPages.test.tsx +486 -0
  184. package/Tests/App/Dashboard/EventNotesUtil.test.ts +933 -0
  185. package/Tests/App/Dashboard/ExceptionMonitorEnvironmentFilter.test.tsx +218 -0
  186. package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
  187. package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
  188. package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
  189. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +665 -0
  190. package/Tests/App/Dashboard/IncidentEpisodeFeedPublicNoteNotifyDefault.test.tsx +494 -0
  191. package/Tests/App/Dashboard/IncidentEpisodeOverviewNotifyDefault.test.tsx +706 -0
  192. package/Tests/App/Dashboard/IncidentFeedPublicNoteNotifyDefault.test.tsx +472 -0
  193. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +858 -0
  194. package/Tests/App/Dashboard/IncomingEmailAddressSettings.test.tsx +567 -0
  195. package/Tests/App/Dashboard/InvestigationClusterToolFormat.test.ts +241 -0
  196. package/Tests/App/Dashboard/InvestigationEvidenceKubectl.test.tsx +322 -0
  197. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
  198. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +606 -3
  199. package/Tests/App/Dashboard/InvestigationPanelClusterAccess.test.tsx +476 -0
  200. package/Tests/App/Dashboard/InvestigationRunDetailsKubectl.test.tsx +383 -0
  201. package/Tests/App/Dashboard/KubectlActivitySummary.test.tsx +366 -0
  202. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +2886 -0
  203. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +2688 -0
  204. package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +915 -0
  205. package/Tests/App/Dashboard/LayerDateTimeFieldTimezoneName.test.tsx +66 -0
  206. package/Tests/App/Dashboard/LogMonitorPreview.test.tsx +174 -0
  207. package/Tests/App/Dashboard/MonitorFeedRefresh.test.tsx +279 -0
  208. package/Tests/App/Dashboard/MonitorMetricQueryConfig.test.ts +244 -0
  209. package/Tests/App/Dashboard/MonitorOpenWorkCard.test.tsx +381 -0
  210. package/Tests/App/Dashboard/MonitorOpenWorkHook.test.tsx +784 -0
  211. package/Tests/App/Dashboard/MonitorOverviewData.test.tsx +2199 -0
  212. package/Tests/App/Dashboard/MonitorOverviewHero.test.tsx +1169 -0
  213. package/Tests/App/Dashboard/MonitorOverviewInput.test.ts +1127 -0
  214. package/Tests/App/Dashboard/MonitorOverviewPage.test.tsx +2136 -0
  215. package/Tests/App/Dashboard/MonitorOverviewSelectReadable.test.ts +368 -0
  216. package/Tests/App/Dashboard/MonitorOverviewStatBar.test.tsx +526 -0
  217. package/Tests/App/Dashboard/MonitorOverviewSupportingCards.test.tsx +542 -0
  218. package/Tests/App/Dashboard/MonitorOwnersCombine.test.ts +299 -0
  219. package/Tests/App/Dashboard/MonitorProbesCard.test.tsx +602 -0
  220. package/Tests/App/Dashboard/MonitorResponseTimeCard.test.tsx +386 -0
  221. package/Tests/App/Dashboard/MonitorSetupAndConnectionCards.test.tsx +612 -0
  222. package/Tests/App/Dashboard/MonitorStatusChangesCard.test.tsx +257 -0
  223. package/Tests/App/Dashboard/MonitorSummaryTestMonitorButton.test.tsx +360 -1
  224. package/Tests/App/Dashboard/MonitorUptimeHistoryCard.test.tsx +835 -0
  225. package/Tests/App/Dashboard/MonitorUptimeSummaryHook.test.tsx +971 -0
  226. package/Tests/App/Dashboard/MonitorViewLayout.test.tsx +580 -0
  227. package/Tests/App/Dashboard/OnCallLayerRestrictionTimesPreserved.test.tsx +441 -0
  228. package/Tests/App/Dashboard/OnCallNavbar.test.tsx +214 -0
  229. package/Tests/App/Dashboard/OnCallSchedulePreviewCalendarDisplay.test.tsx +1389 -0
  230. package/Tests/App/Dashboard/OnCallSchedulePreviewOverrides.test.tsx +205 -1
  231. package/Tests/App/Dashboard/OnCallScheduleTimeInputsSettingsZone.test.tsx +198 -0
  232. package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
  233. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +524 -0
  234. package/Tests/App/Dashboard/RemediationSuggestionCardApproval.test.tsx +702 -0
  235. package/Tests/App/Dashboard/RemoveUserFromProject.test.tsx +427 -0
  236. package/Tests/App/Dashboard/ResourceArchiveSettings.test.tsx +4 -0
  237. package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
  238. package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
  239. package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
  240. package/Tests/App/Dashboard/RumSessionReplaySideMenu.test.tsx +3 -1
  241. package/Tests/App/Dashboard/RunbookStepTypeMaps.test.ts +166 -0
  242. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +622 -0
  243. package/Tests/App/Dashboard/ScheduledMaintenanceChangeStateNotifyDefault.test.tsx +1491 -0
  244. package/Tests/App/Dashboard/ScheduledMaintenanceFeedPublicNoteNotifyDefault.test.tsx +489 -0
  245. package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
  246. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewNotifyDefault.test.tsx +909 -0
  247. package/Tests/App/Dashboard/ScheduledMaintenanceOverviewPage.test.tsx +14 -0
  248. package/Tests/App/Dashboard/ScheduledMaintenanceWindowStatsTranslation.test.tsx +307 -0
  249. package/Tests/App/Dashboard/SecurityEventAttributeColumnPicker.test.tsx +542 -0
  250. package/Tests/App/Dashboard/SecurityEventConnectionFormModal.test.tsx +174 -0
  251. package/Tests/App/Dashboard/SecurityEventConnectionsEmptyState.test.tsx +973 -212
  252. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +491 -52
  253. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +301 -0
  254. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +158 -1
  255. package/Tests/App/Dashboard/SecurityEventProviderTile.test.tsx +869 -0
  256. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +959 -94
  257. package/Tests/App/Dashboard/SecurityEventsNoResults.test.tsx +2 -0
  258. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +274 -1
  259. package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
  260. package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
  261. package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
  262. package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
  263. package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
  264. package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
  265. package/Tests/App/Dashboard/TeamMembershipRemoval.test.ts +900 -0
  266. package/Tests/App/Dashboard/TeamMembershipRemovalPages.test.tsx +460 -0
  267. package/Tests/App/Dashboard/TimezoneElements.test.tsx +321 -0
  268. package/Tests/App/Dashboard/TimezoneSelectButton.test.tsx +634 -0
  269. package/Tests/App/Dashboard/TraceExplorer.test.tsx +260 -0
  270. package/Tests/App/Dashboard/TraceMonitorPreview.test.tsx +182 -0
  271. package/Tests/App/Dashboard/UserTimezoneInit.test.tsx +544 -0
  272. package/Tests/App/Dashboard/WorkflowVariableModals.test.tsx +1630 -0
  273. package/Tests/App/Dashboard/WorkflowVariableRoutes.test.tsx +603 -0
  274. package/Tests/App/Dashboard/WorkflowVariableTokenStatus.test.tsx +589 -0
  275. package/Tests/App/Dashboard/WorkflowVariableUtil.test.ts +1543 -0
  276. package/Tests/App/Dashboard/WorkflowVariableView.test.tsx +3227 -0
  277. package/Tests/App/Dashboard/WorkflowVariablesTable.test.tsx +1277 -395
  278. package/Tests/App/StatusPage/StatusPageOverviewMonitorGroupUptime.test.tsx +714 -0
  279. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.NewYork.test.tsx +1009 -0
  280. package/Tests/App/StatusPage/StatusPageOverviewUptimeBars.test.tsx +1092 -0
  281. package/Tests/Models/DatabaseModels/DomainRoleTierCoverage.test.ts +5 -0
  282. package/Tests/Models/DatabaseModels/KubernetesClusterAiAccessColumns.test.ts +520 -0
  283. package/Tests/Models/DatabaseModels/MonitorSecretKeyColumnAccessControl.test.ts +66 -2
  284. package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
  285. package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
  286. package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
  287. package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
  288. package/Tests/Models/DatabaseModels/WorkspaceProjectAuthTokenAccessControl.test.ts +236 -0
  289. package/Tests/Models/IncidentEpisodePublicNoteNotifyColumnContract.test.ts +103 -0
  290. package/Tests/Models/IncidentPublicNoteNotifyColumnContract.test.ts +96 -0
  291. package/Tests/Models/ScheduledMaintenancePublicNoteNotifyColumnContract.test.ts +111 -0
  292. package/Tests/Server/API/AIInvestigationAPI.test.ts +976 -0
  293. package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +836 -0
  294. package/Tests/Server/API/CommonAPIAssertCanCreateTable.test.ts +565 -0
  295. package/Tests/Server/API/CommonAPIAssertCanReadTable.test.ts +282 -0
  296. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +1744 -0
  297. package/Tests/Server/API/LogHistogramAPI.test.ts +371 -0
  298. package/Tests/Server/API/MicrosoftTeamsLegacyWebhookRemoval.test.ts +125 -30
  299. package/Tests/Server/API/MicrosoftTeamsOAuthState.test.ts +1121 -0
  300. package/Tests/Server/API/MonitorUptimeSummaryAPI.test.ts +685 -0
  301. package/Tests/Server/API/SessionReplayAPI.test.ts +602 -1
  302. package/Tests/Server/API/SlackChannelCacheAPI.test.ts +358 -0
  303. package/Tests/Server/API/SlackOAuthState.test.ts +688 -0
  304. package/Tests/Server/API/StatusPageOverviewMonitorGroupUptime.test.ts +527 -0
  305. package/Tests/Server/API/StatusPageTestEmailReportAuth.test.ts +2 -0
  306. package/Tests/Server/API/StatusPageUptimeAPI.test.ts +427 -0
  307. package/Tests/Server/API/UserProjectsAPI.test.ts +4 -0
  308. package/Tests/Server/API/WorkflowVariableAPI.test.ts +404 -0
  309. package/Tests/Server/API/WorkspaceOAuthTestHelpers.ts +289 -0
  310. package/Tests/Server/API/WorkspaceSendTestNotificationRoutes.test.ts +2064 -0
  311. package/Tests/Server/Infrastructure/GlobalCache.test.ts +86 -0
  312. package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
  313. package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +589 -0
  314. package/Tests/Server/Infrastructure/Postgres/AddOAuth2WorkflowVariablesMigration.test.ts +254 -0
  315. package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
  316. package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
  317. package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
  318. package/Tests/Server/Middleware/BlockedUserMiddleware.test.ts +403 -0
  319. package/Tests/Server/Middleware/MasterAdminAuthorization.test.ts +13 -0
  320. package/Tests/Server/Middleware/PublicRouteUserMiddleware.test.ts +2 -0
  321. package/Tests/Server/Middleware/RemovedProjectMemberAuthorization.test.ts +469 -0
  322. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +77 -1
  323. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +211 -0
  324. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +358 -0
  325. package/Tests/Server/Middleware/UserAuthorization.test.ts +97 -0
  326. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +2 -0
  327. package/Tests/Server/Services/AccessTokenProjectUserGrant.test.ts +14 -2
  328. package/Tests/Server/Services/AccessTokenRemovedMemberAccess.test.ts +1044 -0
  329. package/Tests/Server/Services/AddOwnersIdempotency.test.ts +5 -0
  330. package/Tests/Server/Services/AlertEpisodeMemberCreatePermission.test.ts +139 -0
  331. package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +1361 -0
  332. package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +375 -0
  333. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +2384 -0
  334. package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
  335. package/Tests/Server/Services/FindOwnersProjectMembership.test.ts +267 -0
  336. package/Tests/Server/Services/InboundEmail/SendGridInboundProviderAddress.test.ts +90 -0
  337. package/Tests/Server/Services/IncidentEpisodeMemberCreatePermission.test.ts +143 -0
  338. package/Tests/Server/Services/IncidentEpisodePublicNoteNotifyDefault.test.ts +805 -0
  339. package/Tests/Server/Services/IncidentPublicNoteNotifyDefault.test.ts +724 -0
  340. package/Tests/Server/Services/IncidentRoleProjectMembership.test.ts +233 -0
  341. package/Tests/Server/Services/KubernetesClusterAiAccessAgentRunnerAssignments.test.ts +372 -0
  342. package/Tests/Server/Services/KubernetesClusterAiAccessBindingGuard.test.ts +1876 -0
  343. package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +620 -0
  344. package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +421 -0
  345. package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +3662 -0
  346. package/Tests/Server/Services/KubernetesClusterAiAccessSubjectClusters.test.ts +405 -0
  347. package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +975 -0
  348. package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +497 -0
  349. package/Tests/Server/Services/KubernetesClusterServiceDeleteSettlesRemediation.test.ts +328 -0
  350. package/Tests/Server/Services/LogAggregationService.test.ts +99 -0
  351. package/Tests/Server/Services/MonitorServiceIncomingEmailCustomAddress.test.ts +447 -0
  352. package/Tests/Server/Services/MonitorServiceProbeFlagSync.test.ts +1334 -0
  353. package/Tests/Server/Services/MonitorServiceProbeStatusGrouping.test.ts +1640 -0
  354. package/Tests/Server/Services/MonitorServiceRefreshCurrentStatus.test.ts +225 -0
  355. package/Tests/Server/Services/MonitorStatusBridgeProbePath.test.ts +8 -8
  356. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +264 -1
  357. package/Tests/Server/Services/MonitorStatusTimelineMergedDowntime.test.ts +284 -0
  358. package/Tests/Server/Services/MonitorUptimeSummaryService.test.ts +1043 -0
  359. package/Tests/Server/Services/NetworkDeviceRuleEngines.test.ts +5 -0
  360. package/Tests/Server/Services/OnCallUndeliverablePageOwnerMembership.test.ts +359 -0
  361. package/Tests/Server/Services/ProbeServiceDashboardLink.test.ts +191 -0
  362. package/Tests/Server/Services/ProjectOwnersProjectMembership.test.ts +221 -0
  363. package/Tests/Server/Services/RuleRun/IncidentAlertMaintenanceRuleEnginesRun.test.ts +5 -0
  364. package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
  365. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupARun.test.ts +28 -0
  366. package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +39 -1
  367. package/Tests/Server/Services/RunnerJobEnqueueAiCommandAgentRunner.test.ts +230 -0
  368. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +978 -0
  369. package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +866 -0
  370. package/Tests/Server/Services/RunnerJobSubmitResultRedaction.test.ts +322 -0
  371. package/Tests/Server/Services/RunnerJobSubmitResultUnstorableText.test.ts +357 -0
  372. package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +227 -0
  373. package/Tests/Server/Services/RunnerServiceAgentName.test.ts +581 -0
  374. package/Tests/Server/Services/ScheduledMaintenancePublicNoteNotifyDefault.test.ts +802 -0
  375. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +53 -0
  376. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1175 -0
  377. package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
  378. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
  379. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
  380. package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
  381. package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
  382. package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +174 -0
  383. package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
  384. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +1176 -1
  385. package/Tests/Server/Services/TeamMemberBillingSeatSync.test.ts +9 -0
  386. package/Tests/Server/Services/TeamMemberOnCallCleanup.test.ts +18 -0
  387. package/Tests/Server/Services/TeamMemberProjectMembership.test.ts +255 -0
  388. package/Tests/Server/Services/TeamMemberRemovalRevokesProjectAccess.test.ts +600 -0
  389. package/Tests/Server/Services/TeamMemberResourceCleanup.test.ts +731 -0
  390. package/Tests/Server/Services/TeamMemberWorkspaceAccountCleanup.test.ts +164 -0
  391. package/Tests/Server/Services/TraceAggregationService.test.ts +64 -0
  392. package/Tests/Server/Services/UserServiceBlockedUser.test.ts +293 -0
  393. package/Tests/Server/Services/WorkflowVariableOAuthHooks.test.ts +1016 -0
  394. package/Tests/Server/Services/WorkflowVariableOAuthPostgres.test.ts +543 -0
  395. package/Tests/Server/Services/WorkflowVariableRenameUniqueness.test.ts +16 -5
  396. package/Tests/Server/Services/WorkspaceNotificationRuleNoteDelivery.test.ts +473 -0
  397. package/Tests/Server/Services/WorkspaceNotificationRuleSendTestNotification.test.ts +3690 -0
  398. package/Tests/Server/Services/WorkspaceProjectAuthTokenMiscDataSecrets.test.ts +374 -0
  399. package/Tests/Server/Services/WorkspaceProjectAuthTokenSlackChannelCache.test.ts +143 -0
  400. package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
  401. package/Tests/Server/Types/Database/Permissions/WorkflowVariableOAuthColumnPermission.test.ts +250 -0
  402. package/Tests/Server/Types/Database/QueryHelperJsonContains.test.ts +96 -0
  403. package/Tests/Server/Types/Markdown.test.ts +1035 -1
  404. package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
  405. package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
  406. package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +285 -0
  407. package/Tests/Server/Utils/AI/CodeFix/CodeFixAgentAuth.test.ts +159 -1
  408. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +752 -0
  409. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +1840 -0
  410. package/Tests/Server/Utils/AI/KubectlJobRunner.test.ts +1067 -0
  411. package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +355 -0
  412. package/Tests/Server/Utils/AI/PostIncidentStatusUpdateTool.test.ts +496 -0
  413. package/Tests/Server/Utils/AI/RemediationCommandTools.test.ts +305 -0
  414. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +1365 -0
  415. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +639 -0
  416. package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +1585 -0
  417. package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +1065 -0
  418. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +2138 -1
  419. package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +1035 -0
  420. package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +517 -0
  421. package/Tests/Server/Utils/AI/ResourceTools.test.ts +27 -1
  422. package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
  423. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +1371 -24
  424. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorRollbackRace.test.ts +962 -0
  425. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +518 -0
  426. package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +939 -2
  427. package/Tests/Server/Utils/Database/ProjectScopedRelationReferences.test.ts +371 -0
  428. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +64 -0
  429. package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
  430. package/Tests/Server/Utils/Monitor/DatabaseMetricObservationRemediation.test.ts +102 -0
  431. package/Tests/Server/Utils/Monitor/MonitorAlertCriteriaReferences.test.ts +362 -0
  432. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +405 -0
  433. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1156 -0
  434. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
  435. package/Tests/Server/Utils/Monitor/MonitorEmailAddressRedaction.test.ts +255 -0
  436. package/Tests/Server/Utils/Monitor/MonitorIncidentCriteriaReferences.test.ts +347 -0
  437. package/Tests/Server/Utils/Monitor/MonitorIncidentMemberRoleMembership.test.ts +203 -0
  438. package/Tests/Server/Utils/Monitor/ProbeMonitorsNotification.test.ts +1147 -0
  439. package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
  440. package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +79 -0
  441. package/Tests/Server/Utils/ResourceFeed/ResourceFeedUtil.test.ts +21 -1
  442. package/Tests/Server/Utils/Rules/OwnerRuleAssignment.test.ts +155 -1
  443. package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
  444. package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
  445. package/Tests/Server/Utils/SessionReplay/SessionReplayReadServiceQueries.test.ts +288 -0
  446. package/Tests/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.test.ts +304 -0
  447. package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
  448. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +40 -3
  449. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
  450. package/Tests/Server/Utils/Workflow/OAuth2TokenClient.test.ts +702 -0
  451. package/Tests/Server/Utils/Workflow/OAuth2TokenClientHttpIntegration.test.ts +507 -0
  452. package/Tests/Server/Utils/Workflow/WorkflowVariableOAuthToken.test.ts +831 -0
  453. package/Tests/Server/Utils/Workspace/MicrosoftTeamsActionAuthorization.test.ts +63 -1
  454. package/Tests/Server/Utils/Workspace/MicrosoftTeamsAppAccessToken.test.ts +256 -0
  455. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChannelSend.test.ts +60 -0
  456. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChatActionAuthorization.test.ts +442 -0
  457. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +44 -2
  458. package/Tests/Server/Utils/Workspace/MicrosoftTeamsDirectMessage.test.ts +55 -0
  459. package/Tests/Server/Utils/Workspace/MicrosoftTeamsReactionNoteSync.test.ts +1522 -0
  460. package/Tests/Server/Utils/Workspace/MicrosoftTeamsServiceUrl.test.ts +130 -0
  461. package/Tests/Server/Utils/Workspace/MicrosoftTeamsTeamInstalls.test.ts +4 -4
  462. package/Tests/Server/Utils/Workspace/Slack/SlackActionAuthorization.test.ts +691 -0
  463. package/Tests/Server/Utils/Workspace/Slack/SlackMessageByTimestamp.test.ts +253 -0
  464. package/Tests/Server/Utils/Workspace/Slack/SlackReactionNote.test.ts +574 -0
  465. package/Tests/Server/Utils/Workspace/WorkspaceActionAuthorization.test.ts +488 -0
  466. package/Tests/Server/Utils/Workspace/WorkspaceCreateProjectReferences.test.ts +861 -0
  467. package/Tests/Server/Utils/Workspace/WorkspaceMessageAuthor.test.ts +635 -0
  468. package/Tests/Server/Utils/Workspace/WorkspaceOAuthState.test.ts +548 -0
  469. package/Tests/Server/Utils/Workspace/WorkspaceReactionNote.test.ts +839 -0
  470. package/Tests/Server/Utils/Workspace/WorkspaceSendErrorMessage.test.ts +725 -0
  471. package/Tests/Types/API/Route.test.ts +56 -0
  472. package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
  473. package/Tests/Types/AutoRemediation/AiRemediationCommandPlan.test.ts +283 -9
  474. package/Tests/Types/DateBrowserLocalWallClock.test.ts +280 -0
  475. package/Tests/Types/DateLocalShortMonthNameFallback.test.ts +389 -0
  476. package/Tests/Types/DateUserTimezone.test.ts +177 -4
  477. package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +306 -0
  478. package/Tests/Types/Kubernetes/KubernetesClusterAiAccess.test.ts +283 -0
  479. package/Tests/Types/Kubernetes/KubernetesRunnerPostureWriteScope.test.ts +68 -0
  480. package/Tests/Types/Monitor/DatabaseMonitor/SqlServerPlatform.test.ts +144 -0
  481. package/Tests/Types/Monitor/MonitorStepExceptionMonitor.test.ts +160 -0
  482. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +53 -0
  483. package/Tests/Types/Runbook/RunbookStepType.test.ts +91 -16
  484. package/Tests/Types/Runner/RunnerLiveStatus.test.ts +14 -3
  485. package/Tests/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.test.ts +15 -0
  486. package/Tests/Types/StatusPage/PublicNoteSubscriberNotificationDefault.test.ts +1868 -0
  487. package/Tests/Types/Timezone.test.ts +5 -0
  488. package/Tests/Types/TimezoneAlias.test.ts +1034 -0
  489. package/Tests/Types/Workflow/JiraTemplateFixtures.ts +833 -0
  490. package/Tests/Types/Workflow/JiraTemplateScripts.test.ts +5414 -0
  491. package/Tests/Types/Workflow/JiraTemplateSimulation.test.ts +4803 -0
  492. package/Tests/Types/Workflow/JiraTemplates.test.ts +5429 -0
  493. package/Tests/Types/Workflow/Templates.test.ts +79 -4
  494. package/Tests/Types/Workflow/WorkflowVariableOAuth.test.ts +520 -0
  495. package/Tests/Types/Workspace/WorkspaceNoteReaction.test.ts +177 -0
  496. package/Tests/UI/Components/AttributesJSON/AttributesJSONView.test.tsx +390 -0
  497. package/Tests/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.test.tsx +566 -0
  498. package/Tests/UI/Components/AttributesJSON/JSONHighlight.test.ts +131 -0
  499. package/Tests/UI/Components/BasicFormDropdownNormalization.test.tsx +276 -1
  500. package/Tests/UI/Components/Calendar/Calendar.test.tsx +1611 -0
  501. package/Tests/UI/Components/Calendar/CalendarDayLayout.test.ts +1486 -0
  502. package/Tests/UI/Components/Calendar/CalendarDayLayoutDst.test.ts +632 -0
  503. package/Tests/UI/Components/Calendar/CalendarDst.test.tsx +388 -0
  504. package/Tests/UI/Components/Charts/ChartGroupPlotFloor.test.tsx +170 -0
  505. package/Tests/UI/Components/Charts/HistogramSelection.test.ts +282 -0
  506. package/Tests/UI/Components/CustomTimeRangeModal.test.tsx +6 -0
  507. package/Tests/UI/Components/CustomTimeRangeModalTimezoneTranslation.test.tsx +285 -0
  508. package/Tests/UI/Components/Dropdown.test.tsx +999 -2
  509. package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
  510. package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
  511. package/Tests/UI/Components/Forms/FormFieldCheckboxTranslation.test.tsx +216 -0
  512. package/Tests/UI/Components/Forms/FormFieldTimezoneDescriptionTranslation.test.tsx +461 -0
  513. package/Tests/UI/Components/Forms/IncidentEpisodePublicNoteNotifyPayload.test.tsx +641 -0
  514. package/Tests/UI/Components/Forms/IncidentPublicNoteNotifyPayload.test.tsx +346 -0
  515. package/Tests/UI/Components/Forms/ScheduledMaintenancePublicNoteNotifyPayload.test.tsx +493 -0
  516. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +911 -2
  517. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.NewYork.test.tsx +730 -0
  518. package/Tests/UI/Components/Graphs/DayUptimeGraphTimezone.Tokyo.test.tsx +506 -0
  519. package/Tests/UI/Components/HistogramClickToZoom.test.tsx +619 -0
  520. package/Tests/UI/Components/Icon.test.tsx +26 -0
  521. package/Tests/UI/Components/LogDetailsPanelAttributesJSON.test.tsx +248 -0
  522. package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +47 -1
  523. package/Tests/UI/Components/LogsViewerSmallScreens.test.tsx +620 -0
  524. package/Tests/UI/Components/ModelPageModelChange.test.tsx +242 -3
  525. package/Tests/UI/Components/ModelTable/BaseModelTableDeleteConfirmation.test.tsx +521 -0
  526. package/Tests/UI/Components/MonitorGraphs/Uptime.test.tsx +406 -2
  527. package/Tests/UI/Components/MonitorGraphs/UptimeBarDayModal.test.tsx +169 -2
  528. package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
  529. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +266 -0
  530. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerSmallScreens.test.tsx +439 -0
  531. package/Tests/UI/Components/TimezoneDropdownLegacyValues.test.tsx +704 -0
  532. package/Tests/UI/Components/UseHistogramZoom.test.tsx +89 -1
  533. package/Tests/UI/Components/UseLogsHistogram.test.tsx +175 -0
  534. package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
  535. package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
  536. package/Tests/UI/Monitor/MonitorSummarySnapshotRender.test.tsx +5 -5
  537. package/Tests/UI/Telemetry/TelemetryDetailPanel.test.tsx +28 -0
  538. package/Tests/UI/Utils/ProjectUsersModelAPI.test.ts +51 -0
  539. package/Tests/UI/Utils/Timezone.test.ts +747 -33
  540. package/Tests/UI/Workspace/SendTestNotificationButton.test.tsx +1854 -0
  541. package/Tests/UI/Workspace/WorkspaceCardsSendTestNotification.test.tsx +1864 -0
  542. package/Tests/Utils/AI/InvestigationReport.test.ts +435 -7
  543. package/Tests/Utils/AiRemediation/KubectlAllowlistValidatorParity.test.ts +1084 -0
  544. package/Tests/Utils/AiRemediation/KubectlOutputRedactor.test.ts +2531 -0
  545. package/Tests/Utils/AiRemediation/KubectlPolicy.test.ts +1895 -0
  546. package/Tests/Utils/AiRemediation/KubectlPolicyAllowlist.test.ts +428 -0
  547. package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +828 -0
  548. package/Tests/Utils/AiRemediation/KubectlPolicyCustomResourceScope.test.ts +573 -0
  549. package/Tests/Utils/AiRemediation/KubectlPolicyDenials.test.ts +1525 -0
  550. package/Tests/Utils/AiRemediation/KubectlPolicyExposeOverrides.test.ts +275 -0
  551. package/Tests/Utils/AiRemediation/KubectlPolicyNodePatch.test.ts +428 -0
  552. package/Tests/Utils/AiRemediation/KubectlPolicyObjectWords.test.ts +195 -0
  553. package/Tests/Utils/AiRemediation/KubectlPolicyPatchParents.test.ts +637 -0
  554. package/Tests/Utils/AiRemediation/KubectlPolicyPodSecurityBaseline.test.ts +322 -0
  555. package/Tests/Utils/AiRemediation/KubectlPolicySafeWriteScope.test.ts +1026 -0
  556. package/Tests/Utils/AiRemediation/KubectlWaitBudget.test.ts +267 -0
  557. package/Tests/Utils/AiRemediation/KubectlWriteScope.test.ts +390 -0
  558. package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +777 -0
  559. package/Tests/Utils/AiRemediation/KubectlWriteScopeClusterScoped.test.ts +613 -0
  560. package/Tests/Utils/AiRemediation/KubectlWriteScopeEntryPoint.test.ts +576 -0
  561. package/Tests/Utils/AiRemediation/KubectlWriteScopeKubectlSpellings.test.ts +752 -0
  562. package/Tests/Utils/AiRemediation/KubectlWriteScopeObjectWords.test.ts +358 -0
  563. package/Tests/Utils/AiRemediation/KubectlWriteScopeOverrides.test.ts +293 -0
  564. package/Tests/Utils/AiRemediation/KubectlWriteScopeParityCases.ts +598 -0
  565. package/Tests/Utils/AiRemediation/KubectlWriteScopePolicyParity.test.ts +403 -0
  566. package/Tests/Utils/Dashboard/DashboardClockComponent.test.ts +154 -5
  567. package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
  568. package/Tests/Utils/Monitor/IncomingEmailMonitorAddress.test.ts +478 -0
  569. package/Tests/Utils/Monitor/MonitorCheckScheduleUtil.test.ts +646 -0
  570. package/Tests/Utils/Monitor/MonitorOverviewCriteriaUtil.test.ts +292 -0
  571. package/Tests/Utils/Monitor/MonitorOverviewFamily.test.ts +274 -0
  572. package/Tests/Utils/Monitor/MonitorOverviewPresentationUtil.test.ts +3100 -0
  573. package/Tests/Utils/Monitor/MonitorOverviewProbeUtil.test.ts +1412 -0
  574. package/Tests/Utils/Monitor/MonitorOverviewTargetUtil.test.ts +374 -0
  575. package/Tests/Utils/Monitor/MonitorStatusHistoryUtil.test.ts +332 -0
  576. package/Tests/Utils/Monitor/MonitorUptimeSummaryUtil.test.ts +946 -0
  577. package/Tests/Utils/Rum/SessionIdentity.test.ts +94 -0
  578. package/Tests/Utils/Rum/SessionReplayWafCompatibility.test.ts +840 -0
  579. package/Tests/Utils/Rum/SessionReplayWireEncoding.test.ts +208 -0
  580. package/Tests/Utils/Rum/UserFlow.test.ts +1010 -0
  581. package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
  582. package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
  583. package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
  584. package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
  585. package/Tests/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.test.ts +217 -0
  586. package/Tests/Utils/StatusPage/ResourceUptime.test.ts +1272 -1
  587. package/Tests/Utils/StatusPage/UptimeDailyAggregateTotals.test.ts +298 -0
  588. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +649 -1
  589. package/Tests/Utils/StatusPage/UptimeDailyAggregateWindow.test.ts +314 -0
  590. package/Tests/Utils/Telemetry/AttributesJSON.test.ts +454 -0
  591. package/Tests/Utils/Uptime/DayUptimeGraphUtil.test.ts +418 -2
  592. package/Tests/Utils/Uptime/DayUptimeGraphUtilMidnightDst.test.ts +160 -0
  593. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Auckland.test.ts +45 -0
  594. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Kolkata.test.ts +40 -0
  595. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.London.test.ts +147 -0
  596. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.NewYork.test.ts +48 -0
  597. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezone.Tokyo.test.ts +39 -0
  598. package/Tests/Utils/Uptime/DayUptimeGraphUtilTimezoneCases.ts +1015 -0
  599. package/Tests/Utils/Uptime/UptimeUtil.test.ts +75 -0
  600. package/Tests/Utils/Uptime/UptimeUtilChronologicalOrder.test.ts +1279 -0
  601. package/Types/API/Route.ts +19 -2
  602. package/Types/API/URL.ts +26 -2
  603. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +203 -5
  604. package/Types/Date.ts +121 -7
  605. package/Types/Email/EmailMessage.ts +8 -0
  606. package/Types/Email/EmailTemplateType.ts +1 -0
  607. package/Types/Exception/ExceptionMessages.ts +1 -0
  608. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +488 -0
  609. package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +54 -0
  610. package/Types/Kubernetes/KubernetesClusterAiAccessToolNames.ts +17 -0
  611. package/Types/Monitor/DatabaseMonitor/DatabaseMonitorResponse.ts +9 -0
  612. package/Types/Monitor/DatabaseMonitor/SqlServerPlatform.ts +117 -0
  613. package/Types/Monitor/KubernetesAlertTemplates.ts +6 -5
  614. package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
  615. package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
  616. package/Types/Monitor/MonitorStepExceptionMonitor.ts +56 -0
  617. package/Types/Monitor/MonitorUptimeSummary.ts +113 -0
  618. package/Types/Monitor/Recommendation/MonitorRecommendationUtil.ts +11 -0
  619. package/Types/Permission.ts +90 -0
  620. package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
  621. package/Types/Rules/RuleRun.ts +4 -0
  622. package/Types/Rum/SessionReplay.ts +55 -2
  623. package/Types/Rum/SessionReplayApi.ts +44 -1
  624. package/Types/Rum/UserFlow.ts +187 -0
  625. package/Types/Runbook/RunbookStepType.ts +10 -0
  626. package/Types/Runbook/RunnerJobOrigin.ts +15 -0
  627. package/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.ts +6 -2
  628. package/Types/StatusPage/MergedDowntimeTotals.ts +17 -0
  629. package/Types/StatusPage/PublicNoteSubscriberNotificationDefault.ts +148 -0
  630. package/Types/StatusPage/UptimeDailyAggregate.ts +15 -0
  631. package/Types/Telemetry/TelemetryIngestSurface.ts +9 -0
  632. package/Types/Timezone.ts +5 -0
  633. package/Types/TimezoneAlias.ts +385 -0
  634. package/Types/Workflow/Templates.ts +3041 -2
  635. package/Types/Workflow/WorkflowVariableOAuth.ts +476 -0
  636. package/Types/Workspace/WorkspaceNoteReaction.ts +132 -0
  637. package/Typings/Index.d.ts +24 -0
  638. package/UI/Components/AttributesJSON/AttributesJSONPreferences.ts +175 -0
  639. package/UI/Components/AttributesJSON/AttributesJSONView.tsx +138 -0
  640. package/UI/Components/AttributesJSON/AttributesViewToggle.tsx +79 -0
  641. package/UI/Components/AttributesJSON/BracesGlyph.tsx +30 -0
  642. package/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.tsx +491 -0
  643. package/UI/Components/AttributesJSON/JSONHighlight.ts +77 -0
  644. package/UI/Components/Calendar/Calendar.css +83 -0
  645. package/UI/Components/Calendar/Calendar.tsx +136 -7
  646. package/UI/Components/Calendar/CalendarDayLayout.ts +236 -0
  647. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +23 -1
  648. package/UI/Components/Charts/Utils/HistogramSelection.ts +117 -0
  649. package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +269 -0
  650. package/UI/Components/Charts/Utils/useHistogramZoom.ts +26 -2
  651. package/UI/Components/Date/CustomTimeRangeModal.tsx +26 -3
  652. package/UI/Components/Dropdown/Dropdown.tsx +58 -9
  653. package/UI/Components/Feed/FeedOptions.ts +427 -0
  654. package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
  655. package/UI/Components/Feed/useFeedItems.ts +28 -9
  656. package/UI/Components/Feed/useFeedOptions.ts +225 -0
  657. package/UI/Components/Forms/Fields/FormField.tsx +49 -14
  658. package/UI/Components/Graphs/DayUptimeGraph.tsx +166 -25
  659. package/UI/Components/Graphs/UptimeBarTooltip.tsx +10 -2
  660. package/UI/Components/Graphs/UptimeDaySummary.tsx +8 -0
  661. package/UI/Components/Icon/Icon.tsx +1 -1
  662. package/UI/Components/LogsViewer/LogsViewer.tsx +52 -5
  663. package/UI/Components/LogsViewer/components/ColumnSelector.tsx +13 -2
  664. package/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.tsx +13 -1
  665. package/UI/Components/LogsViewer/components/LogDetailsPanel.tsx +91 -76
  666. package/UI/Components/LogsViewer/components/LogsFacetSidebar.tsx +15 -1
  667. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +28 -106
  668. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +54 -6
  669. package/UI/Components/LogsViewer/components/SavedViewsDropdown.tsx +8 -2
  670. package/UI/Components/LogsViewer/useLogsHistogram.ts +39 -6
  671. package/UI/Components/ModelTable/BaseModelTable.tsx +66 -14
  672. package/UI/Components/MonitorGraphs/Uptime.tsx +12 -0
  673. package/UI/Components/MonitorGraphs/UptimeBarDayModal.tsx +10 -2
  674. package/UI/Components/Page/ModelPage.tsx +59 -3
  675. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +69 -5
  676. package/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.tsx +12 -1
  677. package/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.tsx +15 -1
  678. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +36 -104
  679. package/UI/Components/TelemetryViewer/components/TelemetrySearchBar.tsx +9 -1
  680. package/UI/Utils/ModelAPI/ProjectUsersModelAPI.ts +19 -1
  681. package/UI/Utils/Timezone.ts +69 -28
  682. package/Utils/AI/InvestigationReport.ts +195 -25
  683. package/Utils/AiRemediation/KubectlOutputRedactor.ts +1724 -0
  684. package/Utils/AiRemediation/KubectlPolicy.ts +4136 -0
  685. package/Utils/AiRemediation/KubectlWaitBudget.ts +156 -0
  686. package/Utils/AiRemediation/KubectlWriteScope.ts +1964 -0
  687. package/Utils/Dashboard/Components/DashboardClockComponent.ts +7 -6
  688. package/Utils/LabelRuleImportExport.ts +27 -9
  689. package/Utils/Monitor/IncomingEmailMonitorAddress.ts +292 -0
  690. package/Utils/Monitor/MetricValueFormatter.ts +2 -2
  691. package/Utils/Monitor/MonitorCheckScheduleUtil.ts +654 -0
  692. package/Utils/Monitor/MonitorOverviewCriteriaUtil.ts +188 -0
  693. package/Utils/Monitor/MonitorOverviewFamily.ts +263 -0
  694. package/Utils/Monitor/MonitorOverviewPresentationUtil.ts +1958 -0
  695. package/Utils/Monitor/MonitorOverviewProbeUtil.ts +979 -0
  696. package/Utils/Monitor/MonitorOverviewTargetUtil.ts +299 -0
  697. package/Utils/Monitor/MonitorStatusHistoryUtil.ts +201 -0
  698. package/Utils/Monitor/MonitorUptimeSummaryUtil.ts +638 -0
  699. package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
  700. package/Utils/Rum/SessionIdentity.ts +44 -0
  701. package/Utils/Rum/SessionReplayWireEncoding.ts +137 -0
  702. package/Utils/Rum/UserFlow.ts +1527 -0
  703. package/Utils/Slo/SloDuration.ts +22 -6
  704. package/Utils/Slo/SloHealth.ts +8 -7
  705. package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
  706. package/Utils/Slo/SloOverviewText.ts +33 -0
  707. package/Utils/Slo/SloProjection.ts +4 -3
  708. package/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.ts +107 -0
  709. package/Utils/StatusPage/ResourceUptime.ts +99 -0
  710. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +197 -0
  711. package/Utils/Telemetry/AttributesJSON.ts +367 -0
  712. package/Utils/Uptime/DayUptimeGraphUtil.ts +165 -0
  713. package/Utils/Uptime/UptimeUtil.ts +122 -38
  714. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js +8 -1
  715. package/build/dist/Models/DatabaseModels/AlertEpisodeMember.js.map +1 -1
  716. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js +62 -0
  717. package/build/dist/Models/DatabaseModels/AutoRemediationSuggestion.js.map +1 -1
  718. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js +8 -1
  719. package/build/dist/Models/DatabaseModels/IncidentEpisodeMember.js.map +1 -1
  720. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +10 -3
  721. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  722. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +10 -3
  723. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  724. package/build/dist/Models/DatabaseModels/Index.js +4 -0
  725. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  726. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +434 -0
  727. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  728. package/build/dist/Models/DatabaseModels/Monitor.js +49 -0
  729. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  730. package/build/dist/Models/DatabaseModels/Runner.js +4 -4
  731. package/build/dist/Models/DatabaseModels/Runner.js.map +1 -1
  732. package/build/dist/Models/DatabaseModels/RunnerJob.js +66 -0
  733. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  734. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +11 -3
  735. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  736. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
  737. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
  738. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
  739. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
  740. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
  741. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
  742. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
  743. package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
  744. package/build/dist/Models/DatabaseModels/WorkflowVariable.js +487 -3
  745. package/build/dist/Models/DatabaseModels/WorkflowVariable.js.map +1 -1
  746. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js +64 -16
  747. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  748. package/build/dist/Server/API/AIInvestigationAPI.js +205 -0
  749. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  750. package/build/dist/Server/API/AutoRemediationAPI.js +115 -2
  751. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  752. package/build/dist/Server/API/CommonAPI.js +49 -0
  753. package/build/dist/Server/API/CommonAPI.js.map +1 -1
  754. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +564 -0
  755. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -0
  756. package/build/dist/Server/API/MicrosoftTeamsAPI.js +465 -176
  757. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  758. package/build/dist/Server/API/MonitorAPI.js +107 -1
  759. package/build/dist/Server/API/MonitorAPI.js.map +1 -1
  760. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js +5 -16
  761. package/build/dist/Server/API/OnCallScheduleTimelineAPI.js.map +1 -1
  762. package/build/dist/Server/API/SlackAPI.js +322 -78
  763. package/build/dist/Server/API/SlackAPI.js.map +1 -1
  764. package/build/dist/Server/API/StatusPageAPI.js +123 -17
  765. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  766. package/build/dist/Server/API/TelemetryAPI.js +144 -5
  767. package/build/dist/Server/API/TelemetryAPI.js.map +1 -1
  768. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js +1 -0
  769. package/build/dist/Server/API/UserTwoFactorBackupCodeAPI.js.map +1 -1
  770. package/build/dist/Server/API/WorkflowVariableAPI.js +109 -0
  771. package/build/dist/Server/API/WorkflowVariableAPI.js.map +1 -0
  772. package/build/dist/Server/Infrastructure/GlobalCache.js +29 -0
  773. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  774. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
  775. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
  776. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
  777. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
  778. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js +38 -0
  779. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794300000000-AddOAuth2WorkflowVariables.js.map +1 -0
  780. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js +54 -0
  781. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794400000000-AddKubernetesClusterAiAccess.js.map +1 -0
  782. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js +14 -0
  783. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794500000000-AddIncomingEmailCustomAddressToMonitor.js.map +1 -0
  784. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js +12 -0
  785. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794600000000-AddAuthTokenExpiresAtToWorkspaceProjectAuthToken.js.map +1 -0
  786. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js +32 -0
  787. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794700000000-RemoveAppAccessTokenFromWorkspaceProjectAuthTokenMiscData.js.map +1 -0
  788. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +14 -0
  789. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  790. package/build/dist/Server/Middleware/MasterAdminAuthorization.js +21 -0
  791. package/build/dist/Server/Middleware/MasterAdminAuthorization.js.map +1 -1
  792. package/build/dist/Server/Middleware/TelemetryIngest.js +32 -2
  793. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  794. package/build/dist/Server/Middleware/UserAuthorization.js +39 -6
  795. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  796. package/build/dist/Server/Services/AIAgentService.js +1 -0
  797. package/build/dist/Server/Services/AIAgentService.js.map +1 -1
  798. package/build/dist/Server/Services/AccessTokenService.js +87 -42
  799. package/build/dist/Server/Services/AccessTokenService.js.map +1 -1
  800. package/build/dist/Server/Services/AlertEpisodeMemberService.js +4 -0
  801. package/build/dist/Server/Services/AlertEpisodeMemberService.js.map +1 -1
  802. package/build/dist/Server/Services/AlertEpisodeService.js +12 -1
  803. package/build/dist/Server/Services/AlertEpisodeService.js.map +1 -1
  804. package/build/dist/Server/Services/AlertService.js +110 -23
  805. package/build/dist/Server/Services/AlertService.js.map +1 -1
  806. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js +716 -30
  807. package/build/dist/Server/Services/AutoRemediationRuleEngineService.js.map +1 -1
  808. package/build/dist/Server/Services/AutoRemediationRuleService.js +100 -0
  809. package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
  810. package/build/dist/Server/Services/BillingService.js +1 -0
  811. package/build/dist/Server/Services/BillingService.js.map +1 -1
  812. package/build/dist/Server/Services/DatabaseService.js +7 -0
  813. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  814. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js +11 -16
  815. package/build/dist/Server/Services/InboundEmail/Providers/SendGridInboundProvider.js.map +1 -1
  816. package/build/dist/Server/Services/IncidentEpisodeMemberService.js +4 -0
  817. package/build/dist/Server/Services/IncidentEpisodeMemberService.js.map +1 -1
  818. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +48 -0
  819. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  820. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js +21 -0
  821. package/build/dist/Server/Services/IncidentEpisodeRoleMemberService.js.map +1 -1
  822. package/build/dist/Server/Services/IncidentEpisodeService.js +12 -1
  823. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  824. package/build/dist/Server/Services/IncidentGroupingEngineService.js +8 -0
  825. package/build/dist/Server/Services/IncidentGroupingEngineService.js.map +1 -1
  826. package/build/dist/Server/Services/IncidentMemberService.js +14 -0
  827. package/build/dist/Server/Services/IncidentMemberService.js.map +1 -1
  828. package/build/dist/Server/Services/IncidentPublicNoteService.js +48 -0
  829. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  830. package/build/dist/Server/Services/IncidentService.js +99 -21
  831. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  832. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  833. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  834. package/build/dist/Server/Services/IncidentTemplateService.js +68 -4
  835. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  836. package/build/dist/Server/Services/Index.js +4 -0
  837. package/build/dist/Server/Services/Index.js.map +1 -1
  838. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +1470 -0
  839. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -0
  840. package/build/dist/Server/Services/KubernetesClusterService.js +1097 -0
  841. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  842. package/build/dist/Server/Services/LogAggregationService.js +14 -6
  843. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  844. package/build/dist/Server/Services/MonitorService.js +490 -50
  845. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  846. package/build/dist/Server/Services/MonitorStatusTimelineService.js +540 -3
  847. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  848. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js +2 -0
  849. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleScheduleService.js.map +1 -1
  850. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js +2 -0
  851. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleTeamService.js.map +1 -1
  852. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js +2 -0
  853. package/build/dist/Server/Services/OnCallDutyPolicyEscalationRuleUserService.js.map +1 -1
  854. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js +3 -0
  855. package/build/dist/Server/Services/OnCallDutyPolicyScheduleService.js.map +1 -1
  856. package/build/dist/Server/Services/OnCallNotificationAlertingService.js +29 -7
  857. package/build/dist/Server/Services/OnCallNotificationAlertingService.js.map +1 -1
  858. package/build/dist/Server/Services/OnCallSetupReminderService.js +1 -0
  859. package/build/dist/Server/Services/OnCallSetupReminderService.js.map +1 -1
  860. package/build/dist/Server/Services/ProbeService.js +7 -1
  861. package/build/dist/Server/Services/ProbeService.js.map +1 -1
  862. package/build/dist/Server/Services/ProjectService.js +11 -1
  863. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  864. package/build/dist/Server/Services/RunbookCredentialService.js +24 -0
  865. package/build/dist/Server/Services/RunbookCredentialService.js.map +1 -1
  866. package/build/dist/Server/Services/RunbookSecretService.js +44 -0
  867. package/build/dist/Server/Services/RunbookSecretService.js.map +1 -1
  868. package/build/dist/Server/Services/RunnerJobService.js +641 -21
  869. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  870. package/build/dist/Server/Services/RunnerService.js +344 -5
  871. package/build/dist/Server/Services/RunnerService.js.map +1 -1
  872. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +48 -0
  873. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  874. package/build/dist/Server/Services/ScheduledMaintenanceService.js +102 -20
  875. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  876. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js +67 -4
  877. package/build/dist/Server/Services/ScheduledMaintenanceTemplateService.js.map +1 -1
  878. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
  879. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
  880. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
  881. package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
  882. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
  883. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
  884. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
  885. package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
  886. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
  887. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
  888. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
  889. package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
  890. package/build/dist/Server/Services/ServiceLevelObjectiveService.js +33 -1
  891. package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
  892. package/build/dist/Server/Services/StatusPagePrivateUserService.js +1 -0
  893. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  894. package/build/dist/Server/Services/StatusPageService.js +230 -32
  895. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  896. package/build/dist/Server/Services/StatusPageSubscriberService.js +4 -0
  897. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  898. package/build/dist/Server/Services/TeamMemberService.js +270 -11
  899. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  900. package/build/dist/Server/Services/TraceAggregationService.js +10 -6
  901. package/build/dist/Server/Services/TraceAggregationService.js.map +1 -1
  902. package/build/dist/Server/Services/UserEmailService.js +1 -0
  903. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  904. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1 -0
  905. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -1
  906. package/build/dist/Server/Services/UserNotificationRuleAdminService.js +1 -0
  907. package/build/dist/Server/Services/UserNotificationRuleAdminService.js.map +1 -1
  908. package/build/dist/Server/Services/UserNotificationRuleService.js +4 -0
  909. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  910. package/build/dist/Server/Services/UserService.js +107 -1
  911. package/build/dist/Server/Services/UserService.js.map +1 -1
  912. package/build/dist/Server/Services/WorkflowVariableService.js +396 -7
  913. package/build/dist/Server/Services/WorkflowVariableService.js.map +1 -1
  914. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js +463 -7
  915. package/build/dist/Server/Services/WorkspaceNotificationRuleService.js.map +1 -1
  916. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js +144 -2
  917. package/build/dist/Server/Services/WorkspaceProjectAuthTokenService.js.map +1 -1
  918. package/build/dist/Server/Types/Database/QueryHelper.js +20 -0
  919. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  920. package/build/dist/Server/Types/Markdown.js +394 -27
  921. package/build/dist/Server/Types/Markdown.js.map +1 -1
  922. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
  923. package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
  924. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +123 -0
  925. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -0
  926. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +344 -0
  927. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -0
  928. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +587 -0
  929. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -0
  930. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js +18 -2
  931. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentAuth.js.map +1 -1
  932. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +1380 -239
  933. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  934. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +1099 -68
  935. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  936. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +88 -6
  937. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  938. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +45 -11
  939. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  940. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +41 -11
  941. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  942. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js +11 -4
  943. package/build/dist/Server/Utils/AI/Toolbox/AIActionTools.js.map +1 -1
  944. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js +4 -2
  945. package/build/dist/Server/Utils/AI/Toolbox/ResourceTools.js.map +1 -1
  946. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
  947. package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
  948. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +997 -141
  949. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  950. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js +299 -4
  951. package/build/dist/Server/Utils/AutoRemediation/RemediationVerifier.js.map +1 -1
  952. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js +120 -0
  953. package/build/dist/Server/Utils/Database/AffectedResourceRelations.js.map +1 -0
  954. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js +160 -1
  955. package/build/dist/Server/Utils/Database/ProjectScopedReferenceValidator.js.map +1 -1
  956. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js +1 -0
  957. package/build/dist/Server/Utils/EmailRollup/EmailRollupFlushRunner.js.map +1 -1
  958. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +22 -51
  959. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -1
  960. package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
  961. package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
  962. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +59 -12
  963. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  964. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +139 -109
  965. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  966. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +5 -1
  967. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  968. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +84 -22
  969. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  970. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js +70 -5
  971. package/build/dist/Server/Utils/Monitor/MonitorPayloadRedaction.js.map +1 -1
  972. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js +249 -0
  973. package/build/dist/Server/Utils/Monitor/ProbeMonitorsNotification.js.map +1 -0
  974. package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
  975. package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
  976. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js +1 -0
  977. package/build/dist/Server/Utils/OnCall/OnCallShiftReminderRunner.js.map +1 -1
  978. package/build/dist/Server/Utils/PushNotificationUtil.js +27 -0
  979. package/build/dist/Server/Utils/PushNotificationUtil.js.map +1 -1
  980. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js +26 -3
  981. package/build/dist/Server/Utils/Rules/OwnerRuleAssignment.js.map +1 -1
  982. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
  983. package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
  984. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js +38 -3
  985. package/build/dist/Server/Utils/Runbook/RunbookExecutePermission.js.map +1 -1
  986. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js +143 -23
  987. package/build/dist/Server/Utils/SessionReplay/SessionReplayReadService.js.map +1 -1
  988. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js +406 -0
  989. package/build/dist/Server/Utils/SessionReplay/SessionReplayUserFlowReadService.js.map +1 -0
  990. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
  991. package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
  992. package/build/dist/Server/Utils/StartServer.js +4 -3
  993. package/build/dist/Server/Utils/StartServer.js.map +1 -1
  994. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js +382 -0
  995. package/build/dist/Server/Utils/TeamMember/ProjectLeaveResourceCleanup.js.map +1 -0
  996. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js +1 -0
  997. package/build/dist/Server/Utils/TwoFactorBackupCodeNotification.js.map +1 -1
  998. package/build/dist/Server/Utils/UserPermission/UserPermission.js +10 -0
  999. package/build/dist/Server/Utils/UserPermission/UserPermission.js.map +1 -1
  1000. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +447 -0
  1001. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -0
  1002. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js +202 -0
  1003. package/build/dist/Server/Utils/Workflow/WorkflowVariableOAuthToken.js.map +1 -0
  1004. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js +39 -1
  1005. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Alert.js.map +1 -1
  1006. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js +44 -4
  1007. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/AlertEpisode.js.map +1 -1
  1008. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js +150 -191
  1009. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Incident.js.map +1 -1
  1010. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js +44 -4
  1011. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/IncidentEpisode.js.map +1 -1
  1012. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js +39 -17
  1013. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/Monitor.js.map +1 -1
  1014. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js +151 -145
  1015. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/Actions/ScheduledMaintenance.js.map +1 -1
  1016. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +221 -127
  1017. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  1018. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js +91 -0
  1019. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeamsServiceUrl.js.map +1 -0
  1020. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js +673 -0
  1021. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/ReactionNoteSync.js.map +1 -0
  1022. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js +3 -9
  1023. package/build/dist/Server/Utils/Workspace/Slack/Actions/ActionTypes.js.map +1 -1
  1024. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js +65 -166
  1025. package/build/dist/Server/Utils/Workspace/Slack/Actions/Alert.js.map +1 -1
  1026. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js +63 -157
  1027. package/build/dist/Server/Utils/Workspace/Slack/Actions/AlertEpisode.js.map +1 -1
  1028. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js +23 -3
  1029. package/build/dist/Server/Utils/Workspace/Slack/Actions/Auth.js.map +1 -1
  1030. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js +92 -0
  1031. package/build/dist/Server/Utils/Workspace/Slack/Actions/Authorization.js.map +1 -0
  1032. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js +81 -210
  1033. package/build/dist/Server/Utils/Workspace/Slack/Actions/Incident.js.map +1 -1
  1034. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js +68 -138
  1035. package/build/dist/Server/Utils/Workspace/Slack/Actions/IncidentEpisode.js.map +1 -1
  1036. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js +240 -0
  1037. package/build/dist/Server/Utils/Workspace/Slack/Actions/ReactionNote.js.map +1 -0
  1038. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js +85 -212
  1039. package/build/dist/Server/Utils/Workspace/Slack/Actions/ScheduledMaintenance.js.map +1 -1
  1040. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +60 -17
  1041. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  1042. package/build/dist/Server/Utils/Workspace/Slack/app-manifest.json +2 -0
  1043. package/build/dist/Server/Utils/Workspace/Workspace.js +134 -41
  1044. package/build/dist/Server/Utils/Workspace/Workspace.js.map +1 -1
  1045. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js +197 -0
  1046. package/build/dist/Server/Utils/Workspace/WorkspaceActionAuthorization.js.map +1 -0
  1047. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js +32 -0
  1048. package/build/dist/Server/Utils/Workspace/WorkspaceBase.js.map +1 -1
  1049. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js +199 -0
  1050. package/build/dist/Server/Utils/Workspace/WorkspaceOAuthState.js.map +1 -0
  1051. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js +91 -0
  1052. package/build/dist/Server/Utils/Workspace/WorkspaceProjectReferenceValidator.js.map +1 -0
  1053. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js +450 -0
  1054. package/build/dist/Server/Utils/Workspace/WorkspaceReactionNote.js.map +1 -0
  1055. package/build/dist/Types/API/Route.js +18 -2
  1056. package/build/dist/Types/API/Route.js.map +1 -1
  1057. package/build/dist/Types/API/URL.js +23 -2
  1058. package/build/dist/Types/API/URL.js.map +1 -1
  1059. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +103 -5
  1060. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  1061. package/build/dist/Types/Date.js +97 -7
  1062. package/build/dist/Types/Date.js.map +1 -1
  1063. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  1064. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  1065. package/build/dist/Types/Exception/ExceptionMessages.js +1 -0
  1066. package/build/dist/Types/Exception/ExceptionMessages.js.map +1 -1
  1067. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +245 -0
  1068. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -0
  1069. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +49 -0
  1070. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -0
  1071. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js +16 -0
  1072. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessToolNames.js.map +1 -0
  1073. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js +104 -0
  1074. package/build/dist/Types/Monitor/DatabaseMonitor/SqlServerPlatform.js.map +1 -0
  1075. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js +6 -5
  1076. package/build/dist/Types/Monitor/KubernetesAlertTemplates.js.map +1 -1
  1077. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js +32 -0
  1078. package/build/dist/Types/Monitor/MonitorStepExceptionMonitor.js.map +1 -1
  1079. package/build/dist/Types/Monitor/MonitorUptimeSummary.js +52 -0
  1080. package/build/dist/Types/Monitor/MonitorUptimeSummary.js.map +1 -0
  1081. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js +9 -1
  1082. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationUtil.js.map +1 -1
  1083. package/build/dist/Types/Permission.js +84 -0
  1084. package/build/dist/Types/Permission.js.map +1 -1
  1085. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
  1086. package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
  1087. package/build/dist/Types/Rules/RuleRun.js +4 -0
  1088. package/build/dist/Types/Rules/RuleRun.js.map +1 -1
  1089. package/build/dist/Types/Rum/SessionReplay.js +52 -2
  1090. package/build/dist/Types/Rum/SessionReplay.js.map +1 -1
  1091. package/build/dist/Types/Rum/SessionReplayApi.js +11 -0
  1092. package/build/dist/Types/Rum/SessionReplayApi.js.map +1 -1
  1093. package/build/dist/Types/Rum/UserFlow.js +115 -0
  1094. package/build/dist/Types/Rum/UserFlow.js.map +1 -0
  1095. package/build/dist/Types/Runbook/RunbookStepType.js +10 -0
  1096. package/build/dist/Types/Runbook/RunbookStepType.js.map +1 -1
  1097. package/build/dist/Types/Runbook/RunnerJobOrigin.js +14 -0
  1098. package/build/dist/Types/Runbook/RunnerJobOrigin.js.map +1 -1
  1099. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js +2 -2
  1100. package/build/dist/Types/SecurityEvent/Connectors/SecurityEventConnectorCatalog.js.map +1 -1
  1101. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js +2 -0
  1102. package/build/dist/Types/StatusPage/MergedDowntimeTotals.js.map +1 -0
  1103. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js +65 -0
  1104. package/build/dist/Types/StatusPage/PublicNoteSubscriberNotificationDefault.js.map +1 -0
  1105. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +8 -0
  1106. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  1107. package/build/dist/Types/Timezone.js +5 -0
  1108. package/build/dist/Types/Timezone.js.map +1 -1
  1109. package/build/dist/Types/TimezoneAlias.js +340 -0
  1110. package/build/dist/Types/TimezoneAlias.js.map +1 -0
  1111. package/build/dist/Types/Workflow/Templates.js +2694 -2
  1112. package/build/dist/Types/Workflow/Templates.js.map +1 -1
  1113. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js +314 -0
  1114. package/build/dist/Types/Workflow/WorkflowVariableOAuth.js.map +1 -0
  1115. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js +98 -0
  1116. package/build/dist/Types/Workspace/WorkspaceNoteReaction.js.map +1 -0
  1117. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js +95 -0
  1118. package/build/dist/UI/Components/AttributesJSON/AttributesJSONPreferences.js.map +1 -0
  1119. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js +44 -0
  1120. package/build/dist/UI/Components/AttributesJSON/AttributesJSONView.js.map +1 -0
  1121. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js +27 -0
  1122. package/build/dist/UI/Components/AttributesJSON/AttributesViewToggle.js.map +1 -0
  1123. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js +9 -0
  1124. package/build/dist/UI/Components/AttributesJSON/BracesGlyph.js.map +1 -0
  1125. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js +260 -0
  1126. package/build/dist/UI/Components/AttributesJSON/CopyAttributesAsJSONButton.js.map +1 -0
  1127. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js +56 -0
  1128. package/build/dist/UI/Components/AttributesJSON/JSONHighlight.js.map +1 -0
  1129. package/build/dist/UI/Components/Calendar/Calendar.js +94 -7
  1130. package/build/dist/UI/Components/Calendar/Calendar.js.map +1 -1
  1131. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js +136 -0
  1132. package/build/dist/UI/Components/Calendar/CalendarDayLayout.js.map +1 -0
  1133. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +1 -1
  1134. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  1135. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js +72 -0
  1136. package/build/dist/UI/Components/Charts/Utils/HistogramSelection.js.map +1 -0
  1137. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +178 -0
  1138. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -0
  1139. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js +13 -1
  1140. package/build/dist/UI/Components/Charts/Utils/useHistogramZoom.js.map +1 -1
  1141. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js +20 -4
  1142. package/build/dist/UI/Components/Date/CustomTimeRangeModal.js.map +1 -1
  1143. package/build/dist/UI/Components/Dropdown/Dropdown.js +33 -9
  1144. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  1145. package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
  1146. package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
  1147. package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
  1148. package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
  1149. package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
  1150. package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
  1151. package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
  1152. package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
  1153. package/build/dist/UI/Components/Forms/Fields/FormField.js +36 -13
  1154. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  1155. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +117 -11
  1156. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  1157. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js +5 -1
  1158. package/build/dist/UI/Components/Graphs/UptimeBarTooltip.js.map +1 -1
  1159. package/build/dist/UI/Components/Graphs/UptimeDaySummary.js.map +1 -1
  1160. package/build/dist/UI/Components/Icon/Icon.js +1 -1
  1161. package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
  1162. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +36 -8
  1163. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1164. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js +10 -2
  1165. package/build/dist/UI/Components/LogsViewer/components/ColumnSelector.js.map +1 -1
  1166. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js +9 -1
  1167. package/build/dist/UI/Components/LogsViewer/components/KeyboardShortcutsHelp.js.map +1 -1
  1168. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js +16 -15
  1169. package/build/dist/UI/Components/LogsViewer/components/LogDetailsPanel.js.map +1 -1
  1170. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js +1 -1
  1171. package/build/dist/UI/Components/LogsViewer/components/LogsFacetSidebar.js.map +1 -1
  1172. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +14 -74
  1173. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  1174. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +22 -5
  1175. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  1176. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js +9 -2
  1177. package/build/dist/UI/Components/LogsViewer/components/SavedViewsDropdown.js.map +1 -1
  1178. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js +16 -5
  1179. package/build/dist/UI/Components/LogsViewer/useLogsHistogram.js.map +1 -1
  1180. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +23 -8
  1181. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1182. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +7 -1
  1183. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  1184. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js +5 -1
  1185. package/build/dist/UI/Components/MonitorGraphs/UptimeBarDayModal.js.map +1 -1
  1186. package/build/dist/UI/Components/Page/ModelPage.js +37 -3
  1187. package/build/dist/UI/Components/Page/ModelPage.js.map +1 -1
  1188. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +27 -6
  1189. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1190. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js +7 -1
  1191. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryDetailPanel.js.map +1 -1
  1192. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js +1 -1
  1193. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryFacetSidebar.js.map +1 -1
  1194. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +17 -77
  1195. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  1196. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js +10 -1
  1197. package/build/dist/UI/Components/TelemetryViewer/components/TelemetrySearchBar.js.map +1 -1
  1198. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js +15 -1
  1199. package/build/dist/UI/Utils/ModelAPI/ProjectUsersModelAPI.js.map +1 -1
  1200. package/build/dist/UI/Utils/Timezone.js +52 -17
  1201. package/build/dist/UI/Utils/Timezone.js.map +1 -1
  1202. package/build/dist/Utils/AI/InvestigationReport.js +116 -21
  1203. package/build/dist/Utils/AI/InvestigationReport.js.map +1 -1
  1204. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js +1209 -0
  1205. package/build/dist/Utils/AiRemediation/KubectlOutputRedactor.js.map +1 -0
  1206. package/build/dist/Utils/AiRemediation/KubectlPolicy.js +2973 -0
  1207. package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -0
  1208. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js +99 -0
  1209. package/build/dist/Utils/AiRemediation/KubectlWaitBudget.js.map +1 -0
  1210. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js +1429 -0
  1211. package/build/dist/Utils/AiRemediation/KubectlWriteScope.js.map +1 -0
  1212. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js +7 -6
  1213. package/build/dist/Utils/Dashboard/Components/DashboardClockComponent.js.map +1 -1
  1214. package/build/dist/Utils/LabelRuleImportExport.js +22 -6
  1215. package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
  1216. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js +214 -0
  1217. package/build/dist/Utils/Monitor/IncomingEmailMonitorAddress.js.map +1 -0
  1218. package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
  1219. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js +471 -0
  1220. package/build/dist/Utils/Monitor/MonitorCheckScheduleUtil.js.map +1 -0
  1221. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js +107 -0
  1222. package/build/dist/Utils/Monitor/MonitorOverviewCriteriaUtil.js.map +1 -0
  1223. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js +191 -0
  1224. package/build/dist/Utils/Monitor/MonitorOverviewFamily.js.map +1 -0
  1225. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js +1259 -0
  1226. package/build/dist/Utils/Monitor/MonitorOverviewPresentationUtil.js.map +1 -0
  1227. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js +593 -0
  1228. package/build/dist/Utils/Monitor/MonitorOverviewProbeUtil.js.map +1 -0
  1229. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js +195 -0
  1230. package/build/dist/Utils/Monitor/MonitorOverviewTargetUtil.js.map +1 -0
  1231. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js +127 -0
  1232. package/build/dist/Utils/Monitor/MonitorStatusHistoryUtil.js.map +1 -0
  1233. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js +464 -0
  1234. package/build/dist/Utils/Monitor/MonitorUptimeSummaryUtil.js.map +1 -0
  1235. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
  1236. package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
  1237. package/build/dist/Utils/Rum/SessionIdentity.js +31 -1
  1238. package/build/dist/Utils/Rum/SessionIdentity.js.map +1 -1
  1239. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js +128 -0
  1240. package/build/dist/Utils/Rum/SessionReplayWireEncoding.js.map +1 -0
  1241. package/build/dist/Utils/Rum/UserFlow.js +941 -0
  1242. package/build/dist/Utils/Rum/UserFlow.js.map +1 -0
  1243. package/build/dist/Utils/Slo/SloDuration.js +13 -5
  1244. package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
  1245. package/build/dist/Utils/Slo/SloHealth.js +8 -7
  1246. package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
  1247. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
  1248. package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
  1249. package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
  1250. package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
  1251. package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
  1252. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js +82 -0
  1253. package/build/dist/Utils/StatusPage/MonitorGroupMergedDowntimeUtil.js.map +1 -0
  1254. package/build/dist/Utils/StatusPage/ResourceUptime.js +46 -0
  1255. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  1256. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  1257. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -1
  1258. package/build/dist/Utils/Telemetry/AttributesJSON.js +245 -0
  1259. package/build/dist/Utils/Telemetry/AttributesJSON.js.map +1 -0
  1260. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js +103 -0
  1261. package/build/dist/Utils/Uptime/DayUptimeGraphUtil.js.map +1 -1
  1262. package/build/dist/Utils/Uptime/UptimeUtil.js +91 -27
  1263. package/build/dist/Utils/Uptime/UptimeUtil.js.map +1 -1
  1264. package/jest.config.json +2 -1
  1265. package/package.json +2 -1
  1266. package/tsconfig.tests.json +36 -0
  1267. package/Tests/UI/Components/EmptyState/EmptyStateGuideLinks.test.tsx +0 -337
  1268. package/UI/Components/EmptyState/EmptyStateGuideLinks.tsx +0 -124
  1269. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js +0 -47
  1270. package/build/dist/UI/Components/EmptyState/EmptyStateGuideLinks.js.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import "@testing-library/jest-dom";
2
- import { act, cleanup, render, screen } from "@testing-library/react";
2
+ import { act, cleanup, render, screen, waitFor } from "@testing-library/react";
3
3
  import React, { ReactElement } from "react";
4
4
  import {
5
5
  afterEach,
@@ -9,34 +9,30 @@ import {
9
9
  jest,
10
10
  test,
11
11
  } from "@jest/globals";
12
+ import type { SpyInstance } from "jest-mock";
12
13
 
13
14
  /*
14
- * "I am unable to edit the variables, I am having to delete the variable and
15
- * add it again if I want to make a modification to it."
15
+ * The workflow variables list - Workflows > Global Variables and Workflow >
16
+ * View > Workflow Variables - after it was simplified.
16
17
  *
17
- * Both variable tables - Workflow > Variables (global) and Workflow > View >
18
- * Variables (local) - passed isEditable={false}, so a variable was immutable
19
- * from the moment it was saved. There was a reason for that, and it is why
20
- * turning the flag on is not the whole fix:
18
+ * What was asked for, and what every describe block below pins down:
21
19
  *
22
- * `content` is write-only. Its ColumnAccessControl.read is [] while its
23
- * update list is not, and ModelForm builds the edit modal's prefetch select
24
- * from each field's UPDATE list (getFieldPermissions), never its read list.
25
- * So an edit form that still carries the content field asks the API to select
26
- * a column nobody may read, and SelectPermission refuses the whole GET - the
27
- * modal opens on a red error instead of a form.
20
+ * 1. The list shows Name, Type and Description. The Secret, Token and
21
+ * Created At columns are gone.
22
+ * 2. A row has one action, View, which opens the variable's own page. Show
23
+ * ID, Update Content, Edit Details and Delete are no longer row actions.
24
+ * 3. Create makes a static variable and never asks which kind. An OAuth 2.0
25
+ * variable is created from the More (⋯) menu beside it.
26
+ * 4. Both of the above on the global page and on a workflow's own page.
28
27
  *
29
- * The fix is therefore two-part, and both parts are asserted here: content is
30
- * marked doNotShowWhenEditing (which drops it from the edit form, its select
31
- * AND its payload, because ModelTable filters the array before ModelForm sees
32
- * it), and it gets its own door - an "Update Content" row action writing that
33
- * one column through ModelAPI.
34
- *
35
- * ModelTable is replaced by a prop recorder: what is under test is the
36
- * configuration the page hands it, and the real table fetches on mount.
28
+ * ModelTable, the OAuth create form and the token refresh modal are replaced
29
+ * by prop recorders: what is under test is the configuration the page hands
30
+ * them and what the page does when their callbacks fire. The real table
31
+ * fetches on mount.
37
32
  */
38
33
 
39
34
  let permissionsForTest: Array<unknown> = [];
35
+ let isMasterAdminForTest: boolean = false;
40
36
 
41
37
  jest.mock("../../../UI/Utils/Permission", () => {
42
38
  return {
@@ -60,7 +56,7 @@ jest.mock("../../../UI/Utils/User", () => {
60
56
  __esModule: true,
61
57
  default: {
62
58
  isMasterAdmin: (): boolean => {
63
- return false;
59
+ return isMasterAdminForTest;
64
60
  },
65
61
  getUserId: (): null => {
66
62
  return null;
@@ -80,37 +76,48 @@ jest.mock("../../../UI/Utils/Project", () => {
80
76
  };
81
77
  });
82
78
 
79
+ const getLastParamAsObjectID: ReturnType<
80
+ typeof jest.fn<(position: number) => unknown>
81
+ > = jest.fn<(position: number) => unknown>();
82
+
83
83
  jest.mock("../../../UI/Utils/Navigation", () => {
84
84
  return {
85
85
  __esModule: true,
86
86
  default: {
87
- getLastParamAsObjectID: (): unknown => {
88
- return WORKFLOW_ID;
87
+ getLastParamAsObjectID: (position: number): unknown => {
88
+ return getLastParamAsObjectID(position);
89
89
  },
90
90
  },
91
91
  };
92
92
  });
93
93
 
94
- const updateById: ReturnType<
95
- typeof jest.fn<(data: unknown) => Promise<unknown>>
96
- > = jest.fn<(data: unknown) => Promise<unknown>>();
97
-
98
94
  jest.mock("../../../UI/Utils/ModelAPI/ModelAPI", () => {
99
95
  return {
100
96
  __esModule: true,
101
97
  default: {
102
- updateById: (data: unknown): Promise<unknown> => {
103
- return updateById(data);
98
+ getCommonHeaders: (): Record<string, string> => {
99
+ return { tenantid: "project-header" };
104
100
  },
105
101
  },
106
102
  };
107
103
  });
108
104
 
105
+ const apiPost: ReturnType<typeof jest.fn<(data: unknown) => Promise<unknown>>> =
106
+ jest.fn<(data: unknown) => Promise<unknown>>();
107
+
109
108
  jest.mock("../../../UI/Utils/API/API", () => {
110
109
  return {
111
110
  __esModule: true,
112
111
  default: {
112
+ post: (data: unknown): Promise<unknown> => {
113
+ return apiPost(data);
114
+ },
115
+ // The same precedence as the real one, for the two shapes used here.
113
116
  getFriendlyMessage: (error: unknown): string => {
117
+ if (error instanceof HTTPErrorResponse) {
118
+ return error.message || "Server Error. Please try again";
119
+ }
120
+
114
121
  return error instanceof Error ? error.message : "Request failed.";
115
122
  },
116
123
  },
@@ -120,38 +127,77 @@ jest.mock("../../../UI/Utils/API/API", () => {
120
127
  type FormFieldEntry = {
121
128
  field?: Record<string, unknown> | undefined;
122
129
  title?: string | undefined;
123
- doNotShowWhenEditing?: boolean | undefined;
124
- doNotShowWhenCreating?: boolean | undefined;
125
- required?: boolean | undefined;
130
+ stepId?: string | undefined;
131
+ fieldType?: string | undefined;
132
+ required?:
133
+ | boolean
134
+ | ((values: Record<string, unknown>) => boolean)
135
+ | undefined;
126
136
  description?: string | undefined;
137
+ placeholder?: string | undefined;
138
+ validation?: Record<string, unknown> | undefined;
139
+ showIf?: ((values: Record<string, unknown>) => boolean) | undefined;
140
+ doNotShowWhenCreating?: boolean | undefined;
141
+ cardSelectOptions?: Array<unknown> | undefined;
142
+ dropdownOptions?: Array<unknown> | undefined;
127
143
  };
128
144
 
129
- type ActionButtonEntry = {
145
+ type ColumnEntry = {
146
+ field?: Record<string, unknown> | undefined;
147
+ title?: string | undefined;
148
+ type?: string | undefined;
149
+ getElement?: ((item: unknown) => ReactElement) | undefined;
150
+ };
151
+
152
+ type CardButtonEntry = {
130
153
  title: string;
154
+ icon?: IconProp | undefined;
155
+ buttonStyle?: ButtonStyleType | undefined;
131
156
  disabled?: boolean | undefined;
132
157
  tooltip?: string | undefined;
133
- isVisible?: ((item: unknown) => boolean | undefined) | undefined;
134
- onClick: (
135
- item: unknown,
136
- onCompleteAction: () => void,
137
- onError: (error: Error) => void,
138
- ) => void;
158
+ onClick: () => void;
139
159
  };
140
160
 
141
161
  type CapturedTableProps = {
162
+ id?: string | undefined;
163
+ name?: string | undefined;
164
+ userPreferencesKey?: string | undefined;
165
+ saveFilterProps?: { tableId?: string | undefined } | undefined;
142
166
  isEditable?: boolean | undefined;
143
- editButtonText?: string | undefined;
144
- filters?: Array<{ field?: Record<string, unknown> | undefined }> | undefined;
145
- selectMoreFields?: Record<string, unknown> | undefined;
146
- isCreateable?: boolean | undefined;
147
167
  isDeleteable?: boolean | undefined;
168
+ isCreateable?: boolean | undefined;
169
+ isViewable?: boolean | undefined;
170
+ viewButtonText?: string | undefined;
171
+ showViewIdButton?: boolean | undefined;
172
+ editButtonText?: string | undefined;
173
+ onViewPage?: ((item: unknown) => Promise<unknown>) | undefined;
174
+ actionButtons?: Array<{ title: string }> | undefined;
175
+ cardProps?:
176
+ | {
177
+ title?: string | undefined;
178
+ description?: string | undefined;
179
+ buttons?: Array<CardButtonEntry> | undefined;
180
+ }
181
+ | undefined;
148
182
  query?: Record<string, unknown> | undefined;
183
+ selectMoreFields?: Record<string, unknown> | undefined;
149
184
  formFields?: Array<FormFieldEntry> | undefined;
150
- actionButtons?: Array<ActionButtonEntry> | undefined;
185
+ formSteps?: Array<unknown> | undefined;
151
186
  onBeforeCreate?: ((item: unknown) => Promise<unknown>) | undefined;
152
- cardProps?: { title?: string | undefined } | undefined;
153
- columns?: Array<{ field?: Record<string, unknown> | undefined }> | undefined;
187
+ onFetchSuccess?:
188
+ | ((data: Array<unknown>, totalCount: number) => void)
189
+ | undefined;
190
+ refreshToggle?: string | undefined;
191
+ noItemsMessage?: string | undefined;
192
+ showRefreshButton?: boolean | undefined;
154
193
  searchableFields?: Array<string> | undefined;
194
+ filters?:
195
+ | Array<{
196
+ field?: Record<string, unknown> | undefined;
197
+ title?: string | undefined;
198
+ }>
199
+ | undefined;
200
+ columns?: Array<ColumnEntry> | undefined;
155
201
  };
156
202
 
157
203
  let capturedTableProps: CapturedTableProps | null = null;
@@ -166,37 +212,67 @@ jest.mock("../../../UI/Components/ModelTable/ModelTable", () => {
166
212
  };
167
213
  });
168
214
 
169
- type CapturedModalProps = {
170
- title: string;
171
- error?: string | undefined;
172
- isLoading?: boolean | undefined;
173
- description?: string | undefined;
174
- onClose?: (() => void) | undefined;
175
- onSubmit?: ((data: Record<string, unknown>) => void) | undefined;
176
- formProps: {
177
- initialValues: Record<string, unknown>;
178
- fields: Array<FormFieldEntry>;
179
- };
215
+ type CapturedOAuthModalProps = {
216
+ workflowId?: ObjectID | undefined;
217
+ onClose: () => void;
218
+ onSuccess: (variable: WorkflowVariable) => void;
180
219
  };
181
220
 
182
- let capturedModalProps: CapturedModalProps | null = null;
221
+ let capturedOAuthModalProps: CapturedOAuthModalProps | null = null;
183
222
 
184
- jest.mock("../../../UI/Components/FormModal/BasicFormModal", () => {
185
- return {
186
- __esModule: true,
187
- default: (props: CapturedModalProps): ReactElement => {
188
- capturedModalProps = props;
189
- return <div data-testid="update-content-modal" />;
190
- },
191
- };
192
- });
223
+ jest.mock(
224
+ "../../../../App/FeatureSet/Dashboard/src/Components/Workflow/CreateOAuthWorkflowVariableModal",
225
+ () => {
226
+ return {
227
+ __esModule: true,
228
+ default: (props: CapturedOAuthModalProps): ReactElement => {
229
+ capturedOAuthModalProps = props;
230
+ return <div data-testid="create-oauth-variable-modal" />;
231
+ },
232
+ };
233
+ },
234
+ );
235
+
236
+ type CapturedRefreshModalProps = {
237
+ variableName: string;
238
+ outcome: TokenRefreshOutcome | null;
239
+ onClose: () => void;
240
+ };
241
+
242
+ let capturedRefreshModalProps: CapturedRefreshModalProps | null = null;
243
+
244
+ // Every outcome the modal was rendered with, in order - null is "pending".
245
+ let refreshModalOutcomes: Array<TokenRefreshOutcome | null> = [];
246
+
247
+ jest.mock(
248
+ "../../../../App/FeatureSet/Dashboard/src/Components/Workflow/WorkflowVariableTokenRefreshModal",
249
+ () => {
250
+ return {
251
+ __esModule: true,
252
+ default: (props: CapturedRefreshModalProps): ReactElement => {
253
+ capturedRefreshModalProps = props;
254
+ refreshModalOutcomes.push(props.outcome);
255
+ return <div data-testid="token-refresh-modal" />;
256
+ },
257
+ };
258
+ },
259
+ );
193
260
 
194
261
  import GlobalVariablesPage from "../../../../App/FeatureSet/Dashboard/src/Pages/Workflow/Variable";
195
262
  import WorkflowVariablesPage from "../../../../App/FeatureSet/Dashboard/src/Pages/Workflow/View/Variable";
263
+ import { TokenRefreshOutcome } from "../../../../App/FeatureSet/Dashboard/src/Utils/Workflow/WorkflowVariableUtil";
196
264
  import WorkflowVariable from "../../../Models/DatabaseModels/WorkflowVariable";
265
+ import HTTPErrorResponse from "../../../Types/API/HTTPErrorResponse";
197
266
  import IsNull from "../../../Types/BaseDatabase/IsNull";
267
+ import OneUptimeDate from "../../../Types/Date";
268
+ import IconProp from "../../../Types/Icon/IconProp";
198
269
  import ObjectID from "../../../Types/ObjectID";
199
270
  import Permission from "../../../Types/Permission";
271
+ import {
272
+ OAuth2GrantType,
273
+ WorkflowVariableType,
274
+ } from "../../../Types/Workflow/WorkflowVariableOAuth";
275
+ import { ButtonStyleType } from "../../../UI/Components/Button/Button";
200
276
  import PermissionGate from "../../../UI/Utils/PermissionGate";
201
277
 
202
278
  const PROJECT_ID: ObjectID = new ObjectID(
@@ -212,8 +288,75 @@ const OTHER_VARIABLE_ID: ObjectID = new ObjectID(
212
288
  "44444444-4444-4444-8444-444444444444",
213
289
  );
214
290
 
291
+ const EXPIRES_AT_ISO: string = "2030-01-01T10:00:00.000Z";
292
+
293
+ const OAUTH_MENU_TITLE: string = "Create OAuth 2.0 Variable";
294
+
295
+ // The columns, and their fields, the list no longer shows.
296
+ const REMOVED_COLUMN_TITLES: Array<string> = ["Secret", "Token", "Created At"];
297
+ const REMOVED_COLUMN_FIELDS: Array<string> = [
298
+ "isSecret",
299
+ "oauthAccessTokenExpiresAt",
300
+ "oauthLastRefreshedAt",
301
+ "oauthLastRefreshError",
302
+ "oauthLastRefreshErrorAt",
303
+ "createdAt",
304
+ ];
305
+
306
+ // The row actions the list used to offer, and no longer does.
307
+ const REMOVED_ROW_ACTIONS: Array<string> = [
308
+ "Show ID",
309
+ "Update Content",
310
+ "Update Credentials",
311
+ "Edit Details",
312
+ "Edit",
313
+ "Delete",
314
+ ];
315
+
316
+ // Write-only or secret columns: no list request may ever select them.
317
+ const NEVER_SELECTED_FIELDS: Array<string> = [
318
+ "content",
319
+ "oauthClientSecret",
320
+ "oauthRefreshToken",
321
+ "oauthAccessToken",
322
+ ];
323
+
215
324
  type Page = "global" | "local";
216
325
 
326
+ type PageCase = {
327
+ page: Page;
328
+ workflowId: ObjectID | undefined;
329
+ cardTitle: string;
330
+ noItemsMessage: string;
331
+ reference: string;
332
+ otherReference: string;
333
+ viewRoute: string;
334
+ otherViewRoute: string;
335
+ };
336
+
337
+ const PAGE_CASES: Array<PageCase> = [
338
+ {
339
+ page: "global",
340
+ workflowId: undefined,
341
+ cardTitle: "Global Variables",
342
+ noItemsMessage: "No global variables found.",
343
+ reference: "{{global.variables.THIS_NAME}}",
344
+ otherReference: "{{local.variables.THIS_NAME}}",
345
+ viewRoute: `/dashboard/${PROJECT_ID.toString()}/workflows/variables/${VARIABLE_ID.toString()}`,
346
+ otherViewRoute: `/dashboard/${PROJECT_ID.toString()}/workflows/variables/${OTHER_VARIABLE_ID.toString()}`,
347
+ },
348
+ {
349
+ page: "local",
350
+ workflowId: WORKFLOW_ID,
351
+ cardTitle: "Workflow Variables",
352
+ noItemsMessage: "No workflow variables found.",
353
+ reference: "{{local.variables.THIS_NAME}}",
354
+ otherReference: "{{global.variables.THIS_NAME}}",
355
+ viewRoute: `/dashboard/${PROJECT_ID.toString()}/workflows/${WORKFLOW_ID.toString()}/variables/${VARIABLE_ID.toString()}`,
356
+ otherViewRoute: `/dashboard/${PROJECT_ID.toString()}/workflows/${WORKFLOW_ID.toString()}/variables/${OTHER_VARIABLE_ID.toString()}`,
357
+ },
358
+ ];
359
+
217
360
  function renderPage(page: Page): void {
218
361
  const props: Record<string, unknown> = {};
219
362
 
@@ -245,10 +388,22 @@ function table(): CapturedTableProps {
245
388
  return capturedTableProps;
246
389
  }
247
390
 
391
+ function fieldName(entry: {
392
+ field?: Record<string, unknown> | undefined;
393
+ }): string {
394
+ return Object.keys(entry.field || {})[0] || "";
395
+ }
396
+
397
+ function formFieldNames(): Array<string> {
398
+ return (table().formFields || []).map((entry: FormFieldEntry) => {
399
+ return fieldName(entry);
400
+ });
401
+ }
402
+
248
403
  function formField(name: string): FormFieldEntry {
249
404
  const entry: FormFieldEntry | undefined = (table().formFields || []).find(
250
405
  (field: FormFieldEntry) => {
251
- return Object.keys(field.field || {})[0] === name;
406
+ return fieldName(field) === name;
252
407
  },
253
408
  );
254
409
 
@@ -259,510 +414,1237 @@ function formField(name: string): FormFieldEntry {
259
414
  return entry;
260
415
  }
261
416
 
262
- function updateContentButton(): ActionButtonEntry {
263
- const button: ActionButtonEntry | undefined = (
264
- table().actionButtons || []
265
- ).find((entry: ActionButtonEntry) => {
266
- return entry.title === "Update Content";
267
- });
417
+ function column(title: string): ColumnEntry {
418
+ const entry: ColumnEntry | undefined = (table().columns || []).find(
419
+ (candidate: ColumnEntry) => {
420
+ return candidate.title === title;
421
+ },
422
+ );
423
+
424
+ if (!entry) {
425
+ throw new Error(`The table has no ${title} column`);
426
+ }
427
+
428
+ return entry;
429
+ }
430
+
431
+ function moreMenuButtons(): Array<CardButtonEntry> {
432
+ return table().cardProps?.buttons || [];
433
+ }
434
+
435
+ function oauthMenuButton(): CardButtonEntry {
436
+ const button: CardButtonEntry | undefined = moreMenuButtons().find(
437
+ (entry: CardButtonEntry) => {
438
+ return entry.title === OAUTH_MENU_TITLE;
439
+ },
440
+ );
268
441
 
269
442
  if (!button) {
270
- throw new Error("The table offers no Update Content action");
443
+ throw new Error(`The More menu offers no "${OAUTH_MENU_TITLE}"`);
271
444
  }
272
445
 
273
446
  return button;
274
447
  }
275
448
 
276
- function makeVariable(
277
- id?: ObjectID | null | undefined,
278
- name?: string | undefined,
449
+ function isOAuthFormOpen(): boolean {
450
+ return screen.queryByTestId("create-oauth-variable-modal") !== null;
451
+ }
452
+
453
+ function oauthForm(): CapturedOAuthModalProps {
454
+ if (!isOAuthFormOpen() || !capturedOAuthModalProps) {
455
+ throw new Error("The OAuth 2.0 create form is not open");
456
+ }
457
+
458
+ return capturedOAuthModalProps;
459
+ }
460
+
461
+ function isRefreshModalOpen(): boolean {
462
+ return screen.queryByTestId("token-refresh-modal") !== null;
463
+ }
464
+
465
+ function refreshModal(): CapturedRefreshModalProps {
466
+ if (!isRefreshModalOpen() || !capturedRefreshModalProps) {
467
+ throw new Error("The token refresh modal is not open");
468
+ }
469
+
470
+ return capturedRefreshModalProps;
471
+ }
472
+
473
+ function openOAuthForm(): void {
474
+ act(() => {
475
+ oauthMenuButton().onClick();
476
+ });
477
+ }
478
+
479
+ function staticVariable(): WorkflowVariable {
480
+ const variable: WorkflowVariable = new WorkflowVariable();
481
+ variable._id = VARIABLE_ID.toString();
482
+ variable.name = "PLAIN";
483
+ variable.variableType = WorkflowVariableType.Static;
484
+ return variable;
485
+ }
486
+
487
+ function oauthVariable(
488
+ overrides?: Partial<Record<string, unknown>> | undefined,
279
489
  ): WorkflowVariable {
280
490
  const variable: WorkflowVariable = new WorkflowVariable();
491
+ variable._id = VARIABLE_ID.toString();
492
+ variable.name = "API_TOKEN";
493
+ variable.variableType = WorkflowVariableType.OAuth2;
494
+ variable.oauthGrantType = OAuth2GrantType.ClientCredentials;
281
495
 
282
- if (id !== null) {
283
- variable._id = (id || VARIABLE_ID).toString();
496
+ for (const [key, value] of Object.entries(overrides || {})) {
497
+ (variable as unknown as Record<string, unknown>)[key] = value;
284
498
  }
285
499
 
286
- variable.name = name || "AirflowToken";
287
500
  return variable;
288
501
  }
289
502
 
290
- function openUpdateContentModal(variable?: WorkflowVariable | undefined): void {
291
- act(() => {
292
- updateContentButton().onClick(
293
- variable || makeVariable(),
294
- (): void => {
295
- // onCompleteAction
296
- },
297
- (): void => {
298
- // onError
299
- },
300
- );
503
+ function refreshCall(callIndex: number = 0): {
504
+ url: string;
505
+ headers: unknown;
506
+ data: unknown;
507
+ } {
508
+ const call: { url: unknown; headers: unknown; data: unknown } = apiPost.mock
509
+ .calls[callIndex]![0] as { url: unknown; headers: unknown; data: unknown };
510
+
511
+ return { url: String(call.url), headers: call.headers, data: call.data };
512
+ }
513
+
514
+ type Deferred<T> = {
515
+ promise: Promise<T>;
516
+ resolve: (value: T) => void;
517
+ reject: (error: unknown) => void;
518
+ };
519
+
520
+ function createDeferred<T>(): Deferred<T> {
521
+ let resolve: (value: T) => void = (): void => {
522
+ // Replaced below, synchronously, by the promise executor.
523
+ };
524
+ let reject: (error: unknown) => void = (): void => {
525
+ // Replaced below, synchronously, by the promise executor.
526
+ };
527
+
528
+ const promise: Promise<T> = new Promise<T>(
529
+ (res: (value: T) => void, rej: (error: unknown) => void) => {
530
+ resolve = res;
531
+ reject = rej;
532
+ },
533
+ );
534
+
535
+ return { promise, resolve, reject };
536
+ }
537
+
538
+ /*
539
+ * Fires the open OAuth form's onSuccess with the saved variable and lets
540
+ * whatever it starts settle. Waits for nothing in particular, so it also
541
+ * serves the cases where no token is asked for at all.
542
+ */
543
+ async function saveOAuthVariable(variable: WorkflowVariable): Promise<void> {
544
+ await act(async () => {
545
+ oauthForm().onSuccess(variable);
546
+ });
547
+
548
+ // A few more turns, so a request sent late would still be seen.
549
+ await act(async () => {
550
+ await Promise.resolve();
551
+ await Promise.resolve();
301
552
  });
302
553
  }
303
554
 
304
- function modal(): CapturedModalProps {
305
- if (!capturedModalProps) {
306
- throw new Error("The Update Content modal is not open");
307
- }
555
+ /*
556
+ * Opens the OAuth form from the More menu and fires its onSuccess with the
557
+ * saved variable, then waits for the token outcome to land in the modal.
558
+ */
559
+ async function createOAuthVariable(variable: WorkflowVariable): Promise<void> {
560
+ openOAuthForm();
561
+
562
+ await saveOAuthVariable(variable);
308
563
 
309
- return capturedModalProps;
564
+ await waitFor(() => {
565
+ expect(capturedRefreshModalProps?.outcome).toBeTruthy();
566
+ });
310
567
  }
311
568
 
312
- const PAGES: Array<Page> = ["global", "local"];
569
+ type RoleCase = {
570
+ label: string;
571
+ permissions: Array<Permission>;
572
+ };
573
+
574
+ /*
575
+ * Roles on WorkflowVariable's create list but not its update list. The
576
+ * refresh route writes the token to the variable, so it checks for update and
577
+ * would refuse every one of these.
578
+ */
579
+ const CREATE_ONLY_ROLES: Array<RoleCase> = [
580
+ {
581
+ label: "Create and Read Workflow Variables",
582
+ permissions: [
583
+ Permission.CreateWorkflowVariable,
584
+ Permission.ReadWorkflowVariable,
585
+ ],
586
+ },
587
+ { label: "Project Member", permissions: [Permission.ProjectMember] },
588
+ { label: "Workflow Admin", permissions: [Permission.WorkflowAdmin] },
589
+ { label: "Workflow Member", permissions: [Permission.WorkflowMember] },
590
+ /*
591
+ * A workflow variable is not an operational resource, so the Edit All
592
+ * wildcard does not widen its update list - here or on the server.
593
+ */
594
+ {
595
+ label: "Create Workflow Variables with Edit All Operational Resources",
596
+ permissions: [
597
+ Permission.CreateWorkflowVariable,
598
+ Permission.EditAllOperationalResources,
599
+ ],
600
+ },
601
+ ];
602
+
603
+ // Roles on both lists: these may create the variable and fetch its token.
604
+ const CREATE_AND_UPDATE_ROLES: Array<RoleCase> = [
605
+ { label: "Project Admin", permissions: [Permission.ProjectAdmin] },
606
+ { label: "Project Owner", permissions: [Permission.ProjectOwner] },
607
+ {
608
+ label: "Create and Edit Workflow Variables",
609
+ permissions: [
610
+ Permission.CreateWorkflowVariable,
611
+ Permission.EditWorkflowVariable,
612
+ ],
613
+ },
614
+ ];
615
+
616
+ let clockTick: number = 0;
617
+ let currentDateSpy: SpyInstance<() => Date> | null = null;
313
618
 
314
619
  beforeEach(() => {
315
620
  capturedTableProps = null;
316
- capturedModalProps = null;
317
- updateById.mockReset();
318
- updateById.mockResolvedValue(undefined);
621
+ capturedOAuthModalProps = null;
622
+ capturedRefreshModalProps = null;
623
+ refreshModalOutcomes = [];
624
+ apiPost.mockReset();
625
+ apiPost.mockResolvedValue({
626
+ data: { oauthAccessTokenExpiresAt: EXPIRES_AT_ISO },
627
+ });
628
+ getLastParamAsObjectID.mockReset();
629
+ getLastParamAsObjectID.mockReturnValue(WORKFLOW_ID);
319
630
  permissionsForTest = [Permission.ProjectAdmin];
631
+ isMasterAdminForTest = false;
320
632
  PermissionGate.clearPermissionPropsCache();
633
+
634
+ /*
635
+ * refreshToggle is an ISO timestamp. Two bumps inside the same millisecond
636
+ * would be the same string and read as "not refreshed", so every read of
637
+ * the clock moves it on by a second.
638
+ */
639
+ clockTick = 0;
640
+ currentDateSpy = jest
641
+ .spyOn(OneUptimeDate, "getCurrentDate")
642
+ .mockImplementation((): Date => {
643
+ clockTick++;
644
+ return new Date(Date.UTC(2026, 8, 23, 12, 0, 0) + clockTick * 1000);
645
+ });
321
646
  });
322
647
 
323
648
  afterEach(() => {
324
649
  cleanup();
650
+ currentDateSpy?.mockRestore();
651
+ currentDateSpy = null;
325
652
  });
326
653
 
327
- describe.each(PAGES)("the %s workflow variables table", (page: Page) => {
328
- /*
329
- * The customer's report, stated as a test. Everything else in this file is
330
- * about making this safe rather than about making it true.
331
- */
332
- test("offers Edit", () => {
333
- renderPage(page);
654
+ describe("the pages", () => {
655
+ test("the global page lists the project's variables, with no workflow", () => {
656
+ renderPage("global");
334
657
 
335
- expect(table().isEditable).toBe(true);
336
- expect(table().isCreateable).toBe(true);
337
- expect(table().isDeleteable).toBe(true);
658
+ expect(table().query?.["workflowId"]).toBeInstanceOf(IsNull);
659
+ expect(getLastParamAsObjectID).not.toHaveBeenCalled();
338
660
  });
339
661
 
340
- test("keeps content off the edit form, because it can never be prefilled", () => {
341
- renderPage(page);
662
+ // /dashboard/:projectId/workflows/:id/variables - the id is one from the end.
663
+ test("the workflow page reads the workflow id from the URL", () => {
664
+ renderPage("local");
342
665
 
343
- expect(formField("content").doNotShowWhenEditing).toBe(true);
344
- // Still required when creating - a variable with no content is useless.
345
- expect(formField("content").required).toBe(true);
346
- expect(formField("content").doNotShowWhenCreating).toBeFalsy();
666
+ expect(getLastParamAsObjectID).toHaveBeenCalledWith(1);
667
+ expect(table().query?.["workflowId"]).toBe(WORKFLOW_ID);
347
668
  });
669
+ });
348
670
 
349
- test("leaves the editable columns on the edit form", () => {
350
- renderPage(page);
671
+ describe.each(PAGE_CASES)("the $page variables list", (pageCase: PageCase) => {
672
+ describe("columns", () => {
673
+ test("are exactly Name, Type and Description", () => {
674
+ renderPage(pageCase.page);
675
+
676
+ expect(
677
+ (table().columns || []).map((entry: ColumnEntry) => {
678
+ return entry.title;
679
+ }),
680
+ ).toEqual(["Name", "Type", "Description"]);
681
+
682
+ expect(
683
+ (table().columns || []).map((entry: ColumnEntry) => {
684
+ return fieldName(entry);
685
+ }),
686
+ ).toEqual(["name", "variableType", "description"]);
687
+ });
351
688
 
352
- for (const column of ["name", "description", "isSecret"]) {
353
- expect(formField(column).doNotShowWhenEditing).toBeFalsy();
354
- }
355
- });
689
+ // Ask 1, stated as a test.
690
+ test("no longer include Secret, Token or Created At", () => {
691
+ renderPage(pageCase.page);
356
692
 
357
- /*
358
- * isSecret is on the edit form only because the model's own
359
- * ColumnAccessControl.update for that column is non-empty - ModelForm drops a
360
- * field whose update list is empty, silently and without an error. Asserting
361
- * it here from the model keeps the two ends of that from drifting apart.
362
- */
363
- test("the secret toggle is actually updatable at the model level", () => {
364
- const variable: WorkflowVariable = new WorkflowVariable();
365
-
366
- expect(
367
- variable.getColumnAccessControlForAllColumns()["isSecret"]?.update,
368
- ).toEqual(
369
- expect.arrayContaining([
370
- Permission.ProjectOwner,
371
- Permission.ProjectAdmin,
372
- Permission.EditWorkflowVariable,
373
- ]),
374
- );
693
+ for (const entry of table().columns || []) {
694
+ expect(REMOVED_COLUMN_TITLES).not.toContain(entry.title);
695
+ expect(REMOVED_COLUMN_FIELDS).not.toContain(fieldName(entry));
696
+ }
697
+ });
375
698
 
376
- // And the widening did not drag content's read list along with it.
377
- expect(
378
- variable.getColumnAccessControlForAllColumns()["content"]?.read,
379
- ).toEqual([]);
380
- });
699
+ test("a static variable's Type reads Static", () => {
700
+ renderPage(pageCase.page);
381
701
 
382
- /*
383
- * "Edit" is the verb a user reaches for when they want to change a variable's
384
- * value, and it is the one button that cannot. Naming it for what it edits is
385
- * what makes the neighbouring Update Content action findable.
386
- */
387
- test("names the Edit button for what it actually edits", () => {
388
- renderPage(page);
702
+ render(column("Type").getElement!(staticVariable()));
389
703
 
390
- expect(table().editButtonText).toBe("Edit Details");
391
- });
704
+ expect(screen.getByText("Static")).toBeInTheDocument();
705
+ expect(screen.queryByText("OAuth 2.0")).not.toBeInTheDocument();
706
+ });
392
707
 
393
- /*
394
- * The copy this replaces asked "Should this be encrypted in the Database?".
395
- * content carries no `encrypted: true` and its DDL is a plain text column, so
396
- * somebody turning the toggle on would come away believing a database dump
397
- * was no longer a credential exposure.
398
- */
399
- test("the Secret toggle describes redaction, not encryption", () => {
400
- renderPage(page);
708
+ // Rows saved before OAuth 2.0 variables existed have no type at all.
709
+ test("a variable with no type reads Static", () => {
710
+ renderPage(pageCase.page);
711
+
712
+ const variable: WorkflowVariable = new WorkflowVariable();
713
+ variable._id = VARIABLE_ID.toString();
714
+ variable.name = "LEGACY";
715
+
716
+ render(column("Type").getElement!(variable));
717
+
718
+ expect(screen.getByText("Static")).toBeInTheDocument();
719
+ });
720
+
721
+ test("an OAuth 2.0 variable's Type reads OAuth 2.0, with its grant type underneath", () => {
722
+ renderPage(pageCase.page);
723
+
724
+ render(column("Type").getElement!(oauthVariable()));
725
+
726
+ expect(screen.getByText("OAuth 2.0")).toBeInTheDocument();
727
+ expect(screen.getByText("Client Credentials")).toBeInTheDocument();
728
+ expect(screen.queryByText("Static")).not.toBeInTheDocument();
729
+ });
730
+
731
+ test("names the Refresh Token grant too", () => {
732
+ renderPage(pageCase.page);
401
733
 
402
- const description: string = formField("isSecret").description || "";
734
+ render(
735
+ column("Type").getElement!(
736
+ oauthVariable({ oauthGrantType: OAuth2GrantType.RefreshToken }),
737
+ ),
738
+ );
739
+
740
+ expect(screen.getByText("OAuth 2.0")).toBeInTheDocument();
741
+ expect(screen.getByText("Refresh Token")).toBeInTheDocument();
742
+ });
743
+
744
+ test("an OAuth 2.0 variable with no grant type reads OAuth 2.0 alone", () => {
745
+ renderPage(pageCase.page);
403
746
 
404
- expect(description.toLowerCase()).not.toContain("encrypt");
405
- expect(description).toContain("[REDACTED]");
406
- expect(description.toLowerCase()).toContain("run logs");
747
+ const cell: ReturnType<typeof render> = render(
748
+ column("Type").getElement!(
749
+ oauthVariable({ oauthGrantType: undefined }),
750
+ ),
751
+ );
752
+
753
+ expect(cell.container.textContent).toBe("OAuth 2.0");
754
+ });
755
+
756
+ test("filters and searches only on what the list shows", () => {
757
+ renderPage(pageCase.page);
758
+
759
+ expect(
760
+ (table().filters || []).map(
761
+ (entry: { field?: Record<string, unknown> | undefined }) => {
762
+ return fieldName(entry);
763
+ },
764
+ ),
765
+ ).toEqual(["name", "description"]);
766
+ expect(table().searchableFields).toEqual(["name", "description"]);
767
+ });
407
768
  });
408
769
 
409
- test("warns on the name field that renaming does not rewrite references", () => {
410
- renderPage(page);
770
+ describe("row actions", () => {
771
+ // Ask 2, stated as a test.
772
+ test("are a single View button", () => {
773
+ renderPage(pageCase.page);
774
+
775
+ expect(table().isViewable).toBe(true);
776
+ expect(table().viewButtonText).toBe("View");
777
+ expect(table().showViewIdButton).toBeFalsy();
778
+ expect(table().isEditable).toBe(false);
779
+ expect(table().isDeleteable).toBe(false);
780
+ expect(table().actionButtons || []).toEqual([]);
781
+ });
782
+
783
+ test("no longer offer Show ID, Update Content, Update Credentials, Edit Details or Delete", () => {
784
+ renderPage(pageCase.page);
411
785
 
412
- const description: string = formField("name").description || "";
786
+ const titles: Array<string> = (table().actionButtons || []).map(
787
+ (entry: { title: string }) => {
788
+ return entry.title;
789
+ },
790
+ );
413
791
 
414
- expect(description).toContain(
415
- page === "global" ? "global.variables." : "local.variables.",
416
- );
417
- expect(description.toLowerCase()).toContain("renaming");
418
- expect(description.toLowerCase()).toContain("old name");
792
+ for (const removed of REMOVED_ROW_ACTIONS) {
793
+ expect(titles).not.toContain(removed);
794
+ }
795
+
796
+ // No Edit button left over under a new name, either.
797
+ expect(table().editButtonText).toBeUndefined();
798
+ });
799
+
800
+ test("View opens the variable's own page", async () => {
801
+ renderPage(pageCase.page);
802
+
803
+ const route: unknown = await table().onViewPage!(staticVariable());
804
+
805
+ expect(String(route)).toBe(pageCase.viewRoute);
806
+ });
807
+
808
+ test("View opens an OAuth 2.0 variable's page the same way", async () => {
809
+ renderPage(pageCase.page);
810
+
811
+ const route: unknown = await table().onViewPage!(oauthVariable());
812
+
813
+ expect(String(route)).toBe(pageCase.viewRoute);
814
+ });
815
+
816
+ test("View opens the page of the row it was pressed on", async () => {
817
+ renderPage(pageCase.page);
818
+
819
+ const variable: WorkflowVariable = staticVariable();
820
+ variable._id = OTHER_VARIABLE_ID.toString();
821
+
822
+ const route: unknown = await table().onViewPage!(variable);
823
+
824
+ expect(String(route)).toBe(pageCase.otherViewRoute);
825
+ });
826
+
827
+ // A route with ":id" still in it would open a page that cannot load.
828
+ test("View refuses a row without an id rather than opening a broken page", async () => {
829
+ renderPage(pageCase.page);
830
+
831
+ const variable: WorkflowVariable = new WorkflowVariable();
832
+ variable.name = "NO_ID";
833
+
834
+ await expect(table().onViewPage!(variable)).rejects.toThrow(
835
+ "This variable has no id",
836
+ );
837
+ });
419
838
  });
420
839
 
421
- describe("the Update Content action", () => {
422
- test("is offered, and opens a modal that prefills nothing", () => {
423
- renderPage(page);
840
+ describe("the Create form", () => {
841
+ test("is still offered, on a card named for the page", () => {
842
+ renderPage(pageCase.page);
424
843
 
425
- expect(capturedModalProps).toBeNull();
844
+ expect(table().isCreateable).toBe(true);
845
+ expect(table().cardProps?.title).toBe(pageCase.cardTitle);
846
+ expect(table().noItemsMessage).toBe(pageCase.noItemsMessage);
847
+ expect(table().name).toBe("Workflows");
848
+ expect(table().showRefreshButton).toBe(true);
849
+ });
426
850
 
427
- openUpdateContentModal();
851
+ test("asks only for a static variable's name, description, content and secret toggle", () => {
852
+ renderPage(pageCase.page);
428
853
 
429
- expect(modal().title).toBe("Update Content");
430
- expect(modal().formProps.initialValues).toEqual({});
431
- expect(Object.keys(modal().formProps.fields[0]?.field || {})).toEqual([
854
+ expect(formFieldNames()).toEqual([
855
+ "name",
856
+ "description",
432
857
  "content",
858
+ "isSecret",
433
859
  ]);
434
- expect(modal().description).toContain("AirflowToken");
435
860
  });
436
861
 
437
- test("writes only the content column, on the row that was clicked", async () => {
438
- renderPage(page);
439
- openUpdateContentModal();
862
+ // Ask 3, stated as a test.
863
+ test("never asks which kind of variable to create", () => {
864
+ renderPage(pageCase.page);
440
865
 
441
- await act(async () => {
442
- modal().onSubmit?.({ content: "rotated-token" });
866
+ expect(formFieldNames()).not.toContain("variableType");
867
+ expect(table().formSteps || []).toEqual([]);
868
+
869
+ for (const entry of table().formFields || []) {
870
+ expect(entry.fieldType).not.toBe("CardSelect");
871
+ expect(entry.cardSelectOptions).toBeUndefined();
872
+ // Nothing on the form hides or shows by a type the form never sets.
873
+ expect(entry.showIf).toBeUndefined();
874
+ expect(entry.stepId).toBeUndefined();
875
+ }
876
+ });
877
+
878
+ test("carries none of the OAuth 2.0 settings", () => {
879
+ renderPage(pageCase.page);
880
+
881
+ for (const name of formFieldNames()) {
882
+ expect(name.startsWith("oauth")).toBe(false);
883
+ }
884
+ });
885
+
886
+ test("requires the content, and says it cannot be viewed again", () => {
887
+ renderPage(pageCase.page);
888
+
889
+ expect(formField("content").required).toBe(true);
890
+ expect(formField("content").fieldType).toBe("LongText");
891
+ expect(formField("content").doNotShowWhenCreating).toBeFalsy();
892
+ expect(formField("content").description).toContain(
893
+ "cannot be viewed once saved",
894
+ );
895
+ });
896
+
897
+ test("offers the Secret toggle, optional, and describes redaction rather than encryption", () => {
898
+ renderPage(pageCase.page);
899
+
900
+ const secret: FormFieldEntry = formField("isSecret");
901
+
902
+ expect(secret.fieldType).toBe("Boolean");
903
+ expect(secret.required).toBe(false);
904
+ expect(secret.description).toContain("[REDACTED]");
905
+ expect(secret.description).toContain("cannot be turned off again");
906
+ expect(secret.description).not.toMatch(/encrypt/i);
907
+ });
908
+
909
+ test("leaves the description optional", () => {
910
+ renderPage(pageCase.page);
911
+
912
+ expect(formField("description").required).toBe(false);
913
+ expect(formField("description").fieldType).toBe("LongText");
914
+ });
915
+
916
+ test("validates the name", () => {
917
+ renderPage(pageCase.page);
918
+
919
+ const name: FormFieldEntry = formField("name");
920
+
921
+ expect(name.required).toBe(true);
922
+ expect(name.fieldType).toBe("Text");
923
+ expect(name.validation).toEqual({
924
+ minLength: 2,
925
+ noSpaces: true,
926
+ noSpecialCharacters: true,
443
927
  });
928
+ });
444
929
 
445
- expect(updateById).toHaveBeenCalledTimes(1);
930
+ /*
931
+ * Nothing links a workflow to the variable row it names, so renaming a
932
+ * variable silently breaks every workflow using the old name. The form is
933
+ * the one place that can say so, in the page's own reference syntax.
934
+ */
935
+ test("shows the page's reference syntax, and warns that renaming breaks it", () => {
936
+ renderPage(pageCase.page);
446
937
 
447
- const call: Record<string, unknown> = updateById.mock
448
- .calls[0]?.[0] as Record<string, unknown>;
938
+ const description: string = formField("name").description || "";
449
939
 
450
- expect(String(call["id"])).toBe(VARIABLE_ID.toString());
451
- expect(call["data"]).toEqual({ content: "rotated-token" });
452
- expect(call["modelType"]).toBe(WorkflowVariable);
940
+ expect(description).toContain(pageCase.reference);
941
+ expect(description).not.toContain(pageCase.otherReference);
942
+ expect(description).toContain(
943
+ "Renaming it does not update workflows that already refer to the old name",
944
+ );
453
945
  });
454
946
 
455
- test("closes on success", async () => {
456
- renderPage(page);
457
- openUpdateContentModal();
947
+ test("stamps Static on what it creates", async () => {
948
+ renderPage(pageCase.page);
458
949
 
459
- expect(screen.queryByTestId("update-content-modal")).not.toBeNull();
950
+ const created: WorkflowVariable = (await table().onBeforeCreate!(
951
+ new WorkflowVariable(),
952
+ )) as WorkflowVariable;
460
953
 
461
- await act(async () => {
462
- modal().onSubmit?.({ content: "rotated-token" });
954
+ expect(created.variableType).toBe(WorkflowVariableType.Static);
955
+ });
956
+
957
+ // The form cannot make anything else, whatever arrives in its values.
958
+ test("stamps Static even over a type the values claim to be OAuth 2.0", async () => {
959
+ renderPage(pageCase.page);
960
+
961
+ const item: WorkflowVariable = new WorkflowVariable();
962
+ item.variableType = WorkflowVariableType.OAuth2;
963
+
964
+ const created: WorkflowVariable = (await table().onBeforeCreate!(
965
+ item,
966
+ )) as WorkflowVariable;
967
+
968
+ expect(created.variableType).toBe(WorkflowVariableType.Static);
969
+ });
970
+
971
+ test(
972
+ pageCase.page === "global"
973
+ ? "leaves the workflow unset, so the variable is global"
974
+ : "stamps the workflow, so the variable is local to it",
975
+ async () => {
976
+ renderPage(pageCase.page);
977
+
978
+ const created: WorkflowVariable = (await table().onBeforeCreate!(
979
+ new WorkflowVariable(),
980
+ )) as WorkflowVariable;
981
+
982
+ if (pageCase.workflowId) {
983
+ expect(created.workflowId?.toString()).toBe(
984
+ pageCase.workflowId.toString(),
985
+ );
986
+ } else {
987
+ expect(created.workflowId).toBeUndefined();
988
+ }
989
+ },
990
+ );
991
+ });
992
+
993
+ describe("what the list reads", () => {
994
+ test("is scoped to the page's variables in the current project", () => {
995
+ renderPage(pageCase.page);
996
+
997
+ if (pageCase.workflowId) {
998
+ expect(table().query?.["workflowId"]).toBe(pageCase.workflowId);
999
+ } else {
1000
+ expect(table().query?.["workflowId"]).toBeInstanceOf(IsNull);
1001
+ }
1002
+
1003
+ expect(table().query?.["projectId"]).toBe(PROJECT_ID);
1004
+ });
1005
+
1006
+ // The Type column needs the type and grant type; nothing else rides along.
1007
+ test("selects the type and the grant type, and nothing more", () => {
1008
+ renderPage(pageCase.page);
1009
+
1010
+ expect(table().selectMoreFields).toEqual({
1011
+ variableType: true,
1012
+ oauthGrantType: true,
463
1013
  });
1014
+ });
1015
+
1016
+ test("never selects content, a credential or a token", () => {
1017
+ renderPage(pageCase.page);
1018
+
1019
+ const select: Array<string> = Object.keys(table().selectMoreFields || {});
1020
+
1021
+ for (const name of NEVER_SELECTED_FIELDS) {
1022
+ expect(select).not.toContain(name);
464
1023
 
465
- /*
466
- * Asked of the DOM rather than of the recorder: the recorder only ever
467
- * gains props, so a modal that unmounted still has its last render
468
- * sitting in it.
469
- */
470
- expect(screen.queryByTestId("update-content-modal")).toBeNull();
1024
+ for (const entry of table().columns || []) {
1025
+ expect(fieldName(entry)).not.toBe(name);
1026
+ }
1027
+
1028
+ for (const filter of table().filters || []) {
1029
+ expect(fieldName(filter)).not.toBe(name);
1030
+ }
1031
+
1032
+ expect(table().searchableFields || []).not.toContain(name);
1033
+ }
471
1034
  });
472
1035
 
473
1036
  /*
474
- * The neighbouring secret-rotation modals swallow this error, which loses
475
- * whatever the user typed and looks exactly like a save that worked. On a
476
- * credential that is the difference between a rotation and a silent
477
- * non-rotation.
1037
+ * The two lists keep their own saved filters and column preferences, so
1038
+ * the ids must differ.
478
1039
  */
479
- test("stays open and says why when the write fails", async () => {
480
- renderPage(page);
481
- openUpdateContentModal();
1040
+ test("keeps its table and filter ids apart from the other page's", () => {
1041
+ renderPage(pageCase.page);
1042
+
1043
+ if (pageCase.workflowId) {
1044
+ expect(table().id).toBe("workflow-variables-table");
1045
+ expect(table().saveFilterProps?.tableId).toBe(
1046
+ "workflow-view-variables-table",
1047
+ );
1048
+ } else {
1049
+ expect(table().id).toBe("global-workflow-variables-table");
1050
+ expect(table().saveFilterProps?.tableId).toBe(
1051
+ "workflow-variables-table",
1052
+ );
1053
+ }
1054
+ });
1055
+ });
482
1056
 
483
- updateById.mockRejectedValue(new Error("Not authorized."));
1057
+ describe("the More menu", () => {
1058
+ test("holds exactly one entry: Create OAuth 2.0 Variable", () => {
1059
+ renderPage(pageCase.page);
484
1060
 
485
- await act(async () => {
486
- modal().onSubmit?.({ content: "rotated-token" });
487
- });
1061
+ expect(
1062
+ moreMenuButtons().map((entry: CardButtonEntry) => {
1063
+ return entry.title;
1064
+ }),
1065
+ ).toEqual([OAUTH_MENU_TITLE]);
1066
+ });
488
1067
 
489
- expect(screen.queryByTestId("update-content-modal")).not.toBeNull();
490
- expect(modal().error).toBe("Not authorized.");
1068
+ /*
1069
+ * BaseModelTable puts one button beside the search - the NORMAL button
1070
+ * with the Add icon, or failing that the first NORMAL or PRIMARY one - and
1071
+ * everything else in the More (⋯) menu. An OUTLINE button with its own
1072
+ * icon can never be picked, so this entry stays in the menu even for
1073
+ * somebody the Create button is hidden from.
1074
+ */
1075
+ test("is an outline button, so the table never promotes it beside the search", () => {
1076
+ renderPage(pageCase.page);
1077
+
1078
+ const button: CardButtonEntry = oauthMenuButton();
1079
+
1080
+ expect(button.buttonStyle).toBe(ButtonStyleType.OUTLINE);
1081
+ expect(button.buttonStyle).not.toBe(ButtonStyleType.NORMAL);
1082
+ expect(button.buttonStyle).not.toBe(ButtonStyleType.PRIMARY);
1083
+ expect(button.icon).toBe(IconProp.Key);
1084
+ expect(button.icon).not.toBe(IconProp.Add);
1085
+ });
1086
+
1087
+ test("the card tells people where to find it", () => {
1088
+ renderPage(pageCase.page);
1089
+
1090
+ expect(table().cardProps?.description).toContain("More menu");
1091
+ expect(table().cardProps?.description).toContain("OAuth 2.0");
1092
+ });
1093
+
1094
+ test("is enabled for a project admin, and says what an OAuth variable is", () => {
1095
+ permissionsForTest = [Permission.ProjectAdmin];
1096
+
1097
+ renderPage(pageCase.page);
1098
+
1099
+ expect(oauthMenuButton().disabled).toBe(false);
1100
+ expect(oauthMenuButton().tooltip).toContain("access token");
1101
+ });
1102
+
1103
+ // The gate follows the model's create list, not just the admin roles.
1104
+ test("is enabled for somebody who may only create workflow variables", () => {
1105
+ permissionsForTest = [Permission.CreateWorkflowVariable];
1106
+
1107
+ renderPage(pageCase.page);
1108
+
1109
+ expect(oauthMenuButton().disabled).toBe(false);
1110
+ });
1111
+
1112
+ test("is enabled for a master admin, even before the permission snapshot arrives", () => {
1113
+ permissionsForTest = [];
1114
+ isMasterAdminForTest = true;
1115
+
1116
+ renderPage(pageCase.page);
1117
+
1118
+ expect(oauthMenuButton().disabled).toBe(false);
491
1119
  });
492
1120
 
493
1121
  /*
494
- * BasicFormModal unmounts its form while it is loading, so the form that
495
- * comes back after a failure is a fresh one. Without the draft it comes back
496
- * empty - and the person who has just pasted a long token has to go and find
497
- * it again, which is exactly the friction this whole change is about.
1122
+ * Locked, with the reason, rather than a form that 403s after somebody
1123
+ * has pasted a client secret into it.
498
1124
  */
499
- test("keeps what the user typed when the write fails", async () => {
500
- renderPage(page);
501
- openUpdateContentModal();
1125
+ test("is locked for a viewer, with a tooltip naming the missing permission", () => {
1126
+ permissionsForTest = [Permission.Viewer];
502
1127
 
503
- expect(modal().formProps.initialValues).toEqual({});
1128
+ renderPage(pageCase.page);
504
1129
 
505
- updateById.mockRejectedValue(new Error("Not authorized."));
1130
+ const button: CardButtonEntry = oauthMenuButton();
506
1131
 
507
- await act(async () => {
508
- modal().onSubmit?.({ content: "rotated-token" });
509
- });
1132
+ expect(button.disabled).toBe(true);
1133
+ expect(button.tooltip).toContain(
1134
+ "You do not have permission to create this Workflow Variable",
1135
+ );
1136
+ expect(button.tooltip).toContain("Create Workflow Variables");
1137
+ });
510
1138
 
511
- expect(modal().formProps.initialValues).toEqual({
512
- content: "rotated-token",
1139
+ test("does nothing when pressed while locked", () => {
1140
+ permissionsForTest = [Permission.Viewer];
1141
+
1142
+ renderPage(pageCase.page);
1143
+
1144
+ act(() => {
1145
+ oauthMenuButton().onClick();
513
1146
  });
1147
+
1148
+ expect(isOAuthFormOpen()).toBe(false);
1149
+ expect(capturedOAuthModalProps).toBeNull();
514
1150
  });
515
1151
 
516
- test("does not carry the draft into the next variable", async () => {
517
- renderPage(page);
518
- openUpdateContentModal();
1152
+ /*
1153
+ * An empty snapshot is "not loaded yet", not "not allowed": a disabled
1154
+ * button there would blame somebody who may well hold the permission.
1155
+ */
1156
+ test("is hidden, not locked, while the permission snapshot is still empty", () => {
1157
+ permissionsForTest = [];
519
1158
 
520
- updateById.mockRejectedValue(new Error("Not authorized."));
1159
+ renderPage(pageCase.page);
521
1160
 
522
- await act(async () => {
523
- modal().onSubmit?.({ content: "rotated-token" });
524
- });
1161
+ expect(moreMenuButtons()).toEqual([]);
1162
+ });
525
1163
 
526
- expect(modal().formProps.initialValues).toEqual({
527
- content: "rotated-token",
528
- });
1164
+ /*
1165
+ * The snapshot rides in on an API response header. Without a re-render
1166
+ * after the first fetch, the entry would stay hidden for the life of the
1167
+ * page after a fresh sign-in.
1168
+ */
1169
+ test("appears once the list's first fetch brings the permission snapshot in", () => {
1170
+ permissionsForTest = [];
1171
+
1172
+ renderPage(pageCase.page);
1173
+
1174
+ expect(moreMenuButtons()).toEqual([]);
1175
+
1176
+ permissionsForTest = [Permission.ProjectAdmin];
529
1177
 
530
1178
  act(() => {
531
- modal().onClose?.();
1179
+ table().onFetchSuccess!([], 0);
532
1180
  });
533
1181
 
534
- openUpdateContentModal();
1182
+ expect(oauthMenuButton().disabled).toBe(false);
1183
+ });
1184
+
1185
+ test("opens the OAuth 2.0 create form for this page's variables", () => {
1186
+ renderPage(pageCase.page);
535
1187
 
536
- expect(modal().formProps.initialValues).toEqual({});
1188
+ expect(isOAuthFormOpen()).toBe(false);
1189
+
1190
+ openOAuthForm();
1191
+
1192
+ expect(isOAuthFormOpen()).toBe(true);
1193
+
1194
+ if (pageCase.workflowId) {
1195
+ expect(oauthForm().workflowId).toBe(pageCase.workflowId);
1196
+ } else {
1197
+ expect(oauthForm().workflowId).toBeUndefined();
1198
+ }
537
1199
  });
538
1200
 
539
- test("does not keep the draft after a write that worked", async () => {
540
- renderPage(page);
541
- openUpdateContentModal();
1201
+ test("closing the form without creating hides it and fetches no token", () => {
1202
+ renderPage(pageCase.page);
542
1203
 
543
- await act(async () => {
544
- modal().onSubmit?.({ content: "rotated-token" });
1204
+ openOAuthForm();
1205
+
1206
+ act(() => {
1207
+ oauthForm().onClose();
1208
+ });
1209
+
1210
+ expect(isOAuthFormOpen()).toBe(false);
1211
+ expect(isRefreshModalOpen()).toBe(false);
1212
+ expect(apiPost).not.toHaveBeenCalled();
1213
+ });
1214
+
1215
+ test("can be opened again after it was closed", () => {
1216
+ renderPage(pageCase.page);
1217
+
1218
+ openOAuthForm();
1219
+
1220
+ act(() => {
1221
+ oauthForm().onClose();
545
1222
  });
546
1223
 
547
- openUpdateContentModal();
1224
+ openOAuthForm();
548
1225
 
549
- expect(modal().formProps.initialValues).toEqual({});
1226
+ expect(isOAuthFormOpen()).toBe(true);
550
1227
  });
1228
+ });
551
1229
 
1230
+ describe("after an OAuth 2.0 variable is created", () => {
552
1231
  /*
553
- * makeVariable defaulted to one id, so "the row that was clicked" could not
554
- * be told apart from "whichever row was opened first" - which is the exact
555
- * class of stale-selection bug this change fixes in BaseModelTable. Rotating
556
- * a credential onto the wrong variable would be invisible: content is never
557
- * read back, so it would surface only as a workflow authenticating with the
558
- * wrong token.
1232
+ * A token request can take up to 20 seconds. The modal opens as soon as
1233
+ * it goes out, so something on screen says it is happening.
559
1234
  */
560
- test("writes the second variable when the second one was clicked", async () => {
561
- renderPage(page);
1235
+ test("closes the form and shows a pending token modal while the provider is asked", async () => {
1236
+ const response: Deferred<unknown> = createDeferred<unknown>();
1237
+ apiPost.mockReturnValue(response.promise);
562
1238
 
563
- openUpdateContentModal(makeVariable(VARIABLE_ID, "First"));
1239
+ renderPage(pageCase.page);
1240
+ openOAuthForm();
564
1241
 
565
1242
  act(() => {
566
- modal().onClose?.();
1243
+ oauthForm().onSuccess(oauthVariable());
567
1244
  });
568
1245
 
569
- openUpdateContentModal(makeVariable(OTHER_VARIABLE_ID, "Second"));
570
-
571
- expect(modal().description).toContain("Second");
1246
+ expect(isOAuthFormOpen()).toBe(false);
1247
+ expect(refreshModal().outcome).toBeNull();
1248
+ expect(refreshModal().variableName).toBe("API_TOKEN");
1249
+ expect(apiPost).toHaveBeenCalledTimes(1);
572
1250
 
573
1251
  await act(async () => {
574
- modal().onSubmit?.({ content: "second-token" });
1252
+ response.resolve({
1253
+ data: { oauthAccessTokenExpiresAt: EXPIRES_AT_ISO },
1254
+ });
1255
+ await response.promise;
1256
+ });
1257
+
1258
+ await waitFor(() => {
1259
+ expect(refreshModal().outcome).not.toBeNull();
575
1260
  });
1261
+ });
1262
+
1263
+ test("asks for the new variable's first token through the refresh route, with the tenant header", async () => {
1264
+ renderPage(pageCase.page);
1265
+
1266
+ await createOAuthVariable(oauthVariable());
1267
+
1268
+ expect(apiPost).toHaveBeenCalledTimes(1);
1269
+ expect(refreshCall().url).toContain(
1270
+ `/workflow-variable/${VARIABLE_ID.toString()}/refresh-oauth-token`,
1271
+ );
1272
+ expect(refreshCall().headers).toEqual({ tenantid: "project-header" });
1273
+ expect(refreshCall().data).toEqual({});
1274
+ });
1275
+
1276
+ test("shows when the new token expires once the provider answers", async () => {
1277
+ renderPage(pageCase.page);
1278
+
1279
+ await createOAuthVariable(oauthVariable());
1280
+
1281
+ const outcome: TokenRefreshOutcome = refreshModal().outcome!;
576
1282
 
577
- const call: Record<string, unknown> = updateById.mock
578
- .calls[0]?.[0] as Record<string, unknown>;
1283
+ expect(outcome.variableName).toBe("API_TOKEN");
1284
+ expect(outcome.error).toBeUndefined();
1285
+ expect(outcome.savedWhat).toBeUndefined();
1286
+ expect(outcome.expiresAt).toEqual(new Date(EXPIRES_AT_ISO));
579
1287
 
580
- expect(String(call["id"])).toBe(OTHER_VARIABLE_ID.toString());
1288
+ // Pending first, then the answer - never the answer out of nowhere.
1289
+ expect(refreshModalOutcomes[0]).toBeNull();
1290
+ expect(refreshModalOutcomes[refreshModalOutcomes.length - 1]).toBe(
1291
+ outcome,
1292
+ );
1293
+ });
1294
+
1295
+ test("says so when the provider does not say when the token expires", async () => {
1296
+ apiPost.mockResolvedValue({ data: {} });
1297
+
1298
+ renderPage(pageCase.page);
1299
+
1300
+ await createOAuthVariable(oauthVariable());
1301
+
1302
+ expect(refreshModal().outcome!.error).toBeUndefined();
1303
+ expect(refreshModal().outcome!.expiresAt).toBeNull();
581
1304
  });
582
1305
 
583
1306
  /*
584
- * BasicFormModal unmounts its form while isLoading is true. A flag left
585
- * stuck on turns the error state into a modal with a message, no field to
586
- * retry in, and nothing the user typed - reachable only by reloading.
1307
+ * A mistyped secret or token URL shows up while the person who typed it
1308
+ * is still looking, in the provider's own words.
587
1309
  */
588
- test("stops loading whether the write succeeds or fails", async () => {
589
- renderPage(page);
590
- openUpdateContentModal();
1310
+ test("shows the provider's refusal", async () => {
1311
+ apiPost.mockResolvedValue(
1312
+ new HTTPErrorResponse(
1313
+ 400,
1314
+ {
1315
+ message:
1316
+ "invalid_client: AADSTS7000215: Invalid client secret provided.",
1317
+ },
1318
+ {},
1319
+ ),
1320
+ );
591
1321
 
592
- updateById.mockRejectedValue(new Error("Not authorized."));
1322
+ renderPage(pageCase.page);
593
1323
 
594
- await act(async () => {
595
- modal().onSubmit?.({ content: "rotated-token" });
596
- });
1324
+ await createOAuthVariable(oauthVariable());
597
1325
 
598
- expect(modal().isLoading).toBe(false);
1326
+ const outcome: TokenRefreshOutcome = refreshModal().outcome!;
599
1327
 
600
- updateById.mockResolvedValue(undefined);
1328
+ expect(outcome.variableName).toBe("API_TOKEN");
1329
+ expect(outcome.error).toBe(
1330
+ "invalid_client: AADSTS7000215: Invalid client secret provided.",
1331
+ );
1332
+ expect(outcome.expiresAt).toBeUndefined();
1333
+ });
601
1334
 
602
- await act(async () => {
603
- modal().onSubmit?.({ content: "rotated-token" });
604
- });
1335
+ test("shows a request that never reached the provider", async () => {
1336
+ apiPost.mockRejectedValue(new Error("Network Error"));
605
1337
 
606
- expect(screen.queryByTestId("update-content-modal")).toBeNull();
1338
+ renderPage(pageCase.page);
1339
+
1340
+ await createOAuthVariable(oauthVariable());
1341
+
1342
+ expect(refreshModal().outcome!.error).toBe("Network Error");
1343
+ });
1344
+
1345
+ test("does not call the refresh route for a variable that came back without an id", async () => {
1346
+ renderPage(pageCase.page);
1347
+
1348
+ const variable: WorkflowVariable = oauthVariable({ _id: undefined });
1349
+
1350
+ await createOAuthVariable(variable);
1351
+
1352
+ expect(apiPost).not.toHaveBeenCalled();
1353
+ expect(refreshModal().outcome!.error).toContain(
1354
+ "This variable has no id",
1355
+ );
1356
+ });
1357
+
1358
+ test("calls a variable without a name 'this variable'", async () => {
1359
+ renderPage(pageCase.page);
1360
+
1361
+ const variable: WorkflowVariable = oauthVariable({ name: undefined });
1362
+
1363
+ await createOAuthVariable(variable);
1364
+
1365
+ expect(refreshModal().variableName).toBe("this variable");
1366
+ expect(refreshModal().outcome!.variableName).toBe("this variable");
607
1367
  });
608
1368
 
609
1369
  /*
610
- * The guard that replaced a bare non-null assertion on the id. It must fail
611
- * loudly and leave the modal usable rather than firing a request at an
612
- * undefined id.
1370
+ * Once when the row is added, so it shows at once, and again once the
1371
+ * refresh has written the expiry or the failure to it.
613
1372
  */
614
- test("refuses to write a variable that has no id", async () => {
615
- renderPage(page);
616
- openUpdateContentModal(makeVariable(null));
1373
+ test("refreshes the list when the variable is created, and again once the outcome is in", async () => {
1374
+ const response: Deferred<unknown> = createDeferred<unknown>();
1375
+ apiPost.mockReturnValue(response.promise);
1376
+
1377
+ renderPage(pageCase.page);
1378
+
1379
+ const initialToggle: string | undefined = table().refreshToggle;
1380
+ expect(initialToggle).toBeTruthy();
1381
+
1382
+ openOAuthForm();
1383
+
1384
+ act(() => {
1385
+ oauthForm().onSuccess(oauthVariable());
1386
+ });
1387
+
1388
+ const afterCreateToggle: string | undefined = table().refreshToggle;
1389
+ expect(afterCreateToggle).not.toBe(initialToggle);
617
1390
 
618
1391
  await act(async () => {
619
- modal().onSubmit?.({ content: "rotated-token" });
1392
+ response.resolve({
1393
+ data: { oauthAccessTokenExpiresAt: EXPIRES_AT_ISO },
1394
+ });
1395
+ await response.promise;
620
1396
  });
621
1397
 
622
- expect(updateById).not.toHaveBeenCalled();
623
- expect(screen.queryByTestId("update-content-modal")).not.toBeNull();
624
- expect(modal().error).toContain("no id");
625
- expect(modal().isLoading).toBe(false);
1398
+ await waitFor(() => {
1399
+ expect(table().refreshToggle).not.toBe(afterCreateToggle);
1400
+ });
1401
+
1402
+ expect(table().refreshToggle).not.toBe(initialToggle);
626
1403
  });
627
1404
 
628
- test("clears the error when reopened", async () => {
629
- renderPage(page);
630
- openUpdateContentModal();
1405
+ test("closing the outcome modal removes it", async () => {
1406
+ renderPage(pageCase.page);
631
1407
 
632
- updateById.mockRejectedValue(new Error("Not authorized."));
1408
+ await createOAuthVariable(oauthVariable());
633
1409
 
634
- await act(async () => {
635
- modal().onSubmit?.({ content: "rotated-token" });
1410
+ expect(isRefreshModalOpen()).toBe(true);
1411
+
1412
+ act(() => {
1413
+ refreshModal().onClose();
636
1414
  });
637
1415
 
638
- expect(modal().error).toBe("Not authorized.");
1416
+ expect(isRefreshModalOpen()).toBe(false);
1417
+ expect(isOAuthFormOpen()).toBe(false);
1418
+ });
1419
+
1420
+ test("closing the outcome modal after a failure removes it too", async () => {
1421
+ apiPost.mockRejectedValue(new Error("Network Error"));
1422
+
1423
+ renderPage(pageCase.page);
1424
+
1425
+ await createOAuthVariable(oauthVariable());
639
1426
 
640
1427
  act(() => {
641
- modal().onClose?.();
1428
+ refreshModal().onClose();
642
1429
  });
643
1430
 
644
- openUpdateContentModal();
1431
+ expect(isRefreshModalOpen()).toBe(false);
1432
+ });
1433
+
1434
+ // Only the OAuth form's success fetches a token; the Create form never does.
1435
+ test("a static variable created from the Create form fetches no token", async () => {
1436
+ renderPage(pageCase.page);
1437
+
1438
+ await act(async () => {
1439
+ await table().onBeforeCreate!(new WorkflowVariable());
1440
+ });
645
1441
 
646
- expect(modal().error).toBeUndefined();
1442
+ expect(apiPost).not.toHaveBeenCalled();
1443
+ expect(isRefreshModalOpen()).toBe(false);
647
1444
  });
648
1445
  });
649
1446
 
650
- describe("who may use it", () => {
651
- /*
652
- * The action writes through ModelAPI directly, which ModelTable's own edit
653
- * gating never sees - so without its own gate a member without update
654
- * permission would get a modal that 403s after they had pasted a token
655
- * into it.
656
- */
657
- test("is locked, with the missing permission named, for a viewer", () => {
658
- permissionsForTest = [Permission.Viewer];
1447
+ /*
1448
+ * Creating a variable and refreshing its token are different permissions.
1449
+ * Somebody who may create but not update would only get OneUptime's own
1450
+ * refusal back from the refresh route - shown as if their provider had said
1451
+ * no - so the page does not ask for them.
1452
+ */
1453
+ describe("whose new OAuth 2.0 variable gets its first token fetched", () => {
1454
+ test.each(CREATE_ONLY_ROLES)(
1455
+ "not somebody who may only create variables ($label): the form closes and the list refreshes, with no token request and no token modal",
1456
+ async (role: RoleCase) => {
1457
+ permissionsForTest = role.permissions;
659
1458
 
660
- renderPage(page);
1459
+ renderPage(pageCase.page);
661
1460
 
662
- expect(updateContentButton().disabled).toBe(true);
663
- expect(updateContentButton().tooltip).toContain(
664
- "You do not have permission to update",
665
- );
666
- expect(updateContentButton().isVisible?.(makeVariable())).toBe(true);
1461
+ const initialToggle: string | undefined = table().refreshToggle;
1462
+
1463
+ // They may create, so the menu entry does open the form.
1464
+ expect(oauthMenuButton().disabled).toBe(false);
1465
+
1466
+ openOAuthForm();
1467
+
1468
+ expect(isOAuthFormOpen()).toBe(true);
1469
+
1470
+ await saveOAuthVariable(oauthVariable());
1471
+
1472
+ expect(isOAuthFormOpen()).toBe(false);
1473
+
1474
+ // The new row still shows up at once.
1475
+ expect(table().refreshToggle).not.toBe(initialToggle);
1476
+
1477
+ expect(apiPost).not.toHaveBeenCalled();
1478
+ expect(isRefreshModalOpen()).toBe(false);
1479
+ expect(capturedRefreshModalProps).toBeNull();
1480
+ expect(refreshModalOutcomes).toEqual([]);
1481
+ },
1482
+ );
1483
+
1484
+ // With no token request there is nothing to wait for, so no second bump.
1485
+ test("refreshes the list once, and only once, for somebody who may only create", async () => {
1486
+ permissionsForTest = [
1487
+ Permission.CreateWorkflowVariable,
1488
+ Permission.ReadWorkflowVariable,
1489
+ ];
1490
+
1491
+ renderPage(pageCase.page);
1492
+
1493
+ const initialToggle: string | undefined = table().refreshToggle;
1494
+
1495
+ openOAuthForm();
1496
+
1497
+ await saveOAuthVariable(oauthVariable());
1498
+
1499
+ const afterCreateToggle: string | undefined = table().refreshToggle;
1500
+
1501
+ expect(afterCreateToggle).not.toBe(initialToggle);
1502
+
1503
+ await act(async () => {
1504
+ await Promise.resolve();
1505
+ });
1506
+
1507
+ expect(table().refreshToggle).toBe(afterCreateToggle);
667
1508
  });
668
1509
 
669
- test("is enabled for a key holding EditWorkflowVariable", () => {
670
- permissionsForTest = [Permission.EditWorkflowVariable];
1510
+ test("can open the form again afterwards, still without a token modal in the way", async () => {
1511
+ permissionsForTest = [
1512
+ Permission.CreateWorkflowVariable,
1513
+ Permission.ReadWorkflowVariable,
1514
+ ];
671
1515
 
672
- renderPage(page);
1516
+ renderPage(pageCase.page);
673
1517
 
674
- expect(updateContentButton().disabled).toBe(false);
1518
+ openOAuthForm();
1519
+
1520
+ await saveOAuthVariable(oauthVariable());
1521
+
1522
+ openOAuthForm();
1523
+
1524
+ expect(isOAuthFormOpen()).toBe(true);
1525
+ expect(isRefreshModalOpen()).toBe(false);
675
1526
  });
676
1527
 
1528
+ test.each(CREATE_AND_UPDATE_ROLES)(
1529
+ "somebody who may also update variables ($label): asks for the token and shows the outcome",
1530
+ async (role: RoleCase) => {
1531
+ permissionsForTest = role.permissions;
1532
+
1533
+ renderPage(pageCase.page);
1534
+
1535
+ await createOAuthVariable(oauthVariable());
1536
+
1537
+ expect(isOAuthFormOpen()).toBe(false);
1538
+ expect(apiPost).toHaveBeenCalledTimes(1);
1539
+ expect(refreshCall().url).toContain(
1540
+ `/workflow-variable/${VARIABLE_ID.toString()}/refresh-oauth-token`,
1541
+ );
1542
+
1543
+ expect(refreshModal().variableName).toBe("API_TOKEN");
1544
+ expect(refreshModal().outcome!.error).toBeUndefined();
1545
+ expect(refreshModal().outcome!.expiresAt).toEqual(
1546
+ new Date(EXPIRES_AT_ISO),
1547
+ );
1548
+ expect(refreshModalOutcomes[0]).toBeNull();
1549
+ },
1550
+ );
1551
+
677
1552
  /*
678
- * The permission snapshot rides in on a response header, so it is empty for
679
- * the first paint after a login or a project switch. PermissionGate reports
680
- * that as "not allowed, no reason" precisely so callers hide the affordance
681
- * rather than accuse somebody who may well hold the permission.
1553
+ * PermissionGate lets a master admin do everything before it even looks
1554
+ * at the snapshot, so an empty one does not stop the fetch.
682
1555
  */
683
- test("is hidden entirely while the permission snapshot is still empty", () => {
1556
+ test("a master admin, even before the permission snapshot arrives", async () => {
684
1557
  permissionsForTest = [];
1558
+ isMasterAdminForTest = true;
685
1559
 
686
- renderPage(page);
1560
+ renderPage(pageCase.page);
687
1561
 
688
- expect(updateContentButton().isVisible?.(makeVariable())).toBe(false);
1562
+ await createOAuthVariable(oauthVariable());
1563
+
1564
+ expect(apiPost).toHaveBeenCalledTimes(1);
1565
+ expect(refreshCall().url).toContain(
1566
+ `/workflow-variable/${VARIABLE_ID.toString()}/refresh-oauth-token`,
1567
+ );
1568
+ expect(refreshModal().outcome!.expiresAt).toEqual(
1569
+ new Date(EXPIRES_AT_ISO),
1570
+ );
689
1571
  });
690
- });
691
- });
692
1572
 
693
- describe("the two tables are scoped to different variables", () => {
694
- test("the global table asks for the rows with no workflow", () => {
695
- renderPage("global");
1573
+ test("a master admin whose project role may only create", async () => {
1574
+ permissionsForTest = [Permission.CreateWorkflowVariable];
1575
+ isMasterAdminForTest = true;
696
1576
 
697
- expect(table().query?.["workflowId"]).toBeInstanceOf(IsNull);
698
- expect(String(table().query?.["projectId"])).toBe(PROJECT_ID.toString());
699
- expect(table().cardProps?.title).toBe("Global Variables");
700
- });
1577
+ renderPage(pageCase.page);
701
1578
 
702
- test("the workflow table asks for that workflow's rows", () => {
703
- renderPage("local");
1579
+ await createOAuthVariable(oauthVariable());
704
1580
 
705
- expect(String(table().query?.["workflowId"])).toBe(WORKFLOW_ID.toString());
706
- expect(String(table().query?.["projectId"])).toBe(PROJECT_ID.toString());
707
- expect(table().cardProps?.title).toBe("Workflow Variables");
708
- });
1581
+ expect(apiPost).toHaveBeenCalledTimes(1);
1582
+ expect(isRefreshModalOpen()).toBe(true);
1583
+ });
709
1584
 
710
- /*
711
- * The stamp that makes a new row local rather than global. Getting it wrong
712
- * in the other direction is worse: a global variable created with a
713
- * workflowId disappears from the page that created it.
714
- */
715
- test("a variable created on the workflow page is stamped with the workflow", async () => {
716
- renderPage("local");
1585
+ // The gate is read when the variable is saved, not when the form opened.
1586
+ test("not somebody whose role lost update while the form was open", async () => {
1587
+ permissionsForTest = [Permission.ProjectAdmin];
717
1588
 
718
- const created: WorkflowVariable = (await table().onBeforeCreate?.(
719
- new WorkflowVariable(),
720
- )) as WorkflowVariable;
1589
+ renderPage(pageCase.page);
721
1590
 
722
- expect(created.workflowId?.toString()).toBe(WORKFLOW_ID.toString());
723
- });
1591
+ openOAuthForm();
724
1592
 
725
- test("a variable created on the global page is left unstamped", async () => {
726
- renderPage("global");
1593
+ permissionsForTest = [
1594
+ Permission.CreateWorkflowVariable,
1595
+ Permission.ReadWorkflowVariable,
1596
+ ];
727
1597
 
728
- const created: WorkflowVariable = (await table().onBeforeCreate?.(
729
- new WorkflowVariable(),
730
- )) as WorkflowVariable;
1598
+ await saveOAuthVariable(oauthVariable());
731
1599
 
732
- expect(created.workflowId).toBeUndefined();
733
- });
734
- });
1600
+ expect(isOAuthFormOpen()).toBe(false);
1601
+ expect(apiPost).not.toHaveBeenCalled();
1602
+ expect(isRefreshModalOpen()).toBe(false);
1603
+ });
735
1604
 
736
- describe("the content column never travels back to the browser", () => {
737
- /*
738
- * The read-back inventory. `content` is write-only by design, so every list
739
- * the table builds a select from has to stay clear of it - the columns, the
740
- * filters and the search fields alike - and the Update Content modal must
741
- * never fetch. If any of these ever names content, the list request stops
742
- * failing loudly and starts succeeding with the secret in the response.
743
- */
744
- test.each(PAGES)("%s", (page: Page) => {
745
- renderPage(page);
1605
+ test("somebody whose role gained update while the form was open", async () => {
1606
+ permissionsForTest = [
1607
+ Permission.CreateWorkflowVariable,
1608
+ Permission.ReadWorkflowVariable,
1609
+ ];
1610
+
1611
+ renderPage(pageCase.page);
746
1612
 
747
- for (const column of table().columns || []) {
748
- expect(Object.keys(column.field || {})).not.toContain("content");
749
- }
1613
+ openOAuthForm();
1614
+
1615
+ permissionsForTest = [
1616
+ Permission.CreateWorkflowVariable,
1617
+ Permission.EditWorkflowVariable,
1618
+ ];
1619
+
1620
+ await saveOAuthVariable(oauthVariable());
1621
+
1622
+ await waitFor(() => {
1623
+ expect(refreshModal().outcome).toBeTruthy();
1624
+ });
1625
+
1626
+ expect(apiPost).toHaveBeenCalledTimes(1);
1627
+ });
750
1628
 
751
1629
  /*
752
- * A filter on content would fail the list request the same way a column
753
- * would; selectMoreFields is injected straight into the select, so that one
754
- * would succeed and ship every variable's value to the browser.
1630
+ * An empty snapshot (not a master admin) is PermissionGate's "not loaded
1631
+ * yet": it does not allow, so the page does not ask. The variable still
1632
+ * gets its first token the first time a workflow uses it.
755
1633
  */
756
- for (const filter of table().filters || []) {
757
- expect(Object.keys(filter.field || {})).not.toContain("content");
758
- }
1634
+ test("not while the permission snapshot is empty at the moment of saving", async () => {
1635
+ permissionsForTest = [Permission.ProjectAdmin];
759
1636
 
760
- expect(Object.keys(table().selectMoreFields || {})).not.toContain(
761
- "content",
762
- );
763
- expect(table().searchableFields || []).not.toContain("content");
1637
+ renderPage(pageCase.page);
1638
+
1639
+ openOAuthForm();
1640
+
1641
+ permissionsForTest = [];
1642
+
1643
+ await saveOAuthVariable(oauthVariable());
764
1644
 
765
- openUpdateContentModal();
766
- expect(modal().formProps.initialValues).toEqual({});
1645
+ expect(isOAuthFormOpen()).toBe(false);
1646
+ expect(apiPost).not.toHaveBeenCalled();
1647
+ expect(isRefreshModalOpen()).toBe(false);
1648
+ });
767
1649
  });
768
1650
  });