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

feat: managing teams #9285

Merged
merged 15 commits into from
Mar 8, 2024
Merged

feat: managing teams #9285

merged 15 commits into from
Mar 8, 2024

Conversation

BartoszJarocki
Copy link
Contributor

@BartoszJarocki BartoszJarocki commented Dec 13, 2023

Description

Resolves #9208 #9209 #9210 #9211 #9212 #9213 #9214 #9215 #9216 #9217 #9218

(EDITED by Jordan, PR continues below)

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
Copy link
Contributor

github-actions bot commented Mar 7, 2024

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",
Copy link
Contributor

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
Copy link
Contributor

github-actions bot commented Mar 7, 2024

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.

@jordanh
Copy link
Contributor

jordanh commented Mar 7, 2024

Description

First 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.

Demo

Loom 🔒

Testing scenarios

First, you must promote the user you're testing with to attain the ORG_ADMIN role:

query {
  user(email: "[email protected]") {
    id
  }
}
mutation {
  setOrgUserRole(orgId: "xyzxyzxyz", userId: "local|42424242", role: ORG_ADMIN) {
    ... on SetOrgUserRoleSuccess {
      updatedOrgMember {
        id
        role
      }
    }
  }
}
  • Can see all teams within an Org

  • Navigate to http://localhost:3000/me/organizations

  • Choose your org

  • Click on "Teams" from the sidebar

  • Can create teams

    • From the "Teams" view, click "Add Team"
  • Can add members

    • Choose a Team from the "Teams" view, click "Add Member"
  • Can remove members from any team

    • Choose a Team
    • Click 3-dots menu next to any member -> Remove member
  • Can see all members under my org

  • Can remove any member from my org

    • Choose 3-dots menu -> Remove member
  • Can promote and demote Org Admin role

    • Choose any other member
    • Promote member to Org Admin
    • Demote member to Org Admin

Final checklist

  • I checked the code review guidelines
  • I have added Metrics Representative as reviewer(s) if my PR invovles metrics/data/analytics related changes
  • I have performed a self-review of my code, the same way I'd do it for any other team member
  • I have tested all cases I listed in the testing scenarios and I haven't found any issues or regressions
  • Whenever I took a non-obvious choice I added a comment explaining why I did it this way
  • I added the label One Review Required if the PR introduces only minor changes, does not contain any architectural changes or does not introduce any new patterns and I think one review is sufficient'
  • PR title is human readable and could be used in changelog

Leave Organization
</StyledFlatButton>
)}
{(isViewerOrgAdmin || (isViewerBillingLeader && !isViewerLastBillingLeader)) && (
Copy link
Contributor

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

Copy link
Contributor

github-actions bot commented Mar 7, 2024

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.

@jordanh jordanh marked this pull request as ready for review March 7, 2024 15:44
@github-actions github-actions bot requested a review from mattkrick March 7, 2024 15:44
))}
</div>

{modalPortal(
Copy link
Contributor

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:

  1. If the ORG_ADMIN clicks the link, the client just-in-time fires a mutation to join this team
  2. 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
  3. Instead of having the ORG_ADMIN generate the mass-invite token, we masquerade as the Team Lead (ick)
  4. 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?

Copy link
Contributor

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.

Copy link
Contributor

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.

Copy link
Contributor

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>
Copy link
Contributor

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

Copy link
Contributor

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Done!

))}
</div>

{modalPortal(
Copy link
Contributor

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`
Copy link
Contributor

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

Copy link
Contributor

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()
Copy link
Contributor

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) => {
Copy link
Contributor

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

Copy link
Contributor

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}
Copy link
Contributor

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

Copy link
Contributor

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)
Copy link
Contributor

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

Copy link
Contributor

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'>
Copy link
Contributor

Choose a reason for hiding this comment

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

+1 the tables in Members, Org Settings etc, have some box shadow. This one is a little flat:

Screenshot 2024-03-07 at 18 02 59

Adding a shadow-sm would warm my heart. As would changing rounded to rounded-md.

Copy link
Contributor

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} />
Copy link
Contributor

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

Copy link
Contributor

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}
Copy link
Contributor

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.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was the team lead, I made a second user the team lead, and then clicked on my own menu button and saw it was empty:

Screenshot 2024-03-07 at 19 56 48

Copy link
Contributor

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'>
Copy link
Contributor

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

Copy link
Contributor

Choose a reason for hiding this comment

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

Nice suggestion, and done!

Copy link
Contributor

github-actions bot commented Mar 7, 2024

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.

Copy link
Contributor

github-actions bot commented Mar 7, 2024

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.

@jordanh
Copy link
Contributor

jordanh commented Mar 7, 2024

@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.

@nickoferrall nickoferrall merged commit f351cf9 into master Mar 8, 2024
4 checks passed
@nickoferrall nickoferrall deleted the feat/managing-teams branch March 8, 2024 13:14
@github-actions github-actions bot mentioned this pull request Mar 13, 2024
24 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
5 participants