From: Stephan Müller Date: Thu, 10 Jan 2019 13:58:39 +0000 (+0100) Subject: mgr/dashboard: Render all objects in KV-table X-Git-Tag: v14.1.0~433^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=1033314a24d331702676be28e0c2e7e9fa314f00;p=ceph.git mgr/dashboard: Render all objects in KV-table 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 --- 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 {