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:
parent
72ff6d3a58
commit
1336ae0772
5 changed files with 97 additions and 65 deletions
|
|
@ -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:
|
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:
|
||||||
/>
|
</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>
|
||||||
|
|
|
||||||
|
|
@ -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]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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:
|
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:
|
||||||
|
</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>
|
||||||
|
|
|
||||||
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue