@xh/hoist 74.1.0 → 74.1.2
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 +20 -0
- package/build/types/cmp/grouping/GroupingChooserModel.d.ts +1 -0
- package/build/types/core/types/Interfaces.d.ts +1 -1
- package/build/types/desktop/cmp/grouping/GroupingChooser.d.ts +14 -3
- package/build/types/desktop/cmp/panel/Panel.d.ts +1 -1
- package/cmp/grouping/GroupingChooserModel.ts +5 -0
- package/core/exception/ExceptionHandler.ts +1 -1
- package/core/types/Interfaces.ts +2 -2
- package/desktop/cmp/grouping/GroupingChooser.scss +31 -15
- package/desktop/cmp/grouping/GroupingChooser.ts +125 -45
- package/desktop/cmp/panel/Panel.ts +1 -1
- package/package.json +1 -1
- package/svc/TrackService.ts +4 -3
- package/tsconfig.tsbuildinfo +1 -1
- package/utils/js/LangUtils.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v74.1.2 - 2025-07-03
|
|
4
|
+
|
|
5
|
+
### 🐞 Bug Fixes
|
|
6
|
+
|
|
7
|
+
* Fixed `GroupingChooser` layout issue, visible only when favorites are disabled.
|
|
8
|
+
|
|
9
|
+
## v74.1.1 - 2025-07-02
|
|
10
|
+
|
|
11
|
+
### 🎁 New Features
|
|
12
|
+
|
|
13
|
+
* Further refinements to the `GroupingChooser` desktop UI.
|
|
14
|
+
* Added new props `favoritesSide` and `favoritesTitle`.
|
|
15
|
+
* Deprecated `popoverTitle` prop - use `editorTitle` instead.
|
|
16
|
+
* Moved "Save as Favorite" button to a new compact toolbar within the popover.
|
|
17
|
+
|
|
18
|
+
### 🐞 Bug Fixes
|
|
19
|
+
|
|
20
|
+
* Fixed a bug where `TrackService` was not properly verifying that tracked `data` was below the
|
|
21
|
+
configured `maxDataLength` limit.
|
|
22
|
+
|
|
3
23
|
## v74.1.0 - 2025-06-30
|
|
4
24
|
|
|
5
25
|
### 🎁 New Features
|
|
@@ -177,7 +177,7 @@ export interface TrackOptions {
|
|
|
177
177
|
/** Correlation ID to save along with track log. */
|
|
178
178
|
correlationId?: string;
|
|
179
179
|
/** App-supplied data to save along with track log.*/
|
|
180
|
-
data?: PlainObject |
|
|
180
|
+
data?: PlainObject | Array<unknown>;
|
|
181
181
|
/**
|
|
182
182
|
* Set true to log on the server all primitive values in the 'data' property.
|
|
183
183
|
* May also be specified as list of specific property keys that should be logged.
|
|
@@ -1,19 +1,30 @@
|
|
|
1
1
|
import { GroupingChooserModel } from '@xh/hoist/cmp/grouping';
|
|
2
|
+
import { Side } from '@xh/hoist/core';
|
|
2
3
|
import { ButtonProps } from '@xh/hoist/desktop/cmp/button';
|
|
3
4
|
import '@xh/hoist/desktop/register';
|
|
4
5
|
import './GroupingChooser.scss';
|
|
6
|
+
import { ReactNode } from 'react';
|
|
5
7
|
export interface GroupingChooserProps extends ButtonProps<GroupingChooserModel> {
|
|
8
|
+
/** Title for value-editing portion of popover, or null to suppress. */
|
|
9
|
+
editorTitle?: ReactNode;
|
|
6
10
|
/** Text to represent empty state (i.e. value = null or []) */
|
|
7
11
|
emptyText?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Side of the popover, relative to the value-editing controls, on which the Favorites list
|
|
14
|
+
* should be rendered, if enabled.
|
|
15
|
+
*/
|
|
16
|
+
favoritesSide?: Side;
|
|
17
|
+
/** Title for favorites-list portion of popover, or null to suppress. */
|
|
18
|
+
favoritesTitle?: ReactNode;
|
|
8
19
|
/** Min height in pixels of the popover menu itself. */
|
|
9
20
|
popoverMinHeight?: number;
|
|
10
21
|
/** Position of popover relative to target button. */
|
|
11
22
|
popoverPosition?: 'bottom' | 'top';
|
|
12
|
-
/**
|
|
13
|
-
popoverTitle?:
|
|
23
|
+
/** @deprecated - use `editorTitle` instead */
|
|
24
|
+
popoverTitle?: ReactNode;
|
|
14
25
|
/**
|
|
15
26
|
* Width in pixels of the popover menu itself.
|
|
16
|
-
* If unspecified, will default based on
|
|
27
|
+
* If unspecified, will default based on favorites enabled status + side.
|
|
17
28
|
*/
|
|
18
29
|
popoverWidth?: number;
|
|
19
30
|
/** True (default) to style target button as an input field - blends better in toolbars. */
|
|
@@ -44,7 +44,7 @@ export interface PanelProps extends HoistProps<PanelModel>, Omit<BoxProps, 'titl
|
|
|
44
44
|
*/
|
|
45
45
|
tbar?: Some<ReactNode>;
|
|
46
46
|
/**
|
|
47
|
-
* A toolbar to be docked at the
|
|
47
|
+
* A toolbar to be docked at the bottom of the panel.
|
|
48
48
|
* If specified as an array, items will be passed as children to a Toolbar component.
|
|
49
49
|
*/
|
|
50
50
|
bbar?: Some<ReactNode>;
|
|
@@ -266,6 +266,11 @@ export class GroupingChooserModel extends HoistModel {
|
|
|
266
266
|
);
|
|
267
267
|
}
|
|
268
268
|
|
|
269
|
+
@computed
|
|
270
|
+
get hasFavorites() {
|
|
271
|
+
return !isEmpty(this.favorites);
|
|
272
|
+
}
|
|
273
|
+
|
|
269
274
|
@action
|
|
270
275
|
setFavorites(favorites: string[][]) {
|
|
271
276
|
this.favorites = favorites.filter(v => this.validateValue(v));
|
|
@@ -202,7 +202,7 @@ export class ExceptionHandler {
|
|
|
202
202
|
XH.track({
|
|
203
203
|
category: 'Client Error',
|
|
204
204
|
severity: exception.isRoutine ? 'INFO' : 'ERROR',
|
|
205
|
-
message: exception.message
|
|
205
|
+
message: exception.message || 'Client Error',
|
|
206
206
|
correlationId: exception.correlationId,
|
|
207
207
|
data,
|
|
208
208
|
logData: ['userAlerted']
|
package/core/types/Interfaces.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {RuleLike} from '@xh/hoist/data';
|
|
9
|
-
import {MouseEvent, ReactElement, ReactNode, isValidElement} from 'react';
|
|
10
9
|
import {isString} from 'lodash';
|
|
10
|
+
import {isValidElement, MouseEvent, ReactElement, ReactNode} from 'react';
|
|
11
11
|
import {LoadSpec} from '../load';
|
|
12
12
|
import {Intent, PlainObject, Thunkable} from './Types';
|
|
13
13
|
|
|
@@ -224,7 +224,7 @@ export interface TrackOptions {
|
|
|
224
224
|
correlationId?: string;
|
|
225
225
|
|
|
226
226
|
/** App-supplied data to save along with track log.*/
|
|
227
|
-
data?: PlainObject |
|
|
227
|
+
data?: PlainObject | Array<unknown>;
|
|
228
228
|
|
|
229
229
|
/**
|
|
230
230
|
* Set true to log on the server all primitive values in the 'data' property.
|
|
@@ -34,8 +34,20 @@
|
|
|
34
34
|
position: relative;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
&-popover {
|
|
38
|
+
// 60/40 split in favor of favorites in left/right orientation
|
|
39
|
+
&--faves-right,
|
|
40
|
+
&--faves-left {
|
|
41
|
+
.xh-grouping-chooser__editor {
|
|
42
|
+
width: 40%;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
&--faves-disabled {
|
|
47
|
+
.xh-grouping-chooser__editor {
|
|
48
|
+
flex: 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
39
51
|
}
|
|
40
52
|
|
|
41
53
|
&__list {
|
|
@@ -115,14 +127,24 @@
|
|
|
115
127
|
}
|
|
116
128
|
}
|
|
117
129
|
|
|
118
|
-
&__btn-row {
|
|
119
|
-
min-height: unset !important;
|
|
120
|
-
padding: 2px var(--xh-tbar-item-pad-px);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
130
|
&__favorites {
|
|
124
|
-
|
|
125
|
-
|
|
131
|
+
&--top {
|
|
132
|
+
border-bottom: 1px solid var(--xh-popup-border-color);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
&--right {
|
|
136
|
+
flex: 1;
|
|
137
|
+
border-left: 1px solid var(--xh-popup-border-color);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
&--bottom {
|
|
141
|
+
border-top: 1px solid var(--xh-popup-border-color);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
&--left {
|
|
145
|
+
flex: 1;
|
|
146
|
+
border-right: 1px solid var(--xh-popup-border-color);
|
|
147
|
+
}
|
|
126
148
|
|
|
127
149
|
--xh-menu-border: none;
|
|
128
150
|
|
|
@@ -130,14 +152,8 @@
|
|
|
130
152
|
padding: 0;
|
|
131
153
|
}
|
|
132
154
|
|
|
133
|
-
&__add-btn {
|
|
134
|
-
flex: none;
|
|
135
|
-
margin: var(--xh-pad-px) auto;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
155
|
&__favorite {
|
|
139
156
|
align-items: center;
|
|
140
|
-
max-width: 50vw;
|
|
141
157
|
|
|
142
158
|
.xh-button {
|
|
143
159
|
padding: 0 !important;
|
|
@@ -5,37 +5,62 @@
|
|
|
5
5
|
* Copyright © 2025 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
import {GroupingChooserModel} from '@xh/hoist/cmp/grouping';
|
|
8
|
-
import {
|
|
9
|
-
|
|
8
|
+
import {
|
|
9
|
+
box,
|
|
10
|
+
div,
|
|
11
|
+
filler,
|
|
12
|
+
fragment,
|
|
13
|
+
frame,
|
|
14
|
+
hbox,
|
|
15
|
+
hframe,
|
|
16
|
+
placeholder,
|
|
17
|
+
vbox,
|
|
18
|
+
vframe
|
|
19
|
+
} from '@xh/hoist/cmp/layout';
|
|
20
|
+
import {hoistCmp, Side, uses} from '@xh/hoist/core';
|
|
10
21
|
import {button, ButtonProps} from '@xh/hoist/desktop/cmp/button';
|
|
11
22
|
import {select} from '@xh/hoist/desktop/cmp/input';
|
|
12
23
|
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
13
24
|
import '@xh/hoist/desktop/register';
|
|
25
|
+
import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
|
|
14
26
|
import {Icon} from '@xh/hoist/icon';
|
|
15
27
|
import {menu, menuItem, popover} from '@xh/hoist/kit/blueprint';
|
|
16
28
|
import {dragDropContext, draggable, droppable} from '@xh/hoist/kit/react-beautiful-dnd';
|
|
17
|
-
import {elemWithin, getTestId} from '@xh/hoist/utils/js';
|
|
29
|
+
import {apiDeprecated, elemWithin, getTestId} from '@xh/hoist/utils/js';
|
|
18
30
|
import {splitLayoutProps} from '@xh/hoist/utils/react';
|
|
19
31
|
import classNames from 'classnames';
|
|
20
|
-
import {compact, isEmpty, sortBy} from 'lodash';
|
|
32
|
+
import {compact, isEmpty, isNil, isUndefined, sortBy} from 'lodash';
|
|
21
33
|
import './GroupingChooser.scss';
|
|
34
|
+
import {ReactNode} from 'react';
|
|
22
35
|
|
|
23
36
|
export interface GroupingChooserProps extends ButtonProps<GroupingChooserModel> {
|
|
37
|
+
/** Title for value-editing portion of popover, or null to suppress. */
|
|
38
|
+
editorTitle?: ReactNode;
|
|
39
|
+
|
|
24
40
|
/** Text to represent empty state (i.e. value = null or []) */
|
|
25
41
|
emptyText?: string;
|
|
26
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Side of the popover, relative to the value-editing controls, on which the Favorites list
|
|
45
|
+
* should be rendered, if enabled.
|
|
46
|
+
*/
|
|
47
|
+
favoritesSide?: Side;
|
|
48
|
+
|
|
49
|
+
/** Title for favorites-list portion of popover, or null to suppress. */
|
|
50
|
+
favoritesTitle?: ReactNode;
|
|
51
|
+
|
|
27
52
|
/** Min height in pixels of the popover menu itself. */
|
|
28
53
|
popoverMinHeight?: number;
|
|
29
54
|
|
|
30
55
|
/** Position of popover relative to target button. */
|
|
31
56
|
popoverPosition?: 'bottom' | 'top';
|
|
32
57
|
|
|
33
|
-
/**
|
|
34
|
-
popoverTitle?:
|
|
58
|
+
/** @deprecated - use `editorTitle` instead */
|
|
59
|
+
popoverTitle?: ReactNode;
|
|
35
60
|
|
|
36
61
|
/**
|
|
37
62
|
* Width in pixels of the popover menu itself.
|
|
38
|
-
* If unspecified, will default based on
|
|
63
|
+
* If unspecified, will default based on favorites enabled status + side.
|
|
39
64
|
*/
|
|
40
65
|
popoverWidth?: number;
|
|
41
66
|
|
|
@@ -58,10 +83,13 @@ export const [GroupingChooser, groupingChooser] = hoistCmp.withFactory<GroupingC
|
|
|
58
83
|
{
|
|
59
84
|
model,
|
|
60
85
|
className,
|
|
86
|
+
editorTitle = 'Group By',
|
|
61
87
|
emptyText = 'Ungrouped',
|
|
88
|
+
favoritesSide = 'right',
|
|
89
|
+
favoritesTitle = 'Favorites',
|
|
62
90
|
popoverWidth,
|
|
63
91
|
popoverMinHeight,
|
|
64
|
-
popoverTitle
|
|
92
|
+
popoverTitle,
|
|
65
93
|
popoverPosition = 'bottom',
|
|
66
94
|
styleButtonAsInput = true,
|
|
67
95
|
testId,
|
|
@@ -72,9 +100,18 @@ export const [GroupingChooser, groupingChooser] = hoistCmp.withFactory<GroupingC
|
|
|
72
100
|
const {editorIsOpen, value, allowEmpty, persistFavorites} = model,
|
|
73
101
|
isOpen = editorIsOpen,
|
|
74
102
|
label = isEmpty(value) && allowEmpty ? emptyText : model.getValueLabel(value),
|
|
75
|
-
[layoutProps, buttonProps] = splitLayoutProps(rest)
|
|
103
|
+
[layoutProps, buttonProps] = splitLayoutProps(rest),
|
|
104
|
+
favesClassNameMod = `faves-${persistFavorites ? favoritesSide : 'disabled'}`,
|
|
105
|
+
favesTB = isTB(favoritesSide);
|
|
106
|
+
|
|
107
|
+
if (!isUndefined(popoverTitle)) {
|
|
108
|
+
apiDeprecated('GroupingChooser.popoverTitle', {
|
|
109
|
+
msg: `Update to use 'editorTitle' instead`
|
|
110
|
+
});
|
|
111
|
+
editorTitle = popoverTitle;
|
|
112
|
+
}
|
|
76
113
|
|
|
77
|
-
popoverWidth = popoverWidth || (persistFavorites ? 500 : 250);
|
|
114
|
+
popoverWidth = popoverWidth || (persistFavorites && !favesTB ? 500 : 250);
|
|
78
115
|
|
|
79
116
|
return box({
|
|
80
117
|
ref,
|
|
@@ -83,7 +120,7 @@ export const [GroupingChooser, groupingChooser] = hoistCmp.withFactory<GroupingC
|
|
|
83
120
|
item: popover({
|
|
84
121
|
isOpen,
|
|
85
122
|
popoverRef: model.popoverRef,
|
|
86
|
-
popoverClassName:
|
|
123
|
+
popoverClassName: `xh-grouping-chooser-popover xh-grouping-chooser-popover--${favesClassNameMod} xh-popup--framed`,
|
|
87
124
|
// Left align editor to keep in place when button changing size when commitOnChange: true
|
|
88
125
|
position: `${popoverPosition}-left`,
|
|
89
126
|
minimal: false,
|
|
@@ -103,10 +140,12 @@ export const [GroupingChooser, groupingChooser] = hoistCmp.withFactory<GroupingC
|
|
|
103
140
|
})
|
|
104
141
|
),
|
|
105
142
|
content: popoverCmp({
|
|
143
|
+
editorTitle,
|
|
144
|
+
emptyText,
|
|
145
|
+
favoritesSide,
|
|
146
|
+
favoritesTitle,
|
|
106
147
|
popoverWidth,
|
|
107
148
|
popoverMinHeight,
|
|
108
|
-
popoverTitle,
|
|
109
|
-
emptyText,
|
|
110
149
|
testId
|
|
111
150
|
}),
|
|
112
151
|
onInteraction: (nextOpenState, e) => {
|
|
@@ -127,35 +166,63 @@ export const [GroupingChooser, groupingChooser] = hoistCmp.withFactory<GroupingC
|
|
|
127
166
|
//------------------
|
|
128
167
|
// Editor
|
|
129
168
|
//------------------
|
|
130
|
-
const popoverCmp = hoistCmp.factory<
|
|
131
|
-
render({
|
|
169
|
+
const popoverCmp = hoistCmp.factory<Partial<GroupingChooserProps>>({
|
|
170
|
+
render({
|
|
171
|
+
model,
|
|
172
|
+
editorTitle,
|
|
173
|
+
emptyText,
|
|
174
|
+
favoritesSide,
|
|
175
|
+
favoritesTitle,
|
|
176
|
+
popoverWidth,
|
|
177
|
+
popoverMinHeight,
|
|
178
|
+
testId
|
|
179
|
+
}) {
|
|
180
|
+
const {persistFavorites} = model,
|
|
181
|
+
favesTB = isTB(favoritesSide),
|
|
182
|
+
isFavesFirst = favoritesSide === 'left' || favoritesSide === 'top',
|
|
183
|
+
items = [
|
|
184
|
+
editor({
|
|
185
|
+
editorTitle,
|
|
186
|
+
emptyText,
|
|
187
|
+
testId: getTestId(testId, 'editor')
|
|
188
|
+
}),
|
|
189
|
+
favoritesChooser({
|
|
190
|
+
// Omit if favorites generally disabled, or if none saved yet AND in top/bottom
|
|
191
|
+
// orientation - the empty state looks clumsy in that case. Show when empty in
|
|
192
|
+
// left/right orientation to avoid large jump in popover width.
|
|
193
|
+
omit: !model.persistFavorites || (!model.hasFavorites && favesTB),
|
|
194
|
+
favoritesSide,
|
|
195
|
+
favoritesTitle,
|
|
196
|
+
testId: getTestId(testId, 'favorites')
|
|
197
|
+
})
|
|
198
|
+
],
|
|
199
|
+
itemsContainer = !persistFavorites ? frame : favesTB ? vframe : hframe;
|
|
200
|
+
|
|
201
|
+
if (isFavesFirst) {
|
|
202
|
+
items.reverse();
|
|
203
|
+
}
|
|
204
|
+
|
|
132
205
|
return panel({
|
|
206
|
+
className: 'xh-grouping-chooser-popover__inner',
|
|
133
207
|
width: popoverWidth,
|
|
134
208
|
minHeight: popoverMinHeight,
|
|
135
|
-
items:
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
testId: getTestId(testId, 'editor')
|
|
141
|
-
}),
|
|
142
|
-
favoritesChooser({
|
|
143
|
-
omit: !model.persistFavorites,
|
|
144
|
-
testId: getTestId(testId, 'favorites')
|
|
145
|
-
})
|
|
146
|
-
]
|
|
209
|
+
items: itemsContainer({items}),
|
|
210
|
+
bbar: toolbar({
|
|
211
|
+
compact: true,
|
|
212
|
+
omit: !model.persistFavorites,
|
|
213
|
+
items: [filler(), favoritesAddBtn({testId})]
|
|
147
214
|
})
|
|
148
215
|
});
|
|
149
216
|
}
|
|
150
217
|
});
|
|
151
218
|
|
|
152
219
|
const editor = hoistCmp.factory<GroupingChooserModel>({
|
|
153
|
-
render({
|
|
220
|
+
render({editorTitle, emptyText, testId}) {
|
|
154
221
|
return vbox({
|
|
155
222
|
className: 'xh-grouping-chooser__editor',
|
|
156
223
|
testId,
|
|
157
224
|
items: [
|
|
158
|
-
div({className: 'xh-popup__title', item:
|
|
225
|
+
div({className: 'xh-popup__title', item: editorTitle, omit: isNil(editorTitle)}),
|
|
159
226
|
dimensionList({emptyText}),
|
|
160
227
|
addDimensionControl()
|
|
161
228
|
]
|
|
@@ -330,26 +397,23 @@ function getDimOptions(dims, model) {
|
|
|
330
397
|
// Favorites
|
|
331
398
|
//------------------
|
|
332
399
|
const favoritesChooser = hoistCmp.factory<GroupingChooserModel>({
|
|
333
|
-
render({model, testId}) {
|
|
334
|
-
const {favoritesOptions: options,
|
|
335
|
-
items = isEmpty(options)
|
|
336
|
-
? [menuItem({text: 'No favorites saved.', disabled: true})]
|
|
337
|
-
: options.map(it => favoriteMenuItem(it));
|
|
400
|
+
render({model, favoritesSide, favoritesTitle, testId}) {
|
|
401
|
+
const {favoritesOptions: options, hasFavorites} = model;
|
|
338
402
|
|
|
339
403
|
return vbox({
|
|
340
|
-
className:
|
|
404
|
+
className: `xh-grouping-chooser__favorites xh-grouping-chooser__favorites--${favoritesSide}`,
|
|
341
405
|
testId,
|
|
342
406
|
items: [
|
|
343
|
-
div({
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
407
|
+
div({
|
|
408
|
+
className: 'xh-popup__title',
|
|
409
|
+
item: favoritesTitle,
|
|
410
|
+
omit: isNil(favoritesTitle)
|
|
411
|
+
}),
|
|
412
|
+
hasFavorites
|
|
413
|
+
? menu({
|
|
414
|
+
items: options.map(it => favoriteMenuItem(it))
|
|
415
|
+
})
|
|
416
|
+
: placeholder('No favorites saved.')
|
|
353
417
|
]
|
|
354
418
|
});
|
|
355
419
|
}
|
|
@@ -372,3 +436,19 @@ const favoriteMenuItem = hoistCmp.factory<GroupingChooserModel>({
|
|
|
372
436
|
});
|
|
373
437
|
}
|
|
374
438
|
});
|
|
439
|
+
|
|
440
|
+
const favoritesAddBtn = hoistCmp.factory<GroupingChooserModel>({
|
|
441
|
+
render({model, testId}) {
|
|
442
|
+
return button({
|
|
443
|
+
text: 'Save as Favorite',
|
|
444
|
+
icon: Icon.favorite(),
|
|
445
|
+
className: 'xh-grouping-chooser__favorites__add-btn',
|
|
446
|
+
testId: getTestId(testId, 'favorites-add-btn'),
|
|
447
|
+
omit: !model.persistFavorites,
|
|
448
|
+
disabled: !model.isAddFavoriteEnabled,
|
|
449
|
+
onClick: () => model.addPendingAsFavorite()
|
|
450
|
+
});
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
|
|
454
|
+
const isTB = (favoritesSide: Side) => favoritesSide === 'top' || favoritesSide === 'bottom';
|
|
@@ -84,7 +84,7 @@ export interface PanelProps extends HoistProps<PanelModel>, Omit<BoxProps, 'titl
|
|
|
84
84
|
tbar?: Some<ReactNode>;
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
* A toolbar to be docked at the
|
|
87
|
+
* A toolbar to be docked at the bottom of the panel.
|
|
88
88
|
* If specified as an array, items will be passed as children to a Toolbar component.
|
|
89
89
|
*/
|
|
90
90
|
bbar?: Some<ReactNode>;
|
package/package.json
CHANGED
package/svc/TrackService.ts
CHANGED
|
@@ -132,10 +132,11 @@ export class TrackService extends HoistService {
|
|
|
132
132
|
if (options.logData !== undefined) ret.logData = options.logData;
|
|
133
133
|
if (options.elapsed !== undefined) ret.elapsed = options.elapsed;
|
|
134
134
|
|
|
135
|
-
const {maxDataLength} = this.conf
|
|
136
|
-
|
|
135
|
+
const {maxDataLength} = this.conf,
|
|
136
|
+
dataLength = JSON.stringify(ret.data)?.length ?? 0;
|
|
137
|
+
if (dataLength > maxDataLength) {
|
|
137
138
|
this.logWarn(
|
|
138
|
-
`Track log includes ${
|
|
139
|
+
`Track log includes ${dataLength} chars of JSON data`,
|
|
139
140
|
`exceeds limit of ${maxDataLength}`,
|
|
140
141
|
'data will not be persisted',
|
|
141
142
|
options.data
|