role.tsx 1.9 KB

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