@@ -165,6 +165,103 @@ function RegistriesPicker(props: {
165
165
) ;
166
166
}
167
167
168
+ function RegistryCapabilitiesPicker ( props : {
169
+ capabilityEnabled : { capabilityName : string ; enabled : boolean } [ ] ;
170
+ setCapabilityEnabled : React . Dispatch <
171
+ React . SetStateAction < { capabilityName : string ; enabled : boolean } [ ] >
172
+ > ;
173
+ } ) {
174
+ function onCheckboxClick ( clickedCapability : string , checked : boolean ) {
175
+ const updatedList = [ ...props . capabilityEnabled ] //
176
+ . filter ( ( entry ) => entry . capabilityName !== clickedCapability ) ;
177
+ updatedList . push ( {
178
+ capabilityName : clickedCapability ,
179
+ enabled : checked ,
180
+ } ) ;
181
+ const filteredUpdatedList = updatedList
182
+ . sort ( ( capA , capB ) => {
183
+ return capA . capabilityName . localeCompare ( capB . capabilityName )
184
+ } ) ;
185
+ props . setCapabilityEnabled ( [ ...filteredUpdatedList ] ) ;
186
+ }
187
+
188
+ return (
189
+ < Stack direction = "column" spacing = { 1 } marginY = { 2 } >
190
+ < Typography variant = "body2" marginBottom = { 1 } >
191
+ Filter by Capabilities
192
+ </ Typography >
193
+ < FormGroup >
194
+ { props . capabilityEnabled . map ( ( _cap ) => {
195
+ return (
196
+ < FormControlLabel
197
+ control = {
198
+ < Checkbox
199
+ checked = { _cap . enabled }
200
+ onChange = { ( _e , checked ) =>
201
+ onCheckboxClick ( _cap . capabilityName , checked )
202
+ }
203
+ />
204
+ }
205
+ label = { _cap . capabilityName }
206
+ key = { _cap . capabilityName }
207
+ />
208
+ ) ;
209
+ } ) }
210
+ </ FormGroup >
211
+ </ Stack >
212
+ ) ;
213
+ }
214
+
215
+ function RegistryTagsPicker ( props : {
216
+ tagEnabled : { tagName : string ; enabled : boolean } [ ] ;
217
+ setTagEnabled : React . Dispatch <
218
+ React . SetStateAction < { tagName : string ; enabled : boolean } [ ] >
219
+ > ;
220
+ } ) {
221
+ function onCheckboxClick ( clickedTag : string , checked : boolean ) {
222
+ const prevVal = props . tagEnabled . find (
223
+ ( entry ) => entry . tagName === clickedTag ,
224
+ ) ;
225
+ const updatedList = [ ...props . tagEnabled ] //
226
+ . filter ( ( entry ) => entry . tagName !== clickedTag ) ;
227
+ updatedList . push ( {
228
+ tagName : clickedTag ,
229
+ enabled : checked ,
230
+ } ) ;
231
+ const filteredUpdatedList = updatedList
232
+ . sort ( ( tagA , tagB ) => {
233
+ return tagA . tagName . localeCompare ( tagB . tagName )
234
+ } ) ;
235
+ props . setTagEnabled ( [ ...filteredUpdatedList ] ) ;
236
+ }
237
+
238
+ return (
239
+ < Stack direction = "column" spacing = { 1 } marginY = { 2 } >
240
+ < Typography variant = "body2" marginBottom = { 1 } >
241
+ Filter by Tags
242
+ </ Typography >
243
+ < FormGroup >
244
+ { props . tagEnabled . map ( ( tag ) => {
245
+ return (
246
+ < FormControlLabel
247
+ control = {
248
+ < Checkbox
249
+ checked = { tag . enabled }
250
+ onChange = { ( _e , checked ) =>
251
+ onCheckboxClick ( tag . tagName , checked )
252
+ }
253
+ />
254
+ }
255
+ label = { tag . tagName }
256
+ key = { tag . tagName }
257
+ />
258
+ ) ;
259
+ } ) }
260
+ </ FormGroup >
261
+ </ Stack >
262
+ ) ;
263
+ }
264
+
168
265
const SelectTemplateProject = React . forwardRef (
169
266
(
170
267
props : {
@@ -389,6 +486,22 @@ export type DevfileSearchProps = {
389
486
goBack ?: ( ) => void ;
390
487
} ;
391
488
489
+ /**
490
+ * Calculates if specified devfile is to be included into search results
491
+ * based on devfile tags and tags filter. A devfile is to be included if:
492
+ * - it contains any of selected tags
493
+ * - always if there is no any selected tags
494
+ *
495
+ * @param tags1
496
+ * @param tags2
497
+ * @returns
498
+ */
499
+ function isToBeIncluded ( devfileTags : string [ ] , selectedTags : string [ ] ) : boolean {
500
+ return selectedTags . length == 0 || devfileTags . filter ( ( _devfileTag ) => {
501
+ return selectedTags . find ( ( _selectedTags ) => _devfileTag === _selectedTags ) !== undefined ;
502
+ } ) . length > 0 ;
503
+ }
504
+
392
505
export function DevfileSearch ( props : DevfileSearchProps ) {
393
506
const ITEMS_PER_PAGE = 6 ;
394
507
const QUARKUS_REGEX = / [ Q q ] u a r k u s / ;
@@ -399,13 +512,30 @@ export function DevfileSearch(props: DevfileSearchProps) {
399
512
const [ registryEnabled , setRegistryEnabled ] = React . useState <
400
513
{ registryName : string ; registryUrl : string ; enabled : boolean } [ ]
401
514
> ( [ ] ) ;
515
+ const [ devfileCapabilities , setDevfileCapabilities ] = React . useState < string [ ] > ( [ ] ) ;
516
+ const [ capabilityEnabled , setCapabilityEnabled ] = React . useState <
517
+ { capabilityName : string ; enabled : boolean } [ ]
518
+ > ( [ ] ) ;
519
+ const [ devfileTags , setDevfileTags ] = React . useState < string [ ] > ( [ ] ) ;
520
+ const [ tagEnabled , setTagEnabled ] = React . useState <
521
+ { tagName : string ; enabled : boolean } [ ]
522
+ > ( [ ] ) ;
402
523
const [ searchText , setSearchText ] = React . useState ( '' ) ;
403
524
404
525
function respondToMessage ( messageEvent : MessageEvent ) {
405
526
const message = messageEvent . data as Message ;
406
527
switch ( message . action ) {
407
528
case 'devfileRegistries' : {
408
529
setDevfileRegistries ( ( _devfileRegistries ) => message . data ) ;
530
+ break ;
531
+ }
532
+ case 'devfileCapabilities' : {
533
+ setDevfileCapabilities ( ( _devfileCapabilities ) => message . data ) ;
534
+ break ;
535
+ }
536
+ case 'devfileTags' : {
537
+ setDevfileTags ( ( _devfileTags ) => message . data ) ;
538
+ break ;
409
539
}
410
540
}
411
541
}
@@ -422,6 +552,28 @@ export function DevfileSearch(props: DevfileSearchProps) {
422
552
setRegistryEnabled ( ( _ ) => enabledArray ) ;
423
553
} , [ devfileRegistries ] ) ;
424
554
555
+ React . useEffect ( ( ) => {
556
+ const enabledArray = [ ] ;
557
+ for ( let capability of devfileCapabilities ) {
558
+ enabledArray . push ( {
559
+ capabilityName : capability ,
560
+ enabled : false , // All values set to false means that no filter is to be applied
561
+ } ) ;
562
+ }
563
+ setCapabilityEnabled ( ( _ ) => enabledArray ) ;
564
+ } , [ devfileCapabilities ] ) ;
565
+
566
+ React . useEffect ( ( ) => {
567
+ const enabledArray = [ ] ;
568
+ for ( let tag of devfileTags ) {
569
+ enabledArray . push ( {
570
+ tagName : tag ,
571
+ enabled : false , // All values set to false means that no filter is to be applied
572
+ } ) ;
573
+ }
574
+ setTagEnabled ( ( _ ) => enabledArray ) ;
575
+ } , [ devfileTags ] ) ;
576
+
425
577
React . useEffect ( ( ) => {
426
578
props . setSelectedDevfile ( selectedDevfile ) ;
427
579
} , [ selectedDevfile ] ) ;
@@ -437,21 +589,54 @@ export function DevfileSearch(props: DevfileSearchProps) {
437
589
window . vscodeApi . postMessage ( { action : 'getDevfileRegistries' } ) ;
438
590
} , [ ] ) ;
439
591
592
+ React . useEffect ( ( ) => {
593
+ window . vscodeApi . postMessage ( { action : 'getDevfileCapabilities' } ) ;
594
+ } , [ ] ) ;
595
+
596
+ React . useEffect ( ( ) => {
597
+ window . vscodeApi . postMessage ( { action : 'getDevfileTags' } ) ;
598
+ } , [ ] ) ;
599
+
440
600
React . useEffect ( ( ) => {
441
601
setCurrentPage ( ( _ ) => 1 ) ;
442
- } , [ registryEnabled , searchText ] ) ;
602
+ } , [ registryEnabled , capabilityEnabled , tagEnabled , searchText ] ) ;
443
603
444
604
if ( ! devfileRegistries ) {
445
605
return < LoadScreen title = "Retrieving list of Devfiles" /> ;
446
606
}
447
607
608
+ if ( ! devfileCapabilities ) {
609
+ return < LoadScreen title = "Retrieving list of Devfile Capabilities" /> ;
610
+ }
611
+
612
+ if ( ! devfileTags ) {
613
+ return < LoadScreen title = "Retrieving list of Devfile Tags" /> ;
614
+ }
615
+
448
616
const activeRegistries = registryEnabled //
449
617
. filter ( ( entry ) => entry . enabled ) //
450
618
. map ( ( entry ) => entry . registryName ) ;
451
619
620
+ const debugSupport = capabilityEnabled //
621
+ . filter ( ( _cap ) => _cap . capabilityName === 'Debug Support' ) //
622
+ . filter ( ( _cap ) => _cap . enabled ) //
623
+ . length > 0 ;
624
+
625
+ const deploySupport = capabilityEnabled //
626
+ . filter ( ( _cap ) => _cap . capabilityName === 'Deploy Support' ) //
627
+ . filter ( ( _cap ) => _cap . enabled ) //
628
+ . length > 0 ;
629
+
630
+ const activeTags = tagEnabled
631
+ . filter ( ( _tag ) => _tag . enabled ) //
632
+ . map ( ( _tag ) => _tag . tagName ) ;
633
+
452
634
const devfiles : Devfile [ ] = devfileRegistries //
453
635
. filter ( ( devfileRegistry ) => activeRegistries . includes ( devfileRegistry . name ) ) //
454
636
. flatMap ( ( devfileRegistry ) => devfileRegistry . devfiles ) //
637
+ . filter ( ( devfile ) => debugSupport ? devfile . supportsDebug : true ) //
638
+ . filter ( ( devfile ) => deploySupport ? devfile . supportsDeploy : true ) //
639
+ . filter ( ( devfile ) => isToBeIncluded ( devfile . tags , activeTags ) ) //
455
640
. filter ( ( devfile ) => {
456
641
const searchTerms = searchText . split ( / \s + / ) ;
457
642
return every (
@@ -485,17 +670,51 @@ export function DevfileSearch(props: DevfileSearchProps) {
485
670
< >
486
671
< Stack direction = "column" height = "100%" spacing = { 3 } >
487
672
< Typography variant = "h5" > { props . titleText } </ Typography >
488
- < Stack direction = "row" flexGrow = "1" spacing = { 2 } >
489
- { devfileRegistries . length > 1 && (
490
- < >
491
- < RegistriesPicker
492
- registryEnabled = { registryEnabled }
493
- setRegistryEnabled = { setRegistryEnabled }
494
- />
495
- < Divider orientation = "vertical" />
496
- </ >
497
- ) }
498
- < Stack direction = "column" sx = { { flexGrow : '1' , height : '100%' } } spacing = { 3 } >
673
+ < Stack direction = "row" spacing = { 2 } >
674
+ < Stack direction = "column" sx = { { height : 'calc(100vh - 200px - 5em)' , overflow : 'scroll' , minWidth :'20%' } } spacing = { 0 } >
675
+ { devfileRegistries . length > 1 && (
676
+ < >
677
+ < Stack direction = "row" sx = { { width : '100%' } } spacing = { 0 } >
678
+ < RegistriesPicker
679
+ registryEnabled = { registryEnabled }
680
+ setRegistryEnabled = { setRegistryEnabled }
681
+ />
682
+ </ Stack >
683
+ < Stack direction = "column" sx = { { width : '100%' } } spacing = { 0 } marginBottom = { 1 } >
684
+ < Divider orientation = "horizontal" />
685
+ </ Stack >
686
+ </ >
687
+ ) }
688
+ { devfileCapabilities . length > 1 && (
689
+ < >
690
+ < Stack direction = "row" sx = { { width : '100%' } } spacing = { 0 } >
691
+ < RegistryCapabilitiesPicker
692
+ capabilityEnabled = { capabilityEnabled }
693
+ setCapabilityEnabled = { setCapabilityEnabled }
694
+ />
695
+ </ Stack >
696
+ < Stack direction = "column" sx = { { flexGrow : '1' , width : '100%' } } spacing = { 0 } marginBottom = { 1 } >
697
+ < Divider orientation = "horizontal" />
698
+ </ Stack >
699
+ </ >
700
+ ) }
701
+ { /* disabled */ false && devfileTags . length > 1 && (
702
+ < >
703
+ < Stack direction = "row" sx = { { width : '100%' } } spacing = { 0 } >
704
+ < RegistryTagsPicker
705
+ tagEnabled = { tagEnabled }
706
+ setTagEnabled = { setTagEnabled }
707
+ />
708
+ </ Stack >
709
+ </ >
710
+ ) }
711
+ < Stack direction = "column" sx = { { flexGrow : '1' , height : '100%' , width : '100%' } } spacing = { 0 } >
712
+ </ Stack >
713
+ </ Stack >
714
+ < Stack direction = "column" spacing = { 3 } >
715
+ < Divider orientation = "vertical" sx = { { height : 'calc(100vh - 200px - 5em)' } } />
716
+ </ Stack >
717
+ < Stack direction = "column" sx = { { flexGrow : '1' } } spacing = { 3 } >
499
718
< SearchBar
500
719
searchText = { searchText }
501
720
setSearchText = { setSearchText }
0 commit comments