mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
fix: drag and drop function (#815)
* fix: kanban drag and drop * fix: kanban board issue dnd mutation
This commit is contained in:
parent
6de94efc7d
commit
3fa6185b63
@ -108,7 +108,9 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
key={issue.id}
|
key={issue.id}
|
||||||
draggableId={issue.id}
|
draggableId={issue.id}
|
||||||
index={index}
|
index={index}
|
||||||
isDragDisabled={isNotAllowed || selectedGroup === "created_by"}
|
isDragDisabled={
|
||||||
|
isNotAllowed || selectedGroup === "created_by" || selectedGroup === "labels"
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{(provided, snapshot) => (
|
{(provided, snapshot) => (
|
||||||
<SingleBoardIssue
|
<SingleBoardIssue
|
||||||
|
@ -50,7 +50,6 @@ import {
|
|||||||
MODULE_ISSUES_WITH_PARAMS,
|
MODULE_ISSUES_WITH_PARAMS,
|
||||||
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
PROJECT_ISSUES_LIST_WITH_PARAMS,
|
||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
import useEstimateOption from "hooks/use-estimate-option";
|
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type?: string;
|
type?: string;
|
||||||
@ -93,8 +92,6 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
|
|
||||||
const { orderBy, params } = useIssuesView();
|
const { orderBy, params } = useIssuesView();
|
||||||
|
|
||||||
const { estimateValue } = useEstimateOption(issue.estimate_point);
|
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
@ -113,7 +110,14 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
>(
|
>(
|
||||||
CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params),
|
CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params),
|
||||||
(prevData) =>
|
(prevData) =>
|
||||||
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData),
|
handleIssuesMutation(
|
||||||
|
formData,
|
||||||
|
groupTitle ?? "",
|
||||||
|
selectedGroup,
|
||||||
|
index,
|
||||||
|
orderBy,
|
||||||
|
prevData
|
||||||
|
),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
else if (moduleId)
|
else if (moduleId)
|
||||||
@ -125,10 +129,17 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
>(
|
>(
|
||||||
MODULE_ISSUES_WITH_PARAMS(moduleId as string),
|
MODULE_ISSUES_WITH_PARAMS(moduleId as string),
|
||||||
(prevData) =>
|
(prevData) =>
|
||||||
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData),
|
handleIssuesMutation(
|
||||||
|
formData,
|
||||||
|
groupTitle ?? "",
|
||||||
|
selectedGroup,
|
||||||
|
index,
|
||||||
|
orderBy,
|
||||||
|
prevData
|
||||||
|
),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
else
|
else {
|
||||||
mutate<
|
mutate<
|
||||||
| {
|
| {
|
||||||
[key: string]: IIssue[];
|
[key: string]: IIssue[];
|
||||||
@ -136,10 +147,21 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
| IIssue[]
|
| IIssue[]
|
||||||
>(
|
>(
|
||||||
PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params),
|
PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params),
|
||||||
(prevData) =>
|
(prevData) => {
|
||||||
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData),
|
if (!prevData) return prevData;
|
||||||
|
|
||||||
|
return handleIssuesMutation(
|
||||||
|
formData,
|
||||||
|
groupTitle ?? "",
|
||||||
|
selectedGroup,
|
||||||
|
index,
|
||||||
|
orderBy,
|
||||||
|
prevData
|
||||||
|
);
|
||||||
|
},
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
issuesService
|
issuesService
|
||||||
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
|
.patchIssue(workspaceSlug as string, projectId as string, issue.id, formData)
|
||||||
@ -156,7 +178,18 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[workspaceSlug, projectId, cycleId, moduleId, issue, groupTitle, index, selectedGroup, params]
|
[
|
||||||
|
workspaceSlug,
|
||||||
|
projectId,
|
||||||
|
cycleId,
|
||||||
|
moduleId,
|
||||||
|
issue,
|
||||||
|
groupTitle,
|
||||||
|
index,
|
||||||
|
selectedGroup,
|
||||||
|
orderBy,
|
||||||
|
params,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const getStyle = (
|
const getStyle = (
|
||||||
|
@ -48,6 +48,7 @@ import {
|
|||||||
} from "constants/fetch-keys";
|
} from "constants/fetch-keys";
|
||||||
// image
|
// image
|
||||||
import emptyCycle from "public/empty-state/empty-cycle.svg";
|
import emptyCycle from "public/empty-state/empty-cycle.svg";
|
||||||
|
import { orderArrayBy } from "helpers/array.helper";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type?: "issue" | "cycle" | "module";
|
type?: "issue" | "cycle" | "module";
|
||||||
@ -208,8 +209,8 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...prevData,
|
...prevData,
|
||||||
[sourceGroup]: sourceGroupArray,
|
[sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
|
||||||
[destinationGroup]: destinationGroupArray,
|
[destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
@ -230,8 +231,8 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...prevData,
|
...prevData,
|
||||||
[sourceGroup]: sourceGroupArray,
|
[sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
|
||||||
[destinationGroup]: destinationGroupArray,
|
[destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
@ -250,8 +251,8 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
...prevData,
|
...prevData,
|
||||||
[sourceGroup]: sourceGroupArray,
|
[sourceGroup]: orderArrayBy(sourceGroupArray, orderBy),
|
||||||
[destinationGroup]: destinationGroupArray,
|
[destinationGroup]: orderArrayBy(destinationGroupArray, orderBy),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
false
|
false
|
||||||
@ -482,24 +483,24 @@ export const IssuesView: React.FC<Props> = ({
|
|||||||
<>
|
<>
|
||||||
{isCompleted && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
{isCompleted && <TransferIssues handleClick={() => setTransferIssuesModal(true)} />}
|
||||||
{issueView === "list" ? (
|
{issueView === "list" ? (
|
||||||
<AllLists
|
<AllLists
|
||||||
type={type}
|
type={type}
|
||||||
states={states}
|
states={states}
|
||||||
addIssueToState={addIssueToState}
|
addIssueToState={addIssueToState}
|
||||||
makeIssueCopy={makeIssueCopy}
|
makeIssueCopy={makeIssueCopy}
|
||||||
handleEditIssue={handleEditIssue}
|
handleEditIssue={handleEditIssue}
|
||||||
handleDeleteIssue={handleDeleteIssue}
|
handleDeleteIssue={handleDeleteIssue}
|
||||||
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
|
openIssuesListModal={type !== "issue" ? openIssuesListModal : null}
|
||||||
removeIssue={
|
removeIssue={
|
||||||
type === "cycle"
|
type === "cycle"
|
||||||
? removeIssueFromCycle
|
? removeIssueFromCycle
|
||||||
: type === "module"
|
: type === "module"
|
||||||
? removeIssueFromModule
|
? removeIssueFromModule
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
isCompleted={isCompleted}
|
isCompleted={isCompleted}
|
||||||
userAuth={memberRole}
|
userAuth={memberRole}
|
||||||
/>
|
/>
|
||||||
) : issueView === "kanban" ? (
|
) : issueView === "kanban" ? (
|
||||||
<AllBoards
|
<AllBoards
|
||||||
type={type}
|
type={type}
|
||||||
|
@ -29,7 +29,7 @@ import {
|
|||||||
TrashIcon,
|
TrashIcon,
|
||||||
XMarkIcon,
|
XMarkIcon,
|
||||||
ArrowTopRightOnSquareIcon,
|
ArrowTopRightOnSquareIcon,
|
||||||
PaperClipIcon
|
PaperClipIcon,
|
||||||
} from "@heroicons/react/24/outline";
|
} from "@heroicons/react/24/outline";
|
||||||
// helpers
|
// helpers
|
||||||
import { copyTextToClipboard, truncateText } from "helpers/string.helper";
|
import { copyTextToClipboard, truncateText } from "helpers/string.helper";
|
||||||
@ -82,7 +82,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
|
|
||||||
const { groupByProperty: selectedGroup, params } = useIssueView();
|
const { groupByProperty: selectedGroup, orderBy, params } = useIssueView();
|
||||||
|
|
||||||
const partialUpdateIssue = useCallback(
|
const partialUpdateIssue = useCallback(
|
||||||
(formData: Partial<IIssue>) => {
|
(formData: Partial<IIssue>) => {
|
||||||
@ -97,7 +97,14 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
>(
|
>(
|
||||||
CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params),
|
CYCLE_ISSUES_WITH_PARAMS(cycleId as string, params),
|
||||||
(prevData) =>
|
(prevData) =>
|
||||||
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData),
|
handleIssuesMutation(
|
||||||
|
formData,
|
||||||
|
groupTitle ?? "",
|
||||||
|
selectedGroup,
|
||||||
|
index,
|
||||||
|
orderBy,
|
||||||
|
prevData
|
||||||
|
),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -110,7 +117,14 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
>(
|
>(
|
||||||
MODULE_ISSUES_WITH_PARAMS(moduleId as string, params),
|
MODULE_ISSUES_WITH_PARAMS(moduleId as string, params),
|
||||||
(prevData) =>
|
(prevData) =>
|
||||||
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData),
|
handleIssuesMutation(
|
||||||
|
formData,
|
||||||
|
groupTitle ?? "",
|
||||||
|
selectedGroup,
|
||||||
|
index,
|
||||||
|
orderBy,
|
||||||
|
prevData
|
||||||
|
),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -122,7 +136,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
>(
|
>(
|
||||||
PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params),
|
PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params),
|
||||||
(prevData) =>
|
(prevData) =>
|
||||||
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, prevData),
|
handleIssuesMutation(formData, groupTitle ?? "", selectedGroup, index, orderBy, prevData),
|
||||||
false
|
false
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -138,7 +152,18 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
} else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
|
} else mutate(PROJECT_ISSUES_LIST_WITH_PARAMS(projectId as string, params));
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[workspaceSlug, projectId, cycleId, moduleId, issue, groupTitle, index, selectedGroup, params]
|
[
|
||||||
|
workspaceSlug,
|
||||||
|
projectId,
|
||||||
|
cycleId,
|
||||||
|
moduleId,
|
||||||
|
issue,
|
||||||
|
groupTitle,
|
||||||
|
index,
|
||||||
|
selectedGroup,
|
||||||
|
orderBy,
|
||||||
|
params,
|
||||||
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCopyText = () => {
|
const handleCopyText = () => {
|
||||||
|
@ -37,6 +37,7 @@ export const FILTER_ISSUE_OPTIONS: Array<{
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
import { orderArrayBy } from "helpers/array.helper";
|
||||||
import { IIssue, TIssueGroupByOptions, TIssueOrderByOptions } from "types";
|
import { IIssue, TIssueGroupByOptions, TIssueOrderByOptions } from "types";
|
||||||
|
|
||||||
type THandleIssuesMutation = (
|
type THandleIssuesMutation = (
|
||||||
@ -44,6 +45,7 @@ type THandleIssuesMutation = (
|
|||||||
oldGroupTitle: string,
|
oldGroupTitle: string,
|
||||||
selectedGroupBy: TIssueGroupByOptions,
|
selectedGroupBy: TIssueGroupByOptions,
|
||||||
issueIndex: number,
|
issueIndex: number,
|
||||||
|
orderBy: TIssueOrderByOptions,
|
||||||
prevData?:
|
prevData?:
|
||||||
| {
|
| {
|
||||||
[key: string]: IIssue[];
|
[key: string]: IIssue[];
|
||||||
@ -61,6 +63,7 @@ export const handleIssuesMutation: THandleIssuesMutation = (
|
|||||||
oldGroupTitle,
|
oldGroupTitle,
|
||||||
selectedGroupBy,
|
selectedGroupBy,
|
||||||
issueIndex,
|
issueIndex,
|
||||||
|
orderBy,
|
||||||
prevData
|
prevData
|
||||||
) => {
|
) => {
|
||||||
if (!prevData) return prevData;
|
if (!prevData) return prevData;
|
||||||
@ -89,15 +92,24 @@ export const handleIssuesMutation: THandleIssuesMutation = (
|
|||||||
assignees: formData?.assignees_list ?? oldGroup[issueIndex]?.assignees_list,
|
assignees: formData?.assignees_list ?? oldGroup[issueIndex]?.assignees_list,
|
||||||
};
|
};
|
||||||
|
|
||||||
oldGroup.splice(issueIndex, 1);
|
if (selectedGroupBy !== Object.keys(formData)[0])
|
||||||
newGroup.push(updatedIssue);
|
return {
|
||||||
|
...prevData,
|
||||||
|
[oldGroupTitle ?? ""]: orderArrayBy(
|
||||||
|
oldGroup.map((i) => (i.id === updatedIssue.id ? updatedIssue : i)),
|
||||||
|
orderBy
|
||||||
|
),
|
||||||
|
};
|
||||||
|
|
||||||
const groupThatIsUpdated = selectedGroupBy === "priority" ? formData.priority : formData.state;
|
const groupThatIsUpdated = selectedGroupBy === "priority" ? formData.priority : formData.state;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...prevData,
|
...prevData,
|
||||||
[oldGroupTitle ?? ""]: oldGroup,
|
[oldGroupTitle ?? ""]: orderArrayBy(
|
||||||
[groupThatIsUpdated ?? ""]: newGroup,
|
oldGroup.filter((i) => i.id !== updatedIssue.id),
|
||||||
|
orderBy
|
||||||
|
),
|
||||||
|
[groupThatIsUpdated ?? ""]: orderArrayBy([...newGroup, updatedIssue], orderBy),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -12,7 +12,13 @@ export const orderArrayBy = (
|
|||||||
key: string,
|
key: string,
|
||||||
ordering: "ascending" | "descending" = "ascending"
|
ordering: "ascending" | "descending" = "ascending"
|
||||||
) => {
|
) => {
|
||||||
|
if (key[0] === "-") {
|
||||||
|
ordering = "descending";
|
||||||
|
key = key.slice(1);
|
||||||
|
}
|
||||||
|
|
||||||
const innerKey = key.split("."); // split the key by dot
|
const innerKey = key.split("."); // split the key by dot
|
||||||
|
|
||||||
return array.sort((a, b) => {
|
return array.sort((a, b) => {
|
||||||
const keyA = innerKey.reduce((obj, i) => obj[i], a); // get the value of the inner key
|
const keyA = innerKey.reduce((obj, i) => obj[i], a); // get the value of the inner key
|
||||||
const keyB = innerKey.reduce((obj, i) => obj[i], b); // get the value of the inner key
|
const keyB = innerKey.reduce((obj, i) => obj[i], b); // get the value of the inner key
|
||||||
|
Loading…
Reference in New Issue
Block a user