From bcc7ff0be24111f011b1eff699d90f839d8336c0 Mon Sep 17 00:00:00 2001 From: Valerii Sidorenko Date: Wed, 10 Apr 2024 16:33:09 +0200 Subject: [PATCH 1/2] feat: use rtk query --- .../Errors/ResponseError/ResponseError.tsx | 13 +- .../AppWithClusters/useClusterData.ts | 25 ++- .../Cluster/ClusterInfo/ClusterInfo.tsx | 5 +- src/containers/Clusters/Clusters.scss | 16 +- src/containers/Clusters/Clusters.tsx | 66 ++++---- src/containers/Clusters/useClustersList.ts | 12 -- src/services/api.ts | 6 +- src/store/configureStore.ts | 20 ++- src/store/reducers/api.ts | 28 ++++ src/store/reducers/clusters/clusters.ts | 94 ++++------- src/store/reducers/clusters/selectors.ts | 153 +++++++----------- src/store/reducers/clusters/types.ts | 9 +- src/store/reducers/index.ts | 2 + src/types/redux-location-state.d.ts | 12 +- src/utils/constants.ts | 1 + 15 files changed, 217 insertions(+), 245 deletions(-) delete mode 100644 src/containers/Clusters/useClustersList.ts create mode 100644 src/store/reducers/api.ts diff --git a/src/components/Errors/ResponseError/ResponseError.tsx b/src/components/Errors/ResponseError/ResponseError.tsx index d30cec98ad..ce9be261f9 100644 --- a/src/components/Errors/ResponseError/ResponseError.tsx +++ b/src/components/Errors/ResponseError/ResponseError.tsx @@ -1,8 +1,7 @@ -import type {IResponseError} from '../../../types/api/error'; import i18n from '../i18n'; interface ResponseErrorProps { - error?: IResponseError; + error?: unknown; className?: string; defaultMessage?: string; } @@ -12,5 +11,13 @@ export const ResponseError = ({ className, defaultMessage = i18n('responseError.defaultMessage'), }: ResponseErrorProps) => { - return
{error?.statusText || defaultMessage}
; + let statusText = ''; + if (error && typeof error === 'object') { + if ('statusText' in error && typeof error.statusText === 'string') { + statusText = error.statusText; + } else if ('message' in error && typeof error.message === 'string') { + statusText = error.message; + } + } + return
{statusText || defaultMessage}
; }; diff --git a/src/containers/AppWithClusters/useClusterData.ts b/src/containers/AppWithClusters/useClusterData.ts index e4c80aa09b..a7f994a636 100644 --- a/src/containers/AppWithClusters/useClusterData.ts +++ b/src/containers/AppWithClusters/useClusterData.ts @@ -1,28 +1,25 @@ +import React from 'react'; + import {useLocation} from 'react-router'; import {parseQuery} from '../../routes'; -import {selectClusterInfo} from '../../store/reducers/clusters/selectors'; +import {clustersApi} from '../../store/reducers/clusters/clusters'; import {getAdditionalNodesProps} from '../../utils/additionalProps'; import {USE_CLUSTER_BALANCER_AS_BACKEND_KEY} from '../../utils/constants'; -import {useSetting, useTypedSelector} from '../../utils/hooks'; -import {useClustersList} from '../Clusters/useClustersList'; +import {useSetting} from '../../utils/hooks'; export function useClusterData() { - useClustersList(); const location = useLocation(); + const {clusterName} = parseQuery(location); - const queryParams = parseQuery(location); + const {data} = clustersApi.useGetClustersListQuery(undefined); - const {clusterName} = queryParams; + const info = React.useMemo(() => { + const clusters = data || []; + return clusters.find((cluster) => cluster.name === clusterName); + }, [data, clusterName]); - const { - solomon: monitoring, - balancer, - versions, - cluster, - } = useTypedSelector((state) => - selectClusterInfo(state, typeof clusterName === 'string' ? clusterName : ''), - ); + const {solomon: monitoring, balancer, versions, cluster} = info || {}; const [useClusterBalancerAsBackend] = useSetting(USE_CLUSTER_BALANCER_AS_BACKEND_KEY); diff --git a/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx b/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx index 2d9a7795fe..d4ed347270 100644 --- a/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx +++ b/src/containers/Cluster/ClusterInfo/ClusterInfo.tsx @@ -123,11 +123,12 @@ const getInfo = ( } if (cluster.SystemTablets) { + const tablets = cluster.SystemTablets.slice(0).sort(compareTablets); info.push({ label: i18n('tablets'), value: (
- {cluster.SystemTablets.sort(compareTablets).map((tablet, tabletIndex) => ( + {tablets.map((tablet, tabletIndex) => ( ))}
@@ -226,7 +227,7 @@ export const ClusterInfo = ({ } if (error) { - ; + return ; } return ; diff --git a/src/containers/Clusters/Clusters.scss b/src/containers/Clusters/Clusters.scss index 1188219d11..815d2341a0 100644 --- a/src/containers/Clusters/Clusters.scss +++ b/src/containers/Clusters/Clusters.scss @@ -1,12 +1,12 @@ -@import '../../styles/mixins.scss'; +@use '../../styles/mixins.scss'; .clusters { overflow: auto; padding-top: 15px; - @include body-2-typography(); - @include flex-container(); + @include mixins.body-2-typography(); + @include mixins.flex-container(); &__cluster { display: flex; @@ -128,7 +128,7 @@ &__text { color: var(--g-color-text-primary); - @include body-2-typography(); + @include mixins.body-2-typography(); &::first-letter { color: var(--g-color-text-danger); @@ -145,13 +145,13 @@ overflow: auto; padding-left: 5px; - @include flex-container(); + @include mixins.flex-container(); } &__table-content { overflow: auto; - @include freeze-nth-column(1); + @include mixins.freeze-nth-column(1); } &__balancer-cell { display: flex; @@ -173,4 +173,8 @@ display: flex; align-items: center; } + + &__error { + @include mixins.body-2-typography(); + } } diff --git a/src/containers/Clusters/Clusters.tsx b/src/containers/Clusters/Clusters.tsx index cd9e45376b..6adfc8f860 100644 --- a/src/containers/Clusters/Clusters.tsx +++ b/src/containers/Clusters/Clusters.tsx @@ -4,22 +4,21 @@ import DataTable from '@gravity-ui/react-data-table'; import {Select, TableColumnSetup} from '@gravity-ui/uikit'; import {Helmet} from 'react-helmet-async'; +import {ResponseError} from '../../components/Errors/ResponseError'; import {Loader} from '../../components/Loader'; import {Search} from '../../components/Search'; -import {changeClustersFilters, fetchClustersList} from '../../store/reducers/clusters/clusters'; +import {changeClustersFilters, clustersApi} from '../../store/reducers/clusters/clusters'; import { + aggregateClustersInfo, + filterClusters, selectClusterNameFilter, - selectClustersAggregation, - selectClustersList, - selectFilteredClusters, - selectLoadingFlag, selectServiceFilter, selectStatusFilter, selectVersionFilter, - selectVersions, } from '../../store/reducers/clusters/selectors'; -import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants'; -import {useAutofetcher, useTypedDispatch, useTypedSelector} from '../../utils/hooks'; +import {DEFAULT_POLLING_INTERVAL, DEFAULT_TABLE_SETTINGS} from '../../utils/constants'; +import {useTypedDispatch, useTypedSelector} from '../../utils/hooks'; +import {getMinorVersion} from '../../utils/versions'; import {ClustersStatistics} from './ClustersStatistics'; import {CLUSTERS_COLUMNS} from './columns'; @@ -37,23 +36,16 @@ import {useSelectedColumns} from './useSelectedColumns'; import './Clusters.scss'; export function Clusters() { + const query = clustersApi.useGetClustersListQuery(undefined, { + pollingInterval: DEFAULT_POLLING_INTERVAL, + }); + const dispatch = useTypedDispatch(); - const loading = useTypedSelector(selectLoadingFlag); - const clusters = useTypedSelector(selectClustersList); - const filteredClusters = useTypedSelector(selectFilteredClusters); - const aggregation = useTypedSelector(selectClustersAggregation); const clusterName = useTypedSelector(selectClusterNameFilter); const status = useTypedSelector(selectStatusFilter); const service = useTypedSelector(selectServiceFilter); const version = useTypedSelector(selectVersionFilter); - const versions = useTypedSelector(selectVersions); - - const fetchData = React.useCallback(() => { - dispatch(fetchClustersList()); - }, [dispatch]); - - useAutofetcher(fetchData, [fetchData], true); const changeStatus = (value: string[]) => { dispatch(changeClustersFilters({status: value})); @@ -76,24 +68,41 @@ export function Clusters() { [COLUMNS_NAMES.TITLE], ); - const servicesToSelect = React.useMemo(() => { + const clusters = query.data; + + const {servicesToSelect, versions} = React.useMemo(() => { const clustersServices = new Set(); + const uniqVersions = new Set(); - clusters.forEach((cluster) => { + const clusterList = clusters ?? []; + clusterList.forEach((cluster) => { if (cluster.service) { clustersServices.add(cluster.service); } + cluster.cluster?.Versions?.forEach((v) => { + uniqVersions.add(getMinorVersion(v)); + }); }); - return Array.from(clustersServices).map((clusterService) => { - return { - value: clusterService, - content: clusterService, - }; - }); + return { + servicesToSelect: Array.from(clustersServices).map((value) => ({ + value, + content: value, + })), + versions: Array.from(uniqVersions).map((value) => ({value, content: value})), + }; }, [clusters]); - if (loading && !clusters.length) { + const filteredClusters = React.useMemo(() => { + return filterClusters(clusters ?? [], {clusterName, status, service, version}); + }, [clusterName, clusters, service, status, version]); + + const aggregation = React.useMemo( + () => aggregateClustersInfo(filteredClusters), + [filteredClusters], + ); + + if (query.isLoading) { return ; } @@ -162,6 +171,7 @@ export function Clusters() { /> + {query.isError ? : null}
{ - dispatch(fetchClustersList()); - }, [dispatch]); -} diff --git a/src/services/api.ts b/src/services/api.ts index 90f0e60a35..9a5e6b412d 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -513,8 +513,10 @@ export class YdbEmbeddedAPI extends AxiosWrapper { } // used if not single cluster mode - getClustersList() { - return this.get(`${META_BACKEND || ''}/meta/clusters`, null); + getClustersList(_?: never, {signal}: {signal?: AbortSignal} = {}) { + return this.get(`${META_BACKEND || ''}/meta/clusters`, null, { + requestConfig: {signal}, + }); } } diff --git a/src/store/configureStore.ts b/src/store/configureStore.ts index 56188846a8..1efc00cec0 100644 --- a/src/store/configureStore.ts +++ b/src/store/configureStore.ts @@ -1,5 +1,5 @@ import {configureStore as configureReduxStore} from '@reduxjs/toolkit'; -import type {Action, Reducer, UnknownAction} from '@reduxjs/toolkit'; +import type {Action, Dispatch, Middleware, Reducer, UnknownAction} from '@reduxjs/toolkit'; import type {History} from 'history'; import {createBrowserHistory} from 'history'; import {listenForHistoryChange} from 'redux-location-state'; @@ -8,16 +8,18 @@ import {createApi} from '../services/api'; import {getUrlData} from './getUrlData'; import rootReducer from './reducers'; +import {api as storeApi} from './reducers/api'; import {UPDATE_REF} from './reducers/tooltip'; import getLocationMiddleware from './state-url-mapping'; export let backend: string | undefined, basename: string, clusterName: string | undefined; -function _configureStore( - aRootReducer: Reducer, - history: History, - preloadedState: P, -) { +function _configureStore< + S = any, + A extends Action = UnknownAction, + P = S, + M extends Middleware<{}, S, Dispatch> = any, +>(aRootReducer: Reducer, history: History, preloadedState: P, middleware: M[]) { const {locationMiddleware, reducersWithLocation} = getLocationMiddleware(history, aRootReducer); const store = configureReduxStore({ @@ -30,7 +32,7 @@ function _configureStore( ignoredPaths: ['tooltip.currentHoveredRef'], ignoredActions: [UPDATE_REF], }, - }).concat(locationMiddleware), + }).concat(locationMiddleware, ...middleware), }); return store; @@ -54,7 +56,9 @@ export function configureStore({ })); const history = createBrowserHistory({basename}); - const store = _configureStore(aRootReducer, history, {singleClusterMode}); + const store = _configureStore(aRootReducer, history, {singleClusterMode}, [ + storeApi.middleware, + ]); listenForHistoryChange(store, history); // Interceptor to process OIDC auth diff --git a/src/store/reducers/api.ts b/src/store/reducers/api.ts new file mode 100644 index 0000000000..f335375e8f --- /dev/null +++ b/src/store/reducers/api.ts @@ -0,0 +1,28 @@ +import type {BaseQueryFn} from '@reduxjs/toolkit/query'; +import {createApi} from '@reduxjs/toolkit/query/react'; + +export const api = createApi({ + baseQuery: fakeBaseQuery(), + /** + * This api has endpoints injected in adjacent files, + * which is why no endpoints are shown below. + */ + endpoints: () => ({}), +}); + +export const _NEVER = Symbol(); +type NEVER = typeof _NEVER; + +/** + * Creates a "fake" baseQuery to be used if your api *only* uses the `queryFn` definition syntax. + * This also allows you to specify a specific error type to be shared by all your `queryFn` definitions. + * + * Can't use fakeBaseQuery from @reduxjs/toolkit/query, because of error + */ +function fakeBaseQuery(): BaseQueryFn { + return function () { + throw new Error( + 'When using `fakeBaseQuery`, all queries & mutations must use the `queryFn` definition syntax.', + ); + }; +} diff --git a/src/store/reducers/clusters/clusters.ts b/src/store/reducers/clusters/clusters.ts index 302e92ddc2..109c7e67c0 100644 --- a/src/store/reducers/clusters/clusters.ts +++ b/src/store/reducers/clusters/clusters.ts @@ -1,71 +1,43 @@ -import type {Reducer} from '@reduxjs/toolkit'; +import {createSlice} from '@reduxjs/toolkit'; +import type {PayloadAction} from '@reduxjs/toolkit'; -import {createApiRequest, createRequestActionTypes} from '../../utils'; +import {api} from '../api'; -import type {ClustersAction, ClustersFilters, ClustersState} from './types'; +import type {ClustersFilters} from './types'; import {prepareClustersData} from './utils'; -export const FETCH_CLUSTERS = createRequestActionTypes('clusters', 'FETCH_CLUSTERS'); -const CHANGE_FILTERS = 'clusters/CHANGE_FILTER'; - -const initialState: ClustersState = { - loading: false, - list: [], +const initialState: ClustersFilters = { clusterName: '', status: [], service: [], version: [], }; -const clusters: Reducer = (state = initialState, action) => { - switch (action.type) { - case FETCH_CLUSTERS.REQUEST: { - return { - ...state, - loading: true, - }; - } - case FETCH_CLUSTERS.SUCCESS: { - const {data = []} = action; - - return { - ...state, - loading: false, - list: data, - error: undefined, - }; - } - case FETCH_CLUSTERS.FAILURE: { - return { - ...state, - error: action.error, - loading: false, - }; - } - case CHANGE_FILTERS: { - return { - ...state, - ...action.data, - }; - } - default: - return state; - } -}; - -export function fetchClustersList() { - return createApiRequest({ - request: window.api.getClustersList(), - actions: FETCH_CLUSTERS, - dataHandler: prepareClustersData, - }); -} - -export function changeClustersFilters(filters: Partial) { - return { - type: CHANGE_FILTERS, - data: filters, - } as const; -} - -export default clusters; +const slice = createSlice({ + name: 'clusters', + initialState, + reducers: { + changeClustersFilters: (state, action: PayloadAction>) => ({ + ...state, + ...action.payload, + }), + }, +}); + +export default slice.reducer; +export const {changeClustersFilters} = slice.actions; + +export const clustersApi = api.injectEndpoints({ + endpoints: (builder) => ({ + getClustersList: builder.query({ + queryFn: async (_, {signal}) => { + try { + const data = await window.api.getClustersList(undefined, {signal}); + return {data: prepareClustersData(data)}; + } catch (error) { + return {error}; + } + }, + }), + }), +}); diff --git a/src/store/reducers/clusters/selectors.ts b/src/store/reducers/clusters/selectors.ts index 92b55daf53..d6d42cee77 100644 --- a/src/store/reducers/clusters/selectors.ts +++ b/src/store/reducers/clusters/selectors.ts @@ -1,11 +1,18 @@ -import {createSelector} from '@reduxjs/toolkit'; -import type {Selector} from '@reduxjs/toolkit'; import escapeRegExp from 'lodash/escapeRegExp'; -import type {MetaExtendedClusterInfo} from '../../../types/api/meta'; -import {getMinorVersion} from '../../../utils/versions'; +import type { + ClusterDataAggregation, + ClustersFilters, + ClustersStateSlice, + PreparedCluster, +} from './types'; -import type {ClusterDataAggregation, ClustersStateSlice, PreparedCluster} from './types'; +// ==== Simple selectors ==== + +export const selectClusterNameFilter = (state: ClustersStateSlice) => state.clusters.clusterName; +export const selectStatusFilter = (state: ClustersStateSlice) => state.clusters.status; +export const selectServiceFilter = (state: ClustersStateSlice) => state.clusters.service; +export const selectVersionFilter = (state: ClustersStateSlice) => state.clusters.version; // ==== Filters ==== @@ -66,100 +73,48 @@ const isMatchesByTextQuery = (clusterData: PreparedCluster, searchQuery = '') => return filteredByName || filteredByVersion || filteredByHost; }; -// ==== Simple selectors ==== - -export const selectLoadingFlag = (state: ClustersStateSlice) => state.clusters.loading; -export const selectClustersList = (state: ClustersStateSlice) => state.clusters.list; -export const selectClusterNameFilter = (state: ClustersStateSlice) => state.clusters.clusterName; -export const selectStatusFilter = (state: ClustersStateSlice) => state.clusters.status; -export const selectServiceFilter = (state: ClustersStateSlice) => state.clusters.service; -export const selectVersionFilter = (state: ClustersStateSlice) => state.clusters.version; - -// ==== Complex selectors ==== - -export const selectVersions: Selector = - createSelector(selectClustersList, (clusters) => { - const uniqVersions = new Set(); - - clusters - .map(({cluster}) => cluster?.Versions) - .forEach((clusterVersions) => - clusterVersions?.forEach((version) => { - uniqVersions.add(getMinorVersion(version)); - }), - ); - - return Array.from(uniqVersions).map((version) => ({ - value: version, - content: version, - })); +export function filterClusters(clusters: PreparedCluster[], filters: ClustersFilters) { + return clusters.filter((cluster) => { + return ( + isMatchesByStatus(cluster, filters.status) && + isMatchesByService(cluster, filters.service) && + isMatchesByVersion(cluster, filters.version) && + isMatchesByTextQuery(cluster, filters.clusterName) + ); }); - -export const selectFilteredClusters: Selector = - createSelector( - [ - selectClustersList, - selectClusterNameFilter, - selectStatusFilter, - selectServiceFilter, - selectVersionFilter, - ], - (clusters, textSearchQuery, selectedStatuses, selectedServices, selectedVersions) => { - return clusters.filter((cluster) => { - return ( - isMatchesByStatus(cluster, selectedStatuses) && - isMatchesByService(cluster, selectedServices) && - isMatchesByVersion(cluster, selectedVersions) && - isMatchesByTextQuery(cluster, textSearchQuery) - ); - }); - }, - ); - -export const selectClustersAggregation: Selector = - createSelector(selectFilteredClusters, (clusters) => { - let NodesTotal = 0, - NodesAlive = 0, - LoadAverage = 0, - NumberOfCpus = 0, - StorageUsed = 0, - StorageTotal = 0, - Tenants = 0; - const Hosts = new Set(); - - const filteredClusters = clusters.filter(({cluster}) => !cluster?.error); - - filteredClusters.forEach(({cluster, hosts = {}}) => { - NodesTotal += cluster?.NodesTotal || 0; - NodesAlive += cluster?.NodesAlive || 0; - Object.keys(hosts).forEach((host) => Hosts.add(host)); - Tenants += Number(cluster?.Tenants) || 0; - LoadAverage += Number(cluster?.LoadAverage) || 0; - NumberOfCpus += cluster?.NumberOfCpus || 0; - StorageUsed += cluster?.StorageUsed ? Math.floor(parseInt(cluster.StorageUsed, 10)) : 0; - StorageTotal += cluster?.StorageTotal - ? Math.floor(parseInt(cluster.StorageTotal, 10)) - : 0; - }); - - return { - NodesTotal, - NodesAlive, - Hosts: Hosts.size, - Tenants, - LoadAverage, - NumberOfCpus, - StorageUsed, - StorageTotal, - }; +} + +export function aggregateClustersInfo(clusters: PreparedCluster[]): ClusterDataAggregation { + let NodesTotal = 0, + NodesAlive = 0, + LoadAverage = 0, + NumberOfCpus = 0, + StorageUsed = 0, + StorageTotal = 0, + Tenants = 0; + const Hosts = new Set(); + + const filteredClusters = clusters.filter(({cluster}) => !cluster?.error); + + filteredClusters.forEach(({cluster, hosts = {}}) => { + NodesTotal += cluster?.NodesTotal || 0; + NodesAlive += cluster?.NodesAlive || 0; + Object.keys(hosts).forEach((host) => Hosts.add(host)); + Tenants += Number(cluster?.Tenants) || 0; + LoadAverage += Number(cluster?.LoadAverage) || 0; + NumberOfCpus += cluster?.NumberOfCpus || 0; + StorageUsed += cluster?.StorageUsed ? Math.floor(parseInt(cluster.StorageUsed, 10)) : 0; + StorageTotal += cluster?.StorageTotal ? Math.floor(parseInt(cluster.StorageTotal, 10)) : 0; }); -export const selectClusterInfo = createSelector( - selectClustersList, - (_: unknown, clusterName: string) => clusterName, - (clusters, clusterName) => { - const info: MetaExtendedClusterInfo = - clusters.filter((item) => item.name === clusterName)[0] || {}; - return info; - }, -); + return { + NodesTotal, + NodesAlive, + Hosts: Hosts.size, + Tenants, + LoadAverage, + NumberOfCpus, + StorageUsed, + StorageTotal, + }; +} diff --git a/src/store/reducers/clusters/types.ts b/src/store/reducers/clusters/types.ts index 0f027e8d3e..bb2ca7f2b7 100644 --- a/src/store/reducers/clusters/types.ts +++ b/src/store/reducers/clusters/types.ts @@ -1,8 +1,5 @@ import type {MetaExtendedClusterInfo} from '../../../types/api/meta'; import type {ExtendedMetaClusterVersion} from '../../../utils/clusterVersionColors'; -import type {ApiRequestAction} from '../../utils'; - -import type {FETCH_CLUSTERS, changeClustersFilters} from './clusters'; export interface PreparedCluster extends MetaExtendedClusterInfo { preparedVersions: ExtendedMetaClusterVersion[]; @@ -33,10 +30,6 @@ export interface ClustersState extends ClustersFilters { list: PreparedCluster[]; } -export type ClustersAction = - | ApiRequestAction - | ReturnType; - export interface ClustersStateSlice { - clusters: ClustersState; + clusters: ClustersFilters; } diff --git a/src/store/reducers/index.ts b/src/store/reducers/index.ts index 1b9157396b..cccd7677a7 100644 --- a/src/store/reducers/index.ts +++ b/src/store/reducers/index.ts @@ -1,5 +1,6 @@ import {combineReducers} from '@reduxjs/toolkit'; +import {api} from './api'; import authentication from './authentication/authentication'; import cluster from './cluster/cluster'; import clusterNodes from './clusterNodes/clusterNodes'; @@ -47,6 +48,7 @@ import topic from './topic'; import vDisk from './vdisk/vdisk'; export const rootReducer = { + [api.reducerPath]: api.reducer, singleClusterMode, nodes, topNodesByLoad, diff --git a/src/types/redux-location-state.d.ts b/src/types/redux-location-state.d.ts index 29d6fb4151..84d85e6e26 100644 --- a/src/types/redux-location-state.d.ts +++ b/src/types/redux-location-state.d.ts @@ -1,7 +1,8 @@ /* eslint-disable @typescript-eslint/no-duplicate-imports */ declare module 'redux-location-state' { - import type {Middleware, Reducer, Store} from '@reduxjs/toolkit'; + import type {Dispatch, Middleware, PayloadAction, Reducer, Store} from '@reduxjs/toolkit'; import type {History, Location} from 'history'; + import type {LOCATION_POP, LOCATION_PUSH} from 'redux-location-state/lib/constants'; export function listenForHistoryChange(store: Store, history: History): void; @@ -37,7 +38,14 @@ declare module 'redux-location-state' { location: Location, ) => {location: Location; shouldPush: boolean}, ): { - locationMiddleware: Middleware; + locationMiddleware: Middleware< + {}, + S, + Dispatch< + | PayloadAction + | PayloadAction + > + >; }; } diff --git a/src/utils/constants.ts b/src/utils/constants.ts index 64182967ba..7be1ab6899 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -5,6 +5,7 @@ import {EType} from '../types/api/tablet'; const SECOND = 1000; export const AUTO_RELOAD_INTERVAL = 10 * SECOND; +export const DEFAULT_POLLING_INTERVAL = 30 * SECOND; // by agreement, display all byte values in decimal scale // values in data are always in bytes, never in higher units, // therefore there is no issue arbitrary converting them in UI From ebbcc733e01a058cb4559747c12ff74824ee9d95 Mon Sep 17 00:00:00 2001 From: Valerii Sidorenko Date: Fri, 12 Apr 2024 14:17:30 +0000 Subject: [PATCH 2/2] fix: review --- src/containers/Clusters/Clusters.scss | 1 + src/store/reducers/clusters/types.ts | 7 ------- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/containers/Clusters/Clusters.scss b/src/containers/Clusters/Clusters.scss index 815d2341a0..4fdef07530 100644 --- a/src/containers/Clusters/Clusters.scss +++ b/src/containers/Clusters/Clusters.scss @@ -175,6 +175,7 @@ } &__error { + margin-left: 15px; @include mixins.body-2-typography(); } } diff --git a/src/store/reducers/clusters/types.ts b/src/store/reducers/clusters/types.ts index bb2ca7f2b7..058215aef7 100644 --- a/src/store/reducers/clusters/types.ts +++ b/src/store/reducers/clusters/types.ts @@ -23,13 +23,6 @@ export interface ClustersFilters { clusterName: string; } -export interface ClustersState extends ClustersFilters { - loading: boolean; - error?: unknown; - - list: PreparedCluster[]; -} - export interface ClustersStateSlice { clusters: ClustersFilters; }