11import type { FC } from 'react' ;
2- import { useMemo , useCallback , useEffect , Suspense } from 'react' ;
3- import { Button , ButtonVariant } from '@patternfly/react-core' ;
2+ import { useRef , useMemo , useCallback , useEffect , Suspense } from 'react' ;
3+ import { Button , ButtonVariant , Tooltip } from '@patternfly/react-core' ;
44import { DataViewCheckboxFilter } from '@patternfly/react-data-view' ;
55import type { DataViewFilterOption } from '@patternfly/react-data-view/dist/esm/DataViewFilters' ;
66import * as _ from 'lodash' ;
@@ -96,7 +96,7 @@ import { nodeStatus } from '../../status';
9696import { getNodeClientCSRs , isCSRResource } from './csr' ;
9797import GroupsEditorModal from './modals/GroupsEditorModal' ;
9898import NodeUptime from './node-dashboard/NodeUptime' ;
99- import { getNodeGroups } from './NodeGroupUtils' ;
99+ import { getExistingGroups , getNodeGroups } from './NodeGroupUtils' ;
100100import NodeRoles from './NodeRoles' ;
101101import { NodeStatusWithExtensions } from './NodeStatus' ;
102102import {
@@ -702,6 +702,14 @@ const NodeList: FC<NodeListProps> = ({
702702 [ ] ,
703703 ) ;
704704
705+ const nodeGroupFilterOptions = useMemo < DataViewFilterOption [ ] > ( ( ) => {
706+ const groupNames = getExistingGroups ( data as NodeKind [ ] ) ;
707+ return groupNames . map ( ( groupName ) => ( {
708+ value : groupName ,
709+ label : groupName ,
710+ } ) ) ;
711+ } , [ data ] ) ;
712+
705713 const machineSetFilterOptions = useMemo < DataViewFilterOption [ ] > (
706714 ( ) =>
707715 [
@@ -733,6 +741,7 @@ const NodeList: FC<NodeListProps> = ({
733741 ...initialFiltersDefault ,
734742 status : [ ] ,
735743 roles : [ ] ,
744+ groups : [ ] ,
736745 architecture : [ ] ,
737746 machineOwners : [ ] ,
738747 machineConfigPools : [ ] ,
@@ -757,6 +766,17 @@ const NodeList: FC<NodeListProps> = ({
757766 placeholder = { t ( 'console-app~Filter by roles' ) }
758767 options = { nodeRoleFilterOptions }
759768 /> ,
769+ ...( nodeMgmtV1Enabled
770+ ? [
771+ < DataViewCheckboxFilter
772+ key = "groups"
773+ filterId = "groups"
774+ title = { t ( 'console-app~Groups' ) }
775+ placeholder = { t ( 'console-app~Filter by groups' ) }
776+ options = { nodeGroupFilterOptions }
777+ /> ,
778+ ]
779+ : [ ] ) ,
760780 < DataViewCheckboxFilter
761781 key = "architecture"
762782 filterId = "architecture"
@@ -783,9 +803,11 @@ const NodeList: FC<NodeListProps> = ({
783803 t ,
784804 nodeStatusFilterOptions ,
785805 nodeRoleFilterOptions ,
806+ nodeGroupFilterOptions ,
786807 nodeArchitectureFilterOptions ,
787808 machineSetFilterOptions ,
788809 machineConfigPoolFilterOptions ,
810+ nodeMgmtV1Enabled ,
789811 ] ,
790812 ) ;
791813
@@ -811,6 +833,17 @@ const NodeList: FC<NodeListProps> = ({
811833 }
812834 }
813835
836+ // Groups filter
837+ if ( filters . groups . length > 0 ) {
838+ if ( isCSR ) {
839+ return false ;
840+ }
841+ const nodeGroups = getNodeGroups ( resource as NodeKind ) ;
842+ if ( ! filters . groups . some ( ( r ) => nodeGroups . includes ( r ) ) ) {
843+ return false ;
844+ }
845+ }
846+
814847 // Architecture filter
815848 if ( filters . architecture . length > 0 ) {
816849 if ( isCSR ) {
@@ -881,6 +914,7 @@ type NodeRowItem = (NodeKind | NodeCertificateSigningRequestKind) & {
881914type NodeFilters = ResourceFilters & {
882915 status : string [ ] ;
883916 roles : string [ ] ;
917+ groups : string [ ] ;
884918 architecture : string [ ] ;
885919 machineOwners : string [ ] ;
886920 machineConfigPools : string [ ] ;
@@ -911,6 +945,7 @@ export const NodesPage: FC<NodesPageProps> = ({ selector }) => {
911945 const { t } = useTranslation ( ) ;
912946 const launchOverlay = useOverlay ( ) ;
913947 const nodeMgmtV1Enabled = useFlag ( FLAG_NODE_MGMT_V1 ) ;
948+ const editGroupButtonRef = useRef < HTMLDivElement > ( null ) ;
914949
915950 const [ selectedColumns , , columnPreferenceLoaded ] = useUserPreference < TableColumnsType > (
916951 COLUMN_MANAGEMENT_USER_PREFERENCE_KEY ,
@@ -1047,13 +1082,22 @@ export const NodesPage: FC<NodesPageProps> = ({ selector }) => {
10471082 return (
10481083 < >
10491084 < ListPageHeader title = { t ( 'public~Nodes' ) } >
1050- { nodeMgmtV1Enabled && ! isEditLoading && canEdit ? (
1051- < Button
1052- variant = { ButtonVariant . secondary }
1053- onClick = { ( ) => launchOverlay ( GroupsEditorModal , { } ) }
1054- >
1055- { t ( 'console-app~Edit groups' ) }
1056- </ Button >
1085+ { nodeMgmtV1Enabled ? (
1086+ < >
1087+ < span ref = { ! isEditLoading && ! canEdit ? editGroupButtonRef : undefined } >
1088+ < Button
1089+ variant = { ButtonVariant . secondary }
1090+ onClick = { ( ) => launchOverlay ( GroupsEditorModal , { } ) }
1091+ isDisabled = { isEditLoading || ! canEdit }
1092+ >
1093+ { t ( 'console-app~Edit groups' ) }
1094+ </ Button >
1095+ </ span >
1096+ < Tooltip
1097+ triggerRef = { editGroupButtonRef }
1098+ content = { t ( 'console-app~You do not have permission to edit groups.' ) }
1099+ />
1100+ </ >
10571101 ) : null }
10581102 </ ListPageHeader >
10591103 < ListPageBody >
0 commit comments