@xh/hoist 71.0.0-SNAPSHOT.1735061018823 → 71.0.0-SNAPSHOT.1735062266455

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 (84) hide show
  1. package/CHANGELOG.md +12 -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/data/cube/Query.d.ts +7 -1
  22. package/build/types/desktop/cmp/error/impl/ErrorMessage.d.ts +7 -0
  23. package/build/types/desktop/cmp/mask/impl/Mask.d.ts +8 -0
  24. package/build/types/dynamics/desktop.d.ts +2 -1
  25. package/build/types/dynamics/mobile.d.ts +2 -1
  26. package/build/types/mobile/cmp/error/impl/ErrorMessage.d.ts +7 -0
  27. package/build/types/mobile/cmp/mask/impl/Mask.d.ts +8 -0
  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/data/cube/Query.ts +11 -0
  41. package/data/cube/row/BaseRow.ts +8 -6
  42. package/desktop/appcontainer/AppContainer.ts +5 -3
  43. package/desktop/cmp/dash/container/DashContainer.ts +1 -1
  44. package/desktop/cmp/error/impl/ErrorMessage.ts +65 -0
  45. package/desktop/cmp/mask/impl/Mask.ts +40 -0
  46. package/desktop/cmp/panel/Panel.ts +2 -2
  47. package/desktop/cmp/rest/RestGrid.ts +1 -1
  48. package/dynamics/desktop.ts +4 -2
  49. package/dynamics/mobile.ts +4 -2
  50. package/mobile/appcontainer/AppContainer.ts +5 -3
  51. package/mobile/appcontainer/OptionsDialog.ts +1 -1
  52. package/mobile/cmp/error/impl/ErrorMessage.ts +65 -0
  53. package/mobile/cmp/mask/impl/Mask.ts +34 -0
  54. package/mobile/cmp/panel/Panel.ts +2 -2
  55. package/package.json +1 -1
  56. package/tsconfig.tsbuildinfo +1 -1
  57. package/build/types/desktop/cmp/error/index.d.ts +0 -1
  58. package/build/types/desktop/cmp/treemap/impl/Splitter.d.ts +0 -6
  59. package/build/types/mobile/cmp/error/ErrorMessage.d.ts +0 -42
  60. package/build/types/mobile/cmp/error/index.d.ts +0 -1
  61. package/build/types/mobile/cmp/loadingindicator/LoadingIndicator.d.ts +0 -27
  62. package/build/types/mobile/cmp/loadingindicator/index.d.ts +0 -1
  63. package/build/types/mobile/cmp/mask/Mask.d.ts +0 -25
  64. package/build/types/mobile/cmp/mask/index.d.ts +0 -1
  65. package/desktop/cmp/error/index.ts +0 -1
  66. package/desktop/cmp/treemap/impl/Splitter.scss +0 -15
  67. package/desktop/cmp/treemap/impl/Splitter.ts +0 -28
  68. package/mobile/cmp/error/ErrorMessage.scss +0 -25
  69. package/mobile/cmp/error/ErrorMessage.ts +0 -140
  70. package/mobile/cmp/error/index.ts +0 -8
  71. package/mobile/cmp/loadingindicator/LoadingIndicator.scss +0 -81
  72. package/mobile/cmp/loadingindicator/LoadingIndicator.ts +0 -90
  73. package/mobile/cmp/loadingindicator/index.ts +0 -7
  74. package/mobile/cmp/mask/Mask.ts +0 -75
  75. package/mobile/cmp/mask/index.ts +0 -7
  76. /package/build/types/{desktop/cmp → cmp}/loadingindicator/index.d.ts +0 -0
  77. /package/build/types/{desktop/cmp → cmp}/mask/index.d.ts +0 -0
  78. /package/build/types/{desktop/cmp → cmp}/treemap/index.d.ts +0 -0
  79. /package/{desktop/cmp → cmp}/loadingindicator/index.ts +0 -0
  80. /package/{desktop/cmp → cmp}/mask/index.ts +0 -0
  81. /package/{desktop/cmp → cmp}/treemap/TreeMap.scss +0 -0
  82. /package/{desktop/cmp → cmp}/treemap/index.ts +0 -0
  83. /package/desktop/cmp/mask/{Mask.scss → impl/Mask.scss} +0 -0
  84. /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';
@@ -52,6 +52,12 @@ export interface QueryConfig {
52
52
  /** True to include leaf nodes in return.*/
53
53
  includeLeaves?: boolean;
54
54
 
55
+ /**
56
+ * True (default) to recursively omit single-child parents in the hierarchy.
57
+ * Apps can implement further omit logic using `omitFn`.
58
+ */
59
+ omitRedundantNodes?: boolean;
60
+
55
61
  /**
56
62
  * Optional function to be called for each aggregate node to determine if it should be "locked",
57
63
  * preventing drill-down into its children. Defaults to Cube.lockFn.
@@ -79,6 +85,7 @@ export class Query {
79
85
  readonly filter: Filter;
80
86
  readonly includeRoot: boolean;
81
87
  readonly includeLeaves: boolean;
88
+ readonly omitRedundantNodes: boolean;
82
89
  readonly cube: Cube;
83
90
  readonly lockFn: LockFn;
84
91
  readonly bucketSpecFn: BucketSpecFn;
@@ -93,6 +100,7 @@ export class Query {
93
100
  filter = null,
94
101
  includeRoot = false,
95
102
  includeLeaves = false,
103
+ omitRedundantNodes = true,
96
104
  lockFn = cube.lockFn,
97
105
  bucketSpecFn = cube.bucketSpecFn,
98
106
  omitFn = cube.omitFn
@@ -102,6 +110,7 @@ export class Query {
102
110
  this.dimensions = this.parseDimensions(dimensions);
103
111
  this.includeRoot = includeRoot;
104
112
  this.includeLeaves = includeLeaves;
113
+ this.omitRedundantNodes = omitRedundantNodes;
105
114
  this.filter = parseFilter(filter);
106
115
  this.lockFn = lockFn;
107
116
  this.bucketSpecFn = bucketSpecFn;
@@ -117,6 +126,7 @@ export class Query {
117
126
  filter: this.filter,
118
127
  includeRoot: this.includeRoot,
119
128
  includeLeaves: this.includeLeaves,
129
+ omitRedundantNodes: this.omitRedundantNodes,
120
130
  lockFn: this.lockFn,
121
131
  bucketSpecFn: this.bucketSpecFn,
122
132
  omitFn: this.omitFn,
@@ -153,6 +163,7 @@ export class Query {
153
163
  this.cube === other.cube &&
154
164
  this.includeRoot === other.includeRoot &&
155
165
  this.includeLeaves === other.includeLeaves &&
166
+ this.omitRedundantNodes === other.omitRedundantNodes &&
156
167
  this.bucketSpecFn == other.bucketSpecFn &&
157
168
  this.omitFn == other.omitFn &&
158
169
  this.lockFn == other.lockFn
@@ -65,12 +65,14 @@ export abstract class BaseRow {
65
65
 
66
66
  // 3a) Before attaching examine that we don't have a chain of redundant nodes
67
67
  // (not sure if loop needed -- are these redundant relations transitive?)
68
- while (dataChildren?.length === 1) {
69
- const childRow = dataChildren[0]._meta;
70
- if (this.isRedundantChild(this, childRow)) {
71
- dataChildren = childRow.data.children;
72
- } else {
73
- break;
68
+ if (view.query.omitRedundantNodes) {
69
+ while (dataChildren?.length === 1) {
70
+ const childRow = dataChildren[0]._meta;
71
+ if (this.isRedundantChild(this, childRow)) {
72
+ dataChildren = childRow.data.children;
73
+ } else {
74
+ break;
75
+ }
74
76
  }
75
77
  }
76
78
 
@@ -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.1735061018823",
3
+ "version": "71.0.0-SNAPSHOT.1735062266455",
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",