(core) Adding UI for timing API

Summary:
Adding new buttons to control the `timing` API and a way to view the results
using virtual table features.

Test Plan: Added new

Reviewers: georgegevoian

Reviewed By: georgegevoian

Subscribers: paulfitz

Differential Revision: https://phab.getgrist.com/D4252
This commit is contained in:
Jarosław Sadziński
2024-05-21 18:27:06 +02:00
parent 60423edc17
commit a6ffa6096a
29 changed files with 858 additions and 144 deletions

View File

@@ -1,6 +1,6 @@
import {textarea} from 'app/client/ui/inputs';
import {sanitizeHTML} from 'app/client/ui/sanitizeHTML';
import {basicButton, basicButtonLink, textButton} from 'app/client/ui2018/buttons';
import {basicButton, basicButtonLink, primaryButtonLink, textButton} from 'app/client/ui2018/buttons';
import {cssLabel} from 'app/client/ui2018/checkbox';
import {colors, theme} from 'app/client/ui2018/cssVars';
import {icon} from 'app/client/ui2018/icons';
@@ -403,7 +403,7 @@ export const cssSmallLinkButton = styled(basicButtonLink, `
min-height: 26px;
`);
export const cssSmallButton = styled(basicButton, `
const textSmallButton = `
display: flex;
align-items: center;
gap: 4px;
@@ -423,7 +423,10 @@ export const cssSmallButton = styled(basicButton, `
background-color: #B8791B;
border: none;
}
`);
`;
export const cssSmallButton = styled(basicButton, textSmallButton);
export const cssPrimarySmallLink = styled(primaryButtonLink, textSmallButton);
export const cssMarkdownRendered = styled('div', `
min-height: 1.5rem;

View File

@@ -79,6 +79,7 @@ function GridView(gristDoc, viewSectionModel, isPreview = false) {
BaseView.call(this, gristDoc, viewSectionModel, { isPreview, 'addNewRow': true });
this.viewSection = viewSectionModel;
this.isReadonly = this.gristDoc.isReadonly.get() || this.viewSection.isVirtual();
//--------------------------------------------------
// Observables local to this view
@@ -390,7 +391,7 @@ GridView.gridCommands = {
if (!action) { return; }
// if grist document is in readonly - simply change the value
// without saving
if (this.gristDoc.isReadonly.get()) {
if (this.isReadonly) {
this.viewSection.rawNumFrozen(action.numFrozen);
return;
}
@@ -1270,7 +1271,7 @@ GridView.prototype.buildDom = function() {
const isEditingLabel = koUtil.withKoUtils(ko.pureComputed({
read: () => {
const goodIndex = () => editIndex() === field._index();
const isReadonly = () => this.gristDoc.isReadonlyKo() || self.isPreview;
const isReadonly = () => this.isReadonly || self.isPreview;
const isSummary = () => Boolean(field.column().disableEditData());
return goodIndex() && !isReadonly() && !isSummary();
},
@@ -1335,7 +1336,7 @@ GridView.prototype.buildDom = function() {
},
kd.style('width', field.widthPx),
kd.style('borderRightWidth', v.borderWidthPx),
viewCommon.makeResizable(field.width, {shouldSave: !this.gristDoc.isReadonly.get()}),
viewCommon.makeResizable(field.width, {shouldSave: !this.isReadonly}),
kd.toggleClass('selected', () => ko.unwrap(this.isColSelected.at(field._index()))),
dom.on('contextmenu', ev => {
// This is a little hack to position the menu the same way as with a click
@@ -1382,7 +1383,7 @@ GridView.prototype.buildDom = function() {
this._buildInsertColumnMenu({field}),
);
}),
this.isPreview ? null : kd.maybe(() => !this.gristDoc.isReadonlyKo(), () => (
this.isPreview ? null : kd.maybe(() => !this.isReadonly, () => (
this._modField = dom('div.column_name.mod-add-column.field',
'+',
kd.style("width", PLUS_WIDTH + 'px'),
@@ -1933,7 +1934,7 @@ GridView.prototype._getColumnMenuOptions = function(copySelection) {
numColumns: copySelection.fields.length,
numFrozen: this.viewSection.numFrozen.peek(),
disableModify: calcFieldsCondition(copySelection.fields, f => f.disableModify.peek()),
isReadonly: this.gristDoc.isReadonly.get() || this.isPreview,
isReadonly: this.isReadonly || this.isPreview,
isRaw: this.viewSection.isRaw(),
isFiltered: this.isFiltered(),
isFormula: calcFieldsCondition(copySelection.fields, f => f.column.peek().isRealFormula.peek()),
@@ -1999,17 +2000,17 @@ GridView.prototype.cellContextMenu = function() {
GridView.prototype._getCellContextMenuOptions = function() {
return {
disableInsert: Boolean(
this.gristDoc.isReadonly.get() ||
this.isReadonly ||
this.viewSection.disableAddRemoveRows() ||
this.tableModel.tableMetaRow.onDemand()
),
disableDelete: Boolean(
this.gristDoc.isReadonly.get() ||
this.isReadonly ||
this.viewSection.disableAddRemoveRows() ||
this.getSelection().onlyAddRowSelected()
),
disableMakeHeadersFromRow: Boolean(
this.gristDoc.isReadonly.get() ||
this.isReadonly ||
this.getSelection().rowIds.length !== 1 ||
this.getSelection().onlyAddRowSelected() ||
this.viewSection.table().summarySourceTable() !== 0

View File

@@ -49,6 +49,7 @@ import {DocSettingsPage} from 'app/client/ui/DocumentSettings';
import {isTourActive, isTourActiveObs} from "app/client/ui/OnBoardingPopups";
import {DefaultPageWidget, IPageWidget, toPageWidget} from 'app/client/ui/PageWidgetPicker';
import {linkFromId, NoLink, selectBy} from 'app/client/ui/selectBy';
import {TimingPage} from 'app/client/ui/TimingPage';
import {WebhookPage} from 'app/client/ui/WebhookPage';
import {startWelcomeTour} from 'app/client/ui/WelcomeTour';
import {getTelemetryWidgetTypeFromPageWidget} from 'app/client/ui/widgetTypesMap';
@@ -196,6 +197,8 @@ export class GristDoc extends DisposableWithEvents {
return this.docPageModel.appModel.api.getDocAPI(this.docPageModel.currentDocId.get()!);
}
public isTimingOn = Observable.create(this, false);
private _actionLog: ActionLog;
private _undoStack: UndoStack;
private _lastOwnActionGroup: ActionGroupWithCursorPos | null = null;
@@ -228,6 +231,7 @@ export class GristDoc extends DisposableWithEvents {
) {
super();
console.log("RECEIVED DOC RESPONSE", openDocResponse);
this.isTimingOn.set(openDocResponse.isTimingOn);
this.docData = new DocData(this.docComm, openDocResponse.doc);
this.docModel = new DocModel(this.docData, this.docPageModel);
this.querySetManager = QuerySetManager.create(this, this.docModel, this.docComm);
@@ -635,6 +639,7 @@ export class GristDoc extends DisposableWithEvents {
content === 'data' ? dom.create(RawDataPage, this) :
content === 'settings' ? dom.create(DocSettingsPage, this) :
content === 'webhook' ? dom.create(WebhookPage, this) :
content === 'timing' ? dom.create(TimingPage, this) :
content === 'GristDocTour' ? null :
[
dom.create((owner) => {
@@ -842,16 +847,20 @@ export class GristDoc extends DisposableWithEvents {
}
public onDocChatter(message: CommDocChatter) {
if (!this.docComm.isActionFromThisDoc(message) ||
!message.data.webhooks) {
if (!this.docComm.isActionFromThisDoc(message)) {
return;
}
if (message.data.webhooks.type == 'webhookOverflowError') {
this.trigger('webhookOverflowError',
t('New changes are temporarily suspended. Webhooks queue overflowed.' +
' Please check webhooks settings, remove invalid webhooks, and clean the queue.'),);
} else {
this.trigger('webhooks', message.data.webhooks);
if (message.data.webhooks) {
if (message.data.webhooks.type == 'webhookOverflowError') {
this.trigger('webhookOverflowError',
t('New changes are temporarily suspended. Webhooks queue overflowed.' +
' Please check webhooks settings, remove invalid webhooks, and clean the queue.'),);
} else {
this.trigger('webhooks', message.data.webhooks);
}
} else if (message.data.timing) {
this.isTimingOn.set(message.data.timing.status !== 'disabled');
}
}