From 98fc5f9b5056590975fd2cf96cd03e2027fa7c7d Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stephan=20M=C3=BCller?= Date: Fri, 27 Apr 2018 17:19:51 +0200 Subject: [PATCH] mgr/dashboard: Enable object rendering in KV-table MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Now it's possible to render objects as values in our key-value table. Signed-off-by: Stephan Müller --- .../table-key-value.component.spec.ts | 116 +++++++++++++++++- .../table-key-value.component.ts | 100 ++++++++++----- 2 files changed, 184 insertions(+), 32 deletions(-) diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.spec.ts index 16e05bd1818c3..e965b6493bde1 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.spec.ts @@ -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} + ]); + }); }); }); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.ts index de004797ccbc3..a6ad738073e8b 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table-key-value/table-key-value.component.ts @@ -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() { -- 2.39.5