Sort Environments in Table by Last Updated
Ensure folders push to the top, if both have no last update, sort by name. The sorting algorithm should sort in the following priorities: 1. folders first, 2. last updated descending, 3. by name ascending, the sorting algorithm must: 1. Sort by name ascending, 2. Reverse (sort by name descending), 3. Sort by last deployment ascending, 4. Reverse (last deployment descending, name ascending), 5. Put folders first. It is done this way, as `underscore`'s sort API is very basic: simple comparisons, sorting by ascending only.
This commit is contained in:
parent
27ed9d958a
commit
fa882a674a
3 changed files with 260 additions and 1 deletions
|
@ -3,6 +3,7 @@
|
|||
* Render environments table.
|
||||
*/
|
||||
import { GlLoadingIcon } from '@gitlab/ui';
|
||||
import _ from 'underscore';
|
||||
import environmentItem from './environment_item.vue';
|
||||
|
||||
export default {
|
||||
|
@ -24,6 +25,15 @@ export default {
|
|||
default: false,
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
sortedEnvironments() {
|
||||
return this.sortEnvironments(this.environments).map(env =>
|
||||
this.shouldRenderFolderContent(env)
|
||||
? { ...env, children: this.sortEnvironments(env.children) }
|
||||
: env,
|
||||
);
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
folderUrl(model) {
|
||||
return `${window.location.pathname}/folders/${model.folderName}`;
|
||||
|
@ -31,6 +41,30 @@ export default {
|
|||
shouldRenderFolderContent(env) {
|
||||
return env.isFolder && env.isOpen && env.children && env.children.length > 0;
|
||||
},
|
||||
sortEnvironments(environments) {
|
||||
/*
|
||||
* The sorting algorithm should sort in the following priorities:
|
||||
*
|
||||
* 1. folders first,
|
||||
* 2. last updated descending,
|
||||
* 3. by name ascending,
|
||||
*
|
||||
* the sorting algorithm must:
|
||||
*
|
||||
* 1. Sort by name ascending,
|
||||
* 2. Reverse (sort by name descending),
|
||||
* 3. Sort by last deployment ascending,
|
||||
* 4. Reverse (last deployment descending, name ascending),
|
||||
* 5. Put folders first.
|
||||
*/
|
||||
return _.chain(environments)
|
||||
.sortBy(env => (env.isFolder ? env.folderName : env.name))
|
||||
.reverse()
|
||||
.sortBy(env => (env.last_deployment ? env.last_deployment.created_at : '0000'))
|
||||
.reverse()
|
||||
.sortBy(env => (env.isFolder ? -1 : 1))
|
||||
.value();
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
@ -53,7 +87,7 @@ export default {
|
|||
{{ s__('Environments|Updated') }}
|
||||
</div>
|
||||
</div>
|
||||
<template v-for="(model, i) in environments" :model="model">
|
||||
<template v-for="(model, i) in sortedEnvironments" :model="model">
|
||||
<div
|
||||
is="environment-item"
|
||||
:key="`environment-item-${i}`"
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Sort Environments by Last Updated
|
||||
merge_request: 25260
|
||||
author:
|
||||
type: added
|
|
@ -31,4 +31,224 @@ describe('Environment table', () => {
|
|||
|
||||
expect(vm.$el.getAttribute('class')).toContain('ci-table');
|
||||
});
|
||||
|
||||
describe('sortEnvironments', () => {
|
||||
it('should sort environments by last updated', () => {
|
||||
const mockItems = [
|
||||
{
|
||||
name: 'old',
|
||||
size: 3,
|
||||
isFolder: false,
|
||||
last_deployment: {
|
||||
created_at: new Date(2019, 0, 5).toISOString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'new',
|
||||
size: 3,
|
||||
isFolder: false,
|
||||
last_deployment: {
|
||||
created_at: new Date(2019, 1, 5).toISOString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'older',
|
||||
size: 3,
|
||||
isFolder: false,
|
||||
last_deployment: {
|
||||
created_at: new Date(2018, 0, 5).toISOString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'an environment with no deployment',
|
||||
},
|
||||
];
|
||||
|
||||
vm = mountComponent(Component, {
|
||||
environments: mockItems,
|
||||
canReadEnvironment: true,
|
||||
});
|
||||
|
||||
const [old, newer, older, noDeploy] = mockItems;
|
||||
|
||||
expect(vm.sortEnvironments(mockItems)).toEqual([newer, old, older, noDeploy]);
|
||||
});
|
||||
|
||||
it('should push environments with no deployments to the bottom', () => {
|
||||
const mockItems = [
|
||||
{
|
||||
name: 'production',
|
||||
size: 1,
|
||||
id: 2,
|
||||
state: 'available',
|
||||
external_url: 'https://google.com/production',
|
||||
environment_type: null,
|
||||
last_deployment: null,
|
||||
has_stop_action: false,
|
||||
environment_path: '/Commit451/lab-coat/environments/2',
|
||||
stop_path: '/Commit451/lab-coat/environments/2/stop',
|
||||
folder_path: '/Commit451/lab-coat/environments/folders/production',
|
||||
created_at: '2019-01-17T16:26:10.064Z',
|
||||
updated_at: '2019-01-17T16:27:37.717Z',
|
||||
can_stop: true,
|
||||
},
|
||||
{
|
||||
name: 'review/225addcibuildstatus',
|
||||
size: 2,
|
||||
isFolder: true,
|
||||
isLoadingFolderContent: false,
|
||||
folderName: 'review',
|
||||
isOpen: false,
|
||||
children: [],
|
||||
id: 12,
|
||||
state: 'available',
|
||||
external_url: 'https://google.com/review/225addcibuildstatus',
|
||||
environment_type: 'review',
|
||||
last_deployment: null,
|
||||
has_stop_action: false,
|
||||
environment_path: '/Commit451/lab-coat/environments/12',
|
||||
stop_path: '/Commit451/lab-coat/environments/12/stop',
|
||||
folder_path: '/Commit451/lab-coat/environments/folders/review',
|
||||
created_at: '2019-01-17T16:27:37.877Z',
|
||||
updated_at: '2019-01-17T16:27:37.883Z',
|
||||
can_stop: true,
|
||||
},
|
||||
{
|
||||
name: 'staging',
|
||||
size: 1,
|
||||
id: 1,
|
||||
state: 'available',
|
||||
external_url: 'https://google.com/staging',
|
||||
environment_type: null,
|
||||
last_deployment: {
|
||||
created_at: '2019-01-17T16:26:15.125Z',
|
||||
scheduled_actions: [],
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
vm = mountComponent(Component, {
|
||||
environments: mockItems,
|
||||
canReadEnvironment: true,
|
||||
});
|
||||
|
||||
const [prod, review, staging] = mockItems;
|
||||
|
||||
expect(vm.sortEnvironments(mockItems)).toEqual([review, staging, prod]);
|
||||
});
|
||||
|
||||
it('should sort environments by folder first', () => {
|
||||
const mockItems = [
|
||||
{
|
||||
name: 'old',
|
||||
size: 3,
|
||||
isFolder: false,
|
||||
last_deployment: {
|
||||
created_at: new Date(2019, 0, 5).toISOString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'new',
|
||||
size: 3,
|
||||
isFolder: false,
|
||||
last_deployment: {
|
||||
created_at: new Date(2019, 1, 5).toISOString(),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'older',
|
||||
size: 3,
|
||||
isFolder: true,
|
||||
children: [],
|
||||
},
|
||||
];
|
||||
|
||||
vm = mountComponent(Component, {
|
||||
environments: mockItems,
|
||||
canReadEnvironment: true,
|
||||
});
|
||||
|
||||
const [old, newer, older] = mockItems;
|
||||
|
||||
expect(vm.sortEnvironments(mockItems)).toEqual([older, newer, old]);
|
||||
});
|
||||
|
||||
it('should break ties by name', () => {
|
||||
const mockItems = [
|
||||
{
|
||||
name: 'old',
|
||||
isFolder: false,
|
||||
},
|
||||
{
|
||||
name: 'new',
|
||||
isFolder: false,
|
||||
},
|
||||
{
|
||||
folderName: 'older',
|
||||
isFolder: true,
|
||||
},
|
||||
];
|
||||
|
||||
vm = mountComponent(Component, {
|
||||
environments: mockItems,
|
||||
canReadEnvironment: true,
|
||||
});
|
||||
|
||||
const [old, newer, older] = mockItems;
|
||||
|
||||
expect(vm.sortEnvironments(mockItems)).toEqual([older, newer, old]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('sortedEnvironments', () => {
|
||||
it('it should sort children as well', () => {
|
||||
const mockItems = [
|
||||
{
|
||||
name: 'production',
|
||||
last_deployment: null,
|
||||
},
|
||||
{
|
||||
name: 'review/225addcibuildstatus',
|
||||
isFolder: true,
|
||||
folderName: 'review',
|
||||
isOpen: true,
|
||||
children: [
|
||||
{
|
||||
name: 'review/225addcibuildstatus',
|
||||
last_deployment: {
|
||||
created_at: '2019-01-17T16:26:15.125Z',
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'review/master',
|
||||
last_deployment: {
|
||||
created_at: '2019-02-17T16:26:15.125Z',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'staging',
|
||||
last_deployment: {
|
||||
created_at: '2019-01-17T16:26:15.125Z',
|
||||
},
|
||||
},
|
||||
];
|
||||
const [production, review, staging] = mockItems;
|
||||
const [addcibuildstatus, master] = mockItems[1].children;
|
||||
|
||||
vm = mountComponent(Component, {
|
||||
environments: mockItems,
|
||||
canReadEnvironment: true,
|
||||
});
|
||||
|
||||
expect(vm.sortedEnvironments.map(env => env.name)).toEqual([
|
||||
review.name,
|
||||
staging.name,
|
||||
production.name,
|
||||
]);
|
||||
|
||||
expect(vm.sortedEnvironments[0].children).toEqual([master, addcibuildstatus]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue