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 {useContext, useMemo} from 'react';
    
  12. import {SettingsContext} from './SettingsContext';
    
  13. import {StoreContext} from '../context';
    
  14. import {CHANGE_LOG_URL} from 'react-devtools-shared/src/devtools/constants';
    
  15. 
    
  16. import styles from './SettingsShared.css';
    
  17. 
    
  18. function getChangeLogUrl(version: ?string): string | null {
    
  19.   if (!version) {
    
  20.     return null;
    
  21.   }
    
  22. 
    
  23.   // Version numbers are in the format of: <major>.<minor>.<patch>-<sha>
    
  24.   // e.g. "4.23.0-f0dd459e0"
    
  25.   // GitHub CHANGELOG headers are in the format of: <major>.<minor>.<patch>
    
  26.   // but the "." are stripped from anchor tags, becomming: <major><minor><patch>
    
  27.   const versionAnchor = version.replace(/^(\d+)\.(\d+)\.(\d+).*/, '$1$2$3');
    
  28.   return `${CHANGE_LOG_URL}#${versionAnchor}`;
    
  29. }
    
  30. 
    
  31. export default function GeneralSettings(_: {}): React.Node {
    
  32.   const {
    
  33.     displayDensity,
    
  34.     setDisplayDensity,
    
  35.     setTheme,
    
  36.     setTraceUpdatesEnabled,
    
  37.     theme,
    
  38.     traceUpdatesEnabled,
    
  39.   } = useContext(SettingsContext);
    
  40. 
    
  41.   const {backendVersion, supportsTraceUpdates} = useContext(StoreContext);
    
  42.   const frontendVersion = process.env.DEVTOOLS_VERSION;
    
  43. 
    
  44.   const showBackendVersion =
    
  45.     backendVersion && backendVersion !== frontendVersion;
    
  46. 
    
  47.   return (
    
  48.     <div className={styles.Settings}>
    
  49.       <div className={styles.Setting}>
    
  50.         <div className={styles.RadioLabel}>Theme</div>
    
  51.         <select
    
  52.           className={styles.Select}
    
  53.           value={theme}
    
  54.           onChange={({currentTarget}) => setTheme(currentTarget.value)}>
    
  55.           <option value="auto">Auto</option>
    
  56.           <option value="light">Light</option>
    
  57.           <option value="dark">Dark</option>
    
  58.         </select>
    
  59.       </div>
    
  60. 
    
  61.       <div className={styles.Setting}>
    
  62.         <div className={styles.RadioLabel}>Display density</div>
    
  63.         <select
    
  64.           className={styles.Select}
    
  65.           value={displayDensity}
    
  66.           onChange={({currentTarget}) =>
    
  67.             setDisplayDensity(currentTarget.value)
    
  68.           }>
    
  69.           <option value="compact">Compact</option>
    
  70.           <option value="comfortable">Comfortable</option>
    
  71.         </select>
    
  72.       </div>
    
  73. 
    
  74.       {supportsTraceUpdates && (
    
  75.         <div className={styles.Setting}>
    
  76.           <label>
    
  77.             <input
    
  78.               type="checkbox"
    
  79.               checked={traceUpdatesEnabled}
    
  80.               onChange={({currentTarget}) =>
    
  81.                 setTraceUpdatesEnabled(currentTarget.checked)
    
  82.               }
    
  83.             />{' '}
    
  84.             Highlight updates when components render.
    
  85.           </label>
    
  86.         </div>
    
  87.       )}
    
  88. 
    
  89.       <div className={styles.ReleaseNotes}>
    
  90.         {showBackendVersion && (
    
  91.           <div>
    
  92.             <ul className={styles.VersionsList}>
    
  93.               <li>
    
  94.                 <Version
    
  95.                   label="DevTools backend version:"
    
  96.                   version={backendVersion}
    
  97.                 />
    
  98.               </li>
    
  99.               <li>
    
  100.                 <Version
    
  101.                   label="DevTools frontend version:"
    
  102.                   version={frontendVersion}
    
  103.                 />
    
  104.               </li>
    
  105.             </ul>
    
  106.           </div>
    
  107.         )}
    
  108.         {!showBackendVersion && (
    
  109.           <Version label="DevTools version:" version={frontendVersion} />
    
  110.         )}
    
  111.       </div>
    
  112.     </div>
    
  113.   );
    
  114. }
    
  115. 
    
  116. function Version({label, version}: {label: string, version: ?string}) {
    
  117.   const changelogLink = useMemo(() => {
    
  118.     return getChangeLogUrl(version);
    
  119.   }, [version]);
    
  120. 
    
  121.   if (version == null) {
    
  122.     return null;
    
  123.   } else {
    
  124.     return (
    
  125.       <>
    
  126.         {label}{' '}
    
  127.         <a
    
  128.           className={styles.ReleaseNotesLink}
    
  129.           target="_blank"
    
  130.           rel="noopener noreferrer"
    
  131.           href={changelogLink}>
    
  132.           {version}
    
  133.         </a>
    
  134.       </>
    
  135.     );
    
  136.   }
    
  137. }