@xh/hoist 78.0.0-SNAPSHOT.1763737348746 → 78.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +25 -3
- package/admin/differ/Differ.ts +1 -1
- package/admin/differ/DifferModel.ts +10 -1
- package/build/types/admin/differ/DifferModel.d.ts +4 -0
- package/build/types/cmp/grid/GridModel.d.ts +17 -17
- package/build/types/core/types/Types.d.ts +2 -0
- package/build/types/data/cube/BucketSpec.d.ts +4 -9
- package/build/types/data/cube/Cube.d.ts +3 -3
- package/build/types/data/cube/Query.d.ts +1 -1
- package/build/types/security/msal/MsalClient.d.ts +18 -2
- package/cmp/grid/GridModel.ts +29 -21
- package/core/types/Types.ts +3 -0
- package/data/Store.ts +4 -1
- package/data/cube/BucketSpec.ts +7 -10
- package/data/cube/Cube.ts +3 -3
- package/data/cube/Query.ts +1 -1
- package/data/cube/View.ts +2 -7
- package/package.json +3 -3
- package/security/BaseOAuthClient.ts +1 -1
- package/security/msal/MsalClient.ts +112 -74
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## 78.
|
|
3
|
+
## 78.1.0 - 2025-12-02
|
|
4
|
+
|
|
5
|
+
### ⚙️ Technical
|
|
6
|
+
* New property `MsalClientConfig.enableSsoSilent` to govern use of MSAL SSO api.
|
|
7
|
+
|
|
8
|
+
* Existing property `MsalClientConfig.enableTelemetry` now defaults to `true`.
|
|
9
|
+
|
|
10
|
+
* Improved use of MSAL client API, to maximize effectiveness of SSO. Improved documentation
|
|
11
|
+
and logging. Iframe attempts will now time out by default after 3 seconds vs. 10 seconds.
|
|
12
|
+
This can be further modified by apps via the option
|
|
13
|
+
`MsalClientConfig.msalClientOptions.system.iFrameHashTimeout`
|
|
14
|
+
|
|
15
|
+
### 📚 Libraries
|
|
16
|
+
|
|
17
|
+
* @auth0/auth0-spa-js `2.7 → 2.9`
|
|
18
|
+
* @azure/msal-browser `4.25 → 4.26`
|
|
19
|
+
|
|
20
|
+
## 78.0.0 - 2025-11-21
|
|
4
21
|
|
|
5
22
|
### 💥 Breaking Changes
|
|
6
23
|
|
|
@@ -27,13 +44,18 @@
|
|
|
27
44
|
|
|
28
45
|
### ⚙️ Technical
|
|
29
46
|
|
|
30
|
-
*
|
|
31
|
-
before) or a plain object conforming to the new `BucketSpecConfig` interface.
|
|
47
|
+
* Improved documentation on `BucketSpec` class.
|
|
32
48
|
* Enhanced `FetchService` to recognize variants on the `application/json` content-type when
|
|
33
49
|
processing failed responses and decoding exceptions - e.g. `application/problem+json`.
|
|
34
50
|
|
|
35
51
|
## 77.1.1 - 2025-11-12
|
|
36
52
|
|
|
53
|
+
### 💥 Breaking Changes (upgrade difficulty: 🟢 LOW)
|
|
54
|
+
|
|
55
|
+
* Apps that use and provide the `highcharts` library should be sure to update the version to v12.4.0.
|
|
56
|
+
Refer to `Bootstrap.js` in Toolbox for required import changes.
|
|
57
|
+
* Visit https://www.highcharts.com/blog/changelog/ for specific changes.
|
|
58
|
+
|
|
37
59
|
### 🎁 New Features
|
|
38
60
|
|
|
39
61
|
* New method `StoreRecord.getModifiedValues()` to gather edited data from a store record.
|
package/admin/differ/Differ.ts
CHANGED
|
@@ -60,8 +60,14 @@ export class DifferModel extends HoistModel {
|
|
|
60
60
|
recordsRequired: true
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
+
/**
|
|
64
|
+
* All other configured appInstances URLs, excepting the current one.
|
|
65
|
+
* (Use of startsWith allows configs to end in trailing /)
|
|
66
|
+
*/
|
|
63
67
|
get remoteHosts(): string[] {
|
|
64
|
-
return XH.getConf('xhAppInstances').filter(
|
|
68
|
+
return XH.getConf('xhAppInstances').filter(
|
|
69
|
+
(it: string) => !it.startsWith(window.location.origin)
|
|
70
|
+
);
|
|
65
71
|
}
|
|
66
72
|
|
|
67
73
|
constructor({
|
|
@@ -83,6 +89,9 @@ export class DifferModel extends HoistModel {
|
|
|
83
89
|
|
|
84
90
|
this.url = entityName + 'DiffAdmin';
|
|
85
91
|
|
|
92
|
+
// Default to first available remote for comparison
|
|
93
|
+
this.remoteHost = this.remoteHosts[0];
|
|
94
|
+
|
|
86
95
|
const rendererIsComplex = true;
|
|
87
96
|
this.gridModel = new GridModel({
|
|
88
97
|
store: {
|
|
@@ -24,6 +24,10 @@ export declare class DifferModel extends HoistModel {
|
|
|
24
24
|
hasLoaded: boolean;
|
|
25
25
|
get readonly(): boolean;
|
|
26
26
|
applyRemoteAction: RecordActionSpec;
|
|
27
|
+
/**
|
|
28
|
+
* All other configured appInstances URLs, excepting the current one.
|
|
29
|
+
* (Use of startsWith allows configs to end in trailing /)
|
|
30
|
+
*/
|
|
27
31
|
get remoteHosts(): string[];
|
|
28
32
|
constructor({ parentModel, entityName, displayName, columnFields, matchFields, valueRenderer }: Partial<DifferModel>);
|
|
29
33
|
doLoadAsync(loadSpec: LoadSpec): Promise<void>;
|
|
@@ -326,39 +326,39 @@ export declare class GridModel extends HoistModel {
|
|
|
326
326
|
localExport(filename: string, type: 'excel' | 'csv', params?: PlainObject): void;
|
|
327
327
|
/**
|
|
328
328
|
* Select records in the grid.
|
|
329
|
-
*
|
|
330
329
|
* @param records - one or more record(s) / ID(s) to select.
|
|
331
|
-
* @param
|
|
332
|
-
* ensureVisible - true to make selection visible if it is within a
|
|
333
|
-
* collapsed node or outside of the visible scroll window. Default true.
|
|
334
|
-
* clearSelection - true to clear previous selection (rather than
|
|
335
|
-
* add to it). Default true.
|
|
330
|
+
* @param opts - additional post-selection options
|
|
336
331
|
*/
|
|
337
332
|
selectAsync(records: Some<StoreRecordOrId>, opts?: {
|
|
333
|
+
/**
|
|
334
|
+
* True (default) to scroll the grid or expand nodes as needed to make selection
|
|
335
|
+
* visible if it is within a collapsed node or outside of the visible scroll window.
|
|
336
|
+
*/
|
|
338
337
|
ensureVisible?: boolean;
|
|
338
|
+
/** True (default) to clear previous selection (rather than add to it). */
|
|
339
339
|
clearSelection?: boolean;
|
|
340
340
|
}): Promise<void>;
|
|
341
341
|
/**
|
|
342
342
|
* Select the first row in the grid.
|
|
343
343
|
*
|
|
344
|
-
* See {@link preSelectFirstAsync} for a useful variant of this method
|
|
345
|
-
*
|
|
346
|
-
*
|
|
347
|
-
*
|
|
348
|
-
* @param opts -
|
|
349
|
-
* expandParentGroups - set to true to expand nodes to allow selection when the
|
|
350
|
-
* first selectable node is in a collapsed group. Default true.
|
|
351
|
-
* ensureVisible - set to to true to scroll to the selected row if it is outside of the
|
|
352
|
-
* visible scroll window. Default true.
|
|
353
|
-
*
|
|
344
|
+
* See {@link preSelectFirstAsync} for a useful variant of this method that will leave the
|
|
345
|
+
* any pre-existing selection unchanged, which is what apps typically want when reloading an
|
|
346
|
+
* already-populated grid.
|
|
354
347
|
*/
|
|
355
348
|
selectFirstAsync(opts?: {
|
|
349
|
+
/**
|
|
350
|
+
* True (default) to expand nodes as needed to allow selection when the first selectable
|
|
351
|
+
* node is in a collapsed group.
|
|
352
|
+
*/
|
|
356
353
|
expandParentGroups?: boolean;
|
|
354
|
+
/**
|
|
355
|
+
* True (default) to scroll the grid or expand nodes as needed to make selection
|
|
356
|
+
* visible if it is outside of the visible scroll window.
|
|
357
|
+
*/
|
|
357
358
|
ensureVisible?: boolean;
|
|
358
359
|
}): Promise<void>;
|
|
359
360
|
/**
|
|
360
361
|
* Select the first row in the grid, if no other selection present.
|
|
361
|
-
*
|
|
362
362
|
* This method delegates to {@link selectFirstAsync}.
|
|
363
363
|
*/
|
|
364
364
|
preSelectFirstAsync(): Promise<void>;
|
|
@@ -20,6 +20,8 @@ export type Thunkable<T> = T | (() => T);
|
|
|
20
20
|
export type Awaitable<T> = Promise<T> | T;
|
|
21
21
|
/** Convenience type for a "plain", string-keyed object holding any kind of values. */
|
|
22
22
|
export type PlainObject = Record<string, any>;
|
|
23
|
+
/** Convenience type to make a set of keys optional in a given type. */
|
|
24
|
+
export type SetOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
23
25
|
/**
|
|
24
26
|
* Specification for debouncing in Hoist.
|
|
25
27
|
*
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { BaseRow } from './row/BaseRow';
|
|
2
|
+
import { SetOptional } from '@xh/hoist/core';
|
|
2
3
|
/**
|
|
3
4
|
* Spec to define a bucketing level within the hierarchy of data returned by a Query, as identified
|
|
4
5
|
* by a set of rows passed to a {@link BucketSpecFn} configured on that Query (or defaulted from
|
|
@@ -6,7 +7,7 @@ import { BaseRow } from './row/BaseRow';
|
|
|
6
7
|
* spec's `bucketFn` to determine if it should yield a value for the bucket, causing the row to be
|
|
7
8
|
* nested underneath a new {@link BucketRow} created to hold all rows with that value.
|
|
8
9
|
*/
|
|
9
|
-
export
|
|
10
|
+
export declare class BucketSpec {
|
|
10
11
|
/** Name for the bucketing level configured by this spec - equivalent to a dimension name. */
|
|
11
12
|
name: string;
|
|
12
13
|
/**
|
|
@@ -18,19 +19,13 @@ export interface BucketSpecConfig {
|
|
|
18
19
|
* Function returning bucket row label from the bucket value string returned by bucketFn.
|
|
19
20
|
* Defaults to using the value directly.
|
|
20
21
|
*/
|
|
21
|
-
labelFn
|
|
22
|
+
labelFn: (bucket: string) => string;
|
|
22
23
|
/**
|
|
23
24
|
* Fields on which the `bucketFn` depends, to ensure rows are re-bucketed if dependent field
|
|
24
25
|
* values change. If not provided or does not cover all fields potentially accessed by
|
|
25
26
|
* `bucketFn`, an incremental "data only" update that should have changed a row's bucket can
|
|
26
27
|
* fail to do so.
|
|
27
28
|
*/
|
|
28
|
-
dependentFields?: string[];
|
|
29
|
-
}
|
|
30
|
-
export declare class BucketSpec {
|
|
31
|
-
name: string;
|
|
32
|
-
bucketFn: (row: BaseRow) => string;
|
|
33
|
-
labelFn: (bucket: string) => string;
|
|
34
29
|
dependentFields: string[];
|
|
35
|
-
constructor(config:
|
|
30
|
+
constructor(config: SetOptional<BucketSpec, 'labelFn' | 'dependentFields'>);
|
|
36
31
|
}
|
|
@@ -8,7 +8,7 @@ import { StoreRecord } from '../StoreRecord';
|
|
|
8
8
|
import { AggregateRow } from './row/AggregateRow';
|
|
9
9
|
import { BucketRow } from './row/BucketRow';
|
|
10
10
|
import { BaseRow } from './row/BaseRow';
|
|
11
|
-
import { BucketSpec
|
|
11
|
+
import { BucketSpec } from './BucketSpec';
|
|
12
12
|
export interface CubeConfig {
|
|
13
13
|
fields: CubeField[] | CubeFieldSpec[];
|
|
14
14
|
/** Default configs applied to all `CubeField`s constructed internally by this Cube. */
|
|
@@ -60,9 +60,9 @@ export type OmitFn = (row: AggregateRow | BucketRow) => boolean;
|
|
|
60
60
|
* aggregations and create an unwanted "Open" grouping.
|
|
61
61
|
*
|
|
62
62
|
* @param rows - the rows being checked for bucketing
|
|
63
|
-
* @returns {@link
|
|
63
|
+
* @returns {@link BucketSpec} for dynamic sub-aggregations, or null to perform no bucketing.
|
|
64
64
|
*/
|
|
65
|
-
export type BucketSpecFn = (rows: BaseRow[]) =>
|
|
65
|
+
export type BucketSpecFn = (rows: BaseRow[]) => BucketSpec;
|
|
66
66
|
/**
|
|
67
67
|
* A data store that supports grouping, aggregating, and filtering data on multiple dimensions.
|
|
68
68
|
*
|
|
@@ -79,7 +79,7 @@ export interface QueryConfig {
|
|
|
79
79
|
*
|
|
80
80
|
* This can be used to break selected aggregations into sub-groups dynamically, without having
|
|
81
81
|
* to define another dimension in the Cube and have it apply to all aggregations. See the
|
|
82
|
-
* {@link BucketSpecFn} type and {@link
|
|
82
|
+
* {@link BucketSpecFn} type and {@link BucketSpec} interface for additional information.
|
|
83
83
|
*
|
|
84
84
|
* Defaults to {@link Cube.bucketSpecFn}.
|
|
85
85
|
*/
|
|
@@ -19,7 +19,7 @@ export interface MsalClientConfig extends BaseOAuthClientConfig<MsalTokenSpec> {
|
|
|
19
19
|
domainHint?: string;
|
|
20
20
|
/**
|
|
21
21
|
* True to enable support for built-in telemetry provided by this class's internal MSAL client.
|
|
22
|
-
* Captured performance events will be summarized as {@link MsalClientTelemetry}.
|
|
22
|
+
* Captured performance events will be summarized as {@link MsalClientTelemetry}. Default true.
|
|
23
23
|
*/
|
|
24
24
|
enableTelemetry?: boolean;
|
|
25
25
|
/**
|
|
@@ -42,6 +42,17 @@ export interface MsalClientConfig extends BaseOAuthClientConfig<MsalTokenSpec> {
|
|
|
42
42
|
* See https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/token-lifetimes.md
|
|
43
43
|
*/
|
|
44
44
|
initRefreshTokenExpirationOffsetSecs?: number;
|
|
45
|
+
/**
|
|
46
|
+
* Enable the use of the MSAL ssoSilent() API, which will attempt to use credentials gained by
|
|
47
|
+
* another app or tab to start a new session for this app. Requires iFrames and 3rd party
|
|
48
|
+
* cookies to be enabled. Default true.
|
|
49
|
+
*
|
|
50
|
+
* In practice, and according to documentation, this operation is likely to fail for a
|
|
51
|
+
* number of reasons, and can often do so as timeout. Therefore, keeping the timeout limit
|
|
52
|
+
* value -- `system.iFrameHashTimeout` -- at a relatively low value is critical. Hoist
|
|
53
|
+
* defaults this value to 3000ms vs. the default 10000ms.
|
|
54
|
+
*/
|
|
55
|
+
enableSsoSilent?: boolean;
|
|
45
56
|
/** The log level of MSAL. Default is LogLevel.Warning. */
|
|
46
57
|
msalLogLevel?: LogLevel;
|
|
47
58
|
/**
|
|
@@ -105,14 +116,19 @@ export declare class MsalClient extends BaseOAuthClient<MsalClientConfig, MsalTo
|
|
|
105
116
|
private get loginScopes();
|
|
106
117
|
private get loginExtraScopesToConsent();
|
|
107
118
|
private get refreshOffsetArgs();
|
|
108
|
-
private
|
|
119
|
+
private setAccount;
|
|
120
|
+
private noteAuthComplete;
|
|
121
|
+
private authRequestCore;
|
|
109
122
|
}
|
|
123
|
+
type AuthMethod = 'acquireSilent' | 'ssoSilent' | 'loginPopup' | 'loginRedirect';
|
|
110
124
|
/**
|
|
111
125
|
* Telemetry produced by this client (if enabled) + included in {@link ClientHealthService}
|
|
112
126
|
* reporting. Leverages MSAL's opt-in support for emitting performance events.
|
|
113
127
|
* See https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/performance.md
|
|
114
128
|
*/
|
|
115
129
|
interface MsalClientTelemetry {
|
|
130
|
+
/** Method of last authentication for this client. */
|
|
131
|
+
authMethod: AuthMethod;
|
|
116
132
|
/** Stats across all events */
|
|
117
133
|
summary: {
|
|
118
134
|
successCount: number;
|
package/cmp/grid/GridModel.ts
CHANGED
|
@@ -751,19 +751,22 @@ export class GridModel extends HoistModel {
|
|
|
751
751
|
|
|
752
752
|
/**
|
|
753
753
|
* Select records in the grid.
|
|
754
|
-
*
|
|
755
754
|
* @param records - one or more record(s) / ID(s) to select.
|
|
756
|
-
* @param
|
|
757
|
-
* ensureVisible - true to make selection visible if it is within a
|
|
758
|
-
* collapsed node or outside of the visible scroll window. Default true.
|
|
759
|
-
* clearSelection - true to clear previous selection (rather than
|
|
760
|
-
* add to it). Default true.
|
|
755
|
+
* @param opts - additional post-selection options
|
|
761
756
|
*/
|
|
762
757
|
async selectAsync(
|
|
763
758
|
records: Some<StoreRecordOrId>,
|
|
764
|
-
opts
|
|
759
|
+
opts: {
|
|
760
|
+
/**
|
|
761
|
+
* True (default) to scroll the grid or expand nodes as needed to make selection
|
|
762
|
+
* visible if it is within a collapsed node or outside of the visible scroll window.
|
|
763
|
+
*/
|
|
764
|
+
ensureVisible?: boolean;
|
|
765
|
+
/** True (default) to clear previous selection (rather than add to it). */
|
|
766
|
+
clearSelection?: boolean;
|
|
767
|
+
} = {}
|
|
765
768
|
) {
|
|
766
|
-
const {ensureVisible = true, clearSelection = true} = opts
|
|
769
|
+
const {ensureVisible = true, clearSelection = true} = opts;
|
|
767
770
|
this.selModel.select(records, clearSelection);
|
|
768
771
|
if (ensureVisible) await this.ensureSelectionVisibleAsync();
|
|
769
772
|
}
|
|
@@ -771,19 +774,25 @@ export class GridModel extends HoistModel {
|
|
|
771
774
|
/**
|
|
772
775
|
* Select the first row in the grid.
|
|
773
776
|
*
|
|
774
|
-
* See {@link preSelectFirstAsync} for a useful variant of this method
|
|
775
|
-
*
|
|
776
|
-
*
|
|
777
|
-
*
|
|
778
|
-
* @param opts -
|
|
779
|
-
* expandParentGroups - set to true to expand nodes to allow selection when the
|
|
780
|
-
* first selectable node is in a collapsed group. Default true.
|
|
781
|
-
* ensureVisible - set to to true to scroll to the selected row if it is outside of the
|
|
782
|
-
* visible scroll window. Default true.
|
|
783
|
-
*
|
|
777
|
+
* See {@link preSelectFirstAsync} for a useful variant of this method that will leave the
|
|
778
|
+
* any pre-existing selection unchanged, which is what apps typically want when reloading an
|
|
779
|
+
* already-populated grid.
|
|
784
780
|
*/
|
|
785
|
-
async selectFirstAsync(
|
|
786
|
-
|
|
781
|
+
async selectFirstAsync(
|
|
782
|
+
opts: {
|
|
783
|
+
/**
|
|
784
|
+
* True (default) to expand nodes as needed to allow selection when the first selectable
|
|
785
|
+
* node is in a collapsed group.
|
|
786
|
+
*/
|
|
787
|
+
expandParentGroups?: boolean;
|
|
788
|
+
/**
|
|
789
|
+
* True (default) to scroll the grid or expand nodes as needed to make selection
|
|
790
|
+
* visible if it is outside of the visible scroll window.
|
|
791
|
+
*/
|
|
792
|
+
ensureVisible?: boolean;
|
|
793
|
+
} = {}
|
|
794
|
+
) {
|
|
795
|
+
const {expandParentGroups = true, ensureVisible = true} = opts;
|
|
787
796
|
await this.whenReadyAsync();
|
|
788
797
|
if (!this.isReady) return;
|
|
789
798
|
|
|
@@ -803,7 +812,6 @@ export class GridModel extends HoistModel {
|
|
|
803
812
|
|
|
804
813
|
/**
|
|
805
814
|
* Select the first row in the grid, if no other selection present.
|
|
806
|
-
*
|
|
807
815
|
* This method delegates to {@link selectFirstAsync}.
|
|
808
816
|
*/
|
|
809
817
|
async preSelectFirstAsync() {
|
package/core/types/Types.ts
CHANGED
|
@@ -34,6 +34,9 @@ export type Awaitable<T> = Promise<T> | T;
|
|
|
34
34
|
/** Convenience type for a "plain", string-keyed object holding any kind of values. */
|
|
35
35
|
export type PlainObject = Record<string, any>;
|
|
36
36
|
|
|
37
|
+
/** Convenience type to make a set of keys optional in a given type. */
|
|
38
|
+
export type SetOptional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
|
|
39
|
+
|
|
37
40
|
/**
|
|
38
41
|
* Specification for debouncing in Hoist.
|
|
39
42
|
*
|
package/data/Store.ts
CHANGED
|
@@ -763,7 +763,10 @@ export class Store extends HoistBase {
|
|
|
763
763
|
/** True if the store has changes which need to be committed. */
|
|
764
764
|
@computed
|
|
765
765
|
get isDirty(): boolean {
|
|
766
|
-
return
|
|
766
|
+
return (
|
|
767
|
+
this._current !== this._committed ||
|
|
768
|
+
(this.summaryRecords?.some(it => it.isModified) ?? false)
|
|
769
|
+
);
|
|
767
770
|
}
|
|
768
771
|
|
|
769
772
|
/** Alias for {@link Store.isDirty} */
|
package/data/cube/BucketSpec.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import {BaseRow} from './row/BaseRow';
|
|
9
|
+
import {SetOptional} from '@xh/hoist/core';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Spec to define a bucketing level within the hierarchy of data returned by a Query, as identified
|
|
@@ -14,35 +15,31 @@ import {BaseRow} from './row/BaseRow';
|
|
|
14
15
|
* spec's `bucketFn` to determine if it should yield a value for the bucket, causing the row to be
|
|
15
16
|
* nested underneath a new {@link BucketRow} created to hold all rows with that value.
|
|
16
17
|
*/
|
|
17
|
-
export
|
|
18
|
+
export class BucketSpec {
|
|
18
19
|
/** Name for the bucketing level configured by this spec - equivalent to a dimension name. */
|
|
19
20
|
name: string;
|
|
21
|
+
|
|
20
22
|
/**
|
|
21
23
|
* Function returning the bucketed value (if any) into which the given row should be placed -
|
|
22
24
|
* equivalent to a dimension value. Return null/undefined to exclude the row from bucketing.
|
|
23
25
|
*/
|
|
24
26
|
bucketFn: (row: BaseRow) => string;
|
|
27
|
+
|
|
25
28
|
/**
|
|
26
29
|
* Function returning bucket row label from the bucket value string returned by bucketFn.
|
|
27
30
|
* Defaults to using the value directly.
|
|
28
31
|
*/
|
|
29
|
-
labelFn
|
|
32
|
+
labelFn: (bucket: string) => string;
|
|
33
|
+
|
|
30
34
|
/**
|
|
31
35
|
* Fields on which the `bucketFn` depends, to ensure rows are re-bucketed if dependent field
|
|
32
36
|
* values change. If not provided or does not cover all fields potentially accessed by
|
|
33
37
|
* `bucketFn`, an incremental "data only" update that should have changed a row's bucket can
|
|
34
38
|
* fail to do so.
|
|
35
39
|
*/
|
|
36
|
-
dependentFields?: string[];
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
export class BucketSpec {
|
|
40
|
-
name: string;
|
|
41
|
-
bucketFn: (row: BaseRow) => string;
|
|
42
|
-
labelFn: (bucket: string) => string;
|
|
43
40
|
dependentFields: string[];
|
|
44
41
|
|
|
45
|
-
constructor(config:
|
|
42
|
+
constructor(config: SetOptional<BucketSpec, 'labelFn' | 'dependentFields'>) {
|
|
46
43
|
this.name = config.name;
|
|
47
44
|
this.bucketFn = config.bucketFn;
|
|
48
45
|
this.labelFn = config.labelFn ?? (b => b);
|
package/data/cube/Cube.ts
CHANGED
|
@@ -17,7 +17,7 @@ import {StoreRecord} from '../StoreRecord';
|
|
|
17
17
|
import {AggregateRow} from './row/AggregateRow';
|
|
18
18
|
import {BucketRow} from './row/BucketRow';
|
|
19
19
|
import {BaseRow} from './row/BaseRow';
|
|
20
|
-
import {BucketSpec
|
|
20
|
+
import {BucketSpec} from './BucketSpec';
|
|
21
21
|
import {defaultsDeep, isEmpty} from 'lodash';
|
|
22
22
|
|
|
23
23
|
export interface CubeConfig {
|
|
@@ -82,9 +82,9 @@ export type OmitFn = (row: AggregateRow | BucketRow) => boolean;
|
|
|
82
82
|
* aggregations and create an unwanted "Open" grouping.
|
|
83
83
|
*
|
|
84
84
|
* @param rows - the rows being checked for bucketing
|
|
85
|
-
* @returns {@link
|
|
85
|
+
* @returns {@link BucketSpec} for dynamic sub-aggregations, or null to perform no bucketing.
|
|
86
86
|
*/
|
|
87
|
-
export type BucketSpecFn = (rows: BaseRow[]) =>
|
|
87
|
+
export type BucketSpecFn = (rows: BaseRow[]) => BucketSpec;
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
90
|
* A data store that supports grouping, aggregating, and filtering data on multiple dimensions.
|
package/data/cube/Query.ts
CHANGED
|
@@ -107,7 +107,7 @@ export interface QueryConfig {
|
|
|
107
107
|
*
|
|
108
108
|
* This can be used to break selected aggregations into sub-groups dynamically, without having
|
|
109
109
|
* to define another dimension in the Cube and have it apply to all aggregations. See the
|
|
110
|
-
* {@link BucketSpecFn} type and {@link
|
|
110
|
+
* {@link BucketSpecFn} type and {@link BucketSpec} interface for additional information.
|
|
111
111
|
*
|
|
112
112
|
* Defaults to {@link Cube.bucketSpecFn}.
|
|
113
113
|
*/
|
package/data/cube/View.ts
CHANGED
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
StoreRecord,
|
|
19
19
|
StoreRecordId
|
|
20
20
|
} from '@xh/hoist/data';
|
|
21
|
-
import {BucketSpec} from '@xh/hoist/data/cube/BucketSpec';
|
|
22
21
|
import {ViewRowData} from '@xh/hoist/data/cube/ViewRowData';
|
|
23
22
|
import {action, makeObservable, observable} from '@xh/hoist/mobx';
|
|
24
23
|
import {shallowEqualArrays} from '@xh/hoist/utils/impl';
|
|
@@ -365,13 +364,9 @@ export class View extends HoistBase {
|
|
|
365
364
|
if (!query.bucketSpecFn) return rows;
|
|
366
365
|
if (!query.includeLeaves && rows[0]?.isLeaf) return rows;
|
|
367
366
|
|
|
368
|
-
const
|
|
369
|
-
if (!
|
|
367
|
+
const bucketSpec = query.bucketSpecFn(rows);
|
|
368
|
+
if (!bucketSpec) return rows;
|
|
370
369
|
|
|
371
|
-
const bucketSpec =
|
|
372
|
-
bucketSpecOrConf instanceof BucketSpec
|
|
373
|
-
? bucketSpecOrConf
|
|
374
|
-
: new BucketSpec(bucketSpecOrConf);
|
|
375
370
|
const {name: bucketName, bucketFn, dependentFields} = bucketSpec,
|
|
376
371
|
buckets: Record<string, BaseRow[]> = {},
|
|
377
372
|
ret: BaseRow[] = [];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xh/hoist",
|
|
3
|
-
"version": "78.
|
|
3
|
+
"version": "78.1.0",
|
|
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",
|
|
@@ -28,8 +28,8 @@
|
|
|
28
28
|
]
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@auth0/auth0-spa-js": "~2.
|
|
32
|
-
"@azure/msal-browser": "~4.
|
|
31
|
+
"@auth0/auth0-spa-js": "~2.9.1",
|
|
32
|
+
"@azure/msal-browser": "~4.26.2",
|
|
33
33
|
"@blueprintjs/core": "^5.10.5",
|
|
34
34
|
"@blueprintjs/datetime": "^5.3.7",
|
|
35
35
|
"@blueprintjs/datetime2": "^2.3.7",
|
|
@@ -180,8 +180,8 @@ export abstract class BaseOAuthClient<
|
|
|
180
180
|
* Request a full logout from the underlying OAuth provider.
|
|
181
181
|
*/
|
|
182
182
|
async logoutAsync(): Promise<void> {
|
|
183
|
-
await this.doLogoutAsync();
|
|
184
183
|
this.setSelectedUsername(null);
|
|
184
|
+
await this.doLogoutAsync();
|
|
185
185
|
}
|
|
186
186
|
|
|
187
187
|
/**
|