-
Notifications
You must be signed in to change notification settings - Fork 1.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WEB-2678]feat: added functionality to add labels directly from dropdown #6211
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,11 +1,11 @@ | ||||||||||||||||||||||||||||||||||||||||||||
"use client"; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
import { Fragment, useEffect, useRef, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||
import { useEffect, useRef, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||
import { Placement } from "@popperjs/core"; | ||||||||||||||||||||||||||||||||||||||||||||
import { observer } from "mobx-react"; | ||||||||||||||||||||||||||||||||||||||||||||
import { useParams } from "next/navigation"; | ||||||||||||||||||||||||||||||||||||||||||||
import { usePopper } from "react-popper"; | ||||||||||||||||||||||||||||||||||||||||||||
import { Check, ChevronDown, Search, Tags } from "lucide-react"; | ||||||||||||||||||||||||||||||||||||||||||||
import { Check, ChevronDown, Loader, Search, Tags } from "lucide-react"; | ||||||||||||||||||||||||||||||||||||||||||||
import { Combobox } from "@headlessui/react"; | ||||||||||||||||||||||||||||||||||||||||||||
// plane helpers | ||||||||||||||||||||||||||||||||||||||||||||
import { useOutsideClickDetector } from "@plane/hooks"; | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -14,9 +14,12 @@ import { IIssueLabel } from "@plane/types"; | |||||||||||||||||||||||||||||||||||||||||||
// ui | ||||||||||||||||||||||||||||||||||||||||||||
import { ComboDropDown, Tooltip } from "@plane/ui"; | ||||||||||||||||||||||||||||||||||||||||||||
// hooks | ||||||||||||||||||||||||||||||||||||||||||||
import { useLabel } from "@/hooks/store"; | ||||||||||||||||||||||||||||||||||||||||||||
import { getRandomLabelColor } from "@/constants/label"; | ||||||||||||||||||||||||||||||||||||||||||||
import { useLabel, useUserPermissions } from "@/hooks/store"; | ||||||||||||||||||||||||||||||||||||||||||||
import { useDropdownKeyDown } from "@/hooks/use-dropdown-key-down"; | ||||||||||||||||||||||||||||||||||||||||||||
import { usePlatformOS } from "@/hooks/use-platform-os"; | ||||||||||||||||||||||||||||||||||||||||||||
import { EUserPermissions, EUserPermissionsLevel } from "ee/constants/user-permissions"; | ||||||||||||||||||||||||||||||||||||||||||||
// constants | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
export interface IIssuePropertyLabels { | ||||||||||||||||||||||||||||||||||||||||||||
projectId: string | null; | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -62,6 +65,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro | |||||||||||||||||||||||||||||||||||||||||||
// states | ||||||||||||||||||||||||||||||||||||||||||||
const [query, setQuery] = useState(""); | ||||||||||||||||||||||||||||||||||||||||||||
const [isOpen, setIsOpen] = useState(false); | ||||||||||||||||||||||||||||||||||||||||||||
const [submitting, setSubmitting] = useState<boolean>(false); | ||||||||||||||||||||||||||||||||||||||||||||
// refs | ||||||||||||||||||||||||||||||||||||||||||||
const dropdownRef = useRef<HTMLDivElement | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||
const inputRef = useRef<HTMLInputElement | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -70,9 +74,12 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro | |||||||||||||||||||||||||||||||||||||||||||
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null); | ||||||||||||||||||||||||||||||||||||||||||||
const [isLoading, setIsLoading] = useState<boolean>(false); | ||||||||||||||||||||||||||||||||||||||||||||
// store hooks | ||||||||||||||||||||||||||||||||||||||||||||
const { fetchProjectLabels, getProjectLabels } = useLabel(); | ||||||||||||||||||||||||||||||||||||||||||||
const { fetchProjectLabels, getProjectLabels, createLabel } = useLabel(); | ||||||||||||||||||||||||||||||||||||||||||||
const { isMobile } = usePlatformOS(); | ||||||||||||||||||||||||||||||||||||||||||||
const storeLabels = getProjectLabels(projectId); | ||||||||||||||||||||||||||||||||||||||||||||
const { allowPermissions } = useUserPermissions(); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
const canCreateLabel = allowPermissions([EUserPermissions.ADMIN], EUserPermissionsLevel.PROJECT); | ||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Utilize the The |
||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
const onOpen = () => { | ||||||||||||||||||||||||||||||||||||||||||||
if (!storeLabels && workspaceSlug && projectId) | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -102,11 +109,17 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro | |||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
useOutsideClickDetector(dropdownRef, handleClose); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
const searchInputKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => { | ||||||||||||||||||||||||||||||||||||||||||||
const searchInputKeyDown = async (e: React.KeyboardEvent<HTMLInputElement>) => { | ||||||||||||||||||||||||||||||||||||||||||||
if (query !== "" && e.key === "Escape") { | ||||||||||||||||||||||||||||||||||||||||||||
e.stopPropagation(); | ||||||||||||||||||||||||||||||||||||||||||||
setQuery(""); | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
if (query !== "" && e.key === "Enter") { | ||||||||||||||||||||||||||||||||||||||||||||
e.stopPropagation(); | ||||||||||||||||||||||||||||||||||||||||||||
e.preventDefault(); | ||||||||||||||||||||||||||||||||||||||||||||
await handleAddLabel(query); | ||||||||||||||||||||||||||||||||||||||||||||
} | ||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -249,6 +262,15 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro | |||||||||||||||||||||||||||||||||||||||||||
</button> | ||||||||||||||||||||||||||||||||||||||||||||
); | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
const handleAddLabel = async (labelName: string) => { | ||||||||||||||||||||||||||||||||||||||||||||
if (!projectId) return; | ||||||||||||||||||||||||||||||||||||||||||||
setSubmitting(true); | ||||||||||||||||||||||||||||||||||||||||||||
const label = await createLabel(workspaceSlug, projectId, { name: labelName, color: getRandomLabelColor() }); | ||||||||||||||||||||||||||||||||||||||||||||
onChange([...value, label.id]); | ||||||||||||||||||||||||||||||||||||||||||||
setQuery(""); | ||||||||||||||||||||||||||||||||||||||||||||
setSubmitting(false); | ||||||||||||||||||||||||||||||||||||||||||||
}; | ||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||
Comment on lines
+265
to
+273
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add error handling to Include error handling in Apply this diff: const handleAddLabel = async (labelName: string) => {
if (!projectId) return;
setSubmitting(true);
+ try {
const label = await createLabel(workspaceSlug, projectId, { name: labelName, color: getRandomLabelColor() });
onChange([...value, label.id]);
setQuery("");
+ } catch (error) {
+ // Handle error, e.g., display an error message to the user
+ console.error("Failed to add label:", error);
+ }
setSubmitting(false);
}; 📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||
return ( | ||||||||||||||||||||||||||||||||||||||||||||
<ComboDropDown | ||||||||||||||||||||||||||||||||||||||||||||
as="div" | ||||||||||||||||||||||||||||||||||||||||||||
|
@@ -314,10 +336,19 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro | |||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||
</Combobox.Option> | ||||||||||||||||||||||||||||||||||||||||||||
)) | ||||||||||||||||||||||||||||||||||||||||||||
) : submitting ? ( | ||||||||||||||||||||||||||||||||||||||||||||
<Loader className="spin h-3.5 w-3.5" /> | ||||||||||||||||||||||||||||||||||||||||||||
) : canCreateLabel ? ( | ||||||||||||||||||||||||||||||||||||||||||||
<p | ||||||||||||||||||||||||||||||||||||||||||||
onClick={() => { | ||||||||||||||||||||||||||||||||||||||||||||
handleAddLabel(query); | ||||||||||||||||||||||||||||||||||||||||||||
}} | ||||||||||||||||||||||||||||||||||||||||||||
className="text-left text-custom-text-200 cursor-pointer" | ||||||||||||||||||||||||||||||||||||||||||||
> | ||||||||||||||||||||||||||||||||||||||||||||
+ Add <span className="text-custom-text-100">"{query}"</span> to labels | ||||||||||||||||||||||||||||||||||||||||||||
</p> | ||||||||||||||||||||||||||||||||||||||||||||
) : ( | ||||||||||||||||||||||||||||||||||||||||||||
<span className="flex items-center gap-2 p-1"> | ||||||||||||||||||||||||||||||||||||||||||||
<p className="text-left text-custom-text-200 ">No matching results</p> | ||||||||||||||||||||||||||||||||||||||||||||
</span> | ||||||||||||||||||||||||||||||||||||||||||||
<p className="text-left text-custom-text-200 ">No matching results.</p> | ||||||||||||||||||||||||||||||||||||||||||||
)} | ||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||
</div> | ||||||||||||||||||||||||||||||||||||||||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add error handling to
handleAddLabel
functionCurrently,
handleAddLabel
does not handle errors that might occur during label creation. To enhance robustness, wrap the async call in a try-catch block and handle potential exceptions.Apply this diff to add error handling: