teamStore.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164
  1. import Reflux from 'reflux';
  2. import TeamActions from 'sentry/actions/teamActions';
  3. import {Team} from 'sentry/types';
  4. import {defined} from 'sentry/utils';
  5. import {CommonStoreInterface} from './types';
  6. type State = {
  7. cursor: string | null;
  8. hasMore: boolean | null;
  9. loadedUserTeams: boolean;
  10. loading: boolean;
  11. teams: Team[];
  12. };
  13. type TeamStoreInterface = CommonStoreInterface<State> & {
  14. getAll(): Team[];
  15. getById(id: string): Team | null;
  16. getBySlug(slug: string): Team | null;
  17. init(): void;
  18. initialized: boolean;
  19. loadInitialData(items: Team[], hasMore?: boolean | null, cursor?: string | null): void;
  20. onCreateSuccess(team: Team): void;
  21. onRemoveSuccess(slug: string): void;
  22. onUpdateSuccess(itemId: string, response: Team): void;
  23. reset(): void;
  24. state: State;
  25. };
  26. const teamStoreConfig: Reflux.StoreDefinition & TeamStoreInterface = {
  27. initialized: false,
  28. state: {
  29. teams: [],
  30. loadedUserTeams: false,
  31. loading: true,
  32. hasMore: null,
  33. cursor: null,
  34. },
  35. init() {
  36. this.reset();
  37. this.listenTo(TeamActions.createTeamSuccess, this.onCreateSuccess);
  38. this.listenTo(TeamActions.fetchDetailsSuccess, this.onUpdateSuccess);
  39. this.listenTo(TeamActions.loadTeams, this.loadInitialData);
  40. this.listenTo(TeamActions.loadUserTeams, this.loadUserTeams);
  41. this.listenTo(TeamActions.removeTeamSuccess, this.onRemoveSuccess);
  42. this.listenTo(TeamActions.updateSuccess, this.onUpdateSuccess);
  43. },
  44. reset() {
  45. this.state = {
  46. teams: [],
  47. loadedUserTeams: false,
  48. loading: true,
  49. hasMore: null,
  50. cursor: null,
  51. };
  52. },
  53. loadInitialData(items, hasMore, cursor) {
  54. this.initialized = true;
  55. this.state = {
  56. teams: items.sort((a, b) => a.slug.localeCompare(b.slug)),
  57. loadedUserTeams: defined(hasMore) ? !hasMore : this.state.loadedUserTeams,
  58. loading: false,
  59. hasMore: hasMore ?? this.state.hasMore,
  60. cursor: cursor ?? this.state.cursor,
  61. };
  62. this.trigger(new Set(items.map(item => item.id)));
  63. },
  64. loadUserTeams(userTeams: Team[]) {
  65. const teamIdMap = this.state.teams.reduce((acc: Record<string, Team>, team: Team) => {
  66. acc[team.id] = team;
  67. return acc;
  68. }, {});
  69. // Replace or insert new user teams
  70. userTeams.reduce((acc: Record<string, Team>, userTeam: Team) => {
  71. acc[userTeam.id] = userTeam;
  72. return acc;
  73. }, teamIdMap);
  74. const teams = Object.values(teamIdMap).sort((a, b) => a.slug.localeCompare(b.slug));
  75. this.state = {
  76. ...this.state,
  77. loadedUserTeams: true,
  78. teams,
  79. };
  80. this.trigger(new Set(Object.keys(teamIdMap)));
  81. },
  82. onUpdateSuccess(itemId, response) {
  83. if (!response) {
  84. return;
  85. }
  86. const item = this.getBySlug(itemId);
  87. if (!item) {
  88. this.state = {
  89. ...this.state,
  90. teams: [...this.state.teams, response],
  91. };
  92. this.trigger(new Set([itemId]));
  93. return;
  94. }
  95. // Slug was changed
  96. // Note: This is the proper way to handle slug changes but unfortunately not all of our
  97. // components use stores correctly. To be safe reload browser :((
  98. if (response.slug !== itemId) {
  99. // Replace the team
  100. const teams = [...this.state.teams.filter(({slug}) => slug !== itemId), response];
  101. this.state = {...this.state, teams};
  102. this.trigger(new Set([response.slug]));
  103. return;
  104. }
  105. const newTeams = [...this.state.teams];
  106. const index = newTeams.findIndex(team => team.slug === response.slug);
  107. newTeams[index] = response;
  108. this.state = {...this.state, teams: newTeams};
  109. this.trigger(new Set([itemId]));
  110. },
  111. onRemoveSuccess(slug: string) {
  112. const {teams} = this.state;
  113. this.loadInitialData(teams.filter(team => team.slug !== slug));
  114. },
  115. onCreateSuccess(team: Team) {
  116. this.loadInitialData([...this.state.teams, team]);
  117. },
  118. getState() {
  119. return this.state;
  120. },
  121. getById(id: string) {
  122. const {teams} = this.state;
  123. return teams.find(item => item.id.toString() === id.toString()) || null;
  124. },
  125. getBySlug(slug: string) {
  126. const {teams} = this.state;
  127. return teams.find(item => item.slug === slug) || null;
  128. },
  129. getAll() {
  130. return this.state.teams;
  131. },
  132. };
  133. const TeamStore = Reflux.createStore(teamStoreConfig) as Reflux.Store &
  134. TeamStoreInterface;
  135. export default TeamStore;