From 727399105759056c976a5feb90c0e252cf8bf9d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piggy=20Park=20=28=EB=B0=95=EC=9A=A9=ED=83=9C=29?= Date: Tue, 19 Aug 2025 13:35:17 +0900 Subject: [PATCH] feat: Implement resource-cache synchronization Logic (#6134) * refactor(resource-cache-sync): make improvements useResourceCachSync Signed-off-by: samuel.park * feat(resource-cache): apply resource-query-sync HOF to api-clients Signed-off-by: samuel.park --------- Signed-off-by: samuel.park --- .../composables/use-escalation-policy-api.ts | 10 +- .../service/composables/use-service-api.ts | 11 +- .../webhook/composables/use-webhook-api.ts | 19 ++- .../composables/use-data-source-api.ts | 7 +- .../identity/app/composables/use-app-api.ts | 15 +- .../composables/use-project-group-api.ts | 15 +- .../project/composables/use-project-api.ts | 17 ++- .../provider/composables/use-provider-api.ts | 9 +- .../identity/role/composables/use-role-api.ts | 13 +- .../composables/use-service-account-api.ts | 13 +- .../composables/use-trusted-account-api.ts | 13 +- .../composables/use-user-group-api.ts | 13 +- .../identity/user/composables/use-user-api.ts | 17 ++- .../composables/use-workspace-user-api.ts | 5 +- .../composables/use-collector-api.ts | 14 +- .../metric/composables/use-metric-api.ts | 11 +- .../composables/use-escalation-policy-api.ts | 11 +- .../webhook/composables/use-webhook-api.ts | 17 ++- .../protocol/composables/use-protocol-api.ts | 16 +- .../secret/composables/use-secret-api.ts | 5 +- .../__tests__/use-resource-cache-sync.test.ts | 140 ++++++++++++++++++ .../composable/use-resource-cache-sync.ts | 56 ++++--- 22 files changed, 321 insertions(+), 126 deletions(-) create mode 100644 apps/web/src/query/resource-query/shared/composable/__tests__/use-resource-cache-sync.test.ts diff --git a/apps/web/src/api-clients/alert-manager/escalation-policy/composables/use-escalation-policy-api.ts b/apps/web/src/api-clients/alert-manager/escalation-policy/composables/use-escalation-policy-api.ts index 7f361c35c2..8c73ec6d43 100644 --- a/apps/web/src/api-clients/alert-manager/escalation-policy/composables/use-escalation-policy-api.ts +++ b/apps/web/src/api-clients/alert-manager/escalation-policy/composables/use-escalation-policy-api.ts @@ -7,18 +7,20 @@ import type { EscalationPolicyGetParameters } from '@/api-clients/alert-manager/ import type { EscalationPolicyListParameters } from '@/api-clients/alert-manager/escalation-policy/schema/api-verbs/list'; import type { EscalationPolicyUpdateParameters } from '@/api-clients/alert-manager/escalation-policy/schema/api-verbs/update'; import type { EscalationPolicyModel } from '@/api-clients/alert-manager/escalation-policy/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useEscalationPolicyApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('alertManagerEscalationPolicy'); + const actions = { - create: SpaceConnector.clientV2.alertManager.escalationPolicy.create, - delete: SpaceConnector.clientV2.alertManager.escalationPolicy.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.escalationPolicy.create), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.escalationPolicy.delete), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.escalationPolicy.update), get: SpaceConnector.clientV2.alertManager.escalationPolicy.get, list: SpaceConnector.clientV2.alertManager.escalationPolicy.list>, - update: SpaceConnector.clientV2.alertManager.escalationPolicy.update, }; return { escalationPolicyAPI: actions, }; }; - diff --git a/apps/web/src/api-clients/alert-manager/service/composables/use-service-api.ts b/apps/web/src/api-clients/alert-manager/service/composables/use-service-api.ts index f1006031cb..ca237edd99 100644 --- a/apps/web/src/api-clients/alert-manager/service/composables/use-service-api.ts +++ b/apps/web/src/api-clients/alert-manager/service/composables/use-service-api.ts @@ -8,15 +8,18 @@ import type { ServiceGetParameters } from '@/api-clients/alert-manager/service/s import type { ServiceListParameters } from '@/api-clients/alert-manager/service/schema/api-verbs/list'; import type { ServiceUpdateParameters } from '@/api-clients/alert-manager/service/schema/api-verbs/update'; import type { ServiceModel } from '@/api-clients/alert-manager/service/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useServiceApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('service'); + const actions = { - changeMembers: SpaceConnector.clientV2.alertManager.service.changeMembers, - create: SpaceConnector.clientV2.alertManager.service.create, - delete: SpaceConnector.clientV2.alertManager.service.delete, + changeMembers: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.service.changeMembers), + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.service.create), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.service.delete), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.service.update), get: SpaceConnector.clientV2.alertManager.service.get, list: SpaceConnector.clientV2.alertManager.service.list>, - update: SpaceConnector.clientV2.alertManager.service.update, }; return { diff --git a/apps/web/src/api-clients/alert-manager/webhook/composables/use-webhook-api.ts b/apps/web/src/api-clients/alert-manager/webhook/composables/use-webhook-api.ts index 6d7b725828..6a34145598 100644 --- a/apps/web/src/api-clients/alert-manager/webhook/composables/use-webhook-api.ts +++ b/apps/web/src/api-clients/alert-manager/webhook/composables/use-webhook-api.ts @@ -13,20 +13,23 @@ import type { WebhookUpdateMessageFormatParameters } from '@/api-clients/alert-m import type { WebhookUpdatePluginParameters } from '@/api-clients/alert-manager/webhook/schema/api-verbs/update-plugin'; import type { WebhookVerifyPluginParameters } from '@/api-clients/alert-manager/webhook/schema/api-verbs/verify-plugin'; import type { WebhookListErrorsModel, WebhookModel } from '@/api-clients/alert-manager/webhook/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useWebhookApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('alertManagerWebhook'); + const actions = { - create: SpaceConnector.clientV2.alertManager.webhook.create, - delete: SpaceConnector.clientV2.alertManager.webhook.delete, - disable: SpaceConnector.clientV2.alertManager.webhook.disable, - enable: SpaceConnector.clientV2.alertManager.webhook.enable, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.webhook.create), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.webhook.delete), + disable: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.webhook.disable), + enable: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.webhook.enable), get: SpaceConnector.clientV2.alertManager.webhook.get, listErrors: SpaceConnector.clientV2.alertManager.webhook.listErrors>, list: SpaceConnector.clientV2.alertManager.webhook.list>, - updateMessageFormat: SpaceConnector.clientV2.alertManager.webhook.updateMessageFormat, - updatePlugin: SpaceConnector.clientV2.alertManager.webhook.updatePlugin, - update: SpaceConnector.clientV2.alertManager.webhook.update, - verifyPlugin: SpaceConnector.clientV2.alertManager.webhook.verifyPlugin, + updateMessageFormat: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.webhook.updateMessageFormat), + updatePlugin: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.webhook.updatePlugin), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.webhook.update), + verifyPlugin: wrapResourceCacheRefresh(SpaceConnector.clientV2.alertManager.webhook.verifyPlugin), }; return { diff --git a/apps/web/src/api-clients/cost-analysis/data-source/composables/use-data-source-api.ts b/apps/web/src/api-clients/cost-analysis/data-source/composables/use-data-source-api.ts index e62fb7f5c8..83aa738e12 100644 --- a/apps/web/src/api-clients/cost-analysis/data-source/composables/use-data-source-api.ts +++ b/apps/web/src/api-clients/cost-analysis/data-source/composables/use-data-source-api.ts @@ -6,13 +6,16 @@ import type { CostDataSourceListParameters } from '@/api-clients/cost-analysis/d import type { CostDataSourceSyncParameters } from '@/api-clients/cost-analysis/data-source/schema/api-verbs/sync'; import type { CostDataSourceUpdatePermissionsParameters } from '@/api-clients/cost-analysis/data-source/schema/api-verbs/update-permissions'; import type { CostDataSourceModel } from '@/api-clients/cost-analysis/data-source/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useDataSourceApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('costDataSource'); + const actions = { get: SpaceConnector.clientV2.costAnalysis.dataSource.get, list: SpaceConnector.clientV2.costAnalysis.dataSource.list>, - sync: SpaceConnector.clientV2.costAnalysis.dataSource.sync, - updatePermissions: SpaceConnector.clientV2.costAnalysis.dataSource.updatePermissions, + sync: wrapResourceCacheRefresh(SpaceConnector.clientV2.costAnalysis.dataSource.sync), + updatePermissions: wrapResourceCacheRefresh(SpaceConnector.clientV2.costAnalysis.dataSource.updatePermissions), }; return { diff --git a/apps/web/src/api-clients/identity/app/composables/use-app-api.ts b/apps/web/src/api-clients/identity/app/composables/use-app-api.ts index 5f4fc340fb..74b161710b 100644 --- a/apps/web/src/api-clients/identity/app/composables/use-app-api.ts +++ b/apps/web/src/api-clients/identity/app/composables/use-app-api.ts @@ -12,17 +12,20 @@ import type { AppListParameters } from '@/api-clients/identity/app/schema/api-ve import type { AppStatParameters } from '@/api-clients/identity/app/schema/api-verbs/stat'; import type { AppUpdateParameters } from '@/api-clients/identity/app/schema/api-verbs/update'; import type { AppModel } from '@/api-clients/identity/app/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useAppApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('app'); + const actions = { - create: SpaceConnector.clientV2.identity.app.create, - update: SpaceConnector.clientV2.identity.app.update, - delete: SpaceConnector.clientV2.identity.app.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.app.create), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.app.update), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.app.delete), get: SpaceConnector.clientV2.identity.app.get, list: SpaceConnector.clientV2.identity.app.list>, - enable: SpaceConnector.clientV2.identity.app.enable, - disable: SpaceConnector.clientV2.identity.app.disable, - generateClientSecret: SpaceConnector.clientV2.identity.app.generateClientSecret, + enable: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.app.enable), + disable: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.app.disable), + generateClientSecret: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.app.generateClientSecret), stat: SpaceConnector.clientV2.identity.app.stat, }; diff --git a/apps/web/src/api-clients/identity/project-group/composables/use-project-group-api.ts b/apps/web/src/api-clients/identity/project-group/composables/use-project-group-api.ts index 0cb5cb3065..628ed12f31 100644 --- a/apps/web/src/api-clients/identity/project-group/composables/use-project-group-api.ts +++ b/apps/web/src/api-clients/identity/project-group/composables/use-project-group-api.ts @@ -12,18 +12,21 @@ import type { ProjectGroupRemoveUsersParameters } from '@/api-clients/identity/p import type { ProjectGroupStatParameters } from '@/api-clients/identity/project-group/schema/api-verbs/stat'; import type { ProjectGroupUpdateParameters } from '@/api-clients/identity/project-group/schema/api-verbs/update'; import type { ProjectGroupModel } from '@/api-clients/identity/project-group/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useProjectGroupApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('projectGroup'); + const actions = { - create: SpaceConnector.clientV2.identity.projectGroup.create, - update: SpaceConnector.clientV2.identity.projectGroup.update, - delete: SpaceConnector.clientV2.identity.projectGroup.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.projectGroup.create), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.projectGroup.update), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.projectGroup.delete), get: SpaceConnector.clientV2.identity.projectGroup.get, list: SpaceConnector.clientV2.identity.projectGroup.list>, - addUsers: SpaceConnector.clientV2.identity.projectGroup.addUsers, - removeUsers: SpaceConnector.clientV2.identity.projectGroup.removeUsers, - changeParentGroup: SpaceConnector.clientV2.identity.projectGroup.changeParentGroup, + addUsers: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.projectGroup.addUsers), + removeUsers: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.projectGroup.removeUsers), + changeParentGroup: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.projectGroup.changeParentGroup), stat: SpaceConnector.clientV2.identity.projectGroup.stat, }; diff --git a/apps/web/src/api-clients/identity/project/composables/use-project-api.ts b/apps/web/src/api-clients/identity/project/composables/use-project-api.ts index f47dd68e7a..4bd3bdfd06 100644 --- a/apps/web/src/api-clients/identity/project/composables/use-project-api.ts +++ b/apps/web/src/api-clients/identity/project/composables/use-project-api.ts @@ -13,19 +13,22 @@ import type { ProjectStatParameters } from '@/api-clients/identity/project/schem import type { ProjectUpdateParameters } from '@/api-clients/identity/project/schema/api-verbs/udpate'; import type { ProjectUpdateProjectTypeParameters } from '@/api-clients/identity/project/schema/api-verbs/update-project-type'; import type { ProjectModel } from '@/api-clients/identity/project/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useProjectApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('project'); + const actions = { - create: SpaceConnector.clientV2.identity.project.create, - update: SpaceConnector.clientV2.identity.project.update, - delete: SpaceConnector.clientV2.identity.project.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.project.create), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.project.update), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.project.delete), get: SpaceConnector.clientV2.identity.project.get, list: SpaceConnector.clientV2.identity.project.list>, - addUsers: SpaceConnector.clientV2.identity.project.addUsers, - removeUsers: SpaceConnector.clientV2.identity.project.removeUsers, - changeProjectGroup: SpaceConnector.clientV2.identity.project.changeProjectGroup, - updateProjectType: SpaceConnector.clientV2.identity.project.updateProjectType, + addUsers: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.project.addUsers), + removeUsers: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.project.removeUsers), + changeProjectGroup: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.project.changeProjectGroup), + updateProjectType: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.project.updateProjectType), stat: SpaceConnector.clientV2.identity.project.stat, }; diff --git a/apps/web/src/api-clients/identity/provider/composables/use-provider-api.ts b/apps/web/src/api-clients/identity/provider/composables/use-provider-api.ts index 824054e8fb..07733d3e8b 100644 --- a/apps/web/src/api-clients/identity/provider/composables/use-provider-api.ts +++ b/apps/web/src/api-clients/identity/provider/composables/use-provider-api.ts @@ -9,13 +9,16 @@ import type { ProviderListParameters } from '@/api-clients/identity/provider/sch import type { ProviderStatParameters } from '@/api-clients/identity/provider/schema/api-verbs/stat'; import type { ProviderUpdateParameters } from '@/api-clients/identity/provider/schema/api-verbs/update'; import type { ProviderModel } from '@/api-clients/identity/provider/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useProviderApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('provider'); + const actions = { - create: SpaceConnector.clientV2.identity.provider.create, - update: SpaceConnector.clientV2.identity.provider.update, - delete: SpaceConnector.clientV2.identity.provider.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.provider.create), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.provider.update), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.provider.delete), get: SpaceConnector.clientV2.identity.provider.get, list: SpaceConnector.clientV2.identity.provider.list>, stat: SpaceConnector.clientV2.identity.provider.stat, diff --git a/apps/web/src/api-clients/identity/role/composables/use-role-api.ts b/apps/web/src/api-clients/identity/role/composables/use-role-api.ts index f42c8ee16f..4595d42219 100644 --- a/apps/web/src/api-clients/identity/role/composables/use-role-api.ts +++ b/apps/web/src/api-clients/identity/role/composables/use-role-api.ts @@ -10,16 +10,19 @@ import type { RoleListParameters } from '@/api-clients/identity/role/schema/api- import type { RoleListBasicRoleParameters } from '@/api-clients/identity/role/schema/api-verbs/list-basic-role'; import type { RoleUpdateParameters } from '@/api-clients/identity/role/schema/api-verbs/update'; import type { BasicRoleModel, RoleModel } from '@/api-clients/identity/role/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useRoleApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('role'); + const actions = { - create: SpaceConnector.clientV2.identity.role.create, - update: SpaceConnector.clientV2.identity.role.update, - delete: SpaceConnector.clientV2.identity.role.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.role.create), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.role.update), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.role.delete), get: SpaceConnector.clientV2.identity.role.get, list: SpaceConnector.clientV2.identity.role.list>, - enable: SpaceConnector.clientV2.identity.role.enable, - disable: SpaceConnector.clientV2.identity.role.disable, + enable: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.role.enable), + disable: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.role.disable), listBasicRole: SpaceConnector.clientV2.identity.role.listBasicRole>, }; diff --git a/apps/web/src/api-clients/identity/service-account/composables/use-service-account-api.ts b/apps/web/src/api-clients/identity/service-account/composables/use-service-account-api.ts index f2dbb492e4..b20d61a19e 100644 --- a/apps/web/src/api-clients/identity/service-account/composables/use-service-account-api.ts +++ b/apps/web/src/api-clients/identity/service-account/composables/use-service-account-api.ts @@ -11,18 +11,21 @@ import type { ServiceAccountStatParameters } from '@/api-clients/identity/servic import type { ServiceAccountUpdateParameters } from '@/api-clients/identity/service-account/schema/api-verbs/update'; import type { ServiceAccountUpdateSecretDataParameters } from '@/api-clients/identity/service-account/schema/api-verbs/update-secret-data'; import type { ServiceAccountModel } from '@/api-clients/identity/service-account/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useServiceAccountApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('serviceAccount'); + const actions = { - create: SpaceConnector.clientV2.identity.serviceAccount.create, - update: SpaceConnector.clientV2.identity.serviceAccount.update, - delete: SpaceConnector.clientV2.identity.serviceAccount.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.serviceAccount.create), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.serviceAccount.update), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.serviceAccount.delete), get: SpaceConnector.clientV2.identity.serviceAccount.get, list: SpaceConnector.clientV2.identity.serviceAccount.list>, stat: SpaceConnector.clientV2.identity.serviceAccount.stat, - updateSecretData: SpaceConnector.clientV2.identity.serviceAccount.updateSecretData, - deleteSecretData: SpaceConnector.clientV2.identity.serviceAccount.deleteSecretData, + updateSecretData: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.serviceAccount.updateSecretData), + deleteSecretData: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.serviceAccount.deleteSecretData), }; return { diff --git a/apps/web/src/api-clients/identity/trusted-account/composables/use-trusted-account-api.ts b/apps/web/src/api-clients/identity/trusted-account/composables/use-trusted-account-api.ts index 6d287c531c..84e6285db6 100644 --- a/apps/web/src/api-clients/identity/trusted-account/composables/use-trusted-account-api.ts +++ b/apps/web/src/api-clients/identity/trusted-account/composables/use-trusted-account-api.ts @@ -11,19 +11,22 @@ import type { TrustedAccountSyncParameters } from '@/api-clients/identity/truste import type { TrustedAccountUpdateParameters } from '@/api-clients/identity/trusted-account/schema/api-verbs/update'; import type { TrustedAccountUpdateSecretDataParameters } from '@/api-clients/identity/trusted-account/schema/api-verbs/update-secret-data'; import type { TrustedAccountModel } from '@/api-clients/identity/trusted-account/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useTrustedAccountApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('trustedAccount'); + const actions = { - create: SpaceConnector.clientV2.identity.trustedAccount.create, - update: SpaceConnector.clientV2.identity.trustedAccount.update, - delete: SpaceConnector.clientV2.identity.trustedAccount.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.trustedAccount.create), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.trustedAccount.update), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.trustedAccount.delete), get: SpaceConnector.clientV2.identity.trustedAccount.get, list: SpaceConnector.clientV2.identity.trustedAccount.list>, stat: SpaceConnector.clientV2.identity.trustedAccount.stat, - updateSecretData: SpaceConnector.clientV2.identity.trustedAccount.updateSecretData, - sync: SpaceConnector.clientV2.identity.trustedAccount.sync, + updateSecretData: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.trustedAccount.updateSecretData), + sync: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.trustedAccount.sync), }; return { diff --git a/apps/web/src/api-clients/identity/user-group/composables/use-user-group-api.ts b/apps/web/src/api-clients/identity/user-group/composables/use-user-group-api.ts index 3d5fd32f9a..cc8046c255 100644 --- a/apps/web/src/api-clients/identity/user-group/composables/use-user-group-api.ts +++ b/apps/web/src/api-clients/identity/user-group/composables/use-user-group-api.ts @@ -9,17 +9,20 @@ import type { UserGroupListParameters } from '@/api-clients/identity/user-group/ import type { UserGroupRemoveUsersParameters } from '@/api-clients/identity/user-group/schema/api-verbs/remove-users'; import type { UserGroupUpdateParameters } from '@/api-clients/identity/user-group/schema/api-verbs/update'; import type { UserGroupModel } from '@/api-clients/identity/user-group/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useUserGroupApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('userGroup'); + const actions = { - create: SpaceConnector.clientV2.identity.userGroup.create, - update: SpaceConnector.clientV2.identity.userGroup.update, - delete: SpaceConnector.clientV2.identity.userGroup.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.userGroup.create), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.userGroup.update), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.userGroup.delete), get: SpaceConnector.clientV2.identity.userGroup.get, list: SpaceConnector.clientV2.identity.userGroup.list>, - addUsers: SpaceConnector.clientV2.identity.userGroup.addUsers, - removeUsers: SpaceConnector.clientV2.identity.userGroup.removeUsers, + addUsers: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.userGroup.addUsers), + removeUsers: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.userGroup.removeUsers), }; return { diff --git a/apps/web/src/api-clients/identity/user/composables/use-user-api.ts b/apps/web/src/api-clients/identity/user/composables/use-user-api.ts index 314ec3e23e..106113fdec 100644 --- a/apps/web/src/api-clients/identity/user/composables/use-user-api.ts +++ b/apps/web/src/api-clients/identity/user/composables/use-user-api.ts @@ -11,18 +11,21 @@ import type { UserListParameters } from '@/api-clients/identity/user/schema/api- import type { UserUpdateParameters } from '@/api-clients/identity/user/schema/api-verbs/update'; import type { UserVerifyEmailParameters } from '@/api-clients/identity/user/schema/api-verbs/verify-email'; import type { UserModel } from '@/api-clients/identity/user/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useUserApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('user'); + const actions = { - create: SpaceConnector.clientV2.identity.user.create, - update: SpaceConnector.clientV2.identity.user.update, - delete: SpaceConnector.clientV2.identity.user.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.user.create), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.user.update), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.user.delete), get: SpaceConnector.clientV2.identity.user.get, list: SpaceConnector.clientV2.identity.user.list>, - enable: SpaceConnector.clientV2.identity.user.enable, - disable: SpaceConnector.clientV2.identity.user.disable, - disableMfa: SpaceConnector.clientV2.identity.user.disableMfa, - verifyEmail: SpaceConnector.clientV2.identity.user.verifyEmail, + enable: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.user.enable), + disable: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.user.disable), + disableMfa: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.user.disableMfa), + verifyEmail: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.user.verifyEmail), }; return { diff --git a/apps/web/src/api-clients/identity/workspace-user/composables/use-workspace-user-api.ts b/apps/web/src/api-clients/identity/workspace-user/composables/use-workspace-user-api.ts index 1136eeae6e..fc9ef0f91e 100644 --- a/apps/web/src/api-clients/identity/workspace-user/composables/use-workspace-user-api.ts +++ b/apps/web/src/api-clients/identity/workspace-user/composables/use-workspace-user-api.ts @@ -6,10 +6,13 @@ import type { FindWorkspaceUserParameters } from '@/api-clients/identity/workspa import type { WorkspaceUserGetParameters } from '@/api-clients/identity/workspace-user/schema/api-verbs/get'; import type { WorkspaceUserListParameters } from '@/api-clients/identity/workspace-user/schema/api-verbs/list'; import type { WorkspaceUserModel } from '@/api-clients/identity/workspace-user/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useWorkspaceUserApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('workspaceUser'); + const actions = { - create: SpaceConnector.clientV2.identity.workspaceUser.create, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.identity.workspaceUser.create), get: SpaceConnector.clientV2.identity.workspaceUser.get, list: SpaceConnector.clientV2.identity.workspaceUser.list>, find: SpaceConnector.clientV2.identity.workspaceUser.find, diff --git a/apps/web/src/api-clients/inventory/collector/composables/use-collector-api.ts b/apps/web/src/api-clients/inventory/collector/composables/use-collector-api.ts index 8ea13df805..fc46838ae4 100644 --- a/apps/web/src/api-clients/inventory/collector/composables/use-collector-api.ts +++ b/apps/web/src/api-clients/inventory/collector/composables/use-collector-api.ts @@ -10,17 +10,21 @@ import type { CollectorUpdateParameters } from '@/api-clients/inventory/collecto import type { CollectorUpdatePluginParameters } from '@/api-clients/inventory/collector/schema/api-verbs/update-plugin'; import type { CollectorModel } from '@/api-clients/inventory/collector/schema/model'; import type { JobModel } from '@/api-clients/inventory/job/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useCollectorApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('collector'); + const actions = { - collect: SpaceConnector.clientV2.inventory.collector.collect, - create: SpaceConnector.clientV2.inventory.collector.create, - delete: SpaceConnector.clientV2.inventory.collector.delete, + collect: wrapResourceCacheRefresh(SpaceConnector.clientV2.inventory.collector.collect), + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.inventory.collector.create), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.inventory.collector.delete), + get: SpaceConnector.clientV2.inventory.collector.get, list: SpaceConnector.clientV2.inventory.collector.list>, - update: SpaceConnector.clientV2.inventory.collector.update, - updatePlugin: SpaceConnector.clientV2.inventory.collector.updatePlugin, + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.inventory.collector.update), + updatePlugin: wrapResourceCacheRefresh(SpaceConnector.clientV2.inventory.collector.updatePlugin), }; return { diff --git a/apps/web/src/api-clients/inventory/metric/composables/use-metric-api.ts b/apps/web/src/api-clients/inventory/metric/composables/use-metric-api.ts index 80f39ad737..842a6e5611 100644 --- a/apps/web/src/api-clients/inventory/metric/composables/use-metric-api.ts +++ b/apps/web/src/api-clients/inventory/metric/composables/use-metric-api.ts @@ -8,14 +8,17 @@ import type { MetricListParameters } from '@/api-clients/inventory/metric/schema import type { MetricRunParameters } from '@/api-clients/inventory/metric/schema/api-verbs/run'; import type { MetricUpdateParameters } from '@/api-clients/inventory/metric/schema/api-verbs/update'; import type { MetricModel } from '@/api-clients/inventory/metric/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useMetricApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('metric'); + const actions = { - create: SpaceConnector.clientV2.inventory.metric.create, - delete: SpaceConnector.clientV2.inventory.metric.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.inventory.metric.create), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.inventory.metric.delete), get: SpaceConnector.clientV2.inventory.metric.get, - run: SpaceConnector.clientV2.inventory.metric.run, - update: SpaceConnector.clientV2.inventory.metric.update, + run: wrapResourceCacheRefresh(SpaceConnector.clientV2.inventory.metric.run), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.inventory.metric.update), list: SpaceConnector.clientV2.inventory.metric.list>, }; diff --git a/apps/web/src/api-clients/monitoring/escalation-policy/composables/use-escalation-policy-api.ts b/apps/web/src/api-clients/monitoring/escalation-policy/composables/use-escalation-policy-api.ts index 034ef70877..967db1197d 100644 --- a/apps/web/src/api-clients/monitoring/escalation-policy/composables/use-escalation-policy-api.ts +++ b/apps/web/src/api-clients/monitoring/escalation-policy/composables/use-escalation-policy-api.ts @@ -8,15 +8,18 @@ import type { EscalationPolicyListParameters } from '@/api-clients/monitoring/es import type { EscalationPolicySetDefaultParameters } from '@/api-clients/monitoring/escalation-policy/schema/api-verbs/set-default'; import type { EscalationPolicyUpdateParameters } from '@/api-clients/monitoring/escalation-policy/schema/api-verbs/update'; import type { EscalationPolicyModel } from '@/api-clients/monitoring/escalation-policy/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useEscalationPolicyApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('monitoringEscalationPolicy'); + const actions = { - create: SpaceConnector.clientV2.monitoring.escalationPolicy.create, - delete: SpaceConnector.clientV2.monitoring.escalationPolicy.delete, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.escalationPolicy.create), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.escalationPolicy.delete), get: SpaceConnector.clientV2.monitoring.escalationPolicy.get, list: SpaceConnector.clientV2.monitoring.escalationPolicy.list>, - setDefault: SpaceConnector.clientV2.monitoring.escalationPolicy.setDefault, - update: SpaceConnector.clientV2.monitoring.escalationPolicy.update, + setDefault: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.escalationPolicy.setDefault), + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.escalationPolicy.update), }; return { escalationPolicyAPI: actions, diff --git a/apps/web/src/api-clients/monitoring/webhook/composables/use-webhook-api.ts b/apps/web/src/api-clients/monitoring/webhook/composables/use-webhook-api.ts index 917ef0ee9f..e168d9a9e5 100644 --- a/apps/web/src/api-clients/monitoring/webhook/composables/use-webhook-api.ts +++ b/apps/web/src/api-clients/monitoring/webhook/composables/use-webhook-api.ts @@ -11,18 +11,21 @@ import type { WebhookUpdateParameters } from '@/api-clients/monitoring/webhook/s import type { WebhookUpdatePluginParameters } from '@/api-clients/monitoring/webhook/schema/api-verbs/update-plugin'; import type { WebhookVerifyPluginParameters } from '@/api-clients/monitoring/webhook/schema/api-verbs/verify-plugin'; import type { WebhookModel } from '@/api-clients/monitoring/webhook/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useWebhookApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('monitoringWebhook'); + const actions = { - create: SpaceConnector.clientV2.monitoring.webhook.create, - delete: SpaceConnector.clientV2.monitoring.webhook.delete, - disable: SpaceConnector.clientV2.monitoring.webhook.disable, - enable: SpaceConnector.clientV2.monitoring.webhook.enable, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.webhook.create), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.webhook.delete), + disable: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.webhook.disable), + enable: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.webhook.enable), get: SpaceConnector.clientV2.monitoring.webhook.get, list: SpaceConnector.clientV2.monitoring.webhook.list>, - update: SpaceConnector.clientV2.monitoring.webhook.update, - updatePlugin: SpaceConnector.clientV2.monitoring.webhook.updatePlugin, - verifyPlugin: SpaceConnector.clientV2.monitoring.webhook.verifyPlugin, + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.webhook.update), + updatePlugin: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.webhook.updatePlugin), + verifyPlugin: wrapResourceCacheRefresh(SpaceConnector.clientV2.monitoring.webhook.verifyPlugin), }; return { webhookAPI: actions, diff --git a/apps/web/src/api-clients/notification/protocol/composables/use-protocol-api.ts b/apps/web/src/api-clients/notification/protocol/composables/use-protocol-api.ts index 4ee4b75663..211fd64835 100644 --- a/apps/web/src/api-clients/notification/protocol/composables/use-protocol-api.ts +++ b/apps/web/src/api-clients/notification/protocol/composables/use-protocol-api.ts @@ -10,18 +10,20 @@ import type { ProtocolListParameters } from '@/api-clients/notification/protocol import type { ProtocolUpdateParameters } from '@/api-clients/notification/protocol/schema/api-verbs/update'; import type { ProtocolUpdatePluginParameters } from '@/api-clients/notification/protocol/schema/api-verbs/update-plugin'; import type { ProtocolModel } from '@/api-clients/notification/protocol/schema/model'; - +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useProtocolApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('protocol'); + const actions = { - create: SpaceConnector.clientV2.notification.protocol.create, - delete: SpaceConnector.clientV2.notification.protocol.delete, - disable: SpaceConnector.clientV2.notification.protocol.disable, - enable: SpaceConnector.clientV2.notification.protocol.enable, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.notification.protocol.create), + delete: wrapResourceCacheRefresh(SpaceConnector.clientV2.notification.protocol.delete), + disable: wrapResourceCacheRefresh(SpaceConnector.clientV2.notification.protocol.disable), + enable: wrapResourceCacheRefresh(SpaceConnector.clientV2.notification.protocol.enable), get: SpaceConnector.clientV2.notification.protocol.get, list: SpaceConnector.clientV2.notification.protocol.list>, - update: SpaceConnector.clientV2.notification.protocol.update, - updatePlugin: SpaceConnector.clientV2.notification.protocol.updatePlugin, + update: wrapResourceCacheRefresh(SpaceConnector.clientV2.notification.protocol.update), + updatePlugin: wrapResourceCacheRefresh(SpaceConnector.clientV2.notification.protocol.updatePlugin), }; return { protocolAPI: actions, diff --git a/apps/web/src/api-clients/secret/secret/composables/use-secret-api.ts b/apps/web/src/api-clients/secret/secret/composables/use-secret-api.ts index f65fe3393f..e0dbe88ddc 100644 --- a/apps/web/src/api-clients/secret/secret/composables/use-secret-api.ts +++ b/apps/web/src/api-clients/secret/secret/composables/use-secret-api.ts @@ -5,10 +5,13 @@ import type { SecretCreateParameters } from '@/api-clients/secret/secret/schema/ import type { SecretGetParameters } from '@/api-clients/secret/secret/schema/api-verbs/get'; import type { SecretListParameters } from '@/api-clients/secret/secret/schema/api-verbs/list'; import type { SecretModel } from '@/api-clients/secret/secret/schema/model'; +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; export const useSecretApi = () => { + const { wrapResourceCacheRefresh } = useResourceCacheSync('secret'); + const actions = { - create: SpaceConnector.clientV2.secret.secret.create, + create: wrapResourceCacheRefresh(SpaceConnector.clientV2.secret.secret.create), get: SpaceConnector.clientV2.secret.secret.get, list: SpaceConnector.clientV2.secret.secret.list>, }; diff --git a/apps/web/src/query/resource-query/shared/composable/__tests__/use-resource-cache-sync.test.ts b/apps/web/src/query/resource-query/shared/composable/__tests__/use-resource-cache-sync.test.ts new file mode 100644 index 0000000000..524954e63f --- /dev/null +++ b/apps/web/src/query/resource-query/shared/composable/__tests__/use-resource-cache-sync.test.ts @@ -0,0 +1,140 @@ +import { QueryClient, useQueryClient } from '@tanstack/vue-query'; +import type * as VueQuery from '@tanstack/vue-query'; +import { + describe, it, expect, vi, beforeEach, +} from 'vitest'; + +import { useResourceCacheSync } from '@/query/resource-query/shared/composable/use-resource-cache-sync'; + +vi.mock('@tanstack/vue-query', async (importOriginal) => { + const original = await importOriginal() as typeof VueQuery; + return { + ...original, + useQueryClient: vi.fn(), + }; +}); + +// Mock app context store +vi.mock('@/store/app-context/workspace/user-workspace-store', () => ({ + useUserWorkspaceStore: () => ({ + getters: { + currentWorkspaceId: 'workspace-123', + }, + }), +})); +vi.mock('@/store/app-context/app-context-store', () => ({ + useAppContextStore: () => ({ + getters: { + isAdminMode: false, + }, + }), +})); +// Mock useQueryKeyAppContext +vi.mock('@/query/core/query-key/_composable/use-app-context-query-key', () => ({ + useQueryKeyAppContext: () => ({ + value: ['workspace', 'workspace-123'] as const, + }), +})); + +describe('useResourceCacheSync', () => { + // isolate the test environment (queryClient) + let queryClient: QueryClient; + beforeEach(() => { + queryClient = new QueryClient({ + defaultOptions: { + queries: { + retry: false, + }, + }, + }); + vi.mocked(useQueryClient).mockReturnValue(queryClient); + queryClient.clear(); + }); + + afterEach(() => { + vi.restoreAllMocks(); + }); + + describe('1. wrapResourceCacheRefresh', () => { + it('should invalidate the cache of the resource after the function is successfully executed', async () => { + // Arrange + const { wrapResourceCacheRefresh } = useResourceCacheSync('project'); + const mockApiFn = vi.fn().mockResolvedValue({ status: 'success' }); + const wrappedFn = wrapResourceCacheRefresh(mockApiFn); + const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries'); + + // Act + await wrappedFn({ name: 'new-project' }); + + // Assert + expect(mockApiFn).toHaveBeenCalledTimes(1); + expect(mockApiFn).toHaveBeenCalledWith({ name: 'new-project' }); + + expect(invalidateSpy).toHaveBeenCalledTimes(1); + expect(invalidateSpy).toHaveBeenCalledWith({ + queryKey: ['workspace', 'workspace-123', 'project'], + }); + }); + + it('should invalidate the cache of the resource even if the function fails', async () => { + // Arrange + const { wrapResourceCacheRefresh } = useResourceCacheSync('project'); + const mockApiFn = vi.fn().mockRejectedValue(new Error('API Error')); + const wrappedFn = wrapResourceCacheRefresh(mockApiFn); + const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries'); + + // Act & Assert + await expect(wrappedFn()).rejects.toThrow('API Error'); + + expect(invalidateSpy).toHaveBeenCalledTimes(1); + expect(invalidateSpy).toHaveBeenCalledWith({ + queryKey: ['workspace', 'workspace-123', 'project'], + }); + }); + }); + + describe('2. wrapResourceCacheUpdate', () => { + const resourceType = 'project'; + const resourceQueryKey = ['workspace', 'workspace-123', resourceType]; + + it('should create a new cache with the new data and invalidate the list/stat queries', async () => { + // Arrange + const { wrapResourceCacheUpdate } = useResourceCacheSync(resourceType); + const newProjectData = { project_id: 'project-new', name: 'New Project' }; + const mockApiFn = vi.fn().mockResolvedValue(newProjectData); + const wrappedFn = wrapResourceCacheUpdate(mockApiFn); + const invalidateSpy = vi.spyOn(queryClient, 'invalidateQueries'); + + // Act + await wrappedFn(newProjectData); + + // Assert + const cachedData = queryClient.getQueryData>(resourceQueryKey); + expect(cachedData).toEqual({ 'project-new': newProjectData }); + + expect(invalidateSpy).toHaveBeenCalledTimes(2); + expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: [...resourceQueryKey, 'stat'] }); + expect(invalidateSpy).toHaveBeenCalledWith({ queryKey: [...resourceQueryKey, 'list'] }); + }); + + it('should update the existing cache with the new data', async () => { + // Arrange + const { wrapResourceCacheUpdate } = useResourceCacheSync(resourceType); + const initialData = { project_id: 'project-123', name: 'Old Name' }; + const updatedData = { project_id: 'project-123', name: 'Updated Name' }; + + queryClient.setQueryData(resourceQueryKey, { 'project-123': initialData }); + + const mockApiFn = vi.fn().mockResolvedValue(updatedData); + const wrappedFn = wrapResourceCacheUpdate(mockApiFn); + + // Act + await wrappedFn(updatedData); + + // Assert + const cachedData = queryClient.getQueryData>(resourceQueryKey); + expect(cachedData?.[updatedData.project_id]).toEqual(updatedData); + expect(Object.keys(cachedData ?? {}).length).toBe(1); + }); + }); +}); diff --git a/apps/web/src/query/resource-query/shared/composable/use-resource-cache-sync.ts b/apps/web/src/query/resource-query/shared/composable/use-resource-cache-sync.ts index b6cd8beb26..769efcdab4 100644 --- a/apps/web/src/query/resource-query/shared/composable/use-resource-cache-sync.ts +++ b/apps/web/src/query/resource-query/shared/composable/use-resource-cache-sync.ts @@ -7,60 +7,56 @@ import type { ResourceCacheType, ResourceKeyType } from '@/query/resource-query/ -type MutationCallback = () => Promise; -type callbackForReferenceRefresh = () => Promise; +type Obj = Record; +type AnyFn = (...args: any[]) => any; +type AwaitedRet = Awaited>; -export const useResourceCacheSync = >(resourceType: ResourceKeyType) => { + +export const useResourceCacheSync = (resourceType: ResourceKeyType) => { const queryClient = useQueryClient(); - const mutateWithResourceCacheUpdate = async ( - mutationCallback: MutationCallback, - ): Promise => { - const response = await mutationCallback(); - await _updateResourceCache(resourceType, response, queryClient); - return response; + const wrapResourceCacheRefresh = (fn: F) => async (...args: Parameters): Promise> => { + const { key: referenceQueryKey } = useResourceQueryKey(resourceType); + try { + const res = await fn(...args); + return res; + } finally { + await queryClient.invalidateQueries({ queryKey: referenceQueryKey.value }); + } }; - const refreshResourceCache = async ( - mutationCallback: callbackForReferenceRefresh, - ): Promise => { - await mutationCallback(); - const { key: referenceQueryKey } = useResourceQueryKey(resourceType); - await queryClient.invalidateQueries({ queryKey: referenceQueryKey.value }); + const wrapResourceCacheUpdate = (fn: F) => async (...args: Parameters): Promise> => { + const res = await Promise.resolve(fn(...args)); + await _updateResourceCache(resourceType, res as Obj, queryClient); + return res; }; - return { mutateWithResourceCacheUpdate, refreshResourceCache }; + return { wrapResourceCacheRefresh, wrapResourceCacheUpdate }; }; -const _updateResourceCache = async >( +const _updateResourceCache = async ( resourceType: ResourceKeyType, newData: T, queryClient: QueryClient, ) => { const { key: referenceQueryKey, withSuffix } = useResourceQueryKey(resourceType); - - const idKey = RESOURCE_CONFIG_MAP[resourceType].idKey; + const idKey = RESOURCE_CONFIG_MAP[resourceType].idKey as keyof T; if (!idKey || typeof newData !== 'object' || newData === null || !(idKey in newData)) { throw new Error(`Invalid resource key or data for type: ${resourceType}`); } - queryClient.setQueryData>(referenceQueryKey, (oldData: ResourceCacheType|undefined) => { - const currentResults = oldData ?? {}; - const newDataId = newData[idKey]; + queryClient.setQueryData>(referenceQueryKey.value, (oldData) => { + const currentResults = (oldData ?? {}) as ResourceCacheType; + const newDataId = newData[idKey] as PropertyKey; if (newDataId in currentResults) { - const updatedResults = { ...currentResults }; - updatedResults[newDataId] = newData; - return updatedResults; + return { ...currentResults, [newDataId]: newData }; } - - return { - ...currentResults, - [newDataId]: newData, - }; + return { ...currentResults, [newDataId]: newData }; }); + await Promise.all([ queryClient.invalidateQueries({ queryKey: withSuffix('stat') }), queryClient.invalidateQueries({ queryKey: withSuffix('list') }),