Merge branch 'fix/minor_ui_adjustments' of https://github.com/langflow-ai/langflow into fix/minor_ui_adjustments

This commit is contained in:
cristhianzl 2024-06-10 17:33:47 -03:00
commit bac28d94c2
5 changed files with 131 additions and 382 deletions

View file

@ -2,7 +2,7 @@ import { Transition } from "@headlessui/react";
import { useMemo, useRef, useState } from "react";
import { useHotkeys } from "react-hotkeys-hook";
import IOModal from "../../modals/IOModal";
import ApiModal from "../../modals/apiModal/views";
import ApiModal from "../../modals/apiModal";
import ShareModal from "../../modals/shareModal";
import useFlowStore from "../../stores/flowStore";
import useFlowsManagerStore from "../../stores/flowsManagerStore";

View file

@ -2,35 +2,29 @@ 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 { 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,
LANGFLOW_SUPPORTED_TYPES,
} from "../../constants/constants";
import { EXPORT_CODE_DIALOG } from "../../constants/constants";
import { AuthContext } from "../../contexts/authContext";
import useFlowStore from "../../stores/flowStore";
import { useTweaksStore } from "../../stores/tweaksStore";
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 { uniqueTweakType } from "../../types/components";
import { FlowType } from "../../types/flow/index";
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 { getCurlRunCode, getCurlWebhookCode } from "./utils/get-curl-code";
import { getNodesWithDefaultValue } from "./utils/get-nodes-with-default-value";
import getPythonApiCode from "./utils/get-python-api-code";
import getPythonCode from "./utils/get-python-code";
import { getValue } from "./utils/get-value";
import getWidgetCode from "./utils/get-widget-code";
import { createTabsArray } from "./utils/tabs-array";
const ApiModal = forwardRef(
(
@ -42,122 +36,136 @@ const ApiModal = forwardRef(
}: {
flow: FlowType;
children: ReactNode;
open: any;
setOpen: any;
open?: boolean;
setOpen?: (a: boolean | ((o?: boolean) => boolean)) => void;
},
ref
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] =
mySetOpen !== undefined && myOpen !== undefined
? [myOpen, mySetOpen]
: 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 pythonApiCode = getPythonApiCode(
flow?.id,
autoLogin,
tweak,
flow?.endpoint_name,
);
const curl_run_code = getCurlRunCode(
flow?.id,
autoLogin,
tweak,
flow?.endpoint_name,
);
const curl_webhook_code = getCurlWebhookCode(
flow?.id,
autoLogin,
flow?.endpoint_name,
);
const pythonCode = getPythonCode(flow?.name, tweak);
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
const includeWebhook = flow.webhook;
const tweaksCode = buildTweaks(flow);
const codesArray = [
curl_code,
curl_run_code,
curl_webhook_code,
pythonApiCode,
pythonCode,
widgetCode,
pythonCode,
];
const [tabs, setTabs] = useState(tabsArray(codesArray, 0));
const [tabs, setTabs] = useState(
createTabsArray(codesArray, includeWebhook),
);
function startState() {
tweak.current = [];
setTweak([]);
tweaksList.current = [];
}
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) {
startState();
addTweaks([]);
setTweaksList([]);
} else {
tweak.current = [];
const t = buildTweaks(flow);
tweak.current.push(t);
buildTweaksInitialState();
}
filterNodes();
if (Object.keys(tweaksCode).length > 0) {
setActiveTab("0");
setTabs(tabsArray(codesArray, 1));
setTabs(createTabsArray(codesArray, includeWebhook, true));
} else {
setTabs(tabsArray(codesArray, 1));
setTabs(createTabsArray(codesArray, includeWebhook, true));
}
}, [flow["data"]!["nodes"], open]);
function filterNodes() {
let arrNodesWithValues: string[] = [];
useEffect(() => {
if (canShowTweaks) {
const nodes = flow["data"]!["nodes"];
nodes.forEach((element) => {
const nodeId = element["id"];
const template = element["data"]["node"]["template"];
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"]);
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]);
tweaksList.current = arrNodesWithValues.filter((value, index, self) => {
return self.indexOf(value) === index;
});
}
function buildTweakObject(
const filterNodes = () => {
setTweaksList(getNodesWithDefaultValue(flow));
};
async function buildTweakObject(
tw: string,
changes: string | string[] | boolean | number | Object[] | Object,
template: TemplateVariableType
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 !== "");
}
changes = getChangesType(changes, template);
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)
);
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.current.forEach((element) => {
tweak.forEach((element) => {
if (element[tw] && Object.keys(element[tw])?.length === 0) {
tweak.current = tweak.current.filter((obj) => {
const filteredTweaks = tweak.filter((obj) => {
const prop = obj[Object.keys(obj)[0]].prop;
return prop !== undefined && prop !== null && prop !== "";
});
addTweaks(filteredTweaks);
}
});
}
@ -167,56 +175,34 @@ const ApiModal = forwardRef(
[template["name"]!]: changes,
},
} as uniqueTweakType;
tweak.current.push(newTweak);
tweak.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);
if (tweak && tweak.length > 0) {
const cloneTweak = cloneDeep(tweak);
addCodes(cloneTweak);
addTweaks(cloneTweak);
}
}
function buildContent(value: string) {
const htmlContent = (
<div className="w-[200px]">
<span>{value != null && value != "" ? value : "None"}</span>
</div>
const addCodes = (cloneTweak) => {
const pythonApiCode = getPythonApiCode(flow?.id, autoLogin, cloneTweak);
const curl_code = getCurlRunCode(
flow?.id,
autoLogin,
cloneTweak,
flow?.endpoint_name,
);
return htmlContent;
}
const pythonCode = getPythonCode(flow?.name, cloneTweak);
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
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 ?? "";
if (tabs && tabs?.length > 0) {
tabs![0].code = curl_code;
tabs![1].code = pythonApiCode;
tabs![2].code = pythonCode;
tabs![3].code = widgetCode;
}
return returnValue;
}
};
return (
<BaseModal open={open} setOpen={setOpen}>
@ -229,7 +215,7 @@ const ApiModal = forwardRef(
aria-hidden="true"
/>
</BaseModal.Header>
<BaseModal.Content>
<BaseModal.Content overflowHidden>
<CodeTabsComponent
flow={flow}
tabs={tabs!}
@ -242,11 +228,14 @@ const ApiModal = forwardRef(
buildTweakObject,
getValue,
}}
activeTweaks={activeTweaks}
setActiveTweaks={setActiveTweaks}
allowExport
/>
</BaseModal.Content>
</BaseModal>
);
}
},
);
export default ApiModal;

View file

@ -1,241 +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, 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 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 { getCurlRunCode, getCurlWebhookCode } from "../utils/get-curl-code";
import { getNodesWithDefaultValue } from "../utils/get-nodes-with-default-value";
import getPythonApiCode from "../utils/get-python-api-code";
import getPythonCode from "../utils/get-python-code";
import { getValue } from "../utils/get-value";
import getWidgetCode from "../utils/get-widget-code";
import { createTabsArray } from "../utils/tabs-array";
const ApiModal = forwardRef(
(
{
flow,
children,
open: myOpen,
setOpen: mySetOpen,
}: {
flow: FlowType;
children: ReactNode;
open?: boolean;
setOpen?: (a: boolean | ((o?: boolean) => boolean)) => void;
},
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] =
mySetOpen !== undefined && myOpen !== undefined
? [myOpen, mySetOpen]
: useState(false);
const [activeTab, setActiveTab] = useState("0");
const pythonApiCode = getPythonApiCode(
flow?.id,
autoLogin,
tweak,
flow?.endpoint_name,
);
const curl_run_code = getCurlRunCode(
flow?.id,
autoLogin,
tweak,
flow?.endpoint_name,
);
const curl_webhook_code = getCurlWebhookCode(
flow?.id,
autoLogin,
flow?.endpoint_name,
);
const pythonCode = getPythonCode(flow?.name, tweak);
const widgetCode = getWidgetCode(flow?.id, flow?.name, autoLogin);
const includeWebhook = flow.webhook;
const tweaksCode = buildTweaks(flow);
const codesArray = [
curl_run_code,
curl_webhook_code,
pythonApiCode,
pythonCode,
widgetCode,
pythonCode,
];
const [tabs, setTabs] = useState(
createTabsArray(codesArray, includeWebhook),
);
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(createTabsArray(codesArray, includeWebhook, true));
} else {
setTabs(createTabsArray(codesArray, includeWebhook, true));
}
}, [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 = getCurlRunCode(
flow?.id,
autoLogin,
cloneTweak,
flow?.endpoint_name,
);
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}
allowExport
/>
</BaseModal.Content>
</BaseModal>
);
},
);
export default ApiModal;

View file

@ -29,7 +29,7 @@ const ApiKeyHeaderComponent = ({
<div className="flex flex-shrink-0 items-center gap-2">
<SecretKeyModal data={userId} onCloseModal={fetchApiKeys}>
<Button data-testid="api-key-button-store" variant="primary">
<ForwardedIconComponent name="Plus" className="mr-2 w-4" />
<ForwardedIconComponent name="Plus" className="w-4" />
Add New
</Button>
</SecretKeyModal>

View file

@ -81,6 +81,7 @@ export default function GlobalVariablesPage() {
flex: 2,
}, //This column will be twice as wide as the others
{
headerName: "Type",
field: "type",
cellRenderer: BadgeRenderer,
cellEditor: DropdownEditor,
@ -144,7 +145,7 @@ export default function GlobalVariablesPage() {
<div className="flex flex-shrink-0 items-center gap-2">
<AddNewVariableButton>
<Button data-testid="api-key-button-store" variant="primary">
<IconComponent name="Plus" className="mr-2 w-4" />
<IconComponent name="Plus" className="w-4" />
Add New
</Button>
</AddNewVariableButton>