From c21802d8daa7d90149826cf57adb0b1c31e9dea7 Mon Sep 17 00:00:00 2001 From: mufazalov Date: Thu, 19 Sep 2024 23:06:09 +0300 Subject: [PATCH 1/8] feat(Storage): add columns setup --- .../PDiskPage/PDiskGroups/PDiskGroups.tsx | 39 ++++--- src/containers/PDiskPage/PDiskPage.scss | 28 ++--- src/containers/PDiskPage/PDiskPage.tsx | 24 +++-- src/containers/Storage/PaginatedStorage.tsx | 40 ++++++- src/containers/Storage/Storage.tsx | 60 ++++++++--- .../StorageControls/StorageControls.tsx | 19 +++- .../StorageGroups/PaginatedStorageGroups.tsx | 7 +- .../Storage/StorageGroups/StorageGroups.tsx | 6 +- .../Storage/StorageGroups/columns/columns.tsx | 58 +--------- .../StorageGroups/columns/constants.ts | 16 +++ .../Storage/StorageGroups/columns/hooks.ts | 55 ++++++---- .../Storage/StorageGroups/columns/types.ts | 12 +-- .../StorageNodes/PaginatedStorageNodes.tsx | 12 +-- .../Storage/StorageNodes/StorageNodes.tsx | 13 +-- .../Storage/StorageNodes/columns/columns.tsx | 6 -- .../Storage/StorageNodes/columns/constants.ts | 11 ++ .../Storage/StorageNodes/columns/hooks.ts | 32 ++++++ .../StorageGroupPage/StorageGroupPage.scss | 24 ++--- .../StorageGroupPage/StorageGroupPage.tsx | 102 ++++++++++++++---- src/containers/UserSettings/i18n/en.json | 3 - src/containers/UserSettings/settings.tsx | 8 +- src/containers/VDiskPage/VDiskPage.scss | 25 ++--- src/containers/VDiskPage/VDiskPage.tsx | 34 ++++-- src/services/settings.ts | 2 - src/utils/constants.ts | 2 - 25 files changed, 393 insertions(+), 245 deletions(-) diff --git a/src/containers/PDiskPage/PDiskGroups/PDiskGroups.tsx b/src/containers/PDiskPage/PDiskGroups/PDiskGroups.tsx index e63eb2ad1..37b72d165 100644 --- a/src/containers/PDiskPage/PDiskGroups/PDiskGroups.tsx +++ b/src/containers/PDiskPage/PDiskGroups/PDiskGroups.tsx @@ -1,7 +1,9 @@ import React from 'react'; +import {TableColumnSetup} from '@gravity-ui/uikit'; + import {ResizeableDataTable} from '../../../components/ResizeableDataTable/ResizeableDataTable'; -import {TableSkeleton} from '../../../components/TableSkeleton/TableSkeleton'; +import {TableWithControlsLayout} from '../../../components/TableWithControlsLayout/TableWithControlsLayout'; import { useCapabilitiesLoaded, useStorageGroupsHandlerAvailable, @@ -10,7 +12,7 @@ import {storageApi} from '../../../store/reducers/storage/storage'; import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants'; import {useAutoRefreshInterval} from '../../../utils/hooks'; import {STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY} from '../../Storage/StorageGroups/columns/constants'; -import {useGetDiskStorageColumns} from '../../Storage/StorageGroups/columns/hooks'; +import {useStorageGroupsSelectedColumns} from '../../Storage/StorageGroups/columns/hooks'; import {preparePDiskStorageResponse} from './utils'; @@ -20,6 +22,8 @@ interface PDiskGroupsProps { } export function PDiskGroups({pDiskId, nodeId}: PDiskGroupsProps) { + const {columnsToShow, columnsToSelect, setColumns} = useStorageGroupsSelectedColumns(); + const capabilitiesLoaded = useCapabilitiesLoaded(); const groupsHandlerAvailable = useStorageGroupsHandlerAvailable(); const [autoRefreshInterval] = useAutoRefreshInterval(); @@ -37,18 +41,25 @@ export function PDiskGroups({pDiskId, nodeId}: PDiskGroupsProps) { return preparePDiskStorageResponse(currentData, pDiskId, nodeId) || []; }, [currentData, pDiskId, nodeId]); - const pDiskStorageColumns = useGetDiskStorageColumns(); - - if (loading || !capabilitiesLoaded) { - return ; - } - return ( - + + + + + + + + ); } diff --git a/src/containers/PDiskPage/PDiskPage.scss b/src/containers/PDiskPage/PDiskPage.scss index 1cc67d8f1..72cf55a0b 100644 --- a/src/containers/PDiskPage/PDiskPage.scss +++ b/src/containers/PDiskPage/PDiskPage.scss @@ -6,29 +6,29 @@ overflow: auto; height: 100%; + padding: 0 20px; - &__info-content { + &__meta, + &__title, + &__info, + &__controls, + &__tabs { position: sticky; left: 0; - display: flex; - flex-direction: column; - gap: 20px; - - padding: 20px; + margin-bottom: 20px; } - &__tabs-content { - padding-left: 20px; + &__meta { + margin-top: 20px; } - &__meta, - &__title, - &__info, - &__controls, &__tabs { - position: sticky; - left: 0; + margin-bottom: 0; + } + + &__disk-distribution { + padding: 20px 0; } &__title { diff --git a/src/containers/PDiskPage/PDiskPage.tsx b/src/containers/PDiskPage/PDiskPage.tsx index 88c302c9e..3796a4a72 100644 --- a/src/containers/PDiskPage/PDiskPage.tsx +++ b/src/containers/PDiskPage/PDiskPage.tsx @@ -231,7 +231,11 @@ export function PDiskPage() { const renderTabsContent = () => { switch (pDiskTab) { case 'diskDistribution': { - return pDiskData ? : null; + return pDiskData ? ( +
+ +
+ ) : null; } case 'groups': { return pDiskParamsDefined ? ( @@ -252,16 +256,14 @@ export function PDiskPage() { return (
-
- {renderHelmet()} - {renderPageMeta()} - {renderPageTitle()} - {renderControls()} - {renderError()} - {renderInfo()} - {renderTabs()} -
-
{renderTabsContent()}
+ {renderHelmet()} + {renderPageMeta()} + {renderPageTitle()} + {renderControls()} + {renderError()} + {renderInfo()} + {renderTabs()} + {renderTabsContent()}
); } diff --git a/src/containers/Storage/PaginatedStorage.tsx b/src/containers/Storage/PaginatedStorage.tsx index 5c5320a56..25fd05a84 100644 --- a/src/containers/Storage/PaginatedStorage.tsx +++ b/src/containers/Storage/PaginatedStorage.tsx @@ -3,7 +3,7 @@ import {StringParam, useQueryParams} from 'use-query-params'; import {AccessDenied} from '../../components/Errors/403/AccessDenied'; import {ResponseError} from '../../components/Errors/ResponseError/ResponseError'; import type {RenderControls, RenderErrorMessage} from '../../components/PaginatedTable'; -import {STORAGE_TYPES, VISIBLE_ENTITIES} from '../../store/reducers/storage/constants'; +import {VISIBLE_ENTITIES} from '../../store/reducers/storage/constants'; import {storageTypeSchema, visibleEntitiesSchema} from '../../store/reducers/storage/types'; import type {StorageType, VisibleEntities} from '../../store/reducers/storage/types'; import type {AdditionalNodesProps} from '../../types/additionalProps'; @@ -11,9 +11,9 @@ import {NodesUptimeFilterValues, nodesUptimeFilterValuesSchema} from '../../util import {StorageControls} from './StorageControls/StorageControls'; import {PaginatedStorageGroups} from './StorageGroups/PaginatedStorageGroups'; +import {useStorageGroupsSelectedColumns} from './StorageGroups/columns/hooks'; import {PaginatedStorageNodes} from './StorageNodes/PaginatedStorageNodes'; - -import './Storage.scss'; +import {useStorageNodesSelectedColumns} from './StorageNodes/columns/hooks'; interface PaginatedStorageProps { database?: string; @@ -35,10 +35,29 @@ export const PaginatedStorage = ({ uptimeFilter: StringParam, }); const storageType = storageTypeSchema.parse(queryParams.type); + const isGroups = storageType === 'groups'; + const isNodes = storageType === 'nodes'; + const visibleEntities = visibleEntitiesSchema.parse(queryParams.visible); const searchValue = queryParams.search ?? ''; const nodesUptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter); + const { + columnsToShow: storageNodesColumnsToShow, + columnsToSelect: storageNodesColumnsToSelect, + setColumns: setStorageNodesSelectedColumns, + } = useStorageNodesSelectedColumns({ + additionalNodesProps, + visibleEntities, + database, + }); + + const { + columnsToShow: storageGroupsColumnsToShow, + columnsToSelect: storageGroupsColumnsToSelect, + setColumns: setStorageGroupsSelectedColumns, + } = useStorageGroupsSelectedColumns(visibleEntities); + const handleTextFilterChange = (value: string) => { setQueryParams({search: value || undefined}, 'replaceIn'); }; @@ -70,6 +89,14 @@ export const PaginatedStorage = ({ }; const renderControls: RenderControls = ({totalEntities, foundEntities, inited}) => { + const columnsToSelect = isGroups + ? storageGroupsColumnsToSelect + : storageNodesColumnsToSelect; + + const handleSelectedColumnsUpdate = isGroups + ? setStorageGroupsSelectedColumns + : setStorageNodesSelectedColumns; + return ( ); }; @@ -97,18 +126,18 @@ export const PaginatedStorage = ({ return ; }; - if (storageType === STORAGE_TYPES.nodes) { + if (isNodes) { return ( ); } @@ -123,6 +152,7 @@ export const PaginatedStorage = ({ parentContainer={parentContainer} renderControls={renderControls} renderErrorMessage={renderErrorMessage} + columns={storageGroupsColumnsToShow} /> ); }; diff --git a/src/containers/Storage/Storage.tsx b/src/containers/Storage/Storage.tsx index ca2819356..8876df328 100644 --- a/src/containers/Storage/Storage.tsx +++ b/src/containers/Storage/Storage.tsx @@ -11,7 +11,7 @@ import { useStorageGroupsHandlerAvailable, } from '../../store/reducers/capabilities/hooks'; import type {NodesSortParams} from '../../store/reducers/nodes/types'; -import {STORAGE_TYPES, VISIBLE_ENTITIES} from '../../store/reducers/storage/constants'; +import {VISIBLE_ENTITIES} from '../../store/reducers/storage/constants'; import { filterGroups, filterNodes, @@ -31,7 +31,9 @@ import {NodesUptimeFilterValues, nodesUptimeFilterValuesSchema} from '../../util import {StorageControls} from './StorageControls/StorageControls'; import {StorageGroups} from './StorageGroups/StorageGroups'; +import {useStorageGroupsSelectedColumns} from './StorageGroups/columns/hooks'; import {StorageNodes} from './StorageNodes/StorageNodes'; +import {useStorageNodesSelectedColumns} from './StorageNodes/columns/hooks'; import {b} from './shared'; import {defaultSortNode, getDefaultSortGroup} from './utils'; @@ -73,6 +75,9 @@ export const Storage = ({additionalNodesProps, database, nodeId}: StorageProps) usageFilter: UsageFilterParam, }); const storageType = storageTypeSchema.parse(queryParams.type); + const isGroups = storageType === 'groups'; + const isNodes = storageType === 'nodes'; + const visibleEntities = visibleEntitiesSchema.parse(queryParams.visible); const filter = queryParams.search ?? ''; const uptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter); @@ -90,23 +95,38 @@ export const Storage = ({additionalNodesProps, database, nodeId}: StorageProps) }); const groupsSortParams = groupSort.sortOrder ? groupSort : getDefaultSortGroup(visibleEntities); + const { + columnsToShow: storageNodesColumnsToShow, + columnsToSelect: storageNodesColumnsToSelect, + setColumns: setStorageNodesSelectedColumns, + } = useStorageNodesSelectedColumns({ + additionalNodesProps, + visibleEntities, + database, + }); + + const { + columnsToShow: storageGroupsColumnsToShow, + columnsToSelect: storageGroupsColumnsToSelect, + setColumns: setStorageGroupsSelectedColumns, + } = useStorageGroupsSelectedColumns(visibleEntities); + const nodesQuery = storageApi.useGetStorageNodesInfoQuery( {database, with: visibleEntities, node_id: nodeId}, { - skip: storageType !== STORAGE_TYPES.nodes, + skip: !isNodes, pollingInterval: autoRefreshInterval, }, ); const groupsQuery = storageApi.useGetStorageGroupsInfoQuery( {database, with: visibleEntities, nodeId, shouldUseGroupsHandler: groupsHandlerAvailable}, { - skip: storageType !== STORAGE_TYPES.groups || !capabilitiesLoaded, + skip: !isGroups || !capabilitiesLoaded, pollingInterval: autoRefreshInterval, }, ); - const {currentData, isFetching, error} = - storageType === STORAGE_TYPES.nodes ? nodesQuery : groupsQuery; + const {currentData, isFetching, error} = isNodes ? nodesQuery : groupsQuery; const {currentData: {nodes = []} = {}} = nodesQuery; const {currentData: {groups = []} = {}} = groupsQuery; @@ -160,7 +180,7 @@ export const Storage = ({additionalNodesProps, database, nodeId}: StorageProps) const renderDataTable = () => { return ( - {storageType === STORAGE_TYPES.groups && ( + {isGroups ? ( handleGroupVisibilityChange(VISIBLE_ENTITIES.all)} sort={groupsSort} handleSort={handleGroupsSort} + columns={storageGroupsColumnsToShow} /> - )} - {storageType === STORAGE_TYPES.nodes && ( + ) : null} + {isNodes ? ( - )} + ) : null} ); }; const renderControls = () => { + const entitiesCountCurrent = isGroups ? storageGroups.length : storageNodes.length; + + const columnsToSelect = isGroups + ? storageGroupsColumnsToSelect + : storageNodesColumnsToSelect; + + const handleSelectedColumnsUpdate = isGroups + ? setStorageGroupsSelectedColumns + : setStorageNodesSelectedColumns; + return ( ); }; diff --git a/src/containers/Storage/StorageControls/StorageControls.tsx b/src/containers/Storage/StorageControls/StorageControls.tsx index 48476bbe2..bb348359d 100644 --- a/src/containers/Storage/StorageControls/StorageControls.tsx +++ b/src/containers/Storage/StorageControls/StorageControls.tsx @@ -1,5 +1,8 @@ import React from 'react'; +import type {TableColumnSetupItem} from '@gravity-ui/uikit'; +import {TableColumnSetup} from '@gravity-ui/uikit'; + import {EntitiesCount} from '../../../components/EntitiesCount/EntitiesCount'; import {Search} from '../../../components/Search/Search'; import {UptimeFilter} from '../../../components/UptimeFIlter'; @@ -35,6 +38,9 @@ interface StorageControlsProps { entitiesCountCurrent: number; entitiesCountTotal?: number; entitiesLoading: boolean; + + columnsToSelect: TableColumnSetupItem[]; + handleSelectedColumnsUpdate: (updated: TableColumnSetupItem[]) => void; } export const StorageControls = ({ @@ -59,8 +65,12 @@ export const StorageControls = ({ entitiesCountCurrent, entitiesCountTotal, entitiesLoading, + + columnsToSelect, + handleSelectedColumnsUpdate, }: StorageControlsProps) => { const isNodes = storageType === STORAGE_TYPES.nodes; + const isGroups = storageType === STORAGE_TYPES.groups; const entityName = isNodes ? i18n('nodes') : i18n('groups'); return ( @@ -86,7 +96,7 @@ export const StorageControls = ({ {isNodes && ( )} - {!isNodes && withGroupsUsageFilter && ( + {isGroups && withGroupsUsageFilter && ( + ); }; diff --git a/src/containers/Storage/StorageGroups/PaginatedStorageGroups.tsx b/src/containers/Storage/StorageGroups/PaginatedStorageGroups.tsx index ee7d3b807..f850411dd 100644 --- a/src/containers/Storage/StorageGroups/PaginatedStorageGroups.tsx +++ b/src/containers/Storage/StorageGroups/PaginatedStorageGroups.tsx @@ -12,11 +12,13 @@ import type {VisibleEntities} from '../../../store/reducers/storage/types'; import {StorageGroupsEmptyDataMessage} from './StorageGroupsEmptyDataMessage'; import {STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY} from './columns/constants'; -import {useGetStorageGroupsColumns} from './columns/hooks'; +import type {StorageGroupsColumn} from './columns/types'; import {useGroupsGetter} from './getGroups'; import i18n from './i18n'; interface PaginatedStorageGroupsProps { + columns: StorageGroupsColumn[]; + searchValue: string; visibleEntities: VisibleEntities; database?: string; @@ -30,6 +32,7 @@ interface PaginatedStorageGroupsProps { } export const PaginatedStorageGroups = ({ + columns, searchValue, visibleEntities, database, @@ -39,8 +42,6 @@ export const PaginatedStorageGroups = ({ renderControls, renderErrorMessage, }: PaginatedStorageGroupsProps) => { - const columns = useGetStorageGroupsColumns(visibleEntities); - const capabilitiesLoaded = useCapabilitiesLoaded(); const groupsHandlerAvailable = useStorageGroupsHandlerAvailable(); diff --git a/src/containers/Storage/StorageGroups/StorageGroups.tsx b/src/containers/Storage/StorageGroups/StorageGroups.tsx index 2872e3e1a..744668720 100644 --- a/src/containers/Storage/StorageGroups/StorageGroups.tsx +++ b/src/containers/Storage/StorageGroups/StorageGroups.tsx @@ -7,11 +7,12 @@ import type {HandleSort} from '../../../utils/hooks/useTableSort'; import {StorageGroupsEmptyDataMessage} from './StorageGroupsEmptyDataMessage'; import {STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY} from './columns/constants'; -import {useGetStorageGroupsColumns} from './columns/hooks'; +import type {StorageGroupsColumn} from './columns/types'; import i18n from './i18n'; interface StorageGroupsProps { data: PreparedStorageGroup[]; + columns: StorageGroupsColumn[]; tableSettings: Settings; visibleEntities: VisibleEntities; onShowAll?: VoidFunction; @@ -21,14 +22,13 @@ interface StorageGroupsProps { export function StorageGroups({ data, + columns, tableSettings, visibleEntities, onShowAll, sort, handleSort, }: StorageGroupsProps) { - const columns = useGetStorageGroupsColumns(visibleEntities); - if (!data.length && visibleEntities !== VISIBLE_ENTITIES.all) { return ( { }); }; -export const getDiskPageStorageColumns: StorageColumnsGetter = (data, options) => { - const disksColumn = options?.useAdvancedStorage - ? getDisksColumn() - : getVDisksColumn(data?.nodes); - - return [ - poolNameColumn, - typeColumn, - erasureColumn, - degradedColumn, - groupIdColumn, - usageColumn, - usedColumn, - disksColumn, - ]; -}; - -const getStorageGroupsColumns: StorageColumnsGetter = (data, options) => { - const disksColumn = options?.useAdvancedStorage - ? getDisksColumn() - : getVDisksColumn(data?.nodes); - - return [ +export const getStorageGroupsColumns: StorageColumnsGetter = (data) => { + const columns = [ poolNameColumn, typeColumn, erasureColumn, @@ -275,36 +252,11 @@ const getStorageGroupsColumns: StorageColumnsGetter = (data, options) => { usedSpaceFlagColumn, readColumn, writeColumn, - disksColumn, + getVDisksColumn(data?.nodes), + getDisksColumn(data?.nodes), ]; -}; - -const filterStorageGroupsColumns = ( - columns: StorageGroupsColumn[], - visibleEntities?: VisibleEntities, -) => { - if (visibleEntities === VISIBLE_ENTITIES.space) { - return columns.filter((col) => col.name !== STORAGE_GROUPS_COLUMNS_IDS.Degraded); - } - - if (visibleEntities === VISIBLE_ENTITIES.missing) { - return columns.filter((col) => col.name !== STORAGE_GROUPS_COLUMNS_IDS.DiskSpace); - } - - return columns.filter((col) => { - return ( - col.name !== STORAGE_GROUPS_COLUMNS_IDS.Degraded && - col.name !== STORAGE_GROUPS_COLUMNS_IDS.DiskSpace - ); - }); -}; - -export const getPreparedStorageGroupsColumns: StorageColumnsGetter = (data, options) => { - const rawColumns = getStorageGroupsColumns(data, options); - - const filteredColumns = filterStorageGroupsColumns(rawColumns, options?.visibleEntities); - return filteredColumns.map((column) => ({ + return columns.map((column) => ({ ...column, sortable: isSortableStorageProperty(column.name), })); diff --git a/src/containers/Storage/StorageGroups/columns/constants.ts b/src/containers/Storage/StorageGroups/columns/constants.ts index 73e38d71c..2be1c916f 100644 --- a/src/containers/Storage/StorageGroups/columns/constants.ts +++ b/src/containers/Storage/StorageGroups/columns/constants.ts @@ -3,6 +3,7 @@ import type {ValueOf} from '../../../../types/common'; import i18n from './i18n'; export const STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY = 'storageGroupsColumnsWidth'; +export const STORAGE_GROUPS_SELECTED_COLUMNS_LS_KEY = 'storageGroupsSelectedColumns'; export const STORAGE_GROUPS_COLUMNS_IDS = { PoolName: 'PoolName', @@ -22,6 +23,21 @@ export const STORAGE_GROUPS_COLUMNS_IDS = { type StorageGroupsColumnId = ValueOf; +export const DEFAULT_STORAGE_GROUPS_COLUMNS: StorageGroupsColumnId[] = [ + 'PoolName', + 'MediaType', + 'Erasure', + 'GroupId', + 'Used', + 'Limit', + 'Usage', + 'Read', + 'Write', + 'VDisks', +]; + +export const REQUIRED_STORAGE_GROUPS_COLUMNS: StorageGroupsColumnId[] = ['GroupId']; + // This code is running when module is initialized and correct language may not be set yet // get functions guarantee that i18n fields will be inited on render with current render language export const STORAGE_GROUPS_COLUMNS_TITLES = { diff --git a/src/containers/Storage/StorageGroups/columns/hooks.ts b/src/containers/Storage/StorageGroups/columns/hooks.ts index 9e56af309..0b3e809df 100644 --- a/src/containers/Storage/StorageGroups/columns/hooks.ts +++ b/src/containers/Storage/StorageGroups/columns/hooks.ts @@ -1,29 +1,48 @@ import React from 'react'; import {selectNodesMap} from '../../../../store/reducers/nodesList'; +import {VISIBLE_ENTITIES} from '../../../../store/reducers/storage/constants'; import type {VisibleEntities} from '../../../../store/reducers/storage/types'; -import {USE_ADVANCED_STORAGE_KEY} from '../../../../utils/constants'; -import {useSetting, useTypedSelector} from '../../../../utils/hooks'; +import {useTypedSelector} from '../../../../utils/hooks'; +import {useSelectedColumns} from '../../../../utils/hooks/useSelectedColumns'; -import {getDiskPageStorageColumns, getPreparedStorageGroupsColumns} from './columns'; -import type {StorageColumnsGetter} from './types'; +import {getStorageGroupsColumns} from './columns'; +import { + DEFAULT_STORAGE_GROUPS_COLUMNS, + REQUIRED_STORAGE_GROUPS_COLUMNS, + STORAGE_GROUPS_COLUMNS_IDS, + STORAGE_GROUPS_COLUMNS_TITLES, + STORAGE_GROUPS_SELECTED_COLUMNS_LS_KEY, +} from './constants'; -const useGetStorageColumns = ( - columnsGetter: StorageColumnsGetter, - visibleEntities?: VisibleEntities, -) => { - const [useAdvancedStorage] = useSetting(USE_ADVANCED_STORAGE_KEY, false); +export function useGetStorageGroupsColumns() { const nodes = useTypedSelector(selectNodesMap); return React.useMemo(() => { - return columnsGetter({nodes}, {useAdvancedStorage, visibleEntities}); - }, [columnsGetter, nodes, useAdvancedStorage, visibleEntities]); -}; + return getStorageGroupsColumns({nodes}); + }, [nodes]); +} -export const useGetStorageGroupsColumns = (visibleEntities?: VisibleEntities) => { - return useGetStorageColumns(getPreparedStorageGroupsColumns, visibleEntities); -}; +export function useStorageGroupsSelectedColumns(visibleEntities?: VisibleEntities) { + const columns = useGetStorageGroupsColumns(); -export const useGetDiskStorageColumns = () => { - return useGetStorageColumns(getDiskPageStorageColumns); -}; + const requiredColumns = React.useMemo(() => { + if (visibleEntities === VISIBLE_ENTITIES.missing) { + return [...REQUIRED_STORAGE_GROUPS_COLUMNS, STORAGE_GROUPS_COLUMNS_IDS.Degraded]; + } + + if (visibleEntities === VISIBLE_ENTITIES.space) { + return [...REQUIRED_STORAGE_GROUPS_COLUMNS, STORAGE_GROUPS_COLUMNS_IDS.DiskSpace]; + } + + return REQUIRED_STORAGE_GROUPS_COLUMNS; + }, [visibleEntities]); + + return useSelectedColumns( + columns, + STORAGE_GROUPS_SELECTED_COLUMNS_LS_KEY, + STORAGE_GROUPS_COLUMNS_TITLES, + DEFAULT_STORAGE_GROUPS_COLUMNS, + requiredColumns, + ); +} diff --git a/src/containers/Storage/StorageGroups/columns/types.ts b/src/containers/Storage/StorageGroups/columns/types.ts index e47bdd26e..88beb92d7 100644 --- a/src/containers/Storage/StorageGroups/columns/types.ts +++ b/src/containers/Storage/StorageGroups/columns/types.ts @@ -1,7 +1,7 @@ import type {Column as DataTableColumn} from '@gravity-ui/react-data-table'; import type {Column as PaginatedTableColumn} from '../../../../components/PaginatedTable'; -import type {PreparedStorageGroup, VisibleEntities} from '../../../../store/reducers/storage/types'; +import type {PreparedStorageGroup} from '../../../../store/reducers/storage/types'; import type {NodesMap} from '../../../../types/store/nodesList'; export type StorageGroupsColumn = PaginatedTableColumn & @@ -11,12 +11,4 @@ interface GetStorageColumnsData { nodes?: NodesMap; } -interface GetStorageColumnsOptions { - useAdvancedStorage?: boolean; - visibleEntities?: VisibleEntities; -} - -export type StorageColumnsGetter = ( - data?: GetStorageColumnsData, - options?: GetStorageColumnsOptions, -) => StorageGroupsColumn[]; +export type StorageColumnsGetter = (data?: GetStorageColumnsData) => StorageGroupsColumn[]; diff --git a/src/containers/Storage/StorageNodes/PaginatedStorageNodes.tsx b/src/containers/Storage/StorageNodes/PaginatedStorageNodes.tsx index 2366e5b04..f29827d41 100644 --- a/src/containers/Storage/StorageNodes/PaginatedStorageNodes.tsx +++ b/src/containers/Storage/StorageNodes/PaginatedStorageNodes.tsx @@ -4,25 +4,23 @@ import type {RenderControls, RenderErrorMessage} from '../../../components/Pagin import {ResizeablePaginatedTable} from '../../../components/PaginatedTable'; import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants'; import type {VisibleEntities} from '../../../store/reducers/storage/types'; -import type {AdditionalNodesProps} from '../../../types/additionalProps'; import {NodesUptimeFilterValues} from '../../../utils/nodes'; import {StorageNodesEmptyDataMessage} from './StorageNodesEmptyDataMessage'; import {STORAGE_NODES_COLUMNS_WIDTH_LS_KEY} from './columns/constants'; -import {useGetStorageNodesColumns} from './columns/hooks'; +import type {StorageNodesColumn} from './columns/types'; import {getStorageNodes} from './getNodes'; import i18n from './i18n'; import {getRowUnavailableClassName} from './shared'; -import './StorageNodes.scss'; - interface PaginatedStorageNodesProps { + columns: StorageNodesColumn[]; + searchValue: string; visibleEntities: VisibleEntities; nodesUptimeFilter: NodesUptimeFilterValues; database?: string; - additionalNodesProps?: AdditionalNodesProps; onShowAll: VoidFunction; parentContainer?: Element | null; @@ -31,11 +29,11 @@ interface PaginatedStorageNodesProps { } export const PaginatedStorageNodes = ({ + columns, searchValue, visibleEntities, nodesUptimeFilter, database, - additionalNodesProps, onShowAll, parentContainer, renderControls, @@ -45,8 +43,6 @@ export const PaginatedStorageNodes = ({ return {searchValue, visibleEntities, nodesUptimeFilter, database}; }, [searchValue, visibleEntities, nodesUptimeFilter, database]); - const columns = useGetStorageNodesColumns({additionalNodesProps, visibleEntities, database}); - const renderEmptyDataMessage = () => { if ( visibleEntities !== VISIBLE_ENTITIES.all || diff --git a/src/containers/Storage/StorageNodes/StorageNodes.tsx b/src/containers/Storage/StorageNodes/StorageNodes.tsx index f81aec165..14e13395f 100644 --- a/src/containers/Storage/StorageNodes/StorageNodes.tsx +++ b/src/containers/Storage/StorageNodes/StorageNodes.tsx @@ -3,43 +3,36 @@ import type {Settings, SortOrder} from '@gravity-ui/react-data-table'; import {ResizeableDataTable} from '../../../components/ResizeableDataTable/ResizeableDataTable'; import {VISIBLE_ENTITIES} from '../../../store/reducers/storage/constants'; import type {PreparedStorageNode, VisibleEntities} from '../../../store/reducers/storage/types'; -import type {AdditionalNodesProps} from '../../../types/additionalProps'; import type {HandleSort} from '../../../utils/hooks/useTableSort'; import {NodesUptimeFilterValues} from '../../../utils/nodes'; import {StorageNodesEmptyDataMessage} from './StorageNodesEmptyDataMessage'; import {STORAGE_NODES_COLUMNS_WIDTH_LS_KEY} from './columns/constants'; -import {useGetStorageNodesColumns} from './columns/hooks'; +import type {StorageNodesColumn} from './columns/types'; import i18n from './i18n'; import {getRowUnavailableClassName} from './shared'; -import './StorageNodes.scss'; - interface StorageNodesProps { data: PreparedStorageNode[]; + columns: StorageNodesColumn[]; tableSettings: Settings; visibleEntities: VisibleEntities; nodesUptimeFilter: NodesUptimeFilterValues; onShowAll?: VoidFunction; - additionalNodesProps?: AdditionalNodesProps; sort?: SortOrder; handleSort?: HandleSort; - database?: string; } export function StorageNodes({ data, + columns, tableSettings, visibleEntities, onShowAll, nodesUptimeFilter, - additionalNodesProps, sort, handleSort, - database, }: StorageNodesProps) { - const columns = useGetStorageNodesColumns({additionalNodesProps, visibleEntities, database}); - if ( !data.length && (visibleEntities !== VISIBLE_ENTITIES.all || diff --git a/src/containers/Storage/StorageNodes/columns/columns.tsx b/src/containers/Storage/StorageNodes/columns/columns.tsx index 50d22e45b..8d998e6c3 100644 --- a/src/containers/Storage/StorageNodes/columns/columns.tsx +++ b/src/containers/Storage/StorageNodes/columns/columns.tsx @@ -1,7 +1,6 @@ import DataTable from '@gravity-ui/react-data-table'; import {NodeHostWrapper} from '../../../../components/NodeHostWrapper/NodeHostWrapper'; -import {VISIBLE_ENTITIES} from '../../../../store/reducers/storage/constants'; import type {AdditionalNodesProps} from '../../../../types/additionalProps'; import {cn} from '../../../../utils/cn'; import {EMPTY_DATA_PLACEHOLDER} from '../../../../utils/constants'; @@ -101,7 +100,6 @@ const getStorageNodesColumns = ( export const getPreparedStorageNodesColumns = ({ additionalNodesProps, - visibleEntities, database, }: GetStorageNodesColumnsParams) => { const rawColumns = getStorageNodesColumns(additionalNodesProps, database); @@ -111,9 +109,5 @@ export const getPreparedStorageNodesColumns = ({ sortable: isSortableNodesProperty(column.name), })); - if (visibleEntities !== VISIBLE_ENTITIES.missing) { - return sortableColumns.filter((col) => col.name !== STORAGE_NODES_COLUMNS_IDS.Missing); - } - return sortableColumns; }; diff --git a/src/containers/Storage/StorageNodes/columns/constants.ts b/src/containers/Storage/StorageNodes/columns/constants.ts index df7fdcdd3..787a62e10 100644 --- a/src/containers/Storage/StorageNodes/columns/constants.ts +++ b/src/containers/Storage/StorageNodes/columns/constants.ts @@ -3,6 +3,7 @@ import type {ValueOf} from '../../../../types/common'; import i18n from './i18n'; export const STORAGE_NODES_COLUMNS_WIDTH_LS_KEY = 'storageNodesColumnsWidth'; +export const STORAGE_NODES_SELECTED_COLUMNS_LS_KEY = 'storageNodesSelectedColumns'; export const STORAGE_NODES_COLUMNS_IDS = { NodeId: 'NodeId', @@ -16,6 +17,16 @@ export const STORAGE_NODES_COLUMNS_IDS = { type StorageNodesColumnId = ValueOf; +export const DEFAULT_STORAGE_NODES_COLUMNS: StorageNodesColumnId[] = [ + 'NodeId', + 'Host', + 'DC', + 'Rack', + 'Uptime', + 'PDisks', +]; +export const REQUIRED_STORAGE_NODES_COLUMNS: StorageNodesColumnId[] = ['NodeId']; + // This code is running when module is initialized and correct language may not be set yet // get functions guarantee that i18n fields will be inited on render with current render language export const STORAGE_NODES_COLUMNS_TITLES = { diff --git a/src/containers/Storage/StorageNodes/columns/hooks.ts b/src/containers/Storage/StorageNodes/columns/hooks.ts index 8c192fb29..0c116e720 100644 --- a/src/containers/Storage/StorageNodes/columns/hooks.ts +++ b/src/containers/Storage/StorageNodes/columns/hooks.ts @@ -1,6 +1,16 @@ import React from 'react'; +import {VISIBLE_ENTITIES} from '../../../../store/reducers/storage/constants'; +import {useSelectedColumns} from '../../../../utils/hooks/useSelectedColumns'; + import {getPreparedStorageNodesColumns} from './columns'; +import { + DEFAULT_STORAGE_NODES_COLUMNS, + REQUIRED_STORAGE_NODES_COLUMNS, + STORAGE_NODES_COLUMNS_IDS, + STORAGE_NODES_COLUMNS_TITLES, + STORAGE_NODES_SELECTED_COLUMNS_LS_KEY, +} from './constants'; import type {GetStorageNodesColumnsParams} from './types'; export const useGetStorageNodesColumns = (params: GetStorageNodesColumnsParams) => { @@ -8,3 +18,25 @@ export const useGetStorageNodesColumns = (params: GetStorageNodesColumnsParams) return getPreparedStorageNodesColumns(params); }, [params]); }; + +export function useStorageNodesSelectedColumns({ + visibleEntities, + ...restParams +}: GetStorageNodesColumnsParams) { + const columns = useGetStorageNodesColumns(restParams); + + const requiredColumns = React.useMemo(() => { + if (visibleEntities === VISIBLE_ENTITIES.missing) { + return [...REQUIRED_STORAGE_NODES_COLUMNS, STORAGE_NODES_COLUMNS_IDS.Missing]; + } + return REQUIRED_STORAGE_NODES_COLUMNS; + }, [visibleEntities]); + + return useSelectedColumns( + columns, + STORAGE_NODES_SELECTED_COLUMNS_LS_KEY, + STORAGE_NODES_COLUMNS_TITLES, + DEFAULT_STORAGE_NODES_COLUMNS, + requiredColumns, + ); +} diff --git a/src/containers/StorageGroupPage/StorageGroupPage.scss b/src/containers/StorageGroupPage/StorageGroupPage.scss index e82656ff4..bf03837bb 100644 --- a/src/containers/StorageGroupPage/StorageGroupPage.scss +++ b/src/containers/StorageGroupPage/StorageGroupPage.scss @@ -6,28 +6,28 @@ overflow: auto; height: 100%; + padding: 0 20px; - &__info-content { + &__meta, + &__title, + &__info, + &__tabs { position: sticky; left: 0; - display: flex; - flex-direction: column; - gap: 20px; + margin-bottom: 20px; + } - padding: 20px; + &__meta { + margin-top: 20px; } - &__tabs-content { - padding-left: 20px; + &__title { + margin-bottom: 60px; } - &__meta, - &__title, - &__info, &__tabs { - position: sticky; - left: 0; + margin-bottom: 0; } &__info { diff --git a/src/containers/StorageGroupPage/StorageGroupPage.tsx b/src/containers/StorageGroupPage/StorageGroupPage.tsx index a49fd1400..c9ddeb911 100644 --- a/src/containers/StorageGroupPage/StorageGroupPage.tsx +++ b/src/containers/StorageGroupPage/StorageGroupPage.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import {Tabs} from '@gravity-ui/uikit'; +import {TableColumnSetup, Tabs} from '@gravity-ui/uikit'; import {skipToken} from '@reduxjs/toolkit/query'; import {Helmet} from 'react-helmet-async'; import {StringParam, useQueryParams} from 'use-query-params'; @@ -12,8 +12,10 @@ import {InfoViewerSkeleton} from '../../components/InfoViewerSkeleton/InfoViewer import {InternalLink} from '../../components/InternalLink'; import {PageMetaWithAutorefresh} from '../../components/PageMeta/PageMeta'; import {StorageGroupInfo} from '../../components/StorageGroupInfo/StorageGroupInfo'; +import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout'; import {getStorageGroupPath} from '../../routes'; import {useStorageGroupsHandlerAvailable} from '../../store/reducers/capabilities/hooks'; +import {useClusterBaseInfo} from '../../store/reducers/cluster/cluster'; import {setHeaderBreadcrumbs} from '../../store/reducers/header/header'; import {STORAGE_TYPES} from '../../store/reducers/storage/constants'; import {storageApi} from '../../store/reducers/storage/storage'; @@ -23,8 +25,11 @@ import {cn} from '../../utils/cn'; import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants'; import {useAutoRefreshInterval, useTypedDispatch} from '../../utils/hooks'; import {NodesUptimeFilterValues} from '../../utils/nodes'; +import {useAdditionalNodeProps} from '../AppWithClusters/useClusterData'; import {StorageGroups} from '../Storage/StorageGroups/StorageGroups'; +import {useStorageGroupsSelectedColumns} from '../Storage/StorageGroups/columns/hooks'; import {StorageNodes} from '../Storage/StorageNodes/StorageNodes'; +import {useStorageNodesSelectedColumns} from '../Storage/StorageNodes/columns/hooks'; import {storageGroupPageKeyset} from './i18n'; @@ -63,6 +68,22 @@ export function StorageGroupPage() { dispatch(setHeaderBreadcrumbs('storageGroup', {groupId})); }, [dispatch, groupId]); + const {balancer} = useClusterBaseInfo(); + const additionalNodesProps = useAdditionalNodeProps({balancer}); + + const { + columnsToShow: storageNodesColumnsToShow, + columnsToSelect: storageNodesColumnsToSelect, + setColumns: setStorageNodesSelectedColumns, + } = useStorageNodesSelectedColumns({ + additionalNodesProps, + }); + const { + columnsToShow: storageGroupsColumnsToShow, + columnsToSelect: storageGroupsColumnsToSelect, + setColumns: setStorageGroupsSelectedColumns, + } = useStorageGroupsSelectedColumns(); + const [autoRefreshInterval] = useAutoRefreshInterval(); const shouldUseGroupsHandler = useStorageGroupsHandlerAvailable(); const groupQuery = storageApi.useGetStorageGroupsInfoQuery( @@ -154,26 +175,69 @@ export function StorageGroupPage() { ); }; - const renderTabsContent = () => { - switch (storageGroupTab) { - case 'groups': { - return storageGroupData ? ( + const renderGroupsTable = () => { + if (!storageGroupData) { + return null; + } + + return ( + + + + + - ) : null; - } - case 'nodes': { - return nodesData ? ( + + + ); + }; + const renderNodesTable = () => { + if (!nodesData) { + return null; + } + + return ( + + + + + - ) : null; + + + ); + }; + + const renderTabsContent = () => { + switch (storageGroupTab) { + case 'groups': { + return renderGroupsTable(); + } + case 'nodes': { + return renderNodesTable(); } default: return null; @@ -189,15 +253,13 @@ export function StorageGroupPage() { return (
-
- {renderHelmet()} - {renderPageMeta()} - {renderPageTitle()} - {renderError()} - {renderInfo()} - {renderTabs()} -
-
{renderTabsContent()}
+ {renderHelmet()} + {renderPageMeta()} + {renderPageTitle()} + {renderError()} + {renderInfo()} + {renderTabs()} + {renderTabsContent()}
); } diff --git a/src/containers/UserSettings/i18n/en.json b/src/containers/UserSettings/i18n/en.json index 4ebd8d4f9..775a1c660 100644 --- a/src/containers/UserSettings/i18n/en.json +++ b/src/containers/UserSettings/i18n/en.json @@ -30,9 +30,6 @@ "settings.invertedDisks.title": "Inverted disks space indicators", - "settings.useAdvancedStorage.title": "Use advanced storage", - "settings.useAdvancedStorage.description": "Display additional data in Storage table", - "settings.usePaginatedTables.title": "Use paginated tables", "settings.usePaginatedTables.description": " Use table with data load on scroll for Nodes and Storage tabs. It will increase performance, but could work unstable", diff --git a/src/containers/UserSettings/settings.tsx b/src/containers/UserSettings/settings.tsx index ce8ed90a8..d110827af 100644 --- a/src/containers/UserSettings/settings.tsx +++ b/src/containers/UserSettings/settings.tsx @@ -11,7 +11,6 @@ import { QUERY_USE_MULTI_SCHEMA_KEY, SHOW_DOMAIN_DATABASE_KEY, THEME_KEY, - USE_ADVANCED_STORAGE_KEY, USE_CLUSTER_BALANCER_AS_BACKEND_KEY, USE_PAGINATED_TABLES_KEY, } from '../../utils/constants'; @@ -90,11 +89,6 @@ export const invertedDisksSetting: SettingProps = { settingKey: INVERTED_DISKS_KEY, title: i18n('settings.invertedDisks.title'), }; -export const useAdvancedStorageSetting: SettingProps = { - settingKey: USE_ADVANCED_STORAGE_KEY, - title: i18n('settings.useAdvancedStorage.title'), - description: i18n('settings.useAdvancedStorage.description'), -}; export const usePaginatedTables: SettingProps = { settingKey: USE_PAGINATED_TABLES_KEY, title: i18n('settings.usePaginatedTables.title'), @@ -149,7 +143,7 @@ export const appearanceSection: SettingsSection = { export const experimentsSection: SettingsSection = { id: 'experimentsSection', title: i18n('section.experiments'), - settings: [useAdvancedStorageSetting, usePaginatedTables, queryUseMultiSchemaSetting], + settings: [usePaginatedTables, queryUseMultiSchemaSetting], }; export const devSettingsSection: SettingsSection = { id: 'devSettingsSection', diff --git a/src/containers/VDiskPage/VDiskPage.scss b/src/containers/VDiskPage/VDiskPage.scss index 376ccdad9..ecaa50a40 100644 --- a/src/containers/VDiskPage/VDiskPage.scss +++ b/src/containers/VDiskPage/VDiskPage.scss @@ -3,13 +3,10 @@ .ydb-vdisk-page { position: relative; - display: flex; overflow: auto; - flex-direction: column; - gap: 20px; height: 100%; - padding: 20px; + padding: 0 20px; &__meta, &__title, @@ -18,6 +15,12 @@ &__group-title { position: sticky; left: 0; + + margin-bottom: 20px; + } + + &__meta { + margin-top: 20px; } &__controls { @@ -27,19 +30,7 @@ } &__group-title { + margin-bottom: 0; @include header-1-typography(); } - - &__group-disks { - display: flex; - flex-grow: 1; - flex-flow: row wrap; - gap: 10px; - - margin-top: 20px; - } - - &__group-disk { - width: 150px; - } } diff --git a/src/containers/VDiskPage/VDiskPage.tsx b/src/containers/VDiskPage/VDiskPage.tsx index 9142c99d8..c070e9786 100644 --- a/src/containers/VDiskPage/VDiskPage.tsx +++ b/src/containers/VDiskPage/VDiskPage.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {ArrowsOppositeToDots} from '@gravity-ui/icons'; -import {Icon} from '@gravity-ui/uikit'; +import {Icon, TableColumnSetup} from '@gravity-ui/uikit'; import {skipToken} from '@reduxjs/toolkit/query'; import {Helmet} from 'react-helmet-async'; import {StringParam, useQueryParams} from 'use-query-params'; @@ -12,6 +12,7 @@ import {ResponseError} from '../../components/Errors/ResponseError'; import {InfoViewerSkeleton} from '../../components/InfoViewerSkeleton/InfoViewerSkeleton'; import {PageMetaWithAutorefresh} from '../../components/PageMeta/PageMeta'; import {ResizeableDataTable} from '../../components/ResizeableDataTable/ResizeableDataTable'; +import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout'; import {VDiskInfo} from '../../components/VDiskInfo/VDiskInfo'; import {api} from '../../store/reducers/api'; import {selectIsUserAllowedToMakeChanges} from '../../store/reducers/authentication/authentication'; @@ -29,7 +30,7 @@ import {stringifyVdiskId} from '../../utils/dataFormatters/dataFormatters'; import {getSeverityColor, getVDiskSlotBasedId} from '../../utils/disks/helpers'; import {useAutoRefreshInterval, useTypedDispatch, useTypedSelector} from '../../utils/hooks'; import {STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY} from '../Storage/StorageGroups/columns/constants'; -import {useGetDiskStorageColumns} from '../Storage/StorageGroups/columns/hooks'; +import {useStorageGroupsSelectedColumns} from '../Storage/StorageGroups/columns/hooks'; import {vDiskPageKeyset} from './i18n'; import {prepareVDiskGroupResponse} from './utils'; @@ -216,6 +217,8 @@ export function VDiskPage() { } export function VDiskGroup({groupId}: {groupId: string | number}) { + const {columnsToShow, columnsToSelect, setColumns} = useStorageGroupsSelectedColumns(); + const capabilitiesLoaded = useCapabilitiesLoaded(); const groupsHandlerAvailable = useStorageGroupsHandlerAvailable(); const [autoRefreshInterval] = useAutoRefreshInterval(); @@ -234,8 +237,6 @@ export function VDiskGroup({groupId}: {groupId: string | number}) { return group ? [group] : undefined; }, [currentData, groupId]); - const vDiskStorageColumns = useGetDiskStorageColumns(); - if (!preparedGroups) { return null; } @@ -243,12 +244,25 @@ export function VDiskGroup({groupId}: {groupId: string | number}) { return (
{vDiskPageKeyset('group')}
- + + + + + + + +
); } diff --git a/src/services/settings.ts b/src/services/settings.ts index 222100415..db276e4fc 100644 --- a/src/services/settings.ts +++ b/src/services/settings.ts @@ -18,7 +18,6 @@ import { SHOW_DOMAIN_DATABASE_KEY, TENANT_INITIAL_PAGE_KEY, THEME_KEY, - USE_ADVANCED_STORAGE_KEY, USE_CLUSTER_BALANCER_AS_BACKEND_KEY, USE_PAGINATED_TABLES_KEY, } from '../utils/constants'; @@ -32,7 +31,6 @@ export const DEFAULT_USER_SETTINGS = { [THEME_KEY]: 'system', [LANGUAGE_KEY]: undefined, [INVERTED_DISKS_KEY]: false, - [USE_ADVANCED_STORAGE_KEY]: false, [QUERY_USE_MULTI_SCHEMA_KEY]: true, [BINARY_DATA_IN_PLAIN_TEXT_DISPLAY]: true, [SAVED_QUERIES_KEY]: [], diff --git a/src/utils/constants.ts b/src/utils/constants.ts index a5dc07c15..6c4df6204 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -149,5 +149,3 @@ export const AUTOCOMPLETE_ON_ENTER = 'autocompleteOnEnter'; export const IS_HOTKEYS_HELP_HIDDEN_KEY = 'isHotKeysHelpHidden'; export const DEV_ENABLE_TRACING_FOR_ALL_REQUESTS = 'enable_tracing_for_all_requests'; - -export const USE_ADVANCED_STORAGE_KEY = 'use_advanced_storage'; From 5d8c4746ac8dde38e5d6fba21de104c78124e764 Mon Sep 17 00:00:00 2001 From: mufazalov Date: Mon, 23 Sep 2024 13:53:08 +0300 Subject: [PATCH 2/8] fix(PaginatedStorage): show nodes on Node page --- src/containers/Storage/PaginatedStorage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/Storage/PaginatedStorage.tsx b/src/containers/Storage/PaginatedStorage.tsx index 25fd05a84..03851da86 100644 --- a/src/containers/Storage/PaginatedStorage.tsx +++ b/src/containers/Storage/PaginatedStorage.tsx @@ -101,7 +101,7 @@ export const PaginatedStorage = ({ Date: Mon, 23 Sep 2024 13:58:55 +0300 Subject: [PATCH 3/8] refactor(Storage): init additional nodes props inside components --- src/containers/Cluster/Cluster.tsx | 5 +---- src/containers/Storage/PaginatedStorage.tsx | 14 ++++++-------- src/containers/Storage/Storage.tsx | 11 +++++++---- src/containers/Storage/StorageWrapper.tsx | 2 -- 4 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/containers/Cluster/Cluster.tsx b/src/containers/Cluster/Cluster.tsx index b77a5cb50..d9f559c4c 100644 --- a/src/containers/Cluster/Cluster.tsx +++ b/src/containers/Cluster/Cluster.tsx @@ -173,10 +173,7 @@ export function Cluster({ getLocationObjectFromHref(getClusterPath(clusterTabsIds.storage)).pathname } > - + { +export const PaginatedStorage = ({database, nodeId, parentContainer}: PaginatedStorageProps) => { + const {balancer} = useClusterBaseInfo(); + const additionalNodesProps = useAdditionalNodeProps({balancer}); + const [queryParams, setQueryParams] = useQueryParams({ type: StringParam, visible: StringParam, diff --git a/src/containers/Storage/Storage.tsx b/src/containers/Storage/Storage.tsx index 8876df328..62962c400 100644 --- a/src/containers/Storage/Storage.tsx +++ b/src/containers/Storage/Storage.tsx @@ -10,6 +10,7 @@ import { useCapabilitiesLoaded, useStorageGroupsHandlerAvailable, } from '../../store/reducers/capabilities/hooks'; +import {useClusterBaseInfo} from '../../store/reducers/cluster/cluster'; import type {NodesSortParams} from '../../store/reducers/nodes/types'; import {VISIBLE_ENTITIES} from '../../store/reducers/storage/constants'; import { @@ -24,10 +25,10 @@ import type { StorageType, VisibleEntities, } from '../../store/reducers/storage/types'; -import type {AdditionalNodesProps} from '../../types/additionalProps'; import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants'; import {useAutoRefreshInterval, useTableSort} from '../../utils/hooks'; import {NodesUptimeFilterValues, nodesUptimeFilterValuesSchema} from '../../utils/nodes'; +import {useAdditionalNodeProps} from '../AppWithClusters/useClusterData'; import {StorageControls} from './StorageControls/StorageControls'; import {StorageGroups} from './StorageGroups/StorageGroups'; @@ -57,12 +58,14 @@ const UsageFilterParam = withDefault( ); interface StorageProps { - additionalNodesProps?: AdditionalNodesProps; database?: string; - nodeId?: string; + nodeId?: string | number; } -export const Storage = ({additionalNodesProps, database, nodeId}: StorageProps) => { +export const Storage = ({database, nodeId}: StorageProps) => { + const {balancer} = useClusterBaseInfo(); + const additionalNodesProps = useAdditionalNodeProps({balancer}); + const capabilitiesLoaded = useCapabilitiesLoaded(); const groupsHandlerAvailable = useStorageGroupsHandlerAvailable(); const [autoRefreshInterval] = useAutoRefreshInterval(); diff --git a/src/containers/Storage/StorageWrapper.tsx b/src/containers/Storage/StorageWrapper.tsx index 15cd05c69..d2c64aa32 100644 --- a/src/containers/Storage/StorageWrapper.tsx +++ b/src/containers/Storage/StorageWrapper.tsx @@ -1,4 +1,3 @@ -import type {AdditionalNodesProps} from '../../types/additionalProps'; import {USE_PAGINATED_TABLES_KEY} from '../../utils/constants'; import {useSetting} from '../../utils/hooks'; @@ -9,7 +8,6 @@ interface StorageWrapperProps { database?: string; nodeId?: string; parentContainer?: Element | null; - additionalNodesProps?: AdditionalNodesProps; } export const StorageWrapper = ({parentContainer, ...props}: StorageWrapperProps) => { From 10d58bacc801b01a87edbb452be0c1abcc90f925 Mon Sep 17 00:00:00 2001 From: mufazalov Date: Mon, 23 Sep 2024 15:50:18 +0300 Subject: [PATCH 4/8] fix: use Storage on all pages --- .../PDiskPage/PDiskGroups/PDiskGroups.tsx | 65 ------- src/containers/PDiskPage/PDiskGroups/utils.ts | 19 -- src/containers/PDiskPage/PDiskPage.tsx | 14 +- src/containers/PDiskPage/i18n/en.json | 2 +- src/containers/Storage/Storage.tsx | 15 +- .../StorageGroupPage/StorageGroupPage.scss | 9 +- .../StorageGroupPage/StorageGroupPage.tsx | 164 ++---------------- src/containers/StorageGroupPage/i18n/en.json | 3 +- src/containers/VDiskPage/VDiskPage.scss | 4 +- src/containers/VDiskPage/VDiskPage.tsx | 78 ++------- src/containers/VDiskPage/i18n/en.json | 2 +- src/containers/VDiskPage/utils.ts | 10 -- 12 files changed, 50 insertions(+), 335 deletions(-) delete mode 100644 src/containers/PDiskPage/PDiskGroups/PDiskGroups.tsx delete mode 100644 src/containers/PDiskPage/PDiskGroups/utils.ts delete mode 100644 src/containers/VDiskPage/utils.ts diff --git a/src/containers/PDiskPage/PDiskGroups/PDiskGroups.tsx b/src/containers/PDiskPage/PDiskGroups/PDiskGroups.tsx deleted file mode 100644 index 37b72d165..000000000 --- a/src/containers/PDiskPage/PDiskGroups/PDiskGroups.tsx +++ /dev/null @@ -1,65 +0,0 @@ -import React from 'react'; - -import {TableColumnSetup} from '@gravity-ui/uikit'; - -import {ResizeableDataTable} from '../../../components/ResizeableDataTable/ResizeableDataTable'; -import {TableWithControlsLayout} from '../../../components/TableWithControlsLayout/TableWithControlsLayout'; -import { - useCapabilitiesLoaded, - useStorageGroupsHandlerAvailable, -} from '../../../store/reducers/capabilities/hooks'; -import {storageApi} from '../../../store/reducers/storage/storage'; -import {DEFAULT_TABLE_SETTINGS} from '../../../utils/constants'; -import {useAutoRefreshInterval} from '../../../utils/hooks'; -import {STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY} from '../../Storage/StorageGroups/columns/constants'; -import {useStorageGroupsSelectedColumns} from '../../Storage/StorageGroups/columns/hooks'; - -import {preparePDiskStorageResponse} from './utils'; - -interface PDiskGroupsProps { - nodeId: string | number; - pDiskId: string | number; -} - -export function PDiskGroups({pDiskId, nodeId}: PDiskGroupsProps) { - const {columnsToShow, columnsToSelect, setColumns} = useStorageGroupsSelectedColumns(); - - const capabilitiesLoaded = useCapabilitiesLoaded(); - const groupsHandlerAvailable = useStorageGroupsHandlerAvailable(); - const [autoRefreshInterval] = useAutoRefreshInterval(); - - const {currentData, isFetching} = storageApi.useGetStorageGroupsInfoQuery( - {pDiskId, nodeId, shouldUseGroupsHandler: groupsHandlerAvailable}, - { - pollingInterval: autoRefreshInterval, - skip: !capabilitiesLoaded, - }, - ); - const loading = isFetching && currentData === undefined; - - const preparedGroups = React.useMemo(() => { - return preparePDiskStorageResponse(currentData, pDiskId, nodeId) || []; - }, [currentData, pDiskId, nodeId]); - - return ( - - - - - - - - - ); -} diff --git a/src/containers/PDiskPage/PDiskGroups/utils.ts b/src/containers/PDiskPage/PDiskGroups/utils.ts deleted file mode 100644 index 447faa0db..000000000 --- a/src/containers/PDiskPage/PDiskGroups/utils.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type {PreparedStorageResponse} from '../../../store/reducers/storage/types'; - -export function preparePDiskStorageResponse( - data?: PreparedStorageResponse, - pDiskId?: number | string, - nodeId?: number | string, -) { - return data?.groups?.filter((group) => { - return group.VDisks?.some((vdisk) => { - // If VDisk has PDisk inside, PDiskId and NodeId fields could be only inside PDisk and vice versa - const groupPDiskId = vdisk.PDiskId ?? vdisk.PDisk?.PDiskId; - const groupNodeId = vdisk.NodeId ?? vdisk.PDisk?.NodeId; - - return ( - Number(groupPDiskId) === Number(pDiskId) && Number(groupNodeId) === Number(nodeId) - ); - }); - }); -} diff --git a/src/containers/PDiskPage/PDiskPage.tsx b/src/containers/PDiskPage/PDiskPage.tsx index 3796a4a72..150046556 100644 --- a/src/containers/PDiskPage/PDiskPage.tsx +++ b/src/containers/PDiskPage/PDiskPage.tsx @@ -24,10 +24,10 @@ import {valueIsDefined} from '../../utils'; import {cn} from '../../utils/cn'; import {getPDiskId, getSeverityColor} from '../../utils/disks/helpers'; import {useAutoRefreshInterval, useTypedDispatch, useTypedSelector} from '../../utils/hooks'; +import {Storage} from '../Storage/Storage'; import {DecommissionButton} from './DecommissionButton/DecommissionButton'; import {DecommissionLabel} from './DecommissionLabel/DecommissionLabel'; -import {PDiskGroups} from './PDiskGroups/PDiskGroups'; import {PDiskSpaceDistribution} from './PDiskSpaceDistribution/PDiskSpaceDistribution'; import {pDiskPageKeyset} from './i18n'; @@ -37,7 +37,7 @@ const pdiskPageCn = cn('ydb-pdisk-page'); const PDISK_TABS_IDS = { diskDistribution: 'diskDistribution', - groups: 'groups', + storage: 'storage', } as const; const PDISK_PAGE_TABS = [ @@ -48,9 +48,9 @@ const PDISK_PAGE_TABS = [ }, }, { - id: PDISK_TABS_IDS.groups, + id: PDISK_TABS_IDS.storage, get title() { - return pDiskPageKeyset('groups'); + return pDiskPageKeyset('storage'); }, }, ]; @@ -237,10 +237,8 @@ export function PDiskPage() { ) : null; } - case 'groups': { - return pDiskParamsDefined ? ( - - ) : null; + case 'storage': { + return pDiskParamsDefined ? : null; } default: return null; diff --git a/src/containers/PDiskPage/i18n/en.json b/src/containers/PDiskPage/i18n/en.json index 336060762..df65b30aa 100644 --- a/src/containers/PDiskPage/i18n/en.json +++ b/src/containers/PDiskPage/i18n/en.json @@ -3,7 +3,7 @@ "pdisk": "PDisk", "node": "Node", - "groups": "Groups", + "storage": "Storage", "disk-distribution": "Disk distribution", "empty-slot": "Empty slot", diff --git a/src/containers/Storage/Storage.tsx b/src/containers/Storage/Storage.tsx index 62962c400..5db95c3ec 100644 --- a/src/containers/Storage/Storage.tsx +++ b/src/containers/Storage/Storage.tsx @@ -60,9 +60,11 @@ const UsageFilterParam = withDefault( interface StorageProps { database?: string; nodeId?: string | number; + groupId?: string | number; + pDiskId?: string | number; } -export const Storage = ({database, nodeId}: StorageProps) => { +export const Storage = ({database, nodeId, groupId, pDiskId}: StorageProps) => { const {balancer} = useClusterBaseInfo(); const additionalNodesProps = useAdditionalNodeProps({balancer}); @@ -115,14 +117,21 @@ export const Storage = ({database, nodeId}: StorageProps) => { } = useStorageGroupsSelectedColumns(visibleEntities); const nodesQuery = storageApi.useGetStorageNodesInfoQuery( - {database, with: visibleEntities, node_id: nodeId}, + {database, with: visibleEntities, node_id: nodeId, group_id: groupId}, { skip: !isNodes, pollingInterval: autoRefreshInterval, }, ); const groupsQuery = storageApi.useGetStorageGroupsInfoQuery( - {database, with: visibleEntities, nodeId, shouldUseGroupsHandler: groupsHandlerAvailable}, + { + database, + with: visibleEntities, + nodeId, + groupId, + pDiskId, + shouldUseGroupsHandler: groupsHandlerAvailable, + }, { skip: !isGroups || !capabilitiesLoaded, pollingInterval: autoRefreshInterval, diff --git a/src/containers/StorageGroupPage/StorageGroupPage.scss b/src/containers/StorageGroupPage/StorageGroupPage.scss index bf03837bb..34d6c80e0 100644 --- a/src/containers/StorageGroupPage/StorageGroupPage.scss +++ b/src/containers/StorageGroupPage/StorageGroupPage.scss @@ -11,7 +11,7 @@ &__meta, &__title, &__info, - &__tabs { + &__storage-title { position: sticky; left: 0; @@ -26,15 +26,12 @@ margin-bottom: 60px; } - &__tabs { + &__storage-title { margin-bottom: 0; + @include header-1-typography(); } &__info { margin-top: var(--g-spacing-10); } - - &__tabs { - @include tabs-wrapper-styles(); - } } diff --git a/src/containers/StorageGroupPage/StorageGroupPage.tsx b/src/containers/StorageGroupPage/StorageGroupPage.tsx index c9ddeb911..806169eae 100644 --- a/src/containers/StorageGroupPage/StorageGroupPage.tsx +++ b/src/containers/StorageGroupPage/StorageGroupPage.tsx @@ -1,89 +1,38 @@ import React from 'react'; -import {TableColumnSetup, Tabs} from '@gravity-ui/uikit'; import {skipToken} from '@reduxjs/toolkit/query'; import {Helmet} from 'react-helmet-async'; import {StringParam, useQueryParams} from 'use-query-params'; -import {z} from 'zod'; import {EntityPageTitle} from '../../components/EntityPageTitle/EntityPageTitle'; import {ResponseError} from '../../components/Errors/ResponseError'; import {InfoViewerSkeleton} from '../../components/InfoViewerSkeleton/InfoViewerSkeleton'; -import {InternalLink} from '../../components/InternalLink'; import {PageMetaWithAutorefresh} from '../../components/PageMeta/PageMeta'; import {StorageGroupInfo} from '../../components/StorageGroupInfo/StorageGroupInfo'; -import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout'; -import {getStorageGroupPath} from '../../routes'; import {useStorageGroupsHandlerAvailable} from '../../store/reducers/capabilities/hooks'; -import {useClusterBaseInfo} from '../../store/reducers/cluster/cluster'; import {setHeaderBreadcrumbs} from '../../store/reducers/header/header'; -import {STORAGE_TYPES} from '../../store/reducers/storage/constants'; import {storageApi} from '../../store/reducers/storage/storage'; import {EFlag} from '../../types/api/enums'; import {valueIsDefined} from '../../utils'; import {cn} from '../../utils/cn'; -import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants'; import {useAutoRefreshInterval, useTypedDispatch} from '../../utils/hooks'; -import {NodesUptimeFilterValues} from '../../utils/nodes'; -import {useAdditionalNodeProps} from '../AppWithClusters/useClusterData'; -import {StorageGroups} from '../Storage/StorageGroups/StorageGroups'; -import {useStorageGroupsSelectedColumns} from '../Storage/StorageGroups/columns/hooks'; -import {StorageNodes} from '../Storage/StorageNodes/StorageNodes'; -import {useStorageNodesSelectedColumns} from '../Storage/StorageNodes/columns/hooks'; +import {Storage} from '../Storage/Storage'; import {storageGroupPageKeyset} from './i18n'; import './StorageGroupPage.scss'; -const STORAGE_GROUP_PAGE_TABS = [ - { - id: STORAGE_TYPES.groups, - get title() { - return storageGroupPageKeyset('group'); - }, - }, - { - id: STORAGE_TYPES.nodes, - get title() { - return storageGroupPageKeyset('nodes'); - }, - }, -]; - const storageGroupPageCn = cn('ydb-storage-group-page'); -const storageGroupTabSchema = z.nativeEnum(STORAGE_TYPES).catch(STORAGE_TYPES.groups); - export function StorageGroupPage() { const dispatch = useTypedDispatch(); - const [{groupId, activeTab}] = useQueryParams({ - groupId: StringParam, - activeTab: StringParam, - }); - - const storageGroupTab = storageGroupTabSchema.parse(activeTab); + const [{groupId}] = useQueryParams({groupId: StringParam}); React.useEffect(() => { dispatch(setHeaderBreadcrumbs('storageGroup', {groupId})); }, [dispatch, groupId]); - const {balancer} = useClusterBaseInfo(); - const additionalNodesProps = useAdditionalNodeProps({balancer}); - - const { - columnsToShow: storageNodesColumnsToShow, - columnsToSelect: storageNodesColumnsToSelect, - setColumns: setStorageNodesSelectedColumns, - } = useStorageNodesSelectedColumns({ - additionalNodesProps, - }); - const { - columnsToShow: storageGroupsColumnsToShow, - columnsToSelect: storageGroupsColumnsToSelect, - setColumns: setStorageGroupsSelectedColumns, - } = useStorageGroupsSelectedColumns(); - const [autoRefreshInterval] = useAutoRefreshInterval(); const shouldUseGroupsHandler = useStorageGroupsHandlerAvailable(); const groupQuery = storageApi.useGetStorageGroupsInfoQuery( @@ -93,15 +42,7 @@ export function StorageGroupPage() { }, ); - const nodesQuery = storageApi.useGetStorageNodesInfoQuery( - groupId && storageGroupTab === STORAGE_TYPES.nodes ? {group_id: groupId} : skipToken, - { - pollingInterval: autoRefreshInterval, - }, - ); - const storageGroupData = groupQuery.data?.groups?.[0]; - const nodesData = nodesQuery.data?.nodes; const loading = groupQuery.isFetching && storageGroupData === undefined; @@ -152,103 +93,25 @@ export function StorageGroupPage() { return ; }; - const renderTabs = () => { - return ( -
- { - const path = groupId - ? getStorageGroupPath(groupId, {activeTab: id}) - : undefined; - - return ( - - {tabNode} - - ); - }} - /> -
- ); - }; - - const renderGroupsTable = () => { - if (!storageGroupData) { - return null; - } - - return ( - - - - - - - - - ); - }; - const renderNodesTable = () => { - if (!nodesData) { + const renderStorage = () => { + if (!groupId) { return null; } - return ( - - - - - - - - + +
+ {storageGroupPageKeyset('storage')} +
+ +
); }; - const renderTabsContent = () => { - switch (storageGroupTab) { - case 'groups': { - return renderGroupsTable(); - } - case 'nodes': { - return renderNodesTable(); - } - default: - return null; - } - }; - const renderError = () => { - if (!groupQuery.error && !nodesQuery.error) { + if (!groupQuery.error) { return null; } - return ; + return ; }; return ( @@ -258,8 +121,7 @@ export function StorageGroupPage() { {renderPageTitle()} {renderError()} {renderInfo()} - {renderTabs()} - {renderTabsContent()} + {renderStorage()} ); } diff --git a/src/containers/StorageGroupPage/i18n/en.json b/src/containers/StorageGroupPage/i18n/en.json index 3f35d8fd3..52fd15471 100644 --- a/src/containers/StorageGroupPage/i18n/en.json +++ b/src/containers/StorageGroupPage/i18n/en.json @@ -1,6 +1,5 @@ { "storage-group": "Storage Group", - "group": "Group", - "nodes": "Nodes", + "storage": "Storage", "pool-name": "Pool Name" } diff --git a/src/containers/VDiskPage/VDiskPage.scss b/src/containers/VDiskPage/VDiskPage.scss index ecaa50a40..fba6f02b7 100644 --- a/src/containers/VDiskPage/VDiskPage.scss +++ b/src/containers/VDiskPage/VDiskPage.scss @@ -12,7 +12,7 @@ &__title, &__controls, &__info, - &__group-title { + &__storage-title { position: sticky; left: 0; @@ -29,7 +29,7 @@ gap: var(--g-spacing-2); } - &__group-title { + &__storage-title { margin-bottom: 0; @include header-1-typography(); } diff --git a/src/containers/VDiskPage/VDiskPage.tsx b/src/containers/VDiskPage/VDiskPage.tsx index c070e9786..04e6ad41e 100644 --- a/src/containers/VDiskPage/VDiskPage.tsx +++ b/src/containers/VDiskPage/VDiskPage.tsx @@ -1,7 +1,7 @@ import React from 'react'; import {ArrowsOppositeToDots} from '@gravity-ui/icons'; -import {Icon, TableColumnSetup} from '@gravity-ui/uikit'; +import {Icon} from '@gravity-ui/uikit'; import {skipToken} from '@reduxjs/toolkit/query'; import {Helmet} from 'react-helmet-async'; import {StringParam, useQueryParams} from 'use-query-params'; @@ -11,29 +11,19 @@ import {EntityPageTitle} from '../../components/EntityPageTitle/EntityPageTitle' import {ResponseError} from '../../components/Errors/ResponseError'; import {InfoViewerSkeleton} from '../../components/InfoViewerSkeleton/InfoViewerSkeleton'; import {PageMetaWithAutorefresh} from '../../components/PageMeta/PageMeta'; -import {ResizeableDataTable} from '../../components/ResizeableDataTable/ResizeableDataTable'; -import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout'; import {VDiskInfo} from '../../components/VDiskInfo/VDiskInfo'; import {api} from '../../store/reducers/api'; import {selectIsUserAllowedToMakeChanges} from '../../store/reducers/authentication/authentication'; -import { - useCapabilitiesLoaded, - useStorageGroupsHandlerAvailable, -} from '../../store/reducers/capabilities/hooks'; import {setHeaderBreadcrumbs} from '../../store/reducers/header/header'; -import {storageApi} from '../../store/reducers/storage/storage'; import {vDiskApi} from '../../store/reducers/vdisk/vdisk'; import {valueIsDefined} from '../../utils'; import {cn} from '../../utils/cn'; -import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants'; import {stringifyVdiskId} from '../../utils/dataFormatters/dataFormatters'; import {getSeverityColor, getVDiskSlotBasedId} from '../../utils/disks/helpers'; import {useAutoRefreshInterval, useTypedDispatch, useTypedSelector} from '../../utils/hooks'; -import {STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY} from '../Storage/StorageGroups/columns/constants'; -import {useStorageGroupsSelectedColumns} from '../Storage/StorageGroups/columns/hooks'; +import {Storage} from '../Storage/Storage'; import {vDiskPageKeyset} from './i18n'; -import {prepareVDiskGroupResponse} from './utils'; import './VDiskPage.scss'; @@ -183,9 +173,14 @@ export function VDiskPage() { return ; }; - const renderGroupInfo = () => { - if (valueIsDefined(GroupID)) { - return ; + const renderStorageInfo = () => { + if (valueIsDefined(GroupID) && valueIsDefined(nodeId)) { + return ( + +
{vDiskPageKeyset('storage')}
+ +
+ ); } return null; @@ -200,7 +195,7 @@ export function VDiskPage() { {error ? : null} {renderInfo()} - {renderGroupInfo()} + {renderStorageInfo()} ); }; @@ -215,54 +210,3 @@ export function VDiskPage() { ); } - -export function VDiskGroup({groupId}: {groupId: string | number}) { - const {columnsToShow, columnsToSelect, setColumns} = useStorageGroupsSelectedColumns(); - - const capabilitiesLoaded = useCapabilitiesLoaded(); - const groupsHandlerAvailable = useStorageGroupsHandlerAvailable(); - const [autoRefreshInterval] = useAutoRefreshInterval(); - - const {currentData} = storageApi.useGetStorageGroupsInfoQuery( - {groupId, shouldUseGroupsHandler: groupsHandlerAvailable}, - { - pollingInterval: autoRefreshInterval, - skip: !capabilitiesLoaded, - }, - ); - - const preparedGroups = React.useMemo(() => { - const group = prepareVDiskGroupResponse(currentData, groupId); - - return group ? [group] : undefined; - }, [currentData, groupId]); - - if (!preparedGroups) { - return null; - } - - return ( - -
{vDiskPageKeyset('group')}
- - - - - - - - -
- ); -} diff --git a/src/containers/VDiskPage/i18n/en.json b/src/containers/VDiskPage/i18n/en.json index b88fbba32..fe10fe8f4 100644 --- a/src/containers/VDiskPage/i18n/en.json +++ b/src/containers/VDiskPage/i18n/en.json @@ -3,7 +3,7 @@ "node": "Node", "pdisk": "PDisk", "vdisk": "VDisk", - "group": "Group", + "storage": "Storage", "evict-vdisk-button": "Evict VDisk", "force-evict-vdisk-button": "Evict anyway", diff --git a/src/containers/VDiskPage/utils.ts b/src/containers/VDiskPage/utils.ts deleted file mode 100644 index 0db218a8f..000000000 --- a/src/containers/VDiskPage/utils.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type {PreparedStorageResponse} from '../../store/reducers/storage/types'; - -export function prepareVDiskGroupResponse( - data?: PreparedStorageResponse, - groupId?: string | number, -) { - return data?.groups?.find((group) => { - return Number(group.GroupId) === Number(groupId); - }); -} From c15208eb26a38798395094c607d60ad904ff72e9 Mon Sep 17 00:00:00 2001 From: mufazalov Date: Mon, 23 Sep 2024 16:15:34 +0300 Subject: [PATCH 5/8] fix(Storage): use groupId param only if no nodeId --- src/containers/Storage/Storage.tsx | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/containers/Storage/Storage.tsx b/src/containers/Storage/Storage.tsx index 5db95c3ec..889a6b1bd 100644 --- a/src/containers/Storage/Storage.tsx +++ b/src/containers/Storage/Storage.tsx @@ -25,6 +25,7 @@ import type { StorageType, VisibleEntities, } from '../../store/reducers/storage/types'; +import {valueIsDefined} from '../../utils'; import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants'; import {useAutoRefreshInterval, useTableSort} from '../../utils/hooks'; import {NodesUptimeFilterValues, nodesUptimeFilterValuesSchema} from '../../utils/nodes'; @@ -117,7 +118,13 @@ export const Storage = ({database, nodeId, groupId, pDiskId}: StorageProps) => { } = useStorageGroupsSelectedColumns(visibleEntities); const nodesQuery = storageApi.useGetStorageNodesInfoQuery( - {database, with: visibleEntities, node_id: nodeId, group_id: groupId}, + { + database, + with: visibleEntities, + node_id: nodeId, + // node_id and group_id params doesn't work together + group_id: valueIsDefined(nodeId) ? undefined : groupId, + }, { skip: !isNodes, pollingInterval: autoRefreshInterval, From 113a3ecf4389906db33101084f5be24ecfd623ed Mon Sep 17 00:00:00 2001 From: mufazalov Date: Mon, 23 Sep 2024 16:23:19 +0300 Subject: [PATCH 6/8] minor fixes --- src/containers/Storage/Storage.tsx | 2 +- .../Storage/StorageNodes/columns/hooks.ts | 13 +++++-------- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/containers/Storage/Storage.tsx b/src/containers/Storage/Storage.tsx index 889a6b1bd..bb90f6366 100644 --- a/src/containers/Storage/Storage.tsx +++ b/src/containers/Storage/Storage.tsx @@ -122,7 +122,7 @@ export const Storage = ({database, nodeId, groupId, pDiskId}: StorageProps) => { database, with: visibleEntities, node_id: nodeId, - // node_id and group_id params doesn't work together + // node_id and group_id params don't work together group_id: valueIsDefined(nodeId) ? undefined : groupId, }, { diff --git a/src/containers/Storage/StorageNodes/columns/hooks.ts b/src/containers/Storage/StorageNodes/columns/hooks.ts index 0c116e720..419f4d94d 100644 --- a/src/containers/Storage/StorageNodes/columns/hooks.ts +++ b/src/containers/Storage/StorageNodes/columns/hooks.ts @@ -13,17 +13,14 @@ import { } from './constants'; import type {GetStorageNodesColumnsParams} from './types'; -export const useGetStorageNodesColumns = (params: GetStorageNodesColumnsParams) => { - return React.useMemo(() => { - return getPreparedStorageNodesColumns(params); - }, [params]); -}; - export function useStorageNodesSelectedColumns({ visibleEntities, - ...restParams + database, + additionalNodesProps, }: GetStorageNodesColumnsParams) { - const columns = useGetStorageNodesColumns(restParams); + const columns = React.useMemo(() => { + return getPreparedStorageNodesColumns({database, additionalNodesProps}); + }, [database, additionalNodesProps]); const requiredColumns = React.useMemo(() => { if (visibleEntities === VISIBLE_ENTITIES.missing) { From 6a91699570b65fae3333d3a0532dc1bc3b42869d Mon Sep 17 00:00:00 2001 From: mufazalov Date: Mon, 23 Sep 2024 16:50:55 +0300 Subject: [PATCH 7/8] fix(StorageGroupPage): add with param to query --- src/containers/StorageGroupPage/StorageGroupPage.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/containers/StorageGroupPage/StorageGroupPage.tsx b/src/containers/StorageGroupPage/StorageGroupPage.tsx index 806169eae..3a7b9e231 100644 --- a/src/containers/StorageGroupPage/StorageGroupPage.tsx +++ b/src/containers/StorageGroupPage/StorageGroupPage.tsx @@ -36,7 +36,7 @@ export function StorageGroupPage() { const [autoRefreshInterval] = useAutoRefreshInterval(); const shouldUseGroupsHandler = useStorageGroupsHandlerAvailable(); const groupQuery = storageApi.useGetStorageGroupsInfoQuery( - valueIsDefined(groupId) ? {groupId, shouldUseGroupsHandler} : skipToken, + valueIsDefined(groupId) ? {groupId, shouldUseGroupsHandler, with: 'all'} : skipToken, { pollingInterval: autoRefreshInterval, }, From 5e24996a73f31e11aeb5988eb236d5779ffd0297 Mon Sep 17 00:00:00 2001 From: mufazalov Date: Mon, 23 Sep 2024 17:00:27 +0300 Subject: [PATCH 8/8] fix(StorageGroupPage): wait capabilities loaded --- src/containers/StorageGroupPage/StorageGroupPage.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/containers/StorageGroupPage/StorageGroupPage.tsx b/src/containers/StorageGroupPage/StorageGroupPage.tsx index 3a7b9e231..14ff38806 100644 --- a/src/containers/StorageGroupPage/StorageGroupPage.tsx +++ b/src/containers/StorageGroupPage/StorageGroupPage.tsx @@ -9,7 +9,10 @@ import {ResponseError} from '../../components/Errors/ResponseError'; import {InfoViewerSkeleton} from '../../components/InfoViewerSkeleton/InfoViewerSkeleton'; import {PageMetaWithAutorefresh} from '../../components/PageMeta/PageMeta'; import {StorageGroupInfo} from '../../components/StorageGroupInfo/StorageGroupInfo'; -import {useStorageGroupsHandlerAvailable} from '../../store/reducers/capabilities/hooks'; +import { + useCapabilitiesLoaded, + useStorageGroupsHandlerAvailable, +} from '../../store/reducers/capabilities/hooks'; import {setHeaderBreadcrumbs} from '../../store/reducers/header/header'; import {storageApi} from '../../store/reducers/storage/storage'; import {EFlag} from '../../types/api/enums'; @@ -35,10 +38,12 @@ export function StorageGroupPage() { const [autoRefreshInterval] = useAutoRefreshInterval(); const shouldUseGroupsHandler = useStorageGroupsHandlerAvailable(); + const capabilitiesLoaded = useCapabilitiesLoaded(); const groupQuery = storageApi.useGetStorageGroupsInfoQuery( valueIsDefined(groupId) ? {groupId, shouldUseGroupsHandler, with: 'all'} : skipToken, { pollingInterval: autoRefreshInterval, + skip: !capabilitiesLoaded, }, );