From a58b4cd36510fe566623b52118f04786c7b0ab68 Mon Sep 17 00:00:00 2001 From: cristhianzl Date: Wed, 31 Jul 2024 14:37:26 -0300 Subject: [PATCH 1/2] =?UTF-8?q?=E2=9C=A8=20(App.tsx):=20Add=20useGetGlobal?= =?UTF-8?q?Variables=20hook=20to=20fetch=20global=20variables=20data=20?= =?UTF-8?q?=F0=9F=94=A7=20(addNewVariableButton.tsx):=20Replace=20register?= =?UTF-8?q?GlobalVariable=20function=20with=20usePostGlobalVariables=20hoo?= =?UTF-8?q?k=20for=20adding=20new=20global=20variables=20=F0=9F=94=A7=20(i?= =?UTF-8?q?nputGlobalComponent/index.tsx):=20Replace=20deleteGlobalVariabl?= =?UTF-8?q?e=20function=20with=20useDeleteGlobalVariables=20hook=20for=20d?= =?UTF-8?q?eleting=20global=20variables=20=F0=9F=94=A7=20(authContext.tsx)?= =?UTF-8?q?:=20Remove=20unused=20getGlobalVariables=20function=20and=20set?= =?UTF-8?q?GlobalVariables=20state=20from=20authContext=20=F0=9F=94=A7=20(?= =?UTF-8?q?constants.ts):=20Add=20VARIABLES=20constant=20for=20global=20va?= =?UTF-8?q?riables=20endpoint=20=F0=9F=94=A7=20(index.ts):=20Remove=20getG?= =?UTF-8?q?lobalVariables,=20registerGlobalVariable,=20and=20deleteGlobalV?= =?UTF-8?q?ariable=20functions=20from=20API=20index=20=E2=9C=A8=20(variabl?= =?UTF-8?q?es/index.ts):=20Add=20use-delete-global-variables=20hook=20for?= =?UTF-8?q?=20deleting=20global=20variables=20=F0=9F=94=A7=20(use-delete-g?= =?UTF-8?q?lobal-variables.ts):=20Implement=20useDeleteGlobalVariables=20h?= =?UTF-8?q?ook=20for=20deleting=20global=20variables?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ✨ (use-get-global-variables.ts): Add functionality to fetch and set global variables from API ✨ (use-patch-global-variables.ts): Add functionality to update global variables via API patch request ✨ (use-post-global-variables.ts): Add functionality to create new global variables via API post request 📝 (index.tsx): Import useGetGlobalVariables hook to fetch global variables on login page 📝 (index.tsx): Call mutateGetGlobalVariables function to fetch global variables on successful login 📝 (index.tsx): Import useDeleteGlobalVariables hook to delete global variables on global variables page 📝 (index.tsx): Call mutateDeleteGlobalVariable function to delete selected global variables 📝 (index.tsx): Handle success and error cases for deleting global variables --- src/frontend/src/App.tsx | 5 ++ .../addNewVariableButton.tsx | 24 ++++++--- .../components/inputGlobalComponent/index.tsx | 35 ++++++------ src/frontend/src/contexts/authContext.tsx | 14 ++--- .../src/controllers/API/helpers/constants.ts | 1 + src/frontend/src/controllers/API/index.ts | 47 ---------------- .../API/queries/variables/index.ts | 4 ++ .../variables/use-delete-global-variables.ts | 31 +++++++++++ .../variables/use-get-global-variables.ts | 54 +++++++++++++++++++ .../variables/use-patch-global-variables.ts | 38 +++++++++++++ .../variables/use-post-global-variables.ts | 40 ++++++++++++++ .../src/pages/AdminPage/LoginPage/index.tsx | 5 ++ .../pages/GlobalVariablesPage/index.tsx | 33 ++++++------ 13 files changed, 237 insertions(+), 94 deletions(-) create mode 100644 src/frontend/src/controllers/API/queries/variables/index.ts create mode 100644 src/frontend/src/controllers/API/queries/variables/use-delete-global-variables.ts create mode 100644 src/frontend/src/controllers/API/queries/variables/use-get-global-variables.ts create mode 100644 src/frontend/src/controllers/API/queries/variables/use-patch-global-variables.ts create mode 100644 src/frontend/src/controllers/API/queries/variables/use-post-global-variables.ts diff --git a/src/frontend/src/App.tsx b/src/frontend/src/App.tsx index ca3447e97d0b..8ebcf8b94551 100644 --- a/src/frontend/src/App.tsx +++ b/src/frontend/src/App.tsx @@ -16,6 +16,7 @@ import { import { AuthContext } from "./contexts/authContext"; import { autoLogin } from "./controllers/API"; import { useGetHealthQuery } from "./controllers/API/queries/health"; +import { useGetGlobalVariables } from "./controllers/API/queries/variables"; import { useGetVersionQuery } from "./controllers/API/queries/version"; import { setupAxiosDefaults } from "./controllers/API/utils"; import useTrackLastVisitedPath from "./hooks/use-track-last-visited-path"; @@ -42,6 +43,8 @@ export default function App() { const isLoadingFolders = useFolderStore((state) => state.isLoadingFolders); + const { mutate: mutateGetGlobalVariables } = useGetGlobalVariables(); + const { data: healthData, isFetching: fetchingHealth, @@ -66,6 +69,7 @@ export default function App() { if (user && user["access_token"]) { user["refresh_token"] = "auto"; login(user["access_token"], "auto"); + mutateGetGlobalVariables(); setUserData(user); setAutoLogin(true); fetchAllData(); @@ -99,6 +103,7 @@ export default function App() { */ return () => abortController.abort(); }, []); + const fetchAllData = async () => { setTimeout(async () => { await Promise.all([refreshStars(), fetchData()]); diff --git a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx index 4dcda2deb9dc..b1d6ce0fed31 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx @@ -1,5 +1,5 @@ +import { usePostGlobalVariables } from "@/controllers/API/queries/variables"; import { useState } from "react"; -import { registerGlobalVariable } from "../../controllers/API"; import BaseModal from "../../modals/baseModal"; import useAlertStore from "../../stores/alertStore"; import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables"; @@ -28,6 +28,7 @@ export default function AddNewVariableButton({ const [open, setOpen] = useState(false); const setErrorData = useAlertStore((state) => state.setErrorData); const componentFields = useTypesStore((state) => state.ComponentFields); + const unavaliableFields = new Set( Object.keys( useGlobalVariablesStore((state) => state.unavaliableFields) ?? {}, @@ -46,6 +47,9 @@ export default function AddNewVariableButton({ (state) => state.addGlobalVariable, ); + const { mutate: mutateAddGlobalVariable } = usePostGlobalVariables(); + const setSuccessData = useAlertStore((state) => state.setSuccessData); + function handleSaveVariable() { let data: { name: string; @@ -58,8 +62,10 @@ export default function AddNewVariableButton({ value, default_fields: fields, }; - registerGlobalVariable(data) - .then((res) => { + console.log("here"); + + mutateAddGlobalVariable(data, { + onSuccess: (res) => { const { name, id, type } = res.data; addGlobalVariable(name, id, type, fields); setKey(""); @@ -67,8 +73,12 @@ export default function AddNewVariableButton({ setType(""); setFields([]); setOpen(false); - }) - .catch((error) => { + + setSuccessData({ + title: `Variable ${name} created successfully`, + }); + }, + onError: (error) => { let responseError = error as ResponseErrorDetailAPI; setErrorData({ title: "Error creating variable", @@ -77,8 +87,10 @@ export default function AddNewVariableButton({ "An unexpected error occurred while adding a new variable. Please try again.", ], }); - }); + }, + }); } + return ( state.setErrorData); + const { mutate: mutateDeleteGlobalVariable } = useDeleteGlobalVariables(); + useEffect(() => { if (data && globalVariablesEntries) if (data.load_from_db && !globalVariablesEntries.includes(data.value)) { @@ -38,19 +39,23 @@ export default function InputGlobalComponent({ async function handleDelete(key: string) { const id = getVariableId(key); if (id !== undefined) { - await deleteGlobalVariable(id) - .then(() => { - removeGlobalVariable(key); - if (data?.value === key && data?.load_from_db) { - onChange("", false); - } - }) - .catch(() => { - setErrorData({ - title: "Error deleting variable", - list: [cn("ID not found for variable: ", key)], - }); - }); + mutateDeleteGlobalVariable( + { id }, + { + onSuccess: () => { + removeGlobalVariable(key); + if (data?.value === key && data?.load_from_db) { + onChange("", false); + } + }, + onError: () => { + setErrorData({ + title: "Error deleting variable", + list: [cn("ID not found for variable: ", key)], + }); + }, + }, + ); } else { setErrorData({ title: "Error deleting variable", diff --git a/src/frontend/src/contexts/authContext.tsx b/src/frontend/src/contexts/authContext.tsx index 3521fe8b69a2..907ca0fd65b6 100644 --- a/src/frontend/src/contexts/authContext.tsx +++ b/src/frontend/src/contexts/authContext.tsx @@ -8,14 +8,9 @@ import useFlowsManagerStore from "@/stores/flowsManagerStore"; import { createContext, useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; import Cookies from "universal-cookie"; -import { - getGlobalVariables, - getLoggedUser, - requestLogout, -} from "../controllers/API"; +import { getLoggedUser, requestLogout } from "../controllers/API"; import useAlertStore from "../stores/alertStore"; import { useFolderStore } from "../stores/foldersStore"; -import { useGlobalVariablesStore } from "../stores/globalVariablesStore/globalVariables"; import { useStoreStore } from "../stores/storeStore"; import { Users } from "../types/api"; import { AuthContextType } from "../types/contexts/auth"; @@ -48,9 +43,7 @@ export function AuthProvider({ children }): React.ReactElement { ); const getFoldersApi = useFolderStore((state) => state.getFoldersApi); - const setGlobalVariables = useGlobalVariablesStore( - (state) => state.setGlobalVariables, - ); + const checkHasStore = useStoreStore((state) => state.checkHasStore); const fetchApiData = useStoreStore((state) => state.fetchApiData); const setAllFlows = useFlowsManagerStore((state) => state.setAllFlows); @@ -77,8 +70,7 @@ export function AuthProvider({ children }): React.ReactElement { const isSuperUser = user!.is_superuser; useAuthStore.getState().setIsAdmin(isSuperUser); getFoldersApi(true, true); - const res = await getGlobalVariables(); - setGlobalVariables(res); + checkHasStore(); fetchApiData(); }) diff --git a/src/frontend/src/controllers/API/helpers/constants.ts b/src/frontend/src/controllers/API/helpers/constants.ts index 2212023f0a98..4f54d7a78849 100644 --- a/src/frontend/src/controllers/API/helpers/constants.ts +++ b/src/frontend/src/controllers/API/helpers/constants.ts @@ -17,6 +17,7 @@ export const URLs = { CUSTOM_COMPONENT: `custom_component`, FLOWS: `flows`, FOLDERS: `folders`, + VARIABLES: `variables`, } as const; export function getURL(key: keyof typeof URLs, params: any = {}) { diff --git a/src/frontend/src/controllers/API/index.ts b/src/frontend/src/controllers/API/index.ts index 2b66670998e6..52ca5ba55a16 100644 --- a/src/frontend/src/controllers/API/index.ts +++ b/src/frontend/src/controllers/API/index.ts @@ -818,53 +818,6 @@ export async function requestLogout() { } } -export async function getGlobalVariables(): Promise<{ - [key: string]: { id: string; type: string; default_fields: string[] }; -}> { - const globalVariables = {}; - (await api.get(`${BASE_URL_API}variables/`))?.data?.forEach((element) => { - globalVariables[element.name] = { - id: element.id, - type: element.type, - default_fields: element.default_fields, - }; - }); - return globalVariables; -} - -export async function registerGlobalVariable({ - name, - value, - type, - default_fields = [], -}: { - name: string; - value: string; - type?: string; - default_fields?: string[]; -}): Promise> { - try { - const response = await api.post(`${BASE_URL_API}variables/`, { - name, - value, - type, - default_fields: default_fields, - }); - return response; - } catch (error) { - throw error; - } -} - -export async function deleteGlobalVariable(id: string) { - try { - const response = await api.delete(`${BASE_URL_API}variables/${id}`); - return response; - } catch (error) { - throw error; - } -} - export async function updateGlobalVariable( name: string, value: string, diff --git a/src/frontend/src/controllers/API/queries/variables/index.ts b/src/frontend/src/controllers/API/queries/variables/index.ts new file mode 100644 index 000000000000..47bccb23ceb1 --- /dev/null +++ b/src/frontend/src/controllers/API/queries/variables/index.ts @@ -0,0 +1,4 @@ +export * from "./use-delete-global-variables"; +export * from "./use-get-global-variables"; +export * from "./use-patch-global-variables"; +export * from "./use-post-global-variables"; diff --git a/src/frontend/src/controllers/API/queries/variables/use-delete-global-variables.ts b/src/frontend/src/controllers/API/queries/variables/use-delete-global-variables.ts new file mode 100644 index 000000000000..510956beeeea --- /dev/null +++ b/src/frontend/src/controllers/API/queries/variables/use-delete-global-variables.ts @@ -0,0 +1,31 @@ +import { useMutationFunctionType } from "@/types/api"; +import { UseMutationResult } from "@tanstack/react-query"; +import { api } from "../../api"; +import { getURL } from "../../helpers/constants"; +import { UseRequestProcessor } from "../../services/request-processor"; + +interface DeleteGlobalVariablesParams { + id: string | undefined; +} + +export const useDeleteGlobalVariables: useMutationFunctionType< + undefined, + DeleteGlobalVariablesParams +> = (options?) => { + const { mutate } = UseRequestProcessor(); + + const deleteGlobalVariables = async ({ + id, + }: DeleteGlobalVariablesParams): Promise => { + const res = await api.delete(`${getURL("VARIABLES")}/${id}`); + return res.data; + }; + + const mutation: UseMutationResult< + DeleteGlobalVariablesParams, + any, + DeleteGlobalVariablesParams + > = mutate(["useDeleteGlobalVariables"], deleteGlobalVariables, options); + + return mutation; +}; diff --git a/src/frontend/src/controllers/API/queries/variables/use-get-global-variables.ts b/src/frontend/src/controllers/API/queries/variables/use-get-global-variables.ts new file mode 100644 index 000000000000..5b5df35cf91e --- /dev/null +++ b/src/frontend/src/controllers/API/queries/variables/use-get-global-variables.ts @@ -0,0 +1,54 @@ +import { useGlobalVariablesStore } from "@/stores/globalVariablesStore/globalVariables"; +import { useMutationFunctionType } from "@/types/api"; +import { UseMutationResult } from "@tanstack/react-query"; +import { api } from "../../api"; +import { getURL } from "../../helpers/constants"; +import { UseRequestProcessor } from "../../services/request-processor"; + +type GlobalVariable = { + id: string; + type: string; + default_fields: string[]; + name: string; +}; + +export const useGetGlobalVariables: useMutationFunctionType = ( + options?, +) => { + const { mutate } = UseRequestProcessor(); + + const setGlobalVariables = useGlobalVariablesStore( + (state) => state.setGlobalVariables, + ); + + const getGlobalVariables = async (): Promise<[GlobalVariable]> => { + const res = await api.get(`${getURL("VARIABLES")}/`); + return res.data; + }; + + const getGlobalVariablesFn = async (): Promise<{ + [key: string]: GlobalVariable; + }> => { + const data = await getGlobalVariables(); + const globalVariables = {}; + + data?.forEach((element) => { + globalVariables[element.name] = { + id: element.id, + type: element.type, + default_fields: element.default_fields, + }; + }); + + setGlobalVariables(globalVariables); + return globalVariables; + }; + + const mutation: UseMutationResult = mutate( + ["useGetGlobalVariables"], + getGlobalVariablesFn, + options, + ); + + return mutation; +}; diff --git a/src/frontend/src/controllers/API/queries/variables/use-patch-global-variables.ts b/src/frontend/src/controllers/API/queries/variables/use-patch-global-variables.ts new file mode 100644 index 000000000000..bc2eac5e19cc --- /dev/null +++ b/src/frontend/src/controllers/API/queries/variables/use-patch-global-variables.ts @@ -0,0 +1,38 @@ +import { changeUser, useMutationFunctionType } from "@/types/api"; +import { UseMutationResult } from "@tanstack/react-query"; +import { api } from "../../api"; +import { getURL } from "../../helpers/constants"; +import { UseRequestProcessor } from "../../services/request-processor"; + +interface PatchGlobalVariablesParams { + name: string; + value: string; + id: string; +} + +export const usePatchGlobalVariables: useMutationFunctionType< + undefined, + PatchGlobalVariablesParams +> = (options?) => { + const { mutate } = UseRequestProcessor(); + + async function patchGlobalVariables({ + name, + value, + id, + }: PatchGlobalVariablesParams): Promise { + const res = await api.patch(`${getURL("VARIABLES")}/${id}`, { + name, + value, + }); + return res.data; + } + + const mutation: UseMutationResult< + PatchGlobalVariablesParams, + any, + PatchGlobalVariablesParams + > = mutate(["usePatchGlobalVariables"], patchGlobalVariables, options); + + return mutation; +}; diff --git a/src/frontend/src/controllers/API/queries/variables/use-post-global-variables.ts b/src/frontend/src/controllers/API/queries/variables/use-post-global-variables.ts new file mode 100644 index 000000000000..937954accb82 --- /dev/null +++ b/src/frontend/src/controllers/API/queries/variables/use-post-global-variables.ts @@ -0,0 +1,40 @@ +import { useMutationFunctionType } from "@/types/api"; +import { UseMutationResult } from "@tanstack/react-query"; +import { AxiosResponse } from "axios"; +import { api } from "../../api"; +import { getURL } from "../../helpers/constants"; +import { UseRequestProcessor } from "../../services/request-processor"; + +interface PostGlobalVariablesParams { + name: string; + value: string; + type?: string; + default_fields?: string[]; +} + +export const usePostGlobalVariables: useMutationFunctionType< + undefined, + PostGlobalVariablesParams +> = (options?) => { + const { mutate } = UseRequestProcessor(); + + const postGlobalVariablesFunction = async ({ + name, + value, + type, + default_fields = [], + }): Promise> => { + const res = await api.post(`${getURL("VARIABLES")}`, { + name, + value, + type, + default_fields: default_fields, + }); + return res; + }; + + const mutation: UseMutationResult = + mutate(["usePostGlobalVariables"], postGlobalVariablesFunction, options); + + return mutation; +}; diff --git a/src/frontend/src/pages/AdminPage/LoginPage/index.tsx b/src/frontend/src/pages/AdminPage/LoginPage/index.tsx index c6ce32c30d2e..e4cccd574b8f 100644 --- a/src/frontend/src/pages/AdminPage/LoginPage/index.tsx +++ b/src/frontend/src/pages/AdminPage/LoginPage/index.tsx @@ -1,3 +1,4 @@ +import { useGetGlobalVariables } from "@/controllers/API/queries/variables"; import { useContext, useState } from "react"; import { useNavigate } from "react-router-dom"; import { Button } from "../../../components/ui/button"; @@ -21,6 +22,8 @@ export default function LoginAdminPage() { const { login } = useContext(AuthContext); const setLoading = useAlertStore((state) => state.setLoading); + const { mutate: mutateGetGlobalVariables } = useGetGlobalVariables(); + const { password, username } = inputState; const setErrorData = useAlertStore((state) => state.setErrorData); function handleInput({ @@ -41,6 +44,8 @@ export default function LoginAdminPage() { setLoading(true); login(user.access_token, "login"); + mutateGetGlobalVariables(); + navigate("/admin/"); }) .catch((error) => { diff --git a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx index 6f0dac836c98..51d3fa3f90f5 100644 --- a/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx +++ b/src/frontend/src/pages/SettingsPage/pages/GlobalVariablesPage/index.tsx @@ -1,6 +1,7 @@ import IconComponent from "../../../../components/genericIconComponent"; import { Button } from "../../../../components/ui/button"; +import { useDeleteGlobalVariables } from "@/controllers/API/queries/variables"; import { ColDef, ColGroupDef, SelectionChangedEvent } from "ag-grid-community"; import { useEffect, useState } from "react"; import AddNewVariableButton from "../../../../components/addNewVariableButtonComponent/addNewVariableButton"; @@ -8,7 +9,6 @@ import Dropdown from "../../../../components/dropdownComponent"; import ForwardedIconComponent from "../../../../components/genericIconComponent"; import TableComponent from "../../../../components/tableComponent"; import { Badge } from "../../../../components/ui/badge"; -import { deleteGlobalVariable } from "../../../../controllers/API"; import useAlertStore from "../../../../stores/alertStore"; import { useGlobalVariablesStore } from "../../../../stores/globalVariablesStore/globalVariables"; @@ -108,23 +108,26 @@ export default function GlobalVariablesPage() { const [selectedRows, setSelectedRows] = useState([]); + const { mutate: mutateDeleteGlobalVariable } = useDeleteGlobalVariables(); + async function removeVariables() { - const deleteGlobalVariablesPromise = selectedRows.map(async (row) => { + selectedRows.map(async (row) => { const id = getVariableId(row); - const deleteGlobalVariables = deleteGlobalVariable(id!); - await deleteGlobalVariables; + mutateDeleteGlobalVariable( + { id }, + { + onSuccess: () => { + removeGlobalVariable(row); + }, + onError: () => { + setErrorData({ + title: `Error deleting variable`, + list: [`ID not found for variable: ${row}`], + }); + }, + }, + ); }); - Promise.all(deleteGlobalVariablesPromise) - .then(() => { - selectedRows.forEach((row) => { - removeGlobalVariable(row); - }); - }) - .catch(() => { - setErrorData({ - title: `Error deleting global variables.`, - }); - }); } return ( From 9af94d5dae6771cb639714489255ad2013e6657b Mon Sep 17 00:00:00 2001 From: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com> Date: Wed, 31 Jul 2024 15:15:39 -0300 Subject: [PATCH 2/2] Removed console.log --- .../addNewVariableButtonComponent/addNewVariableButton.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx index b1d6ce0fed31..a2aff271393c 100644 --- a/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx +++ b/src/frontend/src/components/addNewVariableButtonComponent/addNewVariableButton.tsx @@ -62,7 +62,6 @@ export default function AddNewVariableButton({ value, default_fields: fields, }; - console.log("here"); mutateAddGlobalVariable(data, { onSuccess: (res) => {