role.tsx 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. import {useMemo} from 'react';
  2. import type {Organization} from 'sentry/types/organization';
  3. import type {User} from 'sentry/types/user';
  4. import {isActiveSuperuser} from 'sentry/utils/isActiveSuperuser';
  5. import {isRenderFunc} from 'sentry/utils/isRenderFunc';
  6. import {useUser} from 'sentry/utils/useUser';
  7. import withOrganization from 'sentry/utils/withOrganization';
  8. type RoleRenderProps = {
  9. hasRole: boolean;
  10. };
  11. type ChildrenRenderFn = (props: RoleRenderProps) => React.ReactElement | null;
  12. function checkUserRole(user: User, organization: Organization, role: RoleProps['role']) {
  13. if (!user) {
  14. return false;
  15. }
  16. if (isActiveSuperuser()) {
  17. return true;
  18. }
  19. if (!Array.isArray(organization.orgRoleList)) {
  20. return false;
  21. }
  22. const roleIds = organization.orgRoleList.map(r => r.id);
  23. if (!roleIds.includes(role) || !roleIds.includes(organization.orgRole ?? '')) {
  24. return false;
  25. }
  26. const requiredIndex = roleIds.indexOf(role);
  27. const currentIndex = roleIds.indexOf(organization.orgRole ?? '');
  28. return currentIndex >= requiredIndex;
  29. }
  30. interface RoleProps {
  31. /**
  32. * If children is a function then will be treated as a render prop and
  33. * passed RoleRenderProps.
  34. *
  35. * The other interface is more simple, only show `children` if user has
  36. * the minimum required role.
  37. */
  38. children: React.ReactElement | ChildrenRenderFn;
  39. /**
  40. * Current Organization
  41. */
  42. organization: Organization;
  43. /**
  44. * Minimum required role
  45. */
  46. role: string;
  47. }
  48. function Role({role, organization, children}: RoleProps): React.ReactElement | null {
  49. const user = useUser();
  50. const hasRole = useMemo(
  51. () => checkUserRole(user, organization, role),
  52. // It seems that this returns a stable reference, but
  53. [organization, role, user]
  54. );
  55. if (isRenderFunc<ChildrenRenderFn>(children)) {
  56. return children({hasRole});
  57. }
  58. return hasRole ? children : null;
  59. }
  60. const withOrganizationRole = withOrganization(Role);
  61. export {withOrganizationRole as Role};