@xh/hoist 59.2.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 +63 -14
- 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/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 +51 -25
- 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.ts +41 -25
- package/cmp/grid/GridModel.ts +2 -2
- package/cmp/grid/Types.ts +1 -1
- package/cmp/grid/columns/Column.ts +45 -2
- 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 +7 -4
- package/data/StoreRecord.ts +8 -1
- package/desktop/appcontainer/AppContainer.ts +2 -0
- 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/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 +2 -2
- package/mobile/appcontainer/AppContainer.ts +2 -0
- 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/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
|
@@ -4,23 +4,23 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2023 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
+
import {inRange, isNil} from 'lodash';
|
|
8
|
+
import moment from 'moment';
|
|
7
9
|
import {box, span} from '@xh/hoist/cmp/layout';
|
|
8
10
|
import {
|
|
11
|
+
BoxProps,
|
|
9
12
|
hoistCmp,
|
|
10
13
|
HoistModel,
|
|
14
|
+
HoistProps,
|
|
11
15
|
managed,
|
|
12
16
|
useLocalModel,
|
|
13
|
-
XH
|
|
14
|
-
BoxProps,
|
|
15
|
-
HoistProps
|
|
17
|
+
XH
|
|
16
18
|
} from '@xh/hoist/core';
|
|
17
19
|
import {fmtCompactDate, fmtDateTime} from '@xh/hoist/format';
|
|
18
|
-
import {action,
|
|
20
|
+
import {action, computed, makeObservable, observable} from '@xh/hoist/mobx';
|
|
19
21
|
import {Timer} from '@xh/hoist/utils/async';
|
|
20
|
-
import {SECONDS} from '@xh/hoist/utils/datetime';
|
|
22
|
+
import {DAYS, HOURS, LocalDate, SECONDS} from '@xh/hoist/utils/datetime';
|
|
21
23
|
import {withDefault} from '@xh/hoist/utils/js';
|
|
22
|
-
import {getLayoutProps} from '@xh/hoist/utils/react';
|
|
23
|
-
import moment from 'moment';
|
|
24
24
|
|
|
25
25
|
interface RelativeTimestampProps extends HoistProps, BoxProps {
|
|
26
26
|
/**
|
|
@@ -63,11 +63,27 @@ export interface RelativeTimestampOptions {
|
|
|
63
63
|
|
|
64
64
|
/** Time to which the input timestamp is compared. */
|
|
65
65
|
relativeTo?: Date | number;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Governs if calendar days should be used for computing return label rather than the native
|
|
69
|
+
* moment 24-hour day.
|
|
70
|
+
*
|
|
71
|
+
* - Set to 'always' to ensure that any output less than 25 days will refer to the difference
|
|
72
|
+
* in *calendar* days.
|
|
73
|
+
* - Set to 'useTimeForSameDay' for a similar behavior, but showing time differences if the
|
|
74
|
+
* two dates are on the same calendar day.
|
|
75
|
+
* - Set to 'useTimeFor24Hr' for a similar behavior, but showing time differences for
|
|
76
|
+
* any differences less than 24 hours.
|
|
77
|
+
*
|
|
78
|
+
* Null (default) will indicate that the standard behavior, based on moment, be used, whereby
|
|
79
|
+
* 'day' refers simply to a 24-hour time period and has no relation to the calendar.
|
|
80
|
+
*/
|
|
81
|
+
localDateMode?: 'always' | 'useTimeForSameDay' | 'useTimeFor24Hr';
|
|
66
82
|
}
|
|
67
83
|
|
|
68
84
|
/**
|
|
69
85
|
* A component to display the approximate amount of time between a given timestamp and now in a
|
|
70
|
-
* friendly, human
|
|
86
|
+
* friendly, human-readable format (e.g. '6 minutes ago' or 'two hours from now').
|
|
71
87
|
*
|
|
72
88
|
* Automatically updates on a regular interval to stay current.
|
|
73
89
|
*/
|
|
@@ -75,13 +91,13 @@ export const [RelativeTimestamp, relativeTimestamp] = hoistCmp.withFactory<Relat
|
|
|
75
91
|
displayName: 'RelativeTimestamp',
|
|
76
92
|
className: 'xh-relative-timestamp',
|
|
77
93
|
|
|
78
|
-
render({className, ...
|
|
94
|
+
render({className, bind, timestamp, options, ...rest}, ref) {
|
|
79
95
|
const impl = useLocalModel(RelativeTimestampLocalModel);
|
|
80
96
|
|
|
81
97
|
return box({
|
|
82
98
|
className,
|
|
83
|
-
...getLayoutProps(props),
|
|
84
99
|
ref,
|
|
100
|
+
...rest,
|
|
85
101
|
item: span({
|
|
86
102
|
className: 'xh-title-tip',
|
|
87
103
|
item: impl.display,
|
|
@@ -94,7 +110,8 @@ export const [RelativeTimestamp, relativeTimestamp] = hoistCmp.withFactory<Relat
|
|
|
94
110
|
class RelativeTimestampLocalModel extends HoistModel {
|
|
95
111
|
override xhImpl = true;
|
|
96
112
|
|
|
97
|
-
@observable display = '';
|
|
113
|
+
@observable display: string = '';
|
|
114
|
+
|
|
98
115
|
model: HoistModel;
|
|
99
116
|
|
|
100
117
|
@managed
|
|
@@ -103,14 +120,14 @@ class RelativeTimestampLocalModel extends HoistModel {
|
|
|
103
120
|
interval: 5 * SECONDS
|
|
104
121
|
});
|
|
105
122
|
|
|
106
|
-
get timestamp() {
|
|
123
|
+
get timestamp(): Date | number {
|
|
107
124
|
const {model} = this,
|
|
108
125
|
{timestamp, bind} = this.componentProps;
|
|
109
126
|
return withDefault(timestamp, model && bind ? model[bind] : null);
|
|
110
127
|
}
|
|
111
128
|
|
|
112
129
|
@computed.struct
|
|
113
|
-
get options() {
|
|
130
|
+
get options(): RelativeTimestampOptions {
|
|
114
131
|
return this.componentProps.options;
|
|
115
132
|
}
|
|
116
133
|
|
|
@@ -136,65 +153,114 @@ class RelativeTimestampLocalModel extends HoistModel {
|
|
|
136
153
|
|
|
137
154
|
/**
|
|
138
155
|
* Returns a string describing the approximate amount of time between a given timestamp and the
|
|
139
|
-
* present moment in a friendly, human
|
|
156
|
+
* present moment in a friendly, human-readable format.
|
|
140
157
|
*/
|
|
141
158
|
export function getRelativeTimestamp(
|
|
142
159
|
timestamp: Date | number,
|
|
143
160
|
options: RelativeTimestampOptions = {}
|
|
144
|
-
) {
|
|
145
|
-
const
|
|
146
|
-
relFmt =
|
|
147
|
-
|
|
161
|
+
): string {
|
|
162
|
+
const {localDateMode} = options,
|
|
163
|
+
relFmt = !isNil(options.relativeTo)
|
|
164
|
+
? (fmtCompactDate(options.relativeTo, {asHtml: true}) as string)
|
|
165
|
+
: null;
|
|
148
166
|
|
|
149
167
|
options = {
|
|
150
168
|
allowFuture: false,
|
|
151
169
|
short: XH.isMobileApp,
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
equalString:
|
|
170
|
+
pastSuffix: defaultPastSuffix(relFmt),
|
|
171
|
+
futureSuffix: defaultFutureSuffix(relFmt, localDateMode),
|
|
172
|
+
equalString: defaultEqualString(relFmt, localDateMode),
|
|
155
173
|
epsilon: 10,
|
|
156
174
|
emptyResult: '',
|
|
157
175
|
prefix: '',
|
|
158
|
-
relativeTo: Date.now(),
|
|
159
176
|
...options
|
|
160
177
|
};
|
|
161
178
|
|
|
162
179
|
if (!timestamp) return options.emptyResult;
|
|
163
180
|
|
|
164
|
-
|
|
181
|
+
let ret = doFormat(timestamp, options);
|
|
182
|
+
|
|
183
|
+
if (options.prefix) ret = options.prefix + ' ' + ret;
|
|
184
|
+
|
|
185
|
+
return ret;
|
|
165
186
|
}
|
|
166
187
|
|
|
167
188
|
//------------------------
|
|
168
189
|
// Implementation
|
|
169
190
|
//------------------------
|
|
170
|
-
function
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
191
|
+
function defaultPastSuffix(relFmt: String): string {
|
|
192
|
+
return relFmt ? `before ${relFmt}` : 'ago';
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function defaultFutureSuffix(relFmt: String, localDateMode: string): string {
|
|
196
|
+
if (relFmt) return `after ${relFmt}`;
|
|
197
|
+
return localDateMode == 'always' ? 'from today' : 'from now';
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function defaultEqualString(relFmt: String, localDateMode: string): string {
|
|
201
|
+
if (relFmt) return `${relFmt?.includes(':') ? 'at' : 'on'} ${relFmt}`;
|
|
202
|
+
return localDateMode == 'always' ? 'today' : 'just now';
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function doFormat(timestamp: Date | number, opts: RelativeTimestampOptions): string {
|
|
206
|
+
let {relativeTo, localDateMode, epsilon, equalString, allowFuture, short} = opts,
|
|
207
|
+
baseTimestamp = withDefault(relativeTo ?? Date.now()),
|
|
208
|
+
diff = toTimestamp(baseTimestamp) - toTimestamp(timestamp),
|
|
209
|
+
elapsed = Math.abs(diff);
|
|
210
|
+
|
|
211
|
+
// 0) Snap elapsed to calendar elapsed for localDateMode.
|
|
212
|
+
// (+ Early out for tomorrow/yesterday)
|
|
213
|
+
if (localDateMode && inRange(elapsed, 0, 26 * DAYS)) {
|
|
214
|
+
const dayDiff = LocalDate.from(baseTimestamp).diff(LocalDate.from(timestamp));
|
|
215
|
+
|
|
216
|
+
if (
|
|
217
|
+
!(localDateMode == 'useTimeForSameDay' && dayDiff == 0) &&
|
|
218
|
+
!(localDateMode == 'useTimeFor24Hr' && elapsed <= 24 * HOURS)
|
|
219
|
+
) {
|
|
220
|
+
elapsed = Math.abs(dayDiff * DAYS);
|
|
221
|
+
|
|
222
|
+
if (isNil(relativeTo)) {
|
|
223
|
+
if (dayDiff == -1) return 'tomorrow';
|
|
224
|
+
if (dayDiff == 1) return 'yesterday';
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const isEqual = elapsed <= (epsilon ?? 0) * SECONDS,
|
|
175
230
|
isFuture = !isEqual && diff < 0;
|
|
176
231
|
|
|
177
|
-
|
|
178
|
-
if (
|
|
179
|
-
ret = equalString;
|
|
180
|
-
} else if (isFuture && !allowFuture) {
|
|
232
|
+
// 1) Degenerate cases
|
|
233
|
+
if (isFuture && !allowFuture) {
|
|
181
234
|
console.warn(`Unexpected future date provided for timestamp: ${elapsed}ms in the future.`);
|
|
182
|
-
|
|
183
|
-
}
|
|
235
|
+
return '[????]';
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// 2) Handle (epsilon) equals
|
|
239
|
+
if (isEqual) {
|
|
240
|
+
return equalString;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// 3) Basic timestamp, with suffix /prefix
|
|
244
|
+
let ret = '';
|
|
245
|
+
if (elapsed < 60 * SECONDS) {
|
|
184
246
|
// By default, moment will show 'a few seconds' for durations of 0-45 seconds. At the higher
|
|
185
247
|
// end of that range that output is a bit too inaccurate, so we replace as per below.
|
|
186
|
-
ret =
|
|
248
|
+
ret = '<1 minute';
|
|
249
|
+
} else {
|
|
250
|
+
// Main delegate to humanize. Use 24h threshold vs. default 22h to avoid corner case
|
|
251
|
+
// transition w/localDateMode = limited: e.g. 21 hours -> zero days.
|
|
252
|
+
ret = moment.duration(elapsed).humanize({h: 24});
|
|
187
253
|
|
|
188
254
|
// Moment outputs e.g. "a minute" instead of "1 minute". This creates some awkwardness
|
|
189
255
|
// when the leading number comes and goes - "<1 minute" -> "a minute" -> "2 minutes".
|
|
190
256
|
ret = ret.replace(/^(an|a) /, '1 ');
|
|
191
|
-
|
|
192
|
-
if (short) ret = ret.replace('minute', 'min').replace('second', 'sec');
|
|
193
|
-
|
|
194
|
-
ret += ' ' + (isFuture ? opts.futureSuffix : opts.pastSuffix);
|
|
195
257
|
}
|
|
196
258
|
|
|
197
|
-
|
|
259
|
+
if (short) ret = ret.replace('minute', 'min').replace('second', 'sec');
|
|
260
|
+
const suffix = isFuture ? opts.futureSuffix : opts.pastSuffix;
|
|
261
|
+
if (suffix) ret = ret + ' ' + suffix;
|
|
262
|
+
|
|
263
|
+
return ret;
|
|
198
264
|
}
|
|
199
265
|
|
|
200
266
|
function toTimestamp(v: Date | number): number {
|
package/cmp/tab/TabContainer.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2023 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
import {
|
|
7
|
+
import {BoxProps, hoistCmp, HoistProps, refreshContextView, uses, XH} from '@xh/hoist/core';
|
|
8
8
|
import {tabContainerImpl as desktopTabContainerImpl} from '@xh/hoist/dynamics/desktop';
|
|
9
9
|
import {tabContainerImpl as mobileTabContainerImpl} from '@xh/hoist/dynamics/mobile';
|
|
10
10
|
import {TabContainerModel} from './TabContainerModel';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file belongs to Hoist, an application development toolkit
|
|
3
|
+
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
|
|
4
|
+
*
|
|
5
|
+
* Copyright © 2023 Extremely Heavy Industries Inc.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import {Column, ColumnRenderer, ColumnSortSpec} from '@xh/hoist/cmp/grid';
|
|
9
|
+
import {PersistOptions} from '@xh/hoist/core';
|
|
10
|
+
|
|
11
|
+
export type Zone = 'tl' | 'tr' | 'bl' | 'br';
|
|
12
|
+
|
|
13
|
+
export interface ZoneMapping {
|
|
14
|
+
/** Field to display. Must match a Field found in the Store */
|
|
15
|
+
field: string;
|
|
16
|
+
/** True to prefix the field value with its name */
|
|
17
|
+
showLabel?: boolean;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ZoneLimit {
|
|
21
|
+
/** Min number of fields that should be mapped to the zone */
|
|
22
|
+
min?: number;
|
|
23
|
+
/** Max number of fields that should be mapped to the zone */
|
|
24
|
+
max?: number;
|
|
25
|
+
/** Array of allowed fields for the zone */
|
|
26
|
+
only?: string[];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export interface ZoneField {
|
|
30
|
+
field: string;
|
|
31
|
+
displayName: string;
|
|
32
|
+
label: string;
|
|
33
|
+
renderer: ColumnRenderer;
|
|
34
|
+
column: Column;
|
|
35
|
+
chooserGroup: string;
|
|
36
|
+
sortable: boolean;
|
|
37
|
+
sortingOrder: ColumnSortSpec[];
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface ZoneGridModelPersistOptions extends PersistOptions {
|
|
41
|
+
/** True to include mapping information (default true) */
|
|
42
|
+
persistMapping?: boolean;
|
|
43
|
+
/** True to include grouping information (default true) */
|
|
44
|
+
persistGrouping?: boolean;
|
|
45
|
+
/** True to include sorting information (default true) */
|
|
46
|
+
persistSort?: boolean;
|
|
47
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* This file belongs to Hoist, an application development toolkit
|
|
3
|
+
* developed by Extremely Heavy Industries (www.xh.io | info@xh.io)
|
|
4
|
+
*
|
|
5
|
+
* Copyright © 2023 Extremely Heavy Industries Inc.
|
|
6
|
+
*/
|
|
7
|
+
import {hoistCmp, HoistProps, LayoutProps, TestSupportProps, uses, XH} from '@xh/hoist/core';
|
|
8
|
+
import {fragment} from '@xh/hoist/cmp/layout';
|
|
9
|
+
import {GridOptions} from '@xh/hoist/kit/ag-grid';
|
|
10
|
+
import {grid} from '@xh/hoist/cmp/grid';
|
|
11
|
+
import {splitLayoutProps} from '@xh/hoist/utils/react';
|
|
12
|
+
import {zoneMapper as desktopZoneMapper} from '@xh/hoist/dynamics/desktop';
|
|
13
|
+
import {zoneMapper as mobileZoneMapper} from '@xh/hoist/dynamics/mobile';
|
|
14
|
+
import {ZoneGridModel} from './ZoneGridModel';
|
|
15
|
+
|
|
16
|
+
export interface ZoneGridProps extends HoistProps<ZoneGridModel>, LayoutProps, TestSupportProps {
|
|
17
|
+
/**
|
|
18
|
+
* Options for ag-Grid's API.
|
|
19
|
+
*
|
|
20
|
+
* This constitutes an 'escape hatch' for applications that need to get to the underlying
|
|
21
|
+
* ag-Grid API. It should be used with care. Settings made here might be overwritten and/or
|
|
22
|
+
* interfere with the implementation of this component and its use of the ag-Grid API.
|
|
23
|
+
*
|
|
24
|
+
* Note that changes to these options after the component's initial render will be ignored.
|
|
25
|
+
*/
|
|
26
|
+
agOptions?: GridOptions;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* A ZoneGrid is a specialized version of the Grid component.
|
|
31
|
+
*
|
|
32
|
+
* It displays its data with multi-line full-width rows, each broken into four zones for
|
|
33
|
+
* top/bottom and left/right - (tl, tr, bl, br). Zone mappings determine which of the
|
|
34
|
+
* available fields should be extracted from the record and rendered into each zone.
|
|
35
|
+
*/
|
|
36
|
+
export const [ZoneGrid, zoneGrid] = hoistCmp.withFactory<ZoneGridProps>({
|
|
37
|
+
displayName: 'ZoneGrid',
|
|
38
|
+
model: uses(ZoneGridModel),
|
|
39
|
+
className: 'xh-zone-grid',
|
|
40
|
+
|
|
41
|
+
render({model, className, testId, ...props}, ref) {
|
|
42
|
+
const {gridModel, mapperModel} = model,
|
|
43
|
+
[layoutProps] = splitLayoutProps(props),
|
|
44
|
+
platformZoneMapper = XH.isMobileApp ? mobileZoneMapper : desktopZoneMapper;
|
|
45
|
+
|
|
46
|
+
return fragment(
|
|
47
|
+
grid({
|
|
48
|
+
...layoutProps,
|
|
49
|
+
className,
|
|
50
|
+
testId,
|
|
51
|
+
ref,
|
|
52
|
+
model: gridModel,
|
|
53
|
+
agOptions: {
|
|
54
|
+
suppressRowGroupHidesColumns: true,
|
|
55
|
+
suppressMakeColumnVisibleAfterUnGroup: true,
|
|
56
|
+
...props.agOptions
|
|
57
|
+
}
|
|
58
|
+
}),
|
|
59
|
+
mapperModel ? platformZoneMapper() : null
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
});
|