Skip to content

Commit

Permalink
chore: revert back to optimistic update approach for all `update rela…
Browse files Browse the repository at this point in the history
…ted actions` (#3219)
  • Loading branch information
prateekshourya29 committed Dec 22, 2023
1 parent ffda154 commit 5a5a651
Show file tree
Hide file tree
Showing 7 changed files with 249 additions and 96 deletions.
68 changes: 55 additions & 13 deletions web/store/cycle.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ export class CycleStore implements ICycleStore {
}

// computed
/**
* returns all cycle ids for a project
*/
get projectCycleIds() {
const projectId = this.rootStore.app.router.projectId;
if (!projectId) return null;
Expand All @@ -97,6 +100,9 @@ export class CycleStore implements ICycleStore {
return allCycles || null;
}

/**
* returns all completed cycle ids for a project
*/
get projectCompletedCycleIds() {
const allCycles = this.projectCycleIds;
if (!allCycles) return null;
Expand All @@ -107,6 +113,9 @@ export class CycleStore implements ICycleStore {
return completedCycles || null;
}

/**
* returns all upcoming cycle ids for a project
*/
get projectUpcomingCycleIds() {
const allCycles = this.projectCycleIds;
if (!allCycles) return null;
Expand All @@ -117,6 +126,9 @@ export class CycleStore implements ICycleStore {
return upcomingCycles || null;
}

/**
* returns all incomplete cycle ids for a project
*/
get projectIncompleteCycleIds() {
const allCycles = this.projectCycleIds;
if (!allCycles) return null;
Expand All @@ -127,6 +139,9 @@ export class CycleStore implements ICycleStore {
return incompleteCycles || null;
}

/**
* returns all draft cycle ids for a project
*/
get projectDraftCycleIds() {
const allCycles = this.projectCycleIds;
if (!allCycles) return null;
Expand All @@ -137,6 +152,9 @@ export class CycleStore implements ICycleStore {
return draftCycles || null;
}

/**
* returns active cycle id for a project
*/
get projectActiveCycleId() {
const projectId = this.rootStore.app.router.projectId;
if (!projectId) return null;
Expand Down Expand Up @@ -242,14 +260,21 @@ export class CycleStore implements ICycleStore {
* @param data
* @returns
*/
updateCycleDetails = async (workspaceSlug: string, projectId: string, cycleId: string, data: Partial<ICycle>) =>
await this.cycleService.patchCycle(workspaceSlug, projectId, cycleId, data).then((response) => {
updateCycleDetails = async (workspaceSlug: string, projectId: string, cycleId: string, data: Partial<ICycle>) => {
try {
runInAction(() => {
set(this.cycleMap, [cycleId], { ...this.cycleMap?.[cycleId], ...data });
set(this.activeCycleMap, [cycleId], { ...this.activeCycleMap?.[cycleId], ...data });
});
const response = await this.cycleService.patchCycle(workspaceSlug, projectId, cycleId, data);
return response;
});
} catch (error) {
console.log("Failed to patch cycle from cycle store");
this.fetchAllCycles(workspaceSlug, projectId);
this.fetchActiveCycle(workspaceSlug, projectId);
throw error;
}
};

/**
* @description deletes a cycle
Expand All @@ -272,16 +297,25 @@ export class CycleStore implements ICycleStore {
* @param cycleId
* @returns
*/
addCycleToFavorites = async (workspaceSlug: string, projectId: string, cycleId: string) =>
await this.cycleService.addCycleToFavorites(workspaceSlug, projectId, { cycle: cycleId }).then((response) => {
const currentCycle = this.getCycleById(cycleId);
const currentActiveCycle = this.getActiveCycleById(cycleId);
addCycleToFavorites = async (workspaceSlug: string, projectId: string, cycleId: string) => {
const currentCycle = this.getCycleById(cycleId);
const currentActiveCycle = this.getActiveCycleById(cycleId);
try {
runInAction(() => {
if (currentCycle) set(this.cycleMap, [cycleId, "is_favorite"], true);
if (currentActiveCycle) set(this.activeCycleMap, [cycleId, "is_favorite"], true);
});
// updating through api.
const response = await this.cycleService.addCycleToFavorites(workspaceSlug, projectId, { cycle: cycleId });
return response;
});
} catch (error) {
runInAction(() => {
if (currentCycle) set(this.cycleMap, [cycleId, "is_favorite"], false);
if (currentActiveCycle) set(this.activeCycleMap, [cycleId, "is_favorite"], false);
});
throw error;
}
};

/**
* @description removes a cycle from favorites
Expand All @@ -290,14 +324,22 @@ export class CycleStore implements ICycleStore {
* @param cycleId
* @returns
*/
removeCycleFromFavorites = async (workspaceSlug: string, projectId: string, cycleId: string) =>
await this.cycleService.removeCycleFromFavorites(workspaceSlug, projectId, cycleId).then((response) => {
const currentCycle = this.getCycleById(cycleId);
const currentActiveCycle = this.getActiveCycleById(cycleId);
removeCycleFromFavorites = async (workspaceSlug: string, projectId: string, cycleId: string) => {
const currentCycle = this.getCycleById(cycleId);
const currentActiveCycle = this.getActiveCycleById(cycleId);
try {
runInAction(() => {
if (currentCycle) set(this.cycleMap, [cycleId, "is_favorite"], false);
if (currentActiveCycle) set(this.activeCycleMap, [cycleId, "is_favorite"], false);
});
const response = await this.cycleService.removeCycleFromFavorites(workspaceSlug, projectId, cycleId);
return response;
});
} catch (error) {
runInAction(() => {
if (currentCycle) set(this.cycleMap, [cycleId, "is_favorite"], true);
if (currentActiveCycle) set(this.activeCycleMap, [cycleId, "is_favorite"], true);
});
throw error;
}
};
}
19 changes: 14 additions & 5 deletions web/store/label/project-label.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,20 @@ export class ProjectLabelStore implements IProjectLabelStore {
* @returns Promise<IIssueLabel>
*/
updateLabel = async (workspaceSlug: string, projectId: string, labelId: string, data: Partial<IIssueLabel>) => {
runInAction(() => {
set(this.labelMap, [labelId], { ...this.labelMap?.[labelId], ...data });
});
const response = await this.issueLabelService.patchIssueLabel(workspaceSlug, projectId, labelId, data);
return response;
const originalLabel = this.labelMap[labelId];
try {
runInAction(() => {
set(this.labelMap, [labelId], { ...this.labelMap[labelId], ...data });
});
const response = await this.issueLabelService.patchIssueLabel(workspaceSlug, projectId, labelId, data);
return response;
} catch (error) {
console.log("Failed to update label from project store");
runInAction(() => {
set(this.labelMap, [labelId], originalLabel);
});
throw error;
}
};

/**
Expand Down
26 changes: 19 additions & 7 deletions web/store/member/project-member.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,26 @@ export class ProjectMemberStore implements IProjectMemberStore {
) => {
const memberDetails = this.getProjectMemberDetails(userId);
if (!memberDetails) throw new Error("Member not found");
return await this.projectMemberService
.updateProjectMember(workspaceSlug, projectId, memberDetails?.id, data)
.then((response) => {
runInAction(() => {
set(this.projectMemberMap, [projectId, userId, "role"], data.role);
});
return response;
// original data to revert back in case of error
const originalProjectMemberData = this.projectMemberMap?.[projectId]?.[userId];
try {
runInAction(() => {
set(this.projectMemberMap, [projectId, userId, "role"], data.role);
});
const response = await this.projectMemberService.updateProjectMember(
workspaceSlug,
projectId,
memberDetails?.id,
data
);
return response;
} catch (error) {
// revert back to original members in case of error
runInAction(() => {
set(this.projectMemberMap, [projectId, userId], originalProjectMemberData);
});
throw error;
}
};

/**
Expand Down
25 changes: 21 additions & 4 deletions web/store/member/workspace-member.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -199,11 +199,20 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
updateMember = async (workspaceSlug: string, userId: string, data: { role: EUserWorkspaceRoles }) => {
const memberDetails = this.getWorkspaceMemberDetails(userId);
if (!memberDetails) throw new Error("Member not found");
await this.workspaceService.updateWorkspaceMember(workspaceSlug, memberDetails.id, data).then(() => {
// original data to revert back in case of error
const originalProjectMemberData = this.workspaceMemberMap?.[workspaceSlug]?.[userId];
try {
runInAction(() => {
set(this.workspaceMemberMap, [workspaceSlug, userId, "role"], data.role);
});
});
await this.workspaceService.updateWorkspaceMember(workspaceSlug, memberDetails.id, data);
} catch (error) {
// revert back to original members in case of error
runInAction(() => {
set(this.workspaceMemberMap, [workspaceSlug, userId], originalProjectMemberData);
});
throw error;
}
};

/**
Expand Down Expand Up @@ -257,15 +266,23 @@ export class WorkspaceMemberStore implements IWorkspaceMemberStore {
data: Partial<IWorkspaceMemberInvitation>
) => {
const originalMemberInvitations = [...this.workspaceMemberInvitations?.[workspaceSlug]]; // in case of error, we will revert back to original members
await this.workspaceService.updateWorkspaceInvitation(workspaceSlug, invitationId, data).then(() => {
try {
const memberInvitations = originalMemberInvitations?.map((invitation) => ({
...invitation,
...(invitation.id === invitationId && data),
}));
// optimistic update
runInAction(() => {
set(this.workspaceMemberInvitations, workspaceSlug, memberInvitations);
});
});
await this.workspaceService.updateWorkspaceInvitation(workspaceSlug, invitationId, data);
} catch (error) {
// revert back to original members in case of error
runInAction(() => {
set(this.workspaceMemberInvitations, workspaceSlug, originalMemberInvitations);
});
throw error;
}
};

/**
Expand Down
79 changes: 56 additions & 23 deletions web/store/module.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ export class ModulesStore implements IModuleStore {
}

// computed
/**
* get all module ids for the current project
*/
get projectModuleIds() {
const projectId = this.rootStore.app.router.projectId;
if (!projectId) return null;
Expand Down Expand Up @@ -155,14 +158,22 @@ export class ModulesStore implements IModuleStore {
* @param data
* @returns IModule
*/
updateModuleDetails = async (workspaceSlug: string, projectId: string, moduleId: string, data: Partial<IModule>) =>
await this.moduleService.patchModule(workspaceSlug, projectId, moduleId, data).then((response) => {
const moduleDetails = this.getModuleById(moduleId);
updateModuleDetails = async (workspaceSlug: string, projectId: string, moduleId: string, data: Partial<IModule>) => {
const originalModuleDetails = this.getModuleById(moduleId);
try {
runInAction(() => {
set(this.moduleMap, [moduleId], { ...moduleDetails, ...data });
set(this.moduleMap, [moduleId], { ...originalModuleDetails, ...data });
});
const response = await this.moduleService.patchModule(workspaceSlug, projectId, moduleId, data);
return response;
});
} catch (error) {
console.error("Failed to update module in module store", error);
runInAction(() => {
set(this.moduleMap, [moduleId], { ...originalModuleDetails });
});
throw error;
}
};

/**
* @description deletes a module
Expand Down Expand Up @@ -211,15 +222,25 @@ export class ModulesStore implements IModuleStore {
moduleId: string,
linkId: string,
data: Partial<ILinkDetails>
) =>
await this.moduleService.updateModuleLink(workspaceSlug, projectId, moduleId, linkId, data).then((response) => {
const moduleDetails = this.getModuleById(moduleId);
const linkModules = moduleDetails?.link_module.map((link) => (link.id === linkId ? response : link));
) => {
const originalModuleDetails = this.getModuleById(moduleId);
try {
const linkModules = originalModuleDetails?.link_module.map((link) =>
link.id === linkId ? { ...link, ...data } : link
);
runInAction(() => {
set(this.moduleMap, [moduleId, "link_module"], linkModules);
});
const response = await this.moduleService.updateModuleLink(workspaceSlug, projectId, moduleId, linkId, data);
return response;
});
} catch (error) {
console.error("Failed to update module link in module store", error);
runInAction(() => {
set(this.moduleMap, [moduleId, "link_module"], originalModuleDetails?.link_module);
});
throw error;
}
};

/**
* @description deletes a module link
Expand All @@ -244,18 +265,23 @@ export class ModulesStore implements IModuleStore {
* @param moduleId
* @returns
*/
addModuleToFavorites = async (workspaceSlug: string, projectId: string, moduleId: string) =>
await this.moduleService
.addModuleToFavorites(workspaceSlug, projectId, {
addModuleToFavorites = async (workspaceSlug: string, projectId: string, moduleId: string) => {
try {
const moduleDetails = this.getModuleById(moduleId);
if (moduleDetails?.is_favorite) return;
runInAction(() => {
set(this.moduleMap, [moduleId, "is_favorite"], true);
});
await this.moduleService.addModuleToFavorites(workspaceSlug, projectId, {
module: moduleId,
})
.then(() => {
const moduleDetails = this.getModuleById(moduleId);
if (moduleDetails?.is_favorite) return;
runInAction(() => {
set(this.moduleMap, [moduleId, "is_favorite"], true);
});
});
} catch (error) {
console.error("Failed to add module to favorites in module store", error);
runInAction(() => {
set(this.moduleMap, [moduleId, "is_favorite"], false);
});
}
};

/**
* @description removes a module from favorites
Expand All @@ -264,12 +290,19 @@ export class ModulesStore implements IModuleStore {
* @param moduleId
* @returns
*/
removeModuleFromFavorites = async (workspaceSlug: string, projectId: string, moduleId: string) =>
await this.moduleService.removeModuleFromFavorites(workspaceSlug, projectId, moduleId).then(() => {
removeModuleFromFavorites = async (workspaceSlug: string, projectId: string, moduleId: string) => {
try {
const moduleDetails = this.getModuleById(moduleId);
if (!moduleDetails?.is_favorite) return;
runInAction(() => {
set(this.moduleMap, [moduleId, "is_favorite"], false);
});
});
await this.moduleService.removeModuleFromFavorites(workspaceSlug, projectId, moduleId);
} catch (error) {
console.error("Failed to remove module from favorites in module store", error);
runInAction(() => {
set(this.moduleMap, [moduleId, "is_favorite"], true);
});
}
};
}
Loading

0 comments on commit 5a5a651

Please sign in to comment.