This commit is contained in:
Gabriel Almeida 2023-05-22 08:21:29 -03:00
commit 4998838853

View file

@ -1,10 +1,10 @@
import { import {
createContext, createContext,
useEffect, useEffect,
useState, useState,
useRef, useRef,
ReactNode, ReactNode,
useContext, useContext,
} from "react"; } from "react";
import { FlowType } from "../types/flow"; import { FlowType } from "../types/flow";
import { LangFlowState, TabsContextType } from "../types/tabs"; import { LangFlowState, TabsContextType } from "../types/tabs";
@ -15,248 +15,252 @@ import { APITemplateType, TemplateVariableType } from "../types/api";
import { v4 as uuidv4 } from "uuid"; import { v4 as uuidv4 } from "uuid";
const TabsContextInitialValue: TabsContextType = { const TabsContextInitialValue: TabsContextType = {
save: () => { }, save: () => {},
tabIndex: 0, tabIndex: 0,
setTabIndex: (index: number) => { }, setTabIndex: (index: number) => {},
flows: [], flows: [],
removeFlow: (id: string) => { }, removeFlow: (id: string) => {},
addFlow: (flowData?: any) => { }, addFlow: (flowData?: any) => {},
updateFlow: (newFlow: FlowType) => { }, updateFlow: (newFlow: FlowType) => {},
incrementNodeId: () => 0, incrementNodeId: () => 0,
downloadFlow: (flow: FlowType) => { }, downloadFlow: (flow: FlowType) => {},
uploadFlow: () => { }, uploadFlow: () => {},
hardReset: () => { }, hardReset: () => {},
disableCP: false, disableCP: false,
setDisableCP: (state: boolean) => { }, setDisableCP: (state: boolean) => {},
}; };
export const TabsContext = createContext<TabsContextType>( export const TabsContext = createContext<TabsContextType>(
TabsContextInitialValue TabsContextInitialValue
); );
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(uuidv4()); const [id, setId] = useState(uuidv4());
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() {
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(() => {
//get tabs locally saved
let cookie = window.localStorage.getItem("tabsData");
if (cookie && Object.keys(templates).length > 0) {
let cookieObject: LangFlowState = JSON.parse(cookie);
cookieObject.flows.forEach((flow) => {
flow.data.nodes.forEach((node) => {
if (Object.keys(templates[node.data.type]["template"]).length > 0) {
node.data.node.base_classes =
templates[node.data.type]["base_classes"];
flow.data.edges.forEach((edge) => {
if (edge.source === node.id) {
edge.sourceHandle = edge.sourceHandle
.split("|")
.slice(0, 2)
.concat(templates[node.data.type]["base_classes"])
.join("|");
}
});
node.data.node.description =
templates[node.data.type]["description"];
node.data.node.template = updateTemplate(
templates[node.data.type][
"template"
] as unknown as APITemplateType,
node.data.node.template as APITemplateType
);
}
});
});
setTabIndex(cookieObject.tabIndex);
setFlows(cookieObject.flows);
setId(cookieObject.id);
newNodeId.current = cookieObject.nodeId;
}
}, [templates]);
useEffect(() => { function hardReset() {
//get tabs locally saved newNodeId.current = 0;
let cookie = window.localStorage.getItem("tabsData"); setTabIndex(0);
if (cookie && Object.keys(templates).length > 0) { setFlows([]);
let cookieObject: LangFlowState = JSON.parse(cookie); setId(uuidv4());
cookieObject.flows.forEach((flow) => { }
flow.data.nodes.forEach((node) => {
if (Object.keys(templates[node.data.type]["template"]).length > 0) {
node.data.node.base_classes = templates[node.data.type][
"base_classes"
];
flow.data.edges.forEach((edge) => {
if (edge.source === node.id) {
edge.sourceHandle = edge.sourceHandle.split("|").slice(0, 2).concat(templates[node.data.type][
"base_classes"
]).join("|");
}
})
node.data.node.description = templates[node.data.type]['description'];
node.data.node.template = updateTemplate(
templates[node.data.type]["template"] as unknown as APITemplateType,
node.data.node.template as APITemplateType
);
}
});
});
setTabIndex(cookieObject.tabIndex);
setFlows(cookieObject.flows);
setId(cookieObject.id);
newNodeId.current = cookieObject.nodeId;
}
}, [templates]);
function hardReset() { /**
newNodeId.current = 0; * Downloads the current flow as a JSON file
setTabIndex(0); */
setFlows([]); function downloadFlow(flow: FlowType) {
setId(uuidv4()); // create a data URI with the current flow data
} const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
JSON.stringify(flow)
)}`;
/** // create a link element and set its properties
* Downloads the current flow as a JSON file const link = document.createElement("a");
*/ link.href = jsonString;
function downloadFlow(flow: FlowType) { link.download = `${flows[tabIndex].name}.json`;
// create a data URI with the current flow data
const jsonString = `data:text/json;chatset=utf-8,${encodeURIComponent(
JSON.stringify(flow)
)}`;
// create a link element and set its properties // simulate a click on the link element to trigger the download
const link = document.createElement("a"); link.click();
link.href = jsonString; setNoticeData({
link.download = `${flows[tabIndex].name}.json`; title: "Warning: Critical data,JSON file may including API keys.",
});
}
// simulate a click on the link element to trigger the download /**
link.click(); * Creates a file input and listens to a change event to upload a JSON flow file.
setNoticeData({ * If the file type is application/json, the file is read and parsed into a JSON object.
title: "Warning: Critical data,JSON file may including API keys.", * The resulting JSON object is passed to the addFlow function.
}); */
} function uploadFlow() {
// create a file input
const input = document.createElement("input");
input.type = "file";
// add a change event listener to the file input
input.onchange = (e: Event) => {
// check if the file type is application/json
if ((e.target as HTMLInputElement).files[0].type === "application/json") {
// get the file from the file input
const file = (e.target as HTMLInputElement).files[0];
// read the file as text
file.text().then((text) => {
// parse the text into a JSON object
let flow: FlowType = JSON.parse(text);
/** addFlow(flow);
* Creates a file input and listens to a change event to upload a JSON flow file. });
* If the file type is application/json, the file is read and parsed into a JSON object. }
* The resulting JSON object is passed to the addFlow function. };
*/ // trigger the file input click event to open the file dialog
function uploadFlow() { input.click();
// create a file input }
const input = document.createElement("input"); /**
input.type = "file"; * Removes a flow from an array of flows based on its id.
// add a change event listener to the file input * Updates the state of flows and tabIndex using setFlows and setTabIndex hooks.
input.onchange = (e: Event) => { * @param {string} id - The id of the flow to remove.
// check if the file type is application/json */
if ((e.target as HTMLInputElement).files[0].type === "application/json") { function removeFlow(id: string) {
// get the file from the file input setFlows((prevState) => {
const file = (e.target as HTMLInputElement).files[0]; const newFlows = [...prevState];
// read the file as text const index = newFlows.findIndex((flow) => flow.id === id);
file.text().then((text) => { if (index >= 0) {
// parse the text into a JSON object if (index === tabIndex) {
let flow: FlowType = JSON.parse(text); setTabIndex(flows.length - 2);
newFlows.splice(index, 1);
} else {
let flowId = flows[tabIndex].id;
newFlows.splice(index, 1);
setTabIndex(newFlows.findIndex((flow) => flow.id === flowId));
}
}
return newFlows;
});
}
/**
* Add a new flow to the list of flows.
* @param flow Optional flow to add.
*/
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 : "";
addFlow(flow); if (data) {
}); data.nodes.forEach((node) => {
} if (Object.keys(templates[node.data.type]["template"]).length > 0) {
}; node.data.node.base_classes =
// trigger the file input click event to open the file dialog templates[node.data.type]["base_classes"];
input.click(); data.edges.forEach((edge) => {
} if (edge.source === node.id) {
/** edge.sourceHandle = edge.sourceHandle
* Removes a flow from an array of flows based on its id. .split("|")
* Updates the state of flows and tabIndex using setFlows and setTabIndex hooks. .slice(0, 2)
* @param {string} id - The id of the flow to remove. .concat(templates[node.data.type]["base_classes"])
*/ .join("|");
function removeFlow(id: string) { }
setFlows((prevState) => { });
const newFlows = [...prevState]; node.data.node.description = templates[node.data.type]["description"];
const index = newFlows.findIndex((flow) => flow.id === id); node.data.node.template = updateTemplate(
if (index >= 0) { templates[node.data.type]["template"] as unknown as APITemplateType,
if (index === tabIndex) { node.data.node.template as APITemplateType
setTabIndex(flows.length - 2); );
newFlows.splice(index, 1); }
} else { });
let flowId = flows[tabIndex].id; console.log(data);
newFlows.splice(index, 1); }
setTabIndex(newFlows.findIndex((flow) => flow.id === flowId)); // Create a new flow with a default name if no flow is provided.
} let newFlow: FlowType = {
} description,
return newFlows; name: flow?.name ?? "New Flow",
}); id: uuidv4(),
} data,
/** };
* Add a new flow to the list of flows.
* @param flow Optional flow to add.
*/
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 : "";
if (data) { // Increment the ID counter.
data.nodes.forEach((node) => { setId(uuidv4());
if (Object.keys(templates[node.data.type]["template"]).length > 0) {
node.data.node.base_classes = templates[node.data.type][
"base_classes"
];
data.edges.forEach((edge) => {
if (edge.source === node.id) {
edge.sourceHandle = edge.sourceHandle.split("|").slice(0, 2).concat(templates[node.data.type][
"base_classes"
]).join("|");
}
})
node.data.node.description = templates[node.data.type]['description'];
node.data.node.template = updateTemplate(
templates[node.data.type]["template"] as unknown as APITemplateType,
node.data.node.template as APITemplateType
);
}
});
console.log(data);
}
// Create a new flow with a default name if no flow is provided.
let newFlow: FlowType = {
description,
name: flow?.name ?? "New Flow",
id: uuidv4(),
data,
};
// Increment the ID counter. // Add the new flow to the list of flows.
setId(uuidv4()); setFlows((prevState) => {
const newFlows = [...prevState, newFlow];
return newFlows;
});
// Add the new flow to the list of flows. // Set the tab index to the new flow.
setFlows((prevState) => { setTabIndex(flows.length);
const newFlows = [...prevState, newFlow]; }
return newFlows; /**
}); * Updates an existing flow with new data
* @param newFlow - The new flow object containing the updated data
*/
function updateFlow(newFlow: FlowType) {
setFlows((prevState) => {
const newFlows = [...prevState];
const index = newFlows.findIndex((flow) => flow.id === newFlow.id);
if (index !== -1) {
newFlows[index].description = newFlow.description ?? "";
newFlows[index].data = newFlow.data;
newFlows[index].name = newFlow.name;
}
return newFlows;
});
}
const [disableCP, setDisableCP] = useState(false);
// Set the tab index to the new flow. return (
setTabIndex(flows.length); <TabsContext.Provider
} value={{
/** disableCP,
* Updates an existing flow with new data setDisableCP,
* @param newFlow - The new flow object containing the updated data save,
*/ hardReset,
function updateFlow(newFlow: FlowType) { tabIndex,
setFlows((prevState) => { setTabIndex,
const newFlows = [...prevState]; flows,
const index = newFlows.findIndex((flow) => flow.id === newFlow.id); incrementNodeId,
if (index !== -1) { removeFlow,
newFlows[index].description = newFlow.description ?? ""; addFlow,
newFlows[index].data = newFlow.data; updateFlow,
newFlows[index].name = newFlow.name; downloadFlow,
} uploadFlow,
return newFlows; }}
}); >
} {children}
const [disableCP, setDisableCP] = useState(false); </TabsContext.Provider>
);
return (
<TabsContext.Provider
value={{
disableCP,
setDisableCP,
save,
hardReset,
tabIndex,
setTabIndex,
flows,
incrementNodeId,
removeFlow,
addFlow,
updateFlow,
downloadFlow,
uploadFlow,
}}
>
{children}
</TabsContext.Provider>
);
} }