]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: improve device selection modal for creating OSDs 33081/head
authorKiefer Chang <kiefer.chang@suse.com>
Tue, 21 Jan 2020 15:44:01 +0000 (23:44 +0800)
committerKiefer Chang <kiefer.chang@suse.com>
Tue, 3 Mar 2020 14:25:51 +0000 (22:25 +0800)
Display a hint that user should select at least one filter that can be
translated into DriveGroup attributes.

The total capacity are going to be added is also displayed.

Fixes: https://tracker.ceph.com/issues/43166
Signed-off-by: Kiefer Chang <kiefer.chang@suse.com>
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-devices-selection-groups/osd-devices-selection-groups.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-devices-selection-groups/osd-devices-selection-groups.component.ts
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-devices-selection-modal/osd-devices-selection-modal.component.html
src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/osd/osd-devices-selection-modal/osd-devices-selection-modal.component.ts

index 71ff430a051a3a77eabddeb96dd6c0866080c1c8..bfbf3dcf143b426318cc5535e9d56b763b5ffe5e 100644 (file)
@@ -17,6 +17,8 @@
       <button type="button"
               class="btn btn-light"
               (click)="showSelectionModal()"
+              data-toggle="tooltip"
+              [title]="addButtonTooltip"
               [disabled]="availDevices.length === 0 || !canSelect">
         <i [ngClass]="[icons.add]"></i>
         <ng-container i18n>Add</ng-container>
       </div>
       <div>
         <cd-inventory-devices [devices]="devices"
-                              [hiddenColumns]="['available']"
+                              [hiddenColumns]="['available', 'osd_ids']"
                               [filterColumns]="[]">
         </cd-inventory-devices>
       </div>
+      <div *ngIf="type === 'data'"
+           class="float-right">
+        <span i18n>Raw capacity: {{ capacity | dimlessBinary }}</span>
+      </div>
     </ng-template>
   </div>
 </div>
index dd3e711d72f75de20d00b0fe8a54d32ce81a897c..aea4c17d9d87a5916e8cf53ecdc3d03133064841 100644 (file)
@@ -1,4 +1,5 @@
-import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
+import { I18n } from '@ngx-translate/i18n-polyfill';
 
 import * as _ from 'lodash';
 
@@ -15,7 +16,7 @@ import { DevicesSelectionClearEvent } from './devices-selection-clear-event.inte
   templateUrl: './osd-devices-selection-groups.component.html',
   styleUrls: ['./osd-devices-selection-groups.component.scss']
 })
-export class OsdDevicesSelectionGroupsComponent {
+export class OsdDevicesSelectionGroupsComponent implements OnInit, OnChanges {
   // data, wal, db
   @Input() type: string;
 
@@ -36,9 +37,25 @@ export class OsdDevicesSelectionGroupsComponent {
 
   icons = Icons;
   devices: InventoryDevice[] = [];
+  capacity = 0;
   appliedFilters: any[] = [];
 
-  constructor(private bsModalService: BsModalService) {}
+  addButtonTooltip: String;
+  tooltips = {
+    noAvailDevices: this.i18n('No available devices'),
+    addPrimaryFirst: this.i18n('Please add primary devices first'),
+    addByFilters: this.i18n('Add devices by using filters')
+  };
+
+  constructor(private bsModalService: BsModalService, private i18n: I18n) {}
+
+  ngOnInit() {
+    this.updateAddButtonTooltip();
+  }
+
+  ngOnChanges() {
+    this.updateAddButtonTooltip();
+  }
 
   showSelectionModal() {
     let filterColumns = ['human_readable_type', 'sys_api.vendor', 'sys_api.model', 'sys_api.size'];
@@ -57,12 +74,28 @@ export class OsdDevicesSelectionGroupsComponent {
     const modalRef = this.bsModalService.show(OsdDevicesSelectionModalComponent, options);
     modalRef.content.submitAction.subscribe((result: CdTableColumnFiltersChange) => {
       this.devices = result.data;
+      this.capacity = _.sumBy(this.devices, 'sys_api.size');
       this.appliedFilters = result.filters;
       const event = _.assign({ type: this.type }, result);
       this.selected.emit(event);
     });
   }
 
+  private updateAddButtonTooltip() {
+    if (this.type === 'data' && this.availDevices.length === 0) {
+      this.addButtonTooltip = this.tooltips.noAvailDevices;
+    } else {
+      if (!this.canSelect) {
+        // No primary devices added yet.
+        this.addButtonTooltip = this.tooltips.addPrimaryFirst;
+      } else if (this.availDevices.length === 0) {
+        this.addButtonTooltip = this.tooltips.noAvailDevices;
+      } else {
+        this.addButtonTooltip = this.tooltips.addByFilters;
+      }
+    }
+  }
+
   clearDevices() {
     const event = {
       type: this.type,
index 1c51e174c9afbe14c37953d6df9e9994911abdb1..733c207684d9a363a741d41c85f9169ac2c2870d 100644 (file)
@@ -1,18 +1,33 @@
 <cd-modal [modalRef]="bsModalRef">
   <ng-container class="modal-title"
-                i18n>Add {{ deviceType }} devices</ng-container>
+                i18n>{{ deviceType }} devices</ng-container>
 
   <ng-container class="modal-content">
     <form #frm="ngForm"
           [formGroup]="formGroup"
           novalidate>
       <div class="modal-body">
-        <div class="col-sm-12">
-          <cd-inventory-devices [devices]="devices"
-                                [filterColumns]="filterColumns"
-                                [hiddenColumns]="['available', 'osd_ids']"
-                                (filterChange)="onFilterChange($event)">
-          </cd-inventory-devices>
+        <cd-alert-panel *ngIf="!canSubmit"
+                        type="warning"
+                        size="slim"
+                        [showTitle]="false">
+          <ng-container i18n>At least one of these filters must be applied in order to proceed:</ng-container>
+          <span *ngFor="let filter of requiredFilters"
+                class="badge badge-dark ml-2">
+            {{ filter }}
+          </span>
+        </cd-alert-panel>
+        <cd-inventory-devices #inventoryDevices
+                              [devices]="devices"
+                              [filterColumns]="filterColumns"
+                              [hiddenColumns]="['available', 'osd_ids']"
+                              (filterChange)="onFilterChange($event)">
+        </cd-inventory-devices>
+        <div *ngIf="canSubmit">
+          <p class="text-center">
+            <span i18n>Number of devices: {{ filteredDevices.length }}. Raw capacity:
+              {{ capacity | dimlessBinary }}.</span>
+          </p>
         </div>
       </div>
       <div class="modal-footer">
index 4094617aba98f5bb95e15e8b118d66cd2c6a8c07..070d338670e9c5ae6e853fbc5129e2463f713e42 100644 (file)
@@ -1,26 +1,31 @@
-import { Component, EventEmitter, Output } from '@angular/core';
+import { AfterViewInit, Component, EventEmitter, Output, ViewChild } from '@angular/core';
 
 import * as _ from 'lodash';
 import { BsModalRef } from 'ngx-bootstrap/modal';
 
+import { TableColumnProp } from '@swimlane/ngx-datatable';
 import { ActionLabelsI18n } from '../../../../shared/constants/app.constants';
 import { Icons } from '../../../../shared/enum/icons.enum';
 import { CdFormBuilder } from '../../../../shared/forms/cd-form-builder';
 import { CdFormGroup } from '../../../../shared/forms/cd-form-group';
 import { CdTableColumnFiltersChange } from '../../../../shared/models/cd-table-column-filters-change';
 import { InventoryDevice } from '../../inventory/inventory-devices/inventory-device.model';
+import { InventoryDevicesComponent } from '../../inventory/inventory-devices/inventory-devices.component';
 
 @Component({
   selector: 'cd-osd-devices-selection-modal',
   templateUrl: './osd-devices-selection-modal.component.html',
   styleUrls: ['./osd-devices-selection-modal.component.scss']
 })
-export class OsdDevicesSelectionModalComponent {
+export class OsdDevicesSelectionModalComponent implements AfterViewInit {
+  @ViewChild('inventoryDevices', { static: false })
+  inventoryDevices: InventoryDevicesComponent;
+
   @Output()
   submitAction = new EventEmitter<CdTableColumnFiltersChange>();
 
   icons = Icons;
-  filterColumns: string[] = [];
+  filterColumns: TableColumnProp[] = [];
 
   hostname: string;
   deviceType: string;
@@ -29,8 +34,10 @@ export class OsdDevicesSelectionModalComponent {
 
   devices: InventoryDevice[] = [];
   filteredDevices: InventoryDevice[] = [];
+  capacity = 0;
   event: CdTableColumnFiltersChange;
   canSubmit = false;
+  requiredFilters: string[] = [];
 
   constructor(
     private formBuilder: CdFormBuilder,
@@ -41,11 +48,21 @@ export class OsdDevicesSelectionModalComponent {
     this.createForm();
   }
 
+  ngAfterViewInit() {
+    // At least one filter other than hostname is required
+    // Extract the name from table columns for i18n strings
+    const cols = _.filter(this.inventoryDevices.columns, (col) => {
+      return this.filterColumns.includes(col.prop) && col.prop !== 'hostname';
+    });
+    this.requiredFilters = _.map(cols, 'name');
+  }
+
   createForm() {
     this.formGroup = this.formBuilder.group({});
   }
 
   onFilterChange(event: CdTableColumnFiltersChange) {
+    this.capacity = 0;
     this.canSubmit = false;
     if (_.isEmpty(event.filters)) {
       // filters are cleared
@@ -58,6 +75,7 @@ export class OsdDevicesSelectionModalComponent {
       });
       this.canSubmit = !_.isEmpty(filters);
       this.filteredDevices = event.data;
+      this.capacity = _.sumBy(this.filteredDevices, 'sys_api.size');
       this.event = event;
     }
   }