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}