fix: tweaks page (#807)
This pull request addresses multiple bugs and issues that have been identified on the tweaks page of our application. The changes implemented here aim to enhance the overall user experience and improve the stability of the page. Below is an overview of the resolved issues:
BIN
docs/static/img/new_langflow.gif
vendored
|
Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 3.2 MiB |
BIN
docs/static/img/new_langflow2.gif
vendored
|
Before Width: | Height: | Size: 3.2 MiB After Width: | Height: | Size: 3.2 MiB |
BIN
docs/static/videos/langflow_api.mp4
vendored
BIN
docs/static/videos/langflow_build.mp4
vendored
BIN
docs/static/videos/langflow_collection.mp4
vendored
BIN
docs/static/videos/langflow_collection_example.mp4
vendored
BIN
docs/static/videos/langflow_fork.mp4
vendored
BIN
docs/static/videos/langflow_parameters.mp4
vendored
BIN
docs/static/videos/langflow_widget.mp4
vendored
|
Before Width: | Height: | Size: 2 MiB After Width: | Height: | Size: 2 MiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 102 KiB |
|
|
@ -32,13 +32,6 @@ export default function AccordionComponent({
|
|||
value === "" ? setValue(keyValue!) : setValue("");
|
||||
}
|
||||
|
||||
const handleKeyDown = (event) => {
|
||||
if (event.key === "Backspace") {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<Accordion
|
||||
|
|
@ -46,7 +39,6 @@ export default function AccordionComponent({
|
|||
className="w-full"
|
||||
value={value}
|
||||
onValueChange={setValue}
|
||||
onKeyDown={handleKeyDown}
|
||||
>
|
||||
<AccordionItem value={keyValue!} className="border-b">
|
||||
<AccordionTrigger
|
||||
|
|
|
|||
|
|
@ -60,6 +60,11 @@ export default function BuildTrigger({
|
|||
],
|
||||
});
|
||||
}
|
||||
if (errors.length === 0 && allNodesValid) {
|
||||
setSuccessData({
|
||||
title: "Flow is ready to run",
|
||||
});
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error:", error);
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -28,8 +28,11 @@ import {
|
|||
TabsList,
|
||||
TabsTrigger,
|
||||
} from "../../components/ui/tabs";
|
||||
import { alertContext } from "../../contexts/alertContext";
|
||||
import { darkContext } from "../../contexts/darkContext";
|
||||
import { typesContext } from "../../contexts/typesContext";
|
||||
import { codeTabsPropsType } from "../../types/components";
|
||||
import { unselectAllNodes } from "../../utils/reactflowUtils";
|
||||
import { classNames } from "../../utils/utils";
|
||||
import IconComponent from "../genericIconComponent";
|
||||
|
||||
|
|
@ -45,6 +48,8 @@ export default function CodeTabsComponent({
|
|||
const [data, setData] = useState(flow ? flow["data"]!["nodes"] : null);
|
||||
const [openAccordion, setOpenAccordion] = useState<string[]>([]);
|
||||
const { dark } = useContext(darkContext);
|
||||
const { reactFlowInstance } = useContext(typesContext);
|
||||
const { isTweakPage, setIsTweakPage } = useContext(alertContext);
|
||||
|
||||
useEffect(() => {
|
||||
if (flow && flow["data"]!["nodes"]) {
|
||||
|
|
@ -52,6 +57,19 @@ export default function CodeTabsComponent({
|
|||
}
|
||||
}, [flow]);
|
||||
|
||||
useEffect(() => {
|
||||
unselectAllNodes({
|
||||
data,
|
||||
updateNodes: (nodes) => {
|
||||
reactFlowInstance?.setNodes(nodes);
|
||||
},
|
||||
});
|
||||
|
||||
return () => {
|
||||
if (isTweakPage) setIsTweakPage(false);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const copyToClipboard = () => {
|
||||
if (!navigator.clipboard || !navigator.clipboard.writeText) {
|
||||
return;
|
||||
|
|
@ -159,13 +177,13 @@ export default function CodeTabsComponent({
|
|||
)}
|
||||
</div>
|
||||
|
||||
{tabs.map((tab, index) => (
|
||||
{tabs.map((tab, idx) => (
|
||||
<TabsContent
|
||||
value={index.toString()}
|
||||
value={idx.toString()}
|
||||
className="api-modal-tabs-content"
|
||||
key={index} // Remember to add a unique key prop
|
||||
key={idx} // Remember to add a unique key prop
|
||||
>
|
||||
{index < 4 ? (
|
||||
{idx < 4 ? (
|
||||
<>
|
||||
{tab.description && (
|
||||
<div
|
||||
|
|
@ -181,7 +199,7 @@ export default function CodeTabsComponent({
|
|||
{tab.code}
|
||||
</SyntaxHighlighter>
|
||||
</>
|
||||
) : index === 4 ? (
|
||||
) : idx === 4 ? (
|
||||
<>
|
||||
<div className="api-modal-according-display">
|
||||
<div
|
||||
|
|
@ -192,8 +210,8 @@ export default function CodeTabsComponent({
|
|||
: "overflow-hidden"
|
||||
)}
|
||||
>
|
||||
{data?.map((node: any, index) => (
|
||||
<div className="px-3" key={index}>
|
||||
{data?.map((node: any, i) => (
|
||||
<div className="px-3" key={i}>
|
||||
{tweaks?.tweaksList!.current.includes(
|
||||
node["data"]["id"]
|
||||
) && (
|
||||
|
|
@ -236,10 +254,10 @@ export default function CodeTabsComponent({
|
|||
node.data.node.template[templateField]
|
||||
.type === "int")
|
||||
)
|
||||
.map((templateField, index) => {
|
||||
.map((templateField, indx) => {
|
||||
return (
|
||||
<TableRow
|
||||
key={index}
|
||||
key={indx}
|
||||
className="h-10 dark:border-b-muted"
|
||||
>
|
||||
<TableCell className="p-0 text-center text-sm text-foreground">
|
||||
|
|
@ -277,13 +295,9 @@ export default function CodeTabsComponent({
|
|||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList!.find(
|
||||
(obj) =>
|
||||
obj.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
)!.data.node.template[
|
||||
newInputList![
|
||||
i
|
||||
].data.node.template[
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
|
|
@ -330,13 +344,9 @@ export default function CodeTabsComponent({
|
|||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList!.find(
|
||||
(obj) =>
|
||||
obj.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
)!.data.node.template[
|
||||
newInputList![
|
||||
i
|
||||
].data.node.template[
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
|
|
@ -379,13 +389,9 @@ export default function CodeTabsComponent({
|
|||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList!.find(
|
||||
(obj) =>
|
||||
obj.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
)!.data.node.template[
|
||||
newInputList![
|
||||
i
|
||||
].data.node.template[
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
|
|
@ -416,13 +422,9 @@ export default function CodeTabsComponent({
|
|||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList!.find(
|
||||
(obj) =>
|
||||
obj.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
)!.data.node.template[
|
||||
newInputList![
|
||||
i
|
||||
].data.node.template[
|
||||
templateField
|
||||
].value = e;
|
||||
return newInputList;
|
||||
|
|
@ -511,13 +513,9 @@ export default function CodeTabsComponent({
|
|||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList!.find(
|
||||
(obj) =>
|
||||
obj.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
)!.data.node.template[
|
||||
newInputList![
|
||||
i
|
||||
].data.node.template[
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
|
|
@ -551,13 +549,9 @@ export default function CodeTabsComponent({
|
|||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList!.find(
|
||||
(obj) =>
|
||||
obj.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
)!.data.node.template[
|
||||
newInputList![
|
||||
i
|
||||
].data.node.template[
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
|
|
@ -607,14 +601,9 @@ export default function CodeTabsComponent({
|
|||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
|
||||
newInputList!.find(
|
||||
(obj) =>
|
||||
obj.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
)!.data.node.template[
|
||||
newInputList![
|
||||
i
|
||||
].data.node.template[
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
|
|
@ -667,13 +656,9 @@ export default function CodeTabsComponent({
|
|||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList!.find(
|
||||
(obj) =>
|
||||
obj.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
)!.data.node.template[
|
||||
newInputList![
|
||||
i
|
||||
].data.node.template[
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
|
|
@ -726,13 +711,9 @@ export default function CodeTabsComponent({
|
|||
setData((old) => {
|
||||
let newInputList =
|
||||
cloneDeep(old);
|
||||
newInputList!.find(
|
||||
(obj) =>
|
||||
obj.data.node
|
||||
.template[
|
||||
templateField
|
||||
]
|
||||
)!.data.node.template[
|
||||
newInputList![
|
||||
i
|
||||
].data.node.template[
|
||||
templateField
|
||||
].value = target;
|
||||
return newInputList;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ const initialValue: alertContextType = {
|
|||
pushNotificationList: () => {},
|
||||
clearNotificationList: () => {},
|
||||
removeFromNotificationList: () => {},
|
||||
isTweakPage: false,
|
||||
setIsTweakPage: () => {},
|
||||
};
|
||||
|
||||
export const alertContext = createContext<alertContextType>(initialValue);
|
||||
|
|
@ -48,6 +50,7 @@ export function AlertProvider({ children }: { children: ReactNode }) {
|
|||
const [successOpen, setSuccessOpen] = useState(false);
|
||||
const [notificationCenter, setNotificationCenter] = useState(false);
|
||||
const [notificationList, setNotificationList] = useState<AlertItemType[]>([]);
|
||||
const [isTweakPage, setIsTweakPage] = useState<boolean>(false);
|
||||
const pushNotificationList = (notification: AlertItemType) => {
|
||||
setNotificationList((old) => {
|
||||
let newNotificationList = _.cloneDeep(old);
|
||||
|
|
@ -120,6 +123,8 @@ export function AlertProvider({ children }: { children: ReactNode }) {
|
|||
return (
|
||||
<alertContext.Provider
|
||||
value={{
|
||||
isTweakPage,
|
||||
setIsTweakPage,
|
||||
removeFromNotificationList,
|
||||
clearNotificationList,
|
||||
notificationList,
|
||||
|
|
|
|||
|
|
@ -28,7 +28,8 @@ export default function CodeAreaModal({
|
|||
const { dark } = useContext(darkContext);
|
||||
const { reactFlowInstance } = useContext(typesContext);
|
||||
const [height, setHeight] = useState<string | null>(null);
|
||||
const { setErrorData, setSuccessData } = useContext(alertContext);
|
||||
const { setErrorData, setSuccessData, isTweakPage } =
|
||||
useContext(alertContext);
|
||||
const [error, setError] = useState<{
|
||||
detail: { error: string | undefined; traceback: string | undefined };
|
||||
} | null>(null);
|
||||
|
|
@ -39,7 +40,7 @@ export default function CodeAreaModal({
|
|||
if (dynamic && Object.keys(nodeClass!.template).length > 2) {
|
||||
return;
|
||||
}
|
||||
processCode();
|
||||
if (!isTweakPage) processCode();
|
||||
}, []);
|
||||
|
||||
function processNonDynamicField() {
|
||||
|
|
|
|||
|
|
@ -21,7 +21,8 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
const { data, templates } = useContext(typesContext);
|
||||
const { flows, tabId, uploadFlow, tabsState, saveFlow, isBuilt } =
|
||||
useContext(TabsContext);
|
||||
const { setSuccessData, setErrorData } = useContext(alertContext);
|
||||
const { setSuccessData, setErrorData, setIsTweakPage } =
|
||||
useContext(alertContext);
|
||||
const [dataFilter, setFilterData] = useState(data);
|
||||
const [search, setSearch] = useState("");
|
||||
const isPending = tabsState[tabId]?.isPending;
|
||||
|
|
@ -100,7 +101,10 @@ export default function ExtraSidebar(): JSX.Element {
|
|||
<div className="side-bar-button">
|
||||
{flow && flow.data && (
|
||||
<ApiModal flow={flow} disable={!isBuilt}>
|
||||
<div className={classNames("extra-side-bar-buttons")}>
|
||||
<div
|
||||
className={classNames("extra-side-bar-buttons")}
|
||||
onClick={() => setIsTweakPage(true)}
|
||||
>
|
||||
<IconComponent
|
||||
name="Code2"
|
||||
className={
|
||||
|
|
|
|||
|
|
@ -41,6 +41,8 @@ export type alertContextType = {
|
|||
removeFromNotificationList: (index: string) => void;
|
||||
loading: boolean;
|
||||
setLoading: (newState: boolean) => void;
|
||||
isTweakPage: boolean;
|
||||
setIsTweakPage: (newState: boolean) => void;
|
||||
};
|
||||
|
||||
export type darkContextType = {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Edge } from "reactflow";
|
||||
import { Edge, Node } from "reactflow";
|
||||
import { NodeType } from "../flow";
|
||||
|
||||
export type cleanEdgesType = {
|
||||
|
|
@ -8,3 +8,8 @@ export type cleanEdgesType = {
|
|||
};
|
||||
updateEdge: (edge: Edge[]) => void;
|
||||
};
|
||||
|
||||
export type unselectAllNodesType = {
|
||||
updateNodes: (nodes: Node[]) => void;
|
||||
data: Node[] | null;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,13 +2,17 @@ import _ from "lodash";
|
|||
import {
|
||||
Connection,
|
||||
Edge,
|
||||
Node,
|
||||
ReactFlowInstance,
|
||||
ReactFlowJsonObject,
|
||||
} from "reactflow";
|
||||
import { specialCharsRegex } from "../constants/constants";
|
||||
import { APITemplateType } from "../types/api";
|
||||
import { FlowType, NodeType } from "../types/flow";
|
||||
import { cleanEdgesType } from "../types/utils/reactflowUtils";
|
||||
import {
|
||||
cleanEdgesType,
|
||||
unselectAllNodesType,
|
||||
} from "../types/utils/reactflowUtils";
|
||||
import { toNormalCase } from "./utils";
|
||||
|
||||
export function cleanEdges({
|
||||
|
|
@ -55,6 +59,14 @@ export function cleanEdges({
|
|||
updateEdge(newEdges);
|
||||
}
|
||||
|
||||
export function unselectAllNodes({ updateNodes, data }: unselectAllNodesType) {
|
||||
let newNodes = _.cloneDeep(data);
|
||||
newNodes!.forEach((node: Node) => {
|
||||
node.selected = false;
|
||||
});
|
||||
updateNodes(newNodes!);
|
||||
}
|
||||
|
||||
export function isValidConnection(
|
||||
{ source, target, sourceHandle, targetHandle }: Connection,
|
||||
reactFlowInstance: ReactFlowInstance
|
||||
|
|
@ -247,7 +259,6 @@ export function handleKeyDown(
|
|||
inputValue: string | string[] | null,
|
||||
block: string
|
||||
) {
|
||||
console.log(e, inputValue, block);
|
||||
//condition to fix bug control+backspace on Windows/Linux
|
||||
if (
|
||||
(typeof inputValue === "string" &&
|
||||
|
|
|
|||