projectsStatsStore.tsx 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
  1. import {createStore, StoreDefinition} from 'reflux';
  2. import ProjectActions from 'sentry/actions/projectActions';
  3. import {Project} from 'sentry/types';
  4. import {makeSafeRefluxStore} from 'sentry/utils/makeSafeRefluxStore';
  5. interface ProjectsStatsStoreDefinition extends StoreDefinition {
  6. getAll(): ProjectsStatsStoreDefinition['itemsBySlug'];
  7. getBySlug(slug: string): Project;
  8. getInitialState(): ProjectsStatsStoreDefinition['itemsBySlug'];
  9. itemsBySlug: Record<string, Project>;
  10. reset(): void;
  11. }
  12. /**
  13. * This is a store specifically used by the dashboard, so that we can
  14. * clear the store when the Dashboard unmounts
  15. * (as to not disrupt ProjectsStore which a lot more components use)
  16. */
  17. const storeConfig: ProjectsStatsStoreDefinition = {
  18. itemsBySlug: {},
  19. unsubscribeListeners: [],
  20. init() {
  21. this.reset();
  22. this.unsubscribeListeners.push(
  23. this.listenTo(ProjectActions.loadStatsForProjectSuccess, this.onStatsLoadSuccess)
  24. );
  25. this.unsubscribeListeners.push(this.listenTo(ProjectActions.update, this.onUpdate));
  26. this.unsubscribeListeners.push(
  27. this.listenTo(ProjectActions.updateError, this.onUpdateError)
  28. );
  29. },
  30. getInitialState() {
  31. return this.itemsBySlug;
  32. },
  33. reset() {
  34. this.itemsBySlug = {};
  35. this.updatingItems = new Map();
  36. },
  37. onStatsLoadSuccess(projects: Project[]) {
  38. projects.forEach(project => {
  39. this.itemsBySlug[project.slug] = project;
  40. });
  41. this.trigger(this.itemsBySlug);
  42. },
  43. /**
  44. * Optimistic updates
  45. * @param projectSlug Project slug
  46. * @param data Project data
  47. */
  48. onUpdate(projectSlug: string, data: Project) {
  49. const project = this.getBySlug(projectSlug);
  50. this.updatingItems.set(projectSlug, project);
  51. if (!project) {
  52. return;
  53. }
  54. const newProject: Project = {
  55. ...project,
  56. ...data,
  57. };
  58. this.itemsBySlug = {
  59. ...this.itemsBySlug,
  60. [project.slug]: newProject,
  61. };
  62. this.trigger(this.itemsBySlug);
  63. },
  64. onUpdateSuccess(data: Project) {
  65. // Remove project from updating map
  66. this.updatingItems.delete(data.slug);
  67. },
  68. /**
  69. * Revert project data when there was an error updating project details
  70. * @param err Error object
  71. * @param data Previous project data
  72. */
  73. onUpdateError(_err: Error, projectSlug: string) {
  74. const project = this.updatingItems.get(projectSlug);
  75. if (!project) {
  76. return;
  77. }
  78. this.updatingItems.delete(projectSlug);
  79. // Restore old project
  80. this.itemsBySlug = {
  81. ...this.itemsBySlug,
  82. [project.slug]: {...project},
  83. };
  84. this.trigger(this.itemsBySlug);
  85. },
  86. getAll() {
  87. return this.itemsBySlug;
  88. },
  89. getBySlug(slug) {
  90. return this.itemsBySlug[slug];
  91. },
  92. };
  93. const ProjectsStatsStore = createStore(makeSafeRefluxStore(storeConfig));
  94. export default ProjectsStatsStore;