organizations.tsx 4.6 KB

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