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.utils.logger import logger
from langflow.utils.validate import validate_code
import json
# build router
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)
if node is not None:
_ = node.build()
return str(node.params)
raise Exception(f"Node {node_id} not found")
return json.dumps({'valid': True, 'params': str(node.params)})
else:
return json.dumps({'valid': False})
except Exception as 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 {
classNames,
nodeColors,
@ -7,7 +7,7 @@ import {
} from "../../utils";
import ParameterComponent from "./components/parameterComponent";
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 { alertContext } from "../../contexts/alertContext";
import { PopUpContext } from "../../contexts/popUpContext";
@ -15,6 +15,7 @@ import NodeModal from "../../modals/NodeModal";
import { useCallback } from "react";
import { TabsContext } from "../../contexts/tabsContext";
import { debounce } from "../../utils";
import Tooltip from "../../components/TooltipComponent";
export default function GenericNode({
data,
selected,
@ -27,7 +28,7 @@ export default function GenericNode({
const { types, deleteNode } = useContext(typesContext);
const { openPopUp } = useContext(PopUpContext);
const Icon = nodeIcons[types[data.type]];
const [validationStatus, setValidationStatus] = useState("idle");
const [validationStatus, setValidationStatus] = useState(null);
// State for outline color
const [isValid, setIsValid] = useState(false);
const { save } = useContext(TabsContext);
@ -53,9 +54,14 @@ export default function GenericNode({
});
if (response.status === 200) {
setValidationStatus("success");
} else if (response.status === 500) {
setValidationStatus("error");
let jsonResponse = await response.json();
let jsonResponseParsed = await JSON.parse(jsonResponse);
console.log(jsonResponseParsed);
if(jsonResponseParsed.valid){
setValidationStatus(jsonResponseParsed.params);
} else {
setValidationStatus("error");
}
}
} catch (error) {
// console.error("Error validating node:", error);
@ -71,7 +77,7 @@ export default function GenericNode({
}, [params, validateNode]);
useEffect(() => {
if (validationStatus === "success") {
if (validationStatus !== "error") {
setIsValid(true);
} else {
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 flex items-center truncate gap-4 text-lg">
<div className="w-full flex items-center truncate gap-2 text-lg">
<Icon
className="w-10 h-10 p-1 rounded"
style={{
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 className="flex gap-3">
<button
@ -134,7 +149,7 @@ export default function GenericNode({
)
? ""
: "hidden",
"w-6 h-6 dark:text-gray-500 hover:animate-spin"
"w-6 h-6 dark:text-gray-300 hover:animate-spin"
)}
></Cog6ToothIcon>
</button>
@ -143,13 +158,13 @@ export default function GenericNode({
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>
</div>
</div>
<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}
</div>

View file

@ -38,7 +38,7 @@ export default function InputComponent({
}}
/>
<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={() => {
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">
<span onClick={()=>{openPopUp(<TextAreaModal value={myValue} setValue={(t:string) => {setMyValue(t); onChange(t);}}/>)}}
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" : "")
}
>

View file

@ -57,18 +57,18 @@ export default function TabsManagerComponent() {
<div className="ml-auto mr-2 flex gap-3">
<button
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" />
</button>
<button
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" />
</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={() => {
setDark(!dark);
}}
@ -80,7 +80,7 @@ export default function TabsManagerComponent() {
)}
</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>) => {
setNotificationCenter(false);
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";
export type InputComponentType = {
value: string;
@ -68,7 +68,7 @@ export type FloatComponentType = {
export type TooltipComponentType = {
children: ReactElement;
title: string;
title: string | ReactElement;
placement?:
| "bottom-end"
| "bottom-start"