]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
8b3a0f712e6354208e862c31c922a3878948ab6e
[ceph-ci.git] /
1 import { Component, OnDestroy, OnInit, TemplateRef, ViewChild } from '@angular/core';
2 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
3 import { MultiClusterService } from '~/app/shared/api/multi-cluster.service';
4 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
5 import { Icons } from '~/app/shared/enum/icons.enum';
6 import { CdTableAction } from '~/app/shared/models/cd-table-action';
7 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
8 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
9 import { ModalService } from '~/app/shared/services/modal.service';
10 import { MultiClusterFormComponent } from '../multi-cluster-form/multi-cluster-form.component';
11 import { TableComponent } from '~/app/shared/datatable/table/table.component';
12 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
13 import { Permissions } from '~/app/shared/models/permissions';
14 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
15 import { NotificationService } from '~/app/shared/services/notification.service';
16 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
17 import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
18 import { MultiCluster } from '~/app/shared/models/multi-cluster';
19 import { Router } from '@angular/router';
20 import { CookiesService } from '~/app/shared/services/cookie.service';
21 import { Observable, Subscription } from 'rxjs';
22 import { SettingsService } from '~/app/shared/api/settings.service';
23
24 @Component({
25   selector: 'cd-multi-cluster-list',
26   templateUrl: './multi-cluster-list.component.html',
27   styleUrls: ['./multi-cluster-list.component.scss']
28 })
29 export class MultiClusterListComponent implements OnInit, OnDestroy {
30   @ViewChild(TableComponent)
31   table: TableComponent;
32   @ViewChild('urlTpl', { static: true })
33   public urlTpl: TemplateRef<any>;
34
35   private subs = new Subscription();
36   permissions: Permissions;
37   tableActions: CdTableAction[];
38   clusterTokenStatus: object = {};
39   columns: Array<CdTableColumn> = [];
40   data: any;
41   selection = new CdTableSelection();
42   bsModalRef: NgbModalRef;
43   clustersTokenMap: Map<string, string> = new Map<string, string>();
44   newData: any;
45   modalRef: NgbModalRef;
46   hubUrl: string;
47   currentUrl: string;
48   icons = Icons;
49   managedByConfig$: Observable<any>;
50
51   constructor(
52     private multiClusterService: MultiClusterService,
53     private settingsService: SettingsService,
54     private router: Router,
55     public actionLabels: ActionLabelsI18n,
56     private notificationService: NotificationService,
57     private authStorageService: AuthStorageService,
58     private modalService: ModalService,
59     private cookieService: CookiesService
60   ) {
61     this.tableActions = [
62       {
63         permission: 'create',
64         icon: Icons.add,
65         name: this.actionLabels.CONNECT,
66         disable: (selection: CdTableSelection) => this.getDisable('connect', selection),
67         click: () => this.openRemoteClusterInfoModal('connect')
68       },
69       {
70         permission: 'update',
71         icon: Icons.edit,
72         name: this.actionLabels.EDIT,
73         disable: (selection: CdTableSelection) => this.getDisable('edit', selection),
74         click: () => this.openRemoteClusterInfoModal('edit')
75       },
76       {
77         permission: 'update',
78         icon: Icons.refresh,
79         name: this.actionLabels.RECONNECT,
80         disable: (selection: CdTableSelection) => this.getDisable('reconnect', selection),
81         click: () => this.openRemoteClusterInfoModal('reconnect')
82       },
83       {
84         permission: 'delete',
85         icon: Icons.destroy,
86         name: this.actionLabels.DISCONNECT,
87         disable: (selection: CdTableSelection) => this.getDisable('disconnect', selection),
88         click: () => this.openDeleteClusterModal()
89       }
90     ];
91     this.permissions = this.authStorageService.getPermissions();
92   }
93
94   ngOnInit(): void {
95     this.subs.add(
96       this.multiClusterService.subscribe((resp: object) => {
97         if (resp && resp['config']) {
98           const clusterDetailsArray = Object.values(resp['config']).flat();
99           this.data = clusterDetailsArray;
100           this.checkClusterConnectionStatus();
101         }
102       })
103     );
104
105     this.managedByConfig$ = this.settingsService.getValues('MANAGED_BY_CLUSTERS');
106
107     this.columns = [
108       {
109         prop: 'cluster_alias',
110         name: $localize`Alias`,
111         flexGrow: 2
112       },
113       {
114         prop: 'cluster_connection_status',
115         name: $localize`Connection`,
116         flexGrow: 2,
117         cellTransformation: CellTemplate.badge,
118         customTemplateConfig: {
119           map: {
120             1: { value: 'DISCONNECTED', class: 'badge-danger' },
121             0: { value: 'CONNECTED', class: 'badge-success' },
122             2: { value: 'CHECKING..', class: 'badge-info' }
123           }
124         }
125       },
126       {
127         prop: 'name',
128         name: $localize`FSID`,
129         flexGrow: 2
130       },
131       {
132         prop: 'url',
133         name: $localize`URL`,
134         flexGrow: 2,
135         cellTemplate: this.urlTpl
136       },
137       {
138         prop: 'user',
139         name: $localize`User`,
140         flexGrow: 2
141       }
142     ];
143
144     this.subs.add(
145       this.multiClusterService.subscribeClusterTokenStatus((resp: object) => {
146         this.clusterTokenStatus = resp;
147         this.checkClusterConnectionStatus();
148       })
149     );
150   }
151
152   ngOnDestroy() {
153     this.subs.unsubscribe();
154   }
155
156   checkClusterConnectionStatus() {
157     if (this.clusterTokenStatus && this.data) {
158       this.data.forEach((cluster: MultiCluster) => {
159         const clusterStatus = this.clusterTokenStatus[cluster.name.trim()];
160
161         if (clusterStatus !== undefined) {
162           cluster.cluster_connection_status = clusterStatus.status;
163         } else {
164           cluster.cluster_connection_status = 2;
165         }
166
167         if (cluster.cluster_alias === 'local-cluster') {
168           cluster.cluster_connection_status = 0;
169         }
170       });
171     }
172   }
173
174   openRemoteClusterInfoModal(action: string) {
175     const initialState = {
176       clustersData: this.data,
177       action: action,
178       cluster: this.selection.first()
179     };
180     this.bsModalRef = this.modalService.show(MultiClusterFormComponent, initialState, {
181       size: 'xl'
182     });
183     this.bsModalRef.componentInstance.submitAction.subscribe(() => {
184       const currentRoute = this.router.url.split('?')[0];
185       this.multiClusterService.refreshMultiCluster(currentRoute);
186       this.checkClusterConnectionStatus();
187       this.multiClusterService.isClusterAdded(true);
188     });
189   }
190
191   updateSelection(selection: CdTableSelection) {
192     this.selection = selection;
193   }
194
195   openDeleteClusterModal() {
196     const cluster = this.selection.first();
197     this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
198       infoMessage: $localize`Please note that the data for the disconnected cluster will be visible for a duration of ~ 5 minutes. After this period, it will be automatically removed.`,
199       actionDescription: $localize`Disconnect`,
200       itemDescription: $localize`Cluster`,
201       itemNames: [cluster['cluster_alias'] + ' - ' + cluster['user']],
202       submitAction: () =>
203         this.multiClusterService.deleteCluster(cluster['name'], cluster['user']).subscribe(() => {
204           this.cookieService.deleteToken(`${cluster['name']}-${cluster['user']}`);
205           this.multiClusterService.showPrometheusDelayMessage(true);
206           this.modalRef.close();
207           this.notificationService.show(
208             NotificationType.success,
209             $localize`Disconnected cluster '${cluster['cluster_alias']}'`
210           );
211           const currentRoute = this.router.url.split('?')[0];
212           this.multiClusterService.refreshMultiCluster(currentRoute);
213         })
214     });
215   }
216
217   getDisable(action: string, selection: CdTableSelection): string | boolean {
218     if (this.hubUrl !== this.currentUrl) {
219       return $localize`Please switch to the local-cluster to ${action} a remote cluster`;
220     }
221     if (!selection.hasSelection && action !== 'connect') {
222       return $localize`Please select one or more clusters to ${action}`;
223     }
224     if (selection.hasSingleSelection) {
225       const cluster = selection.first();
226       if (cluster['cluster_alias'] === 'local-cluster' && action !== 'connect') {
227         return $localize`Cannot ${action} local cluster`;
228       }
229     }
230     return false;
231   }
232 }