Skip to content

Commit 1a6bfde

Browse files
committed
[DevTools] Add settings to hide Profiler and Suspense tabs
1 parent 1b45e24 commit 1a6bfde

8 files changed

Lines changed: 142 additions & 13 deletions

File tree

packages/react-devtools-extensions/src/main/index.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ import {
2222
} from 'react-devtools-shared/src/storage';
2323
import DevTools from 'react-devtools-shared/src/devtools/views/DevTools';
2424
import {
25+
LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY,
26+
LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY,
2527
LOCAL_STORAGE_SUPPORTS_PROFILING_KEY,
2628
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
2729
} from 'react-devtools-shared/src/constants';
@@ -351,6 +353,10 @@ function createProfilerPanel() {
351353
return;
352354
}
353355

356+
if (localStorageGetItem(LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY) === 'true') {
357+
return;
358+
}
359+
354360
chrome.devtools.panels.create(
355361
__IS_CHROME__ || __IS_EDGE__ ? 'Profiler ⚛' : 'Profiler',
356362
__IS_EDGE__ ? 'icons/production.svg' : '',
@@ -427,6 +433,10 @@ function createSuspensePanel() {
427433
return;
428434
}
429435

436+
if (localStorageGetItem(LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY) === 'true') {
437+
return;
438+
}
439+
430440
chrome.devtools.panels.create(
431441
__IS_CHROME__ || __IS_EDGE__ ? 'Suspense ⚛' : 'Suspense',
432442
__IS_EDGE__ ? 'icons/production.svg' : '',

packages/react-devtools-shared/src/constants.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ export const LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY =
6666
'React::DevTools::traceUpdatesEnabled';
6767
export const LOCAL_STORAGE_SUPPORTS_PROFILING_KEY =
6868
'React::DevTools::supportsProfiling';
69+
export const LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY =
70+
'React::DevTools::hideProfilerTab';
71+
export const LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY =
72+
'React::DevTools::hideSuspenseTab';
6973

7074
export const PROFILER_EXPORT_VERSION = 5;
7175

packages/react-devtools-shared/src/devtools/views/DevTools.js

Lines changed: 57 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,14 @@ import '@reach/menu-button/styles.css';
1313
import '@reach/tooltip/styles.css';
1414

1515
import * as React from 'react';
16-
import {useCallback, useEffect, useLayoutEffect, useMemo, useRef} from 'react';
16+
import {
17+
useCallback,
18+
useContext,
19+
useEffect,
20+
useLayoutEffect,
21+
useMemo,
22+
useRef,
23+
} from 'react';
1724
import Store from '../store';
1825
import {
1926
BridgeContext,
@@ -27,7 +34,10 @@ import SuspenseTab from './SuspenseTab/SuspenseTab';
2734
import TabBar from './TabBar';
2835
import EditorPane from './Editor/EditorPane';
2936
import InspectedElementPane from './InspectedElement/InspectedElementPane';
30-
import {SettingsContextController} from './Settings/SettingsContext';
37+
import {
38+
SettingsContext,
39+
SettingsContextController,
40+
} from './Settings/SettingsContext';
3141
import {TreeContextController} from './Components/TreeContext';
3242
import ViewElementSourceContext from './Components/ViewElementSourceContext';
3343
import FetchFileWithCachingContext from './Components/FetchFileWithCachingContext';
@@ -135,7 +145,46 @@ const suspenseTab = {
135145
title: 'React Suspense',
136146
};
137147

138-
const tabs = [componentsTab, profilerTab, suspenseTab];
148+
const allTabs = [componentsTab, profilerTab, suspenseTab];
149+
150+
function DevToolsNavigationTabBar({
151+
currentTab,
152+
selectTab,
153+
}: {
154+
currentTab: TabID,
155+
selectTab: (tabId: TabID) => void,
156+
}): React.Node {
157+
const {hideProfilerTab, hideSuspenseTab} = useContext(SettingsContext);
158+
const visibleTabs = useMemo(
159+
() =>
160+
allTabs.filter(
161+
t =>
162+
!(hideProfilerTab && t.id === 'profiler') &&
163+
!(hideSuspenseTab && t.id === 'suspense'),
164+
),
165+
[hideProfilerTab, hideSuspenseTab],
166+
);
167+
168+
// If the active tab is hidden, switch to components
169+
useEffect(() => {
170+
if (
171+
(hideProfilerTab && currentTab === 'profiler') ||
172+
(hideSuspenseTab && currentTab === 'suspense')
173+
) {
174+
selectTab('components');
175+
}
176+
}, [hideProfilerTab, hideSuspenseTab, currentTab, selectTab]);
177+
178+
return (
179+
<TabBar
180+
currentTab={currentTab}
181+
id="DevTools"
182+
selectTab={selectTab}
183+
tabs={visibleTabs}
184+
type="navigation"
185+
/>
186+
);
187+
}
139188

140189
export default function DevTools({
141190
bridge,
@@ -248,18 +297,18 @@ export default function DevTools({
248297
if (event.ctrlKey || event.metaKey) {
249298
switch (event.key) {
250299
case '1':
251-
selectTab(tabs[0].id);
300+
selectTab(allTabs[0].id);
252301
event.preventDefault();
253302
event.stopPropagation();
254303
break;
255304
case '2':
256-
selectTab(tabs[1].id);
305+
selectTab(allTabs[1].id);
257306
event.preventDefault();
258307
event.stopPropagation();
259308
break;
260309
case '3':
261-
if (tabs.length > 2) {
262-
selectTab(tabs[2].id);
310+
if (allTabs.length > 2) {
311+
selectTab(allTabs[2].id);
263312
event.preventDefault();
264313
event.stopPropagation();
265314
}
@@ -321,12 +370,9 @@ export default function DevTools({
321370
{process.env.DEVTOOLS_VERSION}
322371
</span>
323372
<div className={styles.Spacer} />
324-
<TabBar
373+
<DevToolsNavigationTabBar
325374
currentTab={tab}
326-
id="DevTools"
327375
selectTab={selectTab}
328-
tabs={tabs}
329-
type="navigation"
330376
/>
331377
</div>
332378
)}

packages/react-devtools-shared/src/devtools/views/Settings/GeneralSettings.js

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,9 @@ function getChangeLogUrl(version: ?string): string | null {
3737
export default function GeneralSettings(_: {}): React.Node {
3838
const {
3939
displayDensity,
40+
hideSuspenseTab,
4041
setDisplayDensity,
42+
setHideSuspenseTab,
4143
setTheme,
4244
setTraceUpdatesEnabled,
4345
theme,
@@ -120,6 +122,26 @@ export default function GeneralSettings(_: {}): React.Node {
120122
</div>
121123
)}
122124

125+
<div className={styles.SettingWrapper}>
126+
<label className={styles.SettingRow}>
127+
<input
128+
type="checkbox"
129+
checked={hideSuspenseTab}
130+
onChange={({currentTarget}) =>
131+
setHideSuspenseTab(currentTarget.checked)
132+
}
133+
className={styles.SettingRowCheckbox}
134+
/>
135+
Hide Suspense tab
136+
</label>
137+
{hideSuspenseTab && (
138+
<div className={styles.SettingHint}>
139+
The Suspense tab will be hidden when DevTools is opened in a new
140+
tab, or when DevTools is reopened in the current tab.
141+
</div>
142+
)}
143+
</div>
144+
123145
<div className={styles.ReleaseNotes}>
124146
{showBackendVersion && (
125147
<div>

packages/react-devtools-shared/src/devtools/views/Settings/ProfilerSettings.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import * as React from 'react';
1111
import {useCallback, useContext, useMemo, useRef} from 'react';
1212
import {useSubscription} from '../hooks';
1313
import {StoreContext} from '../context';
14+
import {SettingsContext} from './SettingsContext';
1415
import {ProfilerContext} from 'react-devtools-shared/src/devtools/views/Profiler/ProfilerContext';
1516

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

2830
const recordChangeDescriptionsSubscription = useMemo(
@@ -102,6 +104,25 @@ export default function ProfilerSettings(_: {}): React.Node {
102104
&nbsp;(ms)
103105
</label>
104106
</div>
107+
<div className={styles.SettingWrapper}>
108+
<label className={styles.SettingRow}>
109+
<input
110+
type="checkbox"
111+
checked={hideProfilerTab}
112+
onChange={({currentTarget}) =>
113+
setHideProfilerTab(currentTarget.checked)
114+
}
115+
className={styles.SettingRowCheckbox}
116+
/>
117+
Hide Profiler tab
118+
</label>
119+
{hideProfilerTab && (
120+
<div className={styles.SettingHint}>
121+
The Profiler tab will be hidden when DevTools is opened in a new
122+
tab, or when DevTools is reopened in the current tab.
123+
</div>
124+
)}
125+
</div>
105126
</div>
106127
);
107128
}

packages/react-devtools-shared/src/devtools/views/Settings/SettingsContext.js

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import {
1919
} from 'react';
2020
import {
2121
LOCAL_STORAGE_BROWSER_THEME,
22+
LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY,
23+
LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY,
2224
LOCAL_STORAGE_PARSE_HOOK_NAMES_KEY,
2325
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
2426
} from 'react-devtools-shared/src/constants';
@@ -53,6 +55,12 @@ type Context = {
5355

5456
traceUpdatesEnabled: boolean,
5557
setTraceUpdatesEnabled: (value: boolean) => void,
58+
59+
hideProfilerTab: boolean,
60+
setHideProfilerTab: (value: boolean) => void,
61+
62+
hideSuspenseTab: boolean,
63+
setHideSuspenseTab: (value: boolean) => void,
5664
};
5765

5866
const SettingsContext: ReactContext<Context> = createContext<Context>(
@@ -113,6 +121,10 @@ function SettingsContextController({
113121
LOCAL_STORAGE_TRACE_UPDATES_ENABLED_KEY,
114122
false,
115123
);
124+
const [hideProfilerTab, setHideProfilerTab] =
125+
useLocalStorageWithLog<boolean>(LOCAL_STORAGE_HIDE_PROFILER_TAB_KEY, false);
126+
const [hideSuspenseTab, setHideSuspenseTab] =
127+
useLocalStorageWithLog<boolean>(LOCAL_STORAGE_HIDE_SUSPENSE_TAB_KEY, false);
116128

117129
const documentElements = useMemo<DocumentElements>(() => {
118130
const array: Array<HTMLElement> = [
@@ -183,8 +195,12 @@ function SettingsContextController({
183195
displayDensity === 'compact'
184196
? COMPACT_LINE_HEIGHT
185197
: COMFORTABLE_LINE_HEIGHT,
198+
hideProfilerTab,
199+
hideSuspenseTab,
186200
parseHookNames,
187201
setDisplayDensity,
202+
setHideProfilerTab,
203+
setHideSuspenseTab,
188204
setParseHookNames,
189205
setTheme,
190206
setTraceUpdatesEnabled,
@@ -194,8 +210,12 @@ function SettingsContextController({
194210
}),
195211
[
196212
displayDensity,
213+
hideProfilerTab,
214+
hideSuspenseTab,
197215
parseHookNames,
198216
setDisplayDensity,
217+
setHideProfilerTab,
218+
setHideSuspenseTab,
199219
setParseHookNames,
200220
setTheme,
201221
setTraceUpdatesEnabled,

packages/react-devtools-shared/src/devtools/views/Settings/SettingsModal.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ function SettingsModalImpl({store}: ImplProps) {
109109
currentTab={selectedTabID}
110110
id="Settings"
111111
selectTab={selectTab}
112-
tabs={tabs}
112+
tabs={allTabs}
113113
type="settings"
114114
/>
115115
<div className={styles.Spacer} />
@@ -123,7 +123,7 @@ function SettingsModalImpl({store}: ImplProps) {
123123
);
124124
}
125125

126-
const tabs = [
126+
const allTabs = [
127127
{
128128
id: 'general',
129129
icon: 'settings',

packages/react-devtools-shared/src/devtools/views/Settings/SettingsShared.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,12 @@
7373
margin-right: 0.25rem;
7474
}
7575

76+
.SettingHint {
77+
font-size: var(--font-size-sans-small);
78+
color: var(--color-dim);
79+
margin-top: 0.25rem;
80+
}
81+
7682
.NoFiltersCell {
7783
padding: 0.25rem 0;
7884
color: var(--color-dim);

0 commit comments

Comments
 (0)