chore: simplify settings management in UI mode (#32440)
This commit is contained in:
parent
b3d767fa14
commit
d7393f998e
|
|
@ -15,14 +15,19 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
import type { Setting } from '@web/uiUtils';
|
|
||||||
import './settingsView.css';
|
import './settingsView.css';
|
||||||
|
|
||||||
|
export type Setting<T> = {
|
||||||
|
value: T,
|
||||||
|
set: (value: T) => void,
|
||||||
|
title: string
|
||||||
|
};
|
||||||
|
|
||||||
export const SettingsView: React.FunctionComponent<{
|
export const SettingsView: React.FunctionComponent<{
|
||||||
settings: Setting<boolean>[],
|
settings: Setting<boolean>[],
|
||||||
}> = ({ settings }) => {
|
}> = ({ settings }) => {
|
||||||
return <div className='vbox settings-view'>
|
return <div className='vbox settings-view'>
|
||||||
{settings.map(([value, set, title]) => {
|
{settings.map(({ value, set, title }) => {
|
||||||
return <div key={title} className='setting'>
|
return <div key={title} className='setting'>
|
||||||
<label>
|
<label>
|
||||||
<input type='checkbox' checked={value} onClick={() => set(!value)}/>
|
<input type='checkbox' checked={value} onClick={() => set(!value)}/>
|
||||||
|
|
|
||||||
|
|
@ -100,36 +100,13 @@ export const UIModeView: React.FC<{}> = ({
|
||||||
const [testingOptionsVisible, setTestingOptionsVisible] = React.useState(false);
|
const [testingOptionsVisible, setTestingOptionsVisible] = React.useState(false);
|
||||||
const [revealSource, setRevealSource] = React.useState(false);
|
const [revealSource, setRevealSource] = React.useState(false);
|
||||||
const onRevealSource = React.useCallback(() => setRevealSource(true), [setRevealSource]);
|
const onRevealSource = React.useCallback(() => setRevealSource(true), [setRevealSource]);
|
||||||
|
|
||||||
const showTestingOptions = false;
|
const showTestingOptions = false;
|
||||||
|
const [singleWorker, setSingleWorker] = React.useState(queryParams.workers === '1');
|
||||||
const [runWorkers, setRunWorkers] = React.useState(queryParams.workers);
|
const [showBrowser, setShowBrowser] = React.useState(queryParams.headed);
|
||||||
const singleWorkerSetting = React.useMemo(() => {
|
const [updateSnapshots, setUpdateSnapshots] = React.useState(queryParams.updateSnapshots === 'all');
|
||||||
return [
|
const [showRouteActions, setShowRouteActions] = useSetting('show-route-actions', true);
|
||||||
runWorkers === '1',
|
const [darkMode, setDarkMode] = useDarkModeSetting();
|
||||||
(value: boolean) => {
|
|
||||||
// When started with `--workers=1`, the setting allows to undo that.
|
|
||||||
// Otherwise, fallback to the cli `--workers=X` argument.
|
|
||||||
setRunWorkers(value ? '1' : (queryParams.workers === '1' ? undefined : queryParams.workers));
|
|
||||||
},
|
|
||||||
'Single worker',
|
|
||||||
] as const;
|
|
||||||
}, [runWorkers, setRunWorkers]);
|
|
||||||
|
|
||||||
const [runHeaded, setRunHeaded] = React.useState(queryParams.headed);
|
|
||||||
const showBrowserSetting = React.useMemo(() => [runHeaded, setRunHeaded, 'Show browser'] as const, [runHeaded, setRunHeaded]);
|
|
||||||
|
|
||||||
const [runUpdateSnapshots, setRunUpdateSnapshots] = React.useState(queryParams.updateSnapshots);
|
|
||||||
const updateSnapshotsSetting = React.useMemo(() => {
|
|
||||||
return [
|
|
||||||
runUpdateSnapshots === 'all',
|
|
||||||
(value: boolean) => setRunUpdateSnapshots(value ? 'all' : 'missing'),
|
|
||||||
'Update snapshots',
|
|
||||||
] as const;
|
|
||||||
}, [runUpdateSnapshots, setRunUpdateSnapshots]);
|
|
||||||
|
|
||||||
const [, , showRouteActionsSetting] = useSetting('show-route-actions', true, 'Show route actions');
|
|
||||||
|
|
||||||
const darkModeSetting = useDarkModeSetting();
|
|
||||||
|
|
||||||
const inputRef = React.useRef<HTMLInputElement>(null);
|
const inputRef = React.useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
|
|
@ -309,11 +286,13 @@ export const UIModeView: React.FC<{}> = ({
|
||||||
grepInvert: queryParams.grepInvert,
|
grepInvert: queryParams.grepInvert,
|
||||||
testIds: [...testIds],
|
testIds: [...testIds],
|
||||||
projects: [...projectFilters].filter(([_, v]) => v).map(([p]) => p),
|
projects: [...projectFilters].filter(([_, v]) => v).map(([p]) => p),
|
||||||
workers: runWorkers,
|
// When started with `--workers=1`, the setting allows to undo that.
|
||||||
|
// Otherwise, fallback to the cli `--workers=X` argument.
|
||||||
|
workers: singleWorker ? '1' : (queryParams.workers === '1' ? undefined : queryParams.workers),
|
||||||
timeout: queryParams.timeout,
|
timeout: queryParams.timeout,
|
||||||
headed: runHeaded,
|
headed: showBrowser,
|
||||||
outputDir: queryParams.outputDir,
|
outputDir: queryParams.outputDir,
|
||||||
updateSnapshots: runUpdateSnapshots,
|
updateSnapshots: updateSnapshots ? 'all' : queryParams.updateSnapshots,
|
||||||
reporters: queryParams.reporters,
|
reporters: queryParams.reporters,
|
||||||
trace: 'on',
|
trace: 'on',
|
||||||
});
|
});
|
||||||
|
|
@ -325,7 +304,7 @@ export const UIModeView: React.FC<{}> = ({
|
||||||
setTestModel({ ...testModel });
|
setTestModel({ ...testModel });
|
||||||
setRunningState(oldState => oldState ? ({ ...oldState, completed: true }) : undefined);
|
setRunningState(oldState => oldState ? ({ ...oldState, completed: true }) : undefined);
|
||||||
});
|
});
|
||||||
}, [projectFilters, isRunningTest, testModel, testServerConnection, runWorkers, runHeaded, runUpdateSnapshots]);
|
}, [projectFilters, isRunningTest, testModel, testServerConnection, singleWorker, showBrowser, updateSnapshots]);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
if (!testServerConnection || !teleSuiteUpdater)
|
if (!testServerConnection || !teleSuiteUpdater)
|
||||||
|
|
@ -522,9 +501,9 @@ export const UIModeView: React.FC<{}> = ({
|
||||||
<div className='section-title'>Testing Options</div>
|
<div className='section-title'>Testing Options</div>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
{testingOptionsVisible && <SettingsView settings={[
|
{testingOptionsVisible && <SettingsView settings={[
|
||||||
singleWorkerSetting,
|
{ value: singleWorker, set: setSingleWorker, title: 'Single worker' },
|
||||||
showBrowserSetting,
|
{ value: showBrowser, set: setShowBrowser, title: 'Show browser' },
|
||||||
updateSnapshotsSetting,
|
{ value: updateSnapshots, set: setUpdateSnapshots, title: 'Update snapshots' },
|
||||||
]} />}
|
]} />}
|
||||||
</>}
|
</>}
|
||||||
<Toolbar noShadow={true} noMinHeight={true} className='settings-toolbar' onClick={() => setSettingsVisible(!settingsVisible)}>
|
<Toolbar noShadow={true} noMinHeight={true} className='settings-toolbar' onClick={() => setSettingsVisible(!settingsVisible)}>
|
||||||
|
|
@ -536,8 +515,8 @@ export const UIModeView: React.FC<{}> = ({
|
||||||
<div className='section-title'>Settings</div>
|
<div className='section-title'>Settings</div>
|
||||||
</Toolbar>
|
</Toolbar>
|
||||||
{settingsVisible && <SettingsView settings={[
|
{settingsVisible && <SettingsView settings={[
|
||||||
darkModeSetting,
|
{ value: darkMode, set: setDarkMode, title: 'Dark mode' },
|
||||||
showRouteActionsSetting,
|
{ value: showRouteActions, set: setShowRouteActions, title: 'Show route actions' },
|
||||||
]} />}
|
]} />}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -72,7 +72,7 @@ export const Workbench: React.FunctionComponent<{
|
||||||
const activeAction = model ? highlightedAction || selectedAction : undefined;
|
const activeAction = model ? highlightedAction || selectedAction : undefined;
|
||||||
const [selectedTime, setSelectedTime] = React.useState<Boundaries | undefined>();
|
const [selectedTime, setSelectedTime] = React.useState<Boundaries | undefined>();
|
||||||
const [sidebarLocation, setSidebarLocation] = useSetting<'bottom' | 'right'>('propertiesSidebarLocation', 'bottom');
|
const [sidebarLocation, setSidebarLocation] = useSetting<'bottom' | 'right'>('propertiesSidebarLocation', 'bottom');
|
||||||
const [showRouteActions, , showRouteActionsSetting] = useSetting('show-route-actions', true, 'Show route actions');
|
const [showRouteActions, setShowRouteActions] = useSetting('show-route-actions', true);
|
||||||
|
|
||||||
const filteredActions = React.useMemo(() => {
|
const filteredActions = React.useMemo(() => {
|
||||||
return (model?.actions || []).filter(action => showRouteActions || !isRouteAction(action));
|
return (model?.actions || []).filter(action => showRouteActions || !isRouteAction(action));
|
||||||
|
|
@ -299,7 +299,7 @@ export const Workbench: React.FunctionComponent<{
|
||||||
const settingsTab: TabbedPaneTabModel = {
|
const settingsTab: TabbedPaneTabModel = {
|
||||||
id: 'settings',
|
id: 'settings',
|
||||||
title: 'Settings',
|
title: 'Settings',
|
||||||
component: <SettingsView settings={[showRouteActionsSetting]}/>,
|
component: <SettingsView settings={[{ value: showRouteActions, set: setShowRouteActions, title: 'Show route actions' }]}/>,
|
||||||
};
|
};
|
||||||
|
|
||||||
return <div className='vbox workbench' {...(inert ? { inert: 'true' } : {})}>
|
return <div className='vbox workbench' {...(inert ? { inert: 'true' } : {})}>
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { type Setting, settings } from './uiUtils';
|
import { settings } from './uiUtils';
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface Document {
|
interface Document {
|
||||||
|
|
@ -68,12 +68,12 @@ export function currentTheme(): Theme {
|
||||||
return document.body.classList.contains('dark-mode') ? 'dark-mode' : 'light-mode';
|
return document.body.classList.contains('dark-mode') ? 'dark-mode' : 'light-mode';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useDarkModeSetting() {
|
export function useDarkModeSetting(): [boolean, (value: boolean) => void] {
|
||||||
const [theme, setTheme] = React.useState(currentTheme() === 'dark-mode');
|
const [theme, setTheme] = React.useState(currentTheme() === 'dark-mode');
|
||||||
return [theme, (value: boolean) => {
|
return [theme, (value: boolean) => {
|
||||||
const current = currentTheme() === 'dark-mode';
|
const current = currentTheme() === 'dark-mode';
|
||||||
if (current !== value)
|
if (current !== value)
|
||||||
toggleTheme();
|
toggleTheme();
|
||||||
setTheme(value);
|
setTheme(value);
|
||||||
}, 'Dark mode'] as Setting<boolean>;
|
}];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -139,10 +139,7 @@ export function copy(text: string) {
|
||||||
textArea.remove();
|
textArea.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Setting<T> = readonly [T, (value: T) => void, string];
|
export function useSetting<S>(name: string | undefined, defaultValue: S, title?: string): [S, React.Dispatch<React.SetStateAction<S>>] {
|
||||||
|
|
||||||
|
|
||||||
export function useSetting<S>(name: string | undefined, defaultValue: S, title?: string): [S, React.Dispatch<React.SetStateAction<S>>, Setting<S>] {
|
|
||||||
if (name)
|
if (name)
|
||||||
defaultValue = settings.getObject(name, defaultValue);
|
defaultValue = settings.getObject(name, defaultValue);
|
||||||
const [value, setValue] = React.useState<S>(defaultValue);
|
const [value, setValue] = React.useState<S>(defaultValue);
|
||||||
|
|
@ -160,9 +157,7 @@ export function useSetting<S>(name: string | undefined, defaultValue: S, title?:
|
||||||
return () => settings.onChangeEmitter.removeEventListener(name, onStoreChange);
|
return () => settings.onChangeEmitter.removeEventListener(name, onStoreChange);
|
||||||
}
|
}
|
||||||
}, [defaultValue, name]);
|
}, [defaultValue, name]);
|
||||||
|
return [value, setValueWrapper];
|
||||||
const setting = [value, setValueWrapper, title || name || ''] as Setting<S>;
|
|
||||||
return [value, setValueWrapper, setting];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue