@xh/hoist 83.1.0 → 84.0.1

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 (250) hide show
  1. package/CHANGELOG.md +76 -0
  2. package/admin/tabs/cluster/instances/logs/levels/LogLevelDialogModel.ts +106 -10
  3. package/admin/tabs/cluster/metrics/MetricsModel.ts +3 -3
  4. package/appcontainer/AppContainerModel.ts +1 -1
  5. package/appcontainer/README.md +20 -0
  6. package/assets.d.ts +34 -0
  7. package/build/types/cmp/ag-grid/AgGrid.d.ts +8 -19
  8. package/build/types/cmp/ag-grid/AgGridModel.d.ts +18 -5
  9. package/build/types/cmp/card/Card.d.ts +9 -4
  10. package/build/types/cmp/card/CardModel.d.ts +15 -2
  11. package/build/types/cmp/chart/Chart.d.ts +2 -2
  12. package/build/types/cmp/chart/ChartModel.d.ts +11 -1
  13. package/build/types/cmp/dataview/DataView.d.ts +4 -2
  14. package/build/types/cmp/dataview/DataViewModel.d.ts +16 -4
  15. package/build/types/cmp/filter/FilterChooserModel.d.ts +7 -1
  16. package/build/types/cmp/form/Form.d.ts +2 -1
  17. package/build/types/cmp/form/FormModel.d.ts +12 -0
  18. package/build/types/cmp/form/field/BaseFieldModel.d.ts +7 -0
  19. package/build/types/cmp/form/formfieldset/FormFieldSetModel.d.ts +7 -1
  20. package/build/types/cmp/grid/GridModel.d.ts +16 -1
  21. package/build/types/cmp/grid/GridSorter.d.ts +14 -0
  22. package/build/types/cmp/grid/Types.d.ts +18 -0
  23. package/build/types/cmp/grid/columns/Column.d.ts +40 -2
  24. package/build/types/cmp/grid/columns/ColumnGroup.d.ts +10 -0
  25. package/build/types/cmp/grouping/GroupingChooserModel.d.ts +9 -2
  26. package/build/types/cmp/layout/Box.d.ts +19 -7
  27. package/build/types/cmp/layout/Frame.d.ts +17 -5
  28. package/build/types/cmp/loadingindicator/LoadingIndicator.d.ts +6 -4
  29. package/build/types/cmp/pinpad/PinPadModel.d.ts +6 -1
  30. package/build/types/cmp/spinner/Spinner.d.ts +31 -10
  31. package/build/types/cmp/tab/TabContainerModel.d.ts +11 -0
  32. package/build/types/cmp/tab/TabModel.d.ts +7 -0
  33. package/build/types/cmp/tab/Types.d.ts +4 -0
  34. package/build/types/cmp/treemap/TreeMapModel.d.ts +3 -3
  35. package/build/types/cmp/viewmanager/ViewManagerModel.d.ts +9 -0
  36. package/build/types/cmp/zoneGrid/ZoneGridModel.d.ts +22 -3
  37. package/build/types/cmp/zoneGrid/impl/ZoneMapperModel.d.ts +6 -0
  38. package/build/types/core/HoistComponent.d.ts +29 -8
  39. package/build/types/core/HoistProps.d.ts +9 -3
  40. package/build/types/core/load/LoadSpec.d.ts +1 -1
  41. package/build/types/core/persist/provider/ViewManagerProvider.d.ts +7 -0
  42. package/build/types/data/Store.d.ts +35 -1
  43. package/build/types/data/StoreSelectionModel.d.ts +18 -2
  44. package/build/types/data/cube/Cube.d.ts +26 -6
  45. package/build/types/data/cube/Query.d.ts +10 -0
  46. package/build/types/data/cube/View.d.ts +21 -2
  47. package/build/types/data/cube/aggregate/Aggregator.d.ts +13 -0
  48. package/build/types/data/cube/aggregate/AverageAggregator.d.ts +1 -0
  49. package/build/types/data/cube/aggregate/AverageStrictAggregator.d.ts +1 -0
  50. package/build/types/data/cube/aggregate/ChildCountAggregator.d.ts +1 -0
  51. package/build/types/data/cube/aggregate/LeafCountAggregator.d.ts +1 -0
  52. package/build/types/data/cube/aggregate/MaxAggregator.d.ts +1 -0
  53. package/build/types/data/cube/aggregate/MinAggregator.d.ts +1 -0
  54. package/build/types/data/cube/aggregate/NullAggregator.d.ts +1 -0
  55. package/build/types/data/cube/aggregate/SingleAggregator.d.ts +1 -0
  56. package/build/types/data/cube/aggregate/SumAggregator.d.ts +1 -0
  57. package/build/types/data/cube/aggregate/SumStrictAggregator.d.ts +1 -0
  58. package/build/types/data/cube/aggregate/UniqueAggregator.d.ts +1 -0
  59. package/build/types/data/filter/BaseFilterFieldSpec.d.ts +9 -0
  60. package/build/types/data/filter/Types.d.ts +12 -0
  61. package/build/types/desktop/cmp/button/AppMenuButton.d.ts +5 -0
  62. package/build/types/desktop/cmp/button/Button.d.ts +5 -1
  63. package/build/types/desktop/cmp/dash/canvas/DashCanvasModel.d.ts +12 -3
  64. package/build/types/desktop/cmp/dash/container/DashContainerModel.d.ts +9 -0
  65. package/build/types/desktop/cmp/dock/DockViewModel.d.ts +7 -0
  66. package/build/types/desktop/cmp/filechooser/FileChooserModel.d.ts +8 -0
  67. package/build/types/desktop/cmp/grid/editors/BooleanEditor.d.ts +1 -0
  68. package/build/types/desktop/cmp/grid/editors/DateEditor.d.ts +1 -0
  69. package/build/types/desktop/cmp/grid/editors/NumberEditor.d.ts +1 -0
  70. package/build/types/desktop/cmp/grid/editors/SelectEditor.d.ts +1 -0
  71. package/build/types/desktop/cmp/grid/editors/TextAreaEditor.d.ts +1 -0
  72. package/build/types/desktop/cmp/grid/editors/TextEditor.d.ts +1 -0
  73. package/build/types/desktop/cmp/input/Picker.d.ts +1 -1
  74. package/build/types/desktop/cmp/input/SegmentedControl.d.ts +16 -2
  75. package/build/types/desktop/cmp/leftrightchooser/LeftRightChooserModel.d.ts +7 -0
  76. package/build/types/desktop/cmp/modalsupport/ModalSupportModel.d.ts +28 -2
  77. package/build/types/desktop/cmp/panel/Panel.d.ts +5 -2
  78. package/build/types/desktop/cmp/panel/PanelModel.d.ts +12 -2
  79. package/build/types/desktop/cmp/rest/RestGrid.d.ts +10 -0
  80. package/build/types/desktop/cmp/rest/RestGridModel.d.ts +9 -1
  81. package/build/types/desktop/cmp/toolbar/Toolbar.d.ts +4 -1
  82. package/build/types/format/FormatDate.d.ts +4 -4
  83. package/build/types/icon/Icon.d.ts +3 -0
  84. package/build/types/kit/blueprint/Wrappers.d.ts +12 -1
  85. package/build/types/mobile/cmp/navigator/NavigatorModel.d.ts +8 -0
  86. package/build/types/mobile/cmp/navigator/PageModel.d.ts +7 -0
  87. package/build/types/mobile/cmp/panel/DialogPanel.d.ts +0 -2
  88. package/build/types/security/BaseOAuthClient.d.ts +9 -0
  89. package/build/types/security/authzero/AuthZeroClient.d.ts +6 -0
  90. package/build/types/security/msal/MsalClient.d.ts +6 -0
  91. package/build/types/svc/FetchService.d.ts +10 -7
  92. package/build/types/svc/TraceService.d.ts +17 -2
  93. package/build/types/utils/async/Timer.d.ts +6 -0
  94. package/build/types/utils/js/LangUtils.d.ts +1 -1
  95. package/build/types/utils/js/TestUtils.d.ts +1 -1
  96. package/build/types/utils/react/index.d.ts +0 -1
  97. package/build/types/utils/telemetry/Span.d.ts +12 -2
  98. package/cmp/ag-grid/AgGrid.ts +8 -19
  99. package/cmp/ag-grid/AgGridModel.ts +18 -5
  100. package/cmp/card/Card.ts +9 -4
  101. package/cmp/card/CardModel.ts +15 -2
  102. package/cmp/chart/Chart.ts +2 -2
  103. package/cmp/chart/ChartModel.ts +11 -1
  104. package/cmp/dataview/DataView.ts +4 -2
  105. package/cmp/dataview/DataViewModel.ts +16 -4
  106. package/cmp/filter/FilterChooserModel.ts +7 -1
  107. package/cmp/form/Form.ts +2 -1
  108. package/cmp/form/FormModel.ts +12 -0
  109. package/cmp/form/README.md +13 -0
  110. package/cmp/form/field/BaseFieldModel.ts +7 -0
  111. package/cmp/form/formfieldset/FormFieldSetModel.ts +7 -1
  112. package/cmp/grid/Grid.scss +14 -8
  113. package/cmp/grid/GridModel.ts +16 -1
  114. package/cmp/grid/GridSorter.ts +14 -0
  115. package/cmp/grid/README.md +12 -0
  116. package/cmp/grid/Types.ts +18 -0
  117. package/cmp/grid/columns/Column.ts +40 -2
  118. package/cmp/grid/columns/ColumnGroup.ts +10 -0
  119. package/cmp/grouping/GroupingChooserModel.ts +9 -2
  120. package/cmp/layout/Box.ts +19 -7
  121. package/cmp/layout/Frame.ts +17 -5
  122. package/cmp/layout/README.md +16 -21
  123. package/cmp/loadingindicator/LoadingIndicator.scss +1 -1
  124. package/cmp/loadingindicator/LoadingIndicator.ts +11 -9
  125. package/cmp/pinpad/PinPadModel.ts +6 -1
  126. package/cmp/spinner/Spinner.scss +13 -0
  127. package/cmp/spinner/Spinner.ts +58 -20
  128. package/cmp/tab/TabContainerModel.ts +11 -0
  129. package/cmp/tab/TabModel.ts +7 -0
  130. package/cmp/tab/Types.ts +4 -0
  131. package/cmp/treemap/TreeMapModel.ts +3 -3
  132. package/cmp/viewmanager/ViewManagerModel.ts +9 -0
  133. package/cmp/zoneGrid/ZoneGridModel.ts +22 -3
  134. package/cmp/zoneGrid/impl/ZoneMapperModel.ts +6 -0
  135. package/core/ExceptionHandler.ts +1 -1
  136. package/core/HoistComponent.ts +36 -11
  137. package/core/HoistProps.ts +9 -3
  138. package/core/README.md +68 -6
  139. package/core/impl/InstanceManager.ts +1 -0
  140. package/core/load/LoadSpec.ts +1 -1
  141. package/core/persist/provider/ViewManagerProvider.ts +7 -0
  142. package/data/README.md +48 -124
  143. package/data/Store.ts +35 -1
  144. package/data/StoreSelectionModel.ts +18 -2
  145. package/data/cube/Cube.ts +26 -6
  146. package/data/cube/Query.ts +10 -0
  147. package/data/cube/README.md +236 -0
  148. package/data/cube/View.ts +21 -2
  149. package/data/cube/aggregate/Aggregator.ts +13 -0
  150. package/data/cube/aggregate/AverageAggregator.ts +1 -0
  151. package/data/cube/aggregate/AverageStrictAggregator.ts +1 -0
  152. package/data/cube/aggregate/ChildCountAggregator.ts +1 -0
  153. package/data/cube/aggregate/LeafCountAggregator.ts +1 -0
  154. package/data/cube/aggregate/MaxAggregator.ts +1 -0
  155. package/data/cube/aggregate/MinAggregator.ts +1 -0
  156. package/data/cube/aggregate/NullAggregator.ts +1 -0
  157. package/data/cube/aggregate/SingleAggregator.ts +1 -0
  158. package/data/cube/aggregate/SumAggregator.ts +1 -0
  159. package/data/cube/aggregate/SumStrictAggregator.ts +1 -0
  160. package/data/cube/aggregate/UniqueAggregator.ts +1 -0
  161. package/data/filter/BaseFilterFieldSpec.ts +9 -0
  162. package/data/filter/Types.ts +12 -0
  163. package/desktop/README.md +131 -9
  164. package/desktop/appcontainer/AboutDialog.ts +2 -0
  165. package/desktop/appcontainer/Banner.ts +5 -2
  166. package/desktop/appcontainer/ChangelogDialog.ts +1 -0
  167. package/desktop/appcontainer/ExceptionDialog.ts +4 -0
  168. package/desktop/appcontainer/ExceptionDialogDetails.ts +4 -1
  169. package/desktop/appcontainer/FeedbackDialog.ts +4 -1
  170. package/desktop/appcontainer/ImpersonationBar.ts +4 -0
  171. package/desktop/appcontainer/LockoutPanel.ts +4 -1
  172. package/desktop/appcontainer/LoginPanel.ts +7 -3
  173. package/desktop/appcontainer/Message.ts +9 -3
  174. package/desktop/appcontainer/OptionsDialog.ts +3 -1
  175. package/desktop/appcontainer/VersionBar.ts +1 -0
  176. package/desktop/appcontainer/suspend/IdlePanel.ts +4 -4
  177. package/desktop/appcontainer/suspend/SuspendPanel.ts +3 -0
  178. package/desktop/cmp/button/AppMenuButton.ts +5 -0
  179. package/desktop/cmp/button/Button.ts +14 -4
  180. package/desktop/cmp/dash/README.md +14 -0
  181. package/desktop/cmp/dash/canvas/DashCanvasModel.ts +12 -3
  182. package/desktop/cmp/dash/container/DashContainerModel.ts +9 -0
  183. package/desktop/cmp/dock/DockViewModel.ts +7 -0
  184. package/desktop/cmp/filechooser/FileChooserModel.ts +9 -2
  185. package/desktop/cmp/grid/editors/BooleanEditor.ts +1 -0
  186. package/desktop/cmp/grid/editors/DateEditor.ts +1 -0
  187. package/desktop/cmp/grid/editors/NumberEditor.ts +1 -0
  188. package/desktop/cmp/grid/editors/SelectEditor.ts +1 -0
  189. package/desktop/cmp/grid/editors/TextAreaEditor.ts +1 -0
  190. package/desktop/cmp/grid/editors/TextEditor.ts +1 -0
  191. package/desktop/cmp/input/Picker.ts +2 -2
  192. package/desktop/cmp/input/SegmentedControl.ts +20 -2
  193. package/desktop/cmp/leftrightchooser/LeftRightChooserModel.ts +7 -0
  194. package/desktop/cmp/modalsupport/ModalSupportModel.ts +31 -2
  195. package/desktop/cmp/panel/Panel.ts +29 -21
  196. package/desktop/cmp/panel/PanelModel.ts +12 -2
  197. package/desktop/cmp/panel/README.md +20 -0
  198. package/desktop/cmp/rest/RestGrid.ts +10 -0
  199. package/desktop/cmp/rest/RestGridModel.ts +9 -1
  200. package/desktop/cmp/toolbar/Toolbar.ts +9 -2
  201. package/desktop/cmp/viewmanager/ViewManager.ts +1 -1
  202. package/docs/README.md +9 -4
  203. package/docs/coding-conventions.md +29 -21
  204. package/docs/doc-registry.json +31 -15
  205. package/docs/planning/docs-roadmap-log.md +11 -0
  206. package/docs/planning/docs-roadmap.md +1 -0
  207. package/docs/upgrade-notes/v84-upgrade-notes.md +136 -0
  208. package/docs/version-compatibility.md +2 -0
  209. package/format/FormatDate.ts +4 -4
  210. package/icon/Icon.ts +9 -0
  211. package/icon/README.md +62 -22
  212. package/icon/index.ts +24 -0
  213. package/kit/README.md +8 -2
  214. package/kit/blueprint/Wrappers.ts +12 -1
  215. package/mcp/README.md +47 -26
  216. package/mcp/cli/ts.ts +39 -4
  217. package/mcp/data/ts-registry.ts +57 -17
  218. package/mcp/tools/typescript.ts +32 -4
  219. package/mobile/appcontainer/AboutDialog.ts +3 -0
  220. package/mobile/appcontainer/Banner.ts +2 -0
  221. package/mobile/appcontainer/ExceptionDialog.ts +4 -0
  222. package/mobile/appcontainer/ExceptionDialogDetails.ts +1 -0
  223. package/mobile/appcontainer/FeedbackDialog.ts +4 -1
  224. package/mobile/appcontainer/ImpersonationBar.ts +2 -0
  225. package/mobile/appcontainer/LockoutPanel.ts +2 -0
  226. package/mobile/appcontainer/LoginPanel.ts +7 -3
  227. package/mobile/appcontainer/Message.ts +9 -3
  228. package/mobile/appcontainer/OptionsDialog.ts +5 -1
  229. package/mobile/appcontainer/VersionBar.ts +1 -0
  230. package/mobile/appcontainer/suspend/IdlePanel.ts +5 -6
  231. package/mobile/appcontainer/suspend/SuspendPanel.ts +3 -0
  232. package/mobile/cmp/navigator/NavigatorModel.ts +8 -0
  233. package/mobile/cmp/navigator/PageModel.ts +7 -0
  234. package/mobile/cmp/panel/DialogPanel.ts +0 -2
  235. package/package.json +11 -11
  236. package/security/BaseOAuthClient.ts +9 -0
  237. package/security/authzero/AuthZeroClient.ts +6 -0
  238. package/security/msal/MsalClient.ts +6 -0
  239. package/styles/vars.scss +14 -0
  240. package/svc/FetchService.ts +25 -15
  241. package/svc/README.md +39 -9
  242. package/svc/TraceService.ts +69 -11
  243. package/utils/README.md +0 -1
  244. package/utils/async/Timer.ts +6 -0
  245. package/utils/js/LangUtils.ts +1 -1
  246. package/utils/js/TestUtils.ts +1 -1
  247. package/utils/react/index.ts +0 -1
  248. package/utils/telemetry/Span.ts +21 -4
  249. package/build/types/utils/react/ClassName.d.ts +0 -14
  250. package/utils/react/ClassName.ts +0 -24
@@ -37,11 +37,13 @@ export const impersonationBar = hoistCmp.factory({
37
37
  enableFullscreen: true,
38
38
  placeholder: 'Select a user to impersonate...',
39
39
  createMessageFn: q => `Impersonate new user "${q}"`,
40
+ testId: 'xh-impersonation-target',
40
41
  onCommit: model.onCommit
41
42
  }),
42
43
  button({
43
44
  icon: Icon.close(),
44
45
  minimal: true,
46
+ testId: 'xh-impersonation-exit-btn',
45
47
  onClick: model.onClose
46
48
  })
47
49
  ]
@@ -39,6 +39,7 @@ export const lockoutPanel = hoistCmp.factory<AppContainerModel>({
39
39
  button({
40
40
  icon: Icon.logout(),
41
41
  text: 'Logout',
42
+ testId: 'xh-lockout-logout-btn',
42
43
  omit: !appSpec.enableLogout,
43
44
  onClick: () => XH.logoutAsync()
44
45
  }),
@@ -46,6 +47,7 @@ export const lockoutPanel = hoistCmp.factory<AppContainerModel>({
46
47
  button({
47
48
  icon: Icon.impersonate(),
48
49
  text: 'End Impersonation',
50
+ testId: 'xh-lockout-end-impersonation-btn',
49
51
  omit: !identityService.isImpersonating,
50
52
  onClick: () => identityService.endImpersonateAsync()
51
53
  })
@@ -30,6 +30,7 @@ export const loginPanel = hoistCmp.factory({
30
30
 
31
31
  return panel({
32
32
  className: 'xh-login',
33
+ testId: 'xh-login',
33
34
  items: [
34
35
  toolbar(filler(), XH.clientAppName, filler()),
35
36
  panel({
@@ -44,14 +45,16 @@ export const loginPanel = hoistCmp.factory({
44
45
  placeholder: 'Username',
45
46
  autoComplete: 'username',
46
47
  autoCapitalize: 'none',
47
- commitOnChange: true
48
+ commitOnChange: true,
49
+ testId: 'xh-login-username'
48
50
  }),
49
51
  textInput({
50
52
  bind: 'password',
51
53
  placeholder: 'Password',
52
54
  autoComplete: 'current-password',
53
55
  type: 'password',
54
- commitOnChange: true
56
+ commitOnChange: true,
57
+ testId: 'xh-login-password'
55
58
  })
56
59
  ]
57
60
  }),
@@ -69,7 +72,8 @@ export const loginPanel = hoistCmp.factory({
69
72
  icon: Icon.login(),
70
73
  text: loginInProgress ? 'Please wait...' : 'Login',
71
74
  disabled: !isValid || loginInProgress,
72
- onClick: () => model.submitAsync()
75
+ onClick: () => model.submitAsync(),
76
+ testId: 'xh-login-btn'
73
77
  })
74
78
  ]
75
79
  })
@@ -31,7 +31,7 @@ export const message = hoistCmp.factory({
31
31
  if (!isOpen) return null;
32
32
 
33
33
  if (cancelProps) {
34
- buttons.push(button({minimal: true, ...cancelProps}));
34
+ buttons.push(button({testId: 'xh-message-cancel-btn', minimal: true, ...cancelProps}));
35
35
  }
36
36
 
37
37
  if (cancelProps || confirmProps) {
@@ -46,8 +46,12 @@ export const message = hoistCmp.factory({
46
46
  // Merge in formModel.isValid here in render stage to get reactivity.
47
47
  buttons.push(
48
48
  formModel
49
- ? button({...confirmProps, disabled: !formModel.isValid})
50
- : button(confirmProps)
49
+ ? button({
50
+ testId: 'xh-message-confirm-btn',
51
+ ...confirmProps,
52
+ disabled: !formModel.isValid
53
+ })
54
+ : button({testId: 'xh-message-confirm-btn', ...confirmProps})
51
55
  );
52
56
  }
53
57
 
@@ -76,6 +80,7 @@ const inputCmp = hoistCmp.factory<MessageModel>(({model}) => {
76
80
  items.push(
77
81
  formField({
78
82
  field: 'value',
83
+ testId: 'xh-message-value',
79
84
  item: withDefault(input.item, textInput())
80
85
  })
81
86
  );
@@ -85,6 +90,7 @@ const inputCmp = hoistCmp.factory<MessageModel>(({model}) => {
85
90
  formField({
86
91
  label: extraConfirmLabel,
87
92
  field: 'extraConfirm',
93
+ testId: 'xh-message-extra-confirm',
88
94
  item: textInput()
89
95
  })
90
96
  );
@@ -30,6 +30,7 @@ export const optionsDialog = hoistCmp.factory({
30
30
  title: `${XH.clientAppName} Options`,
31
31
  icon: Icon.options(),
32
32
  className: 'xh-options-dialog',
33
+ testId: 'xh-options-dialog',
33
34
  isOpen: true,
34
35
  item: [
35
36
  mask({bind: loadTask, spinner: true}),
@@ -43,7 +44,8 @@ export const optionsDialog = hoistCmp.factory({
43
44
  restoreDefaultsButton({
44
45
  intent: 'danger',
45
46
  minimal: false,
46
- className: 'xh-options-dialog__restore-defaults-btn'
47
+ className: 'xh-options-dialog__restore-defaults-btn',
48
+ testId: 'xh-options-restore-defaults-btn'
47
49
  })
48
50
  ]
49
51
  })
@@ -54,6 +56,7 @@ export const optionsDialog = hoistCmp.factory({
54
56
  button({
55
57
  text: 'Cancel',
56
58
  minimal: true,
59
+ testId: 'xh-options-cancel-btn',
57
60
  onClick: () => model.hide()
58
61
  }),
59
62
  button({
@@ -62,6 +65,7 @@ export const optionsDialog = hoistCmp.factory({
62
65
  intent: 'primary',
63
66
  outlined: true,
64
67
  disabled: !formModel.isDirty,
68
+ testId: 'xh-options-save-btn',
65
69
  onClick: () => model.saveAsync()
66
70
  })
67
71
  ]
@@ -27,6 +27,7 @@ export const versionBar = hoistCmp.factory({
27
27
  alignItems: 'center',
28
28
  flex: 'none',
29
29
  className: `xh-version-bar xh-version-bar--${env.toLowerCase()}`,
30
+ testId: 'xh-version-bar',
30
31
  items: [
31
32
  [env, version, tabId].join(' • '),
32
33
  button({
@@ -5,15 +5,12 @@
5
5
  * Copyright © 2026 Extremely Heavy Industries Inc.
6
6
  */
7
7
 
8
- import {XH, hoistCmp} from '@xh/hoist/core';
9
- import {vframe, div, img, p} from '@xh/hoist/cmp/layout';
10
- import {panel} from '@xh/hoist/mobile/cmp/panel';
8
+ import {div, img, p, vframe} from '@xh/hoist/cmp/layout';
9
+ import {hoistCmp, XH} from '@xh/hoist/core';
11
10
  import {Icon} from '@xh/hoist/icon';
12
11
  import {button} from '@xh/hoist/mobile/cmp/button';
13
-
14
12
  import './IdlePanel.scss';
15
-
16
- // @ts-ignore
13
+ import {panel} from '@xh/hoist/mobile/cmp/panel';
17
14
  import idleImage from './IdlePanelImage.png';
18
15
 
19
16
  /**
@@ -28,6 +25,7 @@ export const idlePanel = hoistCmp.factory({
28
25
  render({onReactivate}) {
29
26
  return panel({
30
27
  className: 'xh-idle-panel',
28
+ testId: 'xh-idle-panel',
31
29
  title: `${XH.clientAppName} is sleeping`,
32
30
  icon: Icon.moon(),
33
31
  items: [
@@ -47,6 +45,7 @@ export const idlePanel = hoistCmp.factory({
47
45
  item: button({
48
46
  text: "I'm back!",
49
47
  flex: 1,
48
+ testId: 'xh-idle-reactivate-btn',
50
49
  onClick: onReactivate
51
50
  })
52
51
  })
@@ -53,6 +53,7 @@ export const suspendPanel = hoistCmp.factory<AppContainerModel>({
53
53
 
54
54
  return panel({
55
55
  className: 'xh-suspend-panel',
56
+ testId: 'xh-suspend-panel',
56
57
  title,
57
58
  icon,
58
59
  items: [
@@ -74,12 +75,14 @@ export const suspendPanel = hoistCmp.factory<AppContainerModel>({
74
75
  icon: Icon.refresh(),
75
76
  intent: 'primary',
76
77
  flex: 1,
78
+ testId: 'xh-suspend-reload-btn',
77
79
  onClick: () => XH.reloadApp()
78
80
  }),
79
81
  button({
80
82
  text: 'More Details',
81
83
  icon: Icon.detail(),
82
84
  minimal: true,
85
+ testId: 'xh-suspend-details-btn',
83
86
  omit: !exception,
84
87
  onClick: () =>
85
88
  XH.exceptionHandler.showExceptionDetails(exception)
@@ -14,6 +14,14 @@ import '@xh/hoist/mobile/register';
14
14
  import {PageConfig, PageModel} from './PageModel';
15
15
  import {findScrollableParent, isDraggableEl} from './impl/Utils';
16
16
 
17
+ /**
18
+ * Configuration for a {@link NavigatorModel} - the primary stack-based navigation controller
19
+ * for mobile Hoist apps. Supports swipe-based page transitions, pull-to-refresh, and
20
+ * configurable render/refresh strategies.
21
+ *
22
+ * @see NavigatorModel
23
+ * @see PageConfig
24
+ */
17
25
  export interface NavigatorConfig {
18
26
  /** Configs for PageModels, representing all supported pages within this Navigator/App. */
19
27
  pages: PageConfig[];
@@ -19,6 +19,13 @@ import {warnIf, withDefault} from '@xh/hoist/utils/js';
19
19
  import {stringify} from 'qs';
20
20
  import {NavigatorModel} from './NavigatorModel';
21
21
 
22
+ /**
23
+ * Configuration for a {@link PageModel} - a single page within a {@link NavigatorModel}.
24
+ * Passed as entries in the `pages` array of a {@link NavigatorConfig}.
25
+ *
26
+ * @see PageModel
27
+ * @see NavigatorConfig
28
+ */
22
29
  export interface PageConfig {
23
30
  /** Unique ID. Must match a configured Router5 route name. */
24
31
  id: string;
@@ -20,8 +20,6 @@ export interface DialogPanelProps extends PanelProps {
20
20
  *
21
21
  * These views do not participate in navigation or routing, and are used for showing fullscreen
22
22
  * views outside of the Navigator / TabContainer context.
23
- *
24
- * @see FullscreenPanel for a true fullscreen, non-floating alternative.
25
23
  */
26
24
  export const [DialogPanel, dialogPanel] = hoistCmp.withFactory<DialogPanelProps>({
27
25
  displayName: 'DialogPanel',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "83.1.0",
3
+ "version": "84.0.1",
4
4
  "description": "Hoist add-on for building and deploying React Applications.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -38,17 +38,17 @@
38
38
  ]
39
39
  },
40
40
  "dependencies": {
41
- "@auth0/auth0-spa-js": "~2.17.0",
41
+ "@auth0/auth0-spa-js": "~2.19.0",
42
42
  "@azure/msal-browser": "~4.29.0",
43
43
  "@blueprintjs/core": "^6.3.2",
44
44
  "@blueprintjs/datetime": "^6.0.6",
45
- "@fortawesome/fontawesome-pro": "^6.6.0",
46
- "@fortawesome/fontawesome-svg-core": "^6.6.0",
47
- "@fortawesome/pro-light-svg-icons": "^6.6.0",
48
- "@fortawesome/pro-regular-svg-icons": "^6.6.0",
49
- "@fortawesome/pro-solid-svg-icons": "^6.6.0",
50
- "@fortawesome/pro-thin-svg-icons": "^6.6.0",
51
- "@fortawesome/react-fontawesome": "^0.2.3",
45
+ "@fortawesome/fontawesome-pro": "^7.2.0",
46
+ "@fortawesome/fontawesome-svg-core": "^7.2.0",
47
+ "@fortawesome/pro-light-svg-icons": "^7.2.0",
48
+ "@fortawesome/pro-regular-svg-icons": "^7.2.0",
49
+ "@fortawesome/pro-solid-svg-icons": "^7.2.0",
50
+ "@fortawesome/pro-thin-svg-icons": "^7.2.0",
51
+ "@fortawesome/react-fontawesome": "^3.2.0",
52
52
  "@modelcontextprotocol/sdk": "^1.26.0",
53
53
  "@onsenui/fastclick": "~1.1.1",
54
54
  "@popperjs/core": "~2.11.0",
@@ -59,7 +59,7 @@
59
59
  "commander": "^14.0.3",
60
60
  "core-js": "3.x",
61
61
  "debounce-promise": "~3.1.0",
62
- "dompurify": "~3.3.0",
62
+ "dompurify": "~3.4.0",
63
63
  "fast-deep-equal": "~3.1.1",
64
64
  "filesize": "~11.0.2",
65
65
  "golden-layout": "~1.5.9",
@@ -67,7 +67,7 @@
67
67
  "inter-ui": "~4.1.1",
68
68
  "jquery": "3.x",
69
69
  "jwt-decode": "~4.0.0",
70
- "lodash": "~4.17.21",
70
+ "lodash": "~4.18.0",
71
71
  "lodash-inflection": "~1.5.0",
72
72
  "mobx": "~6.15.0",
73
73
  "mobx-react-lite": "~4.1.0",
@@ -20,6 +20,15 @@ import ShortUniqueId from 'short-unique-id';
20
20
 
21
21
  export type LoginMethod = 'REDIRECT' | 'POPUP';
22
22
 
23
+ /**
24
+ * Base configuration shared by all OAuth client implementations. Extended by
25
+ * {@link MsalClientConfig} and {@link AuthZeroClientConfig} with provider-specific options.
26
+ *
27
+ * See the security package README (`security/README.md`) for authentication architecture
28
+ * and setup guidance.
29
+ *
30
+ * @see BaseOAuthClient
31
+ */
23
32
  export interface BaseOAuthClientConfig<S extends AccessTokenSpec> {
24
33
  /** Client ID (GUID) of your app registered with your Oauth provider. */
25
34
  clientId: string;
@@ -15,6 +15,12 @@ import {mergeDeep, throwIf} from '@xh/hoist/utils/js';
15
15
  import {flatMap, union} from 'lodash';
16
16
  import {BaseOAuthClient, BaseOAuthClientConfig} from '../BaseOAuthClient';
17
17
 
18
+ /**
19
+ * Configuration for an {@link AuthZeroClient} - the Auth0 OAuth client.
20
+ * Extends {@link BaseOAuthClientConfig} with Auth0-specific options.
21
+ *
22
+ * @see AuthZeroClient
23
+ */
18
24
  export interface AuthZeroClientConfig extends BaseOAuthClientConfig<AuthZeroTokenSpec> {
19
25
  /** Domain of your app registered with Auth0. */
20
26
  domain: string;
@@ -23,6 +23,12 @@ import {flatMap, union, uniq} from 'lodash';
23
23
  import {BaseOAuthClient, BaseOAuthClientConfig} from '../BaseOAuthClient';
24
24
  import {AccessTokenSpec, TokenMap} from '../Types';
25
25
 
26
+ /**
27
+ * Configuration for a {@link MsalClient} - the Microsoft Entra ID (Azure AD) OAuth client.
28
+ * Extends {@link BaseOAuthClientConfig} with MSAL-specific options.
29
+ *
30
+ * @see MsalClient
31
+ */
26
32
  export interface MsalClientConfig extends BaseOAuthClientConfig<MsalTokenSpec> {
27
33
  /**
28
34
  * Authority for your organization's tenant: `https://login.microsoftonline.com/[tenantId]`.
package/styles/vars.scss CHANGED
@@ -575,6 +575,11 @@ body {
575
575
  --xh-grid-selected-row-text-color: var(--grid-selected-row-text-color, var(--xh-grid-text-color));
576
576
  --xh-grid-summary-row-border-color: var(--grid-summary-row-border-color, var(--xh-grid-border-color));
577
577
  --xh-grid-text-color: var(--grid-text-color, var(--xh-text-color));
578
+ --xh-grid-tooltip-bg: var(--grid-tooltip-bg, var(--xh-bg-alt));
579
+ --xh-grid-tooltip-border: var(--grid-tooltip-border, var(--xh-border-solid));
580
+ --xh-grid-tooltip-border-radius: var(--grid-tooltip-border-radius, var(--xh-border-radius-px));
581
+ --xh-grid-tooltip-max-width: var(--grid-tooltip-max-width, 400px);
582
+ --xh-grid-tooltip-padding: var(--grid-tooltip-padding, var(--xh-pad-half-px));
578
583
  --xh-grid-tree-indent: var(--grid-tree-indent, 1.2em);
579
584
  --xh-grid-tree-icon-px: var(--grid-tree-icon-px, 10px);
580
585
 
@@ -810,6 +815,15 @@ body {
810
815
  }
811
816
 
812
817
 
818
+ //------------------------
819
+ // Spinner
820
+ //------------------------
821
+ --xh-spinner-color: var(--spinner-color, #{mc('blue-grey', '400')});
822
+
823
+ &.xh-dark {
824
+ --xh-spinner-color: var(--spinner-color, var(--xh-blue-gray));
825
+ }
826
+
813
827
  //------------------------
814
828
  // Tabs
815
829
  //------------------------
@@ -14,7 +14,7 @@ import {
14
14
  XH
15
15
  } from '@xh/hoist/core';
16
16
  import {Exception, HoistException, TimeoutException} from '@xh/hoist/exception';
17
- import {formatTraceparent, Span} from '@xh/hoist/utils/telemetry';
17
+ import {formatTraceparent, Span, SpanConfig} from '@xh/hoist/utils/telemetry';
18
18
  import {PromiseTimeoutSpec} from '@xh/hoist/promise';
19
19
  import {isLocalDate, SECONDS} from '@xh/hoist/utils/datetime';
20
20
  import {apiDeprecated, warnIf} from '@xh/hoist/utils/js';
@@ -34,8 +34,8 @@ export interface FetchServiceDefaults {
34
34
  /**
35
35
  * Service for making managed HTTP requests, both to the app's own Hoist server and to remote APIs.
36
36
  *
37
- * Typically accessed via `XH.fetchService` or the convenience methods on XH `XH.fetch()`,
38
- * `XH.fetchJson()`, `XH.postJson()`, `XH.putJson()`, `XH.deleteJson()` which delegate here.
37
+ * Typically accessed via `XH.fetchService` or the convenience methods on XH - `XH.fetch()`,
38
+ * `XH.fetchJson()`, `XH.postJson()`, `XH.putJson()`, `XH.deleteJson()` - which delegate here.
39
39
  *
40
40
  * Wraps the standard Fetch API with CORS enabled, credentials included, and redirects followed.
41
41
  * Provides JSON convenience methods (`fetchJson`, `postJson`, `putJson`, `patchJson`,
@@ -197,9 +197,16 @@ export class FetchService extends HoistService {
197
197
  // Implementation
198
198
  //-----------------------
199
199
  private async fetchInternalAsync(opts: FetchOptions): Promise<any> {
200
+ // If a span spec provided create, wrap, and recurse
201
+ if (opts.span && !(opts.span instanceof Span)) {
202
+ return XH.traceService.withSpanAsync(opts.span, span =>
203
+ this.fetchInternalAsync({...opts, span})
204
+ );
205
+ }
206
+
200
207
  opts = this.withCorrelationId(opts);
201
208
 
202
- // Tracing create span for this request.
209
+ // Tracing - create span for this request.
203
210
  const span = this.startFetchSpan(opts);
204
211
  if (span) opts = {...opts, traceId: span.traceId};
205
212
 
@@ -219,7 +226,7 @@ export class FetchService extends HoistService {
219
226
  ret = ret.track({...trackOptions, correlationId: correlationId as string, loadSpec});
220
227
  }
221
228
 
222
- // Tracing end span on completion or failure.
229
+ // Tracing - end span on completion or failure.
223
230
  if (span) {
224
231
  ret = ret.then(
225
232
  value => {
@@ -282,7 +289,9 @@ export class FetchService extends HoistService {
282
289
  'Content-Type': isPost ? 'application/x-www-form-urlencoded' : 'text/plain',
283
290
  ...defaultHeaders,
284
291
  ...(opts.asJson ? {Accept: 'application/json'} : {}),
285
- ...(span ? {traceparent: formatTraceparent(span.traceId, span.spanId)} : {}),
292
+ ...(span
293
+ ? {traceparent: formatTraceparent(span.traceId, span.spanId, span.sampled)}
294
+ : {}),
286
295
  ...opts.headers
287
296
  };
288
297
 
@@ -418,13 +427,11 @@ export class FetchService extends HoistService {
418
427
  const method = opts.method ?? (opts.params ? 'POST' : 'GET'),
419
428
  url = this.extractUrlPath(opts.url);
420
429
 
421
- if (url.endsWith('submitSpans')) return null;
422
-
423
430
  return traceService.createSpan({
424
431
  name: method,
425
432
  kind: 'client',
426
- parent: opts.span,
427
- tags: {'http.request.method': method, 'url.path': opts.url, source: 'hoist'},
433
+ parent: opts.span as Span,
434
+ tags: {'http.request.method': method, 'url.path': url, 'xh.source': 'hoist'},
428
435
  caller: this
429
436
  });
430
437
  }
@@ -455,7 +462,7 @@ export class FetchService extends HoistService {
455
462
  }
456
463
  }
457
464
 
458
- private qsFilterFn = (prefix, value) => {
465
+ private qsFilterFn = (_prefix: string, value: any) => {
459
466
  if (isDate(value)) return value.getTime();
460
467
  if (isLocalDate(value)) return value.isoString;
461
468
  return value;
@@ -757,10 +764,12 @@ export interface FetchOptions {
757
764
  track?: string | TrackOptions;
758
765
 
759
766
  /**
760
- * If set, the fetch span created by TraceService will be parented under this span.
761
- * Use to nest fetch calls under a business-level span.
767
+ * Parent span for this fetch request. Use to nest fetch calls under a business-level span.
768
+ *
769
+ * Accepts an existing Span instance, a SpanConfig, or a string span name. When a SpanConfig or
770
+ * string is provided, FetchService will create and manage the parent span internally.
762
771
  */
763
- span?: Span;
772
+ span?: Span | SpanConfig | string;
764
773
 
765
774
  /**
766
775
  * Distributed trace ID for this request. Set automatically by FetchService
@@ -787,7 +796,8 @@ export interface FetchException extends HoistException {
787
796
 
788
797
  /**
789
798
  * True if exception resulted from the fetch being aborted by fetchService, or the application.
790
- * @see FetchService.abort and FetchOptions.autoAbortKey.
799
+ * @see FetchService.abort
800
+ * @see FetchOptions.autoAbortKey
791
801
  */
792
802
  isFetchAborted: boolean;
793
803
  }
package/svc/README.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Services Package
2
2
 
3
+ | Section | Description |
4
+ |---------|-------------|
5
+ | [Overview](#overview) | Purpose and principles of Hoist's built-in singleton services |
6
+ | [Architecture](#architecture) | Service hierarchy, installation, and access via XH |
7
+ | [Built-in Services](#built-in-services) | Reference for all 19 built-in services by category |
8
+ | [Configuration Keys Reference](#configuration-keys-reference) | Soft config keys controlling service behavior |
9
+ | [User Preference Keys Reference](#user-preference-keys-reference) | Per-user preference keys used by services |
10
+ | [Creating Custom Services](#creating-custom-services) | How to create and install application services |
11
+ | [Common Patterns](#common-patterns) | FetchService in loads, tracking, debounced search, WebSockets |
12
+ | [Common Pitfalls](#common-pitfalls) | Fetch errors, native fetch, missing loadSpec, and more |
13
+ | [Related Packages](#related-packages) | Links to core, cmp, promise, and admin packages |
14
+
3
15
  ## Overview
4
16
 
5
17
  The `/svc/` package contains Hoist's built-in singleton services - classes that provide app-wide
@@ -116,15 +128,16 @@ override async doLoadAsync(loadSpec: LoadSpec) {
116
128
 
117
129
  **Configuration Options:**
118
130
 
119
- | Option | Type | Description |
120
- |--------|------|-------------|
121
- | `url` | string | Request URL (relative URLs appended to `XH.baseUrl`) |
122
- | `body` | any | Request body |
123
- | `params` | object | Query string parameters |
124
- | `headers` | object | Additional headers |
125
- | `timeout` | number | Timeout in ms (default 30000) |
126
- | `autoAbortKey` | string | Cancel previous requests with same key |
127
- | `loadSpec` | LoadSpec | Metadata for tracking |
131
+ | Option | Type | Description |
132
+ |--------|------|---------------------------------------------------------------------------------------|
133
+ | `url` | string | Request URL (relative URLs appended to `XH.baseUrl`) |
134
+ | `body` | any | Request body |
135
+ | `params` | object | Query string parameters |
136
+ | `headers` | object | Additional headers |
137
+ | `timeout` | number | Timeout in ms (default 30000) |
138
+ | `autoAbortKey` | string | Cancel previous requests with same key |
139
+ | `loadSpec` | LoadSpec | Metadata for tracking |
140
+ | `span` | `Span \| string \| SpanConfig` | Parent span for tracing. Accepts an existing `Span`, a `SpanConfig`, or a string name |
128
141
 
129
142
  **App-Level Defaults (`FetchService.defaults`):**
130
143
 
@@ -303,6 +316,12 @@ Client-side distributed tracing — creates spans for user actions and fetch cal
303
316
  Hoist server. Exceptions thrown during traced operations include a `traceId` for correlation
304
317
  with server-side traces. Controlled by the `xhTraceConfig` soft config. Requires hoist-core 37+.
305
318
 
319
+ Spans are sampled at creation time using `xhTraceConfig.sampleRules` — an ordered list of
320
+ tag-matching rules with glob pattern support. Child spans inherit their parent's sampling
321
+ decision. Unsampled spans are dropped before export unless they end in error and
322
+ `alwaysSampleErrors` is enabled. The `traceparent` header propagates the sampling flag to
323
+ the server. See the hoist-core tracing documentation for full sampling configuration details.
324
+
306
325
  ```typescript
307
326
  // Wrap an async operation in a span (from any HoistBase subclass)
308
327
  await this.withSpanAsync({name: 'loadPortfolio', caller: this}, async span => {
@@ -317,6 +336,17 @@ const result = this.withSpan({name: 'computeTotals', caller: this}, span => {
317
336
 
318
337
  // Simple string-only config
319
338
  await this.withSpanAsync('loadData', async span => { ... });
339
+
340
+ // Nest a fetch call under a parent span without manual span management.
341
+ // FetchService accepts a string, SpanConfig, or existing Span as the `span` option.
342
+ const data = await XH.fetchJson({
343
+ url: 'api/portfolio',
344
+ span: 'loadPortfolio'
345
+ });
346
+ const data = await XH.fetchJson({
347
+ url: 'api/portfolio',
348
+ span: {name: 'loadPortfolio', tags: {portfolioId: id}, caller: this}
349
+ });
320
350
  ```
321
351
 
322
352
  **SpanConfig:**