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