organizations.tsx 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import {browserHistory} from 'react-router';
  2. import {addErrorMessage, addSuccessMessage} from 'sentry/actionCreators/indicator';
  3. import {resetPageFilters} from 'sentry/actionCreators/pageFilters';
  4. import {Client} from 'sentry/api';
  5. import {usingCustomerDomain} from 'sentry/constants';
  6. import GuideStore from 'sentry/stores/guideStore';
  7. import LatestContextStore from 'sentry/stores/latestContextStore';
  8. import OrganizationsStore from 'sentry/stores/organizationsStore';
  9. import OrganizationStore from 'sentry/stores/organizationStore';
  10. import ProjectsStore from 'sentry/stores/projectsStore';
  11. import TeamStore from 'sentry/stores/teamStore';
  12. import {Organization} from 'sentry/types';
  13. import {normalizeUrl} from 'sentry/utils/withDomainRequired';
  14. type RedirectRemainingOrganizationParams = {
  15. /**
  16. * The organization slug
  17. */
  18. orgId: string;
  19. /**
  20. * Should remove org?
  21. */
  22. removeOrg?: boolean;
  23. };
  24. /**
  25. * After removing an organization, this will redirect to a remaining active organization or
  26. * the screen to create a new organization.
  27. *
  28. * Can optionally remove organization from organizations store.
  29. */
  30. export function redirectToRemainingOrganization({
  31. orgId,
  32. removeOrg,
  33. }: RedirectRemainingOrganizationParams) {
  34. // Remove queued, should redirect
  35. const allOrgs = OrganizationsStore.getAll().filter(
  36. org => org.status.id === 'active' && org.slug !== orgId
  37. );
  38. if (!allOrgs.length) {
  39. browserHistory.push('/organizations/new/');
  40. return;
  41. }
  42. // Let's be smart and select the best org to redirect to
  43. const firstRemainingOrg = allOrgs[0];
  44. const route = `/organizations/${firstRemainingOrg.slug}/issues/`;
  45. if (usingCustomerDomain) {
  46. const {organizationUrl} = firstRemainingOrg.links;
  47. window.location.assign(`${organizationUrl}${normalizeUrl(route)}`);
  48. return;
  49. }
  50. browserHistory.push(route);
  51. // Remove org from SidebarDropdown
  52. if (removeOrg) {
  53. OrganizationsStore.remove(orgId);
  54. }
  55. }
  56. type RemoveParams = {
  57. /**
  58. * The organization slug
  59. */
  60. orgId: string;
  61. /**
  62. * An optional error message to be used in a toast, if remove fails
  63. */
  64. errorMessage?: string;
  65. /**
  66. * An optional success message to be used in a toast, if remove succeeds
  67. */
  68. successMessage?: string;
  69. };
  70. export function remove(api: Client, {successMessage, errorMessage, orgId}: RemoveParams) {
  71. const endpoint = `/organizations/${orgId}/`;
  72. return api
  73. .requestPromise(endpoint, {
  74. method: 'DELETE',
  75. })
  76. .then(() => {
  77. OrganizationsStore.onRemoveSuccess(orgId);
  78. if (successMessage) {
  79. addSuccessMessage(successMessage);
  80. }
  81. })
  82. .catch(() => {
  83. if (errorMessage) {
  84. addErrorMessage(errorMessage);
  85. }
  86. });
  87. }
  88. export function switchOrganization() {
  89. resetPageFilters();
  90. }
  91. export function removeAndRedirectToRemainingOrganization(
  92. api: Client,
  93. params: RedirectRemainingOrganizationParams & RemoveParams
  94. ) {
  95. remove(api, params).then(() => redirectToRemainingOrganization(params));
  96. }
  97. /**
  98. * Set active organization
  99. */
  100. export function setActiveOrganization(org: Organization) {
  101. GuideStore.setActiveOrganization(org);
  102. LatestContextStore.onSetActiveOrganization(org);
  103. }
  104. export function changeOrganizationSlug(
  105. prev: Organization,
  106. next: Partial<Organization> & Pick<Organization, 'slug'>
  107. ) {
  108. OrganizationsStore.onChangeSlug(prev, next);
  109. }
  110. /**
  111. * Updates an organization for the store
  112. *
  113. * Accepts a partial organization as it will merge will existing organization
  114. */
  115. export function updateOrganization(org: Partial<Organization>) {
  116. OrganizationsStore.onUpdate(org);
  117. OrganizationStore.onUpdate(org);
  118. }
  119. type FetchOrganizationByMemberParams = {
  120. addOrg?: boolean;
  121. fetchOrgDetails?: boolean;
  122. };
  123. export async function fetchOrganizationByMember(
  124. api: Client,
  125. memberId: string,
  126. {addOrg, fetchOrgDetails}: FetchOrganizationByMemberParams
  127. ) {
  128. const data = await api.requestPromise(`/organizations/?query=member_id:${memberId}`);
  129. if (!data.length) {
  130. return null;
  131. }
  132. const org = data[0];
  133. if (addOrg) {
  134. // add org to SwitchOrganization dropdown
  135. OrganizationsStore.addOrReplace(org);
  136. }
  137. if (fetchOrgDetails) {
  138. // load SidebarDropdown with org details including `access`
  139. await fetchOrganizationDetails(api, org.slug, {setActive: true, loadProjects: true});
  140. }
  141. return org;
  142. }
  143. type FetchOrganizationDetailsParams = {
  144. /**
  145. * Should load projects in ProjectsStore
  146. */
  147. loadProjects?: boolean;
  148. /**
  149. * Should load teams in TeamStore?
  150. */
  151. loadTeam?: boolean;
  152. /**
  153. * Should set as active organization?
  154. */
  155. setActive?: boolean;
  156. };
  157. export async function fetchOrganizationDetails(
  158. api: Client,
  159. orgId: string,
  160. {setActive, loadProjects, loadTeam}: FetchOrganizationDetailsParams
  161. ) {
  162. const data = await api.requestPromise(`/organizations/${orgId}/`);
  163. if (setActive) {
  164. setActiveOrganization(data);
  165. }
  166. if (loadTeam) {
  167. TeamStore.loadInitialData(data.teams, false, null);
  168. }
  169. if (loadProjects) {
  170. ProjectsStore.loadInitialData(data.projects || []);
  171. }
  172. return data;
  173. }