|
@@ -1,7 +1,7 @@
|
|
|
import * as React from 'react';
|
|
|
|
|
|
import ConfigStore from 'sentry/stores/configStore';
|
|
|
-import {Organization} from 'sentry/types';
|
|
|
+import {Organization, User} from 'sentry/types';
|
|
|
import {isActiveSuperuser} from 'sentry/utils/isActiveSuperuser';
|
|
|
import {isRenderFunc} from 'sentry/utils/isRenderFunc';
|
|
|
import withOrganization from 'sentry/utils/withOrganization';
|
|
@@ -10,9 +10,33 @@ type RoleRenderProps = {
|
|
|
hasRole: boolean;
|
|
|
};
|
|
|
|
|
|
-type ChildrenRenderFn = (props: RoleRenderProps) => React.ReactNode;
|
|
|
+type ChildrenRenderFn = (props: RoleRenderProps) => React.ReactElement | null;
|
|
|
|
|
|
-type Props = {
|
|
|
+function checkUserRole(user: User, organization: Organization, role: RoleProps['role']) {
|
|
|
+ if (!user) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (isActiveSuperuser()) {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!Array.isArray(organization.availableRoles)) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ const roleIds = organization.availableRoles.map(r => r.id);
|
|
|
+
|
|
|
+ if (!roleIds.includes(role) || !roleIds.includes(organization.role ?? '')) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ const requiredIndex = roleIds.indexOf(role);
|
|
|
+ const currentIndex = roleIds.indexOf(organization.role ?? '');
|
|
|
+ return currentIndex >= requiredIndex;
|
|
|
+}
|
|
|
+
|
|
|
+interface RoleProps {
|
|
|
/**
|
|
|
* Minimum required role
|
|
|
*/
|
|
@@ -28,50 +52,23 @@ type Props = {
|
|
|
* The other interface is more simple, only show `children` if user has
|
|
|
* the minimum required role.
|
|
|
*/
|
|
|
- children: React.ReactNode | ChildrenRenderFn;
|
|
|
-};
|
|
|
-
|
|
|
-class Role extends React.Component<Props> {
|
|
|
- hasRole() {
|
|
|
- const user = ConfigStore.get('user');
|
|
|
- const {organization, role} = this.props;
|
|
|
- const {availableRoles} = organization;
|
|
|
-
|
|
|
- const currentRole = organization.role ?? '';
|
|
|
-
|
|
|
- if (!user) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- if (isActiveSuperuser()) {
|
|
|
- return true;
|
|
|
- }
|
|
|
-
|
|
|
- if (!Array.isArray(availableRoles)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
-
|
|
|
- const roleIds = availableRoles.map(r => r.id);
|
|
|
+ children: React.ReactElement | ChildrenRenderFn;
|
|
|
+}
|
|
|
|
|
|
- if (!roleIds.includes(role) || !roleIds.includes(currentRole)) {
|
|
|
- return false;
|
|
|
- }
|
|
|
+function Role({role, organization, children}: RoleProps): React.ReactElement | null {
|
|
|
+ const hasRole = React.useMemo(
|
|
|
+ () => checkUserRole(ConfigStore.get('user'), organization, role),
|
|
|
+ // It seems that this returns a stable reference, but
|
|
|
+ [organization, role, ConfigStore.get('user')]
|
|
|
+ );
|
|
|
|
|
|
- const requiredIndex = roleIds.indexOf(role);
|
|
|
- const currentIndex = roleIds.indexOf(currentRole);
|
|
|
- return currentIndex >= requiredIndex;
|
|
|
+ if (isRenderFunc<ChildrenRenderFn>(children)) {
|
|
|
+ return children({hasRole});
|
|
|
}
|
|
|
|
|
|
- render() {
|
|
|
- const {children} = this.props;
|
|
|
- const hasRole = this.hasRole();
|
|
|
-
|
|
|
- if (isRenderFunc<ChildrenRenderFn>(children)) {
|
|
|
- return children({hasRole});
|
|
|
- }
|
|
|
-
|
|
|
- return hasRole && children ? children : null;
|
|
|
- }
|
|
|
+ return hasRole ? children : null;
|
|
|
}
|
|
|
|
|
|
-export default withOrganization(Role);
|
|
|
+const withOrganizationRole = withOrganization(Role);
|
|
|
+
|
|
|
+export {withOrganizationRole as Role};
|