Skip to content

Commit

Permalink
Display warning text when progress calculation changes
Browse files Browse the repository at this point in the history
There is also a new helper to display HTML content in forms.
  • Loading branch information
cbliard committed Sep 11, 2024
1 parent 390d878 commit 2073a23
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 97 deletions.

This file was deleted.

15 changes: 8 additions & 7 deletions app/forms/settings_form_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ def check_box(name:, **options)
form.check_box(name:, **options)
end

def radio_button_group(name:, values:, **options)
def radio_button_group(name:, values:, button_options: {}, **options)
radio_group_options = options.reverse_merge(
label: setting_label(name)
)
Expand All @@ -71,13 +71,14 @@ def radio_button_group(name:, values:, **options)
**radio_group_options
) do |radio_group|
values.each do |value|
button_options = options.merge(
value:,
checked: setting_value(name) == value,
label: setting_label(name, value),
caption: setting_caption_html(name, value)
radio_group.radio_button(
**button_options.reverse_merge(
value:,
checked: setting_value(name) == value,
label: setting_label(name, value),
caption: setting_caption_html(name, value)
)
)
radio_group.radio_button(**button_options)
end
end
end
Expand Down
64 changes: 29 additions & 35 deletions app/views/admin/settings/progress_tracking/show.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -38,41 +38,35 @@ See COPYRIGHT and LICENSE files for more details.
end
%>

<%= primer_form_with(scope: :settings, action: :update, method: :patch) do |f| %>
<%= render Admin::Settings::ProgressTracking::ProgressCalculationModeForm.new(f) %>
<%= primer_form_with(
scope: :settings, action: :update, method: :patch,
data: {
application_target: "dynamic",
controller: "admin--progress-tracking",
admin__progress_tracking_target: "progressCalculationModeRadioGroup",
admin__progress_tracking_percent_complete_edition_active_value: OpenProject::FeatureDecisions.percent_complete_edition_active?,
admin__progress_tracking_initial_mode_value: Setting.work_package_done_ratio
}
) do |f| %>
<%=
render_inline_settings_form(f, &:submit)
%>
<% end %>

<%= styled_form_tag({ action: :update }, method: :patch) do %>
<section class="form--section"
data-application-target="dynamic"
data-controller="admin--progress-tracking"
data-admin--progress-tracking-percent-complete-edition-active-value="<%= OpenProject::FeatureDecisions.percent_complete_edition_active? %>">
<div class="form--field">
<%= setting_select :work_package_done_ratio,
WorkPackage::DONE_RATIO_OPTIONS.collect { |i| [t("setting_work_package_done_ratio_#{i}"), i] },
container_class: "-middle",
data: { admin__progress_tracking_target: "progressCalculationModeSelect",
action: "admin--progress-tracking#displayWarning" } %>
<div class="form--field-instructions"><%=
if OpenProject::FeatureDecisions.percent_complete_edition_active?
t("setting_work_package_done_ratio_explanation_html")
else
# This condition branch to be removed in 15.0 with :percent_complete_edition feature flag removal
t("setting_work_package_done_ratio_explanation_pre_14_4_without_percent_complete_edition_html")
render_inline_settings_form(f) do |form|
form.radio_button_group(
name: "work_package_done_ratio",
values: WorkPackage::DONE_RATIO_OPTIONS,
button_options: {
data: { action: "admin--progress-tracking#displayWarning" }
}
)
form.html_content do
tag.div(class: "op-toast -warning -with-bottom-spacing",
hidden: true,
data: { admin__progress_tracking_target: "warningToast" }) do
tag.div(class: "op-toast--content") do
tag.p(data: { admin__progress_tracking_target: "warningText" })
end
end
%></div>
</div>
<div class="op-toast -warning -with-bottom-spacing"
hidden
data-admin--progress-tracking-target="warningToast">
<div class="op-toast--content">
<p data-admin--progress-tracking-target="warningText"></p>
</div>
</div>
</section>

<%= styled_button_tag t(:button_save), class: "-primary -with-icon icon-checkmark" %>
end
form.submit
end
%>
<% end %>
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,22 @@ import { Controller } from '@hotwired/stimulus';

export default class ProgressTrackingController extends Controller {
static values = {
initialMode: String,
percentCompleteEditionActive: Boolean,
};

static targets = [
'progressCalculationModeSelect',
'progressCalculationModeRadioGroup',
'warningText',
'warningToast',
];

declare readonly initialModeValue:string;
declare readonly percentCompleteEditionActiveValue:boolean;

declare readonly progressCalculationModeSelectTarget:HTMLSelectElement;
declare readonly progressCalculationModeRadioGroupTarget:HTMLElement;
declare readonly warningTextTarget:HTMLElement;
declare readonly warningToastTarget:HTMLElement;
private initialMode:string;

connect() {
this.initialMode = this.progressCalculationModeSelectTarget.value;
}

displayWarning() {
const warningMessageHtml = this.getWarningMessageHtml();
Expand All @@ -62,21 +59,26 @@ export default class ProgressTrackingController extends Controller {
}
}

getSelectedMode() {
const checkedRadio = this.progressCalculationModeRadioGroupTarget.querySelector('input:checked') as HTMLInputElement;
return checkedRadio?.value || '';
}

getWarningMessageHtml():string {
const newMode = this.progressCalculationModeSelectTarget.value;
if (newMode === this.initialMode) {
const selectedMode = this.getSelectedMode();
if (selectedMode === this.initialModeValue || !selectedMode) {
return '';
}

// to be removed in 15.0 with :percent_complete_edition feature flag removal
if (!this.percentCompleteEditionActiveValue && newMode === 'field') {
if (!this.percentCompleteEditionActiveValue && selectedMode === 'field') {
return I18n.t(
'js.admin.work_packages_settings.warning_progress_calculation_mode_change_from_status_to_field_pre_14_4_without_percent_complete_edition_html',
);
}

return I18n.t(
`js.admin.work_packages_settings.warning_progress_calculation_mode_change_from_${this.initialMode}_to_${newMode}_html`,
`js.admin.work_packages_settings.warning_progress_calculation_mode_change_from_${this.initialModeValue}_to_${selectedMode}_html`,
);
}
}
28 changes: 28 additions & 0 deletions lib/primer/open_project/forms/dsl/html_content_input.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# frozen_string_literal: true

module Primer
module OpenProject
module Forms
module Dsl
class HtmlContentInput < Primer::Forms::Dsl::Input
def initialize(**system_arguments, &html_block)
@html_block = html_block

super(**system_arguments)
end

def to_component
HtmlContent.new(&@html_block)
end

def type
:html_content
end

def name = nil
def form_control? = false
end
end
end
end
end
4 changes: 4 additions & 0 deletions lib/primer/open_project/forms/dsl/input_methods.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ def rich_text_area(**)
def storage_manual_project_folder_selection(**)
add_input StorageManualProjectFolderSelectionInput.new(builder: @builder, form: @form, **)
end

def html_content(**, &)
add_input HtmlContentInput.new(builder: @builder, form: @form, **, &)
end
end
end
end
Expand Down
1 change: 1 addition & 0 deletions lib/primer/open_project/forms/html_content.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<%= rendered_html_content %>
21 changes: 21 additions & 0 deletions lib/primer/open_project/forms/html_content.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# frozen_string_literal: true

module Primer
module OpenProject
module Forms
# :nodoc:
class HtmlContent < Primer::Forms::BaseComponent
def initialize(&html_block)
super()
@html_block = html_block
end

def rendered_html_content
@view_context.capture do
@view_context.instance_exec(&@html_block)
end
end
end
end
end
end
72 changes: 72 additions & 0 deletions spec/features/admin/progress_tracking_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#-- 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.
#++

require "spec_helper"

RSpec.describe "Progress tracking admin page", :cuprite, :js,
with_flag: { percent_complete_edition: true } do
include ActionView::Helpers::SanitizeHelper
include Toasts::Expectations

shared_let(:admin) { create(:admin) }

it "displays a warning when changing progress calculation mode" do
Setting.work_package_done_ratio = "field"
login_as(admin)
visit admin_settings_progress_tracking_path

# change from work-based to status-based
expect(page).to have_field("Work-based", checked: true)
expect(page).to have_field("Status-based", checked: false)

find(:radio_button, "Status-based").click

expected_warning_text =
I18n.t("js.admin.work_packages_settings.warning_progress_calculation_mode_change_from_field_to_status_html")
expected_warning_text = strip_tags(expected_warning_text)[..80] # take only the beginning of the text
expect(page).to have_text(expected_warning_text)

click_on "Save"
expect_and_dismiss_toaster(message: "Successful update.")
expect(Setting.find_by(name: "work_package_done_ratio").value).to eq("status")

# now change from status-based to work-based
expect(page).to have_field("Work-based", checked: false)
expect(page).to have_field("Status-based", checked: true)

find(:radio_button, "Work-based").click
expected_warning_text =
I18n.t("js.admin.work_packages_settings.warning_progress_calculation_mode_change_from_status_to_field_html")
expected_warning_text = strip_tags(expected_warning_text)[..80] # take only the beginning of the text
expect(page).to have_text(expected_warning_text)

click_on "Save"
expect_and_dismiss_toaster(message: "Successful update.")
expect(Setting.find_by(name: "work_package_done_ratio").value).to eq("field")
end
end

0 comments on commit 2073a23

Please sign in to comment.