(core) Allow filtering by selected cell value in cell context menu

Summary: Adds a command and `BaseView` method `filterByThisCellValue`.

Test Plan: Added two tests to `nbrowser/CellContextMenu.ts`

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D3383
This commit is contained in:
Alex Hall 2022-04-18 16:40:29 +02:00
parent ce7eb05ed4
commit 47b77c8c24
4 changed files with 35 additions and 1 deletions

View File

@ -229,6 +229,8 @@ BaseView.commonCommands = {
insertCurrentDateTime: function() { this.insertCurrentDate(true); }, insertCurrentDateTime: function() { this.insertCurrentDate(true); },
copyLink: function() { this.copyLink().catch(reportError); }, copyLink: function() { this.copyLink().catch(reportError); },
filterByThisCellValue: function() { this.filterByThisCellValue(); },
}; };
/** /**
@ -305,6 +307,26 @@ BaseView.prototype.copyLink = async function() {
} }
}; };
BaseView.prototype.filterByThisCellValue = function() {
const rowId = this.viewData.getRowId(this.cursor.rowIndex());
const col = this.viewSection.viewFields().peek()[this.cursor.fieldIndex()].column();
let value = this.tableModel.tableData.getValue(rowId, col.colId.peek());
// This mimics the logic in ColumnFilterMenu.addCountsToMap
// ChoiceList and Reflist values get 'flattened' out so we filter by each element within.
// In any other column type, complex values (even lists) get converted to JSON.
let filterValues;
if (gristTypes.isList(value) && gristTypes.isListType(col.type.peek())) {
filterValues = value.slice(1);
} else {
if (Array.isArray(value)) {
value = JSON.stringify(value);
}
filterValues = [value];
}
this.viewSection.setFilter(col.getRowId(), JSON.stringify({included: filterValues}));
};
/** /**
* Insert a new row immediately before the row at the given index if given an Integer. Otherwise * Insert a new row immediately before the row at the given index if given an Integer. Otherwise
* insert a new row at the end. * insert a new row at the end.

View File

@ -384,6 +384,15 @@ exports.groups = [{
}, },
], ],
}, {
group: 'Filtering',
commands: [
{
name: 'filterByThisCellValue',
keys: [],
desc: `Filter this column by just this cell's value`,
},
]
}, { }, {
group: 'Linking', group: 'Linking',
commands: [ commands: [

View File

@ -43,7 +43,9 @@ export function CellContextMenu(rowOptions: IRowContextMenu, colOptions: IMultiC
...( ...(
(numCols > 1 || numRows > 1) ? [] : [ (numCols > 1 || numRows > 1) ? [] : [
menuDivider(), menuDivider(),
menuItemCmd(allCommands.copyLink, 'Copy anchor link') menuItemCmd(allCommands.copyLink, 'Copy anchor link'),
menuDivider(),
menuItemCmd(allCommands.filterByThisCellValue, `Filter by this value`),
] ]
), ),

View File

@ -407,6 +407,7 @@ interface ICountOptions {
* *
* The optional column type controls how complex cell values are decomposed into keys (e.g. Choice Lists have * The optional column type controls how complex cell values are decomposed into keys (e.g. Choice Lists have
* the possible choices as keys). * the possible choices as keys).
* Note that this logic is replicated in BaseView.prototype.filterByThisCellValue.
*/ */
function addCountsToMap(valueMap: Map<CellValue, IFilterCount>, rowIds: RowId[], function addCountsToMap(valueMap: Map<CellValue, IFilterCount>, rowIds: RowId[],
{ keyMapFunc = identity, labelMapFunc = identity, columnType, { keyMapFunc = identity, labelMapFunc = identity, columnType,