@xh/hoist 56.0.0 → 56.2.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 +18 -4
- package/admin/tabs/general/about/AboutPanel.ts +4 -3
- package/admin/tabs/monitor/MonitorColumns.ts +32 -4
- package/admin/tabs/server/memory/MemoryMonitorModel.ts +80 -16
- package/admin/tabs/server/memory/MemoryMonitorPanel.ts +22 -1
- package/cmp/ag-grid/AgGrid.ts +19 -7
- package/cmp/filter/FilterChooserModel.ts +2 -2
- package/cmp/form/Form.ts +2 -9
- package/cmp/form/FormModel.ts +1 -1
- package/cmp/grid/Grid.ts +68 -25
- package/core/impl/InstallServices.ts +1 -1
- package/data/RecordAction.ts +1 -1
- package/data/Store.ts +1 -1
- package/data/StoreRecord.ts +2 -2
- package/data/cube/Cube.ts +3 -3
- package/data/cube/CubeField.ts +2 -5
- package/data/cube/View.ts +1 -1
- package/data/validation/Rule.ts +3 -3
- package/desktop/cmp/dash/DashViewModel.ts +2 -1
- package/desktop/cmp/dash/container/DashContainerModel.ts +10 -3
- package/desktop/cmp/error/ErrorMessage.ts +2 -2
- package/desktop/cmp/input/CodeInput.ts +2 -2
- package/desktop/cmp/treemap/TreeMapModel.ts +1 -1
- package/kit/ag-grid/index.ts +1 -0
- package/mobile/cmp/error/ErrorMessage.ts +2 -2
- package/mobile/cmp/input/DateInput.ts +2 -2
- package/mobile/cmp/popover/Popover.ts +10 -2
- package/package.json +1 -1
- package/utils/js/LangUtils.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 57.0.0-SNAPSHOT - unreleased
|
|
4
|
+
|
|
5
|
+
## 56.2.0 - 2023-04-28
|
|
6
|
+
* Expose `margin` property on DashContainerModel.
|
|
7
|
+
|
|
8
|
+
### ⚙️ Technical
|
|
9
|
+
* Optimize scrolling performance for `Grid` and `DataView`
|
|
10
|
+
|
|
11
|
+
## 56.1.0 - 2023-04-14
|
|
12
|
+
* Add support for new memory management diagnostics provided by hoist-core
|
|
13
|
+
(requires hoist-core 16.1.0 for full operation).
|
|
14
|
+
|
|
15
|
+
### 🐞 Bug Fixes
|
|
16
|
+
* Fixes bug with display/reporting of exceptions during app initialization sequence.
|
|
17
|
+
|
|
3
18
|
## v56.0.0 - 2023-03-29
|
|
4
19
|
|
|
5
20
|
### 🎁 New Features
|
|
@@ -10,8 +25,6 @@
|
|
|
10
25
|
* New `FetchService.abort()` API allows manually aborting a pending fetch request.
|
|
11
26
|
* Hoist exceptions have been enhanced and standardized, including new TypeScript types. The
|
|
12
27
|
`Error.cause` property is now populated for wrapping exceptions.
|
|
13
|
-
* `PanelModel` now supports a `defaultSize` property specified in percentage as well as pixels
|
|
14
|
-
(e.g. `defaultSize: '20%'` as well as `defaultSize: 200`).
|
|
15
28
|
* New `GridModel.headerMenuDisplay` config for limiting column header menu visibility to on hover.
|
|
16
29
|
|
|
17
30
|
### 💥 Breaking Changes
|
|
@@ -20,10 +33,11 @@
|
|
|
20
33
|
* Requires AG Grid v29.0.0 or higher - update your AG Grid dependency in your app's `package.json`
|
|
21
34
|
file. See the [AG Grid Changelog](https://www.ag-grid.com/changelog) for details.
|
|
22
35
|
* Add a dependency on `@ag-grid-community/styles` to import new dedicated styles package.
|
|
23
|
-
* Imports of AG Grid CSS files within your app's `Bootstrap.ts` file will also need to be
|
|
36
|
+
* Imports of AG Grid CSS files within your app's `Bootstrap.ts` file will also need to be
|
|
37
|
+
updated to import styles from their new location. The recommended imports are now:
|
|
24
38
|
```typescript
|
|
25
39
|
import '@ag-grid-community/styles/ag-grid.css';
|
|
26
|
-
import '@ag-grid-community/styles/ag-theme-balham
|
|
40
|
+
import '@ag-grid-community/styles/ag-theme-balham.css';
|
|
27
41
|
```
|
|
28
42
|
* New `xhActivityTrackingConfig` soft-configuration entry places new limits on the size of
|
|
29
43
|
any `data` objects passed to `XH.track()` calls.
|
|
@@ -91,13 +91,14 @@ function renderBlurb() {
|
|
|
91
91
|
xhLogo(),
|
|
92
92
|
div(
|
|
93
93
|
p(
|
|
94
|
-
'Built with Hoist
|
|
94
|
+
'Built with Hoist, a toolkit for rapid application development from ',
|
|
95
95
|
a({
|
|
96
|
-
href: '
|
|
96
|
+
href: 'https://xh.io',
|
|
97
97
|
target: '_blank',
|
|
98
98
|
rel: 'noopener noreferrer',
|
|
99
99
|
item: 'Extremely Heavy'
|
|
100
|
-
})
|
|
100
|
+
}),
|
|
101
|
+
'.'
|
|
101
102
|
),
|
|
102
103
|
p(
|
|
103
104
|
'Please contact ',
|
|
@@ -9,7 +9,8 @@ import * as Col from '@xh/hoist/cmp/grid/columns';
|
|
|
9
9
|
import {ColumnSpec} from '@xh/hoist/cmp/grid/columns';
|
|
10
10
|
|
|
11
11
|
const mbCol = {width: 150, renderer: numberRenderer({precision: 2, withCommas: true})},
|
|
12
|
-
pctCol = {width: 150, renderer: numberRenderer({precision: 2, withCommas: true, label: '%'})}
|
|
12
|
+
pctCol = {width: 150, renderer: numberRenderer({precision: 2, withCommas: true, label: '%'})},
|
|
13
|
+
msCol = {width: 150, renderer: numberRenderer({precision: 0, withCommas: false})};
|
|
13
14
|
|
|
14
15
|
export const metricUnit: ColumnSpec = {
|
|
15
16
|
field: {name: 'metricUnit', type: 'string'},
|
|
@@ -84,11 +85,38 @@ export const usedHeapMb: ColumnSpec = {
|
|
|
84
85
|
...mbCol
|
|
85
86
|
};
|
|
86
87
|
|
|
87
|
-
export const
|
|
88
|
+
export const usedPctMax: ColumnSpec = {
|
|
88
89
|
field: {
|
|
89
|
-
name: '
|
|
90
|
+
name: 'usedPctMax',
|
|
90
91
|
type: 'number',
|
|
91
|
-
displayName: 'Used (pct
|
|
92
|
+
displayName: 'Used (pct Max)'
|
|
93
|
+
},
|
|
94
|
+
...pctCol
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
export const avgCollectionTime: ColumnSpec = {
|
|
98
|
+
field: {
|
|
99
|
+
name: 'avgCollectionTime',
|
|
100
|
+
type: 'number',
|
|
101
|
+
displayName: 'Avg (ms)'
|
|
102
|
+
},
|
|
103
|
+
...msCol
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
export const collectionCount: ColumnSpec = {
|
|
107
|
+
field: {
|
|
108
|
+
name: 'collectionCount',
|
|
109
|
+
type: 'number',
|
|
110
|
+
displayName: '# GCs'
|
|
111
|
+
},
|
|
112
|
+
...msCol
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
export const pctCollectionTime: ColumnSpec = {
|
|
116
|
+
field: {
|
|
117
|
+
name: 'pctCollectionTime',
|
|
118
|
+
type: 'number',
|
|
119
|
+
displayName: '% Time in GC'
|
|
92
120
|
},
|
|
93
121
|
...pctCol
|
|
94
122
|
};
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
import {ChartModel} from '@xh/hoist/cmp/chart';
|
|
8
8
|
import {GridModel} from '@xh/hoist/cmp/grid';
|
|
9
9
|
import {HoistModel, LoadSpec, managed, XH} from '@xh/hoist/core';
|
|
10
|
+
import {lengthIs, required} from '@xh/hoist/data';
|
|
10
11
|
import {fmtTime} from '@xh/hoist/format';
|
|
12
|
+
import {Icon} from '@xh/hoist/icon';
|
|
11
13
|
import {forOwn, sortBy} from 'lodash';
|
|
12
14
|
import * as MCol from '../../monitor/MonitorColumns';
|
|
13
15
|
|
|
@@ -15,6 +17,14 @@ export class MemoryMonitorModel extends HoistModel {
|
|
|
15
17
|
@managed gridModel: GridModel;
|
|
16
18
|
@managed chartModel: ChartModel;
|
|
17
19
|
|
|
20
|
+
get enabled(): boolean {
|
|
21
|
+
return this.conf.enabled;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
get heapDumpDir(): string {
|
|
25
|
+
return this.conf.heapDumpDir;
|
|
26
|
+
}
|
|
27
|
+
|
|
18
28
|
constructor() {
|
|
19
29
|
super();
|
|
20
30
|
|
|
@@ -24,13 +34,25 @@ export class MemoryMonitorModel extends HoistModel {
|
|
|
24
34
|
filterModel: true,
|
|
25
35
|
store: {idSpec: 'timestamp'},
|
|
26
36
|
colDefaults: {filterable: true},
|
|
37
|
+
headerMenuDisplay: 'hover',
|
|
27
38
|
columns: [
|
|
28
39
|
MCol.timestamp,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
{
|
|
41
|
+
groupId: 'heap',
|
|
42
|
+
headerAlign: 'center',
|
|
43
|
+
children: [
|
|
44
|
+
MCol.totalHeapMb,
|
|
45
|
+
MCol.maxHeapMb,
|
|
46
|
+
MCol.freeHeapMb,
|
|
47
|
+
MCol.usedHeapMb,
|
|
48
|
+
MCol.usedPctMax
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
groupId: 'GC',
|
|
53
|
+
headerAlign: 'center',
|
|
54
|
+
children: [MCol.collectionCount, MCol.avgCollectionTime, MCol.pctCollectionTime]
|
|
55
|
+
}
|
|
34
56
|
]
|
|
35
57
|
});
|
|
36
58
|
|
|
@@ -58,12 +80,14 @@ export class MemoryMonitorModel extends HoistModel {
|
|
|
58
80
|
yAxis: [
|
|
59
81
|
{
|
|
60
82
|
floor: 0,
|
|
61
|
-
|
|
83
|
+
height: '20%',
|
|
84
|
+
title: {text: 'GC Avg (ms)'}
|
|
62
85
|
},
|
|
63
86
|
{
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
87
|
+
floor: 0,
|
|
88
|
+
top: '30%',
|
|
89
|
+
height: '70%',
|
|
90
|
+
title: {text: 'Heap (mb)'}
|
|
67
91
|
}
|
|
68
92
|
],
|
|
69
93
|
tooltip: {outside: true, shared: true}
|
|
@@ -91,34 +115,46 @@ export class MemoryMonitorModel extends HoistModel {
|
|
|
91
115
|
// Process further for chart series.
|
|
92
116
|
const maxSeries = [],
|
|
93
117
|
totalSeries = [],
|
|
94
|
-
usedSeries = []
|
|
118
|
+
usedSeries = [],
|
|
119
|
+
avgGCSeries = [];
|
|
95
120
|
|
|
96
121
|
snaps.forEach(snap => {
|
|
97
122
|
maxSeries.push([snap.timestamp, snap.maxHeapMb]);
|
|
98
123
|
totalSeries.push([snap.timestamp, snap.totalHeapMb]);
|
|
99
124
|
usedSeries.push([snap.timestamp, snap.usedHeapMb]);
|
|
125
|
+
|
|
126
|
+
avgGCSeries.push([snap.timestamp, snap.avgCollectionTime]);
|
|
100
127
|
});
|
|
101
128
|
|
|
102
129
|
chartModel.setSeries([
|
|
103
130
|
{
|
|
104
|
-
name: '
|
|
131
|
+
name: 'GC Avg',
|
|
132
|
+
data: avgGCSeries,
|
|
133
|
+
step: true,
|
|
134
|
+
yAxis: 0
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
name: 'Heap Max',
|
|
105
138
|
data: maxSeries,
|
|
106
139
|
color: '#ef6c00',
|
|
107
|
-
step: true
|
|
140
|
+
step: true,
|
|
141
|
+
yAxis: 1
|
|
108
142
|
},
|
|
109
143
|
{
|
|
110
|
-
name: 'Total',
|
|
144
|
+
name: 'Heap Total',
|
|
111
145
|
data: totalSeries,
|
|
112
146
|
color: '#1976d2',
|
|
113
|
-
step: true
|
|
147
|
+
step: true,
|
|
148
|
+
yAxis: 1
|
|
114
149
|
},
|
|
115
150
|
{
|
|
116
|
-
name: 'Used',
|
|
151
|
+
name: 'Heap Used',
|
|
117
152
|
type: 'area',
|
|
118
153
|
data: usedSeries,
|
|
119
154
|
color: '#bd7c7c',
|
|
120
155
|
fillOpacity: 0.3,
|
|
121
|
-
lineWidth: 1
|
|
156
|
+
lineWidth: 1,
|
|
157
|
+
yAxis: 1
|
|
122
158
|
}
|
|
123
159
|
]);
|
|
124
160
|
} catch (e) {
|
|
@@ -145,4 +181,32 @@ export class MemoryMonitorModel extends HoistModel {
|
|
|
145
181
|
XH.handleException(e);
|
|
146
182
|
}
|
|
147
183
|
}
|
|
184
|
+
|
|
185
|
+
async dumpHeapAsync() {
|
|
186
|
+
try {
|
|
187
|
+
const appEnv = XH.getEnv('appEnvironment').toLowerCase(),
|
|
188
|
+
filename = await XH.prompt({
|
|
189
|
+
title: 'Dump Heap',
|
|
190
|
+
icon: Icon.fileArchive(),
|
|
191
|
+
message: `Specify a filename for the heap dump (to be saved in ${this.heapDumpDir})`,
|
|
192
|
+
input: {
|
|
193
|
+
rules: [required, lengthIs({min: 3, max: 250})],
|
|
194
|
+
initialValue: `${XH.appCode}_${appEnv}_${Date.now()}.hprof`
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
if (!filename) return;
|
|
198
|
+
await XH.fetchJson({
|
|
199
|
+
url: 'memoryMonitorAdmin/dumpHeap',
|
|
200
|
+
params: {filename}
|
|
201
|
+
}).linkTo(this.loadModel);
|
|
202
|
+
await this.loadAsync();
|
|
203
|
+
XH.successToast('Heap dumped successfully to ' + filename);
|
|
204
|
+
} catch (e) {
|
|
205
|
+
XH.handleException(e);
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
private get conf() {
|
|
210
|
+
return XH.getConf('xhMemoryMonitoringConfig', {heapDumpDir: null, enabled: true});
|
|
211
|
+
}
|
|
148
212
|
}
|
|
@@ -10,15 +10,24 @@ import {grid, gridCountLabel} from '@xh/hoist/cmp/grid';
|
|
|
10
10
|
import {filler} from '@xh/hoist/cmp/layout';
|
|
11
11
|
import {creates, hoistCmp} from '@xh/hoist/core';
|
|
12
12
|
import {button, exportButton} from '@xh/hoist/desktop/cmp/button';
|
|
13
|
+
import {errorMessage} from '@xh/hoist/desktop/cmp/error';
|
|
13
14
|
import {panel} from '@xh/hoist/desktop/cmp/panel';
|
|
14
15
|
import {Icon} from '@xh/hoist/icon';
|
|
15
16
|
import {AppModel} from '@xh/hoist/admin/AppModel';
|
|
17
|
+
import {isNil} from 'lodash';
|
|
16
18
|
|
|
17
19
|
export const memoryMonitorPanel = hoistCmp.factory({
|
|
18
20
|
model: creates(MemoryMonitorModel),
|
|
19
21
|
|
|
20
22
|
render({model}) {
|
|
21
|
-
|
|
23
|
+
if (!model.enabled) {
|
|
24
|
+
return errorMessage({
|
|
25
|
+
error: 'Memory Monitoring disabled via xhMemoryMonitoringConfig.'
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const {readonly} = AppModel,
|
|
30
|
+
dumpDisabled = isNil(model.heapDumpDir);
|
|
22
31
|
return panel({
|
|
23
32
|
tbar: [
|
|
24
33
|
button({
|
|
@@ -27,6 +36,7 @@ export const memoryMonitorPanel = hoistCmp.factory({
|
|
|
27
36
|
omit: readonly,
|
|
28
37
|
onClick: () => model.takeSnapshotAsync()
|
|
29
38
|
}),
|
|
39
|
+
'-',
|
|
30
40
|
button({
|
|
31
41
|
text: 'Request GC',
|
|
32
42
|
icon: Icon.trash(),
|
|
@@ -34,6 +44,17 @@ export const memoryMonitorPanel = hoistCmp.factory({
|
|
|
34
44
|
omit: readonly,
|
|
35
45
|
onClick: () => model.requestGcAsync()
|
|
36
46
|
}),
|
|
47
|
+
button({
|
|
48
|
+
text: 'Dump Heap',
|
|
49
|
+
icon: Icon.fileArchive(),
|
|
50
|
+
intent: 'danger',
|
|
51
|
+
omit: readonly,
|
|
52
|
+
disabled: dumpDisabled,
|
|
53
|
+
tooltip: dumpDisabled
|
|
54
|
+
? 'Missing required config xhMemoryMonitoringConfig.heapDumpDir'
|
|
55
|
+
: null,
|
|
56
|
+
onClick: () => model.dumpHeapAsync()
|
|
57
|
+
}),
|
|
37
58
|
filler(),
|
|
38
59
|
gridCountLabel({unit: 'snapshot'}),
|
|
39
60
|
'-',
|
package/cmp/ag-grid/AgGrid.ts
CHANGED
|
@@ -35,13 +35,18 @@ export interface AgGridProps extends HoistProps<AgGridModel>, GridOptions, Layou
|
|
|
35
35
|
* via the `model` prop to control additional Hoist customizations.
|
|
36
36
|
*
|
|
37
37
|
* This component complements and contrasts with the primary Hoist `Grid` class, which provides a
|
|
38
|
-
* significantly more managed and opinionated
|
|
38
|
+
* significantly more managed and opinionated use of ag-Grid and a number of Hoist-specific
|
|
39
39
|
* extensions and customizations. That fully managed component is expected to cover the majority of
|
|
40
40
|
* use cases within Hoist apps and is recommended as the primary grid class within the toolkit.
|
|
41
41
|
*
|
|
42
42
|
* This wrapper is provided for advanced usages of grid that wish to leverage features of the
|
|
43
43
|
* underlying component not yet supported by the Hoist layer - most notably pivoting - where the
|
|
44
44
|
* managed option would conflict with or complicate access to those features.
|
|
45
|
+
*
|
|
46
|
+
* Note that this component uses the ag-Grid `getRowHeight` prop to provide the grid with row
|
|
47
|
+
* heights. As of 4/2023, this may cause scrolling to be slow in large data sets, and
|
|
48
|
+
* applications may wish to set this prop to `null` and use either a fixed `rowWidth` property, or
|
|
49
|
+
* an explicit per-row setting instead. See GridModel for a more efficient, data aware approach.
|
|
45
50
|
*/
|
|
46
51
|
export const [AgGrid, agGrid] = hoistCmp.withFactory<AgGridProps>({
|
|
47
52
|
displayName: 'AgGrid',
|
|
@@ -125,8 +130,10 @@ class AgGridLocalModel extends HoistModel {
|
|
|
125
130
|
@lookup(AgGridModel) model: AgGridModel;
|
|
126
131
|
|
|
127
132
|
get headerHeight() {
|
|
128
|
-
const {hideHeaders, sizingMode} = this.model
|
|
129
|
-
|
|
133
|
+
const {hideHeaders, sizingMode} = this.model,
|
|
134
|
+
AgGridCmp = AgGrid as any;
|
|
135
|
+
|
|
136
|
+
return hideHeaders ? 0 : AgGridCmp.getHeaderHeightForSizingMode(sizingMode);
|
|
130
137
|
}
|
|
131
138
|
|
|
132
139
|
override onLinked() {
|
|
@@ -141,15 +148,20 @@ class AgGridLocalModel extends HoistModel {
|
|
|
141
148
|
}
|
|
142
149
|
}
|
|
143
150
|
|
|
151
|
+
getRowHeight = ({node}) => {
|
|
152
|
+
const {sizingMode} = this.model,
|
|
153
|
+
{groupDisplayType} = this.componentProps,
|
|
154
|
+
AgGridCmp = AgGrid as any;
|
|
155
|
+
return node.group && groupDisplayType === 'groupRows'
|
|
156
|
+
? AgGridCmp.getGroupRowHeightForSizingMode(sizingMode)
|
|
157
|
+
: AgGridCmp.getRowHeightForSizingMode(sizingMode);
|
|
158
|
+
};
|
|
159
|
+
|
|
144
160
|
noteGridReady = agParams => {
|
|
145
161
|
this.model.handleGridReady(agParams);
|
|
146
162
|
this.componentProps.onGridReady?.(agParams);
|
|
147
163
|
};
|
|
148
164
|
|
|
149
|
-
getRowHeight = () => {
|
|
150
|
-
return (AgGrid as any).getRowHeightForSizingMode(this.model.sizingMode);
|
|
151
|
-
};
|
|
152
|
-
|
|
153
165
|
override destroy() {
|
|
154
166
|
this.model?.handleGridUnmount();
|
|
155
167
|
super.destroy();
|
|
@@ -60,7 +60,7 @@ export interface FilterChooserConfig {
|
|
|
60
60
|
fieldSpecs?: Array<FilterChooserFieldSpecConfig | string>;
|
|
61
61
|
|
|
62
62
|
/** Default properties to be assigned to all FilterChooserFieldSpecs created by this model. */
|
|
63
|
-
fieldSpecDefaults?: FilterChooserFieldSpecConfig
|
|
63
|
+
fieldSpecDefaults?: Partial<FilterChooserFieldSpecConfig>;
|
|
64
64
|
|
|
65
65
|
/**
|
|
66
66
|
* Store or cube View that should actually be filtered as this model's value changes.
|
|
@@ -460,7 +460,7 @@ export class FilterChooserModel extends HoistModel {
|
|
|
460
460
|
//--------------------------------
|
|
461
461
|
parseFieldSpecs(
|
|
462
462
|
specs: Array<FilterChooserFieldSpecConfig | string>,
|
|
463
|
-
fieldSpecDefaults: FilterChooserFieldSpecConfig
|
|
463
|
+
fieldSpecDefaults: Partial<FilterChooserFieldSpecConfig>
|
|
464
464
|
): Array<FilterChooserFieldSpec> {
|
|
465
465
|
const {valueSource} = this;
|
|
466
466
|
|
package/cmp/form/Form.ts
CHANGED
|
@@ -4,14 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2022 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
8
|
-
BoxProps,
|
|
9
|
-
DefaultHoistProps,
|
|
10
|
-
elementFactory,
|
|
11
|
-
hoistCmp,
|
|
12
|
-
HoistProps,
|
|
13
|
-
uses
|
|
14
|
-
} from '@xh/hoist/core';
|
|
7
|
+
import {DefaultHoistProps, elementFactory, hoistCmp, HoistProps, uses} from '@xh/hoist/core';
|
|
15
8
|
import equal from 'fast-deep-equal';
|
|
16
9
|
import {createContext, useContext} from 'react';
|
|
17
10
|
import {useCached} from '@xh/hoist/utils/react';
|
|
@@ -31,7 +24,7 @@ export interface FormContextType {
|
|
|
31
24
|
export const FormContext = createContext<FormContextType>({});
|
|
32
25
|
const formContextProvider = elementFactory(FormContext.Provider);
|
|
33
26
|
|
|
34
|
-
export interface FormProps extends HoistProps<FormModel
|
|
27
|
+
export interface FormProps extends HoistProps<FormModel> {
|
|
35
28
|
/**
|
|
36
29
|
* Defaults for certain props on child/nested FormFields.
|
|
37
30
|
* @see FormField (note there are both desktop and mobile implementations).
|
package/cmp/form/FormModel.ts
CHANGED
package/cmp/grid/Grid.ts
CHANGED
|
@@ -8,7 +8,6 @@ import composeRefs from '@seznam/compose-react-refs';
|
|
|
8
8
|
import {agGrid, AgGrid} from '@xh/hoist/cmp/ag-grid';
|
|
9
9
|
import {getTreeStyleClasses} from '@xh/hoist/cmp/grid';
|
|
10
10
|
import {getAgGridMenuItems} from '@xh/hoist/cmp/grid/impl/MenuSupport';
|
|
11
|
-
import {Column} from './columns/Column';
|
|
12
11
|
import {div, fragment, frame} from '@xh/hoist/cmp/layout';
|
|
13
12
|
import {
|
|
14
13
|
hoistCmp,
|
|
@@ -17,7 +16,6 @@ import {
|
|
|
17
16
|
LayoutProps,
|
|
18
17
|
lookup,
|
|
19
18
|
PlainObject,
|
|
20
|
-
SizingMode,
|
|
21
19
|
useLocalModel,
|
|
22
20
|
uses,
|
|
23
21
|
XH
|
|
@@ -137,23 +135,9 @@ class GridLocalModel extends HoistModel {
|
|
|
137
135
|
private model: GridModel;
|
|
138
136
|
agOptions: GridOptions;
|
|
139
137
|
viewRef = createRef<HTMLElement>();
|
|
140
|
-
private fixedRowHeight: number;
|
|
141
138
|
private rowKeyNavSupport: RowKeyNavSupport;
|
|
142
139
|
private prevRs: RecordSet;
|
|
143
140
|
|
|
144
|
-
getRowHeight(node) {
|
|
145
|
-
const {model, agOptions} = this,
|
|
146
|
-
{sizingMode, groupRowHeight} = model,
|
|
147
|
-
{groupDisplayType} = agOptions;
|
|
148
|
-
|
|
149
|
-
if (node?.group) {
|
|
150
|
-
return groupRowHeight ?? groupDisplayType === 'groupRows'
|
|
151
|
-
? (AgGrid as any).getGroupRowHeightForSizingMode(sizingMode)
|
|
152
|
-
: (AgGrid as any).getRowHeightForSizingMode(sizingMode);
|
|
153
|
-
}
|
|
154
|
-
return this.fixedRowHeight;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
141
|
/** @returns true if any root-level records have children */
|
|
158
142
|
@computed
|
|
159
143
|
get isHierarchical(): boolean {
|
|
@@ -220,7 +204,7 @@ class GridLocalModel extends HoistModel {
|
|
|
220
204
|
suppressRowClickSelection: !selModel.isEnabled,
|
|
221
205
|
isRowSelectable: () => selModel.isEnabled,
|
|
222
206
|
tooltipShowDelay: 0,
|
|
223
|
-
getRowHeight:
|
|
207
|
+
getRowHeight: this.defaultGetRowHeight,
|
|
224
208
|
getRowClass: ({data}) => (model.rowClassFn ? model.rowClassFn(data) : null),
|
|
225
209
|
rowClassRules: model.rowClassRules,
|
|
226
210
|
noRowsOverlayComponent: observer(() => div(this.emptyText)),
|
|
@@ -367,20 +351,78 @@ class GridLocalModel extends HoistModel {
|
|
|
367
351
|
};
|
|
368
352
|
}
|
|
369
353
|
|
|
354
|
+
//----------------------
|
|
355
|
+
// Row Height Management
|
|
356
|
+
//----------------------
|
|
357
|
+
@computed
|
|
358
|
+
get calculatedRowHeight() {
|
|
359
|
+
const {model} = this,
|
|
360
|
+
AgGridCmp = AgGrid as any;
|
|
361
|
+
return max([
|
|
362
|
+
AgGridCmp.getRowHeightForSizingMode(model.sizingMode),
|
|
363
|
+
maxBy(model.getVisibleLeafColumns(), 'rowHeight')?.rowHeight
|
|
364
|
+
]);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
@computed
|
|
368
|
+
get calculatedGroupRowHeight() {
|
|
369
|
+
const {sizingMode, groupRowHeight} = this.model,
|
|
370
|
+
{groupDisplayType} = this.agOptions,
|
|
371
|
+
AgGridCmp = AgGrid as any;
|
|
372
|
+
return groupRowHeight ?? groupDisplayType === 'groupRows'
|
|
373
|
+
? AgGridCmp.getGroupRowHeightForSizingMode(sizingMode)
|
|
374
|
+
: AgGridCmp.getRowHeightForSizingMode(sizingMode);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
defaultGetRowHeight = ({node}) => {
|
|
378
|
+
return node.group ? this.calculatedGroupRowHeight : this.calculatedRowHeight;
|
|
379
|
+
};
|
|
380
|
+
|
|
370
381
|
rowHeightReaction() {
|
|
371
|
-
const {model} = this;
|
|
372
382
|
return {
|
|
373
|
-
track: () => [
|
|
374
|
-
|
|
375
|
-
this.
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
383
|
+
track: () => [
|
|
384
|
+
this.useScrollOptimization,
|
|
385
|
+
this.calculatedRowHeight,
|
|
386
|
+
this.calculatedGroupRowHeight
|
|
387
|
+
],
|
|
388
|
+
run: () => {
|
|
389
|
+
const {agApi} = this.model;
|
|
390
|
+
if (!agApi) return;
|
|
391
|
+
agApi.resetRowHeights();
|
|
392
|
+
this.applyScrollOptimization();
|
|
379
393
|
},
|
|
380
|
-
|
|
394
|
+
debounce: 1
|
|
381
395
|
};
|
|
382
396
|
}
|
|
383
397
|
|
|
398
|
+
@computed
|
|
399
|
+
get useScrollOptimization() {
|
|
400
|
+
// When true, we preemptively evaluate and assign functional row heights after data loading.
|
|
401
|
+
// This improves slow scrolling but means function not guaranteed to be re-called
|
|
402
|
+
// when node is rendered in viewport.
|
|
403
|
+
const {model, agOptions} = this;
|
|
404
|
+
return (
|
|
405
|
+
agOptions.getRowHeight &&
|
|
406
|
+
!agOptions.rowHeight &&
|
|
407
|
+
!model.getVisibleLeafColumns().some(c => c.autoHeight) &&
|
|
408
|
+
model.experimental.useScrollOptimization !== false
|
|
409
|
+
);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
applyScrollOptimization() {
|
|
413
|
+
if (!this.useScrollOptimization) return;
|
|
414
|
+
const {agApi, agColumnApi} = this.model,
|
|
415
|
+
{getRowHeight} = this.agOptions,
|
|
416
|
+
params = {api: agApi, columnApi: agColumnApi, context: null} as any;
|
|
417
|
+
|
|
418
|
+
agApi.forEachNode(node => {
|
|
419
|
+
params.node = node;
|
|
420
|
+
params.data = node.data;
|
|
421
|
+
node.setRowHeight(getRowHeight(params));
|
|
422
|
+
});
|
|
423
|
+
agApi.onRowHeightChanged();
|
|
424
|
+
}
|
|
425
|
+
|
|
384
426
|
columnsReaction() {
|
|
385
427
|
const {model} = this;
|
|
386
428
|
return {
|
|
@@ -627,6 +669,7 @@ class GridLocalModel extends HoistModel {
|
|
|
627
669
|
model.noteAgExpandStateChange();
|
|
628
670
|
|
|
629
671
|
this.prevRs = newRs;
|
|
672
|
+
this.applyScrollOptimization();
|
|
630
673
|
}
|
|
631
674
|
|
|
632
675
|
syncSelection() {
|
|
@@ -69,7 +69,7 @@ async function initServicesInternalAsync(svcs: HoistService[]) {
|
|
|
69
69
|
it.name = svcs[idx].constructor.name;
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
throw
|
|
72
|
+
throw XH.exception({
|
|
73
73
|
message: [
|
|
74
74
|
'Failed to initialize services: ',
|
|
75
75
|
...errs.map(it => it.reason.message + ' (' + it.name + ')')
|
package/data/RecordAction.ts
CHANGED
package/data/Store.ts
CHANGED
|
@@ -118,7 +118,7 @@ export interface StoreConfig {
|
|
|
118
118
|
* Flags for experimental features. These features are designed for early client-access and
|
|
119
119
|
* testing, but are not yet part of the Hoist API.
|
|
120
120
|
*/
|
|
121
|
-
experimental?:
|
|
121
|
+
experimental?: PlainObject;
|
|
122
122
|
}
|
|
123
123
|
|
|
124
124
|
/**
|
package/data/StoreRecord.ts
CHANGED
|
@@ -51,7 +51,7 @@ export class StoreRecord {
|
|
|
51
51
|
* This object has the same form as `data`. If this record has not been locally modified, this
|
|
52
52
|
* property will point to the same object as `data`.
|
|
53
53
|
*/
|
|
54
|
-
readonly committedData:
|
|
54
|
+
readonly committedData: PlainObject;
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
57
|
* Unique ID for representing record within ag-Grid node API.
|
|
@@ -171,7 +171,7 @@ export class StoreRecord {
|
|
|
171
171
|
* Unlike 'data', the object returned by this method contains an 'own' property for every
|
|
172
172
|
* Field in the Store. Useful for cloning/iterating over all values (including defaults).
|
|
173
173
|
*/
|
|
174
|
-
getValues():
|
|
174
|
+
getValues(): PlainObject {
|
|
175
175
|
const ret = {id: this.id};
|
|
176
176
|
this.fields.forEach(({name}) => {
|
|
177
177
|
ret[name] = this.data[name];
|
package/data/cube/Cube.ts
CHANGED
|
@@ -205,7 +205,7 @@ export class Cube extends HoistBase {
|
|
|
205
205
|
* @param rawData - flat array of lowest/leaf level data rows.
|
|
206
206
|
* @param info - optional metadata to associate with this cube/dataset.
|
|
207
207
|
*/
|
|
208
|
-
async loadDataAsync(rawData: PlainObject[], info:
|
|
208
|
+
async loadDataAsync(rawData: PlainObject[], info: PlainObject = {}): Promise<void> {
|
|
209
209
|
this.store.loadData(rawData);
|
|
210
210
|
this.setInfo(info);
|
|
211
211
|
await forEachAsync(this._connectedViews, v => v.noteCubeLoaded());
|
|
@@ -248,7 +248,7 @@ export class Cube extends HoistBase {
|
|
|
248
248
|
* Populate the metadata associated with this cube.
|
|
249
249
|
* @param infoUpdates - new key-value pairs to be applied to existing info on this cube.
|
|
250
250
|
*/
|
|
251
|
-
updateInfo(infoUpdates:
|
|
251
|
+
updateInfo(infoUpdates: PlainObject = {}) {
|
|
252
252
|
this.setInfo({...this.info, ...infoUpdates});
|
|
253
253
|
this._connectedViews.forEach(v => v.noteCubeUpdated(null));
|
|
254
254
|
}
|
|
@@ -257,7 +257,7 @@ export class Cube extends HoistBase {
|
|
|
257
257
|
// Implementation
|
|
258
258
|
//---------------------
|
|
259
259
|
@action
|
|
260
|
-
private setInfo(info:
|
|
260
|
+
private setInfo(info: PlainObject) {
|
|
261
261
|
this.info = Object.freeze(info);
|
|
262
262
|
}
|
|
263
263
|
|
package/data/cube/CubeField.ts
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
* Copyright © 2022 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import {PlainObject} from '@xh/hoist/core';
|
|
8
9
|
import {
|
|
9
10
|
Aggregator,
|
|
10
11
|
AverageAggregator,
|
|
@@ -64,11 +65,7 @@ export interface CubeFieldSpec extends FieldSpec {
|
|
|
64
65
|
* @param value - value of record on dimension
|
|
65
66
|
* @param appliedDims - *all* applied dimension values for this record
|
|
66
67
|
*/
|
|
67
|
-
export type CanAggregateFn = (
|
|
68
|
-
dimension: string,
|
|
69
|
-
value: any,
|
|
70
|
-
appliedDims: Record<string, any>
|
|
71
|
-
) => boolean;
|
|
68
|
+
export type CanAggregateFn = (dimension: string, value: any, appliedDims: PlainObject) => boolean;
|
|
72
69
|
|
|
73
70
|
/**
|
|
74
71
|
* Metadata used to define a measure or dimension in Cube. For properties present on raw data source
|
package/data/cube/View.ts
CHANGED
|
@@ -78,7 +78,7 @@ export class View extends HoistBase {
|
|
|
78
78
|
|
|
79
79
|
/** Cube info associated with this View when last updated. */
|
|
80
80
|
@observable.ref
|
|
81
|
-
info:
|
|
81
|
+
info: PlainObject = null;
|
|
82
82
|
|
|
83
83
|
/** timestamp (ms) of the last time this view's data was changed. */
|
|
84
84
|
@observable
|
package/data/validation/Rule.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2022 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {Awaitable, Some} from '../../core';
|
|
7
|
+
import {Awaitable, PlainObject, Some} from '../../core';
|
|
8
8
|
import {castArray} from 'lodash';
|
|
9
9
|
import {StoreRecord} from '../StoreRecord';
|
|
10
10
|
import {BaseFieldModel} from '../../cmp/form';
|
|
@@ -32,7 +32,7 @@ export class Rule {
|
|
|
32
32
|
*/
|
|
33
33
|
export type Constraint<T = any> = (
|
|
34
34
|
fieldState: FieldState<T>,
|
|
35
|
-
allValues:
|
|
35
|
+
allValues: PlainObject
|
|
36
36
|
) => Awaitable<Some<string>>;
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -43,7 +43,7 @@ export type Constraint<T = any> = (
|
|
|
43
43
|
* @param allValues - current values for all fields in form or record, keyed by field name.
|
|
44
44
|
* @returns true if this rule is currently active.
|
|
45
45
|
*/
|
|
46
|
-
export type When = (entity: any, allValues:
|
|
46
|
+
export type When = (entity: any, allValues: PlainObject) => boolean;
|
|
47
47
|
|
|
48
48
|
export interface FieldState<T = any> {
|
|
49
49
|
/** Current value of the field */
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
managed,
|
|
10
10
|
ManagedRefreshContextModel,
|
|
11
11
|
MenuItemLike,
|
|
12
|
+
PlainObject,
|
|
12
13
|
RefreshMode,
|
|
13
14
|
RenderMode
|
|
14
15
|
} from '@xh/hoist/core';
|
|
@@ -18,7 +19,7 @@ import {throwIf} from '@xh/hoist/utils/js';
|
|
|
18
19
|
import {ReactElement} from 'react';
|
|
19
20
|
import {DashViewSpec} from './DashViewSpec';
|
|
20
21
|
|
|
21
|
-
export type DashViewState =
|
|
22
|
+
export type DashViewState = PlainObject;
|
|
22
23
|
|
|
23
24
|
/**
|
|
24
25
|
* Model for a content item within a DashContainer or DashCanvas.
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import {
|
|
8
8
|
managed,
|
|
9
9
|
PersistenceProvider,
|
|
10
|
+
PlainObject,
|
|
10
11
|
RefreshMode,
|
|
11
12
|
RenderMode,
|
|
12
13
|
TaskObserver,
|
|
@@ -46,11 +47,14 @@ export interface DashContainerConfig extends DashConfig<DashContainerViewSpec, D
|
|
|
46
47
|
/** True to include a button in each stack header showing the dash context menu. */
|
|
47
48
|
showMenuButton?: boolean;
|
|
48
49
|
|
|
50
|
+
/** Between items in pixels. */
|
|
51
|
+
margin?: number;
|
|
52
|
+
|
|
49
53
|
/**
|
|
50
54
|
* Custom settings to be passed to the GoldenLayout instance.
|
|
51
55
|
* @see http://golden-layout.com/docs/Config.html
|
|
52
56
|
*/
|
|
53
|
-
goldenLayoutSettings?:
|
|
57
|
+
goldenLayoutSettings?: PlainObject;
|
|
54
58
|
}
|
|
55
59
|
|
|
56
60
|
/**
|
|
@@ -124,7 +128,8 @@ export class DashContainerModel extends DashModel<
|
|
|
124
128
|
//-----------------------------
|
|
125
129
|
renderMode: RenderMode;
|
|
126
130
|
refreshMode: RefreshMode;
|
|
127
|
-
goldenLayoutSettings:
|
|
131
|
+
goldenLayoutSettings: PlainObject;
|
|
132
|
+
margin: number;
|
|
128
133
|
|
|
129
134
|
get isEmpty(): boolean {
|
|
130
135
|
return this.goldenLayout && this.viewModels.length === 0;
|
|
@@ -148,6 +153,7 @@ export class DashContainerModel extends DashModel<
|
|
|
148
153
|
contentLocked = false,
|
|
149
154
|
renameLocked = false,
|
|
150
155
|
showMenuButton = false,
|
|
156
|
+
margin = 6,
|
|
151
157
|
goldenLayoutSettings,
|
|
152
158
|
persistWith = null,
|
|
153
159
|
emptyText = 'No views have been added to the container.',
|
|
@@ -176,6 +182,7 @@ export class DashContainerModel extends DashModel<
|
|
|
176
182
|
this.contentLocked = contentLocked;
|
|
177
183
|
this.renameLocked = renameLocked;
|
|
178
184
|
this.showMenuButton = showMenuButton;
|
|
185
|
+
this.margin = margin;
|
|
179
186
|
this.goldenLayoutSettings = goldenLayoutSettings;
|
|
180
187
|
this.emptyText = emptyText;
|
|
181
188
|
this.addViewButtonText = addViewButtonText;
|
|
@@ -570,7 +577,7 @@ export class DashContainerModel extends DashModel<
|
|
|
570
577
|
...this.goldenLayoutSettings
|
|
571
578
|
},
|
|
572
579
|
dimensions: {
|
|
573
|
-
borderWidth:
|
|
580
|
+
borderWidth: this.margin,
|
|
574
581
|
headerHeight: 25
|
|
575
582
|
}
|
|
576
583
|
},
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Copyright © 2022 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
import {div, frame, p} from '@xh/hoist/cmp/layout';
|
|
8
|
-
import {hoistCmp, HoistProps} from '@xh/hoist/core';
|
|
8
|
+
import {hoistCmp, HoistProps, PlainObject} from '@xh/hoist/core';
|
|
9
9
|
import {button, ButtonProps} from '@xh/hoist/desktop/cmp/button';
|
|
10
10
|
import '@xh/hoist/desktop/register';
|
|
11
11
|
import {isEmpty, isNil, isString} from 'lodash';
|
|
@@ -28,7 +28,7 @@ export interface ErrorMessageProps extends HoistProps {
|
|
|
28
28
|
* Error to display. If undefined, this component will look for an error property on its model.
|
|
29
29
|
* If no error is found, this component will not be displayed.
|
|
30
30
|
*/
|
|
31
|
-
error?: Error | string |
|
|
31
|
+
error?: Error | string | PlainObject;
|
|
32
32
|
/**
|
|
33
33
|
* Message to display for the error.
|
|
34
34
|
* Defaults to the error, or any 'message' property contained within it.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import {HoistInputModel, HoistInputProps, useHoistInputModel} from '@xh/hoist/cmp/input';
|
|
8
8
|
import {box, div, filler, fragment, frame, hbox, label, span, vbox} from '@xh/hoist/cmp/layout';
|
|
9
|
-
import {hoistCmp, HoistProps, LayoutProps, managed, XH} from '@xh/hoist/core';
|
|
9
|
+
import {hoistCmp, HoistProps, LayoutProps, managed, PlainObject, XH} from '@xh/hoist/core';
|
|
10
10
|
import {button} from '@xh/hoist/desktop/cmp/button';
|
|
11
11
|
import {clipboardButton} from '@xh/hoist/desktop/cmp/clipboard';
|
|
12
12
|
import {textInput} from '@xh/hoist/desktop/cmp/input/TextInput';
|
|
@@ -50,7 +50,7 @@ export interface CodeInputProps extends HoistProps, HoistInputProps, LayoutProps
|
|
|
50
50
|
* Configuration object with any properties supported by the CodeMirror API.
|
|
51
51
|
* @see {@link https://codemirror.net/doc/manual.html#api_configuration|CodeMirror Docs}
|
|
52
52
|
*/
|
|
53
|
-
editorProps?:
|
|
53
|
+
editorProps?: PlainObject;
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* True to enable case-insensitive searching within the input. Default false, except in
|
package/kit/ag-grid/index.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* Copyright © 2022 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
import {div, frame, p} from '@xh/hoist/cmp/layout';
|
|
8
|
-
import {hoistCmp, HoistProps} from '@xh/hoist/core';
|
|
8
|
+
import {hoistCmp, HoistProps, PlainObject} from '@xh/hoist/core';
|
|
9
9
|
import {button, ButtonProps} from '@xh/hoist/mobile/cmp/button';
|
|
10
10
|
import '@xh/hoist/mobile/register';
|
|
11
11
|
import {isEmpty, isNil, isString} from 'lodash';
|
|
@@ -28,7 +28,7 @@ export interface ErrorMessageProps extends HoistProps {
|
|
|
28
28
|
* Error to display. If undefined, this component will look for an error property on its model.
|
|
29
29
|
* If no error is found, this component will not be displayed.
|
|
30
30
|
*/
|
|
31
|
-
error?: Error | string |
|
|
31
|
+
error?: Error | string | PlainObject;
|
|
32
32
|
/**
|
|
33
33
|
* Message to display for the error.
|
|
34
34
|
* Defaults to the error, or any 'message' property contained within it.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import {HoistInputModel, HoistInputProps, useHoistInputModel} from '@xh/hoist/cmp/input';
|
|
8
8
|
import {div} from '@xh/hoist/cmp/layout';
|
|
9
|
-
import {hoistCmp, HoistProps, StyleProps, LayoutProps, HSide} from '@xh/hoist/core';
|
|
9
|
+
import {hoistCmp, HoistProps, StyleProps, LayoutProps, HSide, PlainObject} from '@xh/hoist/core';
|
|
10
10
|
import {fmtDate} from '@xh/hoist/format';
|
|
11
11
|
import {Icon} from '@xh/hoist/icon';
|
|
12
12
|
import {singleDatePicker} from '@xh/hoist/kit/react-dates';
|
|
@@ -65,7 +65,7 @@ export interface DateInputProps extends HoistProps, HoistInputProps, StyleProps,
|
|
|
65
65
|
placeholder?: string;
|
|
66
66
|
|
|
67
67
|
/** Props passed to SingleDatePicker component, as per SingleDatePicker docs. */
|
|
68
|
-
singleDatePickerProps?:
|
|
68
|
+
singleDatePickerProps?: PlainObject;
|
|
69
69
|
|
|
70
70
|
/** Alignment of entry text within control, default 'left'. */
|
|
71
71
|
textAlign?: HSide;
|
|
@@ -5,7 +5,15 @@
|
|
|
5
5
|
* Copyright © 2022 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
import {div, fragment} from '@xh/hoist/cmp/layout';
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
Content,
|
|
10
|
+
hoistCmp,
|
|
11
|
+
HoistModel,
|
|
12
|
+
HoistProps,
|
|
13
|
+
PlainObject,
|
|
14
|
+
useLocalModel,
|
|
15
|
+
XH
|
|
16
|
+
} from '@xh/hoist/core';
|
|
9
17
|
import '@xh/hoist/mobile/register';
|
|
10
18
|
import {action, makeObservable, observable} from '@xh/hoist/mobx';
|
|
11
19
|
import {createObservableRef, elementFromContent} from '@xh/hoist/utils/react';
|
|
@@ -59,7 +67,7 @@ export interface PopoverProps extends HoistProps {
|
|
|
59
67
|
popoverClassName?: string;
|
|
60
68
|
|
|
61
69
|
/** Escape hatch to provide additional options to the PopperJS implementation */
|
|
62
|
-
popperOptions?:
|
|
70
|
+
popperOptions?: PlainObject;
|
|
63
71
|
}
|
|
64
72
|
|
|
65
73
|
/**
|
package/package.json
CHANGED
package/utils/js/LangUtils.ts
CHANGED
|
@@ -236,7 +236,7 @@ export function pluralize(s: string, count?: number, includeCount?: boolean): st
|
|
|
236
236
|
}
|
|
237
237
|
|
|
238
238
|
/**
|
|
239
|
-
* Returns the number with an ordinal suffix (
|
|
239
|
+
* Returns the number with an ordinal suffix (i.e. 1 becomes '1st', 11 becomes '11th').
|
|
240
240
|
*
|
|
241
241
|
* @param n - the number to ordinalize
|
|
242
242
|
*/
|