gristlabs_grist-core/app/client/ui/CellContextMenu.ts
Jarosław Sadziński bfd7243fe2 (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
2022-10-17 13:38:21 +02:00

88 lines
3.5 KiB
TypeScript

import { allCommands } from 'app/client/components/commands';
import { menuDivider, menuItemCmd } from 'app/client/ui2018/menus';
import { IMultiColumnContextMenu } from 'app/client/ui/GridViewMenus';
import { IRowContextMenu } from 'app/client/ui/RowContextMenu';
import { COMMENTS } from 'app/client/models/features';
import { dom } from 'grainjs';
export function CellContextMenu(rowOptions: IRowContextMenu, colOptions: IMultiColumnContextMenu) {
const { disableInsert, disableDelete, isViewSorted } = rowOptions;
const { disableModify, isReadonly } = colOptions;
// disableModify is true if the column is a summary column or is being transformed.
// isReadonly is true for readonly mode.
const disableForReadonlyColumn = dom.cls('disabled', Boolean(disableModify) || isReadonly);
const disableForReadonlyView = dom.cls('disabled', isReadonly);
const numCols: number = colOptions.numColumns;
const nameClearColumns = colOptions.isFiltered ?
(numCols > 1 ? `Clear ${numCols} entire columns` : 'Clear entire column') :
(numCols > 1 ? `Clear ${numCols} columns` : 'Clear column');
const nameDeleteColumns = numCols > 1 ? `Delete ${numCols} columns` : 'Delete column';
const numRows: number = rowOptions.numRows;
const nameDeleteRows = numRows > 1 ? `Delete ${numRows} rows` : 'Delete row';
const nameClearCells = (numRows > 1 || numCols > 1) ? 'Clear values' : 'Clear cell';
const result: Array<Element|null> = [];
result.push(
// TODO: implement copy/paste actions
colOptions.isFormula ?
null :
menuItemCmd(allCommands.clearValues, nameClearCells, disableForReadonlyColumn),
menuItemCmd(allCommands.clearColumns, nameClearColumns, disableForReadonlyColumn),
...(
(numCols > 1 || numRows > 1) ? [] : [
menuDivider(),
menuItemCmd(allCommands.copyLink, 'Copy anchor link'),
menuDivider(),
menuItemCmd(allCommands.filterByThisCellValue, `Filter by this value`),
menuItemCmd(allCommands.openDiscussion, 'Comment', dom.cls('disabled', (
isReadonly || numRows === 0 || numCols === 0
)), dom.hide(use => !use(COMMENTS())))
]
),
menuDivider(),
// inserts
...(
isViewSorted ?
// When the view is sorted, any newly added records get shifts instantly at the top or
// bottom. It could be very confusing for users who might expect the record to stay above or
// below the active row. Thus in this case we show a single `insert row` command.
[menuItemCmd(allCommands.insertRecordAfter, 'Insert row',
dom.cls('disabled', disableInsert))] :
[menuItemCmd(allCommands.insertRecordBefore, 'Insert row above',
dom.cls('disabled', disableInsert)),
menuItemCmd(allCommands.insertRecordAfter, 'Insert row below',
dom.cls('disabled', disableInsert))]
),
menuItemCmd(allCommands.duplicateRows, `Duplicate ${numRows === 1 ? 'row' : 'rows'}`,
dom.cls('disabled', disableInsert || numRows === 0)),
menuItemCmd(allCommands.insertFieldBefore, 'Insert column to the left',
disableForReadonlyView),
menuItemCmd(allCommands.insertFieldAfter, 'Insert column to the right',
disableForReadonlyView),
menuDivider(),
// deletes
menuItemCmd(allCommands.deleteRecords, nameDeleteRows, dom.cls('disabled', disableDelete)),
menuItemCmd(allCommands.deleteFields, nameDeleteColumns, disableForReadonlyColumn),
// todo: add "hide N columns"
);
return result;
}