-<ng-container *ngIf="isLoading$ | async">
- <cd-loading-panel>
- <span i18n>Loading snapshot schedules...</span>
- </cd-loading-panel>
-</ng-container>
+<cd-alert-panel
+ *ngIf="(snapScheduleModuleStatus$ | async) === false"
+ type="info"
+ spacingClass="mb-3"
+ i18n
+ class="align-items-center"
+>
+ In order to access the snapshot scheduler feature, the snap_scheduler module must be enabled
+ <button
+ class="btn btn-light mx-2"
+ type="button"
+ (click)="enableSnapshotSchedule()">
+ Enable
+ </button>
+</cd-alert-panel>
-<ng-template #pathTpl
- let-row="row">
+<ng-template
+ #pathTpl
+ let-row="row">
<span
class="fw-bold"
[ngbTooltip]="fullpathTpl"
- triggers="click:blur">{{row.path | path}}</span>
+ triggers="click:blur">
+ {{ row.path | path }}
+ </span>
- <span *ngIf="row.active; else inactiveStatusTpl">
- <i [ngClass]="[icons.success, icons.large]"
- ngbTooltip="{{row.path}} is active"
- class="text-success"></i>
+ <span
+ *ngIf="row.active; else inactiveStatusTpl">
+ <i
+ [ngClass]="[icons.success, icons.large]"
+ ngbTooltip="{{ row.path }} is active"
+ class="text-success"
+ ></i>
</span>
<ng-template #inactiveStatusTpl>
- <i [ngClass]="[icons.warning, icons.large]"
- class="text-warning"
- ngbTooltip="{{row.path}} has been deactivated"></i>
+ <i
+ [ngClass]="[icons.warning, icons.large]"
+ class="text-warning"
+ ngbTooltip="{{ row.path }} has been deactivated"
+ ></i>
</ng-template>
<ng-template #fullpathTpl>
- <span data-toggle="tooltip"
- [title]="row.path"
- class="font-monospace">{{ row.path }}
- <cd-copy-2-clipboard-button *ngIf="row.path"
- [source]="row.path"
- [byId]="false"
- [showIconOnly]="true">
- </cd-copy-2-clipboard-button>
- </span>
-</ng-template>
-
+ <span
+ data-toggle="tooltip"
+ [title]="row.path"
+ class="font-monospace"
+ >{{ row.path }}
+ <cd-copy-2-clipboard-button
+ *ngIf="row.path"
+ [source]="row.path"
+ [byId]="false"
+ [showIconOnly]="true"
+ >
+ </cd-copy-2-clipboard-button>
+ </span>
+ </ng-template>
</ng-template>
<cd-table
[data]="snapshotSchedules$ | async"
+ *ngIf="snapScheduleModuleStatus$ | async"
columnMode="flex"
[columns]="columns"
selectionType="single"
-import { Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild } from '@angular/core';
+import {
+ Component,
+ Input,
+ OnChanges,
+ OnDestroy,
+ OnInit,
+ SimpleChanges,
+ ViewChild
+} from '@angular/core';
import { NgbModalRef } from '@ng-bootstrap/ng-bootstrap';
-import { BehaviorSubject, Observable } from 'rxjs';
-import { finalize, shareReplay, switchMap } from 'rxjs/operators';
+import { BehaviorSubject, Observable, Subscription, of, timer } from 'rxjs';
+import { finalize, map, shareReplay, switchMap } from 'rxjs/operators';
import { CephfsSnapshotScheduleService } from '~/app/shared/api/cephfs-snapshot-schedule.service';
import { CdForm } from '~/app/shared/forms/cd-form';
import { CdTableAction } from '~/app/shared/models/cd-table-action';
import { ModalService } from '~/app/shared/services/modal.service';
import { Icons } from '~/app/shared/enum/icons.enum';
import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
+import { MgrModuleService } from '~/app/shared/api/mgr-module.service';
+import { NotificationService } from '~/app/shared/services/notification.service';
+import { BlockUI, NgBlockUI } from 'ng-block-ui';
+import { NotificationType } from '~/app/shared/enum/notification-type.enum';
@Component({
selector: 'cd-cephfs-snapshotschedule-list',
templateUrl: './cephfs-snapshotschedule-list.component.html',
styleUrls: ['./cephfs-snapshotschedule-list.component.scss']
})
-export class CephfsSnapshotscheduleListComponent extends CdForm implements OnInit, OnChanges {
+export class CephfsSnapshotscheduleListComponent
+ extends CdForm
+ implements OnInit, OnChanges, OnDestroy {
@Input() fsName!: string;
@ViewChild('pathTpl', { static: true })
pathTpl: any;
+ @BlockUI()
+ blockUI: NgBlockUI;
+
snapshotSchedules$!: Observable<SnapshotSchedule[]>;
subject$ = new BehaviorSubject<SnapshotSchedule[]>([]);
- isLoading$ = new BehaviorSubject<boolean>(true);
+ snapScheduleModuleStatus$ = new BehaviorSubject<boolean>(false);
+ moduleServiceListSub!: Subscription;
columns: CdTableColumn[] = [];
tableActions: CdTableAction[] = [];
context!: CdTableFetchDataContext;
selectedName: string = '';
icons = Icons;
+ MODULE_NAME = 'snap_schedule';
+ ENABLE_MODULE_TIMER = 2 * 1000;
+
constructor(
private snapshotScheduleService: CephfsSnapshotScheduleService,
private authStorageService: AuthStorageService,
- private modalService: ModalService
+ private modalService: ModalService,
+ private mgrModuleService: MgrModuleService,
+ private notificationService: NotificationService
) {
super();
this.permissions = this.authStorageService.getPermissions();
}
ngOnInit(): void {
+ this.moduleServiceListSub = this.mgrModuleService
+ .list()
+ .pipe(
+ map((modules: any[]) => modules.find((module) => module?.['name'] === this.MODULE_NAME))
+ )
+ .subscribe({
+ next: (module: any) => this.snapScheduleModuleStatus$.next(module?.enabled)
+ });
+
this.snapshotSchedules$ = this.subject$.pipe(
switchMap(() =>
- this.snapshotScheduleService
- .getSnapshotScheduleList('/', this.fsName)
- .pipe(finalize(() => this.isLoading$.next(false)))
- ),
- shareReplay(1)
+ this.snapScheduleModuleStatus$.pipe(
+ switchMap((status) => {
+ if (!status) {
+ return of([]);
+ }
+ return this.snapshotScheduleService.getSnapshotScheduleList('/', this.fsName);
+ }),
+ shareReplay(1)
+ )
+ )
);
this.columns = [
this.tableActions = [];
}
+ ngOnDestroy(): void {
+ this.moduleServiceListSub.unsubscribe();
+ }
+
fetchData() {
this.subject$.next([]);
}
{ size: 'lg' }
);
}
+
+ enableSnapshotSchedule() {
+ let $obs;
+ const fnWaitUntilReconnected = () => {
+ timer(this.ENABLE_MODULE_TIMER).subscribe(() => {
+ // Trigger an API request to check if the connection is
+ // re-established.
+ this.mgrModuleService.list().subscribe(
+ () => {
+ // Resume showing the notification toasties.
+ this.notificationService.suspendToasties(false);
+ // Unblock the whole UI.
+ this.blockUI.stop();
+ // Reload the data table content.
+ this.notificationService.show(
+ NotificationType.success,
+ $localize`Enabled Snapshot Schedule Module`
+ );
+ // Reload the data table content.
+ },
+ () => {
+ fnWaitUntilReconnected();
+ }
+ );
+ });
+ };
+
+ if (!this.snapScheduleModuleStatus$.value) {
+ $obs = this.mgrModuleService
+ .enable(this.MODULE_NAME)
+ .pipe(finalize(() => this.snapScheduleModuleStatus$.next(true)));
+ }
+ $obs.subscribe(
+ () => undefined,
+ () => {
+ // Suspend showing the notification toasties.
+ this.notificationService.suspendToasties(true);
+ // Block the whole UI to prevent user interactions until
+ // the connection to the backend is reestablished
+ this.blockUI.start($localize`Reconnecting, please wait ...`);
+ fnWaitUntilReconnected();
+ }
+ );
+ }
}