organization.tsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. import * as Sentry from '@sentry/react';
  2. import {addErrorMessage} from 'sentry/actionCreators/indicator';
  3. import {setActiveOrganization} from 'sentry/actionCreators/organizations';
  4. import GlobalSelectionActions from 'sentry/actions/globalSelectionActions';
  5. import OrganizationActions from 'sentry/actions/organizationActions';
  6. import ProjectActions from 'sentry/actions/projectActions';
  7. import TeamActions from 'sentry/actions/teamActions';
  8. import {Client} from 'sentry/api';
  9. import {Organization, Project, Team} from 'sentry/types';
  10. import {getPreloadedDataPromise} from 'sentry/utils/getPreloadedData';
  11. async function fetchOrg(
  12. api: Client,
  13. slug: string,
  14. isInitialFetch?: boolean
  15. ): Promise<Organization> {
  16. const org = await getPreloadedDataPromise(
  17. 'organization',
  18. slug,
  19. () =>
  20. // This data should get preloaded in static/sentry/index.ejs
  21. // If this url changes make sure to update the preload
  22. api.requestPromise(`/organizations/${slug}/`, {query: {detailed: 0}}),
  23. isInitialFetch
  24. );
  25. if (!org) {
  26. throw new Error('retrieved organization is falsey');
  27. }
  28. OrganizationActions.update(org, {replace: true});
  29. setActiveOrganization(org);
  30. return org;
  31. }
  32. async function fetchProjectsAndTeams(
  33. slug: string,
  34. isInitialFetch?: boolean
  35. ): Promise<[Project[], Team[]]> {
  36. // Create a new client so the request is not cancelled
  37. const uncancelableApi = new Client();
  38. const projectsPromise = getPreloadedDataPromise(
  39. 'projects',
  40. slug,
  41. () =>
  42. // This data should get preloaded in static/sentry/index.ejs
  43. // If this url changes make sure to update the preload
  44. uncancelableApi.requestPromise(`/organizations/${slug}/projects/`, {
  45. query: {
  46. all_projects: 1,
  47. collapse: 'latestDeploys',
  48. },
  49. }),
  50. isInitialFetch
  51. );
  52. const teamsPromise = getPreloadedDataPromise(
  53. 'teams',
  54. slug,
  55. // This data should get preloaded in static/sentry/index.ejs
  56. // If this url changes make sure to update the preload
  57. () => uncancelableApi.requestPromise(`/organizations/${slug}/teams/`),
  58. isInitialFetch
  59. );
  60. try {
  61. return await Promise.all([projectsPromise, teamsPromise]);
  62. } catch (err) {
  63. // It's possible these requests fail with a 403 if the user has a role with
  64. // insufficient access to projects and teams, but *can* access org details
  65. // (e.g. billing). An example of this is in org settings.
  66. //
  67. // Ignore 403s and bubble up other API errors
  68. if (err.status !== 403) {
  69. throw err;
  70. }
  71. }
  72. return [[], []];
  73. }
  74. /**
  75. * Fetches an organization's details
  76. *
  77. * @param api A reference to the api client
  78. * @param slug The organization slug
  79. * @param silent Should we silently update the organization (do not clear the
  80. * current organization in the store)
  81. */
  82. export async function fetchOrganizationDetails(
  83. api: Client,
  84. slug: string,
  85. silent: boolean,
  86. isInitialFetch?: boolean
  87. ) {
  88. if (!silent) {
  89. OrganizationActions.reset();
  90. ProjectActions.reset();
  91. GlobalSelectionActions.reset();
  92. }
  93. const loadOrganization = async () => {
  94. try {
  95. await fetchOrg(api, slug, isInitialFetch);
  96. } catch (err) {
  97. if (!err) {
  98. return;
  99. }
  100. OrganizationActions.fetchOrgError(err);
  101. if (err.status === 403 || err.status === 401) {
  102. const errMessage =
  103. typeof err.responseJSON?.detail === 'string'
  104. ? err.responseJSON?.detail
  105. : typeof err.responseJSON?.detail?.message === 'string'
  106. ? err.responseJSON?.detail.message
  107. : null;
  108. if (errMessage) {
  109. addErrorMessage(errMessage);
  110. }
  111. return;
  112. }
  113. Sentry.captureException(err);
  114. }
  115. };
  116. const loadTeamsAndProjects = async () => {
  117. const [projects, teams] = await fetchProjectsAndTeams(slug, isInitialFetch);
  118. ProjectActions.loadProjects(projects);
  119. TeamActions.loadTeams(teams);
  120. };
  121. return Promise.all([loadOrganization(), loadTeamsAndProjects()]);
  122. }