members.tsx 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. import * as Sentry from '@sentry/react';
  2. import {addErrorMessage} from 'sentry/actionCreators/indicator';
  3. import {Client} from 'sentry/api';
  4. import {t} from 'sentry/locale';
  5. import MemberListStore from 'sentry/stores/memberListStore';
  6. import {Member} from 'sentry/types';
  7. function getMemberUser(member: Member) {
  8. return {
  9. ...member.user,
  10. role: member.role,
  11. };
  12. }
  13. export async function fetchOrgMembers(
  14. api: Client,
  15. orgId: string,
  16. projectIds: string[] | null = null
  17. ): Promise<Member[]> {
  18. const endpoint = `/organizations/${orgId}/users/`;
  19. const query = projectIds ? {project: projectIds} : {};
  20. try {
  21. const members = await api.requestPromise(endpoint, {method: 'GET', query});
  22. if (!members) {
  23. // This shouldn't happen if the request was successful
  24. // It should at least be an empty list
  25. Sentry.withScope(scope => {
  26. scope.setExtras({
  27. orgId,
  28. projectIds,
  29. });
  30. Sentry.captureException(new Error('Members is undefined'));
  31. });
  32. }
  33. const memberUsers = members?.filter(({user}: Member) => user);
  34. if (!memberUsers) {
  35. return [];
  36. }
  37. // Update the store with just the users, as avatars rely on them.
  38. MemberListStore.loadInitialData(memberUsers.map(getMemberUser));
  39. return members;
  40. } catch (err) {
  41. addErrorMessage(t('Unable to load organization members'));
  42. }
  43. return [];
  44. }
  45. export type IndexedMembersByProject = Record<string, Member['user'][]>;
  46. /**
  47. * Convert a list of members with user & project data
  48. * into a object that maps project slugs : users in that project.
  49. */
  50. export function indexMembersByProject(members: Member[]): IndexedMembersByProject {
  51. return members.reduce((acc, member) => {
  52. for (const project of member.projects) {
  53. if (!acc.hasOwnProperty(project)) {
  54. acc[project] = [];
  55. }
  56. acc[project].push(member.user);
  57. }
  58. return acc;
  59. }, {});
  60. }
  61. type UpdateMemberOptions = {
  62. data: Member | null;
  63. memberId: string;
  64. orgId: string;
  65. };
  66. export function updateMember(api: Client, {orgId, memberId, data}: UpdateMemberOptions) {
  67. return api.requestPromise(`/organizations/${orgId}/members/${memberId}/`, {
  68. method: 'PUT',
  69. data,
  70. });
  71. }
  72. type ResendMemberInviteOptions = {
  73. memberId: string;
  74. orgId: string;
  75. regenerate?: boolean;
  76. };
  77. export function resendMemberInvite(
  78. api: Client,
  79. {orgId, memberId, regenerate}: ResendMemberInviteOptions
  80. ) {
  81. return api.requestPromise(`/organizations/${orgId}/members/${memberId}/`, {
  82. method: 'PUT',
  83. data: {
  84. regenerate,
  85. reinvite: true,
  86. },
  87. });
  88. }
  89. export function getCurrentMember(api: Client, orgId: string) {
  90. return api.requestPromise(`/organizations/${orgId}/members/me/`);
  91. }