@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,118 @@
1
+ import MoreMenu from "../../../UI/Components/MoreMenu/MoreMenu";
2
+ import MoreMenuItem from "../../../UI/Components/MoreMenu/MoreMenuItem";
3
+ import "@testing-library/jest-dom";
4
+ import { act, fireEvent, render, screen } from "@testing-library/react";
5
+ import React from "react";
6
+ import { describe, expect, jest, test } from "@jest/globals";
7
+
8
+ jest.mock("react-i18next", () => {
9
+ return {
10
+ useTranslation: () => {
11
+ return {
12
+ t: (key: string, options?: { defaultValue?: string }): string => {
13
+ return options?.defaultValue ?? key;
14
+ },
15
+ };
16
+ },
17
+ };
18
+ });
19
+
20
+ /*
21
+ * The menu mounts closed and opens on the next animation frame, so anything
22
+ * asserting the settled look has to let that frame run first — the same
23
+ * choreography Modal.test.tsx flushes.
24
+ */
25
+ type FlushEntranceFrameFunction = () => Promise<void>;
26
+
27
+ const flushEntranceFrame: FlushEntranceFrameFunction =
28
+ async (): Promise<void> => {
29
+ await act(async () => {
30
+ await new Promise<void>((resolve: () => void) => {
31
+ requestAnimationFrame(() => {
32
+ resolve();
33
+ });
34
+ });
35
+ });
36
+ };
37
+
38
+ type RenderMenuFunction = () => HTMLElement;
39
+
40
+ const renderMenuTrigger: RenderMenuFunction = (): HTMLElement => {
41
+ render(
42
+ <MoreMenu dataTestId="more-menu-trigger">
43
+ <MoreMenuItem
44
+ key="first"
45
+ text="First action"
46
+ onClick={() => {
47
+ return;
48
+ }}
49
+ />
50
+ <MoreMenuItem
51
+ key="second"
52
+ text="Second action"
53
+ onClick={() => {
54
+ return;
55
+ }}
56
+ />
57
+ </MoreMenu>,
58
+ );
59
+
60
+ return screen.getByTestId("more-menu-trigger");
61
+ };
62
+
63
+ describe("MoreMenu entrance motion", () => {
64
+ test("the menu mounts faded and shrunk towards its top-right origin", () => {
65
+ const trigger: HTMLElement = renderMenuTrigger();
66
+
67
+ fireEvent.click(trigger);
68
+
69
+ const menu: HTMLElement = screen.getByRole("menu");
70
+
71
+ expect(menu).toHaveClass("opacity-0", "scale-95", "origin-top-right");
72
+ expect(menu).toHaveClass(
73
+ "transition",
74
+ "duration-150",
75
+ "ease-out",
76
+ "motion-reduce:transition-none",
77
+ );
78
+ });
79
+
80
+ test("after the entrance frame the menu is opaque with no lingering transform", async () => {
81
+ const trigger: HTMLElement = renderMenuTrigger();
82
+
83
+ fireEvent.click(trigger);
84
+ await flushEntranceFrame();
85
+
86
+ const menu: HTMLElement = screen.getByRole("menu");
87
+
88
+ expect(menu).toHaveClass("opacity-100");
89
+
90
+ /*
91
+ * A settled menu carries no transform class at all: a lingering scale
92
+ * would make it the containing block for position:fixed descendants —
93
+ * the same invariant Modal pins.
94
+ */
95
+ expect(menu.className).not.toMatch(/(^|\s)(sm:)?(scale|translate)-/);
96
+ });
97
+
98
+ test("closing and reopening starts the entrance from the closed state again", async () => {
99
+ const trigger: HTMLElement = renderMenuTrigger();
100
+
101
+ fireEvent.click(trigger);
102
+ await flushEntranceFrame();
103
+
104
+ expect(screen.getByRole("menu")).toHaveClass("opacity-100");
105
+
106
+ // Toggle closed, then straight back open.
107
+ fireEvent.click(trigger);
108
+ expect(screen.queryByRole("menu")).toBeNull();
109
+
110
+ fireEvent.click(trigger);
111
+
112
+ expect(screen.getByRole("menu")).toHaveClass("opacity-0", "scale-95");
113
+
114
+ await flushEntranceFrame();
115
+
116
+ expect(screen.getByRole("menu")).toHaveClass("opacity-100");
117
+ });
118
+ });
@@ -0,0 +1,178 @@
1
+ /*
2
+ * The dashboard's command palette owns Cmd/Ctrl+K, so the NavBar grew a
3
+ * `disableCommandKShortcut` prop that stops it registering its own document
4
+ * keydown for the products menu. These tests pin the contract in BOTH
5
+ * directions: with the prop the menu must NOT open on Cmd+K (or the palette
6
+ * and the menu would double-fire on one keystroke), and without the prop the
7
+ * legacy shortcut must keep working for every other NavBar consumer.
8
+ */
9
+
10
+ /*
11
+ * NavBar and its children translate labels through useTranslateValue, which
12
+ * needs a live i18next instance. Identity translations keep the test focused
13
+ * on the shortcut wiring. The factory must sit above the component import.
14
+ */
15
+ jest.mock("../../../UI/Utils/Translation", () => {
16
+ return {
17
+ __esModule: true,
18
+ default: () => {
19
+ return {
20
+ translateString: (value: string | undefined) => {
21
+ return value;
22
+ },
23
+ translateValue: (value: unknown) => {
24
+ return value;
25
+ },
26
+ };
27
+ },
28
+ };
29
+ });
30
+
31
+ /*
32
+ * Navigation's current-route reads come from a location hook that only the
33
+ * real router wires up (Navigation.getCurrentRoute throws without it). Active
34
+ * state and navigation are irrelevant here, so stub the statics NavBar and its
35
+ * items touch.
36
+ */
37
+ jest.mock("../../../UI/Utils/Navigation", () => {
38
+ return {
39
+ __esModule: true,
40
+ default: {
41
+ isStartWith: () => {
42
+ return false;
43
+ },
44
+ isOnThisPage: () => {
45
+ return false;
46
+ },
47
+ navigate: () => {},
48
+ },
49
+ };
50
+ });
51
+
52
+ import Navbar, {
53
+ MoreMenuItem,
54
+ NavItem,
55
+ } from "../../../UI/Components/Navbar/NavBar";
56
+ import Route from "../../../Types/API/Route";
57
+ import IconProp from "../../../Types/Icon/IconProp";
58
+ import "@testing-library/jest-dom";
59
+ import { cleanup, fireEvent, render, screen } from "@testing-library/react";
60
+ import React from "react";
61
+ import {
62
+ afterEach,
63
+ beforeAll,
64
+ describe,
65
+ expect,
66
+ jest,
67
+ test,
68
+ } from "@jest/globals";
69
+
70
+ /*
71
+ * jsdom does not implement scrollIntoView; the menu modal calls it to keep the
72
+ * keyboard selection visible. A no-op is all the tests need.
73
+ */
74
+ beforeAll(() => {
75
+ Element.prototype.scrollIntoView = (): void => {};
76
+ });
77
+
78
+ const homeItem: NavItem = {
79
+ id: "home-nav-bar-item",
80
+ title: "Home",
81
+ icon: IconProp.Home,
82
+ route: new Route("/dashboard/home"),
83
+ activeRoute: new Route("/dashboard/home"),
84
+ };
85
+
86
+ const moreMenuItems: Array<MoreMenuItem> = [
87
+ {
88
+ title: "Monitors",
89
+ description: "Monitor anything that can go down.",
90
+ route: new Route("/dashboard/project-id/monitors"),
91
+ icon: IconProp.AltGlobe,
92
+ iconColor: "blue",
93
+ category: "Essentials",
94
+ },
95
+ ];
96
+
97
+ function pressCommandK(): void {
98
+ fireEvent.keyDown(document, { key: "k", metaKey: true });
99
+ }
100
+
101
+ describe("NavBar Cmd/Ctrl+K gating", () => {
102
+ afterEach(() => {
103
+ cleanup();
104
+ });
105
+
106
+ test("without the prop, Cmd+K still toggles the products menu (legacy consumers keep their shortcut)", () => {
107
+ render(<Navbar items={[homeItem]} moreMenuItems={moreMenuItems} />);
108
+
109
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
110
+
111
+ pressCommandK();
112
+ expect(screen.getByRole("dialog")).toBeInTheDocument();
113
+
114
+ // And the same chord closes it again — it is a toggle, not just an opener.
115
+ pressCommandK();
116
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
117
+ });
118
+
119
+ test("Ctrl+K works the same as Cmd+K when the shortcut is enabled", () => {
120
+ render(<Navbar items={[homeItem]} moreMenuItems={moreMenuItems} />);
121
+
122
+ fireEvent.keyDown(document, { key: "k", ctrlKey: true });
123
+ expect(screen.getByRole("dialog")).toBeInTheDocument();
124
+ });
125
+
126
+ test("with disableCommandKShortcut, Cmd+K does NOT open the products menu", () => {
127
+ render(
128
+ <Navbar
129
+ items={[homeItem]}
130
+ moreMenuItems={moreMenuItems}
131
+ disableCommandKShortcut={true}
132
+ />,
133
+ );
134
+
135
+ pressCommandK();
136
+ fireEvent.keyDown(document, { key: "k", ctrlKey: true });
137
+
138
+ expect(screen.queryByRole("dialog")).not.toBeInTheDocument();
139
+ });
140
+
141
+ test("with disableCommandKShortcut, the menu still opens from its trigger button", () => {
142
+ /*
143
+ * Disabling the shortcut must not disable the menu: the button path is the
144
+ * remaining way in, so it has to keep working.
145
+ */
146
+ render(
147
+ <Navbar
148
+ items={[homeItem]}
149
+ moreMenuItems={moreMenuItems}
150
+ disableCommandKShortcut={true}
151
+ />,
152
+ );
153
+
154
+ fireEvent.click(screen.getByText("Products"));
155
+ expect(screen.getByRole("dialog")).toBeInTheDocument();
156
+ });
157
+
158
+ test("with disableCommandKShortcut, Cmd+K's default is not prevented (the palette may claim it)", () => {
159
+ render(
160
+ <Navbar
161
+ items={[homeItem]}
162
+ moreMenuItems={moreMenuItems}
163
+ disableCommandKShortcut={true}
164
+ />,
165
+ );
166
+
167
+ /*
168
+ * fireEvent returns false when some handler called preventDefault. With
169
+ * the NavBar listener unregistered, nothing here may swallow the chord —
170
+ * the whole point is leaving it free for the command palette's handler.
171
+ */
172
+ const defaultAllowed: boolean = fireEvent.keyDown(document, {
173
+ key: "k",
174
+ metaKey: true,
175
+ });
176
+ expect(defaultAllowed).toBe(true);
177
+ });
178
+ });
@@ -40,13 +40,30 @@ describe("OrderedSateList", () => {
40
40
  render(<OrderedStatesList {...props} />);
41
41
  expect(props.data).toHaveLength(3);
42
42
  });
43
- it("renders a ComponentLoader if isLoading prop is true", () => {
43
+ it("renders a skeleton stack if isLoading is true with nothing to show yet", () => {
44
44
  const props: ComponentProps<ItemData> = {
45
45
  ...defaultProps,
46
+ data: [],
46
47
  isLoading: true,
47
48
  };
48
49
  render(<OrderedStatesList {...props} />);
49
- expect(screen.getByTestId("bar-loader")).toBeInTheDocument();
50
+ expect(
51
+ screen.getByTestId("ordered-states-list-skeleton-loader"),
52
+ ).toBeInTheDocument();
53
+ });
54
+ it("keeps existing states visible, dimmed, while refetching", () => {
55
+ const props: ComponentProps<ItemData> = {
56
+ ...defaultProps,
57
+ isLoading: true,
58
+ };
59
+ render(<OrderedStatesList {...props} />);
60
+ expect(
61
+ screen.queryByTestId("ordered-states-list-skeleton-loader"),
62
+ ).toBeNull();
63
+ expect(screen.getByText("item 1")).toBeInTheDocument();
64
+ expect(screen.getByTestId("ordered-states-list-content")).toHaveClass(
65
+ "opacity-60",
66
+ );
50
67
  });
51
68
  it("should render an error message if error prop is present", () => {
52
69
  const props: ComponentProps<ItemData> = {
@@ -0,0 +1,109 @@
1
+ import SideOver, {
2
+ ComponentProps,
3
+ } from "../../../UI/Components/SideOver/SideOver";
4
+ import "@testing-library/jest-dom";
5
+ import { resetPageScrollLockForTesting } from "../../../UI/Utils/PageScrollLock";
6
+ import { act, render, screen } from "@testing-library/react";
7
+ import React, { ReactElement } from "react";
8
+ import {
9
+ afterEach,
10
+ beforeEach,
11
+ describe,
12
+ expect,
13
+ jest,
14
+ test,
15
+ } from "@jest/globals";
16
+
17
+ /*
18
+ * The panel mounts parked off the right edge and slides in on the next
19
+ * animation frame, so anything asserting the settled look has to let that
20
+ * frame run first — the same choreography Modal.test.tsx flushes.
21
+ */
22
+ type FlushEntranceFrameFunction = () => Promise<void>;
23
+
24
+ const flushEntranceFrame: FlushEntranceFrameFunction =
25
+ async (): Promise<void> => {
26
+ await act(async () => {
27
+ await new Promise<void>((resolve: () => void) => {
28
+ requestAnimationFrame(() => {
29
+ resolve();
30
+ });
31
+ });
32
+ });
33
+ };
34
+
35
+ type GetPanelFunction = () => HTMLElement;
36
+
37
+ const getPanel: GetPanelFunction = (): HTMLElement => {
38
+ return screen.getByTestId("side-over-layer").firstElementChild as HTMLElement;
39
+ };
40
+
41
+ describe("SideOver entrance motion", () => {
42
+ const childElement: ReactElement = <div key={0}>child element</div>;
43
+
44
+ const props: ComponentProps = {
45
+ title: "title",
46
+ description: "description",
47
+ onClose: jest.fn(),
48
+ onSubmit: jest.fn(),
49
+ children: childElement,
50
+ };
51
+
52
+ beforeEach(() => {
53
+ resetPageScrollLockForTesting();
54
+ document.body.style.overflow = "";
55
+ document.body.style.paddingRight = "";
56
+ });
57
+
58
+ afterEach(() => {
59
+ jest.clearAllMocks();
60
+ resetPageScrollLockForTesting();
61
+ document.body.style.overflow = "";
62
+ document.body.style.paddingRight = "";
63
+ });
64
+
65
+ test("the panel mounts parked off the right edge with a transform transition", () => {
66
+ render(<SideOver {...props} />);
67
+
68
+ const panel: HTMLElement = getPanel();
69
+
70
+ expect(panel).toHaveClass("translate-x-full");
71
+ expect(panel).toHaveClass(
72
+ "transition-transform",
73
+ "duration-200",
74
+ "ease-out",
75
+ "motion-reduce:transition-none",
76
+ );
77
+
78
+ // The layout contract the rest of the suite pins is untouched.
79
+ expect(panel).toHaveClass("pointer-events-auto", "w-full");
80
+ });
81
+
82
+ test("after the entrance frame the panel has settled with no lingering transform", async () => {
83
+ render(<SideOver {...props} />);
84
+
85
+ await flushEntranceFrame();
86
+
87
+ /*
88
+ * A settled panel carries no transform class at all: a lingering
89
+ * translate would make it the containing block for position:fixed
90
+ * descendants — the same invariant Modal pins.
91
+ */
92
+ expect(getPanel().className).not.toMatch(/(^|\s)(sm:)?(scale|translate)-/);
93
+ });
94
+
95
+ test("the close button eases colour changes and carries a focus-visible ring", () => {
96
+ render(<SideOver {...props} />);
97
+
98
+ const closeButton: HTMLElement = screen.getByTestId("close-button");
99
+
100
+ expect(closeButton).toHaveClass(
101
+ "transition-colors",
102
+ "duration-150",
103
+ "focus:outline-none",
104
+ "focus-visible:ring-2",
105
+ "focus-visible:ring-indigo-500",
106
+ "focus-visible:ring-offset-2",
107
+ );
108
+ });
109
+ });
@@ -0,0 +1,71 @@
1
+ import Skeleton, {
2
+ getSkeletonWidthClass,
3
+ } from "../../../UI/Components/Skeleton/Skeleton";
4
+ import "@testing-library/jest-dom";
5
+ import { render, screen } from "@testing-library/react";
6
+ import React from "react";
7
+ import { describe, expect, test } from "@jest/globals";
8
+
9
+ describe("Skeleton", () => {
10
+ test("renders a pulsing gray placeholder block", () => {
11
+ render(<Skeleton />);
12
+
13
+ const skeleton: HTMLElement = screen.getByTestId("skeleton");
14
+ expect(skeleton).toBeInTheDocument();
15
+ expect(skeleton).toHaveClass("animate-pulse");
16
+ expect(skeleton).toHaveClass("rounded");
17
+ expect(skeleton).toHaveClass("bg-gray-200");
18
+ });
19
+
20
+ /*
21
+ * The block is decoration; the composing loading state (role="status")
22
+ * owns the announcement. Without this, a page of skeletons reads to a
23
+ * screen reader as dozens of empty groups.
24
+ */
25
+ test("hides itself from the accessibility tree", () => {
26
+ render(<Skeleton />);
27
+
28
+ expect(screen.getByTestId("skeleton")).toHaveAttribute(
29
+ "aria-hidden",
30
+ "true",
31
+ );
32
+ });
33
+
34
+ test("appends the caller's sizing classes", () => {
35
+ render(<Skeleton className="h-4 w-24" />);
36
+
37
+ const skeleton: HTMLElement = screen.getByTestId("skeleton");
38
+ expect(skeleton).toHaveClass("h-4");
39
+ expect(skeleton).toHaveClass("w-24");
40
+ });
41
+
42
+ /*
43
+ * Width variants must be a pure function of the index - a Math.random
44
+ * width re-rolls on every render, which flickers on screen and makes the
45
+ * DOM impossible to assert on.
46
+ */
47
+ test("cycles width variants deterministically by index", () => {
48
+ expect(getSkeletonWidthClass(0)).toBe("w-3/4");
49
+ expect(getSkeletonWidthClass(1)).toBe("w-1/2");
50
+ expect(getSkeletonWidthClass(2)).toBe("w-2/3");
51
+ expect(getSkeletonWidthClass(3)).toBe("w-3/4");
52
+
53
+ // Same index, same width - every time.
54
+ expect(getSkeletonWidthClass(7)).toBe(getSkeletonWidthClass(7));
55
+ });
56
+
57
+ test("applies the cycled width variant when given an index", () => {
58
+ render(<Skeleton widthVariantIndex={1} dataTestId="indexed-skeleton" />);
59
+
60
+ expect(screen.getByTestId("indexed-skeleton")).toHaveClass("w-1/2");
61
+ });
62
+
63
+ test("adds no width class when no index is given", () => {
64
+ render(<Skeleton />);
65
+
66
+ const skeleton: HTMLElement = screen.getByTestId("skeleton");
67
+ expect(skeleton).not.toHaveClass("w-3/4");
68
+ expect(skeleton).not.toHaveClass("w-1/2");
69
+ expect(skeleton).not.toHaveClass("w-2/3");
70
+ });
71
+ });