import { GristDoc } from 'app/client/components/GristDoc'; import { ClientColumnGetters } from 'app/client/models/ClientColumnGetters'; import { ViewSectionRec } from 'app/client/models/entities/ViewSectionRec'; import * as rowset from 'app/client/models/rowset'; import { MANUALSORT } from 'app/common/gristTypes'; import { SortFunc } from 'app/common/SortFunc'; import { Sort } from 'app/common/SortSpec'; import * as ko from 'knockout'; import range = require('lodash/range'); /** * Adds a column to the given sort spec, replacing its previous occurrence if * it's already in the sort spec. */ export function addToSort(sortSpecObs: ko.Observable, colRef: number, direction: -1|1) { const spec = sortSpecObs.peek(); const index = Sort.findColIndex(spec, colRef); if (index !== -1) { spec.splice(index, 1, colRef * direction); } else { spec.push(colRef * direction); } sortSpecObs(spec); } export function sortBy(sortSpecObs: ko.Observable, colRef: number, direction: -1|1) { let spec = sortSpecObs.peek(); const colSpec = Sort.findCol(spec, colRef) ?? colRef; spec = [Sort.setColDirection(colSpec, direction)]; sortSpecObs(spec); } // Updates the manual sort positions to the positions currently displayed in the view, sets the // view's default sort spec to be manual sort and broadcasts these changes. // This is excel/google sheets' sort behavior. export async function updatePositions(gristDoc: GristDoc, section: ViewSectionRec): Promise { const tableId = section.table.peek().tableId.peek(); const tableModel = gristDoc.getTableModel(tableId); // Build a sorted array of rowIds the way a view would, using the active sort spec. We just need // the sorted list, and can dispose the observable array immediately. const sortFunc = new SortFunc(new ClientColumnGetters(tableModel, { unversioned: true })); sortFunc.updateSpec(section.activeDisplaySortSpec.peek()); const sortedRows = rowset.SortedRowSet.create( null, (a: rowset.RowId, b: rowset.RowId) => sortFunc.compare(a as number, b as number), tableModel.tableData ); sortedRows.subscribeTo(tableModel); const sortedRowIds = sortedRows.getKoArray().peek().slice(0); sortedRows.dispose(); // The action just assigns consecutive positions to the sorted rows. const colInfo = {[MANUALSORT]: range(0, sortedRowIds.length)}; await gristDoc.docData.sendActions( [ // Update row positions and clear the saved sort spec as a single action bundle. ['BulkUpdateRecord', tableId, sortedRowIds, colInfo], ['UpdateRecord', '_grist_Views_section', section.getRowId(), {sortColRefs: '[]'}], ], `Updated table ${tableId} row positions.` ); // Finally clear out the local sort spec. section.activeSortJson.revert(); }