Files
sentinel/static/app/stores/projectsStatsStore.tsx
2024-02-15 17:01:50 +00:00

109 lines
2.6 KiB
TypeScript

import type {StoreDefinition} from 'reflux';
import {createStore} from 'reflux';
import type {Project} from 'sentry/types';
interface ProjectsStatsStoreDefinition extends StoreDefinition {
getAll(): ProjectsStatsStoreDefinition['itemsBySlug'];
getBySlug(slug: string): Project;
getInitialState(): ProjectsStatsStoreDefinition['itemsBySlug'];
itemsBySlug: Record<string, Project>;
onStatsLoadSuccess(projects: Project[]): void;
onUpdate(projectSlug: string, data: Partial<Project>): void;
onUpdateError(err: Error, projectSlug: string): void;
reset(): void;
}
/**
* This is a store specifically used by the dashboard, so that we can
* clear the store when the Dashboard unmounts
* (as to not disrupt ProjectsStore which a lot more components use)
*/
const storeConfig: ProjectsStatsStoreDefinition = {
itemsBySlug: {},
init() {
// XXX: Do not use `this.listenTo` in this store. We avoid usage of reflux
// listeners due to their leaky nature in tests.
this.reset();
},
getInitialState() {
return this.itemsBySlug;
},
reset() {
this.itemsBySlug = {};
this.updatingItems = new Map();
},
onStatsLoadSuccess(projects) {
projects.forEach(project => {
this.itemsBySlug[project.slug] = project;
});
this.trigger(this.itemsBySlug);
},
/**
* Optimistic updates
* @param projectSlug Project slug
* @param data Project data
*/
onUpdate(projectSlug, data) {
const project = this.getBySlug(projectSlug);
this.updatingItems.set(projectSlug, project);
if (!project) {
return;
}
const newProject: Project = {
...project,
...data,
};
this.itemsBySlug = {
...this.itemsBySlug,
[project.slug]: newProject,
};
this.trigger(this.itemsBySlug);
},
onUpdateSuccess(data: Project) {
// Remove project from updating map
this.updatingItems.delete(data.slug);
},
/**
* Revert project data when there was an error updating project details
* @param err Error object
* @param data Previous project data
*/
onUpdateError(_err, projectSlug) {
const project = this.updatingItems.get(projectSlug);
if (!project) {
return;
}
this.updatingItems.delete(projectSlug);
// Restore old project
this.itemsBySlug = {
...this.itemsBySlug,
[project.slug]: {...project},
};
this.trigger(this.itemsBySlug);
},
getAll() {
return this.itemsBySlug;
},
getBySlug(slug) {
return this.itemsBySlug[slug];
},
};
const ProjectsStatsStore = createStore(storeConfig);
export default ProjectsStatsStore;