@oneuptime/common 12.0.13 → 12.0.14

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 (376) hide show
  1. package/Models/DatabaseModels/OnCallDutyPolicySchedule.ts +14 -0
  2. package/Models/DatabaseModels/UserCall.ts +94 -3
  3. package/Models/DatabaseModels/UserEmail.ts +94 -3
  4. package/Models/DatabaseModels/UserIncomingCallNumber.ts +94 -3
  5. package/Models/DatabaseModels/UserPush.ts +37 -0
  6. package/Models/DatabaseModels/UserSMS.ts +94 -3
  7. package/Models/DatabaseModels/UserWhatsApp.ts +93 -2
  8. package/Server/API/BaseAPI.ts +79 -14
  9. package/Server/API/UserCallAPI.ts +53 -45
  10. package/Server/API/UserEmailAPI.ts +53 -44
  11. package/Server/API/UserIncomingCallNumberAPI.ts +48 -38
  12. package/Server/API/UserNotificationMethodAdminAPI.ts +481 -0
  13. package/Server/API/UserPushAPI.ts +126 -2
  14. package/Server/API/UserSmsAPI.ts +53 -44
  15. package/Server/API/UserWhatsAppAPI.ts +53 -50
  16. package/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.ts +154 -0
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.ts +17 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.ts +45 -0
  19. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
  20. package/Server/Middleware/VerificationCodeRateLimit.ts +586 -0
  21. package/Server/Services/AnalyticsDatabaseService.ts +169 -0
  22. package/Server/Services/DatabaseService.ts +101 -0
  23. package/Server/Services/LogAggregationService.ts +5 -0
  24. package/Server/Services/PushNotificationService.ts +127 -12
  25. package/Server/Services/TeamMemberService.ts +53 -13
  26. package/Server/Services/UserCallService.ts +55 -24
  27. package/Server/Services/UserEmailService.ts +83 -17
  28. package/Server/Services/UserIncomingCallNumberService.ts +49 -85
  29. package/Server/Services/UserNotificationMethodAdminService.ts +1527 -0
  30. package/Server/Services/UserNotificationRuleService.ts +26 -0
  31. package/Server/Services/UserPushService.ts +89 -0
  32. package/Server/Services/UserSmsService.ts +50 -17
  33. package/Server/Services/UserWhatsAppService.ts +48 -15
  34. package/Server/Types/Database/QueryHelper.ts +30 -0
  35. package/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.ts +59 -0
  36. package/Server/Utils/ChannelVerification.ts +510 -0
  37. package/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.ts +13 -16
  38. package/Server/Utils/Monitor/MonitorAlert.ts +24 -21
  39. package/Server/Utils/Monitor/MonitorIncident.ts +21 -18
  40. package/Server/Utils/Monitor/MonitorResourceContext.ts +107 -0
  41. package/Server/Utils/Monitor/MonitorStepResourceIdentity.ts +442 -0
  42. package/Server/Utils/Monitor/SeriesResourceLabels.ts +3 -3
  43. package/Server/Utils/Monitor/SeriesResourceLinker.ts +96 -28
  44. package/Server/Utils/TotpAuth.ts +137 -9
  45. package/Server/Utils/UserRegistrationToken.ts +182 -0
  46. package/Server/Utils/VerificationCode.ts +134 -0
  47. package/Tests/App/Dashboard/AdminNotificationRulesPage.test.tsx +173 -94
  48. package/Tests/App/Dashboard/AdminUserNotificationMethodsPage.test.tsx +1151 -0
  49. package/Tests/App/Dashboard/AdminUserOnCallPages.test.tsx +905 -0
  50. package/Tests/App/Dashboard/DashboardCommandPalette.test.tsx +338 -0
  51. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1 -1
  52. package/Tests/App/Dashboard/MonitorTypePicker.test.tsx +28 -0
  53. package/Tests/Models/UserPushCriticalAlertColumn.test.ts +172 -0
  54. package/Tests/Server/API/BaseAPIGetListParallel.test.ts +519 -0
  55. package/Tests/Server/API/NotificationChannelVerificationAPI.test.ts +543 -0
  56. package/Tests/Server/API/UserIncomingCallNumberApi.test.ts +108 -18
  57. package/Tests/Server/API/UserNotificationMethodAdminAPI.test.ts +963 -0
  58. package/Tests/Server/API/UserPushCriticalAlertsApi.test.ts +114 -0
  59. package/Tests/Server/API/UserSmsApi.test.ts +107 -14
  60. package/Tests/Server/API/UserTotpAuthAPI.test.ts +427 -0
  61. package/Tests/Server/Infrastructure/Postgres/FixTotpOtpUrlAlgorithmMigration.test.ts +315 -0
  62. package/Tests/Server/Middleware/VerificationCodeRateLimit.test.ts +775 -0
  63. package/Tests/Server/Services/AddNetworkDeviceReachabilityColumnsMigration.test.ts +10 -62
  64. package/Tests/Server/Services/AnalyticsDatabasePaginationStability.test.ts +33 -13
  65. package/Tests/Server/Services/AnalyticsDatabaseSortKeyBoundary.test.ts +658 -0
  66. package/Tests/Server/Services/CriticalOnCallAlertDelivery.test.ts +458 -0
  67. package/Tests/Server/Services/CriticalPushAlertPayload.test.ts +301 -0
  68. package/Tests/Server/Services/DatabaseServiceAtomicIncrement.test.ts +143 -0
  69. package/Tests/Server/Services/DeliverNotificationForRuleExtraction.test.ts +1 -0
  70. package/Tests/Server/Services/LogAggregationScanMemory.test.ts +421 -0
  71. package/Tests/Server/Services/LogAggregationService.test.ts +2 -2
  72. package/Tests/Server/Services/NotificationChannelCodeIssuance.test.ts +401 -0
  73. package/Tests/Server/Services/PushNotificationDeliveryOptions.test.ts +204 -0
  74. package/Tests/Server/Services/TeamMemberAutoAcceptInvitation.test.ts +21 -1
  75. package/Tests/Server/Services/TeamMemberInviteRegistrationToken.test.ts +290 -0
  76. package/Tests/Server/Services/UserNotificationMethodAdminService.test.ts +948 -0
  77. package/Tests/Server/Services/UserNotificationRuleExecuteItem.test.ts +1 -0
  78. package/Tests/Server/Services/UserPushCriticalAlertToggle.test.ts +255 -0
  79. package/Tests/Server/Services/UserTotpAuthEnrolment.test.ts +218 -0
  80. package/Tests/Server/TestingUtils/AuthenticatorApp.ts +248 -0
  81. package/Tests/Server/Types/Database/Permissions/NotificationChannelVerificationColumns.test.ts +135 -0
  82. package/Tests/Server/Types/Database/Permissions/OnCallScheduleRelationSelect.test.ts +504 -0
  83. package/Tests/Server/Types/Database/QueryHelperFindWithSameTextAnyOf.test.ts +91 -0
  84. package/Tests/Server/Types/Workflow/Components/JsonToText.test.ts +384 -0
  85. package/Tests/Server/Types/Workflow/Components/MergeJson.test.ts +403 -0
  86. package/Tests/Server/Utils/Browser.test.ts +162 -0
  87. package/Tests/Server/Utils/ChannelVerification.test.ts +689 -0
  88. package/Tests/Server/Utils/Express.test.ts +371 -0
  89. package/Tests/Server/Utils/Monitor/Criteria/CustomCodeMonitorCriteria.test.ts +707 -0
  90. package/Tests/Server/Utils/Monitor/Criteria/DnsMonitorCriteria.test.ts +698 -0
  91. package/Tests/Server/Utils/Monitor/Criteria/IncomingEmailBodyCriteria.test.ts +243 -0
  92. package/Tests/Server/Utils/Monitor/Criteria/IncomingRequestBodyCriteria.test.ts +278 -0
  93. package/Tests/Server/Utils/Monitor/MonitorAlertResourceLinking.test.ts +160 -20
  94. package/Tests/Server/Utils/Monitor/MonitorDependencySuppressionCreatorSkip.test.ts +13 -8
  95. package/Tests/Server/Utils/Monitor/MonitorIncidentResourceLinking.test.ts +162 -18
  96. package/Tests/Server/Utils/Monitor/MonitorResourceContext.test.ts +349 -0
  97. package/Tests/Server/Utils/Monitor/MonitorStepResourceIdentity.test.ts +690 -0
  98. package/Tests/Server/Utils/Monitor/MonitorSummaryPersistence.test.ts +7 -2
  99. package/Tests/Server/Utils/Monitor/SeriesResourceLinker.test.ts +92 -18
  100. package/Tests/Server/Utils/PushNotificationUtilCreators.test.ts +267 -0
  101. package/Tests/Server/Utils/Telemetry/OneuptimeLabel.test.ts +439 -0
  102. package/Tests/Server/Utils/TotpAuth.test.ts +719 -0
  103. package/Tests/Server/Utils/UserRegistrationToken.test.ts +322 -0
  104. package/Tests/Server/Utils/VerificationCode.test.ts +296 -0
  105. package/Tests/Types/AutoRemediation/AutoRemediationSuggestionStatus.test.ts +192 -0
  106. package/Tests/Types/Call/CallRequest.test.ts +189 -0
  107. package/Tests/Types/Dashboard/DashboardSize.test.ts +226 -0
  108. package/Tests/Types/Incident/IncidentSlaStatus.test.ts +191 -0
  109. package/Tests/Types/Metrics/MetricDashboardMetricType.test.ts +278 -0
  110. package/Tests/Types/Metrics/MetricPipelineRuleType.test.ts +517 -0
  111. package/Tests/Types/Monitor/IncomingMonitorDefaultCriteria.test.ts +470 -0
  112. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +6 -4
  113. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCatalog.test.ts +262 -5
  114. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationCoverage.test.ts +1 -1
  115. package/Tests/Types/Monitor/Recommendation/MonitorRecommendationNotificationMode.test.ts +1 -1
  116. package/Tests/Types/Monitor/ServiceAlertTemplates.test.ts +905 -0
  117. package/Tests/Types/Service/ServiceLanguage.test.ts +255 -0
  118. package/Tests/Types/TextRandomGeneration.test.ts +211 -0
  119. package/Tests/UI/Components/Button.test.tsx +175 -1
  120. package/Tests/UI/Components/CodeBlockLanguages.test.tsx +236 -0
  121. package/Tests/UI/Components/CommandPalette/CommandPalette.test.tsx +568 -0
  122. package/Tests/UI/Components/CommandPalette/CommandPaletteKeyboard.test.tsx +239 -0
  123. package/Tests/UI/Components/CommandPalette/CommandPaletteProviders.test.tsx +400 -0
  124. package/Tests/UI/Components/CommandPalette/PaletteFilter.test.ts +234 -0
  125. package/Tests/UI/Components/CommandPalette/RecentCommands.test.ts +97 -0
  126. package/Tests/UI/Components/CountModelSideMenuItemGuard.test.tsx +198 -0
  127. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +1 -1
  128. package/Tests/UI/Components/Forms/Utils/FormFieldSchemaTypeUtil.test.ts +267 -0
  129. package/Tests/UI/Components/List.test.tsx +9 -2
  130. package/Tests/UI/Components/ListLoadingStates.test.tsx +173 -0
  131. package/Tests/UI/Components/MarkdownLazy.test.tsx +113 -0
  132. package/Tests/UI/Components/MarkdownMermaidRetry.test.tsx +110 -0
  133. package/Tests/UI/Components/ModelTable/useCustomFieldColumns.test.tsx +8 -0
  134. package/Tests/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.test.ts +692 -0
  135. package/Tests/UI/Components/MoreMenuMotion.test.tsx +118 -0
  136. package/Tests/UI/Components/NavBarCommandKGating.test.tsx +178 -0
  137. package/Tests/UI/Components/OrderedStatesList.test.tsx +19 -2
  138. package/Tests/UI/Components/SideOverMotion.test.tsx +109 -0
  139. package/Tests/UI/Components/Skeleton.test.tsx +71 -0
  140. package/Tests/UI/Components/TableLoadingStates.test.tsx +279 -0
  141. package/Tests/UI/Components/Tabs.test.tsx +24 -0
  142. package/Tests/UI/Components/Toast.test.tsx +130 -7
  143. package/Tests/UI/Components/ToastStacking.test.tsx +198 -0
  144. package/Tests/UI/Utils/Dropdown.test.ts +423 -0
  145. package/Tests/UI/Utils/ModelAPITenantHeader.test.ts +122 -0
  146. package/Tests/UI/Utils/ModelListCache.test.ts +338 -0
  147. package/Tests/UI/Utils/ProjectListCacheInvalidation.test.ts +225 -0
  148. package/Tests/Utils/API.test.ts +16 -2
  149. package/Tests/Utils/Dashboard/Components/DashboardKubernetesResourceListShared.test.ts +347 -0
  150. package/Tests/Utils/Dashboard/Components/DashboardListSharedArgs.test.ts +259 -0
  151. package/Tests/Utils/Dashboard/Components/DashboardMonitorListComponent.test.ts +466 -0
  152. package/Tests/Utils/Rum/UrlScrubberSegments.test.ts +362 -0
  153. package/Types/Email/EmailTemplateType.ts +1 -0
  154. package/Types/Monitor/MonitorCriteriaInstance.ts +41 -20
  155. package/Types/Monitor/Recommendation/MonitorRecommendationCatalog.ts +131 -8
  156. package/Types/Monitor/Recommendation/MonitorRecommendationTypes.ts +48 -8
  157. package/Types/Monitor/ServiceAlertTemplates.ts +1352 -0
  158. package/Types/Permission.ts +35 -0
  159. package/Types/PushNotification/AndroidNotificationChannel.ts +26 -0
  160. package/Types/PushNotification/PushNotificationMessage.ts +15 -0
  161. package/Types/PushNotification/PushNotificationRequest.ts +8 -16
  162. package/Types/Service/ServiceLanguage.ts +144 -0
  163. package/Types/Text.ts +111 -19
  164. package/UI/Components/Button/Button.tsx +27 -14
  165. package/UI/Components/CodeBlock/CodeBlock.tsx +54 -7
  166. package/UI/Components/CodeBlock/LanguageRegistry.ts +103 -0
  167. package/UI/Components/CommandPalette/CommandPalette.tsx +790 -0
  168. package/UI/Components/CommandPalette/PaletteFilter.ts +196 -0
  169. package/UI/Components/CommandPalette/PaletteRow.tsx +173 -0
  170. package/UI/Components/CommandPalette/RecentCommands.ts +57 -0
  171. package/UI/Components/CommandPalette/Types.ts +49 -0
  172. package/UI/Components/CommandPalette/UseProviderSearch.ts +129 -0
  173. package/UI/Components/Dropdown/Dropdown.tsx +6 -1
  174. package/UI/Components/Feed/FeedItem.tsx +1 -1
  175. package/UI/Components/List/List.tsx +37 -5
  176. package/UI/Components/List/ListSkeleton.tsx +54 -0
  177. package/UI/Components/Markdown.tsx/LazyMarkdownViewer.tsx +6 -1
  178. package/UI/Components/Markdown.tsx/MarkdownViewer.tsx +71 -26
  179. package/UI/Components/Modal/Modal.tsx +2 -2
  180. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  181. package/UI/Components/ModelTable/useCustomFieldColumns.ts +11 -5
  182. package/UI/Components/MoreMenu/MoreMenu.tsx +39 -1
  183. package/UI/Components/Navbar/NavBar.tsx +14 -1
  184. package/UI/Components/OrderedStatesList/OrderedStatesList.tsx +50 -5
  185. package/UI/Components/SideMenu/CountModelSideMenuItem.tsx +40 -1
  186. package/UI/Components/SideOver/SideOver.tsx +37 -2
  187. package/UI/Components/Skeleton/Skeleton.tsx +53 -0
  188. package/UI/Components/Table/Table.tsx +74 -44
  189. package/UI/Components/Table/TableSkeletonRows.tsx +141 -0
  190. package/UI/Components/Tabs/Tab.tsx +1 -1
  191. package/UI/Components/Toast/Toast.tsx +118 -53
  192. package/UI/Components/Toast/ToastInit.tsx +82 -32
  193. package/UI/Styles/Theme.css +40 -0
  194. package/UI/Utils/ModelAPI/ModelAPI.ts +20 -10
  195. package/UI/Utils/ModelListCache.ts +188 -0
  196. package/UI/Utils/Project.ts +29 -0
  197. package/Utils/API.ts +6 -1
  198. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js +14 -0
  199. package/build/dist/Models/DatabaseModels/OnCallDutyPolicySchedule.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/UserCall.js +101 -3
  201. package/build/dist/Models/DatabaseModels/UserCall.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/UserEmail.js +101 -3
  203. package/build/dist/Models/DatabaseModels/UserEmail.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js +101 -3
  205. package/build/dist/Models/DatabaseModels/UserIncomingCallNumber.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/UserPush.js +38 -0
  207. package/build/dist/Models/DatabaseModels/UserPush.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/UserSMS.js +101 -3
  209. package/build/dist/Models/DatabaseModels/UserSMS.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/UserWhatsApp.js +100 -2
  211. package/build/dist/Models/DatabaseModels/UserWhatsApp.js.map +1 -1
  212. package/build/dist/Server/API/BaseAPI.js +69 -13
  213. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  214. package/build/dist/Server/API/UserCallAPI.js +42 -38
  215. package/build/dist/Server/API/UserCallAPI.js.map +1 -1
  216. package/build/dist/Server/API/UserEmailAPI.js +42 -38
  217. package/build/dist/Server/API/UserEmailAPI.js.map +1 -1
  218. package/build/dist/Server/API/UserIncomingCallNumberAPI.js +37 -32
  219. package/build/dist/Server/API/UserIncomingCallNumberAPI.js.map +1 -1
  220. package/build/dist/Server/API/UserNotificationMethodAdminAPI.js +341 -0
  221. package/build/dist/Server/API/UserNotificationMethodAdminAPI.js.map +1 -0
  222. package/build/dist/Server/API/UserPushAPI.js +95 -2
  223. package/build/dist/Server/API/UserPushAPI.js.map +1 -1
  224. package/build/dist/Server/API/UserSmsAPI.js +42 -38
  225. package/build/dist/Server/API/UserSmsAPI.js.map +1 -1
  226. package/build/dist/Server/API/UserWhatsAppAPI.js +42 -40
  227. package/build/dist/Server/API/UserWhatsAppAPI.js.map +1 -1
  228. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js +89 -0
  229. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787142779538-MigrationName.js.map +1 -0
  230. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js +12 -0
  231. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787156982416-MigrationName.js.map +1 -0
  232. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js +40 -0
  233. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1787700000000-FixTotpOtpUrlAlgorithm.js.map +1 -0
  234. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  236. package/build/dist/Server/Middleware/VerificationCodeRateLimit.js +393 -0
  237. package/build/dist/Server/Middleware/VerificationCodeRateLimit.js.map +1 -0
  238. package/build/dist/Server/Services/AnalyticsDatabaseService.js +136 -0
  239. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  240. package/build/dist/Server/Services/DatabaseService.js +74 -0
  241. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  242. package/build/dist/Server/Services/LogAggregationService.js +5 -0
  243. package/build/dist/Server/Services/LogAggregationService.js.map +1 -1
  244. package/build/dist/Server/Services/PushNotificationService.js +69 -30
  245. package/build/dist/Server/Services/PushNotificationService.js.map +1 -1
  246. package/build/dist/Server/Services/TeamMemberService.js +43 -7
  247. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  248. package/build/dist/Server/Services/UserCallService.js +54 -22
  249. package/build/dist/Server/Services/UserCallService.js.map +1 -1
  250. package/build/dist/Server/Services/UserEmailService.js +78 -17
  251. package/build/dist/Server/Services/UserEmailService.js.map +1 -1
  252. package/build/dist/Server/Services/UserIncomingCallNumberService.js +45 -74
  253. package/build/dist/Server/Services/UserIncomingCallNumberService.js.map +1 -1
  254. package/build/dist/Server/Services/UserNotificationMethodAdminService.js +1117 -0
  255. package/build/dist/Server/Services/UserNotificationMethodAdminService.js.map +1 -0
  256. package/build/dist/Server/Services/UserNotificationRuleService.js +20 -0
  257. package/build/dist/Server/Services/UserNotificationRuleService.js.map +1 -1
  258. package/build/dist/Server/Services/UserPushService.js +77 -0
  259. package/build/dist/Server/Services/UserPushService.js.map +1 -1
  260. package/build/dist/Server/Services/UserSmsService.js +50 -17
  261. package/build/dist/Server/Services/UserSmsService.js.map +1 -1
  262. package/build/dist/Server/Services/UserWhatsAppService.js +48 -15
  263. package/build/dist/Server/Services/UserWhatsAppService.js.map +1 -1
  264. package/build/dist/Server/Types/Database/QueryHelper.js +27 -0
  265. package/build/dist/Server/Types/Database/QueryHelper.js.map +1 -1
  266. package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js +46 -0
  267. package/build/dist/Server/Utils/AnalyticsDatabase/QuerySettingsHelper.js.map +1 -1
  268. package/build/dist/Server/Utils/ChannelVerification.js +348 -0
  269. package/build/dist/Server/Utils/ChannelVerification.js.map +1 -0
  270. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js +13 -12
  271. package/build/dist/Server/Utils/Monitor/Criteria/IncomingRequestCriteria.js.map +1 -1
  272. package/build/dist/Server/Utils/Monitor/MonitorAlert.js +20 -17
  273. package/build/dist/Server/Utils/Monitor/MonitorAlert.js.map +1 -1
  274. package/build/dist/Server/Utils/Monitor/MonitorIncident.js +17 -14
  275. package/build/dist/Server/Utils/Monitor/MonitorIncident.js.map +1 -1
  276. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js +95 -0
  277. package/build/dist/Server/Utils/Monitor/MonitorResourceContext.js.map +1 -0
  278. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js +313 -0
  279. package/build/dist/Server/Utils/Monitor/MonitorStepResourceIdentity.js.map +1 -0
  280. package/build/dist/Server/Utils/Monitor/SeriesResourceLabels.js +3 -3
  281. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js +67 -26
  282. package/build/dist/Server/Utils/Monitor/SeriesResourceLinker.js.map +1 -1
  283. package/build/dist/Server/Utils/TotpAuth.js +127 -8
  284. package/build/dist/Server/Utils/TotpAuth.js.map +1 -1
  285. package/build/dist/Server/Utils/UserRegistrationToken.js +170 -0
  286. package/build/dist/Server/Utils/UserRegistrationToken.js.map +1 -0
  287. package/build/dist/Server/Utils/VerificationCode.js +120 -0
  288. package/build/dist/Server/Utils/VerificationCode.js.map +1 -0
  289. package/build/dist/Types/Email/EmailTemplateType.js +1 -0
  290. package/build/dist/Types/Email/EmailTemplateType.js.map +1 -1
  291. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +42 -21
  292. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  293. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js +77 -5
  294. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationCatalog.js.map +1 -1
  295. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js +18 -6
  296. package/build/dist/Types/Monitor/Recommendation/MonitorRecommendationTypes.js.map +1 -1
  297. package/build/dist/Types/Monitor/ServiceAlertTemplates.js +1028 -0
  298. package/build/dist/Types/Monitor/ServiceAlertTemplates.js.map +1 -0
  299. package/build/dist/Types/Permission.js +33 -0
  300. package/build/dist/Types/Permission.js.map +1 -1
  301. package/build/dist/Types/PushNotification/AndroidNotificationChannel.js +27 -0
  302. package/build/dist/Types/PushNotification/AndroidNotificationChannel.js.map +1 -0
  303. package/build/dist/Types/Service/ServiceLanguage.js +96 -0
  304. package/build/dist/Types/Service/ServiceLanguage.js.map +1 -0
  305. package/build/dist/Types/Text.js +82 -17
  306. package/build/dist/Types/Text.js.map +1 -1
  307. package/build/dist/UI/Components/Button/Button.js +22 -14
  308. package/build/dist/UI/Components/Button/Button.js.map +1 -1
  309. package/build/dist/UI/Components/CodeBlock/CodeBlock.js +35 -3
  310. package/build/dist/UI/Components/CodeBlock/CodeBlock.js.map +1 -1
  311. package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js +57 -0
  312. package/build/dist/UI/Components/CodeBlock/LanguageRegistry.js.map +1 -0
  313. package/build/dist/UI/Components/CommandPalette/CommandPalette.js +439 -0
  314. package/build/dist/UI/Components/CommandPalette/CommandPalette.js.map +1 -0
  315. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js +135 -0
  316. package/build/dist/UI/Components/CommandPalette/PaletteFilter.js.map +1 -0
  317. package/build/dist/UI/Components/CommandPalette/PaletteRow.js +83 -0
  318. package/build/dist/UI/Components/CommandPalette/PaletteRow.js.map +1 -0
  319. package/build/dist/UI/Components/CommandPalette/RecentCommands.js +47 -0
  320. package/build/dist/UI/Components/CommandPalette/RecentCommands.js.map +1 -0
  321. package/build/dist/UI/Components/CommandPalette/Types.js +2 -0
  322. package/build/dist/UI/Components/CommandPalette/Types.js.map +1 -0
  323. package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js +88 -0
  324. package/build/dist/UI/Components/CommandPalette/UseProviderSearch.js.map +1 -0
  325. package/build/dist/UI/Components/Dropdown/Dropdown.js +6 -1
  326. package/build/dist/UI/Components/Dropdown/Dropdown.js.map +1 -1
  327. package/build/dist/UI/Components/Feed/FeedItem.js +1 -1
  328. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  329. package/build/dist/UI/Components/List/List.js +19 -5
  330. package/build/dist/UI/Components/List/List.js.map +1 -1
  331. package/build/dist/UI/Components/List/ListSkeleton.js +21 -0
  332. package/build/dist/UI/Components/List/ListSkeleton.js.map +1 -0
  333. package/build/dist/UI/Components/Markdown.tsx/LazyMarkdownViewer.js.map +1 -1
  334. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js +52 -25
  335. package/build/dist/UI/Components/Markdown.tsx/MarkdownViewer.js.map +1 -1
  336. package/build/dist/UI/Components/Modal/Modal.js +2 -2
  337. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  338. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  339. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js +9 -2
  340. package/build/dist/UI/Components/ModelTable/useCustomFieldColumns.js.map +1 -1
  341. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +32 -1
  342. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  343. package/build/dist/UI/Components/Navbar/NavBar.js +5 -1
  344. package/build/dist/UI/Components/Navbar/NavBar.js.map +1 -1
  345. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js +29 -5
  346. package/build/dist/UI/Components/OrderedStatesList/OrderedStatesList.js.map +1 -1
  347. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js +23 -1
  348. package/build/dist/UI/Components/SideMenu/CountModelSideMenuItem.js.map +1 -1
  349. package/build/dist/UI/Components/SideOver/SideOver.js +23 -2
  350. package/build/dist/UI/Components/SideOver/SideOver.js.map +1 -1
  351. package/build/dist/UI/Components/Skeleton/Skeleton.js +23 -0
  352. package/build/dist/UI/Components/Skeleton/Skeleton.js.map +1 -0
  353. package/build/dist/UI/Components/Table/Table.js +35 -24
  354. package/build/dist/UI/Components/Table/Table.js.map +1 -1
  355. package/build/dist/UI/Components/Table/TableSkeletonRows.js +52 -0
  356. package/build/dist/UI/Components/Table/TableSkeletonRows.js.map +1 -0
  357. package/build/dist/UI/Components/Tabs/Tab.js +1 -1
  358. package/build/dist/UI/Components/Tabs/Tab.js.map +1 -1
  359. package/build/dist/UI/Components/Toast/Toast.js +77 -23
  360. package/build/dist/UI/Components/Toast/Toast.js.map +1 -1
  361. package/build/dist/UI/Components/Toast/ToastInit.js +37 -15
  362. package/build/dist/UI/Components/Toast/ToastInit.js.map +1 -1
  363. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -9
  364. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  365. package/build/dist/UI/Utils/ModelListCache.js +126 -0
  366. package/build/dist/UI/Utils/ModelListCache.js.map +1 -0
  367. package/build/dist/UI/Utils/Project.js +24 -1
  368. package/build/dist/UI/Utils/Project.js.map +1 -1
  369. package/build/dist/Utils/API.js +6 -1
  370. package/build/dist/Utils/API.js.map +1 -1
  371. package/jest.config.json +1 -1
  372. package/package.json +2 -3
  373. package/Server/Utils/Monitor/MonitorClusterContext.ts +0 -182
  374. package/Tests/__mocks__/otpauth.js +0 -30
  375. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js +0 -141
  376. package/build/dist/Server/Utils/Monitor/MonitorClusterContext.js.map +0 -1
@@ -26,7 +26,8 @@ import ProxmoxClusterService from "../../../../Server/Services/ProxmoxClusterSer
26
26
  import ServiceService from "../../../../Server/Services/ServiceService";
27
27
  import ProjectScopedReferenceValidator from "../../../../Server/Utils/Database/ProjectScopedReferenceValidator";
28
28
  import MonitorAlert from "../../../../Server/Utils/Monitor/MonitorAlert";
29
- import MonitorClusterContextUtil from "../../../../Server/Utils/Monitor/MonitorClusterContext";
29
+ import MonitorResourceContextUtil from "../../../../Server/Utils/Monitor/MonitorResourceContext";
30
+ import { SeriesResolvedResourceIds } from "../../../../Server/Utils/Monitor/SeriesResourceLinker";
30
31
  import MonitorIncident from "../../../../Server/Utils/Monitor/MonitorIncident";
31
32
  import Dictionary from "../../../../Types/Dictionary";
32
33
  import { JSONObject } from "../../../../Types/JSON";
@@ -133,6 +134,25 @@ function idsOn(
133
134
  });
134
135
  }
135
136
 
137
+ /*
138
+ * The nine-relation shape MonitorResourceContext resolves from the
139
+ * monitor's own step config. Tests stub the util and hand back one of
140
+ * these, spreading over it to name only the relations under test.
141
+ */
142
+ function emptyResourceContext(): SeriesResolvedResourceIds {
143
+ return {
144
+ hostIds: [],
145
+ dockerHostIds: [],
146
+ podmanHostIds: [],
147
+ kubernetesClusterIds: [],
148
+ serviceIds: [],
149
+ proxmoxClusterIds: [],
150
+ cephClusterIds: [],
151
+ dockerSwarmClusterIds: [],
152
+ iotFleetIds: [],
153
+ };
154
+ }
155
+
136
156
  describe("Alerts link the resources their series identifies", () => {
137
157
  let createdAlerts: Array<Alert> = [];
138
158
  let createdIncidents: Array<Incident> = [];
@@ -151,12 +171,7 @@ describe("Alerts link the resources their series identifies", () => {
151
171
  let dockerSwarmClusterRows: Array<{ _id: string }> = [];
152
172
  let iotFleetRows: Array<{ _id: string }> = [];
153
173
 
154
- let clusterContext: {
155
- proxmoxClusterIds: Array<string>;
156
- cephClusterIds: Array<string>;
157
- dockerSwarmClusterIds: Array<string>;
158
- iotFleetIds: Array<string>;
159
- };
174
+ let resourceContext: SeriesResolvedResourceIds;
160
175
 
161
176
  beforeEach(() => {
162
177
  createdAlerts = [];
@@ -172,12 +187,7 @@ describe("Alerts link the resources their series identifies", () => {
172
187
  dockerSwarmClusterRows = [];
173
188
  iotFleetRows = [];
174
189
 
175
- clusterContext = {
176
- proxmoxClusterIds: [],
177
- cephClusterIds: [],
178
- dockerSwarmClusterIds: [],
179
- iotFleetIds: [],
180
- };
190
+ resourceContext = emptyResourceContext();
181
191
 
182
192
  // No alert / incident is already open for this monitor.
183
193
  jest.spyOn(AlertService, "findBy").mockResolvedValue([]);
@@ -188,9 +198,9 @@ describe("Alerts link the resources their series identifies", () => {
188
198
  .mockResolvedValue(true);
189
199
 
190
200
  jest
191
- .spyOn(MonitorClusterContextUtil, "resolveClusterContextForMonitor")
201
+ .spyOn(MonitorResourceContextUtil, "resolveResourceContextForMonitor")
192
202
  .mockImplementation(async () => {
193
- return clusterContext;
203
+ return resourceContext;
194
204
  });
195
205
 
196
206
  jest
@@ -396,10 +406,13 @@ describe("Alerts link the resources their series identifies", () => {
396
406
  expect(idsOn(createdAlerts[1]!.hosts)).toEqual(["host-7"]);
397
407
  });
398
408
 
399
- it("links nothing, and still opens the alert, for an ungrouped monitor", async () => {
409
+ it("links nothing from LABELS, and still opens the alert, for an ungrouped monitor", async () => {
400
410
  /*
401
- * A whole-monitor alert has no series and therefore no resource
402
- * identity. It must not inherit one, and it must still be created.
411
+ * A whole-monitor alert has no series, so the LABEL path has nothing
412
+ * to work with. It must not invent an identity from another
413
+ * series, and it must still be created. (The step-config path can
414
+ * still name a resource here — that is the test above; this one
415
+ * pins that the label path alone contributes nothing.)
403
416
  */
404
417
  hostRows = [{ _id: "host-1" }];
405
418
 
@@ -417,6 +430,131 @@ describe("Alerts link the resources their series identifies", () => {
417
430
  expect(HostService.findBy).not.toHaveBeenCalled();
418
431
  });
419
432
 
433
+ it("links the service an ungrouped metric monitor is scoped to", async () => {
434
+ /*
435
+ * THE REPORTED BUG. ALT-144 came from a Metrics monitor whose only
436
+ * resource identity was the attribute filter
437
+ * `oneuptime.service.name = app-plan-starship-online-production`.
438
+ * It is ungrouped, so there are no series labels and the label path
439
+ * links nothing — the alert's "Affected Resources" card read "No
440
+ * resources affected" even though the monitor named the service.
441
+ *
442
+ * `matchesPerSeries` is deliberately omitted: that is what makes
443
+ * this the ungrouped path.
444
+ */
445
+ resourceContext = {
446
+ ...emptyResourceContext(),
447
+ serviceIds: ["service-1"],
448
+ };
449
+
450
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
451
+ criteriaInstance: criteriaInstance(),
452
+ monitor: monitor(),
453
+ dataToProcess: dataToProcess,
454
+ rootCause: "Memory is above 60%",
455
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
456
+ props: {},
457
+ });
458
+
459
+ expect(createdAlerts).toHaveLength(1);
460
+ expect(idsOn(createdAlerts[0]!.services)).toEqual(["service-1"]);
461
+ });
462
+
463
+ it("links the host an ungrouped host monitor is scoped to", async () => {
464
+ // Same shape for the infra types: the step config names the host.
465
+ resourceContext = {
466
+ ...emptyResourceContext(),
467
+ hostIds: ["host-1"],
468
+ };
469
+
470
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
471
+ criteriaInstance: criteriaInstance(),
472
+ monitor: monitor(),
473
+ dataToProcess: dataToProcess,
474
+ rootCause: "CPU is above 90%",
475
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
476
+ props: {},
477
+ });
478
+
479
+ expect(idsOn(createdAlerts[0]!.hosts)).toEqual(["host-1"]);
480
+ });
481
+
482
+ it("merges the step-config service with the one the series names", async () => {
483
+ /*
484
+ * A grouped monitor can resolve a service from its labels while the
485
+ * step config names another. Neither may erase the other.
486
+ */
487
+ serviceRows = [{ _id: "service-from-label" }];
488
+ resourceContext = {
489
+ ...emptyResourceContext(),
490
+ serviceIds: ["service-from-step-config"],
491
+ };
492
+
493
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
494
+ criteriaInstance: criteriaInstance(),
495
+ monitor: monitor(),
496
+ dataToProcess: dataToProcess,
497
+ rootCause: "CPU is above 90%",
498
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
499
+ matchesPerSeries: [series({ "service.name": "checkout-api" }, "fp-1")],
500
+ props: {},
501
+ });
502
+
503
+ expect(idsOn(createdAlerts[0]!.services).sort()).toEqual([
504
+ "service-from-label",
505
+ "service-from-step-config",
506
+ ]);
507
+ });
508
+
509
+ it("dedupes a service both paths resolved", async () => {
510
+ serviceRows = [{ _id: "service-1" }];
511
+ resourceContext = {
512
+ ...emptyResourceContext(),
513
+ serviceIds: ["service-1"],
514
+ };
515
+
516
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
517
+ criteriaInstance: criteriaInstance(),
518
+ monitor: monitor(),
519
+ dataToProcess: dataToProcess,
520
+ rootCause: "CPU is above 90%",
521
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
522
+ matchesPerSeries: [series({ "service.name": "checkout-api" }, "fp-1")],
523
+ props: {},
524
+ });
525
+
526
+ expect(idsOn(createdAlerts[0]!.services)).toEqual(["service-1"]);
527
+ });
528
+
529
+ it("attaches the step-config resources to EVERY alert of a grouped monitor", async () => {
530
+ /*
531
+ * One evaluation, two breaching series, one shared monitor config.
532
+ * Both alerts are about the same service.
533
+ */
534
+ hostRows = [{ _id: "host-2" }];
535
+ resourceContext = {
536
+ ...emptyResourceContext(),
537
+ serviceIds: ["service-1"],
538
+ };
539
+
540
+ await MonitorAlert.criteriaMetCreateAlertsAndUpdateMonitorStatus({
541
+ criteriaInstance: criteriaInstance(),
542
+ monitor: monitor(),
543
+ dataToProcess: dataToProcess,
544
+ rootCause: "CPU is above 90%",
545
+ autoResolveCriteriaInstanceIdAlertIdsDictionary: NO_AUTO_RESOLVE,
546
+ matchesPerSeries: [
547
+ series({ "host.name": "node-a" }, "fp-1"),
548
+ series({ "host.name": "node-b" }, "fp-2"),
549
+ ],
550
+ props: {},
551
+ });
552
+
553
+ expect(createdAlerts).toHaveLength(2);
554
+ expect(idsOn(createdAlerts[0]!.services)).toEqual(["service-1"]);
555
+ expect(idsOn(createdAlerts[1]!.services)).toEqual(["service-1"]);
556
+ });
557
+
420
558
  it("merges the monitor's step-config cluster with the one the series names", async () => {
421
559
  /*
422
560
  * The alert path used to ASSIGN the step-config clusters over
@@ -424,7 +562,8 @@ describe("Alerts link the resources their series identifies", () => {
424
562
  * Proxmox cluster, an assignment would drop one of them.
425
563
  */
426
564
  proxmoxClusterRows = [{ _id: "pve-from-label" }];
427
- clusterContext = {
565
+ resourceContext = {
566
+ ...emptyResourceContext(),
428
567
  proxmoxClusterIds: ["pve-from-step-config"],
429
568
  cephClusterIds: [],
430
569
  dockerSwarmClusterIds: [],
@@ -448,7 +587,8 @@ describe("Alerts link the resources their series identifies", () => {
448
587
  });
449
588
 
450
589
  it("still attaches the step-config cluster to an ungrouped alert", async () => {
451
- clusterContext = {
590
+ resourceContext = {
591
+ ...emptyResourceContext(),
452
592
  proxmoxClusterIds: [],
453
593
  cephClusterIds: ["ceph-1"],
454
594
  dockerSwarmClusterIds: [],
@@ -30,7 +30,7 @@ import IncidentStateTimelineService from "../../../../Server/Services/IncidentSt
30
30
  import NetworkDeviceOwnerUserService from "../../../../Server/Services/NetworkDeviceOwnerUserService";
31
31
  import ProjectScopedReferenceValidator from "../../../../Server/Utils/Database/ProjectScopedReferenceValidator";
32
32
  import MonitorAlert from "../../../../Server/Utils/Monitor/MonitorAlert";
33
- import MonitorClusterContextUtil from "../../../../Server/Utils/Monitor/MonitorClusterContext";
33
+ import MonitorResourceContextUtil from "../../../../Server/Utils/Monitor/MonitorResourceContext";
34
34
  import { DependencySuppressionResult } from "../../../../Server/Utils/Monitor/MonitorDependencySuppression";
35
35
  import MonitorIncident from "../../../../Server/Utils/Monitor/MonitorIncident";
36
36
  import Dictionary from "../../../../Types/Dictionary";
@@ -185,7 +185,7 @@ describe("Dependency-suppression skip block in the alert / incident creators", (
185
185
 
186
186
  let alertFindBySpy: SpyLike;
187
187
  let incidentFindBySpy: SpyLike;
188
- let clusterContextSpy: SpyLike;
188
+ let resourceContextSpy: SpyLike;
189
189
 
190
190
  beforeEach(() => {
191
191
  createdIncidents = [];
@@ -211,9 +211,14 @@ describe("Dependency-suppression skip block in the alert / incident creators", (
211
211
  * creators — its call count is how these tests observe whether the flow
212
212
  * proceeded past the block.
213
213
  */
214
- clusterContextSpy = jest
215
- .spyOn(MonitorClusterContextUtil, "resolveClusterContextForMonitor")
214
+ resourceContextSpy = jest
215
+ .spyOn(MonitorResourceContextUtil, "resolveResourceContextForMonitor")
216
216
  .mockResolvedValue({
217
+ hostIds: [],
218
+ dockerHostIds: [],
219
+ podmanHostIds: [],
220
+ kubernetesClusterIds: [],
221
+ serviceIds: [],
217
222
  proxmoxClusterIds: [],
218
223
  cephClusterIds: [],
219
224
  dockerSwarmClusterIds: [],
@@ -349,7 +354,7 @@ describe("Dependency-suppression skip block in the alert / incident creators", (
349
354
  expect(skipEvent.relatedCriteriaId).toBe("criteria-1");
350
355
 
351
356
  // The skip block RETURNS: nothing after it (cluster context) runs.
352
- expect(clusterContextSpy.mock.calls).toHaveLength(0);
357
+ expect(resourceContextSpy.mock.calls).toHaveLength(0);
353
358
  });
354
359
 
355
360
  it("suppressed: the open-alert resolve pass still runs before the skip block (resolution is never suppressed)", async () => {
@@ -421,7 +426,7 @@ describe("Dependency-suppression skip block in the alert / incident creators", (
421
426
  // The resolve pass still ran (it sits above both gates) ...
422
427
  expect(alertFindBySpy.mock.calls).toHaveLength(1);
423
428
  // ... and nothing after the gates did.
424
- expect(clusterContextSpy.mock.calls).toHaveLength(0);
429
+ expect(resourceContextSpy.mock.calls).toHaveLength(0);
425
430
  });
426
431
 
427
432
  it("resolve-only entry point resolves an open alert — suppression state cannot block resolution", async () => {
@@ -488,7 +493,7 @@ describe("Dependency-suppression skip block in the alert / incident creators", (
488
493
  );
489
494
  expect(skipEvent.relatedCriteriaId).toBe("criteria-1");
490
495
 
491
- expect(clusterContextSpy.mock.calls).toHaveLength(0);
496
+ expect(resourceContextSpy.mock.calls).toHaveLength(0);
492
497
  });
493
498
 
494
499
  it("suppressed: the open-incident resolve pass still runs before the skip block (resolution is never suppressed)", async () => {
@@ -556,7 +561,7 @@ describe("Dependency-suppression skip block in the alert / incident creators", (
556
561
  expect(createdIncidents).toHaveLength(0);
557
562
 
558
563
  expect(incidentFindBySpy.mock.calls).toHaveLength(1);
559
- expect(clusterContextSpy.mock.calls).toHaveLength(0);
564
+ expect(resourceContextSpy.mock.calls).toHaveLength(0);
560
565
  });
561
566
 
562
567
  it("resolve-only entry point resolves an open incident — suppression state cannot block resolution", async () => {
@@ -23,7 +23,8 @@ import PodmanHostService from "../../../../Server/Services/PodmanHostService";
23
23
  import ProxmoxClusterService from "../../../../Server/Services/ProxmoxClusterService";
24
24
  import ServiceService from "../../../../Server/Services/ServiceService";
25
25
  import ProjectScopedReferenceValidator from "../../../../Server/Utils/Database/ProjectScopedReferenceValidator";
26
- import MonitorClusterContextUtil from "../../../../Server/Utils/Monitor/MonitorClusterContext";
26
+ import MonitorResourceContextUtil from "../../../../Server/Utils/Monitor/MonitorResourceContext";
27
+ import { SeriesResolvedResourceIds } from "../../../../Server/Utils/Monitor/SeriesResourceLinker";
27
28
  import MonitorIncident from "../../../../Server/Utils/Monitor/MonitorIncident";
28
29
  import Dictionary from "../../../../Types/Dictionary";
29
30
  import { JSONObject } from "../../../../Types/JSON";
@@ -125,6 +126,25 @@ function idsOn(
125
126
  });
126
127
  }
127
128
 
129
+ /*
130
+ * The nine-relation shape MonitorResourceContext resolves from the
131
+ * monitor's own step config. Tests stub the util and hand back one of
132
+ * these, spreading over it to name only the relations under test.
133
+ */
134
+ function emptyResourceContext(): SeriesResolvedResourceIds {
135
+ return {
136
+ hostIds: [],
137
+ dockerHostIds: [],
138
+ podmanHostIds: [],
139
+ kubernetesClusterIds: [],
140
+ serviceIds: [],
141
+ proxmoxClusterIds: [],
142
+ cephClusterIds: [],
143
+ dockerSwarmClusterIds: [],
144
+ iotFleetIds: [],
145
+ };
146
+ }
147
+
128
148
  describe("Incidents link the resources their series identifies", () => {
129
149
  let createdIncidents: Array<Incident> = [];
130
150
 
@@ -138,12 +158,7 @@ describe("Incidents link the resources their series identifies", () => {
138
158
  let dockerSwarmClusterRows: Array<{ _id: string }> = [];
139
159
  let iotFleetRows: Array<{ _id: string }> = [];
140
160
 
141
- let clusterContext: {
142
- proxmoxClusterIds: Array<string>;
143
- cephClusterIds: Array<string>;
144
- dockerSwarmClusterIds: Array<string>;
145
- iotFleetIds: Array<string>;
146
- };
161
+ let resourceContext: SeriesResolvedResourceIds;
147
162
 
148
163
  beforeEach(() => {
149
164
  createdIncidents = [];
@@ -158,12 +173,7 @@ describe("Incidents link the resources their series identifies", () => {
158
173
  dockerSwarmClusterRows = [];
159
174
  iotFleetRows = [];
160
175
 
161
- clusterContext = {
162
- proxmoxClusterIds: [],
163
- cephClusterIds: [],
164
- dockerSwarmClusterIds: [],
165
- iotFleetIds: [],
166
- };
176
+ resourceContext = emptyResourceContext();
167
177
 
168
178
  // No incident is already open for this monitor.
169
179
  jest.spyOn(IncidentService, "findBy").mockResolvedValue([]);
@@ -173,9 +183,9 @@ describe("Incidents link the resources their series identifies", () => {
173
183
  .mockResolvedValue(true);
174
184
 
175
185
  jest
176
- .spyOn(MonitorClusterContextUtil, "resolveClusterContextForMonitor")
186
+ .spyOn(MonitorResourceContextUtil, "resolveResourceContextForMonitor")
177
187
  .mockImplementation(async () => {
178
- return clusterContext;
188
+ return resourceContext;
179
189
  });
180
190
 
181
191
  jest
@@ -422,7 +432,14 @@ describe("Incidents link the resources their series identifies", () => {
422
432
  expect(idsOn(createdIncidents[1]!.hosts)).toEqual(["host-7"]);
423
433
  });
424
434
 
425
- it("links nothing, and still opens the incident, for an ungrouped monitor", async () => {
435
+ it("links nothing from LABELS, and still opens the incident, for an ungrouped monitor", async () => {
436
+ /*
437
+ * A whole-monitor incident has no series, so the label path has
438
+ * nothing to work with. It must not invent an identity from another
439
+ * series, and it must still be created. (The step-config path can
440
+ * still name a resource here — that is the test above; this one
441
+ * pins that the label path alone contributes nothing.)
442
+ */
426
443
  hostRows = [{ _id: "host-1" }];
427
444
 
428
445
  await MonitorIncident.criteriaMetCreateIncidentsAndUpdateMonitorStatus({
@@ -441,7 +458,8 @@ describe("Incidents link the resources their series identifies", () => {
441
458
 
442
459
  it("merges the monitor's step-config cluster with the one the series names", async () => {
443
460
  proxmoxClusterRows = [{ _id: "pve-from-label" }];
444
- clusterContext = {
461
+ resourceContext = {
462
+ ...emptyResourceContext(),
445
463
  proxmoxClusterIds: ["pve-from-step-config"],
446
464
  cephClusterIds: [],
447
465
  dockerSwarmClusterIds: [],
@@ -464,8 +482,134 @@ describe("Incidents link the resources their series identifies", () => {
464
482
  ]);
465
483
  });
466
484
 
485
+ it("links the service an ungrouped metric monitor is scoped to", async () => {
486
+ /*
487
+ * THE REPORTED BUG. The alert twin of this came from a Metrics monitor whose only
488
+ * resource identity was the attribute filter
489
+ * `oneuptime.service.name = app-plan-starship-online-production`.
490
+ * It is ungrouped, so there are no series labels and the label path
491
+ * links nothing — the incident's "Affected Resources" card read "No
492
+ * resources affected" even though the monitor named the service.
493
+ *
494
+ * `matchesPerSeries` is deliberately omitted: that is what makes
495
+ * this the ungrouped path.
496
+ */
497
+ resourceContext = {
498
+ ...emptyResourceContext(),
499
+ serviceIds: ["service-1"],
500
+ };
501
+
502
+ await MonitorIncident.criteriaMetCreateIncidentsAndUpdateMonitorStatus({
503
+ criteriaInstance: criteriaInstance(),
504
+ monitor: monitor(),
505
+ dataToProcess: dataToProcess,
506
+ rootCause: "Memory is above 60%",
507
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary: NO_AUTO_RESOLVE,
508
+ props: {},
509
+ });
510
+
511
+ expect(createdIncidents).toHaveLength(1);
512
+ expect(idsOn(createdIncidents[0]!.services)).toEqual(["service-1"]);
513
+ });
514
+
515
+ it("links the host an ungrouped host monitor is scoped to", async () => {
516
+ // Same shape for the infra types: the step config names the host.
517
+ resourceContext = {
518
+ ...emptyResourceContext(),
519
+ hostIds: ["host-1"],
520
+ };
521
+
522
+ await MonitorIncident.criteriaMetCreateIncidentsAndUpdateMonitorStatus({
523
+ criteriaInstance: criteriaInstance(),
524
+ monitor: monitor(),
525
+ dataToProcess: dataToProcess,
526
+ rootCause: "CPU is above 90%",
527
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary: NO_AUTO_RESOLVE,
528
+ props: {},
529
+ });
530
+
531
+ expect(idsOn(createdIncidents[0]!.hosts)).toEqual(["host-1"]);
532
+ });
533
+
534
+ it("merges the step-config service with the one the series names", async () => {
535
+ /*
536
+ * A grouped monitor can resolve a service from its labels while the
537
+ * step config names another. Neither may erase the other.
538
+ */
539
+ serviceRows = [{ _id: "service-from-label" }];
540
+ resourceContext = {
541
+ ...emptyResourceContext(),
542
+ serviceIds: ["service-from-step-config"],
543
+ };
544
+
545
+ await MonitorIncident.criteriaMetCreateIncidentsAndUpdateMonitorStatus({
546
+ criteriaInstance: criteriaInstance(),
547
+ monitor: monitor(),
548
+ dataToProcess: dataToProcess,
549
+ rootCause: "CPU is above 90%",
550
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary: NO_AUTO_RESOLVE,
551
+ matchesPerSeries: [series({ "service.name": "checkout-api" }, "fp-1")],
552
+ props: {},
553
+ });
554
+
555
+ expect(idsOn(createdIncidents[0]!.services).sort()).toEqual([
556
+ "service-from-label",
557
+ "service-from-step-config",
558
+ ]);
559
+ });
560
+
561
+ it("dedupes a service both paths resolved", async () => {
562
+ serviceRows = [{ _id: "service-1" }];
563
+ resourceContext = {
564
+ ...emptyResourceContext(),
565
+ serviceIds: ["service-1"],
566
+ };
567
+
568
+ await MonitorIncident.criteriaMetCreateIncidentsAndUpdateMonitorStatus({
569
+ criteriaInstance: criteriaInstance(),
570
+ monitor: monitor(),
571
+ dataToProcess: dataToProcess,
572
+ rootCause: "CPU is above 90%",
573
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary: NO_AUTO_RESOLVE,
574
+ matchesPerSeries: [series({ "service.name": "checkout-api" }, "fp-1")],
575
+ props: {},
576
+ });
577
+
578
+ expect(idsOn(createdIncidents[0]!.services)).toEqual(["service-1"]);
579
+ });
580
+
581
+ it("attaches the step-config resources to EVERY incident of a grouped monitor", async () => {
582
+ /*
583
+ * One evaluation, two breaching series, one shared monitor config.
584
+ * Both incidents are about the same service.
585
+ */
586
+ hostRows = [{ _id: "host-2" }];
587
+ resourceContext = {
588
+ ...emptyResourceContext(),
589
+ serviceIds: ["service-1"],
590
+ };
591
+
592
+ await MonitorIncident.criteriaMetCreateIncidentsAndUpdateMonitorStatus({
593
+ criteriaInstance: criteriaInstance(),
594
+ monitor: monitor(),
595
+ dataToProcess: dataToProcess,
596
+ rootCause: "CPU is above 90%",
597
+ autoResolveCriteriaInstanceIdIncidentIdsDictionary: NO_AUTO_RESOLVE,
598
+ matchesPerSeries: [
599
+ series({ "host.name": "node-a" }, "fp-1"),
600
+ series({ "host.name": "node-b" }, "fp-2"),
601
+ ],
602
+ props: {},
603
+ });
604
+
605
+ expect(createdIncidents).toHaveLength(2);
606
+ expect(idsOn(createdIncidents[0]!.services)).toEqual(["service-1"]);
607
+ expect(idsOn(createdIncidents[1]!.services)).toEqual(["service-1"]);
608
+ });
609
+
467
610
  it("still attaches the step-config cluster to an ungrouped incident", async () => {
468
- clusterContext = {
611
+ resourceContext = {
612
+ ...emptyResourceContext(),
469
613
  proxmoxClusterIds: [],
470
614
  cephClusterIds: ["ceph-1"],
471
615
  dockerSwarmClusterIds: [],