mirror of
https://github.com/gristlabs/grist-core.git
synced 2024-10-27 20:44:07 +00:00
(core) add +
button to the filter bar
Summary: - Adds a + button to the filter. Button triggers a menu that allow to add one of the column that does not already have a filter set. Caveats: - for now menu only allows to choose from visible column. - This diff introduces a slight change of behavior of how filter works: - Filter used to be automatically removed when user set them to all inclusive (ie: by clicking the `All` button). - With this diff, it is no longer the case. - indeed, when filter are added to the filter bar with the `+` btn they are initially in the `all inclusive` state, hence would have been removed with the above mention behaviour. Test Plan: Added new test to nbrowser/FilterBar Reviewers: paulfitz Reviewed By: paulfitz Differential Revision: https://phab.getgrist.com/D2776
This commit is contained in:
parent
8a26550312
commit
5479159960
@ -264,6 +264,7 @@ export function createFilterMenu(openCtl: IOpenController, sectionFilter: Sectio
|
|||||||
const labelGetter = tableData.getRowPropFunc(field.displayColModel().colId())!;
|
const labelGetter = tableData.getRowPropFunc(field.displayColModel().colId())!;
|
||||||
const formatter = field.createVisibleColFormatter();
|
const formatter = field.createVisibleColFormatter();
|
||||||
const valueMapFunc = (rowId: number) => formatter.formatAny(labelGetter(rowId));
|
const valueMapFunc = (rowId: number) => formatter.formatAny(labelGetter(rowId));
|
||||||
|
const activeFilterBar = field.viewSection.peek().activeFilterBar;
|
||||||
|
|
||||||
const valueCounts: Map<CellValue, {label: string, count: number}> = new Map();
|
const valueCounts: Map<CellValue, {label: string, count: number}> = new Map();
|
||||||
// TODO: as of now, this is not working for non text-or-numeric columns, ie: for Date column it is
|
// TODO: as of now, this is not working for non text-or-numeric columns, ie: for Date column it is
|
||||||
@ -282,7 +283,8 @@ export function createFilterMenu(openCtl: IOpenController, sectionFilter: Sectio
|
|||||||
onClose: () => openCtl.close(),
|
onClose: () => openCtl.close(),
|
||||||
doSave: (reset: boolean = false) => {
|
doSave: (reset: boolean = false) => {
|
||||||
const spec = columnFilter.makeFilterJson();
|
const spec = columnFilter.makeFilterJson();
|
||||||
field.activeFilter(spec === allInclusive ? '' : spec);
|
// If filter is moot and filter bar is hidden, let's remove the filter.
|
||||||
|
field.activeFilter((spec === allInclusive && !activeFilterBar.peek()) ? '' : spec);
|
||||||
if (reset) {
|
if (reset) {
|
||||||
sectionFilter.resetTemporaryRows();
|
sectionFilter.resetTemporaryRows();
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
|
import { allInclusive } from "app/client/models/ColumnFilter";
|
||||||
import { ViewFieldRec, ViewSectionRec } from "app/client/models/DocModel";
|
import { ViewFieldRec, ViewSectionRec } from "app/client/models/DocModel";
|
||||||
import { attachColumnFilterMenu } from "app/client/ui/ColumnFilterMenu";
|
import { attachColumnFilterMenu } from "app/client/ui/ColumnFilterMenu";
|
||||||
import { cssButton, cssButtonGroup } from "app/client/ui2018/buttons";
|
import { cssButton, cssButtonGroup } from "app/client/ui2018/buttons";
|
||||||
import { colors, testId } from "app/client/ui2018/cssVars";
|
import { colors, testId } from "app/client/ui2018/cssVars";
|
||||||
import { icon } from "app/client/ui2018/icons";
|
import { icon } from "app/client/ui2018/icons";
|
||||||
|
import { menu, menuItemAsync } from "app/client/ui2018/menus";
|
||||||
import { dom, IDisposableOwner, IDomArgs, styled } from "grainjs";
|
import { dom, IDisposableOwner, IDomArgs, styled } from "grainjs";
|
||||||
|
|
||||||
export function filterBar(_owner: IDisposableOwner, viewSection: ViewSectionRec) {
|
export function filterBar(_owner: IDisposableOwner, viewSection: ViewSectionRec) {
|
||||||
return cssFilterBar(
|
return cssFilterBar(
|
||||||
testId('filter-bar'),
|
testId('filter-bar'),
|
||||||
dom.forEach(viewSection.filteredFields, (field) => makeFilterField(viewSection, field)),
|
dom.forEach(viewSection.filteredFields, (field) => makeFilterField(viewSection, field)),
|
||||||
|
makePlusButton(viewSection),
|
||||||
cssSpacer(),
|
cssSpacer(),
|
||||||
dom.maybe(viewSection.filterSpecChanged, () => [
|
dom.maybe(viewSection.filterSpecChanged, () => [
|
||||||
primaryButton(
|
primaryButton(
|
||||||
@ -30,18 +33,38 @@ function makeFilterField(viewSection: ViewSectionRec, field: ViewFieldRec) {
|
|||||||
testId('btn'),
|
testId('btn'),
|
||||||
cssIcon('FilterSimple'),
|
cssIcon('FilterSimple'),
|
||||||
cssMenuTextLabel(dom.text(field.label)),
|
cssMenuTextLabel(dom.text(field.label)),
|
||||||
cssBtn.cls('-disabled', field.activeFilter.isSaved),
|
cssBtn.cls('-saved', field.activeFilter.isSaved),
|
||||||
attachColumnFilterMenu(viewSection, field, {placement: 'bottom-start', attach: 'body'}),
|
attachColumnFilterMenu(viewSection, field, {placement: 'bottom-start', attach: 'body'}),
|
||||||
),
|
),
|
||||||
deleteButton(
|
deleteButton(
|
||||||
testId('delete'),
|
testId('delete'),
|
||||||
cssIcon('CrossSmall'),
|
cssIcon('CrossSmall'),
|
||||||
cssBtn.cls('-disabled', field.activeFilter.isSaved),
|
cssBtn.cls('-saved', field.activeFilter.isSaved),
|
||||||
dom.on('click', () => field.activeFilter('')),
|
dom.on('click', () => field.activeFilter('')),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function makePlusButton(viewSectionRec: ViewSectionRec) {
|
||||||
|
return dom.domComputed((use) => {
|
||||||
|
const fields = use(use(viewSectionRec.viewFields).getObservable());
|
||||||
|
const anyFilter = fields.find((f) => use(f.isFiltered));
|
||||||
|
return cssPlusButton(
|
||||||
|
cssBtn.cls('-saved'),
|
||||||
|
cssIcon('Plus'),
|
||||||
|
menu(() => fields.map((f) => (
|
||||||
|
menuItemAsync(
|
||||||
|
() => f.activeFilter(allInclusive),
|
||||||
|
f.label.peek(),
|
||||||
|
dom.cls('disabled', f.isFiltered)
|
||||||
|
)
|
||||||
|
))),
|
||||||
|
anyFilter ? null : cssPlusLabel('Add Filter'),
|
||||||
|
testId('add-filter-btn')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const cssFilterBar = styled('div', `
|
const cssFilterBar = styled('div', `
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: row;
|
flex-direction: row;
|
||||||
@ -75,13 +98,13 @@ const cssBtn = styled('div', `
|
|||||||
.${cssFilterBar.className} > & {
|
.${cssFilterBar.className} > & {
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
}
|
}
|
||||||
&-disabled {
|
&-saved {
|
||||||
color: ${colors.light};
|
color: ${colors.light};
|
||||||
--icon-color: ${colors.light};
|
--icon-color: ${colors.light};
|
||||||
background-color: ${colors.slate};
|
background-color: ${colors.slate};
|
||||||
border-color: ${colors.slate};
|
border-color: ${colors.slate};
|
||||||
}
|
}
|
||||||
&-disabled:hover {
|
&-saved:hover {
|
||||||
background-color: ${colors.darkGrey};
|
background-color: ${colors.darkGrey};
|
||||||
border-color: ${colors.darkGrey};
|
border-color: ${colors.darkGrey};
|
||||||
}
|
}
|
||||||
@ -100,3 +123,9 @@ const cssSpacer = styled('div', `
|
|||||||
width: 8px;
|
width: 8px;
|
||||||
flex-shrink: 0;
|
flex-shrink: 0;
|
||||||
`);
|
`);
|
||||||
|
const cssPlusButton = styled(primaryButton, `
|
||||||
|
padding: 3px 3px
|
||||||
|
`);
|
||||||
|
const cssPlusLabel = styled('span', `
|
||||||
|
margin: 0 12px 0 4px;
|
||||||
|
`);
|
||||||
|
Loading…
Reference in New Issue
Block a user