Modal refactor (#647)

This PR is about the transition from PopupContext to the Radix native
way of handling popups, as well as applying a BaseModal to all of the
modals to improve modularity.
This commit is contained in:
Lucas Oliveira 2023-07-25 08:43:59 -03:00 • committed by GitHub
commit 2d9081403f
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
40 changed files with 2764 additions and 4019 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,3 +1,4 @@
import { cloneDeep } from "lodash";
import React, { useContext, useEffect, useRef, useState } from "react";
import { Handle, Position, useUpdateNodeInternals } from "reactflow";
import ShadTooltip from "../../../../components/ShadTooltipComponent";
@ -13,14 +14,10 @@ import PromptAreaComponent from "../../../../components/promptComponent";
import TextAreaComponent from "../../../../components/textAreaComponent";
import ToggleShadComponent from "../../../../components/toggleShadComponent";
import { MAX_LENGTH_TO_SCROLL_TOOLTIP } from "../../../../constants/constants";
import { PopUpContext } from "../../../../contexts/popUpContext";
import { TabsContext } from "../../../../contexts/tabsContext";
import { typesContext } from "../../../../contexts/typesContext";
import { ParameterComponentType } from "../../../../types/components";
import {
cleanEdges,
isValidConnection,
} from "../../../../utils/reactflowUtils";
import { isValidConnection } from "../../../../utils/reactflowUtils";
import {
nodeColors,
nodeIconsLucide,
@ -36,6 +33,7 @@ export default function ParameterComponent({
left,
id,
data,
setData,
tooltipTitle,
title,
color,
@ -51,7 +49,6 @@ export default function ParameterComponent({
const infoHtml = useRef(null);
const updateNodeInternals = useUpdateNodeInternals();
const [position, setPosition] = useState(0);
const { closePopUp } = useContext(PopUpContext);
const { setTabsState, tabId, save } = useContext(TabsContext);
// Update component position
@ -66,15 +63,16 @@ export default function ParameterComponent({
updateNodeInternals(data.id);
}, [data.id, position, updateNodeInternals]);
useEffect(() => {}, [closePopUp, data.node.template]);
const { reactFlowInstance } = useContext(typesContext);
let disabled =
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
const [myData, setMyData] = useState(useContext(typesContext).data);
const { data: myData } = useContext(typesContext);
const handleOnNewValue = (newValue: any) => {
data.node.template[name].value = newValue;
let newData = cloneDeep(data);
newData.node.template[name].value = newValue;
setData(newData);
// Set state to pending
setTabsState((prev) => {
return {
@ -244,7 +242,6 @@ export default function ParameterComponent({
) : (
<InputComponent
disabled={disabled}
disableCopyPaste={true}
password={data.node.template[name].password ?? false}
value={data.node.template[name].value ?? ""}
onChange={handleOnNewValue}
@ -266,7 +263,6 @@ export default function ParameterComponent({
<div className="mt-2 w-full">
<FloatComponent
disabled={disabled}
disableCopyPaste={true}
value={data.node.template[name].value ?? ""}
onChange={handleOnNewValue}
/>
@ -311,7 +307,6 @@ export default function ParameterComponent({
<div className="mt-2 w-full">
<IntComponent
disabled={disabled}
disableCopyPaste={true}
value={data.node.template[name].value ?? ""}
onChange={handleOnNewValue}
/>
@ -322,15 +317,6 @@ export default function ParameterComponent({
field_name={name}
setNodeClass={(nodeClass) => {
data.node = nodeClass;
if (reactFlowInstance) {
cleanEdges({
flow: {
edges: reactFlowInstance.getEdges(),
nodes: reactFlowInstance.getNodes(),
},
updateEdge: (edge) => reactFlowInstance.setEdges(edge),
});
}
}}
nodeClass={data.node}
disabled={disabled}

View file

@ -1,31 +1,33 @@
import { cloneDeep } from "lodash";
import { useContext, useEffect, useRef, useState } from "react";
import { NodeToolbar } from "reactflow";
import { NodeToolbar, useUpdateNodeInternals } from "reactflow";
import ShadTooltip from "../../components/ShadTooltipComponent";
import Tooltip from "../../components/TooltipComponent";
import IconComponent from "../../components/genericIconComponent";
import { useSSE } from "../../contexts/SSEContext";
import { alertContext } from "../../contexts/alertContext";
import { PopUpContext } from "../../contexts/popUpContext";
import { TabsContext } from "../../contexts/tabsContext";
import { typesContext } from "../../contexts/typesContext";
import NodeModal from "../../modals/NodeModal";
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
import { NodeDataType } from "../../types/flow";
import { cleanEdges } from "../../utils/reactflowUtils";
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
import { classNames, toTitleCase } from "../../utils/utils";
import ParameterComponent from "./components/parameterComponent";
export default function GenericNode({
data,
data: olddata,
selected,
}: {
data: NodeDataType;
selected: boolean;
}) {
const [data, setData] = useState(olddata);
const { setErrorData } = useContext(alertContext);
const { updateFlow, flows, tabId } = useContext(TabsContext);
const updateNodeInternals = useUpdateNodeInternals();
const showError = useRef(true);
const { types, deleteNode } = useContext(typesContext);
const { closePopUp, openPopUp } = useContext(PopUpContext);
const { types, deleteNode, reactFlowInstance } = useContext(typesContext);
// any to avoid type conflict
const Icon: any =
nodeIconsLucide[data.type] || nodeIconsLucide[types[data.type]];
@ -33,7 +35,26 @@ export default function GenericNode({
const [validationStatus, setValidationStatus] = useState(null);
// State for outline color
const { sseData, isBuilding } = useSSE();
const refHtml = useRef(null);
useEffect(() => {
olddata.node = data.node;
let myFlow = flows.find((flow) => flow.id === tabId);
if (reactFlowInstance && myFlow) {
let flow = cloneDeep(myFlow);
flow.data = reactFlowInstance.toObject();
cleanEdges({
flow: {
edges: flow.data.edges,
nodes: flow.data.nodes,
},
updateEdge: (edge) => {
flow.data.edges = edge;
reactFlowInstance.setEdges(edge);
updateNodeInternals(data.id);
},
});
updateFlow(flow);
}
}, [data]);
// New useEffect to watch for changes in sseData and update validation status
useEffect(() => {
@ -58,13 +79,12 @@ export default function GenericNode({
deleteNode(data.id);
return;
}
useEffect(() => {}, [closePopUp, data.node.template]);
return (
<>
<NodeToolbar>
<NodeToolbarComponent
data={data}
openPopUp={openPopUp}
setData={setData}
deleteNode={deleteNode}
></NodeToolbarComponent>
</NodeToolbar>
@ -90,15 +110,6 @@ export default function GenericNode({
</ShadTooltip>
</div>
</div>
<div className="round-button-div">
<button
className="relative"
onClick={(event) => {
event.preventDefault();
openPopUp(<NodeModal data={data} />);
}}
></button>
</div>
<div className="round-button-div">
<div>
<Tooltip
@ -168,6 +179,7 @@ export default function GenericNode({
!data.node.template[t].advanced ? (
<ParameterComponent
data={data}
setData={setData}
color={
nodeColors[types[data.node.template[t].type]] ??
nodeColors[data.node.template[t].type] ??
@ -214,6 +226,7 @@ export default function GenericNode({
</div>
<ParameterComponent
data={data}
setData={setData}
color={nodeColors[types[data.type]] ?? nodeColors.unknown}
title={
data.node.output_types && data.node.output_types.length > 0

View file

@ -7,7 +7,7 @@ type InputProps = {
name: string | null;
description: string | null;
maxLength?: number;
flows: Array<{ id: string; name: string }>;
flows: Array<{ id: string; name: string; description: string }>;
tabId: string;
setName: (name: string) => void;
setDescription: (description: string) => void;
@ -37,7 +37,13 @@ export const EditFlowSettings: React.FC<InputProps> = ({
setName(value);
};
const [desc, setDesc] = useState(
flows.find((f) => f.id === tabId).description
);
const handleDescriptionChange = (event: ChangeEvent<HTMLTextAreaElement>) => {
flows.find((f) => f.id === tabId).description = event.target.value;
setDesc(flows.find((f) => f.id === tabId).description);
setDescription(event.target.value);
};
@ -51,7 +57,7 @@ export const EditFlowSettings: React.FC<InputProps> = ({
)}
</div>
<Input
className="mt-2 font-normal"
className="nopan nodrag noundo nocopy mt-2 font-normal"
onChange={handleNameChange}
type="text"
name="name"
@ -62,12 +68,15 @@ export const EditFlowSettings: React.FC<InputProps> = ({
/>
</Label>
<Label>
<span className="font-medium">Description (optional)</span>
<div className="edit-flow-arrangement mt-3">
<span className="font-medium ">Description (optional)</span>
</div>
<Textarea
name="description"
id="description"
onChange={handleDescriptionChange}
value={description ?? ""}
value={desc}
placeholder="Flow description"
className="mt-2 max-h-[100px] font-normal"
rows={3}

View file

@ -1,5 +1,4 @@
import { useContext, useEffect, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import { useEffect, useState } from "react";
import CodeAreaModal from "../../modals/codeAreaModal";
import { TextAreaComponentType } from "../../types/components";
@ -16,7 +15,6 @@ export default function CodeAreaComponent({
const [myValue, setMyValue] = useState(
typeof value == "string" ? value : JSON.stringify(value)
);
const { openPopUp } = useContext(PopUpContext);
useEffect(() => {
if (disabled) {
setMyValue("");
@ -30,45 +28,26 @@ export default function CodeAreaComponent({
return (
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
<div className="flex w-full items-center">
<span
onClick={() => {
openPopUp(
<CodeAreaModal
value={myValue}
nodeClass={nodeClass}
setNodeClass={setNodeClass}
setValue={(t: string) => {
setMyValue(t);
onChange(t);
}}
/>
);
}}
className={
editNode
? "input-edit-node input-dialog"
: (disabled ? " input-disable input-ring " : "") +
" input-primary text-muted-foreground "
}
>
{myValue !== "" ? myValue : "Type something..."}
</span>
<button
onClick={() => {
openPopUp(
<CodeAreaModal
setNodeClass={setNodeClass}
value={myValue}
nodeClass={nodeClass}
setValue={(t: string) => {
setMyValue(t);
onChange(t);
}}
/>
);
}}
>
<CodeAreaModal
value={myValue}
nodeClass={nodeClass}
setNodeClass={setNodeClass}
setValue={(t: string) => {
setMyValue(t);
onChange(t);
}}
>
<div className="flex w-full items-center">
<span
className={
editNode
? "input-edit-node input-dialog"
: (disabled ? " input-disable input-ring " : "") +
" input-primary text-muted-foreground "
}
>
{myValue !== "" ? myValue : "Type something..."}
</span>
{!editNode && (
<IconComponent
name="ExternalLink"
@ -78,8 +57,8 @@ export default function CodeAreaComponent({
}
/>
)}
</button>
</div>
</div>
</CodeAreaModal>
</div>
);
}

View file

@ -0,0 +1,667 @@
import { cloneDeep } from "lodash";
import { useContext, useEffect, useState } from "react";
import { Prism as SyntaxHighlighter } from "react-syntax-highlighter";
import { oneDark } from "react-syntax-highlighter/dist/cjs/styles/prism";
import AccordionComponent from "../../components/AccordionComponent";
import ShadTooltip from "../../components/ShadTooltipComponent";
import CodeAreaComponent from "../../components/codeAreaComponent";
import Dropdown from "../../components/dropdownComponent";
import FloatComponent from "../../components/floatComponent";
import InputComponent from "../../components/inputComponent";
import InputFileComponent from "../../components/inputFileComponent";
import InputListComponent from "../../components/inputListComponent";
import IntComponent from "../../components/intComponent";
import PromptAreaComponent from "../../components/promptComponent";
import TextAreaComponent from "../../components/textAreaComponent";
import ToggleShadComponent from "../../components/toggleShadComponent";
import {
Table,
TableBody,
TableCell,
TableHead,
TableHeader,
TableRow,
} from "../../components/ui/table";
import {
Tabs,
TabsContent,
TabsList,
TabsTrigger,
} from "../../components/ui/tabs";
import { darkContext } from "../../contexts/darkContext";
import { FlowType } from "../../types/flow/index";
import { classNames } from "../../utils/utils";
import IconComponent from "../genericIconComponent";
export default function CodeTabsComponent({
flow,
tabs,
activeTab,
setActiveTab,
isMessage,
tweaks,
}: {
flow?: FlowType;
tabs: any;
activeTab: string;
setActiveTab: any;
isMessage?: boolean;
tweaks?: {
tweak?: any;
tweaksList?: any;
buildContent?: any;
getValue?: any;
buildTweakObject?: any;
};
}) {
const [isCopied, setIsCopied] = useState<Boolean>(false);
const [data, setData] = useState(flow ? flow["data"]["nodes"] : null);
const [openAccordion, setOpenAccordion] = useState([]);
const { dark } = useContext(darkContext);
useEffect(() => {
if (flow && flow["data"]["nodes"]) {
setData(flow["data"]["nodes"]);
}
}, [flow]);
const copyToClipboard = () => {
if (!navigator.clipboard || !navigator.clipboard.writeText) {
return;
}
navigator.clipboard.writeText(tabs[activeTab].code).then(() => {
setIsCopied(true);
setTimeout(() => {
setIsCopied(false);
}, 2000);
});
};
const downloadAsFile = () => {
const fileExtension = tabs[activeTab].language || ".txt";
const suggestedFileName = `${"generated-code."}${fileExtension}`;
const fileName = window.prompt("Enter the file name.", suggestedFileName);
if (!fileName) {
// user pressed cancel on prompt
return;
}
const blob = new Blob([tabs[activeTab].code], { type: "text/plain" });
const url = URL.createObjectURL(blob);
const link = document.createElement("a");
link.download = fileName;
link.href = url;
link.style.display = "none";
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
URL.revokeObjectURL(url);
};
function openAccordions() {
let accordionsToOpen = [];
tweaks.tweak.current.forEach((el) => {
Object.keys(el).forEach((key) => {
if (Object.keys(el[key]).length > 0) {
accordionsToOpen.push(key);
setOpenAccordion(accordionsToOpen);
}
});
});
if (accordionsToOpen.length == 0) {
setOpenAccordion([]);
}
}
return (
<Tabs
value={activeTab}
className={
"api-modal-tabs " +
(isMessage ? "dark " : "") +
(dark && isMessage ? "bg-background" : "")
}
onValueChange={(value) => {
setActiveTab(value);
if (value === "3") {
openAccordions();
}
}}
>
<div className="api-modal-tablist-div">
<TabsList>
{tabs.map((tab, index) => (
<TabsTrigger
className={
isMessage ? "data-[state=active]:bg-primary-foreground" : ""
}
key={index}
value={index.toString()}
>
{tab.name}
</TabsTrigger>
))}
</TabsList>
{Number(activeTab) < 3 && (
<div className="float-right mx-1 flex gap-2">
<button
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
onClick={copyToClipboard}
>
{isCopied ? (
<IconComponent name="Check" className="h-4 w-4" />
) : (
<IconComponent name="Clipboard" className="h-4 w-4" />
)}
{isCopied ? "Copied!" : "Copy code"}
</button>
<button
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
onClick={downloadAsFile}
>
<IconComponent name="Download" className="h-5 w-5" />
</button>
</div>
)}
</div>
{tabs.map((tab, index) => (
<TabsContent
value={index.toString()}
className="api-modal-tabs-content"
key={index} // Remember to add a unique key prop
>
{index < 3 ? (
<SyntaxHighlighter
className="mt-0 h-full w-full overflow-auto custom-scroll"
language={tab.mode}
style={oneDark}
>
{tab.code}
</SyntaxHighlighter>
) : index === 3 ? (
<>
<div className="api-modal-according-display">
<div
className={classNames(
"h-[70vh] w-full rounded-lg bg-muted",
1 == 1
? "overflow-scroll overflow-x-hidden custom-scroll"
: "overflow-hidden"
)}
>
{data.map((t: any, index) => (
<div className="px-3" key={index}>
{tweaks.tweaksList.current.includes(t["data"]["id"]) && (
<AccordionComponent
trigger={t["data"]["id"]}
open={openAccordion}
keyValue={t["data"]["id"]}
>
<div className="api-modal-table-arrangement">
<Table className="table-fixed bg-muted outline-1">
<TableHeader className="h-10 border-input text-xs font-medium text-ring">
<TableRow className="dark:border-b-muted">
<TableHead className="h-7 text-center">
PARAM
</TableHead>
<TableHead className="h-7 p-0 text-center">
VALUE
</TableHead>
</TableRow>
</TableHeader>
<TableBody className="p-0">
{Object.keys(t["data"]["node"]["template"])
.filter(
(n) =>
n.charAt(0) !== "_" &&
t.data.node.template[n].show &&
(t.data.node.template[n].type === "str" ||
t.data.node.template[n].type ===
"bool" ||
t.data.node.template[n].type ===
"float" ||
t.data.node.template[n].type ===
"code" ||
t.data.node.template[n].type ===
"prompt" ||
t.data.node.template[n].type ===
"file" ||
t.data.node.template[n].type === "int")
)
.map((n, i) => {
return (
<TableRow
key={i}
className="h-10 dark:border-b-muted"
>
<TableCell className="p-0 text-center text-sm text-foreground">
{n}
</TableCell>
<TableCell className="p-0 text-xs text-foreground">
<div className="m-auto w-[250px]">
{t.data.node.template[n].type ===
"str" &&
!t.data.node.template[n].options ? (
<div className="mx-auto">
{t.data.node.template[n]
.list ? (
<InputListComponent
editNode={true}
disabled={false}
value={
!t.data.node.template[n]
.value ||
t.data.node.template[n]
.value === ""
? [""]
: t.data.node.template[
n
].value
}
onChange={(k) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
t["data"]["id"],
k,
t.data.node.template[n]
);
}}
/>
) : t.data.node.template[n]
.multiline ? (
<ShadTooltip
content={tweaks.buildContent(
t.data.node.template[n]
.value
)}
>
<div>
<TextAreaComponent
disabled={false}
editNode={true}
value={
!t.data.node.template[
n
].value ||
t.data.node.template[
n
].value === ""
? ""
: t.data.node
.template[n]
.value
}
onChange={(k) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
t["data"]["id"],
k,
t.data.node
.template[n]
);
}}
/>
</div>
</ShadTooltip>
) : (
<InputComponent
editNode={true}
disabled={false}
password={
t.data.node.template[n]
.password ?? false
}
value={
!t.data.node.template[n]
.value ||
t.data.node.template[n]
.value === ""
? ""
: t.data.node.template[
n
].value
}
onChange={(k) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
t["data"]["id"],
k,
t.data.node.template[n]
);
}}
/>
)}
</div>
) : t.data.node.template[n].type ===
"bool" ? (
<div className="ml-auto">
{" "}
<ToggleShadComponent
enabled={
t.data.node.template[n]
.value
}
setEnabled={(e) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
index
].data.node.template[
n
].value = e;
return newInputList;
});
tweaks.buildTweakObject(
t["data"]["id"],
e,
t.data.node.template[n]
);
}}
size="small"
disabled={false}
/>
</div>
) : t.data.node.template[n].type ===
"file" ? (
<ShadTooltip
content={tweaks.buildContent(
!t.data.node.template[n]
.value ||
t.data.node.template[n]
.value === ""
? ""
: t.data.node.template[n]
.value
)}
>
<div className="mx-auto">
<InputFileComponent
editNode={true}
disabled={false}
value={
t.data.node.template[n]
.value ?? ""
}
onChange={(k: any) => {}}
fileTypes={
t.data.node.template[n]
.fileTypes
}
suffixes={
t.data.node.template[n]
.suffixes
}
onFileChange={(
k: any
) => {}}
></InputFileComponent>
</div>
</ShadTooltip>
) : t.data.node.template[n].type ===
"float" ? (
<div className="mx-auto">
<FloatComponent
disabled={false}
editNode={true}
value={
!t.data.node.template[n]
.value ||
t.data.node.template[n]
.value === ""
? ""
: t.data.node.template[n]
.value
}
onChange={(k) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
t["data"]["id"],
k,
t.data.node.template[n]
);
}}
/>
</div>
) : t.data.node.template[n].type ===
"str" &&
t.data.node.template[n]
.options ? (
<div className="mx-auto">
<Dropdown
editNode={true}
apiModal={true}
options={
t.data.node.template[n]
.options
}
onSelect={(k) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
t["data"]["id"],
k,
t.data.node.template[n]
);
}}
value={
!t.data.node.template[n]
.value ||
t.data.node.template[n]
.value === ""
? ""
: t.data.node.template[n]
.value
}
></Dropdown>
</div>
) : t.data.node.template[n].type ===
"int" ? (
<div className="mx-auto">
<IntComponent
disabled={false}
editNode={true}
value={
!t.data.node.template[n]
.value ||
t.data.node.template[n]
.value === ""
? ""
: t.data.node.template[n]
.value
}
onChange={(k) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
t["data"]["id"],
k,
t.data.node.template[n]
);
}}
/>
</div>
) : t.data.node.template[n].type ===
"prompt" ? (
<ShadTooltip
content={tweaks.buildContent(
!t.data.node.template[n]
.value ||
t.data.node.template[n]
.value === ""
? ""
: t.data.node.template[n]
.value
)}
>
<div className="mx-auto">
<PromptAreaComponent
editNode={true}
disabled={false}
value={
!t.data.node.template[n]
.value ||
t.data.node.template[n]
.value === ""
? ""
: t.data.node.template[
n
].value
}
onChange={(k) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
t["data"]["id"],
k,
t.data.node.template[n]
);
}}
/>
</div>
</ShadTooltip>
) : t.data.node.template[n].type ===
"code" ? (
<ShadTooltip
content={tweaks.buildContent(
tweaks.getValue(
t.data.node.template[n]
.value,
t.data,
t.data.node.template[n]
)
)}
>
<div className="mx-auto">
<CodeAreaComponent
disabled={false}
editNode={true}
value={
!t.data.node.template[n]
.value ||
t.data.node.template[n]
.value === ""
? ""
: t.data.node.template[
n
].value
}
onChange={(k) => {
setData((old) => {
let newInputList =
cloneDeep(old);
newInputList[
index
].data.node.template[
n
].value = k;
return newInputList;
});
tweaks.buildTweakObject(
t["data"]["id"],
k,
t.data.node.template[n]
);
}}
/>
</div>
</ShadTooltip>
) : t.data.node.template[n].type ===
"Any" ? (
"-"
) : (
<div className="hidden"></div>
)}
</div>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</div>
</AccordionComponent>
)}
{tweaks.tweaksList.current.length === 0 && (
<>
<div className="pt-3">
No tweaks are available for this flow.
</div>
</>
)}
</div>
))}
</div>
</div>
</>
) : null}
</TabsContent>
))}
</Tabs>
);
}

View file

@ -1,6 +1,5 @@
import { Listbox, Transition } from "@headlessui/react";
import { Fragment, useContext, useEffect, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import { Fragment, useEffect, useState } from "react";
import { DropDownComponentType } from "../../types/components";
import { classNames } from "../../utils/utils";
import IconComponent from "../genericIconComponent";
@ -13,15 +12,13 @@ export default function Dropdown({
numberOfOptions = 0,
apiModal = false,
}: DropDownComponentType) {
const { closePopUp } = useContext(PopUpContext);
let [internalValue, setInternalValue] = useState(
value === "" || !value ? "Choose an option" : value
);
useEffect(() => {
setInternalValue(value === "" || !value ? "Choose an option" : value);
}, [closePopUp]);
}, [value]);
return (
<>

View file

@ -1,19 +1,12 @@
import { useContext, useEffect, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import { TabsContext } from "../../contexts/tabsContext";
import { useEffect } from "react";
import { FloatComponentType } from "../../types/components";
export default function FloatComponent({
value,
onChange,
disableCopyPaste = false,
disabled,
editNode = false,
}: FloatComponentType) {
const [myValue, setMyValue] = useState(value ?? "");
const { setDisableCopyPaste } = useContext(TabsContext);
const { closePopUp } = useContext(PopUpContext);
const step = 0.1;
const min = 0;
const max = 1;
@ -21,24 +14,13 @@ export default function FloatComponent({
// Clear component state
useEffect(() => {
if (disabled) {
setMyValue("");
onChange("");
}
}, [disabled, onChange]);
useEffect(() => {
setMyValue(value);
}, [closePopUp]);
return (
<div className={"w-full " + (disabled ? "float-component-pointer" : "")}>
<input
onFocus={() => {
if (disableCopyPaste) setDisableCopyPaste(true);
}}
onBlur={() => {
if (disableCopyPaste) setDisableCopyPaste(false);
}}
type="number"
step={step}
min={min}
@ -51,17 +33,17 @@ export default function FloatComponent({
}
}}
max={max}
value={myValue}
value={value ?? ""}
className={
editNode
"nopan nodrag noundo nocopy " +
(editNode
? "input-edit-node"
: "input-primary" + (disabled ? " input-disable " : "")
: "input-primary" + (disabled ? " input-disable " : ""))
}
placeholder={
editNode ? "Number 0 to 1" : "Type a number from zero to one"
}
onChange={(e) => {
setMyValue(e.target.value);
onChange(e.target.value);
}}
/>

View file

@ -1,5 +1,4 @@
import { useContext } from "react";
import { PopUpContext } from "../../../../contexts/popUpContext";
import { useContext, useState } from "react";
import { TabsContext } from "../../../../contexts/tabsContext";
import {
DropdownMenu,
@ -17,10 +16,10 @@ import IconComponent from "../../../genericIconComponent";
import { Button } from "../../../ui/button";
export const MenuBar = ({ flows, tabId }) => {
const { updateFlow, setTabId, addFlow } = useContext(TabsContext);
const { addFlow } = useContext(TabsContext);
const { setErrorData } = useContext(alertContext);
const { openPopUp } = useContext(PopUpContext);
const { undo, redo } = useContext(undoRedoContext);
const [openSettings, setOpenSettings] = useState(false);
const navigate = useNavigate();
@ -62,9 +61,10 @@ export const MenuBar = ({ flows, tabId }) => {
<IconComponent name="Plus" className="header-menu-options" />
New
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
openPopUp(<FlowSettingsModal />);
setOpenSettings(true);
}}
className="cursor-pointer"
>
@ -74,6 +74,7 @@ export const MenuBar = ({ flows, tabId }) => {
/>
Settings
</DropdownMenuItem>
<DropdownMenuItem
onClick={() => {
undo();
@ -94,6 +95,10 @@ export const MenuBar = ({ flows, tabId }) => {
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
<FlowSettingsModal
open={openSettings}
setOpen={setOpenSettings}
></FlowSettingsModal>
</div>
</div>
);

View file

@ -1,56 +1,37 @@
import { useContext, useEffect, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import { TabsContext } from "../../contexts/tabsContext";
import { useEffect, useState } from "react";
import { InputComponentType } from "../../types/components";
import { classNames } from "../../utils/utils";
export default function InputComponent({
value,
onChange,
disableCopyPaste = false,
disabled,
password,
editNode = false,
}: InputComponentType) {
const [myValue, setMyValue] = useState(value ?? "");
const [pwdVisible, setPwdVisible] = useState(false);
const { setDisableCopyPaste } = useContext(TabsContext);
const { closePopUp } = useContext(PopUpContext);
// Clear component state
useEffect(() => {
if (disabled) {
setMyValue("");
onChange("");
}
}, [disabled, onChange]);
useEffect(() => {
setMyValue(value ?? "");
}, [closePopUp]);
return (
<div className={disabled ? "input-component-div" : "relative"}>
<input
value={myValue}
onFocus={() => {
if (disableCopyPaste) setDisableCopyPaste(true);
}}
onBlur={() => {
if (disableCopyPaste) setDisableCopyPaste(false);
}}
value={value}
className={classNames(
disabled ? " input-disable " : "",
password && !pwdVisible && myValue !== ""
? " text-clip password "
: "",
password && !pwdVisible && value !== "" ? " text-clip password " : "",
editNode ? " input-edit-node " : " input-primary ",
password && editNode ? "pr-8" : "",
password && !editNode ? "pr-10" : ""
password && !editNode ? "pr-10" : "",
"nopan nodrag noundo nocopy"
)}
placeholder={password && editNode ? "Key" : "Type something..."}
onChange={(e) => {
setMyValue(e.target.value);
onChange(e.target.value);
}}
/>

View file

@ -1,8 +1,7 @@
import { useContext, useEffect, useState } from "react";
import { useEffect } from "react";
import { InputListComponentType } from "../../types/components";
import _ from "lodash";
import { PopUpContext } from "../../contexts/popUpContext";
import IconComponent from "../genericIconComponent";
export default function InputListComponent({
@ -10,21 +9,12 @@ export default function InputListComponent({
onChange,
disabled,
editNode = false,
onAddInput,
}: InputListComponentType) {
const [inputList, setInputList] = useState(value ?? [""]);
const { closePopUp } = useContext(PopUpContext);
useEffect(() => {
if (disabled) {
setInputList([""]);
onChange([""]);
}
}, [disabled, onChange]);
useEffect(() => {
setInputList(value);
}, [closePopUp]);
}, [disabled]);
return (
<div
@ -33,36 +23,31 @@ export default function InputListComponent({
"flex flex-col gap-3"
}
>
{inputList.map((i, idx) => {
{value.map((i, idx) => {
return (
<div key={idx} className="flex w-full gap-3">
<input
type="text"
value={i}
className={
editNode
"nopan nodrag noundo nocopy " +
(editNode
? "input-edit-node "
: "input-primary " + (disabled ? "input-disable" : "")
: "input-primary " + (disabled ? "input-disable" : ""))
}
placeholder="Type something..."
onChange={(e) => {
setInputList((old) => {
let newInputList = _.cloneDeep(old);
newInputList[idx] = e.target.value;
return newInputList;
});
onChange(inputList);
let newInputList = _.cloneDeep(value);
newInputList[idx] = e.target.value;
onChange(newInputList);
}}
/>
{idx === inputList.length - 1 ? (
{idx === value.length - 1 ? (
<button
onClick={() => {
setInputList((old) => {
let newInputList = _.cloneDeep(old);
newInputList.push("");
return newInputList;
});
onChange(inputList);
let newInputList = _.cloneDeep(value);
newInputList.push("");
onChange(newInputList);
}}
>
<IconComponent
@ -73,12 +58,9 @@ export default function InputListComponent({
) : (
<button
onClick={() => {
setInputList((old) => {
let newInputList = _.cloneDeep(old);
newInputList.splice(idx, 1);
return newInputList;
});
onChange(inputList);
let newInputList = _.cloneDeep(value);
newInputList.splice(idx, 1);
onChange(newInputList);
}}
>
<IconComponent

View file

@ -1,32 +1,21 @@
import { useContext, useEffect, useState } from "react";
import { PopUpContext } from "../../contexts/popUpContext";
import { TabsContext } from "../../contexts/tabsContext";
import { useEffect } from "react";
import { FloatComponentType } from "../../types/components";
export default function IntComponent({
value,
onChange,
disableCopyPaste = false,
disabled,
editNode = false,
}: FloatComponentType) {
const [myValue, setMyValue] = useState(value ?? "");
const { setDisableCopyPaste } = useContext(TabsContext);
const min = 0;
const { closePopUp } = useContext(PopUpContext);
// Clear component state
useEffect(() => {
if (disabled) {
setMyValue("");
onChange("");
}
}, [disabled, onChange]);
useEffect(() => {
setMyValue(value);
}, [closePopUp]);
return (
<div
className={
@ -35,12 +24,6 @@ export default function IntComponent({
}
>
<input
onFocus={() => {
if (disableCopyPaste) setDisableCopyPaste(true);
}}
onBlur={() => {
if (disableCopyPaste) setDisableCopyPaste(false);
}}
onKeyDown={(event) => {
if (
event.key !== "Backspace" &&
@ -67,15 +50,15 @@ export default function IntComponent({
e.target.value = min.toString();
}
}}
value={myValue}
value={value ?? ""}
className={
editNode
"nopan nodrag noundo nocopy " +
(editNode
? " input-edit-node "
: " input-primary " + (disabled ? " input-disable" : "")
: " input-primary " + (disabled ? " input-disable" : ""))
}
placeholder={editNode ? "Integer number" : "Type an integer number"}
onChange={(e) => {
setMyValue(e.target.value);
onChange(e.target.value);
}}
/>

View file

@ -1,8 +1,6 @@
import { useContext, useEffect, useState } from "react";
import { useEffect } from "react";
import { TypeModal } from "../../constants/enums";
import { PopUpContext } from "../../contexts/popUpContext";
import { typesContext } from "../../contexts/typesContext";
import { postValidatePrompt } from "../../controllers/API";
import GenericModal from "../../modals/genericModal";
import { TextAreaComponentType } from "../../types/components";
@ -17,18 +15,13 @@ export default function PromptAreaComponent({
disabled,
editNode = false,
}: TextAreaComponentType) {
const [myValue, setMyValue] = useState(value);
const { openPopUp } = useContext(PopUpContext);
const { reactFlowInstance } = useContext(typesContext);
useEffect(() => {
if (disabled) {
setMyValue("");
onChange("");
}
}, [disabled, onChange]);
}, [disabled]);
useEffect(() => {
setMyValue(value);
if (value !== "" && !editNode) {
postValidatePrompt(field_name, value, nodeClass).then((apiReturn) => {
if (apiReturn.data) {
@ -37,56 +30,32 @@ export default function PromptAreaComponent({
}
});
}
}, [value, reactFlowInstance]);
}, []);
return (
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
<div className="flex w-full items-center">
<span
onClick={() => {
openPopUp(
<GenericModal
type={TypeModal.PROMPT}
value={myValue}
buttonText="Check & Save"
modalTitle="Edit Prompt"
setValue={(t: string) => {
setMyValue(t);
onChange(t);
}}
nodeClass={nodeClass}
setNodeClass={setNodeClass}
/>
);
}}
className={
editNode
? "input-edit-node input-dialog"
: (disabled ? " input-disable text-ring " : "") +
" input-primary text-muted-foreground "
}
>
{myValue !== "" ? myValue : "Type your prompt here"}
</span>
<button
onClick={() => {
openPopUp(
<GenericModal
field_name={field_name}
type={TypeModal.PROMPT}
value={myValue}
buttonText="Check & Save"
modalTitle="Edit Prompt"
setValue={(t: string) => {
setMyValue(t);
onChange(t);
}}
nodeClass={nodeClass}
setNodeClass={setNodeClass}
/>
);
}}
>
<GenericModal
type={TypeModal.PROMPT}
value={value}
buttonText="Check & Save"
modalTitle="Edit Prompt"
setValue={(t: string) => {
onChange(t);
}}
nodeClass={nodeClass}
setNodeClass={setNodeClass}
>
<div className="flex w-full items-center">
<span
className={
editNode
? "input-edit-node input-dialog"
: (disabled ? " input-disable text-ring " : "") +
" input-primary text-muted-foreground "
}
>
{value !== "" ? value : "Type your prompt here..."}
</span>
{!editNode && (
<IconComponent
name="ExternalLink"
@ -96,8 +65,8 @@ export default function PromptAreaComponent({
}
/>
)}
</button>
</div>
</div>
</GenericModal>
</div>
);
}

View file

@ -1,7 +1,5 @@
import { useContext, useEffect, useState } from "react";
import { useEffect } from "react";
import { TypeModal } from "../../constants/enums";
import { PopUpContext } from "../../contexts/popUpContext";
import { TabsContext } from "../../contexts/tabsContext";
import GenericModal from "../../modals/genericModal";
import { TextAreaComponentType } from "../../types/components";
import IconComponent from "../genericIconComponent";
@ -12,71 +10,50 @@ export default function TextAreaComponent({
disabled,
editNode = false,
}: TextAreaComponentType) {
const [myValue, setMyValue] = useState(value);
const { openPopUp, closePopUp } = useContext(PopUpContext);
const { setDisableCopyPaste } = useContext(TabsContext);
// Clear text area
useEffect(() => {
if (disabled) {
setMyValue("");
onChange("");
}
}, [disabled, onChange]);
useEffect(() => {
setMyValue(value);
}, [closePopUp]);
}, [disabled]);
return (
<div className={disabled ? "pointer-events-none w-full " : " w-full"}>
<div className="flex w-full items-center">
<input
value={myValue}
onFocus={() => {
setDisableCopyPaste(true);
}}
onBlur={() => {
setDisableCopyPaste(false);
}}
value={value}
className={
editNode
(editNode
? " input-edit-node "
: " input-primary " + (disabled ? " input-disable" : "")
: " input-primary " + (disabled ? " input-disable" : "")) +
" nopan nodrag noundo nocopy w-full"
}
placeholder={"Type something..."}
onChange={(e) => {
setMyValue(e.target.value);
onChange(e.target.value);
}}
/>
<button
onClick={() => {
openPopUp(
<GenericModal
type={TypeModal.TEXT}
buttonText="Finishing Editing"
modalTitle="Edit Text"
value={myValue}
setValue={(t: string) => {
setMyValue(t);
onChange(t);
}}
<div>
<GenericModal
type={TypeModal.TEXT}
buttonText="Finishing Editing"
modalTitle="Edit Text"
value={value}
setValue={(t: string) => {
onChange(t);
}}
>
{!editNode && (
<IconComponent
name="ExternalLink"
className={
"icons-parameters-comp" +
(disabled ? " text-ring" : " hover:text-accent-foreground")
}
/>
);
}}
>
{!editNode && (
<IconComponent
name="ExternalLink"
className={
"icons-parameters-comp" +
(disabled ? " text-ring" : " hover:text-accent-foreground")
}
/>
)}
</button>
)}
</GenericModal>
</div>
</div>
</div>
);

View file

@ -25,6 +25,7 @@ export default function ToggleShadComponent({
scaleX = 1;
scaleY = 1;
}
return (
<div className={disabled ? "pointer-events-none cursor-not-allowed " : ""}>
<Switch

View file

@ -44,7 +44,7 @@ const DialogContent = React.forwardRef<
<DialogPrimitive.Content
ref={ref}
className={cn(
"fixed z-50 grid w-full gap-3 rounded-b-lg border bg-background p-6 shadow-lg animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
"noundo nocopy fixed z-50 flex w-full flex-col gap-3 rounded-b-lg border bg-background p-6 shadow-lg animate-in data-[state=open]:fade-in-90 data-[state=open]:slide-in-from-bottom-10 sm:max-w-lg sm:rounded-lg sm:zoom-in-90 data-[state=open]:sm:slide-in-from-bottom-0",
className
)}
{...props}

View file

@ -10,7 +10,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
<input
type={type}
className={cn(
"flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
"nopan nodrag noundo nocopy flex h-10 w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
className
)}
ref={ref}

View file

@ -57,7 +57,7 @@ export default function RenameLabel(props) {
ref={inputRef}
onInput={resizeInput}
className={cn(
"rounded-md bg-transparent px-2 outline-ring hover:outline focus:border-none focus:outline active:outline",
"nopan nodrag noundo nocopy rounded-md bg-transparent px-2 outline-ring hover:outline focus:border-none focus:outline active:outline",
props.className
)}
onBlur={() => {

View file

@ -13,7 +13,7 @@ const TabsList = React.forwardRef<
<TabsPrimitive.List
ref={ref}
className={cn(
"inline-flex h-10 items-center justify-center rounded-md bg-muted p-1 text-muted-foreground",
"inline-flex h-10 items-center justify-center rounded-md p-1 text-muted-foreground",
className
)}
{...props}

View file

@ -42,8 +42,6 @@ const TabsContextInitialValue: TabsContextType = {
uploadFlow: () => {},
hardReset: () => {},
saveFlow: async (flow: FlowType) => {},
disableCopyPaste: false,
setDisableCopyPaste: (state: boolean) => {},
lastCopiedSelection: null,
setLastCopiedSelection: (selection: any) => {},
tabsState: {},
@ -585,16 +583,12 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}
}
const [disableCopyPaste, setDisableCopyPaste] = useState(false);
return (
<TabsContext.Provider
value={{
saveFlow,
lastCopiedSelection,
setLastCopiedSelection,
disableCopyPaste,
setDisableCopyPaste,
hardReset,
tabId,
setTabId,

Some files were not shown because too many files have changed in this diff Show more