permissionsObserver.tsx 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. import {Component, Fragment} from 'react';
  2. import {Alert} from 'sentry/components/alert';
  3. import Panel from 'sentry/components/panels/panel';
  4. import PanelBody from 'sentry/components/panels/panelBody';
  5. import PanelHeader from 'sentry/components/panels/panelHeader';
  6. import {t} from 'sentry/locale';
  7. import type {Permissions, Scope, WebhookEvent} from 'sentry/types';
  8. import {
  9. comparePermissionLevels,
  10. toResourcePermissions,
  11. } from 'sentry/utils/consolidatedScopes';
  12. import PermissionSelection from 'sentry/views/settings/organizationDeveloperSettings/permissionSelection';
  13. import Subscriptions from 'sentry/views/settings/organizationDeveloperSettings/resourceSubscriptions';
  14. type DefaultProps = {
  15. appPublished: boolean;
  16. webhookDisabled: boolean;
  17. };
  18. type Props = DefaultProps & {
  19. events: WebhookEvent[];
  20. newApp: boolean;
  21. scopes: Scope[];
  22. };
  23. type State = {
  24. elevating: boolean;
  25. events: WebhookEvent[];
  26. permissions: Permissions;
  27. };
  28. export default class PermissionsObserver extends Component<Props, State> {
  29. static defaultProps: DefaultProps = {
  30. webhookDisabled: false,
  31. appPublished: false,
  32. };
  33. constructor(props: Props) {
  34. super(props);
  35. this.state = {
  36. permissions: this.scopeListToPermissionState(),
  37. events: this.props.events,
  38. elevating: false,
  39. };
  40. }
  41. /**
  42. * Converts the list of raw API scopes passed in to an object that can
  43. * before stored and used via `state`. This object is structured by
  44. * resource and holds "Permission" values. For example:
  45. *
  46. * {
  47. * 'Project': 'read',
  48. * ...,
  49. * }
  50. *
  51. */
  52. scopeListToPermissionState() {
  53. return toResourcePermissions(this.props.scopes);
  54. }
  55. onPermissionChange = (permissions: Permissions) => {
  56. this.setState({permissions});
  57. const new_permissions = toResourcePermissions(this.props.scopes);
  58. let elevating = false;
  59. Object.keys(permissions).some((resource_name: string) => {
  60. if (
  61. comparePermissionLevels(
  62. permissions[resource_name],
  63. new_permissions[resource_name]
  64. ) > 0
  65. ) {
  66. elevating = true;
  67. return true;
  68. }
  69. return false;
  70. });
  71. this.setState({elevating});
  72. };
  73. onEventChange = (events: WebhookEvent[]) => {
  74. this.setState({events});
  75. };
  76. renderCallout() {
  77. const {elevating} = this.state;
  78. if (!this.props.newApp && elevating === true) {
  79. return (
  80. <Alert type="warning" showIcon>
  81. {t(
  82. 'You are going to increase privileges for this integration. Organization members who already had access to the Client Secret may gain extra permissions due to this change. If this is not what you are expecting, consider re-creating the integration.'
  83. )}
  84. </Alert>
  85. );
  86. }
  87. return null;
  88. }
  89. render() {
  90. const {permissions, events} = this.state;
  91. return (
  92. <Fragment>
  93. <Panel>
  94. <PanelHeader>{t('Permissions')}</PanelHeader>
  95. <PanelBody>
  96. <PermissionSelection
  97. permissions={permissions}
  98. onChange={this.onPermissionChange}
  99. appPublished={this.props.appPublished}
  100. />
  101. {this.renderCallout()}
  102. </PanelBody>
  103. </Panel>
  104. <Panel>
  105. <PanelHeader>{t('Webhooks')}</PanelHeader>
  106. <PanelBody>
  107. <Subscriptions
  108. permissions={permissions}
  109. events={events}
  110. onChange={this.onEventChange}
  111. webhookDisabled={this.props.webhookDisabled}
  112. />
  113. </PanelBody>
  114. </Panel>
  115. </Fragment>
  116. );
  117. }
  118. }