members.tsx 2.6 KB

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