From 6a482f36c4d5578465012380b4b5c0b62b79001f Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com> Date: Thu, 25 Jul 2024 18:37:59 -0300 Subject: [PATCH] feat: add custom value on dropown ui (#2961) * Added fuzzy search and custom value on search on Dropdown Component * added allowCustom prop to allow custom values on dropdownComponent * changed type of allowCustom * added custom to custom field on dropdown * Fixed empty search not showing all of the options * Added Text on the left of the label --- src/frontend/package-lock.json | 10 +++ src/frontend/package.json | 1 + .../components/dropdownComponent/index.tsx | 62 ++++++++++++++++--- src/frontend/src/types/components/index.ts | 2 +- 4 files changed, 67 insertions(+), 8 deletions(-) diff --git a/src/frontend/package-lock.json b/src/frontend/package-lock.json index a8445de26..9e90168be 100644 --- a/src/frontend/package-lock.json +++ b/src/frontend/package-lock.json @@ -48,6 +48,7 @@ "esbuild": "^0.21.5", "file-saver": "^2.0.5", "framer-motion": "^11.2.10", + "fuse.js": "^7.0.0", "lodash": "^4.17.21", "lucide-react": "^0.395.0", "million": "^3.1.11", @@ -7804,6 +7805,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/fuse.js": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/fuse.js/-/fuse.js-7.0.0.tgz", + "integrity": "sha512-14F4hBIxqKvD4Zz/XjDc3y94mNZN6pRv3U13Udo0lNLCWRBUsrMv2xwcF/y/Z5sV6+FQW+/ow68cHpm4sunt8Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=10" + } + }, "node_modules/gauge": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", diff --git a/src/frontend/package.json b/src/frontend/package.json index 187ae3dd9..f4b13fd97 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -43,6 +43,7 @@ "esbuild": "^0.21.5", "file-saver": "^2.0.5", "framer-motion": "^11.2.10", + "fuse.js": "^7.0.0", "lodash": "^4.17.21", "lucide-react": "^0.395.0", "million": "^3.1.11", diff --git a/src/frontend/src/components/dropdownComponent/index.tsx b/src/frontend/src/components/dropdownComponent/index.tsx index 0adec0734..f67a627eb 100644 --- a/src/frontend/src/components/dropdownComponent/index.tsx +++ b/src/frontend/src/components/dropdownComponent/index.tsx @@ -1,5 +1,7 @@ import { PopoverAnchor } from "@radix-ui/react-popover"; -import { useRef, useState } from "react"; +import Fuse from "fuse.js"; +import { cloneDeep } from "lodash"; +import { ChangeEvent, useEffect, useRef, useState } from "react"; import { DropDownComponentType } from "../../types/components"; import { cn } from "../../utils/utils"; import { default as ForwardedIconComponent } from "../genericIconComponent"; @@ -8,7 +10,6 @@ import { Command, CommandEmpty, CommandGroup, - CommandInput, CommandItem, CommandList, } from "../ui/command"; @@ -24,6 +25,7 @@ export default function Dropdown({ isLoading, value, options, + combobox = true, onSelect, editNode = false, id = "", @@ -35,6 +37,31 @@ export default function Dropdown({ const PopoverContentDropdown = children || editNode ? PopoverContent : PopoverContentWithoutPortal; + + const [customValue, setCustomValue] = useState(""); + const [filteredOptions, setFilteredOptions] = useState(options); + + const fuse = new Fuse(options, { keys: ["name", "value"] }); + + const searchRoleByTerm = async (event: ChangeEvent) => { + const value = event.target.value; + const searchValues = fuse.search(value); + const filtered = searchValues.map((search) => search.item); + if (!filtered.includes(value) && combobox) filtered.push(value); + setFilteredOptions(value ? filtered : options); + setCustomValue(value); + }; + + useEffect(() => { + if (open) { + const filtered = cloneDeep(options); + if (customValue === value && combobox) { + filtered.push(customValue); + } + setFilteredOptions(filtered); + } + }, [open]); + return ( <> {Object.keys(options ?? [])?.length > 0 ? ( @@ -60,11 +87,14 @@ export default function Dropdown({ editNode ? "input-edit-node" : "py-2", )} > - + {value && value !== "" && - options.find((option) => option === value) - ? options.find((option) => option === value) + filteredOptions.find((option) => option === value) + ? filteredOptions.find((option) => option === value) : "Choose an option..."} @@ -86,11 +116,21 @@ export default function Dropdown({ } > - +
+ + +
No values found. - {options?.map((option, id) => ( + {filteredOptions?.map((option, id) => ( + {customValue === option ? ( + + Text:  + + ) : ( + <> + )} {option} void; editNode?: boolean;