Add Error status to nodes that fail validateNodes

This commit is contained in:
Gabriel Luiz Freitas Almeida 2024-03-21 17:06:05 -03:00
commit b2c6f67a48
6 changed files with 42 additions and 14 deletions

View file

@ -275,7 +275,8 @@ export default function GenericNode({
name="Play" name="Play"
className="absolute ml-0.5 h-5 fill-current stroke-2 text-status-green opacity-30 transition-all group-hover:opacity-0" className="absolute ml-0.5 h-5 fill-current stroke-2 text-status-green opacity-30 transition-all group-hover:opacity-0"
/> />
) : validationStatus && !validationStatus.valid ? ( ) : buildStatus === BuildStatus.ERROR ||
(validationStatus && !validationStatus.valid) ? (
<Xmark <Xmark
isVisible={true} isVisible={true}
className="absolute ml-0.5 h-5 fill-current stroke-2 text-status-red opacity-100 transition-all group-hover:opacity-0" className="absolute ml-0.5 h-5 fill-current stroke-2 text-status-red opacity-100 transition-all group-hover:opacity-0"
@ -301,7 +302,10 @@ export default function GenericNode({
// INACTIVE should have its own class // INACTIVE should have its own class
return "inactive-status"; return "inactive-status";
} }
if (buildStatus === BuildStatus.BUILT && isInvalid) { if (
(buildStatus === BuildStatus.BUILT && isInvalid) ||
buildStatus === BuildStatus.ERROR
) {
return isDark ? "built-invalid-status-dark" : "built-invalid-status"; return isDark ? "built-invalid-status-dark" : "built-invalid-status";
} else if (buildStatus === BuildStatus.BUILDING) { } else if (buildStatus === BuildStatus.BUILDING) {
return "building-status"; return "building-status";

View file

@ -4,6 +4,7 @@ import Loading from "../../../components/ui/loading";
import { FlowType } from "../../../types/flow"; import { FlowType } from "../../../types/flow";
import { MISSED_ERROR_ALERT } from "../../../constants/alerts_constants"; import { MISSED_ERROR_ALERT } from "../../../constants/alerts_constants";
import { BuildStatus } from "../../../constants/enums";
import useAlertStore from "../../../stores/alertStore"; import useAlertStore from "../../../stores/alertStore";
import useFlowStore from "../../../stores/flowStore"; import useFlowStore from "../../../stores/flowStore";
import { validateNodes } from "../../../utils/reactflowUtils"; import { validateNodes } from "../../../utils/reactflowUtils";
@ -22,6 +23,7 @@ export default function BuildTrigger({
const buildFlow = useFlowStore((state) => state.buildFlow); const buildFlow = useFlowStore((state) => state.buildFlow);
const nodes = useFlowStore((state) => state.nodes); const nodes = useFlowStore((state) => state.nodes);
const edges = useFlowStore((state) => state.edges); const edges = useFlowStore((state) => state.edges);
const updateBuildStatus = useFlowStore((state) => state.updateBuildStatus);
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const eventClick = isBuilding ? "pointer-events-none" : ""; const eventClick = isBuilding ? "pointer-events-none" : "";
@ -32,12 +34,15 @@ export default function BuildTrigger({
if (isBuilding) { if (isBuilding) {
return; return;
} }
const errors = validateNodes(nodes, edges); const errorsObjs = validateNodes(nodes, edges);
const errors = errorsObjs.flatMap((errorObj) => errorObj.errors);
if (errors.length > 0) { if (errors.length > 0) {
setErrorData({ setErrorData({
title: MISSED_ERROR_ALERT, title: MISSED_ERROR_ALERT,
list: errors, list: errors,
}); });
const ids = errorsObjs.map((errorObj) => errorObj.id);
updateBuildStatus(ids, BuildStatus.ERROR);
return; return;
} }
const minimumLoadingTime = 200; // in milliseconds const minimumLoadingTime = 200; // in milliseconds

View file

@ -31,6 +31,7 @@ import {
CHAT_SECOND_INITIAL_TEXT, CHAT_SECOND_INITIAL_TEXT,
LANGFLOW_CHAT_TITLE, LANGFLOW_CHAT_TITLE,
} from "../../constants/constants"; } from "../../constants/constants";
import { BuildStatus } from "../../constants/enums";
import { AuthContext } from "../../contexts/authContext"; import { AuthContext } from "../../contexts/authContext";
import { getBuildStatus } from "../../controllers/API"; import { getBuildStatus } from "../../controllers/API";
import useAlertStore from "../../stores/alertStore"; import useAlertStore from "../../stores/alertStore";
@ -49,6 +50,7 @@ export default function FormModal({
}): JSX.Element { }): JSX.Element {
const nodes = useFlowStore((state) => state.nodes); const nodes = useFlowStore((state) => state.nodes);
const edges = useFlowStore((state) => state.edges); const edges = useFlowStore((state) => state.edges);
const updateBuildStatus = useFlowStore((state) => state.updateBuildStatus);
const flowState = useFlowStore((state) => state.flowState); const flowState = useFlowStore((state) => state.flowState);
const setFlowState = useFlowStore((state) => state.setFlowState); const setFlowState = useFlowStore((state) => state.setFlowState);
const [chatValue, setChatValue] = useState(() => { const [chatValue, setChatValue] = useState(() => {
@ -388,7 +390,8 @@ export default function FormModal({
function sendMessage(): void { function sendMessage(): void {
let nodeValidationErrors = validateNodes(nodes, edges); let nodeValidationErrors = validateNodes(nodes, edges);
if (nodeValidationErrors.length === 0) { const errors = nodeValidationErrors.flatMap((error) => error.errors);
if (errors.length === 0) {
setLockChat(true); setLockChat(true);
let inputs = flowState?.input_keys; let inputs = flowState?.input_keys;
setChatValue(""); setChatValue("");
@ -412,8 +415,10 @@ export default function FormModal({
} else { } else {
setErrorData({ setErrorData({
title: INFO_MISSING_ALERT, title: INFO_MISSING_ALERT,
list: nodeValidationErrors, list: errors,
}); });
const ids = nodeValidationErrors.map((error) => error.id);
updateBuildStatus(ids, BuildStatus.ERROR);
} }
} }
function clearChat(): void { function clearChat(): void {

View file

@ -438,16 +438,20 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
const setErrorData = useAlertStore.getState().setErrorData; const setErrorData = useAlertStore.getState().setErrorData;
const setNoticeData = useAlertStore.getState().setNoticeData; const setNoticeData = useAlertStore.getState().setNoticeData;
function validateSubgraph(nodes: string[]) { function validateSubgraph(nodes: string[]) {
const errors = validateNodes( const errorsObjs = validateNodes(
get().nodes.filter((node) => nodes.includes(node.id)), get().nodes.filter((node) => nodes.includes(node.id)),
get().edges get().edges
); );
const errors = errorsObjs.map((obj) => obj.errors).flat();
if (errors.length > 0) { if (errors.length > 0) {
setErrorData({ setErrorData({
title: MISSED_ERROR_ALERT, title: MISSED_ERROR_ALERT,
list: errors, list: errors,
}); });
get().setIsBuilding(false); get().setIsBuilding(false);
const ids = errorsObjs.map((obj) => obj.id).flat();
console.log("ids", ids);
get().updateBuildStatus(ids, BuildStatus.ERROR);
throw new Error("Invalid nodes"); throw new Error("Invalid nodes");
} }
} }
@ -538,7 +542,7 @@ const useFlowStore = create<FlowStoreType>((set, get) => ({
.filter(Boolean) as string[]; .filter(Boolean) as string[];
useFlowStore.getState().updateBuildStatus(idList, BuildStatus.BUILDING); useFlowStore.getState().updateBuildStatus(idList, BuildStatus.BUILDING);
}, },
validateNodes: validateSubgraph, onValidateNodes: validateSubgraph,
}); });
get().setIsBuilding(false); get().setIsBuilding(false);
get().revertBuiltStatusFromBuilding(); get().revertBuiltStatusFromBuilding();

View file

@ -20,7 +20,7 @@ type BuildVerticesParams = {
onBuildComplete?: (allNodesValid: boolean) => void; onBuildComplete?: (allNodesValid: boolean) => void;
onBuildError?: (title, list, idList: VertexLayerElementType[]) => void; onBuildError?: (title, list, idList: VertexLayerElementType[]) => void;
onBuildStart?: (idList: VertexLayerElementType[]) => void; onBuildStart?: (idList: VertexLayerElementType[]) => void;
validateNodes?: (nodes: string[]) => void; onValidateNodes?: (nodes: string[]) => void;
}; };
function getInactiveVertexData(vertexId: string): VertexBuildTypeAPI { function getInactiveVertexData(vertexId: string): VertexBuildTypeAPI {
@ -114,7 +114,7 @@ export async function buildVertices({
onBuildComplete, onBuildComplete,
onBuildError, onBuildError,
onBuildStart, onBuildStart,
validateNodes, onValidateNodes,
}: BuildVerticesParams) { }: BuildVerticesParams) {
let verticesBuild = useFlowStore.getState().verticesBuild; let verticesBuild = useFlowStore.getState().verticesBuild;
// if startNodeId and stopNodeId are provided // if startNodeId and stopNodeId are provided
@ -133,10 +133,10 @@ export async function buildVertices({
if (onGetOrderSuccess) onGetOrderSuccess(); if (onGetOrderSuccess) onGetOrderSuccess();
if (validateNodes) { if (onValidateNodes) {
try { try {
const nodes = useFlowStore.getState().nodes; const nodes = useFlowStore.getState().nodes;
validateNodes(nodes.map((node) => node.id)); onValidateNodes(nodes.map((node) => node.id));
} catch (e) { } catch (e) {
return; return;
} }

View file

@ -330,13 +330,23 @@ export function validateNode(node: NodeType, edges: Edge[]): Array<string> {
}, [] as string[]); }, [] as string[]);
} }
export function validateNodes(nodes: Node[], edges: Edge[]) { export function validateNodes(
nodes: Node[],
edges: Edge[]
): // this returns an array of tuples with the node id and the errors
Array<{ id: string; errors: Array<string> }> {
if (nodes.length === 0) { if (nodes.length === 0) {
return [ return [
{
id: "",
errors: [
"No nodes found in the flow. Please add at least one node to the flow.", "No nodes found in the flow. Please add at least one node to the flow.",
],
},
]; ];
} }
return nodes.flatMap((n: NodeType) => validateNode(n, edges)); // validateNode(n, edges) returns an array of errors for the node
return nodes.map((n) => ({ id: n.id, errors: validateNode(n, edges) }));
} }
export function updateEdges(edges: Edge[]) { export function updateEdges(edges: Edge[]) {