Get data from Validate Nodes and display it on Tooltip
This commit is contained in:
parent
8810a0392a
commit
b8c95fb7ec
6 changed files with 39 additions and 23 deletions
|
|
@ -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
|
|
||||||
|
|
|
||||||
|
|
@ -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,9 +54,14 @@ 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);
|
||||||
setValidationStatus("error");
|
console.log(jsonResponseParsed);
|
||||||
|
if(jsonResponseParsed.valid){
|
||||||
|
setValidationStatus(jsonResponseParsed.params);
|
||||||
|
} else {
|
||||||
|
setValidationStatus("error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// console.error("Error validating node:", error);
|
// console.error("Error validating node:", 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>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
}}
|
}}
|
||||||
|
|
|
||||||
|
|
@ -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" : "")
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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"
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue