diff --git a/locales/en-US/app.ftl b/locales/en-US/app.ftl
index 9eb89ea769..8d51ab50bf 100644
--- a/locales/en-US/app.ftl
+++ b/locales/en-US/app.ftl
@@ -438,6 +438,8 @@ MarkerContextMenu--end-selection-at-marker-start =
End selection at marker’s start
MarkerContextMenu--end-selection-at-marker-end =
End selection at marker’s end
+MarkerContextMenu--override-zero-at-marker-start =
+ Override zero at marker’s start
MarkerContextMenu--copy-description = Copy description
MarkerContextMenu--copy-call-stack = Copy call stack
MarkerContextMenu--copy-url = Copy URL
@@ -681,6 +683,12 @@ MenuButtons--publish--download = Download
MenuButtons--publish--compressing = Compressing…
MenuButtons--publish--error-while-compressing = Error while compressing, try unchecking some checkboxes to reduce the profile size.
+# This string is the button's label, where the button is shown when the "zero"
+# point of the timeline is overridden.
+# Variables:
+# $zeroAt (String) - The timestamp of the overridden "zero"
+MenuButtons--zero-at = Zero at { $zeroAt }
+
## NetworkSettings
## This is used in the network chart.
diff --git a/src/actions/profile-view.ts b/src/actions/profile-view.ts
index 47c50d4017..a87ade1316 100644
--- a/src/actions/profile-view.ts
+++ b/src/actions/profile-view.ts
@@ -1905,6 +1905,13 @@ export function changeMouseTimePosition(
};
}
+export function overrideZeroAt(zeroAt: Milliseconds | null): Action {
+ return {
+ type: 'OVERRIDE_ZERO_AT',
+ zeroAt,
+ };
+}
+
export function changeTableViewOptions(
tab: TabSlug,
tableViewOptions: TableViewOptions
diff --git a/src/components/app/MenuButtons/index.css b/src/components/app/MenuButtons/index.css
index 88f34acab1..dbc8259ab7 100644
--- a/src/components/app/MenuButtons/index.css
+++ b/src/components/app/MenuButtons/index.css
@@ -111,6 +111,15 @@
background-image: url(../../../../res/img/svg/maximize-dark-12.svg);
}
+.menuButtonsResetZeroAtButton::before {
+ background-image: url(../../../../res/img/svg/undo-dark-12.svg);
+}
+
+.menuButtonsZeroAtTimestamp {
+ font-weight: bold;
+ margin-inline-start: 0.3em;
+}
+
.profileInfoUploadedActions {
padding: 8px 0 8px 40px; /* The 40px padding leaves the room for the cloud image */
border-bottom: 1px solid rgb(0 0 0 / 0.05);
diff --git a/src/components/app/MenuButtons/index.tsx b/src/components/app/MenuButtons/index.tsx
index fc2d965154..7fead3fe94 100644
--- a/src/components/app/MenuButtons/index.tsx
+++ b/src/components/app/MenuButtons/index.tsx
@@ -11,7 +11,10 @@ import classNames from 'classnames';
import { Localized } from '@fluent/react';
import explicitConnect from 'firefox-profiler/utils/connect';
-import { getProfileRootRange } from 'firefox-profiler/selectors/profile';
+import {
+ getProfileRootRange,
+ getOverriddenZeroAtTimestamp,
+} from 'firefox-profiler/selectors/profile';
import {
getDataSource,
getProfileUrl,
@@ -36,6 +39,7 @@ import {
dismissNewlyPublished,
profileRemotelyDeleted,
} from 'firefox-profiler/actions/app';
+import { overrideZeroAt } from 'firefox-profiler/actions/profile-view';
import {
getAbortFunction,
@@ -72,12 +76,14 @@ type StateProps = {
readonly hasPrePublishedState: boolean;
readonly abortFunction: () => void;
readonly currentProfileUploadedInformation: UploadedProfileInformation | null;
+ readonly getOverriddenZeroAtTimestamp: string | null;
};
type DispatchProps = {
readonly dismissNewlyPublished: typeof dismissNewlyPublished;
readonly revertToPrePublishedState: typeof revertToPrePublishedState;
readonly profileRemotelyDeleted: typeof profileRemotelyDeleted;
+ readonly overrideZeroAt: typeof overrideZeroAt;
};
type Props = ConnectedProps;
@@ -130,6 +136,11 @@ class MenuButtonsImpl extends React.PureComponent {
});
};
+ _showZeroAtMenu = () => {
+ const { overrideZeroAt } = this.props;
+ overrideZeroAt(null);
+ };
+
_renderUploadedProfileActions(
currentProfileUploadedInformation: UploadedProfileInformation
) {
@@ -309,6 +320,34 @@ class MenuButtonsImpl extends React.PureComponent {
) : null;
}
+ _renderZeroAt() {
+ const { getOverriddenZeroAtTimestamp } = this.props;
+ if (getOverriddenZeroAtTimestamp === null) {
+ return null;
+ }
+
+ return (
+
+ );
+ }
+
_renderRevertProfile() {
const { hasPrePublishedState, revertToPrePublishedState } = this.props;
if (!hasPrePublishedState) {
@@ -330,6 +369,7 @@ class MenuButtonsImpl extends React.PureComponent {
override render() {
return (
<>
+ {this._renderZeroAt()}
{this._renderRevertProfile()}
{this._renderMetaInfoButton()}
{this._renderPublishPanel()}
@@ -360,11 +400,13 @@ export const MenuButtons = explicitConnect(
abortFunction: getAbortFunction(state),
currentProfileUploadedInformation:
getCurrentProfileUploadedInformation(state),
+ getOverriddenZeroAtTimestamp: getOverriddenZeroAtTimestamp(state),
}),
mapDispatchToProps: {
dismissNewlyPublished,
revertToPrePublishedState,
profileRemotelyDeleted,
+ overrideZeroAt,
},
component: MenuButtonsImpl,
}
diff --git a/src/components/shared/MarkerContextMenu.css b/src/components/shared/MarkerContextMenu.css
index 851877cfac..7487c4702f 100644
--- a/src/components/shared/MarkerContextMenu.css
+++ b/src/components/shared/MarkerContextMenu.css
@@ -31,6 +31,10 @@
background-image: url(../../../res/img/svg/end-selection-at-marker-end.svg);
}
+.markerContextMenuIconOverrideZeroAtMarkerStart {
+ background-image: url(../../../res/img/svg/start-selection-at-marker-start.svg);
+}
+
.markerContextMenuIconCopyDescription {
background-image: url(../../../res/img/svg/copy-dark.svg);
}
diff --git a/src/components/shared/MarkerContextMenu.tsx b/src/components/shared/MarkerContextMenu.tsx
index c1243223d8..d08ec5144f 100644
--- a/src/components/shared/MarkerContextMenu.tsx
+++ b/src/components/shared/MarkerContextMenu.tsx
@@ -13,6 +13,7 @@ import {
setContextMenuVisibility,
updatePreviewSelection,
selectTrackFromTid,
+ overrideZeroAt,
} from 'firefox-profiler/actions/profile-view';
import {
getPreviewSelection,
@@ -65,6 +66,7 @@ type DispatchProps = {
readonly updatePreviewSelection: typeof updatePreviewSelection;
readonly setContextMenuVisibility: typeof setContextMenuVisibility;
readonly selectTrackFromTid: typeof selectTrackFromTid;
+ readonly overrideZeroAt: typeof overrideZeroAt;
};
type Props = ConnectedProps;
@@ -141,6 +143,11 @@ class MarkerContextMenuImpl extends PureComponent {
});
};
+ overrideZeroAtMarkerStart = () => {
+ const { marker, overrideZeroAt } = this.props;
+ overrideZeroAt(marker.start);
+ };
+
_isZeroDurationMarker(marker: Marker | null): boolean {
return !marker || marker.end === null;
}
@@ -482,6 +489,15 @@ class MarkerContextMenuImpl extends PureComponent {
>
)}
+
+
+
+