Skip to content

Commit 011f74e

Browse files
committed
Merge branch 'release/14.6' into dev
2 parents 8772589 + b588816 commit 011f74e

File tree

27 files changed

+210
-105
lines changed

27 files changed

+210
-105
lines changed

Diff for: app/components/admin/custom_fields/custom_field_projects/row_component.rb

+2-3
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,10 @@ def more_menu_detach_project
5757
def detach_from_project_url
5858
url_helpers.custom_field_project_path(
5959
custom_field_id: @table.params[:custom_field].id,
60-
custom_fields_project: { project_id: project.id }
60+
custom_fields_project: { project_id: project.id },
61+
page: current_page
6162
)
6263
end
63-
64-
def project = model.first
6564
end
6665
end
6766
end

Diff for: app/components/admin/custom_fields/custom_field_projects/table_component.rb

+1-18
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ module Admin
3030
module CustomFields
3131
module CustomFieldProjects
3232
class TableComponent < Projects::TableComponent
33-
include OpTurbo::Streamable
33+
include ::Projects::Concerns::TableComponent::StreamablePaginationLinksConstraints
3434

3535
def columns
3636
@columns ||= query.selects.reject { |select| select.is_a?(Queries::Selects::NotExistingSelect) }
@@ -39,23 +39,6 @@ def columns
3939
def sortable?
4040
false
4141
end
42-
43-
# @override optional_pagination_options are passed to the pagination_options
44-
# which are passed to #pagination_links_full in pagination_helper.rb
45-
#
46-
# In Turbo streamable components, we need to be able to specify the url_for(action:) so that links are
47-
# generated in the context of the component index action, instead of any turbo stream actions performing
48-
# partial updates on the page.
49-
#
50-
# params[:url_for_action] is passed to the pagination_options making it's way down to any pagination links
51-
# that are generated via link_to which calls url_for which uses the params[:url_for_action] to specify
52-
# the controller action that link_to should use.
53-
#
54-
def optional_pagination_options
55-
return super unless params[:url_for_action]
56-
57-
super.merge(params: { action: params[:url_for_action] })
58-
end
5942
end
6043
end
6144
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#-- copyright
2+
# OpenProject is an open source project management software.
3+
# Copyright (C) the OpenProject GmbH
4+
#
5+
# This program is free software; you can redistribute it and/or
6+
# modify it under the terms of the GNU General Public License version 3.
7+
#
8+
# OpenProject is a fork of ChiliProject, which is a fork of Redmine. The copyright follows:
9+
# Copyright (C) 2006-2013 Jean-Philippe Lang
10+
# Copyright (C) 2010-2013 the ChiliProject Team
11+
#
12+
# This program is free software; you can redistribute it and/or
13+
# modify it under the terms of the GNU General Public License
14+
# as published by the Free Software Foundation; either version 2
15+
# of the License, or (at your option) any later version.
16+
#
17+
# This program is distributed in the hope that it will be useful,
18+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
19+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20+
# GNU General Public License for more details.
21+
#
22+
# You should have received a copy of the GNU General Public License
23+
# along with this program; if not, write to the Free Software
24+
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
25+
#
26+
# See COPYRIGHT and LICENSE files for more details.
27+
#++
28+
29+
module Projects
30+
module Concerns
31+
module TableComponent
32+
module StreamablePaginationLinksConstraints
33+
# @override optional_pagination_options are passed to the pagination_options
34+
# which are passed to #pagination_links_full in pagination_helper.rb
35+
#
36+
# In Turbo streamable components, we need to be able to specify the url_for(action:) so that links are
37+
# generated in the context of the component index action, instead of any turbo stream actions performing
38+
# partial updates on the page.
39+
#
40+
# params[:url_for_action] is passed to the pagination_options making it's way down to any pagination links
41+
# that are generated via link_to which calls url_for which uses the params[:url_for_action] to specify
42+
# the controller action that link_to should use.
43+
#
44+
# data-turbo-action="advance" is added to the pagination links ensure links pushState to the browser
45+
#
46+
def optional_pagination_options
47+
super.tap do |options|
48+
options[:params] = { action: params[:url_for_action] } if params[:url_for_action]
49+
options[:turbo_action] = "advance"
50+
end
51+
end
52+
end
53+
end
54+
end
55+
end

Diff for: app/components/projects/row_component.rb

+4
Original file line numberDiff line numberDiff line change
@@ -373,5 +373,9 @@ def user_can_view_project?
373373
def custom_field_column?(column)
374374
column.is_a?(::Queries::Projects::Selects::CustomField)
375375
end
376+
377+
def current_page
378+
table.model.current_page.to_s
379+
end
376380
end
377381
end

Diff for: app/components/settings/project_custom_fields/project_custom_field_mapping/row_component.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ class RowComponent < Admin::CustomFields::CustomFieldProjects::RowComponent
3535
def detach_from_project_url
3636
url_helpers.unlink_admin_settings_project_custom_field_path(
3737
id: @table.params[:custom_field].id,
38-
project_custom_field_project_mapping: { project_id: project.id }
38+
project_custom_field_project_mapping: { project_id: project.id },
39+
page: current_page
3940
)
4041
end
4142
end

Diff for: app/controllers/admin/custom_fields/custom_field_projects_controller.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ def render_project_list(url_for_action: action_name)
103103
update_via_turbo_stream(
104104
component: Admin::CustomFields::CustomFieldProjects::TableComponent.new(
105105
query: available_custom_fields_projects_query,
106-
params: { custom_field: @custom_field, url_for_action: }
106+
params: params.merge({ custom_field: @custom_field, url_for_action: })
107107
)
108108
)
109109
end

Diff for: app/controllers/admin/settings/project_custom_fields_controller.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ def render_project_list(url_for_action: action_name)
158158
update_via_turbo_stream(
159159
component: Settings::ProjectCustomFields::ProjectCustomFieldMapping::TableComponent.new(
160160
query: project_custom_field_mappings_query,
161-
params: { custom_field: @custom_field, url_for_action: }
161+
params: params.merge({ custom_field: @custom_field, url_for_action: })
162162
)
163163
)
164164
end

Diff for: app/helpers/pagination_helper.rb

+15
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ def previous_or_next_page(page, text, class_suffix)
202202
def link(text, target, attributes)
203203
new_attributes = attributes.dup
204204
new_attributes["data-turbo-stream"] = true if turbo?
205+
new_attributes["data-turbo-action"] = turbo_action if turbo_action.present?
205206

206207
super(text, target, new_attributes)
207208
end
@@ -210,6 +211,20 @@ def allowed_params
210211
@options[:allowed_params] # rubocop:disable Rails/HelperInstanceVariable
211212
end
212213

214+
# Customize the Turbo visit action for pagination links. Can be set to "advance" or "replace".
215+
# "advance" - push a new entry onto the history stack.
216+
# "replace" - replace the current history entry.
217+
# See: https://turbo.hotwired.dev/reference/attributes
218+
#
219+
# Example: Promoting a Frame Navigation to a Page Visit
220+
# By default navigation within a turbo frame does not change the rest of the browser's state,
221+
# but you can promote a frame navigation a "Visit" by setting the turbo-action attribute to "advance".
222+
# See: https://turbo.hotwired.dev/handbook/frames#promoting-a-frame-navigation-to-a-page-visit
223+
#
224+
def turbo_action
225+
@options[:turbo_action] # rubocop:disable Rails/HelperInstanceVariable
226+
end
227+
213228
def turbo?
214229
@options[:turbo] # rubocop:disable Rails/HelperInstanceVariable
215230
end

Diff for: app/seeders/oauth_applications_seeder.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def create_app
5252
OAuth::Applications::CreateService
5353
.new(user: User.system)
5454
.call(
55-
enabled: true,
55+
enabled: false,
5656
name: "OpenProject Mobile App",
5757
redirect_uri: "openprojectapp://oauth-callback",
5858
builtin: true,

Diff for: app/views/notifications/index.html.erb

-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111

1212
<% content_for :content_body do %>
1313
<%= angular_component_tag "opce-notification-center" %>
14-
dd
1514
<% end %>
1615

1716
<% content_for :content_body_right do %>

Diff for: app/views/users/_consent.html.erb

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
<section class="form--section">
22
<h3 class="form--section-title"><%=t('consent.title')%></h3>
3+
<% consent_link = admin_settings_users_path(anchor: 'consent_settings') %>
4+
35
<%= render ::Components::OnOffStatusComponent.new({
46
is_on: @user.consented_at.present?,
57
on_text: format_time(@user.consented_at),
6-
on_description: t('consent.user_has_consented'),
8+
on_description: link_translate('consent.user_has_consented', links: { consent_settings: consent_link }),
79
off_text: t(:label_never),
8-
off_description: t('consent.not_yet_consented')
10+
off_description: link_translate('consent.not_yet_consented', links: { consent_settings: consent_link })
911
}) %>
1012
</section>

Diff for: config/locales/en.yml

+3-3
Original file line numberDiff line numberDiff line change
@@ -1504,8 +1504,8 @@ en:
15041504
failure_message: Consent failed, cannot proceed.
15051505
title: User Consent
15061506
decline_warning_message: You have declined to consent and have been logged out.
1507-
user_has_consented: User has consented to your configured statement at the given time.
1508-
not_yet_consented: User has not consented yet, will be requested upon next login.
1507+
user_has_consented: The user gave their consent to your [configured consent information text](consent_settings).
1508+
not_yet_consented: The user has not yet given their consent to your [configured consent information text](consent_settings). They will be reminded the next time they log in.
15091509
contact_mail_instructions: Define the mail address that users can reach a data controller to perform data change or removal requests.
15101510
contact_your_administrator: Please contact your administrator if you want to have your account deleted.
15111511
contact_this_mail_address: Please contact %{mail_address} if you want to have your account deleted.
@@ -3380,7 +3380,7 @@ en:
33803380
setting_total_percent_complete_mode_work_weighted_average: "Weighted by work"
33813381
setting_total_percent_complete_mode_work_weighted_average_caption_html: >-
33823382
The <i>total % Complete</i> will be weighted against the <i>Work</i> of each work package in the hierarchy.
3383-
Work packages without <i>Work</i> will be ignored (current behaviour).
3383+
Work packages without <i>Work</i> will be ignored.
33843384
setting_total_percent_complete_mode_simple_average: "Simple average"
33853385
setting_total_percent_complete_mode_simple_average_caption_html: >-
33863386
<i>Work</i> is ignored and the <i>total % Complete</i> will be a simple average of <i>% Complete</i> values of work packages in the hierarchy.

Diff for: frontend/src/stimulus/controllers/poll-for-changes.controller.ts

+12-2
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,11 @@ export default class PollForChangesController extends ApplicationController {
3939
autoscrollEnabled: Boolean,
4040
};
4141

42-
static targets = ['reloadButton'];
42+
static targets = ['reloadButton', 'reference'];
4343

4444
declare reloadButtonTarget:HTMLLinkElement;
45+
declare referenceTarget:HTMLElement;
46+
declare readonly hasReferenceTarget:boolean;
4547

4648
declare referenceValue:string;
4749
declare urlValue:string;
@@ -69,12 +71,20 @@ export default class PollForChangesController extends ApplicationController {
6971
clearInterval(this.interval);
7072
}
7173

74+
buildReference():string {
75+
if (this.hasReferenceTarget) {
76+
return this.referenceTarget.dataset.referenceValue as string;
77+
}
78+
79+
return this.referenceValue;
80+
}
81+
7282
reloadButtonTargetConnected() {
7383
this.reloadButtonTarget.addEventListener('click', this.rememberCurrentScrollPosition.bind(this));
7484
}
7585

7686
triggerTurboStream() {
77-
void fetch(`${this.urlValue}?reference=${this.referenceValue}`, {
87+
void fetch(`${this.urlValue}?reference=${this.buildReference()}`, {
7888
headers: {
7989
Accept: 'text/vnd.turbo-stream.html',
8090
},

Diff for: modules/meeting/app/components/meetings/header_component.html.erb

+5-2
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,17 @@
11
<%=
22
helpers.content_controller "poll-for-changes",
3-
poll_for_changes_reference_value: @meeting.changed_hash,
43
poll_for_changes_url_value: check_for_updates_meeting_path(@meeting),
54
poll_for_changes_interval_value: check_for_updates_interval,
65
poll_for_changes_autoscroll_enabled_value: true
76

87
component_wrapper do
98
render(Primer::OpenProject::PageHeader.new(
109
test_selector: "meeting-page-header",
11-
state: @state
10+
state: @state,
11+
data: {
12+
poll_for_changes_target: "reference",
13+
reference_value: @meeting.changed_hash
14+
}
1215
)) do |header|
1316
header.with_title do |title|
1417
title.with_editable_form(model: @meeting,

Diff for: modules/storages/app/components/storages/project_storages/destroy_confirmation_dialog_component.html.erb

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ See COPYRIGHT and LICENSE files for more details.
3131
component_wrapper do
3232
primer_form_with(
3333
model: @project_storage,
34-
url: admin_settings_storage_project_storage_path(id: @project_storage),
34+
url: admin_settings_storage_project_storage_path(id: @project_storage, page: current_page),
3535
data: {
3636
turbo: true,
3737
controller: 'disable-when-checked',

Diff for: modules/storages/app/components/storages/project_storages/destroy_confirmation_dialog_component.rb

+6-1
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ class DestroyConfirmationDialogComponent < ApplicationComponent
3232
include OpTurbo::Streamable
3333
include OpPrimer::ComponentHelpers
3434

35-
def initialize(storage:, project_storage:)
35+
def initialize(storage:, project_storage:, params: {})
3636
super
3737

3838
@storage = storage
3939
@project_storage = project_storage
40+
@params = params
4041
end
4142

4243
def id
@@ -56,6 +57,10 @@ def text
5657
text
5758
end
5859

60+
def current_page
61+
@params[:page]
62+
end
63+
5964
def confirmation_text
6065
I18n.t("project_storages.remove_project.dialog.confirmation_text")
6166
end

Diff for: modules/storages/app/components/storages/project_storages/projects/row_component.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@ def more_menu_detach_project
6868
icon: :trash,
6969
label: I18n.t("project_storages.remove_project.label"),
7070
href: destroy_confirmation_dialog_admin_settings_storage_project_storage_path(
71-
id: project_storage.id
71+
id: project_storage.id,
72+
page: current_page
7273
),
7374
data: {
7475
controller: "async-dialog"

Diff for: modules/storages/app/components/storages/project_storages/projects/table_component.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
# for every "column" defined below.
3333
module Storages::ProjectStorages::Projects
3434
class TableComponent < Projects::TableComponent
35-
include OpTurbo::Streamable
35+
include ::Projects::Concerns::TableComponent::StreamablePaginationLinksConstraints
3636

3737
options :storage
3838

Diff for: modules/storages/app/controllers/storages/admin/storages/project_storages_controller.rb

+3-2
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,8 @@ def update
117117
def destroy_confirmation_dialog
118118
respond_with_dialog Storages::ProjectStorages::DestroyConfirmationDialogComponent.new(
119119
storage: @storage,
120-
project_storage: @project_storage
120+
project_storage: @project_storage,
121+
params:
121122
)
122123
end
123124

@@ -186,7 +187,7 @@ def update_project_list_via_turbo_stream(url_for_action: action_name)
186187
component: Storages::ProjectStorages::Projects::TableComponent.new(
187188
query: storage_projects_query,
188189
storage: @storage,
189-
params: { url_for_action: }
190+
params: params.merge({ url_for_action: })
190191
)
191192
)
192193
end

Diff for: modules/storages/spec/features/storages/admin/project_storages_spec.rb

+21-2
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,10 @@
228228

229229
expect(page).to have_text(project.name)
230230
expect(page).to have_text(subproject.name)
231+
232+
aggregate_failures "pagination links maintain the correct url" do
233+
project_storages_index_page.expect_page_sizes(model: storage)
234+
end
231235
end
232236

233237
context "when the user does not select a folder" do
@@ -297,6 +301,10 @@
297301
project_storages_index_page.within_the_table_row_containing(project.name) do
298302
expect(page).to have_text("No specific folder")
299303
end
304+
305+
aggregate_failures "pagination links maintain the correct url" do
306+
project_storages_index_page.expect_page_sizes(model: storage)
307+
end
300308
end
301309

302310
context "when oauth access has not been granted and manual selection" do
@@ -363,8 +371,15 @@ def call
363371
expect(page).to have_text(project.name)
364372
end
365373

366-
it "is possible to remove the project after checking the confirmation checkbox in the dialog" do
367-
expect(page).to have_text(project.name)
374+
it "is possible to remove the project after checking the confirmation checkbox in the dialog",
375+
with_settings: { per_page_options: "2,5" } do
376+
projects = create_list(:project, 4)
377+
projects.each { |project| create(:project_storage, storage:, project:) }
378+
379+
current_page = 3
380+
visit admin_settings_storage_project_storages_path(storage, page: current_page)
381+
382+
project = project_storages_index_page.project_in_first_row(column_text_separator: "\t")
368383
project_storages_index_page.click_menu_item_of("Remove project", project)
369384

370385
# The original DeleteService would try to remove actual files from actual storages,
@@ -388,6 +403,10 @@ def call
388403
expect(page).to have_no_selector("dialog")
389404
expect(page).to have_text("Successful deletion.")
390405
expect(page).to have_no_text(project.name)
406+
407+
aggregate_failures "pagination links maintain the correct url" do
408+
project_storages_index_page.expect_page_links(model: storage, current_page:)
409+
end
391410
end
392411
end
393412
end

0 commit comments

Comments
 (0)