mirror of
https://github.com/gristlabs/grist-core.git
synced 2026-03-02 04:09:24 +00:00
(core) Comments
Summary: First iteration for comments system for Grist. - Comments are stored in a generic metatable `_grist_Cells` - Each comment is connected to a particular cell (hence the generic name of the table) - Access level works naturally for records stored in this table -- User can add/read comments for cells he can see -- User can't update/remove comments that he doesn't own, but he can delete them by removing cells (rows/columns) -- Anonymous users can't see comments at all. - Each comment can have replies (but replies can't have more replies) Comments are hidden by default, they can be enabled by COMMENTS=true env variable. Some things for follow-up - Avatars, currently the user's profile image is not shown or retrieved from the server - Virtual rendering for comments list in creator panel. Currently, there is a limit of 200 comments. Test Plan: New and existing tests Reviewers: georgegevoian, paulfitz Reviewed By: georgegevoian Subscribers: paulfitz Differential Revision: https://phab.getgrist.com/D3509
This commit is contained in:
43
app/client/models/entities/CellRec.ts
Normal file
43
app/client/models/entities/CellRec.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import {isCensored} from 'app/common/gristTypes';
|
||||
import * as ko from 'knockout';
|
||||
import {KoArray} from 'app/client/lib/koArray';
|
||||
import {jsonObservable} from 'app/client/models/modelUtil';
|
||||
import * as modelUtil from 'app/client/models/modelUtil';
|
||||
import {ColumnRec, DocModel, IRowModel, recordSet, refRecord, TableRec} from 'app/client/models/DocModel';
|
||||
|
||||
|
||||
export interface CellRec extends IRowModel<"_grist_Cells"> {
|
||||
column: ko.Computed<ColumnRec>;
|
||||
table: ko.Computed<TableRec>;
|
||||
children: ko.Computed<KoArray<CellRec>>;
|
||||
hidden: ko.Computed<boolean>;
|
||||
parent: ko.Computed<CellRec>;
|
||||
|
||||
text: modelUtil.KoSaveableObservable<string|undefined>;
|
||||
userName: modelUtil.KoSaveableObservable<string|undefined>;
|
||||
timeCreated: modelUtil.KoSaveableObservable<number|undefined>;
|
||||
timeUpdated: modelUtil.KoSaveableObservable<number|undefined>;
|
||||
resolved: modelUtil.KoSaveableObservable<boolean|undefined>;
|
||||
resolvedBy: modelUtil.KoSaveableObservable<string|undefined>;
|
||||
}
|
||||
|
||||
export function createCellRec(this: CellRec, docModel: DocModel): void {
|
||||
this.hidden = ko.pureComputed(() => isCensored(this.content()));
|
||||
this.column = refRecord(docModel.columns, this.colRef);
|
||||
this.table = refRecord(docModel.tables, this.tableRef);
|
||||
this.parent = refRecord(docModel.cells, this.parentId);
|
||||
this.children = recordSet(this, docModel.cells, 'parentId');
|
||||
const properContent = modelUtil.savingComputed({
|
||||
read: () => this.hidden() ? '{}' : this.content(),
|
||||
write: (setter, val) => setter(this.content, val)
|
||||
});
|
||||
const optionJson = jsonObservable(properContent);
|
||||
|
||||
// Comments:
|
||||
this.text = optionJson.prop('text');
|
||||
this.userName = optionJson.prop('userName');
|
||||
this.timeCreated = optionJson.prop('timeCreated');
|
||||
this.timeUpdated = optionJson.prop('timeUpdated');
|
||||
this.resolved = optionJson.prop('resolved');
|
||||
this.resolvedBy = optionJson.prop('resolvedBy');
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import {KoArray} from 'app/client/lib/koArray';
|
||||
import {DocModel, IRowModel, recordSet, refRecord, TableRec, ViewFieldRec} from 'app/client/models/DocModel';
|
||||
import {CellRec, DocModel, IRowModel, recordSet,
|
||||
refRecord, TableRec, ViewFieldRec} from 'app/client/models/DocModel';
|
||||
import {jsonObservable, ObjObservable} from 'app/client/models/modelUtil';
|
||||
import * as gristTypes from 'app/common/gristTypes';
|
||||
import {getReferencedTableId} from 'app/common/gristTypes';
|
||||
@@ -55,7 +56,7 @@ export interface ColumnRec extends IRowModel<"_grist_Tables_column"> {
|
||||
visibleColModel: ko.Computed<ColumnRec>;
|
||||
|
||||
disableModifyBase: ko.Computed<boolean>; // True if column config can't be modified (name, type, etc.)
|
||||
disableModify: ko.Computed<boolean>; // True if column can't be modified or is being transformed.
|
||||
disableModify: ko.Computed<boolean>; // True if column can't be modified (is summary) or is being transformed.
|
||||
disableEditData: ko.Computed<boolean>; // True to disable editing of the data in this column.
|
||||
|
||||
isHiddenCol: ko.Computed<boolean>;
|
||||
@@ -73,6 +74,7 @@ export interface ColumnRec extends IRowModel<"_grist_Tables_column"> {
|
||||
// (i.e. they aren't actually referenced but they exist in the visible column and are relevant to e.g. autocomplete)
|
||||
// `formatter` formats actual cell values, e.g. a whole list from the display column.
|
||||
formatter: ko.Computed<BaseFormatter>;
|
||||
cells: ko.Computed<KoArray<CellRec>>;
|
||||
|
||||
// Helper which adds/removes/updates column's displayCol to match the formula.
|
||||
saveDisplayFormula(formula: string): Promise<void>|undefined;
|
||||
@@ -83,6 +85,7 @@ export function createColumnRec(this: ColumnRec, docModel: DocModel): void {
|
||||
this.widgetOptionsJson = jsonObservable(this.widgetOptions);
|
||||
this.viewFields = recordSet(this, docModel.viewFields, 'colRef');
|
||||
this.summarySource = refRecord(docModel.columns, this.summarySourceCol);
|
||||
this.cells = recordSet(this, docModel.cells, 'colRef');
|
||||
|
||||
// Is this an empty column (undecided if formula or data); denoted by an empty formula.
|
||||
this.isEmpty = ko.pureComputed(() => this.isFormula() && this.formula() === '');
|
||||
|
||||
Reference in New Issue
Block a user