+ {body} +
+ ); +}); +FormMessage.displayName = "FormMessage"; + +export { + Form, + FormControl, + FormDescription, + FormField, + FormItem, + FormLabel, + FormMessage, + useFormField, +}; diff --git a/src/frontend/src/constants/constants.ts b/src/frontend/src/constants/constants.ts index da2ad92be..4803a3d28 100644 --- a/src/frontend/src/constants/constants.ts +++ b/src/frontend/src/constants/constants.ts @@ -95,6 +95,12 @@ export const EXPORT_DIALOG_SUBTITLE = "Export flow as JSON file."; */ export const SETTINGS_DIALOG_SUBTITLE = "Edit details about your project."; +/** + * The base text for subtitle of Flow Logs (Menubar) + * @constant + */ +export const LOGS_DIALOG_SUBTITLE = "Check out information about your flow."; + /** * The base text for subtitle of Code Dialog (Toolbar) * @constant @@ -125,7 +131,6 @@ export const CODE_PROMPT_DIALOG_SUBTITLE = export const CODE_DICT_DIALOG_SUBTITLE = "Edit your dictionary. This dialog allows you to create your own customized dictionary. You can add as many key-value pairs as you want. While in edit mode, you can enter ({}) or ([]), and this will result in adding a new object or array."; - /** * The base text for subtitle of Prompt Dialog * @constant @@ -533,6 +538,8 @@ export const NOUNS: string[] = [ */ export const USER_PROJECTS_HEADER = "My Collection"; +export const DEFAULT_FOLDER = "My Projects"; + /** * Header text for admin page * @constant @@ -727,6 +734,8 @@ export const OUTPUT_TYPES = new Set([ "JsonOutput", "KeyPairOutput", "StringListOutput", + "RecordsOutput", + "TableOutput", ]); export const CHAT_FIRST_INITIAL_TEXT = @@ -746,8 +755,8 @@ export const EDIT_TEXT_MODAL_TITLE = "Edit Text"; export const EDIT_TEXT_PLACEHOLDER = "Type message here."; export const INPUT_HANDLER_HOVER = "Avaliable input components:"; export const OUTPUT_HANDLER_HOVER = "Avaliable output components:"; -export const TEXT_INPUT_MODAL_TITLE = "Text Inputs"; -export const OUTPUTS_MODAL_TITLE = "Text Outputs"; +export const TEXT_INPUT_MODAL_TITLE = "Inputs"; +export const OUTPUTS_MODAL_TITLE = "Outputs"; export const LANGFLOW_CHAT_TITLE = "Langflow Chat"; export const CHAT_INPUT_PLACEHOLDER = "No chat input variables found. Click to run your flow."; @@ -888,3 +897,6 @@ export const unavailableShortcutss = [ "CTRL + J", "CTRL + U", ]; +export const DEFAULT_TABLE_ALERT_MSG = `Oops! It seems there's no data to display right now. Please check back later.`; + +export const DEFAULT_TABLE_ALERT_TITLE = "No Data Available"; diff --git a/src/frontend/src/controllers/API/api.tsx b/src/frontend/src/controllers/API/api.tsx index 8084dfeb9..529a2f623 100644 --- a/src/frontend/src/controllers/API/api.tsx +++ b/src/frontend/src/controllers/API/api.tsx @@ -22,7 +22,10 @@ function ApiInterceptor() { const interceptor = api.interceptors.response.use( (response) => response, async (error: AxiosError) => { - if (error.response?.status === 403 || error.response?.status === 401) { + if ( + error?.response?.status === 403 || + error?.response?.status === 401 + ) { if (!autoLogin) { if (error?.config?.url?.includes("github")) { return Promise.reject(error); @@ -44,7 +47,7 @@ function ApiInterceptor() { } await clearBuildVerticesState(error); return Promise.reject(error); - } + }, ); const isAuthorizedURL = (url) => { @@ -61,10 +64,10 @@ function ApiInterceptor() { const parsedURL = new URL(url); const isDomainAllowed = authorizedDomains.some( - (domain) => parsedURL.origin === new URL(domain).origin + (domain) => parsedURL.origin === new URL(domain).origin, ); const isEndpointAllowed = authorizedEndpoints.some((endpoint) => - parsedURL.pathname.includes(endpoint) + parsedURL.pathname.includes(endpoint), ); return isDomainAllowed || isEndpointAllowed; @@ -77,6 +80,18 @@ function ApiInterceptor() { // Request interceptor to add access token to every request const requestInterceptor = api.interceptors.request.use( (config) => { + const lastUrl = localStorage.getItem("lastUrlCalled"); + + if ( + config?.url === lastUrl && + config?.url !== "/health" && + config?.method === "get" + ) { + return Promise.reject("Duplicate request"); + } + + localStorage.setItem("lastUrlCalled", config.url ?? ""); + const accessToken = cookies.get("access_token_lf"); if (accessToken && !isAuthorizedURL(config?.url)) { config.headers["Authorization"] = `Bearer ${accessToken}`; @@ -86,7 +101,7 @@ function ApiInterceptor() { }, (error) => { return Promise.reject(error); - } + }, ); return () => { @@ -118,7 +133,7 @@ function ApiInterceptor() { if (error?.config?.headers) { delete error.config.headers["Authorization"]; error.config.headers["Authorization"] = `Bearer ${cookies.get( - "access_token_lf" + "access_token_lf", )}`; const response = await axios.request(error.config); return response; diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 787dc7664..b6dc2ef86 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -1,5 +1,6 @@ +import { ColDef, ColGroupDef } from "ag-grid-community"; import { AxiosRequestConfig, AxiosResponse } from "axios"; -import { Edge, ReactFlowJsonObject,Node } from "reactflow"; +import { Edge, Node, ReactFlowJsonObject } from "reactflow"; import { BASE_URL_API } from "../../constants/constants"; import { api } from "../../controllers/API/api"; import { @@ -18,6 +19,7 @@ import { UserInputType } from "../../types/components"; import { FlowStyleType, FlowType } from "../../types/flow"; import { StoreComponentResponse } from "../../types/store"; import { FlowPoolType } from "../../types/zustand/flow"; +import { extractColumnsFromRows } from "../../utils/utils"; import { APIClassType, BuildStatusTypeAPI, @@ -59,7 +61,7 @@ export async function sendAll(data: sendAllProps) { } export async function postValidateCode( - code: string + code: string, ): Promise