mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: mutation error on issue details
This commit is contained in:
parent
010d98c40d
commit
a0e7475ce8
@ -99,13 +99,15 @@ const IssueDetailSidebar: React.FC<Props> = ({
|
|||||||
|
|
||||||
const handleCycleChange = (cycleId: string) => {
|
const handleCycleChange = (cycleId: string) => {
|
||||||
if (activeWorkspace && activeProject && issueDetail)
|
if (activeWorkspace && activeProject && issueDetail)
|
||||||
issuesServices.addIssueToCycle(activeWorkspace.slug, activeProject.id, cycleId, {
|
issuesServices
|
||||||
issue: issueDetail.id,
|
.addIssueToCycle(activeWorkspace.slug, activeProject.id, cycleId, {
|
||||||
});
|
issue: issueDetail.id,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
submitChanges({});
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(issueDetail?.labels, issueDetail?.labels_list);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="h-full w-full divide-y-2 divide-gray-100">
|
<div className="h-full w-full divide-y-2 divide-gray-100">
|
||||||
@ -141,7 +143,7 @@ const IssueDetailSidebar: React.FC<Props> = ({
|
|||||||
type="button"
|
type="button"
|
||||||
className="p-2 hover:bg-gray-100 border rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 duration-300"
|
className="p-2 hover:bg-gray-100 border rounded-md shadow-sm focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 duration-300"
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
copyTextToClipboard(`${issueDetail?.id}`)
|
copyTextToClipboard(issueDetail?.id ?? "")
|
||||||
.then(() => {
|
.then(() => {
|
||||||
setToastAlert({
|
setToastAlert({
|
||||||
type: "success",
|
type: "success",
|
||||||
@ -249,7 +251,7 @@ const IssueDetailSidebar: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
<div className="basis-1/2">
|
<div className="basis-1/2">
|
||||||
<div className="flex gap-1 flex-wrap">
|
<div className="flex gap-1 flex-wrap">
|
||||||
{issueDetail?.labels.map((label) => {
|
{watchIssue("labels_list")?.map((label) => {
|
||||||
const singleLabel = issueLabels?.find((l) => l.id === label);
|
const singleLabel = issueLabels?.find((l) => l.id === label);
|
||||||
|
|
||||||
if (!singleLabel) return null;
|
if (!singleLabel) return null;
|
||||||
@ -259,11 +261,10 @@ const IssueDetailSidebar: React.FC<Props> = ({
|
|||||||
key={singleLabel.id}
|
key={singleLabel.id}
|
||||||
className="group flex items-center gap-1 border rounded-2xl text-xs px-1 py-0.5 hover:bg-red-50 hover:border-red-500 cursor-pointer"
|
className="group flex items-center gap-1 border rounded-2xl text-xs px-1 py-0.5 hover:bg-red-50 hover:border-red-500 cursor-pointer"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
const updatedLabels = issueDetail?.labels.filter((l) => l !== label);
|
const updatedLabels = watchIssue("labels_list")?.filter((l) => l !== label);
|
||||||
// submitChanges({
|
submitChanges({
|
||||||
// labels_list: updatedLabels,
|
labels_list: updatedLabels,
|
||||||
// });
|
});
|
||||||
console.log(updatedLabels);
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span
|
<span
|
||||||
|
@ -551,6 +551,10 @@ const ListView: React.FC<Props> = ({
|
|||||||
[selectedGroup]: singleGroup,
|
[selectedGroup]: singleGroup,
|
||||||
actionType: "createIssue",
|
actionType: "createIssue",
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
setPreloadedData({
|
||||||
|
actionType: "createIssue",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
@ -1,16 +1,25 @@
|
|||||||
|
import React, { useCallback, useEffect, useState } from "react";
|
||||||
// next
|
// next
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import type { NextPage } from "next";
|
import type { NextPage } from "next";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
import dynamic from "next/dynamic";
|
import dynamic from "next/dynamic";
|
||||||
// react
|
|
||||||
import React, { useCallback, useEffect, useState } from "react";
|
|
||||||
// swr
|
// swr
|
||||||
import useSWR, { mutate } from "swr";
|
import useSWR, { mutate } from "swr";
|
||||||
// react hook form
|
// react hook form
|
||||||
import { useForm } from "react-hook-form";
|
import { useForm } from "react-hook-form";
|
||||||
|
// headless ui
|
||||||
|
import { Disclosure, Menu, Tab, Transition } from "@headlessui/react";
|
||||||
|
// fetch keys
|
||||||
|
import {
|
||||||
|
PROJECT_ISSUES_ACTIVITY,
|
||||||
|
PROJECT_ISSUES_COMMENTS,
|
||||||
|
PROJECT_ISSUES_LIST,
|
||||||
|
} from "constants/fetch-keys";
|
||||||
// services
|
// services
|
||||||
import issuesServices from "lib/services/issues.service";
|
import issuesServices from "lib/services/issues.service";
|
||||||
|
// common
|
||||||
|
import { debounce } from "constants/common";
|
||||||
// hooks
|
// hooks
|
||||||
import useUser from "lib/hooks/useUser";
|
import useUser from "lib/hooks/useUser";
|
||||||
// hoc
|
// hoc
|
||||||
@ -24,12 +33,8 @@ import AddAsSubIssue from "components/project/issues/issue-detail/add-as-sub-iss
|
|||||||
import ConfirmIssueDeletion from "components/project/issues/confirm-issue-deletion";
|
import ConfirmIssueDeletion from "components/project/issues/confirm-issue-deletion";
|
||||||
import IssueDetailSidebar from "components/project/issues/issue-detail/issue-detail-sidebar";
|
import IssueDetailSidebar from "components/project/issues/issue-detail/issue-detail-sidebar";
|
||||||
import IssueActivitySection from "components/project/issues/issue-detail/activity";
|
import IssueActivitySection from "components/project/issues/issue-detail/activity";
|
||||||
// headless ui
|
|
||||||
import { Disclosure, Menu, Tab, Transition } from "@headlessui/react";
|
|
||||||
// ui
|
// ui
|
||||||
import { Spinner, TextArea } from "ui";
|
import { Spinner, TextArea, HeaderButton, Breadcrumbs, BreadcrumbItem } from "ui";
|
||||||
import HeaderButton from "ui/HeaderButton";
|
|
||||||
import { BreadcrumbItem, Breadcrumbs } from "ui/Breadcrumbs";
|
|
||||||
// icons
|
// icons
|
||||||
import {
|
import {
|
||||||
ChevronLeftIcon,
|
ChevronLeftIcon,
|
||||||
@ -39,14 +44,6 @@ import {
|
|||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
// types
|
// types
|
||||||
import { IIssue, IIssueComment, IssueResponse } from "types";
|
import { IIssue, IIssueComment, IssueResponse } from "types";
|
||||||
// fetch keys
|
|
||||||
import {
|
|
||||||
PROJECT_ISSUES_ACTIVITY,
|
|
||||||
PROJECT_ISSUES_COMMENTS,
|
|
||||||
PROJECT_ISSUES_LIST,
|
|
||||||
} from "constants/fetch-keys";
|
|
||||||
// common
|
|
||||||
import { debounce } from "constants/common";
|
|
||||||
|
|
||||||
const RichTextEditor = dynamic(() => import("components/lexical/editor"), {
|
const RichTextEditor = dynamic(() => import("components/lexical/editor"), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
@ -148,7 +145,15 @@ const IssueDetail: NextPage = () => {
|
|||||||
issuesServices
|
issuesServices
|
||||||
.patchIssue(activeWorkspace.slug, projectId as string, issueId as string, payload)
|
.patchIssue(activeWorkspace.slug, projectId as string, issueId as string, payload)
|
||||||
.then((response) => {
|
.then((response) => {
|
||||||
console.log(response);
|
mutateIssues((prevData) => ({
|
||||||
|
...(prevData as IssueResponse),
|
||||||
|
results: (prevData?.results ?? []).map((issue) => {
|
||||||
|
if (issue.id === issueId) {
|
||||||
|
return { ...issue, ...response };
|
||||||
|
}
|
||||||
|
return issue;
|
||||||
|
}),
|
||||||
|
}));
|
||||||
})
|
})
|
||||||
.catch((error) => {
|
.catch((error) => {
|
||||||
console.log(error);
|
console.log(error);
|
||||||
@ -170,25 +175,23 @@ const IssueDetail: NextPage = () => {
|
|||||||
issueDetail.blocked_issues?.map((issue) => issue.blocked_issue_detail?.id),
|
issueDetail.blocked_issues?.map((issue) => issue.blocked_issue_detail?.id),
|
||||||
assignees_list:
|
assignees_list:
|
||||||
issueDetail.assignees_list ?? issueDetail.assignee_details?.map((user) => user.id),
|
issueDetail.assignees_list ?? issueDetail.assignee_details?.map((user) => user.id),
|
||||||
labels_list: issueDetail.labels_list ?? issueDetail.labels?.map((label) => label),
|
labels_list: issueDetail.labels_list ?? issueDetail.labels,
|
||||||
labels: issueDetail.labels_list ?? issueDetail.labels?.map((label) => label),
|
labels: issueDetail.labels_list ?? issueDetail.labels,
|
||||||
});
|
});
|
||||||
}, [issueDetail, reset]);
|
}, [issueDetail, reset]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const issueIndex = issues?.results.findIndex((issue) => issue.id === issueId);
|
const issueDetail = issues?.results.find((issue) => issue.id === issueId);
|
||||||
if (issueIndex === undefined) return;
|
|
||||||
const issueDetail = issues?.results[issueIndex];
|
|
||||||
setIssueDetail(issueDetail);
|
setIssueDetail(issueDetail);
|
||||||
}, [issues, issueId]);
|
}, [issueId, issues]);
|
||||||
|
|
||||||
const prevIssue = issues?.results[issues?.results.findIndex((issue) => issue.id === issueId) - 1];
|
const prevIssue = issues?.results[issues?.results.findIndex((issue) => issue.id === issueId) - 1];
|
||||||
const nextIssue = issues?.results[issues?.results.findIndex((issue) => issue.id === issueId) + 1];
|
const nextIssue = issues?.results[issues?.results.findIndex((issue) => issue.id === issueId) + 1];
|
||||||
|
|
||||||
const subIssues = (issues && issues.results.filter((i) => i.parent === issueDetail?.id)) ?? [];
|
const subIssues = (issues && issues.results.filter((i) => i.parent === issueId)) ?? [];
|
||||||
const siblingIssues =
|
const siblingIssues =
|
||||||
issueDetail &&
|
issueDetail &&
|
||||||
issues?.results.filter((i) => i.parent === issueDetail.parent && i.id !== issueDetail.id);
|
issues?.results.filter((i) => i.parent === issueDetail.parent && i.id !== issueId);
|
||||||
|
|
||||||
const handleSubIssueRemove = (issueId: string) => {
|
const handleSubIssueRemove = (issueId: string) => {
|
||||||
if (activeWorkspace && activeProject) {
|
if (activeWorkspace && activeProject) {
|
||||||
@ -212,8 +215,6 @@ const IssueDetail: NextPage = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log(issueDetail);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppLayout
|
<AppLayout
|
||||||
noPadding={true}
|
noPadding={true}
|
||||||
@ -236,7 +237,7 @@ const IssueDetail: NextPage = () => {
|
|||||||
<HeaderButton
|
<HeaderButton
|
||||||
Icon={ChevronLeftIcon}
|
Icon={ChevronLeftIcon}
|
||||||
label="Previous"
|
label="Previous"
|
||||||
className={`${!prevIssue ? "cursor-not-allowed opacity-70" : ""}`}
|
className={!prevIssue ? "cursor-not-allowed opacity-70" : ""}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!prevIssue) return;
|
if (!prevIssue) return;
|
||||||
router.push(`/projects/${prevIssue.project}/issues/${prevIssue.id}`);
|
router.push(`/projects/${prevIssue.project}/issues/${prevIssue.id}`);
|
||||||
@ -246,7 +247,7 @@ const IssueDetail: NextPage = () => {
|
|||||||
Icon={ChevronRightIcon}
|
Icon={ChevronRightIcon}
|
||||||
disabled={!nextIssue}
|
disabled={!nextIssue}
|
||||||
label="Next"
|
label="Next"
|
||||||
className={`${!nextIssue ? "cursor-not-allowed opacity-70" : ""}`}
|
className={!nextIssue ? "cursor-not-allowed opacity-70" : ""}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
if (!nextIssue) return;
|
if (!nextIssue) return;
|
||||||
router.push(`/projects/${nextIssue.project}/issues/${nextIssue?.id}`);
|
router.push(`/projects/${nextIssue.project}/issues/${nextIssue?.id}`);
|
||||||
@ -284,7 +285,7 @@ const IssueDetail: NextPage = () => {
|
|||||||
<Link href={`/projects/${activeProject.id}/issues/${issueDetail.parent}`}>
|
<Link href={`/projects/${activeProject.id}/issues/${issueDetail.parent}`}>
|
||||||
<a className="flex items-center gap-2">
|
<a className="flex items-center gap-2">
|
||||||
<span
|
<span
|
||||||
className={`h-1.5 w-1.5 block rounded-full`}
|
className="h-1.5 w-1.5 block rounded-full"
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: issueDetail.state_detail.color,
|
backgroundColor: issueDetail.state_detail.color,
|
||||||
}}
|
}}
|
||||||
@ -432,15 +433,13 @@ const IssueDetail: NextPage = () => {
|
|||||||
<Menu.Items className="origin-top-right absolute right-0 mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-50">
|
<Menu.Items className="origin-top-right absolute right-0 mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-50">
|
||||||
<div className="p-1">
|
<div className="p-1">
|
||||||
<Menu.Item as="div">
|
<Menu.Item as="div">
|
||||||
{(active) => (
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
className="flex items-center gap-2 p-2 text-left text-gray-900 hover:bg-theme hover:text-white rounded-md text-xs whitespace-nowrap"
|
||||||
className="flex items-center gap-2 p-2 text-left text-gray-900 hover:bg-theme hover:text-white rounded-md text-xs whitespace-nowrap"
|
onClick={() => setIsAddAsSubIssueOpen(true)}
|
||||||
onClick={() => setIsAddAsSubIssueOpen(true)}
|
>
|
||||||
>
|
Add an existing issue
|
||||||
Add an existing issue
|
</button>
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</div>
|
</div>
|
||||||
</Menu.Items>
|
</Menu.Items>
|
||||||
@ -497,14 +496,12 @@ const IssueDetail: NextPage = () => {
|
|||||||
<Menu.Items className="origin-top-right absolute right-0 mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-50">
|
<Menu.Items className="origin-top-right absolute right-0 mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-50">
|
||||||
<div className="p-1">
|
<div className="p-1">
|
||||||
<Menu.Item as="div">
|
<Menu.Item as="div">
|
||||||
{(active) => (
|
<button
|
||||||
<button
|
className="flex items-center gap-2 p-2 text-left text-gray-900 hover:bg-theme hover:text-white rounded-md text-xs whitespace-nowrap"
|
||||||
className="flex items-center gap-2 p-2 text-left text-gray-900 hover:bg-theme hover:text-white rounded-md text-xs whitespace-nowrap"
|
onClick={() => handleSubIssueRemove(subIssue.id)}
|
||||||
onClick={() => handleSubIssueRemove(subIssue.id)}
|
>
|
||||||
>
|
Remove as sub-issue
|
||||||
Remove as sub-issue
|
</button>
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</div>
|
</div>
|
||||||
</Menu.Items>
|
</Menu.Items>
|
||||||
@ -537,38 +534,34 @@ const IssueDetail: NextPage = () => {
|
|||||||
<Menu.Items className="absolute origin-top-right left-0 mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-10">
|
<Menu.Items className="absolute origin-top-right left-0 mt-2 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5 focus:outline-none z-10">
|
||||||
<div className="p-1">
|
<div className="p-1">
|
||||||
<Menu.Item as="div">
|
<Menu.Item as="div">
|
||||||
{(active) => (
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
className="text-left p-2 text-gray-900 hover:bg-theme hover:text-white rounded-md text-xs whitespace-nowrap w-full"
|
||||||
className="text-left p-2 text-gray-900 hover:bg-theme hover:text-white rounded-md text-xs whitespace-nowrap w-full"
|
onClick={() => {
|
||||||
onClick={() => {
|
setIsOpen(true);
|
||||||
setIsOpen(true);
|
setPreloadedData({
|
||||||
setPreloadedData({
|
parent: issueDetail.id,
|
||||||
parent: issueDetail.id,
|
actionType: "createIssue",
|
||||||
actionType: "createIssue",
|
});
|
||||||
});
|
}}
|
||||||
}}
|
>
|
||||||
>
|
Create new
|
||||||
Create new
|
</button>
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
<Menu.Item as="div">
|
<Menu.Item as="div">
|
||||||
{(active) => (
|
<button
|
||||||
<button
|
type="button"
|
||||||
type="button"
|
className="p-2 text-left text-gray-900 hover:bg-theme hover:text-white rounded-md text-xs whitespace-nowrap"
|
||||||
className="p-2 text-left text-gray-900 hover:bg-theme hover:text-white rounded-md text-xs whitespace-nowrap"
|
onClick={() => {
|
||||||
onClick={() => {
|
setIsAddAsSubIssueOpen(true);
|
||||||
setIsAddAsSubIssueOpen(true);
|
setPreloadedData({
|
||||||
setPreloadedData({
|
parent: issueDetail.id,
|
||||||
parent: issueDetail.id,
|
actionType: "createIssue",
|
||||||
actionType: "createIssue",
|
});
|
||||||
});
|
}}
|
||||||
}}
|
>
|
||||||
>
|
Add an existing issue
|
||||||
Add an existing issue
|
</button>
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</Menu.Item>
|
</Menu.Item>
|
||||||
</div>
|
</div>
|
||||||
</Menu.Items>
|
</Menu.Items>
|
||||||
|
Loading…
Reference in New Issue
Block a user