chore(trace-viewer): preserve column widths after showing resource details (#31093)

* Column widths are now stored on in the NetworkPanel context, this way
they are not reset after selecting an empty range (and changing position
of the NetworkGridView in the component tree).
* Column widths values are now preserved if column set changes (e.g.
selecting entries from a single context and then from multiple
contexts).
This commit is contained in:
Yury Semikhatsky 2024-05-30 12:21:32 -07:00 committed by GitHub
parent f97d87ea5a
commit 4c020c9861
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 40 additions and 15 deletions

View File

@ -76,6 +76,10 @@ export const NetworkTab: React.FunctionComponent<{
return { renderedEntries };
}, [networkModel.resources, networkModel.contextIdMap, sorting, boundaries]);
const [widths, setWidths] = React.useState<Map<ColumnName, number>>(() => {
return new Map(allColumns().map(column => [column, columnWidth(column)]));
});
if (!networkModel.resources.length)
return <PlaceholderPanel text='No network calls' />;
@ -87,7 +91,8 @@ export const NetworkTab: React.FunctionComponent<{
onHighlighted={item => onEntryHovered(item?.resource)}
columns={visibleColumns(!!selectedEntry, renderedEntries)}
columnTitle={columnTitle}
columnWidth={columnWidth}
columnWidths={widths}
setColumnWidths={setWidths}
isError={item => item.status.code >= 400}
isInfo={item => !!item.route}
render={(item, column) => renderCell(item, column)}
@ -96,7 +101,7 @@ export const NetworkTab: React.FunctionComponent<{
/>;
return <>
{!selectedEntry && grid}
{selectedEntry && <SplitView sidebarSize={200} sidebarIsFirst={true} orientation='horizontal'>
{selectedEntry && <SplitView sidebarSize={widths.get('name')!} sidebarIsFirst={true} orientation='horizontal' settingName='networkResourceDetails'>
<NetworkResourceDetails resource={selectedEntry.resource} onClose={() => setSelectedEntry(undefined)} />
{grid}
</SplitView>}
@ -142,13 +147,16 @@ const columnWidth = (column: ColumnName) => {
function visibleColumns(entrySelected: boolean, renderedEntries: RenderedEntry[]): (keyof RenderedEntry)[] {
if (entrySelected)
return ['name'];
const columns: (keyof RenderedEntry)[] = [];
if (hasMultipleContexts(renderedEntries))
columns.push('contextId');
columns.push('name', 'method', 'status', 'contentType', 'duration', 'size', 'start', 'route');
let columns: (keyof RenderedEntry)[] = allColumns();
if (!hasMultipleContexts(renderedEntries))
columns = columns.filter(name => name !== 'contextId');
return columns;
}
function allColumns(): (keyof RenderedEntry)[] {
return ['contextId', 'name', 'method', 'status', 'contentType', 'duration', 'size', 'start', 'route'];
}
const renderCell = (entry: RenderedEntry, column: ColumnName): RenderedGridCell => {
if (column === 'contextId') {
return {

View File

@ -30,19 +30,34 @@ export type RenderedGridCell = {
export type GridViewProps<T> = Omit<ListViewProps<T>, 'render'> & {
columns: (keyof T)[],
columnTitle: (column: keyof T) => string,
columnWidth: (column: keyof T) => number,
columnWidths: Map<keyof T, number>,
setColumnWidths: (widths: Map<keyof T, number>) => void,
render: (item: T, column: keyof T, index: number) => RenderedGridCell,
sorting?: Sorting<T>,
setSorting?: (sorting: Sorting<T> | undefined) => void,
};
export function GridView<T>(model: GridViewProps<T>) {
const initialOffsets: number[] = [];
for (let i = 0; i < model.columns.length - 1; ++i) {
const column = model.columns[i];
initialOffsets[i] = (initialOffsets[i - 1] || 0) + model.columnWidth(column);
const [offsets, setOffsets] = React.useState<number[]>([]);
React.useEffect(() => {
const offsets: number[] = [];
for (let i = 0; i < model.columns.length - 1; ++i) {
const column = model.columns[i];
offsets[i] = (offsets[i - 1] || 0) + model.columnWidths.get(column)!;
}
setOffsets(offsets);
}, [model.columns, model.columnWidths]);
function updateWidths(offsets: number[]) {
const widths = new Map(model.columnWidths.entries());
for (let i = 0; i < offsets.length; ++i) {
const width = offsets[i] - (offsets[i - 1] || 0);
const column = model.columns[i];
widths.set(column, width);
}
model.setColumnWidths(widths);
}
const [offsets, setOffsets] = React.useState<number[]>(initialOffsets);
const toggleSorting = React.useCallback((f: keyof T) => {
model.setSorting?.({ by: f, negate: model.sorting?.by === f ? !model.sorting.negate : false });
@ -52,7 +67,7 @@ export function GridView<T>(model: GridViewProps<T>) {
<ResizeView
orientation={'horizontal'}
offsets={offsets}
setOffsets={setOffsets}
setOffsets={updateWidths}
resizerColor='var(--vscode-panel-border)'
resizerWidth={1}
minColumnWidth={25}>
@ -63,7 +78,7 @@ export function GridView<T>(model: GridViewProps<T>) {
return <div
className={'grid-view-header-cell ' + sortingHeader(column, model.sorting)}
style={{
width: offsets[i] - (offsets[i - 1] || 0),
width: i < model.columns.length - 1 ? model.columnWidths.get(column) : undefined,
}}
onClick={() => model.setSorting && toggleSorting(column)}
>
@ -84,7 +99,9 @@ export function GridView<T>(model: GridViewProps<T>) {
return <div
className={`grid-view-cell grid-view-column-${String(column)}`}
title={title}
style={{ width: offsets[i] - (offsets[i - 1] || 0) }}>
style={{
width: i < model.columns.length - 1 ? model.columnWidths.get(column) : undefined,
}}>
{body}
</div>;
})}