forked from github/plane
[FED-1147] chore: module link mobx integration (#2990)
* chore: link type updated * chore: mobx implementation for module link * chore: update module mutation logic updated and toast alert added
This commit is contained in:
parent
a4d7b2423e
commit
a035cee165
@ -7,12 +7,12 @@ import { Dialog, Transition } from "@headlessui/react";
|
|||||||
// ui
|
// ui
|
||||||
import { Button, Input } from "@plane/ui";
|
import { Button, Input } from "@plane/ui";
|
||||||
// types
|
// types
|
||||||
import type { IIssueLink, linkDetails, ModuleLink } from "types";
|
import type { IIssueLink, ILinkDetails, ModuleLink } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
data?: linkDetails | null;
|
data?: ILinkDetails | null;
|
||||||
status: boolean;
|
status: boolean;
|
||||||
createIssueLink: (formData: IIssueLink | ModuleLink) => Promise<void>;
|
createIssueLink: (formData: IIssueLink | ModuleLink) => Promise<void>;
|
||||||
updateIssueLink: (formData: IIssueLink | ModuleLink, linkId: string) => Promise<void>;
|
updateIssueLink: (formData: IIssueLink | ModuleLink, linkId: string) => Promise<void>;
|
||||||
|
@ -5,14 +5,14 @@ import { Pencil, Trash2, LinkIcon } from "lucide-react";
|
|||||||
// helpers
|
// helpers
|
||||||
import { timeAgo } from "helpers/date-time.helper";
|
import { timeAgo } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { linkDetails, UserAuth } from "types";
|
import { ILinkDetails, UserAuth } from "types";
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
links: linkDetails[];
|
links: ILinkDetails[];
|
||||||
handleDeleteLink: (linkId: string) => void;
|
handleDeleteLink: (linkId: string) => void;
|
||||||
handleEditLink: (link: linkDetails) => void;
|
handleEditLink: (link: ILinkDetails) => void;
|
||||||
userAuth: UserAuth;
|
userAuth: UserAuth;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import useToast from "hooks/use-toast";
|
|||||||
import { CustomDatePicker } from "components/ui";
|
import { CustomDatePicker } from "components/ui";
|
||||||
import { LinkModal, LinksList } from "components/core";
|
import { LinkModal, LinksList } from "components/core";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IIssueLink, TIssuePriorities, linkDetails } from "types";
|
import { IIssue, IIssueLink, TIssuePriorities, ILinkDetails } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { ISSUE_DETAILS } from "constants/fetch-keys";
|
import { ISSUE_DETAILS } from "constants/fetch-keys";
|
||||||
// constants
|
// constants
|
||||||
@ -43,7 +43,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
const { issue, issueUpdate, disableUserActions } = props;
|
const { issue, issueUpdate, disableUserActions } = props;
|
||||||
// states
|
// states
|
||||||
const [linkModal, setLinkModal] = useState(false);
|
const [linkModal, setLinkModal] = useState(false);
|
||||||
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<linkDetails | null>(null);
|
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
user: { currentProjectRole },
|
user: { currentProjectRole },
|
||||||
@ -147,7 +147,7 @@ export const PeekOverviewProperties: FC<IPeekOverviewProperties> = observer((pro
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleEditLink = (link: linkDetails) => {
|
const handleEditLink = (link: ILinkDetails) => {
|
||||||
setSelectedLinkToUpdate(link);
|
setSelectedLinkToUpdate(link);
|
||||||
setLinkModal(true);
|
setLinkModal(true);
|
||||||
};
|
};
|
||||||
|
@ -37,7 +37,7 @@ import { Button, ContrastIcon, DiceIcon, DoubleCircleIcon, StateGroupIcon, UserG
|
|||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import type { IIssue, IIssueLink, linkDetails } from "types";
|
import type { IIssue, IIssueLink, ILinkDetails } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
|
import { ISSUE_DETAILS, PROJECT_ISSUES_ACTIVITY } from "constants/fetch-keys";
|
||||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
@ -78,7 +78,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
const [deleteIssueModal, setDeleteIssueModal] = useState(false);
|
||||||
const [linkModal, setLinkModal] = useState(false);
|
const [linkModal, setLinkModal] = useState(false);
|
||||||
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<linkDetails | null>(null);
|
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
user: userStore,
|
user: userStore,
|
||||||
@ -244,7 +244,7 @@ export const IssueDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
const maxDate = targetDate ? new Date(targetDate) : null;
|
const maxDate = targetDate ? new Date(targetDate) : null;
|
||||||
maxDate?.setDate(maxDate.getDate());
|
maxDate?.setDate(maxDate.getDate());
|
||||||
|
|
||||||
const handleEditLink = (link: linkDetails) => {
|
const handleEditLink = (link: ILinkDetails) => {
|
||||||
setSelectedLinkToUpdate(link);
|
setSelectedLinkToUpdate(link);
|
||||||
setLinkModal(true);
|
setLinkModal(true);
|
||||||
};
|
};
|
||||||
|
@ -1,13 +1,10 @@
|
|||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { mutate } from "swr";
|
|
||||||
import { Controller, useForm } from "react-hook-form";
|
import { Controller, useForm } from "react-hook-form";
|
||||||
import { Disclosure, Popover, Transition } from "@headlessui/react";
|
import { Disclosure, Popover, Transition } from "@headlessui/react";
|
||||||
// mobx store
|
// mobx store
|
||||||
import { useMobxStore } from "lib/mobx/store-provider";
|
import { useMobxStore } from "lib/mobx/store-provider";
|
||||||
// services
|
|
||||||
import { ModuleService } from "services/module.service";
|
|
||||||
// hooks
|
// hooks
|
||||||
import useToast from "hooks/use-toast";
|
import useToast from "hooks/use-toast";
|
||||||
// components
|
// components
|
||||||
@ -28,9 +25,7 @@ import {
|
|||||||
} from "helpers/date-time.helper";
|
} from "helpers/date-time.helper";
|
||||||
import { copyUrlToClipboard } from "helpers/string.helper";
|
import { copyUrlToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import { linkDetails, IModule, ModuleLink } from "types";
|
import { ILinkDetails, IModule, ModuleLink } from "types";
|
||||||
// fetch-keys
|
|
||||||
import { MODULE_DETAILS } from "constants/fetch-keys";
|
|
||||||
// constant
|
// constant
|
||||||
import { MODULE_STATUS } from "constants/module";
|
import { MODULE_STATUS } from "constants/module";
|
||||||
import { EUserWorkspaceRoles } from "constants/workspace";
|
import { EUserWorkspaceRoles } from "constants/workspace";
|
||||||
@ -48,24 +43,30 @@ type Props = {
|
|||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
// services
|
|
||||||
const moduleService = new ModuleService();
|
|
||||||
|
|
||||||
// TODO: refactor this component
|
// TODO: refactor this component
|
||||||
export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
||||||
const { moduleId, handleClose } = props;
|
const { moduleId, handleClose } = props;
|
||||||
|
|
||||||
const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
|
const [moduleDeleteModal, setModuleDeleteModal] = useState(false);
|
||||||
const [moduleLinkModal, setModuleLinkModal] = useState(false);
|
const [moduleLinkModal, setModuleLinkModal] = useState(false);
|
||||||
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<linkDetails | null>(null);
|
const [selectedLinkToUpdate, setSelectedLinkToUpdate] = useState<ILinkDetails | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, peekModule } = router.query;
|
const { workspaceSlug, projectId, peekModule } = router.query;
|
||||||
|
|
||||||
const { module: moduleStore, user: userStore } = useMobxStore();
|
const {
|
||||||
|
module: {
|
||||||
|
moduleDetails: _moduleDetails,
|
||||||
|
updateModuleDetails,
|
||||||
|
createModuleLink,
|
||||||
|
updateModuleLink,
|
||||||
|
deleteModuleLink,
|
||||||
|
},
|
||||||
|
user: userStore,
|
||||||
|
} = useMobxStore();
|
||||||
|
|
||||||
const userRole = userStore.currentProjectRole;
|
const userRole = userStore.currentProjectRole;
|
||||||
const moduleDetails = moduleStore.moduleDetails[moduleId] ?? undefined;
|
const moduleDetails = _moduleDetails[moduleId] ?? undefined;
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const submitChanges = (data: Partial<IModule>) => {
|
const submitChanges = (data: Partial<IModule>) => {
|
||||||
if (!workspaceSlug || !projectId || !moduleId) return;
|
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||||
moduleStore.updateModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId, data);
|
updateModuleDetails(workspaceSlug.toString(), projectId.toString(), moduleId, data);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCreateLink = async (formData: ModuleLink) => {
|
const handleCreateLink = async (formData: ModuleLink) => {
|
||||||
@ -83,21 +84,19 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const payload = { metadata: {}, ...formData };
|
const payload = { metadata: {}, ...formData };
|
||||||
|
|
||||||
await moduleService
|
createModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), payload)
|
||||||
.createModuleLink(workspaceSlug as string, projectId as string, moduleId as string, payload)
|
.then(() => {
|
||||||
.then(() => mutate(MODULE_DETAILS(moduleId as string)))
|
|
||||||
.catch((err) => {
|
|
||||||
if (err.status === 400)
|
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "success",
|
||||||
title: "Error!",
|
title: "Module link created",
|
||||||
message: "This URL already exists for this module.",
|
message: "Module link created successfully.",
|
||||||
});
|
});
|
||||||
else
|
})
|
||||||
|
.catch(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "error",
|
type: "error",
|
||||||
title: "Error!",
|
title: "Error!",
|
||||||
message: "Something went wrong. Please try again.",
|
message: "Some error occurred",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@ -107,50 +106,40 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
|
|
||||||
const payload = { metadata: {}, ...formData };
|
const payload = { metadata: {}, ...formData };
|
||||||
|
|
||||||
const updatedLinks = moduleDetails.link_module.map((l) =>
|
updateModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), linkId, payload)
|
||||||
l.id === linkId
|
|
||||||
? {
|
|
||||||
...l,
|
|
||||||
title: formData.title,
|
|
||||||
url: formData.url,
|
|
||||||
}
|
|
||||||
: l
|
|
||||||
);
|
|
||||||
|
|
||||||
mutate<IModule>(
|
|
||||||
MODULE_DETAILS(module.id),
|
|
||||||
(prevData) => ({ ...(prevData as IModule), link_module: updatedLinks }),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
await moduleService
|
|
||||||
.updateModuleLink(workspaceSlug as string, projectId as string, module.id, linkId, payload)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
mutate(MODULE_DETAILS(module.id));
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Module link updated",
|
||||||
|
message: "Module link updated successfully.",
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(() => {
|
||||||
console.log(err);
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Some error occurred",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteLink = async (linkId: string) => {
|
const handleDeleteLink = async (linkId: string) => {
|
||||||
if (!workspaceSlug || !projectId || !module) return;
|
if (!workspaceSlug || !projectId || !module) return;
|
||||||
|
|
||||||
const updatedLinks = moduleDetails.link_module.filter((l) => l.id !== linkId);
|
deleteModuleLink(workspaceSlug.toString(), projectId.toString(), moduleId.toString(), linkId)
|
||||||
|
|
||||||
mutate<IModule>(
|
|
||||||
MODULE_DETAILS(module.id),
|
|
||||||
(prevData) => ({ ...(prevData as IModule), link_module: updatedLinks }),
|
|
||||||
false
|
|
||||||
);
|
|
||||||
|
|
||||||
await moduleService
|
|
||||||
.deleteModuleLink(workspaceSlug as string, projectId as string, module.id, linkId)
|
|
||||||
.then(() => {
|
.then(() => {
|
||||||
mutate(MODULE_DETAILS(module.id));
|
setToastAlert({
|
||||||
|
type: "success",
|
||||||
|
title: "Module link deleted",
|
||||||
|
message: "Module link deleted successfully.",
|
||||||
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch(() => {
|
||||||
console.log(err);
|
setToastAlert({
|
||||||
|
type: "error",
|
||||||
|
title: "Error!",
|
||||||
|
message: "Some error occurred",
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -236,7 +225,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = observer((props) => {
|
|||||||
? Math.round((moduleDetails.completed_issues / moduleDetails.total_issues) * 100)
|
? Math.round((moduleDetails.completed_issues / moduleDetails.total_issues) * 100)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
const handleEditLink = (link: linkDetails) => {
|
const handleEditLink = (link: ILinkDetails) => {
|
||||||
console.log("link", link);
|
console.log("link", link);
|
||||||
setSelectedLinkToUpdate(link);
|
setSelectedLinkToUpdate(link);
|
||||||
setModuleLinkModal(true);
|
setModuleLinkModal(true);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
// services
|
// services
|
||||||
import { APIService } from "services/api.service";
|
import { APIService } from "services/api.service";
|
||||||
// types
|
// types
|
||||||
import type { IModule, IIssue, IUser } from "types";
|
import type { IModule, IIssue, ILinkDetails } from "types";
|
||||||
import { IIssueResponse } from "store/issues/types";
|
import { IIssueResponse } from "store/issues/types";
|
||||||
import { API_BASE_URL } from "helpers/common.helper";
|
import { API_BASE_URL } from "helpers/common.helper";
|
||||||
|
|
||||||
@ -132,12 +132,8 @@ export class ModuleService extends APIService {
|
|||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string,
|
moduleId: string,
|
||||||
data: {
|
data: Partial<ILinkDetails>
|
||||||
metadata: any;
|
): Promise<ILinkDetails> {
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
): Promise<any> {
|
|
||||||
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/`, data)
|
return this.post(`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/`, data)
|
||||||
.then((response) => response?.data)
|
.then((response) => response?.data)
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
@ -150,12 +146,8 @@ export class ModuleService extends APIService {
|
|||||||
projectId: string,
|
projectId: string,
|
||||||
moduleId: string,
|
moduleId: string,
|
||||||
linkId: string,
|
linkId: string,
|
||||||
data: {
|
data: Partial<ILinkDetails>
|
||||||
metadata: any;
|
): Promise<ILinkDetails> {
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}
|
|
||||||
): Promise<any> {
|
|
||||||
return this.patch(
|
return this.patch(
|
||||||
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`,
|
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`,
|
||||||
data
|
data
|
||||||
|
@ -4,7 +4,7 @@ import { ProjectService } from "services/project";
|
|||||||
import { ModuleService } from "services/module.service";
|
import { ModuleService } from "services/module.service";
|
||||||
// types
|
// types
|
||||||
import { RootStore } from "../root";
|
import { RootStore } from "../root";
|
||||||
import { IIssue, IModule } from "types";
|
import { IIssue, IModule, ILinkDetails } from "types";
|
||||||
import {
|
import {
|
||||||
IIssueGroupWithSubGroupsStructure,
|
IIssueGroupWithSubGroupsStructure,
|
||||||
IIssueGroupedStructure,
|
IIssueGroupedStructure,
|
||||||
@ -49,6 +49,22 @@ export interface IModuleStore {
|
|||||||
data: Partial<IModule>
|
data: Partial<IModule>
|
||||||
) => Promise<IModule>;
|
) => Promise<IModule>;
|
||||||
deleteModule: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
deleteModule: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
||||||
|
|
||||||
|
createModuleLink: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
moduleId: string,
|
||||||
|
data: Partial<ILinkDetails>
|
||||||
|
) => Promise<ILinkDetails>;
|
||||||
|
updateModuleLink: (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
moduleId: string,
|
||||||
|
linkId: string,
|
||||||
|
data: Partial<ILinkDetails>
|
||||||
|
) => Promise<ILinkDetails>;
|
||||||
|
deleteModuleLink: (workspaceSlug: string, projectId: string, moduleId: string, linkId: string) => Promise<void>;
|
||||||
|
|
||||||
addModuleToFavorites: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
addModuleToFavorites: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
||||||
removeModuleFromFavorites: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
removeModuleFromFavorites: (workspaceSlug: string, projectId: string, moduleId: string) => Promise<void>;
|
||||||
updateModuleGanttStructure: (
|
updateModuleGanttStructure: (
|
||||||
@ -119,6 +135,11 @@ export class ModuleStore implements IModuleStore {
|
|||||||
createModule: action,
|
createModule: action,
|
||||||
updateModuleDetails: action,
|
updateModuleDetails: action,
|
||||||
deleteModule: action,
|
deleteModule: action,
|
||||||
|
|
||||||
|
createModuleLink: action,
|
||||||
|
updateModuleLink: action,
|
||||||
|
deleteModuleLink: action,
|
||||||
|
|
||||||
addModuleToFavorites: action,
|
addModuleToFavorites: action,
|
||||||
removeModuleFromFavorites: action,
|
removeModuleFromFavorites: action,
|
||||||
updateModuleGanttStructure: action,
|
updateModuleGanttStructure: action,
|
||||||
@ -288,6 +309,130 @@ export class ModuleStore implements IModuleStore {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
createModuleLink = async (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
moduleId: string,
|
||||||
|
data: Partial<ILinkDetails>
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const response = await this.moduleService.createModuleLink(workspaceSlug, projectId, moduleId, data);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.modules = {
|
||||||
|
...this.modules,
|
||||||
|
[projectId]: this.modules[projectId]?.map((module) =>
|
||||||
|
module.id === moduleId ? { ...module, link_module: [response, ...module.link_module] } : module
|
||||||
|
),
|
||||||
|
};
|
||||||
|
this.moduleDetails = {
|
||||||
|
...this.moduleDetails,
|
||||||
|
[moduleId]: {
|
||||||
|
...this.moduleDetails[moduleId],
|
||||||
|
link_module: [response, ...this.moduleDetails[moduleId].link_module],
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to create module link in module store", error);
|
||||||
|
|
||||||
|
this.fetchModules(workspaceSlug, projectId);
|
||||||
|
this.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
updateModuleLink = async (
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
moduleId: string,
|
||||||
|
linkId: string,
|
||||||
|
data: Partial<ILinkDetails>
|
||||||
|
) => {
|
||||||
|
try {
|
||||||
|
const response = await this.moduleService.updateModuleLink(workspaceSlug, projectId, moduleId, linkId, data);
|
||||||
|
const _modules = {
|
||||||
|
...this.modules,
|
||||||
|
[projectId]: this.modules[projectId]?.map((module) =>
|
||||||
|
module.id === moduleId
|
||||||
|
? {
|
||||||
|
...module,
|
||||||
|
link_module: module.link_module.map((link) => (link.id === linkId ? response : link)),
|
||||||
|
}
|
||||||
|
: module
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
|
const _moduleDetails = {
|
||||||
|
...this.moduleDetails,
|
||||||
|
[moduleId]: {
|
||||||
|
...this.moduleDetails[moduleId],
|
||||||
|
link_module: this.moduleDetails[moduleId].link_module.map((link) => (link.id === linkId ? response : link)),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.modules = _modules;
|
||||||
|
this.moduleDetails = _moduleDetails;
|
||||||
|
});
|
||||||
|
|
||||||
|
return response;
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to update module link in module store", error);
|
||||||
|
|
||||||
|
this.fetchModules(workspaceSlug, projectId);
|
||||||
|
this.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
deleteModuleLink = async (workspaceSlug: string, projectId: string, moduleId: string, linkId: string) => {
|
||||||
|
try {
|
||||||
|
runInAction(() => {
|
||||||
|
this.modules = {
|
||||||
|
...this.modules,
|
||||||
|
[projectId]: this.modules[projectId]?.map((module) =>
|
||||||
|
module.id === moduleId
|
||||||
|
? { ...module, link_module: module.link_module.filter((link) => link.id !== linkId) }
|
||||||
|
: module
|
||||||
|
),
|
||||||
|
};
|
||||||
|
this.moduleDetails = {
|
||||||
|
...this.moduleDetails,
|
||||||
|
[moduleId]: {
|
||||||
|
...this.moduleDetails[moduleId],
|
||||||
|
link_module: this.moduleDetails[moduleId].link_module.filter((link) => link.id !== linkId),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
await this.moduleService.deleteModuleLink(workspaceSlug, projectId, moduleId, linkId);
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to delete module link in module store", error);
|
||||||
|
|
||||||
|
this.fetchModules(workspaceSlug, projectId);
|
||||||
|
this.fetchModuleDetails(workspaceSlug, projectId, moduleId);
|
||||||
|
|
||||||
|
runInAction(() => {
|
||||||
|
this.error = error;
|
||||||
|
});
|
||||||
|
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
addModuleToFavorites = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
addModuleToFavorites = async (workspaceSlug: string, projectId: string, moduleId: string) => {
|
||||||
try {
|
try {
|
||||||
runInAction(() => {
|
runInAction(() => {
|
||||||
|
4
web/types/issues.d.ts
vendored
4
web/types/issues.d.ts
vendored
@ -55,7 +55,7 @@ export interface IIssueLink {
|
|||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface linkDetails {
|
export interface ILinkDetails {
|
||||||
created_at: Date;
|
created_at: Date;
|
||||||
created_by: string;
|
created_by: string;
|
||||||
created_by_detail: IUserLite;
|
created_by_detail: IUserLite;
|
||||||
@ -99,7 +99,7 @@ export interface IIssue {
|
|||||||
// tempId is used for optimistic updates. It is not a part of the API response.
|
// tempId is used for optimistic updates. It is not a part of the API response.
|
||||||
tempId?: string;
|
tempId?: string;
|
||||||
issue_cycle: IIssueCycle | null;
|
issue_cycle: IIssueCycle | null;
|
||||||
issue_link: linkDetails[];
|
issue_link: ILinkDetails[];
|
||||||
issue_module: IIssueModule | null;
|
issue_module: IIssueModule | null;
|
||||||
labels: string[];
|
labels: string[];
|
||||||
label_details: any[];
|
label_details: any[];
|
||||||
|
4
web/types/modules.d.ts
vendored
4
web/types/modules.d.ts
vendored
@ -7,7 +7,7 @@ import type {
|
|||||||
IWorkspaceLite,
|
IWorkspaceLite,
|
||||||
IProjectLite,
|
IProjectLite,
|
||||||
IIssueFilterOptions,
|
IIssueFilterOptions,
|
||||||
linkDetails,
|
ILinkDetails,
|
||||||
} from "types";
|
} from "types";
|
||||||
|
|
||||||
export type TModuleStatus = "backlog" | "planned" | "in-progress" | "paused" | "completed" | "cancelled";
|
export type TModuleStatus = "backlog" | "planned" | "in-progress" | "paused" | "completed" | "cancelled";
|
||||||
@ -29,7 +29,7 @@ export interface IModule {
|
|||||||
id: string;
|
id: string;
|
||||||
lead: string | null;
|
lead: string | null;
|
||||||
lead_detail: IUserLite | null;
|
lead_detail: IUserLite | null;
|
||||||
link_module: linkDetails[];
|
link_module: ILinkDetails[];
|
||||||
links_list: ModuleLink[];
|
links_list: ModuleLink[];
|
||||||
members: string[];
|
members: string[];
|
||||||
members_detail: IUserLite[];
|
members_detail: IUserLite[];
|
||||||
|
Loading…
Reference in New Issue
Block a user