diff --git a/.cursor/rules/generate-new-api-clients.mdc b/.cursor/rules/generate-new-api-clients.mdc new file mode 100644 index 0000000000..bda27fc799 --- /dev/null +++ b/.cursor/rules/generate-new-api-clients.mdc @@ -0,0 +1,138 @@ +--- +description: +globs: +alwaysApply: false +--- + + +## Directory Structure +``` +api-clients/ +├── _common/ +│ ├── composables/ +│ │ └── use-api-query-key.ts +│ └── schema/ +│ ├── api-verbs/ +│ └── model.ts +└── {service-name}/ + ├── {resource}/ + │ ├── composables/ + │ │ └── use-{resource}-api.ts + │ └── schema/ + │ ├── api-verbs/ + │ │ ├── {verb}.ts + │ └── model.ts + └── index.ts +``` + +## API Client Composable Template +```typescript +// use-{resource}-api.ts template +import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; + +import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; +import type { {Resource}{Verb}Parameters } from '@/api-clients/{service}/{resource}/schema/api-verbs/{verb}'; +import type { {Resource}{Verb = list}Parameters } from '@/api-clients/{service}/{resource}/schema/api-verbs/list'; +import type { {Resource}Model } from '@/api-clients/{service}/{resource}/schema/model'; + +export const use{Resource}Api = () => { + // Define API actions + const actions = { + {verb}: SpaceConnector.clientV2.{service}.{resource}.{verb}<{Resource}{Verb}Parameters, {Resource}Model>, + {verb = list}: SpaceConnector.clientV2.{service}.{resource}.list<{Resource}ListParameters, ListResponse<{Resource}Model>>, + // ... other actions + }; + + return { + {resource}API: actions, + }; +}; +``` + +## Schema Templates + +### Model Definition +```typescript +// model.ts template +export interface {Resource}Model { + // Define resource properties + resource_id: string; + name: string; + // ... other properties +} +``` + +### API Verb Parameters +```typescript +// create.ts template example +export interface {Resource}CreateParameters { + // Define create operation parameters + name: string; + // ... other parameters +} + +// list.ts template example +export interface {Resource}ListParameters { + query?: { + filter?: Array<{ + k: string; + v: any; + o: string; + }>; + // ... other query parameters + }; +} +``` + +## Usage Rules + +1. **Naming Conventions** + - Use PascalCase for interface names: `{Resource}Model`, `{Resource}{Verb}Parameters` + - Use camelCase for variables and functions: `use{Resource}Api` + - Follow existing naming patterns in the codebase + +2. **Type Safety** + - Always define proper TypeScript interfaces for all parameters and responses + - Use generics with SpaceConnector client methods + - Define all possible API parameters in schema files + +3. **Query Key Management** + - Use `useAPIQueryKey` for generating consistent query keys + - Create separate query keys for different operations + - Include contextual information in query keys when needed + +4. **Code Organization** + - Keep schema definitions separate from API logic + - Group related files in appropriate directories + - Follow the established directory structure + +5. **Documentation** + - Add JSDoc comments for public interfaces and functions + - Document any special behaviors or requirements + - Include examples for complex parameter structures + +## Example Usage in Components +```typescript +const { {resource}API } = use{Resource}Api(); + +const { key, params } = useServiceQueryKey(service, resource, verb, { + params: ... +}) + +// In composables +const query = useScopedQuery({ + queryKey: {resource}QueryKey.value, + queryFn: () => {resource}API.{verb}(params.value), + // ... other options +}, ['WORKSPACE', 'ADMIN']); +``` + +## Notes +- Always check existing API clients for consistent patterns +- Consider reusability and maintainability +- Follow the service's API documentation for accurate parameter definitions +- Use appropriate error handling and loading states +- Consider implementing proper caching strategies +- Add comments only when it is really complex. (English only) + + diff --git a/.gitignore b/.gitignore index 49eba67df9..66fa09c87b 100755 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,10 @@ node_modules.nosync/ *.swp *.bak +## Cursor rules : Ignore all files in .cursor directory except specific file (rules) +.cursor/* +!.cursor/generate-new-api-clients.mdc + # Turborepo .turbo out/ diff --git a/apps/mirinae-storybook/mock/vue-router-composables.ts b/apps/mirinae-storybook/mock/vue-router-composables.ts new file mode 100644 index 0000000000..4e9b024ed2 --- /dev/null +++ b/apps/mirinae-storybook/mock/vue-router-composables.ts @@ -0,0 +1,22 @@ +export const useRoute = () => ({ + path: '', + hash: '', + query: {}, + params: {}, + fullPath: '', + matched: [], +}); + +export const useRouter = () => ({ + resolve() { + return { + resolved: { + path: '/', + hash: '#', + matched: [], + name: '', + params: {}, + }, + }; + }, +}); diff --git a/apps/mirinae-storybook/vite.config.js b/apps/mirinae-storybook/vite.config.js index 78030bbc64..10efd18cd2 100644 --- a/apps/mirinae-storybook/vite.config.js +++ b/apps/mirinae-storybook/vite.config.js @@ -12,6 +12,7 @@ export default defineConfig({ alias: { '@': path.resolve(__dirname, '../../packages/mirinae/src'), 'vue/dist/vue.esm': path.resolve(__dirname, '../../node_modules/vue/dist/vue.esm.js'), + 'vue-router/composables': path.resolve(__dirname, './mock/vue-router-composables.ts'), }, }, optimizeDeps: { diff --git a/apps/web/package.json b/apps/web/package.json index e9edabb40f..d90a5d0560 100644 --- a/apps/web/package.json +++ b/apps/web/package.json @@ -112,7 +112,7 @@ "postcss-config-custom": "*", "rollup-plugin-visualizer": "^5.9.0", "tsconfig": "*", - "vite": "^4.5.11", + "vite": "^4.5.13", "vite-plugin-stylelint": "^3.3.3", "vite-plugin-vue-type-imports": "^0.2.4", "vitest": "^3.0.8", 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 deleted file mode 100644 index 0077392792..0000000000 --- a/apps/web/src/api-clients/_common/composables/use-scoped-query.ts +++ /dev/null @@ -1,81 +0,0 @@ -// eslint-disable-next-line @typescript-eslint/ban-ts-comment -// @ts-nocheck -/** - * useScopedQuery - A custom wrapper around `useQuery` to enforce scope-based API fetching. - * - * ## Why this hook exists? - * This hook was created to integrate **scope-based API access control** with Vue Query. - * It ensures that queries are only executed when the user's granted scope matches the required scope. - * Additionally, it automatically handles loading states and prevents unnecessary queries. - * - * ## 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. - * - Supports both **static and reactive `enabled` values**. - * - * ## Parameters: - * - `options`: Standard **Vue Query options** (`UseQueryOptions`). - * - `requiredScopes`: A list of **required grant scopes** to determine if the query should execute. - * - * ## Supported Query Options: - * The following options are commonly used within our team: - * - `queryKey`: **Unique key** to identify the query in the cache. - * - `queryFn`: **Function** to fetch data from the API. - * - `select`: **Transform function** to modify response data. - * - `initialData`: **Default value** for the query when no data is available. - * - `staleTime`: **Cache duration** before the query becomes stale. - * - `enabled`: **Boolean or reactive ref** to control when the query should execute. - * - * ## Example Usage: - * - * const myQuery = useScopedQuery({ - * queryKey: ['dashboard', dashboardId], - * queryFn: () => fetchDashboardData(dashboardId), - * select: (data) => data.results, - * initialData: { results: [] }, - * staleTime: 1000 * 60 * 5, // 5 minutes - * enabled: computed(() => isUserAuthorized.value), - * }, ['DOMAIN', 'WORKSPACE']); - * - */ - - -import type { MaybeRef } from '@vueuse/core'; -import { toValue } from '@vueuse/core'; -import { computed, reactive } from 'vue'; - -import type { - UseQueryOptions, -} from '@tanstack/vue-query'; -import { useQuery } from '@tanstack/vue-query'; - -import type { GrantScope } from '@/api-clients/identity/token/schema/type'; - -import { useAppContextStore } from '@/store/app-context/app-context-store'; -import { useUserStore } from '@/store/user/user-store'; - -export const useScopedQuery = ( - options: UseQueryOptions, - 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 queryEnabled = computed(() => { - const _inheritedEnabled = options?.enabled as MaybeRef | undefined; - if (_inheritedEnabled !== undefined && !toValue(_inheritedEnabled)) return false; - return _state.isValidScope && !_state.isLoading; - }); - - return useQuery({ - ...options, - enabled: queryEnabled, - }); -}; diff --git a/apps/web/src/api-clients/_common/constants/api-doc-constant.ts b/apps/web/src/api-clients/_common/constants/api-doc-constant.ts index 91b5b092a1..4f1340d26f 100644 --- a/apps/web/src/api-clients/_common/constants/api-doc-constant.ts +++ b/apps/web/src/api-clients/_common/constants/api-doc-constant.ts @@ -376,6 +376,11 @@ export const API_DOC = { 'list', ], }, + inventory: { + 'metric-data': [ + 'analyze', + ], + }, opsflow: { comment: [ 'create', @@ -413,5 +418,11 @@ export const API_DOC = { 'update', ], }, + repository: { + 'dashboard-template': [ + 'list', + 'register', + ], + }, } as const; export type APIDoc = typeof API_DOC; diff --git a/apps/web/src/api-clients/cost-analysis/budget-usage/schema/api-verbs/analyze.ts b/apps/web/src/api-clients/cost-analysis/budget-usage/schema/api-verbs/analyze.ts index 4c68386e74..65641c9de9 100644 --- a/apps/web/src/api-clients/cost-analysis/budget-usage/schema/api-verbs/analyze.ts +++ b/apps/web/src/api-clients/cost-analysis/budget-usage/schema/api-verbs/analyze.ts @@ -18,9 +18,9 @@ export interface BudgetUsageAnalyzeResult { project_id?: string; workspace_id?: string; data_source_id?: string; - provider_filter?: { - state?: string; - providers?: string[]; - }; + // provider_filter?: { + // state?: string; + // providers?: string[]; + // }; resource_group: Extract; } diff --git a/apps/web/src/api-clients/cost-analysis/budget-usage/schema/api-verbs/list.ts b/apps/web/src/api-clients/cost-analysis/budget-usage/schema/api-verbs/list.ts index 5a4111eaeb..0a082cdf65 100644 --- a/apps/web/src/api-clients/cost-analysis/budget-usage/schema/api-verbs/list.ts +++ b/apps/web/src/api-clients/cost-analysis/budget-usage/schema/api-verbs/list.ts @@ -9,4 +9,5 @@ export interface BudgetUsageListParameters { data_source_id?: string; workspace_id?: string; project_id?: string; + service_account_id?: string; } diff --git a/apps/web/src/api-clients/cost-analysis/budget-usage/schema/model.ts b/apps/web/src/api-clients/cost-analysis/budget-usage/schema/model.ts index 099704073c..7031ca1fdb 100644 --- a/apps/web/src/api-clients/cost-analysis/budget-usage/schema/model.ts +++ b/apps/web/src/api-clients/cost-analysis/budget-usage/schema/model.ts @@ -3,10 +3,10 @@ import type { ResourceGroupType } from '@/api-clients/_common/schema/type'; import type { Currency } from '@/store/display/type'; -interface ProviderFilter { - providers: string[]; - state: 'ENABLED' | 'DISABLED'; -} +// interface ProviderFilter { +// providers: string[]; +// state: 'ENABLED' | 'DISABLED'; +// } export interface BudgetUsageModel { budget_id: string; @@ -15,11 +15,11 @@ export interface BudgetUsageModel { cost: number; limit: number; currency: Currency; - provider_filter?: ProviderFilter; data_source_id: string; resource_group: Extract; project_id: string; workspace_id: string; + service_account_id: string; domain_id: string; updated_at: string; } diff --git a/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/create.ts b/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/create.ts index 23f7c15dfd..1f4083e1ab 100644 --- a/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/create.ts +++ b/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/create.ts @@ -1,21 +1,24 @@ import type { Tags } from '@/api-clients/_common/schema/model'; import type { ResourceGroupType } from '@/api-clients/_common/schema/type'; import type { - BudgetNotification, BudgetPlannedLimit, BudgetTimeUnit, ProviderFilter, + BudgetNotification, BudgetPlannedLimit, BudgetTimeUnit, } from '@/api-clients/cost-analysis/budget/schema/type'; +import type { Currency } from '@/store/display/type'; + export interface BudgetCreateParameters { - data_source_id: string; name?: string; limit?: number; planned_limits?: BudgetPlannedLimit[]; - provider_filter?: ProviderFilter; + currency: Currency; time_unit: BudgetTimeUnit; start: string; end: string; - notifications?: BudgetNotification[]; + notification?: BudgetNotification; tags?: Tags; resource_group: Extract; workspace_id?: string; project_id?: string; + service_account_id?: string; + budget_manager_id?: string; } diff --git a/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/set-notification.ts b/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/set-notification.ts index 050fac8446..78a5737f97 100644 --- a/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/set-notification.ts +++ b/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/set-notification.ts @@ -2,5 +2,5 @@ import type { BudgetNotification } from '@/api-clients/cost-analysis/budget/sche export interface BudgetSetNotificationParameters { budget_id: string; - notifications: BudgetNotification[]; + notification: BudgetNotification; } diff --git a/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/update.ts b/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/update.ts index eebbefe2f3..a12da39dcf 100644 --- a/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/update.ts +++ b/apps/web/src/api-clients/cost-analysis/budget/schema/api-verbs/update.ts @@ -6,5 +6,8 @@ export interface BudgetUpdateParameters { name?: string; limit?: number; planned_limits?: BudgetPlannedLimit[]; + start?: string; + end?: string; + utilization_rate?: number; tags?: Tags; } diff --git a/apps/web/src/api-clients/cost-analysis/budget/schema/model.ts b/apps/web/src/api-clients/cost-analysis/budget/schema/model.ts index 0ad8166b9d..0914af4cf6 100644 --- a/apps/web/src/api-clients/cost-analysis/budget/schema/model.ts +++ b/apps/web/src/api-clients/cost-analysis/budget/schema/model.ts @@ -1,29 +1,36 @@ + import type { Tags } from '@/api-clients/_common/schema/model'; import type { ResourceGroupType } from '@/api-clients/_common/schema/type'; import type { - BudgetNotification, BudgetPlannedLimit, BudgetTimeUnit, ProviderFilter, + BudgetNotification, + BudgetPlannedLimit, + BudgetState, + BudgetTimeUnit, } from '@/api-clients/cost-analysis/budget/schema/type'; import type { Currency } from '@/store/display/type'; - export interface BudgetModel { - budget_id: string; - name: string; - limit: number; - planned_limits: BudgetPlannedLimit[]; - currency: Currency; - provider_filter: ProviderFilter; - time_unit: BudgetTimeUnit; - start: string; - end: string; - notifications: BudgetNotification[]; - tags: Tags; - data_source_id: string; - resource_group: Extract - project_id: string; - workspace_id: string; - domain_id: string; - created_at: string; - updated_at: string; + budget_id: string; + name: string; + limit: number; + planned_limits: BudgetPlannedLimit[]; + currency: Currency; + time_unit: BudgetTimeUnit; + start: string; + end: string; + notification: BudgetNotification; + tags: Tags; + data_source_id: string; + resource_group: Extract; + project_id: string; + workspace_id: string; + service_account_id: string; + budget_manager_id: string; + domain_id: string; + created_at: string; + updated_at: string; + notified_month: string; + utilization_rate: number; + state: BudgetState; } diff --git a/apps/web/src/api-clients/cost-analysis/budget/schema/type.ts b/apps/web/src/api-clients/cost-analysis/budget/schema/type.ts index 65bd3a42cb..ad24146ebc 100644 --- a/apps/web/src/api-clients/cost-analysis/budget/schema/type.ts +++ b/apps/web/src/api-clients/cost-analysis/budget/schema/type.ts @@ -1,11 +1,21 @@ export type BudgetTimeUnit = 'MONTHLY' | 'TOTAL'; -type BudgetNotificationType = 'CRITICAL' | 'WARNING'; -type BudgetNotificationUnit = 'PERCENT' | 'ACTUAL_COST'; +export type BudgetState = 'ACTIVE' | 'SCHEDULED' | 'EXPIRED'; +type BudgetNotificationUnit = 'PERCENT'; +type BudgetNotificationState = 'ENABLED' | 'DISABLED'; -export interface BudgetNotification { +interface BudgetNotificationPlan { threshold: number; unit: BudgetNotificationUnit; - notification_type: BudgetNotificationType; +} + +export interface BudgetNotificationRecipients { + users: string[]; +} + +export interface BudgetNotification { + state: BudgetNotificationState; + plans?: BudgetNotificationPlan[]; + recipients?: BudgetNotificationRecipients; } export interface BudgetPlannedLimit { diff --git a/apps/web/src/api-clients/cost-analysis/cost-report-config/composables/use-cost-report-config-api.ts b/apps/web/src/api-clients/cost-analysis/cost-report-config/composables/use-cost-report-config-api.ts index e69de29bb2..8f4839086a 100644 --- a/apps/web/src/api-clients/cost-analysis/cost-report-config/composables/use-cost-report-config-api.ts +++ b/apps/web/src/api-clients/cost-analysis/cost-report-config/composables/use-cost-report-config-api.ts @@ -0,0 +1,29 @@ +import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; + +import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; +import type { CostReportConfigListParameters } from '@/api-clients/cost-analysis/cost-report-config/schema/api-verbs/list'; +import type { CostReportConfigUpdateParameters } from '@/api-clients/cost-analysis/cost-report-config/schema/api-verbs/update'; +import type { CostReportConfigModel } from '@/api-clients/cost-analysis/cost-report-config/schema/model'; + + +interface UseCostReportConfigApiReturn { + costReportConfigAPI: { + update: (params: CostReportConfigUpdateParameters) => Promise; + list: (params: CostReportConfigListParameters) => Promise>; + } +} + +export const useCostReportConfigApi = (): UseCostReportConfigApiReturn => { + const actions = { + async update(params: CostReportConfigUpdateParameters) { + return SpaceConnector.clientV2.costAnalysis.costReportConfig.update(params); + }, + async list(params: CostReportConfigListParameters) { + return SpaceConnector.clientV2.costAnalysis.costReportConfig.list>(params); + }, + }; + + return { + costReportConfigAPI: actions, + }; +}; diff --git a/apps/web/src/api-clients/cost-analysis/data-source/composables/use-data-source-api.ts b/apps/web/src/api-clients/cost-analysis/data-source/composables/use-data-source-api.ts index e69de29bb2..94eff42640 100644 --- a/apps/web/src/api-clients/cost-analysis/data-source/composables/use-data-source-api.ts +++ b/apps/web/src/api-clients/cost-analysis/data-source/composables/use-data-source-api.ts @@ -0,0 +1,38 @@ +import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; + +import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; +import type { CostDataSourceGetParameters } from '@/api-clients/cost-analysis/data-source/schema/api-verbs/get'; +import type { CostDataSourceListParameters } from '@/api-clients/cost-analysis/data-source/schema/api-verbs/list'; +import type { CostDataSourceSyncParameters } from '@/api-clients/cost-analysis/data-source/schema/api-verbs/sync'; +import type { CostDataSourceUpdatePermissionsParameters } from '@/api-clients/cost-analysis/data-source/schema/api-verbs/update-permissions'; +import type { CostDataSourceModel } from '@/api-clients/cost-analysis/data-source/schema/model'; + +interface UseDataSourceApiReturn { + dataSourceAPI: { + get: (params: CostDataSourceGetParameters) => Promise; + list: (params: CostDataSourceListParameters) => Promise>; + sync: (params: CostDataSourceSyncParameters) => Promise; + updatePermissions: (params: CostDataSourceUpdatePermissionsParameters) => Promise; + } +} + +export const useDataSourceApi = (): UseDataSourceApiReturn => { + const actions = { + async get(params: CostDataSourceGetParameters) { + return SpaceConnector.clientV2.costAnalysis.dataSource.get(params); + }, + async list(params: CostDataSourceListParameters) { + return SpaceConnector.clientV2.costAnalysis.dataSource.list>(params); + }, + async sync(params: CostDataSourceSyncParameters) { + return SpaceConnector.clientV2.costAnalysis.dataSource.sync(params); + }, + async updatePermissions(params: CostDataSourceUpdatePermissionsParameters) { + return SpaceConnector.clientV2.costAnalysis.dataSource.updatePermissions(params); + }, + }; + + return { + dataSourceAPI: actions, + }; +}; diff --git a/apps/web/src/api-clients/cost-analysis/unified-cost/composables/use-unified-cost-api.ts b/apps/web/src/api-clients/cost-analysis/unified-cost/composables/use-unified-cost-api.ts index e69de29bb2..289e9d7da3 100644 --- a/apps/web/src/api-clients/cost-analysis/unified-cost/composables/use-unified-cost-api.ts +++ b/apps/web/src/api-clients/cost-analysis/unified-cost/composables/use-unified-cost-api.ts @@ -0,0 +1,20 @@ +import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; + +import type { AnalyzeResponse } from '@/api-clients/_common/schema/api-verbs/analyze'; +import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; +import type { UnifiedCostAnalyzeParameters } from '@/api-clients/cost-analysis/unified-cost/schema/api-verbs/analyze'; +import type { UnifiedCostListParameters } from '@/api-clients/cost-analysis/unified-cost/schema/api-verbs/list'; +import type { UnifiedCostStatParameters } from '@/api-clients/cost-analysis/unified-cost/schema/api-verbs/stat'; +import type { UnifiedCostModel } from '@/api-clients/cost-analysis/unified-cost/schema/model'; + +export const useUnifiedCostApi = () => { + const actions = { + analyze: SpaceConnector.clientV2.costAnalysis.unifiedCost.analyze>, + list: SpaceConnector.clientV2.costAnalysis.unifiedCost.list>, + stat: SpaceConnector.clientV2.costAnalysis.unifiedCost.stat, + }; + + return { + unifiedCostAPI: actions, + }; +}; diff --git a/apps/web/src/api-clients/dashboard/_types/dashboard-global-variable-type.ts b/apps/web/src/api-clients/dashboard/_types/dashboard-global-variable-type.ts index ca49e1e6bd..5716aa7e17 100644 --- a/apps/web/src/api-clients/dashboard/_types/dashboard-global-variable-type.ts +++ b/apps/web/src/api-clients/dashboard/_types/dashboard-global-variable-type.ts @@ -1,6 +1,4 @@ // Base Model -import type { GLOBAL_VARIABLE_FILTER_TYPE_MAP } from '@/services/dashboards/constants/dashboard-global-variable'; - interface DashboardGlobalVariableBase { key: string; // new_variable name: string; // New Variable @@ -79,4 +77,3 @@ export type DashboardGlobalVariable = -export type GlobalVariableFilterType = keyof typeof GLOBAL_VARIABLE_FILTER_TYPE_MAP; diff --git a/apps/web/src/api-clients/dashboard/_types/dashboard-type.ts b/apps/web/src/api-clients/dashboard/_types/dashboard-type.ts index c3f990a0f2..2bef51f950 100644 --- a/apps/web/src/api-clients/dashboard/_types/dashboard-type.ts +++ b/apps/web/src/api-clients/dashboard/_types/dashboard-type.ts @@ -13,6 +13,7 @@ import type { PrivateDashboardGetParameters } from '@/api-clients/dashboard/priv import type { PrivateDashboardListParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/list'; import type { PrivateDashboardUpdateParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/update'; import type { PrivateDashboardModel } from '@/api-clients/dashboard/private-dashboard/schema/model'; +import type { PrivateFolderModel } from '@/api-clients/dashboard/private-folder/schema/model'; import type { PublicDashboardChangeFolderParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/change-folder'; import type { PublicDashboardCreateParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/create'; import type { PublicDashboardDeleteParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/delete'; @@ -20,16 +21,19 @@ import type { PublicDashboardGetParameters } from '@/api-clients/dashboard/publi import type { PublicDashboardListParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/list'; 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 type { PublicFolderModel } from '@/api-clients/dashboard/public-folder/schema/model'; import type { VariableModelType } from '@/lib/variable-models'; import type { Value } from '@/lib/variable-models/_base/types'; + export type DashboardType = typeof DASHBOARD_TYPE[keyof typeof DASHBOARD_TYPE]; export type DashboardFolderType = 'PUBLIC'|'PRIVATE'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-ignore export type DashboardModel = PublicDashboardModel | PrivateDashboardModel; +export type DashboardFolderModel = PublicFolderModel | PrivateFolderModel; export type DashboardCreateParams = PublicDashboardCreateParameters | PrivateDashboardCreateParameters; export type DashboardChangeFolderParams = PublicDashboardChangeFolderParameters | PrivateDashboardChangeFolderParameters; export type DashboardListParams = PublicDashboardListParameters | PrivateDashboardListParameters; diff --git a/apps/web/src/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api.ts b/apps/web/src/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api.ts index 94168b16fa..1fbd09dea9 100644 --- a/apps/web/src/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api.ts +++ b/apps/web/src/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api.ts @@ -1,10 +1,5 @@ -import type { ComputedRef } from 'vue'; - -import type { QueryKey } from '@tanstack/vue-query'; - import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; -import { useAPIQueryKey } from '@/api-clients/_common/composables/use-api-query-key'; import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; import type { PrivateDashboardChangeFolderParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/change-folder'; import type { PrivateDashboardCreateParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/create'; @@ -14,48 +9,18 @@ import type { PrivateDashboardListParameters } from '@/api-clients/dashboard/pri import type { PrivateDashboardUpdateParameters } from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/update'; import type { PrivateDashboardModel } from '@/api-clients/dashboard/private-dashboard/schema/model'; -interface UsePrivateDashboardApiReturn { - privateDashboardGetQueryKey: ComputedRef; - privateDashboardListQueryKey: ComputedRef; - privateDashboardAPI: { - create: (params: PrivateDashboardCreateParameters) => Promise; - update: (params: PrivateDashboardUpdateParameters) => Promise; - changeFolder: (params: PrivateDashboardChangeFolderParameters) => Promise; - delete: (params: PrivateDashboardDeleteParameters) => Promise; - get: (params: PrivateDashboardGetParameters) => Promise; - list: (params: PrivateDashboardListParameters) => Promise>; - } -} - - -export const usePrivateDashboardApi = (): UsePrivateDashboardApiReturn => { - const privateDashboardGetQueryKey = useAPIQueryKey('dashboard', 'private-dashboard', 'get'); - const privateDashboardListQueryKey = useAPIQueryKey('dashboard', 'private-dashboard', 'list'); +export const usePrivateDashboardApi = () => { const actions = { - async create(params: PrivateDashboardCreateParameters) { - return SpaceConnector.clientV2.dashboard.privateDashboard.create(params); - }, - async update(params: PrivateDashboardUpdateParameters) { - return SpaceConnector.clientV2.dashboard.privateDashboard.update(params); - }, - async changeFolder(params: PrivateDashboardChangeFolderParameters) { - return SpaceConnector.clientV2.dashboard.privateDashboard.changeFolder(params); - }, - async delete(params: PrivateDashboardDeleteParameters) { - return SpaceConnector.clientV2.dashboard.privateDashboard.delete(params); - }, - async get(params: PrivateDashboardGetParameters) { - return SpaceConnector.clientV2.dashboard.privateDashboard.get(params); - }, - async list(params: PrivateDashboardListParameters) { - return SpaceConnector.clientV2.dashboard.privateDashboard.list>(params); - }, + create: SpaceConnector.clientV2.dashboard.privateDashboard.create, + update: SpaceConnector.clientV2.dashboard.privateDashboard.update, + changeFolder: SpaceConnector.clientV2.dashboard.privateDashboard.changeFolder, + delete: SpaceConnector.clientV2.dashboard.privateDashboard.delete, + get: SpaceConnector.clientV2.dashboard.privateDashboard.get, + list: SpaceConnector.clientV2.dashboard.privateDashboard.list>, }; return { - privateDashboardGetQueryKey, - privateDashboardListQueryKey, privateDashboardAPI: actions, }; }; diff --git a/apps/web/src/api-clients/dashboard/private-dashboard/schema/api-verbs/list.ts b/apps/web/src/api-clients/dashboard/private-dashboard/schema/api-verbs/list.ts index 2656ae2b91..ab0ab87fd6 100644 --- a/apps/web/src/api-clients/dashboard/private-dashboard/schema/api-verbs/list.ts +++ b/apps/web/src/api-clients/dashboard/private-dashboard/schema/api-verbs/list.ts @@ -5,4 +5,5 @@ export interface PrivateDashboardListParameters { query?: Query; dashboard_id?: string; name?: string; + folder_id?: string; } diff --git a/apps/web/src/api-clients/dashboard/private-data-table/composables/use-private-data-table-api.ts b/apps/web/src/api-clients/dashboard/private-data-table/composables/use-private-data-table-api.ts index 280c5e58fa..7cb4d1b861 100644 --- a/apps/web/src/api-clients/dashboard/private-data-table/composables/use-private-data-table-api.ts +++ b/apps/web/src/api-clients/dashboard/private-data-table/composables/use-private-data-table-api.ts @@ -1,10 +1,5 @@ -import type { ComputedRef } from 'vue'; - -import type { QueryKey } from '@tanstack/vue-query'; - import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; -import { useAPIQueryKey } from '@/api-clients/_common/composables/use-api-query-key'; import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; import type { DataTableLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import type { PrivateDataTableModel } from '@/api-clients/dashboard/private-data-table/schema/model'; @@ -16,54 +11,18 @@ import type { DataTableLoadParameters } from '@/api-clients/dashboard/public-dat import type { DataTableTransformParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/transform'; import type { DataTableUpdateParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/update'; -interface UsePrivateDataTableApiReturn { - privateDataTableGetQueryKey: ComputedRef; - privateDataTableListQueryKey: ComputedRef; - privateDataTableLoadQueryKey: ComputedRef; - privateDataTableAPI: { - add: (params: DataTableAddParameters) => Promise; - transform: (params: DataTableTransformParameters) => Promise; - update: (params: DataTableUpdateParameters) => Promise; - delete: (params: DataTableDeleteParameters) => Promise; - load: (params: DataTableLoadParameters) => Promise; - get: (params: DataTableGetParameters) => Promise; - list: (params: DataTableListParameters) => Promise>; - } -} - -export const usePrivateDataTableApi = (): UsePrivateDataTableApiReturn => { - const privateDataTableGetQueryKey = useAPIQueryKey('dashboard', 'private-data-table', 'get'); - const privateDataTableListQueryKey = useAPIQueryKey('dashboard', 'private-dashboard', 'list'); - const privateDataTableLoadQueryKey = useAPIQueryKey('dashboard', 'private-dashboard', 'list'); - +export const usePrivateDataTableApi = () => { const action = { - async add(params: DataTableAddParameters) { - return SpaceConnector.clientV2.dashboard.privateDataTable.add(params); - }, - async transform(params: DataTableTransformParameters) { - return SpaceConnector.clientV2.dashboard.privateDataTable.transform(params); - }, - async update(params: DataTableUpdateParameters) { - return SpaceConnector.clientV2.dashboard.privateDataTable.update(params); - }, - async delete(params: DataTableDeleteParameters) { - return SpaceConnector.clientV2.dashboard.privateDataTable.delete(params); - }, - async load(params: DataTableLoadParameters) { - return SpaceConnector.clientV2.dashboard.privateDataTable.load(params); - }, - async get(params: DataTableGetParameters) { - return SpaceConnector.clientV2.dashboard.privateDataTable.get(params); - }, - async list(params: DataTableListParameters) { - return SpaceConnector.clientV2.dashboard.privateDataTable.list>(params); - }, + add: SpaceConnector.clientV2.dashboard.privateDataTable.add, + transform: SpaceConnector.clientV2.dashboard.privateDataTable.transform, + update: SpaceConnector.clientV2.dashboard.privateDataTable.update, + delete: SpaceConnector.clientV2.dashboard.privateDataTable.delete, + load: SpaceConnector.clientV2.dashboard.privateDataTable.load, + get: SpaceConnector.clientV2.dashboard.privateDataTable.get, + list: SpaceConnector.clientV2.dashboard.privateDataTable.list>, }; return { - privateDataTableGetQueryKey, - privateDataTableListQueryKey, - privateDataTableLoadQueryKey, privateDataTableAPI: action, }; }; diff --git a/apps/web/src/api-clients/dashboard/private-folder/composables/use-private-folder-api.ts b/apps/web/src/api-clients/dashboard/private-folder/composables/use-private-folder-api.ts index 20401b6f12..b4ec08100a 100644 --- a/apps/web/src/api-clients/dashboard/private-folder/composables/use-private-folder-api.ts +++ b/apps/web/src/api-clients/dashboard/private-folder/composables/use-private-folder-api.ts @@ -1,10 +1,5 @@ -import type { ComputedRef } from 'vue'; - -import type { QueryKey } from '@tanstack/vue-query'; - import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; -import { useAPIQueryKey } from '@/api-clients/_common/composables/use-api-query-key'; import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; import type { PrivateFolderCreateParameters } from '@/api-clients/dashboard/private-folder/schema/api-verbs/create'; import type { PrivateFolderDeleteParameters } from '@/api-clients/dashboard/private-folder/schema/api-verbs/delete'; @@ -13,43 +8,17 @@ import type { PrivateFolderListParameters } from '@/api-clients/dashboard/privat import type { PrivateFolderUpdateParameters } from '@/api-clients/dashboard/private-folder/schema/api-verbs/update'; import type { PrivateFolderModel } from '@/api-clients/dashboard/private-folder/schema/model'; -interface UsePrivateFolderApiReturn { - privateFolderGetQueryKey: ComputedRef; - privateFolderListQueryKey: ComputedRef; - privateFolderAPI: { - create: (params: PrivateFolderCreateParameters) => Promise; - update: (params: PrivateFolderUpdateParameters) => Promise; - delete: (params: PrivateFolderDeleteParameters) => Promise; - get: (params: PrivateFolderGetParameters) => Promise; - list: (params: PrivateFolderListParameters) => Promise>; - }; -} - -export const usePrivateFolderApi = (): UsePrivateFolderApiReturn => { - const privateFolderGetQueryKey = useAPIQueryKey('dashboard', 'private-folder', 'get'); - const privateFolderListQueryKey = useAPIQueryKey('dashboard', 'private-folder', 'list'); +export const usePrivateFolderApi = () => { const action = { - async create(params: PrivateFolderCreateParameters) { - return SpaceConnector.clientV2.dashboard.privateFolder.create(params); - }, - async update(params: PrivateFolderUpdateParameters) { - return SpaceConnector.clientV2.dashboard.privateFolder.update(params); - }, - async delete(params: PrivateFolderDeleteParameters) { - return SpaceConnector.clientV2.dashboard.privateFolder.delete(params); - }, - async get(params: PrivateFolderGetParameters) { - return SpaceConnector.clientV2.dashboard.privateFolder.get(params); - }, - async list(params: PrivateFolderListParameters) { - return SpaceConnector.clientV2.dashboard.privateFolder.list>(params); - }, + create: SpaceConnector.clientV2.dashboard.privateFolder.create, + update: SpaceConnector.clientV2.dashboard.privateFolder.update, + delete: SpaceConnector.clientV2.dashboard.privateFolder.delete, + get: SpaceConnector.clientV2.dashboard.privateFolder.get, + list: SpaceConnector.clientV2.dashboard.privateFolder.list>, }; return { - privateFolderGetQueryKey, - privateFolderListQueryKey, privateFolderAPI: action, }; }; diff --git a/apps/web/src/api-clients/dashboard/private-widget/composables/use-private-widget-api.ts b/apps/web/src/api-clients/dashboard/private-widget/composables/use-private-widget-api.ts index abb13242b3..7889de09e7 100644 --- a/apps/web/src/api-clients/dashboard/private-widget/composables/use-private-widget-api.ts +++ b/apps/web/src/api-clients/dashboard/private-widget/composables/use-private-widget-api.ts @@ -1,10 +1,5 @@ -import type { ComputedRef } from 'vue'; - -import type { QueryKey } from '@tanstack/vue-query'; - import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; -import { useAPIQueryKey } from '@/api-clients/_common/composables/use-api-query-key'; import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; import type { WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import type { PrivateWidgetCreateParameters } from '@/api-clients/dashboard/private-widget/schema/api-verbs/create'; @@ -16,57 +11,18 @@ import type { PrivateWidgetLoadSumParameters } from '@/api-clients/dashboard/pri import type { PrivateWidgetUpdateParameters } from '@/api-clients/dashboard/private-widget/schema/api-verbs/update'; import type { PrivateWidgetModel } from '@/api-clients/dashboard/private-widget/schema/model'; -interface UsePrivateWidgetApiReturn { - privateWidgetGetQueryKey: ComputedRef; - privateWidgetListQueryKey: ComputedRef; - privateWidgetLoadQueryKey: ComputedRef; - privateWidgetLoadSumQueryKey: ComputedRef; - privateWidgetAPI: { - create: (params: PrivateWidgetCreateParameters) => Promise; - update: (params: PrivateWidgetUpdateParameters) => Promise; - delete: (params: PrivateWidgetDeleteParameters) => Promise; - load: (params: PrivateWidgetLoadParameters) => Promise; - loadSum: (params: PrivateWidgetLoadSumParameters) => Promise; - get: (params: PrivateWidgetGetParameters) => Promise; - list: (params: PrivateWidgetListParameters) => Promise>; - } -} - -export const usePrivateWidgetApi = (): UsePrivateWidgetApiReturn => { - const privateWidgetGetQueryKey = useAPIQueryKey('dashboard', 'private-widget', 'get'); - const privateWidgetListQueryKey = useAPIQueryKey('dashboard', 'private-widget', 'list'); - const privateWidgetLoadQueryKey = useAPIQueryKey('dashboard', 'private-widget', 'load'); - const privateWidgetLoadSumQueryKey = useAPIQueryKey('dashboard', 'private-widget', 'load-sum'); - +export const usePrivateWidgetApi = () => { const action = { - async create(params: PrivateWidgetCreateParameters) { - return SpaceConnector.clientV2.dashboard.privateWidget.create(params); - }, - async update(params: PrivateWidgetUpdateParameters) { - return SpaceConnector.clientV2.dashboard.privateWidget.update(params); - }, - async delete(params: PrivateWidgetDeleteParameters) { - return SpaceConnector.clientV2.dashboard.privateWidget.delete(params); - }, - async load(params: PrivateWidgetLoadParameters) { - return SpaceConnector.clientV2.dashboard.privateWidget.load(params); - }, - async loadSum(params: PrivateWidgetLoadSumParameters) { - return SpaceConnector.clientV2.dashboard.privateWidget.loadSum(params); - }, - async get(params: PrivateWidgetGetParameters) { - return SpaceConnector.clientV2.dashboard.privateWidget.get(params); - }, - async list(params: PrivateWidgetListParameters) { - return SpaceConnector.clientV2.dashboard.privateWidget.list>(params); - }, + create: SpaceConnector.clientV2.dashboard.privateWidget.create, + update: SpaceConnector.clientV2.dashboard.privateWidget.update, + delete: SpaceConnector.clientV2.dashboard.privateWidget.delete, + load: SpaceConnector.clientV2.dashboard.privateWidget.load, + loadSum: SpaceConnector.clientV2.dashboard.privateWidget.loadSum, + get: SpaceConnector.clientV2.dashboard.privateWidget.get, + list: SpaceConnector.clientV2.dashboard.privateWidget.list>, }; return { - privateWidgetGetQueryKey, - privateWidgetListQueryKey, - privateWidgetLoadQueryKey, - privateWidgetLoadSumQueryKey, privateWidgetAPI: action, }; }; 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..ed1d5e728e 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 @@ -1,10 +1,5 @@ -import type { ComputedRef } from 'vue'; - -import type { QueryKey } from '@tanstack/vue-query'; - import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; -import { useAPIQueryKey } from '@/api-clients/_common/composables/use-api-query-key'; import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; import type { PublicDashboardChangeFolderParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/change-folder'; import type { PublicDashboardCreateParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/create'; @@ -16,55 +11,20 @@ import type { PublicDashboardUnshareParameters } from '@/api-clients/dashboard/p import type { PublicDashboardUpdateParameters } from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/update'; import type { PublicDashboardModel } from '@/api-clients/dashboard/public-dashboard/schema/model'; -interface UsePublicDashboardApiReturn { - publicDashboardGetQueryKey: ComputedRef; - publicDashboardListQueryKey: ComputedRef; - publicDashboardAPI: { - create: (params: PublicDashboardCreateParameters) => Promise; - update: (params: PublicDashboardUpdateParameters) => Promise; - changeFolder: (params: PublicDashboardChangeFolderParameters) => Promise; - share: (params: PublicDashboardShareParameters) => Promise; - unshare: (params: PublicDashboardUnshareParameters) => Promise; - delete: (params: PublicDashboardDeleteParameters) => Promise; - get: (params: PublicDashboardGetParameters) => Promise; - list: (params: PublicDashboardListParameters) => Promise>; - } -} - -export const usePublicDashboardApi = (): UsePublicDashboardApiReturn => { - const publicDashboardGetQueryKey = useAPIQueryKey('dashboard', 'public-dashboard', 'get'); - const publicDashboardListQueryKey = useAPIQueryKey('dashboard', 'public-dashboard', 'list'); +export const usePublicDashboardApi = () => { const actions = { - async create(params: PublicDashboardCreateParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.create(params); - }, - async update(params: PublicDashboardUpdateParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.update(params); - }, - async changeFolder(params: PublicDashboardChangeFolderParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.changeFolder(params); - }, - async share(params: PublicDashboardShareParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.share(params); - }, - async unshare(params: PublicDashboardUnshareParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.unshare(params); - }, - async delete(params: PublicDashboardDeleteParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.delete(params); - }, - async get(params: PublicDashboardGetParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.get(params); - }, - async list(params: PublicDashboardListParameters) { - return SpaceConnector.clientV2.dashboard.publicDashboard.list>(params); - }, + create: SpaceConnector.clientV2.dashboard.publicDashboard.create, + update: SpaceConnector.clientV2.dashboard.publicDashboard.update, + changeFolder: SpaceConnector.clientV2.dashboard.publicDashboard.changeFolder, + share: SpaceConnector.clientV2.dashboard.publicDashboard.share, + unshare: SpaceConnector.clientV2.dashboard.publicDashboard.unshare, + delete: SpaceConnector.clientV2.dashboard.publicDashboard.delete, + get: SpaceConnector.clientV2.dashboard.publicDashboard.get, + list: SpaceConnector.clientV2.dashboard.publicDashboard.list>, }; return { - publicDashboardGetQueryKey, - publicDashboardListQueryKey, publicDashboardAPI: actions, }; }; diff --git a/apps/web/src/api-clients/dashboard/public-dashboard/schema/api-verbs/create.ts b/apps/web/src/api-clients/dashboard/public-dashboard/schema/api-verbs/create.ts index fe5c4718e0..d615baf0a9 100644 --- a/apps/web/src/api-clients/dashboard/public-dashboard/schema/api-verbs/create.ts +++ b/apps/web/src/api-clients/dashboard/public-dashboard/schema/api-verbs/create.ts @@ -24,4 +24,5 @@ export interface PublicDashboardCreateParameters { workspace_id?: string; resource_group: Extract; project_id?: string; + project_group_id?: string; } diff --git a/apps/web/src/api-clients/dashboard/public-dashboard/schema/api-verbs/list.ts b/apps/web/src/api-clients/dashboard/public-dashboard/schema/api-verbs/list.ts index 02105bb824..8fe6638e86 100644 --- a/apps/web/src/api-clients/dashboard/public-dashboard/schema/api-verbs/list.ts +++ b/apps/web/src/api-clients/dashboard/public-dashboard/schema/api-verbs/list.ts @@ -7,4 +7,6 @@ export interface PublicDashboardListParameters { name?: string; workspace_id?: string; project_id?: string; + project_group_id?: string; + folder_id?: string; } diff --git a/apps/web/src/api-clients/dashboard/public-dashboard/schema/model.ts b/apps/web/src/api-clients/dashboard/public-dashboard/schema/model.ts index 5ae600ff6d..dc48203ef7 100644 --- a/apps/web/src/api-clients/dashboard/public-dashboard/schema/model.ts +++ b/apps/web/src/api-clients/dashboard/public-dashboard/schema/model.ts @@ -30,6 +30,7 @@ export interface PublicDashboardModel { folder_id: string; resource_group: Extract; project_id: string; + project_group_id: string; workspace_id: string; domain_id: string; created_at: string; diff --git a/apps/web/src/api-clients/dashboard/public-data-table/composables/use-public-data-table-api.ts b/apps/web/src/api-clients/dashboard/public-data-table/composables/use-public-data-table-api.ts index dcf0879a22..7f513c9625 100644 --- a/apps/web/src/api-clients/dashboard/public-data-table/composables/use-public-data-table-api.ts +++ b/apps/web/src/api-clients/dashboard/public-data-table/composables/use-public-data-table-api.ts @@ -1,10 +1,5 @@ -import type { ComputedRef } from 'vue'; - -import type { QueryKey } from '@tanstack/vue-query'; - import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; -import { useAPIQueryKey } from '@/api-clients/_common/composables/use-api-query-key'; import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; import type { DataTableLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import type { DataTableAddParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/add'; @@ -17,54 +12,18 @@ import type { DataTableUpdateParameters } from '@/api-clients/dashboard/public-d import type { PublicDataTableModel } from '@/api-clients/dashboard/public-data-table/schema/model'; -interface UsePublicDataTableApiReturn { - publicDataTableGetQueryKey: ComputedRef; - publicDataTableListQueryKey: ComputedRef; - publicDataTableLoadQueryKey: ComputedRef; - publicDataTableAPI: { - add: (params: DataTableAddParameters) => Promise; - transform: (params: DataTableTransformParameters) => Promise; - update: (params: DataTableUpdateParameters) => Promise; - delete: (params: DataTableDeleteParameters) => Promise; - load: (params: DataTableLoadParameters) => Promise; - get: (params: DataTableGetParameters) => Promise; - list: (params: DataTableListParameters) => Promise>; - } -} - -export const usePublicDataTableApi = (): UsePublicDataTableApiReturn => { - const publicDataTableGetQueryKey = useAPIQueryKey('dashboard', 'public-data-table', 'get'); - const publicDataTableListQueryKey = useAPIQueryKey('dashboard', 'public-data-table', 'list'); - const publicDataTableLoadQueryKey = useAPIQueryKey('dashboard', 'public-data-table', 'load'); - +export const usePublicDataTableApi = () => { const action = { - async add(params: DataTableAddParameters) { - return SpaceConnector.clientV2.dashboard.publicDataTable.add(params); - }, - async transform(params: DataTableTransformParameters) { - return SpaceConnector.clientV2.dashboard.publicDataTable.transform(params); - }, - async update(params: DataTableUpdateParameters) { - return SpaceConnector.clientV2.dashboard.publicDataTable.update(params); - }, - async delete(params: DataTableDeleteParameters) { - return SpaceConnector.clientV2.dashboard.publicDataTable.delete(params); - }, - async load(params: DataTableLoadParameters) { - return SpaceConnector.clientV2.dashboard.publicDataTable.load(params); - }, - async get(params: DataTableGetParameters) { - return SpaceConnector.clientV2.dashboard.publicDataTable.get(params); - }, - async list(params: DataTableListParameters) { - return SpaceConnector.clientV2.dashboard.publicDataTable.list>(params); - }, + add: SpaceConnector.clientV2.dashboard.publicDataTable.add, + transform: SpaceConnector.clientV2.dashboard.publicDataTable.transform, + update: SpaceConnector.clientV2.dashboard.publicDataTable.update, + delete: SpaceConnector.clientV2.dashboard.publicDataTable.delete, + load: SpaceConnector.clientV2.dashboard.publicDataTable.load, + get: SpaceConnector.clientV2.dashboard.publicDataTable.get, + list: SpaceConnector.clientV2.dashboard.publicDataTable.list>, }; return { - publicDataTableGetQueryKey, - publicDataTableListQueryKey, - publicDataTableLoadQueryKey, publicDataTableAPI: action, }; }; diff --git a/apps/web/src/api-clients/dashboard/public-folder/composables/use-public-folder-api.ts b/apps/web/src/api-clients/dashboard/public-folder/composables/use-public-folder-api.ts index 998f523b29..5ff1607081 100644 --- a/apps/web/src/api-clients/dashboard/public-folder/composables/use-public-folder-api.ts +++ b/apps/web/src/api-clients/dashboard/public-folder/composables/use-public-folder-api.ts @@ -1,10 +1,5 @@ -import type { ComputedRef } from 'vue'; - -import type { QueryKey } from '@tanstack/vue-query'; - import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; -import { useAPIQueryKey } from '@/api-clients/_common/composables/use-api-query-key'; import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; import type { PublicFolderCreateParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/create'; import type { PublicFolderDeleteParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/delete'; @@ -15,51 +10,18 @@ import type { PublicFolderUnshareParameters } from '@/api-clients/dashboard/publ import type { PublicFolderUpdateParameters } from '@/api-clients/dashboard/public-folder/schema/api-verbs/update'; import type { PublicFolderModel } from '@/api-clients/dashboard/public-folder/schema/model'; -interface UsePublicFolderApiReturn { - publicFolderGetQueryKey: ComputedRef; - publicFolderListQueryKey: ComputedRef; - publicFolderAPI: { - create: (params: PublicFolderCreateParameters) => Promise; - update: (params: PublicFolderUpdateParameters) => Promise; - share: (params: PublicFolderShareParameters) => Promise; - unshare: (params: PublicFolderUnshareParameters) => Promise; - delete: (params: PublicFolderDeleteParameters) => Promise; - get: (params: PublicFolderGetParameters) => Promise; - list: (params: PublicFolderListParameters) => Promise>; - } -} - -export const usePublicFolderApi = (): UsePublicFolderApiReturn => { - const publicFolderGetQueryKey = useAPIQueryKey('dashboard', 'public-folder', 'get'); - const publicFolderListQueryKey = useAPIQueryKey('dashboard', 'public-folder', 'list'); - +export const usePublicFolderApi = () => { const action = { - async create(params: PublicFolderCreateParameters) { - return SpaceConnector.clientV2.dashboard.publicFolder.create(params); - }, - async update(params: PublicFolderUpdateParameters) { - return SpaceConnector.clientV2.dashboard.publicFolder.update(params); - }, - async share(params: PublicFolderShareParameters) { - return SpaceConnector.clientV2.dashboard.publicFolder.share(params); - }, - async unshare(params: PublicFolderUnshareParameters) { - return SpaceConnector.clientV2.dashboard.publicFolder.unshare(params); - }, - async delete(params: PublicFolderDeleteParameters) { - return SpaceConnector.clientV2.dashboard.publicFolder.delete(params); - }, - async get(params: PublicFolderGetParameters) { - return SpaceConnector.clientV2.dashboard.publicFolder.get(params); - }, - async list(params: PublicFolderListParameters) { - return SpaceConnector.clientV2.dashboard.publicFolder.list>(params); - }, + create: SpaceConnector.clientV2.dashboard.publicFolder.create, + update: SpaceConnector.clientV2.dashboard.publicFolder.update, + share: SpaceConnector.clientV2.dashboard.publicFolder.share, + unshare: SpaceConnector.clientV2.dashboard.publicFolder.unshare, + delete: SpaceConnector.clientV2.dashboard.publicFolder.delete, + get: SpaceConnector.clientV2.dashboard.publicFolder.get, + list: SpaceConnector.clientV2.dashboard.publicFolder.list>, }; return { - publicFolderGetQueryKey, - publicFolderListQueryKey, publicFolderAPI: action, }; }; diff --git a/apps/web/src/api-clients/dashboard/public-folder/schema/api-verbs/create.ts b/apps/web/src/api-clients/dashboard/public-folder/schema/api-verbs/create.ts index 76d46dcf06..65848de62e 100644 --- a/apps/web/src/api-clients/dashboard/public-folder/schema/api-verbs/create.ts +++ b/apps/web/src/api-clients/dashboard/public-folder/schema/api-verbs/create.ts @@ -9,4 +9,5 @@ export interface PublicFolderCreateParameters { dashboards?: string[]; workspace_id?: string; project_id?: string; + project_group_id?: string; } diff --git a/apps/web/src/api-clients/dashboard/public-folder/schema/api-verbs/list.ts b/apps/web/src/api-clients/dashboard/public-folder/schema/api-verbs/list.ts index 5e48ae7302..69bf18aae1 100644 --- a/apps/web/src/api-clients/dashboard/public-folder/schema/api-verbs/list.ts +++ b/apps/web/src/api-clients/dashboard/public-folder/schema/api-verbs/list.ts @@ -7,4 +7,5 @@ export interface PublicFolderListParameters { name?: string; workspace_id?: string; project_id?: string; + project_group_id?: string; } diff --git a/apps/web/src/api-clients/dashboard/public-folder/schema/model.ts b/apps/web/src/api-clients/dashboard/public-folder/schema/model.ts index 424b1471ea..97a58f9209 100644 --- a/apps/web/src/api-clients/dashboard/public-folder/schema/model.ts +++ b/apps/web/src/api-clients/dashboard/public-folder/schema/model.ts @@ -10,6 +10,7 @@ export interface PublicFolderModel { tags: Tags; resource_group: Extract; project_id: string; + project_group_id: string; workspace_id: string; domain_id: string; created_at: string; diff --git a/apps/web/src/api-clients/dashboard/public-widget/composables/use-public-widget-api.ts b/apps/web/src/api-clients/dashboard/public-widget/composables/use-public-widget-api.ts index 36c10f204a..655cc8d533 100644 --- a/apps/web/src/api-clients/dashboard/public-widget/composables/use-public-widget-api.ts +++ b/apps/web/src/api-clients/dashboard/public-widget/composables/use-public-widget-api.ts @@ -1,10 +1,5 @@ -import type { ComputedRef } from 'vue'; - -import type { QueryKey } from '@tanstack/vue-query'; - import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; -import { useAPIQueryKey } from '@/api-clients/_common/composables/use-api-query-key'; import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; import type { WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import type { PublicWidgetCreateParameters } from '@/api-clients/dashboard/public-widget/schema/api-verbs/create'; @@ -16,57 +11,18 @@ import type { PublicWidgetLoadSumParameters } from '@/api-clients/dashboard/publ import type { PublicWidgetUpdateParameters } from '@/api-clients/dashboard/public-widget/schema/api-verbs/update'; import type { PublicWidgetModel } from '@/api-clients/dashboard/public-widget/schema/model'; -interface UsePublicWidgetApiReturn { - publicWidgetGetQueryKey: ComputedRef; - publicWidgetListQueryKey: ComputedRef; - publicWidgetLoadQueryKey: ComputedRef; - publicWidgetLoadSumQueryKey: ComputedRef; - publicWidgetAPI: { - create: (params: PublicWidgetCreateParameters) => Promise; - update: (params: PublicWidgetUpdateParameters) => Promise; - delete: (params: PublicWidgetDeleteParameters) => Promise; - load: (params: PublicWidgetLoadParameters) => Promise; - loadSum: (params: PublicWidgetLoadSumParameters) => Promise; - get: (params: PublicWidgetGetParameters) => Promise; - list: (params: PublicWidgetListParameters) => Promise>; - } -} - -export const usePublicWidgetApi = (): UsePublicWidgetApiReturn => { - const publicWidgetGetQueryKey = useAPIQueryKey('dashboard', 'public-widget', 'get'); - const publicWidgetListQueryKey = useAPIQueryKey('dashboard', 'public-widget', 'list'); - const publicWidgetLoadQueryKey = useAPIQueryKey('dashboard', 'public-widget', 'load'); - const publicWidgetLoadSumQueryKey = useAPIQueryKey('dashboard', 'public-widget', 'load-sum'); - +export const usePublicWidgetApi = () => { const action = { - async create(params: PublicWidgetCreateParameters) { - return SpaceConnector.clientV2.dashboard.publicWidget.create(params); - }, - async update(params: PublicWidgetUpdateParameters) { - return SpaceConnector.clientV2.dashboard.publicWidget.update(params); - }, - async delete(params: PublicWidgetDeleteParameters) { - return SpaceConnector.clientV2.dashboard.publicWidget.delete(params); - }, - async load(params: PublicWidgetLoadParameters) { - return SpaceConnector.clientV2.dashboard.publicWidget.load(params); - }, - async loadSum(params: PublicWidgetLoadSumParameters) { - return SpaceConnector.clientV2.dashboard.publicWidget.loadSum(params); - }, - async get(params: PublicWidgetGetParameters) { - return SpaceConnector.clientV2.dashboard.publicWidget.get(params); - }, - async list(params: PublicWidgetListParameters) { - return SpaceConnector.clientV2.dashboard.publicWidget.list>(params); - }, + create: SpaceConnector.clientV2.dashboard.publicWidget.create, + update: SpaceConnector.clientV2.dashboard.publicWidget.update, + delete: SpaceConnector.clientV2.dashboard.publicWidget.delete, + load: SpaceConnector.clientV2.dashboard.publicWidget.load, + loadSum: SpaceConnector.clientV2.dashboard.publicWidget.loadSum, + get: SpaceConnector.clientV2.dashboard.publicWidget.get, + list: SpaceConnector.clientV2.dashboard.publicWidget.list>, }; return { - publicWidgetGetQueryKey, - publicWidgetListQueryKey, - publicWidgetLoadQueryKey, - publicWidgetLoadSumQueryKey, publicWidgetAPI: action, }; }; diff --git a/apps/web/src/api-clients/identity/service-account/schema/api-verbs/create.ts b/apps/web/src/api-clients/identity/service-account/schema/api-verbs/create.ts index cef311f12b..a952cbcd76 100644 --- a/apps/web/src/api-clients/identity/service-account/schema/api-verbs/create.ts +++ b/apps/web/src/api-clients/identity/service-account/schema/api-verbs/create.ts @@ -7,6 +7,7 @@ export interface ServiceAccountCreateParameters { secret_schema_id?: string; secret_data?: Record; tags?: Tags; + service_account_mgr_id?: string; trusted_account_id?: string; project_id: string; } diff --git a/apps/web/src/api-clients/identity/service-account/schema/api-verbs/update.ts b/apps/web/src/api-clients/identity/service-account/schema/api-verbs/update.ts index ce80ea285e..5cdd4b676e 100644 --- a/apps/web/src/api-clients/identity/service-account/schema/api-verbs/update.ts +++ b/apps/web/src/api-clients/identity/service-account/schema/api-verbs/update.ts @@ -5,5 +5,6 @@ export interface ServiceAccountUpdateParameters { name?: string; data?: Record; tags?: Tags; + service_account_mgr_id?: string; project_id?: string; } diff --git a/apps/web/src/api-clients/identity/service-account/schema/model.ts b/apps/web/src/api-clients/identity/service-account/schema/model.ts index 4beb378887..8e264cf38b 100644 --- a/apps/web/src/api-clients/identity/service-account/schema/model.ts +++ b/apps/web/src/api-clients/identity/service-account/schema/model.ts @@ -20,6 +20,7 @@ export interface ServiceAccountModel { created_at: string; last_synced_at: string; state: ServiceAccountType; + service_account_mgr_id: string; // asset_info: ServiceAccountAssetInfoType; // cost_info: ServiceAccountCostInfoType; } diff --git a/apps/web/src/api-clients/inventory/metric-data/composables/use-metric-data-api.ts b/apps/web/src/api-clients/inventory/metric-data/composables/use-metric-data-api.ts new file mode 100644 index 0000000000..d23b8633d9 --- /dev/null +++ b/apps/web/src/api-clients/inventory/metric-data/composables/use-metric-data-api.ts @@ -0,0 +1,25 @@ +import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; + +import type { AnalyzeResponse } from '@/api-clients/_common/schema/api-verbs/analyze'; +import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; +import type { MetricDataAnalyzeParameters } from '@/api-clients/inventory/metric-data/schema/api-verbs/analyze'; +import type { MetricDataListParameters } from '@/schema/inventory/metric-data/api-verbs/list'; +import type { MetricDataModel } from '@/schema/inventory/metric-data/model'; + + + + +export const useMetricDataApi = () => { + const actions = { + async list(params: MetricDataListParameters) { + return SpaceConnector.clientV2.inventory.metricData.list>(params); + }, + async analyze(params: MetricDataAnalyzeParameters) { + return SpaceConnector.clientV2.inventory.metricData.analyze>(params); + }, + }; + + return { + metricDataAPI: actions, + }; +}; diff --git a/apps/web/src/schema/inventory/metric-data/api-verbs/analyze.ts b/apps/web/src/api-clients/inventory/metric-data/schema/api-verbs/analyze.ts similarity index 100% rename from apps/web/src/schema/inventory/metric-data/api-verbs/analyze.ts rename to apps/web/src/api-clients/inventory/metric-data/schema/api-verbs/analyze.ts diff --git a/apps/web/src/api-clients/repository/dashboard-template/composables/use-dashboard-template-api.ts b/apps/web/src/api-clients/repository/dashboard-template/composables/use-dashboard-template-api.ts new file mode 100644 index 0000000000..169af1d7c8 --- /dev/null +++ b/apps/web/src/api-clients/repository/dashboard-template/composables/use-dashboard-template-api.ts @@ -0,0 +1,18 @@ +import { SpaceConnector } from '@cloudforet/core-lib/space-connector'; + +import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; +import type { DashboardTemplateListParameters } from '@/api-clients/repository/dashboard-template/schema/api-verbs/list'; +import type { DashboardTemplateRegisterParameters } from '@/api-clients/repository/dashboard-template/schema/api-verbs/register'; +import type { DashboardTemplateModel } from '@/api-clients/repository/dashboard-template/schema/model'; + + +export const useDashboardTemplateApi = () => { + const actions = { + register: SpaceConnector.clientV2.repository.dashboardTemplate.register, + list: SpaceConnector.clientV2.repository.dashboardTemplate.list>, + }; + + return { + dashboardTemplateAPI: actions, + }; +}; diff --git a/apps/web/src/schema/repository/dashboard-template/api-verbs/list.ts b/apps/web/src/api-clients/repository/dashboard-template/schema/api-verbs/list.ts similarity index 85% rename from apps/web/src/schema/repository/dashboard-template/api-verbs/list.ts rename to apps/web/src/api-clients/repository/dashboard-template/schema/api-verbs/list.ts index 858649416a..ce94e9b4dc 100644 --- a/apps/web/src/schema/repository/dashboard-template/api-verbs/list.ts +++ b/apps/web/src/api-clients/repository/dashboard-template/schema/api-verbs/list.ts @@ -1,6 +1,6 @@ import type { Query } from '@cloudforet/core-lib/space-connector/type'; -import type { DashboardTemplateState, DashboardTemplateType } from '@/schema/repository/dashboard-template/type'; +import type { DashboardTemplateState, DashboardTemplateType } from '@/api-clients/repository/dashboard-template/schema/type'; export interface DashboardTemplateListParameters { diff --git a/apps/web/src/api-clients/repository/dashboard-template/schema/api-verbs/register.ts b/apps/web/src/api-clients/repository/dashboard-template/schema/api-verbs/register.ts new file mode 100644 index 0000000000..70b3ebb444 --- /dev/null +++ b/apps/web/src/api-clients/repository/dashboard-template/schema/api-verbs/register.ts @@ -0,0 +1,12 @@ +import type { Tags } from '@/api-clients/_common/schema/model'; +import type { DashboardModel } from '@/api-clients/dashboard/_types/dashboard-type'; +import type { DashboardTemplateType } from '@/api-clients/repository/dashboard-template/schema/type'; + +export interface DashboardTemplateRegisterParameters { + template_id?: string; + name: string; + template_type?: DashboardTemplateType; + dashboards?: DashboardModel[]; + labels?: string[]; + tags?: Tags; +} diff --git a/apps/web/src/schema/repository/dashboard-template/model.ts b/apps/web/src/api-clients/repository/dashboard-template/schema/model.ts similarity index 90% rename from apps/web/src/schema/repository/dashboard-template/model.ts rename to apps/web/src/api-clients/repository/dashboard-template/schema/model.ts index 9dc4d5f3ff..e5e638f41d 100644 --- a/apps/web/src/schema/repository/dashboard-template/model.ts +++ b/apps/web/src/api-clients/repository/dashboard-template/schema/model.ts @@ -1,5 +1,5 @@ import type { Tags } from '@/api-clients/_common/schema/model'; -import type { DashboardTemplateState, DashboardTemplateType } from '@/schema/repository/dashboard-template/type'; +import type { DashboardTemplateState, DashboardTemplateType } from '@/api-clients/repository/dashboard-template/schema/type'; import type { SharedDashboardInfo } from '@/services/dashboards/types/shared-dashboard-type'; diff --git a/apps/web/src/schema/repository/dashboard-template/type.ts b/apps/web/src/api-clients/repository/dashboard-template/schema/type.ts similarity index 100% rename from apps/web/src/schema/repository/dashboard-template/type.ts rename to apps/web/src/api-clients/repository/dashboard-template/schema/type.ts diff --git a/apps/web/src/common/components/buttons/ActionMenuButton.vue b/apps/web/src/common/components/buttons/ActionMenuButton.vue index 8a6d6a3226..f46507e21c 100644 --- a/apps/web/src/common/components/buttons/ActionMenuButton.vue +++ b/apps/web/src/common/components/buttons/ActionMenuButton.vue @@ -1,8 +1,10 @@ diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBItem.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBItem.vue new file mode 100644 index 0000000000..acb1bd8408 --- /dev/null +++ b/apps/web/src/common/modules/navigations/new-lsb/LSBItem.vue @@ -0,0 +1,65 @@ + + + + diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBRouterButton.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBRouterButton.vue deleted file mode 100644 index 66e1926335..0000000000 --- a/apps/web/src/common/modules/navigations/new-lsb/LSBRouterButton.vue +++ /dev/null @@ -1,84 +0,0 @@ - - - - - diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBRouterItem.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBRouterItem.vue deleted file mode 100644 index d0c0e8f5c8..0000000000 --- a/apps/web/src/common/modules/navigations/new-lsb/LSBRouterItem.vue +++ /dev/null @@ -1,152 +0,0 @@ - - - - - diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBStarredTree.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBStarredTree.vue new file mode 100644 index 0000000000..b0a061fe9f --- /dev/null +++ b/apps/web/src/common/modules/navigations/new-lsb/LSBStarredTree.vue @@ -0,0 +1,48 @@ + + + diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBTitle.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBTitle.vue new file mode 100644 index 0000000000..11e7a51d50 --- /dev/null +++ b/apps/web/src/common/modules/navigations/new-lsb/LSBTitle.vue @@ -0,0 +1,48 @@ + + + diff --git a/apps/web/src/common/modules/navigations/new-lsb/LSBTopTitle.vue b/apps/web/src/common/modules/navigations/new-lsb/LSBTopTitle.vue deleted file mode 100644 index 4fcc1fc8c0..0000000000 --- a/apps/web/src/common/modules/navigations/new-lsb/LSBTopTitle.vue +++ /dev/null @@ -1,41 +0,0 @@ - - - diff --git a/apps/web/src/common/modules/navigations/new-lsb/composables/use-lsb-router-item-state.ts b/apps/web/src/common/modules/navigations/new-lsb/composables/use-lsb-router-item-state.ts deleted file mode 100644 index 53bd568175..0000000000 --- a/apps/web/src/common/modules/navigations/new-lsb/composables/use-lsb-router-item-state.ts +++ /dev/null @@ -1,55 +0,0 @@ -import type { UnwrapRef, Ref } from 'vue'; -import { computed } from 'vue'; -import type { Location } from 'vue-router'; -import { useRoute, useRouter } from 'vue-router/composables'; - -import { assetUrlConverter } from '@/lib/helper/asset-helper'; - -import type { LSBIcon, LSBRouterPredicate } from '@/common/modules/navigations/new-lsb/type'; - -interface UseLsbRouterItemProps { - to?: Ref>; - icon?: Ref>; - imgIcon?: Ref>; - predicate?: LSBRouterPredicate; -} -export const useLsbRouterItemState = (props: UnwrapRef) => { - const router = useRouter(); - const route = useRoute(); - - const isSelected = computed(() => { - if (!props.to) return false; - - if (props.predicate) { - return props.predicate(props.to, route); - } - - const resolved = router.resolve(props.to); - if (!resolved) return false; - - let currentPath = route.fullPath; - if (currentPath.indexOf('?') > 0) { - currentPath = currentPath.slice(0, currentPath.indexOf('?')); - } - const resolvedHref = resolved.href; - return currentPath === resolvedHref; - }); - const iconName = computed(() => { - if (!props.icon) return ''; - if (typeof props.icon === 'string') return props.icon; - return props.icon.name; - }); - const iconColor = computed(() => { - if (!props.icon) return 'inherit'; - if (typeof props.icon === 'string') return 'inherit'; - return props.icon.color || 'inherit'; - }); - const imgIconUrl = computed(() => (props.imgIcon ? assetUrlConverter(props.imgIcon) : '')); - - return { - isSelected, - iconName, - iconColor, - imgIconUrl, - }; -}; diff --git a/apps/web/src/common/modules/navigations/new-lsb/type.ts b/apps/web/src/common/modules/navigations/new-lsb/type.ts index 39f4908eb1..e05ca944e4 100644 --- a/apps/web/src/common/modules/navigations/new-lsb/type.ts +++ b/apps/web/src/common/modules/navigations/new-lsb/type.ts @@ -1,6 +1,21 @@ +import type { TranslateResult } from 'vue-i18n'; import type { Location, Route } from 'vue-router'; +import type { TreeNodeDisplayType, TreeNodeIcon, TreeNodeLink } from '@cloudforet/mirinae/types/data-display/tree/new-tree/type'; + +import type { FavoriteOptions } from '@/common/modules/favorites/favorite-button/type'; -export type LSBIcon = string | { name: string; color?: string; }; export type HighlightTagType = 'new' | 'beta' | 'update'; export type LSBRouterPredicate = (to: Location, currentRoute: Route) => boolean; +export type LSBItemFavoriteVisibility = 'always' | 'active-only' | 'hovered-only' | 'none'; + +export interface LSBItemProps { + id: string; + name: TranslateResult; + icon?: TreeNodeIcon; + link: TreeNodeLink; + displayType?: TreeNodeDisplayType; + highlightTag?: HighlightTagType; + favoriteOptions?: FavoriteOptions; + favoriteVisibility?: LSBItemFavoriteVisibility; +} diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/helper.ts b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/helper.ts index 6dd2444f28..1591a5945f 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/helper.ts +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/helper.ts @@ -7,7 +7,6 @@ import type { SearchTab } from '@/common/modules/navigations/top-bar/modules/top import { ASSET_INVENTORY_ROUTE } from '@/services/asset-inventory/routes/route-constant'; import { DASHBOARDS_ROUTE } from '@/services/dashboards/routes/route-constant'; -import { PROJECT_ROUTE_V1 } from '@/services/project/v1/routes/route-constant'; import { SERVICE_ACCOUNT_ROUTE } from '@/services/service-account/routes/route-constant'; const queryHelper = new QueryHelper(); @@ -19,11 +18,6 @@ export const topBarSearchReferenceRouter = (type: Exclude, name: SERVICE_ACCOUNT_ROUTE.DETAIL._NAME, params: { serviceAccountId: resourceId, workspaceId }, }; - case SEARCH_TAB.PROJECT: - return { - name: PROJECT_ROUTE_V1.DETAIL._NAME, - params: { id: resourceId, workspaceId }, - }; case SEARCH_TAB.DASHBOARD: return { name: DASHBOARDS_ROUTE.DETAIL._NAME, diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/modules/top-bar-search-dropdown/TopBarSearchDropdown.vue b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/modules/top-bar-search-dropdown/TopBarSearchDropdown.vue index 0c574d7022..d6f8b76d00 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/modules/top-bar-search-dropdown/TopBarSearchDropdown.vue +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/modules/top-bar-search-dropdown/TopBarSearchDropdown.vue @@ -11,6 +11,8 @@ import { } from '@cloudforet/mirinae'; import type { ValueItem } from '@cloudforet/mirinae/types/controls/search/query-search/type'; +import { useReferenceRouter } from '@/router/composables/use-reference-router'; + import { useAllReferenceStore } from '@/store/reference/all-reference-store'; import { useUserStore } from '@/store/user/user-store'; @@ -32,7 +34,6 @@ import { useTopBarSearchStore } from '@/common/modules/navigations/top-bar/modul import type { SearchTab } from '@/common/modules/navigations/top-bar/modules/top-bar-search/type'; import { RECENT_TYPE } from '@/common/modules/navigations/type'; - interface Props { isFocused: boolean; focusingDirection: string; @@ -56,6 +57,8 @@ const recentStore = useRecentStore(); const userStore = useUserStore(); const windowSize = useWindowSize(); +const { getReferenceLocation } = useReferenceRouter(); + const dropdownRef = ref(null); const dropdownSize = useElementSize(dropdownRef); const tabRef = ref(null); @@ -133,7 +136,13 @@ const handleSelect = (item) => { label: item?.name, }, }); - } else if (topBarSearchStore.state.activeTab !== SEARCH_TAB.SERVICE) router.push(topBarSearchReferenceRouter(topBarSearchStore.state.activeTab, item.resource_id, item.workspace_id)); + } else if (topBarSearchStore.state.activeTab !== SEARCH_TAB.SERVICE) { + if (topBarSearchStore.state.activeTab === SEARCH_TAB.PROJECT) { + router.push(getReferenceLocation(item.resource_id, { resource_type: 'identity.Project' })).catch(() => {}); + } else { + router.push(topBarSearchReferenceRouter(topBarSearchStore.state.activeTab, item.resource_id, item.workspace_id)); + } + } topBarSearchStore.setIsActivated(false); }; diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/modules/top-bar-search-dropdown/modules/TopBarSearchRecentListItem.vue b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/modules/top-bar-search-dropdown/modules/TopBarSearchRecentListItem.vue index 7252229caa..6884e9edf0 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/modules/top-bar-search-dropdown/modules/TopBarSearchRecentListItem.vue +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-search/modules/top-bar-search-dropdown/modules/TopBarSearchRecentListItem.vue @@ -7,6 +7,8 @@ import { PI, PIconButton, PLazyImg, PTooltip, } from '@cloudforet/mirinae'; +import { useReferenceRouter } from '@/router/composables/use-reference-router'; + import { useAllReferenceStore } from '@/store/reference/all-reference-store'; import { useRecentStore } from '@/common/modules/navigations/stores/recent-store'; @@ -16,7 +18,6 @@ import { useTopBarSearchStore } from '@/common/modules/navigations/top-bar/modul import type { SearchTab } from '@/common/modules/navigations/top-bar/modules/top-bar-search/type'; import type { RecentItem } from '@/common/modules/navigations/type'; - interface Props { recentItem?: RecentItem; } @@ -29,6 +30,8 @@ const allReferenceStore = useAllReferenceStore(); const recentStore = useRecentStore(); const router = useRouter(); +const { getReferenceLocation } = useReferenceRouter(); + const storeState = reactive({ workspaceMap: computed(() => topBarSearchStore.storeState.workspaceMap), currentWorkspaceId: computed(() => topBarSearchStore.storeState.currentWorkspaceId), @@ -132,11 +135,15 @@ const handleClick = () => { if (topBarSearchStore.state.activeTab === SEARCH_TAB.CLOUD_SERVICE) { router.push(topBarSearchReferenceRouter(topBarSearchStore.state.activeTab, state.convertResourceId, storeState.currentWorkspaceId, props.recentItem?.data)); } else if (topBarSearchStore.state.activeTab !== SEARCH_TAB.SERVICE) { - router.push(topBarSearchReferenceRouter( - topBarSearchStore.state.activeTab, - state.convertResourceId, - storeState.currentWorkspaceId, - )); + if (topBarSearchStore.state.activeTab === SEARCH_TAB.PROJECT) { + router.push(getReferenceLocation(state.convertResourceId, { resource_type: 'identity.Project' })).catch(() => {}); + } else { + router.push(topBarSearchReferenceRouter( + topBarSearchStore.state.activeTab, + state.convertResourceId, + storeState.currentWorkspaceId, + )); + } } topBarSearchStore.setIsActivated(false); }; diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/TopBarToolset.vue b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/TopBarToolset.vue index dcaf4e4b76..2f471bf2ec 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/TopBarToolset.vue +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/TopBarToolset.vue @@ -7,7 +7,7 @@ import { i18n } from '@/translations'; import { useAppContextStore } from '@/store/app-context/app-context-store'; import { useDomainStore } from '@/store/domain/domain-store'; -import { useGlobalConfigStore } from '@/store/global-config/global-config-store'; +import { useGlobalConfigSchemaStore } from '@/store/global-config-schema/global-config-schema-store'; import { useUserStore } from '@/store/user/user-store'; import TopBarAdminToggleButton from '@/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-admin-toggle-button/TopBarAdminToggleButton.vue'; @@ -32,13 +32,13 @@ const emit = defineEmits<{(event: 'hide-menu'): void; const appContextStore = useAppContextStore(); const domainStore = useDomainStore(); const userStore = useUserStore(); -const globalConfigStore = useGlobalConfigStore(); +const globalConfigSchemaStore = useGlobalConfigSchemaStore(); const state = reactive({ isDomainAdmin: computed(() => userStore.getters.isDomainAdmin), isAdminMode: computed(() => appContextStore.getters.isAdminMode), isGrantLoading: computed(() => appContextStore.getters.globalGrantLoading), - visibleAlertIcon: computed(() => globalConfigStore.state.schema.ALERT_MANAGER?.uiAffects?.visibleAlertIcon), + visibleAlertIcon: computed(() => globalConfigSchemaStore.state.uiAffectsSchema.ALERT_MANAGER?.visibleAlertIcon), tooltipTexts: computed>(() => ({ adminToggle: (state.isAdminMode ? i18n.t('COMMON.GNB.TOOLTIP.EXIT_ADMIN_MODE') : i18n.t('COMMON.GNB.TOOLTIP.ENABLE_ADMIN_MODE')) as string, })), diff --git a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-favorite/TopBarFavorite.vue b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-favorite/TopBarFavorite.vue index 002a0c4e55..6c14b99aa2 100644 --- a/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-favorite/TopBarFavorite.vue +++ b/apps/web/src/common/modules/navigations/top-bar/modules/top-bar-toolset/modules/top-bar-favorite/TopBarFavorite.vue @@ -1,8 +1,5 @@ diff --git a/apps/web/src/common/modules/project/ProjectSelectDropdown.vue b/apps/web/src/common/modules/project/ProjectSelectDropdown.vue index 85eb705042..266f1163e5 100644 --- a/apps/web/src/common/modules/project/ProjectSelectDropdown.vue +++ b/apps/web/src/common/modules/project/ProjectSelectDropdown.vue @@ -1,5 +1,6 @@ + + diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataSourcePopover.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataSourcePopover.vue index 629eca906f..c6d897c2c9 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataSourcePopover.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataSourcePopover.vue @@ -4,7 +4,7 @@ import { } from 'vue'; import type { TranslateResult } from 'vue-i18n'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { PButton, PPopover, PSelectCard, PI, PDivider, @@ -12,6 +12,7 @@ import { import type { WidgetCreateParams, WidgetModel } from '@/api-clients/dashboard/_types/widget-type'; import type { DataTableAddParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/add'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; import { i18n } from '@/translations'; import { useAllReferenceStore } from '@/store/reference/all-reference-store'; @@ -32,28 +33,30 @@ import WidgetFormAssetSecurityDataSourcePopper import WidgetFormCostDataSourcePopper from '@/common/modules/widgets/_components/WidgetFormCostDataSourcePopper.vue'; import WidgetFormUnifiedCostDataSourcePopper from '@/common/modules/widgets/_components/WidgetFormUnifiedCostDataSourcePopper.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; +import { useWidgetQuery } from '@/common/modules/widgets/_composables/use-widget-query'; import { DATA_SOURCE_DOMAIN, DATA_TABLE_OPERATOR, DATA_TABLE_TYPE, TRANSFORM_DATA_TABLE_DEFAULT_OPTIONS, } from '@/common/modules/widgets/_constants/data-table-constant'; import { getDuplicatedDataTableName } from '@/common/modules/widgets/_helpers/widget-data-table-helper'; +import { useWidgetContextStore } from '@/common/modules/widgets/_store/widget-context-store'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; import type { DataTableDataType, DataTableSourceType, DataTableOperator, DataTableAddOptions, DataTableTransformOptions, } from '@/common/modules/widgets/types/widget-model'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; const widgetGenerateStore = useWidgetGenerateStore(); const widgetGenerateState = widgetGenerateStore.state; const allReferenceStore = useAllReferenceStore(); -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; +const widgetContextStore = useWidgetContextStore(); +const widgetContextState = widgetContextStore.state; +const widgetContextGetters = widgetContextStore.getters; const userStore = useUserStore(); +const dashboardId = computed(() => widgetContextGetters.dashboardId); const emit = defineEmits<{(e: 'scroll'): void;}>(); @@ -61,20 +64,18 @@ const { visibleContents } = useContentsAccessibility(MENU_ID.ASSET_INVENTORY); /* Query */ const { - dataTableList, - api, - keys: widgetQueryKeys, - queryClient, -} = useWidgetFormQuery({ + api: widgetApi, +} = useWidgetQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); const { - dashboard, - keys, -} = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), + dataTableList, + keys: dataTableKeys, + api: dataTableApi, +} = useWidgetDataTableListQuery({ + widgetId: computed(() => widgetGenerateState.widgetId), }); - +const queryClient = useQueryClient(); const storeState = reactive({ metrics: computed(() => allReferenceStore.getters.metric), @@ -192,22 +193,25 @@ const state = reactive({ }); /* Api */ +const { withSuffix: privateWidgetListWithSuffix } = useServiceQueryKey('dashboard', 'private-widget', 'list'); +const { withSuffix: publicWidgetListWithSuffix } = useServiceQueryKey('dashboard', 'public-widget', 'list'); + const widgetCreateFn = (params: WidgetCreateParams): Promise => { - if (dashboardDetailState.dashboardId?.startsWith('private')) { - return api.privateWidgetAPI.create(params); + if (!params.dashboard_id) { + throw new Error('dashboardId is undefined'); + } + + if (params.dashboard_id.startsWith('private')) { + return widgetApi.privateWidgetAPI.create(params); } - return api.publicWidgetAPI.create(params); + return widgetApi.publicWidgetAPI.create(params); }; const { mutateAsync: createWidget, isPending: widgetCreateLoading } = useMutation({ mutationFn: widgetCreateFn, - onSuccess: (data) => { - const _isPrivate = dashboardDetailState.dashboardId?.startsWith('private'); - const widgetListQueryKey = _isPrivate ? keys.privateWidgetListQueryKey : keys.publicWidgetListQueryKey; - queryClient.setQueryData(widgetListQueryKey.value, (oldData: ListResponse) => (oldData.results?.length ? { - ...oldData, results: [...oldData.results, data], - } : { - ...oldData, results: [data], - })); + onSuccess: (data, variables) => { + const _isPrivate = variables.dashboard_id.startsWith('private'); + const widgetListQueryKey = _isPrivate ? privateWidgetListWithSuffix(variables.dashboard_id) : publicWidgetListWithSuffix(variables.dashboard_id); + queryClient.invalidateQueries({ queryKey: widgetListQueryKey }); widgetGenerateStore.setWidgetFormInfo(data); }, onError: (e) => { @@ -215,16 +219,16 @@ const { mutateAsync: createWidget, isPending: widgetCreateLoading } = useMutatio }, }); const dataTableAddFn = (params: DataTableAddParameters): Promise => { - if (dashboardDetailState.dashboardId?.startsWith('private')) { - return api.privateDataTableAPI.add(params); + if (params.widget_id.startsWith('private')) { + return dataTableApi.privateDataTableAPI.add(params); } - return api.publicDataTableAPI.add(params); + return dataTableApi.publicDataTableAPI.add(params); }; const { mutateAsync: addDataTable, isPending: dataTableAddLoading } = useMutation({ mutationFn: dataTableAddFn, onSuccess: (data) => { const _isPrivate = widgetGenerateState.widgetId?.startsWith('private'); - const dataTableListQueryKey = _isPrivate ? widgetQueryKeys.privateDataTableListQueryKey : widgetQueryKeys.publicDataTableListQueryKey; + const dataTableListQueryKey = _isPrivate ? dataTableKeys.privateDataTableListQueryKey : dataTableKeys.publicDataTableListQueryKey; queryClient.setQueryData(dataTableListQueryKey.value, (oldData: ListResponse) => (oldData.results?.length ? { ...oldData, results: [...oldData.results, data], } : { @@ -269,7 +273,7 @@ const handleCreateUnsavedTransform = async (operator: DataTableOperator) => { } as Partial; const _isPrivate = widgetGenerateState.widgetId?.startsWith('private'); - const dataTableListQueryKey = _isPrivate ? widgetQueryKeys.privateDataTableListQueryKey : widgetQueryKeys.publicDataTableListQueryKey; + const dataTableListQueryKey = _isPrivate ? dataTableKeys.privateDataTableListQueryKey : dataTableKeys.publicDataTableListQueryKey; await queryClient.setQueryData(dataTableListQueryKey.value, (oldData: ListResponse) => (oldData.results?.length ? { ...oldData, results: [...oldData.results, unsavedTransformData], } : { @@ -285,10 +289,13 @@ const handleSelectPopperCondition = (condition: DataTableDataType) => { state.selectedPopperCondition = condition; }; const handleConfirmDataSource = async () => { + if (!dashboardId.value) { + throw new Error('dashboardId is undefined'); + } // create widget if (widgetGenerateState.overlayType === 'ADD' && !widgetGenerateState.widgetId) { await createWidget({ - dashboard_id: dashboardDetailState.dashboardId as string, + dashboard_id: dashboardId.value, tags: { created_by: userStore.state.userId }, widget_type: 'table', }); @@ -343,7 +350,7 @@ const handleConfirmDataSource = async () => { const mergedParams = { ...addParameters, - vars: dashboard.value?.vars || {}, + vars: widgetContextState.dashboard?.vars || {}, }; if (state.selectedDataSourceDomain === DATA_SOURCE_DOMAIN.COST) { mergedParams.options = costOptions; diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardAddContents.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardAddContents.vue index 8c86344cc9..9a4269820e 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardAddContents.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardAddContents.vue @@ -3,7 +3,7 @@ import { computed, defineExpose, onMounted, reactive, watch, } from 'vue'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { cloneDeep, isArray, isEqual, uniq, } from 'lodash'; @@ -17,6 +17,7 @@ import type { PrivateDataTableModel } from '@/api-clients/dashboard/private-data import type { DataTableDeleteParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/delete'; import type { DataTableUpdateParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/update'; import type { PublicDataTableModel } from '@/api-clients/dashboard/public-data-table/schema/model'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; import { i18n } from '@/translations'; import { useAllReferenceStore } from '@/store/reference/all-reference-store'; @@ -38,7 +39,8 @@ import WidgetFormDataTableCardSourceForm import { useDataTableCascadeUpdate, } from '@/common/modules/widgets/_composables/use-data-table-cascade-update'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; +import { useWidgetQuery } from '@/common/modules/widgets/_composables/use-widget-query'; import { DATA_SOURCE_DOMAIN, DATA_TABLE_OPERATOR, @@ -53,7 +55,6 @@ import type { } from '@/common/modules/widgets/types/widget-model'; import { GROUP_BY } from '@/services/cost-explorer/constants/cost-explorer-constant'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; interface Props { selected: boolean; @@ -68,20 +69,24 @@ const props = defineProps(); const widgetGenerateStore = useWidgetGenerateStore(); const widgetGenerateState = widgetGenerateStore.state; const allReferenceStore = useAllReferenceStore(); -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; /* Query */ const { widget, + keys: widgetKeys, + fetcher: widgetFetcher, +} = useWidgetQuery({ + widgetId: computed(() => widgetGenerateState.widgetId), +}); +const { dataTableList, - keys, - api, - fetcher, - queryClient, -} = useWidgetFormQuery({ + keys: dataTableKeys, + api: dataTableApi, + fetcher: dataTableFetcher, +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); +const queryClient = useQueryClient(); const { cascadeUpdateDataTable, } = useDataTableCascadeUpdate({ @@ -230,33 +235,37 @@ const modalState = reactive({ referenceDataTableName: '', }); +/* Query Keys */ +const { withSuffix: privateDataTableGetQueryKey } = useServiceQueryKey('dashboard', 'private-data-table', 'get'); +const { withSuffix: publicDataTableGetQueryKey } = useServiceQueryKey('dashboard', 'public-data-table', 'get'); +const { withSuffix: privateDataTableLoadQueryKey } = useServiceQueryKey('dashboard', 'private-data-table', 'load'); +const { withSuffix: publicDataTableLoadQueryKey } = useServiceQueryKey('dashboard', 'public-data-table', 'load'); +const { withSuffix: privateWidgetLoadQueryKey } = useServiceQueryKey('dashboard', 'private-widget', 'load'); +const { withSuffix: publicWidgetLoadQueryKey } = useServiceQueryKey('dashboard', 'public-widget', 'load'); +const { withSuffix: privateWidgetLoadSumQueryKey } = useServiceQueryKey('dashboard', 'private-widget', 'load-sum'); +const { withSuffix: publicWidgetLoadSumQueryKey } = useServiceQueryKey('dashboard', 'public-widget', 'load-sum'); + /* APIs */ const invalidateLoadQueries = async (data: DataTableModel) => { - await queryClient.invalidateQueries({ - queryKey: [ - ...(state.isPrivate ? keys.privateDataTableLoadQueryKey.value : keys.publicDataTableLoadQueryKey.value), - data.data_table_id, - ], - }); - await queryClient.invalidateQueries({ - queryKey: [ - ...(state.isPrivate ? keys.privateWidgetLoadQueryKey.value : keys.publicWidgetLoadQueryKey.value), - dashboardDetailState.dashboardId, - widgetGenerateState.widgetId, - ], - }); - await queryClient.invalidateQueries({ - queryKey: [ - ...(state.isPrivate ? keys.privateWidgetLoadSumQueryKey.value : keys.publicWidgetLoadSumQueryKey.value), - dashboardDetailState.dashboardId, - widgetGenerateState.widgetId, - ], - }); + if (!widgetGenerateState.widgetId) return; + if (data.data_table_id.startsWith('private')) { + await Promise.all([ + queryClient.invalidateQueries({ queryKey: privateDataTableLoadQueryKey(state.dataTableId) }), + queryClient.invalidateQueries({ queryKey: privateWidgetLoadQueryKey(widgetGenerateState.widgetId) }), + queryClient.invalidateQueries({ queryKey: privateWidgetLoadSumQueryKey(widgetGenerateState.widgetId) }), + ]); + } else { + await Promise.all([ + queryClient.invalidateQueries({ queryKey: publicDataTableLoadQueryKey(state.dataTableId) }), + queryClient.invalidateQueries({ queryKey: publicWidgetLoadQueryKey(widgetGenerateState.widgetId) }), + queryClient.invalidateQueries({ queryKey: publicWidgetLoadSumQueryKey(widgetGenerateState.widgetId) }), + ]); + } }; const { mutateAsync: updateDataTableMutation } = useMutation({ - mutationFn: fetcher.updateDataTableFn, + mutationFn: dataTableFetcher.updateDataTableFn, onSuccess: async (data) => { - const dataTableListQueryKey = state.isPrivate ? keys.privateDataTableListQueryKey : keys.publicDataTableListQueryKey; + const dataTableListQueryKey = state.isPrivate ? dataTableKeys.privateDataTableListQueryKey : dataTableKeys.publicDataTableListQueryKey; await queryClient.setQueryData(dataTableListQueryKey.value, (oldData: ListResponse) => { if (oldData.results) { return { @@ -271,6 +280,7 @@ const { mutateAsync: updateDataTableMutation } = useMutation({ } return oldData; }); + await queryClient.invalidateQueries({ queryKey: state.isPrivate ? privateDataTableGetQueryKey(state.dataTableId) : publicDataTableGetQueryKey(state.dataTableId) }); await invalidateLoadQueries(data); setInitialDataTableForm(); @@ -284,11 +294,11 @@ const { mutateAsync: updateDataTableMutation } = useMutation({ }, }); const { mutateAsync: updateWidget } = useMutation({ - mutationFn: fetcher.updateWidgetFn, + mutationFn: widgetFetcher.updateWidgetFn, onSuccess: (data) => { const widgetQueryKey = widgetGenerateState.widgetId?.startsWith('private') - ? keys.privateWidgetGetQueryKey - : keys.publicWidgetGetQueryKey; + ? widgetKeys.privateWidgetGetQueryKey + : widgetKeys.publicWidgetGetQueryKey; queryClient.setQueryData(widgetQueryKey.value, () => data); }, onError: (e) => { @@ -363,8 +373,8 @@ const updateDataTable = async (): Promise => { }; const deleteDataTableFn = (params: DataTableDeleteParameters): Promise => { if (params.data_table_id.startsWith('private')) { - return api.privateDataTableAPI.delete(params); - } return api.publicDataTableAPI.delete(params); + return dataTableApi.privateDataTableAPI.delete(params); + } return dataTableApi.publicDataTableAPI.delete(params); }; const { mutateAsync: deleteDataTable } = useMutation({ mutationFn: deleteDataTableFn, @@ -376,7 +386,7 @@ const { mutateAsync: deleteDataTable } = useMutation({ widgetGenerateStore.setAllDataTableInvalidMap(_allDataTableInvalidMap); const _isPrivate = widgetGenerateState.widgetId?.startsWith('private'); - const dataTableListQueryKey = _isPrivate ? keys.privateDataTableListQueryKey : keys.publicDataTableListQueryKey; + const dataTableListQueryKey = _isPrivate ? dataTableKeys.privateDataTableListQueryKey : dataTableKeys.publicDataTableListQueryKey; await queryClient.setQueryData(dataTableListQueryKey.value, (oldData: ListResponse) => { if (oldData.results) { return { @@ -441,6 +451,9 @@ const handleCancelModal = () => { modalState.visible = false; }; const handleUpdateDataTable = async () => { + if (!widgetGenerateState.widgetId) { + throw new Error('Widget ID is required'); + } state.loading = true; const result = await updateDataTable(); if (result) { diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardFilters.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardFilters.vue index e5cd5a3d9f..1b95dc5731 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardFilters.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardFilters.vue @@ -40,7 +40,7 @@ import ErrorHandler from '@/common/composables/error/errorHandler'; import { useProxyValue } from '@/common/composables/proxy-state'; import WidgetFormDataTableCardFiltersItem from '@/common/modules/widgets/_components/WidgetFormDataTableCardFiltersItem.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_SOURCE_DOMAIN, DATA_TABLE_QUERY_OPERATOR, @@ -89,7 +89,7 @@ const appContextStore = useAppContextStore(); /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardFiltersItem.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardFiltersItem.vue index a1548c2c11..cd116532d6 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardFiltersItem.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardFiltersItem.vue @@ -21,13 +21,12 @@ import { KEYWORD_FILTER_DISABLED_KEYS, } from '@/common/modules/widgets/_constants/data-table-constant'; import { isGlobalVariableFormat } from '@/common/modules/widgets/_helpers/global-variable-helper'; +import { useWidgetContextStore } from '@/common/modules/widgets/_store/widget-context-store'; import type { DataTableQueryFilterForDropdown } from '@/common/modules/widgets/types/widget-data-table-type'; import { blue, gray } from '@/styles/colors'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; -import { getOrderedGlobalVariables } from '@/services/dashboards/helpers/dashboard-global-variables-helper'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; +import { getOrderedGlobalVariables } from '@/services/_shared/dashboard/dashboard-detail/helpers/dashboard-global-variables-helper'; interface Props { @@ -39,17 +38,15 @@ interface Props { } const props = defineProps(); - const emit = defineEmits<{(e: 'delete'): void; (e: 'update:selected-filter', filter: DataTableQueryFilterForDropdown): void; }>(); + +const widgetContextStore = useWidgetContextStore(); +const widgetContextState = widgetContextStore.state; + const operatorButtonRef = ref(null); -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; -const { dashboard } = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), -}); const state = reactive({ visibleMenu: false, operatorMenu: computed(() => { @@ -103,7 +100,7 @@ const state = reactive({ selectedOperator: [] as MenuItem[], proxySelectedFilter: useProxyValue('selectedFilter', props, emit), globalVariableItems: computed(() => { - const _refinedProperties: DashboardGlobalVariable[] = Object.values(dashboard.value?.vars_schema?.properties ?? {}); + const _refinedProperties: DashboardGlobalVariable[] = Object.values(widgetContextState.dashboard?.vars_schema?.properties ?? {}); const _orderedVariables = getOrderedGlobalVariables(_refinedProperties); return _orderedVariables.map((variable) => ({ name: `{{ global.${variable.key} }}`, diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardHeaderTitle.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardHeaderTitle.vue index 5fae855e2d..08d4537ac0 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardHeaderTitle.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardHeaderTitle.vue @@ -2,7 +2,7 @@ import { computed, reactive } from 'vue'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { cloneDeep } from 'lodash'; import { @@ -17,7 +17,8 @@ import { showErrorMessage, showSuccessMessage } from '@/lib/helper/notice-alert- import ErrorHandler from '@/common/composables/error/errorHandler'; import { useProxyValue } from '@/common/composables/proxy-state'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; +import { useWidgetQuery } from '@/common/modules/widgets/_composables/use-widget-query'; import { DATA_TABLE_TYPE, } from '@/common/modules/widgets/_constants/data-table-constant'; @@ -47,13 +48,20 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { widget, + fetcher: widgetFetcher, + keys: widgetKeys, +} = useWidgetQuery({ + widgetId: computed(() => widgetGenerateState.widgetId), +}); +const { dataTableList, - fetcher, - keys, - queryClient, -} = useWidgetFormQuery({ + keys: dataTableKeys, + fetcher: dataTableFetcher, +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); +const queryClient = useQueryClient(); + const storeState = reactive({ currentDataTable: computed(() => dataTableList.value.find((dataTable) => dataTable.data_table_id === props.dataTableId)), @@ -79,7 +87,7 @@ const handleSelectDataTable = async (dataTableId: string) => { const _widgetOptions = cloneDeep(widget.value?.options); const sanitizedOptions = sanitizeWidgetOptions(_widgetOptions, widget.value?.widget_type, storeState.currentDataTable); await updateWidget({ - widget_id: widgetGenerateState.widgetId, + widget_id: widgetGenerateState.widgetId as string, state: 'INACTIVE', options: sanitizedOptions, }); @@ -121,11 +129,11 @@ const handleClickNameConfirm = async () => { /* Api */ const { mutateAsync: updateWidget } = useMutation({ - mutationFn: fetcher.updateWidgetFn, + mutationFn: widgetFetcher.updateWidgetFn, onSuccess: (data) => { const widgetQueryKey = widgetGenerateState.widgetId?.startsWith('private') - ? keys.privateWidgetQueryKey - : keys.publicWidgetQueryKey; + ? widgetKeys.privateWidgetGetQueryKey + : widgetKeys.publicWidgetGetQueryKey; queryClient.setQueryData(widgetQueryKey.value, () => data); }, onError: (e) => { @@ -134,7 +142,7 @@ const { mutateAsync: updateWidget } = useMutation({ }, }); const { mutate: updateDataTable } = useMutation({ - mutationFn: fetcher.updateDataTableFn, + mutationFn: dataTableFetcher.updateDataTableFn, onSuccess: async (data) => { await syncDataTableList(data); showSuccessMessage(i18n.t('COMMON.WIDGETS.DATA_TABLE.FORM.DATA_TABLE_NAME_SUCCESS'), ''); @@ -147,7 +155,7 @@ const { mutate: updateDataTable } = useMutation({ }); const syncDataTableList = async (data: DataTableModel) => { const _isPrivate = widgetGenerateState.widgetId?.startsWith('private'); - const dataTableListQueryKey = _isPrivate ? keys.privateDataTableListQueryKey : keys.publicDataTableListQueryKey; + const dataTableListQueryKey = _isPrivate ? dataTableKeys.privateDataTableListQueryKey : dataTableKeys.publicDataTableListQueryKey; await queryClient.setQueryData(dataTableListQueryKey.value, (oldData: ListResponse) => { if (oldData.results) { return { @@ -206,10 +214,10 @@ const syncDataTableList = async (data: DataTableModel) => { height="1.25rem" />

- {{ storeState.currentDataTable.name }} + {{ storeState.currentDataTable?.name }}

(); -const widgetGenerateStore = useWidgetGenerateStore(); -const widgetGenerateState = widgetGenerateStore.state; /* Query */ -const { - dataTableList, -} = useWidgetFormQuery({ - widgetId: computed(() => widgetGenerateState.widgetId), -}); +const currentDataTable = useWidgetDataTableQuery(computed(() => props.originData?.data_table_id)); -const storeState = reactive({ - currentDataTable: computed|undefined>(() => dataTableList.value.find((d) => d.data_table_id === dataTableInfo.value.dataTableId)), -}); const dataTableInfo = ref({ dataTableId: props.originData?.data_table_id, @@ -68,7 +52,7 @@ const state = reactive({ const fieldNames = state.refinedLabels.map((label) => label.name); if (fieldNames.includes(DATE_FIELD)) return true; if (fieldNames.length !== new Set(fieldNames).size) return true; - if (state.refinedLabels.some((d) => !isFieldNameValid(d.name, storeState.currentDataTable))) return true; + if (state.refinedLabels.some((d) => !isFieldNameValid(d.name, currentDataTable.data.value))) return true; return false; }), }); @@ -85,7 +69,7 @@ const getInvalidText = (idx: number): TranslateResult|undefined => { if (state.refinedLabels.some((label, lIdx) => lIdx !== idx && label.name === targetName)) { return i18n.t('COMMON.WIDGETS.DATA_TABLE.FORM.ADD_LABELS.DUPLICATED_LABEL'); } - if (!isFieldNameValid(targetName, storeState.currentDataTable)) { + if (!isFieldNameValid(targetName, currentDataTable.data.value)) { return i18n.t('COMMON.WIDGETS.DATA_TABLE.FORM.DUPLICATED_FIELD_NAME'); } return undefined; diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformAggregate.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformAggregate.vue index b2bac9bb7a..5a3e440fae 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformAggregate.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformAggregate.vue @@ -18,7 +18,7 @@ import { showErrorMessage } from '@/lib/helper/notice-alert-helper'; import { useProxyValue } from '@/common/composables/proxy-state'; import WidgetFormDataTableCardTransformFormWrapper from '@/common/modules/widgets/_components/WidgetFormDataTableCardTransformFormWrapper.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR, } from '@/common/modules/widgets/_constants/data-table-constant'; @@ -40,7 +40,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformContents.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformContents.vue index 09826559f2..1f4f445748 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformContents.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformContents.vue @@ -3,7 +3,7 @@ import { computed, defineExpose, onMounted, reactive, watch, } from 'vue'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { cloneDeep, intersection, isEmpty, isEqual, } from 'lodash'; @@ -14,6 +14,7 @@ import type { PrivateDataTableModel } from '@/api-clients/dashboard/private-data import type { DataTableDeleteParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/delete'; import type { DataTableTransformParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/transform'; import type { PublicDataTableModel } from '@/api-clients/dashboard/public-data-table/schema/model'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; import { i18n } from '@/translations'; import { showErrorMessage, showSuccessMessage } from '@/lib/helper/notice-alert-helper'; @@ -43,11 +44,13 @@ import WidgetFormDataTableCardTransformValueMapping import { useDataTableCascadeUpdate, } from '@/common/modules/widgets/_composables/use-data-table-cascade-update'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; +import { useWidgetQuery } from '@/common/modules/widgets/_composables/use-widget-query'; import { - DATA_TABLE_TYPE, type DATA_TABLE_OPERATOR, DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP, + DATA_TABLE_TYPE, DATA_TABLE_OPERATOR, DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP, } from '@/common/modules/widgets/_constants/data-table-constant'; import { sanitizeWidgetOptions } from '@/common/modules/widgets/_helpers/widget-options-helper'; +import { useWidgetContextStore } from '@/common/modules/widgets/_store/widget-context-store'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { DataTableAlertModalMode, TransformDataTableInfo, @@ -59,11 +62,6 @@ import type { JoinOptions, ValueMappingOptions, ConcatOptions, AggregateOptions, AggregateFunction, } from '@/common/modules/widgets/types/widget-model'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; - - - @@ -75,27 +73,30 @@ interface Props { type DataTableModel = PublicDataTableModel|PrivateDataTableModel; const props = defineProps(); +const widgetContextStore = useWidgetContextStore(); +const widgetContextState = widgetContextStore.state; const widgetGenerateStore = useWidgetGenerateStore(); const widgetGenerateState = widgetGenerateStore.state; -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; /* Querys */ const { - dashboard, -} = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), + widget, + keys: widgetKeys, + fetcher: widgetFetcher, +} = useWidgetQuery({ + widgetId: computed(() => widgetGenerateState.widgetId), }); const { - widget, - dataTableList, api, - keys, - fetcher, - queryClient, -} = useWidgetFormQuery({ + keys: dataTableKeys, + fetcher: dataTableFetcher, + dataTableList, +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); +const queryClient = useQueryClient(); + + const { cascadeUpdateDataTable, } = useDataTableCascadeUpdate({ @@ -191,9 +192,20 @@ const getAggregateFunctionMap = () => { }, {} as AggregateFunction); }; + +/* Query Keys */ +const { withSuffix: privateDataTableGetQueryKey } = useServiceQueryKey('dashboard', 'private-data-table', 'get'); +const { withSuffix: publicDataTableGetQueryKey } = useServiceQueryKey('dashboard', 'public-data-table', 'get'); +const { withSuffix: privateDataTableLoadQueryKey } = useServiceQueryKey('dashboard', 'private-data-table', 'load'); +const { withSuffix: publicDataTableLoadQueryKey } = useServiceQueryKey('dashboard', 'public-data-table', 'load'); +const { withSuffix: privateWidgetLoadQueryKey } = useServiceQueryKey('dashboard', 'private-widget', 'load'); +const { withSuffix: publicWidgetLoadQueryKey } = useServiceQueryKey('dashboard', 'public-widget', 'load'); +const { withSuffix: privateWidgetLoadSumQueryKey } = useServiceQueryKey('dashboard', 'private-widget', 'load-sum'); +const { withSuffix: publicWidgetLoadSumQueryKey } = useServiceQueryKey('dashboard', 'public-widget', 'load-sum'); + /* APIs */ const syncDataTableList = async (data: DataTableModel, unsavedId?: string) => { - const dataTableListQueryKey = state.isPrivate ? keys.privateDataTableListQueryKey : keys.publicDataTableListQueryKey; + const dataTableListQueryKey = state.isPrivate ? dataTableKeys.privateDataTableListQueryKey : dataTableKeys.publicDataTableListQueryKey; await queryClient.setQueryData(dataTableListQueryKey.value, (oldData: ListResponse) => { if (oldData.results) { return { @@ -210,31 +222,26 @@ const syncDataTableList = async (data: DataTableModel, unsavedId?: string) => { }); }; const invalidateLoadQueries = async (data: DataTableModel) => { - await queryClient.invalidateQueries({ - queryKey: [ - ...(state.isPrivate ? keys.privateDataTableLoadQueryKey.value : keys.publicDataTableLoadQueryKey.value), - data.data_table_id, - ], - }); - await queryClient.invalidateQueries({ - queryKey: [ - ...(state.isPrivate ? keys.privateWidgetLoadQueryKey.value : keys.publicWidgetLoadQueryKey.value), - dashboardDetailState.dashboardId, - widgetGenerateState.widgetId, - ], - }); - await queryClient.invalidateQueries({ - queryKey: [ - ...(state.isPrivate ? keys.privateWidgetLoadSumQueryKey.value : keys.publicWidgetLoadSumQueryKey.value), - dashboardDetailState.dashboardId, - widgetGenerateState.widgetId, - ], - }); + if (!widgetGenerateState.widgetId) return; + if (data.data_table_id.startsWith('private')) { + await Promise.all([ + queryClient.invalidateQueries({ queryKey: privateDataTableLoadQueryKey(state.dataTableId) }), + queryClient.invalidateQueries({ queryKey: privateWidgetLoadQueryKey(widgetGenerateState.widgetId) }), + queryClient.invalidateQueries({ queryKey: privateWidgetLoadSumQueryKey(widgetGenerateState.widgetId) }), + ]); + } else { + await Promise.all([ + queryClient.invalidateQueries({ queryKey: publicDataTableLoadQueryKey(state.dataTableId) }), + queryClient.invalidateQueries({ queryKey: publicWidgetLoadQueryKey(widgetGenerateState.widgetId) }), + queryClient.invalidateQueries({ queryKey: publicWidgetLoadSumQueryKey(widgetGenerateState.widgetId) }), + ]); + } }; const { mutateAsync: updateDataTableMutation } = useMutation({ - mutationFn: fetcher.updateDataTableFn, + mutationFn: dataTableFetcher.updateDataTableFn, onSuccess: async (data) => { await syncDataTableList(data); + await queryClient.invalidateQueries({ queryKey: state.isPrivate ? privateDataTableGetQueryKey(data.data_table_id) : publicDataTableGetQueryKey(data.data_table_id) }); await invalidateLoadQueries(data); setFailStatus(false); @@ -246,11 +253,11 @@ const { mutateAsync: updateDataTableMutation } = useMutation({ }, }); const { mutateAsync: updateWidget } = useMutation({ - mutationFn: fetcher.updateWidgetFn, + mutationFn: widgetFetcher.updateWidgetFn, onSuccess: (data) => { const widgetQueryKey = widgetGenerateState.widgetId?.startsWith('private') - ? keys.privateWidgetGetQueryKey - : keys.publicWidgetGetQueryKey; + ? widgetKeys.privateWidgetGetQueryKey + : widgetKeys.publicWidgetGetQueryKey; queryClient.setQueryData(widgetQueryKey.value, () => data); }, onError: (e) => { @@ -343,11 +350,14 @@ const updateDataTable = async (): Promise => { } }; if (firstUpdating) { + if (!widgetGenerateState.widgetId) { + throw new Error('Widget ID is required'); + } const createParams = { name: state.dataTableName, widget_id: widgetGenerateState.widgetId, operator: state.operator, - vars: dashboard.value?.vars || {}, + vars: widgetContextState.dashboard?.vars || {}, options: { [state.operator]: options() }, }; const dataTable = await transformDataTableFn(createParams); @@ -421,6 +431,9 @@ const handleCancelModal = () => { modalState.visible = false; }; const handleUpdateDataTable = async () => { + if (!widgetGenerateState.widgetId) { + throw new Error('Widget ID is required'); + } state.loading = true; const result = await updateDataTable(); if (result) { @@ -448,7 +461,7 @@ const clearDataTableInvalidStatus = async (dataTableId: string) => { delete _allDataTableInvalidMap[dataTableId]; widgetGenerateStore.setAllDataTableInvalidMap(_allDataTableInvalidMap); - const dataTableListQueryKey = state.isPrivate ? keys.privateDataTableListQueryKey : keys.publicDataTableListQueryKey; + const dataTableListQueryKey = state.isPrivate ? dataTableKeys.privateDataTableListQueryKey : dataTableKeys.publicDataTableListQueryKey; await queryClient.setQueryData(dataTableListQueryKey.value, (oldData: ListResponse) => { if (oldData.results) { return { diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformDataTableDropdown.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformDataTableDropdown.vue index 4cff59106e..65569beee9 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformDataTableDropdown.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformDataTableDropdown.vue @@ -9,7 +9,7 @@ import { PI, PContextMenu, PFieldTitle } from '@cloudforet/mirinae'; import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type'; import { useProxyValue } from '@/common/composables/proxy-state'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_TYPE } from '@/common/modules/widgets/_constants/data-table-constant'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { TransformDataTableInfo } from '@/common/modules/widgets/types/widget-data-table-type'; @@ -34,7 +34,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformEvaluate.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformEvaluate.vue index e942f3bbec..220c471d2e 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformEvaluate.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformEvaluate.vue @@ -22,7 +22,7 @@ import WidgetFormDataTableCardTransformFormWrapper from '@/common/modules/widgets/_components/WidgetFormDataTableCardTransformFormWrapper.vue'; import WidgetFormDataTableGlobalVariableViewButton from '@/common/modules/widgets/_components/WidgetFormDataTableGlobalVariableViewButton.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_FIELD_TYPE, DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { TransformDataTableInfo, TransformDataTableProps } from '@/common/modules/widgets/types/widget-data-table-type'; @@ -52,7 +52,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformJoin.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformJoin.vue index 335ff707f2..65c94e75f3 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformJoin.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformJoin.vue @@ -13,7 +13,7 @@ import type { SelectDropdownMenuItem } from '@cloudforet/mirinae/types/controls/ import { useProxyValue } from '@/common/composables/proxy-state'; import WidgetFormDataTableCardTransformFormWrapper from '@/common/modules/widgets/_components/WidgetFormDataTableCardTransformFormWrapper.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR, JOIN_TYPE, } from '@/common/modules/widgets/_constants/data-table-constant'; @@ -47,7 +47,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformPivotForm.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformPivotForm.vue index 7d4f8ee90e..cd5e50b501 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformPivotForm.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformPivotForm.vue @@ -18,7 +18,7 @@ import { showErrorMessage } from '@/lib/helper/notice-alert-helper'; import { useProxyValue } from '@/common/composables/proxy-state'; import WidgetFormDataTableCardTransformFormWrapper from '@/common/modules/widgets/_components/WidgetFormDataTableCardTransformFormWrapper.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR, DEFAULT_TRANSFORM_DATA_TABLE_VALUE_MAP, } from '@/common/modules/widgets/_constants/data-table-constant'; @@ -39,7 +39,7 @@ const widgetGenerateState = widgetGenerateStore.state; const { dataTableList, api, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformValueMapping.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformValueMapping.vue index 9ddd1aca9b..ec768d3f77 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformValueMapping.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableCardTransformValueMapping.vue @@ -19,7 +19,7 @@ import { i18n } from '@/translations'; import { useProxyValue } from '@/common/composables/proxy-state'; import WidgetFormDataTableCardTransformFormWrapper from '@/common/modules/widgets/_components/WidgetFormDataTableCardTransformFormWrapper.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_FIELD_TYPE, DATA_TABLE_OPERATOR, @@ -46,7 +46,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); @@ -119,7 +119,7 @@ const getInvalidFieldNameText = (fieldName?: string): TranslateResult|undefined if (!isFieldNameValid(fieldName, storeState.currentDataTable)) return i18n.t('COMMON.WIDGETS.DATA_TABLE.FORM.DUPLICATED_FIELD_NAME'); return undefined; }; -const isFieldNameValid = (fieldName: string, dataTable?: PublicDataTableModel|PrivateDataTableModel): boolean => { +const isFieldNameValid = (fieldName: string, dataTable?: Partial): boolean => { if (!dataTable) return true; const _dataInfoKeys = Object.keys(dataTable.data_info || {}); return !_dataInfoKeys.includes(fieldName); diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableGlobalVariableViewButton.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableGlobalVariableViewButton.vue index 92686f51fe..5ba2d6f6aa 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableGlobalVariableViewButton.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormDataTableGlobalVariableViewButton.vue @@ -2,26 +2,21 @@ import { computed, reactive } from 'vue'; - import { PButton, PPopover, PCopyButton } from '@cloudforet/mirinae'; import type { DashboardGlobalVariable } from '@/api-clients/dashboard/_types/dashboard-global-variable-type'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; -import { getOrderedGlobalVariables } from '@/services/dashboards/helpers/dashboard-global-variables-helper'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; +import { useWidgetContextStore } from '@/common/modules/widgets/_store/widget-context-store'; -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; +import { getOrderedGlobalVariables } from '@/services/_shared/dashboard/dashboard-detail/helpers/dashboard-global-variables-helper'; -const { dashboard } = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), -}); +const widgetContextStore = useWidgetContextStore(); +const widgetContextState = widgetContextStore.state; const state = reactive({ popperVisible: false, variableItems: computed(() => { - const _refinedProperties: DashboardGlobalVariable[] = Object.values(dashboard.value?.vars_schema?.properties || {}) + const _refinedProperties: DashboardGlobalVariable[] = Object.values(widgetContextState.dashboard?.vars_schema?.properties || {}) .map((property) => ({ key: property.key, name: property.name, diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlay.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlay.vue index 8ce39dc6ff..485cd42d4b 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlay.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlay.vue @@ -4,7 +4,7 @@ import { } from 'vue'; import type { TranslateResult } from 'vue-i18n'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { cloneDeep } from 'lodash'; import { @@ -21,17 +21,13 @@ import { showErrorMessage } from '@/lib/helper/notice-alert-helper'; import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetFormOverlayStep1 from '@/common/modules/widgets/_components/WidgetFormOverlayStep1.vue'; import WidgetFormOverlayStep2 from '@/common/modules/widgets/_components/WidgetFormOverlayStep2.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; +import { useWidgetQuery } from '@/common/modules/widgets/_composables/use-widget-query'; import { UNSUPPORTED_CHARTS_IN_PIVOT } from '@/common/modules/widgets/_constants/widget-constant'; import { sanitizeWidgetOptions } from '@/common/modules/widgets/_helpers/widget-options-helper'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; - - -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; const widgetGenerateStore = useWidgetGenerateStore(); const widgetGenerateGetters = widgetGenerateStore.getters; const widgetGenerateState = widgetGenerateStore.state; @@ -39,14 +35,18 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { widget, - dataTableList, api, keys, fetcher, - queryClient, -} = useWidgetFormQuery({ +} = useWidgetQuery({ + widgetId: computed(() => widgetGenerateState.widgetId), +}); +const { + dataTableList, +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); +const queryClient = useQueryClient(); const state = reactive({ selectedDataTable: computed(() => dataTableList.value?.find((item) => item.data_table_id === widgetGenerateState.selectedDataTableId)), @@ -95,7 +95,7 @@ const state = reactive({ /* Api */ const deleteWidget = async (widgetId: string) => { if (!widgetId) return; - const isPrivate = dashboardDetailState.dashboardId?.startsWith('private'); + const isPrivate = widgetId?.startsWith('private'); const _fetcher = isPrivate ? api.privateWidgetAPI.delete : api.publicWidgetAPI.delete; diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayPreviewTable.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayPreviewTable.vue index c32d241f95..002d1743fc 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayPreviewTable.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayPreviewTable.vue @@ -3,8 +3,8 @@ import { computed, onUnmounted, reactive, watch, } from 'vue'; +import { useRoute } from 'vue-router/composables'; -import { useQuery } from '@tanstack/vue-query'; import bytes from 'bytes'; import { sortBy } from 'lodash'; @@ -24,23 +24,21 @@ import { i18n } from '@/translations'; import { useAllReferenceStore } from '@/store/reference/all-reference-store'; import type { ProjectReferenceMap } from '@/store/reference/project-reference-store'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useDataTableLoadQuery } from '@/common/modules/widgets/_composables/use-data-table-load-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; -import { REFERENCE_FIELD_MAP, WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; -import { - normalizeAndSerializeVars, -} from '@/common/modules/widgets/_helpers/global-variable-helper'; +import { REFERENCE_FIELD_MAP } from '@/common/modules/widgets/_constants/widget-constant'; import { sortWidgetTableFields } from '@/common/modules/widgets/_helpers/widget-helper'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { DataInfo } from '@/common/modules/widgets/types/widget-model'; import { gray, white } from '@/styles/colors'; +import { useDashboardRefinedVars } from '@/services/_shared/dashboard/dashboard-detail/contextual-composables/use-dashboard-refined-vars'; import { SIZE_UNITS } from '@/services/asset-inventory/constants/asset-analysis-constant'; import { GRANULARITY } from '@/services/cost-explorer/constants/cost-explorer-constant'; import type { Granularity } from '@/services/cost-explorer/types/cost-explorer-query-type'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; + @@ -57,20 +55,16 @@ type DataTableModel = PublicDataTableModel|PrivateDataTableModel; const widgetGenerateStore = useWidgetGenerateStore(); const widgetGenerateState = widgetGenerateStore.state; const allReferenceStore = useAllReferenceStore(); -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; +const route = useRoute(); +const dashboardId = computed(() => route.params.dashboardId); +const { refinedVars } = useDashboardRefinedVars(dashboardId); /* Query */ const { dataTableList, - api, - keys, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); -const { dashboard } = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), -}); const storeState = reactive({ selectedDataTableId: computed(() => widgetGenerateState.selectedDataTableId), @@ -252,50 +246,16 @@ const getSortIcon = (field: PreviewTableField) => { // return ''; }; -// const getTimeDiffSubText = (field: PreviewTableField): string => { -// if (!state.dataInfo?.[field.name]) return ''; -// const { timediff } = state.dataInfo[field.name]; -// if (!timediff || !Object.entries(timediff ?? {}).length) return ''; -// const [key, value] = Object.entries(timediff)[0]; -// return `( ${value} ${key} )`; -// }; - -const fetchWidgetData = async (params: DataTableLoadParameters): Promise => { - const defaultFetcher = state.isPrivate - ? api.privateDataTableAPI.load - : api.publicDataTableAPI.load; - const res = await defaultFetcher(params); - return res; -}; - -const queryKey = computed(() => [ - ...(state.isPrivate ? keys.privateDataTableLoadQueryKey.value : keys.publicDataTableLoadQueryKey.value), - storeState.selectedDataTableId, - { - granularity: state.selectedGranularity, - // dataTableOptions: normalizeAndSerializeDataTableOptions(state.selectedDataTable?.options), - // dataTables: normalizeAndSerializeDataTableOptions((dataTableList.value || []).map((d) => d?.options || {})), - sortBy: state.sortBy, - thisPage: state.thisPage, - pageSize: state.pageSize, - vars: normalizeAndSerializeVars(dashboard.value?.vars ?? {}), - }, -]); - -const queryResult = useQuery({ - queryKey, - queryFn: () => fetchWidgetData({ - data_table_id: storeState.selectedDataTableId, +const queryResult = useDataTableLoadQuery({ + dataTableId: computed(() => storeState.selectedDataTableId), + params: computed(() => ({ + data_table_id: storeState.selectedDataTableId as string, granularity: state.selectedGranularity, sort: state.sortBy, page: state.page, - vars: dashboard.value?.vars, - }), - enabled: computed(() => storeState.selectedDataTableId !== undefined && state.selectedDataTable !== undefined), - staleTime: WIDGET_LOAD_STALE_TIME, - retry: 2, + vars: refinedVars.value, + })), }); - const dataTableLoading = computed(() => queryResult.isLoading.value || queryResult.isFetching.value); const isError = computed(() => queryResult.isError.value); const errorMessage = computed(() => queryResult.error?.value?.message); diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep1.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep1.vue index b5a5b2a111..54023d0a27 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep1.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep1.vue @@ -19,7 +19,7 @@ import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetFormDataSourcePopover from '@/common/modules/widgets/_components/WidgetFormDataSourcePopover.vue'; import WidgetFormDataTableCard from '@/common/modules/widgets/_components/WidgetFormDataTableCard.vue'; import WidgetFormOverlayPreviewTable from '@/common/modules/widgets/_components/WidgetFormOverlayPreviewTable.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { createDataTableReferenceMap, getDataTableReferenceMapExecutionOrder, @@ -40,7 +40,7 @@ const scrollContainerRef = ref(null); /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep2.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep2.vue index 31d14e6fbc..d8df4af368 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep2.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep2.vue @@ -3,7 +3,7 @@ import { computed, onBeforeMount, onUnmounted, reactive, ref, watch, } from 'vue'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { cloneDeep, isEqual } from 'lodash'; import { @@ -11,8 +11,12 @@ import { } from '@cloudforet/mirinae'; import type { - DashboardOptions, DashboardVars, + DashboardModel, + DashboardOptions, DashboardUpdateParams, DashboardVars, } from '@/api-clients/dashboard/_types/dashboard-type'; +import { usePrivateDashboardApi } from '@/api-clients/dashboard/private-dashboard/composables/use-private-dashboard-api'; +import { usePublicDashboardApi } from '@/api-clients/dashboard/public-dashboard/composables/use-public-dashboard-api'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; import { i18n } from '@/translations'; import { useAppContextStore } from '@/store/app-context/app-context-store'; @@ -22,38 +26,52 @@ import { showErrorMessage } from '@/lib/helper/notice-alert-helper'; import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetFormOverlayStep2WidgetForm from '@/common/modules/widgets/_components/WidgetFormOverlayStep2WidgetForm.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { useWidgetOptionsComplexValidation } from '@/common/modules/widgets/_composables/use-widget-options-complex-validation'; +import { useWidgetQuery } from '@/common/modules/widgets/_composables/use-widget-query'; import { WIDGET_WIDTH_RANGE_LIST } from '@/common/modules/widgets/_constants/widget-display-constant'; import { getWidgetComponent } from '@/common/modules/widgets/_helpers/widget-component-helper'; import { getWidgetConfig } from '@/common/modules/widgets/_helpers/widget-config-helper'; import { sanitizeWidgetOptions } from '@/common/modules/widgets/_helpers/widget-options-helper'; +import { useWidgetContextStore } from '@/common/modules/widgets/_store/widget-context-store'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import WidgetFieldValueManager from '@/common/modules/widgets/_widget-field-value-manager'; import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; import type { WidgetType } from '@/common/modules/widgets/types/widget-model'; -import DashboardToolsetDateDropdown from '@/services/dashboards/components/dashboard-detail/DashboardToolsetDateDropdown.vue'; -import DashboardVariablesV2 from '@/services/dashboards/components/dashboard-detail/DashboardVariablesV2.vue'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; +import DashboardToolsetDateDropdown from '@/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetDateDropdown.vue'; +import { useDashboardWidgetListQuery } from '@/services/_shared/dashboard/dashboard-detail/composables/use-dashboard-widget-list-query'; +import DashboardVariablesV2 from '@/services/_shared/dashboard/dashboard-detail/contextual-components/DashboardVariablesV2.vue'; +import { useDashboardRefinedVars } from '@/services/_shared/dashboard/dashboard-detail/contextual-composables/use-dashboard-refined-vars'; +import { useDashboardDetailInfoStore } from '@/services/_shared/dashboard/dashboard-detail/stores/dashboard-detail-info-store'; +import { useDashboardVarsStore } from '@/services/_shared/dashboard/dashboard-detail/stores/dashboard-vars-store'; import type { AllReferenceTypeInfo } from '@/services/dashboards/stores/all-reference-type-info-store'; import { useAllReferenceTypeInfoStore, } from '@/services/dashboards/stores/all-reference-type-info-store'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; - - const overlayWidgetRef = ref(null); const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; -const dashboardDetailGetters = dashboardDetailStore.getters; const widgetGenerateStore = useWidgetGenerateStore(); const widgetGenerateState = widgetGenerateStore.state; +const dashboardVarsStore = useDashboardVarsStore(); const allReferenceTypeInfoStore = useAllReferenceTypeInfoStore(); const appContextStore = useAppContextStore(); +const widgetContextStore = useWidgetContextStore(); +const widgetContextGetters = widgetContextStore.getters; +const widgetContextState = widgetContextStore.state; +const { + publicDashboardAPI, +} = usePublicDashboardApi(); +const { + privateDashboardAPI, +} = usePrivateDashboardApi(); + const emit = defineEmits<{(event: 'watch-options-changed', value: boolean): void;}>(); +const dashboard = computed(() => widgetContextState.dashboard); +const dashboardId = computed(() => widgetContextGetters.dashboardId); +const { refinedVars } = useDashboardRefinedVars(dashboardId); const storeState = reactive({ isAdminMode: computed(() => appContextStore.getters.isAdminMode), @@ -61,21 +79,23 @@ const storeState = reactive({ /* Query */ const { - dashboard, widgetList, - keys, - fetcher, - queryClient, -} = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), +} = useDashboardWidgetListQuery({ + dashboardId, }); const { widget, - dataTableList, keys: widgetKeys, fetcher: wigetFetcher, widgetLoading, -} = useWidgetFormQuery({ +} = useWidgetQuery({ + widgetId: computed(() => widgetGenerateState.widgetId), +}); +const queryClient = useQueryClient(); + +const { + dataTableList, +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); @@ -175,6 +195,10 @@ const updateWidget = async () => { } if (_isCreating || state.isDashboardLayoutChanged) { + if (!dashboardId.value) { + console.error('dashboard is not found'); + return; + } const _layouts = cloneDeep(dashboard.value?.layouts || []); if (_layouts.length) { const _targetLayout = _layouts[0]; @@ -192,19 +216,23 @@ const updateWidget = async () => { }); } updateDashboard({ - dashboard_id: dashboardDetailState.dashboardId, + dashboard_id: dashboardId.value, layouts: _layouts, }); } }; +const { withSuffix: publicDashboardGetQueryKeyWithSuffix } = useServiceQueryKey('dashboard', 'public-dashboard', 'get'); +const { withSuffix: privateDashboardGetQueryKeyWithSuffix } = useServiceQueryKey('dashboard', 'private-dashboard', 'get'); +const updateDashboardFn = (params: DashboardUpdateParams): Promise => (state.isPrivate ? privateDashboardAPI.update(params) : publicDashboardAPI.update(params)); const { mutate: updateDashboard } = useMutation( { - mutationFn: fetcher.updateDashboardFn, - onSuccess: (data) => { - const dashboardQueryKey = state.isPrivate ? keys.privateDashboardGetQueryKey : keys.publicDashboardGetQueryKey; - // queryClient.invalidateQueries({ queryKey: dashboardQueryKey.value }); - queryClient.setQueryData(dashboardQueryKey.value, () => data); + mutationFn: updateDashboardFn, + onSuccess: (_, variables) => { + const dashboardQueryKey = state.isPrivate + ? privateDashboardGetQueryKeyWithSuffix(variables.dashboard_id) + : publicDashboardGetQueryKeyWithSuffix(variables.dashboard_id); + queryClient.invalidateQueries({ queryKey: dashboardQueryKey }); }, }, ); @@ -234,28 +262,12 @@ const sanitizeAndSortWidgets = (_layoutWidgets: string[] = [], _widgetList: stri const initSnapshot = () => { state.varsSnapshot = cloneDeep(dashboard.value?.vars || {}); - state.dashboardOptionsSnapshot = cloneDeep(dashboardDetailState.options); + state.dashboardOptionsSnapshot = cloneDeep(dashboard.value?.options || {}); }; const reset = () => { - dashboardDetailStore.setVars(state.varsSnapshot); + dashboardVarsStore.setVars(state.varsSnapshot); dashboardDetailStore.setOptions(state.dashboardOptionsSnapshot); }; -// const loadOverlayWidget = async () => { -// await queryClient.invalidateQueries({ -// queryKey: [ -// ...(state.isPrivate ? widgetKeys.privateWidgetLoadQueryKey.value : widgetKeys.publicWidgetLoadQueryKey.value), -// dashboardDetailState.dashboardId, -// widgetGenerateState.widgetId, -// ], -// }); -// await queryClient.invalidateQueries({ -// queryKey: [ -// ...(state.isPrivate ? widgetKeys.privateWidgetLoadSumQueryKey.value : widgetKeys.publicWidgetLoadSumQueryKey.value), -// dashboardDetailState.dashboardId, -// widgetGenerateState.widgetId, -// ], -// }); -// }; /* Event */ const handleChangeWidgetSize = (widgetSize: string) => { @@ -321,6 +333,7 @@ onUnmounted(() => { /> @@ -362,9 +375,9 @@ onUnmounted(() => { :width="state.widgetWidth" :widget-options="widget?.options" :data-tables="dataTableList" - :dashboard-options="dashboardDetailState.options" - :dashboard-vars="dashboardDetailGetters.refinedVars" - :dashboard-id="dashboardDetailState.dashboardId" + :dashboard-options="dashboard?.options" + :dashboard-vars="refinedVars" + :dashboard-id="dashboardId" :all-reference-type-info="state.allReferenceTypeInfo" disable-refresh-on-loading mode="overlay" diff --git a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep2WidgetForm.vue b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep2WidgetForm.vue index 1c80078112..f0d9fa381d 100644 --- a/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep2WidgetForm.vue +++ b/apps/web/src/common/modules/widgets/_components/WidgetFormOverlayStep2WidgetForm.vue @@ -4,7 +4,7 @@ import { } from 'vue'; import type { TranslateResult } from 'vue-i18n'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { cloneDeep, sortBy } from 'lodash'; import { @@ -19,7 +19,8 @@ import { showErrorMessage } from '@/lib/helper/notice-alert-helper'; import NewMark from '@/common/components/marks/NewMark.vue'; import ErrorHandler from '@/common/composables/error/errorHandler'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; +import { useWidgetQuery } from '@/common/modules/widgets/_composables/use-widget-query'; import { DATA_TABLE_OPERATOR, DATA_TABLE_TYPE } from '@/common/modules/widgets/_constants/data-table-constant'; import { WIDGET_COMPONENT_ICON_MAP } from '@/common/modules/widgets/_constants/widget-components-constant'; import { CONSOLE_WIDGET_CONFIG } from '@/common/modules/widgets/_constants/widget-config-list-constant'; @@ -61,13 +62,17 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { - dataTableList, fetcher, keys, - queryClient, -} = useWidgetFormQuery({ +} = useWidgetQuery({ + widgetId: computed(() => widgetGenerateState.widgetId), +}); +const { + dataTableList, +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); +const queryClient = useQueryClient(); const state = reactive({ selectedDataTable: computed(() => dataTableList.value.find((d) => d.data_table_id === widgetGenerateState.selectedDataTableId)), @@ -115,7 +120,7 @@ const { mutateAsync: updateWidget } = useMutation({ onSuccess: (data) => { const widgetQueryKey = widgetGenerateState.widgetId?.startsWith('private') ? keys.privateWidgetGetQueryKey - : keys.publicWidgetGteQueryKey; + : keys.publicWidgetGetQueryKey; queryClient.setQueryData(widgetQueryKey.value, () => data); }, onError: (e) => { diff --git a/apps/web/src/common/modules/widgets/_composables/use-data-table-cascade-update.ts b/apps/web/src/common/modules/widgets/_composables/use-data-table-cascade-update.ts index bfeac9b62f..3f307da111 100644 --- a/apps/web/src/common/modules/widgets/_composables/use-data-table-cascade-update.ts +++ b/apps/web/src/common/modules/widgets/_composables/use-data-table-cascade-update.ts @@ -3,15 +3,20 @@ import { computed, reactive, } from 'vue'; +import { useQueryClient } from '@tanstack/vue-query'; + import type { ListResponse } from '@/api-clients/_common/schema/api-verbs/list'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; import ErrorHandler from '@/common/composables/error/errorHandler'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { createDataTableReferenceMap } from '@/common/modules/widgets/_helpers/widget-data-table-helper'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { DataTableModel, DataTableReference } from '@/common/modules/widgets/types/widget-data-table-type'; + + interface UseDataTableCascadeUpdateOptions { widgetId: ComputedRef; } @@ -26,25 +31,27 @@ export const useDataTableCascadeUpdate = ({ widgetId }: UseDataTableCascadeUpdat /* Query */ const { - dataTableList, - fetcher, keys, - queryClient, - } = useWidgetFormQuery({ + fetcher, + dataTableList, + } = useWidgetDataTableListQuery({ widgetId: computed(() => widgetId.value), }); + const queryClient = useQueryClient(); const _state = reactive({ isPrivate: computed(() => !!widgetId.value?.startsWith('private')), dataTableReferenceMap: computed>(() => createDataTableReferenceMap(dataTableList.value)), }); + const { withSuffix: privateDataTableLoadWithSuffix } = useServiceQueryKey('dashboard', 'private-data-table', 'load'); + const { withSuffix: publicDataTableLoadWithSuffix } = useServiceQueryKey('dashboard', 'public-data-table', 'load'); + const { withSuffix: privateDataTableGetQueryKey } = useServiceQueryKey('dashboard', 'private-data-table', 'get'); + const { withSuffix: publicDataTableGetQueryKey } = useServiceQueryKey('dashboard', 'public-data-table', 'get'); + const _invalidateLoadQueries = async (data: DataTableModel) => { await queryClient.invalidateQueries({ - queryKey: [ - ...(_state.isPrivate ? keys.privateDataTableLoadQueryKey.value : keys.publicDataTableLoadQueryKey.value), - data.data_table_id, - ], + queryKey: _state.isPrivate ? privateDataTableLoadWithSuffix(data.data_table_id) : publicDataTableLoadWithSuffix(data.data_table_id), }); }; @@ -82,6 +89,7 @@ export const useDataTableCascadeUpdate = ({ widgetId }: UseDataTableCascadeUpdat } return oldData; }); + await queryClient.invalidateQueries({ queryKey: _state.isPrivate ? privateDataTableGetQueryKey(result.data_table_id) : publicDataTableGetQueryKey(result.data_table_id) }); await _invalidateLoadQueries(result); await cascadeUpdateDataTable(childId); diff --git a/apps/web/src/common/modules/widgets/_composables/use-data-table-load-query.ts b/apps/web/src/common/modules/widgets/_composables/use-data-table-load-query.ts new file mode 100644 index 0000000000..7e13c6ef66 --- /dev/null +++ b/apps/web/src/common/modules/widgets/_composables/use-data-table-load-query.ts @@ -0,0 +1,54 @@ +import type { ComputedRef } from 'vue'; +import { computed } from 'vue'; + +import { usePrivateDataTableApi } from '@/api-clients/dashboard/private-data-table/composables/use-private-data-table-api'; +import { usePublicDataTableApi } from '@/api-clients/dashboard/public-data-table/composables/use-public-data-table-api'; +import type { DataTableLoadParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/load'; +import { useScopedQuery } from '@/query/composables/use-scoped-query'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; + +import { WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; + +interface UseDataTableLoadQueryOptions { + dataTableId: ComputedRef; + params: ComputedRef; +} + +export const useDataTableLoadQuery = (options: UseDataTableLoadQueryOptions) => { + const { + dataTableId, + params, + } = options; + + const { publicDataTableAPI } = usePublicDataTableApi(); + const { privateDataTableAPI } = usePrivateDataTableApi(); + + const isPrivate = computed(() => !!dataTableId?.value?.startsWith('private')); + + const { key: privateDataTableLoadQueryKey, params: privateDataTableLoadParams } = useServiceQueryKey('dashboard', 'private-data-table', 'load', { + contextKey: dataTableId, + params, + }); + + const { key: publicDataTableLoadQueryKey, params: publicDataTableLoadParams } = useServiceQueryKey('dashboard', 'public-data-table', 'load', { + contextKey: dataTableId, + params, + }); + + + return useScopedQuery({ + queryKey: isPrivate.value ? privateDataTableLoadQueryKey : publicDataTableLoadQueryKey, + queryFn: () => { + if (!dataTableId.value) { + throw new Error('Selected data table id is undefined'); + } + if (isPrivate.value) { + return privateDataTableAPI.load(privateDataTableLoadParams.value); + } + return publicDataTableAPI.load(publicDataTableLoadParams.value); + }, + enabled: computed(() => dataTableId.value !== undefined), + staleTime: WIDGET_LOAD_STALE_TIME, + retry: 2, + }, ['WORKSPACE', 'DOMAIN']); +}; diff --git a/apps/web/src/common/modules/widgets/_composables/use-widget-data-table-list-query.ts b/apps/web/src/common/modules/widgets/_composables/use-widget-data-table-list-query.ts new file mode 100644 index 0000000000..1e1da9e641 --- /dev/null +++ b/apps/web/src/common/modules/widgets/_composables/use-widget-data-table-list-query.ts @@ -0,0 +1,109 @@ +import type { ComputedRef } from 'vue'; +import { computed } from 'vue'; + +import type { QueryKey } from '@tanstack/vue-query'; + +import { usePrivateDataTableApi } from '@/api-clients/dashboard/private-data-table/composables/use-private-data-table-api'; +import { usePublicDataTableApi } from '@/api-clients/dashboard/public-data-table/composables/use-public-data-table-api'; +import type { DataTableListParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/list'; +import type { DataTableUpdateParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/update'; +import { useScopedQuery } from '@/query/composables/use-scoped-query'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; + +import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; + +const DEFAULT_LIST_DATA = { results: [] }; +// const DEFAULT_LOAD_DATA = { results: {}, labels_info: {}, data_info: {} }; +const STALE_TIME = 1000 * 60 * 5; + +interface UseWidgetDataTableListQueryOptions { + widgetId: ComputedRef; +} + +interface UseWidgetDataTableListQueryReturn { + dataTableList: ComputedRef; + isLoading: ComputedRef; + keys: { + publicDataTableListQueryKey: ComputedRef; + privateDataTableListQueryKey: ComputedRef; + }; + api: { + publicDataTableAPI: ReturnType['publicDataTableAPI']; + privateDataTableAPI: ReturnType['privateDataTableAPI']; + }; + fetcher: { + updateDataTableFn: (params: DataTableUpdateParameters) => Promise; + }; +} + +export const useWidgetDataTableListQuery = ({ + widgetId, +}: UseWidgetDataTableListQueryOptions): UseWidgetDataTableListQueryReturn => { + const { + publicDataTableAPI, + } = usePublicDataTableApi(); + const { + privateDataTableAPI, + } = usePrivateDataTableApi(); + + const isPrivate = computed(() => !!widgetId?.value?.startsWith('private')); + + /* Query Keys */ + const { key: publicDataTableListQueryKey, params: publicDataTableListParams } = useServiceQueryKey('dashboard', 'public-data-table', 'list', { + contextKey: widgetId.value, + params: computed(() => ({ + widget_id: widgetId.value as string, + })), + }); + const { key: privateDataTableListQueryKey, params: privateDataTableListParams } = useServiceQueryKey('dashboard', 'private-data-table', 'list', { + contextKey: widgetId.value, + params: computed(() => ({ + widget_id: widgetId.value as string, + })), + }); + + /* Querys */ + const publicDataTableListQuery = useScopedQuery({ + queryKey: publicDataTableListQueryKey, + queryFn: () => publicDataTableAPI.list(publicDataTableListParams.value), + select: (data) => data?.results || [], + enabled: computed(() => !!widgetId?.value && !isPrivate.value), + initialData: DEFAULT_LIST_DATA, + initialDataUpdatedAt: 0, + staleTime: STALE_TIME, + }, ['DOMAIN', 'WORKSPACE']); + const privateDataTableListQuery = useScopedQuery({ + queryKey: privateDataTableListQueryKey, + queryFn: () => privateDataTableAPI.list(privateDataTableListParams.value), + select: (data) => data?.results || [], + enabled: computed(() => !!widgetId?.value && isPrivate.value), + initialData: DEFAULT_LIST_DATA, + initialDataUpdatedAt: 0, + staleTime: STALE_TIME, + }, ['WORKSPACE']); + + /* Fetchers */ + const updateDataTableFn = (params: DataTableUpdateParameters): Promise => { + if (isPrivate.value) { + return privateDataTableAPI.update(params); + } + return publicDataTableAPI.update(params); + }; + + + return { + dataTableList: computed(() => (isPrivate.value ? privateDataTableListQuery.data.value : publicDataTableListQuery.data.value) ?? []), + isLoading: computed(() => (isPrivate.value ? privateDataTableListQuery.isFetching.value : publicDataTableListQuery.isFetching.value)), + api: { + publicDataTableAPI, + privateDataTableAPI, + }, + keys: { + publicDataTableListQueryKey, + privateDataTableListQueryKey, + }, + fetcher: { + updateDataTableFn, + }, + }; +}; diff --git a/apps/web/src/common/modules/widgets/_composables/use-widget-data-table-query.ts b/apps/web/src/common/modules/widgets/_composables/use-widget-data-table-query.ts new file mode 100644 index 0000000000..959b66eaa7 --- /dev/null +++ b/apps/web/src/common/modules/widgets/_composables/use-widget-data-table-query.ts @@ -0,0 +1,59 @@ +import type { ComputedRef } from 'vue'; +import { computed } from 'vue'; + +import { usePrivateDataTableApi } from '@/api-clients/dashboard/private-data-table/composables/use-private-data-table-api'; +import { usePublicDataTableApi } from '@/api-clients/dashboard/public-data-table/composables/use-public-data-table-api'; +import { useScopedQuery } from '@/query/composables/use-scoped-query'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; + + +const STALE_TIME = 1000 * 60 * 5; // 5 minutes +const GC_TIME = 1000 * 60; // 1 minute + +export const useWidgetDataTableQuery = (dataTableId: ComputedRef) => { + const { publicDataTableAPI } = usePublicDataTableApi(); + const { privateDataTableAPI } = usePrivateDataTableApi(); + + const isPrivate = computed(() => dataTableId.value?.startsWith('private')); + + const { key: publicKey, params: publicParams } = useServiceQueryKey('dashboard', 'public-data-table', 'get', { + contextKey: dataTableId, + params: computed(() => ({ + data_table_id: dataTableId.value as string, + })), + }); + const { key: privateKey, params: privateParams } = useServiceQueryKey('dashboard', 'private-data-table', 'get', { + contextKey: dataTableId, + params: computed(() => ({ + data_table_id: dataTableId.value as string, + })), + }); + + const privateDataTableQuery = useScopedQuery({ + queryKey: privateKey, + queryFn: () => { + if (!privateParams.value.data_table_id) { + throw new Error('DataTable ID is required for fetching data'); + } + return privateDataTableAPI.get(privateParams.value); + }, + staleTime: STALE_TIME, + gcTime: GC_TIME, + enabled: computed(() => !!dataTableId.value && isPrivate.value), + }, ['WORKSPACE']); + const publicDataTableQuery = useScopedQuery({ + queryKey: publicKey, + queryFn: () => { + if (!publicParams.value.data_table_id) { + throw new Error('DataTable ID is required for fetching data'); + } + return publicDataTableAPI.get(publicParams.value); + }, + enabled: computed(() => !!dataTableId.value && !isPrivate.value), + staleTime: STALE_TIME, + gcTime: GC_TIME, + }, ['DOMAIN', 'WORKSPACE']); + + + return isPrivate.value ? privateDataTableQuery : publicDataTableQuery; +}; diff --git a/apps/web/src/common/modules/widgets/_composables/use-widget-form-query.ts b/apps/web/src/common/modules/widgets/_composables/use-widget-form-query.ts deleted file mode 100644 index 4c5bac911e..0000000000 --- a/apps/web/src/common/modules/widgets/_composables/use-widget-form-query.ts +++ /dev/null @@ -1,195 +0,0 @@ -import type { ComputedRef } from 'vue'; -import { computed } from 'vue'; - -import type { QueryClient, QueryKey } from '@tanstack/vue-query'; -import { useQueryClient } from '@tanstack/vue-query'; - -import { useScopedQuery } from '@/api-clients/_common/composables/use-scoped-query'; -import type { WidgetModel, WidgetUpdateParams } from '@/api-clients/dashboard/_types/widget-type'; -import { usePrivateDataTableApi } from '@/api-clients/dashboard/private-data-table/composables/use-private-data-table-api'; -import { usePrivateWidgetApi } from '@/api-clients/dashboard/private-widget/composables/use-private-widget-api'; -import { usePublicDataTableApi } from '@/api-clients/dashboard/public-data-table/composables/use-public-data-table-api'; -import type { DataTableUpdateParameters } from '@/api-clients/dashboard/public-data-table/schema/api-verbs/update'; -import { usePublicWidgetApi } from '@/api-clients/dashboard/public-widget/composables/use-public-widget-api'; - -import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; - -const DEFAULT_LIST_DATA = { results: [] }; -// const DEFAULT_LOAD_DATA = { results: {}, labels_info: {}, data_info: {} }; -const STALE_TIME = 1000 * 60 * 5; - -interface UseWidgetFormQueryOptions { - widgetId?: ComputedRef; - preventLoad?: boolean; -} - -interface UseWidgetFormQueryReturn { - widget: ComputedRef; - dataTableList: ComputedRef; - dataTableListLoading: ComputedRef; - widgetLoading: ComputedRef; - keys: { - publicWidgetGetQueryKey: ComputedRef; - privateWidgetGetQueryKey: ComputedRef; - publicWidgetLoadQueryKey: ComputedRef; - privateWidgetLoadQueryKey: ComputedRef; - publicWidgetLoadSumQueryKey: ComputedRef; - privateWidgetLoadSumQueryKey: ComputedRef; - publicDataTableListQueryKey: ComputedRef; - privateDataTableListQueryKey: ComputedRef; - publicDataTableLoadQueryKey: ComputedRef; - privateDataTableLoadQueryKey: ComputedRef; - }; - api: { - publicWidgetAPI: ReturnType['publicWidgetAPI']; - privateWidgetAPI: ReturnType['privateWidgetAPI']; - publicDataTableAPI: ReturnType['publicDataTableAPI']; - privateDataTableAPI: ReturnType['privateDataTableAPI']; - }; - fetcher: { - updateDataTableFn: (params: DataTableUpdateParameters) => Promise; - updateWidgetFn: (params: WidgetUpdateParams) => Promise; - }; - queryClient: QueryClient; -} - -export const useWidgetFormQuery = ({ - widgetId, - preventLoad = false, -}: UseWidgetFormQueryOptions): UseWidgetFormQueryReturn => { - const { - publicWidgetAPI, - publicWidgetGetQueryKey, - publicWidgetLoadQueryKey, - publicWidgetLoadSumQueryKey, - } = usePublicWidgetApi(); - const { - privateWidgetAPI, - privateWidgetGetQueryKey, - privateWidgetLoadQueryKey, - privateWidgetLoadSumQueryKey, - } = usePrivateWidgetApi(); - const { - publicDataTableAPI, - publicDataTableListQueryKey, - publicDataTableLoadQueryKey, - } = usePublicDataTableApi(); - const { - privateDataTableAPI, - privateDataTableListQueryKey, - privateDataTableLoadQueryKey, - } = usePrivateDataTableApi(); - const queryClient = useQueryClient(); - - const isPrivate = computed(() => !!widgetId?.value?.startsWith('private')); - - /* Query Keys */ - const _publicWidgetGetQueryKey = computed(() => [ - ...publicWidgetGetQueryKey.value, - widgetId?.value, - ]); - const _privateWidgetGetQueryKey = computed(() => [ - ...privateWidgetGetQueryKey.value, - widgetId?.value, - ]); - const _publicDataTableListQueryKey = computed(() => [ - ...publicDataTableListQueryKey.value, - widgetId?.value, - ]); - const _privateDataTableListQueryKey = computed(() => [ - ...privateDataTableListQueryKey.value, - widgetId?.value, - ]); - - /* Querys */ - const publicWidgetQuery = useScopedQuery({ - queryKey: _publicWidgetGetQueryKey, - queryFn: () => publicWidgetAPI.get({ - widget_id: widgetId?.value as string, - }), - enabled: computed(() => !!widgetId?.value && !isPrivate.value && !preventLoad), - staleTime: STALE_TIME, - }, ['DOMAIN', 'WORKSPACE']); - const privateWidgetQuery = useScopedQuery({ - queryKey: _privateWidgetGetQueryKey, - queryFn: () => privateWidgetAPI.get({ - widget_id: widgetId?.value as string, - }), - enabled: computed(() => !!widgetId?.value && isPrivate.value && !preventLoad), - staleTime: STALE_TIME, - }, ['WORKSPACE']); - const publicDataTableListQuery = useScopedQuery({ - queryKey: _publicDataTableListQueryKey, - queryFn: () => publicDataTableAPI.list({ - widget_id: widgetId?.value as string, - }), - select: (data) => data?.results || [], - enabled: computed(() => !!widgetId?.value && !isPrivate.value && !preventLoad), - initialData: DEFAULT_LIST_DATA, - initialDataUpdatedAt: 0, - staleTime: STALE_TIME, - }, ['DOMAIN', 'WORKSPACE']); - const privateDataTableListQuery = useScopedQuery({ - queryKey: _privateDataTableListQueryKey, - queryFn: () => privateDataTableAPI.list({ - widget_id: widgetId?.value as string, - }), - select: (data) => data?.results || [], - enabled: computed(() => !!widgetId?.value && isPrivate.value && !preventLoad), - initialData: DEFAULT_LIST_DATA, - initialDataUpdatedAt: 0, - staleTime: STALE_TIME, - }, ['WORKSPACE']); - - /* Fetchers */ - const updateDataTableFn = (params: DataTableUpdateParameters): Promise => { - if (isPrivate.value) { - return privateDataTableAPI.update(params); - } - return publicDataTableAPI.update(params); - }; - const updateWidgetFn = (params: WidgetUpdateParams): Promise => { - if (isPrivate.value) { - return privateWidgetAPI.update(params); - } - return publicWidgetAPI.update(params); - }; - - /* State */ - const dataTableListLoading = computed(() => (isPrivate.value - ? privateDataTableListQuery.isFetching.value - : publicDataTableListQuery.isFetching.value)); - const widgetLoading = computed(() => (isPrivate.value - ? privateWidgetQuery.isFetching.value - : publicWidgetQuery.isFetching.value)); - - return { - widget: computed(() => (isPrivate.value ? privateWidgetQuery.data.value : publicWidgetQuery.data.value)), - dataTableList: computed(() => (isPrivate.value ? privateDataTableListQuery.data.value : publicDataTableListQuery.data.value) ?? []), - dataTableListLoading, - widgetLoading, - api: { - publicWidgetAPI, - privateWidgetAPI, - publicDataTableAPI, - privateDataTableAPI, - }, - keys: { - publicWidgetGetQueryKey: _publicWidgetGetQueryKey, - privateWidgetGetQueryKey: _privateWidgetGetQueryKey, - publicDataTableListQueryKey: _publicDataTableListQueryKey, - privateDataTableListQueryKey: _privateDataTableListQueryKey, - publicWidgetLoadQueryKey: computed(() => publicWidgetLoadQueryKey.value), - privateWidgetLoadQueryKey: computed(() => privateWidgetLoadQueryKey.value), - publicWidgetLoadSumQueryKey: computed(() => publicWidgetLoadSumQueryKey.value), - privateWidgetLoadSumQueryKey: computed(() => privateWidgetLoadSumQueryKey.value), - publicDataTableLoadQueryKey: computed(() => publicDataTableLoadQueryKey.value), - privateDataTableLoadQueryKey: computed(() => privateDataTableLoadQueryKey.value), - }, - fetcher: { - updateDataTableFn, - updateWidgetFn, - }, - queryClient, - }; -}; diff --git a/apps/web/src/common/modules/widgets/_composables/use-widget-frame.ts b/apps/web/src/common/modules/widgets/_composables/use-widget-frame.ts index 489004db5c..872bde8d3a 100644 --- a/apps/web/src/common/modules/widgets/_composables/use-widget-frame.ts +++ b/apps/web/src/common/modules/widgets/_composables/use-widget-frame.ts @@ -19,7 +19,7 @@ import { useUserWorkspaceStore } from '@/store/app-context/workspace/user-worksp import { arrayToQueryString, objectToQueryString, primitiveToQueryString } from '@/lib/router-query-string'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_SOURCE_DOMAIN, DATA_TABLE_TYPE } from '@/common/modules/widgets/_constants/data-table-constant'; import { getWidgetConfig } from '@/common/modules/widgets/_helpers/widget-config-helper'; import type { DisplayAnnotationValue } from '@/common/modules/widgets/_widget-fields/display-annotation/type'; @@ -155,7 +155,7 @@ export const useWidgetFrame = ( /* Query */ const { dataTableList, - } = useWidgetFormQuery({ + } = useWidgetDataTableListQuery({ widgetId: computed(() => props.widgetId), }); const appContextStore = useAppContextStore(); diff --git a/apps/web/src/common/modules/widgets/_composables/use-widget-load-query.ts b/apps/web/src/common/modules/widgets/_composables/use-widget-load-query.ts new file mode 100644 index 0000000000..6505b30313 --- /dev/null +++ b/apps/web/src/common/modules/widgets/_composables/use-widget-load-query.ts @@ -0,0 +1,119 @@ +import { computed, type ComputedRef } from 'vue'; + +import type { WidgetLoadParams, WidgetLoadSumParams } from '@/api-clients/dashboard/_types/widget-type'; +import { usePrivateWidgetApi } from '@/api-clients/dashboard/private-widget/composables/use-private-widget-api'; +import { usePublicWidgetApi } from '@/api-clients/dashboard/public-widget/composables/use-public-widget-api'; +import { useScopedQuery } from '@/query/composables/use-scoped-query'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; + +import { WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; + + + +interface UseWidgetLoadQueryOptions { + widgetId: ComputedRef; + params: ComputedRef; + additionalDeps?: ComputedRef; + enabled?: ComputedRef; +} + + +export const useWidgetLoadQuery = ({ + widgetId, + params, + additionalDeps, + enabled, +}: UseWidgetLoadQueryOptions) => { + const { publicWidgetAPI } = usePublicWidgetApi(); + const { privateWidgetAPI } = usePrivateWidgetApi(); + + const isPrivate = computed(() => { + if (!widgetId.value) return false; + return widgetId.value.startsWith('private'); + }); + + const { key: publicWidgetLoadQueryKey, params: publicWidgetLoadParams } = useServiceQueryKey('dashboard', 'public-widget', 'load', { + contextKey: [ + widgetId.value, + ...(additionalDeps ? [additionalDeps.value] : []), + ], + params, + }); + + const { key: privateWidgetLoadQueryKey, params: privateWidgetLoadParams } = useServiceQueryKey('dashboard', 'private-widget', 'load', { + contextKey: widgetId, + params, + }); + + return useScopedQuery({ + queryKey: isPrivate.value ? privateWidgetLoadQueryKey : publicWidgetLoadQueryKey, + queryFn: () => { + if (isPrivate.value) { + if (!privateWidgetLoadParams.value) { + throw new Error('Widget parameters are required'); + } + return privateWidgetAPI.load(privateWidgetLoadParams.value); + } + if (!publicWidgetLoadParams.value) { + throw new Error('Widget parameters are required'); + } + return publicWidgetAPI.load(publicWidgetLoadParams.value); + }, + enabled, + staleTime: WIDGET_LOAD_STALE_TIME, + }, ['DOMAIN', 'WORKSPACE']); +}; + + +interface UseWidgetLoadSumQueryOptions { + widgetId: ComputedRef; + params: ComputedRef; + additionalDeps?: ComputedRef; + enabled?: ComputedRef; +} + +export const useWidgetLoadSumQuery = ({ + widgetId, + params, + additionalDeps, + enabled, +}: UseWidgetLoadSumQueryOptions) => { + const { publicWidgetAPI } = usePublicWidgetApi(); + const { privateWidgetAPI } = usePrivateWidgetApi(); + + const isPrivate = computed(() => { + if (!widgetId.value) return false; + return widgetId.value.startsWith('private'); + }); + + const { key: publicWidgetLoadSumQueryKey, params: publicWidgetLoadSumParams } = useServiceQueryKey('dashboard', 'public-widget', 'load-sum', { + contextKey: [ + widgetId.value, + ...(additionalDeps ? [additionalDeps.value] : []), + ], + params, + }); + + const { key: privateWidgetLoadSumQueryKey, params: privateWidgetLoadSumParams } = useServiceQueryKey('dashboard', 'private-widget', 'load-sum', { + contextKey: widgetId, + params, + }); + + return useScopedQuery({ + queryKey: isPrivate.value ? privateWidgetLoadSumQueryKey : publicWidgetLoadSumQueryKey, + queryFn: () => { + if (isPrivate.value) { + if (!privateWidgetLoadSumParams.value) { + throw new Error('Widget parameters are required'); + } + return privateWidgetAPI.loadSum(privateWidgetLoadSumParams.value); + } + if (!publicWidgetLoadSumParams.value) { + throw new Error('Widget parameters are required'); + } + return publicWidgetAPI.loadSum(publicWidgetLoadSumParams.value); + }, + enabled, + staleTime: WIDGET_LOAD_STALE_TIME, + }, ['DOMAIN', 'WORKSPACE']); +}; diff --git a/apps/web/src/common/modules/widgets/_composables/use-widget-query.ts b/apps/web/src/common/modules/widgets/_composables/use-widget-query.ts new file mode 100644 index 0000000000..e06be200e0 --- /dev/null +++ b/apps/web/src/common/modules/widgets/_composables/use-widget-query.ts @@ -0,0 +1,108 @@ +import type { ComputedRef } from 'vue'; +import { computed } from 'vue'; + +import type { QueryKey } from '@tanstack/vue-query'; + +import type { WidgetModel, WidgetUpdateParams } from '@/api-clients/dashboard/_types/widget-type'; +import { usePrivateWidgetApi } from '@/api-clients/dashboard/private-widget/composables/use-private-widget-api'; +import type { PrivateWidgetGetParameters } from '@/api-clients/dashboard/private-widget/schema/api-verbs/get'; +import { usePublicWidgetApi } from '@/api-clients/dashboard/public-widget/composables/use-public-widget-api'; +import type { PublicWidgetGetParameters } from '@/api-clients/dashboard/public-widget/schema/api-verbs/get'; +import { useScopedQuery } from '@/query/composables/use-scoped-query'; +import { useServiceQueryKey } from '@/query/query-key/use-service-query-key'; + + +const STALE_TIME = 1000 * 60 * 5; + +interface UseWidgetFormQueryOptions { + widgetId?: ComputedRef; + preventLoad?: boolean; +} + +interface UseWidgetFormQueryReturn { + widget: ComputedRef; + widgetLoading: ComputedRef; + keys: { + publicWidgetGetQueryKey: ComputedRef; + privateWidgetGetQueryKey: ComputedRef; + }; + api: { + publicWidgetAPI: ReturnType['publicWidgetAPI']; + privateWidgetAPI: ReturnType['privateWidgetAPI']; + }; + fetcher: { + updateWidgetFn: (params: WidgetUpdateParams) => Promise; + }; +} + +export const useWidgetQuery = ({ + widgetId, + preventLoad = false, +}: UseWidgetFormQueryOptions): UseWidgetFormQueryReturn => { + const { + publicWidgetAPI, + } = usePublicWidgetApi(); + const { + privateWidgetAPI, + } = usePrivateWidgetApi(); + + const isPrivate = computed(() => !!widgetId?.value?.startsWith('private')); + + /* Query Keys */ + const { key: publicWidgetGetQueryKey, params: publicWidgetGetParams } = useServiceQueryKey('dashboard', 'public-widget', 'get', { + contextKey: widgetId, + params: computed(() => ({ + widget_id: widgetId?.value as string, + })), + }); + const { key: privateWidgetGetQueryKey, params: privateWidgetGetParams } = useServiceQueryKey('dashboard', 'private-widget', 'get', { + contextKey: widgetId, + params: computed(() => ({ + widget_id: widgetId?.value as string, + })), + }); + + /* Querys */ + const publicWidgetQuery = useScopedQuery({ + queryKey: publicWidgetGetQueryKey, + queryFn: () => publicWidgetAPI.get(publicWidgetGetParams.value), + enabled: computed(() => !!widgetId?.value && !isPrivate.value && !preventLoad), + staleTime: STALE_TIME, + }, ['DOMAIN', 'WORKSPACE']); + const privateWidgetQuery = useScopedQuery({ + queryKey: privateWidgetGetQueryKey, + queryFn: () => privateWidgetAPI.get(privateWidgetGetParams.value), + enabled: computed(() => !!widgetId?.value && isPrivate.value && !preventLoad), + staleTime: STALE_TIME, + }, ['WORKSPACE']); + + + /* Fetchers */ + const updateWidgetFn = (params: WidgetUpdateParams): Promise => { + if (isPrivate.value) { + return privateWidgetAPI.update(params); + } + return publicWidgetAPI.update(params); + }; + + /* State */ + const widgetLoading = computed(() => (isPrivate.value + ? privateWidgetQuery.isFetching.value + : publicWidgetQuery.isFetching.value)); + + return { + widget: computed(() => (isPrivate.value ? privateWidgetQuery.data.value : publicWidgetQuery.data.value)), + widgetLoading, + api: { + publicWidgetAPI, + privateWidgetAPI, + }, + keys: { + publicWidgetGetQueryKey, + privateWidgetGetQueryKey, + }, + fetcher: { + updateWidgetFn, + }, + }; +}; diff --git a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-chart-data-helper.test.ts b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-chart-data-helper.test.ts index 9619e60bc5..51fa69001f 100644 --- a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-chart-data-helper.test.ts +++ b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-chart-data-helper.test.ts @@ -1,7 +1,7 @@ import { range } from 'lodash'; import { describe, it, expect } from 'vitest'; -import { getRefinedXYChartData } from '@/services/dashboards/widgets/_helpers/widget-chart-data-helper'; +import { getRefinedXYChartData } from '@/services/_shared/dashboard/dashboard-detail/legacy/widgets/_helpers/widget-chart-data-helper'; interface SubData { date: string; diff --git a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-inherit-options-helper.test.ts b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-inherit-options-helper.test.ts index b7f20f2a23..7d33b784d3 100644 --- a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-inherit-options-helper.test.ts +++ b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-inherit-options-helper.test.ts @@ -7,7 +7,7 @@ import type { InheritOptions, WidgetConfig, WidgetOptionsSchema } from '@/api-cl import { getInheritingOptionKeys, getInitialWidgetInheritOptions, -} from '@/services/dashboards/widgets/_helpers/widget-inherit-options-helper'; +} from '@/services/_shared/dashboard/dashboard-detail/legacy/widgets/_helpers/widget-inherit-options-helper'; diff --git a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-options-filters-helper.test.ts b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-options-filters-helper.test.ts index 61d4f9a8a7..268f259ed6 100644 --- a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-options-filters-helper.test.ts +++ b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-options-filters-helper.test.ts @@ -1,6 +1,6 @@ import type { WidgetFilterKey, WidgetFiltersMap } from '@/api-clients/dashboard/_types/widget-type'; -import { setFilterAndGetWidgetFiltersMap } from '@/services/dashboards/widgets/_helpers/widget-options-filters-helper'; +import { setFilterAndGetWidgetFiltersMap } from '@/services/_shared/dashboard/dashboard-detail/legacy/widgets/_helpers/widget-options-filters-helper'; describe('[Widget Options Filters Helper] setFilterAndGetWidgetFiltersMap', () => { diff --git a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-schema-helper.test.ts b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-schema-helper.test.ts index 611ed71954..3ae48a18fc 100644 --- a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-schema-helper.test.ts +++ b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-schema-helper.test.ts @@ -6,7 +6,7 @@ import type { InheritOptions, WidgetConfig, WidgetOptions } from '@/api-clients/ import { getInitialSchemaProperties, getNonInheritedWidgetOptionNamesAmongUsedVariables, getRefinedSchemaProperties, getWidgetOptionKeyByVariableKey, -} from '@/services/dashboards/widgets/_helpers/widget-schema-helper'; +} from '@/services/_shared/dashboard/dashboard-detail/legacy/widgets/_helpers/widget-schema-helper'; const DEFAULT_WIDGET_CONFIG = { widget_config_id: 'test', diff --git a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-value-label-helper.test.ts b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-value-label-helper.test.ts index 2f2235dbac..75a8942bab 100644 --- a/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-value-label-helper.test.ts +++ b/apps/web/src/common/modules/widgets/_helpers/__tests__/widget-value-label-helper.test.ts @@ -1,7 +1,7 @@ import { describe } from 'vitest'; +import { getWidgetValueLabel } from '@/services/_shared/dashboard/dashboard-detail/legacy/widgets/_helpers/widget-value-label-helper'; import type { AllReferenceTypeInfo } from '@/services/dashboards/stores/all-reference-type-info-store'; -import { getWidgetValueLabel } from '@/services/dashboards/widgets/_helpers/widget-value-label-helper'; const mockAllReferenceTypeInfo: AllReferenceTypeInfo = { provider: { diff --git a/apps/web/src/common/modules/widgets/_helpers/widget-load-helper.ts b/apps/web/src/common/modules/widgets/_helpers/widget-load-helper.ts index 4a62cea577..2e447968ff 100644 --- a/apps/web/src/common/modules/widgets/_helpers/widget-load-helper.ts +++ b/apps/web/src/common/modules/widgets/_helpers/widget-load-helper.ts @@ -44,5 +44,5 @@ export const getWidgetLoadApiQuerySort = (xAxisField: string, dataField: string[ if (isPivot) { return [{ key: SUB_TOTAL_NAME, desc: true }]; } - return dataField.map((field) => ({ key: field, desc: true })); + return dataField?.map((field) => ({ key: field, desc: true })); }; diff --git a/apps/web/src/common/modules/widgets/_store/widget-context-store.ts b/apps/web/src/common/modules/widgets/_store/widget-context-store.ts new file mode 100644 index 0000000000..bafe716292 --- /dev/null +++ b/apps/web/src/common/modules/widgets/_store/widget-context-store.ts @@ -0,0 +1,32 @@ +import { computed, reactive } from 'vue'; + +import { defineStore } from 'pinia'; + +import type { DashboardModel, DashboardOptions } from '@/api-clients/dashboard/_types/dashboard-type'; + +export const useWidgetContextStore = defineStore('widget-context', () => { + const state = reactive({ + dashboard: undefined as DashboardModel | undefined, + }); + + + const getters = { + dashboardId: computed(() => state.dashboard?.dashboard_id), + options: computed(() => state.dashboard?.options || {}), + }; + + const setDashboard = (dashboard?: DashboardModel) => { + state.dashboard = dashboard; + }; + + + const mutations = { + setDashboard, + }; + + return { + state, + getters, + ...mutations, + }; +}); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/category-by/WidgetFieldCategoryBy.vue b/apps/web/src/common/modules/widgets/_widget-fields/category-by/WidgetFieldCategoryBy.vue index c7e70d314b..d5fb8f0e17 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/category-by/WidgetFieldCategoryBy.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/category-by/WidgetFieldCategoryBy.vue @@ -7,7 +7,7 @@ import { PFieldGroup } from '@cloudforet/mirinae'; import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type'; import WidgetFieldDropdownAndMax from '@/common/modules/widgets/_components/WidgetFieldDropdownAndMax.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { sortWidgetTableFields } from '@/common/modules/widgets/_helpers/widget-helper'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { @@ -27,7 +27,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/custom-table-column-width/WidgetFieldCustomTableColumnWidth.vue b/apps/web/src/common/modules/widgets/_widget-fields/custom-table-column-width/WidgetFieldCustomTableColumnWidth.vue index 6fff3a6a09..134a1d8180 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/custom-table-column-width/WidgetFieldCustomTableColumnWidth.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/custom-table-column-width/WidgetFieldCustomTableColumnWidth.vue @@ -16,7 +16,7 @@ import getRandomId from '@/lib/random-id-generator'; import type { } from '@/common/modules/widgets/types/widget-field-value-type'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; import { SUB_TOTAL_NAME } from '@/common/modules/widgets/_constants/widget-field-constant'; import { sortWidgetTableFields } from '@/common/modules/widgets/_helpers/widget-helper'; @@ -43,7 +43,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/data-field-heatmap-color/WidgetFieldDataFieldHeatmapColor.vue b/apps/web/src/common/modules/widgets/_widget-fields/data-field-heatmap-color/WidgetFieldDataFieldHeatmapColor.vue index aeefc4a5c0..e0566f96ae 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/data-field-heatmap-color/WidgetFieldDataFieldHeatmapColor.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/data-field-heatmap-color/WidgetFieldDataFieldHeatmapColor.vue @@ -11,7 +11,7 @@ import type { SelectDropdownMenuItem } from '@cloudforet/mirinae/types/controls/ import { i18n } from '@/translations'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; import { DATA_FIELD_HEATMAP_COLOR } from '@/common/modules/widgets/_constants/widget-field-constant'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; @@ -36,7 +36,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/data-field/WidgetFieldDataField.vue b/apps/web/src/common/modules/widgets/_widget-fields/data-field/WidgetFieldDataField.vue index da1c28077c..9dc5d7193d 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/data-field/WidgetFieldDataField.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/data-field/WidgetFieldDataField.vue @@ -3,10 +3,11 @@ import { computed, reactive, } from 'vue'; + import { PSelectDropdown, PFieldGroup } from '@cloudforet/mirinae'; import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; import { SUB_TOTAL_NAME } from '@/common/modules/widgets/_constants/widget-field-constant'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; @@ -30,7 +31,7 @@ const validator = widgetValidatorRegistry[FIELD_KEY]; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/date-range/WidgetFieldDateRange.vue b/apps/web/src/common/modules/widgets/_widget-fields/date-range/WidgetFieldDateRange.vue index 2116a352f8..4ded536921 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/date-range/WidgetFieldDateRange.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/date-range/WidgetFieldDateRange.vue @@ -13,6 +13,7 @@ import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/t import type { DateRange } from '@/api-clients/dashboard/_types/dashboard-type'; import { useWidgetDateRange } from '@/common/modules/widgets/_composables/use-widget-date-range'; +import { useWidgetContextStore } from '@/common/modules/widgets/_store/widget-context-store'; import { DAILY_ENABLED_VALUES, DATE_RANGE_ADVANCED_OPERATOR_MAP, @@ -34,7 +35,6 @@ import type { WidgetFieldComponentProps, } from '@/common/modules/widgets/types/widget-field-type'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; const GRANULARITY_UNIT_MAP = { MONTHLY: { singular: 'Month', plural: 'Months' }, @@ -51,13 +51,12 @@ const getCommonDateRangeValueLabel = (value: string): string => { const FIELD_KEY = 'dateRange'; const props = defineProps>(); -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; - +const widgetContextStore = useWidgetContextStore(); +const widgetContextState = widgetContextStore.state; const state = reactive({ fieldValue: computed(() => props.fieldManager.data[FIELD_KEY].value), granularity: computed(() => (props.fieldManager.data.granularity?.value?.granularity || 'MONTHLY')), - baseDateRange: computed(() => dashboardDetailState.options.date_range), + baseDateRange: computed(() => widgetContextState.dashboard?.options?.date_range), valueMenuItems: computed(() => { if (state.granularity === 'MONTHLY') return MONTHLY_ENABLED_VALUES.map((value) => ({ label: DATE_RANGE_MONTHLY_VALUE_MAP[value] || getCommonDateRangeValueLabel(value), name: value })); if (state.granularity === 'DAILY') return DAILY_ENABLED_VALUES.map((value) => ({ label: DATE_RANGE_DAILY_VALUE_MAP[value] || getCommonDateRangeValueLabel(value), name: value })); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/format-rules/WidgetFieldFormatRules.vue b/apps/web/src/common/modules/widgets/_widget-fields/format-rules/WidgetFieldFormatRules.vue index 8bb93ebebd..b5c076365e 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/format-rules/WidgetFieldFormatRules.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/format-rules/WidgetFieldFormatRules.vue @@ -11,7 +11,7 @@ import { import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type'; import ColorInput from '@/common/components/inputs/ColorInput.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { FORMAT_RULE_TYPE, } from '@/common/modules/widgets/_constants/widget-field-constant'; @@ -40,7 +40,7 @@ const validator = widgetValidatorRegistry[FIELD_KEY]; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/group-by/WidgetFieldGroupBy.vue b/apps/web/src/common/modules/widgets/_widget-fields/group-by/WidgetFieldGroupBy.vue index 6c35461472..93c7cf0a30 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/group-by/WidgetFieldGroupBy.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/group-by/WidgetFieldGroupBy.vue @@ -10,7 +10,7 @@ import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/t import { i18n } from '@/translations'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { sortWidgetTableFields } from '@/common/modules/widgets/_helpers/widget-helper'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import { @@ -38,7 +38,7 @@ const validator = widgetValidatorRegistry[FIELD_KEY]; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/number-format/WidgetFieldNumberFormat.vue b/apps/web/src/common/modules/widgets/_widget-fields/number-format/WidgetFieldNumberFormat.vue index 64fa46d06f..ccaf3dc07b 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/number-format/WidgetFieldNumberFormat.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/number-format/WidgetFieldNumberFormat.vue @@ -11,7 +11,7 @@ import { customNumberFormatter } from '@cloudforet/utils'; import { i18n } from '@/translations'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; import { NUMBER_FORMAT } from '@/common/modules/widgets/_constants/widget-field-constant'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; @@ -42,7 +42,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/sankey-dimensions/WidgetFieldSankeyDimensions.vue b/apps/web/src/common/modules/widgets/_widget-fields/sankey-dimensions/WidgetFieldSankeyDimensions.vue index 3efee950d2..699afcfe85 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/sankey-dimensions/WidgetFieldSankeyDimensions.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/sankey-dimensions/WidgetFieldSankeyDimensions.vue @@ -14,7 +14,7 @@ import { i18n } from '@/translations'; import { showErrorMessage } from '@/lib/helper/notice-alert-helper'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { sortWidgetTableFields } from '@/common/modules/widgets/_helpers/widget-helper'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import { @@ -41,7 +41,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/stack-by/WidgetFieldStackBy.vue b/apps/web/src/common/modules/widgets/_widget-fields/stack-by/WidgetFieldStackBy.vue index 4e971dcdd3..60711fc3c0 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/stack-by/WidgetFieldStackBy.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/stack-by/WidgetFieldStackBy.vue @@ -7,7 +7,7 @@ import { PFieldGroup } from '@cloudforet/mirinae'; import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type'; import WidgetFieldDropdownAndMax from '@/common/modules/widgets/_components/WidgetFieldDropdownAndMax.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { sortWidgetTableFields } from '@/common/modules/widgets/_helpers/widget-helper'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { StackByOptions } from '@/common/modules/widgets/_widget-fields/stack-by/type'; @@ -26,7 +26,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/sub-total/WidgetFieldSubTotal.vue b/apps/web/src/common/modules/widgets/_widget-fields/sub-total/WidgetFieldSubTotal.vue index 634e36632e..d06f48b25e 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/sub-total/WidgetFieldSubTotal.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/sub-total/WidgetFieldSubTotal.vue @@ -5,7 +5,7 @@ import { PFieldTitle, PToggleButton, PI, PTooltip, PCheckbox, } from '@cloudforet/mirinae'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { SubTotalOptions, SubTotalValue } from '@/common/modules/widgets/_widget-fields/sub-total/type'; @@ -25,7 +25,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/table-column-comparison/WidgetFieldTableColumnComparison.vue b/apps/web/src/common/modules/widgets/_widget-fields/table-column-comparison/WidgetFieldTableColumnComparison.vue index 3ce07dfeb8..6ed29f4dd8 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/table-column-comparison/WidgetFieldTableColumnComparison.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/table-column-comparison/WidgetFieldTableColumnComparison.vue @@ -14,7 +14,7 @@ import { i18n } from '@/translations'; import ColorInput from '@/common/components/inputs/ColorInput.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import { @@ -40,7 +40,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/x-axis/WidgetFieldXAxis.vue b/apps/web/src/common/modules/widgets/_widget-fields/x-axis/WidgetFieldXAxis.vue index cd52890579..4eed195e12 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/x-axis/WidgetFieldXAxis.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/x-axis/WidgetFieldXAxis.vue @@ -7,7 +7,7 @@ import { PFieldGroup } from '@cloudforet/mirinae'; import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type'; import WidgetFieldDropdownAndMax from '@/common/modules/widgets/_components/WidgetFieldDropdownAndMax.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { sortWidgetTableFields } from '@/common/modules/widgets/_helpers/widget-helper'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { XAxisOptions } from '@/common/modules/widgets/_widget-fields/x-axis/type'; @@ -26,7 +26,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widget-fields/y-axis/WidgetFieldYAxis.vue b/apps/web/src/common/modules/widgets/_widget-fields/y-axis/WidgetFieldYAxis.vue index 51a70bf4a4..e4cf544b7e 100644 --- a/apps/web/src/common/modules/widgets/_widget-fields/y-axis/WidgetFieldYAxis.vue +++ b/apps/web/src/common/modules/widgets/_widget-fields/y-axis/WidgetFieldYAxis.vue @@ -7,7 +7,7 @@ import { PFieldGroup } from '@cloudforet/mirinae'; import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type'; import WidgetFieldDropdownAndMax from '@/common/modules/widgets/_components/WidgetFieldDropdownAndMax.vue'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; +import { useWidgetDataTableListQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-list-query'; import { sortWidgetTableFields } from '@/common/modules/widgets/_helpers/widget-helper'; import { useWidgetGenerateStore } from '@/common/modules/widgets/_store/widget-generate-store'; import type { YAxisOptions } from '@/common/modules/widgets/_widget-fields/y-axis/type'; @@ -26,7 +26,7 @@ const widgetGenerateState = widgetGenerateStore.state; /* Query */ const { dataTableList, -} = useWidgetFormQuery({ +} = useWidgetDataTableListQuery({ widgetId: computed(() => widgetGenerateState.widgetId), }); diff --git a/apps/web/src/common/modules/widgets/_widgets/clustered-column-chart/ClusteredColumnChart.vue b/apps/web/src/common/modules/widgets/_widgets/clustered-column-chart/ClusteredColumnChart.vue index 220c9e3afe..3f38a00046 100644 --- a/apps/web/src/common/modules/widgets/_widgets/clustered-column-chart/ClusteredColumnChart.vue +++ b/apps/web/src/common/modules/widgets/_widgets/clustered-column-chart/ClusteredColumnChart.vue @@ -4,7 +4,6 @@ import { computed, defineExpose, onMounted, reactive, ref, watch, } from 'vue'; -import { useQuery } from '@tanstack/vue-query'; import dayjs from 'dayjs'; import type { BarSeriesOption } from 'echarts/charts'; import { init } from 'echarts/core'; @@ -17,20 +16,17 @@ import { import { numberFormatter } from '@cloudforet/utils'; -import type { WidgetLoadParams, WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; +import type { WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import { i18n } from '@/translations'; -import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetFrame from '@/common/modules/widgets/_components/WidgetFrame.vue'; +import { useWidgetDataTableQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-query'; import { useWidgetDateRange } from '@/common/modules/widgets/_composables/use-widget-date-range'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; import { useWidgetFrame } from '@/common/modules/widgets/_composables/use-widget-frame'; +import { useWidgetLoadQuery } from '@/common/modules/widgets/_composables/use-widget-load-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; -import { DATE_FIELD, WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; +import { DATE_FIELD } from '@/common/modules/widgets/_constants/widget-constant'; import { DATE_FORMAT, SUB_TOTAL_NAME } from '@/common/modules/widgets/_constants/widget-field-constant'; -import { - normalizeAndSerializeVars, -} from '@/common/modules/widgets/_helpers/global-variable-helper'; import { getReferenceLabel, getWidgetDateFields, @@ -50,7 +46,6 @@ import type { LegendValue } from '@/common/modules/widgets/_widget-fields/legend import type { NumberFormatValue } from '@/common/modules/widgets/_widget-fields/number-format/type'; import type { TooltipNumberFormatValue } from '@/common/modules/widgets/_widget-fields/tooltip-number-format/type'; import type { XAxisValue } from '@/common/modules/widgets/_widget-fields/x-axis/type'; -import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; import type { DateRange } from '@/common/modules/widgets/types/widget-data-type'; import type { WidgetProps, WidgetEmit, WidgetExpose, @@ -64,10 +59,10 @@ import { MASSIVE_CHART_COLORS } from '@/styles/colorsets'; const props = defineProps(); const emit = defineEmits(); -const { keys, api } = useWidgetFormQuery({ - widgetId: computed(() => props.widgetId), - preventLoad: true, -}); +const { data: dataTable, isFetching: dataTableLoading } = useWidgetDataTableQuery( + computed(() => props.dataTableId), +); +const isPivotDataTable = computed(() => dataTable.value?.operator === DATA_TABLE_OPERATOR.PIVOT); const { dateRange } = useWidgetDateRange({ dateRangeFieldValue: computed(() => (props.widgetOptions?.dateRange?.value as DateRangeValue)), @@ -77,11 +72,9 @@ const { dateRange } = useWidgetDateRange({ const chartContext = ref(null); const state = reactive({ isPrivateWidget: computed(() => props.widgetId.startsWith('private')), - dataTable: undefined as DataTableModel|undefined, - isPivotDataTable: computed(() => state.dataTable?.operator === DATA_TABLE_OPERATOR.PIVOT), unitMap: computed>(() => widgetFrameProps.value.unitMap || {}), - data: computed(() => queryResult.data?.value ?? null), + data: computed(() => loadQuery.data?.value ?? null), chart: null as EChartsType | null, dataField: computed(() => widgetOptionsState.dataFieldInfo?.data?.[0] || ''), xAxisData: computed(() => { @@ -128,8 +121,8 @@ const state = reactive({ const _seriesName = getReferenceLabel(props.allReferenceTypeInfo, state.dataField, p.seriesName); let _value = numberFormatter(p.value) || ''; if (widgetOptionsState.tooltipNumberFormatInfo?.toggleValue) { - const columnFieldForPivot = state.dataTable?.options.PIVOT?.fields?.column; - const fieldName = (state.isPivotDataTable && columnFieldForPivot) ? columnFieldForPivot : p.seriesName; + const columnFieldForPivot = dataTable.value?.options.PIVOT?.fields?.column; + const fieldName = (isPivotDataTable.value && columnFieldForPivot) ? columnFieldForPivot : p.seriesName; const numberFormat = widgetOptionsState.numberFormatInfo[fieldName]; _value = getFormattedNumber(p.value, numberFormat, _unit); } @@ -167,7 +160,6 @@ const state = reactive({ return { start: _start, end: _end }; }), dateFormat: computed(() => DATE_FORMAT?.[widgetOptionsState.dateFormatInfo?.format]?.[widgetOptionsState.granularityInfo?.granularity]), - dataTableLoading: false, }); const widgetOptionsState = reactive({ @@ -182,51 +174,28 @@ const widgetOptionsState = reactive({ }); /* Api */ -const fetchWidgetData = async (params: WidgetLoadParams): Promise => { - const defaultFetcher = state.isPrivateWidget - ? api.privateWidgetAPI.load - : api.publicWidgetAPI.load; - const res = await defaultFetcher(params); - return res; -}; - -const queryKey = computed(() => [ - ...(state.isPrivateWidget ? keys.privateWidgetLoadQueryKey.value : keys.publicWidgetLoadQueryKey.value), - props.dashboardId, - props.widgetId, - props.widgetName, - { - start: dateRange.value.start, - end: dateRange.value.end, - granularity: widgetOptionsState.granularityInfo?.granularity, - dataTableId: props.dataTableId, - // dataTableOptions: normalizeAndSerializeDataTableOptions(state.dataTable?.options || {}), - // dataTables: normalizeAndSerializeDataTableOptions((props.dataTables || []).map((d) => d?.options || {})), - groupBy: widgetOptionsState.xAxisInfo?.data, - count: widgetOptionsState.xAxisInfo?.count, - vars: normalizeAndSerializeVars(props.dashboardVars), - }, -]); - -const queryResult = useQuery({ - queryKey, - queryFn: () => fetchWidgetData({ +const loadQuery = useWidgetLoadQuery({ + widgetId: computed(() => props.widgetId), + params: computed(() => ({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, group_by: widgetOptionsState.xAxisInfo?.data ? [widgetOptionsState.xAxisInfo?.data] : [], - sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[], state.isPivotDataTable), + sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[], isPivotDataTable.value), page: { start: 0, limit: widgetOptionsState.xAxisInfo?.count }, vars: props.dashboardVars, ...getWidgetLoadApiQueryDateRange(widgetOptionsState.granularityInfo?.granularity, dateRange.value), - }), - enabled: computed(() => props.widgetState !== 'INACTIVE' && !!state.dataTable && !props.loadDisabled), - staleTime: WIDGET_LOAD_STALE_TIME, + })), + additionalDeps: computed(() => ({ + widgetName: props.widgetName, + dataTableId: props.dataTableId, + })), + enabled: computed(() => props.widgetState !== 'INACTIVE' && !!dataTable.value && !props.loadDisabled), }); -const widgetLoading = computed(() => queryResult.isFetching.value || state.dataTableLoading); +const widgetLoading = computed(() => loadQuery.isFetching.value || dataTableLoading.value); const errorMessage = computed(() => { - if (!state.dataTable) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE'); - return queryResult.error?.value?.message; + if (!dataTable.value) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE') as string; + return loadQuery.error?.value?.message as string; }); /* Util */ @@ -234,7 +203,7 @@ const getThreshold = (rawData: WidgetLoadResponse): number => { const maxNumber = rawData?.results?.reduce((max, obj) => { const values = Object.values(obj).filter((val) => typeof val === 'number'); return Math.max(max, ...values); - }, 0); + }, 0) || 0; return maxNumber * 0.08; }; const drawChart = (rawData: WidgetLoadResponse|null) => { @@ -252,14 +221,14 @@ const drawChart = (rawData: WidgetLoadResponse|null) => { }); return acc; }, Object.fromEntries((widgetOptionsState.dataFieldInfo?.data as string[])?.map((field) => [field, 0]))); - if (Object.values(_etcData).some((v) => v > 0)) { + if ((Object.values(_etcData) as number[]).some((v) => v > 0)) { _refinedData.push({ [widgetOptionsState.xAxisInfo?.data as string]: 'etc', ..._etcData }); } } const _seriesData: any[] = []; let _dataFields: string[] = widgetOptionsState.dataFieldInfo?.data as string[] || []; - if (state.isPivotDataTable) { + if (isPivotDataTable.value) { const _excludeFields = [...Object.keys(rawData?.labels_info ?? {}), SUB_TOTAL_NAME]; _dataFields = rawData?.order?.filter((v) => !_excludeFields.includes(v)) || []; } @@ -277,8 +246,8 @@ const drawChart = (rawData: WidgetLoadResponse|null) => { fontSize: 10, formatter: (p) => { if (p.value < _threshold) return ''; - const columnFieldForPivot = state.dataTable?.options.PIVOT?.fields?.column; - const fieldName = (state.isPivotDataTable && columnFieldForPivot) ? columnFieldForPivot : p.seriesName; + const columnFieldForPivot = dataTable.value?.options.PIVOT?.fields?.column; + const fieldName = (isPivotDataTable.value && columnFieldForPivot) ? columnFieldForPivot : p.seriesName; const numberFormat = widgetOptionsState.numberFormatInfo[fieldName]; return getFormattedNumber(p.value, numberFormat, _unit); }, @@ -307,7 +276,7 @@ watch([() => state.chartData, () => chartContext.value], ([, chartCtx]) => { } }); -watch([() => state.data, () => props.widgetOptions, () => state.dataTable], ([newData,, _dataTable]) => { +watch([() => state.data, () => props.widgetOptions, dataTable], ([newData,, _dataTable]) => { if (!_dataTable) return; drawChart(newData); }, { immediate: true }); @@ -317,23 +286,9 @@ useResizeObserver(chartContext, throttle(() => { state.chart?.resize(); }, 500)); -watch(() => props.dataTableId, async (newDataTableId) => { - if (!newDataTableId) return; - state.dataTableLoading = true; - const fetcher = state.isPrivateWidget - ? api.privateDataTableAPI.get - : api.publicDataTableAPI.get; - try { - state.dataTable = await fetcher({ data_table_id: newDataTableId }); - } catch (e) { - ErrorHandler.handleError(e); - } finally { - state.dataTableLoading = false; - } -}, { immediate: true }); defineExpose({ loadWidget: () => { - queryResult.refetch(); + loadQuery.refetch(); }, }); onMounted(() => { diff --git a/apps/web/src/common/modules/widgets/_widgets/color-coded-heatmap/ColorCodedHeatmap.vue b/apps/web/src/common/modules/widgets/_widgets/color-coded-heatmap/ColorCodedHeatmap.vue index e78a8b1ed5..c2d47f3a69 100644 --- a/apps/web/src/common/modules/widgets/_widgets/color-coded-heatmap/ColorCodedHeatmap.vue +++ b/apps/web/src/common/modules/widgets/_widgets/color-coded-heatmap/ColorCodedHeatmap.vue @@ -3,7 +3,6 @@ import { computed, defineExpose, onMounted, reactive, watch, } from 'vue'; -import { useQuery } from '@tanstack/vue-query'; import { orderBy } from 'lodash'; import { @@ -11,19 +10,14 @@ import { } from '@cloudforet/mirinae'; import { numberFormatter } from '@cloudforet/utils'; -import type { WidgetLoadParams, WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import { i18n } from '@/translations'; -import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetCustomLegend from '@/common/modules/widgets/_components/WidgetCustomLegend.vue'; import WidgetFrame from '@/common/modules/widgets/_components/WidgetFrame.vue'; +import { useWidgetDataTableQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-query'; import { useWidgetDateRange } from '@/common/modules/widgets/_composables/use-widget-date-range'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; import { useWidgetFrame } from '@/common/modules/widgets/_composables/use-widget-frame'; -import { WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; -import { - normalizeAndSerializeVars, -} from '@/common/modules/widgets/_helpers/global-variable-helper'; +import { useWidgetLoadQuery } from '@/common/modules/widgets/_composables/use-widget-load-query'; import { getReferenceLabel, } from '@/common/modules/widgets/_helpers/widget-date-helper'; @@ -34,7 +28,6 @@ import type { } from '@/common/modules/widgets/_widget-fields/format-rules/type'; import type { GranularityValue } from '@/common/modules/widgets/_widget-fields/granularity/type'; import type { GroupByValue } from '@/common/modules/widgets/_widget-fields/group-by/type'; -import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; import type { WidgetEmit, WidgetExpose, WidgetProps } from '@/common/modules/widgets/types/widget-display-type'; import type { WidgetLegend } from '@/common/modules/widgets/types/widget-legend-typs'; @@ -45,10 +38,9 @@ const MAX_COUNT = 80; const props = defineProps(); const emit = defineEmits(); -const { keys, api } = useWidgetFormQuery({ - widgetId: computed(() => props.widgetId), - preventLoad: true, -}); +const { data: dataTable, isFetching: dataTableLoading } = useWidgetDataTableQuery( + computed(() => props.dataTableId), +); const { dateRange } = useWidgetDateRange({ dateRangeFieldValue: computed(() => (props.widgetOptions?.dateRange?.value as DateRangeValue)), @@ -57,7 +49,6 @@ const { dateRange } = useWidgetDateRange({ }); const state = reactive({ isPrivateWidget: computed(() => props.widgetId.startsWith('private')), - dataTable: undefined as DataTableModel|undefined, boxWidth: computed(() => { if (!props.width) return BOX_MIN_WIDTH; const widgetContentWidth = props.width; @@ -65,7 +56,6 @@ const state = reactive({ return widgetContentWidth / 8 < BOX_MIN_WIDTH ? BOX_MIN_WIDTH : widgetContentWidth / 8; }), legendList: [] as WidgetLegend[], - dataTableLoading: false, }); const widgetOptionsState = reactive({ @@ -76,37 +66,14 @@ const widgetOptionsState = reactive({ }); /* Api */ -const fetchWidgetData = async (params: WidgetLoadParams): Promise => { - const defaultFetcher = state.isPrivateWidget - ? api.privateWidgetAPI.load - : api.publicWidgetAPI.load; - const res = await defaultFetcher(params); - return res; -}; - -const queryKey = computed(() => [ - ...(state.isPrivateWidget ? keys.privateWidgetLoadQueryKey.value : keys.publicWidgetLoadQueryKey.value), - props.dashboardId, - props.widgetId, - props.widgetName, - { - start: dateRange.value.start, - end: dateRange.value.end, - granularity: widgetOptionsState.granularityInfo?.granularity, - dataTableId: props.dataTableId, - // dataTableOptions: normalizeAndSerializeDataTableOptions(state.dataTable?.options as DataTableOptions), - // dataTables: normalizeAndSerializeDataTableOptions((props.dataTables || []).map((d) => d?.options || {})), - groupBy: [widgetOptionsState.groupByInfo?.data as string, widgetOptionsState.formatRulesInfo?.field as string], - vars: normalizeAndSerializeVars(props.dashboardVars), - }, -]); - -const queryResult = useQuery({ - queryKey, - queryFn: () => fetchWidgetData({ +const loadQuery = useWidgetLoadQuery({ + widgetId: computed(() => props.widgetId), + params: computed(() => ({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, - group_by: (widgetOptionsState.groupByInfo?.data && widgetOptionsState.formatRulesInfo?.field) ? [widgetOptionsState.groupByInfo?.data, widgetOptionsState.formatRulesInfo?.field] : [], + group_by: (widgetOptionsState.groupByInfo?.data && widgetOptionsState.formatRulesInfo?.field) + ? [widgetOptionsState.groupByInfo?.data as string, widgetOptionsState.formatRulesInfo?.field as string] + : [], start: dateRange.value.start, end: dateRange.value.end, vars: props.dashboardVars, @@ -114,19 +81,23 @@ const queryResult = useQuery({ start: 1, limit: MAX_COUNT, }, - }), - enabled: computed(() => props.widgetState !== 'INACTIVE' && !!state.dataTable && !props.loadDisabled), - staleTime: WIDGET_LOAD_STALE_TIME, + })), + additionalDeps: computed(() => ({ + widgetName: props.widgetName, + dataTableId: props.dataTableId, + })), + enabled: computed(() => props.widgetState !== 'INACTIVE' && !!dataTable.value && !props.loadDisabled), }); -const widgetLoading = computed(() => queryResult.isFetching.value || state.dataTableLoading); + +const widgetLoading = computed(() => loadQuery.isFetching.value || dataTableLoading.value); const errorMessage = computed(() => { - if (!state.dataTable) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE'); - return queryResult.error?.value?.message; + if (!dataTable.value) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE') as string; + return loadQuery.error?.value?.message as string; }); const refinedData = computed(() => { - const data = queryResult.data?.value; + const data = loadQuery.data?.value; if (!data?.results || !widgetOptionsState.groupByInfo?.data || !widgetOptionsState.formatRulesInfo?.field) return []; const groupByField = widgetOptionsState.groupByInfo.data as string; const formatRulesField = widgetOptionsState.formatRulesInfo.field as string; @@ -160,7 +131,7 @@ const { widgetFrameProps, widgetFrameEventHandlers } = useWidgetFrame(props, emi /* Util */ const getColor = (val: string, field: string): string => { const _label = getReferenceLabel(props.allReferenceTypeInfo, field, val); - return (widgetOptionsState.formatRulesInfo?.rules ?? []).find((d) => d.text === _label || _label.includes(d.text) || val.includes(d.text))?.color + return (widgetOptionsState.formatRulesInfo?.rules ?? []).find((d) => d.text && (d.text === _label || _label.includes(d.text) || val.includes(d.text)))?.color ?? widgetOptionsState.formatRulesInfo.baseColor as string; }; @@ -173,24 +144,9 @@ watch(() => widgetOptionsState.formatRulesInfo, async () => { })); }, { immediate: true }); - -watch(() => props.dataTableId, async (newDataTableId) => { - if (!newDataTableId) return; - state.dataTableLoading = true; - const fetcher = state.isPrivateWidget - ? api.privateDataTableAPI.get - : api.publicDataTableAPI.get; - try { - state.dataTable = await fetcher({ data_table_id: newDataTableId }); - } catch (e) { - ErrorHandler.handleError(e); - } finally { - state.dataTableLoading = false; - } -}, { immediate: true }); defineExpose({ loadWidget: () => { - queryResult.refetch(); + loadQuery.refetch(); }, }); onMounted(() => { diff --git a/apps/web/src/common/modules/widgets/_widgets/color-coded-table-heatmap/ColorCodedTableHeatmap.vue b/apps/web/src/common/modules/widgets/_widgets/color-coded-table-heatmap/ColorCodedTableHeatmap.vue index 011d429ad2..49110e10ca 100644 --- a/apps/web/src/common/modules/widgets/_widgets/color-coded-table-heatmap/ColorCodedTableHeatmap.vue +++ b/apps/web/src/common/modules/widgets/_widgets/color-coded-table-heatmap/ColorCodedTableHeatmap.vue @@ -4,27 +4,23 @@ import { computed, defineExpose, onMounted, reactive, ref, watch, } from 'vue'; -import { useQuery } from '@tanstack/vue-query'; import { cloneDeep, throttle } from 'lodash'; import { PTooltip } from '@cloudforet/mirinae'; import { getContrastingColor, numberFormatter } from '@cloudforet/utils'; -import type { WidgetLoadParams, WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; +import type { WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import { i18n } from '@/translations'; -import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetCustomLegend from '@/common/modules/widgets/_components/WidgetCustomLegend.vue'; import WidgetFrame from '@/common/modules/widgets/_components/WidgetFrame.vue'; +import { useWidgetDataTableQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-query'; import { useWidgetDateRange } from '@/common/modules/widgets/_composables/use-widget-date-range'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; import { useWidgetFrame } from '@/common/modules/widgets/_composables/use-widget-frame'; +import { useWidgetLoadQuery } from '@/common/modules/widgets/_composables/use-widget-load-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; -import { DATE_FIELD, WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; +import { DATE_FIELD } from '@/common/modules/widgets/_constants/widget-constant'; import { SUB_TOTAL_NAME } from '@/common/modules/widgets/_constants/widget-field-constant'; -import { - normalizeAndSerializeVars, -} from '@/common/modules/widgets/_helpers/global-variable-helper'; import { getReferenceLabel, getWidgetDateFields, getWidgetDateRange, @@ -42,7 +38,6 @@ import type { import type { GranularityValue } from '@/common/modules/widgets/_widget-fields/granularity/type'; import type { NumberFormatValue } from '@/common/modules/widgets/_widget-fields/number-format/type'; import type { XAxisValue } from '@/common/modules/widgets/_widget-fields/x-axis/type'; -import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; import type { DateRange } from '@/common/modules/widgets/types/widget-data-type'; import type { WidgetEmit, WidgetExpose, WidgetProps } from '@/common/modules/widgets/types/widget-display-type'; import type { WidgetLegend } from '@/common/modules/widgets/types/widget-legend-typs'; @@ -58,10 +53,11 @@ const BOX_MIN_WIDTH = 64; const props = defineProps(); const emit = defineEmits(); -const { keys, api } = useWidgetFormQuery({ - widgetId: computed(() => props.widgetId), - preventLoad: true, -}); +const { data: dataTable, isFetching: dataTableLoading } = useWidgetDataTableQuery( + computed(() => props.dataTableId), +); +const isPivotDataTable = computed(() => dataTable.value?.operator === DATA_TABLE_OPERATOR.PIVOT); + const { dateRange } = useWidgetDateRange({ dateRangeFieldValue: computed(() => (props.widgetOptions?.dateRange?.value as DateRangeValue)), @@ -70,10 +66,8 @@ const { dateRange } = useWidgetDateRange({ }); const state = reactive({ isPrivateWidget: computed(() => props.widgetId.startsWith('private')), - dataTable: undefined as DataTableModel|undefined, - isPivotDataTable: computed(() => state.dataTable?.operator === DATA_TABLE_OPERATOR.PIVOT), - data: computed(() => queryResult.data?.value), + data: computed(() => loadQuery.data?.value), dataField: computed(() => widgetOptionsState.dataFieldInfo?.data?.[0] || ''), // unit: computed(() => widgetFrameProps.value.unitMap?.[state.dataField]), boxWidth: BOX_MIN_WIDTH, @@ -88,7 +82,7 @@ const state = reactive({ }), yAxisData: computed(() => { if (!state.data?.results?.length) return []; - if (state.isPivotDataTable) { + if (isPivotDataTable.value) { const _excludeFields = [...Object.keys(state.data?.labels_info ?? {}), SUB_TOTAL_NAME]; return state.data.order?.filter((v) => !_excludeFields.includes(v)) || []; } @@ -103,7 +97,6 @@ const state = reactive({ } return { start: _start, end: _end }; }), - dataTableLoading: false, }); const widgetOptionsState = reactive({ @@ -117,49 +110,28 @@ const widgetOptionsState = reactive({ /* Api */ -const fetchWidgetData = async (params: WidgetLoadParams): Promise => { - const defaultFetcher = state.isPrivateWidget - ? api.privateWidgetAPI.load - : api.publicWidgetAPI.load; - const res = await defaultFetcher(params); - return res; -}; -const queryKey = computed(() => [ - ...(state.isPrivateWidget ? keys.privateWidgetLoadQueryKey.value : keys.publicWidgetLoadQueryKey.value), - props.dashboardId, - props.widgetId, - props.widgetName, - { - start: dateRange.value.start, - end: dateRange.value.end, - granularity: widgetOptionsState.granularityInfo?.granularity, - dataTableId: props.dataTableId, - // dataTableOptions: normalizeAndSerializeDataTableOptions(state.dataTable?.options || {}), - // dataTables: normalizeAndSerializeDataTableOptions((props.dataTables || []).map((d) => d?.options || {})), - groupBy: widgetOptionsState.xAxisInfo?.data, - count: widgetOptionsState.xAxisInfo?.count, - vars: normalizeAndSerializeVars(props.dashboardVars), - }, -]); - -const queryResult = useQuery({ - queryKey, - queryFn: () => fetchWidgetData({ +const loadQuery = useWidgetLoadQuery({ + widgetId: computed(() => props.widgetId), + params: computed(() => ({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, group_by: widgetOptionsState.xAxisInfo?.data ? [widgetOptionsState.xAxisInfo?.data as string] : [], ...getWidgetLoadApiQueryDateRange(widgetOptionsState.granularityInfo?.granularity, dateRange.value), ...(!isDateField(widgetOptionsState.xAxisInfo.data) && { page: { start: 1, limit: widgetOptionsState.xAxisInfo?.count } }), vars: props.dashboardVars, - }), - enabled: computed(() => props.widgetState !== 'INACTIVE' && !!state.dataTable && !props.loadDisabled), - staleTime: WIDGET_LOAD_STALE_TIME, + })), + additionalDeps: computed(() => ({ + widgetName: props.widgetName, + dataTableId: props.dataTableId, + })), + enabled: computed(() => props.widgetState !== 'INACTIVE' && !!dataTable.value && !props.loadDisabled), }); -const widgetLoading = computed(() => queryResult.isFetching.value || state.dataTableLoading); + +const widgetLoading = computed(() => loadQuery.isFetching.value || dataTableLoading.value); const errorMessage = computed(() => { - if (!state.dataTable) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE'); - return queryResult.error?.value?.message; + if (!dataTable.value) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE') as string; + return loadQuery.error?.value?.message as string; }); /* Util */ @@ -173,8 +145,8 @@ const targetValue = (xField?: string, yField?: string, format?: 'table'|'tooltip if (!_targetVal) return format === 'table' ? '--' : ''; if (!format) return _targetVal; if (format === 'table') { - const columnFieldForPivot = state.dataTable?.options.PIVOT?.fields?.column; - const fieldName = (state.isPivotDataTable && columnFieldForPivot) ? columnFieldForPivot : _field; + const columnFieldForPivot = dataTable.value?.options.PIVOT?.fields?.column; + const fieldName = (isPivotDataTable.value && columnFieldForPivot) ? columnFieldForPivot : _field; const numberFormat = widgetOptionsState.numberFormatInfo[fieldName]; const _formattedVal = getFormattedNumber(_targetVal, numberFormat); if ((_formattedVal.length * 6.5) > state.boxWidth) return '...'; @@ -239,24 +211,9 @@ watch(() => widgetOptionsState, () => { }, { deep: true }); /* Lifecycle */ - -watch(() => props.dataTableId, async (newDataTableId) => { - if (!newDataTableId) return; - state.dataTableLoading = true; - const fetcher = state.isPrivateWidget - ? api.privateDataTableAPI.get - : api.publicDataTableAPI.get; - try { - state.dataTable = await fetcher({ data_table_id: newDataTableId }); - } catch (e) { - ErrorHandler.handleError(e); - } finally { - state.dataTableLoading = false; - } -}, { immediate: true }); defineExpose({ loadWidget: () => { - queryResult.refetch(); + loadQuery.refetch(); }, }); onMounted(() => { diff --git a/apps/web/src/common/modules/widgets/_widgets/gauge/Gauge.vue b/apps/web/src/common/modules/widgets/_widgets/gauge/Gauge.vue index b81d93d694..ab94c99bba 100644 --- a/apps/web/src/common/modules/widgets/_widgets/gauge/Gauge.vue +++ b/apps/web/src/common/modules/widgets/_widgets/gauge/Gauge.vue @@ -4,7 +4,6 @@ import { computed, defineExpose, onMounted, reactive, ref, watch, } from 'vue'; -import { useQuery } from '@tanstack/vue-query'; import type { GaugeSeriesOption } from 'echarts/charts'; import type { EChartsType, @@ -13,18 +12,14 @@ import { init } from 'echarts/core'; import { isEmpty, orderBy, throttle } from 'lodash'; -import type { WidgetLoadParams, WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; +import type { WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import { i18n } from '@/translations'; -import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetFrame from '@/common/modules/widgets/_components/WidgetFrame.vue'; +import { useWidgetDataTableQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-query'; import { useWidgetDateRange } from '@/common/modules/widgets/_composables/use-widget-date-range'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; import { useWidgetFrame } from '@/common/modules/widgets/_composables/use-widget-frame'; -import { WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; -import { - normalizeAndSerializeVars, -} from '@/common/modules/widgets/_helpers/global-variable-helper'; +import { useWidgetLoadQuery } from '@/common/modules/widgets/_composables/use-widget-load-query'; import { getFormattedNumber } from '@/common/modules/widgets/_helpers/widget-helper'; import type { DataFieldValue } from '@/common/modules/widgets/_widget-fields/data-field/type'; import type { DateRangeValue } from '@/common/modules/widgets/_widget-fields/date-range/type'; @@ -33,7 +28,6 @@ import type { GranularityValue } from '@/common/modules/widgets/_widget-fields/g import type { MaxValue } from '@/common/modules/widgets/_widget-fields/max/type'; import type { MinValue } from '@/common/modules/widgets/_widget-fields/min/type'; import type { NumberFormatValue } from '@/common/modules/widgets/_widget-fields/number-format/type'; -import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; import type { WidgetProps, WidgetEmit, WidgetExpose, @@ -46,11 +40,9 @@ const props = defineProps(); const emit = defineEmits(); const chartContext = ref(null); - -const { keys, api } = useWidgetFormQuery({ - widgetId: computed(() => props.widgetId), - preventLoad: true, -}); +const { data: dataTable, isFetching: dataTableLoading } = useWidgetDataTableQuery( + computed(() => props.dataTableId), +); const { dateRange } = useWidgetDateRange({ dateRangeFieldValue: computed(() => (props.widgetOptions?.dateRange?.value as DateRangeValue)), @@ -59,13 +51,12 @@ const { dateRange } = useWidgetDateRange({ }); const state = reactive({ isPrivateWidget: computed(() => props.widgetId.startsWith('private')), - dataTable: undefined as DataTableModel|undefined, unit: computed(() => { if (!widgetOptionsState.dataFieldInfo?.data) return undefined; return widgetFrameProps.value.unitMap?.[widgetOptionsState.dataFieldInfo.data as string]; }), - data: computed(() => queryResult?.data?.value || null), + data: computed(() => loadQuery.data?.value || null), chart: null as EChartsType | null, chartData: undefined as undefined|number, chartOptions: computed<{series: GaugeSeriesOption[]}>(() => ({ @@ -129,7 +120,6 @@ const state = reactive({ }); return _color; }), - dataTableLoading: false, }); const widgetOptionsState = reactive({ @@ -143,47 +133,26 @@ const widgetOptionsState = reactive({ /* Api */ -const fetchWidgetData = async (params: WidgetLoadParams): Promise => { - const defaultFetcher = state.isPrivateWidget - ? api.privateWidgetAPI.load - : api.publicWidgetAPI.load; - const res = await defaultFetcher(params); - return res; -}; - -const queryKey = computed(() => [ - ...(state.isPrivateWidget ? keys.privateWidgetLoadQueryKey.value : keys.publicWidgetLoadQueryKey.value), - props.dashboardId, - props.widgetId, - props.widgetName, - { - start: dateRange.value.start, - end: dateRange.value.end, - granularity: widgetOptionsState.granularityInfo?.granularity, - dataTableId: props.dataTableId, - // dataTableOptions: normalizeAndSerializeDataTableOptions(state.dataTable?.options || {}), - // dataTables: normalizeAndSerializeDataTableOptions((props.dataTables || []).map((d) => d?.options || {})), - vars: normalizeAndSerializeVars(props.dashboardVars), - }, -]); - -const queryResult = useQuery({ - queryKey, - queryFn: () => fetchWidgetData({ +const loadQuery = useWidgetLoadQuery({ + widgetId: computed(() => props.widgetId), + params: computed(() => ({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, start: dateRange.value.start, end: dateRange.value.end, vars: props.dashboardVars, - }), - enabled: computed(() => props.widgetState !== 'INACTIVE' && !!state.dataTable && !props.loadDisabled), - staleTime: WIDGET_LOAD_STALE_TIME, + })), + additionalDeps: computed(() => ({ + widgetName: props.widgetName, + dataTableId: props.dataTableId, + })), + enabled: computed(() => props.widgetState !== 'INACTIVE' && !!dataTable.value && !props.loadDisabled), }); -const widgetLoading = computed(() => queryResult.isFetching.value || state.dataTableLoading); +const widgetLoading = computed(() => loadQuery.isFetching.value || dataTableLoading.value); const errorMessage = computed(() => { - if (!state.dataTable) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE'); - return queryResult.error?.value?.message; + if (!dataTable.value) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE') as string; + return loadQuery.error?.value?.message as string; }); /* Util */ @@ -205,27 +174,14 @@ watch([() => state.chartData, () => chartContext.value, () => props.widgetOption state.chart.setOption(state.chartOptions, true); } }); -watch([() => state.data, () => props.widgetOptions, () => state.dataTable], ([newData,, _dataTable]) => { +watch([() => state.data, () => props.widgetOptions, dataTable], ([newData,, _dataTable]) => { if (!_dataTable) return; drawChart(newData); }, { immediate: true }); -watch(() => props.dataTableId, async (newDataTableId) => { - if (!newDataTableId) return; - state.dataTableLoading = true; - const fetcher = state.isPrivateWidget - ? api.privateDataTableAPI.get - : api.publicDataTableAPI.get; - try { - state.dataTable = await fetcher({ data_table_id: newDataTableId }); - } catch (e) { - ErrorHandler.handleError(e); - } finally { - state.dataTableLoading = false; - } -}, { immediate: true }); + defineExpose({ loadWidget: () => { - queryResult.refetch(); + loadQuery.refetch(); }, }); onMounted(() => { diff --git a/apps/web/src/common/modules/widgets/_widgets/geo-map/GeoMap.vue b/apps/web/src/common/modules/widgets/_widgets/geo-map/GeoMap.vue index 50af4882f2..32e2c3d410 100644 --- a/apps/web/src/common/modules/widgets/_widgets/geo-map/GeoMap.vue +++ b/apps/web/src/common/modules/widgets/_widgets/geo-map/GeoMap.vue @@ -4,7 +4,6 @@ import { computed, defineExpose, onMounted, reactive, ref, watch, } from 'vue'; -import { useQuery } from '@tanstack/vue-query'; import axios from 'axios'; import type { MapSeriesOption } from 'echarts/charts'; import { init, registerMap } from 'echarts/core'; @@ -15,26 +14,21 @@ import { throttle } from 'lodash'; import { numberFormatter } from '@cloudforet/utils'; -import type { WidgetLoadParams, WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; +import type { WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import { i18n } from '@/translations'; import { useAllReferenceStore } from '@/store/reference/all-reference-store'; import type { RegionReferenceMap } from '@/store/reference/region-reference-store'; -import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetFrame from '@/common/modules/widgets/_components/WidgetFrame.vue'; +import { useWidgetDataTableQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-query'; import { useWidgetDateRange } from '@/common/modules/widgets/_composables/use-widget-date-range'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; import { useWidgetFrame } from '@/common/modules/widgets/_composables/use-widget-frame'; -import { WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; -import { - normalizeAndSerializeVars, -} from '@/common/modules/widgets/_helpers/global-variable-helper'; +import { useWidgetLoadQuery } from '@/common/modules/widgets/_composables/use-widget-load-query'; import type { DataFieldValue } from '@/common/modules/widgets/_widget-fields/data-field/type'; import type { DateRangeValue } from '@/common/modules/widgets/_widget-fields/date-range/type'; import type { GranularityValue } from '@/common/modules/widgets/_widget-fields/granularity/type'; import type { GroupByValue } from '@/common/modules/widgets/_widget-fields/group-by/type'; -import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; import type { WidgetProps, WidgetEmit, WidgetExpose, @@ -48,11 +42,9 @@ import { coral, gray } from '@/styles/colors'; const props = defineProps(); const emit = defineEmits(); const REGION_FIELD = 'Region'; - -const { keys, api } = useWidgetFormQuery({ - widgetId: computed(() => props.widgetId), - preventLoad: true, -}); +const { data: dataTable, isFetching: dataTableLoading } = useWidgetDataTableQuery( + computed(() => props.dataTableId), +); const { dateRange } = useWidgetDateRange({ dateRangeFieldValue: computed(() => (props.widgetOptions?.dateRange?.value as DateRangeValue)), @@ -67,9 +59,8 @@ const storeState = reactive({ const state = reactive({ mapLoaded: false, isPrivateWidget: computed(() => props.widgetId.startsWith('private')), - dataTable: undefined as DataTableModel|undefined, - data: computed(() => queryResult?.data?.value || null), + data: computed(() => loadQuery.data?.value || null), chart: null as EChartsType | null, chartData: [], unit: computed(() => widgetFrameProps.value.unitMap?.[widgetOptionsState.dataFieldInfo?.data as string]), @@ -108,7 +99,6 @@ const state = reactive({ }, ], })), - dataTableLoading: false, }); const widgetOptionsState = reactive({ @@ -118,49 +108,27 @@ const widgetOptionsState = reactive({ }); /* Api */ -const fetchWidgetData = async (params: WidgetLoadParams): Promise => { - const defaultFetcher = state.isPrivateWidget - ? api.privateWidgetAPI.load - : api.publicWidgetAPI.load; - const res = await defaultFetcher(params); - return res; -}; - -const queryKey = computed(() => [ - ...(state.isPrivateWidget ? keys.privateWidgetLoadQueryKey.value : keys.publicWidgetLoadQueryKey.value), - props.dashboardId, - props.widgetId, - props.widgetName, - { - start: dateRange.value.start, - end: dateRange.value.end, - granularity: widgetOptionsState.granularityInfo?.granularity, - dataTableId: props.dataTableId, - // dataTableOptions: normalizeAndSerializeDataTableOptions(state.dataTable?.options || {}), - // dataTables: normalizeAndSerializeDataTableOptions((props.dataTables || []).map((d) => d?.options || {})), - groupBy: widgetOptionsState.groupByInfo?.data, - vars: normalizeAndSerializeVars(props.dashboardVars), - }, -]); - -const queryResult = useQuery({ - queryKey, - queryFn: () => fetchWidgetData({ +const loadQuery = useWidgetLoadQuery({ + widgetId: computed(() => props.widgetId), + params: computed(() => ({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, group_by: !!widgetOptionsState.groupByInfo?.data && widgetOptionsState.groupByInfo?.data === 'Region' ? ['Region'] : [], vars: props.dashboardVars, start: dateRange.value.start, end: dateRange.value.end, - }), - enabled: computed(() => props.widgetState !== 'INACTIVE' && !!state.dataTable && !props.loadDisabled), - staleTime: WIDGET_LOAD_STALE_TIME, + })), + additionalDeps: computed(() => ({ + widgetName: props.widgetName, + dataTableId: props.dataTableId, + })), + enabled: computed(() => props.widgetState !== 'INACTIVE' && !!dataTable.value && !props.loadDisabled), }); -const widgetLoading = computed(() => queryResult.isFetching.value || state.dataTableLoading); -const errorMessage = computed(() => { - if (!state.dataTable) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE'); - return queryResult.error?.value?.message; +const widgetLoading = computed(() => loadQuery.isFetching.value || dataTableLoading.value); +const errorMessage = computed(() => { + if (!dataTable.value) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE') as string; + return loadQuery.error?.value?.message; }); /* Util */ @@ -206,7 +174,7 @@ watch([() => state.chartData, () => chartContext.value, () => state.mapLoaded], state.chart.setOption(state.chartOptions, true); } }); -watch([() => state.data, () => props.widgetOptions, () => state.dataTable], async ([newData,, _dataTable]) => { +watch([() => state.data, () => props.widgetOptions, dataTable], async ([newData,, _dataTable]) => { if (!_dataTable) return; await loadMap(); await drawChart(newData); @@ -216,23 +184,9 @@ useResizeObserver(chartContext, throttle(() => { state.chart?.resize(); }, 500)); -watch(() => props.dataTableId, async (newDataTableId) => { - if (!newDataTableId) return; - state.dataTableLoading = true; - const fetcher = state.isPrivateWidget - ? api.privateDataTableAPI.get - : api.publicDataTableAPI.get; - try { - state.dataTable = await fetcher({ data_table_id: newDataTableId }); - } catch (e) { - ErrorHandler.handleError(e); - } finally { - state.dataTableLoading = false; - } -}, { immediate: true }); defineExpose({ loadWidget: () => { - queryResult.refetch(); + loadQuery.refetch(); }, }); onMounted(() => { diff --git a/apps/web/src/common/modules/widgets/_widgets/heatmap/Heatmap.vue b/apps/web/src/common/modules/widgets/_widgets/heatmap/Heatmap.vue index e4b278e138..751f417581 100644 --- a/apps/web/src/common/modules/widgets/_widgets/heatmap/Heatmap.vue +++ b/apps/web/src/common/modules/widgets/_widgets/heatmap/Heatmap.vue @@ -4,7 +4,6 @@ import { computed, defineExpose, onMounted, reactive, ref, watch, } from 'vue'; -import { useQuery } from '@tanstack/vue-query'; import dayjs from 'dayjs'; import type { HeatmapSeriesOption } from 'echarts/charts'; import type { EChartsType } from 'echarts/core'; @@ -13,20 +12,17 @@ import { isEmpty, max, throttle } from 'lodash'; import { numberFormatter } from '@cloudforet/utils'; -import type { WidgetLoadParams, WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; +import type { WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import { i18n } from '@/translations'; -import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetFrame from '@/common/modules/widgets/_components/WidgetFrame.vue'; +import { useWidgetDataTableQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-query'; import { useWidgetDateRange } from '@/common/modules/widgets/_composables/use-widget-date-range'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; import { useWidgetFrame } from '@/common/modules/widgets/_composables/use-widget-frame'; +import { useWidgetLoadQuery } from '@/common/modules/widgets/_composables/use-widget-load-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; -import { DATE_FIELD, WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; +import { DATE_FIELD } from '@/common/modules/widgets/_constants/widget-constant'; import { SUB_TOTAL_NAME } from '@/common/modules/widgets/_constants/widget-field-constant'; -import { - normalizeAndSerializeVars, -} from '@/common/modules/widgets/_helpers/global-variable-helper'; import { getReferenceLabel, getWidgetDateFields, @@ -43,7 +39,6 @@ import type { DateRangeValue } from '@/common/modules/widgets/_widget-fields/dat import type { GranularityValue } from '@/common/modules/widgets/_widget-fields/granularity/type'; import type { LegendValue } from '@/common/modules/widgets/_widget-fields/legend/type'; import type { XAxisValue } from '@/common/modules/widgets/_widget-fields/x-axis/type'; -import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; import type { DateRange } from '@/common/modules/widgets/types/widget-data-type'; import type { WidgetEmit, WidgetExpose, WidgetProps } from '@/common/modules/widgets/types/widget-display-type'; @@ -53,10 +48,11 @@ import type { WidgetEmit, WidgetExpose, WidgetProps } from '@/common/modules/wid const props = defineProps(); const emit = defineEmits(); -const { keys, api } = useWidgetFormQuery({ - widgetId: computed(() => props.widgetId), - preventLoad: true, -}); +const { data: dataTable, isFetching: dataTableLoading } = useWidgetDataTableQuery( + computed(() => props.dataTableId), +); +const isPivotDataTable = computed(() => dataTable.value?.operator === DATA_TABLE_OPERATOR.PIVOT); + const { dateRange } = useWidgetDateRange({ dateRangeFieldValue: computed(() => (props.widgetOptions?.dateRange?.value as DateRangeValue)), @@ -67,10 +63,8 @@ const chartContext = ref(null); const state = reactive({ isPrivateWidget: computed(() => props.widgetId.startsWith('private')), - dataTable: undefined as DataTableModel|undefined, - isPivotDataTable: computed(() => state.dataTable?.operator === DATA_TABLE_OPERATOR.PIVOT), - data: computed(() => queryResult.data?.value ?? null), + data: computed(() => loadQuery.data?.value ?? null), dataField: computed(() => widgetOptionsState.dataFieldInfo?.data?.[0] || ''), chart: null as EChartsType | null, xAxisData: computed(() => { @@ -83,7 +77,7 @@ const state = reactive({ }), yAxisData: computed(() => { if (!state.data?.results?.length) return []; - if (state.isPivotDataTable) { + if (isPivotDataTable.value) { const _excludeFields = [...Object.keys(state.data?.labels_info ?? {}), SUB_TOTAL_NAME]; return state.data.order?.filter((v) => !_excludeFields.includes(v)) || []; } @@ -118,7 +112,7 @@ const state = reactive({ }, axisLabel: { formatter: (val) => { - if (state.isPivotDataTable) return getReferenceLabel(props.allReferenceTypeInfo, state.dataField, val); + if (isPivotDataTable.value) return getReferenceLabel(props.allReferenceTypeInfo, state.dataField, val); return val; }, }, @@ -169,7 +163,6 @@ const state = reactive({ } return { start: _start, end: _end }; }), - dataTableLoading: false, }); const widgetOptionsState = reactive({ @@ -182,49 +175,27 @@ const widgetOptionsState = reactive({ }); /* Api */ -const fetchWidgetData = async (params: WidgetLoadParams): Promise => { - const defaultFetcher = state.isPrivateWidget - ? api.privateWidgetAPI.load - : api.publicWidgetAPI.load; - const res = await defaultFetcher(params); - return res; -}; -const queryKey = computed(() => [ - ...(state.isPrivateWidget ? keys.privateWidgetLoadQueryKey.value : keys.publicWidgetLoadQueryKey.value), - props.dashboardId, - props.widgetId, - props.widgetName, - { - start: dateRange.value.start, - end: dateRange.value.end, - granularity: widgetOptionsState.granularityInfo?.granularity, - dataTableId: props.dataTableId, - // dataTableOptions: normalizeAndSerializeDataTableOptions(state.dataTable?.options || {}), - // dataTables: normalizeAndSerializeDataTableOptions((props.dataTables || []).map((d) => d?.options || {})), - groupBy: widgetOptionsState.xAxisInfo?.data, - count: widgetOptionsState.xAxisInfo?.count, - vars: normalizeAndSerializeVars(props.dashboardVars), - }, -]); - -const queryResult = useQuery({ - queryKey, - queryFn: () => fetchWidgetData({ +const loadQuery = useWidgetLoadQuery({ + widgetId: computed(() => props.widgetId), + params: computed(() => ({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, group_by: widgetOptionsState.xAxisInfo?.data ? [widgetOptionsState.xAxisInfo?.data] : [], ...getWidgetLoadApiQueryDateRange(widgetOptionsState.granularityInfo?.granularity, dateRange.value), ...(!isDateField(widgetOptionsState.xAxisInfo.data) && { page: { start: 0, limit: widgetOptionsState.xAxisInfo?.count } }), vars: props.dashboardVars, - }), - enabled: computed(() => props.widgetState !== 'INACTIVE' && !!state.dataTable && !props.loadDisabled), - staleTime: WIDGET_LOAD_STALE_TIME, + })), + additionalDeps: computed(() => ({ + widgetName: props.widgetName, + dataTableId: props.dataTableId, + })), + enabled: computed(() => props.widgetState !== 'INACTIVE' && !!dataTable.value && !props.loadDisabled), }); -const widgetLoading = computed(() => queryResult.isFetching.value || state.dataTableLoading); -const errorMessage = computed(() => { - if (!state.dataTable) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE'); - return queryResult.error?.value?.message; +const widgetLoading = computed(() => loadQuery.isFetching.value || dataTableLoading.value); +const errorMessage = computed(() => { + if (!dataTable.value) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE') as string; + return loadQuery.error?.value?.message as string; }); @@ -252,7 +223,7 @@ watch([() => state.chartData, () => chartContext.value], ([, chartCtx]) => { } }); -watch([() => state.data, () => props.widgetOptions, () => state.dataTable], ([newData,, _dataTable]) => { +watch([() => state.data, () => props.widgetOptions, dataTable], ([newData,, _dataTable]) => { if (!_dataTable) return; drawChart(newData); }, { immediate: true }); @@ -268,23 +239,9 @@ useResizeObserver(chartContext, throttle(() => { state.chart?.resize(); }, 500)); -watch(() => props.dataTableId, async (newDataTableId) => { - if (!newDataTableId) return; - state.dataTableLoading = true; - const fetcher = state.isPrivateWidget - ? api.privateDataTableAPI.get - : api.publicDataTableAPI.get; - try { - state.dataTable = await fetcher({ data_table_id: newDataTableId }); - } catch (e) { - ErrorHandler.handleError(e); - } finally { - state.dataTableLoading = false; - } -}, { immediate: true }); defineExpose({ loadWidget: () => { - queryResult.refetch(); + loadQuery.refetch(); }, }); onMounted(() => { diff --git a/apps/web/src/common/modules/widgets/_widgets/line-chart/LineChart.vue b/apps/web/src/common/modules/widgets/_widgets/line-chart/LineChart.vue index 8e7856cca8..2b51a5851a 100644 --- a/apps/web/src/common/modules/widgets/_widgets/line-chart/LineChart.vue +++ b/apps/web/src/common/modules/widgets/_widgets/line-chart/LineChart.vue @@ -4,7 +4,6 @@ import { computed, defineExpose, onMounted, reactive, ref, watch, } from 'vue'; -import { useQuery } from '@tanstack/vue-query'; import dayjs from 'dayjs'; import type { LineSeriesOption } from 'echarts/charts'; import { init } from 'echarts/core'; @@ -17,20 +16,17 @@ import { import { numberFormatter } from '@cloudforet/utils'; -import type { WidgetLoadParams, WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; +import type { WidgetLoadResponse } from '@/api-clients/dashboard/_types/widget-type'; import { i18n } from '@/translations'; -import ErrorHandler from '@/common/composables/error/errorHandler'; import WidgetFrame from '@/common/modules/widgets/_components/WidgetFrame.vue'; +import { useWidgetDataTableQuery } from '@/common/modules/widgets/_composables/use-widget-data-table-query'; import { useWidgetDateRange } from '@/common/modules/widgets/_composables/use-widget-date-range'; -import { useWidgetFormQuery } from '@/common/modules/widgets/_composables/use-widget-form-query'; import { useWidgetFrame } from '@/common/modules/widgets/_composables/use-widget-frame'; +import { useWidgetLoadQuery } from '@/common/modules/widgets/_composables/use-widget-load-query'; import { DATA_TABLE_OPERATOR } from '@/common/modules/widgets/_constants/data-table-constant'; -import { DATE_FIELD, WIDGET_LOAD_STALE_TIME } from '@/common/modules/widgets/_constants/widget-constant'; +import { DATE_FIELD } from '@/common/modules/widgets/_constants/widget-constant'; import { DATE_FORMAT, SUB_TOTAL_NAME } from '@/common/modules/widgets/_constants/widget-field-constant'; -import { - normalizeAndSerializeVars, -} from '@/common/modules/widgets/_helpers/global-variable-helper'; import { getReferenceLabel, getWidgetDateFields, getWidgetDateRange, } from '@/common/modules/widgets/_helpers/widget-date-helper'; @@ -49,7 +45,6 @@ import type { MissingValueValue } from '@/common/modules/widgets/_widget-fields/ import type { NumberFormatValue } from '@/common/modules/widgets/_widget-fields/number-format/type'; import type { TooltipNumberFormatValue } from '@/common/modules/widgets/_widget-fields/tooltip-number-format/type'; import type { XAxisValue } from '@/common/modules/widgets/_widget-fields/x-axis/type'; -import type { DataTableModel } from '@/common/modules/widgets/types/widget-data-table-type'; import type { DateRange } from '@/common/modules/widgets/types/widget-data-type'; import type { WidgetProps, WidgetEmit, WidgetExpose, @@ -63,10 +58,11 @@ import { MASSIVE_CHART_COLORS } from '@/styles/colorsets'; const props = defineProps(); const emit = defineEmits(); -const { keys, api } = useWidgetFormQuery({ - widgetId: computed(() => props.widgetId), - preventLoad: true, -}); +const { data: dataTable, isFetching: dataTableLoading } = useWidgetDataTableQuery( + computed(() => props.dataTableId), +); +const isPivotDataTable = computed(() => dataTable.value?.operator === DATA_TABLE_OPERATOR.PIVOT); + const { dateRange } = useWidgetDateRange({ dateRangeFieldValue: computed(() => (props.widgetOptions?.dateRange?.value as DateRangeValue)), @@ -76,10 +72,8 @@ const { dateRange } = useWidgetDateRange({ const chartContext = ref(null); const state = reactive({ isPrivateWidget: computed(() => props.widgetId.startsWith('private')), - dataTable: undefined as DataTableModel|undefined, - isPivotDataTable: computed(() => state.dataTable?.operator === DATA_TABLE_OPERATOR.PIVOT), - data: computed(() => queryResult?.data?.value || null), + data: computed(() => loadQuery.data?.value || null), chart: null as EChartsType | null, dataField: computed(() => widgetOptionsState.dataFieldInfo?.data?.[0] || ''), xAxisData: computed(() => { @@ -110,7 +104,7 @@ const state = reactive({ itemWidth: 10, itemHeight: 10, formatter: (val) => { - if (state.isPivotDataTable) return getReferenceLabel(props.allReferenceTypeInfo, state.dataField, val); + if (isPivotDataTable.value) return getReferenceLabel(props.allReferenceTypeInfo, state.dataField, val); return val; }, }, @@ -130,8 +124,8 @@ const state = reactive({ if (!_value) return undefined; if (_unit) _seriesName = `${_seriesName} (${_unit})`; if (widgetOptionsState.tooltipNumberFormatInfo?.toggleValue) { - const columnFieldForPivot = state.dataTable?.options.PIVOT?.fields?.column; - const fieldName = (state.isPivotDataTable && columnFieldForPivot) ? columnFieldForPivot : p.seriesName; + const columnFieldForPivot = dataTable.value?.options.PIVOT?.fields?.column; + const fieldName = (isPivotDataTable.value && columnFieldForPivot) ? columnFieldForPivot : p.seriesName; const numberFormat = widgetOptionsState.numberFormatInfo[fieldName]; _value = getFormattedNumber(p.value, numberFormat, _unit); } @@ -169,7 +163,6 @@ const state = reactive({ return { start: _start, end: _end }; }), dateFormat: computed(() => DATE_FORMAT?.[widgetOptionsState.dateFormatInfo?.format]?.[widgetOptionsState.granularityInfo?.granularity]), - dataTableLoading: false, }); const widgetOptionsState = reactive({ @@ -187,51 +180,29 @@ const widgetOptionsState = reactive({ /* Api */ -const fetchWidgetData = async (params: WidgetLoadParams): Promise => { - const defaultFetcher = state.isPrivateWidget - ? api.privateWidgetAPI.load - : api.publicWidgetAPI.load; - const res = await defaultFetcher(params); - return res; -}; - -const queryKey = computed(() => [ - ...(state.isPrivateWidget ? keys.privateWidgetLoadQueryKey.value : keys.publicWidgetLoadQueryKey.value), - props.dashboardId, - props.widgetId, - props.widgetName, - { - start: dateRange.value.start, - end: dateRange.value.end, - granularity: widgetOptionsState.granularityInfo?.granularity, - dataTableId: props.dataTableId, - // dataTableOptions: normalizeAndSerializeDataTableOptions(state.dataTable?.options || {}), - // dataTables: normalizeAndSerializeDataTableOptions((props.dataTables || []).map((d) => d?.options || {})), - groupBy: widgetOptionsState.xAxisInfo?.data, - count: widgetOptionsState.xAxisInfo?.count, - vars: normalizeAndSerializeVars(props.dashboardVars), - }, -]); - -const queryResult = useQuery({ - queryKey, - queryFn: () => fetchWidgetData({ +const loadQuery = useWidgetLoadQuery({ + widgetId: computed(() => props.widgetId), + params: computed(() => ({ widget_id: props.widgetId, granularity: widgetOptionsState.granularityInfo?.granularity, group_by: widgetOptionsState.xAxisInfo?.data ? [widgetOptionsState.xAxisInfo?.data] : [], - sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[], state.isPivotDataTable), + sort: getWidgetLoadApiQuerySort(widgetOptionsState.xAxisInfo?.data as string, widgetOptionsState.dataFieldInfo?.data as string[], isPivotDataTable.value), page: { start: 0, limit: widgetOptionsState.xAxisInfo?.count }, vars: props.dashboardVars, ...getWidgetLoadApiQueryDateRange(widgetOptionsState.granularityInfo?.granularity, dateRange.value), - }), - enabled: computed(() => props.widgetState !== 'INACTIVE' && !!state.dataTable && !props.loadDisabled), - staleTime: WIDGET_LOAD_STALE_TIME, + })), + additionalDeps: computed(() => ({ + widgetName: props.widgetName, + dataTableId: props.dataTableId, + })), + enabled: computed(() => props.widgetState !== 'INACTIVE' && !!dataTable.value && !props.loadDisabled), }); -const widgetLoading = computed(() => queryResult.isFetching.value || state.dataTableLoading); + +const widgetLoading = computed(() => loadQuery.isFetching.value || dataTableLoading.value); const errorMessage = computed(() => { - if (!state.dataTable) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE'); - return queryResult.error?.value?.message; + if (!dataTable.value) return i18n.t('COMMON.WIDGETS.NO_DATA_TABLE_ERROR_MESSAGE') as string; + return loadQuery.error?.value?.message as string; }); /* Util */ @@ -241,7 +212,7 @@ const drawChart = (rawData: WidgetLoadResponse|null) => { const _seriesData: any[] = []; const _defaultValue = widgetOptionsState.missingValueInfo?.type === 'lineToZero' ? 0 : undefined; let _dataFields: string[] = widgetOptionsState.dataFieldInfo?.data as string[] || []; - if (state.isPivotDataTable) { + if (isPivotDataTable.value) { const _excludeFields = [...Object.keys(rawData?.labels_info ?? {}), SUB_TOTAL_NAME]; _dataFields = rawData?.order?.filter((v) => !_excludeFields.includes(v)) || []; } @@ -263,8 +234,8 @@ const drawChart = (rawData: WidgetLoadResponse|null) => { fontSize: 10, formatter: (p) => { if (!p.value) return ''; - const columnFieldForPivot = state.dataTable?.options.PIVOT?.fields?.column; - const fieldName = (state.isPivotDataTable && columnFieldForPivot) ? columnFieldForPivot : _dataField; + const columnFieldForPivot = dataTable.value?.options.PIVOT?.fields?.column; + const fieldName = (isPivotDataTable.value && columnFieldForPivot) ? columnFieldForPivot : _dataField; const numberFormat = widgetOptionsState.numberFormatInfo[fieldName]; return getFormattedNumber(p.value, numberFormat, _unit); @@ -290,7 +261,7 @@ watch([() => state.chartData, () => chartContext.value], ([, chartCtx]) => { state.chart.setOption(state.chartOptions, true); } }); -watch([() => state.data, () => props.widgetOptions, () => state.dataTable], ([newData,, _dataTable]) => { +watch([() => state.data, () => props.widgetOptions, dataTable], ([newData,, _dataTable]) => { if (!_dataTable) return; drawChart(newData); }, { immediate: true }); @@ -300,23 +271,9 @@ useResizeObserver(chartContext, throttle(() => { state.chart?.resize(); }, 500)); -watch(() => props.dataTableId, async (newDataTableId) => { - if (!newDataTableId) return; - state.dataTableLoading = true; - const fetcher = state.isPrivateWidget - ? api.privateDataTableAPI.get - : api.publicDataTableAPI.get; - try { - state.dataTable = await fetcher({ data_table_id: newDataTableId }); - } catch (e) { - ErrorHandler.handleError(e); - } finally { - state.dataTableLoading = false; - } -}, { immediate: true }); defineExpose({ loadWidget: () => { - queryResult.refetch(); + loadQuery.refetch(); }, }); onMounted(() => { diff --git a/apps/web/src/common/modules/widgets/_widgets/number-card/NumberCard.vue b/apps/web/src/common/modules/widgets/_widgets/number-card/NumberCard.vue index 3cfa14de6d..357f36f0aa 100644 --- a/apps/web/src/common/modules/widgets/_widgets/number-card/NumberCard.vue +++ b/apps/web/src/common/modules/widgets/_widgets/number-card/NumberCard.vue @@ -1,10 +1,9 @@ + + diff --git a/apps/web/src/services/dashboards/components/dashboard-create/DashboardCreateBlankBoardItem.vue b/apps/web/src/services/_shared/dashboard/dashboard-create/components/DashboardCreateBlankBoardItem.vue similarity index 69% rename from apps/web/src/services/dashboards/components/dashboard-create/DashboardCreateBlankBoardItem.vue rename to apps/web/src/services/_shared/dashboard/dashboard-create/components/DashboardCreateBlankBoardItem.vue index f6754aded9..d2302754c3 100644 --- a/apps/web/src/services/dashboards/components/dashboard-create/DashboardCreateBlankBoardItem.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-create/components/DashboardCreateBlankBoardItem.vue @@ -4,8 +4,7 @@ import { } from '@cloudforet/mirinae'; import type { BoardSet } from '@cloudforet/mirinae/types/data-display/board/type'; -import { useDashboardCreatePageStore } from '@/services/dashboards/stores/dashboard-create-page-store'; - +import { useDashboardCreatePageStore } from '@/services/_shared/dashboard/dashboard-create/stores/dashboard-create-page-store'; interface Props { templateSets: BoardSet[]; @@ -32,14 +31,22 @@ const handleClickBlankBoardItem = () => { > +
+ + + Only Public + {{ $t('(Everyone in this workspace)') }} + +
diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardManageVariableImportModalTree.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardManageVariableImportModalTree.vue similarity index 100% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardManageVariableImportModalTree.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardManageVariableImportModalTree.vue diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardManageVariableOverlay.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardManageVariableOverlay.vue similarity index 83% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardManageVariableOverlay.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardManageVariableOverlay.vue index 5bcf99907c..9a3f18bbed 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardManageVariableOverlay.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardManageVariableOverlay.vue @@ -3,7 +3,7 @@ import { computed, reactive } from 'vue'; import type { TranslateResult } from 'vue-i18n'; import { useRouter } from 'vue-router/composables'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { cloneDeep } from 'lodash'; import { @@ -19,7 +19,6 @@ import type { } from '@/api-clients/dashboard/_types/dashboard-type'; import { i18n } from '@/translations'; -import { useAppContextStore } from '@/store/app-context/app-context-store'; import { useUserStore } from '@/store/user/user-store'; import { showSuccessMessage } from '@/lib/helper/notice-alert-helper'; @@ -27,20 +26,14 @@ import { showSuccessMessage } from '@/lib/helper/notice-alert-helper'; import DeleteModal from '@/common/components/modals/DeleteModal.vue'; import ErrorHandler from '@/common/composables/error/errorHandler'; -import DashboardManageVariableImportModal - from '@/services/dashboards/components/dashboard-detail/DashboardManageVariableImportModal.vue'; import DashboardVariablesFormModal - from '@/services/dashboards/components/dashboard-detail/DashboardVariablesFormModal.vue'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; + from '@/services/_shared/dashboard/dashboard-detail/components/DashboardVariablesFormModal.vue'; +import { useDashboardGetQuery } from '@/services/_shared/dashboard/dashboard-detail/composables/use-dashboard-get-query'; import { DASHBOARD_VARS_SCHEMA_PRESET, -} from '@/services/dashboards/constants/dashboard-vars-schema-preset'; -import { getOrderedGlobalVariables } from '@/services/dashboards/helpers/dashboard-global-variables-helper'; -import { ADMIN_DASHBOARDS_ROUTE } from '@/services/dashboards/routes/admin/route-constant'; -import { DASHBOARDS_ROUTE } from '@/services/dashboards/routes/route-constant'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; - - +} from '@/services/_shared/dashboard/dashboard-detail/constants/dashboard-vars-schema-preset'; +import { getOrderedGlobalVariables } from '@/services/_shared/dashboard/dashboard-detail/helpers/dashboard-global-variables-helper'; +import { useDashboardDetailInfoStore } from '@/services/_shared/dashboard/dashboard-detail/stores/dashboard-detail-info-store'; interface GlobalVariableTableItem { @@ -53,28 +46,27 @@ interface GlobalVariableTableItem { } interface Props { visible: boolean; + dashboardId: string; } const props = defineProps(); -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; const userStore = useUserStore(); -const appContextStore = useAppContextStore(); +const dashboardDetailInfoStore = useDashboardDetailInfoStore(); const router = useRouter(); +const dashboardId = computed(() => props.dashboardId); /* Query */ const { dashboard, keys, fetcher, - queryClient, isLoading, -} = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), +} = useDashboardGetQuery({ + dashboardId, }); +const queryClient = useQueryClient(); const state = reactive({ - isAdminMode: computed(() => appContextStore.getters.isAdminMode), selectedVariableKey: undefined as string|undefined, modalType: 'CREATE' as 'CREATE'|'UPDATE', formModalVisible: false, @@ -136,27 +128,27 @@ const isPresetVarsSchemaProperty = (key: string): boolean => { }; /* Api */ -const deleteDashboardVarsSchema = async (dashboardId: string, variableKey: string) => { +const deleteDashboardVarsSchema = async (_dashboardId: string, variableKey: string) => { const _varsSchemaProperties = cloneDeep(state.dashboardVarsSchemaProperties); delete _varsSchemaProperties[variableKey]; const _vars = cloneDeep(dashboard.value?.vars || {}); delete _vars[variableKey]; mutate({ - dashboard_id: dashboardId, + dashboard_id: _dashboardId, vars_schema: { properties: _varsSchemaProperties, }, vars: _vars, }); }; -const cloneDashboardVarsSchema = async (dashboardId: string, variableKey: string) => { +const cloneDashboardVarsSchema = async (_dashboardId: string, variableKey: string) => { const _clonedProperty = cloneDeep(state.dashboardVarsSchemaProperties[variableKey]); const _varsNameList: string[] = Object.values(state.dashboardVarsSchemaProperties).map((d) => d.name); const _varsKeyList: string[] = Object.values(state.dashboardVarsSchemaProperties).map((d) => d.key); _clonedProperty.key = getClonedName(_varsKeyList, _clonedProperty.key, 'clone_'); _clonedProperty.name = getClonedName(_varsNameList, _clonedProperty.name); mutate({ - dashboard_id: dashboardId, + dashboard_id: _dashboardId, vars_schema: { properties: { ...state.dashboardVarsSchemaProperties, @@ -169,11 +161,11 @@ const cloneDashboardVarsSchema = async (dashboardId: string, variableKey: string }, }); }; -const updateUseDashboardVarsSchema = (dashboardId: string, variableKey: string, use: boolean) => { +const updateUseDashboardVarsSchema = (_dashboardId: string, variableKey: string, use: boolean) => { const _vars = cloneDeep(dashboard.value?.vars || {}); delete _vars[variableKey]; mutate({ - dashboard_id: dashboardId, + dashboard_id: _dashboardId, vars_schema: { properties: { ...state.dashboardVarsSchemaProperties, @@ -218,7 +210,7 @@ const handleClickCreateButton = () => { state.formModalVisible = true; }; const handleClickImportButton = () => { - state.importModalVisible = true; + dashboardDetailInfoStore.setVariableImportModalVisible(true); }; const handleClickDeleteButton = (variableKey: string) => { state.selectedVariableKey = variableKey; @@ -230,28 +222,30 @@ const handleClickEditButton = (variableKey: string) => { state.formModalVisible = true; }; const handleClickCloneButton = (variableKey: string) => { - if (!dashboardDetailState.dashboardId) return; + if (!dashboardId.value) return; state.actionType = 'CLONE'; - cloneDashboardVarsSchema(dashboardDetailState.dashboardId, variableKey); + cloneDashboardVarsSchema(dashboardId.value, variableKey); }; const handleToggleUse = (variableKey: string, val: boolean) => { - if (!dashboardDetailState.dashboardId) return; + if (!dashboardId.value) return; state.actionType = 'UPDATE'; - updateUseDashboardVarsSchema(dashboardDetailState.dashboardId, variableKey, val); + updateUseDashboardVarsSchema(dashboardId.value, variableKey, val); }; const handleCloseOverlay = () => { - const dashboardDetailRouteName = state.isAdminMode - ? ADMIN_DASHBOARDS_ROUTE.DETAIL._NAME - : DASHBOARDS_ROUTE.DETAIL._NAME; + const _currentRoute = router.currentRoute; + if (!_currentRoute.name) { + console.error('currentRoute is not provided'); + return; + } router.replace({ - name: dashboardDetailRouteName, - params: { dashboardId: dashboardDetailState.dashboardId ?? '' }, + name: _currentRoute.name, + params: _currentRoute.params, }).catch(() => {}); }; const handleConfirmDelete = () => { - if (!dashboardDetailState.dashboardId || !state.selectedVariableKey) return; + if (!dashboardId.value || !state.selectedVariableKey) return; state.actionType = 'DELETE'; - deleteDashboardVarsSchema(dashboardDetailState.dashboardId, state.selectedVariableKey); + deleteDashboardVarsSchema(dashboardId.value, state.selectedVariableKey); }; @@ -328,6 +322,7 @@ const handleConfirmDelete = () => { { - diff --git a/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardManageVariablePortalTargets.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardManageVariablePortalTargets.vue new file mode 100644 index 0000000000..e5c9469320 --- /dev/null +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardManageVariablePortalTargets.vue @@ -0,0 +1,8 @@ + + + diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardRefreshDropdown.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardRefreshDropdown.vue similarity index 89% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardRefreshDropdown.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardRefreshDropdown.vue index 6ae95754cb..2c8284948c 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardRefreshDropdown.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardRefreshDropdown.vue @@ -5,7 +5,7 @@ import { } from 'vue'; import type { TranslateResult } from 'vue-i18n'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { PIconButton, PSelectDropdown } from '@cloudforet/mirinae'; import type { MenuItem } from '@cloudforet/mirinae/types/controls/context-menu/type'; @@ -16,9 +16,9 @@ import type { PrivateDashboardModel } from '@/api-clients/dashboard/private-dash import type { PublicDashboardModel } from '@/api-clients/dashboard/public-dashboard/schema/model'; import { i18n } from '@/translations'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; -import { useDashboardManageable } from '@/services/dashboards/composables/use-dashboard-manageable'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; +import { useDashboardManageable } from '@/services/_shared/dashboard/core/composables/_internal/use-dashboard-manageable'; +import { useDashboardGetQuery } from '@/services/_shared/dashboard/dashboard-detail/composables/use-dashboard-get-query'; +import { useDashboardDetailInfoStore } from '@/services/_shared/dashboard/dashboard-detail/stores/dashboard-detail-info-store'; const REFRESH_INTERVAL_OPTIONS = Object.keys(REFRESH_INTERVAL_OPTIONS_MAP); @@ -41,13 +41,13 @@ const dashboardDetailState = dashboardDetailStore.state; /* Query */ const { - dashboard, keys, fetcher, queryClient, -} = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), -}); -const { isManageable } = useDashboardManageable({ - dashboardId: computed(() => dashboardDetailState.dashboardId), + dashboard, keys, fetcher, +} = useDashboardGetQuery({ + dashboardId: computed(() => props.dashboardId), }); +const queryClient = useQueryClient(); +const { getDashboardManageable } = useDashboardManageable(); +const dashboardManageable = computed(() => getDashboardManageable(dashboard.value)); const state = reactive({ intervalOptionList: computed<{label: TranslateResult; value: RefreshIntervalOption}[]>(() => [ @@ -103,9 +103,9 @@ const handleSelectRefreshIntervalOption = (option) => { clearRefreshInterval(); executeRefreshInterval(); - if (isManageable.value) { + if (dashboardManageable.value) { mutate({ - dashboard_id: dashboardDetailState.dashboardId, + dashboard_id: props.dashboardId, options: { ...(dashboard.value?.options || {}), refresh_interval_option: option, diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardReorderSidebar.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardReorderSidebar.vue similarity index 89% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardReorderSidebar.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardReorderSidebar.vue index b85dad62a9..e6b0dff036 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardReorderSidebar.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardReorderSidebar.vue @@ -5,7 +5,7 @@ import { } from 'vue'; import draggable from 'vuedraggable'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import { PI, PButton, @@ -21,25 +21,34 @@ import { useDisplayStore } from '@/store/display/display-store'; import { WIDGET_COMPONENT_ICON_MAP } from '@/common/modules/widgets/_constants/widget-components-constant'; import { getWidgetConfig } from '@/common/modules/widgets/_helpers/widget-config-helper'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; +import { useDashboardGetQuery } from '@/services/_shared/dashboard/dashboard-detail/composables/use-dashboard-get-query'; +import { useDashboardWidgetListQuery } from '@/services/_shared/dashboard/dashboard-detail/composables/use-dashboard-widget-list-query'; + type WidgetModel = PublicWidgetModel | PrivateWidgetModel; + +const props = defineProps<{ + dashboardId: string; +}>(); + const displayStore = useDisplayStore(); -const dashboardDetailStore = useDashboardDetailInfoStore(); -const dashboardDetailState = dashboardDetailStore.state; +const dashboardId = computed(() => props.dashboardId); /* Query */ const { dashboard, - widgetList, keys, fetcher, - queryClient, -} = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), +} = useDashboardGetQuery({ + dashboardId, +}); +const { + widgetList, +} = useDashboardWidgetListQuery({ + dashboardId, }); +const queryClient = useQueryClient(); const state = reactive({ widgetList: computed(() => { const results: WidgetModel[] = []; @@ -61,7 +70,7 @@ const handleChangeWidgetOrder = () => { const _widgetIdList = state.widgetList.map((w) => w.widget_id); const _updatedLayouts = [{ widgets: _widgetIdList }]; updateDashboard({ - dashboard_id: dashboardDetailState.dashboardId || '', + dashboard_id: dashboardId.value || '', layouts: _updatedLayouts, }); }; @@ -84,7 +93,7 @@ const { mutate: updateDashboard } = useMutation( }, ); -watch(() => dashboardDetailState.dashboardId, (after, before) => { +watch(() => dashboardId.value, (after, before) => { if (after !== before) { displayStore.setVisibleSidebar(false); } diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardToolsetDateCustomModal.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetDateCustomModal.vue similarity index 100% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardToolsetDateCustomModal.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetDateCustomModal.vue diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardToolsetDateDropdown.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetDateDropdown.vue similarity index 86% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardToolsetDateDropdown.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetDateDropdown.vue index 4f01e9ae5e..01e5afe2c5 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardToolsetDateDropdown.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetDateDropdown.vue @@ -2,8 +2,9 @@ import { computed, reactive, watch, } from 'vue'; +import { useRoute } from 'vue-router/composables'; -import { useMutation } from '@tanstack/vue-query'; +import { useMutation, useQueryClient } from '@tanstack/vue-query'; import dayjs from 'dayjs'; import { cloneDeep, range } from 'lodash'; @@ -17,10 +18,11 @@ import { i18n } from '@/translations'; import { useI18nDayjs } from '@/common/composables/i18n-dayjs'; -import DashboardToolsetDateCustomModal from '@/services/dashboards/components/dashboard-detail/DashboardToolsetDateCustomModal.vue'; -import { useDashboardDetailQuery } from '@/services/dashboards/composables/use-dashboard-detail-query'; -import { useDashboardManageable } from '@/services/dashboards/composables/use-dashboard-manageable'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; +import { useDashboardManageable } from '@/services/_shared/dashboard/core/composables/_internal/use-dashboard-manageable'; +import DashboardToolsetDateCustomModal + from '@/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetDateCustomModal.vue'; +import { useDashboardGetQuery } from '@/services/_shared/dashboard/dashboard-detail/composables/use-dashboard-get-query'; +import { useDashboardDetailInfoStore } from '@/services/_shared/dashboard/dashboard-detail/stores/dashboard-detail-info-store'; interface Props { dateRange?: DateRange; @@ -33,19 +35,20 @@ const props = withDefaults(defineProps(), { const { i18nDayjs } = useI18nDayjs(); const dashboardDetailStore = useDashboardDetailInfoStore(); const dashboardDetailState = dashboardDetailStore.state; +const route = useRoute(); +const dashboardId = computed(() => route.params.dashboardId); /* Query */ const { dashboard, fetcher, keys, - queryClient, -} = useDashboardDetailQuery({ - dashboardId: computed(() => dashboardDetailState.dashboardId), -}); -const { isManageable } = useDashboardManageable({ - dashboardId: computed(() => dashboardDetailState.dashboardId), +} = useDashboardGetQuery({ + dashboardId, }); +const queryClient = useQueryClient(); +const { getDashboardManageable } = useDashboardManageable(); +const dashboardManageable = computed(() => getDashboardManageable(dashboard.value)); const state = reactive({ monthMenuItems: computed(() => { const monthData: MenuItem[] = []; @@ -112,9 +115,9 @@ const handleSelectMonthMenuItem = (selected: string) => { updateDashboardDateRange(state.selectedDateRange); } - if (isManageable.value && !props.widgetMode) { + if (dashboardManageable.value && !props.widgetMode) { mutate({ - dashboard_id: dashboardDetailState.dashboardId, + dashboard_id: dashboardId.value, options: { ...(dashboard.value?.options || {}), date_range: state.selectedDateRange, diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardToolsetScope.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetScope.vue similarity index 98% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardToolsetScope.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetScope.vue index 457dbb192e..59fedf905c 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardToolsetScope.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardToolsetScope.vue @@ -19,9 +19,9 @@ import type { WorkspaceReferenceMap } from '@/store/reference/workspace-referenc import ErrorHandler from '@/common/composables/error/errorHandler'; import WorkspaceLogoIcon from '@/common/modules/navigations/top-bar/modules/top-bar-header/WorkspaceLogoIcon.vue'; +import { useDashboardDetailInfoStore } from '@/services/_shared/dashboard/dashboard-detail/stores/dashboard-detail-info-store'; import { workspaceStateFormatter } from '@/services/advanced/composables/refined-table-data'; import { WORKSPACE_STATE } from '@/services/advanced/constants/workspace-constant'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesFormDynamic.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardVariablesFormDynamic.vue similarity index 99% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesFormDynamic.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardVariablesFormDynamic.vue index da21e38ba0..a3a4cd5a3a 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesFormDynamic.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardVariablesFormDynamic.vue @@ -30,7 +30,7 @@ import { useProxyValue } from '@/common/composables/proxy-state'; import { DASHBOARD_GLOBAL_VARIABLES_PRESET_LIST, -} from '@/services/dashboards/constants/dashboard-global-variable-preset'; +} from '@/services/_shared/dashboard/dashboard-detail/constants/dashboard-global-variable-preset'; const SELECTION_TYPE = { MULTI_SELECT: 'multi', @@ -51,13 +51,11 @@ const emit = defineEmits<{(e: 'update:is-valid', isValid: boolean): void; (e: 'update:data', data: DynamicVariableData): void; }>(); -const appContextStore = useAppContextStore(); const allReferenceStore = useAllReferenceStore(); - +const appContextStore = useAppContextStore(); const { visibleContents } = useContentsAccessibility(MENU_ID.ASSET_INVENTORY); const storeState = reactive({ - isAdminMode: computed(() => appContextStore.getters.isAdminMode), namespaces: computed(() => allReferenceStore.getters.namespace), providers: computed(() => allReferenceStore.getters.provider), metrics: computed(() => allReferenceStore.getters.metric), @@ -201,7 +199,7 @@ const state = reactive({ selectedCostDataSourceMenuItem: computed(() => state.costDataSourceMenuItems.filter((d) => d.name === state.selectedCostDataSourceId)), }); const { allItems: costDataSourceFilterMenuItems } = useCostDataSourceFilterMenuItems({ - isAdminMode: computed(() => storeState.isAdminMode), + isAdminMode: computed(() => appContextStore.getters.isAdminMode), costDataSource: computed(() => storeState.costDataSources[state.selectedCostDataSourceId]), }); diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesFormManual.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardVariablesFormManual.vue similarity index 100% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesFormManual.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardVariablesFormManual.vue diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesFormModal.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardVariablesFormModal.vue similarity index 92% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesFormModal.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardVariablesFormModal.vue index 8185722b9a..6ee6d79d5c 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesFormModal.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/components/DashboardVariablesFormModal.vue @@ -1,7 +1,7 @@ + + + + diff --git a/apps/web/src/services/_shared/dashboard/dashboard-detail/contextual-components/DashboardDetailHeader.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/contextual-components/DashboardDetailHeader.vue new file mode 100644 index 0000000000..5f0d75d962 --- /dev/null +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/contextual-components/DashboardDetailHeader.vue @@ -0,0 +1,193 @@ + + + + + diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesV2.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/contextual-components/DashboardVariablesV2.vue similarity index 58% rename from apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesV2.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/contextual-components/DashboardVariablesV2.vue index 88a58c3b21..215622031a 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardVariablesV2.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/contextual-components/DashboardVariablesV2.vue @@ -1,5 +1,7 @@ diff --git a/apps/web/src/services/_shared/dashboard/dashboard-detail/contextual-composables/use-dashboard-refined-vars.ts b/apps/web/src/services/_shared/dashboard/dashboard-detail/contextual-composables/use-dashboard-refined-vars.ts new file mode 100644 index 0000000000..48eb20c59b --- /dev/null +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/contextual-composables/use-dashboard-refined-vars.ts @@ -0,0 +1,51 @@ +import type { ComputedRef } from 'vue'; +import { computed } from 'vue'; + +import { cloneDeep, isEmpty } from 'lodash'; + +import type { DashboardVars } from '@/api-clients/dashboard/_types/dashboard-type'; + +import WorkspaceVariableModel from '@/lib/variable-models/managed-model/resource-model/workspace-variable-model'; + +import { useDashboardSharedContext } from '@/services/_shared/dashboard/core/composables/_internal/use-dashboard-shared-context'; +import { useDashboardGetQuery } from '@/services/_shared/dashboard/dashboard-detail/composables/use-dashboard-get-query'; +import { useDashboardDetailInfoStore } from '@/services/_shared/dashboard/dashboard-detail/stores/dashboard-detail-info-store'; +import { useDashboardVarsStore } from '@/services/_shared/dashboard/dashboard-detail/stores/dashboard-vars-store'; + +export const useDashboardRefinedVars = (dashboardId: ComputedRef) => { + const dashboardVarsStore = useDashboardVarsStore(); + const dashboardVarsState = dashboardVarsStore.state; + const dashboardDetailStore = useDashboardDetailInfoStore(); + const dashboardDetailState = dashboardDetailStore.state; + + const { dashboard } = useDashboardGetQuery({ + dashboardId, + }); + const { projectContextType, projectGroupOrProjectId, isAdminMode } = useDashboardSharedContext(); + + const refinedVars = computed(() => { + let _vars: DashboardVars = cloneDeep(dashboard.value?.vars ?? {}); + const tempVars: DashboardVars = cloneDeep(dashboardVarsState.vars ?? {}); + if (!isEmpty(tempVars)) _vars = tempVars; + if (projectGroupOrProjectId.value) { + if (projectContextType.value === 'PROJECT') { + _vars.project_id = [projectGroupOrProjectId.value]; + } else if (projectContextType.value === 'PROJECT_GROUP') { + _vars.project_group_id = [projectGroupOrProjectId.value]; + } + } + + const selectedWorkspaceId = dashboardDetailState.selectedWorkspaceId; + if (isAdminMode.value) { + if (selectedWorkspaceId && selectedWorkspaceId !== 'all') { + _vars[WorkspaceVariableModel.meta.idKey] = [selectedWorkspaceId]; + } else { + delete _vars[WorkspaceVariableModel.meta.idKey]; + } + } else { + delete _vars[WorkspaceVariableModel.meta.idKey]; + } + return _vars; + }); + return { refinedVars }; +}; diff --git a/apps/web/src/services/dashboards/helpers/__tests__/widget-width-helper.md b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/__tests__/widget-width-helper.md similarity index 100% rename from apps/web/src/services/dashboards/helpers/__tests__/widget-width-helper.md rename to apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/__tests__/widget-width-helper.md diff --git a/apps/web/src/services/dashboards/helpers/__tests__/widget-width-helper.test.ts b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/__tests__/widget-width-helper.test.ts similarity index 95% rename from apps/web/src/services/dashboards/helpers/__tests__/widget-width-helper.test.ts rename to apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/__tests__/widget-width-helper.test.ts index 10d587673e..84db9f26c7 100644 --- a/apps/web/src/services/dashboards/helpers/__tests__/widget-width-helper.test.ts +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/__tests__/widget-width-helper.test.ts @@ -5,8 +5,8 @@ import type { WidgetSize } from '@/api-clients/dashboard/_types/widget-type'; import { WIDGET_CONTAINER_MAX_WIDTH, WIDGET_CONTAINER_MIN_WIDTH, -} from '@/services/dashboards/constants/widget-container-config'; -import { widgetWidthAssigner } from '@/services/dashboards/helpers/widget-width-helper'; +} from '@/services/_shared/dashboard/dashboard-detail/constants/widget-container-config'; +import { widgetWidthAssigner } from '@/services/_shared/dashboard/dashboard-detail/helpers/widget-width-helper'; /** diff --git a/apps/web/src/services/dashboards/helpers/dashboard-global-variables-helper.ts b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/dashboard-global-variables-helper.ts similarity index 82% rename from apps/web/src/services/dashboards/helpers/dashboard-global-variables-helper.ts rename to apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/dashboard-global-variables-helper.ts index d0464b125a..f97cec240a 100644 --- a/apps/web/src/services/dashboards/helpers/dashboard-global-variables-helper.ts +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/dashboard-global-variables-helper.ts @@ -2,7 +2,7 @@ import { orderBy } from 'lodash'; import type { DashboardGlobalVariable } from '@/api-clients/dashboard/_types/dashboard-global-variable-type'; -import { DASHBOARD_VARS_SCHEMA_PRESET } from '@/services/dashboards/constants/dashboard-vars-schema-preset'; +import { DASHBOARD_VARS_SCHEMA_PRESET } from '@/services/_shared/dashboard/dashboard-detail/constants/dashboard-vars-schema-preset'; export const getOrderedGlobalVariables = (variables: DashboardGlobalVariable[]): DashboardGlobalVariable[] => { const _presetKeys: string[] = Object.keys(DASHBOARD_VARS_SCHEMA_PRESET.properties); diff --git a/apps/web/src/services/dashboards/helpers/dashboard-widget-info-helper.ts b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/dashboard-widget-info-helper.ts similarity index 89% rename from apps/web/src/services/dashboards/helpers/dashboard-widget-info-helper.ts rename to apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/dashboard-widget-info-helper.ts index a3a89fb5f3..3e4eb3378c 100644 --- a/apps/web/src/services/dashboards/helpers/dashboard-widget-info-helper.ts +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/dashboard-widget-info-helper.ts @@ -11,9 +11,9 @@ import type { import getRandomId from '@/lib/random-id-generator'; -import { getInheritingOptionKeys } from '@/services/dashboards/widgets/_helpers/widget-inherit-options-helper'; -import { getWidgetOptionKeyByVariableKey } from '@/services/dashboards/widgets/_helpers/widget-schema-helper'; -import type { UpdatableWidgetInfo } from '@/services/dashboards/widgets/_types/widget-type'; +import { getInheritingOptionKeys } from '@/services/_shared/dashboard/dashboard-detail/legacy/widgets/_helpers/widget-inherit-options-helper'; +import { getWidgetOptionKeyByVariableKey } from '@/services/_shared/dashboard/dashboard-detail/legacy/widgets/_helpers/widget-schema-helper'; +import type { UpdatableWidgetInfo } from '@/services/_shared/dashboard/dashboard-detail/legacy/widgets/_types/widget-type'; /** * @description get updated widget info. if the property is not changed, it will be declared as undefined. diff --git a/apps/web/src/services/dashboards/helpers/widget-theme-helper.ts b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/widget-theme-helper.ts similarity index 84% rename from apps/web/src/services/dashboards/helpers/widget-theme-helper.ts rename to apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/widget-theme-helper.ts index f842fa52e9..868dcf95eb 100644 --- a/apps/web/src/services/dashboards/helpers/widget-theme-helper.ts +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/widget-theme-helper.ts @@ -1,5 +1,5 @@ -import type { WidgetThemeOption, WidgetThemeAssignedList } from '@/services/dashboards/constants/widget-container-config'; -import { WIDGET_THEMES } from '@/services/dashboards/widgets/_types/widget-type'; +import type { WidgetThemeOption, WidgetThemeAssignedList } from '@/services/_shared/dashboard/dashboard-detail/constants/widget-container-config'; +import { WIDGET_THEMES } from '@/services/_shared/dashboard/dashboard-detail/legacy/widgets/_types/widget-type'; const WIDGET_THEME_LEN = WIDGET_THEMES.length; diff --git a/apps/web/src/services/dashboards/helpers/widget-width-helper.ts b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/widget-width-helper.ts similarity index 96% rename from apps/web/src/services/dashboards/helpers/widget-width-helper.ts rename to apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/widget-width-helper.ts index 5a2e6a3bf3..a6ec224dc4 100644 --- a/apps/web/src/services/dashboards/helpers/widget-width-helper.ts +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/helpers/widget-width-helper.ts @@ -7,7 +7,7 @@ import { WIDGET_WIDTH_RANGE_LIST, WIDGET_GAP, WIDGET_WIDTH_CRITERIA, -} from '@/services/dashboards/constants/widget-container-config'; +} from '@/services/_shared/dashboard/dashboard-detail/constants/widget-container-config'; const isEveryWidthMax = (sizeRow: string[], widthRow: number[]): boolean => sizeRow.every((size, idx) => { diff --git a/apps/web/src/services/dashboards/components/legacy/DashboardManageVariableForm.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardManageVariableForm.vue similarity index 97% rename from apps/web/src/services/dashboards/components/legacy/DashboardManageVariableForm.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardManageVariableForm.vue index acd9bc3b1b..377bb8250a 100644 --- a/apps/web/src/services/dashboards/components/legacy/DashboardManageVariableForm.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardManageVariableForm.vue @@ -15,11 +15,11 @@ import getRandomId from '@/lib/random-id-generator'; import { useFormValidator } from '@/common/composables/form-validator'; import DashboardManageVariableOptionsField - from '@/services/dashboards/components/legacy/DashboardManageVariableOptionsField.vue'; + from '@/services/_shared/dashboard/dashboard-detail/legacy/DashboardManageVariableOptionsField.vue'; import type { ManageVariableFormOption, ManageVariableOverlayStatus, -} from '@/services/dashboards/types/manage-variable-type'; +} from '@/services/_shared/dashboard/dashboard-detail/types/manage-variable-type'; const CLONE_PREFIX = 'Copy - '; diff --git a/apps/web/src/services/dashboards/components/legacy/DashboardManageVariableOptionsField.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardManageVariableOptionsField.vue similarity index 100% rename from apps/web/src/services/dashboards/components/legacy/DashboardManageVariableOptionsField.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardManageVariableOptionsField.vue diff --git a/apps/web/src/services/dashboards/components/legacy/DashboardVariableDropdown.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardVariableDropdown.vue similarity index 98% rename from apps/web/src/services/dashboards/components/legacy/DashboardVariableDropdown.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardVariableDropdown.vue index e9d6446a08..0f365f0863 100644 --- a/apps/web/src/services/dashboards/components/legacy/DashboardVariableDropdown.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardVariableDropdown.vue @@ -27,8 +27,8 @@ import { getVariableModelMenuHandler } from '@/lib/variable-models/variable-mode import WorkspaceLogoIcon from '@/common/modules/navigations/top-bar/modules/top-bar-header/WorkspaceLogoIcon.vue'; +import { useDashboardDetailInfoStore } from '@/services/_shared/dashboard/dashboard-detail/stores/dashboard-detail-info-store'; import { getWorkspaceInfo } from '@/services/advanced/composables/refined-table-data'; -import { useDashboardDetailInfoStore } from '@/services/dashboards/stores/dashboard-detail-info-store'; interface Props { diff --git a/apps/web/src/services/dashboards/components/legacy/DashboardVariables.vue b/apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardVariables.vue similarity index 89% rename from apps/web/src/services/dashboards/components/legacy/DashboardVariables.vue rename to apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardVariables.vue index d1dd61aceb..f430aeb83a 100644 --- a/apps/web/src/services/dashboards/components/legacy/DashboardVariables.vue +++ b/apps/web/src/services/_shared/dashboard/dashboard-detail/legacy/DashboardVariables.vue @@ -1,5 +1,6 @@ + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetCreateFormAmountPlan.vue b/apps/web/src/services/cost-explorer/components/BudgetCreateFormAmountPlan.vue index a142221bc4..0b94359de4 100644 --- a/apps/web/src/services/cost-explorer/components/BudgetCreateFormAmountPlan.vue +++ b/apps/web/src/services/cost-explorer/components/BudgetCreateFormAmountPlan.vue @@ -99,7 +99,7 @@ watch([() => state.amountPlanInfo, () => state.isAllValid], ([amountPlanInfo, is
import { - computed, defineEmits, reactive, watch, + computed, reactive, watch, } from 'vue'; import { diff --git a/apps/web/src/services/cost-explorer/components/BudgetCreateManagerSelect.vue b/apps/web/src/services/cost-explorer/components/BudgetCreateManagerSelect.vue new file mode 100644 index 0000000000..1b75cffb2c --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetCreateManagerSelect.vue @@ -0,0 +1,61 @@ + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetCreateScopeSelect.vue b/apps/web/src/services/cost-explorer/components/BudgetCreateScopeSelect.vue new file mode 100644 index 0000000000..39e6134bf9 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetCreateScopeSelect.vue @@ -0,0 +1,108 @@ + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetCreateStep1.vue b/apps/web/src/services/cost-explorer/components/BudgetCreateStep1.vue new file mode 100644 index 0000000000..3b91cc8050 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetCreateStep1.vue @@ -0,0 +1,196 @@ + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetCreateStep2.vue b/apps/web/src/services/cost-explorer/components/BudgetCreateStep2.vue new file mode 100644 index 0000000000..4ea3ba7fe6 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetCreateStep2.vue @@ -0,0 +1,698 @@ + + + + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetCreateStep3.vue b/apps/web/src/services/cost-explorer/components/BudgetCreateStep3.vue new file mode 100644 index 0000000000..399938a680 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetCreateStep3.vue @@ -0,0 +1,210 @@ + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetDeleteCheckModal.vue b/apps/web/src/services/cost-explorer/components/BudgetDeleteCheckModal.vue new file mode 100644 index 0000000000..55c2043395 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetDeleteCheckModal.vue @@ -0,0 +1,71 @@ + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetDetailBaseInformation.vue b/apps/web/src/services/cost-explorer/components/BudgetDetailBaseInformation.vue new file mode 100644 index 0000000000..dedefc644f --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetDetailBaseInformation.vue @@ -0,0 +1,484 @@ + + + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetDetailDeleteModal.vue b/apps/web/src/services/cost-explorer/components/BudgetDetailDeleteModal.vue index c6723ee189..e7af83959f 100644 --- a/apps/web/src/services/cost-explorer/components/BudgetDetailDeleteModal.vue +++ b/apps/web/src/services/cost-explorer/components/BudgetDetailDeleteModal.vue @@ -1,77 +1,62 @@ - - - + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetDetailHeading.vue b/apps/web/src/services/cost-explorer/components/BudgetDetailHeading.vue index 07f13379bd..0b7226e2ac 100644 --- a/apps/web/src/services/cost-explorer/components/BudgetDetailHeading.vue +++ b/apps/web/src/services/cost-explorer/components/BudgetDetailHeading.vue @@ -1,16 +1,16 @@ + + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetListPeriodCustomModal.vue b/apps/web/src/services/cost-explorer/components/BudgetListPeriodCustomModal.vue new file mode 100644 index 0000000000..9085d0825e --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetListPeriodCustomModal.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetMainList.vue b/apps/web/src/services/cost-explorer/components/BudgetMainList.vue index 6884206ac7..86d57d5e3e 100644 --- a/apps/web/src/services/cost-explorer/components/BudgetMainList.vue +++ b/apps/web/src/services/cost-explorer/components/BudgetMainList.vue @@ -1,84 +1,355 @@ - - diff --git a/apps/web/src/services/cost-explorer/components/BudgetMainToolbox.vue b/apps/web/src/services/cost-explorer/components/BudgetMainToolbox.vue index c6618f1407..f46138095a 100644 --- a/apps/web/src/services/cost-explorer/components/BudgetMainToolbox.vue +++ b/apps/web/src/services/cost-explorer/components/BudgetMainToolbox.vue @@ -1,6 +1,6 @@ + + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetNameEditModal.vue b/apps/web/src/services/cost-explorer/components/BudgetNameEditModal.vue new file mode 100644 index 0000000000..b9342dedd8 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetNameEditModal.vue @@ -0,0 +1,112 @@ + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetUsageTrend.vue b/apps/web/src/services/cost-explorer/components/BudgetUsageTrend.vue new file mode 100644 index 0000000000..30de3d5620 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetUsageTrend.vue @@ -0,0 +1,29 @@ + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetUsageTrendMonthly.vue b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendMonthly.vue new file mode 100644 index 0000000000..02f3dcdd62 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendMonthly.vue @@ -0,0 +1,57 @@ + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetUsageTrendMonthlyChart.vue b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendMonthlyChart.vue new file mode 100644 index 0000000000..d0a78d923c --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendMonthlyChart.vue @@ -0,0 +1,227 @@ + + + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetUsageTrendMonthlyTable.vue b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendMonthlyTable.vue new file mode 100644 index 0000000000..e3137edbe9 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendMonthlyTable.vue @@ -0,0 +1,217 @@ + + + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetUsageTrendTotal.vue b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendTotal.vue new file mode 100644 index 0000000000..271b6dae27 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendTotal.vue @@ -0,0 +1,55 @@ + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetUsageTrendTotalChart.vue b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendTotalChart.vue new file mode 100644 index 0000000000..ad0c627ff8 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendTotalChart.vue @@ -0,0 +1,259 @@ + + + + + diff --git a/apps/web/src/services/cost-explorer/components/BudgetUsageTrendTotalTable.vue b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendTotalTable.vue new file mode 100644 index 0000000000..32d0a768f8 --- /dev/null +++ b/apps/web/src/services/cost-explorer/components/BudgetUsageTrendTotalTable.vue @@ -0,0 +1,294 @@ + + + + + diff --git a/apps/web/src/services/cost-explorer/components/CostAnalysisChartLegends.vue b/apps/web/src/services/cost-explorer/components/CostAnalysisChartLegends.vue index 57c208e8f7..2fe814d36f 100644 --- a/apps/web/src/services/cost-explorer/components/CostAnalysisChartLegends.vue +++ b/apps/web/src/services/cost-explorer/components/CostAnalysisChartLegends.vue @@ -1,6 +1,6 @@ + + diff --git a/apps/web/src/services/cost-explorer/pages/BudgetDetailPage.vue b/apps/web/src/services/cost-explorer/pages/BudgetDetailPage.vue index 179b5a3e22..f6bf045071 100644 --- a/apps/web/src/services/cost-explorer/pages/BudgetDetailPage.vue +++ b/apps/web/src/services/cost-explorer/pages/BudgetDetailPage.vue @@ -7,36 +7,33 @@ import { PLink, PScopedNotification } from '@cloudforet/mirinae'; import type { BudgetModel } from '@/api-clients/cost-analysis/budget/schema/model'; import { i18n } from '@/translations'; -import { useGlobalConfigStore } from '@/store/global-config/global-config-store'; +import { useGlobalConfigSchemaStore } from '@/store/global-config-schema/global-config-schema-store'; import { useUserStore } from '@/store/user/user-store'; import ErrorHandler from '@/common/composables/error/errorHandler'; +import BudgetDetailBaseInformation from '@/services/cost-explorer/components/BudgetDetailBaseInformation.vue'; import BudgetDetailHeading from '@/services/cost-explorer/components/BudgetDetailHeading.vue'; -import BudgetDetailInfo from '@/services/cost-explorer/components/BudgetDetailInfo.vue'; -import BudgetDetailNotifications - from '@/services/cost-explorer/components/BudgetDetailNotifications.vue'; -import BudgetDetailSummary - from '@/services/cost-explorer/components/BudgetDetailSummary.vue'; +import BudgetUsageTrend from '@/services/cost-explorer/components/BudgetUsageTrend.vue'; import { ADMIN_COST_EXPLORER_ROUTE } from '@/services/cost-explorer/routes/admin/route-constant'; import { useBudgetDetailPageStore } from '@/services/cost-explorer/stores/budget-detail-page-store'; interface Props { - budgetId: string; + budgetId: string; } const props = withDefaults(defineProps(), { budgetId: '', }); const userStore = useUserStore(); -const globalConfigStore = useGlobalConfigStore(); +const globalConfigSchemaStore = useGlobalConfigSchemaStore(); const budgetPageStore = useBudgetDetailPageStore(); const budgetPageState = budgetPageStore.$state; const state = reactive({ loading: true, budgetData: computed(() => budgetPageState.budgetData), - visibleBudgetNotification: computed(() => globalConfigStore.state.schema.ALERT_MANAGER?.uiAffects?.visibleBudgetNotification ?? false), + visibleBudgetNotification: computed(() => globalConfigSchemaStore.state.uiAffectsSchema.ALERT_MANAGER?.visibleBudgetNotification ?? false), isWorkspaceTarget: computed(() => (state.budgetData?.resource_group === 'WORKSPACE')), adminModeLink: computed(() => ({ name: ADMIN_COST_EXPLORER_ROUTE.BUDGET.DETAIL._NAME, @@ -59,47 +56,51 @@ const state = reactive({ state.loading = false; } })(); - - diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardFolderSingleMoveModal.vue b/apps/web/src/services/dashboards/components/dashboard-detail/DashboardFolderSingleMoveModal.vue index b619728e5e..cd4d44671e 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardFolderSingleMoveModal.vue +++ b/apps/web/src/services/dashboards/components/dashboard-detail/DashboardFolderSingleMoveModal.vue @@ -3,7 +3,7 @@ import { computed, reactive, watch, } from 'vue'; -import { useMutation } from '@tanstack/vue-query'; +import { useQueryClient } from '@tanstack/vue-query'; import { PButtonModal, PFieldGroup, PI, PSelectDropdown, @@ -11,14 +11,6 @@ import { import type { SelectDropdownMenuItem } from '@cloudforet/mirinae/types/controls/dropdown/select-dropdown/type'; import type { DashboardChangeFolderParams } from '@/api-clients/dashboard/_types/dashboard-type'; -import type { - PrivateDashboardChangeFolderParameters, -} from '@/api-clients/dashboard/private-dashboard/schema/api-verbs/change-folder'; -import type { PrivateFolderModel } from '@/api-clients/dashboard/private-folder/schema/model'; -import type { - PublicDashboardChangeFolderParameters, -} from '@/api-clients/dashboard/public-dashboard/schema/api-verbs/change-folder'; -import type { PublicFolderModel } from '@/api-clients/dashboard/public-folder/schema/model'; import { i18n } from '@/translations'; import { useAppContextStore } from '@/store/app-context/app-context-store'; @@ -27,13 +19,12 @@ import { showErrorMessage, showSuccessMessage } from '@/lib/helper/notice-alert- import { useProxyValue } from '@/common/composables/proxy-state'; +import { useDashboardChangeFolderMutation } from '@/services/_shared/dashboard/core/composables/mutations/use-dashboard-change-folder-mutation'; +import { useDashboardFolderQuery } from '@/services/dashboards/composables/use-dashboard-folder-query'; import { useDashboardQuery } from '@/services/dashboards/composables/use-dashboard-query'; import { useDashboardPageControlStore } from '@/services/dashboards/stores/dashboard-page-control-store'; - - -type DashboardModel = PrivateFolderModel | PublicFolderModel; interface Props { visible: boolean; dashboardId: string; @@ -48,13 +39,14 @@ const appContextStore = useAppContextStore(); const dashboardPageControlStore = useDashboardPageControlStore(); /* Query */ +const queryClient = useQueryClient(); const { - publicFolderList, - privateFolderList, keys, - api, - queryClient, } = useDashboardQuery(); +const { + publicFolderList, + privateFolderList, +} = useDashboardFolderQuery(); const storeState = reactive({ isAdminMode: computed(() => appContextStore.getters.isAdminMode), @@ -92,30 +84,20 @@ const state = reactive({ }); /* Api */ -const changeFolderFn = (params: PrivateDashboardChangeFolderParameters | PublicDashboardChangeFolderParameters): Promise => { - const _isPrivate = props.dashboardId.startsWith('private'); - if (_isPrivate) { - return api.privateDashboardAPI.changeFolder(params as PrivateDashboardChangeFolderParameters); - } - return api.publicDashboardAPI.changeFolder(params as PublicDashboardChangeFolderParameters); -}; -const { mutate: changeFolder } = useMutation( - { - mutationFn: changeFolderFn, - onSuccess: () => { - showSuccessMessage(i18n.t('DASHBOARDS.DETAIL.ALT_S_MOVE_DASHBOARD'), ''); - const isPrivate = props.dashboardId.startsWith('private'); - const dashboardListQueryKey = isPrivate ? keys.privateDashboardListQueryKey : keys.publicDashboardListQueryKey; - queryClient.invalidateQueries({ queryKey: dashboardListQueryKey.value }); - }, - onError: (e) => { - showErrorMessage(i18n.t('DASHBOARDS.DETAIL.ALT_E_MOVE_DASHBOARD'), e); - }, - onSettled: () => { - state.proxyVisible = false; - }, +const { mutate: changeFolder } = useDashboardChangeFolderMutation({ + onSuccess: () => { + showSuccessMessage(i18n.t('DASHBOARDS.DETAIL.ALT_S_MOVE_DASHBOARD'), ''); + const isPrivate = props.dashboardId.startsWith('private'); + const dashboardListQueryKey = isPrivate ? keys.privateDashboardListQueryKey : keys.publicDashboardListQueryKey; + queryClient.invalidateQueries({ queryKey: dashboardListQueryKey.value }); }, -); + onError: (e) => { + showErrorMessage(i18n.t('DASHBOARDS.DETAIL.ALT_E_MOVE_DASHBOARD'), e); + }, + onSettled: () => { + state.proxyVisible = false; + }, +}); /* Event */ const handleFormConfirm = async () => { diff --git a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardManageVariableImportModal.vue b/apps/web/src/services/dashboards/components/dashboard-detail/DashboardManageVariableImportModal.vue index 015e796ff9..d04b6a0553 100644 --- a/apps/web/src/services/dashboards/components/dashboard-detail/DashboardManageVariableImportModal.vue +++ b/apps/web/src/services/dashboards/components/dashboard-detail/DashboardManageVariableImportModal.vue @@ -1,7 +1,7 @@