diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 557bae0a3..9c9a6e6fa 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -15,7 +15,7 @@ "@formkit/vue": "^1.0.0-beta.15", "@intlify/unplugin-vue-i18n": "^0.5.0 || ^0.7.0 || ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^1.0.0", "@openid/appauth": "^1.3.1", - "@tanstack/vue-query": "^4.32.6", + "@tanstack/vue-query": "^4.32.6 || ^5.0.0", "@vueform/multiselect": "^2.5.2", "axios": "^0.27.2 || ^1.0.0", "crypto-js": "^4.1.1", @@ -1225,23 +1225,23 @@ } }, "node_modules/@tanstack/query-core": { - "version": "4.36.1", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.36.1.tgz", - "integrity": "sha512-DJSilV5+ytBP1FbFcEJovv4rnnm/CokuVvrBEtW/Va9DvuJ3HksbXUJEpI0aV1KtuL4ZoO9AVE6PyNLzF7tLeA==", + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.8.1.tgz", + "integrity": "sha512-Y0enatz2zQXBAsd7XmajlCs+WaitdR7dIFkqz9Xd7HL4KV04JOigWVreYseTmNH7YFSBSC/BJ9uuNp1MAf+GfA==", "funding": { "type": "github", "url": "https://github.com/sponsors/tannerlinsley" } }, "node_modules/@tanstack/vue-query": { - "version": "4.37.1", - "resolved": "https://registry.npmjs.org/@tanstack/vue-query/-/vue-query-4.37.1.tgz", - "integrity": "sha512-QzCQ94g2oZQcEfI4nfqa6Qr3aFXtXiEH17Jho+QFl73c7epqsWNcyP3ovF1fgJz5jEOE5OYtwgkoaRKIRaSigg==", + "version": "5.8.1", + "resolved": "https://registry.npmjs.org/@tanstack/vue-query/-/vue-query-5.8.1.tgz", + "integrity": "sha512-gPgEp+9U8NWdX4ZFA25aQEUoAybrqAYmu1ZKg+5U44sZRAZSA+ShUV3N3LYX8Tixs6dTqIXTL/crIyMMSchCyg==", "dependencies": { - "@tanstack/match-sorter-utils": "^8.1.1", - "@tanstack/query-core": "4.36.1", - "@vue/devtools-api": "^6.4.2", - "vue-demi": "^0.13.11" + "@tanstack/match-sorter-utils": "^8.8.4", + "@tanstack/query-core": "5.8.1", + "@vue/devtools-api": "^6.5.0", + "vue-demi": "^0.14.6" }, "funding": { "type": "github", @@ -1249,7 +1249,7 @@ }, "peerDependencies": { "@vue/composition-api": "^1.1.2", - "vue": "^2.5.0 || ^3.0.0" + "vue": "^2.6.0 || ^3.3.0" }, "peerDependenciesMeta": { "@vue/composition-api": { @@ -1258,9 +1258,9 @@ } }, "node_modules/@tanstack/vue-query/node_modules/vue-demi": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.13.11.tgz", - "integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==", + "version": "0.14.6", + "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.6.tgz", + "integrity": "sha512-8QA7wrYSHKaYgUxDA5ZC24w+eHm3sYCbp0EzcDwKqN3p6HqtTCGR/GVsPyZW92unff4UlcSh++lmqDWN3ZIq4w==", "hasInstallScript": true, "bin": { "vue-demi-fix": "bin/vue-demi-fix.js", diff --git a/frontend/package.json b/frontend/package.json index 89e5a6547..0f8d99372 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -34,7 +34,7 @@ "qs": "^6.11.0", "vue": "^3.2.37", "vue-i18n": "^9.2.2", - "@tanstack/vue-query": "^4.32.6", + "@tanstack/vue-query": "^4.32.6 || ^5.0.0", "vue-router": "^4.1.2", "vue-unused-components-checker": "^1.1.2" }, diff --git a/frontend/src/api/artifacts.ts b/frontend/src/api/artifacts.ts index ea406c80e..a09a4c7df 100644 --- a/frontend/src/api/artifacts.ts +++ b/frontend/src/api/artifacts.ts @@ -2,29 +2,29 @@ // // SPDX-License-Identifier: MIT -import { useQuery } from "@tanstack/vue-query"; +import { useQuery, type UseQueryReturnType } from "@tanstack/vue-query"; import type { Ref } from "vue"; import type { operations } from "./generated"; import { apiGet } from "./index"; // Get all rules +type ArtifactsOpType = operations["get_artifacts_api_v1_artifacts_get"]; +type ArtifactsOutputType = + ArtifactsOpType["responses"][200]["content"]["application/json"]; +type ArtifactsErrorType = + ArtifactsOpType["responses"][422]["content"]["application/json"]; export const useArtifactsQuery = ( users: Ref | undefined, groups: Ref | undefined, -) => { +): UseQueryReturnType => { const url = "/api/v1/artifacts"; - - type OpType = operations["get_artifacts_api_v1_artifacts_get"]; - type OutputType = OpType["responses"][200]["content"]["application/json"]; - type ErrorType = OpType["responses"][422]["content"]["application/json"]; - const queryParams = { users, groups }; const visible = (groups && groups.value && groups.value.length > 0) || (users && users.value && users.value.length > 0); - return useQuery( - [url, queryParams], - apiGet, - { enabled: visible }, - ); + return useQuery({ + queryKey: [url, queryParams], + queryFn: apiGet, + enabled: visible, + }); }; diff --git a/frontend/src/api/index.ts b/frontend/src/api/index.ts index 76b22e774..72ea1736a 100644 --- a/frontend/src/api/index.ts +++ b/frontend/src/api/index.ts @@ -53,10 +53,19 @@ export async function getApiClient() { }); } -export const apiGet = async ({ queryKey }: QueryFunctionContext) => { +interface QueryFunctionContextOrDirect + extends Omit { + signal?: QueryFunctionContext["signal"]; + meta?: QueryFunctionContext["meta"]; +} +export const apiGet = async ({ + queryKey, + signal, +}: QueryFunctionContextOrDirect) => { const axiosConfig = await getAxiosConfig(); const url = queryKey[0] as string; axiosConfig["params"] = queryKey[1]; + axiosConfig["signal"] = signal; const response = await http.get(url, axiosConfig); return response.data; }; diff --git a/frontend/src/api/rules.ts b/frontend/src/api/rules.ts index b75565433..4a61f74d7 100644 --- a/frontend/src/api/rules.ts +++ b/frontend/src/api/rules.ts @@ -3,103 +3,136 @@ // SPDX-License-Identifier: MIT import { useUserStore } from "@/stores/user"; -import { useMutation, useQuery, useQueryClient } from "@tanstack/vue-query"; +import { + useMutation, + useQuery, + useQueryClient, + type UseMutationReturnType, + type UseQueryReturnType, +} from "@tanstack/vue-query"; import type { Ref } from "vue"; import type { paths } from "./generated"; import { apiDelete, apiGet, apiPatch, apiPost, apiPut } from "./index"; // Get all rules -export const useRulesQuery = () => { +type RulesOpType = paths["/api/v1/users/{username}/rules"]["get"]; +type RulesOutputType = + RulesOpType["responses"][200]["content"]["application/json"]; +type RulesErrorType = + RulesOpType["responses"][422]["content"]["application/json"]; +export const useRulesQuery = (): UseQueryReturnType< + RulesOutputType, + RulesErrorType +> => { const userStore = useUserStore(); const url = `/api/v1/users/${userStore.username}/rules`; - - type OpType = paths["/api/v1/users/{username}/rules"]["get"]; - type OutputType = OpType["responses"][200]["content"]["application/json"]; - type ErrorType = OpType["responses"][422]["content"]["application/json"]; - - return useQuery([url], apiGet, { + return useQuery({ + queryKey: [url], + queryFn: apiGet, enabled: userStore.loggedIn, }); }; // Get a rule -export const useRuleQuery = (id: number) => { +type RuleOpType = paths["/api/v1/users/{username}/rules/{id}"]["get"]; +type RuleOutputType = + RuleOpType["responses"][200]["content"]["application/json"]; +type RuleErrorType = + RuleOpType["responses"][422]["content"]["application/json"]; +export const useRuleQuery = ( + id: number, +): UseQueryReturnType => { const userStore = useUserStore(); const url = `/api/v1/users/${userStore.username}/rules/${id}`; - - type OpType = paths["/api/v1/users/{username}/rules/{id}"]["get"]; - type OutputType = OpType["responses"][200]["content"]["application/json"]; - type ErrorType = OpType["responses"][422]["content"]["application/json"]; - - return useQuery([url], apiGet); + return useQuery({ queryKey: [url], queryFn: apiGet }); }; // Add a new rule -export const useAddRuleMutation = () => { +type AddRuleOpType = paths["/api/v1/users/{username}/rules"]["post"]; +type AddRuleBodyType = + AddRuleOpType["requestBody"]["content"]["application/json"]; +type AddRuleOutputType = + AddRuleOpType["responses"][200]["content"]["application/json"]; +type AddRuleErrorType = + AddRuleOpType["responses"][422]["content"]["application/json"]; +export const useAddRuleMutation = (): UseMutationReturnType< + AddRuleOutputType, + AddRuleErrorType, + AddRuleBodyType, + unknown +> => { const userStore = useUserStore(); const client = useQueryClient(); - - type OpType = paths["/api/v1/users/{username}/rules"]["post"]; - type BodyType = OpType["requestBody"]["content"]["application/json"]; - type OutputType = OpType["responses"][200]["content"]["application/json"]; - type ErrorType = OpType["responses"][422]["content"]["application/json"]; - - return useMutation( - (data) => - apiPost( + return useMutation({ + mutationFn: (data) => + apiPost( `/api/v1/users/${userStore.username}/rules`, data, ), - { - onSuccess: async () => { - await client.invalidateQueries([ - `/api/v1/users/${userStore.username}/rules`, - ]); - }, + + onSuccess: async () => { + await client.invalidateQueries({ + queryKey: [`/api/v1/users/${userStore.username}/rules`], + }); }, - ); + }); }; // Edit a rule -export const useEditRuleMutation = (id: number) => { +type EditRuleOpType = paths["/api/v1/users/{username}/rules/{id}"]["put"]; +type EditRuleOutputType = + EditRuleOpType["responses"][200]["content"]["application/json"]; +type EditRuleErrorType = + EditRuleOpType["responses"][422]["content"]["application/json"]; +export const useEditRuleMutation = ( + id: number, +): UseMutationReturnType< + EditRuleOutputType, + EditRuleErrorType, + EditRuleOutputType, + unknown +> => { const userStore = useUserStore(); const client = useQueryClient(); const url = `/api/v1/users/${userStore.username}/rules/${id}`; - - type OpType = paths["/api/v1/users/{username}/rules/{id}"]["put"]; - type OutputType = OpType["responses"][200]["content"]["application/json"]; - type ErrorType = OpType["responses"][422]["content"]["application/json"]; - - return useMutation( - (data: OutputType) => apiPut(url, data), - { - onSuccess: async () => { - await client.invalidateQueries([url]); - await client.invalidateQueries([ - `/api/v1/users/${userStore.username}/rules`, - ]); - }, + return useMutation({ + mutationFn: (data: EditRuleOutputType) => + apiPut(url, data), + + onSuccess: async () => { + await client.invalidateQueries({ queryKey: [url] }); + await client.invalidateQueries({ + queryKey: [`/api/v1/users/${userStore.username}/rules`], + }); }, - ); + }); }; // Delete a rule -export const useDeleteRuleMutation = () => { +type DeleteRuleOpType = paths["/api/v1/users/{username}/rules/{id}"]["delete"]; +type DeleteRuleOutputType = DeleteRuleOpType["parameters"]["path"]["id"]; +type DeleteRuleErrorType = + DeleteRuleOpType["responses"][422]["content"]["application/json"]; +export const useDeleteRuleMutation = (): UseMutationReturnType< + void, + DeleteRuleErrorType, + DeleteRuleOutputType, + unknown +> => { const userStore = useUserStore(); const client = useQueryClient(); - - type OpType = paths["/api/v1/users/{username}/rules/{id}"]["delete"]; - type ErrorType = OpType["responses"][422]["content"]["application/json"]; - - return useMutation( - (id) => apiDelete(`/api/v1/users/${userStore.username}/rules/${id}`), - { - onSuccess: async () => { - const url = `/api/v1/users/${userStore.username}/rules`; - await client.invalidateQueries([url], { refetchType: "active" }); - }, + return useMutation({ + mutationFn: (id) => + apiDelete(`/api/v1/users/${userStore.username}/rules/${id}`), + + onSuccess: async () => { + const url = `/api/v1/users/${userStore.username}/rules`; + await client.invalidateQueries({ + queryKey: [url], + refetchType: "active", + }); }, - ); + }); }; /* @@ -107,58 +140,74 @@ export const useDeleteRuleMutation = () => { */ // Get all rules -export const useAdminRulesQuery = (username: Ref) => { +type AdminRulesOpType = paths["/api/v1/admin/rules"]["get"]; +type AdminRulesOutputType = + AdminRulesOpType["responses"][200]["content"]["application/json"]; +type AdminRulesErrorType = + AdminRulesOpType["responses"][422]["content"]["application/json"]; +export const useAdminRulesQuery = ( + username: Ref, +): UseQueryReturnType => { const url = `/api/v1/admin/rules`; - - type OpType = paths["/api/v1/admin/rules"]["get"]; - type OutputType = OpType["responses"][200]["content"]["application/json"]; - type ErrorType = OpType["responses"][422]["content"]["application/json"]; - - return useQuery( - [url, { username }], - apiGet, - ); + return useQuery({ + queryKey: [url, { username }], + queryFn: apiGet, + }); }; // Get disabled rules -export const useDisabledRulesQuery = () => { +type DisabledRulesOpType = paths["/api/v1/admin/rules"]["get"]; +type DisabledRulesOutputType = + DisabledRulesOpType["responses"][200]["content"]["application/json"]; +type DisabledRulesErrorType = + DisabledRulesOpType["responses"][422]["content"]["application/json"]; +export const useDisabledRulesQuery = (): UseQueryReturnType< + DisabledRulesOutputType, + DisabledRulesErrorType +> => { const url = "/api/v1/admin/rules"; - - type OpType = paths["/api/v1/admin/rules"]["get"]; - type OutputType = OpType["responses"][200]["content"]["application/json"]; - type ErrorType = OpType["responses"][422]["content"]["application/json"]; - return useQuery( - [url, { disabled: true }], - apiGet, - ); + return useQuery({ + queryKey: [url, { disabled: true }], + queryFn: apiGet, + }); }; // Patch an existing rule -export const usePatchRuleMutation = () => { +type PatchRuleOpType = paths["/api/v1/admin/rules/{id}"]["patch"]; +type PatchRuleBodyType = + PatchRuleOpType["requestBody"]["content"]["application/json"]; +type PatchRuleOutputType = + PatchRuleOpType["responses"][200]["content"]["application/json"]; +type PatchRuleFnOutputType = { + id: PatchRuleOpType["parameters"]["path"]["id"]; + rule: PatchRuleBodyType; +}; +type PatchRuleErrorType = + PatchRuleOpType["responses"][422]["content"]["application/json"]; +export const usePatchRuleMutation = (): UseMutationReturnType< + PatchRuleOutputType, + PatchRuleErrorType, + PatchRuleFnOutputType, + unknown +> => { const client = useQueryClient(); - - type OpType = paths["/api/v1/admin/rules/{id}"]["patch"]; - type BodyType = OpType["requestBody"]["content"]["application/json"]; - type OutputType = OpType["responses"][200]["content"]["application/json"]; - type ErrorType = OpType["responses"][422]["content"]["application/json"]; - - return useMutation< - OutputType, - ErrorType, - { id: OpType["parameters"]["path"]["id"]; rule: BodyType } - >( - ({ id, rule }) => { - return apiPatch(`/api/v1/admin/rules/${id}`, rule); + return useMutation({ + mutationFn: ({ id, rule }) => { + return apiPatch( + `/api/v1/admin/rules/${id}`, + rule, + ); }, - { - onSuccess: async () => { - await client.invalidateQueries([ + + onSuccess: async () => { + await client.invalidateQueries({ + queryKey: [ "/api/v1/admin/rules", { disabled: true, }, - ]); - }, + ], + }); }, - ); + }); }; diff --git a/frontend/src/components/AdminRuleEnableForm.vue b/frontend/src/components/AdminRuleEnableForm.vue index 5579ee72b..9706150f5 100644 --- a/frontend/src/components/AdminRuleEnableForm.vue +++ b/frontend/src/components/AdminRuleEnableForm.vue @@ -36,12 +36,14 @@ const handleSubmit = async ( try { const response = await editMutation(formDataToRuleMutation(data)); // Success! - await queryClient.invalidateQueries([ - "/api/v1/admin/rules", - { - username: props.rule.user.name, - }, - ]); + await queryClient.invalidateQueries({ + queryKey: [ + "/api/v1/admin/rules", + { + username: props.rule.user.name, + }, + ], + }); toastStore.addToast({ color: "success", title: "Rule enabled", diff --git a/frontend/src/components/AdminUserRulesSelector.vue b/frontend/src/components/AdminUserRulesSelector.vue index 53edb1643..1cb392b97 100644 --- a/frontend/src/components/AdminUserRulesSelector.vue +++ b/frontend/src/components/AdminUserRulesSelector.vue @@ -20,7 +20,6 @@ const getUsers = async (query: string) => { // const results = await apiGetUsers({ const results = await apiGet({ queryKey: ["/api/v1/admin/users", { search: query }], - meta: undefined, }); const options = results.map((item) => item.name); return options; diff --git a/frontend/src/components/rule-edit/generation-rule/DestinationList.vue b/frontend/src/components/rule-edit/generation-rule/DestinationList.vue index bdf2755be..2f3734ff6 100644 --- a/frontend/src/components/rule-edit/generation-rule/DestinationList.vue +++ b/frontend/src/components/rule-edit/generation-rule/DestinationList.vue @@ -27,7 +27,6 @@ const getDestinations = async () => { try { data = await apiGet({ queryKey: [url], - meta: undefined, }); } catch (e) { const error = e as AxiosError; diff --git a/frontend/src/components/rule-edit/generation-rule/FilterApplication.vue b/frontend/src/components/rule-edit/generation-rule/FilterApplication.vue index a7b102050..469c3e765 100644 --- a/frontend/src/components/rule-edit/generation-rule/FilterApplication.vue +++ b/frontend/src/components/rule-edit/generation-rule/FilterApplication.vue @@ -14,7 +14,6 @@ const url = "/api/v1/applications"; const getApplications = async () => { const results = await apiGet({ queryKey: [url], - meta: undefined, }); return results; }; diff --git a/frontend/src/components/rule-edit/tracking-rule/ArtifactsFollowedParams.vue b/frontend/src/components/rule-edit/tracking-rule/ArtifactsFollowedParams.vue index cb978a9be..08f355753 100644 --- a/frontend/src/components/rule-edit/tracking-rule/ArtifactsFollowedParams.vue +++ b/frontend/src/components/rule-edit/tracking-rule/ArtifactsFollowedParams.vue @@ -38,7 +38,6 @@ const route = "/api/v1/artifacts"; const getArtifacts = async (query: string) => { const results = await apiGet({ queryKey: [route, { names: `*${query}*` }], - meta: undefined, }); return results; }; diff --git a/frontend/src/components/rule-edit/tracking-rule/ArtifactsGroupOwnedParams.vue b/frontend/src/components/rule-edit/tracking-rule/ArtifactsGroupOwnedParams.vue index 7cb784a3b..da14b1b26 100644 --- a/frontend/src/components/rule-edit/tracking-rule/ArtifactsGroupOwnedParams.vue +++ b/frontend/src/components/rule-edit/tracking-rule/ArtifactsGroupOwnedParams.vue @@ -17,7 +17,6 @@ const url = `/api/v1/users/${userStore.username}/groups`; const getUserGroups = async () => { const results = await apiGet({ queryKey: [url], - meta: undefined, }); return results; }; diff --git a/frontend/src/components/rule-edit/tracking-rule/UserMultiSelect.vue b/frontend/src/components/rule-edit/tracking-rule/UserMultiSelect.vue index 556657747..acae22aa8 100644 --- a/frontend/src/components/rule-edit/tracking-rule/UserMultiSelect.vue +++ b/frontend/src/components/rule-edit/tracking-rule/UserMultiSelect.vue @@ -35,7 +35,6 @@ const getUsers = async (query: string) => { } const results = await apiGet({ queryKey: [url, { search: query }], - meta: undefined, }); return results; };