@oneuptime/common 13.0.8 → 14.0.0

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 (333) hide show
  1. package/Models/AnalyticsModels/AuditLog.ts +23 -15
  2. package/Models/DatabaseModels/GlobalConfig.ts +24 -0
  3. package/Models/DatabaseModels/Monitor.ts +3 -2
  4. package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
  5. package/Scripts/generate-service-worker.js +65 -4
  6. package/Server/API/BaseAPI.ts +26 -5
  7. package/Server/API/GlobalConfigAPI.ts +228 -462
  8. package/Server/API/ProjectOIDC.ts +25 -16
  9. package/Server/API/ProjectSSO.ts +24 -16
  10. package/Server/API/StatusPageAPI.ts +100 -42
  11. package/Server/API/TeamMemberAPI.ts +10 -1
  12. package/Server/Enterprise/EnterpriseEdition.ts +649 -0
  13. package/Server/Enterprise/EnterpriseFeature.ts +48 -0
  14. package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
  15. package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
  16. package/Server/EnvironmentConfig.ts +147 -2
  17. package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
  18. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +2 -0
  19. package/Server/Middleware/UserAuthorization.ts +38 -16
  20. package/Server/Services/AuditLogService.ts +84 -1079
  21. package/Server/Services/EnterpriseLicenseService.ts +38 -0
  22. package/Server/Services/GlobalConfigService.ts +80 -1
  23. package/Server/Services/MonitorProbeService.ts +116 -20
  24. package/Server/Services/MonitorService.ts +56 -4
  25. package/Server/Services/MonitorStatusTimelineService.ts +284 -0
  26. package/Server/Services/MonitorTemplateService.ts +26 -0
  27. package/Server/Services/ProjectService.ts +284 -0
  28. package/Server/Services/RumSessionPinService.ts +25 -6
  29. package/Server/Services/StatusPagePrivateUserService.ts +7 -3
  30. package/Server/Services/StatusPageService.ts +78 -1
  31. package/Server/Services/TeamMemberService.ts +11 -0
  32. package/Server/Services/TeamService.ts +10 -0
  33. package/Server/Services/UserService.ts +10 -17
  34. package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
  35. package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
  36. package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
  37. package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
  38. package/Server/Types/Markdown.ts +41 -0
  39. package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
  40. package/Server/Utils/EditionEnforcement.ts +233 -0
  41. package/Server/Utils/FrontendEnvironment.ts +41 -2
  42. package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
  43. package/Server/Utils/Monitor/AffectedResourceList.ts +190 -0
  44. package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
  45. package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +543 -333
  46. package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
  47. package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
  48. package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
  49. package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
  50. package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
  51. package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
  52. package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
  53. package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
  54. package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
  55. package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
  56. package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
  57. package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
  58. package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
  59. package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
  60. package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
  61. package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
  62. package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
  63. package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
  64. package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
  65. package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
  66. package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
  67. package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
  68. package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
  69. package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
  70. package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
  71. package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
  72. package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
  73. package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
  74. package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
  75. package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
  76. package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
  77. package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
  78. package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
  79. package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
  80. package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
  81. package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
  82. package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
  83. package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
  84. package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
  85. package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
  86. package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
  87. package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
  88. package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
  89. package/Tests/Server/Services/AuditLogService.test.ts +460 -990
  90. package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
  91. package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
  92. package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
  93. package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
  94. package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
  95. package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
  96. package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
  97. package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
  98. package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
  99. package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
  100. package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
  101. package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
  102. package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
  103. package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
  104. package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
  105. package/Tests/Server/Types/Markdown.test.ts +181 -0
  106. package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
  107. package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
  108. package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
  109. package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
  110. package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
  111. package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
  112. package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +934 -96
  113. package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
  114. package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
  115. package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
  116. package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
  117. package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
  118. package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
  119. package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
  120. package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
  121. package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
  122. package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
  123. package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
  124. package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
  125. package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
  126. package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
  127. package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
  128. package/Tests/Utils/HostAddressUtil.test.ts +138 -0
  129. package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
  130. package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
  131. package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
  132. package/Types/API/Hostname.ts +63 -16
  133. package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
  134. package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
  135. package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
  136. package/Types/Database/CanonicalModelInstance.ts +102 -0
  137. package/Types/Database/TableColumn.ts +20 -6
  138. package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
  139. package/Types/IP/IPv6.ts +6 -1
  140. package/Types/Monitor/MonitorStep.ts +6 -1
  141. package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
  142. package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
  143. package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
  144. package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
  145. package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
  146. package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
  147. package/UI/Components/ModelList/ModelList.tsx +11 -1
  148. package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
  149. package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
  150. package/UI/esbuild-enterprise.js +263 -0
  151. package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
  152. package/Utils/HostAddressUtil.ts +94 -0
  153. package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
  154. package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
  155. package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
  156. package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
  157. package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
  158. package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
  159. package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
  160. package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
  161. package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
  162. package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
  163. package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
  164. package/build/dist/Server/API/BaseAPI.js +26 -5
  165. package/build/dist/Server/API/BaseAPI.js.map +1 -1
  166. package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
  167. package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
  168. package/build/dist/Server/API/ProjectOIDC.js +24 -16
  169. package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
  170. package/build/dist/Server/API/ProjectSSO.js +24 -16
  171. package/build/dist/Server/API/ProjectSSO.js.map +1 -1
  172. package/build/dist/Server/API/StatusPageAPI.js +93 -43
  173. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  174. package/build/dist/Server/API/TeamMemberAPI.js +8 -1
  175. package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
  176. package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
  177. package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
  178. package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
  179. package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
  180. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
  181. package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
  182. package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
  183. package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
  184. package/build/dist/Server/EnvironmentConfig.js +84 -2
  185. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  186. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
  187. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
  188. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +2 -0
  189. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  190. package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
  191. package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
  192. package/build/dist/Server/Services/AuditLogService.js +71 -740
  193. package/build/dist/Server/Services/AuditLogService.js.map +1 -1
  194. package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
  195. package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
  196. package/build/dist/Server/Services/GlobalConfigService.js +63 -0
  197. package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
  198. package/build/dist/Server/Services/MonitorProbeService.js +90 -17
  199. package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
  200. package/build/dist/Server/Services/MonitorService.js +45 -4
  201. package/build/dist/Server/Services/MonitorService.js.map +1 -1
  202. package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
  203. package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
  204. package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
  205. package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
  206. package/build/dist/Server/Services/ProjectService.js +214 -0
  207. package/build/dist/Server/Services/ProjectService.js.map +1 -1
  208. package/build/dist/Server/Services/RumSessionPinService.js +24 -6
  209. package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
  210. package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
  211. package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
  212. package/build/dist/Server/Services/StatusPageService.js +71 -0
  213. package/build/dist/Server/Services/StatusPageService.js.map +1 -1
  214. package/build/dist/Server/Services/TeamMemberService.js +10 -0
  215. package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
  216. package/build/dist/Server/Services/TeamService.js +9 -0
  217. package/build/dist/Server/Services/TeamService.js.map +1 -1
  218. package/build/dist/Server/Services/UserService.js +10 -16
  219. package/build/dist/Server/Services/UserService.js.map +1 -1
  220. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
  221. package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
  222. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
  223. package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
  224. package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
  225. package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
  226. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
  227. package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
  228. package/build/dist/Server/Types/Markdown.js +31 -0
  229. package/build/dist/Server/Types/Markdown.js.map +1 -1
  230. package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
  231. package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
  232. package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
  233. package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
  234. package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
  235. package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
  236. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
  237. package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
  238. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +96 -0
  239. package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
  240. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
  241. package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
  242. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +449 -261
  243. package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
  244. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
  245. package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
  246. package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
  247. package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
  248. package/build/dist/Types/API/Hostname.js +59 -11
  249. package/build/dist/Types/API/Hostname.js.map +1 -1
  250. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
  251. package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
  252. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
  253. package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
  254. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
  255. package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
  256. package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
  257. package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
  258. package/build/dist/Types/Database/TableColumn.js +19 -6
  259. package/build/dist/Types/Database/TableColumn.js.map +1 -1
  260. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
  261. package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
  262. package/build/dist/Types/IP/IPv6.js +6 -1
  263. package/build/dist/Types/IP/IPv6.js.map +1 -1
  264. package/build/dist/Types/Monitor/MonitorStep.js +5 -0
  265. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  266. package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
  267. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
  268. package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
  269. package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
  270. package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
  271. package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
  272. package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
  273. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
  274. package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
  275. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
  276. package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
  277. package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
  278. package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
  279. package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
  280. package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
  281. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
  282. package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
  283. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
  284. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
  285. package/build/dist/Utils/HostAddressUtil.js +80 -0
  286. package/build/dist/Utils/HostAddressUtil.js.map +1 -0
  287. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
  288. package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
  289. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
  290. package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
  291. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
  292. package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
  293. package/jest.config.json +3 -1
  294. package/package.json +1 -1
  295. package/test-setup.sh +103 -34
  296. package/tsconfig.json +13 -0
  297. package/Server/API/EnterpriseLicenseAPI.ts +0 -925
  298. package/Server/API/TeamComplianceAPI.ts +0 -158
  299. package/Server/Middleware/SCIMAuthorization.ts +0 -141
  300. package/Server/Services/TeamComplianceService.ts +0 -733
  301. package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
  302. package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
  303. package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
  304. package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
  305. package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
  306. package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
  307. package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
  308. package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
  309. package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
  310. package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
  311. package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
  312. package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
  313. package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
  314. package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
  315. package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
  316. package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
  317. package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
  318. package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
  319. package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
  320. package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
  321. package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
  322. package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
  323. package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
  324. package/build/dist/Server/Services/TeamComplianceService.js +0 -537
  325. package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
  326. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
  327. package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
  328. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
  329. package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
  330. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
  331. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
  332. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
  333. package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
@@ -0,0 +1,572 @@
1
+ import "@testing-library/jest-dom";
2
+ import {
3
+ afterEach,
4
+ beforeEach,
5
+ describe,
6
+ expect,
7
+ jest,
8
+ test,
9
+ } from "@jest/globals";
10
+ import { cleanup, render, screen } from "@testing-library/react";
11
+ import fs from "fs";
12
+ import path from "path";
13
+ import React, { FunctionComponent, ReactElement } from "react";
14
+
15
+ /*
16
+ * The core shells of the audit-log and team-compliance screens.
17
+ *
18
+ * Since the Community / Enterprise split those screens are Enterprise code
19
+ * (ee/Dashboard/AuditLogs, ee/Dashboard/TeamCompliance). Each module stays at
20
+ * its old path as a small shell - same default export, same props - so the 27
21
+ * pages that render <AuditLogsTable>, the route files and the lazy page map
22
+ * never change. A shell renders the Enterprise plugin when the project may use
23
+ * the feature AND the bundle includes it, and the upsell card otherwise.
24
+ *
25
+ * The member compliance status table has no shell and no plugin key: only the
26
+ * Compliance page shows it, and ee's page imports it from ee/ directly. The
27
+ * old shell (Components/Team/TeamComplianceStatusTable) and its key were
28
+ * unreachable, and are pinned here as gone.
29
+ *
30
+ * Pinned here, for each shell:
31
+ * - which tier it asks for (audit logs: Enterprise; compliance: Scale), on
32
+ * the Cloud and self-hosted, CE and EE;
33
+ * - that the plugin gets the caller's props untouched;
34
+ * - that an ineligible project never renders (or downloads) the plugin;
35
+ * - that an eligible project on a Community bundle is pointed at the
36
+ * edition, never told to upgrade its plan;
37
+ * - the Teams side menu shows Compliance exactly when the page would.
38
+ *
39
+ * The plugins come from a stand-in for src/Enterprise/Plugins; `null` means
40
+ * "the real module", which in this jest config is the empty Community stub.
41
+ * Billing, edition and plan are pinned in every test (CI's config.env sets
42
+ * BILLING_ENABLED=true). Nothing here imports ee/.
43
+ */
44
+
45
+ let billingEnabledForTest: boolean = false;
46
+ let enterpriseEditionForTest: boolean = false;
47
+ let currentPlanForTest: string | null = null;
48
+ let pluginsForTest: Record<string, unknown> | null = null;
49
+
50
+ const CLOUD_PLAN_ENV: Record<string, string> = {
51
+ SUBSCRIPTION_PLAN_BASIC: "Free,priceMonthlyId1,priceYearlyId1,0,0,1,0",
52
+ SUBSCRIPTION_PLAN_GROWTH: "Growth,priceMonthlyId2,priceYearlyId2,0,0,2,14",
53
+ SUBSCRIPTION_PLAN_SCALE: "Scale,priceMonthlyId3,priceYearlyId3,0,0,3,0",
54
+ SUBSCRIPTION_PLAN_ENTERPRISE:
55
+ "Enterprise,priceMonthlyId4,priceYearlyId4,-1,-1,4,14",
56
+ };
57
+
58
+ jest.mock("../../../UI/Config", () => {
59
+ const actual: Record<string, unknown> = jest.requireActual(
60
+ "../../../UI/Config",
61
+ ) as Record<string, unknown>;
62
+
63
+ const mocked: Record<string, unknown> = { ...actual };
64
+
65
+ Object.defineProperty(mocked, "BILLING_ENABLED", {
66
+ get: (): boolean => {
67
+ return billingEnabledForTest;
68
+ },
69
+ });
70
+
71
+ Object.defineProperty(mocked, "IS_ENTERPRISE_EDITION", {
72
+ get: (): boolean => {
73
+ return enterpriseEditionForTest;
74
+ },
75
+ });
76
+
77
+ mocked["getAllEnvVars"] = (): Record<string, string> => {
78
+ return CLOUD_PLAN_ENV;
79
+ };
80
+
81
+ return mocked;
82
+ });
83
+
84
+ jest.mock("../../../../App/FeatureSet/Dashboard/src/Enterprise/Plugins", () => {
85
+ const actual: { getDashboardPlugins: () => Record<string, unknown> } =
86
+ jest.requireActual(
87
+ "../../../../App/FeatureSet/Dashboard/src/Enterprise/Plugins",
88
+ ) as { getDashboardPlugins: () => Record<string, unknown> };
89
+
90
+ return {
91
+ __esModule: true,
92
+ getDashboardPlugins: (): Record<string, unknown> => {
93
+ return pluginsForTest === null
94
+ ? actual.getDashboardPlugins()
95
+ : pluginsForTest;
96
+ },
97
+ };
98
+ });
99
+
100
+ jest.mock("react-i18next", () => {
101
+ return {
102
+ useTranslation: () => {
103
+ return {
104
+ t: (value: string): string => {
105
+ return value;
106
+ },
107
+ };
108
+ },
109
+ };
110
+ });
111
+
112
+ import AuditLogsTable, {
113
+ ComponentProps as AuditLogsTableShellProps,
114
+ } from "../../../../App/FeatureSet/Dashboard/src/Components/AuditLogs/AuditLogsTable";
115
+ import SettingsAuditLogsSettings from "../../../../App/FeatureSet/Dashboard/src/Pages/Settings/AuditLogsSettings";
116
+ import TeamViewCompliance, {
117
+ TEAM_COMPLIANCE_UPSELL,
118
+ } from "../../../../App/FeatureSet/Dashboard/src/Pages/Teams/View/Compliance";
119
+ import TeamViewSideMenu, {
120
+ isTeamComplianceMenuItemVisible,
121
+ } from "../../../../App/FeatureSet/Dashboard/src/Pages/Teams/View/SideMenu";
122
+ import {
123
+ AuditLogsTableProps,
124
+ DASHBOARD_ENTERPRISE_PLUGIN_KEYS,
125
+ } from "../../../../App/FeatureSet/Dashboard/src/Enterprise/EnterprisePlugins";
126
+ import PageComponentProps from "../../../../App/FeatureSet/Dashboard/src/Pages/PageComponentProps";
127
+ import { getDashboardPlugins } from "../../../../App/FeatureSet/Dashboard/src/Enterprise/Plugins";
128
+ import Route from "../../../Types/API/Route";
129
+ import { PlanType } from "../../../Types/Billing/SubscriptionPlan";
130
+ import ObjectID from "../../../Types/ObjectID";
131
+ import ProjectUtil from "../../../UI/Utils/Project";
132
+ import {
133
+ PROJECT_ID,
134
+ goTo,
135
+ linksIn,
136
+ renderMenu,
137
+ sectionTitlesInOrder,
138
+ } from "./SideMenuHarness";
139
+
140
+ /*
141
+ * Compile-time: the shell's props ARE the contract's props, both ways, so the
142
+ * shell and the Enterprise body cannot drift apart without this file failing
143
+ * to type-check.
144
+ */
145
+ type Exactly<A, B> = [A] extends [B] ? ([B] extends [A] ? true : false) : false;
146
+ const AUDIT_LOGS_TABLE_PROPS_MATCH: Exactly<
147
+ AuditLogsTableShellProps,
148
+ AuditLogsTableProps
149
+ > = true;
150
+
151
+ // Where the removed status-table shell used to live.
152
+ const REMOVED_STATUS_TABLE_SHELL: string = path.resolve(
153
+ __dirname,
154
+ "..",
155
+ "..",
156
+ "..",
157
+ "..",
158
+ "App",
159
+ "FeatureSet",
160
+ "Dashboard",
161
+ "src",
162
+ "Components",
163
+ "Team",
164
+ "TeamComplianceStatusTable.tsx",
165
+ );
166
+
167
+ type Deployment = "cloud" | "self-hosted-enterprise" | "self-hosted-community";
168
+
169
+ const pinDeployment: (deployment: Deployment, plan?: PlanType) => void = (
170
+ deployment: Deployment,
171
+ plan?: PlanType,
172
+ ): void => {
173
+ billingEnabledForTest = deployment === "cloud";
174
+ // The Cloud runs the Enterprise image: its effective edition is true.
175
+ enterpriseEditionForTest = deployment !== "self-hosted-community";
176
+ currentPlanForTest = plan || null;
177
+ };
178
+
179
+ const SLO_ID: ObjectID = new ObjectID("33333333-3333-4333-8333-333333333333");
180
+
181
+ const PAGE_PROPS: PageComponentProps = {
182
+ pageRoute: new Route("/dashboard/project-id/settings/audit-logs"),
183
+ currentProject: null,
184
+ hasPaymentMethod: true,
185
+ };
186
+
187
+ // What a plugin was rendered with, per plugin key.
188
+ let receivedProps: Record<string, unknown> = {};
189
+
190
+ const recordingPlugin: (
191
+ key: string,
192
+ ) => FunctionComponent<Record<string, unknown>> = (
193
+ key: string,
194
+ ): FunctionComponent<Record<string, unknown>> => {
195
+ const Plugin: FunctionComponent<Record<string, unknown>> = (
196
+ props: Record<string, unknown>,
197
+ ): ReactElement => {
198
+ receivedProps[key] = props;
199
+ return <div data-testid={`plugin-${key}`} />;
200
+ };
201
+
202
+ return Plugin;
203
+ };
204
+
205
+ let lazyLoads: number = 0;
206
+
207
+ const lazyPlugin: (
208
+ key: string,
209
+ ) => React.ExoticComponent<Record<string, unknown>> = (
210
+ key: string,
211
+ ): React.ExoticComponent<Record<string, unknown>> => {
212
+ return React.lazy(
213
+ async (): Promise<{
214
+ default: FunctionComponent<Record<string, unknown>>;
215
+ }> => {
216
+ lazyLoads += 1;
217
+ return { default: recordingPlugin(key) };
218
+ },
219
+ );
220
+ };
221
+
222
+ const installPlugins: () => void = (): void => {
223
+ pluginsForTest = {
224
+ AuditLogsTable: recordingPlugin("AuditLogsTable"),
225
+ SettingsAuditLogsSettings: recordingPlugin("SettingsAuditLogsSettings"),
226
+ TeamCompliance: recordingPlugin("TeamCompliance"),
227
+ };
228
+ };
229
+
230
+ // The two upsell wordings the audit-log card uses.
231
+ const AUDIT_PLAN_PITCH: string =
232
+ "Audit Logs are available on the Enterprise plan. Upgrade to turn on audit logging for this project.";
233
+ const AUDIT_EDITION_PITCH: string =
234
+ "Audit Logs are a OneUptime Enterprise Edition feature. Switch to the Enterprise Edition build to enable audit logging.";
235
+
236
+ beforeEach(() => {
237
+ pinDeployment("self-hosted-community");
238
+ pluginsForTest = {};
239
+ receivedProps = {};
240
+ lazyLoads = 0;
241
+
242
+ /*
243
+ * A spy rather than a module mock: ProjectUtil is a class of statics, which
244
+ * an object spread would drop, and the side menu needs the real
245
+ * getCurrentProjectId to build its links.
246
+ */
247
+ jest.spyOn(ProjectUtil, "getCurrentPlan").mockImplementation((() => {
248
+ return currentPlanForTest;
249
+ }) as never);
250
+ });
251
+
252
+ afterEach(() => {
253
+ cleanup();
254
+ jest.restoreAllMocks();
255
+ });
256
+
257
+ describe("the shell contract", () => {
258
+ test("the shell's props are exactly the contract's props", () => {
259
+ expect(AUDIT_LOGS_TABLE_PROPS_MATCH).toBe(true);
260
+ });
261
+
262
+ test("this jest config (a Community build) has no audit-log or compliance plugin", () => {
263
+ pluginsForTest = null;
264
+
265
+ const plugins: Record<string, unknown> = getDashboardPlugins() as Record<
266
+ string,
267
+ unknown
268
+ >;
269
+
270
+ expect(plugins["AuditLogsTable"]).toBeUndefined();
271
+ expect(plugins["SettingsAuditLogsSettings"]).toBeUndefined();
272
+ expect(plugins["TeamCompliance"]).toBeUndefined();
273
+ });
274
+
275
+ test("the member status table is not a plugin key, and core has no shell for it", () => {
276
+ expect(DASHBOARD_ENTERPRISE_PLUGIN_KEYS).toContain("TeamCompliance");
277
+ expect(DASHBOARD_ENTERPRISE_PLUGIN_KEYS).not.toContain(
278
+ "TeamComplianceStatusTable",
279
+ );
280
+ expect(fs.existsSync(REMOVED_STATUS_TABLE_SHELL)).toBe(false);
281
+ // Negative control: the path points where the shell really lived.
282
+ expect(fs.existsSync(path.dirname(REMOVED_STATUS_TABLE_SHELL))).toBe(true);
283
+ });
284
+ });
285
+
286
+ describe("AuditLogsTable (the table on every resource page)", () => {
287
+ const renderTable: () => void = (): void => {
288
+ render(
289
+ <AuditLogsTable
290
+ title="SLO Audit Logs"
291
+ description="Changes people made to this SLO."
292
+ rootResourceId={SLO_ID}
293
+ />,
294
+ );
295
+ };
296
+
297
+ test("self-hosted Enterprise Edition renders the plugin with the caller's props, untouched", () => {
298
+ pinDeployment("self-hosted-enterprise");
299
+ installPlugins();
300
+
301
+ render(
302
+ <AuditLogsTable
303
+ title="Monitor Audit Logs"
304
+ description="Changes to this monitor."
305
+ resourceType="Monitor"
306
+ resourceId={SLO_ID}
307
+ />,
308
+ );
309
+
310
+ expect(screen.getByTestId("plugin-AuditLogsTable")).toBeInTheDocument();
311
+ expect(receivedProps["AuditLogsTable"]).toEqual({
312
+ title: "Monitor Audit Logs",
313
+ description: "Changes to this monitor.",
314
+ resourceType: "Monitor",
315
+ resourceId: SLO_ID,
316
+ });
317
+ });
318
+
319
+ test("the root pointer reaches the plugin as the very same ObjectID", () => {
320
+ pinDeployment("self-hosted-enterprise");
321
+ installPlugins();
322
+
323
+ renderTable();
324
+
325
+ const props: Record<string, unknown> = receivedProps[
326
+ "AuditLogsTable"
327
+ ] as Record<string, unknown>;
328
+
329
+ expect(props["rootResourceId"]).toBe(SLO_ID);
330
+ });
331
+
332
+ test("the Cloud on the Enterprise plan renders the plugin", () => {
333
+ pinDeployment("cloud", PlanType.Enterprise);
334
+ installPlugins();
335
+
336
+ renderTable();
337
+
338
+ expect(screen.getByTestId("plugin-AuditLogsTable")).toBeInTheDocument();
339
+ });
340
+
341
+ test.each([PlanType.Free, PlanType.Growth, PlanType.Scale])(
342
+ "the Cloud on the %s plan gets the plan upsell, and the plugin never loads",
343
+ (plan: PlanType) => {
344
+ pinDeployment("cloud", plan);
345
+ pluginsForTest = { AuditLogsTable: lazyPlugin("AuditLogsTable") };
346
+
347
+ renderTable();
348
+
349
+ expect(screen.getByText(AUDIT_PLAN_PITCH)).toBeInTheDocument();
350
+ expect(screen.getByText("SLO Audit Logs")).toBeInTheDocument();
351
+ expect(
352
+ screen.queryByTestId("plugin-AuditLogsTable"),
353
+ ).not.toBeInTheDocument();
354
+ expect(lazyLoads).toBe(0);
355
+ },
356
+ );
357
+
358
+ test("the self-hosted Community Edition gets the edition upsell, even if a plugin were present", () => {
359
+ pinDeployment("self-hosted-community");
360
+ installPlugins();
361
+
362
+ renderTable();
363
+
364
+ expect(screen.getByText(AUDIT_EDITION_PITCH)).toBeInTheDocument();
365
+ expect(
366
+ screen.queryByTestId("plugin-AuditLogsTable"),
367
+ ).not.toBeInTheDocument();
368
+ });
369
+
370
+ test.each<[Deployment, PlanType | undefined]>([
371
+ ["cloud", PlanType.Enterprise],
372
+ ["self-hosted-enterprise", undefined],
373
+ ])(
374
+ "an eligible %s project on a Community bundle is pointed at the edition, not a plan",
375
+ (deployment: Deployment, plan: PlanType | undefined) => {
376
+ pinDeployment(deployment, plan);
377
+ pluginsForTest = null;
378
+
379
+ renderTable();
380
+
381
+ expect(screen.getByText(AUDIT_EDITION_PITCH)).toBeInTheDocument();
382
+ expect(screen.queryByText(AUDIT_PLAN_PITCH)).not.toBeInTheDocument();
383
+ },
384
+ );
385
+
386
+ test("reads the plugins when it renders, not when it was imported", () => {
387
+ pinDeployment("self-hosted-enterprise");
388
+ pluginsForTest = {};
389
+
390
+ const { unmount } = render(
391
+ <AuditLogsTable title="Audit Logs" description="Everything." />,
392
+ );
393
+ expect(
394
+ screen.queryByTestId("plugin-AuditLogsTable"),
395
+ ).not.toBeInTheDocument();
396
+ unmount();
397
+
398
+ installPlugins();
399
+ render(<AuditLogsTable title="Audit Logs" description="Everything." />);
400
+ expect(screen.getByTestId("plugin-AuditLogsTable")).toBeInTheDocument();
401
+ });
402
+
403
+ test("a lazy plugin downloads once, on first render", async () => {
404
+ pinDeployment("self-hosted-enterprise");
405
+ pluginsForTest = { AuditLogsTable: lazyPlugin("AuditLogsTable") };
406
+
407
+ renderTable();
408
+
409
+ expect(
410
+ await screen.findByTestId("plugin-AuditLogsTable"),
411
+ ).toBeInTheDocument();
412
+ expect(lazyLoads).toBe(1);
413
+ });
414
+ });
415
+
416
+ describe("Settings > Audit Logs", () => {
417
+ test("renders the plugin with the page's own props for an eligible project", () => {
418
+ pinDeployment("cloud", PlanType.Enterprise);
419
+ installPlugins();
420
+
421
+ render(<SettingsAuditLogsSettings {...PAGE_PROPS} />);
422
+
423
+ expect(
424
+ screen.getByTestId("plugin-SettingsAuditLogsSettings"),
425
+ ).toBeInTheDocument();
426
+ expect(receivedProps["SettingsAuditLogsSettings"]).toEqual(PAGE_PROPS);
427
+ });
428
+
429
+ test("the Cloud below the Enterprise plan gets the settings upsell", () => {
430
+ pinDeployment("cloud", PlanType.Scale);
431
+ installPlugins();
432
+
433
+ render(<SettingsAuditLogsSettings {...PAGE_PROPS} />);
434
+
435
+ expect(screen.getByText("Audit Logs Settings")).toBeInTheDocument();
436
+ expect(screen.getByText(AUDIT_PLAN_PITCH)).toBeInTheDocument();
437
+ expect(
438
+ screen.queryByTestId("plugin-SettingsAuditLogsSettings"),
439
+ ).not.toBeInTheDocument();
440
+ });
441
+
442
+ test("the Community Edition gets the edition upsell", () => {
443
+ pinDeployment("self-hosted-community");
444
+ pluginsForTest = null;
445
+
446
+ render(<SettingsAuditLogsSettings {...PAGE_PROPS} />);
447
+
448
+ expect(screen.getByText("Audit Logs Settings")).toBeInTheDocument();
449
+ expect(screen.getByText(AUDIT_EDITION_PITCH)).toBeInTheDocument();
450
+ });
451
+ });
452
+
453
+ describe("Teams > View > Compliance", () => {
454
+ test.each([PlanType.Scale, PlanType.Enterprise])(
455
+ "the Cloud on the %s plan renders the plugin with the page's props",
456
+ (plan: PlanType) => {
457
+ pinDeployment("cloud", plan);
458
+ installPlugins();
459
+
460
+ render(<TeamViewCompliance {...PAGE_PROPS} />);
461
+
462
+ expect(screen.getByTestId("plugin-TeamCompliance")).toBeInTheDocument();
463
+ expect(receivedProps["TeamCompliance"]).toEqual(PAGE_PROPS);
464
+ },
465
+ );
466
+
467
+ test.each([PlanType.Free, PlanType.Growth])(
468
+ "the Cloud on the %s plan gets the Scale upsell",
469
+ (plan: PlanType) => {
470
+ pinDeployment("cloud", plan);
471
+ installPlugins();
472
+
473
+ render(<TeamViewCompliance {...PAGE_PROPS} />);
474
+
475
+ expect(screen.getAllByText("Upgrade to Scale").length).toBeGreaterThan(0);
476
+ expect(
477
+ screen.getByText(TEAM_COMPLIANCE_UPSELL.featureName),
478
+ ).toBeInTheDocument();
479
+ expect(
480
+ screen.queryByTestId("plugin-TeamCompliance"),
481
+ ).not.toBeInTheDocument();
482
+ },
483
+ );
484
+
485
+ test("self-hosted Enterprise Edition renders the plugin", () => {
486
+ pinDeployment("self-hosted-enterprise");
487
+ installPlugins();
488
+
489
+ render(<TeamViewCompliance {...PAGE_PROPS} />);
490
+
491
+ expect(screen.getByTestId("plugin-TeamCompliance")).toBeInTheDocument();
492
+ });
493
+
494
+ test("the Community Edition gets the edition upsell with the page's wording", () => {
495
+ pinDeployment("self-hosted-community");
496
+ pluginsForTest = null;
497
+
498
+ render(<TeamViewCompliance {...PAGE_PROPS} />);
499
+
500
+ expect(screen.getByText("Team Compliance Rules")).toBeInTheDocument();
501
+ expect(
502
+ screen.getAllByText("Learn about Enterprise Edition").length,
503
+ ).toBeGreaterThan(0);
504
+ expect(screen.queryByText("Upgrade to Scale")).not.toBeInTheDocument();
505
+ });
506
+
507
+ test("the upsell keeps the page's wording and its four benefits", () => {
508
+ expect(TEAM_COMPLIANCE_UPSELL.title).toBe("Compliance Settings");
509
+ expect(TEAM_COMPLIANCE_UPSELL.description).toBe(
510
+ "Enforce compliance rules on this team.",
511
+ );
512
+ expect(TEAM_COMPLIANCE_UPSELL.benefits).toHaveLength(4);
513
+ });
514
+ });
515
+
516
+ describe("Teams > View side menu: the Compliance item", () => {
517
+ const TEAM_ID: ObjectID = new ObjectID(
518
+ "00000000-0000-4000-8000-000000000009",
519
+ );
520
+
521
+ test.each<[Deployment, PlanType | undefined, boolean]>([
522
+ ["cloud", PlanType.Free, false],
523
+ ["cloud", PlanType.Growth, false],
524
+ ["cloud", PlanType.Scale, true],
525
+ ["cloud", PlanType.Enterprise, true],
526
+ ["cloud", undefined, false],
527
+ ["self-hosted-enterprise", undefined, true],
528
+ ["self-hosted-community", undefined, false],
529
+ ])(
530
+ "%s on plan %s: shown=%s",
531
+ async (
532
+ deployment: Deployment,
533
+ plan: PlanType | undefined,
534
+ shown: boolean,
535
+ ) => {
536
+ pinDeployment(deployment, plan);
537
+
538
+ expect(isTeamComplianceMenuItemVisible()).toBe(shown);
539
+
540
+ goTo(`/dashboard/${PROJECT_ID}/settings/teams/${TEAM_ID.toString()}`);
541
+ await renderMenu(<TeamViewSideMenu modelId={TEAM_ID} />);
542
+
543
+ expect(sectionTitlesInOrder().includes("Compliance")).toBe(shown);
544
+
545
+ if (shown) {
546
+ expect(linksIn("Compliance")[0]?.href).toContain(
547
+ `${TEAM_ID.toString()}/compliance`,
548
+ );
549
+ }
550
+ },
551
+ );
552
+
553
+ test("the menu and the page agree: shown exactly when the page renders the feature", () => {
554
+ installPlugins();
555
+
556
+ for (const [deployment, plan] of [
557
+ ["cloud", PlanType.Growth],
558
+ ["cloud", PlanType.Scale],
559
+ ["self-hosted-enterprise", undefined],
560
+ ["self-hosted-community", undefined],
561
+ ] as Array<[Deployment, PlanType | undefined]>) {
562
+ pinDeployment(deployment, plan);
563
+
564
+ const { unmount } = render(<TeamViewCompliance {...PAGE_PROPS} />);
565
+ const pageShowsFeature: boolean =
566
+ screen.queryByTestId("plugin-TeamCompliance") !== null;
567
+ unmount();
568
+
569
+ expect(isTeamComplianceMenuItemVisible()).toBe(pageShowsFeature);
570
+ }
571
+ });
572
+ });