@xh/hoist 59.1.0 → 59.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +75 -1
- package/admin/AppComponent.ts +1 -1
- package/admin/tabs/activity/ActivityTab.ts +1 -1
- package/admin/tabs/general/GeneralTab.ts +2 -2
- package/admin/tabs/general/alertBanner/AlertBannerModel.ts +2 -2
- package/admin/tabs/general/config/ConfigPanel.ts +1 -0
- package/admin/tabs/monitor/MonitorTab.ts +1 -1
- package/admin/tabs/server/ServerTab.ts +1 -1
- package/admin/tabs/userData/UserDataTab.ts +1 -1
- package/cmp/ag-grid/AgGrid.scss +60 -12
- package/cmp/ag-grid/AgGrid.ts +8 -2
- package/cmp/badge/Badge.ts +18 -5
- package/cmp/chart/Chart.ts +13 -11
- package/cmp/clock/Clock.ts +6 -5
- package/cmp/dataview/DataView.ts +5 -3
- package/cmp/form/Form.ts +25 -6
- package/cmp/grid/Grid.scss +10 -0
- package/cmp/grid/Grid.ts +41 -25
- package/cmp/grid/GridModel.ts +138 -34
- package/cmp/grid/Types.ts +1 -1
- package/cmp/grid/columns/Column.ts +45 -2
- package/cmp/grid/columns/ColumnGroup.ts +11 -0
- package/cmp/grid/impl/GridHScrollbar.ts +140 -0
- package/cmp/grid/renderers/MultiFieldRenderer.ts +1 -1
- package/cmp/input/HoistInputModel.ts +4 -4
- package/cmp/input/HoistInputProps.ts +3 -1
- package/cmp/layout/Box.ts +4 -2
- package/cmp/relativetimestamp/RelativeTimestamp.ts +106 -40
- package/cmp/store/StoreFilterField.ts +2 -2
- package/cmp/tab/TabContainer.ts +1 -1
- package/cmp/zoneGrid/Types.ts +47 -0
- package/cmp/zoneGrid/ZoneGrid.ts +62 -0
- package/cmp/zoneGrid/ZoneGridModel.ts +666 -0
- package/cmp/zoneGrid/impl/ZoneGridPersistenceModel.ts +143 -0
- package/cmp/zoneGrid/impl/ZoneMapperModel.ts +335 -0
- package/cmp/zoneGrid/index.ts +3 -0
- package/core/HoistComponent.ts +23 -10
- package/core/HoistProps.ts +25 -6
- package/core/XH.ts +49 -27
- package/core/elem.ts +11 -3
- package/core/impl/InstanceManager.ts +24 -1
- package/core/model/HoistModel.ts +4 -4
- package/data/RecordAction.ts +8 -5
- package/data/StoreRecord.ts +8 -1
- package/data/cube/Query.ts +37 -3
- package/data/cube/View.ts +2 -2
- package/data/cube/row/BaseRow.ts +2 -2
- package/desktop/appcontainer/AppContainer.ts +2 -0
- package/desktop/appcontainer/Banner.ts +2 -2
- package/desktop/cmp/appbar/AppBar.ts +8 -6
- package/desktop/cmp/button/Button.ts +14 -3
- package/desktop/cmp/button/ButtonGroup.ts +14 -3
- package/desktop/cmp/button/ZoneMapperButton.ts +82 -0
- package/desktop/cmp/button/index.ts +1 -0
- package/desktop/cmp/dash/canvas/DashCanvas.ts +14 -4
- package/desktop/cmp/dash/container/DashContainer.ts +11 -4
- package/desktop/cmp/dash/container/DashContainerModel.ts +3 -2
- package/desktop/cmp/dash/container/impl/DashContainerUtils.ts +4 -4
- package/desktop/cmp/dock/DockViewModel.ts +10 -8
- package/desktop/cmp/dock/impl/DockContainer.ts +1 -0
- package/desktop/cmp/error/ErrorMessage.ts +9 -8
- package/desktop/cmp/form/FormField.ts +34 -10
- package/desktop/cmp/grid/columns/Actions.ts +2 -1
- package/desktop/cmp/grid/impl/colchooser/ColChooser.ts +3 -2
- package/desktop/cmp/grouping/GroupingChooser.ts +29 -29
- package/desktop/cmp/input/ButtonGroupInput.ts +1 -1
- package/desktop/cmp/input/Checkbox.ts +3 -3
- package/desktop/cmp/input/CodeInput.ts +2 -1
- package/desktop/cmp/input/DateInput.ts +128 -123
- package/desktop/cmp/input/JsonInput.ts +1 -1
- package/desktop/cmp/input/NumberInput.ts +3 -2
- package/desktop/cmp/input/RadioInput.ts +3 -1
- package/desktop/cmp/input/Select.ts +31 -4
- package/desktop/cmp/input/SwitchInput.ts +2 -1
- package/desktop/cmp/input/TextArea.ts +3 -3
- package/desktop/cmp/input/TextInput.ts +51 -47
- package/desktop/cmp/panel/Panel.ts +21 -19
- package/desktop/cmp/panel/impl/ResizeContainer.ts +3 -2
- package/desktop/cmp/pinpad/impl/PinPad.ts +4 -3
- package/desktop/cmp/record/RecordActionBar.ts +12 -3
- package/desktop/cmp/record/impl/RecordActionButton.ts +1 -0
- package/desktop/cmp/rest/Actions.ts +10 -5
- package/desktop/cmp/rest/RestGrid.ts +20 -6
- package/desktop/cmp/rest/impl/RestForm.ts +5 -4
- package/desktop/cmp/rest/impl/RestGridToolbar.ts +3 -2
- package/desktop/cmp/tab/TabSwitcher.ts +8 -3
- package/desktop/cmp/tab/impl/Tab.ts +2 -1
- package/desktop/cmp/tab/impl/TabContainer.ts +18 -15
- package/desktop/cmp/toolbar/Toolbar.ts +3 -1
- package/desktop/cmp/treemap/SplitTreeMap.ts +2 -1
- package/desktop/cmp/treemap/TreeMap.ts +5 -3
- package/desktop/cmp/zoneGrid/impl/ZoneMapper.scss +71 -0
- package/desktop/cmp/zoneGrid/impl/ZoneMapper.ts +232 -0
- package/desktop/cmp/zoneGrid/impl/ZoneMapperDialog.ts +35 -0
- package/dynamics/desktop.ts +2 -0
- package/dynamics/mobile.ts +2 -0
- package/inspector/instances/InstancesModel.ts +3 -3
- package/mobile/appcontainer/AppContainer.ts +2 -0
- package/mobile/appcontainer/Banner.ts +2 -2
- package/mobile/cmp/button/ZoneMapperButton.ts +41 -0
- package/mobile/cmp/button/index.ts +1 -0
- package/mobile/cmp/error/ErrorMessage.ts +4 -4
- package/mobile/cmp/input/Select.scss +1 -0
- package/mobile/cmp/input/Select.ts +7 -0
- package/mobile/cmp/input/TextInput.ts +1 -0
- package/mobile/cmp/menu/impl/Menu.scss +7 -1
- package/mobile/cmp/panel/DialogPanel.scss +18 -6
- package/mobile/cmp/panel/DialogPanel.ts +3 -1
- package/mobile/cmp/zoneGrid/impl/ZoneMapper.scss +67 -0
- package/mobile/cmp/zoneGrid/impl/ZoneMapper.ts +236 -0
- package/package.json +4 -3
- package/styles/vars.scss +3 -3
- package/svc/InspectorService.ts +1 -1
- package/utils/js/DomUtils.ts +10 -0
- package/utils/js/LangUtils.ts +10 -0
- package/utils/js/TestUtils.ts +9 -0
- package/utils/js/index.ts +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,78 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 59.3.0 - 2023-11-09
|
|
4
|
+
|
|
5
|
+
### 🎁 New Features
|
|
6
|
+
|
|
7
|
+
* Improved Hoist support for automated testing via Playwright, Cypress, and similar tools:
|
|
8
|
+
* Core Hoist components now accept an optional `testId` prop, to be rendered at an appropriate
|
|
9
|
+
level of the DOM (within a `data-testid` HTML attribute). This can minimize the need to select
|
|
10
|
+
components using criteria such as CSS classes or labels that are more likely to change and
|
|
11
|
+
break tests.
|
|
12
|
+
* When given a `testId`, certain composite components will generate and set "sub-testIds" on
|
|
13
|
+
selected internal components. For example, a `TabContainer` will set a testId on each switcher
|
|
14
|
+
button (derived from its tabId), and a `Form` will set testIds on nested `FormField`
|
|
15
|
+
and `HoistInput` components (derived from their bound field names).
|
|
16
|
+
* This release represents a first step in ongoing work to facilitate automated end-to-end
|
|
17
|
+
testing of Hoist applications. Additional Hoist-specific utilities for writing tests in
|
|
18
|
+
libraries such as Cypress and Playwright are coming soon.
|
|
19
|
+
* Added new `ZoneGrid` component, a highly specialized `Grid` that always displays its data with
|
|
20
|
+
multi-line, full-width rows. Each row is broken into four zones (top/bottom and left/right),
|
|
21
|
+
each of which can mapped by the user to render data from one or more fields.
|
|
22
|
+
* Primarily intended for mobile, where horizontal scrolling can present usability issues, but
|
|
23
|
+
also available on desktop, where it can serve as an easily user-configurable `DataView`.
|
|
24
|
+
* Added `Column.sortToBottom` to force specified values to sort the bottom, regardless of sort
|
|
25
|
+
direction. Intended primarily to force null values to sort below all others.
|
|
26
|
+
* Upgraded the `RelativeTimestamp` component with a new `localDateMode` option to customize how
|
|
27
|
+
near-term date/time differences are rendered with regards to calendar days.
|
|
28
|
+
|
|
29
|
+
### 🐞 Bug Fixes
|
|
30
|
+
|
|
31
|
+
* Fixed bug where interacting with a `Select` within a `Popover` can inadvertently cause the
|
|
32
|
+
popover to close. If your app already has special handling in place to prevent this, you should
|
|
33
|
+
be able to unwind it after upgrading.
|
|
34
|
+
* Improved the behavior of the clear button in `TextInput`. Clearing a field no longer drops focus,
|
|
35
|
+
allowing the user to immediately begin typing in a new value.
|
|
36
|
+
* Fixed arguments passed to `ErrorMessageProps.actionFn` and `ErrorMessageProps.detailsFn`.
|
|
37
|
+
* Improved default error text in `ErrorMessage`.
|
|
38
|
+
|
|
39
|
+
### ⚙️ Technical
|
|
40
|
+
|
|
41
|
+
* Improved core `HoistComponent` performance by preventing unnecessary re-renderings triggered by
|
|
42
|
+
spurious model lookup changes.
|
|
43
|
+
* New flag `GridModel.experimental.enableFullWidthScroll` enables scrollbars to span pinned columns.
|
|
44
|
+
* Early test release behind the flag, expected to made the default behavior in next release.
|
|
45
|
+
* Renamed `XH.getActiveModels()` to `XH.getModels()` for clarity / consistency.
|
|
46
|
+
* API change, but not expected to impact applications.
|
|
47
|
+
* Added `XH.getModel()` convenience method to return the first matching model.
|
|
48
|
+
|
|
49
|
+
## 59.2.0 - 2023-10-16
|
|
50
|
+
|
|
51
|
+
### 🎁 New Features
|
|
52
|
+
|
|
53
|
+
* New `DockViewConfig.onClose` hook invoked when a user attempts to remove a `DockContainer` view.
|
|
54
|
+
* Added `GridModel` APIs to lookup and show / hide entire column groups.
|
|
55
|
+
* Left / right borders are now rendered along `Grid` `ColumnGroup` edges by default, controllable
|
|
56
|
+
with new `ColumnGroupSpec.borders` config.
|
|
57
|
+
* Enhanced the `CubeQuery` to support per-query post-processing functions
|
|
58
|
+
with `Query.omitFn`, `Query.bucketSpecFn` and `Query.lockFn`. These properties default to their
|
|
59
|
+
respective properties on `Cube`.
|
|
60
|
+
|
|
61
|
+
### 🐞 Bug Fixes
|
|
62
|
+
|
|
63
|
+
* `DashContainerModel` fixes:
|
|
64
|
+
* Fix bug where `addView` would throw when adding a view to a row or column
|
|
65
|
+
* Fix bug where `allowRemove` flag was dropped from state for containers
|
|
66
|
+
* Fix bug in `DockContainer` where adding / removing views would cause other views to be
|
|
67
|
+
remounted
|
|
68
|
+
* Fixed erroneous `GridModel` warning when using a tree column within a column group
|
|
69
|
+
* Fixed regression to alert banners. Resume allowing elements as messages.
|
|
70
|
+
* Fix `Grid` cell border styling inconsistencies.
|
|
71
|
+
|
|
72
|
+
### ⚙️ Typescript API Adjustments
|
|
73
|
+
|
|
74
|
+
* Added type for `ActionFnData.record`.
|
|
75
|
+
|
|
3
76
|
## 59.1.0 - 2023-09-20
|
|
4
77
|
|
|
5
78
|
### 🎁 New Features
|
|
@@ -24,7 +97,8 @@
|
|
|
24
97
|
* Improved styling for disabled `checkbox` inputs.
|
|
25
98
|
|
|
26
99
|
### ⚙️ Technical
|
|
27
|
-
|
|
100
|
+
|
|
101
|
+
* `XH.showException` has been deprecated. Use similar methods on `XH.exceptionHandler` instead.
|
|
28
102
|
|
|
29
103
|
### 📚 Libraries
|
|
30
104
|
|
package/admin/AppComponent.ts
CHANGED
|
@@ -30,7 +30,7 @@ export const AppComponent = hoistCmp({
|
|
|
30
30
|
const tbar = hoistCmp.factory<AppModel>(({model}) =>
|
|
31
31
|
appBar({
|
|
32
32
|
icon: Icon.gears({size: '2x', prefix: 'fal'}),
|
|
33
|
-
leftItems: [tabSwitcher({enableOverflow: true})],
|
|
33
|
+
leftItems: [tabSwitcher({testId: 'tab-switcher', enableOverflow: true})],
|
|
34
34
|
rightItems: [
|
|
35
35
|
button({
|
|
36
36
|
icon: Icon.openExternal(),
|
|
@@ -16,7 +16,7 @@ export const activityTab = hoistCmp.factory(() =>
|
|
|
16
16
|
tabContainer({
|
|
17
17
|
modelConfig: {
|
|
18
18
|
route: 'default.activity',
|
|
19
|
-
switcher: {orientation: 'left'},
|
|
19
|
+
switcher: {orientation: 'left', testId: 'activity-tab-switcher'},
|
|
20
20
|
tabs: [
|
|
21
21
|
{id: 'tracking', icon: Icon.analytics(), content: activityTrackingPanel},
|
|
22
22
|
{id: 'clientErrors', icon: Icon.warning(), content: clientErrorsPanel},
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import {configPanel} from '@xh/hoist/admin/tabs/general/config/ConfigPanel';
|
|
8
8
|
import {tabContainer} from '@xh/hoist/cmp/tab';
|
|
9
|
-
import {
|
|
9
|
+
import {hoistCmp, XH} from '@xh/hoist/core';
|
|
10
10
|
import {Icon} from '@xh/hoist/icon';
|
|
11
11
|
import {aboutPanel} from './about/AboutPanel';
|
|
12
12
|
import {alertBannerPanel} from './alertBanner/AlertBannerPanel';
|
|
@@ -16,7 +16,7 @@ export const generalTab = hoistCmp.factory(() =>
|
|
|
16
16
|
tabContainer({
|
|
17
17
|
modelConfig: {
|
|
18
18
|
route: 'default.general',
|
|
19
|
-
switcher: {orientation: 'left'},
|
|
19
|
+
switcher: {orientation: 'left', testId: 'general-tab-switcher'},
|
|
20
20
|
tabs: [
|
|
21
21
|
{id: 'about', icon: Icon.info(), content: aboutPanel},
|
|
22
22
|
{id: 'config', icon: Icon.settings(), content: configPanel},
|
|
@@ -11,7 +11,7 @@ import {HoistModel, LoadSpec, managed, XH, Intent, PlainObject} from '@xh/hoist/
|
|
|
11
11
|
import {dateIs, required} from '@xh/hoist/data';
|
|
12
12
|
import {action, makeObservable, observable} from '@xh/hoist/mobx';
|
|
13
13
|
import {AppModel} from '@xh/hoist/admin/AppModel';
|
|
14
|
-
import
|
|
14
|
+
import {some, sortBy, without} from 'lodash';
|
|
15
15
|
import {computed} from 'mobx';
|
|
16
16
|
|
|
17
17
|
export class AlertBannerModel extends HoistModel {
|
|
@@ -151,7 +151,7 @@ export class AlertBannerModel extends HoistModel {
|
|
|
151
151
|
@computed
|
|
152
152
|
get currentValuesSavedAsPreset() {
|
|
153
153
|
const {message, intent, iconName, enableClose} = this.formModel.values;
|
|
154
|
-
return
|
|
154
|
+
return some(this.savedPresets, {message, intent, iconName, enableClose});
|
|
155
155
|
}
|
|
156
156
|
|
|
157
157
|
async loadPresetsAsync() {
|
|
@@ -17,7 +17,7 @@ export const monitorTab = hoistCmp.factory(() => {
|
|
|
17
17
|
? tabContainer({
|
|
18
18
|
modelConfig: {
|
|
19
19
|
route: 'default.monitor',
|
|
20
|
-
switcher: {orientation: 'left'},
|
|
20
|
+
switcher: {orientation: 'left', testId: 'monitor-tab-switcher'},
|
|
21
21
|
tabs: [
|
|
22
22
|
{id: 'status', icon: Icon.shieldCheck(), content: monitorResultsPanel},
|
|
23
23
|
{id: 'config', icon: Icon.settings(), content: monitorEditorPanel}
|
|
@@ -20,7 +20,7 @@ export const serverTab = hoistCmp.factory(() =>
|
|
|
20
20
|
tabContainer({
|
|
21
21
|
modelConfig: {
|
|
22
22
|
route: 'default.server',
|
|
23
|
-
switcher: {orientation: 'left'},
|
|
23
|
+
switcher: {orientation: 'left', testId: 'server-tab-switcher'},
|
|
24
24
|
tabs: [
|
|
25
25
|
{id: 'logViewer', icon: Icon.fileText(), content: logViewer},
|
|
26
26
|
{id: 'logLevels', icon: Icon.settings(), content: logLevelPanel},
|
package/cmp/ag-grid/AgGrid.scss
CHANGED
|
@@ -5,6 +5,14 @@
|
|
|
5
5
|
* Copyright © 2023 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
@mixin group-border($side) {
|
|
9
|
+
border-#{$side}: var(--xh-border-solid);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@mixin pinned-border($side) {
|
|
13
|
+
border-#{$side}: 1px solid var(--xh-grid-pinned-column-border-color);
|
|
14
|
+
}
|
|
15
|
+
|
|
8
16
|
// Ag-grid installs an outer div around itself.
|
|
9
17
|
.xh-ag-grid > div {
|
|
10
18
|
width: 100%;
|
|
@@ -120,14 +128,17 @@
|
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
&--no-row-borders {
|
|
123
|
-
.ag-row
|
|
124
|
-
|
|
131
|
+
.ag-row,
|
|
132
|
+
.ag-cell {
|
|
133
|
+
border-bottom: none;
|
|
134
|
+
border-top: none;
|
|
135
|
+
}
|
|
125
136
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
137
|
+
// Deliberately keep border on full-width grouped rows even when we aren't adding row borders.
|
|
138
|
+
// Without this collapsed groups (which don't stripe) blend together in a solid block.
|
|
139
|
+
.ag-row.ag-row-group.ag-full-width-row {
|
|
140
|
+
border-bottom: 1px solid var(--xh-grid-group-border-color);
|
|
141
|
+
border-top: 1px solid var(--xh-grid-group-border-color);
|
|
131
142
|
}
|
|
132
143
|
}
|
|
133
144
|
|
|
@@ -187,8 +198,14 @@
|
|
|
187
198
|
}
|
|
188
199
|
}
|
|
189
200
|
|
|
190
|
-
.ag-cell
|
|
191
|
-
|
|
201
|
+
.ag-cell {
|
|
202
|
+
&.ag-cell-last-left-pinned:not(.ag-cell-focus) {
|
|
203
|
+
@include pinned-border(right);
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
&.ag-cell-first-right-pinned:not(.ag-cell-focus) {
|
|
207
|
+
@include pinned-border(left);
|
|
208
|
+
}
|
|
192
209
|
}
|
|
193
210
|
|
|
194
211
|
// We use flexbox to consistently vertically center cell contents across
|
|
@@ -227,21 +244,52 @@
|
|
|
227
244
|
&--no-cell-borders {
|
|
228
245
|
.ag-cell,
|
|
229
246
|
.ag-context-menu-open .ag-cell-focus:not(.ag-cell-range-selected) {
|
|
230
|
-
|
|
247
|
+
// Preserve left and right borders to avoid jumpiness upon cell focus
|
|
248
|
+
border-top: none;
|
|
249
|
+
border-bottom: none;
|
|
250
|
+
border-left-color: transparent;
|
|
251
|
+
border-right-color: transparent;
|
|
231
252
|
}
|
|
232
253
|
}
|
|
233
254
|
|
|
234
255
|
// Cell focus
|
|
235
256
|
&--no-cell-focus {
|
|
257
|
+
// Preserve cell borders when enabled upon "invisible" cell focus
|
|
258
|
+
&.xh-ag-grid--cell-borders .ag-has-focus .ag-cell-focus:not(.ag-cell-range-selected) {
|
|
259
|
+
border-right-color: var(--xh-grid-border-color);
|
|
260
|
+
}
|
|
261
|
+
|
|
236
262
|
.ag-has-focus {
|
|
237
263
|
.ag-cell-focus:not(.ag-cell-range-selected) {
|
|
238
|
-
|
|
264
|
+
// Preserve left and right borders to avoid jumpiness upon cell focus
|
|
265
|
+
border-top: none;
|
|
266
|
+
border-bottom: none;
|
|
267
|
+
border-left-color: transparent;
|
|
268
|
+
border-right-color: transparent;
|
|
269
|
+
|
|
270
|
+
&.ag-cell {
|
|
271
|
+
&.ag-cell-last-left-pinned {
|
|
272
|
+
@include pinned-border(right);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
&.ag-cell-first-right-pinned {
|
|
276
|
+
@include pinned-border(left);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
&.xh-cell--group-border-left {
|
|
280
|
+
@include group-border(left);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
&.xh-cell--group-border-right {
|
|
284
|
+
@include group-border(right);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
239
287
|
}
|
|
240
288
|
}
|
|
241
289
|
}
|
|
242
290
|
|
|
243
291
|
&--show-cell-focus {
|
|
244
|
-
.ag-cell-focus {
|
|
292
|
+
.ag-cell-focus:focus-within {
|
|
245
293
|
border-color: var(--xh-grid-cell-focus-border-color) !important;
|
|
246
294
|
}
|
|
247
295
|
}
|
package/cmp/ag-grid/AgGrid.ts
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
HoistProps,
|
|
13
13
|
LayoutProps,
|
|
14
14
|
lookup,
|
|
15
|
+
TestSupportProps,
|
|
15
16
|
useLocalModel,
|
|
16
17
|
uses,
|
|
17
18
|
XH
|
|
@@ -23,7 +24,11 @@ import {isNil} from 'lodash';
|
|
|
23
24
|
import './AgGrid.scss';
|
|
24
25
|
import {AgGridModel} from './AgGridModel';
|
|
25
26
|
|
|
26
|
-
export interface AgGridProps
|
|
27
|
+
export interface AgGridProps
|
|
28
|
+
extends HoistProps<AgGridModel>,
|
|
29
|
+
GridOptions,
|
|
30
|
+
LayoutProps,
|
|
31
|
+
TestSupportProps {}
|
|
27
32
|
|
|
28
33
|
/**
|
|
29
34
|
* Minimal wrapper for AgGridReact, supporting direct use of the ag-Grid component with limited
|
|
@@ -53,7 +58,7 @@ export const [AgGrid, agGrid] = hoistCmp.withFactory<AgGridProps>({
|
|
|
53
58
|
className: 'xh-ag-grid',
|
|
54
59
|
model: uses(AgGridModel),
|
|
55
60
|
|
|
56
|
-
render({model, className, ...props}, ref) {
|
|
61
|
+
render({model, className, testId, ...props}, ref) {
|
|
57
62
|
if (!AgGridReact) {
|
|
58
63
|
console.error(
|
|
59
64
|
'ag-Grid has not been imported in to this application. Please import and ' +
|
|
@@ -90,6 +95,7 @@ export const [AgGrid, agGrid] = hoistCmp.withFactory<AgGridProps>({
|
|
|
90
95
|
hideHeaders ? 'xh-ag-grid--hide-headers' : null
|
|
91
96
|
),
|
|
92
97
|
...layoutProps,
|
|
98
|
+
testId,
|
|
93
99
|
item: createElement(AgGridReact, {
|
|
94
100
|
...AgGrid['DEFAULT_PROPS'],
|
|
95
101
|
// Default some ag-grid props, but allow overriding.
|
package/cmp/badge/Badge.ts
CHANGED
|
@@ -4,9 +4,12 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2023 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
+
import {div} from '@xh/hoist/cmp/layout';
|
|
7
8
|
import {BoxProps, hoistCmp, HoistProps, Intent} from '@xh/hoist/core';
|
|
9
|
+
import {TEST_ID} from '@xh/hoist/utils/js';
|
|
10
|
+
import {splitLayoutProps} from '@xh/hoist/utils/react';
|
|
8
11
|
import classNames from 'classnames';
|
|
9
|
-
import {
|
|
12
|
+
import {merge} from 'lodash';
|
|
10
13
|
import './Badge.scss';
|
|
11
14
|
|
|
12
15
|
export interface BadgeProps extends HoistProps, BoxProps {
|
|
@@ -26,8 +29,10 @@ export const [Badge, badge] = hoistCmp.withFactory<BadgeProps>({
|
|
|
26
29
|
|
|
27
30
|
className: 'xh-badge',
|
|
28
31
|
|
|
29
|
-
render(
|
|
30
|
-
const classes = []
|
|
32
|
+
render(props, ref) {
|
|
33
|
+
const classes = [],
|
|
34
|
+
[layoutProps, {className, intent, compact, children, testId, ...restProps}] =
|
|
35
|
+
splitLayoutProps(props);
|
|
31
36
|
|
|
32
37
|
if (intent) {
|
|
33
38
|
classes.push(`xh-badge--intent-${intent}`);
|
|
@@ -37,9 +42,17 @@ export const [Badge, badge] = hoistCmp.withFactory<BadgeProps>({
|
|
|
37
42
|
classes.push('xh-badge--compact');
|
|
38
43
|
}
|
|
39
44
|
|
|
45
|
+
const divProps = merge(
|
|
46
|
+
{className: classNames(className, classes)},
|
|
47
|
+
{style: layoutProps},
|
|
48
|
+
{[TEST_ID]: testId},
|
|
49
|
+
restProps
|
|
50
|
+
);
|
|
51
|
+
|
|
40
52
|
return div({
|
|
41
|
-
|
|
42
|
-
...
|
|
53
|
+
ref,
|
|
54
|
+
...divProps,
|
|
55
|
+
items: children
|
|
43
56
|
});
|
|
44
57
|
}
|
|
45
58
|
});
|
package/cmp/chart/Chart.ts
CHANGED
|
@@ -6,19 +6,20 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import composeRefs from '@seznam/compose-react-refs';
|
|
8
8
|
import {box, div} from '@xh/hoist/cmp/layout';
|
|
9
|
-
import {placeholder} from '../layout';
|
|
10
9
|
import {
|
|
11
|
-
lookup,
|
|
12
10
|
hoistCmp,
|
|
13
11
|
HoistModel,
|
|
12
|
+
HoistProps,
|
|
13
|
+
LayoutProps,
|
|
14
|
+
lookup,
|
|
15
|
+
PlainObject,
|
|
16
|
+
TestSupportProps,
|
|
14
17
|
useLocalModel,
|
|
15
18
|
uses,
|
|
16
|
-
XH
|
|
17
|
-
BoxProps,
|
|
18
|
-
HoistProps,
|
|
19
|
-
PlainObject
|
|
19
|
+
XH
|
|
20
20
|
} from '@xh/hoist/core';
|
|
21
21
|
import {useContextMenu} from '@xh/hoist/dynamics/desktop';
|
|
22
|
+
import {Icon} from '@xh/hoist/icon';
|
|
22
23
|
import {Highcharts} from '@xh/hoist/kit/highcharts';
|
|
23
24
|
import {runInAction} from '@xh/hoist/mobx';
|
|
24
25
|
import {
|
|
@@ -28,18 +29,18 @@ import {
|
|
|
28
29
|
useOnVisibleChange
|
|
29
30
|
} from '@xh/hoist/utils/react';
|
|
30
31
|
import {assign, castArray, cloneDeep, forOwn, isEqual, isPlainObject, merge, omit} from 'lodash';
|
|
31
|
-
import {
|
|
32
|
+
import {placeholder} from '../layout';
|
|
33
|
+
import './Chart.scss';
|
|
32
34
|
import {ChartModel} from './ChartModel';
|
|
33
|
-
import {installZoomoutGesture} from './impl/zoomout';
|
|
34
35
|
import {installCopyToClipboard} from './impl/copyToClipboard';
|
|
36
|
+
import {installZoomoutGesture} from './impl/zoomout';
|
|
35
37
|
import {DarkTheme} from './theme/Dark';
|
|
36
38
|
import {LightTheme} from './theme/Light';
|
|
37
|
-
import './Chart.scss';
|
|
38
39
|
|
|
39
40
|
installZoomoutGesture(Highcharts);
|
|
40
41
|
installCopyToClipboard(Highcharts);
|
|
41
42
|
|
|
42
|
-
export interface ChartProps extends HoistProps<ChartModel>,
|
|
43
|
+
export interface ChartProps extends HoistProps<ChartModel>, LayoutProps, TestSupportProps {
|
|
43
44
|
/**
|
|
44
45
|
* Ratio of width-to-height of displayed chart. If defined and greater than 0, the chart will
|
|
45
46
|
* respect this ratio within the available space. Otherwise, the chart will stretch on both
|
|
@@ -58,7 +59,7 @@ export const [Chart, chart] = hoistCmp.withFactory<ChartProps>({
|
|
|
58
59
|
model: uses(ChartModel),
|
|
59
60
|
className: 'xh-chart',
|
|
60
61
|
|
|
61
|
-
render({model, className, aspectRatio, ...props}, ref) {
|
|
62
|
+
render({model, className, aspectRatio, testId, ...props}, ref) {
|
|
62
63
|
if (!Highcharts) {
|
|
63
64
|
console.error(
|
|
64
65
|
'Highcharts has not been imported in to this application. Please import and ' +
|
|
@@ -85,6 +86,7 @@ export const [Chart, chart] = hoistCmp.withFactory<ChartProps>({
|
|
|
85
86
|
const coreContents = box({
|
|
86
87
|
...layoutProps,
|
|
87
88
|
className,
|
|
89
|
+
testId,
|
|
88
90
|
ref,
|
|
89
91
|
item: div({
|
|
90
92
|
style: {margin: 'auto'},
|
package/cmp/clock/Clock.ts
CHANGED
|
@@ -6,16 +6,16 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import {box, span} from '@xh/hoist/cmp/layout';
|
|
8
8
|
import {
|
|
9
|
+
BoxProps,
|
|
9
10
|
hoistCmp,
|
|
10
11
|
HoistModel,
|
|
12
|
+
HoistProps,
|
|
11
13
|
managed,
|
|
12
|
-
BoxProps,
|
|
13
14
|
useLocalModel,
|
|
14
|
-
XH
|
|
15
|
-
HoistProps
|
|
15
|
+
XH
|
|
16
16
|
} from '@xh/hoist/core';
|
|
17
17
|
import {fmtDate, TIME_FMT} from '@xh/hoist/format';
|
|
18
|
-
import {action,
|
|
18
|
+
import {action, makeObservable, observable} from '@xh/hoist/mobx';
|
|
19
19
|
import {Timer} from '@xh/hoist/utils/async';
|
|
20
20
|
import {MINUTES, ONE_SECOND} from '@xh/hoist/utils/datetime';
|
|
21
21
|
import {isNumber} from 'lodash';
|
|
@@ -54,11 +54,12 @@ export const [Clock, clock] = hoistCmp.withFactory<ClockProps>({
|
|
|
54
54
|
displayName: 'Clock',
|
|
55
55
|
className: 'xh-clock',
|
|
56
56
|
|
|
57
|
-
render({className, ...props}, ref) {
|
|
57
|
+
render({className, testId, ...props}, ref) {
|
|
58
58
|
const impl = useLocalModel(ClockLocalModel);
|
|
59
59
|
return box({
|
|
60
60
|
className,
|
|
61
61
|
...getLayoutProps(props),
|
|
62
|
+
testId,
|
|
62
63
|
ref,
|
|
63
64
|
item: span(impl.display)
|
|
64
65
|
});
|
package/cmp/dataview/DataView.ts
CHANGED
|
@@ -7,12 +7,13 @@
|
|
|
7
7
|
import {AgGrid} from '@xh/hoist/cmp/ag-grid';
|
|
8
8
|
import {grid} from '@xh/hoist/cmp/grid';
|
|
9
9
|
import {
|
|
10
|
-
BoxProps,
|
|
11
10
|
hoistCmp,
|
|
12
11
|
HoistModel,
|
|
13
12
|
HoistProps,
|
|
13
|
+
LayoutProps,
|
|
14
14
|
lookup,
|
|
15
15
|
PlainObject,
|
|
16
|
+
TestSupportProps,
|
|
16
17
|
useLocalModel,
|
|
17
18
|
uses
|
|
18
19
|
} from '@xh/hoist/core';
|
|
@@ -22,7 +23,7 @@ import {isFunction, merge} from 'lodash';
|
|
|
22
23
|
import './DataView.scss';
|
|
23
24
|
import {DataViewModel} from './DataViewModel';
|
|
24
25
|
|
|
25
|
-
export interface DataViewProps extends HoistProps<DataViewModel>,
|
|
26
|
+
export interface DataViewProps extends HoistProps<DataViewModel>, LayoutProps, TestSupportProps {
|
|
26
27
|
/**
|
|
27
28
|
* Options for ag-Grid's API.
|
|
28
29
|
*
|
|
@@ -44,13 +45,14 @@ export const [DataView, dataView] = hoistCmp.withFactory<DataViewProps>({
|
|
|
44
45
|
model: uses(DataViewModel),
|
|
45
46
|
className: 'xh-data-view',
|
|
46
47
|
|
|
47
|
-
render({model, className, ...props}, ref) {
|
|
48
|
+
render({model, className, testId, ...props}, ref) {
|
|
48
49
|
const [layoutProps] = splitLayoutProps(props),
|
|
49
50
|
impl = useLocalModel(DataViewLocalModel);
|
|
50
51
|
|
|
51
52
|
return grid({
|
|
52
53
|
...layoutProps,
|
|
53
54
|
className,
|
|
55
|
+
testId,
|
|
54
56
|
ref,
|
|
55
57
|
model: model.gridModel,
|
|
56
58
|
agOptions: impl.agOptions
|
package/cmp/form/Form.ts
CHANGED
|
@@ -4,12 +4,19 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2023 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
DefaultHoistProps,
|
|
9
|
+
elementFactory,
|
|
10
|
+
hoistCmp,
|
|
11
|
+
HoistProps,
|
|
12
|
+
TestSupportProps,
|
|
13
|
+
uses
|
|
14
|
+
} from '@xh/hoist/core';
|
|
15
|
+
import {useCached} from '@xh/hoist/utils/react';
|
|
8
16
|
import equal from 'fast-deep-equal';
|
|
9
17
|
import {createContext, useContext} from 'react';
|
|
10
|
-
import {useCached} from '@xh/hoist/utils/react';
|
|
11
|
-
import {FormModel} from './FormModel';
|
|
12
18
|
import {BaseFormFieldProps} from './BaseFormFieldProps';
|
|
19
|
+
import {FormModel} from './FormModel';
|
|
13
20
|
|
|
14
21
|
/** @internal */
|
|
15
22
|
export interface FormContextType {
|
|
@@ -18,13 +25,21 @@ export interface FormContextType {
|
|
|
18
25
|
|
|
19
26
|
/** Reference to associated FormModel. */
|
|
20
27
|
model?: FormModel;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Not rendered into the DOM directly - `Form` is a context provider and not a concrete
|
|
31
|
+
* component - but will auto-generate and apply a testId of `${formTestId}-${fieldName}`
|
|
32
|
+
* for every child {@link FormField} component, providing a centralized way to wire up
|
|
33
|
+
* a form and all of its fields for testing.
|
|
34
|
+
*/
|
|
35
|
+
testId?: string;
|
|
21
36
|
}
|
|
22
37
|
|
|
23
38
|
/** @internal */
|
|
24
39
|
export const FormContext = createContext<FormContextType>({});
|
|
25
40
|
const formContextProvider = elementFactory(FormContext.Provider);
|
|
26
41
|
|
|
27
|
-
export interface FormProps extends HoistProps<FormModel
|
|
42
|
+
export interface FormProps extends HoistProps<FormModel>, TestSupportProps {
|
|
28
43
|
/**
|
|
29
44
|
* Defaults for certain props on child/nested FormFields.
|
|
30
45
|
* @see FormField (note there are both desktop and mobile implementations).
|
|
@@ -50,14 +65,18 @@ export const [Form, form] = hoistCmp.withFactory<FormProps>({
|
|
|
50
65
|
displayName: 'Form',
|
|
51
66
|
model: uses(FormModel, {publishMode: 'none'}),
|
|
52
67
|
|
|
53
|
-
render({model, fieldDefaults = {}, children}) {
|
|
68
|
+
render({model, fieldDefaults = {}, testId, children}) {
|
|
54
69
|
// gather own and inherited field defaults...
|
|
55
70
|
const parentDefaults = useContext(FormContext).fieldDefaults;
|
|
56
71
|
if (parentDefaults) fieldDefaults = {...parentDefaults, ...fieldDefaults};
|
|
57
72
|
|
|
58
73
|
// ...and deliver as a cached context to avoid spurious re-renders
|
|
59
74
|
const formContext = useCached(
|
|
60
|
-
{
|
|
75
|
+
{
|
|
76
|
+
model,
|
|
77
|
+
fieldDefaults,
|
|
78
|
+
testId
|
|
79
|
+
},
|
|
61
80
|
(a, b) => a.model === b.model && equal(a.fieldDefaults, b.fieldDefaults)
|
|
62
81
|
);
|
|
63
82
|
return formContextProvider({value: formContext, items: children});
|
package/cmp/grid/Grid.scss
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
@use 'sass:math';
|
|
9
|
+
@use '../ag-grid/AgGrid';
|
|
9
10
|
|
|
10
11
|
.xh-grid:not(.xh-data-view) {
|
|
11
12
|
//------------------------
|
|
@@ -124,6 +125,15 @@
|
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
// Render left / right group borders
|
|
129
|
+
.ag-cell.xh-cell--group-border-left {
|
|
130
|
+
@include AgGrid.group-border(left);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
.ag-cell.xh-cell--group-border-right {
|
|
134
|
+
@include AgGrid.group-border(right);
|
|
135
|
+
}
|
|
136
|
+
|
|
127
137
|
.xh-ag-grid {
|
|
128
138
|
&--tiny {
|
|
129
139
|
.ag-cell.xh-cell--invalid::before {
|