argo-cd

Форк
0
159 строк · 8.1 Кб
1
import {ErrorNotification, FormField, NotificationType, SlidingPanel} from 'argo-ui';
2
import * as React from 'react';
3
import {Form, FormApi} from 'react-form';
4
import {ARGO_WARNING_COLOR, ProgressPopup, Spinner} from '../../../shared/components';
5
import {Consumer, ContextApis} from '../../../shared/context';
6
import * as models from '../../../shared/models';
7
import {services} from '../../../shared/services';
8
import {ApplicationRetryOptions} from '../application-retry-options/application-retry-options';
9
import {ApplicationManualSyncFlags, ApplicationSyncOptions, FORCE_WARNING, SyncFlags} from '../application-sync-options/application-sync-options';
10
import {ApplicationSelector} from '../../../shared/components';
11
import {confirmSyncingAppOfApps, getAppDefaultSource} from '../utils';
12

13
interface Progress {
14
    percentage: number;
15
    title: string;
16
}
17

18
export const ApplicationsSyncPanel = ({show, apps, hide}: {show: boolean; apps: models.Application[]; hide: () => void}) => {
19
    const [form, setForm] = React.useState<FormApi>(null);
20
    const [progress, setProgress] = React.useState<Progress>(null);
21
    const getSelectedApps = (params: any) => apps.filter((_, i) => params['app/' + i]);
22
    const [isPending, setPending] = React.useState(false);
23
    const syncHandler = (currentForm: FormApi, ctx: ContextApis, applications: models.Application[]) => {
24
        const formValues = currentForm.getFormState().values;
25
        const replaceChecked = formValues.syncOptions?.includes('Replace=true');
26
        const selectedApps = [];
27
        const selectedAppOfApps: models.Application[] = [];
28
        let containAppOfApps = false;
29

30
        for (const key in formValues) {
31
            if (key.startsWith('app/') && formValues[key]) {
32
                selectedApps.push(applications[parseInt(key.slice(key.lastIndexOf('/') + 1), 10)]);
33
            }
34
        }
35

36
        selectedApps.forEach(app => {
37
            if (app.isAppOfAppsPattern) {
38
                containAppOfApps = true;
39
                selectedAppOfApps.push(app);
40
            }
41
        });
42

43
        if (replaceChecked && containAppOfApps) {
44
            confirmSyncingAppOfApps(selectedAppOfApps, ctx, currentForm).then(confirmed => {
45
                setPending(confirmed ? true : false);
46
            });
47
        } else {
48
            currentForm.submitForm(null);
49
        }
50
    };
51
    return (
52
        <Consumer>
53
            {ctx => (
54
                <SlidingPanel
55
                    isMiddle={true}
56
                    isShown={show}
57
                    onClose={() => hide()}
58
                    header={
59
                        <div>
60
                            <button className='argo-button argo-button--base' disabled={isPending} onClick={() => syncHandler(form, ctx, apps)}>
61
                                <Spinner show={isPending} style={{marginRight: '5px'}} />
62
                                Sync
63
                            </button>{' '}
64
                            <button onClick={() => hide()} className='argo-button argo-button--base-o'>
65
                                Cancel
66
                            </button>
67
                        </div>
68
                    }>
69
                    <Form
70
                        defaultValues={{syncFlags: []}}
71
                        onSubmit={async (params: any) => {
72
                            setPending(true);
73
                            const selectedApps = getSelectedApps(params);
74
                            const syncFlags = {...params.syncFlags} as SyncFlags;
75
                            const force = syncFlags.Force || false;
76
                            if (force) {
77
                                const confirmed = await ctx.popup.confirm('Synchronize with force?', () => (
78
                                    <div>
79
                                        <i className='fa fa-exclamation-triangle' style={{color: ARGO_WARNING_COLOR}} /> {FORCE_WARNING} Are you sure you want to continue?
80
                                    </div>
81
                                ));
82
                                if (!confirmed) {
83
                                    setPending(false);
84
                                    return;
85
                                }
86
                            }
87
                            if (selectedApps.length === 0) {
88
                                ctx.notifications.show({content: `No apps selected`, type: NotificationType.Error});
89
                                setPending(false);
90
                                return;
91
                            }
92

93
                            const syncStrategy: models.SyncStrategy = syncFlags.ApplyOnly || false ? {apply: {force}} : {hook: {force}};
94

95
                            setProgress({percentage: 0, title: 'Starting...'});
96
                            let i = 0;
97
                            for (const app of selectedApps) {
98
                                await services.applications
99
                                    .sync(
100
                                        app.metadata.name,
101
                                        app.metadata.namespace,
102
                                        getAppDefaultSource(app).targetRevision,
103
                                        syncFlags.Prune || false,
104
                                        syncFlags.DryRun || false,
105
                                        syncStrategy,
106
                                        null,
107
                                        params.syncOptions,
108
                                        params.retryStrategy
109
                                    )
110
                                    .catch(e => {
111
                                        ctx.notifications.show({
112
                                            content: <ErrorNotification title={`Unable to sync ${app.metadata.name}`} e={e} />,
113
                                            type: NotificationType.Error
114
                                        });
115
                                    })
116
                                    .finally(() => {
117
                                        setPending(false);
118
                                    });
119
                                i++;
120
                                setProgress({
121
                                    percentage: i / selectedApps.length,
122
                                    title: `${i} of ${selectedApps.length} apps now syncing`
123
                                });
124
                            }
125
                            setProgress({percentage: 100, title: 'Complete'});
126
                        }}
127
                        getApi={setForm}>
128
                        {formApi => (
129
                            <React.Fragment>
130
                                <div className='argo-form-row' style={{marginTop: 0}}>
131
                                    <h4>Sync app(s)</h4>
132
                                    {progress !== null && <ProgressPopup onClose={() => setProgress(null)} percentage={progress.percentage} title={progress.title} />}
133
                                    <div style={{marginBottom: '1em'}}>
134
                                        <FormField formApi={formApi} field='syncFlags' component={ApplicationManualSyncFlags} />
135
                                    </div>
136
                                    <div style={{marginBottom: '1em'}}>
137
                                        <label>Sync Options</label>
138
                                        <ApplicationSyncOptions
139
                                            options={formApi.values.syncOptions}
140
                                            onChanged={opts => {
141
                                                formApi.setTouched('syncOptions', true);
142
                                                formApi.setValue('syncOptions', opts);
143
                                            }}
144
                                            id='applications-sync-panel'
145
                                        />
146
                                    </div>
147

148
                                    <ApplicationRetryOptions id='applications-sync-panel' formApi={formApi} />
149

150
                                    <ApplicationSelector apps={apps} formApi={formApi} />
151
                                </div>
152
                            </React.Fragment>
153
                        )}
154
                    </Form>
155
                </SlidingPanel>
156
            )}
157
        </Consumer>
158
    );
159
};
160

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.