;
+ relation?: "blocking" | null;
}
) {
return this.post(
@@ -658,7 +659,12 @@ class ProjectIssuesServices extends APIService {
});
}
- async deleteDraftIssue(workspaceSlug: string, projectId: string, issueId: string): Promise
{
+ async deleteDraftIssue(
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string,
+ user: ICurrentUserResponse
+ ): Promise {
return this.delete(
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issue-drafts/${issueId}/`
)
diff --git a/web/store/draft-issue.ts b/web/store/draft-issue.ts
new file mode 100644
index 000000000..f4247c04d
--- /dev/null
+++ b/web/store/draft-issue.ts
@@ -0,0 +1,189 @@
+// mobx
+import { action, observable, runInAction, makeAutoObservable } from "mobx";
+// services
+import issueService from "services/issues.service";
+// types
+import type { ICurrentUserResponse, IIssue } from "types";
+
+class DraftIssuesStore {
+ issues: { [key: string]: IIssue } = {};
+ isIssuesLoading: boolean = false;
+ rootStore: any | null = null;
+
+ constructor(_rootStore: any | null = null) {
+ makeAutoObservable(this, {
+ issues: observable.ref,
+ isIssuesLoading: observable.ref,
+ rootStore: observable.ref,
+ loadDraftIssues: action,
+ getIssueById: action,
+ createDraftIssue: action,
+ updateDraftIssue: action,
+ deleteDraftIssue: action,
+ });
+
+ this.rootStore = _rootStore;
+ }
+
+ /**
+ * @description Fetch all draft issues of a project and hydrate issues field
+ */
+
+ loadDraftIssues = async (workspaceSlug: string, projectId: string, params?: any) => {
+ this.isIssuesLoading = true;
+ try {
+ const issuesResponse = await issueService.getDraftIssues(workspaceSlug, projectId, params);
+
+ const issues = Array.isArray(issuesResponse) ? { allIssues: issuesResponse } : issuesResponse;
+
+ runInAction(() => {
+ this.issues = issues;
+ this.isIssuesLoading = false;
+ });
+ } catch (error) {
+ this.isIssuesLoading = false;
+ console.error("Fetching issues error", error);
+ }
+ };
+
+ /**
+ * @description Fetch a single draft issue by id and hydrate issues field
+ * @param workspaceSlug
+ * @param projectId
+ * @param issueId
+ * @returns {IIssue}
+ */
+
+ getIssueById = async (
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string
+ ): Promise => {
+ if (this.issues[issueId]) return this.issues[issueId];
+
+ try {
+ const issueResponse: IIssue = await issueService.getDraftIssueById(
+ workspaceSlug,
+ projectId,
+ issueId
+ );
+
+ const issues = {
+ ...this.issues,
+ [issueId]: { ...issueResponse },
+ };
+
+ runInAction(() => {
+ this.issues = issues;
+ });
+
+ return issueResponse;
+ } catch (error) {
+ throw error;
+ }
+ };
+
+ /**
+ * @description Create a new draft issue and hydrate issues field
+ * @param workspaceSlug
+ * @param projectId
+ * @param issueForm
+ * @param user
+ * @returns {IIssue}
+ */
+
+ createDraftIssue = async (
+ workspaceSlug: string,
+ projectId: string,
+ issueForm: IIssue,
+ user: ICurrentUserResponse
+ ): Promise => {
+ try {
+ const issueResponse = await issueService.createDraftIssue(
+ workspaceSlug,
+ projectId,
+ issueForm,
+ user
+ );
+
+ const issues = {
+ ...this.issues,
+ [issueResponse.id]: { ...issueResponse },
+ };
+
+ runInAction(() => {
+ this.issues = issues;
+ });
+ return issueResponse;
+ } catch (error) {
+ console.error("Creating issue error", error);
+ throw error;
+ }
+ };
+
+ updateDraftIssue = async (
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string,
+ issueForm: Partial,
+ user: ICurrentUserResponse
+ ) => {
+ // keep a copy of the issue in the store
+ const originalIssue = { ...this.issues[issueId] };
+
+ // immediately update the issue in the store
+ const updatedIssue = { ...this.issues[issueId], ...issueForm };
+ if (updatedIssue.assignees_list) updatedIssue.assignees = updatedIssue.assignees_list;
+
+ try {
+ runInAction(() => {
+ this.issues[issueId] = { ...updatedIssue };
+ });
+
+ // make a patch request to update the issue
+ const issueResponse: IIssue = await issueService.updateDraftIssue(
+ workspaceSlug,
+ projectId,
+ issueId,
+ issueForm,
+ user
+ );
+
+ const updatedIssues = { ...this.issues };
+ updatedIssues[issueId] = { ...issueResponse };
+
+ runInAction(() => {
+ this.issues = updatedIssues;
+ });
+ } catch (error) {
+ // if there is an error, revert the changes
+ runInAction(() => {
+ this.issues[issueId] = originalIssue;
+ });
+
+ return error;
+ }
+ };
+
+ deleteDraftIssue = async (
+ workspaceSlug: string,
+ projectId: string,
+ issueId: string,
+ user: ICurrentUserResponse
+ ) => {
+ const issues = { ...this.issues };
+ delete issues[issueId];
+
+ try {
+ runInAction(() => {
+ this.issues = issues;
+ });
+
+ issueService.deleteDraftIssue(workspaceSlug, projectId, issueId, user);
+ } catch (error) {
+ console.error("Deleting issue error", error);
+ }
+ };
+}
+
+export default DraftIssuesStore;
diff --git a/web/store/root.ts b/web/store/root.ts
index ce0bdfad5..cdb4c8356 100644
--- a/web/store/root.ts
+++ b/web/store/root.ts
@@ -6,6 +6,7 @@ import ThemeStore from "./theme";
import ProjectStore, { IProjectStore } from "./project";
import ProjectPublishStore, { IProjectPublishStore } from "./project-publish";
import IssuesStore from "./issues";
+import DraftIssuesStore from "./draft-issue";
enableStaticRendering(typeof window === "undefined");
@@ -15,6 +16,7 @@ export class RootStore {
project: IProjectStore;
projectPublish: IProjectPublishStore;
issues: IssuesStore;
+ draftIssuesStore: DraftIssuesStore;
constructor() {
this.user = new UserStore(this);
@@ -22,5 +24,6 @@ export class RootStore {
this.project = new ProjectStore(this);
this.projectPublish = new ProjectPublishStore(this);
this.issues = new IssuesStore(this);
+ this.draftIssuesStore = new DraftIssuesStore(this);
}
}
diff --git a/web/types/issues.d.ts b/web/types/issues.d.ts
index 3e09872d4..ca49bc7ec 100644
--- a/web/types/issues.d.ts
+++ b/web/types/issues.d.ts
@@ -76,8 +76,10 @@ export type IssueRelationType = "duplicate" | "relates_to" | "blocked_by";
export interface IssueRelation {
id: string;
issue: string;
- related_issue: string;
+ issue_detail: BlockeIssueDetail;
relation_type: IssueRelationType;
+ related_issue: string;
+ relation: "blocking" | null;
}
export interface IIssue {
@@ -87,20 +89,8 @@ export interface IIssue {
assignees_list: string[];
attachment_count: number;
attachments: any[];
- issue_relations: {
- id: string;
- issue: string;
- issue_detail: BlockeIssueDetail;
- relation_type: IssueRelationType;
- related_issue: string;
- }[];
- related_issues: {
- id: string;
- issue: string;
- related_issue_detail: BlockeIssueDetail;
- relation_type: IssueRelationType;
- related_issue: string;
- }[];
+ issue_relations: IssueRelation[];
+ related_issues: IssueRelation[];
bridge_id?: string | null;
completed_at: Date;
created_at: string;