Repository navigation
Add a basic function list panel - #6403
Conversation
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #6403 +/- ##
==========================================
- Coverage 84.95% 84.95% -0.01%
==========================================
Files 359 362 +3
Lines 39137 39631 +494
Branches 11096 11260 +164
==========================================
+ Hits 33249 33668 +419
- Misses 5451 5524 +73
- Partials 437 439 +2 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
182a5ea to
1ccc6ef
Compare
canova
left a comment
There was a problem hiding this comment.
Thanks for the PR!
Do you think this basic version of the function list is still useful when we don't have the other panels in it? I'm leaning towards hiding the panel for now, and maybe make it accessible from the devtools etc. for testing. But if you think it still has some value in this state we can also ship it like this.
Another issue that I noticed is that, whenever I switch to another thread while the function list is selected, we don't select any function in the list by default. But we do that initial selection for the first loaded thread only (I think we run that code only on mount). In the call tree, we always select something. I think it would be good to do the same.
| // function list's default", encoded as an absent query parameter. | ||
| const VALID_FUNCTION_LIST_SORT_COLUMNS = new Set(['total', 'self']); | ||
|
|
||
| function convertFunctionListSortToString( |
There was a problem hiding this comment.
This looks very similar to how we do for the marker table. Can we maybe deduplicate these by merging these ..ToString and ..FromString helpers. I think it should be easy to do that.
| } | ||
|
|
||
| // FunctionList sort URL encoding. Same convention as the marker table: | ||
| // internal storage is primary-last, URL is primary-first. `null` means "at the |
There was a problem hiding this comment.
Hmm, I think this "primary-first" comment is not correct actually. Currently we do .reverse() in both directions but ColumnSortState.entries is already primary first. So this ends up making primary last. I think the comment below (deduplicating) would also help with this difference.
| type DispatchProps = { | ||
| readonly changeSelectedFunctionIndex: typeof changeSelectedFunctionIndex; | ||
| readonly changeRightClickedFunctionIndex: typeof changeRightClickedFunctionIndex; | ||
| readonly addTransformToStack: typeof addTransformToStack; |
There was a problem hiding this comment.
nit: we don't seem to dispatch this action so far, but maybe we'll use it later?
| // The call tree's own order (by total sample count) is the intended order, | ||
| // so no columns are user-sortable. |
There was a problem hiding this comment.
Seems like this is not accurate anymore as function list has user-sortable columns
| // The call tree's own order (by total sample count) is the intended order, | ||
| // so no columns are user-sortable. | ||
| getSortableColumns(): SortableColumn[] { | ||
| if (this._internal instanceof CallTreeInternalFunctionList) { |
There was a problem hiding this comment.
Hmm these checks are a bit weird. Wouldn't it be better to create a sorting method on CallTreeInternal and implement them inside of them directly? This would simplify both getSortableColumns and getRoots.
| // Update window.history synchronously instead of waiting for the | ||
| // UrlManager's componentDidUpdate, which is deferred by React's render | ||
| // scheduling and would otherwise pushState a new entry. | ||
| replaceHistoryWithUrlState(getUrlState(getState())); |
There was a problem hiding this comment.
Oh welp, calling replaceState from the action directly before UrlManager seems hacky to me. We have the UrlManager to handle these type of things, and I think it should be handled there.
Thinking about it, I think this currently works coincidentally because calling this here skips the checks inside that UrlManager. And it also only works because FunctionList's componentDidMount runs before UrlManager.componentDidUpdate if I understand correctly.
Can we make it so that UrlManager can make this decision instead? We could add isSelectionOnlyUrlChange(prev, next) helper in url-handling.ts and then and then we can use it inside UrlManager.
Also I think we wanted to also keep the selected call node of call tree in the url. I think having something like isSelectionOnlyUrlChange would allow us to extend more easily later.
There was a problem hiding this comment.
Uh oh I hadn't really looked at this part at all. Thank you for catching this. isSelectionOnlyUrlChange is a great idea.
| vars={item.l10nVars ? item.l10nVars(ctx) : undefined} | ||
| elems={item.l10nElems} | ||
| > | ||
| <div className="react-contextmenu-item-content" title={oneLine``}> |
There was a problem hiding this comment.
nit: just title=""? I don't also know if we need it because of fluent, we might also just remove the whole attribute if it works.
Add a new "Function List" tab which shows a flat, sortable list of functions rather than a tree. Selection is per-function instead of per-call-node, so this adds a per-thread selected function to the URL state, along with the URL handling, reducers and selectors that go with it. Selecting a function replaces the current history entry instead of pushing a new one. Otherwise, holding the down arrow key in the list would flood the back/forward history and get rate-limited by the browser.
The call tree's context menu operates on a call node path, which the function list does not have. Add a sibling menu that operates on a function index instead. The menu items are described by a data table rather than repeated JSX, because the same set of transforms is about to be reused by more than one view.
These are the same single-key shortcuts the call tree context menu offers (m, f, S, c, C, r, R, d), applied to the selected function.
When the function list tab is active, the activity graph should highlight every sample whose stack contains the selected function, rather than the samples belonging to a selected call node.
Clicking a sample already selects the corresponding self call node. When the function list tab is active, also select that call node's function so the click has an effect there too.
Previously, changeSelectedFunctionIndex called replaceState directly, so that the UrlManager's later componentDidUpdate found the URL already up to date and didn't push a new entry. Instead, the UrlManager now compares the previous and the next URL state, and replaces the current entry if only the selection changed.
1ccc6ef to
751f8c6
Compare
I don't have a super strong opinion on it but I think it's useful enough in this state to be visible by default, specifically the fact that you can select a function and have the activity graph show you where in the timeline it is present anywhere in the stack.
True. I added this in if (this.props.threadsKey !== prevProps.threadsKey) {
this.maybeProcureInitialSelection();
} |
There was a problem hiding this comment.
Thanks for the PR!
Do you think this basic version of the function list is still useful when we don't have the other panels in it? I'm leaning towards hiding the panel for now, and maybe make it accessible from the devtools etc. for testing. But if you think it still has some value in this state we can also ship it like this.I don't have a super strong opinion on it but I think it's useful enough in this state to be visible by default, specifically the fact that you can select a function and have the activity graph show you where in the timeline it is present anywhere in the stack.
Sounds good, let's ship it then!
Another issue I found:
STR:
- Open the right sidebar if it's not open yet.
- Select a function in the function list
- Press "m" to merge the function.
The function is no longer visible but the right sidebar still shows the old function (and no line is selected visibly anymore)
And then I can keep spamming "m" and it applies the merge transform to the same function that's no longer visible.
When I press "m" on the call tree, the selected line gets updated.
I guess it's not a huge bug, but it's worth fixing either here or as a follow-up.
a4c1399
Main | Deploy preview
This PR adds a "Function List" panel. In this PR this is only the plain list and doesn't have caller / callee trees or flame graphs yet; see #5233 for a full demo with those included.