From 7eb31301ad558e6c92685f7689612ebdf5edc3ea Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Fri, 14 Mar 2025 11:06:30 +0900 Subject: [PATCH 01/20] feat(query-key): create reference query key composable & improve query key management logic Signed-off-by: samuel.park --- .../_common/composables/use-api-query-key.ts | 35 +++++------ .../composables/use-global-query-params.ts | 58 +++++++++++++++++++ .../composables/use-reference-query-key.ts | 42 ++++++++++++++ .../_common/constants/query-key-constant.ts | 1 + apps/web/src/query/reference/helper.ts | 8 +++ apps/web/src/query/reference/type.ts | 27 +++++++++ 6 files changed, 149 insertions(+), 22 deletions(-) create mode 100644 apps/web/src/api-clients/_common/composables/use-global-query-params.ts create mode 100644 apps/web/src/api-clients/_common/composables/use-reference-query-key.ts create mode 100644 apps/web/src/api-clients/_common/constants/query-key-constant.ts create mode 100644 apps/web/src/query/reference/helper.ts create mode 100644 apps/web/src/query/reference/type.ts diff --git a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts index 1c92d0c5f8..4ef0c52dd9 100644 --- a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts +++ b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts @@ -1,11 +1,12 @@ -import { computed, reactive } from 'vue'; +import { computed } from 'vue'; import type { ResourceName, ServiceName, Verb, } from '@/api-clients/_common/types/query-key-type'; -import { useAppContextStore } from '@/store/app-context/app-context-store'; -import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store'; +import { SERVICE_PREFIX } from '../constants/query-key-constant'; +import type { GlobalQueryParams } from './use-global-query-params'; +import { useGlobalQueryParams } from './use-global-query-params'; /** * Generates a computed query key for API requests, incorporating global parameters. @@ -14,7 +15,7 @@ import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-worksp * @param resource - The resource name, specifying the target API resource (e.g., 'public-data-table'). * @param verb - The API action verb, defining the type of request (e.g., 'get', 'list', 'update'). * @param additionalGlobalParams - Optional additional global parameters (e.g., workspace ID, admin mode). - * @returns A computed reference to the query key array, structured as `[service, resource, verb, { globalParams }]`. + * @returns A computed reference to the query key array, structured as `[SERVICE_PREFIX, service, resource, verb, { globalParams }]`. * * ### Example Usage: * ```ts @@ -26,29 +27,19 @@ import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-worksp * - **Cache management**: Enables precise cache invalidation and data synchronization. */ -interface GlobalQueryParams { - workspaceId?: string; - isAdminMode?: boolean; -} export const useAPIQueryKey = , V extends Verb>( service: S, resource: R, verb: V, additionalGlobalParams?: Partial, ) => { - const appContextStore = useAppContextStore(); - const userWorkspaceStore = useUserWorkspaceStore(); + const globalQueryParams = useGlobalQueryParams(additionalGlobalParams); - const _state = reactive({ - currentWorkdpaceId: computed(() => userWorkspaceStore.getters.currentWorkspaceId), - isAdminMode: computed(() => appContextStore.getters.isAdminMode), - }); - - const globalQueryParams = reactive({ - workspaceId: _state.currentWorkdpaceId, - isAdminMode: _state.isAdminMode, - ...additionalGlobalParams, - }); - - return computed(() => [service, resource, verb, { ...globalQueryParams }]); + return computed(() => [ + SERVICE_PREFIX, + service, + resource, + verb, + { ...globalQueryParams.value }, + ]); }; diff --git a/apps/web/src/api-clients/_common/composables/use-global-query-params.ts b/apps/web/src/api-clients/_common/composables/use-global-query-params.ts new file mode 100644 index 0000000000..795eae329b --- /dev/null +++ b/apps/web/src/api-clients/_common/composables/use-global-query-params.ts @@ -0,0 +1,58 @@ +import type { ComputedRef } from 'vue'; +import { computed, reactive } from 'vue'; + +import { useAppContextStore } from '@/store/app-context/app-context-store'; +import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store'; + +/** + * Interface for global query parameters used across API requests. + * These parameters are automatically included in API and reference query keys. + */ +export interface GlobalQueryParams { + /** Current workspace ID from the workspace context */ + workspaceId?: string; + /** Flag indicating whether admin mode is enabled */ + isAdminMode?: boolean; +} + +/** + * Composable that manages global query parameters with reactive state. + * This hook centralizes the management of workspace and admin mode parameters + * that are commonly used across different API queries. + * + * @param additionalGlobalParams - Optional additional global parameters to merge with default params + * @returns A computed reference containing the combined global query parameters + * + * ### Example Usage: + * ```ts + * const globalParams = useGlobalQueryParams(); + * // Access params + * console.log(globalParams.value.workspaceId); + * console.log(globalParams.value.isAdminMode); + * + * // With additional params + * const params = useGlobalQueryParams({ workspaceId: 'custom-id' }); + * ``` + * + * ### Features: + * - **Reactive State**: Automatically updates when workspace or admin mode changes + * - **Parameter Merging**: Allows overriding default params with custom values + * - **Type Safety**: Provides TypeScript interfaces for parameter validation + */ +export const useGlobalQueryParams = (additionalGlobalParams?: Partial): ComputedRef => { + const appContextStore = useAppContextStore(); + const userWorkspaceStore = useUserWorkspaceStore(); + + const _state = reactive({ + currentWorkspaceId: computed(() => userWorkspaceStore.getters.currentWorkspaceId), + isAdminMode: computed(() => appContextStore.getters.isAdminMode), + }); + + const globalQueryParams = reactive({ + workspaceId: _state.currentWorkspaceId, + isAdminMode: _state.isAdminMode, + ...additionalGlobalParams, + }); + + return computed(() => ({ ...globalQueryParams })); +}; diff --git a/apps/web/src/api-clients/_common/composables/use-reference-query-key.ts b/apps/web/src/api-clients/_common/composables/use-reference-query-key.ts new file mode 100644 index 0000000000..336701ec06 --- /dev/null +++ b/apps/web/src/api-clients/_common/composables/use-reference-query-key.ts @@ -0,0 +1,42 @@ +import { computed } from 'vue'; + +import { getReferencePrimaryQueryKey } from '@/query/reference/helper'; +import type { ReferenceResourceType } from '@/query/reference/type'; + +import type { GlobalQueryParams } from './use-global-query-params'; +import { useGlobalQueryParams } from './use-global-query-params'; + +/** + * Composable that generates a reference query key with global parameters. + * This hook creates a query key specifically for reference data, which is structured differently + * from regular API query keys but still includes global parameters. + * + * @param resourceType - The type of reference resource (e.g., 'public-dashboard', 'project') + * @param additionalGlobalParams - Optional additional global parameters to include in the query key + * @returns A computed reference to the query key array, structured as `[REFERENCE_PREFIX, ...referencePrimaryKey, { globalParams }]` + * + * ### Example Usage: + * ```ts + * // Basic usage + * const referenceKey = useReferenceQueryKey('public-dashboard'); + * + * // With additional params + * const referenceKey = useReferenceQueryKey('public-dashboard', { workspaceId: 'custom-id' }); + * ``` + * + * ### Features: + * - **Reference Key Structure**: Creates a specialized key structure for reference data + * - **Global Parameter Integration**: Automatically includes workspace and admin mode parameters + * - **Type Safety**: Ensures valid reference resource types through TypeScript + */ +export const useReferenceQueryKey = ( + resourceType: ReferenceResourceType, + additionalGlobalParams?: Partial, +) => { + const globalQueryParams = useGlobalQueryParams(additionalGlobalParams); + + return computed(() => [ + ...getReferencePrimaryQueryKey(resourceType), + { ...globalQueryParams.value }, + ]); +}; diff --git a/apps/web/src/api-clients/_common/constants/query-key-constant.ts b/apps/web/src/api-clients/_common/constants/query-key-constant.ts new file mode 100644 index 0000000000..07acce3fe0 --- /dev/null +++ b/apps/web/src/api-clients/_common/constants/query-key-constant.ts @@ -0,0 +1 @@ +export const SERVICE_PREFIX = 'service' as const; diff --git a/apps/web/src/query/reference/helper.ts b/apps/web/src/query/reference/helper.ts new file mode 100644 index 0000000000..4a4905337e --- /dev/null +++ b/apps/web/src/query/reference/helper.ts @@ -0,0 +1,8 @@ +import type { ReferenceResourceType } from './type'; + +export const REFERENCE_PREFIX = 'reference' as const; + +export const getReferencePrimaryQueryKey = (resourceType: ReferenceResourceType) => [ + REFERENCE_PREFIX, + resourceType, +]; diff --git a/apps/web/src/query/reference/type.ts b/apps/web/src/query/reference/type.ts new file mode 100644 index 0000000000..4f47b86356 --- /dev/null +++ b/apps/web/src/query/reference/type.ts @@ -0,0 +1,27 @@ +export type ReferenceResourceType = + 'app' + |'cloud-service-type' + |'cloud-service-query-set' + |'collector' + |'cost-data-source' + |'escalation-policy' + |'metric' + |'namespace' + |'plugin' + |'project-group' + |'project' + |'protocol' + |'provider' + |'public-dashboard' + |'public-folder' + |'region' + |'role' + |'secret' + |'service-account' + |'service' + |'trusted-service-account' + |'user-group' + |'user' + |'webhook' + |'workspace-group' + |'workspace'; From 053af7980004c37b7db829692297bc13788cec56 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Fri, 14 Mar 2025 11:13:05 +0900 Subject: [PATCH 02/20] fix(service-query): apply query invalidation (admin <-> workspace) Signed-off-by: samuel.park --- .../top-bar-admin-toggle-button/TopBarAdminToggleButton.vue | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue index 1e47de19ed..618365d53e 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue @@ -2,8 +2,10 @@ import Vue, { computed, reactive } from 'vue'; import { useRouter } from 'vue-router/composables'; +import { useQueryClient } from '@tanstack/vue-query'; import { throttle } from 'lodash'; +import { SERVICE_PREFIX } from '@/api-clients/_common/constants/query-key-constant'; import type { WorkspaceModel } from '@/api-clients/identity/workspace/schema/model'; import { i18n } from '@/translations'; @@ -20,6 +22,7 @@ const appContextStore = useAppContextStore(); const userWorkspaceStore = useUserWorkspaceStore(); const workspaceStoreGetters = userWorkspaceStore.getters; const router = useRouter(); +const queryClient = useQueryClient(); const state = reactive({ isAdminMode: computed(() => appContextStore.getters.isAdminMode), @@ -34,6 +37,7 @@ const handleToggleAdminMode = throttle(async () => { return; } appContextStore.setGlobalGrantLoading(true); + await queryClient.invalidateQueries({ queryKey: [SERVICE_PREFIX] }); if (state.isAdminMode) { await userWorkspaceStore.load(); if (state.workspaceList.length === 0) { From 63ba0540ed80a83fa17ec0d29ffcf11ef658b76b Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Mon, 17 Mar 2025 01:05:48 +0900 Subject: [PATCH 03/20] refactor(query-key): refactor service/reference query key composable & refactor dir Signed-off-by: samuel.park --- .../_common/composables/use-api-query-key.ts | 20 ++++---- .../_common/types/query-key-type.ts | 11 +++++ .../_composables/use-query-key-base.ts} | 48 +++++++++++-------- apps/web/src/query/_types/query-key-type.ts | 9 ++++ .../_composables}/use-reference-query-key.ts | 21 ++++---- .../reference/_constant/query-key-constant.ts | 1 + .../_helper/reference-query-key-helper.ts | 7 +++ .../_types/reference-query-key-type.ts | 16 +++++++ .../reference-resource-type.ts} | 0 apps/web/src/query/reference/helper.ts | 8 ---- 10 files changed, 94 insertions(+), 47 deletions(-) rename apps/web/src/{api-clients/_common/composables/use-global-query-params.ts => query/_composables/use-query-key-base.ts} (52%) create mode 100644 apps/web/src/query/_types/query-key-type.ts rename apps/web/src/{api-clients/_common/composables => query/reference/_composables}/use-reference-query-key.ts (62%) create mode 100644 apps/web/src/query/reference/_constant/query-key-constant.ts create mode 100644 apps/web/src/query/reference/_helper/reference-query-key-helper.ts create mode 100644 apps/web/src/query/reference/_types/reference-query-key-type.ts rename apps/web/src/query/reference/{type.ts => _types/reference-resource-type.ts} (100%) delete mode 100644 apps/web/src/query/reference/helper.ts diff --git a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts index 4ef0c52dd9..0ad6f517f8 100644 --- a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts +++ b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts @@ -1,12 +1,12 @@ +import type { ComputedRef } from 'vue'; import { computed } from 'vue'; +import { SERVICE_PREFIX } from '@/api-clients/_common/constants/query-key-constant'; import type { - ResourceName, ServiceName, Verb, + ResourceName, ServiceName, ServiceQueryKey, Verb, } from '@/api-clients/_common/types/query-key-type'; - -import { SERVICE_PREFIX } from '../constants/query-key-constant'; -import type { GlobalQueryParams } from './use-global-query-params'; -import { useGlobalQueryParams } from './use-global-query-params'; +import type { QueryKeyBaseParams } from '@/query/_composables/use-query-key-base'; +import { useQueryKeyBase } from '@/query/_composables/use-query-key-base'; /** * Generates a computed query key for API requests, incorporating global parameters. @@ -14,7 +14,7 @@ import { useGlobalQueryParams } from './use-global-query-params'; * @param service - The service name, representing the API service scope (e.g., 'dashboard'). * @param resource - The resource name, specifying the target API resource (e.g., 'public-data-table'). * @param verb - The API action verb, defining the type of request (e.g., 'get', 'list', 'update'). - * @param additionalGlobalParams - Optional additional global parameters (e.g., workspace ID, admin mode). + * @param queryKeyOptions - Optional query key options to merge with default params * @returns A computed reference to the query key array, structured as `[SERVICE_PREFIX, service, resource, verb, { globalParams }]`. * * ### Example Usage: @@ -31,15 +31,15 @@ export const useAPIQueryKey = , service: S, resource: R, verb: V, - additionalGlobalParams?: Partial, -) => { - const globalQueryParams = useGlobalQueryParams(additionalGlobalParams); + queryKeyOptions?: Partial, +): ComputedRef> => { + const queryKeyBase = useQueryKeyBase(queryKeyOptions); return computed(() => [ + ...queryKeyBase.value, SERVICE_PREFIX, service, resource, verb, - { ...globalQueryParams.value }, ]); }; diff --git a/apps/web/src/api-clients/_common/types/query-key-type.ts b/apps/web/src/api-clients/_common/types/query-key-type.ts index b8430ca461..8d90137d90 100644 --- a/apps/web/src/api-clients/_common/types/query-key-type.ts +++ b/apps/web/src/api-clients/_common/types/query-key-type.ts @@ -1,4 +1,7 @@ import type { API_DOC } from '@/api-clients/_common/constants/api-doc'; +import type { SERVICE_PREFIX } from '@/api-clients/_common/constants/query-key-constant'; +import type { QueryKeyBase } from '@/query/_types/query-key-type'; + /** @@ -7,3 +10,11 @@ import type { API_DOC } from '@/api-clients/_common/constants/api-doc'; export type ServiceName = keyof typeof API_DOC; export type ResourceName = keyof (typeof API_DOC)[S]; export type Verb> = Extract<(typeof API_DOC)[S][R], string[]>[number] | string; + +export type ServiceQueryKey, V extends Verb> = [ + ...QueryKeyBase, + typeof SERVICE_PREFIX, + S, + R, + V, +]; diff --git a/apps/web/src/api-clients/_common/composables/use-global-query-params.ts b/apps/web/src/query/_composables/use-query-key-base.ts similarity index 52% rename from apps/web/src/api-clients/_common/composables/use-global-query-params.ts rename to apps/web/src/query/_composables/use-query-key-base.ts index 795eae329b..56df222100 100644 --- a/apps/web/src/api-clients/_common/composables/use-global-query-params.ts +++ b/apps/web/src/query/_composables/use-query-key-base.ts @@ -1,18 +1,23 @@ import type { ComputedRef } from 'vue'; import { computed, reactive } from 'vue'; +import type { QueryKeyBase } from '@/query/_types/query-key-type'; + import { useAppContextStore } from '@/store/app-context/app-context-store'; import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store'; + /** * Interface for global query parameters used across API requests. * These parameters are automatically included in API and reference query keys. */ -export interface GlobalQueryParams { - /** Current workspace ID from the workspace context */ - workspaceId?: string; +export interface QueryKeyBaseParams { /** Flag indicating whether admin mode is enabled */ isAdminMode?: boolean; + /** Current workspace ID from the workspace context */ + workspaceId?: string; + /** Additional parameters that might be added */ + [key: string]: any; } /** @@ -20,39 +25,42 @@ export interface GlobalQueryParams { * This hook centralizes the management of workspace and admin mode parameters * that are commonly used across different API queries. * - * @param additionalGlobalParams - Optional additional global parameters to merge with default params - * @returns A computed reference containing the combined global query parameters + * @param queryKeyOptions - Optional query key options to merge with default params + * @returns A computed reference containing the combined global query parameters as an ordered array * * ### Example Usage: * ```ts - * const globalParams = useGlobalQueryParams(); - * // Access params - * console.log(globalParams.value.workspaceId); - * console.log(globalParams.value.isAdminMode); + * const queryKeyBase = useQueryKeyBase(); + * // Access params (now returns array) + * const [mode, workspaceId, others] = queryKeyBase.value; * * // With additional params - * const params = useGlobalQueryParams({ workspaceId: 'custom-id' }); + * const params = useQueryKeyBase({ customParam: 'value' }); * ``` * * ### Features: + * - **Ordered Parameters**: Guarantees consistent parameter order: [mode, workspaceId, others] * - **Reactive State**: Automatically updates when workspace or admin mode changes - * - **Parameter Merging**: Allows overriding default params with custom values - * - **Type Safety**: Provides TypeScript interfaces for parameter validation + * - **Parameter Merging**: Allows adding custom parameters in the others object */ -export const useGlobalQueryParams = (additionalGlobalParams?: Partial): ComputedRef => { +export const useQueryKeyBase = (queryKeyOptions?: Partial): ComputedRef => { const appContextStore = useAppContextStore(); const userWorkspaceStore = useUserWorkspaceStore(); const _state = reactive({ - currentWorkspaceId: computed(() => userWorkspaceStore.getters.currentWorkspaceId), isAdminMode: computed(() => appContextStore.getters.isAdminMode), + currentWorkspaceId: computed(() => userWorkspaceStore.getters.currentWorkspaceId), }); - const globalQueryParams = reactive({ - workspaceId: _state.currentWorkspaceId, - isAdminMode: _state.isAdminMode, - ...additionalGlobalParams, - }); + return computed(() => { + const { isAdminMode, workspaceId: _workspaceId, ...otherParams } = queryKeyOptions || {}; + const mode = (isAdminMode || _state.isAdminMode) ? 'ADMIN' : 'WORKSPACE'; + const workspaceId = _workspaceId || _state.currentWorkspaceId; - return computed(() => ({ ...globalQueryParams })); + return [ + mode, + workspaceId, + Object.keys(otherParams).length > 0 ? otherParams : undefined, + ]; + }); }; diff --git a/apps/web/src/query/_types/query-key-type.ts b/apps/web/src/query/_types/query-key-type.ts new file mode 100644 index 0000000000..075e152cf9 --- /dev/null +++ b/apps/web/src/query/_types/query-key-type.ts @@ -0,0 +1,9 @@ + +export type QueryKeyBase = [ + mode: 'ADMIN' | 'WORKSPACE', + workspaceId: string | undefined, + others: Record | undefined, +]; + + + diff --git a/apps/web/src/api-clients/_common/composables/use-reference-query-key.ts b/apps/web/src/query/reference/_composables/use-reference-query-key.ts similarity index 62% rename from apps/web/src/api-clients/_common/composables/use-reference-query-key.ts rename to apps/web/src/query/reference/_composables/use-reference-query-key.ts index 336701ec06..90632e001d 100644 --- a/apps/web/src/api-clients/_common/composables/use-reference-query-key.ts +++ b/apps/web/src/query/reference/_composables/use-reference-query-key.ts @@ -1,10 +1,13 @@ +import type { ComputedRef } from 'vue'; import { computed } from 'vue'; -import { getReferencePrimaryQueryKey } from '@/query/reference/helper'; -import type { ReferenceResourceType } from '@/query/reference/type'; +import type { QueryKeyBaseParams } from '@/query/_composables/use-query-key-base'; +import { useQueryKeyBase } from '@/query/_composables/use-query-key-base'; +import { getReferencePrimaryQueryKey } from '@/query/reference/_helper/reference-query-key-helper'; +import type { ReferenceQueryKey } from '@/query/reference/_types/reference-query-key-type'; +import type { ReferenceResourceType } from '@/query/reference/_types/reference-resource-type'; + -import type { GlobalQueryParams } from './use-global-query-params'; -import { useGlobalQueryParams } from './use-global-query-params'; /** * Composable that generates a reference query key with global parameters. @@ -12,7 +15,7 @@ import { useGlobalQueryParams } from './use-global-query-params'; * from regular API query keys but still includes global parameters. * * @param resourceType - The type of reference resource (e.g., 'public-dashboard', 'project') - * @param additionalGlobalParams - Optional additional global parameters to include in the query key + * @param queryKeyOptions - Optional query key options to merge with default params * @returns A computed reference to the query key array, structured as `[REFERENCE_PREFIX, ...referencePrimaryKey, { globalParams }]` * * ### Example Usage: @@ -31,12 +34,12 @@ import { useGlobalQueryParams } from './use-global-query-params'; */ export const useReferenceQueryKey = ( resourceType: ReferenceResourceType, - additionalGlobalParams?: Partial, -) => { - const globalQueryParams = useGlobalQueryParams(additionalGlobalParams); + queryKeyOptions?: Partial, +): ComputedRef => { + const queryKeyBase = useQueryKeyBase(queryKeyOptions); return computed(() => [ + ...queryKeyBase.value, ...getReferencePrimaryQueryKey(resourceType), - { ...globalQueryParams.value }, ]); }; diff --git a/apps/web/src/query/reference/_constant/query-key-constant.ts b/apps/web/src/query/reference/_constant/query-key-constant.ts new file mode 100644 index 0000000000..6b3d88f9b5 --- /dev/null +++ b/apps/web/src/query/reference/_constant/query-key-constant.ts @@ -0,0 +1 @@ +export const REFERENCE_PREFIX = 'reference' as const; diff --git a/apps/web/src/query/reference/_helper/reference-query-key-helper.ts b/apps/web/src/query/reference/_helper/reference-query-key-helper.ts new file mode 100644 index 0000000000..caca6958be --- /dev/null +++ b/apps/web/src/query/reference/_helper/reference-query-key-helper.ts @@ -0,0 +1,7 @@ +import { REFERENCE_PREFIX } from '@/query/reference/_constant/query-key-constant'; +import type { ReferenceResourceType } from '@/query/reference/_types/reference-resource-type'; + +export const getReferencePrimaryQueryKey = (resourceType: ReferenceResourceType): [typeof REFERENCE_PREFIX, ReferenceResourceType] => [ + REFERENCE_PREFIX, + resourceType, +]; diff --git a/apps/web/src/query/reference/_types/reference-query-key-type.ts b/apps/web/src/query/reference/_types/reference-query-key-type.ts new file mode 100644 index 0000000000..0c1cc2a21f --- /dev/null +++ b/apps/web/src/query/reference/_types/reference-query-key-type.ts @@ -0,0 +1,16 @@ +import type { QueryKeyBase } from '@/query/_types/query-key-type'; +import { REFERENCE_PREFIX } from '@/query/reference/_constant/query-key-constant'; +import type { ReferenceResourceType } from '@/query/reference/_types/reference-resource-type'; + + +export type ReferenceQueryKey = [ + ...QueryKeyBase, + typeof REFERENCE_PREFIX, + ReferenceResourceType +]; + +// 명시적인 반환 타입 정의 +export const getReferencePrimaryQueryKey = (resourceType: ReferenceResourceType): [typeof REFERENCE_PREFIX, ReferenceResourceType] => [ + REFERENCE_PREFIX, + resourceType, +]; diff --git a/apps/web/src/query/reference/type.ts b/apps/web/src/query/reference/_types/reference-resource-type.ts similarity index 100% rename from apps/web/src/query/reference/type.ts rename to apps/web/src/query/reference/_types/reference-resource-type.ts diff --git a/apps/web/src/query/reference/helper.ts b/apps/web/src/query/reference/helper.ts deleted file mode 100644 index 4a4905337e..0000000000 --- a/apps/web/src/query/reference/helper.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { ReferenceResourceType } from './type'; - -export const REFERENCE_PREFIX = 'reference' as const; - -export const getReferencePrimaryQueryKey = (resourceType: ReferenceResourceType) => [ - REFERENCE_PREFIX, - resourceType, -]; From 138387baabccfb7c85aa2b16755ce48ea487d8e3 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Mon, 17 Mar 2025 01:07:08 +0900 Subject: [PATCH 04/20] feat(query-client): create and register base query client Signed-off-by: samuel.park --- apps/web/src/main.ts | 4 +++- apps/web/src/query/index.ts | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 apps/web/src/query/index.ts diff --git a/apps/web/src/main.ts b/apps/web/src/main.ts index 3d8cc3687e..6ef2d9a2fc 100644 --- a/apps/web/src/main.ts +++ b/apps/web/src/main.ts @@ -10,6 +10,7 @@ import VTooltip from 'v-tooltip'; import SpaceDesignSystem from '@cloudforet/mirinae'; import directive from '@/directives'; +import { queryClient } from '@/query'; import { SpaceRouter } from '@/router'; import { i18n } from '@/translations'; @@ -17,6 +18,7 @@ import { pinia } from '@/store/pinia'; import { siteInit } from '@/lib/site-initializer'; + import App from './App.vue'; import '@/styles/style.pcss'; @@ -30,7 +32,7 @@ Vue.use(Fragment.Plugin); Vue.use(VTooltip, { defaultClass: 'p-tooltip', defaultBoundariesElement: document.body }); Vue.use(PortalVue); Vue.use(PiniaVuePlugin); -Vue.use(VueQueryPlugin); +Vue.use(VueQueryPlugin, { queryClient }); directive(Vue); diff --git a/apps/web/src/query/index.ts b/apps/web/src/query/index.ts new file mode 100644 index 0000000000..5e6f978ebc --- /dev/null +++ b/apps/web/src/query/index.ts @@ -0,0 +1,3 @@ +import { QueryClient } from '@tanstack/vue-query'; + +export const queryClient = new QueryClient(); From 17f33851a754d19f594439f170d60bf08e8f731f Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Mon, 17 Mar 2025 01:08:11 +0900 Subject: [PATCH 05/20] feat(invalidator): create service/reference query global invalidator Signed-off-by: samuel.park --- .../helpers/service-query-invalidation-helper.ts | 16 ++++++++++++++++ .../reference-query-invalidation-helper.ts | 14 ++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts create mode 100644 apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts diff --git a/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts b/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts new file mode 100644 index 0000000000..1df9e803a7 --- /dev/null +++ b/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts @@ -0,0 +1,16 @@ +import { SERVICE_PREFIX } from '@/api-clients/_common/constants/query-key-constant'; +import { queryClient } from '@/query'; + + + + +export const invalidateServiceQuery = (mode?: 'ADMIN' | 'WORKSPACE') => { + queryClient.invalidateQueries({ + predicate: (query) => { + const [queryMode,,, queryType] = query.queryKey; + if (queryType !== SERVICE_PREFIX) return false; + if (mode && mode !== queryMode) return false; + return true; + }, + }); +}; diff --git a/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts b/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts new file mode 100644 index 0000000000..c917625220 --- /dev/null +++ b/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts @@ -0,0 +1,14 @@ +import { queryClient } from '@/query'; +import { REFERENCE_PREFIX } from '@/query/reference/_constant/query-key-constant'; + + +export const invalidateReferenceQuery = (mode?: 'ADMIN' | 'WORKSPACE') => { + queryClient.invalidateQueries({ + predicate: (query) => { + const [queryMode,,, queryType] = query.queryKey; + if (queryType !== REFERENCE_PREFIX) return false; + if (mode && mode !== queryMode) return false; + return true; + }, + }); +}; From 1b0f7b637509c41532267614c662cf6c821dd1c3 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Mon, 17 Mar 2025 09:32:10 +0900 Subject: [PATCH 06/20] refactor: improve query key type (service/reference) Signed-off-by: samuel.park --- .../_common/composables/use-api-query-key.ts | 30 +++++++------ .../service-query-invalidation-helper.ts | 20 +++++---- .../_common/types/query-key-type.ts | 6 +-- ...y-key-base.ts => use-query-key-context.ts} | 43 ++++++++++--------- apps/web/src/query/_types/query-key-type.ts | 8 ++-- .../_composables/use-reference-query-key.ts | 20 +++++---- .../reference/_constant/query-key-constant.ts | 1 - .../reference-query-invalidation-helper.ts | 18 +++++--- .../_helper/reference-query-key-helper.ts | 7 --- .../_types/reference-query-key-type.ts | 12 +----- 10 files changed, 82 insertions(+), 83 deletions(-) rename apps/web/src/query/_composables/{use-query-key-base.ts => use-query-key-context.ts} (56%) delete mode 100644 apps/web/src/query/reference/_constant/query-key-constant.ts delete mode 100644 apps/web/src/query/reference/_helper/reference-query-key-helper.ts diff --git a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts index 0ad6f517f8..fcad7252f9 100644 --- a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts +++ b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts @@ -1,12 +1,11 @@ import type { ComputedRef } from 'vue'; import { computed } from 'vue'; -import { SERVICE_PREFIX } from '@/api-clients/_common/constants/query-key-constant'; import type { ResourceName, ServiceName, ServiceQueryKey, Verb, } from '@/api-clients/_common/types/query-key-type'; -import type { QueryKeyBaseParams } from '@/query/_composables/use-query-key-base'; -import { useQueryKeyBase } from '@/query/_composables/use-query-key-base'; +import type { QueryKeyContextParams } from '@/query/_composables/use-query-key-context'; +import { useQueryKeyContext } from '@/query/_composables/use-query-key-context'; /** * Generates a computed query key for API requests, incorporating global parameters. @@ -15,29 +14,36 @@ import { useQueryKeyBase } from '@/query/_composables/use-query-key-base'; * @param resource - The resource name, specifying the target API resource (e.g., 'public-data-table'). * @param verb - The API action verb, defining the type of request (e.g., 'get', 'list', 'update'). * @param queryKeyOptions - Optional query key options to merge with default params - * @returns A computed reference to the query key array, structured as `[SERVICE_PREFIX, service, resource, verb, { globalParams }]`. + * @returns A computed reference to the query key array, structured as `[QueryContext, service, resource, verb]` * * ### Example Usage: * ```ts - * const queryKey = useAPIQueryKey('dashboard', 'public-data-table', 'get'); + * // Basic usage + * const queryKey = useAPIQueryKey('dashboard', 'public-data-table', 'get'); + * + * // With additional params + * const queryKey = useAPIQueryKey('dashboard', 'public-data-table', 'get', { + * workspaceId: 'custom-id', + * isAdminMode: true + * }); * ``` + * * The generated query key ensures: - * - **Type safety**: Prevents invalid API calls by enforcing a valid `service/resource/verb` combination. - * - **Auto-completion**: Provides intelligent suggestions based on predefined API structure. - * - **Cache management**: Enables precise cache invalidation and data synchronization. + * - **Type safety**: Prevents invalid API calls by enforcing a valid `service/resource/verb` combination + * - **Auto-completion**: Provides intelligent suggestions based on predefined API structure + * - **Cache management**: Enables precise cache invalidation and data synchronization */ export const useAPIQueryKey = , V extends Verb>( service: S, resource: R, verb: V, - queryKeyOptions?: Partial, + queryKeyOptions?: Partial, ): ComputedRef> => { - const queryKeyBase = useQueryKeyBase(queryKeyOptions); + const queryKeyContext = useQueryKeyContext({ ...queryKeyOptions, context: 'service' }); return computed(() => [ - ...queryKeyBase.value, - SERVICE_PREFIX, + queryKeyContext.value, service, resource, verb, diff --git a/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts b/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts index 1df9e803a7..48d77d4535 100644 --- a/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts +++ b/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts @@ -1,15 +1,17 @@ -import { SERVICE_PREFIX } from '@/api-clients/_common/constants/query-key-constant'; import { queryClient } from '@/query'; +import type { QueryContext } from '@/query/_types/query-key-type'; - - - -export const invalidateServiceQuery = (mode?: 'ADMIN' | 'WORKSPACE') => { - queryClient.invalidateQueries({ +/** + * Invalidates all service queries based on the specified mode. + * + * @param mode - Optional mode filter ('ADMIN' | 'WORKSPACE') + */ +export const invalidateServiceQuery = async (mode?: 'admin' | 'workspace') => { + await queryClient.invalidateQueries({ predicate: (query) => { - const [queryMode,,, queryType] = query.queryKey; - if (queryType !== SERVICE_PREFIX) return false; - if (mode && mode !== queryMode) return false; + const [queryContext] = query.queryKey as [QueryContext, ...unknown[]]; + if (!queryContext || queryContext.context !== 'service') return false; + if (mode && mode !== queryContext.mode) return false; return true; }, }); diff --git a/apps/web/src/api-clients/_common/types/query-key-type.ts b/apps/web/src/api-clients/_common/types/query-key-type.ts index 8d90137d90..2526380002 100644 --- a/apps/web/src/api-clients/_common/types/query-key-type.ts +++ b/apps/web/src/api-clients/_common/types/query-key-type.ts @@ -1,6 +1,5 @@ import type { API_DOC } from '@/api-clients/_common/constants/api-doc'; -import type { SERVICE_PREFIX } from '@/api-clients/_common/constants/query-key-constant'; -import type { QueryKeyBase } from '@/query/_types/query-key-type'; +import type { QueryContext } from '@/query/_types/query-key-type'; @@ -12,8 +11,7 @@ export type ResourceName = keyof (typeof API_DOC)[S]; export type Verb> = Extract<(typeof API_DOC)[S][R], string[]>[number] | string; export type ServiceQueryKey, V extends Verb> = [ - ...QueryKeyBase, - typeof SERVICE_PREFIX, + QueryContext, S, R, V, diff --git a/apps/web/src/query/_composables/use-query-key-base.ts b/apps/web/src/query/_composables/use-query-key-context.ts similarity index 56% rename from apps/web/src/query/_composables/use-query-key-base.ts rename to apps/web/src/query/_composables/use-query-key-context.ts index 56df222100..e9387f5db2 100644 --- a/apps/web/src/query/_composables/use-query-key-base.ts +++ b/apps/web/src/query/_composables/use-query-key-context.ts @@ -1,7 +1,7 @@ import type { ComputedRef } from 'vue'; import { computed, reactive } from 'vue'; -import type { QueryKeyBase } from '@/query/_types/query-key-type'; +import type { QueryContext } from '@/query/_types/query-key-type'; import { useAppContextStore } from '@/store/app-context/app-context-store'; import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store'; @@ -11,13 +11,10 @@ import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-worksp * Interface for global query parameters used across API requests. * These parameters are automatically included in API and reference query keys. */ -export interface QueryKeyBaseParams { - /** Flag indicating whether admin mode is enabled */ +export interface QueryKeyContextParams { isAdminMode?: boolean; - /** Current workspace ID from the workspace context */ workspaceId?: string; - /** Additional parameters that might be added */ - [key: string]: any; + context: 'service' | 'reference'; } /** @@ -26,24 +23,28 @@ export interface QueryKeyBaseParams { * that are commonly used across different API queries. * * @param queryKeyOptions - Optional query key options to merge with default params - * @returns A computed reference containing the combined global query parameters as an ordered array + * @returns A computed reference containing the combined global query parameters as a QueryContext object * * ### Example Usage: * ```ts - * const queryKeyBase = useQueryKeyBase(); - * // Access params (now returns array) - * const [mode, workspaceId, others] = queryKeyBase.value; + * const queryContext = useQueryKeyContext({ context: 'service' }); + * // Access params + * const { mode, workspaceId, context } = queryContext.value; * * // With additional params - * const params = useQueryKeyBase({ customParam: 'value' }); + * const params = useQueryKeyContext({ + * context: 'service', + * isAdminMode: true, + * workspaceId: 'custom-id' + * }); * ``` * * ### Features: - * - **Ordered Parameters**: Guarantees consistent parameter order: [mode, workspaceId, others] + * - **Structured Context**: Returns a QueryContext object with mode, workspaceId, and context * - **Reactive State**: Automatically updates when workspace or admin mode changes - * - **Parameter Merging**: Allows adding custom parameters in the others object + * - **Type Safety**: Ensures context is always provided with valid values */ -export const useQueryKeyBase = (queryKeyOptions?: Partial): ComputedRef => { +export const useQueryKeyContext = (queryKeyOptions: QueryKeyContextParams): ComputedRef => { const appContextStore = useAppContextStore(); const userWorkspaceStore = useUserWorkspaceStore(); @@ -52,15 +53,17 @@ export const useQueryKeyBase = (queryKeyOptions?: Partial): currentWorkspaceId: computed(() => userWorkspaceStore.getters.currentWorkspaceId), }); - return computed(() => { - const { isAdminMode, workspaceId: _workspaceId, ...otherParams } = queryKeyOptions || {}; - const mode = (isAdminMode || _state.isAdminMode) ? 'ADMIN' : 'WORKSPACE'; + return computed(() => { + const { + isAdminMode, workspaceId: _workspaceId, context, + } = queryKeyOptions || {}; + const mode = (isAdminMode || _state.isAdminMode) ? 'admin' : 'workspace'; const workspaceId = _workspaceId || _state.currentWorkspaceId; - return [ + return { mode, workspaceId, - Object.keys(otherParams).length > 0 ? otherParams : undefined, - ]; + context, + }; }); }; diff --git a/apps/web/src/query/_types/query-key-type.ts b/apps/web/src/query/_types/query-key-type.ts index 075e152cf9..fe4cd8b45c 100644 --- a/apps/web/src/query/_types/query-key-type.ts +++ b/apps/web/src/query/_types/query-key-type.ts @@ -1,9 +1,9 @@ -export type QueryKeyBase = [ - mode: 'ADMIN' | 'WORKSPACE', +export interface QueryContext { + mode: 'admin' | 'workspace', workspaceId: string | undefined, - others: Record | undefined, -]; + context: 'service' | 'reference', +} diff --git a/apps/web/src/query/reference/_composables/use-reference-query-key.ts b/apps/web/src/query/reference/_composables/use-reference-query-key.ts index 90632e001d..176b1772b7 100644 --- a/apps/web/src/query/reference/_composables/use-reference-query-key.ts +++ b/apps/web/src/query/reference/_composables/use-reference-query-key.ts @@ -1,9 +1,8 @@ import type { ComputedRef } from 'vue'; import { computed } from 'vue'; -import type { QueryKeyBaseParams } from '@/query/_composables/use-query-key-base'; -import { useQueryKeyBase } from '@/query/_composables/use-query-key-base'; -import { getReferencePrimaryQueryKey } from '@/query/reference/_helper/reference-query-key-helper'; +import type { QueryKeyContextParams } from '@/query/_composables/use-query-key-context'; +import { useQueryKeyContext } from '@/query/_composables/use-query-key-context'; import type { ReferenceQueryKey } from '@/query/reference/_types/reference-query-key-type'; import type { ReferenceResourceType } from '@/query/reference/_types/reference-resource-type'; @@ -16,7 +15,7 @@ import type { ReferenceResourceType } from '@/query/reference/_types/reference-r * * @param resourceType - The type of reference resource (e.g., 'public-dashboard', 'project') * @param queryKeyOptions - Optional query key options to merge with default params - * @returns A computed reference to the query key array, structured as `[REFERENCE_PREFIX, ...referencePrimaryKey, { globalParams }]` + * @returns A computed reference to the query key array, structured as `[QueryContext, resourceType]` * * ### Example Usage: * ```ts @@ -24,7 +23,10 @@ import type { ReferenceResourceType } from '@/query/reference/_types/reference-r * const referenceKey = useReferenceQueryKey('public-dashboard'); * * // With additional params - * const referenceKey = useReferenceQueryKey('public-dashboard', { workspaceId: 'custom-id' }); + * const referenceKey = useReferenceQueryKey('public-dashboard', { + * workspaceId: 'custom-id', + * context: 'reference' + * }); * ``` * * ### Features: @@ -34,12 +36,12 @@ import type { ReferenceResourceType } from '@/query/reference/_types/reference-r */ export const useReferenceQueryKey = ( resourceType: ReferenceResourceType, - queryKeyOptions?: Partial, + queryKeyOptions?: Partial, ): ComputedRef => { - const queryKeyBase = useQueryKeyBase(queryKeyOptions); + const queryKeyContext = useQueryKeyContext({ ...queryKeyOptions, context: 'reference' }); return computed(() => [ - ...queryKeyBase.value, - ...getReferencePrimaryQueryKey(resourceType), + queryKeyContext.value, + resourceType, ]); }; diff --git a/apps/web/src/query/reference/_constant/query-key-constant.ts b/apps/web/src/query/reference/_constant/query-key-constant.ts deleted file mode 100644 index 6b3d88f9b5..0000000000 --- a/apps/web/src/query/reference/_constant/query-key-constant.ts +++ /dev/null @@ -1 +0,0 @@ -export const REFERENCE_PREFIX = 'reference' as const; diff --git a/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts b/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts index c917625220..7b4898913a 100644 --- a/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts +++ b/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts @@ -1,13 +1,17 @@ import { queryClient } from '@/query'; -import { REFERENCE_PREFIX } from '@/query/reference/_constant/query-key-constant'; +import type { QueryContext } from '@/query/_types/query-key-type'; - -export const invalidateReferenceQuery = (mode?: 'ADMIN' | 'WORKSPACE') => { - queryClient.invalidateQueries({ +/** + * Invalidates all reference queries based on the specified mode. + * + * @param mode - Optional mode filter ('ADMIN' | 'WORKSPACE') + */ +export const invalidateReferenceQuery = async (mode?: 'admin' | 'workspace') => { + await queryClient.invalidateQueries({ predicate: (query) => { - const [queryMode,,, queryType] = query.queryKey; - if (queryType !== REFERENCE_PREFIX) return false; - if (mode && mode !== queryMode) return false; + const [queryContext] = query.queryKey as [QueryContext, ...unknown[]]; + if (!queryContext || queryContext.context !== 'reference') return false; + if (mode && mode !== queryContext.mode) return false; return true; }, }); diff --git a/apps/web/src/query/reference/_helper/reference-query-key-helper.ts b/apps/web/src/query/reference/_helper/reference-query-key-helper.ts deleted file mode 100644 index caca6958be..0000000000 --- a/apps/web/src/query/reference/_helper/reference-query-key-helper.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { REFERENCE_PREFIX } from '@/query/reference/_constant/query-key-constant'; -import type { ReferenceResourceType } from '@/query/reference/_types/reference-resource-type'; - -export const getReferencePrimaryQueryKey = (resourceType: ReferenceResourceType): [typeof REFERENCE_PREFIX, ReferenceResourceType] => [ - REFERENCE_PREFIX, - resourceType, -]; diff --git a/apps/web/src/query/reference/_types/reference-query-key-type.ts b/apps/web/src/query/reference/_types/reference-query-key-type.ts index 0c1cc2a21f..1b827fafae 100644 --- a/apps/web/src/query/reference/_types/reference-query-key-type.ts +++ b/apps/web/src/query/reference/_types/reference-query-key-type.ts @@ -1,16 +1,8 @@ -import type { QueryKeyBase } from '@/query/_types/query-key-type'; -import { REFERENCE_PREFIX } from '@/query/reference/_constant/query-key-constant'; +import type { QueryContext } from '@/query/_types/query-key-type'; import type { ReferenceResourceType } from '@/query/reference/_types/reference-resource-type'; export type ReferenceQueryKey = [ - ...QueryKeyBase, - typeof REFERENCE_PREFIX, + QueryContext, ReferenceResourceType ]; - -// 명시적인 반환 타입 정의 -export const getReferencePrimaryQueryKey = (resourceType: ReferenceResourceType): [typeof REFERENCE_PREFIX, ReferenceResourceType] => [ - REFERENCE_PREFIX, - resourceType, -]; From a52f2e2c3121f1ad78b13cd0d2d9f860d80fbc13 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Mon, 17 Mar 2025 09:33:20 +0900 Subject: [PATCH 07/20] fix(admin-toggle): apply global query invalidation helper Signed-off-by: samuel.park --- .../TopBarAdminToggleButton.vue | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue index 618365d53e..83f8bcc3be 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue @@ -2,10 +2,9 @@ import Vue, { computed, reactive } from 'vue'; import { useRouter } from 'vue-router/composables'; -import { useQueryClient } from '@tanstack/vue-query'; import { throttle } from 'lodash'; -import { SERVICE_PREFIX } from '@/api-clients/_common/constants/query-key-constant'; +import { invalidateServiceQuery } from '@/api-clients/_common/helpers/service-query-invalidation-helper'; import type { WorkspaceModel } from '@/api-clients/identity/workspace/schema/model'; import { i18n } from '@/translations'; @@ -18,11 +17,11 @@ import { getLastAccessedWorkspaceId } from '@/lib/site-initializer/last-accessed import { LANDING_ROUTE } from '@/services/landing/routes/route-constant'; + const appContextStore = useAppContextStore(); const userWorkspaceStore = useUserWorkspaceStore(); const workspaceStoreGetters = userWorkspaceStore.getters; const router = useRouter(); -const queryClient = useQueryClient(); const state = reactive({ isAdminMode: computed(() => appContextStore.getters.isAdminMode), @@ -37,7 +36,7 @@ const handleToggleAdminMode = throttle(async () => { return; } appContextStore.setGlobalGrantLoading(true); - await queryClient.invalidateQueries({ queryKey: [SERVICE_PREFIX] }); + await invalidateServiceQuery(state.isAdminMode ? 'admin' : 'workspace'); if (state.isAdminMode) { await userWorkspaceStore.load(); if (state.workspaceList.length === 0) { From 6c0690f4e1626016f5bdc0bb5f5f378fa03f2b48 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Tue, 18 Mar 2025 16:34:53 +0900 Subject: [PATCH 08/20] feat(api-keys): create api base query-key Signed-off-by: samuel.park --- .../api-clients/dashboard/private-dashboard/keys.ts | 8 ++++++++ .../api-clients/dashboard/private-data-table/keys.ts | 10 ++++++++++ .../src/api-clients/dashboard/private-folder/keys.ts | 8 ++++++++ .../src/api-clients/dashboard/private-widget/keys.ts | 12 ++++++++++++ .../api-clients/dashboard/public-dashboard/keys.ts | 8 ++++++++ .../api-clients/dashboard/public-data-table/keys.ts | 10 ++++++++++ .../src/api-clients/dashboard/public-folder/keys.ts | 8 ++++++++ .../src/api-clients/dashboard/public-widget/keys.ts | 12 ++++++++++++ 8 files changed, 76 insertions(+) create mode 100644 apps/web/src/api-clients/dashboard/private-dashboard/keys.ts create mode 100644 apps/web/src/api-clients/dashboard/private-data-table/keys.ts create mode 100644 apps/web/src/api-clients/dashboard/private-folder/keys.ts create mode 100644 apps/web/src/api-clients/dashboard/private-widget/keys.ts create mode 100644 apps/web/src/api-clients/dashboard/public-dashboard/keys.ts create mode 100644 apps/web/src/api-clients/dashboard/public-data-table/keys.ts create mode 100644 apps/web/src/api-clients/dashboard/public-folder/keys.ts create mode 100644 apps/web/src/api-clients/dashboard/public-widget/keys.ts diff --git a/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts b/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts new file mode 100644 index 0000000000..a0dd6f1b0e --- /dev/null +++ b/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts @@ -0,0 +1,8 @@ +import type { PrivateDashboardGetParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/get'; +import type { PrivateDashboardListParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/list'; + +export const privateDashboardKeys = { + all: ['private-dashboard'], + list: (params: PrivateDashboardListParameters) => [...privateDashboardKeys.all, 'list', params], + get: (idParam: PrivateDashboardGetParameters['dashboard_id']) => [...privateDashboardKeys.all, 'get', idParam], +}; diff --git a/apps/web/src/api-clients/dashboard/private-data-table/keys.ts b/apps/web/src/api-clients/dashboard/private-data-table/keys.ts new file mode 100644 index 0000000000..f6e8fe61ce --- /dev/null +++ b/apps/web/src/api-clients/dashboard/private-data-table/keys.ts @@ -0,0 +1,10 @@ +import type { DataTableGetParameters } from '@/api-clients/dashboard/private-data-table/schema/api-verbs/get'; +import type { DataTableListParameters } from '@/api-clients/dashboard/private-data-table/schema/api-verbs/list'; +import type { DataTableLoadParameters } from '@/api-clients/dashboard/private-data-table/schema/api-verbs/load'; + +export const privateDataTableKeys = { + all: ['private-data-table'], + list: (params: DataTableListParameters) => [...privateDataTableKeys.all, 'list', params], + get: (idParam: DataTableGetParameters['data_table_id']) => [...privateDataTableKeys.all, 'get', idParam], + load: (idParam: DataTableLoadParameters['data_table_id']) => [...privateDataTableKeys.all, 'load', idParam], +}; diff --git a/apps/web/src/api-clients/dashboard/private-folder/keys.ts b/apps/web/src/api-clients/dashboard/private-folder/keys.ts new file mode 100644 index 0000000000..a3a8d8948a --- /dev/null +++ b/apps/web/src/api-clients/dashboard/private-folder/keys.ts @@ -0,0 +1,8 @@ +import type { PrivateFolderGetParameters } from '@/api-clients/dashboard/private-folder/schema/api-verbs/get'; +import type { PrivateFolderListParameters } from '@/api-clients/dashboard/private-folder/schema/api-verbs/list'; + +export const privateFolderKeys = { + all: ['private-folder'], + list: (params: PrivateFolderListParameters) => [...privateFolderKeys.all, 'list', params], + get: (idParam: PrivateFolderGetParameters['folder_id']) => [...privateFolderKeys.all, 'get', idParam], +}; diff --git a/apps/web/src/api-clients/dashboard/private-widget/keys.ts b/apps/web/src/api-clients/dashboard/private-widget/keys.ts new file mode 100644 index 0000000000..3741ad3c8a --- /dev/null +++ b/apps/web/src/api-clients/dashboard/private-widget/keys.ts @@ -0,0 +1,12 @@ +import type { PrivateWidgetGetParameters } from '@/api-clients/dashboard/private-widget/schema/api-verbs/get'; +import type { PrivateWidgetListParameters } from '@/api-clients/dashboard/private-widget/schema/api-verbs/list'; +import type { PrivateWidgetLoadParameters } from '@/api-clients/dashboard/private-widget/schema/api-verbs/load'; +import type { PrivateWidgetLoadSumParameters } from '@/api-clients/dashboard/private-widget/schema/api-verbs/load-sum'; + +export const privateWidgetKeys = { + all: ['private-widget'], + list: (params: PrivateWidgetListParameters) => [...privateWidgetKeys.all, 'list', params], + get: (idParam: PrivateWidgetGetParameters['widget_id']) => [...privateWidgetKeys.all, 'get', idParam], + load: (idParam: PrivateWidgetLoadParameters['widget_id']) => [...privateWidgetKeys.all, 'load', idParam], + loadSum: (idParam: PrivateWidgetLoadSumParameters['widget_id']) => [...privateWidgetKeys.all, 'load-sum', idParam], +}; diff --git a/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts b/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts new file mode 100644 index 0000000000..6b20473141 --- /dev/null +++ b/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts @@ -0,0 +1,8 @@ +import type { PublicDashboardGetParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/get'; +import type { PublicDashboardListParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/list'; + +export const publicDashboardKeys = { + all: ['public-dashboard'], + list: (params: PublicDashboardListParameters) => [...publicDashboardKeys.all, 'list', params], + get: (idParam: PublicDashboardGetParameters['dashboard_id']) => [...publicDashboardKeys.all, 'get', idParam], +}; diff --git a/apps/web/src/api-clients/dashboard/public-data-table/keys.ts b/apps/web/src/api-clients/dashboard/public-data-table/keys.ts new file mode 100644 index 0000000000..6ea189969e --- /dev/null +++ b/apps/web/src/api-clients/dashboard/public-data-table/keys.ts @@ -0,0 +1,10 @@ +import type { DataTableGetParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/get'; +import type { DataTableListParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/list'; +import type { DataTableLoadParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/load'; + +export const publicDataTableKeys = { + all: ['public-data-table'], + list: (params: DataTableListParameters) => [...publicDataTableKeys.all, 'list', params], + get: (idParam: DataTableGetParameters['data_table_id']) => [...publicDataTableKeys.all, 'get', idParam], + load: (idParam: DataTableLoadParameters['data_table_id']) => [...publicDataTableKeys.all, 'load', idParam], +}; diff --git a/apps/web/src/api-clients/dashboard/public-folder/keys.ts b/apps/web/src/api-clients/dashboard/public-folder/keys.ts new file mode 100644 index 0000000000..7f9329b70f --- /dev/null +++ b/apps/web/src/api-clients/dashboard/public-folder/keys.ts @@ -0,0 +1,8 @@ +import type { PublicFolderGetParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/get'; +import type { PublicFolderListParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/list'; + +export const publicFolderKeys = { + all: ['public-folder'], + list: (params: PublicFolderListParameters) => [...publicFolderKeys.all, 'list', params], + get: (idParam: PublicFolderGetParameters['folder_id']) => [...publicFolderKeys.all, 'get', idParam], +}; diff --git a/apps/web/src/api-clients/dashboard/public-widget/keys.ts b/apps/web/src/api-clients/dashboard/public-widget/keys.ts new file mode 100644 index 0000000000..78e0e6c2f5 --- /dev/null +++ b/apps/web/src/api-clients/dashboard/public-widget/keys.ts @@ -0,0 +1,12 @@ +import type { PublicWidgetGetParameters } from '@/api-clients/dashboard/public-widget/schema/api-verbs/get'; +import type { PublicWidgetListParameters } from '@/api-clients/dashboard/public-widget/schema/api-verbs/list'; +import type { PublicWidgetLoadParameters } from '@/api-clients/dashboard/public-widget/schema/api-verbs/load'; +import type { PublicWidgetLoadSumParameters } from '@/api-clients/dashboard/public-widget/schema/api-verbs/load-sum'; + +export const publicWidgetKeys = { + all: ['public-widget'], + list: (params: PublicWidgetListParameters) => [...publicWidgetKeys.all, 'list', params], + get: (idParam: PublicWidgetGetParameters['widget_id']) => [...publicWidgetKeys.all, 'get', idParam], + load: (idParam: PublicWidgetLoadParameters['widget_id']) => [...publicWidgetKeys.all, 'load', idParam], + loadSum: (idParam: PublicWidgetLoadSumParameters['widget_id']) => [...publicWidgetKeys.all, 'load-sum', idParam], +}; From 7e5a6091e18af6e156d1bcc02ecd1f4e0413c434 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Tue, 18 Mar 2025 16:40:06 +0900 Subject: [PATCH 09/20] feat(query-key): create new api query-key generator with factory pattern Signed-off-by: samuel.park --- .../_common/composables/use-api-query-key.ts | 149 +++++++++++++----- .../_common/constants/api-query-key-map.ts | 34 ++++ .../_common/types/query-key-type.ts | 9 +- ...ontext.ts => use-query-key-app-context.ts} | 51 +++++- .../_composables/use-reference-query-key.ts | 4 +- 5 files changed, 199 insertions(+), 48 deletions(-) create mode 100644 apps/web/src/api-clients/_common/constants/api-query-key-map.ts rename apps/web/src/query/_composables/{use-query-key-context.ts => use-query-key-app-context.ts} (65%) diff --git a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts index fcad7252f9..143fd1a807 100644 --- a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts +++ b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts @@ -1,51 +1,118 @@ import type { ComputedRef } from 'vue'; -import { computed } from 'vue'; +import { reactive, computed } from 'vue'; +import type { QueryKey } from '@tanstack/vue-query'; + +import { API_QUERY_KEY_MAP } from '@/api-clients/_common/constants/api-query-key-map'; import type { - ResourceName, ServiceName, ServiceQueryKey, Verb, + APIQueryKeyMapService, APIQueryKeyMapResource, APIQueryKeyMapVerb, ServiceName, ResourceName, Verb, } from '@/api-clients/_common/types/query-key-type'; -import type { QueryKeyContextParams } from '@/query/_composables/use-query-key-context'; -import { useQueryKeyContext } from '@/query/_composables/use-query-key-context'; - -/** - * Generates a computed query key for API requests, incorporating global parameters. - * - * @param service - The service name, representing the API service scope (e.g., 'dashboard'). - * @param resource - The resource name, specifying the target API resource (e.g., 'public-data-table'). - * @param verb - The API action verb, defining the type of request (e.g., 'get', 'list', 'update'). - * @param queryKeyOptions - Optional query key options to merge with default params - * @returns A computed reference to the query key array, structured as `[QueryContext, service, resource, verb]` - * - * ### Example Usage: - * ```ts - * // Basic usage - * const queryKey = useAPIQueryKey('dashboard', 'public-data-table', 'get'); - * - * // With additional params - * const queryKey = useAPIQueryKey('dashboard', 'public-data-table', 'get', { - * workspaceId: 'custom-id', - * isAdminMode: true - * }); - * ``` - * - * The generated query key ensures: - * - **Type safety**: Prevents invalid API calls by enforcing a valid `service/resource/verb` combination - * - **Auto-completion**: Provides intelligent suggestions based on predefined API structure - * - **Cache management**: Enables precise cache invalidation and data synchronization - */ +import { useQueryKeyAppContext } from '@/query/_composables/use-query-key-app-context'; + +import { useAppContextStore } from '@/store/app-context/app-context-store'; +import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store'; + + +type QueryKeyArray = unknown[]; +type QueryKeyArrayWithDep = QueryKeyArray & { + addDep: (deps: Record) => QueryKeyArray; +}; +type ExtractParams = T extends (params: infer P) => any ? P : never; + +type VerbFunction = { + (params?: ExtractParams): QueryKeyArrayWithDep; + addDep: (deps: Record) => QueryKeyArray; +}; + +type MapVerbToReturnType = T extends QueryKeyArray + ? QueryKeyArray + : T extends (params: any) => any + ? VerbFunction + : never; + +type UseAPIQueryResult = { + [S in APIQueryKeyMapService]: { + [R in APIQueryKeyMapResource]: { + [V in APIQueryKeyMapVerb]: MapVerbToReturnType<(typeof API_QUERY_KEY_MAP)[S][R][V]>; + }; + }; +}; + +type APIQueryKeyValue = QueryKeyArray | ((params?: Record) => QueryKeyArray); + +export const _useAPIQueryKey = (): ComputedRef => { + const queryKeyAppContext = useQueryKeyAppContext(); + + return computed(() => { + const createKeyWithContext = (queryKeyValue: T): MapVerbToReturnType => { + if (Array.isArray(queryKeyValue)) { + return [...queryKeyAppContext.value, ...queryKeyValue] as MapVerbToReturnType; + } + + const verbFunction = (params?: ExtractParams) => { + const baseKey = queryKeyValue(params); + const result = [...queryKeyAppContext.value, ...baseKey] as QueryKeyArrayWithDep; + result.addDep = (deps) => [...queryKeyAppContext.value, ...baseKey, deps]; + return result; + }; + + verbFunction.addDep = (deps) => [...queryKeyAppContext.value, ...queryKeyValue(), deps]; + return verbFunction as MapVerbToReturnType; + }; + + return Object.entries(API_QUERY_KEY_MAP).reduce((services, [serviceName, resources]) => ({ + ...services, + [serviceName]: Object.entries(resources).reduce((resourceMap, [resourceName, verbs]) => ({ + ...resourceMap, + [resourceName]: Object.entries(verbs).reduce((verbMap, [verb, queryKeyValue]) => ({ + ...verbMap, + [verb]: createKeyWithContext(queryKeyValue as APIQueryKeyValue), + }), {}), + }), {}), + }), {} as UseAPIQueryResult); + }); +}; + + + + + + + + + + + + + + + + + +interface GlobalQueryParams { + workspaceId?: string; + isAdminMode?: boolean; +} export const useAPIQueryKey = , V extends Verb>( service: S, resource: R, verb: V, - queryKeyOptions?: Partial, -): ComputedRef> => { - const queryKeyContext = useQueryKeyContext({ ...queryKeyOptions, context: 'service' }); - - return computed(() => [ - queryKeyContext.value, - service, - resource, - verb, - ]); + additionalGlobalParams?: Partial, +): ComputedRef => { + const appContextStore = useAppContextStore(); + const userWorkspaceStore = useUserWorkspaceStore(); + + const _state = reactive({ + currentWorkdpaceId: computed(() => userWorkspaceStore.getters.currentWorkspaceId), + isAdminMode: computed(() => appContextStore.getters.isAdminMode), + }); + + const globalQueryParams = reactive({ + workspaceId: _state.currentWorkdpaceId, + isAdminMode: _state.isAdminMode, + ...additionalGlobalParams, + }); + + return computed(() => [service, resource, verb, { ...globalQueryParams }]); }; diff --git a/apps/web/src/api-clients/_common/constants/api-query-key-map.ts b/apps/web/src/api-clients/_common/constants/api-query-key-map.ts new file mode 100644 index 0000000000..b7ff3c05a9 --- /dev/null +++ b/apps/web/src/api-clients/_common/constants/api-query-key-map.ts @@ -0,0 +1,34 @@ +import { privateDashboardKeys } from '@/api-clients/dashboard/private-dashboard/keys'; +import { privateDataTableKeys } from '@/api-clients/dashboard/private-data-table/keys'; +import { privateFolderKeys } from '@/api-clients/dashboard/private-folder/keys'; +import { privateWidgetKeys } from '@/api-clients/dashboard/private-widget/keys'; +import { publicDashboardKeys } from '@/api-clients/dashboard/public-dashboard/keys'; +import { publicDataTableKeys } from '@/api-clients/dashboard/public-data-table/keys'; +import { publicFolderKeys } from '@/api-clients/dashboard/public-folder/keys'; +import { publicWidgetKeys } from '@/api-clients/dashboard/public-widget/keys'; +import { commentKeys } from '@/api-clients/opsflow/comment/keys'; +import { eventKeys } from '@/api-clients/opsflow/event/keys'; +import { taskCategoryKeys } from '@/api-clients/opsflow/task-category/keys'; +import { taskTypeKeys } from '@/api-clients/opsflow/task-type/keys'; +import { taskKeys } from '@/api-clients/opsflow/task/keys'; + +export const API_QUERY_KEY_MAP = { + dashboard: { + publicFolder: publicFolderKeys, + publicDashboard: publicDashboardKeys, + publicDataTable: publicDataTableKeys, + publicWidget: publicWidgetKeys, + privateFolder: privateFolderKeys, + privateDashboard: privateDashboardKeys, + privateDataTable: privateDataTableKeys, + privateWidget: privateWidgetKeys, + }, + opsflow: { + comment: commentKeys, + task: taskKeys, + taskCategory: taskCategoryKeys, + taskType: taskTypeKeys, + event: eventKeys, + }, +} as const; + diff --git a/apps/web/src/api-clients/_common/types/query-key-type.ts b/apps/web/src/api-clients/_common/types/query-key-type.ts index 2526380002..c1abcbb528 100644 --- a/apps/web/src/api-clients/_common/types/query-key-type.ts +++ b/apps/web/src/api-clients/_common/types/query-key-type.ts @@ -1,5 +1,7 @@ import type { API_DOC } from '@/api-clients/_common/constants/api-doc'; -import type { QueryContext } from '@/query/_types/query-key-type'; +// import type { QueryContext } from '@/query/_types/query-key-type'; + +import type { API_QUERY_KEY_MAP } from '../constants/api-query-key-map'; @@ -11,8 +13,11 @@ export type ResourceName = keyof (typeof API_DOC)[S]; export type Verb> = Extract<(typeof API_DOC)[S][R], string[]>[number] | string; export type ServiceQueryKey, V extends Verb> = [ - QueryContext, S, R, V, ]; + +export type APIQueryKeyMapService = keyof typeof API_QUERY_KEY_MAP; +export type APIQueryKeyMapResource = keyof (typeof API_QUERY_KEY_MAP)[S]; +export type APIQueryKeyMapVerb> = keyof (typeof API_QUERY_KEY_MAP)[S][R]; diff --git a/apps/web/src/query/_composables/use-query-key-context.ts b/apps/web/src/query/_composables/use-query-key-app-context.ts similarity index 65% rename from apps/web/src/query/_composables/use-query-key-context.ts rename to apps/web/src/query/_composables/use-query-key-app-context.ts index e9387f5db2..2e0f1b8d32 100644 --- a/apps/web/src/query/_composables/use-query-key-context.ts +++ b/apps/web/src/query/_composables/use-query-key-app-context.ts @@ -1,8 +1,6 @@ import type { ComputedRef } from 'vue'; import { computed, reactive } from 'vue'; -import type { QueryContext } from '@/query/_types/query-key-type'; - import { useAppContextStore } from '@/store/app-context/app-context-store'; import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store'; @@ -11,10 +9,18 @@ import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-worksp * Interface for global query parameters used across API requests. * These parameters are automatically included in API and reference query keys. */ +export type QueryContextType = 'service' | 'reference'; + export interface QueryKeyContextParams { isAdminMode?: boolean; workspaceId?: string; - context: 'service' | 'reference'; + context: QueryContextType; +} + +export interface QueryContext { + mode: 'admin' | 'workspace'; + workspaceId?: string; + context: QueryContextType; } /** @@ -67,3 +73,42 @@ export const useQueryKeyContext = (queryKeyOptions: QueryKeyContextParams): Comp }; }); }; + + +interface AdminModeState { + isAdminMode: true; + workspaceId?: undefined; +} + +interface WorkspaceModeState { + isAdminMode: false; + workspaceId: string; +} + +type QueryKeyState = AdminModeState | WorkspaceModeState; + + +export const useQueryKeyAppContext = (context: QueryContextType = 'service') => { + const appContextStore = useAppContextStore(); + const userWorkspaceStore = useUserWorkspaceStore(); + + const _state = reactive({ + isAdminMode: computed(() => appContextStore.getters.isAdminMode), + workspaceId: computed(() => userWorkspaceStore.getters.currentWorkspaceId), + }); + + return computed(() => { + const state: QueryKeyState = _state.isAdminMode + ? { isAdminMode: true } + : { + isAdminMode: false, + // workspaceId: _state.workspaceId! + workspaceId: _state.workspaceId ?? '', + }; + + return state.isAdminMode + ? [context, 'admin'] + : [context, 'workspace', state.workspaceId]; + }); +}; + diff --git a/apps/web/src/query/reference/_composables/use-reference-query-key.ts b/apps/web/src/query/reference/_composables/use-reference-query-key.ts index 176b1772b7..17b06f2627 100644 --- a/apps/web/src/query/reference/_composables/use-reference-query-key.ts +++ b/apps/web/src/query/reference/_composables/use-reference-query-key.ts @@ -1,8 +1,8 @@ import type { ComputedRef } from 'vue'; import { computed } from 'vue'; -import type { QueryKeyContextParams } from '@/query/_composables/use-query-key-context'; -import { useQueryKeyContext } from '@/query/_composables/use-query-key-context'; +import type { QueryKeyContextParams } from '@/query/_composables/use-query-key-app-context'; +import { useQueryKeyContext } from '@/query/_composables/use-query-key-app-context'; import type { ReferenceQueryKey } from '@/query/reference/_types/reference-query-key-type'; import type { ReferenceResourceType } from '@/query/reference/_types/reference-resource-type'; From 87af86315e16dd9dc277e5e0f48804599150bf04 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Tue, 18 Mar 2025 16:40:51 +0900 Subject: [PATCH 10/20] feat(ops-flow): create base query-key Signed-off-by: samuel.park --- apps/web/src/api-clients/opsflow/comment/keys.ts | 9 +++++++++ apps/web/src/api-clients/opsflow/event/keys.ts | 7 +++++++ apps/web/src/api-clients/opsflow/task-category/keys.ts | 9 +++++++++ apps/web/src/api-clients/opsflow/task-type/keys.ts | 9 +++++++++ apps/web/src/api-clients/opsflow/task/keys.ts | 9 +++++++++ 5 files changed, 43 insertions(+) create mode 100644 apps/web/src/api-clients/opsflow/comment/keys.ts create mode 100644 apps/web/src/api-clients/opsflow/event/keys.ts create mode 100644 apps/web/src/api-clients/opsflow/task-category/keys.ts create mode 100644 apps/web/src/api-clients/opsflow/task-type/keys.ts create mode 100644 apps/web/src/api-clients/opsflow/task/keys.ts diff --git a/apps/web/src/api-clients/opsflow/comment/keys.ts b/apps/web/src/api-clients/opsflow/comment/keys.ts new file mode 100644 index 0000000000..1125f24314 --- /dev/null +++ b/apps/web/src/api-clients/opsflow/comment/keys.ts @@ -0,0 +1,9 @@ +import type { CommentGetParameters } from '@/api-clients/opsflow/comment/schema/api-verbs/get'; +import type { CommentListParameters } from '@/api-clients/opsflow/comment/schema/api-verbs/list'; + +export const commentKeys = { + all: ['comment'], + list: (params: CommentListParameters) => [...commentKeys.all, 'list', params], + get: (idParam: CommentGetParameters['comment_id']) => [...commentKeys.all, 'get', idParam], +}; + diff --git a/apps/web/src/api-clients/opsflow/event/keys.ts b/apps/web/src/api-clients/opsflow/event/keys.ts new file mode 100644 index 0000000000..2d03f6f12c --- /dev/null +++ b/apps/web/src/api-clients/opsflow/event/keys.ts @@ -0,0 +1,7 @@ +import type { EventListParameters } from '@/api-clients/opsflow/event/schema/api-verbs/list'; + +export const eventKeys = { + all: ['event'], + list: (params: EventListParameters) => [...eventKeys.all, 'list', params], +}; + diff --git a/apps/web/src/api-clients/opsflow/task-category/keys.ts b/apps/web/src/api-clients/opsflow/task-category/keys.ts new file mode 100644 index 0000000000..4686dab116 --- /dev/null +++ b/apps/web/src/api-clients/opsflow/task-category/keys.ts @@ -0,0 +1,9 @@ +import type { TaskCategoryGetParameters } from '@/api-clients/opsflow/task-category/schema/api-verbs/get'; +import type { TaskCategoryListParameters } from '@/api-clients/opsflow/task-category/schema/api-verbs/list'; + +export const taskCategoryKeys = { + all: ['task-category'], + list: (params: TaskCategoryListParameters) => [...taskCategoryKeys.all, 'list', params], + get: (idParam: TaskCategoryGetParameters['category_id']) => [...taskCategoryKeys.all, 'get', idParam], +}; + diff --git a/apps/web/src/api-clients/opsflow/task-type/keys.ts b/apps/web/src/api-clients/opsflow/task-type/keys.ts new file mode 100644 index 0000000000..1c970cc2d4 --- /dev/null +++ b/apps/web/src/api-clients/opsflow/task-type/keys.ts @@ -0,0 +1,9 @@ +import type { TaskTypeGetParameters } from '@/api-clients/opsflow/task-type/schema/api-verbs/get'; +import type { TaskTypeListParameters } from '@/api-clients/opsflow/task-type/schema/api-verbs/list'; + +export const taskTypeKeys = { + all: ['task-type'], + list: (params: TaskTypeListParameters) => [...taskTypeKeys.all, 'list', params], + get: (idParam: TaskTypeGetParameters['task_type_id']) => [...taskTypeKeys.all, 'get', idParam], +}; + diff --git a/apps/web/src/api-clients/opsflow/task/keys.ts b/apps/web/src/api-clients/opsflow/task/keys.ts new file mode 100644 index 0000000000..dec8dcea27 --- /dev/null +++ b/apps/web/src/api-clients/opsflow/task/keys.ts @@ -0,0 +1,9 @@ +import type { TaskGetParameters } from '@/api-clients/opsflow/task/schema/api-verbs/get'; +import type { TaskListParameters } from '@/api-clients/opsflow/task/schema/api-verbs/list'; + +export const taskKeys = { + all: ['task'], + list: (params: TaskListParameters) => [...taskKeys.all, 'list', params], + get: (idParam: TaskGetParameters['task_id']) => [...taskKeys.all, 'get', idParam], +}; + From f68d0ec8ba5fc509e88fac62f5d9158b960328a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9A=A9=ED=83=9C?= Date: Tue, 18 Mar 2025 22:36:37 +0900 Subject: [PATCH 11/20] refactor(query-composable): improve query composable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 박용태 --- .../_common/composables/use-api-query-key.ts | 4 ++-- .../_common/composables/use-scoped-query.ts | 22 ++++++++----------- apps/web/src/query/_types/query-key-type.ts | 1 + 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts index 143fd1a807..6f16ac4556 100644 --- a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts +++ b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts @@ -8,12 +8,12 @@ import type { APIQueryKeyMapService, APIQueryKeyMapResource, APIQueryKeyMapVerb, ServiceName, ResourceName, Verb, } from '@/api-clients/_common/types/query-key-type'; import { useQueryKeyAppContext } from '@/query/_composables/use-query-key-app-context'; +import type { QueryKeyArray } from '@/query/_types/query-key-type'; import { useAppContextStore } from '@/store/app-context/app-context-store'; import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-workspace-store'; -type QueryKeyArray = unknown[]; type QueryKeyArrayWithDep = QueryKeyArray & { addDep: (deps: Record) => QueryKeyArray; }; @@ -41,7 +41,7 @@ type UseAPIQueryResult = { type APIQueryKeyValue = QueryKeyArray | ((params?: Record) => QueryKeyArray); export const _useAPIQueryKey = (): ComputedRef => { - const queryKeyAppContext = useQueryKeyAppContext(); + const queryKeyAppContext = useQueryKeyAppContext('service'); return computed(() => { const createKeyWithContext = (queryKeyValue: T): MapVerbToReturnType => { diff --git a/apps/web/src/api-clients/_common/composables/use-scoped-query.ts b/apps/web/src/api-clients/_common/composables/use-scoped-query.ts index 0077392792..1b114ee946 100644 --- a/apps/web/src/api-clients/_common/composables/use-scoped-query.ts +++ b/apps/web/src/api-clients/_common/composables/use-scoped-query.ts @@ -1,5 +1,3 @@ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-nocheck /** * useScopedQuery - A custom wrapper around `useQuery` to enforce scope-based API fetching. * @@ -10,8 +8,8 @@ * * ## Functionality * - Extends `useQuery` with **grant scope validation**. - * - Runs queries only when **the user’s scope is valid** and the app is **ready**. - * - Uses Vue’s **reactivity** to dynamically compute the `enabled` state. + * - Runs queries only when **the user's scope is valid** and the app is **ready**. + * - Uses Vue's **reactivity** to dynamically compute the `enabled` state. * - Supports both **static and reactive `enabled` values**. * * ## Parameters: @@ -43,7 +41,7 @@ import type { MaybeRef } from '@vueuse/core'; import { toValue } from '@vueuse/core'; -import { computed, reactive } from 'vue'; +import { computed } from 'vue'; import type { UseQueryOptions, @@ -57,21 +55,19 @@ import { useUserStore } from '@/store/user/user-store'; export const useScopedQuery = ( options: UseQueryOptions, - requiredScopes: GrantScope[] = [], + requiredScopes: GrantScope[], ) => { const appContextStore = useAppContextStore(); const userStore = useUserStore(); - const _state = reactive({ - currentGrantScope: computed(() => userStore.state.currentGrantInfo?.scope || 'USER'), - isLoading: computed(() => appContextStore.getters.globalGrantLoading), - isValidScope: computed(() => requiredScopes.includes(_state.currentGrantScope)), - }); + const currentGrantScope = computed(() => userStore.state.currentGrantInfo?.scope || 'USER'); + const isLoading = computed(() => appContextStore.getters.globalGrantLoading); + const isValidScope = computed(() => requiredScopes.includes(currentGrantScope.value)); const queryEnabled = computed(() => { - const _inheritedEnabled = options?.enabled as MaybeRef | undefined; + const _inheritedEnabled = ('enabled' in options ? options.enabled : undefined) as MaybeRef | undefined; if (_inheritedEnabled !== undefined && !toValue(_inheritedEnabled)) return false; - return _state.isValidScope && !_state.isLoading; + return isValidScope.value && !isLoading.value; }); return useQuery({ diff --git a/apps/web/src/query/_types/query-key-type.ts b/apps/web/src/query/_types/query-key-type.ts index fe4cd8b45c..9f3caa44d1 100644 --- a/apps/web/src/query/_types/query-key-type.ts +++ b/apps/web/src/query/_types/query-key-type.ts @@ -6,4 +6,5 @@ export interface QueryContext { } +export type QueryKeyArray = unknown[]; From 87f275c660192987bd80b02c725882b76e22d02f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9A=A9=ED=83=9C?= Date: Tue, 18 Mar 2025 22:37:21 +0900 Subject: [PATCH 12/20] feat(reference-query): create reference query key composable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 박용태 --- .../_composables/use-reference-query-key.ts | 49 ++++--------------- .../_constants/reference-type-map.ts | 28 +++++++++++ .../_types/reference-resource-type.ts | 31 ++---------- 3 files changed, 42 insertions(+), 66 deletions(-) create mode 100644 apps/web/src/query/reference/_constants/reference-type-map.ts diff --git a/apps/web/src/query/reference/_composables/use-reference-query-key.ts b/apps/web/src/query/reference/_composables/use-reference-query-key.ts index 17b06f2627..a206412825 100644 --- a/apps/web/src/query/reference/_composables/use-reference-query-key.ts +++ b/apps/web/src/query/reference/_composables/use-reference-query-key.ts @@ -1,47 +1,18 @@ import type { ComputedRef } from 'vue'; import { computed } from 'vue'; -import type { QueryKeyContextParams } from '@/query/_composables/use-query-key-app-context'; -import { useQueryKeyContext } from '@/query/_composables/use-query-key-app-context'; -import type { ReferenceQueryKey } from '@/query/reference/_types/reference-query-key-type'; -import type { ReferenceResourceType } from '@/query/reference/_types/reference-resource-type'; +import { useQueryKeyAppContext } from '@/query/_composables/use-query-key-app-context'; +import type { QueryKeyArray } from '@/query/_types/query-key-type'; +import { REFERENCE_TYPE_MAP } from '@/query/reference/_constants/reference-type-map'; +type UseReferenceQueryKeyResult = Record; -/** - * Composable that generates a reference query key with global parameters. - * This hook creates a query key specifically for reference data, which is structured differently - * from regular API query keys but still includes global parameters. - * - * @param resourceType - The type of reference resource (e.g., 'public-dashboard', 'project') - * @param queryKeyOptions - Optional query key options to merge with default params - * @returns A computed reference to the query key array, structured as `[QueryContext, resourceType]` - * - * ### Example Usage: - * ```ts - * // Basic usage - * const referenceKey = useReferenceQueryKey('public-dashboard'); - * - * // With additional params - * const referenceKey = useReferenceQueryKey('public-dashboard', { - * workspaceId: 'custom-id', - * context: 'reference' - * }); - * ``` - * - * ### Features: - * - **Reference Key Structure**: Creates a specialized key structure for reference data - * - **Global Parameter Integration**: Automatically includes workspace and admin mode parameters - * - **Type Safety**: Ensures valid reference resource types through TypeScript - */ -export const useReferenceQueryKey = ( - resourceType: ReferenceResourceType, - queryKeyOptions?: Partial, -): ComputedRef => { - const queryKeyContext = useQueryKeyContext({ ...queryKeyOptions, context: 'reference' }); +export const useReferenceQueryKey = (): ComputedRef => { + const queryKeyAppContext = useQueryKeyAppContext('reference'); - return computed(() => [ - queryKeyContext.value, - resourceType, - ]); + return computed(() => Object.entries(REFERENCE_TYPE_MAP).reduce((acc, [key, value]) => ({ + ...acc, + [key]: [queryKeyAppContext.value, value], + }), {} as UseReferenceQueryKeyResult)); }; diff --git a/apps/web/src/query/reference/_constants/reference-type-map.ts b/apps/web/src/query/reference/_constants/reference-type-map.ts new file mode 100644 index 0000000000..8f962f2acf --- /dev/null +++ b/apps/web/src/query/reference/_constants/reference-type-map.ts @@ -0,0 +1,28 @@ +export const REFERENCE_TYPE_MAP = { + app: 'app', + cloudServiceType: 'cloud_service_type', + cloudServiceQuerySet: 'cloud_service_query_set', + collector: 'collector', + costDataSource: 'cost_data_source', + escalationPolicy: 'escalation_policy', + metric: 'metric', + namespace: 'namespace', + plugin: 'plugin', + projectGroup: 'project_group', + project: 'project', + protocol: 'protocol', + provider: 'provider', + publicDashboard: 'public_dashboard', + publicFolder: 'public_folder', + region: 'region', + role: 'role', + secret: 'secret', + serviceAccount: 'service_account', + service: 'service', + trustedServiceAccount: 'trusted_service_account', + userGroup: 'user_group', + user: 'user', + webhook: 'webhook', + workspaceGroup: 'workspace_group', + workspace: 'workspace', +} as const; diff --git a/apps/web/src/query/reference/_types/reference-resource-type.ts b/apps/web/src/query/reference/_types/reference-resource-type.ts index 4f47b86356..7c0682df92 100644 --- a/apps/web/src/query/reference/_types/reference-resource-type.ts +++ b/apps/web/src/query/reference/_types/reference-resource-type.ts @@ -1,27 +1,4 @@ -export type ReferenceResourceType = - 'app' - |'cloud-service-type' - |'cloud-service-query-set' - |'collector' - |'cost-data-source' - |'escalation-policy' - |'metric' - |'namespace' - |'plugin' - |'project-group' - |'project' - |'protocol' - |'provider' - |'public-dashboard' - |'public-folder' - |'region' - |'role' - |'secret' - |'service-account' - |'service' - |'trusted-service-account' - |'user-group' - |'user' - |'webhook' - |'workspace-group' - |'workspace'; +import type { REFERENCE_TYPE_MAP } from '@/query/reference/_constants/reference-type-map'; + + +export type ReferenceResourceType = typeof REFERENCE_TYPE_MAP[keyof typeof REFERENCE_TYPE_MAP]; From 98500e139b45d8ac04161f1ed8064460b599d9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9A=A9=ED=83=9C?= Date: Tue, 18 Mar 2025 22:38:11 +0900 Subject: [PATCH 13/20] feat(reference-query): create reference query composable --- .../query/_composables/use-reference-query.ts | 38 ++++++++++++ .../reference/_types/reference-query-type.ts | 21 +++++++ .../reference/use-all-reference-query.ts | 48 +++++++++++++++ .../use-public-dashboard-reference-query.ts | 58 +++++++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 apps/web/src/query/_composables/use-reference-query.ts create mode 100644 apps/web/src/query/reference/_types/reference-query-type.ts create mode 100644 apps/web/src/query/reference/use-all-reference-query.ts create mode 100644 apps/web/src/query/reference/use-public-dashboard-reference-query.ts diff --git a/apps/web/src/query/_composables/use-reference-query.ts b/apps/web/src/query/_composables/use-reference-query.ts new file mode 100644 index 0000000000..50434de6f4 --- /dev/null +++ b/apps/web/src/query/_composables/use-reference-query.ts @@ -0,0 +1,38 @@ +import { toValue, type MaybeRef } from '@vueuse/core'; +import { computed } from 'vue'; + +import { useQuery, type UseQueryOptions } from '@tanstack/vue-query'; + +import type { APIError } from '@cloudforet/core-lib/space-connector/error'; + +import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; + +import { useAppContextStore } from '@/store/app-context/app-context-store'; + + +const REFERENCE_LOAD_TTL = 1000 * 60 * 60 * 3; // 3 hours + +export const useReferenceQuery = , TError = unknown, TData = TQueryFnData>( + options: UseQueryOptions, +) => { + const appContextStore = useAppContextStore(); + + const queryEnabled = computed(() => { + const _inheritedEnabled = ('enabled' in options ? options.enabled : undefined) as MaybeRef | undefined; + if (_inheritedEnabled !== undefined && !toValue(_inheritedEnabled)) return false; + return !appContextStore.getters.globalGrantLoading; + }); + + return useQuery({ + ...options, + enabled: queryEnabled, + staleTime: REFERENCE_LOAD_TTL, + retry: (failureCount, err) => { + if ((err as APIError).status === 404) { + return false; + } + return failureCount < 3; + }, + // TODO: add error handler + }); +}; diff --git a/apps/web/src/query/reference/_types/reference-query-type.ts b/apps/web/src/query/reference/_types/reference-query-type.ts new file mode 100644 index 0000000000..28ca561ffb --- /dev/null +++ b/apps/web/src/query/reference/_types/reference-query-type.ts @@ -0,0 +1,21 @@ +export interface ReferenceItem> { + key?: string; + label?: string; + name?: string; + color?: string; + icon?: string; + provider?: string; + continent?: { + continent_code?: string; + continent_label?: string; + latitude?: number; + longitude?: number; + }; + latitude?: string; + longitude?: string; + data?: Data; + description?: string; + link?: string; +} + +export type ReferenceMap = Record; diff --git a/apps/web/src/query/reference/use-all-reference-query.ts b/apps/web/src/query/reference/use-all-reference-query.ts new file mode 100644 index 0000000000..f7706d36cb --- /dev/null +++ b/apps/web/src/query/reference/use-all-reference-query.ts @@ -0,0 +1,48 @@ +import type { ComputedRef } from 'vue'; +import { computed } from 'vue'; + +import { usePublicDashboardReferenceQuery } from '@/query/reference/use-public-dashboard-reference-query'; + +import type { REFERENCE_TYPE_MAP } from './_constants/reference-type-map'; + +interface ReferenceGetters { + publicDashboard: { + items: ComputedRef>; + typeInfo: ComputedRef; + status: ComputedRef<{ + isLoading: boolean; + isError: boolean; + }>; + }; +} + +export const useAllReferenceQuery = () => { + const publicDashboardQuery = usePublicDashboardReferenceQuery(); + + const getters = { + publicDashboard: { + items: computed(() => publicDashboardQuery.data.value?.referenceMap), + typeInfo: computed(() => publicDashboardQuery.data.value), + status: computed(() => ({ + isLoading: publicDashboardQuery.isPending.value, + isError: publicDashboardQuery.isError.value, + })), + }, + // TODO: add other reference queries + }; + + const refetch = async (type: keyof typeof REFERENCE_TYPE_MAP) => { + switch (type) { + case 'publicDashboard': + await publicDashboardQuery.refetch(); break; + // TODO: add other reference queries + default: + throw new Error(`Unsupported reference type: ${type}`); + } + }; + + return { + getters, + refetch, + }; +}; diff --git a/apps/web/src/query/reference/use-public-dashboard-reference-query.ts b/apps/web/src/query/reference/use-public-dashboard-reference-query.ts new file mode 100644 index 0000000000..c556a0996b --- /dev/null +++ b/apps/web/src/query/reference/use-public-dashboard-reference-query.ts @@ -0,0 +1,58 @@ +import type { ComputedRef } from 'vue'; + +import { usePublicDashboardApi } from '@/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api'; +import type { PublicDashboardModel } from '@/api-clients/dashboard/public-dashboard/schema/model'; +import { useReferenceQuery } from '@/query/_composables/use-reference-query'; +import { useReferenceQueryKey } from '@/query/reference/_composables/use-reference-query-key'; +import type { ReferenceItem, ReferenceMap } from '@/query/reference/_types/reference-query-type'; + +interface PublicDashboardResourceItemData { + resourceGroup?: PublicDashboardModel['resource_group']; + projectId?: string; + folderId?: string; + shared?: boolean; + scope?: string; +} +export type PublicDashboardReferenceItem = Required, 'key'|'label'|'name'|'data'>>; +export type PublicDashboardReferenceMap = ReferenceMap; + + + +export const usePublicDashboardReferenceQuery = () => { + const queryKey = useReferenceQueryKey(); + const { publicDashboardAPI } = usePublicDashboardApi(); + + const queryFn = () => publicDashboardAPI.list({ + query: { + only: ['dashboard_id', 'name', 'project_id', 'resource_group', 'shared', 'scope', 'folder_id'], + }, + }); + + return useReferenceQuery({ + queryKey: queryKey.value.publicDashboard, + queryFn, + select: (data) => { + const referenceMap: PublicDashboardReferenceMap = {}; + data.results?.forEach((dashboard) => { + referenceMap[dashboard.dashboard_id] = { + key: dashboard.dashboard_id, + label: dashboard.name, + name: dashboard.name, + data: { + resourceGroup: dashboard.resource_group, + projectId: dashboard.project_id, + folderId: dashboard.folder_id, + shared: dashboard.shared, + scope: dashboard.scope, + }, + }; + }); + return { + type: 'public_dashboard', + key: 'dashboard_id', + name: 'Public Dashboard', + referenceMap, + }; + }, + }); +}; From e6c17ed51aa7a4c345968a23cc4de5cbd1077371 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9A=A9=ED=83=9C?= Date: Thu, 20 Mar 2025 22:55:26 +0900 Subject: [PATCH 14/20] feat(reference-query): refactor reference query Signed-off-by: piggggggggy --- .../_composables/use-query-key-app-context.ts | 16 +-- .../query/_composables/use-reference-query.ts | 3 +- .../_composables/use-reference-query-key.ts | 6 +- .../_constants/reference-type-map.ts | 133 ++++++++++++++---- .../reference/_types/reference-query-type.ts | 7 + .../_types/reference-resource-type.ts | 4 +- .../reference/use-all-reference-query.ts | 34 ++--- 7 files changed, 143 insertions(+), 60 deletions(-) diff --git a/apps/web/src/query/_composables/use-query-key-app-context.ts b/apps/web/src/query/_composables/use-query-key-app-context.ts index 2e0f1b8d32..6597ef191d 100644 --- a/apps/web/src/query/_composables/use-query-key-app-context.ts +++ b/apps/web/src/query/_composables/use-query-key-app-context.ts @@ -9,18 +9,18 @@ import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-worksp * Interface for global query parameters used across API requests. * These parameters are automatically included in API and reference query keys. */ -export type QueryContextType = 'service' | 'reference'; +export type QueryScope = 'service' | 'reference'; export interface QueryKeyContextParams { isAdminMode?: boolean; workspaceId?: string; - context: QueryContextType; + scope: QueryScope; } export interface QueryContext { mode: 'admin' | 'workspace'; workspaceId?: string; - context: QueryContextType; + scope: QueryScope; } /** @@ -61,7 +61,7 @@ export const useQueryKeyContext = (queryKeyOptions: QueryKeyContextParams): Comp return computed(() => { const { - isAdminMode, workspaceId: _workspaceId, context, + isAdminMode, workspaceId: _workspaceId, scope, } = queryKeyOptions || {}; const mode = (isAdminMode || _state.isAdminMode) ? 'admin' : 'workspace'; const workspaceId = _workspaceId || _state.currentWorkspaceId; @@ -69,7 +69,7 @@ export const useQueryKeyContext = (queryKeyOptions: QueryKeyContextParams): Comp return { mode, workspaceId, - context, + scope, }; }); }; @@ -88,7 +88,7 @@ interface WorkspaceModeState { type QueryKeyState = AdminModeState | WorkspaceModeState; -export const useQueryKeyAppContext = (context: QueryContextType = 'service') => { +export const useQueryKeyAppContext = (queryScope: QueryScope = 'service') => { const appContextStore = useAppContextStore(); const userWorkspaceStore = useUserWorkspaceStore(); @@ -107,8 +107,8 @@ export const useQueryKeyAppContext = (context: QueryContextType = 'service') => }; return state.isAdminMode - ? [context, 'admin'] - : [context, 'workspace', state.workspaceId]; + ? [queryScope, 'admin'] + : [queryScope, 'workspace', state.workspaceId]; }); }; diff --git a/apps/web/src/query/_composables/use-reference-query.ts b/apps/web/src/query/_composables/use-reference-query.ts index 50434de6f4..8f5484bb51 100644 --- a/apps/web/src/query/_composables/use-reference-query.ts +++ b/apps/web/src/query/_composables/use-reference-query.ts @@ -11,6 +11,7 @@ import { useAppContextStore } from '@/store/app-context/app-context-store'; const REFERENCE_LOAD_TTL = 1000 * 60 * 60 * 3; // 3 hours +const INITIAL_LIST_RESPONSE_DATA: ListResponse = { results: [] }; export const useReferenceQuery = , TError = unknown, TData = TQueryFnData>( options: UseQueryOptions, @@ -33,6 +34,6 @@ export const useReferenceQuery = , TE } return failureCount < 3; }, - // TODO: add error handler + initialData: (() => INITIAL_LIST_RESPONSE_DATA as TQueryFnData), }); }; diff --git a/apps/web/src/query/reference/_composables/use-reference-query-key.ts b/apps/web/src/query/reference/_composables/use-reference-query-key.ts index a206412825..c67d8e6f0f 100644 --- a/apps/web/src/query/reference/_composables/use-reference-query-key.ts +++ b/apps/web/src/query/reference/_composables/use-reference-query-key.ts @@ -3,15 +3,15 @@ import { computed } from 'vue'; import { useQueryKeyAppContext } from '@/query/_composables/use-query-key-app-context'; import type { QueryKeyArray } from '@/query/_types/query-key-type'; -import { REFERENCE_TYPE_MAP } from '@/query/reference/_constants/reference-type-map'; +import { REFERENCE_TYPE_INFO_MAP } from '@/query/reference/_constants/reference-type-map'; -type UseReferenceQueryKeyResult = Record; +type UseReferenceQueryKeyResult = Record; export const useReferenceQueryKey = (): ComputedRef => { const queryKeyAppContext = useQueryKeyAppContext('reference'); - return computed(() => Object.entries(REFERENCE_TYPE_MAP).reduce((acc, [key, value]) => ({ + return computed(() => Object.entries(REFERENCE_TYPE_INFO_MAP).reduce((acc, [key, value]) => ({ ...acc, [key]: [queryKeyAppContext.value, value], }), {} as UseReferenceQueryKeyResult)); diff --git a/apps/web/src/query/reference/_constants/reference-type-map.ts b/apps/web/src/query/reference/_constants/reference-type-map.ts index 8f962f2acf..a70a252c89 100644 --- a/apps/web/src/query/reference/_constants/reference-type-map.ts +++ b/apps/web/src/query/reference/_constants/reference-type-map.ts @@ -1,28 +1,107 @@ -export const REFERENCE_TYPE_MAP = { - app: 'app', - cloudServiceType: 'cloud_service_type', - cloudServiceQuerySet: 'cloud_service_query_set', - collector: 'collector', - costDataSource: 'cost_data_source', - escalationPolicy: 'escalation_policy', - metric: 'metric', - namespace: 'namespace', - plugin: 'plugin', - projectGroup: 'project_group', - project: 'project', - protocol: 'protocol', - provider: 'provider', - publicDashboard: 'public_dashboard', - publicFolder: 'public_folder', - region: 'region', - role: 'role', - secret: 'secret', - serviceAccount: 'service_account', - service: 'service', - trustedServiceAccount: 'trusted_service_account', - userGroup: 'user_group', - user: 'user', - webhook: 'webhook', - workspaceGroup: 'workspace_group', - workspace: 'workspace', +export const REFERENCE_TYPE_INFO_MAP = { + app: { + type: 'app', + key: 'app_id', + name: 'App', + }, + cloudServiceType: { + type: 'cloud_service_type', + key: 'cloud_service_type_id', + name: 'Cloud Service Type', + }, + cloudServiceQuerySet: { + type: 'cloud_service_query_set', + key: 'query_set_id', + name: 'Cloud Service Query Set', + }, + collector: { + type: 'collector', + key: 'collector_id', + name: 'Collector', + }, + costDataSource: { + type: 'cost_data_source', + key: 'data_source_id', + name: 'Cost Data Source', + }, + escalationPolicy: { + type: 'escalation_policy', + key: 'escalation_policy_id', + name: 'Escalation Policy', + }, + metric: { + type: 'metric', + key: 'metric_id', + name: 'Metric', + }, + namespace: { + type: 'namespace', + key: 'namespace_id', + name: 'Namespace', + }, + plugin: { + type: 'plugin', + key: 'plugin_id', + name: 'Plugin', + }, + projectGroup: { + type: 'project_group', + key: 'project_group_id', + name: 'Project Group', + }, + project: { + type: 'project', + key: 'project_id', + name: 'Project', + }, + publicDashboard: { + type: 'public_dashboard', + key: 'dashboard_id', + name: 'Public Dashboard', + }, + publicFolder: { + type: 'public_folder', + key: 'folder_id', + name: 'Public Folder', + }, + region: { + type: 'region', + key: 'region_code', + name: 'Region', + }, + role: { + type: 'role', + key: 'role_id', + name: 'Role', + }, + secret: { + type: 'secret', + key: 'secret_id', + name: 'Secret', + }, + serviceAccount: { + type: 'service_account', + key: 'service_account_id', + name: 'Service Account', + }, + service: { + type: 'service', + key: 'service_id', + name: 'Service', + }, + trustedAccount: { + type: 'trusted_account', + key: 'trusted_account_id', + name: 'name', + }, + userGroup: { + type: 'user_group', + key: 'user_group_id', + name: 'User Group', + }, + workspace: { + type: 'workspace', + key: 'workspace_id', + name: 'Workspace', + }, } as const; diff --git a/apps/web/src/query/reference/_types/reference-query-type.ts b/apps/web/src/query/reference/_types/reference-query-type.ts index 28ca561ffb..0fa2a9cd48 100644 --- a/apps/web/src/query/reference/_types/reference-query-type.ts +++ b/apps/web/src/query/reference/_types/reference-query-type.ts @@ -19,3 +19,10 @@ export interface ReferenceItem> { } export type ReferenceMap = Record; + +export interface ReferenceTypeInfo { + type: string; // 'project' + key: string; // project_id + name: string; // Project + referenceMap: ReferenceMap; +} diff --git a/apps/web/src/query/reference/_types/reference-resource-type.ts b/apps/web/src/query/reference/_types/reference-resource-type.ts index 7c0682df92..b5fe29a379 100644 --- a/apps/web/src/query/reference/_types/reference-resource-type.ts +++ b/apps/web/src/query/reference/_types/reference-resource-type.ts @@ -1,4 +1,4 @@ -import type { REFERENCE_TYPE_MAP } from '@/query/reference/_constants/reference-type-map'; +import type { REFERENCE_TYPE_INFO_MAP } from '@/query/reference/_constants/reference-type-map'; -export type ReferenceResourceType = typeof REFERENCE_TYPE_MAP[keyof typeof REFERENCE_TYPE_MAP]; +export type ReferenceResourceType = typeof REFERENCE_TYPE_INFO_MAP[keyof typeof REFERENCE_TYPE_INFO_MAP]; diff --git a/apps/web/src/query/reference/use-all-reference-query.ts b/apps/web/src/query/reference/use-all-reference-query.ts index f7706d36cb..4e139e8e81 100644 --- a/apps/web/src/query/reference/use-all-reference-query.ts +++ b/apps/web/src/query/reference/use-all-reference-query.ts @@ -1,37 +1,26 @@ -import type { ComputedRef } from 'vue'; import { computed } from 'vue'; -import { usePublicDashboardReferenceQuery } from '@/query/reference/use-public-dashboard-reference-query'; +import { useQueryClient } from '@tanstack/vue-query'; -import type { REFERENCE_TYPE_MAP } from './_constants/reference-type-map'; +import type { PublicDashboardReferenceMap } from '@/query/reference/use-public-dashboard-reference-query'; +import { usePublicDashboardReferenceQuery } from '@/query/reference/use-public-dashboard-reference-query'; -interface ReferenceGetters { - publicDashboard: { - items: ComputedRef>; - typeInfo: ComputedRef; - status: ComputedRef<{ - isLoading: boolean; - isError: boolean; - }>; - }; -} +import type { REFERENCE_TYPE_INFO_MAP } from './_constants/reference-type-map'; export const useAllReferenceQuery = () => { const publicDashboardQuery = usePublicDashboardReferenceQuery(); + const queryClient = useQueryClient(); const getters = { publicDashboard: { - items: computed(() => publicDashboardQuery.data.value?.referenceMap), + items: computed(() => publicDashboardQuery.data.value?.referenceMap ?? {}), typeInfo: computed(() => publicDashboardQuery.data.value), - status: computed(() => ({ - isLoading: publicDashboardQuery.isPending.value, - isError: publicDashboardQuery.isError.value, - })), + isLoading: computed(() => publicDashboardQuery.isFetching.value), }, // TODO: add other reference queries }; - const refetch = async (type: keyof typeof REFERENCE_TYPE_MAP) => { + const refetch = async (type: keyof typeof REFERENCE_TYPE_INFO_MAP) => { switch (type) { case 'publicDashboard': await publicDashboardQuery.refetch(); break; @@ -41,8 +30,15 @@ export const useAllReferenceQuery = () => { } }; + const refetchAll = async () => { + queryClient.invalidateQueries({ + queryKey: ['reference'], + }); + }; + return { getters, refetch, + refetchAll, }; }; From 923e706b8d565e9b7eaa99ce7bbd5cc273d270b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9A=A9=ED=83=9C?= Date: Thu, 20 Mar 2025 22:56:12 +0900 Subject: [PATCH 15/20] feat(reference-sync): create reference query sync composable Signed-off-by: piggggggggy --- .../composables/use-public-dashboard-api.ts | 8 +- .../_composables/use-reference-query-sync.ts | 77 +++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 apps/web/src/query/reference/_composables/use-reference-query-sync.ts diff --git a/apps/web/src/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api.ts b/apps/web/src/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api.ts index e2969a6483..e243d5d0ba 100644 --- a/apps/web/src/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api.ts +++ b/apps/web/src/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api.ts @@ -15,6 +15,7 @@ import type { PublicDashboardShareParameters } from '@/api-clients/dashboard/pub import type { PublicDashboardUnshareParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/unshare'; import type { PublicDashboardUpdateParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/update'; import type { PublicDashboardModel } from '@/api-clients/dashboard/public-dashboard/schema/model'; +import { useReferenceQuerySync } from '@/query/reference/_composables/use-reference-query-sync'; interface UsePublicDashboardApiReturn { publicDashboardGetQueryKey: ComputedRef; @@ -34,13 +35,14 @@ interface UsePublicDashboardApiReturn { export const usePublicDashboardApi = (): UsePublicDashboardApiReturn => { const publicDashboardGetQueryKey = useAPIQueryKey('dashboard', 'public-dashboard', 'get'); const publicDashboardListQueryKey = useAPIQueryKey('dashboard', 'public-dashboard', 'list'); + const { withReferenceUpdate, withReferenceRefresh } = useReferenceQuerySync('publicDashboard'); const actions = { async create(params: PublicDashboardCreateParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.create(params); + return withReferenceUpdate(() => SpaceConnector.clientV2.dashboard.publicDashboard.create(params)); }, async update(params: PublicDashboardUpdateParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.update(params); + return withReferenceUpdate(() => SpaceConnector.clientV2.dashboard.publicDashboard.update(params)); }, async changeFolder(params: PublicDashboardChangeFolderParameters) { return SpaceConnector.clientV2.dashboard.publicDashboard.changeFolder(params); @@ -52,7 +54,7 @@ export const usePublicDashboardApi = (): UsePublicDashboardApiReturn => { return SpaceConnector.clientV2.dashboard.publicDashboard.unshare(params); }, async delete(params: PublicDashboardDeleteParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.delete(params); + return withReferenceRefresh(() => SpaceConnector.clientV2.dashboard.publicDashboard.delete(params)); }, async get(params: PublicDashboardGetParameters) { return SpaceConnector.clientV2.dashboard.publicDashboard.get(params); diff --git a/apps/web/src/query/reference/_composables/use-reference-query-sync.ts b/apps/web/src/query/reference/_composables/use-reference-query-sync.ts new file mode 100644 index 0000000000..b976b48781 --- /dev/null +++ b/apps/web/src/query/reference/_composables/use-reference-query-sync.ts @@ -0,0 +1,77 @@ +import type { QueryClient } from '@tanstack/vue-query'; +import { useQueryClient } from '@tanstack/vue-query'; + +import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; +import type { QueryKeyArray } from '@/query/_types/query-key-type'; +import { useReferenceQueryKey } from '@/query/reference/_composables/use-reference-query-key'; +import { REFERENCE_TYPE_INFO_MAP } from '@/query/reference/_constants/reference-type-map'; + + +type MutationCallback = () => Promise; + +export const useReferenceQuerySync = (resourceType: keyof typeof REFERENCE_TYPE_INFO_MAP) => { + const queryClient = useQueryClient(); + + const withReferenceUpdate = async ( + mutationCallback: MutationCallback, + ): Promise => { + const response = await mutationCallback(); + const referenceQueryKey = useReferenceQueryKey(); + const queryKey = referenceQueryKey.value[resourceType]; + await updateReferenceCache(queryClient, queryKey, response, resourceType); + return response; + }; + + const withReferenceRefresh = async ( + mutationCallback: MutationCallback, + ): Promise => { + await mutationCallback(); + const referenceQueryKey = useReferenceQueryKey(); + const queryKey = referenceQueryKey.value[resourceType]; + await queryClient.invalidateQueries({ queryKey }); + }; + + return { withReferenceUpdate, withReferenceRefresh }; +}; + + +const updateReferenceCache = async ( + queryClient: QueryClient, + queryKey: QueryKeyArray, + newData: T, + resourceType: keyof typeof REFERENCE_TYPE_INFO_MAP, +) => { + const resourceKey = REFERENCE_TYPE_INFO_MAP[resourceType].key; + + if (!resourceKey || !newData[resourceKey]) { + throw new Error(`Invalid resource key or data for type: ${resourceType}`); + } + + queryClient.setQueryData>(queryKey, (oldData: ListResponse | undefined) => { + const currentResults = oldData?.results ?? []; + + if (newData == null) { + return oldData; + } + + const existingItemIndex = currentResults.findIndex( + (item) => item?.[resourceKey] === newData[resourceKey], + ); + + if (existingItemIndex > -1) { + const updatedResults = [...currentResults]; + updatedResults[existingItemIndex] = newData; + return { results: updatedResults }; + } + + return { + results: [...currentResults, newData], + }; + }); +}; + + + + + + From 03d501fdfc28a9b8a37c8c83f848921fe0030350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9A=A9=ED=83=9C?= Date: Thu, 20 Mar 2025 22:56:36 +0900 Subject: [PATCH 16/20] fix(invalidator): refactor query invalidators Signed-off-by: piggggggggy --- .../helpers/service-query-invalidation-helper.ts | 15 ++------------- .../reference-query-invalidation-helper.ts | 15 ++------------- 2 files changed, 4 insertions(+), 26 deletions(-) diff --git a/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts b/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts index 48d77d4535..2a26826df3 100644 --- a/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts +++ b/apps/web/src/api-clients/_common/helpers/service-query-invalidation-helper.ts @@ -1,18 +1,7 @@ import { queryClient } from '@/query'; -import type { QueryContext } from '@/query/_types/query-key-type'; -/** - * Invalidates all service queries based on the specified mode. - * - * @param mode - Optional mode filter ('ADMIN' | 'WORKSPACE') - */ -export const invalidateServiceQuery = async (mode?: 'admin' | 'workspace') => { +export const invalidateServiceQuery = async (mode: 'admin' | 'workspace') => { await queryClient.invalidateQueries({ - predicate: (query) => { - const [queryContext] = query.queryKey as [QueryContext, ...unknown[]]; - if (!queryContext || queryContext.context !== 'service') return false; - if (mode && mode !== queryContext.mode) return false; - return true; - }, + queryKey: ['service', mode], }); }; diff --git a/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts b/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts index 7b4898913a..919683a837 100644 --- a/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts +++ b/apps/web/src/query/reference/_helper/reference-query-invalidation-helper.ts @@ -1,18 +1,7 @@ import { queryClient } from '@/query'; -import type { QueryContext } from '@/query/_types/query-key-type'; -/** - * Invalidates all reference queries based on the specified mode. - * - * @param mode - Optional mode filter ('ADMIN' | 'WORKSPACE') - */ -export const invalidateReferenceQuery = async (mode?: 'admin' | 'workspace') => { +export const invalidateReferenceQuery = async (mode: 'admin' | 'workspace') => { await queryClient.invalidateQueries({ - predicate: (query) => { - const [queryContext] = query.queryKey as [QueryContext, ...unknown[]]; - if (!queryContext || queryContext.context !== 'reference') return false; - if (mode && mode !== queryContext.mode) return false; - return true; - }, + queryKey: ['reference', mode], }); }; From 21311f861c7913b81e86c5fb7087ee41ce5ca8ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=B0=95=EC=9A=A9=ED=83=9C?= Date: Thu, 20 Mar 2025 22:57:08 +0900 Subject: [PATCH 17/20] feat(query-key): apply immutable object to api query key Signed-off-by: piggggggggy --- .../_common/composables/use-api-query-key.ts | 23 +++++++++++++++---- .../src/query/_helper/immutable-key-helper.ts | 16 +++++++++++++ 2 files changed, 35 insertions(+), 4 deletions(-) create mode 100644 apps/web/src/query/_helper/immutable-key-helper.ts diff --git a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts index 6f16ac4556..0d0d556bea 100644 --- a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts +++ b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts @@ -8,6 +8,7 @@ import type { APIQueryKeyMapService, APIQueryKeyMapResource, APIQueryKeyMapVerb, ServiceName, ResourceName, Verb, } from '@/api-clients/_common/types/query-key-type'; import { useQueryKeyAppContext } from '@/query/_composables/use-query-key-app-context'; +import { createImmutableObject } from '@/query/_helper/immutable-key-helper'; import type { QueryKeyArray } from '@/query/_types/query-key-type'; import { useAppContextStore } from '@/store/app-context/app-context-store'; @@ -46,17 +47,31 @@ export const _useAPIQueryKey = (): ComputedRef => { return computed(() => { const createKeyWithContext = (queryKeyValue: T): MapVerbToReturnType => { if (Array.isArray(queryKeyValue)) { - return [...queryKeyAppContext.value, ...queryKeyValue] as MapVerbToReturnType; + return [ + ...queryKeyAppContext.value, + ...createImmutableObject(queryKeyValue), + ] as MapVerbToReturnType; } const verbFunction = (params?: ExtractParams) => { const baseKey = queryKeyValue(params); - const result = [...queryKeyAppContext.value, ...baseKey] as QueryKeyArrayWithDep; - result.addDep = (deps) => [...queryKeyAppContext.value, ...baseKey, deps]; + const result = [ + ...queryKeyAppContext.value, + ...createImmutableObject(baseKey), + ] as QueryKeyArrayWithDep; + result.addDep = (deps) => [ + ...queryKeyAppContext.value, + ...createImmutableObject(baseKey), + createImmutableObject(deps), + ]; return result; }; - verbFunction.addDep = (deps) => [...queryKeyAppContext.value, ...queryKeyValue(), deps]; + verbFunction.addDep = (deps) => [ + ...queryKeyAppContext.value, + ...createImmutableObject(queryKeyValue()), + createImmutableObject(deps), + ]; return verbFunction as MapVerbToReturnType; }; diff --git a/apps/web/src/query/_helper/immutable-key-helper.ts b/apps/web/src/query/_helper/immutable-key-helper.ts new file mode 100644 index 0000000000..f1372f94b1 --- /dev/null +++ b/apps/web/src/query/_helper/immutable-key-helper.ts @@ -0,0 +1,16 @@ +export const createImmutableObject = >(obj: T): T => { + if (obj === null || typeof obj !== 'object') { + return obj; + } + + if (Array.isArray(obj)) { + return obj.map((item) => createImmutableObject(item)) as unknown as T; + } + + const immutableObj = Object.entries(obj).reduce((acc, [key, value]) => ({ + ...acc, + [key]: createImmutableObject(value), + }), {}); + + return Object.freeze(immutableObj) as T; +}; From 2635d86280ca94a4fe6e8c99a4be91daa1b4a766 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Fri, 21 Mar 2025 10:56:23 +0900 Subject: [PATCH 18/20] chore: small fix Signed-off-by: samuel.park --- .../api-clients/dashboard/private-dashboard/keys.ts | 6 +++--- .../api-clients/dashboard/private-data-table/keys.ts | 8 ++++---- .../src/api-clients/dashboard/private-folder/keys.ts | 6 +++--- .../src/api-clients/dashboard/private-widget/keys.ts | 10 +++++----- .../src/api-clients/dashboard/public-dashboard/keys.ts | 6 +++--- .../api-clients/dashboard/public-data-table/keys.ts | 8 ++++---- .../src/api-clients/dashboard/public-folder/keys.ts | 6 +++--- .../src/api-clients/dashboard/public-widget/keys.ts | 10 +++++----- apps/web/src/api-clients/opsflow/comment/keys.ts | 6 +++--- apps/web/src/api-clients/opsflow/event/keys.ts | 4 ++-- apps/web/src/api-clients/opsflow/task-category/keys.ts | 6 +++--- apps/web/src/api-clients/opsflow/task-type/keys.ts | 6 +++--- apps/web/src/api-clients/opsflow/task/keys.ts | 6 +++--- 13 files changed, 44 insertions(+), 44 deletions(-) diff --git a/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts b/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts index a0dd6f1b0e..a7cfda6d86 100644 --- a/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts +++ b/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts @@ -2,7 +2,7 @@ import type { PrivateDashboardGetParameters } from '@/api-clients/dashboard/priv import type { PrivateDashboardListParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/list'; export const privateDashboardKeys = { - all: ['private-dashboard'], - list: (params: PrivateDashboardListParameters) => [...privateDashboardKeys.all, 'list', params], - get: (idParam: PrivateDashboardGetParameters['dashboard_id']) => [...privateDashboardKeys.all, 'get', idParam], + all: ['private-dashboard'] as const, + list: (params: PrivateDashboardListParameters) => [...privateDashboardKeys.all, 'list', params] as const, + get: (idParam: PrivateDashboardGetParameters['dashboard_id']) => [...privateDashboardKeys.all, 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/private-data-table/keys.ts b/apps/web/src/api-clients/dashboard/private-data-table/keys.ts index f6e8fe61ce..3e56601bca 100644 --- a/apps/web/src/api-clients/dashboard/private-data-table/keys.ts +++ b/apps/web/src/api-clients/dashboard/private-data-table/keys.ts @@ -3,8 +3,8 @@ import type { DataTableListParameters } from '@/api-clients/dashboard/private-da import type { DataTableLoadParameters } from '@/api-clients/dashboard/private-data-table/schema/api-verbs/load'; export const privateDataTableKeys = { - all: ['private-data-table'], - list: (params: DataTableListParameters) => [...privateDataTableKeys.all, 'list', params], - get: (idParam: DataTableGetParameters['data_table_id']) => [...privateDataTableKeys.all, 'get', idParam], - load: (idParam: DataTableLoadParameters['data_table_id']) => [...privateDataTableKeys.all, 'load', idParam], + all: ['private-data-table'] as const, + list: (params: DataTableListParameters) => [...privateDataTableKeys.all, 'list', params] as const, + get: (idParam: DataTableGetParameters['data_table_id']) => [...privateDataTableKeys.all, 'get', idParam] as const, + load: (idParam: DataTableLoadParameters['data_table_id']) => [...privateDataTableKeys.all, 'load', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/private-folder/keys.ts b/apps/web/src/api-clients/dashboard/private-folder/keys.ts index a3a8d8948a..17aeec4cf4 100644 --- a/apps/web/src/api-clients/dashboard/private-folder/keys.ts +++ b/apps/web/src/api-clients/dashboard/private-folder/keys.ts @@ -2,7 +2,7 @@ import type { PrivateFolderGetParameters } from '@/api-clients/dashboard/private import type { PrivateFolderListParameters } from '@/api-clients/dashboard/private-folder/schema/api-verbs/list'; export const privateFolderKeys = { - all: ['private-folder'], - list: (params: PrivateFolderListParameters) => [...privateFolderKeys.all, 'list', params], - get: (idParam: PrivateFolderGetParameters['folder_id']) => [...privateFolderKeys.all, 'get', idParam], + all: ['private-folder'] as const, + list: (params: PrivateFolderListParameters) => [...privateFolderKeys.all, 'list', params] as const, + get: (idParam: PrivateFolderGetParameters['folder_id']) => [...privateFolderKeys.all, 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/private-widget/keys.ts b/apps/web/src/api-clients/dashboard/private-widget/keys.ts index 3741ad3c8a..e96d9b161c 100644 --- a/apps/web/src/api-clients/dashboard/private-widget/keys.ts +++ b/apps/web/src/api-clients/dashboard/private-widget/keys.ts @@ -4,9 +4,9 @@ import type { PrivateWidgetLoadParameters } from '@/api-clients/dashboard/privat import type { PrivateWidgetLoadSumParameters } from '@/api-clients/dashboard/private-widget/schema/api-verbs/load-sum'; export const privateWidgetKeys = { - all: ['private-widget'], - list: (params: PrivateWidgetListParameters) => [...privateWidgetKeys.all, 'list', params], - get: (idParam: PrivateWidgetGetParameters['widget_id']) => [...privateWidgetKeys.all, 'get', idParam], - load: (idParam: PrivateWidgetLoadParameters['widget_id']) => [...privateWidgetKeys.all, 'load', idParam], - loadSum: (idParam: PrivateWidgetLoadSumParameters['widget_id']) => [...privateWidgetKeys.all, 'load-sum', idParam], + all: ['private-widget'] as const, + list: (params: PrivateWidgetListParameters) => [...privateWidgetKeys.all, 'list', params] as const, + get: (idParam: PrivateWidgetGetParameters['widget_id']) => [...privateWidgetKeys.all, 'get', idParam] as const, + load: (idParam: PrivateWidgetLoadParameters['widget_id']) => [...privateWidgetKeys.all, 'load', idParam] as const, + loadSum: (idParam: PrivateWidgetLoadSumParameters['widget_id']) => [...privateWidgetKeys.all, 'load-sum', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts b/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts index 6b20473141..7de67a7d72 100644 --- a/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts +++ b/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts @@ -2,7 +2,7 @@ import type { PublicDashboardGetParameters } from '@/api-clients/dashboard/publi import type { PublicDashboardListParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/list'; export const publicDashboardKeys = { - all: ['public-dashboard'], - list: (params: PublicDashboardListParameters) => [...publicDashboardKeys.all, 'list', params], - get: (idParam: PublicDashboardGetParameters['dashboard_id']) => [...publicDashboardKeys.all, 'get', idParam], + all: ['public-dashboard'] as const, + list: (params: PublicDashboardListParameters) => [...publicDashboardKeys.all, 'list', params] as const, + get: (idParam: PublicDashboardGetParameters['dashboard_id']) => [...publicDashboardKeys.all, 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/public-data-table/keys.ts b/apps/web/src/api-clients/dashboard/public-data-table/keys.ts index 6ea189969e..b21c4803d2 100644 --- a/apps/web/src/api-clients/dashboard/public-data-table/keys.ts +++ b/apps/web/src/api-clients/dashboard/public-data-table/keys.ts @@ -3,8 +3,8 @@ import type { DataTableListParameters } from '@/api-clients/dashboard/public-dat import type { DataTableLoadParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/load'; export const publicDataTableKeys = { - all: ['public-data-table'], - list: (params: DataTableListParameters) => [...publicDataTableKeys.all, 'list', params], - get: (idParam: DataTableGetParameters['data_table_id']) => [...publicDataTableKeys.all, 'get', idParam], - load: (idParam: DataTableLoadParameters['data_table_id']) => [...publicDataTableKeys.all, 'load', idParam], + all: ['public-data-table'] as const, + list: (params: DataTableListParameters) => [...publicDataTableKeys.all, 'list', params] as const, + get: (idParam: DataTableGetParameters['data_table_id']) => [...publicDataTableKeys.all, 'get', idParam] as const, + load: (idParam: DataTableLoadParameters['data_table_id']) => [...publicDataTableKeys.all, 'load', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/public-folder/keys.ts b/apps/web/src/api-clients/dashboard/public-folder/keys.ts index 7f9329b70f..207357b2ec 100644 --- a/apps/web/src/api-clients/dashboard/public-folder/keys.ts +++ b/apps/web/src/api-clients/dashboard/public-folder/keys.ts @@ -2,7 +2,7 @@ import type { PublicFolderGetParameters } from '@/api-clients/dashboard/public-f import type { PublicFolderListParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/list'; export const publicFolderKeys = { - all: ['public-folder'], - list: (params: PublicFolderListParameters) => [...publicFolderKeys.all, 'list', params], - get: (idParam: PublicFolderGetParameters['folder_id']) => [...publicFolderKeys.all, 'get', idParam], + all: ['public-folder'] as const, + list: (params: PublicFolderListParameters) => [...publicFolderKeys.all, 'list', params] as const, + get: (idParam: PublicFolderGetParameters['folder_id']) => [...publicFolderKeys.all, 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/public-widget/keys.ts b/apps/web/src/api-clients/dashboard/public-widget/keys.ts index 78e0e6c2f5..6cff69946a 100644 --- a/apps/web/src/api-clients/dashboard/public-widget/keys.ts +++ b/apps/web/src/api-clients/dashboard/public-widget/keys.ts @@ -4,9 +4,9 @@ import type { PublicWidgetLoadParameters } from '@/api-clients/dashboard/public- import type { PublicWidgetLoadSumParameters } from '@/api-clients/dashboard/public-widget/schema/api-verbs/load-sum'; export const publicWidgetKeys = { - all: ['public-widget'], - list: (params: PublicWidgetListParameters) => [...publicWidgetKeys.all, 'list', params], - get: (idParam: PublicWidgetGetParameters['widget_id']) => [...publicWidgetKeys.all, 'get', idParam], - load: (idParam: PublicWidgetLoadParameters['widget_id']) => [...publicWidgetKeys.all, 'load', idParam], - loadSum: (idParam: PublicWidgetLoadSumParameters['widget_id']) => [...publicWidgetKeys.all, 'load-sum', idParam], + all: ['public-widget'] as const, + list: (params: PublicWidgetListParameters) => [...publicWidgetKeys.all, 'list', params] as const, + get: (idParam: PublicWidgetGetParameters['widget_id']) => [...publicWidgetKeys.all, 'get', idParam] as const, + load: (idParam: PublicWidgetLoadParameters['widget_id']) => [...publicWidgetKeys.all, 'load', idParam] as const, + loadSum: (idParam: PublicWidgetLoadSumParameters['widget_id']) => [...publicWidgetKeys.all, 'load-sum', idParam] as const, }; diff --git a/apps/web/src/api-clients/opsflow/comment/keys.ts b/apps/web/src/api-clients/opsflow/comment/keys.ts index 1125f24314..d29c72d797 100644 --- a/apps/web/src/api-clients/opsflow/comment/keys.ts +++ b/apps/web/src/api-clients/opsflow/comment/keys.ts @@ -2,8 +2,8 @@ import type { CommentGetParameters } from '@/api-clients/opsflow/comment/schema/ import type { CommentListParameters } from '@/api-clients/opsflow/comment/schema/api-verbs/list'; export const commentKeys = { - all: ['comment'], - list: (params: CommentListParameters) => [...commentKeys.all, 'list', params], - get: (idParam: CommentGetParameters['comment_id']) => [...commentKeys.all, 'get', idParam], + all: ['comment'] as const, + list: (params: CommentListParameters) => [...commentKeys.all, 'list', params] as const, + get: (idParam: CommentGetParameters['comment_id']) => [...commentKeys.all, 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/opsflow/event/keys.ts b/apps/web/src/api-clients/opsflow/event/keys.ts index 2d03f6f12c..4c5a86b41f 100644 --- a/apps/web/src/api-clients/opsflow/event/keys.ts +++ b/apps/web/src/api-clients/opsflow/event/keys.ts @@ -1,7 +1,7 @@ import type { EventListParameters } from '@/api-clients/opsflow/event/schema/api-verbs/list'; export const eventKeys = { - all: ['event'], - list: (params: EventListParameters) => [...eventKeys.all, 'list', params], + all: ['event'] as const, + list: (params: EventListParameters) => [...eventKeys.all, 'list', params] as const, }; diff --git a/apps/web/src/api-clients/opsflow/task-category/keys.ts b/apps/web/src/api-clients/opsflow/task-category/keys.ts index 4686dab116..91b8637cd7 100644 --- a/apps/web/src/api-clients/opsflow/task-category/keys.ts +++ b/apps/web/src/api-clients/opsflow/task-category/keys.ts @@ -2,8 +2,8 @@ import type { TaskCategoryGetParameters } from '@/api-clients/opsflow/task-categ import type { TaskCategoryListParameters } from '@/api-clients/opsflow/task-category/schema/api-verbs/list'; export const taskCategoryKeys = { - all: ['task-category'], - list: (params: TaskCategoryListParameters) => [...taskCategoryKeys.all, 'list', params], - get: (idParam: TaskCategoryGetParameters['category_id']) => [...taskCategoryKeys.all, 'get', idParam], + all: ['task-category'] as const, + list: (params: TaskCategoryListParameters) => [...taskCategoryKeys.all, 'list', params] as const, + get: (idParam: TaskCategoryGetParameters['category_id']) => [...taskCategoryKeys.all, 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/opsflow/task-type/keys.ts b/apps/web/src/api-clients/opsflow/task-type/keys.ts index 1c970cc2d4..a728047557 100644 --- a/apps/web/src/api-clients/opsflow/task-type/keys.ts +++ b/apps/web/src/api-clients/opsflow/task-type/keys.ts @@ -2,8 +2,8 @@ import type { TaskTypeGetParameters } from '@/api-clients/opsflow/task-type/sche import type { TaskTypeListParameters } from '@/api-clients/opsflow/task-type/schema/api-verbs/list'; export const taskTypeKeys = { - all: ['task-type'], - list: (params: TaskTypeListParameters) => [...taskTypeKeys.all, 'list', params], - get: (idParam: TaskTypeGetParameters['task_type_id']) => [...taskTypeKeys.all, 'get', idParam], + all: ['task-type'] as const, + list: (params: TaskTypeListParameters) => [...taskTypeKeys.all, 'list', params] as const, + get: (idParam: TaskTypeGetParameters['task_type_id']) => [...taskTypeKeys.all, 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/opsflow/task/keys.ts b/apps/web/src/api-clients/opsflow/task/keys.ts index dec8dcea27..9bb49c3dbe 100644 --- a/apps/web/src/api-clients/opsflow/task/keys.ts +++ b/apps/web/src/api-clients/opsflow/task/keys.ts @@ -2,8 +2,8 @@ import type { TaskGetParameters } from '@/api-clients/opsflow/task/schema/api-ve import type { TaskListParameters } from '@/api-clients/opsflow/task/schema/api-verbs/list'; export const taskKeys = { - all: ['task'], - list: (params: TaskListParameters) => [...taskKeys.all, 'list', params], - get: (idParam: TaskGetParameters['task_id']) => [...taskKeys.all, 'get', idParam], + all: ['task'] as const, + list: (params: TaskListParameters) => [...taskKeys.all, 'list', params] as const, + get: (idParam: TaskGetParameters['task_id']) => [...taskKeys.all, 'get', idParam] as const, }; From edba5e0701604bd767f40dca1d6119e62238f211 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Fri, 21 Mar 2025 15:37:48 +0900 Subject: [PATCH 19/20] chore: remove all index in resource keys Signed-off-by: samuel.park --- .../src/api-clients/dashboard/private-dashboard/keys.ts | 7 ++++--- .../src/api-clients/dashboard/private-data-table/keys.ts | 7 +++---- .../web/src/api-clients/dashboard/private-folder/keys.ts | 5 ++--- .../web/src/api-clients/dashboard/private-widget/keys.ts | 9 ++++----- .../src/api-clients/dashboard/public-dashboard/keys.ts | 5 ++--- .../src/api-clients/dashboard/public-data-table/keys.ts | 7 +++---- apps/web/src/api-clients/dashboard/public-folder/keys.ts | 5 ++--- apps/web/src/api-clients/dashboard/public-widget/keys.ts | 9 ++++----- apps/web/src/api-clients/opsflow/comment/keys.ts | 5 ++--- apps/web/src/api-clients/opsflow/event/keys.ts | 3 +-- apps/web/src/api-clients/opsflow/task-category/keys.ts | 5 ++--- apps/web/src/api-clients/opsflow/task-type/keys.ts | 5 ++--- apps/web/src/api-clients/opsflow/task/keys.ts | 5 ++--- 13 files changed, 33 insertions(+), 44 deletions(-) diff --git a/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts b/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts index a7cfda6d86..25d1828adc 100644 --- a/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts +++ b/apps/web/src/api-clients/dashboard/private-dashboard/keys.ts @@ -1,8 +1,9 @@ import type { PrivateDashboardGetParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/get'; import type { PrivateDashboardListParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/list'; + + export const privateDashboardKeys = { - all: ['private-dashboard'] as const, - list: (params: PrivateDashboardListParameters) => [...privateDashboardKeys.all, 'list', params] as const, - get: (idParam: PrivateDashboardGetParameters['dashboard_id']) => [...privateDashboardKeys.all, 'get', idParam] as const, + list: (params: PrivateDashboardListParameters) => ['private-dashboard', 'list', params] as const, + get: (idParam: PrivateDashboardGetParameters['dashboard_id']) => ['private-dashboard', 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/private-data-table/keys.ts b/apps/web/src/api-clients/dashboard/private-data-table/keys.ts index 3e56601bca..f60d01e88d 100644 --- a/apps/web/src/api-clients/dashboard/private-data-table/keys.ts +++ b/apps/web/src/api-clients/dashboard/private-data-table/keys.ts @@ -3,8 +3,7 @@ import type { DataTableListParameters } from '@/api-clients/dashboard/private-da import type { DataTableLoadParameters } from '@/api-clients/dashboard/private-data-table/schema/api-verbs/load'; export const privateDataTableKeys = { - all: ['private-data-table'] as const, - list: (params: DataTableListParameters) => [...privateDataTableKeys.all, 'list', params] as const, - get: (idParam: DataTableGetParameters['data_table_id']) => [...privateDataTableKeys.all, 'get', idParam] as const, - load: (idParam: DataTableLoadParameters['data_table_id']) => [...privateDataTableKeys.all, 'load', idParam] as const, + list: (params: DataTableListParameters) => ['private-data-table', 'list', params] as const, + get: (idParam: DataTableGetParameters['data_table_id']) => ['private-data-table', 'get', idParam] as const, + load: (idParam: DataTableLoadParameters['data_table_id']) => ['private-data-table', 'load', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/private-folder/keys.ts b/apps/web/src/api-clients/dashboard/private-folder/keys.ts index 17aeec4cf4..83d9236d8d 100644 --- a/apps/web/src/api-clients/dashboard/private-folder/keys.ts +++ b/apps/web/src/api-clients/dashboard/private-folder/keys.ts @@ -2,7 +2,6 @@ import type { PrivateFolderGetParameters } from '@/api-clients/dashboard/private import type { PrivateFolderListParameters } from '@/api-clients/dashboard/private-folder/schema/api-verbs/list'; export const privateFolderKeys = { - all: ['private-folder'] as const, - list: (params: PrivateFolderListParameters) => [...privateFolderKeys.all, 'list', params] as const, - get: (idParam: PrivateFolderGetParameters['folder_id']) => [...privateFolderKeys.all, 'get', idParam] as const, + list: (params: PrivateFolderListParameters) => ['private-folder', 'list', params] as const, + get: (idParam: PrivateFolderGetParameters['folder_id']) => ['private-folder', 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/private-widget/keys.ts b/apps/web/src/api-clients/dashboard/private-widget/keys.ts index e96d9b161c..14479b4b11 100644 --- a/apps/web/src/api-clients/dashboard/private-widget/keys.ts +++ b/apps/web/src/api-clients/dashboard/private-widget/keys.ts @@ -4,9 +4,8 @@ import type { PrivateWidgetLoadParameters } from '@/api-clients/dashboard/privat import type { PrivateWidgetLoadSumParameters } from '@/api-clients/dashboard/private-widget/schema/api-verbs/load-sum'; export const privateWidgetKeys = { - all: ['private-widget'] as const, - list: (params: PrivateWidgetListParameters) => [...privateWidgetKeys.all, 'list', params] as const, - get: (idParam: PrivateWidgetGetParameters['widget_id']) => [...privateWidgetKeys.all, 'get', idParam] as const, - load: (idParam: PrivateWidgetLoadParameters['widget_id']) => [...privateWidgetKeys.all, 'load', idParam] as const, - loadSum: (idParam: PrivateWidgetLoadSumParameters['widget_id']) => [...privateWidgetKeys.all, 'load-sum', idParam] as const, + list: (params: PrivateWidgetListParameters) => ['private-widget', 'list', params] as const, + get: (idParam: PrivateWidgetGetParameters['widget_id']) => ['private-widget', 'get', idParam] as const, + load: (idParam: PrivateWidgetLoadParameters['widget_id']) => ['private-widget', 'load', idParam] as const, + loadSum: (idParam: PrivateWidgetLoadSumParameters['widget_id']) => ['private-widget', 'load-sum', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts b/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts index 7de67a7d72..36f5611bf3 100644 --- a/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts +++ b/apps/web/src/api-clients/dashboard/public-dashboard/keys.ts @@ -2,7 +2,6 @@ import type { PublicDashboardGetParameters } from '@/api-clients/dashboard/publi import type { PublicDashboardListParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/list'; export const publicDashboardKeys = { - all: ['public-dashboard'] as const, - list: (params: PublicDashboardListParameters) => [...publicDashboardKeys.all, 'list', params] as const, - get: (idParam: PublicDashboardGetParameters['dashboard_id']) => [...publicDashboardKeys.all, 'get', idParam] as const, + list: (params: PublicDashboardListParameters) => ['public-dashboard', 'list', params] as const, + get: (idParam: PublicDashboardGetParameters['dashboard_id']) => ['public-dashboard', 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/public-data-table/keys.ts b/apps/web/src/api-clients/dashboard/public-data-table/keys.ts index b21c4803d2..ce17c1f617 100644 --- a/apps/web/src/api-clients/dashboard/public-data-table/keys.ts +++ b/apps/web/src/api-clients/dashboard/public-data-table/keys.ts @@ -3,8 +3,7 @@ import type { DataTableListParameters } from '@/api-clients/dashboard/public-dat import type { DataTableLoadParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/load'; export const publicDataTableKeys = { - all: ['public-data-table'] as const, - list: (params: DataTableListParameters) => [...publicDataTableKeys.all, 'list', params] as const, - get: (idParam: DataTableGetParameters['data_table_id']) => [...publicDataTableKeys.all, 'get', idParam] as const, - load: (idParam: DataTableLoadParameters['data_table_id']) => [...publicDataTableKeys.all, 'load', idParam] as const, + list: (params: DataTableListParameters) => ['public-data-table', 'list', params] as const, + get: (idParam: DataTableGetParameters['data_table_id']) => ['public-data-table', 'get', idParam] as const, + load: (idParam: DataTableLoadParameters['data_table_id']) => ['public-data-table', 'load', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/public-folder/keys.ts b/apps/web/src/api-clients/dashboard/public-folder/keys.ts index 207357b2ec..49ca9a3931 100644 --- a/apps/web/src/api-clients/dashboard/public-folder/keys.ts +++ b/apps/web/src/api-clients/dashboard/public-folder/keys.ts @@ -2,7 +2,6 @@ import type { PublicFolderGetParameters } from '@/api-clients/dashboard/public-f import type { PublicFolderListParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/list'; export const publicFolderKeys = { - all: ['public-folder'] as const, - list: (params: PublicFolderListParameters) => [...publicFolderKeys.all, 'list', params] as const, - get: (idParam: PublicFolderGetParameters['folder_id']) => [...publicFolderKeys.all, 'get', idParam] as const, + list: (params: PublicFolderListParameters) => ['public-folder', 'list', params] as const, + get: (idParam: PublicFolderGetParameters['folder_id']) => ['public-folder', 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/dashboard/public-widget/keys.ts b/apps/web/src/api-clients/dashboard/public-widget/keys.ts index 6cff69946a..01981f58c5 100644 --- a/apps/web/src/api-clients/dashboard/public-widget/keys.ts +++ b/apps/web/src/api-clients/dashboard/public-widget/keys.ts @@ -4,9 +4,8 @@ import type { PublicWidgetLoadParameters } from '@/api-clients/dashboard/public- import type { PublicWidgetLoadSumParameters } from '@/api-clients/dashboard/public-widget/schema/api-verbs/load-sum'; export const publicWidgetKeys = { - all: ['public-widget'] as const, - list: (params: PublicWidgetListParameters) => [...publicWidgetKeys.all, 'list', params] as const, - get: (idParam: PublicWidgetGetParameters['widget_id']) => [...publicWidgetKeys.all, 'get', idParam] as const, - load: (idParam: PublicWidgetLoadParameters['widget_id']) => [...publicWidgetKeys.all, 'load', idParam] as const, - loadSum: (idParam: PublicWidgetLoadSumParameters['widget_id']) => [...publicWidgetKeys.all, 'load-sum', idParam] as const, + list: (params: PublicWidgetListParameters) => ['public-widget', 'list', params] as const, + get: (idParam: PublicWidgetGetParameters['widget_id']) => ['public-widget', 'get', idParam] as const, + load: (idParam: PublicWidgetLoadParameters['widget_id']) => ['public-widget', 'load', idParam] as const, + loadSum: (idParam: PublicWidgetLoadSumParameters['widget_id']) => ['public-widget', 'load-sum', idParam] as const, }; diff --git a/apps/web/src/api-clients/opsflow/comment/keys.ts b/apps/web/src/api-clients/opsflow/comment/keys.ts index d29c72d797..80878c2455 100644 --- a/apps/web/src/api-clients/opsflow/comment/keys.ts +++ b/apps/web/src/api-clients/opsflow/comment/keys.ts @@ -2,8 +2,7 @@ import type { CommentGetParameters } from '@/api-clients/opsflow/comment/schema/ import type { CommentListParameters } from '@/api-clients/opsflow/comment/schema/api-verbs/list'; export const commentKeys = { - all: ['comment'] as const, - list: (params: CommentListParameters) => [...commentKeys.all, 'list', params] as const, - get: (idParam: CommentGetParameters['comment_id']) => [...commentKeys.all, 'get', idParam] as const, + list: (params: CommentListParameters) => ['comment', 'list', params] as const, + get: (idParam: CommentGetParameters['comment_id']) => ['comment', 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/opsflow/event/keys.ts b/apps/web/src/api-clients/opsflow/event/keys.ts index 4c5a86b41f..f3dd352a10 100644 --- a/apps/web/src/api-clients/opsflow/event/keys.ts +++ b/apps/web/src/api-clients/opsflow/event/keys.ts @@ -1,7 +1,6 @@ import type { EventListParameters } from '@/api-clients/opsflow/event/schema/api-verbs/list'; export const eventKeys = { - all: ['event'] as const, - list: (params: EventListParameters) => [...eventKeys.all, 'list', params] as const, + list: (params: EventListParameters) => ['event', 'list', params] as const, }; diff --git a/apps/web/src/api-clients/opsflow/task-category/keys.ts b/apps/web/src/api-clients/opsflow/task-category/keys.ts index 91b8637cd7..624f6ed709 100644 --- a/apps/web/src/api-clients/opsflow/task-category/keys.ts +++ b/apps/web/src/api-clients/opsflow/task-category/keys.ts @@ -2,8 +2,7 @@ import type { TaskCategoryGetParameters } from '@/api-clients/opsflow/task-categ import type { TaskCategoryListParameters } from '@/api-clients/opsflow/task-category/schema/api-verbs/list'; export const taskCategoryKeys = { - all: ['task-category'] as const, - list: (params: TaskCategoryListParameters) => [...taskCategoryKeys.all, 'list', params] as const, - get: (idParam: TaskCategoryGetParameters['category_id']) => [...taskCategoryKeys.all, 'get', idParam] as const, + list: (params: TaskCategoryListParameters) => ['task-category', 'list', params] as const, + get: (idParam: TaskCategoryGetParameters['category_id']) => ['task-category', 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/opsflow/task-type/keys.ts b/apps/web/src/api-clients/opsflow/task-type/keys.ts index a728047557..f5c5473eeb 100644 --- a/apps/web/src/api-clients/opsflow/task-type/keys.ts +++ b/apps/web/src/api-clients/opsflow/task-type/keys.ts @@ -2,8 +2,7 @@ import type { TaskTypeGetParameters } from '@/api-clients/opsflow/task-type/sche import type { TaskTypeListParameters } from '@/api-clients/opsflow/task-type/schema/api-verbs/list'; export const taskTypeKeys = { - all: ['task-type'] as const, - list: (params: TaskTypeListParameters) => [...taskTypeKeys.all, 'list', params] as const, - get: (idParam: TaskTypeGetParameters['task_type_id']) => [...taskTypeKeys.all, 'get', idParam] as const, + list: (params: TaskTypeListParameters) => ['task-type', 'list', params] as const, + get: (idParam: TaskTypeGetParameters['task_type_id']) => ['task-type', 'get', idParam] as const, }; diff --git a/apps/web/src/api-clients/opsflow/task/keys.ts b/apps/web/src/api-clients/opsflow/task/keys.ts index 9bb49c3dbe..201d6996fb 100644 --- a/apps/web/src/api-clients/opsflow/task/keys.ts +++ b/apps/web/src/api-clients/opsflow/task/keys.ts @@ -2,8 +2,7 @@ import type { TaskGetParameters } from '@/api-clients/opsflow/task/schema/api-ve import type { TaskListParameters } from '@/api-clients/opsflow/task/schema/api-verbs/list'; export const taskKeys = { - all: ['task'] as const, - list: (params: TaskListParameters) => [...taskKeys.all, 'list', params] as const, - get: (idParam: TaskGetParameters['task_id']) => [...taskKeys.all, 'get', idParam] as const, + list: (params: TaskListParameters) => ['task', 'list', params] as const, + get: (idParam: TaskGetParameters['task_id']) => ['task', 'get', idParam] as const, }; From 80bf23fc79442d00bb05a0308aa74f261c5922c2 Mon Sep 17 00:00:00 2001 From: Yongtae Park Date: Fri, 21 Mar 2025 15:39:26 +0900 Subject: [PATCH 20/20] feat(use-api-query-key): optimize composable performance Signed-off-by: samuel.park --- .gitignore | 1 + .../_common/composables/use-api-query-key.ts | 105 +++++++----------- 2 files changed, 42 insertions(+), 64 deletions(-) diff --git a/.gitignore b/.gitignore index 49eba67df9..e557c2d0c6 100755 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ node_modules.nosync/ # Dev tools .DS_Store .vscode +.cursor .idea *.swp *.bak diff --git a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts index 0d0d556bea..1eb55742ab 100644 --- a/apps/web/src/api-clients/_common/composables/use-api-query-key.ts +++ b/apps/web/src/api-clients/_common/composables/use-api-query-key.ts @@ -22,14 +22,11 @@ type ExtractParams = T extends (params: infer P) => any ? P : never; type VerbFunction = { (params?: ExtractParams): QueryKeyArrayWithDep; - addDep: (deps: Record) => QueryKeyArray; }; -type MapVerbToReturnType = T extends QueryKeyArray - ? QueryKeyArray - : T extends (params: any) => any - ? VerbFunction - : never; +type MapVerbToReturnType = T extends (params: any) => any + ? VerbFunction + : never; type UseAPIQueryResult = { [S in APIQueryKeyMapService]: { @@ -39,72 +36,52 @@ type UseAPIQueryResult = { }; }; -type APIQueryKeyValue = QueryKeyArray | ((params?: Record) => QueryKeyArray); +type APIQueryKeyValue = (params?: Record) => QueryKeyArray; + export const _useAPIQueryKey = (): ComputedRef => { const queryKeyAppContext = useQueryKeyAppContext('service'); - - return computed(() => { - const createKeyWithContext = (queryKeyValue: T): MapVerbToReturnType => { - if (Array.isArray(queryKeyValue)) { - return [ - ...queryKeyAppContext.value, - ...createImmutableObject(queryKeyValue), - ] as MapVerbToReturnType; - } - - const verbFunction = (params?: ExtractParams) => { - const baseKey = queryKeyValue(params); - const result = [ - ...queryKeyAppContext.value, - ...createImmutableObject(baseKey), - ] as QueryKeyArrayWithDep; - result.addDep = (deps) => [ - ...queryKeyAppContext.value, - ...createImmutableObject(baseKey), - createImmutableObject(deps), - ]; - return result; - }; - - verbFunction.addDep = (deps) => [ - ...queryKeyAppContext.value, - ...createImmutableObject(queryKeyValue()), - createImmutableObject(deps), - ]; - return verbFunction as MapVerbToReturnType; - }; - - return Object.entries(API_QUERY_KEY_MAP).reduce((services, [serviceName, resources]) => ({ - ...services, - [serviceName]: Object.entries(resources).reduce((resourceMap, [resourceName, verbs]) => ({ - ...resourceMap, - [resourceName]: Object.entries(verbs).reduce((verbMap, [verb, queryKeyValue]) => ({ - ...verbMap, - [verb]: createKeyWithContext(queryKeyValue as APIQueryKeyValue), - }), {}), - }), {}), - }), {} as UseAPIQueryResult); - }); + const globalContext = computed(() => queryKeyAppContext.value); + + + const apiStructure = Object.entries(API_QUERY_KEY_MAP).reduce>((result, [serviceName, resources]) => { + result[serviceName as APIQueryKeyMapService] = Object.entries(resources).reduce((resourceResult, [resourceName, verbs]) => { + resourceResult[resourceName] = Object.entries(verbs).reduce((verbResult, [verb, queryKeyValue]) => { + const staticKey = createImmutableObject([serviceName, resourceName, verb]); + + const verbFunction = (params?: ExtractParams) => { + const baseKey = computed(() => (queryKeyValue as T)(params)); + const queryKey = [ + ...globalContext.value, + ...staticKey, + ...createImmutableObject(baseKey.value), + ] as QueryKeyArray; + + (queryKey as QueryKeyArrayWithDep).addDep = (deps: Record): QueryKeyArray => [ + ...globalContext.value, + ...staticKey, + ...createImmutableObject(baseKey.value), + createImmutableObject(deps), + ]; + + return queryKey as QueryKeyArrayWithDep; + }; + + verbResult[verb] = verbFunction; + return verbResult; + }, {}); + return resourceResult; + }, {}); + return result; + }, {} as Record); + + + return computed(() => apiStructure as UseAPIQueryResult); }; - - - - - - - - - - - - - - interface GlobalQueryParams { workspaceId?: string; isAdminMode?: boolean;