update template working for local flow on browser

This commit is contained in:
anovazzi1 2023-04-27 19:24:02 -03:00
commit d91beb9cda
7 changed files with 109 additions and 81 deletions

View file

@ -59,5 +59,5 @@
"last 1 safari version" "last 1 safari version"
] ]
}, },
"proxy": "http://backend:7860" "proxy": "http://127.0.0.1:5003"
} }

View file

@ -1,12 +1,20 @@
import { createContext, useEffect, useState, useRef, ReactNode, useContext } from "react"; import {
createContext,
useEffect,
useState,
useRef,
ReactNode,
useContext,
} from "react";
import { FlowType } from "../types/flow"; import { FlowType } from "../types/flow";
import { LangFlowState, TabsContextType } from "../types/tabs"; import { LangFlowState, TabsContextType } from "../types/tabs";
import { normalCaseToSnakeCase } from "../utils"; import { normalCaseToSnakeCase, updateObject } from "../utils";
import { alertContext } from "./alertContext"; import { alertContext } from "./alertContext";
import { typesContext } from "./typesContext"; import { typesContext } from "./typesContext";
import { TemplateVariableType } from "../types/api";
const TabsContextInitialValue: TabsContextType = { const TabsContextInitialValue: TabsContextType = {
save:()=>{}, save: () => {},
tabIndex: 0, tabIndex: 0,
setTabIndex: (index: number) => {}, setTabIndex: (index: number) => {},
flows: [], flows: [],
@ -14,11 +22,11 @@ const TabsContextInitialValue: TabsContextType = {
addFlow: (flowData?: any) => {}, addFlow: (flowData?: any) => {},
updateFlow: (newFlow: FlowType) => {}, updateFlow: (newFlow: FlowType) => {},
incrementNodeId: () => 0, incrementNodeId: () => 0,
downloadFlow: (flow:FlowType) => {}, downloadFlow: (flow: FlowType) => {},
uploadFlow: () => {}, uploadFlow: () => {},
lockChat: false, lockChat: false,
setLockChat:(prevState:boolean)=>{}, setLockChat: (prevState: boolean) => {},
hardReset:()=>{}, hardReset: () => {},
}; };
export const TabsContext = createContext<TabsContextType>( export const TabsContext = createContext<TabsContextType>(
@ -26,61 +34,64 @@ export const TabsContext = createContext<TabsContextType>(
); );
export function TabsProvider({ children }: { children: ReactNode }) { export function TabsProvider({ children }: { children: ReactNode }) {
const {setNoticeData} = useContext(alertContext) const { setNoticeData } = useContext(alertContext);
const [tabIndex, setTabIndex] = useState(0); const [tabIndex, setTabIndex] = useState(0);
const [flows, setFlows] = useState<Array<FlowType>>([]); const [flows, setFlows] = useState<Array<FlowType>>([]);
const [id, setId] = useState(0); const [id, setId] = useState(0);
const [lockChat, setLockChat] = useState(false); const [lockChat, setLockChat] = useState(false);
const {templates} = useContext(typesContext ) const { templates } = useContext(typesContext);
const newNodeId = useRef(0); const newNodeId = useRef(0);
function incrementNodeId() { function incrementNodeId() {
newNodeId.current = newNodeId.current + 1; newNodeId.current = newNodeId.current + 1;
return newNodeId.current; return newNodeId.current;
} }
function save(){ function save() {
console.log("save") console.log("save");
if (flows.length !== 0) if (flows.length !== 0)
window.localStorage.setItem( window.localStorage.setItem(
"tabsData", "tabsData",
JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current }) JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current })
); );
} }
useEffect(() => { useEffect(() => {
//save tabs locally //save tabs locally
save() save();
}, [flows, id, tabIndex, newNodeId]); }, [flows, id, tabIndex, newNodeId]);
useEffect(() => { useEffect(() => {
//get tabs locally saved //get tabs locally saved
let cookie = window.localStorage.getItem("tabsData"); let cookie = window.localStorage.getItem("tabsData");
if (cookie) { if (cookie && Object.keys(templates).length > 0) {
console.log(templates) let cookieObject: LangFlowState = JSON.parse(cookie);
console.log(Object.keys(templates).length) cookieObject.flows.forEach((flow) => {
let cookieObject:LangFlowState = JSON.parse(cookie); flow.data.nodes.forEach((node) => {
cookieObject.flows.forEach(flow=>{ node.data.node.template = updateObject(
console.log(flow) node.data.node.template as TemplateVariableType,
// flow.data.nodes.forEach(node=>{ templates[node.data.type][
// console.log(node.data) "template"
// }) ] as unknown as TemplateVariableType
}) );
console.log(node)
});
});
setTabIndex(cookieObject.tabIndex); setTabIndex(cookieObject.tabIndex);
setFlows(cookieObject.flows); setFlows(cookieObject.flows);
setId(cookieObject.id); setId(cookieObject.id);
newNodeId.current = cookieObject.nodeId; newNodeId.current = cookieObject.nodeId;
} }
}, [templates]); }, [templates]);
function hardReset(){ function hardReset() {
newNodeId.current=0; newNodeId.current = 0;
setTabIndex(0);setFlows([]);setId(0); setTabIndex(0);
setFlows([]);
setId(0);
} }
/** /**
* Downloads the current flow as a JSON file * Downloads the current flow as a JSON file
*/ */
function downloadFlow(flow:FlowType) { function downloadFlow(flow: FlowType) {
// create a data URI with the current flow data // create a data URI with the current flow data
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
JSON.stringify(flow) JSON.stringify(flow)
@ -93,7 +104,9 @@ export function TabsProvider({ children }: { children: ReactNode }) {
// simulate a click on the link element to trigger the download // simulate a click on the link element to trigger the download
link.click(); link.click();
setNoticeData({title:"Warning: Critical data,JSON file may including API keys."}) setNoticeData({
title: "Warning: Critical data,JSON file may including API keys.",
});
} }
/** /**
@ -150,7 +163,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
function addFlow(flow?: FlowType) { function addFlow(flow?: FlowType) {
// Get data from the flow or set it to null if there's no flow provided. // Get data from the flow or set it to null if there's no flow provided.
const data = flow?.data ? flow.data : null; const data = flow?.data ? flow.data : null;
const description = flow?.description?flow.description:"" const description = flow?.description ? flow.description : "";
// Create a new flow with a default name if no flow is provided. // Create a new flow with a default name if no flow is provided.
let newFlow: FlowType = { let newFlow: FlowType = {
@ -182,7 +195,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
const newFlows = [...prevState]; const newFlows = [...prevState];
const index = newFlows.findIndex((flow) => flow.id === newFlow.id); const index = newFlows.findIndex((flow) => flow.id === newFlow.id);
if (index !== -1) { if (index !== -1) {
newFlows[index].description = newFlow.description??"" newFlows[index].description = newFlow.description ?? "";
newFlows[index].data = newFlow.data; newFlows[index].data = newFlow.data;
newFlows[index].name = newFlow.name; newFlows[index].name = newFlow.name;
newFlows[index].chat = newFlow.chat; newFlows[index].chat = newFlow.chat;

View file

@ -1,6 +1,8 @@
import { createContext, ReactNode, useState } from "react"; import { createContext, ReactNode, useEffect, useState } from "react";
import { Node} from "reactflow"; import { Node} from "reactflow";
import { typesContextType } from "../types/typesContext"; import { typesContextType } from "../types/typesContext";
import { getAll } from "../controllers/API";
import { APIKindType } from "../types/api";
//context to share types adn functions from nodes to flow //context to share types adn functions from nodes to flow
@ -23,6 +25,40 @@ export function TypesProvider({ children }:{children:ReactNode}) {
const [reactFlowInstance, setReactFlowInstance] = useState(null); const [reactFlowInstance, setReactFlowInstance] = useState(null);
const [templates, setTemplates] = useState({}); const [templates, setTemplates] = useState({});
const [data, setData] = useState({}); const [data, setData] = useState({});
useEffect(() => {
async function getTypes(): Promise<void> {
// Make an asynchronous API call to retrieve all data.
let result = await getAll();
// Update the state of the component with the retrieved data.
setData(result.data);
setTemplates(
Object.keys(result.data).reduce((acc, curr) => {
Object.keys(result.data[curr]).forEach((c: keyof APIKindType)=>{
acc[c] = result.data[curr][c]
})
return acc;
},{})
);
// Set the types by reducing over the keys of the result data and updating the accumulator.
setTypes(
Object.keys(result.data).reduce((acc, curr) => {
Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => {
acc[c] = curr;
// Add the base classes to the accumulator as well.
result.data[curr][c].base_classes?.forEach((b) => {
acc[b] = curr;
});
});
return acc;
}, {})
);
}
// Call the getTypes function.
getTypes();
}, [setTypes]);
function deleteNode(idx:string) { function deleteNode(idx:string) {
reactFlowInstance.setNodes( reactFlowInstance.setNodes(
reactFlowInstance.getNodes().filter((n:Node) => n.id !== idx) reactFlowInstance.getNodes().filter((n:Node) => n.id !== idx)

View file

@ -2,51 +2,14 @@ import { Bars2Icon } from "@heroicons/react/24/outline";
import DisclosureComponent from "../DisclosureComponent"; import DisclosureComponent from "../DisclosureComponent";
import { nodeColors, nodeIcons, nodeNames } from "../../../../utils"; import { nodeColors, nodeIcons, nodeNames } from "../../../../utils";
import { useContext, useEffect, useState } from "react"; import { useContext, useEffect, useState } from "react";
import { getAll } from "../../../../controllers/API";
import { typesContext } from "../../../../contexts/typesContext"; import { typesContext } from "../../../../contexts/typesContext";
import { import {
APIClassType, APIClassType,
APIKindType,
APIObjectType, APIObjectType,
} from "../../../../types/api"; } from "../../../../types/api";
export default function ExtraSidebar() { export default function ExtraSidebar() {
const [data, setData] = useState({}); const {data} = useContext(typesContext)
const { setTypes } = useContext(typesContext);
const { setTemplates } = useContext(typesContext);
useEffect(() => {
async function getTypes(): Promise<void> {
// Make an asynchronous API call to retrieve all data.
let result = await getAll();
// Update the state of the component with the retrieved data.
setData(result.data);
setTemplates(
Object.keys(result.data).reduce((acc, curr) => {
Object.keys(result.data[curr]).forEach((c: keyof APIKindType)=>{
acc[c] = result.data[curr][c]
})
return acc;
},{})
);
// Set the types by reducing over the keys of the result data and updating the accumulator.
setTypes(
Object.keys(result.data).reduce((acc, curr) => {
Object.keys(result.data[curr]).forEach((c: keyof APIKindType) => {
acc[c] = curr;
// Add the base classes to the accumulator as well.
result.data[curr][c].base_classes?.forEach((b) => {
acc[b] = curr;
});
});
return acc;
}, {})
);
}
// Call the getTypes function.
getTypes();
}, [setTypes]);
function onDragStart( function onDragStart(
event: React.DragEvent<any>, event: React.DragEvent<any>,

View file

@ -16,21 +16,23 @@ import AlertDropdown from "../../../../alerts/alertDropDown";
import { alertContext } from "../../../../contexts/alertContext"; import { alertContext } from "../../../../contexts/alertContext";
import ImportModal from "../../../../modals/importModal"; import ImportModal from "../../../../modals/importModal";
import ExportModal from "../../../../modals/exportModal"; import ExportModal from "../../../../modals/exportModal";
import { typesContext } from "../../../../contexts/typesContext";
export default function TabsManagerComponent() { export default function TabsManagerComponent() {
const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } = const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } =
useContext(TabsContext); useContext(TabsContext);
const { openPopUp } = useContext(PopUpContext); const { openPopUp } = useContext(PopUpContext);
const {templates} = useContext(typesContext)
const AlertWidth = 256; const AlertWidth = 256;
const { dark, setDark } = useContext(darkContext); const { dark, setDark } = useContext(darkContext);
const { notificationCenter, setNotificationCenter } = const { notificationCenter, setNotificationCenter } =
useContext(alertContext); useContext(alertContext);
useEffect(() => { useEffect(() => {
//create the first flow //create the first flow
if (flows.length === 0) { if (flows.length === 0&& Object.keys(templates).length>0) {
addFlow(); addFlow();
} }
}, [addFlow, flows.length]); }, [addFlow, flows.length,templates]);
return ( return (
<div className="h-full w-full flex flex-col"> <div className="h-full w-full flex flex-col">

View file

@ -32,7 +32,7 @@ var _ = require("lodash");
export default function FlowPage({ flow }:{flow:FlowType}) { export default function FlowPage({ flow }:{flow:FlowType}) {
let { updateFlow, incrementNodeId} = let { updateFlow, incrementNodeId} =
useContext(TabsContext); useContext(TabsContext);
const { types, reactFlowInstance, setReactFlowInstance } = const { types, reactFlowInstance, setReactFlowInstance, templates } =
useContext(typesContext); useContext(typesContext);
const reactFlowWrapper = useRef(null); const reactFlowWrapper = useRef(null);
@ -180,7 +180,7 @@ export default function FlowPage({ flow }:{flow:FlowType}) {
return ( return (
<div className="w-full h-full" ref={reactFlowWrapper}> <div className="w-full h-full" ref={reactFlowWrapper}>
{Object.keys(types).length > 0 ? ( {Object.keys(templates).length > 0 && Object.keys(types).length > 0 ? (
<> <>
<ReactFlow <ReactFlow
nodes={nodes} nodes={nodes}

View file

@ -18,7 +18,6 @@ import {
} from "@heroicons/react/24/outline"; } from "@heroicons/react/24/outline";
import { Connection, Edge, Node, ReactFlowInstance } from "reactflow"; import { Connection, Edge, Node, ReactFlowInstance } from "reactflow";
import { FlowType } from "./types/flow"; import { FlowType } from "./types/flow";
import { APIClassType } from "./types/api";
var _ = require('lodash') var _ = require('lodash')
export function classNames(...classes:Array<string>) { export function classNames(...classes:Array<string>) {
@ -390,6 +389,21 @@ export function removeApiKeys(flow:FlowType):FlowType{
return cleanFLow return cleanFLow
} }
export function UpdateTemplate(newTemplate:APIClassType,oldTemplate:APIClassType){ export function updateObject<T extends Record<string, any>>(reference: T, objectToUpdate: T): T {
let clonedObject = _.cloneDeep(objectToUpdate)
// Loop through each key in the object to update
for (const key in clonedObject) {
// If the key is not in the reference object, delete it
if (!(key in reference)) {
delete clonedObject[key];
}
}
// Loop through each key in the reference object
for (const key in reference) {
// If the key is not in the object to update, add it
if (!(key in clonedObject)) {
clonedObject[key] = reference[key];
}
}
return clonedObject;
} }