Merge branch 'saveComponent' into feature/store

This commit is contained in:
cristhianzl 2023-10-19 18:08:52 -03:00
commit 91d0da573d
21 changed files with 268 additions and 509 deletions

File diff suppressed because one or more lines are too long

View file

@ -42,9 +42,7 @@ export default function App() {
successData,
successOpen,
setSuccessOpen,
setErrorData,
loading,
setLoading,
} = useContext(alertContext);
const navigate = useNavigate();
const { fetchError } = useContext(typesContext);

View file

@ -438,11 +438,7 @@ export default function ParameterComponent({
) : left === true && type === "prompt" ? (
<div className="mt-2 w-full">
<PromptAreaComponent
readonly={
data.node?.flow && data.node.template[name].dynamic
? true
: false
}
readonly={data.node?.flow ? true : false}
field_name={name}
setNodeClass={(nodeClass) => {
data.node = nodeClass;

View file

@ -24,7 +24,8 @@ export default function PromptAreaComponent({
}, [disabled]);
useEffect(() => {
if (value !== "" && !editNode && !readonly) {
//prevent update from prompt template after group node if prompt is wrongly marked as not dynamic
if (value !== "" && !editNode && !readonly && !nodeClass?.flow) {
postValidatePrompt(field_name!, value, nodeClass!).then((apiReturn) => {
if (apiReturn.data) {
setNodeClass!(apiReturn.data.frontend_node);

View file

@ -90,7 +90,7 @@ export function TabsProvider({ children }: { children: ReactNode }) {
const [flows, setFlows] = useState<Array<FlowType>>([]);
const [id, setId] = useState(uid());
const { templates, reactFlowInstance } = useContext(typesContext);
const { templates, reactFlowInstance, setData } = useContext(typesContext);
const [lastCopiedSelection, setLastCopiedSelection] = useState<{
nodes: any;
edges: any;
@ -139,11 +139,24 @@ export function TabsProvider({ children }: { children: ReactNode }) {
}
function processDBData(DbData: FlowType[]) {
let storeComponents: { [key: string]: APIClassType } = {};
DbData.forEach((flow: FlowType) => {
try {
if (!flow.data) {
return;
}
if (flow.data && flow.is_component) {
storeComponents[(flow.data.nodes[0].data as NodeDataType).type] = (
flow.data.nodes[0].data as NodeDataType
).node!;
}
setData((prev) => {
let newData = _.cloneDeep(prev);
Object.keys(storeComponents).forEach((key) => {
newData["custom_components"][key] = storeComponents[key];
});
return newData;
});
processDataFromFlow(flow, false);
} catch (e) {}
});

View file

@ -7,11 +7,12 @@ import {
useState,
} from "react";
import { Edge, Node, ReactFlowInstance } from "reactflow";
import { getAll, getHealth } from "../controllers/API";
import { getAll, getHealth, saveFlowToDatabase } from "../controllers/API";
import { APIClassType, APIKindType } from "../types/api";
import { localStorageUserType } from "../types/entities";
import { NodeDataType } from "../types/flow";
import { typesContextType } from "../types/typesContext";
import { createFlowComponent } from "../utils/reactflowUtils";
import {
checkLocalStorageKey,
getSetFromObject,
@ -71,17 +72,19 @@ export function TypesProvider({ children }: { children: ReactNode }) {
if (isMounted && result?.status === 200) {
setLoading(false);
let { data } = _.cloneDeep(result);
const savedComponents = autoLogin
? localStorage.getItem("auto")
: localStorage.getItem(userData?.id!);
if (savedComponents !== null) {
const { components }: localStorageUserType = JSON.parse(
savedComponents!
);
Object.keys(components).forEach((key) => {
data["custom_components"][key] = components[key].node!;
});
}
// const savedComponents = autoLogin
// ? localStorage.getItem("auto")
// : localStorage.getItem(userData?.id!);
// if (savedComponents !== null) {
// // const { components }: localStorageUserType = JSON.parse(
// // savedComponents!
// // );
// Object.keys(components).forEach((key) => {
// data["custom_components"][key] = (
// components[key].data?.nodes[0].data! as NodeDataType
// ).node!;
// });
// }
setData(data);
setTemplates(
Object.keys(data).reduce((acc, curr) => {
@ -147,12 +150,12 @@ export function TypesProvider({ children }: { children: ReactNode }) {
}
function saveComponent(component: NodeDataType, id: string) {
let savedComponentsJSON: localStorageUserType = { components: {} };
if (checkLocalStorageKey(id)) {
let savedComponents = localStorage.getItem(id)!;
savedComponentsJSON = JSON.parse(savedComponents);
}
let components = savedComponentsJSON.components;
// let savedComponentsJSON: localStorageUserType = { components: {} };
// if (checkLocalStorageKey(id)) {
// let savedComponents = localStorage.getItem(id)!;
// savedComponentsJSON = JSON.parse(savedComponents);
// }
// let components = savedComponentsJSON.components;
let key = component.type;
if (data["custom_components"][key] !== undefined) {
let { newKey, increment } = IncrementObjectKey(
@ -181,9 +184,10 @@ export function TypesProvider({ children }: { children: ReactNode }) {
}
}
component.node!.official = false;
components[key] = component;
savedComponentsJSON.components = components;
localStorage.setItem(id, JSON.stringify(savedComponentsJSON));
// components[key] = createFlowComponent(component);
saveFlowToDatabase(createFlowComponent(component));
// savedComponentsJSON.components = components;
// localStorage.setItem(id, JSON.stringify(savedComponentsJSON));
setData((prev) => {
let newData = { ...prev };
//clone to prevent reference erro

View file

@ -112,12 +112,14 @@ export async function saveFlowToDatabase(newFlow: {
data: ReactFlowJsonObject | null;
description: string;
style?: FlowStyleType;
is_component?: boolean;
}): Promise<FlowType> {
try {
const response = await api.post(`${BASE_URL_API}flows/`, {
name: newFlow.name,
data: newFlow.data,
description: newFlow.description,
is_component: newFlow.is_component,
});
if (response.status !== 201) {
@ -536,3 +538,44 @@ export async function addApiKeyStore(key: string) {
throw error;
}
}
/**
* Saves a new flow to the database.
*
* @param {FlowType} newFlow - The flow data to save.
* @returns {Promise<any>} The saved flow data.
* @throws Will throw an error if saving fails.
*/
export async function saveFlowStore(newFlow: {
name: string;
data: ReactFlowJsonObject | null;
description: string;
style?: FlowStyleType;
is_component?: boolean;
}): Promise<FlowType> {
try {
const response = await api.post(`${BASE_URL_API}store/`, {
name: newFlow.name,
data: newFlow.data,
description: newFlow.description,
is_component: newFlow.is_component,
});
if (response.status !== 201) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.data;
} catch (error) {
console.error(error);
throw error;
}
}
/**
* Fetches the flows from the store.
* @returns {Promise<>} A promise that resolves to an AxiosResponse containing the build status.
*
*/
export async function getFlowsStore(): Promise<AxiosResponse<FlowType[]>> {
return await api.get(`${BASE_URL_API}store/`);
}

View file

@ -438,12 +438,7 @@ const EditNodeModal = forwardRef(
<div className="mx-auto">
<PromptAreaComponent
readonly={
myData.current.node?.flow &&
myData.current.node.template[
templateParam
].dynamic
? true
: false
myData.current.node?.flow ? true : false
}
field_name={templateParam}
editNode={true}

View file

@ -1,4 +1,4 @@
import { NodeDataType } from "../flow";
import { FlowType } from "../flow";
export type sidebarNavigationItemType = {
name: string;
@ -8,5 +8,5 @@ export type sidebarNavigationItemType = {
};
export type localStorageUserType = {
components: { [key: string]: NodeDataType };
components: { [key: string]: FlowType };
};

View file

@ -7,7 +7,7 @@ export type FlowType = {
data: ReactFlowJsonObject | null;
description: string;
style?: FlowStyleType;
isNode?: boolean;
is_component?: boolean;
};
export type NodeType = {
id: string;

View file

@ -437,8 +437,8 @@ export function convertValuesToNumbers(arr) {
for (const key in obj) {
if (obj.hasOwnProperty(key)) {
let value = obj[key];
if (/\s/g.test(value)) {
value = value.trim();
if (/^\d+$/.test(value)) {
value = value?.toString().trim();
}
newObj[key] =
value === "" || isNaN(value) ? value.toString() : Number(value);
@ -1079,9 +1079,9 @@ export function createFlowComponent(nodeData: NodeDataType): FlowType {
viewport: { x: 1, y: 1, zoom: 1 },
},
description: nodeData.node?.description || "",
name: nodeData.node?.display_name || "",
name: nodeData.node?.display_name || nodeData.type || "",
id: nodeData.id || "",
isNode: true,
is_component: true,
};
return flowNode;
}

View file

@ -21,7 +21,17 @@ test("KeypairListComponent", async ({ page }) => {
await page.locator('//*[@id="keypair0"]').click();
await page.locator('//*[@id="keypair0"]').fill("testtesttesttest");
await page.locator('//*[@id="keypair100"]').click();
await page.locator('//*[@id="keypair100"]').fill("testtesttesttesttesttest");
await page
.locator('//*[@id="keypair100"]')
.fill("test test test test test test");
const valueWithSpace = await page
.locator('//*[@id="keypair100"]')
.inputValue();
if (valueWithSpace !== "test test test test test test") {
expect(false).toBeTruthy();
}
const plusButtonLocatorNode = page.locator('//*[@id="plusbtn0"]');
const elementCountNode = await plusButtonLocatorNode.count();
@ -94,7 +104,7 @@ test("KeypairListComponent", async ({ page }) => {
await page.locator('//*[@id="keypair100"]').click();
await page
.locator('//*[@id="keypair100"]')
.fill("testtesttesttesttesttest");
.fill("test test test test test test");
const plusButtonLocator = page.locator('//*[@id="plusbtn0"]');
const elementCount = await plusButtonLocator.count();
@ -132,7 +142,7 @@ test("KeypairListComponent", async ({ page }) => {
if (
key1 === "testtesttesttest" &&
value1 === "testtesttesttesttesttest" &&
value1 === "test test test test test test" &&
key2 === "testtesttesttest2" &&
value2 === "testtesttesttesttesttest2"
) {