(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
This commit is contained in:
Cyprien P 2021-05-06 14:23:50 +02:00
parent 570baa95a5
commit 8056bb0069
4 changed files with 24 additions and 16 deletions

View File

@ -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);
};
/**

View File

@ -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<void>;
public onResize(): void;

View File

@ -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);
}
};
}

View File

@ -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<boolean>) {
function makeFilterPanel(section: ViewSectionRec, filteredFields: ViewFieldRec[],
popupControls: WeakMap<ViewFieldRec, PopupControl>) {
popupControls: WeakMap<ViewFieldRec, PopupControl>,
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'),
),