forked from github/plane
chore: link edit functionality (#1895)
This commit is contained in:
parent
d74ec7bda9
commit
c3c6ba9e34
@ -1,4 +1,4 @@
|
|||||||
import React from "react";
|
import React, { useEffect } from "react";
|
||||||
|
|
||||||
// react-hook-form
|
// react-hook-form
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
@ -7,12 +7,15 @@ import { Dialog, Transition } from "@headlessui/react";
|
|||||||
// ui
|
// ui
|
||||||
import { Input, PrimaryButton, SecondaryButton } from "components/ui";
|
import { Input, PrimaryButton, SecondaryButton } from "components/ui";
|
||||||
// types
|
// types
|
||||||
import type { IIssueLink, ModuleLink } from "types";
|
import type { IIssueLink, linkDetails, ModuleLink } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
onFormSubmit: (formData: IIssueLink | ModuleLink) => Promise<void>;
|
data?: linkDetails | null;
|
||||||
|
status: boolean;
|
||||||
|
createIssueLink: (formData: IIssueLink | ModuleLink) => Promise<void>;
|
||||||
|
updateIssueLink: (formData: IIssueLink | ModuleLink, linkId: string) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultValues: IIssueLink | ModuleLink = {
|
const defaultValues: IIssueLink | ModuleLink = {
|
||||||
@ -20,7 +23,14 @@ const defaultValues: IIssueLink | ModuleLink = {
|
|||||||
url: "",
|
url: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }) => {
|
export const LinkModal: React.FC<Props> = ({
|
||||||
|
isOpen,
|
||||||
|
handleClose,
|
||||||
|
createIssueLink,
|
||||||
|
updateIssueLink,
|
||||||
|
status,
|
||||||
|
data,
|
||||||
|
}) => {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
formState: { errors, isSubmitting },
|
formState: { errors, isSubmitting },
|
||||||
@ -30,11 +40,6 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
|
|||||||
defaultValues,
|
defaultValues,
|
||||||
});
|
});
|
||||||
|
|
||||||
const onSubmit = async (formData: IIssueLink | ModuleLink) => {
|
|
||||||
await onFormSubmit({ title: formData.title, url: formData.url });
|
|
||||||
onClose();
|
|
||||||
};
|
|
||||||
|
|
||||||
const onClose = () => {
|
const onClose = () => {
|
||||||
handleClose();
|
handleClose();
|
||||||
const timeout = setTimeout(() => {
|
const timeout = setTimeout(() => {
|
||||||
@ -43,6 +48,27 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
|
|||||||
}, 500);
|
}, 500);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleFormSubmit = async (formData: IIssueLink | ModuleLink) => {
|
||||||
|
if (!data) await createIssueLink({ title: formData.title, url: formData.url });
|
||||||
|
else await updateIssueLink({ title: formData.title, url: formData.url }, data.id);
|
||||||
|
onClose();
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleCreateUpdatePage = async (formData: IIssueLink | ModuleLink) => {
|
||||||
|
await handleFormSubmit(formData);
|
||||||
|
|
||||||
|
reset({
|
||||||
|
...defaultValues,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
reset({
|
||||||
|
...defaultValues,
|
||||||
|
...data,
|
||||||
|
});
|
||||||
|
}, [data, reset]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={isOpen} as={React.Fragment}>
|
<Transition.Root show={isOpen} as={React.Fragment}>
|
||||||
<Dialog as="div" className="relative z-20" onClose={onClose}>
|
<Dialog as="div" className="relative z-20" onClose={onClose}>
|
||||||
@ -70,14 +96,14 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
|
|||||||
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
leaveTo="opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95"
|
||||||
>
|
>
|
||||||
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-custom-background-100 border border-custom-border-200 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
<Dialog.Panel className="relative transform overflow-hidden rounded-lg bg-custom-background-100 border border-custom-border-200 px-5 py-8 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-2xl sm:p-6">
|
||||||
<form onSubmit={handleSubmit(onSubmit)}>
|
<form onSubmit={handleSubmit(handleCreateUpdatePage)}>
|
||||||
<div>
|
<div>
|
||||||
<div className="space-y-5">
|
<div className="space-y-5">
|
||||||
<Dialog.Title
|
<Dialog.Title
|
||||||
as="h3"
|
as="h3"
|
||||||
className="text-lg font-medium leading-6 text-custom-text-100"
|
className="text-lg font-medium leading-6 text-custom-text-100"
|
||||||
>
|
>
|
||||||
Add Link
|
{status ? "Update Link" : "Add Link"}
|
||||||
</Dialog.Title>
|
</Dialog.Title>
|
||||||
<div className="mt-2 space-y-3">
|
<div className="mt-2 space-y-3">
|
||||||
<div>
|
<div>
|
||||||
@ -113,7 +139,13 @@ export const LinkModal: React.FC<Props> = ({ isOpen, handleClose, onFormSubmit }
|
|||||||
<div className="mt-5 flex justify-end gap-2">
|
<div className="mt-5 flex justify-end gap-2">
|
||||||
<SecondaryButton onClick={onClose}>Cancel</SecondaryButton>
|
<SecondaryButton onClick={onClose}>Cancel</SecondaryButton>
|
||||||
<PrimaryButton type="submit" loading={isSubmitting}>
|
<PrimaryButton type="submit" loading={isSubmitting}>
|
||||||
{isSubmitting ? "Adding Link..." : "Add Link"}
|
{status
|
||||||
|
? isSubmitting
|
||||||
|
? "Updating Link..."
|
||||||
|
: "Update Link"
|
||||||
|
: isSubmitting
|
||||||
|
? "Adding Link..."
|
||||||
|
: "Add Link"}
|
||||||
</PrimaryButton>
|
</PrimaryButton>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -1,25 +1,24 @@
|
|||||||
// icons
|
// icons
|
||||||
import { ArrowTopRightOnSquareIcon, LinkIcon, TrashIcon } from "@heroicons/react/24/outline";
|
import { ArrowTopRightOnSquareIcon, LinkIcon, TrashIcon } from "@heroicons/react/24/outline";
|
||||||
|
import { Icon } from "components/ui";
|
||||||
// helpers
|
// helpers
|
||||||
import { timeAgo } from "helpers/date-time.helper";
|
import { timeAgo } from "helpers/date-time.helper";
|
||||||
// types
|
// types
|
||||||
import { IUserLite, UserAuth } from "types";
|
import { linkDetails, UserAuth } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
links: {
|
links: linkDetails[];
|
||||||
id: string;
|
|
||||||
created_at: Date;
|
|
||||||
created_by: string;
|
|
||||||
created_by_detail: IUserLite;
|
|
||||||
metadata: any;
|
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}[];
|
|
||||||
handleDeleteLink: (linkId: string) => void;
|
handleDeleteLink: (linkId: string) => void;
|
||||||
|
handleEditLink: (link: linkDetails) => void;
|
||||||
userAuth: UserAuth;
|
userAuth: UserAuth;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }) => {
|
export const LinksList: React.FC<Props> = ({
|
||||||
|
links,
|
||||||
|
handleDeleteLink,
|
||||||
|
handleEditLink,
|
||||||
|
userAuth,
|
||||||
|
}) => {
|
||||||
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -28,6 +27,13 @@ export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }
|
|||||||
<div key={link.id} className="relative">
|
<div key={link.id} className="relative">
|
||||||
{!isNotAllowed && (
|
{!isNotAllowed && (
|
||||||
<div className="absolute top-1.5 right-1.5 z-[1] flex items-center gap-1">
|
<div className="absolute top-1.5 right-1.5 z-[1] flex items-center gap-1">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="grid h-7 w-7 place-items-center rounded bg-custom-background-90 p-1 outline-none hover:bg-custom-background-80"
|
||||||
|
onClick={() => handleEditLink(link)}
|
||||||
|
>
|
||||||
|
<Icon iconName="edit" className="text-custom-text-200" />
|
||||||
|
</button>
|
||||||
<a
|
<a
|
||||||
href={link.url}
|
href={link.url}
|
||||||
target="_blank"
|
target="_blank"
|
||||||
|
@ -37,7 +37,7 @@ import { LinkIcon, CalendarDaysIcon, TrashIcon, PlusIcon } from "@heroicons/reac
|
|||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import type { ICycle, IIssue, IIssueLink, IModule } from "types";
|
import type { ICycle, IIssue, IIssueLink, linkDetails, IModule } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { ISSUE_DETAILS } from "constants/fetch-keys";
|
import { ISSUE_DETAILS } from "constants/fetch-keys";
|
||||||
|
|
||||||
@ -77,6 +77,7 @@ export const IssueDetailsSidebar: React.FC<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 router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, issueId } = router.query;
|
const { workspaceSlug, projectId, issueId } = router.query;
|
||||||
@ -156,6 +157,43 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleUpdateLink = async (formData: IIssueLink, linkId: string) => {
|
||||||
|
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||||
|
|
||||||
|
const payload = { metadata: {}, ...formData };
|
||||||
|
|
||||||
|
const updatedLinks = issueDetail.issue_link.map((l) =>
|
||||||
|
l.id === linkId
|
||||||
|
? {
|
||||||
|
...l,
|
||||||
|
title: formData.title,
|
||||||
|
url: formData.url,
|
||||||
|
}
|
||||||
|
: l
|
||||||
|
);
|
||||||
|
|
||||||
|
mutate<IIssue>(
|
||||||
|
ISSUE_DETAILS(issueDetail.id),
|
||||||
|
(prevData) => ({ ...(prevData as IIssue), issue_link: updatedLinks }),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
await issuesService
|
||||||
|
.updateIssueLink(
|
||||||
|
workspaceSlug as string,
|
||||||
|
projectId as string,
|
||||||
|
issueDetail.id,
|
||||||
|
linkId,
|
||||||
|
payload
|
||||||
|
)
|
||||||
|
.then((res) => {
|
||||||
|
mutate(ISSUE_DETAILS(issueDetail.id));
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleDeleteLink = async (linkId: string) => {
|
const handleDeleteLink = async (linkId: string) => {
|
||||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||||
|
|
||||||
@ -220,14 +258,25 @@ export const IssueDetailsSidebar: React.FC<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) => {
|
||||||
|
setSelectedLinkToUpdate(link);
|
||||||
|
setLinkModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
const isNotAllowed = memberRole.isGuest || memberRole.isViewer;
|
const isNotAllowed = memberRole.isGuest || memberRole.isViewer;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LinkModal
|
<LinkModal
|
||||||
isOpen={linkModal}
|
isOpen={linkModal}
|
||||||
handleClose={() => setLinkModal(false)}
|
handleClose={() => {
|
||||||
onFormSubmit={handleCreateLink}
|
setLinkModal(false);
|
||||||
|
setSelectedLinkToUpdate(null);
|
||||||
|
}}
|
||||||
|
data={selectedLinkToUpdate}
|
||||||
|
status={selectedLinkToUpdate ? true : false}
|
||||||
|
createIssueLink={handleCreateLink}
|
||||||
|
updateIssueLink={handleUpdateLink}
|
||||||
/>
|
/>
|
||||||
<DeleteIssueModal
|
<DeleteIssueModal
|
||||||
handleClose={() => setDeleteIssueModal(false)}
|
handleClose={() => setDeleteIssueModal(false)}
|
||||||
@ -490,6 +539,7 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
<LinksList
|
<LinksList
|
||||||
links={issueDetail.issue_link}
|
links={issueDetail.issue_link}
|
||||||
handleDeleteLink={handleDeleteLink}
|
handleDeleteLink={handleDeleteLink}
|
||||||
|
handleEditLink={handleEditLink}
|
||||||
userAuth={memberRole}
|
userAuth={memberRole}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
|
@ -37,7 +37,7 @@ import { LinkIcon } from "@heroicons/react/20/solid";
|
|||||||
import { renderDateFormat, renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
import { renderDateFormat, renderShortDateWithYearFormat } from "helpers/date-time.helper";
|
||||||
import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
|
import { capitalizeFirstLetter, copyTextToClipboard } from "helpers/string.helper";
|
||||||
// types
|
// types
|
||||||
import { ICurrentUserResponse, IIssue, IModule, ModuleLink } from "types";
|
import { ICurrentUserResponse, IIssue, linkDetails, IModule, ModuleLink } from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { MODULE_DETAILS } from "constants/fetch-keys";
|
import { MODULE_DETAILS } from "constants/fetch-keys";
|
||||||
// constant
|
// constant
|
||||||
@ -61,6 +61,7 @@ type Props = {
|
|||||||
export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIssues, user }) => {
|
export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIssues, user }) => {
|
||||||
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 router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, moduleId } = router.query;
|
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||||
@ -115,6 +116,37 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIs
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleUpdateLink = async (formData: ModuleLink, linkId: string) => {
|
||||||
|
if (!workspaceSlug || !projectId || !module) return;
|
||||||
|
|
||||||
|
const payload = { metadata: {}, ...formData };
|
||||||
|
|
||||||
|
const updatedLinks = module.link_module.map((l) =>
|
||||||
|
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 modulesService
|
||||||
|
.updateModuleLink(workspaceSlug as string, projectId as string, module.id, linkId, payload)
|
||||||
|
.then((res) => {
|
||||||
|
mutate(MODULE_DETAILS(module.id));
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleDeleteLink = async (linkId: string) => {
|
const handleDeleteLink = async (linkId: string) => {
|
||||||
if (!workspaceSlug || !projectId || !module) return;
|
if (!workspaceSlug || !projectId || !module) return;
|
||||||
|
|
||||||
@ -170,12 +202,23 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIs
|
|||||||
? Math.round((module.completed_issues / module.total_issues) * 100)
|
? Math.round((module.completed_issues / module.total_issues) * 100)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
|
const handleEditLink = (link: linkDetails) => {
|
||||||
|
setSelectedLinkToUpdate(link);
|
||||||
|
setModuleLinkModal(true);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<LinkModal
|
<LinkModal
|
||||||
isOpen={moduleLinkModal}
|
isOpen={moduleLinkModal}
|
||||||
handleClose={() => setModuleLinkModal(false)}
|
handleClose={() => {
|
||||||
onFormSubmit={handleCreateLink}
|
setModuleLinkModal(false);
|
||||||
|
setSelectedLinkToUpdate(null);
|
||||||
|
}}
|
||||||
|
data={selectedLinkToUpdate}
|
||||||
|
status={selectedLinkToUpdate ? true : false}
|
||||||
|
createIssueLink={handleCreateLink}
|
||||||
|
updateIssueLink={handleUpdateLink}
|
||||||
/>
|
/>
|
||||||
<DeleteModuleModal
|
<DeleteModuleModal
|
||||||
isOpen={moduleDeleteModal}
|
isOpen={moduleDeleteModal}
|
||||||
@ -544,7 +587,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIs
|
|||||||
</Disclosure>
|
</Disclosure>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex w-full flex-col border-t border-custom-border-200 px-6 py-6 text-xs">
|
<div className="flex w-full flex-col border-t border-custom-border-200 px-6 pt-6 pb-10 text-xs">
|
||||||
<div className="flex w-full items-center justify-between">
|
<div className="flex w-full items-center justify-between">
|
||||||
<h4 className="text-sm font-medium text-custom-text-200">Links</h4>
|
<h4 className="text-sm font-medium text-custom-text-200">Links</h4>
|
||||||
<button
|
<button
|
||||||
@ -558,6 +601,7 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({ module, isOpen, moduleIs
|
|||||||
{memberRole && module.link_module && module.link_module.length > 0 ? (
|
{memberRole && module.link_module && module.link_module.length > 0 ? (
|
||||||
<LinksList
|
<LinksList
|
||||||
links={module.link_module}
|
links={module.link_module}
|
||||||
|
handleEditLink={handleEditLink}
|
||||||
handleDeleteLink={handleDeleteLink}
|
handleDeleteLink={handleDeleteLink}
|
||||||
userAuth={memberRole}
|
userAuth={memberRole}
|
||||||
/>
|
/>
|
||||||
|
@ -459,6 +459,29 @@ class ProjectIssuesServices extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateIssueLink(
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
issueId: string,
|
||||||
|
linkId: string,
|
||||||
|
data: {
|
||||||
|
metadata: any;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
},
|
||||||
|
|
||||||
|
): Promise<any> {
|
||||||
|
return this.patch(
|
||||||
|
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/`,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
.then((response) => response?.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error?.response;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async deleteIssueLink(
|
async deleteIssueLink(
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
|
@ -212,6 +212,28 @@ class ProjectIssuesServices extends APIService {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async updateModuleLink(
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
moduleId: string,
|
||||||
|
linkId: string,
|
||||||
|
data: {
|
||||||
|
metadata: any;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
},
|
||||||
|
|
||||||
|
): Promise<any> {
|
||||||
|
return this.patch(
|
||||||
|
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
.then((response) => response?.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error?.response;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async deleteModuleLink(
|
async deleteModuleLink(
|
||||||
workspaceSlug: string,
|
workspaceSlug: string,
|
||||||
projectId: string,
|
projectId: string,
|
||||||
|
20
apps/app/types/issues.d.ts
vendored
20
apps/app/types/issues.d.ts
vendored
@ -56,6 +56,16 @@ export interface IIssueLink {
|
|||||||
url: string;
|
url: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface linkDetails {
|
||||||
|
created_at: Date;
|
||||||
|
created_by: string;
|
||||||
|
created_by_detail: IUserLite;
|
||||||
|
id: string;
|
||||||
|
metadata: any;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IIssue {
|
export interface IIssue {
|
||||||
archived_at: string;
|
archived_at: string;
|
||||||
assignees: string[];
|
assignees: string[];
|
||||||
@ -80,15 +90,7 @@ export interface IIssue {
|
|||||||
estimate_point: number | null;
|
estimate_point: number | null;
|
||||||
id: string;
|
id: string;
|
||||||
issue_cycle: IIssueCycle | null;
|
issue_cycle: IIssueCycle | null;
|
||||||
issue_link: {
|
issue_link: linkDetails[];
|
||||||
created_at: Date;
|
|
||||||
created_by: string;
|
|
||||||
created_by_detail: IUserLite;
|
|
||||||
id: string;
|
|
||||||
metadata: any;
|
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}[];
|
|
||||||
issue_module: IIssueModule | null;
|
issue_module: IIssueModule | null;
|
||||||
labels: string[];
|
labels: string[];
|
||||||
label_details: any[];
|
label_details: any[];
|
||||||
|
11
apps/app/types/modules.d.ts
vendored
11
apps/app/types/modules.d.ts
vendored
@ -7,6 +7,7 @@ import type {
|
|||||||
IWorkspaceLite,
|
IWorkspaceLite,
|
||||||
IProjectLite,
|
IProjectLite,
|
||||||
IIssueFilterOptions,
|
IIssueFilterOptions,
|
||||||
|
linkDetails,
|
||||||
} from "types";
|
} from "types";
|
||||||
|
|
||||||
export interface IModule {
|
export interface IModule {
|
||||||
@ -26,15 +27,7 @@ export interface IModule {
|
|||||||
id: string;
|
id: string;
|
||||||
lead: string | null;
|
lead: string | null;
|
||||||
lead_detail: IUserLite | null;
|
lead_detail: IUserLite | null;
|
||||||
link_module: {
|
link_module: linkDetails[];
|
||||||
created_at: Date;
|
|
||||||
created_by: string;
|
|
||||||
created_by_detail: IUserLite;
|
|
||||||
id: string;
|
|
||||||
metadata: any;
|
|
||||||
title: string;
|
|
||||||
url: string;
|
|
||||||
}[];
|
|
||||||
links_list: ModuleLink[];
|
links_list: ModuleLink[];
|
||||||
members: string[];
|
members: string[];
|
||||||
members_list: string[];
|
members_list: string[];
|
||||||
|
Loading…
Reference in New Issue
Block a user