mirror of
https://github.com/opf/openproject.git
synced 2026-06-13 19:20:00 +00:00
[#67969] Limit number of items in subitems widget
Allows for a configurable limit of items to be displayed. If a project has more subitems than can be displayed, a "View all subitems" link is displayed. This commit also fixes ordering by creation date.
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module FinderMethods
|
||||
end
|
||||
@@ -0,0 +1,38 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
#-- copyright
|
||||
# OpenProject is an open source project management software.
|
||||
# Copyright (C) the OpenProject GmbH
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License version 3.
|
||||
#
|
||||
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
|
||||
# Copyright (C) 2006-2013 Jean-Philippe Lang
|
||||
# Copyright (C) 2010-2013 the ChiliProject Team
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# See COPYRIGHT and LICENSE files for more details.
|
||||
#++
|
||||
|
||||
module FinderMethods
|
||||
module WithMore
|
||||
def first_with_more(limit)
|
||||
result = self.limit(limit + 1)
|
||||
[result.first(limit), result.size > limit]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -30,12 +30,12 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
|
||||
<%=
|
||||
widget_wrapper do |container|
|
||||
if children.empty?
|
||||
if has_no_subitems?
|
||||
container.with_row do
|
||||
render(Primer::Beta::Text.new(color: :subtle)) { I18n.t("overviews.widgets.subitems.no_visible_children") }
|
||||
end
|
||||
else
|
||||
children.find_each do |child|
|
||||
displayed_subitems.each do |child|
|
||||
container.with_row do
|
||||
flex_layout do |row|
|
||||
row.with_column do
|
||||
@@ -60,6 +60,12 @@ See COPYRIGHT and LICENSE files for more details.
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if has_more_subitems?
|
||||
container.with_row do
|
||||
render(Primer::Beta::Link.new(href: view_all_subitems_path)) { I18n.t("overviews.widgets.subitems.view_all_subitems") }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
%>
|
||||
|
||||
@@ -32,22 +32,55 @@ module Overviews
|
||||
module Widgets
|
||||
class SubitemsComponent < Grids::WidgetComponent
|
||||
include OpPrimer::ComponentHelpers
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
SUBITEMS_LIMIT = 10
|
||||
private_constant :SUBITEMS_LIMIT
|
||||
|
||||
param :project
|
||||
|
||||
delegate :description, to: :project
|
||||
option :limit, default: -> { SUBITEMS_LIMIT }
|
||||
|
||||
def title
|
||||
I18n.t("overviews.widgets.subitems.in_this_#{project.workspace_type}")
|
||||
end
|
||||
|
||||
def children
|
||||
@children ||= project.children.visible
|
||||
def displayed_subitems
|
||||
subitems_with_more.first
|
||||
end
|
||||
|
||||
def has_more_subitems?
|
||||
subitems_with_more.last
|
||||
end
|
||||
|
||||
def has_no_subitems?
|
||||
displayed_subitems.empty?
|
||||
end
|
||||
|
||||
def wrapper_arguments
|
||||
{ full_width: true }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def subitems_with_more
|
||||
@subitems_with_more ||= project.children
|
||||
.visible(current_user)
|
||||
.unscope(:order)
|
||||
.newest
|
||||
.extending(FinderMethods::WithMore)
|
||||
.first_with_more(limit)
|
||||
end
|
||||
|
||||
def view_all_subitems_path
|
||||
@view_all_subitems_path ||= projects_path(::API::Decorators::QueryParamsRepresenter.new(project_query).to_h)
|
||||
end
|
||||
|
||||
def project_query
|
||||
ProjectQuery.new
|
||||
.where("active", "=", "t")
|
||||
.where("parent_id", "=", project.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,6 +10,7 @@ en:
|
||||
in_this_program: "In this program"
|
||||
in_this_project: "In this project"
|
||||
no_visible_children: "There are no visible children."
|
||||
view_all_subitems: "View all subitems"
|
||||
members:
|
||||
title: "Latest members"
|
||||
view_all_members: "View all members"
|
||||
|
||||
@@ -31,17 +31,20 @@
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe Overviews::Widgets::SubitemsComponent, type: :component do
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
def render_component(...)
|
||||
render_inline(described_class.new(...))
|
||||
end
|
||||
|
||||
let(:project) { build_stubbed(:project) }
|
||||
let(:user) { build_stubbed(:user) }
|
||||
let(:params) { {} }
|
||||
|
||||
current_user { user }
|
||||
|
||||
subject(:rendered_component) do
|
||||
render_component(project)
|
||||
render_component(project, current_user:, **params)
|
||||
end
|
||||
|
||||
context "with no children" do
|
||||
@@ -57,9 +60,38 @@ RSpec.describe Overviews::Widgets::SubitemsComponent, type: :component do
|
||||
context "when visible to user" do
|
||||
let(:user) { create(:admin) }
|
||||
|
||||
it "renders the children" do
|
||||
expect(rendered_component).to have_list "In this project" do |list|
|
||||
expect(list).to have_list_item count: 3, text: /My Project No. \d+/
|
||||
context "and a limit greater than the number of all subitems (default: 10)" do
|
||||
it "renders all subitems, without a 'view all' item", :aggregate_failures do
|
||||
expect(rendered_component).to have_list "In this project" do |list|
|
||||
expect(list).to have_list_item count: 3, text: /My Project No. \d+/
|
||||
expect(list).to have_no_list_item text: "View all subitems"
|
||||
end
|
||||
end
|
||||
|
||||
it "does not render 'view all' link" do
|
||||
expect(rendered_component).to have_no_link "View all subitems"
|
||||
end
|
||||
end
|
||||
|
||||
context "and a limit less than the number of all subitems" do
|
||||
let(:params) { { limit: 2 } }
|
||||
|
||||
it "renders specified subitems, along with a 'view all' item", :aggregate_failures do
|
||||
expect(rendered_component).to have_list "In this project" do |list|
|
||||
expect(list).to have_list_item count: 2, text: /My Project No. \d+/
|
||||
expect(list).to have_list_item text: "View all subitems"
|
||||
end
|
||||
end
|
||||
|
||||
it "renders 'view all' link to projects with parent filter", :aggregate_failures do
|
||||
expect(rendered_component).to have_link "View all subitems" do |link|
|
||||
uri = Addressable::URI.parse(link[:href])
|
||||
expect(uri.path).to eq projects_path
|
||||
expect(uri.query_values["filters"]).to be_json_eql %{[
|
||||
{"active":{"operator":"=","values":["t"]}},
|
||||
{"parent":{"operator":"=","values":["#{project.id}"]}}
|
||||
]}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user