body.tsx 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import {Fragment, useState} from 'react';
  2. import AlertActions from 'sentry/actions/alertActions';
  3. import Alert from 'sentry/components/alert';
  4. import Button from 'sentry/components/button';
  5. import ErrorBoundary from 'sentry/components/errorBoundary';
  6. import Footer from 'sentry/components/footer';
  7. import {Body, Main} from 'sentry/components/layouts/thirds';
  8. import {IconWarning} from 'sentry/icons';
  9. import {t, tct} from 'sentry/locale';
  10. import {Organization} from 'sentry/types';
  11. import useApi from 'sentry/utils/useApi';
  12. import withOrganization from 'sentry/utils/withOrganization';
  13. type Props = {
  14. organization: Organization;
  15. children?: React.ReactNode;
  16. };
  17. function DeletionInProgress({organization}: Props) {
  18. return (
  19. <Body>
  20. <Main>
  21. <Alert type="warning" icon={<IconWarning />}>
  22. {tct(
  23. 'The [organization] organization is currently in the process of being deleted from Sentry.',
  24. {
  25. organization: <strong>{organization.slug}</strong>,
  26. }
  27. )}
  28. </Alert>
  29. </Main>
  30. </Body>
  31. );
  32. }
  33. function DeletionPending({organization}: Props) {
  34. const api = useApi();
  35. const [isRestoring, setIsRestoring] = useState(false);
  36. const onRestore = async () => {
  37. setIsRestoring(true);
  38. try {
  39. await api.requestPromise(`/organizations/${organization.slug}/`, {
  40. method: 'PUT',
  41. data: {cancelDeletion: true},
  42. });
  43. window.location.reload();
  44. } catch {
  45. setIsRestoring(false);
  46. AlertActions.addAlert({
  47. message:
  48. 'We were unable to restore this organization. Please try again or contact support.',
  49. type: 'error',
  50. });
  51. }
  52. };
  53. return (
  54. <Body>
  55. <Main>
  56. <h3>{t('Deletion Scheduled')}</h3>
  57. <p>
  58. {tct('The [organization] organization is currently scheduled for deletion.', {
  59. organization: <strong>{organization.slug}</strong>,
  60. })}
  61. </p>
  62. {organization.access.includes('org:admin') ? (
  63. <div>
  64. <p>
  65. {t(
  66. 'Would you like to cancel this process and restore the organization back to the original state?'
  67. )}
  68. </p>
  69. <p>
  70. <Button priority="primary" onClick={onRestore} disabled={isRestoring}>
  71. {t('Restore Organization')}
  72. </Button>
  73. </p>
  74. </div>
  75. ) : (
  76. <p>
  77. {t(
  78. 'If this is a mistake, contact an organization owner and ask them to restore this organization.'
  79. )}
  80. </p>
  81. )}
  82. <p>
  83. <small>
  84. {t(
  85. "Note: Restoration is available until the process begins. Once it does, there's no recovering the data that has been removed."
  86. )}
  87. </small>
  88. </p>
  89. </Main>
  90. </Body>
  91. );
  92. }
  93. function OrganizationDetailsBody({children, organization}: Props) {
  94. const status = organization?.status?.id;
  95. if (status === 'pending_deletion') {
  96. return <DeletionPending organization={organization} />;
  97. }
  98. if (status === 'deletion_in_progress') {
  99. return <DeletionInProgress organization={organization} />;
  100. }
  101. return (
  102. <Fragment>
  103. <ErrorBoundary>{children}</ErrorBoundary>
  104. <Footer />
  105. </Fragment>
  106. );
  107. }
  108. export default withOrganization(OrganizationDetailsBody);