]> git.apps.os.sepia.ceph.com Git - ceph.git/blob
45f5dd7b2c22d1dfeb67b341c362753bb10db9a3
[ceph.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         cellTransformation: CellTemplate.badge,
68         customTemplateConfig: {
69           map: {
70             hdd: { value: 'HDD', class: 'badge-hdd' },
71             'ssd/nvme': { value: 'SSD', class: 'badge-ssd' }
72           }
73         }
74       },
75       {
76         name: this.i18n('Available'),
77         prop: 'available',
78         flexGrow: 1
79       },
80       {
81         name: this.i18n('Vendor'),
82         prop: 'sys_api.vendor',
83         flexGrow: 1
84       },
85       {
86         name: this.i18n('Model'),
87         prop: 'sys_api.model',
88         flexGrow: 1
89       },
90       {
91         name: this.i18n('Size'),
92         prop: 'sys_api.size',
93         flexGrow: 1,
94         pipe: this.dimlessBinary
95       },
96       {
97         name: this.i18n('OSDs'),
98         prop: 'osd_ids',
99         flexGrow: 1,
100         cellTransformation: CellTemplate.badge,
101         customTemplateConfig: {
102           class: 'badge-dark',
103           prefix: 'osd.'
104         }
105       }
106     ];
107
108     this.columns = columns.filter((col: any) => {
109       return !this.hiddenColumns.includes(col.prop);
110     });
111
112     // init filters
113     this.filters = this.columns
114       .filter((col: any) => {
115         return this.filterColumns.includes(col.prop);
116       })
117       .map((col: any) => {
118         return {
119           label: col.name,
120           prop: col.prop,
121           initValue: '*',
122           value: '*',
123           options: [{ value: '*', formatValue: '*' }],
124           pipe: col.pipe
125         };
126       });
127
128     this.filterInDevices = [...this.devices];
129     this.updateFilterOptions(this.devices);
130   }
131
132   ngOnChanges() {
133     this.updateFilterOptions(this.devices);
134     this.filterInDevices = [...this.devices];
135     // TODO: apply filter, columns changes, filter changes
136   }
137
138   updateFilterOptions(devices: InventoryDevice[]) {
139     // update filter options to all possible values in a column, might be time-consuming
140     this.filters.forEach((filter) => {
141       const values = _.sortedUniq(_.map(devices, filter.prop).sort());
142       const options = values.map((v: string) => {
143         return {
144           value: v,
145           formatValue: filter.pipe ? filter.pipe.transform(v) : v
146         };
147       });
148       filter.options = [{ value: '*', formatValue: '*' }, ...options];
149     });
150   }
151
152   doFilter() {
153     this.filterOutDevices = [];
154     const appliedFilters = [];
155     let devices: any = [...this.devices];
156     this.filters.forEach((filter) => {
157       if (filter.value === filter.initValue) {
158         return;
159       }
160       appliedFilters.push({
161         label: filter.label,
162         prop: filter.prop,
163         value: filter.value,
164         formatValue: filter.pipe ? filter.pipe.transform(filter.value) : filter.value
165       });
166       // Separate devices to filter-in and filter-out parts.
167       // Cast column value to string type because options are always string.
168       const parts = _.partition(devices, (row) => {
169         // use getter from ngx-datatable for props like 'sys_api.size'
170         const valueGetter = getterForProp(filter.prop);
171         return `${valueGetter(row, filter.prop)}` === filter.value;
172       });
173       devices = parts[0];
174       this.filterOutDevices = [...this.filterOutDevices, ...parts[1]];
175     });
176     this.filterInDevices = devices;
177     this.filterChange.emit({
178       filters: appliedFilters,
179       filterInDevices: this.filterInDevices,
180       filterOutDevices: this.filterOutDevices
181     });
182   }
183
184   onFilterChange() {
185     this.doFilter();
186   }
187
188   onFilterReset() {
189     this.filters.forEach((item) => {
190       item.value = item.initValue;
191     });
192     this.filterInDevices = [...this.devices];
193     this.filterOutDevices = [];
194     this.filterChange.emit({
195       filters: [],
196       filterInDevices: this.filterInDevices,
197       filterOutDevices: this.filterOutDevices
198     });
199   }
200 }