Commit dd4f91c9 authored by Nick Kipling's avatar Nick Kipling Committed by Robert Speicher

Adding sort to the projects package list page

Updated the UI to include sort dropdown
Added reorder options to the packages list
Updated sorting helper with package options
Added tests to test that sorting works
Updated pot file
Added changelog
parent f502d4e2
---
title: Adds sorting of packages at the project level
merge_request: 15448
author:
type: added
......@@ -4,11 +4,15 @@ module Projects
module Packages
class PackagesController < ApplicationController
include PackagesAccess
include SortingHelper
before_action :authorize_destroy_package!, only: [:destroy]
def index
@packages = project.packages.has_version.page(params[:page])
@packages = project.packages
.has_version
.sort_by_attribute(@sort = params[:sort] || 'created_desc')
.page(params[:page])
end
def show
......
# frozen_string_literal: true
module EE
module PackagesHelper
def package_sort_path(options = {})
"#{request.path}?#{options.to_param}"
end
end
end
......@@ -64,6 +64,43 @@ module EE
end
end
def packages_sort_options_hash
{
sort_value_recently_created => sort_title_created_date,
sort_value_oldest_created => sort_title_created_date,
sort_value_name => sort_title_name,
sort_value_name_desc => sort_title_name,
sort_value_version_desc => sort_title_version,
sort_value_version_asc => sort_title_version,
sort_value_type_desc => sort_value_type_desc,
sort_value_type_asc => sort_title_type
}
end
def packages_reverse_sort_order_hash
{
sort_value_recently_created => sort_value_oldest_created,
sort_value_oldest_created => sort_value_recently_created,
sort_value_name => sort_value_name_desc,
sort_value_name_desc => sort_value_name,
sort_value_version_desc => sort_value_version_asc,
sort_value_version_asc => sort_value_version_desc,
sort_value_type_desc => sort_value_type_asc,
sort_value_type_asc => sort_value_type_desc
}
end
def packages_sort_option_title(sort_value)
packages_sort_options_hash[sort_value]
end
def packages_sort_direction_button(sort_value)
reverse_sort = packages_reverse_sort_order_hash[sort_value]
url = package_sort_path(sort: reverse_sort)
sort_direction_button(url, reverse_sort, sort_value)
end
# Creates a button with the opposite ordering for the current field in UI.
def sort_order_button(sort)
opposite_sorting_param = epics_ordering_options_hash[sort] || epics_ordering_options_hash.key(sort)
......@@ -95,6 +132,14 @@ module EE
s_('SortOptions|Weight')
end
def sort_title_version
s_('SortOptions|Version')
end
def sort_title_type
s_('SortOptions|Type')
end
def sort_value_start_date
'start_date_asc'
end
......@@ -118,5 +163,21 @@ module EE
def sort_value_weight
'weight'
end
def sort_value_version_asc
'version_asc'
end
def sort_value_version_desc
'version_desc'
end
def sort_value_type_asc
'type_asc'
end
def sort_value_type_desc
'type_desc'
end
end
end
......@@ -24,6 +24,16 @@ class Packages::Package < ApplicationRecord
scope :preload_files, -> { preload(:package_files) }
scope :last_of_each_version, -> { where(id: all.select('MAX(id) AS id').group(:version)) }
# Sorting
scope :order_created, -> { reorder('created_at ASC') }
scope :order_created_desc, -> { reorder('created_at DESC') }
scope :order_name, -> { reorder('name ASC') }
scope :order_name_desc, -> { reorder('name DESC') }
scope :order_version, -> { reorder('version ASC') }
scope :order_version_desc, -> { reorder('version DESC') }
scope :order_type, -> { reorder('package_type ASC') }
scope :order_type_desc, -> { reorder('package_type DESC') }
def self.for_projects(projects)
return none unless projects.any?
......@@ -40,6 +50,20 @@ class Packages::Package < ApplicationRecord
.where(packages_package_files: { file_name: file_name }).last!
end
def self.sort_by_attribute(method)
case method.to_s
when 'created_asc' then order_created
when 'name_asc' then order_name
when 'name_desc' then order_name_desc
when 'version_asc' then order_version
when 'version_desc' then order_version_desc
when 'type_asc' then order_type
when 'type_desc' then order_type_desc
else
order_created_desc
end
end
private
def valid_npm_package_name
......
- sort_value = @sort
- sort_title = packages_sort_option_title(sort_value)
- page_title _("Packages")
- can_destroy_package = can?(current_user, :destroy_package, @project)
- if @packages.any?
.d-flex.justify-content-end
.dropdown.inline.prepend-top-default.append-bottom-default.package-sort-dropdown
.btn-group{ role: 'group' }
.btn-group{ role: 'group' }
%button.dropdown-menu-toggle{ type: 'button', data: { toggle: 'dropdown', display: 'static' }, class: 'btn btn-default' }
= sort_title
= icon('chevron-down')
%ul.dropdown-menu.dropdown-menu-right.dropdown-menu-selectable.dropdown-menu-sort
%li
= sortable_item(sort_title_created_date, package_sort_path(sort: sort_value_recently_created), sort_title)
= sortable_item(sort_title_name, package_sort_path(sort: sort_value_name_desc), sort_title)
= sortable_item(sort_title_version, package_sort_path(sort: sort_value_version_desc), sort_title)
= sortable_item(sort_title_type, package_sort_path(sort: sort_value_type_desc), sort_title)
= packages_sort_direction_button(sort_value)
.table-holder
.gl-responsive-table-row.table-row-header{ role: 'row' }
.gl-responsive-table-row.table-row-header.bg-secondary-50.px-2.border-top{ role: 'row' }
.table-section.section-30{ role: 'rowheader' }
= _('Name')
.table-section.section-20{ role: 'rowheader' }
......@@ -14,7 +31,7 @@
= _('Created')
.table-section.section-10{ role: 'rowheader' }
- @packages.each do |package|
.gl-responsive-table-row
.gl-responsive-table-row.package-row.px-2
.table-section.section-30
.table-mobile-header{ role: "rowheader" }= _("Name")
.table-mobile-content.flex-truncate-parent
......
......@@ -3,6 +3,8 @@
require 'spec_helper'
describe 'Packages' do
include SortingHelper
let(:user) { create(:user) }
let(:project) { create(:project) }
......@@ -83,7 +85,86 @@ describe 'Packages' do
end
end
context 'sorting when there are packages' do
let!(:aaa_package) do
create(
:maven_package,
name: 'aaa/company/app/my-app',
version: '1.0-SNAPSHOT',
project: project)
end
let!(:bbb_package) do
create(
:maven_package,
name: 'bbb/company/app/my-app',
version: '1.1-SNAPSHOT',
project: project)
end
it 'sorts by created date descending' do
visit project_packages_path(project, sort: sort_value_created_date)
expect(first_package).to include(bbb_package.name)
expect(last_package).to include(aaa_package.name)
end
it 'sorts by created date ascending' do
visit project_packages_path(project, sort: sort_value_oldest_created)
expect(first_package).to include(aaa_package.name)
expect(last_package).to include(bbb_package.name)
end
it 'sorts by name descending' do
visit project_packages_path(project, sort: sort_value_name_desc)
expect(first_package).to include(bbb_package.name)
expect(last_package).to include(aaa_package.name)
end
it 'sorts by name ascending' do
visit project_packages_path(project, sort: sort_value_name)
expect(first_package).to include(aaa_package.name)
expect(last_package).to include(bbb_package.name)
end
it 'sorts by version descending' do
visit project_packages_path(project, sort: sort_value_version_desc)
expect(first_package).to include(bbb_package.name)
expect(last_package).to include(aaa_package.name)
end
it 'sorts by version ascending' do
visit project_packages_path(project, sort: sort_value_version_asc)
expect(first_package).to include(aaa_package.name)
expect(last_package).to include(bbb_package.name)
end
end
context 'sorting different types of packages' do
let!(:maven_package) { create(:maven_package, project: project) }
let!(:npm_package) { create(:npm_package, project: project) }
it 'sorts by type descending' do
visit project_packages_path(project, sort: sort_value_type_desc)
expect(first_package).to include(npm_package.name)
expect(last_package).to include(maven_package.name)
end
it 'sorts by type ascending' do
visit project_packages_path(project, sort: sort_value_type_asc)
expect(first_package).to include(maven_package.name)
expect(last_package).to include(npm_package.name)
end
end
def visit_project_packages
visit project_packages_path(project)
end
def first_package
page.all('.table-holder .package-row').first.text
end
def last_package
page.all('.table-holder .package-row').last.text
end
end
......@@ -2,6 +2,8 @@
require 'spec_helper'
RSpec.describe Packages::Package, type: :model do
include SortingHelper
describe 'relationships' do
it { is_expected.to belong_to(:project) }
it { is_expected.to have_many(:package_files).dependent(:destroy) }
......
......@@ -14938,6 +14938,12 @@ msgstr ""
msgid "SortOptions|Start soon"
msgstr ""
msgid "SortOptions|Type"
msgstr ""
msgid "SortOptions|Version"
msgstr ""
msgid "SortOptions|Weight"
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment