11
unstable_getCacheForType as getCacheForType,
12
startTransition,
13
} from 'react';
14
-import Store from './devtools/store';
15
-import {inspectElement as inspectElementMutableSource} from './inspectedElementMutableSource';
14
+import Store from 'react-devtools-shared/src/devtools/store';
15
+import {inspectElement as inspectElementMutableSource} from 'react-devtools-shared/src/inspectedElementMutableSource';
16
+import ElementPollingCancellationError from 'react-devtools-shared/src//errors/ElementPollingCancellationError';
17
18
import type {FrontendBridge} from 'react-devtools-shared/src/bridge';
19
import type {Wakeable} from 'shared/ReactTypes';
178
element: Element,
179
refresh: RefreshFunction,
180
store: Store,
180
-}): void {
181
+}): void | Promise<void> {
182
const {id} = element;
183
const rendererID = store.getRendererIDForElement(id);
184
186
return;
187
}
188
188
- inspectElementMutableSource({
189
+ return inspectElementMutableSource({
190
bridge,
191
element,
192
path: null,
203
});
204
}
205
},
205
-
206
- // There isn't much to do about errors in this case,
207
- // but we should at least log them so they aren't silent.
208
- error => {
209
- console.error(error);
210
- },
206
);
207
}
208
209
+function createPromiseWhichResolvesInOneSecond() {
210
+ return new Promise(resolve => setTimeout(resolve, 1000));
211
+}
212
+
213
+type PollingStatus = 'idle' | 'running' | 'paused' | 'aborted';
214
+
215
+export function startElementUpdatesPolling({
216
+ bridge,
217
+ element,
218
+ refresh,
219
+ store,
220
+}: {
221
+ bridge: FrontendBridge,
222
+ element: Element,
223
+ refresh: RefreshFunction,
224
+ store: Store,
225
+}): {abort: () => void, pause: () => void, resume: () => void} {
226
+ let status: PollingStatus = 'idle';
227
+
228
+ function abort() {
229
+ status = 'aborted';
230
+ }
231
+
232
+ function resume() {
233
+ if (status === 'running' || status === 'aborted') {
234
+ return;
235
+ }
236
+
237
+ status = 'idle';
238
+ poll();
239
+ }
240
+
241
+ function pause() {
242
+ if (status === 'paused' || status === 'aborted') {
243
+ return;
244
+ }
245
+
246
+ status = 'paused';
247
+ }
248
+
249
+ function poll(): Promise<void> {
250
+ status = 'running';
251
+
252
+ return Promise.allSettled([
253
+ checkForUpdate({bridge, element, refresh, store}),
254
+ createPromiseWhichResolvesInOneSecond(),
255
+ ])
256
+ .then(([{status: updateStatus, reason}]) => {
257
+ // There isn't much to do about errors in this case,
258
+ // but we should at least log them, so they aren't silent.
259
+ // Log only if polling is still active, we can't handle the case when
260
+ // request was sent, and then bridge was remounted (for example, when user did navigate to a new page),
261
+ // but at least we can mark that polling was aborted
262
+ if (updateStatus === 'rejected' && status !== 'aborted') {
263
+ // This is expected Promise rejection, no need to log it
264
+ if (reason instanceof ElementPollingCancellationError) {
265
+ return;
266
+ }
267
+
268
+ console.error(reason);
269
+ }
270
+ })
271
+ .finally(() => {
272
+ const shouldContinuePolling =
273
+ status !== 'aborted' && status !== 'paused';
274
+
275
+ status = 'idle';
276
+
277
+ if (shouldContinuePolling) {
278
+ return poll();
279
+ }
280
+ });
281
+ }
282
+
283
+ poll();
284
+
285
+ return {abort, resume, pause};
286
+}
287
+
288
export function clearCacheBecauseOfError(refresh: RefreshFunction): void {
289
startTransition(() => {
290
const map = createMap();