@xh/hoist 75.0.0-SNAPSHOT.1751070190067 → 75.0.0-SNAPSHOT.1751290908617
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/CHANGELOG.md +9 -0
- package/build/types/cmp/grouping/GroupingChooserModel.d.ts +7 -4
- package/build/types/desktop/cmp/grouping/GroupingChooser.d.ts +4 -4
- package/build/types/mobile/cmp/grouping/GroupingChooser.d.ts +2 -6
- package/cmp/grouping/GroupingChooserModel.ts +20 -12
- package/desktop/cmp/grouping/GroupingChooser.scss +28 -39
- package/desktop/cmp/grouping/GroupingChooser.ts +72 -82
- package/mobile/appcontainer/FeedbackDialog.ts +4 -0
- package/mobile/appcontainer/OptionsDialog.ts +3 -1
- package/mobile/cmp/grid/impl/ColChooser.ts +3 -2
- package/mobile/cmp/grouping/GroupingChooser.scss +41 -20
- package/mobile/cmp/grouping/GroupingChooser.ts +60 -89
- package/mobile/cmp/panel/DialogPanel.scss +5 -0
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,8 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
## v75.0.0-SNAPSHOT - unreleased
|
|
4
4
|
|
|
5
|
+
## v74.1.0 - 2025-06-30
|
|
6
|
+
|
|
5
7
|
### 🎁 New Features
|
|
6
8
|
|
|
9
|
+
* Updated the `GroupingChooser` UI to use a single popover for both updating the value and
|
|
10
|
+
selecting/managing favorite groupings (if enabled).
|
|
11
|
+
* Adjusted `GroupingChooserModel` API and some CSS class names and testIds of `GroupingChooser`
|
|
12
|
+
internals, although those changes are very unlikely to require app-level adjustments.
|
|
13
|
+
* Adjusted/removed (rarely used) desktop and mobile `GroupingChooser` props related to popover
|
|
14
|
+
sizing and titling.
|
|
15
|
+
* Updated the mobile UI to use a full-screen dialog, similar to `ColumnChooser`.
|
|
7
16
|
* Added props to `ViewManager` to customize icons used for different types of views, and modified
|
|
8
17
|
default icons for Global and Shared views.
|
|
9
18
|
* Added `ViewManager.extraMenuItems` prop to allow insertion of custom, app-specific items into the
|
|
@@ -8,7 +8,10 @@ export interface GroupingChooserConfig {
|
|
|
8
8
|
dimensions?: (DimensionSpec | string)[];
|
|
9
9
|
/** Initial value as an array of dimension names, or a function to produce such an array. */
|
|
10
10
|
initialValue?: string[] | (() => string[]);
|
|
11
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Initial favorites as an array of dim name arrays, or a function to produce such an array.
|
|
13
|
+
* Ignored if `persistWith.persistFavorites: false`.
|
|
14
|
+
*/
|
|
12
15
|
initialFavorites?: string[][] | (() => string[][]);
|
|
13
16
|
/** Options governing persistence. */
|
|
14
17
|
persistWith?: GroupingChooserPersistOptions;
|
|
@@ -47,7 +50,6 @@ export declare class GroupingChooserModel extends HoistModel {
|
|
|
47
50
|
persistFavorites: boolean;
|
|
48
51
|
pendingValue: string[];
|
|
49
52
|
editorIsOpen: boolean;
|
|
50
|
-
favoritesIsOpen: boolean;
|
|
51
53
|
popoverRef: import("react").RefObject<HTMLElement> & import("react").RefCallback<HTMLElement>;
|
|
52
54
|
private dimensions;
|
|
53
55
|
private dimensionNames;
|
|
@@ -55,12 +57,12 @@ export declare class GroupingChooserModel extends HoistModel {
|
|
|
55
57
|
get dimensionSpecs(): DimensionSpec[];
|
|
56
58
|
get isValid(): boolean;
|
|
57
59
|
get isAddEnabled(): boolean;
|
|
60
|
+
get isAddFavoriteEnabled(): boolean;
|
|
58
61
|
constructor({ dimensions, initialValue, initialFavorites, persistWith, allowEmpty, maxDepth, commitOnChange }: GroupingChooserConfig);
|
|
59
62
|
setDimensions(dimensions: Array<DimensionSpec | string>): void;
|
|
60
63
|
setValue(value: string[]): void;
|
|
61
64
|
toggleEditor(): void;
|
|
62
|
-
|
|
63
|
-
closePopover(): void;
|
|
65
|
+
closeEditor(): void;
|
|
64
66
|
addPendingDim(dimName: string): void;
|
|
65
67
|
replacePendingDimAtIdx(dimName: string, idx: number): void;
|
|
66
68
|
removePendingDimAtIdx(idx: number): void;
|
|
@@ -76,6 +78,7 @@ export declare class GroupingChooserModel extends HoistModel {
|
|
|
76
78
|
}[];
|
|
77
79
|
setFavorites(favorites: string[][]): void;
|
|
78
80
|
addFavorite(value: string[]): void;
|
|
81
|
+
addPendingAsFavorite(): void;
|
|
79
82
|
removeFavorite(value: string[]): void;
|
|
80
83
|
isFavorite(value: string[]): boolean;
|
|
81
84
|
private initPersist;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { GroupingChooserModel } from '@xh/hoist/cmp/grouping';
|
|
2
2
|
import { ButtonProps } from '@xh/hoist/desktop/cmp/button';
|
|
3
3
|
import '@xh/hoist/desktop/register';
|
|
4
|
-
import { ReactElement } from 'react';
|
|
5
4
|
import './GroupingChooser.scss';
|
|
6
5
|
export interface GroupingChooserProps extends ButtonProps<GroupingChooserModel> {
|
|
7
6
|
/** Text to represent empty state (i.e. value = null or []) */
|
|
@@ -12,12 +11,13 @@ export interface GroupingChooserProps extends ButtonProps<GroupingChooserModel>
|
|
|
12
11
|
popoverPosition?: 'bottom' | 'top';
|
|
13
12
|
/** Title for popover (default "GROUP BY") or null to suppress. */
|
|
14
13
|
popoverTitle?: string;
|
|
15
|
-
/**
|
|
14
|
+
/**
|
|
15
|
+
* Width in pixels of the popover menu itself.
|
|
16
|
+
* If unspecified, will default based on whether favorites are enabled.
|
|
17
|
+
*/
|
|
16
18
|
popoverWidth?: number;
|
|
17
19
|
/** True (default) to style target button as an input field - blends better in toolbars. */
|
|
18
20
|
styleButtonAsInput?: boolean;
|
|
19
|
-
/** Icon clicked to launch favorites menu. Defaults to Icon.favorite() */
|
|
20
|
-
favoritesIcon?: ReactElement;
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
23
|
* Control for selecting a list of dimensions for grouping APIs, with built-in support for
|
|
@@ -3,14 +3,10 @@ import { ButtonProps } from '@xh/hoist/mobile/cmp/button';
|
|
|
3
3
|
import '@xh/hoist/mobile/register';
|
|
4
4
|
import './GroupingChooser.scss';
|
|
5
5
|
export interface GroupingChooserProps extends ButtonProps<GroupingChooserModel> {
|
|
6
|
+
/** Custom title for editor dialog, or null to suppress. */
|
|
7
|
+
dialogTitle?: string;
|
|
6
8
|
/** Text to represent empty state (i.e. value = null or [])*/
|
|
7
9
|
emptyText?: string;
|
|
8
|
-
/** Title for popover (default "GROUP BY") or null to suppress. */
|
|
9
|
-
popoverTitle?: string;
|
|
10
|
-
/** Min height in pixels of the popover inner content (excl. header & toolbar). */
|
|
11
|
-
popoverMinHeight?: number;
|
|
12
|
-
/** Width in pixels of the popover menu itself. */
|
|
13
|
-
popoverWidth?: number;
|
|
14
10
|
}
|
|
15
11
|
/**
|
|
16
12
|
* Control for selecting a list of dimensions for grouping APIs.
|
|
@@ -23,7 +23,10 @@ export interface GroupingChooserConfig {
|
|
|
23
23
|
/** Initial value as an array of dimension names, or a function to produce such an array. */
|
|
24
24
|
initialValue?: string[] | (() => string[]);
|
|
25
25
|
|
|
26
|
-
/**
|
|
26
|
+
/**
|
|
27
|
+
* Initial favorites as an array of dim name arrays, or a function to produce such an array.
|
|
28
|
+
* Ignored if `persistWith.persistFavorites: false`.
|
|
29
|
+
*/
|
|
27
30
|
initialFavorites?: string[][] | (() => string[][]);
|
|
28
31
|
|
|
29
32
|
/** Options governing persistence. */
|
|
@@ -74,7 +77,6 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
74
77
|
// Implementation fields for Control
|
|
75
78
|
@observable.ref pendingValue: string[] = [];
|
|
76
79
|
@observable editorIsOpen: boolean = false;
|
|
77
|
-
@observable favoritesIsOpen: boolean = false;
|
|
78
80
|
popoverRef = createObservableRef<HTMLElement>();
|
|
79
81
|
|
|
80
82
|
// Internal state
|
|
@@ -105,6 +107,15 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
105
107
|
return !atMaxDepth && !isEmpty(availableDims);
|
|
106
108
|
}
|
|
107
109
|
|
|
110
|
+
@computed
|
|
111
|
+
get isAddFavoriteEnabled(): boolean {
|
|
112
|
+
return (
|
|
113
|
+
this.persistFavorites &&
|
|
114
|
+
!isEmpty(this.pendingValue) &&
|
|
115
|
+
!this.isFavorite(this.pendingValue)
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
108
119
|
constructor({
|
|
109
120
|
dimensions,
|
|
110
121
|
initialValue = [],
|
|
@@ -169,21 +180,13 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
169
180
|
toggleEditor() {
|
|
170
181
|
this.pendingValue = this.value;
|
|
171
182
|
this.editorIsOpen = !this.editorIsOpen;
|
|
172
|
-
this.favoritesIsOpen = false;
|
|
173
183
|
}
|
|
174
184
|
|
|
175
185
|
@action
|
|
176
|
-
|
|
177
|
-
this.favoritesIsOpen = !this.favoritesIsOpen;
|
|
186
|
+
closeEditor() {
|
|
178
187
|
this.editorIsOpen = false;
|
|
179
188
|
}
|
|
180
189
|
|
|
181
|
-
@action
|
|
182
|
-
closePopover() {
|
|
183
|
-
this.editorIsOpen = false;
|
|
184
|
-
this.favoritesIsOpen = false;
|
|
185
|
-
}
|
|
186
|
-
|
|
187
190
|
//-------------------------
|
|
188
191
|
// Value handling
|
|
189
192
|
//-------------------------
|
|
@@ -224,7 +227,7 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
224
227
|
if (!isEqual(value, pendingValue) && this.validateValue(pendingValue)) {
|
|
225
228
|
this.setValue(pendingValue);
|
|
226
229
|
}
|
|
227
|
-
this.
|
|
230
|
+
this.closeEditor();
|
|
228
231
|
}
|
|
229
232
|
|
|
230
233
|
validateValue(value: string[]) {
|
|
@@ -274,6 +277,11 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
274
277
|
this.favorites = [...this.favorites, value];
|
|
275
278
|
}
|
|
276
279
|
|
|
280
|
+
@action
|
|
281
|
+
addPendingAsFavorite() {
|
|
282
|
+
this.addFavorite(this.pendingValue);
|
|
283
|
+
}
|
|
284
|
+
|
|
277
285
|
@action
|
|
278
286
|
removeFavorite(value: string[]) {
|
|
279
287
|
this.favorites = this.favorites.filter(v => !isEqual(v, value));
|
|
@@ -22,11 +22,6 @@
|
|
|
22
22
|
color: var(--xh-text-color-muted);
|
|
23
23
|
}
|
|
24
24
|
}
|
|
25
|
-
|
|
26
|
-
// We must account for the favorites icon when eliding text
|
|
27
|
-
&--with-favorites {
|
|
28
|
-
padding-right: 30px !important;
|
|
29
|
-
}
|
|
30
25
|
}
|
|
31
26
|
|
|
32
27
|
// Outer box is sized via layoutSupport - all nested inner elements should stretch to fill.
|
|
@@ -39,6 +34,10 @@
|
|
|
39
34
|
position: relative;
|
|
40
35
|
}
|
|
41
36
|
|
|
37
|
+
&__editor {
|
|
38
|
+
flex: 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
42
41
|
&__list {
|
|
43
42
|
margin-bottom: var(--xh-pad-half-px);
|
|
44
43
|
background-color: var(--xh-bg-alt);
|
|
@@ -121,48 +120,38 @@
|
|
|
121
120
|
padding: 2px var(--xh-tbar-item-pad-px);
|
|
122
121
|
}
|
|
123
122
|
|
|
124
|
-
&
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
justify-content: center;
|
|
128
|
-
width: 30px;
|
|
129
|
-
height: 20px;
|
|
130
|
-
position: absolute;
|
|
131
|
-
top: 0;
|
|
132
|
-
right: 0;
|
|
133
|
-
cursor: pointer;
|
|
134
|
-
color: var(--xh-text-color-muted);
|
|
135
|
-
|
|
136
|
-
&:hover {
|
|
137
|
-
color: var(--xh-text-color);
|
|
138
|
-
}
|
|
123
|
+
&__favorites {
|
|
124
|
+
flex: 1;
|
|
125
|
+
border-left: 1px solid var(--xh-popup-border-color);
|
|
139
126
|
|
|
140
|
-
|
|
141
|
-
height: 15px;
|
|
142
|
-
}
|
|
127
|
+
--xh-menu-border: none;
|
|
143
128
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
width: 12px;
|
|
129
|
+
.bp5-menu {
|
|
130
|
+
padding: 0;
|
|
147
131
|
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
&__favorite {
|
|
151
|
-
align-items: center;
|
|
152
|
-
max-width: 50vw;
|
|
153
132
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
min-height: 20px !important;
|
|
158
|
-
visibility: hidden;
|
|
133
|
+
&__add-btn {
|
|
134
|
+
flex: none;
|
|
135
|
+
margin: var(--xh-pad-px) auto;
|
|
159
136
|
}
|
|
160
137
|
|
|
161
|
-
|
|
162
|
-
|
|
138
|
+
&__favorite {
|
|
139
|
+
align-items: center;
|
|
140
|
+
max-width: 50vw;
|
|
163
141
|
|
|
164
142
|
.xh-button {
|
|
165
|
-
|
|
143
|
+
padding: 0 !important;
|
|
144
|
+
min-width: 20px !important;
|
|
145
|
+
min-height: 20px !important;
|
|
146
|
+
visibility: hidden;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
&:hover {
|
|
150
|
+
background-color: var(--xh-bg-highlight);
|
|
151
|
+
|
|
152
|
+
.xh-button {
|
|
153
|
+
visibility: unset;
|
|
154
|
+
}
|
|
166
155
|
}
|
|
167
156
|
}
|
|
168
157
|
}
|
|
@@ -5,18 +5,17 @@
|
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
import {GroupingChooserModel} from '@xh/hoist/cmp/grouping';
|
|
8
|
-
import {box, div, filler, fragment, hbox, vbox} from '@xh/hoist/cmp/layout';
|
|
8
|
+
import {box, div, filler, fragment, hbox, hframe, vbox} from '@xh/hoist/cmp/layout';
|
|
9
9
|
import {hoistCmp, uses} from '@xh/hoist/core';
|
|
10
10
|
import {button, ButtonProps} from '@xh/hoist/desktop/cmp/button';
|
|
11
11
|
import {select} from '@xh/hoist/desktop/cmp/input';
|
|
12
12
|
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
13
13
|
import '@xh/hoist/desktop/register';
|
|
14
14
|
import {Icon} from '@xh/hoist/icon';
|
|
15
|
-
import {menu,
|
|
15
|
+
import {menu, menuItem, popover} from '@xh/hoist/kit/blueprint';
|
|
16
16
|
import {dragDropContext, draggable, droppable} from '@xh/hoist/kit/react-beautiful-dnd';
|
|
17
|
-
import {elemWithin, getTestId
|
|
17
|
+
import {elemWithin, getTestId} from '@xh/hoist/utils/js';
|
|
18
18
|
import {splitLayoutProps} from '@xh/hoist/utils/react';
|
|
19
|
-
import {ReactElement} from 'react';
|
|
20
19
|
import classNames from 'classnames';
|
|
21
20
|
import {compact, isEmpty, sortBy} from 'lodash';
|
|
22
21
|
import './GroupingChooser.scss';
|
|
@@ -34,14 +33,14 @@ export interface GroupingChooserProps extends ButtonProps<GroupingChooserModel>
|
|
|
34
33
|
/** Title for popover (default "GROUP BY") or null to suppress. */
|
|
35
34
|
popoverTitle?: string;
|
|
36
35
|
|
|
37
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Width in pixels of the popover menu itself.
|
|
38
|
+
* If unspecified, will default based on whether favorites are enabled.
|
|
39
|
+
*/
|
|
38
40
|
popoverWidth?: number;
|
|
39
41
|
|
|
40
42
|
/** True (default) to style target button as an input field - blends better in toolbars. */
|
|
41
43
|
styleButtonAsInput?: boolean;
|
|
42
|
-
|
|
43
|
-
/** Icon clicked to launch favorites menu. Defaults to Icon.favorite() */
|
|
44
|
-
favoritesIcon?: ReactElement;
|
|
45
44
|
}
|
|
46
45
|
|
|
47
46
|
/**
|
|
@@ -60,24 +59,22 @@ export const [GroupingChooser, groupingChooser] = hoistCmp.withFactory<GroupingC
|
|
|
60
59
|
model,
|
|
61
60
|
className,
|
|
62
61
|
emptyText = 'Ungrouped',
|
|
63
|
-
popoverWidth
|
|
62
|
+
popoverWidth,
|
|
64
63
|
popoverMinHeight,
|
|
65
64
|
popoverTitle = 'Group By',
|
|
66
65
|
popoverPosition = 'bottom',
|
|
67
66
|
styleButtonAsInput = true,
|
|
68
67
|
testId,
|
|
69
|
-
favoritesIcon,
|
|
70
68
|
...rest
|
|
71
69
|
},
|
|
72
70
|
ref
|
|
73
71
|
) {
|
|
74
|
-
const {editorIsOpen,
|
|
75
|
-
isOpen = editorIsOpen
|
|
72
|
+
const {editorIsOpen, value, allowEmpty, persistFavorites} = model,
|
|
73
|
+
isOpen = editorIsOpen,
|
|
76
74
|
label = isEmpty(value) && allowEmpty ? emptyText : model.getValueLabel(value),
|
|
77
|
-
[layoutProps, buttonProps] = splitLayoutProps(rest)
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
editorTestId = getTestId(testId, 'editor');
|
|
75
|
+
[layoutProps, buttonProps] = splitLayoutProps(rest);
|
|
76
|
+
|
|
77
|
+
popoverWidth = popoverWidth || (persistFavorites ? 500 : 250);
|
|
81
78
|
|
|
82
79
|
return box({
|
|
83
80
|
ref,
|
|
@@ -87,10 +84,9 @@ export const [GroupingChooser, groupingChooser] = hoistCmp.withFactory<GroupingC
|
|
|
87
84
|
isOpen,
|
|
88
85
|
popoverRef: model.popoverRef,
|
|
89
86
|
popoverClassName: 'xh-grouping-chooser-popover xh-popup--framed',
|
|
90
|
-
//
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
minimal: styleButtonAsInput,
|
|
87
|
+
// Left align editor to keep in place when button changing size when commitOnChange: true
|
|
88
|
+
position: `${popoverPosition}-left`,
|
|
89
|
+
minimal: false,
|
|
94
90
|
item: fragment(
|
|
95
91
|
button({
|
|
96
92
|
text: label,
|
|
@@ -98,34 +94,27 @@ export const [GroupingChooser, groupingChooser] = hoistCmp.withFactory<GroupingC
|
|
|
98
94
|
tabIndex: -1,
|
|
99
95
|
className: classNames(
|
|
100
96
|
'xh-grouping-chooser-button',
|
|
101
|
-
styleButtonAsInput ? 'xh-grouping-chooser-button--as-input' : null
|
|
102
|
-
persistFavorites ? 'xh-grouping-chooser-button--with-favorites' : null
|
|
97
|
+
styleButtonAsInput ? 'xh-grouping-chooser-button--as-input' : null
|
|
103
98
|
),
|
|
104
99
|
minimal: styleButtonAsInput,
|
|
105
100
|
...buttonProps,
|
|
106
101
|
onClick: () => model.toggleEditor(),
|
|
107
102
|
testId
|
|
108
|
-
})
|
|
109
|
-
favoritesIconCmp({testId: favoritesIconTestId, favoritesIcon})
|
|
103
|
+
})
|
|
110
104
|
),
|
|
111
|
-
content:
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
testId: editorTestId
|
|
119
|
-
}),
|
|
105
|
+
content: popoverCmp({
|
|
106
|
+
popoverWidth,
|
|
107
|
+
popoverMinHeight,
|
|
108
|
+
popoverTitle,
|
|
109
|
+
emptyText,
|
|
110
|
+
testId
|
|
111
|
+
}),
|
|
120
112
|
onInteraction: (nextOpenState, e) => {
|
|
121
113
|
if (
|
|
122
114
|
isOpen &&
|
|
123
115
|
nextOpenState === false &&
|
|
124
116
|
e?.target &&
|
|
125
|
-
!elemWithin(
|
|
126
|
-
e.target as HTMLElement,
|
|
127
|
-
'xh-grouping-chooser-button--with-favorites'
|
|
128
|
-
)
|
|
117
|
+
!elemWithin(e.target as HTMLElement, 'xh-grouping-chooser-button')
|
|
129
118
|
) {
|
|
130
119
|
model.commitPendingValueAndClose();
|
|
131
120
|
}
|
|
@@ -138,18 +127,38 @@ export const [GroupingChooser, groupingChooser] = hoistCmp.withFactory<GroupingC
|
|
|
138
127
|
//------------------
|
|
139
128
|
// Editor
|
|
140
129
|
//------------------
|
|
141
|
-
const
|
|
142
|
-
render({popoverWidth, popoverMinHeight, popoverTitle, emptyText, testId}) {
|
|
130
|
+
const popoverCmp = hoistCmp.factory<GroupingChooserModel>({
|
|
131
|
+
render({model, popoverWidth, popoverMinHeight, popoverTitle, emptyText, testId}) {
|
|
143
132
|
return panel({
|
|
144
133
|
width: popoverWidth,
|
|
145
134
|
minHeight: popoverMinHeight,
|
|
135
|
+
items: hframe({
|
|
136
|
+
items: [
|
|
137
|
+
editor({
|
|
138
|
+
popoverTitle,
|
|
139
|
+
emptyText,
|
|
140
|
+
testId: getTestId(testId, 'editor')
|
|
141
|
+
}),
|
|
142
|
+
favoritesChooser({
|
|
143
|
+
omit: !model.persistFavorites,
|
|
144
|
+
testId: getTestId(testId, 'favorites')
|
|
145
|
+
})
|
|
146
|
+
]
|
|
147
|
+
})
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
const editor = hoistCmp.factory<GroupingChooserModel>({
|
|
153
|
+
render({popoverTitle, emptyText, testId}) {
|
|
154
|
+
return vbox({
|
|
155
|
+
className: 'xh-grouping-chooser__editor',
|
|
156
|
+
testId,
|
|
146
157
|
items: [
|
|
147
158
|
div({className: 'xh-popup__title', item: popoverTitle, omit: !popoverTitle}),
|
|
148
159
|
dimensionList({emptyText}),
|
|
149
|
-
addDimensionControl()
|
|
150
|
-
|
|
151
|
-
],
|
|
152
|
-
testId
|
|
160
|
+
addDimensionControl()
|
|
161
|
+
]
|
|
153
162
|
});
|
|
154
163
|
}
|
|
155
164
|
});
|
|
@@ -283,7 +292,7 @@ const addDimensionControl = hoistCmp.factory<GroupingChooserModel>({
|
|
|
283
292
|
// ensure the Select loses its internal input state.
|
|
284
293
|
key: JSON.stringify(options),
|
|
285
294
|
options,
|
|
286
|
-
placeholder: 'Add...',
|
|
295
|
+
placeholder: 'Add level...',
|
|
287
296
|
flex: 1,
|
|
288
297
|
width: null,
|
|
289
298
|
hideDropdownIndicator: true,
|
|
@@ -320,47 +329,28 @@ function getDimOptions(dims, model) {
|
|
|
320
329
|
//------------------
|
|
321
330
|
// Favorites
|
|
322
331
|
//------------------
|
|
323
|
-
const
|
|
324
|
-
render({model, testId, favoritesIcon}) {
|
|
325
|
-
if (!model.persistFavorites) return null;
|
|
326
|
-
return div({
|
|
327
|
-
item: favoritesIcon ?? Icon.favorite(),
|
|
328
|
-
className: 'xh-grouping-chooser__favorite-icon',
|
|
329
|
-
[TEST_ID]: testId,
|
|
330
|
-
onClick: e => {
|
|
331
|
-
model.toggleFavoritesMenu();
|
|
332
|
-
e.stopPropagation();
|
|
333
|
-
}
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
const favoritesMenu = hoistCmp.factory<GroupingChooserModel>({
|
|
332
|
+
const favoritesChooser = hoistCmp.factory<GroupingChooserModel>({
|
|
339
333
|
render({model, testId}) {
|
|
340
|
-
const options = model
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if (isEmpty(options)) {
|
|
346
|
-
items.push(menuItem({text: 'No favorites saved...', disabled: true}));
|
|
347
|
-
} else {
|
|
348
|
-
items.push(...options.map(it => favoriteMenuItem(it)));
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
items.push(
|
|
352
|
-
menuDivider({omit: omitAdd}),
|
|
353
|
-
menuItem({
|
|
354
|
-
icon: Icon.add({intent: 'success'}),
|
|
355
|
-
text: 'Add current',
|
|
356
|
-
omit: omitAdd,
|
|
357
|
-
onClick: () => model.addFavorite(model.value)
|
|
358
|
-
})
|
|
359
|
-
);
|
|
334
|
+
const {favoritesOptions: options, isAddFavoriteEnabled} = model,
|
|
335
|
+
items = isEmpty(options)
|
|
336
|
+
? [menuItem({text: 'No favorites saved.', disabled: true})]
|
|
337
|
+
: options.map(it => favoriteMenuItem(it));
|
|
360
338
|
|
|
361
339
|
return vbox({
|
|
340
|
+
className: 'xh-grouping-chooser__favorites',
|
|
362
341
|
testId,
|
|
363
|
-
items: [
|
|
342
|
+
items: [
|
|
343
|
+
div({className: 'xh-popup__title', item: 'Favorites'}),
|
|
344
|
+
menu({items}),
|
|
345
|
+
button({
|
|
346
|
+
text: 'Add current',
|
|
347
|
+
icon: Icon.add({intent: 'success'}),
|
|
348
|
+
className: 'xh-grouping-chooser__favorites__add-btn',
|
|
349
|
+
outlined: true,
|
|
350
|
+
omit: !isAddFavoriteEnabled,
|
|
351
|
+
onClick: () => model.addPendingAsFavorite()
|
|
352
|
+
})
|
|
353
|
+
]
|
|
364
354
|
});
|
|
365
355
|
}
|
|
366
356
|
});
|
|
@@ -369,7 +359,7 @@ const favoriteMenuItem = hoistCmp.factory<GroupingChooserModel>({
|
|
|
369
359
|
render({model, value, label}) {
|
|
370
360
|
return menuItem({
|
|
371
361
|
text: label,
|
|
372
|
-
className: 'xh-grouping-
|
|
362
|
+
className: 'xh-grouping-chooser__favorites__favorite',
|
|
373
363
|
onClick: () => model.setValue(value),
|
|
374
364
|
labelElement: button({
|
|
375
365
|
icon: Icon.delete(),
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import {FeedbackDialogModel} from '@xh/hoist/appcontainer/FeedbackDialogModel';
|
|
8
8
|
import {filler} from '@xh/hoist/cmp/layout';
|
|
9
9
|
import {hoistCmp, uses} from '@xh/hoist/core';
|
|
10
|
+
import {Icon} from '@xh/hoist/icon';
|
|
10
11
|
import {button} from '@xh/hoist/mobile/cmp/button';
|
|
11
12
|
import {dialog} from '@xh/hoist/mobile/cmp/dialog';
|
|
12
13
|
import {textArea} from '@xh/hoist/mobile/cmp/input';
|
|
@@ -41,6 +42,9 @@ export const feedbackDialog = hoistCmp.factory({
|
|
|
41
42
|
}),
|
|
42
43
|
button({
|
|
43
44
|
text: 'Send',
|
|
45
|
+
icon: Icon.mail(),
|
|
46
|
+
intent: 'primary',
|
|
47
|
+
outlined: true,
|
|
44
48
|
onClick: () => model.submitAsync()
|
|
45
49
|
})
|
|
46
50
|
]
|
|
@@ -57,8 +57,10 @@ export const optionsDialog = hoistCmp.factory({
|
|
|
57
57
|
onClick: () => model.hide()
|
|
58
58
|
}),
|
|
59
59
|
button({
|
|
60
|
-
text: '
|
|
60
|
+
text: 'Apply',
|
|
61
61
|
icon: reloadRequired ? Icon.refresh() : Icon.check(),
|
|
62
|
+
intent: 'primary',
|
|
63
|
+
outlined: true,
|
|
62
64
|
disabled: !formModel.isDirty,
|
|
63
65
|
onClick: () => model.saveAsync()
|
|
64
66
|
})
|
|
@@ -60,7 +60,6 @@ export const [ColChooser, colChooser] = hoistCmp.withFactory<ColChooserProps>({
|
|
|
60
60
|
onDragEnd: impl.onDragEnd,
|
|
61
61
|
items: [
|
|
62
62
|
panel({
|
|
63
|
-
title: 'Visible Columns',
|
|
64
63
|
className: 'xh-col-chooser__section',
|
|
65
64
|
scrollable: true,
|
|
66
65
|
items: [
|
|
@@ -119,8 +118,10 @@ export const [ColChooser, colChooser] = hoistCmp.withFactory<ColChooserProps>({
|
|
|
119
118
|
onClick: () => model.close()
|
|
120
119
|
}),
|
|
121
120
|
button({
|
|
122
|
-
text: '
|
|
121
|
+
text: 'Apply',
|
|
123
122
|
icon: Icon.check(),
|
|
123
|
+
intent: 'primary',
|
|
124
|
+
outlined: true,
|
|
124
125
|
onClick: () => {
|
|
125
126
|
model.commit();
|
|
126
127
|
model.close();
|
|
@@ -16,18 +16,23 @@
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
&__editor {
|
|
20
|
+
.xh-panel__content {
|
|
21
|
+
padding: var(--xh-pad-px);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
19
25
|
&__row {
|
|
20
26
|
display: flex;
|
|
21
27
|
align-items: center;
|
|
22
28
|
background-color: var(--xh-bg);
|
|
23
|
-
height:
|
|
29
|
+
height: 45px;
|
|
24
30
|
flex-shrink: 0;
|
|
25
31
|
|
|
26
32
|
&__grabber {
|
|
27
33
|
display: flex;
|
|
28
34
|
align-items: center;
|
|
29
35
|
justify-content: center;
|
|
30
|
-
height: 30px;
|
|
31
36
|
width: 30px;
|
|
32
37
|
}
|
|
33
38
|
|
|
@@ -49,30 +54,46 @@
|
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
&__add-control {
|
|
52
|
-
|
|
57
|
+
// Align with already-added level controls.
|
|
58
|
+
padding: 5px 40px 5px 30px;
|
|
53
59
|
}
|
|
54
60
|
|
|
55
|
-
&
|
|
56
|
-
height:
|
|
57
|
-
|
|
61
|
+
&__favorites {
|
|
62
|
+
// Fix at 50% of dialog height, preventing panel's default flex:auto
|
|
63
|
+
flex: none !important;
|
|
64
|
+
height: 50%;
|
|
58
65
|
|
|
59
|
-
|
|
60
|
-
|
|
66
|
+
// Section heading style for internal title (like colChooser)
|
|
67
|
+
.xh-panel-header {
|
|
68
|
+
background-color: var(--xh-appbar-bg);
|
|
69
|
+
color: var(--xh-appbar-title-color);
|
|
70
|
+
padding-left: var(--xh-pad-px);
|
|
61
71
|
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
72
|
|
|
65
|
-
.xh-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
73
|
+
.xh-panel__content {
|
|
74
|
+
padding: var(--xh-pad-px);
|
|
75
|
+
}
|
|
69
76
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
77
|
+
// Empty state placeholder - don't flex as it pushes add button down.
|
|
78
|
+
.xh-placeholder {
|
|
79
|
+
flex: none;
|
|
80
|
+
margin: var(--xh-pad-px);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Individual favorite items (hBoxes w/buttons)
|
|
84
|
+
&__favorite {
|
|
85
|
+
flex: none !important;
|
|
86
|
+
height: 35px;
|
|
87
|
+
align-items: center;
|
|
73
88
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
89
|
+
.xh-button {
|
|
90
|
+
justify-content: left;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
&__add-btn {
|
|
95
|
+
width: 200px;
|
|
96
|
+
margin: var(--xh-pad-px) auto;
|
|
97
|
+
}
|
|
77
98
|
}
|
|
78
99
|
}
|