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"
]
},
"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 { 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<TabsContextType>(
@ -26,61 +34,64 @@ export const TabsContext = createContext<TabsContextType>(
);
export function TabsProvider({ children }: { children: ReactNode }) {
const {setNoticeData} = useContext(alertContext)
const { setNoticeData } = useContext(alertContext);
const [tabIndex, setTabIndex] = useState(0);
const [flows, setFlows] = useState<Array<FlowType>>([]);
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;

View file

@ -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<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) {
reactFlowInstance.setNodes(
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 { 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<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]);
const {data} = useContext(typesContext)
function onDragStart(
event: React.DragEvent<any>,

View file

@ -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 (
<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}) {
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 (
<div className="w-full h-full" ref={reactFlowWrapper}>
{Object.keys(types).length > 0 ? (
{Object.keys(templates).length > 0 && Object.keys(types).length > 0 ? (
<>
<ReactFlow
nodes={nodes}

View file

@ -18,7 +18,6 @@ import {
} from "@heroicons/react/24/outline";
import { Connection, Edge, Node, ReactFlowInstance } from "reactflow";
import { FlowType } from "./types/flow";
import { APIClassType } from "./types/api";
var _ = require('lodash')
export function classNames(...classes:Array<string>) {
@ -390,6 +389,21 @@ export function removeApiKeys(flow:FlowType):FlowType{
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;
}