@gooddata/sdk-ui 11.53.0-alpha.0 → 11.53.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm/base/localization/bundles/en-US.localization-bundle.d.ts +8 -0
- package/esm/base/localization/bundles/en-US.localization-bundle.d.ts.map +1 -1
- package/esm/base/localization/bundles/en-US.localization-bundle.js +8 -0
- package/esm/base/react/legacy/withEntireDataView.d.ts.map +1 -1
- package/esm/base/react/legacy/withEntireDataView.js +174 -125
- package/package.json +11 -11
|
@@ -2283,6 +2283,14 @@ export declare const en_US: {
|
|
|
2283
2283
|
text: string;
|
|
2284
2284
|
crowdinContext: string;
|
|
2285
2285
|
};
|
|
2286
|
+
"parameter_filter.dropdown.search_label": {
|
|
2287
|
+
text: string;
|
|
2288
|
+
crowdinContext: string;
|
|
2289
|
+
};
|
|
2290
|
+
"parameter_filter.dropdown.default_suffix": {
|
|
2291
|
+
text: string;
|
|
2292
|
+
crowdinContext: string;
|
|
2293
|
+
};
|
|
2286
2294
|
"parameter_filter.dropdown.preview_label": {
|
|
2287
2295
|
text: string;
|
|
2288
2296
|
crowdinContext: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"en-US.localization-bundle.d.ts","sourceRoot":"","sources":["../../../../src/base/localization/bundles/en-US.localization-bundle.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK
|
|
1
|
+
{"version":3,"file":"en-US.localization-bundle.d.ts","sourceRoot":"","sources":["../../../../src/base/localization/bundles/en-US.localization-bundle.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0vJjB,CAAC"}
|
|
@@ -2285,6 +2285,14 @@ export const en_US = {
|
|
|
2285
2285
|
"text": "Reset",
|
|
2286
2286
|
"crowdinContext": "Reset link in the parameter control dropdown; reverts the value to the workspace default"
|
|
2287
2287
|
},
|
|
2288
|
+
"parameter_filter.dropdown.search_label": {
|
|
2289
|
+
"text": "Search values",
|
|
2290
|
+
"crowdinContext": "Accessible name of the search field above the list of allowed values in the parameter control dropdown"
|
|
2291
|
+
},
|
|
2292
|
+
"parameter_filter.dropdown.default_suffix": {
|
|
2293
|
+
"text": "(Default)",
|
|
2294
|
+
"crowdinContext": "Suffix shown next to an allowed value title in the parameter control dropdown. Identifies which value is the parameter default."
|
|
2295
|
+
},
|
|
2288
2296
|
"parameter_filter.dropdown.preview_label": {
|
|
2289
2297
|
"text": "Preview:",
|
|
2290
2298
|
"crowdinContext": "Preview label in the parameter control dropdown"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withEntireDataView.d.ts","sourceRoot":"","sources":["../../../../src/base/react/legacy/withEntireDataView.tsx"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"withEntireDataView.d.ts","sourceRoot":"","sources":["../../../../src/base/react/legacy/withEntireDataView.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAuB,KAAK,aAAa,EAA4C,MAAM,OAAO,CAAC;AAG1G,OAAO,EAAE,KAAK,SAAS,EAAc,MAAM,YAAY,CAAC;AAExD,OAAO,EAEH,KAAK,SAAS,EAOjB,MAAM,2BAA2B,CAAC;AAInC,OAAO,EAIH,KAAK,gBAAgB,EAIxB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,KAAK,eAAe,EAAsB,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EAAE,KAAK,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAkC/E;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IAClC;;;OAGG;IACH,SAAS,EAAE,OAAO,CAAC;IAEnB;;OAEG;IACH,QAAQ,CAAC,EAAE,SAAS,CAAC;IAErB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,gBAAgB,CAAC,QAAQ,CAAC,CAAC;IAGpC,IAAI,EAAE,SAAS,CAAC;IAEhB;;OAEG;IACH,aAAa,CAAC,cAAc,EAAE,eAAe,GAAG,IAAI,CAAC;IAErD;;OAEG;IACH,cAAc,CAAC,IAAI,EAAE,GAAG,EAAE,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvD;;OAEG;IACH,gBAAgB,IAAI,IAAI,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,uBAAuB,EAChE,cAAc,EAAE,aAAa,CAAC,CAAC,GAAG,qBAAqB,CAAC,GACzD,aAAa,CAAC,CAAC,CAAC,CAsblB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
// (C) 2019-2026 GoodData Corporation
|
|
3
|
-
import {
|
|
3
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
4
4
|
import { isEqual, omit } from "lodash-es";
|
|
5
5
|
import { injectIntl } from "react-intl";
|
|
6
6
|
import { isNoDataError, isUnexpectedResponseError, } from "@gooddata/sdk-backend-spi";
|
|
@@ -11,6 +11,23 @@ import { IntlWrapper } from "../../localization/IntlWrapper.js";
|
|
|
11
11
|
import { DataViewFacade } from "../../results/facade.js";
|
|
12
12
|
import { createExportErrorFunction, createExportFunction } from "../../vis/export.js";
|
|
13
13
|
import { getAvailableDrillTargets } from "./availableDrillTargets.js";
|
|
14
|
+
/**
|
|
15
|
+
* Applies the wrapped component's `defaultProps` the same way React did for class components: the default
|
|
16
|
+
* value is only used when the respective prop is `undefined`.
|
|
17
|
+
*/
|
|
18
|
+
function applyDefaultProps(props, defaultProps) {
|
|
19
|
+
const keys = Object.keys(defaultProps);
|
|
20
|
+
if (keys.every((key) => props[key] !== undefined)) {
|
|
21
|
+
return props;
|
|
22
|
+
}
|
|
23
|
+
const propsWithDefaults = { ...props };
|
|
24
|
+
keys.forEach((key) => {
|
|
25
|
+
if (propsWithDefaults[key] === undefined) {
|
|
26
|
+
propsWithDefaults[key] = defaultProps[key];
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return propsWithDefaults;
|
|
30
|
+
}
|
|
14
31
|
/**
|
|
15
32
|
* A HOC to wrap data visualization components with loading / error handling.
|
|
16
33
|
*
|
|
@@ -22,99 +39,81 @@ import { getAvailableDrillTargets } from "./availableDrillTargets.js";
|
|
|
22
39
|
* @internal
|
|
23
40
|
*/
|
|
24
41
|
export function withEntireDataView(InnerComponent) {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
42
|
+
const innerDefaultProps = (InnerComponent.defaultProps || {});
|
|
43
|
+
function LoadingHOCWrapped(receivedProps) {
|
|
44
|
+
const props = applyDefaultProps(receivedProps, innerDefaultProps);
|
|
45
|
+
const [state, setState] = useState({
|
|
46
|
+
isLoading: false,
|
|
47
|
+
error: null,
|
|
48
|
+
executionResult: null,
|
|
49
|
+
dataView: null,
|
|
50
|
+
});
|
|
51
|
+
// refs holding the latest props and state, so that the (possibly async) callbacks below always work
|
|
52
|
+
// with the current values - the same way `this.props` and `this.state` did
|
|
53
|
+
const latestPropsRef = useRef(props);
|
|
54
|
+
latestPropsRef.current = props;
|
|
55
|
+
const latestStateRef = useRef(state);
|
|
56
|
+
latestStateRef.current = state;
|
|
57
|
+
const hasUnmounted = useRef(false);
|
|
58
|
+
const abortController = useRef(new AbortController());
|
|
29
59
|
/**
|
|
30
60
|
* Fingerprint of the last execution definition the initialize was called with.
|
|
31
61
|
*/
|
|
32
|
-
lastInitRequestFingerprint = null;
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
};
|
|
41
|
-
this.onLoadingChanged = this.onLoadingChanged.bind(this);
|
|
42
|
-
this.onDataTooLarge = this.onDataTooLarge.bind(this);
|
|
43
|
-
this.onNegativeValues = this.onNegativeValues.bind(this);
|
|
44
|
-
this.onDataView = this.onDataView.bind(this);
|
|
45
|
-
this.abortController = new AbortController();
|
|
46
|
-
}
|
|
47
|
-
componentDidMount() {
|
|
48
|
-
void this.initDataLoading(this.props.execution, this.props.forecastConfig, this.props.outliersConfig, this.props.clusteringConfig);
|
|
49
|
-
}
|
|
50
|
-
render() {
|
|
51
|
-
const { isLoading, error, dataView, seType } = this.state;
|
|
52
|
-
const { intl } = this.props;
|
|
53
|
-
// lower-level components do not need workspace
|
|
54
|
-
const props = this.stripWorkspace(this.props);
|
|
55
|
-
return (_jsx(InnerComponent, { ...props, dataView: dataView, onDataTooLarge: this.onDataTooLarge, onNegativeValues: this.onNegativeValues, error: error, seType: seType, isLoading: isLoading, intl: intl }));
|
|
56
|
-
}
|
|
57
|
-
UNSAFE_componentWillReceiveProps(nextProps) {
|
|
58
|
-
// we need strict equality here in case only the buckets changed (not measures or attributes)
|
|
59
|
-
if (!this.props.execution.equals(nextProps.execution) ||
|
|
60
|
-
!isEqual(this.props.forecastConfig, nextProps.forecastConfig) ||
|
|
61
|
-
!isEqual(this.props.clusteringConfig, nextProps.clusteringConfig) ||
|
|
62
|
-
!isEqual(this.props.outliersConfig, nextProps.outliersConfig)) {
|
|
63
|
-
this.refreshAbortController();
|
|
64
|
-
void this.initDataLoading(nextProps.execution, nextProps.forecastConfig, nextProps.outliersConfig, nextProps.clusteringConfig);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
componentWillUnmount() {
|
|
68
|
-
this.hasUnmounted = true;
|
|
69
|
-
this.onLoadingChanged = () => { };
|
|
70
|
-
this.onDataView = () => { };
|
|
71
|
-
this.onError = () => { };
|
|
72
|
-
this.refreshAbortController();
|
|
73
|
-
}
|
|
74
|
-
refreshAbortController() {
|
|
75
|
-
if (this.props.enableExecutionCancelling) {
|
|
76
|
-
if (this.state.isLoading) {
|
|
77
|
-
this.abortController.abort();
|
|
62
|
+
const lastInitRequestFingerprint = useRef(null);
|
|
63
|
+
const updateState = useCallback((newState) => {
|
|
64
|
+
setState((s) => ({ ...s, ...newState }));
|
|
65
|
+
}, []);
|
|
66
|
+
const refreshAbortController = useCallback(() => {
|
|
67
|
+
if (latestPropsRef.current.enableExecutionCancelling) {
|
|
68
|
+
if (latestStateRef.current.isLoading) {
|
|
69
|
+
abortController.current.abort();
|
|
78
70
|
}
|
|
79
|
-
|
|
71
|
+
abortController.current = new AbortController();
|
|
80
72
|
}
|
|
81
|
-
}
|
|
82
|
-
onLoadingChanged(loadingState) {
|
|
83
|
-
|
|
84
|
-
|
|
73
|
+
}, []);
|
|
74
|
+
const onLoadingChanged = useCallback((loadingState) => {
|
|
75
|
+
if (hasUnmounted.current) {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
latestPropsRef.current.onLoadingChanged?.(loadingState);
|
|
85
79
|
const { isLoading } = loadingState;
|
|
86
|
-
const
|
|
80
|
+
const newState = { isLoading };
|
|
87
81
|
if (isLoading) {
|
|
88
|
-
|
|
82
|
+
newState.error = null;
|
|
89
83
|
}
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
onDataView(dataView) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
84
|
+
updateState(newState);
|
|
85
|
+
}, [updateState]);
|
|
86
|
+
const onDataView = useCallback((dataView) => {
|
|
87
|
+
if (hasUnmounted.current) {
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
latestPropsRef.current.onDataView?.(DataViewFacade.for(dataView));
|
|
91
|
+
}, []);
|
|
92
|
+
const onError = useCallback((error) => {
|
|
93
|
+
if (hasUnmounted.current) {
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
const { onExportReady } = latestPropsRef.current;
|
|
98
97
|
if (!isForecastNotReceived(error) && !isClusteringNotReceived(error)) {
|
|
99
98
|
const err = error;
|
|
100
|
-
|
|
99
|
+
updateState({ error: err.getMessage(), seType: err.seType, dataView: null });
|
|
101
100
|
}
|
|
102
|
-
|
|
101
|
+
onLoadingChanged({ isLoading: false });
|
|
103
102
|
if (onExportReady) {
|
|
104
103
|
onExportReady(createExportErrorFunction(error));
|
|
105
104
|
}
|
|
106
|
-
|
|
107
|
-
}
|
|
108
|
-
onDataTooLarge(_data, errorMessage) {
|
|
109
|
-
|
|
110
|
-
}
|
|
111
|
-
onNegativeValues() {
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
isRequestStale(fingerprint) {
|
|
115
|
-
return
|
|
116
|
-
}
|
|
117
|
-
|
|
105
|
+
latestPropsRef.current.onError?.(error);
|
|
106
|
+
}, [onLoadingChanged, updateState]);
|
|
107
|
+
const onDataTooLarge = useCallback((_data, errorMessage) => {
|
|
108
|
+
onError(new DataTooLargeToDisplaySdkError(errorMessage));
|
|
109
|
+
}, [onError]);
|
|
110
|
+
const onNegativeValues = useCallback(() => {
|
|
111
|
+
onError(new NegativeValuesSdkError());
|
|
112
|
+
}, [onError]);
|
|
113
|
+
const isRequestStale = useCallback((fingerprint) => {
|
|
114
|
+
return lastInitRequestFingerprint.current !== fingerprint || hasUnmounted.current;
|
|
115
|
+
}, []);
|
|
116
|
+
const loadClusteringData = useCallback(async (dataView, executionResult, clusteringConfig) => {
|
|
118
117
|
let result = dataView.withClustering(clusteringConfig);
|
|
119
118
|
try {
|
|
120
119
|
const clusteringResult = await executionResult.readClusteringAll(clusteringConfig);
|
|
@@ -131,13 +130,13 @@ export function withEntireDataView(InnerComponent) {
|
|
|
131
130
|
throw new ClusteringNotReceivedSdkError(err.responseBody?.reason || err.message || "Unknown error", err);
|
|
132
131
|
}
|
|
133
132
|
return result;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
const { pushData } =
|
|
133
|
+
}, []);
|
|
134
|
+
const loadForecastData = useCallback(async (dataView, executionResult, forecastConfig) => {
|
|
135
|
+
const { pushData } = latestPropsRef.current;
|
|
137
136
|
try {
|
|
138
137
|
const forecastResult = await executionResult.readForecastAll(dataView.forecastConfig);
|
|
139
138
|
const updatedDataView = dataView.withForecast(dataView.forecastConfig, forecastResult);
|
|
140
|
-
|
|
139
|
+
updateState({ dataView: updatedDataView });
|
|
141
140
|
if (pushData) {
|
|
142
141
|
pushData({
|
|
143
142
|
dataView: updatedDataView,
|
|
@@ -150,20 +149,20 @@ export function withEntireDataView(InnerComponent) {
|
|
|
150
149
|
}
|
|
151
150
|
catch (e) {
|
|
152
151
|
const updatedDataView = dataView.withForecast(undefined);
|
|
153
|
-
|
|
152
|
+
updateState({ dataView: updatedDataView });
|
|
154
153
|
if (pushData) {
|
|
155
154
|
pushData({ dataView: updatedDataView });
|
|
156
155
|
}
|
|
157
156
|
const err = e;
|
|
158
157
|
throw new ForecastNotReceivedSdkError(err.responseBody?.reason || err.message || "Unknown error", err);
|
|
159
158
|
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
const { pushData } =
|
|
159
|
+
}, [updateState]);
|
|
160
|
+
const loadOutliersData = useCallback(async (dataView, executionResult, _outliersConfig) => {
|
|
161
|
+
const { pushData } = latestPropsRef.current;
|
|
163
162
|
try {
|
|
164
163
|
const outliersResult = await executionResult.readOutliersAll(dataView.outliersConfig);
|
|
165
164
|
const updatedDataView = dataView.withOutliers(dataView.outliersConfig, outliersResult);
|
|
166
|
-
|
|
165
|
+
updateState({ dataView: updatedDataView });
|
|
167
166
|
if (pushData) {
|
|
168
167
|
pushData({
|
|
169
168
|
dataView: updatedDataView,
|
|
@@ -173,19 +172,19 @@ export function withEntireDataView(InnerComponent) {
|
|
|
173
172
|
}
|
|
174
173
|
catch (e) {
|
|
175
174
|
const updatedDataView = dataView.withForecast(undefined);
|
|
176
|
-
|
|
175
|
+
updateState({ dataView: updatedDataView });
|
|
177
176
|
if (pushData) {
|
|
178
177
|
pushData({ dataView: updatedDataView });
|
|
179
178
|
}
|
|
180
179
|
const err = e;
|
|
181
180
|
throw new ForecastNotReceivedSdkError(err.responseBody?.reason || err.message || "Unknown error", err);
|
|
182
181
|
}
|
|
183
|
-
}
|
|
184
|
-
handleLoadingSuccess(dataView, executionResult) {
|
|
185
|
-
const { onExportReady, pushData, exportTitle } =
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
182
|
+
}, [updateState]);
|
|
183
|
+
const handleLoadingSuccess = useCallback((dataView, executionResult) => {
|
|
184
|
+
const { onExportReady, pushData, exportTitle } = latestPropsRef.current;
|
|
185
|
+
updateState({ dataView, error: null, executionResult });
|
|
186
|
+
onLoadingChanged({ isLoading: false });
|
|
187
|
+
onDataView(dataView);
|
|
189
188
|
if (onExportReady) {
|
|
190
189
|
onExportReady(createExportFunction(dataView.result, exportTitle));
|
|
191
190
|
}
|
|
@@ -193,12 +192,12 @@ export function withEntireDataView(InnerComponent) {
|
|
|
193
192
|
const availableDrillTargets = getAvailableDrillTargets(DataViewFacade.for(dataView));
|
|
194
193
|
pushData({ dataView, availableDrillTargets });
|
|
195
194
|
}
|
|
196
|
-
}
|
|
197
|
-
handleLoadingError(error, fingerprint) {
|
|
198
|
-
if (
|
|
195
|
+
}, [onDataView, onLoadingChanged, updateState]);
|
|
196
|
+
const handleLoadingError = useCallback((error, fingerprint) => {
|
|
197
|
+
if (isRequestStale(fingerprint)) {
|
|
199
198
|
return;
|
|
200
199
|
}
|
|
201
|
-
const { pushData } =
|
|
200
|
+
const { pushData } = latestPropsRef.current;
|
|
202
201
|
/*
|
|
203
202
|
* There can be situations, where there is no data to visualize but the result / dataView contains
|
|
204
203
|
* metadata essential for setup of drilling. Look for that and if available push up.
|
|
@@ -207,21 +206,21 @@ export function withEntireDataView(InnerComponent) {
|
|
|
207
206
|
const availableDrillTargets = getAvailableDrillTargets(DataViewFacade.for(error.dataView));
|
|
208
207
|
pushData({ availableDrillTargets });
|
|
209
208
|
}
|
|
210
|
-
|
|
211
|
-
}
|
|
212
|
-
|
|
209
|
+
onError(convertError(error));
|
|
210
|
+
}, [isRequestStale, onError]);
|
|
211
|
+
const initDataLoading = useCallback(async (originalExecution, forecastConfig, outliersConfig, clusteringConfig) => {
|
|
213
212
|
let execution = originalExecution;
|
|
214
|
-
if (
|
|
215
|
-
execution = execution.withSignal(
|
|
213
|
+
if (latestPropsRef.current.enableExecutionCancelling) {
|
|
214
|
+
execution = execution.withSignal(abortController.current.signal);
|
|
216
215
|
}
|
|
217
|
-
const { pushData } =
|
|
218
|
-
|
|
219
|
-
|
|
216
|
+
const { pushData } = latestPropsRef.current;
|
|
217
|
+
onLoadingChanged({ isLoading: true });
|
|
218
|
+
updateState({ dataView: null });
|
|
220
219
|
const fingerprint = defFingerprint(execution.definition);
|
|
221
|
-
|
|
220
|
+
lastInitRequestFingerprint.current = fingerprint;
|
|
222
221
|
try {
|
|
223
222
|
const executionResult = await execution.execute();
|
|
224
|
-
if (
|
|
223
|
+
if (isRequestStale(fingerprint)) {
|
|
225
224
|
return;
|
|
226
225
|
}
|
|
227
226
|
const originalDataView = await executionResult.readAll().catch((err) => {
|
|
@@ -236,7 +235,7 @@ export function withEntireDataView(InnerComponent) {
|
|
|
236
235
|
}
|
|
237
236
|
throw err;
|
|
238
237
|
});
|
|
239
|
-
if (
|
|
238
|
+
if (isRequestStale(defFingerprint(originalDataView.definition))) {
|
|
240
239
|
/*
|
|
241
240
|
* Stop right now if the data are not relevant anymore because there was another
|
|
242
241
|
* initialize request in the meantime.
|
|
@@ -251,7 +250,7 @@ export function withEntireDataView(InnerComponent) {
|
|
|
251
250
|
dataView = dataView.withOutliers(outliersConfig);
|
|
252
251
|
}
|
|
253
252
|
if (clusteringConfig) {
|
|
254
|
-
dataView = await
|
|
253
|
+
dataView = await loadClusteringData(originalDataView, executionResult, clusteringConfig);
|
|
255
254
|
if (forecastConfig) {
|
|
256
255
|
dataView = dataView.withForecast(forecastConfig);
|
|
257
256
|
}
|
|
@@ -259,29 +258,79 @@ export function withEntireDataView(InnerComponent) {
|
|
|
259
258
|
dataView = dataView.withOutliers(outliersConfig);
|
|
260
259
|
}
|
|
261
260
|
}
|
|
262
|
-
|
|
263
|
-
if (
|
|
261
|
+
handleLoadingSuccess(dataView, executionResult);
|
|
262
|
+
if (hasUnmounted.current) {
|
|
264
263
|
return;
|
|
265
264
|
}
|
|
266
265
|
if (dataView.forecastConfig && forecastConfig) {
|
|
267
|
-
dataView = await
|
|
266
|
+
dataView = await loadForecastData(dataView, executionResult, forecastConfig);
|
|
268
267
|
}
|
|
269
268
|
if (dataView.outliersConfig && outliersConfig) {
|
|
270
|
-
await
|
|
269
|
+
await loadOutliersData(dataView, executionResult, outliersConfig);
|
|
271
270
|
}
|
|
272
271
|
}
|
|
273
272
|
catch (error) {
|
|
274
|
-
|
|
273
|
+
handleLoadingError(error, fingerprint);
|
|
275
274
|
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
|
|
275
|
+
}, [
|
|
276
|
+
handleLoadingError,
|
|
277
|
+
handleLoadingSuccess,
|
|
278
|
+
isRequestStale,
|
|
279
|
+
loadClusteringData,
|
|
280
|
+
loadForecastData,
|
|
281
|
+
loadOutliersData,
|
|
282
|
+
onLoadingChanged,
|
|
283
|
+
updateState,
|
|
284
|
+
]);
|
|
285
|
+
// componentDidMount & componentWillUnmount
|
|
286
|
+
useEffect(() => {
|
|
287
|
+
hasUnmounted.current = false;
|
|
288
|
+
void initDataLoading(props.execution, props.forecastConfig, props.outliersConfig, props.clusteringConfig);
|
|
289
|
+
return () => {
|
|
290
|
+
hasUnmounted.current = true;
|
|
291
|
+
refreshAbortController();
|
|
292
|
+
};
|
|
293
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
294
|
+
}, []);
|
|
295
|
+
// UNSAFE_componentWillReceiveProps; the props are compared with custom equality, hence the effect runs
|
|
296
|
+
// on every render and decides on its own whether the data must be loaded again
|
|
297
|
+
const isFirstEffectRunRef = useRef(true);
|
|
298
|
+
const prevRef = useRef({
|
|
299
|
+
execution: props.execution,
|
|
300
|
+
forecastConfig: props.forecastConfig,
|
|
301
|
+
outliersConfig: props.outliersConfig,
|
|
302
|
+
clusteringConfig: props.clusteringConfig,
|
|
303
|
+
});
|
|
304
|
+
useEffect(() => {
|
|
305
|
+
const { execution, forecastConfig, outliersConfig, clusteringConfig } = props;
|
|
306
|
+
if (isFirstEffectRunRef.current) {
|
|
307
|
+
// the mount effect above has already started the initial load
|
|
308
|
+
isFirstEffectRunRef.current = false;
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const prev = prevRef.current;
|
|
312
|
+
prevRef.current = { execution, forecastConfig, outliersConfig, clusteringConfig };
|
|
313
|
+
// we need strict equality here in case only the buckets changed (not measures or attributes)
|
|
314
|
+
if (!prev.execution.equals(execution) ||
|
|
315
|
+
!isEqual(prev.forecastConfig, forecastConfig) ||
|
|
316
|
+
!isEqual(prev.clusteringConfig, clusteringConfig) ||
|
|
317
|
+
!isEqual(prev.outliersConfig, outliersConfig)) {
|
|
318
|
+
refreshAbortController();
|
|
319
|
+
void initDataLoading(execution, forecastConfig, outliersConfig, clusteringConfig);
|
|
320
|
+
}
|
|
321
|
+
});
|
|
322
|
+
const stripWorkspace = (allProps) => {
|
|
323
|
+
return omit(allProps, ["workspace"]);
|
|
279
324
|
};
|
|
325
|
+
const { isLoading, error, dataView, seType } = state;
|
|
326
|
+
const { intl } = props;
|
|
327
|
+
// lower-level components do not need workspace
|
|
328
|
+
const innerProps = stripWorkspace(props);
|
|
329
|
+
return (_jsx(InnerComponent, { ...innerProps, dataView: dataView, onDataTooLarge: onDataTooLarge, onNegativeValues: onNegativeValues, error: error, seType: seType, isLoading: isLoading, intl: intl }));
|
|
280
330
|
}
|
|
281
331
|
const IntlLoadingHOC = injectIntl(LoadingHOCWrapped);
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
};
|
|
332
|
+
function LoadingHOC(props) {
|
|
333
|
+
return (_jsx(IntlWrapper, { locale: props.locale, children: _jsx(IntlLoadingHOC, { ...props }) }));
|
|
334
|
+
}
|
|
335
|
+
return LoadingHOC;
|
|
287
336
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui",
|
|
3
|
-
"version": "11.53.0-alpha.
|
|
3
|
+
"version": "11.53.0-alpha.2",
|
|
4
4
|
"description": "GoodData.UI SDK - Core",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"ts-invariant": "0.10.3",
|
|
43
43
|
"tslib": "2.8.1",
|
|
44
44
|
"uuid": "11.1.1",
|
|
45
|
-
"@gooddata/sdk-backend-spi": "11.53.0-alpha.
|
|
46
|
-
"@gooddata/sdk-model": "11.53.0-alpha.
|
|
47
|
-
"@gooddata/util": "11.53.0-alpha.
|
|
45
|
+
"@gooddata/sdk-backend-spi": "11.53.0-alpha.2",
|
|
46
|
+
"@gooddata/sdk-model": "11.53.0-alpha.2",
|
|
47
|
+
"@gooddata/util": "11.53.0-alpha.2"
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -87,13 +87,13 @@
|
|
|
87
87
|
"typescript": "5.9.3",
|
|
88
88
|
"vitest": "4.1.8",
|
|
89
89
|
"vitest-dom": "0.1.1",
|
|
90
|
-
"@gooddata/
|
|
91
|
-
"@gooddata/
|
|
92
|
-
"@gooddata/
|
|
93
|
-
"@gooddata/
|
|
94
|
-
"@gooddata/sdk-backend-
|
|
95
|
-
"@gooddata/
|
|
96
|
-
"@gooddata/stylelint-config": "11.53.0-alpha.
|
|
90
|
+
"@gooddata/eslint-config": "11.53.0-alpha.2",
|
|
91
|
+
"@gooddata/i18n-toolkit": "11.53.0-alpha.2",
|
|
92
|
+
"@gooddata/oxlint-config": "11.53.0-alpha.2",
|
|
93
|
+
"@gooddata/sdk-backend-base": "11.53.0-alpha.2",
|
|
94
|
+
"@gooddata/sdk-backend-mockingbird": "11.53.0-alpha.2",
|
|
95
|
+
"@gooddata/reference-workspace": "11.53.0-alpha.2",
|
|
96
|
+
"@gooddata/stylelint-config": "11.53.0-alpha.2"
|
|
97
97
|
},
|
|
98
98
|
"peerDependencies": {
|
|
99
99
|
"react": "^18.0.0 || ^19.0.0",
|