Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 40 additions & 26 deletions src/components/VDiskPopup/VDiskPopup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ import {createVDiskDeveloperUILink} from '../../utils/developerUI/developerUI';
import {isFullVDiskData} from '../../utils/disks/helpers';
import type {PreparedVDisk, UnavailableDonor} from '../../utils/disks/types';
import {useTypedSelector} from '../../utils/hooks';
import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
import {
useIsUserAllowedToMakeChanges,
useIsViewerUser,
} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
import {bytesToGB, bytesToSpeed} from '../../utils/utils';
import type {InfoViewerItem} from '../InfoViewer';
import {InfoViewer} from '../InfoViewer';
Expand All @@ -23,23 +26,27 @@ import {preparePDiskData} from '../PDiskPopup/PDiskPopup';
import {getVDiskLink} from '../VDisk/utils';
import {vDiskInfoKeyset} from '../VDiskInfo/i18n';

import {vDiskPopupKeyset} from './i18n';

import './VDiskPopup.scss';

const b = cn('vdisk-storage-popup');

const prepareUnavailableVDiskData = (data: UnavailableDonor, withDeveloperUILink?: boolean) => {
const {NodeId, PDiskId, VSlotId, StoragePoolName} = data;

const vdiskData: InfoViewerItem[] = [{label: 'State', value: 'not available'}];
const vdiskData: InfoViewerItem[] = [
{label: vDiskPopupKeyset('label_state'), value: vDiskPopupKeyset('context_not-available')},
];

if (StoragePoolName) {
vdiskData.push({label: 'StoragePool', value: StoragePoolName});
vdiskData.push({label: vDiskPopupKeyset('label_storage-pool'), value: StoragePoolName});
}

vdiskData.push(
{label: 'NodeId', value: NodeId ?? EMPTY_DATA_PLACEHOLDER},
{label: 'PDiskId', value: PDiskId ?? EMPTY_DATA_PLACEHOLDER},
{label: 'VSlotId', value: VSlotId ?? EMPTY_DATA_PLACEHOLDER},
{label: vDiskPopupKeyset('label_node-id'), value: NodeId ?? EMPTY_DATA_PLACEHOLDER},
{label: vDiskPopupKeyset('label_pdisk-id'), value: PDiskId ?? EMPTY_DATA_PLACEHOLDER},
{label: vDiskPopupKeyset('label_vslot-id'), value: VSlotId ?? EMPTY_DATA_PLACEHOLDER},
);

if (
Expand All @@ -55,7 +62,7 @@ const prepareUnavailableVDiskData = (data: UnavailableDonor, withDeveloperUILink
});

vdiskData.push({
label: 'Links',
label: vDiskPopupKeyset('label_links'),
value: <LinkWithIcon title={'Developer UI'} url={vDiskInternalViewerPath} />,
});
}
Expand Down Expand Up @@ -85,58 +92,61 @@ const prepareVDiskData = (data: PreparedVDisk, withDeveloperUILink?: boolean) =>
} = data;

const vdiskData: InfoViewerItem[] = [
{label: 'VDisk', value: StringifiedId},
{label: 'State', value: VDiskState ?? 'not available'},
{label: vDiskPopupKeyset('label_vdisk'), value: StringifiedId},
{
label: vDiskPopupKeyset('label_state'),
value: VDiskState ?? vDiskPopupKeyset('context_not-available'),
},
];

if (StoragePoolName) {
vdiskData.push({label: 'StoragePool', value: StoragePoolName});
vdiskData.push({label: vDiskPopupKeyset('label_storage-pool'), value: StoragePoolName});
}

if (SatisfactionRank && SatisfactionRank.FreshRank?.Flag !== EFlag.Green) {
vdiskData.push({
label: 'Fresh',
label: vDiskPopupKeyset('label_fresh'),
value: SatisfactionRank.FreshRank?.Flag,
});
}

if (SatisfactionRank && SatisfactionRank.LevelRank?.Flag !== EFlag.Green) {
vdiskData.push({
label: 'Level',
label: vDiskPopupKeyset('label_level'),
value: SatisfactionRank.LevelRank?.Flag,
});
}

if (SatisfactionRank && SatisfactionRank.FreshRank?.RankPercent) {
vdiskData.push({
label: 'Fresh',
label: vDiskPopupKeyset('label_fresh'),
value: SatisfactionRank.FreshRank.RankPercent,
});
}

if (SatisfactionRank && SatisfactionRank.LevelRank?.RankPercent) {
vdiskData.push({
label: 'Level',
label: vDiskPopupKeyset('label_level'),
value: SatisfactionRank.LevelRank.RankPercent,
});
}

if (DiskSpace && DiskSpace !== EFlag.Green) {
vdiskData.push({label: 'Space', value: DiskSpace});
vdiskData.push({label: vDiskPopupKeyset('label_space'), value: DiskSpace});
}

if (FrontQueues && FrontQueues !== EFlag.Green) {
vdiskData.push({label: 'FrontQueues', value: FrontQueues});
vdiskData.push({label: vDiskPopupKeyset('label_front-queues'), value: FrontQueues});
}

if (Replicated === false && VDiskState === EVDiskState.OK) {
vdiskData.push({label: 'Replicated', value: 'NO'});
vdiskData.push({label: vDiskPopupKeyset('label_replicated'), value: 'NO'});

// Only show replication progress and time remaining when disk is not replicated and state is OK
if (valueIsDefined(ReplicationProgress)) {
const progressPercent = Math.round(ReplicationProgress * 100);
vdiskData.push({
label: 'Progress',
label: vDiskPopupKeyset('label_progress'),
value: `${progressPercent}%`,
});
}
Expand All @@ -145,31 +155,34 @@ const prepareVDiskData = (data: PreparedVDisk, withDeveloperUILink?: boolean) =>
const timeRemaining = formatUptimeInSeconds(ReplicationSecondsRemaining);
if (timeRemaining) {
vdiskData.push({
label: 'Remaining',
label: vDiskPopupKeyset('label_remaining'),
value: timeRemaining,
});
}
}
}

if (UnsyncedVDisks) {
vdiskData.push({label: 'UnsyncVDisks', value: UnsyncedVDisks});
vdiskData.push({label: vDiskPopupKeyset('label_unsync-vdisks'), value: UnsyncedVDisks});
}

if (Number(AllocatedSize)) {
vdiskData.push({
label: 'Allocated',
label: vDiskPopupKeyset('label_allocated'),
value: bytesToGB(AllocatedSize),
});
}

if (Number(ReadThroughput)) {
vdiskData.push({label: 'Read', value: bytesToSpeed(ReadThroughput)});
vdiskData.push({
label: vDiskPopupKeyset('label_read'),
value: bytesToSpeed(ReadThroughput),
});
}

if (Number(WriteThroughput)) {
vdiskData.push({
label: 'Write',
label: vDiskPopupKeyset('label_write'),
value: bytesToSpeed(WriteThroughput),
});
}
Expand All @@ -191,7 +204,7 @@ const prepareVDiskData = (data: PreparedVDisk, withDeveloperUILink?: boolean) =>
const vDiskPagePath = getVDiskLink({VDiskSlotId, PDiskId, NodeId, StringifiedId});
if (vDiskPagePath) {
vdiskData.push({
label: 'Links',
label: vDiskPopupKeyset('label_links'),
value: (
<Flex wrap="wrap" gap={2}>
<LinkWithIcon
Expand Down Expand Up @@ -221,6 +234,7 @@ interface VDiskPopupProps {

export const VDiskPopup = ({data}: VDiskPopupProps) => {
const isFullData = isFullVDiskData(data);
const isViewerUser = useIsViewerUser();

const isUserAllowedToMakeChanges = useIsUserAllowedToMakeChanges();

Expand All @@ -247,7 +261,7 @@ export const VDiskPopup = ({data}: VDiskPopupProps) => {
const donors = data.Donors;
for (const donor of donors) {
donorsInfo.push({
label: 'VDisk',
label: vDiskPopupKeyset('label_vdisk'),
value: <InternalLink to={getVDiskLink(donor)}>{donor.StringifiedId}</InternalLink>,
});
}
Expand All @@ -257,7 +271,7 @@ export const VDiskPopup = ({data}: VDiskPopupProps) => {
<div className={b()}>
{data.DonorMode && <Label className={b('donor-label')}>Donor</Label>}
<InfoViewer title="VDisk" info={vdiskInfo} size="s" />
{pdiskInfo && <InfoViewer title="PDisk" info={pdiskInfo} size="s" />}
{pdiskInfo && isViewerUser && <InfoViewer title="PDisk" info={pdiskInfo} size="s" />}
{donorsInfo.length > 0 && <InfoViewer title="Donors" info={donorsInfo} size="s" />}
</div>
);
Expand Down
21 changes: 21 additions & 0 deletions src/components/VDiskPopup/i18n/en.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"context_not-available": "not available",
"label_state": "State",
"label_storage-pool": "StoragePool",
"label_node-id": "NodeId",
"label_pdisk-id": "PDiskId",
"label_vslot-id": "VSlotId",
"label_links": "Links",
"label_vdisk": "VDisk",
"label_fresh": "Fresh",
"label_level": "Level",
"label_space": "Space",
"label_front-queues": "FrontQueues",
"label_replicated": "Replicated",
"label_progress": "Progress",
"label_remaining": "Remaining",
"label_unsync-vdisks": "UnsyncVDisks",
"label_allocated": "Allocated",
"label_read": "Read",
"label_write": "Write"
}
7 changes: 7 additions & 0 deletions src/components/VDiskPopup/i18n/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {registerKeysets} from '../../../utils/i18n';

import en from './en.json';

const COMPONENT = 'ydb-vDisk-popup';

export const vDiskPopupKeyset = registerKeysets(COMPONENT, {en});
6 changes: 6 additions & 0 deletions src/components/nodesColumns/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,12 @@ export function isMonitoringUserNodesColumn(columnId: string): boolean {
return MONITORING_USER_COLUMNS_IDS.includes(columnId as NodesColumnId);
}

// Columns, that should displayed only for users with isViewerAllowed:true
const VIEWER_USER_COLUMNS_IDS: NodesColumnId[] = ['LoadAverage'];
export function isViewerUserNodesColumn(columnId: string): boolean {
return VIEWER_USER_COLUMNS_IDS.some((el) => el === columnId);
}

// 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 NODES_COLUMNS_TITLES = {
Expand Down
21 changes: 17 additions & 4 deletions src/containers/Nodes/Nodes.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import React from 'react';

import type {Column} from '../../components/PaginatedTable';
import {isMonitoringUserNodesColumn} from '../../components/nodesColumns/constants';
import {
isMonitoringUserNodesColumn,
isViewerUserNodesColumn,
} from '../../components/nodesColumns/constants';
import type {NodesColumnId} from '../../components/nodesColumns/constants';
import type {NodesPreparedEntity} from '../../store/reducers/nodes/types';
import type {AdditionalNodesProps} from '../../types/additionalProps';
import type {NodesGroupByField} from '../../types/api/nodes';
import {useIsUserAllowedToMakeChanges} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
import {
useIsUserAllowedToMakeChanges,
useIsViewerUser,
} from '../../utils/hooks/useIsUserAllowedToMakeChanges';

import {PaginatedNodes} from './PaginatedNodes';
import {getNodesColumns} from './columns/columns';
Expand Down Expand Up @@ -45,13 +51,20 @@ export function Nodes({
groupByParams = ALL_NODES_GROUP_BY_PARAMS,
}: NodesProps) {
const isUserAllowedToMakeChanges = useIsUserAllowedToMakeChanges();
const isViewerUser = useIsViewerUser();

const preparedColumns = React.useMemo(() => {
if (isUserAllowedToMakeChanges) {
return columns;
}
return columns.filter((column) => !isMonitoringUserNodesColumn(column.name));
}, [columns, isUserAllowedToMakeChanges]);
const filteredColumns = columns.filter(
(column) => !isMonitoringUserNodesColumn(column.name),
);
if (isViewerUser) {
return filteredColumns;
}
return filteredColumns.filter((column) => !isViewerUserNodesColumn(column.name));
}, [columns, isUserAllowedToMakeChanges, isViewerUser]);

return (
<PaginatedNodes
Expand Down
4 changes: 3 additions & 1 deletion src/containers/Nodes/NodesControls/NodesControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
} from '../../../store/reducers/capabilities/hooks';
import {useProblemFilter} from '../../../store/reducers/settings/hooks';
import type {NodesGroupByField} from '../../../types/api/nodes';
import {useIsViewerUser} from '../../../utils/hooks/useIsUserAllowedToMakeChanges';
import {PeerRoleFilter} from '../PeerRoleFilter/PeerRoleFilter';
import {getNodesGroupByOptions} from '../columns/constants';
import i18n from '../i18n';
Expand Down Expand Up @@ -58,12 +59,13 @@ export function NodesControls({
handleGroupByParamChange,
} = useNodesPageQueryParams(groupByParams);
const {problemFilter, handleProblemFilterChange} = useProblemFilter();
const isViewerUser = useIsViewerUser();

const systemStateGroupingAvailable = useViewerNodesHandlerHasGroupingBySystemState();
const groupByoptions = getNodesGroupByOptions(groupByParams, systemStateGroupingAvailable);

const networStatsAvailable = useViewerNodesHandlerHasNetworkStats();
const shouldDisplayPeerRoleFilter = withPeerRoleFilter && networStatsAvailable;
const shouldDisplayPeerRoleFilter = withPeerRoleFilter && networStatsAvailable && isViewerUser;

const handleGroupBySelectUpdate = (value: string[]) => {
handleGroupByParamChange(value[0]);
Expand Down
7 changes: 6 additions & 1 deletion src/containers/Nodes/useNodesPageQueryParams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {StringParam, useQueryParams} from 'use-query-params';

import {useViewerNodesHandlerHasGroupingBySystemState} from '../../store/reducers/capabilities/hooks';
import type {NodesGroupByField, NodesPeerRole} from '../../types/api/nodes';
import {useIsViewerUser} from '../../utils/hooks/useIsUserAllowedToMakeChanges';
import type {NodesUptimeFilterValues} from '../../utils/nodes';
import {nodesUptimeFilterValuesSchema} from '../../utils/nodes';

Expand All @@ -16,9 +17,13 @@ export function useNodesPageQueryParams(groupByParams: NodesGroupByField[] | und
nodesGroupBy: StringParam,
});

const isViewerUser = useIsViewerUser();

const uptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter);
const searchValue = queryParams.search ?? '';
const peerRoleFilter = parseNodesPeerRoleFilter(queryParams.peerRole);
const peerRoleFilter = isViewerUser
? parseNodesPeerRoleFilter(queryParams.peerRole)
: 'database';

const systemStateGroupingAvailable = useViewerNodesHandlerHasGroupingBySystemState();
const groupByParam = parseNodesGroupByParam(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,12 @@ export const DEFAULT_STORAGE_GROUPS_COLUMNS: StorageGroupsColumnId[] = [
'VDisks',
];

// Columns, that should displayed only for users with isViewerAllowed:true
const VIEWER_USER_COLUMNS_IDS: StorageGroupsColumnId[] = ['DiskSpace'];
export function isViewerGroupsColumn(columnId: string): boolean {
return VIEWER_USER_COLUMNS_IDS.some((el) => el === columnId);
}

export const REQUIRED_STORAGE_GROUPS_COLUMNS: StorageGroupsColumnId[] = ['GroupId'];

// This code is running when module is initialized and correct language may not be set yet
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import React from 'react';

import {VISIBLE_ENTITIES} from '../../../../store/reducers/storage/constants';
import {useIsUserAllowedToMakeChanges} from '../../../../utils/hooks/useIsUserAllowedToMakeChanges';
import {
useIsUserAllowedToMakeChanges,
useIsViewerUser,
} from '../../../../utils/hooks/useIsUserAllowedToMakeChanges';
import {useSelectedColumns} from '../../../../utils/hooks/useSelectedColumns';

import {getStorageGroupsColumns} from './columns';
Expand All @@ -12,6 +15,7 @@ import {
STORAGE_GROUPS_COLUMNS_TITLES,
STORAGE_GROUPS_SELECTED_COLUMNS_LS_KEY,
isMonitoringUserGroupsColumn,
isViewerGroupsColumn,
} from './constants';
import type {GetStorageGroupsColumnsParams} from './types';

Expand All @@ -20,15 +24,22 @@ export function useStorageGroupsSelectedColumns({
viewContext,
}: GetStorageGroupsColumnsParams) {
const isUserAllowedToMakeChanges = useIsUserAllowedToMakeChanges();
const isViewerUser = useIsViewerUser();

const columns = React.useMemo(() => {
const allColumns = getStorageGroupsColumns({viewContext});

if (isUserAllowedToMakeChanges) {
return allColumns;
}
return allColumns.filter((column) => !isMonitoringUserGroupsColumn(column.name));
}, [isUserAllowedToMakeChanges, viewContext]);
const filteredColumns = allColumns.filter(
(column) => !isMonitoringUserGroupsColumn(column.name),
);
if (isViewerUser) {
return filteredColumns;
}
return filteredColumns.filter((column) => !isViewerGroupsColumn(column.name));
}, [isUserAllowedToMakeChanges, viewContext, isViewerUser]);

const requiredColumns = React.useMemo(() => {
if (visibleEntities === VISIBLE_ENTITIES.missing) {
Expand Down
Loading
Loading