gristlabs_grist-core/app/client/models/ClientColumnGetters.ts
Alex Hall bc54a6646e (core) Filter rows based on linked widgets when exporting view
Summary:
Fixes a problem reported here: https://community.getgrist.com/t/exporting-the-records-in-a-linked-view/2556/4

The download CSV/Excel link now contains an additional `linkingFilter` URL parameter containing JSON-encoded `filters` and `operations`. This object is originally created in the frontend in `LinkingState`, and previously it was only used internally in the frontend. It would make its way via `QuerySetManager` to `QuerySet.getFilterFunc` where the actual filtering logic happened. Now most of that logic has been moved to a similar function in `common`. The new function works with a new interface `ColumnGettersByColId` which abstract over the different ways data is accessed in the client and server in this context. There's no significant new logic in the diff, just refactoring and wiring.

Test Plan: Expanded two `nbrowser/SelectBy*.ts` test suites to also check the contents of a downloaded CSV in different linking scenarios.

Reviewers: paulfitz

Reviewed By: paulfitz

Differential Revision: https://phab.getgrist.com/D3961
2023-07-26 21:49:52 +02:00

70 lines
2.5 KiB
TypeScript

import DataTableModel from 'app/client/models/DataTableModel';
import {ColumnGetter, ColumnGetters, ColumnGettersByColId} from 'app/common/ColumnGetters';
import * as gristTypes from 'app/common/gristTypes';
import {choiceGetter} from 'app/common/SortFunc';
import {Sort} from 'app/common/SortSpec';
import {TableData} from 'app/common/TableData';
/**
*
* An implementation of ColumnGetters for the client, drawing
* on the observables and models available in that context.
*
*/
export class ClientColumnGetters implements ColumnGetters {
// If the "unversioned" option is set, then cells with multiple
// versions will be read as a single version - the first version
// available of parent, local, or remote. This can make sense for
// sorting, so cells appear in a reasonably sensible place.
constructor(private _tableModel: DataTableModel, private _options: {
unversioned?: boolean} = {}) {
}
public getColGetter(colSpec: Sort.ColSpec): ColumnGetter | null {
const rowModel = this._tableModel.docModel.columns.getRowModel(Sort.getColRef(colSpec));
const colId = rowModel.colId();
let getter: ColumnGetter|undefined = this._tableModel.tableData.getRowPropFunc(colId);
if (!getter) { return null; }
if (this._options.unversioned && this._tableModel.tableData.mayHaveVersions()) {
const valueGetter = getter;
getter = (rowId) => {
const value = valueGetter(rowId);
if (value && gristTypes.isVersions(value)) {
const versions = value[1];
return ('parent' in versions) ? versions.parent :
('local' in versions) ? versions.local : versions.remote;
}
return value;
};
}
const details = Sort.specToDetails(colSpec);
if (details.orderByChoice) {
if (rowModel.pureType() === 'Choice') {
const choices: string[] = rowModel.widgetOptionsJson.peek()?.choices || [];
getter = choiceGetter(getter, choices);
}
}
return getter;
}
public getManualSortGetter(): ((rowId: number) => any) | null {
const manualSortCol = this._tableModel.tableMetaRow.columns().peek().find(
(c: any) => c.colId() === gristTypes.MANUALSORT);
if (!manualSortCol) {
return null;
}
return this.getColGetter(manualSortCol.getRowId());
}
}
export class ClientColumnGettersByColId implements ColumnGettersByColId {
constructor(private _tableData: TableData) {
}
public getColGetterByColId(colId: string): ColumnGetter {
return this._tableData.getRowPropFunc(colId);
}
}