diff --git a/src/containers/Nodes/Nodes.tsx b/src/containers/Nodes/Nodes.tsx index 2c1cb8570..0ab2192c9 100644 --- a/src/containers/Nodes/Nodes.tsx +++ b/src/containers/Nodes/Nodes.tsx @@ -42,6 +42,8 @@ export interface NodesProps { parentRef: React.RefObject; additionalNodesProps?: AdditionalNodesProps; + withPeerRoleFilter?: boolean; + columns?: Column[]; defaultColumnsIds?: NodesColumnId[]; requiredColumnsIds?: NodesColumnId[]; @@ -54,6 +56,7 @@ export function Nodes({ database, parentRef, additionalNodesProps, + withPeerRoleFilter, columns = getNodesColumns({database, getNodeRef: additionalNodesProps?.getNodeRef}), defaultColumnsIds = DEFAULT_NODES_COLUMNS, requiredColumnsIds = REQUIRED_NODES_COLUMNS, @@ -92,6 +95,7 @@ export function Nodes({ path={path} database={database} parentRef={parentRef} + withPeerRoleFilter={withPeerRoleFilter} columns={columns} defaultColumnsIds={defaultColumnsIds} requiredColumnsIds={requiredColumnsIds} @@ -106,6 +110,7 @@ export function Nodes({ path={path} database={database} parentRef={parentRef} + withPeerRoleFilter={withPeerRoleFilter} columns={columns} defaultColumnsIds={defaultColumnsIds} requiredColumnsIds={requiredColumnsIds} @@ -123,6 +128,8 @@ interface NodesComponentProps { database?: string; parentRef: React.RefObject; + withPeerRoleFilter?: boolean; + columns: Column[]; defaultColumnsIds: NodesColumnId[]; requiredColumnsIds: NodesColumnId[]; @@ -134,13 +141,14 @@ function NodesComponent({ path, database, parentRef, + withPeerRoleFilter, columns, defaultColumnsIds, requiredColumnsIds, selectedColumnsKey, groupByParams, }: NodesComponentProps) { - const {searchValue, uptimeFilter} = useNodesPageQueryParams(groupByParams); + const {searchValue, uptimeFilter, peerRoleFilter} = useNodesPageQueryParams(groupByParams); const {problemFilter} = useProblemFilter(); const viewerNodesHandlerHasGrouping = useViewerNodesHandlerHasGrouping(); @@ -157,6 +165,7 @@ function NodesComponent({ void; @@ -31,6 +37,8 @@ export function NodesControls({ withGroupBySelect, groupByParams = [], + withPeerRoleFilter, + columnsToSelect, handleSelectedColumnsUpdate, @@ -41,10 +49,12 @@ export function NodesControls({ const { searchValue, uptimeFilter, + peerRoleFilter, groupByParam, handleSearchQueryChange, handleUptimeFilterChange, + handlePeerRoleFilterChange, handleGroupByParamChange, } = useNodesPageQueryParams(groupByParams); const {problemFilter, handleProblemFilterChange} = useProblemFilter(); @@ -52,6 +62,9 @@ export function NodesControls({ const systemStateGroupingAvailable = useViewerNodesHandlerHasGroupingBySystemState(); const groupByoptions = getNodesGroupByOptions(groupByParams, systemStateGroupingAvailable); + const networStatsAvailable = useViewerNodesHandlerHasNetworkStats(); + const shouldDisplayPeerRoleFilter = withPeerRoleFilter && networStatsAvailable; + const handleGroupBySelectUpdate = (value: string[]) => { handleGroupByParamChange(value[0]); }; @@ -70,6 +83,12 @@ export function NodesControls({ {withGroupBySelect ? null : ( )} + {shouldDisplayPeerRoleFilter ? ( + + {i18n('controls_peer-role-label')} + + + ) : null} { + const tableFilters: NodesFilters = React.useMemo(() => { return { path, database, searchValue, problemFilter, uptimeFilter, + peerRoleFilter, filterGroup, filterGroupBy, }; - }, [path, database, searchValue, problemFilter, uptimeFilter, filterGroup, filterGroupBy]); + }, [ + path, + database, + searchValue, + problemFilter, + uptimeFilter, + peerRoleFilter, + filterGroup, + filterGroupBy, + ]); const renderEmptyDataMessage = () => { if (problemFilter !== 'All' || uptimeFilter !== NodesUptimeFilterValues.All) { diff --git a/src/containers/Nodes/PeerRoleFilter/PeerRoleFilter.tsx b/src/containers/Nodes/PeerRoleFilter/PeerRoleFilter.tsx new file mode 100644 index 000000000..a7348ec24 --- /dev/null +++ b/src/containers/Nodes/PeerRoleFilter/PeerRoleFilter.tsx @@ -0,0 +1,24 @@ +import {RadioButton} from '@gravity-ui/uikit'; + +import type {NodesPeerRole} from '../../../types/api/nodes'; + +import {NODES_PEER_ROLES, NODES_PEER_ROLES_TITLES} from './utils'; + +interface PeerRoleFilterProps { + value?: NodesPeerRole; + onChange: (value: NodesPeerRole) => void; +} + +export function PeerRoleFilter({value = 'database', onChange}: PeerRoleFilterProps) { + return ( + + {NODES_PEER_ROLES.map((role) => { + return ( + + {NODES_PEER_ROLES_TITLES[role]} + + ); + })} + + ); +} diff --git a/src/containers/Nodes/PeerRoleFilter/utils.tsx b/src/containers/Nodes/PeerRoleFilter/utils.tsx new file mode 100644 index 000000000..cb31994cf --- /dev/null +++ b/src/containers/Nodes/PeerRoleFilter/utils.tsx @@ -0,0 +1,23 @@ +import type {NodesPeerRole} from '../../../types/api/nodes'; +import i18n from '../i18n'; + +export const NODES_PEER_ROLES: NodesPeerRole[] = ['database', 'static', 'other', 'any']; + +export const NODES_PEER_ROLES_TITLES: Record = { + get database() { + return i18n('database'); + }, + get static() { + return i18n('static'); + }, + get other() { + return i18n('other'); + }, + get any() { + return i18n('any'); + }, +}; + +export function parseNodesPeerRoleFilter(paramToParse: unknown): NodesPeerRole | undefined { + return NODES_PEER_ROLES.find((peerRoleParam) => peerRoleParam === paramToParse); +} diff --git a/src/containers/Nodes/getNodes.ts b/src/containers/Nodes/getNodes.ts index a1906208e..694db7e86 100644 --- a/src/containers/Nodes/getNodes.ts +++ b/src/containers/Nodes/getNodes.ts @@ -27,8 +27,16 @@ export const getNodes: FetchData< } = params; const {sortOrder, columnId} = sortParams ?? {}; - const {path, database, searchValue, problemFilter, uptimeFilter, filterGroup, filterGroupBy} = - filters ?? {}; + const { + path, + database, + searchValue, + problemFilter, + uptimeFilter, + peerRoleFilter, + filterGroup, + filterGroupBy, + } = filters ?? {}; const sortField = getNodesColumnSortField(columnId); const sort = sortField ? prepareSortValue(sortField, sortOrder) : undefined; @@ -47,6 +55,7 @@ export const getNodes: FetchData< filter: searchValue, problems_only: getProblemParamValue(problemFilter), uptime: getUptimeParamValue(uptimeFilter), + filter_peer_role: peerRoleFilter, filter_group: filterGroup, filter_group_by: filterGroupBy, fieldsRequired: dataFieldsRequired, diff --git a/src/containers/Nodes/i18n/en.json b/src/containers/Nodes/i18n/en.json index 2499e177b..8bfccdc21 100644 --- a/src/containers/Nodes/i18n/en.json +++ b/src/containers/Nodes/i18n/en.json @@ -6,5 +6,12 @@ "no-nodes-groups": "No nodes groups", "controls_search-placeholder": "Host name", - "controls_group-by-placeholder": "Group by:" + "controls_group-by-placeholder": "Group by:", + + "controls_peer-role-label": "Peer role:", + + "database": "database", + "static": "static", + "other": "other", + "any": "any" } diff --git a/src/containers/Nodes/useNodesPageQueryParams.ts b/src/containers/Nodes/useNodesPageQueryParams.ts index ff824efa6..b06f90399 100644 --- a/src/containers/Nodes/useNodesPageQueryParams.ts +++ b/src/containers/Nodes/useNodesPageQueryParams.ts @@ -1,21 +1,24 @@ import {StringParam, useQueryParams} from 'use-query-params'; import {useViewerNodesHandlerHasGroupingBySystemState} from '../../store/reducers/capabilities/hooks'; -import type {NodesGroupByField} from '../../types/api/nodes'; +import type {NodesGroupByField, NodesPeerRole} from '../../types/api/nodes'; import type {NodesUptimeFilterValues} from '../../utils/nodes'; import {nodesUptimeFilterValuesSchema} from '../../utils/nodes'; +import {parseNodesPeerRoleFilter} from './PeerRoleFilter/utils'; import {parseNodesGroupByParam} from './columns/constants'; export function useNodesPageQueryParams(groupByParams: NodesGroupByField[] | undefined) { const [queryParams, setQueryParams] = useQueryParams({ uptimeFilter: StringParam, + peerRole: StringParam, search: StringParam, nodesGroupBy: StringParam, }); const uptimeFilter = nodesUptimeFilterValuesSchema.parse(queryParams.uptimeFilter); const searchValue = queryParams.search ?? ''; + const peerRoleFilter = parseNodesPeerRoleFilter(queryParams.peerRole); const systemStateGroupingAvailable = useViewerNodesHandlerHasGroupingBySystemState(); const groupByParam = parseNodesGroupByParam( @@ -30,6 +33,9 @@ export function useNodesPageQueryParams(groupByParams: NodesGroupByField[] | und const handleUptimeFilterChange = (value: NodesUptimeFilterValues) => { setQueryParams({uptimeFilter: value}, 'replaceIn'); }; + const handlePeerRoleFilterChange = (value: NodesPeerRole) => { + setQueryParams({peerRole: value}, 'replaceIn'); + }; const handleGroupByParamChange = (value: string) => { setQueryParams({nodesGroupBy: value}, 'replaceIn'); }; @@ -37,10 +43,12 @@ export function useNodesPageQueryParams(groupByParams: NodesGroupByField[] | und return { uptimeFilter, searchValue, + peerRoleFilter, groupByParam, handleSearchQueryChange, handleUptimeFilterChange, + handlePeerRoleFilterChange, handleGroupByParamChange, }; } diff --git a/src/containers/Tenant/Diagnostics/Network/NetworkWrapper.tsx b/src/containers/Tenant/Diagnostics/Network/NetworkWrapper.tsx index 673ea8a5b..b31ffc12e 100644 --- a/src/containers/Tenant/Diagnostics/Network/NetworkWrapper.tsx +++ b/src/containers/Tenant/Diagnostics/Network/NetworkWrapper.tsx @@ -41,6 +41,7 @@ export function NetworkWrapper({ path={path} database={database} parentRef={parentRef} + withPeerRoleFilter additionalNodesProps={additionalNodesProps} columns={getNetworkTableNodesColumns({ database: database, diff --git a/src/store/reducers/capabilities/hooks.ts b/src/store/reducers/capabilities/hooks.ts index 86288a619..cafdfdda7 100644 --- a/src/store/reducers/capabilities/hooks.ts +++ b/src/store/reducers/capabilities/hooks.ts @@ -63,7 +63,7 @@ export const useViewerNodesHandlerHasGroupingBySystemState = () => { }; export const useViewerNodesHandlerHasNetworkStats = () => { - return useGetFeatureVersion('/viewer/nodes') > 12; + return useGetFeatureVersion('/viewer/nodes') > 13; }; export const useFeatureFlagsAvailable = () => { diff --git a/src/store/reducers/nodes/types.ts b/src/store/reducers/nodes/types.ts index de73fd410..92176d80d 100644 --- a/src/store/reducers/nodes/types.ts +++ b/src/store/reducers/nodes/types.ts @@ -3,6 +3,7 @@ import type {OrderType} from '@gravity-ui/react-data-table'; import type {EFlag} from '../../../types/api/enums'; import type { NodesGroupByField, + NodesPeerRole, NodesSortValue, TEndpoint, TPoolStats, @@ -58,6 +59,7 @@ export interface NodesFilters { searchValue: string; problemFilter: ProblemFilterValue; uptimeFilter: NodesUptimeFilterValues; + peerRoleFilter?: NodesPeerRole; path?: string; database?: string; diff --git a/src/types/api/nodes.ts b/src/types/api/nodes.ts index 9b8115fb2..af800716d 100644 --- a/src/types/api/nodes.ts +++ b/src/types/api/nodes.ts @@ -233,6 +233,9 @@ type NodesType = | 'storage' // v6 | 'any'; +// v14 +export type NodesPeerRole = 'database' | 'static' | 'other' | 'any'; + type NodesWithFilter = 'space' | 'missing' | 'all'; // v6 @@ -330,6 +333,7 @@ export interface NodesRequestParams { problems_only?: boolean; /** filter nodes by id or host */ filter?: string; + filter_peer_role?: NodesPeerRole; // v14 sort?: NodesSort;