From 1033314a24d331702676be28e0c2e7e9fa314f00 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Stephan=20M=C3=BCller?= Date: Thu, 10 Jan 2019 14:58:39 +0100 Subject: [PATCH] mgr/dashboard: Render all objects in KV-table MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The problem was that the key value table didn't render all objects in the given object, even if 'renderObjects' was set to true. For example you give it an object with 2 attributes each of them holds a non empty object, this will result in a table data that is not fully converted to key value objects, which will result as text '[Object object]' in the table view. Now every object will be rendered and the key value array will be sorted by key. Fixes: https://tracker.ceph.com/issues/37859 Signed-off-by: Stephan Müller --- .../table-key-value.component.spec.ts | 55 +++++++------------ .../table-key-value.component.ts | 51 +++++++++-------- 2 files changed, 46 insertions(+), 60 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 cb69b3badfa16..f697b2c1b5368 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 @@ -130,9 +130,10 @@ describe('TableKeyValueComponent', () => { 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); + const pairInverse = [{ key: 'ceph', value: 'mimic' }, { key: 'dash', value: 'board' }]; + expect(component._makePairs(pair)).toEqual(pairInverse); expect(component._makePairs({ dash: 'board' })).toEqual([{ key: 'dash', value: 'board' }]); - expect(component._makePairs({ dash: 'board', ceph: 'mimic' })).toEqual(pair); + expect(component._makePairs({ dash: 'board', ceph: 'mimic' })).toEqual(pairInverse); }); it('tests _makePairsFromArray', () => { @@ -179,32 +180,6 @@ describe('TableKeyValueComponent', () => { }); }); - 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 layer', value: 'something' }, - { key: 'first second l3_1', value: 33 }, - { key: 'first second l3_2', value: 44 } - ]); - }); - describe('render objects', () => { beforeEach(() => { component.data = { @@ -218,6 +193,14 @@ describe('TableKeyValueComponent', () => { } }, someKey: 0, + o2: { + sub1: { + x: 42 + }, + sub2: { + y: 555 + } + }, additionalKeyContainingObject: { type: 'none' }, keyWithEmptyObject: {} }; @@ -227,14 +210,16 @@ describe('TableKeyValueComponent', () => { it('with parent key', () => { component.ngOnInit(); expect(component.tableData).toEqual([ - { key: 'someKey', value: 0 }, + { key: 'additionalKeyContainingObject type', value: 'none' }, { key: 'keyWithEmptyObject', value: '' }, - { key: 'options someSetting1', value: 38 }, + { key: 'o2 sub1 x', value: 42 }, + { key: 'o2 sub2 y', value: 555 }, { key: 'options anotherSetting2', value: 'somethingElse' }, + { key: 'options someSetting1', value: 38 }, { key: 'options suboptions sub1', value: 12 }, { key: 'options suboptions sub2', value: 34 }, { key: 'options suboptions sub3', value: 56 }, - { key: 'additionalKeyContainingObject type', value: 'none' } + { key: 'someKey', value: 0 } ]); }); @@ -242,14 +227,16 @@ describe('TableKeyValueComponent', () => { component.appendParentKey = false; component.ngOnInit(); expect(component.tableData).toEqual([ - { key: 'someKey', value: 0 }, + { key: 'anotherSetting2', value: 'somethingElse' }, { key: 'keyWithEmptyObject', value: '' }, + { key: 'someKey', value: 0 }, { key: 'someSetting1', value: 38 }, - { key: 'anotherSetting2', value: 'somethingElse' }, { key: 'sub1', value: 12 }, { key: 'sub2', value: 34 }, { key: 'sub3', value: 56 }, - { key: 'type', value: 'none' } + { key: 'type', value: 'none' }, + { key: 'x', value: 42 }, + { key: 'y', value: 555 } ]); }); }); 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 500ee033d3922..3bc9d2a1281af 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 @@ -107,7 +107,7 @@ export class TableKeyValueComponent implements OnInit, OnChanges { 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; + return _.sortBy(this.renderObjects ? this.insertFlattenObjects(temp) : temp, 'key'); } _makePairsFromArray(data: any[]): Item[] { @@ -142,34 +142,33 @@ export class TableKeyValueComponent implements OnInit, OnChanges { })); } - _insertFlattenObjects(temp: any[]) { - const itemsToRemoveIndexes = []; - const itemsToAdd = []; - temp.forEach((v, i) => { - if (_.isObject(v.value)) { - if (_.isEmpty(v.value)) { - temp[i]['value'] = ''; - } else { - itemsToRemoveIndexes.push(i); - this._makePairs(v.value).forEach((item) => { - if (this.appendParentKey) { - item.key = v.key + ' ' + item.key; - } - itemsToAdd.push(item); - i++; - }); + private insertFlattenObjects(temp: Item[]): any[] { + return _.flattenDeep( + temp.map((item) => { + const value = item.value; + const isObject = _.isObject(value); + if (!isObject || _.isEmpty(value)) { + if (isObject) { + item.value = ''; + } + return item; } - } - }); + return this.splitItemIntoItems(item); + }) + ); + } - _.remove(temp, (item, itemIndex) => { - return _.includes(itemsToRemoveIndexes, itemIndex); - }); - itemsToAdd.forEach((item) => { - temp.push(item); + /** + * Split item into items will call _makePairs inside _makePairs (recursion), in oder to split + * the object item up into items as planned. + */ + private splitItemIntoItems(v: { key: string; value: object }): Item[] { + return this._makePairs(v.value).map((item) => { + if (this.appendParentKey) { + item.key = v.key + ' ' + item.key; + } + return item; }); - - return temp; } _convertValue(v: Item): Item { -- 2.47.3