github.com/argoproj/argo-cd/v3@v3.2.1/ui/src/app/applications/components/applications-list/applications-table.tsx (about) 1 import {DataLoader, DropDownMenu, Tooltip} from 'argo-ui'; 2 import * as React from 'react'; 3 import Moment from 'react-moment'; 4 import {Key, KeybindingContext, useNav} from 'argo-ui/v2'; 5 import {Cluster} from '../../../shared/components'; 6 import {Consumer, Context} from '../../../shared/context'; 7 import * as models from '../../../shared/models'; 8 import {ApplicationURLs} from '../application-urls'; 9 import * as AppUtils from '../utils'; 10 import {getAppDefaultSource, OperationState} from '../utils'; 11 import {ApplicationsLabels} from './applications-labels'; 12 import {ApplicationsSource} from './applications-source'; 13 import {services} from '../../../shared/services'; 14 import './applications-table.scss'; 15 16 export const ApplicationsTable = (props: { 17 applications: models.Application[]; 18 syncApplication: (appName: string, appNamespace: string) => any; 19 refreshApplication: (appName: string, appNamespace: string) => any; 20 deleteApplication: (appName: string, appNamespace: string) => any; 21 }) => { 22 const [selectedApp, navApp, reset] = useNav(props.applications.length); 23 const ctxh = React.useContext(Context); 24 25 const {useKeybinding} = React.useContext(KeybindingContext); 26 27 useKeybinding({keys: Key.DOWN, action: () => navApp(1)}); 28 useKeybinding({keys: Key.UP, action: () => navApp(-1)}); 29 useKeybinding({ 30 keys: Key.ESCAPE, 31 action: () => { 32 reset(); 33 return selectedApp > -1 ? true : false; 34 } 35 }); 36 useKeybinding({ 37 keys: Key.ENTER, 38 action: () => { 39 if (selectedApp > -1) { 40 ctxh.navigation.goto(`/${AppUtils.getAppUrl(props.applications[selectedApp])}`); 41 return true; 42 } 43 return false; 44 } 45 }); 46 47 return ( 48 <Consumer> 49 {ctx => ( 50 <DataLoader load={() => services.viewPreferences.getPreferences()}> 51 {pref => { 52 const favList = pref.appList.favoritesAppList || []; 53 return ( 54 <div className='applications-table argo-table-list argo-table-list--clickable'> 55 {props.applications.map((app, i) => ( 56 <div 57 key={AppUtils.appInstanceName(app)} 58 className={`argo-table-list__row 59 applications-list__entry applications-list__entry--health-${app.status.health.status} ${selectedApp === i ? 'applications-tiles__selected' : ''}`}> 60 <div 61 className={`row applications-list__table-row ${app.status.sourceHydrator?.currentOperation ? 'applications-table-row--with-hydrator' : ''}`} 62 onClick={e => ctx.navigation.goto(`/${AppUtils.getAppUrl(app)}`, {}, {event: e})}> 63 <div className='columns small-4'> 64 <div className='row'> 65 <div className=' columns small-2'> 66 <div> 67 <Tooltip content={favList?.includes(app.metadata.name) ? 'Remove Favorite' : 'Add Favorite'}> 68 <button 69 onClick={e => { 70 e.stopPropagation(); 71 favList?.includes(app.metadata.name) 72 ? favList.splice(favList.indexOf(app.metadata.name), 1) 73 : favList.push(app.metadata.name); 74 services.viewPreferences.updatePreferences({appList: {...pref.appList, favoritesAppList: favList}}); 75 }}> 76 <i 77 className={favList?.includes(app.metadata.name) ? 'fas fa-star' : 'far fa-star'} 78 style={{ 79 cursor: 'pointer', 80 marginRight: '7px', 81 color: favList?.includes(app.metadata.name) ? '#FFCE25' : '#8fa4b1' 82 }} 83 /> 84 </button> 85 </Tooltip> 86 <ApplicationURLs urls={app.status.summary.externalURLs} /> 87 </div> 88 </div> 89 <div className='show-for-xxlarge columns small-4'>Name:</div> 90 <div className='columns small-12 xxlarge-6'> 91 <Tooltip 92 content={ 93 <> 94 {app.metadata.name} 95 <br /> 96 <Moment fromNow={true} ago={true}> 97 {app.metadata.creationTimestamp} 98 </Moment> 99 </> 100 }> 101 <span className='application-name'>{app.metadata.name}</span> 102 </Tooltip> 103 </div> 104 </div> 105 <div className='row'> 106 <div className=' columns small-2' /> 107 <div className='show-for-xxlarge columns small-4'>Project:</div> 108 <div className='columns small-12 xxlarge-6'>{app.spec.project}</div> 109 </div> 110 </div> 111 112 <div className='columns small-6'> 113 <div className='row'> 114 <div className='show-for-xxlarge columns small-2'>Source:</div> 115 <div className='columns small-12 xxlarge-10 applications-table-source' style={{position: 'relative'}}> 116 <div className='applications-table-source__link'> 117 <ApplicationsSource source={getAppDefaultSource(app)} /> 118 </div> 119 <div className='applications-table-source__labels'> 120 <ApplicationsLabels app={app} /> 121 </div> 122 </div> 123 </div> 124 <div className='row'> 125 <div className='show-for-xxlarge columns small-2'>Destination:</div> 126 <div className='columns small-12 xxlarge-10'> 127 <Cluster server={app.spec.destination.server} name={app.spec.destination.name} />/{app.spec.destination.namespace} 128 </div> 129 </div> 130 </div> 131 132 <div className='columns small-2'> 133 <AppUtils.HealthStatusIcon state={app.status.health} /> <span>{app.status.health.status}</span> <br /> 134 {app.status.sourceHydrator?.currentOperation && ( 135 <> 136 <AppUtils.HydrateOperationPhaseIcon operationState={app.status.sourceHydrator.currentOperation} />{' '} 137 <span>{app.status.sourceHydrator.currentOperation.phase}</span> <br /> 138 </> 139 )} 140 <AppUtils.ComparisonStatusIcon status={app.status.sync.status} /> 141 <span>{app.status.sync.status}</span> <OperationState app={app} quiet={true} /> 142 <DropDownMenu 143 anchor={() => ( 144 <button className='argo-button argo-button--light argo-button--lg argo-button--short'> 145 <i className='fa fa-ellipsis-v' /> 146 </button> 147 )} 148 items={[ 149 { 150 title: 'Sync', 151 iconClassName: 'fa fa-fw fa-sync', 152 action: () => props.syncApplication(app.metadata.name, app.metadata.namespace) 153 }, 154 { 155 title: 'Refresh', 156 iconClassName: 'fa fa-fw fa-redo', 157 action: () => props.refreshApplication(app.metadata.name, app.metadata.namespace) 158 }, 159 { 160 title: 'Delete', 161 iconClassName: 'fa fa-fw fa-times-circle', 162 action: () => props.deleteApplication(app.metadata.name, app.metadata.namespace) 163 } 164 ]} 165 /> 166 </div> 167 </div> 168 </div> 169 ))} 170 </div> 171 ); 172 }} 173 </DataLoader> 174 )} 175 </Consumer> 176 ); 177 };