@xh/hoist 73.0.0-SNAPSHOT.1746476925456 → 73.0.0-SNAPSHOT.1746482507483

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +15 -3
  2. package/admin/columns/Rest.ts +0 -1
  3. package/admin/columns/Tracking.ts +6 -9
  4. package/admin/tabs/activity/tracking/ActivityTrackingModel.ts +14 -47
  5. package/admin/tabs/activity/tracking/ActivityTrackingPanel.ts +1 -1
  6. package/admin/tabs/activity/tracking/detail/ActivityDetailModel.ts +35 -51
  7. package/admin/tabs/activity/tracking/detail/ActivityDetailView.ts +5 -7
  8. package/admin/tabs/client/clients/ClientsModel.ts +2 -7
  9. package/admin/tabs/client/clients/ClientsPanel.ts +2 -3
  10. package/build/types/admin/tabs/activity/tracking/ActivityTrackingModel.d.ts +2 -7
  11. package/build/types/admin/tabs/activity/tracking/detail/ActivityDetailModel.d.ts +6 -18
  12. package/build/types/cmp/grid/Types.d.ts +4 -1
  13. package/build/types/desktop/cmp/grid/impl/filter/headerfilter/values/ValuesTabModel.d.ts +2 -0
  14. package/build/types/desktop/cmp/input/DateInput.d.ts +3 -2
  15. package/build/types/desktop/cmp/input/NumberInput.d.ts +3 -2
  16. package/build/types/desktop/cmp/input/TextInput.d.ts +3 -2
  17. package/build/types/mobile/cmp/input/DateInput.d.ts +3 -2
  18. package/build/types/mobile/cmp/input/NumberInput.d.ts +3 -2
  19. package/build/types/mobile/cmp/input/SearchInput.d.ts +3 -2
  20. package/build/types/mobile/cmp/input/TextInput.d.ts +3 -2
  21. package/cmp/grid/Types.ts +4 -1
  22. package/cmp/grid/filter/GridFilterModel.ts +1 -1
  23. package/desktop/cmp/grid/impl/filter/headerfilter/values/ValuesTab.scss +13 -0
  24. package/desktop/cmp/grid/impl/filter/headerfilter/values/ValuesTab.ts +29 -2
  25. package/desktop/cmp/grid/impl/filter/headerfilter/values/ValuesTabModel.ts +37 -15
  26. package/desktop/cmp/input/DateInput.ts +3 -2
  27. package/desktop/cmp/input/NumberInput.ts +3 -2
  28. package/desktop/cmp/input/TextInput.ts +3 -2
  29. package/mobile/cmp/input/DateInput.ts +3 -2
  30. package/mobile/cmp/input/NumberInput.ts +3 -2
  31. package/mobile/cmp/input/SearchInput.ts +3 -2
  32. package/mobile/cmp/input/TextInput.ts +3 -2
  33. package/package.json +1 -1
  34. package/tsconfig.tsbuildinfo +1 -1
  35. package/admin/tabs/client/clients/activity/ClientDetail.scss +0 -24
  36. package/admin/tabs/client/clients/activity/ClientDetailModel.ts +0 -83
  37. package/admin/tabs/client/clients/activity/ClientDetailPanel.ts +0 -63
  38. package/build/types/admin/tabs/client/clients/activity/ClientDetailModel.d.ts +0 -21
  39. package/build/types/admin/tabs/client/clients/activity/ClientDetailPanel.d.ts +0 -3
package/CHANGELOG.md CHANGED
@@ -4,8 +4,14 @@
4
4
 
5
5
  ### 💥 Breaking Changes (upgrade difficulty: 🟢 TRIVIAL - minor upgrade to Hoist Core)
6
6
 
7
- Requires `hoist-core >= 30.0` with new APIs to support the consolidated Admin Console "Clients" tab
8
- and new properties on `TrackLog`.
7
+ * Requires `hoist-core >= 30.0` with new APIs to support the consolidated Admin Console "Clients"
8
+ tab and new properties on `TrackLog`.
9
+ * Apps with a custom `AppModel` for their admin app that extends `@xh/hoist/admin/AppModel` must
10
+ ensure they call `super.initAsync()` within their override of that lifecycle method, if
11
+ applicable. This did not previously have any effect, but is required now for the superclass to
12
+ initialize a new `ViewManagerModel`.
13
+ * For clarity, [here is where Toolbox makes that call](https://github.com/xh/toolbox/blob/f15a8018ce36c2ae998b45724b48a16320b88e49/client-app/src/admin/AppModel.ts#L12).
14
+
9
15
 
10
16
  ### 🎁 New Features
11
17
 
@@ -32,6 +38,8 @@ and new properties on `TrackLog`.
32
38
 
33
39
  * Corrected `GridGroupSortFn` param types.
34
40
  * Corrected `StoreCountLabelProps` interface.
41
+ * Corrected `textAlign` type in `DateInputProps`, `NumberInputProps` `SearchInputProps` and
42
+ `TextInputProps`.
35
43
 
36
44
  ### ⚙️ Technical
37
45
 
@@ -41,7 +49,7 @@ and new properties on `TrackLog`.
41
49
  * The two versions *should* be the same, but in cases where a browser "restores" a tab and
42
50
  re-inits an app without reloading the code itself, the upgrade check would miss the fact that
43
51
  the client remained on an older version.
44
- * Note that a misconfigured build - where the client build version is not set to the same value
52
+ * ⚠️ NOTE that a misconfigured build - where the client version is not set to the same value
45
53
  as the server - would result in a false positive for an upgrade. The two should always match.
46
54
  * Calls to `Promise.track()` that are rejected with an exception will be tracked with new
47
55
  severity level of `TrackSeverity.ERROR`
@@ -119,6 +127,10 @@ and new properties on `TrackLog`.
119
127
 
120
128
  ### 🎁 New Features
121
129
 
130
+ * Improvements to Grid columns `HeaderFilter` component:
131
+ * `GridFilterModel` `commitOnChage` now set to `false` by default
132
+ * Addition of ability to append terms to active filter **only** when `commitOnChage:false`
133
+ * Column header filtering functionality now similar to Excel on Windows
122
134
  * Introduced a new "JSON Search" feature to the Hoist Admin Console, accessible from the Config,
123
135
  User Preference, and JSON Blob tabs. Supports searching JSON values stored within these objects
124
136
  to filter and match data using JSON Path expressions.
@@ -17,7 +17,6 @@ export const dateCreatedNoYear: ColumnSpec = {
17
17
  ...Col.dateTimeSec,
18
18
  field: {name: 'dateCreated', type: 'date'},
19
19
  tooltip: true,
20
- align: 'right',
21
20
  renderer: dateTimeRenderer({fmt: 'MMM DD HH:mm:ss'})
22
21
  };
23
22
 
@@ -13,8 +13,6 @@ import {fmtDate, fmtSpan, numberRenderer} from '@xh/hoist/format';
13
13
  import {Icon} from '@xh/hoist/icon';
14
14
  import {ReactElement} from 'react';
15
15
 
16
- const autosizeMaxWidth = 400;
17
-
18
16
  export const appBuild: ColumnSpec = {
19
17
  field: {
20
18
  name: 'appBuild',
@@ -76,7 +74,7 @@ export const correlationId: ColumnSpec = {
76
74
  export const data: ColumnSpec = {
77
75
  field: {name: 'data', type: 'json'},
78
76
  width: 250,
79
- autosizeMaxWidth
77
+ autosizeMaxWidth: 400
80
78
  };
81
79
 
82
80
  export const day: ColumnSpec = {
@@ -181,7 +179,7 @@ export const error: ColumnSpec = {
181
179
  type: 'string'
182
180
  },
183
181
  width: 250,
184
- autosizeMaxWidth,
182
+ autosizeMaxWidth: 400,
185
183
  renderer: e => fmtSpan(e, {className: 'xh-font-family-mono xh-font-size-small'})
186
184
  };
187
185
 
@@ -213,7 +211,7 @@ export const msg: ColumnSpec = {
213
211
  aggregator: 'UNIQUE'
214
212
  },
215
213
  width: 250,
216
- autosizeMaxWidth
214
+ autosizeMaxWidth: 400
217
215
  };
218
216
 
219
217
  export const severity: ColumnSpec = {
@@ -269,13 +267,13 @@ export const url: ColumnSpec = {
269
267
  displayName: 'URL'
270
268
  },
271
269
  width: 250,
272
- autosizeMaxWidth
270
+ autosizeMaxWidth: 400
273
271
  };
274
272
 
275
273
  export const urlPathOnly: ColumnSpec = {
276
274
  field: url.field,
277
275
  width: 250,
278
- autosizeMaxWidth,
276
+ autosizeMaxWidth: 400,
279
277
  tooltip: true,
280
278
  renderer: v => {
281
279
  if (!v) return null;
@@ -295,8 +293,7 @@ export const userAgent: ColumnSpec = {
295
293
  isDimension: true,
296
294
  aggregator: 'UNIQUE'
297
295
  },
298
- width: 130,
299
- autosizeMaxWidth
296
+ width: 130
300
297
  };
301
298
 
302
299
  export const userAlertedFlag: ColumnSpec = {
@@ -15,15 +15,14 @@ import {FormModel} from '@xh/hoist/cmp/form';
15
15
  import {ColumnRenderer, ColumnSpec, GridModel, TreeStyle} from '@xh/hoist/cmp/grid';
16
16
  import {GroupingChooserModel} from '@xh/hoist/cmp/grouping';
17
17
  import {HoistModel, LoadSpec, managed, PlainObject, XH} from '@xh/hoist/core';
18
- import {Cube, CubeFieldSpec, FieldSpec, StoreRecord} from '@xh/hoist/data';
18
+ import {Cube, CubeFieldSpec, FieldSpec} from '@xh/hoist/data';
19
19
  import {dateRenderer, dateTimeSecRenderer, fmtNumber, numberRenderer} from '@xh/hoist/format';
20
20
  import {action, computed, makeObservable, observable} from '@xh/hoist/mobx';
21
21
  import {LocalDate} from '@xh/hoist/utils/datetime';
22
22
  import {compact, get, isEmpty, isEqual, round} from 'lodash';
23
23
  import moment from 'moment';
24
- import {ActivityDetailProvider} from './detail/ActivityDetailModel';
25
24
 
26
- export class ActivityTrackingModel extends HoistModel implements ActivityDetailProvider {
25
+ export class ActivityTrackingModel extends HoistModel {
27
26
  /** FormModel for server-side querying controls. */
28
27
  @managed formModel: FormModel;
29
28
 
@@ -40,17 +39,6 @@ export class ActivityTrackingModel extends HoistModel implements ActivityDetailP
40
39
  */
41
40
  @observable.ref dataFields: ActivityTrackingDataFieldSpec[] = [];
42
41
 
43
- // TODO - process two collections - one for agg grid with _agg fields left as-is, another for
44
- // detail grid and filter that replaces (potentially multiple) agg fields with a single
45
- // underlying field.
46
- get dataFieldCols(): ColumnSpec[] {
47
- return this.dataFields.map(df => ({
48
- field: df,
49
- renderer: this.getDfRenderer(df),
50
- appData: {showInAggGrid: !!df.aggregator}
51
- }));
52
- }
53
-
54
42
  @observable showFilterChooser: boolean = false;
55
43
 
56
44
  get enabled(): boolean {
@@ -89,18 +77,21 @@ export class ActivityTrackingModel extends HoistModel implements ActivityDetailP
89
77
  return this.maxRows === this.cube.store.allCount;
90
78
  }
91
79
 
80
+ // TODO - process two collections - one for agg grid with _agg fields left as-is, another for
81
+ // detail grid and filter that replaces (potentially multiple) agg fields with a single
82
+ // underlying field.
83
+ get dataFieldCols(): ColumnSpec[] {
84
+ return this.dataFields.map(df => ({
85
+ field: df,
86
+ renderer: this.getDfRenderer(df),
87
+ appData: {showInAggGrid: !!df.aggregator}
88
+ }));
89
+ }
90
+
92
91
  get viewManagerModel() {
93
92
  return getAppModel().viewManagerModels.activityTracking;
94
93
  }
95
94
 
96
- //-----------------------
97
- // ActivityDetailProvider
98
- //-----------------------
99
- readonly isActivityDetailProvider = true;
100
-
101
- /** Raw leaf-level log entries for the selected aggregate record, for detail. */
102
- @observable.ref trackLogs: PlainObject[] = [];
103
-
104
95
  private _monthFormat = 'MMM YYYY';
105
96
 
106
97
  constructor() {
@@ -130,11 +121,6 @@ export class ActivityTrackingModel extends HoistModel implements ActivityDetailP
130
121
  track: () => [this.cube.records, this.dimensions],
131
122
  run: () => this.loadGridAsync(),
132
123
  debounce: 100
133
- },
134
- {
135
- track: () => this.gridModel.selectedRecords,
136
- run: recs => (this.trackLogs = this.getAllLeafRows(recs)),
137
- debounce: 100
138
124
  }
139
125
  );
140
126
  }
@@ -287,23 +273,6 @@ export class ActivityTrackingModel extends HoistModel implements ActivityDetailP
287
273
  };
288
274
  }
289
275
 
290
- // Extract all leaf, track-entry-level rows from an aggregate record (at any level).
291
- private getAllLeafRows(aggRecs: StoreRecord[], ret = []): PlainObject[] {
292
- if (isEmpty(aggRecs)) return [];
293
-
294
- aggRecs.forEach(aggRec => {
295
- if (aggRec.children.length) {
296
- this.getAllLeafRows(aggRec.children, ret);
297
- } else if (aggRec.raw.leafRows) {
298
- aggRec.raw.leafRows.forEach(leaf => {
299
- ret.push({...leaf});
300
- });
301
- }
302
- });
303
-
304
- return ret;
305
- }
306
-
307
276
  //------------------------
308
277
  // Impl - core data models
309
278
  //------------------------
@@ -413,12 +382,11 @@ export class ActivityTrackingModel extends HoistModel implements ActivityDetailP
413
382
  const hidden = true;
414
383
  return new GridModel({
415
384
  persistWith: {...this.persistWith, path: 'aggGrid'},
416
- selModel: 'multiple',
417
385
  enableExport: true,
418
386
  colChooserModel: true,
419
387
  treeMode: true,
420
388
  treeStyle: TreeStyle.HIGHLIGHTS_AND_BORDERS,
421
- autosizeOptions: {mode: 'managed', includeCollapsedChildren: true},
389
+ autosizeOptions: {mode: 'managed'},
422
390
  exportOptions: {filename: exportFilename('activity-summary')},
423
391
  emptyText: 'No activity reported...',
424
392
  sortBy: ['cubeLabel'],
@@ -430,7 +398,6 @@ export class ActivityTrackingModel extends HoistModel implements ActivityDetailP
430
398
  displayName: 'Group'
431
399
  },
432
400
  minWidth: 100,
433
- autosizeMaxWidth: 400,
434
401
  isTreeColumn: true,
435
402
  comparator: this.cubeLabelComparator.bind(this)
436
403
  },
@@ -155,7 +155,7 @@ const aggregateView = hoistCmp.factory<ActivityTrackingModel>(({model}) => {
155
155
  persistWith: {...model.persistWith, path: 'aggPanel'}
156
156
  },
157
157
  tbar: toolbar({
158
- compact: true,
158
+ // compact: true,
159
159
  items: [
160
160
  groupingChooser({flex: 10, maxWidth: 300}),
161
161
  filler(),
@@ -6,32 +6,17 @@
6
6
  */
7
7
  import {exportFilename} from '@xh/hoist/admin/AdminUtils';
8
8
  import * as Col from '@xh/hoist/admin/columns';
9
- import {ActivityTrackingDataFieldSpec} from '@xh/hoist/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel';
10
9
  import {FormModel} from '@xh/hoist/cmp/form';
11
- import {ColumnSpec, GridModel} from '@xh/hoist/cmp/grid';
12
- import {HoistModel, lookup, managed, PersistOptions, PlainObject} from '@xh/hoist/core';
10
+ import {GridModel} from '@xh/hoist/cmp/grid';
11
+ import {HoistModel, lookup, managed} from '@xh/hoist/core';
13
12
  import {StoreRecord} from '@xh/hoist/data';
14
13
  import {timestampReplacer} from '@xh/hoist/format';
15
14
  import {action, bindable, computed, makeObservable, observable} from '@xh/hoist/mobx';
16
- import {get, isString} from 'lodash';
17
-
18
- /**
19
- * Interface to cover the two usages of this component - {@link ActivityTrackingModel} and {@link ClientDetailModel}
20
- */
21
- export interface ActivityDetailProvider {
22
- isActivityDetailProvider: true;
23
- trackLogs: PlainObject[];
24
- persistWith?: PersistOptions;
25
- colDefaults?: Record<string, Partial<ColumnSpec>>;
26
- dataFields?: ActivityTrackingDataFieldSpec[];
27
- dataFieldCols?: ColumnSpec[];
28
- }
15
+ import {get} from 'lodash';
16
+ import {ActivityTrackingModel} from '../ActivityTrackingModel';
29
17
 
30
18
  export class ActivityDetailModel extends HoistModel {
31
- @lookup(model => {
32
- return model.isActivityDetailProvider ?? false;
33
- })
34
- parentModel: ActivityDetailProvider;
19
+ @lookup(ActivityTrackingModel) activityTrackingModel: ActivityTrackingModel;
35
20
 
36
21
  @managed @observable.ref gridModel: GridModel;
37
22
  @managed @observable.ref formModel: FormModel;
@@ -46,22 +31,14 @@ export class ActivityDetailModel extends HoistModel {
46
31
  /** Stringified, pretty-printed, optionally path-filtered `data` payload. */
47
32
  @observable formattedData: string;
48
33
 
49
- get dataFields(): ActivityTrackingDataFieldSpec[] {
50
- return this.parentModel?.dataFields ?? [];
51
- }
52
-
53
- get dataFieldCols(): ColumnSpec[] {
54
- return this.parentModel?.dataFieldCols ?? [];
55
- }
56
-
57
34
  @computed
58
35
  get hasExtraTrackData(): boolean {
59
- return this.gridModel?.selectedRecord?.data.data != null;
36
+ return this.gridModel.selectedRecord?.data.data != null;
60
37
  }
61
38
 
62
39
  @computed
63
40
  get hasSelection() {
64
- return this.gridModel?.selectedRecord != null;
41
+ return this.gridModel.selectedRecord != null;
65
42
  }
66
43
 
67
44
  constructor() {
@@ -70,22 +47,17 @@ export class ActivityDetailModel extends HoistModel {
70
47
  }
71
48
 
72
49
  override onLinked() {
73
- if (this.parentModel.persistWith) {
74
- this.persistWith = {...this.parentModel.persistWith, path: 'activityDetail'};
75
- this.markPersist('formattedDataFilterPath', {
76
- path: `${this.persistWith.path}.formattedDataFilterPath`
77
- });
78
- }
50
+ this.markPersist('formattedDataFilterPath', this.activityTrackingModel.persistWith);
79
51
 
80
52
  this.addReaction(
81
53
  {
82
- track: () => this.dataFields,
54
+ track: () => this.activityTrackingModel.dataFields,
83
55
  run: () => this.createAndSetCoreModels(),
84
56
  fireImmediately: true
85
57
  },
86
58
  {
87
- track: () => this.parentModel.trackLogs,
88
- run: trackLogs => this.showTrackLogsAsync(trackLogs)
59
+ track: () => this.activityTrackingModel.gridModel.selectedRecord,
60
+ run: aggRec => this.showActivityEntriesAsync(aggRec)
89
61
  },
90
62
  {
91
63
  track: () => this.gridModel.selectedRecord,
@@ -101,12 +73,29 @@ export class ActivityDetailModel extends HoistModel {
101
73
  //------------------
102
74
  // Implementation
103
75
  //------------------
104
- private async showTrackLogsAsync(trackLogs: PlainObject[]) {
105
- const {gridModel} = this;
106
- gridModel.loadData(trackLogs);
76
+ private async showActivityEntriesAsync(aggRec: StoreRecord) {
77
+ const {gridModel} = this,
78
+ leaves = this.getAllLeafRows(aggRec);
79
+
80
+ gridModel.loadData(leaves);
107
81
  await gridModel.preSelectFirstAsync();
108
82
  }
109
83
 
84
+ // Extract all leaf, track-entry-level rows from an aggregate record (at any level).
85
+ private getAllLeafRows(aggRec: StoreRecord, ret = []) {
86
+ if (!aggRec) return [];
87
+
88
+ if (aggRec.children.length) {
89
+ aggRec.children.forEach(childRec => this.getAllLeafRows(childRec, ret));
90
+ } else if (aggRec.raw.leafRows) {
91
+ aggRec.raw.leafRows.forEach(leaf => {
92
+ ret.push({...leaf});
93
+ });
94
+ }
95
+
96
+ return ret;
97
+ }
98
+
110
99
  /** Extract data from a (detail) grid record and flush it into our form for display. */
111
100
  @action
112
101
  private showEntryDetail(detailRec: StoreRecord) {
@@ -150,13 +139,11 @@ export class ActivityDetailModel extends HoistModel {
150
139
  }
151
140
 
152
141
  private createGridModel(): GridModel {
153
- const {persistWith, parentModel, dataFieldCols} = this,
154
- colDefaults = parentModel.colDefaults ?? {},
155
- hidden = true,
142
+ const hidden = true,
156
143
  pinned = true;
157
144
 
158
145
  return new GridModel({
159
- persistWith: persistWith ? {...persistWith, path: `${persistWith.path}.grid`} : null,
146
+ persistWith: {...this.activityTrackingModel.persistWith, path: 'detailGrid'},
160
147
  sortBy: 'dateCreated|desc',
161
148
  colChooserModel: true,
162
149
  enableExport: true,
@@ -187,11 +174,8 @@ export class ActivityDetailModel extends HoistModel {
187
174
  {...Col.urlPathOnly},
188
175
  {...Col.data, hidden},
189
176
  {...Col.dateCreatedNoYear, displayName: 'Timestamp'},
190
- ...dataFieldCols
191
- ].map(it => {
192
- const fieldName = isString(it.field) ? it.field : it.field.name;
193
- return {...it, ...colDefaults[fieldName]};
194
- })
177
+ ...this.activityTrackingModel.dataFieldCols
178
+ ]
195
179
  });
196
180
  }
197
181
 
@@ -37,12 +37,11 @@ export const activityDetailView = hoistCmp.factory({
37
37
  const tbar = hoistCmp.factory<ActivityDetailModel>(({model}) => {
38
38
  const {gridModel} = model;
39
39
  return toolbar({
40
- compact: true,
41
40
  items: [
42
41
  filler(),
43
42
  gridCountLabel({unit: 'entry'}),
44
43
  '-',
45
- gridFindField({gridModel, key: gridModel.xhId, width: 250}),
44
+ gridFindField({gridModel, key: gridModel.xhId}),
46
45
  colChooserButton({gridModel}),
47
46
  exportButton()
48
47
  ]
@@ -51,8 +50,6 @@ const tbar = hoistCmp.factory<ActivityDetailModel>(({model}) => {
51
50
 
52
51
  // Discrete outer panel to retain sizing across master/detail selection changes.
53
52
  const detailRecPanel = hoistCmp.factory<ActivityDetailModel>(({model}) => {
54
- const {persistWith} = model;
55
-
56
53
  return panel({
57
54
  collapsedTitle: 'Activity Details',
58
55
  collapsedIcon: Icon.info(),
@@ -60,9 +57,10 @@ const detailRecPanel = hoistCmp.factory<ActivityDetailModel>(({model}) => {
60
57
  modelConfig: {
61
58
  side: 'bottom',
62
59
  defaultSize: 400,
63
- persistWith: persistWith
64
- ? {...persistWith, path: `${persistWith.path}.singleActivityDetailPanel`}
65
- : null
60
+ persistWith: {
61
+ ...model.activityTrackingModel.persistWith,
62
+ path: 'singleActivityDetailPanel'
63
+ }
66
64
  },
67
65
  item: detailRecForm()
68
66
  });
@@ -73,8 +73,6 @@ export class ClientsModel extends BaseAdminTabModel {
73
73
  }
74
74
 
75
75
  override async doLoadAsync(loadSpec: LoadSpec) {
76
- const {gridModel} = this;
77
-
78
76
  try {
79
77
  const data = await XH.fetchJson({
80
78
  url: 'clientAdmin/allClients',
@@ -82,15 +80,12 @@ export class ClientsModel extends BaseAdminTabModel {
82
80
  });
83
81
  if (loadSpec.isStale) return;
84
82
 
85
- gridModel.loadData(data);
86
- gridModel.preSelectFirstAsync();
83
+ this.gridModel.loadData(data);
87
84
  runInAction(() => {
88
85
  this.lastRefresh = Date.now();
89
86
  });
90
87
  } catch (e) {
91
- if (loadSpec.isStale || loadSpec.isAutoRefresh) return;
92
-
93
- gridModel.clear();
88
+ if (loadSpec.isStale) return;
94
89
  XH.handleException(e, {alertType: 'toast'});
95
90
  }
96
91
  }
@@ -4,10 +4,9 @@
4
4
  *
5
5
  * Copyright © 2025 Extremely Heavy Industries Inc.
6
6
  */
7
- import {clientDetailPanel} from '@xh/hoist/admin/tabs/client/clients/activity/ClientDetailPanel';
8
7
  import {errorMessage} from '@xh/hoist/cmp/error';
9
8
  import {grid, gridCountLabel} from '@xh/hoist/cmp/grid';
10
- import {filler, fragment, hframe, p} from '@xh/hoist/cmp/layout';
9
+ import {filler, fragment, p} from '@xh/hoist/cmp/layout';
11
10
  import {relativeTimestamp} from '@xh/hoist/cmp/relativetimestamp';
12
11
  import {storeFilterField} from '@xh/hoist/cmp/store';
13
12
  import {creates, hoistCmp, XH} from '@xh/hoist/core';
@@ -49,7 +48,7 @@ export const clientsPanel = hoistCmp.factory<ClientsModel>({
49
48
  colChooserButton(),
50
49
  exportButton()
51
50
  ],
52
- items: hframe(grid(), clientDetailPanel()),
51
+ item: grid(),
53
52
  mask: 'onLoad',
54
53
  ref: model.viewRef
55
54
  });
@@ -6,8 +6,7 @@ import { GroupingChooserModel } from '@xh/hoist/cmp/grouping';
6
6
  import { HoistModel, LoadSpec, PlainObject } from '@xh/hoist/core';
7
7
  import { Cube } from '@xh/hoist/data';
8
8
  import { LocalDate } from '@xh/hoist/utils/datetime';
9
- import { ActivityDetailProvider } from './detail/ActivityDetailModel';
10
- export declare class ActivityTrackingModel extends HoistModel implements ActivityDetailProvider {
9
+ export declare class ActivityTrackingModel extends HoistModel {
11
10
  /** FormModel for server-side querying controls. */
12
11
  formModel: FormModel;
13
12
  /** Models for data-handling components - can be rebuilt due to change in dataFields. */
@@ -21,7 +20,6 @@ export declare class ActivityTrackingModel extends HoistModel implements Activit
21
20
  * and promoted to top-level columns in the grids. Supports dot-delimited paths as names.
22
21
  */
23
22
  dataFields: ActivityTrackingDataFieldSpec[];
24
- get dataFieldCols(): ColumnSpec[];
25
23
  showFilterChooser: boolean;
26
24
  get enabled(): boolean;
27
25
  get dimensions(): string[];
@@ -34,10 +32,8 @@ export declare class ActivityTrackingModel extends HoistModel implements Activit
34
32
  get maxRows(): number;
35
33
  /** True if data loaded from the server has been topped by maxRows. */
36
34
  get maxRowsReached(): boolean;
35
+ get dataFieldCols(): ColumnSpec[];
37
36
  get viewManagerModel(): import("../../../../cmp/viewmanager").ViewManagerModel<PlainObject>;
38
- readonly isActivityDetailProvider = true;
39
- /** Raw leaf-level log entries for the selected aggregate record, for detail. */
40
- trackLogs: PlainObject[];
41
37
  private _monthFormat;
42
38
  constructor();
43
39
  doLoadAsync(loadSpec: LoadSpec): Promise<void>;
@@ -53,7 +49,6 @@ export declare class ActivityTrackingModel extends HoistModel implements Activit
53
49
  private cubeLabelComparator;
54
50
  private getComparableValForDim;
55
51
  private get query();
56
- private getAllLeafRows;
57
52
  private createAndSetCoreModels;
58
53
  private createCube;
59
54
  private createFilterChooserModel;
@@ -1,20 +1,9 @@
1
- import { ActivityTrackingDataFieldSpec } from '@xh/hoist/admin/tabs/activity/tracking/datafields/DataFieldsEditorModel';
2
1
  import { FormModel } from '@xh/hoist/cmp/form';
3
- import { ColumnSpec, GridModel } from '@xh/hoist/cmp/grid';
4
- import { HoistModel, PersistOptions, PlainObject } from '@xh/hoist/core';
5
- /**
6
- * Interface to cover the two usages of this component - {@link ActivityTrackingModel} and {@link ClientDetailModel}
7
- */
8
- export interface ActivityDetailProvider {
9
- isActivityDetailProvider: true;
10
- trackLogs: PlainObject[];
11
- persistWith?: PersistOptions;
12
- colDefaults?: Record<string, Partial<ColumnSpec>>;
13
- dataFields?: ActivityTrackingDataFieldSpec[];
14
- dataFieldCols?: ColumnSpec[];
15
- }
2
+ import { GridModel } from '@xh/hoist/cmp/grid';
3
+ import { HoistModel } from '@xh/hoist/core';
4
+ import { ActivityTrackingModel } from '../ActivityTrackingModel';
16
5
  export declare class ActivityDetailModel extends HoistModel {
17
- parentModel: ActivityDetailProvider;
6
+ activityTrackingModel: ActivityTrackingModel;
18
7
  gridModel: GridModel;
19
8
  formModel: FormModel;
20
9
  /**
@@ -25,13 +14,12 @@ export declare class ActivityDetailModel extends HoistModel {
25
14
  formattedDataFilterPath: string;
26
15
  /** Stringified, pretty-printed, optionally path-filtered `data` payload. */
27
16
  formattedData: string;
28
- get dataFields(): ActivityTrackingDataFieldSpec[];
29
- get dataFieldCols(): ColumnSpec[];
30
17
  get hasExtraTrackData(): boolean;
31
18
  get hasSelection(): boolean;
32
19
  constructor();
33
20
  onLinked(): void;
34
- private showTrackLogsAsync;
21
+ private showActivityEntriesAsync;
22
+ private getAllLeafRows;
35
23
  /** Extract data from a (detail) grid record and flush it into our form for display. */
36
24
  private showEntryDetail;
37
25
  private updateFormattedData;
@@ -60,7 +60,10 @@ export interface GridFilterModelConfig {
60
60
  * gridModel's store.
61
61
  */
62
62
  bind?: Store | View;
63
- /** True (default) to update filters immediately after each change made in the column-based filter UI.*/
63
+ /**
64
+ * True to update filters immediately after each change made in the column-based filter UI.
65
+ * Defaults to False.
66
+ */
64
67
  commitOnChange?: boolean;
65
68
  /**
66
69
  * Specifies the fields this model supports for filtering. Should be configs for
@@ -11,6 +11,7 @@ export declare class ValuesTabModel extends HoistModel {
11
11
  pendingValues: any[];
12
12
  /** Bound search term for `StoreFilterField` */
13
13
  filterText: string;
14
+ combineCurrentFilters: boolean;
14
15
  /** FieldFilter output by this model. */
15
16
  get filter(): FieldFilterSpec;
16
17
  get allVisibleRecsChecked(): boolean;
@@ -26,6 +27,7 @@ export declare class ValuesTabModel extends HoistModel {
26
27
  reset(): void;
27
28
  setRecsChecked(isChecked: boolean, values: any[]): void;
28
29
  toggleAllRecsChecked(): void;
30
+ setPendingValues(): void;
29
31
  private getFilter;
30
32
  private doSyncWithFilter;
31
33
  private syncGrid;
@@ -2,10 +2,11 @@ import { PopperBoundary, PopperModifierOverrides } from '@blueprintjs/core';
2
2
  import { TimePickerProps } from '@blueprintjs/datetime';
3
3
  import { ReactDayPickerSingleProps } from '@blueprintjs/datetime2/src/common/reactDayPickerProps';
4
4
  import { HoistInputProps } from '@xh/hoist/cmp/input';
5
- import { HoistProps, HSide, LayoutProps, Some } from '@xh/hoist/core';
5
+ import { HoistProps, LayoutProps, Some } from '@xh/hoist/core';
6
6
  import '@xh/hoist/desktop/register';
7
7
  import { Position } from '@xh/hoist/kit/blueprint';
8
8
  import { LocalDate } from '@xh/hoist/utils/datetime';
9
+ import type { Property } from 'csstype';
9
10
  import { ReactElement, ReactNode } from 'react';
10
11
  import './DateInput.scss';
11
12
  export interface DateInputProps extends HoistProps, LayoutProps, HoistInputProps {
@@ -88,7 +89,7 @@ export interface DateInputProps extends HoistProps, LayoutProps, HoistInputProps
88
89
  */
89
90
  strictInputParsing?: boolean;
90
91
  /** Alignment of entry text within control, default 'left'. */
91
- textAlign?: HSide;
92
+ textAlign?: Property.TextAlign;
92
93
  /**
93
94
  * Props passed to the TimePicker, as per Blueprint docs.
94
95
  * @see https://blueprintjs.com/docs/#datetime/dateinput
@@ -1,7 +1,8 @@
1
1
  import { HoistInputProps } from '@xh/hoist/cmp/input';
2
- import { HoistProps, HSide, LayoutProps, StyleProps } from '@xh/hoist/core';
2
+ import { HoistProps, LayoutProps, StyleProps } from '@xh/hoist/core';
3
3
  import '@xh/hoist/desktop/register';
4
4
  import { NumericPrecision, ZeroPad } from '@xh/hoist/format';
5
+ import type { Property } from 'csstype';
5
6
  import { KeyboardEventHandler, ReactElement, ReactNode, Ref } from 'react';
6
7
  export interface NumberInputProps extends HoistProps, LayoutProps, StyleProps, HoistInputProps {
7
8
  value?: number;
@@ -51,7 +52,7 @@ export interface NumberInputProps extends HoistProps, LayoutProps, StyleProps, H
51
52
  /** Standard step size for increment/decrement handling. */
52
53
  stepSize?: number;
53
54
  /** Alignment of entry text within control, default 'right'. */
54
- textAlign?: HSide;
55
+ textAlign?: Property.TextAlign;
55
56
  /**
56
57
  * Text appended to the rendered value within control when not editing.
57
58
  * Can be used to append e.g. "%" or a unit without need for an external right label.
@@ -1,6 +1,7 @@
1
1
  import { HoistInputModel, HoistInputProps } from '@xh/hoist/cmp/input';
2
- import { HoistProps, HSide, LayoutProps, StyleProps } from '@xh/hoist/core';
2
+ import { HoistProps, LayoutProps, StyleProps } from '@xh/hoist/core';
3
3
  import '@xh/hoist/desktop/register';
4
+ import type { Property } from 'csstype';
4
5
  import { FocusEvent, KeyboardEventHandler, ReactElement, ReactNode, Ref } from 'react';
5
6
  export interface TextInputProps extends HoistProps, HoistInputProps, LayoutProps, StyleProps {
6
7
  value?: string;
@@ -36,7 +37,7 @@ export interface TextInputProps extends HoistProps, HoistInputProps, LayoutProps
36
37
  /** True to select contents when control receives focus. */
37
38
  selectOnFocus?: boolean;
38
39
  /** Alignment of entry text within control, default 'left'. */
39
- textAlign?: HSide;
40
+ textAlign?: Property.TextAlign;
40
41
  /** True to allow browser spell check, default false. */
41
42
  spellCheck?: boolean;
42
43
  /** Underlying HTML <input> element type. */