fix: session error after retries + refactor on interceptor component (#2803)
* 📝 (API): Add AxiosRequestConfig to import statement in api.tsx for better type checking 🔧 (API): Add useFlowsManagerStore to import statement in api.tsx for managing saveLoading state ♻️ (API): Refactor ApiInterceptor function in api.tsx to improve error handling and flow control 📝 (API): Update comments in api.tsx for better code readability and understanding 🔧 (API): Add setSaveLoading function to FlowsManagerStoreType in flowsManagerStore.ts for managing saveLoading state * 🐛 (frontend): fix potential error when api response is null or undefined by adding optional chaining to data property access * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
parent
57c72d3ea4
commit
011ebc2a5c
4 changed files with 56 additions and 32 deletions
|
|
@ -2,7 +2,8 @@ import {
|
||||||
LANGFLOW_ACCESS_TOKEN,
|
LANGFLOW_ACCESS_TOKEN,
|
||||||
LANGFLOW_AUTO_LOGIN_OPTION,
|
LANGFLOW_AUTO_LOGIN_OPTION,
|
||||||
} from "@/constants/constants";
|
} from "@/constants/constants";
|
||||||
import axios, { AxiosError, AxiosInstance } from "axios";
|
import useFlowsManagerStore from "@/stores/flowsManagerStore";
|
||||||
|
import axios, { AxiosError, AxiosInstance, AxiosRequestConfig } from "axios";
|
||||||
import { useContext, useEffect } from "react";
|
import { useContext, useEffect } from "react";
|
||||||
import { Cookies } from "react-cookie";
|
import { Cookies } from "react-cookie";
|
||||||
import { renewAccessToken } from ".";
|
import { renewAccessToken } from ".";
|
||||||
|
|
@ -19,9 +20,10 @@ const api: AxiosInstance = axios.create({
|
||||||
|
|
||||||
function ApiInterceptor() {
|
function ApiInterceptor() {
|
||||||
const setErrorData = useAlertStore((state) => state.setErrorData);
|
const setErrorData = useAlertStore((state) => state.setErrorData);
|
||||||
let { accessToken, login, logout, authenticationErrorCount, autoLogin } =
|
let { accessToken, logout, authenticationErrorCount, autoLogin } =
|
||||||
useContext(AuthContext);
|
useContext(AuthContext);
|
||||||
const cookies = new Cookies();
|
const cookies = new Cookies();
|
||||||
|
const setSaveLoading = useFlowsManagerStore((state) => state.setSaveLoading);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const interceptor = api.interceptors.response.use(
|
const interceptor = api.interceptors.response.use(
|
||||||
|
|
@ -39,7 +41,8 @@ function ApiInterceptor() {
|
||||||
if (!stillRefresh) {
|
if (!stillRefresh) {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
const acceptedRequest = await tryToRenewAccessToken(error);
|
|
||||||
|
await tryToRenewAccessToken(error);
|
||||||
|
|
||||||
const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN);
|
const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN);
|
||||||
|
|
||||||
|
|
@ -47,11 +50,12 @@ function ApiInterceptor() {
|
||||||
return Promise.reject(error);
|
return Promise.reject(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
return acceptedRequest;
|
await remakeRequest(error);
|
||||||
|
setSaveLoading(false);
|
||||||
|
authenticationErrorCount = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
await clearBuildVerticesState(error);
|
await clearBuildVerticesState(error);
|
||||||
return Promise.reject(error);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -67,7 +71,6 @@ function ApiInterceptor() {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const parsedURL = new URL(url);
|
const parsedURL = new URL(url);
|
||||||
|
|
||||||
const isDomainAllowed = authorizedDomains.some(
|
const isDomainAllowed = authorizedDomains.some(
|
||||||
(domain) => parsedURL.origin === new URL(domain).origin,
|
(domain) => parsedURL.origin === new URL(domain).origin,
|
||||||
);
|
);
|
||||||
|
|
@ -131,10 +134,7 @@ function ApiInterceptor() {
|
||||||
async function tryToRenewAccessToken(error: AxiosError) {
|
async function tryToRenewAccessToken(error: AxiosError) {
|
||||||
try {
|
try {
|
||||||
if (window.location.pathname.includes("/login")) return;
|
if (window.location.pathname.includes("/login")) return;
|
||||||
const res = await renewAccessToken();
|
await renewAccessToken();
|
||||||
if (res?.data?.access_token && res?.data?.refresh_token) {
|
|
||||||
login(res?.data?.access_token, cookies.get(LANGFLOW_AUTO_LOGIN_OPTION));
|
|
||||||
}
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
clearBuildVerticesState(error);
|
clearBuildVerticesState(error);
|
||||||
logout();
|
logout();
|
||||||
|
|
@ -152,6 +152,28 @@ function ApiInterceptor() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function remakeRequest(error: AxiosError) {
|
||||||
|
const originalRequest = error.config as AxiosRequestConfig;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const accessToken = cookies.get(LANGFLOW_ACCESS_TOKEN);
|
||||||
|
if (!accessToken) {
|
||||||
|
throw new Error("Access token not found in cookies");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Modify headers in originalRequest
|
||||||
|
originalRequest.headers = {
|
||||||
|
...(originalRequest.headers as Record<string, string>), // Cast to suppress TypeScript error
|
||||||
|
Authorization: `Bearer ${accessToken}`,
|
||||||
|
};
|
||||||
|
|
||||||
|
const response = await axios.request(originalRequest);
|
||||||
|
return response.data; // Or handle the response as needed
|
||||||
|
} catch (err) {
|
||||||
|
throw err; // Throw the error if request fails again
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ const GITHUB_API_URL = "https://api.github.com";
|
||||||
export async function getRepoStars(owner: string, repo: string) {
|
export async function getRepoStars(owner: string, repo: string) {
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`${GITHUB_API_URL}/repos/${owner}/${repo}`);
|
const response = await api.get(`${GITHUB_API_URL}/repos/${owner}/${repo}`);
|
||||||
return response.data.stargazers_count;
|
return response?.data.stargazers_count;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching repository data:", error);
|
console.error("Error fetching repository data:", error);
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -101,7 +101,7 @@ export async function getExamples(): Promise<FlowType[]> {
|
||||||
"https://api.github.com/repos/langflow-ai/langflow_examples/contents/examples?ref=main";
|
"https://api.github.com/repos/langflow-ai/langflow_examples/contents/examples?ref=main";
|
||||||
const response = await api.get(url);
|
const response = await api.get(url);
|
||||||
|
|
||||||
const jsonFiles = response.data.filter((file: any) => {
|
const jsonFiles = response?.data.filter((file: any) => {
|
||||||
return file.name.endsWith(".json");
|
return file.name.endsWith(".json");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -143,7 +143,7 @@ export async function saveFlowToDatabase(newFlow: {
|
||||||
if (response?.status !== 201) {
|
if (response?.status !== 201) {
|
||||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -168,10 +168,10 @@ export async function updateFlowInDatabase(
|
||||||
endpoint_name: updatedFlow.endpoint_name,
|
endpoint_name: updatedFlow.endpoint_name,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response?.status !== 200) {
|
if (response && response?.status !== 200) {
|
||||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -187,10 +187,10 @@ export async function updateFlowInDatabase(
|
||||||
export async function readFlowsFromDatabase() {
|
export async function readFlowsFromDatabase() {
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`${BASE_URL_API}flows/`);
|
const response = await api.get(`${BASE_URL_API}flows/`);
|
||||||
if (response?.status !== 200) {
|
if (response && response?.status !== 200) {
|
||||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -200,10 +200,10 @@ export async function readFlowsFromDatabase() {
|
||||||
export async function downloadFlowsFromDatabase() {
|
export async function downloadFlowsFromDatabase() {
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`${BASE_URL_API}flows/download/`);
|
const response = await api.get(`${BASE_URL_API}flows/download/`);
|
||||||
if (response?.status !== 200) {
|
if (response && response?.status !== 200) {
|
||||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -217,7 +217,7 @@ export async function uploadFlowsToDatabase(flows: FormData) {
|
||||||
if (response?.status !== 201) {
|
if (response?.status !== 201) {
|
||||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -237,7 +237,7 @@ export async function deleteFlowFromDatabase(flowId: string) {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -254,10 +254,10 @@ export async function deleteFlowFromDatabase(flowId: string) {
|
||||||
export async function getFlowFromDatabase(flowId: number) {
|
export async function getFlowFromDatabase(flowId: number) {
|
||||||
try {
|
try {
|
||||||
const response = await api.get(`${BASE_URL_API}flows/${flowId}`);
|
const response = await api.get(`${BASE_URL_API}flows/${flowId}`);
|
||||||
if (response?.status !== 200) {
|
if (response && response?.status !== 200) {
|
||||||
throw new Error(`HTTP error! status: ${response?.status}`);
|
throw new Error(`HTTP error! status: ${response?.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -276,7 +276,7 @@ export async function getFlowStylesFromDatabase() {
|
||||||
if (response.status !== 200) {
|
if (response.status !== 200) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -302,7 +302,7 @@ export async function saveFlowStyleToDatabase(flowStyle: FlowStyleType) {
|
||||||
if (response.status !== 201) {
|
if (response.status !== 201) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -316,7 +316,7 @@ export async function saveFlowStyleToDatabase(flowStyle: FlowStyleType) {
|
||||||
*/
|
*/
|
||||||
export async function getVersion() {
|
export async function getVersion() {
|
||||||
const response = await api.get(`${BASE_URL_API}version`);
|
const response = await api.get(`${BASE_URL_API}version`);
|
||||||
return response.data;
|
return response?.data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -416,7 +416,7 @@ export async function onLogin(user: LoginType) {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const data = response.data;
|
const data = response?.data;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -431,7 +431,7 @@ export async function autoLogin(abortSignal) {
|
||||||
});
|
});
|
||||||
|
|
||||||
if (response.status === 200) {
|
if (response.status === 200) {
|
||||||
const data = response.data;
|
const data = response?.data;
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -607,7 +607,7 @@ export async function saveFlowStore(
|
||||||
if (response.status !== 201) {
|
if (response.status !== 201) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -862,7 +862,7 @@ export async function updateFlowStore(
|
||||||
if (response.status !== 201) {
|
if (response.status !== 201) {
|
||||||
throw new Error(`HTTP error! status: ${response.status}`);
|
throw new Error(`HTTP error! status: ${response.status}`);
|
||||||
}
|
}
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -872,7 +872,7 @@ export async function updateFlowStore(
|
||||||
export async function requestLogout() {
|
export async function requestLogout() {
|
||||||
try {
|
try {
|
||||||
const response = await api.post(`${BASE_URL_API}logout`);
|
const response = await api.post(`${BASE_URL_API}logout`);
|
||||||
return response.data;
|
return response?.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error(error);
|
console.error(error);
|
||||||
throw error;
|
throw error;
|
||||||
|
|
@ -883,7 +883,7 @@ export async function getGlobalVariables(): Promise<{
|
||||||
[key: string]: { id: string; type: string; default_fields: string[] };
|
[key: string]: { id: string; type: string; default_fields: string[] };
|
||||||
}> {
|
}> {
|
||||||
const globalVariables = {};
|
const globalVariables = {};
|
||||||
(await api.get(`${BASE_URL_API}variables/`)).data.forEach((element) => {
|
(await api.get(`${BASE_URL_API}variables/`))?.data?.forEach((element) => {
|
||||||
globalVariables[element.name] = {
|
globalVariables[element.name] = {
|
||||||
id: element.id,
|
id: element.id,
|
||||||
type: element.type,
|
type: element.type,
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,7 @@ const useFlowsManagerStore = create<FlowsManagerStoreType>((set, get) => ({
|
||||||
},
|
},
|
||||||
currentFlow: undefined,
|
currentFlow: undefined,
|
||||||
saveLoading: false,
|
saveLoading: false,
|
||||||
|
setSaveLoading: (saveLoading: boolean) => set({ saveLoading }),
|
||||||
isLoading: true,
|
isLoading: true,
|
||||||
setIsLoading: (isLoading: boolean) => set({ isLoading }),
|
setIsLoading: (isLoading: boolean) => set({ isLoading }),
|
||||||
refreshFlows: () => {
|
refreshFlows: () => {
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,7 @@ export type FlowsManagerStoreType = {
|
||||||
currentFlowId: string;
|
currentFlowId: string;
|
||||||
setCurrentFlowId: (currentFlowId: string) => void;
|
setCurrentFlowId: (currentFlowId: string) => void;
|
||||||
saveLoading: boolean;
|
saveLoading: boolean;
|
||||||
|
setSaveLoading: (saveLoading: boolean) => void;
|
||||||
isLoading: boolean;
|
isLoading: boolean;
|
||||||
setIsLoading: (isLoading: boolean) => void;
|
setIsLoading: (isLoading: boolean) => void;
|
||||||
refreshFlows: () => Promise<void>;
|
refreshFlows: () => Promise<void>;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue