Skip to content

Commit

Permalink
[DevTools] Add open in editor for fb (facebook#22649)
Browse files Browse the repository at this point in the history
Co-authored-by: Brian Vaughn <bvaughn@fb.com>
  • Loading branch information
2 people authored and zhengjitf committed Apr 15, 2022
1 parent c5930e8 commit 0e48a88
Show file tree
Hide file tree
Showing 11 changed files with 108 additions and 3 deletions.
2 changes: 2 additions & 0 deletions packages/react-devtools-core/webpack.standalone.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ const __DEV__ = NODE_ENV === 'development';

const DEVTOOLS_VERSION = getVersionString();

const EDITOR_URL = process.env.EDITOR_URL || null;
const LOGGING_URL = process.env.LOGGING_URL || null;

const featureFlagTarget =
Expand Down Expand Up @@ -83,6 +84,7 @@ module.exports = {
__TEST__: NODE_ENV === 'test',
'process.env.DEVTOOLS_PACKAGE': `"react-devtools-core"`,
'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null,
'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
'process.env.LOGGING_URL': `"${LOGGING_URL}"`,
'process.env.NODE_ENV': `"${NODE_ENV}"`,
Expand Down
2 changes: 2 additions & 0 deletions packages/react-devtools-extensions/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ const __DEV__ = NODE_ENV === 'development';

const DEVTOOLS_VERSION = getVersionString(process.env.DEVTOOLS_VERSION);

const EDITOR_URL = process.env.EDITOR_URL || null;
const LOGGING_URL = process.env.LOGGING_URL || null;

const featureFlagTarget = process.env.FEATURE_FLAG_TARGET || 'extension-oss';
Expand Down Expand Up @@ -92,6 +93,7 @@ module.exports = {
__TEST__: NODE_ENV === 'test',
'process.env.DEVTOOLS_PACKAGE': `"react-devtools-extensions"`,
'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null,
'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
'process.env.LOGGING_URL': `"${LOGGING_URL}"`,
'process.env.NODE_ENV': `"${NODE_ENV}"`,
Expand Down
3 changes: 3 additions & 0 deletions packages/react-devtools-inline/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ if (!NODE_ENV) {

const __DEV__ = NODE_ENV === 'development';

const EDITOR_URL = process.env.EDITOR_URL || null;

const DEVTOOLS_VERSION = getVersionString();

const babelOptions = {
Expand Down Expand Up @@ -76,6 +78,7 @@ module.exports = {
__TEST__: NODE_ENV === 'test',
'process.env.DEVTOOLS_PACKAGE': `"react-devtools-inline"`,
'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null,
'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
'process.env.NODE_ENV': `"${NODE_ENV}"`,
'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`,
Expand Down
3 changes: 3 additions & 0 deletions packages/react-devtools-shared/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ export const LOCAL_STORAGE_FILTER_PREFERENCES_KEY =
export const SESSION_STORAGE_LAST_SELECTION_KEY =
'React::DevTools::lastSelection';

export const LOCAL_STORAGE_OPEN_IN_EDITOR_URL =
'React::DevTools::openInEditorUrl';

export const LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY =
'React::DevTools::parseHookNames';

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export type IconType =
| 'copy'
| 'delete'
| 'down'
| 'editor'
| 'expanded'
| 'export'
| 'filter'
Expand Down Expand Up @@ -72,6 +73,9 @@ export default function ButtonIcon({className = '', type}: Props) {
case 'down':
pathData = PATH_DOWN;
break;
case 'editor':
pathData = PATH_EDITOR;
break;
case 'expanded':
pathData = PATH_EXPANDED;
break;
Expand Down Expand Up @@ -268,3 +272,7 @@ const PATH_VIEW_DOM = `
const PATH_VIEW_SOURCE = `
M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z
`;

const PATH_EDITOR = `
M7 5h10v2h2V3c0-1.1-.9-1.99-2-1.99L7 1c-1.1 0-2 .9-2 2v4h2V5zm8.41 11.59L20 12l-4.59-4.59L14 8.83 17.17 12 14 15.17l1.41 1.42zM10 15.17L6.83 12 10 8.83 8.59 7.41 4 12l4.59 4.59L10 15.17zM17 19H7v-2H5v4c0 1.1.9 2 2 2h10c1.1 0 2-.9 2-2v-4h-2v2z
`;
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
*/

import * as React from 'react';
import {useCallback, useContext} from 'react';
import {useCallback, useContext, useSyncExternalStore} from 'react';
import {TreeDispatcherContext, TreeStateContext} from './TreeContext';
import {BridgeContext, StoreContext, OptionsContext} from '../context';
import Button from '../Button';
Expand All @@ -20,6 +20,8 @@ import {ElementTypeSuspense} from 'react-devtools-shared/src/types';
import CannotSuspendWarningMessage from './CannotSuspendWarningMessage';
import InspectedElementView from './InspectedElementView';
import {InspectedElementContext} from './InspectedElementContext';
import {getOpenInEditorURL} from '../../../utils';
import {LOCAL_STORAGE_OPEN_IN_EDITOR_URL} from '../../../constants';

import styles from './InspectedElement.css';

Expand Down Expand Up @@ -123,6 +125,21 @@ export default function InspectedElementWrapper(_: Props) {
inspectedElement != null &&
inspectedElement.canToggleSuspense;

const editorURL = useSyncExternalStore(
function subscribe(callback) {
window.addEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback);
return function unsubscribe() {
window.removeEventListener(LOCAL_STORAGE_OPEN_IN_EDITOR_URL, callback);
};
},
function getState() {
return getOpenInEditorURL();
},
);

const canOpenInEditor =
editorURL && inspectedElement != null && inspectedElement.source != null;

const toggleErrored = useCallback(() => {
if (inspectedElement == null || targetErrorBoundaryID == null) {
return;
Expand Down Expand Up @@ -198,6 +215,18 @@ export default function InspectedElementWrapper(_: Props) {
}
}, [bridge, dispatch, element, isSuspended, modalDialogDispatch, store]);

const onOpenInEditor = useCallback(() => {
const source = inspectedElement?.source;
if (source == null || editorURL == null) {
return;
}

const url = new URL(editorURL);
url.href = url.href.replace('{path}', source.fileName);
url.href = url.href.replace('{line}', String(source.lineNumber));
window.open(url);
}, [inspectedElement, editorURL]);

if (element === null) {
return (
<div className={styles.InspectedElement}>
Expand All @@ -223,7 +252,14 @@ export default function InspectedElementWrapper(_: Props) {
{element.displayName}
</div>
</div>

{canOpenInEditor && (
<Button
className={styles.IconButton}
onClick={onOpenInEditor}
title="Open in editor">
<ButtonIcon type="editor" />
</Button>
)}
{canToggleError && (
<Toggle
className={styles.IconButton}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ import {
useRef,
useState,
} from 'react';
import {useSubscription} from '../hooks';
import {LOCAL_STORAGE_OPEN_IN_EDITOR_URL} from '../../../constants';
import {useLocalStorage, useSubscription} from '../hooks';
import {StoreContext} from '../context';
import Button from '../Button';
import ButtonIcon from '../ButtonIcon';
Expand All @@ -37,6 +38,7 @@ import {
ElementTypeProfiler,
ElementTypeSuspense,
} from 'react-devtools-shared/src/types';
import {getDefaultOpenInEditorURL} from 'react-devtools-shared/src/utils';

import styles from './SettingsShared.css';

Expand Down Expand Up @@ -81,6 +83,11 @@ export default function ComponentsSettings(_: {||}) {
[setParseHookNames],
);

const [openInEditorURL, setOpenInEditorURL] = useLocalStorage<string>(
LOCAL_STORAGE_OPEN_IN_EDITOR_URL,
getDefaultOpenInEditorURL(),
);

const [componentFilters, setComponentFilters] = useState<
Array<ComponentFilter>,
>(() => [...store.componentFilters]);
Expand Down Expand Up @@ -271,6 +278,19 @@ export default function ComponentsSettings(_: {||}) {
<span className={styles.Warning}>(may be slow)</span>
</label>

<label className={styles.OpenInURLSetting}>
Open in Editor URL:{' '}
<input
className={styles.Input}
type="text"
placeholder={process.env.EDITOR_URL ?? 'vscode://file/{path}:{line}'}
value={openInEditorURL}
onChange={event => {
setOpenInEditorURL(event.target.value);
}}
/>
</label>

<div className={styles.Header}>Hide components where...</div>

<table className={styles.Table}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@
margin-bottom: 0;
}

.OpenInURLSetting {
margin: 0.5rem 0;
}

.OptionGroup {
display: inline-flex;
flex-direction: row;
Expand All @@ -30,6 +34,10 @@
margin-right: 0.5rem;
}

.Spacer {
height: 0.5rem;
}

.Select {
}

Expand Down
3 changes: 3 additions & 0 deletions packages/react-devtools-shared/src/devtools/views/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,9 @@ export function useLocalStorage<T>(
value instanceof Function ? (value: any)(storedValue) : value;
setStoredValue(valueToStore);
localStorageSetItem(key, JSON.stringify(valueToStore));

// Notify listeners that this setting has changed.
window.dispatchEvent(new Event(key));
} catch (error) {
console.log(error);
}
Expand Down
17 changes: 17 additions & 0 deletions packages/react-devtools-shared/src/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import {
import {ElementTypeRoot} from 'react-devtools-shared/src/types';
import {
LOCAL_STORAGE_FILTER_PREFERENCES_KEY,
LOCAL_STORAGE_OPEN_IN_EDITOR_URL,
LOCAL_STORAGE_SHOULD_BREAK_ON_CONSOLE_ERRORS,
LOCAL_STORAGE_SHOULD_PATCH_CONSOLE_KEY,
LOCAL_STORAGE_SHOW_INLINE_WARNINGS_AND_ERRORS_KEY,
Expand Down Expand Up @@ -386,6 +387,22 @@ export function setShowInlineWarningsAndErrors(value: boolean): void {
);
}

export function getDefaultOpenInEditorURL(): string {
return typeof process.env.EDITOR_URL === 'string'
? process.env.EDITOR_URL
: '';
}

export function getOpenInEditorURL(): string {
try {
const raw = localStorageGetItem(LOCAL_STORAGE_OPEN_IN_EDITOR_URL);
if (raw != null) {
return JSON.parse(raw);
}
} catch (error) {}
return getDefaultOpenInEditorURL();
}

export function separateDisplayNameAndHOCs(
displayName: string | null,
type: ElementType,
Expand Down
3 changes: 3 additions & 0 deletions packages/react-devtools-shell/webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ if (!TARGET) {
process.exit(1);
}

const EDITOR_URL = process.env.EDITOR_URL || null;

const builtModulesDir = resolve(
__dirname,
'..',
Expand Down Expand Up @@ -69,6 +71,7 @@ const config = {
__PROFILE__: false,
__TEST__: NODE_ENV === 'test',
'process.env.GITHUB_URL': `"${GITHUB_URL}"`,
'process.env.EDITOR_URL': EDITOR_URL != null ? `"${EDITOR_URL}"` : null,
'process.env.DEVTOOLS_PACKAGE': `"react-devtools-shell"`,
'process.env.DEVTOOLS_VERSION': `"${DEVTOOLS_VERSION}"`,
'process.env.DARK_MODE_DIMMED_WARNING_COLOR': `"${DARK_MODE_DIMMED_WARNING_COLOR}"`,
Expand Down

0 comments on commit 0e48a88

Please sign in to comment.