mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 18:48:08 +00:00 
			
		
		
		
	* move list to component * use helper instead * add changelog * clarify changelog copy * delete components now that helper is in use * move helper to util, remove template helper invokation * add optional sorting to lazyPaginatedQuery based on sortBy query attribute * Add serialization to entity-alias and entity so that they can be sorted by name on list view * Same logic as base normalizeItems for extractLazyPaginatedData so that metadata shows on list * Add headers --------- Co-authored-by: claire bontempo <68122737+hellobontempo@users.noreply.github.com>
This commit is contained in:
		
							
								
								
									
										3
									
								
								changelog/24103.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								changelog/24103.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,3 @@ | |||||||
|  | ```release-note:improvement | ||||||
|  | ui: Sort list view of entities and aliases alphabetically using the item name | ||||||
|  | ``` | ||||||
| @@ -13,6 +13,7 @@ export default Route.extend(ListRoute, { | |||||||
|         responsePath: 'data.keys', |         responsePath: 'data.keys', | ||||||
|         page: params.page, |         page: params.page, | ||||||
|         pageFilter: params.pageFilter, |         pageFilter: params.pageFilter, | ||||||
|  |         sortBy: 'name', | ||||||
|       }) |       }) | ||||||
|       .catch((err) => { |       .catch((err) => { | ||||||
|         if (err.httpStatus === 404) { |         if (err.httpStatus === 404) { | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ export default Route.extend(ListRoute, { | |||||||
|         responsePath: 'data.keys', |         responsePath: 'data.keys', | ||||||
|         page: params.page, |         page: params.page, | ||||||
|         pageFilter: params.pageFilter, |         pageFilter: params.pageFilter, | ||||||
|  |         sortBy: 'name', | ||||||
|       }) |       }) | ||||||
|       .catch((err) => { |       .catch((err) => { | ||||||
|         if (err.httpStatus === 404) { |         if (err.httpStatus === 404) { | ||||||
|   | |||||||
| @@ -4,6 +4,10 @@ import ApplicationSerializer from '../application'; | |||||||
| export default ApplicationSerializer.extend({ | export default ApplicationSerializer.extend({ | ||||||
|   normalizeItems(payload) { |   normalizeItems(payload) { | ||||||
|     if (payload.data.keys && Array.isArray(payload.data.keys)) { |     if (payload.data.keys && Array.isArray(payload.data.keys)) { | ||||||
|  |       if (typeof payload.data.keys[0] !== 'string') { | ||||||
|  |         // If keys is not an array of strings, it was already normalized into objects in extractLazyPaginatedData | ||||||
|  |         return payload.data.keys; | ||||||
|  |       } | ||||||
|       return payload.data.keys.map((key) => { |       return payload.data.keys.map((key) => { | ||||||
|         const model = payload.data.key_info[key]; |         const model = payload.data.key_info[key]; | ||||||
|         model.id = key; |         model.id = key; | ||||||
|   | |||||||
| @@ -1,2 +1,13 @@ | |||||||
| import IdentitySerializer from './_base'; | import IdentitySerializer from './_base'; | ||||||
| export default IdentitySerializer.extend(); | export default IdentitySerializer.extend({ | ||||||
|  |   extractLazyPaginatedData(payload) { | ||||||
|  |     return payload.data.keys.map((key) => { | ||||||
|  |       const model = payload.data.key_info[key]; | ||||||
|  |       model.id = key; | ||||||
|  |       if (payload.backend) { | ||||||
|  |         model.backend = payload.backend; | ||||||
|  |       } | ||||||
|  |       return model; | ||||||
|  |     }); | ||||||
|  |   }, | ||||||
|  | }); | ||||||
|   | |||||||
| @@ -7,4 +7,14 @@ export default IdentitySerializer.extend(EmbeddedRecordsMixin, { | |||||||
|   attrs: { |   attrs: { | ||||||
|     aliases: { embedded: 'always' }, |     aliases: { embedded: 'always' }, | ||||||
|   }, |   }, | ||||||
|  |   extractLazyPaginatedData(payload) { | ||||||
|  |     return payload.data.keys.map((key) => { | ||||||
|  |       const model = payload.data.key_info[key]; | ||||||
|  |       model.id = key; | ||||||
|  |       if (payload.backend) { | ||||||
|  |         model.backend = payload.backend; | ||||||
|  |       } | ||||||
|  |       return model; | ||||||
|  |     }); | ||||||
|  |   }, | ||||||
| }); | }); | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import { assert } from '@ember/debug'; | |||||||
| import { set, get, computed } from '@ember/object'; | import { set, get, computed } from '@ember/object'; | ||||||
| import clamp from 'vault/utils/clamp'; | import clamp from 'vault/utils/clamp'; | ||||||
| import config from 'vault/config/environment'; | import config from 'vault/config/environment'; | ||||||
|  | import sortObjects from 'vault/utils/sort-objects'; | ||||||
|  |  | ||||||
| const { DEFAULT_PAGE_SIZE } = config.APP; | const { DEFAULT_PAGE_SIZE } = config.APP; | ||||||
|  |  | ||||||
| @@ -176,11 +177,12 @@ export default Store.extend({ | |||||||
|   // store data cache as { response, dataset} |   // store data cache as { response, dataset} | ||||||
|   // also populated `lazyCaches` attribute |   // also populated `lazyCaches` attribute | ||||||
|   storeDataset(modelName, query, response, array) { |   storeDataset(modelName, query, response, array) { | ||||||
|     const dataSet = { |     const dataset = query.sortBy ? sortObjects(array, query.sortBy) : array; | ||||||
|  |     const value = { | ||||||
|       response, |       response, | ||||||
|       dataset: array, |       dataset, | ||||||
|     }; |     }; | ||||||
|     this.setLazyCacheForModel(modelName, query, dataSet); |     this.setLazyCacheForModel(modelName, query, value); | ||||||
|   }, |   }, | ||||||
|  |  | ||||||
|   clearDataset(modelName) { |   clearDataset(modelName) { | ||||||
|   | |||||||
							
								
								
									
										14
									
								
								ui/app/utils/sort-objects.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								ui/app/utils/sort-objects.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | |||||||
|  | export default function sortObjects(array, key) { | ||||||
|  |   if (Array.isArray(array) && array?.every((e) => e[key] && typeof e[key] === 'string')) { | ||||||
|  |     return array.sort((a, b) => { | ||||||
|  |       // ignore upper vs lowercase | ||||||
|  |       const valueA = a[key].toUpperCase(); | ||||||
|  |       const valueB = b[key].toUpperCase(); | ||||||
|  |       if (valueA < valueB) return -1; | ||||||
|  |       if (valueA > valueB) return 1; | ||||||
|  |       return 0; | ||||||
|  |     }); | ||||||
|  |   } | ||||||
|  |   // if not sortable, return original array | ||||||
|  |   return array; | ||||||
|  | } | ||||||
							
								
								
									
										86
									
								
								ui/tests/unit/utils/sort-objects-test.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								ui/tests/unit/utils/sort-objects-test.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | |||||||
|  | import sortObjects from 'vault/utils/sort-objects'; | ||||||
|  | import { module, test } from 'qunit'; | ||||||
|  |  | ||||||
|  | module('Unit | Utility | sort-objects', function () { | ||||||
|  |   test('it sorts array of objects', function (assert) { | ||||||
|  |     const originalArray = [ | ||||||
|  |       { foo: 'grape', bar: 'third' }, | ||||||
|  |       { foo: 'banana', bar: 'second' }, | ||||||
|  |       { foo: 'lemon', bar: 'fourth' }, | ||||||
|  |       { foo: 'apple', bar: 'first' }, | ||||||
|  |     ]; | ||||||
|  |     const expectedArray = [ | ||||||
|  |       { bar: 'first', foo: 'apple' }, | ||||||
|  |       { bar: 'second', foo: 'banana' }, | ||||||
|  |       { bar: 'third', foo: 'grape' }, | ||||||
|  |       { bar: 'fourth', foo: 'lemon' }, | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     assert.propEqual(sortObjects(originalArray, 'foo'), expectedArray, 'it sorts array of objects'); | ||||||
|  |  | ||||||
|  |     const originalWithNumbers = [ | ||||||
|  |       { foo: 'Z', bar: 'fourth' }, | ||||||
|  |       { foo: '1', bar: 'first' }, | ||||||
|  |       { foo: '2', bar: 'second' }, | ||||||
|  |       { foo: 'A', bar: 'third' }, | ||||||
|  |     ]; | ||||||
|  |     const expectedWithNumbers = [ | ||||||
|  |       { bar: 'first', foo: '1' }, | ||||||
|  |       { bar: 'second', foo: '2' }, | ||||||
|  |       { bar: 'third', foo: 'A' }, | ||||||
|  |       { bar: 'fourth', foo: 'Z' }, | ||||||
|  |     ]; | ||||||
|  |     assert.propEqual( | ||||||
|  |       sortObjects(originalWithNumbers, 'foo'), | ||||||
|  |       expectedWithNumbers, | ||||||
|  |       'it sorts strings with numbers and letters' | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   test('it disregards capitalization', function (assert) { | ||||||
|  |     // sort() arranges capitalized values before lowercase, the helper removes case by making all strings toUppercase() | ||||||
|  |     const originalArray = [ | ||||||
|  |       { foo: 'something-a', bar: 'third' }, | ||||||
|  |       { foo: 'D-something', bar: 'second' }, | ||||||
|  |       { foo: 'SOMETHING-b', bar: 'fourth' }, | ||||||
|  |       { foo: 'a-something', bar: 'first' }, | ||||||
|  |     ]; | ||||||
|  |     const expectedArray = [ | ||||||
|  |       { bar: 'first', foo: 'a-something' }, | ||||||
|  |       { bar: 'second', foo: 'D-something' }, | ||||||
|  |       { bar: 'third', foo: 'something-a' }, | ||||||
|  |       { bar: 'fourth', foo: 'SOMETHING-b' }, | ||||||
|  |     ]; | ||||||
|  |  | ||||||
|  |     assert.propEqual( | ||||||
|  |       sortObjects(originalArray, 'foo'), | ||||||
|  |       expectedArray, | ||||||
|  |       'it sorts array of objects regardless of capitalization' | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   test('it fails gracefully', function (assert) { | ||||||
|  |     const originalArray = [ | ||||||
|  |       { foo: 'b', bar: 'two' }, | ||||||
|  |       { foo: 'a', bar: 'one' }, | ||||||
|  |     ]; | ||||||
|  |     assert.propEqual( | ||||||
|  |       sortObjects(originalArray, 'someKey'), | ||||||
|  |       originalArray, | ||||||
|  |       'it returns original array if key does not exist' | ||||||
|  |     ); | ||||||
|  |     assert.deepEqual(sortObjects('not an array'), 'not an array', 'it returns original arg if not an array'); | ||||||
|  |  | ||||||
|  |     const notStrings = [ | ||||||
|  |       { foo: '1', bar: 'third' }, | ||||||
|  |       { foo: 'Z', bar: 'second' }, | ||||||
|  |       { foo: 1, bar: 'fourth' }, | ||||||
|  |       { foo: 2, bar: 'first' }, | ||||||
|  |     ]; | ||||||
|  |     assert.propEqual( | ||||||
|  |       sortObjects(notStrings, 'foo'), | ||||||
|  |       notStrings, | ||||||
|  |       'it returns original array if values are not all strings' | ||||||
|  |     ); | ||||||
|  |   }); | ||||||
|  | }); | ||||||
		Reference in New Issue
	
	Block a user
	 Chelsea Shaw
					Chelsea Shaw