@@ -11,6 +11,8 @@ import {
1111 DragDrop ,
1212 Draggable ,
1313 Droppable ,
14+ Flex ,
15+ FlexItem ,
1416 Text ,
1517 TextContent ,
1618 TextVariants ,
@@ -24,6 +26,8 @@ import { Column, ColumnSizeMap, getDefaultColumns, getFullColumnName } from '../
2426import './columns-modal.css' ;
2527import Modal from './modal' ;
2628
29+ export const COLUMN_FILTER_KEYS = [ 'source' , 'destination' , 'time' , 'host' , 'namespace' , 'owner' , 'ip' , 'dns' ] ;
30+
2731export const ColumnsModal : React . FC < {
2832 isModalOpen : boolean ;
2933 setModalOpen : ( v : boolean ) => void ;
@@ -35,29 +39,22 @@ export const ColumnsModal: React.FC<{
3539} > = ( { id, config, isModalOpen, setModalOpen, columns, setColumns, setColumnSizes } ) => {
3640 const [ resetClicked , setResetClicked ] = React . useState < boolean > ( false ) ;
3741 const [ updatedColumns , setUpdatedColumns ] = React . useState < Column [ ] > ( [ ] ) ;
38- const [ isSaveDisabled , setSaveDisabled ] = React . useState < boolean > ( true ) ;
39- const [ isAllSelected , setAllSelected ] = React . useState < boolean > ( false ) ;
42+ const [ filterKeys , setFilterKeys ] = React . useState < string [ ] > ( [ ] ) ;
4043 const { t } = useTranslation ( 'plugin__netobserv-plugin' ) ;
4144
45+ React . useEffect ( ( ) => {
46+ if ( isModalOpen ) {
47+ setFilterKeys ( [ ] ) ;
48+ }
49+ } , [ isModalOpen ] ) ;
50+
4251 React . useEffect ( ( ) => {
4352 if ( ! isModalOpen || _ . isEmpty ( updatedColumns ) ) {
4453 setUpdatedColumns ( _ . cloneDeep ( columns ) ) ;
4554 }
4655 // eslint-disable-next-line react-hooks/exhaustive-deps
4756 } , [ columns , isModalOpen ] ) ;
4857
49- React . useEffect ( ( ) => {
50- let allSelected = true ;
51- _ . forEach ( updatedColumns , ( col : Column ) => {
52- if ( ! col . isSelected ) {
53- allSelected = false ;
54- return false ;
55- }
56- } ) ;
57- setAllSelected ( allSelected ) ;
58- setSaveDisabled ( _ . isEmpty ( updatedColumns . filter ( col => col . isSelected ) ) ) ;
59- } , [ updatedColumns ] ) ;
60-
6158 const onDrop = React . useCallback (
6259 ( source , dest ) => {
6360 if ( dest ) {
@@ -91,13 +88,49 @@ export const ColumnsModal: React.FC<{
9188 setUpdatedColumns ( getDefaultColumns ( config . columns ) . filter ( c => columns . some ( existing => existing . id === c . id ) ) ) ;
9289 } , [ columns , config . columns ] ) ;
9390
91+ const isSaveDisabled = React . useCallback ( ( ) => {
92+ return _ . isEmpty ( updatedColumns . filter ( c => c . isSelected ) ) ;
93+ } , [ updatedColumns ] ) ;
94+
95+ const isFilteredColumn = React . useCallback ( ( c : Column , fks : string [ ] ) => {
96+ return (
97+ _ . isEmpty ( fks ) ||
98+ _ . reduce (
99+ fks ,
100+ ( acc , fk ) =>
101+ ( acc =
102+ acc &&
103+ ( c . id . toLowerCase ( ) . includes ( fk ) ||
104+ c . name . toLowerCase ( ) . includes ( fk ) ||
105+ c . group ?. toLowerCase ( ) . includes ( fk ) ||
106+ false ) ) ,
107+ true
108+ )
109+ ) ;
110+ } , [ ] ) ;
111+
112+ const getColumnFilterKeys = React . useCallback ( ( ) => {
113+ return COLUMN_FILTER_KEYS . filter ( fk => columns . some ( c => isFilteredColumn ( c , [ fk ] ) ) ) ;
114+ } , [ columns , isFilteredColumn ] ) ;
115+
116+ const filteredColumns = React . useCallback ( ( ) => {
117+ return updatedColumns . filter ( c => isFilteredColumn ( c , filterKeys ) ) ;
118+ } , [ filterKeys , isFilteredColumn , updatedColumns ] ) ;
119+
120+ const isAllSelected = React . useCallback ( ( ) => {
121+ return _ . reduce ( filteredColumns ( ) , ( acc , c ) => ( acc = acc && c . isSelected ) , true ) ;
122+ } , [ filteredColumns ] ) ;
123+
94124 const onSelectAll = React . useCallback ( ( ) => {
125+ const allSelected = isAllSelected ( ) ;
95126 const result = [ ...updatedColumns ] ;
96- _ . forEach ( result , ( col : Column ) => {
97- col . isSelected = ! isAllSelected ;
127+ _ . forEach ( result , ( c : Column ) => {
128+ if ( isFilteredColumn ( c , filterKeys ) ) {
129+ c . isSelected = ! allSelected ;
130+ }
98131 } ) ;
99132 setUpdatedColumns ( result ) ;
100- } , [ updatedColumns , setUpdatedColumns , isAllSelected ] ) ;
133+ } , [ isAllSelected , updatedColumns , isFilteredColumn , filterKeys ] ) ;
101134
102135 const onClose = React . useCallback ( ( ) => {
103136 setResetClicked ( false ) ;
@@ -113,7 +146,18 @@ export const ColumnsModal: React.FC<{
113146 onClose ( ) ;
114147 } , [ resetClicked , setColumns , updatedColumns , onClose , setColumnSizes ] ) ;
115148
116- const draggableItems = updatedColumns . map ( ( column , i ) => (
149+ const toggleChip = React . useCallback (
150+ ( key : string ) => {
151+ if ( filterKeys . includes ( key ) ) {
152+ setFilterKeys ( filterKeys . filter ( k => k !== key ) ) ;
153+ } else {
154+ setFilterKeys ( COLUMN_FILTER_KEYS . filter ( f => f === key || filterKeys . includes ( f ) ) ) ;
155+ }
156+ } ,
157+ [ filterKeys ]
158+ ) ;
159+
160+ const draggableItems = filteredColumns ( ) . map ( ( column , i ) => (
117161 < Draggable key = { i } hasNoWrapper >
118162 < DataListItem
119163 key = { 'data-list-item-' + i }
@@ -153,15 +197,46 @@ export const ColumnsModal: React.FC<{
153197 scrollable = { true }
154198 onClose = { onClose }
155199 description = {
156- < TextContent >
157- < Text component = { TextVariants . p } >
158- { t ( 'Selected columns will appear in the table.' ) }
159- { t ( 'Click and drag the items to reorder the columns in the table.' ) }
160- </ Text >
161- < Button isInline onClick = { onSelectAll } variant = "link" >
162- { isAllSelected ? t ( 'Unselect all' ) : t ( 'Select all' ) }
163- </ Button >
164- </ TextContent >
200+ < >
201+ < TextContent >
202+ < Text component = { TextVariants . p } >
203+ { t ( 'Selected columns will appear in the table.' ) }
204+ { t ( 'Click and drag the items to reorder the columns in the table.' ) }
205+ </ Text >
206+ </ TextContent >
207+ < Flex className = "popup-header-margin" >
208+ < FlexItem flex = { { default : 'flex_4' } } >
209+ < Flex className = "flex-gap" >
210+ { getColumnFilterKeys ( ) . map ( key => {
211+ return (
212+ < FlexItem
213+ key = { key }
214+ onClick = { ( ) => toggleChip ( key ) }
215+ className = { `custom-chip ${
216+ filterKeys . includes ( key ) ? 'selected' : 'unselected'
217+ } buttonless gap pointer`}
218+ >
219+ < Text component = { TextVariants . p } > { key } </ Text >
220+ </ FlexItem >
221+ ) ;
222+ } ) }
223+ </ Flex >
224+ </ FlexItem >
225+ < FlexItem flex = { { default : 'flex_1' } } className = "flex-center" >
226+ { _ . isEmpty ( filteredColumns ( ) ) ? (
227+ < Button isInline onClick = { ( ) => setFilterKeys ( [ ] ) } variant = "link" >
228+ { t ( 'Clear filters' ) }
229+ </ Button >
230+ ) : (
231+ < Button isInline onClick = { onSelectAll } variant = "link" >
232+ { `${ isAllSelected ( ) ? t ( 'Unselect all' ) : t ( 'Select all' ) } ${
233+ ! _ . isEmpty ( filterKeys ) ? ' ' + filterKeys . join ( ',' ) : ''
234+ } `}
235+ </ Button >
236+ ) }
237+ </ FlexItem >
238+ </ Flex >
239+ </ >
165240 }
166241 footer = {
167242 < div className = "footer" >
@@ -171,10 +246,10 @@ export const ColumnsModal: React.FC<{
171246 < Button data-test = "columns-cancel-button" key = "cancel" variant = "link" onClick = { ( ) => onClose ( ) } >
172247 { t ( 'Cancel' ) }
173248 </ Button >
174- < Tooltip content = { t ( 'At least one column must be selected' ) } trigger = "" isVisible = { isSaveDisabled } >
249+ < Tooltip content = { t ( 'At least one column must be selected' ) } trigger = "" isVisible = { isSaveDisabled ( ) } >
175250 < Button
176251 data-test = "columns-save-button"
177- isDisabled = { isSaveDisabled }
252+ isDisabled = { isSaveDisabled ( ) }
178253 key = "confirm"
179254 variant = "primary"
180255 onClick = { ( ) => onSave ( ) }
0 commit comments