Migrate Tweaks Module to Zustand Library and Add All Flows (#1847)
* ✨ (codeTabsComponent/index.tsx): refactor code to remove unnecessary code and improve readability 📝 (codeTabsComponent/index.tsx): update comments in source code to provide better understanding of the code logic ♻️ (apiModal/index.tsx): refactor code to remove unnecessary code and improve readability 📝 (apiModal/index.tsx): update comments in source code to provide better understanding of the code logic 🔧 (tweaksStore.ts): add new store for managing tweaks data 📝 (components/index.ts): update codeTabsPropsType to use array syntax for tweak and tweaksList properties for better readability and consistency ♻️ (utils/utils.ts): refactor toTitleCase function to remove unnecessary comma and improve code readability ♻️ (utils/utils.ts): refactor groupByFamily function to remove unnecessary comma and improve code readability ♻️ (utils/utils.ts): refactor getPythonApiCode function to remove unnecessary comma and improve code readability ♻️ (utils/utils.ts): refactor getCurlCode function to remove unnecessary comma and improve code readability ♻️ (utils/utils.ts): refactor getPythonCode function to remove unnecessary comma and improve code readability ♻️ (utils/utils.ts): refactor getWidgetCode function to remove unnecessary comma and improve code readability ♻️ (utils/utils.ts): refactor getFieldTitle function to remove unnecessary comma and improve code readability ♻️ (utils/utils.ts): refactor IncrementObjectKey function to remove unnecessary comma and improve code readability ♻️ (utils/utils.ts): refactor getSetFromObject function to remove unnecessary comma and improve code readability ♻️ (utils/utils.ts): refactor getRandomName function to remove unnecessary comma and improve code readability * 📝 (codeTabsComponent/index.tsx): remove unnecessary whitespace in className ♻️ (codeTabsComponent/index.tsx): refactor code to improve readability and remove unnecessary code ♻️ (apiModal/index.tsx): refactor code to improve readability and remove unnecessary code ♻️ (tweaksStore.ts): refactor code to improve readability and remove unnecessary code ✨ (zustand/tweaks/index.ts): add types for tweaks store * ✨ (codeTabsComponent/index.tsx): refactor code to improve readability and remove unnecessary code ♻️ (codeTabsComponent/index.tsx): refactor code to improve readability and remove unnecessary code ♻️ (utils/utils.ts): refactor code to improve readability and remove unnecessary code ✅ (tweaks_test.spec.ts): add end-to-end test to check if tweaks are updating when something on the flow changes * 🐛 (accordionComponent/index.tsx): fix variable name from 'trigger' to 'keyValue' for better clarity and readability ♻️ (accordionComponent/index.tsx): refactor code to use 'defaultValue' prop instead of manually setting the value in the AccordionItem component 🐛 (codeTabsComponent/index.tsx): remove unused 'openAccordions' function ♻️ (codeTabsComponent/index.tsx): refactor code to remove unnecessary condition for opening accordions in the onValueChange event handler ♻️ (codeTabsComponent/index.tsx): refactor code to remove unused 'open' prop in AccordionItem component ♻️ (codeTabsComponent/index.tsx): refactor code to remove unused 'openAccordion' state variable ♻️ (codeTabsComponent/index.tsx): refactor code to remove unused 'openAccordions' function call in the onValueChange event handler * 🐛 (apiModal/index.tsx): remove unnecessary comma after ref parameter in ApiModal component ♻️ (apiModal/index.tsx): refactor code to improve readability and remove unnecessary commas in function parameters ✨ (apiModal/index.tsx): add conditional check before assigning values to tabs array to prevent errors when tabs is undefined or empty * 🐛 (index.tsx): remove unnecessary defaultValue prop from Accordion component ♻️ (index.tsx): refactor AccordionItem component to remove defaultValue prop and simplify code * 🐛 (apiModal/index.tsx): remove unnecessary comma after ref parameter in function signature ♻️ (apiModal/index.tsx): refactor code to improve readability and remove unnecessary comma after ref parameter in function signature * refactor tweaks * ✨ (codeTabsComponent/index.tsx): add autoFocus prop to the tweaks switch to prevent it from automatically gaining focus when rendered ♻️ (codeTabsComponent/index.tsx): refactor classNames in the api-modal-according-display div to remove unnecessary whitespace ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api-modal-according-display div to improve readability and remove unnecessary parentheses ♻️ (codeTabsComponent/index.tsx): refactor mapping of templateFields in the api * fix tests on tweaks
This commit is contained in:
parent
71324440a2
commit
c69f950cba
17 changed files with 575 additions and 435 deletions
|
|
@ -15,17 +15,16 @@ export default function AccordionComponent({
|
|||
sideBar,
|
||||
}: AccordionComponentType): JSX.Element {
|
||||
const [value, setValue] = useState(
|
||||
open.length === 0 ? "" : getOpenAccordion()
|
||||
open.length === 0 ? "" : getOpenAccordion(),
|
||||
);
|
||||
|
||||
function getOpenAccordion(): string {
|
||||
let value = "";
|
||||
open.forEach((el) => {
|
||||
if (el == trigger) {
|
||||
value = trigger;
|
||||
if (el == keyValue) {
|
||||
value = keyValue;
|
||||
}
|
||||
});
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { Transition } from "@headlessui/react";
|
||||
import { useEffect, useMemo, useRef, useState } from "react";
|
||||
import IOModal from "../../modals/IOModal";
|
||||
import ApiModal from "../../modals/apiModal";
|
||||
import ApiModal from "../../modals/apiModal/views";
|
||||
import ShareModal from "../../modals/shareModal";
|
||||
import useFlowStore from "../../stores/flowStore";
|
||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ import IconComponent from "../genericIconComponent";
|
|||
import InputComponent from "../inputComponent";
|
||||
import KeypairListComponent from "../keypairListComponent";
|
||||
import ShadTooltip from "../shadTooltipComponent";
|
||||
import { Label } from "../ui/label";
|
||||
import { Switch } from "../ui/switch";
|
||||
|
||||
export default function CodeTabsComponent({
|
||||
flow,
|
||||
|
|
@ -49,14 +51,13 @@ export default function CodeTabsComponent({
|
|||
setActiveTab,
|
||||
isMessage,
|
||||
tweaks,
|
||||
setActiveTweaks,
|
||||
activeTweaks,
|
||||
}: codeTabsPropsType) {
|
||||
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
||||
const [data, setData] = useState(flow ? flow["data"]!["nodes"] : null);
|
||||
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
|
||||
const dark = useDarkStore((state) => state.dark);
|
||||
const unselectAll = useFlowStore((state) => state.unselectAll);
|
||||
const setNode = useFlowStore((state) => state.setNode);
|
||||
|
||||
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
|
|
@ -107,21 +108,6 @@ export default function CodeTabsComponent({
|
|||
URL.revokeObjectURL(url);
|
||||
};
|
||||
|
||||
function openAccordions() {
|
||||
let accordionsToOpen: string[] = [];
|
||||
tweaks?.tweak!.current.forEach((el) => {
|
||||
Object.keys(el).forEach((key) => {
|
||||
if (Object.keys(el[key]).length > 0) {
|
||||
accordionsToOpen.push(key);
|
||||
setOpenAccordion(accordionsToOpen);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (accordionsToOpen.length == 0) {
|
||||
setOpenAccordion([]);
|
||||
}
|
||||
}
|
||||
return (
|
||||
<Tabs
|
||||
value={activeTab}
|
||||
|
|
@ -132,9 +118,6 @@ export default function CodeTabsComponent({
|
|||
}
|
||||
onValueChange={(value) => {
|
||||
setActiveTab(value);
|
||||
if (value === "3") {
|
||||
openAccordions();
|
||||
}
|
||||
}}
|
||||
>
|
||||
<div className="api-modal-tablist-div">
|
||||
|
|
@ -155,27 +138,58 @@ export default function CodeTabsComponent({
|
|||
) : (
|
||||
<div></div>
|
||||
)}
|
||||
{Number(activeTab) < 4 && (
|
||||
<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}
|
||||
|
||||
<div className="float-right mx-1 mb-1 mt-2 flex gap-2">
|
||||
<div
|
||||
className={
|
||||
Number(activeTab) > 2
|
||||
? "hidden"
|
||||
: "relative top-[2.5px] flex gap-2"
|
||||
}
|
||||
>
|
||||
<Switch
|
||||
style={{
|
||||
transform: `scaleX(${0.7}) scaleY(${0.7})`,
|
||||
}}
|
||||
id="tweaks-switch"
|
||||
onCheckedChange={setActiveTweaks}
|
||||
autoFocus={false}
|
||||
/>
|
||||
<Label
|
||||
className={
|
||||
"relative right-1 top-[4px] text-xs font-medium text-gray-500 dark:text-gray-300 " +
|
||||
(activeTweaks
|
||||
? "font-bold text-black dark:text-white"
|
||||
: "font-medium")
|
||||
}
|
||||
htmlFor="tweaks-switch"
|
||||
>
|
||||
{isCopied ? (
|
||||
<IconComponent name="Check" className="h-4 w-4" />
|
||||
) : (
|
||||
<IconComponent name="Clipboard" className="h-4 w-4" />
|
||||
)}
|
||||
{isCopied ? "Copied!" : "Copy Code"}
|
||||
</button>
|
||||
<button
|
||||
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
||||
onClick={downloadAsFile}
|
||||
>
|
||||
<IconComponent name="Download" className="h-5 w-5" />
|
||||
</button>
|
||||
Tweaks
|
||||
</Label>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{Number(activeTab) < 4 && (
|
||||
<>
|
||||
<button
|
||||
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
||||
onClick={copyToClipboard}
|
||||
>
|
||||
{isCopied ? (
|
||||
<IconComponent name="Check" className="h-4 w-4" />
|
||||
) : (
|
||||
<IconComponent name="Clipboard" className="h-4 w-4" />
|
||||
)}
|
||||
{isCopied ? "Copied!" : "Copy Code"}
|
||||
</button>
|
||||
<button
|
||||
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
||||
onClick={downloadAsFile}
|
||||
>
|
||||
<IconComponent name="Download" className="h-5 w-5" />
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{tabs.map((tab, idx) => (
|
||||
|
|
@ -205,14 +219,12 @@ export default function CodeTabsComponent({
|
|||
<div className="api-modal-according-display">
|
||||
<div
|
||||
className={classNames(
|
||||
"h-[70vh] w-full overflow-y-auto overflow-x-hidden rounded-lg bg-muted custom-scroll"
|
||||
"h-[70vh] w-full overflow-y-auto overflow-x-hidden rounded-lg bg-muted custom-scroll",
|
||||
)}
|
||||
>
|
||||
{data?.map((node: any, i) => (
|
||||
<div className="px-3" key={i}>
|
||||
{tweaks?.tweaksList!.current.includes(
|
||||
node["data"]["id"]
|
||||
) && (
|
||||
{tweaks?.tweaksList!.includes(node["data"]["id"]) && (
|
||||
<AccordionComponent
|
||||
trigger={
|
||||
<ShadTooltip
|
||||
|
|
@ -223,7 +235,6 @@ export default function CodeTabsComponent({
|
|||
<div>{node["data"]["node"]["display_name"]}</div>
|
||||
</ShadTooltip>
|
||||
}
|
||||
open={openAccordion}
|
||||
keyValue={node["data"]["id"]}
|
||||
>
|
||||
<div className="api-modal-table-arrangement">
|
||||
|
|
@ -247,8 +258,8 @@ export default function CodeTabsComponent({
|
|||
.show &&
|
||||
LANGFLOW_SUPPORTED_TYPES.has(
|
||||
node.data.node.template[templateField]
|
||||
.type
|
||||
)
|
||||
.type,
|
||||
),
|
||||
)
|
||||
.map((templateField, indx) => {
|
||||
return (
|
||||
|
|
@ -298,12 +309,12 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -339,13 +350,13 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -383,12 +394,12 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -416,12 +427,12 @@ export default function CodeTabsComponent({
|
|||
].value = e;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
e,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
size="small"
|
||||
|
|
@ -447,7 +458,7 @@ export default function CodeTabsComponent({
|
|||
].fileTypes
|
||||
}
|
||||
onFileChange={(
|
||||
value: any
|
||||
value: any,
|
||||
) => {
|
||||
node.data.node.template[
|
||||
templateField
|
||||
|
|
@ -490,12 +501,12 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -525,12 +536,12 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
value={
|
||||
|
|
@ -582,12 +593,12 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -623,12 +634,12 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -664,12 +675,12 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -693,7 +704,7 @@ export default function CodeTabsComponent({
|
|||
node.data.node!
|
||||
.template[
|
||||
templateField
|
||||
].value
|
||||
].value,
|
||||
)
|
||||
}
|
||||
duplicateKey={
|
||||
|
|
@ -702,15 +713,15 @@ export default function CodeTabsComponent({
|
|||
onChange={(target) => {
|
||||
const valueToNumbers =
|
||||
convertValuesToNumbers(
|
||||
target
|
||||
target,
|
||||
);
|
||||
node.data.node!.template[
|
||||
templateField
|
||||
].value = valueToNumbers;
|
||||
setErrorDuplicateKey(
|
||||
hasDuplicateKeys(
|
||||
valueToNumbers
|
||||
)
|
||||
valueToNumbers,
|
||||
),
|
||||
);
|
||||
setData((old) => {
|
||||
let newInputList =
|
||||
|
|
@ -722,12 +733,12 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
isList={
|
||||
|
|
@ -767,12 +778,12 @@ export default function CodeTabsComponent({
|
|||
].value = target;
|
||||
return newInputList;
|
||||
});
|
||||
tweaks.buildTweakObject!(
|
||||
tweaks?.buildTweakObject!(
|
||||
node["data"]["id"],
|
||||
target,
|
||||
node.data.node.template[
|
||||
templateField
|
||||
]
|
||||
],
|
||||
);
|
||||
}}
|
||||
/>
|
||||
|
|
@ -795,7 +806,7 @@ export default function CodeTabsComponent({
|
|||
</AccordionComponent>
|
||||
)}
|
||||
|
||||
{tweaks?.tweaksList!.current.length === 0 && (
|
||||
{tweaks?.tweaksList!.length === 0 && (
|
||||
<>
|
||||
<div className="pt-3">
|
||||
No tweaks are available for this flow.
|
||||
|
|
|
|||
|
|
@ -1,245 +0,0 @@
|
|||
import "ace-builds/src-noconflict/ext-language_tools";
|
||||
import "ace-builds/src-noconflict/mode-python";
|
||||
import "ace-builds/src-noconflict/theme-github";
|
||||
import "ace-builds/src-noconflict/theme-twilight";
|
||||
import {
|
||||
ReactNode,
|
||||
forwardRef,
|
||||
useContext,
|
||||
useEffect,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
// import "ace-builds/webpack-resolver";
|
||||
import CodeTabsComponent from "../../components/codeTabsComponent";
|
||||
import IconComponent from "../../components/genericIconComponent";
|
||||
import {
|
||||
EXPORT_CODE_DIALOG,
|
||||
LANGFLOW_SUPPORTED_TYPES,
|
||||
} from "../../constants/constants";
|
||||
import { AuthContext } from "../../contexts/authContext";
|
||||
import useFlowStore from "../../stores/flowStore";
|
||||
import { TemplateVariableType } from "../../types/api";
|
||||
import { tweakType, uniqueTweakType } from "../../types/components";
|
||||
import { FlowType, NodeType } from "../../types/flow/index";
|
||||
import { buildTweaks, convertArrayToObj } from "../../utils/reactflowUtils";
|
||||
import {
|
||||
getCurlCode,
|
||||
getPythonApiCode,
|
||||
getPythonCode,
|
||||
getWidgetCode,
|
||||
tabsArray,
|
||||
} from "../../utils/utils";
|
||||
import BaseModal from "../baseModal";
|
||||
|
||||
const ApiModal = forwardRef(
|
||||
(
|
||||
{
|
||||
flow,
|
||||
children,
|
||||
}: {
|
||||
flow: FlowType;
|
||||
children: ReactNode;
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const { autoLogin } = useContext(AuthContext);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState("0");
|
||||
const tweak = useRef<tweakType>([]);
|
||||
const tweaksList = useRef<string[]>([]);
|
||||
const [getTweak, setTweak] = useState<tweakType>([]);
|
||||
const flowState = useFlowStore((state) => state.flowState);
|
||||
const pythonApiCode = getPythonApiCode(flow, autoLogin, tweak.current);
|
||||
const curl_code = getCurlCode(flow, autoLogin, tweak.current);
|
||||
const pythonCode = getPythonCode(flow, tweak.current);
|
||||
const widgetCode = getWidgetCode(flow, autoLogin, flowState);
|
||||
const tweaksCode = buildTweaks(flow);
|
||||
const codesArray = [
|
||||
curl_code,
|
||||
pythonApiCode,
|
||||
pythonCode,
|
||||
widgetCode,
|
||||
pythonCode,
|
||||
];
|
||||
const [tabs, setTabs] = useState(tabsArray(codesArray, 0));
|
||||
|
||||
function startState() {
|
||||
tweak.current = [];
|
||||
setTweak([]);
|
||||
tweaksList.current = [];
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (flow["data"]!["nodes"].length == 0) {
|
||||
startState();
|
||||
} else {
|
||||
tweak.current = [];
|
||||
const t = buildTweaks(flow);
|
||||
tweak.current.push(t);
|
||||
}
|
||||
|
||||
filterNodes();
|
||||
|
||||
if (Object.keys(tweaksCode).length > 0) {
|
||||
setActiveTab("0");
|
||||
setTabs(tabsArray(codesArray, 1));
|
||||
} else {
|
||||
setTabs(tabsArray(codesArray, 1));
|
||||
}
|
||||
}, [flow["data"]!["nodes"], open]);
|
||||
|
||||
function filterNodes() {
|
||||
let arrNodesWithValues: string[] = [];
|
||||
|
||||
flow["data"]!["nodes"].forEach((node) => {
|
||||
if (!node["data"]["node"]["template"]) {
|
||||
return;
|
||||
}
|
||||
Object.keys(node["data"]["node"]["template"])
|
||||
.filter(
|
||||
(templateField) =>
|
||||
templateField.charAt(0) !== "_" &&
|
||||
node.data.node.template[templateField].show &&
|
||||
LANGFLOW_SUPPORTED_TYPES.has(
|
||||
node.data.node.template[templateField].type
|
||||
)
|
||||
)
|
||||
.map((n, i) => {
|
||||
arrNodesWithValues.push(node["id"]);
|
||||
});
|
||||
});
|
||||
|
||||
tweaksList.current = arrNodesWithValues.filter((value, index, self) => {
|
||||
return self.indexOf(value) === index;
|
||||
});
|
||||
}
|
||||
function buildTweakObject(
|
||||
tw: string,
|
||||
changes: string | string[] | boolean | number | Object[] | Object,
|
||||
template: TemplateVariableType
|
||||
) {
|
||||
if (typeof changes === "string" && template.type === "float") {
|
||||
changes = parseFloat(changes);
|
||||
}
|
||||
if (typeof changes === "string" && template.type === "int") {
|
||||
changes = parseInt(changes);
|
||||
}
|
||||
if (template.list === true && Array.isArray(changes)) {
|
||||
changes = changes?.filter((x) => x !== "");
|
||||
}
|
||||
|
||||
if (template.type === "dict" && Array.isArray(changes)) {
|
||||
changes = convertArrayToObj(changes);
|
||||
}
|
||||
|
||||
if (template.type === "NestedDict") {
|
||||
changes = JSON.stringify(changes);
|
||||
}
|
||||
|
||||
const existingTweak = tweak.current.find((element) =>
|
||||
element.hasOwnProperty(tw)
|
||||
);
|
||||
|
||||
if (existingTweak) {
|
||||
existingTweak[tw][template["name"]!] = changes as string;
|
||||
|
||||
if (existingTweak[tw][template["name"]!] == template.value) {
|
||||
tweak.current.forEach((element) => {
|
||||
if (element[tw] && Object.keys(element[tw])?.length === 0) {
|
||||
tweak.current = tweak.current.filter((obj) => {
|
||||
const prop = obj[Object.keys(obj)[0]].prop;
|
||||
return prop !== undefined && prop !== null && prop !== "";
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const newTweak = {
|
||||
[tw]: {
|
||||
[template["name"]!]: changes,
|
||||
},
|
||||
} as uniqueTweakType;
|
||||
tweak.current.push(newTweak);
|
||||
}
|
||||
|
||||
const pythonApiCode = getPythonApiCode(flow, autoLogin, tweak.current);
|
||||
const curl_code = getCurlCode(flow, autoLogin, tweak.current);
|
||||
const pythonCode = getPythonCode(flow, tweak.current);
|
||||
const widgetCode = getWidgetCode(flow, autoLogin, flowState);
|
||||
|
||||
tabs![0].code = curl_code;
|
||||
tabs![1].code = pythonApiCode;
|
||||
tabs![2].code = pythonCode;
|
||||
tabs![3].code = widgetCode;
|
||||
|
||||
setTweak(tweak.current);
|
||||
}
|
||||
|
||||
function buildContent(value: string) {
|
||||
const htmlContent = (
|
||||
<div className="w-[200px]">
|
||||
<span>{value != null && value != "" ? value : "None"}</span>
|
||||
</div>
|
||||
);
|
||||
return htmlContent;
|
||||
}
|
||||
|
||||
function getValue(
|
||||
value: string,
|
||||
node: NodeType,
|
||||
template: TemplateVariableType
|
||||
) {
|
||||
let returnValue = value ?? "";
|
||||
|
||||
if (getTweak.length > 0) {
|
||||
for (const obj of getTweak) {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const value = obj[key];
|
||||
if (key == node["id"]) {
|
||||
Object.keys(value).forEach((key) => {
|
||||
if (key == template["name"]) {
|
||||
returnValue = value[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return value ?? "";
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
return (
|
||||
<BaseModal open={open} setOpen={setOpen}>
|
||||
<BaseModal.Trigger asChild>{children}</BaseModal.Trigger>
|
||||
<BaseModal.Header description={EXPORT_CODE_DIALOG}>
|
||||
<span className="pr-2">API</span>
|
||||
<IconComponent
|
||||
name="Code2"
|
||||
className="h-6 w-6 pl-1 text-gray-800 dark:text-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<CodeTabsComponent
|
||||
flow={flow}
|
||||
tabs={tabs!}
|
||||
activeTab={activeTab}
|
||||
setActiveTab={setActiveTab}
|
||||
tweaks={{
|
||||
tweak,
|
||||
tweaksList,
|
||||
buildContent,
|
||||
buildTweakObject,
|
||||
getValue,
|
||||
}}
|
||||
/>
|
||||
</BaseModal.Content>
|
||||
</BaseModal>
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
export default ApiModal;
|
||||
10
src/frontend/src/modals/apiModal/utils/build-content.tsx
Normal file
10
src/frontend/src/modals/apiModal/utils/build-content.tsx
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
export function buildContent(value: string) {
|
||||
const htmlContent = (
|
||||
<div className="w-[200px]">
|
||||
<span>{value != null && value != "" ? value : "None"}</span>
|
||||
</div>
|
||||
);
|
||||
return htmlContent;
|
||||
}
|
||||
|
||||
export default buildContent;
|
||||
8
src/frontend/src/modals/apiModal/utils/build-tweaks.ts
Normal file
8
src/frontend/src/modals/apiModal/utils/build-tweaks.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { FlowType } from "../../../types/flow";
|
||||
|
||||
export function buildTweaks(flow: FlowType) {
|
||||
return flow.data!.nodes.reduce((acc, node) => {
|
||||
acc[node.data.id] = {};
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
|
||||
|
||||
export const checkCanBuildTweakObject = (element, templateField) => {
|
||||
return (
|
||||
element.data.node.template[templateField] &&
|
||||
templateField.charAt(0) !== "_" &&
|
||||
element.data.node.template[templateField].show &&
|
||||
LANGFLOW_SUPPORTED_TYPES.has(
|
||||
element.data.node.template[templateField].type,
|
||||
) &&
|
||||
templateField !== "code"
|
||||
);
|
||||
};
|
||||
26
src/frontend/src/modals/apiModal/utils/get-changes-types.ts
Normal file
26
src/frontend/src/modals/apiModal/utils/get-changes-types.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
import { TemplateVariableType } from "../../../types/api";
|
||||
import { convertArrayToObj } from "../../../utils/reactflowUtils";
|
||||
|
||||
export const getChangesType = (
|
||||
changes: string | string[] | boolean | number | Object[] | Object,
|
||||
template: TemplateVariableType,
|
||||
) => {
|
||||
if (typeof changes === "string" && template.type === "float") {
|
||||
changes = parseFloat(changes);
|
||||
}
|
||||
if (typeof changes === "string" && template.type === "int") {
|
||||
changes = parseInt(changes);
|
||||
}
|
||||
if (template.list === true && Array.isArray(changes)) {
|
||||
changes = changes?.filter((x) => x !== "");
|
||||
}
|
||||
|
||||
if (template.type === "dict" && Array.isArray(changes)) {
|
||||
changes = convertArrayToObj(changes);
|
||||
}
|
||||
|
||||
if (template.type === "NestedDict") {
|
||||
changes = JSON.stringify(changes);
|
||||
}
|
||||
return changes;
|
||||
};
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
import { LANGFLOW_SUPPORTED_TYPES } from "../../../constants/constants";
|
||||
|
||||
export const getNodesWithDefaultValue = (flow) => {
|
||||
let arrNodesWithValues: string[] = [];
|
||||
|
||||
flow["data"]!["nodes"].forEach((node) => {
|
||||
if (!node["data"]["node"]["template"]) {
|
||||
return;
|
||||
}
|
||||
Object.keys(node["data"]["node"]["template"])
|
||||
.filter(
|
||||
(templateField) =>
|
||||
templateField.charAt(0) !== "_" &&
|
||||
node.data.node.template[templateField].show &&
|
||||
LANGFLOW_SUPPORTED_TYPES.has(
|
||||
node.data.node.template[templateField].type,
|
||||
),
|
||||
)
|
||||
.map((n, i) => {
|
||||
arrNodesWithValues.push(node["id"]);
|
||||
});
|
||||
});
|
||||
|
||||
const tweaksListFiltered = arrNodesWithValues.filter((value, index, self) => {
|
||||
return self.indexOf(value) === index;
|
||||
});
|
||||
return tweaksListFiltered;
|
||||
};
|
||||
29
src/frontend/src/modals/apiModal/utils/get-value.ts
Normal file
29
src/frontend/src/modals/apiModal/utils/get-value.ts
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
import { TemplateVariableType } from "../../../types/api";
|
||||
import { NodeType } from "../../../types/flow";
|
||||
|
||||
export const getValue = (
|
||||
value: string,
|
||||
node: NodeType,
|
||||
template: TemplateVariableType,
|
||||
tweak: Object[],
|
||||
) => {
|
||||
let returnValue = value ?? "";
|
||||
|
||||
if (tweak.length > 0) {
|
||||
for (const obj of tweak) {
|
||||
Object.keys(obj).forEach((key) => {
|
||||
const value = obj[key];
|
||||
if (key == node["id"]) {
|
||||
Object.keys(value).forEach((key) => {
|
||||
if (key == template["name"]) {
|
||||
returnValue = value[key];
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
return value ?? "";
|
||||
}
|
||||
return returnValue;
|
||||
};
|
||||
211
src/frontend/src/modals/apiModal/views/index.tsx
Normal file
211
src/frontend/src/modals/apiModal/views/index.tsx
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
import "ace-builds/src-noconflict/ext-language_tools";
|
||||
import "ace-builds/src-noconflict/mode-python";
|
||||
import "ace-builds/src-noconflict/theme-github";
|
||||
import "ace-builds/src-noconflict/theme-twilight";
|
||||
import { ReactNode, forwardRef, useContext, useEffect, useState } from "react";
|
||||
// import "ace-builds/webpack-resolver";
|
||||
import { cloneDeep } from "lodash";
|
||||
import CodeTabsComponent from "../../../components/codeTabsComponent";
|
||||
import IconComponent from "../../../components/genericIconComponent";
|
||||
import { EXPORT_CODE_DIALOG } from "../../../constants/constants";
|
||||
import { AuthContext } from "../../../contexts/authContext";
|
||||
import { useTweaksStore } from "../../../stores/tweaksStore";
|
||||
import { TemplateVariableType } from "../../../types/api";
|
||||
import { uniqueTweakType } from "../../../types/components";
|
||||
import { FlowType } from "../../../types/flow/index";
|
||||
import {
|
||||
getCurlCode,
|
||||
getPythonApiCode,
|
||||
getPythonCode,
|
||||
getWidgetCode,
|
||||
tabsArray,
|
||||
} from "../../../utils/utils";
|
||||
import BaseModal from "../../baseModal";
|
||||
import { buildContent } from "../utils/build-content";
|
||||
import { buildTweaks } from "../utils/build-tweaks";
|
||||
import { checkCanBuildTweakObject } from "../utils/check-can-build-tweak-object";
|
||||
import { getChangesType } from "../utils/get-changes-types";
|
||||
import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value";
|
||||
import { getValue } from "../utils/get-value";
|
||||
|
||||
const ApiModal = forwardRef(
|
||||
(
|
||||
{
|
||||
flow,
|
||||
children,
|
||||
}: {
|
||||
flow: FlowType;
|
||||
children: ReactNode;
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const tweak = useTweaksStore((state) => state.tweak);
|
||||
const addTweaks = useTweaksStore((state) => state.setTweak);
|
||||
const setTweaksList = useTweaksStore((state) => state.setTweaksList);
|
||||
const tweaksList = useTweaksStore((state) => state.tweaksList);
|
||||
|
||||
const [activeTweaks, setActiveTweaks] = useState(false);
|
||||
const { autoLogin } = useContext(AuthContext);
|
||||
const [open, setOpen] = useState(false);
|
||||
const [activeTab, setActiveTab] = useState("0");
|
||||
const pythonApiCode = getPythonApiCode(flow?.id, autoLogin, tweak);
|
||||
const curl_code = getCurlCode(flow?.id, autoLogin, tweak);
|
||||
const pythonCode = getPythonCode(flow?.name, tweak);
|
||||
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
|
||||
const tweaksCode = buildTweaks(flow);
|
||||
const codesArray = [
|
||||
curl_code,
|
||||
pythonApiCode,
|
||||
pythonCode,
|
||||
widgetCode,
|
||||
pythonCode,
|
||||
];
|
||||
const [tabs, setTabs] = useState(tabsArray(codesArray, 0));
|
||||
|
||||
const canShowTweaks =
|
||||
flow &&
|
||||
flow["data"] &&
|
||||
flow["data"]!["nodes"] &&
|
||||
tweak &&
|
||||
tweak?.length > 0 &&
|
||||
activeTweaks === true;
|
||||
|
||||
const buildTweaksInitialState = () => {
|
||||
const newTweak: any = [];
|
||||
const t = buildTweaks(flow);
|
||||
newTweak.push(t);
|
||||
addTweaks(newTweak);
|
||||
addCodes(newTweak);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (flow["data"]!["nodes"].length == 0) {
|
||||
addTweaks([]);
|
||||
setTweaksList([]);
|
||||
} else {
|
||||
buildTweaksInitialState();
|
||||
}
|
||||
|
||||
filterNodes();
|
||||
|
||||
if (Object.keys(tweaksCode).length > 0) {
|
||||
setActiveTab("0");
|
||||
setTabs(tabsArray(codesArray, 1));
|
||||
} else {
|
||||
setTabs(tabsArray(codesArray, 1));
|
||||
}
|
||||
}, [flow["data"]!["nodes"], open]);
|
||||
|
||||
useEffect(() => {
|
||||
if (canShowTweaks) {
|
||||
const nodes = flow["data"]!["nodes"];
|
||||
nodes.forEach((element) => {
|
||||
const nodeId = element["id"];
|
||||
const template = element["data"]["node"]["template"];
|
||||
|
||||
Object.keys(template).forEach((templateField) => {
|
||||
if (checkCanBuildTweakObject(element, templateField)) {
|
||||
buildTweakObject(
|
||||
nodeId,
|
||||
element.data.node.template[templateField].value,
|
||||
element.data.node.template[templateField],
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
} else {
|
||||
buildTweaksInitialState();
|
||||
}
|
||||
}, [activeTweaks]);
|
||||
|
||||
const filterNodes = () => {
|
||||
setTweaksList(getNodesWithDefaultValue(flow));
|
||||
};
|
||||
|
||||
async function buildTweakObject(
|
||||
tw: string,
|
||||
changes: string | string[] | boolean | number | Object[] | Object,
|
||||
template: TemplateVariableType,
|
||||
) {
|
||||
changes = getChangesType(changes, template);
|
||||
|
||||
const existingTweak = tweak.find((element) => element.hasOwnProperty(tw));
|
||||
|
||||
if (existingTweak) {
|
||||
existingTweak[tw][template["name"]!] = changes as string;
|
||||
|
||||
if (existingTweak[tw][template["name"]!] == template.value) {
|
||||
tweak.forEach((element) => {
|
||||
if (element[tw] && Object.keys(element[tw])?.length === 0) {
|
||||
const filteredTweaks = tweak.filter((obj) => {
|
||||
const prop = obj[Object.keys(obj)[0]].prop;
|
||||
return prop !== undefined && prop !== null && prop !== "";
|
||||
});
|
||||
addTweaks(filteredTweaks);
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
const newTweak = {
|
||||
[tw]: {
|
||||
[template["name"]!]: changes,
|
||||
},
|
||||
} as uniqueTweakType;
|
||||
tweak.push(newTweak);
|
||||
}
|
||||
|
||||
if (tweak && tweak.length > 0) {
|
||||
const cloneTweak = cloneDeep(tweak);
|
||||
addCodes(cloneTweak);
|
||||
addTweaks(cloneTweak);
|
||||
}
|
||||
}
|
||||
|
||||
const addCodes = (cloneTweak) => {
|
||||
const pythonApiCode = getPythonApiCode(flow?.id, autoLogin, cloneTweak);
|
||||
const curl_code = getCurlCode(flow?.id, autoLogin, cloneTweak);
|
||||
const pythonCode = getPythonCode(flow?.name, cloneTweak);
|
||||
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
|
||||
|
||||
if (tabs && tabs?.length > 0) {
|
||||
tabs![0].code = curl_code;
|
||||
tabs![1].code = pythonApiCode;
|
||||
tabs![2].code = pythonCode;
|
||||
tabs![3].code = widgetCode;
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<BaseModal open={open} setOpen={setOpen}>
|
||||
<BaseModal.Trigger asChild>{children}</BaseModal.Trigger>
|
||||
<BaseModal.Header description={EXPORT_CODE_DIALOG}>
|
||||
<span className="pr-2">API</span>
|
||||
<IconComponent
|
||||
name="Code2"
|
||||
className="h-6 w-6 pl-1 text-gray-800 dark:text-white"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</BaseModal.Header>
|
||||
<BaseModal.Content>
|
||||
<CodeTabsComponent
|
||||
flow={flow}
|
||||
tabs={tabs!}
|
||||
activeTab={activeTab}
|
||||
setActiveTab={setActiveTab}
|
||||
tweaks={{
|
||||
tweak,
|
||||
tweaksList,
|
||||
buildContent,
|
||||
buildTweakObject,
|
||||
getValue,
|
||||
}}
|
||||
activeTweaks={activeTweaks}
|
||||
setActiveTweaks={setActiveTweaks}
|
||||
/>
|
||||
</BaseModal.Content>
|
||||
</BaseModal>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export default ApiModal;
|
||||
9
src/frontend/src/stores/tweaksStore.ts
Normal file
9
src/frontend/src/stores/tweaksStore.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { create } from "zustand";
|
||||
import { TweaksStoreType } from "../types/zustand/tweaks";
|
||||
|
||||
export const useTweaksStore = create<TweaksStoreType>((set, get) => ({
|
||||
tweak: [],
|
||||
setTweak: (tweak) => set({ tweak }),
|
||||
tweaksList: [],
|
||||
setTweaksList: (tweaksList) => set({ tweaksList }),
|
||||
}));
|
||||
|
|
@ -511,7 +511,7 @@ export type nodeToolbarPropsType = {
|
|||
updateNodeCode?: (
|
||||
newNodeClass: APIClassType,
|
||||
code: string,
|
||||
name: string
|
||||
name: string,
|
||||
) => void;
|
||||
setShowState: (show: boolean | SetStateAction<boolean>) => void;
|
||||
isOutdated?: boolean;
|
||||
|
|
@ -561,7 +561,7 @@ export type chatMessagePropsType = {
|
|||
updateChat: (
|
||||
chat: ChatMessageType,
|
||||
message: string,
|
||||
stream_url?: string
|
||||
stream_url?: string,
|
||||
) => void;
|
||||
};
|
||||
|
||||
|
|
@ -646,20 +646,23 @@ export type codeTabsPropsType = {
|
|||
setActiveTab: (value: string) => void;
|
||||
isMessage?: boolean;
|
||||
tweaks?: {
|
||||
tweak?: { current: tweakType };
|
||||
tweaksList?: { current: Array<string> };
|
||||
tweak?: tweakType;
|
||||
tweaksList?: Array<string>;
|
||||
buildContent?: (value: string) => ReactNode;
|
||||
getValue?: (
|
||||
value: string,
|
||||
node: NodeType,
|
||||
template: TemplateVariableType
|
||||
template: TemplateVariableType,
|
||||
tweak: tweakType,
|
||||
) => string;
|
||||
buildTweakObject?: (
|
||||
tw: string,
|
||||
changes: string | string[] | boolean | number | Object[] | Object,
|
||||
template: TemplateVariableType
|
||||
) => string | void;
|
||||
template: TemplateVariableType,
|
||||
) => Promise<string | void>;
|
||||
};
|
||||
activeTweaks?: boolean;
|
||||
setActiveTweaks?: (value: boolean) => void;
|
||||
};
|
||||
|
||||
export type crashComponentPropsType = {
|
||||
|
|
|
|||
8
src/frontend/src/types/zustand/tweaks/index.ts
Normal file
8
src/frontend/src/types/zustand/tweaks/index.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import { tweakType } from "../../components";
|
||||
|
||||
export type TweaksStoreType = {
|
||||
tweak: tweakType;
|
||||
setTweak: (tweak: tweakType) => void;
|
||||
tweaksList: string[];
|
||||
setTweaksList: (tweaksList: string[]) => void;
|
||||
};
|
||||
|
|
@ -102,18 +102,18 @@ export function unselectAllNodes({ updateNodes, data }: unselectAllNodesType) {
|
|||
export function isValidConnection(
|
||||
{ source, target, sourceHandle, targetHandle }: Connection,
|
||||
nodes: Node[],
|
||||
edges: Edge[]
|
||||
edges: Edge[],
|
||||
) {
|
||||
const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!);
|
||||
const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!);
|
||||
if (
|
||||
targetHandleObject.inputTypes?.some(
|
||||
(n) => n === sourceHandleObject.dataType
|
||||
(n) => n === sourceHandleObject.dataType,
|
||||
) ||
|
||||
sourceHandleObject.baseClasses.some(
|
||||
(t) =>
|
||||
targetHandleObject.inputTypes?.some((n) => n === t) ||
|
||||
t === targetHandleObject.type
|
||||
t === targetHandleObject.type,
|
||||
)
|
||||
) {
|
||||
let targetNode = nodes.find((node) => node.id === target!)?.data?.node;
|
||||
|
|
@ -146,7 +146,7 @@ export function removeApiKeys(flow: FlowType): FlowType {
|
|||
|
||||
export function updateTemplate(
|
||||
reference: APITemplateType,
|
||||
objectToUpdate: APITemplateType
|
||||
objectToUpdate: APITemplateType,
|
||||
): APITemplateType {
|
||||
let clonedObject: APITemplateType = cloneDeep(reference);
|
||||
|
||||
|
|
@ -206,7 +206,7 @@ export const processDataFromFlow = (flow: FlowType, refreshIds = true) => {
|
|||
|
||||
export function updateIds(
|
||||
{ edges, nodes }: { edges: Edge[]; nodes: Node[] },
|
||||
selection?: { edges: Edge[]; nodes: Node[] }
|
||||
selection?: { edges: Edge[]; nodes: Node[] },
|
||||
) {
|
||||
let idsMap = {};
|
||||
const selectionIds = selection?.nodes.map((n) => n.id);
|
||||
|
|
@ -234,7 +234,7 @@ export function updateIds(
|
|||
edge.source = idsMap[edge.source];
|
||||
edge.target = idsMap[edge.target];
|
||||
const sourceHandleObject: sourceHandleType = scapeJSONParse(
|
||||
edge.sourceHandle!
|
||||
edge.sourceHandle!,
|
||||
);
|
||||
edge.sourceHandle = scapedJSONStringfy({
|
||||
...sourceHandleObject,
|
||||
|
|
@ -244,7 +244,7 @@ export function updateIds(
|
|||
edge.data.sourceHandle.id = edge.source;
|
||||
}
|
||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||
edge.targetHandle!
|
||||
edge.targetHandle!,
|
||||
);
|
||||
edge.targetHandle = scapedJSONStringfy({
|
||||
...targetHandleObject,
|
||||
|
|
@ -264,13 +264,6 @@ export function updateIds(
|
|||
return idsMap;
|
||||
}
|
||||
|
||||
export function buildTweaks(flow: FlowType) {
|
||||
return flow.data!.nodes.reduce((acc, node) => {
|
||||
acc[node.data.id] = {};
|
||||
return acc;
|
||||
}, {});
|
||||
}
|
||||
|
||||
export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
||||
if (!node.data?.node?.template || !Object.keys(node.data.node.template)) {
|
||||
return [
|
||||
|
|
@ -297,11 +290,11 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
|||
(scapeJSONParse(edge.targetHandle!) as targetHandleType).fieldName ===
|
||||
t &&
|
||||
(scapeJSONParse(edge.targetHandle!) as targetHandleType).id ===
|
||||
node.id
|
||||
node.id,
|
||||
)
|
||||
) {
|
||||
errors.push(
|
||||
`${displayName || type} is missing ${getFieldTitle(template, t)}.`
|
||||
`${displayName || type} is missing ${getFieldTitle(template, t)}.`,
|
||||
);
|
||||
} else if (
|
||||
template[t].type === "dict" &&
|
||||
|
|
@ -315,15 +308,15 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
|||
errors.push(
|
||||
`${displayName || type} (${getFieldTitle(
|
||||
template,
|
||||
t
|
||||
)}) contains duplicate keys with the same values.`
|
||||
t,
|
||||
)}) contains duplicate keys with the same values.`,
|
||||
);
|
||||
if (hasEmptyKey(template[t].value))
|
||||
errors.push(
|
||||
`${displayName || type} (${getFieldTitle(
|
||||
template,
|
||||
t
|
||||
)}) field must not be empty.`
|
||||
t,
|
||||
)}) field must not be empty.`,
|
||||
);
|
||||
}
|
||||
return errors;
|
||||
|
|
@ -332,7 +325,7 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
|||
|
||||
export function validateNodes(
|
||||
nodes: Node[],
|
||||
edges: Edge[]
|
||||
edges: Edge[],
|
||||
): // this returns an array of tuples with the node id and the errors
|
||||
Array<{ id: string; errors: Array<string> }> {
|
||||
if (nodes.length === 0) {
|
||||
|
|
@ -353,7 +346,7 @@ export function updateEdges(edges: Edge[]) {
|
|||
if (edges)
|
||||
edges.forEach((edge) => {
|
||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||
edge.targetHandle!
|
||||
edge.targetHandle!,
|
||||
);
|
||||
edge.className = "stroke-gray-900 stroke-connection";
|
||||
});
|
||||
|
|
@ -420,7 +413,7 @@ export function handleKeyDown(
|
|||
| React.KeyboardEvent<HTMLInputElement>
|
||||
| React.KeyboardEvent<HTMLTextAreaElement>,
|
||||
inputValue: string | string[] | null,
|
||||
block: string
|
||||
block: string,
|
||||
) {
|
||||
//condition to fix bug control+backspace on Windows/Linux
|
||||
if (
|
||||
|
|
@ -445,7 +438,7 @@ export function handleKeyDown(
|
|||
}
|
||||
|
||||
export function handleOnlyIntegerInput(
|
||||
event: React.KeyboardEvent<HTMLInputElement>
|
||||
event: React.KeyboardEvent<HTMLInputElement>,
|
||||
) {
|
||||
if (
|
||||
event.key === "." ||
|
||||
|
|
@ -461,7 +454,7 @@ export function handleOnlyIntegerInput(
|
|||
|
||||
export function getConnectedNodes(
|
||||
edge: Edge,
|
||||
nodes: Array<NodeType>
|
||||
nodes: Array<NodeType>,
|
||||
): Array<NodeType> {
|
||||
const sourceId = edge.source;
|
||||
const targetId = edge.target;
|
||||
|
|
@ -561,7 +554,7 @@ export function checkOldEdgesHandles(edges: Edge[]): boolean {
|
|||
!edge.sourceHandle ||
|
||||
!edge.targetHandle ||
|
||||
!edge.sourceHandle.includes("{") ||
|
||||
!edge.targetHandle.includes("{")
|
||||
!edge.targetHandle.includes("{"),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -584,7 +577,7 @@ export function customStringify(obj: any): string {
|
|||
|
||||
const keys = Object.keys(obj).sort();
|
||||
const keyValuePairs = keys.map(
|
||||
(key) => `"${key}":${customStringify(obj[key])}`
|
||||
(key) => `"${key}":${customStringify(obj[key])}`,
|
||||
);
|
||||
return `{${keyValuePairs.join(",")}}`;
|
||||
}
|
||||
|
|
@ -613,7 +606,7 @@ export function getHandleId(
|
|||
source: string,
|
||||
sourceHandle: string,
|
||||
target: string,
|
||||
targetHandle: string
|
||||
targetHandle: string,
|
||||
) {
|
||||
return (
|
||||
"reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle
|
||||
|
|
@ -624,7 +617,7 @@ export function generateFlow(
|
|||
selection: OnSelectionChangeParams,
|
||||
nodes: Node[],
|
||||
edges: Edge[],
|
||||
name: string
|
||||
name: string,
|
||||
): generateFlowType {
|
||||
const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } };
|
||||
const uid = new ShortUniqueId({ length: 5 });
|
||||
|
|
@ -633,7 +626,7 @@ export function generateFlow(
|
|||
newFlowData.edges = selection.edges.filter(
|
||||
(edge) =>
|
||||
selection.nodes.some((node) => node.id === edge.target) &&
|
||||
selection.nodes.some((node) => node.id === edge.source)
|
||||
selection.nodes.some((node) => node.id === edge.source),
|
||||
);
|
||||
newFlowData.nodes = selection.nodes;
|
||||
|
||||
|
|
@ -654,7 +647,7 @@ export function generateFlow(
|
|||
(edge) =>
|
||||
(selection.nodes.some((node) => node.id === edge.target) ||
|
||||
selection.nodes.some((node) => node.id === edge.source)) &&
|
||||
newFlowData.edges.every((e) => e.id !== edge.id)
|
||||
newFlowData.edges.every((e) => e.id !== edge.id),
|
||||
),
|
||||
};
|
||||
}
|
||||
|
|
@ -665,13 +658,13 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) {
|
|||
const { nodes, edges } = groupNode.data.node!.flow!.data!;
|
||||
const lastNode = findLastNode(groupNode.data.node!.flow!.data!);
|
||||
newEdges = newEdges.filter(
|
||||
(e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id)
|
||||
(e) => !(nodes.some((n) => n.id === e.source) && e.source !== lastNode?.id),
|
||||
);
|
||||
newEdges.forEach((edge) => {
|
||||
if (lastNode && edge.source === lastNode.id) {
|
||||
edge.source = groupNode.id;
|
||||
let newSourceHandle: sourceHandleType = scapeJSONParse(
|
||||
edge.sourceHandle!
|
||||
edge.sourceHandle!,
|
||||
);
|
||||
newSourceHandle.id = groupNode.id;
|
||||
edge.sourceHandle = scapedJSONStringfy(newSourceHandle);
|
||||
|
|
@ -698,7 +691,7 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) {
|
|||
export function filterFlow(
|
||||
selection: OnSelectionChangeParams,
|
||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
|
||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void,
|
||||
) {
|
||||
setNodes((nodes) => nodes.filter((node) => !selection.nodes.includes(node)));
|
||||
setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge)));
|
||||
|
|
@ -736,7 +729,7 @@ export function updateFlowPosition(NewPosition: XYPosition, flow: FlowType) {
|
|||
export function concatFlows(
|
||||
flow: FlowType,
|
||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
|
||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void,
|
||||
) {
|
||||
const { nodes, edges } = flow.data!;
|
||||
setNodes((old) => [...old, ...nodes]);
|
||||
|
|
@ -745,7 +738,7 @@ export function concatFlows(
|
|||
|
||||
export function validateSelection(
|
||||
selection: OnSelectionChangeParams,
|
||||
edges: Edge[]
|
||||
edges: Edge[],
|
||||
): Array<string> {
|
||||
//add edges to selection if selection mode selected only nodes
|
||||
if (selection.edges.length === 0) {
|
||||
|
|
@ -757,7 +750,7 @@ export function validateSelection(
|
|||
let nodesSet = new Set(selection.nodes.map((n) => n.id));
|
||||
// then filter the edges that are connected to the nodes in the set
|
||||
let connectedEdges = selection.edges.filter(
|
||||
(e) => nodesSet.has(e.source) && nodesSet.has(e.target)
|
||||
(e) => nodesSet.has(e.source) && nodesSet.has(e.target),
|
||||
);
|
||||
// add the edges to the selection
|
||||
selection.edges = connectedEdges;
|
||||
|
|
@ -771,17 +764,17 @@ export function validateSelection(
|
|||
selection.nodes.some(
|
||||
(node) =>
|
||||
isInputNode(node.data as NodeDataType) ||
|
||||
isOutputNode(node.data as NodeDataType)
|
||||
isOutputNode(node.data as NodeDataType),
|
||||
)
|
||||
) {
|
||||
errorsArray.push(
|
||||
"Please select only nodes that are not input or output nodes"
|
||||
"Please select only nodes that are not input or output nodes",
|
||||
);
|
||||
}
|
||||
//check if there are two or more nodes with free outputs
|
||||
if (
|
||||
selection.nodes.filter(
|
||||
(n) => !selection.edges.some((e) => e.source === n.id)
|
||||
(n) => !selection.edges.some((e) => e.source === n.id),
|
||||
).length > 1
|
||||
) {
|
||||
errorsArray.push("Please select only one node with free outputs");
|
||||
|
|
@ -792,7 +785,7 @@ export function validateSelection(
|
|||
selection.nodes.some(
|
||||
(node) =>
|
||||
!selection.edges.some((edge) => edge.target === node.id) &&
|
||||
!selection.edges.some((edge) => edge.source === node.id)
|
||||
!selection.edges.some((edge) => edge.source === node.id),
|
||||
)
|
||||
) {
|
||||
errorsArray.push("Please select only nodes that are connected");
|
||||
|
|
@ -849,8 +842,8 @@ export function mergeNodeTemplates({
|
|||
nodeTemplate[key].display_name
|
||||
? nodeTemplate[key].display_name
|
||||
: nodeTemplate[key].name
|
||||
? toTitleCase(nodeTemplate[key].name)
|
||||
: toTitleCase(key);
|
||||
? toTitleCase(nodeTemplate[key].name)
|
||||
: toTitleCase(key);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
|
@ -861,7 +854,7 @@ function isHandleConnected(
|
|||
edges: Edge[],
|
||||
key: string,
|
||||
field: TemplateVariableType,
|
||||
nodeId: string
|
||||
nodeId: string,
|
||||
) {
|
||||
/*
|
||||
this function receives a flow and a handleId and check if there is a connection with this handle
|
||||
|
|
@ -877,7 +870,7 @@ function isHandleConnected(
|
|||
id: nodeId,
|
||||
proxy: { id: field.proxy!.id, field: field.proxy!.field },
|
||||
inputTypes: field.input_types,
|
||||
} as targetHandleType)
|
||||
} as targetHandleType),
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
|
|
@ -892,7 +885,7 @@ function isHandleConnected(
|
|||
fieldName: key,
|
||||
id: nodeId,
|
||||
inputTypes: field.input_types,
|
||||
} as targetHandleType)
|
||||
} as targetHandleType),
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
|
|
@ -915,7 +908,7 @@ export function generateNodeTemplate(Flow: FlowType) {
|
|||
|
||||
export function generateNodeFromFlow(
|
||||
flow: FlowType,
|
||||
getNodeId: (type: string) => string
|
||||
getNodeId: (type: string) => string,
|
||||
): NodeType {
|
||||
const { nodes } = flow.data!;
|
||||
const outputNode = cloneDeep(findLastNode(flow.data!));
|
||||
|
|
@ -946,7 +939,7 @@ export function generateNodeFromFlow(
|
|||
export function connectedInputNodesOnHandle(
|
||||
nodeId: string,
|
||||
handleId: string,
|
||||
{ nodes, edges }: { nodes: NodeType[]; edges: Edge[] }
|
||||
{ nodes, edges }: { nodes: NodeType[]; edges: Edge[] },
|
||||
) {
|
||||
const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> =
|
||||
[];
|
||||
|
|
@ -983,7 +976,7 @@ export function connectedInputNodesOnHandle(
|
|||
|
||||
export function updateProxyIdsOnTemplate(
|
||||
template: APITemplateType,
|
||||
idsMap: { [key: string]: string }
|
||||
idsMap: { [key: string]: string },
|
||||
) {
|
||||
Object.keys(template).forEach((key) => {
|
||||
if (template[key].proxy && idsMap[template[key].proxy!.id]) {
|
||||
|
|
@ -994,7 +987,7 @@ export function updateProxyIdsOnTemplate(
|
|||
|
||||
export function updateEdgesIds(
|
||||
edges: Edge[],
|
||||
idsMap: { [key: string]: string }
|
||||
idsMap: { [key: string]: string },
|
||||
) {
|
||||
edges.forEach((edge) => {
|
||||
let targetHandle: targetHandleType = edge.data.targetHandle;
|
||||
|
|
@ -1027,7 +1020,7 @@ export function expandGroupNode(
|
|||
nodes: Node[],
|
||||
edges: Edge[],
|
||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void
|
||||
setEdges: (update: Edge[] | ((oldState: Edge[]) => Edge[])) => void,
|
||||
) {
|
||||
const idsMap = updateIds(flow!.data!);
|
||||
updateProxyIdsOnTemplate(template, idsMap);
|
||||
|
|
@ -1070,7 +1063,7 @@ export function expandGroupNode(
|
|||
const lastNode = cloneDeep(findLastNode(flow!.data!));
|
||||
newEdge.source = lastNode!.id;
|
||||
let newSourceHandle: sourceHandleType = scapeJSONParse(
|
||||
newEdge.sourceHandle!
|
||||
newEdge.sourceHandle!,
|
||||
);
|
||||
newSourceHandle.id = lastNode!.id;
|
||||
newEdge.data.sourceHandle = newSourceHandle;
|
||||
|
|
@ -1124,7 +1117,7 @@ export function expandGroupNode(
|
|||
|
||||
export function getGroupStatus(
|
||||
flow: FlowType,
|
||||
ssData: { [key: string]: { valid: boolean; params: string } }
|
||||
ssData: { [key: string]: { valid: boolean; params: string } },
|
||||
) {
|
||||
let status = { valid: true, params: SUCCESS_BUILD };
|
||||
const { nodes } = flow.data!;
|
||||
|
|
@ -1143,7 +1136,7 @@ export function getGroupStatus(
|
|||
|
||||
export function createFlowComponent(
|
||||
nodeData: NodeDataType,
|
||||
version: string
|
||||
version: string,
|
||||
): FlowType {
|
||||
const flowNode: FlowType = {
|
||||
data: {
|
||||
|
|
@ -1179,7 +1172,7 @@ export function downloadNode(NodeFLow: FlowType) {
|
|||
|
||||
export function updateComponentNameAndType(
|
||||
data: any,
|
||||
component: NodeDataType
|
||||
component: NodeDataType,
|
||||
) {}
|
||||
|
||||
export function removeFileNameFromComponents(flow: FlowType) {
|
||||
|
|
@ -1253,7 +1246,7 @@ export function extractFieldsFromComponenents(data: APIObjectType) {
|
|||
export function downloadFlow(
|
||||
flow: FlowType,
|
||||
flowName: string,
|
||||
flowDescription?: string
|
||||
flowDescription?: string,
|
||||
) {
|
||||
let clonedFlow = cloneDeep(flow);
|
||||
removeFileNameFromComponents(clonedFlow);
|
||||
|
|
@ -1263,7 +1256,7 @@ export function downloadFlow(
|
|||
...clonedFlow,
|
||||
name: flowName,
|
||||
description: flowDescription,
|
||||
})
|
||||
}),
|
||||
)}`;
|
||||
|
||||
// create a link element and set its properties
|
||||
|
|
@ -1278,7 +1271,7 @@ export function downloadFlow(
|
|||
export function downloadFlows() {
|
||||
downloadFlowsFromDatabase().then((flows) => {
|
||||
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
|
||||
JSON.stringify(flows)
|
||||
JSON.stringify(flows),
|
||||
)}`;
|
||||
|
||||
// create a link element and set its properties
|
||||
|
|
@ -1293,7 +1286,7 @@ export function downloadFlows() {
|
|||
|
||||
export const createNewFlow = (
|
||||
flowData: ReactFlowJsonObject,
|
||||
flow: FlowType
|
||||
flow: FlowType,
|
||||
) => {
|
||||
return {
|
||||
description: flow?.description ?? getRandomDescription(),
|
||||
|
|
|
|||
|
|
@ -13,9 +13,8 @@ import {
|
|||
nodeGroupedObjType,
|
||||
tweakType,
|
||||
} from "../types/components";
|
||||
import { FlowType, NodeType } from "../types/flow";
|
||||
import { NodeType } from "../types/flow";
|
||||
import { FlowState } from "../types/tabs";
|
||||
import { buildTweaks } from "./reactflowUtils";
|
||||
|
||||
export function classNames(...classes: Array<string>): string {
|
||||
return classes.filter(Boolean).join(" ");
|
||||
|
|
@ -323,17 +322,10 @@ export function getChatInputField(flowState?: FlowState) {
|
|||
* @returns {string} - The python code
|
||||
*/
|
||||
export function getPythonApiCode(
|
||||
flow: FlowType,
|
||||
flowId: string,
|
||||
isAuth: boolean,
|
||||
tweak?: any[],
|
||||
tweaksBuildedObject,
|
||||
): string {
|
||||
const flowId = flow.id;
|
||||
|
||||
// create a dictionary of node ids and the values is an empty dictionary
|
||||
// flow.data.nodes.forEach((node) => {
|
||||
// node.data.id
|
||||
// }
|
||||
const tweaks = buildTweaks(flow);
|
||||
return `import requests
|
||||
from typing import Optional
|
||||
|
||||
|
|
@ -341,11 +333,7 @@ BASE_API_URL = "${window.location.protocol}//${window.location.host}/api/v1/run"
|
|||
FLOW_ID = "${flowId}"
|
||||
# You can tweak the flow by adding a tweaks dictionary
|
||||
# e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}}
|
||||
TWEAKS = ${
|
||||
tweak && tweak.length > 0
|
||||
? buildTweakObject(tweak)
|
||||
: JSON.stringify(tweaks, null, 2)
|
||||
}
|
||||
TWEAKS = ${JSON.stringify(tweaksBuildedObject, null, 2)}
|
||||
|
||||
def run_flow(message: str,
|
||||
flow_id: str,
|
||||
|
|
@ -391,13 +379,10 @@ print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${
|
|||
* @returns {string} - The curl code
|
||||
*/
|
||||
export function getCurlCode(
|
||||
flow: FlowType,
|
||||
flowId: string,
|
||||
isAuth: boolean,
|
||||
tweak?: any[],
|
||||
tweaksBuildedObject,
|
||||
): string {
|
||||
const flowId = flow.id;
|
||||
const tweaks = buildTweaks(flow);
|
||||
|
||||
return `curl -X POST \\
|
||||
${window.location.protocol}//${
|
||||
window.location.host
|
||||
|
|
@ -408,11 +393,7 @@ export function getCurlCode(
|
|||
-d '{"input_value": "message",
|
||||
"output_type": "chat",
|
||||
"input_type": "chat",
|
||||
"tweaks": ${
|
||||
tweak && tweak.length > 0
|
||||
? buildTweakObject(tweak)
|
||||
: JSON.stringify(tweaks, null, 2)
|
||||
}}'
|
||||
"tweaks": ${JSON.stringify(tweaksBuildedObject, null, 2)}'
|
||||
`;
|
||||
}
|
||||
|
||||
|
|
@ -439,16 +420,9 @@ export function getOutputIds(flow) {
|
|||
* @param {any[]} tweak - The tweaks
|
||||
* @returns {string} - The python code
|
||||
*/
|
||||
export function getPythonCode(flow: FlowType, tweak?: any[]): string {
|
||||
const flowName = flow.name;
|
||||
const tweaks = buildTweaks(flow);
|
||||
|
||||
export function getPythonCode(flowName: string, tweaksBuildedObject): string {
|
||||
return `from langflow.load import run_flow_from_json
|
||||
TWEAKS = ${
|
||||
tweak && tweak.length > 0
|
||||
? buildTweakObject(tweak)
|
||||
: JSON.stringify(tweaks, null, 2)
|
||||
}
|
||||
TWEAKS = ${JSON.stringify(tweaksBuildedObject, null, 2)}
|
||||
|
||||
result = run_flow_from_json(flow="${flowName}.json",
|
||||
input_value="message",
|
||||
|
|
@ -461,15 +435,10 @@ result = run_flow_from_json(flow="${flowName}.json",
|
|||
* @returns {string} - The widget code
|
||||
*/
|
||||
export function getWidgetCode(
|
||||
flow: FlowType,
|
||||
flowId: string,
|
||||
flowName: string,
|
||||
isAuth: boolean,
|
||||
flowState?: FlowState,
|
||||
): string {
|
||||
const flowId = flow.id;
|
||||
const flowName = flow.name;
|
||||
const inputs = buildInputs();
|
||||
let chat_input_field = getChatInputField(flowState);
|
||||
|
||||
return `<script src="https://cdn.jsdelivr.net/gh/langflow-ai/langflow-embedded-chat@1.0_alpha/dist/build/static/js/bundle.min.js"></script>
|
||||
|
||||
<langflow-chat
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ test("curl_api_generation", async ({ page, context }) => {
|
|||
await page.getByRole("tab", { name: "cURL" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
navigator.clipboard.readText(),
|
||||
);
|
||||
const clipboardContent = await handle.jsonValue();
|
||||
const oldValue = clipboardContent;
|
||||
|
|
@ -50,10 +50,78 @@ test("curl_api_generation", async ({ page, context }) => {
|
|||
await page.getByRole("tab", { name: "cURL" }).click();
|
||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||
const handle2 = await page.evaluateHandle(() =>
|
||||
navigator.clipboard.readText()
|
||||
navigator.clipboard.readText(),
|
||||
);
|
||||
const clipboardContent2 = await handle2.jsonValue();
|
||||
const newValue = clipboardContent2;
|
||||
expect(oldValue).not.toBe(newValue);
|
||||
expect(clipboardContent2.length).toBeGreaterThan(clipboardContent.length);
|
||||
});
|
||||
|
||||
test("check if tweaks are updating when someothing on the flow changes", async ({
|
||||
page,
|
||||
}) => {
|
||||
await page.goto("/");
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
let modalCount = 0;
|
||||
try {
|
||||
const modalTitleElement = await page?.getByTestId("modal-title");
|
||||
if (modalTitleElement) {
|
||||
modalCount = await modalTitleElement.count();
|
||||
}
|
||||
} catch (error) {
|
||||
modalCount = 0;
|
||||
}
|
||||
|
||||
while (modalCount === 0) {
|
||||
await page.locator('//*[@id="new-project-btn"]').click();
|
||||
await page.waitForTimeout(5000);
|
||||
modalCount = await page.getByTestId("modal-title")?.count();
|
||||
}
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await page.getByTestId("blank-flow").click();
|
||||
await page.waitForTimeout(1000);
|
||||
await page.getByTestId("extended-disclosure").click();
|
||||
await page.getByPlaceholder("Search").click();
|
||||
await page.getByPlaceholder("Search").fill("Chroma");
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
await page
|
||||
.getByTestId("vectorstoresChroma")
|
||||
.dragTo(page.locator('//*[@id="react-flow-id"]'));
|
||||
await page.mouse.up();
|
||||
await page.mouse.down();
|
||||
await page.getByTitle("fit view").click();
|
||||
await page.getByTitle("zoom out").click();
|
||||
await page.getByTitle("zoom out").click();
|
||||
await page.getByTitle("zoom out").click();
|
||||
await page.getByTestId("input-collection_name").click();
|
||||
await page
|
||||
.getByTestId("input-collection_name")
|
||||
.fill("collection_name_test_123123123!@#$&*(&%$@");
|
||||
|
||||
await page.getByTestId("input-index_directory").click();
|
||||
await page
|
||||
.getByTestId("input-index_directory")
|
||||
.fill("index_directory_123123123!@#$&*(&%$@");
|
||||
|
||||
await page.getByText("API", { exact: true }).first().click();
|
||||
|
||||
await page.getByText("Tweaks").nth(1).click();
|
||||
|
||||
await page.getByText("collection_name_test_123123123!@#$&*(&%$@").isVisible();
|
||||
await page.getByText("index_directory_123123123!@#$&*(&%$@").isVisible();
|
||||
|
||||
await page.getByText("Python API", { exact: true }).click();
|
||||
|
||||
await page.getByText("collection_name_test_123123123!@#$&*(&%$@").isVisible();
|
||||
await page.getByText("index_directory_123123123!@#$&*(&%$@").isVisible();
|
||||
|
||||
await page.getByText("Python Code", { exact: true }).click();
|
||||
|
||||
await page.getByText("collection_name_test_123123123!@#$&*(&%$@").isVisible();
|
||||
await page.getByText("index_directory_123123123!@#$&*(&%$@").isVisible();
|
||||
});
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue