Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions packages/react-devtools-extensions/src/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import {
} from 'react-devtools-shared/src/storage';
import DevTools from 'react-devtools-shared/src/devtools/views/DevTools';
import {
LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY,
LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY,
LOCAL_STORAGE_SUPPORTS_PROFILING_KEY,
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
} from 'react-devtools-shared/src/constants';
Expand Down Expand Up @@ -351,6 +353,10 @@ function createProfilerPanel() {
return;
}

if (localStorageGetItem(LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY) === 'true') {
return;
}

chrome.devtools.panels.create(
__IS_CHROME__ || __IS_EDGE__ ? 'Profiler ⚛' : 'Profiler',
__IS_EDGE__ ? 'icons/production.svg' : '',
Expand Down Expand Up @@ -427,6 +433,10 @@ function createSuspensePanel() {
return;
}

if (localStorageGetItem(LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY) === 'true') {
return;
}

chrome.devtools.panels.create(
__IS_CHROME__ || __IS_EDGE__ ? 'Suspense ⚛' : 'Suspense',
__IS_EDGE__ ? 'icons/production.svg' : '',
Expand Down
4 changes: 4 additions & 0 deletions packages/react-devtools-shared/src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,10 @@ export const LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY =
'React::DevTools::traceUpdatesEnabled';
export const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY =
'React::DevTools::supportsProfiling';
export const LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY =
'React::DevTools::hideProfilerTab';
export const LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY =
'React::DevTools::hideSuspenseTab';

export const PROFILER_EXPORT_VERSION = 5;

Expand Down
119 changes: 73 additions & 46 deletions packages/react-devtools-shared/src/devtools/views/DevTools.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,14 @@ import '@reach/menu-button/styles.css';
import '@reach/tooltip/styles.css';

import * as React from 'react';
import {useCallback, useEffect, useLayoutEffect, useMemo, useRef} from 'react';
import {
useCallback,
useContext,
useEffect,
useLayoutEffect,
useMemo,
useRef,
} from 'react';
import Store from '../store';
import {
BridgeContext,
Expand All @@ -27,7 +34,10 @@ import SuspenseTab from './SuspenseTab/SuspenseTab';
import TabBar from './TabBar';
import EditorPane from './Editor/EditorPane';
import InspectedElementPane from './InspectedElement/InspectedElementPane';
import {SettingsContextController} from './Settings/SettingsContext';
import {
SettingsContext,
SettingsContextController,
} from './Settings/SettingsContext';
import {TreeContextController} from './Components/TreeContext';
import ViewElementSourceContext from './Components/ViewElementSourceContext';
import FetchFileWithCachingContext from './Components/FetchFileWithCachingContext';
Expand Down Expand Up @@ -135,7 +145,64 @@ const suspenseTab = {
title: 'React Suspense',
};

const tabs = [componentsTab, profilerTab, suspenseTab];
const allTabs = [componentsTab, profilerTab, suspenseTab];

function DevToolsNavigationTabBar({
currentTab,
selectTab,
}: {
currentTab: TabID,
selectTab: (tabId: TabID) => void,
}): React.Node {
const {hideProfilerTab, hideSuspenseTab} = useContext(SettingsContext);
const visibleTabs = useMemo(
() =>
allTabs.filter(
t =>
!(hideProfilerTab && t.id === 'profiler') &&
!(hideSuspenseTab && t.id === 'suspense'),
),
[hideProfilerTab, hideSuspenseTab],
);

// If the active tab is hidden, switch to components
useEffect(() => {
if (
(hideProfilerTab && currentTab === 'profiler') ||
(hideSuspenseTab && currentTab === 'suspense')
) {
selectTab('components');
}
}, [hideProfilerTab, hideSuspenseTab, currentTab, selectTab]);

// Override keyboard shortcuts to use visible tabs only
useEffect(() => {
const handleKeyDown = (event: KeyboardEvent) => {
if (event.ctrlKey || event.metaKey) {
const tabIndex = parseInt(event.key, 10) - 1;
if (tabIndex >= 0 && tabIndex < visibleTabs.length) {
selectTab(visibleTabs[tabIndex].id);
event.preventDefault();
event.stopPropagation();
}
}
};
window.addEventListener('keydown', handleKeyDown);
return () => {
window.removeEventListener('keydown', handleKeyDown);
};
}, [visibleTabs, selectTab]);

return (
<TabBar
currentTab={currentTab}
id="DevTools"
selectTab={selectTab}
tabs={visibleTabs}
type="navigation"
/>
);
}

export default function DevTools({
bridge,
Expand Down Expand Up @@ -233,45 +300,8 @@ export default function DevTools({

const devToolsRef = useRef<HTMLElement | null>(null);

useEffect(() => {
if (!showTabBar) {
return;
}

const div = devToolsRef.current;
if (div === null) {
return;
}

const ownerWindow = div.ownerDocument.defaultView;
const handleKeyDown = (event: KeyboardEvent) => {
if (event.ctrlKey || event.metaKey) {
switch (event.key) {
case '1':
selectTab(tabs[0].id);
event.preventDefault();
event.stopPropagation();
break;
case '2':
selectTab(tabs[1].id);
event.preventDefault();
event.stopPropagation();
break;
case '3':
if (tabs.length > 2) {
selectTab(tabs[2].id);
event.preventDefault();
event.stopPropagation();
}
break;
}
}
};
ownerWindow.addEventListener('keydown', handleKeyDown);
return () => {
ownerWindow.removeEventListener('keydown', handleKeyDown);
};
}, [showTabBar]);
// Keyboard shortcuts (Ctrl/Cmd+1/2/3) are handled in
// DevToolsNavigationTabBar to operate on visible tabs only.

useLayoutEffect(() => {
return () => {
Expand Down Expand Up @@ -321,12 +351,9 @@ export default function DevTools({
{process.env.DEVTOOLS_VERSION}
</span>
<div className={styles.Spacer} />
<TabBar
<DevToolsNavigationTabBar
currentTab={tab}
id="DevTools"
selectTab={selectTab}
tabs={tabs}
type="navigation"
/>
</div>
)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ function getChangeLogUrl(version: ?string): string | null {
export default function GeneralSettings(_: {}): React.Node {
const {
displayDensity,
hideSuspenseTab,
setDisplayDensity,
setHideSuspenseTab,
setTheme,
setTraceUpdatesEnabled,
theme,
Expand Down Expand Up @@ -120,6 +122,26 @@ export default function GeneralSettings(_: {}): React.Node {
</div>
)}

<div className={styles.SettingWrapper}>
<label className={styles.SettingRow}>
<input
type="checkbox"
checked={hideSuspenseTab}
onChange={({currentTarget}) =>
setHideSuspenseTab(currentTarget.checked)
}
className={styles.SettingRowCheckbox}
/>
Hide Suspense tab
</label>
{hideSuspenseTab && (
<div className={styles.SettingHint}>
The Suspense tab will be hidden when DevTools is opened in a new
tab, or when DevTools is reopened in the current tab.
</div>
)}
</div>

<div className={styles.ReleaseNotes}>
{showBackendVersion && (
<div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import * as React from 'react';
import {useCallback, useContext, useMemo, useRef} from 'react';
import {useSubscription} from '../hooks';
import {StoreContext} from '../context';
import {SettingsContext} from './SettingsContext';
import {ProfilerContext} from 'react-devtools-shared/src/devtools/views/Profiler/ProfilerContext';

import styles from './SettingsShared.css';
Expand All @@ -23,6 +24,7 @@ export default function ProfilerSettings(_: {}): React.Node {
setIsCommitFilterEnabled,
setMinCommitDuration,
} = useContext(ProfilerContext);
const {hideProfilerTab, setHideProfilerTab} = useContext(SettingsContext);
const store = useContext(StoreContext);

const recordChangeDescriptionsSubscription = useMemo(
Expand Down Expand Up @@ -102,6 +104,25 @@ export default function ProfilerSettings(_: {}): React.Node {
&nbsp;(ms)
</label>
</div>
<div className={styles.SettingWrapper}>
<label className={styles.SettingRow}>
<input
type="checkbox"
checked={hideProfilerTab}
onChange={({currentTarget}) =>
setHideProfilerTab(currentTarget.checked)
}
className={styles.SettingRowCheckbox}
/>
Hide Profiler tab
</label>
{hideProfilerTab && (
<div className={styles.SettingHint}>
The Profiler tab will be hidden when DevTools is opened in a new
tab, or when DevTools is reopened in the current tab.
</div>
)}
</div>
</div>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import {
} from 'react';
import {
LOCAL_STORAGE_BROWSER_THEME,
LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY,
LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY,
LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY,
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
} from 'react-devtools-shared/src/constants';
Expand Down Expand Up @@ -53,6 +55,12 @@ type Context = {

traceUpdatesEnabled: boolean,
setTraceUpdatesEnabled: (value: boolean) => void,

hideProfilerTab: boolean,
setHideProfilerTab: (value: boolean) => void,

hideSuspenseTab: boolean,
setHideSuspenseTab: (value: boolean) => void,
};

const SettingsContext: ReactContext<Context> = createContext<Context>(
Expand Down Expand Up @@ -113,6 +121,10 @@ function SettingsContextController({
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
false,
);
const [hideProfilerTab, setHideProfilerTab] =
useLocalStorageWithLog<boolean>(LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY, false);
const [hideSuspenseTab, setHideSuspenseTab] =
useLocalStorageWithLog<boolean>(LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY, false);

const documentElements = useMemo<DocumentElements>(() => {
const array: Array<HTMLElement> = [
Expand Down Expand Up @@ -183,8 +195,12 @@ function SettingsContextController({
displayDensity === 'compact'
? COMPACT_LINE_HEIGHT
: COMFORTABLE_LINE_HEIGHT,
hideProfilerTab,
hideSuspenseTab,
parseHookNames,
setDisplayDensity,
setHideProfilerTab,
setHideSuspenseTab,
setParseHookNames,
setTheme,
setTraceUpdatesEnabled,
Expand All @@ -194,8 +210,12 @@ function SettingsContextController({
}),
[
displayDensity,
hideProfilerTab,
hideSuspenseTab,
parseHookNames,
setDisplayDensity,
setHideProfilerTab,
setHideSuspenseTab,
setParseHookNames,
setTheme,
setTraceUpdatesEnabled,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ function SettingsModalImpl({store}: ImplProps) {
currentTab={selectedTabID}
id="Settings"
selectTab={selectTab}
tabs={tabs}
tabs={allTabs}
type="settings"
/>
<div className={styles.Spacer} />
Expand All @@ -123,7 +123,7 @@ function SettingsModalImpl({store}: ImplProps) {
);
}

const tabs = [
const allTabs = [
{
id: 'general',
icon: 'settings',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@
margin-right: 0.25rem;
}

.SettingHint {
font-size: var(--font-size-sans-small);
color: var(--color-dim);
margin-top: 0.25rem;
}

.NoFiltersCell {
padding: 0.25rem 0;
color: var(--color-dim);
Expand Down