@xh/hoist 71.0.0-SNAPSHOT.1735047359409 → 71.0.0-SNAPSHOT.1735061320692

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 (83) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/admin/tabs/activity/tracking/ActivityTrackingPanel.ts +1 -1
  3. package/admin/tabs/cluster/ClusterTab.ts +1 -1
  4. package/admin/tabs/cluster/connpool/ConnPoolMonitorPanel.ts +1 -1
  5. package/admin/tabs/cluster/environment/ServerEnvPanel.ts +1 -1
  6. package/admin/tabs/cluster/logs/LogDisplay.ts +1 -1
  7. package/admin/tabs/cluster/logs/LogViewer.ts +1 -1
  8. package/admin/tabs/cluster/memory/MemoryMonitorPanel.ts +1 -1
  9. package/admin/tabs/cluster/services/DetailsPanel.ts +1 -1
  10. package/admin/tabs/cluster/websocket/WebSocketPanel.ts +1 -1
  11. package/admin/tabs/monitor/MonitorTab.ts +1 -1
  12. package/admin/tabs/userData/roles/RolePanel.ts +1 -1
  13. package/build/types/{desktop/cmp → cmp}/error/ErrorMessage.d.ts +4 -4
  14. package/build/types/cmp/error/index.d.ts +1 -0
  15. package/build/types/{desktop/cmp → cmp}/loadingindicator/LoadingIndicator.d.ts +0 -1
  16. package/build/types/{desktop/cmp → cmp}/mask/Mask.d.ts +1 -3
  17. package/build/types/{desktop/cmp → cmp}/treemap/SplitTreeMap.d.ts +0 -1
  18. package/build/types/{desktop/cmp → cmp}/treemap/SplitTreeMapModel.d.ts +0 -1
  19. package/build/types/{desktop/cmp → cmp}/treemap/TreeMap.d.ts +0 -1
  20. package/build/types/{desktop/cmp → cmp}/treemap/TreeMapModel.d.ts +0 -1
  21. package/build/types/desktop/cmp/error/impl/ErrorMessage.d.ts +7 -0
  22. package/build/types/desktop/cmp/mask/impl/Mask.d.ts +8 -0
  23. package/build/types/dynamics/desktop.d.ts +2 -1
  24. package/build/types/dynamics/mobile.d.ts +2 -1
  25. package/build/types/mobile/cmp/error/impl/ErrorMessage.d.ts +7 -0
  26. package/build/types/mobile/cmp/mask/impl/Mask.d.ts +8 -0
  27. package/build/types/security/authzero/AuthZeroClient.d.ts +16 -5
  28. package/cmp/error/ErrorBoundary.ts +2 -4
  29. package/{desktop/cmp → cmp}/error/ErrorMessage.scss +8 -1
  30. package/{desktop/cmp → cmp}/error/ErrorMessage.ts +24 -50
  31. package/cmp/error/index.ts +1 -0
  32. package/{desktop/cmp → cmp}/loadingindicator/LoadingIndicator.scss +4 -1
  33. package/{desktop/cmp → cmp}/loadingindicator/LoadingIndicator.ts +5 -9
  34. package/{desktop/cmp → cmp}/mask/Mask.ts +16 -25
  35. package/{desktop/cmp → cmp}/treemap/SplitTreeMap.scss +16 -0
  36. package/{desktop/cmp → cmp}/treemap/SplitTreeMap.ts +14 -6
  37. package/{desktop/cmp → cmp}/treemap/SplitTreeMapModel.ts +0 -1
  38. package/{desktop/cmp → cmp}/treemap/TreeMap.ts +2 -3
  39. package/{desktop/cmp → cmp}/treemap/TreeMapModel.ts +0 -1
  40. package/desktop/appcontainer/AppContainer.ts +5 -3
  41. package/desktop/cmp/dash/container/DashContainer.ts +1 -1
  42. package/desktop/cmp/error/impl/ErrorMessage.ts +65 -0
  43. package/desktop/cmp/mask/impl/Mask.ts +40 -0
  44. package/desktop/cmp/panel/Panel.ts +2 -2
  45. package/desktop/cmp/rest/RestGrid.ts +1 -1
  46. package/dynamics/desktop.ts +4 -2
  47. package/dynamics/mobile.ts +4 -2
  48. package/mobile/appcontainer/AppContainer.ts +5 -3
  49. package/mobile/appcontainer/OptionsDialog.ts +1 -1
  50. package/mobile/cmp/error/impl/ErrorMessage.ts +65 -0
  51. package/mobile/cmp/mask/impl/Mask.ts +34 -0
  52. package/mobile/cmp/panel/Panel.ts +2 -2
  53. package/package.json +1 -1
  54. package/security/authzero/AuthZeroClient.ts +38 -21
  55. package/tsconfig.tsbuildinfo +1 -1
  56. package/build/types/desktop/cmp/error/index.d.ts +0 -1
  57. package/build/types/desktop/cmp/treemap/impl/Splitter.d.ts +0 -6
  58. package/build/types/mobile/cmp/error/ErrorMessage.d.ts +0 -42
  59. package/build/types/mobile/cmp/error/index.d.ts +0 -1
  60. package/build/types/mobile/cmp/loadingindicator/LoadingIndicator.d.ts +0 -27
  61. package/build/types/mobile/cmp/loadingindicator/index.d.ts +0 -1
  62. package/build/types/mobile/cmp/mask/Mask.d.ts +0 -25
  63. package/build/types/mobile/cmp/mask/index.d.ts +0 -1
  64. package/desktop/cmp/error/index.ts +0 -1
  65. package/desktop/cmp/treemap/impl/Splitter.scss +0 -15
  66. package/desktop/cmp/treemap/impl/Splitter.ts +0 -28
  67. package/mobile/cmp/error/ErrorMessage.scss +0 -25
  68. package/mobile/cmp/error/ErrorMessage.ts +0 -140
  69. package/mobile/cmp/error/index.ts +0 -8
  70. package/mobile/cmp/loadingindicator/LoadingIndicator.scss +0 -81
  71. package/mobile/cmp/loadingindicator/LoadingIndicator.ts +0 -90
  72. package/mobile/cmp/loadingindicator/index.ts +0 -7
  73. package/mobile/cmp/mask/Mask.ts +0 -75
  74. package/mobile/cmp/mask/index.ts +0 -7
  75. /package/build/types/{desktop/cmp → cmp}/loadingindicator/index.d.ts +0 -0
  76. /package/build/types/{desktop/cmp → cmp}/mask/index.d.ts +0 -0
  77. /package/build/types/{desktop/cmp → cmp}/treemap/index.d.ts +0 -0
  78. /package/{desktop/cmp → cmp}/loadingindicator/index.ts +0 -0
  79. /package/{desktop/cmp → cmp}/mask/index.ts +0 -0
  80. /package/{desktop/cmp → cmp}/treemap/TreeMap.scss +0 -0
  81. /package/{desktop/cmp → cmp}/treemap/index.ts +0 -0
  82. /package/desktop/cmp/mask/{Mask.scss → impl/Mask.scss} +0 -0
  83. /package/mobile/cmp/mask/{Mask.scss → impl/Mask.scss} +0 -0
@@ -7,13 +7,10 @@
7
7
  import {AgGrid} from '@xh/hoist/cmp/ag-grid';
8
8
  import {box, div, fragment, hbox, hframe, p, placeholder, vbox, vframe} from '@xh/hoist/cmp/layout';
9
9
  import {BoxProps, hoistCmp, HoistProps, uses, XH} from '@xh/hoist/core';
10
- import {errorMessage} from '@xh/hoist/desktop/cmp/error';
11
- import {mask} from '@xh/hoist/desktop/cmp/mask';
12
- import '@xh/hoist/desktop/register';
10
+ import {errorMessage} from '@xh/hoist/cmp/error';
11
+ import {mask} from '@xh/hoist/cmp/mask';
13
12
  import classNames from 'classnames';
14
13
  import {compact, uniq} from 'lodash';
15
- import {splitter} from './impl/Splitter';
16
-
17
14
  import './SplitTreeMap.scss';
18
15
  import {SplitTreeMapModel} from './SplitTreeMapModel';
19
16
  import {treeMap} from './TreeMap';
@@ -110,7 +107,8 @@ const mapTitle = hoistCmp.factory<SplitTreeMapModel>(({model, isPrimary}) => {
110
107
 
111
108
  const container = titleOrientation === 'horizontal' ? hbox : vbox,
112
109
  dim = titleOrientation === 'horizontal' ? 'height' : 'width',
113
- size = (AgGrid as any).getHeaderHeightForSizingMode(XH.sizingMode);
110
+ sizingMode = XH.isMobileApp ? 'tiny' : XH.sizingMode,
111
+ size = (AgGrid as any).getHeaderHeightForSizingMode(sizingMode);
114
112
 
115
113
  return container({
116
114
  style: {[dim]: `${size}px`},
@@ -125,6 +123,16 @@ const mapTitle = hoistCmp.factory<SplitTreeMapModel>(({model, isPrimary}) => {
125
123
  });
126
124
  });
127
125
 
126
+ const splitter = hoistCmp.factory<SplitTreeMapModel>(({model}) => {
127
+ const {orientation} = model,
128
+ vertical = orientation === 'vertical',
129
+ cmp = vertical ? hbox : vbox;
130
+
131
+ return cmp({
132
+ className: `xh-split-treemap__splitter xh-split-treemap__splitter--${vertical ? 'vertical' : 'horizontal'}`
133
+ });
134
+ });
135
+
128
136
  const errorPanel = hoistCmp.factory(({errors}) =>
129
137
  errorMessage({error: errors.join(' '), message: fragment(errors.map(e => p(e)))})
130
138
  );
@@ -5,7 +5,6 @@
5
5
  * Copyright © 2024 Extremely Heavy Industries Inc.
6
6
  */
7
7
  import {HoistModel, managed, PlainObject, Theme} from '@xh/hoist/core';
8
- import '@xh/hoist/desktop/register';
9
8
  import {action, observable, computed, makeObservable} from '@xh/hoist/mobx';
10
9
  import {throwIf, withDefault} from '@xh/hoist/utils/js';
11
10
  import {StoreRecord, StoreRecordId} from '@xh/hoist/data';
@@ -17,9 +17,8 @@ import {
17
17
  uses,
18
18
  XH
19
19
  } from '@xh/hoist/core';
20
- import {errorMessage} from '@xh/hoist/desktop/cmp/error';
21
- import {mask} from '@xh/hoist/desktop/cmp/mask';
22
- import '@xh/hoist/desktop/register';
20
+ import {errorMessage} from '@xh/hoist/cmp/error';
21
+ import {mask} from '@xh/hoist/cmp/mask';
23
22
  import {Highcharts} from '@xh/hoist/kit/highcharts';
24
23
  import {wait} from '@xh/hoist/promise';
25
24
  import {logError, logWithDebug} from '@xh/hoist/utils/js';
@@ -8,7 +8,6 @@ import {HoistModel, PlainObject, Theme} from '@xh/hoist/core';
8
8
  import {Store, StoreRecord, StoreRecordId} from '@xh/hoist/data';
9
9
  import {GridModel} from '@xh/hoist/cmp/grid';
10
10
  import {FilterLike} from '@xh/hoist/data/filter/Types';
11
- import '@xh/hoist/desktop/register';
12
11
  import {numberRenderer} from '@xh/hoist/format';
13
12
  import {action, bindable, computed, makeObservable, observable} from '@xh/hoist/mobx';
14
13
  import {throwIf, withDefault} from '@xh/hoist/utils/js';
@@ -17,7 +17,7 @@ import {zoneMapperDialog as zoneMapper} from '@xh/hoist/desktop/cmp/zoneGrid/imp
17
17
  import {columnHeaderFilter} from '@xh/hoist/desktop/cmp/grid/impl/filter/ColumnHeaderFilter';
18
18
  import {ColumnHeaderFilterModel} from '@xh/hoist/desktop/cmp/grid/impl/filter/ColumnHeaderFilterModel';
19
19
  import {gridFilterDialog} from '@xh/hoist/desktop/cmp/grid/impl/filter/GridFilterDialog';
20
- import {mask} from '@xh/hoist/desktop/cmp/mask';
20
+ import {mask} from '@xh/hoist/cmp/mask';
21
21
  import {ModalSupportModel} from '@xh/hoist/desktop/cmp/modalsupport';
22
22
  import {pinPadImpl} from '@xh/hoist/desktop/cmp/pinpad/impl/PinPad';
23
23
  import {storeFilterFieldImpl} from '@xh/hoist/desktop/cmp/store/impl/StoreFilterField';
@@ -26,6 +26,8 @@ import {useContextMenu, useHotkeys} from '@xh/hoist/desktop/hooks';
26
26
  import {installDesktopImpls} from '@xh/hoist/dynamics/desktop';
27
27
  import {inspectorPanel} from '@xh/hoist/inspector/InspectorPanel';
28
28
  import {blueprintProvider} from '@xh/hoist/kit/blueprint';
29
+ import {errorMessageImpl} from '@xh/hoist/desktop/cmp/error/impl/ErrorMessage';
30
+ import {maskImpl} from '@xh/hoist/desktop/cmp/mask/impl/Mask';
29
31
  import {elementFromContent, useOnMount} from '@xh/hoist/utils/react';
30
32
  import {isEmpty} from 'lodash';
31
33
  import {aboutDialog} from './AboutDialog';
@@ -41,7 +43,6 @@ import {optionsDialog} from './OptionsDialog';
41
43
  import {toastSource} from './ToastSource';
42
44
  import {versionBar} from './VersionBar';
43
45
  import {ReactElement} from 'react';
44
- import {errorMessage} from '../cmp/error/ErrorMessage';
45
46
 
46
47
  installDesktopImpls({
47
48
  tabContainerImpl,
@@ -56,7 +57,8 @@ installDesktopImpls({
56
57
  ColumnHeaderFilterModel,
57
58
  useContextMenu,
58
59
  ModalSupportModel,
59
- errorMessage
60
+ errorMessageImpl,
61
+ maskImpl
60
62
  });
61
63
  /**
62
64
  * Top-level wrapper for Desktop applications.
@@ -14,7 +14,7 @@ import {
14
14
  TestSupportProps,
15
15
  uses
16
16
  } from '@xh/hoist/core';
17
- import {mask} from '@xh/hoist/desktop/cmp/mask';
17
+ import {mask} from '@xh/hoist/cmp/mask';
18
18
  import {Classes, overlay} from '@xh/hoist/kit/blueprint';
19
19
  import {useOnMount, useOnResize} from '@xh/hoist/utils/react';
20
20
  import {useContext} from 'react';
@@ -0,0 +1,65 @@
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
+ import {hoistCmp} from '@xh/hoist/core';
8
+ import {div, filler, hbox, p} from '@xh/hoist/cmp/layout';
9
+ import {ErrorMessageProps} from '@xh/hoist/cmp/error';
10
+ import {button, ButtonProps} from '@xh/hoist/desktop/cmp/button';
11
+ import {Icon} from '@xh/hoist/icon';
12
+ import {isString} from 'lodash';
13
+ import {isValidElement} from 'react';
14
+ import '@xh/hoist/desktop/register';
15
+
16
+ /**
17
+ * Desktop implementation of ErrorMessage.
18
+ * @internal
19
+ */
20
+ export const errorMessageImpl = hoistCmp.factory<ErrorMessageProps>({
21
+ render({error, message, title, actionButtonProps, detailsButtonProps}) {
22
+ let buttons = [],
23
+ buttonBar = null;
24
+ if (detailsButtonProps) buttons.push(detailsButton(detailsButtonProps as ButtonProps));
25
+ if (actionButtonProps) buttons.push(actionButton(actionButtonProps as ButtonProps));
26
+ if (buttons.length == 1) {
27
+ buttonBar = buttons[0];
28
+ } else if (buttons.length == 2) {
29
+ buttonBar = hbox(buttons[0], filler(), buttons[1]);
30
+ }
31
+
32
+ return div({
33
+ className: 'xh-error-message__inner',
34
+ items: [titleCmp({title}), messageCmp({message, error}), buttonBar]
35
+ });
36
+ }
37
+ });
38
+
39
+ const titleCmp = hoistCmp.factory(({title}) => {
40
+ if (isValidElement(title)) return title;
41
+ if (isString(title)) return div({className: 'xh-error-message__title', item: title});
42
+ return null;
43
+ });
44
+
45
+ const messageCmp = hoistCmp.factory(({message}) => {
46
+ if (isValidElement(message)) return message;
47
+ if (isString(message)) return p(message);
48
+ return null;
49
+ });
50
+
51
+ const actionButton = hoistCmp.factory<ButtonProps>(props => {
52
+ return button({
53
+ text: 'Retry',
54
+ icon: Icon.refresh(),
55
+ ...props
56
+ });
57
+ });
58
+
59
+ const detailsButton = hoistCmp.factory<ButtonProps>(props => {
60
+ return button({
61
+ text: 'Details',
62
+ icon: Icon.detail(),
63
+ ...props
64
+ });
65
+ });
@@ -0,0 +1,40 @@
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
+ import {hoistCmp} from '@xh/hoist/core';
8
+ import {box, vbox, vspacer} from '@xh/hoist/cmp/layout';
9
+ import {MaskProps} from '@xh/hoist/cmp/mask';
10
+ import {spinner as spinnerCmp} from '@xh/hoist/cmp/spinner';
11
+ import {Classes, overlay} from '@xh/hoist/kit/blueprint';
12
+ import classNames from 'classnames';
13
+ import '@xh/hoist/desktop/register';
14
+ import './Mask.scss';
15
+
16
+ /**
17
+ * Desktop implementation of Mask.
18
+ * @internal
19
+ */
20
+ export const maskImpl = hoistCmp.factory<MaskProps>({
21
+ render({message, onClick, inline = true, spinner = false, className}) {
22
+ return overlay({
23
+ className: classNames(className, Classes.OVERLAY_SCROLL_CONTAINER),
24
+ autoFocus: false,
25
+ isOpen: true,
26
+ canEscapeKeyClose: false,
27
+ usePortal: !inline,
28
+ enforceFocus: !inline,
29
+ item: vbox({
30
+ onClick,
31
+ className: 'xh-mask-body',
32
+ items: [
33
+ spinner ? spinnerCmp() : null,
34
+ spinner ? vspacer(10) : null,
35
+ message ? box({className: 'xh-mask-text', item: message}) : null
36
+ ]
37
+ })
38
+ });
39
+ }
40
+ });
@@ -17,8 +17,8 @@ import {
17
17
  useContextModel,
18
18
  uses
19
19
  } from '@xh/hoist/core';
20
- import {loadingIndicator} from '@xh/hoist/desktop/cmp/loadingindicator';
21
- import {mask} from '@xh/hoist/desktop/cmp/mask';
20
+ import {loadingIndicator} from '@xh/hoist/cmp/loadingindicator';
21
+ import {mask} from '@xh/hoist/cmp/mask';
22
22
  import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
23
23
  import {useContextMenu, useHotkeys} from '@xh/hoist/desktop/hooks';
24
24
  import '@xh/hoist/desktop/register';
@@ -8,7 +8,7 @@
8
8
  import {grid} from '@xh/hoist/cmp/grid';
9
9
  import {fragment} from '@xh/hoist/cmp/layout';
10
10
  import {hoistCmp, HoistProps, PlainObject, Some, uses} from '@xh/hoist/core';
11
- import {MaskProps} from '@xh/hoist/desktop/cmp/mask';
11
+ import {MaskProps} from '@xh/hoist/cmp/mask';
12
12
  import {panel, PanelProps} from '@xh/hoist/desktop/cmp/panel';
13
13
  import '@xh/hoist/desktop/register';
14
14
  import {getTestId} from '@xh/hoist/utils/js';
@@ -22,12 +22,13 @@ export let colChooser = null;
22
22
  export let zoneMapper = null;
23
23
  export let columnHeaderFilter = null;
24
24
  export let dockContainerImpl = null;
25
- export let errorMessage = null;
26
25
  export let gridFilterDialog = null;
27
26
  export let pinPadImpl = null;
28
27
  export let storeFilterFieldImpl = null;
29
28
  export let tabContainerImpl = null;
30
29
  export let useContextMenu = null;
30
+ export let errorMessageImpl = null;
31
+ export let maskImpl = null;
31
32
 
32
33
  /**
33
34
  * Provide implementations of functions and classes exported in this file.
@@ -42,10 +43,11 @@ export function installDesktopImpls(impls) {
42
43
  zoneMapper = impls.zoneMapper;
43
44
  columnHeaderFilter = impls.columnHeaderFilter;
44
45
  dockContainerImpl = impls.dockContainerImpl;
45
- errorMessage = impls.errorMessage;
46
46
  gridFilterDialog = impls.gridFilterDialog;
47
47
  pinPadImpl = impls.pinPadImpl;
48
48
  storeFilterFieldImpl = impls.storeFilterFieldImpl;
49
49
  tabContainerImpl = impls.tabContainerImpl;
50
50
  useContextMenu = impls.useContextMenu;
51
+ errorMessageImpl = impls.errorMessageImpl;
52
+ maskImpl = impls.maskImpl;
51
53
  }
@@ -18,10 +18,11 @@
18
18
  export let ColChooserModel = null;
19
19
  export let colChooser = null;
20
20
  export let zoneMapper = null;
21
- export let errorMessage = null;
22
21
  export let pinPadImpl = null;
23
22
  export let storeFilterFieldImpl = null;
24
23
  export let tabContainerImpl = null;
24
+ export let errorMessageImpl = null;
25
+ export let maskImpl = null;
25
26
 
26
27
  /**
27
28
  * Provide implementations of functions and classes exported in this file.
@@ -32,8 +33,9 @@ export function installMobileImpls(impls) {
32
33
  ColChooserModel = impls.ColChooserModel;
33
34
  colChooser = impls.colChooser;
34
35
  zoneMapper = impls.zoneMapper;
35
- errorMessage = impls.errorMessage;
36
36
  pinPadImpl = impls.pinPadImpl;
37
37
  storeFilterFieldImpl = impls.storeFilterFieldImpl;
38
38
  tabContainerImpl = impls.tabContainerImpl;
39
+ errorMessageImpl = impls.errorMessageImpl;
40
+ maskImpl = impls.maskImpl;
39
41
  }
@@ -8,17 +8,18 @@ import {AppContainerModel} from '@xh/hoist/appcontainer/AppContainerModel';
8
8
  import {errorBoundary} from '@xh/hoist/cmp/error/ErrorBoundary';
9
9
  import {fragment, frame, vframe, viewport} from '@xh/hoist/cmp/layout';
10
10
  import {createElement, hoistCmp, refreshContextView, uses, XH} from '@xh/hoist/core';
11
+ import {errorMessageImpl} from '@xh/hoist/mobile/cmp/error/impl/ErrorMessage';
12
+ import {maskImpl} from '@xh/hoist/mobile/cmp/mask/impl/Mask';
11
13
  import {installMobileImpls} from '@xh/hoist/dynamics/mobile';
12
14
  import {colChooser} from '@xh/hoist/mobile/cmp/grid/impl/ColChooser';
13
15
  import {ColChooserModel} from '@xh/hoist/mobile/cmp/grid/impl/ColChooserModel';
14
- import {mask} from '@xh/hoist/mobile/cmp/mask';
16
+ import {mask} from '@xh/hoist/cmp/mask';
15
17
  import {pinPadImpl} from '@xh/hoist/mobile/cmp/pinpad/impl/PinPad';
16
18
  import {storeFilterFieldImpl} from '@xh/hoist/mobile/cmp/store/impl/StoreFilterField';
17
19
  import {tabContainerImpl} from '@xh/hoist/mobile/cmp/tab/impl/TabContainer';
18
20
  import {zoneMapper} from '@xh/hoist/mobile/cmp/zoneGrid/impl/ZoneMapper';
19
21
  import {elementFromContent, useOnMount} from '@xh/hoist/utils/react';
20
22
  import {isEmpty} from 'lodash';
21
- import {errorMessage} from '../cmp/error/ErrorMessage';
22
23
  import {aboutDialog} from './AboutDialog';
23
24
  import {banner} from './Banner';
24
25
  import {exceptionDialog} from './ExceptionDialog';
@@ -40,7 +41,8 @@ installMobileImpls({
40
41
  colChooser,
41
42
  ColChooserModel,
42
43
  zoneMapper,
43
- errorMessage
44
+ errorMessageImpl,
45
+ maskImpl
44
46
  });
45
47
 
46
48
  /**
@@ -11,7 +11,7 @@ import {hoistCmp, uses, XH} from '@xh/hoist/core';
11
11
  import {Icon} from '@xh/hoist/icon';
12
12
  import {button, restoreDefaultsButton} from '@xh/hoist/mobile/cmp/button';
13
13
  import {formField} from '@xh/hoist/mobile/cmp/form';
14
- import {mask} from '@xh/hoist/mobile/cmp/mask';
14
+ import {mask} from '@xh/hoist/cmp/mask';
15
15
  import './OptionsDialog.scss';
16
16
  import {dialogPanel} from '@xh/hoist/mobile/cmp/panel';
17
17
 
@@ -0,0 +1,65 @@
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
+ import {hoistCmp} from '@xh/hoist/core';
8
+ import {div, filler, hbox, p} from '@xh/hoist/cmp/layout';
9
+ import {ErrorMessageProps} from '@xh/hoist/cmp/error';
10
+ import {button, ButtonProps} from '@xh/hoist/mobile/cmp/button';
11
+ import {Icon} from '@xh/hoist/icon';
12
+ import {isString} from 'lodash';
13
+ import {isValidElement} from 'react';
14
+ import '@xh/hoist/mobile/register';
15
+
16
+ /**
17
+ * Mobile implementation of ErrorMessage.
18
+ * @internal
19
+ */
20
+ export const errorMessageImpl = hoistCmp.factory<ErrorMessageProps>({
21
+ render({error, message, title, actionButtonProps, detailsButtonProps}) {
22
+ let buttons = [],
23
+ buttonBar = null;
24
+ if (detailsButtonProps) buttons.push(detailsButton(detailsButtonProps as ButtonProps));
25
+ if (actionButtonProps) buttons.push(actionButton(actionButtonProps as ButtonProps));
26
+ if (buttons.length == 1) {
27
+ buttonBar = buttons[0];
28
+ } else if (buttons.length == 2) {
29
+ buttonBar = hbox(buttons[0], filler(), buttons[1]);
30
+ }
31
+
32
+ return div({
33
+ className: 'xh-error-message__inner',
34
+ items: [titleCmp({title}), messageCmp({message, error}), buttonBar]
35
+ });
36
+ }
37
+ });
38
+
39
+ const titleCmp = hoistCmp.factory(({title}) => {
40
+ if (isValidElement(title)) return title;
41
+ if (isString(title)) return div({className: 'xh-error-message__title', item: title});
42
+ return null;
43
+ });
44
+
45
+ const messageCmp = hoistCmp.factory(({message}) => {
46
+ if (isValidElement(message)) return message;
47
+ if (isString(message)) return p(message);
48
+ return null;
49
+ });
50
+
51
+ const actionButton = hoistCmp.factory<ButtonProps>(props => {
52
+ return button({
53
+ text: 'Retry',
54
+ icon: Icon.refresh(),
55
+ ...props
56
+ });
57
+ });
58
+
59
+ const detailsButton = hoistCmp.factory<ButtonProps>(props => {
60
+ return button({
61
+ text: 'Show Details',
62
+ icon: Icon.detail(),
63
+ ...props
64
+ });
65
+ });
@@ -0,0 +1,34 @@
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
+ import {hoistCmp} from '@xh/hoist/core';
8
+ import {box, div, vbox, vspacer} from '@xh/hoist/cmp/layout';
9
+ import {MaskProps} from '@xh/hoist/cmp/mask';
10
+ import {spinner as spinnerCmp} from '@xh/hoist/cmp/spinner';
11
+ import '@xh/hoist/mobile/register';
12
+ import './Mask.scss';
13
+
14
+ /**
15
+ * Mobile implementation of Mask.
16
+ * @internal
17
+ */
18
+ export const maskImpl = hoistCmp.factory<MaskProps>({
19
+ render({message, onClick, spinner = false, className}, ref) {
20
+ return div({
21
+ ref,
22
+ onClick,
23
+ className,
24
+ item: vbox({
25
+ className: 'xh-mask-body',
26
+ items: [
27
+ spinner ? spinnerCmp() : null,
28
+ spinner ? vspacer(10) : null,
29
+ message ? box({className: 'xh-mask-text', item: message}) : null
30
+ ]
31
+ })
32
+ });
33
+ }
34
+ });
@@ -15,8 +15,8 @@ import {
15
15
  hoistCmp,
16
16
  HoistModel
17
17
  } from '@xh/hoist/core';
18
- import {loadingIndicator} from '@xh/hoist/mobile/cmp/loadingindicator';
19
- import {mask} from '@xh/hoist/mobile/cmp/mask';
18
+ import {loadingIndicator} from '@xh/hoist/cmp/loadingindicator';
19
+ import {mask} from '@xh/hoist/cmp/mask';
20
20
  import {toolbar} from '@xh/hoist/mobile/cmp/toolbar';
21
21
  import '@xh/hoist/mobile/register';
22
22
  import {splitLayoutProps} from '@xh/hoist/utils/react';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "71.0.0-SNAPSHOT.1735047359409",
3
+ "version": "71.0.0-SNAPSHOT.1735061320692",
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",
@@ -4,7 +4,8 @@
4
4
  *
5
5
  * Copyright © 2024 Extremely Heavy Industries Inc.
6
6
  */
7
- import {Auth0Client, Auth0ClientOptions} from '@auth0/auth0-spa-js';
7
+ import type {Auth0ClientOptions} from '@auth0/auth0-spa-js';
8
+ import {Auth0Client} from '@auth0/auth0-spa-js';
8
9
  import {XH} from '@xh/hoist/core';
9
10
  import {never, wait} from '@xh/hoist/promise';
10
11
  import {Token, TokenMap} from '@xh/hoist/security/Token';
@@ -14,9 +15,23 @@ import {flatMap, union} from 'lodash';
14
15
  import {BaseOAuthClient, BaseOAuthClientConfig} from '../BaseOAuthClient';
15
16
 
16
17
  export interface AuthZeroClientConfig extends BaseOAuthClientConfig<AuthZeroTokenSpec> {
17
- /** Domain of your app registered with Auth0 */
18
+ /** Domain of your app registered with Auth0. */
18
19
  domain: string;
19
20
 
21
+ /**
22
+ * Audience to pass to interactive login and ID token requests.
23
+ *
24
+ * If you are also requesting an *access* token for a single audience, pass that value here to
25
+ * ensure that the initial login/token request returns a ready-to-use access token (and refresh
26
+ * token) with a single request to the Auth0 API, instead of requiring two.
27
+ *
28
+ * This also avoids issues with browsers that block third party cookies when running on
29
+ * localhost or with an Auth0 domain that does not match the app's own domain. In those cases,
30
+ * Auth0 must use refresh tokens to obtain access tokens, and a single audience allows that
31
+ * exchange to work without extra user interaction that this class does not currently support.
32
+ */
33
+ audience?: string;
34
+
20
35
  /**
21
36
  * Additional options for the Auth0Client ctor. Will be deep merged with defaults, with options
22
37
  * supplied here taking precedence. Use with care, as overriding defaults may have unintended
@@ -31,9 +46,7 @@ export interface AuthZeroTokenSpec {
31
46
 
32
47
  /**
33
48
  * Audience (i.e. API) identifier for AccessToken. Must be registered with Auth0.
34
- *
35
- * Note that this is required to ensure that issued token is a JWT and not
36
- * an opaque string.
49
+ * Note that this is required to ensure that issued token is a JWT and not an opaque string.
37
50
  */
38
51
  audience: string;
39
52
  }
@@ -95,7 +108,9 @@ export class AuthZeroClient extends BaseOAuthClient<AuthZeroClientConfig, AuthZe
95
108
 
96
109
  protected override async doLoginPopupAsync(): Promise<void> {
97
110
  try {
98
- await this.client.loginWithPopup({authorizationParams: {scope: this.loginScope}});
111
+ await this.client.loginWithPopup({
112
+ authorizationParams: {scope: this.loginScope}
113
+ });
99
114
  await this.noteUserAuthenticatedAsync();
100
115
  } catch (e) {
101
116
  const msg = e.message?.toLowerCase();
@@ -167,25 +182,27 @@ export class AuthZeroClient extends BaseOAuthClient<AuthZeroClientConfig, AuthZe
167
182
  // Private implementation
168
183
  //------------------------
169
184
  private createClient(): Auth0Client {
170
- const {clientId, domain, authZeroClientOptions} = this.config;
185
+ const {clientId, domain, audience, authZeroClientOptions} = this.config;
171
186
  throwIf(!domain, 'Missing Auth0 "domain". Please review your config.');
172
187
 
173
- return new Auth0Client(
174
- mergeDeep(
175
- {
176
- clientId,
177
- domain,
178
- useRefreshTokens: true,
179
- useRefreshTokensFallback: true,
180
- authorizationParams: {
181
- scope: this.loginScope,
182
- redirect_uri: this.redirectUrl
183
- },
184
- cacheLocation: 'localstorage'
188
+ const mergedConfig = mergeDeep(
189
+ {
190
+ clientId,
191
+ domain,
192
+ useRefreshTokens: true,
193
+ useRefreshTokensFallback: true,
194
+ authorizationParams: {
195
+ scope: this.loginScope,
196
+ redirect_uri: this.redirectUrl,
197
+ audience
185
198
  },
186
- authZeroClientOptions
187
- )
199
+ cacheLocation: 'localstorage'
200
+ },
201
+ authZeroClientOptions
188
202
  );
203
+
204
+ this.logDebug(`Creating Auth0Client with merged config`, mergedConfig);
205
+ return new Auth0Client(mergedConfig);
189
206
  }
190
207
 
191
208
  private get loginScope(): string {