1+ import {
2+ K8sResourceCommon ,
3+ useFlag ,
4+ } from '@openshift-console/dynamic-plugin-sdk' ;
15import { useCallback , useMemo , useState } from 'react' ;
6+ import { useTranslation } from 'react-i18next' ;
7+ import { useSearchParams } from 'react-router-dom-v5-compat' ;
8+ import { FLAG_PIPELINE_TEKTON_RESULT_INSTALLED } from '../../consts' ;
29import type {
310 CheckboxFilterConfig ,
411 FilterValues ,
512} from '../common/DataViewFilterToolbar' ;
13+ import {
14+ isPipelineRunLoadedFromTektonResults ,
15+ pipelineFilterReducer ,
16+ pipelineRunDataSourceFilter ,
17+ pipelineRunFilterReducer ,
18+ pipelineRunStatusFilter ,
19+ pipelineStatusFilter ,
20+ } from '../utils/pipeline-filter-reducer' ;
21+ import { ListFilterId , ListFilterLabels } from '../utils/pipeline-utils' ;
622
7- interface UseDataViewFilterOptions < T > {
23+ export type ResourceType = 'Pipeline' | 'PipelineRun' | 'TaskRun' ;
24+
25+ interface UseDataViewFilterOptions < T extends K8sResourceCommon > {
826 data : T [ ] ;
9- getName : ( obj : T ) => string ;
27+ getName ? : ( obj : T ) => string ;
1028 getLabels ?: ( obj : T ) => Record < string , string > | undefined ;
11- checkboxFilters ?: CheckboxFilterConfig [ ] ;
12- matchesCheckboxFilter ?: (
13- obj : T ,
14- filterId : string ,
15- selectedValues : string [ ] ,
16- ) => boolean ;
29+ resourceType ?: ResourceType ;
30+ defaultStatusValues ?: string [ ] ;
31+ defaultDataSourceValues ?: string [ ] ;
1732}
1833
1934const matchesLabels = (
@@ -31,74 +46,256 @@ const matchesLabels = (
3146 } ) ;
3247} ;
3348
34- export const useDataViewFilter = < T > ( {
49+ interface ResourceFilterConfig {
50+ statusOptions : ListFilterId [ ] ;
51+ statusFilter : ( phases : any , obj : any ) => boolean ;
52+ statusReducer : ( obj : any ) => string ;
53+ hasDataSourceFilter : boolean ;
54+ defaultStatusValues ?: string [ ] ;
55+ defaultDataSourceValues ?: string [ ] ;
56+ }
57+
58+ const RESOURCE_FILTER_CONFIG : Record < ResourceType , ResourceFilterConfig > = {
59+ Pipeline : {
60+ statusOptions : [
61+ ListFilterId . Succeeded ,
62+ ListFilterId . Running ,
63+ ListFilterId . Failed ,
64+ ListFilterId . Cancelled ,
65+ ListFilterId . Other ,
66+ ] ,
67+ statusFilter : pipelineStatusFilter ,
68+ statusReducer : pipelineFilterReducer ,
69+ hasDataSourceFilter : false ,
70+ } ,
71+ PipelineRun : {
72+ statusOptions : [
73+ ListFilterId . Succeeded ,
74+ ListFilterId . Running ,
75+ ListFilterId . Failed ,
76+ ListFilterId . Cancelled ,
77+ ListFilterId . Other ,
78+ ] ,
79+ statusFilter : pipelineRunStatusFilter ,
80+ statusReducer : pipelineRunFilterReducer ,
81+ hasDataSourceFilter : true ,
82+ defaultDataSourceValues : [ 'cluster-data' ] ,
83+ } ,
84+ TaskRun : {
85+ statusOptions : [
86+ ListFilterId . Succeeded ,
87+ ListFilterId . Running ,
88+ ListFilterId . Failed ,
89+ ListFilterId . Cancelled ,
90+ ] ,
91+ statusFilter : pipelineRunStatusFilter ,
92+ statusReducer : pipelineRunFilterReducer ,
93+ hasDataSourceFilter : true ,
94+ defaultDataSourceValues : [ 'cluster-data' ] ,
95+ } ,
96+ } ;
97+
98+ const defaultGetName = < T extends K8sResourceCommon > ( obj : T ) : string =>
99+ obj . metadata ?. name || '' ;
100+
101+ const defaultGetLabels = < T extends K8sResourceCommon > (
102+ obj : T ,
103+ ) : Record < string , string > | undefined => obj . metadata ?. labels ;
104+
105+ export const useDataViewFilter = < T extends K8sResourceCommon > ( {
35106 data,
36- getName,
37- getLabels,
38- checkboxFilters = [ ] ,
39- matchesCheckboxFilter,
107+ getName = defaultGetName ,
108+ getLabels = defaultGetLabels ,
109+ resourceType,
110+ defaultStatusValues,
111+ defaultDataSourceValues,
40112} : UseDataViewFilterOptions < T > ) => {
113+ const { t } = useTranslation ( 'plugin__pipelines-console-plugin' ) ;
114+ const isTektonResultEnabled = useFlag ( FLAG_PIPELINE_TEKTON_RESULT_INSTALLED ) ;
115+ const allStatusIds = useMemo ( ( ) => Object . values ( ListFilterId ) , [ ] ) ;
116+ const resetFilterState = { name : '' , labels : [ ] } ;
117+
118+ const checkboxFilters = useMemo < CheckboxFilterConfig [ ] > ( ( ) => {
119+ if ( ! resourceType ) return [ ] ;
120+ const config = RESOURCE_FILTER_CONFIG [ resourceType ] ;
121+ if ( ! config ?. statusOptions ?. length ) return [ ] ;
122+ const filters : CheckboxFilterConfig [ ] = [
123+ {
124+ id : 'status' ,
125+ title : t ( 'Status' ) ,
126+ placeholder : t ( 'Filter by status' ) ,
127+ defaultValues : defaultStatusValues ?? config . defaultStatusValues ,
128+ options : config . statusOptions . map ( ( id ) => ( {
129+ value : id ,
130+ label : ListFilterLabels [ id ] ,
131+ count : 0 ,
132+ } ) ) ,
133+ } ,
134+ ] ;
135+ if ( config . hasDataSourceFilter && isTektonResultEnabled ) {
136+ filters . push ( {
137+ id : 'dataSource' ,
138+ title : t ( 'Data source' ) ,
139+ placeholder : t ( 'Filter by data source' ) ,
140+ defaultValues :
141+ defaultDataSourceValues ?? config . defaultDataSourceValues ,
142+ options : [
143+ { value : 'cluster-data' , label : t ( 'Cluster' ) , count : 0 } ,
144+ { value : 'archived-data' , label : t ( 'Archived' ) , count : 0 } ,
145+ ] ,
146+ } ) ;
147+ }
148+ return filters ;
149+ } , [
150+ resourceType ,
151+ isTektonResultEnabled ,
152+ t ,
153+ defaultStatusValues ,
154+ defaultDataSourceValues ,
155+ ] ) ;
156+
157+ const config = resourceType
158+ ? RESOURCE_FILTER_CONFIG [ resourceType ]
159+ : undefined ;
160+
161+ const matchesCheckboxFilter = useCallback (
162+ ( obj : T , filterId : string , selectedValues : string [ ] ) => {
163+ if ( filterId === 'status' && config ) {
164+ return config . statusFilter (
165+ { selected : selectedValues , all : allStatusIds } ,
166+ obj ,
167+ ) ;
168+ }
169+ if ( filterId === 'dataSource' ) {
170+ return pipelineRunDataSourceFilter ( { selected : selectedValues } , obj ) ;
171+ }
172+ return true ;
173+ } ,
174+ [ allStatusIds , config ] ,
175+ ) ;
176+
177+ const getCheckboxFilterValue = useCallback (
178+ ( obj : T , filterId : string ) : string | undefined => {
179+ if ( filterId === 'status' && config ) return config . statusReducer ( obj ) ;
180+ if ( filterId === 'dataSource' ) {
181+ return isPipelineRunLoadedFromTektonResults ( obj )
182+ ? 'archived-data'
183+ : 'cluster-data' ;
184+ }
185+ return undefined ;
186+ } ,
187+ [ config ] ,
188+ ) ;
189+
41190 const initialValues = useMemo ( ( ) => {
42191 const values : FilterValues = { name : '' , labels : [ ] } ;
43192 checkboxFilters . forEach ( ( f ) => {
44- values [ f . id ] = [ ] ;
193+ values [ f . id ] = f . defaultValues ?? [ ] ;
45194 } ) ;
46195 return values ;
47196 } , [ checkboxFilters ] ) ;
48197
49198 const [ filterValues , setFilterValues ] = useState < FilterValues > ( initialValues ) ;
199+ const [ , setSearchParams ] = useSearchParams ( ) ;
200+
201+ const resetPage = useCallback ( ( ) => {
202+ setSearchParams ( ( prev ) => {
203+ const next = new URLSearchParams ( prev ) ;
204+ next . set ( 'page' , '1' ) ;
205+ return next ;
206+ } ) ;
207+ } , [ setSearchParams ] ) ;
50208
51209 const onFilterChange = useCallback (
52210 ( key : string , value : string | string [ ] ) => {
53211 setFilterValues ( ( prev ) => ( { ...prev , [ key ] : value } ) ) ;
212+ resetPage ( ) ;
54213 } ,
55- [ ] ,
214+ [ resetPage ] ,
56215 ) ;
57216
58217 const onClearAll = useCallback ( ( ) => {
59- setFilterValues ( initialValues ) ;
60- } , [ initialValues ] ) ;
218+ setFilterValues ( resetFilterState ) ;
219+ resetPage ( ) ;
220+ } , [ resetPage ] ) ;
61221
62- const filteredData = useMemo ( ( ) => {
63- if ( ! data ) return [ ] ;
64- return data . filter ( ( obj ) => {
222+ const passesNameAndLabelFilters = useCallback (
223+ ( obj : T ) : boolean => {
65224 const name = getName ( obj ) ;
66225 if (
67226 filterValues . name &&
68227 ! name ?. toLowerCase ( ) . includes ( filterValues . name . toLowerCase ( ) )
69228 ) {
70229 return false ;
71230 }
72-
73231 const labelFilters = filterValues . labels || [ ] ;
74232 if ( labelFilters . length > 0 && getLabels ) {
75233 if ( ! matchesLabels ( getLabels ( obj ) , labelFilters ) ) {
76234 return false ;
77235 }
78236 }
237+ return true ;
238+ } ,
239+ [ filterValues . name , filterValues . labels , getName , getLabels ] ,
240+ ) ;
79241
80- if ( matchesCheckboxFilter ) {
81- for ( const filter of checkboxFilters ) {
82- const selected = ( filterValues [ filter . id ] as string [ ] ) || [ ] ;
83- if (
84- selected . length > 0 &&
85- ! matchesCheckboxFilter ( obj , filter . id , selected )
86- ) {
87- return false ;
88- }
242+ const passesCheckboxFilter = useCallback (
243+ ( obj : T , excludeFilterId ?: string ) : boolean => {
244+ if ( ! resourceType ) return true ;
245+ for ( const filter of checkboxFilters ) {
246+ if ( filter . id === excludeFilterId ) continue ;
247+ const selected = ( filterValues [ filter . id ] as string [ ] ) || [ ] ;
248+ if (
249+ selected . length > 0 &&
250+ ! matchesCheckboxFilter ( obj , filter . id , selected )
251+ ) {
252+ return false ;
89253 }
90254 }
91-
92255 return true ;
93- } ) ;
256+ } ,
257+ [ resourceType , checkboxFilters , filterValues , matchesCheckboxFilter ] ,
258+ ) ;
259+
260+ const filteredData = useMemo ( ( ) => {
261+ if ( ! data ) return [ ] ;
262+ return data . filter (
263+ ( obj ) => passesNameAndLabelFilters ( obj ) && passesCheckboxFilter ( obj ) ,
264+ ) ;
265+ } , [ data , passesNameAndLabelFilters , passesCheckboxFilter ] ) ;
266+
267+ const updatedCheckboxFilters = useMemo ( ( ) => {
268+ if ( ! resourceType || ! data ) return checkboxFilters ;
269+ return checkboxFilters . map ( ( filter ) => ( {
270+ ...filter ,
271+ options : filter . options . map ( ( opt ) => {
272+ let count = 0 ;
273+ data . forEach ( ( obj ) => {
274+ if (
275+ passesNameAndLabelFilters ( obj ) &&
276+ passesCheckboxFilter ( obj , filter . id ) &&
277+ getCheckboxFilterValue ( obj , filter . id ) === opt . value
278+ ) {
279+ count ++ ;
280+ }
281+ } ) ;
282+ return { ...opt , count } ;
283+ } ) ,
284+ } ) ) ;
94285 } , [
95- data ,
96- filterValues ,
97- getName ,
98- getLabels ,
286+ resourceType ,
99287 checkboxFilters ,
100- matchesCheckboxFilter ,
288+ data ,
289+ getCheckboxFilterValue ,
290+ passesNameAndLabelFilters ,
291+ passesCheckboxFilter ,
101292 ] ) ;
102293
103- return { filterValues, onFilterChange, onClearAll, filteredData } ;
294+ return {
295+ filterValues,
296+ onFilterChange,
297+ onClearAll,
298+ filteredData,
299+ updatedCheckboxFilters,
300+ } ;
104301} ;
0 commit comments