diff --git a/app/client/components/BaseView.js b/app/client/components/BaseView.js index 61f4c75d..8e328308 100644 --- a/app/client/components/BaseView.js +++ b/app/client/components/BaseView.js @@ -229,6 +229,8 @@ BaseView.commonCommands = { insertCurrentDateTime: function() { this.insertCurrentDate(true); }, 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 at the end. diff --git a/app/client/components/commandList.js b/app/client/components/commandList.js index a1483608..ca5bb1d6 100644 --- a/app/client/components/commandList.js +++ b/app/client/components/commandList.js @@ -384,6 +384,15 @@ exports.groups = [{ }, ], +}, { + group: 'Filtering', + commands: [ + { + name: 'filterByThisCellValue', + keys: [], + desc: `Filter this column by just this cell's value`, + }, + ] }, { group: 'Linking', commands: [ diff --git a/app/client/ui/CellContextMenu.ts b/app/client/ui/CellContextMenu.ts index 63359777..b4f1d7ef 100644 --- a/app/client/ui/CellContextMenu.ts +++ b/app/client/ui/CellContextMenu.ts @@ -43,7 +43,9 @@ export function CellContextMenu(rowOptions: IRowContextMenu, colOptions: IMultiC ...( (numCols > 1 || numRows > 1) ? [] : [ menuDivider(), - menuItemCmd(allCommands.copyLink, 'Copy anchor link') + menuItemCmd(allCommands.copyLink, 'Copy anchor link'), + menuDivider(), + menuItemCmd(allCommands.filterByThisCellValue, `Filter by this value`), ] ), diff --git a/app/client/ui/ColumnFilterMenu.ts b/app/client/ui/ColumnFilterMenu.ts index bb2bdae2..4ca761d5 100644 --- a/app/client/ui/ColumnFilterMenu.ts +++ b/app/client/ui/ColumnFilterMenu.ts @@ -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 possible choices as keys). + * Note that this logic is replicated in BaseView.prototype.filterByThisCellValue. */ function addCountsToMap(valueMap: Map, rowIds: RowId[], { keyMapFunc = identity, labelMapFunc = identity, columnType,