]> git.apps.os.sepia.ceph.com Git - ceph-ci.git/blob
b54d846eef1cc76e27abe080ee5a3c38946b69ad
[ceph-ci.git] /
1 import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
2 import { I18n } from '@ngx-translate/i18n-polyfill';
3
4 import { getterForProp } from '@swimlane/ngx-datatable/release/utils';
5 import * as _ from 'lodash';
6
7 import { CellTemplate } from '../../../../shared/enum/cell-template.enum';
8 import { Icons } from '../../../../shared/enum/icons.enum';
9 import { CdTableColumn } from '../../../../shared/models/cd-table-column';
10 import { DimlessBinaryPipe } from '../../../../shared/pipes/dimless-binary.pipe';
11 import { InventoryDeviceFilter } from './inventory-device-filter.interface';
12 import { InventoryDeviceFiltersChangeEvent } from './inventory-device-filters-change-event.interface';
13 import { InventoryDevice } from './inventory-device.model';
14
15 @Component({
16   selector: 'cd-inventory-devices',
17   templateUrl: './inventory-devices.component.html',
18   styleUrls: ['./inventory-devices.component.scss']
19 })
20 export class InventoryDevicesComponent implements OnInit, OnChanges {
21   // Devices
22   @Input() devices: InventoryDevice[] = [];
23
24   // Do not display these columns
25   @Input() hiddenColumns: string[] = [];
26
27   // Show filters for these columns, specify empty array to disable
28   @Input() filterColumns = [
29     'hostname',
30     'human_readable_type',
31     'available',
32     'sys_api.vendor',
33     'sys_api.model',
34     'sys_api.size'
35   ];
36
37   // Device table row selection type
38   @Input() selectionType: string = undefined;
39
40   @Output() filterChange = new EventEmitter<InventoryDeviceFiltersChangeEvent>();
41
42   filterInDevices: InventoryDevice[] = [];
43   filterOutDevices: InventoryDevice[] = [];
44
45   icons = Icons;
46   columns: Array<CdTableColumn> = [];
47   filters: InventoryDeviceFilter[] = [];
48
49   constructor(private dimlessBinary: DimlessBinaryPipe, private i18n: I18n) {}
50
51   ngOnInit() {
52     const columns = [
53       {
54         name: this.i18n('Hostname'),
55         prop: 'hostname',
56         flexGrow: 1
57       },
58       {
59         name: this.i18n('Device path'),
60         prop: 'path',
61         flexGrow: 1
62       },
63       {
64         name: this.i18n('Type'),
65         prop: 'human_readable_type',
66         flexGrow: 1,
67         cellClass: 'text-center',
68         cellTransformation: CellTemplate.badge,
69         customTemplateConfig: {
70           map: {
71             hdd: { value: 'HDD', class: 'badge-hdd' },
72             'ssd/nvme': { value: 'SSD', class: 'badge-ssd' }
73           }
74         }
75       },
76       {
77         name: this.i18n('Available'),
78         prop: 'available',
79         flexGrow: 1
80       },
81       {
82         name: this.i18n('Vendor'),
83         prop: 'sys_api.vendor',
84         flexGrow: 1
85       },
86       {
87         name: this.i18n('Model'),
88         prop: 'sys_api.model',
89         flexGrow: 1
90       },
91       {
92         name: this.i18n('Size'),
93         prop: 'sys_api.size',
94         flexGrow: 1,
95         pipe: this.dimlessBinary
96       },
97       {
98         name: this.i18n('OSDs'),
99         prop: 'osd_ids',
100         flexGrow: 1,
101         cellClass: 'text-center',
102         cellTransformation: CellTemplate.badge,
103         customTemplateConfig: {
104           class: 'badge-dark',
105           prefix: 'osd.'
106         }
107       }
108     ];
109
110     this.columns = columns.filter((col: any) => {
111       return !this.hiddenColumns.includes(col.prop);
112     });
113
114     // init filters
115     this.filters = this.columns
116       .filter((col: any) => {
117         return this.filterColumns.includes(col.prop);
118       })
119       .map((col: any) => {
120         return {
121           label: col.name,
122           prop: col.prop,
123           initValue: '*',
124           value: '*',
125           options: [{ value: '*', formatValue: '*' }],
126           pipe: col.pipe
127         };
128       });
129
130     this.filterInDevices = [...this.devices];
131     this.updateFilterOptions(this.devices);
132   }
133
134   ngOnChanges() {
135     this.updateFilterOptions(this.devices);
136     this.filterInDevices = [...this.devices];
137     // TODO: apply filter, columns changes, filter changes
138   }
139
140   updateFilterOptions(devices: InventoryDevice[]) {
141     // update filter options to all possible values in a column, might be time-consuming
142     this.filters.forEach((filter) => {
143       const values = _.sortedUniq(_.map(devices, filter.prop).sort());
144       const options = values.map((v: string) => {
145         return {
146           value: v,
147           formatValue: filter.pipe ? filter.pipe.transform(v) : v
148         };
149       });
150       filter.options = [{ value: '*', formatValue: '*' }, ...options];
151     });
152   }
153
154   doFilter() {
155     this.filterOutDevices = [];
156     const appliedFilters = [];
157     let devices: any = [...this.devices];
158     this.filters.forEach((filter) => {
159       if (filter.value === filter.initValue) {
160         return;
161       }
162       appliedFilters.push({
163         label: filter.label,
164         prop: filter.prop,
165         value: filter.value,
166         formatValue: filter.pipe ? filter.pipe.transform(filter.value) : filter.value
167       });
168       // Separate devices to filter-in and filter-out parts.
169       // Cast column value to string type because options are always string.
170       const parts = _.partition(devices, (row) => {
171         // use getter from ngx-datatable for props like 'sys_api.size'
172         const valueGetter = getterForProp(filter.prop);
173         return `${valueGetter(row, filter.prop)}` === filter.value;
174       });
175       devices = parts[0];
176       this.filterOutDevices = [...this.filterOutDevices, ...parts[1]];
177     });
178     this.filterInDevices = devices;
179     this.filterChange.emit({
180       filters: appliedFilters,
181       filterInDevices: this.filterInDevices,
182       filterOutDevices: this.filterOutDevices
183     });
184   }
185
186   onFilterChange() {
187     this.doFilter();
188   }
189
190   onFilterReset() {
191     this.filters.forEach((item) => {
192       item.value = item.initValue;
193     });
194     this.filterInDevices = [...this.devices];
195     this.filterOutDevices = [];
196     this.filterChange.emit({
197       filters: [],
198       filterInDevices: this.filterInDevices,
199       filterOutDevices: this.filterOutDevices
200     });
201   }
202 }