(core) Adding sort options for columns.

Summary:
Adding sort options for columns.
- Sort menu has a new option "More sort options" that opens up Sort left menu
- Each sort entry has an additional menu with 3 options
-- Order by choice index (for the Choice column, orders by choice position)
-- Empty last (puts empty values last in ascending order, first in descending order)
-- Natural sort (for Text column, compares strings with numbers as numbers)
Updated also CSV/Excel export and api sorting.
Most of the changes in this diff is a sort expression refactoring. Pulling out all the methods
that works on sortExpression array into a single namespace.

Test Plan: Browser tests

Reviewers: alexmojaki

Reviewed By: alexmojaki

Subscribers: dsagal, alexmojaki

Differential Revision: https://phab.getgrist.com/D3077
This commit is contained in:
Jarosław Sadziński
2021-11-03 12:44:28 +01:00
parent 0f946616b6
commit 3c72639e25
20 changed files with 992 additions and 267 deletions

View File

@@ -1,5 +1,8 @@
import {ColumnGetters} from 'app/common/ColumnGetters';
import { ColumnGetter, ColumnGetters } from 'app/common/ColumnGetters';
import * as gristTypes from 'app/common/gristTypes';
import { safeJsonParse } from 'app/common/gutil';
import { choiceGetter } from 'app/common/SortFunc';
import { Sort } from 'app/common/SortSpec';
/**
*
@@ -12,23 +15,33 @@ export class ServerColumnGetters implements ColumnGetters {
private _colIndices: Map<number, string>;
constructor(rowIds: number[], private _dataByColId: {[colId: string]: any}, private _columns: any[]) {
this._rowIndices = new Map<number, number>(rowIds.map((rowId, r) => [rowId, r] as [number, number]));
this._rowIndices = new Map<number, number>(rowIds.map((rowId, index) => [rowId, index] as [number, number]));
this._colIndices = new Map<number, string>(_columns.map(col => [col.id, col.colId] as [number, string]));
}
public getColGetter(colRef: number): ((rowId: number) => any) | null {
public getColGetter(colSpec: Sort.ColSpec): ColumnGetter | null {
const colRef = Sort.getColRef(colSpec);
const colId = this._colIndices.get(colRef);
if (colId === undefined) {
return null;
}
const col = this._dataByColId[colId];
return rowId => {
let getter = (rowId: number) => {
const idx = this._rowIndices.get(rowId);
if (idx === undefined) {
return null;
}
return col[idx];
};
const details = Sort.specToDetails(colSpec);
if (details.orderByChoice) {
const rowModel = this._columns.find(c => c.id == colRef);
if (rowModel?.type === 'Choice') {
const choices: string[] = safeJsonParse(rowModel.widgetOptions, {}).choices || [];
getter = choiceGetter(getter, choices);
}
}
return getter;
}
public getManualSortGetter(): ((rowId: number) => any) | null {