* 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 ---------
This commit is contained in:
parent
2d3e52fa92
commit
5917d9ae47
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:improvement
|
||||||
|
ui: Sort list view of entities and aliases alphabetically using the item name
|
||||||
|
```
|
|
@ -18,6 +18,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) {
|
||||||
|
|
|
@ -18,6 +18,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) {
|
||||||
|
|
|
@ -9,6 +9,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;
|
||||||
|
|
|
@ -4,4 +4,15 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
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;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
|
@ -12,4 +12,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;
|
||||||
|
});
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -12,6 +12,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;
|
||||||
|
|
||||||
|
@ -185,11 +186,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) {
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue