@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
@@ -0,0 +1,192 @@
1
+ import AutoRemediationSuggestionStatus, {
2
+ AutoRemediationSuggestionStatusHelper,
3
+ } from "../../../Types/AutoRemediation/AutoRemediationSuggestionStatus";
4
+ import { describe, expect, test } from "@jest/globals";
5
+
6
+ /*
7
+ * Contract under test — the lifecycle vocabulary of an auto-remediation
8
+ * suggestion and the single predicate that splits it into terminal vs open.
9
+ *
10
+ * A suggestion is the approvable action object a matched rule attaches to an
11
+ * incident or alert. isTerminalStatus draws the line between states that can
12
+ * still be actioned (Planning, Suggested — a human or the executor may yet
13
+ * move them) and states that are frozen for good (Approved, AutoExecuted,
14
+ * Dismissed, NoneApplicable). Anything downstream that decides whether to show
15
+ * an approve/dismiss control, re-run planning, or leave a suggestion alone
16
+ * relies on this partition being exact — every status classified, none in both
17
+ * halves.
18
+ *
19
+ * The enum is string-valued, so the wire/DB representation of each member is
20
+ * itself part of the contract: renaming a value would silently orphan rows
21
+ * persisted under the old string. These tests pin both the string values and
22
+ * the terminal/open classification.
23
+ */
24
+
25
+ /*
26
+ * The two open (non-terminal) states — still actionable.
27
+ */
28
+ const OPEN_STATUSES: Array<AutoRemediationSuggestionStatus> = [
29
+ AutoRemediationSuggestionStatus.Planning,
30
+ AutoRemediationSuggestionStatus.Suggested,
31
+ ];
32
+
33
+ /*
34
+ * The four terminal states — frozen, never change again.
35
+ */
36
+ const TERMINAL_STATUSES: Array<AutoRemediationSuggestionStatus> = [
37
+ AutoRemediationSuggestionStatus.Approved,
38
+ AutoRemediationSuggestionStatus.AutoExecuted,
39
+ AutoRemediationSuggestionStatus.Dismissed,
40
+ AutoRemediationSuggestionStatus.NoneApplicable,
41
+ ];
42
+
43
+ describe("AutoRemediationSuggestionStatus enum", () => {
44
+ test("each member's string value matches its name", () => {
45
+ expect(AutoRemediationSuggestionStatus.Planning).toBe("Planning");
46
+ expect(AutoRemediationSuggestionStatus.Suggested).toBe("Suggested");
47
+ expect(AutoRemediationSuggestionStatus.Approved).toBe("Approved");
48
+ expect(AutoRemediationSuggestionStatus.AutoExecuted).toBe("AutoExecuted");
49
+ expect(AutoRemediationSuggestionStatus.Dismissed).toBe("Dismissed");
50
+ expect(AutoRemediationSuggestionStatus.NoneApplicable).toBe(
51
+ "NoneApplicable",
52
+ );
53
+ });
54
+
55
+ test("declares exactly six members and no extras", () => {
56
+ const values: Array<string> = Object.values(
57
+ AutoRemediationSuggestionStatus,
58
+ );
59
+ expect(values).toHaveLength(6);
60
+ expect(values.slice().sort()).toEqual(
61
+ [
62
+ "Approved",
63
+ "AutoExecuted",
64
+ "Dismissed",
65
+ "NoneApplicable",
66
+ "Planning",
67
+ "Suggested",
68
+ ].sort(),
69
+ );
70
+ });
71
+
72
+ test("all member string values are unique", () => {
73
+ const values: Array<string> = Object.values(
74
+ AutoRemediationSuggestionStatus,
75
+ );
76
+ const unique: Set<string> = new Set(values);
77
+ expect(unique.size).toBe(values.length);
78
+ });
79
+ });
80
+
81
+ describe("AutoRemediationSuggestionStatusHelper.isTerminalStatus", () => {
82
+ test.each(TERMINAL_STATUSES)(
83
+ "returns true for terminal status %s",
84
+ (status: AutoRemediationSuggestionStatus) => {
85
+ expect(
86
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(status),
87
+ ).toBe(true);
88
+ },
89
+ );
90
+
91
+ test.each(OPEN_STATUSES)(
92
+ "returns false for open status %s",
93
+ (status: AutoRemediationSuggestionStatus) => {
94
+ expect(
95
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(status),
96
+ ).toBe(false);
97
+ },
98
+ );
99
+
100
+ test("terminal and open sets together cover every enum member with no overlap", () => {
101
+ const allStatuses: Array<AutoRemediationSuggestionStatus> = Object.values(
102
+ AutoRemediationSuggestionStatus,
103
+ );
104
+ const partitioned: Array<AutoRemediationSuggestionStatus> = [
105
+ ...TERMINAL_STATUSES,
106
+ ...OPEN_STATUSES,
107
+ ];
108
+
109
+ /*
110
+ * No status appears in both halves.
111
+ */
112
+ expect(new Set(partitioned).size).toBe(partitioned.length);
113
+
114
+ /*
115
+ * Every enum member lands in exactly one half.
116
+ */
117
+ expect(partitioned.slice().sort()).toEqual(allStatuses.slice().sort());
118
+ });
119
+
120
+ test("classifies every enum member without leaving any unclassified", () => {
121
+ const allStatuses: Array<AutoRemediationSuggestionStatus> = Object.values(
122
+ AutoRemediationSuggestionStatus,
123
+ );
124
+
125
+ for (const status of allStatuses) {
126
+ const isTerminal: boolean =
127
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(status);
128
+ const expectedTerminal: boolean = TERMINAL_STATUSES.includes(status);
129
+ expect(isTerminal).toBe(expectedTerminal);
130
+ }
131
+ });
132
+
133
+ test("is a pure predicate — repeated calls yield the same result", () => {
134
+ for (const status of Object.values(AutoRemediationSuggestionStatus)) {
135
+ const first: boolean =
136
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(status);
137
+ const second: boolean =
138
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(status);
139
+ expect(second).toBe(first);
140
+ }
141
+ });
142
+
143
+ test("returns exactly a boolean, never a truthy/falsy proxy", () => {
144
+ const terminalResult: boolean =
145
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(
146
+ AutoRemediationSuggestionStatus.Approved,
147
+ );
148
+ const openResult: boolean =
149
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(
150
+ AutoRemediationSuggestionStatus.Planning,
151
+ );
152
+ expect(typeof terminalResult).toBe("boolean");
153
+ expect(typeof openResult).toBe("boolean");
154
+ });
155
+
156
+ test("matches the raw string value of each member (DB/wire representation)", () => {
157
+ /*
158
+ * The enum is string-backed, so a persisted row carries the string, not the
159
+ * TS enum reference. Passing the equivalent raw string must classify the
160
+ * same way — guarding against a future rename that would strand old rows.
161
+ */
162
+ expect(
163
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(
164
+ "Dismissed" as AutoRemediationSuggestionStatus,
165
+ ),
166
+ ).toBe(true);
167
+ expect(
168
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(
169
+ "Suggested" as AutoRemediationSuggestionStatus,
170
+ ),
171
+ ).toBe(false);
172
+ });
173
+
174
+ test("treats an unknown status as non-terminal (no false freeze)", () => {
175
+ /*
176
+ * Defensive edge: a value outside the enum (legacy or corrupt data) is not
177
+ * one of the four terminal constants, so the predicate reports false. That
178
+ * keeps an unrecognized suggestion open/actionable rather than silently
179
+ * frozen.
180
+ */
181
+ expect(
182
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(
183
+ "SomethingElse" as AutoRemediationSuggestionStatus,
184
+ ),
185
+ ).toBe(false);
186
+ expect(
187
+ AutoRemediationSuggestionStatusHelper.isTerminalStatus(
188
+ "" as AutoRemediationSuggestionStatus,
189
+ ),
190
+ ).toBe(false);
191
+ });
192
+ });
@@ -0,0 +1,189 @@
1
+ import Phone from "../../../Types/Phone";
2
+ import { isHighRiskPhoneNumber } from "../../../Types/Call/CallRequest";
3
+ import { describe, expect, test } from "@jest/globals";
4
+
5
+ /*
6
+ * isHighRiskPhoneNumber(phone) stringifies the Phone and returns true when the
7
+ * resulting string starts with any of a fixed set of high-risk country dialing
8
+ * codes. The matching is a plain String.prototype.startsWith over the raw
9
+ * value, so behavior hinges on: the exact leading characters (including the
10
+ * "+"), the ordering-independent "some" scan, and the boundary between a real
11
+ * code and a number that merely shares leading digits with one.
12
+ *
13
+ * These tests exercise the real branches: every high-risk code (true path),
14
+ * ordinary countries (false path), near-miss prefixes that share leading digits
15
+ * but are not a code, the required leading "+", formatting/length boundaries,
16
+ * and copy-constructed Phone objects.
17
+ */
18
+
19
+ /*
20
+ * The exact high-risk set encoded in CallRequest.ts. Kept as a local literal so
21
+ * the test asserts against a known expectation rather than re-importing the
22
+ * private constant.
23
+ */
24
+ const HIGH_RISK_DIALING_CODES: Array<string> = [
25
+ "+92",
26
+ "+27",
27
+ "+213",
28
+ "+371",
29
+ "+370",
30
+ "+372",
31
+ "+252",
32
+ "+232",
33
+ "+231",
34
+ "+53",
35
+ "+960",
36
+ "+992",
37
+ "+880",
38
+ "+62",
39
+ "+84",
40
+ "+95",
41
+ ];
42
+
43
+ type MakeValidNumberFunction = (dialingCode: string) => string;
44
+
45
+ /*
46
+ * Build a phone string that starts with the given dialing code and satisfies
47
+ * Phone's constructor regex (3 digits, 3 digits, then 4-7 digits => 10-13 total
48
+ * digits). Padding with zeros to 12 total digits keeps every generated number
49
+ * inside the valid range regardless of whether the code has 2 or 3 digits.
50
+ */
51
+ const makeValidNumber: MakeValidNumberFunction = (
52
+ dialingCode: string,
53
+ ): string => {
54
+ const digits: string = dialingCode.replace("+", "");
55
+ const padding: string = "0000000000000".substring(0, 12 - digits.length);
56
+ return "+" + digits + padding;
57
+ };
58
+
59
+ describe("isHighRiskPhoneNumber flags every high-risk dialing code", () => {
60
+ test.each(HIGH_RISK_DIALING_CODES)(
61
+ "flags a number starting with %s",
62
+ (dialingCode: string) => {
63
+ const phone: Phone = new Phone(makeValidNumber(dialingCode));
64
+ expect(isHighRiskPhoneNumber(phone)).toBe(true);
65
+ },
66
+ );
67
+
68
+ test("flags Tajikistan (+992) on its own three-digit code, not via +92", () => {
69
+ /*
70
+ * +992 does not start with +92, so it can only be flagged by its own
71
+ * three-digit entry. This guards against a regression where only the
72
+ * shorter code were present.
73
+ */
74
+ const phone: Phone = new Phone(makeValidNumber("+992"));
75
+ expect(phone.toString().startsWith("+92")).toBe(false);
76
+ expect(isHighRiskPhoneNumber(phone)).toBe(true);
77
+ });
78
+ });
79
+
80
+ describe("isHighRiskPhoneNumber does not flag ordinary / low-risk countries", () => {
81
+ const lowRiskNumbers: Array<string> = [
82
+ "+15551234567", // United States / Canada (+1)
83
+ "+442071234567", // United Kingdom (+44)
84
+ "+491234567890", // Germany (+49)
85
+ "+611234567890", // Australia (+61)
86
+ "+331234567890", // France (+33)
87
+ "+811234567890", // Japan (+81)
88
+ "+861234567890", // China (+86)
89
+ "+551234567890", // Brazil (+55)
90
+ "+521234567890", // Mexico (+52) sits right next to Cuba (+53)
91
+ "+919876543210", // India (+91) sits right next to Pakistan (+92)
92
+ ];
93
+
94
+ test.each(lowRiskNumbers)("does not flag %s", (phoneNumber: string) => {
95
+ const phone: Phone = new Phone(phoneNumber);
96
+ expect(isHighRiskPhoneNumber(phone)).toBe(false);
97
+ });
98
+ });
99
+
100
+ describe("near-miss prefixes that only share leading digits are not flagged", () => {
101
+ /*
102
+ * Each entry starts with the same first digits as a real high-risk code but
103
+ * diverges before the full code, so startsWith must return false. This is the
104
+ * key discriminating branch: matching is prefix-exact, not "close enough".
105
+ */
106
+ const nearMisses: Array<[string, string]> = [
107
+ ["+254123456789", "Kenya (+254) vs Somalia (+252)"],
108
+ ["+994123456789", "Azerbaijan (+994) vs Tajikistan (+992)"],
109
+ ["+886123456789", "Taiwan (+886) vs Bangladesh (+880)"],
110
+ [
111
+ "+373123456789",
112
+ "Moldova (+373) vs Latvia/Lithuania/Estonia (+371/+370/+372)",
113
+ ],
114
+ ["+919876543210", "India (+91) vs Pakistan (+92)"],
115
+ ["+521234567890", "Mexico (+52) vs Cuba (+53)"],
116
+ ];
117
+
118
+ test.each(nearMisses)("does not flag %s", (phoneNumber: string) => {
119
+ const phone: Phone = new Phone(phoneNumber);
120
+ expect(isHighRiskPhoneNumber(phone)).toBe(false);
121
+ });
122
+ });
123
+
124
+ describe("the leading + is part of the match", () => {
125
+ test("a high-risk number without the leading + is not flagged", () => {
126
+ /*
127
+ * The stored value is exactly what the caller passed. Without the "+", the
128
+ * string is "920000000000", which does not start with "+92".
129
+ */
130
+ const phone: Phone = new Phone("920000000000");
131
+ expect(phone.toString().startsWith("+")).toBe(false);
132
+ expect(isHighRiskPhoneNumber(phone)).toBe(false);
133
+ });
134
+
135
+ test("the same digits with the leading + are flagged", () => {
136
+ const phone: Phone = new Phone("+920000000000");
137
+ expect(isHighRiskPhoneNumber(phone)).toBe(true);
138
+ });
139
+ });
140
+
141
+ describe("formatting and length boundaries", () => {
142
+ test("flags a high-risk number written with separators after the code", () => {
143
+ /*
144
+ * "+232-123-4567" is a valid Phone (3 digits, sep, 3 digits, sep, 4 digits)
145
+ * whose string still starts with the Sierra Leone code "+232".
146
+ */
147
+ const phone: Phone = new Phone("+232-123-4567");
148
+ expect(isHighRiskPhoneNumber(phone)).toBe(true);
149
+ });
150
+
151
+ test("flags the shortest valid high-risk number (10 digits)", () => {
152
+ const phone: Phone = new Phone("+9200000000");
153
+ expect(isHighRiskPhoneNumber(phone)).toBe(true);
154
+ });
155
+
156
+ test("flags the longest valid high-risk number (13 digits)", () => {
157
+ const phone: Phone = new Phone("+9200000000000");
158
+ expect(isHighRiskPhoneNumber(phone)).toBe(true);
159
+ });
160
+ });
161
+
162
+ describe("Phone construction variants are evaluated identically", () => {
163
+ test("a Phone copy-constructed from another Phone is still flagged", () => {
164
+ const original: Phone = new Phone("+920000000000");
165
+ const copy: Phone = new Phone(original);
166
+ expect(copy.toString()).toEqual(original.toString());
167
+ expect(isHighRiskPhoneNumber(copy)).toBe(true);
168
+ });
169
+
170
+ test("mutating a Phone to a high-risk value changes the result", () => {
171
+ const phone: Phone = new Phone("+15551234567");
172
+ expect(isHighRiskPhoneNumber(phone)).toBe(false);
173
+ phone.phone = "+840000000000";
174
+ expect(isHighRiskPhoneNumber(phone)).toBe(true);
175
+ });
176
+ });
177
+
178
+ describe("return value contract", () => {
179
+ test("always returns a strict boolean", () => {
180
+ const flagged: boolean = isHighRiskPhoneNumber(new Phone("+920000000000"));
181
+ const notFlagged: boolean = isHighRiskPhoneNumber(
182
+ new Phone("+15551234567"),
183
+ );
184
+ expect(typeof flagged).toBe("boolean");
185
+ expect(typeof notFlagged).toBe("boolean");
186
+ expect(flagged).toBe(true);
187
+ expect(notFlagged).toBe(false);
188
+ });
189
+ });
@@ -0,0 +1,226 @@
1
+ import DefaultDashboardSize, {
2
+ GetDashboardComponentWidthInDashboardUnits,
3
+ SpaceBetweenUnitsInPx,
4
+ } from "../../../Types/Dashboard/DashboardSize";
5
+ import { describe, expect, test } from "@jest/globals";
6
+
7
+ /*
8
+ * GetDashboardComponentWidthInDashboardUnits converts a pixel width into a
9
+ * count of dashboard grid units. The internal math is:
10
+ *
11
+ * eachUnitSizeInPx = currentTotalDashboardWidthInPx / widthInDashboardUnits
12
+ * units = Math.ceil(componentWidthInPx / eachUnitSizeInPx)
13
+ * return units < 1 ? 1 : units
14
+ *
15
+ * where widthInDashboardUnits comes from DefaultDashboardSize. The tests below
16
+ * pin down the ceiling rounding, the floor-to-1 clamp, the absence of any
17
+ * upper clamp, and the degenerate divide-by-zero behaviour.
18
+ */
19
+
20
+ describe("GetDashboardComponentWidthInDashboardUnits", () => {
21
+ /*
22
+ * The whole module is calibrated around a 12-unit-wide grid. If that default
23
+ * ever changes, the hand-computed expectations below would silently drift, so
24
+ * assert the assumption explicitly and fail loudly here instead.
25
+ */
26
+ const GRID_UNITS: number = DefaultDashboardSize.widthInDashboardUnits;
27
+
28
+ test("assumes the default grid is 12 units wide", () => {
29
+ expect(GRID_UNITS).toBe(12);
30
+ });
31
+
32
+ describe("basic conversion", () => {
33
+ test("returns 1 when the component spans exactly one unit", () => {
34
+ /*
35
+ * total 1200px over 12 units => 100px per unit. A 100px component is
36
+ * exactly one unit and must round to 1 (not 2).
37
+ */
38
+ const units: number = GetDashboardComponentWidthInDashboardUnits(
39
+ 1200,
40
+ 100,
41
+ );
42
+ expect(units).toBe(1);
43
+ });
44
+
45
+ test("returns 2 when the component spans exactly two units", () => {
46
+ const units: number = GetDashboardComponentWidthInDashboardUnits(
47
+ 1200,
48
+ 200,
49
+ );
50
+ expect(units).toBe(2);
51
+ });
52
+
53
+ test("returns the full grid width when the component fills the dashboard", () => {
54
+ const units: number = GetDashboardComponentWidthInDashboardUnits(
55
+ 1200,
56
+ 1200,
57
+ );
58
+ expect(units).toBe(GRID_UNITS);
59
+ });
60
+
61
+ test("scales the unit size with the total dashboard width", () => {
62
+ /*
63
+ * total 600px over 12 units => 50px per unit. A 50px component is one
64
+ * unit and a 150px component is three units. The unit size is derived
65
+ * from the total width, so a different total yields a different mapping.
66
+ */
67
+ expect(GetDashboardComponentWidthInDashboardUnits(600, 50)).toBe(1);
68
+ expect(GetDashboardComponentWidthInDashboardUnits(600, 150)).toBe(3);
69
+ });
70
+ });
71
+
72
+ describe("ceiling / round-up behaviour", () => {
73
+ test("rounds a partial unit up to the next whole unit", () => {
74
+ /*
75
+ * 100px per unit. 150px is 1.5 units and must round up to 2. 250px is
76
+ * 2.5 units and must round up to 3.
77
+ */
78
+ expect(GetDashboardComponentWidthInDashboardUnits(1200, 150)).toBe(2);
79
+ expect(GetDashboardComponentWidthInDashboardUnits(1200, 250)).toBe(3);
80
+ });
81
+
82
+ test("rounds up even a single pixel over a unit boundary", () => {
83
+ /*
84
+ * 101px is 1.01 units; the ceiling makes it consume 2 whole units so the
85
+ * component is never visually clipped.
86
+ */
87
+ expect(GetDashboardComponentWidthInDashboardUnits(1200, 101)).toBe(2);
88
+ });
89
+
90
+ test("does not round up when the width lands exactly on a boundary", () => {
91
+ /*
92
+ * ceil(2.0) is 2, not 3. Exact multiples of the unit size stay put.
93
+ */
94
+ expect(GetDashboardComponentWidthInDashboardUnits(1200, 200)).toBe(2);
95
+ expect(GetDashboardComponentWidthInDashboardUnits(1200, 300)).toBe(3);
96
+ });
97
+
98
+ test("rounds a sub-unit width up to a single unit", () => {
99
+ /*
100
+ * 50px is half a unit; ceil(0.5) is 1, so a component narrower than one
101
+ * unit still occupies a whole unit.
102
+ */
103
+ expect(GetDashboardComponentWidthInDashboardUnits(1200, 50)).toBe(1);
104
+ });
105
+ });
106
+
107
+ describe("floor-to-1 clamp", () => {
108
+ test("returns 1 for a zero-width component", () => {
109
+ /*
110
+ * ceil(0) is 0, which is below the minimum, so the clamp forces 1. A
111
+ * component always occupies at least one grid unit.
112
+ */
113
+ expect(GetDashboardComponentWidthInDashboardUnits(1200, 0)).toBe(1);
114
+ });
115
+
116
+ test("returns 1 for a negative component width", () => {
117
+ /*
118
+ * ceil(-0.5) is -0, which is below the minimum and clamps to 1 rather
119
+ * than returning a negative or zero unit count.
120
+ */
121
+ expect(GetDashboardComponentWidthInDashboardUnits(1200, -50)).toBe(1);
122
+ });
123
+
124
+ test("returns 1 when the total dashboard width is negative", () => {
125
+ /*
126
+ * A negative total flips the sign of the unit size, so a positive
127
+ * component yields a negative raw unit count that clamps to 1.
128
+ */
129
+ expect(GetDashboardComponentWidthInDashboardUnits(-1200, 100)).toBe(1);
130
+ });
131
+ });
132
+
133
+ describe("no upper clamp", () => {
134
+ test("returns more than the grid width when the component overflows the dashboard", () => {
135
+ /*
136
+ * A 2400px component on a 1200px dashboard is 24 units. The function does
137
+ * not cap the result at the 12-unit grid width.
138
+ */
139
+ const units: number = GetDashboardComponentWidthInDashboardUnits(
140
+ 1200,
141
+ 2400,
142
+ );
143
+ expect(units).toBe(24);
144
+ expect(units).toBeGreaterThan(GRID_UNITS);
145
+ });
146
+ });
147
+
148
+ describe("degenerate totals (divide by zero)", () => {
149
+ test("returns Infinity when the total is zero but the component is positive", () => {
150
+ /*
151
+ * A zero total makes the per-unit size zero, so a positive component
152
+ * divides by zero to Infinity. ceil(Infinity) is Infinity, which is above
153
+ * the minimum and is returned as-is rather than clamped.
154
+ */
155
+ const units: number = GetDashboardComponentWidthInDashboardUnits(0, 100);
156
+ expect(units).toBe(Infinity);
157
+ expect(Number.isFinite(units)).toBe(false);
158
+ });
159
+
160
+ test("returns NaN when both the total and the component are zero", () => {
161
+ /*
162
+ * 0 / 0 is NaN, ceil(NaN) is NaN, and NaN < 1 is false, so NaN passes the
163
+ * clamp untouched.
164
+ */
165
+ const units: number = GetDashboardComponentWidthInDashboardUnits(0, 0);
166
+ expect(Number.isNaN(units)).toBe(true);
167
+ });
168
+ });
169
+
170
+ describe("independence from inter-unit spacing", () => {
171
+ test("ignores SpaceBetweenUnitsInPx when computing the unit count", () => {
172
+ /*
173
+ * Unlike GetWidthOfDashboardComponent, this function divides the raw total
174
+ * width by the unit count and never subtracts SpaceBetweenUnitsInPx. Prove
175
+ * that by showing the result depends only on total and component width: a
176
+ * 100px component on a 1200px dashboard is exactly one unit regardless of
177
+ * the spacing constant's value.
178
+ */
179
+ expect(SpaceBetweenUnitsInPx).toBeGreaterThan(0);
180
+ expect(GetDashboardComponentWidthInDashboardUnits(1200, 100)).toBe(1);
181
+ });
182
+ });
183
+
184
+ describe("monotonicity", () => {
185
+ test("never decreases as the component width grows", () => {
186
+ /*
187
+ * For a fixed dashboard width, a wider component can only ever require the
188
+ * same number of units or more. Sweep a range of widths and assert the
189
+ * unit count is non-decreasing.
190
+ */
191
+ const total: number = 1200;
192
+ let previous: number = GetDashboardComponentWidthInDashboardUnits(
193
+ total,
194
+ 0,
195
+ );
196
+
197
+ for (
198
+ let componentWidth: number = 0;
199
+ componentWidth <= 2400;
200
+ componentWidth += 37
201
+ ) {
202
+ const current: number = GetDashboardComponentWidthInDashboardUnits(
203
+ total,
204
+ componentWidth,
205
+ );
206
+ expect(current).toBeGreaterThanOrEqual(previous);
207
+ previous = current;
208
+ }
209
+ });
210
+ });
211
+
212
+ describe("output shape", () => {
213
+ test("always returns a whole number for finite positive inputs", () => {
214
+ const widths: Array<number> = [1, 49, 50, 99, 100, 101, 599, 1200, 5000];
215
+
216
+ for (const componentWidth of widths) {
217
+ const units: number = GetDashboardComponentWidthInDashboardUnits(
218
+ 1200,
219
+ componentWidth,
220
+ );
221
+ expect(Number.isInteger(units)).toBe(true);
222
+ expect(units).toBeGreaterThanOrEqual(1);
223
+ }
224
+ });
225
+ });
226
+ });