@oneuptime/common 13.0.8 → 14.0.1
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.
- package/Models/AnalyticsModels/AuditLog.ts +23 -15
- package/Models/DatabaseModels/GlobalConfig.ts +24 -0
- package/Models/DatabaseModels/Index.ts +4 -0
- package/Models/DatabaseModels/Monitor.ts +3 -2
- package/Models/DatabaseModels/MonitorTemplate.ts +2 -1
- package/Models/DatabaseModels/ServiceLevelObjectiveFeed.ts +2 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.ts +522 -0
- package/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.ts +38 -4
- package/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.ts +603 -0
- package/Scripts/generate-service-worker.js +65 -4
- package/Server/API/BaseAPI.ts +26 -5
- package/Server/API/GlobalConfigAPI.ts +228 -462
- package/Server/API/ProjectOIDC.ts +25 -16
- package/Server/API/ProjectSSO.ts +24 -16
- package/Server/API/StatusPageAPI.ts +100 -42
- package/Server/API/TeamMemberAPI.ts +10 -1
- package/Server/Enterprise/EnterpriseEdition.ts +649 -0
- package/Server/Enterprise/EnterpriseFeature.ts +48 -0
- package/Server/Enterprise/EnterpriseLicenseSnapshot.ts +192 -0
- package/Server/Enterprise/EnterpriseServerModule.ts +233 -0
- package/Server/EnvironmentConfig.ts +147 -2
- package/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.ts +25 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.ts +248 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.ts +19 -0
- package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +6 -0
- package/Server/Middleware/UserAuthorization.ts +38 -16
- package/Server/Services/AuditLogService.ts +84 -1079
- package/Server/Services/DatabaseService.ts +10 -0
- package/Server/Services/EnterpriseLicenseService.ts +38 -0
- package/Server/Services/GlobalConfigService.ts +80 -1
- package/Server/Services/Index.ts +4 -0
- package/Server/Services/MonitorProbeService.ts +116 -20
- package/Server/Services/MonitorService.ts +59 -6
- package/Server/Services/MonitorStatusTimelineService.ts +284 -0
- package/Server/Services/MonitorTemplateService.ts +26 -0
- package/Server/Services/ProjectService.ts +284 -0
- package/Server/Services/RumSessionPinService.ts +25 -6
- package/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.ts +385 -0
- package/Server/Services/ServiceLevelObjectiveLabelRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.ts +92 -16
- package/Server/Services/ServiceLevelObjectiveMonitorRuleService.ts +36 -1
- package/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.ts +521 -0
- package/Server/Services/ServiceLevelObjectiveOwnerRuleService.ts +51 -0
- package/Server/Services/ServiceLevelObjectiveService.ts +28 -0
- package/Server/Services/StatusPagePrivateUserService.ts +7 -3
- package/Server/Services/StatusPageService.ts +78 -1
- package/Server/Services/TeamMemberService.ts +11 -0
- package/Server/Services/TeamService.ts +10 -0
- package/Server/Services/UserService.ts +10 -17
- package/Server/Types/Database/Permissions/CreatePermission.ts +15 -0
- package/Server/Types/Database/Permissions/EditionPermission.ts +208 -18
- package/Server/Types/Database/Permissions/TablePermission.ts +10 -3
- package/Server/Types/Database/Permissions/UpdatePermission.ts +29 -0
- package/Server/Types/Markdown.ts +41 -0
- package/Server/Types/Workflow/Components/Telegram/SendMessageToChat.ts +27 -1
- package/Server/Utils/AI/Toolbox/SloTools.ts +1 -0
- package/Server/Utils/CommunityEditionSsoReport.ts +361 -0
- package/Server/Utils/EditionEnforcement.ts +233 -0
- package/Server/Utils/FrontendEnvironment.ts +41 -2
- package/Server/Utils/InstanceHealth/RedisHealth.ts +12 -277
- package/Server/Utils/Monitor/AffectedResourceList.ts +148 -0
- package/Server/Utils/Monitor/Criteria/CompareCriteria.ts +1 -1
- package/Server/Utils/Monitor/Criteria/EvaluateOverTime.ts +10 -1
- package/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.ts +1 -1
- package/Server/Utils/Monitor/MonitorCriteriaEvaluator.ts +720 -465
- package/Server/Utils/Monitor/MonitoringIntervalValidator.ts +116 -0
- package/Server/Utils/Monitor/RootCauseList.ts +139 -0
- package/Server/Utils/Rules/RuleRun/RuleRunRegistry.ts +28 -0
- package/Server/Utils/Slo/SloRulePatternValidator.ts +42 -0
- package/Server/Utils/Workspace/Slack/Slack.ts +423 -10
- package/Tests/App/Accounts/LoginPasskey.test.tsx +18 -0
- package/Tests/App/Accounts/LoginSsoEdition.test.tsx +616 -0
- package/Tests/App/AdminDashboard/AdminAuthenticationSsoEdition.test.tsx +217 -0
- package/Tests/App/AdminDashboard/AdminEnterprisePluginPage.test.tsx +357 -0
- package/Tests/App/AdminDashboard/EnterpriseLicensesShell.test.tsx +214 -0
- package/Tests/App/AdminDashboard/GlobalSSOEnterpriseShells.test.tsx +271 -0
- package/Tests/App/AdminDashboard/HealthShells.test.tsx +659 -0
- package/Tests/App/Dashboard/AuditLogsAndComplianceShells.test.tsx +572 -0
- package/Tests/App/Dashboard/EnterpriseFeatureUpgrade.test.tsx +547 -0
- package/Tests/App/Dashboard/EnterprisePluginPage.test.tsx +667 -0
- package/Tests/App/Dashboard/FeedFilterSortIntegration.test.tsx +1632 -0
- package/Tests/App/Dashboard/FeedOptionsLocales.test.ts +250 -0
- package/Tests/App/Dashboard/FeedOrdering.test.ts +279 -9
- package/Tests/App/Dashboard/IdentityEnterpriseShells.test.tsx +319 -0
- package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +60 -1
- package/Tests/App/Dashboard/InvestigationPanel.test.tsx +594 -3
- package/Tests/App/Dashboard/OnboardingSsoEmptyState.test.tsx +185 -0
- package/Tests/App/Dashboard/ProductOrientation.test.tsx +646 -0
- package/Tests/App/Dashboard/ResourceFeed.test.tsx +612 -2
- package/Tests/App/Dashboard/ResourceFeedPageWiring.test.ts +30 -0
- package/Tests/App/Dashboard/ResourceFeedPagesFilterSort.test.tsx +1202 -0
- package/Tests/App/Dashboard/ScheduledMaintenanceFeedRefresh.test.tsx +52 -1
- package/Tests/App/Dashboard/SecurityEventConnectionDiagnostics.test.tsx +45 -9
- package/Tests/App/Dashboard/SecurityEventDetailPanel.test.tsx +399 -0
- package/Tests/App/Dashboard/SecurityEventListRow.test.tsx +214 -0
- package/Tests/App/Dashboard/SecurityEventsEmptyState.test.tsx +1 -83
- package/Tests/App/Dashboard/SecurityEventsNavTabs.test.tsx +248 -0
- package/Tests/App/Dashboard/SecurityEventsViewer.test.tsx +1203 -0
- package/Tests/App/Dashboard/SloFeed.test.tsx +106 -1
- package/Tests/App/Dashboard/SloMonitorRuleCriteria.test.tsx +566 -0
- package/Tests/App/Dashboard/SloNavigationWiring.test.tsx +6 -4
- package/Tests/App/Dashboard/SloNoticeBanner.test.tsx +186 -0
- package/Tests/App/Dashboard/SloOverviewKpiStrip.test.tsx +388 -44
- package/Tests/App/Dashboard/SloOverviewLayout.test.tsx +613 -0
- package/Tests/App/Dashboard/UserEmailCallSites.test.tsx +11 -91
- package/Tests/App/StatusPage/StatusPageSsoEmptyState.test.tsx +319 -0
- package/Tests/Helpers/RefreshAwareApiScan.ts +757 -0
- package/Tests/Helpers/TenantScopedRequestScan.ts +515 -0
- package/Tests/Models/DatabaseModels/ResourceFeedModels.test.ts +0 -8
- package/Tests/Models/DatabaseModels/SloLabelAndOwnerRuleModels.test.ts +404 -0
- package/Tests/Models/DatabaseModels/SloOverhaulModels.test.ts +17 -1
- package/Tests/Models/DatabaseModels/StaticRuleCriteriaInheritance.test.ts +4 -2
- package/Tests/Scripts/GenerateServiceWorker.test.ts +931 -0
- package/Tests/Server/API/BaseAPICreateItemDoesNotMutateModel.test.ts +130 -0
- package/Tests/Server/API/GlobalConfigLicense.test.ts +742 -497
- package/Tests/Server/API/OnCallReadinessAPI.test.ts +35 -909
- package/Tests/Server/API/SsoProviderListingsEdition.test.ts +432 -0
- package/Tests/Server/API/TeamMemberLeaveScimLockEdition.test.ts +252 -0
- package/Tests/Server/Enterprise/EnterpriseEdition.test.ts +824 -0
- package/Tests/Server/Enterprise/EnterpriseFeatureActive.test.ts +643 -0
- package/Tests/Server/Enterprise/EnterpriseLicenseSnapshot.test.ts +294 -0
- package/Tests/Server/Enterprise/EnterpriseModelFeatureMap.test.ts +93 -0
- package/Tests/Server/Enterprise/EnterpriseOnlyModulesLiveInEe.test.ts +582 -0
- package/Tests/Server/Enterprise/EnterpriseServerModule.test.ts +247 -0
- package/Tests/Server/Enterprise/FakeEnterpriseModule.ts +502 -0
- package/Tests/Server/Enterprise/TestBillingFlag.ts +70 -0
- package/Tests/Server/EnvironmentConfigEnterpriseEdition.test.ts +314 -0
- package/Tests/Server/Infrastructure/ContainerBootConfiguration.test.ts +289 -0
- package/Tests/Server/Infrastructure/E2EClickHouseFixtureAccess.test.ts +5 -1
- package/Tests/Server/Infrastructure/Postgres/AddConfigurableRuleCriteriaMigration.test.ts +3 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloLabelAndOwnerRulesMigration.test.ts +407 -0
- package/Tests/Server/Infrastructure/Postgres/AddSloMonitorRuleMonitorTypeMigration.test.ts +171 -0
- package/Tests/Server/Infrastructure/Postgres/SloProductOverhaulMigration.test.ts +88 -4
- package/Tests/Server/Middleware/UserAuthorization.test.ts +37 -2
- package/Tests/Server/Middleware/UserAuthorizationEditionEnforcement.test.ts +516 -0
- package/Tests/Server/Services/AuditLogService.test.ts +460 -990
- package/Tests/Server/Services/CreateAndReadResponsesKeepIds.test.ts +263 -0
- package/Tests/Server/Services/DatabaseServiceRuleCriteriaValidation.test.ts +104 -0
- package/Tests/Server/Services/EnterpriseLicenseServiceKeyGeneration.test.ts +151 -0
- package/Tests/Server/Services/GlobalConfigServiceLicenseColumns.test.ts +357 -0
- package/Tests/Server/Services/MonitorDestinationInfoIPv6.test.ts +101 -0
- package/Tests/Server/Services/MonitorProbeServiceIntervalScheduling.test.ts +333 -0
- package/Tests/Server/Services/MonitorStatusTimelineDailyAggregates.test.ts +303 -0
- package/Tests/Server/Services/ProjectServiceAuditLogLicense.test.ts +701 -0
- package/Tests/Server/Services/ProjectServiceAuditLogSettingsCache.test.ts +31 -35
- package/Tests/Server/Services/RuleRun/LabelRuleEnginesGroupBRun.test.ts +48 -1
- package/Tests/Server/Services/RuleRun/OwnerRuleEnginesGroupBRun.test.ts +30 -0
- package/Tests/Server/Services/ScimPushGroupsTeamLocksEdition.test.ts +431 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleEngines.test.ts +1170 -0
- package/Tests/Server/Services/ServiceLevelObjectiveLabelAndOwnerRuleServices.test.ts +172 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.test.ts +323 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleService.test.ts +115 -0
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorRuleTriggers.test.ts +21 -2
- package/Tests/Server/Services/ServiceLevelObjectiveMonitorTypePostgres.test.ts +480 -0
- package/Tests/Server/Services/ServiceLevelObjectiveService.test.ts +162 -0
- package/Tests/Server/Services/SsoRequirementReadMasking.test.ts +419 -0
- package/Tests/Server/Services/SsoRequirementWriteGuard.test.ts +769 -0
- package/Tests/Server/Services/StaticRuleCriteriaRuntimeCoverage.test.ts +45 -6
- package/Tests/Server/Services/StatusPagePrivateUserInvitationPolicy.test.ts +94 -0
- package/Tests/Server/Services/UserAuthenticationService.test.ts +35 -0
- package/Tests/Server/Services/UserServiceSeatLimit.test.ts +94 -56
- package/Tests/Server/Types/Database/FeedEventTypeFilterQuery.test.ts +745 -0
- package/Tests/Server/Types/Database/Permissions/EditionPermission.test.ts +1823 -0
- package/Tests/Server/Types/Markdown.test.ts +183 -1
- package/Tests/Server/Types/Workflow/Components/ApiComponentSsrf.test.ts +49 -0
- package/Tests/Server/Types/Workflow/Components/TelegramSendMessageToChat.test.ts +331 -0
- package/Tests/Server/Utils/AI/SloTools.test.ts +10 -0
- package/Tests/Server/Utils/CommunityEditionSsoReport.test.ts +565 -0
- package/Tests/Server/Utils/EditionEnforcement.test.ts +303 -0
- package/Tests/Server/Utils/FrontendEnvironment.test.ts +367 -0
- package/Tests/Server/Utils/InstanceHealth/RedisHealth.test.ts +38 -418
- package/Tests/Server/Utils/Monitor/AffectedResourceList.test.ts +518 -0
- package/Tests/Server/Utils/Monitor/Criteria/EvaluateOverTime.test.ts +24 -4
- package/Tests/Server/Utils/Monitor/Criteria/MetricMonitorCriteriaAnomalyUnits.test.ts +1 -1
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluator.test.ts +1339 -96
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorBreachingSamples.test.ts +1101 -0
- package/Tests/Server/Utils/Monitor/MonitorCriteriaEvaluatorMetricUnits.test.ts +106 -80
- package/Tests/Server/Utils/Monitor/MonitoringIntervalValidator.test.ts +188 -0
- package/Tests/Server/Utils/Monitor/RootCauseList.test.ts +252 -0
- package/Tests/Server/Utils/Rules/RuleRun/RuleRunPermission.test.ts +154 -0
- package/Tests/Server/Utils/SSRFProtection.test.ts +111 -0
- package/Tests/Server/Utils/Slo/SloRulePatternValidator.test.ts +67 -0
- package/Tests/Server/Utils/VM/VMRunnerSsrf.test.ts +213 -0
- package/Tests/Server/Utils/Workspace/Slack/SlackMarkdownSectionSplit.test.ts +1209 -0
- package/Tests/Types/API/HostnameFromAuthority.test.ts +20 -10
- package/Tests/Types/API/HostnameIPv6.test.ts +149 -0
- package/Tests/Types/API/Route.test.ts +56 -0
- package/Tests/Types/API/URLSchemeLikePath.test.ts +304 -0
- package/Tests/Types/Database/CanonicalModelInstance.test.ts +190 -0
- package/Tests/UI/Components/EditionLabelLapseCopy.ts +104 -0
- package/Tests/UI/Components/EditionLabelLicenseManagerWiring.test.tsx +254 -0
- package/Tests/UI/Components/EditionLabelLicenseRefresh.test.tsx +84 -178
- package/Tests/UI/Components/EditionLabelLicenseStatus.test.tsx +1586 -0
- package/Tests/UI/Components/EditionLabelLicenseWritesGuard.test.tsx +157 -0
- package/Tests/UI/Components/FeedOptions.test.ts +1404 -0
- package/Tests/UI/Components/FeedOptionsButton.test.tsx +2603 -0
- package/Tests/UI/Components/Graphs/DayUptimeGraph.test.tsx +49 -2
- package/Tests/UI/Components/Icon.test.tsx +26 -0
- package/Tests/UI/Components/MarkdownConverters.test.ts +684 -0
- package/Tests/UI/Components/ModelListEmptyState.test.tsx +289 -0
- package/Tests/UI/Components/RuleCriteria/RuleCriteriaModelTable.test.tsx +3 -3
- package/Tests/UI/Components/TelemetryViewer/TelemetryViewerEmptyContent.test.tsx +131 -0
- package/Tests/UI/Components/useFeedItemsViewKey.test.tsx +1017 -0
- package/Tests/UI/Components/useFeedOptions.test.tsx +1107 -0
- package/Tests/UI/EsbuildEnterpriseAlias.test.ts +1127 -0
- package/Tests/Utils/HostAddressUtil.test.ts +138 -0
- package/Tests/Utils/LabelRuleImportExport.test.ts +102 -0
- package/Tests/Utils/Monitor/MonitorDestinationUtil.test.ts +313 -0
- package/Tests/Utils/Monitor/MonitoringIntervalUtil.test.ts +304 -0
- package/Tests/Utils/Slo/SloDuration.test.ts +115 -24
- package/Tests/Utils/Slo/SloHealth.test.ts +93 -10
- package/Tests/Utils/Slo/SloMonitorRuleCriteria.test.ts +109 -0
- package/Tests/Utils/Slo/SloOverviewText.test.ts +64 -0
- package/Tests/Utils/StatusPage/UptimeDailyAggregateUtil.test.ts +248 -0
- package/Types/API/Hostname.ts +63 -16
- package/Types/API/Route.ts +19 -2
- package/Types/API/URL.ts +26 -2
- package/Types/Database/AccessControl/ColumnAccessControl.ts +19 -7
- package/Types/Database/AccessControl/ColumnBillingAccessControl.ts +19 -7
- package/Types/Database/AccessControl/OwnerOnlyColumn.ts +15 -6
- package/Types/Database/CanonicalModelInstance.ts +102 -0
- package/Types/Database/TableColumn.ts +20 -6
- package/Types/EnterpriseLicense/EnterpriseLicensePeriods.ts +29 -0
- package/Types/IP/IPv6.ts +6 -1
- package/Types/Monitor/MetricMonitor/MetricCriteriaContext.ts +6 -5
- package/Types/Monitor/MetricMonitor/MetricMonitorResponse.ts +9 -0
- package/Types/Monitor/MonitorStep.ts +6 -1
- package/Types/Monitor/ProxmoxAlertTemplates.ts +1 -1
- package/Types/Permission.ts +90 -0
- package/Types/Rules/RuleCriteriaFieldRegistry.ts +11 -0
- package/Types/Rules/RuleRun.ts +4 -0
- package/Types/StatusPage/UptimeDailyAggregate.ts +110 -0
- package/UI/Components/EditionLabel/EditionLabel.tsx +796 -1195
- package/UI/Components/EditionLabel/LicenseManager.ts +119 -0
- package/UI/Components/Feed/FeedOptions.ts +427 -0
- package/UI/Components/Feed/FeedOptionsButton.tsx +692 -0
- package/UI/Components/Feed/useFeedItems.ts +28 -9
- package/UI/Components/Feed/useFeedOptions.ts +225 -0
- package/UI/Components/Graphs/DayUptimeGraph.tsx +123 -15
- package/UI/Components/Icon/Icon.tsx +1 -1
- package/UI/Components/Markdown.tsx/MarkdownConverters.ts +0 -0
- package/UI/Components/ModelList/ModelList.tsx +11 -1
- package/UI/Components/MonitorGraphs/Uptime.tsx +69 -0
- package/UI/Components/TelemetryViewer/TelemetryViewer.tsx +28 -12
- package/UI/esbuild-enterprise.js +263 -0
- package/Utils/EnterpriseLicense/EnterpriseLicenseUsage.ts +7 -2
- package/Utils/HostAddressUtil.ts +94 -0
- package/Utils/LabelRuleImportExport.ts +27 -9
- package/Utils/Monitor/MetricValueFormatter.ts +2 -2
- package/Utils/Monitor/MonitorDestinationUtil.ts +157 -0
- package/Utils/Monitor/MonitoringIntervalUtil.ts +436 -0
- package/Utils/Rules/MonitorTypeRuleCriteria.ts +31 -0
- package/Utils/Slo/SloDuration.ts +22 -6
- package/Utils/Slo/SloHealth.ts +8 -7
- package/Utils/Slo/SloMonitorRuleCriteria.ts +33 -1
- package/Utils/Slo/SloOverviewText.ts +33 -0
- package/Utils/Slo/SloProjection.ts +4 -3
- package/Utils/StatusPage/UptimeDailyAggregateUtil.ts +192 -0
- package/build/dist/Models/AnalyticsModels/AuditLog.js +23 -15
- package/build/dist/Models/AnalyticsModels/AuditLog.js.map +1 -1
- package/build/dist/Models/DatabaseModels/GlobalConfig.js +25 -0
- package/build/dist/Models/DatabaseModels/GlobalConfig.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Index.js +4 -0
- package/build/dist/Models/DatabaseModels/Index.js.map +1 -1
- package/build/dist/Models/DatabaseModels/Monitor.js +2 -2
- package/build/dist/Models/DatabaseModels/Monitor.js.map +1 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js +2 -1
- package/build/dist/Models/DatabaseModels/MonitorTemplate.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js +2 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveFeed.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js +530 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveLabelRule.js.map +1 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js +39 -4
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveMonitorRule.js.map +1 -1
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js +612 -0
- package/build/dist/Models/DatabaseModels/ServiceLevelObjectiveOwnerRule.js.map +1 -0
- package/build/dist/Server/API/BaseAPI.js +26 -5
- package/build/dist/Server/API/BaseAPI.js.map +1 -1
- package/build/dist/Server/API/GlobalConfigAPI.js +148 -344
- package/build/dist/Server/API/GlobalConfigAPI.js.map +1 -1
- package/build/dist/Server/API/ProjectOIDC.js +24 -16
- package/build/dist/Server/API/ProjectOIDC.js.map +1 -1
- package/build/dist/Server/API/ProjectSSO.js +24 -16
- package/build/dist/Server/API/ProjectSSO.js.map +1 -1
- package/build/dist/Server/API/StatusPageAPI.js +93 -43
- package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
- package/build/dist/Server/API/TeamMemberAPI.js +8 -1
- package/build/dist/Server/API/TeamMemberAPI.js.map +1 -1
- package/build/dist/Server/Enterprise/EnterpriseEdition.js +466 -0
- package/build/dist/Server/Enterprise/EnterpriseEdition.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js +39 -0
- package/build/dist/Server/Enterprise/EnterpriseFeature.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js +70 -0
- package/build/dist/Server/Enterprise/EnterpriseLicenseSnapshot.js.map +1 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js +84 -0
- package/build/dist/Server/Enterprise/EnterpriseServerModule.js.map +1 -0
- package/build/dist/Server/EnvironmentConfig.js +84 -2
- package/build/dist/Server/EnvironmentConfig.js.map +1 -1
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js +18 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1793900000000-AddEnterpriseEditionFirstSeenAt.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js +93 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794100000000-AddSloLabelAndOwnerRules.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js +12 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1794200000000-AddSloMonitorRuleMonitorType.js.map +1 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +6 -0
- package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
- package/build/dist/Server/Middleware/UserAuthorization.js +30 -11
- package/build/dist/Server/Middleware/UserAuthorization.js.map +1 -1
- package/build/dist/Server/Services/AuditLogService.js +71 -740
- package/build/dist/Server/Services/AuditLogService.js.map +1 -1
- package/build/dist/Server/Services/DatabaseService.js +7 -0
- package/build/dist/Server/Services/DatabaseService.js.map +1 -1
- package/build/dist/Server/Services/EnterpriseLicenseService.js +34 -0
- package/build/dist/Server/Services/EnterpriseLicenseService.js.map +1 -1
- package/build/dist/Server/Services/GlobalConfigService.js +63 -0
- package/build/dist/Server/Services/GlobalConfigService.js.map +1 -1
- package/build/dist/Server/Services/Index.js +4 -0
- package/build/dist/Server/Services/Index.js.map +1 -1
- package/build/dist/Server/Services/MonitorProbeService.js +90 -17
- package/build/dist/Server/Services/MonitorProbeService.js.map +1 -1
- package/build/dist/Server/Services/MonitorService.js +48 -6
- package/build/dist/Server/Services/MonitorService.js.map +1 -1
- package/build/dist/Server/Services/MonitorStatusTimelineService.js +242 -0
- package/build/dist/Server/Services/MonitorStatusTimelineService.js.map +1 -1
- package/build/dist/Server/Services/MonitorTemplateService.js +16 -0
- package/build/dist/Server/Services/MonitorTemplateService.js.map +1 -1
- package/build/dist/Server/Services/ProjectService.js +214 -0
- package/build/dist/Server/Services/ProjectService.js.map +1 -1
- package/build/dist/Server/Services/RumSessionPinService.js +24 -6
- package/build/dist/Server/Services/RumSessionPinService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js +295 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveLabelRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js +59 -14
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleEngineService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js +22 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveMonitorRuleService.js.map +1 -1
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js +400 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleEngineService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js +56 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveOwnerRuleService.js.map +1 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js +21 -0
- package/build/dist/Server/Services/ServiceLevelObjectiveService.js.map +1 -1
- package/build/dist/Server/Services/StatusPagePrivateUserService.js +7 -3
- package/build/dist/Server/Services/StatusPagePrivateUserService.js.map +1 -1
- package/build/dist/Server/Services/StatusPageService.js +71 -0
- package/build/dist/Server/Services/StatusPageService.js.map +1 -1
- package/build/dist/Server/Services/TeamMemberService.js +10 -0
- package/build/dist/Server/Services/TeamMemberService.js.map +1 -1
- package/build/dist/Server/Services/TeamService.js +9 -0
- package/build/dist/Server/Services/TeamService.js.map +1 -1
- package/build/dist/Server/Services/UserService.js +10 -16
- package/build/dist/Server/Services/UserService.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js +10 -0
- package/build/dist/Server/Types/Database/Permissions/CreatePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js +154 -14
- package/build/dist/Server/Types/Database/Permissions/EditionPermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js +10 -3
- package/build/dist/Server/Types/Database/Permissions/TablePermission.js.map +1 -1
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js +17 -0
- package/build/dist/Server/Types/Database/Permissions/UpdatePermission.js.map +1 -1
- package/build/dist/Server/Types/Markdown.js +31 -0
- package/build/dist/Server/Types/Markdown.js.map +1 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js +20 -1
- package/build/dist/Server/Types/Workflow/Components/Telegram/SendMessageToChat.js.map +1 -1
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js +1 -0
- package/build/dist/Server/Utils/AI/Toolbox/SloTools.js.map +1 -1
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js +223 -0
- package/build/dist/Server/Utils/CommunityEditionSsoReport.js.map +1 -0
- package/build/dist/Server/Utils/EditionEnforcement.js +187 -0
- package/build/dist/Server/Utils/EditionEnforcement.js.map +1 -0
- package/build/dist/Server/Utils/FrontendEnvironment.js +31 -2
- package/build/dist/Server/Utils/FrontendEnvironment.js.map +1 -1
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js +6 -193
- package/build/dist/Server/Utils/InstanceHealth/RedisHealth.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js +67 -0
- package/build/dist/Server/Utils/Monitor/AffectedResourceList.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/Criteria/CompareCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js +8 -1
- package/build/dist/Server/Utils/Monitor/Criteria/EvaluateOverTime.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/Criteria/MetricMonitorCriteria.js +1 -1
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js +585 -367
- package/build/dist/Server/Utils/Monitor/MonitorCriteriaEvaluator.js.map +1 -1
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js +88 -0
- package/build/dist/Server/Utils/Monitor/MonitoringIntervalValidator.js.map +1 -0
- package/build/dist/Server/Utils/Monitor/RootCauseList.js +101 -0
- package/build/dist/Server/Utils/Monitor/RootCauseList.js.map +1 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js +28 -0
- package/build/dist/Server/Utils/Rules/RuleRun/RuleRunRegistry.js.map +1 -1
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js +28 -0
- package/build/dist/Server/Utils/Slo/SloRulePatternValidator.js.map +1 -0
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js +331 -11
- package/build/dist/Server/Utils/Workspace/Slack/Slack.js.map +1 -1
- package/build/dist/Types/API/Hostname.js +59 -11
- package/build/dist/Types/API/Hostname.js.map +1 -1
- package/build/dist/Types/API/Route.js +18 -2
- package/build/dist/Types/API/Route.js.map +1 -1
- package/build/dist/Types/API/URL.js +23 -2
- package/build/dist/Types/API/URL.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js +19 -7
- package/build/dist/Types/Database/AccessControl/ColumnBillingAccessControl.js.map +1 -1
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js +13 -6
- package/build/dist/Types/Database/AccessControl/OwnerOnlyColumn.js.map +1 -1
- package/build/dist/Types/Database/CanonicalModelInstance.js +88 -0
- package/build/dist/Types/Database/CanonicalModelInstance.js.map +1 -0
- package/build/dist/Types/Database/TableColumn.js +19 -6
- package/build/dist/Types/Database/TableColumn.js.map +1 -1
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js +28 -0
- package/build/dist/Types/EnterpriseLicense/EnterpriseLicensePeriods.js.map +1 -0
- package/build/dist/Types/IP/IPv6.js +6 -1
- package/build/dist/Types/IP/IPv6.js.map +1 -1
- package/build/dist/Types/Monitor/MonitorStep.js +5 -0
- package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
- package/build/dist/Types/Monitor/ProxmoxAlertTemplates.js +1 -1
- package/build/dist/Types/Permission.js +84 -0
- package/build/dist/Types/Permission.js.map +1 -1
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js +11 -0
- package/build/dist/Types/Rules/RuleCriteriaFieldRegistry.js.map +1 -1
- package/build/dist/Types/Rules/RuleRun.js +4 -0
- package/build/dist/Types/Rules/RuleRun.js.map +1 -1
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js +32 -0
- package/build/dist/Types/StatusPage/UptimeDailyAggregate.js.map +1 -0
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js +414 -585
- package/build/dist/UI/Components/EditionLabel/EditionLabel.js.map +1 -1
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js +2 -0
- package/build/dist/UI/Components/EditionLabel/LicenseManager.js.map +1 -0
- package/build/dist/UI/Components/Feed/FeedOptions.js +235 -0
- package/build/dist/UI/Components/Feed/FeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js +346 -0
- package/build/dist/UI/Components/Feed/FeedOptionsButton.js.map +1 -0
- package/build/dist/UI/Components/Feed/useFeedItems.js +17 -7
- package/build/dist/UI/Components/Feed/useFeedItems.js.map +1 -1
- package/build/dist/UI/Components/Feed/useFeedOptions.js +130 -0
- package/build/dist/UI/Components/Feed/useFeedOptions.js.map +1 -0
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js +90 -17
- package/build/dist/UI/Components/Graphs/DayUptimeGraph.js.map +1 -1
- package/build/dist/UI/Components/Icon/Icon.js +1 -1
- package/build/dist/UI/Components/Icon/Icon.js.map +1 -1
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js +0 -0
- package/build/dist/UI/Components/Markdown.tsx/MarkdownConverters.js.map +1 -1
- package/build/dist/UI/Components/ModelList/ModelList.js +4 -1
- package/build/dist/UI/Components/ModelList/ModelList.js.map +1 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js +42 -1
- package/build/dist/UI/Components/MonitorGraphs/Uptime.js.map +1 -1
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js +2 -2
- package/build/dist/UI/Components/TelemetryViewer/TelemetryViewer.js.map +1 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js +6 -2
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseUsage.js.map +1 -1
- package/build/dist/Utils/HostAddressUtil.js +80 -0
- package/build/dist/Utils/HostAddressUtil.js.map +1 -0
- package/build/dist/Utils/LabelRuleImportExport.js +22 -6
- package/build/dist/Utils/LabelRuleImportExport.js.map +1 -1
- package/build/dist/Utils/Monitor/MetricValueFormatter.js +2 -2
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js +127 -0
- package/build/dist/Utils/Monitor/MonitorDestinationUtil.js.map +1 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js +374 -0
- package/build/dist/Utils/Monitor/MonitoringIntervalUtil.js.map +1 -0
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js +18 -0
- package/build/dist/Utils/Rules/MonitorTypeRuleCriteria.js.map +1 -0
- package/build/dist/Utils/Slo/SloDuration.js +13 -5
- package/build/dist/Utils/Slo/SloDuration.js.map +1 -1
- package/build/dist/Utils/Slo/SloHealth.js +8 -7
- package/build/dist/Utils/Slo/SloHealth.js.map +1 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js +16 -1
- package/build/dist/Utils/Slo/SloMonitorRuleCriteria.js.map +1 -1
- package/build/dist/Utils/Slo/SloOverviewText.js +16 -0
- package/build/dist/Utils/Slo/SloOverviewText.js.map +1 -1
- package/build/dist/Utils/Slo/SloProjection.js.map +1 -1
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js +148 -0
- package/build/dist/Utils/StatusPage/UptimeDailyAggregateUtil.js.map +1 -0
- package/jest.config.json +3 -1
- package/package.json +1 -1
- package/test-setup.sh +103 -34
- package/tsconfig.json +13 -0
- package/Server/API/EnterpriseLicenseAPI.ts +0 -925
- package/Server/API/TeamComplianceAPI.ts +0 -158
- package/Server/Middleware/SCIMAuthorization.ts +0 -141
- package/Server/Services/TeamComplianceService.ts +0 -733
- package/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.ts +0 -186
- package/Server/Utils/InstanceHealth/PostgresHealth.ts +0 -286
- package/Tests/App/AdminDashboard/EnterpriseLicenseInstanceActivity.test.tsx +0 -451
- package/Tests/App/Dashboard/AuditLogsTable.test.tsx +0 -598
- package/Tests/App/Dashboard/SecurityEventsExplorer.test.tsx +0 -761
- package/Tests/App/Dashboard/SecurityEventsSideMenu.test.tsx +0 -247
- package/Tests/App/Dashboard/SecurityEventsTableColumns.test.tsx +0 -382
- package/Tests/App/Dashboard/SecurityEventsVolumeChart.test.tsx +0 -321
- package/Tests/Server/API/EnterpriseLicenseReportUserCount.test.ts +0 -1851
- package/Tests/Server/Middleware/SCIMAuthorization.test.ts +0 -525
- package/Tests/Server/Services/TeamComplianceServiceBehaviour.test.ts +0 -1845
- package/Tests/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.test.ts +0 -495
- package/Tests/Server/Utils/InstanceHealth/PostgresHealth.test.ts +0 -337
- package/Tests/Utils/EnterpriseLicenseSeats.test.ts +0 -576
- package/Tests/Utils/EnterpriseLicenseSync.test.ts +0 -568
- package/Utils/EnterpriseLicense/EnterpriseLicenseSeats.ts +0 -287
- package/Utils/EnterpriseLicense/EnterpriseLicenseSync.ts +0 -244
- package/build/dist/Server/API/EnterpriseLicenseAPI.js +0 -646
- package/build/dist/Server/API/EnterpriseLicenseAPI.js.map +0 -1
- package/build/dist/Server/API/TeamComplianceAPI.js +0 -111
- package/build/dist/Server/API/TeamComplianceAPI.js.map +0 -1
- package/build/dist/Server/Middleware/SCIMAuthorization.js +0 -124
- package/build/dist/Server/Middleware/SCIMAuthorization.js.map +0 -1
- package/build/dist/Server/Services/TeamComplianceService.js +0 -537
- package/build/dist/Server/Services/TeamComplianceService.js.map +0 -1
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js +0 -145
- package/build/dist/Server/Utils/EnterpriseLicense/EnterpriseLicenseSeatUtil.js.map +0 -1
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js +0 -194
- package/build/dist/Server/Utils/InstanceHealth/PostgresHealth.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js +0 -168
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSeats.js.map +0 -1
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js +0 -174
- package/build/dist/Utils/EnterpriseLicense/EnterpriseLicenseSync.js.map +0 -1
|
@@ -0,0 +1,1127 @@
|
|
|
1
|
+
import { afterAll, describe, expect, test } from "@jest/globals";
|
|
2
|
+
import childProcess from "child_process";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import os from "os";
|
|
5
|
+
import path from "path";
|
|
6
|
+
|
|
7
|
+
/*
|
|
8
|
+
* How the Dashboard and AdminDashboard builds decide between the Community
|
|
9
|
+
* and the Enterprise UI (UI/esbuild-enterprise.js).
|
|
10
|
+
*
|
|
11
|
+
* Each frontend imports its Enterprise UI through one bare specifier, from
|
|
12
|
+
* one file (src/Enterprise/Plugins.ts). The helper aliases that specifier to
|
|
13
|
+
* ee/<Frontend>/Index.tsx when the Enterprise plugin is on disk (and
|
|
14
|
+
* ONEUPTIME_EDITION allows it), and to the Community stub otherwise. Getting
|
|
15
|
+
* it wrong fails silently in the worst direction: esbuild reads the
|
|
16
|
+
* frontend's tsconfig "paths" natively, so a broken alias quietly bundles the
|
|
17
|
+
* Community stub into an image tagged Enterprise. Hence the sentinel string,
|
|
18
|
+
* and hence these tests building real bundles.
|
|
19
|
+
*
|
|
20
|
+
* Everything runs in a node SUBPROCESS, the way the build loads these files:
|
|
21
|
+
* esbuild refuses to load under Common's jsdom test environment (see
|
|
22
|
+
* EsbuildConfig.test.ts), and the helper reads the edition from the
|
|
23
|
+
* environment, which a subprocess gets exactly as the build does.
|
|
24
|
+
*
|
|
25
|
+
* The fixtures are temp directories laid out like the repository
|
|
26
|
+
* (packages/App/FeatureSet/<Frontend> next to ee/) and like the image
|
|
27
|
+
* (/usr/src/app/FeatureSet/<Frontend> next to /usr/src/ee). The bundle
|
|
28
|
+
* fixture uses the REAL src/Enterprise/{Plugins,EnterprisePlugins,
|
|
29
|
+
* CommunityPlugins}.ts, so what is proven is the shipped door, not a copy.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
const UI_DIR: string = path.resolve(__dirname, "..", "..", "UI");
|
|
33
|
+
const ESBUILD_ENTERPRISE: string = path.join(UI_DIR, "esbuild-enterprise.js");
|
|
34
|
+
const ESBUILD_CONFIG: string = path.join(UI_DIR, "esbuild-config.js");
|
|
35
|
+
const PACKAGES_DIR: string = path.resolve(__dirname, "..", "..", "..");
|
|
36
|
+
const REPOSITORY_ROOT: string = path.resolve(PACKAGES_DIR, "..");
|
|
37
|
+
|
|
38
|
+
const DASHBOARD_DIR: string = path.join(
|
|
39
|
+
PACKAGES_DIR,
|
|
40
|
+
"App",
|
|
41
|
+
"FeatureSet",
|
|
42
|
+
"Dashboard",
|
|
43
|
+
);
|
|
44
|
+
const ADMIN_DASHBOARD_DIR: string = path.join(
|
|
45
|
+
PACKAGES_DIR,
|
|
46
|
+
"App",
|
|
47
|
+
"FeatureSet",
|
|
48
|
+
"AdminDashboard",
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const DASHBOARD_SENTINEL: string = "ONEUPTIME_EE_DASHBOARD_PLUGIN_v1";
|
|
52
|
+
const COMMUNITY_FIXTURE_MARKER: string = "COMMUNITY_STUB_FIXTURE_MARKER";
|
|
53
|
+
|
|
54
|
+
const temporaryRoots: Array<string> = [];
|
|
55
|
+
|
|
56
|
+
type ChildEnvironment = Record<string, string>;
|
|
57
|
+
|
|
58
|
+
/*
|
|
59
|
+
* The child gets this process's environment minus everything that steers the
|
|
60
|
+
* edition or the build mode, plus the overrides. null deletes a variable.
|
|
61
|
+
*/
|
|
62
|
+
function childEnvironment(
|
|
63
|
+
overrides: Record<string, string | null>,
|
|
64
|
+
): ChildEnvironment {
|
|
65
|
+
const environment: ChildEnvironment = {};
|
|
66
|
+
|
|
67
|
+
for (const key of Object.keys(process.env)) {
|
|
68
|
+
const value: string | undefined = process.env[key];
|
|
69
|
+
|
|
70
|
+
if (typeof value === "string") {
|
|
71
|
+
environment[key] = value;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
for (const key of [
|
|
76
|
+
"ONEUPTIME_EDITION",
|
|
77
|
+
"ONEUPTIME_EE_DIR",
|
|
78
|
+
"NODE_ENV",
|
|
79
|
+
"analyze",
|
|
80
|
+
]) {
|
|
81
|
+
delete environment[key];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
for (const [key, value] of Object.entries(overrides)) {
|
|
85
|
+
if (value === null) {
|
|
86
|
+
delete environment[key];
|
|
87
|
+
} else {
|
|
88
|
+
environment[key] = value;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
return environment;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function runNode(
|
|
96
|
+
script: string,
|
|
97
|
+
overrides: Record<string, string | null>,
|
|
98
|
+
cwd: string = REPOSITORY_ROOT,
|
|
99
|
+
preload: string | null = null,
|
|
100
|
+
): string {
|
|
101
|
+
const args: Array<string> = preload ? ["-r", preload] : [];
|
|
102
|
+
|
|
103
|
+
return childProcess
|
|
104
|
+
.execFileSync(process.execPath, [...args, "-e", script], {
|
|
105
|
+
cwd,
|
|
106
|
+
encoding: "utf8",
|
|
107
|
+
env: childEnvironment(overrides),
|
|
108
|
+
})
|
|
109
|
+
.trim();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function makeTempDir(prefix: string): string {
|
|
113
|
+
// realpath: macOS-style /tmp symlinks must not make paths compare unequal.
|
|
114
|
+
const root: string = fs.realpathSync(
|
|
115
|
+
fs.mkdtempSync(path.join(os.tmpdir(), prefix)),
|
|
116
|
+
);
|
|
117
|
+
temporaryRoots.push(root);
|
|
118
|
+
return root;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function writeFile(filePath: string, contents: string): void {
|
|
122
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
123
|
+
fs.writeFileSync(filePath, contents);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
interface ResolveOptions {
|
|
127
|
+
frontendDir: string;
|
|
128
|
+
pluginSpecifier: string;
|
|
129
|
+
eeSubdir: string;
|
|
130
|
+
internalSpecifier: string;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
interface BuildDecision {
|
|
134
|
+
edition: string;
|
|
135
|
+
requestedEdition: string;
|
|
136
|
+
pluginEntry: string | null;
|
|
137
|
+
communityStub: string;
|
|
138
|
+
candidates: Array<string>;
|
|
139
|
+
alias: Record<string, string>;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
interface ResolveResult {
|
|
143
|
+
ok: boolean;
|
|
144
|
+
error: string;
|
|
145
|
+
decision: BuildDecision | null;
|
|
146
|
+
description: string;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function dashboardOptions(frontendDir: string): ResolveOptions {
|
|
150
|
+
return {
|
|
151
|
+
frontendDir,
|
|
152
|
+
pluginSpecifier: "@oneuptime/ee-dashboard",
|
|
153
|
+
eeSubdir: "Dashboard",
|
|
154
|
+
internalSpecifier: "@oneuptime/dashboard",
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function adminDashboardOptions(frontendDir: string): ResolveOptions {
|
|
159
|
+
return {
|
|
160
|
+
frontendDir,
|
|
161
|
+
pluginSpecifier: "@oneuptime/ee-admin-dashboard",
|
|
162
|
+
eeSubdir: "AdminDashboard",
|
|
163
|
+
internalSpecifier: "@oneuptime/admin-dashboard",
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/*
|
|
168
|
+
* Runs resolveEnterpriseBuild in a child with the given environment. Options
|
|
169
|
+
* are passed as JSON, so a missing key really is missing.
|
|
170
|
+
*/
|
|
171
|
+
function resolveInChild(
|
|
172
|
+
options: Partial<ResolveOptions> | null,
|
|
173
|
+
overrides: Record<string, string | null> = {},
|
|
174
|
+
): ResolveResult {
|
|
175
|
+
const script: string = `
|
|
176
|
+
const helper = require(${JSON.stringify(ESBUILD_ENTERPRISE)});
|
|
177
|
+
try {
|
|
178
|
+
const decision = helper.resolveEnterpriseBuild(${JSON.stringify(options)});
|
|
179
|
+
console.log(JSON.stringify({
|
|
180
|
+
ok: true,
|
|
181
|
+
error: "",
|
|
182
|
+
decision: decision,
|
|
183
|
+
description: helper.describeEnterpriseBuild("Dashboard", decision),
|
|
184
|
+
}));
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.log(JSON.stringify({
|
|
187
|
+
ok: false,
|
|
188
|
+
error: String((error && error.message) || error),
|
|
189
|
+
decision: null,
|
|
190
|
+
description: "",
|
|
191
|
+
}));
|
|
192
|
+
}
|
|
193
|
+
`;
|
|
194
|
+
|
|
195
|
+
return JSON.parse(runNode(script, overrides)) as ResolveResult;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
function readRequestedEditionInChild(
|
|
199
|
+
overrides: Record<string, string | null>,
|
|
200
|
+
): { ok: boolean; value: string; error: string } {
|
|
201
|
+
const script: string = `
|
|
202
|
+
const helper = require(${JSON.stringify(ESBUILD_ENTERPRISE)});
|
|
203
|
+
try {
|
|
204
|
+
console.log(JSON.stringify({ ok: true, value: helper.readRequestedEdition(), error: "" }));
|
|
205
|
+
} catch (error) {
|
|
206
|
+
console.log(JSON.stringify({ ok: false, value: "", error: String(error.message) }));
|
|
207
|
+
}
|
|
208
|
+
`;
|
|
209
|
+
|
|
210
|
+
return JSON.parse(runNode(script, overrides)) as {
|
|
211
|
+
ok: boolean;
|
|
212
|
+
value: string;
|
|
213
|
+
error: string;
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
interface Layout {
|
|
218
|
+
root: string;
|
|
219
|
+
frontendDir: string;
|
|
220
|
+
eeDir: string;
|
|
221
|
+
communityStub: string;
|
|
222
|
+
eeEntry: string;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/*
|
|
226
|
+
* A minimal tree the resolver can decide on. "repository" mirrors
|
|
227
|
+
* packages/App/FeatureSet/<Frontend> + <repo>/ee; "container" mirrors
|
|
228
|
+
* /usr/src/app/FeatureSet/<Frontend> + /usr/src/ee.
|
|
229
|
+
*/
|
|
230
|
+
// Whether the temp directory tells "CaseProbe" and "caseprobe" apart.
|
|
231
|
+
function isCaseSensitiveFileSystem(): boolean {
|
|
232
|
+
const directory: string = fs.mkdtempSync(
|
|
233
|
+
path.join(os.tmpdir(), "oneuptime-ee-case-"),
|
|
234
|
+
);
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
fs.writeFileSync(path.join(directory, "CaseProbe"), "");
|
|
238
|
+
return !fs.existsSync(path.join(directory, "caseprobe"));
|
|
239
|
+
} finally {
|
|
240
|
+
fs.rmSync(directory, { recursive: true, force: true });
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
function makeLayout(
|
|
245
|
+
shape: "repository" | "container",
|
|
246
|
+
options: { withEnterprise: boolean; frontend?: string; eeSubdir?: string },
|
|
247
|
+
): Layout {
|
|
248
|
+
const root: string = makeTempDir("oneuptime-ee-alias-");
|
|
249
|
+
const frontend: string = options.frontend || "Dashboard";
|
|
250
|
+
const eeSubdir: string = options.eeSubdir || frontend;
|
|
251
|
+
|
|
252
|
+
const frontendDir: string =
|
|
253
|
+
shape === "repository"
|
|
254
|
+
? path.join(root, "packages", "App", "FeatureSet", frontend)
|
|
255
|
+
: path.join(root, "usr", "src", "app", "FeatureSet", frontend);
|
|
256
|
+
|
|
257
|
+
const eeDir: string =
|
|
258
|
+
shape === "repository"
|
|
259
|
+
? path.join(root, "ee")
|
|
260
|
+
: path.join(root, "usr", "src", "ee");
|
|
261
|
+
|
|
262
|
+
const communityStub: string = path.join(
|
|
263
|
+
frontendDir,
|
|
264
|
+
"src",
|
|
265
|
+
"Enterprise",
|
|
266
|
+
"CommunityPlugins.ts",
|
|
267
|
+
);
|
|
268
|
+
writeFile(communityStub, "export default {};\n");
|
|
269
|
+
|
|
270
|
+
const eeEntry: string = path.join(eeDir, eeSubdir, "Index.tsx");
|
|
271
|
+
|
|
272
|
+
if (options.withEnterprise) {
|
|
273
|
+
writeFile(eeEntry, "export default {};\n");
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return { root, frontendDir, eeDir, communityStub, eeEntry };
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
afterAll(() => {
|
|
280
|
+
while (temporaryRoots.length > 0) {
|
|
281
|
+
fs.rmSync(temporaryRoots.pop() as string, {
|
|
282
|
+
recursive: true,
|
|
283
|
+
force: true,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe("choosing the edition (resolveEnterpriseBuild)", () => {
|
|
289
|
+
test("a checkout without ee/ builds the Community stub", () => {
|
|
290
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: false });
|
|
291
|
+
const result: ResolveResult = resolveInChild(
|
|
292
|
+
dashboardOptions(layout.frontendDir),
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
expect([result.ok, result.error]).toEqual([true, ""]);
|
|
296
|
+
expect(result.decision!.edition).toBe("community");
|
|
297
|
+
expect(result.decision!.requestedEdition).toBe("auto");
|
|
298
|
+
expect(result.decision!.pluginEntry).toBeNull();
|
|
299
|
+
expect(result.decision!.alias["@oneuptime/ee-dashboard"]).toBe(
|
|
300
|
+
layout.communityStub,
|
|
301
|
+
);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
test("a checkout with ee/ builds the Enterprise plugin (repository layout)", () => {
|
|
305
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: true });
|
|
306
|
+
const result: ResolveResult = resolveInChild(
|
|
307
|
+
dashboardOptions(layout.frontendDir),
|
|
308
|
+
);
|
|
309
|
+
|
|
310
|
+
expect(result.decision!.edition).toBe("enterprise");
|
|
311
|
+
expect(result.decision!.pluginEntry).toBe(layout.eeEntry);
|
|
312
|
+
// The FILE, not the directory: a directory alias misses Index.tsx.
|
|
313
|
+
expect(result.decision!.alias["@oneuptime/ee-dashboard"]).toBe(
|
|
314
|
+
path.join(layout.root, "ee", "Dashboard", "Index.tsx"),
|
|
315
|
+
);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
test("the image layout finds /usr/src/ee next to /usr/src/app", () => {
|
|
319
|
+
const layout: Layout = makeLayout("container", { withEnterprise: true });
|
|
320
|
+
const result: ResolveResult = resolveInChild(
|
|
321
|
+
dashboardOptions(layout.frontendDir),
|
|
322
|
+
);
|
|
323
|
+
|
|
324
|
+
expect(result.decision!.edition).toBe("enterprise");
|
|
325
|
+
expect(result.decision!.alias["@oneuptime/ee-dashboard"]).toBe(
|
|
326
|
+
path.join(layout.root, "usr", "src", "ee", "Dashboard", "Index.tsx"),
|
|
327
|
+
);
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
test("tries the repository location first, then the image location", () => {
|
|
331
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: false });
|
|
332
|
+
const result: ResolveResult = resolveInChild(
|
|
333
|
+
dashboardOptions(layout.frontendDir),
|
|
334
|
+
);
|
|
335
|
+
|
|
336
|
+
expect(result.decision!.candidates).toEqual([
|
|
337
|
+
path.join(layout.root, "ee", "Dashboard", "Index.tsx"),
|
|
338
|
+
path.join(layout.root, "packages", "ee", "Dashboard", "Index.tsx"),
|
|
339
|
+
]);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
test("ONEUPTIME_EDITION=community builds the stub even with ee/ present", () => {
|
|
343
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: true });
|
|
344
|
+
const result: ResolveResult = resolveInChild(
|
|
345
|
+
dashboardOptions(layout.frontendDir),
|
|
346
|
+
{ ONEUPTIME_EDITION: "community" },
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
expect(result.decision!.edition).toBe("community");
|
|
350
|
+
expect(result.decision!.requestedEdition).toBe("community");
|
|
351
|
+
expect(result.decision!.pluginEntry).toBeNull();
|
|
352
|
+
expect(result.decision!.alias["@oneuptime/ee-dashboard"]).toBe(
|
|
353
|
+
layout.communityStub,
|
|
354
|
+
);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
test("ONEUPTIME_EDITION=enterprise builds the plugin when it is there", () => {
|
|
358
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: true });
|
|
359
|
+
const result: ResolveResult = resolveInChild(
|
|
360
|
+
dashboardOptions(layout.frontendDir),
|
|
361
|
+
{ ONEUPTIME_EDITION: "enterprise" },
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
expect(result.decision!.edition).toBe("enterprise");
|
|
365
|
+
expect(result.decision!.alias["@oneuptime/ee-dashboard"]).toBe(
|
|
366
|
+
layout.eeEntry,
|
|
367
|
+
);
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test("ONEUPTIME_EDITION=enterprise with no plugin fails the build instead of shipping Community", () => {
|
|
371
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: false });
|
|
372
|
+
const result: ResolveResult = resolveInChild(
|
|
373
|
+
dashboardOptions(layout.frontendDir),
|
|
374
|
+
{ ONEUPTIME_EDITION: "enterprise" },
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
expect(result.ok).toBe(false);
|
|
378
|
+
expect(result.error).toContain("ONEUPTIME_EDITION=enterprise");
|
|
379
|
+
expect(result.error).toContain("Enterprise UI plugin for Dashboard");
|
|
380
|
+
// It names every place it looked, so the fix is obvious from the log.
|
|
381
|
+
expect(result.error).toContain(
|
|
382
|
+
path.join(layout.root, "ee", "Dashboard", "Index.tsx"),
|
|
383
|
+
);
|
|
384
|
+
expect(result.error).toContain(
|
|
385
|
+
path.join(layout.root, "packages", "ee", "Dashboard", "Index.tsx"),
|
|
386
|
+
);
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
test("an ee/ directory without the plugin file is not the Enterprise Edition", () => {
|
|
390
|
+
/*
|
|
391
|
+
* A leftover ee/node_modules after switching branches, or a directory
|
|
392
|
+
* that happens to be called Index.tsx, must not count: "found" means the
|
|
393
|
+
* Index.tsx FILE.
|
|
394
|
+
*/
|
|
395
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: false });
|
|
396
|
+
fs.mkdirSync(path.join(layout.eeDir, "node_modules"), { recursive: true });
|
|
397
|
+
fs.mkdirSync(path.join(layout.eeDir, "Dashboard", "Index.tsx", "nested"), {
|
|
398
|
+
recursive: true,
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
const auto: ResolveResult = resolveInChild(
|
|
402
|
+
dashboardOptions(layout.frontendDir),
|
|
403
|
+
);
|
|
404
|
+
expect(auto.decision!.edition).toBe("community");
|
|
405
|
+
|
|
406
|
+
const enterprise: ResolveResult = resolveInChild(
|
|
407
|
+
dashboardOptions(layout.frontendDir),
|
|
408
|
+
{ ONEUPTIME_EDITION: "enterprise" },
|
|
409
|
+
);
|
|
410
|
+
expect(enterprise.ok).toBe(false);
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
/*
|
|
414
|
+
* On a case-insensitive file system (macOS, Windows) a lowercase index.tsx
|
|
415
|
+
* IS Index.tsx, so this only means something where names are
|
|
416
|
+
* case-sensitive - the Linux build machines and the image.
|
|
417
|
+
*/
|
|
418
|
+
const caseSensitiveTest: typeof test.skip = isCaseSensitiveFileSystem()
|
|
419
|
+
? test
|
|
420
|
+
: test.skip;
|
|
421
|
+
|
|
422
|
+
caseSensitiveTest("a lowercase index.tsx is not the plugin file", () => {
|
|
423
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: false });
|
|
424
|
+
writeFile(path.join(layout.eeDir, "Dashboard", "index.tsx"), "");
|
|
425
|
+
|
|
426
|
+
const auto: ResolveResult = resolveInChild(
|
|
427
|
+
dashboardOptions(layout.frontendDir),
|
|
428
|
+
);
|
|
429
|
+
expect(auto.decision!.edition).toBe("community");
|
|
430
|
+
|
|
431
|
+
const enterprise: ResolveResult = resolveInChild(
|
|
432
|
+
dashboardOptions(layout.frontendDir),
|
|
433
|
+
{ ONEUPTIME_EDITION: "enterprise" },
|
|
434
|
+
);
|
|
435
|
+
expect(enterprise.ok).toBe(false);
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
test("each frontend picks its own ee subdirectory", () => {
|
|
439
|
+
const layout: Layout = makeLayout("repository", {
|
|
440
|
+
withEnterprise: true,
|
|
441
|
+
frontend: "AdminDashboard",
|
|
442
|
+
});
|
|
443
|
+
// A Dashboard plugin alone must not satisfy the AdminDashboard.
|
|
444
|
+
writeFile(path.join(layout.eeDir, "Dashboard", "Index.tsx"), "");
|
|
445
|
+
|
|
446
|
+
const admin: ResolveResult = resolveInChild(
|
|
447
|
+
adminDashboardOptions(layout.frontendDir),
|
|
448
|
+
);
|
|
449
|
+
|
|
450
|
+
expect(admin.decision!.alias["@oneuptime/ee-admin-dashboard"]).toBe(
|
|
451
|
+
path.join(layout.eeDir, "AdminDashboard", "Index.tsx"),
|
|
452
|
+
);
|
|
453
|
+
|
|
454
|
+
fs.rmSync(path.join(layout.eeDir, "AdminDashboard"), {
|
|
455
|
+
recursive: true,
|
|
456
|
+
force: true,
|
|
457
|
+
});
|
|
458
|
+
|
|
459
|
+
const adminWithoutPlugin: ResolveResult = resolveInChild(
|
|
460
|
+
adminDashboardOptions(layout.frontendDir),
|
|
461
|
+
);
|
|
462
|
+
expect(adminWithoutPlugin.decision!.edition).toBe("community");
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
test("ONEUPTIME_EE_DIR replaces the default locations", () => {
|
|
466
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: true });
|
|
467
|
+
const elsewhere: string = makeTempDir("oneuptime-ee-elsewhere-");
|
|
468
|
+
writeFile(path.join(elsewhere, "Dashboard", "Index.tsx"), "");
|
|
469
|
+
|
|
470
|
+
const moved: ResolveResult = resolveInChild(
|
|
471
|
+
dashboardOptions(layout.frontendDir),
|
|
472
|
+
{ ONEUPTIME_EE_DIR: elsewhere },
|
|
473
|
+
);
|
|
474
|
+
|
|
475
|
+
expect(moved.decision!.candidates).toEqual([
|
|
476
|
+
path.join(elsewhere, "Dashboard", "Index.tsx"),
|
|
477
|
+
]);
|
|
478
|
+
expect(moved.decision!.alias["@oneuptime/ee-dashboard"]).toBe(
|
|
479
|
+
path.join(elsewhere, "Dashboard", "Index.tsx"),
|
|
480
|
+
);
|
|
481
|
+
|
|
482
|
+
// Pointed at a directory with no plugin, the repository ee/ is NOT used.
|
|
483
|
+
const empty: string = makeTempDir("oneuptime-ee-empty-");
|
|
484
|
+
const none: ResolveResult = resolveInChild(
|
|
485
|
+
dashboardOptions(layout.frontendDir),
|
|
486
|
+
{ ONEUPTIME_EE_DIR: empty },
|
|
487
|
+
);
|
|
488
|
+
expect(none.decision!.edition).toBe("community");
|
|
489
|
+
});
|
|
490
|
+
|
|
491
|
+
test("always maps the internal specifier and Common into the frontend", () => {
|
|
492
|
+
/*
|
|
493
|
+
* ee code reaches core as "@oneuptime/dashboard/..." and "Common/...",
|
|
494
|
+
* both served from the frontend itself so bundling never needs an
|
|
495
|
+
* install inside ee/. Both editions get the same aliases, so core
|
|
496
|
+
* resolves identically either way.
|
|
497
|
+
*/
|
|
498
|
+
for (const withEnterprise of [false, true]) {
|
|
499
|
+
const layout: Layout = makeLayout("repository", { withEnterprise });
|
|
500
|
+
const result: ResolveResult = resolveInChild(
|
|
501
|
+
dashboardOptions(layout.frontendDir),
|
|
502
|
+
);
|
|
503
|
+
|
|
504
|
+
expect(result.decision!.alias["@oneuptime/dashboard"]).toBe(
|
|
505
|
+
path.join(layout.frontendDir, "src"),
|
|
506
|
+
);
|
|
507
|
+
expect(result.decision!.alias["Common"]).toBe(
|
|
508
|
+
path.join(layout.frontendDir, "node_modules", "Common"),
|
|
509
|
+
);
|
|
510
|
+
expect(Object.keys(result.decision!.alias).sort()).toEqual(
|
|
511
|
+
["@oneuptime/dashboard", "@oneuptime/ee-dashboard", "Common"].sort(),
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
test("says which edition it built, for the build log", () => {
|
|
517
|
+
const enterpriseLayout: Layout = makeLayout("repository", {
|
|
518
|
+
withEnterprise: true,
|
|
519
|
+
});
|
|
520
|
+
const enterprise: ResolveResult = resolveInChild(
|
|
521
|
+
dashboardOptions(enterpriseLayout.frontendDir),
|
|
522
|
+
);
|
|
523
|
+
expect(enterprise.description).toBe(
|
|
524
|
+
`Dashboard: building the Enterprise Edition UI from ${enterpriseLayout.eeEntry}`,
|
|
525
|
+
);
|
|
526
|
+
|
|
527
|
+
const communityLayout: Layout = makeLayout("repository", {
|
|
528
|
+
withEnterprise: true,
|
|
529
|
+
});
|
|
530
|
+
const community: ResolveResult = resolveInChild(
|
|
531
|
+
dashboardOptions(communityLayout.frontendDir),
|
|
532
|
+
{ ONEUPTIME_EDITION: "community" },
|
|
533
|
+
);
|
|
534
|
+
expect(community.description).toBe(
|
|
535
|
+
"Dashboard: building the Community Edition UI (ONEUPTIME_EDITION=community)",
|
|
536
|
+
);
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
test("refuses a frontend with no Community stub", () => {
|
|
540
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: true });
|
|
541
|
+
fs.rmSync(layout.communityStub);
|
|
542
|
+
|
|
543
|
+
const result: ResolveResult = resolveInChild(
|
|
544
|
+
dashboardOptions(layout.frontendDir),
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
expect(result.ok).toBe(false);
|
|
548
|
+
expect(result.error).toContain("Community plugin stub is missing");
|
|
549
|
+
});
|
|
550
|
+
|
|
551
|
+
test("refuses missing options and a relative frontend directory", () => {
|
|
552
|
+
const layout: Layout = makeLayout("repository", { withEnterprise: false });
|
|
553
|
+
|
|
554
|
+
for (const key of [
|
|
555
|
+
"frontendDir",
|
|
556
|
+
"pluginSpecifier",
|
|
557
|
+
"eeSubdir",
|
|
558
|
+
"internalSpecifier",
|
|
559
|
+
] as Array<keyof ResolveOptions>) {
|
|
560
|
+
const options: Partial<ResolveOptions> = {
|
|
561
|
+
...dashboardOptions(layout.frontendDir),
|
|
562
|
+
};
|
|
563
|
+
delete options[key];
|
|
564
|
+
|
|
565
|
+
const result: ResolveResult = resolveInChild(options);
|
|
566
|
+
expect([key, result.ok, result.error]).toEqual([
|
|
567
|
+
key,
|
|
568
|
+
false,
|
|
569
|
+
`resolveEnterpriseBuild: "${key}" is required.`,
|
|
570
|
+
]);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
expect(resolveInChild(null).ok).toBe(false);
|
|
574
|
+
|
|
575
|
+
const relative: ResolveResult = resolveInChild({
|
|
576
|
+
...dashboardOptions("packages/App/FeatureSet/Dashboard"),
|
|
577
|
+
});
|
|
578
|
+
expect(relative.ok).toBe(false);
|
|
579
|
+
expect(relative.error).toContain("must be absolute");
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
|
|
583
|
+
describe("reading ONEUPTIME_EDITION", () => {
|
|
584
|
+
test.each([
|
|
585
|
+
[null, "auto"],
|
|
586
|
+
["", "auto"],
|
|
587
|
+
[" ", "auto"],
|
|
588
|
+
["auto", "auto"],
|
|
589
|
+
["community", "community"],
|
|
590
|
+
["enterprise", "enterprise"],
|
|
591
|
+
[" Enterprise ", "enterprise"],
|
|
592
|
+
["COMMUNITY", "community"],
|
|
593
|
+
])("%p reads as %p", (raw: string | null, expected: string) => {
|
|
594
|
+
const result: { ok: boolean; value: string; error: string } =
|
|
595
|
+
readRequestedEditionInChild({ ONEUPTIME_EDITION: raw });
|
|
596
|
+
|
|
597
|
+
expect([result.ok, result.value]).toEqual([true, expected]);
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
test.each(["enterprize", "ee", "ce", "true"])(
|
|
601
|
+
"a typo (%p) fails the build rather than guessing an edition",
|
|
602
|
+
(raw: string) => {
|
|
603
|
+
const result: { ok: boolean; value: string; error: string } =
|
|
604
|
+
readRequestedEditionInChild({ ONEUPTIME_EDITION: raw });
|
|
605
|
+
|
|
606
|
+
expect(result.ok).toBe(false);
|
|
607
|
+
expect(result.error).toContain(
|
|
608
|
+
"ONEUPTIME_EDITION must be one of auto, community, enterprise",
|
|
609
|
+
);
|
|
610
|
+
expect(result.error).toContain(`"${raw}"`);
|
|
611
|
+
},
|
|
612
|
+
);
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
describe("the real frontends", () => {
|
|
616
|
+
/*
|
|
617
|
+
* The two shipped esbuild.config.js files, run for real with esbuild's
|
|
618
|
+
* build() swapped for a probe (preloaded into the same module instance),
|
|
619
|
+
* so what is asserted is the config they would build with. NODE_PATH lets
|
|
620
|
+
* "Common/..." resolve even where the frontend is not installed - the
|
|
621
|
+
* Common Test CI job installs Common alone.
|
|
622
|
+
*/
|
|
623
|
+
interface ProbedBuild {
|
|
624
|
+
alias: Record<string, string>;
|
|
625
|
+
keys: Array<string>;
|
|
626
|
+
log: Array<string>;
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
function probeFrontendBuild(
|
|
630
|
+
frontendDir: string,
|
|
631
|
+
overrides: Record<string, string | null>,
|
|
632
|
+
): ProbedBuild {
|
|
633
|
+
const probeDir: string = makeTempDir("oneuptime-ee-probe-");
|
|
634
|
+
const preload: string = path.join(probeDir, "probe.js");
|
|
635
|
+
|
|
636
|
+
writeFile(
|
|
637
|
+
preload,
|
|
638
|
+
`
|
|
639
|
+
const config = require(${JSON.stringify(ESBUILD_CONFIG)});
|
|
640
|
+
const log = [];
|
|
641
|
+
const originalLog = console.log;
|
|
642
|
+
console.log = function () {
|
|
643
|
+
log.push(Array.prototype.join.call(arguments, " "));
|
|
644
|
+
};
|
|
645
|
+
function report(built) {
|
|
646
|
+
originalLog(JSON.stringify({
|
|
647
|
+
alias: built.alias,
|
|
648
|
+
keys: Object.keys(built),
|
|
649
|
+
log: log,
|
|
650
|
+
}));
|
|
651
|
+
}
|
|
652
|
+
config.build = report;
|
|
653
|
+
config.watch = report;
|
|
654
|
+
`,
|
|
655
|
+
);
|
|
656
|
+
|
|
657
|
+
const output: string = runNode(
|
|
658
|
+
`require(${JSON.stringify(path.join(frontendDir, "esbuild.config.js"))});`,
|
|
659
|
+
{ NODE_PATH: PACKAGES_DIR, ...overrides },
|
|
660
|
+
frontendDir,
|
|
661
|
+
preload,
|
|
662
|
+
);
|
|
663
|
+
|
|
664
|
+
return JSON.parse(output) as ProbedBuild;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
const EXPECTED_CONFIG_KEYS: Array<string> = [
|
|
668
|
+
"entryPoints",
|
|
669
|
+
"bundle",
|
|
670
|
+
"outdir",
|
|
671
|
+
"format",
|
|
672
|
+
"platform",
|
|
673
|
+
"target",
|
|
674
|
+
"sourcemap",
|
|
675
|
+
"minify",
|
|
676
|
+
"keepNames",
|
|
677
|
+
"treeShaking",
|
|
678
|
+
"splitting",
|
|
679
|
+
"publicPath",
|
|
680
|
+
"define",
|
|
681
|
+
"external",
|
|
682
|
+
"alias",
|
|
683
|
+
"plugins",
|
|
684
|
+
"loader",
|
|
685
|
+
"resolveExtensions",
|
|
686
|
+
"metafile",
|
|
687
|
+
];
|
|
688
|
+
|
|
689
|
+
test.each([
|
|
690
|
+
[
|
|
691
|
+
"Dashboard",
|
|
692
|
+
DASHBOARD_DIR,
|
|
693
|
+
"@oneuptime/ee-dashboard",
|
|
694
|
+
"@oneuptime/dashboard",
|
|
695
|
+
],
|
|
696
|
+
[
|
|
697
|
+
"AdminDashboard",
|
|
698
|
+
ADMIN_DASHBOARD_DIR,
|
|
699
|
+
"@oneuptime/ee-admin-dashboard",
|
|
700
|
+
"@oneuptime/admin-dashboard",
|
|
701
|
+
],
|
|
702
|
+
])(
|
|
703
|
+
"%s builds the Community stub under ONEUPTIME_EDITION=community",
|
|
704
|
+
(
|
|
705
|
+
name: string,
|
|
706
|
+
frontendDir: string,
|
|
707
|
+
pluginSpecifier: string,
|
|
708
|
+
internalSpecifier: string,
|
|
709
|
+
) => {
|
|
710
|
+
const probed: ProbedBuild = probeFrontendBuild(frontendDir, {
|
|
711
|
+
ONEUPTIME_EDITION: "community",
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
expect(probed.alias[pluginSpecifier]).toBe(
|
|
715
|
+
path.join(frontendDir, "src", "Enterprise", "CommunityPlugins.ts"),
|
|
716
|
+
);
|
|
717
|
+
expect(probed.alias[internalSpecifier]).toBe(
|
|
718
|
+
path.join(frontendDir, "src"),
|
|
719
|
+
);
|
|
720
|
+
expect(probed.alias["Common"]).toBe(
|
|
721
|
+
path.join(frontendDir, "node_modules", "Common"),
|
|
722
|
+
);
|
|
723
|
+
|
|
724
|
+
// The shared aliases createConfig adds are still there.
|
|
725
|
+
expect(Object.keys(probed.alias)).toEqual(
|
|
726
|
+
expect.arrayContaining(["react", "react-dom", "i18next"]),
|
|
727
|
+
);
|
|
728
|
+
|
|
729
|
+
// additionalAlias only: no new top-level config keys.
|
|
730
|
+
expect([...probed.keys].sort()).toEqual([...EXPECTED_CONFIG_KEYS].sort());
|
|
731
|
+
|
|
732
|
+
expect(probed.log).toContain(
|
|
733
|
+
`${name}: building the Community Edition UI (ONEUPTIME_EDITION=community)`,
|
|
734
|
+
);
|
|
735
|
+
},
|
|
736
|
+
);
|
|
737
|
+
|
|
738
|
+
test.each([
|
|
739
|
+
["Dashboard", DASHBOARD_DIR, "@oneuptime/ee-dashboard"],
|
|
740
|
+
["AdminDashboard", ADMIN_DASHBOARD_DIR, "@oneuptime/ee-admin-dashboard"],
|
|
741
|
+
])(
|
|
742
|
+
"%s builds the Enterprise plugin when one is on disk",
|
|
743
|
+
(name: string, frontendDir: string, pluginSpecifier: string) => {
|
|
744
|
+
const eeDir: string = makeTempDir("oneuptime-ee-real-frontend-");
|
|
745
|
+
const entry: string = path.join(eeDir, name, "Index.tsx");
|
|
746
|
+
writeFile(entry, "export default {};\n");
|
|
747
|
+
|
|
748
|
+
const probed: ProbedBuild = probeFrontendBuild(frontendDir, {
|
|
749
|
+
ONEUPTIME_EE_DIR: eeDir,
|
|
750
|
+
});
|
|
751
|
+
|
|
752
|
+
expect(probed.alias[pluginSpecifier]).toBe(entry);
|
|
753
|
+
expect(probed.log).toContain(
|
|
754
|
+
`${name}: building the Enterprise Edition UI from ${entry}`,
|
|
755
|
+
);
|
|
756
|
+
},
|
|
757
|
+
);
|
|
758
|
+
});
|
|
759
|
+
|
|
760
|
+
describe("bundling for real", () => {
|
|
761
|
+
interface BundleResult {
|
|
762
|
+
ok: boolean;
|
|
763
|
+
error: string;
|
|
764
|
+
// Every emitted file concatenated - chunks included.
|
|
765
|
+
output: string;
|
|
766
|
+
inputs: Array<string>;
|
|
767
|
+
evaluated: {
|
|
768
|
+
ok: boolean;
|
|
769
|
+
error: string;
|
|
770
|
+
value: {
|
|
771
|
+
shell: string;
|
|
772
|
+
pluginKeys: Array<string>;
|
|
773
|
+
buildMarker: string | null;
|
|
774
|
+
areaResult: string | null;
|
|
775
|
+
sharedCount: number;
|
|
776
|
+
commonLabel: string;
|
|
777
|
+
} | null;
|
|
778
|
+
};
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
const REAL_ENTERPRISE_DIR: string = path.join(
|
|
782
|
+
DASHBOARD_DIR,
|
|
783
|
+
"src",
|
|
784
|
+
"Enterprise",
|
|
785
|
+
);
|
|
786
|
+
|
|
787
|
+
/*
|
|
788
|
+
* A frontend that uses the REAL core door. The ee area imports a core shell
|
|
789
|
+
* back through "@oneuptime/dashboard/...", closing the same import cycle
|
|
790
|
+
* the real Enterprise bundle has (core shell -> Plugins -> ee Index -> ee
|
|
791
|
+
* area -> core shell).
|
|
792
|
+
*/
|
|
793
|
+
function makeBundleFixture(options: {
|
|
794
|
+
withEnterprise: boolean;
|
|
795
|
+
topLevelPluginRead?: boolean;
|
|
796
|
+
}): Layout {
|
|
797
|
+
const layout: Layout = makeLayout("repository", {
|
|
798
|
+
withEnterprise: false,
|
|
799
|
+
});
|
|
800
|
+
const src: string = path.join(layout.frontendDir, "src");
|
|
801
|
+
|
|
802
|
+
for (const file of [
|
|
803
|
+
"Plugins.ts",
|
|
804
|
+
"EnterprisePlugins.ts",
|
|
805
|
+
"CommunityPlugins.ts",
|
|
806
|
+
]) {
|
|
807
|
+
writeFile(
|
|
808
|
+
path.join(src, "Enterprise", file),
|
|
809
|
+
fs.readFileSync(path.join(REAL_ENTERPRISE_DIR, file), "utf8"),
|
|
810
|
+
);
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
// Proves the stub is what ships when ee/ is not bundled.
|
|
814
|
+
fs.appendFileSync(
|
|
815
|
+
path.join(src, "Enterprise", "CommunityPlugins.ts"),
|
|
816
|
+
`\nexport const COMMUNITY_MARKER: string = "${COMMUNITY_FIXTURE_MARKER}";\n(globalThis as any).__communityMarker = COMMUNITY_MARKER;\n`,
|
|
817
|
+
);
|
|
818
|
+
|
|
819
|
+
writeFile(
|
|
820
|
+
path.join(src, "Utils", "Shared.ts"),
|
|
821
|
+
"export const sharedToken: { count: number } = { count: 0 };\n",
|
|
822
|
+
);
|
|
823
|
+
|
|
824
|
+
writeFile(
|
|
825
|
+
path.join(src, "Components", "Shell.ts"),
|
|
826
|
+
`
|
|
827
|
+
import { getDashboardPlugins } from "../Enterprise/Plugins";
|
|
828
|
+
export const renderShell = (): string => {
|
|
829
|
+
return getDashboardPlugins().buildMarker || "community";
|
|
830
|
+
};
|
|
831
|
+
`,
|
|
832
|
+
);
|
|
833
|
+
|
|
834
|
+
writeFile(
|
|
835
|
+
path.join(src, "Index.tsx"),
|
|
836
|
+
`
|
|
837
|
+
import { renderShell } from "./Components/Shell";
|
|
838
|
+
import { getDashboardPlugins } from "./Enterprise/Plugins";
|
|
839
|
+
import { sharedToken } from "./Utils/Shared";
|
|
840
|
+
import { commonLabel } from "Common/Label";
|
|
841
|
+
|
|
842
|
+
sharedToken.count += 1;
|
|
843
|
+
|
|
844
|
+
const plugins: any = getDashboardPlugins();
|
|
845
|
+
(globalThis as any).__fixtureResult = {
|
|
846
|
+
shell: renderShell(),
|
|
847
|
+
pluginKeys: Object.keys(plugins).sort(),
|
|
848
|
+
buildMarker: plugins.buildMarker || null,
|
|
849
|
+
areaResult: plugins.SettingsSSO ? plugins.SettingsSSO() : null,
|
|
850
|
+
sharedCount: sharedToken.count,
|
|
851
|
+
commonLabel: commonLabel,
|
|
852
|
+
};
|
|
853
|
+
`,
|
|
854
|
+
);
|
|
855
|
+
|
|
856
|
+
// A stand-in Common, reached through <frontend>/node_modules/Common.
|
|
857
|
+
const common: string = path.join(layout.root, "packages", "Common");
|
|
858
|
+
writeFile(
|
|
859
|
+
path.join(common, "Label.ts"),
|
|
860
|
+
'export const commonLabel: string = "common-label";\n',
|
|
861
|
+
);
|
|
862
|
+
fs.mkdirSync(path.join(layout.frontendDir, "node_modules"), {
|
|
863
|
+
recursive: true,
|
|
864
|
+
});
|
|
865
|
+
fs.symlinkSync(
|
|
866
|
+
common,
|
|
867
|
+
path.join(layout.frontendDir, "node_modules", "Common"),
|
|
868
|
+
"dir",
|
|
869
|
+
);
|
|
870
|
+
|
|
871
|
+
if (options.withEnterprise) {
|
|
872
|
+
writeFile(
|
|
873
|
+
path.join(layout.eeDir, "Dashboard", "Area", "Plugins.ts"),
|
|
874
|
+
options.topLevelPluginRead
|
|
875
|
+
? `
|
|
876
|
+
import { getDashboardPlugins } from "@oneuptime/dashboard/Enterprise/Plugins";
|
|
877
|
+
const eager: any = getDashboardPlugins();
|
|
878
|
+
export default { SettingsSSO: (): string => String(eager) };
|
|
879
|
+
`
|
|
880
|
+
: `
|
|
881
|
+
import { renderShell } from "@oneuptime/dashboard/Components/Shell";
|
|
882
|
+
import { sharedToken } from "@oneuptime/dashboard/Utils/Shared";
|
|
883
|
+
import { commonLabel } from "Common/Label";
|
|
884
|
+
export default {
|
|
885
|
+
SettingsSSO: (): string => {
|
|
886
|
+
return commonLabel + ":" + typeof renderShell + ":" + sharedToken.count;
|
|
887
|
+
},
|
|
888
|
+
};
|
|
889
|
+
`,
|
|
890
|
+
);
|
|
891
|
+
|
|
892
|
+
writeFile(
|
|
893
|
+
layout.eeEntry,
|
|
894
|
+
`
|
|
895
|
+
import { DashboardEnterprisePlugins } from "@oneuptime/dashboard/Enterprise/EnterprisePlugins";
|
|
896
|
+
import AreaPlugins from "./Area/Plugins";
|
|
897
|
+
|
|
898
|
+
export const ONEUPTIME_EE_DASHBOARD_PLUGIN_SENTINEL: string =
|
|
899
|
+
"${DASHBOARD_SENTINEL}";
|
|
900
|
+
|
|
901
|
+
export default {
|
|
902
|
+
...AreaPlugins,
|
|
903
|
+
buildMarker: ONEUPTIME_EE_DASHBOARD_PLUGIN_SENTINEL,
|
|
904
|
+
} satisfies DashboardEnterprisePlugins;
|
|
905
|
+
`,
|
|
906
|
+
);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
return layout;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
/*
|
|
913
|
+
* Builds the fixture with the real createConfig plus the helper's aliases -
|
|
914
|
+
* exactly what esbuild.config.js does - then loads the bundle as ESM.
|
|
915
|
+
*/
|
|
916
|
+
function bundle(
|
|
917
|
+
layout: Layout,
|
|
918
|
+
overrides: Record<string, string | null>,
|
|
919
|
+
): BundleResult {
|
|
920
|
+
const outdir: string = path.join(layout.root, "out");
|
|
921
|
+
|
|
922
|
+
const script: string = `
|
|
923
|
+
const fs = require("fs");
|
|
924
|
+
const path = require("path");
|
|
925
|
+
const url = require("url");
|
|
926
|
+
const { createConfig } = require(${JSON.stringify(ESBUILD_CONFIG)});
|
|
927
|
+
const { resolveEnterpriseAliases } = require(${JSON.stringify(ESBUILD_ENTERPRISE)});
|
|
928
|
+
const esbuild = require(require.resolve("esbuild", {
|
|
929
|
+
paths: [${JSON.stringify(UI_DIR)}],
|
|
930
|
+
}));
|
|
931
|
+
|
|
932
|
+
const outdir = ${JSON.stringify(outdir)};
|
|
933
|
+
const empty = { ok: false, error: "", value: null };
|
|
934
|
+
|
|
935
|
+
(async function () {
|
|
936
|
+
let cfg;
|
|
937
|
+
let result;
|
|
938
|
+
try {
|
|
939
|
+
cfg = createConfig({
|
|
940
|
+
serviceName: "Dashboard",
|
|
941
|
+
publicPath: "/dashboard/dist/",
|
|
942
|
+
additionalAlias: resolveEnterpriseAliases({
|
|
943
|
+
frontendDir: ${JSON.stringify(layout.frontendDir)},
|
|
944
|
+
pluginSpecifier: "@oneuptime/ee-dashboard",
|
|
945
|
+
eeSubdir: "Dashboard",
|
|
946
|
+
internalSpecifier: "@oneuptime/dashboard",
|
|
947
|
+
}),
|
|
948
|
+
});
|
|
949
|
+
cfg.entryPoints = [${JSON.stringify(path.join(layout.frontendDir, "src", "Index.tsx"))}];
|
|
950
|
+
cfg.outdir = outdir;
|
|
951
|
+
cfg.metafile = true;
|
|
952
|
+
cfg.logLevel = "silent";
|
|
953
|
+
result = await esbuild.build(cfg);
|
|
954
|
+
} catch (error) {
|
|
955
|
+
console.log(JSON.stringify({
|
|
956
|
+
ok: false,
|
|
957
|
+
error: String((error && error.message) || error),
|
|
958
|
+
output: "",
|
|
959
|
+
inputs: [],
|
|
960
|
+
evaluated: empty,
|
|
961
|
+
}));
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
const files = fs.readdirSync(outdir).filter(function (file) {
|
|
966
|
+
return file.endsWith(".js");
|
|
967
|
+
});
|
|
968
|
+
const output = files.map(function (file) {
|
|
969
|
+
return fs.readFileSync(path.join(outdir, file), "utf8");
|
|
970
|
+
}).join("\\n");
|
|
971
|
+
|
|
972
|
+
// Load the bundle the way a browser would: as ES modules.
|
|
973
|
+
fs.writeFileSync(path.join(outdir, "package.json"), '{"type":"module"}');
|
|
974
|
+
let evaluated;
|
|
975
|
+
try {
|
|
976
|
+
await import(url.pathToFileURL(path.join(outdir, "Index.js")).href);
|
|
977
|
+
evaluated = { ok: true, error: "", value: globalThis.__fixtureResult };
|
|
978
|
+
} catch (error) {
|
|
979
|
+
evaluated = {
|
|
980
|
+
ok: false,
|
|
981
|
+
error: String((error && error.message) || error),
|
|
982
|
+
value: null,
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
console.log(JSON.stringify({
|
|
987
|
+
ok: true,
|
|
988
|
+
error: "",
|
|
989
|
+
output: output,
|
|
990
|
+
inputs: Object.keys(result.metafile.inputs),
|
|
991
|
+
evaluated: evaluated,
|
|
992
|
+
}));
|
|
993
|
+
})();
|
|
994
|
+
`;
|
|
995
|
+
|
|
996
|
+
return JSON.parse(runNode(script, overrides)) as BundleResult;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
function countInputs(inputs: Array<string>, suffix: string): number {
|
|
1000
|
+
return inputs.filter((input: string): boolean => {
|
|
1001
|
+
return input.endsWith(suffix);
|
|
1002
|
+
}).length;
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
test("an Enterprise production build carries the sentinel and loads", () => {
|
|
1006
|
+
const layout: Layout = makeBundleFixture({ withEnterprise: true });
|
|
1007
|
+
const result: BundleResult = bundle(layout, { NODE_ENV: "production" });
|
|
1008
|
+
|
|
1009
|
+
expect([result.ok, result.error]).toEqual([true, ""]);
|
|
1010
|
+
|
|
1011
|
+
// Minified and tree-shaken, and the sentinel is still there.
|
|
1012
|
+
expect(result.output).toContain(DASHBOARD_SENTINEL);
|
|
1013
|
+
expect(result.output).not.toContain(COMMUNITY_FIXTURE_MARKER);
|
|
1014
|
+
expect(countInputs(result.inputs, "ee/Dashboard/Index.tsx")).toBe(1);
|
|
1015
|
+
expect(countInputs(result.inputs, "Enterprise/CommunityPlugins.ts")).toBe(
|
|
1016
|
+
0,
|
|
1017
|
+
);
|
|
1018
|
+
|
|
1019
|
+
expect([result.evaluated.ok, result.evaluated.error]).toEqual([true, ""]);
|
|
1020
|
+
expect(result.evaluated.value).toEqual({
|
|
1021
|
+
shell: DASHBOARD_SENTINEL,
|
|
1022
|
+
pluginKeys: ["SettingsSSO", "buildMarker"],
|
|
1023
|
+
buildMarker: DASHBOARD_SENTINEL,
|
|
1024
|
+
// ee reached core through "@oneuptime/dashboard/..." and "Common/...".
|
|
1025
|
+
areaResult: "common-label:function:1",
|
|
1026
|
+
sharedCount: 1,
|
|
1027
|
+
commonLabel: "common-label",
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
1030
|
+
|
|
1031
|
+
test("core and ee share ONE instance of a core module", () => {
|
|
1032
|
+
/*
|
|
1033
|
+
* The entry imports Utils/Shared relatively and the ee area imports it as
|
|
1034
|
+
* "@oneuptime/dashboard/Utils/Shared". Two copies would mean two
|
|
1035
|
+
* singletons (two i18n instances, two stores) - the count above would
|
|
1036
|
+
* read 0 from the ee side.
|
|
1037
|
+
*/
|
|
1038
|
+
const layout: Layout = makeBundleFixture({ withEnterprise: true });
|
|
1039
|
+
const result: BundleResult = bundle(layout, { NODE_ENV: "production" });
|
|
1040
|
+
|
|
1041
|
+
expect(countInputs(result.inputs, "src/Utils/Shared.ts")).toBe(1);
|
|
1042
|
+
expect(countInputs(result.inputs, "Label.ts")).toBe(1);
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
test("an Enterprise development build carries the sentinel too", () => {
|
|
1046
|
+
const layout: Layout = makeBundleFixture({ withEnterprise: true });
|
|
1047
|
+
const result: BundleResult = bundle(layout, {});
|
|
1048
|
+
|
|
1049
|
+
expect([result.ok, result.error]).toEqual([true, ""]);
|
|
1050
|
+
expect(result.output).toContain(DASHBOARD_SENTINEL);
|
|
1051
|
+
expect(result.evaluated.value?.buildMarker).toBe(DASHBOARD_SENTINEL);
|
|
1052
|
+
});
|
|
1053
|
+
|
|
1054
|
+
test("a Community build has no sentinel and no ee code", () => {
|
|
1055
|
+
const layout: Layout = makeBundleFixture({ withEnterprise: false });
|
|
1056
|
+
const result: BundleResult = bundle(layout, { NODE_ENV: "production" });
|
|
1057
|
+
|
|
1058
|
+
expect([result.ok, result.error]).toEqual([true, ""]);
|
|
1059
|
+
expect(result.output).not.toContain(DASHBOARD_SENTINEL);
|
|
1060
|
+
expect(result.output).toContain(COMMUNITY_FIXTURE_MARKER);
|
|
1061
|
+
expect(countInputs(result.inputs, "Enterprise/CommunityPlugins.ts")).toBe(
|
|
1062
|
+
1,
|
|
1063
|
+
);
|
|
1064
|
+
expect(
|
|
1065
|
+
result.inputs.some((input: string): boolean => {
|
|
1066
|
+
return input.includes("ee/");
|
|
1067
|
+
}),
|
|
1068
|
+
).toBe(false);
|
|
1069
|
+
|
|
1070
|
+
expect(result.evaluated.value).toEqual({
|
|
1071
|
+
shell: "community",
|
|
1072
|
+
pluginKeys: [],
|
|
1073
|
+
buildMarker: null,
|
|
1074
|
+
areaResult: null,
|
|
1075
|
+
sharedCount: 1,
|
|
1076
|
+
commonLabel: "common-label",
|
|
1077
|
+
});
|
|
1078
|
+
});
|
|
1079
|
+
|
|
1080
|
+
test("ONEUPTIME_EDITION=community leaves ee/ out even when it is on disk", () => {
|
|
1081
|
+
const layout: Layout = makeBundleFixture({ withEnterprise: true });
|
|
1082
|
+
const result: BundleResult = bundle(layout, {
|
|
1083
|
+
NODE_ENV: "production",
|
|
1084
|
+
ONEUPTIME_EDITION: "community",
|
|
1085
|
+
});
|
|
1086
|
+
|
|
1087
|
+
expect([result.ok, result.error]).toEqual([true, ""]);
|
|
1088
|
+
expect(result.output).not.toContain(DASHBOARD_SENTINEL);
|
|
1089
|
+
expect(
|
|
1090
|
+
result.inputs.some((input: string): boolean => {
|
|
1091
|
+
return input.includes("ee/Dashboard");
|
|
1092
|
+
}),
|
|
1093
|
+
).toBe(false);
|
|
1094
|
+
expect(result.evaluated.value?.shell).toBe("community");
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
test("ONEUPTIME_EDITION=enterprise without ee/ fails before bundling anything", () => {
|
|
1098
|
+
const layout: Layout = makeBundleFixture({ withEnterprise: false });
|
|
1099
|
+
const result: BundleResult = bundle(layout, {
|
|
1100
|
+
NODE_ENV: "production",
|
|
1101
|
+
ONEUPTIME_EDITION: "enterprise",
|
|
1102
|
+
});
|
|
1103
|
+
|
|
1104
|
+
expect(result.ok).toBe(false);
|
|
1105
|
+
expect(result.error).toContain("ONEUPTIME_EDITION=enterprise");
|
|
1106
|
+
expect(fs.existsSync(path.join(layout.root, "out"))).toBe(false);
|
|
1107
|
+
});
|
|
1108
|
+
|
|
1109
|
+
test("reading the plugins at module load crashes the Enterprise bundle (why the rule exists)", () => {
|
|
1110
|
+
/*
|
|
1111
|
+
* The negative control for the "call getDashboardPlugins() only inside a
|
|
1112
|
+
* function" rule: the same cycle, but the ee area reads the plugins at
|
|
1113
|
+
* its top level. It builds fine and dies on load - and only in the
|
|
1114
|
+
* Enterprise build, which is why it needs a guard of its own
|
|
1115
|
+
* (App/Tests/EnterpriseImportGuard.test.ts).
|
|
1116
|
+
*/
|
|
1117
|
+
const layout: Layout = makeBundleFixture({
|
|
1118
|
+
withEnterprise: true,
|
|
1119
|
+
topLevelPluginRead: true,
|
|
1120
|
+
});
|
|
1121
|
+
const result: BundleResult = bundle(layout, { NODE_ENV: "production" });
|
|
1122
|
+
|
|
1123
|
+
expect([result.ok, result.error]).toEqual([true, ""]);
|
|
1124
|
+
expect(result.evaluated.ok).toBe(false);
|
|
1125
|
+
expect(result.evaluated.error).not.toBe("");
|
|
1126
|
+
});
|
|
1127
|
+
});
|