refactor: add useGetRefreshFlows mutation and update code to use it (#3475)

* Added refresh flows mutation

* Changed places that used refreshFlows to use the mutation

* removed old refreshFlows

* removed readFlowsFromDatabase api call

* Removed unused API calls from API.ts

* Removed getFlowFromDatabase call
This commit is contained in:
Lucas Oliveira 2024-08-21 12:21:19 -03:00 committed by GitHub
commit 3a408c8141
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 79 additions and 207 deletions

View file

@ -55,157 +55,6 @@ export async function sendAll(data: sendAllProps) {
return await api.post(`${BASE_URL_API}predict`, data);
}
/**
* Fetches a list of JSON files from a GitHub repository and returns their contents as an array of FlowType objects.
*
* @returns {Promise<FlowType[]>} A promise that resolves to an array of FlowType objects.
*/
export async function getExamples(): Promise<FlowType[]> {
const url =
"https://api.github.com/repos/langflow-ai/langflow_examples/contents/examples?ref=main";
const response = await api.get(url);
const jsonFiles = response?.data.filter((file: any) => {
return file.name.endsWith(".json");
});
const contentsPromises = jsonFiles.map(async (file: any) => {
const contentResponse = await api.get(file.download_url);
return contentResponse.data;
});
return await Promise.all(contentsPromises);
}
/**
* 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 saveFlowToDatabase(newFlow: {
name: string;
id: string;
data: ReactFlowJsonObject | null;
description: string;
style?: FlowStyleType;
is_component?: boolean;
folder_id?: string;
endpoint_name?: string;
}): 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,
folder_id: newFlow.folder_id === "" ? null : newFlow.folder_id,
endpoint_name: newFlow.endpoint_name,
});
if (response?.status !== 201) {
throw new Error(`HTTP error! status: ${response?.status}`);
}
return response?.data;
} catch (error) {
console.error(error);
throw error;
}
}
/**
* Reads all flows from the database.
*
* @returns {Promise<any>} The flows data.
* @throws Will throw an error if reading fails.
*/
export async function readFlowsFromDatabase() {
try {
const response = await api.get(`${BASE_URL_API}flows/`);
if (response && response?.status !== 200) {
throw new Error(`HTTP error! status: ${response?.status}`);
}
return response?.data;
} catch (error) {
console.error(error);
throw error;
}
}
export async function uploadFlowsToDatabase(flows: FormData) {
try {
const response = await api.post(`${BASE_URL_API}flows/upload/`, flows);
if (response?.status !== 201) {
throw new Error(`HTTP error! status: ${response?.status}`);
}
return response?.data;
} catch (error) {
console.error(error);
throw error;
}
}
/**
* Deletes a flow from the database.
*
* @param {string} flowId - The ID of the flow to delete.
* @returns {Promise<any>} The deleted flow data.
* @throws Will throw an error if deletion fails.
*/
export async function deleteFlowFromDatabase(flowId: string) {
try {
const response = await api.delete(`${BASE_URL_API}flows/${flowId}`);
if (response.status !== 200) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response?.data;
} catch (error) {
console.error(error);
throw error;
}
}
/**
* Fetches a flow from the database by ID.
*
* @param {number} flowId - The ID of the flow to fetch.
* @returns {Promise<any>} The flow data.
* @throws Will throw an error if fetching fails.
*/
export async function getFlowFromDatabase(flowId: number) {
try {
const response = await api.get(`${BASE_URL_API}flows/${flowId}`);
if (response && response?.status !== 200) {
throw new Error(`HTTP error! status: ${response?.status}`);
}
return response?.data;
} catch (error) {
console.error(error);
throw error;
}
}
/**
* Fetches flow styles from the database.
*
* @returns {Promise<any>} The flow styles data.
* @throws Will throw an error if fetching fails.
*/
export async function getFlowStylesFromDatabase() {
try {
const response = await api.get(`${BASE_URL_API}flow_styles/`);
if (response.status !== 200) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response?.data;
} catch (error) {
console.error(error);
throw error;
}
}
/**
* Fetches the version of the API.
*

View file

@ -0,0 +1,67 @@
import useAlertStore from "@/stores/alertStore";
import useFlowsManagerStore from "@/stores/flowsManagerStore";
import { useFolderStore } from "@/stores/foldersStore";
import { useTypesStore } from "@/stores/typesStore";
import { useMutationFunctionType } from "@/types/api";
import { FlowType } from "@/types/flow";
import {
extractFieldsFromComponenents,
processFlows,
} from "@/utils/reactflowUtils";
import { UseMutationResult } from "@tanstack/react-query";
import { api } from "../../api";
import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor";
export const useGetRefreshFlows: useMutationFunctionType<
undefined,
undefined
> = (options?) => {
const { mutate } = UseRequestProcessor();
const setExamples = useFlowsManagerStore((state) => state.setExamples);
const setFlows = useFlowsManagerStore((state) => state.setFlows);
const setErrorData = useAlertStore((state) => state.setErrorData);
const starterProjectId = useFolderStore((state) => state.starterProjectId);
const getRefreshFlowsFn = async (): Promise<void> => {
try {
} catch (e) {
setErrorData({
title: "Could not load flows from database",
});
throw e;
}
const response = await api.get<FlowType[]>(`${getURL("FLOWS")}/`);
const dbData = response.data;
if (dbData) {
const { data, flows } = processFlows(dbData);
const examples = flows.filter(
(flow) => flow.folder_id === starterProjectId,
);
setExamples(examples);
const flowsWithoutStarterFolder = flows.filter(
(flow) => flow.folder_id !== starterProjectId,
);
setFlows(flowsWithoutStarterFolder);
useTypesStore.setState((state) => ({
data: { ...state.data, ["saved_components"]: data },
ComponentFields: extractFieldsFromComponenents({
...state.data,
["saved_components"]: data,
}),
}));
return;
}
};
const mutation: UseMutationResult<void, any, undefined> = mutate(
["useGetRefreshFlows"],
getRefreshFlowsFn,
options,
);
return mutation;
};

View file

@ -1,18 +1,19 @@
import { DEFAULT_FOLDER, STARTER_FOLDER_NAME } from "@/constants/constants";
import { FolderType } from "@/pages/MainPage/entities";
import useFlowsManagerStore from "@/stores/flowsManagerStore";
import { useFolderStore } from "@/stores/foldersStore";
import { useTypesStore } from "@/stores/typesStore";
import { useQueryFunctionType } from "@/types/api";
import { api } from "../../api";
import { getURL } from "../../helpers/constants";
import { UseRequestProcessor } from "../../services/request-processor";
import { useGetRefreshFlows } from "../flows/use-get-refresh-flows";
export const useGetFoldersQuery: useQueryFunctionType<
undefined,
FolderType[]
> = (options) => {
const { query } = UseRequestProcessor();
const { mutateAsync: refreshFlows } = useGetRefreshFlows();
const setStarterProjectId = useFolderStore(
(state) => state.setStarterProjectId,
@ -36,10 +37,9 @@ export const useGetFoldersQuery: useQueryFunctionType<
const myCollectionId = data?.find((f) => f.name === DEFAULT_FOLDER)?.id;
setMyCollectionId(myCollectionId);
const { refreshFlows } = useFlowsManagerStore.getState();
const { getTypes } = useTypesStore.getState();
await refreshFlows();
await refreshFlows(undefined);
await getTypes();
return foldersWithoutStarterProjects;

View file

@ -1,7 +1,7 @@
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
import { createFileUpload } from "@/helpers/create-file-upload";
import { getObjectsFromFilelist } from "@/helpers/get-objects-from-filelist";
import useFlowStore from "@/stores/flowStore";
import useFlowsManagerStore from "@/stores/flowsManagerStore";
import { FlowType } from "@/types/flow";
import { processDataFromFlow } from "@/utils/reactflowUtils";
import useAddFlow from "./use-add-flow";
@ -9,7 +9,7 @@ import useAddFlow from "./use-add-flow";
const useUploadFlow = () => {
const addFlow = useAddFlow();
const paste = useFlowStore((state) => state.paste);
const refreshFlows = useFlowsManagerStore((state) => state.refreshFlows);
const { mutate: refreshFlows } = useGetRefreshFlows();
const getFlowsFromFiles = async ({
files,
@ -90,7 +90,7 @@ const useUploadFlow = () => {
throw new Error("Invalid flow data");
}
}
refreshFlows();
refreshFlows(undefined);
}
} catch (e) {
throw e;

View file

@ -1,4 +1,5 @@
import FeatureFlags from "@/../feature-config.json";
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
import { useGetGlobalVariables } from "@/controllers/API/queries/variables";
import useSaveFlow from "@/hooks/flows/use-save-flow";
import { SaveChangesModal } from "@/modals/saveChangesModal";
@ -33,7 +34,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
const flows = useFlowsManagerStore((state) => state.flows);
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
const refreshFlows = useFlowsManagerStore((state) => state.refreshFlows);
const { mutateAsync: refreshFlows } = useGetRefreshFlows();
const setIsLoading = useFlowsManagerStore((state) => state.setIsLoading);
const getTypes = useTypesStore((state) => state.getTypes);
@ -74,7 +75,7 @@ export default function FlowPage({ view }: { view?: boolean }): JSX.Element {
setCurrentFlow(isAnExistingFlow);
} else if (!flows) {
setIsLoading(true);
await refreshFlows();
await refreshFlows(undefined);
await getTypes();
setIsLoading(false);
}

View file

@ -1,3 +1,4 @@
import { useGetRefreshFlows } from "@/controllers/API/queries/flows/use-get-refresh-flows";
import { useGetGlobalVariables } from "@/controllers/API/queries/variables";
import useFlowStore from "@/stores/flowStore";
import { useTypesStore } from "@/stores/typesStore";
@ -16,7 +17,7 @@ export default function ViewPage() {
const flows = useFlowsManagerStore((state) => state.flows);
const currentFlowId = useFlowsManagerStore((state) => state.currentFlowId);
const refreshFlows = useFlowsManagerStore((state) => state.refreshFlows);
const { mutateAsync: refreshFlows } = useGetRefreshFlows();
const setIsLoading = useFlowsManagerStore((state) => state.setIsLoading);
const getTypes = useTypesStore((state) => state.getTypes);
@ -34,7 +35,7 @@ export default function ViewPage() {
setCurrentFlow(isAnExistingFlow);
} else if (!flows) {
setIsLoading(true);
await refreshFlows();
await refreshFlows(undefined);
await getTypes();
setIsLoading(false);
}

View file

@ -1,19 +1,11 @@
import { cloneDeep } from "lodash";
import { create } from "zustand";
import { readFlowsFromDatabase } from "../controllers/API";
import { FlowType } from "../types/flow";
import {
FlowsManagerStoreType,
UseUndoRedoOptions,
} from "../types/zustand/flowsManager";
import {
extractFieldsFromComponenents,
processFlows,
} from "../utils/reactflowUtils";
import useAlertStore from "./alertStore";
import useFlowStore from "./flowStore";
import { useFolderStore } from "./foldersStore";
import { useTypesStore } from "./typesStore";
const defaultOptions: UseUndoRedoOptions = {
maxHistorySize: 100,
@ -53,43 +45,6 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
setSaveLoading: (saveLoading: boolean) => set({ saveLoading }),
isLoading: false,
setIsLoading: (isLoading: boolean) => set({ isLoading }),
refreshFlows: () => {
return new Promise<void>((resolve, reject) => {
const starterFolderId = useFolderStore.getState().starterProjectId;
readFlowsFromDatabase()
.then((dbData) => {
if (dbData) {
const { data, flows } = processFlows(dbData);
const examples = flows.filter(
(flow) => flow.folder_id === starterFolderId,
);
get().setExamples(examples);
const flowsWithoutStarterFolder = flows.filter(
(flow) => flow.folder_id !== starterFolderId,
);
get().setFlows(flowsWithoutStarterFolder);
useTypesStore.setState((state) => ({
data: { ...state.data, ["saved_components"]: data },
ComponentFields: extractFieldsFromComponenents({
...state.data,
["saved_components"]: data,
}),
}));
resolve();
}
})
.catch((e) => {
set({ isLoading: false });
useAlertStore.getState().setErrorData({
title: "Could not load flows from database",
});
reject(e);
});
});
},
takeSnapshot: () => {
const currentFlowId = get().currentFlowId;
// push the current graph to the past state

View file

@ -12,7 +12,6 @@ export type FlowsManagerStoreType = {
setSaveLoading: (saveLoading: boolean) => void;
isLoading: boolean;
setIsLoading: (isLoading: boolean) => void;
refreshFlows: () => Promise<void>;
undo: () => void;
redo: () => void;
takeSnapshot: () => void;