@xh/hoist 76.0.0-SNAPSHOT.1755397026376 → 76.0.0-SNAPSHOT.1755652707785

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 CHANGED
@@ -4,8 +4,20 @@
4
4
 
5
5
  ### 🎁 New Features
6
6
 
7
- * Added new `extraConfirmText`, `extraConfirmLabel` properties to `MessageOptions`. Use this option
8
- to require the specified text to be re-typed by a user when confirming a potentially destructive or disruptive action.
7
+ * Added new `extraConfirmText`, `extraConfirmLabel` properties to `MessageOptions`. Use this option
8
+ to require the specified text to be re-typed by a user when confirming a potentially destructive
9
+ or disruptive action.
10
+
11
+ ### 🐞 Bug Fixes
12
+
13
+ * Handled an edge-case `ViewManager` bug where `enableDefault` changed to `false` after some user
14
+ state had already been persisted w/users pointed at in-code default view. The manager now calls
15
+ its configured `initialViewSpec` function as expected in this case.
16
+
17
+ ### ⚙️ Technical
18
+
19
+ * Added control to trigger browser GC from app footer. Useful for troubleshooting memory issues.
20
+ Requires running chromium-based browser via e.g. `start chrome --js-flags="--expose-gc`.
9
21
 
10
22
  ## 75.0.1 - 2025-08-11
11
23
 
@@ -20,11 +32,11 @@
20
32
  Provides easier discoverability on desktop and supports this feature on mobile, where we
21
33
  don't have context menus.
22
34
  * Enhanced `FilterChooser` to better handle filters with different `op`s on the same field.
23
- * Multiple "inclusive" ops (e.g. `=`, `like`) will be OR'ed together.
24
- * Multiple "exclusive" ops (e.g. `!=`, `not like`) will be AND'ed together.
25
- * Range ops (e.g. `<`, `>` ) use a heuristic to avoid creating a filter that could never match.
26
- * This behavior is consistent with current behavior and user intuition and should maximize the
27
- ability to create useful queries using this component.
35
+ * Multiple "inclusive" ops (e.g. `=`, `like`) will be OR'ed together.
36
+ * Multiple "exclusive" ops (e.g. `!=`, `not like`) will be AND'ed together.
37
+ * Range ops (e.g. `<`, `>` ) use a heuristic to avoid creating a filter that could never match.
38
+ * This behavior is consistent with current behavior and user intuition and should maximize the
39
+ ability to create useful queries using this component.
28
40
  * Deprecated the `RelativeTimestamp.options` prop - all the same options are now top-level props.
29
41
  * Added new `GroupingChooserModel.sortDimensions` config. Set to `false` to respect the order in
30
42
  which `dimensions` are provided to the model.
@@ -58,8 +70,9 @@
58
70
  * Hoist now sets a reference to an app's singleton `AuthModel` on a static `instance` property of
59
71
  the app-specified class. App developers can declare a typed static `instance` property on their
60
72
  model class and use it to access the singleton with its proper type, vs. `XH.authModel`.
61
- * The `XH.authModel` property is still set and available - this is a non-breaking change.
62
- * This approach was already (and continues to be) used for services and the `AppModel` singleton.
73
+ * The `XH.authModel` property is still set and available - this is a non-breaking change.
74
+ * This approach was already (and continues to be) used for services and the `AppModel`
75
+ singleton.
63
76
 
64
77
  ### 💥 Breaking Changes (upgrade difficulty: 🟢 LOW - removing deprecations)
65
78
 
@@ -14,7 +14,7 @@ export declare class DataAccess<T> {
14
14
  views: ViewInfo[];
15
15
  state: ViewUserState;
16
16
  }>;
17
- /** Fetch the latest version of a view. */
17
+ /** Fetch the latest version of a view, or the in-code default if token null/undefined/empty. */
18
18
  fetchViewAsync(token: string): Promise<View<T>>;
19
19
  /** Create a new view, owned by the current user.*/
20
20
  createViewAsync(spec: ViewCreateSpec): Promise<View<T>>;
@@ -47,7 +47,7 @@ export class DataAccess<T> {
47
47
  }
48
48
  }
49
49
 
50
- /** Fetch the latest version of a view. */
50
+ /** Fetch the latest version of a view, or the in-code default if token null/undefined/empty. */
51
51
  async fetchViewAsync(token: string): Promise<View<T>> {
52
52
  const {model} = this;
53
53
  if (!token) return View.createDefault(model);
@@ -19,7 +19,7 @@ import type {ViewManagerProvider, ReactionSpec} from '@xh/hoist/core';
19
19
  import {genDisplayName} from '@xh/hoist/data';
20
20
  import {fmtDateTime} from '@xh/hoist/format';
21
21
  import {action, bindable, makeObservable, observable, comparer, runInAction} from '@xh/hoist/mobx';
22
- import {SECONDS} from '@xh/hoist/utils/datetime';
22
+ import {ONE_SECOND, SECONDS} from '@xh/hoist/utils/datetime';
23
23
  import {executeIfFunction, pluralize, throwIf} from '@xh/hoist/utils/js';
24
24
  import {find, isEqual, isNil, isNull, isObject, isUndefined, lowerCase, uniqBy} from 'lodash';
25
25
  import {ReactNode} from 'react';
@@ -531,8 +531,8 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
531
531
  // Implementation
532
532
  //------------------
533
533
  private async initAsync() {
534
- let {dataAccess, pendingValueStorageKey} = this,
535
- initialState;
534
+ let {dataAccess, pendingValueStorageKey, enableDefault} = this,
535
+ initialState: ViewUserState;
536
536
 
537
537
  try {
538
538
  // 1) Initialize views and related state
@@ -547,17 +547,23 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
547
547
  }
548
548
  });
549
549
 
550
- // 2) Initialize/choose initial view. Null is ok, and will yield default.
550
+ // 2) Select the initial view.
551
551
  let initialView: ViewInfo,
552
552
  initialTkn: string = initialState.currentView;
553
- if (isUndefined(initialTkn)) {
553
+ if (isUndefined(initialTkn) || (isNull(initialTkn) && !enableDefault)) {
554
+ // Token undefined (no prior view) or null (in-code default *had* been loaded) but
555
+ // default no longer enabled - call initialViewSpec.
554
556
  initialView = this.initialViewSpec?.(views);
555
557
  } else if (!isNull(initialTkn)) {
558
+ // Token provided - find the view, falling back to initialViewSpec if not found.
556
559
  initialView = find(views, {token: initialTkn}) ?? this.initialViewSpec?.(views);
557
560
  } else {
561
+ // Token null - active signal to load in-code default.
558
562
  initialView = null;
559
563
  }
560
564
 
565
+ // Note that the above routine failed to resolve a view, we will pass undefined here
566
+ // and load the in-code default, even if not enabled. We have no other choice!
561
567
  await this.loadViewAsync(initialView?.token, this.pendingValue);
562
568
  } catch (e) {
563
569
  // Always ensure at least default view is installed (other state defaults are fine)
@@ -594,7 +600,7 @@ export class ViewManagerModel<T = PlainObject> extends HoistModel {
594
600
  track: () => this.userPinned,
595
601
  run: userPinned => dataAccess.updateStateAsync({userPinned}),
596
602
  equals: comparer.structural,
597
- debounce: 1 * SECONDS
603
+ debounce: ONE_SECOND
598
604
  },
599
605
  {
600
606
  track: () => this.autoSave,
@@ -52,6 +52,12 @@ export const versionBar = hoistCmp.factory({
52
52
  omit: isAdminApp || !XH.getUser().isHoistAdminReader,
53
53
  title: 'Open Admin Console',
54
54
  onClick: () => XH.appContainerModel.openAdmin()
55
+ }),
56
+ // Force GC, available via V8/chromium and "start chrome --js-flags="--expose-gc"
57
+ Icon.memory({
58
+ omit: !window['gc'],
59
+ title: 'Force GC',
60
+ onClick: () => window['gc']()
55
61
  })
56
62
  ]
57
63
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xh/hoist",
3
- "version": "76.0.0-SNAPSHOT.1755397026376",
3
+ "version": "76.0.0-SNAPSHOT.1755652707785",
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",