From cfc7b28f297f807c33cc4c0445e0801a25430b11 Mon Sep 17 00:00:00 2001 From: Valerii Sidorenko Date: Tue, 23 Apr 2024 16:36:12 +0000 Subject: [PATCH] feat(Tenant): use rtk query --- .../Healthcheck/HealthcheckPreview.tsx | 11 +- .../TenantCpu/TopNodesByCpu.tsx | 36 +--- .../TenantCpu/TopNodesByLoad.tsx | 36 +--- .../TenantOverview/TenantCpu/TopQueries.tsx | 32 +-- .../TenantOverview/TenantCpu/TopShards.tsx | 32 +-- .../TenantMemory/TopNodesByMemory.tsx | 36 +--- .../TenantOverview/TenantOverview.tsx | 42 +--- .../TenantOverviewTableLayout.tsx | 7 +- .../TenantStorage/TopGroups.tsx | 37 +--- .../TenantStorage/TopTables.tsx | 33 +-- .../TenantOverview/useHealthcheck.ts | 2 +- src/services/api.ts | 11 +- src/store/reducers/index.ts | 14 -- src/store/reducers/tenant/tenant.ts | 202 ++++-------------- src/store/reducers/tenant/types.ts | 27 --- .../executeTopTables/executeTopTables.ts | 102 ++------- .../tenantOverview/executeTopTables/types.ts | 15 -- .../tenantOverview/topNodes/topNodes.ts | 29 +++ .../topNodesByCpu/topNodesByCpu.ts | 88 -------- .../tenantOverview/topNodesByCpu/types.ts | 30 --- .../topNodesByLoad/topNodesByLoad.ts | 88 -------- .../tenantOverview/topNodesByLoad/types.ts | 30 --- .../topNodesByMemory/topNodesByMemory.ts | 88 -------- .../tenantOverview/topNodesByMemory/types.ts | 30 --- .../topQueries/tenantOverviewTopQueries.ts | 100 ++------- .../tenantOverview/topQueries/types.ts | 18 -- .../topShards/tenantOverviewTopShards.ts | 103 ++------- .../tenantOverview/topShards/types.ts | 18 -- .../topStorageGroups/topStorageGroups.ts | 119 +++-------- .../tenantOverview/topStorageGroups/types.ts | 25 --- 30 files changed, 256 insertions(+), 1185 deletions(-) delete mode 100644 src/store/reducers/tenantOverview/executeTopTables/types.ts create mode 100644 src/store/reducers/tenantOverview/topNodes/topNodes.ts delete mode 100644 src/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts delete mode 100644 src/store/reducers/tenantOverview/topNodesByCpu/types.ts delete mode 100644 src/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts delete mode 100644 src/store/reducers/tenantOverview/topNodesByLoad/types.ts delete mode 100644 src/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts delete mode 100644 src/store/reducers/tenantOverview/topNodesByMemory/types.ts delete mode 100644 src/store/reducers/tenantOverview/topQueries/types.ts delete mode 100644 src/store/reducers/tenantOverview/topShards/types.ts diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx index 1f117115b9..fb14e5bf0e 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/Healthcheck/HealthcheckPreview.tsx @@ -41,7 +41,16 @@ export function HealthcheckPreview(props: HealthcheckPreviewProps) {
{i18n('title.healthcheck')}
-
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx index 41a17d9d6a..1044edb864 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByCpu.tsx @@ -1,18 +1,8 @@ -import React from 'react'; - import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; -import { - getTopNodesByCpu, - selectTopNodesByCpu, - setDataWasNotLoaded, -} from '../../../../../store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu'; +import {topNodesApi} from '../../../../../store/reducers/tenantOverview/topNodes/topNodes'; import type {AdditionalNodesProps} from '../../../../../types/additionalProps'; -import { - useAutofetcher, - useSearchQuery, - useTypedDispatch, - useTypedSelector, -} from '../../../../../utils/hooks'; +import {DEFAULT_POLLING_INTERVAL} from '../../../../../utils/constants'; +import {useSearchQuery, useTypedSelector} from '../../../../../utils/hooks'; import {getTopNodesByCpuColumns} from '../../../../Nodes/getNodesColumns'; import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; @@ -25,27 +15,18 @@ interface TopNodesByCpuProps { } export function TopNodesByCpu({path, additionalNodesProps}: TopNodesByCpuProps) { - const dispatch = useTypedDispatch(); - const query = useSearchQuery(); - const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByCpu); const {autorefresh} = useTypedSelector((state) => state.schema); - const topNodes = useTypedSelector(selectTopNodesByCpu); const columns = getTopNodesByCpuColumns(additionalNodesProps?.getNodeRef); - const fetchNodes = React.useCallback( - (isBackground: boolean) => { - if (!isBackground) { - dispatch(setDataWasNotLoaded()); - } - - dispatch(getTopNodesByCpu({tenant: path})); - }, - [dispatch, path], + const {currentData, isFetching, error} = topNodesApi.useGetTopNodesQuery( + {tenant: path, sortValue: 'CPU'}, + {pollingInterval: autorefresh ? DEFAULT_POLLING_INTERVAL : 0}, ); - useAutofetcher(fetchNodes, [fetchNodes], autorefresh); + const loading = isFetching && currentData === undefined; + const topNodes = currentData; const title = getSectionTitle({ entity: i18n('nodes'), @@ -62,7 +43,6 @@ export function TopNodesByCpu({path, additionalNodesProps}: TopNodesByCpuProps) columns={columns} title={title} loading={loading} - wasLoaded={wasLoaded} error={error} emptyDataMessage={i18n('top-nodes.empty-data')} /> diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx index 274e5ee4f4..5da25aa5b2 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopNodesByLoad.tsx @@ -1,18 +1,8 @@ -import React from 'react'; - import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; -import { - getTopNodesByLoad, - selectTopNodesByLoad, - setDataWasNotLoaded, -} from '../../../../../store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad'; +import {topNodesApi} from '../../../../../store/reducers/tenantOverview/topNodes/topNodes'; import type {AdditionalNodesProps} from '../../../../../types/additionalProps'; -import { - useAutofetcher, - useSearchQuery, - useTypedDispatch, - useTypedSelector, -} from '../../../../../utils/hooks'; +import {DEFAULT_POLLING_INTERVAL} from '../../../../../utils/constants'; +import {useSearchQuery, useTypedSelector} from '../../../../../utils/hooks'; import {getTopNodesByLoadColumns} from '../../../../Nodes/getNodesColumns'; import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; @@ -25,27 +15,18 @@ interface TopNodesByLoadProps { } export function TopNodesByLoad({path, additionalNodesProps}: TopNodesByLoadProps) { - const dispatch = useTypedDispatch(); - const query = useSearchQuery(); - const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByLoad); const {autorefresh} = useTypedSelector((state) => state.schema); - const topNodes = useTypedSelector(selectTopNodesByLoad); const columns = getTopNodesByLoadColumns(additionalNodesProps?.getNodeRef); - const fetchNodes = React.useCallback( - (isBackground: boolean) => { - if (!isBackground) { - dispatch(setDataWasNotLoaded()); - } - - dispatch(getTopNodesByLoad({tenant: path})); - }, - [dispatch, path], + const {currentData, isFetching, error} = topNodesApi.useGetTopNodesQuery( + {tenant: path, sortValue: 'LoadAverage'}, + {pollingInterval: autorefresh ? DEFAULT_POLLING_INTERVAL : 0}, ); - useAutofetcher(fetchNodes, [fetchNodes], autorefresh); + const loading = isFetching && currentData === undefined; + const topNodes = currentData; const title = getSectionTitle({ entity: i18n('nodes'), @@ -62,7 +43,6 @@ export function TopNodesByLoad({path, additionalNodesProps}: TopNodesByLoadProps columns={columns} title={title} loading={loading} - wasLoaded={wasLoaded} error={error} emptyDataMessage={i18n('top-nodes.empty-data')} /> diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx index 86d7b75f9b..0eeb7e14a2 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopQueries.tsx @@ -10,11 +10,9 @@ import { TENANT_PAGES_IDS, TENANT_QUERY_TABS_ID, } from '../../../../../store/reducers/tenant/constants'; -import { - fetchTenantOverviewTopQueries, - setDataWasNotLoaded, -} from '../../../../../store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries'; -import {useAutofetcher, useTypedDispatch, useTypedSelector} from '../../../../../utils/hooks'; +import {topQueriesApi} from '../../../../../store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries'; +import {DEFAULT_POLLING_INTERVAL} from '../../../../../utils/constants'; +import {useTypedDispatch, useTypedSelector} from '../../../../../utils/hooks'; import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; import {getTenantOverviewTopQueriesColumns} from '../../TopQueries/getTopQueriesColumns'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; @@ -33,27 +31,16 @@ export function TopQueries({path}: TopQueriesProps) { const query = parseQuery(location); const {autorefresh} = useTypedSelector((state) => state.schema); - - const { - loading, - wasLoaded, - error, - data: {result: data = undefined} = {}, - } = useTypedSelector((state) => state.tenantOverviewTopQueries); const columns = getTenantOverviewTopQueriesColumns(); - useAutofetcher( - (isBackground) => { - if (!isBackground) { - dispatch(setDataWasNotLoaded()); - } - - dispatch(fetchTenantOverviewTopQueries(path)); - }, - [dispatch, path], - autorefresh, + const {currentData, isFetching, error} = topQueriesApi.useGetTopQueriesQuery( + {database: path}, + {pollingInterval: autorefresh ? DEFAULT_POLLING_INTERVAL : 0}, ); + const loading = isFetching && currentData === undefined; + const {result: data} = currentData || {}; + const handleRowClick = React.useCallback( (row: any) => { const {QueryText: input} = row; @@ -89,7 +76,6 @@ export function TopQueries({path}: TopQueriesProps) { onRowClick={handleRowClick} title={title} loading={loading} - wasLoaded={wasLoaded} error={error} tableClassNameModifiers={{'top-queries': true}} /> diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx index 5cd9bff72a..8a6548e534 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantCpu/TopShards.tsx @@ -2,11 +2,9 @@ import {useLocation} from 'react-router'; import {parseQuery} from '../../../../../routes'; import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; -import { - sendTenantOverviewTopShardsQuery, - setDataWasNotLoaded, -} from '../../../../../store/reducers/tenantOverview/topShards/tenantOverviewTopShards'; -import {useAutofetcher, useTypedDispatch, useTypedSelector} from '../../../../../utils/hooks'; +import {topShardsApi} from '../../../../../store/reducers/tenantOverview/topShards/tenantOverviewTopShards'; +import {DEFAULT_POLLING_INTERVAL} from '../../../../../utils/constants'; +import {useTypedSelector} from '../../../../../utils/hooks'; import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; import {getTopShardsColumns} from '../../TopShards/getTopShardsColumns'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; @@ -18,31 +16,20 @@ interface TopShardsProps { } export const TopShards = ({path}: TopShardsProps) => { - const dispatch = useTypedDispatch(); const location = useLocation(); const query = parseQuery(location); const {autorefresh, currentSchemaPath} = useTypedSelector((state) => state.schema); - const { - loading, - data: {result: data = undefined} = {}, - error, - wasLoaded, - } = useTypedSelector((state) => state.tenantOverviewTopShards); - - useAutofetcher( - (isBackground) => { - if (!isBackground) { - dispatch(setDataWasNotLoaded()); - } - dispatch(sendTenantOverviewTopShardsQuery(path, currentSchemaPath)); - }, - [dispatch, path, currentSchemaPath], - autorefresh, + const {currentData, isFetching, error} = topShardsApi.useGetTopShardsQuery( + {database: path, path: currentSchemaPath}, + {pollingInterval: autorefresh ? DEFAULT_POLLING_INTERVAL : 0}, ); + const loading = isFetching && currentData === undefined; + const {result: data} = currentData || {}; + const columns = getTopShardsColumns(path, location); const title = getSectionTitle({ @@ -60,7 +47,6 @@ export const TopShards = ({path}: TopShardsProps) => { columns={columns} title={title} loading={loading} - wasLoaded={wasLoaded} error={error} tableClassNameModifiers={{'top-queries': true}} /> diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx index bd47cf5e7b..3e4634855b 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantMemory/TopNodesByMemory.tsx @@ -1,18 +1,8 @@ -import React from 'react'; - import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; -import { - getTopNodesByMemory, - selectTopNodesByMemory, - setDataWasNotLoaded, -} from '../../../../../store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory'; +import {topNodesApi} from '../../../../../store/reducers/tenantOverview/topNodes/topNodes'; import type {AdditionalNodesProps} from '../../../../../types/additionalProps'; -import { - useAutofetcher, - useSearchQuery, - useTypedDispatch, - useTypedSelector, -} from '../../../../../utils/hooks'; +import {DEFAULT_POLLING_INTERVAL} from '../../../../../utils/constants'; +import {useSearchQuery, useTypedSelector} from '../../../../../utils/hooks'; import {getTopNodesByMemoryColumns} from '../../../../Nodes/getNodesColumns'; import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; @@ -25,29 +15,20 @@ interface TopNodesByMemoryProps { } export function TopNodesByMemory({path, additionalNodesProps}: TopNodesByMemoryProps) { - const dispatch = useTypedDispatch(); - const query = useSearchQuery(); - const {wasLoaded, loading, error} = useTypedSelector((state) => state.topNodesByMemory); const {autorefresh} = useTypedSelector((state) => state.schema); - const topNodes = useTypedSelector(selectTopNodesByMemory); const columns = getTopNodesByMemoryColumns({ getNodeRef: additionalNodesProps?.getNodeRef, }); - const fetchNodes = React.useCallback( - (isBackground: boolean) => { - if (!isBackground) { - dispatch(setDataWasNotLoaded()); - } - - dispatch(getTopNodesByMemory({tenant: path})); - }, - [dispatch, path], + const {currentData, isFetching, error} = topNodesApi.useGetTopNodesQuery( + {tenant: path, sortValue: 'Memory'}, + {pollingInterval: autorefresh ? DEFAULT_POLLING_INTERVAL : 0}, ); - useAutofetcher(fetchNodes, [fetchNodes], autorefresh); + const loading = isFetching && currentData === undefined; + const topNodes = currentData; const title = getSectionTitle({ entity: i18n('nodes'), @@ -64,7 +45,6 @@ export function TopNodesByMemory({path, additionalNodesProps}: TopNodesByMemoryP columns={columns} title={title} loading={loading} - wasLoaded={wasLoaded} error={error} emptyDataMessage={i18n('top-nodes.empty-data')} /> diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx index 49215a9fdb..443cc1d11f 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverview.tsx @@ -1,14 +1,12 @@ -import React from 'react'; - import {Loader} from '@gravity-ui/uikit'; import {EntityStatus} from '../../../../components/EntityStatus/EntityStatus'; import {TENANT_METRICS_TABS_IDS} from '../../../../store/reducers/tenant/constants'; -import {getTenantInfo, setDataWasNotLoaded} from '../../../../store/reducers/tenant/tenant'; +import {tenantApi} from '../../../../store/reducers/tenant/tenant'; import {calculateTenantMetrics} from '../../../../store/reducers/tenants/utils'; import type {AdditionalNodesProps, AdditionalTenantsProps} from '../../../../types/additionalProps'; -import {TENANT_DEFAULT_TITLE} from '../../../../utils/constants'; -import {useAutofetcher, useTypedDispatch, useTypedSelector} from '../../../../utils/hooks'; +import {DEFAULT_POLLING_INTERVAL, TENANT_DEFAULT_TITLE} from '../../../../utils/constants'; +import {useTypedSelector} from '../../../../utils/hooks'; import {mapDatabaseTypeToDBName} from '../../utils/schema'; import {DefaultOverviewContent} from './DefaultOverviewContent/DefaultOverviewContent'; @@ -33,14 +31,7 @@ export function TenantOverview({ additionalTenantProps, additionalNodesProps, }: TenantOverviewProps) { - const dispatch = useTypedDispatch(); - - const { - tenant, - loading: tenantLoading, - wasLoaded: tenantWasLoaded, - metricsTab, - } = useTypedSelector((state) => state.tenant); + const {metricsTab} = useTypedSelector((state) => state.tenant); const {autorefresh} = useTypedSelector((state) => state.schema); const { @@ -52,24 +43,13 @@ export function TenantOverview({ refetch: fetchHealthcheck, } = useHealthcheck(tenantName, {autorefresh}); - const fetchTenant = React.useCallback( - (isBackground = true) => { - if (!isBackground) { - dispatch(setDataWasNotLoaded()); - } - dispatch(getTenantInfo({path: tenantName})); - }, - [dispatch, tenantName], - ); - - useAutofetcher( - (isBackground) => { - fetchTenant(isBackground); + const {currentData: tenant, isFetching} = tenantApi.useGetTenantInfoQuery( + {path: tenantName}, + { + pollingInterval: autorefresh ? DEFAULT_POLLING_INTERVAL : 0, }, - [fetchTenant], - autorefresh, ); - + const tenantLoading = isFetching && tenant === undefined; const {Name, Type, Overall} = tenant || {}; const tenantType = mapDatabaseTypeToDBName(Type); @@ -84,7 +64,7 @@ export function TenantOverview({ memoryStats, blobStorageStats, tabletStorageStats, - } = calculateTenantMetrics(tenant); + } = calculateTenantMetrics(tenant ?? undefined); const storageMetrics = { blobStorageUsed: blobStorage, @@ -133,7 +113,7 @@ export function TenantOverview({ } }; - if (tenantLoading && !tenantWasLoaded) { + if (tenantLoading) { return (
diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx index 994789bdc3..03015a8cec 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantOverviewTableLayout.tsx @@ -5,7 +5,6 @@ import type {DataTableProps} from '@gravity-ui/react-data-table'; import {ResponseError} from '../../../../components/Errors/ResponseError'; import {TableSkeleton} from '../../../../components/TableSkeleton/TableSkeleton'; -import type {IResponseError} from '../../../../types/api/error'; import { TENANT_OVERVIEW_TABLES_LIMIT, TENANT_OVERVIEW_TABLES_SETTINGS, @@ -16,8 +15,7 @@ import {b} from './utils'; interface TenantOverviewTableLayoutProps extends Omit, 'theme'> { title: React.ReactNode; loading?: boolean; - wasLoaded?: boolean; - error?: IResponseError; + error?: unknown; tableClassNameModifiers?: { [name: string]: string | boolean | undefined; }; @@ -27,7 +25,6 @@ export function TenantOverviewTableLayout({ title, error, loading, - wasLoaded, tableClassNameModifiers = {}, ...props }: TenantOverviewTableLayoutProps) { @@ -36,7 +33,7 @@ export function TenantOverviewTableLayout({ return ; } - if (loading && !wasLoaded) { + if (loading) { return ; } diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx index 0f89150b2e..7ece61bae6 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopGroups.tsx @@ -1,17 +1,7 @@ -import React from 'react'; - import {TENANT_DIAGNOSTICS_TABS_IDS} from '../../../../../store/reducers/tenant/constants'; -import { - getTopStorageGroups, - selectTopStorageGroups, - setDataWasNotLoaded, -} from '../../../../../store/reducers/tenantOverview/topStorageGroups/topStorageGroups'; -import { - useAutofetcher, - useSearchQuery, - useTypedDispatch, - useTypedSelector, -} from '../../../../../utils/hooks'; +import {topStorageGroupsApi} from '../../../../../store/reducers/tenantOverview/topStorageGroups/topStorageGroups'; +import {DEFAULT_POLLING_INTERVAL} from '../../../../../utils/constants'; +import {useSearchQuery, useTypedSelector} from '../../../../../utils/hooks'; import {getStorageTopGroupsColumns} from '../../../../Storage/StorageGroups/getStorageGroupsColumns'; import {TenantTabsGroups, getTenantPath} from '../../../TenantPages'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; @@ -23,28 +13,18 @@ interface TopGroupsProps { } export function TopGroups({tenant}: TopGroupsProps) { - const dispatch = useTypedDispatch(); - const query = useSearchQuery(); const {autorefresh} = useTypedSelector((state) => state.schema); - const {loading, wasLoaded, error} = useTypedSelector((state) => state.topStorageGroups); - const topGroups = useTypedSelector(selectTopStorageGroups); const columns = getStorageTopGroupsColumns(); - const fetchData = React.useCallback( - (isBackground: boolean) => { - if (!isBackground) { - dispatch(setDataWasNotLoaded()); - } - - dispatch(getTopStorageGroups({tenant})); - }, - [dispatch, tenant], + const {currentData, isFetching, error} = topStorageGroupsApi.useGetTopStorageGroupsQuery( + {tenant}, + {pollingInterval: autorefresh ? DEFAULT_POLLING_INTERVAL : 0}, ); - - useAutofetcher(fetchData, [fetchData], autorefresh); + const loading = isFetching && currentData === undefined; + const topGroups = currentData; const title = getSectionTitle({ entity: i18n('groups'), @@ -61,7 +41,6 @@ export function TopGroups({tenant}: TopGroupsProps) { columns={columns} title={title} loading={loading} - wasLoaded={wasLoaded} error={error} /> ); diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx b/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx index 839fdf4c50..f0123e9040 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx +++ b/src/containers/Tenant/Diagnostics/TenantOverview/TenantStorage/TopTables.tsx @@ -4,13 +4,11 @@ import {useLocation} from 'react-router'; import {CellWithPopover} from '../../../../../components/CellWithPopover/CellWithPopover'; import {LinkToSchemaObject} from '../../../../../components/LinkToSchemaObject/LinkToSchemaObject'; -import { - fetchTopTables, - setDataWasNotLoaded, -} from '../../../../../store/reducers/tenantOverview/executeTopTables/executeTopTables'; +import {topTablesApi} from '../../../../../store/reducers/tenantOverview/executeTopTables/executeTopTables'; import type {KeyValueRow} from '../../../../../types/api/query'; import {formatBytes, getSizeWithSignificantDigits} from '../../../../../utils/bytesParsers'; -import {useAutofetcher, useTypedDispatch, useTypedSelector} from '../../../../../utils/hooks'; +import {DEFAULT_POLLING_INTERVAL} from '../../../../../utils/constants'; +import {useTypedSelector} from '../../../../../utils/hooks'; import {TenantOverviewTableLayout} from '../TenantOverviewTableLayout'; import {getSectionTitle} from '../getSectionTitle'; import i18n from '../i18n'; @@ -22,29 +20,17 @@ interface TopTablesProps { } export function TopTables({path}: TopTablesProps) { - const dispatch = useTypedDispatch(); const location = useLocation(); const {autorefresh} = useTypedSelector((state) => state.schema); - const { - loading, - wasLoaded, - error, - data: {result: data = undefined} = {}, - } = useTypedSelector((state) => state.executeTopTables); - - useAutofetcher( - (isBackground) => { - if (!isBackground) { - dispatch(setDataWasNotLoaded()); - } - - dispatch(fetchTopTables(path)); - }, - [dispatch, path], - autorefresh, + const {currentData, error, isFetching} = topTablesApi.useGetTopTablesQuery( + {path}, + {pollingInterval: autorefresh ? DEFAULT_POLLING_INTERVAL : 0}, ); + const loading = isFetching && currentData === undefined; + + const {result: data} = currentData || {}; const formatSize = (value?: number) => { const size = getSizeWithSignificantDigits(data?.length ? Number(data[0].Size) : 0, 0); @@ -84,7 +70,6 @@ export function TopTables({path}: TopTablesProps) { columns={columns} title={title} loading={loading} - wasLoaded={wasLoaded} error={error} /> ); diff --git a/src/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts b/src/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts index 43331c703e..4c88f16439 100644 --- a/src/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts +++ b/src/containers/Tenant/Diagnostics/TenantOverview/useHealthcheck.ts @@ -1,4 +1,3 @@ -import {DEFAULT_POLLING_INTERVAL} from '../../../../lib'; import { healthcheckApi, selectIssuesStatistics, @@ -7,6 +6,7 @@ import { import type {IssuesTree} from '../../../../store/reducers/healthcheckInfo/types'; import {SelfCheckResult} from '../../../../types/api/healthcheck'; import type {StatusFlag} from '../../../../types/api/healthcheck'; +import {DEFAULT_POLLING_INTERVAL} from '../../../../utils/constants'; import {useTypedSelector} from '../../../../utils/hooks'; interface HealthcheckParams { diff --git a/src/services/api.ts b/src/services/api.ts index 0fd42a3e9f..f5e283bc79 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -83,7 +83,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper { cluster_name: clusterName, }); } - getTenantInfo({path}: {path: string}, {concurrentId}: AxiosOptions = {}) { + getTenantInfo({path}: {path: string}, {concurrentId, signal}: AxiosOptions = {}) { return this.get( this.getPath('/viewer/json/tenantinfo'), { @@ -91,7 +91,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper { tablets: true, storage: true, }, - {concurrentId: concurrentId || `getTenantInfo|${path}`}, + {concurrentId: concurrentId || `getTenantInfo|${path}`, requestConfig: {signal}}, ); } getNodes( @@ -137,7 +137,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper { sortValue, ...params }: StorageApiRequestParams, - {concurrentId}: AxiosOptions = {}, + {concurrentId, signal}: AxiosOptions = {}, ) { const sort = prepareSortValue(sortValue, sortOrder); @@ -152,7 +152,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper { sort, ...params, }, - {concurrentId}, + {concurrentId, requestConfig: {signal}}, ); } getPdiskInfo(nodeId: string | number, pdiskId: string | number) { @@ -316,7 +316,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper { schema?: Schema; syntax?: QuerySyntax; }, - {concurrentId}: AxiosOptions = {}, + {concurrentId, signal}: AxiosOptions = {}, ) { // Time difference to ensure that timeout from ui will be shown rather than backend error const uiTimeout = 9 * 60 * 1000; @@ -342,6 +342,7 @@ export class YdbEmbeddedAPI extends AxiosWrapper { { concurrentId, timeout: uiTimeout, + requestConfig: {signal}, }, ); } diff --git a/src/store/reducers/index.ts b/src/store/reducers/index.ts index 44b235d132..f256d23ed3 100644 --- a/src/store/reducers/index.ts +++ b/src/store/reducers/index.ts @@ -33,13 +33,6 @@ import tablet from './tablet'; import tablets from './tablets'; import tabletsFilters from './tabletsFilters'; import tenant from './tenant/tenant'; -import executeTopTables from './tenantOverview/executeTopTables/executeTopTables'; -import {topNodesByCpu} from './tenantOverview/topNodesByCpu/topNodesByCpu'; -import {topNodesByLoad} from './tenantOverview/topNodesByLoad/topNodesByLoad'; -import {topNodesByMemory} from './tenantOverview/topNodesByMemory/topNodesByMemory'; -import {tenantOverviewTopQueries} from './tenantOverview/topQueries/tenantOverviewTopQueries'; -import {tenantOverviewTopShards} from './tenantOverview/topShards/tenantOverviewTopShards'; -import topStorageGroups from './tenantOverview/topStorageGroups/topStorageGroups'; import tenants from './tenants/tenants'; import tooltip from './tooltip'; import topic from './topic'; @@ -49,13 +42,9 @@ export const rootReducer = { [api.reducerPath]: api.reducer, singleClusterMode, nodes, - topNodesByLoad, - topNodesByCpu, - topNodesByMemory, cluster, tenant, storage, - topStorageGroups, node, tooltip, tablets, @@ -79,10 +68,7 @@ export const rootReducer = { describe, schemaAcl, executeTopQueries, - executeTopTables, - tenantOverviewTopQueries, shardsWorkload, - tenantOverviewTopShards, hotKeys, authentication, header, diff --git a/src/store/reducers/tenant/tenant.ts b/src/store/reducers/tenant/tenant.ts index b10d1ef831..5d465e818d 100644 --- a/src/store/reducers/tenant/tenant.ts +++ b/src/store/reducers/tenant/tenant.ts @@ -1,10 +1,9 @@ -import type {Reducer} from '@reduxjs/toolkit'; +import {createSlice} from '@reduxjs/toolkit'; +import type {PayloadAction} from '@reduxjs/toolkit'; -import type {TTenant} from '../../../types/api/tenant'; -import {createApiRequest, createRequestActionTypes} from '../../utils'; +import {api} from '../api'; import type { - TenantAction, TenantDiagnosticsTab, TenantMetricsTab, TenantPage, @@ -13,159 +12,44 @@ import type { TenantSummaryTab, } from './types'; -export const FETCH_TENANT = createRequestActionTypes('tenant', 'FETCH_TENANT'); - -const SET_TOP_LEVEL_TAB = 'tenant/SET_TOP_LEVEL_TAB'; -const SET_QUERY_TAB = 'tenant/SET_QUERY_TAB'; -const SET_DIAGNOSTICS_TAB = 'tenant/SET_DIAGNOSTICS_TAB'; -const SET_SUMMARY_TAB = 'tenant/SET_SUMMARY_TAB'; -const SET_METRICS_TAB = 'tenant/SET_METRICS_TAB'; -const CLEAR_TENANT = 'tenant/CLEAR_TENANT'; -const SET_DATA_WAS_NOT_LOADED = 'tenant/SET_DATA_WAS_NOT_LOADED'; - -// Tenant diagnostics tab content was requested twice, -// because requests were sent before state was set as loading and after tenant data is fully loaded -// So tenant data is considered loading from the start, there is no attempt to load tab content -// TODO: try fix with 'display: none' for tenant diagnostics tab content while tenant data loading, -// but with parallel (not sequent) data requests -const initialState = {loading: true, wasLoaded: false}; - -const tenantReducer: Reducer = (state = initialState, action) => { - switch (action.type) { - case FETCH_TENANT.REQUEST: { - return { - ...state, - loading: true, - }; - } - - case FETCH_TENANT.SUCCESS: { - return { - ...state, - tenant: action.data, - loading: false, - wasLoaded: true, - error: undefined, - }; - } - - case FETCH_TENANT.FAILURE: { - if (action.error?.isCancelled) { - return state; - } - - return { - ...state, - error: action.error, - loading: false, - wasLoaded: true, - }; - } - - case CLEAR_TENANT: { - return { - ...state, - tenant: undefined, - loading: true, - }; - } - - case SET_TOP_LEVEL_TAB: { - return { - ...state, - tenantPage: action.data, - }; - } - case SET_QUERY_TAB: { - return { - ...state, - queryTab: action.data, - }; - } - case SET_DIAGNOSTICS_TAB: { - return { - ...state, - diagnosticsTab: action.data, - }; - } - case SET_SUMMARY_TAB: { - return { - ...state, - summaryTab: action.data, - }; - } - case SET_METRICS_TAB: { - return { - ...state, - metricsTab: action.data, - }; - } - - case SET_DATA_WAS_NOT_LOADED: { - return { - ...state, - wasLoaded: false, - }; - } - - default: - return state; - } -}; - -export const getTenantInfo = ({path}: {path: string}) => { - return createApiRequest({ - request: window.api.getTenantInfo({path}, {concurrentId: 'getTenantInfo'}), - actions: FETCH_TENANT, - dataHandler: (tenantData): TTenant | undefined => { - return tenantData.TenantInfo?.[0]; +const slice = createSlice({ + name: 'tenant', + initialState: {} as TenantState, + reducers: { + setTenantPage: (state, action: PayloadAction) => { + state.tenantPage = action.payload; }, - }); -}; - -export const clearTenant = () => { - return {type: CLEAR_TENANT} as const; -}; - -export function setTenantPage(page: TenantPage) { - return { - type: SET_TOP_LEVEL_TAB, - data: page, - } as const; -} - -export function setQueryTab(tab: TenantQueryTab) { - return { - type: SET_QUERY_TAB, - data: tab, - } as const; -} - -export function setDiagnosticsTab(tab: TenantDiagnosticsTab) { - return { - type: SET_DIAGNOSTICS_TAB, - data: tab, - } as const; -} - -export function setSummaryTab(tab: TenantSummaryTab) { - return { - type: SET_SUMMARY_TAB, - data: tab, - } as const; -} - -export function setMetricsTab(tab: TenantMetricsTab) { - return { - type: SET_METRICS_TAB, - data: tab, - } as const; -} - -export const setDataWasNotLoaded = () => { - return { - type: SET_DATA_WAS_NOT_LOADED, - } as const; -}; - -export default tenantReducer; + setQueryTab: (state, action: PayloadAction) => { + state.queryTab = action.payload; + }, + setDiagnosticsTab: (state, action: PayloadAction) => { + state.diagnosticsTab = action.payload; + }, + setSummaryTab: (state, action: PayloadAction) => { + state.summaryTab = action.payload; + }, + setMetricsTab: (state, action: PayloadAction) => { + state.metricsTab = action.payload; + }, + }, +}); + +export default slice.reducer; +export const {setTenantPage, setQueryTab, setDiagnosticsTab, setSummaryTab, setMetricsTab} = + slice.actions; + +export const tenantApi = api.injectEndpoints({ + endpoints: (builder) => ({ + getTenantInfo: builder.query({ + queryFn: async ({path}: {path: string}, {signal}) => { + try { + const tenantData = await window.api.getTenantInfo({path}, {signal}); + return {data: tenantData.TenantInfo?.[0] ?? null}; + } catch (error) { + return {error}; + } + }, + providesTags: ['All'], + }), + }), +}); diff --git a/src/store/reducers/tenant/types.ts b/src/store/reducers/tenant/types.ts index 198921dc50..d643990730 100644 --- a/src/store/reducers/tenant/types.ts +++ b/src/store/reducers/tenant/types.ts @@ -1,7 +1,4 @@ -import type {IResponseError} from '../../../types/api/error'; -import type {TTenant} from '../../../types/api/tenant'; import type {ValueOf} from '../../../types/common'; -import type {ApiRequestAction} from '../../utils'; import type { TENANT_DIAGNOSTICS_TABS_IDS, @@ -10,16 +7,6 @@ import type { TENANT_QUERY_TABS_ID, TENANT_SUMMARY_TABS_IDS, } from './constants'; -import type { - FETCH_TENANT, - clearTenant, - setDataWasNotLoaded, - setDiagnosticsTab, - setMetricsTab, - setQueryTab, - setSummaryTab, - setTenantPage, -} from './tenant'; export type TenantPage = ValueOf; @@ -29,23 +16,9 @@ export type TenantSummaryTab = ValueOf; export type TenantMetricsTab = ValueOf; export interface TenantState { - loading: boolean; - wasLoaded: boolean; tenantPage?: TenantPage; queryTab?: TenantQueryTab; diagnosticsTab?: TenantDiagnosticsTab; summaryTab?: TenantSummaryTab; metricsTab?: TenantMetricsTab; - tenant?: TTenant; - error?: IResponseError; } - -export type TenantAction = - | ApiRequestAction - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType - | ReturnType; diff --git a/src/store/reducers/tenantOverview/executeTopTables/executeTopTables.ts b/src/store/reducers/tenantOverview/executeTopTables/executeTopTables.ts index 9f0faa9a0a..8624970bec 100644 --- a/src/store/reducers/tenantOverview/executeTopTables/executeTopTables.ts +++ b/src/store/reducers/tenantOverview/executeTopTables/executeTopTables.ts @@ -1,18 +1,6 @@ -import type {Reducer} from '@reduxjs/toolkit'; - import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants'; import {parseQueryAPIExecuteResponse} from '../../../../utils/query'; -import {createApiRequest, createRequestActionTypes} from '../../../utils'; - -import type {TopTablesAction, TopTablesState} from './types'; - -export const FETCH_TOP_TABLES = createRequestActionTypes('top-tables', 'FETCH_TOP_TABLES'); -const SET_DATA_WAS_NOT_LOADED = 'top-tables/SET_DATA_WAS_NOT_LOADED'; - -const initialState = { - loading: false, - wasLoaded: false, -}; +import {api} from '../../api'; const getQueryText = (path: string) => { return ` @@ -25,70 +13,26 @@ GROUP BY Path `; }; -const executeTopTables: Reducer = ( - state = initialState, - action, -) => { - switch (action.type) { - case FETCH_TOP_TABLES.REQUEST: { - return { - ...state, - loading: true, - error: undefined, - }; - } - case FETCH_TOP_TABLES.SUCCESS: { - return { - ...state, - data: action.data, - loading: false, - error: undefined, - wasLoaded: true, - }; - } - // 401 Unauthorized error is handled by GenericAPI - case FETCH_TOP_TABLES.FAILURE: { - if (action.error?.isCancelled) { - return state; - } - return { - ...state, - error: action.error || 'Unauthorized', - loading: false, - }; - } - case SET_DATA_WAS_NOT_LOADED: - return { - ...state, - wasLoaded: false, - }; - default: - return state; - } -}; - -export const fetchTopTables = (database: string) => { - return createApiRequest({ - request: window.api.sendQuery( - { - schema: 'modern', - query: getQueryText(database), - database, - action: 'execute-scan', - }, - { - concurrentId: 'executeTopTables', +export const topTablesApi = api.injectEndpoints({ + endpoints: (builder) => ({ + getTopTables: builder.query({ + queryFn: async ({path}: {path: string}, {signal}) => { + try { + const data = await window.api.sendQuery( + { + schema: 'modern', + query: getQueryText(path), + database: path, + action: 'execute-scan', + }, + {signal}, + ); + return {data: parseQueryAPIExecuteResponse(data)}; + } catch (error) { + return {error: error || 'Unauthorized'}; + } }, - ), - actions: FETCH_TOP_TABLES, - dataHandler: parseQueryAPIExecuteResponse, - }); -}; - -export function setDataWasNotLoaded() { - return { - type: SET_DATA_WAS_NOT_LOADED, - } as const; -} - -export default executeTopTables; + providesTags: ['All'], + }), + }), +}); diff --git a/src/store/reducers/tenantOverview/executeTopTables/types.ts b/src/store/reducers/tenantOverview/executeTopTables/types.ts deleted file mode 100644 index 5cad8e605c..0000000000 --- a/src/store/reducers/tenantOverview/executeTopTables/types.ts +++ /dev/null @@ -1,15 +0,0 @@ -import type {IQueryResult, QueryErrorResponse} from '../../../../types/store/query'; -import type {ApiRequestAction} from '../../../utils'; - -import type {FETCH_TOP_TABLES, setDataWasNotLoaded} from './executeTopTables'; - -export interface TopTablesState { - loading: boolean; - wasLoaded: boolean; - data?: IQueryResult; - error?: QueryErrorResponse; -} - -export type TopTablesAction = - | ApiRequestAction - | ReturnType; diff --git a/src/store/reducers/tenantOverview/topNodes/topNodes.ts b/src/store/reducers/tenantOverview/topNodes/topNodes.ts new file mode 100644 index 0000000000..036327f6ca --- /dev/null +++ b/src/store/reducers/tenantOverview/topNodes/topNodes.ts @@ -0,0 +1,29 @@ +import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants'; +import {api} from '../../api'; +import type {NodesApiRequestParams} from '../../nodes/types'; +import {prepareNodesData} from '../../nodes/utils'; + +export const topNodesApi = api.injectEndpoints({ + endpoints: (builder) => ({ + getTopNodes: builder.query({ + queryFn: async (params: NodesApiRequestParams, {signal}) => { + try { + const data = await window.api.getNodes( + { + type: 'any', + sortOrder: -1, + // sortValue: 'CPU', + limit: TENANT_OVERVIEW_TABLES_LIMIT, + ...params, + }, + {signal}, + ); + return {data: prepareNodesData(data).Nodes}; + } catch (error) { + return {error}; + } + }, + providesTags: ['All'], + }), + }), +}); diff --git a/src/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts b/src/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts deleted file mode 100644 index fafcfdb20d..0000000000 --- a/src/store/reducers/tenantOverview/topNodesByCpu/topNodesByCpu.ts +++ /dev/null @@ -1,88 +0,0 @@ -import type {Reducer} from '@reduxjs/toolkit'; - -import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants'; -import {createApiRequest, createRequestActionTypes} from '../../../utils'; -import type {NodesApiRequestParams} from '../../nodes/types'; -import {prepareNodesData} from '../../nodes/utils'; - -import type {TopNodesByCpuAction, TopNodesByCpuState, TopPoolsStateSlice} from './types'; - -export const FETCH_TOP_NODES_BY_CPU = createRequestActionTypes( - 'topNodesByCpu', - 'FETCH_TOP_NODES_BY_CPU', -); -const SET_DATA_WAS_NOT_LOADED = 'topNodesByCpu/SET_DATA_WAS_NOT_LOADED'; - -const initialState = { - loading: false, - wasLoaded: false, -}; - -export const topNodesByCpu: Reducer = ( - state = initialState, - action, -) => { - switch (action.type) { - case FETCH_TOP_NODES_BY_CPU.REQUEST: { - return { - ...state, - loading: true, - }; - } - case FETCH_TOP_NODES_BY_CPU.SUCCESS: { - return { - ...state, - data: action.data?.Nodes, - loading: false, - wasLoaded: true, - error: undefined, - }; - } - case FETCH_TOP_NODES_BY_CPU.FAILURE: { - if (action.error?.isCancelled) { - return state; - } - - return { - ...state, - error: action.error, - loading: false, - }; - } - case SET_DATA_WAS_NOT_LOADED: { - return { - ...state, - wasLoaded: false, - }; - } - default: - return state; - } -}; - -const concurrentId = 'getTopNodeByCpu'; - -export function getTopNodesByCpu({ - type = 'any', - sortOrder = -1, - sortValue = 'CPU', - limit = TENANT_OVERVIEW_TABLES_LIMIT, - ...params -}: NodesApiRequestParams) { - return createApiRequest({ - request: window.api.getNodes( - {type, sortOrder, sortValue, limit, ...params}, - {concurrentId}, - ), - actions: FETCH_TOP_NODES_BY_CPU, - dataHandler: prepareNodesData, - }); -} - -export const selectTopNodesByCpu = (state: TopPoolsStateSlice) => state.topNodesByCpu.data; - -export const setDataWasNotLoaded = () => { - return { - type: SET_DATA_WAS_NOT_LOADED, - } as const; -}; diff --git a/src/store/reducers/tenantOverview/topNodesByCpu/types.ts b/src/store/reducers/tenantOverview/topNodesByCpu/types.ts deleted file mode 100644 index 114564e16a..0000000000 --- a/src/store/reducers/tenantOverview/topNodesByCpu/types.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type {IResponseError} from '../../../../types/api/error'; -import type {ApiRequestAction} from '../../../utils'; -import type {NodesPreparedEntity} from '../../nodes/types'; - -import type {FETCH_TOP_NODES_BY_CPU, setDataWasNotLoaded} from './topNodesByCpu'; - -export interface TopNodesByCpuState { - loading: boolean; - wasLoaded: boolean; - data?: NodesPreparedEntity[]; - error?: IResponseError; -} - -export interface TopNodesByCpuHandledResponse { - Nodes?: NodesPreparedEntity[]; -} - -type TopNodesByCpuApiRequestAction = ApiRequestAction< - typeof FETCH_TOP_NODES_BY_CPU, - TopNodesByCpuHandledResponse, - IResponseError ->; - -export type TopNodesByCpuAction = - | TopNodesByCpuApiRequestAction - | ReturnType; - -export interface TopPoolsStateSlice { - topNodesByCpu: TopNodesByCpuState; -} diff --git a/src/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts b/src/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts deleted file mode 100644 index 7a0ad437b5..0000000000 --- a/src/store/reducers/tenantOverview/topNodesByLoad/topNodesByLoad.ts +++ /dev/null @@ -1,88 +0,0 @@ -import type {Reducer} from '@reduxjs/toolkit'; - -import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants'; -import {createApiRequest, createRequestActionTypes} from '../../../utils'; -import type {NodesApiRequestParams} from '../../nodes/types'; -import {prepareNodesData} from '../../nodes/utils'; - -import type {TopNodesByLoadAction, TopNodesByLoadState, TopNodesByLoadStateSlice} from './types'; - -export const FETCH_TOP_NODES_BY_LOAD = createRequestActionTypes( - 'topNodesByLoad', - 'FETCH_TOP_NODES_BY_LOAD', -); -const SET_DATA_WAS_NOT_LOADED = 'topNodesByLoad/SET_DATA_WAS_NOT_LOADED'; - -const initialState = { - loading: false, - wasLoaded: false, -}; - -export const topNodesByLoad: Reducer = ( - state = initialState, - action, -) => { - switch (action.type) { - case FETCH_TOP_NODES_BY_LOAD.REQUEST: { - return { - ...state, - loading: true, - }; - } - case FETCH_TOP_NODES_BY_LOAD.SUCCESS: { - return { - ...state, - data: action.data?.Nodes, - loading: false, - wasLoaded: true, - error: undefined, - }; - } - case FETCH_TOP_NODES_BY_LOAD.FAILURE: { - if (action.error?.isCancelled) { - return state; - } - - return { - ...state, - error: action.error, - loading: false, - }; - } - case SET_DATA_WAS_NOT_LOADED: { - return { - ...state, - wasLoaded: false, - }; - } - default: - return state; - } -}; - -const concurrentId = 'getTopNodesByLoad'; - -export function getTopNodesByLoad({ - type = 'any', - sortOrder = -1, - sortValue = 'LoadAverage', - limit = TENANT_OVERVIEW_TABLES_LIMIT, - ...params -}: NodesApiRequestParams) { - return createApiRequest({ - request: window.api.getNodes( - {type, sortOrder, sortValue, limit, ...params}, - {concurrentId}, - ), - actions: FETCH_TOP_NODES_BY_LOAD, - dataHandler: prepareNodesData, - }); -} - -export const selectTopNodesByLoad = (state: TopNodesByLoadStateSlice) => state.topNodesByLoad.data; - -export const setDataWasNotLoaded = () => { - return { - type: SET_DATA_WAS_NOT_LOADED, - } as const; -}; diff --git a/src/store/reducers/tenantOverview/topNodesByLoad/types.ts b/src/store/reducers/tenantOverview/topNodesByLoad/types.ts deleted file mode 100644 index 4044fceb02..0000000000 --- a/src/store/reducers/tenantOverview/topNodesByLoad/types.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type {IResponseError} from '../../../../types/api/error'; -import type {ApiRequestAction} from '../../../utils'; -import type {NodesPreparedEntity} from '../../nodes/types'; - -import type {FETCH_TOP_NODES_BY_LOAD, setDataWasNotLoaded} from './topNodesByLoad'; - -export interface TopNodesByLoadState { - loading: boolean; - wasLoaded: boolean; - data?: NodesPreparedEntity[]; - error?: IResponseError; -} - -export interface TopNodesByLoadHandledResponse { - Nodes?: NodesPreparedEntity[]; -} - -type TopNodesByLoadApiRequestAction = ApiRequestAction< - typeof FETCH_TOP_NODES_BY_LOAD, - TopNodesByLoadHandledResponse, - IResponseError ->; - -export type TopNodesByLoadAction = - | TopNodesByLoadApiRequestAction - | ReturnType; - -export interface TopNodesByLoadStateSlice { - topNodesByLoad: TopNodesByLoadState; -} diff --git a/src/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts b/src/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts deleted file mode 100644 index 3f97dd3f2e..0000000000 --- a/src/store/reducers/tenantOverview/topNodesByMemory/topNodesByMemory.ts +++ /dev/null @@ -1,88 +0,0 @@ -import type {Reducer} from '@reduxjs/toolkit'; - -import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants'; -import {createApiRequest, createRequestActionTypes} from '../../../utils'; -import type {NodesApiRequestParams} from '../../nodes/types'; -import {prepareNodesData} from '../../nodes/utils'; - -import type {TopNodesByMemoryAction, TopNodesByMemorySlice, TopNodesByMemoryState} from './types'; - -export const FETCH_TOP_NODES_BY_MEMORY = createRequestActionTypes( - 'topNodesByMemory', - 'FETCH_TOP_NODES_BY_MEMORY', -); -const SET_DATA_WAS_NOT_LOADED = 'topNodesByMemory/SET_DATA_WAS_NOT_LOADED'; - -const initialState = { - loading: false, - wasLoaded: false, -}; - -export const topNodesByMemory: Reducer = ( - state = initialState, - action, -) => { - switch (action.type) { - case FETCH_TOP_NODES_BY_MEMORY.REQUEST: { - return { - ...state, - loading: true, - }; - } - case FETCH_TOP_NODES_BY_MEMORY.SUCCESS: { - return { - ...state, - data: action.data?.Nodes, - loading: false, - wasLoaded: true, - error: undefined, - }; - } - case FETCH_TOP_NODES_BY_MEMORY.FAILURE: { - if (action.error?.isCancelled) { - return state; - } - - return { - ...state, - error: action.error, - loading: false, - }; - } - case SET_DATA_WAS_NOT_LOADED: { - return { - ...state, - wasLoaded: false, - }; - } - default: - return state; - } -}; - -const concurrentId = 'getTopNodeByMemory'; - -export function getTopNodesByMemory({ - type = 'any', - sortOrder = -1, - sortValue = 'Memory', - limit = TENANT_OVERVIEW_TABLES_LIMIT, - ...params -}: NodesApiRequestParams) { - return createApiRequest({ - request: window.api.getNodes( - {type, sortOrder, sortValue, limit, ...params}, - {concurrentId}, - ), - actions: FETCH_TOP_NODES_BY_MEMORY, - dataHandler: prepareNodesData, - }); -} - -export const selectTopNodesByMemory = (state: TopNodesByMemorySlice) => state.topNodesByMemory.data; - -export const setDataWasNotLoaded = () => { - return { - type: SET_DATA_WAS_NOT_LOADED, - } as const; -}; diff --git a/src/store/reducers/tenantOverview/topNodesByMemory/types.ts b/src/store/reducers/tenantOverview/topNodesByMemory/types.ts deleted file mode 100644 index c052d212c8..0000000000 --- a/src/store/reducers/tenantOverview/topNodesByMemory/types.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type {IResponseError} from '../../../../types/api/error'; -import type {ApiRequestAction} from '../../../utils'; -import type {NodesPreparedEntity} from '../../nodes/types'; - -import type {FETCH_TOP_NODES_BY_MEMORY, setDataWasNotLoaded} from './topNodesByMemory'; - -export interface TopNodesByMemoryState { - loading: boolean; - wasLoaded: boolean; - data?: NodesPreparedEntity[]; - error?: IResponseError; -} - -export interface TopNodesByMemoryHandledResponse { - Nodes?: NodesPreparedEntity[]; -} - -type TopNodesByMemoryApiRequestAction = ApiRequestAction< - typeof FETCH_TOP_NODES_BY_MEMORY, - TopNodesByMemoryHandledResponse, - IResponseError ->; - -export type TopNodesByMemoryAction = - | TopNodesByMemoryApiRequestAction - | ReturnType; - -export interface TopNodesByMemorySlice { - topNodesByMemory: TopNodesByMemoryState; -} diff --git a/src/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts b/src/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts index 4b9d214f67..faa029d03f 100644 --- a/src/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts +++ b/src/store/reducers/tenantOverview/topQueries/tenantOverviewTopQueries.ts @@ -1,22 +1,6 @@ -import type {Reducer} from '@reduxjs/toolkit'; - import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants'; import {parseQueryAPIExecuteResponse} from '../../../../utils/query'; -import {createApiRequest, createRequestActionTypes} from '../../../utils'; - -import type {TenantOverviewTopQueriesAction, TenantOverviewTopQueriesState} from './types'; - -export const FETCH_TENANT_OVERVIEW_TOP_QUERIES = createRequestActionTypes( - 'tenantOverviewTopQueries', - 'FETCH_TOP_QUERIES', -); -const SET_DATA_WAS_NOT_LOADED = 'tenantOverviewTopQueries/SET_DATA_WAS_NOT_LOADED'; - -const initialState = { - loading: false, - wasLoaded: false, - filters: {}, -}; +import {api} from '../../api'; const getQueryText = (path: string) => { return ` @@ -29,64 +13,26 @@ LIMIT ${TENANT_OVERVIEW_TABLES_LIMIT} `; }; -export const tenantOverviewTopQueries: Reducer< - TenantOverviewTopQueriesState, - TenantOverviewTopQueriesAction -> = (state = initialState, action) => { - switch (action.type) { - case FETCH_TENANT_OVERVIEW_TOP_QUERIES.REQUEST: { - return { - ...state, - loading: true, - error: undefined, - }; - } - case FETCH_TENANT_OVERVIEW_TOP_QUERIES.SUCCESS: { - return { - ...state, - data: action.data, - loading: false, - error: undefined, - wasLoaded: true, - }; - } - // 401 Unauthorized error is handled by GenericAPI - case FETCH_TENANT_OVERVIEW_TOP_QUERIES.FAILURE: { - return { - ...state, - error: action.error || 'Unauthorized', - loading: false, - }; - } - case SET_DATA_WAS_NOT_LOADED: - return { - ...state, - wasLoaded: false, - }; - default: - return state; - } -}; - -export const fetchTenantOverviewTopQueries = (database: string) => - createApiRequest({ - request: window.api.sendQuery( - { - schema: 'modern', - query: getQueryText(database), - database, - action: 'execute-scan', +export const topQueriesApi = api.injectEndpoints({ + endpoints: (builder) => ({ + getTopQueries: builder.query({ + queryFn: async ({database}: {database: string}, {signal}) => { + try { + const data = await window.api.sendQuery( + { + schema: 'modern', + query: getQueryText(database), + database, + action: 'execute-scan', + }, + {signal}, + ); + return {data: parseQueryAPIExecuteResponse(data)}; + } catch (error) { + return {error: error || new Error('Unauthorized')}; + } }, - { - concurrentId: 'executeTopQueries', - }, - ), - actions: FETCH_TENANT_OVERVIEW_TOP_QUERIES, - dataHandler: parseQueryAPIExecuteResponse, - }); - -export function setDataWasNotLoaded() { - return { - type: SET_DATA_WAS_NOT_LOADED, - } as const; -} + providesTags: ['All'], + }), + }), +}); diff --git a/src/store/reducers/tenantOverview/topQueries/types.ts b/src/store/reducers/tenantOverview/topQueries/types.ts deleted file mode 100644 index f774501eda..0000000000 --- a/src/store/reducers/tenantOverview/topQueries/types.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type {IQueryResult, QueryErrorResponse} from '../../../../types/store/query'; -import type {ApiRequestAction} from '../../../utils'; - -import type { - FETCH_TENANT_OVERVIEW_TOP_QUERIES, - setDataWasNotLoaded, -} from './tenantOverviewTopQueries'; - -export interface TenantOverviewTopQueriesState { - loading: boolean; - wasLoaded: boolean; - data?: IQueryResult; - error?: QueryErrorResponse; -} - -export type TenantOverviewTopQueriesAction = - | ApiRequestAction - | ReturnType; diff --git a/src/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts b/src/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts index f2ae796800..78ce8240ea 100644 --- a/src/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts +++ b/src/store/reducers/tenantOverview/topShards/tenantOverviewTopShards.ts @@ -1,21 +1,6 @@ -import type {Reducer} from '@reduxjs/toolkit'; - import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants'; import {parseQueryAPIExecuteResponse} from '../../../../utils/query'; -import {createApiRequest, createRequestActionTypes} from '../../../utils'; - -import type {TenantOverviewTopShardsAction, TenantOverviewTopShardsState} from './types'; - -export const FETCH_TENANT_OVERVIEW_TOP_SHARDS = createRequestActionTypes( - 'tenantOverviewTopShards', - 'FETCH_TENANT_OVERVIEW_TOP_SHARDS', -); -const SET_DATA_WAS_NOT_LOADED = 'tenantOverviewTopShards/SET_DATA_WAS_NOT_LOADED'; - -const initialState = { - loading: false, - wasLoaded: false, -}; +import {api} from '../../api'; function createShardQuery(path: string, tenantName?: string) { const pathSelect = tenantName @@ -36,68 +21,26 @@ LIMIT ${TENANT_OVERVIEW_TABLES_LIMIT}`; const queryAction = 'execute-scan'; -export const tenantOverviewTopShards: Reducer< - TenantOverviewTopShardsState, - TenantOverviewTopShardsAction -> = (state = initialState, action) => { - switch (action.type) { - case FETCH_TENANT_OVERVIEW_TOP_SHARDS.REQUEST: { - return { - ...state, - loading: true, - error: undefined, - }; - } - case FETCH_TENANT_OVERVIEW_TOP_SHARDS.SUCCESS: { - return { - ...state, - data: action.data, - loading: false, - error: undefined, - wasLoaded: true, - }; - } - // 401 Unauthorized error is handled by GenericAPI - case FETCH_TENANT_OVERVIEW_TOP_SHARDS.FAILURE: { - if (action.error?.isCancelled) { - return state; - } - - return { - ...state, - error: action.error || 'Unauthorized', - loading: false, - }; - } - case SET_DATA_WAS_NOT_LOADED: - return { - ...state, - wasLoaded: false, - }; - default: - return state; - } -}; - -export const sendTenantOverviewTopShardsQuery = (database: string, path = '') => - createApiRequest({ - request: window.api.sendQuery( - { - schema: 'modern', - query: createShardQuery(path, database), - database, - action: queryAction, - }, - { - concurrentId: 'executeTopShards', +export const topShardsApi = api.injectEndpoints({ + endpoints: (builder) => ({ + getTopShards: builder.query({ + queryFn: async ({database, path = ''}: {database: string; path?: string}, {signal}) => { + try { + const data = await window.api.sendQuery( + { + schema: 'modern', + query: createShardQuery(path, database), + database, + action: queryAction, + }, + {signal}, + ); + return {data: parseQueryAPIExecuteResponse(data)}; + } catch (error) { + return {error: error || new Error('Unauthorized')}; + } }, - ), - actions: FETCH_TENANT_OVERVIEW_TOP_SHARDS, - dataHandler: parseQueryAPIExecuteResponse, - }); - -export function setDataWasNotLoaded() { - return { - type: SET_DATA_WAS_NOT_LOADED, - } as const; -} + providesTags: ['All'], + }), + }), +}); diff --git a/src/store/reducers/tenantOverview/topShards/types.ts b/src/store/reducers/tenantOverview/topShards/types.ts deleted file mode 100644 index 029c916442..0000000000 --- a/src/store/reducers/tenantOverview/topShards/types.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type {IQueryResult, QueryErrorResponse} from '../../../../types/store/query'; -import type {ApiRequestAction} from '../../../utils'; - -import type { - FETCH_TENANT_OVERVIEW_TOP_SHARDS, - setDataWasNotLoaded, -} from './tenantOverviewTopShards'; - -export interface TenantOverviewTopShardsState { - loading: boolean; - wasLoaded: boolean; - data?: IQueryResult; - error?: QueryErrorResponse; -} - -export type TenantOverviewTopShardsAction = - | ApiRequestAction - | ReturnType; diff --git a/src/store/reducers/tenantOverview/topStorageGroups/topStorageGroups.ts b/src/store/reducers/tenantOverview/topStorageGroups/topStorageGroups.ts index 39baf13d8c..2205cc6ad4 100644 --- a/src/store/reducers/tenantOverview/topStorageGroups/topStorageGroups.ts +++ b/src/store/reducers/tenantOverview/topStorageGroups/topStorageGroups.ts @@ -1,99 +1,32 @@ -import type {Reducer} from '@reduxjs/toolkit'; - import {EVersion} from '../../../../types/api/storage'; import {TENANT_OVERVIEW_TABLES_LIMIT} from '../../../../utils/constants'; -import {createApiRequest, createRequestActionTypes} from '../../../utils'; +import {api} from '../../api'; import type {StorageApiRequestParams} from '../../storage/types'; -import type { - TopStorageGroupsAction, - TopStorageGroupsState, - TopStorageGroupsStateSlice, -} from './types'; import {prepareTopStorageGroupsResponse} from './utils'; -export const FETCH_TOP_STORAGE_GROUPS = createRequestActionTypes( - 'topStorageGroups', - 'FETCH_TOP_STORAGE_GROUPS', -); - -const SET_DATA_WAS_NOT_LOADED = 'topStorageGroups/SET_DATA_WAS_NOT_LOADED'; - -const initialState = { - loading: true, - wasLoaded: false, -}; - -const topStorageGroups: Reducer = ( - state = initialState, - action, -) => { - switch (action.type) { - case FETCH_TOP_STORAGE_GROUPS.REQUEST: { - return { - ...state, - loading: true, - }; - } - case FETCH_TOP_STORAGE_GROUPS.SUCCESS: { - return { - ...state, - data: action.data.groups, - loading: false, - wasLoaded: true, - error: undefined, - }; - } - case FETCH_TOP_STORAGE_GROUPS.FAILURE: { - if (action.error?.isCancelled) { - return state; - } - - return { - ...state, - error: action.error, - loading: false, - wasLoaded: true, - }; - } - case SET_DATA_WAS_NOT_LOADED: { - return { - ...state, - wasLoaded: false, - }; - } - default: - return state; - } -}; - -export const getTopStorageGroups = ({ - tenant, - visibleEntities = 'all', - nodeId, - sortOrder = -1, - sortValue = 'Usage', - limit = TENANT_OVERVIEW_TABLES_LIMIT, - version = EVersion.v2, - ...params -}: StorageApiRequestParams) => { - return createApiRequest({ - request: window.api.getStorageInfo( - {tenant, visibleEntities, nodeId, version, sortOrder, sortValue, limit, ...params}, - {concurrentId: 'getTopStorageGroups'}, - ), - actions: FETCH_TOP_STORAGE_GROUPS, - dataHandler: prepareTopStorageGroupsResponse, - }); -}; - -export const selectTopStorageGroups = (state: TopStorageGroupsStateSlice) => - state.topStorageGroups.data; - -export const setDataWasNotLoaded = () => { - return { - type: SET_DATA_WAS_NOT_LOADED, - } as const; -}; - -export default topStorageGroups; +export const topStorageGroupsApi = api.injectEndpoints({ + endpoints: (builder) => ({ + getTopStorageGroups: builder.query({ + queryFn: async (params: StorageApiRequestParams, {signal}) => { + try { + const data = await window.api.getStorageInfo( + { + visibleEntities: 'all', + sortOrder: -1, + sortValue: 'Usage', + limit: TENANT_OVERVIEW_TABLES_LIMIT, + version: EVersion.v2, + ...params, + }, + {signal}, + ); + return {data: prepareTopStorageGroupsResponse(data).groups || []}; + } catch (error) { + return {error}; + } + }, + providesTags: ['All'], + }), + }), +}); diff --git a/src/store/reducers/tenantOverview/topStorageGroups/types.ts b/src/store/reducers/tenantOverview/topStorageGroups/types.ts index 90cb763d85..69ce6c7f87 100644 --- a/src/store/reducers/tenantOverview/topStorageGroups/types.ts +++ b/src/store/reducers/tenantOverview/topStorageGroups/types.ts @@ -1,30 +1,5 @@ -import type {IResponseError} from '../../../../types/api/error'; -import type {ApiRequestAction} from '../../../utils'; import type {PreparedStorageGroup} from '../../storage/types'; -import type {FETCH_TOP_STORAGE_GROUPS, setDataWasNotLoaded} from './topStorageGroups'; - -export interface TopStorageGroupsState { - loading: boolean; - wasLoaded: boolean; - data?: PreparedStorageGroup[]; - error?: IResponseError; -} - export interface PreparedTopStorageGroupsResponse { groups?: PreparedStorageGroup[]; } - -type GetTopStorageGroupApiRequestAction = ApiRequestAction< - typeof FETCH_TOP_STORAGE_GROUPS, - PreparedTopStorageGroupsResponse, - IResponseError ->; - -export type TopStorageGroupsAction = - | GetTopStorageGroupApiRequestAction - | ReturnType; - -export interface TopStorageGroupsStateSlice { - topStorageGroups: TopStorageGroupsState; -}