Updated global variables to ShadCN and updated logic to show variables as different things
This commit is contained in:
parent
50d27eeaa0
commit
d003be4fe2
7 changed files with 202 additions and 169 deletions
14
src/frontend/package-lock.json
generated
14
src/frontend/package-lock.json
generated
|
|
@ -42,6 +42,7 @@
|
|||
"base64-js": "^1.5.1",
|
||||
"class-variance-authority": "^0.6.1",
|
||||
"clsx": "^1.2.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"dompurify": "^3.0.5",
|
||||
"esbuild": "^0.17.19",
|
||||
"framer-motion": "^11.0.6",
|
||||
|
|
@ -4797,6 +4798,19 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/cmdk": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.0.0.tgz",
|
||||
"integrity": "sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dialog": "1.0.5",
|
||||
"@radix-ui/react-primitive": "1.0.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/code-block-writer": {
|
||||
"version": "12.0.0",
|
||||
"resolved": "https://registry.npmjs.org/code-block-writer/-/code-block-writer-12.0.0.tgz",
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
"base64-js": "^1.5.1",
|
||||
"class-variance-authority": "^0.6.1",
|
||||
"clsx": "^1.2.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"dompurify": "^3.0.5",
|
||||
"esbuild": "^0.17.19",
|
||||
"framer-motion": "^11.0.6",
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import PromptAreaComponent from "../../../../components/promptComponent";
|
|||
import TextAreaComponent from "../../../../components/textAreaComponent";
|
||||
import ToggleShadComponent from "../../../../components/toggleShadComponent";
|
||||
import { Button } from "../../../../components/ui/button";
|
||||
import { CommandItem } from "../../../../components/ui/command";
|
||||
import { RefreshButton } from "../../../../components/ui/refreshButton";
|
||||
import {
|
||||
INPUT_HANDLER_HOVER,
|
||||
|
|
@ -23,6 +24,7 @@ import {
|
|||
OUTPUT_HANDLER_HOVER,
|
||||
TOOLTIP_EMPTY,
|
||||
} from "../../../../constants/constants";
|
||||
import AddNewVariableButton from "../../../../pages/globalVariablesPage/components/addNewVariableButton";
|
||||
import useAlertStore from "../../../../stores/alertStore";
|
||||
import useFlowStore from "../../../../stores/flowStore";
|
||||
import useFlowsManagerStore from "../../../../stores/flowsManagerStore";
|
||||
|
|
@ -46,7 +48,7 @@ import {
|
|||
nodeIconsLucide,
|
||||
nodeNames,
|
||||
} from "../../../../utils/styleUtils";
|
||||
import { classNames, groupByFamily } from "../../../../utils/utils";
|
||||
import { classNames, cn, groupByFamily } from "../../../../utils/utils";
|
||||
|
||||
export default function ParameterComponent({
|
||||
left,
|
||||
|
|
@ -386,7 +388,7 @@ export default function ParameterComponent({
|
|||
<>
|
||||
<div
|
||||
className={
|
||||
"w-full truncate text-sm flex items-center" +
|
||||
"flex w-full items-center truncate text-sm" +
|
||||
(left ? "" : " text-end")
|
||||
}
|
||||
>
|
||||
|
|
@ -546,33 +548,47 @@ export default function ParameterComponent({
|
|||
password={data.node?.template[name].password ?? false}
|
||||
value={data.node?.template[name].value ?? ""}
|
||||
options={globalVariablesEntries}
|
||||
onChange={(value) => {
|
||||
handleOnNewValue(value);
|
||||
if (globalVariablesEntries.includes(value)) {
|
||||
setNoticeData({
|
||||
title: `the value inserted in ${data.node?.display_name} is a global variable, \n
|
||||
the real value will be update on run`,
|
||||
});
|
||||
setNode(data.id, (oldNode) => {
|
||||
let newNode = cloneDeep(oldNode);
|
||||
newNode.data = {
|
||||
...newNode.data,
|
||||
};
|
||||
newNode.data.node.template[name].load_from_db = true;
|
||||
return newNode;
|
||||
});
|
||||
} else {
|
||||
setNode(data.id, (oldNode) => {
|
||||
let newNode = cloneDeep(oldNode);
|
||||
newNode.data = {
|
||||
...newNode.data,
|
||||
};
|
||||
newNode.data.node.template[name].load_from_db = false;
|
||||
return newNode;
|
||||
});
|
||||
}
|
||||
//mark as global variable
|
||||
}}
|
||||
optionsPlaceholder={"Global Variables"}
|
||||
optionsButton={
|
||||
<AddNewVariableButton>
|
||||
<CommandItem value={"new"}>
|
||||
<IconComponent
|
||||
name="Plus"
|
||||
className={cn("mr-2 h-4 w-4 text-primary")}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
Add New Variable
|
||||
</CommandItem>
|
||||
</AddNewVariableButton>
|
||||
}
|
||||
selectedOption={
|
||||
data?.node?.template[name].load_from_db ?? false
|
||||
? data?.node?.template[name].value
|
||||
: ""
|
||||
}
|
||||
setSelectedOption={(value) => {
|
||||
handleOnNewValue(value);
|
||||
setNode(data.id, (oldNode) => {
|
||||
let newNode = cloneDeep(oldNode);
|
||||
newNode.data = {
|
||||
...newNode.data,
|
||||
};
|
||||
newNode.data.node.template[name].load_from_db =
|
||||
value === "" ? false : true;
|
||||
return newNode;
|
||||
});
|
||||
}}
|
||||
onChange={(value) => {
|
||||
handleOnNewValue(value);
|
||||
setNode(data.id, (oldNode) => {
|
||||
let newNode = cloneDeep(oldNode);
|
||||
newNode.data = {
|
||||
...newNode.data,
|
||||
};
|
||||
newNode.data.node.template[name].load_from_db = false;
|
||||
return newNode;
|
||||
});
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{data.node?.template[name].refresh_button && (
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
import { Listbox, Transition } from "@headlessui/react";
|
||||
import * as Form from "@radix-ui/react-form";
|
||||
import { Fragment, useEffect, useRef, useState } from "react";
|
||||
import AddNewVariableButton from "../../pages/globalVariablesPage/components/addNewVariableButton";
|
||||
import { PopoverAnchor } from "@radix-ui/react-popover";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { InputComponentType } from "../../types/components";
|
||||
import { handleKeyDown } from "../../utils/reactflowUtils";
|
||||
import { classNames, cn } from "../../utils/utils";
|
||||
import IconComponent from "../genericIconComponent";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "../ui/command";
|
||||
import { Input } from "../ui/input";
|
||||
import { Separator } from "../ui/separator";
|
||||
import { Popover, PopoverContentWithoutPortal } from "../ui/popover";
|
||||
|
||||
export default function InputComponent({
|
||||
autoFocus = false,
|
||||
|
|
@ -23,7 +30,11 @@ export default function InputComponent({
|
|||
className,
|
||||
id = "",
|
||||
blurOnEnter = false,
|
||||
selectedOption,
|
||||
setSelectedOption,
|
||||
options = [],
|
||||
optionsPlaceholder = "Search options...",
|
||||
optionsButton,
|
||||
}: InputComponentType): JSX.Element {
|
||||
const [pwdVisible, setPwdVisible] = useState(false);
|
||||
const refInput = useRef<HTMLInputElement>(null);
|
||||
|
|
@ -36,10 +47,6 @@ export default function InputComponent({
|
|||
}
|
||||
}, [disabled]);
|
||||
|
||||
const filteredOptions = options.filter((option) =>
|
||||
option.toLowerCase().includes(value.toLowerCase())
|
||||
);
|
||||
|
||||
function onInputLostFocus(event): void {
|
||||
if (onBlur) onBlur(event);
|
||||
}
|
||||
|
|
@ -81,144 +88,118 @@ export default function InputComponent({
|
|||
</Form.Control>
|
||||
) : (
|
||||
<>
|
||||
<Input
|
||||
id={id}
|
||||
ref={refInput}
|
||||
type="text"
|
||||
onBlur={onInputLostFocus}
|
||||
value={value}
|
||||
autoFocus={autoFocus}
|
||||
disabled={disabled}
|
||||
required={required}
|
||||
className={classNames(
|
||||
password && !pwdVisible && value !== ""
|
||||
? " text-clip password "
|
||||
: "",
|
||||
editNode ? " input-edit-node " : "",
|
||||
password && editNode ? "pr-8" : "",
|
||||
password && !editNode ? "pr-10" : "",
|
||||
className!
|
||||
)}
|
||||
placeholder={password && editNode ? "Key" : placeholder}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
handleKeyDown(e, value, "");
|
||||
if (blurOnEnter && e.key === "Enter") refInput.current?.blur();
|
||||
}}
|
||||
data-testid={editNode ? id + "-edit" : id}
|
||||
/>
|
||||
<Listbox
|
||||
onChange={(val) => {
|
||||
onChange(val);
|
||||
}}
|
||||
>
|
||||
<>
|
||||
<div className={"relative mt-1 "}>
|
||||
<Transition
|
||||
show={showOptions}
|
||||
as={Fragment}
|
||||
leave="transition ease-in duration-100"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<Listbox.Options
|
||||
className={classNames(
|
||||
editNode
|
||||
? "dropdown-component-true-options nowheel custom-scroll"
|
||||
: "dropdown-component-false-options nowheel custom-scroll",
|
||||
false ? "mb-2 w-[250px]" : "absolute w-full"
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-between px-4 pb-3 pt-2 font-semibold">
|
||||
<div className="flex items-center gap-2">
|
||||
<IconComponent name="Globe" className="h-4 w-4" />
|
||||
Global Variables
|
||||
</div>
|
||||
<div>
|
||||
<AddNewVariableButton>
|
||||
<button className="text-muted-foreground hover:text-accent-foreground">
|
||||
<IconComponent name="Plus" className="h-5 w-5" />
|
||||
</button>
|
||||
</AddNewVariableButton>
|
||||
</div>
|
||||
</div>
|
||||
<Separator />
|
||||
{filteredOptions.map((option, id) => (
|
||||
<Listbox.Option
|
||||
<Popover open={showOptions} onOpenChange={setShowOptions}>
|
||||
<PopoverAnchor>
|
||||
<Input
|
||||
id={id}
|
||||
ref={refInput}
|
||||
type="text"
|
||||
onBlur={onInputLostFocus}
|
||||
value={value}
|
||||
autoFocus={autoFocus}
|
||||
disabled={disabled || selectedOption !== ""}
|
||||
onClick={() => {
|
||||
selectedOption !== "" && setShowOptions(true);
|
||||
}}
|
||||
required={required}
|
||||
className={classNames(
|
||||
password && !pwdVisible && value !== ""
|
||||
? " text-clip password "
|
||||
: "",
|
||||
editNode ? " input-edit-node " : "",
|
||||
password && editNode ? "pr-8" : "",
|
||||
password && !editNode ? "pr-10" : "",
|
||||
className!
|
||||
)}
|
||||
placeholder={password && editNode ? "Key" : placeholder}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
onKeyDown={(e) => {
|
||||
handleKeyDown(e, value, "");
|
||||
if (blurOnEnter && e.key === "Enter")
|
||||
refInput.current?.blur();
|
||||
}}
|
||||
data-testid={editNode ? id + "-edit" : id}
|
||||
/>
|
||||
</PopoverAnchor>
|
||||
<PopoverContentWithoutPortal
|
||||
className="nocopy nopan nodelete nodrag noundo p-0"
|
||||
style={{ minWidth: refInput?.current?.clientWidth ?? "200px" }}
|
||||
side="bottom"
|
||||
align="center"
|
||||
>
|
||||
<Command>
|
||||
<CommandInput placeholder={optionsPlaceholder} />
|
||||
<CommandList>
|
||||
<CommandEmpty>No results found.</CommandEmpty>
|
||||
<CommandGroup defaultChecked={false}>
|
||||
{options.map((option, id) => (
|
||||
<CommandItem
|
||||
key={id}
|
||||
className={({ active }) =>
|
||||
classNames(
|
||||
active ? " bg-accent" : "",
|
||||
editNode
|
||||
? "dropdown-component-false-option"
|
||||
: "dropdown-component-true-option",
|
||||
" hover:bg-accent"
|
||||
)
|
||||
}
|
||||
value={option}
|
||||
onSelect={(currentValue) => {
|
||||
setSelectedOption &&
|
||||
setSelectedOption(
|
||||
currentValue === selectedOption
|
||||
? ""
|
||||
: currentValue
|
||||
);
|
||||
setShowOptions(false);
|
||||
}}
|
||||
>
|
||||
{({ selected, active }) => (
|
||||
<>
|
||||
<span
|
||||
className={classNames(
|
||||
selected ? "font-semibold" : "font-normal",
|
||||
"block truncate "
|
||||
)}
|
||||
data-testid={`${option}-${id ?? ""}-option`}
|
||||
>
|
||||
{option}
|
||||
</span>
|
||||
|
||||
{selected ? (
|
||||
<span
|
||||
className={classNames(
|
||||
"dropdown-component-choosal"
|
||||
)}
|
||||
>
|
||||
<IconComponent
|
||||
name="Check"
|
||||
className={
|
||||
"dropdown-component-check-icon text-foreground"
|
||||
}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</span>
|
||||
) : null}
|
||||
</>
|
||||
)}
|
||||
</Listbox.Option>
|
||||
<IconComponent
|
||||
name="Check"
|
||||
className={cn(
|
||||
"mr-2 h-4 w-4 text-primary",
|
||||
selectedOption === option
|
||||
? "opacity-100"
|
||||
: "opacity-0"
|
||||
)}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
{option}
|
||||
</CommandItem>
|
||||
))}
|
||||
</Listbox.Options>
|
||||
</Transition>
|
||||
</div>
|
||||
</>
|
||||
</Listbox>
|
||||
{optionsButton && optionsButton}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContentWithoutPortal>
|
||||
</Popover>
|
||||
<div
|
||||
className={cn(
|
||||
"pointer-events-auto absolute inset-y-0 h-full w-full",
|
||||
selectedOption !== "" ? "" : "hidden"
|
||||
)}
|
||||
onClick={
|
||||
selectedOption !== ""
|
||||
? (e) => {
|
||||
setShowOptions((old) => !old);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
: () => {}
|
||||
}
|
||||
></div>
|
||||
</>
|
||||
)}
|
||||
|
||||
{options.length > 0 && (
|
||||
<span
|
||||
className={cn(
|
||||
password ? "right-8" : "right-0",
|
||||
"absolute inset-y-0 flex items-center pr-2"
|
||||
)}
|
||||
<span
|
||||
className={cn(
|
||||
password ? "right-8" : "right-0",
|
||||
"absolute inset-y-0 flex items-center pr-2"
|
||||
)}
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
className="text-muted-foreground hover:text-accent-foreground"
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
setShowOptions(!showOptions);
|
||||
}}
|
||||
className="text-muted-foreground hover:text-accent-foreground"
|
||||
>
|
||||
<IconComponent
|
||||
name="Globe"
|
||||
className="h-4 w-4"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
</span>
|
||||
)}
|
||||
<IconComponent name="Globe" className="h-4 w-4" aria-hidden="true" />
|
||||
</button>
|
||||
</span>
|
||||
|
||||
{password && (
|
||||
<button
|
||||
|
|
|
|||
|
|
@ -117,7 +117,7 @@ const CommandItem = React.forwardRef<
|
|||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
||||
"relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none aria-selected:bg-accent aria-selected:text-accent-foreground data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -27,4 +27,21 @@ const PopoverContent = React.forwardRef<
|
|||
));
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
||||
|
||||
export { Popover, PopoverContent, PopoverTrigger };
|
||||
const PopoverContentWithoutPortal = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = "center", sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
PopoverContentWithoutPortal.displayName = PopoverPrimitive.Content.displayName;
|
||||
|
||||
export { Popover, PopoverContent, PopoverContentWithoutPortal, PopoverTrigger };
|
||||
|
|
|
|||
|
|
@ -20,7 +20,11 @@ export type InputComponentType = {
|
|||
className?: string;
|
||||
id?: string;
|
||||
blurOnEnter?: boolean;
|
||||
optionsPlaceholder?: string;
|
||||
options?: string[];
|
||||
optionsButton?: ReactElement;
|
||||
selectedOption?: string;
|
||||
setSelectedOption?: (value: string) => void;
|
||||
};
|
||||
export type ToggleComponentType = {
|
||||
enabled: boolean;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue