@@ -22,28 +22,26 @@ import {
2222 EmptyStateBody ,
2323 EmptyStateFooter ,
2424 EmptyStateActions ,
25- Stack ,
26- StackItem ,
2725 Card ,
2826 CardBody ,
2927 Flex ,
3028 FlexItem ,
31- Tooltip ,
3229 Modal ,
3330 ModalVariant ,
3431 ModalBody ,
3532 ModalFooter ,
36- ModalHeader
33+ ModalHeader ,
34+ DropdownItem ,
35+ Dropdown ,
36+ MenuToggleElement ,
37+ MenuToggle ,
38+ DropdownList ,
39+ CardHeader ,
40+ CardTitle ,
41+ Gallery ,
42+ GalleryItem
3743} from '@patternfly/react-core' ;
38- import {
39- ExternalLinkAltIcon ,
40- OutlinedQuestionCircleIcon ,
41- GithubIcon ,
42- CatalogIcon ,
43- PencilAltIcon ,
44- UploadIcon ,
45- TrashIcon
46- } from '@patternfly/react-icons' ;
44+ import { ExternalLinkAltIcon , OutlinedQuestionCircleIcon , GithubIcon , EllipsisVIcon } from '@patternfly/react-icons' ;
4745import { ExpandableSection } from '@patternfly/react-core/dist/esm/components/ExpandableSection/ExpandableSection' ;
4846import { v4 as uuidv4 } from 'uuid' ;
4947
@@ -68,10 +66,11 @@ const DashboardNative: React.FunctionComponent = () => {
6866 const [ isLoading , setIsLoading ] = React . useState < boolean > ( true ) ;
6967 const [ mergeStatus ] = React . useState < { branch : string ; message : string ; success : boolean } | null > ( null ) ;
7068 const [ diffData , setDiffData ] = React . useState < { branch : string ; changes : ChangeData [ ] } | null > ( null ) ;
71- const [ isModalOpen , setIsModalOpen ] = React . useState < boolean > ( false ) ;
72- const [ alerts , setAlerts ] = React . useState < AlertItem [ ] > ( [ ] ) ;
69+ const [ isActionMenuOpen , setIsActionMenuOpen ] = React . useState < { [ key : string ] : boolean } > ( { } ) ;
70+ const [ isChangeModalOpen , setIsChangeModalOpen ] = React . useState < boolean > ( false ) ;
7371 const [ isDeleteModalOpen , setIsDeleteModalOpen ] = React . useState ( false ) ;
7472 const [ isPublishModalOpen , setIsPublishModalOpen ] = React . useState ( false ) ;
73+ const [ alerts , setAlerts ] = React . useState < AlertItem [ ] > ( [ ] ) ;
7574 const [ selectedBranch , setSelectedBranch ] = React . useState < string | null > ( null ) ;
7675 const [ isPublishing , setIsPublishing ] = React . useState ( false ) ;
7776 const [ expandedFiles , setExpandedFiles ] = React . useState < Record < string , boolean > > ( { } ) ;
@@ -171,7 +170,7 @@ const DashboardNative: React.FunctionComponent = () => {
171170 const result = await response . json ( ) ;
172171 if ( response . ok ) {
173172 setDiffData ( { branch : branchName , changes : result . changes } ) ;
174- setIsModalOpen ( true ) ;
173+ setIsChangeModalOpen ( true ) ;
175174 } else {
176175 console . error ( 'Failed to get branch changes:' , result . error ) ;
177176 }
@@ -286,6 +285,20 @@ const DashboardNative: React.FunctionComponent = () => {
286285 } ) ) ;
287286 } ;
288287
288+ const onActionMenuToggle = ( id : string , isOpen : boolean ) => {
289+ setIsActionMenuOpen ( ( prevState ) => ( {
290+ ...prevState ,
291+ [ id ] : isOpen
292+ } ) ) ;
293+ } ;
294+
295+ const onActionMenuSelect = ( id : string ) => {
296+ setIsActionMenuOpen ( ( prevState ) => ( {
297+ ...prevState ,
298+ [ id ] : false
299+ } ) ) ;
300+ } ;
301+
289302 return (
290303 < div >
291304 < PageBreadcrumb hasBodyWrapper = { false } >
@@ -330,6 +343,7 @@ const DashboardNative: React.FunctionComponent = () => {
330343 />
331344 ) ) }
332345 </ AlertGroup >
346+
333347 { isLoading ? (
334348 < Spinner size = "lg" />
335349 ) : branches . length === 0 ? (
@@ -370,41 +384,73 @@ const DashboardNative: React.FunctionComponent = () => {
370384 </ EmptyStateFooter >
371385 </ EmptyState >
372386 ) : (
373- < Stack hasGutter >
387+ < Gallery
388+ hasGutter
389+ minWidths = { {
390+ md : '400px' ,
391+ lg : '450px' ,
392+ xl : '500px' ,
393+ '2xl' : '600px'
394+ } }
395+ >
374396 { branches . map ( ( branch ) => (
375- < StackItem key = { branch . name } >
376- < Card >
397+ < GalleryItem key = { branch . name } >
398+ < Card key = { branch . name } >
399+ < CardHeader
400+ actions = { {
401+ actions : (
402+ < Dropdown
403+ onSelect = { ( ) => onActionMenuSelect ( branch . name ) }
404+ toggle = { ( toggleRef : React . Ref < MenuToggleElement > ) => (
405+ < MenuToggle
406+ ref = { toggleRef }
407+ isExpanded = { isActionMenuOpen [ branch . name ] || false }
408+ onClick = { ( ) => onActionMenuToggle ( branch . name , ! isActionMenuOpen [ branch . name ] ) }
409+ variant = "plain"
410+ aria-label = "contribution action menu"
411+ icon = { < EllipsisVIcon aria-hidden = "true" /> }
412+ />
413+ ) }
414+ isOpen = { isActionMenuOpen [ branch . name ] || false }
415+ onOpenChange = { ( isOpen : boolean ) => onActionMenuToggle ( branch . name , isOpen ) }
416+ >
417+ < DropdownList >
418+ < DropdownItem key = "show-changes" onClick = { ( ) => handleShowChanges ( branch . name ) } >
419+ Show Changes
420+ </ DropdownItem >
421+ < DropdownItem key = "edit-contribution" onClick = { ( ) => handleEditContribution ( branch . name ) } >
422+ Edit Contribution
423+ </ DropdownItem >
424+ < DropdownItem key = "publish-contribution" onClick = { ( ) => handlePublishContribution ( branch . name ) } >
425+ Publish Contribution
426+ </ DropdownItem >
427+ < DropdownItem key = "delete-contribution" onClick = { ( ) => handleDeleteContribution ( branch . name ) } >
428+ Delete Contribution
429+ </ DropdownItem >
430+ </ DropdownList >
431+ </ Dropdown >
432+ )
433+ } }
434+ >
435+ < CardTitle >
436+ < b > { branch . message } </ b >
437+ </ CardTitle >
438+ </ CardHeader >
377439 < CardBody >
378440 < Flex justifyContent = { { default : 'justifyContentSpaceBetween' } } >
379441 < FlexItem >
380442 Branch Name: { branch . name }
381443 < br />
382- Contribution Title: < b > { branch . message } </ b >
383- < br />
384444 Author: { branch . author } { ' ' }
385445 < br />
386446 Created on: { formatDateTime ( branch . creationDate ) }
387447 </ FlexItem >
388- < FlexItem align = { { default : 'alignRight' } } >
389- < Tooltip aria = "none" aria-live = "polite" content = { < div > Show Changes</ div > } >
390- < Button icon = { < CatalogIcon /> } variant = "plain" aria-label = "show" onClick = { ( ) => handleShowChanges ( branch . name ) } />
391- </ Tooltip >
392- < Tooltip aria = "none" aria-live = "polite" content = { < div > Edit Contribution</ div > } >
393- < Button icon = { < PencilAltIcon /> } variant = "plain" aria-label = "edit" onClick = { ( ) => handleEditContribution ( branch . name ) } />
394- </ Tooltip >
395- < Tooltip aria = "none" aria-live = "polite" content = { < div > Publish Changes</ div > } >
396- < Button icon = { < UploadIcon /> } variant = "plain" aria-label = "publish" onClick = { ( ) => handlePublishContribution ( branch . name ) } />
397- </ Tooltip >
398- < Tooltip aria = "none" aria-live = "polite" content = { < div > Delete</ div > } >
399- < Button icon = { < TrashIcon /> } variant = "plain" aria-label = "delete" onClick = { ( ) => handleDeleteContribution ( branch . name ) } />
400- </ Tooltip >
401- </ FlexItem >
402448 </ Flex >
403449 </ CardBody >
404450 </ Card >
405- </ StackItem >
451+ </ GalleryItem >
406452 ) ) }
407- </ Stack >
453+ </ Gallery >
408454 ) }
409455
410456 { mergeStatus && (
@@ -416,8 +462,8 @@ const DashboardNative: React.FunctionComponent = () => {
416462 < Modal
417463 variant = { ModalVariant . medium }
418464 title = { `Files Contained in Branch: ${ diffData ?. branch } ` }
419- isOpen = { isModalOpen }
420- onClose = { ( ) => setIsModalOpen ( false ) }
465+ isOpen = { isChangeModalOpen }
466+ onClose = { ( ) => setIsChangeModalOpen ( false ) }
421467 aria-labelledby = "changes-contribution-modal-title"
422468 aria-describedby = "changes-contribution-body-variant"
423469 >
@@ -459,6 +505,7 @@ const DashboardNative: React.FunctionComponent = () => {
459505 ) }
460506 </ ModalBody >
461507 </ Modal >
508+
462509 < Modal
463510 variant = { ModalVariant . small }
464511 title = "Deleting Contribution"
0 commit comments