fix: dropdown and multiselect component values on disabled and option text not truncating (#3089)

* Fixed dropdown component showing empty value and not showing dropdown when combobox is true

* Fixed multiselect component showing empty value and not showing dropdown when combobox is true

* Added disabled onChange on multiline and dropdown, with snapshot ignore

* Fixed tooltip skip delay duration that made tooltip on Dropdown unusable

* Fixed size of text inside dropdown and multiselect

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
Lucas Oliveira 2024-07-30 18:30:50 -03:00 • committed by GitHub
commit 1336ae0772
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 97 additions and 65 deletions

View file

@ -5,6 +5,7 @@ import { ChangeEvent, useEffect, useRef, useState } from "react";
import { DropDownComponentType } from "../../types/components"; import { DropDownComponentType } from "../../types/components";
import { cn } from "../../utils/utils"; import { cn } from "../../utils/utils";
import { default as ForwardedIconComponent } from "../genericIconComponent"; import { default as ForwardedIconComponent } from "../genericIconComponent";
import ShadTooltip from "../shadTooltipComponent";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { import {
Command, Command,
@ -47,15 +48,21 @@ export default function Dropdown({
const value = event.target.value; const value = event.target.value;
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) filtered.push(value); if (!filtered.includes(value) && combobox && value) filtered.push(value);
setFilteredOptions(value ? filtered : options); setFilteredOptions(value ? filtered : options);
setCustomValue(value); setCustomValue(value);
}; };
useEffect(() => {
if (disabled && value !== "") {
onSelect("", undefined, true);
}
}, [disabled]);
useEffect(() => { useEffect(() => {
if (open) { if (open) {
const filtered = cloneDeep(options); const filtered = cloneDeep(options);
if (customValue === value && combobox) { if (customValue === value && value && combobox) {
filtered.push(customValue); filtered.push(customValue);
} }
setFilteredOptions(filtered); setFilteredOptions(filtered);
@ -64,7 +71,7 @@ export default function Dropdown({
return ( return (
<> <>
{Object.keys(options ?? [])?.length > 0 ? ( {Object.keys(options ?? [])?.length > 0 || combobox ? (
<> <>
<Popover open={open} onOpenChange={children ? () => {} : setOpen}> <Popover open={open} onOpenChange={children ? () => {} : setOpen}>
{children ? ( {children ? (
@ -131,32 +138,40 @@ export default function Dropdown({
<CommandEmpty>No values found.</CommandEmpty> <CommandEmpty>No values found.</CommandEmpty>
<CommandGroup defaultChecked={false}> <CommandGroup defaultChecked={false}>
{filteredOptions?.map((option, id) => ( {filteredOptions?.map((option, id) => (
<CommandItem <ShadTooltip
delayDuration={700}
key={id} key={id}
value={option} content={option}
onSelect={(currentValue) => {
onSelect(currentValue);
setOpen(false);
}}
className="items-center truncate"
data-testid={`${option}-${id ?? ""}-option`}
> >
{customValue === option ? ( <div>
<span className="text-muted-foreground"> <CommandItem
Text:&nbsp; key={id}
</span> value={option}
) : ( onSelect={(currentValue) => {
<></> onSelect(currentValue);
)} setOpen(false);
{option} }}
<ForwardedIconComponent className="items-center overflow-hidden truncate"
name="Check" data-testid={`${option}-${id ?? ""}-option`}
className={cn( >
"ml-auto h-4 w-4 text-primary", {customValue === option ? (
value === option ? "opacity-100" : "opacity-0", <span className="text-muted-foreground">
)} Text:&nbsp;
/> </span>
</CommandItem> ) : (
<></>
)}
<span className="truncate">{option}</span>
<ForwardedIconComponent
name="Check"
className={cn(
"ml-auto h-4 w-4 shrink-0 text-primary",
value === option ? "opacity-100" : "opacity-0",
)}
/>
</CommandItem>
</div>
</ShadTooltip>
))} ))}
</CommandGroup> </CommandGroup>
</CommandList> </CommandList>

View file

@ -18,7 +18,7 @@ export default function InputListComponent({
}: InputListComponentType): JSX.Element { }: InputListComponentType): JSX.Element {
useEffect(() => { useEffect(() => {
if (disabled && value.length > 0 && value[0] !== "") { if (disabled && value.length > 0 && value[0] !== "") {
onChange([""]); onChange([""], undefined, true);
} }
}, [disabled]); }, [disabled]);

View file

@ -4,6 +4,7 @@ import { useEffect, useRef, useState } from "react";
import { MultiselectComponentType } from "../../types/components"; import { MultiselectComponentType } from "../../types/components";
import { cn } from "../../utils/utils"; import { cn } from "../../utils/utils";
import { default as ForwardedIconComponent } from "../genericIconComponent"; import { default as ForwardedIconComponent } from "../genericIconComponent";
import ShadTooltip from "../shadTooltipComponent";
import { Button } from "../ui/button"; import { Button } from "../ui/button";
import { import {
Command, Command,
@ -51,7 +52,7 @@ export default function MultiselectComponent({
const fuse = onlySelected ? fuseValues : fuseOptions; const fuse = onlySelected ? fuseValues : fuseOptions;
const searchValues = fuse.search(v); const searchValues = fuse.search(v);
let filtered: string[] = searchValues.map((search) => search.item); let filtered: string[] = searchValues.map((search) => search.item);
if (!filtered.includes(v) && combobox) filtered = [v, ...filtered]; if (!filtered.includes(v) && combobox && v) filtered = [v, ...filtered];
setFilteredOptions( setFilteredOptions(
v v
? filtered ? filtered
@ -61,6 +62,12 @@ export default function MultiselectComponent({
); );
}; };
useEffect(() => {
if (disabled && value.length > 0 && value[0] !== "") {
onSelect([], undefined, true);
}
}, [disabled]);
useEffect(() => { useEffect(() => {
searchRoleByTerm(searchValue); searchRoleByTerm(searchValue);
}, [onlySelected]); }, [onlySelected]);
@ -72,7 +79,7 @@ export default function MultiselectComponent({
useEffect(() => { useEffect(() => {
setCustomValues(value.filter((v) => !defaultOptions.includes(v)) ?? []); setCustomValues(value.filter((v) => !defaultOptions.includes(v)) ?? []);
setOptions([ setOptions([
...value.filter((v) => !defaultOptions.includes(v)), ...value.filter((v) => !defaultOptions.includes(v) && v),
...defaultOptions, ...defaultOptions,
]); ]);
}, [value]); }, [value]);
@ -87,7 +94,7 @@ export default function MultiselectComponent({
return ( return (
<> <>
{Object.keys(options ?? [])?.length > 0 ? ( {Object.keys(options ?? [])?.length > 0 || combobox ? (
<> <>
<Popover open={open} onOpenChange={children ? () => {} : setOpen}> <Popover open={open} onOpenChange={children ? () => {} : setOpen}>
{children ? ( {children ? (
@ -171,38 +178,48 @@ export default function MultiselectComponent({
<CommandEmpty>No values found.</CommandEmpty> <CommandEmpty>No values found.</CommandEmpty>
<CommandGroup defaultChecked={false}> <CommandGroup defaultChecked={false}>
{filteredOptions?.map((option, id) => ( {filteredOptions?.map((option, id) => (
<CommandItem <ShadTooltip
delayDuration={700}
key={id} key={id}
value={option} content={option}
onSelect={(currentValue) => {
if (value.includes(currentValue)) {
onSelect(value.filter((v) => v !== currentValue));
} else {
onSelect([...value, currentValue]);
}
}}
className="items-center truncate"
data-testid={`${option}-${id ?? ""}-option`}
> >
{customValues.includes(option) || <div>
searchValue === option ? ( <CommandItem
<span className="text-muted-foreground"> key={id}
Text:&nbsp; value={option}
</span> onSelect={(currentValue) => {
) : ( if (value.includes(currentValue)) {
<></> onSelect(
)} value.filter((v) => v !== currentValue),
{option} );
<ForwardedIconComponent } else {
name="Check" onSelect([...value, currentValue]);
className={cn( }
"ml-auto h-4 w-4 text-primary", }}
value.includes(option) className="items-center overflow-hidden truncate"
? "opacity-100" data-testid={`${option}-${id ?? ""}-option`}
: "opacity-0", >
)} {customValues.includes(option) ||
/> searchValue === option ? (
</CommandItem> <span className="text-muted-foreground">
Text:&nbsp;
</span>
) : (
<></>
)}
<span className="truncate">{option}</span>
<ForwardedIconComponent
name="Check"
className={cn(
"ml-auto h-4 w-4 shrink-0 text-primary",
value.includes(option)
? "opacity-100"
: "opacity-0",
)}
/>
</CommandItem>
</div>
</ShadTooltip>
))} ))}
</CommandGroup> </CommandGroup>
</CommandList> </CommandList>

View file

@ -14,7 +14,7 @@ export default function ContextWrapper({ children }: { children: ReactNode }) {
<BrowserRouter> <BrowserRouter>
<QueryClientProvider client={queryClient}> <QueryClientProvider client={queryClient}>
<AuthProvider> <AuthProvider>
<TooltipProvider> <TooltipProvider skipDelayDuration={0}>
<ReactFlowProvider> <ReactFlowProvider>
<ApiInterceptor /> <ApiInterceptor />
{children} {children}

View file

@ -56,7 +56,7 @@ export type DropDownComponentType = {
value: string; value: string;
combobox?: boolean; combobox?: boolean;
options: string[]; options: string[];
onSelect: (value: string) => void; onSelect: (value: string, dbValue?: boolean, snapshot?: boolean) => void;
editNode?: boolean; editNode?: boolean;
id?: string; id?: string;
children?: ReactNode; children?: ReactNode;
@ -67,7 +67,7 @@ export type MultiselectComponentType = {
value: string[]; value: string[];
combobox?: boolean; combobox?: boolean;
options: string[]; options: string[];
onSelect: (value: string[]) => void; onSelect: (value: string[], dbValue?: boolean, snapshot?: boolean) => void;
editNode?: boolean; editNode?: boolean;
id?: string; id?: string;
children?: ReactNode; children?: ReactNode;
@ -96,7 +96,7 @@ export type ParameterComponentType = {
}; };
export type InputListComponentType = { export type InputListComponentType = {
value: string[]; value: string[];
onChange: (value: string[]) => void; onChange: (value: string[], dbValue?: boolean, snapshot?: boolean) => void;
disabled: boolean; disabled: boolean;
editNode?: boolean; editNode?: boolean;
componentName?: string; componentName?: string;