diff --git a/src/frontend/package.json b/src/frontend/package.json index b669569e3..84e9ad595 100644 --- a/src/frontend/package.json +++ b/src/frontend/package.json @@ -59,5 +59,5 @@ "last 1 safari version" ] }, - "proxy": "http://backend:7860" + "proxy": "http://127.0.0.1:5003" } \ No newline at end of file diff --git a/src/frontend/src/contexts/tabsContext.tsx b/src/frontend/src/contexts/tabsContext.tsx index 2823f6044..9903bda30 100644 --- a/src/frontend/src/contexts/tabsContext.tsx +++ b/src/frontend/src/contexts/tabsContext.tsx @@ -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 { LangFlowState, TabsContextType } from "../types/tabs"; -import { normalCaseToSnakeCase } from "../utils"; +import { normalCaseToSnakeCase, updateObject } from "../utils"; import { alertContext } from "./alertContext"; import { typesContext } from "./typesContext"; +import { TemplateVariableType } from "../types/api"; const TabsContextInitialValue: TabsContextType = { - save:()=>{}, + save: () => {}, tabIndex: 0, setTabIndex: (index: number) => {}, flows: [], @@ -14,11 +22,11 @@ const TabsContextInitialValue: TabsContextType = { addFlow: (flowData?: any) => {}, updateFlow: (newFlow: FlowType) => {}, incrementNodeId: () => 0, - downloadFlow: (flow:FlowType) => {}, + downloadFlow: (flow: FlowType) => {}, uploadFlow: () => {}, lockChat: false, - setLockChat:(prevState:boolean)=>{}, - hardReset:()=>{}, + setLockChat: (prevState: boolean) => {}, + hardReset: () => {}, }; export const TabsContext = createContext( @@ -26,61 +34,64 @@ export const TabsContext = createContext( ); export function TabsProvider({ children }: { children: ReactNode }) { - const {setNoticeData} = useContext(alertContext) + const { setNoticeData } = useContext(alertContext); const [tabIndex, setTabIndex] = useState(0); const [flows, setFlows] = useState>([]); const [id, setId] = useState(0); const [lockChat, setLockChat] = useState(false); - const {templates} = useContext(typesContext ) + const { templates } = useContext(typesContext); const newNodeId = useRef(0); function incrementNodeId() { newNodeId.current = newNodeId.current + 1; return newNodeId.current; } - function save(){ - console.log("save") + function save() { + console.log("save"); if (flows.length !== 0) - window.localStorage.setItem( - "tabsData", - JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current }) - ); + window.localStorage.setItem( + "tabsData", + JSON.stringify({ tabIndex, flows, id, nodeId: newNodeId.current }) + ); } useEffect(() => { //save tabs locally - save() + save(); }, [flows, id, tabIndex, newNodeId]); - - useEffect(() => { //get tabs locally saved let cookie = window.localStorage.getItem("tabsData"); - if (cookie) { - console.log(templates) - console.log(Object.keys(templates).length) - let cookieObject:LangFlowState = JSON.parse(cookie); - cookieObject.flows.forEach(flow=>{ - console.log(flow) - // flow.data.nodes.forEach(node=>{ - // console.log(node.data) - // }) - }) + if (cookie && Object.keys(templates).length > 0) { + let cookieObject: LangFlowState = JSON.parse(cookie); + cookieObject.flows.forEach((flow) => { + flow.data.nodes.forEach((node) => { + node.data.node.template = updateObject( + node.data.node.template as TemplateVariableType, + templates[node.data.type][ + "template" + ] as unknown as TemplateVariableType + ); + console.log(node) + }); + }); setTabIndex(cookieObject.tabIndex); setFlows(cookieObject.flows); setId(cookieObject.id); newNodeId.current = cookieObject.nodeId; } }, [templates]); - function hardReset(){ - newNodeId.current=0; - setTabIndex(0);setFlows([]);setId(0); + function hardReset() { + newNodeId.current = 0; + setTabIndex(0); + setFlows([]); + setId(0); } /** * 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 const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent( JSON.stringify(flow) @@ -93,7 +104,9 @@ export function TabsProvider({ children }: { children: ReactNode }) { // simulate a click on the link element to trigger the download 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) { // Get data from the flow or set it to null if there's no flow provided. 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. let newFlow: FlowType = { @@ -182,7 +195,7 @@ export function TabsProvider({ children }: { children: ReactNode }) { const newFlows = [...prevState]; const index = newFlows.findIndex((flow) => flow.id === newFlow.id); if (index !== -1) { - newFlows[index].description = newFlow.description??"" + newFlows[index].description = newFlow.description ?? ""; newFlows[index].data = newFlow.data; newFlows[index].name = newFlow.name; newFlows[index].chat = newFlow.chat; diff --git a/src/frontend/src/contexts/typesContext.tsx b/src/frontend/src/contexts/typesContext.tsx index 95f9622c7..ad86d4699 100644 --- a/src/frontend/src/contexts/typesContext.tsx +++ b/src/frontend/src/contexts/typesContext.tsx @@ -1,6 +1,8 @@ -import { createContext, ReactNode, useState } from "react"; +import { createContext, ReactNode, useEffect, useState } from "react"; import { Node} from "reactflow"; 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 @@ -23,6 +25,40 @@ export function TypesProvider({ children }:{children:ReactNode}) { const [reactFlowInstance, setReactFlowInstance] = useState(null); const [templates, setTemplates] = useState({}); const [data, setData] = useState({}); + + useEffect(() => { + async function getTypes(): Promise { + // 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) { reactFlowInstance.setNodes( reactFlowInstance.getNodes().filter((n:Node) => n.id !== idx) diff --git a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx index f89c2abd6..9f08674b5 100644 --- a/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/extraSidebarComponent/index.tsx @@ -2,51 +2,14 @@ import { Bars2Icon } from "@heroicons/react/24/outline"; import DisclosureComponent from "../DisclosureComponent"; import { nodeColors, nodeIcons, nodeNames } from "../../../../utils"; import { useContext, useEffect, useState } from "react"; -import { getAll } from "../../../../controllers/API"; import { typesContext } from "../../../../contexts/typesContext"; import { APIClassType, - APIKindType, APIObjectType, } from "../../../../types/api"; export default function ExtraSidebar() { - const [data, setData] = useState({}); - const { setTypes } = useContext(typesContext); - const { setTemplates } = useContext(typesContext); - - useEffect(() => { - async function getTypes(): Promise { - // 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]); + const {data} = useContext(typesContext) function onDragStart( event: React.DragEvent, diff --git a/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx b/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx index 71c964cbe..6ea12a8fa 100644 --- a/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx +++ b/src/frontend/src/pages/FlowPage/components/tabsManagerComponent/index.tsx @@ -16,21 +16,23 @@ import AlertDropdown from "../../../../alerts/alertDropDown"; import { alertContext } from "../../../../contexts/alertContext"; import ImportModal from "../../../../modals/importModal"; import ExportModal from "../../../../modals/exportModal"; +import { typesContext } from "../../../../contexts/typesContext"; export default function TabsManagerComponent() { const { flows, addFlow, tabIndex, setTabIndex, uploadFlow, downloadFlow } = useContext(TabsContext); const { openPopUp } = useContext(PopUpContext); + const {templates} = useContext(typesContext) const AlertWidth = 256; const { dark, setDark } = useContext(darkContext); const { notificationCenter, setNotificationCenter } = useContext(alertContext); useEffect(() => { //create the first flow - if (flows.length === 0) { + if (flows.length === 0&& Object.keys(templates).length>0) { addFlow(); } - }, [addFlow, flows.length]); + }, [addFlow, flows.length,templates]); return (
diff --git a/src/frontend/src/pages/FlowPage/index.tsx b/src/frontend/src/pages/FlowPage/index.tsx index 4fc315926..eef70bf5b 100644 --- a/src/frontend/src/pages/FlowPage/index.tsx +++ b/src/frontend/src/pages/FlowPage/index.tsx @@ -32,7 +32,7 @@ var _ = require("lodash"); export default function FlowPage({ flow }:{flow:FlowType}) { let { updateFlow, incrementNodeId} = useContext(TabsContext); - const { types, reactFlowInstance, setReactFlowInstance } = + const { types, reactFlowInstance, setReactFlowInstance, templates } = useContext(typesContext); const reactFlowWrapper = useRef(null); @@ -180,7 +180,7 @@ export default function FlowPage({ flow }:{flow:FlowType}) { return (
- {Object.keys(types).length > 0 ? ( + {Object.keys(templates).length > 0 && Object.keys(types).length > 0 ? ( <> ) { @@ -390,6 +389,21 @@ export function removeApiKeys(flow:FlowType):FlowType{ return cleanFLow } -export function UpdateTemplate(newTemplate:APIClassType,oldTemplate:APIClassType){ - +export function updateObject>(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; } \ No newline at end of file