@oneuptime/common 14.0.7 → 14.0.9

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 (1064) hide show
  1. package/Models/DatabaseModels/Incident.ts +267 -1
  2. package/Models/DatabaseModels/IncidentCustomField.ts +202 -0
  3. package/Models/DatabaseModels/IncidentEpisode.ts +30 -0
  4. package/Models/DatabaseModels/IncidentTemplate.ts +126 -1
  5. package/Models/DatabaseModels/Index.ts +2 -0
  6. package/Models/DatabaseModels/KubernetesAiAgent.ts +364 -0
  7. package/Models/DatabaseModels/KubernetesCluster.ts +3 -3
  8. package/Models/DatabaseModels/Project.ts +55 -5
  9. package/Models/DatabaseModels/ProxmoxResource.ts +49 -1
  10. package/Models/DatabaseModels/RunnerJob.ts +75 -0
  11. package/Models/DatabaseModels/StatusPage.ts +55 -0
  12. package/Models/DatabaseModels/StatusPageSubscriber.ts +128 -0
  13. package/Models/DatabaseModels/TeamComplianceSetting.ts +143 -2
  14. package/Models/DatabaseModels/WorkspaceProjectAuthToken.ts +17 -0
  15. package/Server/API/AIChatAPI.ts +6 -3
  16. package/Server/API/AIInvestigationAPI.ts +17 -10
  17. package/Server/API/AutoRemediationAPI.ts +207 -25
  18. package/Server/API/IncidentAPI.ts +162 -0
  19. package/Server/API/KubernetesClusterAiAccessAPI.ts +623 -21
  20. package/Server/API/MicrosoftTeamsAPI.ts +93 -14
  21. package/Server/API/ProxmoxResourceAPI.ts +244 -14
  22. package/Server/API/StatusPageAPI.ts +487 -171
  23. package/Server/API/StatusPageSubscriberAPI.ts +63 -15
  24. package/Server/Infrastructure/GlobalCache.ts +32 -0
  25. package/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.ts +49 -0
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.ts +108 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.ts +33 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.ts +51 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.ts +33 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.ts +168 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.ts +44 -0
  32. package/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.ts +99 -0
  33. package/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.ts +137 -0
  34. package/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.ts +42 -0
  35. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +20 -0
  36. package/Server/Infrastructure/Semaphore.ts +10 -0
  37. package/Server/Middleware/IdentityRateLimit.ts +108 -3
  38. package/Server/Middleware/SubscriberNotificationPreviewRateLimit.ts +237 -0
  39. package/Server/Middleware/SubscriberNotificationTestSendRateLimit.ts +304 -0
  40. package/Server/Middleware/TelemetryIngest.ts +41 -18
  41. package/Server/Services/AIService.ts +70 -1
  42. package/Server/Services/AlertService.ts +352 -11
  43. package/Server/Services/AlertSeverityService.ts +65 -15
  44. package/Server/Services/AutoRemediationRuleService.ts +1 -1
  45. package/Server/Services/DatabaseService.ts +93 -10
  46. package/Server/Services/IncidentCustomFieldService.ts +276 -1
  47. package/Server/Services/IncidentEpisodePublicNoteService.ts +28 -0
  48. package/Server/Services/IncidentEpisodeService.ts +15 -0
  49. package/Server/Services/IncidentEpisodeStateTimelineService.ts +27 -1
  50. package/Server/Services/IncidentPublicNoteService.ts +30 -1
  51. package/Server/Services/IncidentService.ts +1788 -142
  52. package/Server/Services/IncidentSeverityService.ts +66 -15
  53. package/Server/Services/IncidentStateTimelineService.ts +13 -0
  54. package/Server/Services/IncidentTemplateService.ts +109 -0
  55. package/Server/Services/KubernetesAiAgentJobService.ts +185 -0
  56. package/Server/Services/KubernetesAiAgentService.ts +1634 -0
  57. package/Server/Services/KubernetesClusterAiAccessService.ts +1118 -451
  58. package/Server/Services/KubernetesClusterService.ts +129 -21
  59. package/Server/Services/ProjectService.ts +32 -0
  60. package/Server/Services/ProxmoxResourceService.ts +322 -5
  61. package/Server/Services/RunnerJobService.ts +241 -104
  62. package/Server/Services/RunnerService.ts +1 -1
  63. package/Server/Services/ScheduledMaintenancePublicNoteService.ts +30 -1
  64. package/Server/Services/ScheduledMaintenanceService.ts +805 -19
  65. package/Server/Services/ScheduledMaintenanceStateTimelineService.ts +414 -56
  66. package/Server/Services/SmsService.ts +10 -0
  67. package/Server/Services/StatusPageService.ts +65 -8
  68. package/Server/Services/StatusPageSubscriberNotificationTemplateService.ts +299 -37
  69. package/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.ts +129 -0
  70. package/Server/Services/StatusPageSubscriberService.ts +1161 -64
  71. package/Server/Services/TeamComplianceSettingService.ts +1125 -9
  72. package/Server/Types/Markdown.ts +153 -6
  73. package/Server/Types/Workflow/Components/Email.ts +61 -2
  74. package/Server/Utils/AI/ClusterAccess/ClusterAccessContext.ts +67 -9
  75. package/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.ts +39 -10
  76. package/Server/Utils/AI/ClusterAccess/KubectlJobRunner.ts +14 -3
  77. package/Server/Utils/AI/Remediation/RemediationCommandTools.ts +37 -15
  78. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +67 -24
  79. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +48 -5
  80. package/Server/Utils/AI/SRE/IncidentPostmortemRunner.ts +40 -8
  81. package/Server/Utils/AI/SRE/InvestigationEligibility.ts +13 -2
  82. package/Server/Utils/AI/SRE/InvestigationGrader.ts +1 -1
  83. package/Server/Utils/AutoRemediation/CommandPlanExecutor.ts +6 -1
  84. package/Server/Utils/CustomField/CustomFieldRename.ts +378 -0
  85. package/Server/Utils/DataSource/EgressGuard.ts +66 -21
  86. package/Server/Utils/Mail/PinnedSmtpSocket.ts +130 -0
  87. package/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.ts +10 -0
  88. package/Server/Utils/SSRFProtection.ts +76 -16
  89. package/Server/Utils/StatusPage/IncidentStatusPageScope.ts +948 -0
  90. package/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.ts +656 -0
  91. package/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.ts +805 -0
  92. package/Server/Utils/StatusPage/StatusPageExclusion.ts +18 -0
  93. package/Server/Utils/StatusPage/StatusPageReadAccess.ts +125 -0
  94. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.ts +151 -0
  95. package/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.ts +70 -0
  96. package/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.ts +421 -0
  97. package/Server/Utils/StatusPage/SubscriberNotificationClaim.ts +107 -0
  98. package/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.ts +1049 -0
  99. package/Server/Utils/StatusPage/SubscriberNotificationFanOut.ts +180 -0
  100. package/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.ts +839 -0
  101. package/Server/Utils/StatusPage/SubscriberNotificationResendAccess.ts +393 -0
  102. package/Server/Utils/StatusPage/SubscriberNotificationRunLimit.ts +246 -0
  103. package/Server/Utils/StatusPage/SubscriberNotificationTiming.ts +133 -0
  104. package/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.ts +215 -0
  105. package/Server/Utils/StatusPageResource.ts +51 -20
  106. package/Server/Utils/Telemetry/InventoryEntityRegistry.ts +133 -7
  107. package/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.ts +58 -4
  108. package/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.ts +447 -0
  109. package/Server/Utils/Telemetry/ProxmoxNativePush.ts +903 -0
  110. package/Server/Utils/Telemetry/TelemetryEntity.ts +87 -27
  111. package/Server/Utils/VM/VMAPI.ts +1 -0
  112. package/Server/Utils/VM/VMRunner.ts +10 -0
  113. package/Server/Utils/Workflow/OAuth2TokenClient.ts +10 -0
  114. package/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.ts +684 -47
  115. package/Server/Views/Partials/SensitiveUrlToken.ejs +8 -5
  116. package/Tests/App/Accounts/RegisterVerifyEmail.test.tsx +748 -0
  117. package/Tests/App/Accounts/ResendVerificationEmail.test.tsx +1222 -0
  118. package/Tests/App/Accounts/VerificationEmailResendUtils.test.ts +797 -0
  119. package/Tests/App/Accounts/VerifyEmailPending.test.tsx +538 -0
  120. package/Tests/App/Accounts/VerifyEmailResend.test.tsx +779 -0
  121. package/Tests/App/AdminDashboard/RowActionPlacementOverrides.test.tsx +278 -0
  122. package/Tests/App/Dashboard/AIChatChartWidgetZoom.test.tsx +738 -0
  123. package/Tests/App/Dashboard/AIFeaturesSettingsPointers.test.tsx +147 -0
  124. package/Tests/App/Dashboard/AIInsightsKubernetesClusterPage.test.tsx +1523 -0
  125. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +463 -3
  126. package/Tests/App/Dashboard/AffectedResourcesPickerDropdownPlacement.test.tsx +958 -0
  127. package/Tests/App/Dashboard/AffectedResourcesPickerFocusLeave.test.tsx +595 -0
  128. package/Tests/App/Dashboard/AskAiAvailability.test.ts +20 -3
  129. package/Tests/App/Dashboard/AskAiDisabled.test.tsx +8 -3
  130. package/Tests/App/Dashboard/CephRateChartReload.test.tsx +1456 -0
  131. package/Tests/App/Dashboard/CephTimeRangeZoom.test.tsx +1229 -0
  132. package/Tests/App/Dashboard/ChartCardTimeRangeZoom.test.tsx +151 -0
  133. package/Tests/App/Dashboard/ChartCardZoomAffordances.test.tsx +257 -0
  134. package/Tests/App/Dashboard/ChartRefetchFrame.test.tsx +141 -0
  135. package/Tests/App/Dashboard/ChartZoomHarness.tsx +249 -0
  136. package/Tests/App/Dashboard/ChartZoomStandIn.tsx +131 -0
  137. package/Tests/App/Dashboard/CloudServerlessSlowLoads.test.tsx +628 -0
  138. package/Tests/App/Dashboard/CloudServerlessTimeRangeZoom.test.tsx +607 -0
  139. package/Tests/App/Dashboard/ClusterAccessNotice.test.tsx +91 -19
  140. package/Tests/App/Dashboard/CompanionMetricsTabZoom.test.tsx +632 -0
  141. package/Tests/App/Dashboard/ContainerChartZoomStandIn.tsx +195 -0
  142. package/Tests/App/Dashboard/ContainerHostOverviewSlowLoads.test.tsx +542 -0
  143. package/Tests/App/Dashboard/ContainerHostOverviewTimeRangeZoom.test.tsx +848 -0
  144. package/Tests/App/Dashboard/ContainerMetricsTimeRangeZoom.test.tsx +561 -0
  145. package/Tests/App/Dashboard/CustomFieldsSettingsIncidentOptions.test.tsx +357 -0
  146. package/Tests/App/Dashboard/DashboardBoardWideZoomShell.test.tsx +1147 -0
  147. package/Tests/App/Dashboard/DashboardEditPermissions.test.tsx +3 -2
  148. package/Tests/App/Dashboard/DashboardHistogramWidgetDragCursor.test.tsx +399 -0
  149. package/Tests/App/Dashboard/DashboardHistogramWidgetZoom.test.tsx +985 -0
  150. package/Tests/App/Dashboard/DashboardHistogramWidgetZoomHint.test.tsx +803 -0
  151. package/Tests/App/Dashboard/DashboardLazyPages.test.tsx +1 -0
  152. package/Tests/App/Dashboard/DashboardSettingsPreviewZoom.test.tsx +679 -0
  153. package/Tests/App/Dashboard/DashboardSloAndDataSourceChartZoom.test.tsx +881 -0
  154. package/Tests/App/Dashboard/DashboardTraceStatusWidgets.test.tsx +878 -0
  155. package/Tests/App/Dashboard/DatabaseMetricChartModalTimeRangeZoom.test.tsx +442 -0
  156. package/Tests/App/Dashboard/DatabaseOverviewTimeRangeZoom.test.tsx +831 -0
  157. package/Tests/App/Dashboard/DatabaseServerComponents.test.tsx +43 -0
  158. package/Tests/App/Dashboard/DockerSwarmInsightsTimeRangeZoom.test.tsx +524 -0
  159. package/Tests/App/Dashboard/DockerSwarmRateChartRefresh.test.tsx +259 -0
  160. package/Tests/App/Dashboard/EdgeDetailPanelHistory.test.tsx +763 -0
  161. package/Tests/App/Dashboard/EdgeDetailPanelTimeRangeZoom.test.tsx +547 -0
  162. package/Tests/App/Dashboard/EdgeHistoryBucketsCases.tsx +565 -0
  163. package/Tests/App/Dashboard/EdgeHistoryBucketsKathmandu.test.tsx +73 -0
  164. package/Tests/App/Dashboard/EdgeHistoryBucketsKolkata.test.tsx +74 -0
  165. package/Tests/App/Dashboard/EdgeHistoryBucketsNewYork.test.tsx +72 -0
  166. package/Tests/App/Dashboard/EdgeHistoryBucketsUtc.test.tsx +72 -0
  167. package/Tests/App/Dashboard/EmbeddedMetricCardRefresh.test.tsx +310 -0
  168. package/Tests/App/Dashboard/EmbeddedMetricCardTimeRangeZoom.test.tsx +536 -0
  169. package/Tests/App/Dashboard/EscalationRuleReadiness.test.tsx +3 -1
  170. package/Tests/App/Dashboard/EscalationRuleRowActions.test.tsx +660 -0
  171. package/Tests/App/Dashboard/EventNotes.test.tsx +778 -2
  172. package/Tests/App/Dashboard/EventNotesPages.test.tsx +119 -0
  173. package/Tests/App/Dashboard/EventNotesUtil.test.ts +116 -17
  174. package/Tests/App/Dashboard/EventOverviewPages.test.tsx +828 -17
  175. package/Tests/App/Dashboard/EventOverviewSnapshotExplorerZoom.test.tsx +1139 -0
  176. package/Tests/App/Dashboard/EventOverviewSnapshotZoomAcrossTabs.test.tsx +1057 -0
  177. package/Tests/App/Dashboard/EventOverviewTelemetrySnapshotZoom.test.tsx +757 -0
  178. package/Tests/App/Dashboard/ExceptionOccurrenceTrendZoom.test.tsx +675 -0
  179. package/Tests/App/Dashboard/ExceptionOccurrencesZoomSurvivesViewSwitch.test.tsx +405 -0
  180. package/Tests/App/Dashboard/ExceptionSignalPages.test.tsx +67 -3
  181. package/Tests/App/Dashboard/ExceptionTablesSpanStatus.test.tsx +515 -0
  182. package/Tests/App/Dashboard/ExplorerOwnZoomRegression.test.tsx +739 -0
  183. package/Tests/App/Dashboard/FlowBandwidthAxisCases.tsx +461 -0
  184. package/Tests/App/Dashboard/FlowBandwidthAxisKathmandu.test.tsx +25 -0
  185. package/Tests/App/Dashboard/FlowBandwidthAxisKolkata.test.tsx +25 -0
  186. package/Tests/App/Dashboard/FlowBandwidthAxisNewYork.test.tsx +25 -0
  187. package/Tests/App/Dashboard/FlowBandwidthAxisUtc.test.tsx +24 -0
  188. package/Tests/App/Dashboard/FlowTopTalkersZoomRefetch.test.tsx +722 -0
  189. package/Tests/App/Dashboard/FlowViewportGuard.test.tsx +2526 -0
  190. package/Tests/App/Dashboard/HostPagesSlowLoads.test.tsx +872 -0
  191. package/Tests/App/Dashboard/HostPagesTimeRangeZoom.test.tsx +1208 -0
  192. package/Tests/App/Dashboard/IncidentChangeStateNotifyDefault.test.tsx +91 -1
  193. package/Tests/App/Dashboard/IncidentCreateDetailsStep.test.tsx +643 -0
  194. package/Tests/App/Dashboard/IncidentCreateFromAlerts.test.tsx +8 -1
  195. package/Tests/App/Dashboard/IncidentCreateStatusPageScope.test.tsx +601 -0
  196. package/Tests/App/Dashboard/IncidentCustomFieldTemplateVariables.test.tsx +386 -0
  197. package/Tests/App/Dashboard/IncidentNoteTemplatePlaceholders.test.tsx +124 -0
  198. package/Tests/App/Dashboard/IncidentNoteTemplateVariablesLoader.test.ts +305 -0
  199. package/Tests/App/Dashboard/IncidentOverviewNotifyDefault.test.tsx +112 -0
  200. package/Tests/App/Dashboard/IncidentRootCauseTimeRangeZoom.test.tsx +358 -0
  201. package/Tests/App/Dashboard/IncidentSettingsRenotifyOnPublish.test.tsx +674 -0
  202. package/Tests/App/Dashboard/IncidentSettingsStatusPageScope.test.tsx +1051 -0
  203. package/Tests/App/Dashboard/IncidentTemplateCustomFields.test.tsx +384 -0
  204. package/Tests/App/Dashboard/IncidentTemplateStatusPageScopeCard.test.tsx +215 -0
  205. package/Tests/App/Dashboard/InfrastructureGraph.test.tsx +100 -9
  206. package/Tests/App/Dashboard/InfrastructureMetricsTabTimeRangeZoom.test.tsx +485 -0
  207. package/Tests/App/Dashboard/InvestigationDrawerCompanionZoom.test.tsx +655 -0
  208. package/Tests/App/Dashboard/InvestigationDrawerZoom.test.tsx +830 -0
  209. package/Tests/App/Dashboard/InvestigationNotStarted.test.tsx +338 -2
  210. package/Tests/App/Dashboard/InvoicesPayInvoice.test.tsx +454 -16
  211. package/Tests/App/Dashboard/KubernetesClusterAiAccessSettings.test.ts +799 -819
  212. package/Tests/App/Dashboard/KubernetesClusterAiAgentOverviewCard.test.tsx +367 -0
  213. package/Tests/App/Dashboard/KubernetesClusterAiAgentStatus.test.ts +1202 -0
  214. package/Tests/App/Dashboard/KubernetesClusterAiDocumentationMarkdown.test.ts +106 -0
  215. package/Tests/App/Dashboard/KubernetesClusterAiNavigation.test.tsx +354 -0
  216. package/Tests/App/Dashboard/KubernetesClusterAiPage.test.tsx +1884 -2054
  217. package/Tests/App/Dashboard/KubernetesClusterAiPageServerParity.test.ts +478 -179
  218. package/Tests/App/Dashboard/KubernetesClusterMetricTooltips.test.ts +50 -0
  219. package/Tests/App/Dashboard/KubernetesClusterOverviewTooltips.test.tsx +2 -1
  220. package/Tests/App/Dashboard/KubernetesClusterOverviewZoom.test.tsx +1217 -0
  221. package/Tests/App/Dashboard/KubernetesClusterPagesZoom.test.tsx +731 -0
  222. package/Tests/App/Dashboard/KubernetesCostsLoadRecovery.test.tsx +869 -0
  223. package/Tests/App/Dashboard/KubernetesCostsZoom.test.tsx +1214 -0
  224. package/Tests/App/Dashboard/KubernetesCostsZoomExactHours.test.tsx +692 -0
  225. package/Tests/App/Dashboard/KubernetesNetworkThroughputReload.test.tsx +902 -0
  226. package/Tests/App/Dashboard/KubernetesNetworkZoomBucketEdges.test.tsx +571 -0
  227. package/Tests/App/Dashboard/KubernetesOverviewZoomBucketEdges.test.tsx +697 -0
  228. package/Tests/App/Dashboard/KubernetesResourceMetricsTabZoom.test.tsx +633 -0
  229. package/Tests/App/Dashboard/LogsExplorerTimeRangeZoom.test.tsx +470 -0
  230. package/Tests/App/Dashboard/LogsInsightsTimeRangeZoom.test.tsx +948 -0
  231. package/Tests/App/Dashboard/LogsViewerPinnedWindowZoom.test.tsx +486 -0
  232. package/Tests/App/Dashboard/MetricChartsBucketInspectorDoubleClick.test.tsx +1001 -0
  233. package/Tests/App/Dashboard/MetricExplorerInvestigationAutoRefresh.test.tsx +514 -0
  234. package/Tests/App/Dashboard/MetricExplorerSavedViewZoomRoundTrip.test.tsx +581 -0
  235. package/Tests/App/Dashboard/MetricExplorerTimeRangeZoom.test.tsx +1162 -0
  236. package/Tests/App/Dashboard/MetricMonitorPreviewZoomLabel.test.ts +72 -0
  237. package/Tests/App/Dashboard/MetricRowSparklineTimeRangeZoom.test.tsx +204 -0
  238. package/Tests/App/Dashboard/MetricViewFirstResultLands.test.tsx +408 -0
  239. package/Tests/App/Dashboard/MetricViewOwnZoomResetPlacement.test.tsx +952 -0
  240. package/Tests/App/Dashboard/MetricViewTimeRange.test.ts +139 -0
  241. package/Tests/App/Dashboard/MetricViewTimeRangeZoom.test.tsx +556 -0
  242. package/Tests/App/Dashboard/MonitorMetricsChartWrappersZoom.test.tsx +552 -0
  243. package/Tests/App/Dashboard/MonitorMetricsTabsTimeRangeZoom.test.tsx +740 -0
  244. package/Tests/App/Dashboard/MonitorOverviewChartsTimeRangeZoom.test.tsx +735 -0
  245. package/Tests/App/Dashboard/MonitorStepPreviewsTimeRangeZoom.test.tsx +835 -0
  246. package/Tests/App/Dashboard/NetworkDeviceTimeRangeZoom.test.tsx +1115 -0
  247. package/Tests/App/Dashboard/OnCallPreventionGuards.test.tsx +186 -17
  248. package/Tests/App/Dashboard/OnCallRulesDeleteGuard.test.tsx +155 -46
  249. package/Tests/App/Dashboard/PasskeySettings.test.tsx +87 -2
  250. package/Tests/App/Dashboard/ProjectAISettingsPages.test.tsx +884 -0
  251. package/Tests/App/Dashboard/ProxmoxNodeRemove.test.tsx +621 -0
  252. package/Tests/App/Dashboard/ProxmoxOverviewSlowLoads.test.tsx +584 -0
  253. package/Tests/App/Dashboard/ProxmoxPagesTimeRangeZoom.test.tsx +823 -0
  254. package/Tests/App/Dashboard/ProxmoxRateChartReload.test.tsx +1253 -0
  255. package/Tests/App/Dashboard/PublicDashboardBoardWideZoom.test.tsx +605 -0
  256. package/Tests/App/Dashboard/PublicNotePagesNotifyDefault.test.tsx +113 -1
  257. package/Tests/App/Dashboard/RealRowsLineChart.tsx +250 -0
  258. package/Tests/App/Dashboard/RechartsHostsPlotCursor.test.tsx +513 -0
  259. package/Tests/App/Dashboard/RowActionPlacementOverrides.test.tsx +865 -0
  260. package/Tests/App/Dashboard/RumOverviewTimeRangeZoom.test.tsx +877 -0
  261. package/Tests/App/Dashboard/RunnerKubernetesAgentForm.test.tsx +20 -4
  262. package/Tests/App/Dashboard/RunnerSupersededByAiAgentNote.test.tsx +296 -0
  263. package/Tests/App/Dashboard/SecurityEventConnectionsTable.test.tsx +146 -36
  264. package/Tests/App/Dashboard/ServiceDatabaseSlowLoads.test.tsx +1166 -0
  265. package/Tests/App/Dashboard/ServiceMapGraph.test.tsx +1243 -104
  266. package/Tests/App/Dashboard/ServiceOverviewTimeRangeZoom.test.tsx +792 -0
  267. package/Tests/App/Dashboard/SloBudgetBurnDownZoom.test.tsx +771 -0
  268. package/Tests/App/Dashboard/SloBudgetBurnDownZoomAffordances.test.tsx +380 -0
  269. package/Tests/App/Dashboard/SloEventMetricsBarChartZoom.test.tsx +369 -0
  270. package/Tests/App/Dashboard/SloHistoryChartsTimeRangeZoom.test.tsx +694 -0
  271. package/Tests/App/Dashboard/SloHistoryChartsZoomAffordances.test.tsx +497 -0
  272. package/Tests/App/Dashboard/SloMetricsTimeRangeZoom.test.tsx +541 -0
  273. package/Tests/App/Dashboard/SlowLoadHarness.ts +123 -0
  274. package/Tests/App/Dashboard/SnapshotExplorerPrimaryZoom.test.tsx +1194 -0
  275. package/Tests/App/Dashboard/SnapshotViewerPinnedWindow.test.tsx +620 -0
  276. package/Tests/App/Dashboard/SubscriberAudienceSummary.test.tsx +512 -0
  277. package/Tests/App/Dashboard/SubscriberNotificationPreviewModal.test.tsx +837 -0
  278. package/Tests/App/Dashboard/SubscriberNotificationStatusLabel.test.tsx +88 -0
  279. package/Tests/App/Dashboard/SubscriberNotificationStatusResend.test.tsx +473 -0
  280. package/Tests/App/Dashboard/SubscriberTemplateLivePreview.test.tsx +196 -0
  281. package/Tests/App/Dashboard/TeamAddedSubscribersUnsubscribedNotice.test.tsx +248 -0
  282. package/Tests/App/Dashboard/TelemetrySnapshotPanelTimeRangeZoom.test.tsx +765 -0
  283. package/Tests/App/Dashboard/TelemetrySnapshotZoom.test.tsx +516 -0
  284. package/Tests/App/Dashboard/TelemetrySnapshotZoomAcrossTabs.test.tsx +827 -0
  285. package/Tests/App/Dashboard/TimeRangeZoomPageHarness.tsx +463 -0
  286. package/Tests/App/Dashboard/TraceChartEditorStatusSplit.test.tsx +543 -0
  287. package/Tests/App/Dashboard/TraceStatusPresentation.test.tsx +967 -0
  288. package/Tests/App/Dashboard/TraceTimelineMinimapZoom.test.tsx +315 -0
  289. package/Tests/App/Dashboard/TracesAnalyticsStatusSplit.test.tsx +778 -0
  290. package/Tests/App/Dashboard/TracesAnalyticsViewZoom.test.tsx +349 -0
  291. package/Tests/App/Dashboard/TracesExplorerTimeRangeZoom.test.tsx +551 -0
  292. package/Tests/App/Dashboard/TracesStatusChartAndFacet.test.tsx +687 -0
  293. package/Tests/App/Dashboard/TracesViewerStaleResponses.test.tsx +458 -0
  294. package/Tests/App/Dashboard/UptimeStripsExcludedFromZoom.test.tsx +406 -0
  295. package/Tests/App/Dashboard/VMwareOverviewSlowLoads.test.tsx +535 -0
  296. package/Tests/App/Dashboard/VMwarePagesTimeRangeZoom.test.tsx +606 -0
  297. package/Tests/App/Dashboard/ValueWidgetSparklineStaleHover.test.tsx +1292 -0
  298. package/Tests/App/Dashboard/ValueWidgetSparklineZoom.test.tsx +765 -0
  299. package/Tests/App/SensitiveUrlTokenBootstrap.test.ts +64 -3
  300. package/Tests/App/StatusPage/StatusPageResourceExplorer.test.tsx +98 -0
  301. package/Tests/App/StatusPage/StatusPageUnsubscribePage.test.tsx +412 -0
  302. package/Tests/Models/DatabaseModels/KubernetesAiAgentModel.test.ts +295 -0
  303. package/Tests/Models/DatabaseModels/TeamComplianceSettingModel.test.ts +347 -0
  304. package/Tests/Models/IncidentCustomFieldApiSchemaContract.test.ts +217 -0
  305. package/Tests/Models/IncidentCustomFieldCreateSettingsColumns.test.ts +252 -0
  306. package/Tests/Models/StatusPageSubscriberUnsubscribeColumns.test.ts +218 -0
  307. package/Tests/Server/API/AIChatRouteAuthorization.test.ts +58 -0
  308. package/Tests/Server/API/AIGenerationProjectAIToggle.test.ts +1 -1
  309. package/Tests/Server/API/AIInvestigationAPI.test.ts +123 -45
  310. package/Tests/Server/API/AutoRemediationApproveClusterRound.test.ts +1329 -0
  311. package/Tests/Server/API/AutoRemediationApproveKubectlRecheck.test.ts +25 -2
  312. package/Tests/Server/API/ExpiredSessionRouteGuards.test.ts +7 -0
  313. package/Tests/Server/API/IncidentSubscriberAudienceAPI.test.ts +1408 -0
  314. package/Tests/Server/API/KubernetesClusterAiAccessAPI.test.ts +2 -0
  315. package/Tests/Server/API/KubernetesClusterAiAccessAPIAgent.test.ts +903 -0
  316. package/Tests/Server/API/MicrosoftTeamsChatsRefreshRoute.test.ts +667 -0
  317. package/Tests/Server/API/MicrosoftTeamsManifest.test.ts +294 -6
  318. package/Tests/Server/API/ProxmoxResourceAPIRemoveNode.test.ts +1932 -0
  319. package/Tests/Server/API/StatusPageIncidentScope.test.ts +1868 -0
  320. package/Tests/Server/API/StatusPageIncidentScopePostgres.test.ts +790 -0
  321. package/Tests/Server/API/StatusPageManageSubscriptionRecipient.test.ts +10 -1
  322. package/Tests/Server/API/StatusPageManageSubscriptionTemplateVariables.test.ts +206 -18
  323. package/Tests/Server/API/StatusPagePostmortemVisibility.test.ts +14 -2
  324. package/Tests/Server/API/StatusPageSubscriberCreateResponse.test.ts +217 -0
  325. package/Tests/Server/API/StatusPageSubscriberOwnership.test.ts +103 -2
  326. package/Tests/Server/API/StatusPageUnsubscribeAPI.test.ts +396 -0
  327. package/Tests/Server/Infrastructure/GlobalCache.test.ts +195 -0
  328. package/Tests/Server/Infrastructure/Postgres/AddIncidentStatusPageScopeMigration.test.ts +395 -0
  329. package/Tests/Server/Infrastructure/Postgres/AddIncidentTemplateStatusPageScopeFlagMigration.test.ts +150 -0
  330. package/Tests/Server/Infrastructure/Postgres/AddKubernetesAiAgentAndAiDefaultsMigration.test.ts +623 -0
  331. package/Tests/Server/Infrastructure/Postgres/AddKubernetesClusterAiAccessMigration.test.ts +87 -10
  332. package/Tests/Server/Infrastructure/Postgres/AddSubscriberNotificationClaimedAtMigration.test.ts +156 -0
  333. package/Tests/Server/Infrastructure/Postgres/AddTeamComplianceRuleScopeMigration.test.ts +622 -0
  334. package/Tests/Server/Infrastructure/Postgres/SkipHiddenIncidentCreatedNotificationsMigration.test.ts +410 -0
  335. package/Tests/Server/Middleware/IdentityRateLimit.test.ts +551 -1
  336. package/Tests/Server/Middleware/SubscriberNotificationPreviewRateLimit.test.ts +238 -0
  337. package/Tests/Server/Middleware/SubscriberNotificationTestSendRateLimit.test.ts +245 -0
  338. package/Tests/Server/Middleware/TelemetryIngestBrowserKey.test.ts +61 -4
  339. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerPinnedKey.test.ts +98 -2
  340. package/Tests/Server/Middleware/TelemetryIngestKubernetesAgentRunnerRateLimit.test.ts +105 -2
  341. package/Tests/Server/Services/AIServiceBalanceBlocker.test.ts +282 -0
  342. package/Tests/Server/Services/AddStatusPageSubscriberUnsubscribeTokenMigration.test.ts +152 -0
  343. package/Tests/Server/Services/AlertMonitorClearWritesNull.test.ts +409 -0
  344. package/Tests/Server/Services/AlertMonitorEditFeed.test.ts +474 -0
  345. package/Tests/Server/Services/AlertMonitorEditGuard.test.ts +610 -0
  346. package/Tests/Server/Services/AutoRemediationClusterRuleEngine.test.ts +2 -0
  347. package/Tests/Server/Services/AutoRemediationRuleCommandRunners.test.ts +2 -1
  348. package/Tests/Server/Services/CrossProjectRelationWriteGuard.test.ts +221 -36
  349. package/Tests/Server/Services/DatabaseServiceCompareAndSetColumns.test.ts +191 -0
  350. package/Tests/Server/Services/IncidentAffectedMonitorsEdit.test.ts +1360 -0
  351. package/Tests/Server/Services/IncidentAlertSloLinkSurvivesEdit.test.ts +3 -1
  352. package/Tests/Server/Services/IncidentCreatedRenotifyOnPublish.test.ts +681 -0
  353. package/Tests/Server/Services/IncidentCreatedResend.test.ts +775 -0
  354. package/Tests/Server/Services/IncidentCustomFieldRenamePostgres.test.ts +713 -0
  355. package/Tests/Server/Services/IncidentCustomFieldService.test.ts +751 -0
  356. package/Tests/Server/Services/IncidentCustomFieldValueValidation.test.ts +556 -0
  357. package/Tests/Server/Services/IncidentSeverityDeletePausesComplianceRules.test.ts +488 -0
  358. package/Tests/Server/Services/IncidentStatusPageScope.test.ts +2971 -0
  359. package/Tests/Server/Services/IncidentStatusPageScopeFeed.test.ts +131 -0
  360. package/Tests/Server/Services/IncidentStatusPageScopePostgres.test.ts +625 -0
  361. package/Tests/Server/Services/IncidentTemplateCustomFieldsCopy.test.ts +311 -0
  362. package/Tests/Server/Services/IncidentTemplateStatusPageScope.test.ts +363 -0
  363. package/Tests/Server/Services/KubernetesAiAgentJobService.test.ts +329 -0
  364. package/Tests/Server/Services/KubernetesAiAgentServiceHelpers.test.ts +618 -0
  365. package/Tests/Server/Services/KubernetesAiAgentServiceLifecycle.test.ts +1444 -0
  366. package/Tests/Server/Services/KubernetesAiAgentServiceRegister.test.ts +1666 -0
  367. package/Tests/Server/Services/KubernetesClusterAiAccessDeletedRunnerRemedy.test.ts +140 -111
  368. package/Tests/Server/Services/KubernetesClusterAiAccessGapNextSteps.test.ts +267 -105
  369. package/Tests/Server/Services/KubernetesClusterAiAccessLegacySuperseded.test.ts +440 -0
  370. package/Tests/Server/Services/KubernetesClusterAiAccessService.test.ts +567 -411
  371. package/Tests/Server/Services/KubernetesClusterAiAccessTarget.test.ts +1168 -0
  372. package/Tests/Server/Services/KubernetesClusterAiSettingsPermission.test.ts +410 -12
  373. package/Tests/Server/Services/KubernetesClusterServiceAiAccessFeed.test.ts +55 -0
  374. package/Tests/Server/Services/ProjectServiceNewProjectAiDefaults.test.ts +288 -0
  375. package/Tests/Server/Services/ProxmoxResourcePostgres.test.ts +5633 -0
  376. package/Tests/Server/Services/ProxmoxResourceService.test.ts +6458 -5
  377. package/Tests/Server/Services/PublicNoteEditFeedEventType.test.ts +213 -0
  378. package/Tests/Server/Services/PublicNoteResendAccess.test.ts +994 -0
  379. package/Tests/Server/Services/RunnerJobEnqueueKubectl.test.ts +48 -15
  380. package/Tests/Server/Services/RunnerJobEnqueueKubectlAiAgent.test.ts +620 -0
  381. package/Tests/Server/Services/RunnerJobKubectlWriteScope.test.ts +170 -3
  382. package/Tests/Server/Services/RunnerJobTimeoutReason.test.ts +72 -0
  383. package/Tests/Server/Services/RunnerServiceAgentName.test.ts +6 -4
  384. package/Tests/Server/Services/ScheduledMaintenanceAttachmentEdit.test.ts +2113 -0
  385. package/Tests/Server/Services/ScheduledMaintenanceMonitorRelease.test.ts +972 -0
  386. package/Tests/Server/Services/ScheduledMaintenanceSubscriberTemplateFormats.test.ts +289 -9
  387. package/Tests/Server/Services/SmsServiceFailIfNotSent.test.ts +67 -0
  388. package/Tests/Server/Services/StatusPageReportIncidentCounts.test.ts +610 -0
  389. package/Tests/Server/Services/StatusPageSubscriberAudienceCounts.test.ts +201 -0
  390. package/Tests/Server/Services/StatusPageSubscriberAudienceCountsPostgres.test.ts +271 -0
  391. package/Tests/Server/Services/StatusPageSubscriberConfirmationTemplateEscaping.test.ts +200 -0
  392. package/Tests/Server/Services/StatusPageSubscriberNotificationLogRedaction.test.ts +54 -0
  393. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateCompile.test.ts +37 -0
  394. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateIncidentRecordAccess.test.ts +772 -0
  395. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookup.test.ts +506 -0
  396. package/Tests/Server/Services/StatusPageSubscriberNotificationTemplateLookupPostgres.test.ts +261 -0
  397. package/Tests/Server/Services/StatusPageSubscriberReport.test.ts +21 -5
  398. package/Tests/Server/Services/StatusPageSubscriberUnsubscribe.test.ts +1618 -0
  399. package/Tests/Server/Services/StatusPageSubscriberUnsubscribeLinkSenders.test.ts +373 -0
  400. package/Tests/Server/Services/StatusPageSubscriberUnsubscribePostgres.test.ts +388 -0
  401. package/Tests/Server/Services/SubscriberNotificationInFlightRequeue.test.ts +500 -0
  402. package/Tests/Server/Services/TeamComplianceSettingPostgres.test.ts +2237 -0
  403. package/Tests/Server/Services/TeamComplianceSettingService.test.ts +3988 -138
  404. package/Tests/Server/Types/MarkdownEmailLinks.test.ts +320 -0
  405. package/Tests/Server/Types/Workflow/Components/Email.test.ts +491 -1
  406. package/Tests/Server/Types/Workflow/Components/EmailSmtpPinning.test.ts +398 -0
  407. package/Tests/Server/Utils/AI/ClusterAccessContext.test.ts +107 -1
  408. package/Tests/Server/Utils/AI/IncidentPostmortemRunner.test.ts +351 -0
  409. package/Tests/Server/Utils/AI/InvestigationClusterAccessWiring.test.ts +2 -0
  410. package/Tests/Server/Utils/AI/InvestigationEligibility.test.ts +310 -0
  411. package/Tests/Server/Utils/AI/KubectlInvestigationToolkit.test.ts +70 -0
  412. package/Tests/Server/Utils/AI/KubectlJobRunnerFinishedJob.test.ts +58 -0
  413. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectl.test.ts +2 -0
  414. package/Tests/Server/Utils/AI/RemediationCommandToolsKubectlOutcome.test.ts +2 -0
  415. package/Tests/Server/Utils/AI/RemediationCommandToolsLiveCluster.test.ts +2 -0
  416. package/Tests/Server/Utils/AI/RemediationCommandToolsRunnerScope.test.ts +125 -1
  417. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +252 -3
  418. package/Tests/Server/Utils/AI/RemediationExecutionRunnerClusterMode.test.ts +2 -0
  419. package/Tests/Server/Utils/AI/RemediationExecutionRunnerProjectGates.test.ts +240 -0
  420. package/Tests/Server/Utils/AI/RemediationKubectlCopyParity.test.ts +2 -0
  421. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutor.test.ts +2 -0
  422. package/Tests/Server/Utils/AutoRemediation/CommandPlanExecutorUnknownRun.test.ts +2 -0
  423. package/Tests/Server/Utils/AutoRemediation/CommandPlanVerification.test.ts +2 -0
  424. package/Tests/Server/Utils/CustomField/CustomFieldRename.test.ts +586 -0
  425. package/Tests/Server/Utils/DataSource/EgressGuard.test.ts +246 -10
  426. package/Tests/Server/Utils/DataSource/EgressGuardDeploymentConfig.test.ts +226 -0
  427. package/Tests/Server/Utils/DataSource/EgressGuardPinning.test.ts +131 -0
  428. package/Tests/Server/Utils/DataSource/HttpFetch.test.ts +4 -0
  429. package/Tests/Server/Utils/EgressPolicyEnvironment.ts +45 -0
  430. package/Tests/Server/Utils/Mail/PinnedSmtpSocket.test.ts +409 -0
  431. package/Tests/Server/Utils/Monitor/MonitorCriteriaObservationBuilderUnits.test.ts +23 -0
  432. package/Tests/Server/Utils/SSRFProtection.test.ts +4 -0
  433. package/Tests/Server/Utils/SSRFProtectionCloudServiceAddresses.test.ts +4 -0
  434. package/Tests/Server/Utils/SSRFProtectionPrivateNetwork.test.ts +4 -0
  435. package/Tests/Server/Utils/SSRFProtectionResolutionDetail.test.ts +314 -0
  436. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScope.test.ts +1699 -0
  437. package/Tests/Server/Utils/StatusPage/IncidentStatusPageScopeQueriesPostgres.test.ts +508 -0
  438. package/Tests/Server/Utils/StatusPage/IncidentSubscriberAudienceCallerPermission.test.ts +246 -0
  439. package/Tests/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.test.ts +1348 -0
  440. package/Tests/Server/Utils/StatusPage/StatusPageReadAccess.test.ts +221 -0
  441. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.test.ts +132 -0
  442. package/Tests/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.test.ts +155 -0
  443. package/Tests/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.test.ts +708 -0
  444. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaim.test.ts +255 -0
  445. package/Tests/Server/Utils/StatusPage/SubscriberNotificationClaimPostgres.test.ts +528 -0
  446. package/Tests/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.test.ts +1238 -0
  447. package/Tests/Server/Utils/StatusPage/SubscriberNotificationFanOut.test.ts +472 -0
  448. package/Tests/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.test.ts +1168 -0
  449. package/Tests/Server/Utils/StatusPage/SubscriberNotificationRunLimit.test.ts +275 -0
  450. package/Tests/Server/Utils/StatusPage/SubscriberNotificationTiming.test.ts +131 -0
  451. package/Tests/Server/Utils/StatusPageResource.test.ts +98 -0
  452. package/Tests/Server/Utils/Telemetry/HostAssetAttributesFromOtlp.test.ts +68 -0
  453. package/Tests/Server/Utils/Telemetry/InventoryMirrorPostgres.test.ts +370 -0
  454. package/Tests/Server/Utils/Telemetry/NetworkDeviceInventoryAttributes.test.ts +522 -0
  455. package/Tests/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.test.ts +155 -0
  456. package/Tests/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.test.ts +8631 -0
  457. package/Tests/Server/Utils/Telemetry/ProxmoxNativePush.test.ts +2852 -0
  458. package/Tests/Server/Utils/Telemetry/TelemetryEntity.test.ts +367 -1
  459. package/Tests/Server/Utils/Telemetry/TelemetryIngestionKeyGuard.test.ts +45 -3
  460. package/Tests/Server/Utils/VM/VMRunnerPrivateNetworkWiring.test.ts +17 -0
  461. package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +75 -0
  462. package/Tests/Server/Utils/Workspace/MicrosoftTeamsChats.test.ts +25 -0
  463. package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNames.test.ts +3119 -0
  464. package/Tests/Server/Utils/Workspace/MicrosoftTeamsGroupChatNamesPostgres.test.ts +1721 -0
  465. package/Tests/Types/CustomField/CustomFieldSavedViews.test.ts +247 -0
  466. package/Tests/Types/CustomField/CustomFieldTemplateValues.test.ts +186 -0
  467. package/Tests/Types/CustomField/CustomFieldTypeCorrespondence.test.ts +48 -0
  468. package/Tests/Types/CustomField/CustomFieldValueFormat.test.ts +215 -0
  469. package/Tests/Types/CustomField/CustomFieldValueValidator.test.ts +343 -0
  470. package/Tests/Types/CustomField/CustomFieldVariableKey.test.ts +364 -0
  471. package/Tests/Types/Kubernetes/KubernetesAgentChartAiAccess.test.ts +581 -113
  472. package/Tests/Types/Kubernetes/KubernetesAiAgentAccessContract.test.ts +510 -0
  473. package/Tests/Types/SafeHtml.test.ts +102 -0
  474. package/Tests/Types/StatusPage/IncidentCreatedRenotify.test.ts +419 -0
  475. package/Tests/Types/StatusPage/IncidentCreatedResend.test.ts +118 -0
  476. package/Tests/Types/StatusPage/IncidentScopeAddedPagesNotification.test.ts +558 -0
  477. package/Tests/Types/StatusPage/IncidentSubscriberAudience.test.ts +284 -0
  478. package/Tests/Types/StatusPage/StatusPageSubscriberUnsubscribe.test.ts +341 -0
  479. package/Tests/Types/StatusPage/SubscriberNotificationPreview.test.ts +196 -0
  480. package/Tests/Types/StatusPage/SubscriberNotificationResend.test.ts +201 -0
  481. package/Tests/Types/StatusPage/SubscriberNotificationTemplateCompiler.test.ts +277 -0
  482. package/Tests/Types/StatusPage/SubscriberNotificationTemplatePreview.test.ts +179 -0
  483. package/Tests/Types/StatusPage/SubscriberNotificationTemplateVariables.test.ts +324 -0
  484. package/Tests/Types/StatusPage/SubscriberUpdateNotification.test.ts +60 -13
  485. package/Tests/Types/Team/ComplianceRule.test.ts +1029 -0
  486. package/Tests/Types/Team/TeamComplianceStatus.test.ts +176 -0
  487. package/Tests/UI/Components/ActionButton/RowActions.test.tsx +641 -0
  488. package/Tests/UI/Components/ActionButton/RowActionsAccessibility.test.tsx +414 -0
  489. package/Tests/UI/Components/ActionButton/SplitActionButtons.test.ts +565 -0
  490. package/Tests/UI/Components/Charts/BarChartDragToSelect.test.tsx +386 -0
  491. package/Tests/UI/Components/Charts/ChartDoubleClickResetWithoutDblclick.test.tsx +1025 -0
  492. package/Tests/UI/Components/Charts/ChartGroupPageZoomHint.test.tsx +196 -0
  493. package/Tests/UI/Components/Charts/ChartPlaceholdersTakeDoubleClick.test.tsx +1861 -0
  494. package/Tests/UI/Components/Charts/ChartPlotClicksWhileResetArmed.test.tsx +382 -0
  495. package/Tests/UI/Components/Charts/ChartRangeSelection.test.tsx +704 -0
  496. package/Tests/UI/Components/Charts/ChartRangeSelectionDoubleClickReset.test.tsx +1481 -0
  497. package/Tests/UI/Components/Charts/ChartRangeSelectionRealRecharts.test.tsx +918 -0
  498. package/Tests/UI/Components/Charts/ChartRowBucketStart.test.ts +350 -0
  499. package/Tests/UI/Components/Charts/DoubleClickReset.test.tsx +996 -0
  500. package/Tests/UI/Components/Charts/HistogramDoubleClickResetRealRecharts.test.tsx +965 -0
  501. package/Tests/UI/Components/Charts/HistogramDriftThenRefetch.test.tsx +277 -0
  502. package/Tests/UI/Components/Charts/HistogramRangeSelectionDataChange.test.tsx +1757 -0
  503. package/Tests/UI/Components/Charts/HistogramRangeSelectionRealRecharts.test.tsx +560 -0
  504. package/Tests/UI/Components/Charts/TimeRangeZoom/ChartPageTimeRangeZoom.test.tsx +513 -0
  505. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.test.tsx +845 -0
  506. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.test.tsx +119 -0
  507. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHintTailwind.test.tsx +274 -0
  508. package/Tests/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.test.ts +433 -0
  509. package/Tests/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.test.tsx +863 -0
  510. package/Tests/UI/Components/Charts/TimeRangeZoom/ZoomDocsPromises.test.tsx +1147 -0
  511. package/Tests/UI/Components/CustomFields/CustomFieldFormFields.test.ts +432 -0
  512. package/Tests/UI/Components/CustomFields/CustomFieldModelFormFields.test.tsx +685 -0
  513. package/Tests/UI/Components/CustomFields/CustomFieldsDetailOrder.test.tsx +469 -0
  514. package/Tests/UI/Components/DisabledButtonTooltip.test.tsx +14 -3
  515. package/Tests/UI/Components/EntityDropdownEscape.test.tsx +454 -0
  516. package/Tests/UI/Components/EntityDropdownFocusLeave.test.tsx +420 -0
  517. package/Tests/UI/Components/Forms/FormFieldDropdownDisabled.test.tsx +233 -0
  518. package/Tests/UI/Components/Forms/ModelFormCustomFieldInputs.test.tsx +325 -0
  519. package/Tests/UI/Components/Forms/ModelFormDropdownOptionsRefused.test.tsx +358 -0
  520. package/Tests/UI/Components/Input.test.tsx +80 -1
  521. package/Tests/UI/Components/LogsAnalyticsViewZoom.test.tsx +947 -0
  522. package/Tests/UI/Components/LogsHistogramDragTooltip.test.tsx +17 -5
  523. package/Tests/UI/Components/LogsViewerAnalyticsZoom.test.tsx +501 -0
  524. package/Tests/UI/Components/LogsViewerHistogramZoom.test.tsx +1 -1
  525. package/Tests/UI/Components/ModelTable/BaseModelTableBulkDelete.test.tsx +6 -4
  526. package/Tests/UI/Components/ModelTable/BaseModelTablePermissionGating.test.tsx +60 -8
  527. package/Tests/UI/Components/ModelTable/BaseModelTableRowActions.test.tsx +476 -0
  528. package/Tests/UI/Components/ModelTable/CustomFieldColumns.test.tsx +22 -0
  529. package/Tests/UI/Components/ModelTable/ModelTableWrapContent.test.tsx +7 -5
  530. package/Tests/UI/Components/MoreMenuPortal.test.tsx +623 -0
  531. package/Tests/UI/Components/StatusPage/ResourceGridActions.test.tsx +538 -0
  532. package/Tests/UI/Components/StatusPage/ResourceGridSelection.test.tsx +14 -4
  533. package/Tests/UI/Components/TableCellWrapping.test.tsx +3 -3
  534. package/Tests/UI/Components/TableRowActions.test.tsx +472 -0
  535. package/Tests/UI/Components/TelemetryHistogramDragTooltip.test.tsx +1 -1
  536. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerHistogramClickZoom.test.tsx +1 -1
  537. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerZoomScope.test.tsx +470 -0
  538. package/Tests/UI/Components/TelemetryViewer/UseViewerTimeRangeZoom.test.tsx +571 -0
  539. package/Tests/UI/Components/TelemetryViewer/ViewerDoubleClickResetUnderDataChange.test.tsx +928 -0
  540. package/Tests/UI/Components/TelemetryViewer/ViewerFollowsEnclosingZoom.test.tsx +1569 -0
  541. package/Tests/UI/Components/Toggle.test.tsx +66 -0
  542. package/Tests/UI/MicrosoftTeams/MicrosoftTeamsChatsCardRefreshNames.test.tsx +1023 -0
  543. package/Tests/UI/Monitor/NetworkPathView.test.tsx +289 -0
  544. package/Tests/UI/Rum/ChunkLoader.test.ts +201 -0
  545. package/Tests/UI/Rum/FidelityNotices.test.ts +54 -0
  546. package/Tests/UI/Rum/ReplayCorrelationPanel.test.tsx +72 -0
  547. package/Tests/UI/Rum/ReplayFrameCapture.test.ts +1009 -9
  548. package/Tests/UI/Rum/ReplayRecordedAssets.test.ts +1069 -0
  549. package/Tests/UI/Rum/ReplayStage.test.tsx +913 -2
  550. package/Tests/UI/Rum/SessionReplayTable.test.tsx +443 -8
  551. package/Tests/UI/Rum/SessionReplayUsersTable.test.tsx +439 -9
  552. package/Tests/UI/Rum/UserFlowTablesRowActions.test.tsx +501 -0
  553. package/Tests/Utils/AiRemediation/KubectlPolicyChartRbacParity.test.ts +47 -19
  554. package/Tests/Utils/AiRemediation/KubectlWriteScopeCallerParity.test.ts +2 -0
  555. package/Tests/Utils/AiRemediation/KubernetesAiAgentPolicyCopyParity.test.ts +396 -0
  556. package/Tests/Utils/Dashboard/DashboardTimeRangeZoom.test.ts +104 -1
  557. package/Tests/Utils/Incident/IncidentNoteTemplateVariables.test.ts +623 -0
  558. package/Tests/Utils/Markdown/MarkdownEscape.test.ts +89 -0
  559. package/Tests/Utils/ProbeNetworkFailureUtil.test.ts +992 -0
  560. package/Tests/Utils/RequestFailedDetails.test.ts +575 -0
  561. package/Types/AI/AIRunType.ts +9 -4
  562. package/Types/AI/InvestigationNotStartedReason.ts +6 -0
  563. package/Types/AutoRemediation/AiRemediationCommandPlan.ts +14 -16
  564. package/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.ts +28 -0
  565. package/Types/CustomField/CustomFieldOrder.ts +55 -0
  566. package/Types/CustomField/CustomFieldSavedViews.ts +225 -0
  567. package/Types/CustomField/CustomFieldTemplateMerge.ts +71 -0
  568. package/Types/CustomField/CustomFieldType.ts +14 -0
  569. package/Types/CustomField/CustomFieldValueFormat.ts +161 -0
  570. package/Types/CustomField/CustomFieldValueValidator.ts +488 -0
  571. package/Types/CustomField/CustomFieldVariableKey.ts +211 -0
  572. package/Types/Dashboard/DashboardComponents/DashboardTraceChartComponent.ts +4 -2
  573. package/Types/Kubernetes/KubernetesClusterAiAccess.ts +263 -32
  574. package/Types/Kubernetes/KubernetesClusterAiAccessPermissions.ts +20 -16
  575. package/Types/Kubernetes/KubernetesClusterAiInsights.ts +81 -0
  576. package/Types/Monitor/ProxmoxAlertTemplates.ts +4 -4
  577. package/Types/SafeHtml.ts +93 -0
  578. package/Types/StatusPage/IncidentCreatedRenotify.ts +224 -0
  579. package/Types/StatusPage/IncidentCreatedResend.ts +108 -0
  580. package/Types/StatusPage/IncidentScopeAddedPagesNotification.ts +343 -0
  581. package/Types/StatusPage/IncidentSubscriberAudience.ts +332 -0
  582. package/Types/StatusPage/StatusPageSubscriberUnsubscribe.ts +405 -0
  583. package/Types/StatusPage/SubscriberNotificationInterruption.ts +32 -0
  584. package/Types/StatusPage/SubscriberNotificationPreview.ts +322 -0
  585. package/Types/StatusPage/SubscriberNotificationResend.ts +132 -0
  586. package/Types/StatusPage/SubscriberNotificationTemplateCompiler.ts +180 -0
  587. package/Types/StatusPage/SubscriberNotificationTemplatePreview.ts +301 -0
  588. package/Types/StatusPage/SubscriberNotificationTemplateVariables.ts +217 -4
  589. package/Types/StatusPage/SubscriberUpdateNotification.ts +32 -11
  590. package/Types/Team/ComplianceNotificationChannel.ts +22 -0
  591. package/Types/Team/ComplianceRule.ts +434 -0
  592. package/Types/Team/ComplianceRuleType.ts +21 -0
  593. package/Types/Team/TeamComplianceStatus.ts +81 -0
  594. package/Types/Telemetry/TelemetryIngestSurface.ts +28 -0
  595. package/UI/Components/ActionButton/ActionButtonSchema.ts +21 -0
  596. package/UI/Components/ActionButton/RowActions.tsx +238 -0
  597. package/UI/Components/ActionButton/SplitActionButtons.ts +173 -0
  598. package/UI/Components/Charts/Area/AreaChart.tsx +32 -2
  599. package/UI/Components/Charts/Bar/BarChart.tsx +40 -3
  600. package/UI/Components/Charts/ChartGroup/ChartGroup.tsx +37 -11
  601. package/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.tsx +80 -243
  602. package/UI/Components/Charts/ChartLibrary/BarChart/BarChart.tsx +122 -31
  603. package/UI/Components/Charts/ChartLibrary/LineChart/LineChart.tsx +95 -244
  604. package/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.ts +214 -0
  605. package/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.ts +32 -0
  606. package/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.ts +599 -0
  607. package/UI/Components/Charts/Line/LineChart.tsx +32 -2
  608. package/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.tsx +70 -0
  609. package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.tsx +226 -0
  610. package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.tsx +73 -0
  611. package/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.ts +163 -0
  612. package/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.ts +215 -0
  613. package/UI/Components/Charts/Utils/DataPoint.ts +20 -8
  614. package/UI/Components/Charts/Utils/XAxis.ts +75 -0
  615. package/UI/Components/Charts/Utils/useHistogramRangeSelection.ts +493 -59
  616. package/UI/Components/CustomFields/CustomFieldFormFields.ts +317 -0
  617. package/UI/Components/CustomFields/CustomFieldModelFormFields.tsx +395 -0
  618. package/UI/Components/CustomFields/CustomFieldsDetail.tsx +95 -55
  619. package/UI/Components/EntityDropdown/EntityDropdown.tsx +107 -11
  620. package/UI/Components/Forms/Fields/FormField.tsx +10 -0
  621. package/UI/Components/Forms/ModelForm.tsx +70 -8
  622. package/UI/Components/Forms/Validation.ts +1 -1
  623. package/UI/Components/Input/Input.tsx +90 -57
  624. package/UI/Components/List/ListRow.tsx +8 -74
  625. package/UI/Components/LogsViewer/LogsViewer.tsx +40 -11
  626. package/UI/Components/LogsViewer/components/LogTimeRangePicker.tsx +22 -6
  627. package/UI/Components/LogsViewer/components/LogsAnalyticsView.tsx +209 -6
  628. package/UI/Components/LogsViewer/components/LogsHistogram.tsx +127 -84
  629. package/UI/Components/LogsViewer/components/LogsViewerToolbar.tsx +3 -0
  630. package/UI/Components/ModelFormModal/ModelFormModal.tsx +2 -4
  631. package/UI/Components/ModelTable/AnalyticsModelTable.tsx +2 -6
  632. package/UI/Components/ModelTable/BaseModelTable.tsx +21 -9
  633. package/UI/Components/ModelTable/CustomFieldColumns.tsx +14 -1
  634. package/UI/Components/ModelTable/ModelTable.tsx +6 -7
  635. package/UI/Components/MoreMenu/MoreMenu.tsx +365 -30
  636. package/UI/Components/MoreMenu/MoreMenuItem.tsx +70 -17
  637. package/UI/Components/OrderedStatesList/Item.tsx +7 -72
  638. package/UI/Components/StatusPage/ResourceGrid.tsx +126 -77
  639. package/UI/Components/Table/TableBody.tsx +8 -2
  640. package/UI/Components/Table/TableRow.tsx +20 -140
  641. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +41 -10
  642. package/UI/Components/TelemetryViewer/components/TelemetryHistogram.tsx +47 -9
  643. package/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.tsx +25 -6
  644. package/UI/Components/TelemetryViewer/types.ts +2 -0
  645. package/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.ts +448 -0
  646. package/UI/Components/Toggle/Toggle.tsx +26 -0
  647. package/UI/Components/Tooltip/Tooltip.tsx +8 -1
  648. package/UI/Styles/Theme.css +14 -2
  649. package/UI/Utils/SensitiveUrlToken.ts +10 -5
  650. package/Utils/API.ts +247 -2
  651. package/Utils/AiRemediation/CommandPolicy.ts +1 -1
  652. package/Utils/AiRemediation/KubectlPolicy.ts +1 -1
  653. package/Utils/Dashboard/DashboardTimeRangeZoom.ts +46 -2
  654. package/Utils/Incident/IncidentNoteTemplateVariables.ts +304 -0
  655. package/Utils/Markdown/MarkdownEscape.ts +65 -0
  656. package/Utils/ProbeNetworkFailureUtil.ts +673 -0
  657. package/build/dist/Models/DatabaseModels/Incident.js +267 -1
  658. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  659. package/build/dist/Models/DatabaseModels/IncidentCustomField.js +207 -1
  660. package/build/dist/Models/DatabaseModels/IncidentCustomField.js.map +1 -1
  661. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +31 -0
  662. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  663. package/build/dist/Models/DatabaseModels/IncidentTemplate.js +124 -1
  664. package/build/dist/Models/DatabaseModels/IncidentTemplate.js.map +1 -1
  665. package/build/dist/Models/DatabaseModels/Index.js +2 -0
  666. package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
  667. package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js +385 -0
  668. package/build/dist/Models/DatabaseModels/KubernetesAiAgent.js.map +1 -0
  669. package/build/dist/Models/DatabaseModels/KubernetesCluster.js +3 -3
  670. package/build/dist/Models/DatabaseModels/KubernetesCluster.js.map +1 -1
  671. package/build/dist/Models/DatabaseModels/Project.js +56 -5
  672. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  673. package/build/dist/Models/DatabaseModels/ProxmoxResource.js +51 -1
  674. package/build/dist/Models/DatabaseModels/ProxmoxResource.js.map +1 -1
  675. package/build/dist/Models/DatabaseModels/RunnerJob.js +74 -0
  676. package/build/dist/Models/DatabaseModels/RunnerJob.js.map +1 -1
  677. package/build/dist/Models/DatabaseModels/StatusPage.js +56 -0
  678. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  679. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js +131 -0
  680. package/build/dist/Models/DatabaseModels/StatusPageSubscriber.js.map +1 -1
  681. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js +134 -3
  682. package/build/dist/Models/DatabaseModels/TeamComplianceSetting.js.map +1 -1
  683. package/build/dist/Models/DatabaseModels/WorkspaceProjectAuthToken.js.map +1 -1
  684. package/build/dist/Server/API/AIChatAPI.js +6 -1
  685. package/build/dist/Server/API/AIChatAPI.js.map +1 -1
  686. package/build/dist/Server/API/AIInvestigationAPI.js +17 -10
  687. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  688. package/build/dist/Server/API/AutoRemediationAPI.js +144 -24
  689. package/build/dist/Server/API/AutoRemediationAPI.js.map +1 -1
  690. package/build/dist/Server/API/IncidentAPI.js +100 -1
  691. package/build/dist/Server/API/IncidentAPI.js.map +1 -1
  692. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js +436 -22
  693. package/build/dist/Server/API/KubernetesClusterAiAccessAPI.js.map +1 -1
  694. package/build/dist/Server/API/MicrosoftTeamsAPI.js +69 -13
  695. package/build/dist/Server/API/MicrosoftTeamsAPI.js.map +1 -1
  696. package/build/dist/Server/API/ProxmoxResourceAPI.js +187 -14
  697. package/build/dist/Server/API/ProxmoxResourceAPI.js.map +1 -1
  698. package/build/dist/Server/API/StatusPageAPI.js +417 -176
  699. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  700. package/build/dist/Server/API/StatusPageSubscriberAPI.js +52 -13
  701. package/build/dist/Server/API/StatusPageSubscriberAPI.js.map +1 -1
  702. package/build/dist/Server/Infrastructure/GlobalCache.js +27 -0
  703. package/build/dist/Server/Infrastructure/GlobalCache.js.map +1 -1
  704. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js +41 -0
  705. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795300000000-SkipHiddenIncidentCreatedNotifications.js.map +1 -0
  706. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js +57 -0
  707. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795400000000-AddIncidentStatusPageScope.js.map +1 -0
  708. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js +23 -0
  709. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795500000000-AddIncidentTemplateStatusPageScopeFlag.js.map +1 -0
  710. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js +40 -0
  711. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795600000000-AddStatusPageSubscriberUnsubscribeToken.js.map +1 -0
  712. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js +26 -0
  713. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795700000000-AddStatusPageSubscriberIsAddedByTeam.js.map +1 -0
  714. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js +89 -0
  715. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795800000000-AddIncidentCustomFieldCreateAndNotificationSettings.js.map +1 -0
  716. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js +29 -0
  717. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1795900000000-AddSubscriberNotificationClaimedAt.js.map +1 -0
  718. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js +50 -0
  719. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796000000000-AddTeamComplianceRuleScope.js.map +1 -0
  720. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js +84 -0
  721. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796100000000-AddKubernetesAiAgentAndAiDefaults.js.map +1 -0
  722. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js +31 -0
  723. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1796200000000-AddProxmoxResourceNativePushColumns.js.map +1 -0
  724. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +20 -0
  725. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  726. package/build/dist/Server/Infrastructure/Semaphore.js +3 -0
  727. package/build/dist/Server/Infrastructure/Semaphore.js.map +1 -1
  728. package/build/dist/Server/Middleware/IdentityRateLimit.js +89 -3
  729. package/build/dist/Server/Middleware/IdentityRateLimit.js.map +1 -1
  730. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js +149 -0
  731. package/build/dist/Server/Middleware/SubscriberNotificationPreviewRateLimit.js.map +1 -0
  732. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js +190 -0
  733. package/build/dist/Server/Middleware/SubscriberNotificationTestSendRateLimit.js.map +1 -0
  734. package/build/dist/Server/Middleware/TelemetryIngest.js +34 -19
  735. package/build/dist/Server/Middleware/TelemetryIngest.js.map +1 -1
  736. package/build/dist/Server/Services/AIService.js +59 -1
  737. package/build/dist/Server/Services/AIService.js.map +1 -1
  738. package/build/dist/Server/Services/AlertService.js +248 -13
  739. package/build/dist/Server/Services/AlertService.js.map +1 -1
  740. package/build/dist/Server/Services/AlertSeverityService.js +51 -15
  741. package/build/dist/Server/Services/AlertSeverityService.js.map +1 -1
  742. package/build/dist/Server/Services/AutoRemediationRuleService.js +1 -1
  743. package/build/dist/Server/Services/AutoRemediationRuleService.js.map +1 -1
  744. package/build/dist/Server/Services/DatabaseService.js +56 -7
  745. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  746. package/build/dist/Server/Services/IncidentCustomFieldService.js +204 -8
  747. package/build/dist/Server/Services/IncidentCustomFieldService.js.map +1 -1
  748. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js +24 -0
  749. package/build/dist/Server/Services/IncidentEpisodePublicNoteService.js.map +1 -1
  750. package/build/dist/Server/Services/IncidentEpisodeService.js +14 -0
  751. package/build/dist/Server/Services/IncidentEpisodeService.js.map +1 -1
  752. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js +26 -0
  753. package/build/dist/Server/Services/IncidentEpisodeStateTimelineService.js.map +1 -1
  754. package/build/dist/Server/Services/IncidentPublicNoteService.js +26 -1
  755. package/build/dist/Server/Services/IncidentPublicNoteService.js.map +1 -1
  756. package/build/dist/Server/Services/IncidentService.js +1251 -72
  757. package/build/dist/Server/Services/IncidentService.js.map +1 -1
  758. package/build/dist/Server/Services/IncidentSeverityService.js +51 -15
  759. package/build/dist/Server/Services/IncidentSeverityService.js.map +1 -1
  760. package/build/dist/Server/Services/IncidentStateTimelineService.js +12 -0
  761. package/build/dist/Server/Services/IncidentStateTimelineService.js.map +1 -1
  762. package/build/dist/Server/Services/IncidentTemplateService.js +83 -0
  763. package/build/dist/Server/Services/IncidentTemplateService.js.map +1 -1
  764. package/build/dist/Server/Services/KubernetesAiAgentJobService.js +158 -0
  765. package/build/dist/Server/Services/KubernetesAiAgentJobService.js.map +1 -0
  766. package/build/dist/Server/Services/KubernetesAiAgentService.js +1145 -0
  767. package/build/dist/Server/Services/KubernetesAiAgentService.js.map +1 -0
  768. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js +842 -371
  769. package/build/dist/Server/Services/KubernetesClusterAiAccessService.js.map +1 -1
  770. package/build/dist/Server/Services/KubernetesClusterService.js +86 -17
  771. package/build/dist/Server/Services/KubernetesClusterService.js.map +1 -1
  772. package/build/dist/Server/Services/ProjectService.js +22 -0
  773. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  774. package/build/dist/Server/Services/ProxmoxResourceService.js +258 -3
  775. package/build/dist/Server/Services/ProxmoxResourceService.js.map +1 -1
  776. package/build/dist/Server/Services/RunnerJobService.js +178 -92
  777. package/build/dist/Server/Services/RunnerJobService.js.map +1 -1
  778. package/build/dist/Server/Services/RunnerService.js +1 -1
  779. package/build/dist/Server/Services/RunnerService.js.map +1 -1
  780. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js +26 -1
  781. package/build/dist/Server/Services/ScheduledMaintenancePublicNoteService.js.map +1 -1
  782. package/build/dist/Server/Services/ScheduledMaintenanceService.js +582 -20
  783. package/build/dist/Server/Services/ScheduledMaintenanceService.js.map +1 -1
  784. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js +316 -46
  785. package/build/dist/Server/Services/ScheduledMaintenanceStateTimelineService.js.map +1 -1
  786. package/build/dist/Server/Services/SmsService.js +2 -22
  787. package/build/dist/Server/Services/SmsService.js.map +1 -1
  788. package/build/dist/Server/Services/StatusPageService.js +47 -9
  789. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  790. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js +237 -32
  791. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateService.js.map +1 -1
  792. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js +109 -0
  793. package/build/dist/Server/Services/StatusPageSubscriberNotificationTemplateStatusPageService.js.map +1 -1
  794. package/build/dist/Server/Services/StatusPageSubscriberService.js +925 -99
  795. package/build/dist/Server/Services/StatusPageSubscriberService.js.map +1 -1
  796. package/build/dist/Server/Services/TeamComplianceSettingService.js +833 -7
  797. package/build/dist/Server/Services/TeamComplianceSettingService.js.map +1 -1
  798. package/build/dist/Server/Types/Markdown.js +110 -6
  799. package/build/dist/Server/Types/Markdown.js.map +1 -1
  800. package/build/dist/Server/Types/Workflow/Components/Email.js +55 -6
  801. package/build/dist/Server/Types/Workflow/Components/Email.js.map +1 -1
  802. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js +52 -9
  803. package/build/dist/Server/Utils/AI/ClusterAccess/ClusterAccessContext.js.map +1 -1
  804. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js +13 -9
  805. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlInvestigationToolkit.js.map +1 -1
  806. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js +7 -3
  807. package/build/dist/Server/Utils/AI/ClusterAccess/KubectlJobRunner.js.map +1 -1
  808. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js +29 -15
  809. package/build/dist/Server/Utils/AI/Remediation/RemediationCommandTools.js.map +1 -1
  810. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +56 -20
  811. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  812. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +39 -5
  813. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  814. package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js +30 -3
  815. package/build/dist/Server/Utils/AI/SRE/IncidentPostmortemRunner.js.map +1 -1
  816. package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js +13 -2
  817. package/build/dist/Server/Utils/AI/SRE/InvestigationEligibility.js.map +1 -1
  818. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +1 -1
  819. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js +4 -2
  820. package/build/dist/Server/Utils/AutoRemediation/CommandPlanExecutor.js.map +1 -1
  821. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js +211 -0
  822. package/build/dist/Server/Utils/CustomField/CustomFieldRename.js.map +1 -0
  823. package/build/dist/Server/Utils/DataSource/EgressGuard.js +41 -12
  824. package/build/dist/Server/Utils/DataSource/EgressGuard.js.map +1 -1
  825. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js +101 -0
  826. package/build/dist/Server/Utils/Mail/PinnedSmtpSocket.js.map +1 -0
  827. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js +9 -0
  828. package/build/dist/Server/Utils/Monitor/MonitorCriteriaObservationBuilder.js.map +1 -1
  829. package/build/dist/Server/Utils/SSRFProtection.js +48 -6
  830. package/build/dist/Server/Utils/SSRFProtection.js.map +1 -1
  831. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js +631 -0
  832. package/build/dist/Server/Utils/StatusPage/IncidentStatusPageScope.js.map +1 -0
  833. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js +403 -0
  834. package/build/dist/Server/Utils/StatusPage/IncidentSubscriberAudienceBuilder.js.map +1 -0
  835. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js +451 -0
  836. package/build/dist/Server/Utils/StatusPage/IncidentTemplateVariableBuilder.js.map +1 -0
  837. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js +13 -0
  838. package/build/dist/Server/Utils/StatusPage/StatusPageExclusion.js.map +1 -0
  839. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js +91 -0
  840. package/build/dist/Server/Utils/StatusPage/StatusPageReadAccess.js.map +1 -0
  841. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js +101 -0
  842. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeNotice.js.map +1 -0
  843. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js +47 -0
  844. package/build/dist/Server/Utils/StatusPage/StatusPageSubscriberUnsubscribeToken.js.map +1 -0
  845. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js +273 -0
  846. package/build/dist/Server/Utils/StatusPage/SubscriberIncidentEmailBuilder.js.map +1 -0
  847. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js +73 -0
  848. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationClaim.js.map +1 -0
  849. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js +722 -0
  850. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationDeliveryRecord.js.map +1 -0
  851. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js +102 -0
  852. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationFanOut.js.map +1 -0
  853. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js +527 -0
  854. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationPreviewBuilder.js.map +1 -0
  855. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js +278 -0
  856. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationResendAccess.js.map +1 -0
  857. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js +137 -0
  858. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationRunLimit.js.map +1 -0
  859. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js +103 -0
  860. package/build/dist/Server/Utils/StatusPage/SubscriberNotificationTiming.js.map +1 -0
  861. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js +114 -0
  862. package/build/dist/Server/Utils/StatusPage/SubscriberTemplateIncidentRecordAccess.js.map +1 -0
  863. package/build/dist/Server/Utils/StatusPageResource.js +39 -7
  864. package/build/dist/Server/Utils/StatusPageResource.js.map +1 -1
  865. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js +111 -6
  866. package/build/dist/Server/Utils/Telemetry/InventoryEntityRegistry.js.map +1 -1
  867. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js +40 -4
  868. package/build/dist/Server/Utils/Telemetry/ProxmoxCephSnapshotScan.js.map +1 -1
  869. package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js +296 -0
  870. package/build/dist/Server/Utils/Telemetry/ProxmoxNativeNodeLiveness.js.map +1 -0
  871. package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js +699 -0
  872. package/build/dist/Server/Utils/Telemetry/ProxmoxNativePush.js.map +1 -0
  873. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js +77 -19
  874. package/build/dist/Server/Utils/Telemetry/TelemetryEntity.js.map +1 -1
  875. package/build/dist/Server/Utils/VM/VMAPI.js.map +1 -1
  876. package/build/dist/Server/Utils/VM/VMRunner.js +1 -0
  877. package/build/dist/Server/Utils/VM/VMRunner.js.map +1 -1
  878. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js +3 -0
  879. package/build/dist/Server/Utils/Workflow/OAuth2TokenClient.js.map +1 -1
  880. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js +505 -42
  881. package/build/dist/Server/Utils/Workspace/MicrosoftTeams/MicrosoftTeams.js.map +1 -1
  882. package/build/dist/Types/AI/AIRunType.js +9 -4
  883. package/build/dist/Types/AI/AIRunType.js.map +1 -1
  884. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js +10 -16
  885. package/build/dist/Types/AutoRemediation/AiRemediationCommandPlan.js.map +1 -1
  886. package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js +28 -0
  887. package/build/dist/Types/AutoRemediation/AiRemediationCommandPolicyVerdict.js.map +1 -0
  888. package/build/dist/Types/CustomField/CustomFieldOrder.js +36 -0
  889. package/build/dist/Types/CustomField/CustomFieldOrder.js.map +1 -0
  890. package/build/dist/Types/CustomField/CustomFieldSavedViews.js +135 -0
  891. package/build/dist/Types/CustomField/CustomFieldSavedViews.js.map +1 -0
  892. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js +27 -0
  893. package/build/dist/Types/CustomField/CustomFieldTemplateMerge.js.map +1 -0
  894. package/build/dist/Types/CustomField/CustomFieldType.js +12 -0
  895. package/build/dist/Types/CustomField/CustomFieldType.js.map +1 -1
  896. package/build/dist/Types/CustomField/CustomFieldValueFormat.js +126 -0
  897. package/build/dist/Types/CustomField/CustomFieldValueFormat.js.map +1 -0
  898. package/build/dist/Types/CustomField/CustomFieldValueValidator.js +280 -0
  899. package/build/dist/Types/CustomField/CustomFieldValueValidator.js.map +1 -0
  900. package/build/dist/Types/CustomField/CustomFieldVariableKey.js +150 -0
  901. package/build/dist/Types/CustomField/CustomFieldVariableKey.js.map +1 -0
  902. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js +72 -16
  903. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccess.js.map +1 -1
  904. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js +20 -16
  905. package/build/dist/Types/Kubernetes/KubernetesClusterAiAccessPermissions.js.map +1 -1
  906. package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js +17 -0
  907. package/build/dist/Types/Kubernetes/KubernetesClusterAiInsights.js.map +1 -0
  908. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +4 -4
  909. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js.map +1 -1
  910. package/build/dist/Types/SafeHtml.js +84 -0
  911. package/build/dist/Types/SafeHtml.js.map +1 -0
  912. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js +117 -0
  913. package/build/dist/Types/StatusPage/IncidentCreatedRenotify.js.map +1 -0
  914. package/build/dist/Types/StatusPage/IncidentCreatedResend.js +86 -0
  915. package/build/dist/Types/StatusPage/IncidentCreatedResend.js.map +1 -0
  916. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js +246 -0
  917. package/build/dist/Types/StatusPage/IncidentScopeAddedPagesNotification.js.map +1 -0
  918. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js +183 -0
  919. package/build/dist/Types/StatusPage/IncidentSubscriberAudience.js.map +1 -0
  920. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js +277 -0
  921. package/build/dist/Types/StatusPage/StatusPageSubscriberUnsubscribe.js.map +1 -0
  922. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js +27 -0
  923. package/build/dist/Types/StatusPage/SubscriberNotificationInterruption.js.map +1 -0
  924. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js +190 -0
  925. package/build/dist/Types/StatusPage/SubscriberNotificationPreview.js.map +1 -0
  926. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js +102 -0
  927. package/build/dist/Types/StatusPage/SubscriberNotificationResend.js.map +1 -0
  928. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js +97 -0
  929. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateCompiler.js.map +1 -0
  930. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js +175 -0
  931. package/build/dist/Types/StatusPage/SubscriberNotificationTemplatePreview.js.map +1 -0
  932. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js +144 -4
  933. package/build/dist/Types/StatusPage/SubscriberNotificationTemplateVariables.js.map +1 -1
  934. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js +29 -9
  935. package/build/dist/Types/StatusPage/SubscriberUpdateNotification.js.map +1 -1
  936. package/build/dist/Types/Team/ComplianceNotificationChannel.js +23 -0
  937. package/build/dist/Types/Team/ComplianceNotificationChannel.js.map +1 -0
  938. package/build/dist/Types/Team/ComplianceRule.js +304 -0
  939. package/build/dist/Types/Team/ComplianceRule.js.map +1 -0
  940. package/build/dist/Types/Team/ComplianceRuleType.js +21 -0
  941. package/build/dist/Types/Team/ComplianceRuleType.js.map +1 -1
  942. package/build/dist/Types/Team/TeamComplianceStatus.js +2 -0
  943. package/build/dist/Types/Team/TeamComplianceStatus.js.map +1 -0
  944. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js +25 -0
  945. package/build/dist/Types/Telemetry/TelemetryIngestSurface.js.map +1 -1
  946. package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js +20 -1
  947. package/build/dist/UI/Components/ActionButton/ActionButtonSchema.js.map +1 -1
  948. package/build/dist/UI/Components/ActionButton/RowActions.js +113 -0
  949. package/build/dist/UI/Components/ActionButton/RowActions.js.map +1 -0
  950. package/build/dist/UI/Components/ActionButton/SplitActionButtons.js +71 -0
  951. package/build/dist/UI/Components/ActionButton/SplitActionButtons.js.map +1 -0
  952. package/build/dist/UI/Components/Charts/Area/AreaChart.js +16 -1
  953. package/build/dist/UI/Components/Charts/Area/AreaChart.js.map +1 -1
  954. package/build/dist/UI/Components/Charts/Bar/BarChart.js +16 -1
  955. package/build/dist/UI/Components/Charts/Bar/BarChart.js.map +1 -1
  956. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js +27 -5
  957. package/build/dist/UI/Components/Charts/ChartGroup/ChartGroup.js.map +1 -1
  958. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js +61 -194
  959. package/build/dist/UI/Components/Charts/ChartLibrary/AreaChart/AreaChart.js.map +1 -1
  960. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js +84 -26
  961. package/build/dist/UI/Components/Charts/ChartLibrary/BarChart/BarChart.js.map +1 -1
  962. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js +75 -196
  963. package/build/dist/UI/Components/Charts/ChartLibrary/LineChart/LineChart.js.map +1 -1
  964. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js +133 -0
  965. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/DoubleClick.js.map +1 -1
  966. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js +26 -0
  967. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartBucketsChange.js.map +1 -0
  968. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js +371 -0
  969. package/build/dist/UI/Components/Charts/ChartLibrary/Utils/UseChartRangeSelection.js.map +1 -0
  970. package/build/dist/UI/Components/Charts/Line/LineChart.js +16 -1
  971. package/build/dist/UI/Components/Charts/Line/LineChart.js.map +1 -1
  972. package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js +35 -0
  973. package/build/dist/UI/Components/Charts/TimeRangeZoom/ResetTimeRangeZoomButton.js.map +1 -0
  974. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js +107 -0
  975. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomContext.js.map +1 -0
  976. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js +41 -0
  977. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomHint.js.map +1 -0
  978. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js +117 -0
  979. package/build/dist/UI/Components/Charts/TimeRangeZoom/TimeRangeZoomUtil.js.map +1 -0
  980. package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js +121 -0
  981. package/build/dist/UI/Components/Charts/TimeRangeZoom/UseTimeRangeZoom.js.map +1 -0
  982. package/build/dist/UI/Components/Charts/Utils/DataPoint.js +15 -7
  983. package/build/dist/UI/Components/Charts/Utils/DataPoint.js.map +1 -1
  984. package/build/dist/UI/Components/Charts/Utils/XAxis.js +70 -0
  985. package/build/dist/UI/Components/Charts/Utils/XAxis.js.map +1 -1
  986. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js +305 -38
  987. package/build/dist/UI/Components/Charts/Utils/useHistogramRangeSelection.js.map +1 -1
  988. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js +169 -0
  989. package/build/dist/UI/Components/CustomFields/CustomFieldFormFields.js.map +1 -0
  990. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js +212 -0
  991. package/build/dist/UI/Components/CustomFields/CustomFieldModelFormFields.js.map +1 -0
  992. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js +64 -49
  993. package/build/dist/UI/Components/CustomFields/CustomFieldsDetail.js.map +1 -1
  994. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js +89 -14
  995. package/build/dist/UI/Components/EntityDropdown/EntityDropdown.js.map +1 -1
  996. package/build/dist/UI/Components/Forms/Fields/FormField.js +11 -2
  997. package/build/dist/UI/Components/Forms/Fields/FormField.js.map +1 -1
  998. package/build/dist/UI/Components/Forms/ModelForm.js +39 -5
  999. package/build/dist/UI/Components/Forms/ModelForm.js.map +1 -1
  1000. package/build/dist/UI/Components/Forms/Validation.js +1 -1
  1001. package/build/dist/UI/Components/Forms/Validation.js.map +1 -1
  1002. package/build/dist/UI/Components/Input/Input.js +69 -54
  1003. package/build/dist/UI/Components/Input/Input.js.map +1 -1
  1004. package/build/dist/UI/Components/List/ListRow.js +4 -39
  1005. package/build/dist/UI/Components/List/ListRow.js.map +1 -1
  1006. package/build/dist/UI/Components/LogsViewer/LogsViewer.js +31 -8
  1007. package/build/dist/UI/Components/LogsViewer/LogsViewer.js.map +1 -1
  1008. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js +10 -1
  1009. package/build/dist/UI/Components/LogsViewer/components/LogTimeRangePicker.js.map +1 -1
  1010. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js +139 -21
  1011. package/build/dist/UI/Components/LogsViewer/components/LogsAnalyticsView.js.map +1 -1
  1012. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js +30 -8
  1013. package/build/dist/UI/Components/LogsViewer/components/LogsHistogram.js.map +1 -1
  1014. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js +1 -1
  1015. package/build/dist/UI/Components/LogsViewer/components/LogsViewerToolbar.js.map +1 -1
  1016. package/build/dist/UI/Components/ModelFormModal/ModelFormModal.js.map +1 -1
  1017. package/build/dist/UI/Components/ModelTable/AnalyticsModelTable.js.map +1 -1
  1018. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +12 -2
  1019. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  1020. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js +13 -1
  1021. package/build/dist/UI/Components/ModelTable/CustomFieldColumns.js.map +1 -1
  1022. package/build/dist/UI/Components/ModelTable/ModelTable.js +1 -1
  1023. package/build/dist/UI/Components/ModelTable/ModelTable.js.map +1 -1
  1024. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +253 -14
  1025. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  1026. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +43 -13
  1027. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  1028. package/build/dist/UI/Components/OrderedStatesList/Item.js +2 -38
  1029. package/build/dist/UI/Components/OrderedStatesList/Item.js.map +1 -1
  1030. package/build/dist/UI/Components/StatusPage/ResourceGrid.js +53 -15
  1031. package/build/dist/UI/Components/StatusPage/ResourceGrid.js.map +1 -1
  1032. package/build/dist/UI/Components/Table/TableBody.js +6 -2
  1033. package/build/dist/UI/Components/Table/TableBody.js.map +1 -1
  1034. package/build/dist/UI/Components/Table/TableRow.js +12 -75
  1035. package/build/dist/UI/Components/Table/TableRow.js.map +1 -1
  1036. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +32 -7
  1037. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  1038. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js +27 -9
  1039. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryHistogram.js.map +1 -1
  1040. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js +11 -1
  1041. package/build/dist/UI/Components/TelemetryViewer/components/TelemetryTimeRangePicker.js.map +1 -1
  1042. package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js +272 -0
  1043. package/build/dist/UI/Components/TelemetryViewer/useViewerTimeRangeZoom.js.map +1 -0
  1044. package/build/dist/UI/Components/Toggle/Toggle.js +14 -1
  1045. package/build/dist/UI/Components/Toggle/Toggle.js.map +1 -1
  1046. package/build/dist/UI/Components/Tooltip/Tooltip.js +1 -1
  1047. package/build/dist/UI/Components/Tooltip/Tooltip.js.map +1 -1
  1048. package/build/dist/UI/Utils/SensitiveUrlToken.js +10 -5
  1049. package/build/dist/UI/Utils/SensitiveUrlToken.js.map +1 -1
  1050. package/build/dist/Utils/API.js +177 -1
  1051. package/build/dist/Utils/API.js.map +1 -1
  1052. package/build/dist/Utils/AiRemediation/CommandPolicy.js +1 -1
  1053. package/build/dist/Utils/AiRemediation/CommandPolicy.js.map +1 -1
  1054. package/build/dist/Utils/AiRemediation/KubectlPolicy.js +1 -1
  1055. package/build/dist/Utils/AiRemediation/KubectlPolicy.js.map +1 -1
  1056. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js +27 -1
  1057. package/build/dist/Utils/Dashboard/DashboardTimeRangeZoom.js.map +1 -1
  1058. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js +155 -0
  1059. package/build/dist/Utils/Incident/IncidentNoteTemplateVariables.js.map +1 -0
  1060. package/build/dist/Utils/Markdown/MarkdownEscape.js +48 -0
  1061. package/build/dist/Utils/Markdown/MarkdownEscape.js.map +1 -1
  1062. package/build/dist/Utils/ProbeNetworkFailureUtil.js +460 -0
  1063. package/build/dist/Utils/ProbeNetworkFailureUtil.js.map +1 -0
  1064. package/package.json +1 -1
@@ -14,6 +14,9 @@ import QueryHelper from "../Types/Database/QueryHelper";
14
14
  import DatabaseService from "./DatabaseService";
15
15
  import IncidentCustomField from "../../Models/DatabaseModels/IncidentCustomField";
16
16
  import CustomFieldMappingService from "./CustomFieldMappingService";
17
+ import IncidentCustomFieldService from "./IncidentCustomFieldService";
18
+ import { mergeTemplateCustomFields } from "../../Types/CustomField/CustomFieldTemplateMerge";
19
+ import { formatCustomFieldValueValidationErrors, validateCustomFieldValues, } from "../../Types/CustomField/CustomFieldValueValidator";
17
20
  import AIRunService from "./AIRunService";
18
21
  import AIRunType from "../../Types/AI/AIRunType";
19
22
  import AIRunStatus from "../../Types/AI/AIRunStatus";
@@ -39,6 +42,14 @@ import { getAffectedResourceRelations } from "../Utils/Database/AffectedResource
39
42
  import SloRecordReferenceValidator from "../Utils/Slo/SloRecordReferenceValidator";
40
43
  import UserNotificationEventType from "../../Types/UserNotification/UserNotificationEventType";
41
44
  import StatusPageSubscriberNotificationStatus from "../../Types/StatusPage/StatusPageSubscriberNotificationStatus";
45
+ import IncidentCreatedRenotify from "../../Types/StatusPage/IncidentCreatedRenotify";
46
+ import IncidentCreatedResend from "../../Types/StatusPage/IncidentCreatedResend";
47
+ import IncidentScopeAddedPagesNotification, { IncidentScopeAddedPagesNotificationAction, } from "../../Types/StatusPage/IncidentScopeAddedPagesNotification";
48
+ import NotAuthorizedException from "../../Types/Exception/NotAuthorizedException";
49
+ import StatusPage from "../../Models/DatabaseModels/StatusPage";
50
+ import StatusPageService from "./StatusPageService";
51
+ import StatusPageReadAccess from "../Utils/StatusPage/StatusPageReadAccess";
52
+ import SubscriberNotificationResendAccess from "../Utils/StatusPage/SubscriberNotificationResendAccess";
42
53
  import DockerHost from "../../Models/DatabaseModels/DockerHost";
43
54
  import PodmanHost from "../../Models/DatabaseModels/PodmanHost";
44
55
  import Host from "../../Models/DatabaseModels/Host";
@@ -57,6 +68,7 @@ import ServiceType from "../../Types/Telemetry/ServiceType";
57
68
  import OneUptimeDate from "../../Types/Date";
58
69
  import TelemetryUtil from "../Utils/Telemetry/Telemetry";
59
70
  import MetricResourceAttributeUtil from "../../Utils/Metrics/MetricResourceAttributeUtil";
71
+ import { escapeMarkdownInline } from "../../Utils/Markdown/MarkdownEscape";
60
72
  import logger from "../Utils/Logger";
61
73
  import ProductAnalytics from "../Utils/ProductAnalytics";
62
74
  import Semaphore from "../Infrastructure/Semaphore";
@@ -316,18 +328,36 @@ export class Service extends DatabaseService {
316
328
  }
317
329
  async onBeforeUpdate(updateBy) {
318
330
  /*
319
- * get monitors for this incident.
320
- * if the monitors are removed then change them to operational state.
321
- * then change all of the monitors in this incident to the changeMonitorStatusToId.
331
+ * Records which monitors the update takes off and puts on each incident,
332
+ * the monitor status it writes, and whether the incident was resolved
333
+ * before it, for onUpdateSuccess to decide what that does to the
334
+ * monitors (updateMonitorsForIncidentEdit).
322
335
  */
323
- var _a, _b, _c, _d, _e, _f, _g, _h, _j;
324
336
  updateBy.query = applyIncidentSelfPrivacyFilter(updateBy.query, updateBy.props);
325
337
  if (updateBy.data.isPrivate === true) {
326
338
  updateBy.data.isVisibleOnStatusPage = false;
327
339
  }
340
+ this.stripServiceOwnedScopeColumns(updateBy);
341
+ /*
342
+ * Before anything below adds values of its own to customFields (the
343
+ * mapped values copied from monitors), so only what the caller wrote is
344
+ * checked.
345
+ */
346
+ await this.validateCustomFieldValuesOnUpdate(updateBy);
347
+ // Before the hooks below add a Pending of their own.
348
+ const isCreatedNotificationResendRequested = this.isCreatedNotificationResendRequested(updateBy);
328
349
  await this.validateProjectScopedReferences(updateBy);
329
350
  const carryForward = {};
330
- if (updateBy.data.monitors ||
351
+ const data = updateBy.data;
352
+ /*
353
+ * Only an update that sends the monitor list changes which monitors the
354
+ * incident holds. One that sends just the monitor status (the API, the
355
+ * CLI or a workflow) takes no monitor off: reading the missing list as
356
+ * empty would restore every monitor, and walking it threw. A list set to
357
+ * null is sent: TypeORM clears a many-to-many set to null, like [].
358
+ */
359
+ const isMonitorListUpdated = data["monitors"] !== undefined;
360
+ if (isMonitorListUpdated ||
331
361
  updateBy.data.changeMonitorStatusTo ||
332
362
  updateBy.data.changeMonitorStatusToId) {
333
363
  const incidentsToUpdate = await this.findBy({
@@ -343,46 +373,54 @@ export class Service extends DatabaseService {
343
373
  skip: 0,
344
374
  props: updateBy.props,
345
375
  });
376
+ /*
377
+ * The monitor status the update writes, in any shape the API accepts
378
+ * (an id, a bare uuid string or a relation object), so the status an
379
+ * update writes is never mistaken for one it leaves alone.
380
+ */
381
+ const monitorStatusIdInUpdate = resolveReferenceId(data["changeMonitorStatusToId"]) ||
382
+ resolveReferenceId(data["changeMonitorStatusTo"]);
383
+ const newMonitorChangeStatusIdTo = monitorStatusIdInUpdate
384
+ ? new ObjectID(monitorStatusIdInUpdate.toString())
385
+ : undefined;
386
+ const isChangeMonitorStatusToCleared = !newMonitorChangeStatusIdTo &&
387
+ (data["changeMonitorStatusToId"] === null ||
388
+ data["changeMonitorStatusTo"] === null);
389
+ const monitorIdsAfterUpdate = isMonitorListUpdated
390
+ ? this.getMonitorIdsInUpdate(data["monitors"])
391
+ : [];
346
392
  for (const incident of incidentsToUpdate) {
393
+ const storedMonitors = incident.monitors || [];
394
+ const storedMonitorIds = storedMonitors.map((monitor) => {
395
+ return this.getMonitorIdForComparison(monitor);
396
+ });
397
+ const monitorsRemoved = isMonitorListUpdated
398
+ ? storedMonitors.filter((monitor) => {
399
+ return !monitorIdsAfterUpdate.includes(this.getMonitorIdForComparison(monitor));
400
+ })
401
+ : [];
347
402
  carryForward[incident.id.toString()] = {
348
- monitorsRemoved: [],
349
- monitorsAdded: [],
403
+ monitorsRemoved: monitorsRemoved,
404
+ /*
405
+ * Read now, before the write: an update that resolves the incident
406
+ * and takes a monitor off must still restore that monitor, and one
407
+ * that reopens a resolved incident must not restore it twice.
408
+ * After the write, the state no longer tells these cases apart.
409
+ */
410
+ isResolvedBeforeUpdate: monitorsRemoved.length > 0
411
+ ? await this.isIncidentResolved({ incidentId: incident.id })
412
+ : undefined,
413
+ monitorsAdded: monitorIdsAfterUpdate
414
+ .filter((monitorId) => {
415
+ return !storedMonitorIds.includes(monitorId);
416
+ })
417
+ .map((monitorId) => {
418
+ return new Monitor(new ObjectID(monitorId));
419
+ }),
350
420
  oldChangeMonitorStatusIdTo: incident.changeMonitorStatusToId,
351
- newMonitorChangeStatusIdTo: updateBy.data.changeMonitorStatusToId ||
352
- ((_a = updateBy.data.changeMonitorStatusTo) === null || _a === void 0 ? void 0 : _a._id) ||
353
- undefined,
421
+ newMonitorChangeStatusIdTo: newMonitorChangeStatusIdTo,
422
+ isChangeMonitorStatusToCleared: isChangeMonitorStatusToCleared,
354
423
  };
355
- for (const monitor of incident.monitors || []) {
356
- // check if this monitor is actually removed.
357
- let isRemoved = true;
358
- for (const updatedMonitor of (_b = updateBy.data) === null || _b === void 0 ? void 0 : _b.monitors) {
359
- if (updatedMonitor._id &&
360
- updatedMonitor._id.toString() === ((_c = monitor._id) === null || _c === void 0 ? void 0 : _c.toString())) {
361
- isRemoved = false;
362
- break;
363
- }
364
- }
365
- if (isRemoved) {
366
- (_e = (_d = carryForward[incident.id.toString()]) === null || _d === void 0 ? void 0 : _d.monitorsRemoved) === null || _e === void 0 ? void 0 : _e.push(monitor);
367
- }
368
- }
369
- if (updateBy.data.monitors && updateBy.data.monitors.length > 0) {
370
- for (const monitor of (_f = updateBy.data) === null || _f === void 0 ? void 0 : _f.monitors) {
371
- // check if this monitor is actually added.
372
- let isAdded = true;
373
- for (const existingMonitor of incident.monitors || []) {
374
- if (existingMonitor._id &&
375
- existingMonitor._id.toString() === ((_g = monitor._id) === null || _g === void 0 ? void 0 : _g.toString())) {
376
- isAdded = false;
377
- break;
378
- }
379
- }
380
- if (isAdded) {
381
- // this monitor is added.
382
- (_j = (_h = carryForward[incident.id.toString()]) === null || _h === void 0 ? void 0 : _h.monitorsAdded) === null || _j === void 0 ? void 0 : _j.push(monitor);
383
- }
384
- }
385
- }
386
424
  }
387
425
  }
388
426
  // Set notification status based on shouldStatusPageSubscribersBeNotifiedOnIncidentCreated if it's being updated
@@ -401,6 +439,30 @@ export class Service extends DatabaseService {
401
439
  StatusPageSubscriberNotificationStatus.Pending;
402
440
  }
403
441
  }
442
+ await this.queueCreatedNotificationResendToAllStatusPagesIfRequested(updateBy);
443
+ /*
444
+ * Retry or Resend - a user's Pending - over a notification that is
445
+ * being sent would let a second run send it alongside, or be
446
+ * overwritten when the send settles (SubscriberNotificationResendAccess).
447
+ * 'Resend to all pages' above has refused that already, with its own
448
+ * reason; the hooks below queue their own Pending only from a settled
449
+ * state.
450
+ */
451
+ await SubscriberNotificationResendAccess.assertNotQueuedWhileBeingSent({
452
+ modelType: Model,
453
+ service: this,
454
+ updateBy: updateBy,
455
+ statusColumns: [
456
+ "subscriberNotificationStatusOnIncidentCreated",
457
+ "subscriberNotificationStatusOnPostmortemPublished",
458
+ ],
459
+ });
460
+ await this.clearCreatedNotificationRecordOnResend({
461
+ updateBy: updateBy,
462
+ isResendRequested: isCreatedNotificationResendRequested,
463
+ });
464
+ await this.queueCreatedNotificationOnPublishIfRequested(updateBy);
465
+ await this.applyStatusPageScopeToUpdate(updateBy, carryForward);
404
466
  /*
405
467
  * Re-apply mapped custom field values. Covers the Custom Fields modal
406
468
  * saving the whole bag back over a mapped value, and the incident's
@@ -417,6 +479,839 @@ export class Service extends DatabaseService {
417
479
  carryForward: carryForward,
418
480
  };
419
481
  }
482
+ /*
483
+ * The ids of the monitors an update's list holds, deduplicated and
484
+ * lowercased like getMonitorIdForComparison. The list reaches the hook as
485
+ * models, `{ _id }` objects, ObjectIDs or bare uuid strings (API update),
486
+ * and comparing only `_id` read every bare id as a monitor taken off and
487
+ * put back on again.
488
+ */
489
+ getMonitorIdsInUpdate(monitors) {
490
+ const monitorIds = [];
491
+ for (const monitorId of resolveReferenceIds(monitors)) {
492
+ const normalizedMonitorId = monitorId
493
+ .toString()
494
+ .trim()
495
+ .toLowerCase();
496
+ if (!monitorIds.includes(normalizedMonitorId)) {
497
+ monitorIds.push(normalizedMonitorId);
498
+ }
499
+ }
500
+ return monitorIds;
501
+ }
502
+ // A monitor's id as getMonitorIdsInUpdate writes it, for comparing the two.
503
+ getMonitorIdForComparison(monitor) {
504
+ var _a;
505
+ return (((_a = monitor._id) === null || _a === void 0 ? void 0 : _a.toString()) || "").trim().toLowerCase();
506
+ }
507
+ /*
508
+ * The incidents an update will write to, as they are stored, for the hooks
509
+ * below that decide what else joins the update.
510
+ *
511
+ * Read as root: the answer only decides which columns join this update, and
512
+ * the update itself is still checked against the caller's permissions
513
+ * afterwards. Reading with the caller's props would fail the whole edit for
514
+ * a role that may edit incidents but not read these columns. The query
515
+ * already carries the caller's privacy filter (applyIncidentSelfPrivacyFilter),
516
+ * but not their tenant: the update's permission check adds it only after
517
+ * this hook runs. So a non-root caller's read is limited to their own
518
+ * project here, or a request for another project's incident id would be
519
+ * answered with that incident's state (a refusal that depends on it)
520
+ * instead of the usual "nothing updated".
521
+ */
522
+ async findIncidentsForUpdateHook(data) {
523
+ const updateBy = data.updateBy;
524
+ const query = !updateBy.props.isRoot && updateBy.props.tenantId
525
+ ? Object.assign(Object.assign({}, updateBy.query), { projectId: updateBy.props.tenantId }) : updateBy.query;
526
+ return await this.findBy({
527
+ query: query,
528
+ select: data.select,
529
+ limit: LIMIT_MAX,
530
+ skip: 0,
531
+ props: {
532
+ isRoot: true,
533
+ },
534
+ });
535
+ }
536
+ /*
537
+ * CUSTOM FIELD VALUES must fit their fields: a Number field holds a number,
538
+ * a Dropdown one of its options (CustomFieldValueValidator has the rules).
539
+ *
540
+ * Only for writes a user or an API key makes. Root writes - the server's
541
+ * own, such as values copied from monitors or an incident template - are
542
+ * trusted, and the mapped values are added after this runs, so they never
543
+ * reach it. Only the keys a write changes are checked, so a value stored
544
+ * before these checks, or a dropdown option removed since, does not stop
545
+ * someone saving the rest of the card.
546
+ *
547
+ * "Required on create" is not enforced here: incidents created by
548
+ * monitors, the API, Slack, Microsoft Teams or AI cannot fill in a form.
549
+ */
550
+ async getCustomFieldDefinitionsForValidation(projectId) {
551
+ const definitions = await IncidentCustomFieldService.findBy({
552
+ query: {
553
+ projectId: projectId,
554
+ },
555
+ select: {
556
+ name: true,
557
+ customFieldType: true,
558
+ dropdownOptions: true,
559
+ },
560
+ limit: LIMIT_PER_PROJECT,
561
+ skip: 0,
562
+ props: {
563
+ isRoot: true,
564
+ },
565
+ });
566
+ const result = [];
567
+ for (const definition of definitions) {
568
+ if (typeof definition.name !== "string") {
569
+ continue;
570
+ }
571
+ result.push({
572
+ name: definition.name,
573
+ customFieldType: definition.customFieldType,
574
+ dropdownOptions: definition.dropdownOptions,
575
+ });
576
+ }
577
+ return result;
578
+ }
579
+ hasCustomFieldValuesToValidate(customFields) {
580
+ return (customFields !== null &&
581
+ typeof customFields === "object" &&
582
+ !Array.isArray(customFields) &&
583
+ Object.keys(customFields).length > 0);
584
+ }
585
+ throwIfCustomFieldValuesInvalid(errors) {
586
+ if (errors.length > 0) {
587
+ throw new BadDataException(formatCustomFieldValueValidationErrors(errors));
588
+ }
589
+ }
590
+ async validateCustomFieldValuesOnCreate(data) {
591
+ const customFields = data.createBy.data.customFields;
592
+ if (data.createBy.props.isRoot ||
593
+ !data.projectId ||
594
+ !this.hasCustomFieldValuesToValidate(customFields)) {
595
+ return;
596
+ }
597
+ this.throwIfCustomFieldValuesInvalid(validateCustomFieldValues({
598
+ definitions: await this.getCustomFieldDefinitionsForValidation(data.projectId),
599
+ customFields: customFields,
600
+ storedCustomFields: {},
601
+ }));
602
+ }
603
+ /*
604
+ * Checked against each incident the update writes, because what counts as
605
+ * changed depends on what that incident already holds.
606
+ */
607
+ async validateCustomFieldValuesOnUpdate(updateBy) {
608
+ const customFields = updateBy.data.customFields;
609
+ if (updateBy.props.isRoot ||
610
+ !this.hasCustomFieldValuesToValidate(customFields)) {
611
+ return;
612
+ }
613
+ const incidents = await this.findIncidentsForUpdateHook({
614
+ updateBy: updateBy,
615
+ select: {
616
+ _id: true,
617
+ projectId: true,
618
+ customFields: true,
619
+ },
620
+ });
621
+ const definitionsByProject = new Map();
622
+ for (const incident of incidents) {
623
+ if (!incident.projectId) {
624
+ continue;
625
+ }
626
+ const projectKey = incident.projectId.toString();
627
+ if (!definitionsByProject.has(projectKey)) {
628
+ definitionsByProject.set(projectKey, await this.getCustomFieldDefinitionsForValidation(incident.projectId));
629
+ }
630
+ this.throwIfCustomFieldValuesInvalid(validateCustomFieldValues({
631
+ definitions: definitionsByProject.get(projectKey),
632
+ customFields: customFields,
633
+ storedCustomFields: incident.customFields,
634
+ }));
635
+ }
636
+ }
637
+ /*
638
+ * isScopedToStatusPages and statusPagesNotifiedOnCreation are this
639
+ * service's to write. A client value for either is dropped before any hook
640
+ * runs, so what the hooks write is all that is written: the flag is derived
641
+ * from statusPages (applyStatusPageScopeToUpdate), and the record is the
642
+ * notification job's - a client must not be able to seed it and so keep
643
+ * pages from ever hearing about the incident, or clear it and have them
644
+ * told twice. Root (internal) callers keep the record they send.
645
+ */
646
+ stripServiceOwnedScopeColumns(updateBy) {
647
+ const data = updateBy.data;
648
+ delete data["isScopedToStatusPages"];
649
+ if (!updateBy.props.isRoot) {
650
+ delete data["statusPagesNotifiedOnCreation"];
651
+ }
652
+ }
653
+ /*
654
+ * Whether an update itself asks for the 'created' notification to go out
655
+ * again: it sets the status to Pending - the API route of resending it,
656
+ * and the dashboard's Retry - turns notifying on creation on, which
657
+ * onBeforeUpdate maps to Pending, or asks for it to be sent to every
658
+ * status page again (IncidentCreatedResend, the dashboard's Resend). Read
659
+ * before any hook adds a Pending of its own.
660
+ */
661
+ isCreatedNotificationResendRequested(updateBy) {
662
+ return (updateBy.data.subscriberNotificationStatusOnIncidentCreated ===
663
+ StatusPageSubscriberNotificationStatus.Pending ||
664
+ updateBy.data.shouldStatusPageSubscribersBeNotifiedOnIncidentCreated ===
665
+ true ||
666
+ IncidentCreatedResend.isRequested(updateBy.miscDataProps));
667
+ }
668
+ /*
669
+ * 'Resend to all pages' (see IncidentCreatedResend): the 'created'
670
+ * notification goes back to Pending with a message saying so, and
671
+ * clearCreatedNotificationRecordOnResend empties its record of told pages
672
+ * in the same write, so the job sends it to every page the incident
673
+ * reaches now - after a failure too, where a plain Retry would resume.
674
+ *
675
+ * Everything is written into the caller's own update, so it lands with the
676
+ * rest of it or not at all, and the column check that runs after this hook
677
+ * still decides whether the caller may write the status. That check is
678
+ * also made here first, before the incidents are read: the refusals below
679
+ * depend on the notification's state, and a caller who may not send it
680
+ * again is told only that. The incidents are then read with the caller's
681
+ * own permissions (and the privacy filter already on the query), so an
682
+ * incident they cannot see never decides the answer; when they can see
683
+ * none of those the update matches, nothing is queued.
684
+ *
685
+ * Refused - with the reason, rather than silently dropped, because asking
686
+ * for it is the whole point of the request - when any matched incident's
687
+ * notification did not go out (Skipped) or is on its way (Pending,
688
+ * InProgress), and when the same update sets the status to anything but
689
+ * Pending.
690
+ */
691
+ async queueCreatedNotificationResendToAllStatusPagesIfRequested(updateBy) {
692
+ if (!IncidentCreatedResend.isRequested(updateBy.miscDataProps)) {
693
+ return;
694
+ }
695
+ const requestedStatus = updateBy.data.subscriberNotificationStatusOnIncidentCreated;
696
+ if (requestedStatus !== undefined &&
697
+ requestedStatus !== StatusPageSubscriberNotificationStatus.Pending) {
698
+ throw new BadDataException(IncidentCreatedResend.conflictingStatusMessage);
699
+ }
700
+ SubscriberNotificationResendAccess.assertCallerMayUpdateColumns({
701
+ modelType: Model,
702
+ columns: {
703
+ subscriberNotificationStatusOnIncidentCreated: StatusPageSubscriberNotificationStatus.Pending,
704
+ subscriberNotificationStatusMessage: IncidentCreatedResend.queuedMessage,
705
+ statusPagesNotifiedOnCreation: [],
706
+ },
707
+ props: updateBy.props,
708
+ refusal: IncidentCreatedResend.noPermissionMessage,
709
+ });
710
+ const incidents = await this.findBy({
711
+ query: updateBy.query,
712
+ select: {
713
+ _id: true,
714
+ subscriberNotificationStatusOnIncidentCreated: true,
715
+ },
716
+ limit: LIMIT_MAX,
717
+ skip: 0,
718
+ props: updateBy.props,
719
+ });
720
+ for (const incident of incidents) {
721
+ const refusal = IncidentCreatedResend.getRefusalReason(incident.subscriberNotificationStatusOnIncidentCreated);
722
+ if (refusal) {
723
+ throw new BadDataException(refusal);
724
+ }
725
+ }
726
+ if (incidents.length === 0) {
727
+ return;
728
+ }
729
+ updateBy.data.subscriberNotificationStatusOnIncidentCreated =
730
+ StatusPageSubscriberNotificationStatus.Pending;
731
+ if (updateBy.data.subscriberNotificationStatusMessage === undefined) {
732
+ updateBy.data.subscriberNotificationStatusMessage =
733
+ IncidentCreatedResend.queuedMessage;
734
+ }
735
+ }
736
+ /*
737
+ * A resend asked for by the update itself (see
738
+ * isCreatedNotificationResendRequested) goes to every status page, as it
739
+ * always did. The job skips the pages in its record of told pages
740
+ * (Incident.statusPagesNotifiedOnCreation), so without this a resend of a
741
+ * notification that went out would reach nobody: the record is emptied in
742
+ * the same write.
743
+ *
744
+ * It is kept in three cases:
745
+ * - Failed: Retry resumes where the failed send stopped, so the pages it
746
+ * told are not told twice - unless the update asks for it to go to every
747
+ * page again (IncidentCreatedResend), which is what that request is for;
748
+ * - Pending or InProgress: the notification is on its way already, and its
749
+ * record is what keeps a send queued for added pages from reaching the
750
+ * pages told before (IncidentCreatedResend refuses these);
751
+ * - a root caller that writes the record itself.
752
+ *
753
+ * An update matching several incidents empties the record when any of them
754
+ * would otherwise be resent to nobody, because the write applies the same
755
+ * data to all of them.
756
+ */
757
+ async clearCreatedNotificationRecordOnResend(data) {
758
+ const updateBy = data.updateBy;
759
+ if (!data.isResendRequested) {
760
+ return;
761
+ }
762
+ if (updateBy.data["statusPagesNotifiedOnCreation"] !== undefined) {
763
+ return;
764
+ }
765
+ if (IncidentCreatedResend.isRequested(updateBy.miscDataProps)) {
766
+ /*
767
+ * Queued for every page by
768
+ * queueCreatedNotificationResendToAllStatusPagesIfRequested, which
769
+ * left the status alone when the caller can see none of the incidents
770
+ * the update matches: nothing to read to decide.
771
+ */
772
+ if (updateBy.data.subscriberNotificationStatusOnIncidentCreated ===
773
+ StatusPageSubscriberNotificationStatus.Pending) {
774
+ updateBy.data.statusPagesNotifiedOnCreation = [];
775
+ }
776
+ return;
777
+ }
778
+ const incidents = await this.findIncidentsForUpdateHook({
779
+ updateBy: updateBy,
780
+ select: {
781
+ _id: true,
782
+ subscriberNotificationStatusOnIncidentCreated: true,
783
+ },
784
+ });
785
+ const someIncidentWouldReachNobody = incidents.some((incident) => {
786
+ return ![
787
+ StatusPageSubscriberNotificationStatus.Failed,
788
+ StatusPageSubscriberNotificationStatus.Pending,
789
+ StatusPageSubscriberNotificationStatus.InProgress,
790
+ ].includes(incident.subscriberNotificationStatusOnIncidentCreated);
791
+ });
792
+ if (someIncidentWouldReachNobody) {
793
+ updateBy.data.statusPagesNotifiedOnCreation = [];
794
+ }
795
+ }
796
+ /*
797
+ * Publishing a hidden incident can announce it: when the editor turns
798
+ * 'Visible on Status Page' on and ticks "Notify subscribers that this
799
+ * incident was created" (see IncidentCreatedRenotify), the incident's
800
+ * 'created' notification goes back to Pending, and the
801
+ * Incident:SendNotificationToSubscribers job sends it now that the incident
802
+ * is visible - to the pages its record of told pages does not list, so an
803
+ * incident whose notification went out before it was hidden tells only the
804
+ * pages added while it was hidden.
805
+ *
806
+ * It only ever re-queues a notification with someone left to tell, for an
807
+ * incident that is hidden today, not private, and meant to notify on
808
+ * creation, so a stray request cannot email subscribers twice or break a
809
+ * deliberate "don't notify". The status is written into this same update,
810
+ * so it lands together with the visibility change or not at all. The
811
+ * column (and its message) are computed, but their update ACL lists the
812
+ * incident roles, so a non-root edit still passes the column check that
813
+ * runs after this hook.
814
+ *
815
+ * An update that sets the status itself - the API route of resetting it to
816
+ * Pending, or the notify-on-create flag above - is left alone. An update
817
+ * that matches several incidents queues only when every one of them
818
+ * qualifies, because the write applies the same data to all of them.
819
+ */
820
+ async queueCreatedNotificationOnPublishIfRequested(updateBy) {
821
+ if (!IncidentCreatedRenotify.isRequested(updateBy.miscDataProps)) {
822
+ return;
823
+ }
824
+ if (updateBy.data.isVisibleOnStatusPage !== true) {
825
+ return;
826
+ }
827
+ if (updateBy.data.subscriberNotificationStatusOnIncidentCreated !== undefined) {
828
+ return;
829
+ }
830
+ const incidents = await this.findIncidentsForUpdateHook({
831
+ updateBy: updateBy,
832
+ select: {
833
+ _id: true,
834
+ isVisibleOnStatusPage: true,
835
+ isPrivate: true,
836
+ subscriberNotificationStatusOnIncidentCreated: true,
837
+ shouldStatusPageSubscribersBeNotifiedOnIncidentCreated: true,
838
+ statusPagesNotifiedOnCreation: true,
839
+ statusPages: {
840
+ _id: true,
841
+ },
842
+ },
843
+ });
844
+ if (incidents.length === 0) {
845
+ return;
846
+ }
847
+ const everyIncidentQualifies = incidents.every((incident) => {
848
+ return IncidentCreatedRenotify.canRenotifyOnPublish({
849
+ isVisibleOnStatusPage: incident.isVisibleOnStatusPage,
850
+ isPrivate: updateBy.data.isPrivate !== undefined &&
851
+ updateBy.data.isPrivate !== null
852
+ ? updateBy.data.isPrivate
853
+ : incident.isPrivate,
854
+ subscriberNotificationStatusOnIncidentCreated: incident.subscriberNotificationStatusOnIncidentCreated,
855
+ shouldStatusPageSubscribersBeNotifiedOnIncidentCreated: incident.shouldStatusPageSubscribersBeNotifiedOnIncidentCreated,
856
+ // The pages it is limited to once this update is written.
857
+ statusPages: updateBy.data.statusPages !== undefined
858
+ ? updateBy.data.statusPages
859
+ : incident.statusPages,
860
+ statusPagesNotifiedOnCreation: incident.statusPagesNotifiedOnCreation,
861
+ });
862
+ });
863
+ if (!everyIncidentQualifies) {
864
+ logger.debug(`Not re-queueing the incident created notification on publish: ${incidents.length} incident(s) matched and not all of them were hidden, set to notify subscribers and had subscribers left to tell.`);
865
+ return;
866
+ }
867
+ updateBy.data.subscriberNotificationStatusOnIncidentCreated =
868
+ StatusPageSubscriberNotificationStatus.Pending;
869
+ updateBy.data.subscriberNotificationStatusMessage =
870
+ IncidentCreatedRenotify.queuedMessage;
871
+ }
872
+ /*
873
+ * The status pages a new incident is limited to (Incident.statusPages), and
874
+ * the two columns that follow from them.
875
+ *
876
+ * isScopedToStatusPages is derived from the list, whatever the caller sent
877
+ * for it: the column is computed, which exempts it from the column check on
878
+ * create, so a client value would otherwise be stored as is - and a scoped
879
+ * flag with no pages hides the incident from every status page.
880
+ *
881
+ * statusPagesNotifiedOnCreation is the created-notification job's record of
882
+ * the pages it told. A client must not be able to seed it and so keep pages
883
+ * from ever hearing about the incident; only root (internal) callers keep
884
+ * what they send.
885
+ *
886
+ * The pages a non-root caller picks must be pages they can read (see
887
+ * StatusPageReadAccess), except the pages of an incident template they can
888
+ * read: the dashboard fills a template's pages in for everyone who declares
889
+ * from it, which is what the template is for. Pages copied from a template
890
+ * on the server are not the caller's pick. That is checked once the pages
891
+ * are known to be the project's (assertCallerCanPickStatusPagesOnCreate).
892
+ *
893
+ * `isScopedToNothingByTemplate`: declared through the API from a template
894
+ * whose status pages were all deleted. The incident is scoped with no
895
+ * pages - hidden from every status page - rather than unscoped.
896
+ */
897
+ applyStatusPageScopeToCreate(data) {
898
+ const createBy = data.createBy;
899
+ if (!createBy.props.isRoot) {
900
+ delete createBy.data.statusPagesNotifiedOnCreation;
901
+ }
902
+ const statusPageIds = IncidentScopeAddedPagesNotification.normalizeStatusPageIds(createBy.data.statusPages);
903
+ if (createBy.data.statusPages !== undefined &&
904
+ createBy.data.statusPages !== null) {
905
+ createBy.data.statusPages = this.toStatusPageStubs(statusPageIds);
906
+ }
907
+ createBy.data.isScopedToStatusPages =
908
+ statusPageIds.length > 0 || data.isScopedToNothingByTemplate === true;
909
+ }
910
+ /*
911
+ * The pages a non-root caller picks for a new incident must be pages they
912
+ * can read (see applyStatusPageScopeToCreate). Runs after the project check,
913
+ * so another project's page, or one that does not exist, is reported as
914
+ * such rather than as a page the caller cannot read.
915
+ */
916
+ async assertCallerCanPickStatusPagesOnCreate(data) {
917
+ const createBy = data.createBy;
918
+ const statusPageIds = IncidentScopeAddedPagesNotification.normalizeStatusPageIds(createBy.data.statusPages);
919
+ if (createBy.props.isRoot ||
920
+ !data.statusPagesFromCaller ||
921
+ statusPageIds.length === 0) {
922
+ return;
923
+ }
924
+ const readableStatusPageIds = await StatusPageReadAccess.getReadableStatusPageIds({
925
+ statusPageIds: statusPageIds,
926
+ props: createBy.props,
927
+ });
928
+ let unreadableStatusPageIds = statusPageIds.filter((id) => {
929
+ return !readableStatusPageIds.includes(id);
930
+ });
931
+ if (unreadableStatusPageIds.length > 0) {
932
+ const templateStatusPageIds = await this.getStatusPageIdsOfTemplatesReadableByCaller({
933
+ projectId: data.projectId,
934
+ props: createBy.props,
935
+ });
936
+ unreadableStatusPageIds = unreadableStatusPageIds.filter((id) => {
937
+ return !templateStatusPageIds.includes(id);
938
+ });
939
+ }
940
+ if (unreadableStatusPageIds.length > 0) {
941
+ throw new NotAuthorizedException(StatusPageReadAccess.getRefusalMessage("incident"));
942
+ }
943
+ }
944
+ /*
945
+ * The status pages the incident templates the caller can read are limited
946
+ * to. Such a page may be picked for a new incident without reading it:
947
+ * declaring from the template picks it anyway. The templates are read with
948
+ * the caller's permissions (and labels); their pages as root. A caller who
949
+ * cannot read templates at all gets none.
950
+ */
951
+ async getStatusPageIdsOfTemplatesReadableByCaller(data) {
952
+ let templates = [];
953
+ try {
954
+ templates = await IncidentTemplateService.findBy({
955
+ query: {
956
+ projectId: data.projectId,
957
+ },
958
+ select: {
959
+ _id: true,
960
+ },
961
+ limit: LIMIT_MAX,
962
+ skip: 0,
963
+ props: data.props,
964
+ });
965
+ }
966
+ catch (err) {
967
+ // No access to templates (or not on a plan that has them): no pages.
968
+ logger.debug(`Could not read the caller's incident templates while checking the status pages of a new incident: ${err}`);
969
+ return [];
970
+ }
971
+ if (templates.length === 0) {
972
+ return [];
973
+ }
974
+ const templatesWithPages = await IncidentTemplateService.findBy({
975
+ query: {
976
+ _id: QueryHelper.any(templates.map((template) => {
977
+ return template.id.toString();
978
+ })),
979
+ projectId: data.projectId,
980
+ },
981
+ select: {
982
+ _id: true,
983
+ statusPages: {
984
+ _id: true,
985
+ },
986
+ },
987
+ limit: LIMIT_MAX,
988
+ skip: 0,
989
+ props: {
990
+ isRoot: true,
991
+ },
992
+ });
993
+ return IncidentScopeAddedPagesNotification.normalizeStatusPageIds(templatesWithPages.flatMap((template) => {
994
+ return template.statusPages || [];
995
+ }));
996
+ }
997
+ /*
998
+ * The status pages an incident is limited to, on update. Everything that
999
+ * follows from a write to Incident.statusPages happens here, in the
1000
+ * caller's own update, so the list, the flag and a re-queued notification
1001
+ * land together or not at all:
1002
+ *
1003
+ * - isScopedToStatusPages is derived from the list the update writes (a
1004
+ * value the caller sent for it was dropped by
1005
+ * stripServiceOwnedScopeColumns). Nothing else ever sets it, and it is
1006
+ * never recomputed when join rows disappear: deleting the only page an
1007
+ * incident is scoped to leaves it scoped to nothing, hidden from every
1008
+ * page, rather than widened to all of them;
1009
+ * - a non-root caller's list is topped up with the pages the incident is
1010
+ * scoped to that the caller cannot read. Status pages are label-scoped,
1011
+ * so an editor may see only some of an incident's pages, and a list write
1012
+ * replaces the whole list (the dashboard sends back what the editor
1013
+ * sees). Without this, saving the incident would silently drop every page
1014
+ * the editor was not shown;
1015
+ * - the pages a non-root caller adds must be pages they can read (see
1016
+ * StatusPageReadAccess);
1017
+ * - with IncidentScopeAddedPagesNotification requested, the 'created'
1018
+ * notification is queued again for the pages the update adds;
1019
+ * - what was added and removed is carried forward for the feed item
1020
+ * onUpdateSuccess writes, and so is whether the notification was on its
1021
+ * way already, which onUpdateSuccess checks again once the pages are
1022
+ * written.
1023
+ *
1024
+ * The flag and the notification columns are computed, but their update
1025
+ * access control lists every role that may edit statusPages, so a non-root
1026
+ * edit passes the column check that runs after this hook.
1027
+ */
1028
+ async applyStatusPageScopeToUpdate(updateBy, carryForward) {
1029
+ const data = updateBy.data;
1030
+ if (data["statusPages"] === undefined) {
1031
+ return;
1032
+ }
1033
+ const incidents = await this.findIncidentsForUpdateHook({
1034
+ updateBy: updateBy,
1035
+ select: {
1036
+ _id: true,
1037
+ statusPages: {
1038
+ _id: true,
1039
+ },
1040
+ isVisibleOnStatusPage: true,
1041
+ isPrivate: true,
1042
+ subscriberNotificationStatusOnIncidentCreated: true,
1043
+ shouldStatusPageSubscribersBeNotifiedOnIncidentCreated: true,
1044
+ statusPagesNotifiedOnCreation: true,
1045
+ },
1046
+ });
1047
+ const requestedStatusPageIds = IncidentScopeAddedPagesNotification.normalizeStatusPageIds(data["statusPages"]);
1048
+ const hiddenStatusPageIds = updateBy.props.isRoot
1049
+ ? []
1050
+ : await this.getScopedStatusPageIdsHiddenFromCaller({
1051
+ incidents: incidents,
1052
+ props: updateBy.props,
1053
+ });
1054
+ const statusPageIds = [
1055
+ ...requestedStatusPageIds,
1056
+ ...hiddenStatusPageIds.filter((id) => {
1057
+ return !requestedStatusPageIds.includes(id);
1058
+ }),
1059
+ ];
1060
+ if (!updateBy.props.isRoot) {
1061
+ await StatusPageReadAccess.assertCallerCanPickStatusPages({
1062
+ statusPageIds: this.getStatusPageIdsAddedToAny({
1063
+ incidents: incidents,
1064
+ statusPageIds: statusPageIds,
1065
+ }),
1066
+ props: updateBy.props,
1067
+ subject: "incident",
1068
+ });
1069
+ }
1070
+ data["statusPages"] = this.toStatusPageStubs(statusPageIds);
1071
+ data["isScopedToStatusPages"] = statusPageIds.length > 0;
1072
+ const decisions = [];
1073
+ for (const incident of incidents) {
1074
+ const incidentId = incident.id.toString();
1075
+ const change = IncidentScopeAddedPagesNotification.getScopeChange({
1076
+ before: incident.statusPages,
1077
+ after: statusPageIds,
1078
+ });
1079
+ const action = IncidentScopeAddedPagesNotification.getAction({
1080
+ addedStatusPageIds: change.addedStatusPageIds,
1081
+ incident: {
1082
+ subscriberNotificationStatusOnIncidentCreated: incident.subscriberNotificationStatusOnIncidentCreated,
1083
+ shouldStatusPageSubscribersBeNotifiedOnIncidentCreated: incident.shouldStatusPageSubscribersBeNotifiedOnIncidentCreated,
1084
+ isVisibleOnStatusPage: this.getValueAfterUpdate(updateBy.data.isVisibleOnStatusPage, incident.isVisibleOnStatusPage),
1085
+ isPrivate: this.getValueAfterUpdate(updateBy.data.isPrivate, incident.isPrivate),
1086
+ statusPagesNotifiedOnCreation: incident.statusPagesNotifiedOnCreation,
1087
+ },
1088
+ });
1089
+ carryForward[incidentId] = Object.assign(Object.assign({ monitorsRemoved: [], monitorsAdded: [], oldChangeMonitorStatusIdTo: undefined, newMonitorChangeStatusIdTo: undefined }, carryForward[incidentId]), { statusPageScopeChange: Object.assign(Object.assign({}, change), { isScoped: statusPageIds.length > 0, notificationQueued: false,
1090
+ /*
1091
+ * On its way already, and nothing in this update sets the status:
1092
+ * onUpdateSuccess makes sure the send did not finish without the
1093
+ * added pages in the meantime.
1094
+ */
1095
+ notificationAlreadyQueued: action ===
1096
+ IncidentScopeAddedPagesNotificationAction.AlreadyQueued &&
1097
+ updateBy.data.subscriberNotificationStatusOnIncidentCreated ===
1098
+ undefined }) });
1099
+ decisions.push({
1100
+ incidentId: incidentId,
1101
+ action: action,
1102
+ recordToSeed: action === IncidentScopeAddedPagesNotificationAction.Queue
1103
+ ? IncidentScopeAddedPagesNotification.getRecordToSeedOnQueue({
1104
+ statusPagesNotifiedOnCreation: incident.statusPagesNotifiedOnCreation,
1105
+ statusPageIdsBeforeUpdate: incident.statusPages,
1106
+ })
1107
+ : undefined,
1108
+ });
1109
+ }
1110
+ this.queueCreatedNotificationForAddedStatusPagesIfRequested({
1111
+ updateBy: updateBy,
1112
+ decisions: decisions,
1113
+ carryForward: carryForward,
1114
+ });
1115
+ }
1116
+ /*
1117
+ * The pages an update writing `statusPageIds` adds to at least one of the
1118
+ * incidents it matches.
1119
+ */
1120
+ getStatusPageIdsAddedToAny(data) {
1121
+ const added = [];
1122
+ for (const incident of data.incidents) {
1123
+ for (const id of IncidentScopeAddedPagesNotification.getScopeChange({
1124
+ before: incident.statusPages,
1125
+ after: data.statusPageIds,
1126
+ }).addedStatusPageIds) {
1127
+ if (!added.includes(id)) {
1128
+ added.push(id);
1129
+ }
1130
+ }
1131
+ }
1132
+ return added;
1133
+ }
1134
+ /*
1135
+ * Adding status pages to an incident's scope can tell them the incident was
1136
+ * created: with IncidentScopeAddedPagesNotification requested, the 'created'
1137
+ * notification goes back to Pending, and the job sends it to the pages it
1138
+ * has no record of telling (Incident.statusPagesNotifiedOnCreation). See
1139
+ * IncidentScopeAddedPagesNotification.getAction for when it applies.
1140
+ *
1141
+ * A notification that was never sent has no record yet, so the pages the
1142
+ * incident was limited to before are written in as the record in the same
1143
+ * write (getRecordToSeedOnQueue): the job then tells only the added pages.
1144
+ *
1145
+ * An update that sets the status itself - the API route of resetting it to
1146
+ * Pending, the notify-on-create flag, or publishing a hidden incident - is
1147
+ * left alone. An update that matches several incidents queues only when it
1148
+ * may for every one of them, because the write applies the same data to
1149
+ * all. For the same reason it cannot write a record that differs between
1150
+ * them, or overwrite the record of an incident that has one, and is refused
1151
+ * instead.
1152
+ */
1153
+ queueCreatedNotificationForAddedStatusPagesIfRequested(data) {
1154
+ var _a;
1155
+ const updateBy = data.updateBy;
1156
+ if (!IncidentScopeAddedPagesNotification.isRequested(updateBy.miscDataProps)) {
1157
+ return;
1158
+ }
1159
+ if (updateBy.data.subscriberNotificationStatusOnIncidentCreated !== undefined) {
1160
+ return;
1161
+ }
1162
+ const actions = data.decisions.map((decision) => {
1163
+ return decision.action;
1164
+ });
1165
+ if (!actions.includes(IncidentScopeAddedPagesNotificationAction.Queue)) {
1166
+ return;
1167
+ }
1168
+ const everyIncidentMayQueue = actions.every((action) => {
1169
+ return (action === IncidentScopeAddedPagesNotificationAction.Queue ||
1170
+ action === IncidentScopeAddedPagesNotificationAction.AlreadyQueued);
1171
+ });
1172
+ if (!everyIncidentMayQueue) {
1173
+ logger.debug(`Not queueing the incident created notification for added status pages: ${actions.length} incident(s) matched and not all of them gained status pages and may be announced.`);
1174
+ return;
1175
+ }
1176
+ const recordsToSeed = data.decisions
1177
+ .map((decision) => {
1178
+ return decision.recordToSeed;
1179
+ })
1180
+ .filter((record) => {
1181
+ return record !== undefined;
1182
+ });
1183
+ if (recordsToSeed.length > 0) {
1184
+ const recordToSeed = recordsToSeed[0];
1185
+ const everyIncidentTakesTheSameRecord = recordsToSeed.length === data.decisions.length &&
1186
+ recordsToSeed.every((record) => {
1187
+ return ([...record].sort().join(",") === [...recordToSeed].sort().join(","));
1188
+ });
1189
+ if (!everyIncidentTakesTheSameRecord) {
1190
+ throw new BadDataException("These incidents cannot be sent the incident-created notification for their added status pages together: they were limited to different status pages, or not all of them were ever announced. Change them one at a time.");
1191
+ }
1192
+ updateBy.data.statusPagesNotifiedOnCreation = recordToSeed;
1193
+ }
1194
+ updateBy.data.subscriberNotificationStatusOnIncidentCreated =
1195
+ StatusPageSubscriberNotificationStatus.Pending;
1196
+ updateBy.data.subscriberNotificationStatusMessage =
1197
+ IncidentScopeAddedPagesNotification.queuedMessage;
1198
+ for (const decision of data.decisions) {
1199
+ const scopeChange = (_a = data.carryForward[decision.incidentId]) === null || _a === void 0 ? void 0 : _a.statusPageScopeChange;
1200
+ if (scopeChange &&
1201
+ decision.action === IncidentScopeAddedPagesNotificationAction.Queue) {
1202
+ scopeChange.notificationQueued = true;
1203
+ }
1204
+ }
1205
+ }
1206
+ /*
1207
+ * An update that added pages while the 'created' notification was Pending
1208
+ * or being sent left the status alone: the queued send reads the scope when
1209
+ * it goes out, and a running send reads it again once it has finished (see
1210
+ * the Incident:SendNotificationToSubscribers job). One case slips between
1211
+ * the two: the whole send started after this update read the status and
1212
+ * finished before it wrote the pages. Once the pages are written, this
1213
+ * checks for exactly that - the send finished, and an added page is not in
1214
+ * its record - and queues the notification again for the pages it missed.
1215
+ *
1216
+ * Never throws: the update is already written.
1217
+ */
1218
+ async requeueCreatedNotificationIfAddedPagesWereMissed(data) {
1219
+ var _a, _b;
1220
+ if (!((_a = data.change) === null || _a === void 0 ? void 0 : _a.notificationAlreadyQueued) ||
1221
+ data.change.addedStatusPageIds.length === 0) {
1222
+ return;
1223
+ }
1224
+ try {
1225
+ const incident = await this.findOneById({
1226
+ id: data.incidentId,
1227
+ select: {
1228
+ subscriberNotificationStatusOnIncidentCreated: true,
1229
+ statusPagesNotifiedOnCreation: true,
1230
+ },
1231
+ props: {
1232
+ isRoot: true,
1233
+ },
1234
+ });
1235
+ if ((incident === null || incident === void 0 ? void 0 : incident.subscriberNotificationStatusOnIncidentCreated) !==
1236
+ StatusPageSubscriberNotificationStatus.Success) {
1237
+ // Still on its way (it will see the pages), or settled otherwise.
1238
+ return;
1239
+ }
1240
+ const recorded = IncidentScopeAddedPagesNotification.getRecordedStatusPageIds(incident.statusPagesNotifiedOnCreation) || [];
1241
+ const missed = data.change.addedStatusPageIds.some((id) => {
1242
+ return !recorded.includes(id);
1243
+ });
1244
+ if (!missed) {
1245
+ return;
1246
+ }
1247
+ await this.updateOneById({
1248
+ id: data.incidentId,
1249
+ data: {
1250
+ subscriberNotificationStatusOnIncidentCreated: StatusPageSubscriberNotificationStatus.Pending,
1251
+ subscriberNotificationStatusMessage: IncidentScopeAddedPagesNotification.queuedMessage,
1252
+ },
1253
+ props: {
1254
+ isRoot: true,
1255
+ ignoreHooks: true,
1256
+ },
1257
+ });
1258
+ }
1259
+ catch (err) {
1260
+ logger.error(`Failed to check whether the incident created notification reached the status pages added to the incident: ${err}`, {
1261
+ incidentId: (_b = data.incidentId) === null || _b === void 0 ? void 0 : _b.toString(),
1262
+ });
1263
+ }
1264
+ }
1265
+ /*
1266
+ * The pages the matched incidents are scoped to that the caller cannot
1267
+ * read, which a list write from them must keep (see
1268
+ * applyStatusPageScopeToUpdate). A bulk update writes the same list onto
1269
+ * every incident it matches, so it can only keep them when every matched
1270
+ * incident holds the same hidden pages; otherwise it would scope some of
1271
+ * them to pages they were never scoped to, and it is refused.
1272
+ */
1273
+ async getScopedStatusPageIdsHiddenFromCaller(data) {
1274
+ const heldByIncident = data.incidents.map((incident) => {
1275
+ return IncidentScopeAddedPagesNotification.normalizeStatusPageIds(incident.statusPages);
1276
+ });
1277
+ const heldIds = IncidentScopeAddedPagesNotification.normalizeStatusPageIds(heldByIncident.flat());
1278
+ if (heldIds.length === 0) {
1279
+ return [];
1280
+ }
1281
+ const readableIds = await StatusPageReadAccess.getReadableStatusPageIds({
1282
+ statusPageIds: heldIds,
1283
+ props: data.props,
1284
+ });
1285
+ const hiddenByIncident = heldByIncident.map((held) => {
1286
+ return held
1287
+ .filter((id) => {
1288
+ return !readableIds.includes(id);
1289
+ })
1290
+ .sort();
1291
+ });
1292
+ const hiddenIds = hiddenByIncident[0] || [];
1293
+ const everyIncidentHidesTheSame = hiddenByIncident.every((hidden) => {
1294
+ return hidden.join(",") === hiddenIds.join(",");
1295
+ });
1296
+ if (!everyIncidentHidesTheSame) {
1297
+ throw new BadDataException("These incidents are limited to different status pages that you do not have access to, so their status pages cannot be changed together. Change them one at a time.");
1298
+ }
1299
+ return hiddenIds;
1300
+ }
1301
+ toStatusPageStubs(statusPageIds) {
1302
+ return statusPageIds.map((statusPageId) => {
1303
+ const statusPage = new StatusPage();
1304
+ statusPage._id = statusPageId;
1305
+ return statusPage;
1306
+ });
1307
+ }
1308
+ // A column's value once an update is written: the update's, else the stored.
1309
+ getValueAfterUpdate(updatedValue, storedValue) {
1310
+ if (updatedValue !== undefined && updatedValue !== null) {
1311
+ return updatedValue;
1312
+ }
1313
+ return storedValue;
1314
+ }
420
1315
  /*
421
1316
  * An update can repoint an incident at another project's state, severity or
422
1317
  * monitor status just as easily as a create can, and the result is the same:
@@ -533,6 +1428,16 @@ export class Service extends DatabaseService {
533
1428
  modelName: "On-Call Policy",
534
1429
  service: OnCallDutyPolicyService,
535
1430
  },
1431
+ /*
1432
+ * The status pages the incident is limited to. Another project's page
1433
+ * here would put that project's page name into this incident's feed and
1434
+ * scope it to a page it can never show on.
1435
+ */
1436
+ {
1437
+ column: "statusPages",
1438
+ modelName: "Status Page",
1439
+ service: StatusPageService,
1440
+ },
536
1441
  ...getAffectedResourceRelations(this.getModel()),
537
1442
  ];
538
1443
  }
@@ -567,6 +1472,20 @@ export class Service extends DatabaseService {
567
1472
  false;
568
1473
  }
569
1474
  const projectId = createBy.props.tenantId || createBy.data.projectId;
1475
+ /*
1476
+ * The values the caller sent, before a template or a mapping adds any:
1477
+ * those are not the caller's to get wrong.
1478
+ */
1479
+ await this.validateCustomFieldValuesOnCreate({
1480
+ createBy: createBy,
1481
+ projectId: projectId,
1482
+ });
1483
+ /*
1484
+ * Status pages the caller picked, as opposed to ones copied from a
1485
+ * template below (see applyStatusPageScopeToCreate).
1486
+ */
1487
+ const statusPagesFromCaller = createBy.data.statusPages !== undefined &&
1488
+ createBy.data.statusPages !== null;
570
1489
  /*
571
1490
  * Declaring the incident from alerts. The alert ids are checked here,
572
1491
  * before the incident number is taken and before anything is written, so
@@ -626,6 +1545,8 @@ export class Service extends DatabaseService {
626
1545
  }
627
1546
  // Determine the initial incident state
628
1547
  let initialIncidentStateId = undefined;
1548
+ // Declared from a template whose status pages were all deleted.
1549
+ let isScopedToNothingByTemplate = false;
629
1550
  // If currentIncidentStateId is already provided (manual selection), use it
630
1551
  if (createBy.data.currentIncidentStateId) {
631
1552
  initialIncidentStateId = createBy.data.currentIncidentStateId;
@@ -676,6 +1597,9 @@ export class Service extends DatabaseService {
676
1597
  services: { _id: true },
677
1598
  onCallDutyPolicies: { _id: true },
678
1599
  labels: { _id: true },
1600
+ statusPages: { _id: true },
1601
+ isScopedToStatusPages: true,
1602
+ customFields: true,
679
1603
  },
680
1604
  props: {
681
1605
  isRoot: true,
@@ -782,8 +1706,43 @@ export class Service extends DatabaseService {
782
1706
  createBy.data.labels = stubs;
783
1707
  }
784
1708
  }
1709
+ // Applying a template that has status pages scopes the incident.
1710
+ if (createBy.data.statusPages === undefined) {
1711
+ const stubs = stubBy(StatusPage, incidentTemplate.statusPages);
1712
+ if (stubs && stubs.length > 0) {
1713
+ createBy.data.statusPages = stubs;
1714
+ }
1715
+ else if (incidentTemplate.isScopedToStatusPages) {
1716
+ /*
1717
+ * A template limited to status pages that have all been deleted
1718
+ * since. Its incidents stay limited - to nothing - like an
1719
+ * incident whose pages were deleted, rather than reaching every
1720
+ * page that lists their monitors.
1721
+ */
1722
+ isScopedToNothingByTemplate = true;
1723
+ }
1724
+ }
1725
+ /*
1726
+ * The template's custom field values fill in the fields the caller
1727
+ * left out; a value the caller sent always wins. Merged, not
1728
+ * replaced, so the caller's own values are never dropped. They are
1729
+ * the template's, so the value check above (the caller's values
1730
+ * only) does not see them, and the mapping below still has the last
1731
+ * word on a mapped field.
1732
+ */
1733
+ const customFieldsWithTemplate = mergeTemplateCustomFields({
1734
+ templateCustomFields: incidentTemplate.customFields,
1735
+ customFields: createBy.data.customFields,
1736
+ });
1737
+ if (customFieldsWithTemplate) {
1738
+ createBy.data.customFields = customFieldsWithTemplate;
1739
+ }
785
1740
  }
786
1741
  }
1742
+ this.applyStatusPageScopeToCreate({
1743
+ createBy: createBy,
1744
+ isScopedToNothingByTemplate: isScopedToNothingByTemplate,
1745
+ });
787
1746
  // If no custom state is provided or found, fall back to default created state
788
1747
  if (!initialIncidentStateId) {
789
1748
  const incidentState = await IncidentStateService.findOneBy({
@@ -859,6 +1818,12 @@ export class Service extends DatabaseService {
859
1818
  subject: "incident",
860
1819
  serviceLevelObjectives: createBy.data.serviceLevelObjectives,
861
1820
  });
1821
+ // Before the counter increment too, like the checks above.
1822
+ await this.assertCallerCanPickStatusPagesOnCreate({
1823
+ createBy: createBy,
1824
+ projectId: projectId,
1825
+ statusPagesFromCaller: statusPagesFromCaller,
1826
+ });
862
1827
  const incidentCounterResult = await ProjectService.incrementAndGetIncidentCounter(projectId);
863
1828
  createBy.data.currentIncidentStateId = initialIncidentStateId;
864
1829
  createBy.data.incidentNumber = incidentCounterResult.counter;
@@ -964,6 +1929,8 @@ export class Service extends DatabaseService {
964
1929
  * The resources named under "Resources Affected" are read by the feed
965
1930
  * builder itself (LinkedAffectedResources), one relation at a time.
966
1931
  */
1932
+ // The created feed item names the status pages a scoped incident is limited to.
1933
+ isScopedToStatusPages: true,
967
1934
  },
968
1935
  props: {
969
1936
  isRoot: true,
@@ -1492,6 +2459,37 @@ export class Service extends DatabaseService {
1492
2459
  throw error;
1493
2460
  }
1494
2461
  }
2462
+ /*
2463
+ * The status pages a scoped incident is limited to, as a Markdown list for
2464
+ * its created feed item. Read on their own rather than in onCreateSuccess's
2465
+ * select: a find that selects several many-to-many lists returns a row for
2466
+ * every combination of them.
2467
+ */
2468
+ async getScopedStatusPagesMarkdown(incident) {
2469
+ const incidentWithStatusPages = await this.findOneById({
2470
+ id: incident.id,
2471
+ select: {
2472
+ statusPages: {
2473
+ _id: true,
2474
+ name: true,
2475
+ },
2476
+ },
2477
+ props: {
2478
+ isRoot: true,
2479
+ },
2480
+ });
2481
+ const statusPages = (incidentWithStatusPages === null || incidentWithStatusPages === void 0 ? void 0 : incidentWithStatusPages.statusPages) || [];
2482
+ if (statusPages.length === 0) {
2483
+ // Scoped to pages that have all been deleted since: hidden everywhere.
2484
+ return `- None: the status pages it was limited to have been deleted, so it is not shown on any status page.\n`;
2485
+ }
2486
+ let markdown = "";
2487
+ for (const statusPage of statusPages) {
2488
+ // A page name is free text: kept from turning into a link or an image.
2489
+ markdown += `- [${escapeMarkdownInline(statusPage.name || "Untitled status page")}](${(await StatusPageService.getStatusPageLinkInDashboard(incident.projectId, statusPage.id)).toString()})\n`;
2490
+ }
2491
+ return markdown;
2492
+ }
1495
2493
  async createIncidentFeedAsync(incident) {
1496
2494
  var _a, _b, _c, _d, _e, _f, _g;
1497
2495
  try {
@@ -1534,6 +2532,11 @@ ${incident.description || "No description provided."}
1534
2532
  }
1535
2533
  feedInfoInMarkdown += `\n\n`;
1536
2534
  }
2535
+ if (incident.isScopedToStatusPages) {
2536
+ feedInfoInMarkdown += `📣 **Limited to Status Pages**:\n`;
2537
+ feedInfoInMarkdown += await this.getScopedStatusPagesMarkdown(incident);
2538
+ feedInfoInMarkdown += `\n\n`;
2539
+ }
1537
2540
  if (incident.rootCause) {
1538
2541
  feedInfoInMarkdown += `\n
1539
2542
  📄 **Root Cause**:
@@ -1812,7 +2815,7 @@ ${incident.remediationNotes || "No remediation notes provided."}
1812
2815
  return URL.fromString(dashboardUrl.toString()).addRoute(`/${projectId.toString()}/incidents/${incidentId.toString()}`);
1813
2816
  }
1814
2817
  async onUpdateSuccess(onUpdate, updatedItemIds) {
1815
- var _a, _b, _c, _d, _e;
2818
+ var _a, _b, _c, _d;
1816
2819
  CustomFieldMappingService.restampAfterMultiRowUpdate({
1817
2820
  definitionModelType: IncidentCustomField,
1818
2821
  updateBy: onUpdate.updateBy,
@@ -2241,8 +3244,6 @@ ${incidentSeverity.name}
2241
3244
  isRoot: true,
2242
3245
  },
2243
3246
  });
2244
- // change these monitors back to operational state.
2245
- await this.markMonitorsActiveForMonitoring(projectId, incidentCarryForward.monitorsRemoved);
2246
3247
  feedInfoInMarkdown += `\n\n**🗑️ Monitors Removed**:\n`;
2247
3248
  for (const monitor of monitorsRemoved) {
2248
3249
  feedInfoInMarkdown += `- [${monitor.name}](${(await MonitorService.getMonitorLinkInDashboard(projectId, monitor.id)).toString()})\n`;
@@ -2273,8 +3274,23 @@ ${incidentSeverity.name}
2273
3274
  }
2274
3275
  shouldAddIncidentFeed = true;
2275
3276
  }
3277
+ const statusPageScopeMarkdown = await this.getStatusPageScopeFeedMarkdown({
3278
+ projectId: projectId,
3279
+ incidentId: incidentId,
3280
+ change: incidentCarryForward.statusPageScopeChange,
3281
+ });
3282
+ if (statusPageScopeMarkdown) {
3283
+ feedInfoInMarkdown += statusPageScopeMarkdown;
3284
+ shouldAddIncidentFeed = true;
3285
+ }
3286
+ await this.requeueCreatedNotificationIfAddedPagesWereMissed({
3287
+ incidentId: incidentId,
3288
+ change: incidentCarryForward.statusPageScopeChange,
3289
+ });
3290
+ // Saving the status the incident already had changes nothing.
2276
3291
  if (incidentCarryForward.oldChangeMonitorStatusIdTo &&
2277
- incidentCarryForward.newMonitorChangeStatusIdTo) {
3292
+ incidentCarryForward.newMonitorChangeStatusIdTo &&
3293
+ this.isMonitorStatusChangedByUpdate(incidentCarryForward)) {
2278
3294
  const oldMonitorStatus = await MonitorStatusService.findOneBy({
2279
3295
  query: {
2280
3296
  _id: incidentCarryForward.oldChangeMonitorStatusIdTo,
@@ -2302,33 +3318,13 @@ ${incidentSeverity.name}
2302
3318
  shouldAddIncidentFeed = true;
2303
3319
  }
2304
3320
  }
2305
- const changeNewMonitorStatusTo = incidentCarryForward.newMonitorChangeStatusIdTo ||
2306
- incidentCarryForward.oldChangeMonitorStatusIdTo;
2307
- if (((_e = incidentCarryForward.monitorsAdded) === null || _e === void 0 ? void 0 : _e.length) > 0) {
2308
- await this.disableActiveMonitoringIfManualIncident(incidentId);
2309
- }
2310
- if (changeNewMonitorStatusTo) {
2311
- const incident = await this.findOneById({
2312
- id: incidentId,
2313
- select: {
2314
- projectId: true,
2315
- monitors: {
2316
- _id: true,
2317
- },
2318
- },
2319
- props: {
2320
- isRoot: true,
2321
- },
2322
- });
2323
- const monitorsForThisIncident = (incident === null || incident === void 0 ? void 0 : incident.monitors) || [];
2324
- await MonitorService.changeMonitorStatus(projectId, monitorsForThisIncident.map((monitor) => {
2325
- var _a;
2326
- return new ObjectID(((_a = monitor._id) === null || _a === void 0 ? void 0 : _a.toString()) || "");
2327
- }), changeNewMonitorStatusTo, true, // notifyMonitorOwners
2328
- "Status was changed because Incident " +
2329
- incidentNumberDisplay +
2330
- " was updated.", undefined, onUpdate.updateBy.props);
2331
- }
3321
+ await this.updateMonitorsForIncidentEdit({
3322
+ projectId: projectId,
3323
+ incidentId: incidentId,
3324
+ incidentNumberDisplay: incidentNumberDisplay,
3325
+ carryForward: incidentCarryForward,
3326
+ props: onUpdate.updateBy.props,
3327
+ });
2332
3328
  }
2333
3329
  }
2334
3330
  if (shouldAddIncidentFeed) {
@@ -2348,6 +3344,189 @@ ${incidentSeverity.name}
2348
3344
  }
2349
3345
  return onUpdate;
2350
3346
  }
3347
+ /*
3348
+ * Whether an update puts the incident's monitors in a different status
3349
+ * from the one it held: it writes a status, and not the same one again.
3350
+ */
3351
+ isMonitorStatusChangedByUpdate(carryForward) {
3352
+ var _a;
3353
+ if (!carryForward.newMonitorChangeStatusIdTo) {
3354
+ return false;
3355
+ }
3356
+ return (carryForward.newMonitorChangeStatusIdTo.toString().toLowerCase() !==
3357
+ (((_a = carryForward.oldChangeMonitorStatusIdTo) === null || _a === void 0 ? void 0 : _a.toString()) || "").toLowerCase());
3358
+ }
3359
+ /*
3360
+ * What an edit of an incident's monitors, or of the status it puts them
3361
+ * in, does to the monitors themselves. The feed item records the edit
3362
+ * either way; this only decides which monitors change.
3363
+ *
3364
+ * The monitors taken off the incident are restored, unless another open
3365
+ * incident still holds them (markMonitorsActiveForMonitoring), when the
3366
+ * incident was open before the update. That includes an update that
3367
+ * resolves it as well: resolving restores only the monitors it still
3368
+ * holds (IncidentStateTimelineService), so this is the only restore the
3369
+ * ones taken off get. A monitor taken off an incident that was resolved
3370
+ * already was restored when it resolved, and restoring it again could
3371
+ * overwrite a status set since (maintenance, or a manual monitor's status
3372
+ * set by hand).
3373
+ *
3374
+ * A resolved incident, as it stands after the update, does nothing else
3375
+ * to its monitors. Nothing would clear what it did: an added monitor of a
3376
+ * manual incident would never be probed again, and the incident's status
3377
+ * would sit on its monitors as false downtime.
3378
+ *
3379
+ * An open incident:
3380
+ * - stops probing the monitors of a manual incident when one is added,
3381
+ * as creating it did (disableActiveMonitoringIfManualIncident);
3382
+ * - puts the monitors added in its status, and all of its monitors only
3383
+ * when the edit changes that status. Every save used to put all of them
3384
+ * in it again, overwriting a status a probe had set since.
3385
+ */
3386
+ async updateMonitorsForIncidentEdit(data) {
3387
+ const carryForward = data.carryForward;
3388
+ if (carryForward.monitorsRemoved.length > 0 &&
3389
+ !carryForward.isResolvedBeforeUpdate) {
3390
+ // change these monitors back to operational state.
3391
+ await this.markMonitorsActiveForMonitoring(data.projectId, carryForward.monitorsRemoved);
3392
+ }
3393
+ const isMonitorStatusChanged = this.isMonitorStatusChangedByUpdate(carryForward);
3394
+ if (carryForward.monitorsAdded.length === 0 && !isMonitorStatusChanged) {
3395
+ return;
3396
+ }
3397
+ /*
3398
+ * Read after the update is written, so an edit that resolves the
3399
+ * incident as well counts as resolved: changing the state restored the
3400
+ * monitors it holds, the added ones included.
3401
+ */
3402
+ if (await this.isIncidentResolved({ incidentId: data.incidentId })) {
3403
+ return;
3404
+ }
3405
+ if (carryForward.monitorsAdded.length > 0) {
3406
+ await this.disableActiveMonitoringIfManualIncident(data.incidentId);
3407
+ }
3408
+ // The status the incident puts its monitors in after the update.
3409
+ const monitorStatusIdToApply = carryForward.isChangeMonitorStatusToCleared
3410
+ ? undefined
3411
+ : carryForward.newMonitorChangeStatusIdTo ||
3412
+ carryForward.oldChangeMonitorStatusIdTo;
3413
+ if (!monitorStatusIdToApply ||
3414
+ (!isMonitorStatusChanged && carryForward.monitorsAdded.length === 0)) {
3415
+ return;
3416
+ }
3417
+ const addedMonitorIds = carryForward.monitorsAdded.map((monitor) => {
3418
+ return this.getMonitorIdForComparison(monitor);
3419
+ });
3420
+ /*
3421
+ * The monitors the incident holds now, so a status is only ever put on
3422
+ * a monitor the update left on it.
3423
+ */
3424
+ const incident = await this.findOneById({
3425
+ id: data.incidentId,
3426
+ select: {
3427
+ monitors: {
3428
+ _id: true,
3429
+ },
3430
+ },
3431
+ props: {
3432
+ isRoot: true,
3433
+ },
3434
+ });
3435
+ const monitorIdsToChange = ((incident === null || incident === void 0 ? void 0 : incident.monitors) || [])
3436
+ .filter((monitor) => {
3437
+ return (isMonitorStatusChanged ||
3438
+ addedMonitorIds.includes(this.getMonitorIdForComparison(monitor)));
3439
+ })
3440
+ .map((monitor) => {
3441
+ var _a;
3442
+ return new ObjectID(((_a = monitor._id) === null || _a === void 0 ? void 0 : _a.toString()) || "");
3443
+ });
3444
+ if (monitorIdsToChange.length === 0) {
3445
+ return;
3446
+ }
3447
+ await MonitorService.changeMonitorStatus(data.projectId, monitorIdsToChange, monitorStatusIdToApply, true, // notifyMonitorOwners
3448
+ "Status was changed because Incident " +
3449
+ data.incidentNumberDisplay +
3450
+ " was updated.", undefined, data.props);
3451
+ }
3452
+ /*
3453
+ * The part of an update's feed item that records a change of the status
3454
+ * pages the incident is limited to: the pages added and removed, whether
3455
+ * the incident is now limited at all, and whether the added pages will be
3456
+ * sent the 'created' notification. Empty when the scope did not change.
3457
+ *
3458
+ * Page names are read as root, like the monitor names above. The pages were
3459
+ * validated as this project's when they were written, and the read is
3460
+ * filtered on the project anyway. Never throws: the update is already
3461
+ * written, and a missing line in the feed must not turn it into an error.
3462
+ */
3463
+ async getStatusPageScopeFeedMarkdown(data) {
3464
+ var _a, _b;
3465
+ const change = data.change;
3466
+ if (!change ||
3467
+ (change.addedStatusPageIds.length === 0 &&
3468
+ change.removedStatusPageIds.length === 0)) {
3469
+ return "";
3470
+ }
3471
+ try {
3472
+ const statusPages = await StatusPageService.findBy({
3473
+ query: {
3474
+ _id: QueryHelper.any([
3475
+ ...change.addedStatusPageIds,
3476
+ ...change.removedStatusPageIds,
3477
+ ]),
3478
+ projectId: data.projectId,
3479
+ },
3480
+ select: {
3481
+ _id: true,
3482
+ name: true,
3483
+ },
3484
+ limit: LIMIT_MAX,
3485
+ skip: 0,
3486
+ props: {
3487
+ isRoot: true,
3488
+ },
3489
+ });
3490
+ const statusPageLines = async (ids) => {
3491
+ let lines = "";
3492
+ for (const id of ids) {
3493
+ const statusPage = statusPages.find((page) => {
3494
+ var _a;
3495
+ return ((_a = page.id) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase()) === id;
3496
+ });
3497
+ if (!statusPage) {
3498
+ // Deleted since: its name is gone with it.
3499
+ lines += `- A deleted status page\n`;
3500
+ continue;
3501
+ }
3502
+ // A page name is free text: kept from turning into a link or an image.
3503
+ lines += `- [${escapeMarkdownInline(statusPage.name || "Untitled status page")}](${(await StatusPageService.getStatusPageLinkInDashboard(data.projectId, statusPage.id)).toString()})\n`;
3504
+ }
3505
+ return lines;
3506
+ };
3507
+ let markdown = "";
3508
+ if (change.addedStatusPageIds.length > 0) {
3509
+ markdown += `\n\n**📣 Status Pages Added**:\n${await statusPageLines(change.addedStatusPageIds)}`;
3510
+ }
3511
+ if (change.removedStatusPageIds.length > 0) {
3512
+ markdown += `\n\n**🔕 Status Pages Removed**:\n${await statusPageLines(change.removedStatusPageIds)}`;
3513
+ }
3514
+ markdown += change.isScoped
3515
+ ? `\n\nThis incident is shown on, and notifies the subscribers of, only its selected status pages that list its monitors.\n`
3516
+ : `\n\nThis incident is no longer limited to specific status pages: it is shown on every status page that lists its monitors, except pages that only show incidents limited to them.\n`;
3517
+ if (change.notificationQueued) {
3518
+ markdown += `\nSubscribers of the added status pages will be sent the notification that this incident was created.\n`;
3519
+ }
3520
+ return markdown;
3521
+ }
3522
+ catch (err) {
3523
+ logger.error(`Failed to describe the status page scope change in the incident feed: ${err}`, {
3524
+ projectId: (_a = data.projectId) === null || _a === void 0 ? void 0 : _a.toString(),
3525
+ incidentId: (_b = data.incidentId) === null || _b === void 0 ? void 0 : _b.toString(),
3526
+ });
3527
+ return "";
3528
+ }
3529
+ }
2351
3530
  async doesMonitorHasMoreActiveManualIncidents(monitorId, proojectId) {
2352
3531
  const resolvedState = await IncidentStateService.findOneBy({
2353
3532
  query: {