From 1282052ba403a50e3416531876852cc318d2ba2a Mon Sep 17 00:00:00 2001 From: mufazalov Date: Wed, 28 Aug 2024 16:14:22 +0300 Subject: [PATCH] feat(Storage): add advanced disks view --- .../DiskStateProgressBar.scss | 7 +- src/components/PDiskPopup/PDiskPopup.tsx | 1 + src/components/VDisk/VDisk.tsx | 49 ++++++++---- src/components/VDisk/VDiskWithDonorsStack.tsx | 16 ++-- src/components/VDiskPopup/VDiskPopup.tsx | 1 + .../PDiskPage/PDiskGroups/PDiskGroups.tsx | 16 +--- src/containers/Storage/Disks/Disks.scss | 46 +++++++++++ src/containers/Storage/Disks/Disks.tsx | 76 +++++++++++++++++++ src/containers/Storage/PDisk/PDisk.scss | 6 +- src/containers/Storage/PDisk/PDisk.tsx | 48 ++++++++---- src/containers/Storage/PaginatedStorage.tsx | 5 -- src/containers/Storage/Storage.tsx | 6 +- .../StorageGroups/PaginatedStorageGroups.tsx | 15 +--- .../Storage/StorageGroups/StorageGroups.scss | 3 +- .../Storage/StorageGroups/StorageGroups.tsx | 15 +--- .../StorageGroups/getStorageGroupsColumns.tsx | 56 +++++++++++--- src/containers/Storage/StorageGroups/hooks.ts | 29 +++++++ .../StorageNodes/getStorageNodesColumns.tsx | 2 +- src/containers/UserSettings/i18n/en.json | 3 + src/containers/UserSettings/settings.tsx | 13 +++- src/containers/VDiskPage/VDiskPage.tsx | 15 +--- src/services/settings.ts | 2 + src/utils/constants.ts | 2 + src/utils/disks/prepareDisks.ts | 7 +- 24 files changed, 324 insertions(+), 115 deletions(-) create mode 100644 src/containers/Storage/Disks/Disks.scss create mode 100644 src/containers/Storage/Disks/Disks.tsx create mode 100644 src/containers/Storage/StorageGroups/hooks.ts diff --git a/src/components/DiskStateProgressBar/DiskStateProgressBar.scss b/src/components/DiskStateProgressBar/DiskStateProgressBar.scss index eacf58e09..4963d0c51 100644 --- a/src/components/DiskStateProgressBar/DiskStateProgressBar.scss +++ b/src/components/DiskStateProgressBar/DiskStateProgressBar.scss @@ -8,12 +8,13 @@ --progress-bar-border-color: var(--g-color-base-misc-heavy); --progress-bar-background-color: var(--g-color-base-misc-light); --progress-bar-fill-color: var(--g-color-base-misc-medium); + --progress-bar-height: var(--g-text-body-3-line-height); position: relative; z-index: 0; min-width: 50px; - height: var(--g-text-body-3-line-height); + height: var(--progress-bar-height); text-align: center; @@ -23,8 +24,8 @@ background-color: var(--progress-bar-background-color); &_compact { + --progress-bar-height: 12px; min-width: 0; - height: 12px; border-radius: 2px; } @@ -101,7 +102,7 @@ font-size: var(--g-text-body-1-font-size); // bar height minus borders - line-height: calc(var(--g-text-body-3-line-height) - #{$border-width * 2}); + line-height: calc(var(--progress-bar-height) - #{$border-width * 2}); color: inherit; } diff --git a/src/components/PDiskPopup/PDiskPopup.tsx b/src/components/PDiskPopup/PDiskPopup.tsx index 1e5f92f6e..8cd8d25b7 100644 --- a/src/components/PDiskPopup/PDiskPopup.tsx +++ b/src/components/PDiskPopup/PDiskPopup.tsx @@ -75,6 +75,7 @@ export const PDiskPopup = ({data, nodes, ...props}: PDiskPopupProps) => { { +export const VDisk = ({ + data = {}, + nodes, + compact, + showPopup, + onShowPopup, + onHidePopup, + progressBarClassName, +}: VDiskProps) => { const isFullData = isFullVDiskData(data); const diskPagesAvailable = useDiskPagesAvailable(); @@ -32,12 +44,14 @@ export const VDisk = ({data = {}, nodes, compact}: VDiskProps) => { const anchor = React.useRef(null); - const showPopup = () => { + const handleShowPopup = () => { setIsPopupVisible(true); + onShowPopup?.(); }; - const hidePopup = () => { + const handleHidePopup = () => { setIsPopupVisible(false); + onHidePopup?.(); }; let vDiskPath: string | undefined; @@ -62,23 +76,26 @@ export const VDisk = ({data = {}, nodes, compact}: VDiskProps) => { return ( - -
- {vDiskPath ? ( - - - - ) : ( + +
+ - )} +
); diff --git a/src/components/VDisk/VDiskWithDonorsStack.tsx b/src/components/VDisk/VDiskWithDonorsStack.tsx index f7f0a2bab..6b4bc6106 100644 --- a/src/components/VDisk/VDiskWithDonorsStack.tsx +++ b/src/components/VDisk/VDiskWithDonorsStack.tsx @@ -1,32 +1,29 @@ -import type {NodesMap} from '../../types/store/nodesList'; import {stringifyVdiskId} from '../../utils/dataFormatters/dataFormatters'; import {isFullVDiskData} from '../../utils/disks/helpers'; import type {PreparedVDisk} from '../../utils/disks/types'; import {Stack} from '../Stack/Stack'; +import type {VDiskProps} from './VDisk'; import {VDisk} from './VDisk'; -interface VDiskWithDonorsStackProps { +interface VDiskWithDonorsStackProps extends VDiskProps { data?: PreparedVDisk; - nodes?: NodesMap; - compact?: boolean; className?: string; stackClassName?: string; } export function VDiskWithDonorsStack({ data, - nodes, - compact, className, stackClassName, + ...restProps }: VDiskWithDonorsStackProps) { const donors = data?.Donors; const content = donors && donors.length > 0 ? ( - + {donors.map((donor) => { const isFullData = isFullVDiskData(donor); @@ -35,14 +32,13 @@ export function VDiskWithDonorsStack({ ); })} ) : ( - + ); return
{content}
; diff --git a/src/components/VDiskPopup/VDiskPopup.tsx b/src/components/VDiskPopup/VDiskPopup.tsx index d09c35524..86488c7f3 100644 --- a/src/components/VDiskPopup/VDiskPopup.tsx +++ b/src/components/VDiskPopup/VDiskPopup.tsx @@ -148,6 +148,7 @@ export const VDiskPopup = ({data, nodes, ...props}: VDiskPopupProps) => { { - return getDiskPageStorageColumns(nodesMap); - }, [nodesMap]); + const pDiskStorageColumns = useGetDiskStorageColumns(); if (loading) { return ; diff --git a/src/containers/Storage/Disks/Disks.scss b/src/containers/Storage/Disks/Disks.scss new file mode 100644 index 000000000..9ff651f57 --- /dev/null +++ b/src/containers/Storage/Disks/Disks.scss @@ -0,0 +1,46 @@ +.ydb-storage-disks { + display: flex; + flex-direction: row; + align-items: center; + gap: 20px; + + width: max-content; + + &__vdisks-wrapper { + display: flex; + flex-grow: 1; + flex-direction: row; + gap: 4px; + + width: 300px; + } + + &__pdisks-wrapper { + display: flex; + flex-direction: row; + justify-content: left; + gap: 6px; + + width: max-content; + } + + &__vdisk-item { + flex-basis: 8px; + flex-shrink: 0; + } + &__vdisk-progress-bar { + --progress-bar-height: 18px; + + border-radius: 4px; + } + + &__pdisk-item { + width: 80px; + } + &__pdisk-progress-bar { + --progress-bar-height: 20px; + padding-left: var(--g-spacing-2); + + text-align: left; + } +} diff --git a/src/containers/Storage/Disks/Disks.tsx b/src/containers/Storage/Disks/Disks.tsx new file mode 100644 index 000000000..9c16c6543 --- /dev/null +++ b/src/containers/Storage/Disks/Disks.tsx @@ -0,0 +1,76 @@ +import React from 'react'; + +import {VDiskWithDonorsStack} from '../../../components/VDisk/VDiskWithDonorsStack'; +import type {NodesMap} from '../../../types/store/nodesList'; +import {cn} from '../../../utils/cn'; +import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters'; +import type {PreparedVDisk} from '../../../utils/disks/types'; +import {PDisk} from '../PDisk'; + +import './Disks.scss'; + +const b = cn('ydb-storage-disks'); + +interface DisksProps { + vDisks?: PreparedVDisk[]; + nodes?: NodesMap; +} + +export function Disks({vDisks = [], nodes}: DisksProps) { + const [highlightedVDisk, setHighlightedVDisk] = React.useState(); + + return ( +
+
+ {vDisks?.map((vDisk) => { + // Do not show PDisk popup for VDisk + const vDiskToShow = {...vDisk, PDisk: undefined}; + + const vDiskId = stringifyVdiskId(vDisk.VDiskId); + + return ( +
+ setHighlightedVDisk(vDiskId)} + onHidePopup={() => setHighlightedVDisk(undefined)} + progressBarClassName={b('vdisk-progress-bar')} + /> +
+ ); + })} +
+ +
+ {vDisks?.map((vDisk) => { + const vDiskId = stringifyVdiskId(vDisk.VDiskId); + + if (!vDisk.PDisk) { + return null; + } + + return ( + setHighlightedVDisk(vDiskId)} + onHidePopup={() => setHighlightedVDisk(undefined)} + /> + ); + })} +
+
+ ); +} diff --git a/src/containers/Storage/PDisk/PDisk.scss b/src/containers/Storage/PDisk/PDisk.scss index 52a275bdb..69bf5e5d6 100644 --- a/src/containers/Storage/PDisk/PDisk.scss +++ b/src/containers/Storage/PDisk/PDisk.scss @@ -40,12 +40,14 @@ &__media-type { position: absolute; - top: 0; + top: 50%; right: 4px; font-size: var(--g-text-body-1-font-size); - line-height: var(--g-text-body-3-line-height); + line-height: var(--g-text-body-1-line-height); color: var(--g-color-text-secondary); + + transform: translateY(-50%); } } diff --git a/src/containers/Storage/PDisk/PDisk.tsx b/src/containers/Storage/PDisk/PDisk.tsx index 32cd9cf58..aacf7ac70 100644 --- a/src/containers/Storage/PDisk/PDisk.tsx +++ b/src/containers/Storage/PDisk/PDisk.tsx @@ -18,24 +18,41 @@ import './PDisk.scss'; const b = cn('pdisk-storage'); interface PDiskProps { - nodeId: number; data?: PreparedPDisk; vDisks?: TVDiskStateInfo[]; + showPopup?: boolean; + onShowPopup?: VoidFunction; + onHidePopup?: VoidFunction; + className?: string; + progressBarClassName?: string; } -export const PDisk = ({nodeId, data = {}, vDisks}: PDiskProps) => { +export const PDisk = ({ + data = {}, + vDisks, + showPopup, + onShowPopup, + onHidePopup, + className, + progressBarClassName, +}: PDiskProps) => { const [isPopupVisible, setIsPopupVisible] = React.useState(false); const diskPagesAvailable = useDiskPagesAvailable(); const anchor = React.useRef(null); - const showPopup = () => { + const {NodeId, PDiskId} = data; + const pDiskIdsDefined = valueIsDefined(NodeId) && valueIsDefined(PDiskId); + + const handleShowPopup = () => { setIsPopupVisible(true); + onShowPopup?.(); }; - const hidePopup = () => { + const handleHidePopup = () => { setIsPopupVisible(false); + onHidePopup?.(); }; const renderVDisks = () => { @@ -68,30 +85,31 @@ export const PDisk = ({nodeId, data = {}, vDisks}: PDiskProps) => { ); }; - let pDiskPath = createHref( - routes.node, - {id: nodeId, activeTab: STRUCTURE}, - {pdiskId: data.PDiskId || ''}, - ); + let pDiskPath: string | undefined; + + if (pDiskIdsDefined) { + pDiskPath = createHref(routes.node, {id: NodeId, activeTab: STRUCTURE}, {pdiskId: PDiskId}); + } - if (diskPagesAvailable && valueIsDefined(data.PDiskId)) { - pDiskPath = getPDiskPagePath(data.PDiskId, nodeId); + if (pDiskIdsDefined && diskPagesAvailable) { + pDiskPath = getPDiskPagePath(PDiskId, NodeId); } return ( - -
+ +
{renderVDisks()}
{data.Type}
diff --git a/src/containers/Storage/PaginatedStorage.tsx b/src/containers/Storage/PaginatedStorage.tsx index 380e77f41..0726c7bd3 100644 --- a/src/containers/Storage/PaginatedStorage.tsx +++ b/src/containers/Storage/PaginatedStorage.tsx @@ -3,12 +3,10 @@ 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 {selectNodesMap} from '../../store/reducers/nodesList'; import {STORAGE_TYPES, 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'; -import {useTypedSelector} from '../../utils/hooks'; import {NodesUptimeFilterValues, nodesUptimeFilterValuesSchema} from '../../utils/nodes'; import {StorageControls} from './StorageControls/StorageControls'; @@ -55,8 +53,6 @@ export const PaginatedStorage = ({ setQueryParams({uptimeFilter: value}, 'replaceIn'); }; - const nodesMap = useTypedSelector(selectNodesMap); - const handleShowAllGroups = () => { handleGroupVisibilityChange(VISIBLE_ENTITIES.all); }; @@ -121,7 +117,6 @@ export const PaginatedStorage = ({ visibleEntities={visibleEntities} database={database} nodeId={nodeId} - nodesMap={nodesMap} onShowAll={handleShowAllGroups} parentContainer={parentContainer} renderControls={renderControls} diff --git a/src/containers/Storage/Storage.tsx b/src/containers/Storage/Storage.tsx index 00c91cda1..75c843e54 100644 --- a/src/containers/Storage/Storage.tsx +++ b/src/containers/Storage/Storage.tsx @@ -7,7 +7,6 @@ import {isAccessError} from '../../components/Errors/PageError/PageError'; import {ResponseError} from '../../components/Errors/ResponseError'; import {TableWithControlsLayout} from '../../components/TableWithControlsLayout/TableWithControlsLayout'; import type {NodesSortParams} from '../../store/reducers/nodes/types'; -import {selectNodesMap} from '../../store/reducers/nodesList'; import {STORAGE_TYPES, VISIBLE_ENTITIES} from '../../store/reducers/storage/constants'; import { filterGroups, @@ -23,7 +22,7 @@ import type { } from '../../store/reducers/storage/types'; import type {AdditionalNodesProps} from '../../types/additionalProps'; import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants'; -import {useAutoRefreshInterval, useTableSort, useTypedSelector} from '../../utils/hooks'; +import {useAutoRefreshInterval, useTableSort} from '../../utils/hooks'; import {NodesUptimeFilterValues, nodesUptimeFilterValuesSchema} from '../../utils/nodes'; import {StorageControls} from './StorageControls/StorageControls'; @@ -72,8 +71,6 @@ export const Storage = ({additionalNodesProps, database, nodeId}: StorageProps) const uptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter); const usageFilter = queryParams.usageFilter; - const nodesMap = useTypedSelector(selectNodesMap); - const [nodeSort, setNodeSort] = React.useState({ sortOrder: undefined, sortValue: undefined, @@ -166,7 +163,6 @@ export const Storage = ({additionalNodesProps, database, nodeId}: StorageProps) visibleEntities={visibleEntities} data={storageGroups} tableSettings={DEFAULT_TABLE_SETTINGS} - nodes={nodesMap} onShowAll={() => handleGroupVisibilityChange(VISIBLE_ENTITIES.all)} sort={groupsSort} handleSort={handleGroupsSort} diff --git a/src/containers/Storage/StorageGroups/PaginatedStorageGroups.tsx b/src/containers/Storage/StorageGroups/PaginatedStorageGroups.tsx index e820f08d5..2388f69aa 100644 --- a/src/containers/Storage/StorageGroups/PaginatedStorageGroups.tsx +++ b/src/containers/Storage/StorageGroups/PaginatedStorageGroups.tsx @@ -4,14 +4,11 @@ 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 {NodesMap} from '../../../types/store/nodesList'; import {StorageGroupsEmptyDataMessage} from './StorageGroupsEmptyDataMessage'; import {getStorageGroups} from './getGroups'; -import { - STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY, - getPreparedStorageGroupsColumns, -} from './getStorageGroupsColumns'; +import {STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY} from './getStorageGroupsColumns'; +import {useGetStorageColumns} from './hooks'; import i18n from './i18n'; interface PaginatedStorageGroupsProps { @@ -19,7 +16,6 @@ interface PaginatedStorageGroupsProps { visibleEntities: VisibleEntities; database?: string; nodeId?: string; - nodesMap?: NodesMap; onShowAll: VoidFunction; @@ -33,20 +29,17 @@ export const PaginatedStorageGroups = ({ visibleEntities, database, nodeId, - nodesMap, onShowAll, parentContainer, renderControls, renderErrorMessage, }: PaginatedStorageGroupsProps) => { + const columns = useGetStorageColumns(visibleEntities); + const tableFilters = React.useMemo(() => { return {searchValue, visibleEntities, database, nodeId}; }, [searchValue, visibleEntities, database, nodeId]); - const columns = React.useMemo(() => { - return getPreparedStorageGroupsColumns(nodesMap, visibleEntities); - }, [nodesMap, visibleEntities]); - const renderEmptyDataMessage = () => { if (visibleEntities !== VISIBLE_ENTITIES.all) { return ( diff --git a/src/containers/Storage/StorageGroups/StorageGroups.scss b/src/containers/Storage/StorageGroups/StorageGroups.scss index 22e1a915b..70008689b 100644 --- a/src/containers/Storage/StorageGroups/StorageGroups.scss +++ b/src/containers/Storage/StorageGroups/StorageGroups.scss @@ -1,5 +1,6 @@ .global-storage-groups { - &__vdisks-column { + &__vdisks-column, + &__disks-column { overflow: visible; // to enable stacked disks overflow the row } diff --git a/src/containers/Storage/StorageGroups/StorageGroups.tsx b/src/containers/Storage/StorageGroups/StorageGroups.tsx index a7bf4e664..caab34a4b 100644 --- a/src/containers/Storage/StorageGroups/StorageGroups.tsx +++ b/src/containers/Storage/StorageGroups/StorageGroups.tsx @@ -1,25 +1,19 @@ -import React from 'react'; - 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 {PreparedStorageGroup, VisibleEntities} from '../../../store/reducers/storage/types'; -import type {NodesMap} from '../../../types/store/nodesList'; import type {HandleSort} from '../../../utils/hooks/useTableSort'; import {StorageGroupsEmptyDataMessage} from './StorageGroupsEmptyDataMessage'; -import { - STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY, - getPreparedStorageGroupsColumns, -} from './getStorageGroupsColumns'; +import {STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY} from './getStorageGroupsColumns'; +import {useGetStorageColumns} from './hooks'; import i18n from './i18n'; import './StorageGroups.scss'; interface StorageGroupsProps { data: PreparedStorageGroup[]; - nodes?: NodesMap; tableSettings: Settings; visibleEntities: VisibleEntities; onShowAll?: VoidFunction; @@ -31,14 +25,11 @@ export function StorageGroups({ data, tableSettings, visibleEntities, - nodes, onShowAll, sort, handleSort, }: StorageGroupsProps) { - const columns = React.useMemo(() => { - return getPreparedStorageGroupsColumns(nodes, visibleEntities); - }, [nodes, visibleEntities]); + const columns = useGetStorageColumns(visibleEntities); if (!data.length && visibleEntities !== VISIBLE_ENTITIES.all) { return ( diff --git a/src/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx b/src/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx index 043c1f958..e92679318 100644 --- a/src/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx +++ b/src/containers/Storage/StorageGroups/getStorageGroupsColumns.tsx @@ -18,6 +18,7 @@ import {cn} from '../../../utils/cn'; import {stringifyVdiskId} from '../../../utils/dataFormatters/dataFormatters'; import {isSortableStorageProperty} from '../../../utils/storage'; import {bytesToGB, bytesToSpeed} from '../../../utils/utils'; +import {Disks} from '../Disks/Disks'; import {getDegradedSeverity, getUsageSeverityForStorageGroup} from '../utils'; import i18n from './i18n'; @@ -43,6 +44,7 @@ export const GROUPS_COLUMNS_IDS = { Read: 'Read', Write: 'Write', VDisks: 'VDisks', + Disks: 'Disks', Degraded: 'Degraded', } as const; @@ -233,6 +235,28 @@ const getVDisksColumn = (nodes?: NodesMap): StorageGroupsColumn => ({ sortable: false, }); +const getDisksColumn = (nodes?: NodesMap): StorageGroupsColumn => ({ + name: GROUPS_COLUMNS_IDS.Disks, + className: b('disks-column'), + header: 'Disks', + render: ({row}) => { + return ; + }, + align: DataTable.CENTER, + width: 1050, + resizeable: false, + sortable: false, +}); + +interface GetColumnsData { + nodes?: NodesMap; +} + +interface GetColumnsOptions { + useAdvancedStorage?: boolean; + visibleEntities?: VisibleEntities; +} + export const getStorageTopGroupsColumns = (): StorageGroupsColumn[] => { const columns = [ groupIdColumn, @@ -251,7 +275,14 @@ export const getStorageTopGroupsColumns = (): StorageGroupsColumn[] => { }); }; -export const getDiskPageStorageColumns = (nodes?: NodesMap): StorageGroupsColumn[] => { +export const getDiskPageStorageColumns = ( + data?: GetColumnsData, + options?: GetColumnsOptions, +): StorageGroupsColumn[] => { + const disksColumn = options?.useAdvancedStorage + ? getDisksColumn() + : getVDisksColumn(data?.nodes); + return [ poolNameColumn, typeColumn, @@ -260,11 +291,18 @@ export const getDiskPageStorageColumns = (nodes?: NodesMap): StorageGroupsColumn groupIdColumn, usageColumn, usedColumn, - getVDisksColumn(nodes), + disksColumn, ]; }; -const getStorageGroupsColumns = (nodes?: NodesMap): StorageGroupsColumn[] => { +const getStorageGroupsColumns = ( + data?: GetColumnsData, + options?: GetColumnsOptions, +): StorageGroupsColumn[] => { + const disksColumn = options?.useAdvancedStorage + ? getDisksColumn() + : getVDisksColumn(data?.nodes); + return [ poolNameColumn, typeColumn, @@ -277,13 +315,13 @@ const getStorageGroupsColumns = (nodes?: NodesMap): StorageGroupsColumn[] => { usedSpaceFlagColumn, readColumn, writeColumn, - getVDisksColumn(nodes), + disksColumn, ]; }; const filterStorageGroupsColumns = ( columns: StorageGroupsColumn[], - visibleEntities: VisibleEntities, + visibleEntities?: VisibleEntities, ) => { if (visibleEntities === VISIBLE_ENTITIES.space) { return columns.filter((col) => col.name !== GROUPS_COLUMNS_IDS.Degraded); @@ -302,12 +340,12 @@ const filterStorageGroupsColumns = ( }; export const getPreparedStorageGroupsColumns = ( - nodesMap: NodesMap | undefined, - visibleEntities: VisibleEntities, + data?: GetColumnsData, + options?: GetColumnsOptions, ) => { - const rawColumns = getStorageGroupsColumns(nodesMap); + const rawColumns = getStorageGroupsColumns(data, options); - const filteredColumns = filterStorageGroupsColumns(rawColumns, visibleEntities); + const filteredColumns = filterStorageGroupsColumns(rawColumns, options?.visibleEntities); return filteredColumns.map((column) => ({ ...column, diff --git a/src/containers/Storage/StorageGroups/hooks.ts b/src/containers/Storage/StorageGroups/hooks.ts new file mode 100644 index 000000000..65683a9cc --- /dev/null +++ b/src/containers/Storage/StorageGroups/hooks.ts @@ -0,0 +1,29 @@ +import React from 'react'; + +import {selectNodesMap} from '../../../store/reducers/nodesList'; +import type {VisibleEntities} from '../../../store/reducers/storage/types'; +import {USE_ADVANCED_STORAGE_KEY} from '../../../utils/constants'; +import {useSetting, useTypedSelector} from '../../../utils/hooks'; + +import { + getDiskPageStorageColumns, + getPreparedStorageGroupsColumns, +} from './getStorageGroupsColumns'; + +export const useGetStorageColumns = (visibleEntities: VisibleEntities) => { + const [useAdvancedStorage] = useSetting(USE_ADVANCED_STORAGE_KEY, false); + const nodes = useTypedSelector(selectNodesMap); + + return React.useMemo(() => { + return getPreparedStorageGroupsColumns({nodes}, {visibleEntities, useAdvancedStorage}); + }, [visibleEntities, useAdvancedStorage, nodes]); +}; + +export const useGetDiskStorageColumns = () => { + const [useAdvancedStorage] = useSetting(USE_ADVANCED_STORAGE_KEY, false); + const nodes = useTypedSelector(selectNodesMap); + + return React.useMemo(() => { + return getDiskPageStorageColumns({nodes}, {useAdvancedStorage}); + }, [useAdvancedStorage, nodes]); +}; diff --git a/src/containers/Storage/StorageNodes/getStorageNodesColumns.tsx b/src/containers/Storage/StorageNodes/getStorageNodesColumns.tsx index 9cca952cb..4397397c9 100644 --- a/src/containers/Storage/StorageNodes/getStorageNodesColumns.tsx +++ b/src/containers/Storage/StorageNodes/getStorageNodesColumns.tsx @@ -94,7 +94,7 @@ const getStorageNodesColumns = ( return (
- +
); })} diff --git a/src/containers/UserSettings/i18n/en.json b/src/containers/UserSettings/i18n/en.json index 444723a1d..232daaffb 100644 --- a/src/containers/UserSettings/i18n/en.json +++ b/src/containers/UserSettings/i18n/en.json @@ -33,6 +33,9 @@ "settings.useNodesEndpoint.title": "Break the Nodes tab in Diagnostics", "settings.useNodesEndpoint.description": "Use /viewer/json/nodes endpoint for Nodes tab in diagnostics. It could return incorrect data on versions before 24-1", + "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 fa7e81cee..99eb33f76 100644 --- a/src/containers/UserSettings/settings.tsx +++ b/src/containers/UserSettings/settings.tsx @@ -11,6 +11,7 @@ import { QUERY_USE_MULTI_SCHEMA_KEY, SHOW_DOMAIN_DATABASE_KEY, THEME_KEY, + USE_ADVANCED_STORAGE_KEY, USE_CLUSTER_BALANCER_AS_BACKEND_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, USE_PAGINATED_TABLES_KEY, @@ -95,6 +96,11 @@ export const useNodesEndpointSetting: SettingProps = { title: i18n('settings.useNodesEndpoint.title'), description: i18n('settings.useNodesEndpoint.description'), }; +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 +155,12 @@ export const appearanceSection: SettingsSection = { export const experimentsSection: SettingsSection = { id: 'experimentsSection', title: i18n('section.experiments'), - settings: [useNodesEndpointSetting, usePaginatedTables, queryUseMultiSchemaSetting], + settings: [ + useNodesEndpointSetting, + useAdvancedStorageSetting, + usePaginatedTables, + queryUseMultiSchemaSetting, + ], }; export const devSettingsSection: SettingsSection = { id: 'devSettingsSection', diff --git a/src/containers/VDiskPage/VDiskPage.tsx b/src/containers/VDiskPage/VDiskPage.tsx index 31577e9f1..487eace91 100644 --- a/src/containers/VDiskPage/VDiskPage.tsx +++ b/src/containers/VDiskPage/VDiskPage.tsx @@ -15,7 +15,6 @@ import {ResizeableDataTable} from '../../components/ResizeableDataTable/Resizeab import {VDiskInfo} from '../../components/VDiskInfo/VDiskInfo'; import {selectIsUserAllowedToMakeChanges} from '../../store/reducers/authentication/authentication'; import {setHeaderBreadcrumbs} from '../../store/reducers/header/header'; -import {selectNodesMap} from '../../store/reducers/nodesList'; import type {PreparedStorageGroup} from '../../store/reducers/storage/types'; import {vDiskApi} from '../../store/reducers/vdisk/vdisk'; import {valueIsDefined} from '../../utils'; @@ -24,10 +23,8 @@ import {DEFAULT_TABLE_SETTINGS} from '../../utils/constants'; import {stringifyVdiskId} from '../../utils/dataFormatters/dataFormatters'; import {getSeverityColor} from '../../utils/disks/helpers'; import {useAutoRefreshInterval, useTypedDispatch, useTypedSelector} from '../../utils/hooks'; -import { - STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY, - getDiskPageStorageColumns, -} from '../Storage/StorageGroups/getStorageGroupsColumns'; +import {STORAGE_GROUPS_COLUMNS_WIDTH_LS_KEY} from '../Storage/StorageGroups/getStorageGroupsColumns'; +import {useGetDiskStorageColumns} from '../Storage/StorageGroups/hooks'; import {vDiskPageKeyset} from './i18n'; @@ -206,17 +203,13 @@ export function VDiskPage() { } export function VDiskGroup({data}: {data: PreparedStorageGroup}) { - const nodesMap = useTypedSelector(selectNodesMap); - - const pDiskStorageColumns = React.useMemo(() => { - return getDiskPageStorageColumns(nodesMap); - }, [nodesMap]); + const vDiskStorageColumns = useGetDiskStorageColumns(); return ( ); diff --git a/src/services/settings.ts b/src/services/settings.ts index bfe6b777f..7cecfc899 100644 --- a/src/services/settings.ts +++ b/src/services/settings.ts @@ -19,6 +19,7 @@ import { SHOW_DOMAIN_DATABASE_KEY, TENANT_INITIAL_PAGE_KEY, THEME_KEY, + USE_ADVANCED_STORAGE_KEY, USE_CLUSTER_BALANCER_AS_BACKEND_KEY, USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY, USE_PAGINATED_TABLES_KEY, @@ -34,6 +35,7 @@ export const DEFAULT_USER_SETTINGS = { [LANGUAGE_KEY]: undefined, [INVERTED_DISKS_KEY]: false, [USE_NODES_ENDPOINT_IN_DIAGNOSTICS_KEY]: true, + [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 2ae485634..ff7878a2b 100644 --- a/src/utils/constants.ts +++ b/src/utils/constants.ts @@ -161,3 +161,5 @@ 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'; diff --git a/src/utils/disks/prepareDisks.ts b/src/utils/disks/prepareDisks.ts index c67f41f32..f27d05bf4 100644 --- a/src/utils/disks/prepareDisks.ts +++ b/src/utils/disks/prepareDisks.ts @@ -8,7 +8,12 @@ import type {PreparedPDisk, PreparedVDisk} from './types'; export function prepareVDiskData(vdiskState: TVDiskStateInfo = {}): PreparedVDisk { // Prepare PDisk only if it is present - const PDisk = vdiskState.PDisk ? preparePDiskData(vdiskState.PDisk) : undefined; + const PDisk = vdiskState.PDisk + ? preparePDiskData({ + ...vdiskState.PDisk, + NodeId: vdiskState.PDisk.NodeId ?? vdiskState.NodeId, + }) + : undefined; const PDiskId = vdiskState.PDiskId ?? PDisk?.PDiskId;