mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) Use new Banner component for activation messages
Summary: Use new Banner component for activation messages. Test Plan: Existing tests. Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D3483
This commit is contained in:
parent
02dd96daf2
commit
7176b7efb6
@ -1,93 +0,0 @@
|
|||||||
import {Banner, buildBannerMessage} from 'app/client/components/Banner';
|
|
||||||
import {buildUpgradeMessage} from 'app/client/components/DocumentUsage';
|
|
||||||
import {sessionStorageBoolObs} from 'app/client/lib/localStorageObs';
|
|
||||||
import {AppModel} from 'app/client/models/AppModel';
|
|
||||||
import {isFreeProduct} from 'app/common/Features';
|
|
||||||
import {isOwner} from 'app/common/roles';
|
|
||||||
import {Disposable, dom, makeTestId, Observable} from 'grainjs';
|
|
||||||
|
|
||||||
const testId = makeTestId('test-site-usage-banner-');
|
|
||||||
|
|
||||||
export class SiteUsageBanner extends Disposable {
|
|
||||||
private readonly _currentOrg = this._app.currentOrg;
|
|
||||||
private readonly _currentOrgUsage = this._app.currentOrgUsage;
|
|
||||||
private readonly _product = this._currentOrg?.billingAccount?.product;
|
|
||||||
private readonly _currentUser = this._app.currentValidUser;
|
|
||||||
|
|
||||||
// Session storage observable. Set to false to dismiss the banner for the session.
|
|
||||||
private _showApproachingLimitBannerPref?: Observable<boolean>;
|
|
||||||
|
|
||||||
constructor(private _app: AppModel) {
|
|
||||||
super();
|
|
||||||
|
|
||||||
if (this._currentUser && isOwner(this._currentOrg)) {
|
|
||||||
this._showApproachingLimitBannerPref = this.autoDispose(sessionStorageBoolObs(
|
|
||||||
`u=${this._currentUser.id}:org=${this._currentOrg.id}:showApproachingLimitBanner`,
|
|
||||||
true,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public buildDom() {
|
|
||||||
return dom.maybe(this._currentOrgUsage, (usage) => {
|
|
||||||
const {approachingLimit, gracePeriod, deleteOnly} = usage;
|
|
||||||
if (deleteOnly > 0 || gracePeriod > 0) {
|
|
||||||
return this._buildExceedingLimitsBanner(deleteOnly + gracePeriod);
|
|
||||||
} else if (approachingLimit > 0) {
|
|
||||||
return this._buildApproachingLimitsBanner(approachingLimit);
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _buildApproachingLimitsBanner(numDocs: number) {
|
|
||||||
return dom.domComputed(use => {
|
|
||||||
if (this._showApproachingLimitBannerPref && !use(this._showApproachingLimitBannerPref)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const limitsMessage = numDocs > 1
|
|
||||||
? `${numDocs} documents are approaching their limits.`
|
|
||||||
: `${numDocs} document is approaching its limits.`;
|
|
||||||
return dom.create(Banner, {
|
|
||||||
content: buildBannerMessage(
|
|
||||||
limitsMessage,
|
|
||||||
(this._product && isFreeProduct(this._product)
|
|
||||||
? [' ', buildUpgradeMessage(true)]
|
|
||||||
: null
|
|
||||||
),
|
|
||||||
testId('text'),
|
|
||||||
),
|
|
||||||
style: 'warning',
|
|
||||||
showCloseButton: true,
|
|
||||||
onClose: () => this._showApproachingLimitBannerPref?.set(false),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private _buildExceedingLimitsBanner(numDocs: number) {
|
|
||||||
const limitsMessage = numDocs > 1
|
|
||||||
? `${numDocs} documents have exceeded their limits.`
|
|
||||||
: `${numDocs} document has exceeded its limits.`;
|
|
||||||
return dom.create(Banner, {
|
|
||||||
content: buildBannerMessage(
|
|
||||||
limitsMessage,
|
|
||||||
(this._product && isFreeProduct(this._product)
|
|
||||||
? [' ', buildUpgradeMessage(true)]
|
|
||||||
: null
|
|
||||||
),
|
|
||||||
testId('text'),
|
|
||||||
),
|
|
||||||
contentSmall: buildBannerMessage(
|
|
||||||
(this._product && isFreeProduct(this._product)
|
|
||||||
? buildUpgradeMessage(true, 'short')
|
|
||||||
: limitsMessage
|
|
||||||
),
|
|
||||||
),
|
|
||||||
style: 'error',
|
|
||||||
showCloseButton: false,
|
|
||||||
showExpandButton: true,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,4 @@
|
|||||||
import {DocUsageBanner} from 'app/client/components/DocUsageBanner';
|
import {buildDocumentBanners, buildHomeBanners} from 'app/client/components/Banners';
|
||||||
import {SiteUsageBanner} from 'app/client/components/SiteUsageBanner';
|
|
||||||
import {domAsync} from 'app/client/lib/domAsync';
|
import {domAsync} from 'app/client/lib/domAsync';
|
||||||
import {loadBillingPage} from 'app/client/lib/imports';
|
import {loadBillingPage} from 'app/client/lib/imports';
|
||||||
import {createSessionObs, isBoolean, isNumber} from 'app/client/lib/sessionObs';
|
import {createSessionObs, isBoolean, isNumber} from 'app/client/lib/sessionObs';
|
||||||
@ -105,7 +104,7 @@ function pagePanelsHome(owner: IDisposableOwner, appModel: AppModel, app: App) {
|
|||||||
},
|
},
|
||||||
headerMain: createTopBarHome(appModel),
|
headerMain: createTopBarHome(appModel),
|
||||||
contentMain: createDocMenu(pageModel),
|
contentMain: createDocMenu(pageModel),
|
||||||
contentTop: dom.create(SiteUsageBanner, appModel),
|
contentTop: buildHomeBanners(appModel),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,7 +154,7 @@ function pagePanelsDoc(owner: IDisposableOwner, appModel: AppModel, appObj: App)
|
|||||||
contentMain: dom.maybe(pageModel.gristDoc, (gristDoc) => gristDoc.buildDom()),
|
contentMain: dom.maybe(pageModel.gristDoc, (gristDoc) => gristDoc.buildDom()),
|
||||||
onResize,
|
onResize,
|
||||||
testId,
|
testId,
|
||||||
contentTop: dom.create(DocUsageBanner, pageModel),
|
contentTop: buildDocumentBanners(pageModel),
|
||||||
contentBottom: dom.create(createBottomBarDoc, pageModel, leftPanelOpen, rightPanelOpen),
|
contentBottom: dom.create(createBottomBarDoc, pageModel, leftPanelOpen, rightPanelOpen),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import {SiteUsageBanner} from 'app/client/components/SiteUsageBanner';
|
import {buildHomeBanners} from 'app/client/components/Banners';
|
||||||
import {beaconOpenMessage} from 'app/client/lib/helpScout';
|
import {beaconOpenMessage} from 'app/client/lib/helpScout';
|
||||||
import {AppModel, reportError} from 'app/client/models/AppModel';
|
import {AppModel, reportError} from 'app/client/models/AppModel';
|
||||||
import {BillingModel, BillingModelImpl, ISubscriptionModel} from 'app/client/models/BillingModel';
|
import {BillingModel, BillingModelImpl, ISubscriptionModel} from 'app/client/models/BillingModel';
|
||||||
@ -66,7 +66,7 @@ export class BillingPage extends Disposable {
|
|||||||
content: leftPanelBasic(this._appModel, panelOpen),
|
content: leftPanelBasic(this._appModel, panelOpen),
|
||||||
},
|
},
|
||||||
headerMain: this._createTopBarBilling(),
|
headerMain: this._createTopBarBilling(),
|
||||||
contentTop: dom.create(SiteUsageBanner, this._appModel),
|
contentTop: buildHomeBanners(this._appModel),
|
||||||
contentMain: this._buildCurrentPageDom()
|
contentMain: this._buildCurrentPageDom()
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -94,22 +94,7 @@ export function makeSendAppPage(opts: {
|
|||||||
const staticOrigin = process.env.APP_STATIC_URL || "";
|
const staticOrigin = process.env.APP_STATIC_URL || "";
|
||||||
const staticBaseUrl = `${staticOrigin}/v/${options.tag || tag}/`;
|
const staticBaseUrl = `${staticOrigin}/v/${options.tag || tag}/`;
|
||||||
const customHeadHtmlSnippet = server?.create.getExtraHeadHtml?.() ?? "";
|
const customHeadHtmlSnippet = server?.create.getExtraHeadHtml?.() ?? "";
|
||||||
// TODO: Temporary changes until there is a handy banner to put this in.
|
const warning = testLogin ? "<div class=\"dev_warning\">Authentication is not enforced</div>" : "";
|
||||||
let warning = testLogin ? "<div class=\"dev_warning\">Authentication is not enforced</div>" : "";
|
|
||||||
const activation = config.activation;
|
|
||||||
if (!warning && activation) {
|
|
||||||
if (activation.trial) {
|
|
||||||
warning = `Trial: ${activation.trial.daysLeft} day(s) left`;
|
|
||||||
} else if (activation.needKey) {
|
|
||||||
warning = 'Activation key needed. Documents in read-only mode.';
|
|
||||||
} else if (activation.key?.daysLeft && activation.key.daysLeft < 30) {
|
|
||||||
warning = `Need reactivation in ${activation.key.daysLeft} day(s)`;
|
|
||||||
}
|
|
||||||
if (warning) {
|
|
||||||
warning = `<div class="dev_warning activation-msg">${warning}</div>`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Temporary changes end.
|
|
||||||
const content = fileContent
|
const content = fileContent
|
||||||
.replace("<!-- INSERT WARNING -->", warning)
|
.replace("<!-- INSERT WARNING -->", warning)
|
||||||
.replace("<!-- INSERT TITLE SUFFIX -->", getPageTitleSuffix(server?.getGristConfig()))
|
.replace("<!-- INSERT TITLE SUFFIX -->", getPageTitleSuffix(server?.getGristConfig()))
|
||||||
|
10
stubs/app/client/components/Banners.ts
Normal file
10
stubs/app/client/components/Banners.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
import {AppModel} from 'app/client/models/AppModel';
|
||||||
|
import {DocPageModel} from 'app/client/models/DocPageModel';
|
||||||
|
|
||||||
|
export function buildHomeBanners(_app: AppModel) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildDocumentBanners(_docPageModel: DocPageModel) {
|
||||||
|
return null;
|
||||||
|
}
|
@ -1,10 +0,0 @@
|
|||||||
import {DocPageModel} from 'app/client/models/DocPageModel';
|
|
||||||
import {Disposable} from 'grainjs';
|
|
||||||
|
|
||||||
export class DocUsageBanner extends Disposable {
|
|
||||||
constructor(_docPageModel: DocPageModel) { super(); }
|
|
||||||
|
|
||||||
public buildDom() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user