@@ -19,6 +19,7 @@ import {
1919import { ResourceLink } from '@openshift-console/dynamic-plugin-sdk' ;
2020import { ErrorState } from '@patternfly/react-component-groups' ;
2121import { EmptyState , EmptyStateBody } from '@patternfly/react-core' ;
22+ import type { DataViewTd } from '@patternfly/react-data-view/dist/esm/DataViewTable' ;
2223import { DataViewTh , DataViewTr } from '@patternfly/react-data-view/dist/esm/DataViewTable' ;
2324import { CubesIcon } from '@patternfly/react-icons' ;
2425import { ThProps } from '@patternfly/react-table' ;
@@ -30,13 +31,27 @@ import {
3031 ShowOperandsInAllNamespacesRadioGroup ,
3132 useShowOperandsInAllNamespaces ,
3233} from '../shared/AllNamespaces' ;
34+ import {
35+ type GitOpsManagedColumn ,
36+ NAMESPACE_COLUMN_ID ,
37+ useGitOpsColumnManagement ,
38+ } from '../shared/ColumnManagement' ;
3339import {
3440 GitOpsDataViewTable ,
3541 useGitOpsDataViewSort ,
3642 useGitOpsListPagePagination ,
3743} from '../shared/DataView' ;
38- import { filterByConsoleNameAndLabels , getLabelsSortKey , parseLabelFilterParam } from '../shared/listPageTextFilters' ;
44+ import { GitOpsListPageToolbar } from '../shared/GitOpsListPageToolbar' ;
45+ import {
46+ filterByConsoleNameAndLabels ,
47+ getLabelsSortKey ,
48+ parseLabelFilterParam ,
49+ } from '../shared/listPageTextFilters' ;
3950import { MetadataLabels } from '../shared/MetadataLabels/MetadataLabels' ;
51+ import {
52+ getProjectManagedColumns ,
53+ PROJECT_LIST_COLUMN_MANAGEMENT_ID ,
54+ } from '../shared/projectListColumns' ;
4055
4156import { useProjectActionsProvider } from './hooks/useProjectActionsProvider' ;
4257
@@ -83,17 +98,23 @@ const ProjectList: React.FC<ProjectListTabProps> = ({
8398 namespace,
8499 } ) ;
85100
86- const columnSortConfig = React . useMemo ( ( ) => {
87- return [
88- 'name' ,
89- ...( ! listAllNamespaces || ! namespace || namespace === '' ? [ 'namespace' ] : [ ] ) ,
90- 'description' ,
91- 'applications' ,
92- 'labels' ,
93- 'last-updated' ,
94- 'actions' ,
95- ] . map ( ( key ) => ( { key } ) ) ;
96- } , [ listAllNamespaces , namespace ] ) ;
101+ const { t } = useTranslation ( 'plugin__gitops-plugin' ) ;
102+ const includeNamespaceColumn = ! namespace || namespace === '' ;
103+ const managedColumns = React . useMemo ( ( ) => getProjectManagedColumns ( true , t ) , [ t ] ) ;
104+
105+ const { activeColumnIds, columnManagement, filterDataView } = useGitOpsColumnManagement ( {
106+ columnManagementID : PROJECT_LIST_COLUMN_MANAGEMENT_ID ,
107+ columns : managedColumns ,
108+ resourceType : t ( 'AppProjects' ) ,
109+ includeNamespaceColumn,
110+ showNamespaceHelp : includeNamespaceColumn ,
111+ } ) ;
112+
113+ const columnSortConfig = React . useMemo (
114+ ( ) =>
115+ managedColumns . filter ( ( column ) => ! column . alwaysShown ) . map ( ( column ) => ( { key : column . id } ) ) ,
116+ [ managedColumns ] ,
117+ ) ;
97118
98119 const { searchParams, sortBy, direction, getSortParams } =
99120 useGitOpsDataViewSort ( columnSortConfig ) ;
@@ -103,9 +124,7 @@ const ProjectList: React.FC<ProjectListTabProps> = ({
103124 const nameQuery = searchParams . get ( 'name' ) || '' ;
104125 const labelsParam = searchParams . get ( 'labels' ) || '' ;
105126
106- const { t } = useTranslation ( 'plugin__gitops-plugin' ) ;
107-
108- const columnsDV = useColumnsDV ( namespace , getSortParams ) ;
127+ const columnsDV = useColumnsDV ( managedColumns , getSortParams , columnSortConfig ) ;
109128 const sortedProjects = React . useMemo ( ( ) => {
110129 return sortData ( appProjects as AppProjectKind [ ] , sortBy , direction , applications , appsLoaded ) ;
111130 } , [ appProjects , sortBy , direction , applications , appsLoaded ] ) ;
@@ -149,8 +168,15 @@ const ProjectList: React.FC<ProjectListTabProps> = ({
149168 namespace,
150169 searchParams,
151170 } ) ;
152- const rows = useProjectsRowsDV ( pagedItems , namespace , applications , appsLoaded ) ;
153- const showNamespaceColumn = ! namespace || namespace === '' ;
171+ const rows = useProjectsRowsDV ( pagedItems , managedColumns , applications , appsLoaded ) ;
172+ const columnIds = React . useMemo (
173+ ( ) => managedColumns . map ( ( column ) => column . id ) ,
174+ [ managedColumns ] ,
175+ ) ;
176+ const { columns : visibleColumnsDV , rows : visibleRows } = React . useMemo (
177+ ( ) => filterDataView ( columnsDV , rows , columnIds , activeColumnIds ) ,
178+ [ filterDataView , columnsDV , rows , columnIds , activeColumnIds ] ,
179+ ) ;
154180
155181 // Check if there are projects initially (before search)
156182 const hasProjects = React . useMemo ( ( ) => {
@@ -176,7 +202,7 @@ const ProjectList: React.FC<ProjectListTabProps> = ({
176202 const empty = (
177203 < Tbody >
178204 < Tr key = "loading" ouiaId = "table-tr-loading" >
179- < Td colSpan = { columnsDV . length } >
205+ < Td colSpan = { visibleColumnsDV . length || columnsDV . length } >
180206 < EmptyState
181207 headingLevel = "h4"
182208 icon = { CubesIcon }
@@ -193,7 +219,7 @@ const ProjectList: React.FC<ProjectListTabProps> = ({
193219 const error = loadError && (
194220 < Tbody >
195221 < Tr key = "loading" ouiaId = { 'table-tr-loading' } >
196- < Td colSpan = { columnsDV . length } >
222+ < Td colSpan = { visibleColumnsDV . length || columnsDV . length } >
197223 < ErrorState
198224 titleText = { t ( 'Unable to load data' ) }
199225 bodyText = { t (
@@ -204,7 +230,17 @@ const ProjectList: React.FC<ProjectListTabProps> = ({
204230 </ Tr >
205231 </ Tbody >
206232 ) ;
207- const isEmptyState = ! loadError && rows . length === 0 ;
233+ const isEmptyState = ! loadError && visibleRows . length === 0 ;
234+
235+ const listPageFilter = ! hideNameLabelFilters && hasProjects && (
236+ < ListPageFilter
237+ data = { data }
238+ loaded = { loaded }
239+ rowFilters = { filters }
240+ onFilterChange = { onFilterChange }
241+ nameFilterPlaceholder = { t ( 'Search by name...' ) }
242+ />
243+ ) ;
208244
209245 return (
210246 < div >
@@ -224,25 +260,19 @@ const ProjectList: React.FC<ProjectListTabProps> = ({
224260 </ ListPageHeader >
225261 ) }
226262 < ListPageBody >
227- { ! hideNameLabelFilters && hasProjects && (
228- < ListPageFilter
229- data = { data }
230- loaded = { loaded }
231- rowFilters = { filters }
232- onFilterChange = { onFilterChange }
233- nameFilterPlaceholder = { t ( 'Search by name...' ) }
234- />
263+ { hasProjects && (
264+ < GitOpsListPageToolbar filters = { listPageFilter } columnManagement = { columnManagement } />
235265 ) }
236266 < div
237267 className = {
238- showNamespaceColumn
268+ includeNamespaceColumn
239269 ? 'gitops-project-list gitops-project-list--with-namespace'
240270 : 'gitops-project-list'
241271 }
242272 >
243273 < GitOpsDataViewTable
244- columns = { columnsDV }
245- rows = { rows }
274+ columns = { visibleColumnsDV }
275+ rows = { visibleRows }
246276 isEmpty = { isEmptyState }
247277 emptyState = { empty }
248278 isError = { ! ! loadError }
@@ -390,82 +420,67 @@ export const sortData = (
390420 } ) ;
391421} ;
392422
393- const sortableHeaderProps = (
394- ariaLabel : string ,
395- className : string ,
396- sort : ThProps [ 'sort' ] ,
397- ) : ThProps => ( {
398- 'aria-label' : ariaLabel ,
399- className,
400- sort,
401- tooltip : '' ,
402- } ) ;
403-
404423export const useColumnsDV = (
405- namespace : string | undefined ,
424+ managedColumns : GitOpsManagedColumn [ ] ,
406425 getSortParams : ( columnIndex : number ) => ThProps [ 'sort' ] ,
426+ columnSortConfig : { key : string } [ ] ,
407427) : DataViewTh [ ] => {
408- const showNamespace = ! namespace || namespace === '' ;
409- const i : number = showNamespace ? 1 : 0 ;
410428 const { t } = useTranslation ( 'plugin__gitops-plugin' ) ;
411- const columns : DataViewTh [ ] = [
412- {
413- cell : t ( 'Name' ) ,
414- props : sortableHeaderProps ( 'name' , 'pf-m-width-20' , getSortParams ( 0 ) ) ,
415- } ,
416- ...( showNamespace
417- ? [
418- {
419- cell : t ( 'Namespace' ) ,
420- props : sortableHeaderProps ( 'namespace' , 'pf-m-width-15' , getSortParams ( 1 ) ) ,
421- } ,
422- ]
423- : [ ] ) ,
424- {
425- cell : t ( 'Description' ) ,
426- props : sortableHeaderProps ( 'description' , 'pf-m-width-10' , getSortParams ( 1 + i ) ) ,
427- } ,
428- {
429- cell : t ( 'Applications' ) ,
430- props : sortableHeaderProps ( 'applications' , 'pf-m-width-15' , getSortParams ( 2 + i ) ) ,
431- } ,
432- {
433- cell : t ( 'Labels' ) ,
434- props : sortableHeaderProps ( 'labels' , 'pf-m-width-20' , getSortParams ( 3 + i ) ) ,
435- } ,
436- {
437- cell : t ( 'Last Updated' ) ,
438- props : sortableHeaderProps (
439- 'last updated' ,
440- 'pf-m-width-15' ,
441- getSortParams ( showNamespace ? 5 : 4 ) ,
442- ) ,
443- } ,
444- {
445- cell : '' ,
446- props : { 'aria-label' : 'actions' } ,
447- } ,
448- ] ;
449429
450- return columns ;
430+ const titleById : Record < string , string > = {
431+ name : t ( 'Name' ) ,
432+ [ NAMESPACE_COLUMN_ID ] : t ( 'Namespace' ) ,
433+ description : t ( 'Description' ) ,
434+ applications : t ( 'Applications' ) ,
435+ labels : t ( 'Labels' ) ,
436+ 'last-updated' : t ( 'Last Updated' ) ,
437+ actions : '' ,
438+ } ;
439+
440+ const widthById : Record < string , string > = {
441+ name : 'pf-m-width-20' ,
442+ [ NAMESPACE_COLUMN_ID ] : 'pf-m-width-15' ,
443+ description : 'pf-m-width-10' ,
444+ applications : 'pf-m-width-15' ,
445+ labels : 'pf-m-width-20' ,
446+ 'last-updated' : 'pf-m-width-15' ,
447+ } ;
448+
449+ return managedColumns . map ( ( column ) => {
450+ if ( column . id === 'actions' ) {
451+ return {
452+ cell : '' ,
453+ props : { 'aria-label' : 'actions' } ,
454+ } ;
455+ }
456+ const sortIndex = columnSortConfig . findIndex ( ( entry ) => entry . key === column . id ) ;
457+ return {
458+ cell : titleById [ column . id ] ?? column . title ,
459+ props : {
460+ 'aria-label' : column . id ,
461+ className : widthById [ column . id ] ,
462+ tooltip : '' ,
463+ ...( sortIndex >= 0 ? { sort : getSortParams ( sortIndex ) } : { } ) ,
464+ } ,
465+ } ;
466+ } ) ;
451467} ;
452468
453469export const useProjectsRowsDV = (
454470 projectsList : AppProjectKind [ ] ,
455- namespace : string | undefined ,
471+ managedColumns : GitOpsManagedColumn [ ] ,
456472 applications : ApplicationKind [ ] ,
457473 appsLoaded : boolean ,
458474) : DataViewTr [ ] => {
459475 const rows : DataViewTr [ ] = [ ] ;
460476 if ( projectsList == undefined || projectsList . length == 0 ) {
461477 return rows ;
462478 }
463- const showNamespace = ! namespace || namespace === '' ;
464479 projectsList . forEach ( ( obj , index ) => {
465480 const appsCount = getApplicationsCount ( obj , applications , appsLoaded ) ;
466481
467- rows . push ( [
468- {
482+ const cellsById : Record < string , DataViewTd > = {
483+ name : {
469484 cell : (
470485 < ResourceLink
471486 groupVersionKind = { modelToGroupVersionKind ( AppProjectModel ) }
@@ -477,23 +492,19 @@ export const useProjectsRowsDV = (
477492 id : 'name' ,
478493 dataLabel : 'Name' ,
479494 } ,
480- ...( showNamespace
481- ? [
482- {
483- cell : < ResourceLink kind = "Namespace" name = { obj . metadata . namespace } /> ,
484- id : obj . metadata . namespace ,
485- dataLabel : 'Namespace' ,
486- } ,
487- ]
488- : [ ] ) ,
489- {
495+ [ NAMESPACE_COLUMN_ID ] : {
496+ cell : < ResourceLink kind = "Namespace" name = { obj . metadata . namespace } /> ,
497+ id : obj . metadata . namespace ,
498+ dataLabel : 'Namespace' ,
499+ } ,
500+ description : {
490501 id : 'description' ,
491502 dataLabel : 'Description' ,
492503 cell : (
493504 < span className = "gitops-project-list__description" > { obj . spec ?. description || '-' } </ span >
494505 ) ,
495506 } ,
496- {
507+ applications : {
497508 id : 'applications' ,
498509 dataLabel : 'Applications' ,
499510 cell : (
@@ -502,7 +513,7 @@ export const useProjectsRowsDV = (
502513 </ span >
503514 ) ,
504515 } ,
505- {
516+ labels : {
506517 id : 'labels' ,
507518 dataLabel : 'Labels' ,
508519 cell : (
@@ -521,7 +532,7 @@ export const useProjectsRowsDV = (
521532 </ div >
522533 ) ,
523534 } ,
524- {
535+ 'last-updated' : {
525536 id : 'last-updated' ,
526537 cell : ( ( ) => {
527538 const lastUpdate = getLastUpdateTimestamp ( obj ) ;
@@ -532,12 +543,14 @@ export const useProjectsRowsDV = (
532543 ) ;
533544 } ) ( ) ,
534545 } ,
535- {
546+ actions : {
536547 id : 'actions-' + index ,
537548 cell : < ProjectActionsCell project = { obj } index = { index } /> ,
538549 props : { style : { paddingTop : 8 , paddingRight : 0 , paddingLeft : 0 , width : 10 } } ,
539550 } ,
540- ] ) ;
551+ } ;
552+
553+ rows . push ( managedColumns . map ( ( column ) => cellsById [ column . id ] ) ) ;
541554 } ) ;
542555 return rows ;
543556} ;
0 commit comments