Skip to content

Commit

Permalink
refactor: add useGetRefreshFlows mutation and update code to use it (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
lucaseduoli authored Aug 21, 2024
1 parent 0586d1e commit 3a408c8
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 207 deletions.
151 changes: 0 additions & 151 deletions src/frontend/src/controllers/API/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
};
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions src/frontend/src/hooks/flows/use-upload-flow.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
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";

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,
Expand Down Expand Up @@ -90,7 +90,7 @@ const useUploadFlow = () => {
throw new Error("Invalid flow data");
}
}
refreshFlows();
refreshFlows(undefined);
}
} catch (e) {
throw e;
Expand Down
5 changes: 3 additions & 2 deletions src/frontend/src/pages/FlowPage/index.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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);
}
Expand Down
5 changes: 3 additions & 2 deletions src/frontend/src/pages/ViewPage/index.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -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);

Expand All @@ -34,7 +35,7 @@ export default function ViewPage() {
setCurrentFlow(isAnExistingFlow);
} else if (!flows) {
setIsLoading(true);
await refreshFlows();
await refreshFlows(undefined);
await getTypes();
setIsLoading(false);
}
Expand Down
45 changes: 0 additions & 45 deletions src/frontend/src/stores/flowsManagerStore.ts
Original file line number Diff line number Diff line change
@@ -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,
Expand Down Expand Up @@ -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
Expand Down
Loading

0 comments on commit 3a408c8

Please sign in to comment.