-
Notifications
You must be signed in to change notification settings - Fork 419
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve dropped functions UI #4682
base: main
Are you sure you want to change the base?
Conversation
This PR implements some changes to the arrow panel code which make arrow panels usable for the dropped functions panel in the call tree settings. With the previous implementation, I encountered these issues: - When the source view was open, the panel would be clipped to the call tree bounds and could not overlap the source view. The overflow:auto clip from the splitter view was applying to the panel. - With a narrow viewport or an unusually positioned anchor element, the panel would sometimes be positioned partially offscreen. - It was tricky to enforce a maximum height on the panel in a way that squished the list box inside the panel. - The panel would reposition itself based on the size of the anchor element *while the panel was open*. E.g. you would click an "x" button to remove a dropped function, and the anchor button's label would change from "10 dropped functions" to "9 dropped functions", causing the button to shrink. Then the panel would shift slightly to the left, moving the "x" button out from under the mouse cursor. This commit fixes all of these issues. The most important change is the switch to position:fixed: Now the panel will no longer be clipped by overflow:hidden/auto ancestor of the button that opens the panel. Furthermore, the panel position is only computed during opening and then remains unchanged while the panel is open. And there is some logic to make the panel fit onscreen (while also making sure that the arrow still points at the right place).
This has a few advantages: - You'll be able to remove dropped functions after you've pushed other transforms on the transform stack - The transform stack doesn't become cluttered when you drop many functions - When loading a profile with many dropped functions, computing the filtered thread is much faster because we don't compute a new samples table for each individual dropped function - External tools which use the web console API (by dispatching actions manually) can drop multiple functions with a single dispatch, greatly reducing the time spent in per-dispatch renders
a30cbff
to
f3001f2
Compare
Codecov ReportPatch coverage:
Additional details and impacted files@@ Coverage Diff @@
## main #4682 +/- ##
==========================================
- Coverage 88.33% 88.21% -0.13%
==========================================
Files 299 301 +2
Lines 26709 26829 +120
Branches 7206 7231 +25
==========================================
+ Hits 23594 23667 +73
- Misses 2902 2944 +42
- Partials 213 218 +5
☔ View full report in Codecov by Sentry. |
This is ready for review now. It's not super polished visually, but I think it's a vast improvement over what we have today. Also, I really want the It's also missing some tests. |
@@ -993,6 +987,53 @@ TransformNavigator--collapse-function-subtree = Collapse subtree: { $item } | |||
# $item (String) - Search filter of the markers that transform will apply to. | |||
TransformNavigator--drop-samples-outside-of-markers-matching = Drop samples outside of markers matching: “{ $item }” | |||
|
|||
## "Dropped functions" settings UI | |||
## | |||
## A "dropped function" is a function which is excluded from the sample data. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A comment this long is not helpful for localization, it's going to clutter the UI given its size. Comments on the individual strings are OK.
.label = | ||
{ $numberOfDroppedFunctions -> | ||
[one] 1 dropped function | ||
*[other] { $numberOfDroppedFunctions } dropped functions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: fix the indentation. I would also shorten the variable name, e.g. just $num
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, this looks pretty good to me. I left a few comments (on the 2nd commit only), tell me what you think!
return (dispatch) => { | ||
dispatch({ | ||
type: 'DROP_FUNCTIONS', | ||
threadsKey, | ||
functionIndexes, | ||
}); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't need a thunk action, you can return the action directly.
(same below)
@@ -407,6 +408,14 @@ export function getQueryStringFromUrlState(urlState: UrlState): string { | |||
urlState.profileSpecific.transforms[selectedThreadsKey] | |||
) || undefined; | |||
} | |||
if ( | |||
selectedThreadsKey !== null && | |||
urlState.profileSpecific.droppedFunctions[selectedThreadsKey] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you should probably check whether it's an empty array?
/** | ||
* The DropFunction transform removes samples from the thread that have a function | ||
* somewhere in its stack. | ||
* | ||
* A:4,0 A:1,0 | ||
* / \ Drop Func C | | ||
* v v --> v | ||
* B:3,0 C:1,0 B:1,0 | ||
* / \ | | ||
* v v v | ||
* C:2,1 D:1,1 D:1,1 | ||
* | | ||
* v | ||
* D:1,1 | ||
*/ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if we could put this ascii art schema somewhere?
type DispatchProps = {| | ||
+undropFunctions: typeof undropFunctions, | ||
|}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This doesn't seem to be used here after all.
|
||
render() { | ||
const { droppedFunctions } = this.props; | ||
const numberOfDroppedFunctions = droppedFunctions.length; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optional nit: I'd take the length as a prop (and compute it in mapStateToProps
) instead of the full array. Indeed the component only needs this information.
padding: 1px; | ||
border: 0; | ||
border-radius: 2px; | ||
background: url(../../../res/img/svg/close-dark.svg) no-repeat center; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit:
you can use firefox-profiler-res
instead of these ../../
. It's not shorter but easier to use.
DispatchProps | ||
>({ | ||
mapStateToProps: (state) => ({ | ||
droppedFunctions: selectedThreadSelectors.getDroppedFunctions(state), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you don't need this prop, you can do everything with just droppedFunctionsDisplayData
.
@@ -88,6 +89,9 @@ class StackSettingsImpl extends PureComponent<Props> { | |||
<StackImplementationSetting /> | |||
</li> | |||
) : null} | |||
<li className="panelSettingsListItem"> | |||
<DroppedFunctionsSetting /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if it should be present when no function are dropped yet... What do you think?
# This message is shown inside the list of dropped functions when the list is empty. | ||
# It instructs the user about the purpose of the list. | ||
# The text "Drop samples with this function" should be consistent with the | ||
# translation of `CallNodeContextMenu--transform-drop-function`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@flodolo do you think it would be good to reuse directly the value for that translation here?
Although we might not need it anymore if we don't display it when there's no function like I suggest elsewhere.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, this is pretty much the only use case where using a message reference makes sense.
The only downside is that, if the referenced message is not translated yet, we'll show the referenced ID (and not fall back to the English text).
type Props = ConnectedProps<{||}, StateProps, DispatchProps>; | ||
|
||
class DroppedFunctionsSettingImpl extends PureComponent<Props> { | ||
_panelPosition = { anchorEdge: 'left', distanceFromEdge: 200 }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This magic number 200
feels weird, maybe we should be explicit and specify the panelWidth: 400
here as well even if it's the default.
Random thought: maybe we'd need to support percentages instead of absolute lengths? Maybe also it's possible to support them by using calc
instead of computing in JS.. not sure though...
Production | Deploy preview
Fixes #4678.
┆Issue is synchronized with this Jira Task