1
0
mirror of https://github.com/meineerde/redmine.git synced 2026-01-31 19:47:14 +00:00

"Progress bar" custom field format (#42335).

Patch by Jens Krämer (user:jkraemer).


git-svn-id: https://svn.redmine.org/redmine/trunk@23560 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
Go MAEDA 2025-03-26 10:33:46 +00:00
parent bacdb72670
commit 2b26027982
5 changed files with 144 additions and 0 deletions

View File

@ -843,6 +843,7 @@ de:
label_year: Jahr
label_yesterday: gestern
label_default_query: Standardabfrage
label_progressbar: Fortschrittsbalken
mail_body_account_activation_request: "Ein neuer Benutzer (%{value}) hat sich registriert. Sein Konto wartet auf Ihre Genehmigung:"
mail_body_account_information: Ihre Konto-Informationen

View File

@ -1150,6 +1150,7 @@ en:
label_edited: Edited
label_time_by_author: "%{time} by %{author}"
label_involved_principals: Author / Previous assignee
label_progressbar: Progress bar
button_login: Login
button_submit: Submit

View File

@ -1025,6 +1025,7 @@ fr:
for_this_user: For this user
label_trackers_description: Description des trackers
label_open_trackers_description: Afficher la description des trackers
label_progressbar: Barre de progression
button_login: Connexion
button_submit: Soumettre

View File

@ -1082,5 +1082,61 @@ module Redmine
})
end
end
class ProgressbarFormat < Numeric
add 'progressbar'
self.form_partial = nil
self.totalable_supported = false
def label
"label_progressbar"
end
def cast_single_value(custom_field, value, customized=nil)
value.to_i.clamp(0, 100)
end
def validate_single_value(custom_field, value, customized=nil)
errs = super
errs << ::I18n.t('activerecord.errors.messages.not_a_number') unless /^\d*$/.match?(value.to_s.strip)
errs << ::I18n.t('activerecord.errors.messages.invalid') unless value.to_i.between?(0, 100)
errs
end
def query_filter_options(custom_field, query)
{:type => :integer}
end
def group_statement(custom_field)
order_statement(custom_field)
end
def edit_tag(view, tag_id, tag_name, custom_value, options={})
view.select_tag(
tag_name,
view.options_for_select(
(0..100).step(Setting.issue_done_ratio_interval.to_i).to_a.collect {|r| ["#{r} %", r]},
custom_value.value
),
options.merge(id: tag_id, style: "width: 75px;")
)
end
def bulk_edit_tag(view, tag_id, tag_name, custom_field, objects, value, options={})
opts = view.options_for_select([[l(:label_no_change_option), '']] + (0..100).step(Setting.issue_done_ratio_interval.to_i).to_a.collect {|r| ["#{r} %", r]})
view.select_tag(tag_name, opts, options.merge(id: tag_id, style: "width: 75px;")) +
bulk_clear_tag(view, tag_id, tag_name, custom_field, value)
end
def formatted_value(view, custom_field, value, customized=nil, html=false)
text = "#{value}%"
if html
view.progress_bar(value.to_i, legend: (text if view.action_name == 'show'))
else
text
end
end
end
end
end

View File

@ -0,0 +1,85 @@
# frozen_string_literal: true
# Redmine - project management software
# Copyright (C) 2006- Jean-Philippe Lang
#
# 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.
require_relative '../../../../test_helper'
require 'redmine/field_format'
module Redmine::FieldFormat
class ProgressbarFormatTest < ActiveSupport::TestCase
def setup
@field = IssueCustomField.new(name: 'ProgressbarTest', field_format: 'progressbar')
@format = Redmine::FieldFormat::ProgressbarFormat.instance
end
def test_validate_invalid_value
cv = CustomValue.new(custom_field: @field, value: '120')
assert_include ::I18n.t('activerecord.errors.messages.invalid'), @format.validate_custom_value(cv)
end
def test_validate_numericality
cv = CustomValue.new(custom_field: @field, value: 'abc')
assert_include ::I18n.t('activerecord.errors.messages.not_a_number'), @format.validate_custom_value(cv)
end
def test_cast_value_clamping
assert_equal 0, @field.cast_value('-10')
assert_equal 0, @field.cast_value('0')
assert_equal 50, @field.cast_value('50')
assert_equal 100, @field.cast_value('120')
end
def test_empty_value
assert_nil @field.cast_value('')
end
def test_totalable_support
assert_not @format.totalable_supported?
end
def test_validate_non_numeric_value_should_fail
assert_include ::I18n.t('activerecord.errors.messages.not_a_number'),
@format.validate_single_value(@field, "abc")
end
def test_validate_negative_value_should_fail
assert_include ::I18n.t('activerecord.errors.messages.invalid'),
@format.validate_single_value(@field, "-10")
end
def test_validate_value_above_100_should_fail
assert_include ::I18n.t('activerecord.errors.messages.invalid'),
@format.validate_single_value(@field, "150")
end
def test_validate_valid_value_should_pass
assert_empty @format.validate_single_value(@field, "50")
assert_empty @format.validate_single_value(@field, "0")
assert_empty @format.validate_single_value(@field, "100")
end
def test_validate_blank_value_should_pass
assert_empty @format.validate_single_value(@field, "")
end
def test_query_filter_options
options = @format.query_filter_options(@field, nil)
assert_equal :integer, options[:type]
end
end
end