@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,403 @@
1
+ import MergeJSON from "../../../../../Server/Types/Workflow/Components/JSON/MergeJson";
2
+ import {
3
+ RunOptions,
4
+ RunReturnType,
5
+ } from "../../../../../Server/Types/Workflow/ComponentCode";
6
+ import Exception from "../../../../../Types/Exception/Exception";
7
+ import { JSONObject } from "../../../../../Types/JSON";
8
+ import ObjectID from "../../../../../Types/ObjectID";
9
+ import ComponentMetadata, {
10
+ Port,
11
+ } from "../../../../../Types/Workflow/Component";
12
+ import ComponentID from "../../../../../Types/Workflow/ComponentID";
13
+ import { describe, expect, test } from "@jest/globals";
14
+
15
+ /*
16
+ * Fixture bundling the RunOptions passed to a component together with the
17
+ * spy-able mocks embedded inside it, so a test can both drive the component and
18
+ * assert on how the component talked back through `onError` / `log`.
19
+ */
20
+ interface OptionsFixture {
21
+ options: RunOptions;
22
+ onError: jest.Mock;
23
+ log: jest.Mock;
24
+ }
25
+
26
+ /*
27
+ * Build a deterministic RunOptions object. `onError` echoes the exception it is
28
+ * given (mirroring the real runner, which returns the exception so callers can
29
+ * `throw options.onError(...)`) while recording that it was invoked.
30
+ */
31
+ function makeOptions(): OptionsFixture {
32
+ const log: jest.Mock = jest.fn();
33
+ const onError: jest.Mock = jest.fn((exception: Exception): Exception => {
34
+ return exception;
35
+ });
36
+
37
+ return {
38
+ log,
39
+ onError,
40
+ options: {
41
+ log: log as RunOptions["log"],
42
+ workflowLogId: ObjectID.generate(),
43
+ workflowId: ObjectID.generate(),
44
+ projectId: ObjectID.generate(),
45
+ onError: onError as RunOptions["onError"],
46
+ executeWorkflow: async (): Promise<void> => {},
47
+ } as RunOptions,
48
+ };
49
+ }
50
+
51
+ /*
52
+ * Convenience wrapper: run a fresh MergeJSON with the supplied args and return
53
+ * both the fixture (for `onError` assertions) and the promise, without awaiting,
54
+ * so error-path tests can use `expect(...).rejects`.
55
+ */
56
+ function runMerge(args: JSONObject): {
57
+ fixture: OptionsFixture;
58
+ result: Promise<RunReturnType>;
59
+ } {
60
+ const fixture: OptionsFixture = makeOptions();
61
+ const result: Promise<RunReturnType> = new MergeJSON().run(
62
+ args,
63
+ fixture.options,
64
+ );
65
+
66
+ return { fixture, result };
67
+ }
68
+
69
+ describe("MergeJSON constructor and metadata", () => {
70
+ test("wires up the Merge JSON component metadata", () => {
71
+ const component: MergeJSON = new MergeJSON();
72
+ const metadata: ComponentMetadata = component.getMetadata();
73
+
74
+ expect(metadata.id).toBe(ComponentID.MergeJson);
75
+ expect(metadata.title).toBe("Merge JSON");
76
+ });
77
+
78
+ test("exposes both success and error out ports", () => {
79
+ const metadata: ComponentMetadata = new MergeJSON().getMetadata();
80
+ const portIds: Array<string> = metadata.outPorts.map((p: Port): string => {
81
+ return p.id;
82
+ });
83
+
84
+ expect(portIds).toContain("success");
85
+ expect(portIds).toContain("error");
86
+ });
87
+ });
88
+
89
+ describe("MergeJSON successful merges", () => {
90
+ test("merges two disjoint objects and routes to the success port", async () => {
91
+ const {
92
+ fixture,
93
+ result,
94
+ }: { fixture: OptionsFixture; result: Promise<RunReturnType> } = runMerge({
95
+ json1: { a: 1 },
96
+ json2: { b: 2 },
97
+ });
98
+
99
+ const value: RunReturnType = await result;
100
+
101
+ expect(value.executePort?.id).toBe("success");
102
+ expect(value.returnValues).toEqual({ json: { a: 1, b: 2 } });
103
+ expect(fixture.onError).not.toHaveBeenCalled();
104
+ });
105
+
106
+ test("gives json2 precedence over json1 on conflicting keys", async () => {
107
+ const value: RunReturnType = await runMerge({
108
+ json1: { shared: "from-json1", onlyOne: 1 },
109
+ json2: { shared: "from-json2", onlyTwo: 2 },
110
+ }).result;
111
+
112
+ expect(value.returnValues["json"]).toEqual({
113
+ shared: "from-json2",
114
+ onlyOne: 1,
115
+ onlyTwo: 2,
116
+ });
117
+ });
118
+
119
+ test("performs a shallow merge so a nested value from json2 fully replaces json1", async () => {
120
+ const value: RunReturnType = await runMerge({
121
+ json1: { user: { name: "alice", age: 30 } },
122
+ json2: { user: { name: "bob" } },
123
+ }).result;
124
+
125
+ /*
126
+ * A deep merge would keep `age`; the spread-based implementation replaces
127
+ * the whole nested object, so only json2's `user` survives.
128
+ */
129
+ expect(value.returnValues["json"]).toEqual({ user: { name: "bob" } });
130
+ });
131
+
132
+ test("returns an empty object when both inputs are empty objects", async () => {
133
+ const value: RunReturnType = await runMerge({
134
+ json1: {},
135
+ json2: {},
136
+ }).result;
137
+
138
+ expect(value.returnValues).toEqual({ json: {} });
139
+ expect(value.executePort?.id).toBe("success");
140
+ });
141
+
142
+ test("keeps every key when one input is empty", async () => {
143
+ const value: RunReturnType = await runMerge({
144
+ json1: {},
145
+ json2: { only: "json2" },
146
+ }).result;
147
+
148
+ expect(value.returnValues["json"]).toEqual({ only: "json2" });
149
+ });
150
+
151
+ test("does not mutate the returned json to share a reference with either input", async () => {
152
+ const json1: JSONObject = { a: 1 };
153
+ const json2: JSONObject = { b: 2 };
154
+ const value: RunReturnType = await runMerge({ json1, json2 }).result;
155
+
156
+ expect(value.returnValues["json"]).not.toBe(json1);
157
+ expect(value.returnValues["json"]).not.toBe(json2);
158
+ });
159
+ });
160
+
161
+ describe("MergeJSON string inputs parsed as JSON", () => {
162
+ test("parses json1 supplied as a JSON string before merging", async () => {
163
+ const value: RunReturnType = await runMerge({
164
+ json1: '{"a":1}',
165
+ json2: { b: 2 },
166
+ }).result;
167
+
168
+ expect(value.returnValues["json"]).toEqual({ a: 1, b: 2 });
169
+ expect(value.executePort?.id).toBe("success");
170
+ });
171
+
172
+ test("parses both json1 and json2 when both are JSON strings", async () => {
173
+ const value: RunReturnType = await runMerge({
174
+ json1: '{"a":1}',
175
+ json2: '{"b":2}',
176
+ }).result;
177
+
178
+ expect(value.returnValues["json"]).toEqual({ a: 1, b: 2 });
179
+ });
180
+
181
+ test("accepts lenient JSON5 syntax (single quotes, unquoted keys, trailing commas)", async () => {
182
+ const value: RunReturnType = await runMerge({
183
+ json1: "{ a: 'one', }",
184
+ json2: "{ b: 'two', }",
185
+ }).result;
186
+
187
+ expect(value.returnValues["json"]).toEqual({ a: "one", b: "two" });
188
+ });
189
+
190
+ test("surfaces a raw parse error (not routed through onError) for malformed json1", async () => {
191
+ const {
192
+ fixture,
193
+ result,
194
+ }: { fixture: OptionsFixture; result: Promise<RunReturnType> } = runMerge({
195
+ json1: "{ this is not valid",
196
+ json2: { b: 2 },
197
+ });
198
+
199
+ await expect(result).rejects.toThrow();
200
+ /*
201
+ * The parse happens outside the onError-wrapped guards, so a bad JSON
202
+ * string escapes as a raw parser exception rather than being routed to the
203
+ * component's error port.
204
+ */
205
+ expect(fixture.onError).not.toHaveBeenCalled();
206
+ });
207
+ });
208
+
209
+ describe("MergeJSON json1 validation failures", () => {
210
+ test("rejects when json1 is undefined", async () => {
211
+ const {
212
+ fixture,
213
+ result,
214
+ }: { fixture: OptionsFixture; result: Promise<RunReturnType> } = runMerge({
215
+ json2: { b: 2 },
216
+ });
217
+
218
+ await expect(result).rejects.toThrow("JSON1 is undefined.");
219
+ expect(fixture.onError).toHaveBeenCalledTimes(1);
220
+ });
221
+
222
+ test("treats an empty string json1 as undefined", async () => {
223
+ const {
224
+ fixture,
225
+ result,
226
+ }: { fixture: OptionsFixture; result: Promise<RunReturnType> } = runMerge({
227
+ json1: "",
228
+ json2: { b: 2 },
229
+ });
230
+
231
+ await expect(result).rejects.toThrow("JSON1 is undefined.");
232
+ expect(fixture.onError).toHaveBeenCalled();
233
+ });
234
+
235
+ test("treats the falsy number 0 json1 as undefined", async () => {
236
+ const { result }: { result: Promise<RunReturnType> } = runMerge({
237
+ json1: 0,
238
+ json2: { b: 2 },
239
+ });
240
+
241
+ await expect(result).rejects.toThrow("JSON1 is undefined.");
242
+ });
243
+
244
+ test("treats a false json1 as undefined", async () => {
245
+ const { result }: { result: Promise<RunReturnType> } = runMerge({
246
+ json1: false,
247
+ json2: { b: 2 },
248
+ });
249
+
250
+ await expect(result).rejects.toThrow("JSON1 is undefined.");
251
+ });
252
+
253
+ test("rejects a non-object, non-string json1 with a type error", async () => {
254
+ const {
255
+ fixture,
256
+ result,
257
+ }: { fixture: OptionsFixture; result: Promise<RunReturnType> } = runMerge({
258
+ json1: 42,
259
+ json2: { b: 2 },
260
+ });
261
+
262
+ await expect(result).rejects.toThrow("JSON1 is should be of type object.");
263
+ expect(fixture.onError).toHaveBeenCalled();
264
+ });
265
+
266
+ test("rejects a json1 string that parses to a non-object", async () => {
267
+ const { result }: { result: Promise<RunReturnType> } = runMerge({
268
+ json1: "42",
269
+ json2: { b: 2 },
270
+ });
271
+
272
+ await expect(result).rejects.toThrow("JSON1 is should be of type object.");
273
+ });
274
+ });
275
+
276
+ describe("MergeJSON json2 validation failures", () => {
277
+ test("rejects when json2 is undefined", async () => {
278
+ const {
279
+ fixture,
280
+ result,
281
+ }: { fixture: OptionsFixture; result: Promise<RunReturnType> } = runMerge({
282
+ json1: { a: 1 },
283
+ });
284
+
285
+ await expect(result).rejects.toThrow("JSON2 is undefined.");
286
+ expect(fixture.onError).toHaveBeenCalledTimes(1);
287
+ });
288
+
289
+ test("treats an empty string json2 as undefined", async () => {
290
+ const { result }: { result: Promise<RunReturnType> } = runMerge({
291
+ json1: { a: 1 },
292
+ json2: "",
293
+ });
294
+
295
+ await expect(result).rejects.toThrow("JSON2 is undefined.");
296
+ });
297
+
298
+ test("rejects a non-object, non-string json2 with a type error", async () => {
299
+ const {
300
+ fixture,
301
+ result,
302
+ }: { fixture: OptionsFixture; result: Promise<RunReturnType> } = runMerge({
303
+ json1: { a: 1 },
304
+ json2: 42,
305
+ });
306
+
307
+ await expect(result).rejects.toThrow("JSON2 is should be of type object.");
308
+ expect(fixture.onError).toHaveBeenCalled();
309
+ });
310
+
311
+ test("rejects a json2 string that parses to a non-object", async () => {
312
+ const { result }: { result: Promise<RunReturnType> } = runMerge({
313
+ json1: { a: 1 },
314
+ json2: "true",
315
+ });
316
+
317
+ await expect(result).rejects.toThrow("JSON2 is should be of type object.");
318
+ });
319
+ });
320
+
321
+ describe("MergeJSON validation ordering", () => {
322
+ test("reports the json1 failure first when both inputs are missing", async () => {
323
+ const { result }: { result: Promise<RunReturnType> } = runMerge({});
324
+
325
+ await expect(result).rejects.toThrow("JSON1 is undefined.");
326
+ });
327
+
328
+ test("only reaches the json2 checks once json1 is valid", async () => {
329
+ const { result }: { result: Promise<RunReturnType> } = runMerge({
330
+ json1: { a: 1 },
331
+ });
332
+
333
+ await expect(result).rejects.toThrow("JSON2 is undefined.");
334
+ });
335
+ });
336
+
337
+ describe("MergeJSON out-port guards", () => {
338
+ /*
339
+ * These guards live before any argument handling. They are normally
340
+ * unreachable because the real metadata always defines both ports, so we
341
+ * drive them by swapping in a metadata clone whose out ports are missing.
342
+ */
343
+ test("throws when the success port is missing from metadata", async () => {
344
+ const component: MergeJSON = new MergeJSON();
345
+ const base: ComponentMetadata = component.getMetadata();
346
+ component.setMetadata({
347
+ ...base,
348
+ outPorts: base.outPorts.filter((p: Port): boolean => {
349
+ return p.id !== "success";
350
+ }),
351
+ });
352
+
353
+ const fixture: OptionsFixture = makeOptions();
354
+
355
+ await expect(
356
+ component.run({ json1: { a: 1 }, json2: { b: 2 } }, fixture.options),
357
+ ).rejects.toThrow("Success port not found");
358
+ expect(fixture.onError).toHaveBeenCalled();
359
+ });
360
+
361
+ test("throws when the error port is missing from metadata", async () => {
362
+ const component: MergeJSON = new MergeJSON();
363
+ const base: ComponentMetadata = component.getMetadata();
364
+ component.setMetadata({
365
+ ...base,
366
+ outPorts: base.outPorts.filter((p: Port): boolean => {
367
+ return p.id !== "error";
368
+ }),
369
+ });
370
+
371
+ const fixture: OptionsFixture = makeOptions();
372
+
373
+ await expect(
374
+ component.run({ json1: { a: 1 }, json2: { b: 2 } }, fixture.options),
375
+ ).rejects.toThrow("Error port not found");
376
+ expect(fixture.onError).toHaveBeenCalled();
377
+ });
378
+ });
379
+
380
+ describe("MergeJSON array inputs", () => {
381
+ /*
382
+ * Arrays are truthy and `typeof [] === "object"`, so they pass the guards and
383
+ * get spread by index. This documents the real (arguably surprising)
384
+ * behavior rather than prescribing it.
385
+ */
386
+ test("spreads array inputs by numeric index into the merged object", async () => {
387
+ const value: RunReturnType = await runMerge({
388
+ json1: ["x"],
389
+ json2: { a: 1 },
390
+ }).result;
391
+
392
+ expect(value.returnValues["json"]).toEqual({ "0": "x", a: 1 });
393
+ });
394
+
395
+ test("adds nothing for an empty array input", async () => {
396
+ const value: RunReturnType = await runMerge({
397
+ json1: { a: 1 },
398
+ json2: [],
399
+ }).result;
400
+
401
+ expect(value.returnValues["json"]).toEqual({ a: 1 });
402
+ });
403
+ });
@@ -0,0 +1,162 @@
1
+ import { describe, expect, test } from "@jest/globals";
2
+ import BrowserUtil from "../../../Server/Utils/Browser";
3
+ import ScreenSizeType from "../../../Types/ScreenSizeType";
4
+
5
+ /*
6
+ * BrowserUtil.getViewportHeightAndWidth is a pure, synchronous lookup: it maps
7
+ * a ScreenSizeType enum value to a fixed viewport { height, width }. It has one
8
+ * switch case per enum member plus a default arm that mirrors Desktop.
9
+ *
10
+ * These tests pin every branch (Desktop, Mobile, Tablet, default), the exact
11
+ * pixel values each branch returns, and the shape/orientation invariants that
12
+ * downstream page.setViewportSize relies on. The function touches no network,
13
+ * no filesystem, no clock and no randomness, so every assertion is fully
14
+ * deterministic.
15
+ */
16
+
17
+ interface Viewport {
18
+ height: number;
19
+ width: number;
20
+ }
21
+
22
+ function viewportFor(screenSizeType: ScreenSizeType): Viewport {
23
+ return BrowserUtil.getViewportHeightAndWidth({
24
+ screenSizeType: screenSizeType,
25
+ });
26
+ }
27
+
28
+ describe("BrowserUtil.getViewportHeightAndWidth", () => {
29
+ describe("per screen size branch", () => {
30
+ test("Desktop maps to 1920x1080 (landscape full HD)", () => {
31
+ const viewport: Viewport = viewportFor(ScreenSizeType.Desktop);
32
+
33
+ expect(viewport).toEqual({ height: 1080, width: 1920 });
34
+ });
35
+
36
+ test("Mobile maps to 360x640 (portrait handset)", () => {
37
+ const viewport: Viewport = viewportFor(ScreenSizeType.Mobile);
38
+
39
+ expect(viewport).toEqual({ height: 640, width: 360 });
40
+ });
41
+
42
+ test("Tablet maps to 1024x768", () => {
43
+ const viewport: Viewport = viewportFor(ScreenSizeType.Tablet);
44
+
45
+ expect(viewport).toEqual({ height: 768, width: 1024 });
46
+ });
47
+ });
48
+
49
+ describe("default / unknown branch", () => {
50
+ test("an unknown screen size falls through to the Desktop defaults", () => {
51
+ /*
52
+ * The switch has an explicit default arm that assigns the same 1080x1920
53
+ * as Desktop. It is only reachable with a value outside the enum, so we
54
+ * cast an arbitrary string through unknown to exercise it. If a future
55
+ * change forgets the default, this catches the resulting 0x0 viewport.
56
+ */
57
+ const viewport: Viewport = viewportFor(
58
+ "SomeUnsupportedSize" as unknown as ScreenSizeType,
59
+ );
60
+
61
+ expect(viewport).toEqual({ height: 1080, width: 1920 });
62
+ });
63
+
64
+ test("the default branch never returns the 0x0 initial values", () => {
65
+ const viewport: Viewport = viewportFor("" as unknown as ScreenSizeType);
66
+
67
+ expect(viewport.height).toBeGreaterThan(0);
68
+ expect(viewport.width).toBeGreaterThan(0);
69
+ });
70
+
71
+ test("default and Desktop are indistinguishable", () => {
72
+ const desktop: Viewport = viewportFor(ScreenSizeType.Desktop);
73
+ const unknown: Viewport = viewportFor(
74
+ "not-a-real-size" as unknown as ScreenSizeType,
75
+ );
76
+
77
+ expect(unknown).toEqual(desktop);
78
+ });
79
+ });
80
+
81
+ describe("shape and value invariants", () => {
82
+ const allSizes: Array<ScreenSizeType> = [
83
+ ScreenSizeType.Desktop,
84
+ ScreenSizeType.Mobile,
85
+ ScreenSizeType.Tablet,
86
+ ];
87
+
88
+ test("every enum member yields exactly a height and width", () => {
89
+ for (const size of allSizes) {
90
+ const viewport: Viewport = viewportFor(size);
91
+
92
+ expect(Object.keys(viewport).sort()).toEqual(["height", "width"]);
93
+ }
94
+ });
95
+
96
+ test("every dimension is a positive, finite integer", () => {
97
+ for (const size of allSizes) {
98
+ const viewport: Viewport = viewportFor(size);
99
+
100
+ for (const value of [viewport.height, viewport.width]) {
101
+ expect(Number.isInteger(value)).toBe(true);
102
+ expect(Number.isFinite(value)).toBe(true);
103
+ expect(value).toBeGreaterThan(0);
104
+ }
105
+ }
106
+ });
107
+
108
+ test("Mobile is the only portrait orientation; Desktop and Tablet are landscape", () => {
109
+ const mobile: Viewport = viewportFor(ScreenSizeType.Mobile);
110
+ const desktop: Viewport = viewportFor(ScreenSizeType.Desktop);
111
+ const tablet: Viewport = viewportFor(ScreenSizeType.Tablet);
112
+
113
+ expect(mobile.width).toBeLessThan(mobile.height);
114
+ expect(desktop.width).toBeGreaterThan(desktop.height);
115
+ expect(tablet.width).toBeGreaterThan(tablet.height);
116
+ });
117
+
118
+ test("Desktop is the largest surface and Mobile the smallest", () => {
119
+ const areaOf: (viewport: Viewport) => number = (
120
+ viewport: Viewport,
121
+ ): number => {
122
+ return viewport.height * viewport.width;
123
+ };
124
+
125
+ const desktopArea: number = areaOf(viewportFor(ScreenSizeType.Desktop));
126
+ const tabletArea: number = areaOf(viewportFor(ScreenSizeType.Tablet));
127
+ const mobileArea: number = areaOf(viewportFor(ScreenSizeType.Mobile));
128
+
129
+ expect(desktopArea).toBeGreaterThan(tabletArea);
130
+ expect(tabletArea).toBeGreaterThan(mobileArea);
131
+ });
132
+
133
+ test("the three known sizes are all distinct", () => {
134
+ const serialized: Array<string> = allSizes.map(
135
+ (size: ScreenSizeType): string => {
136
+ return JSON.stringify(viewportFor(size));
137
+ },
138
+ );
139
+
140
+ expect(new Set(serialized).size).toBe(allSizes.length);
141
+ });
142
+ });
143
+
144
+ describe("purity and determinism", () => {
145
+ test("repeated calls with the same input return equal values", () => {
146
+ const first: Viewport = viewportFor(ScreenSizeType.Tablet);
147
+ const second: Viewport = viewportFor(ScreenSizeType.Tablet);
148
+
149
+ expect(second).toEqual(first);
150
+ });
151
+
152
+ test("each call returns a fresh object, so callers cannot corrupt later results", () => {
153
+ const first: Viewport = viewportFor(ScreenSizeType.Desktop);
154
+ first.height = -1;
155
+ first.width = -1;
156
+
157
+ const second: Viewport = viewportFor(ScreenSizeType.Desktop);
158
+
159
+ expect(second).toEqual({ height: 1080, width: 1920 });
160
+ });
161
+ });
162
+ });