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