]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
b6b52a15c99d2aaabf6c9a7dfeac2eeffcc962d0
[ceph.git] /
1 import {
2   Component,
3   Input,
4   OnChanges,
5   OnDestroy,
6   OnInit,
7   SimpleChanges,
8   ViewChild
9 } from '@angular/core';
10 import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
11 import { BehaviorSubject, Observable, Subscription, of, timer } from 'rxjs';
12 import { finalize, map, shareReplay, switchMap } from 'rxjs/operators';
13 import { CephfsSnapshotScheduleService } from '~/app/shared/api/cephfs-snapshot-schedule.service';
14 import { CdForm } from '~/app/shared/forms/cd-form';
15 import { CdTableAction } from '~/app/shared/models/cd-table-action';
16 import { CdTableColumn } from '~/app/shared/models/cd-table-column';
17 import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
18 import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
19 import { Permissions } from '~/app/shared/models/permissions';
20 import { SnapshotSchedule } from '~/app/shared/models/snapshot-schedule';
21 import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
22 import { ModalService } from '~/app/shared/services/modal.service';
23 import { Icons } from '~/app/shared/enum/icons.enum';
24 import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
25 import { MgrModuleService } from '~/app/shared/api/mgr-module.service';
26 import { NotificationService } from '~/app/shared/services/notification.service';
27 import { BlockUI, NgBlockUI } from 'ng-block-ui';
28 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
29 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
30 import { CephfsSnapshotscheduleFormComponent } from '../cephfs-snapshotschedule-form/cephfs-snapshotschedule-form.component';
31
32 @Component({
33   selector: 'cd-cephfs-snapshotschedule-list',
34   templateUrl: './cephfs-snapshotschedule-list.component.html',
35   styleUrls: ['./cephfs-snapshotschedule-list.component.scss']
36 })
37 export class CephfsSnapshotscheduleListComponent
38   extends CdForm
39   implements OnInit, OnChanges, OnDestroy {
40   @Input() fsName!: string;
41   @Input() id!: number;
42
43   @ViewChild('pathTpl', { static: true })
44   pathTpl: any;
45
46   @BlockUI()
47   blockUI: NgBlockUI;
48
49   snapshotSchedules$!: Observable<SnapshotSchedule[]>;
50   subject$ = new BehaviorSubject<SnapshotSchedule[]>([]);
51   snapScheduleModuleStatus$ = new BehaviorSubject<boolean>(false);
52   moduleServiceListSub!: Subscription;
53   columns: CdTableColumn[] = [];
54   tableActions: CdTableAction[] = [];
55   context!: CdTableFetchDataContext;
56   selection = new CdTableSelection();
57   permissions!: Permissions;
58   modalRef!: NgbModalRef;
59   errorMessage: string = '';
60   selectedName: string = '';
61   icons = Icons;
62
63   MODULE_NAME = 'snap_schedule';
64   ENABLE_MODULE_TIMER = 2 * 1000;
65
66   constructor(
67     private snapshotScheduleService: CephfsSnapshotScheduleService,
68     private authStorageService: AuthStorageService,
69     private modalService: ModalService,
70     private mgrModuleService: MgrModuleService,
71     private notificationService: NotificationService,
72     private actionLables: ActionLabelsI18n
73   ) {
74     super();
75     this.permissions = this.authStorageService.getPermissions();
76   }
77
78   ngOnChanges(changes: SimpleChanges): void {
79     if (changes.fsName) {
80       this.subject$.next([]);
81     }
82   }
83
84   ngOnInit(): void {
85     this.moduleServiceListSub = this.mgrModuleService
86       .list()
87       .pipe(
88         map((modules: any[]) => modules.find((module) => module?.['name'] === this.MODULE_NAME))
89       )
90       .subscribe({
91         next: (module: any) => this.snapScheduleModuleStatus$.next(module?.enabled)
92       });
93
94     this.snapshotSchedules$ = this.subject$.pipe(
95       switchMap(() =>
96         this.snapScheduleModuleStatus$.pipe(
97           switchMap((status) => {
98             if (!status) {
99               return of([]);
100             }
101             return this.snapshotScheduleService.getSnapshotScheduleList('/', this.fsName);
102           }),
103           shareReplay(1)
104         )
105       )
106     );
107
108     this.columns = [
109       { prop: 'path', name: $localize`Path`, flexGrow: 3, cellTemplate: this.pathTpl },
110       { prop: 'subvol', name: $localize`Subvolume` },
111       { prop: 'schedule', name: $localize`Repeat interval` },
112       { prop: 'retention', name: $localize`Retention policy` },
113       { prop: 'created_count', name: $localize`Created Count` },
114       { prop: 'pruned_count', name: $localize`Deleted Count` },
115       { prop: 'start', name: $localize`Start time`, cellTransformation: CellTemplate.timeAgo },
116       { prop: 'created', name: $localize`Created`, cellTransformation: CellTemplate.timeAgo }
117     ];
118
119     this.tableActions = [
120       {
121         name: this.actionLables.CREATE,
122         permission: 'create',
123         icon: Icons.add,
124         click: () => this.openModal(false)
125       },
126       {
127         name: this.actionLables.EDIT,
128         permission: 'update',
129         icon: Icons.edit,
130         click: () => this.openModal(true)
131       }
132     ];
133   }
134
135   ngOnDestroy(): void {
136     this.moduleServiceListSub.unsubscribe();
137   }
138
139   fetchData() {
140     this.subject$.next([]);
141   }
142
143   updateSelection(selection: CdTableSelection) {
144     this.selection = selection;
145   }
146
147   openModal(edit = false) {
148     this.modalService.show(
149       CephfsSnapshotscheduleFormComponent,
150       {
151         fsName: this.fsName,
152         id: this.id,
153         path: this.selection?.first()?.path,
154         schedule: this.selection?.first()?.schedule,
155         retention: this.selection?.first()?.retention,
156         start: this.selection?.first()?.start,
157         status: this.selection?.first()?.status,
158         isEdit: edit
159       },
160       { size: 'lg' }
161     );
162   }
163
164   enableSnapshotSchedule() {
165     let $obs;
166     const fnWaitUntilReconnected = () => {
167       timer(this.ENABLE_MODULE_TIMER).subscribe(() => {
168         // Trigger an API request to check if the connection is
169         // re-established.
170         this.mgrModuleService.list().subscribe(
171           () => {
172             // Resume showing the notification toasties.
173             this.notificationService.suspendToasties(false);
174             // Unblock the whole UI.
175             this.blockUI.stop();
176             // Reload the data table content.
177             this.notificationService.show(
178               NotificationType.success,
179               $localize`Enabled Snapshot Schedule Module`
180             );
181             // Reload the data table content.
182           },
183           () => {
184             fnWaitUntilReconnected();
185           }
186         );
187       });
188     };
189
190     if (!this.snapScheduleModuleStatus$.value) {
191       $obs = this.mgrModuleService
192         .enable(this.MODULE_NAME)
193         .pipe(finalize(() => this.snapScheduleModuleStatus$.next(true)));
194     }
195     $obs.subscribe(
196       () => undefined,
197       () => {
198         // Suspend showing the notification toasties.
199         this.notificationService.suspendToasties(true);
200         // Block the whole UI to prevent user interactions until
201         // the connection to the backend is reestablished
202         this.blockUI.start($localize`Reconnecting, please wait ...`);
203         fnWaitUntilReconnected();
204       }
205     );
206   }
207 }