ropegeo-common 1.12.9 → 1.12.11
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/README.md +3 -3
- package/dist/components/RopeGeoCursorPaginationHttpRequest.d.ts +18 -3
- package/dist/components/RopeGeoCursorPaginationHttpRequest.d.ts.map +1 -1
- package/dist/components/RopeGeoCursorPaginationHttpRequest.js +73 -14
- package/dist/components/RopeGeoHttpRequest.d.ts +17 -3
- package/dist/components/RopeGeoHttpRequest.d.ts.map +1 -1
- package/dist/components/RopeGeoHttpRequest.js +55 -3
- package/dist/components/RopeGeoPaginationHttpRequest.d.ts +17 -2
- package/dist/components/RopeGeoPaginationHttpRequest.d.ts.map +1 -1
- package/dist/components/RopeGeoPaginationHttpRequest.js +58 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -312,9 +312,9 @@ Abstract classes live under `minimap/abstract/`, concrete under `minimap/concret
|
|
|
312
312
|
|
|
313
313
|
| Name | Description | Import |
|
|
314
314
|
| --- | --- | --- |
|
|
315
|
-
| `RopeGeoHttpRequest` | Single GET/POST wrapper; parses `Result.fromResponseBody`; optional `timeoutAfterSeconds`
|
|
316
|
-
| `RopeGeoCursorPaginationHttpRequest` | Cursor-paginated fetch with `loadMore`;
|
|
317
|
-
| `RopeGeoPaginationHttpRequest<T>` | Page-based fetch;
|
|
315
|
+
| `RopeGeoHttpRequest` | Single GET/POST wrapper; parses `Result.fromResponseBody`; optional `timeoutAfterSeconds`, `isOnline`, `refreshOnReconnect`, `timeoutCountdown`, and `refreshing` (stale-while-revalidate) children args. | `import { RopeGeoHttpRequest, Method, Service } from 'ropegeo-common/components'` |
|
|
316
|
+
| `RopeGeoCursorPaginationHttpRequest` | Cursor-paginated fetch with `loadMore`; `data` is `T[] \| null` (null until first success); optional `timeoutAfterSeconds`, `isOnline`, `refreshOnReconnect`, `refreshing`, `timeoutCountdown`. | `import { RopeGeoCursorPaginationHttpRequest } from 'ropegeo-common/components'` |
|
|
317
|
+
| `RopeGeoPaginationHttpRequest<T>` | Page-based fetch; concatenates `results` into `data` (`T[]` when complete, otherwise `null` with `errors`); optional `isOnline`, `refreshOnReconnect`, `refreshing`, `timeoutCountdown`. | `import { RopeGeoPaginationHttpRequest } from 'ropegeo-common/components'` |
|
|
318
318
|
|
|
319
319
|
---
|
|
320
320
|
|
|
@@ -14,22 +14,37 @@ export type RopeGeoCursorPaginationHttpRequestProps<T = unknown> = {
|
|
|
14
14
|
timeoutAfterSeconds?: number;
|
|
15
15
|
/**
|
|
16
16
|
* When `false`, no HTTP requests run and children receive {@link NO_NETWORK_MESSAGE} as the error.
|
|
17
|
-
*
|
|
17
|
+
* Previously loaded `data` and cursor `params` are kept until the network returns.
|
|
18
18
|
*/
|
|
19
19
|
isOnline?: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* When `isOnline` goes from `false` to online and there is already successful data for the same
|
|
22
|
+
* request (only the soft {@link NO_NETWORK_MESSAGE} error), a new fetch runs only if this is
|
|
23
|
+
* `true`. Otherwise stale data stays visible and `errors` is cleared. When there is no
|
|
24
|
+
* successful data yet, or the last error was not the offline placeholder, a fetch always runs.
|
|
25
|
+
* @default false
|
|
26
|
+
*/
|
|
27
|
+
refreshOnReconnect?: boolean;
|
|
20
28
|
/**
|
|
21
29
|
* Response body is parsed via CursorPaginationResults.fromResponseBody (must include resultType).
|
|
22
30
|
* Parsed shape is ValidatedCursorPaginationResponse; children receive result.results as data.
|
|
31
|
+
* `data` is `null` until the first successful response for the current request identity, then an
|
|
32
|
+
* array (possibly empty) for loaded pages.
|
|
23
33
|
*/
|
|
24
34
|
children: (args: {
|
|
25
35
|
loading: boolean;
|
|
26
36
|
loadingMore: boolean;
|
|
27
|
-
|
|
37
|
+
/**
|
|
38
|
+
* `true` while the initial request is in flight after at least one successful response for the
|
|
39
|
+
* current request identity (stale-while-revalidate). Not used for `loadMore` alone.
|
|
40
|
+
*/
|
|
41
|
+
refreshing: boolean;
|
|
42
|
+
data: T[] | null;
|
|
28
43
|
errors: Error | null;
|
|
29
44
|
loadMore: () => void;
|
|
30
45
|
hasMore: boolean;
|
|
31
46
|
timeoutCountdown: number | null;
|
|
32
47
|
}) => ReactNode;
|
|
33
48
|
};
|
|
34
|
-
export declare function RopeGeoCursorPaginationHttpRequest<T = unknown>({ service, method, path, pathParams, queryParams, timeoutAfterSeconds, isOnline, children, }: RopeGeoCursorPaginationHttpRequestProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
49
|
+
export declare function RopeGeoCursorPaginationHttpRequest<T = unknown>({ service, method, path, pathParams, queryParams, timeoutAfterSeconds, isOnline, refreshOnReconnect, children, }: RopeGeoCursorPaginationHttpRequestProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
35
50
|
//# sourceMappingURL=RopeGeoCursorPaginationHttpRequest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopeGeoCursorPaginationHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoCursorPaginationHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AASvC,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAoB,MAAM,sBAAsB,CAAC;AAsCzE,MAAM,MAAM,uCAAuC,CAAC,CAAC,GAAG,OAAO,IAAI;IACjE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,sBAAsB,CAAC;IACpC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB
|
|
1
|
+
{"version":3,"file":"RopeGeoCursorPaginationHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoCursorPaginationHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AASvC,OAAO,EACL,KAAK,sBAAsB,EAE5B,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAoB,MAAM,sBAAsB,CAAC;AAsCzE,MAAM,MAAM,uCAAuC,CAAC,CAAC,GAAG,OAAO,IAAI;IACjE,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,sBAAsB,CAAC;IACpC;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;OAGG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,OAAO,CAAC;QACjB,WAAW,EAAE,OAAO,CAAC;QACrB;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC;QACrB,QAAQ,EAAE,MAAM,IAAI,CAAC;QACrB,OAAO,EAAE,OAAO,CAAC;QACjB,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;KACjC,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF,wBAAgB,kCAAkC,CAAC,CAAC,GAAG,OAAO,EAAE,EAC9D,OAAO,EACP,MAAmB,EACnB,IAAI,EACJ,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,QAAQ,EACR,kBAA0B,EAC1B,QAAQ,GACT,EAAE,uCAAuC,CAAC,CAAC,CAAC,2CA6U5C"}
|
|
@@ -30,16 +30,26 @@ function getResponseBody(raw) {
|
|
|
30
30
|
}
|
|
31
31
|
return raw;
|
|
32
32
|
}
|
|
33
|
-
function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.Method.GET, path, pathParams, queryParams, timeoutAfterSeconds, isOnline, children, }) {
|
|
33
|
+
function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.Method.GET, path, pathParams, queryParams, timeoutAfterSeconds, isOnline, refreshOnReconnect = false, children, }) {
|
|
34
34
|
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
35
35
|
const [loadingMore, setLoadingMore] = (0, react_1.useState)(false);
|
|
36
|
-
const [data, setData] = (0, react_1.useState)(
|
|
36
|
+
const [data, setData] = (0, react_1.useState)(null);
|
|
37
37
|
const [params, setParams] = (0, react_1.useState)(queryParams);
|
|
38
38
|
const [errors, setErrors] = (0, react_1.useState)(null);
|
|
39
39
|
const [timeoutCountdown, setTimeoutCountdown] = (0, react_1.useState)(null);
|
|
40
|
+
const [hasCommittedOnce, setHasCommittedOnce] = (0, react_1.useState)(false);
|
|
41
|
+
const errorsRef = (0, react_1.useRef)(errors);
|
|
42
|
+
const hasCommittedRef = (0, react_1.useRef)(hasCommittedOnce);
|
|
43
|
+
errorsRef.current = errors;
|
|
44
|
+
hasCommittedRef.current = hasCommittedOnce;
|
|
40
45
|
const loadingMoreRef = (0, react_1.useRef)(false);
|
|
41
46
|
const loadMoreAbortRef = (0, react_1.useRef)(null);
|
|
42
47
|
const hasMore = params.cursor != null;
|
|
48
|
+
const pathParamsKey = JSON.stringify(pathParams ?? null);
|
|
49
|
+
const queryKey = queryParams.toQueryString();
|
|
50
|
+
const requestKey = (0, react_1.useMemo)(() => `${service}|${method}|${path}|${pathParamsKey}|${queryKey}|${timeoutAfterSeconds ?? ""}`, [service, method, path, pathParamsKey, queryKey, timeoutAfterSeconds]);
|
|
51
|
+
const prevIsOnlineRef = (0, react_1.useRef)(undefined);
|
|
52
|
+
const lastRequestKeyRef = (0, react_1.useRef)("");
|
|
43
53
|
const buildUrl = (0, react_1.useCallback)((p) => {
|
|
44
54
|
const baseUrl = RopeGeoHttpRequest_1.SERVICE_BASE_URL[service];
|
|
45
55
|
const resolvedPath = resolvePath(path, pathParams);
|
|
@@ -48,24 +58,61 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
|
|
|
48
58
|
return new URL(fullPath, baseUrl).toString();
|
|
49
59
|
}, [service, path, pathParams]);
|
|
50
60
|
(0, react_1.useEffect)(() => {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
61
|
+
const online = isOnline !== false;
|
|
62
|
+
const prevOnline = prevIsOnlineRef.current;
|
|
63
|
+
const reconnecting = prevOnline === false && online;
|
|
64
|
+
const keyChanged = lastRequestKeyRef.current !== requestKey;
|
|
65
|
+
if (!online) {
|
|
66
|
+
if (keyChanged) {
|
|
67
|
+
lastRequestKeyRef.current = requestKey;
|
|
68
|
+
setData(null);
|
|
69
|
+
setHasCommittedOnce(false);
|
|
70
|
+
setParams(queryParams);
|
|
71
|
+
setErrors(null);
|
|
72
|
+
}
|
|
73
|
+
loadMoreAbortRef.current?.abort();
|
|
74
|
+
loadMoreAbortRef.current = null;
|
|
75
|
+
loadingMoreRef.current = false;
|
|
76
|
+
setLoadingMore(false);
|
|
77
|
+
prevIsOnlineRef.current = false;
|
|
54
78
|
setLoading(false);
|
|
55
79
|
setErrors(new Error(network_1.NO_NETWORK_MESSAGE));
|
|
56
80
|
setTimeoutCountdown(null);
|
|
57
81
|
return;
|
|
58
82
|
}
|
|
83
|
+
if (keyChanged) {
|
|
84
|
+
lastRequestKeyRef.current = requestKey;
|
|
85
|
+
setHasCommittedOnce(false);
|
|
86
|
+
setData(null);
|
|
87
|
+
setParams(queryParams);
|
|
88
|
+
setErrors(null);
|
|
89
|
+
}
|
|
90
|
+
if (!keyChanged && reconnecting) {
|
|
91
|
+
const onlyNoNetwork = errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE;
|
|
92
|
+
if (hasCommittedRef.current && onlyNoNetwork && !refreshOnReconnect) {
|
|
93
|
+
setErrors(null);
|
|
94
|
+
setLoading(false);
|
|
95
|
+
prevIsOnlineRef.current = true;
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
prevIsOnlineRef.current = true;
|
|
59
100
|
let cancelled = false;
|
|
60
101
|
const abortController = new AbortController();
|
|
61
102
|
const timedOutRef = { current: false };
|
|
62
103
|
const requestStartedAt = Date.now();
|
|
63
104
|
const timeoutMs = (0, network_1.resolveRequestTimeoutMs)(timeoutAfterSeconds);
|
|
64
|
-
setData([]);
|
|
65
|
-
setParams(queryParams);
|
|
66
105
|
setLoading(true);
|
|
67
106
|
setErrors(null);
|
|
68
107
|
setTimeoutCountdown(null);
|
|
108
|
+
const keepStaleDuringFetch = reconnecting &&
|
|
109
|
+
hasCommittedRef.current &&
|
|
110
|
+
errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE &&
|
|
111
|
+
refreshOnReconnect;
|
|
112
|
+
if (!keyChanged && !keepStaleDuringFetch) {
|
|
113
|
+
setData(null);
|
|
114
|
+
setParams(queryParams);
|
|
115
|
+
}
|
|
69
116
|
const policyDispose = timeoutMs == null
|
|
70
117
|
? () => { }
|
|
71
118
|
: (0, network_1.installNetworkRequestPolicyTimers)(requestStartedAt, timeoutMs, {
|
|
@@ -96,11 +143,15 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
|
|
|
96
143
|
const text = await res.text();
|
|
97
144
|
if (!res.ok) {
|
|
98
145
|
setErrors(new Error(`HTTP ${res.status}: ${text || res.statusText}`));
|
|
99
|
-
setData(
|
|
146
|
+
setData(null);
|
|
147
|
+
setHasCommittedOnce(false);
|
|
100
148
|
return;
|
|
101
149
|
}
|
|
102
150
|
if (text.length === 0) {
|
|
103
151
|
setData([]);
|
|
152
|
+
setParams(queryParams.withCursor(null));
|
|
153
|
+
setErrors(null);
|
|
154
|
+
setHasCommittedOnce(true);
|
|
104
155
|
return;
|
|
105
156
|
}
|
|
106
157
|
try {
|
|
@@ -113,6 +164,7 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
|
|
|
113
164
|
setData(results);
|
|
114
165
|
setParams(queryParams.withCursor(nextCursor));
|
|
115
166
|
setErrors(null);
|
|
167
|
+
setHasCommittedOnce(true);
|
|
116
168
|
}
|
|
117
169
|
catch (parseError) {
|
|
118
170
|
if (!cancelled) {
|
|
@@ -123,7 +175,8 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
|
|
|
123
175
|
parseError: parseError instanceof Error ? parseError.message : String(parseError),
|
|
124
176
|
});
|
|
125
177
|
setErrors(new Error("Invalid JSON response"));
|
|
126
|
-
setData(
|
|
178
|
+
setData(null);
|
|
179
|
+
setHasCommittedOnce(false);
|
|
127
180
|
}
|
|
128
181
|
}
|
|
129
182
|
})
|
|
@@ -132,7 +185,8 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
|
|
|
132
185
|
return;
|
|
133
186
|
if (timedOutRef.current) {
|
|
134
187
|
setErrors(new Error(network_1.NETWORK_REQUEST_TIMED_OUT_MESSAGE));
|
|
135
|
-
setData(
|
|
188
|
+
setData(null);
|
|
189
|
+
setHasCommittedOnce(false);
|
|
136
190
|
return;
|
|
137
191
|
}
|
|
138
192
|
if ((0, network_1.isAbortError)(err))
|
|
@@ -142,7 +196,8 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
|
|
|
142
196
|
error: err instanceof Error ? err.message : String(err),
|
|
143
197
|
});
|
|
144
198
|
setErrors(err instanceof Error ? err : new Error(String(err)));
|
|
145
|
-
setData(
|
|
199
|
+
setData(null);
|
|
200
|
+
setHasCommittedOnce(false);
|
|
146
201
|
})
|
|
147
202
|
.finally(() => {
|
|
148
203
|
policyDispose();
|
|
@@ -160,11 +215,13 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
|
|
|
160
215
|
service,
|
|
161
216
|
method,
|
|
162
217
|
path,
|
|
163
|
-
|
|
164
|
-
|
|
218
|
+
pathParamsKey,
|
|
219
|
+
queryKey,
|
|
165
220
|
buildUrl,
|
|
166
221
|
timeoutAfterSeconds,
|
|
167
222
|
isOnline,
|
|
223
|
+
refreshOnReconnect,
|
|
224
|
+
requestKey,
|
|
168
225
|
]);
|
|
169
226
|
(0, react_1.useEffect)(() => {
|
|
170
227
|
return () => {
|
|
@@ -222,7 +279,7 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
|
|
|
222
279
|
const body = getResponseBody(raw);
|
|
223
280
|
const result = models_1.CursorPaginationResults.fromResponseBody(body);
|
|
224
281
|
const { results, nextCursor } = result;
|
|
225
|
-
setData((prev) => [...prev, ...results]);
|
|
282
|
+
setData((prev) => [...(prev ?? []), ...results]);
|
|
226
283
|
setParams((p) => p.withCursor(nextCursor));
|
|
227
284
|
}
|
|
228
285
|
catch (parseError) {
|
|
@@ -258,9 +315,11 @@ function RopeGeoCursorPaginationHttpRequest({ service, method = RopeGeoHttpReque
|
|
|
258
315
|
setLoadingMore(false);
|
|
259
316
|
});
|
|
260
317
|
}, [params, method, buildUrl, timeoutAfterSeconds, isOnline]);
|
|
318
|
+
const refreshing = loading && hasCommittedOnce;
|
|
261
319
|
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children({
|
|
262
320
|
loading,
|
|
263
321
|
loadingMore,
|
|
322
|
+
refreshing,
|
|
264
323
|
data,
|
|
265
324
|
errors,
|
|
266
325
|
loadMore,
|
|
@@ -24,16 +24,30 @@ export type RopeGeoHttpRequestProps<T = unknown> = {
|
|
|
24
24
|
timeoutAfterSeconds?: number;
|
|
25
25
|
/**
|
|
26
26
|
* When `false`, the request is not started and children receive {@link NO_NETWORK_MESSAGE} as the
|
|
27
|
-
* error.
|
|
28
|
-
* `expo-network`) so fetches are
|
|
27
|
+
* error. Previously loaded `data` is kept until the network returns. When `true` or omitted,
|
|
28
|
+
* behavior is unchanged. Pass from app-level connectivity (e.g. `expo-network`) so fetches are
|
|
29
|
+
* not fired while offline.
|
|
29
30
|
*/
|
|
30
31
|
isOnline?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* When `isOnline` goes from `false` to online and there is already successful data for the same
|
|
34
|
+
* request (only the soft {@link NO_NETWORK_MESSAGE} error), a new fetch runs only if this is
|
|
35
|
+
* `true`. Otherwise stale data stays visible and `errors` is cleared. When there is no
|
|
36
|
+
* successful data yet, or the last error was not the offline placeholder, a fetch always runs.
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
refreshOnReconnect?: boolean;
|
|
31
40
|
/**
|
|
32
41
|
* Response body is parsed via Result.fromResponseBody (must include resultType and result).
|
|
33
42
|
* Children receive the validated result.result as data (typed by T).
|
|
34
43
|
*/
|
|
35
44
|
children: (args: {
|
|
36
45
|
loading: boolean;
|
|
46
|
+
/**
|
|
47
|
+
* `true` while a request is in flight after at least one successful response for the current
|
|
48
|
+
* request identity (stale-while-revalidate).
|
|
49
|
+
*/
|
|
50
|
+
refreshing: boolean;
|
|
37
51
|
data: T | null;
|
|
38
52
|
errors: Error | null;
|
|
39
53
|
/**
|
|
@@ -44,5 +58,5 @@ export type RopeGeoHttpRequestProps<T = unknown> = {
|
|
|
44
58
|
timeoutCountdown: number | null;
|
|
45
59
|
}) => ReactNode;
|
|
46
60
|
};
|
|
47
|
-
export declare function RopeGeoHttpRequest<T = unknown>({ service, method, path, pathParams, queryParams, body, timeoutAfterSeconds, isOnline, children, }: RopeGeoHttpRequestProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
61
|
+
export declare function RopeGeoHttpRequest<T = unknown>({ service, method, path, pathParams, queryParams, body, timeoutAfterSeconds, isOnline, refreshOnReconnect, children, }: RopeGeoHttpRequestProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
48
62
|
//# sourceMappingURL=RopeGeoHttpRequest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopeGeoHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWvC,eAAO,MAAM,OAAO;;CAEV,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAE7D,eAAO,MAAM,MAAM;;;;;CAKT,CAAC;AACX,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;AAE1D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAEpD,CAAC;AAmCF,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,OAAO,IAAI;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B
|
|
1
|
+
{"version":3,"file":"RopeGeoHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAWvC,eAAO,MAAM,OAAO;;CAEV,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,OAAO,CAAC,CAAC,MAAM,OAAO,OAAO,CAAC,CAAC;AAE7D,eAAO,MAAM,MAAM;;;;;CAKT,CAAC;AACX,MAAM,MAAM,MAAM,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;AAE1D,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,OAAO,EAAE,MAAM,CAEpD,CAAC;AAmCF,MAAM,MAAM,uBAAuB,CAAC,CAAC,GAAG,OAAO,IAAI;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAAC,CAAC;IACpE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;OAGG;IACH,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,OAAO,CAAC;QACjB;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;QACf,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC;QACrB;;;;WAIG;QACH,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;KACjC,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,OAAO,EAAE,EAC9C,OAAO,EACP,MAAM,EACN,IAAI,EACJ,UAAU,EACV,WAAW,EACX,IAAI,EACJ,mBAAmB,EACnB,QAAQ,EACR,kBAA0B,EAC1B,QAAQ,GACT,EAAE,uBAAuB,CAAC,CAAC,CAAC,2CA0N5B"}
|
|
@@ -40,11 +40,16 @@ function buildUrl(baseUrl, path, pathParams, queryParams) {
|
|
|
40
40
|
}
|
|
41
41
|
return url.toString();
|
|
42
42
|
}
|
|
43
|
-
function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, body, timeoutAfterSeconds, isOnline, children, }) {
|
|
43
|
+
function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, body, timeoutAfterSeconds, isOnline, refreshOnReconnect = false, children, }) {
|
|
44
44
|
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
45
45
|
const [data, setData] = (0, react_1.useState)(null);
|
|
46
46
|
const [errors, setErrors] = (0, react_1.useState)(null);
|
|
47
47
|
const [timeoutCountdown, setTimeoutCountdown] = (0, react_1.useState)(null);
|
|
48
|
+
const [hasCommittedOnce, setHasCommittedOnce] = (0, react_1.useState)(false);
|
|
49
|
+
const errorsRef = (0, react_1.useRef)(errors);
|
|
50
|
+
const hasCommittedRef = (0, react_1.useRef)(hasCommittedOnce);
|
|
51
|
+
errorsRef.current = errors;
|
|
52
|
+
hasCommittedRef.current = hasCommittedOnce;
|
|
48
53
|
const pathParamsKey = JSON.stringify(pathParams ?? null);
|
|
49
54
|
const queryParamsKey = JSON.stringify(queryParams ?? null);
|
|
50
55
|
const bodyKey = body === undefined || body === null
|
|
@@ -52,14 +57,43 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
|
|
|
52
57
|
: typeof body === "object"
|
|
53
58
|
? JSON.stringify(body)
|
|
54
59
|
: body;
|
|
60
|
+
const requestKey = (0, react_1.useMemo)(() => `${service}|${method}|${path}|${pathParamsKey}|${queryParamsKey}|${String(bodyKey)}|${timeoutAfterSeconds ?? ""}`, [service, method, path, pathParamsKey, queryParamsKey, bodyKey, timeoutAfterSeconds]);
|
|
61
|
+
const prevIsOnlineRef = (0, react_1.useRef)(undefined);
|
|
62
|
+
const lastRequestKeyRef = (0, react_1.useRef)("");
|
|
55
63
|
(0, react_1.useEffect)(() => {
|
|
56
|
-
|
|
64
|
+
const online = isOnline !== false;
|
|
65
|
+
const prevOnline = prevIsOnlineRef.current;
|
|
66
|
+
const reconnecting = prevOnline === false && online;
|
|
67
|
+
const keyChanged = lastRequestKeyRef.current !== requestKey;
|
|
68
|
+
if (!online) {
|
|
69
|
+
if (keyChanged) {
|
|
70
|
+
lastRequestKeyRef.current = requestKey;
|
|
71
|
+
setData(null);
|
|
72
|
+
setHasCommittedOnce(false);
|
|
73
|
+
setErrors(null);
|
|
74
|
+
}
|
|
75
|
+
prevIsOnlineRef.current = false;
|
|
57
76
|
setLoading(false);
|
|
58
|
-
setData(null);
|
|
59
77
|
setErrors(new Error(network_1.NO_NETWORK_MESSAGE));
|
|
60
78
|
setTimeoutCountdown(null);
|
|
61
79
|
return;
|
|
62
80
|
}
|
|
81
|
+
if (keyChanged) {
|
|
82
|
+
lastRequestKeyRef.current = requestKey;
|
|
83
|
+
setHasCommittedOnce(false);
|
|
84
|
+
setData(null);
|
|
85
|
+
setErrors(null);
|
|
86
|
+
}
|
|
87
|
+
if (!keyChanged && reconnecting) {
|
|
88
|
+
const onlyNoNetwork = errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE;
|
|
89
|
+
if (hasCommittedRef.current && onlyNoNetwork && !refreshOnReconnect) {
|
|
90
|
+
setErrors(null);
|
|
91
|
+
setLoading(false);
|
|
92
|
+
prevIsOnlineRef.current = true;
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
prevIsOnlineRef.current = true;
|
|
63
97
|
let cancelled = false;
|
|
64
98
|
const abortController = new AbortController();
|
|
65
99
|
const timedOutRef = { current: false };
|
|
@@ -68,6 +102,13 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
|
|
|
68
102
|
setLoading(true);
|
|
69
103
|
setErrors(null);
|
|
70
104
|
setTimeoutCountdown(null);
|
|
105
|
+
const keepStaleDuringFetch = reconnecting &&
|
|
106
|
+
hasCommittedRef.current &&
|
|
107
|
+
errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE &&
|
|
108
|
+
refreshOnReconnect;
|
|
109
|
+
if (!keyChanged && !keepStaleDuringFetch) {
|
|
110
|
+
setData(null);
|
|
111
|
+
}
|
|
71
112
|
const policyDispose = timeoutMs == null
|
|
72
113
|
? () => { }
|
|
73
114
|
: (0, network_1.installNetworkRequestPolicyTimers)(requestStartedAt, timeoutMs, {
|
|
@@ -105,10 +146,13 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
|
|
|
105
146
|
if (!res.ok) {
|
|
106
147
|
setErrors(new Error(`HTTP ${res.status}: ${text || res.statusText}`));
|
|
107
148
|
setData(null);
|
|
149
|
+
setHasCommittedOnce(false);
|
|
108
150
|
return;
|
|
109
151
|
}
|
|
110
152
|
if (text.length === 0) {
|
|
111
153
|
setData(null);
|
|
154
|
+
setErrors(null);
|
|
155
|
+
setHasCommittedOnce(true);
|
|
112
156
|
return;
|
|
113
157
|
}
|
|
114
158
|
try {
|
|
@@ -117,6 +161,7 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
|
|
|
117
161
|
if (!cancelled) {
|
|
118
162
|
setData(parsed.result);
|
|
119
163
|
setErrors(null);
|
|
164
|
+
setHasCommittedOnce(true);
|
|
120
165
|
}
|
|
121
166
|
}
|
|
122
167
|
catch (parseError) {
|
|
@@ -129,6 +174,7 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
|
|
|
129
174
|
});
|
|
130
175
|
setErrors(parseError instanceof Error ? parseError : new Error("Invalid JSON response"));
|
|
131
176
|
setData(null);
|
|
177
|
+
setHasCommittedOnce(false);
|
|
132
178
|
}
|
|
133
179
|
}
|
|
134
180
|
})
|
|
@@ -138,6 +184,7 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
|
|
|
138
184
|
if (timedOutRef.current) {
|
|
139
185
|
setErrors(new Error(network_1.NETWORK_REQUEST_TIMED_OUT_MESSAGE));
|
|
140
186
|
setData(null);
|
|
187
|
+
setHasCommittedOnce(false);
|
|
141
188
|
return;
|
|
142
189
|
}
|
|
143
190
|
if ((0, network_1.isAbortError)(err))
|
|
@@ -148,6 +195,7 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
|
|
|
148
195
|
});
|
|
149
196
|
setErrors(err instanceof Error ? err : new Error(String(err)));
|
|
150
197
|
setData(null);
|
|
198
|
+
setHasCommittedOnce(false);
|
|
151
199
|
})
|
|
152
200
|
.finally(() => {
|
|
153
201
|
policyDispose();
|
|
@@ -170,9 +218,13 @@ function RopeGeoHttpRequest({ service, method, path, pathParams, queryParams, bo
|
|
|
170
218
|
bodyKey,
|
|
171
219
|
timeoutAfterSeconds,
|
|
172
220
|
isOnline,
|
|
221
|
+
refreshOnReconnect,
|
|
222
|
+
requestKey,
|
|
173
223
|
]);
|
|
224
|
+
const refreshing = loading && hasCommittedOnce;
|
|
174
225
|
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children({
|
|
175
226
|
loading,
|
|
227
|
+
refreshing,
|
|
176
228
|
data,
|
|
177
229
|
errors,
|
|
178
230
|
timeoutCountdown,
|
|
@@ -20,11 +20,26 @@ export type RopeGeoPaginationHttpRequestProps<T = unknown> = {
|
|
|
20
20
|
timeoutAfterSeconds?: number;
|
|
21
21
|
/**
|
|
22
22
|
* When `false`, no HTTP requests run and children receive {@link NO_NETWORK_MESSAGE} as the error.
|
|
23
|
-
*
|
|
23
|
+
* Previously loaded `data`, `received`, and `total` are kept so UIs can stay on stale results until
|
|
24
|
+
* the network returns. Same semantics as `isOnline` on {@link RopeGeoHttpRequest} and
|
|
25
|
+
* {@link RopeGeoCursorPaginationHttpRequest}.
|
|
24
26
|
*/
|
|
25
27
|
isOnline?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* When `isOnline` goes from `false` to online and there is already successful data for the same
|
|
30
|
+
* request (only the soft {@link NO_NETWORK_MESSAGE} error), a new fetch runs only if this is
|
|
31
|
+
* `true`. Otherwise stale data stays visible and `errors` is cleared. When there is no
|
|
32
|
+
* successful data yet, or the last error was not the offline placeholder, a fetch always runs.
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
refreshOnReconnect?: boolean;
|
|
26
36
|
children: (args: {
|
|
27
37
|
loading: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* `true` while a full pagination pass is in flight after at least one successful completion for
|
|
40
|
+
* the current request identity (stale-while-revalidate).
|
|
41
|
+
*/
|
|
42
|
+
refreshing: boolean;
|
|
28
43
|
received: number;
|
|
29
44
|
total: number | null;
|
|
30
45
|
/**
|
|
@@ -44,5 +59,5 @@ export type RopeGeoPaginationHttpRequestProps<T = unknown> = {
|
|
|
44
59
|
* {@link PaginationResults.fromResponseBody}. Final `data` is pages concatenated in page order.
|
|
45
60
|
* In-flight requests use one {@link AbortController}: unmount or any failure aborts the rest.
|
|
46
61
|
*/
|
|
47
|
-
export declare function RopeGeoPaginationHttpRequest<T = unknown>({ service, method, path, pathParams, queryParams, batchSize, timeoutAfterSeconds, isOnline, children, }: RopeGeoPaginationHttpRequestProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
62
|
+
export declare function RopeGeoPaginationHttpRequest<T = unknown>({ service, method, path, pathParams, queryParams, batchSize, timeoutAfterSeconds, isOnline, refreshOnReconnect, children, }: RopeGeoPaginationHttpRequestProps<T>): import("react/jsx-runtime").JSX.Element;
|
|
48
63
|
//# sourceMappingURL=RopeGeoPaginationHttpRequest.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"RopeGeoPaginationHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoPaginationHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAUvC,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAoB,MAAM,sBAAsB,CAAC;AA8DzE,MAAM,MAAM,iCAAiC,CAAC,CAAC,GAAG,OAAO,IAAI;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B
|
|
1
|
+
{"version":3,"file":"RopeGeoPaginationHttpRequest.d.ts","sourceRoot":"","sources":["../../src/components/RopeGeoPaginationHttpRequest.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAUvC,OAAO,EACL,KAAK,gBAAgB,EAEtB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,MAAM,EAAE,OAAO,EAAoB,MAAM,sBAAsB,CAAC;AA8DzE,MAAM,MAAM,iCAAiC,CAAC,CAAC,GAAG,OAAO,IAAI;IAC3D,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC;IAC9C,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,WAAW,EAAE,gBAAgB,CAAC;IAC9B;;;;OAIG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,EAAE,CAAC,IAAI,EAAE;QACf,OAAO,EAAE,OAAO,CAAC;QACjB;;;WAGG;QACH,UAAU,EAAE,OAAO,CAAC;QACpB,QAAQ,EAAE,MAAM,CAAC;QACjB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB;;;WAGG;QACH,IAAI,EAAE,CAAC,EAAE,GAAG,IAAI,CAAC;QACjB,+FAA+F;QAC/F,MAAM,EAAE,KAAK,GAAG,IAAI,CAAC;QACrB,qGAAqG;QACrG,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;KACjC,KAAK,SAAS,CAAC;CACjB,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAAC,CAAC,GAAG,OAAO,EAAE,EACxD,OAAO,EACP,MAAmB,EACnB,IAAI,EACJ,UAAU,EACV,WAAW,EACX,SAAc,EACd,mBAAmB,EACnB,QAAQ,EACR,kBAA0B,EAC1B,QAAQ,GACT,EAAE,iCAAiC,CAAC,CAAC,CAAC,2CAqTtC"}
|
|
@@ -57,36 +57,79 @@ function concatPaginationResultItemsSorted(pagesByNum) {
|
|
|
57
57
|
* {@link PaginationResults.fromResponseBody}. Final `data` is pages concatenated in page order.
|
|
58
58
|
* In-flight requests use one {@link AbortController}: unmount or any failure aborts the rest.
|
|
59
59
|
*/
|
|
60
|
-
function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.Method.GET, path, pathParams, queryParams, batchSize = 10, timeoutAfterSeconds, isOnline, children, }) {
|
|
60
|
+
function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.Method.GET, path, pathParams, queryParams, batchSize = 10, timeoutAfterSeconds, isOnline, refreshOnReconnect = false, children, }) {
|
|
61
61
|
const [loading, setLoading] = (0, react_1.useState)(true);
|
|
62
62
|
const [received, setReceived] = (0, react_1.useState)(0);
|
|
63
63
|
const [total, setTotal] = (0, react_1.useState)(null);
|
|
64
64
|
const [data, setData] = (0, react_1.useState)(null);
|
|
65
65
|
const [errors, setErrors] = (0, react_1.useState)(null);
|
|
66
66
|
const [timeoutCountdown, setTimeoutCountdown] = (0, react_1.useState)(null);
|
|
67
|
+
const [hasCommittedOnce, setHasCommittedOnce] = (0, react_1.useState)(false);
|
|
68
|
+
const errorsRef = (0, react_1.useRef)(errors);
|
|
69
|
+
const hasCommittedRef = (0, react_1.useRef)(hasCommittedOnce);
|
|
70
|
+
errorsRef.current = errors;
|
|
71
|
+
hasCommittedRef.current = hasCommittedOnce;
|
|
67
72
|
const pathParamsKey = JSON.stringify(pathParams ?? null);
|
|
68
73
|
const queryParamsKey = queryParams.toQueryString();
|
|
69
74
|
const effectiveBatch = Math.max(1, Math.floor(batchSize));
|
|
75
|
+
const requestKey = (0, react_1.useMemo)(() => `${service}|${method}|${path}|${pathParamsKey}|${queryParamsKey}|${effectiveBatch}|${timeoutAfterSeconds ?? ""}`, [service, method, path, pathParamsKey, queryParamsKey, effectiveBatch, timeoutAfterSeconds]);
|
|
76
|
+
const prevIsOnlineRef = (0, react_1.useRef)(undefined);
|
|
77
|
+
const lastRequestKeyRef = (0, react_1.useRef)("");
|
|
70
78
|
(0, react_1.useEffect)(() => {
|
|
71
|
-
|
|
79
|
+
const online = isOnline !== false;
|
|
80
|
+
const prevOnline = prevIsOnlineRef.current;
|
|
81
|
+
const reconnecting = prevOnline === false && online;
|
|
82
|
+
const keyChanged = lastRequestKeyRef.current !== requestKey;
|
|
83
|
+
if (!online) {
|
|
84
|
+
if (keyChanged) {
|
|
85
|
+
lastRequestKeyRef.current = requestKey;
|
|
86
|
+
setHasCommittedOnce(false);
|
|
87
|
+
setReceived(0);
|
|
88
|
+
setTotal(null);
|
|
89
|
+
setData(null);
|
|
90
|
+
setErrors(null);
|
|
91
|
+
}
|
|
92
|
+
prevIsOnlineRef.current = false;
|
|
72
93
|
setLoading(false);
|
|
73
|
-
setReceived(0);
|
|
74
|
-
setTotal(null);
|
|
75
|
-
setData(null);
|
|
76
94
|
setErrors(new Error(network_1.NO_NETWORK_MESSAGE));
|
|
77
95
|
setTimeoutCountdown(null);
|
|
78
96
|
return;
|
|
79
97
|
}
|
|
98
|
+
if (keyChanged) {
|
|
99
|
+
lastRequestKeyRef.current = requestKey;
|
|
100
|
+
setHasCommittedOnce(false);
|
|
101
|
+
setReceived(0);
|
|
102
|
+
setTotal(null);
|
|
103
|
+
setData(null);
|
|
104
|
+
setErrors(null);
|
|
105
|
+
}
|
|
106
|
+
if (!keyChanged && reconnecting) {
|
|
107
|
+
const onlyNoNetwork = errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE;
|
|
108
|
+
if (hasCommittedRef.current && onlyNoNetwork && !refreshOnReconnect) {
|
|
109
|
+
setErrors(null);
|
|
110
|
+
setLoading(false);
|
|
111
|
+
prevIsOnlineRef.current = true;
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
prevIsOnlineRef.current = true;
|
|
80
116
|
let cancelled = false;
|
|
81
117
|
const abortController = new AbortController();
|
|
82
118
|
const { signal } = abortController;
|
|
83
119
|
const timeoutMs = (0, network_1.resolveRequestTimeoutMs)(timeoutAfterSeconds);
|
|
84
120
|
setLoading(true);
|
|
85
|
-
setReceived(0);
|
|
86
|
-
setTotal(null);
|
|
87
|
-
setData(null);
|
|
88
121
|
setErrors(null);
|
|
89
122
|
setTimeoutCountdown(null);
|
|
123
|
+
const keepStaleDuringFetch = reconnecting &&
|
|
124
|
+
hasCommittedRef.current &&
|
|
125
|
+
errorsRef.current?.message === network_1.NO_NETWORK_MESSAGE &&
|
|
126
|
+
refreshOnReconnect;
|
|
127
|
+
if (!keyChanged && !keepStaleDuringFetch) {
|
|
128
|
+
setReceived(0);
|
|
129
|
+
setTotal(null);
|
|
130
|
+
setData(null);
|
|
131
|
+
setHasCommittedOnce(false);
|
|
132
|
+
}
|
|
90
133
|
const baseUrl = RopeGeoHttpRequest_1.SERVICE_BASE_URL[service];
|
|
91
134
|
const resolvedPath = resolvePath(path, pathParams);
|
|
92
135
|
const baseInit = {
|
|
@@ -219,6 +262,7 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
|
|
|
219
262
|
return;
|
|
220
263
|
setData(concatPaginationResultItemsSorted(pagesByNum));
|
|
221
264
|
setErrors(null);
|
|
265
|
+
setHasCommittedOnce(true);
|
|
222
266
|
return;
|
|
223
267
|
}
|
|
224
268
|
const lastPage = Math.max(1, Math.ceil(totalCount / limit));
|
|
@@ -249,6 +293,7 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
|
|
|
249
293
|
return;
|
|
250
294
|
setData(concatPaginationResultItemsSorted(pagesByNum));
|
|
251
295
|
setErrors(null);
|
|
296
|
+
setHasCommittedOnce(true);
|
|
252
297
|
}
|
|
253
298
|
catch (err) {
|
|
254
299
|
if (cancelled || (0, network_1.isAbortError)(err))
|
|
@@ -258,6 +303,7 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
|
|
|
258
303
|
});
|
|
259
304
|
setErrors(err instanceof Error ? err : new Error(String(err)));
|
|
260
305
|
setData(null);
|
|
306
|
+
setHasCommittedOnce(false);
|
|
261
307
|
}
|
|
262
308
|
finally {
|
|
263
309
|
clearActivePolicy();
|
|
@@ -275,13 +321,16 @@ function RopeGeoPaginationHttpRequest({ service, method = RopeGeoHttpRequest_1.M
|
|
|
275
321
|
path,
|
|
276
322
|
pathParamsKey,
|
|
277
323
|
queryParamsKey,
|
|
278
|
-
queryParams,
|
|
279
324
|
effectiveBatch,
|
|
280
325
|
timeoutAfterSeconds,
|
|
281
326
|
isOnline,
|
|
327
|
+
refreshOnReconnect,
|
|
328
|
+
requestKey,
|
|
282
329
|
]);
|
|
330
|
+
const refreshing = loading && hasCommittedOnce;
|
|
283
331
|
return ((0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: children({
|
|
284
332
|
loading,
|
|
333
|
+
refreshing,
|
|
285
334
|
received,
|
|
286
335
|
total,
|
|
287
336
|
data,
|