(core) Bundling save funciton in the field editor

Summary:
Some editors do some async work before saving the value (Ref column can add new
records). Those actions were send without bundling, so it wasn't possible to undo those
actions with togheter.

Test Plan: Added new test

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D4285
pull/1091/head
Jarosław Sadziński 3 months ago
parent 7f28aee79c
commit 9c4814e7aa

@ -380,13 +380,13 @@ export class FieldEditor extends Disposable {
if (!editor) { return false; }
// Make sure the editor is save ready
const saveIndex = this._cursor.rowIndex();
return await this._gristDoc.docData.bundleActions(null, async () => {
await editor.prepForSave();
if (this.isDisposed()) {
// We shouldn't normally get disposed here, but if we do, avoid confusing JS errors.
console.warn(t("Unable to finish saving edited cell")); // tslint:disable-line:no-console
return false;
}
// Then save the value the appropriate way
// TODO: this isFormula value doesn't actually reflect if editing the formula, since
// editingFormula() is used for toggling column headers, and this is deferred to start of
@ -400,13 +400,13 @@ export class FieldEditor extends Disposable {
const formula = String(editor.getCellValue() ?? '');
// Bundle multiple changes so that we can undo them in one step.
if (isFormula !== col.isFormula.peek() || formula !== col.formula.peek()) {
waitPromise = this._gristDoc.docData.bundleActions(null, () => Promise.all([
waitPromise = Promise.all([
col.updateColValues({isFormula, formula}),
// If we're saving a non-empty formula, then also add an empty record to the table
// so that the formula calculation is visible to the user.
(!this._detached.get() && this._editRow._isAddRow.peek() && formula !== "" ?
this._editRow.updateColValues({}) : undefined),
]));
]);
}
} else {
const value = editor.getCellValue();
@ -433,6 +433,7 @@ export class FieldEditor extends Disposable {
this.dispose();
await waitPromise;
return isFormula || (saveIndex !== cursor.rowIndex());
});
}
}

@ -13,6 +13,41 @@ describe('ReferenceList', function() {
});
describe('other', function() {
it('fix: changing ref list with a new referenced row was not bundled', async function() {
// When user added a new referenced row through the RefList editor, the UI sent two separate
// actions. One for adding the new row, and another for updating the RefList column.
await session.tempNewDoc(cleanup);
await gu.sendActions([
['ModifyColumn', 'Table1', 'B', {type: 'RefList:Table1'}],
['AddRecord', 'Table1', null, {A: 'a'}],
]);
await gu.openColumnPanel();
await gu.getCell('B', 1).doClick();
await gu.setRefShowColumn('A');
await gu.getCell('B', 1).click();
await gu.sendKeys(Key.ENTER, 'b');
await gu.waitToPass(async () => {
await driver.findWait('.test-ref-editor-new-item', 100).click();
});
await gu.sendKeys(Key.ENTER);
await gu.waitForServer();
// Check the data - use waitToPass helper, as previously it might have failed
// as 2 separate actions were sent.
await gu.waitToPass(async () => {
assert.deepEqual(await gu.getVisibleGridCells('A', [1, 2]), ['a', 'b']);
assert.deepEqual(await gu.getVisibleGridCells('B', [1, 2]), ['b', '']);
assert.equal(await gu.getGridRowCount(), 3);
});
// Now press undo once, and check that the new row is removed and the RefList is updated.
await gu.undo();
assert.deepEqual(await gu.getVisibleGridCells('A', [1]), ['a']);
assert.deepEqual(await gu.getVisibleGridCells('B', [1]), ['']);
assert.equal(await gu.getGridRowCount(), 2);
});
it('fix: doesnt break when table is renamed', async function() {
// There was a bug in this scenario:
// 1. Create a Ref column that targets itself

Loading…
Cancel
Save