]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard_v2: Data transform in k/v table
authorStephan Müller <smueller@suse.com>
Fri, 16 Feb 2018 16:26:44 +0000 (17:26 +0100)
committerRicardo Dias <rdias@suse.com>
Mon, 5 Mar 2018 13:07:13 +0000 (13:07 +0000)
The key value table can transform the input data into key value objects
now, you don't have to care about that anymore.

Also the first column of the data used in cd-table will be sorted if
not set manual through the "sorts" array.

Signed-off-by: Stephan Müller <smueller@suse.com>
src/pybind/mgr/dashboard_v2/frontend/src/app/ceph/rgw/rgw-daemon-details/rgw-daemon-details.component.ts
src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.html
src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.spec.ts
src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.ts
src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table/table.component.html
src/pybind/mgr/dashboard_v2/frontend/src/app/shared/datatable/table/table.component.ts

index 418f46c707c7bea4f748e521061f890431ea532b..e6be4f277a6379271bbb157e5b49c4c2aa5d5f07 100644 (file)
@@ -11,7 +11,7 @@ import { RgwDaemonService } from '../services/rgw-daemon.service';
 })
 export class RgwDaemonDetailsComponent implements OnInit {
 
-  metadata: Array<object> = [];
+  metadata: any;
   serviceId = '';
 
   @Input() selected?: Array<any> = [];
@@ -29,19 +29,9 @@ export class RgwDaemonDetailsComponent implements OnInit {
     if (_.isEmpty(this.serviceId)) {
       return;
     }
-
     this.rgwDaemonService.get(this.serviceId)
       .then((resp) => {
-        const metadata = [];
-        const keys = _.keys(resp['rgw_metadata']);
-        keys.sort();
-        _.map(keys, (key) => {
-          metadata.push({
-            'key': key,
-            'value': resp['rgw_metadata'][key]
-          });
-        });
-        this.metadata = metadata;
+        this.metadata = resp['rgw_metadata'];
       });
   }
 }
index b09e5e9e1ba3dc22aa352143616a15daab59e077..d0ab74c078636ca7d4b30e1a494758355dc76cdf 100644 (file)
@@ -1,4 +1,4 @@
-<cd-table [data]="data"
+<cd-table [data]="tableData"
           [columns]="columns"
           columnMode="flex"
           [toolHeader]="false"
index 4bbca79b78fe539ee8ea30737d02e21508d2224d..16e05bd1818c3d1355de58e41f146aee565fc299 100644 (file)
@@ -23,10 +23,77 @@ describe('TableKeyValueComponent', () => {
   beforeEach(() => {
     fixture = TestBed.createComponent(TableKeyValueComponent);
     component = fixture.componentInstance;
-    fixture.detectChanges();
   });
 
   it('should create', () => {
     expect(component).toBeTruthy();
   });
+
+  it('should make key value object pairs out of arrays with length two', () => {
+    component.data = [
+      ['someKey', 0],
+      [3, 'something'],
+    ];
+    component.ngOnInit();
+    expect(component.tableData.length).toBe(2);
+    expect(component.tableData[0].key).toBe('someKey');
+    expect(component.tableData[1].value).toBe('something');
+  });
+
+  it('should transform arrays', () => {
+    component.data = [
+      ['someKey', [1, 2, 3]],
+      [3, 'something']
+    ];
+    component.ngOnInit();
+    expect(component.tableData.length).toBe(2);
+    expect(component.tableData[0].key).toBe('someKey');
+    expect(component.tableData[0].value).toBe('1, 2, 3');
+    expect(component.tableData[1].value).toBe('something');
+  });
+
+  it('should remove pure object values', () => {
+    component.data = [
+      [3, 'something'],
+      ['will be removed', { a: 3, b: 4, c: 5}]
+    ];
+    component.ngOnInit();
+    expect(component.tableData.length).toBe(1);
+    expect(component.tableData[0].value).toBe('something');
+  });
+
+  it('should make key value object pairs out of an object', () => {
+    component.data = {
+      3: 'something',
+      someKey: 0
+    };
+    component.ngOnInit();
+    expect(component.tableData.length).toBe(2);
+    expect(component.tableData[0].value).toBe('something');
+    expect(component.tableData[1].key).toBe('someKey');
+  });
+
+  it('should make do nothing if data is correct', () => {
+    component.data = [
+      {
+        key: 3,
+        value: 'something'
+      },
+      {
+        key: 'someKey',
+        value: 0
+      }
+    ];
+    component.ngOnInit();
+    expect(component.tableData.length).toBe(2);
+    expect(component.tableData[0].value).toBe('something');
+    expect(component.tableData[1].key).toBe('someKey');
+  });
+
+  it('should throw error if miss match', () => {
+    component.data = 38;
+    expect(() => component.ngOnInit()).toThrowError('Wrong data format');
+    component.data = [['someKey', 0, 3]];
+    expect(() => component.ngOnInit()).toThrowError('Wrong array format');
+  });
 });
index 46e4f71f90ec6768d75f41f9375b24eed11db292..101580f35ef11b7a158b0625c240ba54cc2fb64e 100644 (file)
@@ -1,4 +1,6 @@
-import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
+import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
+
+import * as _ from 'lodash';
 
 import { CellTemplate } from '../../enum/cell-template.enum';
 import { CdTableColumn } from '../../models/cd-table-column';
@@ -16,28 +18,16 @@ import { CdTableColumn } from '../../models/cd-table-column';
   templateUrl: './table-key-value.component.html',
   styleUrls: ['./table-key-value.component.scss']
 })
-export class TableKeyValueComponent implements OnInit {
+export class TableKeyValueComponent implements OnInit, OnChanges {
 
   columns: Array<CdTableColumn> = [];
 
-  /**
-   * An array of objects to be displayed in the data table.
-   */
-  @Input() data: Array<object> = [];
+  @Input() data: any;
 
-  /**
-   * The name of the attribute to be displayed as key.
-   * Defaults to 'key'.
-   * @type {string}
-   */
-  @Input() key = 'key';
-
-  /**
-   * The name of the attribute to be displayed as value.
-   * Defaults to 'value'.
-   * @type {string}
-   */
-  @Input() value = 'value';
+  tableData: {
+    key: string,
+    value: any
+  }[];
 
   /**
    * The function that will be called to update the input data.
@@ -49,15 +39,58 @@ export class TableKeyValueComponent implements OnInit {
   ngOnInit() {
     this.columns = [
       {
-        prop: this.key,
+        prop: 'key',
         flexGrow: 1,
         cellTransformation: CellTemplate.bold
       },
       {
-        prop: this.value,
+        prop: 'value',
         flexGrow: 3
       }
     ];
+    this.useData();
+  }
+
+  ngOnChanges(changes) {
+    this.useData();
+  }
+
+  useData() {
+    let temp = [];
+    if (!this.data) {
+      return; // Wait for data
+    } else if (_.isArray(this.data)) {
+      const first = this.data[0];
+      if (_.isPlainObject(first) && _.has(first, 'key') && _.has(first, 'value')) {
+        temp = [...this.data];
+      } else {
+        if (_.isArray(first)) {
+          if (first.length === 2) {
+            temp = this.data.map(a => ({
+              key: a[0],
+              value: a[1]
+            }));
+          } else {
+            throw new Error('Wrong array format');
+          }
+        }
+      }
+    } else if (_.isPlainObject(this.data)) {
+      temp = Object.keys(this.data).map(k => ({
+        key: k,
+        value: this.data[k]
+      }));
+    } else {
+      throw new Error('Wrong data format');
+    }
+    this.tableData = temp.map(o => {
+      if (_.isArray(o.value)) {
+        o.value = o.value.join(', ');
+      } else if (_.isObject(o.value)) {
+        return;
+      }
+      return o;
+    }).filter(o => o); // Filters out undefined
   }
 
   reloadData() {
index a3c66b861acecff7fcde0d3701bc184fe62ba2aa..9445a5f26c121ddf33a1f77e48c35c4918066067 100644 (file)
@@ -53,6 +53,7 @@
                  [selectionType]="selectionType"
                  [selected]="selected"
                  (select)="toggleExpandRow()"
+                 [sorts]="sorts"
                  [columns]="columns"
                  [columnMode]="columnMode"
                  [rows]="rows"
index 9f0c2ad8a45087a72b6e3ff1336154ca8cb79acb..5ecba71dfcc26ca85feeba2296498494f3336f0f 100644 (file)
@@ -12,7 +12,7 @@ import {
   ViewChild
 } from '@angular/core';
 
-import { DatatableComponent } from '@swimlane/ngx-datatable';
+import { DatatableComponent, SortDirection, SortPropDir } from '@swimlane/ngx-datatable';
 import * as _ from 'lodash';
 
 import { CdTableColumn } from '../../models/cd-table-column';
@@ -34,6 +34,8 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges {
   @Input() data: any[] = [];
   // Each item -> { prop: 'attribute name', name: 'display name' }
   @Input() columns: CdTableColumn[];
+  // Each item -> { prop: 'attribute name', dir: 'asc'||'desc'}
+  @Input() sorts?: SortPropDir[];
   // Method used for setting column widths.
   @Input() columnMode ?= 'force';
   // Name of the component e.g. 'TableDetailsComponent'
@@ -87,6 +89,14 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges {
     if (this.detailsComponent) {
       this.selectionType = 'multi';
     }
+    if (!this.sorts) {
+      this.sorts = [
+        {
+          prop: this.columns[0].prop,
+          dir: SortDirection.asc
+        }
+      ];
+    }
   }
 
   ngAfterContentChecked() {
@@ -97,8 +107,7 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges {
     // https://github.com/swimlane/ngx-datatable/issues/193#issuecomment-329144543
     if (this.table && this.table.element.clientWidth !== this.currentWidth) {
       this.currentWidth = this.table.element.clientWidth;
-      // Force the redrawing of the table.
-      window.dispatchEvent(new Event('resize'));
+      this.table.recalculate();
     }
   }
 
@@ -128,6 +137,9 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges {
   }
 
   useData() {
+    if (!this.data) {
+      return; // Wait for data
+    }
     this.rows = [...this.data];
     this.loadingIndicator = false;
   }