]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
3cc281f7e1ab94400d3377e9768d5424359b7b8a
[ceph-ci.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 { Subscription } from 'rxjs';
14
15 import { OrchestratorService } from '../../../../shared/api/orchestrator.service';
16 import { FormModalComponent } from '../../../../shared/components/form-modal/form-modal.component';
17 import { TableComponent } from '../../../../shared/datatable/table/table.component';
18 import { CellTemplate } from '../../../../shared/enum/cell-template.enum';
19 import { Icons } from '../../../../shared/enum/icons.enum';
20 import { NotificationType } from '../../../../shared/enum/notification-type.enum';
21 import { CdTableAction } from '../../../../shared/models/cd-table-action';
22 import { CdTableColumn } from '../../../../shared/models/cd-table-column';
23 import { CdTableColumnFiltersChange } from '../../../../shared/models/cd-table-column-filters-change';
24 import { CdTableSelection } from '../../../../shared/models/cd-table-selection';
25 import { Permission } from '../../../../shared/models/permissions';
26 import { DimlessBinaryPipe } from '../../../../shared/pipes/dimless-binary.pipe';
27 import { AuthStorageService } from '../../../../shared/services/auth-storage.service';
28 import { ModalService } from '../../../../shared/services/modal.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: ModalService,
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         cellClass: 'text-center',
121         cellTransformation: CellTemplate.checkIcon
122       },
123       {
124         name: this.i18n('Vendor'),
125         prop: 'sys_api.vendor',
126         flexGrow: 1
127       },
128       {
129         name: this.i18n('Model'),
130         prop: 'sys_api.model',
131         flexGrow: 1
132       },
133       {
134         name: this.i18n('Size'),
135         prop: 'sys_api.size',
136         flexGrow: 1,
137         pipe: this.dimlessBinary
138       },
139       {
140         name: this.i18n('OSDs'),
141         prop: 'osd_ids',
142         flexGrow: 1,
143         cellTransformation: CellTemplate.badge,
144         customTemplateConfig: {
145           class: 'badge-dark',
146           prefix: 'osd.'
147         }
148       }
149     ];
150
151     this.columns = columns.filter((col: any) => {
152       return !this.hiddenColumns.includes(col.prop);
153     });
154
155     // init column filters
156     _.forEach(this.filterColumns, (prop) => {
157       const col = _.find(this.columns, { prop: prop });
158       if (col) {
159         col.filterable = true;
160       }
161     });
162
163     if (this.fetchInventory.observers.length > 0) {
164       this.fetchInventorySub = this.table.fetchData.subscribe(() => {
165         this.fetchInventory.emit();
166       });
167     }
168   }
169
170   ngOnDestroy() {
171     if (this.fetchInventorySub) {
172       this.fetchInventorySub.unsubscribe();
173     }
174   }
175
176   onColumnFiltersChanged(event: CdTableColumnFiltersChange) {
177     this.filterChange.emit(event);
178   }
179
180   updateSelection(selection: CdTableSelection) {
181     this.selection = selection;
182   }
183
184   identifyDevice() {
185     const selected = this.selection.first();
186     const hostname = selected.hostname;
187     const device = selected.path || selected.device_id;
188     this.modalService.show(FormModalComponent, {
189       titleText: this.i18n(`Identify device {{device}}`, { device }),
190       message: this.i18n('Please enter the duration how long to blink the LED.'),
191       fields: [
192         {
193           type: 'select',
194           name: 'duration',
195           value: 300,
196           required: true,
197           typeConfig: {
198             options: [
199               { text: this.i18n('1 minute'), value: 60 },
200               { text: this.i18n('2 minutes'), value: 120 },
201               { text: this.i18n('5 minutes'), value: 300 },
202               { text: this.i18n('10 minutes'), value: 600 },
203               { text: this.i18n('15 minutes'), value: 900 }
204             ]
205           }
206         }
207       ],
208       submitButtonText: this.i18n('Execute'),
209       onSubmit: (values: any) => {
210         this.orchService.identifyDevice(hostname, device, values.duration).subscribe(() => {
211           this.notificationService.show(
212             NotificationType.success,
213             this.i18n(`Identifying '{{device}}' started on host '{{hostname}}'`, {
214               hostname,
215               device
216             })
217           );
218         });
219       }
220     });
221   }
222 }