From 0eba6989e45b147a7ddd0ab0bfc753a2c3a68e2b Mon Sep 17 00:00:00 2001 From: vitshev Date: Tue, 3 Sep 2024 15:42:00 +0200 Subject: [PATCH] feat(Queries): default ACO [#436] --- packages/ui/README.md | 21 +++++----- .../ui/src/shared/constants/settings-types.ts | 11 +++-- packages/ui/src/shared/yt-types.d.ts | 3 +- .../containers/SettingsMenu/SettingsMenu.scss | 5 +++ .../SettingsMenu/SettingsMenuSelect.tsx | 41 +++++++++++++++++++ .../SettingsPanel/settings-description.tsx | 33 +++++++++++++++ .../QueryResults/hooks/useCurrentQuery.ts | 6 ++- .../src/ui/pages/query-tracker/module/api.ts | 16 ++++---- .../query-tracker/module/query/actions.ts | 24 +++++++---- .../query-tracker/module/query/selectors.ts | 24 ++++++++--- .../query-tracker/module/query/utills.ts | 5 +-- .../query-tracker/module/query_aco/actions.ts | 27 +++++++++++- .../query-tracker/module/query_aco/reducer.ts | 2 + .../module/query_aco/selectors.ts | 24 +++++++++-- 14 files changed, 197 insertions(+), 45 deletions(-) create mode 100644 packages/ui/src/ui/containers/SettingsMenu/SettingsMenuSelect.tsx diff --git a/packages/ui/README.md b/packages/ui/README.md index 7a9fc8844..f25a10f83 100644 --- a/packages/ui/README.md +++ b/packages/ui/README.md @@ -81,16 +81,17 @@ It is supposed that a user is developer on a cluster if he has `write` access to Available flags (**default values** are highlighted in bold): -| Flag name | Allowed values | Description | -| :----------------------------------- | :----------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -| enable_per_bundle_tablet_accounting | **true**, false | Allows editing of resources of tablets through BundleEditorDialog [YTFRONT-2851](https://nda.ya.ru/t/xnLq-3Dm6fPYPo) | -| enable_per_account_tablet_accounting | **false**, true | Allows editing of resources of tablets through AccountEditorDialog [YTFRONT-2851](https://nda.ya.ru/t/xnLq-3Dm6fPYPo) | -| per_bundle_accounting_help_link | **null**, url as string | Help link for resources of tablets to display from AccountEditorDialog about moving the resources to bundles [YTFRONT-2851](https://nda.ya.ru/t/xnLq-3Dm6fPYPo) | -| enable_maintenance_api_nodes | **null**, boolean | Allows to use `add_maintenance`/`remove_maintenance` commands from `Comopnents/Nodes` page [YTFRONT-3792](https://nda.ya.ru/t/RvueJLzN6fWx3h) | -| enable_maintenance_api_proxies | **null**, boolean | Allows to use `add_maintenance`/`remove_maintenance` commands from `Components/HTTP Proxies` and `Components/RPC Proxies` pages [YTFRONT-3792](https://nda.ya.ru/t/RvueJLzN6fWx3h) | -| chyt_controller_base_url | **null**, url as string | Base url for chyt-controller | -| livy_controller_base_url | **null**, url as string | Base url for spyt-controller | -| job_trace_url_template | **null**, `{title: string; url_template: string; enforce_for_trees?: Array}` | If defined adds `Job trace` item to meta-table on `Job/Details` page for a job with `archive_features/has_trace == true` and for jobs from a tree in `enforce_for_trees`, example: `{title: 'Open im MyProfiling', url_template: 'https://my.profiling.service/{cluster}/{operationId}/{jobId}', enforce_for_trees: ['tree-with-traces'] }` | +| Flag name | Allowed values | Description | +|:---------------------------------------|:-------------------------------------------------------------------------------------|:--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| enable_per_bundle_tablet_accounting | **true**, false | Allows editing of resources of tablets through BundleEditorDialog [YTFRONT-2851](https://nda.ya.ru/t/xnLq-3Dm6fPYPo) | +| enable_per_account_tablet_accounting | **false**, true | Allows editing of resources of tablets through AccountEditorDialog [YTFRONT-2851](https://nda.ya.ru/t/xnLq-3Dm6fPYPo) | +| per_bundle_accounting_help_link | **null**, url as string | Help link for resources of tablets to display from AccountEditorDialog about moving the resources to bundles [YTFRONT-2851](https://nda.ya.ru/t/xnLq-3Dm6fPYPo) | +| enable_maintenance_api_nodes | **null**, boolean | Allows to use `add_maintenance`/`remove_maintenance` commands from `Comopnents/Nodes` page [YTFRONT-3792](https://nda.ya.ru/t/RvueJLzN6fWx3h) | +| enable_maintenance_api_proxies | **null**, boolean | Allows to use `add_maintenance`/`remove_maintenance` commands from `Components/HTTP Proxies` and `Components/RPC Proxies` pages [YTFRONT-3792](https://nda.ya.ru/t/RvueJLzN6fWx3h) | +| chyt_controller_base_url | **null**, url as string | Base url for chyt-controller | +| livy_controller_base_url | **null**, url as string | Base url for spyt-controller | +| job_trace_url_template | **null**, `{title: string; url_template: string; enforce_for_trees?: Array}` | If defined adds `Job trace` item to meta-table on `Job/Details` page for a job with `archive_features/has_trace == true` and for jobs from a tree in `enforce_for_trees`, example: `{title: 'Open im MyProfiling', url_template: 'https://my.profiling.service/{cluster}/{operationId}/{jobId}', enforce_for_trees: ['tree-with-traces'] }` | +| query_tracker_default_aco | **null**, `{stage1: string; stage2: string; }` | Sets the default ACO in Query Tracker requests for each stage | ### Configuration diff --git a/packages/ui/src/shared/constants/settings-types.ts b/packages/ui/src/shared/constants/settings-types.ts index 1cfb29379..64e3e4db9 100644 --- a/packages/ui/src/shared/constants/settings-types.ts +++ b/packages/ui/src/shared/constants/settings-types.ts @@ -69,7 +69,7 @@ interface AccountsSettings { 'global::accounts::dashboardVisibilityMode': 'string'; } -type ClusterName = string; +export type Stage = string; interface QueryTrackerSettings { 'global::queryTracker::queriesListSidebarVisibilityMode': boolean; @@ -81,7 +81,11 @@ interface ChytSettings { } type QueryTrackerLastSelectedACOsSettings = { - [key in `local::${ClusterName}::queryTracker::lastSelectedACOs`]: string[]; + [key in `qt-stage::${Stage}::queryTracker::lastSelectedACOs`]: string[]; +}; + +type QueryTrackerUserDefaultACOSettings = { + [key in `qt-stage::${Stage}::queryTracker::defaultACO`]: string; }; interface OtherSettings { @@ -113,7 +117,8 @@ type DescribedSettings = GlobalSettings & AccountsSettings & QueryTrackerSettings & ChytSettings & - QueryTrackerLastSelectedACOsSettings; + QueryTrackerLastSelectedACOsSettings & + QueryTrackerUserDefaultACOSettings; export type Settings = DescribedSettings & OtherSettings; diff --git a/packages/ui/src/shared/yt-types.d.ts b/packages/ui/src/shared/yt-types.d.ts index aff38f9e4..ddbca122a 100644 --- a/packages/ui/src/shared/yt-types.d.ts +++ b/packages/ui/src/shared/yt-types.d.ts @@ -1,5 +1,5 @@ import type {YTError} from '../@types/types'; -import type {Settings} from './constants/settings-types'; +import type {Settings, Stage} from './constants/settings-types'; import type {UISettings} from './ui-settings'; export interface YTConfig { @@ -24,6 +24,7 @@ export interface ClusterUiConfig { enable_maintenance_api_proxies?: boolean; chyt_controller_base_url?: string; livy_controller_base_url?: string; + query_tracker_default_aco?: Record; job_trace_url_template?: { title: string; url_template: string; diff --git a/packages/ui/src/ui/containers/SettingsMenu/SettingsMenu.scss b/packages/ui/src/ui/containers/SettingsMenu/SettingsMenu.scss index 80e93156a..30d6af138 100644 --- a/packages/ui/src/ui/containers/SettingsMenu/SettingsMenu.scss +++ b/packages/ui/src/ui/containers/SettingsMenu/SettingsMenu.scss @@ -52,6 +52,11 @@ &_one-line { display: flex; } + + &_select { + margin-left: 0; + margin-bottom: 0; + } } &-annotation { diff --git a/packages/ui/src/ui/containers/SettingsMenu/SettingsMenuSelect.tsx b/packages/ui/src/ui/containers/SettingsMenu/SettingsMenuSelect.tsx new file mode 100644 index 000000000..d6c14921e --- /dev/null +++ b/packages/ui/src/ui/containers/SettingsMenu/SettingsMenuSelect.tsx @@ -0,0 +1,41 @@ +import React, {useEffect, useState} from 'react'; +import block from 'bem-cn-lite'; +import {SelectSingle} from '../../components/Select/Select'; + +import './SettingsMenu.scss'; + +const b = block('elements-page'); + +type SettingsMenuSelectOption = + | {options: Array<{value: string; text: string}>} + | {getOptionsOnMount: () => Promise>}; +type SettingsMenuSelectProps = { + placeholder?: string; + label?: string; + getSetting: () => string; + setSetting: (value?: string) => void; +} & SettingsMenuSelectOption; + +export const SettingsMenuSelect = (props: SettingsMenuSelectProps) => { + const value = props.getSetting(); + const [items, setItems] = useState('options' in props ? props.options : []); + + useEffect(() => { + if ('getOptionsOnMount' in props) { + props?.getOptionsOnMount().then((options) => { + setItems(options); + }); + } + }, []); + + return ( +
+ props.setSetting(value)} + placeholder={props.placeholder} + /> +
+ ); +}; diff --git a/packages/ui/src/ui/containers/SettingsPanel/settings-description.tsx b/packages/ui/src/ui/containers/SettingsPanel/settings-description.tsx index 6eb50b9c4..d31866645 100644 --- a/packages/ui/src/ui/containers/SettingsPanel/settings-description.tsx +++ b/packages/ui/src/ui/containers/SettingsPanel/settings-description.tsx @@ -53,6 +53,11 @@ import Link from '../../components/Link/Link'; import Button from '../../components/Button/Button'; import {AddTokenForm, VcsList} from '../../pages/query-tracker/Vcs/SettingsMenu'; import {selectIsVcsVisible, selectVcsConfig} from '../../pages/query-tracker/module/vcs/selectors'; +import {SettingsMenuSelect} from '../SettingsMenu/SettingsMenuSelect'; +import {getDefaultQueryACO} from '../../pages/query-tracker/module/query_aco/selectors'; +import {getQueryACO, setUserDefaultACO} from '../../pages/query-tracker/module/query_aco/actions'; +import {Item} from '../../components/Select/Select'; +import {useThunkDispatch} from '../../store/thunkDispatch'; export interface SettingsPage { title: string; @@ -80,6 +85,7 @@ function wrapEscapeText(text: string) { } function useSettings(cluster: string, isAdmin: boolean): Array { + const dispatch = useThunkDispatch(); const clusterNS = useSelector(getCurrentClusterNS); const httpProxyVersion: string = useSelector(getHttpProxyVersion); @@ -87,6 +93,7 @@ function useSettings(cluster: string, isAdmin: boolean): Array { const masterVersion: string = useSelector(getGlobalMasterVersion); const vcsConfig = useSelector(selectVcsConfig); const isVcsVisible = useSelector(selectIsVcsVisible); + const defaultUserACO = useSelector(getDefaultQueryACO); return compact_([ makePage('General', generalIcon, [ @@ -511,6 +518,32 @@ function useSettings(cluster: string, isAdmin: boolean): Array { ]), ), + makePage( + 'Query ACO', + undefined, + compact_([ + makeItem( + 'Default ACO', + undefined, + + dispatch(getQueryACO()).then((data) => { + return data.access_control_objects.reduce( + (acc: Item[], item: string) => { + acc.push({value: item, text: item}); + return acc; + }, + [] as Item[], + ); + }) + } + setSetting={(value) => value && dispatch(setUserDefaultACO(value))} + getSetting={() => defaultUserACO} + />, + ), + ]), + ), + makePage( 'About', infoIcon, diff --git a/packages/ui/src/ui/pages/query-tracker/QueryResults/hooks/useCurrentQuery.ts b/packages/ui/src/ui/pages/query-tracker/QueryResults/hooks/useCurrentQuery.ts index a9274a804..2e7062565 100644 --- a/packages/ui/src/ui/pages/query-tracker/QueryResults/hooks/useCurrentQuery.ts +++ b/packages/ui/src/ui/pages/query-tracker/QueryResults/hooks/useCurrentQuery.ts @@ -3,6 +3,7 @@ import {useDispatch, useSelector} from 'react-redux'; import {QueriesPoolingContext} from '../../hooks/QueriesPooling/context'; import {getCurrentQuery} from '../../module/query/selectors'; +import {getDefaultQueryACO} from '../../module/query_aco/selectors'; import {isQueryProgress} from '../../utils/query'; import {QueryItem} from '../../module/api'; import {prepareQueryPlanIds} from '../../module/query/utills'; @@ -10,6 +11,7 @@ import {UPDATE_QUERY} from '../../../../pages/query-tracker/module/query-tracker export function useCurrentQuery() { const query = useSelector(getCurrentQuery); + const defaultQueryACO = useSelector(getDefaultQueryACO); const pollingContext = useContext(QueriesPoolingContext); const dispatch = useDispatch(); @@ -19,10 +21,10 @@ export function useCurrentQuery() { ([item]: QueryItem[]) => { dispatch({ type: UPDATE_QUERY, - data: prepareQueryPlanIds(item), + data: prepareQueryPlanIds(item, defaultQueryACO), }); }, - [dispatch], + [dispatch, defaultQueryACO], ); useEffect( diff --git a/packages/ui/src/ui/pages/query-tracker/module/api.ts b/packages/ui/src/ui/pages/query-tracker/module/api.ts index 5ebcb3efc..1380ee85d 100644 --- a/packages/ui/src/ui/pages/query-tracker/module/api.ts +++ b/packages/ui/src/ui/pages/query-tracker/module/api.ts @@ -10,8 +10,8 @@ import {getClusterConfigByName, getClusterProxy} from '../../../store/selectors/ import {generateQuerySettings, generateQueryText} from '../utils/query_generate'; import {RootState} from '../../../store/reducers'; import {makeDirectDownloadPath} from '../../../utils/navigation'; -import {DEFAULT_QUERY_ACO, getQueryTrackerRequestOptions} from './query/selectors'; import {QueriesHistoryCursorDirection, UPDATE_QUERIES_LIST} from './query-tracker-contants'; +import {getEffectiveApiStage, getQueryTrackerRequestOptions} from './query/selectors'; import {AnyAction} from 'redux'; import {QueryEngine} from './engines'; import {getLastSelectedACONamespaces, selectIsMultipleAco} from './query_aco/selectors'; @@ -212,7 +212,7 @@ export type QueriesListRequestParams = { export async function generateQueryFromTable( engine: QueryEngine, - {cluster, path}: {cluster: string; path: string}, + {cluster, path, defaultQueryACO}: {cluster: string; path: string; defaultQueryACO: string}, ): Promise { const selectedCluster = getClusterConfigByName(cluster); const node = await ytApiV3.get({ @@ -239,8 +239,8 @@ export async function generateQueryFromTable( }), files: [], annotations: {}, - access_control_object: DEFAULT_QUERY_ACO, - access_control_objects: [DEFAULT_QUERY_ACO], + access_control_object: defaultQueryACO, + access_control_objects: [defaultQueryACO], settings: generateQuerySettings(engine, cluster), }; } @@ -571,13 +571,15 @@ export function addACOToLastSelected( ): ThunkAction, RootState, any, AnyAction> { return async (dispatch, getState) => { const state = getState(); - const cluster = state.global.cluster; const lastSelectedACONamespaces = getLastSelectedACONamespaces(state); + const stage = getEffectiveApiStage(state); await dispatch( - setSettingByKey(`local::${cluster}::queryTracker::lastSelectedACOs`, [ + setSettingByKey(`qt-stage::${stage}::queryTracker::lastSelectedACOs`, [ ...aco, - ...lastSelectedACONamespaces.filter((item) => !aco.includes(item)).slice(0, 9), + ...lastSelectedACONamespaces + .filter((item: string) => !aco.includes(item)) + .slice(0, 9), ]), ); }; diff --git a/packages/ui/src/ui/pages/query-tracker/module/query/actions.ts b/packages/ui/src/ui/pages/query-tracker/module/query/actions.ts index d0417fb7e..66b6f239e 100644 --- a/packages/ui/src/ui/pages/query-tracker/module/query/actions.ts +++ b/packages/ui/src/ui/pages/query-tracker/module/query/actions.ts @@ -15,7 +15,6 @@ import { } from '../api'; import {requestQueriesList} from '../queries_list/actions'; import { - DEFAULT_QUERY_ACO, SHARED_QUERY_ACO, getCurrentQuery, getQueryDraft, @@ -37,8 +36,8 @@ import {wrapApiPromiseByToaster} from '../../../../utils/utils'; import {prepareQueryPlanIds} from './utills'; import {chytApiAction, spytApiAction} from '../../../../utils/strawberryControllerApi'; import guid from '../../../../common/hammer/guid'; -import {selectIsMultipleAco} from '../query_aco/selectors'; import {getSettingQueryTrackerStage} from '../../../../store/selectors/settings-ts'; +import {getDefaultQueryACO, selectIsMultipleAco} from '../query_aco/selectors'; import { REQUEST_QUERY, @@ -128,7 +127,8 @@ export function loadQuery( }); query.files = query.files.map((file) => ({...file, id: guid()})); - const queryItem = prepareQueryPlanIds(query); + const defaultQueryACO = getDefaultQueryACO(state); + const queryItem = prepareQueryPlanIds(query, defaultQueryACO); if (config?.dontReplaceQueryText) { queryItem.query = state.queryTracker.query.draft.query; @@ -168,11 +168,13 @@ export function createQueryFromTablePath( | UpdateQueryAction | SetQueryReadyAction > { - return async (dispatch) => { + return async (dispatch, getState) => { dispatch({type: REQUEST_QUERY}); try { + const state = getState(); + const defaultQueryACO = getDefaultQueryACO(state); const draft = await wrapApiPromiseByToaster( - generateQueryFromTable(engine, {cluster, path}), + generateQueryFromTable(engine, {cluster, path, defaultQueryACO}), { toasterName: 'load_query', skipSuccessToast: true, @@ -208,11 +210,16 @@ export function createEmptyQuery( query?: string, settings?: Record, ): ThunkAction { - return (dispatch) => { + return (dispatch, getState) => { + const state = getState(); + const defaultQueryACO = getDefaultQueryACO(state); + dispatch({ type: SET_QUERY, data: { initialQuery: { + access_control_object: defaultQueryACO, + access_control_objects: [defaultQueryACO], query: query || '', engine, settings: settings || {}, @@ -335,11 +342,12 @@ export const toggleShareQuery = const query = selectQuery(state); if (!query) return; - let aco = query.access_control_objects || [DEFAULT_QUERY_ACO]; + const defaultQueryACO = getDefaultQueryACO(state); + let aco = query.access_control_objects || [defaultQueryACO]; if (aco.includes(SHARED_QUERY_ACO)) { aco = aco.filter((i) => i !== SHARED_QUERY_ACO); - if (!aco.length) aco = [DEFAULT_QUERY_ACO]; + if (!aco.length) aco = [defaultQueryACO]; } else { aco = [...aco, SHARED_QUERY_ACO]; } diff --git a/packages/ui/src/ui/pages/query-tracker/module/query/selectors.ts b/packages/ui/src/ui/pages/query-tracker/module/query/selectors.ts index 0b56b6caf..d53cc0960 100644 --- a/packages/ui/src/ui/pages/query-tracker/module/query/selectors.ts +++ b/packages/ui/src/ui/pages/query-tracker/module/query/selectors.ts @@ -11,7 +11,7 @@ import {QTEditorError} from '../types/editor'; import {YTError} from '../../../../types'; import {isYTError} from '../../../../../shared/utils'; import {getQueryResults} from '../query_result/selectors'; -import {selectIsMultipleAco} from '../query_aco/selectors'; +import {getDefaultQueryACO, selectIsMultipleAco} from '../query_aco/selectors'; const QT_STAGE = getQueryTrackerStage(); const getState = (state: RootState) => state.queryTracker.query; @@ -101,18 +101,30 @@ export const getQueryEditorErrors = (state: RootState): QTEditorError[] => { export const getDirtySinceLastSubmit = (state: RootState) => state.queryTracker.query.dirtySinceLastSubmit; -const getAco = (isMultipleAco: boolean, state?: QueryItem | DraftQuery): string[] => { - if (isMultipleAco) return state?.access_control_objects ?? [DEFAULT_QUERY_ACO]; +export const getEffectiveApiStage = (state: RootState) => { + return state.queryTracker?.aco?.data?.query_tracker_stage ?? 'production'; +}; + +const getAco = ( + defaultACO: string, + isMultipleAco: boolean, + state?: QueryItem | DraftQuery, +): string[] => { + if (isMultipleAco) return state?.access_control_objects ?? [defaultACO]; - return state?.access_control_object ? [state?.access_control_object] : [DEFAULT_QUERY_ACO]; + return state?.access_control_object ? [state?.access_control_object] : [defaultACO]; }; export const getCurrentQueryACO = (state: RootState) => { - return getAco(selectIsMultipleAco(state), state.queryTracker.query?.queryItem); + const defaultACO = getDefaultQueryACO(state); + + return getAco(defaultACO, selectIsMultipleAco(state), state.queryTracker.query?.queryItem); }; export const getCurrentDraftQueryACO = (state: RootState) => { - return getAco(selectIsMultipleAco(state), state.queryTracker.query?.draft); + const defaultACO = getDefaultQueryACO(state); + + return getAco(defaultACO, selectIsMultipleAco(state), state.queryTracker.query?.draft); }; export const getProgressYQLStatistics = (state: RootState) => { diff --git a/packages/ui/src/ui/pages/query-tracker/module/query/utills.ts b/packages/ui/src/ui/pages/query-tracker/module/query/utills.ts index cf26d1bdd..78801be80 100644 --- a/packages/ui/src/ui/pages/query-tracker/module/query/utills.ts +++ b/packages/ui/src/ui/pages/query-tracker/module/query/utills.ts @@ -1,6 +1,5 @@ import omit_ from 'lodash/omit'; import {QueryItem} from '../api'; -import {DEFAULT_QUERY_ACO} from './selectors'; export const cleanupQueryForDraft = (query: QueryItem): QueryItem => { return { @@ -9,7 +8,7 @@ export const cleanupQueryForDraft = (query: QueryItem): QueryItem => { }; }; -export const prepareQueryPlanIds = (query: QueryItem): QueryItem => { +export const prepareQueryPlanIds = (query: QueryItem, defaultQueryACO: string): QueryItem => { const nodes = query.progress?.yql_plan?.Basic.nodes; const links = query.progress?.yql_plan?.Basic.links; const operations = query.progress?.yql_plan?.Detailed?.Operations; @@ -34,7 +33,7 @@ export const prepareQueryPlanIds = (query: QueryItem): QueryItem => { } if (!query.access_control_objects) { - query.access_control_objects = [DEFAULT_QUERY_ACO]; + query.access_control_objects = [defaultQueryACO]; } return query; diff --git a/packages/ui/src/ui/pages/query-tracker/module/query_aco/actions.ts b/packages/ui/src/ui/pages/query-tracker/module/query_aco/actions.ts index 34f7ed15f..62fc15d33 100644 --- a/packages/ui/src/ui/pages/query-tracker/module/query_aco/actions.ts +++ b/packages/ui/src/ui/pages/query-tracker/module/query_aco/actions.ts @@ -1,13 +1,23 @@ +import {AnyAction} from 'redux'; import {ThunkAction} from 'redux-thunk'; import {Toaster} from '@gravity-ui/uikit'; import type {AxiosError} from 'axios'; import {YTApiId, ytApiV4Id} from '../../../../rum/rum-wrap-api'; -import {getQueryTrackerRequestOptions} from '../query/selectors'; +import {getEffectiveApiStage, getQueryTrackerRequestOptions} from '../query/selectors'; import {QUERY_ACO_LOADING} from './constants'; import {showErrorPopup} from '../../../../utils/utils'; import {QueryACOActions} from './reducer'; +import {RootState} from '../../../../store/reducers'; +import {setSettingByKey} from '../../../../store/actions/settings'; -export const getQueryACO = (): ThunkAction, any, any, QueryACOActions> => { +type QueryTrackerInfoResponse = Awaited>; + +export const getQueryACO = (): ThunkAction< + Promise, + any, + any, + QueryACOActions +> => { return (dispatch, getState) => { const state = getState(); const {stage} = getQueryTrackerRequestOptions(state); @@ -41,6 +51,8 @@ export const getQueryACO = (): ThunkAction, any, any, QueryACOA type: QUERY_ACO_LOADING.SUCCESS, data: {data}, }); + + return data; }) .catch((error) => { // @todo Remove the condition when the method will be implemented on all clusters @@ -61,3 +73,14 @@ export const getQueryACO = (): ThunkAction, any, any, QueryACOA }); }; }; + +export function setUserDefaultACO( + aco: string, +): ThunkAction, RootState, any, AnyAction> { + return async (dispatch, getState) => { + const state = getState(); + const stage = getEffectiveApiStage(state); + + await dispatch(setSettingByKey(`qt-stage::${stage}::queryTracker::defaultACO`, aco)); + }; +} diff --git a/packages/ui/src/ui/pages/query-tracker/module/query_aco/reducer.ts b/packages/ui/src/ui/pages/query-tracker/module/query_aco/reducer.ts index dedcad787..dd40c902f 100644 --- a/packages/ui/src/ui/pages/query-tracker/module/query_aco/reducer.ts +++ b/packages/ui/src/ui/pages/query-tracker/module/query_aco/reducer.ts @@ -6,6 +6,7 @@ export interface QueryACOState { data: { cluster_name: string; access_control_objects: string[]; + query_tracker_stage: string; supported_features: {access_control: boolean; multiple_aco?: boolean}; }; loading: boolean; @@ -17,6 +18,7 @@ const initialState: QueryACOState = { data: { cluster_name: '', access_control_objects: [], + query_tracker_stage: '', supported_features: { access_control: false, }, diff --git a/packages/ui/src/ui/pages/query-tracker/module/query_aco/selectors.ts b/packages/ui/src/ui/pages/query-tracker/module/query_aco/selectors.ts index 8e72ed8db..c0599fc05 100644 --- a/packages/ui/src/ui/pages/query-tracker/module/query_aco/selectors.ts +++ b/packages/ui/src/ui/pages/query-tracker/module/query_aco/selectors.ts @@ -3,13 +3,14 @@ import {SelectOption} from '@gravity-ui/uikit/build/esm/components/Select/types' import {RootState} from '../../../../store/reducers'; import {getSettingsData} from '../../../../store/selectors/settings-base'; import {createSelector} from 'reselect'; -import {SHARED_QUERY_ACO} from '../query/selectors'; +import {DEFAULT_QUERY_ACO, SHARED_QUERY_ACO, getEffectiveApiStage} from '../query/selectors'; +import {getClusterUiConfig} from '../../../../store/selectors/global'; const selectAcoState = (state: RootState) => state.queryTracker.aco; export const getLastSelectedACONamespaces = (state: RootState) => { - const cluster = state.global.cluster; + const stage = getEffectiveApiStage(state); - return getSettingsData(state)[`local::${cluster}::queryTracker::lastSelectedACOs`] ?? []; + return getSettingsData(state)[`qt-stage::${stage}::queryTracker::lastSelectedACOs`] ?? []; }; export const getQueryACOOptions = (state: RootState): SelectOption[] => { @@ -42,3 +43,20 @@ export const isSupportedShareQuery = createSelector( return isMultipleAco && aco.includes(SHARED_QUERY_ACO); }, ); + +export const getClusterDefaultQueryACO = (state: RootState) => { + const queryTrackerDefaultACO = getClusterUiConfig(state)?.query_tracker_default_aco; + const stage = getEffectiveApiStage(state); + + return (queryTrackerDefaultACO && queryTrackerDefaultACO[stage]) || DEFAULT_QUERY_ACO; +}; + +export const getUserDefaultQueryACO = (state: RootState) => { + const stage = getEffectiveApiStage(state); + + return getSettingsData(state)[`qt-stage::${stage}::queryTracker::defaultACO`]; +}; + +export const getDefaultQueryACO = (state: RootState) => { + return getUserDefaultQueryACO(state) ?? getClusterDefaultQueryACO(state); +};