@samitouri / QOS-React-2 / commits / b6606ecba8

DevTools shows unsupported renderer version dialog (#16897)

* DevTools shows unsupported renderer version dialog * Optimistic CHANGELOG udpate

Brian Vaughn committed Sep 26, 2019 at 08:41 UTC b6606ecba80b591ea66db1e2ee1fed72befb4c32
12 files changed +161 -10
packages/react-devtools-extensions/src/main.js
+1 -1
@@ -161,7 +161,7 @@ function createPanelIfReactLoaded() {
161 overrideTab,
162 profilerPortalContainer,
163 showTabBar: false,
164 - showWelcomeToTheNewDevToolsDialog: true,
164 + warnIfUnsupportedVersionDetected: true,
165 store,
166 viewElementSourceFunction,
167 }),
packages/react-devtools-shared/src/backend/agent.js
+4
@@ -474,6 +474,10 @@ export default class Agent extends EventEmitter<{|
474 }
475 };
476
477 + onUnsupportedRenderer(rendererID: number) {
478 + this._bridge.send('unsupportedRendererVersion', rendererID);
479 + }
480 +
481 _throttledPersistSelection = throttle((rendererID: number, id: number) => {
482 // This is throttled, so both renderer and selected ID
483 // might not be available by the time we read them.
packages/react-devtools-shared/src/backend/index.js
+22 -8
@@ -39,6 +39,10 @@ export function initBackend(
39 },
40 ),
41
42 + hook.sub('unsupported-renderer-version', (id: number) => {
43 + agent.onUnsupportedRenderer(id);
44 + }),
45 +
46 hook.sub('operations', agent.onHookOperations),
47
48 // TODO Add additional subscriptions required for profiling mode
@@ -48,23 +52,33 @@ export function initBackend(
52 let rendererInterface = hook.rendererInterfaces.get(id);
53
54 // Inject any not-yet-injected renderers (if we didn't reload-and-profile)
51 - if (!rendererInterface) {
55 + if (rendererInterface == null) {
56 if (typeof renderer.findFiberByHostInstance === 'function') {
57 + // react-reconciler v16+
58 rendererInterface = attach(hook, id, renderer, global);
54 - } else {
59 + } else if (renderer.ComponentTree) {
60 + // react-dom v15
61 rendererInterface = attachLegacy(hook, id, renderer, global);
62 + } else {
63 + // Older react-dom or other unsupported renderer version
64 }
65
58 - hook.rendererInterfaces.set(id, rendererInterface);
66 + if (rendererInterface != null) {
67 + hook.rendererInterfaces.set(id, rendererInterface);
68 + }
69 }
70
71 // Notify the DevTools frontend about new renderers.
72 // This includes any that were attached early (via __REACT_DEVTOOLS_ATTACH__).
63 - hook.emit('renderer-attached', {
64 - id,
65 - renderer,
66 - rendererInterface,
67 - });
73 + if (rendererInterface != null) {
74 + hook.emit('renderer-attached', {
75 + id,
76 + renderer,
77 + rendererInterface,
78 + });
79 + } else {
80 + hook.emit('unsupported-renderer-version', id);
81 + }
82 };
83
84 // Connect renderers that have already injected themselves.
packages/react-devtools-shared/src/backend/types.js
+4 -1
@@ -81,7 +81,10 @@ export type ReactRenderer = {
81 // Enables DevTools to append owners-only component stack to error messages.
82 getCurrentFiber?: () => Fiber | null,
83
84 - // <= 15
84 + // Uniquely identifies React DOM v15.
85 + ComponentTree?: any,
86 +
87 + // Present for React DOM v12 (possibly earlier) through v15.
88 Mount?: any,
89 };
90
packages/react-devtools-shared/src/bridge.js
+1
@@ -83,6 +83,7 @@ type BackendEvents = {|
83 stopInspectingNative: [boolean],
84 syncSelectionFromNativeElementsPanel: [],
85 syncSelectionToNativeElementsPanel: [],
86 + unsupportedRendererVersion: [RendererID],
87
88 // React Native style editor plug-in.
89 isNativeStyleEditorSupported: [
packages/react-devtools-shared/src/constants.js
+3
@@ -35,6 +35,9 @@ export const PROFILER_EXPORT_VERSION = 4;
35 export const CHANGE_LOG_URL =
36 'https://github.com/facebook/react/blob/master/packages/react-devtools/CHANGELOG.md';
37
38 +export const UNSUPPORTED_VERSION_URL =
39 + 'https://reactjs.org/blog/2019/08/15/new-react-devtools.html#how-do-i-get-the-old-version-back';
40 +
41 // HACK
42 //
43 // Extracting during build time avoids a temporarily invalid state for the inline target.
packages/react-devtools-shared/src/devtools/store.js
+17
@@ -73,6 +73,7 @@ export default class Store extends EventEmitter<{|
73 supportsNativeStyleEditor: [],
74 supportsProfiling: [],
75 supportsReloadAndProfile: [],
76 + unsupportedRendererVersionDetected: [],
77 |}> {
78 _bridge: FrontendBridge;
79
@@ -125,6 +126,8 @@ export default class Store extends EventEmitter<{|
126 _supportsProfiling: boolean = false;
127 _supportsReloadAndProfile: boolean = false;
128
129 + _unsupportedRendererVersionDetected: boolean = false;
130 +
131 // Total number of visible elements (within all roots).
132 // Used for windowing purposes.
133 _weightAcrossRoots: number = 0;
@@ -179,6 +182,10 @@ export default class Store extends EventEmitter<{|
182 'isNativeStyleEditorSupported',
183 this.onBridgeNativeStyleEditorSupported,
184 );
185 + bridge.addListener(
186 + 'unsupportedRendererVersion',
187 + this.onBridgeUnsupportedRendererVersion,
188 + );
189
190 this._profilerStore = new ProfilerStore(bridge, this, isProfiling);
191 }
@@ -337,6 +344,10 @@ export default class Store extends EventEmitter<{|
344 return this._supportsReloadAndProfile && this._isBackendStorageAPISupported;
345 }
346
347 + get unsupportedRendererVersionDetected(): boolean {
348 + return this._unsupportedRendererVersionDetected;
349 + }
350 +
351 containsElement(id: number): boolean {
352 return this._idToElement.get(id) != null;
353 }
@@ -1009,4 +1020,10 @@ export default class Store extends EventEmitter<{|
1020
1021 this.emit('supportsReloadAndProfile');
1022 };
1023 +
1024 + onBridgeUnsupportedRendererVersion = () => {
1025 + this._unsupportedRendererVersionDetected = true;
1026 +
1027 + this.emit('unsupportedRendererVersionDetected');
1028 + };
1029 }
packages/react-devtools-shared/src/devtools/views/DevTools.js
+4
@@ -24,6 +24,7 @@ import ViewElementSourceContext from './Components/ViewElementSourceContext';
24 import {ProfilerContextController} from './Profiler/ProfilerContext';
25 import {ModalDialogContextController} from './ModalDialog';
26 import ReactLogo from './ReactLogo';
27 +import UnsupportedVersionDialog from './UnsupportedVersionDialog';
28 import WarnIfLegacyBackendDetected from './WarnIfLegacyBackendDetected';
29
30 import styles from './DevTools.css';
@@ -51,6 +52,7 @@ export type Props = {|
52 showTabBar?: boolean,
53 store: Store,
54 warnIfLegacyBackendDetected?: boolean,
55 + warnIfUnsupportedVersionDetected?: boolean,
56 viewElementSourceFunction?: ?ViewElementSource,
57
58 // This property is used only by the web extension target.
@@ -92,6 +94,7 @@ export default function DevTools({
94 showTabBar = false,
95 store,
96 warnIfLegacyBackendDetected = false,
97 + warnIfUnsupportedVersionDetected = false,
98 viewElementSourceFunction,
99 }: Props) {
100 const [tab, setTab] = useState(defaultTab);
@@ -164,6 +167,7 @@ export default function DevTools({
167 </ViewElementSourceContext.Provider>
168 </SettingsContextController>
169 {warnIfLegacyBackendDetected && <WarnIfLegacyBackendDetected />}
170 + {warnIfUnsupportedVersionDetected && <UnsupportedVersionDialog />}
171 </ModalDialogContextController>
172 </StoreContext.Provider>
173 </BridgeContext.Provider>
packages/react-devtools-shared/src/devtools/views/UnsupportedVersionDialog.css new
+20
@@ -0,0 +1,20 @@
1 +.Row {
2 + display: flex;
3 + flex-direction: row;
4 + align-items: center;
5 +}
6 +
7 +.Column {
8 + display: flex;
9 + flex-direction: column;
10 + align-items: center;
11 +}
12 +
13 +.Title {
14 + font-size: var(--font-size-sans-large);
15 + margin-bottom: 0.5rem;
16 +}
17 +
18 +.ReleaseNotesLink {
19 + color: var(--color-button-active);
20 +}
\ No newline at end of file
packages/react-devtools-shared/src/devtools/views/UnsupportedVersionDialog.js new
+83
@@ -0,0 +1,83 @@
1 +/**
2 + * Copyright (c) Facebook, Inc. and its affiliates.
3 + *
4 + * This source code is licensed under the MIT license found in the
5 + * LICENSE file in the root directory of this source tree.
6 + *
7 + * @flow
8 + */
9 +
10 +import React, {Fragment, useContext, useEffect, useState} from 'react';
11 +import {unstable_batchedUpdates as batchedUpdates} from 'react-dom';
12 +import {ModalDialogContext} from './ModalDialog';
13 +import {StoreContext} from './context';
14 +import {UNSUPPORTED_VERSION_URL} from 'react-devtools-shared/src/constants';
15 +
16 +import styles from './UnsupportedVersionDialog.css';
17 +
18 +type DAILOG_STATE = 'dialog-not-shown' | 'show-dialog' | 'dialog-shown';
19 +
20 +export default function UnsupportedVersionDialog(_: {||}) {
21 + const {dispatch} = useContext(ModalDialogContext);
22 + const store = useContext(StoreContext);
23 + const [state, setState] = useState<DAILOG_STATE>('dialog-not-shown');
24 +
25 + useEffect(
26 + () => {
27 + if (state === 'dialog-not-shown') {
28 + const showDialog = () => {
29 + batchedUpdates(() => {
30 + setState('show-dialog');
31 + dispatch({
32 + canBeDismissed: true,
33 + type: 'SHOW',
34 + content: <DialogContent />,
35 + });
36 + });
37 + };
38 +
39 + if (store.unsupportedRendererVersionDetected) {
40 + showDialog();
41 + } else {
42 + store.addListener('unsupportedRendererVersionDetected', showDialog);
43 + return () => {
44 + store.removeListener(
45 + 'unsupportedRendererVersionDetected',
46 + showDialog,
47 + );
48 + };
49 + }
50 + }
51 + },
52 + [state, store],
53 + );
54 +
55 + return null;
56 +}
57 +
58 +function DialogContent(_: {||}) {
59 + return (
60 + <Fragment>
61 + <div className={styles.Row}>
62 + <div>
63 + <div className={styles.Title}>Unsupported React version detected</div>
64 + <p>
65 + This version of React DevTools supports React DOM v15+ and React
66 + Native v61+.
67 + </p>
68 + <p>
69 + In order to use DevTools with an older version of React, you'll need
70 + to{' '}
71 + <a
72 + className={styles.ReleaseNotesLink}
73 + target="_blank"
74 + rel="noopener noreferrer"
75 + href={UNSUPPORTED_VERSION_URL}>
76 + install an older version of the extension
77 + </a>.
78 + </p>
79 + </div>
80 + </div>
81 + </Fragment>
82 + );
83 +}
packages/react-devtools-shell/src/devtools.js
+1
@@ -57,6 +57,7 @@ inject('dist/app.js', () => {
57 browserTheme: 'light',
58 showTabBar: true,
59 warnIfLegacyBackendDetected: true,
60 + warnIfUnsupportedVersionDetected: true,
61 }),
62 );
63 },
packages/react-devtools/CHANGELOG.md
+1
@@ -12,6 +12,7 @@
12 * Fixed bug where Components panel was always empty for certain users. ([linshunghuang](https://github.com/linshunghuang) in [#16900](https://github.com/facebook/react/pull/16900))
13 * Fixed regression in DevTools editable hooks interface that caused primitive values to be shown as `undefined`. ([bvaughn](https://github.com/bvaughn) in [#16867](https://github.com/facebook/react/pull/16867))
14 * Fixed bug where DevTools showed stale values in props/state/hooks editing interface. ([bvaughn](https://github.com/bvaughn) in [#16878](https://github.com/facebook/react/pull/16878))
15 +* Show unsupported version dialog with downgrade instructions. ([bvaughn](https://github.com/bvaughn) in [#16897](https://github.com/facebook/react/pull/16897))
16 </details>
17
18 ## 4.1.0 (September 19, 2019)