(core) Fixing cursor position for filtered linked section.

Summary:
In a selector table, when a selected row is filtered out of view, linked widgets should update based on the newly selected row.
There were a few bugs that contributed to this wrong behavior:
- Gridview wasn't subscribing to the current row id, and the row with id 'new' was being converted to the first row
- Cursor was keeping track of the currently selected row id, it was hiding a problem behind the proper rowIndex
- Undo/redo somehow leveraged the wrong rowId from the cursor during the position restore.

The `No data` text was also changed to be more meaningful.

Test Plan: Added and updated.

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D3937
This commit is contained in:
Jarosław Sadziński
2023-07-07 10:54:01 +02:00
parent 9a80f4bdf5
commit 75d979abdb
25 changed files with 418 additions and 138 deletions

View File

@@ -28,7 +28,7 @@
*/
import DataTableModel from 'app/client/models/DataTableModel';
import {DocModel} from 'app/client/models/DocModel';
import {BaseFilteredRowSource, RowId, RowList, RowSource} from 'app/client/models/rowset';
import {BaseFilteredRowSource, RowList, RowSource} from 'app/client/models/rowset';
import {TableData} from 'app/client/models/TableData';
import {ActiveDocAPI, ClientQuery, QueryOperation} from 'app/common/ActiveDocAPI';
import {CellValue, TableDataAction} from 'app/common/DocActions';
@@ -37,7 +37,7 @@ import {isList} from "app/common/gristTypes";
import {nativeCompare} from 'app/common/gutil';
import {IRefCountSub, RefCountMap} from 'app/common/RefCountMap';
import {RowFilterFunc} from 'app/common/RowFilterFunc';
import {TableData as BaseTableData} from 'app/common/TableData';
import {TableData as BaseTableData, UIRowId} from 'app/common/TableData';
import {tbind} from 'app/common/tbind';
import {decodeObject} from "app/plugin/objtypes";
import {Disposable, Holder, IDisposableOwnerT} from 'grainjs';
@@ -303,7 +303,7 @@ export class TableQuerySets {
/**
* Returns a filtering function which tells whether a row matches the given query.
*/
export function getFilterFunc(docData: DocData, query: ClientQuery): RowFilterFunc<RowId> {
export function getFilterFunc(docData: DocData, query: ClientQuery): RowFilterFunc<UIRowId> {
// NOTE we rely without checking on tableId and colIds being valid.
const tableData: BaseTableData = docData.getTable(query.tableId)!;
const colFuncs = Object.keys(query.filters).sort().map(
@@ -312,22 +312,22 @@ export function getFilterFunc(docData: DocData, query: ClientQuery): RowFilterFu
const values = new Set(query.filters[colId]);
switch (query.operations[colId]) {
case "intersects":
return (rowId: RowId) => {
return (rowId: UIRowId) => {
const value = getter(rowId) as CellValue;
return isList(value) &&
(decodeObject(value) as unknown[]).some(v => values.has(v));
};
case "empty":
return (rowId: RowId) => {
return (rowId: UIRowId) => {
const value = getter(rowId);
// `isList(value) && value.length === 1` means `value == ['L']` i.e. an empty list
return !value || isList(value) && value.length === 1;
};
case "in":
return (rowId: RowId) => values.has(getter(rowId));
return (rowId: UIRowId) => values.has(getter(rowId));
}
});
return (rowId: RowId) => colFuncs.every(f => f(rowId));
return (rowId: UIRowId) => colFuncs.every(f => f(rowId));
}
/**