-
Notifications
You must be signed in to change notification settings - Fork 333
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: managing teams #9285
feat: managing teams #9285
Conversation
d01f583
to
ca157f7
Compare
ca157f7
to
a73feae
Compare
Also: feat: As a SuperAdmin, I can promote others to SuperAdmin feat: As a SuperAdmin, I can demote others to other roles chore: yarn changes chore: update .vscode/launch.json from dep. pwa-chome to chrome
d3123a3
to
1e45eb4
Compare
This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR will be delayed and might be rejected due to its size. |
@@ -30,15 +30,15 @@ | |||
{ | |||
"name": "Launch Chrome", | |||
"request": "launch", | |||
"type": "pwa-chrome", |
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.
pwa-chrome is no longer supported on my version of VS Code, the type is now simply chrome
Also: feat: As a SuperAdmin, I can promote others to SuperAdmin feat: As a SuperAdmin, I can demote others to other roles chore: yarn changes chore: update .vscode/launch.json from dep. pwa-chome to chrome
This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR will be delayed and might be rejected due to its size. |
DescriptionFirst off, my sincere apologies for the size of this PR. It passed from @BartoszJarocki to @mwermuth and now I'm taking it over the line. This PR is a "first cut" of allowing a SuperAdmin to be able to manage their organization. Acceptance Criteria / Test Cases are given below. DemoLoom 🔒 Testing scenariosFirst, you must promote the user you're testing with to attain the query {
user(email: "[email protected]") {
id
}
} mutation {
setOrgUserRole(orgId: "xyzxyzxyz", userId: "local|42424242", role: ORG_ADMIN) {
... on SetOrgUserRoleSuccess {
updatedOrgMember {
id
role
}
}
}
}
Final checklist
|
Leave Organization | ||
</StyledFlatButton> | ||
)} | ||
{(isViewerOrgAdmin || (isViewerBillingLeader && !isViewerLastBillingLeader)) && ( |
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.
This (and below) was the most significant change I made to what was started:
I created a wholly new control for Org Admin actions vs. actions that can be taken by the BillingLeader. This helped simplify logic when decided what role can take what action
This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR will be delayed and might be rejected due to its size. |
))} | ||
</div> | ||
|
||
{modalPortal( |
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.
@nickoferrall I've noted a bug just now that needs resolving before this can be merged. If the ORG_ADMIN
is not a member of the team, the mutation that creates the MassInvitation link will fail. I can see 4 options:
- If the ORG_ADMIN clicks the link, the client just-in-time fires a mutation to join this team
- We do the same thing, but on the server-side: if an ORG_ADMIN tries to create a massInvite token, they are joined to the team first
- Instead of having the ORG_ADMIN generate the mass-invite token, we masquerade as the Team Lead (ick)
- We remove the "Add Member" functionality all together
I am split between options #1 and #4 and would love a second opinion. What do you think?
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.
Why not just allow creating mass invitations from non-team members if they are an org admin? It could be irritating to join all those teams and getting the notifications and all.
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 think that handling everything on the server would be ideal as it's more secure and less error-prone, but I think we should go with option four.
The PR is already a big 'un. Shipping this without the "Add Member" functionality will still add a lot of value, so I think we should work on "Add Member" in a separate PR.
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.
@nickoferrall I like your logic there. Ok, I will do that.
Why not just allow creating mass invitations from non-team members if they are an org admin? It could be irritating to join all those teams and getting the notifications and all.
The underlying data model has the massInvitation belonging to a TeamMember. I suppose the fifth (and best) option would be to modify the massInvitation table to have invitations also be able to belong to non-TeamMembers (i.e. the ORG_ADMIN) as well
I'd probably be nice to get that table off of rethinkdb before making that modification
<div className='divide-y divide-slate-300 overflow-hidden rounded border border-slate-300 bg-white'> | ||
<div className='bg-slate-100 px-4 py-2'> | ||
<div className='flex w-full justify-between'> | ||
<div className='flex items-center font-bold'>{allTeams.length} Teams</div> |
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 if there's only one team, the copy should be "Team" rather than "Teams". We can use the plural helper function for this: https://github.com/ParabolInc/parabol/blob/8c68bf771a350b31c7948e6bd11c5c110e30c977/packages/client/utils/plural.ts
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.
^ this is from a review in progress, not complete
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.
Done!
))} | ||
</div> | ||
|
||
{modalPortal( |
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 think that handling everything on the server would be ideal as it's more secure and less error-prone, but I think we should go with option four.
The PR is already a big 'un. Shipping this without the "Add Member" functionality will still add a lot of value, so I think we should work on "Add Member" in a separate PR.
history.push(`/me/organizations/${teamOrgId}/teams`) | ||
} | ||
|
||
const labelStyles = `text-left text-sm font-semibold mb-3 text-slate-600` |
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 these vars are just used in one place, so I find it kinda confusing that they're defined here rather than inline with the rest of the classNames
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 agree! I'll update
<Input | ||
autoFocus | ||
onChange={(e) => { | ||
e.preventDefault() |
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 e.preventDefault()
can be removed as there's no default to prevent. It'd probably be cleaner to move this to a handleChange
function, but not important
teamOrgId: string | ||
} | ||
|
||
const DeleteTeamDialogRoot = (props: Props) => { |
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 I know you didn't write this, but I think we should delete this file. The convention is using Root components for lazy loading where we have a separate query.
As there's no query here, we should delete it and just use DeleteTeamDialog
in the parent
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.
Oh for sure, nice catch
<Suspense fallback={<Loader />}> | ||
<DeleteTeamDialog | ||
onDeleteTeam={onDeleteTeam} | ||
isOpen={true} |
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 rather than isOpen={true}
, in the parent component, we can use isDeleteTeamDialogOpened
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.
Thank you, I done did it this way :)
) | ||
} | ||
|
||
export default withMutationProps(OrgAdminActionMenu) |
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 we're normally now using the hook useMutation
rather than this HOC
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.
Thank you for helping me climb the learning curve. I refactored this
</div> | ||
</div> | ||
|
||
<div className='divide-y divide-slate-300 overflow-hidden rounded border border-slate-300 bg-white'> |
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.
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.
Done!
{picture ? ( | ||
<Avatar hasBadge={false} picture={picture} size={44} /> | ||
) : ( | ||
<img alt='' src={defaultUserAvatar} /> |
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 alt tag could be default avatar
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.
done
</div> | ||
<div> | ||
<Button | ||
disabled={!showMenuButton} |
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 as a new user, I go to the org team members page, I just see myself in the org members table, and I see the menu button. The menu button is disabled and I don't get feedback as to why it's disabled.
I think we should hide the button instead of disabling it or show a tooltip on hover explaining why it's disabled.
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.
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.
Great finds! Fixed up
</div> | ||
</div> | ||
|
||
<div className='divide-y divide-slate-300 overflow-hidden rounded border border-slate-300 bg-white'> |
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 adding rounded-md
and shadow-sm
would also make this table more consistent with the others and help it pop
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 suggestion, and done!
down scoping this PR
This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR will be delayed and might be rejected due to its size. |
This PR exceeds the recommended size of 1000 lines. Please make sure you are NOT addressing multiple issues with one PR. Note this PR will be delayed and might be rejected due to its size. |
@nickoferrall thank's for the review! I think I've addressed you're review. If you feel comfortable merging, please do. Else, happy to address anything else or pass to another reviewer. |
Description
Resolves #9208 #9209 #9210 #9211 #9212 #9213 #9214 #9215 #9216 #9217 #9218
(EDITED by Jordan, PR continues below)