access.tsx 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. import {Component} from 'react';
  2. import Alert from 'sentry/components/alert';
  3. import {t} from 'sentry/locale';
  4. import {Config, Organization, Scope} from 'sentry/types';
  5. import {isRenderFunc} from 'sentry/utils/isRenderFunc';
  6. import withConfig from 'sentry/utils/withConfig';
  7. import withOrganization from 'sentry/utils/withOrganization';
  8. const DEFAULT_NO_ACCESS_MESSAGE = (
  9. <Alert type="error" showIcon>
  10. {t('You do not have sufficient permissions to access this.')}
  11. </Alert>
  12. );
  13. // Props that function children will get.
  14. export type ChildRenderProps = {
  15. hasAccess: boolean;
  16. hasSuperuser: boolean;
  17. };
  18. type ChildFunction = (props: ChildRenderProps) => React.ReactNode;
  19. type DefaultProps = {
  20. /**
  21. * List of required access levels
  22. */
  23. access: Scope[];
  24. /**
  25. * Custom renderer function for "no access" message OR `true` to use
  26. * default message. `false` will suppress message.
  27. */
  28. renderNoAccessMessage: ChildFunction | boolean;
  29. /**
  30. * Requires superuser
  31. */
  32. isSuperuser?: boolean;
  33. /**
  34. * Should the component require all access levels or just one or more.
  35. */
  36. requireAll?: boolean;
  37. };
  38. const defaultProps: DefaultProps = {
  39. renderNoAccessMessage: false,
  40. isSuperuser: false,
  41. requireAll: true,
  42. access: [],
  43. };
  44. type Props = {
  45. /**
  46. * Configuration from ConfigStore
  47. */
  48. config: Config;
  49. /**
  50. * Current Organization
  51. */
  52. organization: Organization;
  53. /**
  54. * Children can be a node or a function as child.
  55. */
  56. children?: React.ReactNode | ChildFunction;
  57. } & Partial<DefaultProps>;
  58. /**
  59. * Component to handle access restrictions.
  60. */
  61. class Access extends Component<Props> {
  62. static defaultProps = defaultProps;
  63. render() {
  64. const {
  65. organization,
  66. config,
  67. access,
  68. requireAll,
  69. isSuperuser,
  70. renderNoAccessMessage,
  71. children,
  72. } = this.props;
  73. const {access: orgAccess} = organization || {access: []};
  74. const method = requireAll ? 'every' : 'some';
  75. const hasAccess = !access || access[method](acc => orgAccess.includes(acc));
  76. const hasSuperuser = !!(config.user && config.user.isSuperuser);
  77. const renderProps: ChildRenderProps = {
  78. hasAccess,
  79. hasSuperuser,
  80. };
  81. const render = hasAccess && (!isSuperuser || hasSuperuser);
  82. if (!render && typeof renderNoAccessMessage === 'function') {
  83. return renderNoAccessMessage(renderProps);
  84. }
  85. if (!render && renderNoAccessMessage) {
  86. return DEFAULT_NO_ACCESS_MESSAGE;
  87. }
  88. if (isRenderFunc<ChildFunction>(children)) {
  89. return children(renderProps);
  90. }
  91. return render ? children : null;
  92. }
  93. }
  94. export default withOrganization(withConfig(Access));