-
-
Notifications
You must be signed in to change notification settings - Fork 345
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Summary: This also enables the new Usage section for all sites. Currently, it shows metrics for document row count, but only if the user has full document read access. Otherwise, a message about insufficient access is shown. Test Plan: Browser tests. Reviewers: jarek Reviewed By: jarek Subscribers: alexmojaki Differential Revision: https://phab.getgrist.com/D3377
- Loading branch information
1 parent
01b1c31
commit af5b3c9
Showing
14 changed files
with
537 additions
and
199 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,171 @@ | ||
import {buildUpgradeMessage, getLimitStatusMessage} from 'app/client/components/DocumentUsage'; | ||
import {sessionStorageBoolObs} from 'app/client/lib/localStorageObs'; | ||
import {DocPageModel} from 'app/client/models/DocPageModel'; | ||
import {colors, isNarrowScreenObs} from 'app/client/ui2018/cssVars'; | ||
import {icon} from 'app/client/ui2018/icons'; | ||
import {Computed, Disposable, dom, DomComputed, makeTestId, Observable, styled} from 'grainjs'; | ||
|
||
const testId = makeTestId('test-doc-usage-banner-'); | ||
|
||
export class DocUsageBanner extends Disposable { | ||
// Whether the banner is vertically expanded on narrow screens. | ||
private readonly _isExpanded = Observable.create(this, true); | ||
|
||
private readonly _currentDoc = this._docPageModel.currentDoc; | ||
private readonly _currentDocId = this._docPageModel.currentDocId; | ||
private readonly _dataLimitStatus = this._docPageModel.dataLimitStatus; | ||
|
||
private readonly _currentOrg = Computed.create(this, this._currentDoc, (_use, doc) => { | ||
return doc?.workspace.org ?? null; | ||
}); | ||
|
||
private readonly _shouldShowBanner: Computed<boolean> = | ||
Computed.create(this, this._currentOrg, (_use, org) => { | ||
return org?.access !== 'guests' && org?.access !== null; | ||
}); | ||
|
||
// Session storage observable. Set to false to dismiss the banner for the session. | ||
private _showApproachingLimitBannerPref: Observable<boolean>; | ||
|
||
constructor(private _docPageModel: DocPageModel) { | ||
super(); | ||
this.autoDispose(this._currentDocId.addListener((docId) => { | ||
if (this._showApproachingLimitBannerPref?.isDisposed() === false) { | ||
this._showApproachingLimitBannerPref.dispose(); | ||
} | ||
const userId = this._docPageModel.appModel.currentUser?.id ?? 0; | ||
this._showApproachingLimitBannerPref = sessionStorageBoolObs( | ||
`u=${userId}:doc=${docId}:showApproachingLimitBanner`, | ||
true, | ||
); | ||
})); | ||
} | ||
|
||
public buildDom() { | ||
return dom.maybe(this._dataLimitStatus, (status): DomComputed => { | ||
switch (status) { | ||
case 'approachingLimit': { return this._buildApproachingLimitBanner(); } | ||
case 'gracePeriod': | ||
case 'deleteOnly': { return this._buildExceedingLimitBanner(status === 'deleteOnly'); } | ||
} | ||
}); | ||
} | ||
|
||
private _buildApproachingLimitBanner() { | ||
return dom.maybe(this._shouldShowBanner, () => { | ||
return dom.domComputed(use => { | ||
if (!use(this._showApproachingLimitBannerPref)) { | ||
return null; | ||
} | ||
|
||
const org = use(this._currentOrg); | ||
if (!org) { return null; } | ||
|
||
const features = org.billingAccount?.product.features; | ||
return cssApproachingLimitBanner( | ||
cssBannerMessage( | ||
cssWhiteIcon('Idea'), | ||
cssLightlyBoldedText( | ||
getLimitStatusMessage('approachingLimit', features), | ||
' ', | ||
buildUpgradeMessage(org.access === 'owners'), | ||
testId('text'), | ||
), | ||
), | ||
cssCloseButton('CrossBig', | ||
dom.on('click', () => this._showApproachingLimitBannerPref.set(false)), | ||
testId('close'), | ||
), | ||
testId('container'), | ||
); | ||
}); | ||
}); | ||
} | ||
|
||
private _buildExceedingLimitBanner(isDeleteOnly: boolean) { | ||
return dom.maybe(this._shouldShowBanner, () => { | ||
return dom.maybe(this._currentOrg, org => { | ||
const features = org.billingAccount?.product.features; | ||
return cssExceedingLimitBanner( | ||
cssBannerMessage( | ||
cssWhiteIcon('Idea'), | ||
cssLightlyBoldedText( | ||
dom.domComputed(use => { | ||
const isExpanded = use(this._isExpanded); | ||
const isNarrowScreen = use(isNarrowScreenObs()); | ||
const isOwner = org.access === 'owners'; | ||
if (isNarrowScreen && !isExpanded) { | ||
return buildUpgradeMessage(isOwner, 'short'); | ||
} | ||
|
||
return [ | ||
getLimitStatusMessage(isDeleteOnly ? 'deleteOnly' : 'gracePeriod', features), | ||
' ', | ||
buildUpgradeMessage(isOwner), | ||
]; | ||
}), | ||
testId('text'), | ||
), | ||
), | ||
dom.maybe(isNarrowScreenObs(), () => { | ||
return dom.domComputed(this._isExpanded, isExpanded => | ||
cssExpandButton( | ||
isExpanded ? 'DropdownUp' : 'Dropdown', | ||
dom.on('click', () => this._isExpanded.set(!isExpanded)), | ||
), | ||
); | ||
}), | ||
testId('container'), | ||
); | ||
}); | ||
}); | ||
} | ||
} | ||
|
||
const cssLightlyBoldedText = styled('div', ` | ||
font-weight: 500; | ||
`); | ||
|
||
const cssUsageBanner = styled('div', ` | ||
display: flex; | ||
align-items: flex-start; | ||
padding: 10px; | ||
color: white; | ||
gap: 16px; | ||
`); | ||
|
||
const cssApproachingLimitBanner = styled(cssUsageBanner, ` | ||
background: #E6A117; | ||
`); | ||
|
||
const cssExceedingLimitBanner = styled(cssUsageBanner, ` | ||
background: ${colors.error}; | ||
`); | ||
|
||
const cssIconAndText = styled('div', ` | ||
display: flex; | ||
gap: 16px; | ||
`); | ||
|
||
const cssBannerMessage = styled(cssIconAndText, ` | ||
flex-grow: 1; | ||
justify-content: center; | ||
`); | ||
|
||
const cssIcon = styled(icon, ` | ||
flex-shrink: 0; | ||
width: 16px; | ||
height: 16px; | ||
`); | ||
|
||
const cssWhiteIcon = styled(cssIcon, ` | ||
background-color: white; | ||
`); | ||
|
||
const cssCloseButton = styled(cssIcon, ` | ||
flex-shrink: 0; | ||
cursor: pointer; | ||
background-color: white; | ||
`); | ||
|
||
const cssExpandButton = cssCloseButton; |
Oops, something went wrong.