]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
mgr/dashboard: Enable object rendering in KV-table 21701/head
authorStephan Müller <smueller@suse.com>
Fri, 27 Apr 2018 15:19:51 +0000 (17:19 +0200)
committerStephan Müller <smueller@suse.com>
Wed, 2 May 2018 10:04:10 +0000 (12:04 +0200)
Now it's possible to render objects as values in our key-value table.

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

index 16e05bd1818c3d1355de58e41f146aee565fc299..e965b6493bde11fa86f46925fcc111e6b00f31d1 100644 (file)
@@ -27,6 +27,11 @@ describe('TableKeyValueComponent', () => {
 
   it('should create', () => {
     expect(component).toBeTruthy();
+    expect(component._convertValue).toBeTruthy();
+    expect(component._makePairs).toBeTruthy();
+    expect(component._makePairsFromObject).toBeTruthy();
+    expect(component._makePairsFromArray).toBeTruthy();
+    expect(component._insertFlattenObjects).toBeTruthy();
   });
 
   it('should make key value object pairs out of arrays with length two', () => {
@@ -62,7 +67,7 @@ describe('TableKeyValueComponent', () => {
     expect(component.tableData[0].value).toBe('something');
   });
 
-  it('should make key value object pairs out of an object', () => {
+  it('makes key value object pairs out of an object', () => {
     component.data = {
       3: 'something',
       someKey: 0
@@ -73,7 +78,7 @@ describe('TableKeyValueComponent', () => {
     expect(component.tableData[1].key).toBe('someKey');
   });
 
-  it('should make do nothing if data is correct', () => {
+  it('does nothing if data is correct', () => {
     component.data = [
       {
         key: 3,
@@ -90,10 +95,113 @@ describe('TableKeyValueComponent', () => {
     expect(component.tableData[1].key).toBe('someKey');
   });
 
-  it('should throw error if miss match', () => {
+  it('throws errors 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');
+    expect(() => component.ngOnInit()).toThrowError('Wrong array format: [string, any][]');
+    component.data = [{somekey: 939, somethingElse: 'test'}];
+    expect(() => component.ngOnInit())
+      .toThrowError('Wrong object array format: {key: string, value: any}[]');
+  });
+
+  it('tests _makePairs', () => {
+    expect(component._makePairs([['dash', 'board']])).toEqual([{key: 'dash', value: 'board'}]);
+    const pair = [{key: 'dash', value: 'board'}, {key: 'ceph', value: 'mimic'}];
+    expect(component._makePairs(pair)).toEqual(pair);
+    expect(component._makePairs({dash: 'board'})).toEqual([{key: 'dash', value: 'board'}]);
+    expect(component._makePairs({dash: 'board', ceph: 'mimic'})).toEqual(pair);
+  });
+
+  it('tests _makePairsFromArray', () => {
+    expect(component._makePairsFromArray([['dash', 'board']]))
+      .toEqual([{key: 'dash', value: 'board'}]);
+    const pair = [{key: 'dash', value: 'board'}, {key: 'ceph', value: 'mimic'}];
+    expect(component._makePairsFromArray(pair)).toEqual(pair);
+  });
+
+  it('tests _makePairsFromObject', () => {
+    expect(component._makePairsFromObject({dash: 'board'}))
+      .toEqual([{key: 'dash', value: 'board'}]);
+    expect(component._makePairsFromObject({dash: 'board', ceph: 'mimic'}))
+      .toEqual([{key: 'dash', value: 'board'}, {key: 'ceph', value: 'mimic'}]);
+  });
+
+  it('tests _convertValue', () => {
+    const v = value => ({key: 'sth', value: value});
+    expect(component._convertValue(v('something'))).toEqual(v('something'));
+    expect(component._convertValue(v([1, 2, 3]))).toEqual(v('1, 2, 3'));
+    expect(component._convertValue(v({sth: 'something'}))).toBe(undefined);
+    component.renderObjects = true;
+    expect(component._convertValue(v({sth: 'something'}))).toEqual(v({sth: 'something'}));
+  });
+
+  it('tests _insertFlattenObjects', () => {
+    component.renderObjects = true;
+    const v = [
+      {
+        key: 'no',
+        value: 'change'
+      },
+      {
+        key: 'first',
+        value: {
+          second: {
+            l3_1: 33,
+            l3_2: 44
+          },
+          layer: 'something'
+        }
+      }
+    ];
+    expect(component._insertFlattenObjects(v)).toEqual([
+      {key: 'no', value: 'change'},
+      {key: 'first second l3_1', value: 33},
+      {key: 'first second l3_2', value: 44},
+      {key: 'first layer', value: 'something'}
+    ]);
+  });
+
+  describe('render objects', () => {
+    beforeEach(() => {
+      component.data = {
+        options: {
+          someSetting1: 38,
+          anotherSetting2: 'somethingElse',
+          suboptions : {
+            sub1: 12,
+            sub2: 34,
+            sub3: 56
+          }
+        },
+        someKey: 0
+      };
+      component.renderObjects = true;
+    });
+
+    it('with parent key', () => {
+      component.ngOnInit();
+      expect(component.tableData).toEqual([
+        {key: 'options someSetting1', value: 38},
+        {key: 'options anotherSetting2', value: 'somethingElse'},
+        {key: 'options suboptions sub1', value: 12},
+        {key: 'options suboptions sub2', value: 34},
+        {key: 'options suboptions sub3', value: 56},
+        {key: 'someKey', value: 0}
+      ]);
+    });
+
+    it('without parent key', () => {
+      component.appendParentKey = false;
+      component.ngOnInit();
+      expect(component.tableData).toEqual([
+        {key: 'someSetting1', value: 38},
+        {key: 'anotherSetting2', value: 'somethingElse'},
+        {key: 'sub1', value: 12},
+        {key: 'sub2', value: 34},
+        {key: 'sub3', value: 56},
+        {key: 'someKey', value: 0}
+      ]);
+    });
   });
 });
index de004797ccbc3b038b2189a34820ded7c07509cd..a6ad738073e8b9266d6505d94781849b0f3371a8 100644 (file)
@@ -25,6 +25,10 @@ export class TableKeyValueComponent implements OnInit, OnChanges {
   @Input() data: any;
   @Input() autoReload: any = 5000;
 
+  @Input() renderObjects = false;
+  // Only used if objects are rendered
+  @Input() appendParentKey = true;
+
   tableData: {
     key: string,
     value: any
@@ -57,41 +61,81 @@ export class TableKeyValueComponent implements OnInit, OnChanges {
   }
 
   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];
+    }
+    this.tableData = this._makePairs(this.data);
+  }
+
+  _makePairs(data: any) {
+    let temp = [];
+    if (!data) {
+      return; // Wait for data
+    } else if (_.isArray(data)) {
+      temp = this._makePairsFromArray(data);
+    } else if (_.isPlainObject(data)) {
+      temp = this._makePairsFromObject(data);
+    } else {
+      throw new Error('Wrong data format');
+    }
+    temp = temp.map((v) => this._convertValue(v)).filter(o => o); // Filters out undefined
+    return this.renderObjects ? this._insertFlattenObjects(temp) : temp;
+  }
+
+  _makePairsFromArray(data: any[]) {
+    let temp = [];
+    const first = data[0];
+    if (_.isPlainObject(first)) {
+      if (_.has(first, 'key') && _.has(first, 'value')) {
+        temp = [...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');
-          }
-        }
+        throw new Error('Wrong object array format: {key: string, value: any}[]');
       }
-    } 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');
+      if (_.isArray(first)) {
+        if (first.length === 2) {
+          temp = data.map(a => ({
+            key: a[0],
+            value: a[1]
+          }));
+        } else {
+          throw new Error('Wrong array format: [string, any][]');
+        }
+      }
     }
-    this.tableData = temp.map(o => {
-      if (_.isArray(o.value)) {
-        o.value = o.value.join(', ');
-      } else if (_.isObject(o.value)) {
-        return;
+    return temp;
+  }
+
+  _makePairsFromObject(data: object) {
+    return Object.keys(data).map(k => ({
+      key: k,
+      value: data[k]
+    }));
+  }
+
+  _insertFlattenObjects(temp: any[]) {
+    temp.forEach((v, i) => {
+      if (_.isPlainObject(v.value)) {
+        temp.splice(i, 1);
+        this._makePairs(v.value).forEach(item => {
+          if (this.appendParentKey) {
+            item.key = v.key + ' ' + item.key;
+          }
+          temp.splice(i, 0, item);
+          i++;
+        });
       }
-      return o;
-    }).filter(o => o); // Filters out undefined
+    });
+    return temp;
+  }
+
+  _convertValue(v: any) {
+    if (_.isArray(v.value)) {
+      v.value = v.value.join(', ');
+    } else if (_.isPlainObject(v.value) && !this.renderObjects) {
+      return;
+    }
+    return v;
   }
 
   reloadData() {