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:
BIN
test/fixtures/docs/Hello.grist
vendored
BIN
test/fixtures/docs/Hello.grist
vendored
Binary file not shown.
@@ -68,13 +68,13 @@ describe('Pages', function() {
|
||||
await gu.waitForServer();
|
||||
|
||||
// Click on a page; check the URL, selected item, and the title of the view section.
|
||||
await clickPage(/Documents/)
|
||||
await gu.openPage(/Documents/);
|
||||
assert.match(await driver.getCurrentUrl(), /\/p\/3/);
|
||||
assert.match(await driver.find('.test-treeview-itemHeader.selected').getText(), /Documents/);
|
||||
assert.match(await gu.getActiveSectionTitle(), /Documents/i);
|
||||
|
||||
// Click on another page; check the URL, selected item, and the title of the view section.
|
||||
await clickPage(/People/)
|
||||
await gu.openPage(/People/);
|
||||
assert.match(await driver.getCurrentUrl(), /\/p\/2/);
|
||||
assert.match(await driver.find('.test-treeview-itemHeader.selected').getText(), /People/);
|
||||
assert.match(await gu.getActiveSectionTitle(), /People/i);
|
||||
@@ -109,7 +109,7 @@ describe('Pages', function() {
|
||||
|
||||
it('should allow renaming table when click on page selected label', async () => {
|
||||
// do rename
|
||||
await clickPage(/People/)
|
||||
await gu.openPage(/People/);
|
||||
await driver.findContent('.test-treeview-label', 'People').doClick();
|
||||
await driver.find('.test-docpage-editor').sendKeys('PeopleRenamed', Key.ENTER);
|
||||
await gu.waitForServer();
|
||||
@@ -214,7 +214,7 @@ describe('Pages', function() {
|
||||
}
|
||||
|
||||
// goto page 'Interactions'
|
||||
await clickPage(/Interactions/);
|
||||
await gu.openPage(/Interactions/);
|
||||
|
||||
// check selected page
|
||||
assert.match(await selectedPage(), /Interactions/);
|
||||
@@ -249,7 +249,7 @@ describe('Pages', function() {
|
||||
it('undo/redo should update url', async () => {
|
||||
|
||||
// goto page 'Interactions' and send keys
|
||||
await clickPage(/Interactions/);
|
||||
await gu.openPage(/Interactions/);
|
||||
assert.match(await driver.find('.test-treeview-itemHeader.selected').getText(), /Interactions/);
|
||||
await driver.findContentWait('.gridview_data_row_num', /1/, 2000);
|
||||
await driver.sendKeys(Key.ENTER, 'Foo', Key.ENTER);
|
||||
@@ -257,7 +257,7 @@ describe('Pages', function() {
|
||||
assert.deepEqual(await gu.getVisibleGridCells(0, [1]), ['Foo']);
|
||||
|
||||
// goto page 'People' and click undo
|
||||
await clickPage(/People/);
|
||||
await gu.openPage(/People/);
|
||||
await gu.waitForDocToLoad();
|
||||
await gu.waitForUrl(/\/p\/2\b/); // check that url match p/2
|
||||
|
||||
@@ -277,7 +277,7 @@ describe('Pages', function() {
|
||||
|
||||
it('Add new page should update url', async () => {
|
||||
// goto page 'Interactions' and check that url updated
|
||||
await clickPage(/Interactions/);
|
||||
await gu.openPage(/Interactions/);
|
||||
await gu.waitForUrl(/\/p\/1\b/);
|
||||
|
||||
// Add new Page, check that url updated and page is selected
|
||||
@@ -286,7 +286,7 @@ describe('Pages', function() {
|
||||
assert.match(await driver.find('.test-treeview-itemHeader.selected').getText(), /Table1/);
|
||||
|
||||
// goto page 'Interactions' and check that url updated and page selectd
|
||||
await clickPage(/Interactions/);
|
||||
await gu.openPage(/Interactions/);
|
||||
await gu.waitForUrl(/\/p\/1\b/);
|
||||
assert.match(await driver.find('.test-treeview-itemHeader.selected').getText(), /Interactions/);
|
||||
});
|
||||
@@ -496,7 +496,3 @@ async function movePage(page: RegExp, target: {before: RegExp}|{after: RegExp})
|
||||
})
|
||||
.release());
|
||||
}
|
||||
|
||||
function clickPage(name: string|RegExp) {
|
||||
return driver.findContent('.test-treeview-itemHeader', name).find(".test-docpage-initial").doClick();
|
||||
}
|
||||
|
||||
@@ -860,6 +860,11 @@ export function getPageItem(pageName: string|RegExp): WebElementPromise {
|
||||
.findClosest('.test-treeview-itemHeaderWrapper');
|
||||
}
|
||||
|
||||
export async function openPage(name: string|RegExp) {
|
||||
await driver.findContentWait('.test-treeview-itemHeader', name, 500).find(".test-docpage-initial").doClick();
|
||||
await waitForServer(); // wait for table load
|
||||
}
|
||||
|
||||
/**
|
||||
* Open the page menu for the specified page (by clicking the dots icon visible on hover).
|
||||
*/
|
||||
@@ -1082,9 +1087,9 @@ export async function renameColumn(col: IColHeader, newName: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a table using RAW data view. Return back a current url.
|
||||
* Removes a table using RAW data view. Returns a current url.
|
||||
*/
|
||||
export async function removeTable(tableId: string) {
|
||||
export async function removeTable(tableId: string, goBack: boolean = false) {
|
||||
const back = await driver.getCurrentUrl();
|
||||
await driver.find(".test-tools-raw").click();
|
||||
const tableIdList = await driver.findAll('.test-raw-data-table-id', e => e.getText());
|
||||
@@ -1096,6 +1101,10 @@ export async function removeTable(tableId: string) {
|
||||
await driver.find(".test-raw-data-menu-remove").click();
|
||||
await driver.find(".test-modal-confirm").click();
|
||||
await waitForServer();
|
||||
if (goBack) {
|
||||
await driver.get(back);
|
||||
await waitAppFocus();
|
||||
}
|
||||
return back;
|
||||
}
|
||||
|
||||
@@ -1400,6 +1409,11 @@ export function openColumnMenu(col: IColHeader|string, option?: string): WebElem
|
||||
return new WebElementPromise(driver, openColumnMenuHelper(col, option));
|
||||
}
|
||||
|
||||
export async function deleteColumn(col: IColHeader|string) {
|
||||
await openColumnMenu(col, 'Delete column');
|
||||
await waitForServer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the type of the currently selected field to value.
|
||||
*/
|
||||
@@ -2554,13 +2568,30 @@ export async function changeBehavior(option: string|RegExp) {
|
||||
/**
|
||||
* Gets all available options in the behavior menu.
|
||||
*/
|
||||
export async function availableBehaviorOptions() {
|
||||
export async function availableBehaviorOptions() {
|
||||
await driver.find('.test-field-behaviour').click();
|
||||
const list = await driver.findAll('.grist-floating-menu li', el => el.getText());
|
||||
await driver.sendKeys(Key.ESCAPE);
|
||||
return list;
|
||||
}
|
||||
|
||||
export function withComments() {
|
||||
let oldEnv: testUtils.EnvironmentSnapshot;
|
||||
before(async () => {
|
||||
if (process.env.COMMENTS !== 'true') {
|
||||
oldEnv = new testUtils.EnvironmentSnapshot();
|
||||
process.env.COMMENTS = 'true';
|
||||
await server.restart();
|
||||
}
|
||||
});
|
||||
after(async () => {
|
||||
if (oldEnv) {
|
||||
oldEnv.restore();
|
||||
await server.restart();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // end of namespace gristUtils
|
||||
|
||||
stackWrapOwnMethods(gristUtils);
|
||||
|
||||
Reference in New Issue
Block a user