mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
Merge pull request #339 from makeplane/chore/new_link_endpoint
chore: new link endpoints
This commit is contained in:
commit
3af3bb0fb5
@ -16,7 +16,7 @@ import type { IIssueLink, ModuleLink } from "types";
|
|||||||
type Props = {
|
type Props = {
|
||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
onFormSubmit: (formData: IIssueLink | ModuleLink) => void;
|
onFormSubmit: (formData: IIssueLink | ModuleLink) => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
const defaultValues: ModuleLink = {
|
const defaultValues: ModuleLink = {
|
||||||
|
@ -14,6 +14,7 @@ type Props = {
|
|||||||
created_at: Date;
|
created_at: Date;
|
||||||
created_by: string;
|
created_by: string;
|
||||||
created_by_detail: IUserLite;
|
created_by_detail: IUserLite;
|
||||||
|
metadata: any;
|
||||||
title: string;
|
title: string;
|
||||||
url: string;
|
url: string;
|
||||||
}[];
|
}[];
|
||||||
@ -56,8 +57,8 @@ export const LinksList: React.FC<Props> = ({ links, handleDeleteLink, userAuth }
|
|||||||
<h5 className="w-4/5">{link.title}</h5>
|
<h5 className="w-4/5">{link.title}</h5>
|
||||||
<p className="mt-0.5 text-gray-500">
|
<p className="mt-0.5 text-gray-500">
|
||||||
Added {timeAgo(link.created_at)}
|
Added {timeAgo(link.created_at)}
|
||||||
{/* <br />
|
<br />
|
||||||
by {link.created_by_detail.email} */}
|
by {link.created_by_detail.email}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
|
@ -86,7 +86,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
|||||||
return () => {
|
return () => {
|
||||||
window.removeEventListener("keydown", handleKeyDown);
|
window.removeEventListener("keydown", handleKeyDown);
|
||||||
};
|
};
|
||||||
}, []);
|
}, [handleClose]);
|
||||||
|
|
||||||
const addIssueToCycle = async (issueId: string, cycleId: string) => {
|
const addIssueToCycle = async (issueId: string, cycleId: string) => {
|
||||||
if (!workspaceSlug || !projectId) return;
|
if (!workspaceSlug || !projectId) return;
|
||||||
|
@ -77,6 +77,17 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
|
console.log("isseu details: ", issueDetail);
|
||||||
|
|
||||||
|
// const { data: issueLinks } = useSWR(
|
||||||
|
// workspaceSlug && projectId
|
||||||
|
// ? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)
|
||||||
|
// : null,
|
||||||
|
// workspaceSlug && projectId
|
||||||
|
// ? () => issuesService.getIssues(workspaceSlug as string, projectId as string)
|
||||||
|
// : null
|
||||||
|
// );
|
||||||
|
|
||||||
const { data: issues } = useSWR(
|
const { data: issues } = useSWR(
|
||||||
workspaceSlug && projectId
|
workspaceSlug && projectId
|
||||||
? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)
|
? PROJECT_ISSUES_LIST(workspaceSlug as string, projectId as string)
|
||||||
@ -149,16 +160,12 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
const handleCreateLink = async (formData: IIssueLink) => {
|
const handleCreateLink = async (formData: IIssueLink) => {
|
||||||
if (!workspaceSlug || !projectId || !issueDetail) return;
|
if (!workspaceSlug || !projectId || !issueDetail) return;
|
||||||
|
|
||||||
const previousLinks = issueDetail?.issue_link.map((l) => ({ title: l.title, url: l.url }));
|
const payload = { metadata: {}, ...formData };
|
||||||
|
|
||||||
const payload: Partial<IIssue> = {
|
|
||||||
links_list: [...(previousLinks ?? []), formData],
|
|
||||||
};
|
|
||||||
|
|
||||||
await issuesService
|
await issuesService
|
||||||
.patchIssue(workspaceSlug as string, projectId as string, issueDetail.id, payload)
|
.createIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(ISSUE_DETAILS(issueDetail.id as string));
|
mutate(ISSUE_DETAILS(issueDetail.id));
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
@ -171,17 +178,15 @@ export const IssueDetailsSidebar: React.FC<Props> = ({
|
|||||||
const updatedLinks = issueDetail.issue_link.filter((l) => l.id !== linkId);
|
const updatedLinks = issueDetail.issue_link.filter((l) => l.id !== linkId);
|
||||||
|
|
||||||
mutate<IIssue>(
|
mutate<IIssue>(
|
||||||
ISSUE_DETAILS(issueDetail.id as string),
|
ISSUE_DETAILS(issueDetail.id),
|
||||||
(prevData) => ({ ...(prevData as IIssue), issue_link: updatedLinks }),
|
(prevData) => ({ ...(prevData as IIssue), issue_link: updatedLinks }),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
await issuesService
|
await issuesService
|
||||||
.patchIssue(workspaceSlug as string, projectId as string, issueDetail.id, {
|
.deleteIssueLink(workspaceSlug as string, projectId as string, issueDetail.id, linkId)
|
||||||
links_list: updatedLinks,
|
|
||||||
})
|
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(ISSUE_DETAILS(issueDetail.id as string));
|
mutate(ISSUE_DETAILS(issueDetail.id));
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
|
@ -71,6 +71,8 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
|
|||||||
const [startDateRange, setStartDateRange] = useState<Date | null>(new Date());
|
const [startDateRange, setStartDateRange] = useState<Date | null>(new Date());
|
||||||
const [endDateRange, setEndDateRange] = useState<Date | null>(null);
|
const [endDateRange, setEndDateRange] = useState<Date | null>(null);
|
||||||
|
|
||||||
|
console.log("module details: ", module);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, moduleId } = router.query;
|
const { workspaceSlug, projectId, moduleId } = router.query;
|
||||||
|
|
||||||
@ -115,14 +117,10 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
|
|||||||
const handleCreateLink = async (formData: ModuleLink) => {
|
const handleCreateLink = async (formData: ModuleLink) => {
|
||||||
if (!workspaceSlug || !projectId || !moduleId) return;
|
if (!workspaceSlug || !projectId || !moduleId) return;
|
||||||
|
|
||||||
const previousLinks = module?.link_module.map((l) => ({ title: l.title, url: l.url }));
|
const payload = { metadata: {}, ...formData };
|
||||||
|
|
||||||
const payload: Partial<IModule> = {
|
|
||||||
links_list: [...(previousLinks ?? []), formData],
|
|
||||||
};
|
|
||||||
|
|
||||||
await modulesService
|
await modulesService
|
||||||
.patchModule(workspaceSlug as string, projectId as string, moduleId as string, payload)
|
.createModuleLink(workspaceSlug as string, projectId as string, moduleId as string, payload)
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
mutate(MODULE_DETAILS(moduleId as string));
|
mutate(MODULE_DETAILS(moduleId as string));
|
||||||
})
|
})
|
||||||
@ -135,11 +133,25 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDeleteLink = (linkId: string) => {
|
const handleDeleteLink = async (linkId: string) => {
|
||||||
if (!module) return;
|
if (!workspaceSlug || !projectId || !module) return;
|
||||||
|
|
||||||
const updatedLinks = module.link_module.filter((l) => l.id !== linkId);
|
const updatedLinks = module.link_module.filter((l) => l.id !== linkId);
|
||||||
submitChanges({ links_list: updatedLinks });
|
|
||||||
|
mutate<IModule>(
|
||||||
|
MODULE_DETAILS(module.id),
|
||||||
|
(prevData) => ({ ...(prevData as IModule), link_module: updatedLinks }),
|
||||||
|
false
|
||||||
|
);
|
||||||
|
|
||||||
|
await modulesService
|
||||||
|
.deleteModuleLink(workspaceSlug as string, projectId as string, module.id, linkId)
|
||||||
|
.then((res) => {
|
||||||
|
mutate(MODULE_DETAILS(module.id));
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
console.log(err);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -350,27 +362,6 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="py-1">
|
|
||||||
<div className="flex items-center justify-between gap-2">
|
|
||||||
<h4>Links</h4>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
className="grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-gray-100"
|
|
||||||
onClick={() => setModuleLinkModal(true)}
|
|
||||||
>
|
|
||||||
<PlusIcon className="h-4 w-4" />
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className="mt-2 space-y-2">
|
|
||||||
{module.link_module && module.link_module.length > 0 ? (
|
|
||||||
<LinksList
|
|
||||||
links={module.link_module}
|
|
||||||
handleDeleteLink={handleDeleteLink}
|
|
||||||
userAuth={userAuth}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col items-center justify-center w-full gap-2">
|
<div className="flex flex-col items-center justify-center w-full gap-2">
|
||||||
{isStartValid && isEndValid ? (
|
{isStartValid && isEndValid ? (
|
||||||
@ -388,6 +379,27 @@ export const ModuleDetailsSidebar: React.FC<Props> = ({
|
|||||||
""
|
""
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
<div className="py-1 text-xs">
|
||||||
|
<div className="flex items-center justify-between gap-2">
|
||||||
|
<h4>Links</h4>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className="grid h-7 w-7 place-items-center rounded p-1 outline-none duration-300 hover:bg-gray-100"
|
||||||
|
onClick={() => setModuleLinkModal(true)}
|
||||||
|
>
|
||||||
|
<PlusIcon className="h-4 w-4" />
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className="mt-2 space-y-2">
|
||||||
|
{module.link_module && module.link_module.length > 0 ? (
|
||||||
|
<LinksList
|
||||||
|
links={module.link_module}
|
||||||
|
handleDeleteLink={handleDeleteLink}
|
||||||
|
userAuth={userAuth}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<Loader>
|
<Loader>
|
||||||
|
@ -293,6 +293,41 @@ class ProjectIssuesServices extends APIService {
|
|||||||
throw error?.response?.data;
|
throw error?.response?.data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createIssueLink(
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
issueId: string,
|
||||||
|
data: {
|
||||||
|
metadata: any;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
): Promise<any> {
|
||||||
|
return this.post(
|
||||||
|
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/`,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
.then((response) => response?.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error?.response?.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteIssueLink(
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
issueId: string,
|
||||||
|
linkId: string
|
||||||
|
): Promise<any> {
|
||||||
|
return this.delete(
|
||||||
|
`/api/workspaces/${workspaceSlug}/projects/${projectId}/issues/${issueId}/issue-links/${linkId}/`
|
||||||
|
)
|
||||||
|
.then((response) => response?.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error?.response?.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new ProjectIssuesServices();
|
export default new ProjectIssuesServices();
|
||||||
|
@ -116,6 +116,41 @@ class ProjectIssuesServices extends APIService {
|
|||||||
throw error?.response?.data;
|
throw error?.response?.data;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async createModuleLink(
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
moduleId: string,
|
||||||
|
data: {
|
||||||
|
metadata: any;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
}
|
||||||
|
): Promise<any> {
|
||||||
|
return this.post(
|
||||||
|
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/`,
|
||||||
|
data
|
||||||
|
)
|
||||||
|
.then((response) => response?.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error?.response?.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteModuleLink(
|
||||||
|
workspaceSlug: string,
|
||||||
|
projectId: string,
|
||||||
|
moduleId: string,
|
||||||
|
linkId: string
|
||||||
|
): Promise<any> {
|
||||||
|
return this.delete(
|
||||||
|
`/api/workspaces/${workspaceSlug}/projects/${projectId}/modules/${moduleId}/module-links/${linkId}/`
|
||||||
|
)
|
||||||
|
.then((response) => response?.data)
|
||||||
|
.catch((error) => {
|
||||||
|
throw error?.response?.data;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new ProjectIssuesServices();
|
export default new ProjectIssuesServices();
|
||||||
|
1
apps/app/types/issues.d.ts
vendored
1
apps/app/types/issues.d.ts
vendored
@ -82,6 +82,7 @@ export interface IIssue {
|
|||||||
created_by: string;
|
created_by: string;
|
||||||
created_by_detail: IUserLite;
|
created_by_detail: IUserLite;
|
||||||
id: string;
|
id: string;
|
||||||
|
metadata: any;
|
||||||
title: string;
|
title: string;
|
||||||
url: string;
|
url: string;
|
||||||
}[];
|
}[];
|
||||||
|
1
apps/app/types/modules.d.ts
vendored
1
apps/app/types/modules.d.ts
vendored
@ -14,6 +14,7 @@ export interface IModule {
|
|||||||
created_by: string;
|
created_by: string;
|
||||||
created_by_detail: IUserLite;
|
created_by_detail: IUserLite;
|
||||||
id: string;
|
id: string;
|
||||||
|
metadata: any;
|
||||||
title: string;
|
title: string;
|
||||||
url: string;
|
url: string;
|
||||||
}[];
|
}[];
|
||||||
|
Loading…
Reference in New Issue
Block a user