fix: Improve dropdown component with null option filtering (#6830)

Improve dropdown component with null option filtering
This commit is contained in:
Deon Sanchez 2025-02-25 15:10:57 -07:00 • committed by GitHub
commit e98b25fd9b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 20 additions and 8 deletions

View file

@ -7,9 +7,14 @@ import { getStatusColor } from "@/utils/stringManipulation";
import { PopoverAnchor } from "@radix-ui/react-popover"; import { PopoverAnchor } from "@radix-ui/react-popover";
import Fuse from "fuse.js"; import Fuse from "fuse.js";
import { cloneDeep } from "lodash"; import { cloneDeep } from "lodash";
import { ChangeEvent, useEffect, useRef, useState } from "react"; import { ChangeEvent, useEffect, useMemo, useRef, useState } from "react";
import { DropDownComponent } from "../../../types/components"; import { DropDownComponent } from "../../../types/components";
import { cn, formatName, formatPlaceholderName } from "../../../utils/utils"; import {
cn,
filterNullOptions,
formatName,
formatPlaceholderName,
} from "../../../utils/utils";
import { default as ForwardedIconComponent } from "../../common/genericIconComponent"; import { default as ForwardedIconComponent } from "../../common/genericIconComponent";
import ShadTooltip from "../../common/shadTooltipComponent"; import ShadTooltip from "../../common/shadTooltipComponent";
import { Button } from "../../ui/button"; import { Button } from "../../ui/button";
@ -43,11 +48,13 @@ export default function Dropdown({
dialogInputs, dialogInputs,
...baseInputProps ...baseInputProps
}: BaseInputProps & DropDownComponent): JSX.Element { }: BaseInputProps & DropDownComponent): JSX.Element {
const validOptions = useMemo(() => filterNullOptions(options), [options]);
// Initialize state and refs // Initialize state and refs
const [open, setOpen] = useState(children ? true : false); const [open, setOpen] = useState(children ? true : false);
const [openDialog, setOpenDialog] = useState(false); const [openDialog, setOpenDialog] = useState(false);
const [customValue, setCustomValue] = useState(""); const [customValue, setCustomValue] = useState("");
const [filteredOptions, setFilteredOptions] = useState(options); const [filteredOptions, setFilteredOptions] = useState(validOptions);
const [refreshOptions, setRefreshOptions] = useState(false); const [refreshOptions, setRefreshOptions] = useState(false);
const refButton = useRef<HTMLButtonElement>(null); const refButton = useRef<HTMLButtonElement>(null);
@ -56,7 +63,7 @@ export default function Dropdown({
? formatPlaceholderName(name) ? formatPlaceholderName(name)
: "Choose an option..."; : "Choose an option...";
const { firstWord } = formatName(name); const { firstWord } = formatName(name);
const fuse = new Fuse(options, { keys: ["name", "value"] }); const fuse = new Fuse(validOptions, { keys: ["name", "value"] });
const PopoverContentDropdown = const PopoverContentDropdown =
children || editNode ? PopoverContent : PopoverContentWithoutPortal; children || editNode ? PopoverContent : PopoverContentWithoutPortal;
const { nodeClass, nodeId, handleNodeClass, tooltip } = baseInputProps; const { nodeClass, nodeId, handleNodeClass, tooltip } = baseInputProps;
@ -84,7 +91,7 @@ export default function Dropdown({
const searchValues = fuse.search(value); const searchValues = fuse.search(value);
const filtered = searchValues.map((search) => search.item); const filtered = searchValues.map((search) => search.item);
if (!filtered.includes(value) && combobox && value) filtered.push(value); if (!filtered.includes(value) && combobox && value) filtered.push(value);
setFilteredOptions(value ? filtered : options); setFilteredOptions(value ? filtered : validOptions);
setCustomValue(value); setCustomValue(value);
}; };
@ -133,7 +140,7 @@ export default function Dropdown({
useEffect(() => { useEffect(() => {
if (open) { if (open) {
const filtered = cloneDeep(options); const filtered = cloneDeep(validOptions);
if (customValue === value && value && combobox) { if (customValue === value && value && combobox) {
filtered.push(customValue); filtered.push(customValue);
} }
@ -159,7 +166,7 @@ export default function Dropdown({
<Button <Button
disabled={ disabled={
disabled || disabled ||
(Object.keys(options).length === 0 && (Object.keys(validOptions).length === 0 &&
!combobox && !combobox &&
!dialogInputs?.fields?.data?.node?.template) !dialogInputs?.fields?.data?.node?.template)
} }
@ -397,7 +404,7 @@ export default function Dropdown({
); );
// Loading state // Loading state
if (Object.keys(options).length === 0 && !combobox && isLoading) { if (Object.keys(validOptions).length === 0 && !combobox && isLoading) {
return ( return (
<div> <div>
<span className="text-sm italic">Loading...</span> <span className="text-sm italic">Loading...</span>

View file

@ -765,3 +765,8 @@ export const isStringArray = (value: unknown): value is string[] => {
}; };
export const stringToBool = (str) => (str === "false" ? false : true); export const stringToBool = (str) => (str === "false" ? false : true);
// Filter out null/undefined options
export const filterNullOptions = (opts: any[]): any[] => {
return opts.filter((opt) => opt !== null && opt !== undefined);
};