@xh/hoist 71.0.0-SNAPSHOT.1735247152243 → 71.0.0-SNAPSHOT.1735310060928
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/types/desktop/cmp/grid/impl/filter/ColumnHeaderFilterModel.d.ts +6 -31
- package/build/types/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilter.d.ts +7 -0
- package/build/types/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilterModel.d.ts +32 -0
- package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomRowModel.d.ts +3 -3
- package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTabModel.d.ts +4 -4
- package/build/types/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTabModel.d.ts +3 -3
- package/cmp/grid/impl/ColumnHeader.ts +1 -4
- package/desktop/cmp/grid/impl/filter/ColumnHeaderFilter.ts +6 -75
- package/desktop/cmp/grid/impl/filter/ColumnHeaderFilterModel.ts +12 -160
- package/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilter.ts +88 -0
- package/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilterModel.ts +181 -0
- package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomRowModel.ts +2 -2
- package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTabModel.ts +3 -3
- package/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTabModel.ts +7 -6
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- /package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomRow.d.ts +0 -0
- /package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTab.d.ts +0 -0
- /package/build/types/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTab.d.ts +0 -0
- /package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomRow.ts +0 -0
- /package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTab.scss +0 -0
- /package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTab.ts +0 -0
- /package/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTab.scss +0 -0
- /package/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTab.ts +0 -0
|
@@ -1,38 +1,13 @@
|
|
|
1
1
|
import { Column } from '@xh/hoist/cmp/grid';
|
|
2
|
-
import { TabContainerModel } from '@xh/hoist/cmp/tab';
|
|
3
2
|
import { HoistModel } from '@xh/hoist/core';
|
|
4
|
-
import { GridFilterModel
|
|
5
|
-
import { CustomTabModel } from './custom/CustomTabModel';
|
|
6
|
-
import { ValuesTabModel } from './values/ValuesTabModel';
|
|
3
|
+
import { GridFilterModel } from '@xh/hoist/cmp/grid';
|
|
7
4
|
export declare class ColumnHeaderFilterModel extends HoistModel {
|
|
8
5
|
xhImpl: boolean;
|
|
9
|
-
column: Column;
|
|
10
|
-
|
|
11
|
-
fieldSpec: GridFilterFieldSpec;
|
|
6
|
+
readonly column: Column;
|
|
7
|
+
readonly filterModel: GridFilterModel;
|
|
12
8
|
isOpen: boolean;
|
|
13
|
-
tabContainerModel: TabContainerModel;
|
|
14
|
-
valuesTabModel: ValuesTabModel;
|
|
15
|
-
customTabModel: CustomTabModel;
|
|
16
|
-
get field(): string;
|
|
17
|
-
get store(): import("../../../../../data").Store;
|
|
18
|
-
get fieldType(): import("../../../../../data").FieldType;
|
|
19
|
-
get currentGridFilter(): import("../../../../../data").Filter;
|
|
20
|
-
get columnFilters(): import("../../../../../data").FieldFilter[];
|
|
21
|
-
get columnCompoundFilter(): import("../../../../../data").CompoundFilter;
|
|
22
9
|
get hasFilter(): boolean;
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
constructor({ filterModel, column }: {
|
|
27
|
-
filterModel: any;
|
|
28
|
-
column: any;
|
|
29
|
-
});
|
|
30
|
-
commit(close?: boolean): void;
|
|
31
|
-
clear(close?: boolean): void;
|
|
32
|
-
openMenu(): void;
|
|
33
|
-
closeMenu(): void;
|
|
34
|
-
private syncWithFilter;
|
|
35
|
-
private setColumnFilters;
|
|
36
|
-
private doCommitOnChange;
|
|
37
|
-
private resetTabModels;
|
|
10
|
+
constructor(filterModel: GridFilterModel, column: Column);
|
|
11
|
+
open(): void;
|
|
12
|
+
close(): void;
|
|
38
13
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { HeaderFilterModel } from './HeaderFilterModel';
|
|
2
|
+
/**
|
|
3
|
+
* Pop-up panel to display column specific filters
|
|
4
|
+
*
|
|
5
|
+
* @internal
|
|
6
|
+
*/
|
|
7
|
+
export declare const headerFilter: import("@xh/hoist/core").ElementFactory<import("@xh/hoist/core").DefaultHoistProps<HeaderFilterModel>>;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { TabContainerModel } from '@xh/hoist/cmp/tab';
|
|
2
|
+
import { HoistModel } from '@xh/hoist/core';
|
|
3
|
+
import { GridFilterFieldSpec } from '@xh/hoist/cmp/grid';
|
|
4
|
+
import { CustomTabModel } from './custom/CustomTabModel';
|
|
5
|
+
import { ValuesTabModel } from './values/ValuesTabModel';
|
|
6
|
+
import { ColumnHeaderFilterModel } from '../ColumnHeaderFilterModel';
|
|
7
|
+
export declare class HeaderFilterModel extends HoistModel {
|
|
8
|
+
xhImpl: boolean;
|
|
9
|
+
fieldSpec: GridFilterFieldSpec;
|
|
10
|
+
parent: ColumnHeaderFilterModel;
|
|
11
|
+
tabContainerModel: TabContainerModel;
|
|
12
|
+
valuesTabModel: ValuesTabModel;
|
|
13
|
+
customTabModel: CustomTabModel;
|
|
14
|
+
get filterModel(): import("@xh/hoist/cmp/grid").GridFilterModel;
|
|
15
|
+
get field(): string;
|
|
16
|
+
get store(): import("../../../../../../data").Store;
|
|
17
|
+
get fieldType(): import("../../../../../../data").FieldType;
|
|
18
|
+
get currentGridFilter(): import("../../../../../../data").Filter;
|
|
19
|
+
get columnFilters(): import("../../../../../../data").FieldFilter[];
|
|
20
|
+
get columnCompoundFilter(): import("../../../../../../data").CompoundFilter;
|
|
21
|
+
get hasFilter(): boolean;
|
|
22
|
+
get hasPendingFilter(): boolean;
|
|
23
|
+
get isCustomFilter(): boolean;
|
|
24
|
+
get commitOnChange(): boolean;
|
|
25
|
+
onLinked(): void;
|
|
26
|
+
commit(close?: boolean): void;
|
|
27
|
+
clear(close?: boolean): void;
|
|
28
|
+
private syncWithFilter;
|
|
29
|
+
private setColumnFilters;
|
|
30
|
+
private doCommitOnChange;
|
|
31
|
+
private resetTabModels;
|
|
32
|
+
}
|
package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomRowModel.d.ts
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { HoistModel } from '@xh/hoist/core';
|
|
2
2
|
import { FieldFilterOperator, FieldFilterSpec } from '@xh/hoist/data';
|
|
3
|
-
import {
|
|
3
|
+
import { HeaderFilterModel } from '../HeaderFilterModel';
|
|
4
4
|
import { CustomTabModel } from './CustomTabModel';
|
|
5
5
|
type OperatorOptionValue = 'blank' | 'not blank' | FieldFilterOperator;
|
|
6
6
|
/**
|
|
@@ -9,12 +9,12 @@ type OperatorOptionValue = 'blank' | 'not blank' | FieldFilterOperator;
|
|
|
9
9
|
export declare class CustomRowModel extends HoistModel {
|
|
10
10
|
xhImpl: boolean;
|
|
11
11
|
parentModel: CustomTabModel;
|
|
12
|
-
headerFilterModel:
|
|
12
|
+
headerFilterModel: HeaderFilterModel;
|
|
13
13
|
op: OperatorOptionValue;
|
|
14
14
|
inputVal: any;
|
|
15
15
|
/** FieldFilter config output of this row. */
|
|
16
16
|
get value(): FieldFilterSpec;
|
|
17
|
-
get fieldSpec(): import("
|
|
17
|
+
get fieldSpec(): import("../../../../../../../cmp/grid").GridFilterFieldSpec;
|
|
18
18
|
get options(): {
|
|
19
19
|
label: string;
|
|
20
20
|
value: OperatorOptionValue;
|
package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTabModel.d.ts
RENAMED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { HoistModel } from '@xh/hoist/core';
|
|
2
2
|
import { CompoundFilterOperator, FilterLike } from '@xh/hoist/data';
|
|
3
|
-
import {
|
|
3
|
+
import { HeaderFilterModel } from '../HeaderFilterModel';
|
|
4
4
|
import { CustomRowModel } from './CustomRowModel';
|
|
5
5
|
export declare class CustomTabModel extends HoistModel {
|
|
6
6
|
xhImpl: boolean;
|
|
7
|
-
headerFilterModel:
|
|
7
|
+
headerFilterModel: HeaderFilterModel;
|
|
8
8
|
op: CompoundFilterOperator;
|
|
9
9
|
rowModels: CustomRowModel[];
|
|
10
10
|
/** Filter config output by this model. */
|
|
11
11
|
get filter(): FilterLike;
|
|
12
|
-
get fieldSpec(): import("
|
|
12
|
+
get fieldSpec(): import("../../../../../../../cmp/grid").GridFilterFieldSpec;
|
|
13
13
|
get currentGridFilter(): import("@xh/hoist/data").Filter;
|
|
14
14
|
get columnFilters(): import("@xh/hoist/data").FieldFilter[];
|
|
15
|
-
constructor(headerFilterModel:
|
|
15
|
+
constructor(headerFilterModel: HeaderFilterModel);
|
|
16
16
|
syncWithFilter(): void;
|
|
17
17
|
reset(): void;
|
|
18
18
|
addEmptyRow(): void;
|
package/build/types/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTabModel.d.ts
RENAMED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { GridFilterModel, GridModel } from '@xh/hoist/cmp/grid';
|
|
2
2
|
import { HoistModel } from '@xh/hoist/core';
|
|
3
3
|
import { FieldFilterSpec } from '@xh/hoist/data';
|
|
4
|
-
import {
|
|
4
|
+
import { HeaderFilterModel } from '../HeaderFilterModel';
|
|
5
5
|
export declare class ValuesTabModel extends HoistModel {
|
|
6
6
|
xhImpl: boolean;
|
|
7
|
-
headerFilterModel:
|
|
7
|
+
headerFilterModel: HeaderFilterModel;
|
|
8
8
|
/** Checkbox grid to display enumerated set of values */
|
|
9
9
|
gridModel: GridModel;
|
|
10
10
|
/** List of currently checked values in the list*/
|
|
@@ -21,7 +21,7 @@ export declare class ValuesTabModel extends HoistModel {
|
|
|
21
21
|
get values(): any[];
|
|
22
22
|
get valueCount(): number;
|
|
23
23
|
get hasHiddenValues(): boolean;
|
|
24
|
-
constructor(headerFilterModel:
|
|
24
|
+
constructor(headerFilterModel: HeaderFilterModel);
|
|
25
25
|
syncWithFilter(): void;
|
|
26
26
|
reset(): void;
|
|
27
27
|
setRecsChecked(isChecked: boolean, values: any[]): void;
|
|
@@ -199,10 +199,7 @@ class ColumnHeaderModel extends HoistModel {
|
|
|
199
199
|
this.availableSorts = this.parseAvailableSorts();
|
|
200
200
|
|
|
201
201
|
if (!XH.isMobileApp && xhColumn?.filterable && filterModel?.getFieldSpec(xhColumn.field)) {
|
|
202
|
-
this.columnHeaderFilterModel = new ColumnHeaderFilterModel(
|
|
203
|
-
filterModel,
|
|
204
|
-
column: xhColumn
|
|
205
|
-
});
|
|
202
|
+
this.columnHeaderFilterModel = new ColumnHeaderFilterModel(filterModel, xhColumn);
|
|
206
203
|
this.enableFilter = true;
|
|
207
204
|
} else {
|
|
208
205
|
this.isAgFiltered = agColumn.isFilterActive();
|
|
@@ -5,18 +5,14 @@
|
|
|
5
5
|
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {div,
|
|
9
|
-
import {tabContainer} from '@xh/hoist/cmp/tab';
|
|
8
|
+
import {div, span} from '@xh/hoist/cmp/layout';
|
|
10
9
|
import {hoistCmp, uses} from '@xh/hoist/core';
|
|
11
|
-
import {button, buttonGroup} from '@xh/hoist/desktop/cmp/button';
|
|
12
|
-
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
13
|
-
import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
|
|
14
10
|
import {Icon} from '@xh/hoist/icon';
|
|
15
11
|
import {popover} from '@xh/hoist/kit/blueprint';
|
|
16
|
-
import {stopPropagation} from '@xh/hoist/utils/js';
|
|
17
12
|
import './ColumnHeaderFilter.scss';
|
|
18
13
|
import classNames from 'classnames';
|
|
19
14
|
import {ColumnHeaderFilterModel} from './ColumnHeaderFilterModel';
|
|
15
|
+
import {headerFilter} from './headerfilter/HeaderFilter';
|
|
20
16
|
|
|
21
17
|
/**
|
|
22
18
|
* Component to manage column filters from header. Will appear as a "filter" icon if filters are
|
|
@@ -41,83 +37,18 @@ export const columnHeaderFilter = hoistCmp.factory({
|
|
|
41
37
|
hasBackdrop: true,
|
|
42
38
|
interactionKind: 'click',
|
|
43
39
|
onInteraction: open => {
|
|
44
|
-
if (!open) model.
|
|
40
|
+
if (!open) model.close();
|
|
45
41
|
},
|
|
46
42
|
item: div({
|
|
47
43
|
item: hasFilter ? Icon.filter() : Icon.columnMenu(),
|
|
48
44
|
onClick: e => {
|
|
49
45
|
e.stopPropagation();
|
|
50
|
-
model.
|
|
46
|
+
model.open();
|
|
51
47
|
}
|
|
52
48
|
}),
|
|
53
49
|
targetTagName: 'div',
|
|
54
|
-
|
|
50
|
+
// Force unmount on close
|
|
51
|
+
content: isOpen ? headerFilter() : span()
|
|
55
52
|
});
|
|
56
53
|
}
|
|
57
54
|
});
|
|
58
|
-
|
|
59
|
-
const content = hoistCmp.factory({
|
|
60
|
-
render() {
|
|
61
|
-
return panel({
|
|
62
|
-
title: `Filter`,
|
|
63
|
-
className: 'xh-column-header-filter',
|
|
64
|
-
compactHeader: true,
|
|
65
|
-
onClick: stopPropagation,
|
|
66
|
-
onDoubleClick: stopPropagation,
|
|
67
|
-
headerItems: [switcher()],
|
|
68
|
-
item: tabContainer(),
|
|
69
|
-
bbar: bbar()
|
|
70
|
-
});
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
const bbar = hoistCmp.factory<ColumnHeaderFilterModel>({
|
|
75
|
-
render({model}) {
|
|
76
|
-
const {commitOnChange} = model;
|
|
77
|
-
return toolbar({
|
|
78
|
-
compact: true,
|
|
79
|
-
items: [
|
|
80
|
-
filler(),
|
|
81
|
-
button({
|
|
82
|
-
icon: Icon.delete(),
|
|
83
|
-
text: 'Clear Filter',
|
|
84
|
-
intent: 'danger',
|
|
85
|
-
disabled: !model.hasFilter,
|
|
86
|
-
onClick: () => model.clear()
|
|
87
|
-
}),
|
|
88
|
-
button({
|
|
89
|
-
omit: commitOnChange,
|
|
90
|
-
icon: Icon.check(),
|
|
91
|
-
text: 'Apply Filter',
|
|
92
|
-
intent: 'success',
|
|
93
|
-
disabled: !model.hasFilter && !model.hasPendingFilter,
|
|
94
|
-
onClick: () => model.commit()
|
|
95
|
-
})
|
|
96
|
-
]
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
|
|
101
|
-
const switcher = hoistCmp.factory<ColumnHeaderFilterModel>(({model}) => {
|
|
102
|
-
const {fieldType, enableValues} = model.fieldSpec,
|
|
103
|
-
{tabs} = model.tabContainerModel;
|
|
104
|
-
|
|
105
|
-
return buttonGroup({
|
|
106
|
-
omit: !enableValues || fieldType === 'bool',
|
|
107
|
-
className: 'xh-column-header-filter__tab-switcher',
|
|
108
|
-
items: tabs.map(it => switcherButton({...it}))
|
|
109
|
-
});
|
|
110
|
-
});
|
|
111
|
-
|
|
112
|
-
const switcherButton = hoistCmp.factory<ColumnHeaderFilterModel>(({model, id, title}) => {
|
|
113
|
-
const {tabContainerModel} = model,
|
|
114
|
-
{activeTabId} = tabContainerModel;
|
|
115
|
-
|
|
116
|
-
return button({
|
|
117
|
-
className: 'xh-column-header-filter__tab-switcher__button',
|
|
118
|
-
text: title,
|
|
119
|
-
active: activeTabId === id,
|
|
120
|
-
outlined: true,
|
|
121
|
-
onClick: () => tabContainerModel.activateTab(id)
|
|
122
|
-
});
|
|
123
|
-
});
|
|
@@ -6,186 +6,38 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {Column} from '@xh/hoist/cmp/grid';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {action, computed, makeObservable, observable} from '@xh/hoist/mobx';
|
|
12
|
-
import {wait} from '@xh/hoist/promise';
|
|
9
|
+
import {HoistModel} from '@xh/hoist/core';
|
|
10
|
+
import {action, makeObservable, observable} from '@xh/hoist/mobx';
|
|
13
11
|
import {isEmpty} from 'lodash';
|
|
14
|
-
import {GridFilterModel
|
|
15
|
-
import {customTab} from './custom/CustomTab';
|
|
16
|
-
import {CustomTabModel} from './custom/CustomTabModel';
|
|
17
|
-
import {valuesTab} from './values/ValuesTab';
|
|
18
|
-
import {ValuesTabModel} from './values/ValuesTabModel';
|
|
12
|
+
import {GridFilterModel} from '@xh/hoist/cmp/grid';
|
|
19
13
|
|
|
20
14
|
export class ColumnHeaderFilterModel extends HoistModel {
|
|
21
15
|
override xhImpl = true;
|
|
22
16
|
|
|
23
|
-
column: Column;
|
|
24
|
-
|
|
25
|
-
fieldSpec: GridFilterFieldSpec;
|
|
17
|
+
readonly column: Column;
|
|
18
|
+
readonly filterModel: GridFilterModel;
|
|
26
19
|
|
|
27
|
-
@observable isOpen = false;
|
|
28
|
-
|
|
29
|
-
@managed tabContainerModel: TabContainerModel;
|
|
30
|
-
@managed valuesTabModel: ValuesTabModel;
|
|
31
|
-
@managed customTabModel: CustomTabModel;
|
|
32
|
-
|
|
33
|
-
get field() {
|
|
34
|
-
return this.fieldSpec.field;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
get store() {
|
|
38
|
-
return this.gridFilterModel.gridModel.store;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
get fieldType() {
|
|
42
|
-
return this.store.getField(this.field).type;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
get currentGridFilter() {
|
|
46
|
-
return this.gridFilterModel.filter;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
get columnFilters() {
|
|
50
|
-
return this.gridFilterModel.getColumnFilters(this.field);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
get columnCompoundFilter() {
|
|
54
|
-
return this.gridFilterModel.getColumnCompoundFilter(this.field);
|
|
55
|
-
}
|
|
20
|
+
@observable isOpen: boolean = false;
|
|
56
21
|
|
|
57
22
|
get hasFilter() {
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
get hasPendingFilter() {
|
|
62
|
-
const {activeTabId} = this.tabContainerModel;
|
|
63
|
-
return activeTabId === 'valuesFilter'
|
|
64
|
-
? !!this.valuesTabModel.filter
|
|
65
|
-
: !!this.customTabModel.filter;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@computed
|
|
69
|
-
get isCustomFilter() {
|
|
70
|
-
const {columnCompoundFilter, columnFilters} = this;
|
|
71
|
-
if (columnCompoundFilter) return true;
|
|
72
|
-
if (isEmpty(columnFilters)) return false;
|
|
73
|
-
return columnFilters.some(it => !['=', '!=', 'includes'].includes(it.op));
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
get commitOnChange() {
|
|
77
|
-
return this.gridFilterModel.commitOnChange;
|
|
23
|
+
const filters = this.filterModel.getColumnFilters(this.column.field);
|
|
24
|
+
return !isEmpty(filters);
|
|
78
25
|
}
|
|
79
26
|
|
|
80
|
-
constructor(
|
|
27
|
+
constructor(filterModel: GridFilterModel, column: Column) {
|
|
81
28
|
super();
|
|
82
29
|
makeObservable(this);
|
|
83
|
-
|
|
84
|
-
this.gridFilterModel = filterModel;
|
|
30
|
+
this.filterModel = filterModel;
|
|
85
31
|
this.column = column;
|
|
86
|
-
this.fieldSpec = filterModel.getFieldSpec(column.field);
|
|
87
|
-
|
|
88
|
-
const {enableValues} = this.fieldSpec;
|
|
89
|
-
this.valuesTabModel = enableValues ? new ValuesTabModel(this) : null;
|
|
90
|
-
this.customTabModel = new CustomTabModel(this);
|
|
91
|
-
this.tabContainerModel = new TabContainerModel({
|
|
92
|
-
switcher: false,
|
|
93
|
-
tabs: [
|
|
94
|
-
{
|
|
95
|
-
id: 'valuesFilter',
|
|
96
|
-
title: 'Values',
|
|
97
|
-
content: valuesTab,
|
|
98
|
-
omit: !enableValues
|
|
99
|
-
},
|
|
100
|
-
{
|
|
101
|
-
id: 'customFilter',
|
|
102
|
-
title: 'Custom',
|
|
103
|
-
content: customTab
|
|
104
|
-
}
|
|
105
|
-
],
|
|
106
|
-
xhImpl: true
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
this.addReaction({
|
|
110
|
-
track: () => this.valuesTabModel?.filter,
|
|
111
|
-
run: () => this.doCommitOnChange('valuesFilter'),
|
|
112
|
-
debounce: 100
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
this.addReaction({
|
|
116
|
-
track: () => this.customTabModel.filter,
|
|
117
|
-
run: () => this.doCommitOnChange('customFilter'),
|
|
118
|
-
debounce: 100
|
|
119
|
-
});
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
@action
|
|
123
|
-
commit(close = true) {
|
|
124
|
-
const {tabContainerModel, customTabModel, valuesTabModel} = this,
|
|
125
|
-
{activeTabId} = tabContainerModel,
|
|
126
|
-
valuesIsActive = activeTabId === 'valuesFilter',
|
|
127
|
-
activeTabModel = valuesIsActive ? valuesTabModel : customTabModel,
|
|
128
|
-
otherTabModel = valuesIsActive ? customTabModel : valuesTabModel;
|
|
129
|
-
|
|
130
|
-
this.setColumnFilters(activeTabModel.filter);
|
|
131
|
-
if (close) {
|
|
132
|
-
this.closeMenu();
|
|
133
|
-
} else {
|
|
134
|
-
// We must wait before resetting as GridFilterModel.setFilter() is async
|
|
135
|
-
wait().then(() => otherTabModel?.reset());
|
|
136
|
-
}
|
|
137
32
|
}
|
|
138
33
|
|
|
139
34
|
@action
|
|
140
|
-
|
|
141
|
-
this.setColumnFilters(null);
|
|
142
|
-
if (close) {
|
|
143
|
-
this.closeMenu();
|
|
144
|
-
} else {
|
|
145
|
-
// We must wait before resetting as GridFilterModel.setFilter() is async
|
|
146
|
-
wait().then(() => this.resetTabModels());
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
@action
|
|
151
|
-
openMenu() {
|
|
35
|
+
open() {
|
|
152
36
|
this.isOpen = true;
|
|
153
|
-
this.syncWithFilter();
|
|
154
37
|
}
|
|
155
38
|
|
|
156
39
|
@action
|
|
157
|
-
|
|
40
|
+
close() {
|
|
158
41
|
this.isOpen = false;
|
|
159
42
|
}
|
|
160
|
-
|
|
161
|
-
//-------------------
|
|
162
|
-
// Implementation
|
|
163
|
-
//-------------------
|
|
164
|
-
@action
|
|
165
|
-
private syncWithFilter() {
|
|
166
|
-
const {isCustomFilter, valuesTabModel, customTabModel, tabContainerModel} = this,
|
|
167
|
-
useCustomTab = isCustomFilter || !valuesTabModel,
|
|
168
|
-
toTab = useCustomTab ? customTabModel : valuesTabModel,
|
|
169
|
-
toTabId = useCustomTab ? 'customFilter' : 'valuesFilter';
|
|
170
|
-
|
|
171
|
-
this.resetTabModels();
|
|
172
|
-
toTab.syncWithFilter();
|
|
173
|
-
|
|
174
|
-
tabContainerModel.activateTab(toTabId);
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
private setColumnFilters(filters) {
|
|
178
|
-
this.gridFilterModel.setColumnFilters(this.field, filters);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
private doCommitOnChange(tab) {
|
|
182
|
-
if (!this.commitOnChange) return;
|
|
183
|
-
if (this.tabContainerModel.activeTabId !== tab) return;
|
|
184
|
-
this.commit(false);
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
private resetTabModels() {
|
|
188
|
-
this.customTabModel.reset();
|
|
189
|
-
this.valuesTabModel?.reset();
|
|
190
|
-
}
|
|
191
43
|
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file belongs to Hoist, an application development toolkit
|
|
3
|
+
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
|
|
4
|
+
*
|
|
5
|
+
* Copyright © 2024 Extremely Heavy Industries Inc.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {filler} from '@xh/hoist/cmp/layout';
|
|
9
|
+
import {tabContainer} from '@xh/hoist/cmp/tab';
|
|
10
|
+
import {creates, hoistCmp} from '@xh/hoist/core';
|
|
11
|
+
import {button, buttonGroup} from '@xh/hoist/desktop/cmp/button';
|
|
12
|
+
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
13
|
+
import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
|
|
14
|
+
import {Icon} from '@xh/hoist/icon';
|
|
15
|
+
import {stopPropagation} from '@xh/hoist/utils/js';
|
|
16
|
+
import {HeaderFilterModel} from './HeaderFilterModel';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Pop-up panel to display column specific filters
|
|
20
|
+
*
|
|
21
|
+
* @internal
|
|
22
|
+
*/
|
|
23
|
+
export const headerFilter = hoistCmp.factory({
|
|
24
|
+
model: creates(HeaderFilterModel),
|
|
25
|
+
render() {
|
|
26
|
+
return panel({
|
|
27
|
+
title: `Filter`,
|
|
28
|
+
className: 'xh-column-header-filter',
|
|
29
|
+
compactHeader: true,
|
|
30
|
+
onClick: stopPropagation,
|
|
31
|
+
onDoubleClick: stopPropagation,
|
|
32
|
+
headerItems: [switcher()],
|
|
33
|
+
item: tabContainer(),
|
|
34
|
+
bbar: bbar()
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
const bbar = hoistCmp.factory<HeaderFilterModel>({
|
|
40
|
+
render({model}) {
|
|
41
|
+
const {commitOnChange} = model;
|
|
42
|
+
return toolbar({
|
|
43
|
+
compact: true,
|
|
44
|
+
items: [
|
|
45
|
+
filler(),
|
|
46
|
+
button({
|
|
47
|
+
icon: Icon.delete(),
|
|
48
|
+
text: 'Clear Filter',
|
|
49
|
+
intent: 'danger',
|
|
50
|
+
disabled: !model.hasFilter,
|
|
51
|
+
onClick: () => model.clear()
|
|
52
|
+
}),
|
|
53
|
+
button({
|
|
54
|
+
omit: commitOnChange,
|
|
55
|
+
icon: Icon.check(),
|
|
56
|
+
text: 'Apply Filter',
|
|
57
|
+
intent: 'success',
|
|
58
|
+
disabled: !model.hasFilter && !model.hasPendingFilter,
|
|
59
|
+
onClick: () => model.commit()
|
|
60
|
+
})
|
|
61
|
+
]
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const switcher = hoistCmp.factory<HeaderFilterModel>(({model}) => {
|
|
67
|
+
const {fieldType, enableValues} = model.fieldSpec,
|
|
68
|
+
{tabs} = model.tabContainerModel;
|
|
69
|
+
|
|
70
|
+
return buttonGroup({
|
|
71
|
+
omit: !enableValues || fieldType === 'bool',
|
|
72
|
+
className: 'xh-column-header-filter__tab-switcher',
|
|
73
|
+
items: tabs.map(it => switcherButton({...it}))
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
const switcherButton = hoistCmp.factory<HeaderFilterModel>(({model, id, title}) => {
|
|
78
|
+
const {tabContainerModel} = model,
|
|
79
|
+
{activeTabId} = tabContainerModel;
|
|
80
|
+
|
|
81
|
+
return button({
|
|
82
|
+
className: 'xh-column-header-filter__tab-switcher__button',
|
|
83
|
+
text: title,
|
|
84
|
+
active: activeTabId === id,
|
|
85
|
+
outlined: true,
|
|
86
|
+
onClick: () => tabContainerModel.activateTab(id)
|
|
87
|
+
});
|
|
88
|
+
});
|