Merge dev into types_refactor
This commit is contained in:
commit
0d92a62759
69 changed files with 3960 additions and 4502 deletions
|
|
@ -134,6 +134,7 @@ async def stream_build(flow_id: str):
|
|||
# to set the input_keys values
|
||||
artifacts.update(vertex.artifacts)
|
||||
except Exception as exc:
|
||||
logger.exception(exc)
|
||||
params = str(exc)
|
||||
valid = False
|
||||
flow_data_store[flow_id]["status"] = BuildStatus.FAILURE
|
||||
|
|
|
|||
|
|
@ -176,6 +176,8 @@ class Vertex:
|
|||
for node in nodes:
|
||||
built = node.build()
|
||||
if isinstance(built, list):
|
||||
if key not in self.params:
|
||||
self.params[key] = []
|
||||
self.params[key].extend(built)
|
||||
else:
|
||||
self.params[key].append(built)
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class DocumentLoaderVertex(Vertex):
|
|||
self._built_object
|
||||
)
|
||||
return f"""{self.vertex_type}({len(self._built_object)} documents)
|
||||
\nAvg. Document Length (characters): {avg_length}
|
||||
\nAvg. Document Length (characters): {int(avg_length)}
|
||||
Documents: {self._built_object[:3]}..."""
|
||||
return f"{self.vertex_type}()"
|
||||
|
||||
|
|
@ -136,7 +136,7 @@ class TextSplitterVertex(Vertex):
|
|||
self._built_object
|
||||
)
|
||||
return f"""{self.vertex_type}({len(self._built_object)} documents)
|
||||
\nAvg. Document Length (characters): {avg_length}
|
||||
\nAvg. Document Length (characters): {int(avg_length)}
|
||||
\nDocuments: {self._built_object[:3]}..."""
|
||||
return f"{self.vertex_type}()"
|
||||
|
||||
|
|
|
|||
|
|
@ -59,15 +59,20 @@ def setup_static_files(app: FastAPI, static_files_dir: Path):
|
|||
return FileResponse(path)
|
||||
|
||||
|
||||
# app = create_app()
|
||||
# setup_static_files(app, static_files_dir)
|
||||
def get_static_files_dir():
|
||||
"""Get the static files directory relative to Langflow's main.py file."""
|
||||
frontend_path = Path(__file__).parent
|
||||
return frontend_path / "frontend"
|
||||
|
||||
|
||||
def setup_app(static_files_dir: Optional[Path] = None) -> FastAPI:
|
||||
"""Setup the FastAPI app."""
|
||||
# get the directory of the current file
|
||||
if not static_files_dir:
|
||||
frontend_path = Path(__file__).parent
|
||||
static_files_dir = frontend_path / "frontend"
|
||||
static_files_dir = get_static_files_dir()
|
||||
|
||||
if not static_files_dir or not static_files_dir.exists():
|
||||
raise RuntimeError(f"Static files directory {static_files_dir} does not exist.")
|
||||
app = create_app()
|
||||
setup_static_files(app, static_files_dir)
|
||||
return app
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ FORCE_SHOW_FIELDS = [
|
|||
"headers",
|
||||
"max_value_length",
|
||||
"max_tokens",
|
||||
"google_cse_id",
|
||||
]
|
||||
|
||||
DEFAULT_PROMPT = """
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ class TextSplittersFrontendNode(FrontendNode):
|
|||
required=True,
|
||||
show=True,
|
||||
name="documents",
|
||||
is_list=True,
|
||||
)
|
||||
)
|
||||
name = "separator"
|
||||
|
|
|
|||
|
|
@ -259,7 +259,7 @@ class VectorStoreFrontendNode(FrontendNode):
|
|||
field.required = False
|
||||
field.show = True
|
||||
field.advanced = False
|
||||
|
||||
field.is_list = True
|
||||
elif "embedding" in field.name:
|
||||
# for backwards compatibility
|
||||
field.name = "embedding"
|
||||
|
|
|
|||
3511
src/frontend/package-lock.json
generated
3511
src/frontend/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
|
@ -24,6 +24,7 @@
|
|||
"@tabler/icons-react": "^2.18.0",
|
||||
"@tailwindcss/forms": "^0.5.3",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@types/axios": "^0.14.0",
|
||||
"accordion": "^3.0.2",
|
||||
"ace-builds": "^1.16.0",
|
||||
"add": "^2.0.6",
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -1,30 +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 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;
|
||||
}): JSX.Element {
|
||||
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
|
||||
// PROBLEM HERE OTAVIO
|
||||
const Icon: any =
|
||||
|
|
@ -33,7 +36,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 +80,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,7 +111,6 @@ export default function GenericNode({
|
|||
</ShadTooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div className="round-button-div"></div>
|
||||
<div className="round-button-div">
|
||||
<div>
|
||||
<Tooltip
|
||||
|
|
@ -162,6 +182,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] ??
|
||||
|
|
@ -208,6 +229,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
|
||||
|
|
|
|||
|
|
@ -27,7 +27,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);
|
||||
};
|
||||
|
||||
|
|
@ -41,7 +47,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"
|
||||
|
|
@ -52,12 +58,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}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
667
src/frontend/src/components/codeTabsComponent/index.tsx
Normal file
667
src/frontend/src/components/codeTabsComponent/index.tsx
Normal 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>
|
||||
);
|
||||
}
|
||||
|
|
@ -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): JSX.Element {
|
||||
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 (
|
||||
<>
|
||||
|
|
|
|||
|
|
@ -1,19 +1,13 @@
|
|||
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";
|
||||
import { Input } from "../ui/input";
|
||||
|
||||
export default function FloatComponent({
|
||||
value,
|
||||
onChange,
|
||||
disableCopyPaste = false,
|
||||
disabled,
|
||||
editNode = false,
|
||||
}: FloatComponentType): JSX.Element {
|
||||
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 +15,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);
|
||||
}}
|
||||
<div className="w-full">
|
||||
<Input
|
||||
type="number"
|
||||
step={step}
|
||||
min={min}
|
||||
|
|
@ -51,17 +34,13 @@ export default function FloatComponent({
|
|||
}
|
||||
}}
|
||||
max={max}
|
||||
value={myValue}
|
||||
className={
|
||||
editNode
|
||||
? "input-edit-node"
|
||||
: "input-primary" + (disabled ? " input-disable " : "")
|
||||
}
|
||||
value={value ?? ""}
|
||||
disabled={disabled}
|
||||
className={editNode ? "input-edit-node" : ""}
|
||||
placeholder={
|
||||
editNode ? "Number 0 to 1" : "Type a number from zero to one"
|
||||
}
|
||||
onChange={(e) => {
|
||||
setMyValue(e.target.value);
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
@ -18,10 +17,10 @@ import IconComponent from "../../../genericIconComponent";
|
|||
import { Button } from "../../../ui/button";
|
||||
|
||||
export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
|
||||
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();
|
||||
|
||||
|
|
@ -63,9 +62,10 @@ export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
|
|||
<IconComponent name="Plus" className="header-menu-options" />
|
||||
New
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
openPopUp(<FlowSettingsModal />);
|
||||
setOpenSettings(true);
|
||||
}}
|
||||
className="cursor-pointer"
|
||||
>
|
||||
|
|
@ -75,6 +75,7 @@ export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
|
|||
/>
|
||||
Settings
|
||||
</DropdownMenuItem>
|
||||
|
||||
<DropdownMenuItem
|
||||
onClick={() => {
|
||||
undo();
|
||||
|
|
@ -95,6 +96,10 @@ export const MenuBar = ({ flows, tabId }: menuBarPropsType): JSX.Element => {
|
|||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
<FlowSettingsModal
|
||||
open={openSettings}
|
||||
setOpen={setOpenSettings}
|
||||
></FlowSettingsModal>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
import { Input } from "../ui/input";
|
||||
|
||||
export default function InputComponent({
|
||||
value,
|
||||
onChange,
|
||||
disableCopyPaste = false,
|
||||
disabled,
|
||||
password,
|
||||
editNode = false,
|
||||
}: InputComponentType): JSX.Element {
|
||||
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);
|
||||
}}
|
||||
<div className="relative w-full">
|
||||
<Input
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
className={classNames(
|
||||
disabled ? " input-disable " : "",
|
||||
password && !pwdVisible && myValue !== ""
|
||||
? " text-clip password "
|
||||
: "",
|
||||
editNode ? " input-edit-node " : " input-primary ",
|
||||
password && !pwdVisible && value !== "" ? " text-clip password " : "",
|
||||
editNode ? " input-edit-node " : "",
|
||||
password && editNode ? "pr-8" : "",
|
||||
password && !editNode ? "pr-10" : ""
|
||||
)}
|
||||
placeholder={password && editNode ? "Key" : "Type something..."}
|
||||
onChange={(e) => {
|
||||
setMyValue(e.target.value);
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -1,8 +1,9 @@
|
|||
import { useContext, useEffect, useState } from "react";
|
||||
import { useEffect } from "react";
|
||||
import { InputListComponentType } from "../../types/components";
|
||||
|
||||
import { Input } from "../ui/input";
|
||||
import { classNames } from "../../utils/utils";
|
||||
import _ from "lodash";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import IconComponent from "../genericIconComponent";
|
||||
|
||||
export default function InputListComponent({
|
||||
|
|
@ -10,59 +11,42 @@ export default function InputListComponent({
|
|||
onChange,
|
||||
disabled,
|
||||
editNode = false,
|
||||
onAddInput,
|
||||
}: InputListComponentType): JSX.Element {
|
||||
const [inputList, setInputList] = useState(value ?? [""]);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (disabled) {
|
||||
setInputList([""]);
|
||||
onChange([""]);
|
||||
}
|
||||
}, [disabled, onChange]);
|
||||
|
||||
useEffect(() => {
|
||||
setInputList(value);
|
||||
}, [closePopUp]);
|
||||
}, [disabled]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={
|
||||
(disabled ? "pointer-events-none cursor-not-allowed" : "") +
|
||||
"flex flex-col gap-3"
|
||||
}
|
||||
>
|
||||
{inputList.map((i, idx) => {
|
||||
<div
|
||||
className={
|
||||
classNames(
|
||||
value.length > 1 && editNode ? "my-1" : "",
|
||||
"flex flex-col gap-3"
|
||||
)
|
||||
}>
|
||||
{value.map((i, idx) => {
|
||||
return (
|
||||
<div key={idx} className="flex w-full gap-3">
|
||||
<input
|
||||
<Input
|
||||
disabled={disabled}
|
||||
type="text"
|
||||
value={i}
|
||||
className={
|
||||
editNode
|
||||
? "input-edit-node "
|
||||
: "input-primary " + (disabled ? "input-disable" : "")
|
||||
}
|
||||
className={editNode ? "input-edit-node" : ""}
|
||||
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 +57,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
|
||||
|
|
|
|||
|
|
@ -1,46 +1,25 @@
|
|||
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";
|
||||
import { Input } from "../ui/input";
|
||||
|
||||
export default function IntComponent({
|
||||
value,
|
||||
onChange,
|
||||
disableCopyPaste = false,
|
||||
disabled,
|
||||
editNode = false,
|
||||
}: FloatComponentType): JSX.Element {
|
||||
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={
|
||||
"w-full " +
|
||||
(disabled ? "pointer-events-none w-full cursor-not-allowed" : "")
|
||||
}
|
||||
>
|
||||
<input
|
||||
onFocus={() => {
|
||||
if (disableCopyPaste) setDisableCopyPaste(true);
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (disableCopyPaste) setDisableCopyPaste(false);
|
||||
}}
|
||||
<div className="w-full">
|
||||
<Input
|
||||
onKeyDown={(event) => {
|
||||
if (
|
||||
event.key !== "Backspace" &&
|
||||
|
|
@ -67,15 +46,11 @@ export default function IntComponent({
|
|||
e.target.value = min.toString();
|
||||
}
|
||||
}}
|
||||
value={myValue}
|
||||
className={
|
||||
editNode
|
||||
? " input-edit-node "
|
||||
: " input-primary " + (disabled ? " input-disable" : "")
|
||||
}
|
||||
value={value ?? ""}
|
||||
className={editNode ? "input-edit-node" : ""}
|
||||
disabled={disabled}
|
||||
placeholder={editNode ? "Integer number" : "Type an integer number"}
|
||||
onChange={(e) => {
|
||||
setMyValue(e.target.value);
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -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): JSX.Element {
|
||||
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>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
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";
|
||||
import { Input } from "../ui/input";
|
||||
|
||||
export default function TextAreaComponent({
|
||||
value,
|
||||
|
|
@ -12,59 +11,32 @@ export default function TextAreaComponent({
|
|||
disabled,
|
||||
editNode = false,
|
||||
}: TextAreaComponentType): JSX.Element {
|
||||
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);
|
||||
}}
|
||||
className={
|
||||
editNode
|
||||
? " input-edit-node "
|
||||
: " input-primary " + (disabled ? " input-disable" : "")
|
||||
}
|
||||
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 className="flex w-full items-center">
|
||||
<Input
|
||||
value={value}
|
||||
disabled={disabled}
|
||||
className={editNode ? "input-edit-node" : ""}
|
||||
placeholder={"Type something..."}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
<GenericModal
|
||||
type={TypeModal.TEXT}
|
||||
buttonText="Finishing Editing"
|
||||
modalTitle="Edit Text"
|
||||
value={value}
|
||||
setValue={(t: string) => {
|
||||
onChange(t);
|
||||
}}
|
||||
>
|
||||
{!editNode && (
|
||||
|
|
@ -76,7 +48,7 @@ export default function TextAreaComponent({
|
|||
}
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
</GenericModal>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ export default function ToggleShadComponent({
|
|||
scaleX = 1;
|
||||
scaleY = 1;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={disabled ? "pointer-events-none cursor-not-allowed " : ""}>
|
||||
<Switch
|
||||
|
|
|
|||
|
|
@ -56,4 +56,4 @@ const AccordionContent = React.forwardRef<
|
|||
));
|
||||
AccordionContent.displayName = AccordionPrimitive.Content.displayName;
|
||||
|
||||
export { Accordion, AccordionItem, AccordionTrigger, AccordionContent };
|
||||
export { Accordion, AccordionContent, AccordionItem, AccordionTrigger };
|
||||
|
|
|
|||
|
|
@ -77,9 +77,9 @@ CardFooter.displayName = "CardFooter";
|
|||
|
||||
export {
|
||||
Card,
|
||||
CardHeader,
|
||||
CardFooter,
|
||||
CardTitle,
|
||||
CardDescription,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardFooter,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
@ -116,10 +116,10 @@ DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|||
|
||||
export {
|
||||
Dialog,
|
||||
DialogTrigger,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -182,18 +182,18 @@ DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
|
|||
|
||||
export {
|
||||
DropdownMenu,
|
||||
DropdownMenuTrigger,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuCheckboxItem,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuLabel,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuRadioItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuShortcut,
|
||||
DropdownMenuGroup,
|
||||
DropdownMenuPortal,
|
||||
DropdownMenuSub,
|
||||
DropdownMenuSubContent,
|
||||
DropdownMenuSubTrigger,
|
||||
DropdownMenuRadioGroup,
|
||||
DropdownMenuTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -9,10 +9,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
|||
return (
|
||||
<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",
|
||||
className
|
||||
)}
|
||||
className={cn("nopan nodrag noundo nocopy input-primary", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -218,19 +218,19 @@ MenubarShortcut.displayname = "MenubarShortcut";
|
|||
|
||||
export {
|
||||
Menubar,
|
||||
MenubarMenu,
|
||||
MenubarTrigger,
|
||||
MenubarContent,
|
||||
MenubarItem,
|
||||
MenubarSeparator,
|
||||
MenubarLabel,
|
||||
MenubarCheckboxItem,
|
||||
MenubarContent,
|
||||
MenubarGroup,
|
||||
MenubarItem,
|
||||
MenubarLabel,
|
||||
MenubarMenu,
|
||||
MenubarPortal,
|
||||
MenubarRadioGroup,
|
||||
MenubarRadioItem,
|
||||
MenubarPortal,
|
||||
MenubarSeparator,
|
||||
MenubarShortcut,
|
||||
MenubarSub,
|
||||
MenubarSubContent,
|
||||
MenubarSubTrigger,
|
||||
MenubarGroup,
|
||||
MenubarSub,
|
||||
MenubarShortcut,
|
||||
MenubarTrigger,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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={() => {
|
||||
|
|
|
|||
|
|
@ -103,11 +103,11 @@ TableCaption.displayName = "TableCaption";
|
|||
|
||||
export {
|
||||
Table,
|
||||
TableHeader,
|
||||
TableBody,
|
||||
TableCaption,
|
||||
TableCell,
|
||||
TableFooter,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
TableCell,
|
||||
TableCaption,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
@ -51,4 +51,4 @@ const TabsContent = React.forwardRef<
|
|||
));
|
||||
TabsContent.displayName = TabsPrimitive.Content.displayName;
|
||||
|
||||
export { Tabs, TabsList, TabsTrigger, TabsContent };
|
||||
export { Tabs, TabsContent, TabsList, TabsTrigger };
|
||||
|
|
|
|||
|
|
@ -8,10 +8,7 @@ const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
|||
({ className, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
className={cn(
|
||||
"flex min-h-[80px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background 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
|
||||
)}
|
||||
className={cn("nopan nodrag noundo nocopy textarea-primary", className)}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -28,4 +28,4 @@ const TooltipContent = React.forwardRef<
|
|||
));
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||
|
||||
export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
|
||||
export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger };
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -71,18 +71,7 @@ export function TypesProvider({ children }: { children: ReactNode }) {
|
|||
// Clear the interval if successful.
|
||||
clearInterval(intervalId);
|
||||
} catch (error) {
|
||||
retryCount++;
|
||||
// On error, double the delay for the next attempt up to a maximum.
|
||||
delay = Math.min(30000, delay * 2);
|
||||
// Log errors but don't do anything else - the function will try again on the next interval.
|
||||
console.error(error);
|
||||
// Clear the old interval and start a new one with the new delay.
|
||||
if (retryCount <= maxRetryCount) {
|
||||
clearInterval(intervalId);
|
||||
intervalId = setInterval(getTypes, delay);
|
||||
} else {
|
||||
console.error("Max retry attempts reached. Stopping retries.");
|
||||
}
|
||||
console.error("An error has occurred while fetching types.");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
undoRedoContextType,
|
||||
} from "../types/typesContext";
|
||||
import { TabsContext } from "./tabsContext";
|
||||
import { isWrappedWithClass } from "../utils/utils";
|
||||
|
||||
const initialValue = {
|
||||
undo: () => {},
|
||||
|
|
@ -137,17 +138,21 @@ export function UndoRedoProvider({ children }) {
|
|||
}
|
||||
|
||||
const keyDownHandler = (event: KeyboardEvent) => {
|
||||
if (
|
||||
event.key === "z" &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey
|
||||
) {
|
||||
redo();
|
||||
} else if (event.key === "y" && (event.ctrlKey || event.metaKey)) {
|
||||
event.preventDefault(); // prevent the default action
|
||||
redo();
|
||||
} else if (event.key === "z" && (event.ctrlKey || event.metaKey)) {
|
||||
undo();
|
||||
if (!isWrappedWithClass(event, "noundo")) {
|
||||
if (
|
||||
event.key === "z" &&
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.shiftKey
|
||||
) {
|
||||
event.preventDefault();
|
||||
redo();
|
||||
} else if (event.key === "y" && (event.ctrlKey || event.metaKey)) {
|
||||
event.preventDefault(); // prevent the default action
|
||||
redo();
|
||||
} else if (event.key === "z" && (event.ctrlKey || event.metaKey)) {
|
||||
event.preventDefault();
|
||||
undo();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
58
src/frontend/src/controllers/API/api.tsx
Normal file
58
src/frontend/src/controllers/API/api.tsx
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
import axios, { AxiosError, AxiosInstance } from "axios";
|
||||
import { useContext, useEffect, useRef } from "react";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
|
||||
// Create a new Axios instance
|
||||
const api: AxiosInstance = axios.create({
|
||||
baseURL: "",
|
||||
});
|
||||
|
||||
function ApiInterceptor() {
|
||||
const retryCounts = useRef([]);
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
|
||||
useEffect(() => {
|
||||
const interceptor = api.interceptors.response.use(
|
||||
(response) => response,
|
||||
async (error: AxiosError) => {
|
||||
let retryCount = 0;
|
||||
|
||||
while (retryCount < 4) {
|
||||
await sleep(5000); // Sleep for 5 seconds
|
||||
retryCount++;
|
||||
try {
|
||||
const response = await axios.request(error.config);
|
||||
return response;
|
||||
} catch (error) {
|
||||
if (retryCount === 3) {
|
||||
setErrorData({
|
||||
title: "There was an error on web connection, please: ",
|
||||
list: [
|
||||
"Refresh the page",
|
||||
"Use a new flow tab",
|
||||
"Check if the backend is up",
|
||||
"Endpoint: " + error.config.url,
|
||||
],
|
||||
});
|
||||
return Promise.reject(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
return () => {
|
||||
// Clean up the interceptor when the component unmounts
|
||||
api.interceptors.response.eject(interceptor);
|
||||
};
|
||||
}, [retryCounts]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// Function to sleep for a given duration in milliseconds
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
export { ApiInterceptor, api };
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
import axios, { AxiosResponse } from "axios";
|
||||
import { AxiosResponse } from "axios";
|
||||
import { ReactFlowJsonObject } from "reactflow";
|
||||
import { api } from "../../controllers/API/api";
|
||||
import { APIObjectType, sendAllProps } from "../../types/api/index";
|
||||
import { FlowStyleType, FlowType } from "../../types/flow";
|
||||
import {
|
||||
|
|
@ -17,16 +18,14 @@ import {
|
|||
* @returns {Promise<AxiosResponse<APIObjectType>>} A promise that resolves to an AxiosResponse containing all the objects.
|
||||
*/
|
||||
export async function getAll(): Promise<AxiosResponse<APIObjectType>> {
|
||||
return await axios.get(`/api/v1/all`);
|
||||
return await api.get(`/api/v1/all`);
|
||||
}
|
||||
|
||||
const GITHUB_API_URL = "https://api.github.com";
|
||||
|
||||
export async function getRepoStars(owner, repo) {
|
||||
try {
|
||||
const response = await axios.get(
|
||||
`${GITHUB_API_URL}/repos/${owner}/${repo}`
|
||||
);
|
||||
const response = await api.get(`${GITHUB_API_URL}/repos/${owner}/${repo}`);
|
||||
return response.data.stargazers_count;
|
||||
} catch (error) {
|
||||
console.error("Error fetching repository data:", error);
|
||||
|
|
@ -41,13 +40,13 @@ export async function getRepoStars(owner, repo) {
|
|||
* @returns {AxiosResponse<any>} The API response.
|
||||
*/
|
||||
export async function sendAll(data: sendAllProps) {
|
||||
return await axios.post(`/api/v1/predict`, data);
|
||||
return await api.post(`/api/v1/predict`, data);
|
||||
}
|
||||
|
||||
export async function postValidateCode(
|
||||
code: string
|
||||
): Promise<AxiosResponse<errorsTypeAPI>> {
|
||||
return await axios.post("/api/v1/validate/code", { code });
|
||||
return await api.post("/api/v1/validate/code", { code });
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -62,7 +61,7 @@ export async function postValidatePrompt(
|
|||
template: string,
|
||||
frontend_node: APIClassType
|
||||
): Promise<AxiosResponse<PromptTypeAPI>> {
|
||||
return await axios.post("/api/v1/validate/prompt", {
|
||||
return await api.post("/api/v1/validate/prompt", {
|
||||
name: name,
|
||||
template: template,
|
||||
frontend_node: frontend_node,
|
||||
|
|
@ -76,15 +75,15 @@ export async function postValidatePrompt(
|
|||
*/
|
||||
export async function getExamples(): Promise<FlowType[]> {
|
||||
const url =
|
||||
"https://api.github.com/repos/logspace-ai/langflow_examples/contents/examples?ref=fix_examples";
|
||||
const response = await axios.get(url);
|
||||
"https://api.github.com/repos/logspace-ai/langflow_examples/contents/examples?ref=main";
|
||||
const response = await api.get(url);
|
||||
|
||||
const jsonFiles = response.data.filter((file: any) => {
|
||||
return file.name.endsWith(".json");
|
||||
});
|
||||
|
||||
const contentsPromises = jsonFiles.map(async (file: any) => {
|
||||
const contentResponse = await axios.get(file.download_url);
|
||||
const contentResponse = await api.get(file.download_url);
|
||||
return contentResponse.data;
|
||||
});
|
||||
|
||||
|
|
@ -106,11 +105,12 @@ export async function saveFlowToDatabase(newFlow: {
|
|||
style?: FlowStyleType;
|
||||
}): Promise<FlowType> {
|
||||
try {
|
||||
const response = await axios.post("/api/v1/flows/", {
|
||||
const response = await api.post("/api/v1/flows/", {
|
||||
name: newFlow.name,
|
||||
data: newFlow.data,
|
||||
description: newFlow.description,
|
||||
});
|
||||
|
||||
if (response.status !== 201) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
|
@ -131,7 +131,7 @@ export async function updateFlowInDatabase(
|
|||
updatedFlow: FlowType
|
||||
): Promise<FlowType> {
|
||||
try {
|
||||
const response = await axios.patch(`/api/v1/flows/${updatedFlow.id}`, {
|
||||
const response = await api.patch(`/api/v1/flows/${updatedFlow.id}`, {
|
||||
name: updatedFlow.name,
|
||||
data: updatedFlow.data,
|
||||
description: updatedFlow.description,
|
||||
|
|
@ -155,7 +155,7 @@ export async function updateFlowInDatabase(
|
|||
*/
|
||||
export async function readFlowsFromDatabase() {
|
||||
try {
|
||||
const response = await axios.get("/api/v1/flows/");
|
||||
const response = await api.get("/api/v1/flows/");
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
|
@ -168,7 +168,7 @@ export async function readFlowsFromDatabase() {
|
|||
|
||||
export async function downloadFlowsFromDatabase() {
|
||||
try {
|
||||
const response = await axios.get("/api/v1/flows/download/");
|
||||
const response = await api.get("/api/v1/flows/download/");
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
|
@ -181,7 +181,7 @@ export async function downloadFlowsFromDatabase() {
|
|||
|
||||
export async function uploadFlowsToDatabase(flows) {
|
||||
try {
|
||||
const response = await axios.post(`/api/v1/flows/upload/`, flows);
|
||||
const response = await api.post(`/api/v1/flows/upload/`, flows);
|
||||
|
||||
if (response.status !== 201) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
|
|
@ -202,7 +202,7 @@ export async function uploadFlowsToDatabase(flows) {
|
|||
*/
|
||||
export async function deleteFlowFromDatabase(flowId: string) {
|
||||
try {
|
||||
const response = await axios.delete(`/api/v1/flows/${flowId}`);
|
||||
const response = await api.delete(`/api/v1/flows/${flowId}`);
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
|
@ -222,7 +222,7 @@ export async function deleteFlowFromDatabase(flowId: string) {
|
|||
*/
|
||||
export async function getFlowFromDatabase(flowId: number) {
|
||||
try {
|
||||
const response = await axios.get(`/api/v1/flows/${flowId}`);
|
||||
const response = await api.get(`/api/v1/flows/${flowId}`);
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
|
@ -241,7 +241,7 @@ export async function getFlowFromDatabase(flowId: number) {
|
|||
*/
|
||||
export async function getFlowStylesFromDatabase() {
|
||||
try {
|
||||
const response = await axios.get("/api/v1/flow_styles/");
|
||||
const response = await api.get("/api/v1/flow_styles/");
|
||||
if (response.status !== 200) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
|
@ -261,7 +261,7 @@ export async function getFlowStylesFromDatabase() {
|
|||
*/
|
||||
export async function saveFlowStyleToDatabase(flowStyle: FlowStyleType) {
|
||||
try {
|
||||
const response = await axios.post("/api/v1/flow_styles/", flowStyle, {
|
||||
const response = await api.post("/api/v1/flow_styles/", flowStyle, {
|
||||
headers: {
|
||||
accept: "application/json",
|
||||
"Content-Type": "application/json",
|
||||
|
|
@ -284,7 +284,7 @@ export async function saveFlowStyleToDatabase(flowStyle: FlowStyleType) {
|
|||
* @returns {Promise<AxiosResponse<any>>} A promise that resolves to an AxiosResponse containing the version information.
|
||||
*/
|
||||
export async function getVersion() {
|
||||
const respnose = await axios.get("/api/v1/version");
|
||||
const respnose = await api.get("/api/v1/version");
|
||||
return respnose.data;
|
||||
}
|
||||
|
||||
|
|
@ -294,7 +294,7 @@ export async function getVersion() {
|
|||
* @returns {Promise<AxiosResponse<any>>} A promise that resolves to an AxiosResponse containing the health status.
|
||||
*/
|
||||
export async function getHealth() {
|
||||
return await axios.get("/health"); // Health is the only endpoint that doesn't require /api/v1
|
||||
return await api.get("/health"); // Health is the only endpoint that doesn't require /api/v1
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -306,7 +306,7 @@ export async function getHealth() {
|
|||
export async function getBuildStatus(
|
||||
flowId: string
|
||||
): Promise<BuildStatusTypeAPI> {
|
||||
return await axios.get(`/api/v1/build/${flowId}/status`);
|
||||
return await api.get(`/api/v1/build/${flowId}/status`);
|
||||
}
|
||||
|
||||
//docs for postbuildinit
|
||||
|
|
@ -319,7 +319,7 @@ export async function getBuildStatus(
|
|||
export async function postBuildInit(
|
||||
flow: FlowType
|
||||
): Promise<AxiosResponse<InitTypeAPI>> {
|
||||
return await axios.post(`/api/v1/build/init/${flow.id}`, flow);
|
||||
return await api.post(`/api/v1/build/init/${flow.id}`, flow);
|
||||
}
|
||||
|
||||
// fetch(`/upload/${id}`, {
|
||||
|
|
@ -337,5 +337,5 @@ export async function uploadFile(
|
|||
): Promise<AxiosResponse<UploadFileTypeAPI>> {
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
return await axios.post(`/api/v1/upload/${id}`, formData);
|
||||
return await api.post(`/api/v1/upload/${id}`, formData);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,9 +38,10 @@
|
|||
|
||||
--info-background: #f0f4fd;
|
||||
--info-foreground: #141653;
|
||||
|
||||
|
||||
--high-indigo: #4338ca;
|
||||
--medium-indigo: #6366f1;
|
||||
--low-indigo: #e0e7ff;
|
||||
|
||||
--chat-bot-icon: #afe6ef;
|
||||
--chat-user-icon: #aface9;
|
||||
|
|
@ -52,6 +53,7 @@
|
|||
--chat-trigger-disabled: #b4c3da;
|
||||
--status-red: #ef4444;
|
||||
--status-yellow: #eab308;
|
||||
--chat-send: #059669;
|
||||
--status-green: #4ade80;
|
||||
--status-blue:#2563eb;
|
||||
--connection: #555;
|
||||
|
|
@ -104,6 +106,7 @@
|
|||
|
||||
--high-indigo: #4338ca;
|
||||
--medium-indigo: #6366f1;
|
||||
--low-indigo: #e0e7ff;
|
||||
|
||||
/* Colors that are shared in dark and light mode */
|
||||
--blur-shared: #151923d2;
|
||||
|
|
@ -112,6 +115,7 @@
|
|||
--chat-trigger-disabled: #2d3b54;
|
||||
--status-red: #ef4444;
|
||||
--status-yellow: #eab308;
|
||||
--chat-send: #059669;
|
||||
--status-green: #4ade80;
|
||||
--status-blue: #2563eb;
|
||||
--connection: #555;
|
||||
|
|
@ -145,6 +149,9 @@ code {
|
|||
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
|
||||
monospace;
|
||||
}
|
||||
pre {
|
||||
font-family: inherit;
|
||||
}
|
||||
|
||||
/* The style below sets the cursor property of the element with the class .react-flow__pane to the default cursor.
|
||||
The cursor: default; property value restores the browser's default cursor style for the targeted element. By applying this style, the element will no longer have a custom cursor appearance such as "grab" or any other custom cursor defined elsewhere in the application. Instead, it will revert to the default cursor style determined by the browser, typically an arrow-shaped cursor. */
|
||||
|
|
@ -236,15 +243,17 @@ The cursor: default; property value restores the browser's default cursor style
|
|||
.button-div-style {
|
||||
@apply gap-2 flex
|
||||
}
|
||||
.input-primary:focus{
|
||||
@apply focus:placeholder-transparent focus:ring-ring focus:border-ring
|
||||
.input-primary{
|
||||
@apply disabled:cursor-not-allowed disabled:opacity-50 focus:placeholder-transparent focus:ring-ring focus:border-ring bg-background block text-left border-border form-input px-3 placeholder:text-muted-foreground rounded-md shadow-sm sm:text-sm w-full truncate
|
||||
}
|
||||
.input-primary {
|
||||
@apply bg-background block border-border form-input px-3 placeholder:text-muted-foreground rounded-md shadow-sm sm:text-sm truncate w-full;
|
||||
|
||||
/* The same as input-primary but no-truncate */
|
||||
.textarea-primary{
|
||||
@apply disabled:cursor-not-allowed disabled:opacity-50 focus:placeholder-transparent focus:ring-ring focus:border-ring bg-background block text-left border-border form-input px-3 placeholder:text-muted-foreground rounded-md shadow-sm sm:text-sm w-full
|
||||
}
|
||||
|
||||
|
||||
.input-edit-node{
|
||||
@apply input-primary border-border placeholder:text-center pt-0.5 pb-0.5 text-center
|
||||
@apply input-primary border-border pt-0.5 pb-0.5 text-left w-full
|
||||
}
|
||||
.input-search{
|
||||
@apply input-primary pr-7 mx-2
|
||||
|
|
@ -547,7 +556,7 @@ The cursor: default; property value restores the browser's default cursor style
|
|||
@apply z-10 mt-1 max-h-60 overflow-auto rounded-md bg-background py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm
|
||||
}
|
||||
.dropdown-component-true-options {
|
||||
@apply dropdown-component-options w-[215px]
|
||||
@apply dropdown-component-options lg:w-[32%]
|
||||
}
|
||||
.dropdown-component-false-options {
|
||||
@apply dropdown-component-options w-full
|
||||
|
|
@ -932,7 +941,7 @@ The cursor: default; property value restores the browser's default cursor style
|
|||
}
|
||||
|
||||
.api-modal-tabs {
|
||||
@apply w-full h-full overflow-hidden text-center bg-muted rounded-md border
|
||||
@apply lg:w-full h-full flex flex-col overflow-hidden text-center bg-muted rounded-md border sm:w-[75vw]
|
||||
}
|
||||
.api-modal-tablist-div {
|
||||
@apply flex items-center justify-between px-2
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import App from "./App";
|
|||
import ContextWrapper from "./contexts";
|
||||
import reportWebVitals from "./reportWebVitals";
|
||||
|
||||
import { ApiInterceptor } from "./controllers/API/api";
|
||||
import "./index.css";
|
||||
|
||||
const root = ReactDOM.createRoot(
|
||||
|
|
@ -13,6 +14,7 @@ root.render(
|
|||
<ContextWrapper>
|
||||
<BrowserRouter>
|
||||
<App />
|
||||
<ApiInterceptor />
|
||||
</BrowserRouter>
|
||||
</ContextWrapper>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,734 +2,285 @@ import "ace-builds/src-noconflict/ext-language_tools";
|
|||
import "ace-builds/src-noconflict/mode-python";
|
||||
import "ace-builds/src-noconflict/theme-github";
|
||||
import "ace-builds/src-noconflict/theme-twilight";
|
||||
import { Check, Clipboard } from "lucide-react";
|
||||
import { useContext, useEffect, useRef, 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 {
|
||||
ReactNode,
|
||||
forwardRef,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
// import "ace-builds/webpack-resolver";
|
||||
import CodeTabsComponent from "../../components/codeTabsComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
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 {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../../components/ui/dialog";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
TableCell,
|
||||
TableHead,
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "../../components/ui/table";
|
||||
import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "../../components/ui/tabs";
|
||||
import { EXPORT_CODE_DIALOG } from "../../constants/constants";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { FlowType, NodeDataType } from "../../types/flow/index";
|
||||
import { buildTweaks } from "../../utils/reactflowUtils";
|
||||
import {
|
||||
classNames,
|
||||
getCurlCode,
|
||||
getPythonApiCode,
|
||||
getPythonCode,
|
||||
} from "../../utils/utils";
|
||||
export default function ApiModal({ flow }: { flow: FlowType }): JSX.Element {
|
||||
const [open, setOpen] = useState(true);
|
||||
const { dark } = useContext(darkContext);
|
||||
const { closePopUp, closeEdit, setCloseEdit } = useContext(PopUpContext);
|
||||
const [activeTab, setActiveTab] = useState("0");
|
||||
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
||||
const [enabled, setEnabled] = useState(null);
|
||||
const [openAccordion, setOpenAccordion] = useState([]);
|
||||
const tweak = useRef([]);
|
||||
const tweaksList = useRef([]);
|
||||
const { setTweak, getTweak, tabsState } = useContext(TabsContext);
|
||||
const copyToClipboard = () => {
|
||||
if (!navigator.clipboard || !navigator.clipboard.writeText) {
|
||||
return;
|
||||
}
|
||||
import BaseModal from "../baseModal";
|
||||
|
||||
navigator.clipboard.writeText(tabs[activeTab].code).then(() => {
|
||||
setIsCopied(true);
|
||||
|
||||
setTimeout(() => {
|
||||
setIsCopied(false);
|
||||
}, 2000);
|
||||
});
|
||||
};
|
||||
const pythonApiCode = getPythonApiCode(flow, tweak.current, tabsState);
|
||||
const curl_code = getCurlCode(flow, tweak.current, tabsState);
|
||||
const pythonCode = getPythonCode(flow, tweak.current, tabsState);
|
||||
const tweaksCode = buildTweaks(flow);
|
||||
const tabs = [
|
||||
const ApiModal = forwardRef(
|
||||
(
|
||||
{
|
||||
name: "cURL",
|
||||
mode: "bash",
|
||||
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||
code: curl_code,
|
||||
flow,
|
||||
children,
|
||||
}: {
|
||||
flow: FlowType;
|
||||
children: ReactNode;
|
||||
},
|
||||
{
|
||||
name: "Python API",
|
||||
mode: "python",
|
||||
image:
|
||||
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
||||
code: pythonApiCode,
|
||||
},
|
||||
{
|
||||
name: "Python Code",
|
||||
mode: "python",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
code: pythonCode,
|
||||
},
|
||||
];
|
||||
ref
|
||||
) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState("0");
|
||||
const tweak = useRef([]);
|
||||
const tweaksList = useRef([]);
|
||||
const { setTweak, getTweak, tabsState } = useContext(TabsContext);
|
||||
const pythonApiCode = getPythonApiCode(flow, tweak.current, tabsState);
|
||||
const curl_code = getCurlCode(flow, tweak.current, tabsState);
|
||||
const pythonCode = getPythonCode(flow, tweak.current, tabsState);
|
||||
const tweaksCode = buildTweaks(flow);
|
||||
const [tabs, setTabs] = useState([
|
||||
{
|
||||
name: "cURL",
|
||||
mode: "bash",
|
||||
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||
language: "sh",
|
||||
code: curl_code,
|
||||
},
|
||||
{
|
||||
name: "Python API",
|
||||
mode: "python",
|
||||
image:
|
||||
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
||||
language: "py",
|
||||
code: pythonApiCode,
|
||||
},
|
||||
{
|
||||
name: "Python Code",
|
||||
mode: "python",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: pythonCode,
|
||||
},
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (closeEdit !== "") {
|
||||
tweak.current = getTweak;
|
||||
if (tweak.current.length > 0) {
|
||||
setActiveTab("3");
|
||||
openAccordions();
|
||||
} else {
|
||||
startTweaks();
|
||||
}
|
||||
} else {
|
||||
if (tweak?.current) {
|
||||
startTweaks();
|
||||
}
|
||||
}
|
||||
}, [closeEdit]);
|
||||
|
||||
useEffect(() => {
|
||||
filterNodes();
|
||||
}, []);
|
||||
|
||||
if (Object.keys(tweaksCode).length > 0) {
|
||||
tabs.push({
|
||||
name: "Tweaks",
|
||||
mode: "python",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
code: pythonCode,
|
||||
});
|
||||
}
|
||||
|
||||
function setModalOpen(x: boolean) {
|
||||
setOpen(x);
|
||||
if (x === false) {
|
||||
setCloseEdit("");
|
||||
function startState() {
|
||||
tweak.current = [];
|
||||
setTweak([]);
|
||||
closePopUp();
|
||||
}
|
||||
}
|
||||
|
||||
function startTweaks() {
|
||||
const t = buildTweaks(flow);
|
||||
tweak?.current?.push(t);
|
||||
}
|
||||
|
||||
function filterNodes() {
|
||||
let arrNodesWithValues = [];
|
||||
|
||||
flow["data"]["nodes"].forEach((t) => {
|
||||
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) => {
|
||||
arrNodesWithValues.push(t["id"]);
|
||||
});
|
||||
});
|
||||
|
||||
tweaksList.current = arrNodesWithValues.filter((value, index, self) => {
|
||||
return self.indexOf(value) === index;
|
||||
});
|
||||
}
|
||||
|
||||
// DIFICULT IN FIND WHERE TW,CHANGES AND TEMPLATE ARE USED
|
||||
function buildTweakObject(tw, changes, template): void {
|
||||
if (template.type === "float") {
|
||||
changes = parseFloat(changes);
|
||||
}
|
||||
if (template.type === "int") {
|
||||
changes = parseInt(changes);
|
||||
}
|
||||
if (template.list === true && Array.isArray(changes)) {
|
||||
changes = changes?.filter((x) => x !== "");
|
||||
tweaksList.current = [];
|
||||
}
|
||||
|
||||
const existingTweak = tweak.current.find((element) =>
|
||||
element.hasOwnProperty(tw)
|
||||
);
|
||||
|
||||
if (existingTweak) {
|
||||
existingTweak[tw][template["name"]] = changes;
|
||||
|
||||
if (existingTweak[tw][template["name"]] == template.value) {
|
||||
tweak.current.forEach((element) => {
|
||||
if (element[tw] && Object.keys(element[tw])?.length === 0) {
|
||||
tweak.current = tweak.current.filter((obj) => {
|
||||
const prop = obj[Object.keys(obj)[0]].prop;
|
||||
return prop !== undefined && prop !== null && prop !== "";
|
||||
});
|
||||
}
|
||||
});
|
||||
useEffect(() => {
|
||||
if (flow["data"]["nodes"].length == 0) {
|
||||
startState();
|
||||
} else {
|
||||
tweak.current = [];
|
||||
const t = buildTweaks(flow);
|
||||
tweak.current.push(t);
|
||||
}
|
||||
} else {
|
||||
const newTweak = {
|
||||
[tw]: {
|
||||
[template["name"]]: changes,
|
||||
},
|
||||
};
|
||||
tweak.current.push(newTweak);
|
||||
}
|
||||
|
||||
const pythonApiCode = getPythonApiCode(flow, tweak.current);
|
||||
const curl_code = getCurlCode(flow, tweak.current);
|
||||
const pythonCode = getPythonCode(flow, tweak.current);
|
||||
filterNodes();
|
||||
|
||||
tabs[0].code = curl_code;
|
||||
tabs[1].code = pythonApiCode;
|
||||
tabs[2].code = pythonCode;
|
||||
|
||||
setTweak(tweak.current);
|
||||
}
|
||||
|
||||
function buildContent(value: string): JSX.Element {
|
||||
const htmlContent = (
|
||||
<div className="w-[200px]">
|
||||
<span>{value != null && value != "" ? value : "None"}</span>
|
||||
</div>
|
||||
);
|
||||
return htmlContent;
|
||||
}
|
||||
|
||||
// DIFICULT FINDIND WHERE TEMPLATE IS USED
|
||||
function getValue(value: string, node: NodeDataType, template): string {
|
||||
let returnValue = value ?? "";
|
||||
|
||||
if (getTweak.length > 0) {
|
||||
for (const obj of getTweak) {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const value = obj[key];
|
||||
if (key == node["id"]) {
|
||||
Object.keys(value).forEach((key) => {
|
||||
if (key == template["name"]) {
|
||||
returnValue = value[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (Object.keys(tweaksCode).length > 0) {
|
||||
setActiveTab("0");
|
||||
setTabs([
|
||||
{
|
||||
name: "cURL",
|
||||
mode: "bash",
|
||||
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||
language: "sh",
|
||||
code: curl_code,
|
||||
},
|
||||
{
|
||||
name: "Python API",
|
||||
mode: "python",
|
||||
image:
|
||||
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
||||
language: "py",
|
||||
code: pythonApiCode,
|
||||
},
|
||||
{
|
||||
name: "Python Code",
|
||||
mode: "python",
|
||||
language: "py",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
code: pythonCode,
|
||||
},
|
||||
{
|
||||
name: "Tweaks",
|
||||
mode: "python",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: pythonCode,
|
||||
},
|
||||
]);
|
||||
} else {
|
||||
setTabs([
|
||||
{
|
||||
name: "cURL",
|
||||
mode: "bash",
|
||||
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||
language: "sh",
|
||||
code: curl_code,
|
||||
},
|
||||
{
|
||||
name: "Python API",
|
||||
mode: "python",
|
||||
image:
|
||||
"https://images.squarespace-cdn.com/content/v1/5df3d8c5d2be5962e4f87890/1628015119369-OY4TV3XJJ53ECO0W2OLQ/Python+API+Training+Logo.png?format=1000w",
|
||||
language: "py",
|
||||
code: pythonApiCode,
|
||||
},
|
||||
{
|
||||
name: "Python Code",
|
||||
mode: "python",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: pythonCode,
|
||||
},
|
||||
]);
|
||||
}
|
||||
} else {
|
||||
return value ?? "";
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
}, [flow["data"]["nodes"], open]);
|
||||
|
||||
function openAccordions(): void {
|
||||
let accordionsToOpen = [];
|
||||
tweak.current.forEach((el) => {
|
||||
Object.keys(el).forEach((key) => {
|
||||
if (Object.keys(el[key]).length > 0) {
|
||||
accordionsToOpen.push(key);
|
||||
setOpenAccordion(accordionsToOpen);
|
||||
}
|
||||
function filterNodes() {
|
||||
let arrNodesWithValues = [];
|
||||
|
||||
flow["data"]["nodes"].forEach((t) => {
|
||||
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) => {
|
||||
arrNodesWithValues.push(t["id"]);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
return (
|
||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||
<DialogTrigger></DialogTrigger>
|
||||
<DialogContent className="h-[80vh] md:max-w-[80vw]">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center">
|
||||
<span className="pr-2">Code</span>
|
||||
<IconComponent
|
||||
name="Code2"
|
||||
className="h-6 w-6 pl-1 text-gray-800 dark:text-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</DialogTitle>
|
||||
<DialogDescription>{EXPORT_CODE_DIALOG}</DialogDescription>
|
||||
</DialogHeader>
|
||||
tweaksList.current = arrNodesWithValues.filter((value, index, self) => {
|
||||
return self.indexOf(value) === index;
|
||||
});
|
||||
}
|
||||
function buildTweakObject(tw, changes, template) {
|
||||
if (template.type === "float") {
|
||||
changes = parseFloat(changes);
|
||||
}
|
||||
if (template.type === "int") {
|
||||
changes = parseInt(changes);
|
||||
}
|
||||
if (template.list === true && Array.isArray(changes)) {
|
||||
changes = changes?.filter((x) => x !== "");
|
||||
}
|
||||
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
className="api-modal-tabs"
|
||||
onValueChange={(value) => {
|
||||
setActiveTab(value);
|
||||
if (value === "3") {
|
||||
openAccordions();
|
||||
const existingTweak = tweak.current.find((element) =>
|
||||
element.hasOwnProperty(tw)
|
||||
);
|
||||
|
||||
if (existingTweak) {
|
||||
existingTweak[tw][template["name"]] = changes;
|
||||
|
||||
if (existingTweak[tw][template["name"]] == template.value) {
|
||||
tweak.current.forEach((element) => {
|
||||
if (element[tw] && Object.keys(element[tw])?.length === 0) {
|
||||
tweak.current = tweak.current.filter((obj) => {
|
||||
const prop = obj[Object.keys(obj)[0]].prop;
|
||||
return prop !== undefined && prop !== null && prop !== "";
|
||||
});
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="api-modal-tablist-div">
|
||||
<TabsList>
|
||||
{tabs.map((tab, index) => (
|
||||
<TabsTrigger key={index} value={index.toString()}>
|
||||
{tab.name}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
{Number(activeTab) < 3 && (
|
||||
<div className="float-right">
|
||||
<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 ? <Check size={18} /> : <Clipboard size={15} />}
|
||||
{isCopied ? "Copied!" : "Copy code"}
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const newTweak = {
|
||||
[tw]: {
|
||||
[template["name"]]: changes,
|
||||
},
|
||||
};
|
||||
tweak.current.push(newTweak);
|
||||
}
|
||||
|
||||
{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="h-[60vh] 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-[60vh] w-full rounded-lg bg-muted",
|
||||
1 == 1
|
||||
? "overflow-scroll overflow-x-hidden custom-scroll"
|
||||
: "overflow-hidden"
|
||||
)}
|
||||
>
|
||||
{flow["data"]["nodes"].map((t: any, index) => (
|
||||
<div className="px-3" key={index}>
|
||||
{tweaksList.current.includes(t["data"]["id"]) && (
|
||||
<AccordionComponent
|
||||
trigger={t["data"]["id"]}
|
||||
keyValue={t["data"]["id"]}
|
||||
open={openAccordion}
|
||||
>
|
||||
<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) => {}}
|
||||
onAddInput={(k) => {
|
||||
buildTweakObject(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node
|
||||
.template[n]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
) : t.data.node.template[n]
|
||||
.multiline ? (
|
||||
<ShadTooltip
|
||||
content={buildContent(
|
||||
t.data.node.template[
|
||||
n
|
||||
].value
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
<TextAreaComponent
|
||||
disabled={false}
|
||||
editNode={true}
|
||||
value={getValue(
|
||||
t.data.node
|
||||
.template[n]
|
||||
.value,
|
||||
t.data,
|
||||
t.data.node
|
||||
.template[n]
|
||||
)}
|
||||
onChange={(k) => {
|
||||
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={getValue(
|
||||
t.data.node.template[
|
||||
n
|
||||
].value,
|
||||
t.data,
|
||||
t.data.node.template[
|
||||
n
|
||||
]
|
||||
)}
|
||||
onChange={(k) => {
|
||||
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) => {
|
||||
t.data.node.template[
|
||||
n
|
||||
].value = e;
|
||||
setEnabled(e);
|
||||
buildTweakObject(
|
||||
t["data"]["id"],
|
||||
e,
|
||||
t.data.node.template[
|
||||
n
|
||||
]
|
||||
);
|
||||
}}
|
||||
size="small"
|
||||
disabled={false}
|
||||
/>
|
||||
</div>
|
||||
) : t.data.node.template[n]
|
||||
.type === "file" ? (
|
||||
<ShadTooltip
|
||||
content={buildContent(
|
||||
getValue(
|
||||
t.data.node.template[n]
|
||||
.value,
|
||||
t.data,
|
||||
t.data.node.template[n]
|
||||
)
|
||||
)}
|
||||
>
|
||||
<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={getValue(
|
||||
t.data.node.template[n]
|
||||
.value,
|
||||
t.data,
|
||||
t.data.node.template[n]
|
||||
)}
|
||||
onChange={(k) => {
|
||||
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) => {
|
||||
buildTweakObject(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node.template[
|
||||
n
|
||||
]
|
||||
);
|
||||
}}
|
||||
value={getValue(
|
||||
t.data.node.template[n]
|
||||
.value,
|
||||
t.data,
|
||||
t.data.node.template[n]
|
||||
)}
|
||||
></Dropdown>
|
||||
</div>
|
||||
) : t.data.node.template[n]
|
||||
.type === "int" ? (
|
||||
<div className="mx-auto">
|
||||
<IntComponent
|
||||
disabled={false}
|
||||
editNode={true}
|
||||
value={getValue(
|
||||
t.data.node.template[n]
|
||||
.value,
|
||||
t.data,
|
||||
t.data.node.template[n]
|
||||
)}
|
||||
onChange={(k) => {
|
||||
buildTweakObject(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node.template[
|
||||
n
|
||||
]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : t.data.node.template[n]
|
||||
.type === "prompt" ? (
|
||||
<ShadTooltip
|
||||
content={buildContent(
|
||||
getValue(
|
||||
t.data.node.template[n]
|
||||
.value,
|
||||
t.data,
|
||||
t.data.node.template[n]
|
||||
)
|
||||
)}
|
||||
>
|
||||
<div className="mx-auto">
|
||||
<PromptAreaComponent
|
||||
editNode={true}
|
||||
disabled={false}
|
||||
value={getValue(
|
||||
t.data.node.template[
|
||||
n
|
||||
].value,
|
||||
t.data,
|
||||
t.data.node.template[
|
||||
n
|
||||
]
|
||||
)}
|
||||
onChange={(k) => {
|
||||
buildTweakObject(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node
|
||||
.template[n]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</ShadTooltip>
|
||||
) : t.data.node.template[n]
|
||||
.type === "code" ? (
|
||||
<ShadTooltip
|
||||
content={buildContent(
|
||||
getValue(
|
||||
t.data.node.template[n]
|
||||
.value,
|
||||
t.data,
|
||||
t.data.node.template[n]
|
||||
)
|
||||
)}
|
||||
>
|
||||
<div className="mx-auto">
|
||||
<CodeAreaComponent
|
||||
disabled={false}
|
||||
editNode={true}
|
||||
value={getValue(
|
||||
t.data.node.template[
|
||||
n
|
||||
].value,
|
||||
t.data,
|
||||
t.data.node.template[
|
||||
n
|
||||
]
|
||||
)}
|
||||
onChange={(k) => {
|
||||
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>
|
||||
)}
|
||||
const pythonApiCode = getPythonApiCode(flow, tweak.current);
|
||||
const curl_code = getCurlCode(flow, tweak.current);
|
||||
const pythonCode = getPythonCode(flow, tweak.current);
|
||||
|
||||
{tweaksList.current.length === 0 && (
|
||||
<>
|
||||
<div className="pt-3">
|
||||
No tweaks are available for this flow.
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : null}
|
||||
</TabsContent>
|
||||
))}
|
||||
</Tabs>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
tabs[0].code = curl_code;
|
||||
tabs[1].code = pythonApiCode;
|
||||
tabs[2].code = pythonCode;
|
||||
|
||||
setTweak(tweak.current);
|
||||
}
|
||||
|
||||
function buildContent(value) {
|
||||
const htmlContent = (
|
||||
<div className="w-[200px]">
|
||||
<span>{value != null && value != "" ? value : "None"}</span>
|
||||
</div>
|
||||
);
|
||||
return htmlContent;
|
||||
}
|
||||
|
||||
function getValue(value, node, template) {
|
||||
let returnValue = value ?? "";
|
||||
|
||||
if (getTweak.length > 0) {
|
||||
for (const obj of getTweak) {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const value = obj[key];
|
||||
if (key == node["id"]) {
|
||||
Object.keys(value).forEach((key) => {
|
||||
if (key == template["name"]) {
|
||||
returnValue = value[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return value ?? "";
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseModal open={open} setOpen={setOpen}>
|
||||
<BaseModal.Trigger>{children}</BaseModal.Trigger>
|
||||
<BaseModal.Header description={EXPORT_CODE_DIALOG}>
|
||||
<span className="pr-2">Code</span>
|
||||
<IconComponent
|
||||
name="Code2"
|
||||
className="h-6 w-6 pl-1 text-gray-800 dark:text-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<CodeTabsComponent
|
||||
flow={flow}
|
||||
tabs={tabs}
|
||||
activeTab={activeTab}
|
||||
setActiveTab={setActiveTab}
|
||||
tweaks={{
|
||||
tweak,
|
||||
tweaksList,
|
||||
buildContent,
|
||||
buildTweakObject,
|
||||
getValue,
|
||||
}}
|
||||
/>
|
||||
</BaseModal.Content>
|
||||
</BaseModal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default ApiModal;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { useContext, useRef, useState } from "react";
|
||||
import { cloneDeep } from "lodash";
|
||||
import { ReactNode, forwardRef, useContext, useEffect, useState } from "react";
|
||||
import CodeAreaComponent from "../../components/codeAreaComponent";
|
||||
import Dropdown from "../../components/dropdownComponent";
|
||||
import FloatComponent from "../../components/floatComponent";
|
||||
|
|
@ -12,15 +13,6 @@ import TextAreaComponent from "../../components/textAreaComponent";
|
|||
import ToggleShadComponent from "../../components/toggleShadComponent";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../../components/ui/dialog";
|
||||
import {
|
||||
Table,
|
||||
TableBody,
|
||||
|
|
@ -30,319 +22,304 @@ import {
|
|||
TableRow,
|
||||
} from "../../components/ui/table";
|
||||
import { limitScrollFieldsModal } from "../../constants/constants";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import { editNodeToggleType } from "../../types/components";
|
||||
import { NodeDataType } from "../../types/flow";
|
||||
import { classNames } from "../../utils/utils";
|
||||
import BaseModal from "../baseModal";
|
||||
|
||||
export default function EditNodeModal({
|
||||
data,
|
||||
}: {
|
||||
data: NodeDataType;
|
||||
}): JSX.Element {
|
||||
const [open, setOpen] = useState(true);
|
||||
const [nodeLength, setNodeLength] = useState(
|
||||
Object.keys(data.node.template).filter(
|
||||
(t) =>
|
||||
t.charAt(0) !== "_" &&
|
||||
data.node.template[t].show &&
|
||||
(data.node.template[t].type === "str" ||
|
||||
data.node.template[t].type === "bool" ||
|
||||
data.node.template[t].type === "float" ||
|
||||
data.node.template[t].type === "code" ||
|
||||
data.node.template[t].type === "prompt" ||
|
||||
data.node.template[t].type === "file" ||
|
||||
data.node.template[t].type === "int")
|
||||
).length
|
||||
);
|
||||
const [nodeValue, setNodeValue] = useState(null);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
const { types } = useContext(typesContext);
|
||||
const ref = useRef();
|
||||
const { setTabsState, tabId } = useContext(TabsContext);
|
||||
const { reactFlowInstance } = useContext(typesContext);
|
||||
const EditNodeModal = forwardRef(
|
||||
(
|
||||
{
|
||||
data,
|
||||
setData,
|
||||
nodeLength,
|
||||
children,
|
||||
}: {
|
||||
data: NodeDataType;
|
||||
setData: (data: NodeDataType) => void;
|
||||
nodeLength: number;
|
||||
children: ReactNode;
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
const [myData, setMyData] = useState(data);
|
||||
const { setTabsState, tabId } = useContext(TabsContext);
|
||||
const { reactFlowInstance } = useContext(typesContext);
|
||||
|
||||
let disabled =
|
||||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === data.id) ??
|
||||
false;
|
||||
if (nodeLength == 0) {
|
||||
closePopUp();
|
||||
}
|
||||
let disabled =
|
||||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === data.id) ??
|
||||
false;
|
||||
|
||||
function setModalOpen(x: boolean): void {
|
||||
setOpen(x);
|
||||
if (x === false) {
|
||||
closePopUp();
|
||||
function changeAdvanced(n) {
|
||||
setMyData((old) => {
|
||||
let newData = cloneDeep(old);
|
||||
newData.node.template[n].advanced = !newData.node.template[n].advanced;
|
||||
return newData;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function changeAdvanced(node: editNodeToggleType): void {
|
||||
Object.keys(data.node.template).map((n, i) => {
|
||||
if (n === node.name) {
|
||||
data.node.template[n].advanced = !data.node.template[n].advanced;
|
||||
}
|
||||
return n;
|
||||
});
|
||||
setNodeValue(!nodeValue);
|
||||
}
|
||||
const handleOnNewValue = (newValue: any, name) => {
|
||||
setMyData((old) => {
|
||||
let newData = cloneDeep(old);
|
||||
newData.node.template[name].value = newValue;
|
||||
return newData;
|
||||
});
|
||||
};
|
||||
|
||||
const handleOnNewValue = (
|
||||
newValue: string | string[] | boolean,
|
||||
name: string
|
||||
): void => {
|
||||
data.node.template[name].value = newValue;
|
||||
// Set state to pending
|
||||
setTabsState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[tabId]: {
|
||||
...prev[tabId],
|
||||
isPending: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
setMyData(data); // reset data to what it is on node when opening modal
|
||||
}, [modalOpen]);
|
||||
|
||||
return (
|
||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||
<DialogTrigger asChild></DialogTrigger>
|
||||
<DialogContent className="sm:max-w-[600px] lg:max-w-[700px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center">
|
||||
<span className="pr-2">{data.type}</span>
|
||||
<Badge variant="secondary">ID: {data.id}</Badge>
|
||||
</DialogTitle>
|
||||
<DialogDescription asChild>
|
||||
<div>
|
||||
{data.node?.description}
|
||||
<div className="flex pt-3">
|
||||
<IconComponent
|
||||
name="Variable"
|
||||
className="edit-node-modal-variable "
|
||||
/>
|
||||
<span className="edit-node-modal-span">Parameters</span>
|
||||
</div>
|
||||
</div>
|
||||
</DialogDescription>
|
||||
</DialogHeader>
|
||||
return (
|
||||
<BaseModal size="large-h-full" open={modalOpen} setOpen={setModalOpen}>
|
||||
<BaseModal.Trigger>{children}</BaseModal.Trigger>
|
||||
<BaseModal.Header description={myData.node?.description}>
|
||||
<span className="pr-2">{myData.type}</span>
|
||||
<Badge variant="secondary">ID: {myData.id}</Badge>
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<div className="flex pb-2">
|
||||
<IconComponent
|
||||
name="Variable"
|
||||
className="edit-node-modal-variable "
|
||||
/>
|
||||
<span className="edit-node-modal-span">Parameters</span>
|
||||
</div>
|
||||
|
||||
<div className="edit-node-modal-arrangement">
|
||||
<div
|
||||
className={classNames(
|
||||
"edit-node-modal-box",
|
||||
nodeLength > limitScrollFieldsModal
|
||||
? "overflow-scroll overflow-x-hidden custom-scroll"
|
||||
: "overflow-hidden"
|
||||
)}
|
||||
>
|
||||
{nodeLength > 0 && (
|
||||
<div className="edit-node-modal-table">
|
||||
<Table className="table-fixed bg-muted outline-1">
|
||||
<TableHeader className="edit-node-modal-table-header">
|
||||
<TableRow className="">
|
||||
<TableHead className="h-7 text-center">PARAM</TableHead>
|
||||
<TableHead className="h-7 p-0 text-center">
|
||||
VALUE
|
||||
</TableHead>
|
||||
<TableHead className="h-7 text-center">SHOW</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody className="p-0">
|
||||
{Object.keys(data.node.template)
|
||||
.filter(
|
||||
(t) =>
|
||||
t.charAt(0) !== "_" &&
|
||||
data.node.template[t].show &&
|
||||
(data.node.template[t].type === "str" ||
|
||||
data.node.template[t].type === "bool" ||
|
||||
data.node.template[t].type === "float" ||
|
||||
data.node.template[t].type === "code" ||
|
||||
data.node.template[t].type === "prompt" ||
|
||||
data.node.template[t].type === "file" ||
|
||||
data.node.template[t].type === "int")
|
||||
)
|
||||
.map((n, i) => (
|
||||
<TableRow key={i} className="h-10">
|
||||
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
|
||||
{data.node.template[n].name
|
||||
? data.node.template[n].name
|
||||
: data.node.template[n].display_name}
|
||||
</TableCell>
|
||||
<TableCell className="w-[300px] p-0 text-center text-xs text-foreground ">
|
||||
{data.node.template[n].type === "str" &&
|
||||
!data.node.template[n].options ? (
|
||||
<div className="mx-auto">
|
||||
{data.node.template[n].list ? (
|
||||
<InputListComponent
|
||||
editNode={true}
|
||||
<div className="edit-node-modal-arrangement">
|
||||
<div
|
||||
className={classNames(
|
||||
"edit-node-modal-box",
|
||||
nodeLength > limitScrollFieldsModal
|
||||
? "overflow-scroll overflow-x-hidden custom-scroll"
|
||||
: "overflow-hidden"
|
||||
)}
|
||||
>
|
||||
{nodeLength > 0 && (
|
||||
<div className="edit-node-modal-table">
|
||||
<Table className="table-fixed bg-muted outline-1">
|
||||
<TableHeader className="edit-node-modal-table-header">
|
||||
<TableRow className="">
|
||||
<TableHead className="h-7 text-center">PARAM</TableHead>
|
||||
<TableHead className="h-7 p-0 text-center">
|
||||
VALUE
|
||||
</TableHead>
|
||||
<TableHead className="h-7 text-center">SHOW</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody className="p-0">
|
||||
{Object.keys(myData.node.template)
|
||||
.filter(
|
||||
(t) =>
|
||||
t.charAt(0) !== "_" &&
|
||||
myData.node.template[t].show &&
|
||||
(myData.node.template[t].type === "str" ||
|
||||
myData.node.template[t].type === "bool" ||
|
||||
myData.node.template[t].type === "float" ||
|
||||
myData.node.template[t].type === "code" ||
|
||||
myData.node.template[t].type === "prompt" ||
|
||||
myData.node.template[t].type === "file" ||
|
||||
myData.node.template[t].type === "int")
|
||||
)
|
||||
.map((n, i) => (
|
||||
<TableRow key={i} className="h-10">
|
||||
<TableCell className="truncate p-0 text-center text-sm text-foreground sm:px-3">
|
||||
{myData.node.template[n].name
|
||||
? myData.node.template[n].name
|
||||
: myData.node.template[n].display_name}
|
||||
</TableCell>
|
||||
<TableCell className="w-[300px] p-0 text-center text-xs text-foreground ">
|
||||
{myData.node.template[n].type === "str" &&
|
||||
!myData.node.template[n].options ? (
|
||||
<div className="mx-auto">
|
||||
{myData.node.template[n].list ? (
|
||||
<InputListComponent
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
value={
|
||||
!myData.node.template[n].value ||
|
||||
myData.node.template[n].value === ""
|
||||
? [""]
|
||||
: myData.node.template[n].value
|
||||
}
|
||||
onChange={(t: string[]) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
) : myData.node.template[n].multiline ? (
|
||||
<TextAreaComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={
|
||||
myData.node.template[n].value ?? ""
|
||||
}
|
||||
onChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<InputComponent
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
password={
|
||||
myData.node.template[n].password ??
|
||||
false
|
||||
}
|
||||
value={
|
||||
myData.node.template[n].value ?? ""
|
||||
}
|
||||
onChange={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : myData.node.template[n].type === "bool" ? (
|
||||
<div className="ml-auto">
|
||||
{" "}
|
||||
<ToggleShadComponent
|
||||
disabled={disabled}
|
||||
value={
|
||||
!data.node.template[n].value ||
|
||||
data.node.template[n].value === ""
|
||||
? [""]
|
||||
: data.node.template[n].value
|
||||
}
|
||||
onChange={(t: string[]) => {
|
||||
console.log(t);
|
||||
enabled={myData.node.template[n].value}
|
||||
setEnabled={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
size="small"
|
||||
/>
|
||||
) : data.node.template[n].multiline ? (
|
||||
<TextAreaComponent
|
||||
</div>
|
||||
) : myData.node.template[n].type === "float" ? (
|
||||
<div className="mx-auto">
|
||||
<FloatComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={data.node.template[n].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<InputComponent
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
password={
|
||||
data.node.template[n].password ?? false
|
||||
}
|
||||
value={data.node.template[n].value ?? ""}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : data.node.template[n].type === "bool" ? (
|
||||
<div className="ml-auto">
|
||||
{" "}
|
||||
oi
|
||||
</div>
|
||||
) : myData.node.template[n].type === "str" &&
|
||||
myData.node.template[n].options ? (
|
||||
<div className="mx-auto">
|
||||
<Dropdown
|
||||
numberOfOptions={nodeLength}
|
||||
editNode={true}
|
||||
options={myData.node.template[n].options}
|
||||
onSelect={(t) => handleOnNewValue(t, n)}
|
||||
value={
|
||||
myData.node.template[n].value ??
|
||||
"Choose an option"
|
||||
}
|
||||
></Dropdown>
|
||||
</div>
|
||||
) : myData.node.template[n].type === "int" ? (
|
||||
<div className="mx-auto">
|
||||
<IntComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : myData.node.template[n].type === "file" ? (
|
||||
<div className="mx-auto">
|
||||
<InputFileComponent
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
fileTypes={
|
||||
myData.node.template[n].fileTypes
|
||||
}
|
||||
suffixes={myData.node.template[n].suffixes}
|
||||
onFileChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
></InputFileComponent>
|
||||
</div>
|
||||
) : myData.node.template[n].type === "prompt" ? (
|
||||
<div className="mx-auto">
|
||||
<PromptAreaComponent
|
||||
field_name={n}
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
nodeClass={myData.node}
|
||||
setNodeClass={(nodeClass) => {
|
||||
myData.node = nodeClass;
|
||||
}}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : myData.node.template[n].type === "code" ? (
|
||||
<div className="mx-auto">
|
||||
<CodeAreaComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : myData.node.template[n].type === "Any" ? (
|
||||
"-"
|
||||
) : (
|
||||
<div className="hidden"></div>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="p-0 text-right">
|
||||
<div className="items-center text-center">
|
||||
<ToggleShadComponent
|
||||
enabled={!myData.node.template[n].advanced}
|
||||
setEnabled={(e) => changeAdvanced(n)}
|
||||
disabled={disabled}
|
||||
enabled={data.node.template[n].value}
|
||||
setEnabled={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
) : data.node.template[n].type === "float" ? (
|
||||
<div className="mx-auto">
|
||||
<FloatComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={data.node.template[n].value ?? ""}
|
||||
onChange={(t) => {
|
||||
data.node.template[n].value = t;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : data.node.template[n].type === "str" &&
|
||||
data.node.template[n].options ? (
|
||||
<div className="mx-auto">
|
||||
<Dropdown
|
||||
numberOfOptions={nodeLength}
|
||||
editNode={true}
|
||||
options={data.node.template[n].options}
|
||||
onSelect={(t) => handleOnNewValue(t, n)}
|
||||
value={
|
||||
data.node.template[n].value ??
|
||||
"Choose an option"
|
||||
}
|
||||
></Dropdown>
|
||||
</div>
|
||||
) : data.node.template[n].type === "int" ? (
|
||||
<div className="mx-auto">
|
||||
<IntComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={data.node.template[n].value ?? ""}
|
||||
onChange={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : data.node.template[n].type === "file" ? (
|
||||
<div className="mx-auto">
|
||||
<InputFileComponent
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
value={data.node.template[n].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
fileTypes={data.node.template[n].fileTypes}
|
||||
suffixes={data.node.template[n].suffixes}
|
||||
onFileChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
></InputFileComponent>
|
||||
</div>
|
||||
) : data.node.template[n].type === "prompt" ? (
|
||||
<div className="mx-auto">
|
||||
<PromptAreaComponent
|
||||
field_name={n}
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
nodeClass={data.node}
|
||||
setNodeClass={(nodeClass) => {
|
||||
data.node = nodeClass;
|
||||
}}
|
||||
value={data.node.template[n].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : data.node.template[n].type === "code" ? (
|
||||
<div className="mx-auto">
|
||||
<CodeAreaComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={data.node.template[n].value ?? ""}
|
||||
onChange={(t: string) => {
|
||||
handleOnNewValue(t, n);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : data.node.template[n].type === "Any" ? (
|
||||
"-"
|
||||
) : (
|
||||
<div className="hidden"></div>
|
||||
)}
|
||||
</TableCell>
|
||||
<TableCell className="p-0 text-right">
|
||||
<div className="items-center text-center">
|
||||
<ToggleShadComponent
|
||||
enabled={!data.node.template[n].advanced}
|
||||
setEnabled={(e) =>
|
||||
changeAdvanced(data.node.template[n])
|
||||
}
|
||||
disabled={disabled}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</BaseModal.Content>
|
||||
|
||||
<DialogFooter>
|
||||
<BaseModal.Footer>
|
||||
<Button
|
||||
className="mt-3"
|
||||
onClick={() => {
|
||||
setData(cloneDeep(myData)); //saves data with actual state of modal
|
||||
setTabsState((prev) => {
|
||||
return {
|
||||
...prev,
|
||||
[tabId]: {
|
||||
...prev[tabId],
|
||||
isPending: true,
|
||||
},
|
||||
};
|
||||
});
|
||||
setModalOpen(false);
|
||||
}}
|
||||
type="submit"
|
||||
>
|
||||
Save Changes
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
</BaseModal.Footer>
|
||||
</BaseModal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default EditNodeModal;
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { ReactNode, useContext } from "react";
|
||||
import { ReactNode } from "react";
|
||||
|
||||
import React from "react";
|
||||
import {
|
||||
|
|
@ -9,12 +9,19 @@ import {
|
|||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../../components/ui/dialog";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { ContentProps, HeaderProps, headerConstType } from "../../types/components";
|
||||
import { headerConstType } from "../../types/components";
|
||||
|
||||
type ContentProps = { children: ReactNode };
|
||||
type HeaderProps = { children: ReactNode; description: string };
|
||||
type FooterProps = { children: ReactNode };
|
||||
type TriggerProps = { children: ReactNode };
|
||||
|
||||
const Content: React.FC<ContentProps> = ({ children }) => {
|
||||
return <div className="h-full w-full">{children}</div>;
|
||||
};
|
||||
const Trigger: React.FC<ContentProps> = ({ children }) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
const Header: React.FC<{ children: ReactNode; description: string }> = ({
|
||||
children,
|
||||
|
|
@ -27,36 +34,82 @@ const Header: React.FC<{ children: ReactNode; description: string }> = ({
|
|||
</DialogHeader>
|
||||
);
|
||||
};
|
||||
interface BaseModalProps {
|
||||
children: [React.ReactElement<ContentProps>, React.ReactElement<HeaderProps>];
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
}
|
||||
function BaseModal({ open, setOpen, children }: BaseModalProps): JSX.Element {
|
||||
const { closePopUp, setCloseEdit } = useContext(PopUpContext);
|
||||
|
||||
function setModalOpen(x: boolean): void {
|
||||
setOpen(x);
|
||||
if (x === false) {
|
||||
setTimeout(() => {
|
||||
setCloseEdit("editcode");
|
||||
closePopUp();
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
const Footer: React.FC<{ children: ReactNode }> = ({ children }) => {
|
||||
return <>{children}</>;
|
||||
};
|
||||
interface BaseModalProps {
|
||||
children: [
|
||||
React.ReactElement<ContentProps>,
|
||||
React.ReactElement<HeaderProps>,
|
||||
React.ReactElement<TriggerProps>?,
|
||||
React.ReactElement<FooterProps>?
|
||||
];
|
||||
open?: boolean;
|
||||
setOpen?: (open: boolean) => void;
|
||||
size?: "smaller" | "small" | "medium" | "large" | "large-h-full";
|
||||
}
|
||||
function BaseModal({
|
||||
open,
|
||||
setOpen,
|
||||
children,
|
||||
size = "large",
|
||||
}: BaseModalProps) {
|
||||
const headerChild = React.Children.toArray(children).find(
|
||||
(child) => (child as React.ReactElement).type === Header
|
||||
);
|
||||
const triggerChild = React.Children.toArray(children).find(
|
||||
(child) => (child as React.ReactElement).type === Trigger
|
||||
);
|
||||
const ContentChild = React.Children.toArray(children).find(
|
||||
(child) => (child as React.ReactElement).type === Content
|
||||
);
|
||||
const ContentFooter = React.Children.toArray(children).find(
|
||||
(child) => (child as React.ReactElement).type === Footer
|
||||
);
|
||||
|
||||
let minWidth: string;
|
||||
let height: string;
|
||||
|
||||
switch (size) {
|
||||
case "smaller":
|
||||
minWidth = "min-w-[40vw]";
|
||||
height = "h-[25vh]";
|
||||
break;
|
||||
case "small":
|
||||
minWidth = "min-w-[40vw]";
|
||||
height = "h-[40vh]";
|
||||
break;
|
||||
case "medium":
|
||||
minWidth = "min-w-[60vw]";
|
||||
height = "h-[60vh]";
|
||||
break;
|
||||
case "large":
|
||||
minWidth = "min-w-[80vw]";
|
||||
height = "h-[80vh]";
|
||||
break;
|
||||
case "large-h-full":
|
||||
minWidth = "min-w-[80vw]";
|
||||
break;
|
||||
default:
|
||||
minWidth = "min-w-[80vw]";
|
||||
height = "h-[80vh]";
|
||||
break;
|
||||
}
|
||||
|
||||
//UPDATE COLORS AND STYLE CLASSSES
|
||||
return (
|
||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||
<DialogTrigger className="hidden"></DialogTrigger>
|
||||
<DialogContent className="min-w-[80vw]">
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger className="w-full" hidden={triggerChild ? false : true}>
|
||||
{triggerChild}
|
||||
</DialogTrigger>
|
||||
<DialogContent className={minWidth}>
|
||||
{headerChild}
|
||||
<div className="mt-2 flex h-[80vh] w-full ">{ContentChild}</div>
|
||||
<div className={`mt-2 flex flex-col ${height} w-full `}>
|
||||
{ContentChild}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-row-reverse">{ContentFooter}</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
|
|
@ -64,4 +117,6 @@ function BaseModal({ open, setOpen, children }: BaseModalProps): JSX.Element {
|
|||
|
||||
BaseModal.Content = Content;
|
||||
BaseModal.Header = Header;
|
||||
BaseModal.Trigger = Trigger;
|
||||
BaseModal.Footer = Footer;
|
||||
export default BaseModal;
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
import { DialogTitle } from "@radix-ui/react-dialog";
|
||||
import "ace-builds/src-noconflict/ace";
|
||||
import "ace-builds/src-noconflict/ext-language_tools";
|
||||
import "ace-builds/src-noconflict/mode-python";
|
||||
import "ace-builds/src-noconflict/theme-github";
|
||||
import "ace-builds/src-noconflict/theme-twilight";
|
||||
import { useContext, useState } from "react";
|
||||
import { ReactNode, useContext, useState } from "react";
|
||||
import AceEditor from "react-ace";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { CODE_PROMPT_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { postValidateCode } from "../../controllers/API";
|
||||
import { APIClassType } from "../../types/api";
|
||||
import BaseModal from "../baseModal";
|
||||
|
|
@ -22,21 +20,13 @@ export default function CodeAreaModal({
|
|||
setValue,
|
||||
nodeClass,
|
||||
setNodeClass,
|
||||
children,
|
||||
}: codeAreaModalPropsType): JSX.Element {
|
||||
const [code, setCode] = useState(value);
|
||||
const { dark } = useContext(darkContext);
|
||||
const { closePopUp, setCloseEdit } = useContext(PopUpContext);
|
||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||
|
||||
function setModalOpen(x: boolean): void {
|
||||
if (x === false) {
|
||||
setCloseEdit("codearea");
|
||||
closePopUp();
|
||||
}
|
||||
}
|
||||
|
||||
// Check for custom code errors
|
||||
function handleClick(): void {
|
||||
function handleClick() {
|
||||
postValidateCode(code)
|
||||
.then((apiReturn) => {
|
||||
if (apiReturn.data) {
|
||||
|
|
@ -47,7 +37,7 @@ export default function CodeAreaModal({
|
|||
title: "Code is ready to run",
|
||||
});
|
||||
setValue(code);
|
||||
setModalOpen(false);
|
||||
setOpen(false);
|
||||
} else {
|
||||
if (funcErrors.length !== 0) {
|
||||
setErrorData({
|
||||
|
|
@ -75,17 +65,18 @@ export default function CodeAreaModal({
|
|||
});
|
||||
}
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<BaseModal open={true} setOpen={setModalOpen}>
|
||||
<BaseModal open={open} setOpen={setOpen}>
|
||||
<BaseModal.Trigger>{children}</BaseModal.Trigger>
|
||||
<BaseModal.Header description={CODE_PROMPT_DIALOG_SUBTITLE}>
|
||||
<DialogTitle className="flex items-center">
|
||||
<span className="pr-2">Edit Code</span>
|
||||
<IconComponent
|
||||
name="prompts"
|
||||
className="h-6 w-6 pl-1 text-primary "
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</DialogTitle>
|
||||
<span className="pr-2">Edit Code</span>
|
||||
<IconComponent
|
||||
name="prompts"
|
||||
className="h-6 w-6 pl-1 text-primary "
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<div className="flex h-full w-full flex-col transition-all">
|
||||
|
|
|
|||
|
|
@ -1,60 +1,34 @@
|
|||
import { useContext, useRef, useState } from "react";
|
||||
import { ReactNode, forwardRef, useContext, useState } from "react";
|
||||
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { Checkbox } from "../../components/ui/checkbox";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../../components/ui/dialog";
|
||||
import { EXPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { removeApiKeys } from "../../utils/reactflowUtils";
|
||||
import BaseModal from "../baseModal";
|
||||
|
||||
export default function ExportModal(): JSX.Element {
|
||||
const [open, setOpen] = useState(true);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
const ref = useRef();
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
const ExportModal = forwardRef((props: { children: ReactNode }, ref): JSX.Element => {
|
||||
const { flows, tabId, updateFlow, downloadFlow, saveFlow } =
|
||||
useContext(TabsContext);
|
||||
const [isMaxLength, setIsMaxLength] = useState(false);
|
||||
function setModalOpen(x: boolean): void {
|
||||
setOpen(x);
|
||||
if (x === false) {
|
||||
setTimeout(() => {
|
||||
closePopUp();
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
const [checked, setChecked] = useState(false);
|
||||
const [name, setName] = useState(flows.find((f) => f.id === tabId).name);
|
||||
const [description, setDescription] = useState(
|
||||
flows.find((f) => f.id === tabId).description
|
||||
);
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||
<DialogTrigger asChild></DialogTrigger>
|
||||
<DialogContent className="h-[420px] lg:max-w-[600px] ">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center">
|
||||
<span className="pr-2">Export</span>
|
||||
<IconComponent
|
||||
name="Download"
|
||||
className="h-6 w-6 pl-1 text-foreground"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</DialogTitle>
|
||||
<DialogDescription>{EXPORT_DIALOG_SUBTITLE}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<BaseModal size="smaller" open={open} setOpen={setOpen}>
|
||||
<BaseModal.Trigger>{props.children}</BaseModal.Trigger>
|
||||
<BaseModal.Header description={EXPORT_DIALOG_SUBTITLE}>
|
||||
<span className="pr-2">Export</span>
|
||||
<IconComponent
|
||||
name="Download"
|
||||
className="h-6 w-6 pl-1 text-foreground"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<EditFlowSettings
|
||||
name={name}
|
||||
description={description}
|
||||
|
|
@ -64,42 +38,42 @@ export default function ExportModal(): JSX.Element {
|
|||
setDescription={setDescription}
|
||||
updateFlow={updateFlow}
|
||||
/>
|
||||
<div className="flex items-center space-x-2">
|
||||
<div className="mt-3 flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id="terms"
|
||||
onCheckedChange={(event: boolean): void => {
|
||||
setChecked(event);
|
||||
}}
|
||||
/>
|
||||
<label htmlFor="terms" className="export-modal-save-api text-sm">
|
||||
<label htmlFor="terms" className="export-modal-save-api text-sm ">
|
||||
Save with my API keys
|
||||
</label>
|
||||
</div>
|
||||
</BaseModal.Content>
|
||||
|
||||
<DialogFooter>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (checked)
|
||||
downloadFlow(
|
||||
flows.find((f) => f.id === tabId),
|
||||
name,
|
||||
description
|
||||
);
|
||||
else
|
||||
downloadFlow(
|
||||
removeApiKeys(flows.find((f) => f.id === tabId)),
|
||||
name,
|
||||
description
|
||||
);
|
||||
|
||||
closePopUp();
|
||||
}}
|
||||
type="submit"
|
||||
>
|
||||
Download Flow
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<BaseModal.Footer>
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (checked)
|
||||
downloadFlow(
|
||||
flows.find((f) => f.id === tabId),
|
||||
name,
|
||||
description
|
||||
);
|
||||
else
|
||||
downloadFlow(
|
||||
removeApiKeys(flows.find((f) => f.id === tabId)),
|
||||
name,
|
||||
description
|
||||
);
|
||||
setOpen(false);
|
||||
}}
|
||||
type="submit"
|
||||
>
|
||||
Download Flow
|
||||
</Button>
|
||||
</BaseModal.Footer>
|
||||
</BaseModal>
|
||||
);
|
||||
}
|
||||
});
|
||||
export default ExportModal;
|
||||
|
|
|
|||
|
|
@ -2,23 +2,16 @@ import { useContext, useRef, useState } from "react";
|
|||
import EditFlowSettings from "../../components/EditFlowSettingsComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogDescription,
|
||||
DialogFooter,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
DialogTrigger,
|
||||
} from "../../components/ui/dialog";
|
||||
import { SETTINGS_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import BaseModal from "../baseModal";
|
||||
import { FlowSettingsPropsType } from "../../types/components";
|
||||
|
||||
export default function FlowSettingsModal(): JSX.Element {
|
||||
const [open, setOpen] = useState(true);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
export default function FlowSettingsModal({
|
||||
open,
|
||||
setOpen,
|
||||
}: FlowSettingsPropsType): JSX.Element {
|
||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||
const ref = useRef();
|
||||
const { flows, tabId, updateFlow, setTabsState, saveFlow } =
|
||||
|
|
@ -28,34 +21,21 @@ export default function FlowSettingsModal(): JSX.Element {
|
|||
const [description, setDescription] = useState(
|
||||
flows.find((f) => f.id === tabId).description
|
||||
);
|
||||
function setModalOpen(x: boolean): void {
|
||||
setOpen(x);
|
||||
if (x === false) {
|
||||
setTimeout(() => {
|
||||
closePopUp();
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
function handleClick(): void {
|
||||
let savedFlow = flows.find((f) => f.id === tabId);
|
||||
savedFlow.name = name;
|
||||
savedFlow.description = description;
|
||||
saveFlow(savedFlow);
|
||||
setSuccessData({ title: "Changes saved successfully" });
|
||||
closePopUp();
|
||||
setOpen(false);
|
||||
}
|
||||
return (
|
||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||
<DialogTrigger asChild></DialogTrigger>
|
||||
<DialogContent className="h-[390px] lg:max-w-[600px]">
|
||||
<DialogHeader>
|
||||
<DialogTitle className="flex items-center">
|
||||
<span className="pr-2">Settings </span>
|
||||
<IconComponent name="Settings2" className="mr-2 h-4 w-4 " />
|
||||
</DialogTitle>
|
||||
<DialogDescription>{SETTINGS_DIALOG_SUBTITLE}</DialogDescription>
|
||||
</DialogHeader>
|
||||
|
||||
<BaseModal open={open} setOpen={setOpen} size="smaller">
|
||||
<BaseModal.Header description={SETTINGS_DIALOG_SUBTITLE}>
|
||||
<span className="pr-2">Settings</span>
|
||||
<IconComponent name="Settings2" className="mr-2 h-4 w-4 " />
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<EditFlowSettings
|
||||
name={name}
|
||||
description={description}
|
||||
|
|
@ -65,13 +45,13 @@ export default function FlowSettingsModal(): JSX.Element {
|
|||
setDescription={setDescription}
|
||||
updateFlow={updateFlow}
|
||||
/>
|
||||
</BaseModal.Content>
|
||||
|
||||
<DialogFooter>
|
||||
<Button onClick={handleClick} type="submit">
|
||||
Save
|
||||
</Button>
|
||||
</DialogFooter>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
<BaseModal.Footer>
|
||||
<Button onClick={handleClick} type="submit">
|
||||
Save
|
||||
</Button>
|
||||
</BaseModal.Footer>
|
||||
</BaseModal>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { useEffect } from "react";
|
||||
import IconComponent from "../../../components/genericIconComponent";
|
||||
import { chatInputType } from "../../../types/components";
|
||||
import { Textarea } from "../../../components/ui/textarea";
|
||||
import { classNames } from "../../../utils/utils";
|
||||
|
||||
export default function ChatInput({
|
||||
|
|
@ -26,8 +27,8 @@ export default function ChatInput({
|
|||
|
||||
return (
|
||||
<div className="relative">
|
||||
<textarea
|
||||
onKeyDown={(event): void => {
|
||||
<Textarea
|
||||
onKeyDown={(event) => {
|
||||
if (event.key === "Enter" && !lockChat && !event.shiftKey) {
|
||||
sendMessage();
|
||||
}
|
||||
|
|
@ -69,10 +70,10 @@ export default function ChatInput({
|
|||
className={classNames(
|
||||
"form-modal-send-button",
|
||||
noInput
|
||||
? "bg-indigo-600 text-background"
|
||||
? "bg-high-indigo text-background"
|
||||
: chatValue === ""
|
||||
? "text-primary"
|
||||
: "bg-emerald-600 text-background"
|
||||
: "bg-chat-send text-background"
|
||||
)}
|
||||
disabled={lockChat}
|
||||
onClick={(): void => sendMessage()}
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@ import remarkMath from "remark-math";
|
|||
import MaleTechnology from "../../../assets/male-technologist.png";
|
||||
import Robot from "../../../assets/robot.png";
|
||||
import SanitizedHTMLWrapper from "../../../components/SanitizedHTMLWrapper";
|
||||
import CodeTabsComponent from "../../../components/codeTabsComponent";
|
||||
import IconComponent from "../../../components/genericIconComponent";
|
||||
import { ChatMessageType } from "../../../types/chat";
|
||||
import { classNames } from "../../../utils/utils";
|
||||
import FileCard from "../fileComponent";
|
||||
import { CodeBlock } from "./codeBlock";
|
||||
import { chatMessagePropsType } from "../../../types/components";
|
||||
|
||||
export default function ChatMessage({
|
||||
chat,
|
||||
lockChat,
|
||||
|
|
@ -75,57 +76,75 @@ export default function ChatMessage({
|
|||
<div className="w-full dark:text-white">
|
||||
<div className="w-full">
|
||||
{useMemo(
|
||||
() => (
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
rehypePlugins={[rehypeMathjax]}
|
||||
className="markdown prose inline-block break-words text-primary
|
||||
dark:prose-invert sm:w-[30vw] sm:max-w-[30vw] lg:w-[40vw] lg:max-w-[40vw]"
|
||||
components={{
|
||||
code: ({
|
||||
node,
|
||||
inline,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
if (children.length) {
|
||||
if (children[0] === "▍") {
|
||||
return (
|
||||
<span className="form-modal-markdown-span">
|
||||
▍
|
||||
</span>
|
||||
() =>
|
||||
chat.message.toString() === "" && lockChat ? (
|
||||
<IconComponent
|
||||
name="MoreHorizontal"
|
||||
className="h-8 w-8 animate-pulse"
|
||||
/>
|
||||
) : (
|
||||
<ReactMarkdown
|
||||
remarkPlugins={[remarkGfm, remarkMath]}
|
||||
rehypePlugins={[rehypeMathjax]}
|
||||
className="markdown prose inline-block break-words text-primary dark:prose-invert
|
||||
sm:w-[30vw] sm:max-w-[30vw] lg:w-[40vw] lg:max-w-[40vw]"
|
||||
components={{
|
||||
pre({ node, ...props }) {
|
||||
return <>{props.children}</>;
|
||||
},
|
||||
code: ({
|
||||
node,
|
||||
inline,
|
||||
className,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
if (children.length) {
|
||||
if (children[0] === "▍") {
|
||||
return (
|
||||
<span className="form-modal-markdown-span">
|
||||
▍
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
children[0] = (children[0] as string).replace(
|
||||
"`▍`",
|
||||
"▍"
|
||||
);
|
||||
}
|
||||
|
||||
children[0] = (children[0] as string).replace(
|
||||
"`▍`",
|
||||
"▍"
|
||||
const match = /language-(\w+)/.exec(
|
||||
className || ""
|
||||
);
|
||||
}
|
||||
|
||||
const match = /language-(\w+)/.exec(
|
||||
className || ""
|
||||
);
|
||||
|
||||
return !inline ? (
|
||||
<CodeBlock
|
||||
key={Math.random()}
|
||||
language={(match && match[1]) || ""}
|
||||
value={String(children).replace(/\n$/, "")}
|
||||
{...props}
|
||||
/>
|
||||
) : (
|
||||
<code className={className} {...props}>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{chat.message.toString()}
|
||||
</ReactMarkdown>
|
||||
),
|
||||
return !inline ? (
|
||||
<CodeTabsComponent
|
||||
isMessage
|
||||
tabs={[
|
||||
{
|
||||
name: (match && match[1]) || "",
|
||||
mode: (match && match[1]) || "",
|
||||
image:
|
||||
"https://curl.se/logo/curl-symbol-transparent.png",
|
||||
language: (match && match[1]) || "",
|
||||
code: String(children).replace(/\n$/, ""),
|
||||
},
|
||||
]}
|
||||
activeTab={"0"}
|
||||
setActiveTab={() => {}}
|
||||
/>
|
||||
) : (
|
||||
<code className={className} {...props}>
|
||||
{children}
|
||||
</code>
|
||||
);
|
||||
},
|
||||
}}
|
||||
>
|
||||
{chat.message.toString()}
|
||||
</ReactMarkdown>
|
||||
),
|
||||
[chat.message, chat.message.toString()]
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ export default function FormModal({
|
|||
setOpen,
|
||||
}: {
|
||||
open: boolean;
|
||||
setOpen: Function;
|
||||
setOpen: (open: boolean) => void;
|
||||
flow: FlowType;
|
||||
}): JSX.Element {
|
||||
const { tabsState, setTabsState } = useContext(TabsContext);
|
||||
|
|
@ -389,8 +389,8 @@ export default function FormModal({
|
|||
}
|
||||
|
||||
return (
|
||||
<Dialog open={open} onOpenChange={setModalOpen}>
|
||||
<DialogTrigger className="hidden"></DialogTrigger>
|
||||
<Dialog open={open} onOpenChange={setOpen}>
|
||||
<DialogTrigger hidden></DialogTrigger>
|
||||
{tabsState[flow.id].formKeysData && (
|
||||
<DialogContent className="min-w-[80vw]">
|
||||
<DialogHeader>
|
||||
|
|
@ -398,7 +398,7 @@ export default function FormModal({
|
|||
<span className="pr-2">Chat</span>
|
||||
<IconComponent
|
||||
name="prompts"
|
||||
className="h-6 w-6 pl-1 text-gray-800 dark:text-white"
|
||||
className="h-6 w-6 pl-1 text-foreground"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</DialogTitle>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import { ReactNode, useContext, useEffect, useRef, useState } from "react";
|
||||
import SanitizedHTMLWrapper from "../../components/SanitizedHTMLWrapper";
|
||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import { Badge } from "../../components/ui/badge";
|
||||
import { Button } from "../../components/ui/button";
|
||||
import { DialogTitle } from "../../components/ui/dialog";
|
||||
import { Textarea } from "../../components/ui/textarea";
|
||||
import {
|
||||
INVALID_CHARACTERS,
|
||||
|
|
@ -15,8 +14,6 @@ import {
|
|||
} from "../../constants/constants";
|
||||
import { TypeModal } from "../../constants/enums";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { postValidatePrompt } from "../../controllers/API";
|
||||
import { APIClassType } from "../../types/api";
|
||||
import {
|
||||
|
|
@ -36,6 +33,7 @@ export default function GenericModal({
|
|||
type,
|
||||
nodeClass,
|
||||
setNodeClass,
|
||||
children,
|
||||
}: genericModalPropsType): JSX.Element {
|
||||
const [myButtonText] = useState(buttonText);
|
||||
const [myModalTitle] = useState(modalTitle);
|
||||
|
|
@ -43,17 +41,9 @@ export default function GenericModal({
|
|||
const [inputValue, setInputValue] = useState(value);
|
||||
const [isEdit, setIsEdit] = useState(true);
|
||||
const [wordsHighlight, setWordsHighlight] = useState([]);
|
||||
const { dark } = useContext(darkContext);
|
||||
const { setErrorData, setSuccessData, setNoticeData } =
|
||||
useContext(alertContext);
|
||||
const { closePopUp, setCloseEdit } = useContext(PopUpContext);
|
||||
const ref = useRef();
|
||||
function setModalOpen(x: boolean): void {
|
||||
if (x === false) {
|
||||
setCloseEdit("generic");
|
||||
closePopUp();
|
||||
}
|
||||
}
|
||||
const divRef = useRef(null);
|
||||
const divRefPrompt = useRef(null);
|
||||
|
||||
|
|
@ -97,6 +87,10 @@ export default function GenericModal({
|
|||
}
|
||||
}, [inputValue, type]);
|
||||
|
||||
useEffect(() => {
|
||||
setInputValue(value);
|
||||
}, [value]);
|
||||
|
||||
const coloredContent = (inputValue || "")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
|
|
@ -130,7 +124,6 @@ export default function GenericModal({
|
|||
postValidatePrompt(field_name, inputValue, nodeClass)
|
||||
.then((apiReturn) => {
|
||||
if (apiReturn.data) {
|
||||
setNodeClass(apiReturn.data?.frontend_node);
|
||||
let inputVariables = apiReturn.data.input_variables ?? [];
|
||||
if (inputVariables && inputVariables.length === 0) {
|
||||
setIsEdit(true);
|
||||
|
|
@ -142,6 +135,7 @@ export default function GenericModal({
|
|||
setSuccessData({
|
||||
title: "Prompt is ready",
|
||||
});
|
||||
setNodeClass(apiReturn.data?.frontend_node);
|
||||
setModalOpen(closeModal);
|
||||
setValue(inputValue);
|
||||
}
|
||||
|
|
@ -162,8 +156,11 @@ export default function GenericModal({
|
|||
});
|
||||
}
|
||||
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<BaseModal open={true} setOpen={setModalOpen}>
|
||||
<BaseModal open={modalOpen} setOpen={setModalOpen}>
|
||||
<BaseModal.Trigger>{children}</BaseModal.Trigger>
|
||||
<BaseModal.Header
|
||||
description={(() => {
|
||||
switch (myModalTitle) {
|
||||
|
|
@ -178,14 +175,12 @@ export default function GenericModal({
|
|||
}
|
||||
})()}
|
||||
>
|
||||
<DialogTitle className="flex items-center">
|
||||
<span className="pr-2">{myModalTitle}</span>
|
||||
<IconComponent
|
||||
name="FileText"
|
||||
className="h-6 w-6 pl-1 text-primary "
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</DialogTitle>
|
||||
<span className="pr-2">{myModalTitle}</span>
|
||||
<IconComponent
|
||||
name="FileText"
|
||||
className="h-6 w-6 pl-1 text-primary "
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<div className="flex h-full flex-col">
|
||||
|
|
@ -269,7 +264,7 @@ export default function GenericModal({
|
|||
))}
|
||||
</div>
|
||||
</div>
|
||||
<span className="mt-1 text-xs text-muted-foreground">
|
||||
<span className="mt-2 text-xs text-muted-foreground">
|
||||
Prompt variables can be created with any chosen name inside
|
||||
curly brackets, e.g. {"{variable_name}"}
|
||||
</span>
|
||||
|
|
@ -279,11 +274,11 @@ export default function GenericModal({
|
|||
<Button
|
||||
onClick={() => {
|
||||
switch (myModalType) {
|
||||
case 1:
|
||||
case TypeModal.TEXT:
|
||||
setValue(inputValue);
|
||||
setModalOpen(false);
|
||||
break;
|
||||
case 2:
|
||||
case TypeModal.PROMPT:
|
||||
!inputValue || inputValue === ""
|
||||
? setModalOpen(false)
|
||||
: validatePrompt(false);
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@ import {
|
|||
} from "../../components/ui/dialog";
|
||||
import { IMPORT_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { PopUpContext } from "../../contexts/popUpContext";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { getExamples } from "../../controllers/API";
|
||||
import { FlowType } from "../../types/flow";
|
||||
|
|
@ -27,20 +26,11 @@ import ButtonBox from "./buttonBox";
|
|||
export default function ImportModal(): JSX.Element {
|
||||
const [open, setOpen] = useState(true);
|
||||
const { setErrorData } = useContext(alertContext);
|
||||
const { closePopUp } = useContext(PopUpContext);
|
||||
const ref = useRef();
|
||||
const [showExamples, setShowExamples] = useState(false);
|
||||
const [loadingExamples, setLoadingExamples] = useState(false);
|
||||
const [examples, setExamples] = useState<FlowType[]>([]);
|
||||
const { uploadFlow, addFlow } = useContext(TabsContext);
|
||||
function setModalOpen(x: boolean): void {
|
||||
setOpen(x);
|
||||
if (x === false) {
|
||||
setTimeout(() => {
|
||||
closePopUp();
|
||||
}, 300);
|
||||
}
|
||||
}
|
||||
|
||||
function handleExamples(): void {
|
||||
setLoadingExamples(true);
|
||||
|
|
@ -57,8 +47,10 @@ export default function ImportModal(): JSX.Element {
|
|||
);
|
||||
}
|
||||
|
||||
const [modalOpen, setModalOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<Dialog open={true} onOpenChange={setModalOpen}>
|
||||
<Dialog open={modalOpen} onOpenChange={setModalOpen}>
|
||||
<DialogTrigger></DialogTrigger>
|
||||
<DialogContent
|
||||
className={classNames(
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
|||
import { APIClassType } from "../../../../types/api";
|
||||
import { FlowType, NodeType } from "../../../../types/flow";
|
||||
import { isValidConnection } from "../../../../utils/reactflowUtils";
|
||||
import { isWrappedWithClass } from "../../../../utils/utils";
|
||||
import ConnectionLineComponent from "../ConnectionLineComponent";
|
||||
import ExtraSidebar from "../extraSidebarComponent";
|
||||
|
||||
|
|
@ -38,7 +39,6 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
let {
|
||||
updateFlow,
|
||||
uploadFlow,
|
||||
disableCopyPaste,
|
||||
addFlow,
|
||||
getNodeId,
|
||||
paste,
|
||||
|
|
@ -63,34 +63,34 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
// this effect is used to attach the global event handlers
|
||||
|
||||
const onKeyDown = (event: KeyboardEvent) => {
|
||||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "c" &&
|
||||
lastSelection &&
|
||||
!disableCopyPaste
|
||||
) {
|
||||
event.preventDefault();
|
||||
setLastCopiedSelection(_.cloneDeep(lastSelection));
|
||||
}
|
||||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "v" &&
|
||||
lastCopiedSelection &&
|
||||
!disableCopyPaste
|
||||
) {
|
||||
event.preventDefault();
|
||||
let bounds = reactFlowWrapper.current.getBoundingClientRect();
|
||||
paste(lastCopiedSelection, {
|
||||
x: position.x - bounds.left,
|
||||
y: position.y - bounds.top,
|
||||
});
|
||||
}
|
||||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "g" &&
|
||||
lastSelection
|
||||
) {
|
||||
event.preventDefault();
|
||||
if (!isWrappedWithClass(event, "nocopy")) {
|
||||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "c" &&
|
||||
lastSelection
|
||||
) {
|
||||
event.preventDefault();
|
||||
setLastCopiedSelection(_.cloneDeep(lastSelection));
|
||||
}
|
||||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "v" &&
|
||||
lastCopiedSelection
|
||||
) {
|
||||
event.preventDefault();
|
||||
let bounds = reactFlowWrapper.current.getBoundingClientRect();
|
||||
paste(lastCopiedSelection, {
|
||||
x: position.x - bounds.left,
|
||||
y: position.y - bounds.top,
|
||||
});
|
||||
}
|
||||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key === "g" &&
|
||||
lastSelection
|
||||
) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
};
|
||||
const handleMouseMove = (event: MouseEvent) => {
|
||||
|
|
@ -124,7 +124,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
updateFlow(flow);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [nodes, edges]);
|
||||
}, [edges]);
|
||||
//update flow when tabs change
|
||||
useEffect(() => {
|
||||
setNodes(flow?.data?.nodes ?? []);
|
||||
|
|
@ -355,8 +355,6 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
setLastSelection(flow);
|
||||
}, []);
|
||||
|
||||
const { setDisableCopyPaste } = useContext(TabsContext);
|
||||
|
||||
return (
|
||||
<div className="flex h-full overflow-hidden">
|
||||
<ExtraSidebar />
|
||||
|
|
@ -378,15 +376,6 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
});
|
||||
}}
|
||||
edges={edges}
|
||||
onPaneClick={() => {
|
||||
setDisableCopyPaste(false);
|
||||
}}
|
||||
onPaneMouseLeave={() => {
|
||||
setDisableCopyPaste(true);
|
||||
}}
|
||||
onPaneMouseEnter={() => {
|
||||
setDisableCopyPaste(false);
|
||||
}}
|
||||
onNodesChange={onNodesChangeMod}
|
||||
onEdgesChange={onEdgesChangeMod}
|
||||
onConnect={onConnect}
|
||||
|
|
@ -407,9 +396,6 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
onDrop={onDrop}
|
||||
onNodesDelete={onDelete}
|
||||
onSelectionChange={onSelectionChange}
|
||||
nodesDraggable={!disableCopyPaste}
|
||||
panOnDrag={!disableCopyPaste}
|
||||
zoomOnDoubleClick={!disableCopyPaste}
|
||||
className="theme-attribution"
|
||||
minZoom={0.01}
|
||||
maxZoom={8}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import { Search } from "lucide-react";
|
||||
import { useContext, useState } from "react";
|
||||
import ShadTooltip from "../../../../components/ShadTooltipComponent";
|
||||
import IconComponent from "../../../../components/genericIconComponent";
|
||||
import { Input } from "../../../../components/ui/input";
|
||||
import { Separator } from "../../../../components/ui/separator";
|
||||
import { alertContext } from "../../../../contexts/alertContext";
|
||||
import { PopUpContext } from "../../../../contexts/popUpContext";
|
||||
import { TabsContext } from "../../../../contexts/tabsContext";
|
||||
import { typesContext } from "../../../../contexts/typesContext";
|
||||
import ApiModal from "../../../../modals/ApiModal";
|
||||
|
|
@ -20,7 +19,6 @@ import DisclosureComponent from "../DisclosureComponent";
|
|||
|
||||
export default function ExtraSidebar(): JSX.Element {
|
||||
const { data } = useContext(typesContext);
|
||||
const { openPopUp } = useContext(PopUpContext);
|
||||
const { flows, tabId, uploadFlow, tabsState, saveFlow } =
|
||||
useContext(TabsContext);
|
||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||
|
|
@ -58,6 +56,7 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
return ret;
|
||||
});
|
||||
}
|
||||
const flow = flows.find((f) => f.id === tabId);
|
||||
|
||||
return (
|
||||
<div className="side-bar-arrangement">
|
||||
|
|
@ -74,31 +73,27 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
</ShadTooltip>
|
||||
|
||||
<ShadTooltip content="Export" side="top">
|
||||
<button
|
||||
className={classNames("extra-side-bar-buttons")}
|
||||
onClick={(event): void => {
|
||||
openPopUp(<ExportModal />);
|
||||
}}
|
||||
>
|
||||
<IconComponent name="FileDown" className="side-bar-button-size" />
|
||||
</button>
|
||||
<ExportModal>
|
||||
<div className={classNames("extra-side-bar-buttons")}>
|
||||
<IconComponent name="FileDown" className="side-bar-button-size" />
|
||||
</div>
|
||||
</ExportModal>
|
||||
</ShadTooltip>
|
||||
<ShadTooltip content="Code" side="top">
|
||||
<button
|
||||
className={classNames("extra-side-bar-buttons")}
|
||||
onClick={(event): void => {
|
||||
openPopUp(<ApiModal flow={flows.find((f) => f.id === tabId)} />);
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Code2" className="side-bar-button-size" />
|
||||
</button>
|
||||
{flow && flow.data && (
|
||||
<ApiModal flow={flow}>
|
||||
<div className={classNames("extra-side-bar-buttons")}>
|
||||
<IconComponent name="Code2" className="side-bar-button-size" />
|
||||
</div>
|
||||
</ApiModal>
|
||||
)}
|
||||
</ShadTooltip>
|
||||
|
||||
<ShadTooltip content="Save" side="top">
|
||||
<button
|
||||
className="extra-side-bar-buttons"
|
||||
onClick={(event): void => {
|
||||
saveFlow(flows.find((f) => f.id === tabId));
|
||||
onClick={(event) => {
|
||||
saveFlow(flow);
|
||||
setSuccessData({ title: "Changes saved successfully" });
|
||||
}}
|
||||
disabled={!isPending}
|
||||
|
|
@ -115,12 +110,12 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
</div>
|
||||
<Separator />
|
||||
<div className="side-bar-search-div-placement">
|
||||
<input
|
||||
<Input
|
||||
type="text"
|
||||
name="search"
|
||||
id="search"
|
||||
placeholder="Search"
|
||||
className="input-search"
|
||||
className="nopan nodrag noundo nocopy input-search"
|
||||
onChange={(e) => {
|
||||
handleSearchInput(e.target.value);
|
||||
// Set search input state
|
||||
|
|
@ -128,7 +123,11 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
}}
|
||||
/>
|
||||
<div className="search-icon">
|
||||
<Search size={20} strokeWidth={1.5} className="text-primary" />
|
||||
<IconComponent
|
||||
name="Search"
|
||||
className={"h-5 w-5 stroke-[1.5] text-primary"}
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -7,24 +7,24 @@ import EditNodeModal from "../../../../modals/EditNodeModal";
|
|||
import { nodeToolbarPropsType } from "../../../../types/components";
|
||||
import { classNames } from "../../../../utils/utils";
|
||||
|
||||
const NodeToolbarComponent = (props: nodeToolbarPropsType): JSX.Element => {
|
||||
export default function NodeToolbarComponent({ data, setData, deleteNode }: nodeToolbarPropsType): JSX.Element {
|
||||
const [nodeLength, setNodeLength] = useState(
|
||||
Object.keys(props.data.node.template).filter(
|
||||
Object.keys(data.node.template).filter(
|
||||
(t) =>
|
||||
t.charAt(0) !== "_" &&
|
||||
props.data.node.template[t].show &&
|
||||
(props.data.node.template[t].type === "str" ||
|
||||
props.data.node.template[t].type === "bool" ||
|
||||
props.data.node.template[t].type === "float" ||
|
||||
props.data.node.template[t].type === "code" ||
|
||||
props.data.node.template[t].type === "prompt" ||
|
||||
props.data.node.template[t].type === "file" ||
|
||||
props.data.node.template[t].type === "Any" ||
|
||||
props.data.node.template[t].type === "int")
|
||||
data.node.template[t].show &&
|
||||
(data.node.template[t].type === "str" ||
|
||||
data.node.template[t].type === "bool" ||
|
||||
data.node.template[t].type === "float" ||
|
||||
data.node.template[t].type === "code" ||
|
||||
data.node.template[t].type === "prompt" ||
|
||||
data.node.template[t].type === "file" ||
|
||||
data.node.template[t].type === "Any" ||
|
||||
data.node.template[t].type === "int")
|
||||
).length
|
||||
);
|
||||
|
||||
const { setLastCopiedSelection, paste } = useContext(TabsContext);
|
||||
const { paste } = useContext(TabsContext);
|
||||
const reactFlowInstance = useReactFlow();
|
||||
return (
|
||||
<>
|
||||
|
|
@ -34,7 +34,7 @@ const NodeToolbarComponent = (props: nodeToolbarPropsType): JSX.Element => {
|
|||
<button
|
||||
className="relative inline-flex items-center rounded-l-md bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10"
|
||||
onClick={() => {
|
||||
props.deleteNode(props.data.id);
|
||||
deleteNode(data.id);
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Trash2" className="h-4 w-4" />
|
||||
|
|
@ -50,14 +50,14 @@ const NodeToolbarComponent = (props: nodeToolbarPropsType): JSX.Element => {
|
|||
event.preventDefault();
|
||||
paste(
|
||||
{
|
||||
nodes: [reactFlowInstance.getNode(props.data.id)],
|
||||
nodes: [reactFlowInstance.getNode(data.id)],
|
||||
edges: [],
|
||||
},
|
||||
{
|
||||
x: 50,
|
||||
y: 10,
|
||||
paneX: reactFlowInstance.getNode(props.data.id).position.x,
|
||||
paneY: reactFlowInstance.getNode(props.data.id).position.y,
|
||||
paneX: reactFlowInstance.getNode(data.id).position.x,
|
||||
paneY: reactFlowInstance.getNode(data.id).position.y,
|
||||
}
|
||||
);
|
||||
}}
|
||||
|
|
@ -68,25 +68,23 @@ const NodeToolbarComponent = (props: nodeToolbarPropsType): JSX.Element => {
|
|||
|
||||
<ShadTooltip
|
||||
content={
|
||||
props.data.node.documentation === ""
|
||||
? "Coming Soon"
|
||||
: "Documentation"
|
||||
data.node.documentation === "" ? "Coming Soon" : "Documentation"
|
||||
}
|
||||
side="top"
|
||||
>
|
||||
<a
|
||||
className={classNames(
|
||||
"relative -ml-px inline-flex items-center bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" +
|
||||
(props.data.node.documentation === ""
|
||||
(data.node.documentation === ""
|
||||
? " text-muted-foreground"
|
||||
: " text-foreground")
|
||||
)}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={props.data.node.documentation}
|
||||
href={data.node.documentation}
|
||||
// deactivate link if no documentation is provided
|
||||
onClick={(event) => {
|
||||
if (props.data.node.documentation === "") {
|
||||
if (data.node.documentation === "") {
|
||||
event.preventDefault();
|
||||
}
|
||||
}}
|
||||
|
|
@ -96,28 +94,27 @@ const NodeToolbarComponent = (props: nodeToolbarPropsType): JSX.Element => {
|
|||
</ShadTooltip>
|
||||
|
||||
<ShadTooltip content="Edit" side="top">
|
||||
<button
|
||||
className={classNames(
|
||||
"relative -ml-px inline-flex items-center rounded-r-md bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" +
|
||||
(nodeLength == 0
|
||||
? " text-muted-foreground"
|
||||
: " text-foreground")
|
||||
)}
|
||||
onClick={(event) => {
|
||||
if (nodeLength == 0) {
|
||||
event.preventDefault();
|
||||
}
|
||||
event.preventDefault();
|
||||
props.openPopUp(<EditNodeModal data={props.data} />);
|
||||
}}
|
||||
>
|
||||
<IconComponent name="Settings2" className="h-4 w-4 " />
|
||||
</button>
|
||||
<div>
|
||||
<EditNodeModal
|
||||
data={data}
|
||||
setData={setData}
|
||||
nodeLength={nodeLength}
|
||||
>
|
||||
<div
|
||||
className={classNames(
|
||||
"relative -ml-px inline-flex items-center rounded-r-md bg-background px-2 py-2 text-foreground shadow-md ring-1 ring-inset ring-ring transition-all duration-500 ease-in-out hover:bg-muted focus:z-10" +
|
||||
(nodeLength == 0
|
||||
? " text-muted-foreground"
|
||||
: " text-foreground")
|
||||
)}
|
||||
>
|
||||
<IconComponent name="Settings2" className="h-4 w-4 " />
|
||||
</div>
|
||||
</EditNodeModal>
|
||||
</div>
|
||||
</ShadTooltip>
|
||||
</span>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export default NodeToolbarComponent;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { ForwardRefExoticComponent, ReactElement, ReactNode, RefAttributes, SVGProps } from "react";
|
||||
import { APIClassType } from "../api";
|
||||
import { APIClassType, APITemplateType } from "../api";
|
||||
import { FlowStyleType, FlowType, NodeDataType } from "../flow/index";
|
||||
import { typesContextType } from "../typesContext";
|
||||
import { ChatMessageType } from "../chat";
|
||||
|
|
@ -9,7 +9,6 @@ export type InputComponentType = {
|
|||
disabled?: boolean;
|
||||
onChange: (value: string) => void;
|
||||
password: boolean;
|
||||
disableCopyPaste?: boolean;
|
||||
editNode?: boolean;
|
||||
onChangePass?: (value: boolean | boolean) => void;
|
||||
showPass?: boolean;
|
||||
|
|
@ -30,6 +29,7 @@ export type DropDownComponentType = {
|
|||
};
|
||||
export type ParameterComponentType = {
|
||||
data: NodeDataType;
|
||||
setData: (value: NodeDataType) => void;
|
||||
title: string;
|
||||
id: string;
|
||||
color: string;
|
||||
|
|
@ -47,7 +47,6 @@ export type InputListComponentType = {
|
|||
onChange: (value: string[]) => void;
|
||||
disabled: boolean;
|
||||
editNode?: boolean;
|
||||
onAddInput?: (value?: string[]) => void;
|
||||
};
|
||||
|
||||
export type TextAreaComponentType = {
|
||||
|
|
@ -95,7 +94,6 @@ export type DisclosureComponentType = {
|
|||
export type FloatComponentType = {
|
||||
value: string;
|
||||
disabled?: boolean;
|
||||
disableCopyPaste?: boolean;
|
||||
onChange: (value: string) => void;
|
||||
editNode?: boolean;
|
||||
};
|
||||
|
|
@ -175,7 +173,7 @@ export 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;
|
||||
|
|
@ -224,7 +222,7 @@ export type nodeToolbarType = {
|
|||
description: string;
|
||||
display_name: string;
|
||||
documentation: string;
|
||||
template: object;
|
||||
template: APITemplateType;
|
||||
};
|
||||
value: void;
|
||||
};
|
||||
|
|
@ -290,7 +288,7 @@ export type fileCardPropsType = {
|
|||
export type nodeToolbarPropsType = {
|
||||
data: NodeDataType;
|
||||
deleteNode: (idx: string) => void;
|
||||
openPopUp: (element: JSX.Element) => void;
|
||||
setData: (newState: {}) => void;
|
||||
};
|
||||
|
||||
export type parsedDataType = {
|
||||
|
|
@ -321,6 +319,7 @@ export type codeAreaModalPropsType = {
|
|||
value: string;
|
||||
nodeClass: APIClassType;
|
||||
setNodeClass: (Class: APIClassType) => void;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export type chatMessagePropsType = {
|
||||
|
|
@ -344,6 +343,7 @@ export type genericModalPropsType = {
|
|||
type: number;
|
||||
nodeClass?: APIClassType;
|
||||
setNodeClass?: (Class: APIClassType) => void;
|
||||
children: ReactNode;
|
||||
};
|
||||
|
||||
export type buttonBoxPropsType = {
|
||||
|
|
@ -356,3 +356,8 @@ export type buttonBoxPropsType = {
|
|||
deactivate?: boolean;
|
||||
size: "small" | "medium" | "big";
|
||||
};
|
||||
|
||||
export type FlowSettingsPropsType = {
|
||||
open: boolean;
|
||||
setOpen: (open: boolean) => void;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -20,9 +20,6 @@ export type TabsContextType = {
|
|||
uploadFlows: () => void;
|
||||
uploadFlow: (newFlow?: boolean, file?: File) => void;
|
||||
hardReset: () => void;
|
||||
//disable CopyPaste
|
||||
disableCopyPaste: boolean;
|
||||
setDisableCopyPaste: (value: boolean) => void;
|
||||
getNodeId: (nodeType: string) => string;
|
||||
tabsState: TabsState;
|
||||
setTabsState: Dispatch<SetStateAction<TabsState>>;
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import {
|
|||
MessageSquare,
|
||||
MessagesSquare,
|
||||
MoonIcon,
|
||||
MoreHorizontal,
|
||||
Paperclip,
|
||||
Plus,
|
||||
Redo,
|
||||
|
|
@ -269,6 +270,7 @@ export const nodeIconsLucide: iconsType = {
|
|||
Copy,
|
||||
Upload,
|
||||
MessageSquare,
|
||||
MoreHorizontal,
|
||||
};
|
||||
export function getConnectedNodes(edge: Edge, nodes: Array<Node>): Array<Node> {
|
||||
const sourceId = edge.source;
|
||||
|
|
|
|||
|
|
@ -90,12 +90,10 @@ export function checkUpperWords(str: string): string {
|
|||
return words.join(" ");
|
||||
}
|
||||
|
||||
export function groupByFamily(
|
||||
data: APIClassType,
|
||||
baseClasses: string,
|
||||
left: boolean,
|
||||
type: string
|
||||
): groupedObjType[] {
|
||||
export const isWrappedWithClass = (event: any, className: string | undefined) =>
|
||||
event.target.closest(`.${className}`);
|
||||
|
||||
export function groupByFamily(data: APIClassType, baseClasses: string, left: boolean, type: string): groupedObjType[] {
|
||||
let parentOutput: string;
|
||||
let arrOfParent: string[] = [];
|
||||
let arrOfType: { family: string; type: string; component: string }[] = [];
|
||||
|
|
@ -283,7 +281,7 @@ export function buildTweakObject(tweak: tweakType[]): string {
|
|||
});
|
||||
});
|
||||
|
||||
const tweakString = JSON.stringify(tweak, null, 2);
|
||||
const tweakString = JSON.stringify(tweak.at(-1), null, 2);
|
||||
return tweakString;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -29,6 +29,8 @@ module.exports = {
|
|||
},
|
||||
extend: {
|
||||
colors: {
|
||||
"low-indigo": "var(--low-indigo)",
|
||||
"chat-send": "var(--chat-send)",
|
||||
connection: "var(--connection)",
|
||||
"almost-dark-gray": "var(--almost-dark-gray)",
|
||||
"almost-light-blue": "var(--almost-light-blue)",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue