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
1 change: 1 addition & 0 deletions res/css/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
--z-copy-table-warning: 4;
--z-tree-view: 0;
--z-tree-view-inner: 2;
--z-tree-view-header-divider: 1;
--z-overflow-edge-indicator: 3;
--z-chart-viewport-expanded: 1;
--z-timeline-selection: 1;
Expand Down
8 changes: 8 additions & 0 deletions src/actions/profile-view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ import {
import { changeStoredProfileNameInDb } from 'firefox-profiler/app-logic/uploaded-profiles-db';
import type { TabSlug } from '../app-logic/tabs-handling';
import type { CallNodeInfo } from '../profile-logic/call-node-info';
import type { SingleColumnSortState } from '../components/shared/TreeView';
import { intersectSets } from 'firefox-profiler/utils/set';

/**
Expand Down Expand Up @@ -1615,6 +1616,13 @@ export function changeMarkersSearchString(searchString: string): Action {
};
}

export function changeMarkerTableSort(sort: SingleColumnSortState[]): Action {
return {
type: 'CHANGE_MARKER_TABLE_SORT',
sort,
};
}

export function changeNetworkSearchString(searchString: string): Action {
return {
type: 'CHANGE_NETWORK_SEARCH_STRING',
Expand Down
62 changes: 61 additions & 1 deletion src/app-logic/url-handling.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,9 @@ import { tabSlugs } from '../app-logic/tabs-handling';
import { StringTable } from 'firefox-profiler/utils/string-table';
import type { ProfileUpgradeInfo } from 'firefox-profiler/profile-logic/processed-profile-versioning';
import type { ProfileAndProfileUpgradeInfo } from 'firefox-profiler/actions/receive-profile';
import type { SingleColumnSortState } from '../components/shared/TreeView';

export const CURRENT_URL_VERSION = 16;
export const CURRENT_URL_VERSION = 17;

/**
* This static piece of state might look like an anti-pattern, but it's a relatively
Expand Down Expand Up @@ -190,6 +191,7 @@ type CallTreeQuery = BaseQuery & {
type MarkersQuery = BaseQuery & {
markerSearch: string; // "DOMEvent"
marker?: MarkerIndex; // Selected marker index for the current thread, e.g. 42
markerSort?: string; // "duration:desc,start:asc" — primary first
};

type NetworkQuery = BaseQuery & {
Expand Down Expand Up @@ -228,6 +230,7 @@ type Query = BaseQuery & {
// Markers specific
markerSearch?: string;
marker?: MarkerIndex;
markerSort?: string;

// Network specific
networkSearch?: string;
Expand Down Expand Up @@ -394,6 +397,9 @@ export function getQueryStringFromUrlState(urlState: UrlState): string {
urlState.profileSpecific.selectedMarkers[selectedThreadsKey] !== null
? urlState.profileSpecific.selectedMarkers[selectedThreadsKey]
: undefined;
query.markerSort = convertMarkerTableSortToString(
urlState.profileSpecific.markerTableSort
);
break;
case 'network-chart':
query = baseQuery as NetworkQueryShape;
Expand Down Expand Up @@ -632,10 +638,59 @@ export function stateFromLocation(
? query.hiddenThreads.split('-').map((index) => Number(index))
: null,
selectedMarkers,
markerTableSort: convertMarkerTableSortFromString(query.markerSort),
},
};
}

// MarkerTable sort URL encoding. The internal ColumnSortState stores the
// primary-sorted column last (newest click wins as primary); the URL puts the
// primary first for human readability.
const VALID_MARKER_SORT_COLUMNS = new Set(['start', 'duration', 'name']);

function convertMarkerTableSortToString(
sort: SingleColumnSortState[]
): string | undefined {
if (sort.length === 0) {
return undefined;
}
// Omit when it matches the marker table's own default.
if (sort.length === 1 && sort[0].column === 'start' && sort[0].ascending) {
return undefined;
}
return sort
.slice()
.reverse()
.map((s) => `${s.column}-${s.ascending ? 'asc' : 'desc'}`)
.join('~');
}

function convertMarkerTableSortFromString(
raw: string | null | void
): SingleColumnSortState[] {
if (!raw) {
return [];
}
const parsed: SingleColumnSortState[] = [];
for (const part of raw.split('~')) {
const dashIndex = part.lastIndexOf('-');
if (dashIndex === -1) {
return [];
}
const column = part.slice(0, dashIndex);
const dir = part.slice(dashIndex + 1);
if (
!VALID_MARKER_SORT_COLUMNS.has(column) ||
(dir !== 'asc' && dir !== 'desc')
) {
return [];
}
parsed.push({ column, ascending: dir === 'asc' });
}
// URL is primary-first; internal storage is primary-last.
return parsed.reverse();
}

function convertGlobalTrackOrderFromString(
rawString: string | null | void
): TrackIndex[] {
Expand Down Expand Up @@ -1443,6 +1498,11 @@ const _upgraders: {
.join('~');
}
},
[17]: (_processedLocation: ProcessedLocationBeforeUpgrade) => {
// Adds the optional `markerSort` query parameter for the marker table.
// No migration is necessary: older URLs simply omit it and the default
// (sort by start ascending) is used.
},
};

/**
Expand Down
30 changes: 15 additions & 15 deletions src/components/calltree/CallTree.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ class CallTreeImpl extends PureComponent<Props> {
{
propName: 'totalPercent',
titleL10nId: '',
initialWidth: 50,
initialWidth: 55,
hideDividerAfter: true,
},
{
Expand All @@ -120,28 +120,28 @@ class CallTreeImpl extends PureComponent<Props> {
minWidth: 30,
initialWidth: 70,
resizable: true,
headerWidthAdjustment: 50,
headerWidthAdjustment: 55 /* totalPercent initialWidth */,
},
{
propName: 'self',
titleL10nId: 'CallTree--tracing-ms-self',
minWidth: 30,
initialWidth: 70,
minWidth: 40,
initialWidth: 80,
resizable: true,
},
{
propName: 'icon',
titleL10nId: '',
component: Icon as any,
initialWidth: 10,
initialWidth: 20,
},
];
case 'samples':
return [
{
propName: 'totalPercent',
titleL10nId: '',
initialWidth: 50,
initialWidth: 55,
hideDividerAfter: true,
},
{
Expand All @@ -150,28 +150,28 @@ class CallTreeImpl extends PureComponent<Props> {
minWidth: 30,
initialWidth: 70,
resizable: true,
headerWidthAdjustment: 50,
headerWidthAdjustment: 55 /* totalPercent initialWidth */,
},
{
propName: 'self',
titleL10nId: 'CallTree--samples-self',
minWidth: 30,
initialWidth: 70,
minWidth: 40,
initialWidth: 80,
resizable: true,
},
{
propName: 'icon',
titleL10nId: '',
component: Icon as any,
initialWidth: 10,
initialWidth: 20,
},
];
case 'bytes':
return [
{
propName: 'totalPercent',
titleL10nId: '',
initialWidth: 50,
initialWidth: 55,
hideDividerAfter: true,
},
{
Expand All @@ -180,20 +180,20 @@ class CallTreeImpl extends PureComponent<Props> {
minWidth: 30,
initialWidth: 140,
resizable: true,
headerWidthAdjustment: 50,
headerWidthAdjustment: 55 /* totalPercent initialWidth */,
},
{
propName: 'self',
titleL10nId: 'CallTree--bytes-self',
minWidth: 30,
initialWidth: 90,
minWidth: 40,
initialWidth: 100,
resizable: true,
},
{
propName: 'icon',
titleL10nId: '',
component: Icon as any,
initialWidth: 10,
initialWidth: 20,
},
];
default:
Expand Down
Loading
Loading