Skip to content
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

fix: Rules > Detection (SEIM) Rules][SCREEN READER]: Snooze notifications modal is not trapping VoiceOver + Safari properly #182670

Merged
merged 13 commits into from
May 20, 2024

Conversation

alexwizp
Copy link
Contributor

@alexwizp alexwizp commented May 6, 2024

Closes: https://github.com/elastic/security-team/issues/8716

Description

The Detection Rules table has a Snooze notifications modal that is not trapping focus consistently in Safari + VoiceOver. The focus is being "bounced" to the <main> container when I traverse using Ctrl + Opt + RIGHT_ARROW or quick arrow navigation methods. These are the default VO navigation methods. This is not affecting Chrome + JAWS or Firefox + NVDA. Screenshot and MOV attached below.

Steps to recreate

  1. Open Detection Rules (SIEM)
  2. Enable VoiceOver (only use Safari for this test)
  3. Tab to the first Snooze Notification bell icon and press Ctrl + Opt + Enter to open it
  4. Navigate through the modal by pressing Ctrl + Opt + Right_Arrow
  5. Verify when your focus should be on the "days" dropdown, it pops out to the main container, escaping the modal

What was done?

  1. Focus trap logic has been implemented to ensure that focus returns to the correct location after executing onRuleChanged.

Screen:

Screen.Recording.2024-05-06.at.15.18.34.mov

…ions modal is not trapping VoiceOver + Safari properly

Closes: elastic/security-team#8716
@alexwizp alexwizp added Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. v8.15.0 release_note:skip Skip the PR/issue when compiling release notes Feature:Rule Actions Security Solution Rule Actions feature Feature:Alerting/RulesManagement Issues related to the Rules Management UX Team:Detection Rule Management Security Detection Rule Management Team Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) labels May 6, 2024
@alexwizp
Copy link
Contributor Author

alexwizp commented May 6, 2024

/ci

@alexwizp alexwizp marked this pull request as ready for review May 6, 2024 13:44
@alexwizp alexwizp requested a review from a team as a code owner May 6, 2024 13:44
@elasticmachine
Copy link
Contributor

Pinging @elastic/response-ops (Team:ResponseOps)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-solution (Team: SecuritySolution)

@elasticmachine
Copy link
Contributor

Pinging @elastic/security-detection-rule-management (Team:Detection Rule Management)

try {
await onRuleChanged(...args);
} finally {
setTimeout(() => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the reason for adding this timeout?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cnasikas the rendering cycle after calling await onRuleChanged(...args) must complete for the reference to focusTrapButtonRef to be updated. It might work without setTimeout, but I can't be certain it will work stable

Copy link
Member

@cnasikas cnasikas May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having a timeout in the callback without React being aware may cause various issues. For example, the timeout will not be cleaned if the user navigates to another page and the component unmounts. Moving the focusTrapButtonRef.current?.focus() to a useEffect that will trigger every time the rule is updated seems more appropriate. I am curious about the UX of a user using the mouse. Will it focus the button also for them?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cnasikas, thank you for your suggestion. At the moment, I'm not entirely certain if it will be effective, probably not. I'll need some time to consider alternative approaches. But for now not sure that we can fix that differently

@1Copenut fyi

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JiaweiWu proposed the usage of requestAnimationFrame. It is being used by the EUI library (https://github.com/elastic/eui/blob/main/packages/eui/src/components/inline_edit/inline_edit_form.tsx#L242) Also, could autofocus work?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @cnasikas and @JiaweiWu. The option with requestAnimationFrame seems to be working.

@alexwizp alexwizp requested a review from cnasikas May 14, 2024 08:02
@kibana-ci
Copy link
Collaborator

💚 Build Succeeded

Metrics [docs]

Async chunks

Total size of all lazy-loaded chunks that will be downloaded as the user navigates the app

id before after diff
triggersActionsUi 1.6MB 1.6MB +1.0KB

History

To update your PR or re-run it, just comment with:
@elasticmachine merge upstream

Copy link
Member

@cnasikas cnasikas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed that we pass the same focusTrapButtonRef to all buttons. Is that supported or does the reference hold the last button only?

@cnasikas
Copy link
Member

Also, I noticed that if I set a schedule with the mouse the button will be focused and show a tooltip. Is this a behavior we want to do for users who do not navigate with the keyboard? @mdefazio Any opinion on this?

Screen.Recording.2024-05-20.at.12.06.20.PM.mov

@alexwizp
Copy link
Contributor Author

@cnasikas Please correct me if I'm wrong. If I understand the business logic correctly, the Notify column can have one of three states (buttons): scheduledSnoozeButton, unsnoozedButton, and indefiniteSnoozeButton.

After calling onRuleChanged, the state changes, and the button where the EuiPopover was originally opened gets re-rendered to reflect the new state. This is what causes the problem, as the browser loses the current element and returns the focus to document.body.

How does that solution work? : As I mentioned at the beginning, in the UI we can have only one of the three buttons at a time. This means that if I set a single reference to all three buttons, this reference will ultimately point to the currently rendered element. Then, after calling onRuleChanged, we should wait a bit for the state to be rendered (requestAnimationFrame helps with that) and simply return focus to new rendered item.

Regarding the Tooltip question, its behavior has indeed changed. The button remains in focus, and this is a condition to show that tooltip. I don't know is we need somehow fix that or not.

@cnasikas
Copy link
Member

Thank you @alexwizp for your detailed answer and your patience with me.

This means that if I set a single reference to all three buttons, this reference will ultimately point to the currently rendered element

This was not clear to me. Thanks for clarifying!

Regarding the Tooltip question, its behavior has indeed changed. The button remains in focus, and this is a condition to show that tooltip. I don't know is we need somehow fix that or not.

I am ok with the change. Let's wait for @mdefazio to hear his opinion on this before merging. Other than that LGTM!

@mdefazio
Copy link
Contributor

@cnasikas Thanks for the ping. I don't think showing the tooltip/keeping focus on the button is bad here. And since this is our default button behavior anyway, let's wait on doing anything extra here.

@alexwizp alexwizp merged commit 953706a into elastic:main May 20, 2024
20 checks passed
@kibanamachine kibanamachine added the backport:skip This commit does not require backporting label May 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backport:skip This commit does not require backporting Feature:Alerting/RulesManagement Issues related to the Rules Management UX Feature:Rule Actions Security Solution Rule Actions feature release_note:skip Skip the PR/issue when compiling release notes Team:Detection Rule Management Security Detection Rule Management Team Team:ResponseOps Label for the ResponseOps team (formerly the Cases and Alerting teams) Team: SecuritySolution Security Solutions Team working on SIEM, Endpoint, Timeline, Resolver, etc. v8.15.0
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants