(core) Add API endpoint to get site usage summary

Summary:
The summary includes a count of documents that are approaching
limits, in grace period, or delete-only. The endpoint is only accessible
to site owners, and is currently unused. A follow-up diff will add usage
banners to the site home page, which will use the response from the
endpoint to communicate usage information to owners.

Test Plan: Browser and server tests.

Reviewers: alexmojaki

Reviewed By: alexmojaki

Differential Revision: https://phab.getgrist.com/D3420
This commit is contained in:
George Gevoian
2022-05-16 10:41:12 -07:00
parent cbdbe3f605
commit f48d579f64
23 changed files with 559 additions and 185 deletions

View File

@@ -5,7 +5,7 @@ import {ActionGroup} from 'app/common/ActionGroup';
import {ActiveDocAPI, ApplyUAOptions, ApplyUAResult} from 'app/common/ActiveDocAPI';
import {DocAction, UserAction} from 'app/common/DocActions';
import {OpenLocalDocResult} from 'app/common/DocListAPI';
import {DocUsage} from 'app/common/DocUsage';
import {FilteredDocUsageSummary} from 'app/common/DocUsage';
import {docUrl} from 'app/common/urlUtils';
import {Events as BackboneEvents} from 'backbone';
import {Disposable, Emitter} from 'grainjs';
@@ -18,7 +18,7 @@ export interface DocUserAction extends CommMessage {
data: {
docActions: DocAction[];
actionGroup: ActionGroup;
docUsage: DocUsage;
docUsage: FilteredDocUsageSummary;
error?: string;
};
}

View File

@@ -11,12 +11,12 @@ 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 _currentDocUsage = this._docPageModel.currentDocUsage;
private readonly _currentOrg = this._docPageModel.currentOrg;
private readonly _currentOrg = Computed.create(this, this._currentDoc, (_use, doc) => {
return doc?.workspace.org ?? null;
private readonly _dataLimitStatus = Computed.create(this, this._currentDocUsage, (_use, usage) => {
return usage?.dataLimitStatus ?? null;
});
private readonly _shouldShowBanner: Computed<boolean> =

View File

@@ -30,13 +30,23 @@ const ACCESS_DENIED_MESSAGE = 'Usage statistics are only available to users with
*/
export class DocumentUsage extends Disposable {
private readonly _currentDoc = this._docPageModel.currentDoc;
private readonly _dataLimitStatus = this._docPageModel.dataLimitStatus;
private readonly _rowCount = this._docPageModel.rowCount;
private readonly _dataSizeBytes = this._docPageModel.dataSizeBytes;
private readonly _attachmentsSizeBytes = this._docPageModel.attachmentsSizeBytes;
private readonly _currentDocUsage = this._docPageModel.currentDocUsage;
private readonly _currentOrg = this._docPageModel.currentOrg;
private readonly _currentOrg = Computed.create(this, this._currentDoc, (_use, doc) => {
return doc?.workspace.org ?? null;
private readonly _dataLimitStatus = Computed.create(this, this._currentDocUsage, (_use, usage) => {
return usage?.dataLimitStatus ?? null;
});
private readonly _rowCount = Computed.create(this, this._currentDocUsage, (_use, usage) => {
return usage?.rowCount;
});
private readonly _dataSizeBytes = Computed.create(this, this._currentDocUsage, (_use, usage) => {
return usage?.dataSizeBytes;
});
private readonly _attachmentsSizeBytes = Computed.create(this, this._currentDocUsage, (_use, usage) => {
return usage?.attachmentsSizeBytes;
});
private readonly _rowMetrics: Computed<MetricOptions | null> =
@@ -102,7 +112,9 @@ export class DocumentUsage extends Disposable {
Computed.create(
this, this._currentDoc, this._rowCount, this._dataSizeBytes, this._attachmentsSizeBytes,
(_use, doc, rowCount, dataSize, attachmentsSize) => {
return !doc || [rowCount, dataSize, attachmentsSize].some(metric => metric === 'pending');
return !doc || [rowCount, dataSize, attachmentsSize].some(metric => {
return metric === 'pending' || metric === undefined;
});
}
);

View File

@@ -478,7 +478,7 @@ export class GristDoc extends DisposableWithEvents {
if (schemaUpdated) {
this.trigger('schemaUpdateAction', docActions);
}
this.docPageModel.updateDocUsage(message.data.docUsage);
this.docPageModel.updateCurrentDocUsage(message.data.docUsage);
}
}