update template working for local flow on browser
This commit is contained in:
parent
a8f2d69f9a
commit
d91beb9cda
7 changed files with 109 additions and 81 deletions
|
|
@ -59,5 +59,5 @@
|
|||
"last 1 safari version"
|
||||
]
|
||||
},
|
||||
"proxy": "http://backend:7860"
|
||||
"proxy": "http://127.0.0.1:5003"
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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>,
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue