Fixed state handling of Prompt Component, undo working

This commit is contained in:
Lucas Oliveira 2023-12-09 00:33:51 -03:00
commit 82ef6bc72a
7 changed files with 55 additions and 50 deletions

View file

@ -31,9 +31,11 @@ import { FlowsContext } from "../../../../contexts/flowsContext";
import { typesContext } from "../../../../contexts/typesContext"; import { typesContext } from "../../../../contexts/typesContext";
import { undoRedoContext } from "../../../../contexts/undoRedoContext"; import { undoRedoContext } from "../../../../contexts/undoRedoContext";
import { postCustomComponentUpdate } from "../../../../controllers/API"; import { postCustomComponentUpdate } from "../../../../controllers/API";
import { APIClassType } from "../../../../types/api";
import { ParameterComponentType } from "../../../../types/components"; import { ParameterComponentType } from "../../../../types/components";
import { NodeDataType } from "../../../../types/flow"; import { NodeDataType } from "../../../../types/flow";
import { import {
cleanEdges,
convertObjToArray, convertObjToArray,
convertValuesToNumbers, convertValuesToNumbers,
hasDuplicateKeys, hasDuplicateKeys,
@ -69,7 +71,8 @@ export default function ParameterComponent({
const { setErrorData } = useContext(alertContext); const { setErrorData } = useContext(alertContext);
const updateNodeInternals = useUpdateNodeInternals(); const updateNodeInternals = useUpdateNodeInternals();
const [position, setPosition] = useState(0); const [position, setPosition] = useState(0);
const { setTabsState, tabId, flows, tabsState } = useContext(FlowsContext); const { setTabsState, tabId, flows, tabsState, updateFlow } =
useContext(FlowsContext);
const flow = flows.find((flow) => flow.id === tabId)?.data?.nodes ?? null; const flow = flows.find((flow) => flow.id === tabId)?.data?.nodes ?? null;
@ -139,6 +142,40 @@ export default function ParameterComponent({
renderTooltips(); renderTooltips();
}; };
const handleNodeClass = (newNodeClass: APIClassType, code?: string): void => {
if (data.node!.template[name].value !== newNodeClass.template[name].value) {
takeSnapshot();
}
data.node = newNodeClass;
data.node.template[name].value = code;
updateNodeInternals(data.id);
// Set state to pending
//@ts-ignore
if (data.node!.template[name].value !== code) {
const tabs = cloneDeep(tabsState);
tabs[tabId].isPending = false;
tabs[tabId].formKeysData = tabsState[tabId].formKeysData;
setTabsState({
...tabs,
});
}
renderTooltips();
let flow = flows.find((flow) => flow.id === tabId);
if (reactFlowInstance && flow && flow.data) {
cleanEdges({
flow: {
edges: flow.data!.edges,
nodes: flow.data!.nodes,
},
updateEdge: (edge) => {
reactFlowInstance.setEdges(edge);
updateNodeInternals(data.id);
},
});
updateFlow(flow);
}
};
const [errorDuplicateKey, setErrorDuplicateKey] = useState(false); const [errorDuplicateKey, setErrorDuplicateKey] = useState(false);
useEffect(() => { useEffect(() => {
@ -443,9 +480,7 @@ export default function ParameterComponent({
: false : false
} }
dynamic={data.node?.template[name].dynamic ?? false} dynamic={data.node?.template[name].dynamic ?? false}
setNodeClass={(nodeClass) => { setNodeClass={handleNodeClass}
data.node = nodeClass;
}}
nodeClass={data.node} nodeClass={data.node}
disabled={disabled} disabled={disabled}
value={data.node?.template[name].value ?? ""} value={data.node?.template[name].value ?? ""}
@ -479,15 +514,11 @@ export default function ParameterComponent({
<PromptAreaComponent <PromptAreaComponent
readonly={data.node?.flow ? true : false} readonly={data.node?.flow ? true : false}
field_name={name} field_name={name}
setNodeClass={(nodeClass) => { setNodeClass={handleNodeClass}
data.node = nodeClass;
}}
nodeClass={data.node} nodeClass={data.node}
disabled={disabled} disabled={disabled}
value={data.node?.template[name].value ?? ""} value={data.node?.template[name].value ?? ""}
onChange={(e) => { onChange={handleOnNewValue}
handleOnNewValue(e);
}}
id={"prompt-input-" + index} id={"prompt-input-" + index}
data-testid={"prompt-input-" + index} data-testid={"prompt-input-" + index}
/> />

View file

@ -14,11 +14,7 @@ import { undoRedoContext } from "../../contexts/undoRedoContext";
import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent"; import NodeToolbarComponent from "../../pages/FlowPage/components/nodeToolbarComponent";
import { validationStatusType } from "../../types/components"; import { validationStatusType } from "../../types/components";
import { NodeDataType } from "../../types/flow"; import { NodeDataType } from "../../types/flow";
import { import { handleKeyDown, scapedJSONStringfy } from "../../utils/reactflowUtils";
cleanEdges,
handleKeyDown,
scapedJSONStringfy,
} from "../../utils/reactflowUtils";
import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils"; import { nodeColors, nodeIconsLucide } from "../../utils/styleUtils";
import { classNames, getFieldTitle } from "../../utils/utils"; import { classNames, getFieldTitle } from "../../utils/utils";
import ParameterComponent from "./components/parameterComponent"; import ParameterComponent from "./components/parameterComponent";
@ -85,27 +81,10 @@ export default function GenericNode({
useEffect(() => { useEffect(() => {
countHandles(); countHandles();
}, []); }, [data, data.node]);
// State for outline color // State for outline color
const { sseData, isBuilding } = useSSE(); const { sseData, isBuilding } = useSSE();
useEffect(() => {
let flow = flows.find((flow) => flow.id === tabId);
if (reactFlowInstance && flow && flow.data) {
cleanEdges({
flow: {
edges: flow.data!.edges,
nodes: flow.data!.nodes,
},
updateEdge: (edge) => {
reactFlowInstance.setEdges(edge);
updateNodeInternals(data.id);
},
});
updateFlow(flow);
}
countHandles();
}, [modalContextOpen]);
useEffect(() => { useEffect(() => {
setNodeDescription(data.node!.description); setNodeDescription(data.node!.description);

View file

@ -31,9 +31,7 @@ export default function PromptAreaComponent({
value={value} value={value}
buttonText="Check & Save" buttonText="Check & Save"
modalTitle="Edit Prompt" modalTitle="Edit Prompt"
setValue={(value: string) => { setValue={onChange}
onChange(value);
}}
nodeClass={nodeClass} nodeClass={nodeClass}
setNodeClass={setNodeClass} setNodeClass={setNodeClass}
> >

View file

@ -150,9 +150,9 @@ const EditNodeModal = forwardRef(
.map((templateParam, index) => { .map((templateParam, index) => {
let id = { let id = {
inputTypes: inputTypes:
data.node!.template[templateParam].input_types, myData.node!.template[templateParam].input_types,
type: data.node!.template[templateParam].type, type: myData.node!.template[templateParam].type,
id: data.id, id: myData.id,
fieldName: templateParam, fieldName: templateParam,
}; };
let disabled = let disabled =
@ -160,11 +160,11 @@ const EditNodeModal = forwardRef(
(edge) => (edge) =>
edge.targetHandle === edge.targetHandle ===
scapedJSONStringfy( scapedJSONStringfy(
data.node!.template[templateParam].proxy myData.node!.template[templateParam].proxy
? { ? {
...id, ...id,
proxy: proxy:
data.node?.template[templateParam] myData.node?.template[templateParam]
.proxy, .proxy,
} }
: id : id

View file

@ -88,8 +88,7 @@ export default function CodeAreaModal({
.then((apiReturn) => { .then((apiReturn) => {
const { data } = apiReturn; const { data } = apiReturn;
if (data) { if (data) {
setNodeClass(data); setNodeClass(data, code);
setValue(code);
setError({ detail: { error: undefined, traceback: undefined } }); setError({ detail: { error: undefined, traceback: undefined } });
setOpen(false); setOpen(false);
} }

View file

@ -114,7 +114,6 @@ export default function GenericModal({
// if field_name is an empty string, then we need to set it // if field_name is an empty string, then we need to set it
// to the first key of the custom_fields object // to the first key of the custom_fields object
if (field_name === "") { if (field_name === "") {
console.log(apiReturn.data?.frontend_node?.custom_fields);
field_name = Array.isArray( field_name = Array.isArray(
apiReturn.data?.frontend_node?.custom_fields?.[""] apiReturn.data?.frontend_node?.custom_fields?.[""]
) )
@ -134,9 +133,8 @@ export default function GenericModal({
JSON.stringify(apiReturn.data?.frontend_node) !== JSON.stringify(apiReturn.data?.frontend_node) !==
JSON.stringify({}) JSON.stringify({})
) { ) {
setNodeClass!(apiReturn.data?.frontend_node); setNodeClass!(apiReturn.data?.frontend_node, inputValue);
setModalOpen(closeModal); setModalOpen(closeModal);
setValue(inputValue);
setIsEdit(false); setIsEdit(false);
setSuccessData({ setSuccessData({
title: "Prompt is ready", title: "Prompt is ready",

View file

@ -95,7 +95,7 @@ export type TextAreaComponentType = {
export type PromptAreaComponentType = { export type PromptAreaComponentType = {
field_name?: string; field_name?: string;
nodeClass?: APIClassType; nodeClass?: APIClassType;
setNodeClass?: (value: APIClassType) => void; setNodeClass?: (value: APIClassType, code?: string) => void;
disabled: boolean; disabled: boolean;
onChange: (value: string[] | string) => void; onChange: (value: string[] | string) => void;
value: string; value: string;
@ -110,7 +110,7 @@ export type CodeAreaComponentType = {
value: string; value: string;
editNode?: boolean; editNode?: boolean;
nodeClass?: APIClassType; nodeClass?: APIClassType;
setNodeClass?: (value: APIClassType) => void; setNodeClass?: (value: APIClassType, code?: string) => void;
dynamic?: boolean; dynamic?: boolean;
id?: string; id?: string;
readonly?: boolean; readonly?: boolean;
@ -500,7 +500,7 @@ export type codeAreaModalPropsType = {
setValue: (value: string) => void; setValue: (value: string) => void;
value: string; value: string;
nodeClass: APIClassType | undefined; nodeClass: APIClassType | undefined;
setNodeClass: (Class: APIClassType) => void | undefined; setNodeClass: (Class: APIClassType, code?: string) => void | undefined;
children: ReactNode; children: ReactNode;
dynamic?: boolean; dynamic?: boolean;
readonly?: boolean; readonly?: boolean;
@ -526,7 +526,7 @@ export type genericModalPropsType = {
modalTitle: string; modalTitle: string;
type: number; type: number;
nodeClass?: APIClassType; nodeClass?: APIClassType;
setNodeClass?: (Class: APIClassType) => void; setNodeClass?: (Class: APIClassType, code?: string) => void;
children: ReactNode; children: ReactNode;
id?: string; id?: string;
readonly?: boolean; readonly?: boolean;