Browse Source

fix(ts): Correct types of Member['user'] (#49261)

The user may be null when it is a member invite
Evan Purkhiser 1 year ago
parent
commit
c1e3eed5ce

+ 6 - 4
static/app/actionCreators/members.tsx

@@ -4,7 +4,7 @@ import {addErrorMessage} from 'sentry/actionCreators/indicator';
 import {Client} from 'sentry/api';
 import {t} from 'sentry/locale';
 import MemberListStore from 'sentry/stores/memberListStore';
-import {Member} from 'sentry/types';
+import {Member, User} from 'sentry/types';
 
 function getMemberUser(member: Member) {
   return {
@@ -53,19 +53,21 @@ export async function fetchOrgMembers(
   return [];
 }
 
-export type IndexedMembersByProject = Record<string, Member['user'][]>;
+export type IndexedMembersByProject = Record<string, User[]>;
 
 /**
  * Convert a list of members with user & project data
  * into a object that maps project slugs : users in that project.
  */
 export function indexMembersByProject(members: Member[]): IndexedMembersByProject {
-  return members.reduce((acc, member) => {
+  return members.reduce<IndexedMembersByProject>((acc, member) => {
     for (const project of member.projects) {
       if (!acc.hasOwnProperty(project)) {
         acc[project] = [];
       }
-      acc[project].push(member.user);
+      if (member.user) {
+        acc[project].push(member.user);
+      }
     }
     return acc;
   }, {});

+ 4 - 1
static/app/types/organization.tsx

@@ -145,7 +145,10 @@ export interface Member {
     teamSlug: string;
   }[];
   teams: string[]; // # Deprecated, use teamRoles
-  user: User;
+  /**
+   * User may be null when the member represents an invited member
+   */
+  user: User | null;
 }
 
 /**

+ 1 - 1
static/app/views/alerts/rules/issue/details/textRule.tsx

@@ -82,7 +82,7 @@ export function TextAction({
 }) {
   if (action.targetType === 'Member') {
     const user = memberList.find(
-      member => member.user.id === `${action.targetIdentifier}`
+      member => member.user?.id === `${action.targetIdentifier}`
     );
     return (
       <Fragment>{t('Send a notification to %s', user?.email ?? t('unknown'))}</Fragment>

+ 3 - 3
static/app/views/settings/organizationIntegrations/integrationExternalUserMappings.tsx

@@ -80,7 +80,7 @@ class IntegrationExternalUserMappings extends AsyncComponent<Props, State> {
       acc.push(
         ...externalUsers
           .filter(externalUser => externalUser.provider === integration.provider.key)
-          .map(externalUser => ({...externalUser, sentryName: user.name}))
+          .map(externalUser => ({...externalUser, sentryName: user?.name ?? member.name}))
       );
       return acc;
     }, [] as ExternalActorMapping[]);
@@ -105,9 +105,9 @@ class IntegrationExternalUserMappings extends AsyncComponent<Props, State> {
   sentryNamesMapper(members: Member[]) {
     return members
       .filter(member => member.user)
-      .map(({user: {id}, email, name}) => {
+      .map(({user, email, name}) => {
         const label = email !== name ? `${name} - ${email}` : `${email}`;
-        return {id, name: label};
+        return {id: user?.id!, name: label};
       });
   }
 

+ 3 - 3
static/app/views/settings/organizationMembers/organizationMemberDetail.tsx

@@ -156,9 +156,9 @@ class OrganizationMemberDetail extends AsyncView<Props, State> {
     const {organization, router} = this.props;
     const {user} = this.state.member!;
 
-    const requests = user.authenticators.map(auth =>
-      removeAuthenticator(this.api, user.id, auth.id)
-    );
+    const requests =
+      user?.authenticators.map(auth => removeAuthenticator(this.api, user.id, auth.id)) ??
+      [];
 
     try {
       await Promise.all(requests);

+ 4 - 1
static/app/views/settings/organizationMembers/organizationMemberRow.tsx

@@ -123,7 +123,10 @@ export default class OrganizationMemberRow extends PureComponent<Props, State> {
     return (
       <StyledPanelItem data-test-id={email}>
         <MemberHeading>
-          <UserAvatar size={32} user={user ?? {id: email, email}} />
+          <UserAvatar
+            size={32}
+            user={user ?? {email, id: email, name: email, type: 'user'}}
+          />
           <MemberDescription to={detailsUrl}>
             <h5 style={{margin: '0 0 3px'}}>
               <UserName>{name}</UserName>