// FROM: https://dataform.co/blog/how-we-use-mobx-to-solve-our-frontend-state // https://assets.dataform.co/blog/archive/mobx_store.png import {action, computed, observable, runInAction} from 'mobx'; import Loadable from './loadable'; export default class Loadable { // our state entity class public static create(val?: T) { return new Loadable(val); } @observable private value: T; @observable private loading: boolean = false; constructor(val?: T) { this.set(val); } public isLoading() { return this.loading; } public val() { return this.value; } public set(value: T) { this.loading = false; this.value = value; } public setLoading(loading: boolean) { this.loading = loading; } } interface IProject { projectName: string; projectId: string; } export class RootStore { @observable public currentProjectId: string = null; @observable public projectsList = Loadable.create(); public readonly projectStoreMap = new Map(); public projectStore(projectId: string) { if (!this.projectStoreMap.has(projectId)) { const project = this.projectsList .val() .find(project => project.projectId === projectId); if (!project) { throw new Error('Project not found'); } this.projectStoreMap.set(projectId, new ProjectStore(project)); } return this.projectStoreMap.get(projectId); } @computed public get currentProjectStore() { return this.projectStore(this.currentProjectId); } @action public setCurrentProjectId(projectId: string) { this.currentProjectId = projectId; } @action.bound public async fetchProjectsList() { this.projectsList.setLoading(true); const response = await ApiService.get().projectList({}); runInAction('fetchProjectsListSuccess', () => this.projectsList.set(response.projects) ); } } interface IBranch { branchName: string; } class ProjectStore { public readonly currentProject: IProject; @observable public branchList = Loadable.create(); @observable public currentBranchName: string = null; public readonly branchStoreMap = new Map(); constructor(project: IProject) { this.currentProject = project; } public branchStore(branchName: string) { if (!this.branchStoreMap.has(branchName)) { const branch = this.branchList .val() .find(branch => branch.branchName === branchName); if (!branch) { throw new Error('Branch not found'); } this.branchStoreMap.set(branchName, new BranchStore(branch)); } return this.branchStoreMap.get(branchName); } @computed public get currentBranchStore() { return this.branchStore(this.currentBranchName); } @action public setCurrentBranchName(branchName: string) { this.currentBranchName = branchName; } @action.bound public async fetchBranchList() { this.branchList.setLoading(true); const response = await ApiService.get().branchList({ projectId: this.currentProject.projectId, }); runInAction('fetchBranchListSuccess', () => this.branchList.set(response.branches) ); } } const rootStore = new RootStore();