refactor: add useQuery management on globalVariables CRUD (#3121)

* ✨ (App.tsx): Add useGetGlobalVariables hook to fetch global variables data
🔧 (addNewVariableButton.tsx): Replace registerGlobalVariable function with usePostGlobalVariables hook for adding new global variables
🔧 (inputGlobalComponent/index.tsx): Replace deleteGlobalVariable function with useDeleteGlobalVariables hook for deleting global variables
🔧 (authContext.tsx): Remove unused getGlobalVariables function and setGlobalVariables state from authContext
🔧 (constants.ts): Add VARIABLES constant for global variables endpoint
🔧 (index.ts): Remove getGlobalVariables, registerGlobalVariable, and deleteGlobalVariable functions from API index
✨ (variables/index.ts): Add use-delete-global-variables hook for deleting global variables
🔧 (use-delete-global-variables.ts): Implement useDeleteGlobalVariables hook for deleting global variables

✨ (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

* Removed console.log

---------

Co-authored-by: Lucas Oliveira <62335616+lucaseduoli@users.noreply.github.com>
This commit is contained in:
Cristhian Zanforlin Lousa 2024-07-31 16:49:54 -03:00 • committed by GitHub
commit 61c921e1ae
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 236 additions and 94 deletions

View file

@ -16,6 +16,7 @@ import {
import { AuthContext } from "./contexts/authContext"; import { AuthContext } from "./contexts/authContext";
import { autoLogin } from "./controllers/API"; import { autoLogin } from "./controllers/API";
import { useGetHealthQuery } from "./controllers/API/queries/health"; import { useGetHealthQuery } from "./controllers/API/queries/health";
import { useGetGlobalVariables } from "./controllers/API/queries/variables";
import { useGetVersionQuery } from "./controllers/API/queries/version"; import { useGetVersionQuery } from "./controllers/API/queries/version";
import { setupAxiosDefaults } from "./controllers/API/utils"; import { setupAxiosDefaults } from "./controllers/API/utils";
import useTrackLastVisitedPath from "./hooks/use-track-last-visited-path"; import useTrackLastVisitedPath from "./hooks/use-track-last-visited-path";
@ -42,6 +43,8 @@ export default function App() {
const isLoadingFolders = useFolderStore((state) => state.isLoadingFolders); const isLoadingFolders = useFolderStore((state) => state.isLoadingFolders);
const { mutate: mutateGetGlobalVariables } = useGetGlobalVariables();
const { const {
data: healthData, data: healthData,
isFetching: fetchingHealth, isFetching: fetchingHealth,
@ -66,6 +69,7 @@ export default function App() {
if (user && user["access_token"]) { if (user && user["access_token"]) {
user["refresh_token"] = "auto"; user["refresh_token"] = "auto";
login(user["access_token"], "auto"); login(user["access_token"], "auto");
mutateGetGlobalVariables();
setUserData(user); setUserData(user);
setAutoLogin(true); setAutoLogin(true);
fetchAllData(); fetchAllData();
@ -99,6 +103,7 @@ export default function App() {
*/ */
return () => abortController.abort(); return () => abortController.abort();
}, []); }, []);
const fetchAllData = async () => { const fetchAllData = async () => {
setTimeout(async () => { setTimeout(async () => {
await Promise.all([refreshStars(), fetchData()]); await Promise.all([refreshStars(), fetchData()]);

View file

@ -1,5 +1,5 @@
import { usePostGlobalVariables } from "@/controllers/API/queries/variables";
import { useState } from "react"; import { useState } from "react";
import { registerGlobalVariable } from "../../controllers/API";
import BaseModal from "../../modals/baseModal"; import BaseModal from "../../modals/baseModal";
import useAlertStore from "../../stores/alertStore"; import useAlertStore from "../../stores/alertStore";
import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables"; import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables";
@ -28,6 +28,7 @@ export default function AddNewVariableButton({
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const componentFields = useTypesStore((state) => state.ComponentFields); const componentFields = useTypesStore((state) => state.ComponentFields);
const unavaliableFields = new Set( const unavaliableFields = new Set(
Object.keys( Object.keys(
useGlobalVariablesStore((state) => state.unavaliableFields) ?? {}, useGlobalVariablesStore((state) => state.unavaliableFields) ?? {},
@ -46,6 +47,9 @@ export default function AddNewVariableButton({
(state) => state.addGlobalVariable, (state) => state.addGlobalVariable,
); );
const { mutate: mutateAddGlobalVariable } = usePostGlobalVariables();
const setSuccessData = useAlertStore((state) => state.setSuccessData);
function handleSaveVariable() { function handleSaveVariable() {
let data: { let data: {
name: string; name: string;
@ -58,8 +62,9 @@ export default function AddNewVariableButton({
value, value,
default_fields: fields, default_fields: fields,
}; };
registerGlobalVariable(data)
.then((res) => { mutateAddGlobalVariable(data, {
onSuccess: (res) => {
const { name, id, type } = res.data; const { name, id, type } = res.data;
addGlobalVariable(name, id, type, fields); addGlobalVariable(name, id, type, fields);
setKey(""); setKey("");
@ -67,8 +72,12 @@ export default function AddNewVariableButton({
setType(""); setType("");
setFields([]); setFields([]);
setOpen(false); setOpen(false);
})
.catch((error) => { setSuccessData({
title: `Variable ${name} created successfully`,
});
},
onError: (error) => {
let responseError = error as ResponseErrorDetailAPI; let responseError = error as ResponseErrorDetailAPI;
setErrorData({ setErrorData({
title: "Error creating variable", title: "Error creating variable",
@ -77,8 +86,10 @@ export default function AddNewVariableButton({
"An unexpected error occurred while adding a new variable. Please try again.", "An unexpected error occurred while adding a new variable. Please try again.",
], ],
}); });
}); },
});
} }
return ( return (
<BaseModal <BaseModal
open={open} open={open}

View file

@ -1,6 +1,5 @@
import { useDeleteGlobalVariables } from "@/controllers/API/queries/variables";
import { useEffect } from "react"; import { useEffect } from "react";
import { Controller } from "react-hook-form";
import { deleteGlobalVariable } from "../../controllers/API";
import DeleteConfirmationModal from "../../modals/deleteConfirmationModal"; import DeleteConfirmationModal from "../../modals/deleteConfirmationModal";
import useAlertStore from "../../stores/alertStore"; import useAlertStore from "../../stores/alertStore";
import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables"; import { useGlobalVariablesStore } from "../../stores/globalVariablesStore/globalVariables";
@ -28,6 +27,8 @@ export default function InputGlobalComponent({
); );
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
const { mutate: mutateDeleteGlobalVariable } = useDeleteGlobalVariables();
useEffect(() => { useEffect(() => {
if (data && globalVariablesEntries) if (data && globalVariablesEntries)
if (data.load_from_db && !globalVariablesEntries.includes(data.value)) { if (data.load_from_db && !globalVariablesEntries.includes(data.value)) {
@ -38,19 +39,23 @@ export default function InputGlobalComponent({
async function handleDelete(key: string) { async function handleDelete(key: string) {
const id = getVariableId(key); const id = getVariableId(key);
if (id !== undefined) { if (id !== undefined) {
await deleteGlobalVariable(id) mutateDeleteGlobalVariable(
.then(() => { { id },
removeGlobalVariable(key); {
if (data?.value === key && data?.load_from_db) { onSuccess: () => {
onChange("", false); removeGlobalVariable(key);
} if (data?.value === key && data?.load_from_db) {
}) onChange("", false);
.catch(() => { }
setErrorData({ },
title: "Error deleting variable", onError: () => {
list: [cn("ID not found for variable: ", key)], setErrorData({
}); title: "Error deleting variable",
}); list: [cn("ID not found for variable: ", key)],
});
},
},
);
} else { } else {
setErrorData({ setErrorData({
title: "Error deleting variable", title: "Error deleting variable",

View file

@ -8,14 +8,9 @@ import useFlowsManagerStore from "@/stores/flowsManagerStore";
import { createContext, useEffect, useState } from "react"; import { createContext, useEffect, useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import Cookies from "universal-cookie"; import Cookies from "universal-cookie";
import { import { getLoggedUser, requestLogout } from "../controllers/API";
getGlobalVariables,
getLoggedUser,
requestLogout,
} from "../controllers/API";
import useAlertStore from "../stores/alertStore"; import useAlertStore from "../stores/alertStore";
import { useFolderStore } from "../stores/foldersStore"; import { useFolderStore } from "../stores/foldersStore";
import { useGlobalVariablesStore } from "../stores/globalVariablesStore/globalVariables";
import { useStoreStore } from "../stores/storeStore"; import { useStoreStore } from "../stores/storeStore";
import { Users } from "../types/api"; import { Users } from "../types/api";
import { AuthContextType } from "../types/contexts/auth"; import { AuthContextType } from "../types/contexts/auth";
@ -48,9 +43,7 @@ export function AuthProvider({ children }): React.ReactElement {
); );
const getFoldersApi = useFolderStore((state) => state.getFoldersApi); const getFoldersApi = useFolderStore((state) => state.getFoldersApi);
const setGlobalVariables = useGlobalVariablesStore(
(state) => state.setGlobalVariables,
);
const checkHasStore = useStoreStore((state) => state.checkHasStore); const checkHasStore = useStoreStore((state) => state.checkHasStore);
const fetchApiData = useStoreStore((state) => state.fetchApiData); const fetchApiData = useStoreStore((state) => state.fetchApiData);
const setAllFlows = useFlowsManagerStore((state) => state.setAllFlows); const setAllFlows = useFlowsManagerStore((state) => state.setAllFlows);
@ -77,8 +70,7 @@ export function AuthProvider({ children }): React.ReactElement {
const isSuperUser = user!.is_superuser; const isSuperUser = user!.is_superuser;
useAuthStore.getState().setIsAdmin(isSuperUser); useAuthStore.getState().setIsAdmin(isSuperUser);
getFoldersApi(true, true); getFoldersApi(true, true);
const res = await getGlobalVariables();
setGlobalVariables(res);
checkHasStore(); checkHasStore();
fetchApiData(); fetchApiData();
}) })

View file

@ -17,6 +17,7 @@ export const URLs = {
CUSTOM_COMPONENT: `custom_component`, CUSTOM_COMPONENT: `custom_component`,
FLOWS: `flows`, FLOWS: `flows`,
FOLDERS: `folders`, FOLDERS: `folders`,
VARIABLES: `variables`,
} as const; } as const;
export function getURL(key: keyof typeof URLs, params: any = {}) { export function getURL(key: keyof typeof URLs, params: any = {}) {

View file

@ -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<AxiosResponse<{ name: string; id: string; type: string }>> {
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( export async function updateGlobalVariable(
name: string, name: string,
value: string, value: string,

View file

@ -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";

View file

@ -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<any> => {
const res = await api.delete(`${getURL("VARIABLES")}/${id}`);
return res.data;
};
const mutation: UseMutationResult<
DeleteGlobalVariablesParams,
any,
DeleteGlobalVariablesParams
> = mutate(["useDeleteGlobalVariables"], deleteGlobalVariables, options);
return mutation;
};

View file

@ -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<undefined, void> = (
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<any, any, any> = mutate(
["useGetGlobalVariables"],
getGlobalVariablesFn,
options,
);
return mutation;
};

View file

@ -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<any> {
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;
};

View file

@ -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<AxiosResponse<{ name: string; id: string; type: string }>> => {
const res = await api.post(`${getURL("VARIABLES")}`, {
name,
value,
type,
default_fields: default_fields,
});
return res;
};
const mutation: UseMutationResult<any, any, PostGlobalVariablesParams> =
mutate(["usePostGlobalVariables"], postGlobalVariablesFunction, options);
return mutation;
};

View file

@ -1,3 +1,4 @@
import { useGetGlobalVariables } from "@/controllers/API/queries/variables";
import { useContext, useState } from "react"; import { useContext, useState } from "react";
import { useNavigate } from "react-router-dom"; import { useNavigate } from "react-router-dom";
import { Button } from "../../../components/ui/button"; import { Button } from "../../../components/ui/button";
@ -21,6 +22,8 @@ export default function LoginAdminPage() {
const { login } = useContext(AuthContext); const { login } = useContext(AuthContext);
const setLoading = useAlertStore((state) => state.setLoading); const setLoading = useAlertStore((state) => state.setLoading);
const { mutate: mutateGetGlobalVariables } = useGetGlobalVariables();
const { password, username } = inputState; const { password, username } = inputState;
const setErrorData = useAlertStore((state) => state.setErrorData); const setErrorData = useAlertStore((state) => state.setErrorData);
function handleInput({ function handleInput({
@ -41,6 +44,8 @@ export default function LoginAdminPage() {
setLoading(true); setLoading(true);
login(user.access_token, "login"); login(user.access_token, "login");
mutateGetGlobalVariables();
navigate("/admin/"); navigate("/admin/");
}) })
.catch((error) => { .catch((error) => {

View file

@ -1,6 +1,7 @@
import IconComponent from "../../../../components/genericIconComponent"; import IconComponent from "../../../../components/genericIconComponent";
import { Button } from "../../../../components/ui/button"; import { Button } from "../../../../components/ui/button";
import { useDeleteGlobalVariables } from "@/controllers/API/queries/variables";
import { ColDef, ColGroupDef, SelectionChangedEvent } from "ag-grid-community"; import { ColDef, ColGroupDef, SelectionChangedEvent } from "ag-grid-community";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import AddNewVariableButton from "../../../../components/addNewVariableButtonComponent/addNewVariableButton"; import AddNewVariableButton from "../../../../components/addNewVariableButtonComponent/addNewVariableButton";
@ -8,7 +9,6 @@ import Dropdown from "../../../../components/dropdownComponent";
import ForwardedIconComponent from "../../../../components/genericIconComponent"; import ForwardedIconComponent from "../../../../components/genericIconComponent";
import TableComponent from "../../../../components/tableComponent"; import TableComponent from "../../../../components/tableComponent";
import { Badge } from "../../../../components/ui/badge"; import { Badge } from "../../../../components/ui/badge";
import { deleteGlobalVariable } from "../../../../controllers/API";
import useAlertStore from "../../../../stores/alertStore"; import useAlertStore from "../../../../stores/alertStore";
import { useGlobalVariablesStore } from "../../../../stores/globalVariablesStore/globalVariables"; import { useGlobalVariablesStore } from "../../../../stores/globalVariablesStore/globalVariables";
@ -108,23 +108,26 @@ export default function GlobalVariablesPage() {
const [selectedRows, setSelectedRows] = useState<string[]>([]); const [selectedRows, setSelectedRows] = useState<string[]>([]);
const { mutate: mutateDeleteGlobalVariable } = useDeleteGlobalVariables();
async function removeVariables() { async function removeVariables() {
const deleteGlobalVariablesPromise = selectedRows.map(async (row) => { selectedRows.map(async (row) => {
const id = getVariableId(row); const id = getVariableId(row);
const deleteGlobalVariables = deleteGlobalVariable(id!); mutateDeleteGlobalVariable(
await deleteGlobalVariables; { 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 ( return (