]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
1a48903510c1a46aceccd9a93d694bbe77377c22
[ceph.git] /
1 import {
2   Component,
3   EventEmitter,
4   Input,
5   OnDestroy,
6   OnInit,
7   Output,
8   ViewChild
9 } from '@angular/core';
10
11 import { I18n } from '@ngx-translate/i18n-polyfill';
12 import * as _ from 'lodash';
13 import { BsModalService } from 'ngx-bootstrap/modal';
14 import { Subscription } from 'rxjs';
15
16 import { OrchestratorService } from '../../../../shared/api/orchestrator.service';
17 import { FormModalComponent } from '../../../../shared/components/form-modal/form-modal.component';
18 import { TableComponent } from '../../../../shared/datatable/table/table.component';
19 import { CellTemplate } from '../../../../shared/enum/cell-template.enum';
20 import { Icons } from '../../../../shared/enum/icons.enum';
21 import { NotificationType } from '../../../../shared/enum/notification-type.enum';
22 import { CdTableAction } from '../../../../shared/models/cd-table-action';
23 import { CdTableColumn } from '../../../../shared/models/cd-table-column';
24 import { CdTableColumnFiltersChange } from '../../../../shared/models/cd-table-column-filters-change';
25 import { CdTableSelection } from '../../../../shared/models/cd-table-selection';
26 import { Permission } from '../../../../shared/models/permissions';
27 import { DimlessBinaryPipe } from '../../../../shared/pipes/dimless-binary.pipe';
28 import { AuthStorageService } from '../../../../shared/services/auth-storage.service';
29 import { NotificationService } from '../../../../shared/services/notification.service';
30 import { InventoryDevice } from './inventory-device.model';
31
32 @Component({
33   selector: 'cd-inventory-devices',
34   templateUrl: './inventory-devices.component.html',
35   styleUrls: ['./inventory-devices.component.scss']
36 })
37 export class InventoryDevicesComponent implements OnInit, OnDestroy {
38   @ViewChild(TableComponent, { static: true })
39   table: TableComponent;
40
41   // Devices
42   @Input() devices: InventoryDevice[] = [];
43
44   // Do not display these columns
45   @Input() hiddenColumns: string[] = [];
46
47   // Show filters for these columns, specify empty array to disable
48   @Input() filterColumns = [
49     'hostname',
50     'human_readable_type',
51     'available',
52     'sys_api.vendor',
53     'sys_api.model',
54     'sys_api.size'
55   ];
56
57   // Device table row selection type
58   @Input() selectionType: string = undefined;
59
60   @Output() filterChange = new EventEmitter<CdTableColumnFiltersChange>();
61
62   @Output() fetchInventory = new EventEmitter();
63
64   icons = Icons;
65   columns: Array<CdTableColumn> = [];
66   selection: CdTableSelection = new CdTableSelection();
67   permission: Permission;
68   tableActions: CdTableAction[];
69   fetchInventorySub: Subscription;
70
71   constructor(
72     private authStorageService: AuthStorageService,
73     private dimlessBinary: DimlessBinaryPipe,
74     private i18n: I18n,
75     private modalService: BsModalService,
76     private notificationService: NotificationService,
77     private orchService: OrchestratorService
78   ) {}
79
80   ngOnInit() {
81     this.permission = this.authStorageService.getPermissions().osd;
82     this.tableActions = [
83       {
84         permission: 'update',
85         icon: Icons.show,
86         click: () => this.identifyDevice(),
87         name: this.i18n('Identify'),
88         disable: () => !this.selection.hasSingleSelection,
89         canBePrimary: (selection: CdTableSelection) => !selection.hasSingleSelection,
90         visible: () => _.isString(this.selectionType)
91       }
92     ];
93     const columns = [
94       {
95         name: this.i18n('Hostname'),
96         prop: 'hostname',
97         flexGrow: 1
98       },
99       {
100         name: this.i18n('Device path'),
101         prop: 'path',
102         flexGrow: 1
103       },
104       {
105         name: this.i18n('Type'),
106         prop: 'human_readable_type',
107         flexGrow: 1,
108         cellTransformation: CellTemplate.badge,
109         customTemplateConfig: {
110           map: {
111             hdd: { value: 'HDD', class: 'badge-hdd' },
112             ssd: { value: 'SSD', class: 'badge-ssd' }
113           }
114         }
115       },
116       {
117         name: this.i18n('Available'),
118         prop: 'available',
119         flexGrow: 1
120       },
121       {
122         name: this.i18n('Vendor'),
123         prop: 'sys_api.vendor',
124         flexGrow: 1
125       },
126       {
127         name: this.i18n('Model'),
128         prop: 'sys_api.model',
129         flexGrow: 1
130       },
131       {
132         name: this.i18n('Size'),
133         prop: 'sys_api.size',
134         flexGrow: 1,
135         pipe: this.dimlessBinary
136       },
137       {
138         name: this.i18n('OSDs'),
139         prop: 'osd_ids',
140         flexGrow: 1,
141         cellTransformation: CellTemplate.badge,
142         customTemplateConfig: {
143           class: 'badge-dark',
144           prefix: 'osd.'
145         }
146       }
147     ];
148
149     this.columns = columns.filter((col: any) => {
150       return !this.hiddenColumns.includes(col.prop);
151     });
152
153     // init column filters
154     _.forEach(this.filterColumns, (prop) => {
155       const col = _.find(this.columns, { prop: prop });
156       if (col) {
157         col.filterable = true;
158       }
159     });
160
161     if (this.fetchInventory.observers.length > 0) {
162       this.fetchInventorySub = this.table.fetchData.subscribe(() => {
163         this.fetchInventory.emit();
164       });
165     }
166   }
167
168   ngOnDestroy() {
169     if (this.fetchInventorySub) {
170       this.fetchInventorySub.unsubscribe();
171     }
172   }
173
174   onColumnFiltersChanged(event: CdTableColumnFiltersChange) {
175     this.filterChange.emit(event);
176   }
177
178   updateSelection(selection: CdTableSelection) {
179     this.selection = selection;
180   }
181
182   identifyDevice() {
183     const selected = this.selection.first();
184     const hostname = selected.hostname;
185     const device = selected.path || selected.device_id;
186     this.modalService.show(FormModalComponent, {
187       initialState: {
188         titleText: this.i18n(`Identify device {{device}}`, { device }),
189         message: this.i18n('Please enter the duration how long to blink the LED.'),
190         fields: [
191           {
192             type: 'select',
193             name: 'duration',
194             value: 300,
195             required: true,
196             typeConfig: {
197               options: [
198                 { text: this.i18n('1 minute'), value: 60 },
199                 { text: this.i18n('2 minutes'), value: 120 },
200                 { text: this.i18n('5 minutes'), value: 300 },
201                 { text: this.i18n('10 minutes'), value: 600 },
202                 { text: this.i18n('15 minutes'), value: 900 }
203               ]
204             }
205           }
206         ],
207         submitButtonText: this.i18n('Execute'),
208         onSubmit: (values: any) => {
209           this.orchService.identifyDevice(hostname, device, values.duration).subscribe(() => {
210             this.notificationService.show(
211               NotificationType.success,
212               this.i18n(`Identifying '{{device}}' started on host '{{hostname}}'`, {
213                 hostname,
214                 device
215               })
216             );
217           });
218         }
219       }
220     });
221   }
222 }