Merge remote-tracking branch 'origin/dev' into types_refactor
This commit is contained in:
commit
ec79cc43bd
170 changed files with 3755 additions and 2142 deletions
2
src/frontend/.dockerignore
Normal file
2
src/frontend/.dockerignore
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
**/node_modules
|
||||
**/build
|
||||
|
|
@ -53,7 +53,7 @@ export default function ParameterComponent({
|
|||
const [position, setPosition] = useState(0);
|
||||
const { setTabsState, tabId, save, flows } = useContext(TabsContext);
|
||||
|
||||
const flow = flows.find((f) => f.id === tabId)?.data?.nodes ?? null;
|
||||
const flow = flows.find((flow) => flow.id === tabId)?.data?.nodes ?? null;
|
||||
|
||||
// Update component position
|
||||
useEffect(() => {
|
||||
|
|
@ -69,7 +69,8 @@ export default function ParameterComponent({
|
|||
|
||||
const { reactFlowInstance } = useContext(typesContext);
|
||||
let disabled =
|
||||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === id) ?? false;
|
||||
reactFlowInstance?.getEdges().some((edge) => edge.targetHandle === id) ??
|
||||
false;
|
||||
|
||||
const { data: myData } = useContext(typesContext);
|
||||
|
||||
|
|
@ -97,8 +98,8 @@ export default function ParameterComponent({
|
|||
// @ts-ignore
|
||||
infoHtml.current = (
|
||||
<div className="h-full w-full break-words">
|
||||
{info.split("\n").map((line, i) => (
|
||||
<p key={i} className="block">
|
||||
{info.split("\n").map((line, index) => (
|
||||
<p key={index} className="block">
|
||||
{line}
|
||||
</p>
|
||||
))}
|
||||
|
|
@ -111,15 +112,16 @@ export default function ParameterComponent({
|
|||
|
||||
if (groupedObj && groupedObj.length > 0) {
|
||||
//@ts-ignore
|
||||
refHtml.current = groupedObj.map((item, i) => {
|
||||
//@ts-ignore
|
||||
refHtml.current = groupedObj.map((item, index) => {
|
||||
const Icon: any =
|
||||
nodeIconsLucide[item.family] ?? nodeIconsLucide["unknown"];
|
||||
|
||||
return (
|
||||
<span
|
||||
key={i}
|
||||
key={index}
|
||||
className={classNames(
|
||||
i > 0 ? "mt-2 flex items-center" : "flex items-center"
|
||||
index > 0 ? "mt-2 flex items-center" : "flex items-center"
|
||||
)}
|
||||
>
|
||||
<div
|
||||
|
|
@ -142,10 +144,10 @@ export default function ParameterComponent({
|
|||
{" "}
|
||||
{item.type === "" ? "" : " - "}
|
||||
{item.type.split(", ").length > 2
|
||||
? item.type.split(", ").map((el, i) => (
|
||||
<React.Fragment key={el + i}>
|
||||
? item.type.split(", ").map((el, index) => (
|
||||
<React.Fragment key={el + index}>
|
||||
<span>
|
||||
{i === item.type.split(", ").length - 1
|
||||
{index === item.type.split(", ").length - 1
|
||||
? el
|
||||
: (el += `, `)}
|
||||
</span>
|
||||
|
|
@ -267,8 +269,8 @@ export default function ParameterComponent({
|
|||
<ToggleShadComponent
|
||||
disabled={disabled}
|
||||
enabled={data.node?.template[name].value ?? false}
|
||||
setEnabled={(t) => {
|
||||
handleOnNewValue(t);
|
||||
setEnabled={(isEnabled) => {
|
||||
handleOnNewValue(isEnabled);
|
||||
}}
|
||||
size="large"
|
||||
/>
|
||||
|
|
@ -312,8 +314,8 @@ export default function ParameterComponent({
|
|||
onChange={handleOnNewValue}
|
||||
fileTypes={data.node?.template[name].fileTypes}
|
||||
suffixes={data.node?.template[name].suffixes}
|
||||
onFileChange={(t: string) => {
|
||||
data.node!.template[name].file_path = t;
|
||||
onFileChange={(filePath: string) => {
|
||||
data.node!.template[name].file_path = filePath;
|
||||
save();
|
||||
}}
|
||||
></InputFileComponent>
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ import { useSSE } from "../../contexts/SSEContext";
|
|||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
|
||||
import { validationStatusType } from "../../types/components";
|
||||
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";
|
||||
import { validationStatusType } from "../../types/components";
|
||||
|
||||
export default function GenericNode({
|
||||
data: olddata,
|
||||
|
|
@ -27,7 +27,8 @@ export default function GenericNode({
|
|||
const updateNodeInternals = useUpdateNodeInternals();
|
||||
const { types, deleteNode, reactFlowInstance } = useContext(typesContext);
|
||||
const name = nodeIconsLucide[data.type] ? data.type : types[data.type];
|
||||
const [validationStatus, setValidationStatus] = useState<validationStatusType | null>(null);
|
||||
const [validationStatus, setValidationStatus] =
|
||||
useState<validationStatusType | null>(null);
|
||||
// State for outline color
|
||||
const { sseData, isBuilding } = useSSE();
|
||||
useEffect(() => {
|
||||
|
|
@ -115,7 +116,6 @@ export default function GenericNode({
|
|||
</span>
|
||||
) : (
|
||||
<div className="max-h-96 overflow-auto">
|
||||
|
||||
{typeof validationStatus.params === "string"
|
||||
? validationStatus.params
|
||||
.split("\n")
|
||||
|
|
@ -163,52 +163,59 @@ export default function GenericNode({
|
|||
|
||||
<>
|
||||
{Object.keys(data.node!.template)
|
||||
.filter((t) => t.charAt(0) !== "_")
|
||||
.map((t: string, idx) => (
|
||||
.filter((templateField) => templateField.charAt(0) !== "_")
|
||||
.map((templateField: string, idx) => (
|
||||
<div key={idx}>
|
||||
{data.node!.template[t].show &&
|
||||
!data.node!.template[t].advanced ? (
|
||||
{data.node!.template[templateField].show &&
|
||||
!data.node!.template[templateField].advanced ? (
|
||||
<ParameterComponent
|
||||
key={
|
||||
(data.node!.template[t].input_types?.join(";") ??
|
||||
data.node!.template[t].type) +
|
||||
(data.node!.template[templateField].input_types?.join(
|
||||
";"
|
||||
) ?? data.node!.template[templateField].type) +
|
||||
"|" +
|
||||
t +
|
||||
templateField +
|
||||
"|" +
|
||||
data.id
|
||||
}
|
||||
data={data}
|
||||
setData={setData}
|
||||
color={
|
||||
nodeColors[types[data.node?.template[t].type!]] ??
|
||||
nodeColors[data.node?.template[t].type!] ??
|
||||
nodeColors[
|
||||
types[data.node?.template[templateField].type!]
|
||||
] ??
|
||||
nodeColors[data.node?.template[templateField].type!] ??
|
||||
nodeColors.unknown
|
||||
}
|
||||
title={
|
||||
data.node?.template[t].display_name
|
||||
? data.node.template[t].display_name
|
||||
: data.node?.template[t].name
|
||||
? toTitleCase(data.node.template[t].name)
|
||||
: toTitleCase(t)
|
||||
data.node?.template[templateField].display_name
|
||||
? data.node.template[templateField].display_name
|
||||
: data.node?.template[templateField].name
|
||||
? toTitleCase(data.node.template[templateField].name)
|
||||
: toTitleCase(templateField)
|
||||
}
|
||||
info={data.node?.template[t].info}
|
||||
name={t}
|
||||
info={data.node?.template[templateField].info}
|
||||
name={templateField}
|
||||
tooltipTitle={
|
||||
data.node?.template[t].input_types?.join("\n") ??
|
||||
data.node?.template[t].type
|
||||
data.node?.template[templateField].input_types?.join(
|
||||
"\n"
|
||||
) ?? data.node?.template[templateField].type
|
||||
}
|
||||
required={data.node?.template[t].required}
|
||||
required={data.node?.template[templateField].required}
|
||||
id={
|
||||
(data.node?.template[t].input_types?.join(";") ??
|
||||
data.node?.template[t].type) +
|
||||
(data.node?.template[templateField].input_types?.join(
|
||||
";"
|
||||
) ?? data.node?.template[templateField].type) +
|
||||
"|" +
|
||||
t +
|
||||
templateField +
|
||||
"|" +
|
||||
data.id
|
||||
}
|
||||
left={true}
|
||||
type={data.node?.template[t].type}
|
||||
optionalHandle={data.node?.template[t].input_types}
|
||||
type={data.node?.template[templateField].type}
|
||||
optionalHandle={
|
||||
data.node?.template[templateField].input_types
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
<></>
|
||||
|
|
|
|||
|
|
@ -36,14 +36,14 @@ export default function SingleAlert({
|
|||
/>
|
||||
</div>
|
||||
<div className="ml-3">
|
||||
<h3 className="break-words text-sm font-medium text-error-foreground">
|
||||
<h3 className="text-sm font-medium text-error-foreground word-break-break-word">
|
||||
{dropItem.title}
|
||||
</h3>
|
||||
{dropItem.list ? (
|
||||
<div className="mt-2 text-sm text-error-foreground">
|
||||
<ul className="list-disc space-y-1 pl-5">
|
||||
{dropItem.list.map((item, idx) => (
|
||||
<li className="break-words" key={idx}>
|
||||
<li className="word-break-break-word" key={idx}>
|
||||
{item}
|
||||
</li>
|
||||
))}
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ export default function AlertDropdown({
|
|||
return (
|
||||
<Popover
|
||||
open={open}
|
||||
onOpenChange={(k) => {
|
||||
setOpen(k);
|
||||
if (k) setNotificationCenter(false);
|
||||
onOpenChange={(target) => {
|
||||
setOpen(target);
|
||||
if (target) setNotificationCenter(false);
|
||||
}}
|
||||
>
|
||||
<PopoverTrigger>{children}</PopoverTrigger>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,9 @@ export default function NoticeAlert({
|
|||
/>
|
||||
</div>
|
||||
<div className="ml-3 flex-1 md:flex md:justify-between">
|
||||
<p className="text-sm text-info-foreground">{title}</p>
|
||||
<p className="text-sm text-info-foreground word-break-break-word">
|
||||
{title}
|
||||
</p>
|
||||
<p className="mt-3 text-sm md:ml-6 md:mt-0">
|
||||
{link !== "" ? (
|
||||
<Link
|
||||
|
|
|
|||
|
|
@ -2,8 +2,8 @@ import React, { ChangeEvent, useEffect, useRef, useState } from "react";
|
|||
import { Input } from "../../components/ui/input";
|
||||
import { Label } from "../../components/ui/label";
|
||||
import { Textarea } from "../../components/ui/textarea";
|
||||
import { InputProps } from "../../types/components";
|
||||
import { readFlowsFromDatabase } from "../../controllers/API";
|
||||
import { InputProps } from "../../types/components";
|
||||
import { FlowType } from "../../types/flow";
|
||||
|
||||
export const EditFlowSettings: React.FC<InputProps> = ({
|
||||
|
|
@ -43,12 +43,12 @@ export const EditFlowSettings: React.FC<InputProps> = ({
|
|||
};
|
||||
|
||||
const [desc, setDesc] = useState(
|
||||
flows.find((f) => f.id === tabId)?.description
|
||||
flows.find((flow) => flow.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);
|
||||
flows.find((flow) => flow.id === tabId)!.description = event.target.value;
|
||||
setDesc(flows.find((flow) => flow.id === tabId)?.description);
|
||||
setDescription(event.target.value);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -84,13 +84,15 @@ export default function BuildTrigger({
|
|||
const parsedData = JSON.parse(event.data);
|
||||
// if the event is the end of the stream, close the connection
|
||||
if (parsedData.end_of_stream) {
|
||||
// Close the connection and finish
|
||||
finished = true;
|
||||
eventSource.close();
|
||||
|
||||
return;
|
||||
} else if (parsedData.log) {
|
||||
// If the event is a log, log it
|
||||
setSuccessData({ title: parsedData.log });
|
||||
} else if (parsedData.input_keys) {
|
||||
} else if (parsedData.input_keys !== undefined) {
|
||||
//@ts-ignore
|
||||
setTabsState((old: TabsState) => {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ export default function Chat({ flow }: ChatType): JSX.Element {
|
|||
const nodes: NodeType[] = useNodes();
|
||||
useEffect(() => {
|
||||
const prevNodes = prevNodesRef.current;
|
||||
const currentNodes = nodes.map((node: NodeType) =>
|
||||
const currentNodes = nodes.map((node: NodeType) =>
|
||||
_.cloneDeep(node.data.node?.template)
|
||||
);
|
||||
if (
|
||||
|
|
@ -62,8 +62,7 @@ export default function Chat({ flow }: ChatType): JSX.Element {
|
|||
tabsState &&
|
||||
tabsState[flow.id] &&
|
||||
tabsState[flow.id].formKeysData &&
|
||||
tabsState[flow.id].formKeysData.input_keys &&
|
||||
Object.keys(tabsState[flow.id].formKeysData.input_keys!).length > 0
|
||||
tabsState[flow.id].formKeysData.input_keys !== null
|
||||
) {
|
||||
setCanOpen(true);
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -34,9 +34,9 @@ export default function CodeAreaComponent({
|
|||
value={myValue}
|
||||
nodeClass={nodeClass}
|
||||
setNodeClass={setNodeClass!}
|
||||
setValue={(t: string) => {
|
||||
setMyValue(t);
|
||||
onChange(t);
|
||||
setValue={(value: string) => {
|
||||
setMyValue(value);
|
||||
onChange(value);
|
||||
}}
|
||||
>
|
||||
<div className="flex w-full items-center">
|
||||
|
|
|
|||
|
|
@ -119,21 +119,25 @@ export default function CodeTabsComponent({
|
|||
}}
|
||||
>
|
||||
<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>
|
||||
{tabs.length > 0 && tabs[0].name !== "" ? (
|
||||
<TabsList>
|
||||
{tabs.map((tab, index) => (
|
||||
<TabsTrigger
|
||||
className={
|
||||
isMessage ? "data-[state=active]:bg-primary-foreground" : ""
|
||||
}
|
||||
key={index}
|
||||
value={index.toString()}
|
||||
>
|
||||
{tab.name}
|
||||
</TabsTrigger>
|
||||
))}
|
||||
</TabsList>
|
||||
) : (
|
||||
<div></div>
|
||||
)}
|
||||
{Number(activeTab) < 4 && (
|
||||
<div className="float-right mx-1 flex gap-2">
|
||||
<div className="float-right mx-1 mb-1 mt-2 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}
|
||||
|
|
@ -188,13 +192,15 @@ export default function CodeTabsComponent({
|
|||
: "overflow-hidden"
|
||||
)}
|
||||
>
|
||||
{data?.map((t: any, index) => (
|
||||
{data?.map((node: any, index) => (
|
||||
<div className="px-3" key={index}>
|
||||
{tweaks?.tweaksList!.current.includes(t["data"]["id"]) && (
|
||||
{tweaks?.tweaksList!.current.includes(
|
||||
node["data"]["id"]
|
||||
) && (
|
||||
<AccordionComponent
|
||||
trigger={t["data"]["id"]}
|
||||
trigger={node["data"]["id"]}
|
||||
open={openAccordion}
|
||||
keyValue={t["data"]["id"]}
|
||||
keyValue={node["data"]["id"]}
|
||||
>
|
||||
<div className="api-modal-table-arrangement">
|
||||
<Table className="table-fixed bg-muted outline-1">
|
||||
|
|
@ -209,78 +215,92 @@ export default function CodeTabsComponent({
|
|||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody className="p-0">
|
||||
{Object.keys(t["data"]["node"]["template"])
|
||||
{Object.keys(node["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")
|
||||
(templateField) =>
|
||||
templateField.charAt(0) !== "_" &&
|
||||
node.data.node.template[templateField]
|
||||
.show &&
|
||||
(node.data.node.template[templateField]
|
||||
.type === "str" ||
|
||||
node.data.node.template[templateField]
|
||||
.type === "bool" ||
|
||||
node.data.node.template[templateField]
|
||||
.type === "float" ||
|
||||
node.data.node.template[templateField]
|
||||
.type === "code" ||
|
||||
node.data.node.template[templateField]
|
||||
.type === "prompt" ||
|
||||
node.data.node.template[templateField]
|
||||
.type === "file" ||
|
||||
node.data.node.template[templateField]
|
||||
.type === "int")
|
||||
)
|
||||
.map((n, i) => {
|
||||
.map((templateField, index) => {
|
||||
return (
|
||||
<TableRow
|
||||
key={i}
|
||||
key={index}
|
||||
className="h-10 dark:border-b-muted"
|
||||
>
|
||||
<TableCell className="p-0 text-center text-sm text-foreground">
|
||||
{n}
|
||||
{templateField}
|
||||
</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 ? (
|
||||
{node.data.node.template[
|
||||
templateField
|
||||
].type === "str" &&
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].options ? (
|
||||
<div className="mx-auto">
|
||||
{t.data.node.template[n]
|
||||
.list ? (
|
||||
{node.data.node.template[
|
||||
templateField
|
||||
].list ? (
|
||||
<InputListComponent
|
||||
editNode={true}
|
||||
disabled={false}
|
||||
value={
|
||||
!t.data.node.template[n]
|
||||
.value ||
|
||||
t.data.node.template[n]
|
||||
.value === ""
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].value ||
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? [""]
|
||||
: t.data.node.template[
|
||||
n
|
||||
: node.data.node
|
||||
.template[
|
||||
templateField
|
||||
].value
|
||||
}
|
||||
onChange={(k) => {
|
||||
onChange={(target) => {
|
||||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList![
|
||||
index
|
||||
].data.node.template[
|
||||
n
|
||||
].value = k;
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node.template[n]
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
) : t.data.node.template[n]
|
||||
.multiline ? (
|
||||
) : node.data.node.template[
|
||||
templateField
|
||||
].multiline ? (
|
||||
<ShadTooltip
|
||||
content={tweaks.buildContent!(
|
||||
t.data.node.template[n]
|
||||
.value
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value
|
||||
)}
|
||||
>
|
||||
<div>
|
||||
|
|
@ -288,33 +308,38 @@ export default function CodeTabsComponent({
|
|||
disabled={false}
|
||||
editNode={true}
|
||||
value={
|
||||
!t.data.node.template[
|
||||
n
|
||||
!node.data.node
|
||||
.template[
|
||||
templateField
|
||||
].value ||
|
||||
t.data.node.template[
|
||||
n
|
||||
node.data.node
|
||||
.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? ""
|
||||
: t.data.node
|
||||
.template[n]
|
||||
.value
|
||||
: node.data.node
|
||||
.template[
|
||||
templateField
|
||||
].value
|
||||
}
|
||||
onChange={(k) => {
|
||||
onChange={(target) => {
|
||||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList![
|
||||
index
|
||||
].data.node.template[
|
||||
n
|
||||
].value = k;
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node
|
||||
.template[n]
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -325,47 +350,55 @@ export default function CodeTabsComponent({
|
|||
editNode={true}
|
||||
disabled={false}
|
||||
password={
|
||||
t.data.node.template[n]
|
||||
.password ?? false
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].password ?? false
|
||||
}
|
||||
value={
|
||||
!t.data.node.template[n]
|
||||
.value ||
|
||||
t.data.node.template[n]
|
||||
.value === ""
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].value ||
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? ""
|
||||
: t.data.node.template[
|
||||
n
|
||||
: node.data.node
|
||||
.template[
|
||||
templateField
|
||||
].value
|
||||
}
|
||||
onChange={(k) => {
|
||||
onChange={(target) => {
|
||||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList![
|
||||
index
|
||||
].data.node.template[
|
||||
n
|
||||
].value = k;
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node.template[n]
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : t.data.node.template[n].type ===
|
||||
"bool" ? (
|
||||
) : node.data.node.template[
|
||||
templateField
|
||||
].type === "bool" ? (
|
||||
<div className="ml-auto">
|
||||
{" "}
|
||||
<ToggleShadComponent
|
||||
enabled={
|
||||
t.data.node.template[n]
|
||||
.value
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value
|
||||
}
|
||||
setEnabled={(e) => {
|
||||
setData((old) => {
|
||||
|
|
@ -374,31 +407,37 @@ export default function CodeTabsComponent({
|
|||
newInputList![
|
||||
index
|
||||
].data.node.template[
|
||||
n
|
||||
templateField
|
||||
].value = e;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
t["data"]["id"],
|
||||
node["data"]["id"],
|
||||
e,
|
||||
t.data.node.template[n]
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
);
|
||||
}}
|
||||
size="small"
|
||||
disabled={false}
|
||||
/>
|
||||
</div>
|
||||
) : t.data.node.template[n].type ===
|
||||
"file" ? (
|
||||
) : node.data.node.template[
|
||||
templateField
|
||||
].type === "file" ? (
|
||||
<ShadTooltip
|
||||
content={tweaks.buildContent!(
|
||||
!t.data.node.template[n]
|
||||
.value ||
|
||||
t.data.node.template[n]
|
||||
.value === ""
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].value ||
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? ""
|
||||
: t.data.node.template[n]
|
||||
.value
|
||||
: node.data.node.template[
|
||||
templateField
|
||||
].value
|
||||
)}
|
||||
>
|
||||
<div className="mx-auto">
|
||||
|
|
@ -406,147 +445,176 @@ export default function CodeTabsComponent({
|
|||
editNode={true}
|
||||
disabled={false}
|
||||
value={
|
||||
t.data.node.template[n]
|
||||
.value ?? ""
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value ?? ""
|
||||
}
|
||||
onChange={(k: any) => {}}
|
||||
onChange={(
|
||||
target: any
|
||||
) => {}}
|
||||
fileTypes={
|
||||
t.data.node.template[n]
|
||||
.fileTypes
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].fileTypes
|
||||
}
|
||||
suffixes={
|
||||
t.data.node.template[n]
|
||||
.suffixes
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].suffixes
|
||||
}
|
||||
onFileChange={(
|
||||
value: any
|
||||
) => {
|
||||
t.data.node.template[
|
||||
n
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].file_path = value;
|
||||
}}
|
||||
></InputFileComponent>
|
||||
</div>
|
||||
</ShadTooltip>
|
||||
) : t.data.node.template[n].type ===
|
||||
"float" ? (
|
||||
) : node.data.node.template[
|
||||
templateField
|
||||
].type === "float" ? (
|
||||
<div className="mx-auto">
|
||||
<FloatComponent
|
||||
disabled={false}
|
||||
editNode={true}
|
||||
value={
|
||||
!t.data.node.template[n]
|
||||
.value ||
|
||||
t.data.node.template[n]
|
||||
.value === ""
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].value ||
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? ""
|
||||
: t.data.node.template[n]
|
||||
.value
|
||||
: node.data.node.template[
|
||||
templateField
|
||||
].value
|
||||
}
|
||||
onChange={(k) => {
|
||||
onChange={(target) => {
|
||||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList![
|
||||
index
|
||||
].data.node.template[
|
||||
n
|
||||
].value = k;
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node.template[n]
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : t.data.node.template[n].type ===
|
||||
"str" &&
|
||||
t.data.node.template[n]
|
||||
.options ? (
|
||||
) : node.data.node.template[
|
||||
templateField
|
||||
].type === "str" &&
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].options ? (
|
||||
<div className="mx-auto">
|
||||
<Dropdown
|
||||
editNode={true}
|
||||
apiModal={true}
|
||||
options={
|
||||
t.data.node.template[n]
|
||||
.options
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].options
|
||||
}
|
||||
onSelect={(k) => {
|
||||
onSelect={(target) => {
|
||||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList![
|
||||
index
|
||||
].data.node.template[
|
||||
n
|
||||
].value = k;
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node.template[n]
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
);
|
||||
}}
|
||||
value={
|
||||
!t.data.node.template[n]
|
||||
.value ||
|
||||
t.data.node.template[n]
|
||||
.value === ""
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].value ||
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? ""
|
||||
: t.data.node.template[n]
|
||||
.value
|
||||
: node.data.node.template[
|
||||
templateField
|
||||
].value
|
||||
}
|
||||
></Dropdown>
|
||||
</div>
|
||||
) : t.data.node.template[n].type ===
|
||||
"int" ? (
|
||||
) : node.data.node.template[
|
||||
templateField
|
||||
].type === "int" ? (
|
||||
<div className="mx-auto">
|
||||
<IntComponent
|
||||
disabled={false}
|
||||
editNode={true}
|
||||
value={
|
||||
!t.data.node.template[n]
|
||||
.value ||
|
||||
t.data.node.template[n]
|
||||
.value === ""
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].value ||
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? ""
|
||||
: t.data.node.template[n]
|
||||
.value
|
||||
: node.data.node.template[
|
||||
templateField
|
||||
].value
|
||||
}
|
||||
onChange={(k) => {
|
||||
onChange={(target) => {
|
||||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList![
|
||||
index
|
||||
].data.node.template[
|
||||
n
|
||||
].value = k;
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node.template[n]
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : t.data.node.template[n].type ===
|
||||
"prompt" ? (
|
||||
) : node.data.node.template[
|
||||
templateField
|
||||
].type === "prompt" ? (
|
||||
<ShadTooltip
|
||||
content={tweaks.buildContent!(
|
||||
!t.data.node.template[n]
|
||||
.value ||
|
||||
t.data.node.template[n]
|
||||
.value === ""
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].value ||
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? ""
|
||||
: t.data.node.template[n]
|
||||
.value
|
||||
: node.data.node.template[
|
||||
templateField
|
||||
].value
|
||||
)}
|
||||
>
|
||||
<div className="mx-auto">
|
||||
|
|
@ -554,44 +622,53 @@ export default function CodeTabsComponent({
|
|||
editNode={true}
|
||||
disabled={false}
|
||||
value={
|
||||
!t.data.node.template[n]
|
||||
.value ||
|
||||
t.data.node.template[n]
|
||||
.value === ""
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].value ||
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? ""
|
||||
: t.data.node.template[
|
||||
n
|
||||
: node.data.node
|
||||
.template[
|
||||
templateField
|
||||
].value
|
||||
}
|
||||
onChange={(k) => {
|
||||
onChange={(target) => {
|
||||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList![
|
||||
index
|
||||
].data.node.template[
|
||||
n
|
||||
].value = k;
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node.template[n]
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</ShadTooltip>
|
||||
) : t.data.node.template[n].type ===
|
||||
"code" ? (
|
||||
) : node.data.node.template[
|
||||
templateField
|
||||
].type === "code" ? (
|
||||
<ShadTooltip
|
||||
content={tweaks.buildContent!(
|
||||
tweaks.getValue!(
|
||||
t.data.node.template[n]
|
||||
.value,
|
||||
t.data,
|
||||
t.data.node.template[n]
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value,
|
||||
node.data,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
)
|
||||
)}
|
||||
>
|
||||
|
|
@ -600,37 +677,43 @@ export default function CodeTabsComponent({
|
|||
disabled={false}
|
||||
editNode={true}
|
||||
value={
|
||||
!t.data.node.template[n]
|
||||
.value ||
|
||||
t.data.node.template[n]
|
||||
.value === ""
|
||||
!node.data.node.template[
|
||||
templateField
|
||||
].value ||
|
||||
node.data.node.template[
|
||||
templateField
|
||||
].value === ""
|
||||
? ""
|
||||
: t.data.node.template[
|
||||
n
|
||||
: node.data.node
|
||||
.template[
|
||||
templateField
|
||||
].value
|
||||
}
|
||||
onChange={(k) => {
|
||||
onChange={(target) => {
|
||||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList![
|
||||
index
|
||||
].data.node.template[
|
||||
n
|
||||
].value = k;
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
t["data"]["id"],
|
||||
k,
|
||||
t.data.node.template[n]
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</ShadTooltip>
|
||||
) : t.data.node.template[n].type ===
|
||||
"Any" ? (
|
||||
) : node.data.node.template[
|
||||
templateField
|
||||
].type === "Any" ? (
|
||||
"-"
|
||||
) : (
|
||||
<div className="hidden"></div>
|
||||
|
|
|
|||
|
|
@ -25,12 +25,12 @@ export default function FloatComponent({
|
|||
type="number"
|
||||
step={step}
|
||||
min={min}
|
||||
onInput={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.value < min.toString()) {
|
||||
e.target.value = min.toString();
|
||||
onInput={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.value < min.toString()) {
|
||||
event.target.value = min.toString();
|
||||
}
|
||||
if (e.target.value > max.toString()) {
|
||||
e.target.value = max.toString();
|
||||
if (event.target.value > max.toString()) {
|
||||
event.target.value = max.toString();
|
||||
}
|
||||
}}
|
||||
max={max}
|
||||
|
|
@ -40,8 +40,8 @@ export default function FloatComponent({
|
|||
placeholder={
|
||||
editNode ? "Number 0 to 1" : "Type a number from zero to one"
|
||||
}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
onChange={(event) => {
|
||||
onChange(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -31,9 +31,24 @@ export default function Header(): JSX.Element {
|
|||
return (
|
||||
<div className="header-arrangement">
|
||||
<div className="header-start-display">
|
||||
<Link to="/">
|
||||
<span className="ml-4 text-2xl">⛓️</span>
|
||||
</Link>
|
||||
{tabId === "" || !tabId ? (
|
||||
<div className="ml-2">
|
||||
<a
|
||||
href="https://www.langflow.org/"
|
||||
target="_blank"
|
||||
rel="noreferrer"
|
||||
className="header-waitlist-link-box"
|
||||
>
|
||||
<span className="pr-1 text-2xl">⛓️</span>
|
||||
<span>Join The Waitlist</span>
|
||||
</a>
|
||||
</div>
|
||||
) : (
|
||||
<Link to="/">
|
||||
<span className="ml-4 text-2xl">⛓️</span>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{flows.findIndex((f) => tabId === f.id) !== -1 && tabId !== "" && (
|
||||
<MenuBar flows={flows} tabId={tabId} />
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -31,8 +31,8 @@ export default function InputComponent({
|
|||
password && !editNode ? "pr-10" : ""
|
||||
)}
|
||||
placeholder={password && editNode ? "Key" : "Type something..."}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
onChange={(event) => {
|
||||
onChange(event.target.value);
|
||||
}}
|
||||
/>
|
||||
{password && (
|
||||
|
|
|
|||
|
|
@ -49,11 +49,11 @@ export default function InputFileComponent({
|
|||
input.style.display = "none"; // Hidden from view
|
||||
input.multiple = false; // Allow only one file selection
|
||||
|
||||
input.onchange = (e: Event): void => {
|
||||
input.onchange = (event: Event): void => {
|
||||
setLoading(true);
|
||||
|
||||
// Get the selected file
|
||||
const file = (e.target as HTMLInputElement).files?.[0];
|
||||
const file = (event.target as HTMLInputElement).files?.[0];
|
||||
|
||||
// Check if the file type is correct
|
||||
if (file && checkFileType(file.name)) {
|
||||
|
|
|
|||
|
|
@ -25,18 +25,18 @@ export default function InputListComponent({
|
|||
"flex flex-col gap-3"
|
||||
)}
|
||||
>
|
||||
{value.map((i, idx) => {
|
||||
{value.map((singleValue, idx) => {
|
||||
return (
|
||||
<div key={idx} className="flex w-full gap-3">
|
||||
<Input
|
||||
disabled={disabled}
|
||||
type="text"
|
||||
value={i}
|
||||
value={singleValue}
|
||||
className={editNode ? "input-edit-node" : ""}
|
||||
placeholder="Type something..."
|
||||
onChange={(e) => {
|
||||
onChange={(event) => {
|
||||
let newInputList = _.cloneDeep(value);
|
||||
newInputList[idx] = e.target.value;
|
||||
newInputList[idx] = event.target.value;
|
||||
onChange(newInputList);
|
||||
}}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -41,17 +41,17 @@ export default function IntComponent({
|
|||
type="number"
|
||||
step="1"
|
||||
min={min}
|
||||
onInput={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (e.target.value < min.toString()) {
|
||||
e.target.value = min.toString();
|
||||
onInput={(event: React.ChangeEvent<HTMLInputElement>) => {
|
||||
if (event.target.value < min.toString()) {
|
||||
event.target.value = min.toString();
|
||||
}
|
||||
}}
|
||||
value={value ?? ""}
|
||||
className={editNode ? "input-edit-node" : ""}
|
||||
disabled={disabled}
|
||||
placeholder={editNode ? "Integer number" : "Type an integer number"}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
onChange={(event) => {
|
||||
onChange(event.target.value);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -39,8 +39,8 @@ export default function PromptAreaComponent({
|
|||
value={value}
|
||||
buttonText="Check & Save"
|
||||
modalTitle="Edit Prompt"
|
||||
setValue={(t: string) => {
|
||||
onChange(t);
|
||||
setValue={(value: string) => {
|
||||
onChange(value);
|
||||
}}
|
||||
nodeClass={nodeClass}
|
||||
setNodeClass={setNodeClass}
|
||||
|
|
|
|||
|
|
@ -25,8 +25,8 @@ export default function TextAreaComponent({
|
|||
disabled={disabled}
|
||||
className={editNode ? "input-edit-node" : ""}
|
||||
placeholder={"Type something..."}
|
||||
onChange={(e) => {
|
||||
onChange(e.target.value);
|
||||
onChange={(event) => {
|
||||
onChange(event.target.value);
|
||||
}}
|
||||
/>
|
||||
<div>
|
||||
|
|
@ -35,8 +35,8 @@ export default function TextAreaComponent({
|
|||
buttonText="Finishing Editing"
|
||||
modalTitle="Edit Text"
|
||||
value={value}
|
||||
setValue={(t: string) => {
|
||||
onChange(t);
|
||||
setValue={(value: string) => {
|
||||
onChange(value);
|
||||
}}
|
||||
>
|
||||
{!editNode && (
|
||||
|
|
|
|||
|
|
@ -18,8 +18,8 @@ export default function ToggleComponent({
|
|||
<div className={disabled ? "pointer-events-none cursor-not-allowed" : ""}>
|
||||
<Switch
|
||||
checked={enabled}
|
||||
onChange={(x: boolean) => {
|
||||
setEnabled(x);
|
||||
onChange={(isEnabled: boolean) => {
|
||||
setEnabled(isEnabled);
|
||||
}}
|
||||
className={classNames(
|
||||
enabled ? "bg-primary" : "bg-input",
|
||||
|
|
|
|||
|
|
@ -35,8 +35,8 @@ export default function ToggleShadComponent({
|
|||
disabled={disabled}
|
||||
className=""
|
||||
checked={enabled}
|
||||
onCheckedChange={(x: boolean) => {
|
||||
setEnabled(x);
|
||||
onCheckedChange={(isEnabled: boolean) => {
|
||||
setEnabled(isEnabled);
|
||||
}}
|
||||
></Switch>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -15,8 +15,8 @@ export default function RenameLabel(props) {
|
|||
useEffect(() => {
|
||||
if (isRename) {
|
||||
setMyValue(props.value);
|
||||
document.addEventListener("keydown", (e) => {
|
||||
if (e.key === "Escape") {
|
||||
document.addEventListener("keydown", (event) => {
|
||||
if (event.key === "Escape") {
|
||||
setIsRename(false);
|
||||
props.setValue("");
|
||||
}
|
||||
|
|
@ -67,8 +67,8 @@ export default function RenameLabel(props) {
|
|||
}
|
||||
}}
|
||||
value={myValue}
|
||||
onChange={(e) => {
|
||||
setMyValue(e.target.value);
|
||||
onChange={(event) => {
|
||||
setMyValue(event.target.value);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -18,7 +18,8 @@ import {
|
|||
uploadFlowsToDatabase,
|
||||
} from "../controllers/API";
|
||||
import { APIClassType, APITemplateType } from "../types/api";
|
||||
import { FlowType, NodeDataType, NodeType, TweaksType } from "../types/flow";
|
||||
import { tweakType } from "../types/components";
|
||||
import { FlowType, NodeDataType, NodeType } from "../types/flow";
|
||||
import { TabsContextType, TabsState, errorsVarType } from "../types/tabs";
|
||||
import {
|
||||
addVersionToDuplicates,
|
||||
|
|
@ -28,7 +29,6 @@ import {
|
|||
import { getRandomDescription, getRandomName } from "../utils/utils";
|
||||
import { alertContext } from "./alertContext";
|
||||
import { typesContext } from "./typesContext";
|
||||
import { tweakType } from "../types/components";
|
||||
|
||||
const uid = new ShortUniqueId({ length: 5 });
|
||||
|
||||
|
|
@ -320,13 +320,13 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
const input = document.createElement("input");
|
||||
input.type = "file";
|
||||
// add a change event listener to the file input
|
||||
input.onchange = (e: Event) => {
|
||||
input.onchange = (event: Event) => {
|
||||
// check if the file type is application/json
|
||||
if (
|
||||
(e.target as HTMLInputElement).files![0].type === "application/json"
|
||||
(event.target as HTMLInputElement).files![0].type === "application/json"
|
||||
) {
|
||||
// get the file from the file input
|
||||
const file = (e.target as HTMLInputElement).files![0];
|
||||
const file = (event.target as HTMLInputElement).files![0];
|
||||
// read the file as text
|
||||
const formData = new FormData();
|
||||
formData.append("file", file);
|
||||
|
|
@ -357,7 +357,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
*/
|
||||
|
||||
function paste(
|
||||
selectionInstance: {nodes: Node[], edges: Edge[]},
|
||||
selectionInstance: { nodes: Node[]; edges: Edge[] },
|
||||
position: { x: number; y: number; paneX?: number; paneY?: number }
|
||||
) {
|
||||
let minimumX = Infinity;
|
||||
|
|
@ -365,12 +365,12 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
let idsMap = {};
|
||||
let nodes: Node<NodeDataType>[] = reactFlowInstance!.getNodes();
|
||||
let edges = reactFlowInstance!.getEdges();
|
||||
selectionInstance.nodes.forEach((n: Node) => {
|
||||
if (n.position.y < minimumY) {
|
||||
minimumY = n.position.y;
|
||||
selectionInstance.nodes.forEach((node: Node) => {
|
||||
if (node.position.y < minimumY) {
|
||||
minimumY = node.position.y;
|
||||
}
|
||||
if (n.position.x < minimumX) {
|
||||
minimumX = n.position.x;
|
||||
if (node.position.x < minimumX) {
|
||||
minimumX = node.position.x;
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -378,43 +378,43 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
? { x: position.paneX + position.x, y: position.paneY! + position.y }
|
||||
: reactFlowInstance!.project({ x: position.x, y: position.y });
|
||||
|
||||
selectionInstance.nodes.forEach((n: NodeType) => {
|
||||
selectionInstance.nodes.forEach((node: NodeType) => {
|
||||
// Generate a unique node ID
|
||||
let newId = getNodeId(n.data.type);
|
||||
idsMap[n.id] = newId;
|
||||
let newId = getNodeId(node.data.type);
|
||||
idsMap[node.id] = newId;
|
||||
|
||||
// Create a new node object
|
||||
const newNode: NodeType = {
|
||||
id: newId,
|
||||
type: "genericNode",
|
||||
position: {
|
||||
x: insidePosition.x + n.position!.x - minimumX,
|
||||
y: insidePosition.y + n.position!.y - minimumY,
|
||||
x: insidePosition.x + node.position!.x - minimumX,
|
||||
y: insidePosition.y + node.position!.y - minimumY,
|
||||
},
|
||||
data: {
|
||||
..._.cloneDeep(n.data),
|
||||
..._.cloneDeep(node.data),
|
||||
id: newId,
|
||||
},
|
||||
};
|
||||
|
||||
// Add the new node to the list of nodes in state
|
||||
nodes = nodes
|
||||
.map((e) => ({ ...e, selected: false }))
|
||||
.map((node) => ({ ...node, selected: false }))
|
||||
.concat({ ...newNode, selected: false });
|
||||
});
|
||||
reactFlowInstance!.setNodes(nodes);
|
||||
|
||||
selectionInstance.edges.forEach((e) => {
|
||||
let source = idsMap[e.source];
|
||||
let target = idsMap[e.target];
|
||||
let sourceHandleSplitted = e.sourceHandle!.split("|");
|
||||
selectionInstance.edges.forEach((edge) => {
|
||||
let source = idsMap[edge.source];
|
||||
let target = idsMap[edge.target];
|
||||
let sourceHandleSplitted = edge.sourceHandle!.split("|");
|
||||
let sourceHandle =
|
||||
sourceHandleSplitted[0] +
|
||||
"|" +
|
||||
source +
|
||||
"|" +
|
||||
sourceHandleSplitted.slice(2).join("|");
|
||||
let targetHandleSplitted = e.targetHandle!.split("|");
|
||||
let targetHandleSplitted = edge.targetHandle!.split("|");
|
||||
let targetHandle =
|
||||
targetHandleSplitted.slice(0, -1).join("|") + "|" + target;
|
||||
let id =
|
||||
|
|
@ -439,7 +439,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
animated: targetHandle.split("|")[0] === "Text",
|
||||
selected: false,
|
||||
},
|
||||
edges.map((e) => ({ ...e, selected: false }))
|
||||
edges.map((edge) => ({ ...edge, selected: false }))
|
||||
);
|
||||
});
|
||||
reactFlowInstance!.setEdges(edges);
|
||||
|
|
@ -521,8 +521,8 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
node.data.node.base_classes = template["base_classes"];
|
||||
edges.forEach((edge) => {
|
||||
if (edge.source === node.id) {
|
||||
edge.sourceHandle = edge.sourceHandle!
|
||||
.split("|")
|
||||
edge.sourceHandle = edge
|
||||
.sourceHandle!.split("|")
|
||||
.slice(0, 2)
|
||||
.concat(template["base_classes"])
|
||||
.join("|");
|
||||
|
|
@ -537,7 +537,10 @@ export function TabsProvider({ children }: { children: ReactNode }) {
|
|||
});
|
||||
};
|
||||
|
||||
const createNewFlow = (flowData: { data: ReactFlowJsonObject | null; description: string; }, flow: FlowType) => ({
|
||||
const createNewFlow = (
|
||||
flowData: { data: ReactFlowJsonObject | null; description: string },
|
||||
flow: FlowType
|
||||
) => ({
|
||||
description: flowData.description,
|
||||
name: flow?.name ?? getRandomName(),
|
||||
data: flowData.data,
|
||||
|
|
|
|||
|
|
@ -88,12 +88,12 @@ export function TypesProvider({ children }: { children: ReactNode }) {
|
|||
|
||||
function deleteNode(idx: string) {
|
||||
reactFlowInstance!.setNodes(
|
||||
reactFlowInstance!.getNodes().filter((n: Node) => n.id !== idx)
|
||||
reactFlowInstance!.getNodes().filter((node: Node) => node.id !== idx)
|
||||
);
|
||||
reactFlowInstance!.setEdges(
|
||||
reactFlowInstance!
|
||||
.getEdges()
|
||||
.filter((ns) => ns.source !== idx && ns.target !== idx)
|
||||
.filter((edge) => edge.source !== idx && edge.target !== idx)
|
||||
);
|
||||
}
|
||||
return (
|
||||
|
|
|
|||
|
|
@ -34,14 +34,18 @@ export function UndoRedoProvider({ children }) {
|
|||
const [past, setPast] = useState<HistoryItem[][]>(flows.map(() => []));
|
||||
const [future, setFuture] = useState<HistoryItem[][]>(flows.map(() => []));
|
||||
const [tabIndex, setTabIndex] = useState(
|
||||
flows.findIndex((f) => f.id === tabId)
|
||||
flows.findIndex((flow) => flow.id === tabId)
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
// whenever the flows variable changes, we need to add one array to the past and future states
|
||||
setPast((old) => flows.map((f, i) => (old[i] ? old[i] : [])));
|
||||
setFuture((old) => flows.map((f, i) => (old[i] ? old[i] : [])));
|
||||
setTabIndex(flows.findIndex((f) => f.id === tabId));
|
||||
setPast((old) =>
|
||||
flows.map((flow, index) => (old[index] ? old[index] : []))
|
||||
);
|
||||
setFuture((old) =>
|
||||
flows.map((flow, index) => (old[index] ? old[index] : []))
|
||||
);
|
||||
setTabIndex(flows.findIndex((flow) => flow.id === tabId));
|
||||
}, [flows, tabId]);
|
||||
|
||||
const { setNodes, setEdges, getNodes, getEdges } = useReactFlow();
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import "ace-builds/src-noconflict/mode-python";
|
|||
import "ace-builds/src-noconflict/theme-github";
|
||||
import "ace-builds/src-noconflict/theme-twilight";
|
||||
import {
|
||||
MutableRefObject,
|
||||
ReactNode,
|
||||
forwardRef,
|
||||
useContext,
|
||||
|
|
@ -16,17 +15,18 @@ import CodeTabsComponent from "../../components/codeTabsComponent";
|
|||
import IconComponent from "../../components/genericIconComponent";
|
||||
import { EXPORT_CODE_DIALOG } from "../../constants/constants";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { FlowType, NodeType, TweaksType } from "../../types/flow/index";
|
||||
import { TemplateVariableType } from "../../types/api";
|
||||
import { tweakType, uniqueTweakType } from "../../types/components";
|
||||
import { FlowType, NodeType } from "../../types/flow/index";
|
||||
import { buildTweaks } from "../../utils/reactflowUtils";
|
||||
import {
|
||||
getCurlCode,
|
||||
getPythonApiCode,
|
||||
getPythonCode,
|
||||
getWidgetCode,
|
||||
tabsArray,
|
||||
} from "../../utils/utils";
|
||||
import BaseModal from "../baseModal";
|
||||
import { tweakType, uniqueTweakType } from "../../types/components";
|
||||
import { APITemplateType, TemplateVariableType } from "../../types/api";
|
||||
|
||||
const ApiModal = forwardRef(
|
||||
(
|
||||
|
|
@ -51,39 +51,14 @@ const ApiModal = forwardRef(
|
|||
const pythonCode = getPythonCode(flow, tweak.current, tabsState);
|
||||
const widgetCode = getWidgetCode(flow, 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,
|
||||
},
|
||||
{
|
||||
name: "Chat Widget HTML",
|
||||
description:
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
|
||||
mode: "html",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: widgetCode,
|
||||
},
|
||||
]);
|
||||
const codesArray = [
|
||||
curl_code,
|
||||
pythonApiCode,
|
||||
pythonCode,
|
||||
widgetCode,
|
||||
pythonCode,
|
||||
];
|
||||
const [tabs, setTabs] = useState(tabsArray(codesArray, 0));
|
||||
|
||||
function startState() {
|
||||
tweak.current = [];
|
||||
|
|
@ -104,102 +79,31 @@ const ApiModal = forwardRef(
|
|||
|
||||
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: "Chat Widget HTML",
|
||||
description:
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
|
||||
mode: "html",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: widgetCode,
|
||||
},
|
||||
{
|
||||
name: "Tweaks",
|
||||
mode: "python",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: pythonCode,
|
||||
},
|
||||
]);
|
||||
setTabs(tabsArray(codesArray, 1));
|
||||
} 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,
|
||||
},
|
||||
{
|
||||
name: "Chat Widget HTML",
|
||||
description:
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
|
||||
mode: "html",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: widgetCode,
|
||||
},
|
||||
]);
|
||||
setTabs(tabsArray(codesArray, 1));
|
||||
}
|
||||
}, [flow["data"]!["nodes"], open]);
|
||||
|
||||
function filterNodes() {
|
||||
let arrNodesWithValues: string[] = [];
|
||||
|
||||
flow["data"]!["nodes"].forEach((t) => {
|
||||
Object.keys(t["data"]["node"]["template"])
|
||||
flow["data"]!["nodes"].forEach((node) => {
|
||||
Object.keys(node["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")
|
||||
(templateField) =>
|
||||
templateField.charAt(0) !== "_" &&
|
||||
node.data.node.template[templateField].show &&
|
||||
(node.data.node.template[templateField].type === "str" ||
|
||||
node.data.node.template[templateField].type === "bool" ||
|
||||
node.data.node.template[templateField].type === "float" ||
|
||||
node.data.node.template[templateField].type === "code" ||
|
||||
node.data.node.template[templateField].type === "prompt" ||
|
||||
node.data.node.template[templateField].type === "file" ||
|
||||
node.data.node.template[templateField].type === "int")
|
||||
)
|
||||
.map((n, i) => {
|
||||
arrNodesWithValues.push(t["id"]);
|
||||
arrNodesWithValues.push(node["id"]);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -207,7 +111,11 @@ const ApiModal = forwardRef(
|
|||
return self.indexOf(value) === index;
|
||||
});
|
||||
}
|
||||
function buildTweakObject(tw: string, changes: string | string[] | boolean | number, template: TemplateVariableType) {
|
||||
function buildTweakObject(
|
||||
tw: string,
|
||||
changes: string | string[] | boolean | number,
|
||||
template: TemplateVariableType
|
||||
) {
|
||||
if (typeof changes === "string" && template.type === "float") {
|
||||
changes = parseFloat(changes);
|
||||
}
|
||||
|
|
@ -266,7 +174,11 @@ const ApiModal = forwardRef(
|
|||
return htmlContent;
|
||||
}
|
||||
|
||||
function getValue(value: string, node: NodeType, template: TemplateVariableType) {
|
||||
function getValue(
|
||||
value: string,
|
||||
node: NodeType,
|
||||
template: TemplateVariableType
|
||||
) {
|
||||
let returnValue = value ?? "";
|
||||
|
||||
if (getTweak.length > 0) {
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@ import { limitScrollFieldsModal } from "../../constants/constants";
|
|||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import { NodeDataType } from "../../types/flow";
|
||||
import { TabsState } from "../../types/tabs";
|
||||
import { classNames } from "../../utils/utils";
|
||||
import BaseModal from "../baseModal";
|
||||
import { TabsState } from "../../types/tabs";
|
||||
|
||||
const EditNodeModal = forwardRef(
|
||||
(
|
||||
|
|
@ -50,13 +50,15 @@ const EditNodeModal = forwardRef(
|
|||
const { reactFlowInstance } = useContext(typesContext);
|
||||
|
||||
let disabled =
|
||||
reactFlowInstance?.getEdges().some((e) => e.targetHandle === data.id) ??
|
||||
false;
|
||||
reactFlowInstance
|
||||
?.getEdges()
|
||||
.some((edge) => edge.targetHandle === data.id) ?? false;
|
||||
|
||||
function changeAdvanced(n: string): void {
|
||||
function changeAdvanced(templateParam: string): void {
|
||||
setMyData((old) => {
|
||||
let newData = cloneDeep(old);
|
||||
newData.node!.template[n].advanced = !newData.node!.template[n].advanced;
|
||||
newData.node!.template[templateParam].advanced =
|
||||
!newData.node!.template[templateParam].advanced;
|
||||
return newData;
|
||||
});
|
||||
}
|
||||
|
|
@ -116,51 +118,65 @@ const EditNodeModal = forwardRef(
|
|||
<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")
|
||||
(templateParam) =>
|
||||
templateParam.charAt(0) !== "_" &&
|
||||
myData.node?.template[templateParam].show &&
|
||||
(myData.node.template[templateParam].type ===
|
||||
"str" ||
|
||||
myData.node.template[templateParam].type ===
|
||||
"bool" ||
|
||||
myData.node.template[templateParam].type ===
|
||||
"float" ||
|
||||
myData.node.template[templateParam].type ===
|
||||
"code" ||
|
||||
myData.node.template[templateParam].type ===
|
||||
"prompt" ||
|
||||
myData.node.template[templateParam].type ===
|
||||
"file" ||
|
||||
myData.node.template[templateParam].type ===
|
||||
"int")
|
||||
)
|
||||
.map((n, i) => (
|
||||
<TableRow key={i} className="h-10">
|
||||
.map((templateParam, index) => (
|
||||
<TableRow key={index} 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}
|
||||
{myData.node?.template[templateParam].name
|
||||
? myData.node.template[templateParam].name
|
||||
: myData.node?.template[templateParam]
|
||||
.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 ? (
|
||||
{myData.node?.template[templateParam].type ===
|
||||
"str" &&
|
||||
!myData.node.template[templateParam].options ? (
|
||||
<div className="mx-auto">
|
||||
{myData.node.template[n].list ? (
|
||||
{myData.node.template[templateParam].list ? (
|
||||
<InputListComponent
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
value={
|
||||
!myData.node.template[n].value ||
|
||||
myData.node.template[n].value === ""
|
||||
!myData.node.template[templateParam]
|
||||
.value ||
|
||||
myData.node.template[templateParam]
|
||||
.value === ""
|
||||
? [""]
|
||||
: myData.node.template[n].value
|
||||
: myData.node.template[templateParam]
|
||||
.value
|
||||
}
|
||||
onChange={(t: string[]) => {
|
||||
handleOnNewValue(t, n);
|
||||
onChange={(value: string[]) => {
|
||||
handleOnNewValue(value, templateParam);
|
||||
}}
|
||||
/>
|
||||
) : myData.node.template[n].multiline ? (
|
||||
) : myData.node.template[templateParam]
|
||||
.multiline ? (
|
||||
<TextAreaComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={
|
||||
myData.node.template[n].value ?? ""
|
||||
myData.node.template[templateParam]
|
||||
.value ?? ""
|
||||
}
|
||||
onChange={(t: string | string[]) => {
|
||||
handleOnNewValue(t, n);
|
||||
onChange={(value: string | string[]) => {
|
||||
handleOnNewValue(value, templateParam);
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
|
|
@ -168,105 +184,142 @@ const EditNodeModal = forwardRef(
|
|||
editNode={true}
|
||||
disabled={disabled}
|
||||
password={
|
||||
myData.node.template[n].password ??
|
||||
false
|
||||
myData.node.template[templateParam]
|
||||
.password ?? false
|
||||
}
|
||||
value={
|
||||
myData.node.template[n].value ?? ""
|
||||
myData.node.template[templateParam]
|
||||
.value ?? ""
|
||||
}
|
||||
onChange={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
onChange={(value) => {
|
||||
handleOnNewValue(value, templateParam);
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
) : myData.node?.template[n].type === "bool" ? (
|
||||
) : myData.node?.template[templateParam].type ===
|
||||
"bool" ? (
|
||||
<div className="ml-auto">
|
||||
{" "}
|
||||
<ToggleShadComponent
|
||||
disabled={disabled}
|
||||
enabled={myData.node.template[n].value}
|
||||
setEnabled={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
enabled={
|
||||
myData.node.template[templateParam].value
|
||||
}
|
||||
setEnabled={(isEnabled) => {
|
||||
handleOnNewValue(
|
||||
isEnabled,
|
||||
templateParam
|
||||
);
|
||||
}}
|
||||
size="small"
|
||||
/>
|
||||
</div>
|
||||
) : myData.node?.template[n].type === "float" ? (
|
||||
) : myData.node?.template[templateParam].type ===
|
||||
"float" ? (
|
||||
<div className="mx-auto">
|
||||
<FloatComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
value={
|
||||
myData.node.template[templateParam]
|
||||
.value ?? ""
|
||||
}
|
||||
onChange={(value) => {
|
||||
handleOnNewValue(value, templateParam);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : myData.node?.template[n].type === "str" &&
|
||||
myData.node.template[n].options ? (
|
||||
) : myData.node?.template[templateParam].type ===
|
||||
"str" &&
|
||||
myData.node.template[templateParam].options ? (
|
||||
<div className="mx-auto">
|
||||
<Dropdown
|
||||
numberOfOptions={nodeLength}
|
||||
editNode={true}
|
||||
options={myData.node.template[n].options}
|
||||
onSelect={(t) => handleOnNewValue(t, n)}
|
||||
options={
|
||||
myData.node.template[templateParam]
|
||||
.options
|
||||
}
|
||||
onSelect={(value) =>
|
||||
handleOnNewValue(value, templateParam)
|
||||
}
|
||||
value={
|
||||
myData.node.template[n].value ??
|
||||
"Choose an option"
|
||||
myData.node.template[templateParam]
|
||||
.value ?? "Choose an option"
|
||||
}
|
||||
></Dropdown>
|
||||
</div>
|
||||
) : myData.node?.template[n].type === "int" ? (
|
||||
) : myData.node?.template[templateParam].type ===
|
||||
"int" ? (
|
||||
<div className="mx-auto">
|
||||
<IntComponent
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t) => {
|
||||
handleOnNewValue(t, n);
|
||||
value={
|
||||
myData.node.template[templateParam]
|
||||
.value ?? ""
|
||||
}
|
||||
onChange={(value) => {
|
||||
handleOnNewValue(value, templateParam);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : myData.node?.template[n].type === "file" ? (
|
||||
) : myData.node?.template[templateParam].type ===
|
||||
"file" ? (
|
||||
<div className="mx-auto">
|
||||
<InputFileComponent
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t: string | string[]) => {
|
||||
handleOnNewValue(t, n);
|
||||
value={
|
||||
myData.node.template[templateParam]
|
||||
.value ?? ""
|
||||
}
|
||||
onChange={(value: string | string[]) => {
|
||||
handleOnNewValue(value, templateParam);
|
||||
}}
|
||||
fileTypes={
|
||||
myData.node.template[n].fileTypes
|
||||
myData.node.template[templateParam]
|
||||
.fileTypes
|
||||
}
|
||||
suffixes={myData.node.template[n].suffixes}
|
||||
onFileChange={(t: string) => {
|
||||
data.node!.template[n].file_path = t;
|
||||
suffixes={
|
||||
myData.node.template[templateParam]
|
||||
.suffixes
|
||||
}
|
||||
onFileChange={(filePath: string) => {
|
||||
data.node!.template[
|
||||
templateParam
|
||||
].file_path = filePath;
|
||||
}}
|
||||
></InputFileComponent>
|
||||
</div>
|
||||
) : myData.node?.template[n].type === "prompt" ? (
|
||||
) : myData.node?.template[templateParam].type ===
|
||||
"prompt" ? (
|
||||
<div className="mx-auto">
|
||||
<PromptAreaComponent
|
||||
field_name={n}
|
||||
field_name={templateParam}
|
||||
editNode={true}
|
||||
disabled={disabled}
|
||||
nodeClass={myData.node}
|
||||
setNodeClass={(nodeClass) => {
|
||||
myData.node = nodeClass;
|
||||
}}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t: string | string[]) => {
|
||||
handleOnNewValue(t, n);
|
||||
value={
|
||||
myData.node.template[templateParam]
|
||||
.value ?? ""
|
||||
}
|
||||
onChange={(value: string | string[]) => {
|
||||
handleOnNewValue(value, templateParam);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : myData.node?.template[n].type === "code" ? (
|
||||
) : myData.node?.template[templateParam].type ===
|
||||
"code" ? (
|
||||
<div className="mx-auto">
|
||||
<CodeAreaComponent
|
||||
dynamic={
|
||||
data.node!.template[n].dynamic ?? false
|
||||
data.node!.template[templateParam]
|
||||
.dynamic ?? false
|
||||
}
|
||||
setNodeClass={(nodeClass) => {
|
||||
data.node = nodeClass;
|
||||
|
|
@ -274,13 +327,17 @@ const EditNodeModal = forwardRef(
|
|||
nodeClass={data.node}
|
||||
disabled={disabled}
|
||||
editNode={true}
|
||||
value={myData.node.template[n].value ?? ""}
|
||||
onChange={(t: string | string[]) => {
|
||||
handleOnNewValue(t, n);
|
||||
value={
|
||||
myData.node.template[templateParam]
|
||||
.value ?? ""
|
||||
}
|
||||
onChange={(value: string | string[]) => {
|
||||
handleOnNewValue(value, templateParam);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
) : myData.node?.template[n].type === "Any" ? (
|
||||
) : myData.node?.template[templateParam].type ===
|
||||
"Any" ? (
|
||||
"-"
|
||||
) : (
|
||||
<div className="hidden"></div>
|
||||
|
|
@ -289,8 +346,13 @@ const EditNodeModal = forwardRef(
|
|||
<TableCell className="p-0 text-right">
|
||||
<div className="items-center text-center">
|
||||
<ToggleShadComponent
|
||||
enabled={!myData.node?.template[n].advanced}
|
||||
setEnabled={(e) => changeAdvanced(n)}
|
||||
enabled={
|
||||
!myData.node?.template[templateParam]
|
||||
.advanced
|
||||
}
|
||||
setEnabled={(e) =>
|
||||
changeAdvanced(templateParam)
|
||||
}
|
||||
disabled={disabled}
|
||||
size="small"
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -4,17 +4,16 @@ import "ace-builds/src-noconflict/mode-python";
|
|||
import "ace-builds/src-noconflict/theme-github";
|
||||
import "ace-builds/src-noconflict/theme-twilight";
|
||||
// import "ace-builds/webpack-resolver";
|
||||
import { ReactNode, useContext, useEffect, useState } from "react";
|
||||
import { useContext, useEffect, 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 { codeAreaModalPropsType } from "../../types/components";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import { postCustomComponent, postValidateCode } from "../../controllers/API";
|
||||
import { APIClassType } from "../../types/api";
|
||||
import { codeAreaModalPropsType } from "../../types/components";
|
||||
import BaseModal from "../baseModal";
|
||||
|
||||
export default function CodeAreaModal({
|
||||
|
|
@ -174,8 +173,8 @@ export default function CodeAreaModal({
|
|||
<h1 className="text-lg text-destructive">
|
||||
{error?.detail?.error}
|
||||
</h1>
|
||||
<div className="ml-2 w-full break-all text-sm text-status-red">
|
||||
<pre className="w-full whitespace-pre-wrap break-all">
|
||||
<div className="ml-2 w-full text-sm text-status-red word-break-break-word">
|
||||
<pre className="w-full word-break-break-word">
|
||||
{error?.detail?.traceback}
|
||||
</pre>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -13,9 +13,12 @@ const ExportModal = forwardRef(
|
|||
const { flows, tabId, updateFlow, downloadFlow, saveFlow } =
|
||||
useContext(TabsContext);
|
||||
const [checked, setChecked] = useState(false);
|
||||
const [name, setName] = useState(flows.find((f) => f.id === tabId)?.name);
|
||||
const [name, setName] = useState(
|
||||
flows.find((flow) => flow.id === tabId)?.name
|
||||
);
|
||||
const [invalidName, setInvalidName] = useState(false);
|
||||
const [description, setDescription] = useState(
|
||||
flows.find((f) => f.id === tabId)?.description
|
||||
flows.find((flow) => flow.id === tabId)?.description
|
||||
);
|
||||
const [open, setOpen] = useState(false);
|
||||
return (
|
||||
|
|
@ -31,6 +34,8 @@ const ExportModal = forwardRef(
|
|||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<EditFlowSettings
|
||||
invalidName={invalidName}
|
||||
setInvalidName={setInvalidName}
|
||||
name={name!}
|
||||
description={description!}
|
||||
flows={flows}
|
||||
|
|
@ -56,13 +61,13 @@ const ExportModal = forwardRef(
|
|||
onClick={() => {
|
||||
if (checked)
|
||||
downloadFlow(
|
||||
flows.find((f) => f.id === tabId)!,
|
||||
flows.find((flow) => flow.id === tabId)!,
|
||||
name!,
|
||||
description
|
||||
);
|
||||
else
|
||||
downloadFlow(
|
||||
removeApiKeys(flows.find((f) => f.id === tabId)!),
|
||||
removeApiKeys(flows.find((flow) => flow.id === tabId)!),
|
||||
name!,
|
||||
description
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,17 +14,18 @@ export default function FlowSettingsModal({
|
|||
}: FlowSettingsPropsType): JSX.Element {
|
||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||
const ref = useRef();
|
||||
const { flows, tabId, updateFlow, saveFlow } =
|
||||
useContext(TabsContext);
|
||||
const { flows, tabId, updateFlow, saveFlow } = useContext(TabsContext);
|
||||
const maxLength = 50;
|
||||
const [name, setName] = useState(flows.find((f) => f.id === tabId)!.name);
|
||||
const [name, setName] = useState(
|
||||
flows.find((flow) => flow.id === tabId)!.name
|
||||
);
|
||||
const [description, setDescription] = useState(
|
||||
flows.find((f) => f.id === tabId)!.description
|
||||
flows.find((flow) => flow.id === tabId)!.description
|
||||
);
|
||||
const [invalidName, setInvalidName] = useState(false);
|
||||
|
||||
function handleClick(): void {
|
||||
let savedFlow = flows.find((f) => f.id === tabId);
|
||||
let savedFlow = flows.find((flow) => flow.id === tabId);
|
||||
savedFlow!.name = name;
|
||||
savedFlow!.description = description;
|
||||
saveFlow(savedFlow!);
|
||||
|
|
|
|||
|
|
@ -47,8 +47,8 @@ export default function ChatInput({
|
|||
}`,
|
||||
}}
|
||||
value={lockChat ? "Thinking..." : chatValue}
|
||||
onChange={(e): void => {
|
||||
setChatValue(e.target.value);
|
||||
onChange={(event): void => {
|
||||
setChatValue(event.target.value);
|
||||
}}
|
||||
className={classNames(
|
||||
lockChat
|
||||
|
|
|
|||
|
|
@ -85,8 +85,8 @@ export default function ChatMessage({
|
|||
<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]"
|
||||
className="markdown prose min-w-full text-primary word-break-break-word
|
||||
dark:prose-invert"
|
||||
components={{
|
||||
pre({ node, ...props }) {
|
||||
return <>{props.children}</>;
|
||||
|
|
@ -184,7 +184,7 @@ export default function ChatMessage({
|
|||
}
|
||||
/>
|
||||
</button>
|
||||
<span className="prose inline-block break-words text-primary dark:prose-invert">
|
||||
<span className="prose text-primary word-break-break-word dark:prose-invert">
|
||||
{promptOpen
|
||||
? template?.split("\n")?.map((line, index) => {
|
||||
const regex = /{([^}]+)}/g;
|
||||
|
|
|
|||
|
|
@ -24,9 +24,8 @@ import {
|
|||
import { Textarea } from "../../components/ui/textarea";
|
||||
import { CHAT_FORM_DIALOG_SUBTITLE } from "../../constants/constants";
|
||||
import { TabsContext } from "../../contexts/tabsContext";
|
||||
import { TabsState } from "../../types/tabs";
|
||||
import { validateNodes } from "../../utils/reactflowUtils";
|
||||
import { TabsState, errorsVarType } from "../../types/tabs";
|
||||
import { AxiosError } from "axios";
|
||||
|
||||
export default function FormModal({
|
||||
flow,
|
||||
|
|
@ -48,7 +47,7 @@ export default function FormModal({
|
|||
const handleKeys = formKeysData.handle_keys;
|
||||
|
||||
const keyToUse = Object.keys(inputKeys!).find(
|
||||
(k) => !handleKeys?.some((j) => j === k) && inputKeys![k] === ""
|
||||
(key) => !handleKeys?.some((j) => j === key) && inputKeys![key] === ""
|
||||
);
|
||||
|
||||
return inputKeys![keyToUse!];
|
||||
|
|
@ -69,14 +68,17 @@ export default function FormModal({
|
|||
const id = useRef(flow.id);
|
||||
const tabsStateFlowId = tabsState[flow.id];
|
||||
const tabsStateFlowIdFormKeysData = tabsStateFlowId.formKeysData;
|
||||
const [chatKey, setChatKey] = useState(
|
||||
Object.keys(tabsState[flow.id].formKeysData.input_keys!).find(
|
||||
(k) =>
|
||||
!tabsState[flow.id].formKeysData.handle_keys!.some((j) => j === k) &&
|
||||
tabsState[flow.id].formKeysData.input_keys![k] === ""
|
||||
)
|
||||
);
|
||||
|
||||
const [chatKey, setChatKey] = useState(() => {
|
||||
if (tabsState[flow.id]?.formKeysData?.input_keys) {
|
||||
return Object.keys(tabsState[flow.id].formKeysData.input_keys).find(
|
||||
(key) =>
|
||||
!tabsState[flow.id].formKeysData.handle_keys.some((j) => j === key) &&
|
||||
tabsState[flow.id].formKeysData.input_keys[key] === ""
|
||||
);
|
||||
}
|
||||
// TODO: return a sensible default
|
||||
return "";
|
||||
});
|
||||
useEffect(() => {
|
||||
if (messagesRef.current) {
|
||||
messagesRef.current.scrollTop = messagesRef.current.scrollHeight;
|
||||
|
|
@ -162,7 +164,8 @@ export default function FormModal({
|
|||
chatId: string,
|
||||
isDevelopment: boolean = false
|
||||
): string {
|
||||
const isSecureProtocol = window.location.protocol === "https:";
|
||||
const isSecureProtocol =
|
||||
window.location.protocol === "https:" || window.location.port === "443";
|
||||
const webSocketProtocol = isSecureProtocol ? "wss" : "ws";
|
||||
const host = isDevelopment ? "localhost:7860" : window.location.host;
|
||||
const chatEndpoint = `/api/v1/chat/${chatId}`;
|
||||
|
|
@ -425,98 +428,104 @@ export default function FormModal({
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{Object.keys(tabsState[id.current].formKeysData.input_keys!).map(
|
||||
(i, k) => (
|
||||
<div className="file-component-accordion-div" key={k}>
|
||||
{tabsState[id.current]?.formKeysData?.input_keys
|
||||
? Object.keys(
|
||||
tabsState[id.current].formKeysData.input_keys
|
||||
).map((key, index) => (
|
||||
<div className="file-component-accordion-div" key={index}>
|
||||
<AccordionComponent
|
||||
trigger={
|
||||
<div className="file-component-badge-div">
|
||||
<Badge variant="gray" size="md">
|
||||
{key}
|
||||
</Badge>
|
||||
|
||||
<div
|
||||
className="-mb-1"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<ToggleShadComponent
|
||||
enabled={chatKey === key}
|
||||
setEnabled={(value) =>
|
||||
handleOnCheckedChange(value, key)
|
||||
}
|
||||
size="small"
|
||||
disabled={tabsState[
|
||||
id.current
|
||||
].formKeysData.handle_keys.some(
|
||||
(t) => t === key
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
key={index}
|
||||
keyValue={key}
|
||||
>
|
||||
<div className="file-component-tab-column">
|
||||
{tabsState[id.current].formKeysData.handle_keys.some(
|
||||
(t) => t === key
|
||||
) && (
|
||||
<div className="font-normal text-muted-foreground ">
|
||||
Source: Component
|
||||
</div>
|
||||
)}
|
||||
<Textarea
|
||||
className="custom-scroll"
|
||||
value={
|
||||
tabsState[id.current].formKeysData.input_keys[key]
|
||||
}
|
||||
onChange={(e) => {
|
||||
//@ts-ignore
|
||||
setTabsState((old: TabsState) => {
|
||||
let newTabsState = _.cloneDeep(old);
|
||||
newTabsState[
|
||||
id.current
|
||||
].formKeysData.input_keys[key] = e.target.value;
|
||||
return newTabsState;
|
||||
});
|
||||
}}
|
||||
disabled={chatKey === key}
|
||||
placeholder="Enter text..."
|
||||
></Textarea>
|
||||
</div>
|
||||
</AccordionComponent>
|
||||
</div>
|
||||
))
|
||||
: null}
|
||||
{tabsState[id.current].formKeysData.memory_keys.map(
|
||||
(key, index) => (
|
||||
<div className="file-component-accordion-div" key={index}>
|
||||
<AccordionComponent
|
||||
trigger={
|
||||
<div className="file-component-badge-div">
|
||||
<Badge variant="gray" size="md">
|
||||
{i}
|
||||
{key}
|
||||
</Badge>
|
||||
|
||||
<div
|
||||
className="-mb-1"
|
||||
onClick={(event) => {
|
||||
event.stopPropagation();
|
||||
}}
|
||||
>
|
||||
<div className="-mb-1">
|
||||
<ToggleShadComponent
|
||||
enabled={chatKey === i}
|
||||
setEnabled={(value) =>
|
||||
handleOnCheckedChange(value, i)
|
||||
}
|
||||
enabled={chatKey === key}
|
||||
setEnabled={() => {}}
|
||||
size="small"
|
||||
disabled={tabsState[
|
||||
id.current
|
||||
].formKeysData.handle_keys?.some((t) => t === i)}
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
key={k}
|
||||
keyValue={i}
|
||||
key={index}
|
||||
keyValue={key}
|
||||
>
|
||||
<div className="file-component-tab-column">
|
||||
{tabsState[id.current].formKeysData.handle_keys?.some(
|
||||
(t) => t === i
|
||||
) && (
|
||||
<div className="font-normal text-muted-foreground ">
|
||||
Source: Component
|
||||
</div>
|
||||
)}
|
||||
<Textarea
|
||||
className="custom-scroll"
|
||||
value={
|
||||
tabsState[id.current].formKeysData.input_keys![i]
|
||||
}
|
||||
onChange={(e) => {
|
||||
//@ts-ignore
|
||||
setTabsState((old: TabsState) => {
|
||||
let newTabsState = _.cloneDeep(old);
|
||||
newTabsState[id.current].formKeysData.input_keys![
|
||||
i
|
||||
] = e.target.value;
|
||||
return newTabsState;
|
||||
});
|
||||
}}
|
||||
disabled={chatKey === i}
|
||||
placeholder="Enter text..."
|
||||
></Textarea>
|
||||
<div className="font-normal text-muted-foreground ">
|
||||
Source: Memory
|
||||
</div>
|
||||
</div>
|
||||
</AccordionComponent>
|
||||
</div>
|
||||
)
|
||||
)}
|
||||
{tabsState[id.current].formKeysData.memory_keys?.map((i, k) => (
|
||||
<div className="file-component-accordion-div" key={k}>
|
||||
<AccordionComponent
|
||||
trigger={
|
||||
<div className="file-component-badge-div">
|
||||
<Badge variant="gray" size="md">
|
||||
{i}
|
||||
</Badge>
|
||||
<div className="-mb-1">
|
||||
<ToggleShadComponent
|
||||
enabled={chatKey === i}
|
||||
setEnabled={() => {}}
|
||||
size="small"
|
||||
disabled={true}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
key={k}
|
||||
keyValue={i}
|
||||
>
|
||||
<div className="file-component-tab-column">
|
||||
<div className="font-normal text-muted-foreground ">
|
||||
Source: Memory
|
||||
</div>
|
||||
</div>
|
||||
</AccordionComponent>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<div className="eraser-column-arrangement">
|
||||
<div className="eraser-size">
|
||||
|
|
@ -536,14 +545,14 @@ export default function FormModal({
|
|||
</div>
|
||||
<div ref={messagesRef} className="chat-message-div">
|
||||
{chatHistory.length > 0 ? (
|
||||
chatHistory.map((c, i) => (
|
||||
chatHistory.map((chat, index) => (
|
||||
<ChatMessage
|
||||
lockChat={lockChat}
|
||||
chat={c}
|
||||
chat={chat}
|
||||
lastMessage={
|
||||
chatHistory.length - 1 === i ? true : false
|
||||
chatHistory.length - 1 === index ? true : false
|
||||
}
|
||||
key={i}
|
||||
key={index}
|
||||
/>
|
||||
))
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Ref, RefObject, useContext, useEffect, useRef, useState } from "react";
|
||||
import { useContext, useEffect, useRef, useState } from "react";
|
||||
import SanitizedHTMLWrapper from "../../components/SanitizedHTMLWrapper";
|
||||
import ShadTooltip from "../../components/ShadTooltipComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
|
|
@ -198,9 +198,9 @@ export default function GenericModal({
|
|||
setIsEdit(false);
|
||||
}}
|
||||
autoFocus
|
||||
onChange={(e) => {
|
||||
setInputValue(e.target.value);
|
||||
checkVariables(e.target.value);
|
||||
onChange={(event) => {
|
||||
setInputValue(event.target.value);
|
||||
checkVariables(event.target.value);
|
||||
}}
|
||||
placeholder="Type message here."
|
||||
/>
|
||||
|
|
@ -208,12 +208,12 @@ export default function GenericModal({
|
|||
<TextAreaContentView />
|
||||
) : type !== TypeModal.PROMPT ? (
|
||||
<Textarea
|
||||
//@ts-ignore
|
||||
//@ts-ignore
|
||||
ref={ref}
|
||||
className="form-input h-full w-full rounded-lg focus-visible:ring-1"
|
||||
value={inputValue}
|
||||
onChange={(e) => {
|
||||
setInputValue(e.target.value);
|
||||
onChange={(event) => {
|
||||
setInputValue(event.target.value);
|
||||
}}
|
||||
placeholder="Type message here."
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -87,7 +87,7 @@ export default function ButtonBox({
|
|||
<div className="mb-auto mt-auto w-full">
|
||||
<h3
|
||||
className={classNames(
|
||||
"w-full break-words font-semibold text-background truncate-multiline",
|
||||
"w-full font-semibold text-background truncate-multiline word-break-break-word",
|
||||
titleFontSize,
|
||||
marginTop
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -18,9 +18,9 @@ export default function DisclosureComponent({
|
|||
<span className="components-disclosure-title">{title}</span>
|
||||
</div>
|
||||
<div className="components-disclosure-div">
|
||||
{buttons.map((x, index) => (
|
||||
<button key={index} onClick={x.onClick}>
|
||||
{x.Icon}
|
||||
{buttons.map((btn, index) => (
|
||||
<button key={index} onClick={btn.onClick}>
|
||||
{btn.Icon}
|
||||
</button>
|
||||
))}
|
||||
<div>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,12 @@
|
|||
import _ from "lodash";
|
||||
import { MouseEvent, useCallback, useContext, useEffect, useRef, useState } from "react";
|
||||
import {
|
||||
MouseEvent,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import ReactFlow, {
|
||||
Background,
|
||||
Connection,
|
||||
|
|
@ -27,11 +34,11 @@ import { typesContext } from "../../../../contexts/typesContext";
|
|||
import { undoRedoContext } from "../../../../contexts/undoRedoContext";
|
||||
import { APIClassType } from "../../../../types/api";
|
||||
import { FlowType, NodeType } from "../../../../types/flow";
|
||||
import { TabsState } from "../../../../types/tabs";
|
||||
import { isValidConnection } from "../../../../utils/reactflowUtils";
|
||||
import { isWrappedWithClass } from "../../../../utils/utils";
|
||||
import ConnectionLineComponent from "../ConnectionLineComponent";
|
||||
import ExtraSidebar from "../extraSidebarComponent";
|
||||
import { TabsState } from "../../../../types/tabs";
|
||||
|
||||
const nodeTypes = {
|
||||
genericNode: GenericNode,
|
||||
|
|
@ -143,10 +150,10 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
}, [setExtraComponent, setExtraNavigation]);
|
||||
|
||||
const onEdgesChangeMod = useCallback(
|
||||
(s: EdgeChange[]) => {
|
||||
onEdgesChange(s);
|
||||
setNodes((x) => {
|
||||
let newX = _.cloneDeep(x);
|
||||
(change: EdgeChange[]) => {
|
||||
onEdgesChange(change);
|
||||
setNodes((node) => {
|
||||
let newX = _.cloneDeep(node);
|
||||
return newX;
|
||||
});
|
||||
//@ts-ignore
|
||||
|
|
@ -164,8 +171,8 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
);
|
||||
|
||||
const onNodesChangeMod = useCallback(
|
||||
(s: NodeChange[]) => {
|
||||
onNodesChange(s);
|
||||
(change: NodeChange[]) => {
|
||||
onNodesChange(change);
|
||||
//@ts-ignore
|
||||
setTabsState((prev: TabsState) => {
|
||||
return {
|
||||
|
|
@ -197,8 +204,8 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
eds
|
||||
)
|
||||
);
|
||||
setNodes((x) => {
|
||||
let newX = _.cloneDeep(x);
|
||||
setNodes((node) => {
|
||||
let newX = _.cloneDeep(node);
|
||||
return newX;
|
||||
});
|
||||
},
|
||||
|
|
@ -223,7 +230,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
|
||||
const onDragOver = useCallback((event: React.DragEvent) => {
|
||||
event.preventDefault();
|
||||
if (event.dataTransfer.types.some((t) => t === "nodedata")) {
|
||||
if (event.dataTransfer.types.some((types) => types === "nodedata")) {
|
||||
event.dataTransfer.dropEffect = "move";
|
||||
} else {
|
||||
event.dataTransfer.dropEffect = "copy";
|
||||
|
|
@ -233,7 +240,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
const onDrop = useCallback(
|
||||
(event: React.DragEvent) => {
|
||||
event.preventDefault();
|
||||
if (event.dataTransfer.types.some((t) => t === "nodedata")) {
|
||||
if (event.dataTransfer.types.some((types) => types === "nodedata")) {
|
||||
takeSnapshot();
|
||||
|
||||
// Get the current bounds of the ReactFlow wrapper element
|
||||
|
|
@ -283,7 +290,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
// Add the new node to the list of nodes in state
|
||||
}
|
||||
setNodes((nds) => nds.concat(newNode));
|
||||
} else if (event.dataTransfer.types.some((t) => t === "Files")) {
|
||||
} else if (event.dataTransfer.types.some((types) => types === "Files")) {
|
||||
takeSnapshot();
|
||||
uploadFlow(false, event.dataTransfer.files.item(0)!);
|
||||
}
|
||||
|
|
@ -305,7 +312,10 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
takeSnapshot();
|
||||
setEdges(
|
||||
edges.filter(
|
||||
(ns) => !mynodes.some((n) => ns.source === n.id || ns.target === n.id)
|
||||
(edge) =>
|
||||
!mynodes.some(
|
||||
(node) => edge.source === node.id || edge.target === node.id
|
||||
)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
|
@ -328,7 +338,7 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
|
||||
const onEdgeUpdateEnd = useCallback((_, edge: Edge): void => {
|
||||
if (!edgeUpdateSuccessful.current) {
|
||||
setEdges((eds) => eds.filter((e) => e.id !== edge.id));
|
||||
setEdges((eds) => eds.filter((edg) => edg.id !== edge.id));
|
||||
}
|
||||
edgeUpdateSuccessful.current = true;
|
||||
}, []);
|
||||
|
|
@ -352,9 +362,12 @@ export default function Page({ flow }: { flow: FlowType }): JSX.Element {
|
|||
}
|
||||
}, [selectionEnded, lastSelection]);
|
||||
|
||||
const onSelectionChange = useCallback((flow: OnSelectionChangeParams): void => {
|
||||
setLastSelection(flow);
|
||||
}, []);
|
||||
const onSelectionChange = useCallback(
|
||||
(flow: OnSelectionChangeParams): void => {
|
||||
setLastSelection(flow);
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="flex h-full overflow-hidden">
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
return ret;
|
||||
});
|
||||
}
|
||||
const flow = flows.find((f) => f.id === tabId);
|
||||
const flow = flows.find((flow) => flow.id === tabId);
|
||||
useEffect(() => {
|
||||
// show components with error on load
|
||||
let errors: string[] = [];
|
||||
|
|
@ -143,10 +143,10 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
id="search"
|
||||
placeholder="Search"
|
||||
className="nopan nodrag noundo nocopy input-search"
|
||||
onChange={(e) => {
|
||||
handleSearchInput(e.target.value);
|
||||
onChange={(event) => {
|
||||
handleSearchInput(event.target.value);
|
||||
// Set search input state
|
||||
setSearch(e.target.value);
|
||||
setSearch(event.target.value);
|
||||
}}
|
||||
/>
|
||||
<div className="search-icon">
|
||||
|
|
@ -161,42 +161,43 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
<div className="side-bar-components-div-arrangement">
|
||||
{Object.keys(dataFilter)
|
||||
.sort()
|
||||
.map((d: keyof APIObjectType, i) =>
|
||||
Object.keys(dataFilter[d]).length > 0 ? (
|
||||
.map((SBSectionName: keyof APIObjectType, index) =>
|
||||
Object.keys(dataFilter[SBSectionName]).length > 0 ? (
|
||||
<DisclosureComponent
|
||||
openDisc={search.length == 0 ? false : true}
|
||||
key={i}
|
||||
key={index}
|
||||
button={{
|
||||
title: nodeNames[d] ?? nodeNames.unknown,
|
||||
Icon: nodeIconsLucide[d] ?? nodeIconsLucide.unknown,
|
||||
title: nodeNames[SBSectionName] ?? nodeNames.unknown,
|
||||
Icon:
|
||||
nodeIconsLucide[SBSectionName] ?? nodeIconsLucide.unknown,
|
||||
}}
|
||||
>
|
||||
<div className="side-bar-components-gap">
|
||||
{Object.keys(dataFilter[d])
|
||||
{Object.keys(dataFilter[SBSectionName])
|
||||
.sort()
|
||||
.map((t: string, k) => (
|
||||
.map((SBItemName: string, index) => (
|
||||
<ShadTooltip
|
||||
content={data[d][t].display_name}
|
||||
content={data[SBSectionName][SBItemName].display_name}
|
||||
side="right"
|
||||
key={k}
|
||||
key={index}
|
||||
>
|
||||
<div key={k} data-tooltip-id={t}>
|
||||
<div key={index} data-tooltip-id={SBItemName}>
|
||||
<div
|
||||
draggable={!data[d][t].error}
|
||||
draggable={!data[SBSectionName][SBItemName].error}
|
||||
className={
|
||||
"side-bar-components-border bg-background" +
|
||||
(data[d][t].error
|
||||
(data[SBSectionName][SBItemName].error
|
||||
? " cursor-not-allowed select-none"
|
||||
: "")
|
||||
}
|
||||
style={{
|
||||
borderLeftColor:
|
||||
nodeColors[d] ?? nodeColors.unknown,
|
||||
nodeColors[SBSectionName] ?? nodeColors.unknown,
|
||||
}}
|
||||
onDragStart={(event) =>
|
||||
onDragStart(event, {
|
||||
type: t,
|
||||
node: data[d][t],
|
||||
type: SBItemName,
|
||||
node: data[SBSectionName][SBItemName],
|
||||
})
|
||||
}
|
||||
onDragEnd={() => {
|
||||
|
|
@ -209,7 +210,7 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
>
|
||||
<div className="side-bar-components-div-form">
|
||||
<span className="side-bar-components-text">
|
||||
{data[d][t].display_name}
|
||||
{data[SBSectionName][SBItemName].display_name}
|
||||
</span>
|
||||
<IconComponent
|
||||
name="Menu"
|
||||
|
|
@ -223,7 +224,7 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
</div>
|
||||
</DisclosureComponent>
|
||||
) : (
|
||||
<div key={i}></div>
|
||||
<div key={index}></div>
|
||||
)
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,17 +14,17 @@ export default function NodeToolbarComponent({
|
|||
}: nodeToolbarPropsType): JSX.Element {
|
||||
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 === "Any" ||
|
||||
data.node.template[t].type === "int")
|
||||
(templateField) =>
|
||||
templateField.charAt(0) !== "_" &&
|
||||
data.node?.template[templateField].show &&
|
||||
(data.node.template[templateField].type === "str" ||
|
||||
data.node.template[templateField].type === "bool" ||
|
||||
data.node.template[templateField].type === "float" ||
|
||||
data.node.template[templateField].type === "code" ||
|
||||
data.node.template[templateField].type === "prompt" ||
|
||||
data.node.template[templateField].type === "file" ||
|
||||
data.node.template[templateField].type === "Any" ||
|
||||
data.node.template[templateField].type === "int")
|
||||
).length
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -301,13 +301,13 @@
|
|||
}
|
||||
|
||||
.error-build-message {
|
||||
@apply mt-6 w-96 cursor-pointer rounded-md bg-error-background p-4 shadow-xl;
|
||||
@apply mt-6 w-96 cursor-pointer rounded-md bg-error-background p-4 shadow-xl;
|
||||
}
|
||||
.error-build-message-circle {
|
||||
@apply alert-icon text-status-red;
|
||||
}
|
||||
.error-build-text {
|
||||
@apply text-error-foreground;
|
||||
@apply text-error-foreground word-break-break-word;
|
||||
}
|
||||
.error-build-foreground {
|
||||
@apply error-build-text alert-font-size;
|
||||
|
|
@ -326,7 +326,7 @@
|
|||
@apply alert-icon text-status-green;
|
||||
}
|
||||
.success-alert-message {
|
||||
@apply alert-font-size text-success-foreground;
|
||||
@apply word-break-break-word alert-font-size text-success-foreground;
|
||||
}
|
||||
|
||||
.card-component-title-display {
|
||||
|
|
@ -336,7 +336,7 @@
|
|||
@apply flex h-7 w-7 items-center justify-center rounded-full text-2xl;
|
||||
}
|
||||
.card-component-title-size {
|
||||
@apply inline-block w-full flex-1 break-words truncate-doubleline;
|
||||
@apply w-full flex-1 word-break-break-word truncate-doubleline;
|
||||
}
|
||||
.card-component-delete-button {
|
||||
@apply flex self-start;
|
||||
|
|
@ -495,6 +495,12 @@
|
|||
.header-github-link-box {
|
||||
@apply inline-flex h-9 items-center justify-center rounded-md border border-input px-3 pr-0 shadow-sm;
|
||||
}
|
||||
.header-waitlist-link-box {
|
||||
@apply inline-flex h-9 items-center justify-center rounded-md border border-input px-2 shadow-sm text-sm font-medium text-muted-foreground ring-offset-background disabled:pointer-events-none disabled:opacity-50 whitespace-nowrap;
|
||||
}
|
||||
.header-waitlist-link-box:hover {
|
||||
@apply hover:bg-accent hover:text-accent-foreground;
|
||||
}
|
||||
.header-github-link {
|
||||
@apply header-github-link-box text-sm font-medium text-muted-foreground ring-offset-background disabled:pointer-events-none disabled:opacity-50;
|
||||
}
|
||||
|
|
@ -544,7 +550,7 @@
|
|||
@apply focus:outline-none focus:ring-1 focus:ring-primary focus:ring-offset-1;
|
||||
}
|
||||
.toggle-component-span {
|
||||
@apply pointer-events-none relative inline-block h-5 w-5 transform rounded-full shadow ring-0 transition duration-200 ease-in-out;
|
||||
@apply pointer-events-none relative h-5 w-5 transform rounded-full shadow ring-0 transition duration-200 ease-in-out;
|
||||
}
|
||||
.toggle-component-second-span {
|
||||
@apply absolute inset-0 flex h-full w-full items-center justify-center transition-opacity;
|
||||
|
|
@ -590,13 +596,13 @@
|
|||
@apply flex-max-width items-center text-start;
|
||||
}
|
||||
.chat-message-modal-text {
|
||||
@apply relative inline-block w-full text-start text-sm font-normal text-muted-foreground;
|
||||
@apply relative w-full text-start text-sm font-normal text-muted-foreground;
|
||||
}
|
||||
.chat-message-modal-icon-div {
|
||||
@apply absolute -left-2 -top-1 cursor-pointer;
|
||||
}
|
||||
.chat-message-modal-thought {
|
||||
@apply chat-message-modal-thought-cursor ml-3 inline-block h-full w-[95%] rounded-md border border-ring bg-muted px-2 pb-3 pt-3 text-start text-muted-foreground;
|
||||
@apply chat-message-modal-thought-cursor ml-3 h-full w-[95%] rounded-md border border-ring bg-muted px-2 pb-3 pt-3 text-start text-muted-foreground;
|
||||
}
|
||||
.chat-message-modal-thought-cursor {
|
||||
@apply cursor-pointer overflow-scroll scrollbar-hide;
|
||||
|
|
@ -608,7 +614,7 @@
|
|||
@apply mt-1 animate-pulse cursor-default;
|
||||
}
|
||||
.chat-message-modal-alert {
|
||||
@apply inline-block px-3 text-start text-muted-foreground;
|
||||
@apply px-3 text-start text-muted-foreground;
|
||||
}
|
||||
|
||||
.file-card-modal-image-div {
|
||||
|
|
@ -852,11 +858,11 @@
|
|||
@apply bg-white text-primary;
|
||||
}
|
||||
.code-highlight {
|
||||
@apply block max-h-[64vh] w-full overflow-y-hidden break-all border-0 px-3 py-2 text-sm outline-0;
|
||||
@apply block max-h-[64vh] w-full overflow-y-hidden word-break-break-word border-0 px-3 py-2 text-sm outline-0;
|
||||
}
|
||||
|
||||
.code-nohighlight {
|
||||
@apply block max-h-[70vh] w-full overflow-y-hidden break-all border-0 px-3 py-2 text-sm outline-0;
|
||||
@apply block max-h-[70vh] w-full overflow-y-hidden word-break-break-word border-0 px-3 py-2 text-sm outline-0;
|
||||
}
|
||||
.form-modal-lockchat {
|
||||
@apply form-input block w-full rounded-md border-border p-4 pr-16 custom-scroll focus:border-ring focus:ring-ring sm:text-sm;
|
||||
|
|
@ -913,7 +919,7 @@
|
|||
@apply rounded-md border border-ring/60;
|
||||
}
|
||||
.form-modal-chat-thought-size {
|
||||
@apply inline-block h-full w-[95%];
|
||||
@apply h-full w-[95%];
|
||||
}
|
||||
.form-modal-chat-thought {
|
||||
@apply form-modal-chat-thought-border form-modal-chat-thought-size cursor-pointer overflow-scroll bg-background px-2 py-2 text-start text-primary scrollbar-hide;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,10 @@
|
|||
import _ from "lodash";
|
||||
import { Connection, ReactFlowInstance, ReactFlowJsonObject } from "reactflow";
|
||||
import {
|
||||
Connection,
|
||||
Edge,
|
||||
ReactFlowInstance,
|
||||
ReactFlowJsonObject,
|
||||
} from "reactflow";
|
||||
import { APITemplateType } from "../types/api";
|
||||
import { FlowType, NodeType } from "../types/flow";
|
||||
import { cleanEdgesType } from "../types/utils/reactflowUtils";
|
||||
|
|
@ -15,7 +20,7 @@ export function cleanEdges({
|
|||
const sourceNode = nodes.find((node) => node.id === edge.source);
|
||||
const targetNode = nodes.find((node) => node.id === edge.target);
|
||||
if (!sourceNode || !targetNode) {
|
||||
newEdges = newEdges.filter((e) => e.id !== edge.id);
|
||||
newEdges = newEdges.filter((edg) => edg.id !== edge.id);
|
||||
}
|
||||
// check if the source and target handle still exists
|
||||
if (sourceNode && targetNode) {
|
||||
|
|
@ -41,7 +46,7 @@ export function cleanEdges({
|
|||
...sourceNode.data.node?.base_classes!,
|
||||
].join("|");
|
||||
if (id !== sourceHandle) {
|
||||
newEdges = newEdges.filter((e) => e.id !== edge.id);
|
||||
newEdges = newEdges.filter((edg) => edg.id !== edge.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -57,15 +62,15 @@ export function isValidConnection(
|
|||
targetHandle
|
||||
?.split("|")[0]
|
||||
.split(";")
|
||||
.some((n) => n === sourceHandle?.split("|")[0]) ||
|
||||
.some((target) => target === sourceHandle?.split("|")[0]) ||
|
||||
sourceHandle
|
||||
?.split("|")
|
||||
.slice(2)
|
||||
.some((t) =>
|
||||
.some((target) =>
|
||||
targetHandle
|
||||
?.split("|")[0]
|
||||
.split(";")
|
||||
.some((n) => n === t)
|
||||
.some((n) => n === target)
|
||||
) ||
|
||||
targetHandle?.split("|")[0] === "str"
|
||||
) {
|
||||
|
|
@ -126,38 +131,41 @@ export function updateTemplate(
|
|||
return clonedObject;
|
||||
}
|
||||
|
||||
export function updateIds(newFlow: ReactFlowJsonObject, getNodeId: (type: string) => string) {
|
||||
export function updateIds(
|
||||
newFlow: ReactFlowJsonObject,
|
||||
getNodeId: (type: string) => string
|
||||
) {
|
||||
let idsMap = {};
|
||||
|
||||
newFlow.nodes.forEach((n: NodeType) => {
|
||||
newFlow.nodes.forEach((node: NodeType) => {
|
||||
// Generate a unique node ID
|
||||
let newId = getNodeId(n.data.type);
|
||||
idsMap[n.id] = newId;
|
||||
n.id = newId;
|
||||
n.data.id = newId;
|
||||
let newId = getNodeId(node.data.type);
|
||||
idsMap[node.id] = newId;
|
||||
node.id = newId;
|
||||
node.data.id = newId;
|
||||
// Add the new node to the list of nodes in state
|
||||
});
|
||||
|
||||
newFlow.edges.forEach((e) => {
|
||||
e.source = idsMap[e.source];
|
||||
e.target = idsMap[e.target];
|
||||
let sourceHandleSplitted = e.sourceHandle!.split("|");
|
||||
e.sourceHandle =
|
||||
newFlow.edges.forEach((edge) => {
|
||||
edge.source = idsMap[edge.source];
|
||||
edge.target = idsMap[edge.target];
|
||||
let sourceHandleSplitted = edge.sourceHandle!.split("|");
|
||||
edge.sourceHandle =
|
||||
sourceHandleSplitted[0] +
|
||||
"|" +
|
||||
e.source +
|
||||
edge.source +
|
||||
"|" +
|
||||
sourceHandleSplitted.slice(2).join("|");
|
||||
let targetHandleSplitted = e.targetHandle!.split("|");
|
||||
e.targetHandle =
|
||||
targetHandleSplitted.slice(0, -1).join("|") + "|" + e.target;
|
||||
e.id =
|
||||
let targetHandleSplitted = edge.targetHandle!.split("|");
|
||||
edge.targetHandle =
|
||||
targetHandleSplitted.slice(0, -1).join("|") + "|" + edge.target;
|
||||
edge.id =
|
||||
"reactflow__edge-" +
|
||||
e.source +
|
||||
e.sourceHandle +
|
||||
edge.source +
|
||||
edge.sourceHandle +
|
||||
"-" +
|
||||
e.target +
|
||||
e.targetHandle;
|
||||
edge.target +
|
||||
edge.targetHandle;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -169,10 +177,10 @@ export function buildTweaks(flow: FlowType) {
|
|||
}
|
||||
|
||||
export function validateNode(
|
||||
n: NodeType,
|
||||
node: NodeType,
|
||||
reactFlowInstance: ReactFlowInstance
|
||||
): Array<string> {
|
||||
if (!n.data?.node?.template || !Object.keys(n.data.node.template)) {
|
||||
if (!node.data?.node?.template || !Object.keys(node.data.node.template)) {
|
||||
return [
|
||||
"We've noticed a potential issue with a node in the flow. Please review it and, if necessary, submit a bug report with your exported flow file. Thank you for your help!",
|
||||
];
|
||||
|
|
@ -181,7 +189,7 @@ export function validateNode(
|
|||
const {
|
||||
type,
|
||||
node: { template },
|
||||
} = n.data;
|
||||
} = node.data;
|
||||
|
||||
return Object.keys(template).reduce(
|
||||
(errors: Array<string>, t) =>
|
||||
|
|
@ -194,9 +202,9 @@ export function validateNode(
|
|||
!reactFlowInstance
|
||||
.getEdges()
|
||||
.some(
|
||||
(e) =>
|
||||
e.targetHandle?.split("|")[1] === t &&
|
||||
e.targetHandle.split("|")[2] === n.id
|
||||
(edge) =>
|
||||
edge.targetHandle?.split("|")[1] === t &&
|
||||
edge.targetHandle.split("|")[2] === node.id
|
||||
)
|
||||
? [
|
||||
`${type} is missing ${
|
||||
|
|
@ -232,3 +240,12 @@ export function addVersionToDuplicates(flow: FlowType, flows: FlowType[]) {
|
|||
|
||||
return newName;
|
||||
}
|
||||
|
||||
export function getConnectedNodes(
|
||||
edge: Edge,
|
||||
nodes: Array<NodeType>
|
||||
): Array<NodeType> {
|
||||
const sourceId = edge.source;
|
||||
const targetId = edge.target;
|
||||
return nodes.filter((node) => node.id === targetId || node.id === sourceId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,6 @@ import {
|
|||
XCircle,
|
||||
Zap,
|
||||
} from "lucide-react";
|
||||
import { Edge, Node } from "reactflow";
|
||||
import { AirbyteIcon } from "../icons/Airbyte";
|
||||
import { AnthropicIcon } from "../icons/Anthropic";
|
||||
import { BingIcon } from "../icons/Bing";
|
||||
|
|
@ -207,6 +206,7 @@ export const nodeIconsLucide: iconsType = {
|
|||
SupabaseVectorStore: SupabaseIcon,
|
||||
VertexAI: VertexAIIcon,
|
||||
ChatVertexAI: VertexAIIcon,
|
||||
VertexAIEmbeddings: VertexAIIcon,
|
||||
agents: Rocket,
|
||||
WikipediaAPIWrapper: SvgWikipedia,
|
||||
chains: Link,
|
||||
|
|
@ -278,8 +278,3 @@ export const nodeIconsLucide: iconsType = {
|
|||
MessageSquare,
|
||||
MoreHorizontal,
|
||||
};
|
||||
export function getConnectedNodes(edge: Edge, nodes: Array<Node>): Array<Node> {
|
||||
const sourceId = edge.source;
|
||||
const targetId = edge.target;
|
||||
return nodes.filter((node) => node.id === targetId || node.id === sourceId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
import clsx, { ClassValue } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import { ADJECTIVES, DESCRIPTIONS, NOUNS } from "../flow_constants";
|
||||
import { IVarHighlightType, groupDataType, groupedObjType, tweakType } from "../types/components";
|
||||
import { APIDataType } from "../types/api";
|
||||
import {
|
||||
IVarHighlightType,
|
||||
groupedObjType,
|
||||
tweakType,
|
||||
} from "../types/components";
|
||||
import { FlowType, NodeType } from "../types/flow";
|
||||
import { TabsState } from "../types/tabs";
|
||||
import { buildTweaks } from "./reactflowUtils";
|
||||
import { APIClassType, APIDataType, APIObjectType } from "../types/api";
|
||||
|
||||
export function classNames(...classes: Array<string>): string {
|
||||
return classes.filter(Boolean).join(" ");
|
||||
|
|
@ -89,10 +93,23 @@ export function checkUpperWords(str: string): string {
|
|||
export const isWrappedWithClass = (event: any, className: string | undefined) =>
|
||||
event.target.closest(`.${className}`);
|
||||
|
||||
export function groupByFamily(data: APIDataType, baseClasses: string, left: boolean, flow?: NodeType[]): groupedObjType[] {
|
||||
export function groupByFamily(
|
||||
data: APIDataType,
|
||||
baseClasses: string,
|
||||
left: boolean,
|
||||
flow?: NodeType[]
|
||||
): groupedObjType[] {
|
||||
const baseClassesSet = new Set(baseClasses.split("\n"));
|
||||
let arrOfPossibleInputs: Array<{ category: string; nodes: string[]; full: boolean; }> = [];
|
||||
let arrOfPossibleOutputs: Array<{ category: string; nodes: string[]; full: boolean; }> = [];
|
||||
let arrOfPossibleInputs: Array<{
|
||||
category: string;
|
||||
nodes: string[];
|
||||
full: boolean;
|
||||
}> = [];
|
||||
let arrOfPossibleOutputs: Array<{
|
||||
category: string;
|
||||
nodes: string[];
|
||||
full: boolean;
|
||||
}> = [];
|
||||
let checkedNodes = new Map();
|
||||
const excludeTypes = new Set([
|
||||
"str",
|
||||
|
|
@ -104,11 +121,14 @@ export function groupByFamily(data: APIDataType, baseClasses: string, left: bool
|
|||
"int",
|
||||
]);
|
||||
|
||||
const checkBaseClass = (t) =>
|
||||
t.type &&
|
||||
t.show &&
|
||||
((!excludeTypes.has(t.type) && baseClassesSet.has(t.type)) ||
|
||||
(t.input_types && t.input_types.some((x) => baseClassesSet.has(x))));
|
||||
const checkBaseClass = (template) =>
|
||||
template.type &&
|
||||
template.show &&
|
||||
((!excludeTypes.has(template.type) && baseClassesSet.has(template.type)) ||
|
||||
(template.input_types &&
|
||||
template.input_types.some((inputType) =>
|
||||
baseClassesSet.has(inputType)
|
||||
)));
|
||||
|
||||
if (flow) {
|
||||
for (const node of flow) {
|
||||
|
|
@ -120,7 +140,9 @@ export function groupByFamily(data: APIDataType, baseClasses: string, left: bool
|
|||
Object.values(nodeData.node!.template).some(checkBaseClass),
|
||||
hasBaseClassInBaseClasses:
|
||||
foundNode?.hasBaseClassInBaseClasses ||
|
||||
nodeData.node!.base_classes.some((t) => baseClassesSet.has(t)),
|
||||
nodeData.node!.base_classes.some((baseClass) =>
|
||||
baseClassesSet.has(baseClass)
|
||||
),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -136,8 +158,8 @@ export function groupByFamily(data: APIDataType, baseClasses: string, left: bool
|
|||
hasBaseClassInTemplate: Object.values(node!.template).some(
|
||||
checkBaseClass
|
||||
),
|
||||
hasBaseClassInBaseClasses: node!.base_classes.some((t) =>
|
||||
baseClassesSet.has(t)
|
||||
hasBaseClassInBaseClasses: node!.base_classes.some((baseClass) =>
|
||||
baseClassesSet.has(baseClass)
|
||||
),
|
||||
};
|
||||
checkedNodes.set(n, foundNode);
|
||||
|
|
@ -163,13 +185,13 @@ export function groupByFamily(data: APIDataType, baseClasses: string, left: bool
|
|||
}
|
||||
|
||||
return left
|
||||
? arrOfPossibleOutputs.map((t) => ({
|
||||
family: t.category,
|
||||
type: t.full ? "" : t.nodes.join(", "),
|
||||
? arrOfPossibleOutputs.map((output) => ({
|
||||
family: output.category,
|
||||
type: output.full ? "" : output.nodes.join(", "),
|
||||
}))
|
||||
: arrOfPossibleInputs.map((t) => ({
|
||||
family: t.category,
|
||||
type: t.full ? "" : t.nodes.join(", "),
|
||||
: arrOfPossibleInputs.map((input) => ({
|
||||
family: input.category,
|
||||
type: input.full ? "" : input.nodes.join(", "),
|
||||
}));
|
||||
}
|
||||
|
||||
|
|
@ -248,6 +270,27 @@ export function buildTweakObject(tweak: tweakType) {
|
|||
return tweakString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get Chat Input Field
|
||||
* @param {FlowType} flow - The current flow.
|
||||
* @param {TabsState} tabsState - The current tabs state.
|
||||
* @returns {string} - The chat input field
|
||||
*/
|
||||
export function getChatInputField(flow: FlowType, tabsState?: TabsState) {
|
||||
let chat_input_field = "text";
|
||||
|
||||
if (
|
||||
tabsState[flow.id] &&
|
||||
tabsState[flow.id].formKeysData &&
|
||||
tabsState[flow.id].formKeysData.input_keys
|
||||
) {
|
||||
chat_input_field = Object.keys(
|
||||
tabsState[flow.id].formKeysData.input_keys
|
||||
)[0];
|
||||
}
|
||||
return chat_input_field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to get the python code for the API
|
||||
* @param {string} flowId - The id of the flow
|
||||
|
|
@ -365,6 +408,7 @@ export function getWidgetCode(flow: FlowType, tabsState?: TabsState): string {
|
|||
const flowId = flow.id;
|
||||
const flowName = flow.name;
|
||||
const inputs = buildInputs(tabsState!, flow.id);
|
||||
let chat_input_field = getChatInputField(flow, tabsState);
|
||||
|
||||
return `<script src="https://cdn.jsdelivr.net/gh/logspace-ai/langflow-embedded-chat@main/dist/build/static/js/bundle.min.js"></script>
|
||||
|
||||
|
|
@ -377,11 +421,88 @@ chat_input_field: Input key that you want the chat to send the user message with
|
|||
${
|
||||
tabsState![flow.id] && tabsState![flow.id].formKeysData
|
||||
? `chat_inputs='${inputs}'
|
||||
chat_input_field="${
|
||||
Object.keys(tabsState![flow.id].formKeysData.input_keys!)[0]
|
||||
}"
|
||||
chat_input_field="${chat_input_field}"
|
||||
`
|
||||
: ""
|
||||
}host_url="http://localhost:7860"
|
||||
}host_url="http://localhost:7860"
|
||||
></langflow-chat>`;
|
||||
}
|
||||
|
||||
export function tabsArray(codes: string[], method: number) {
|
||||
if (!method) return;
|
||||
if (method === 0) {
|
||||
return [
|
||||
{
|
||||
name: "cURL",
|
||||
mode: "bash",
|
||||
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||
language: "sh",
|
||||
code: codes[0],
|
||||
},
|
||||
{
|
||||
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: codes[1],
|
||||
},
|
||||
{
|
||||
name: "Python Code",
|
||||
mode: "python",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: codes[2],
|
||||
},
|
||||
{
|
||||
name: "Chat Widget HTML",
|
||||
description:
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
|
||||
mode: "html",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: codes[3],
|
||||
},
|
||||
];
|
||||
}
|
||||
return [
|
||||
{
|
||||
name: "cURL",
|
||||
mode: "bash",
|
||||
image: "https://curl.se/logo/curl-symbol-transparent.png",
|
||||
language: "sh",
|
||||
code: codes[0],
|
||||
},
|
||||
{
|
||||
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: codes[1],
|
||||
},
|
||||
{
|
||||
name: "Python Code",
|
||||
mode: "python",
|
||||
language: "py",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
code: codes[2],
|
||||
},
|
||||
{
|
||||
name: "Chat Widget HTML",
|
||||
description:
|
||||
"Insert this code anywhere in your <body> tag. To use with react and other libs, check our <a class='link-color' href='https://langflow.org/guidelines/widget'>documentation</a>.",
|
||||
mode: "html",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: codes[3],
|
||||
},
|
||||
{
|
||||
name: "Tweaks",
|
||||
mode: "python",
|
||||
image: "https://cdn-icons-png.flaticon.com/512/5968/5968350.png",
|
||||
language: "py",
|
||||
code: codes[4],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,7 +155,9 @@ module.exports = {
|
|||
overflow: "hidden",
|
||||
"text-overflow": "ellipsis",
|
||||
},
|
||||
|
||||
".word-break-break-word": {
|
||||
wordBreak: "break-word",
|
||||
},
|
||||
".arrow-hide": {
|
||||
"&::-webkit-inner-spin-button": {
|
||||
"-webkit-appearance": "none",
|
||||
|
|
|
|||
|
|
@ -6,6 +6,9 @@ const apiRoutes = ["^/api/v1/", "/health"];
|
|||
// Use environment variable to determine the target.
|
||||
const target = process.env.VITE_PROXY_TARGET || "http://127.0.0.1:7860";
|
||||
|
||||
// Use environment variable to determine the UI server port
|
||||
const port = process.env.VITE_PORT || 3000;
|
||||
|
||||
const proxyTargets = apiRoutes.reduce((proxyObj, route) => {
|
||||
proxyObj[route] = {
|
||||
target: target,
|
||||
|
|
@ -22,7 +25,7 @@ export default defineConfig(() => {
|
|||
},
|
||||
plugins: [react(), svgr()],
|
||||
server: {
|
||||
port: 3000,
|
||||
port: port,
|
||||
proxy: {
|
||||
...proxyTargets,
|
||||
},
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue