diff --git a/packages/trace-viewer/src/ui/workbench.tsx b/packages/trace-viewer/src/ui/workbench.tsx index 5e7639fcab..e0cd88fda0 100644 --- a/packages/trace-viewer/src/ui/workbench.tsx +++ b/packages/trace-viewer/src/ui/workbench.tsx @@ -32,6 +32,7 @@ import { AttachmentsTab } from './attachmentsTab'; import type { Boundaries } from '../geometry'; import { InspectorTab } from './inspectorTab'; import { ToolbarButton } from '@web/components/toolbarButton'; +import { useSetting } from '@web/uiUtils'; export const Workbench: React.FunctionComponent<{ model?: MultiTraceModel, @@ -51,6 +52,7 @@ export const Workbench: React.FunctionComponent<{ const [highlightedLocator, setHighlightedLocator] = React.useState(''); const activeAction = model ? highlightedAction || selectedAction : undefined; const [selectedTime, setSelectedTime] = React.useState(); + const [sidebarLocation, setSidebarLocation] = useSetting<'bottom' | 'right'>('propertiesSidebarLocation', 'bottom'); const sources = React.useMemo(() => model?.sources || new Map(), [model]); @@ -165,7 +167,7 @@ export const Workbench: React.FunctionComponent<{ setSelectedTime={setSelectedTime} /> - + - - + }}> + + + ]} + rightToolbar={[ + sidebarLocation === 'bottom' ? { + setSidebarLocation('right'); + }}> + + : { + setSidebarLocation('bottom'); + }}> + ]} /> diff --git a/packages/web/src/components/splitView.tsx b/packages/web/src/components/splitView.tsx index 636414729d..19952e89fc 100644 --- a/packages/web/src/components/splitView.tsx +++ b/packages/web/src/components/splitView.tsx @@ -14,17 +14,19 @@ limitations under the License. */ +import { useMeasure, useSetting } from '../uiUtils'; import './splitView.css'; import * as React from 'react'; -export interface SplitViewProps { - sidebarSize: number, - sidebarHidden?: boolean, - sidebarIsFirst?: boolean, - orientation?: 'vertical' | 'horizontal', - minSidebarSize?: number, - children: JSX.Element | JSX.Element[] | string, -} +export type SplitViewProps = { + sidebarSize: number; + sidebarHidden?: boolean; + sidebarIsFirst?: boolean; + orientation?: 'vertical' | 'horizontal'; + minSidebarSize?: number; + settingName?: string; + children: JSX.Element | JSX.Element[] | string; +}; const kMinSize = 50; @@ -34,10 +36,24 @@ export const SplitView: React.FC = ({ sidebarIsFirst = false, orientation = 'vertical', minSidebarSize = kMinSize, + settingName, children }) => { - const [size, setSize] = React.useState(Math.max(minSidebarSize, sidebarSize)); + const [hSize, setHSize] = useSetting(settingName ? settingName + '.' + orientation + ':size' : undefined, Math.max(minSidebarSize, sidebarSize)); + const [vSize, setVSize] = useSetting(settingName ? settingName + '.' + orientation + ':size' : undefined, Math.max(minSidebarSize, sidebarSize)); const [resizing, setResizing] = React.useState<{ offset: number, size: number } | null>(null); + const [measure, ref] = useMeasure(); + + let size: number; + if (orientation === 'vertical') { + size = vSize; + if (measure && measure.height < vSize) + size = measure.height - 10; + } else { + size = hSize; + if (measure && measure.width < hSize) + size = measure.width - 10; + } const childrenArray = React.Children.toArray(children); document.body.style.userSelect = resizing ? 'none' : 'inherit'; @@ -54,7 +70,7 @@ export const SplitView: React.FC = ({ resizerStyle = { right: resizing ? 0 : size - 4, left: resizing ? 0 : undefined, width: resizing ? 'initial' : 8 }; } - return
+ return
{childrenArray[0]}
{ !sidebarHidden &&
{childrenArray[1]}
} { !sidebarHidden &&
= ({ const splitView = (event.target as HTMLElement).parentElement!; const rect = splitView.getBoundingClientRect(); const size = Math.min(Math.max(minSidebarSize, newSize), (orientation === 'vertical' ? rect.height : rect.width) - minSidebarSize); - setSize(size); + if (orientation === 'vertical') + setVSize(size); + else + setHSize(size); } }} >
} diff --git a/packages/web/src/components/tabbedPane.tsx b/packages/web/src/components/tabbedPane.tsx index 2c0b9e205f..a23efd8e9a 100644 --- a/packages/web/src/components/tabbedPane.tsx +++ b/packages/web/src/components/tabbedPane.tsx @@ -34,18 +34,24 @@ export const TabbedPane: React.FunctionComponent<{ }> = ({ tabs, selectedTab, setSelectedTab, leftToolbar, rightToolbar }) => { return
- {[ - ...leftToolbar || [], - ...tabs.map(tab => ( - )), -
, - ...rightToolbar || [], - ]}
+ +
+ {...leftToolbar || []} +
+
+ {[...tabs.map(tab => ( + )), + ]} +
+
+ {...rightToolbar || []} +
+
{ tabs.map(tab => { if (tab.component) diff --git a/packages/web/src/uiUtils.ts b/packages/web/src/uiUtils.ts index b092ad0614..1d037a6323 100644 --- a/packages/web/src/uiUtils.ts +++ b/packages/web/src/uiUtils.ts @@ -117,11 +117,12 @@ export function copy(text: string) { textArea.remove(); } -export function useSetting(name: string, defaultValue: S): [S, React.Dispatch>] { - const value = settings.getObject(name, defaultValue); +export function useSetting(name: string | undefined, defaultValue: S): [S, React.Dispatch>] { + const value = name ? settings.getObject(name, defaultValue) : defaultValue; const [state, setState] = React.useState(value); const setStateWrapper = (value: React.SetStateAction) => { - settings.setObject(name, value); + if (name) + settings.setObject(name, value); setState(value); }; return [state, setStateWrapper];