]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
755f3e73d5f3b3a49b1f6081749b476139303ba3
[ceph.git] /
1 import { Component, ViewChild } from '@angular/core';
2
3 import { I18n } from '@ngx-translate/i18n-polyfill';
4 import { BlockUI, NgBlockUI } from 'ng-block-ui';
5 import { timer as observableTimer } from 'rxjs';
6
7 import { MgrModuleService } from '../../../../shared/api/mgr-module.service';
8 import { TableComponent } from '../../../../shared/datatable/table/table.component';
9 import { CellTemplate } from '../../../../shared/enum/cell-template.enum';
10 import { Icons } from '../../../../shared/enum/icons.enum';
11 import { CdTableAction } from '../../../../shared/models/cd-table-action';
12 import { CdTableColumn } from '../../../../shared/models/cd-table-column';
13 import { CdTableFetchDataContext } from '../../../../shared/models/cd-table-fetch-data-context';
14 import { CdTableSelection } from '../../../../shared/models/cd-table-selection';
15 import { Permission } from '../../../../shared/models/permissions';
16 import { AuthStorageService } from '../../../../shared/services/auth-storage.service';
17 import { NotificationService } from '../../../../shared/services/notification.service';
18
19 @Component({
20   selector: 'cd-mgr-module-list',
21   templateUrl: './mgr-module-list.component.html',
22   styleUrls: ['./mgr-module-list.component.scss']
23 })
24 export class MgrModuleListComponent {
25   @ViewChild(TableComponent, { static: true })
26   table: TableComponent;
27   @BlockUI()
28   blockUI: NgBlockUI;
29
30   permission: Permission;
31   tableActions: CdTableAction[];
32   columns: CdTableColumn[] = [];
33   modules: object[] = [];
34   selection: CdTableSelection = new CdTableSelection();
35
36   constructor(
37     private authStorageService: AuthStorageService,
38     private mgrModuleService: MgrModuleService,
39     private notificationService: NotificationService,
40     private i18n: I18n
41   ) {
42     this.permission = this.authStorageService.getPermissions().configOpt;
43     this.columns = [
44       {
45         name: this.i18n('Name'),
46         prop: 'name',
47         flexGrow: 1
48       },
49       {
50         name: this.i18n('Enabled'),
51         prop: 'enabled',
52         flexGrow: 1,
53         cellClass: 'text-center',
54         cellTransformation: CellTemplate.checkIcon
55       }
56     ];
57     const getModuleUri = () =>
58       this.selection.first() && encodeURIComponent(this.selection.first().name);
59     this.tableActions = [
60       {
61         name: this.i18n('Edit'),
62         permission: 'update',
63         disable: () => {
64           if (!this.selection.hasSelection) {
65             return true;
66           }
67           // Disable the 'edit' button when the module has no options.
68           return Object.values(this.selection.first().options).length === 0;
69         },
70         routerLink: () => `/mgr-modules/edit/${getModuleUri()}`,
71         icon: Icons.edit
72       },
73       {
74         name: this.i18n('Enable'),
75         permission: 'update',
76         click: () => this.updateModuleState(),
77         disable: () => this.isTableActionDisabled('enabled'),
78         icon: Icons.start
79       },
80       {
81         name: this.i18n('Disable'),
82         permission: 'update',
83         click: () => this.updateModuleState(),
84         disable: () => this.isTableActionDisabled('disabled'),
85         disableDesc: () => this.getTableActionDisabledDesc(),
86         icon: Icons.stop
87       }
88     ];
89   }
90
91   getModuleList(context: CdTableFetchDataContext) {
92     this.mgrModuleService.list().subscribe(
93       (resp: object[]) => {
94         this.modules = resp;
95       },
96       () => {
97         context.error();
98       }
99     );
100   }
101
102   updateSelection(selection: CdTableSelection) {
103     this.selection = selection;
104   }
105
106   /**
107    * Check if the table action is disabled.
108    * @param state The expected module state, e.g. ``enabled`` or ``disabled``.
109    * @returns If the specified state is validated to true or no selection is
110    *   done, then ``true`` is returned, otherwise ``false``.
111    */
112   isTableActionDisabled(state: 'enabled' | 'disabled') {
113     if (!this.selection.hasSelection) {
114       return true;
115     }
116     const selected = this.selection.first();
117     // Make sure the user can't modify the run state of the 'Dashboard' module.
118     // This check is only done in the UI because the REST API should still be
119     // able to do so.
120     if (selected.name === 'dashboard') {
121       return true;
122     }
123     // Always-on modules can't be disabled.
124     if (selected.always_on) {
125       return true;
126     }
127     switch (state) {
128       case 'enabled':
129         return selected.enabled;
130       case 'disabled':
131         return !selected.enabled;
132     }
133   }
134
135   getTableActionDisabledDesc(): string | undefined {
136     if (this.selection.hasSelection) {
137       const selected = this.selection.first();
138       if (selected.always_on) {
139         return this.i18n('This Manager module is always on.');
140       }
141     }
142
143     return undefined;
144   }
145
146   /**
147    * Update the Ceph Mgr module state to enabled or disabled.
148    */
149   updateModuleState() {
150     if (!this.selection.hasSelection) {
151       return;
152     }
153
154     let $obs;
155     const fnWaitUntilReconnected = () => {
156       observableTimer(2000).subscribe(() => {
157         // Trigger an API request to check if the connection is
158         // re-established.
159         this.mgrModuleService.list().subscribe(
160           () => {
161             // Resume showing the notification toasties.
162             this.notificationService.suspendToasties(false);
163             // Unblock the whole UI.
164             this.blockUI.stop();
165             // Reload the data table content.
166             this.table.refreshBtn();
167           },
168           () => {
169             fnWaitUntilReconnected();
170           }
171         );
172       });
173     };
174
175     // Note, the Ceph Mgr is always restarted when a module
176     // is enabled/disabled.
177     const module = this.selection.first();
178     if (module.enabled) {
179       $obs = this.mgrModuleService.disable(module.name);
180     } else {
181       $obs = this.mgrModuleService.enable(module.name);
182     }
183     $obs.subscribe(
184       () => {},
185       () => {
186         // Suspend showing the notification toasties.
187         this.notificationService.suspendToasties(true);
188         // Block the whole UI to prevent user interactions until
189         // the connection to the backend is reestablished
190         this.blockUI.start(this.i18n('Reconnecting, please wait ...'));
191         fnWaitUntilReconnected();
192       }
193     );
194   }
195 }