]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
f6135515aa36c5c64d990d7024d83d056b1ed9b9
[ceph-ci.git] /
1 import { Component, Input, OnChanges, SimpleChanges, TemplateRef, ViewChild } from '@angular/core';
2 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
3 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
4 import { Icons } from '~/app/shared/enum/icons.enum';
5 import { CdTableAction } from '~/app/shared/models/cd-table-action';
6 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
7 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
8 import { Permission } from '~/app/shared/models/permissions';
9 import { ModalService } from '~/app/shared/services/modal.service';
10 import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
11 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
12 import { FinishedTask } from '~/app/shared/models/finished-task';
13 import { Observable, Subscriber, forkJoin as observableForkJoin } from 'rxjs';
14 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
15 import { TableComponent } from '~/app/shared/datatable/table/table.component';
16 import { RgwMultisiteSyncFlowModalComponent } from '../rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component';
17 import { FlowType } from '../models/rgw-multisite';
18 import { RgwMultisiteSyncPipeModalComponent } from '../rgw-multisite-sync-pipe-modal/rgw-multisite-sync-pipe-modal.component';
19 import { ModalCdsService } from '~/app/shared/services/modal-cds.service';
20 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
21
22 enum MultisiteResourceType {
23   flow = 'flow',
24   pipe = 'pipe'
25 }
26
27 @Component({
28   selector: 'cd-rgw-multisite-sync-policy-details',
29   templateUrl: './rgw-multisite-sync-policy-details.component.html',
30   styleUrls: ['./rgw-multisite-sync-policy-details.component.scss']
31 })
32 export class RgwMultisiteSyncPolicyDetailsComponent implements OnChanges {
33   @Input()
34   expandedRow: any;
35   @Input()
36   permission: Permission;
37
38   @ViewChild(TableComponent)
39   table: TableComponent;
40   @ViewChild('deleteTpl', { static: true })
41   deleteTpl: TemplateRef<any>;
42
43   resourceType: MultisiteResourceType = MultisiteResourceType.flow;
44   flowType = FlowType;
45   modalRef: NgbModalRef;
46   symmetricalFlowData: any = [];
47   directionalFlowData: any = [];
48   pipeData: any = [];
49   symmetricalFlowCols: CdTableColumn[];
50   directionalFlowCols: CdTableColumn[];
51   pipeCols: CdTableColumn[];
52   symFlowTableActions: CdTableAction[];
53   dirFlowTableActions: CdTableAction[];
54   pipeTableActions: CdTableAction[];
55   symFlowSelection = new CdTableSelection();
56   dirFlowSelection = new CdTableSelection();
57   pipeSelection = new CdTableSelection();
58
59   constructor(
60     private actionLabels: ActionLabelsI18n,
61     private modalService: ModalService,
62     private rgwMultisiteService: RgwMultisiteService,
63     private taskWrapper: TaskWrapperService,
64     private cdsModalService: ModalCdsService
65   ) {
66     this.symmetricalFlowCols = [
67       {
68         name: 'Name',
69         prop: 'id',
70         flexGrow: 1
71       },
72       {
73         name: 'Zones',
74         prop: 'zones',
75         flexGrow: 1
76       }
77     ];
78     this.directionalFlowCols = [
79       {
80         name: 'Source Zone',
81         prop: 'source_zone',
82         flexGrow: 1
83       },
84       {
85         name: 'Destination Zone',
86         prop: 'dest_zone',
87         flexGrow: 1
88       }
89     ];
90     this.pipeCols = [
91       {
92         name: 'Name',
93         prop: 'id',
94         flexGrow: 1
95       },
96       {
97         name: 'Source Zone',
98         prop: 'source.zones',
99         flexGrow: 1
100       },
101       {
102         name: 'Destination Zone',
103         prop: 'dest.zones',
104         flexGrow: 1
105       },
106       {
107         name: 'Source Bucket',
108         prop: 'source.bucket',
109         flexGrow: 1
110       },
111       {
112         name: 'Destination Bucket',
113         prop: 'dest.bucket',
114         flexGrow: 1
115       }
116     ];
117     const symAddAction: CdTableAction = {
118       permission: 'create',
119       icon: Icons.add,
120       name: this.actionLabels.CREATE,
121       click: () => this.openModal(FlowType.symmetrical),
122       canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
123     };
124     const symEditAction: CdTableAction = {
125       permission: 'update',
126       icon: Icons.edit,
127       name: this.actionLabels.EDIT,
128       click: () => this.openModal(FlowType.symmetrical, true)
129     };
130     const symDeleteAction: CdTableAction = {
131       permission: 'delete',
132       icon: Icons.destroy,
133       disable: () => !this.symFlowSelection.hasSelection,
134       name: this.actionLabels.DELETE,
135       click: () => this.deleteFlow(FlowType.symmetrical),
136       canBePrimary: (selection: CdTableSelection) => selection.hasMultiSelection
137     };
138     this.symFlowTableActions = [symAddAction, symEditAction, symDeleteAction];
139     const dirAddAction: CdTableAction = {
140       permission: 'create',
141       icon: Icons.add,
142       name: this.actionLabels.CREATE,
143       click: () => this.openModal(FlowType.directional),
144       canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
145     };
146     const dirDeleteAction: CdTableAction = {
147       permission: 'delete',
148       icon: Icons.destroy,
149       // TODO: disabling 'delete' as we are not getting flow_id from backend which is needed for deletion
150       disable: () =>
151         'Deleting the directional flow is disabled in the UI. Please use CLI to delete the directional flow',
152       name: this.actionLabels.DELETE,
153       click: () => this.deleteFlow(FlowType.directional),
154       canBePrimary: (selection: CdTableSelection) => selection.hasSelection
155     };
156     this.dirFlowTableActions = [dirAddAction, dirDeleteAction];
157     const pipeAddAction: CdTableAction = {
158       permission: 'create',
159       icon: Icons.add,
160       name: this.actionLabels.CREATE,
161       click: () => this.openPipeModal(),
162       canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
163     };
164     const pipeEditAction: CdTableAction = {
165       permission: 'update',
166       icon: Icons.edit,
167       name: this.actionLabels.EDIT,
168       click: () => this.openPipeModal(true)
169     };
170     const pipeDeleteAction: CdTableAction = {
171       permission: 'delete',
172       icon: Icons.destroy,
173       disable: () => !this.pipeSelection.hasSelection,
174       name: this.actionLabels.DELETE,
175       click: () => this.deletePipe(),
176       canBePrimary: (selection: CdTableSelection) => selection.hasMultiSelection
177     };
178     this.pipeTableActions = [pipeAddAction, pipeEditAction, pipeDeleteAction];
179   }
180
181   ngOnChanges(changes: SimpleChanges): void {
182     if (changes.expandedRow.currentValue && changes.expandedRow.currentValue.groupName) {
183       this.symmetricalFlowData = [];
184       this.directionalFlowData = [];
185       this.loadData();
186     }
187   }
188
189   loadData(context?: any) {
190     if (this.expandedRow) {
191       this.rgwMultisiteService
192         .getSyncPolicyGroup(this.expandedRow.groupName, this.expandedRow.bucket)
193         .subscribe(
194           (policy: any) => {
195             this.symmetricalFlowData = policy.data_flow[FlowType.symmetrical] || [];
196             this.directionalFlowData = policy.data_flow[FlowType.directional] || [];
197             this.pipeData = policy.pipes || [];
198           },
199           () => {
200             if (context) {
201               context.error();
202             }
203           }
204         );
205     }
206   }
207
208   updateSelection(selection: any, type: FlowType) {
209     if (type === FlowType.directional) {
210       this.dirFlowSelection = selection;
211     } else {
212       this.symFlowSelection = selection;
213     }
214   }
215
216   async openModal(flowType: FlowType, edit = false) {
217     const action = edit ? 'edit' : 'create';
218     const initialState = {
219       groupType: flowType,
220       groupExpandedRow: this.expandedRow,
221       flowSelectedRow:
222         flowType === FlowType.symmetrical
223           ? this.symFlowSelection.first()
224           : this.dirFlowSelection.first(),
225       action: action
226     };
227
228     this.modalRef = this.modalService.show(RgwMultisiteSyncFlowModalComponent, initialState, {
229       size: 'lg'
230     });
231
232     try {
233       const res = await this.modalRef.result;
234       if (res === NotificationType.success) {
235         this.loadData();
236       }
237     } catch (err) {}
238   }
239
240   deleteFlow(flowType: FlowType) {
241     this.resourceType = MultisiteResourceType.flow;
242     let selection = this.symFlowSelection;
243     if (flowType === FlowType.directional) {
244       selection = this.dirFlowSelection;
245     }
246     const flowIds = selection.selected.map((flow: any) => flow.id);
247     this.cdsModalService.show(CriticalConfirmationModalComponent, {
248       itemDescription: selection.hasSingleSelection ? $localize`Flow` : $localize`Flows`,
249       itemNames: flowIds,
250       bodyTemplate: this.deleteTpl,
251       submitActionObservable: () => {
252         return new Observable((observer: Subscriber<any>) => {
253           this.taskWrapper
254             .wrapTaskAroundCall({
255               task: new FinishedTask('rgw/multisite/sync-flow/delete', {
256                 flow_ids: flowIds
257               }),
258               call: observableForkJoin(
259                 selection.selected.map((flow: any) => {
260                   return this.rgwMultisiteService.removeSyncFlow(
261                     flow.id,
262                     flowType,
263                     this.expandedRow.groupName,
264                     this.expandedRow.bucket
265                   );
266                 })
267               )
268             })
269             .subscribe({
270               error: (error: any) => {
271                 // Forward the error to the observer.
272                 observer.error(error);
273                 // Reload the data table content because some deletions might
274                 // have been executed successfully in the meanwhile.
275                 this.table.refreshBtn();
276               },
277               complete: () => {
278                 // Notify the observer that we are done.
279                 observer.complete();
280                 // Reload the data table content.
281                 this.table.refreshBtn();
282               }
283             });
284         });
285       }
286     });
287   }
288
289   async openPipeModal(edit = false) {
290     const action = edit ? 'edit' : 'create';
291     const initialState = {
292       groupExpandedRow: this.expandedRow,
293       pipeSelectedRow: this.pipeSelection.first(),
294       action: action
295     };
296
297     this.modalRef = this.modalService.show(RgwMultisiteSyncPipeModalComponent, initialState, {
298       size: 'lg'
299     });
300
301     try {
302       const res = await this.modalRef.result;
303       if (res === NotificationType.success) {
304         this.loadData();
305       }
306     } catch (err) {}
307   }
308
309   deletePipe() {
310     this.resourceType = MultisiteResourceType.pipe;
311     const pipeIds = this.pipeSelection.selected.map((pipe: any) => pipe.id);
312     this.cdsModalService.show(CriticalConfirmationModalComponent, {
313       itemDescription: this.pipeSelection.hasSingleSelection ? $localize`Pipe` : $localize`Pipes`,
314       itemNames: pipeIds,
315       bodyTemplate: this.deleteTpl,
316       submitActionObservable: () => {
317         return new Observable((observer: Subscriber<any>) => {
318           this.taskWrapper
319             .wrapTaskAroundCall({
320               task: new FinishedTask('rgw/multisite/sync-pipe/delete', {
321                 pipe_ids: pipeIds
322               }),
323               call: observableForkJoin(
324                 this.pipeSelection.selected.map((pipe: any) => {
325                   return this.rgwMultisiteService.removeSyncPipe(
326                     pipe.id,
327                     this.expandedRow.groupName,
328                     this.expandedRow.bucket
329                   );
330                 })
331               )
332             })
333             .subscribe({
334               error: (error: any) => {
335                 // Forward the error to the observer.
336                 observer.error(error);
337                 // Reload the data table content because some deletions might
338                 // have been executed successfully in the meanwhile.
339                 this.table.refreshBtn();
340               },
341               complete: () => {
342                 // Notify the observer that we are done.
343                 observer.complete();
344                 // Reload the data table content.
345                 this.table.refreshBtn();
346               }
347             });
348         });
349       }
350     });
351   }
352 }