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