From eb0e61e95a55f648d3b87bdc86154ff05dfeee3f Mon Sep 17 00:00:00 2001 From: Devin Villarosa Date: Thu, 28 Nov 2024 14:24:38 -0800 Subject: [PATCH 1/3] [UI v2] poc: Re-organize variable queries and mutations using queryOptions factory pattern --- ui-v2/eslint.config.js | 2 + ui-v2/package-lock.json | 164 +++++++++++++++++++++++++ ui-v2/package.json | 1 + ui-v2/src/hooks/variables.ts | 226 +++++++++++++++++------------------ 4 files changed, 277 insertions(+), 116 deletions(-) diff --git a/ui-v2/eslint.config.js b/ui-v2/eslint.config.js index 1be368f4b886..bef636a21566 100644 --- a/ui-v2/eslint.config.js +++ b/ui-v2/eslint.config.js @@ -7,6 +7,7 @@ import globals from "globals"; import tseslint from "typescript-eslint"; import testingLibrary from "eslint-plugin-testing-library"; import jestDom from "eslint-plugin-jest-dom"; +import pluginQuery from "@tanstack/eslint-plugin-query"; export default tseslint.config( { ignores: ["dist", "src/api/prefect.ts"] }, @@ -14,6 +15,7 @@ export default tseslint.config( extends: [ js.configs.recommended, ...tseslint.configs.recommendedTypeChecked, + ...pluginQuery.configs["flat/recommended"], ], files: ["**/*.{ts,tsx}"], languageOptions: { diff --git a/ui-v2/package-lock.json b/ui-v2/package-lock.json index 1f27c879a097..3f1cee99dea3 100644 --- a/ui-v2/package-lock.json +++ b/ui-v2/package-lock.json @@ -54,6 +54,7 @@ "@storybook/react": "^8.4.2", "@storybook/react-vite": "^8.4.2", "@storybook/test": "^8.4.2", + "@tanstack/eslint-plugin-query": "^5.61.6", "@tanstack/eslint-plugin-router": "^1.77.7", "@tanstack/router-devtools": "^1.58.15", "@tanstack/router-plugin": "^1.58.12", @@ -3767,6 +3768,169 @@ "@swc/counter": "^0.1.3" } }, + "node_modules/@tanstack/eslint-plugin-query": { + "version": "5.61.6", + "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.61.6.tgz", + "integrity": "sha512-39DEve67KRcUOv4WI3svSyKzFGEhPTH4gzy99UBh2PmrDOUvAjfG59zSheNJFLHHokpSOQYJhFRNuMlC00CBMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/utils": "^8.15.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/scope-manager": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.16.0.tgz", + "integrity": "sha512-mwsZWubQvBki2t5565uxF0EYvG+FwdFb8bMtDuGQLdCCnGPrDEDvm1gtfynuKlnpzeBRqdFCkMf9jg1fnAK8sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/types": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.16.0.tgz", + "integrity": "sha512-NzrHj6thBAOSE4d9bsuRNMvk+BvaQvmY4dDglgkgGC0EW/tB3Kelnp3tAKH87GEwzoxgeQn9fNGRyFJM/xd+GQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/typescript-estree": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.16.0.tgz", + "integrity": "sha512-E2+9IzzXMc1iaBy9zmo+UYvluE3TW7bCGWSF41hVWUE01o8nzr1rvOQYSxelxr6StUvRcTMe633eY8mXASMaNw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/visitor-keys": "8.16.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/utils": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz", + "integrity": "sha512-C1zRy/mOL8Pj157GiX4kaw7iyRLKfJXBR3L82hk5kS/GyHcOFmy4YUq/zfZti72I9wnuQtA/+xzft4wCC8PJdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.16.0", + "@typescript-eslint/types": "8.16.0", + "@typescript-eslint/typescript-estree": "8.16.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/@typescript-eslint/visitor-keys": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.16.0.tgz", + "integrity": "sha512-pq19gbaMOmFE3CbL0ZB8J8BFCo2ckfHBfaIsaOZgBIF4EoISJIdLX5xRhd0FGB0LlHReNRuzoJoMGpTjq8F2CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.16.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@tanstack/eslint-plugin-query/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/@tanstack/eslint-plugin-router": { "version": "1.77.7", "resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-router/-/eslint-plugin-router-1.77.7.tgz", diff --git a/ui-v2/package.json b/ui-v2/package.json index 4b3925f52bfc..0a8658674491 100644 --- a/ui-v2/package.json +++ b/ui-v2/package.json @@ -64,6 +64,7 @@ "@storybook/react": "^8.4.2", "@storybook/react-vite": "^8.4.2", "@storybook/test": "^8.4.2", + "@tanstack/eslint-plugin-query": "^5.61.6", "@tanstack/eslint-plugin-router": "^1.77.7", "@tanstack/router-devtools": "^1.58.15", "@tanstack/router-plugin": "^1.58.12", diff --git a/ui-v2/src/hooks/variables.ts b/ui-v2/src/hooks/variables.ts index ecfa717ce26c..ba8c4d771c1f 100644 --- a/ui-v2/src/hooks/variables.ts +++ b/ui-v2/src/hooks/variables.ts @@ -11,82 +11,91 @@ import { type UseVariablesOptions = components["schemas"]["Body_read_variables_variables_filter_post"]; +type Variables = UseVariablesOptions["variables"]; -type VariableKeys = { - all: readonly ["variables"]; - filtered: ( - options: UseVariablesOptions, - ) => readonly ["variables", "filtered", string]; - filteredCount: (options?: UseVariablesOptions) => readonly string[]; +// ----- 🌐 APIs 📨 +// ---------------------------- +const fetchVariablesRequest = async (body: UseVariablesOptions) => { + const response = await getQueryService().POST("/variables/filter", { + body, + }); + return response.data; }; -/** - * Query key factory for variables-related queries - * - * @property {readonly string[]} all - Base key for all variable queries - * @property {function} filtered - Generates key for filtered variable queries, incorporating filter options - * @property {function} filteredCount - Generates key for filtered count queries, including name and tag filters - */ -const variableKeys: VariableKeys = { - all: ["variables"], - filtered: (options) => [ - ...variableKeys.all, - "filtered", - JSON.stringify(options), - ], - filteredCount: (options) => { - const key = [...variableKeys.all, "filtered-count"]; - if (options?.variables?.name?.like_) key.push(options.variables.name.like_); - if (options?.variables?.tags?.all_?.length) - key.push(JSON.stringify(options.variables.tags)); - return key; +const fetchVariableCountRequest = async ( + body: UseVariablesOptions | Record, +) => { + const response = await getQueryService().POST("/variables/count", { + body, + }); + return response.data; +}; + +const createVariableRequest = ( + variable: components["schemas"]["VariableCreate"], +) => { + return getQueryService().POST("/variables/", { + body: variable, + }); +}; + +const updateVariableRequest = ( + variable: components["schemas"]["VariableUpdate"] & { + id: string; }, +) => { + const { id, ...body } = variable; + return getQueryService().PATCH("/variables/{id}", { + params: { path: { id } }, + body, + }); }; -/** - * Builds a query configuration for fetching filtered variables - * @param options - Filter options for the variables query including pagination, sorting, and filtering criteria - * @returns A query configuration object compatible with TanStack Query including: - * - queryKey: A unique key for caching the query results - * - queryFn: The async function to fetch the filtered variables - * - staleTime: How long the data should be considered fresh (1 second) - * - placeholderData: Uses previous data while loading new data - */ -const buildVariablesQuery = (options: UseVariablesOptions) => - queryOptions({ - queryKey: variableKeys.filtered(options), - queryFn: async () => { - const response = await getQueryService().POST("/variables/filter", { - body: options, - }); - return response.data; - }, - staleTime: 1000, - placeholderData: keepPreviousData, +const deleteVariableRequest = (id: string) => { + return getQueryService().DELETE("/variables/{id}", { + params: { path: { id } }, }); +}; + +// ----- 🔑 Queries 🗄️ +// ---------------------------- /** - * Builds a query configuration for counting variables with optional filters - * @param options - Optional filter options for the variables count query - * @returns A query configuration object compatible with TanStack Query including: - * - queryKey: A unique key for caching the count results - * - queryFn: The async function to fetch the filtered count - * - staleTime: How long the data should be considered fresh (1 second) - * - placeholderData: Uses previous data while loading new data + * ``` + * 🏗️ Variable queries construction 👷 + * all => ['variables'] // key to match ['variables', ..., ...] + * list => ['variables', 'list'] // key to match ['variables', 'list', ..., ...] + * ['variables', 'list', { ...withOptionsFoo }] + * ['variables', 'list', { ...withOptionsBar }] + * ['variables', 'list', { ...withOptionsBaz }] + * count => ['variables', 'count'] // key to match ['variables', 'count', ..., ...] + * ['variables', 'count', {}] // all count + * ['variables', 'count', { ...withOptionsFoo }] + * ['variables', 'count', { ...withOptionsBar }] + * ['variables', 'count', { ...withOptionsBaz }] + * ``` */ -const buildCountQuery = (options?: UseVariablesOptions) => - queryOptions({ - queryKey: variableKeys.filteredCount(options), - queryFn: async () => { - const body = options?.variables ? { variables: options.variables } : {}; - const response = await getQueryService().POST("/variables/count", { - body, - }); - return response.data; - }, - staleTime: 1000, - placeholderData: keepPreviousData, - }); +const variableQueries = { + all: () => ["variables"] as const, + lists: () => [...variableQueries.all(), "list"] as const, + list: (options: UseVariablesOptions) => + queryOptions({ + queryKey: [...variableQueries.lists(), options] as const, + queryFn: () => fetchVariablesRequest(options), + staleTime: 1000, + placeholderData: keepPreviousData, + }), + counts: () => [...variableQueries.all(), "count"] as const, + count: (variables?: Variables) => { + const body = { variables }; + return queryOptions({ + queryKey: [...variableQueries.counts(), body] as const, + queryFn: () => fetchVariableCountRequest(body), + staleTime: 1000, + placeholderData: keepPreviousData, + }); + }, +} as const; /** * Hook for fetching and managing variables data with filtering, pagination, and counts @@ -129,11 +138,11 @@ export const useVariables = (options: UseVariablesOptions) => { const results = useQueries({ queries: [ // Filtered variables with pagination - buildVariablesQuery(options), + variableQueries.list(options), // Filtered count - buildCountQuery(options), + variableQueries.count(options.variables), // Total count - buildCountQuery(), + variableQueries.count(), ], }); @@ -178,11 +187,14 @@ useVariables.loader = ({ context: { queryClient: QueryClient }; }) => Promise.all([ - context.queryClient.ensureQueryData(buildVariablesQuery(deps)), - context.queryClient.ensureQueryData(buildCountQuery(deps)), - context.queryClient.ensureQueryData(buildCountQuery()), + context.queryClient.ensureQueryData(variableQueries.list(deps)), + context.queryClient.ensureQueryData(variableQueries.count(deps.variables)), + context.queryClient.ensureQueryData(variableQueries.count()), ]); +// ----- ✍🏼 Mutations 🗄️ +// ---------------------------- + /** * Hook for creating a new variable * @@ -193,7 +205,14 @@ useVariables.loader = ({ * * @example * ```ts - * const { createVariable, isLoading } = useCreateVariable({ + * const { createVariable, isLoading } = useCreateVariable(); + * + * // Create a new variable + * createVariable({ + * name: 'MY_VARIABLE', + * value: 'secret-value', + * tags: ['production', 'secrets'] + * }, { * onSuccess: () => { * // Handle successful creation * console.log('Variable created successfully'); @@ -203,27 +222,15 @@ useVariables.loader = ({ * console.error('Failed to create variable:', error); * } * }); - * - * // Create a new variable - * createVariable({ - * name: 'MY_VARIABLE', - * value: 'secret-value', - * tags: ['production', 'secrets'] - * }); * ``` */ export const useCreateVariable = () => { const queryClient = useQueryClient(); - const { mutate: createVariable, ...rest } = useMutation({ - mutationFn: (variable: components["schemas"]["VariableCreate"]) => { - return getQueryService().POST("/variables/", { - body: variable, - }); - }, + mutationFn: createVariableRequest, onSettled: async () => { return await queryClient.invalidateQueries({ - queryKey: variableKeys.all, + queryKey: variableQueries.all(), }); }, }); @@ -231,10 +238,6 @@ export const useCreateVariable = () => { return { createVariable, ...rest }; }; -type VariableUpdateWithId = components["schemas"]["VariableUpdate"] & { - id: string; -}; - /** * Hook for updating an existing variable * @@ -245,14 +248,7 @@ type VariableUpdateWithId = components["schemas"]["VariableUpdate"] & { * * @example * ```ts - * const { updateVariable } = useUpdateVariable({ - * onSuccess: () => { - * // Handle successful update - * }, - * onError: (error) => { - * console.error('Failed to update variable:', error); - * } - * }); + * const { updateVariable } = useUpdateVariable(); * * // Update an existing variable * updateVariable({ @@ -260,6 +256,13 @@ type VariableUpdateWithId = components["schemas"]["VariableUpdate"] & { * name: 'UPDATED_NAME', * value: 'new-value', * tags: ['production'] + * }, { + * onSuccess: () => { + * // Handle successful update + * }, + * onError: (error) => { + * console.error('Failed to update variable:', error); + * } * }); * ``` */ @@ -267,16 +270,10 @@ export const useUpdateVariable = () => { const queryClient = useQueryClient(); const { mutate: updateVariable, ...rest } = useMutation({ - mutationFn: (variable: VariableUpdateWithId) => { - const { id, ...body } = variable; - return getQueryService().PATCH("/variables/{id}", { - params: { path: { id } }, - body, - }); - }, + mutationFn: updateVariableRequest, onSettled: async () => { return await queryClient.invalidateQueries({ - queryKey: variableKeys.all, + queryKey: variableQueries.all(), }); }, }); @@ -291,7 +288,10 @@ export const useUpdateVariable = () => { * * @example * ```ts - * const { deleteVariable } = useDeleteVariable({ + * const { deleteVariable } = useDeleteVariable(); + * + * // Delete a variable by ID + * deleteVariable('variable-id-to-delete', { * onSuccess: () => { * // Handle successful deletion * }, @@ -299,22 +299,16 @@ export const useUpdateVariable = () => { * console.error('Failed to delete variable:', error); * } * }); - * - * // Delete a variable by ID - * deleteVariable('variable-id-to-delete'); * ``` */ export const useDeleteVariable = () => { const queryClient = useQueryClient(); const { mutate: deleteVariable, ...rest } = useMutation({ - mutationFn: async (id: string) => - await getQueryService().DELETE("/variables/{id}", { - params: { path: { id } }, - }), + mutationFn: deleteVariableRequest, onSettled: async () => { return await queryClient.invalidateQueries({ - queryKey: variableKeys.all, + queryKey: variableQueries.all(), }); }, }); From 16ac123e7c5c19ee0a33a3b206e6ef1cd2e98748 Mon Sep 17 00:00:00 2001 From: Devin Villarosa Date: Fri, 29 Nov 2024 13:13:07 -0800 Subject: [PATCH 2/3] fix: Fix where to place pluginRouter configs --- ui-v2/eslint.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-v2/eslint.config.js b/ui-v2/eslint.config.js index bef636a21566..214762a6992a 100644 --- a/ui-v2/eslint.config.js +++ b/ui-v2/eslint.config.js @@ -15,7 +15,6 @@ export default tseslint.config( extends: [ js.configs.recommended, ...tseslint.configs.recommendedTypeChecked, - ...pluginQuery.configs["flat/recommended"], ], files: ["**/*.{ts,tsx}"], languageOptions: { @@ -46,6 +45,7 @@ export default tseslint.config( ...react.configs["jsx-runtime"].rules, }, }, + ...pluginQuery.configs["flat/recommended"], ...pluginRouter.configs["flat/recommended"], { files: ["tests/**/*.{ts,tsx}"], From d8d505e546b66710bc1c8ef7dfc006d0602a338c Mon Sep 17 00:00:00 2001 From: Devin Villarosa Date: Fri, 29 Nov 2024 13:22:37 -0800 Subject: [PATCH 3/3] revert: Move API calls back inline --- ui-v2/src/hooks/variables.ts | 84 +++++++++++++++--------------------- 1 file changed, 34 insertions(+), 50 deletions(-) diff --git a/ui-v2/src/hooks/variables.ts b/ui-v2/src/hooks/variables.ts index ba8c4d771c1f..6e8f7b1e779b 100644 --- a/ui-v2/src/hooks/variables.ts +++ b/ui-v2/src/hooks/variables.ts @@ -11,51 +11,10 @@ import { type UseVariablesOptions = components["schemas"]["Body_read_variables_variables_filter_post"]; -type Variables = UseVariablesOptions["variables"]; - -// ----- 🌐 APIs 📨 -// ---------------------------- -const fetchVariablesRequest = async (body: UseVariablesOptions) => { - const response = await getQueryService().POST("/variables/filter", { - body, - }); - return response.data; -}; - -const fetchVariableCountRequest = async ( - body: UseVariablesOptions | Record, -) => { - const response = await getQueryService().POST("/variables/count", { - body, - }); - return response.data; -}; - -const createVariableRequest = ( - variable: components["schemas"]["VariableCreate"], -) => { - return getQueryService().POST("/variables/", { - body: variable, - }); -}; - -const updateVariableRequest = ( - variable: components["schemas"]["VariableUpdate"] & { - id: string; - }, -) => { - const { id, ...body } = variable; - return getQueryService().PATCH("/variables/{id}", { - params: { path: { id } }, - body, - }); -}; - -const deleteVariableRequest = (id: string) => { - return getQueryService().DELETE("/variables/{id}", { - params: { path: { id } }, - }); +type VariableUpdateWithId = components["schemas"]["VariableUpdate"] & { + id: string; }; +type VariablesFilter = components["schemas"]["VariableFilter"]; // ----- 🔑 Queries 🗄️ // ---------------------------- @@ -81,16 +40,27 @@ const variableQueries = { list: (options: UseVariablesOptions) => queryOptions({ queryKey: [...variableQueries.lists(), options] as const, - queryFn: () => fetchVariablesRequest(options), + queryFn: async () => { + const response = await getQueryService().POST("/variables/filter", { + body: options, + }); + return response.data; + }, staleTime: 1000, placeholderData: keepPreviousData, }), counts: () => [...variableQueries.all(), "count"] as const, - count: (variables?: Variables) => { + count: (variables?: VariablesFilter | null) => { const body = { variables }; return queryOptions({ queryKey: [...variableQueries.counts(), body] as const, - queryFn: () => fetchVariableCountRequest(body), + queryFn: + () => async (body: UseVariablesOptions | Record) => { + const response = await getQueryService().POST("/variables/count", { + body, + }); + return response.data; + }, staleTime: 1000, placeholderData: keepPreviousData, }); @@ -227,7 +197,11 @@ useVariables.loader = ({ export const useCreateVariable = () => { const queryClient = useQueryClient(); const { mutate: createVariable, ...rest } = useMutation({ - mutationFn: createVariableRequest, + mutationFn: (variable: components["schemas"]["VariableCreate"]) => { + return getQueryService().POST("/variables/", { + body: variable, + }); + }, onSettled: async () => { return await queryClient.invalidateQueries({ queryKey: variableQueries.all(), @@ -270,7 +244,13 @@ export const useUpdateVariable = () => { const queryClient = useQueryClient(); const { mutate: updateVariable, ...rest } = useMutation({ - mutationFn: updateVariableRequest, + mutationFn: (variable: VariableUpdateWithId) => { + const { id, ...body } = variable; + return getQueryService().PATCH("/variables/{id}", { + params: { path: { id } }, + body, + }); + }, onSettled: async () => { return await queryClient.invalidateQueries({ queryKey: variableQueries.all(), @@ -305,7 +285,11 @@ export const useDeleteVariable = () => { const queryClient = useQueryClient(); const { mutate: deleteVariable, ...rest } = useMutation({ - mutationFn: deleteVariableRequest, + mutationFn: (id: string) => { + return getQueryService().DELETE("/variables/{id}", { + params: { path: { id } }, + }); + }, onSettled: async () => { return await queryClient.invalidateQueries({ queryKey: variableQueries.all(),