@xh/hoist 59.4.0 → 59.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -1
- package/appcontainer/AppStateModel.ts +1 -1
- package/cmp/ag-grid/AgGridModel.ts +11 -5
- package/cmp/grid/Grid.ts +8 -6
- package/cmp/grid/impl/Utils.ts +1 -1
- package/cmp/relativetimestamp/RelativeTimestamp.ts +5 -2
- package/cmp/zoneGrid/ZoneGridModel.ts +1 -1
- package/core/HoistBase.ts +7 -6
- package/core/HoistBaseDecorators.ts +11 -6
- package/core/HoistComponent.ts +1 -3
- package/core/exception/ExceptionHandler.ts +4 -4
- package/core/load/LoadSupport.ts +7 -8
- package/data/cube/aggregate/UniqueAggregator.ts +3 -5
- package/desktop/cmp/button/ColChooserButton.ts +7 -5
- package/desktop/cmp/button/ZoneMapperButton.ts +7 -5
- package/desktop/cmp/dash/canvas/DashCanvasModel.ts +2 -2
- package/desktop/cmp/dash/container/DashContainerModel.ts +2 -2
- package/desktop/cmp/dock/DockViewModel.ts +21 -11
- package/desktop/cmp/dock/impl/DockView.ts +4 -2
- package/desktop/cmp/form/FormField.ts +2 -2
- package/desktop/cmp/grid/editors/BooleanEditor.ts +5 -1
- package/desktop/cmp/grid/editors/DateEditor.ts +2 -2
- package/desktop/cmp/input/DateInput.ts +1 -3
- package/desktop/cmp/panel/Panel.ts +4 -2
- package/desktop/cmp/panel/PanelModel.ts +5 -5
- package/desktop/cmp/treemap/TreeMap.ts +4 -3
- package/inspector/instances/InstancesModel.ts +6 -6
- package/mobile/cmp/button/ColAutosizeButton.ts +4 -3
- package/mobile/cmp/button/ColChooserButton.ts +4 -3
- package/mobile/cmp/button/ExpandCollapseButton.ts +4 -3
- package/mobile/cmp/button/ZoneMapperButton.ts +4 -3
- package/mobile/cmp/input/DateInput.ts +1 -1
- package/mobile/cmp/input/Select.ts +3 -3
- package/mobile/cmp/panel/Panel.ts +4 -2
- package/package.json +2 -2
- package/svc/AutoRefreshService.ts +1 -1
- package/svc/ChangelogService.ts +3 -3
- package/svc/EnvironmentService.ts +1 -1
- package/svc/GridExportService.ts +3 -8
- package/svc/IdentityService.ts +1 -1
- package/svc/TrackService.ts +3 -9
- package/utils/async/Timer.ts +2 -2
- package/utils/datetime/LocalDate.ts +13 -13
- package/utils/js/Decorators.ts +18 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,11 +1,31 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 59.5.1 - 2024-01-05
|
|
4
|
+
|
|
5
|
+
### 🐞 Bug Fixes
|
|
6
|
+
|
|
7
|
+
* Fixed `DateEditor` calendar popover not showing for non-pinned columns.
|
|
8
|
+
|
|
9
|
+
## 59.5.0 - 2023-12-11
|
|
10
|
+
|
|
11
|
+
### 🎁 New Features
|
|
12
|
+
|
|
13
|
+
* Added new `dialogWidth` and `dialogHeight` configs to `DockViewModel`.
|
|
14
|
+
|
|
15
|
+
### 🐞 Bug Fixes
|
|
16
|
+
|
|
17
|
+
* Fixed serialization of expand/collapse state within `AgGridModel`, which was badly broken and
|
|
18
|
+
could trigger long browser hangs for grids with > 2 levels of nesting and numeric record IDs.
|
|
19
|
+
* Fixed `UniqueAggregator` to properly check equality for `Date` fields.
|
|
20
|
+
* Pinned `react-grid-layout@1.4.3` to avoid v1.4.4 bugs affecting `DashCanvas` interactions
|
|
21
|
+
(see https://github.com/react-grid-layout/react-grid-layout/issues/1990).
|
|
22
|
+
|
|
3
23
|
## 59.4.0 - 2023-11-28
|
|
4
24
|
|
|
5
25
|
### 💥 Breaking Changes
|
|
6
26
|
|
|
7
27
|
* The constructors for `ColumnGroup` no long accept arbitrary rest (e.g `...rest`)
|
|
8
|
-
arguments for applying app-specific data to the object. Instead, use the new `appData` property.
|
|
28
|
+
arguments for applying app-specific data to the object. Instead, use the new `appData` property.
|
|
9
29
|
|
|
10
30
|
### ⚙️ Technical
|
|
11
31
|
|
|
@@ -34,7 +34,7 @@ export class AppStateModel extends HoistModel {
|
|
|
34
34
|
@action
|
|
35
35
|
setAppState(nextState: AppState) {
|
|
36
36
|
if (this.state !== nextState) {
|
|
37
|
-
this.logDebug(`AppState change
|
|
37
|
+
this.logDebug(`AppState change`, `${this.state} → ${nextState}`);
|
|
38
38
|
}
|
|
39
39
|
this.state = nextState;
|
|
40
40
|
}
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
isEqual,
|
|
20
20
|
isNil,
|
|
21
21
|
partition,
|
|
22
|
-
|
|
22
|
+
setWith,
|
|
23
23
|
startCase
|
|
24
24
|
} from 'lodash';
|
|
25
25
|
import {GridSorter, GridSorterLike} from '../grid/GridSorter';
|
|
@@ -466,8 +466,12 @@ export class AgGridModel extends HoistModel {
|
|
|
466
466
|
this._prevSortBy = sortBy;
|
|
467
467
|
}
|
|
468
468
|
|
|
469
|
-
/**
|
|
470
|
-
|
|
469
|
+
/**
|
|
470
|
+
* @returns the current row expansion state of the grid in a serializable form.
|
|
471
|
+
* Returned object has keys for StoreRecordIds of top-level, expanded records and values
|
|
472
|
+
* of either `true` or an object with keys of StoreRecordIds of expanded child records.
|
|
473
|
+
*/
|
|
474
|
+
getExpandState(): PlainObject {
|
|
471
475
|
this.throwIfNotReady();
|
|
472
476
|
|
|
473
477
|
const expandState = {};
|
|
@@ -486,8 +490,10 @@ export class AgGridModel extends HoistModel {
|
|
|
486
490
|
return;
|
|
487
491
|
}
|
|
488
492
|
|
|
493
|
+
// Note use of setWith + customizer - required to ensure that nested nodes are
|
|
494
|
+
// serialized as objects - see https://github.com/xh/hoist-react/issues/3550.
|
|
489
495
|
const path = this.getGroupNodePath(node);
|
|
490
|
-
|
|
496
|
+
setWith(expandState, path, true, () => ({}));
|
|
491
497
|
}
|
|
492
498
|
});
|
|
493
499
|
|
|
@@ -498,7 +504,7 @@ export class AgGridModel extends HoistModel {
|
|
|
498
504
|
* Sets the grid row expansion state
|
|
499
505
|
* @param expandState - grid expand state retrieved via getExpandState()
|
|
500
506
|
*/
|
|
501
|
-
setExpandState(expandState:
|
|
507
|
+
setExpandState(expandState: PlainObject) {
|
|
502
508
|
this.throwIfNotReady();
|
|
503
509
|
|
|
504
510
|
const {agApi} = this;
|
package/cmp/grid/Grid.ts
CHANGED
|
@@ -634,9 +634,8 @@ export class GridLocalModel extends HoistModel {
|
|
|
634
634
|
let transaction = null;
|
|
635
635
|
if (prevCount !== 0) {
|
|
636
636
|
transaction = this.genTransaction(newRs, prevRs);
|
|
637
|
-
this.logDebug(this.transactionLogStr(transaction));
|
|
638
|
-
|
|
639
637
|
if (!this.transactionIsEmpty(transaction)) {
|
|
638
|
+
this.logDebug(...this.genTxnLogMsgs(transaction));
|
|
640
639
|
agApi.applyTransaction(transaction);
|
|
641
640
|
}
|
|
642
641
|
} else {
|
|
@@ -698,10 +697,13 @@ export class GridLocalModel extends HoistModel {
|
|
|
698
697
|
return isEmpty(t.update) && isEmpty(t.add) && isEmpty(t.remove);
|
|
699
698
|
}
|
|
700
699
|
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
700
|
+
private genTxnLogMsgs(t): string[] {
|
|
701
|
+
const {add, update, remove} = t;
|
|
702
|
+
return [
|
|
703
|
+
`update: ${update ? update.length : 0}`,
|
|
704
|
+
`add: ${add ? add.length : 0}`,
|
|
705
|
+
`remove: ${remove ? remove.length : 0}`
|
|
706
|
+
];
|
|
705
707
|
}
|
|
706
708
|
|
|
707
709
|
//------------------------
|
package/cmp/grid/impl/Utils.ts
CHANGED
|
@@ -19,7 +19,7 @@ export function managedRenderer<T extends ColumnRenderer | GroupRowRenderer>(
|
|
|
19
19
|
try {
|
|
20
20
|
return fn.apply(null, arguments);
|
|
21
21
|
} catch (e) {
|
|
22
|
-
console.warn(`Renderer for '${identifier}' has thrown an error
|
|
22
|
+
console.warn(`Renderer for '${identifier}' has thrown an error`, e);
|
|
23
23
|
return '#ERROR';
|
|
24
24
|
}
|
|
25
25
|
} as unknown as T;
|
|
@@ -20,7 +20,7 @@ import {fmtCompactDate, fmtDateTime} from '@xh/hoist/format';
|
|
|
20
20
|
import {action, computed, makeObservable, observable} from '@xh/hoist/mobx';
|
|
21
21
|
import {Timer} from '@xh/hoist/utils/async';
|
|
22
22
|
import {DAYS, HOURS, LocalDate, SECONDS} from '@xh/hoist/utils/datetime';
|
|
23
|
-
import {withDefault} from '@xh/hoist/utils/js';
|
|
23
|
+
import {logWarn, withDefault} from '@xh/hoist/utils/js';
|
|
24
24
|
|
|
25
25
|
interface RelativeTimestampProps extends HoistProps, BoxProps {
|
|
26
26
|
/**
|
|
@@ -231,7 +231,10 @@ function doFormat(timestamp: Date | number, opts: RelativeTimestampOptions): str
|
|
|
231
231
|
|
|
232
232
|
// 1) Degenerate cases
|
|
233
233
|
if (isFuture && !allowFuture) {
|
|
234
|
-
|
|
234
|
+
logWarn(
|
|
235
|
+
`Unexpected future date provided for timestamp: ${elapsed}ms in the future.`,
|
|
236
|
+
RelativeTimestamp
|
|
237
|
+
);
|
|
235
238
|
return '[????]';
|
|
236
239
|
}
|
|
237
240
|
|
|
@@ -620,7 +620,7 @@ export class ZoneGridModel extends HoistModel {
|
|
|
620
620
|
ret[zone] = this.parseZoneMapping(zone, rawMapping);
|
|
621
621
|
} catch (e) {
|
|
622
622
|
if (strict) throw e;
|
|
623
|
-
|
|
623
|
+
this.logWarn(e.message);
|
|
624
624
|
ret[zone] = this._defaultState.mappings[zone];
|
|
625
625
|
}
|
|
626
626
|
});
|
package/core/HoistBase.ts
CHANGED
|
@@ -140,12 +140,12 @@ export abstract class HoistBase {
|
|
|
140
140
|
addReaction(...specs: ReactionSpec<any>[]): IReactionDisposer | IReactionDisposer[] {
|
|
141
141
|
const disposers = specs.map(s => {
|
|
142
142
|
if (!s) return null;
|
|
143
|
-
let {track, when, run, debounce, ...
|
|
143
|
+
let {track, when, run, debounce, ...rest} = s;
|
|
144
144
|
throwIf(
|
|
145
145
|
(track && when) || (!track && !when),
|
|
146
146
|
"Must specify either 'track' or 'when' in addReaction."
|
|
147
147
|
);
|
|
148
|
-
opts = parseReactionOptions(
|
|
148
|
+
const opts = parseReactionOptions(rest);
|
|
149
149
|
run = bindAndDebounce(this, run, debounce);
|
|
150
150
|
|
|
151
151
|
const disposer = track ? mobxReaction(track, run, opts) : mobxWhen(when, run, opts);
|
|
@@ -267,9 +267,10 @@ export abstract class HoistBase {
|
|
|
267
267
|
run: data => provider.write(data)
|
|
268
268
|
});
|
|
269
269
|
} catch (e) {
|
|
270
|
-
|
|
270
|
+
this.logError(
|
|
271
271
|
`Failed to configure Persistence for '${property}'. Be sure to fully specify ` +
|
|
272
|
-
`'persistWith' on this object or in the method call
|
|
272
|
+
`'persistWith' on this object or in the method call`,
|
|
273
|
+
e
|
|
273
274
|
);
|
|
274
275
|
}
|
|
275
276
|
}
|
|
@@ -293,7 +294,7 @@ export abstract class HoistBase {
|
|
|
293
294
|
/**
|
|
294
295
|
* Object containing options accepted by MobX 'reaction' API as well as arguments below.
|
|
295
296
|
*/
|
|
296
|
-
export
|
|
297
|
+
export interface ReactionSpec<T = any> extends Omit<IReactionOptions<T, any>, 'equals'> {
|
|
297
298
|
/**
|
|
298
299
|
* Function returning data to observe - first arg to the underlying reaction() call.
|
|
299
300
|
* Specify this or `when`.
|
|
@@ -314,7 +315,7 @@ export type ReactionSpec<T = any> = IReactionOptions<T, any> & {
|
|
|
314
315
|
|
|
315
316
|
/** Specify a default from {@link comparer} or a custom comparer function. */
|
|
316
317
|
equals?: keyof typeof comparer | IEqualsComparer<T>;
|
|
317
|
-
}
|
|
318
|
+
}
|
|
318
319
|
|
|
319
320
|
/**
|
|
320
321
|
* Object containing options accepted by MobX 'autorun' API as well as arguments below.
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import {cloneDeep, isUndefined} from 'lodash';
|
|
8
8
|
import {wait} from '../promise';
|
|
9
|
-
import {throwIf} from '../utils/js';
|
|
9
|
+
import {logError, throwIf} from '../utils/js';
|
|
10
10
|
import {HoistBaseClass, PersistenceProvider, PersistOptions} from './';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -66,9 +66,10 @@ function createPersistDescriptor(
|
|
|
66
66
|
'@persist decorator should be applied to an instance of HoistBase'
|
|
67
67
|
);
|
|
68
68
|
if (descriptor.get || descriptor.set) {
|
|
69
|
-
|
|
69
|
+
logError(
|
|
70
70
|
`Error defining ${property} : @persist or @persistWith should be defined closest ` +
|
|
71
|
-
`to property, and after mobx annotation e.g. '@bindable @persist ${property}'
|
|
71
|
+
`to property, and after mobx annotation e.g. '@bindable @persist ${property}'`,
|
|
72
|
+
target
|
|
72
73
|
);
|
|
73
74
|
return descriptor;
|
|
74
75
|
}
|
|
@@ -89,9 +90,13 @@ function createPersistDescriptor(
|
|
|
89
90
|
});
|
|
90
91
|
});
|
|
91
92
|
} catch (e) {
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
`'
|
|
93
|
+
logError(
|
|
94
|
+
[
|
|
95
|
+
`Failed to configure Persistence for '${property}'. Be sure to fully specify ` +
|
|
96
|
+
`'persistWith' on this object or annotation`,
|
|
97
|
+
e
|
|
98
|
+
],
|
|
99
|
+
target
|
|
95
100
|
);
|
|
96
101
|
}
|
|
97
102
|
|
package/core/HoistComponent.ts
CHANGED
|
@@ -282,9 +282,7 @@ function wrapWithModel(render: RenderFn, cfg: Config): RenderFn {
|
|
|
282
282
|
if (!model && !spec.optional && spec instanceof UsesSpec) {
|
|
283
283
|
console.error(`
|
|
284
284
|
Failed to find model with selector '${formatSelector(spec.selector)}' for
|
|
285
|
-
component '${
|
|
286
|
-
cfg.displayName
|
|
287
|
-
}'. Ensure the proper model is available via context, or
|
|
285
|
+
component '${cfg.displayName}'. Ensure the proper model is available via context, or
|
|
288
286
|
specify explicitly using the 'model' prop.
|
|
289
287
|
`);
|
|
290
288
|
return cmpErrDisplay({...getLayoutProps(props), item: 'No model found'});
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import {Exception} from './Exception';
|
|
8
8
|
import {fragment, span} from '@xh/hoist/cmp/layout';
|
|
9
|
-
import {stripTags} from '@xh/hoist/utils/js';
|
|
9
|
+
import {logError, logWarn, stripTags} from '@xh/hoist/utils/js';
|
|
10
10
|
import {Icon} from '@xh/hoist/icon';
|
|
11
11
|
import {forOwn, has, isArray, isNil, isObject, omitBy, pick, set} from 'lodash';
|
|
12
12
|
import {HoistException, PlainObject, XH} from '../';
|
|
@@ -189,7 +189,7 @@ export class ExceptionHandler {
|
|
|
189
189
|
username = XH.getUsername();
|
|
190
190
|
|
|
191
191
|
if (!username) {
|
|
192
|
-
|
|
192
|
+
logWarn('Error report cannot be submitted to UI server - user unknown', this);
|
|
193
193
|
return false;
|
|
194
194
|
}
|
|
195
195
|
|
|
@@ -206,7 +206,7 @@ export class ExceptionHandler {
|
|
|
206
206
|
});
|
|
207
207
|
return true;
|
|
208
208
|
} catch (e) {
|
|
209
|
-
|
|
209
|
+
logError(['Exception while submitting error report to UI server', e], this);
|
|
210
210
|
return false;
|
|
211
211
|
}
|
|
212
212
|
}
|
|
@@ -261,7 +261,7 @@ export class ExceptionHandler {
|
|
|
261
261
|
return stripTags(JSON.stringify(ret, null, 4));
|
|
262
262
|
} catch (e) {
|
|
263
263
|
const message = 'Failed to serialize error';
|
|
264
|
-
|
|
264
|
+
logError([message, exception, e], this);
|
|
265
265
|
return JSON.stringify({message}, null, 4);
|
|
266
266
|
}
|
|
267
267
|
}
|
package/core/load/LoadSupport.ts
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
import {HoistBase, managed, PlainObject, RefreshContextModel, TaskObserver} from '../';
|
|
8
8
|
import {LoadSpec, Loadable} from './';
|
|
9
9
|
import {makeObservable, observable, runInAction} from '@xh/hoist/mobx';
|
|
10
|
-
import {throwIf} from '@xh/hoist/utils/js';
|
|
11
|
-
import {isPlainObject} from 'lodash';
|
|
10
|
+
import {logDebug, logError, throwIf} from '@xh/hoist/utils/js';
|
|
11
|
+
import {isPlainObject, pull} from 'lodash';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
14
|
* Provides support for objects that participate in Hoist's loading/refresh lifecycle.
|
|
@@ -98,18 +98,17 @@ export class LoadSupport extends HoistBase implements Loadable {
|
|
|
98
98
|
if (target instanceof RefreshContextModel) return;
|
|
99
99
|
|
|
100
100
|
const elapsed = this.lastLoadCompleted.getTime() - this.lastLoadRequested.getTime(),
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}${elapsed}ms`;
|
|
101
|
+
status = exception ? 'failed' : null,
|
|
102
|
+
msg = pull([loadSpec.typeDisplay, status, `${elapsed}ms`, exception], null);
|
|
104
103
|
|
|
105
104
|
if (exception) {
|
|
106
105
|
if (exception.isRoutine) {
|
|
107
|
-
|
|
106
|
+
logDebug(msg, target);
|
|
108
107
|
} else {
|
|
109
|
-
|
|
108
|
+
logError(msg, target);
|
|
110
109
|
}
|
|
111
110
|
} else {
|
|
112
|
-
|
|
111
|
+
logDebug(msg, target);
|
|
113
112
|
}
|
|
114
113
|
});
|
|
115
114
|
}
|
|
@@ -4,20 +4,18 @@
|
|
|
4
4
|
*
|
|
5
5
|
* Copyright © 2023 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
|
-
|
|
8
7
|
import {Aggregator} from './Aggregator';
|
|
9
|
-
import {isEmpty} from 'lodash';
|
|
8
|
+
import {isEmpty, isEqual} from 'lodash';
|
|
10
9
|
|
|
11
10
|
export class UniqueAggregator extends Aggregator {
|
|
12
11
|
override aggregate(rows, fieldName) {
|
|
13
12
|
if (isEmpty(rows)) return null;
|
|
14
|
-
|
|
15
13
|
const val = rows[0].data[fieldName];
|
|
16
|
-
return rows.every(it => it.data[fieldName]
|
|
14
|
+
return rows.every(it => isEqual(it.data[fieldName], val)) ? val : null;
|
|
17
15
|
}
|
|
18
16
|
|
|
19
17
|
override replace(rows, currAgg, update, context) {
|
|
20
18
|
const {newValue} = update;
|
|
21
|
-
return rows.length === 1 || newValue
|
|
19
|
+
return rows.length === 1 || isEqual(newValue, currAgg) ? newValue : null;
|
|
22
20
|
}
|
|
23
21
|
}
|
|
@@ -12,7 +12,7 @@ import {ColChooserModel} from '@xh/hoist/desktop/cmp/grid/impl/colchooser/ColCho
|
|
|
12
12
|
import '@xh/hoist/desktop/register';
|
|
13
13
|
import {Icon} from '@xh/hoist/icon';
|
|
14
14
|
import {popover, Position} from '@xh/hoist/kit/blueprint';
|
|
15
|
-
import {stopPropagation, withDefault} from '@xh/hoist/utils/js';
|
|
15
|
+
import {logError, stopPropagation, withDefault} from '@xh/hoist/utils/js';
|
|
16
16
|
import {button, ButtonProps} from './Button';
|
|
17
17
|
|
|
18
18
|
export interface ColChooserButtonProps extends ButtonProps {
|
|
@@ -40,15 +40,17 @@ export const [ColChooserButton, colChooserButton] = hoistCmp.withFactory<ColChoo
|
|
|
40
40
|
const colChooserModel = gridModel?.colChooserModel as ColChooserModel;
|
|
41
41
|
|
|
42
42
|
if (!gridModel) {
|
|
43
|
-
|
|
44
|
-
"No GridModel available
|
|
43
|
+
logError(
|
|
44
|
+
"No GridModel available. Provide via a 'gridModel' prop, or context.",
|
|
45
|
+
ColChooserButton
|
|
45
46
|
);
|
|
46
47
|
disabled = true;
|
|
47
48
|
}
|
|
48
49
|
|
|
49
50
|
if (!colChooserModel) {
|
|
50
|
-
|
|
51
|
-
'No ColChooserModel available on bound GridModel - enable via GridModel.colChooserModel config.'
|
|
51
|
+
logError(
|
|
52
|
+
'No ColChooserModel available on bound GridModel - enable via GridModel.colChooserModel config.',
|
|
53
|
+
ColChooserButton
|
|
52
54
|
);
|
|
53
55
|
disabled = true;
|
|
54
56
|
}
|
|
@@ -12,7 +12,7 @@ import {ZoneMapperModel} from '@xh/hoist/cmp/zoneGrid/impl/ZoneMapperModel';
|
|
|
12
12
|
import {zoneMapper} from '@xh/hoist/desktop/cmp/zoneGrid/impl/ZoneMapper';
|
|
13
13
|
import {Icon} from '@xh/hoist/icon';
|
|
14
14
|
import {popover, Position} from '@xh/hoist/kit/blueprint';
|
|
15
|
-
import {stopPropagation, withDefault} from '@xh/hoist/utils/js';
|
|
15
|
+
import {logError, stopPropagation, withDefault} from '@xh/hoist/utils/js';
|
|
16
16
|
import {button, ButtonProps} from './Button';
|
|
17
17
|
|
|
18
18
|
export interface ZoneMapperButtonProps extends ButtonProps {
|
|
@@ -37,15 +37,17 @@ export const [ZoneMapperButton, zoneMapperButton] = hoistCmp.withFactory<ZoneMap
|
|
|
37
37
|
const mapperModel = zoneGridModel?.mapperModel as ZoneMapperModel;
|
|
38
38
|
|
|
39
39
|
if (!zoneGridModel) {
|
|
40
|
-
|
|
41
|
-
"No ZoneGridModel available
|
|
40
|
+
logError(
|
|
41
|
+
"No ZoneGridModel available. Provide via a 'zoneGridModel' prop, or context.",
|
|
42
|
+
ZoneMapperButton
|
|
42
43
|
);
|
|
43
44
|
disabled = true;
|
|
44
45
|
}
|
|
45
46
|
|
|
46
47
|
if (!mapperModel) {
|
|
47
|
-
|
|
48
|
-
'No ZoneMapperModel available on bound ZoneGridModel - enable via ZoneGridModel.zoneMapperModel config.'
|
|
48
|
+
logError(
|
|
49
|
+
'No ZoneMapperModel available on bound ZoneGridModel - enable via ZoneGridModel.zoneMapperModel config.',
|
|
50
|
+
ZoneMapperButton
|
|
49
51
|
);
|
|
50
52
|
disabled = true;
|
|
51
53
|
}
|
|
@@ -189,7 +189,7 @@ export class DashCanvasModel extends DashModel<
|
|
|
189
189
|
this.provider = PersistenceProvider.create({path: 'dashCanvas', ...persistWith});
|
|
190
190
|
persistState = this.provider.read();
|
|
191
191
|
} catch (e) {
|
|
192
|
-
|
|
192
|
+
this.logError(e);
|
|
193
193
|
XH.safeDestroy(this.provider);
|
|
194
194
|
this.provider = null;
|
|
195
195
|
}
|
|
@@ -419,7 +419,7 @@ export class DashCanvasModel extends DashModel<
|
|
|
419
419
|
if (this.hasSpec(viewSpecId)) {
|
|
420
420
|
this.addViewInternal(viewSpecId, state);
|
|
421
421
|
} else {
|
|
422
|
-
|
|
422
|
+
this.logWarn(`Unknown viewSpecId [${viewSpecId}] found in state - skipping.`);
|
|
423
423
|
}
|
|
424
424
|
});
|
|
425
425
|
} finally {
|
|
@@ -195,7 +195,7 @@ export class DashContainerModel extends DashModel<
|
|
|
195
195
|
this.provider = PersistenceProvider.create({path: 'dashContainer', ...persistWith});
|
|
196
196
|
persistState = this.provider.read();
|
|
197
197
|
} catch (e) {
|
|
198
|
-
|
|
198
|
+
this.logError(e);
|
|
199
199
|
XH.safeDestroy(this.provider);
|
|
200
200
|
this.provider = null;
|
|
201
201
|
}
|
|
@@ -238,7 +238,7 @@ export class DashContainerModel extends DashModel<
|
|
|
238
238
|
async loadStateAsync(state) {
|
|
239
239
|
const containerEl = this.containerRef.current;
|
|
240
240
|
if (!containerEl) {
|
|
241
|
-
|
|
241
|
+
this.logWarn(
|
|
242
242
|
'DashboardContainer not yet rendered - cannot update state - change will be discarded!'
|
|
243
243
|
);
|
|
244
244
|
return;
|
|
@@ -33,12 +33,16 @@ export interface DockViewConfig {
|
|
|
33
33
|
icon?: ReactElement;
|
|
34
34
|
/** Content to be rendered by this DockView. */
|
|
35
35
|
content: Content;
|
|
36
|
-
/** Width
|
|
37
|
-
width?: number;
|
|
38
|
-
/** Height
|
|
39
|
-
height?: number;
|
|
40
|
-
/** Width of collapsed header
|
|
41
|
-
collapsedWidth?: number;
|
|
36
|
+
/** Width: if not set, will be determined by content. */
|
|
37
|
+
width?: string | number;
|
|
38
|
+
/** Height: if not set, will be determined by content. */
|
|
39
|
+
height?: string | number;
|
|
40
|
+
/** Width of collapsed header. If not set, width will be determined by the length of the title. */
|
|
41
|
+
collapsedWidth?: string | number;
|
|
42
|
+
/** Width when displayed in a modal dialog. If not set, will fall back on default `width`. */
|
|
43
|
+
dialogWidth?: string | number;
|
|
44
|
+
/** Height when displayed in a modal dialog. If not set, will fall back on default `height`. */
|
|
45
|
+
dialogHeight?: string | number;
|
|
42
46
|
/** Strategy for rendering this DockView. If null, will default to its container's mode. */
|
|
43
47
|
renderMode?: RenderMode;
|
|
44
48
|
/** Strategy for refreshing this DockView. If null, will default to its container's mode. */
|
|
@@ -72,9 +76,11 @@ export class DockViewModel extends HoistModel {
|
|
|
72
76
|
@observable docked: boolean;
|
|
73
77
|
@observable collapsed: boolean;
|
|
74
78
|
content: Content;
|
|
75
|
-
width: number;
|
|
76
|
-
height: number;
|
|
77
|
-
collapsedWidth: number;
|
|
79
|
+
width: string | number;
|
|
80
|
+
height: string | number;
|
|
81
|
+
collapsedWidth: string | number;
|
|
82
|
+
dialogWidth: string | number;
|
|
83
|
+
dialogHeight: string | number;
|
|
78
84
|
allowClose: boolean;
|
|
79
85
|
allowDialog: boolean;
|
|
80
86
|
onClose?: () => Awaitable<boolean | void>;
|
|
@@ -107,6 +113,8 @@ export class DockViewModel extends HoistModel {
|
|
|
107
113
|
width,
|
|
108
114
|
height,
|
|
109
115
|
collapsedWidth,
|
|
116
|
+
dialogWidth,
|
|
117
|
+
dialogHeight,
|
|
110
118
|
refreshMode,
|
|
111
119
|
renderMode,
|
|
112
120
|
docked = true,
|
|
@@ -127,6 +135,8 @@ export class DockViewModel extends HoistModel {
|
|
|
127
135
|
this.width = width;
|
|
128
136
|
this.height = height;
|
|
129
137
|
this.collapsedWidth = collapsedWidth;
|
|
138
|
+
this.dialogWidth = dialogWidth ?? width;
|
|
139
|
+
this.dialogHeight = dialogHeight ?? height;
|
|
130
140
|
|
|
131
141
|
this.docked = docked;
|
|
132
142
|
this.collapsed = collapsed;
|
|
@@ -140,8 +150,8 @@ export class DockViewModel extends HoistModel {
|
|
|
140
150
|
this.refreshContextModel = new ManagedRefreshContextModel(this);
|
|
141
151
|
|
|
142
152
|
this.modalSupportModel = new ModalSupportModel({
|
|
143
|
-
width:
|
|
144
|
-
height:
|
|
153
|
+
width: dialogWidth ?? null,
|
|
154
|
+
height: dialogHeight ?? null,
|
|
145
155
|
defaultModal: !docked,
|
|
146
156
|
canOutsideClickClose: false
|
|
147
157
|
});
|
|
@@ -36,6 +36,8 @@ export const dockView = hoistCmp.factory<DockViewProps>({
|
|
|
36
36
|
width,
|
|
37
37
|
height,
|
|
38
38
|
collapsedWidth,
|
|
39
|
+
dialogWidth,
|
|
40
|
+
dialogHeight,
|
|
39
41
|
collapsed,
|
|
40
42
|
docked,
|
|
41
43
|
isActive,
|
|
@@ -67,8 +69,8 @@ export const dockView = hoistCmp.factory<DockViewProps>({
|
|
|
67
69
|
return modalSupport({
|
|
68
70
|
model: model.modalSupportModel,
|
|
69
71
|
item: vbox({
|
|
70
|
-
width: collapsed ? collapsedWidth : width,
|
|
71
|
-
height:
|
|
72
|
+
width: collapsed ? collapsedWidth : docked ? width : dialogWidth,
|
|
73
|
+
height: collapsed ? undefined : docked ? height : dialogHeight,
|
|
72
74
|
className: classNames(className, `xh-dock-view--${suffix}`),
|
|
73
75
|
items: [header, body]
|
|
74
76
|
})
|
|
@@ -15,7 +15,7 @@ import {fmtDate, fmtDateTime, fmtJson, fmtNumber} from '@xh/hoist/format';
|
|
|
15
15
|
import {Icon} from '@xh/hoist/icon';
|
|
16
16
|
import {tooltip} from '@xh/hoist/kit/blueprint';
|
|
17
17
|
import {isLocalDate} from '@xh/hoist/utils/datetime';
|
|
18
|
-
import {errorIf, getTestId, TEST_ID, throwIf, withDefault} from '@xh/hoist/utils/js';
|
|
18
|
+
import {errorIf, getTestId, logWarn, TEST_ID, throwIf, withDefault} from '@xh/hoist/utils/js';
|
|
19
19
|
import {getLayoutProps, getReactElementName, useOnMount, useOnUnmount} from '@xh/hoist/utils/react';
|
|
20
20
|
import classNames from 'classnames';
|
|
21
21
|
import {isBoolean, isDate, isEmpty, isFinite, isNil, isUndefined, kebabCase} from 'lodash';
|
|
@@ -107,7 +107,7 @@ export const [FormField, formField] = hoistCmp.withFactory<FormFieldProps>({
|
|
|
107
107
|
model = model ?? (formModel && field ? formModel.fields[field] : null);
|
|
108
108
|
|
|
109
109
|
if (!model) {
|
|
110
|
-
|
|
110
|
+
logWarn(`Unable to bind FormField to field "${field}" on backing FormModel`, FormField);
|
|
111
111
|
}
|
|
112
112
|
|
|
113
113
|
// Model related props
|
|
@@ -12,6 +12,7 @@ import {useImperativeHandle} from 'react';
|
|
|
12
12
|
import {EditorProps} from './EditorProps';
|
|
13
13
|
import './Editors.scss';
|
|
14
14
|
import {useInlineEditorModel} from './impl/InlineEditorModel';
|
|
15
|
+
import {logWarn} from '@xh/hoist/utils/js';
|
|
15
16
|
|
|
16
17
|
export interface BooleanEditorProps extends EditorProps<CheckboxProps> {
|
|
17
18
|
/**
|
|
@@ -35,7 +36,10 @@ export const [BooleanEditor, booleanEditor] = hoistCmp.withFactory<BooleanEditor
|
|
|
35
36
|
quickToggle = quickToggle ?? !fullRowEditing;
|
|
36
37
|
|
|
37
38
|
if (quickToggle && fullRowEditing) {
|
|
38
|
-
|
|
39
|
+
logWarn(
|
|
40
|
+
"'quickToggle' prop ignored for GridModel with full row editing.",
|
|
41
|
+
BooleanEditor
|
|
42
|
+
);
|
|
39
43
|
quickToggle = false;
|
|
40
44
|
}
|
|
41
45
|
|
|
@@ -91,7 +91,7 @@ function computeStyleInAgGrid(
|
|
|
91
91
|
|
|
92
92
|
const inputEl = data.instance.reference,
|
|
93
93
|
leftContainer = inputEl.closest('.ag-pinned-left-cols-container'),
|
|
94
|
-
centerContainer = inputEl.closest('.ag-center-cols-
|
|
94
|
+
centerContainer = inputEl.closest('.ag-center-cols-container'),
|
|
95
95
|
rightContainer = inputEl.closest('.ag-pinned-right-cols-container'),
|
|
96
96
|
rowContainer = centerContainer || leftContainer || rightContainer;
|
|
97
97
|
|
|
@@ -143,7 +143,7 @@ function computeStyleInAgGrid(
|
|
|
143
143
|
|
|
144
144
|
// Solve y axis (top). Default position is underneath cell
|
|
145
145
|
// Flips to above if cell is near bottom of grid.
|
|
146
|
-
// If
|
|
146
|
+
// If popper height is greater than grid height, the popper stays in the default position.
|
|
147
147
|
const flipToAbove =
|
|
148
148
|
popperHeight < pcHeight && inputElBottom - scrollTop + popperHeight > pcHeight,
|
|
149
149
|
trTop = flipToAbove ? inputElTop - popperHeight : inputElBottom;
|
|
@@ -319,9 +319,7 @@ class DateInputModel extends HoistInputModel {
|
|
|
319
319
|
if (date) {
|
|
320
320
|
date = this.applyPrecision(date);
|
|
321
321
|
} else {
|
|
322
|
-
|
|
323
|
-
'DateInput value exceeded max/minDate bounds on change - reset to null.'
|
|
324
|
-
);
|
|
322
|
+
this.logDebug('Value exceeded max/minDate bounds on change - reset to null.');
|
|
325
323
|
}
|
|
326
324
|
}
|
|
327
325
|
this.noteValueChange(date);
|
|
@@ -23,6 +23,7 @@ import {toolbar} from '@xh/hoist/desktop/cmp/toolbar';
|
|
|
23
23
|
import {useContextMenu, useHotkeys} from '@xh/hoist/desktop/hooks';
|
|
24
24
|
import '@xh/hoist/desktop/register';
|
|
25
25
|
import {HotkeyConfig} from '@xh/hoist/kit/blueprint';
|
|
26
|
+
import {logWarn} from '@xh/hoist/utils/js';
|
|
26
27
|
import {splitLayoutProps} from '@xh/hoist/utils/react';
|
|
27
28
|
import {castArray, omitBy} from 'lodash';
|
|
28
29
|
import {Children, isValidElement, ReactElement, ReactNode, useLayoutEffect, useRef} from 'react';
|
|
@@ -256,8 +257,9 @@ function parseLoadDecorator(prop: any, name: string, contextModel: HoistModel) {
|
|
|
256
257
|
if (prop === 'onLoad') {
|
|
257
258
|
const loadModel = contextModel?.loadModel;
|
|
258
259
|
if (!loadModel) {
|
|
259
|
-
|
|
260
|
-
`Cannot use 'onLoad' for '${name}' - the linked context model must enable LoadSupport to support this feature
|
|
260
|
+
logWarn(
|
|
261
|
+
`Cannot use 'onLoad' for '${name}' - the linked context model must enable LoadSupport to support this feature.`,
|
|
262
|
+
Panel
|
|
261
263
|
);
|
|
262
264
|
return null;
|
|
263
265
|
}
|
|
@@ -213,7 +213,7 @@ export class PanelModel extends HoistModel {
|
|
|
213
213
|
: defaultSize;
|
|
214
214
|
|
|
215
215
|
if ((collapsible || resizable) && (isNil(defaultSize) || isNil(side))) {
|
|
216
|
-
|
|
216
|
+
this.logError(
|
|
217
217
|
"Must specify 'defaultSize' and 'side' for a collapsible or resizable PanelModel. Panel sizing disabled."
|
|
218
218
|
);
|
|
219
219
|
collapsible = false;
|
|
@@ -221,12 +221,12 @@ export class PanelModel extends HoistModel {
|
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
if (!isNil(maxSize) && maxSize < minSize) {
|
|
224
|
-
|
|
224
|
+
this.logError("'maxSize' must be greater than 'minSize'. No 'maxSize' will be set.");
|
|
225
225
|
maxSize = null;
|
|
226
226
|
}
|
|
227
227
|
|
|
228
228
|
if (resizable && !resizeWhileDragging && !showSplitter) {
|
|
229
|
-
|
|
229
|
+
this.logError(
|
|
230
230
|
"Must not set 'showSplitter = false' for a resizable PanelModel unless 'resizeWhileDragging` is enabled. Panel sizing disabled."
|
|
231
231
|
);
|
|
232
232
|
resizable = false;
|
|
@@ -277,7 +277,7 @@ export class PanelModel extends HoistModel {
|
|
|
277
277
|
this.provider = PersistenceProvider.create({path: 'panel', ...persistWith});
|
|
278
278
|
state = this.provider.read() ?? this.legacyState();
|
|
279
279
|
} catch (e) {
|
|
280
|
-
|
|
280
|
+
this.logError(e);
|
|
281
281
|
XH.safeDestroy(this.provider);
|
|
282
282
|
this.provider = null;
|
|
283
283
|
}
|
|
@@ -408,7 +408,7 @@ export class PanelModel extends HoistModel {
|
|
|
408
408
|
return data;
|
|
409
409
|
}
|
|
410
410
|
} catch (e) {
|
|
411
|
-
|
|
411
|
+
this.logError('Failed reading legacy state', e);
|
|
412
412
|
}
|
|
413
413
|
}
|
|
414
414
|
return null;
|
|
@@ -22,7 +22,7 @@ import {mask} from '@xh/hoist/desktop/cmp/mask';
|
|
|
22
22
|
import '@xh/hoist/desktop/register';
|
|
23
23
|
import {Highcharts} from '@xh/hoist/kit/highcharts';
|
|
24
24
|
import {wait} from '@xh/hoist/promise';
|
|
25
|
-
import {logWithDebug} from '@xh/hoist/utils/js';
|
|
25
|
+
import {logError, logWithDebug} from '@xh/hoist/utils/js';
|
|
26
26
|
import {
|
|
27
27
|
createObservableRef,
|
|
28
28
|
getLayoutProps,
|
|
@@ -53,9 +53,10 @@ export const [TreeMap, treeMap] = hoistCmp.withFactory<TreeMapProps>({
|
|
|
53
53
|
|
|
54
54
|
render({model, className, testId, ...props}, ref) {
|
|
55
55
|
if (!Highcharts) {
|
|
56
|
-
|
|
56
|
+
logError(
|
|
57
57
|
'Highcharts has not been imported in to this application. Please import and ' +
|
|
58
|
-
'register in Bootstrap.js. See Toolbox for an example.'
|
|
58
|
+
'register in Bootstrap.js. See Toolbox for an example.',
|
|
59
|
+
TreeMap
|
|
59
60
|
);
|
|
60
61
|
return 'Highcharts not available';
|
|
61
62
|
}
|
|
@@ -369,8 +369,8 @@ export class InstancesModel extends HoistModel {
|
|
|
369
369
|
const displayGroup = inst.isHoistService
|
|
370
370
|
? 'Services'
|
|
371
371
|
: inst.isStore
|
|
372
|
-
|
|
373
|
-
|
|
372
|
+
? 'Stores'
|
|
373
|
+
: 'Models';
|
|
374
374
|
data.push({...inst, displayGroup});
|
|
375
375
|
});
|
|
376
376
|
|
|
@@ -464,8 +464,8 @@ export class InstancesModel extends HoistModel {
|
|
|
464
464
|
isGetter && !isLoadedGetter
|
|
465
465
|
? 'get(?)'
|
|
466
466
|
: isProxy
|
|
467
|
-
|
|
468
|
-
|
|
467
|
+
? 'Proxy'
|
|
468
|
+
: v?.constructor?.name ?? typeof v;
|
|
469
469
|
|
|
470
470
|
return {
|
|
471
471
|
id: `${xhId}-${property}${fromWatchlistItem ? '-wl' : ''}`,
|
|
@@ -479,8 +479,8 @@ export class InstancesModel extends HoistModel {
|
|
|
479
479
|
isHoistModel || isHoistService || isStore
|
|
480
480
|
? v.xhId
|
|
481
481
|
: isProxy
|
|
482
|
-
|
|
483
|
-
|
|
482
|
+
? '[cannot render]'
|
|
483
|
+
: v,
|
|
484
484
|
valueType,
|
|
485
485
|
isOwnProperty,
|
|
486
486
|
isObservable,
|
|
@@ -10,7 +10,7 @@ import {hoistCmp, useContextModel} from '@xh/hoist/core';
|
|
|
10
10
|
import {Icon} from '@xh/hoist/icon';
|
|
11
11
|
import {button, ButtonProps} from '@xh/hoist/mobile/cmp/button';
|
|
12
12
|
import '@xh/hoist/mobile/register';
|
|
13
|
-
import {withDefault} from '@xh/hoist/utils/js';
|
|
13
|
+
import {logError, withDefault} from '@xh/hoist/utils/js';
|
|
14
14
|
|
|
15
15
|
export interface ColAutosizeButtonProps extends ButtonProps {
|
|
16
16
|
/** GridModel of the grid for which this button should autosize columns. */
|
|
@@ -31,8 +31,9 @@ export const [ColAutosizeButton, colAutosizeButton] = hoistCmp.withFactory<ColAu
|
|
|
31
31
|
gridModel = withDefault(gridModel, useContextModel(GridModel));
|
|
32
32
|
|
|
33
33
|
if (!gridModel?.autosizeEnabled) {
|
|
34
|
-
|
|
35
|
-
"No GridModel available with autosize enabled. Provide via a 'gridModel' prop, or context."
|
|
34
|
+
logError(
|
|
35
|
+
"No GridModel available with autosize enabled. Provide via a 'gridModel' prop, or context.",
|
|
36
|
+
ColAutosizeButton
|
|
36
37
|
);
|
|
37
38
|
return button({icon, disabled: true, ...props});
|
|
38
39
|
}
|
|
@@ -9,7 +9,7 @@ import {hoistCmp, useContextModel} from '@xh/hoist/core';
|
|
|
9
9
|
import {Icon} from '@xh/hoist/icon';
|
|
10
10
|
import {button, ButtonProps} from '@xh/hoist/mobile/cmp/button';
|
|
11
11
|
import '@xh/hoist/mobile/register';
|
|
12
|
-
import {withDefault} from '@xh/hoist/utils/js';
|
|
12
|
+
import {logError, withDefault} from '@xh/hoist/utils/js';
|
|
13
13
|
|
|
14
14
|
export interface ColChooserButtonProps extends ButtonProps {
|
|
15
15
|
/** GridModel of the grid for which this button should show a chooser. */
|
|
@@ -30,8 +30,9 @@ export const [ColChooserButton, colChooserButton] = hoistCmp.withFactory<ColChoo
|
|
|
30
30
|
gridModel = withDefault(gridModel, useContextModel(GridModel));
|
|
31
31
|
|
|
32
32
|
if (!gridModel) {
|
|
33
|
-
|
|
34
|
-
"No GridModel available
|
|
33
|
+
logError(
|
|
34
|
+
"No GridModel available. Provide via a 'gridModel' prop, or context.",
|
|
35
|
+
ColChooserButton
|
|
35
36
|
);
|
|
36
37
|
return button({icon, disabled: true, ...props});
|
|
37
38
|
}
|
|
@@ -9,7 +9,7 @@ import {hoistCmp, useContextModel} from '@xh/hoist/core';
|
|
|
9
9
|
import {Icon} from '@xh/hoist/icon';
|
|
10
10
|
import {button, ButtonProps} from '@xh/hoist/mobile/cmp/button';
|
|
11
11
|
import '@xh/hoist/mobile/register';
|
|
12
|
-
import {withDefault} from '@xh/hoist/utils/js';
|
|
12
|
+
import {logError, withDefault} from '@xh/hoist/utils/js';
|
|
13
13
|
import {isEmpty} from 'lodash';
|
|
14
14
|
|
|
15
15
|
export interface ExpandCollapseButtonProps extends ButtonProps {
|
|
@@ -28,8 +28,9 @@ export const [ExpandCollapseButton, expandCollapseButton] =
|
|
|
28
28
|
gridModel = withDefault(gridModel, useContextModel(GridModel));
|
|
29
29
|
|
|
30
30
|
if (!gridModel) {
|
|
31
|
-
|
|
32
|
-
"No GridModel available. Provide via a 'gridModel' prop, or context."
|
|
31
|
+
logError(
|
|
32
|
+
"No GridModel available. Provide via a 'gridModel' prop, or context.",
|
|
33
|
+
ExpandCollapseButton
|
|
33
34
|
);
|
|
34
35
|
return button({icon: Icon.expand(), disabled: true, ...props});
|
|
35
36
|
}
|
|
@@ -8,7 +8,7 @@ import {hoistCmp, useContextModel} from '@xh/hoist/core';
|
|
|
8
8
|
import {ZoneGridModel} from '../../../cmp/zoneGrid';
|
|
9
9
|
import {button, ButtonProps} from '@xh/hoist/mobile/cmp/button';
|
|
10
10
|
import {Icon} from '@xh/hoist/icon';
|
|
11
|
-
import {withDefault} from '@xh/hoist/utils/js';
|
|
11
|
+
import {logError, withDefault} from '@xh/hoist/utils/js';
|
|
12
12
|
import '@xh/hoist/mobile/register';
|
|
13
13
|
|
|
14
14
|
export interface ZoneMapperButtonProps extends ButtonProps {
|
|
@@ -28,8 +28,9 @@ export const [ZoneMapperButton, zoneMapperButton] = hoistCmp.withFactory<ZoneMap
|
|
|
28
28
|
zoneGridModel = withDefault(zoneGridModel, useContextModel(ZoneGridModel));
|
|
29
29
|
|
|
30
30
|
if (!zoneGridModel) {
|
|
31
|
-
|
|
32
|
-
"No ZoneGridModel available
|
|
31
|
+
logError(
|
|
32
|
+
"No ZoneGridModel available. Provide via a 'zoneGridModel' prop, or context.",
|
|
33
|
+
ZoneMapperButton
|
|
33
34
|
);
|
|
34
35
|
return button({icon, disabled: true, ...props});
|
|
35
36
|
}
|
|
@@ -161,7 +161,7 @@ class DateInputModel extends HoistInputModel {
|
|
|
161
161
|
if (date && this.isOutsideRange(date)) {
|
|
162
162
|
// Dates outside of min/max constraints are reset to null.
|
|
163
163
|
date = null;
|
|
164
|
-
|
|
164
|
+
this.logDebug('Value exceeded max/minDate bounds on change - reset to null.');
|
|
165
165
|
}
|
|
166
166
|
this.noteValueChange(date ? date.toDate() : null);
|
|
167
167
|
};
|
|
@@ -272,8 +272,8 @@ class SelectInputModel extends HoistInputModel {
|
|
|
272
272
|
? reactAsyncCreatableSelect
|
|
273
273
|
: reactAsyncSelect
|
|
274
274
|
: creatableMode
|
|
275
|
-
|
|
276
|
-
|
|
275
|
+
? reactCreatableSelect
|
|
276
|
+
: reactSelect;
|
|
277
277
|
}
|
|
278
278
|
|
|
279
279
|
@action
|
|
@@ -468,7 +468,7 @@ class SelectInputModel extends HoistInputModel {
|
|
|
468
468
|
return matchOpts;
|
|
469
469
|
})
|
|
470
470
|
.catch(e => {
|
|
471
|
-
|
|
471
|
+
this.logError(e);
|
|
472
472
|
throw e;
|
|
473
473
|
});
|
|
474
474
|
};
|
|
@@ -24,6 +24,7 @@ import {omitBy} from 'lodash';
|
|
|
24
24
|
import {isValidElement, ReactNode, ReactElement} from 'react';
|
|
25
25
|
import {panelHeader} from './impl/PanelHeader';
|
|
26
26
|
import './Panel.scss';
|
|
27
|
+
import {logWarn} from '@xh/hoist/utils/js';
|
|
27
28
|
|
|
28
29
|
export interface PanelProps extends HoistProps, Omit<BoxProps, 'title'> {
|
|
29
30
|
/** A toolbar to be docked at the bottom of the panel. */
|
|
@@ -141,8 +142,9 @@ function parseLoadDecorator(prop, name, contextModel) {
|
|
|
141
142
|
if (prop === 'onLoad') {
|
|
142
143
|
const loadModel = contextModel?.loadModel;
|
|
143
144
|
if (!loadModel) {
|
|
144
|
-
|
|
145
|
-
`Cannot use 'onLoad' for '${name}'. Context model does not implement loading
|
|
145
|
+
logWarn(
|
|
146
|
+
`Cannot use 'onLoad' for '${name}'. Context model does not implement loading.`,
|
|
147
|
+
Panel
|
|
146
148
|
);
|
|
147
149
|
return null;
|
|
148
150
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "59.
|
|
3
|
+
"version": "59.5.1",
|
|
4
4
|
"description": "Hoist add-on for building and deploying React Applications.",
|
|
5
5
|
"repository": "github:xh/hoist-react",
|
|
6
6
|
"homepage": "https://xh.io",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"react-beautiful-dnd": "~13.1.0",
|
|
66
66
|
"react-dates": "~21.8.0",
|
|
67
67
|
"react-dropzone": "~10.2.2",
|
|
68
|
-
"react-grid-layout": "
|
|
68
|
+
"react-grid-layout": "1.4.3",
|
|
69
69
|
"react-markdown": "^8.0.7",
|
|
70
70
|
"react-onsenui": "~1.13.2",
|
|
71
71
|
"react-popper": "~2.3.0",
|
|
@@ -69,7 +69,7 @@ export class AutoRefreshService extends HoistService {
|
|
|
69
69
|
pendingLoad = lastRequested && lastRequested > lastCompleted;
|
|
70
70
|
|
|
71
71
|
if (!pendingLoad && olderThan(last, this.interval * SECONDS)) {
|
|
72
|
-
this.logDebug('Triggering application auto-refresh
|
|
72
|
+
this.logDebug('Triggering application auto-refresh');
|
|
73
73
|
await ctx.autoRefreshAsync();
|
|
74
74
|
}
|
|
75
75
|
}
|
package/svc/ChangelogService.ts
CHANGED
|
@@ -96,12 +96,12 @@ export class ChangelogService extends HoistService {
|
|
|
96
96
|
const {latestAvailableVersion, LAST_READ_PREF_KEY} = this;
|
|
97
97
|
|
|
98
98
|
if (includes(latestAvailableVersion, 'SNAPSHOT')) {
|
|
99
|
-
|
|
99
|
+
this.logWarn('Unable to mark changelog as read when latest version is SNAPSHOT.');
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
if (!latestAvailableVersion || !XH.prefService.hasKey(LAST_READ_PREF_KEY)) {
|
|
104
|
-
|
|
104
|
+
this.logWarn(
|
|
105
105
|
'Unable to mark changelog as read - latest version or required pref not found.'
|
|
106
106
|
);
|
|
107
107
|
return;
|
|
@@ -147,7 +147,7 @@ export class ChangelogService extends HoistService {
|
|
|
147
147
|
|
|
148
148
|
return versions;
|
|
149
149
|
} catch (e) {
|
|
150
|
-
|
|
150
|
+
this.logError(
|
|
151
151
|
'Error parsing changelog JSON into versions - changelog will not be available',
|
|
152
152
|
e
|
|
153
153
|
);
|
|
@@ -136,7 +136,7 @@ export class EnvironmentService extends HoistService {
|
|
|
136
136
|
// prompted to refresh.
|
|
137
137
|
const clientVersion = this.get('clientVersion');
|
|
138
138
|
if (appVersion !== clientVersion) {
|
|
139
|
-
|
|
139
|
+
this.logWarn(
|
|
140
140
|
`Version mismatch detected between client and server - ${clientVersion} vs ${appVersion}`
|
|
141
141
|
);
|
|
142
142
|
}
|
package/svc/GridExportService.ts
CHANGED
|
@@ -327,13 +327,8 @@ export class GridExportService extends HoistService {
|
|
|
327
327
|
: it.exportName;
|
|
328
328
|
|
|
329
329
|
if (!isString(ret)) {
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
it.colId +
|
|
333
|
-
' with an invalid "exportName", ' +
|
|
334
|
-
'probably caused by setting "headerName" to a React element. Please specify an ' +
|
|
335
|
-
'appropriate "exportName". Defaulting to ' +
|
|
336
|
-
it.colId
|
|
330
|
+
this.logWarn(
|
|
331
|
+
`Tried to export column '${it.colId}' with an invalid "exportName", probably caused by setting "headerName" to a React element. Please specify an appropriate "exportName". Defaulting to '${it.colId}'`
|
|
337
332
|
);
|
|
338
333
|
ret = it.colId;
|
|
339
334
|
}
|
|
@@ -345,7 +340,7 @@ export class GridExportService extends HoistService {
|
|
|
345
340
|
const headerCounts = countBy(headers.map(it => it.toLowerCase())),
|
|
346
341
|
dupeHeaders = keys(pickBy(headerCounts, it => it > 1));
|
|
347
342
|
if (type === 'excelTable' && !isEmpty(dupeHeaders)) {
|
|
348
|
-
|
|
343
|
+
this.logWarn(
|
|
349
344
|
'Excel tables require unique headers on each column. Consider using the "exportName" property to ensure unique headers. Duplicate headers: ',
|
|
350
345
|
dupeHeaders
|
|
351
346
|
);
|
package/svc/IdentityService.ts
CHANGED
|
@@ -62,7 +62,7 @@ export class IdentityService extends HoistService {
|
|
|
62
62
|
try {
|
|
63
63
|
await XH.appModel?.logoutAsync();
|
|
64
64
|
} catch (e) {
|
|
65
|
-
|
|
65
|
+
this.logError('Error calling XH.appModel.logoutAsync()', e);
|
|
66
66
|
}
|
|
67
67
|
return XH.fetchJson({url: 'xh/logout'})
|
|
68
68
|
.then(() => XH.reloadApp())
|
package/svc/TrackService.ts
CHANGED
|
@@ -45,19 +45,13 @@ export class TrackService extends HoistService {
|
|
|
45
45
|
|
|
46
46
|
// Short-circuit if disabled...
|
|
47
47
|
if (!this.enabled) {
|
|
48
|
-
|
|
49
|
-
'[TrackService] | Activity tracking disabled - activity will not be tracked.',
|
|
50
|
-
options
|
|
51
|
-
);
|
|
48
|
+
this.logDebug('Activity tracking disabled - activity will not be tracked.', options);
|
|
52
49
|
return;
|
|
53
50
|
}
|
|
54
51
|
|
|
55
52
|
// ...or invalid request (with warning for developer)...
|
|
56
53
|
if (!options.message) {
|
|
57
|
-
|
|
58
|
-
'[TrackService] | Required message not provided - activity will not be tracked.',
|
|
59
|
-
options
|
|
60
|
-
);
|
|
54
|
+
this.logWarn('Required message not provided - activity will not be tracked.', options);
|
|
61
55
|
return;
|
|
62
56
|
}
|
|
63
57
|
|
|
@@ -113,7 +107,7 @@ export class TrackService extends HoistService {
|
|
|
113
107
|
|
|
114
108
|
await XH.fetchJson({url: 'xh/track', params});
|
|
115
109
|
} catch (e) {
|
|
116
|
-
|
|
110
|
+
this.logError('Failed to persist track log', options, e);
|
|
117
111
|
}
|
|
118
112
|
}
|
|
119
113
|
}
|
package/utils/async/Timer.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import {XH} from '@xh/hoist/core';
|
|
8
8
|
import {wait} from '@xh/hoist/promise';
|
|
9
9
|
import {MILLISECONDS, MINUTES, olderThan} from '@xh/hoist/utils/datetime';
|
|
10
|
-
import {logWarn, throwIf} from '@xh/hoist/utils/js';
|
|
10
|
+
import {logError, logWarn, throwIf} from '@xh/hoist/utils/js';
|
|
11
11
|
import {isBoolean, isFinite, isFunction, isNil, isString, pull} from 'lodash';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -122,7 +122,7 @@ export class Timer {
|
|
|
122
122
|
try {
|
|
123
123
|
await (this.internalRunFn() as any).timeout(this.timeoutMs);
|
|
124
124
|
} catch (e) {
|
|
125
|
-
|
|
125
|
+
logError(['Error executing timer', e], this);
|
|
126
126
|
}
|
|
127
127
|
this.isRunning = false;
|
|
128
128
|
this.lastRun = new Date();
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
* Copyright © 2023 Extremely Heavy Industries Inc.
|
|
6
6
|
*/
|
|
7
7
|
import {XH} from '@xh/hoist/core';
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
8
|
+
import {computeOnce, throwIf} from '@xh/hoist/utils/js';
|
|
9
|
+
import {isNil, isString} from 'lodash';
|
|
10
10
|
import moment, {Moment, MomentInput} from 'moment';
|
|
11
11
|
|
|
12
12
|
/**
|
|
@@ -25,9 +25,9 @@ export class LocalDate {
|
|
|
25
25
|
private static _instances = new Map();
|
|
26
26
|
static VALID_UNITS = ['year', 'quarter', 'month', 'week', 'day', 'date'];
|
|
27
27
|
|
|
28
|
-
private _isoString;
|
|
29
|
-
private _moment;
|
|
30
|
-
private _date;
|
|
28
|
+
private _isoString: string;
|
|
29
|
+
private _moment: Moment;
|
|
30
|
+
private _date: Date;
|
|
31
31
|
|
|
32
32
|
//------------------------
|
|
33
33
|
// Factories
|
|
@@ -99,8 +99,8 @@ export class LocalDate {
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
/** Is the input value a local Date? */
|
|
102
|
-
static isLocalDate(
|
|
103
|
-
return
|
|
102
|
+
static isLocalDate(val: any): boolean {
|
|
103
|
+
return !!val?.isLocalDate;
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
//--------------------
|
|
@@ -168,15 +168,15 @@ export class LocalDate {
|
|
|
168
168
|
//----------------
|
|
169
169
|
// Core overrides.
|
|
170
170
|
//----------------
|
|
171
|
-
toString() {
|
|
171
|
+
toString(): string {
|
|
172
172
|
return this._isoString;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
toJSON() {
|
|
175
|
+
toJSON(): string {
|
|
176
176
|
return this._isoString;
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
valueOf() {
|
|
179
|
+
valueOf(): string {
|
|
180
180
|
return this._isoString;
|
|
181
181
|
}
|
|
182
182
|
|
|
@@ -281,7 +281,7 @@ export class LocalDate {
|
|
|
281
281
|
return this.isWeekday ? this : this.previousWeekday();
|
|
282
282
|
}
|
|
283
283
|
|
|
284
|
-
diff(other, unit = 'days'): number {
|
|
284
|
+
diff(other: LocalDate, unit: moment.unitOfTime.Diff = 'days'): number {
|
|
285
285
|
this.ensureUnitValid(unit);
|
|
286
286
|
return this._moment.diff(other._moment, unit);
|
|
287
287
|
}
|
|
@@ -290,7 +290,7 @@ export class LocalDate {
|
|
|
290
290
|
// Implementation
|
|
291
291
|
//-------------------
|
|
292
292
|
/** @internal - use one of the static factory methods instead. */
|
|
293
|
-
private constructor(s) {
|
|
293
|
+
private constructor(s: string) {
|
|
294
294
|
const m = moment(s, 'YYYY-MM-DD', true);
|
|
295
295
|
throwIf(
|
|
296
296
|
!m.isValid(),
|
|
@@ -315,6 +315,6 @@ export class LocalDate {
|
|
|
315
315
|
* Is the input value a local Date?
|
|
316
316
|
* Convenience alias for LocalDate.isLocalDate()
|
|
317
317
|
*/
|
|
318
|
-
export function isLocalDate(val): val is LocalDate {
|
|
318
|
+
export function isLocalDate(val: any): val is LocalDate {
|
|
319
319
|
return !!val?.isLocalDate;
|
|
320
320
|
}
|
package/utils/js/Decorators.ts
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import {XH} from '@xh/hoist/core';
|
|
8
8
|
import {debounce, isFunction} from 'lodash';
|
|
9
|
-
import {
|
|
10
|
-
import {withDebug} from './LogUtils';
|
|
9
|
+
import {getOrCreate, throwIf, warnIf} from './LangUtils';
|
|
10
|
+
import {withDebug, withInfo} from './LogUtils';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Decorates a class method so that it is debounced by the specified duration.
|
|
@@ -53,7 +53,22 @@ export function computeOnce(target, key, descriptor) {
|
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
|
-
* Modify a method so that its execution is tracked and timed with a
|
|
56
|
+
* Modify a method so that its execution is tracked and timed with a log message on the console.
|
|
57
|
+
* @see withInfo
|
|
58
|
+
*/
|
|
59
|
+
export function logWithInfo(target, key, descriptor) {
|
|
60
|
+
const {value} = descriptor;
|
|
61
|
+
throwIf(!isFunction(value), '@logWithInfo must be applied to a class method.');
|
|
62
|
+
return {
|
|
63
|
+
...descriptor,
|
|
64
|
+
value: function (...args) {
|
|
65
|
+
return withInfo(key, () => value.apply(this, args), this);
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Modify a method so that its execution is tracked and timed with a debug message on the console.
|
|
57
72
|
* @see withDebug
|
|
58
73
|
*/
|
|
59
74
|
export function logWithDebug(target, key, descriptor) {
|