From 8056bb0069c2623dcca3dde04e33e2bc75f1c780 Mon Sep 17 00:00:00 2001 From: Cyprien P Date: Thu, 6 May 2021 14:23:50 +0200 Subject: [PATCH] (core) close sort&filter menu when clicking Save/Revert buttons Summary: - close sort&filter menu when clicking Save/Revert buttons - also closes when clicking Apply/Cancel from a nested filter menu Test Plan: - updated existing test to match new spec - added new test to cover new behaviour Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2799 --- app/client/components/BaseView.js | 4 ++-- app/client/declarations.d.ts | 2 +- app/client/ui/ColumnFilterMenu.ts | 17 +++++++++++------ app/client/ui/ViewSectionMenu.ts | 17 ++++++++++------- 4 files changed, 24 insertions(+), 16 deletions(-) diff --git a/app/client/components/BaseView.js b/app/client/components/BaseView.js index afdf126f..1a5303af 100644 --- a/app/client/components/BaseView.js +++ b/app/client/components/BaseView.js @@ -650,8 +650,8 @@ BaseView.prototype.getLastDataRowIndex = function() { /** * Creates and opens ColumnFilterMenu for a given field, and returns its PopupControl. */ -BaseView.prototype.createFilterMenu = function(openCtl, field) { - return createFilterMenu(openCtl, this._sectionFilter, field, this._filteredRowSource, this.tableModel.tableData); +BaseView.prototype.createFilterMenu = function(openCtl, field, onClose) { + return createFilterMenu(openCtl, this._sectionFilter, field, this._filteredRowSource, this.tableModel.tableData, onClose); }; /** diff --git a/app/client/declarations.d.ts b/app/client/declarations.d.ts index 2c135177..c8775adf 100644 --- a/app/client/declarations.d.ts +++ b/app/client/declarations.d.ts @@ -60,7 +60,7 @@ declare module "app/client/components/BaseView" { constructor(gristDoc: GristDoc, viewSectionModel: any); public setCursorPos(cursorPos: CursorPos): void; - public createFilterMenu(ctl: IOpenController, field: ViewFieldRec): HTMLElement; + public createFilterMenu(ctl: IOpenController, field: ViewFieldRec, onClose?: () => void): HTMLElement; public buildTitleControls(): DomArg; public getLoadingDonePromise(): Promise; public onResize(): void; diff --git a/app/client/ui/ColumnFilterMenu.ts b/app/client/ui/ColumnFilterMenu.ts index 41ef7bba..7ad8564f 100644 --- a/app/client/ui/ColumnFilterMenu.ts +++ b/app/client/ui/ColumnFilterMenu.ts @@ -5,6 +5,7 @@ */ import {allInclusive, ColumnFilter, isEquivalentFilter} from 'app/client/models/ColumnFilter'; +import {ColumnFilterMenuModel, IFilterCount} from 'app/client/models/ColumnFilterMenuModel'; import {ViewFieldRec, ViewSectionRec} from 'app/client/models/DocModel'; import {FilteredRowSource} from 'app/client/models/rowset'; import {SectionFilter} from 'app/client/models/SectionFilter'; @@ -17,9 +18,8 @@ import {menuCssClass, menuDivider} from 'app/client/ui2018/menus'; import {CellValue} from 'app/common/DocActions'; import {Computed, Disposable, dom, DomElementMethod, IDisposableOwner, input, makeTestId, styled} from 'grainjs'; import identity = require('lodash/identity'); +import noop = require('lodash/noop'); import {IOpenController, IPopupOptions, setPopupToCreateDom} from 'popweasel'; -import {ColumnFilterMenuModel, IFilterCount} from '../models/ColumnFilterMenuModel'; - interface IFilterMenuOptions { model: ColumnFilterMenuModel; @@ -258,7 +258,7 @@ function buildSummary(label: string, SummaryModelCtor: SummaryModelCreator, mode * Returns content for the newly created columnFilterMenu; for use with setPopupToCreateDom(). */ export function createFilterMenu(openCtl: IOpenController, sectionFilter: SectionFilter, field: ViewFieldRec, - rowSource: FilteredRowSource, tableData: TableData) { + rowSource: FilteredRowSource, tableData: TableData, onClose: () => void = noop) { // Go through all of our shown and hidden rows, and count them up by the values in this column. const valueGetter = tableData.getRowPropFunc(field.column().colId())!; const labelGetter = tableData.getRowPropFunc(field.displayColModel().colId())!; @@ -280,7 +280,7 @@ export function createFilterMenu(openCtl: IOpenController, sectionFilter: Sectio return columnFilterMenu(openCtl, { model, valueCounts, - onClose: () => openCtl.close(), + onClose: () => { openCtl.close(); onClose(); }, doSave: (reset: boolean = false) => { const spec = columnFilter.makeFilterJson(); // If filter is moot and filter bar is hidden, let's remove the filter. @@ -321,14 +321,19 @@ const defaultPopupOptions: IPopupOptions = { trigger: ['click'], }; +interface IColumnFilterMenuOptions extends IPopupOptions { + // callback for when the content of the menu is closed by clicking the apply or revert buttons + onCloseContent?: () => void; +} + // Helper to attach the column filter menu. export function attachColumnFilterMenu(viewSection: ViewSectionRec, field: ViewFieldRec, - popupOptions: IPopupOptions): DomElementMethod { + popupOptions: IColumnFilterMenuOptions): DomElementMethod { const options = {...defaultPopupOptions, ...popupOptions}; return (elem) => { const instance = viewSection.viewInstance(); if (instance && instance.createFilterMenu) { // Should be set if using BaseView - setPopupToCreateDom(elem, ctl => instance.createFilterMenu(ctl, field), options); + setPopupToCreateDom(elem, ctl => instance.createFilterMenu(ctl, field, popupOptions.onCloseContent), options); } }; } diff --git a/app/client/ui/ViewSectionMenu.ts b/app/client/ui/ViewSectionMenu.ts index 3fcbb24a..4080274d 100644 --- a/app/client/ui/ViewSectionMenu.ts +++ b/app/client/ui/ViewSectionMenu.ts @@ -1,10 +1,11 @@ import {flipColDirection, parseSortColRefs} from 'app/client/lib/sortUtil'; +import {reportError} from 'app/client/models/AppModel'; import {ColumnRec, DocModel, ViewFieldRec, ViewRec, ViewSectionRec} from 'app/client/models/DocModel'; import {CustomComputed} from 'app/client/models/modelUtil'; import {attachColumnFilterMenu} from 'app/client/ui/ColumnFilterMenu'; import {addFilterMenu} from 'app/client/ui/FilterBar'; -import {makeViewLayoutMenu} from 'app/client/ui/ViewLayoutMenu'; import {hoverTooltip} from 'app/client/ui/tooltips'; +import {makeViewLayoutMenu} from 'app/client/ui/ViewLayoutMenu'; import {basicButton, primaryButton} from 'app/client/ui2018/buttons'; import {colors, vars} from 'app/client/ui2018/cssVars'; import {icon} from 'app/client/ui2018/icons'; @@ -43,7 +44,7 @@ export function viewSectionMenu(owner: IDisposableOwner, docModel: DocModel, vie || !use(viewSection.activeFilterBar.isSaved) )); - const save = () => doSave(docModel, viewSection); + const save = () => { doSave(docModel, viewSection).catch(reportError); }; const revert = () => doRevert(viewSection); return [ @@ -58,23 +59,23 @@ export function viewSectionMenu(owner: IDisposableOwner, docModel: DocModel, vie cssFilterIconWrapper.cls('-any', anyFilter), cssFilterIcon('Filter') ), - menu(_ctl => [ + menu(ctl => [ dom.domComputed(use => { use(viewSection.activeSortJson.isSaved); // Rebuild sort panel if sort gets saved. A little hacky. return makeSortPanel(viewSection, use(viewSection.activeSortSpec), (row: number) => docModel.columns.getRowModel(row)); }), dom.domComputed(viewSection.filteredFields, fields => - makeFilterPanel(viewSection, fields, popupControls)), + makeFilterPanel(viewSection, fields, popupControls, () => ctl.close())), makeAddFilterButton(viewSection, popupControls), makeFilterBarToggle(viewSection.activeFilterBar), dom.domComputed(displaySaveObs, displaySave => [ displaySave ? cssMenuInfoHeader( cssSaveButton('Save', testId('btn-save'), - dom.on('click', save), + dom.on('click', () => { save(); ctl.close(); }), dom.boolAttr('disabled', isReadonly)), basicButton('Revert', testId('btn-revert'), - dom.on('click', revert)) + dom.on('click', () => { revert(); ctl.close(); })) ) : null, ]), ]), @@ -180,7 +181,8 @@ export function makeFilterBarToggle(activeFilterBar: CustomComputed) { function makeFilterPanel(section: ViewSectionRec, filteredFields: ViewFieldRec[], - popupControls: WeakMap) { + popupControls: WeakMap, + onCloseContent: () => void) { const fields = filteredFields.map(field => { const fieldChanged = Computed.create(null, fromKo(field.activeFilter.isSaved), (_use, isSaved) => !isSaved); return cssMenuText( @@ -191,6 +193,7 @@ function makeFilterPanel(section: ViewSectionRec, filteredFields: ViewFieldRec[] attachColumnFilterMenu(section, field, { placement: 'bottom-end', trigger: ['click', (_el, popupControl) => popupControls.set(field, popupControl)], + onCloseContent, }), testId('filter-icon'), ),