Closed aldo-expensify closed 1 year ago
Triggered auto assignment to @johncschuster (Bug
), see https://stackoverflow.com/c/expensify/questions/14418 for more details.
Platforms
in OP are ✅)The cause is pretty narrowed down here:
I think this would have been easier to fix if we were dealing with functional components. There out of the box memoization with Class components. The recommended way is to use the library memoize-one
which we don't currently have, and I'm not sure we want it since we are moving toward functional components.
FYI - No Slack thread for this one.
Triggered auto assignment to @flodnv (Engineering
), see https://stackoverflow.com/c/expensify/questions/4319 for more details.
From @aldo-expensify's investigation it seems like @roryabraham you caused this in https://github.com/Expensify/App/pull/18883, can you have a look please and let us know what you think?
Also, Vit was recommending me to get help from one of our external expert agencies to work on this (here). I think that could be a good idea.
Looking into this now
I'm not sure I yet see how this is related to https://github.com/Expensify/App/pull/18883, because the OptionsSelector
doesn't yet use the useArrowKeyFocusManager
or useKeyboardShortcut
hooks.
Found this lib which honestly seems pretty slick
PopoverMenu
subscribe shortcuts globally using useArrowKeyFocusManager
and useKeyboardShortcut
BaseOptionsSelector
subscribes globally ARROW UP
and ARROW DOWN
keys using ArrowKeyFocusManager
(here)PopoverMenu
subscribed shortcuts before BaseOptionsSelector
's subscribed shortcuts, just because of mounting order. This made the BaseOptionsSelector
's callback execute first.PopoverMenu
is constantly unsubscribing and subscribing the shortcuts, moving the callback to the front of any other with the same priority thanks to the way we insert the callback here (slice).PopoverMenu
executes first, it doesn't give a chance to BaseOptionsSelector
's callback to execute because it prevents bubbling shouldBubble = false
(default here)I'm pretty sure you could fix this particular bug by playing with the priorities during subscribe, but I still think this should be fix in a way it stops unsubscribing/subscribing every cycle.
Found this lib which honestly seems pretty slick
Interesting, the focus trap thing could help solving the problem we have with key event listeners that keep listening even out of view (see https://expensify.slack.com/archives/C01GTK53T8Q/p1685138015892469 / https://github.com/Expensify/App/issues/18419)
This seems like the exact scenario the upcoming React.useEvent
hook is designed for.
This seems like the exact scenario the upcoming
React.useEvent
hook is designed for.
In only found this: https://github.com/reactjs/rfcs/pull/220
Is this going to be implemented? Looks good, but I think for the moment, if that is not near to be released, this can be done with useCallback
+ useMemo
in functional react. In class components is hard I believe.
Yeah, it's just an RFC now, and we should be able to simulate it.
Put up a draft PR with a potential fix: https://github.com/Expensify/App/pull/20016. More testing and discussion is needed since it uses an experimental React feature which is explained in good detail here: https://react.dev/learn/separating-events-from-effects#declaring-an-event-function
PR is being worked on, Melv. Chill.
I haven't made any progress on the PR, been tied down with deploy chores. Considering making this external, but if we need to use a new React hook to fix it then we need a slack convo first
@johncschuster @roryabraham this issue was created 2 weeks ago. Are we close to a solution? Let's make sure we're treating this as a top priority. Don't hesitate to create a thread in #expensify-open-source to align faster in real time. Thanks!
This is being solved internally, Melv. Chill
@roryabraham is it being solved internally? Your last comment mentions making it External, can we do that now?
Yeah, I'm a bit hesitant to make it external without a clearer understanding of the root cause of the problem. Going to make this external.
Job added to Upwork: https://www.upwork.com/jobs/~01ecaf4548dae58200
Current assignee @johncschuster is eligible for the External assigner, not assigning anyone new.
Triggered auto assignment to Contributor-plus team member for initial proposal review - @Santhosh-Sellavel (External
)
Current assignee @roryabraham is eligible for the External assigner, not assigning anyone new.
The issue occurs when the user selects an item from the OptionList, moves to a next screen, and then returns. Upon returning, the arrow key selection (UP and DOWN) stops working in the PopoverMenu component. To reproduce: Open the panel to invite new members to a workspace (/workspace//invite). Verify that arrow keys (UP and DOWN) work and change the selected row. Select an item using the mouse. Click “Next.” Go back to the previous screen. BUG: The arrow keys no longer change the highlighted row.
The issue stems from a conflict between the keyboard subscription in the PopoverMenu component (which also re-renders multiple times) and the useKeyboardShortcut hook. Initially, when entering the Workspace invite members page, the keyboard subscription is handled by the ArrowKeyFocusManager in the componentDidMount event, occurring after the PopoverMenu subscription. This initial setup works fine. However, upon leaving the screen and returning, the PopoverMenu subscribes again, even though it is not currently visible. Consequently, when the Workspace page becomes visible again, the componentDidMount event is not fired, and the last subscription from the PopoverMenu remains active.
To resolve the issue, we need to modify the implementation of the PopoverMenu component. The PopoverMenu component uses the useArrowKeyFocusManager, which internally uses the useKeyboardShortcut hook. Currently, the PopoverMenu does not pass information about whether it is active or not to the useArrowKeyFocusManager, causing it to always subscribe to keyboard shortcuts. To address this, we can add an “isActive” prop to the useArrowKeyFocusManager, which will indicate whether the menu is currently active or not. This prop can be derived from the “props.isVisible” value. On top of this, I would add the suggestion and cleanups from @aldo-expensify
Ok, I think that makes sense. Thanks for the explanation @gedu 🙇🏼
📣 @gedu You have been assigned to this job by @roryabraham! Please apply to this job in Upwork and leave a comment on the Github issue letting us know when we can expect a PR to be ready for review 🧑💻 Keep in mind: Code of Conduct | Contributing 📖
I'll just wait for the PR then, thanks for the early review @roryabraham!
@roryabraham @aldo-expensify Hey, while I was adding the isActive
and doing the cleanup, I noticed that the useArrowKeyFocusManager
function has an unstable type for the disabledIndexes parameter, which is disabledIndexes = [].
This causes any hook that uses this parameter to be recreated every time.
I was improving the callback for useKeyboardShortcut
so the useEffect
doesn't get called everytime. but if I do this
const arrowUpCallback = useCallback(() => {
if (maxIndex < 0) {
return;
}
setFocusedIndex((index) => {
const currentFocusedIndex = index > 0 ? index - 1 : maxIndex;
let newFocusedIndex = currentFocusedIndex;
while (disabledIndexes.includes(newFocusedIndex)) {
newFocusedIndex = newFocusedIndex > 0 ? newFocusedIndex - 1 : maxIndex;
if (newFocusedIndex === currentFocusedIndex) {
// all indexes are disabled
return index; // no-op
}
}
return newFocusedIndex;
});
}, [disabledIndexes, maxIndex]);
useKeyboardShortcut(CONST.KEYBOARD_SHORTCUTS.ARROW_UP, arrowUpCallback, arrowConfig);
because `disabledIndexes` always is a new array the function will be recreating calling again the `useEffect`, chatting internally I think the best option is to create a const array and use it, in this case, is good because we just query the value, doing this we avoid that when other use this hook they don't need to use `useMemo` and pass always an array.
```
const EMPTY_ARRAY = Object.freeze([]);
function useArrowKeyFocusManager({
maxIndex,
onFocusedIndexChange = () => {},
initialFocusedIndex = 0,
disabledIndexes = EMPTY_ARRAY,
shouldExcludeTextAreaNodes = true,
isActive,
}) {}
Doing `freeze` so if someone tries to mutate the array get an error, because at least for now we don't want to support that behavior.
I want to point this out because as we start using hooks, these issues could arise in many places.
What do you think?
Before
<img width="337" alt="Screen Shot 2023-06-14 at 15 37 46" src="https://github.com/Expensify/App/assets/1676818/5e0e4291-852e-4fe4-8c84-d3a2429eb005">
After
<img width="309" alt="Screen Shot 2023-06-14 at 15 38 13" src="https://github.com/Expensify/App/assets/1676818/277053ba-4635-4b74-b425-dc720e039509">
The isActive
addition would also come in handy in this PR, since we want to be able to use the useArrowKeyFocusManager
for two different contexts (emojis and suggestions), and being able to disable
a keyboard shortcut subscription temporarily, would be great
Based on my calculations, the pull request did not get merged within 3 working days of assignment. Please, check out my computations here:
On to the next one 🚀
Reviewing
label has been removed, please complete the "BugZero Checklist".
The solution for this issue has been :rocket: deployed to production :rocket: in version 1.3.30-5 and is now subject to a 7-day regression period :calendar:. Here is the list of pull requests that resolve this issue:
If no regressions arise, payment will be issued on 2023-06-29. :confetti_ball:
After the hold period is over and BZ checklist items are completed, please complete any of the applicable payments for this issue, and check them off once done.
As a reminder, here are the bonuses/penalties that should be applied for any External issue:
BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:
I think this is ready for payment now
BugZero Checklist: The PR fixing this issue has been merged! The following checklist (instructions) will need to be completed before the issue can be closed:
- [x] [@Santhosh-Sellavel] The PR that introduced the bug has been identified. Link to the PR: https://github.com/Expensify/App/pull/18883
- [x] [@Santhosh-Sellavel] The offending PR has been commented on, pointing out the bug it caused and why, so the author and reviewers can learn from the mistake. Link to comment: Already pointed out by @aldo-expensify in th issue description https://github.com/Expensify/App/pull/18883/files#r1206010822
- [x] [@Santhosh-Sellavel] A discussion in #expensify-bugs has been started about whether any other steps should be taken (e.g. updating the PR review checklist) in order to catch this type of bug sooner. Link to discussion: Should have been caught with our checklist.
- [x] [@Santhosh-Sellavel] Determine if we should create a regression test for this bug. Yes
- [x] [@Santhosh-Sellavel] If we decide to create a regression test for the bug, please propose the regression test steps to ensure the same bug will not reach production again. https://github.com/Expensify/App/issues/19700#issuecomment-1616859600
- [ ] [@johncschuster] Link the GH issue for creating/updating the regression test once above steps have been agreed upon:
Bug: Arrow key selection stops working on the workspace invite members page
👍 or 👎
cc: @roryabraham @johncschuster
@Santhosh-Sellavel Upwork invite sent. Can you please ping me when you've accepted?
@Santhosh-Sellavel has requested payment via NewDot 🎉
Paid
Thanks, @anmurali!
Then, since @gedu works for Callstack, we are all set to close this 🎉
If you haven’t already, check out our contributing guidelines for onboarding and email contributors@expensify.com to request to join our Slack channel!
Coming from: https://github.com/Expensify/App/pull/18883/files#r1206010822
Action Performed:
Expected Result:
Pressing UP or DOWN should change the highlighted row
Actual Result:
Pressing UP or DOWN doesn't do anything
Workaround:
Can the user still use Expensify without this being fixed? Have you informed them of the workaround?
Platforms:
Which of our officially supported platforms is this issue occurring on?
Version Number: Reproducible in staging?: Reproducible in production?: If this was caught during regression testing, add the test name, ID and link from TestRail: Email or phone of affected tester (no customers): Logs: https://stackoverflow.com/c/expensify/questions/4856 Notes/Photos/Videos: Any additional supporting documentation Expensify/Expensify Issue URL: Issue reported by: Slack conversation:
View all open jobs on GitHub
Upwork Automation - Do Not Edit