Skip to content

Commit 9faf5e8

Browse files
committed
Make it possible to override the zeroAt value
1 parent d07c28b commit 9faf5e8

File tree

12 files changed

+152
-3
lines changed

12 files changed

+152
-3
lines changed

locales/en-US/app.ftl

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,8 @@ MarkerContextMenu--end-selection-at-marker-start =
438438
End selection at marker’s <strong>start</strong>
439439
MarkerContextMenu--end-selection-at-marker-end =
440440
End selection at marker’s <strong>end</strong>
441+
MarkerContextMenu--override-zero-at-marker-start =
442+
Override zero at marker’s start
441443
MarkerContextMenu--copy-description = Copy description
442444
MarkerContextMenu--copy-call-stack = Copy call stack
443445
MarkerContextMenu--copy-url = Copy URL
@@ -681,6 +683,12 @@ MenuButtons--publish--download = Download
681683
MenuButtons--publish--compressing = Compressing…
682684
MenuButtons--publish--error-while-compressing = Error while compressing, try unchecking some checkboxes to reduce the profile size.
683685
686+
# This string is the button's label, where the button is shown when the "zero"
687+
# point of the timeline is overridden.
688+
# Variables:
689+
# $zeroAt (String) - The timestamp of the overridden "zero"
690+
MenuButtons--zero-at = Zero at <span>{ $zeroAt }</span>
691+
684692
## NetworkSettings
685693
## This is used in the network chart.
686694

src/actions/profile-view.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1905,6 +1905,13 @@ export function changeMouseTimePosition(
19051905
};
19061906
}
19071907

1908+
export function overrideZeroAt(zeroAt: Milliseconds | null): Action {
1909+
return {
1910+
type: 'OVERRIDE_ZERO_AT',
1911+
zeroAt,
1912+
};
1913+
}
1914+
19081915
export function changeTableViewOptions(
19091916
tab: TabSlug,
19101917
tableViewOptions: TableViewOptions

src/components/app/MenuButtons/index.css

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,15 @@
111111
background-image: url(../../../../res/img/svg/maximize-dark-12.svg);
112112
}
113113

114+
.menuButtonsResetZeroAtButton::before {
115+
background-image: url(../../../../res/img/svg/undo-dark-12.svg);
116+
}
117+
118+
.menuButtonsZeroAtTimestamp {
119+
font-weight: bold;
120+
margin-inline-start: 0.3em;
121+
}
122+
114123
.profileInfoUploadedActions {
115124
padding: 8px 0 8px 40px; /* The 40px padding leaves the room for the cloud image */
116125
border-bottom: 1px solid rgb(0 0 0 / 0.05);

src/components/app/MenuButtons/index.tsx

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@ import classNames from 'classnames';
1111
import { Localized } from '@fluent/react';
1212

1313
import explicitConnect from 'firefox-profiler/utils/connect';
14-
import { getProfileRootRange } from 'firefox-profiler/selectors/profile';
14+
import {
15+
getProfileRootRange,
16+
getOverriddenZeroAtTimestamp,
17+
} from 'firefox-profiler/selectors/profile';
1518
import {
1619
getDataSource,
1720
getProfileUrl,
@@ -36,6 +39,7 @@ import {
3639
dismissNewlyPublished,
3740
profileRemotelyDeleted,
3841
} from 'firefox-profiler/actions/app';
42+
import { overrideZeroAt } from 'firefox-profiler/actions/profile-view';
3943

4044
import {
4145
getAbortFunction,
@@ -72,12 +76,14 @@ type StateProps = {
7276
readonly hasPrePublishedState: boolean;
7377
readonly abortFunction: () => void;
7478
readonly currentProfileUploadedInformation: UploadedProfileInformation | null;
79+
readonly getOverriddenZeroAtTimestamp: string | null;
7580
};
7681

7782
type DispatchProps = {
7883
readonly dismissNewlyPublished: typeof dismissNewlyPublished;
7984
readonly revertToPrePublishedState: typeof revertToPrePublishedState;
8085
readonly profileRemotelyDeleted: typeof profileRemotelyDeleted;
86+
readonly overrideZeroAt: typeof overrideZeroAt;
8187
};
8288

8389
type Props = ConnectedProps<OwnProps, StateProps, DispatchProps>;
@@ -130,6 +136,11 @@ class MenuButtonsImpl extends React.PureComponent<Props, State> {
130136
});
131137
};
132138

139+
_showZeroAtMenu = () => {
140+
const { overrideZeroAt } = this.props;
141+
overrideZeroAt(null);
142+
};
143+
133144
_renderUploadedProfileActions(
134145
currentProfileUploadedInformation: UploadedProfileInformation
135146
) {
@@ -309,6 +320,34 @@ class MenuButtonsImpl extends React.PureComponent<Props, State> {
309320
) : null;
310321
}
311322

323+
_renderZeroAt() {
324+
const { getOverriddenZeroAtTimestamp } = this.props;
325+
if (getOverriddenZeroAtTimestamp === null) {
326+
return null;
327+
}
328+
329+
return (
330+
<button
331+
type="button"
332+
className="menuButtonsButton menuButtonsButton-hasIcon menuButtonsResetZeroAtButton"
333+
onClick={this._showZeroAtMenu}
334+
>
335+
<Localized
336+
id="MenuButtons--zero-at"
337+
attrs={{ title: true }}
338+
vars={{ zeroAt: getOverriddenZeroAtTimestamp }}
339+
elems={{
340+
span: <span className="menuButtonsZeroAtTimestamp" />,
341+
}}
342+
>
343+
<>
344+
Zero at <span>{getOverriddenZeroAtTimestamp}</span>
345+
</>
346+
</Localized>
347+
</button>
348+
);
349+
}
350+
312351
_renderRevertProfile() {
313352
const { hasPrePublishedState, revertToPrePublishedState } = this.props;
314353
if (!hasPrePublishedState) {
@@ -330,6 +369,7 @@ class MenuButtonsImpl extends React.PureComponent<Props, State> {
330369
override render() {
331370
return (
332371
<>
372+
{this._renderZeroAt()}
333373
{this._renderRevertProfile()}
334374
{this._renderMetaInfoButton()}
335375
{this._renderPublishPanel()}
@@ -360,11 +400,13 @@ export const MenuButtons = explicitConnect<OwnProps, StateProps, DispatchProps>(
360400
abortFunction: getAbortFunction(state),
361401
currentProfileUploadedInformation:
362402
getCurrentProfileUploadedInformation(state),
403+
getOverriddenZeroAtTimestamp: getOverriddenZeroAtTimestamp(state),
363404
}),
364405
mapDispatchToProps: {
365406
dismissNewlyPublished,
366407
revertToPrePublishedState,
367408
profileRemotelyDeleted,
409+
overrideZeroAt,
368410
},
369411
component: MenuButtonsImpl,
370412
}

src/components/shared/MarkerContextMenu.css

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
background-image: url(../../../res/img/svg/end-selection-at-marker-end.svg);
3232
}
3333

34+
.markerContextMenuIconOverrideZeroAtMarkerStart {
35+
background-image: url(../../../res/img/svg/start-selection-at-marker-start.svg);
36+
}
37+
3438
.markerContextMenuIconCopyDescription {
3539
background-image: url(../../../res/img/svg/copy-dark.svg);
3640
}

src/components/shared/MarkerContextMenu.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
setContextMenuVisibility,
1414
updatePreviewSelection,
1515
selectTrackFromTid,
16+
overrideZeroAt,
1617
} from 'firefox-profiler/actions/profile-view';
1718
import {
1819
getPreviewSelection,
@@ -65,6 +66,7 @@ type DispatchProps = {
6566
readonly updatePreviewSelection: typeof updatePreviewSelection;
6667
readonly setContextMenuVisibility: typeof setContextMenuVisibility;
6768
readonly selectTrackFromTid: typeof selectTrackFromTid;
69+
readonly overrideZeroAt: typeof overrideZeroAt;
6870
};
6971

7072
type Props = ConnectedProps<OwnProps, StateProps, DispatchProps>;
@@ -141,6 +143,11 @@ class MarkerContextMenuImpl extends PureComponent<Props> {
141143
});
142144
};
143145

146+
overrideZeroAtMarkerStart = () => {
147+
const { marker, overrideZeroAt } = this.props;
148+
overrideZeroAt(marker.start);
149+
};
150+
144151
_isZeroDurationMarker(marker: Marker | null): boolean {
145152
return !marker || marker.end === null;
146153
}
@@ -482,6 +489,15 @@ class MarkerContextMenuImpl extends PureComponent<Props> {
482489
</>
483490
)}
484491

492+
<div className="react-contextmenu-separator" />
493+
494+
<MenuItem onClick={this.overrideZeroAtMarkerStart}>
495+
<span className="react-contextmenu-icon markerContextMenuIconOverrideZeroAtMarkerStart" />
496+
<Localized id="MarkerContextMenu--override-zero-at-marker-start">
497+
Override zero at marker’s start
498+
</Localized>
499+
</MenuItem>
500+
485501
<div className="react-contextmenu-separator" />
486502
<MenuItem onClick={this.copyMarkerDescription}>
487503
<span className="react-contextmenu-icon markerContextMenuIconCopyDescription" />
@@ -539,6 +555,7 @@ const MarkerContextMenu = explicitConnect<OwnProps, StateProps, DispatchProps>({
539555
updatePreviewSelection,
540556
setContextMenuVisibility,
541557
selectTrackFromTid,
558+
overrideZeroAt,
542559
},
543560
component: MarkerContextMenuImpl,
544561
});

src/reducers/profile-view.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -824,6 +824,15 @@ const mouseTimePosition: Reducer<Milliseconds | null> = (
824824
}
825825
};
826826

827+
const overrideZeroAt: Reducer<Milliseconds | null> = (state = null, action) => {
828+
switch (action.type) {
829+
case 'OVERRIDE_ZERO_AT':
830+
return action.zeroAt;
831+
default:
832+
return state;
833+
}
834+
};
835+
827836
/**
828837
* Provide a mechanism to wrap the reducer in a special function that can reset
829838
* the state to the default values. This is useful when viewing multiple profiles
@@ -864,6 +873,7 @@ const profileViewReducer: Reducer<ProfileViewState> = wrapReducerInResetter(
864873
hoveredMarker,
865874
mouseTimePosition,
866875
perTab: tableViewOptionsPerTab,
876+
overrideZeroAt,
867877
}),
868878
profile,
869879
globalTracks,

src/selectors/profile.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import * as Tracks from '../profile-logic/tracks';
66
import * as CPU from '../profile-logic/cpu';
77
import * as UrlState from './url-state';
88
import { ensureExists } from '../utils/types';
9+
import { formatTimestamp } from '../utils/format-numbers';
910
import {
1011
accumulateCounterSamples,
1112
extractProfileFilterPageData,
@@ -96,8 +97,23 @@ export const getScrollToSelectionGeneration: Selector<number> = (state) =>
9697
getProfileViewOptions(state).scrollToSelectionGeneration;
9798
export const getFocusCallTreeGeneration: Selector<number> = (state) =>
9899
getProfileViewOptions(state).focusCallTreeGeneration;
99-
export const getZeroAt: Selector<Milliseconds> = (state) =>
100-
getProfileRootRange(state).start;
100+
export const getZeroAt: Selector<Milliseconds> = (state) => {
101+
const viewOptions = getProfileViewOptions(state);
102+
if (viewOptions.overrideZeroAt !== null) {
103+
return viewOptions.overrideZeroAt;
104+
}
105+
return getProfileRootRange(state).start;
106+
};
107+
export const getOverriddenZeroAtTimestamp: Selector<string | null> = (
108+
state
109+
) => {
110+
const viewOptions = getProfileViewOptions(state);
111+
if (viewOptions.overrideZeroAt === null) {
112+
return null;
113+
}
114+
const offset = viewOptions.overrideZeroAt - getProfileRootRange(state).start;
115+
return formatTimestamp(offset);
116+
};
101117
export const getProfileTimelineUnit: Selector<TimelineUnit> = (state) => {
102118
const { sampleUnits } = getProfile(state).meta;
103119
return sampleUnits ? sampleUnits.time : 'ms';

src/test/components/MarkerTable.test.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,23 @@ describe('MarkerTable', function () {
239239
);
240240
});
241241

242+
it('can override the zero at timing using the context menu', () => {
243+
const { getRowElement } = setup();
244+
245+
const startNode = ensureExists(
246+
getRowElement(/setTimeout/).querySelector('.start')
247+
);
248+
expect(startNode).toHaveTextContent('0.153s');
249+
250+
fireFullContextMenu(getRowElement(/setTimeout/) as HTMLElement);
251+
fireFullClick(screen.getByText('Override zero at marker’s start'));
252+
253+
const startNode2 = ensureExists(
254+
getRowElement(/setTimeout/).querySelector('.start')
255+
);
256+
expect(startNode2).toHaveTextContent('0s');
257+
});
258+
242259
describe('EmptyReasons', () => {
243260
it('shows reasons when a profile has no non-network markers', () => {
244261
const { profile } = getProfileFromTextSamples('A'); // Just a simple profile without any marker.

src/test/components/__snapshots__/MarkerChart.test.tsx.snap

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,20 @@ exports[`MarkerChart context menus displays when right clicking on a marker 1`]
133133
<div
134134
class="react-contextmenu-separator"
135135
/>
136+
<div
137+
aria-disabled="false"
138+
class="react-contextmenu-item"
139+
role="menuitem"
140+
tabindex="-1"
141+
>
142+
<span
143+
class="react-contextmenu-icon markerContextMenuIconOverrideZeroAtMarkerStart"
144+
/>
145+
Override zero at marker’s start
146+
</div>
147+
<div
148+
class="react-contextmenu-separator"
149+
/>
136150
<div
137151
aria-disabled="false"
138152
class="react-contextmenu-item"

0 commit comments

Comments
 (0)