index.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import {Component, Fragment} from 'react';
  2. import {browserHistory, RouteComponentProps} from 'react-router';
  3. import {addLoadingMessage} from 'app/actionCreators/indicator';
  4. import {
  5. changeOrganizationSlug,
  6. removeAndRedirectToRemainingOrganization,
  7. updateOrganization,
  8. } from 'app/actionCreators/organizations';
  9. import {Client} from 'app/api';
  10. import Button from 'app/components/button';
  11. import Confirm from 'app/components/confirm';
  12. import {Panel, PanelHeader} from 'app/components/panels';
  13. import SentryDocumentTitle from 'app/components/sentryDocumentTitle';
  14. import {t, tct} from 'app/locale';
  15. import {Organization} from 'app/types';
  16. import withApi from 'app/utils/withApi';
  17. import withOrganization from 'app/utils/withOrganization';
  18. import Field from 'app/views/settings/components/forms/field';
  19. import SettingsPageHeader from 'app/views/settings/components/settingsPageHeader';
  20. import TextBlock from 'app/views/settings/components/text/textBlock';
  21. import PermissionAlert from 'app/views/settings/organization/permissionAlert';
  22. import OrganizationSettingsForm from './organizationSettingsForm';
  23. type Props = {
  24. api: Client;
  25. organization: Organization;
  26. } & RouteComponentProps<{orgId: string}, {}>;
  27. class OrganizationGeneralSettings extends Component<Props> {
  28. handleRemoveOrganization = () => {
  29. const {api, organization, params} = this.props;
  30. if (!organization) {
  31. return;
  32. }
  33. addLoadingMessage();
  34. removeAndRedirectToRemainingOrganization(api, {
  35. orgId: params.orgId,
  36. successMessage: `${organization.name} is queued for deletion.`,
  37. errorMessage: `Error removing the ${organization.name} organization`,
  38. });
  39. };
  40. handleSave = (prevData: Organization, data: Partial<Organization>) => {
  41. if (data.slug && data.slug !== prevData.slug) {
  42. changeOrganizationSlug(
  43. prevData,
  44. data as Partial<Organization> & Pick<Organization, 'slug'>
  45. );
  46. browserHistory.replace(`/settings/${data.slug}/`);
  47. } else {
  48. // This will update OrganizationStore (as well as OrganizationsStore
  49. // which is slightly incorrect because it has summaries vs a detailed org)
  50. updateOrganization(data);
  51. }
  52. };
  53. render() {
  54. const {organization, params} = this.props;
  55. const {orgId} = params;
  56. const access = new Set(organization.access);
  57. const hasProjects = organization.projects && !!organization.projects.length;
  58. return (
  59. <Fragment>
  60. <SentryDocumentTitle title={t('General Settings')} orgSlug={orgId} />
  61. <div>
  62. <SettingsPageHeader title={t('Organization Settings')} />
  63. <PermissionAlert />
  64. <OrganizationSettingsForm
  65. {...this.props}
  66. initialData={organization}
  67. access={access}
  68. onSave={this.handleSave}
  69. />
  70. {access.has('org:admin') && !organization.isDefault && (
  71. <Panel>
  72. <PanelHeader>{t('Remove Organization')}</PanelHeader>
  73. <Field
  74. label={t('Remove Organization')}
  75. help={t(
  76. 'Removing this organization will delete all data including projects and their associated events.'
  77. )}
  78. >
  79. <div>
  80. <Confirm
  81. priority="danger"
  82. confirmText={t('Remove Organization')}
  83. message={
  84. <div>
  85. <TextBlock>
  86. {tct(
  87. 'Removing the organization, [name] is permanent and cannot be undone! Are you sure you want to continue?',
  88. {
  89. name: organization && <strong>{organization.name}</strong>,
  90. }
  91. )}
  92. </TextBlock>
  93. {hasProjects && (
  94. <div>
  95. <TextBlock noMargin>
  96. {t(
  97. 'This will also remove the following associated projects:'
  98. )}
  99. </TextBlock>
  100. <ul className="ref-projects">
  101. {organization.projects.map(project => (
  102. <li key={project.slug}>{project.slug}</li>
  103. ))}
  104. </ul>
  105. </div>
  106. )}
  107. </div>
  108. }
  109. onConfirm={this.handleRemoveOrganization}
  110. >
  111. <Button
  112. priority="danger"
  113. title={t(
  114. 'Remove %s organization',
  115. organization && organization.name
  116. )}
  117. >
  118. {t('Remove Organization')}
  119. </Button>
  120. </Confirm>
  121. </div>
  122. </Field>
  123. </Panel>
  124. )}
  125. </div>
  126. </Fragment>
  127. );
  128. }
  129. }
  130. export default withApi(withOrganization(OrganizationGeneralSettings));