@xh/hoist 80.0.0-SNAPSHOT.1768251400948 → 80.0.0-SNAPSHOT.1768251669499
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 -14
- package/build/types/cmp/grid/GridModel.d.ts +2 -2
- package/build/types/cmp/layout/Tags.d.ts +0 -2
- package/build/types/cmp/tab/TabContainerModel.d.ts +1 -1
- package/build/types/core/XH.d.ts +3 -1
- package/build/types/core/enums/RenderMode.d.ts +1 -1
- package/build/types/desktop/cmp/button/AppMenuButton.d.ts +10 -1
- package/build/types/desktop/cmp/dash/canvas/DashCanvasModel.d.ts +6 -46
- package/build/types/dynamics/desktop.d.ts +0 -1
- package/build/types/dynamics/mobile.d.ts +0 -1
- package/build/types/mobile/cmp/header/AppMenuButton.d.ts +10 -1
- package/build/types/svc/IdentityService.d.ts +4 -2
- package/cmp/grid/GridModel.ts +2 -2
- package/cmp/layout/Tags.ts +0 -2
- package/cmp/tab/TabContainerModel.ts +1 -1
- package/core/XH.ts +9 -4
- package/core/enums/RenderMode.ts +1 -1
- package/desktop/appcontainer/AppContainer.ts +0 -2
- package/desktop/cmp/appbar/AppBar.scss +24 -5
- package/desktop/cmp/button/AppMenuButton.ts +30 -2
- package/desktop/cmp/dash/canvas/DashCanvas.ts +4 -21
- package/desktop/cmp/dash/canvas/DashCanvasModel.ts +24 -140
- package/dynamics/desktop.ts +0 -2
- package/dynamics/mobile.ts +0 -2
- package/mobile/appcontainer/AppContainer.ts +0 -2
- package/mobile/cmp/header/AppBar.scss +11 -0
- package/mobile/cmp/header/AppMenuButton.ts +29 -1
- package/package.json +3 -3
- package/styles/vars.scss +2 -1
- package/svc/IdentityService.ts +14 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/build/types/cmp/layout/CollapsibleSet.d.ts +0 -14
- package/build/types/desktop/cmp/button/CollapsibleSetButton.d.ts +0 -12
- package/build/types/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWell.d.ts +0 -19
- package/build/types/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWellModel.d.ts +0 -11
- package/build/types/mobile/cmp/button/CollapsibleSetButton.d.ts +0 -12
- package/cmp/layout/CollapsibleSet.scss +0 -49
- package/cmp/layout/CollapsibleSet.ts +0 -135
- package/desktop/cmp/button/CollapsibleSetButton.ts +0 -57
- package/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWell.scss +0 -34
- package/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWell.ts +0 -135
- package/desktop/cmp/dash/canvas/widgetwell/DashCanvasWidgetWellModel.ts +0 -65
- package/mobile/cmp/button/CollapsibleSetButton.ts +0 -57
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2026 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {wait} from '@xh/hoist/promise';
|
|
8
7
|
import type {LayoutItem} from 'react-grid-layout';
|
|
9
8
|
import {Persistable, PersistableState, PersistenceProvider, XH} from '@xh/hoist/core';
|
|
10
9
|
import {required} from '@xh/hoist/data';
|
|
@@ -18,7 +17,6 @@ import {createObservableRef} from '@xh/hoist/utils/react';
|
|
|
18
17
|
import {
|
|
19
18
|
defaultsDeep,
|
|
20
19
|
find,
|
|
21
|
-
omit,
|
|
22
20
|
uniqBy,
|
|
23
21
|
times,
|
|
24
22
|
without,
|
|
@@ -43,12 +41,11 @@ export interface DashCanvasConfig extends DashConfig<DashCanvasViewSpec, DashCan
|
|
|
43
41
|
rowHeight?: number;
|
|
44
42
|
|
|
45
43
|
/**
|
|
46
|
-
* Whether views should "compact" vertically
|
|
44
|
+
* Whether views should "compact" vertically or horizontally
|
|
47
45
|
* to condense space. Default `true` defaults to vertical compaction.
|
|
48
|
-
* Use `wrap` with caution. It only works well if all items are 1 row high.
|
|
49
46
|
* See react-grid-layout docs for more information.
|
|
50
|
-
*/
|
|
51
|
-
compact?: boolean | 'vertical' | 'horizontal'
|
|
47
|
+
* */
|
|
48
|
+
compact?: boolean | 'vertical' | 'horizontal';
|
|
52
49
|
|
|
53
50
|
/** Between items [x,y] in pixels. Default `[10, 10]`. */
|
|
54
51
|
margin?: [number, number];
|
|
@@ -63,35 +60,6 @@ export interface DashCanvasConfig extends DashConfig<DashCanvasViewSpec, DashCan
|
|
|
63
60
|
* Whether a grid background should be shown. Default false.
|
|
64
61
|
*/
|
|
65
62
|
showGridBackground?: boolean;
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
* Whether the canvas should accept drag-and-drop of views from outside
|
|
69
|
-
* the canvas. Default false.
|
|
70
|
-
*/
|
|
71
|
-
allowsDrop?: boolean;
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Optional callback to invoke after a view is successfully dropped onto the canvas.
|
|
75
|
-
*/
|
|
76
|
-
onDropDone?: (viewModel: DashCanvasViewModel) => void;
|
|
77
|
-
|
|
78
|
-
/**
|
|
79
|
-
* Optional callback to invoke when an item is dragged over the canvas. This may be used to
|
|
80
|
-
* customize how the size of the dropping placeholder is calculated. The callback should
|
|
81
|
-
* return an object with optional properties indicating the desired width, height (in grid units),
|
|
82
|
-
* and offset (in pixels) of the dropping placeholder. The method's signature is the same as
|
|
83
|
-
* the `onDropDragOver` prop of ReactGridLayout.
|
|
84
|
-
* Returning `false` will prevent the dropping placeholder from being shown, and prevents a drop.
|
|
85
|
-
* Returning `void` will use the default behavior, which is to size the placeholder as per the
|
|
86
|
-
* `dropConfig.defaultItem` specification.
|
|
87
|
-
*/
|
|
88
|
-
onDropDragOver?: (e: DragEvent) => OnDropDragOverResult;
|
|
89
|
-
|
|
90
|
-
/**
|
|
91
|
-
* Whether an overlay with an Add View button should be rendered
|
|
92
|
-
* when the canvas is empty. Default true.
|
|
93
|
-
*/
|
|
94
|
-
showAddViewButtonWhenEmpty?: boolean;
|
|
95
63
|
}
|
|
96
64
|
|
|
97
65
|
export interface DashCanvasItemState {
|
|
@@ -108,16 +76,6 @@ export interface DashCanvasItemLayout {
|
|
|
108
76
|
h: number;
|
|
109
77
|
}
|
|
110
78
|
|
|
111
|
-
export type OnDropDragOverResult =
|
|
112
|
-
| {
|
|
113
|
-
w?: number;
|
|
114
|
-
h?: number;
|
|
115
|
-
dragOffsetX?: number;
|
|
116
|
-
dragOffsetY?: number;
|
|
117
|
-
}
|
|
118
|
-
| false
|
|
119
|
-
| void;
|
|
120
|
-
|
|
121
79
|
/**
|
|
122
80
|
* Model for {@link DashCanvas}, managing all configurable options for the component and publishing
|
|
123
81
|
* the observable state of its current widgets and their layout.
|
|
@@ -131,21 +89,16 @@ export class DashCanvasModel
|
|
|
131
89
|
//------------------------------
|
|
132
90
|
@bindable columns: number;
|
|
133
91
|
@bindable rowHeight: number;
|
|
134
|
-
@bindable compact: 'vertical' | 'horizontal'
|
|
92
|
+
@bindable compact: 'vertical' | 'horizontal';
|
|
135
93
|
@bindable.ref margin: [number, number]; // [x, y]
|
|
136
94
|
@bindable.ref containerPadding: [number, number]; // [x, y]
|
|
137
95
|
@bindable showGridBackground: boolean;
|
|
138
96
|
@bindable rglHeight: number;
|
|
139
|
-
@bindable showAddViewButtonWhenEmpty: boolean;
|
|
140
97
|
|
|
141
98
|
//-----------------------------
|
|
142
99
|
// Public properties
|
|
143
100
|
//-----------------------------
|
|
144
|
-
DROPPING_ELEM_ID = '__dropping-elem__';
|
|
145
101
|
maxRows: number;
|
|
146
|
-
allowsDrop: boolean;
|
|
147
|
-
onDropDone: (viewModel: DashCanvasViewModel) => void;
|
|
148
|
-
draggedInView: DashCanvasItemState;
|
|
149
102
|
|
|
150
103
|
/** Current number of rows in canvas */
|
|
151
104
|
get rows(): number {
|
|
@@ -165,27 +118,21 @@ export class DashCanvasModel
|
|
|
165
118
|
private isLoadingState: boolean;
|
|
166
119
|
|
|
167
120
|
get rglLayout() {
|
|
168
|
-
return this.layout
|
|
169
|
-
.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
minH: viewSpec.minHeight,
|
|
184
|
-
maxW: viewSpec.maxWidth,
|
|
185
|
-
minW: viewSpec.minWidth
|
|
186
|
-
};
|
|
187
|
-
})
|
|
188
|
-
.filter(Boolean);
|
|
121
|
+
return this.layout.map(it => {
|
|
122
|
+
const dashCanvasView = this.getView(it.i),
|
|
123
|
+
{autoHeight, viewSpec} = dashCanvasView;
|
|
124
|
+
|
|
125
|
+
return {
|
|
126
|
+
...it,
|
|
127
|
+
resizeHandles: autoHeight
|
|
128
|
+
? ['w', 'e']
|
|
129
|
+
: ['s', 'w', 'e', 'n', 'sw', 'nw', 'se', 'ne'],
|
|
130
|
+
maxH: viewSpec.maxHeight,
|
|
131
|
+
minH: viewSpec.minHeight,
|
|
132
|
+
maxW: viewSpec.maxWidth,
|
|
133
|
+
minW: viewSpec.minWidth
|
|
134
|
+
};
|
|
135
|
+
});
|
|
189
136
|
}
|
|
190
137
|
|
|
191
138
|
constructor({
|
|
@@ -205,11 +152,7 @@ export class DashCanvasModel
|
|
|
205
152
|
maxRows = Infinity,
|
|
206
153
|
containerPadding = margin,
|
|
207
154
|
extraMenuItems,
|
|
208
|
-
showGridBackground = false
|
|
209
|
-
showAddViewButtonWhenEmpty = true,
|
|
210
|
-
allowsDrop = false,
|
|
211
|
-
onDropDone,
|
|
212
|
-
onDropDragOver
|
|
155
|
+
showGridBackground = false
|
|
213
156
|
}: DashCanvasConfig) {
|
|
214
157
|
super();
|
|
215
158
|
makeObservable(this);
|
|
@@ -257,10 +200,6 @@ export class DashCanvasModel
|
|
|
257
200
|
this.addViewButtonText = addViewButtonText;
|
|
258
201
|
this.extraMenuItems = extraMenuItems;
|
|
259
202
|
this.showGridBackground = showGridBackground;
|
|
260
|
-
this.showAddViewButtonWhenEmpty = showAddViewButtonWhenEmpty;
|
|
261
|
-
this.allowsDrop = allowsDrop;
|
|
262
|
-
this.onDropDone = onDropDone;
|
|
263
|
-
if (onDropDragOver) this.onDropDragOver = onDropDragOver;
|
|
264
203
|
|
|
265
204
|
this.loadState(initialState);
|
|
266
205
|
this.state = this.buildState();
|
|
@@ -398,59 +337,6 @@ export class DashCanvasModel
|
|
|
398
337
|
this.getView(id)?.ensureVisible();
|
|
399
338
|
}
|
|
400
339
|
|
|
401
|
-
onDrop(rglLayout: LayoutItem[], layoutItem: LayoutItem, evt: Event) {
|
|
402
|
-
throwIf(
|
|
403
|
-
!this.draggedInView,
|
|
404
|
-
`No draggedInView set on DashCanvasModel prior to onDrop operation.
|
|
405
|
-
Typically a developer would set this in response to dragstart events from
|
|
406
|
-
a DashViewTray or similar component.`
|
|
407
|
-
);
|
|
408
|
-
|
|
409
|
-
const droppingItem: any = rglLayout.find(it => it.i === this.DROPPING_ELEM_ID);
|
|
410
|
-
if (!droppingItem) {
|
|
411
|
-
// if `onDropDragOver` returned false, we won't have a dropping item
|
|
412
|
-
// and we cancel the drop
|
|
413
|
-
this.draggedInView = null;
|
|
414
|
-
return;
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
const {viewSpecId, title, state} = this.draggedInView,
|
|
418
|
-
layout = omit(layoutItem, 'i'),
|
|
419
|
-
newViewModel: DashCanvasViewModel = this.addViewInternal(viewSpecId, {
|
|
420
|
-
title,
|
|
421
|
-
state,
|
|
422
|
-
layout
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
// Change ID of dropping item to the new view's id
|
|
426
|
-
// so that the new view goes where the dropping item is.
|
|
427
|
-
droppingItem.i = newViewModel.id;
|
|
428
|
-
|
|
429
|
-
// must wait a tick for RGL to settle
|
|
430
|
-
wait().then(() => {
|
|
431
|
-
this.draggedInView = null;
|
|
432
|
-
this.onRglLayoutChange(rglLayout);
|
|
433
|
-
this.onDropDone?.(newViewModel);
|
|
434
|
-
});
|
|
435
|
-
}
|
|
436
|
-
|
|
437
|
-
setDraggedInView(view?: DashCanvasItemState) {
|
|
438
|
-
this.draggedInView = view;
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
onDropDragOver(evt: DragEvent): OnDropDragOverResult {
|
|
442
|
-
if (!this.draggedInView) return false;
|
|
443
|
-
|
|
444
|
-
return {
|
|
445
|
-
w: this.draggedInView.layout.w,
|
|
446
|
-
h: this.draggedInView.layout.h
|
|
447
|
-
};
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
getViewsBySpecId(id) {
|
|
451
|
-
return this.viewModels.filter(it => it.viewSpec.id === id);
|
|
452
|
-
}
|
|
453
|
-
|
|
454
340
|
//------------------------
|
|
455
341
|
// Persistable Interface
|
|
456
342
|
//------------------------
|
|
@@ -527,12 +413,6 @@ export class DashCanvasModel
|
|
|
527
413
|
|
|
528
414
|
onRglLayoutChange(rglLayout: LayoutItem[]) {
|
|
529
415
|
rglLayout = rglLayout.map(it => pick(it, ['i', 'x', 'y', 'w', 'h']));
|
|
530
|
-
|
|
531
|
-
// Early out if RGL is changing layout as user is dragging droppable
|
|
532
|
-
// item around the canvas. This will be called again once dragging
|
|
533
|
-
// has stopped and user has dropped the item onto the canvas.
|
|
534
|
-
if (rglLayout.some(it => it.i === this.DROPPING_ELEM_ID)) return;
|
|
535
|
-
|
|
536
416
|
this.setLayout(rglLayout);
|
|
537
417
|
}
|
|
538
418
|
|
|
@@ -616,6 +496,10 @@ export class DashCanvasModel
|
|
|
616
496
|
return some(this.viewSpecs, {id});
|
|
617
497
|
}
|
|
618
498
|
|
|
499
|
+
private getViewsBySpecId(id) {
|
|
500
|
+
return this.viewModels.filter(it => it.viewSpec.id === id);
|
|
501
|
+
}
|
|
502
|
+
|
|
619
503
|
private getNextAvailablePosition({
|
|
620
504
|
width,
|
|
621
505
|
height,
|
package/dynamics/desktop.ts
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
*
|
|
16
16
|
* See the platform specific AppContainer where these implementations are actually provided.
|
|
17
17
|
*/
|
|
18
|
-
export let collapsibleSetButton = null;
|
|
19
18
|
export let ColChooserModel = null;
|
|
20
19
|
export let ColumnHeaderFilterModel = null;
|
|
21
20
|
export let ModalSupportModel = null;
|
|
@@ -38,7 +37,6 @@ export let DynamicTabSwitcherModel = null;
|
|
|
38
37
|
* Not for Application use.
|
|
39
38
|
*/
|
|
40
39
|
export function installDesktopImpls(impls) {
|
|
41
|
-
collapsibleSetButton = impls.collapsibleSetButton;
|
|
42
40
|
ColChooserModel = impls.ColChooserModel;
|
|
43
41
|
ColumnHeaderFilterModel = impls.ColumnHeaderFilterModel;
|
|
44
42
|
ModalSupportModel = impls.ModalSupportModel;
|
package/dynamics/mobile.ts
CHANGED
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
*
|
|
16
16
|
* See the platform specific AppContainer where these implementations are actually provided.
|
|
17
17
|
*/
|
|
18
|
-
export let collapsibleSetButton = null;
|
|
19
18
|
export let ColChooserModel = null;
|
|
20
19
|
export let colChooser = null;
|
|
21
20
|
export let zoneMapper = null;
|
|
@@ -31,7 +30,6 @@ export let maskImpl = null;
|
|
|
31
30
|
* Not for Application use.
|
|
32
31
|
*/
|
|
33
32
|
export function installMobileImpls(impls) {
|
|
34
|
-
collapsibleSetButton = impls.collapsibleSetButton;
|
|
35
33
|
ColChooserModel = impls.ColChooserModel;
|
|
36
34
|
colChooser = impls.colChooser;
|
|
37
35
|
zoneMapper = impls.zoneMapper;
|
|
@@ -18,7 +18,6 @@ import {pinPadImpl} from '@xh/hoist/mobile/cmp/pinpad/impl/PinPad';
|
|
|
18
18
|
import {storeFilterFieldImpl} from '@xh/hoist/mobile/cmp/store/impl/StoreFilterField';
|
|
19
19
|
import {tabContainerImpl} from '@xh/hoist/mobile/cmp/tab/impl/TabContainer';
|
|
20
20
|
import {zoneMapper} from '@xh/hoist/mobile/cmp/zoneGrid/impl/ZoneMapper';
|
|
21
|
-
import {collapsibleSetButton} from '@xh/hoist/mobile/cmp/button/CollapsibleSetButton';
|
|
22
21
|
import {elementFromContent, useOnMount} from '@xh/hoist/utils/react';
|
|
23
22
|
import {isEmpty} from 'lodash';
|
|
24
23
|
import {aboutDialog} from './AboutDialog';
|
|
@@ -35,7 +34,6 @@ import {toastSource} from './ToastSource';
|
|
|
35
34
|
import {versionBar} from './VersionBar';
|
|
36
35
|
|
|
37
36
|
installMobileImpls({
|
|
38
|
-
collapsibleSetButton,
|
|
39
37
|
tabContainerImpl,
|
|
40
38
|
storeFilterFieldImpl,
|
|
41
39
|
pinPadImpl,
|
|
@@ -18,6 +18,17 @@
|
|
|
18
18
|
display: flex;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
.xh-app-menu-button__user-profile {
|
|
22
|
+
border-radius: 50%;
|
|
23
|
+
border: 1px solid var(--xh-appbar-title-color);
|
|
24
|
+
cursor: pointer;
|
|
25
|
+
height: 28px;
|
|
26
|
+
font-size: var(--xh-font-size-small-em);
|
|
27
|
+
line-height: 27px;
|
|
28
|
+
text-align: center;
|
|
29
|
+
width: 28px;
|
|
30
|
+
}
|
|
31
|
+
|
|
21
32
|
.xh-button {
|
|
22
33
|
background: transparent !important;
|
|
23
34
|
color: var(--xh-appbar-title-color) !important;
|
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2026 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import {div} from '@xh/hoist/cmp/layout';
|
|
8
|
+
import {hoistCmp, HoistProps, HoistUser, MenuItemLike, XH} from '@xh/hoist/core';
|
|
8
9
|
import {Icon} from '@xh/hoist/icon';
|
|
9
10
|
import {menuButton, MenuButtonProps} from '@xh/hoist/mobile/cmp/menu';
|
|
10
11
|
import '@xh/hoist/mobile/register';
|
|
11
12
|
import {withDefault} from '@xh/hoist/utils/js';
|
|
13
|
+
import {isFunction} from 'lodash';
|
|
14
|
+
import {ReactNode} from 'react';
|
|
12
15
|
|
|
13
16
|
export interface AppMenuButtonProps extends MenuButtonProps {
|
|
14
17
|
/** Array of app-specific MenuItems or configs to create them. */
|
|
@@ -37,8 +40,17 @@ export interface AppMenuButtonProps extends MenuButtonProps {
|
|
|
37
40
|
|
|
38
41
|
/** True to hide the About button */
|
|
39
42
|
hideAboutItem?: boolean;
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Replace the default hamburger icon with a user profile representation. Set to true to render
|
|
46
|
+
* the user's initials from their `HoistUser.displayName`. Alternately, provide a custom
|
|
47
|
+
* function to render an alternate compact string or element for the current user.
|
|
48
|
+
*/
|
|
49
|
+
renderWithUserProfile?: boolean | RenderWithUserProfileCustomFn;
|
|
40
50
|
}
|
|
41
51
|
|
|
52
|
+
type RenderWithUserProfileCustomFn = (user: HoistUser) => ReactNode;
|
|
53
|
+
|
|
42
54
|
/**
|
|
43
55
|
* A top-level application drop down menu, which installs a standard set of menu items for common
|
|
44
56
|
* application actions. Application specific items can be displayed before these standard items.
|
|
@@ -62,11 +74,13 @@ export const [AppMenuButton, appMenuButton] = hoistCmp.withFactory<AppMenuButton
|
|
|
62
74
|
hideOptionsItem,
|
|
63
75
|
hideThemeItem,
|
|
64
76
|
hideAboutItem,
|
|
77
|
+
renderWithUserProfile,
|
|
65
78
|
...rest
|
|
66
79
|
} = props;
|
|
67
80
|
|
|
68
81
|
return menuButton({
|
|
69
82
|
className,
|
|
83
|
+
icon: renderWithUserProfile ? userProfile({renderWithUserProfile}) : Icon.menu(),
|
|
70
84
|
menuItems: buildMenuItems(props),
|
|
71
85
|
menuClassName: 'xh-app-menu',
|
|
72
86
|
popoverProps: {popoverClassName: 'xh-app-menu-popover'},
|
|
@@ -78,6 +92,20 @@ export const [AppMenuButton, appMenuButton] = hoistCmp.withFactory<AppMenuButton
|
|
|
78
92
|
//---------------------------
|
|
79
93
|
// Implementation
|
|
80
94
|
//---------------------------
|
|
95
|
+
const userProfile = hoistCmp.factory<
|
|
96
|
+
HoistProps & {renderWithUserProfile: true | RenderWithUserProfileCustomFn}
|
|
97
|
+
>({
|
|
98
|
+
model: false,
|
|
99
|
+
render({renderWithUserProfile}) {
|
|
100
|
+
return div({
|
|
101
|
+
className: 'xh-app-menu-button__user-profile',
|
|
102
|
+
item: isFunction(renderWithUserProfile)
|
|
103
|
+
? renderWithUserProfile(XH.getUser())
|
|
104
|
+
: XH.getUserInitials()
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
81
109
|
function buildMenuItems({
|
|
82
110
|
hideOptionsItem,
|
|
83
111
|
hideFeedbackItem,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "80.0.0-SNAPSHOT.
|
|
3
|
+
"version": "80.0.0-SNAPSHOT.1768251669499",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|
|
@@ -62,11 +62,11 @@
|
|
|
62
62
|
"moment": "~2.30.1",
|
|
63
63
|
"numbro": "~2.5.0",
|
|
64
64
|
"onsenui": "~2.12.8",
|
|
65
|
-
"qs": "~6.14.
|
|
65
|
+
"qs": "~6.14.0",
|
|
66
66
|
"react-beautiful-dnd": "~13.1.0",
|
|
67
67
|
"react-dates": "~21.8.0",
|
|
68
68
|
"react-dropzone": "~10.2.2",
|
|
69
|
-
"react-grid-layout": "2.
|
|
69
|
+
"react-grid-layout": "2.1.1",
|
|
70
70
|
"react-markdown": "~10.1.0",
|
|
71
71
|
"react-onsenui": "~1.13.2",
|
|
72
72
|
"react-popper": "~2.3.0",
|
package/styles/vars.scss
CHANGED
|
@@ -205,13 +205,14 @@ body {
|
|
|
205
205
|
//---------
|
|
206
206
|
--xh-appbar-bg: var(--appbar-bg, var(--xh-bg-alt));
|
|
207
207
|
--xh-appbar-border-color: var(--appbar-border-color, transparent);
|
|
208
|
+
--xh-appbar-box-shadow: var(--appbar-box-shadow, #{0 0 0 1px rgb(17 20 24 / 10%), 0 1px 1px rgb(17 20 24 / 20%)});
|
|
208
209
|
--xh-appbar-color: var(--appbar-color, var(--xh-text-color));
|
|
209
210
|
--xh-appbar-height: var(--appbar-height, 42);
|
|
210
211
|
--xh-appbar-height-px: calc(var(--xh-appbar-height) * 1px);
|
|
211
212
|
--xh-appbar-title-color: var(--appbar-title-color, #{mc('blue-grey', '700')});
|
|
212
213
|
--xh-appbar-title-font-size: var(--appbar-title-font-size, calc(var(--xh-font-size) * 1.9));
|
|
213
214
|
--xh-appbar-title-font-size-px: calc(var(--xh-appbar-title-font-size) * 1px);
|
|
214
|
-
--xh-appbar-
|
|
215
|
+
--xh-appbar-user-profile-hover-color: var(--appbar-user-profile-hover-color, var(--xh-orange));
|
|
215
216
|
|
|
216
217
|
&.xh-dark {
|
|
217
218
|
--xh-appbar-border-color: var(--appbar-border-color, #{mc('blue-grey', '700')});
|
package/svc/IdentityService.ts
CHANGED
|
@@ -30,16 +30,28 @@ export class IdentityService extends HoistService {
|
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
/**
|
|
33
|
+
/** @returns current acting user (see authUser for notes on impersonation) */
|
|
34
34
|
get user(): HoistUser {
|
|
35
35
|
return this._apparentUser;
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
/**
|
|
38
|
+
/** @returns current acting user's username. */
|
|
39
39
|
get username(): string {
|
|
40
40
|
return this.user?.username ?? null;
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
+
/** @returns current acting user's initials, based on displayName. */
|
|
44
|
+
get userInitials(): string {
|
|
45
|
+
// Handle common case of displayName being left as an email address.
|
|
46
|
+
const [displayName] = this.user.displayName.split('@'),
|
|
47
|
+
nameParts = displayName.split(/[\s.]+/);
|
|
48
|
+
|
|
49
|
+
return nameParts
|
|
50
|
+
.map(part => part.charAt(0).toUpperCase())
|
|
51
|
+
.join('')
|
|
52
|
+
.substring(0, XH.isMobileApp ? 2 : 3);
|
|
53
|
+
}
|
|
54
|
+
|
|
43
55
|
/**
|
|
44
56
|
* Actual user who authenticated to the web application.
|
|
45
57
|
* This will be the same as the user except when an administrator is impersonation another
|