github.com/argoproj/argo-cd@v1.8.7/ui/src/app/applications/components/application-status-panel/application-status-panel.tsx (about) 1 import {HelpIcon} from 'argo-ui'; 2 import * as React from 'react'; 3 import {DataLoader} from '../../../shared/components'; 4 import {Revision} from '../../../shared/components/revision'; 5 import {Timestamp} from '../../../shared/components/timestamp'; 6 import * as models from '../../../shared/models'; 7 import {services} from '../../../shared/services'; 8 import * as utils from '../utils'; 9 import {ApplicationSyncWindowStatusIcon, ComparisonStatusIcon, getAppOperationState, HealthStatusIcon, OperationState, syncStatusMessage} from '../utils'; 10 import {RevisionMetadataPanel} from './revision-metadata-panel'; 11 12 require('./application-status-panel.scss'); 13 14 interface Props { 15 application: models.Application; 16 showOperation?: () => any; 17 showConditions?: () => any; 18 } 19 20 export const ApplicationStatusPanel = ({application, showOperation, showConditions}: Props) => { 21 const today = new Date(); 22 23 let daysSinceLastSynchronized = 0; 24 const history = application.status.history || []; 25 if (history.length > 0) { 26 const deployDate = new Date(history[history.length - 1].deployedAt); 27 daysSinceLastSynchronized = Math.round(Math.abs((today.getTime() - deployDate.getTime()) / (24 * 60 * 60 * 1000))); 28 } 29 const cntByCategory = (application.status.conditions || []).reduce( 30 (map, next) => map.set(utils.getConditionCategory(next), (map.get(utils.getConditionCategory(next)) || 0) + 1), 31 new Map<string, number>() 32 ); 33 const appOperationState = getAppOperationState(application); 34 if (application.metadata.deletionTimestamp) { 35 showOperation = null; 36 } 37 38 return ( 39 <div className='application-status-panel row'> 40 <div className='application-status-panel__item columns small-2'> 41 <div className='application-status-panel__item-value'> 42 <HealthStatusIcon state={application.status.health} /> 43 44 {application.status.health.status} 45 <HelpIcon title='The health status of your app' /> 46 </div> 47 <div className='application-status-panel__item-name'>{application.status.health.message}</div> 48 </div> 49 <div className='application-status-panel__item columns small-2' style={{position: 'relative'}}> 50 <div className='application-status-panel__item-value'> 51 <ComparisonStatusIcon status={application.status.sync.status} label={true} /> 52 <HelpIcon title='Whether or not the version of your app is up to date with your repo. You may wish to sync your app if it is out-of-sync.' /> 53 </div> 54 <div className='application-status-panel__item-name'>{syncStatusMessage(application)}</div> 55 <div className='application-status-panel__item-name'> 56 {application.status && application.status.sync && application.status.sync.revision && ( 57 <RevisionMetadataPanel appName={application.metadata.name} type={application.spec.source.chart && 'helm'} revision={application.status.sync.revision} /> 58 )} 59 </div> 60 </div> 61 {appOperationState && ( 62 <div className='application-status-panel__item columns small-4 '> 63 <div className={`application-status-panel__item-value application-status-panel__item-value--${appOperationState.phase}`}> 64 <a onClick={() => showOperation && showOperation()}> 65 <OperationState app={application} /> 66 <HelpIcon 67 title={ 68 'Whether or not your last app sync was successful. It has been ' + 69 daysSinceLastSynchronized + 70 ' days since last sync. Click for the status of that sync.' 71 } 72 /> 73 </a> 74 </div> 75 {appOperationState.syncResult && appOperationState.syncResult.revision && ( 76 <div className='application-status-panel__item-name'> 77 To <Revision repoUrl={application.spec.source.repoURL} revision={appOperationState.syncResult.revision} /> 78 </div> 79 )} 80 <div className='application-status-panel__item-name'> 81 {appOperationState.phase} <Timestamp date={appOperationState.finishedAt || appOperationState.startedAt} /> 82 </div> 83 {(appOperationState.syncResult && appOperationState.syncResult.revision && ( 84 <RevisionMetadataPanel 85 appName={application.metadata.name} 86 type={application.spec.source.chart && 'helm'} 87 revision={appOperationState.syncResult.revision} 88 /> 89 )) || <div className='application-status-panel__item-name'>{appOperationState.message}</div>} 90 </div> 91 )} 92 {application.status.conditions && ( 93 <div className={`application-status-panel__item columns small-2`}> 94 <div className='application-status-panel__item-value' onClick={() => showConditions && showConditions()}> 95 {cntByCategory.get('info') && <a className='info'>{cntByCategory.get('info')} Info</a>} 96 {cntByCategory.get('warning') && <a className='warning'>{cntByCategory.get('warning')} Warnings</a>} 97 {cntByCategory.get('error') && <a className='error'>{cntByCategory.get('error')} Errors</a>} 98 </div> 99 </div> 100 )} 101 <DataLoader 102 noLoaderOnInputChange={true} 103 input={application.metadata.name} 104 load={async name => { 105 return await services.applications.getApplicationSyncWindowState(name); 106 }}> 107 {(data: models.ApplicationSyncWindowState) => ( 108 <React.Fragment> 109 <div className='application-status-panel__item columns small-2' style={{position: 'relative'}}> 110 <div className='application-status-panel__item-value'> 111 {data.assignedWindows && ( 112 <React.Fragment> 113 <ApplicationSyncWindowStatusIcon project={application.spec.project} state={data} /> 114 <HelpIcon 115 title={ 116 'The aggregate state of sync windows for this app. ' + 117 'Red: no syncs allowed. ' + 118 'Yellow: manual syncs allowed. ' + 119 'Green: all syncs allowed' 120 } 121 /> 122 </React.Fragment> 123 )} 124 </div> 125 </div> 126 </React.Fragment> 127 )} 128 </DataLoader> 129 </div> 130 ); 131 };