@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,667 @@
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 { act, cleanup, render, screen } from "@testing-library/react";
11
+ import React, {
12
+ FunctionComponent,
13
+ ReactElement,
14
+ forwardRef,
15
+ useImperativeHandle,
16
+ } from "react";
17
+
18
+ /*
19
+ * The Dashboard's Enterprise plugin door and the component every enterprise
20
+ * shell renders.
21
+ *
22
+ * A shell (Settings > SSO, the audit log table, ...) stays at its original
23
+ * path in core and renders <EnterprisePluginPage>: the ee plugin when the
24
+ * project may use the feature AND this bundle includes it, the upsell card
25
+ * otherwise. The plugins come from getDashboardPlugins(), which in every
26
+ * Community build - and in this jest config, through its moduleNameMapper -
27
+ * is the empty Community stub.
28
+ *
29
+ * Billing and the edition are pinned in every test: CI's config.env sets
30
+ * BILLING_ENABLED=true.
31
+ */
32
+
33
+ let billingEnabledForTest: boolean = false;
34
+ let enterpriseEditionForTest: boolean = false;
35
+ let currentPlanForTest: string | null = null;
36
+
37
+ const CLOUD_PLAN_ENV: Record<string, string> = {
38
+ SUBSCRIPTION_PLAN_BASIC: "Free,priceMonthlyId1,priceYearlyId1,0,0,1,0",
39
+ SUBSCRIPTION_PLAN_GROWTH: "Growth,priceMonthlyId2,priceYearlyId2,0,0,2,14",
40
+ SUBSCRIPTION_PLAN_SCALE: "Scale,priceMonthlyId3,priceYearlyId3,0,0,3,0",
41
+ SUBSCRIPTION_PLAN_ENTERPRISE:
42
+ "Enterprise,priceMonthlyId4,priceYearlyId4,-1,-1,4,14",
43
+ };
44
+
45
+ jest.mock("../../../UI/Config", () => {
46
+ const actual: Record<string, unknown> = jest.requireActual(
47
+ "../../../UI/Config",
48
+ ) as Record<string, unknown>;
49
+
50
+ const mocked: Record<string, unknown> = { ...actual };
51
+
52
+ Object.defineProperty(mocked, "BILLING_ENABLED", {
53
+ get: (): boolean => {
54
+ return billingEnabledForTest;
55
+ },
56
+ });
57
+
58
+ Object.defineProperty(mocked, "IS_ENTERPRISE_EDITION", {
59
+ get: (): boolean => {
60
+ return enterpriseEditionForTest;
61
+ },
62
+ });
63
+
64
+ mocked["getAllEnvVars"] = (): Record<string, string> => {
65
+ return CLOUD_PLAN_ENV;
66
+ };
67
+
68
+ return mocked;
69
+ });
70
+
71
+ jest.mock("../../../UI/Utils/Project", () => {
72
+ const actual: Record<string, any> = jest.requireActual(
73
+ "../../../UI/Utils/Project",
74
+ ) as Record<string, any>;
75
+
76
+ return {
77
+ __esModule: true,
78
+ ...actual,
79
+ default: {
80
+ ...actual["default"],
81
+ getCurrentPlan: (): string | null => {
82
+ return currentPlanForTest;
83
+ },
84
+ },
85
+ };
86
+ });
87
+
88
+ import EnterprisePluginPage, {
89
+ getUpgradeReason,
90
+ } from "../../../../App/FeatureSet/Dashboard/src/Enterprise/EnterprisePluginPage";
91
+ import { getDashboardPlugins } from "../../../../App/FeatureSet/Dashboard/src/Enterprise/Plugins";
92
+ import {
93
+ DASHBOARD_ENTERPRISE_PLUGIN_KEYS,
94
+ DashboardEnterprisePlugins,
95
+ EnterprisePluginComponent,
96
+ } from "../../../../App/FeatureSet/Dashboard/src/Enterprise/EnterprisePlugins";
97
+ import {
98
+ AUDIT_LOGS_REQUIRED_PLAN,
99
+ IDENTITY_REQUIRED_PLAN,
100
+ } from "../../../../App/FeatureSet/Dashboard/src/Enterprise/EnterpriseEligibility";
101
+ import { EnterpriseUpgradeReason } from "../../../../App/FeatureSet/Dashboard/src/Components/EnterpriseEdition/EnterpriseFeatureUpgrade";
102
+ import AuditLogsEnterpriseUpgrade from "../../../../App/FeatureSet/Dashboard/src/Components/AuditLogs/AuditLogsEnterpriseUpgrade";
103
+ import PageComponentProps from "../../../../App/FeatureSet/Dashboard/src/Pages/PageComponentProps";
104
+ import Route from "../../../Types/API/Route";
105
+ import { PlanType } from "../../../Types/Billing/SubscriptionPlan";
106
+ import IconProp from "../../../Types/Icon/IconProp";
107
+ import ObjectID from "../../../Types/ObjectID";
108
+
109
+ type Deployment = "cloud" | "self-hosted-enterprise" | "self-hosted-community";
110
+
111
+ const pinDeployment: (deployment: Deployment) => void = (
112
+ deployment: Deployment,
113
+ ): void => {
114
+ billingEnabledForTest = deployment === "cloud";
115
+ // The Cloud runs the Enterprise image: its effective edition is true.
116
+ enterpriseEditionForTest = deployment !== "self-hosted-community";
117
+ };
118
+
119
+ const PAGE_PROPS: PageComponentProps = {
120
+ pageRoute: new Route("/dashboard/project-id/settings/sso"),
121
+ currentProject: null,
122
+ hasPaymentMethod: true,
123
+ };
124
+
125
+ const UPSELL: {
126
+ title: string;
127
+ description: string;
128
+ featureName: string;
129
+ benefits: Array<{ icon: IconProp; title: string; subtitle: string }>;
130
+ } = {
131
+ title: "Single Sign On (SSO)",
132
+ description: "Configure SAML SSO for your project.",
133
+ featureName: "SAML Single Sign On",
134
+ benefits: [
135
+ {
136
+ icon: IconProp.Lock,
137
+ title: "Centralized auth",
138
+ subtitle: "Revoke access from one place.",
139
+ },
140
+ ],
141
+ };
142
+
143
+ const FakeSSOPage: FunctionComponent<PageComponentProps> = (
144
+ props: PageComponentProps,
145
+ ): ReactElement => {
146
+ return (
147
+ <div data-testid="fake-sso-plugin">
148
+ {props.pageRoute.toString()}|{String(props.hasPaymentMethod)}
149
+ </div>
150
+ );
151
+ };
152
+
153
+ let lazyLoads: number = 0;
154
+ let releaseLazyPlugin: (() => void) | null = null;
155
+
156
+ /*
157
+ * A React.lazy plugin, the shape ee areas hand over. It counts its loads (an
158
+ * ineligible project must never download the ee chunk) and can be held
159
+ * pending to observe the loading state.
160
+ */
161
+ const makeLazyPlugin: (
162
+ holdUntilReleased: boolean,
163
+ ) => EnterprisePluginComponent<PageComponentProps> = (
164
+ holdUntilReleased: boolean,
165
+ ): EnterprisePluginComponent<PageComponentProps> => {
166
+ return React.lazy(
167
+ async (): Promise<{ default: FunctionComponent<PageComponentProps> }> => {
168
+ lazyLoads += 1;
169
+
170
+ if (holdUntilReleased) {
171
+ await new Promise<void>((resolve: () => void) => {
172
+ releaseLazyPlugin = resolve;
173
+ });
174
+ }
175
+
176
+ return { default: FakeSSOPage };
177
+ },
178
+ );
179
+ };
180
+
181
+ beforeEach(() => {
182
+ billingEnabledForTest = false;
183
+ enterpriseEditionForTest = false;
184
+ currentPlanForTest = null;
185
+ lazyLoads = 0;
186
+ releaseLazyPlugin = null;
187
+ });
188
+
189
+ afterEach(() => {
190
+ cleanup();
191
+ });
192
+
193
+ describe("getUpgradeReason", () => {
194
+ test("an eligible project that still sees the card lacks the Enterprise build, not a plan", () => {
195
+ pinDeployment("cloud");
196
+ expect(getUpgradeReason(true)).toBe(EnterpriseUpgradeReason.Edition);
197
+ });
198
+
199
+ test("an ineligible Cloud project needs a plan", () => {
200
+ pinDeployment("cloud");
201
+ expect(getUpgradeReason(false)).toBe(EnterpriseUpgradeReason.Plan);
202
+ });
203
+
204
+ test("an ineligible self-hosted install needs the Enterprise Edition", () => {
205
+ pinDeployment("self-hosted-community");
206
+ expect(getUpgradeReason(false)).toBe(EnterpriseUpgradeReason.Edition);
207
+ });
208
+ });
209
+
210
+ describe("EnterprisePluginPage", () => {
211
+ test("renders the plugin, with the shell's props, for an eligible Cloud project", () => {
212
+ pinDeployment("cloud");
213
+ currentPlanForTest = PlanType.Scale;
214
+
215
+ render(
216
+ <EnterprisePluginPage
217
+ plugin={FakeSSOPage}
218
+ pluginProps={PAGE_PROPS}
219
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
220
+ upsell={UPSELL}
221
+ />,
222
+ );
223
+
224
+ expect(screen.getByTestId("fake-sso-plugin")).toHaveTextContent(
225
+ "/dashboard/project-id/settings/sso|true",
226
+ );
227
+ expect(screen.queryByText("SAML Single Sign On")).not.toBeInTheDocument();
228
+ });
229
+
230
+ test("shows the plan upsell, and never downloads the plugin, below the tier", () => {
231
+ pinDeployment("cloud");
232
+ currentPlanForTest = PlanType.Growth;
233
+
234
+ render(
235
+ <EnterprisePluginPage
236
+ plugin={makeLazyPlugin(false)}
237
+ pluginProps={PAGE_PROPS}
238
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
239
+ upsell={UPSELL}
240
+ />,
241
+ );
242
+
243
+ expect(screen.getAllByText("Upgrade to Scale")).toHaveLength(2);
244
+ expect(screen.getByText("SAML Single Sign On")).toBeInTheDocument();
245
+ expect(screen.queryByTestId("fake-sso-plugin")).not.toBeInTheDocument();
246
+ expect(lazyLoads).toBe(0);
247
+ });
248
+
249
+ test("uses the page's own tier: Scale is not enough for an Enterprise-tier feature", () => {
250
+ pinDeployment("cloud");
251
+ currentPlanForTest = PlanType.Scale;
252
+
253
+ render(
254
+ <EnterprisePluginPage
255
+ plugin={FakeSSOPage}
256
+ pluginProps={PAGE_PROPS}
257
+ requiredPlan={AUDIT_LOGS_REQUIRED_PLAN}
258
+ upsell={UPSELL}
259
+ />,
260
+ );
261
+
262
+ expect(screen.getAllByText("Upgrade to Enterprise")).toHaveLength(2);
263
+ expect(screen.queryByTestId("fake-sso-plugin")).not.toBeInTheDocument();
264
+ });
265
+
266
+ test("an eligible Cloud project on a Community bundle is pointed at the edition, never told to upgrade", () => {
267
+ pinDeployment("cloud");
268
+ currentPlanForTest = PlanType.Enterprise;
269
+
270
+ render(
271
+ <EnterprisePluginPage
272
+ plugin={undefined}
273
+ pluginProps={PAGE_PROPS}
274
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
275
+ upsell={UPSELL}
276
+ />,
277
+ );
278
+
279
+ expect(screen.getAllByText("Learn about Enterprise Edition")).toHaveLength(
280
+ 2,
281
+ );
282
+ expect(screen.queryByText("Upgrade to Scale")).not.toBeInTheDocument();
283
+ });
284
+
285
+ test("self-hosted Enterprise Edition renders the plugin", () => {
286
+ pinDeployment("self-hosted-enterprise");
287
+
288
+ render(
289
+ <EnterprisePluginPage
290
+ plugin={FakeSSOPage}
291
+ pluginProps={PAGE_PROPS}
292
+ requiredPlan={AUDIT_LOGS_REQUIRED_PLAN}
293
+ upsell={UPSELL}
294
+ />,
295
+ );
296
+
297
+ expect(screen.getByTestId("fake-sso-plugin")).toBeInTheDocument();
298
+ });
299
+
300
+ test("self-hosted Community Edition shows the edition upsell, plugin or not", () => {
301
+ pinDeployment("self-hosted-community");
302
+
303
+ render(
304
+ <EnterprisePluginPage
305
+ plugin={FakeSSOPage}
306
+ pluginProps={PAGE_PROPS}
307
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
308
+ upsell={UPSELL}
309
+ />,
310
+ );
311
+
312
+ expect(screen.getAllByText("Learn about Enterprise Edition")).toHaveLength(
313
+ 2,
314
+ );
315
+ expect(screen.queryByTestId("fake-sso-plugin")).not.toBeInTheDocument();
316
+ });
317
+
318
+ test("self-hosted Enterprise Edition on a Community bundle shows the edition upsell", () => {
319
+ pinDeployment("self-hosted-enterprise");
320
+
321
+ render(
322
+ <EnterprisePluginPage
323
+ plugin={undefined}
324
+ pluginProps={PAGE_PROPS}
325
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
326
+ upsell={UPSELL}
327
+ />,
328
+ );
329
+
330
+ expect(screen.getAllByText("Learn about Enterprise Edition")).toHaveLength(
331
+ 2,
332
+ );
333
+ });
334
+
335
+ test("a lazy plugin shows the in-card loader, then the plugin", async () => {
336
+ pinDeployment("self-hosted-enterprise");
337
+
338
+ render(
339
+ <EnterprisePluginPage
340
+ plugin={makeLazyPlugin(true)}
341
+ pluginProps={PAGE_PROPS}
342
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
343
+ upsell={UPSELL}
344
+ />,
345
+ );
346
+
347
+ expect(await screen.findByTestId("component-loader")).toBeInTheDocument();
348
+ expect(screen.queryByTestId("fake-sso-plugin")).not.toBeInTheDocument();
349
+
350
+ await act(async () => {
351
+ releaseLazyPlugin?.();
352
+ });
353
+
354
+ expect(await screen.findByTestId("fake-sso-plugin")).toBeInTheDocument();
355
+ expect(screen.queryByTestId("component-loader")).not.toBeInTheDocument();
356
+ expect(lazyLoads).toBe(1);
357
+ });
358
+
359
+ test("uses a caller's loading element while the plugin downloads", async () => {
360
+ pinDeployment("self-hosted-enterprise");
361
+
362
+ render(
363
+ <EnterprisePluginPage
364
+ plugin={makeLazyPlugin(true)}
365
+ pluginProps={PAGE_PROPS}
366
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
367
+ upsell={UPSELL}
368
+ loadingElement={<div data-testid="custom-loading" />}
369
+ />,
370
+ );
371
+
372
+ expect(await screen.findByTestId("custom-loading")).toBeInTheDocument();
373
+ expect(screen.queryByTestId("component-loader")).not.toBeInTheDocument();
374
+
375
+ await act(async () => {
376
+ releaseLazyPlugin?.();
377
+ });
378
+
379
+ expect(await screen.findByTestId("fake-sso-plugin")).toBeInTheDocument();
380
+ });
381
+
382
+ test("isEligible overrides the plan and edition check, both ways", () => {
383
+ pinDeployment("cloud");
384
+ currentPlanForTest = PlanType.Free;
385
+
386
+ const { unmount } = render(
387
+ <EnterprisePluginPage
388
+ plugin={FakeSSOPage}
389
+ pluginProps={PAGE_PROPS}
390
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
391
+ upsell={UPSELL}
392
+ isEligible={true}
393
+ />,
394
+ );
395
+ expect(screen.getByTestId("fake-sso-plugin")).toBeInTheDocument();
396
+ unmount();
397
+
398
+ pinDeployment("self-hosted-enterprise");
399
+ render(
400
+ <EnterprisePluginPage
401
+ plugin={FakeSSOPage}
402
+ pluginProps={PAGE_PROPS}
403
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
404
+ upsell={UPSELL}
405
+ isEligible={false}
406
+ />,
407
+ );
408
+ expect(screen.queryByTestId("fake-sso-plugin")).not.toBeInTheDocument();
409
+ expect(screen.getByText("SAML Single Sign On")).toBeInTheDocument();
410
+ });
411
+
412
+ test("renderUpsell replaces the card and is told why it is showing", () => {
413
+ pinDeployment("cloud");
414
+ const reasons: Array<EnterpriseUpgradeReason> = [];
415
+
416
+ const renderAuditUpsell: (
417
+ reason: EnterpriseUpgradeReason,
418
+ ) => ReactElement = (reason: EnterpriseUpgradeReason): ReactElement => {
419
+ reasons.push(reason);
420
+ return (
421
+ <AuditLogsEnterpriseUpgrade
422
+ title="Audit Logs"
423
+ description="Every change made in this project."
424
+ reason={reason}
425
+ />
426
+ );
427
+ };
428
+
429
+ // Below the tier: sell the plan.
430
+ currentPlanForTest = PlanType.Scale;
431
+ const { unmount } = render(
432
+ <EnterprisePluginPage
433
+ plugin={FakeSSOPage}
434
+ pluginProps={PAGE_PROPS}
435
+ requiredPlan={AUDIT_LOGS_REQUIRED_PLAN}
436
+ renderUpsell={renderAuditUpsell}
437
+ />,
438
+ );
439
+ expect(
440
+ screen.getByText(
441
+ "Audit Logs are available on the Enterprise plan. Upgrade to turn on audit logging for this project.",
442
+ ),
443
+ ).toBeInTheDocument();
444
+ unmount();
445
+
446
+ // On the tier, but the bundle has no plugin: the edition, not a plan.
447
+ currentPlanForTest = PlanType.Enterprise;
448
+ render(
449
+ <EnterprisePluginPage
450
+ plugin={undefined}
451
+ pluginProps={PAGE_PROPS}
452
+ requiredPlan={AUDIT_LOGS_REQUIRED_PLAN}
453
+ renderUpsell={renderAuditUpsell}
454
+ />,
455
+ );
456
+ expect(
457
+ screen.getByText(
458
+ "Audit Logs are a OneUptime Enterprise Edition feature. Switch to the Enterprise Edition build to enable audit logging.",
459
+ ),
460
+ ).toBeInTheDocument();
461
+
462
+ expect(reasons).toEqual([
463
+ EnterpriseUpgradeReason.Plan,
464
+ EnterpriseUpgradeReason.Edition,
465
+ ]);
466
+ });
467
+
468
+ test("forwards a ref through to the plugin, lazy or not", async () => {
469
+ pinDeployment("self-hosted-enterprise");
470
+
471
+ /*
472
+ * No contract key takes a ref today (the member compliance status table,
473
+ * the one that did, is imported by ee's Compliance page directly), so the
474
+ * props and handle are this test's own: a future ref-taking plugin must
475
+ * still get the caller's ref.
476
+ */
477
+ interface FakeTableProps {
478
+ teamId: ObjectID;
479
+ }
480
+
481
+ interface FakeTableRef {
482
+ refresh: () => void;
483
+ }
484
+
485
+ /*
486
+ * Spelled out rather than as RefAttributes: since @types/react 18.3
487
+ * RefAttributes also allows legacy string refs, which React.lazy strips -
488
+ * so a lazy forwardRef table would not fit a RefAttributes slot.
489
+ */
490
+ type FakeTablePluginProps = FakeTableProps & {
491
+ ref?: React.Ref<FakeTableRef> | undefined;
492
+ };
493
+
494
+ const refreshes: Array<string> = [];
495
+
496
+ const FakeComplianceTable: React.ForwardRefExoticComponent<
497
+ FakeTableProps & React.RefAttributes<FakeTableRef>
498
+ > = forwardRef<FakeTableRef, FakeTableProps>(
499
+ (props: FakeTableProps, ref: React.Ref<FakeTableRef>): ReactElement => {
500
+ useImperativeHandle(ref, () => {
501
+ return {
502
+ refresh: (): void => {
503
+ refreshes.push(props.teamId.toString());
504
+ },
505
+ };
506
+ });
507
+
508
+ return <div data-testid="fake-compliance-table" />;
509
+ },
510
+ );
511
+ FakeComplianceTable.displayName = "FakeComplianceTable";
512
+
513
+ const teamId: ObjectID = new ObjectID(
514
+ "11111111-1111-4111-8111-111111111111",
515
+ );
516
+
517
+ /*
518
+ * Typed as a contract slot would be: a forwardRef table fits it both
519
+ * eagerly and behind React.lazy (a RefAttributes-typed slot would reject
520
+ * the lazy one under @types/react 18.3, which this package installs).
521
+ */
522
+ const plugins: Array<EnterprisePluginComponent<FakeTablePluginProps>> = [
523
+ FakeComplianceTable,
524
+ React.lazy(async (): Promise<{ default: typeof FakeComplianceTable }> => {
525
+ return { default: FakeComplianceTable };
526
+ }),
527
+ ];
528
+
529
+ for (const plugin of plugins) {
530
+ const tableRef: React.RefObject<FakeTableRef> =
531
+ React.createRef<FakeTableRef>();
532
+
533
+ const { unmount } = render(
534
+ <EnterprisePluginPage<FakeTablePluginProps>
535
+ plugin={plugin}
536
+ pluginProps={{ teamId, ref: tableRef }}
537
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
538
+ upsell={UPSELL}
539
+ />,
540
+ );
541
+
542
+ expect(
543
+ await screen.findByTestId("fake-compliance-table"),
544
+ ).toBeInTheDocument();
545
+
546
+ tableRef.current?.refresh();
547
+ unmount();
548
+ }
549
+
550
+ expect(refreshes).toEqual([teamId.toString(), teamId.toString()]);
551
+ });
552
+ });
553
+
554
+ describe("the Community plugin door (what this jest config resolves)", () => {
555
+ test("getDashboardPlugins() is the empty Community stub", () => {
556
+ const plugins: DashboardEnterprisePlugins = getDashboardPlugins();
557
+
558
+ expect(plugins).toEqual({});
559
+ expect(plugins.buildMarker).toBeUndefined();
560
+
561
+ for (const key of DASHBOARD_ENTERPRISE_PLUGIN_KEYS) {
562
+ expect([key, plugins[key]]).toEqual([key, undefined]);
563
+ }
564
+ });
565
+
566
+ test("returns the same object on every call", () => {
567
+ expect(getDashboardPlugins()).toBe(getDashboardPlugins());
568
+ });
569
+
570
+ test("names every screen a plugin can provide, once", () => {
571
+ expect([...DASHBOARD_ENTERPRISE_PLUGIN_KEYS].sort()).toEqual(
572
+ [
573
+ "AuditLogsTable",
574
+ "SettingsAuditLogsSettings",
575
+ "SettingsOIDC",
576
+ "SettingsSCIM",
577
+ "SettingsSSO",
578
+ "StatusPageOIDC",
579
+ "StatusPageSCIM",
580
+ "StatusPageSSO",
581
+ "TeamCompliance",
582
+ "LicenseManager",
583
+ ].sort(),
584
+ );
585
+ expect(new Set(DASHBOARD_ENTERPRISE_PLUGIN_KEYS).size).toBe(
586
+ DASHBOARD_ENTERPRISE_PLUGIN_KEYS.length,
587
+ );
588
+ // The member status table is only ever rendered by ee's Compliance page.
589
+ expect(DASHBOARD_ENTERPRISE_PLUGIN_KEYS).not.toContain(
590
+ "TeamComplianceStatusTable",
591
+ );
592
+ });
593
+
594
+ test("a shell reading the real door on a Community build shows the upsell even when eligible", () => {
595
+ pinDeployment("cloud");
596
+ currentPlanForTest = PlanType.Enterprise;
597
+
598
+ render(
599
+ <EnterprisePluginPage
600
+ plugin={getDashboardPlugins().SettingsSSO}
601
+ pluginProps={PAGE_PROPS}
602
+ requiredPlan={IDENTITY_REQUIRED_PLAN}
603
+ upsell={UPSELL}
604
+ />,
605
+ );
606
+
607
+ expect(screen.getAllByText("Learn about Enterprise Edition")).toHaveLength(
608
+ 2,
609
+ );
610
+ });
611
+ });
612
+
613
+ describe("the plugin door with other plugin modules", () => {
614
+ /*
615
+ * These swap what "@oneuptime/ee-dashboard" resolves to, so they run on a
616
+ * fresh module registry and render nothing afterwards.
617
+ */
618
+ beforeEach(() => {
619
+ jest.resetModules();
620
+ });
621
+
622
+ afterEach(() => {
623
+ jest.dontMock("@oneuptime/ee-dashboard");
624
+ jest.resetModules();
625
+ });
626
+
627
+ test("hands back the Enterprise plugin object as is", async () => {
628
+ const enterprisePlugins: DashboardEnterprisePlugins = {
629
+ buildMarker: "ONEUPTIME_EE_DASHBOARD_PLUGIN_v1",
630
+ SettingsSSO: FakeSSOPage,
631
+ };
632
+
633
+ jest.doMock("@oneuptime/ee-dashboard", () => {
634
+ return { __esModule: true, default: enterprisePlugins };
635
+ });
636
+
637
+ const door: { getDashboardPlugins: () => DashboardEnterprisePlugins } =
638
+ await import(
639
+ "../../../../App/FeatureSet/Dashboard/src/Enterprise/Plugins"
640
+ );
641
+
642
+ expect(door.getDashboardPlugins()).toBe(enterprisePlugins);
643
+ expect(door.getDashboardPlugins().SettingsSSO).toBe(FakeSSOPage);
644
+ });
645
+
646
+ test("fails loudly, naming the rule, when read before the plugin module finished loading", async () => {
647
+ /*
648
+ * What a top-level read sees in the Enterprise bundle's import cycle: the
649
+ * plugin binding is still undefined. A silent {} would quietly turn an
650
+ * Enterprise install into the Community UI.
651
+ */
652
+ jest.doMock("@oneuptime/ee-dashboard", () => {
653
+ return { __esModule: true, default: undefined };
654
+ });
655
+
656
+ const door: { getDashboardPlugins: () => DashboardEnterprisePlugins } =
657
+ await import(
658
+ "../../../../App/FeatureSet/Dashboard/src/Enterprise/Plugins"
659
+ );
660
+
661
+ expect(() => {
662
+ return door.getDashboardPlugins();
663
+ }).toThrow(
664
+ "getDashboardPlugins() ran before the Enterprise plugin module finished loading. Call it inside a render or function body, never at module top level.",
665
+ );
666
+ });
667
+ });