1. /**
    
  2.  * Copyright (c) Meta Platforms, Inc. and 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 * as React from 'react';
    
  11. import {Fragment, useContext, useEffect} from 'react';
    
  12. import {ModalDialogContext} from './ModalDialog';
    
  13. import {StoreContext} from './context';
    
  14. import {currentBridgeProtocol} from 'react-devtools-shared/src/bridge';
    
  15. import Button from './Button';
    
  16. import ButtonIcon from './ButtonIcon';
    
  17. import {copy} from 'clipboard-js';
    
  18. import styles from './UnsupportedBridgeProtocolDialog.css';
    
  19. 
    
  20. import type {BridgeProtocol} from 'react-devtools-shared/src/bridge';
    
  21. 
    
  22. const DEVTOOLS_VERSION = process.env.DEVTOOLS_VERSION;
    
  23. const INSTRUCTIONS_FB_URL =
    
  24.   'https://fb.me/devtools-unsupported-bridge-protocol';
    
  25. const MODAL_DIALOG_ID = 'UnsupportedBridgeProtocolDialog';
    
  26. 
    
  27. export default function UnsupportedBridgeProtocolDialog(_: {}): null {
    
  28.   const {dialogs, dispatch} = useContext(ModalDialogContext);
    
  29.   const store = useContext(StoreContext);
    
  30. 
    
  31.   const isVisible = !!dialogs.find(dialog => dialog.id === MODAL_DIALOG_ID);
    
  32. 
    
  33.   useEffect(() => {
    
  34.     const updateDialog = () => {
    
  35.       if (!isVisible) {
    
  36.         if (store.unsupportedBridgeProtocolDetected) {
    
  37.           dispatch({
    
  38.             canBeDismissed: false,
    
  39.             id: MODAL_DIALOG_ID,
    
  40.             type: 'SHOW',
    
  41.             content: (
    
  42.               <DialogContent unsupportedBridgeProtocol={store.bridgeProtocol} />
    
  43.             ),
    
  44.           });
    
  45.         }
    
  46.       } else {
    
  47.         if (!store.unsupportedBridgeProtocolDetected) {
    
  48.           dispatch({
    
  49.             type: 'HIDE',
    
  50.             id: MODAL_DIALOG_ID,
    
  51.           });
    
  52.         }
    
  53.       }
    
  54.     };
    
  55. 
    
  56.     updateDialog();
    
  57. 
    
  58.     store.addListener('unsupportedBridgeProtocolDetected', updateDialog);
    
  59.     return () => {
    
  60.       store.removeListener('unsupportedBridgeProtocolDetected', updateDialog);
    
  61.     };
    
  62.   }, [isVisible, store]);
    
  63. 
    
  64.   return null;
    
  65. }
    
  66. 
    
  67. function DialogContent({
    
  68.   unsupportedBridgeProtocol,
    
  69. }: {
    
  70.   unsupportedBridgeProtocol: BridgeProtocol,
    
  71. }) {
    
  72.   const {version, minNpmVersion, maxNpmVersion} = unsupportedBridgeProtocol;
    
  73. 
    
  74.   let instructions;
    
  75.   if (maxNpmVersion === null) {
    
  76.     const upgradeInstructions = `npm i -g react-devtools@^${minNpmVersion}`;
    
  77.     instructions = (
    
  78.       <>
    
  79.         <p className={styles.Paragraph}>
    
  80.           To fix this, upgrade the DevTools NPM package:
    
  81.         </p>
    
  82.         <pre className={styles.NpmCommand}>
    
  83.           {upgradeInstructions}
    
  84.           <Button
    
  85.             onClick={() => copy(upgradeInstructions)}
    
  86.             title="Copy upgrade command to clipboard">
    
  87.             <ButtonIcon type="copy" />
    
  88.           </Button>
    
  89.         </pre>
    
  90.       </>
    
  91.     );
    
  92.   } else {
    
  93.     const downgradeInstructions = `npm i -g react-devtools@${maxNpmVersion}`;
    
  94.     instructions = (
    
  95.       <>
    
  96.         <p className={styles.Paragraph}>
    
  97.           To fix this, downgrade the DevTools NPM package:
    
  98.         </p>
    
  99.         <pre className={styles.NpmCommand}>
    
  100.           {downgradeInstructions}
    
  101.           <Button
    
  102.             onClick={() => copy(downgradeInstructions)}
    
  103.             title="Copy downgrade command to clipboard">
    
  104.             <ButtonIcon type="copy" />
    
  105.           </Button>
    
  106.         </pre>
    
  107.       </>
    
  108.     );
    
  109.   }
    
  110. 
    
  111.   return (
    
  112.     <Fragment>
    
  113.       <div className={styles.Column}>
    
  114.         <div className={styles.Title}>Unsupported DevTools backend version</div>
    
  115.         <p className={styles.Paragraph}>
    
  116.           You are running <code>react-devtools</code> version{' '}
    
  117.           <span className={styles.Version}>{DEVTOOLS_VERSION}</span>.
    
  118.         </p>
    
  119.         <p className={styles.Paragraph}>
    
  120.           This requires bridge protocol{' '}
    
  121.           <span className={styles.Version}>
    
  122.             version {currentBridgeProtocol.version}
    
  123.           </span>
    
  124.           . However the current backend version uses bridge protocol{' '}
    
  125.           <span className={styles.Version}>version {version}</span>.
    
  126.         </p>
    
  127.         {instructions}
    
  128.         <p className={styles.Paragraph}>
    
  129.           Or{' '}
    
  130.           <a className={styles.Link} href={INSTRUCTIONS_FB_URL} target="_blank">
    
  131.             click here
    
  132.           </a>{' '}
    
  133.           for more information.
    
  134.         </p>
    
  135.       </div>
    
  136.     </Fragment>
    
  137.   );
    
  138. }