(core) Changing shortcuts for adding and removing rows

Summary:
New shortcuts for removing and adding rows.
For adding a row we now have Mod+(Shift)+Enter
For removing rows we now have Mod+Delete/Mod+Backspace

Before removing rows, the user is prompted to confirm, this prompt
can be dismissed and this setting can be remembered. User needs
to confirm only when using shortcut.

Old shortcuts are still active and shows information about this change.
This information is shown only once, after this shortcuts have default
behavior (zooming).
New users don't see this explanation.

Test Plan: Updated

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D3655
This commit is contained in:
Jarosław Sadziński
2022-10-21 12:55:01 +02:00
parent 0a8ce2178a
commit 6460c22a89
21 changed files with 582 additions and 105 deletions

View File

@@ -5,7 +5,6 @@ import {server, setupTestSuite} from 'test/nbrowser/testUtils';
describe('ReferenceColumns', function() {
this.timeout(20000);
setupTestSuite();
let session: Session;
const cleanup = setupTestSuite({team: true});
@@ -543,7 +542,8 @@ describe('ReferenceColumns', function() {
// Delete a row.
await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
await driver.find('body').sendKeys(Key.chord(await gu.modKey(), '-'));
await driver.find('body').sendKeys(Key.chord(await gu.modKey(), Key.DELETE));
await gu.confirm(true, true);
await gu.waitForServer();
// See that the value is gone from the autocomplete.
@@ -554,7 +554,7 @@ describe('ReferenceColumns', function() {
// Add a row.
await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
await driver.find('body').sendKeys(Key.chord(await gu.modKey(), '='));
await driver.find('body').sendKeys(Key.chord(await gu.modKey(), Key.ENTER));
await gu.waitForServer();
await driver.sendKeys('HELIOTROPE', Key.ENTER);
await gu.waitForServer();

View File

@@ -154,8 +154,7 @@ describe('ReferenceList', function() {
// Now delete the row containing Avatar.
await gu.getCell('Title', 4, 'Films record').doClick();
await gu.sendKeys(Key.chord(await gu.modKey(), '-'));
await gu.waitForServer();
await gu.removeRow(4);
// Check that all references to Avatar are deleted.
assert.deepEqual(
@@ -840,8 +839,7 @@ describe('ReferenceList', function() {
// Delete a row.
await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
await driver.find('body').sendKeys(Key.chord(await gu.modKey(), '-'));
await gu.waitForServer();
await gu.removeRow(1);
// See that the value is gone from the autocomplete.
await cell.click();
@@ -851,7 +849,7 @@ describe('ReferenceList', function() {
// Add a row.
await gu.getCell({section: 'Colors', col: 'Color Name', rowNum: 1}).doClick();
await driver.find('body').sendKeys(Key.chord(await gu.modKey(), '='));
await driver.find('body').sendKeys(Key.chord(await gu.modKey(), Key.ENTER));
await gu.waitForServer();
await driver.sendKeys('HELIOTROPE', Key.ENTER);
await gu.waitForServer();

View File

@@ -411,6 +411,30 @@ export async function getGridRowCount(): Promise<number> {
return parseInt(rowNum, 10);
}
/**
* Returns the total row count in the card list that is the active section by scrolling to the bottom
* and examining the last row number. The count includes the special "Add Row".
*/
export async function getCardListCount(): Promise<number> {
await sendKeys(Key.chord(await modKey(), Key.DOWN));
const rowNum = await driver.find('.active.detailview_record_detail .detail_row_num').getText();
return parseInt(rowNum, 10);
}
/**
* Returns the total row count in the card widget that is the active section by looking
* at the displayed count in the section header. The count includes the special "Add Row".
*/
export async function getCardCount(): Promise<number> {
const section = await driver.findWait('.active_section', 4000);
const counter = await section.findAll(".grist-single-record__menu__count");
if (counter.length) {
const cardRow = (await counter[0].getText()).split(' OF ')[1];
return parseInt(cardRow) + 1;
}
return 1;
}
/**
* Return the .column-name element for the specified column, which may be specified by full name
* or index, and may include a section (or will use the active section by default).
@@ -856,6 +880,22 @@ export async function sendActions(actions: UserAction[]) {
await waitForServer();
}
/**
* Confirms dialog for removing rows. In the future, can be used for other dialogs.
*/
export async function confirm(save = true, remember = false) {
if (await driver.find(".test-confirm-save").isPresent()) {
if (remember) {
await driver.find(".test-confirm-remember").click();
}
if (save) {
await driver.find(".test-confirm-save").click();
} else {
await driver.find(".test-confirm-cancel").click();
}
}
}
/**
* Returns the left-panel item for the given page, given by a full string name, or a RegExp.
* You may simply click it to switch to that page.
@@ -2472,6 +2512,15 @@ export async function scrollActiveView(x: number, y: number) {
await driver.sleep(10); // wait a bit for the scroll to happen (this is async operation in Grist).
}
export async function scrollActiveViewTop() {
await driver.executeScript(function() {
const view = document.querySelector(".active_section .grid_view_data") ||
document.querySelector(".active_section .detailview_scroll_pane");
view!.scrollTop = 0;
});
await driver.sleep(10); // wait a bit for the scroll to happen (this is async operation in Grist).
}
/**
* Filters a column in a Grid using the filter menu.
*/

View File

@@ -88,7 +88,18 @@ export function setupTestSuite(options?: TestSuiteOptions) {
// Also, log out, to avoid logins interacting, unless NO_CLEANUP is requested (useful for
// debugging tests).
if (!process.env.NO_CLEANUP) {
after(() => server.removeLogin());
after(async () => {
try {
await server.removeLogin();
} catch(err) {
// If there are any alerts open, close them as it might be blocking other tests.
if (err.name && err.name === 'UnexpectedAlertOpenError') {
await driver.switchTo().alert().accept();
assert.fail("Unexpected alert open");
}
throw err;
}
});
}
// If requested, clear user preferences for all test users after this suite.