]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
4f9cf27db0ffd91143ed69a92ced4390db380663
[ceph.git] /
1 import {
2   Component,
3   Input,
4   OnChanges,
5   OnInit,
6   SimpleChanges,
7   TemplateRef,
8   ViewChild
9 } from '@angular/core';
10 import { BehaviorSubject, Observable, of } from 'rxjs';
11 import { catchError, switchMap, tap } from 'rxjs/operators';
12 import { CephfsSubvolumeService } from '~/app/shared/api/cephfs-subvolume.service';
13 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
14 import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
15 import { Icons } from '~/app/shared/enum/icons.enum';
16 import { CdTableAction } from '~/app/shared/models/cd-table-action';
17 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
18 import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
19 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
20 import { CephfsSubvolume } from '~/app/shared/models/cephfs-subvolume.model';
21 import { ModalService } from '~/app/shared/services/modal.service';
22 import { CephfsSubvolumeFormComponent } from '../cephfs-subvolume-form/cephfs-subvolume-form.component';
23 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
24 import { Permissions } from '~/app/shared/models/permissions';
25 import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
26 import { FinishedTask } from '~/app/shared/models/finished-task';
27 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
28 import { FormControl } from '@angular/forms';
29 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
30 import { CdForm } from '~/app/shared/forms/cd-form';
31 import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
32 import { CephfsSubvolumeGroupService } from '~/app/shared/api/cephfs-subvolume-group.service';
33 import { CephfsSubvolumeGroup } from '~/app/shared/models/cephfs-subvolume-group.model';
34
35 @Component({
36   selector: 'cd-cephfs-subvolume-list',
37   templateUrl: './cephfs-subvolume-list.component.html',
38   styleUrls: ['./cephfs-subvolume-list.component.scss']
39 })
40 export class CephfsSubvolumeListComponent extends CdForm implements OnInit, OnChanges {
41   @ViewChild('quotaUsageTpl', { static: true })
42   quotaUsageTpl: any;
43
44   @ViewChild('typeTpl', { static: true })
45   typeTpl: any;
46
47   @ViewChild('modeToHumanReadableTpl', { static: true })
48   modeToHumanReadableTpl: any;
49
50   @ViewChild('nameTpl', { static: true })
51   nameTpl: any;
52
53   @ViewChild('quotaSizeTpl', { static: true })
54   quotaSizeTpl: any;
55
56   @ViewChild('removeTmpl', { static: true })
57   removeTmpl: TemplateRef<any>;
58
59   @Input() fsName: string;
60   @Input() pools: any[];
61
62   columns: CdTableColumn[] = [];
63   tableActions: CdTableAction[];
64   context: CdTableFetchDataContext;
65   selection = new CdTableSelection();
66   removeForm: CdFormGroup;
67   icons = Icons;
68   permissions: Permissions;
69   modalRef: NgbModalRef;
70   errorMessage: string = '';
71   selectedName: string = '';
72
73   subVolumes$: Observable<CephfsSubvolume[]>;
74   subVolumeGroups$: Observable<CephfsSubvolumeGroup[]>;
75   subject = new BehaviorSubject<CephfsSubvolume[]>([]);
76   groupsSubject = new BehaviorSubject<CephfsSubvolume[]>([]);
77
78   subvolumeGroupList: string[] = [];
79   subVolumesList: CephfsSubvolume[] = [];
80
81   activeGroupName: string = '';
82
83   constructor(
84     private cephfsSubVolumeService: CephfsSubvolumeService,
85     private actionLabels: ActionLabelsI18n,
86     private modalService: ModalService,
87     private authStorageService: AuthStorageService,
88     private taskWrapper: TaskWrapperService,
89     private cephfsSubvolumeGroupService: CephfsSubvolumeGroupService
90   ) {
91     super();
92     this.permissions = this.authStorageService.getPermissions();
93   }
94
95   ngOnInit(): void {
96     this.columns = [
97       {
98         name: $localize`Name`,
99         prop: 'name',
100         flexGrow: 1,
101         cellTemplate: this.nameTpl
102       },
103       {
104         name: $localize`Data Pool`,
105         prop: 'info.data_pool',
106         flexGrow: 0.7,
107         cellTransformation: CellTemplate.badge,
108         customTemplateConfig: {
109           class: 'badge-background-primary'
110         }
111       },
112       {
113         name: $localize`Usage`,
114         prop: 'info.bytes_pcent',
115         flexGrow: 0.7,
116         cellTemplate: this.quotaUsageTpl,
117         cellClass: 'text-right'
118       },
119       {
120         name: $localize`Path`,
121         prop: 'info.path',
122         flexGrow: 1,
123         cellTransformation: CellTemplate.path
124       },
125       {
126         name: $localize`Mode`,
127         prop: 'info.mode',
128         flexGrow: 0.5,
129         cellTemplate: this.modeToHumanReadableTpl
130       },
131       {
132         name: $localize`Created`,
133         prop: 'info.created_at',
134         flexGrow: 0.5,
135         cellTransformation: CellTemplate.timeAgo
136       }
137     ];
138
139     this.tableActions = [
140       {
141         name: this.actionLabels.CREATE,
142         permission: 'create',
143         icon: Icons.add,
144         click: () => this.openModal()
145       },
146       {
147         name: this.actionLabels.EDIT,
148         permission: 'update',
149         icon: Icons.edit,
150         click: () => this.openModal(true)
151       },
152       {
153         name: this.actionLabels.REMOVE,
154         permission: 'delete',
155         icon: Icons.destroy,
156         click: () => this.removeSubVolumeModal()
157       }
158     ];
159
160     this.subVolumeGroups$ = this.groupsSubject.pipe(
161       switchMap(() =>
162         this.cephfsSubvolumeGroupService.get(this.fsName, false).pipe(
163           tap((groups) => {
164             this.subvolumeGroupList = groups.map((group) => group.name);
165             this.subvolumeGroupList.unshift('');
166           }),
167           catchError(() => {
168             this.context.error();
169             return of(null);
170           })
171         )
172       )
173     );
174   }
175
176   fetchData() {
177     this.subject.next([]);
178   }
179
180   ngOnChanges(changes: SimpleChanges) {
181     if (changes.fsName) {
182       this.subject.next([]);
183       this.groupsSubject.next([]);
184     }
185   }
186
187   updateSelection(selection: CdTableSelection) {
188     this.selection = selection;
189   }
190
191   openModal(edit = false) {
192     this.modalService.show(
193       CephfsSubvolumeFormComponent,
194       {
195         fsName: this.fsName,
196         subVolumeName: this.selection?.first()?.name,
197         subVolumeGroupName: this.activeGroupName,
198         pools: this.pools,
199         isEdit: edit
200       },
201       { size: 'lg' }
202     );
203   }
204
205   removeSubVolumeModal() {
206     this.removeForm = new CdFormGroup({
207       retainSnapshots: new FormControl(false)
208     });
209     this.errorMessage = '';
210     this.selectedName = this.selection.first().name;
211     this.modalRef = this.modalService.show(CriticalConfirmationModalComponent, {
212       actionDescription: 'Remove',
213       itemNames: [this.selectedName],
214       itemDescription: 'Subvolume',
215       childFormGroup: this.removeForm,
216       childFormGroupTemplate: this.removeTmpl,
217       submitAction: () =>
218         this.taskWrapper
219           .wrapTaskAroundCall({
220             task: new FinishedTask('cephfs/subvolume/remove', { subVolumeName: this.selectedName }),
221             call: this.cephfsSubVolumeService.remove(
222               this.fsName,
223               this.selectedName,
224               this.activeGroupName,
225               this.removeForm.getValue('retainSnapshots')
226             )
227           })
228           .subscribe({
229             complete: () => this.modalRef.close(),
230             error: (error) => {
231               this.modalRef.componentInstance.stopLoadingSpinner();
232               this.errorMessage = error.error.detail;
233             }
234           })
235     });
236   }
237
238   selectSubVolumeGroup(subVolumeGroupName: string) {
239     this.activeGroupName = subVolumeGroupName;
240     this.getSubVolumes();
241   }
242
243   getSubVolumes() {
244     this.subVolumes$ = this.subject.pipe(
245       switchMap(() =>
246         this.cephfsSubVolumeService.get(this.fsName, this.activeGroupName).pipe(
247           catchError(() => {
248             this.context.error();
249             return of(null);
250           })
251         )
252       )
253     );
254   }
255 }