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,
|
sideBar,
|
||||||
}: AccordionComponentType): JSX.Element {
|
}: AccordionComponentType): JSX.Element {
|
||||||
const [value, setValue] = useState(
|
const [value, setValue] = useState(
|
||||||
open.length === 0 ? "" : getOpenAccordion()
|
open.length === 0 ? "" : getOpenAccordion(),
|
||||||
);
|
);
|
||||||
|
|
||||||
function getOpenAccordion(): string {
|
function getOpenAccordion(): string {
|
||||||
let value = "";
|
let value = "";
|
||||||
open.forEach((el) => {
|
open.forEach((el) => {
|
||||||
if (el == trigger) {
|
if (el == keyValue) {
|
||||||
value = trigger;
|
value = keyValue;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Transition } from "@headlessui/react";
|
import { Transition } from "@headlessui/react";
|
||||||
import { useEffect, useMemo, useRef, useState } from "react";
|
import { useEffect, useMemo, useRef, useState } from "react";
|
||||||
import IOModal from "../../modals/IOModal";
|
import IOModal from "../../modals/IOModal";
|
||||||
import ApiModal from "../../modals/apiModal";
|
import ApiModal from "../../modals/apiModal/views";
|
||||||
import ShareModal from "../../modals/shareModal";
|
import ShareModal from "../../modals/shareModal";
|
||||||
import useFlowStore from "../../stores/flowStore";
|
import useFlowStore from "../../stores/flowStore";
|
||||||
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
import useFlowsManagerStore from "../../stores/flowsManagerStore";
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,8 @@ import IconComponent from "../genericIconComponent";
|
||||||
import InputComponent from "../inputComponent";
|
import InputComponent from "../inputComponent";
|
||||||
import KeypairListComponent from "../keypairListComponent";
|
import KeypairListComponent from "../keypairListComponent";
|
||||||
import ShadTooltip from "../shadTooltipComponent";
|
import ShadTooltip from "../shadTooltipComponent";
|
||||||
|
import { Label } from "../ui/label";
|
||||||
|
import { Switch } from "../ui/switch";
|
||||||
|
|
||||||
export default function CodeTabsComponent({
|
export default function CodeTabsComponent({
|
||||||
flow,
|
flow,
|
||||||
|
|
@ -49,14 +51,13 @@ export default function CodeTabsComponent({
|
||||||
setActiveTab,
|
setActiveTab,
|
||||||
isMessage,
|
isMessage,
|
||||||
tweaks,
|
tweaks,
|
||||||
|
setActiveTweaks,
|
||||||
|
activeTweaks,
|
||||||
}: codeTabsPropsType) {
|
}: codeTabsPropsType) {
|
||||||
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
const [isCopied, setIsCopied] = useState<Boolean>(false);
|
||||||
const [data, setData] = useState(flow ? flow["data"]!["nodes"] : null);
|
const [data, setData] = useState(flow ? flow["data"]!["nodes"] : null);
|
||||||
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
|
|
||||||
const dark = useDarkStore((state) => state.dark);
|
const dark = useDarkStore((state) => state.dark);
|
||||||
const unselectAll = useFlowStore((state) => state.unselectAll);
|
const unselectAll = useFlowStore((state) => state.unselectAll);
|
||||||
const setNode = useFlowStore((state) => state.setNode);
|
|
||||||
|
|
||||||
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
|
@ -107,21 +108,6 @@ export default function CodeTabsComponent({
|
||||||
URL.revokeObjectURL(url);
|
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 (
|
return (
|
||||||
<Tabs
|
<Tabs
|
||||||
value={activeTab}
|
value={activeTab}
|
||||||
|
|
@ -132,9 +118,6 @@ export default function CodeTabsComponent({
|
||||||
}
|
}
|
||||||
onValueChange={(value) => {
|
onValueChange={(value) => {
|
||||||
setActiveTab(value);
|
setActiveTab(value);
|
||||||
if (value === "3") {
|
|
||||||
openAccordions();
|
|
||||||
}
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="api-modal-tablist-div">
|
<div className="api-modal-tablist-div">
|
||||||
|
|
@ -155,27 +138,58 @@ export default function CodeTabsComponent({
|
||||||
) : (
|
) : (
|
||||||
<div></div>
|
<div></div>
|
||||||
)}
|
)}
|
||||||
{Number(activeTab) < 4 && (
|
|
||||||
<div className="float-right mx-1 mb-1 mt-2 flex gap-2">
|
<div className="float-right mx-1 mb-1 mt-2 flex gap-2">
|
||||||
<button
|
<div
|
||||||
className="flex items-center gap-1.5 rounded bg-none p-1 text-xs text-gray-500 dark:text-gray-300"
|
className={
|
||||||
onClick={copyToClipboard}
|
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 ? (
|
Tweaks
|
||||||
<IconComponent name="Check" className="h-4 w-4" />
|
</Label>
|
||||||
) : (
|
|
||||||
<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>
|
||||||
)}
|
|
||||||
|
{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>
|
</div>
|
||||||
|
|
||||||
{tabs.map((tab, idx) => (
|
{tabs.map((tab, idx) => (
|
||||||
|
|
@ -205,14 +219,12 @@ export default function CodeTabsComponent({
|
||||||
<div className="api-modal-according-display">
|
<div className="api-modal-according-display">
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
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) => (
|
{data?.map((node: any, i) => (
|
||||||
<div className="px-3" key={i}>
|
<div className="px-3" key={i}>
|
||||||
{tweaks?.tweaksList!.current.includes(
|
{tweaks?.tweaksList!.includes(node["data"]["id"]) && (
|
||||||
node["data"]["id"]
|
|
||||||
) && (
|
|
||||||
<AccordionComponent
|
<AccordionComponent
|
||||||
trigger={
|
trigger={
|
||||||
<ShadTooltip
|
<ShadTooltip
|
||||||
|
|
@ -223,7 +235,6 @@ export default function CodeTabsComponent({
|
||||||
<div>{node["data"]["node"]["display_name"]}</div>
|
<div>{node["data"]["node"]["display_name"]}</div>
|
||||||
</ShadTooltip>
|
</ShadTooltip>
|
||||||
}
|
}
|
||||||
open={openAccordion}
|
|
||||||
keyValue={node["data"]["id"]}
|
keyValue={node["data"]["id"]}
|
||||||
>
|
>
|
||||||
<div className="api-modal-table-arrangement">
|
<div className="api-modal-table-arrangement">
|
||||||
|
|
@ -247,8 +258,8 @@ export default function CodeTabsComponent({
|
||||||
.show &&
|
.show &&
|
||||||
LANGFLOW_SUPPORTED_TYPES.has(
|
LANGFLOW_SUPPORTED_TYPES.has(
|
||||||
node.data.node.template[templateField]
|
node.data.node.template[templateField]
|
||||||
.type
|
.type,
|
||||||
)
|
),
|
||||||
)
|
)
|
||||||
.map((templateField, indx) => {
|
.map((templateField, indx) => {
|
||||||
return (
|
return (
|
||||||
|
|
@ -298,12 +309,12 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -339,13 +350,13 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node
|
node.data.node
|
||||||
.template[
|
.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -383,12 +394,12 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -416,12 +427,12 @@ export default function CodeTabsComponent({
|
||||||
].value = e;
|
].value = e;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
e,
|
e,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
size="small"
|
size="small"
|
||||||
|
|
@ -447,7 +458,7 @@ export default function CodeTabsComponent({
|
||||||
].fileTypes
|
].fileTypes
|
||||||
}
|
}
|
||||||
onFileChange={(
|
onFileChange={(
|
||||||
value: any
|
value: any,
|
||||||
) => {
|
) => {
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
|
|
@ -490,12 +501,12 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -525,12 +536,12 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
value={
|
value={
|
||||||
|
|
@ -582,12 +593,12 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -623,12 +634,12 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -664,12 +675,12 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -693,7 +704,7 @@ export default function CodeTabsComponent({
|
||||||
node.data.node!
|
node.data.node!
|
||||||
.template[
|
.template[
|
||||||
templateField
|
templateField
|
||||||
].value
|
].value,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
duplicateKey={
|
duplicateKey={
|
||||||
|
|
@ -702,15 +713,15 @@ export default function CodeTabsComponent({
|
||||||
onChange={(target) => {
|
onChange={(target) => {
|
||||||
const valueToNumbers =
|
const valueToNumbers =
|
||||||
convertValuesToNumbers(
|
convertValuesToNumbers(
|
||||||
target
|
target,
|
||||||
);
|
);
|
||||||
node.data.node!.template[
|
node.data.node!.template[
|
||||||
templateField
|
templateField
|
||||||
].value = valueToNumbers;
|
].value = valueToNumbers;
|
||||||
setErrorDuplicateKey(
|
setErrorDuplicateKey(
|
||||||
hasDuplicateKeys(
|
hasDuplicateKeys(
|
||||||
valueToNumbers
|
valueToNumbers,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
setData((old) => {
|
setData((old) => {
|
||||||
let newInputList =
|
let newInputList =
|
||||||
|
|
@ -722,12 +733,12 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
isList={
|
isList={
|
||||||
|
|
@ -767,12 +778,12 @@ export default function CodeTabsComponent({
|
||||||
].value = target;
|
].value = target;
|
||||||
return newInputList;
|
return newInputList;
|
||||||
});
|
});
|
||||||
tweaks.buildTweakObject!(
|
tweaks?.buildTweakObject!(
|
||||||
node["data"]["id"],
|
node["data"]["id"],
|
||||||
target,
|
target,
|
||||||
node.data.node.template[
|
node.data.node.template[
|
||||||
templateField
|
templateField
|
||||||
]
|
],
|
||||||
);
|
);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
@ -795,7 +806,7 @@ export default function CodeTabsComponent({
|
||||||
</AccordionComponent>
|
</AccordionComponent>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{tweaks?.tweaksList!.current.length === 0 && (
|
{tweaks?.tweaksList!.length === 0 && (
|
||||||
<>
|
<>
|
||||||
<div className="pt-3">
|
<div className="pt-3">
|
||||||
No tweaks are available for this flow.
|
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?: (
|
updateNodeCode?: (
|
||||||
newNodeClass: APIClassType,
|
newNodeClass: APIClassType,
|
||||||
code: string,
|
code: string,
|
||||||
name: string
|
name: string,
|
||||||
) => void;
|
) => void;
|
||||||
setShowState: (show: boolean | SetStateAction<boolean>) => void;
|
setShowState: (show: boolean | SetStateAction<boolean>) => void;
|
||||||
isOutdated?: boolean;
|
isOutdated?: boolean;
|
||||||
|
|
@ -561,7 +561,7 @@ export type chatMessagePropsType = {
|
||||||
updateChat: (
|
updateChat: (
|
||||||
chat: ChatMessageType,
|
chat: ChatMessageType,
|
||||||
message: string,
|
message: string,
|
||||||
stream_url?: string
|
stream_url?: string,
|
||||||
) => void;
|
) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -646,20 +646,23 @@ export type codeTabsPropsType = {
|
||||||
setActiveTab: (value: string) => void;
|
setActiveTab: (value: string) => void;
|
||||||
isMessage?: boolean;
|
isMessage?: boolean;
|
||||||
tweaks?: {
|
tweaks?: {
|
||||||
tweak?: { current: tweakType };
|
tweak?: tweakType;
|
||||||
tweaksList?: { current: Array<string> };
|
tweaksList?: Array<string>;
|
||||||
buildContent?: (value: string) => ReactNode;
|
buildContent?: (value: string) => ReactNode;
|
||||||
getValue?: (
|
getValue?: (
|
||||||
value: string,
|
value: string,
|
||||||
node: NodeType,
|
node: NodeType,
|
||||||
template: TemplateVariableType
|
template: TemplateVariableType,
|
||||||
|
tweak: tweakType,
|
||||||
) => string;
|
) => string;
|
||||||
buildTweakObject?: (
|
buildTweakObject?: (
|
||||||
tw: string,
|
tw: string,
|
||||||
changes: string | string[] | boolean | number | Object[] | Object,
|
changes: string | string[] | boolean | number | Object[] | Object,
|
||||||
template: TemplateVariableType
|
template: TemplateVariableType,
|
||||||
) => string | void;
|
) => Promise<string | void>;
|
||||||
};
|
};
|
||||||
|
activeTweaks?: boolean;
|
||||||
|
setActiveTweaks?: (value: boolean) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type crashComponentPropsType = {
|
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(
|
export function isValidConnection(
|
||||||
{ source, target, sourceHandle, targetHandle }: Connection,
|
{ source, target, sourceHandle, targetHandle }: Connection,
|
||||||
nodes: Node[],
|
nodes: Node[],
|
||||||
edges: Edge[]
|
edges: Edge[],
|
||||||
) {
|
) {
|
||||||
const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!);
|
const targetHandleObject: targetHandleType = scapeJSONParse(targetHandle!);
|
||||||
const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!);
|
const sourceHandleObject: sourceHandleType = scapeJSONParse(sourceHandle!);
|
||||||
if (
|
if (
|
||||||
targetHandleObject.inputTypes?.some(
|
targetHandleObject.inputTypes?.some(
|
||||||
(n) => n === sourceHandleObject.dataType
|
(n) => n === sourceHandleObject.dataType,
|
||||||
) ||
|
) ||
|
||||||
sourceHandleObject.baseClasses.some(
|
sourceHandleObject.baseClasses.some(
|
||||||
(t) =>
|
(t) =>
|
||||||
targetHandleObject.inputTypes?.some((n) => n === t) ||
|
targetHandleObject.inputTypes?.some((n) => n === t) ||
|
||||||
t === targetHandleObject.type
|
t === targetHandleObject.type,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
let targetNode = nodes.find((node) => node.id === target!)?.data?.node;
|
let targetNode = nodes.find((node) => node.id === target!)?.data?.node;
|
||||||
|
|
@ -146,7 +146,7 @@ export function removeApiKeys(flow: FlowType): FlowType {
|
||||||
|
|
||||||
export function updateTemplate(
|
export function updateTemplate(
|
||||||
reference: APITemplateType,
|
reference: APITemplateType,
|
||||||
objectToUpdate: APITemplateType
|
objectToUpdate: APITemplateType,
|
||||||
): APITemplateType {
|
): APITemplateType {
|
||||||
let clonedObject: APITemplateType = cloneDeep(reference);
|
let clonedObject: APITemplateType = cloneDeep(reference);
|
||||||
|
|
||||||
|
|
@ -206,7 +206,7 @@ export const processDataFromFlow = (flow: FlowType, refreshIds = true) => {
|
||||||
|
|
||||||
export function updateIds(
|
export function updateIds(
|
||||||
{ edges, nodes }: { edges: Edge[]; nodes: Node[] },
|
{ edges, nodes }: { edges: Edge[]; nodes: Node[] },
|
||||||
selection?: { edges: Edge[]; nodes: Node[] }
|
selection?: { edges: Edge[]; nodes: Node[] },
|
||||||
) {
|
) {
|
||||||
let idsMap = {};
|
let idsMap = {};
|
||||||
const selectionIds = selection?.nodes.map((n) => n.id);
|
const selectionIds = selection?.nodes.map((n) => n.id);
|
||||||
|
|
@ -234,7 +234,7 @@ export function updateIds(
|
||||||
edge.source = idsMap[edge.source];
|
edge.source = idsMap[edge.source];
|
||||||
edge.target = idsMap[edge.target];
|
edge.target = idsMap[edge.target];
|
||||||
const sourceHandleObject: sourceHandleType = scapeJSONParse(
|
const sourceHandleObject: sourceHandleType = scapeJSONParse(
|
||||||
edge.sourceHandle!
|
edge.sourceHandle!,
|
||||||
);
|
);
|
||||||
edge.sourceHandle = scapedJSONStringfy({
|
edge.sourceHandle = scapedJSONStringfy({
|
||||||
...sourceHandleObject,
|
...sourceHandleObject,
|
||||||
|
|
@ -244,7 +244,7 @@ export function updateIds(
|
||||||
edge.data.sourceHandle.id = edge.source;
|
edge.data.sourceHandle.id = edge.source;
|
||||||
}
|
}
|
||||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||||
edge.targetHandle!
|
edge.targetHandle!,
|
||||||
);
|
);
|
||||||
edge.targetHandle = scapedJSONStringfy({
|
edge.targetHandle = scapedJSONStringfy({
|
||||||
...targetHandleObject,
|
...targetHandleObject,
|
||||||
|
|
@ -264,13 +264,6 @@ export function updateIds(
|
||||||
return idsMap;
|
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> {
|
export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
||||||
if (!node.data?.node?.template || !Object.keys(node.data.node.template)) {
|
if (!node.data?.node?.template || !Object.keys(node.data.node.template)) {
|
||||||
return [
|
return [
|
||||||
|
|
@ -297,11 +290,11 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
||||||
(scapeJSONParse(edge.targetHandle!) as targetHandleType).fieldName ===
|
(scapeJSONParse(edge.targetHandle!) as targetHandleType).fieldName ===
|
||||||
t &&
|
t &&
|
||||||
(scapeJSONParse(edge.targetHandle!) as targetHandleType).id ===
|
(scapeJSONParse(edge.targetHandle!) as targetHandleType).id ===
|
||||||
node.id
|
node.id,
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
errors.push(
|
errors.push(
|
||||||
`${displayName || type} is missing ${getFieldTitle(template, t)}.`
|
`${displayName || type} is missing ${getFieldTitle(template, t)}.`,
|
||||||
);
|
);
|
||||||
} else if (
|
} else if (
|
||||||
template[t].type === "dict" &&
|
template[t].type === "dict" &&
|
||||||
|
|
@ -315,15 +308,15 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
||||||
errors.push(
|
errors.push(
|
||||||
`${displayName || type} (${getFieldTitle(
|
`${displayName || type} (${getFieldTitle(
|
||||||
template,
|
template,
|
||||||
t
|
t,
|
||||||
)}) contains duplicate keys with the same values.`
|
)}) contains duplicate keys with the same values.`,
|
||||||
);
|
);
|
||||||
if (hasEmptyKey(template[t].value))
|
if (hasEmptyKey(template[t].value))
|
||||||
errors.push(
|
errors.push(
|
||||||
`${displayName || type} (${getFieldTitle(
|
`${displayName || type} (${getFieldTitle(
|
||||||
template,
|
template,
|
||||||
t
|
t,
|
||||||
)}) field must not be empty.`
|
)}) field must not be empty.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return errors;
|
return errors;
|
||||||
|
|
@ -332,7 +325,7 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
|
||||||
|
|
||||||
export function validateNodes(
|
export function validateNodes(
|
||||||
nodes: Node[],
|
nodes: Node[],
|
||||||
edges: Edge[]
|
edges: Edge[],
|
||||||
): // this returns an array of tuples with the node id and the errors
|
): // this returns an array of tuples with the node id and the errors
|
||||||
Array<{ id: string; errors: Array<string> }> {
|
Array<{ id: string; errors: Array<string> }> {
|
||||||
if (nodes.length === 0) {
|
if (nodes.length === 0) {
|
||||||
|
|
@ -353,7 +346,7 @@ export function updateEdges(edges: Edge[]) {
|
||||||
if (edges)
|
if (edges)
|
||||||
edges.forEach((edge) => {
|
edges.forEach((edge) => {
|
||||||
const targetHandleObject: targetHandleType = scapeJSONParse(
|
const targetHandleObject: targetHandleType = scapeJSONParse(
|
||||||
edge.targetHandle!
|
edge.targetHandle!,
|
||||||
);
|
);
|
||||||
edge.className = "stroke-gray-900 stroke-connection";
|
edge.className = "stroke-gray-900 stroke-connection";
|
||||||
});
|
});
|
||||||
|
|
@ -420,7 +413,7 @@ export function handleKeyDown(
|
||||||
| React.KeyboardEvent<HTMLInputElement>
|
| React.KeyboardEvent<HTMLInputElement>
|
||||||
| React.KeyboardEvent<HTMLTextAreaElement>,
|
| React.KeyboardEvent<HTMLTextAreaElement>,
|
||||||
inputValue: string | string[] | null,
|
inputValue: string | string[] | null,
|
||||||
block: string
|
block: string,
|
||||||
) {
|
) {
|
||||||
//condition to fix bug control+backspace on Windows/Linux
|
//condition to fix bug control+backspace on Windows/Linux
|
||||||
if (
|
if (
|
||||||
|
|
@ -445,7 +438,7 @@ export function handleKeyDown(
|
||||||
}
|
}
|
||||||
|
|
||||||
export function handleOnlyIntegerInput(
|
export function handleOnlyIntegerInput(
|
||||||
event: React.KeyboardEvent<HTMLInputElement>
|
event: React.KeyboardEvent<HTMLInputElement>,
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
event.key === "." ||
|
event.key === "." ||
|
||||||
|
|
@ -461,7 +454,7 @@ export function handleOnlyIntegerInput(
|
||||||
|
|
||||||
export function getConnectedNodes(
|
export function getConnectedNodes(
|
||||||
edge: Edge,
|
edge: Edge,
|
||||||
nodes: Array<NodeType>
|
nodes: Array<NodeType>,
|
||||||
): Array<NodeType> {
|
): Array<NodeType> {
|
||||||
const sourceId = edge.source;
|
const sourceId = edge.source;
|
||||||
const targetId = edge.target;
|
const targetId = edge.target;
|
||||||
|
|
@ -561,7 +554,7 @@ export function checkOldEdgesHandles(edges: Edge[]): boolean {
|
||||||
!edge.sourceHandle ||
|
!edge.sourceHandle ||
|
||||||
!edge.targetHandle ||
|
!edge.targetHandle ||
|
||||||
!edge.sourceHandle.includes("{") ||
|
!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 keys = Object.keys(obj).sort();
|
||||||
const keyValuePairs = keys.map(
|
const keyValuePairs = keys.map(
|
||||||
(key) => `"${key}":${customStringify(obj[key])}`
|
(key) => `"${key}":${customStringify(obj[key])}`,
|
||||||
);
|
);
|
||||||
return `{${keyValuePairs.join(",")}}`;
|
return `{${keyValuePairs.join(",")}}`;
|
||||||
}
|
}
|
||||||
|
|
@ -613,7 +606,7 @@ export function getHandleId(
|
||||||
source: string,
|
source: string,
|
||||||
sourceHandle: string,
|
sourceHandle: string,
|
||||||
target: string,
|
target: string,
|
||||||
targetHandle: string
|
targetHandle: string,
|
||||||
) {
|
) {
|
||||||
return (
|
return (
|
||||||
"reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle
|
"reactflow__edge-" + source + sourceHandle + "-" + target + targetHandle
|
||||||
|
|
@ -624,7 +617,7 @@ export function generateFlow(
|
||||||
selection: OnSelectionChangeParams,
|
selection: OnSelectionChangeParams,
|
||||||
nodes: Node[],
|
nodes: Node[],
|
||||||
edges: Edge[],
|
edges: Edge[],
|
||||||
name: string
|
name: string,
|
||||||
): generateFlowType {
|
): generateFlowType {
|
||||||
const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } };
|
const newFlowData = { nodes, edges, viewport: { zoom: 1, x: 0, y: 0 } };
|
||||||
const uid = new ShortUniqueId({ length: 5 });
|
const uid = new ShortUniqueId({ length: 5 });
|
||||||
|
|
@ -633,7 +626,7 @@ export function generateFlow(
|
||||||
newFlowData.edges = selection.edges.filter(
|
newFlowData.edges = selection.edges.filter(
|
||||||
(edge) =>
|
(edge) =>
|
||||||
selection.nodes.some((node) => node.id === edge.target) &&
|
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;
|
newFlowData.nodes = selection.nodes;
|
||||||
|
|
||||||
|
|
@ -654,7 +647,7 @@ export function generateFlow(
|
||||||
(edge) =>
|
(edge) =>
|
||||||
(selection.nodes.some((node) => node.id === edge.target) ||
|
(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.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 { nodes, edges } = groupNode.data.node!.flow!.data!;
|
||||||
const lastNode = findLastNode(groupNode.data.node!.flow!.data!);
|
const lastNode = findLastNode(groupNode.data.node!.flow!.data!);
|
||||||
newEdges = newEdges.filter(
|
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) => {
|
newEdges.forEach((edge) => {
|
||||||
if (lastNode && edge.source === lastNode.id) {
|
if (lastNode && edge.source === lastNode.id) {
|
||||||
edge.source = groupNode.id;
|
edge.source = groupNode.id;
|
||||||
let newSourceHandle: sourceHandleType = scapeJSONParse(
|
let newSourceHandle: sourceHandleType = scapeJSONParse(
|
||||||
edge.sourceHandle!
|
edge.sourceHandle!,
|
||||||
);
|
);
|
||||||
newSourceHandle.id = groupNode.id;
|
newSourceHandle.id = groupNode.id;
|
||||||
edge.sourceHandle = scapedJSONStringfy(newSourceHandle);
|
edge.sourceHandle = scapedJSONStringfy(newSourceHandle);
|
||||||
|
|
@ -698,7 +691,7 @@ export function reconnectEdges(groupNode: NodeType, excludedEdges: Edge[]) {
|
||||||
export function filterFlow(
|
export function filterFlow(
|
||||||
selection: OnSelectionChangeParams,
|
selection: OnSelectionChangeParams,
|
||||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
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)));
|
setNodes((nodes) => nodes.filter((node) => !selection.nodes.includes(node)));
|
||||||
setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge)));
|
setEdges((edges) => edges.filter((edge) => !selection.edges.includes(edge)));
|
||||||
|
|
@ -736,7 +729,7 @@ export function updateFlowPosition(NewPosition: XYPosition, flow: FlowType) {
|
||||||
export function concatFlows(
|
export function concatFlows(
|
||||||
flow: FlowType,
|
flow: FlowType,
|
||||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
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!;
|
const { nodes, edges } = flow.data!;
|
||||||
setNodes((old) => [...old, ...nodes]);
|
setNodes((old) => [...old, ...nodes]);
|
||||||
|
|
@ -745,7 +738,7 @@ export function concatFlows(
|
||||||
|
|
||||||
export function validateSelection(
|
export function validateSelection(
|
||||||
selection: OnSelectionChangeParams,
|
selection: OnSelectionChangeParams,
|
||||||
edges: Edge[]
|
edges: Edge[],
|
||||||
): Array<string> {
|
): Array<string> {
|
||||||
//add edges to selection if selection mode selected only nodes
|
//add edges to selection if selection mode selected only nodes
|
||||||
if (selection.edges.length === 0) {
|
if (selection.edges.length === 0) {
|
||||||
|
|
@ -757,7 +750,7 @@ export function validateSelection(
|
||||||
let nodesSet = new Set(selection.nodes.map((n) => n.id));
|
let nodesSet = new Set(selection.nodes.map((n) => n.id));
|
||||||
// then filter the edges that are connected to the nodes in the set
|
// then filter the edges that are connected to the nodes in the set
|
||||||
let connectedEdges = selection.edges.filter(
|
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
|
// add the edges to the selection
|
||||||
selection.edges = connectedEdges;
|
selection.edges = connectedEdges;
|
||||||
|
|
@ -771,17 +764,17 @@ export function validateSelection(
|
||||||
selection.nodes.some(
|
selection.nodes.some(
|
||||||
(node) =>
|
(node) =>
|
||||||
isInputNode(node.data as NodeDataType) ||
|
isInputNode(node.data as NodeDataType) ||
|
||||||
isOutputNode(node.data as NodeDataType)
|
isOutputNode(node.data as NodeDataType),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
errorsArray.push(
|
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
|
//check if there are two or more nodes with free outputs
|
||||||
if (
|
if (
|
||||||
selection.nodes.filter(
|
selection.nodes.filter(
|
||||||
(n) => !selection.edges.some((e) => e.source === n.id)
|
(n) => !selection.edges.some((e) => e.source === n.id),
|
||||||
).length > 1
|
).length > 1
|
||||||
) {
|
) {
|
||||||
errorsArray.push("Please select only one node with free outputs");
|
errorsArray.push("Please select only one node with free outputs");
|
||||||
|
|
@ -792,7 +785,7 @@ export function validateSelection(
|
||||||
selection.nodes.some(
|
selection.nodes.some(
|
||||||
(node) =>
|
(node) =>
|
||||||
!selection.edges.some((edge) => edge.target === node.id) &&
|
!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");
|
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].display_name
|
? nodeTemplate[key].display_name
|
||||||
: nodeTemplate[key].name
|
: nodeTemplate[key].name
|
||||||
? toTitleCase(nodeTemplate[key].name)
|
? toTitleCase(nodeTemplate[key].name)
|
||||||
: toTitleCase(key);
|
: toTitleCase(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
@ -861,7 +854,7 @@ function isHandleConnected(
|
||||||
edges: Edge[],
|
edges: Edge[],
|
||||||
key: string,
|
key: string,
|
||||||
field: TemplateVariableType,
|
field: TemplateVariableType,
|
||||||
nodeId: string
|
nodeId: string,
|
||||||
) {
|
) {
|
||||||
/*
|
/*
|
||||||
this function receives a flow and a handleId and check if there is a connection with this handle
|
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,
|
id: nodeId,
|
||||||
proxy: { id: field.proxy!.id, field: field.proxy!.field },
|
proxy: { id: field.proxy!.id, field: field.proxy!.field },
|
||||||
inputTypes: field.input_types,
|
inputTypes: field.input_types,
|
||||||
} as targetHandleType)
|
} as targetHandleType),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -892,7 +885,7 @@ function isHandleConnected(
|
||||||
fieldName: key,
|
fieldName: key,
|
||||||
id: nodeId,
|
id: nodeId,
|
||||||
inputTypes: field.input_types,
|
inputTypes: field.input_types,
|
||||||
} as targetHandleType)
|
} as targetHandleType),
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -915,7 +908,7 @@ export function generateNodeTemplate(Flow: FlowType) {
|
||||||
|
|
||||||
export function generateNodeFromFlow(
|
export function generateNodeFromFlow(
|
||||||
flow: FlowType,
|
flow: FlowType,
|
||||||
getNodeId: (type: string) => string
|
getNodeId: (type: string) => string,
|
||||||
): NodeType {
|
): NodeType {
|
||||||
const { nodes } = flow.data!;
|
const { nodes } = flow.data!;
|
||||||
const outputNode = cloneDeep(findLastNode(flow.data!));
|
const outputNode = cloneDeep(findLastNode(flow.data!));
|
||||||
|
|
@ -946,7 +939,7 @@ export function generateNodeFromFlow(
|
||||||
export function connectedInputNodesOnHandle(
|
export function connectedInputNodesOnHandle(
|
||||||
nodeId: string,
|
nodeId: string,
|
||||||
handleId: string,
|
handleId: string,
|
||||||
{ nodes, edges }: { nodes: NodeType[]; edges: Edge[] }
|
{ nodes, edges }: { nodes: NodeType[]; edges: Edge[] },
|
||||||
) {
|
) {
|
||||||
const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> =
|
const connectedNodes: Array<{ name: string; id: string; isGroup: boolean }> =
|
||||||
[];
|
[];
|
||||||
|
|
@ -983,7 +976,7 @@ export function connectedInputNodesOnHandle(
|
||||||
|
|
||||||
export function updateProxyIdsOnTemplate(
|
export function updateProxyIdsOnTemplate(
|
||||||
template: APITemplateType,
|
template: APITemplateType,
|
||||||
idsMap: { [key: string]: string }
|
idsMap: { [key: string]: string },
|
||||||
) {
|
) {
|
||||||
Object.keys(template).forEach((key) => {
|
Object.keys(template).forEach((key) => {
|
||||||
if (template[key].proxy && idsMap[template[key].proxy!.id]) {
|
if (template[key].proxy && idsMap[template[key].proxy!.id]) {
|
||||||
|
|
@ -994,7 +987,7 @@ export function updateProxyIdsOnTemplate(
|
||||||
|
|
||||||
export function updateEdgesIds(
|
export function updateEdgesIds(
|
||||||
edges: Edge[],
|
edges: Edge[],
|
||||||
idsMap: { [key: string]: string }
|
idsMap: { [key: string]: string },
|
||||||
) {
|
) {
|
||||||
edges.forEach((edge) => {
|
edges.forEach((edge) => {
|
||||||
let targetHandle: targetHandleType = edge.data.targetHandle;
|
let targetHandle: targetHandleType = edge.data.targetHandle;
|
||||||
|
|
@ -1027,7 +1020,7 @@ export function expandGroupNode(
|
||||||
nodes: Node[],
|
nodes: Node[],
|
||||||
edges: Edge[],
|
edges: Edge[],
|
||||||
setNodes: (update: Node[] | ((oldState: Node[]) => Node[])) => void,
|
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!);
|
const idsMap = updateIds(flow!.data!);
|
||||||
updateProxyIdsOnTemplate(template, idsMap);
|
updateProxyIdsOnTemplate(template, idsMap);
|
||||||
|
|
@ -1070,7 +1063,7 @@ export function expandGroupNode(
|
||||||
const lastNode = cloneDeep(findLastNode(flow!.data!));
|
const lastNode = cloneDeep(findLastNode(flow!.data!));
|
||||||
newEdge.source = lastNode!.id;
|
newEdge.source = lastNode!.id;
|
||||||
let newSourceHandle: sourceHandleType = scapeJSONParse(
|
let newSourceHandle: sourceHandleType = scapeJSONParse(
|
||||||
newEdge.sourceHandle!
|
newEdge.sourceHandle!,
|
||||||
);
|
);
|
||||||
newSourceHandle.id = lastNode!.id;
|
newSourceHandle.id = lastNode!.id;
|
||||||
newEdge.data.sourceHandle = newSourceHandle;
|
newEdge.data.sourceHandle = newSourceHandle;
|
||||||
|
|
@ -1124,7 +1117,7 @@ export function expandGroupNode(
|
||||||
|
|
||||||
export function getGroupStatus(
|
export function getGroupStatus(
|
||||||
flow: FlowType,
|
flow: FlowType,
|
||||||
ssData: { [key: string]: { valid: boolean; params: string } }
|
ssData: { [key: string]: { valid: boolean; params: string } },
|
||||||
) {
|
) {
|
||||||
let status = { valid: true, params: SUCCESS_BUILD };
|
let status = { valid: true, params: SUCCESS_BUILD };
|
||||||
const { nodes } = flow.data!;
|
const { nodes } = flow.data!;
|
||||||
|
|
@ -1143,7 +1136,7 @@ export function getGroupStatus(
|
||||||
|
|
||||||
export function createFlowComponent(
|
export function createFlowComponent(
|
||||||
nodeData: NodeDataType,
|
nodeData: NodeDataType,
|
||||||
version: string
|
version: string,
|
||||||
): FlowType {
|
): FlowType {
|
||||||
const flowNode: FlowType = {
|
const flowNode: FlowType = {
|
||||||
data: {
|
data: {
|
||||||
|
|
@ -1179,7 +1172,7 @@ export function downloadNode(NodeFLow: FlowType) {
|
||||||
|
|
||||||
export function updateComponentNameAndType(
|
export function updateComponentNameAndType(
|
||||||
data: any,
|
data: any,
|
||||||
component: NodeDataType
|
component: NodeDataType,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
export function removeFileNameFromComponents(flow: FlowType) {
|
export function removeFileNameFromComponents(flow: FlowType) {
|
||||||
|
|
@ -1253,7 +1246,7 @@ export function extractFieldsFromComponenents(data: APIObjectType) {
|
||||||
export function downloadFlow(
|
export function downloadFlow(
|
||||||
flow: FlowType,
|
flow: FlowType,
|
||||||
flowName: string,
|
flowName: string,
|
||||||
flowDescription?: string
|
flowDescription?: string,
|
||||||
) {
|
) {
|
||||||
let clonedFlow = cloneDeep(flow);
|
let clonedFlow = cloneDeep(flow);
|
||||||
removeFileNameFromComponents(clonedFlow);
|
removeFileNameFromComponents(clonedFlow);
|
||||||
|
|
@ -1263,7 +1256,7 @@ export function downloadFlow(
|
||||||
...clonedFlow,
|
...clonedFlow,
|
||||||
name: flowName,
|
name: flowName,
|
||||||
description: flowDescription,
|
description: flowDescription,
|
||||||
})
|
}),
|
||||||
)}`;
|
)}`;
|
||||||
|
|
||||||
// create a link element and set its properties
|
// create a link element and set its properties
|
||||||
|
|
@ -1278,7 +1271,7 @@ export function downloadFlow(
|
||||||
export function downloadFlows() {
|
export function downloadFlows() {
|
||||||
downloadFlowsFromDatabase().then((flows) => {
|
downloadFlowsFromDatabase().then((flows) => {
|
||||||
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
|
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
|
||||||
JSON.stringify(flows)
|
JSON.stringify(flows),
|
||||||
)}`;
|
)}`;
|
||||||
|
|
||||||
// create a link element and set its properties
|
// create a link element and set its properties
|
||||||
|
|
@ -1293,7 +1286,7 @@ export function downloadFlows() {
|
||||||
|
|
||||||
export const createNewFlow = (
|
export const createNewFlow = (
|
||||||
flowData: ReactFlowJsonObject,
|
flowData: ReactFlowJsonObject,
|
||||||
flow: FlowType
|
flow: FlowType,
|
||||||
) => {
|
) => {
|
||||||
return {
|
return {
|
||||||
description: flow?.description ?? getRandomDescription(),
|
description: flow?.description ?? getRandomDescription(),
|
||||||
|
|
|
||||||
|
|
@ -13,9 +13,8 @@ import {
|
||||||
nodeGroupedObjType,
|
nodeGroupedObjType,
|
||||||
tweakType,
|
tweakType,
|
||||||
} from "../types/components";
|
} from "../types/components";
|
||||||
import { FlowType, NodeType } from "../types/flow";
|
import { NodeType } from "../types/flow";
|
||||||
import { FlowState } from "../types/tabs";
|
import { FlowState } from "../types/tabs";
|
||||||
import { buildTweaks } from "./reactflowUtils";
|
|
||||||
|
|
||||||
export function classNames(...classes: Array<string>): string {
|
export function classNames(...classes: Array<string>): string {
|
||||||
return classes.filter(Boolean).join(" ");
|
return classes.filter(Boolean).join(" ");
|
||||||
|
|
@ -323,17 +322,10 @@ export function getChatInputField(flowState?: FlowState) {
|
||||||
* @returns {string} - The python code
|
* @returns {string} - The python code
|
||||||
*/
|
*/
|
||||||
export function getPythonApiCode(
|
export function getPythonApiCode(
|
||||||
flow: FlowType,
|
flowId: string,
|
||||||
isAuth: boolean,
|
isAuth: boolean,
|
||||||
tweak?: any[],
|
tweaksBuildedObject,
|
||||||
): string {
|
): 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
|
return `import requests
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
|
|
||||||
|
|
@ -341,11 +333,7 @@ BASE_API_URL = "${window.location.protocol}//${window.location.host}/api/v1/run"
|
||||||
FLOW_ID = "${flowId}"
|
FLOW_ID = "${flowId}"
|
||||||
# You can tweak the flow by adding a tweaks dictionary
|
# You can tweak the flow by adding a tweaks dictionary
|
||||||
# e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}}
|
# e.g {"OpenAI-XXXXX": {"model_name": "gpt-4"}}
|
||||||
TWEAKS = ${
|
TWEAKS = ${JSON.stringify(tweaksBuildedObject, null, 2)}
|
||||||
tweak && tweak.length > 0
|
|
||||||
? buildTweakObject(tweak)
|
|
||||||
: JSON.stringify(tweaks, null, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
def run_flow(message: str,
|
def run_flow(message: str,
|
||||||
flow_id: str,
|
flow_id: str,
|
||||||
|
|
@ -391,13 +379,10 @@ print(run_flow(message=message, flow_id=FLOW_ID, tweaks=TWEAKS${
|
||||||
* @returns {string} - The curl code
|
* @returns {string} - The curl code
|
||||||
*/
|
*/
|
||||||
export function getCurlCode(
|
export function getCurlCode(
|
||||||
flow: FlowType,
|
flowId: string,
|
||||||
isAuth: boolean,
|
isAuth: boolean,
|
||||||
tweak?: any[],
|
tweaksBuildedObject,
|
||||||
): string {
|
): string {
|
||||||
const flowId = flow.id;
|
|
||||||
const tweaks = buildTweaks(flow);
|
|
||||||
|
|
||||||
return `curl -X POST \\
|
return `curl -X POST \\
|
||||||
${window.location.protocol}//${
|
${window.location.protocol}//${
|
||||||
window.location.host
|
window.location.host
|
||||||
|
|
@ -408,11 +393,7 @@ export function getCurlCode(
|
||||||
-d '{"input_value": "message",
|
-d '{"input_value": "message",
|
||||||
"output_type": "chat",
|
"output_type": "chat",
|
||||||
"input_type": "chat",
|
"input_type": "chat",
|
||||||
"tweaks": ${
|
"tweaks": ${JSON.stringify(tweaksBuildedObject, null, 2)}'
|
||||||
tweak && tweak.length > 0
|
|
||||||
? buildTweakObject(tweak)
|
|
||||||
: JSON.stringify(tweaks, null, 2)
|
|
||||||
}}'
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -439,16 +420,9 @@ export function getOutputIds(flow) {
|
||||||
* @param {any[]} tweak - The tweaks
|
* @param {any[]} tweak - The tweaks
|
||||||
* @returns {string} - The python code
|
* @returns {string} - The python code
|
||||||
*/
|
*/
|
||||||
export function getPythonCode(flow: FlowType, tweak?: any[]): string {
|
export function getPythonCode(flowName: string, tweaksBuildedObject): string {
|
||||||
const flowName = flow.name;
|
|
||||||
const tweaks = buildTweaks(flow);
|
|
||||||
|
|
||||||
return `from langflow.load import run_flow_from_json
|
return `from langflow.load import run_flow_from_json
|
||||||
TWEAKS = ${
|
TWEAKS = ${JSON.stringify(tweaksBuildedObject, null, 2)}
|
||||||
tweak && tweak.length > 0
|
|
||||||
? buildTweakObject(tweak)
|
|
||||||
: JSON.stringify(tweaks, null, 2)
|
|
||||||
}
|
|
||||||
|
|
||||||
result = run_flow_from_json(flow="${flowName}.json",
|
result = run_flow_from_json(flow="${flowName}.json",
|
||||||
input_value="message",
|
input_value="message",
|
||||||
|
|
@ -461,15 +435,10 @@ result = run_flow_from_json(flow="${flowName}.json",
|
||||||
* @returns {string} - The widget code
|
* @returns {string} - The widget code
|
||||||
*/
|
*/
|
||||||
export function getWidgetCode(
|
export function getWidgetCode(
|
||||||
flow: FlowType,
|
flowId: string,
|
||||||
|
flowName: string,
|
||||||
isAuth: boolean,
|
isAuth: boolean,
|
||||||
flowState?: FlowState,
|
|
||||||
): string {
|
): 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>
|
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
|
<langflow-chat
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ test("curl_api_generation", async ({ page, context }) => {
|
||||||
await page.getByRole("tab", { name: "cURL" }).click();
|
await page.getByRole("tab", { name: "cURL" }).click();
|
||||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||||
const handle = await page.evaluateHandle(() =>
|
const handle = await page.evaluateHandle(() =>
|
||||||
navigator.clipboard.readText()
|
navigator.clipboard.readText(),
|
||||||
);
|
);
|
||||||
const clipboardContent = await handle.jsonValue();
|
const clipboardContent = await handle.jsonValue();
|
||||||
const oldValue = clipboardContent;
|
const oldValue = clipboardContent;
|
||||||
|
|
@ -50,10 +50,78 @@ test("curl_api_generation", async ({ page, context }) => {
|
||||||
await page.getByRole("tab", { name: "cURL" }).click();
|
await page.getByRole("tab", { name: "cURL" }).click();
|
||||||
await page.getByRole("button", { name: "Copy Code" }).click();
|
await page.getByRole("button", { name: "Copy Code" }).click();
|
||||||
const handle2 = await page.evaluateHandle(() =>
|
const handle2 = await page.evaluateHandle(() =>
|
||||||
navigator.clipboard.readText()
|
navigator.clipboard.readText(),
|
||||||
);
|
);
|
||||||
const clipboardContent2 = await handle2.jsonValue();
|
const clipboardContent2 = await handle2.jsonValue();
|
||||||
const newValue = clipboardContent2;
|
const newValue = clipboardContent2;
|
||||||
expect(oldValue).not.toBe(newValue);
|
expect(oldValue).not.toBe(newValue);
|
||||||
expect(clipboardContent2.length).toBeGreaterThan(clipboardContent.length);
|
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