- {labelChildren.map((child) => (
-
-
- (
+
+ <>
+
+ {isEditLabelForm ? (
+
{
+ setEditLabelForm(false);
+ setIsUpdating(false);
}}
/>
- {child.name}
-
-
-
-
-
-
- }
- >
-
removeFromGroup(child)}>
-
-
- Remove from group
-
-
-
editLabel(child)}>
-
-
- Edit label
-
-
-
-
+ ) : (
+
+ )}
-
-
-
-
+
+
+
+
+
- ))}
+
+
+
+ {labelChildren.map((child, index) => (
+
+
+ {renderDraggable((provided: DraggableProvided, snapshot: DraggableStateSnapshot) => (
+
+
handleLabelDelete(child)}
+ draggableSnapshot={snapshot}
+ dragHandleProps={provided.dragHandleProps!}
+ setIsUpdating={setIsUpdating}
+ isChild
+ />
+
+ ))}
+
+
+ ))}
+
+
+
+ {droppableProvided.placeholder}
+ >
-
-
+ )}
+
>
)}
diff --git a/web/components/labels/project-setting-label-item.tsx b/web/components/labels/project-setting-label-item.tsx
new file mode 100644
index 000000000..29ac427af
--- /dev/null
+++ b/web/components/labels/project-setting-label-item.tsx
@@ -0,0 +1,91 @@
+import React, { Dispatch, SetStateAction, useState } from "react";
+import { useRouter } from "next/router";
+import { useMobxStore } from "lib/mobx/store-provider";
+import { DraggableProvidedDragHandleProps, DraggableStateSnapshot } from "@hello-pangea/dnd";
+// types
+import { IIssueLabel } from "types";
+//icons
+import { X, Pencil } from "lucide-react";
+//components
+import { ICustomMenuItem, LabelItemBlock } from "./label-block/label-item-block";
+import { CreateUpdateLabelInline } from "./create-update-label-inline";
+
+type Props = {
+ label: IIssueLabel;
+ handleLabelDelete: (label: IIssueLabel) => void;
+ draggableSnapshot: DraggableStateSnapshot;
+ dragHandleProps: DraggableProvidedDragHandleProps;
+ setIsUpdating: Dispatch
>;
+ isChild: boolean;
+};
+
+export const ProjectSettingLabelItem: React.FC = (props) => {
+ const { label, setIsUpdating, handleLabelDelete, draggableSnapshot, dragHandleProps, isChild } = props;
+
+ const { combineTargetFor, isDragging } = draggableSnapshot;
+
+ // router
+ const router = useRouter();
+ const { workspaceSlug, projectId } = router.query;
+
+ // store
+ const { projectLabel: projectLabelStore } = useMobxStore();
+
+ //state
+ const [isEditLabelForm, setEditLabelForm] = useState(false);
+
+ const removeFromGroup = (label: IIssueLabel) => {
+ if (!workspaceSlug || !projectId) return;
+
+ projectLabelStore.updateLabel(workspaceSlug.toString(), projectId.toString(), label.id, {
+ parent: null,
+ });
+ };
+
+ const customMenuItems: ICustomMenuItem[] = [
+ {
+ CustomIcon: X,
+ onClick: removeFromGroup,
+ isVisible: !!label.parent,
+ text: "Remove from group",
+ },
+ {
+ CustomIcon: Pencil,
+ onClick: () => {
+ setEditLabelForm(true);
+ setIsUpdating(true);
+ },
+ isVisible: true,
+ text: "Edit label",
+ },
+ ];
+
+ return (
+
+ {isEditLabelForm ? (
+ {
+ setEditLabelForm(false);
+ setIsUpdating(false);
+ }}
+ />
+ ) : (
+
+ )}
+
+ );
+};
diff --git a/web/components/labels/project-setting-label-list-item.tsx b/web/components/labels/project-setting-label-list-item.tsx
deleted file mode 100644
index fec3bcd2e..000000000
--- a/web/components/labels/project-setting-label-list-item.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import React, { useRef, useState } from "react";
-
-//hook
-import useOutsideClickDetector from "hooks/use-outside-click-detector";
-// ui
-import { CustomMenu } from "@plane/ui";
-// types
-import { IIssueLabels } from "types";
-//icons
-import { Component, X, Pencil } from "lucide-react";
-
-type Props = {
- label: IIssueLabels;
- addLabelToGroup: (parentLabel: IIssueLabels) => void;
- editLabel: (label: IIssueLabels) => void;
- handleLabelDelete: () => void;
-};
-
-export const ProjectSettingLabelItem: React.FC = (props) => {
- const { label, addLabelToGroup, editLabel, handleLabelDelete } = props;
-
- const [isMenuActive, setIsMenuActive] = useState(false);
- const actionSectionRef = useRef(null);
-
- useOutsideClickDetector(actionSectionRef, () => setIsMenuActive(false));
-
- return (
-
-
-
-
{label.name}
-
-
-
- setIsMenuActive(!isMenuActive)}>
-
-
- }
- >
-
addLabelToGroup(label)}>
-
-
- Convert to group
-
-
-
editLabel(label)}>
-
-
- Edit label
-
-
-
-
-
-
-
-
- );
-};
diff --git a/web/components/labels/project-setting-label-list.tsx b/web/components/labels/project-setting-label-list.tsx
index 84bda8f97..48ca0f07f 100644
--- a/web/components/labels/project-setting-label-list.tsx
+++ b/web/components/labels/project-setting-label-list.tsx
@@ -1,75 +1,96 @@
import React, { useState, useRef } from "react";
import { useRouter } from "next/router";
import useSWR from "swr";
+import { observer } from "mobx-react-lite";
+import {
+ DragDropContext,
+ Draggable,
+ DraggableProvided,
+ DraggableStateSnapshot,
+ DropResult,
+ Droppable,
+} from "@hello-pangea/dnd";
// store
-import { observer } from "mobx-react-lite";
import { useMobxStore } from "lib/mobx/store-provider";
// components
-import {
- CreateUpdateLabelInline,
- DeleteLabelModal,
- LabelsListModal,
- ProjectSettingLabelItem,
- ProjectSettingLabelGroup,
-} from "components/labels";
+import { CreateUpdateLabelInline, DeleteLabelModal, ProjectSettingLabelGroup } from "components/labels";
// ui
import { Button, Loader } from "@plane/ui";
import { EmptyState } from "components/common";
// images
import emptyLabel from "public/empty-state/label.svg";
// types
-import { IIssueLabels } from "types";
+import { IIssueLabel } from "types";
+//component
+import { ProjectSettingLabelItem } from "./project-setting-label-item";
+import useDraggableInPortal from "hooks/use-draggable-portal";
+
+const LABELS_ROOT = "labels.root";
export const ProjectSettingsLabelList: React.FC = observer(() => {
// router
const router = useRouter();
const { workspaceSlug, projectId } = router.query;
+ const renderDraggable = useDraggableInPortal();
+
// store
- const { project: projectStore } = useMobxStore();
-
+ const {
+ projectLabel: { fetchProjectLabels, projectLabels, updateLabelPosition, projectLabelsTree },
+ } = useMobxStore();
// states
- const [labelForm, setLabelForm] = useState(false);
+ const [showLabelForm, setLabelForm] = useState(false);
const [isUpdating, setIsUpdating] = useState(false);
- const [labelsListModal, setLabelsListModal] = useState(false);
- const [labelToUpdate, setLabelToUpdate] = useState