diff --git a/packages/react-devtools-extensions/src/main/index.js b/packages/react-devtools-extensions/src/main/index.js index 70e2dc45676..f21bdc7a9a9 100644 --- a/packages/react-devtools-extensions/src/main/index.js +++ b/packages/react-devtools-extensions/src/main/index.js @@ -18,7 +18,12 @@ import { LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY, } from 'react-devtools-shared/src/constants'; import {logEvent} from 'react-devtools-shared/src/Logger'; -import {normalizeUrlIfValid} from 'react-devtools-shared/src/utils'; +import { + getAlwaysOpenInEditor, + getOpenInEditorURL, + normalizeUrlIfValid, +} from 'react-devtools-shared/src/utils'; +import {checkConditions} from 'react-devtools-shared/src/devtools/views/Editor/utils'; import { setBrowserSelectionFromReact, @@ -543,3 +548,32 @@ if (chrome.devtools.panels.setThemeChangeHandler) { // Firefox chrome.devtools.panels.onThemeChanged.addListener(onThemeChanged); } + +// Firefox doesn't support resources handlers yet. +if (chrome.devtools.panels.setOpenResourceHandler) { + chrome.devtools.panels.setOpenResourceHandler( + ( + resource, + lineNumber = 1, + // The column is a new feature so we have to specify a default if it doesn't exist + columnNumber = 1, + ) => { + const alwaysOpenInEditor = getAlwaysOpenInEditor(); + const editorURL = getOpenInEditorURL(); + if (alwaysOpenInEditor && editorURL) { + const location = ['', resource.url, lineNumber, columnNumber]; + const {url, shouldDisableButton} = checkConditions(editorURL, location); + if (!shouldDisableButton) { + window.open(url); + return; + } + } + // Otherwise fallback to the built-in behavior. + chrome.devtools.panels.openResource( + resource.url, + lineNumber - 1, + columnNumber - 1, + ); + }, + ); +} diff --git a/packages/react-devtools-shared/src/devtools/views/Editor/EditorPane.js b/packages/react-devtools-shared/src/devtools/views/Editor/EditorPane.js index 09c76e1d26e..eb759748ca2 100644 --- a/packages/react-devtools-shared/src/devtools/views/Editor/EditorPane.js +++ b/packages/react-devtools-shared/src/devtools/views/Editor/EditorPane.js @@ -37,6 +37,7 @@ export type Props = {selectedSource: ?SourceSelection}; function EditorPane({selectedSource}: Props) { const [showSettings, setShowSettings] = useState(false); + const [showLinkInfo, setShowLinkInfo] = useState(false); const editorURL = useSyncExternalStore( function subscribe(callback) { @@ -50,6 +51,30 @@ function EditorPane({selectedSource}: Props) { }, ); + if (showLinkInfo) { + return ( +
+
+
+ To enable link handling in your browser's DevTools settings, look + for the option Extension -> Link Handling. Select "React Developer + Tools". +
+
+ +
+
+ ); + } + let editorToolbar; if (showSettings) { editorToolbar = ( @@ -87,7 +112,13 @@ function EditorPane({selectedSource}: Props) { {editorToolbar}
{editorURL ? ( - + { + if (alwaysOpenInEditor) { + startTransition(() => setShowLinkInfo(true)); + } + }} + /> ) : ( 'Configure an external editor to open local files.' )} diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/CodeEditorByDefault.js b/packages/react-devtools-shared/src/devtools/views/Settings/CodeEditorByDefault.js index 74dba4947b2..cabc3d6584b 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/CodeEditorByDefault.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/CodeEditorByDefault.js @@ -13,7 +13,11 @@ import {useLocalStorage} from '../hooks'; import styles from './SettingsShared.css'; -export default function CodeEditorByDefault(_: {}): React.Node { +export default function CodeEditorByDefault({ + onChange, +}: { + onChange?: boolean => void, +}): React.Node { const [alwaysOpenInEditor, setAlwaysOpenInEditor] = useLocalStorage( LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR, false, @@ -24,9 +28,12 @@ export default function CodeEditorByDefault(_: {}): React.Node { - setAlwaysOpenInEditor(currentTarget.checked) - } + onChange={({currentTarget}) => { + setAlwaysOpenInEditor(currentTarget.checked); + if (onChange) { + onChange(currentTarget.checked); + } + }} className={styles.SettingRowCheckbox} /> Open local files directly in your code editor diff --git a/packages/react-devtools-shared/src/devtools/views/Settings/GeneralSettings.js b/packages/react-devtools-shared/src/devtools/views/Settings/GeneralSettings.js index c6db4e89320..6823dd9f619 100644 --- a/packages/react-devtools-shared/src/devtools/views/Settings/GeneralSettings.js +++ b/packages/react-devtools-shared/src/devtools/views/Settings/GeneralSettings.js @@ -13,10 +13,13 @@ import {SettingsContext} from './SettingsContext'; import {StoreContext} from '../context'; import {CHANGE_LOG_URL} from 'react-devtools-shared/src/devtools/constants'; import {isInternalFacebookBuild} from 'react-devtools-feature-flags'; -import CodeEditorOptions from './CodeEditorOptions'; import styles from './SettingsShared.css'; + +import CodeEditorOptions from './CodeEditorOptions'; import CodeEditorByDefault from './CodeEditorByDefault'; +import {LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR} from '../../../constants'; +import {useLocalStorage} from '../hooks'; function getChangeLogUrl(version: ?string): string | null { if (!version) { @@ -47,6 +50,11 @@ export default function GeneralSettings(_: {}): React.Node { const showBackendVersion = backendVersion && backendVersion !== frontendVersion; + const [alwaysOpenInEditor] = useLocalStorage( + LOCAL_STORAGE_ALWAYS_OPEN_IN_EDITOR, + false, + ); + return (
{isInternalFacebookBuild && ( @@ -87,6 +95,13 @@ export default function GeneralSettings(_: {}): React.Node {
+ {alwaysOpenInEditor && (__IS_CHROME__ || __IS_EDGE__) ? ( +
+ To enable link handling in your browser's DevTools settings, look + for the option Extension -> Link Handling. Select "React Developer + Tools". +
+ ) : null}