-
Notifications
You must be signed in to change notification settings - Fork 365
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
feat: [M3-7490] - Improve NodeBalancer Restricted User Experience #10095
Conversation
'& :hover': { | ||
color: '#4d99f1', | ||
}, | ||
'&& .MuiSvgIcon-root': { | ||
fill: theme.color.disabledText, |
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.
We only display the tooltip for when things are disabled
* spreading excessive styles for everywhere this is used. | ||
* | ||
*/ | ||
export const StyledTagButton = styled(Button, { |
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.
We can use this in other places as well, but I didn't want to expand the scope of this PR too much.
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.
👍 that being said we should both add a unit test and add/modify a story if it is meant to stay
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.
Agree with this new component and thanks for creating a test/story as per @abailly-akamai. Should we open a ticket for the other places?
@@ -78,7 +81,7 @@ export const SelectFirewallPanel = (props: Props) => { | |||
value={selectedFirewall} | |||
/> | |||
<StyledLinkButtonBox> | |||
<LinkButton onClick={handleCreateFirewallClick}> | |||
<LinkButton isDisabled={disabled} onClick={handleCreateFirewallClick}> |
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.
To disable this link in create flows for restricted users, probably should've been passed in to begin with.
@@ -87,6 +88,7 @@ const StyledConfigsButton = styled(Button, { | |||
})); | |||
|
|||
interface Props { | |||
grants: Grants | undefined; |
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.
Passing in grants
due to the fact this is a class component and it was available from it's parent.
@@ -123,7 +123,6 @@ export const CreateBucketDrawer = (props: Props) => { | |||
{isRestrictedUser && ( | |||
<Notice | |||
data-qa-permissions-notice | |||
important |
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.
Don't want the icon version for drawers anymore.
firewall: 'Firewalls', | ||
database: 'Databases', | ||
vpc: 'VPCs', | ||
}; |
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.
Moved to /src/features/Account/constants
Coverage Report: ❌ |
I'm not a huge fan of how we force a restricted user to look at a big yellow banner on landing pages. I think it would be nice if we had a more subtile way to indicate they have read-only permissions for example. For the load balancer empty state, should we disable the "Create" button with a tooltip instead of putting a yellow banner at the top? I still feel like "Access is restricted" is too generic. I think it would be nice to let the user know they have "read only permission" or that they "do not have permission to create"... Those are just my opinions on the UX aspect of this, will continue to review regardless. |
@bnussman-akamai I'll circle back to UX about the wording, but if you can review the functionality that would be awesome! |
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.
General functionality looks good! Have a few comments/questions
const disabled = | ||
Boolean(profile?.restricted) && !grants?.global.add_nodebalancers; | ||
Boolean(profile?.restricted) && | ||
!(grants?.global.add_nodebalancers && grants?.global.add_linodes); |
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 confirmed I was able to create a NodeBalancer as a restricted user without add_linodes
permission.
I understand why we might want to take add_linodes
into account for UX reasons, but I'd prefer if we just check add_nodebalancers
and not add_linodes
so we are in parity with how the API works.
Screen.Recording.2024-01-26.at.10.32.01.AM.mov
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.
+1 this. Any reason why the Add Linodes permission should be required for adding/modifying NodeBalancers?
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.
if that's the case we should document this in code more thouroughly
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.
Ahh yea I was under the impression that linodes with read_only perms couldn't be added to NodeBalancers, I guess that's not the case.
packages/manager/src/features/NodeBalancers/NodeBalancerDetail/NodeBalancerConfigurations.tsx
Outdated
Show resolved
Hide resolved
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.
Nice work! Added comments to clean things up and some questions. I'll give this a more thorough review once code improvements from reviewers have been addressed 👍
* spreading excessive styles for everywhere this is used. | ||
* | ||
*/ | ||
export const StyledTagButton = styled(Button, { |
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.
👍 that being said we should both add a unit test and add/modify a story if it is meant to stay
const disabled = | ||
Boolean(profile?.restricted) && !grants?.global.add_nodebalancers; | ||
Boolean(profile?.restricted) && | ||
!(grants?.global.add_nodebalancers && grants?.global.add_linodes); |
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.
if that's the case we should document this in code more thouroughly
packages/manager/src/features/NodeBalancers/NodeBalancerCreate.tsx
Outdated
Show resolved
Hide resolved
@@ -628,6 +645,8 @@ class NodeBalancerConfigurations extends React.Component<CombinedProps, State> { | |||
? parseInt(expandedConfigId, 10) === config.id | |||
: false; | |||
|
|||
const isRestricted = this.isRestrictedUser(); | |||
|
|||
const L = { |
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.
Not related to this PR, but const L
👎
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.
ramda 😡
packages/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancersLanding.tsx
Outdated
Show resolved
Hide resolved
...s/manager/src/features/NodeBalancers/NodeBalancersLanding/NodeBalancersLandingEmptyState.tsx
Outdated
Show resolved
Hide resolved
|
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.
Verified testing steps, LGTM! Thanks for considering others' feedback.
* spreading excessive styles for everywhere this is used. | ||
* | ||
*/ | ||
export const StyledTagButton = styled(Button, { |
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.
Agree with this new component and thanks for creating a test/story as per @abailly-akamai. Should we open a ticket for the other places?
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.
Reads so much better, thanks for the changes!
Feature behaves as described in the PR and looks great from my vantage point ✅
profile: Profile | undefined; | ||
}) => { | ||
return Boolean(profile?.restricted) && !grants?.global[globalGrantType]; | ||
}; |
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 know it's clear from the name however
- can we add return types here?
- i think it's always super useful to complement those utils with JSDocs
I updated it here, it was only one reference. |
Description 📝
To prevent unauthorized access to specific flows and provide clearer guidance, we aim to restrict entry to users without the required permissions while providing new notices.
Tooltips specifically designed for disabled buttons will persist within action menus. These tooltips prove valuable in scenarios where a restricted user has permission to delete their personal resources but lacks the permission to delete those belonging to the admin user. In such cases, we refrain from displaying notices on the page.
For restricted users:
Changes 🔄
useIsResourceRestricted
hook that verifies if a user with restricted access can edit specific cloud resources (Linodes, NodeBalancers, Volumes, etc.) Admin-created resources may be restricted, but those created by the restricted user are editable.entityNameMap
tograntTypeMap
and addedas const
in order to generate a union of the mapped names to provide type-safety touseIsResourceRestricted
and allow for capitalization/plurality in the names.StyledTagButton
to replace our one-off usages of adding tags.getRestrictedResourceText
utility to help generate resource-specific notices.isRestrictedGlobalGrantType
util which can be used to throughout Cloud Manager (+15 occurrences we can update in the future)Preview 📷
Note
We changed the banner slightly from the screenshots. The text will now say
You don't have permissions to ${action} ${resourceType}. Please contact your account administrator to request the necessary permissions.
How to test 🧪
Prerequisites
(How to setup test environment)
Read Only
for everythingReproduction steps
Restricted User Perm: "Read Only"
Restricted User Perm: "Read Only" w/ Can add Linodes, Can add NodeBalancers
As an Author I have considered 🤔
Check all that apply