@xh/hoist 59.3.1 → 59.3.2
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 +6 -0
- package/cmp/zoneGrid/ZoneGridModel.ts +52 -36
- package/core/XH.ts +3 -3
- package/package.json +1 -1
- package/svc/EnvironmentService.ts +1 -1
- package/utils/async/Timer.ts +30 -18
package/CHANGELOG.md
CHANGED
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
} from '@ag-grid-community/core';
|
|
50
50
|
import {Icon} from '@xh/hoist/icon';
|
|
51
51
|
import {throwIf, withDefault} from '@xh/hoist/utils/js';
|
|
52
|
-
import {castArray, forOwn, isEmpty, isFinite, isPlainObject, isString} from 'lodash';
|
|
52
|
+
import {castArray, forOwn, isEmpty, isFinite, isPlainObject, isString, find} from 'lodash';
|
|
53
53
|
import {ReactNode} from 'react';
|
|
54
54
|
import {ZoneMapperConfig, ZoneMapperModel} from './impl/ZoneMapperModel';
|
|
55
55
|
import {ZoneGridPersistenceModel} from './impl/ZoneGridPersistenceModel';
|
|
@@ -326,7 +326,7 @@ export class ZoneGridModel extends HoistModel {
|
|
|
326
326
|
|
|
327
327
|
this.availableColumns = columns.map(it => ({...it, hidden: true}));
|
|
328
328
|
this.limits = limits;
|
|
329
|
-
this.mappings = this.parseMappings(mappings);
|
|
329
|
+
this.mappings = this.parseMappings(mappings, true);
|
|
330
330
|
|
|
331
331
|
this.leftColumnSpec = leftColumnSpec;
|
|
332
332
|
this.rightColumnSpec = rightColumnSpec;
|
|
@@ -397,7 +397,7 @@ export class ZoneGridModel extends HoistModel {
|
|
|
397
397
|
|
|
398
398
|
@action
|
|
399
399
|
setMappings(mappings: Record<Zone, Some<string | ZoneMapping>>) {
|
|
400
|
-
this.mappings = this.parseMappings(mappings);
|
|
400
|
+
this.mappings = this.parseMappings(mappings, false);
|
|
401
401
|
this.gridModel.setColumns(this.getColumns());
|
|
402
402
|
}
|
|
403
403
|
|
|
@@ -611,46 +611,62 @@ export class ZoneGridModel extends HoistModel {
|
|
|
611
611
|
}
|
|
612
612
|
|
|
613
613
|
private parseMappings(
|
|
614
|
-
mappings: Record<Zone, Some<string | ZoneMapping
|
|
614
|
+
mappings: Record<Zone, Some<string | ZoneMapping>>,
|
|
615
|
+
strict: boolean
|
|
615
616
|
): Record<Zone, ZoneMapping[]> {
|
|
616
617
|
const ret = {} as Record<Zone, ZoneMapping[]>;
|
|
617
|
-
forOwn(mappings, (rawMapping, zone) => {
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
if (
|
|
618
|
+
forOwn(mappings, (rawMapping, zone: Zone) => {
|
|
619
|
+
try {
|
|
620
|
+
ret[zone] = this.parseZoneMapping(zone, rawMapping);
|
|
621
|
+
} catch (e) {
|
|
622
|
+
if (strict) throw e;
|
|
623
|
+
console.warn(e.message);
|
|
624
|
+
ret[zone] = this._defaultState.mappings[zone];
|
|
625
|
+
}
|
|
626
|
+
});
|
|
627
|
+
return ret;
|
|
628
|
+
}
|
|
622
629
|
|
|
623
|
-
|
|
624
|
-
|
|
630
|
+
private parseZoneMapping(zone: Zone, rawMapping: Some<string | ZoneMapping>): ZoneMapping[] {
|
|
631
|
+
const ret: ZoneMapping[] = [];
|
|
625
632
|
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
633
|
+
// 1) Standardize raw mapping into an array of ZoneMappings
|
|
634
|
+
castArray(rawMapping).forEach(it => {
|
|
635
|
+
if (!it) return;
|
|
629
636
|
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
isFinite(limit.min) && mapping.length < limit.min,
|
|
635
|
-
`Requires minimum ${limit.min} mappings in zone "${zone}"`
|
|
636
|
-
);
|
|
637
|
-
throwIf(
|
|
638
|
-
isFinite(limit.max) && mapping.length > limit.max,
|
|
639
|
-
`Exceeds maximum ${limit.max} mappings in zone "${zone}"`
|
|
640
|
-
);
|
|
641
|
-
|
|
642
|
-
if (!isEmpty(limit.only)) {
|
|
643
|
-
mapping.forEach(it => {
|
|
644
|
-
throwIf(
|
|
645
|
-
!limit.only.includes(it.field),
|
|
646
|
-
`Field "${it.field}" not allowed in zone "${zone}"`
|
|
647
|
-
);
|
|
648
|
-
});
|
|
649
|
-
}
|
|
650
|
-
}
|
|
637
|
+
const fieldSpec = isString(it) ? {field: it} : it,
|
|
638
|
+
col = this.findColumnSpec(fieldSpec);
|
|
639
|
+
|
|
640
|
+
throwIf(!col, `Column not found for field '${fieldSpec.field}'`);
|
|
651
641
|
|
|
652
|
-
ret
|
|
642
|
+
ret.push(fieldSpec);
|
|
653
643
|
});
|
|
644
|
+
|
|
645
|
+
// 2) Ensure we respect configured limits
|
|
646
|
+
const limit = this.limits?.[zone];
|
|
647
|
+
if (limit) {
|
|
648
|
+
throwIf(
|
|
649
|
+
isFinite(limit.min) && ret.length < limit.min,
|
|
650
|
+
`Requires minimum ${limit.min} mappings in zone "${zone}."`
|
|
651
|
+
);
|
|
652
|
+
|
|
653
|
+
throwIf(
|
|
654
|
+
isFinite(limit.max) && ret.length > limit.max,
|
|
655
|
+
`Exceeds maximum ${limit.max} mappings in zone "${zone}".`
|
|
656
|
+
);
|
|
657
|
+
|
|
658
|
+
if (!isEmpty(limit.only)) {
|
|
659
|
+
const offender = find(ret, it => !limit.only.includes(it.field));
|
|
660
|
+
throwIf(offender, `Field "${offender?.field}" not allowed in zone "${zone}".`);
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
// 3) Ensure top zones have at least the minimum required single field
|
|
665
|
+
throwIf(
|
|
666
|
+
(zone == 'tl' || zone == 'tr') && isEmpty(ret),
|
|
667
|
+
`Top mapping '${zone}' requires at least one field.`
|
|
668
|
+
);
|
|
669
|
+
|
|
654
670
|
return ret;
|
|
655
671
|
}
|
|
656
672
|
|
package/core/XH.ts
CHANGED
|
@@ -674,9 +674,9 @@ export class XHApi {
|
|
|
674
674
|
|
|
675
675
|
/** Get the first active model that matches the given selector, or null if none found. */
|
|
676
676
|
getModel<T extends HoistModel>(selector: ModelSelector = '*'): T {
|
|
677
|
-
instanceManager.models
|
|
678
|
-
if (m.matchesSelector(selector, true)) return m;
|
|
679
|
-
}
|
|
677
|
+
for (let m of instanceManager.models) {
|
|
678
|
+
if (m.matchesSelector(selector, true)) return m as T;
|
|
679
|
+
}
|
|
680
680
|
return null;
|
|
681
681
|
}
|
|
682
682
|
|
package/package.json
CHANGED
|
@@ -125,7 +125,7 @@ export class EnvironmentService extends HoistService {
|
|
|
125
125
|
} else if (mode === 'forceReload') {
|
|
126
126
|
XH.suspendApp({
|
|
127
127
|
reason: 'APP_UPDATE',
|
|
128
|
-
message: `A new version of ${XH.clientAppName} is available
|
|
128
|
+
message: `A new version of ${XH.clientAppName} is now available (${appVersion}) and requires an immediate update.`
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
131
|
}
|
package/utils/async/Timer.ts
CHANGED
|
@@ -15,19 +15,20 @@ import {isBoolean, isFinite, isFunction, isNil, isString, pull} from 'lodash';
|
|
|
15
15
|
* Promise-aware recurring task timer for use by framework and applications.
|
|
16
16
|
*
|
|
17
17
|
* This object is designed to be robust across failing tasks, and never to re-run the task
|
|
18
|
-
* simultaneously, unless in the case of a timeout.
|
|
19
|
-
*
|
|
18
|
+
* simultaneously, unless in the case of a timeout. Callers can optionally specify the duration
|
|
19
|
+
* of asynchronous tasks by returning a Promise from runFn.
|
|
20
20
|
*
|
|
21
|
-
* This object seeks to mirror the API and semantics of
|
|
22
|
-
* as
|
|
23
|
-
*
|
|
24
|
-
*
|
|
21
|
+
* This object seeks to mirror the API and semantics of `Timer.groovy` from Hoist Core as closely
|
|
22
|
+
* as possible. However, there are important differences due to the synchronous nature of
|
|
23
|
+
* javascript. In particular, there is no support for `runImmediatelyAndBlock`, and the `timeout`
|
|
24
|
+
* argument will not be able to interrupt synchronous activity of the runFn.
|
|
25
25
|
*
|
|
26
|
-
* All public properties should be considered read-only.
|
|
27
|
-
* of this
|
|
26
|
+
* All public properties should be considered read-only.
|
|
27
|
+
* See `setInterval()` to change the interval of this Timer dynamically.
|
|
28
28
|
*/
|
|
29
29
|
export class Timer {
|
|
30
30
|
static _timers: Timer[] = [];
|
|
31
|
+
static MIN_INTERVAL_MS = 500;
|
|
31
32
|
|
|
32
33
|
runFn: () => any = null;
|
|
33
34
|
interval: number | (() => number) = null;
|
|
@@ -41,6 +42,8 @@ export class Timer {
|
|
|
41
42
|
isRunning: boolean = false;
|
|
42
43
|
lastRun: Date = null;
|
|
43
44
|
|
|
45
|
+
private warnedIntervals = new Set();
|
|
46
|
+
|
|
44
47
|
/** Create a new Timer. */
|
|
45
48
|
static create({
|
|
46
49
|
runFn,
|
|
@@ -67,9 +70,7 @@ export class Timer {
|
|
|
67
70
|
this._timers = [];
|
|
68
71
|
}
|
|
69
72
|
|
|
70
|
-
/**
|
|
71
|
-
* Permanently cancel this timer.
|
|
72
|
-
*/
|
|
73
|
+
/** Permanently cancel this timer. */
|
|
73
74
|
cancel() {
|
|
74
75
|
this.cancelInternal();
|
|
75
76
|
pull(Timer._timers, this);
|
|
@@ -77,7 +78,6 @@ export class Timer {
|
|
|
77
78
|
|
|
78
79
|
/**
|
|
79
80
|
* Change the interval of this timer.
|
|
80
|
-
*
|
|
81
81
|
* @param interval - ms to wait between runs or any value `<=0` to pause the timer.
|
|
82
82
|
*/
|
|
83
83
|
setInterval(interval: number) {
|
|
@@ -94,7 +94,10 @@ export class Timer {
|
|
|
94
94
|
this.intervalUnits = args.intervalUnits;
|
|
95
95
|
this.timeoutUnits = args.timeoutUnits;
|
|
96
96
|
this.delay = this.parseDelay(args.delay);
|
|
97
|
-
throwIf(
|
|
97
|
+
throwIf(
|
|
98
|
+
this.interval == null || this.runFn == null,
|
|
99
|
+
'Missing required arguments for Timer - both interval and runFn must be specified.'
|
|
100
|
+
);
|
|
98
101
|
|
|
99
102
|
wait(this.delay).then(() => this.heartbeatAsync());
|
|
100
103
|
}
|
|
@@ -133,18 +136,27 @@ export class Timer {
|
|
|
133
136
|
return isString(val) ? () => XH.configService.get(val) : val;
|
|
134
137
|
}
|
|
135
138
|
|
|
136
|
-
private parseDelay(val): number {
|
|
139
|
+
private parseDelay(val: number | boolean): number {
|
|
137
140
|
if (isBoolean(val)) return val ? this.intervalMs : 0;
|
|
138
141
|
return isFinite(val) ? val : 0;
|
|
139
142
|
}
|
|
140
143
|
|
|
141
144
|
private get intervalMs() {
|
|
142
|
-
const {interval, intervalUnits} = this
|
|
145
|
+
const {interval, intervalUnits, warnedIntervals} = this,
|
|
146
|
+
min = Timer.MIN_INTERVAL_MS;
|
|
147
|
+
|
|
143
148
|
if (isNil(interval)) return null;
|
|
149
|
+
|
|
144
150
|
let ret = (isFunction(interval) ? interval() : interval) * intervalUnits;
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
ret
|
|
151
|
+
|
|
152
|
+
if (ret > 0 && ret < min) {
|
|
153
|
+
if (!warnedIntervals.has(ret)) {
|
|
154
|
+
warnedIntervals.add(ret);
|
|
155
|
+
console.warn(
|
|
156
|
+
`Timer interval of ${ret}ms requested - forcing to min interval of ${min}ms.`
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
ret = min;
|
|
148
160
|
}
|
|
149
161
|
return ret;
|
|
150
162
|
}
|