index.tsx 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import {useCallback} from 'react';
  2. import {addErrorMessage} from 'sentry/actionCreators/indicator';
  3. import CheckboxField from 'sentry/components/forms/fields/checkboxField';
  4. import SelectField from 'sentry/components/forms/fields/selectField';
  5. import TextField from 'sentry/components/forms/fields/textField';
  6. import Form from 'sentry/components/forms/form';
  7. import {OnSubmitCallback} from "sentry/components/forms/types";
  8. import NarrowLayout from 'sentry/components/narrowLayout';
  9. import SentryDocumentTitle from 'sentry/components/sentryDocumentTitle';
  10. import {t, tct} from 'sentry/locale';
  11. import ConfigStore from 'sentry/stores/configStore';
  12. import {OrganizationSummary} from 'sentry/types';
  13. import {
  14. getRegionChoices,
  15. shouldDisplayRegions,
  16. } from 'sentry/utils/regions';
  17. import useApi from 'sentry/utils/useApi';
  18. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  19. function removeDataStorageLocationFromFormData(
  20. formData: Record<string, any>
  21. ): Record<string, any> {
  22. const shallowFormDataClone = {...formData};
  23. delete shallowFormDataClone.dataStorageLocation;
  24. return shallowFormDataClone;
  25. }
  26. function OrganizationCreate() {
  27. const termsUrl = ConfigStore.get('termsUrl');
  28. const privacyUrl = ConfigStore.get('privacyUrl');
  29. const regionChoices = getRegionChoices();
  30. const client = useApi();
  31. // This is a trimmed down version of the logic in ApiForm. It validates the
  32. // form data prior to submitting the request, and overrides the request host
  33. // with the selected region's URL if one is provided.
  34. const submitOrganizationCreate: OnSubmitCallback = useCallback((data, onSubmitSuccess, onSubmitError, _event, formModel) => {
  35. if (!formModel.validateForm()) {
  36. return;
  37. }
  38. const regionUrl = data.dataStorageLocation;
  39. client.request("/organizations/", {
  40. method:"POST",
  41. data: removeDataStorageLocationFromFormData(data),
  42. host: regionUrl,
  43. success: onSubmitSuccess,
  44. error: onSubmitError
  45. });
  46. }, [client]);
  47. return (
  48. <SentryDocumentTitle title={t('Create Organization')}>
  49. <NarrowLayout showLogout>
  50. <h3>{t('Create a New Organization')}</h3>
  51. <p>
  52. {t(
  53. "Organizations represent the top level in your hierarchy. You'll be able to bundle a collection of teams within an organization as well as give organization-wide permissions to users."
  54. )}
  55. </p>
  56. <Form
  57. initialData={{defaultTeam: true}}
  58. submitLabel={t('Create Organization')}
  59. apiEndpoint="/organizations/"
  60. apiMethod="POST"
  61. onSubmit={submitOrganizationCreate}
  62. onSubmitSuccess={(createdOrg: OrganizationSummary) => {
  63. const hasCustomerDomain = createdOrg?.features.includes('customer-domains');
  64. let nextUrl = normalizeUrl(
  65. `/organizations/${createdOrg.slug}/projects/new/`,
  66. {forceCustomerDomain: hasCustomerDomain}
  67. );
  68. if (hasCustomerDomain) {
  69. nextUrl = `${createdOrg.links.organizationUrl}${nextUrl}`;
  70. }
  71. // redirect to project creation *(BYPASS REACT ROUTER AND FORCE PAGE REFRESH TO GRAB CSRF TOKEN)*
  72. // browserHistory.pushState(null, `/organizations/${data.slug}/projects/new/`);
  73. window.location.assign(nextUrl);
  74. }}
  75. onSubmitError={error => {
  76. addErrorMessage(
  77. error.responseJSON?.detail ?? t('Unable to create organization.')
  78. );
  79. }}
  80. requireChanges
  81. >
  82. <TextField
  83. id="organization-name"
  84. name="name"
  85. label={t('Organization Name')}
  86. placeholder={t('e.g. My Company')}
  87. inline={false}
  88. flexibleControlStateSize
  89. stacked
  90. required
  91. />
  92. {shouldDisplayRegions() && (
  93. <SelectField
  94. name="dataStorageLocation"
  95. label="Data Storage Location"
  96. help="Where will this organization reside?"
  97. choices={regionChoices}
  98. inline={false}
  99. stacked
  100. required
  101. />
  102. )}
  103. {termsUrl && privacyUrl && (
  104. <CheckboxField
  105. name="agreeTerms"
  106. label={tct(
  107. 'I agree to the [termsLink:Terms of Service] and the [privacyLink:Privacy Policy]',
  108. {
  109. termsLink: <a href={termsUrl} />,
  110. privacyLink: <a href={privacyUrl} />,
  111. }
  112. )}
  113. inline={false}
  114. stacked
  115. required
  116. />
  117. )}
  118. </Form>
  119. </NarrowLayout>
  120. </SentryDocumentTitle>
  121. );
  122. }
  123. export default OrganizationCreate;