(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:
Jarosław Sadziński
2022-10-17 11:47:16 +02:00
parent 8be920dd25
commit bfd7243fe2
41 changed files with 2621 additions and 77 deletions

View File

@@ -79,7 +79,6 @@ export function isRenameTable(act: DocAction): act is RenameTable { return act[0
const SCHEMA_ACTIONS = new Set(['AddTable', 'RemoveTable', 'RenameTable', 'AddColumn',
'RemoveColumn', 'RenameColumn', 'ModifyColumn']);
// Maps each data action to whether it's a bulk action.
const DATA_ACTIONS = new Set(['AddRecord', 'RemoveRecord', 'UpdateRecord', 'BulkAddRecord',
'BulkRemoveRecord', 'BulkUpdateRecord', 'ReplaceTableData', 'TableData']);

View File

@@ -45,6 +45,7 @@ export interface UserInfo {
Origin: string | null;
LinkKey: Record<string, string | undefined>;
UserID: number | null;
UserRef: string | null;
[attributes: string]: unknown;
toJSON(): {[key: string]: any};
}

View File

@@ -175,6 +175,7 @@ export interface UserAccessData {
id: number;
name: string;
email: string;
ref?: string|null;
picture?: string|null; // When present, a url to a public image of unspecified dimensions.
// Represents the user's direct access to the resource of interest. Lack of access to a resource
// is represented by a null value.

View File

@@ -344,3 +344,10 @@ export function isValidRuleValue(value: CellValue|undefined) {
}
export type RefListValue = [GristObjCode.List, ...number[]]|null;
/**
* Type of cell metadata information.
*/
export enum CellInfoType {
COMMENT = 1,
}

View File

@@ -568,6 +568,9 @@ export interface GristLoadConfig {
// Loaded namespaces for translations.
namespaces?: readonly string[];
// TODO: remove when comments will be released.
featureComments?: boolean;
}
export const HideableUiElements = StringUnion("helpCenter", "billing", "templates", "multiSite", "multiAccounts");

View File

@@ -4,7 +4,7 @@ import { GristObjCode } from "app/plugin/GristData";
// tslint:disable:object-literal-key-quotes
export const SCHEMA_VERSION = 32;
export const SCHEMA_VERSION = 33;
export const schema = {
@@ -196,6 +196,17 @@ export const schema = {
filter : "Text",
},
"_grist_Cells": {
tableRef : "Ref:_grist_Tables",
colRef : "Ref:_grist_Tables_column",
rowId : "Int",
root : "Bool",
parentId : "Ref:_grist_Cells",
type : "Int",
content : "Text",
userRef : "Text",
},
};
export interface SchemaTypes {
@@ -388,4 +399,15 @@ export interface SchemaTypes {
filter: string;
};
"_grist_Cells": {
tableRef: number;
colRef: number;
rowId: number;
root: boolean;
parentId: number;
type: number;
content: string;
userRef: string;
};
}