mentionables.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. import {PureComponent} from 'react';
  2. import uniqBy from 'lodash/uniqBy';
  3. import MemberListStore from 'sentry/stores/memberListStore';
  4. import {Organization, Project, User} from 'sentry/types';
  5. import {callIfFunction} from 'sentry/utils/callIfFunction';
  6. import {isRenderFunc} from 'sentry/utils/isRenderFunc';
  7. import Projects from 'sentry/utils/projects';
  8. import withOrganization from 'sentry/utils/withOrganization';
  9. import {Mentionable} from './types';
  10. const buildUserId = (id: string) => `user:${id}`;
  11. const buildTeamId = (id: string) => `team:${id}`;
  12. type ChildFuncProps = {
  13. members: Mentionable[];
  14. teams: Mentionable[];
  15. };
  16. type Props = {
  17. children: (props: ChildFuncProps) => React.ReactNode;
  18. me: User;
  19. organization: Organization;
  20. projectSlugs: string[];
  21. };
  22. type State = {
  23. members: User[];
  24. };
  25. /**
  26. * Make sure the actionCreator, `fetchOrgMembers`, has been called somewhere
  27. * higher up the component chain.
  28. *
  29. * Will provide a list of users and teams that can be used for @-mentions
  30. * */
  31. class Mentionables extends PureComponent<Props, State> {
  32. state: State = {
  33. members: MemberListStore.getAll(),
  34. };
  35. componentWillUnmount() {
  36. this.listeners.forEach(callIfFunction);
  37. }
  38. listeners = [
  39. MemberListStore.listen((users: User[]) => {
  40. this.handleMemberListUpdate(users);
  41. }, undefined),
  42. ];
  43. handleMemberListUpdate = (members: User[]) => {
  44. if (members === this.state.members) {
  45. return;
  46. }
  47. this.setState({
  48. members,
  49. });
  50. };
  51. getMemberList(memberList: User[], sessionUser: User): Mentionable[] {
  52. const members = uniqBy(memberList, ({id}) => id).filter(
  53. ({id}) => !sessionUser || sessionUser.id !== id
  54. );
  55. return members.map(member => ({
  56. id: buildUserId(member.id),
  57. display: member.name,
  58. email: member.email,
  59. }));
  60. }
  61. getTeams(projects: Project[]): Mentionable[] {
  62. const uniqueTeams = uniqBy(
  63. projects
  64. .map(({teams}) => teams)
  65. .reduce((acc, teams) => acc.concat(teams || []), []),
  66. 'id'
  67. );
  68. return uniqueTeams.map(team => ({
  69. id: buildTeamId(team.id),
  70. display: `#${team.slug}`,
  71. email: team.id,
  72. }));
  73. }
  74. renderChildren = ({projects}) => {
  75. const {children, me} = this.props;
  76. if (isRenderFunc<ChildFuncProps>(children)) {
  77. return children({
  78. members: this.getMemberList(this.state.members, me),
  79. teams: this.getTeams(projects),
  80. });
  81. }
  82. return null;
  83. };
  84. render() {
  85. const {organization, projectSlugs} = this.props;
  86. if (!projectSlugs || !projectSlugs.length) {
  87. return this.renderChildren({projects: []});
  88. }
  89. return (
  90. <Projects slugs={projectSlugs} orgId={organization.slug}>
  91. {this.renderChildren}
  92. </Projects>
  93. );
  94. }
  95. }
  96. export default withOrganization(Mentionables);