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

Jamie/control menu angular ui2 #2283

Merged
merged 61 commits into from
Jan 17, 2020
Merged

Conversation

SEAjamieD
Copy link
Contributor

@SEAjamieD SEAjamieD commented Nov 20, 2019

🔩 Description: What code changed, and why?

An ongoing effort to remove stencil components. The goal of this branch was to remove chef-control-menu from the codebase. It is replaced here with an Angular Material component, specifically mat-select and mat-option. In order to remain keyboard accessible, onClick functions within mat-option have been changed to onSelectionChange per angular material requirement.

⛓️ Related Resources

#2061

👍 Definition of Done

All chef-control-menus have been replaced, slight styling updates to what was requested by UX.

All Control menus are keyboard accessible.

👟 How to Build and Test the Change

build components/automate_ui_devproxy && start_all_services

Across the site, control menus can be found in:
Settings >
notifications
policies
projects
API Tokens
Teams
Users
Node Credentials
Node Integrations

Compliance >
Reports > Nodes Tab
Reports > Profiles Tab
Reports > Controls Tab

✅ Checklist

  • Tests added/updated?
  • Docs added/updated?

📷 Screenshots, if applicable

@@ -196,3 +196,49 @@ chef-loading-spinner[fixed] {
input {
line-height: normal;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Angular Material requires a lot of over rides, but doesn't really seem to have a good place to target globally outside of the styles.css file. Any suggestions on a better location for something like this. Will get crowded after adding several more components.

@SEAjamieD SEAjamieD marked this pull request as ready for review November 25, 2019 23:08
@SEAjamieD SEAjamieD self-assigned this Nov 25, 2019
@SEAjamieD SEAjamieD requested a review from susanev November 25, 2019 23:09
@SEAjamieD
Copy link
Contributor Author

@susanev - from a UX/style perspective, this ticket is done. I'm still trying to work through some Cypress testing issues, but I feel comfortable opening up this PR for any style and/or user
related issues you might find.

@SEAjamieD
Copy link
Contributor Author

@susanev - Major apologies! I failed to update to new spec pictured here. On that now and will retag when done
Screen Shot 2019-11-25 at 3 20 59 PM

@SEAjamieD
Copy link
Contributor Author

@susanev - Ok, new colors and states are in. Sorry about that!

}

&:hover {
background-color: #DEE5FD;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@susanev several of these colors here are ones that I haven't seen used in the codebase yet. Are there names you want to use for them when I make the variables?

@susanev
Copy link
Contributor

susanev commented Nov 26, 2019

@SEAjamieD can we increase the icon size? maybe font-size: 20px; or similar. also can we get the icon centered in the button?

also, we need to be able to tab to these buttons, and open them and select an option with keyboard only. you can tab to them, but there's no visible focus (maybe cause you set the outline to 0?).. and you cant open the menu with ur keyboard.

flow should be..

  • tab to item
  • space bar to open
  • arrow keys to navigate in the menu
  • enter to select

and if you tab off the menu should close.

@susanev susanev removed their request for review December 6, 2019 18:00
@SEAjamieD SEAjamieD force-pushed the jamie/control-menu-angular-ui2 branch 2 times, most recently from 8d05df1 to f95753b Compare December 20, 2019 21:58
<chef-option (click)="removeMember(member)">Remove Member</chef-option>
</chef-control-menu>
<mat-select panelClass="chef-control-menu-x">
<mat-option (onSelectionChange)="removeMember($event, member)">Remove Member</mat-option>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

mat-select requires the use of onSelectionChange in order to be keyboard accessible. Unfortunately this will cause a double fire of connected function -> one for the selection and one for the deselection. The current workaround is running an if check for whether on not this was user input using $event.isUserInput. see: angular/components#4094 (comment)

Copy link
Contributor

Choose a reason for hiding this comment

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

The material docs (https://v6.material.angular.io/components/select/overview)" indicate "mat-select is designed to work inside of a <mat-form-field> element." Not clear what the ramifications of that are. Any potential pitfalls using it without a <mat-form-field> ?

Comment on lines 23 to 26
export interface KeyboardEvent {
isUserInput: boolean;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

By default - isUserInput is not part of the KeyboardEvent interface - this extends it.

Copy link
Contributor

Choose a reason for hiding this comment

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

Educate me: is isUserInput something you are populating or is it actually provided by the system though not exposed...?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

isUserInput is provided by Angular Material. Every time an option is selected there is an event fired for selected and an event fired for deselected. The selected event passed through isUserInput = true and the deselection event passes through isUserInput = false;

Comment on lines 110 to 113
removeMember($event: KeyboardEvent, member: Member): void {
if ($event.isUserInput) {
this.store.dispatch(new RemovePolicyMembers(<PolicyMembersMgmtPayload>{
id: this.policy.id,
members: [member]
}));
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

An example of using the $event.isUserInput to only get the selection and not the deselection.

<chef-option (click)="notifyCopy()" data-cy="copy-token">
<chef-table-cell class="controls">
<mat-select panelClass="chef-control-menu-x" id="menu-{{token.id}}" data-cy="token-control">
<mat-option (onSelectionChange)="notifyCopy($event)" data-cy="copy-token">
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Again - instances of passing in the event to check agains isUserInput.

Comment on lines 31 to 33
export interface KeyboardEvent {
isUserInput: boolean;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Same as above - extending Keyboard Event

Copy link
Contributor

Choose a reason for hiding this comment

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

See my earlier comment; this should only occur once in a common file.

@SEAjamieD
Copy link
Contributor Author

@susanev

also, we need to be able to tab to these buttons, and open them and select an option with keyboard only. you can tab to them, but there's no visible focus (maybe cause you set the outline to 0?).. and you cant open the menu with ur keyboard.

flow should be..

tab to item
space bar to open
arrow keys to navigate in the menu
enter to select
and if you tab off the menu should close.

How set are you on this flow? With angular material we get most of this built in, only change is that instead of using space bar to open, enter opens. Is this acceptable?

@susanev
Copy link
Contributor

susanev commented Dec 24, 2019

@SEAjamieD that's fine, thanks for checking!!

Copy link
Contributor

@msorens msorens left a comment

Choose a reason for hiding this comment

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

Initial pass--some items need fixing as noted below.

<chef-option (click)="removeMember(member)">Remove Member</chef-option>
</chef-control-menu>
<mat-select panelClass="chef-control-menu-x">
<mat-option (onSelectionChange)="removeMember($event, member)">Remove Member</mat-option>
Copy link
Contributor

Choose a reason for hiding this comment

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

The material docs (https://v6.material.angular.io/components/select/overview)" indicate "mat-select is designed to work inside of a <mat-form-field> element." Not clear what the ramifications of that are. Any potential pitfalls using it without a <mat-form-field> ?

@@ -20,6 +20,10 @@ import {

export type PolicyTabName = 'definition' | 'members';

export interface KeyboardEvent {
Copy link
Contributor

Choose a reason for hiding this comment

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

🤔 You are actually replacing the definition not extending it, and that makes it rather confusing for someone who expects a KeyboardEvent to be the original.
Would suggest rename this and really extend it:

Suggested change
export interface KeyboardEvent {
export interface ChefKeyboardEvent extends KeyboardEvent {

Also, I notice you export KeyboardEvent in two different files; they happen to be the same so no harm done at the moment, but that is brittle.
I would urge moving/consolidating it to a new file under src/app/types and just have a single definition that is imported in the three files that need it.

Finally, would like to add an in-code comment so folks know exactly what it is for: "isUserInput allows filtering to selection events and ignores deselection events".

<chef-table-cell class="three-dot-column">
<chef-control-menu id="menu-{{token.id}}" data-cy="token-control">
<chef-option (click)="notifyCopy()" data-cy="copy-token">
<chef-table-cell class="controls">
Copy link
Contributor

Choose a reason for hiding this comment

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

Here is another pattern to look for--this line also needs to be reverted, and again, check for other occurrences. Be sure to check the corresponding scss entry for this, too.

Comment on lines 31 to 33
export interface KeyboardEvent {
isUserInput: boolean;
}
Copy link
Contributor

Choose a reason for hiding this comment

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

See my earlier comment; this should only occur once in a common file.

Comment on lines 23 to 26
export interface KeyboardEvent {
isUserInput: boolean;
}

Copy link
Contributor

Choose a reason for hiding this comment

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

Educate me: is isUserInput something you are populating or is it actually provided by the system though not exposed...?

<chef-option (click)="startProjectDelete(project)" data-cy="delete-project">Delete Project</chef-option>
</chef-control-menu>
<mat-select panelClass="chef-control-menu-x">
<mat-option (onSelectionChange)="startProjectDelete(project)" data-cy="delete-project">Delete Project</mat-option>
Copy link
Contributor

Choose a reason for hiding this comment

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

If I am following your protocols, need to add guard if ($event.isUserInput)... inside of the target method (startProjectDelete).
And since a global search for .isUserInput only shows that guard presently in 3 files, I believe there are several others to instrument as well.

Copy link
Contributor

Choose a reason for hiding this comment

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

Per our conversation, please add on this method and check that there are no other missing ones. Thanks!

@susanev
Copy link
Contributor

susanev commented Dec 24, 2019

@SEAjamieD it looks and works well.. a few more things

  • for some reason, the height of a row with a control menu increases from 55px to 76px, since we will have some tables with rows with and without control menus we really want those to be the same height, any way to keep the row with a control menu at the same height as rows without?
  • the menu style when opened, and with focus on the menu items looks a bit different than what these were originally designed to look like..
    • font appears to be roboto but should be muli like the rest of automate
    • on open, the first item has the gray background and im not sure why... would prefer no background color until something gets focus or hover
    • on hover/focus can we change the background color to our chef-primary-dark and change the font color to white? (i believe these were the styles before converting to angular material)

seajamied added 8 commits January 15, 2020 13:51
Signed-off-by: seajamied <[email protected]>
…st row, which is why the test is failing

Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
Signed-off-by: seajamied <[email protected]>
@SEAjamieD SEAjamieD force-pushed the jamie/control-menu-angular-ui2 branch from 3b60a2b to dd1d114 Compare January 15, 2020 22:10
Copy link
Contributor

@susanev susanev left a comment

Choose a reason for hiding this comment

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

one last super small thing, lets get the background color on selection to use the same primary blue as our buttons; thanks for all of your work on this!!

seajamied added 2 commits January 16, 2020 13:37
Copy link
Contributor

@msorens msorens left a comment

Choose a reason for hiding this comment

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

The gating function we talked about (included in my comments below) is the only one of significance, I would say. The rest of my baker's dozen below are nitty-gritty cleanup. On the whole, the code looks great and it works well, so giving the thumbs up!

}
}

&[aria-owns] { // hacky alternative to active
Copy link
Contributor

Choose a reason for hiding this comment

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

The comment gives me only a vague idea of justification; might you have a URL reference you could add here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've updated the comment so it makes a little more sense. Ultimately, I noticed "aria-owns" being applied and hooked in on it.

aria-owns by definition tells assistive technology that another element being placed on the screen should be treated as a child element of the current element we're interacting with (https://developers.google.com/web/fundamentals/accessibility/semantics-aria/aria-labels-and-relationships#aria-owns)

I'm ultimately utilizing it out of scope because when aria-owns is added, we know that the dropdown panel is open.

@@ -27,6 +27,7 @@
--blue-de-france: #3DA5FF;
--gray: #B7BCBC;
--blue: #174AF0;
--palatinate-blue: #0E3DD5;
Copy link
Contributor

Choose a reason for hiding this comment

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

Wondering what your source is for this color?
Every reference I can find (e.g. https://encycolorpedia.com/search?q=palatinate+blue) shows palatinate blue as #273be2

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I got if from the Automate Extended Color Palette.

<chef-option (click)="startProjectDelete(project)" data-cy="delete-project">Delete Project</chef-option>
</chef-control-menu>
<mat-select panelClass="chef-control-menu-x">
<mat-option (onSelectionChange)="startProjectDelete(project)" data-cy="delete-project">Delete Project</mat-option>
Copy link
Contributor

Choose a reason for hiding this comment

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

Per our conversation, please add on this method and check that there are no other missing ones. Thanks!

@susanev
Copy link
Contributor

susanev commented Jan 17, 2020

@SEAjamieD you're going to remove that .toml right?

Signed-off-by: seajamied <[email protected]>
@SEAjamieD
Copy link
Contributor Author

@susanev

@SEAjamieD you're going to remove that .toml right?

sorry thank you!

Copy link
Contributor

@bcmdarroch bcmdarroch left a comment

Choose a reason for hiding this comment

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

Looks good to me! Had a few questions on the code.

I did notice a little weirdness on the focus but doesn't seem like a blocker:
Screen Shot 2020-01-17 at 11 08 19 AM

this.deleteModalVisible = true;
this.policyToDelete = policy;
public startPolicyDelete($event: ChefKeyboardEvent, policy: Policy): void {
if ($event.isUserInput) {
Copy link
Contributor

Choose a reason for hiding this comment

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

what does this conditional do? Is it necessary for any control menu item handler?

Copy link
Contributor Author

@SEAjamieD SEAjamieD Jan 17, 2020

Choose a reason for hiding this comment

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

This is an effect of using Material UI's mat-select component. When a selection is made, it fires off two events instead of just one. One of the events is the item being selected, and the other event is something being DEselected.

Unfortunately, without this gate being added, we'd fire off two events. The workaround is to check for the isUserInput property being true, if it is - that's the selected event we want.

@susanev
Copy link
Contributor

susanev commented Jan 17, 2020

thanks for your attention to detail @bcmdarroch!!
we are aware of the focus weirdness and we decided to move forward with it, but hoping that when the ui team has a chance to think more about how we are using material then we can revisit it then.

@SEAjamieD SEAjamieD merged commit 8e488da into master Jan 17, 2020
@chef-expeditor chef-expeditor bot deleted the jamie/control-menu-angular-ui2 branch January 17, 2020 23:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants