Get data from Validate Nodes and display it on Tooltip

This commit is contained in:
Lucas Oliveira 2023-05-09 16:56:05 -03:00
commit b8c95fb7ec
6 changed files with 39 additions and 23 deletions

View file

@ -10,6 +10,7 @@ from langflow.api.base import (
from langflow.interface.run import build_graph from langflow.interface.run import build_graph
from langflow.utils.logger import logger from langflow.utils.logger import logger
from langflow.utils.validate import validate_code from langflow.utils.validate import validate_code
import json
# build router # build router
router = APIRouter(prefix="/validate", tags=["validate"]) router = APIRouter(prefix="/validate", tags=["validate"])
@ -46,8 +47,8 @@ def post_validate_node(node_id: str, data: dict):
node = graph.get_node(node_id) node = graph.get_node(node_id)
if node is not None: if node is not None:
_ = node.build() _ = node.build()
return str(node.params) return json.dumps({'valid': True, 'params': str(node.params)})
raise Exception(f"Node {node_id} not found") else:
return json.dumps({'valid': False})
except Exception as e: except Exception as e:
logger.error(e) logger.error(e)
raise HTTPException(status_code=500, detail=str(e)) from e

View file

@ -1,4 +1,4 @@
import { Cog6ToothIcon, TrashIcon } from "@heroicons/react/24/outline"; import { BugAntIcon, Cog6ToothIcon, ExclamationCircleIcon, InformationCircleIcon, TrashIcon } from "@heroicons/react/24/outline";
import { import {
classNames, classNames,
nodeColors, nodeColors,
@ -7,7 +7,7 @@ import {
} from "../../utils"; } from "../../utils";
import ParameterComponent from "./components/parameterComponent"; import ParameterComponent from "./components/parameterComponent";
import { typesContext } from "../../contexts/typesContext"; import { typesContext } from "../../contexts/typesContext";
import { useContext, useState, useEffect, useRef } from "react"; import { useContext, useState, useEffect, useRef, Fragment } from "react";
import { NodeDataType } from "../../types/flow"; import { NodeDataType } from "../../types/flow";
import { alertContext } from "../../contexts/alertContext"; import { alertContext } from "../../contexts/alertContext";
import { PopUpContext } from "../../contexts/popUpContext"; import { PopUpContext } from "../../contexts/popUpContext";
@ -15,6 +15,7 @@ import NodeModal from "../../modals/NodeModal";
import { useCallback } from "react"; import { useCallback } from "react";
import { TabsContext } from "../../contexts/tabsContext"; import { TabsContext } from "../../contexts/tabsContext";
import { debounce } from "../../utils"; import { debounce } from "../../utils";
import Tooltip from "../../components/TooltipComponent";
export default function GenericNode({ export default function GenericNode({
data, data,
selected, selected,
@ -27,7 +28,7 @@ export default function GenericNode({
const { types, deleteNode } = useContext(typesContext); const { types, deleteNode } = useContext(typesContext);
const { openPopUp } = useContext(PopUpContext); const { openPopUp } = useContext(PopUpContext);
const Icon = nodeIcons[types[data.type]]; const Icon = nodeIcons[types[data.type]];
const [validationStatus, setValidationStatus] = useState("idle"); const [validationStatus, setValidationStatus] = useState(null);
// State for outline color // State for outline color
const [isValid, setIsValid] = useState(false); const [isValid, setIsValid] = useState(false);
const { save } = useContext(TabsContext); const { save } = useContext(TabsContext);
@ -53,10 +54,15 @@ export default function GenericNode({
}); });
if (response.status === 200) { if (response.status === 200) {
setValidationStatus("success"); let jsonResponse = await response.json();
} else if (response.status === 500) { let jsonResponseParsed = await JSON.parse(jsonResponse);
console.log(jsonResponseParsed);
if(jsonResponseParsed.valid){
setValidationStatus(jsonResponseParsed.params);
} else {
setValidationStatus("error"); setValidationStatus("error");
} }
}
} catch (error) { } catch (error) {
// console.error("Error validating node:", error); // console.error("Error validating node:", error);
setValidationStatus("error"); setValidationStatus("error");
@ -71,7 +77,7 @@ export default function GenericNode({
}, [params, validateNode]); }, [params, validateNode]);
useEffect(() => { useEffect(() => {
if (validationStatus === "success") { if (validationStatus !== "error") {
setIsValid(true); setIsValid(true);
} else { } else {
setIsValid(false); setIsValid(false);
@ -100,14 +106,23 @@ export default function GenericNode({
)} )}
> >
<div className="w-full dark:text-white flex items-center justify-between p-4 gap-8 bg-gray-50 rounded-t-lg dark:bg-gray-800 border-b dark:border-b-gray-700 "> <div className="w-full dark:text-white flex items-center justify-between p-4 gap-8 bg-gray-50 rounded-t-lg dark:bg-gray-800 border-b dark:border-b-gray-700 ">
<div className="w-full flex items-center truncate gap-4 text-lg"> <div className="w-full flex items-center truncate gap-2 text-lg">
<Icon <Icon
className="w-10 h-10 p-1 rounded" className="w-10 h-10 p-1 rounded"
style={{ style={{
color: nodeColors[types[data.type]] ?? nodeColors.unknown, color: nodeColors[types[data.type]] ?? nodeColors.unknown,
}} }}
/> />
<div className="truncate">{data.type}</div> <div className="ml-2 truncate">{data.type}</div>
{validationStatus && validationStatus !== "error" ?
<Tooltip title={
<div className="max-h-96 overflow-auto">
{validationStatus}
</div>}>
<ExclamationCircleIcon className="w-5 hover:text-gray-500 hover:dark:text-gray-300" />
</Tooltip>
: <></>
}
</div> </div>
<div className="flex gap-3"> <div className="flex gap-3">
<button <button
@ -134,7 +149,7 @@ export default function GenericNode({
) )
? "" ? ""
: "hidden", : "hidden",
"w-6 h-6 dark:text-gray-500 hover:animate-spin" "w-6 h-6 dark:text-gray-300 hover:animate-spin"
)} )}
></Cog6ToothIcon> ></Cog6ToothIcon>
</button> </button>
@ -143,13 +158,13 @@ export default function GenericNode({
deleteNode(data.id); deleteNode(data.id);
}} }}
> >
<TrashIcon className="w-6 h-6 hover:text-red-500 dark:text-gray-500 dark:hover:text-red-500"></TrashIcon> <TrashIcon className="w-6 h-6 hover:text-red-500 dark:text-gray-300 dark:hover:text-red-500"></TrashIcon>
</button> </button>
</div> </div>
</div> </div>
<div className="w-full h-full py-5"> <div className="w-full h-full py-5">
<div className="w-full text-gray-500 px-5 pb-3 text-sm"> <div className="w-full text-gray-500 dark:text-gray-300 px-5 pb-3 text-sm">
{data.node.description} {data.node.description}
</div> </div>

View file

@ -38,7 +38,7 @@ export default function InputComponent({
}} }}
/> />
<button <button
className="absolute inset-y-0 right-0 items-center px-4 text-gray-600" className="absolute inset-y-0 right-0 items-center px-4 text-gray-600 dark:text-gray-300"
onClick={() => { onClick={() => {
setPwdVisible(!pwdVisible); setPwdVisible(!pwdVisible);
}} }}

View file

@ -18,7 +18,7 @@ export default function TextAreaComponent({ value, onChange, disabled }:TextArea
<div className="w-full flex items-center gap-3"> <div className="w-full flex items-center gap-3">
<span onClick={()=>{openPopUp(<TextAreaModal value={myValue} setValue={(t:string) => {setMyValue(t); onChange(t);}}/>)}} <span onClick={()=>{openPopUp(<TextAreaModal value={myValue} setValue={(t:string) => {setMyValue(t); onChange(t);}}/>)}}
className={ className={
"truncate block w-full text-gray-500 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" + "truncate block w-full text-gray-500 dark:text-gray-100 px-3 py-2 rounded-md border border-gray-300 dark:border-gray-700 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm" +
(disabled ? " bg-gray-200" : "") (disabled ? " bg-gray-200" : "")
} }
> >

View file

@ -57,18 +57,18 @@ export default function TabsManagerComponent() {
<div className="ml-auto mr-2 flex gap-3"> <div className="ml-auto mr-2 flex gap-3">
<button <button
onClick={() => openPopUp(<ImportModal />)} onClick={() => openPopUp(<ImportModal />)}
className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-600 hover:text-gray-500" className="flex items-center gap-1 pr-2 border-gray-400 border-r text-sm text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200"
> >
Import <ArrowUpTrayIcon className="w-5 h-5" /> Import <ArrowUpTrayIcon className="w-5 h-5" />
</button> </button>
<button <button
onClick={() => openPopUp(<ExportModal />)} onClick={() => openPopUp(<ExportModal />)}
className="flex items-center gap-1 mr-2 text-sm text-gray-600 hover:text-gray-500" className="flex items-center gap-1 mr-2 text-sm text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200"
> >
Export <ArrowDownTrayIcon className="h-5 w-5" /> Export <ArrowDownTrayIcon className="h-5 w-5" />
</button> </button>
<button <button
className="text-gray-600 hover:text-gray-500 " className="text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200"
onClick={() => { onClick={() => {
setDark(!dark); setDark(!dark);
}} }}
@ -80,7 +80,7 @@ export default function TabsManagerComponent() {
)} )}
</button> </button>
<button <button
className="text-gray-600 hover:text-gray-500 relative" className="text-gray-600 hover:text-gray-500 dark:text-gray-300 dark:hover:text-gray-200 relative"
onClick={(event: React.MouseEvent<HTMLElement>) => { onClick={(event: React.MouseEvent<HTMLElement>) => {
setNotificationCenter(false); setNotificationCenter(false);
const top = (event.target as Element).getBoundingClientRect().top; const top = (event.target as Element).getBoundingClientRect().top;

View file

@ -1,4 +1,4 @@
import { ForwardRefExoticComponent, ReactElement, ReactNode } from "react"; import { ForwardRefExoticComponent, ReactElement, ReactFragment, ReactNode } from "react";
import { NodeDataType } from "../flow/index"; import { NodeDataType } from "../flow/index";
export type InputComponentType = { export type InputComponentType = {
value: string; value: string;
@ -68,7 +68,7 @@ export type FloatComponentType = {
export type TooltipComponentType = { export type TooltipComponentType = {
children: ReactElement; children: ReactElement;
title: string; title: string | ReactElement;
placement?: placement?:
| "bottom-end" | "bottom-end"
| "bottom-start" | "bottom-start"