Commit d15eb48c authored by Robert Speicher's avatar Robert Speicher

Merge branch 'add-sorting-to-packages-list' into 'master'

Adding sort to the projects package list page

See merge request gitlab-org/gitlab!15448
parents f502d4e2 dd4f91c9
---
title: Adds sorting of packages at the project level
merge_request: 15448
author:
type: added
......@@ -12,6 +12,6 @@ module PackagesAccess
def verify_packages_enabled!
render_404 unless Gitlab.config.packages.enabled &&
project.feature_available?(:packages)
project.feature_available?(:packages)
end
end
......@@ -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