refactor: improve readability of several components (#3714)
* refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * refactor to improve readability * ✅ (Simple Agent.spec.ts): update expected count of python words to 2 for accurate test results 📝 (auto-login-off.spec.ts): add a 1-second timeout before checking visibility of a text element to ensure proper rendering and improve test reliability * 📝 (cardComponent/index.tsx): Extract handlePlaygroundClick function to improve code readability and maintainability 📝 (codeAreaComponent/index.tsx): Refactor code to use consistent naming conventions and improve code structure 📝 (rename-label.tsx): Refactor code to use consistent naming conventions and improve code structure 📝 (dictAreaModal/index.tsx): Refactor code to use consistent naming conventions and improve code structure * 🔧 (rename-label.tsx): Refactor RenameLabel component to improve readability and maintainability by restructuring the component logic into separate functions for handling blur, change, and double click events. Split the component rendering logic into separate functions for input and span elements. * update type * [autofix.ci] apply automated fixes --------- Co-authored-by: anovazzi1 <otavio2204@gmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
835559a05d
commit
40798c5b5a
13 changed files with 737 additions and 710 deletions
|
|
@ -55,6 +55,32 @@ export default function CollectionCardComponent({
|
||||||
|
|
||||||
const { onDragStart } = useDragStart(data);
|
const { onDragStart } = useDragStart(data);
|
||||||
|
|
||||||
|
const handlePlaygroundClick = (e: React.MouseEvent<HTMLButtonElement>) => {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
track("Playground Button Clicked", { flowId: data.id });
|
||||||
|
setLoadingPlayground(true);
|
||||||
|
const flow = getFlowById(data.id);
|
||||||
|
if (flow) {
|
||||||
|
if (!hasPlayground(flow)) {
|
||||||
|
setErrorData({
|
||||||
|
title: "Error",
|
||||||
|
list: ["This flow doesn't have a playground."],
|
||||||
|
});
|
||||||
|
setLoadingPlayground(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setCurrentFlow(flow);
|
||||||
|
setOpenPlayground(true);
|
||||||
|
setLoadingPlayground(false);
|
||||||
|
} else {
|
||||||
|
setErrorData({
|
||||||
|
title: "Error",
|
||||||
|
list: ["Error getting flow data."],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Card
|
<Card
|
||||||
|
|
@ -135,31 +161,7 @@ export default function CollectionCardComponent({
|
||||||
size="sm"
|
size="sm"
|
||||||
className="gap-2 whitespace-nowrap bg-muted"
|
className="gap-2 whitespace-nowrap bg-muted"
|
||||||
data-testid={"playground-flow-button-" + data.id}
|
data-testid={"playground-flow-button-" + data.id}
|
||||||
onClick={(e) => {
|
onClick={handlePlaygroundClick}
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
track("Playground Button Clicked", { flowId: data.id });
|
|
||||||
setLoadingPlayground(true);
|
|
||||||
const flow = getFlowById(data.id);
|
|
||||||
if (flow) {
|
|
||||||
if (!hasPlayground(flow)) {
|
|
||||||
setErrorData({
|
|
||||||
title: "Error",
|
|
||||||
list: ["This flow doesn't have a playground."],
|
|
||||||
});
|
|
||||||
setLoadingPlayground(false);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
setCurrentFlow(flow);
|
|
||||||
setOpenPlayground(true);
|
|
||||||
setLoadingPlayground(false);
|
|
||||||
} else {
|
|
||||||
setErrorData({
|
|
||||||
title: "Error",
|
|
||||||
list: ["Error getting flow data."],
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{!loadingPlayground ? (
|
{!loadingPlayground ? (
|
||||||
<IconComponent
|
<IconComponent
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import CodeAreaModal from "../../modals/codeAreaModal";
|
import CodeAreaModal from "../../modals/codeAreaModal";
|
||||||
import { CodeAreaComponentType } from "../../types/components";
|
import { CodeAreaComponentType } from "../../types/components";
|
||||||
|
import { cn } from "../../utils/utils";
|
||||||
|
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
|
|
||||||
|
|
@ -17,57 +18,68 @@ export default function CodeAreaComponent({
|
||||||
open,
|
open,
|
||||||
setOpen,
|
setOpen,
|
||||||
}: CodeAreaComponentType) {
|
}: CodeAreaComponentType) {
|
||||||
const [myValue, setMyValue] = useState(
|
const [componentValue, setComponentValue] = useState(
|
||||||
typeof value == "string" ? value : JSON.stringify(value),
|
typeof value == "string" ? value : JSON.stringify(value),
|
||||||
);
|
);
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (disabled && myValue !== "") {
|
if (disabled && componentValue !== "") {
|
||||||
setMyValue("");
|
setComponentValue("");
|
||||||
onChange("", undefined, true);
|
onChange("", undefined, true);
|
||||||
}
|
}
|
||||||
}, [disabled]);
|
}, [disabled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMyValue(typeof value == "string" ? value : JSON.stringify(value));
|
setComponentValue(typeof value == "string" ? value : JSON.stringify(value));
|
||||||
}, [value]);
|
}, [value]);
|
||||||
|
|
||||||
|
const handleValueChange = (newValue) => {
|
||||||
|
onChange(newValue);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderInputText = () => (
|
||||||
|
<span
|
||||||
|
id={id}
|
||||||
|
data-testid={id}
|
||||||
|
className={cn(
|
||||||
|
editNode
|
||||||
|
? "input-edit-node input-dialog"
|
||||||
|
: "primary-input text-muted-foreground",
|
||||||
|
disabled && !editNode && "input-disable input-ring",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{value !== "" ? value : "Type something..."}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderExternalLinkIcon = () => {
|
||||||
|
if (editNode) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={disabled ? "pointer-events-none w-full" : "w-full"}>
|
<IconComponent
|
||||||
|
name="ExternalLink"
|
||||||
|
className={cn(
|
||||||
|
"icons-parameters-comp shrink-0",
|
||||||
|
disabled ? "text-ring" : "hover:text-accent-foreground",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn("w-full", disabled && "pointer-events-none")}>
|
||||||
<CodeAreaModal
|
<CodeAreaModal
|
||||||
open={open}
|
open={open}
|
||||||
setOpen={setOpen}
|
setOpen={setOpen}
|
||||||
readonly={readonly}
|
readonly={readonly}
|
||||||
dynamic={dynamic}
|
dynamic={dynamic}
|
||||||
value={myValue}
|
value={value}
|
||||||
nodeClass={nodeClass}
|
nodeClass={nodeClass}
|
||||||
setNodeClass={setNodeClass!}
|
setNodeClass={setNodeClass!}
|
||||||
setValue={(value: string) => {
|
setValue={handleValueChange}
|
||||||
setMyValue(value);
|
|
||||||
onChange(value);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<div className="flex w-full items-center gap-3">
|
<div className="flex w-full items-center gap-3">
|
||||||
<span
|
{renderInputText()}
|
||||||
id={id}
|
{renderExternalLinkIcon()}
|
||||||
data-testid={id}
|
|
||||||
className={
|
|
||||||
editNode
|
|
||||||
? "input-edit-node input-dialog"
|
|
||||||
: (disabled ? "input-disable input-ring " : "") +
|
|
||||||
" primary-input text-muted-foreground"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{myValue !== "" ? myValue : "Type something..."}
|
|
||||||
</span>
|
|
||||||
{!editNode && (
|
|
||||||
<IconComponent
|
|
||||||
name="ExternalLink"
|
|
||||||
className={
|
|
||||||
"icons-parameters-comp shrink-0" +
|
|
||||||
(disabled ? " text-ring" : " hover:text-accent-foreground")
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</CodeAreaModal>
|
</CodeAreaModal>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -69,14 +69,7 @@ export default function Dropdown({
|
||||||
}
|
}
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
return (
|
const renderTriggerButton = () => (
|
||||||
<>
|
|
||||||
{Object.keys(options ?? [])?.length > 0 || combobox ? (
|
|
||||||
<>
|
|
||||||
<Popover open={open} onOpenChange={children ? () => {} : setOpen}>
|
|
||||||
{children ? (
|
|
||||||
<PopoverAnchor>{children}</PopoverAnchor>
|
|
||||||
) : (
|
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
@ -85,44 +78,30 @@ export default function Dropdown({
|
||||||
role="combobox"
|
role="combobox"
|
||||||
ref={refButton}
|
ref={refButton}
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
data-testid={`${id ?? ""}`}
|
data-testid={id}
|
||||||
className={cn(
|
className={cn(
|
||||||
editNode
|
editNode
|
||||||
? "dropdown-component-outline"
|
? "dropdown-component-outline input-edit-node"
|
||||||
: "dropdown-component-false-outline",
|
: "dropdown-component-false-outline py-2",
|
||||||
"w-full justify-between font-normal",
|
"w-full justify-between font-normal",
|
||||||
editNode ? "input-edit-node" : "py-2",
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span
|
<span className="truncate" data-testid={`value-dropdown-${id}`}>
|
||||||
className="truncate"
|
|
||||||
data-testid={`value-dropdown-` + id}
|
|
||||||
>
|
|
||||||
{value &&
|
{value &&
|
||||||
value !== "" &&
|
value !== "" &&
|
||||||
filteredOptions.find((option) => option === value)
|
filteredOptions.find((option) => option === value)
|
||||||
? filteredOptions.find((option) => option === value)
|
? filteredOptions.find((option) => option === value)
|
||||||
: "Choose an option..."}
|
: "Choose an option..."}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ForwardedIconComponent
|
<ForwardedIconComponent
|
||||||
name="ChevronsUpDown"
|
name="ChevronsUpDown"
|
||||||
className="ml-2 h-4 w-4 shrink-0 opacity-50"
|
className="ml-2 h-4 w-4 shrink-0 opacity-50"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
)}
|
);
|
||||||
<PopoverContentDropdown
|
|
||||||
side="bottom"
|
const renderSearchInput = () => (
|
||||||
avoidCollisions={!!children}
|
|
||||||
className="noflow nowheel nopan nodelete nodrag p-0"
|
|
||||||
style={
|
|
||||||
children
|
|
||||||
? {}
|
|
||||||
: { minWidth: refButton?.current?.clientWidth ?? "200px" }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Command>
|
|
||||||
<div className="flex items-center border-b px-3">
|
<div className="flex items-center border-b px-3">
|
||||||
<ForwardedIconComponent
|
<ForwardedIconComponent
|
||||||
name="search"
|
name="search"
|
||||||
|
|
@ -134,32 +113,26 @@ export default function Dropdown({
|
||||||
className="flex h-9 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderOptionsList = () => (
|
||||||
<CommandList>
|
<CommandList>
|
||||||
<CommandEmpty>No values found.</CommandEmpty>
|
<CommandEmpty>No values found.</CommandEmpty>
|
||||||
<CommandGroup defaultChecked={false}>
|
<CommandGroup defaultChecked={false}>
|
||||||
{filteredOptions?.map((option, id) => (
|
{filteredOptions?.map((option, index) => (
|
||||||
<ShadTooltip
|
<ShadTooltip key={index} delayDuration={700} content={option}>
|
||||||
delayDuration={700}
|
|
||||||
key={id}
|
|
||||||
content={option}
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
<CommandItem
|
<CommandItem
|
||||||
key={id}
|
|
||||||
value={option}
|
value={option}
|
||||||
onSelect={(currentValue) => {
|
onSelect={(currentValue) => {
|
||||||
onSelect(currentValue);
|
onSelect(currentValue);
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}}
|
}}
|
||||||
className="items-center overflow-hidden truncate"
|
className="items-center overflow-hidden truncate"
|
||||||
data-testid={`${option}-${id ?? ""}-option`}
|
data-testid={`${option}-${index}-option`}
|
||||||
>
|
>
|
||||||
{customValue === option ? (
|
{customValue === option && (
|
||||||
<span className="text-muted-foreground">
|
<span className="text-muted-foreground">Text: </span>
|
||||||
Text:
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
)}
|
||||||
<span className="truncate">{option}</span>
|
<span className="truncate">{option}</span>
|
||||||
<ForwardedIconComponent
|
<ForwardedIconComponent
|
||||||
|
|
@ -175,25 +148,46 @@ export default function Dropdown({
|
||||||
))}
|
))}
|
||||||
</CommandGroup>
|
</CommandGroup>
|
||||||
</CommandList>
|
</CommandList>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderPopoverContent = () => (
|
||||||
|
<PopoverContentDropdown
|
||||||
|
side="bottom"
|
||||||
|
avoidCollisions={!!children}
|
||||||
|
className="noflow nowheel nopan nodelete nodrag p-0"
|
||||||
|
style={
|
||||||
|
children ? {} : { minWidth: refButton?.current?.clientWidth ?? "200px" }
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Command>
|
||||||
|
{renderSearchInput()}
|
||||||
|
{renderOptionsList()}
|
||||||
</Command>
|
</Command>
|
||||||
</PopoverContentDropdown>
|
</PopoverContentDropdown>
|
||||||
</Popover>
|
);
|
||||||
</>
|
|
||||||
|
if (Object.keys(options).length === 0 && !combobox) {
|
||||||
|
return isLoading ? (
|
||||||
|
<div>
|
||||||
|
<span className="text-sm italic">Loading...</span>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
|
||||||
{(!isLoading && (
|
|
||||||
<div>
|
<div>
|
||||||
<span className="text-sm italic">
|
<span className="text-sm italic">
|
||||||
No parameters are available for display.
|
No parameters are available for display.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)) || (
|
);
|
||||||
<div>
|
}
|
||||||
<span className="text-sm italic">Loading...</span>
|
|
||||||
</div>
|
return (
|
||||||
)}
|
<Popover open={open} onOpenChange={children ? () => {} : setOpen}>
|
||||||
</>
|
{children ? (
|
||||||
)}
|
<PopoverAnchor>{children}</PopoverAnchor>
|
||||||
</>
|
) : (
|
||||||
|
renderTriggerButton()
|
||||||
|
)}
|
||||||
|
{renderPopoverContent()}
|
||||||
|
</Popover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,19 @@ export default function FloatComponent({
|
||||||
}
|
}
|
||||||
}, [disabled]);
|
}, [disabled]);
|
||||||
|
|
||||||
|
const handleInput = (event: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
|
const inputValue = Number(event.target.value);
|
||||||
|
if (inputValue < min) {
|
||||||
|
event.target.value = min.toString();
|
||||||
|
} else if (inputValue > max) {
|
||||||
|
event.target.value = max.toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
onChange(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Input
|
<Input
|
||||||
|
|
@ -28,25 +41,14 @@ export default function FloatComponent({
|
||||||
type="number"
|
type="number"
|
||||||
step={step}
|
step={step}
|
||||||
min={min}
|
min={min}
|
||||||
onInput={(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
if (Number(event.target.value) < min) {
|
|
||||||
event.target.value = min.toString();
|
|
||||||
}
|
|
||||||
if (Number(event.target.value) > max) {
|
|
||||||
event.target.value = max.toString();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
max={max}
|
max={max}
|
||||||
value={value ?? ""}
|
value={value ?? ""}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className={editNode ? "input-edit-node" : ""}
|
className={editNode ? "input-edit-node" : ""}
|
||||||
placeholder={`Enter a value`}
|
placeholder="Enter a value"
|
||||||
onChange={(event) => {
|
onInput={handleInput}
|
||||||
onChange(event.target.value);
|
onChange={handleChange}
|
||||||
}}
|
onKeyDown={(e) => handleKeyDown(e, value, "")}
|
||||||
onKeyDown={(e) => {
|
|
||||||
handleKeyDown(e, value, "");
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,36 @@ export default function InputListComponent({
|
||||||
|
|
||||||
if (!value?.length) value = [""];
|
if (!value?.length) value = [""];
|
||||||
|
|
||||||
|
const handleInputChange = (index, newValue) => {
|
||||||
|
const newInputList = _.cloneDeep(value);
|
||||||
|
newInputList[index] = newValue;
|
||||||
|
onChange(newInputList);
|
||||||
|
};
|
||||||
|
|
||||||
|
const addNewInput = (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const newInputList = _.cloneDeep(value);
|
||||||
|
newInputList.push("");
|
||||||
|
onChange(newInputList);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeInput = (index, e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
const newInputList = _.cloneDeep(value);
|
||||||
|
newInputList.splice(index, 1);
|
||||||
|
onChange(newInputList);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getButtonClassName = () =>
|
||||||
|
classNames(
|
||||||
|
disabled || playgroundDisabled
|
||||||
|
? "cursor-not-allowed text-muted-foreground"
|
||||||
|
: "text-primary hover:text-accent-foreground",
|
||||||
|
);
|
||||||
|
|
||||||
|
const getTestId = (type, index) =>
|
||||||
|
`input-list-${type}-btn${editNode ? "-edit" : ""}_${componentName}-${index}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
|
@ -36,72 +66,31 @@ export default function InputListComponent({
|
||||||
"flex w-full flex-col gap-3",
|
"flex w-full flex-col gap-3",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{value.map((singleValue, idx) => {
|
{value.map((singleValue, index) => (
|
||||||
return (
|
<div key={index} className="flex w-full gap-3">
|
||||||
<div key={idx} className="flex w-full gap-3">
|
|
||||||
<Input
|
<Input
|
||||||
disabled={disabled || playgroundDisabled}
|
disabled={disabled || playgroundDisabled}
|
||||||
type="text"
|
type="text"
|
||||||
value={singleValue}
|
value={singleValue}
|
||||||
className={editNode ? "input-edit-node" : ""}
|
className={editNode ? "input-edit-node" : ""}
|
||||||
placeholder="Type something..."
|
placeholder="Type something..."
|
||||||
onChange={(event) => {
|
onChange={(event) => handleInputChange(index, event.target.value)}
|
||||||
let newInputList = _.cloneDeep(value);
|
data-testid={`${id}_${index}`}
|
||||||
newInputList[idx] = event.target.value;
|
|
||||||
onChange(newInputList);
|
|
||||||
}}
|
|
||||||
data-testid={`${id}_` + idx}
|
|
||||||
/>
|
/>
|
||||||
{idx === 0 ? (
|
|
||||||
<Button
|
<Button
|
||||||
unstyled
|
unstyled
|
||||||
className={cn(
|
className={getButtonClassName()}
|
||||||
disabled || playgroundDisabled
|
onClick={index === 0 ? addNewInput : (e) => removeInput(index, e)}
|
||||||
? "cursor-not-allowed text-muted-foreground"
|
data-testid={getTestId(index === 0 ? "plus" : "minus", index)}
|
||||||
: "text-primary hover:text-accent-foreground",
|
|
||||||
)}
|
|
||||||
onClick={(e) => {
|
|
||||||
let newInputList = _.cloneDeep(value);
|
|
||||||
newInputList.push("");
|
|
||||||
onChange(newInputList);
|
|
||||||
e.preventDefault();
|
|
||||||
}}
|
|
||||||
data-testid={
|
|
||||||
`input-list-plus-btn${
|
|
||||||
editNode ? "-edit" : ""
|
|
||||||
}_${componentName}-` + idx
|
|
||||||
}
|
|
||||||
disabled={disabled || playgroundDisabled}
|
disabled={disabled || playgroundDisabled}
|
||||||
>
|
>
|
||||||
<IconComponent name="Plus" className="h-4 w-4" />
|
<IconComponent
|
||||||
|
name={index === 0 ? "Plus" : "X"}
|
||||||
|
className="h-4 w-4"
|
||||||
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
) : (
|
|
||||||
<Button
|
|
||||||
unstyled
|
|
||||||
className={cn(
|
|
||||||
disabled || playgroundDisabled
|
|
||||||
? "cursor-not-allowed text-muted-foreground"
|
|
||||||
: "text-primary hover:text-accent-foreground",
|
|
||||||
)}
|
|
||||||
data-testid={
|
|
||||||
`input-list-minus-btn${
|
|
||||||
editNode ? "-edit" : ""
|
|
||||||
}_${componentName}-` + idx
|
|
||||||
}
|
|
||||||
onClick={(e) => {
|
|
||||||
let newInputList = _.cloneDeep(value);
|
|
||||||
newInputList.splice(idx, 1);
|
|
||||||
onChange(newInputList);
|
|
||||||
e.preventDefault();
|
|
||||||
}}
|
|
||||||
disabled={disabled || playgroundDisabled}
|
|
||||||
>
|
|
||||||
<IconComponent name="X" className="h-4 w-4" />
|
|
||||||
</Button>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
))}
|
||||||
})}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,36 +38,57 @@ export default function IntComponent({
|
||||||
onChange(Number(e.target.value));
|
onChange(Number(e.target.value));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getStepValue = () => {
|
||||||
|
return (Number.isInteger(rangeSpec?.step) ? rangeSpec.step : 1) ?? 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMinValue = () => {
|
||||||
|
return rangeSpec?.min ?? min;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getMaxValue = () => {
|
||||||
|
return rangeSpec?.max ?? undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInputClassName = () => {
|
||||||
|
return cn(
|
||||||
|
editNode ? "input-edit-node" : "",
|
||||||
|
"nopan nodelete nodrag noflow primary-input",
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleNumberChange = (newValue) => {
|
||||||
|
onChange(Number(newValue));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleInputChange = (event) => {
|
||||||
|
const inputValue = Number(event.target.value);
|
||||||
|
if (inputValue < getMinValue()) {
|
||||||
|
event.target.value = getMinValue().toString();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const inputRef = useRef(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<NumberInput
|
<NumberInput
|
||||||
id={id}
|
id={id}
|
||||||
step={(Number.isInteger(rangeSpec?.step) ? rangeSpec?.step : 1) ?? 1}
|
step={getStepValue()}
|
||||||
min={rangeSpec?.min ?? min}
|
min={getMinValue()}
|
||||||
max={rangeSpec?.max ?? undefined}
|
max={getMaxValue()}
|
||||||
onChange={(value) => {
|
onChange={handleNumberChange}
|
||||||
onChange(Number(value));
|
|
||||||
}}
|
|
||||||
value={value ?? ""}
|
value={value ?? ""}
|
||||||
>
|
>
|
||||||
<NumberInputField
|
<NumberInputField
|
||||||
className={cn(
|
className={getInputClassName()}
|
||||||
editNode ? "input-edit-node" : "",
|
|
||||||
"nopan nodelete nodrag noflow primary-input",
|
|
||||||
)}
|
|
||||||
onChange={handleChangeInput}
|
onChange={handleChangeInput}
|
||||||
onKeyDown={(event) => {
|
onKeyDown={(event) => handleKeyDown(event, value, "")}
|
||||||
handleKeyDown(event, value, "");
|
onInput={handleInputChange}
|
||||||
}}
|
|
||||||
onInput={(event: React.ChangeEvent<HTMLInputElement>) => {
|
|
||||||
if (Number(event.target.value) < min) {
|
|
||||||
event.target.value = min.toString();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
placeholder={editNode ? "Integer number" : "Type an integer number"}
|
placeholder={editNode ? "Integer number" : "Type an integer number"}
|
||||||
data-testid={id}
|
data-testid={id}
|
||||||
ref={ref}
|
ref={inputRef}
|
||||||
/>
|
/>
|
||||||
<NumberInputStepper paddingRight={10}>
|
<NumberInputStepper paddingRight={10}>
|
||||||
<NumberIncrementStepper fontSize={8} marginTop={6} />
|
<NumberIncrementStepper fontSize={8} marginTop={6} />
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,6 @@ import {
|
||||||
hasDuplicateKeys,
|
hasDuplicateKeys,
|
||||||
} from "@/utils/reactflowUtils";
|
} from "@/utils/reactflowUtils";
|
||||||
import { cloneDeep } from "lodash";
|
import { cloneDeep } from "lodash";
|
||||||
import { classNames } from "../../utils/utils";
|
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
import { Input } from "../ui/input";
|
import { Input } from "../ui/input";
|
||||||
|
|
||||||
|
|
@ -27,7 +26,7 @@ export default function KeypairListComponent({
|
||||||
|
|
||||||
const [duplicateKey, setDuplicateKey] = useState(false);
|
const [duplicateKey, setDuplicateKey] = useState(false);
|
||||||
|
|
||||||
const myValue =
|
const values =
|
||||||
Object.keys(value || {})?.length === 0 || !value
|
Object.keys(value || {})?.length === 0 || !value
|
||||||
? [{ "": "" }]
|
? [{ "": "" }]
|
||||||
: convertObjToArray(value, "dict");
|
: convertObjToArray(value, "dict");
|
||||||
|
|
@ -43,62 +42,64 @@ export default function KeypairListComponent({
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChangeKey = (event, idx) => {
|
const handleChangeKey = (event, idx) => {
|
||||||
const oldKey = Object.keys(myValue[idx])[0];
|
const oldKey = Object.keys(values[idx])[0];
|
||||||
const updatedObj = { [event.target.value]: myValue[idx][oldKey] };
|
const updatedObj = { [event.target.value]: values[idx][oldKey] };
|
||||||
|
|
||||||
const newValue = cloneDeep(myValue);
|
const newValue = cloneDeep(values);
|
||||||
newValue[idx] = updatedObj;
|
newValue[idx] = updatedObj;
|
||||||
|
|
||||||
handleNewValue(newValue);
|
handleNewValue(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleChangeValue = (event, idx) => {
|
const handleChangeValue = (event, idx) => {
|
||||||
const key = Object.keys(myValue[idx])[0];
|
const key = Object.keys(values[idx])[0];
|
||||||
const updatedObj = { [key]: event.target.value };
|
const updatedObj = { [key]: event.target.value };
|
||||||
|
|
||||||
const newValue = cloneDeep(myValue);
|
const newValue = cloneDeep(values);
|
||||||
newValue[idx] = updatedObj;
|
newValue[idx] = updatedObj;
|
||||||
|
|
||||||
handleNewValue(newValue);
|
handleNewValue(newValue);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const addNewKeyValuePair = () => {
|
||||||
|
const newValues = cloneDeep(values);
|
||||||
|
newValues.push({ "": "" });
|
||||||
|
onChange(newValues);
|
||||||
|
};
|
||||||
|
|
||||||
|
const removeKeyValuePair = (index) => {
|
||||||
|
const newValues = cloneDeep(values);
|
||||||
|
newValues.splice(index, 1);
|
||||||
|
onChange(newValues);
|
||||||
|
};
|
||||||
|
|
||||||
|
const getInputClassName = (isEditNode, isDuplicateKey) => {
|
||||||
|
return `${isEditNode ? "input-edit-node" : ""} ${isDuplicateKey ? "input-invalid" : ""}`.trim();
|
||||||
|
};
|
||||||
|
|
||||||
|
const getTestId = (prefix, index) =>
|
||||||
|
`${editNode ? "editNode" : ""}${prefix}${index}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={`flex h-full flex-col gap-3 ${values?.length > 1 && editNode ? "mx-2 my-1" : ""}`}
|
||||||
myValue?.length > 1 && editNode ? "mx-2 my-1" : "",
|
|
||||||
"flex h-full flex-col gap-3",
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
{myValue?.map((obj, index) => {
|
{values?.map((obj, index) =>
|
||||||
return Object.keys(obj).map((key, idx) => {
|
Object.keys(obj).map((key, idx) => (
|
||||||
return (
|
|
||||||
<div key={idx} className="flex w-full gap-2">
|
<div key={idx} className="flex w-full gap-2">
|
||||||
<Input
|
<Input
|
||||||
data-testid={
|
data-testid={getTestId("keypair", index)}
|
||||||
editNode ? "editNodekeypair" + index : "keypair" + index
|
id={getTestId("keypair", index)}
|
||||||
}
|
|
||||||
id={editNode ? "editNodekeypair" + index : "keypair" + index}
|
|
||||||
type="text"
|
type="text"
|
||||||
value={key.trim()}
|
value={key.trim()}
|
||||||
className={classNames(
|
className={getInputClassName(editNode, duplicateKey)}
|
||||||
editNode ? "input-edit-node" : "",
|
|
||||||
duplicateKey ? "input-invalid" : "",
|
|
||||||
)}
|
|
||||||
placeholder="Type key..."
|
placeholder="Type key..."
|
||||||
onChange={(event) => handleChangeKey(event, index)}
|
onChange={(event) => handleChangeKey(event, index)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Input
|
<Input
|
||||||
data-testid={
|
data-testid={getTestId("keypair", index + 100)}
|
||||||
editNode
|
id={getTestId("keypair", index + 100)}
|
||||||
? "editNodekeypair" + (index + 100).toString()
|
|
||||||
: "keypair" + (index + 100).toString()
|
|
||||||
}
|
|
||||||
id={
|
|
||||||
editNode
|
|
||||||
? "editNodekeypair" + (index + 100).toString()
|
|
||||||
: "keypair" + (index + 100).toString()
|
|
||||||
}
|
|
||||||
type="text"
|
type="text"
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
value={obj[key]}
|
value={obj[key]}
|
||||||
|
|
@ -107,56 +108,34 @@ export default function KeypairListComponent({
|
||||||
onChange={(event) => handleChangeValue(event, index)}
|
onChange={(event) => handleChangeValue(event, index)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{isList && index === myValue.length - 1 ? (
|
{isList &&
|
||||||
|
(index === values.length - 1 ? (
|
||||||
<button
|
<button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
onClick={() => {
|
onClick={addNewKeyValuePair}
|
||||||
let newInputList = cloneDeep(myValue);
|
id={getTestId("plusbtn", index)}
|
||||||
newInputList.push({ "": "" });
|
|
||||||
onChange(newInputList);
|
|
||||||
}}
|
|
||||||
id={
|
|
||||||
editNode
|
|
||||||
? "editNodeplusbtn" + index.toString()
|
|
||||||
: "plusbtn" + index.toString()
|
|
||||||
}
|
|
||||||
data-testid={id}
|
data-testid={id}
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="Plus"
|
name="Plus"
|
||||||
className={"h-4 w-4 hover:text-accent-foreground"}
|
className="h-4 w-4 hover:text-accent-foreground"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
) : isList ? (
|
) : (
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => removeKeyValuePair(index)}
|
||||||
let newInputList = cloneDeep(myValue);
|
data-testid={getTestId("minusbtn", index)}
|
||||||
newInputList.splice(index, 1);
|
id={getTestId("minusbtn", index)}
|
||||||
onChange(newInputList);
|
|
||||||
}}
|
|
||||||
data-testid={
|
|
||||||
editNode
|
|
||||||
? "editNodeminusbtn" + index.toString()
|
|
||||||
: "minusbtn" + index.toString()
|
|
||||||
}
|
|
||||||
id={
|
|
||||||
editNode
|
|
||||||
? "editNodeminusbtn" + index.toString()
|
|
||||||
: "minusbtn" + index.toString()
|
|
||||||
}
|
|
||||||
>
|
>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
name="X"
|
name="X"
|
||||||
className="h-4 w-4 hover:text-status-red"
|
className="h-4 w-4 hover:text-status-red"
|
||||||
/>
|
/>
|
||||||
</button>
|
</button>
|
||||||
) : (
|
))}
|
||||||
""
|
</div>
|
||||||
|
)),
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
});
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -92,14 +92,15 @@ export default function MultiselectComponent({
|
||||||
}
|
}
|
||||||
}, [open]);
|
}, [open]);
|
||||||
|
|
||||||
return (
|
const handleOptionSelect = (currentValue) => {
|
||||||
<>
|
if (value.includes(currentValue)) {
|
||||||
{Object.keys(options ?? [])?.length > 0 || combobox ? (
|
onSelect(value.filter((v) => v !== currentValue));
|
||||||
<>
|
} else {
|
||||||
<Popover open={open} onOpenChange={children ? () => {} : setOpen}>
|
onSelect([...value, currentValue]);
|
||||||
{children ? (
|
}
|
||||||
<PopoverAnchor>{children}</PopoverAnchor>
|
};
|
||||||
) : (
|
|
||||||
|
const renderDropdownTrigger = () => (
|
||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
@ -108,47 +109,28 @@ export default function MultiselectComponent({
|
||||||
role="combobox"
|
role="combobox"
|
||||||
ref={refButton}
|
ref={refButton}
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
data-testid={`${id ?? ""}`}
|
data-testid={id}
|
||||||
className={cn(
|
className={cn(
|
||||||
editNode
|
editNode
|
||||||
? "dropdown-component-outline"
|
? "dropdown-component-outline input-edit-node"
|
||||||
: "dropdown-component-false-outline",
|
: "dropdown-component-false-outline py-2",
|
||||||
"w-full justify-between font-normal",
|
"w-full justify-between font-normal",
|
||||||
editNode ? "input-edit-node" : "py-2",
|
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<span
|
<span className="truncate" data-testid={`value-dropdown-${id}`}>
|
||||||
className="truncate"
|
{value.length > 0 && options.find((option) => value.includes(option))
|
||||||
data-testid={`value-dropdown-` + id}
|
|
||||||
>
|
|
||||||
{value &&
|
|
||||||
value.length > 0 &&
|
|
||||||
options.find((option) => value.includes(option))
|
|
||||||
? value.join(", ")
|
? value.join(", ")
|
||||||
: "Choose an option..."}
|
: "Choose an option..."}
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<ForwardedIconComponent
|
<ForwardedIconComponent
|
||||||
name="ChevronsUpDown"
|
name="ChevronsUpDown"
|
||||||
className="ml-2 h-4 w-4 shrink-0 opacity-50"
|
className="ml-2 h-4 w-4 shrink-0 opacity-50"
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
)}
|
);
|
||||||
<PopoverContentDropdown
|
|
||||||
onOpenAutoFocus={(event) => {
|
const renderSearchInput = () => (
|
||||||
event.preventDefault();
|
|
||||||
}}
|
|
||||||
side="bottom"
|
|
||||||
avoidCollisions={!!children}
|
|
||||||
className="noflow nowheel nopan nodelete nodrag p-0"
|
|
||||||
style={
|
|
||||||
children
|
|
||||||
? {}
|
|
||||||
: { minWidth: refButton?.current?.clientWidth ?? "200px" }
|
|
||||||
}
|
|
||||||
>
|
|
||||||
<Command>
|
|
||||||
<div className="flex items-center border-b px-3">
|
<div className="flex items-center border-b px-3">
|
||||||
<ForwardedIconComponent
|
<ForwardedIconComponent
|
||||||
name="search"
|
name="search"
|
||||||
|
|
@ -157,7 +139,6 @@ export default function MultiselectComponent({
|
||||||
<input
|
<input
|
||||||
onChange={(event) => {
|
onChange={(event) => {
|
||||||
setSearchValue(event.target.value);
|
setSearchValue(event.target.value);
|
||||||
searchRoleByTerm(event.target.value);
|
|
||||||
}}
|
}}
|
||||||
placeholder="Search options..."
|
placeholder="Search options..."
|
||||||
className="flex h-9 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
className="flex h-9 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
|
||||||
|
|
@ -173,48 +154,30 @@ export default function MultiselectComponent({
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderOptionsList = () => (
|
||||||
<CommandList className="overflow-y-scroll">
|
<CommandList className="overflow-y-scroll">
|
||||||
<CommandEmpty>No values found.</CommandEmpty>
|
<CommandEmpty>No values found.</CommandEmpty>
|
||||||
<CommandGroup defaultChecked={false}>
|
<CommandGroup>
|
||||||
{filteredOptions?.map((option, id) => (
|
{filteredOptions.map((option, index) => (
|
||||||
<ShadTooltip
|
<ShadTooltip key={index} delayDuration={700} content={option}>
|
||||||
delayDuration={700}
|
|
||||||
key={id}
|
|
||||||
content={option}
|
|
||||||
>
|
|
||||||
<div>
|
<div>
|
||||||
<CommandItem
|
<CommandItem
|
||||||
key={id}
|
|
||||||
value={option}
|
value={option}
|
||||||
onSelect={(currentValue) => {
|
onSelect={handleOptionSelect}
|
||||||
if (value.includes(currentValue)) {
|
|
||||||
onSelect(
|
|
||||||
value.filter((v) => v !== currentValue),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
onSelect([...value, currentValue]);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
className="items-center overflow-hidden truncate"
|
className="items-center overflow-hidden truncate"
|
||||||
data-testid={`${option}-${id ?? ""}-option`}
|
data-testid={`${option}-${id ?? ""}-option`}
|
||||||
>
|
>
|
||||||
{customValues.includes(option) ||
|
{(customValues.includes(option) || searchValue === option) && (
|
||||||
searchValue === option ? (
|
<span className="text-muted-foreground">Text: </span>
|
||||||
<span className="text-muted-foreground">
|
|
||||||
Text:
|
|
||||||
</span>
|
|
||||||
) : (
|
|
||||||
<></>
|
|
||||||
)}
|
)}
|
||||||
<span className="truncate">{option}</span>
|
<span className="truncate">{option}</span>
|
||||||
<ForwardedIconComponent
|
<ForwardedIconComponent
|
||||||
name="Check"
|
name="Check"
|
||||||
className={cn(
|
className={cn(
|
||||||
"ml-auto h-4 w-4 shrink-0 text-primary",
|
"ml-auto h-4 w-4 shrink-0 text-primary",
|
||||||
value.includes(option)
|
value.includes(option) ? "opacity-100" : "opacity-0",
|
||||||
? "opacity-100"
|
|
||||||
: "opacity-0",
|
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
</CommandItem>
|
</CommandItem>
|
||||||
|
|
@ -223,25 +186,45 @@ export default function MultiselectComponent({
|
||||||
))}
|
))}
|
||||||
</CommandGroup>
|
</CommandGroup>
|
||||||
</CommandList>
|
</CommandList>
|
||||||
</Command>
|
);
|
||||||
</PopoverContentDropdown>
|
|
||||||
</Popover>
|
if (Object.keys(options).length === 0 && !combobox) {
|
||||||
</>
|
return isLoading ? (
|
||||||
|
<div>
|
||||||
|
<span className="text-sm italic">Loading...</span>
|
||||||
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<>
|
|
||||||
{(!isLoading && (
|
|
||||||
<div>
|
<div>
|
||||||
<span className="text-sm italic">
|
<span className="text-sm italic">
|
||||||
No parameters are available for display.
|
No parameters are available for display.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)) || (
|
);
|
||||||
<div>
|
}
|
||||||
<span className="text-sm italic">Loading...</span>
|
|
||||||
</div>
|
return (
|
||||||
)}
|
<Popover open={open} onOpenChange={children ? () => {} : setOpen}>
|
||||||
</>
|
{children ? (
|
||||||
)}
|
<PopoverAnchor>{children}</PopoverAnchor>
|
||||||
</>
|
) : (
|
||||||
|
renderDropdownTrigger()
|
||||||
|
)}
|
||||||
|
<PopoverContentDropdown
|
||||||
|
onOpenAutoFocus={(event) => event.preventDefault()}
|
||||||
|
side="bottom"
|
||||||
|
avoidCollisions={!!children}
|
||||||
|
className="noflow nowheel nopan nodelete nodrag p-0"
|
||||||
|
style={
|
||||||
|
children
|
||||||
|
? {}
|
||||||
|
: { minWidth: refButton?.current?.clientWidth ?? "200px" }
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Command>
|
||||||
|
{renderSearchInput()}
|
||||||
|
{renderOptionsList()}
|
||||||
|
</Command>
|
||||||
|
</PopoverContentDropdown>
|
||||||
|
</Popover>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import PromptModal from "@/modals/promptModal";
|
import PromptModal from "@/modals/promptModal";
|
||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { PromptAreaComponentType } from "../../types/components";
|
import { PromptAreaComponentType } from "../../types/components";
|
||||||
|
import { cn } from "../../utils/utils";
|
||||||
import IconComponent from "../genericIconComponent";
|
import IconComponent from "../genericIconComponent";
|
||||||
import { Button } from "../ui/button";
|
import { Button } from "../ui/button";
|
||||||
|
|
||||||
|
|
@ -21,8 +22,38 @@ export default function PromptAreaComponent({
|
||||||
}
|
}
|
||||||
}, [disabled]);
|
}, [disabled]);
|
||||||
|
|
||||||
|
const renderPromptText = () => (
|
||||||
|
<span
|
||||||
|
id={id}
|
||||||
|
data-testid={id}
|
||||||
|
className={cn(
|
||||||
|
editNode
|
||||||
|
? "input-edit-node input-dialog"
|
||||||
|
: "primary-input text-muted-foreground",
|
||||||
|
disabled && !editNode && "input-disable text-ring",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{value !== "" ? value : "Type your prompt here..."}
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderExternalLinkIcon = () => {
|
||||||
|
if (editNode) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={disabled ? "pointer-events-none w-full" : "w-full"}>
|
<IconComponent
|
||||||
|
id={id}
|
||||||
|
name="ExternalLink"
|
||||||
|
className={cn(
|
||||||
|
"icons-parameters-comp shrink-0",
|
||||||
|
disabled ? "text-ring" : "hover:text-accent-foreground",
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={cn("w-full", disabled && "pointer-events-none")}>
|
||||||
<PromptModal
|
<PromptModal
|
||||||
id={id}
|
id={id}
|
||||||
field_name={field_name}
|
field_name={field_name}
|
||||||
|
|
@ -34,28 +65,8 @@ export default function PromptAreaComponent({
|
||||||
>
|
>
|
||||||
<Button unstyled className="w-full">
|
<Button unstyled className="w-full">
|
||||||
<div className="flex w-full items-center gap-3">
|
<div className="flex w-full items-center gap-3">
|
||||||
<span
|
{renderPromptText()}
|
||||||
id={id}
|
{renderExternalLinkIcon()}
|
||||||
data-testid={id}
|
|
||||||
className={
|
|
||||||
editNode
|
|
||||||
? "input-edit-node input-dialog"
|
|
||||||
: (disabled ? "input-disable text-ring " : "") +
|
|
||||||
" primary-input text-muted-foreground"
|
|
||||||
}
|
|
||||||
>
|
|
||||||
{value !== "" ? value : "Type your prompt here..."}
|
|
||||||
</span>
|
|
||||||
{!editNode && (
|
|
||||||
<IconComponent
|
|
||||||
id={id}
|
|
||||||
name="ExternalLink"
|
|
||||||
className={
|
|
||||||
"icons-parameters-comp shrink-0" +
|
|
||||||
(disabled ? " text-ring" : " hover:text-accent-foreground")
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</Button>
|
</Button>
|
||||||
</PromptModal>
|
</PromptModal>
|
||||||
|
|
|
||||||
|
|
@ -22,65 +22,67 @@ export default function TextAreaComponent({
|
||||||
}
|
}
|
||||||
}, [disabled]);
|
}, [disabled]);
|
||||||
|
|
||||||
return (
|
const renderTextarea = () => (
|
||||||
<div className={"flex w-full items-center" + (disabled ? "" : "")}>
|
|
||||||
<div className="flex w-full items-center gap-3" data-testid={"div-" + id}>
|
|
||||||
<Textarea
|
<Textarea
|
||||||
id={id}
|
id={id}
|
||||||
data-testid={id}
|
data-testid={id}
|
||||||
value={value}
|
value={value}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
"w-full resize-none",
|
||||||
password !== undefined && password && value !== ""
|
password !== undefined && password && value !== ""
|
||||||
? "text-clip password"
|
? "text-clip password"
|
||||||
: "",
|
: "",
|
||||||
editNode ? "input-edit-node" : "",
|
editNode ? "input-edit-node" : "",
|
||||||
password != undefined ? "pr-8" : "",
|
password !== undefined ? "pr-8" : "",
|
||||||
"w-full",
|
|
||||||
"resize-none",
|
|
||||||
)}
|
)}
|
||||||
rows={1}
|
rows={1}
|
||||||
placeholder={"Type something..."}
|
placeholder="Type something..."
|
||||||
onChange={(event) => {
|
onChange={(event) => onChange(event.target.value)}
|
||||||
onChange(event.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderExternalLinkButton = () => (
|
||||||
<ComponentTextModal
|
<ComponentTextModal
|
||||||
changeVisibility={updateVisibility}
|
changeVisibility={updateVisibility}
|
||||||
value={value}
|
value={value}
|
||||||
setValue={(value: string) => {
|
setValue={(value) => onChange(value)}
|
||||||
onChange(value);
|
|
||||||
}}
|
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
password={password}
|
password={password}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={
|
className={classNames(
|
||||||
"flex items-center" + (password ? "relative left-6" : "")
|
"flex items-center",
|
||||||
}
|
password ? "relative left-6" : "",
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<Button unstyled>
|
<Button unstyled>
|
||||||
<IconComponent
|
<IconComponent
|
||||||
strokeWidth={1.5}
|
strokeWidth={1.5}
|
||||||
id={id}
|
id={id}
|
||||||
name="ExternalLink"
|
name="ExternalLink"
|
||||||
className={
|
className={classNames(
|
||||||
"icons-parameters-comp shrink-0" +
|
"icons-parameters-comp shrink-0",
|
||||||
(disabled ? " text-ring" : " hover:text-accent-foreground")
|
disabled ? "text-ring" : "hover:text-accent-foreground",
|
||||||
}
|
)}
|
||||||
/>
|
/>
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</ComponentTextModal>
|
</ComponentTextModal>
|
||||||
{password !== undefined && (
|
);
|
||||||
|
|
||||||
|
const renderPasswordToggle = () => {
|
||||||
|
if (password === undefined) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
<Button
|
<Button
|
||||||
unstyled
|
unstyled
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
"mb-px text-muted-foreground hover:text-current",
|
"side-bar-button-size absolute mb-px text-muted-foreground hover:text-current",
|
||||||
editNode
|
editNode
|
||||||
? "side-bar-button-size absolute bottom-[1.3rem] right-[4.2rem]"
|
? "bottom-[1.3rem] right-[4.2rem]"
|
||||||
: "side-bar-button-size absolute bottom-4 right-[4.2rem]",
|
: "bottom-4 right-[4.2rem]",
|
||||||
)}
|
)}
|
||||||
onClick={(event) => {
|
onClick={(event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
@ -122,7 +124,15 @@ export default function TextAreaComponent({
|
||||||
</svg>
|
</svg>
|
||||||
)}
|
)}
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames("flex w-full items-center", disabled ? "" : "")}>
|
||||||
|
<div className="flex w-full items-center gap-3" data-testid={`div-${id}`}>
|
||||||
|
{renderTextarea()}
|
||||||
|
{renderExternalLinkButton()}
|
||||||
|
{renderPasswordToggle()}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,30 @@
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { cn } from "../../utils/utils";
|
import { cn } from "../../utils/utils";
|
||||||
|
|
||||||
export default function RenameLabel(props) {
|
export default function RenameLabel({
|
||||||
|
value,
|
||||||
|
setValue,
|
||||||
|
className,
|
||||||
|
rename,
|
||||||
|
setRename,
|
||||||
|
}) {
|
||||||
const [internalState, setInternalState] = useState(false);
|
const [internalState, setInternalState] = useState(false);
|
||||||
const [isRename, setIsRename] = props.rename
|
const [componentValue, setComponentValue] = useState(value);
|
||||||
? [props.rename, props.setRename]
|
const [isRename, setIsRename] = rename
|
||||||
|
? [rename, setRename]
|
||||||
: [internalState, setInternalState];
|
: [internalState, setInternalState];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (props.value) setMyValue(props.value);
|
if (value) setComponentValue(value);
|
||||||
}, [props.value]);
|
}, [value]);
|
||||||
|
|
||||||
const [myValue, setMyValue] = useState(props.value);
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isRename) {
|
if (isRename) {
|
||||||
setMyValue(props.value);
|
setComponentValue(value);
|
||||||
document.addEventListener("keydown", (event) => {
|
document.addEventListener("keydown", (event) => {
|
||||||
if (event.key === "Escape") {
|
if (event.key === "Escape") {
|
||||||
setIsRename(false);
|
setIsRename(false);
|
||||||
props.setValue("");
|
setValue("");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (inputRef.current) {
|
if (inputRef.current) {
|
||||||
|
|
@ -52,41 +58,47 @@ export default function RenameLabel(props) {
|
||||||
input.style.width = `${textWidth + 16}px`;
|
input.style.width = `${textWidth + 16}px`;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return (
|
|
||||||
<div>
|
const handleBlur = () => {
|
||||||
{isRename ? (
|
setIsRename(false);
|
||||||
|
if (componentValue !== "") {
|
||||||
|
setValue(componentValue);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleChange = (event) => {
|
||||||
|
setComponentValue(event.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDoubleClick = () => {
|
||||||
|
setIsRename(true);
|
||||||
|
setComponentValue(value);
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderInput = () => (
|
||||||
<input
|
<input
|
||||||
autoFocus
|
|
||||||
ref={inputRef}
|
ref={inputRef}
|
||||||
onInput={resizeInput}
|
onInput={resizeInput}
|
||||||
className={cn(
|
className={cn(
|
||||||
"nopan nodelete nodrag noflow rounded-md bg-transparent px-2 outline-ring hover:outline focus:border-none focus:outline active:outline",
|
"nopan nodelete nodrag noflow rounded-md bg-transparent px-2 outline-ring hover:outline focus:border-none focus:outline active:outline",
|
||||||
props.className,
|
className,
|
||||||
)}
|
)}
|
||||||
onBlur={() => {
|
onBlur={handleBlur}
|
||||||
setIsRename(false);
|
value={componentValue}
|
||||||
if (props.value !== "") {
|
onChange={handleChange}
|
||||||
props.setValue(myValue);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
value={myValue}
|
|
||||||
onChange={(event) => {
|
|
||||||
setMyValue(event.target.value);
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
) : (
|
);
|
||||||
|
|
||||||
|
const renderSpan = () => (
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<span
|
<span
|
||||||
className={cn("truncate px-2 text-left", props.className)}
|
className={cn("truncate px-2 text-left", className)}
|
||||||
onDoubleClick={() => {
|
onDoubleClick={handleDoubleClick}
|
||||||
setIsRename(true);
|
|
||||||
setMyValue(props.value);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{props.value}
|
{value}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
return <div>{isRename ? renderInput() : renderSpan()}</div>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,31 +27,29 @@ export default function DictAreaModal({
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false);
|
||||||
const isDark = useDarkStore((state) => state.dark);
|
const isDark = useDarkStore((state) => state.dark);
|
||||||
const [myValue, setMyValue] = useState(value);
|
const [componentValue, setComponentValue] = useState(value);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setMyValue(value);
|
setComponentValue(value);
|
||||||
}, [value, open]);
|
}, [value, open]);
|
||||||
|
|
||||||
return (
|
const handleSubmit = () => {
|
||||||
<BaseModal
|
if (onChange) {
|
||||||
size="medium-h-full"
|
onChange(componentValue);
|
||||||
open={open}
|
|
||||||
disable={disabled}
|
|
||||||
setOpen={setOpen}
|
|
||||||
onSubmit={
|
|
||||||
onChange
|
|
||||||
? () => {
|
|
||||||
onChange(myValue);
|
|
||||||
setOpen(false);
|
setOpen(false);
|
||||||
}
|
}
|
||||||
: undefined
|
};
|
||||||
}
|
|
||||||
>
|
const handleJsonChange = (edit) => {
|
||||||
<BaseModal.Trigger className="h-full">{children}</BaseModal.Trigger>
|
setComponentValue(edit.src);
|
||||||
<BaseModal.Header
|
};
|
||||||
description={onChange ? CODE_DICT_DIALOG_SUBTITLE : null}
|
|
||||||
>
|
const customizeCopy = (copy) => {
|
||||||
|
navigator.clipboard.writeText(JSON.stringify(copy));
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderHeader = () => (
|
||||||
|
<BaseModal.Header description={onChange ? CODE_DICT_DIALOG_SUBTITLE : null}>
|
||||||
<span className="pr-2">
|
<span className="pr-2">
|
||||||
{onChange ? "Edit Dictionary" : "View Dictionary"}
|
{onChange ? "Edit Dictionary" : "View Dictionary"}
|
||||||
</span>
|
</span>
|
||||||
|
|
@ -61,6 +59,9 @@ export default function DictAreaModal({
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</BaseModal.Header>
|
</BaseModal.Header>
|
||||||
|
);
|
||||||
|
|
||||||
|
const renderContent = () => (
|
||||||
<BaseModal.Content>
|
<BaseModal.Content>
|
||||||
<div className="flex h-full w-full flex-col transition-all">
|
<div className="flex h-full w-full flex-col transition-all">
|
||||||
<JsonView
|
<JsonView
|
||||||
|
|
@ -69,16 +70,25 @@ export default function DictAreaModal({
|
||||||
className={!isDark ? "json-view-white" : "json-view-dark"}
|
className={!isDark ? "json-view-white" : "json-view-dark"}
|
||||||
editable={!!onChange}
|
editable={!!onChange}
|
||||||
enableClipboard
|
enableClipboard
|
||||||
onChange={(edit) => {
|
onChange={handleJsonChange}
|
||||||
setMyValue(edit.src);
|
src={cloneDeep(componentValue)}
|
||||||
}}
|
customizeCopy={customizeCopy}
|
||||||
src={cloneDeep(myValue)}
|
|
||||||
customizeCopy={(copy) => {
|
|
||||||
navigator.clipboard.writeText(JSON.stringify(copy));
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</BaseModal.Content>
|
</BaseModal.Content>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<BaseModal
|
||||||
|
size="medium-h-full"
|
||||||
|
open={open}
|
||||||
|
disable={disabled}
|
||||||
|
setOpen={setOpen}
|
||||||
|
onSubmit={onChange ? handleSubmit : undefined}
|
||||||
|
>
|
||||||
|
<BaseModal.Trigger className="h-full">{children}</BaseModal.Trigger>
|
||||||
|
{renderHeader()}
|
||||||
|
{renderContent()}
|
||||||
<BaseModal.Footer submit={onChange ? { label: "Save" } : undefined} />
|
<BaseModal.Footer submit={onChange ? { label: "Save" } : undefined} />
|
||||||
</BaseModal>
|
</BaseModal>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,8 @@ test("when auto_login is false, admin can CRUD user's and should see just your o
|
||||||
timeout: 30000,
|
timeout: 30000,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await page.waitForTimeout(1000);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
await page.getByText(secondRandomFlowName, { exact: true }).isVisible(),
|
await page.getByText(secondRandomFlowName, { exact: true }).isVisible(),
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue