From 2f6999e9cc90f20bb9d2dd336f67b391ce9f49db Mon Sep 17 00:00:00 2001 From: Paul Fitzpatrick Date: Mon, 17 Jun 2024 14:31:43 -0400 Subject: [PATCH] updated at 2024-06-17T14:31:43-04:00 --- ext/app/client/components/Banners.ts | 25 ++++++++++---- .../client/lib/enterpriseDeploymentCheck.ts | 22 ++++++++++++ ext/app/client/ui/ActivationPage.ts | 10 ++++-- ext/app/client/ui/ProductUpgrades.ts | 34 ++++++------------- ext/app/server/lib/ActivationReader.ts | 23 ++++++++++--- ext/app/server/lib/create.ts | 21 +++++++----- ext/app/server/lib/logins.ts | 7 +++- 7 files changed, 97 insertions(+), 45 deletions(-) create mode 100644 ext/app/client/lib/enterpriseDeploymentCheck.ts diff --git a/ext/app/client/components/Banners.ts b/ext/app/client/components/Banners.ts index 1642862..c0f551c 100644 --- a/ext/app/client/components/Banners.ts +++ b/ext/app/client/components/Banners.ts @@ -16,16 +16,29 @@ */ import {buildActivationBanner} from 'app/client/components/ActivationBanner'; +import * as CoreBanners from 'app/client/components/CoreBanners'; import {DocUsageBanner} from 'app/client/components/DocUsageBanner'; import {SiteUsageBanner} from 'app/client/components/SiteUsageBanner'; import {AppModel} from 'app/client/models/AppModel'; import {DocPageModel} from 'app/client/models/DocPageModel'; import {dom} from 'grainjs'; +import {createEnterpriseSpecificFunc} from "app/client/lib/enterpriseDeploymentCheck"; -export function buildHomeBanners(app: AppModel) { - return buildActivationBanner() || dom.create(SiteUsageBanner, app); -} +const EEBanners = { + buildHomeBanners(app: AppModel) { + return buildActivationBanner() || dom.create(SiteUsageBanner, app); + }, + buildDocumentBanners(docPageModel: DocPageModel) { + return buildActivationBanner() || dom.create(DocUsageBanner, docPageModel); + } +}; -export function buildDocumentBanners(docPageModel: DocPageModel) { - return buildActivationBanner() || dom.create(DocUsageBanner, docPageModel); -} +export const buildHomeBanners = createEnterpriseSpecificFunc( + EEBanners.buildHomeBanners, + CoreBanners.buildHomeBanners +); + +export const buildDocumentBanners = createEnterpriseSpecificFunc( + EEBanners.buildDocumentBanners, + CoreBanners.buildDocumentBanners +); diff --git a/ext/app/client/lib/enterpriseDeploymentCheck.ts b/ext/app/client/lib/enterpriseDeploymentCheck.ts new file mode 100644 index 0000000..d32cd49 --- /dev/null +++ b/ext/app/client/lib/enterpriseDeploymentCheck.ts @@ -0,0 +1,22 @@ +import { GristDeploymentType } from "app/common/gristUrls"; +import { getGristConfig } from "app/common/urlUtils"; + +const enterpriseDeploymentTypes: GristDeploymentType[] = ['saas', 'enterprise']; +export function isEnterpriseDeployment(): boolean { + return enterpriseDeploymentTypes.includes(getGristConfig().deploymentType ?? 'core'); +} + +/** + * Calls one of the provided callbacks at call time, based on the edition of grist that's running. + * @param enterpriseCallback - Called when an enterprise deployment type is used. + * @param nonEnterpriseCallback - Called for non-enterprise deployment types (e.g. core, desktop). + */ +export function createEnterpriseSpecificFunc

( + enterpriseCallback: (...args: P) => R, + nonEnterpriseCallback: (...args: P) => R +) +{ + return function callCorrectCallback(...args: P): R { + return isEnterpriseDeployment() ? enterpriseCallback(...args) : nonEnterpriseCallback(...args); + }; +} diff --git a/ext/app/client/ui/ActivationPage.ts b/ext/app/client/ui/ActivationPage.ts index 6eb8f59..dff5a61 100644 --- a/ext/app/client/ui/ActivationPage.ts +++ b/ext/app/client/ui/ActivationPage.ts @@ -4,6 +4,7 @@ import {ActivationModel, ActivationModelImpl} from 'app/client/models/Activation import {urlState} from 'app/client/models/gristUrlState'; import * as css from 'app/client/ui/ActivationPageCss'; import {AppHeader} from 'app/client/ui/AppHeader'; +import {DefaultActivationPage, IActivationPageCreator} from 'app/client/ui/DefaultActivationPage'; import {createForbiddenPage} from 'app/client/ui/errorPages'; import {leftPanelBasic} from 'app/client/ui/LeftPanelCommon'; import {pagePanels} from 'app/client/ui/PagePanels'; @@ -13,13 +14,18 @@ import {bigPrimaryButtonLink} from 'app/client/ui2018/buttons'; import {cssLink} from 'app/client/ui2018/links'; import {loadingSpinner} from 'app/client/ui2018/loaders'; import {IActivationStatus} from 'app/common/ActivationAPI'; -import {commonUrls, getPageTitleSuffix} from 'app/common/gristUrls'; +import { commonUrls, getPageTitleSuffix } from 'app/common/gristUrls'; import {getGristConfig} from 'app/common/urlUtils'; import {Computed, Disposable, dom, makeTestId, Observable, subscribe} from 'grainjs'; +import {isEnterpriseDeployment} from "app/client/lib/enterpriseDeploymentCheck"; const testId = makeTestId('test-ap-'); -export class ActivationPage extends Disposable { +export function getActivationPage(): IActivationPageCreator { + return isEnterpriseDeployment() ? EnterpriseActivationPage : DefaultActivationPage; +} + +export class EnterpriseActivationPage extends Disposable { private readonly _currentPage = Computed.create(this, urlState().state, (_use, s) => s.activation); private _model: ActivationModel = new ActivationModelImpl(this._appModel); diff --git a/ext/app/client/ui/ProductUpgrades.ts b/ext/app/client/ui/ProductUpgrades.ts index 9cc5b2e..1b8f5a6 100644 --- a/ext/app/client/ui/ProductUpgrades.ts +++ b/ext/app/client/ui/ProductUpgrades.ts @@ -1,17 +1,13 @@ import type {AppModel} from 'app/client/models/AppModel'; import {PlanSelection} from 'app/common/BillingAPI'; -import {commonUrls} from 'app/common/gristUrls'; -import {Disposable, DomArg, DomContents, IDisposableOwner} from 'grainjs'; +import { commonUrls } from 'app/common/gristUrls'; +import {Disposable} from 'grainjs'; +import * as CoreTeamModals from "app/client/ui/CreateTeamModal"; +import {createEnterpriseSpecificFunc} from "app/client/lib/enterpriseDeploymentCheck"; -export async function buildNewSiteModal(context: Disposable, options: { - appModel: AppModel, - plan?: PlanSelection, - onCreate?: () => void -}) { - window.location.href = commonUrls.plans; -} +export const buildNewSiteModal = CoreTeamModals.buildNewSiteModal; -export async function buildUpgradeModal(owner: Disposable, options: { +async function buildEnterpriseUpgradeModal(owner: Disposable, options: { appModel: AppModel, pickPlan?: PlanSelection, reason?: 'upgrade' | 'renew', @@ -19,17 +15,9 @@ export async function buildUpgradeModal(owner: Disposable, options: { window.location.href = commonUrls.plans; } -export function showTeamUpgradeConfirmation(owner: Disposable) { -} +export const buildUpgradeModal = createEnterpriseSpecificFunc( + buildEnterpriseUpgradeModal, + CoreTeamModals.buildUpgradeModal, +); -export interface UpgradeButton { - showUpgradeCard(...args: DomArg[]): DomContents; - showUpgradeButton(...args: DomArg[]): DomContents; -} - -export function buildUpgradeButton(owner: IDisposableOwner, app: AppModel): UpgradeButton { - return { - showUpgradeCard : () => null, - showUpgradeButton : () => null, - }; -} +export const buildUpgradeButton = CoreTeamModals.buildUpgradeButton; diff --git a/ext/app/server/lib/ActivationReader.ts b/ext/app/server/lib/ActivationReader.ts index c1ae9f7..946c4b3 100644 --- a/ext/app/server/lib/ActivationReader.ts +++ b/ext/app/server/lib/ActivationReader.ts @@ -9,12 +9,25 @@ import * as fs from 'fs'; import * as jwt from 'jsonwebtoken'; import moment from 'moment'; -const GRIST_ACTIVATION = process.env.GRIST_ACTIVATION; -const GRIST_ACTIVATION_FILE = process.env.GRIST_ACTIVATION_FILE; -const TEST_ENABLE_ACTIVATION = process.env.TEST_ENABLE_ACTIVATION; +/** + * Export dependencies to allow dynamic changes with unit tests. + * Proxy process.env to allow behaviour changes without explicitly depending on this file. + */ +export const Deps = { + get GRIST_ACTIVATION() { + return process.env.GRIST_ACTIVATION; + }, + get GRIST_ACTIVATION_FILE() { + return process.env.GRIST_ACTIVATION_FILE; + }, + get TEST_ENABLE_ACTIVATION() { + return process.env.TEST_ENABLE_ACTIVATION; + } +}; -export const Deps = {GRIST_ACTIVATION, GRIST_ACTIVATION_FILE, - TEST_ENABLE_ACTIVATION}; +// If any of the activation environment variables are set, assume the host is trying to run enterprise. +export const isRunningEnterprise = + () => Deps.GRIST_ACTIVATION || Deps.GRIST_ACTIVATION_FILE || Deps.TEST_ENABLE_ACTIVATION; /** * Plan: when grist-ee is installed, it will show a trial period diff --git a/ext/app/server/lib/create.ts b/ext/app/server/lib/create.ts index bd2e859..90ac28b 100644 --- a/ext/app/server/lib/create.ts +++ b/ext/app/server/lib/create.ts @@ -1,14 +1,13 @@ import { Activation } from 'app/gen-server/lib/Activation'; import { configureSendGridNotifier } from 'app/gen-server/lib/configureSendGridNotifier'; -import { checkAzureExternalStorage, - configureAzureExternalStorage } from 'app/server/lib/configureAzureExternalStorage'; -import { checkMinIOExternalStorage, - configureMinIOExternalStorage } from 'app/server/lib/configureMinIOExternalStorage'; -import { checkS3ExternalStorage, - configureS3ExternalStorage } from 'app/server/lib/configureS3ExternalStorage'; -import { makeSimpleCreator } from 'app/server/lib/ICreate'; +import { checkAzureExternalStorage, configureAzureExternalStorage } from 'app/server/lib/configureAzureExternalStorage'; +import { checkMinIOExternalStorage, configureMinIOExternalStorage } from 'app/server/lib/configureMinIOExternalStorage'; +import { checkS3ExternalStorage, configureS3ExternalStorage } from 'app/server/lib/configureS3ExternalStorage'; +import { ICreate, makeSimpleCreator } from 'app/server/lib/ICreate'; +import { isRunningEnterprise } from 'app/server/lib/ActivationReader'; +import { makeCoreCreator } from 'app/server/lib/coreCreator'; -export const create = makeSimpleCreator({ +export const makeEnterpriseCreator = () => makeSimpleCreator({ deploymentType: 'enterprise', storage: [ { @@ -34,3 +33,9 @@ export const create = makeSimpleCreator({ create: configureSendGridNotifier, }, }); + +export const create = isRunningEnterprise() ? makeEnterpriseCreator() : makeCoreCreator(); + +export function getCreator(): ICreate { + return create; +} diff --git a/ext/app/server/lib/logins.ts b/ext/app/server/lib/logins.ts index 680f50f..162ffb9 100644 --- a/ext/app/server/lib/logins.ts +++ b/ext/app/server/lib/logins.ts @@ -3,10 +3,15 @@ import { GristLoginSystem } from 'app/server/lib/GristServer'; import { getMinimalLoginSystem } from 'app/server/lib/MinimalLogin'; import { getSamlLoginSystem } from 'app/server/lib/SamlConfig'; import { getConnectLoginSystem } from 'app/server/lib/GristConnect'; +import { isRunningEnterprise } from "app/server/lib/ActivationReader"; +import { getCoreLoginSystem } from 'app/server/lib/coreLogins'; -export async function getLoginSystem(): Promise { +export async function getEnterpriseLoginSystem(): Promise { return await getSamlLoginSystem() || await getForwardAuthLoginSystem() || await getConnectLoginSystem() || await getMinimalLoginSystem(); } + +export const getLoginSystem: () => Promise = + isRunningEnterprise() ? getEnterpriseLoginSystem : getCoreLoginSystem;