@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.
Files changed (24) hide show
  1. package/build/types/desktop/cmp/grid/impl/filter/ColumnHeaderFilterModel.d.ts +6 -31
  2. package/build/types/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilter.d.ts +7 -0
  3. package/build/types/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilterModel.d.ts +32 -0
  4. package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomRowModel.d.ts +3 -3
  5. package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTabModel.d.ts +4 -4
  6. package/build/types/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTabModel.d.ts +3 -3
  7. package/cmp/grid/impl/ColumnHeader.ts +1 -4
  8. package/desktop/cmp/grid/impl/filter/ColumnHeaderFilter.ts +6 -75
  9. package/desktop/cmp/grid/impl/filter/ColumnHeaderFilterModel.ts +12 -160
  10. package/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilter.ts +88 -0
  11. package/desktop/cmp/grid/impl/filter/headerfilter/HeaderFilterModel.ts +181 -0
  12. package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomRowModel.ts +2 -2
  13. package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTabModel.ts +3 -3
  14. package/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTabModel.ts +7 -6
  15. package/package.json +1 -1
  16. package/tsconfig.tsbuildinfo +1 -1
  17. /package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomRow.d.ts +0 -0
  18. /package/build/types/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTab.d.ts +0 -0
  19. /package/build/types/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTab.d.ts +0 -0
  20. /package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomRow.ts +0 -0
  21. /package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTab.scss +0 -0
  22. /package/desktop/cmp/grid/impl/filter/{custom → headerfilter/custom}/CustomTab.ts +0 -0
  23. /package/desktop/cmp/grid/impl/filter/{values → headerfilter/values}/ValuesTab.scss +0 -0
  24. /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, GridFilterFieldSpec } from '@xh/hoist/cmp/grid';
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
- gridFilterModel: GridFilterModel;
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
- get hasPendingFilter(): boolean;
24
- get isCustomFilter(): boolean;
25
- get commitOnChange(): boolean;
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
+ }
@@ -1,6 +1,6 @@
1
1
  import { HoistModel } from '@xh/hoist/core';
2
2
  import { FieldFilterOperator, FieldFilterSpec } from '@xh/hoist/data';
3
- import { ColumnHeaderFilterModel } from '@xh/hoist/desktop/cmp/grid/impl/filter/ColumnHeaderFilterModel';
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: ColumnHeaderFilterModel;
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("../../../../../../cmp/grid").GridFilterFieldSpec;
17
+ get fieldSpec(): import("../../../../../../../cmp/grid").GridFilterFieldSpec;
18
18
  get options(): {
19
19
  label: string;
20
20
  value: OperatorOptionValue;
@@ -1,18 +1,18 @@
1
1
  import { HoistModel } from '@xh/hoist/core';
2
2
  import { CompoundFilterOperator, FilterLike } from '@xh/hoist/data';
3
- import { ColumnHeaderFilterModel } from '../ColumnHeaderFilterModel';
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: ColumnHeaderFilterModel;
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("../../../../../../cmp/grid").GridFilterFieldSpec;
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: ColumnHeaderFilterModel);
15
+ constructor(headerFilterModel: HeaderFilterModel);
16
16
  syncWithFilter(): void;
17
17
  reset(): void;
18
18
  addEmptyRow(): void;
@@ -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 { ColumnHeaderFilterModel } from '../ColumnHeaderFilterModel';
4
+ import { HeaderFilterModel } from '../HeaderFilterModel';
5
5
  export declare class ValuesTabModel extends HoistModel {
6
6
  xhImpl: boolean;
7
- headerFilterModel: ColumnHeaderFilterModel;
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: ColumnHeaderFilterModel);
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, filler} from '@xh/hoist/cmp/layout';
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.closeMenu();
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.openMenu();
46
+ model.open();
51
47
  }
52
48
  }),
53
49
  targetTagName: 'div',
54
- content: content()
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 {TabContainerModel} from '@xh/hoist/cmp/tab';
10
- import {HoistModel, managed} from '@xh/hoist/core';
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, GridFilterFieldSpec} from '@xh/hoist/cmp/grid';
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
- gridFilterModel: GridFilterModel;
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
- return !isEmpty(this.columnFilters);
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({filterModel, column}) {
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
- clear(close = true) {
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
- closeMenu() {
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
+ });