]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
798307a0cf9f44502b142323e4fd48d3fa191b14
[ceph.git] /
1 import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core';
2 import { BehaviorSubject, Observable, forkJoin, of } from 'rxjs';
3 import { catchError, shareReplay, switchMap, tap } from 'rxjs/operators';
4 import { CephfsSubvolumeGroupService } from '~/app/shared/api/cephfs-subvolume-group.service';
5 import { CephfsSubvolumeService } from '~/app/shared/api/cephfs-subvolume.service';
6 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
7 import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
8 import { Icons } from '~/app/shared/enum/icons.enum';
9 import { CdTableAction } from '~/app/shared/models/cd-table-action';
10 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
11 import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
12 import { CephfsSubvolume, SubvolumeSnapshot } from '~/app/shared/models/cephfs-subvolume.model';
13 import { CephfsSubvolumeSnapshotsFormComponent } from './cephfs-subvolume-snapshots-form/cephfs-subvolume-snapshots-form.component';
14 import { ModalService } from '~/app/shared/services/modal.service';
15 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
16 import { Permissions } from '~/app/shared/models/permissions';
17 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
18 import { CdDatePipe } from '~/app/shared/pipes/cd-date.pipe';
19 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
20 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
21 import { FinishedTask } from '~/app/shared/models/finished-task';
22 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
23
24 @Component({
25   selector: 'cd-cephfs-subvolume-snapshots-list',
26   templateUrl: './cephfs-subvolume-snapshots-list.component.html',
27   styleUrls: ['./cephfs-subvolume-snapshots-list.component.scss']
28 })
29 export class CephfsSubvolumeSnapshotsListComponent implements OnInit, OnChanges {
30   @Input() fsName: string;
31
32   context: CdTableFetchDataContext;
33   columns: CdTableColumn[] = [];
34   tableActions: CdTableAction[];
35   selection = new CdTableSelection();
36   permissions: Permissions;
37   modalRef: NgbModalRef;
38
39   subVolumes$: Observable<CephfsSubvolume[]>;
40   snapshots$: Observable<any[]>;
41   snapshotSubject = new BehaviorSubject<SubvolumeSnapshot[]>([]);
42   subVolumeSubject = new BehaviorSubject<CephfsSubvolume[]>([]);
43
44   subvolumeGroupList: string[] = [];
45   subVolumesList: string[];
46
47   activeGroupName = '';
48   activeSubVolumeName = '';
49
50   isSubVolumesAvailable = false;
51   isLoading = true;
52
53   observables: any = [];
54
55   constructor(
56     private cephfsSubvolumeGroupService: CephfsSubvolumeGroupService,
57     private cephfsSubvolumeService: CephfsSubvolumeService,
58     private actionLabels: ActionLabelsI18n,
59     private modalService: ModalService,
60     private authStorageService: AuthStorageService,
61     private cdDatePipe: CdDatePipe,
62     private taskWrapper: TaskWrapperService
63   ) {
64     this.permissions = this.authStorageService.getPermissions();
65   }
66
67   ngOnInit(): void {
68     this.columns = [
69       {
70         name: $localize`Name`,
71         prop: 'name',
72         flexGrow: 1
73       },
74       {
75         name: $localize`Created`,
76         prop: 'info.created_at',
77         flexGrow: 1,
78         pipe: this.cdDatePipe
79       },
80       {
81         name: $localize`Pending Clones`,
82         prop: 'info.has_pending_clones',
83         flexGrow: 0.5,
84         cellTransformation: CellTemplate.badge,
85         customTemplateConfig: {
86           map: {
87             no: { class: 'badge-success' },
88             yes: { class: 'badge-info' }
89           }
90         }
91       }
92     ];
93
94     this.tableActions = [
95       {
96         name: this.actionLabels.CREATE,
97         permission: 'create',
98         icon: Icons.add,
99         click: () => this.openModal()
100       },
101       {
102         name: this.actionLabels.REMOVE,
103         permission: 'delete',
104         icon: Icons.destroy,
105         click: () => this.deleteSnapshot()
106       }
107     ];
108
109     this.cephfsSubvolumeGroupService
110       .get(this.fsName)
111       .pipe(
112         switchMap((groups) => {
113           // manually adding the group '_nogroup' to the list.
114           groups.unshift({ name: '' });
115
116           const observables = groups.map((group) =>
117             this.cephfsSubvolumeService.existsInFs(this.fsName, group.name).pipe(
118               switchMap((resp) => {
119                 if (resp) {
120                   this.subvolumeGroupList.push(group.name);
121                 }
122                 return of(resp); // Emit the response
123               })
124             )
125           );
126
127           return forkJoin(observables);
128         })
129       )
130       .subscribe(() => {
131         if (this.subvolumeGroupList.length) {
132           this.isSubVolumesAvailable = true;
133         }
134         this.isLoading = false;
135       });
136   }
137
138   ngOnChanges(changes: SimpleChanges): void {
139     if (changes.fsName) {
140       this.subVolumeSubject.next([]);
141     }
142   }
143
144   selectSubVolumeGroup(subVolumeGroupName: string) {
145     this.activeGroupName = subVolumeGroupName;
146     this.getSubVolumes();
147   }
148
149   selectSubVolume(subVolumeName: string) {
150     this.activeSubVolumeName = subVolumeName;
151     this.getSubVolumesSnapshot();
152   }
153
154   getSubVolumes() {
155     this.subVolumes$ = this.subVolumeSubject.pipe(
156       switchMap(() =>
157         this.cephfsSubvolumeService.get(this.fsName, this.activeGroupName, false).pipe(
158           tap((resp) => {
159             this.subVolumesList = resp.map((subVolume) => subVolume.name);
160             this.activeSubVolumeName = resp[0].name;
161             this.getSubVolumesSnapshot();
162           })
163         )
164       )
165     );
166   }
167
168   getSubVolumesSnapshot() {
169     this.snapshots$ = this.snapshotSubject.pipe(
170       switchMap(() =>
171         this.cephfsSubvolumeService
172           .getSnapshots(this.fsName, this.activeSubVolumeName, this.activeGroupName)
173           .pipe(
174             catchError(() => {
175               this.context.error();
176               return of(null);
177             })
178           )
179       ),
180       shareReplay(1)
181     );
182   }
183
184   fetchData() {
185     this.snapshotSubject.next([]);
186   }
187
188   openModal(edit = false) {
189     this.modalService.show(
190       CephfsSubvolumeSnapshotsFormComponent,
191       {
192         fsName: this.fsName,
193         subVolumeName: this.activeSubVolumeName,
194         subVolumeGroupName: this.activeGroupName,
195         subVolumeGroups: this.subvolumeGroupList,
196         isEdit: edit
197       },
198       { size: 'lg' }
199     );
200   }
201
202   updateSelection(selection: CdTableSelection) {
203     this.selection = selection;
204   }
205
206   deleteSnapshot() {
207     const snapshotName = this.selection.first().name;
208     const subVolumeName = this.activeSubVolumeName;
209     const subVolumeGroupName = this.activeGroupName;
210     const fsName = this.fsName;
211     this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
212       actionDescription: 'Remove',
213       itemNames: [snapshotName],
214       itemDescription: 'Snapshot',
215       submitAction: () =>
216         this.taskWrapper
217           .wrapTaskAroundCall({
218             task: new FinishedTask('cephfs/subvolume/snapshot/delete', {
219               fsName: fsName,
220               subVolumeName: subVolumeName,
221               subVolumeGroupName: subVolumeGroupName,
222               snapshotName: snapshotName
223             }),
224             call: this.cephfsSubvolumeService.deleteSnapshot(
225               fsName,
226               subVolumeName,
227               snapshotName,
228               subVolumeGroupName
229             )
230           })
231           .subscribe({
232             complete: () => this.modalRef.close(),
233             error: () => this.modalRef.componentInstance.stopLoadingSpinner()
234           })
235     });
236   }
237 }