github.com/argoproj/argo-cd@v1.8.7/ui/src/app/applications/components/applications-sync-panel/applications-sync-panel.tsx (about) 1 import {ErrorNotification, NotificationType, SlidingPanel} from 'argo-ui'; 2 import * as React from 'react'; 3 import {Checkbox, Form, FormApi} from 'react-form'; 4 import {ProgressPopup} from '../../../shared/components'; 5 import {Consumer} from '../../../shared/context'; 6 import * as models from '../../../shared/models'; 7 import {services} from '../../../shared/services'; 8 import {ComparisonStatusIcon, HealthStatusIcon, OperationPhaseIcon} from '../utils'; 9 10 interface Progress { 11 percentage: number; 12 title: string; 13 } 14 15 export const ApplicationsSyncPanel = ({show, apps, hide}: {show: boolean; apps: models.Application[]; hide: () => void}) => { 16 const [form, setForm] = React.useState<FormApi>(null); 17 const [progress, setProgress] = React.useState<Progress>(null); 18 const getSelectedApps = (params: any) => apps.filter((_, i) => params['app/' + i]); 19 return ( 20 <Consumer> 21 {ctx => ( 22 <SlidingPanel 23 isMiddle={true} 24 isShown={show} 25 onClose={() => hide()} 26 header={ 27 <div> 28 <button className='argo-button argo-button--base' onClick={() => form.submitForm(null)}> 29 Sync 30 </button>{' '} 31 <button onClick={() => hide()} className='argo-button argo-button--base-o'> 32 Cancel 33 </button> 34 </div> 35 }> 36 <Form 37 onSubmit={async (params: any) => { 38 const selectedApps = getSelectedApps(params); 39 if (selectedApps.length === 0) { 40 ctx.notifications.show({content: `No apps selected`, type: NotificationType.Error}); 41 return; 42 } 43 const syncStrategy: models.SyncStrategy = params.applyOnly ? {apply: {force: params.force}} : {hook: {force: params.force}}; 44 setProgress({percentage: 0, title: 'Starting...'}); 45 let i = 0; 46 for (const app of selectedApps) { 47 await services.applications.sync(app.metadata.name, app.spec.source.targetRevision, params.prune, params.dryRun, syncStrategy, null).catch(e => { 48 ctx.notifications.show({ 49 content: <ErrorNotification title={`Unable to sync ${app.metadata.name}`} e={e} />, 50 type: NotificationType.Error 51 }); 52 }); 53 i++; 54 setProgress({ 55 percentage: i / selectedApps.length, 56 title: `${i} of ${selectedApps.length} apps now syncing` 57 }); 58 } 59 setProgress({percentage: 100, title: 'Complete'}); 60 }} 61 getApi={setForm}> 62 {formApi => ( 63 <React.Fragment> 64 <div className='argo-form-row'> 65 <h4>Sync app(s)</h4> 66 {progress !== null && <ProgressPopup onClose={() => setProgress(null)} percentage={progress.percentage} title={progress.title} />} 67 <label>Options:</label> 68 <div style={{paddingLeft: '1em'}}> 69 <label> 70 <Checkbox field='prune' /> Prune 71 </label> 72 73 <label> 74 <Checkbox field='dryRun' /> Dry Run 75 </label> 76 77 <label> 78 <Checkbox field='applyOnly' /> Apply Only 79 </label> 80 81 <label> 82 <Checkbox field='force' /> Force 83 </label> 84 </div> 85 <label> 86 Apps (<a onClick={() => apps.forEach((_, i) => formApi.setValue('app/' + i, true))}>all</a>/ 87 <a onClick={() => apps.forEach((app, i) => formApi.setValue('app/' + i, app.status.sync.status === models.SyncStatuses.OutOfSync))}> 88 out of sync 89 </a> 90 /<a onClick={() => apps.forEach((_, i) => formApi.setValue('app/' + i, false))}>none</a> 91 ): 92 </label> 93 <div style={{paddingLeft: '1em'}}> 94 {apps.map((app, i) => ( 95 <label key={app.metadata.name}> 96 <Checkbox field={`app/${i}`} /> 97 98 {app.metadata.name} 99 100 <ComparisonStatusIcon status={app.status.sync.status} /> 101 102 <HealthStatusIcon state={app.status.health} /> 103 104 <OperationPhaseIcon app={app} /> 105 <br /> 106 </label> 107 ))} 108 </div> 109 </div> 110 </React.Fragment> 111 )} 112 </Form> 113 </SlidingPanel> 114 )} 115 </Consumer> 116 ); 117 };