fix(validate.py): raise an exception with a message when node is not found
feat(GenericNode): add node validation with outline color feedback feat(tailwind.config.js): add styles for outline colors and animations
This commit is contained in:
parent
09320824a9
commit
f122151b12
3 changed files with 100 additions and 33 deletions
|
|
@ -47,7 +47,7 @@ def post_validate_node(node_id: str, data: dict):
|
||||||
if node is not None:
|
if node is not None:
|
||||||
_ = node.build()
|
_ = node.build()
|
||||||
return node.params
|
return node.params
|
||||||
raise
|
raise Exception(f"Node {node_id} not found")
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.exception(e)
|
logger.exception(e)
|
||||||
raise HTTPException(status_code=500, detail=str(e)) from e
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
||||||
|
|
|
||||||
|
|
@ -7,9 +7,10 @@ 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, useRef } from "react";
|
import { useContext, useState, useEffect, useRef } from "react";
|
||||||
import { NodeDataType } from "../../types/flow";
|
import { NodeDataType } from "../../types/flow";
|
||||||
import { alertContext } from "../../contexts/alertContext";
|
import { alertContext } from "../../contexts/alertContext";
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
export default function GenericNode({
|
export default function GenericNode({
|
||||||
data,
|
data,
|
||||||
|
|
@ -22,6 +23,53 @@ export default function GenericNode({
|
||||||
const showError = useRef(true);
|
const showError = useRef(true);
|
||||||
const { types, deleteNode } = useContext(typesContext);
|
const { types, deleteNode } = useContext(typesContext);
|
||||||
const Icon = nodeIcons[types[data.type]];
|
const Icon = nodeIcons[types[data.type]];
|
||||||
|
|
||||||
|
// State for outline color
|
||||||
|
const [isGreenOutline, setIsGreenOutline] = useState(false);
|
||||||
|
const [isRedOutline, setIsRedOutline] = useState(false);
|
||||||
|
const { reactFlowInstance } = useContext(typesContext);
|
||||||
|
|
||||||
|
const validateNode = useCallback(async () => {
|
||||||
|
try {
|
||||||
|
const response = await fetch(`/validate/node/${data.id}`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
},
|
||||||
|
body: JSON.stringify(reactFlowInstance.toObject()),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status === 200) {
|
||||||
|
setIsGreenOutline(true);
|
||||||
|
setIsRedOutline(false);
|
||||||
|
} else if (response.status === 500) {
|
||||||
|
setIsRedOutline(true);
|
||||||
|
setIsGreenOutline(false);
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Error validating node:', error);
|
||||||
|
setIsRedOutline(true);
|
||||||
|
}
|
||||||
|
}, [data.id, reactFlowInstance]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
validateNode();
|
||||||
|
}, [
|
||||||
|
validateNode,
|
||||||
|
...Object.values(data.node.template).flatMap((t) => Object.values(t)),
|
||||||
|
|
||||||
|
]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isGreenOutline) {
|
||||||
|
setTimeout(() => {
|
||||||
|
setIsGreenOutline(false);
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}, [isGreenOutline]);
|
||||||
|
|
||||||
|
const outlineColor = isGreenOutline ? 'animate-pulse-green' : isRedOutline ? 'border-red-outline' : '';
|
||||||
|
|
||||||
if (!Icon) {
|
if (!Icon) {
|
||||||
if (showError.current) {
|
if (showError.current) {
|
||||||
setErrorData({
|
setErrorData({
|
||||||
|
|
@ -34,9 +82,11 @@ export default function GenericNode({
|
||||||
deleteNode(data.id);
|
deleteNode(data.id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
outlineColor,
|
||||||
selected ? "border border-blue-500" : "border dark:border-gray-700",
|
selected ? "border border-blue-500" : "border dark:border-gray-700",
|
||||||
"prompt-node relative bg-white dark:bg-gray-900 w-96 rounded-lg flex flex-col justify-center"
|
"prompt-node relative bg-white dark:bg-gray-900 w-96 rounded-lg flex flex-col justify-center"
|
||||||
)}
|
)}
|
||||||
|
|
|
||||||
|
|
@ -1,45 +1,62 @@
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
const plugin = require('tailwindcss/plugin')
|
const plugin = require("tailwindcss/plugin");
|
||||||
module.exports = {
|
module.exports = {
|
||||||
content: ["./src/**/*.{js,ts,tsx,jsx}"],
|
content: ["./src/**/*.{js,ts,tsx,jsx}"],
|
||||||
darkMode: 'class',
|
darkMode: "class",
|
||||||
important: true,
|
important: true,
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {
|
||||||
|
borderColor: {
|
||||||
|
"red-outline": "rgba(255, 0, 0, 0.8)",
|
||||||
|
"green-outline": "rgba(72, 187, 120, 0.7)",
|
||||||
|
},
|
||||||
|
boxShadow: {
|
||||||
|
"red-outline": "0 0 5px rgba(255, 0, 0, 0.5)",
|
||||||
|
"green-outline": "0 0 5px rgba(72, 187, 120, 0.7)",
|
||||||
|
},
|
||||||
|
|
||||||
|
animation: {
|
||||||
|
"pulse-green": "pulseGreen 1s linear",
|
||||||
|
},
|
||||||
|
keyframes: {
|
||||||
|
pulseGreen: {
|
||||||
|
"0%": { boxShadow: "0 0 0 0 rgba(72, 187, 120, 0.7)" },
|
||||||
|
"100%": { boxShadow: "0 0 0 10px rgba(72, 187, 120, 0)" },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
require("@tailwindcss/forms")({
|
require("@tailwindcss/forms")({
|
||||||
strategy: 'class', // only generate classes
|
strategy: "class", // only generate classes
|
||||||
}),
|
}),
|
||||||
plugin(function ({ addUtilities }) {
|
plugin(function ({ addUtilities }) {
|
||||||
addUtilities({
|
addUtilities({
|
||||||
'.scrollbar-hide': {
|
".scrollbar-hide": {
|
||||||
/* IE and Edge */
|
/* IE and Edge */
|
||||||
'-ms-overflow-style': 'none',
|
"-ms-overflow-style": "none",
|
||||||
/* Firefox */
|
/* Firefox */
|
||||||
'scrollbar-width': 'none',
|
"scrollbar-width": "none",
|
||||||
/* Safari and Chrome */
|
/* Safari and Chrome */
|
||||||
'&::-webkit-scrollbar': {
|
"&::-webkit-scrollbar": {
|
||||||
display: 'none'
|
display: "none",
|
||||||
}
|
|
||||||
},
|
|
||||||
'.arrow-hide':{
|
|
||||||
'&::-webkit-inner-spin-button':{
|
|
||||||
'-webkit-appearance': 'none',
|
|
||||||
'margin': 0
|
|
||||||
},
|
|
||||||
'&::-webkit-outer-spin-button':{
|
|
||||||
'-webkit-appearance': 'none',
|
|
||||||
'margin': 0
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'.password':{
|
".arrow-hide": {
|
||||||
|
"&::-webkit-inner-spin-button": {
|
||||||
|
"-webkit-appearance": "none",
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
"&::-webkit-outer-spin-button": {
|
||||||
|
"-webkit-appearance": "none",
|
||||||
|
margin: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
".password": {
|
||||||
"-webkit-text-security": "disc",
|
"-webkit-text-security": "disc",
|
||||||
"font-family": "text-security-disc"
|
"font-family": "text-security-disc",
|
||||||
|
},
|
||||||
}
|
});
|
||||||
}
|
}),
|
||||||
)
|
|
||||||
})
|
|
||||||
],
|
],
|
||||||
}
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue