From b465b75b564f46f1413da6f165150487e1ad6588 Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 19 Nov 2025 17:04:07 +0100 Subject: [PATCH 01/16] Refactor postgresql? method to improve configuration handling --- lib/redmine_workload.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/redmine_workload.rb b/lib/redmine_workload.rb index 8371569..f910766 100644 --- a/lib/redmine_workload.rb +++ b/lib/redmine_workload.rb @@ -16,6 +16,12 @@ module RedmineWorkload # Check whether Redmine is running postgresql database def self.postgresql? - ActiveRecord::Base.configurations[Rails.env]['adapter'] == 'postgresql' + db_config = if ActiveRecord::Base.configurations.respond_to?(:configs_for) + ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first + else + ActiveRecord::Base.configurations[Rails.env] + end + adapter = db_config.respond_to?(:adapter) ? db_config.adapter : db_config['adapter'] + adapter == 'postgresql' end end From d8658c63fc9e3b98203dbc3d051806d6bbecdd4f Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 19 Nov 2025 17:30:14 +0100 Subject: [PATCH 02/16] Add step to install Subversion in workflow --- .github/workflows/5-0-stable.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/5-0-stable.yml b/.github/workflows/5-0-stable.yml index 4c2acf7..ae1cfc0 100644 --- a/.github/workflows/5-0-stable.yml +++ b/.github/workflows/5-0-stable.yml @@ -64,6 +64,8 @@ jobs: RAILS_ENV: test NAME: redmine_workload steps: + - name: Install svn + run: sudo apt-get update && sudo apt-get install -y subversion - name: Clone Redmine # Get the latest stable Redmine run: svn export http://svn.redmine.org/redmine/branches/5.0-stable/ redmine From 37d629311da3955949488817c67187c3ae9aacb0 Mon Sep 17 00:00:00 2001 From: Dave Cornewell Date: Fri, 6 Feb 2026 16:52:31 -0500 Subject: [PATCH 03/16] Updates to support Redmine 6 and Rails 7 --- CHANGELOG.md | 13 ++++++++++++- README.md | 4 ++-- app/controllers/workloads_controller.rb | 2 -- app/models/wl_national_holiday.rb | 2 -- app/models/wl_user_vacation.rb | 2 -- db/migrate/001_create_wl_user_vacations.rb | 2 +- db/migrate/002_create_wl_user_data.rb | 2 +- db/migrate/003_create_wl_national_holidays.rb | 2 +- db/migrate/004_add_main_group_to_wl_user_data.rb | 2 +- init.rb | 9 +++++---- lib/redmine_workload.rb | 8 +++++++- lib/redmine_workload/extensions/user_patch.rb | 3 ++- .../hooks/after_plugins_loaded_hook.rb | 2 +- 13 files changed, 33 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c93b066..9094923 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,17 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## 4.0.0 - 2026-02-06 + +### Changed + +* Updated for Redmine 6.0.x / Rails 7.2 compatibility +* Fixed Rails version comparisons to use Gem::Version +* Updated database adapter detection for Rails 7.2 +* Updated ActiveRecord migrations to version 7.2 +* Removed deprecated `unloadable` from controllers and models +* Fixed Ruby version comparison for PostgreSQL requirement + ## 3.0.2 - 2023-07-24 ### Deletes @@ -108,4 +119,4 @@ not at the bottom of the page --- -**NOTE** Changes prior and equal to version 1.1.0 are not reported. \ No newline at end of file +**NOTE** Changes prior and equal to version 1.1.0 are not reported. diff --git a/README.md b/README.md index bde7634..99c64be 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Workload Plugin for Redmine -![Redmine Workload Version](https://img.shields.io/badge/Redmine_Plugin-v3.0.2-red) ![Redmine Version](https://img.shields.io/badge/Redmine-v5.0.z-blue) ![Language Support](https://img.shields.io/badge/Languages-en,_de,_fr,_es,_it-green) ![Version Stage](https://img.shields.io/badge/Stage-release-important) ![ci](https://github.com/xmera-circle/redmine_workload/actions/workflows/5-0-stable.yml/badge.svg) +![Redmine Workload Version](https://img.shields.io/badge/Redmine_Plugin-v4.0.0-red) ![Redmine Version](https://img.shields.io/badge/v6.0.z-blue) ![Language Support](https://img.shields.io/badge/Languages-en,_de,_fr,_es,_it-green) ![Version Stage](https://img.shields.io/badge/Stage-release-important) ![ci](https://github.com/xmera-circle/redmine_workload/actions/workflows/5-0-stable.yml/badge.svg) A complete rewrite of the original workload-plugin from Rafael Calleja. The plugin calculates how much work each user would have to do per day in order to hit the deadlines for all his issues. @@ -140,4 +140,4 @@ Here you can export the values that are shown in the browser to use it in other |Hours of overdue issues|*hours*|Aggregated hours of issues that are behind schedule.| |Number of unplanned issues|*number*|Number of issues that are unplanned.| |Hours of unplanned issues|*hours*|Aggregated hours of issues that are unplanned.| -|..date..|*datum* and *hours*|Column is named from the belonging datum. Lists per line the hours per day.| \ No newline at end of file +|..date..|*datum* and *hours*|Column is named from the belonging datum. Lists per line the hours per day.| diff --git a/app/controllers/workloads_controller.rb b/app/controllers/workloads_controller.rb index 3d2085c..d6ff120 100644 --- a/app/controllers/workloads_controller.rb +++ b/app/controllers/workloads_controller.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class WorkloadsController < ApplicationController - unloadable - helper :gantt helper :issues helper :projects diff --git a/app/models/wl_national_holiday.rb b/app/models/wl_national_holiday.rb index e3724f0..4ca94f1 100644 --- a/app/models/wl_national_holiday.rb +++ b/app/models/wl_national_holiday.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class WlNationalHoliday < ActiveRecord::Base - unloadable - validates :start, date: true validates :end, date: true validates :start, :end, :reason, presence: true diff --git a/app/models/wl_user_vacation.rb b/app/models/wl_user_vacation.rb index 1a79698..caf679a 100644 --- a/app/models/wl_user_vacation.rb +++ b/app/models/wl_user_vacation.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true class WlUserVacation < ActiveRecord::Base - unloadable - belongs_to :user, inverse_of: :wl_user_vacations, optional: true validates :date_from, date: true diff --git a/db/migrate/001_create_wl_user_vacations.rb b/db/migrate/001_create_wl_user_vacations.rb index b8f2a27..f4ee30c 100644 --- a/db/migrate/001_create_wl_user_vacations.rb +++ b/db/migrate/001_create_wl_user_vacations.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class CreateWlUserVacations < ActiveRecord::Migration[5.2] +class CreateWlUserVacations < ActiveRecord::Migration[7.2] def change create_table :wl_user_vacations do |t| t.belongs_to :user, index: true, null: false diff --git a/db/migrate/002_create_wl_user_data.rb b/db/migrate/002_create_wl_user_data.rb index e6c4412..aade81b 100644 --- a/db/migrate/002_create_wl_user_data.rb +++ b/db/migrate/002_create_wl_user_data.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class CreateWlUserData < ActiveRecord::Migration[5.2] +class CreateWlUserData < ActiveRecord::Migration[7.2] def change create_table :wl_user_datas do |t| t.belongs_to :user, index: true, null: false diff --git a/db/migrate/003_create_wl_national_holidays.rb b/db/migrate/003_create_wl_national_holidays.rb index 73a13fd..7a84dab 100644 --- a/db/migrate/003_create_wl_national_holidays.rb +++ b/db/migrate/003_create_wl_national_holidays.rb @@ -1,6 +1,6 @@ # frozen_string_literal: true -class CreateWlNationalHolidays < ActiveRecord::Migration[5.2] +class CreateWlNationalHolidays < ActiveRecord::Migration[7.2] def change create_table :wl_national_holidays do |t| t.date :start, null: false diff --git a/db/migrate/004_add_main_group_to_wl_user_data.rb b/db/migrate/004_add_main_group_to_wl_user_data.rb index bb334a4..9595e34 100644 --- a/db/migrate/004_add_main_group_to_wl_user_data.rb +++ b/db/migrate/004_add_main_group_to_wl_user_data.rb @@ -4,7 +4,7 @@ # Adds main_group column to store the users group which should be considered when # calculating group workloads. # -class AddMainGroupToWlUserData < ActiveRecord::Migration[5.2] +class AddMainGroupToWlUserData < ActiveRecord::Migration[7.2] def change add_column :wl_user_datas, :main_group, :integer add_index :wl_user_datas, :main_group diff --git a/init.rb b/init.rb index 24d4610..2d68e56 100755 --- a/init.rb +++ b/init.rb @@ -9,11 +9,11 @@ description 'This is a plugin for Redmine, originally developed by Rafael Calleja. It ' \ 'displays the estimated number of hours users and groups have to work to finish ' \ 'all their assigned issus on time.' - version '3.0.2' + version '4.0.0' url 'https://github.com/xmera-circle/redmine_workload' - if RedmineWorkload.postgresql? && RUBY_VERSION <= '3.1' - msg = "#{name} requires at least Ruby 3.1.z when using postgresql database." + if RedmineWorkload.postgresql? && Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.1.0') + msg = "#{name} requires at least Ruby 3.1.0 when using postgresql database." raise Redmine::PluginRequirementError, msg end @@ -49,7 +49,8 @@ permission :edit_user_data, wl_user_datas: :update end -if Rails.version < '6' +# Rails 6+ handles autoloading differently with Zeitwerk +if Gem::Version.new(Rails.version) < Gem::Version.new('6.0') plugin = Redmine::Plugin.find(:redmine_workload) Rails.application.configure do config.autoload_paths << "#{plugin.directory}/app/presenters" diff --git a/lib/redmine_workload.rb b/lib/redmine_workload.rb index 8371569..f910766 100644 --- a/lib/redmine_workload.rb +++ b/lib/redmine_workload.rb @@ -16,6 +16,12 @@ module RedmineWorkload # Check whether Redmine is running postgresql database def self.postgresql? - ActiveRecord::Base.configurations[Rails.env]['adapter'] == 'postgresql' + db_config = if ActiveRecord::Base.configurations.respond_to?(:configs_for) + ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first + else + ActiveRecord::Base.configurations[Rails.env] + end + adapter = db_config.respond_to?(:adapter) ? db_config.adapter : db_config['adapter'] + adapter == 'postgresql' end end diff --git a/lib/redmine_workload/extensions/user_patch.rb b/lib/redmine_workload/extensions/user_patch.rb index 72924d2..03b84c6 100644 --- a/lib/redmine_workload/extensions/user_patch.rb +++ b/lib/redmine_workload/extensions/user_patch.rb @@ -28,7 +28,8 @@ def main_group_id end end -if Rails.version < '6' +# Rails 6+ uses after_plugins_loaded hook instead +if Gem::Version.new(Rails.version) < Gem::Version.new('6.0') Rails.configuration.to_prepare do unless User.included_modules.include?(RedmineWorkload::Extensions::UserPatch) User.prepend RedmineWorkload::Extensions::UserPatch diff --git a/lib/redmine_workload/hooks/after_plugins_loaded_hook.rb b/lib/redmine_workload/hooks/after_plugins_loaded_hook.rb index c0199a0..fca7dc3 100644 --- a/lib/redmine_workload/hooks/after_plugins_loaded_hook.rb +++ b/lib/redmine_workload/hooks/after_plugins_loaded_hook.rb @@ -4,7 +4,7 @@ module RedmineWorkload module Hooks class AfterPluginsLoadedHook < Redmine::Hook::Listener def after_plugins_loaded(_context = {}) - return unless Rails.version > '6' + return unless Gem::Version.new(Rails.version) >= Gem::Version.new('6.0') patch = RedmineWorkload::Extensions::UserPatch klass = User From 42e46fe18568feb274153ef58e3ab791ba35eb07 Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 21 Mar 2026 17:42:02 +0000 Subject: [PATCH 04/16] Fix HTTP 500 error when invalid date is entered in workload filter Wrap the `to_date` conversion in `sanitizeDateParameter` with a begin-rescue block to catch `Date::Error`. Previously, strings like "2026-01-32" passed the `respond_to?(:to_date)` check but raised an unhandled exception during conversion. Now invalid dates fall back to the default value instead of crashing. Adds functional tests for all three date parameters (first_day, last_day, start_date) to cover the invalid date case. Fixes https://github.com/xmera-circle/redmine_workload/issues/41 https://claude.ai/code/session_01BSqVnAYvK1kCejeMnp4MqM --- app/controllers/workloads_controller.rb | 10 ++++---- test/functional/workloads_controller_test.rb | 27 ++++++++++++++++++++ 2 files changed, 32 insertions(+), 5 deletions(-) diff --git a/app/controllers/workloads_controller.rb b/app/controllers/workloads_controller.rb index 3d2085c..93e96d6 100644 --- a/app/controllers/workloads_controller.rb +++ b/app/controllers/workloads_controller.rb @@ -110,10 +110,10 @@ def assignee_ids end def sanitizeDateParameter(parameter, default) - if parameter.respond_to?(:to_date) - parameter.to_date - else - default - end + return default unless parameter.respond_to?(:to_date) + + parameter.to_date + rescue Date::Error + default end end diff --git a/test/functional/workloads_controller_test.rb b/test/functional/workloads_controller_test.rb index ec894b0..644d6e6 100644 --- a/test/functional/workloads_controller_test.rb +++ b/test/functional/workloads_controller_test.rb @@ -43,5 +43,32 @@ class WorkloadsControllerTest < ActionDispatch::IntegrationTest assert flash[:error].match(/Character encoding not allowed./) end + + test 'should get index with invalid first_day date without raising an error' do + manager = roles :roles_001 + manager.add_permission! :view_all_workloads + log_user('jsmith', 'jsmith') + + get workloads_path(workload: { first_day: '2026-01-32' }) + assert_response :success + end + + test 'should get index with invalid last_day date without raising an error' do + manager = roles :roles_001 + manager.add_permission! :view_all_workloads + log_user('jsmith', 'jsmith') + + get workloads_path(workload: { last_day: '2026-13-01' }) + assert_response :success + end + + test 'should get index with invalid start_date without raising an error' do + manager = roles :roles_001 + manager.add_permission! :view_all_workloads + log_user('jsmith', 'jsmith') + + get workloads_path(workload: { start_date: 'not-a-date' }) + assert_response :success + end end end From ca4be9dcc7b7821cdd8cd353b93d91e6b0fcbf2c Mon Sep 17 00:00:00 2001 From: Claude Date: Sat, 21 Mar 2026 18:09:35 +0000 Subject: [PATCH 05/16] Fix HTTP 500 when 'Use as today' date is after end date When the user sets a 'Use as today' (start_date) value beyond the last_day of the displayed time span, the UserWorkload model crashes with a NoMethodError because 'today' falls outside the time_span and hours_for_issue[today] returns nil. Cap @today to @last_day in the controller before passing it to UserWorkload. Show a flash warning when the capping occurs so the user is informed. Fixes #40 https://claude.ai/code/session_01BSqVnAYvK1kCejeMnp4MqM --- app/controllers/workloads_controller.rb | 7 ++++++ config/locales/de.yml | 1 + config/locales/en.yml | 1 + test/functional/workloads_controller_test.rb | 26 ++++++++++++++++++++ 4 files changed, 35 insertions(+) diff --git a/app/controllers/workloads_controller.rb b/app/controllers/workloads_controller.rb index 93e96d6..9040eee 100644 --- a/app/controllers/workloads_controller.rb +++ b/app/controllers/workloads_controller.rb @@ -32,6 +32,12 @@ def index # Make sure that last_day is at most 12 months after first_day to prevent # long running times @last_day = [(@first_day >> 12) - 1, @last_day].min + + # Make sure that today is not after last_day to prevent a crash in the + # workload calculation (today would be outside the time span) + @today_capped = @today > @last_day + @today = [@today, @last_day].min + @time_span_to_display = @first_day..@last_day if @date_check @@ -56,6 +62,7 @@ def index respond_to do |format| format.html do flash.now[:error] = l(:error_date_setting) unless @date_check + flash.now[:warning] = l(:warning_today_capped_to_last_day) if @today_capped render action: :index end diff --git a/config/locales/de.yml b/config/locales/de.yml index 0aee4b8..5a28ec0 100755 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -100,6 +100,7 @@ de: workload_unscheduled_issues_num: 'Anzahl ungeplanter Tickets:' workload_unscheduled_issues_hours: 'Stunden aus ungeplanten Tickets:' error_date_setting: 'Überprüfen Sie Ihre Eingabe! Das Enddatum (bis) liegt vor dem Startdatum (von).' + warning_today_capped_to_last_day: 'Das "Als Heute verwenden"-Datum lag nach dem Enddatum und wurde auf das Enddatum gesetzt.' error_encoding_setting: 'Zeichenkodierung nicht erlaubt. Gültige Werte: %{value}.' label_workload_calculation: Workloadberechnung label_include_parent_tasks: Hauptaufgaben einbeziehen diff --git a/config/locales/en.yml b/config/locales/en.yml index 670b832..b111ff9 100755 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -100,6 +100,7 @@ en: workload_unscheduled_issues_num: 'Number of unscheduled issues:' workload_unscheduled_issues_hours: 'Hours of unscheduled issues:' error_date_setting: 'Please check your data! The end date is before the start date.' + warning_today_capped_to_last_day: 'The "Use as today" date was after the end date and has been set to the end date.' error_encoding_setting: 'Character encoding not allowed. Valid values: %{value}.' label_workload_calculation: Workload calculation label_include_parent_tasks: Include parent tasks diff --git a/test/functional/workloads_controller_test.rb b/test/functional/workloads_controller_test.rb index 644d6e6..c039a85 100644 --- a/test/functional/workloads_controller_test.rb +++ b/test/functional/workloads_controller_test.rb @@ -70,5 +70,31 @@ class WorkloadsControllerTest < ActionDispatch::IntegrationTest get workloads_path(workload: { start_date: 'not-a-date' }) assert_response :success end + + test 'should get index without error when start_date is after last_day' do + manager = roles :roles_001 + manager.add_permission! :view_all_workloads + log_user('jsmith', 'jsmith') + + get workloads_path(workload: { + first_day: '2026-01-01', + last_day: '2026-01-31', + start_date: '2026-06-01' + }) + assert_response :success + end + + test 'should show warning when start_date is after last_day' do + manager = roles :roles_001 + manager.add_permission! :view_all_workloads + log_user('jsmith', 'jsmith') + + get workloads_path(workload: { + first_day: '2026-01-01', + last_day: '2026-01-31', + start_date: '2026-06-01' + }) + assert flash[:warning].present? + end end end From 62abdab04e3ae4eca85fd7deef4e769594545d3e Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 08:13:48 +0000 Subject: [PATCH 06/16] CI: run tests against Redmine 6.1-stable The 4.x line requires Redmine 6: migrations were bumped to ActiveRecord::Migration[7.2] in 4.0.0, which Rails 6.1 (Redmine 5.0) rejects with `Unknown migration version "7.2"`. The workflow therefore could not pass against 5.0-stable any more. Changes: * Rename 5-0-stable.yml to 6-1-stable.yml and export branches/6.1-stable instead of 5.0-stable. * Bump Ruby to 3.2. Redmine 6.1 requires `ruby '>= 3.2.0', '< 3.5.0'`, so `bundle install` fails on 3.1. * Add `rake assets:precompile` after the migrations. Redmine 6 uses Propshaft. * actions/checkout v3 -> v4. Workflow name ("GitHub CI") and job id (plugin_tests) are unchanged so existing required status checks keep matching. Redmine 5 remains served by the 3.x line. README: point the CI badge at the renamed workflow. --- .github/workflows/{5-0-stable.yml => 6-1-stable.yml} | 10 +++++++--- README.md | 2 +- 2 files changed, 8 insertions(+), 4 deletions(-) rename .github/workflows/{5-0-stable.yml => 6-1-stable.yml} (94%) diff --git a/.github/workflows/5-0-stable.yml b/.github/workflows/6-1-stable.yml similarity index 94% rename from .github/workflows/5-0-stable.yml rename to .github/workflows/6-1-stable.yml index ae1cfc0..6b2f93b 100644 --- a/.github/workflows/5-0-stable.yml +++ b/.github/workflows/6-1-stable.yml @@ -1,5 +1,8 @@ # This configuration is taken from Redmine DMSF plugin # and adapted to the needs of Redmine Workload plugin. +# +# Targets Redmine 6.1-stable (Rails 7.2). Plugin versions 4.x require +# Redmine 6; for Redmine 5 use the 3.x line. # # Copyright © 2023 Liane Hampe # Copyright © 2022-23 Karel Pičman @@ -68,16 +71,16 @@ jobs: run: sudo apt-get update && sudo apt-get install -y subversion - name: Clone Redmine # Get the latest stable Redmine - run: svn export http://svn.redmine.org/redmine/branches/5.0-stable/ redmine + run: svn export http://svn.redmine.org/redmine/branches/6.1-stable/ redmine - name: Checkout plugin - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: redmine/plugins/${{ env.NAME }} - name: Install Ruby and gems uses: ruby/setup-ruby@v1 with: bundler-cache: true - ruby-version: '3.1' + ruby-version: '3.2' - name: Setup database # Create the database run: | @@ -100,6 +103,7 @@ jobs: bundle exec rake db:migrate bundle exec rake redmine:plugins:migrate bundle exec rake redmine:load_default_data + bundle exec rake assets:precompile env: REDMINE_LANG: en working-directory: redmine diff --git a/README.md b/README.md index 99c64be..99d90e1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Workload Plugin for Redmine -![Redmine Workload Version](https://img.shields.io/badge/Redmine_Plugin-v4.0.0-red) ![Redmine Version](https://img.shields.io/badge/v6.0.z-blue) ![Language Support](https://img.shields.io/badge/Languages-en,_de,_fr,_es,_it-green) ![Version Stage](https://img.shields.io/badge/Stage-release-important) ![ci](https://github.com/xmera-circle/redmine_workload/actions/workflows/5-0-stable.yml/badge.svg) +![Redmine Workload Version](https://img.shields.io/badge/Redmine_Plugin-v4.0.0-red) ![Redmine Version](https://img.shields.io/badge/v6.0.z-blue) ![Language Support](https://img.shields.io/badge/Languages-en,_de,_fr,_es,_it-green) ![Version Stage](https://img.shields.io/badge/Stage-release-important) ![ci](https://github.com/xmera-circle/redmine_workload/actions/workflows/6-1-stable.yml/badge.svg) A complete rewrite of the original workload-plugin from Rafael Calleja. The plugin calculates how much work each user would have to do per day in order to hit the deadlines for all his issues. From 0c1c1c4721ad07226586fa0beb94f5934b41b51c Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 08:31:03 +0000 Subject: [PATCH 07/16] Fix test_helper for Rails 7.2: do not use Rails.root at load time `rake redmine:plugins:test:units` runs the tests through `Rails::TestUnit::Runner.run_from_rake`, which spawns `bin/rails test` in a separate process. That process requires the test files *before* the Rails environment is loaded, and on Rails 7.2 `rails/commands` no longer pulls in railties' `rails.rb` on the way. `Rails` is then only a bare namespace module and `Rails.root` does not exist: test/test_helper.rb:4:in `': undefined method `root' for Rails:Module (NoMethodError) On Rails 6.1 (Redmine 5.0) `rails.rb` happened to be loaded by then, so the same line worked. Resolve Redmine's test_helper by path instead, which is what Redmine's own plugins do and what the environment does not have to be loaded for. plugins//test/test_helper.rb -> ../../../test/test_helper --- test/test_helper.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_helper.rb b/test/test_helper.rb index 3c00634..ea5ed43 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true # Load the normal Rails helper -require Rails.root.join('test/test_helper.rb') +require File.expand_path('../../../test/test_helper', __dir__) # Load other test helper modules require File.expand_path('authenticate_user', __dir__) require File.expand_path('workload_object_helper', __dir__) From 08c7604ade0cc6fa97daa669a9043938679690f7 Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 08:31:13 +0000 Subject: [PATCH 08/16] CI: upload test.log when a run fails The plugin test tasks print the failure but not the surrounding log. Attaching test.log as an artifact on failure makes the next iteration diagnosable without reproducing locally. Taken from the DMSF workflow. --- .github/workflows/6-1-stable.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/workflows/6-1-stable.yml b/.github/workflows/6-1-stable.yml index 6b2f93b..6a383f8 100644 --- a/.github/workflows/6-1-stable.yml +++ b/.github/workflows/6-1-stable.yml @@ -114,6 +114,14 @@ jobs: bundle exec rake redmine:plugins:test:units bundle exec rake redmine:plugins:test:functionals bundle exec rake redmine:plugins:test:integration + - name: Archive test.log + # Keep the log so failing runs can be diagnosed + if: failure() + uses: actions/upload-artifact@v4 + with: + name: "test_${{matrix.engine}}.log" + path: redmine/log/test.log + if-no-files-found: ignore - name: Cleanup # Rollback plugin's changes to the database # Stop the database engine From 7575e0a876dd825ee6f200b8d0df6dc6573e3e91 Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 08:46:26 +0000 Subject: [PATCH 09/16] Fix WlUserSelectionTest for Redmine 6 fixture loading Two tests failed with exactly one extra user: WlUserSelectionTest#test_should_return_all_users_if_the_current_user_is_admin WlUserSelectionTest#test_should_return_all_active_users_when_user_has_permission_:view_all_workloads Redmine 6.0 added `fixtures :all` to ActiveSupport::TestCase in test/test_helper.rb; Redmine 5.0 did not have it. Every fixture file is now loaded no matter what a test class declares, including groups_users.yml, which makes users(:users_008) a member of groups 10 and 11. `WlUserSelection#all_users` is `User.joins(:groups).distinct.active` -- every user belonging to any group. Under Redmine 6 that legitimately includes users(:users_008), so comparing against only the users generated in setup is wrong. Confirmed in the CI log: WlUserData Load ... WHERE `wl_user_datas`.`user_id` IN (8, 41, 42, 43) The plugin behaves correctly; only the tests' assumption about the fixture universe was stale. Record the pre-existing group members in setup and add them to the expectation, walking Group#users rather than reusing the scope under test. Note that the per-class `fixtures ...` declarations throughout this plugin's test suite are effectively inert on Redmine 6 for the same reason. They are left alone here. --- test/unit/user_selection_test.rb | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/test/unit/user_selection_test.rb b/test/unit/user_selection_test.rb index 77411d0..cb40dc2 100644 --- a/test/unit/user_selection_test.rb +++ b/test/unit/user_selection_test.rb @@ -10,6 +10,15 @@ class WlUserSelectionTest < ActiveSupport::TestCase :users, :issue_statuses, :enumerations, :roles def setup + # Redmine >= 6.0 declares `fixtures :all` in its own test_helper, so every + # fixture file is loaded regardless of what a test class asks for. Among + # them is groups_users.yml, which makes users(:users_008) a member of two + # groups. Queries for "all users belonging to any group" therefore no + # longer return only the users generated below. Record what is already + # there before adding anything. + @fixture_group_member_ids = + Group.all.flat_map { |group| group.users.select(&:active?) }.map(&:id).uniq + @group1 = Group.generate! @group2 = Group.generate! @group3 = Group.generate! @@ -26,11 +35,19 @@ def setup @group_member_ids end + ## + # All users a global workload query may return: the ones generated in setup + # plus the group members that come from Redmine's own fixtures. + # + def all_group_member_ids + (@fixture_group_member_ids + @group_member_ids.flatten).uniq.sort + end + test 'should return all users if the current user is admin' do current_user = User.generate!(admin: true) groups = WlGroupSelection.new(user: current_user, groups: [@group1.id, @group2.id, @group3.id]) users = WlUserSelection.new(user: current_user, group_selection: groups) - assert_equal @group_member_ids.flatten.sort, users.allowed_to_display.map(&:id).sort + assert_equal all_group_member_ids, users.allowed_to_display.map(&:id).sort end test 'should return all active users when user has permission :view_all_workloads' do @@ -40,7 +57,7 @@ def setup groups = WlGroupSelection.new(user: current_user, groups: [@group1.id, @group2.id, @group3.id]) users = WlUserSelection.new(user: current_user, group_selection: groups) - expected = @group_member_ids.flatten.sort + expected = all_group_member_ids current = users.send(:all_users).map(&:id).sort assert_equal expected, current end From 86f220de34bbe391ed431b9a41b32a27498bbcec Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 08:13:48 +0000 Subject: [PATCH 10/16] Declare Redmine 6.1 as the supported version 4.0.0 announced Redmine 6.0.x, but nothing in the repository ever tested against Redmine 6 and the plugin had no `requires_redmine` at all, so an incompatible install failed with a stack trace instead of a clear message. * init.rb: add `requires_redmine version_or_higher: '6.1'`. * README/CHANGELOG: state 6.1.z, the version the CI workflow covers. Redmine 6.0.z ships the same Rails 7.2 and probably works, but it is untested and therefore not claimed. * README: add a "support of Redmine 6" section spelling out that 4.x is not backward compatible (Migration[7.2]) and that Redmine 5 stays on the 3.x line. * README: the PostgreSQL/Ruby 3.1 warning is moot now that Redmine 6.1 requires Ruby >= 3.2; keep the note but say so. --- CHANGELOG.md | 4 +++- README.md | 16 ++++++++++++++-- init.rb | 1 + 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9094923..bfd71a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,12 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed -* Updated for Redmine 6.0.x / Rails 7.2 compatibility +* Updated for Redmine 6.1.x / Rails 7.2 compatibility * Fixed Rails version comparisons to use Gem::Version * Updated database adapter detection for Rails 7.2 * Updated ActiveRecord migrations to version 7.2 * Removed deprecated `unloadable` from controllers and models * Fixed Ruby version comparison for PostgreSQL requirement +* Declared `requires_redmine version_or_higher: '6.1'` +* CI now runs against Redmine 6.1-stable on Ruby 3.2 instead of 5.0-stable ## 3.0.2 - 2023-07-24 diff --git a/README.md b/README.md index 99d90e1..016ccd1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Workload Plugin for Redmine -![Redmine Workload Version](https://img.shields.io/badge/Redmine_Plugin-v4.0.0-red) ![Redmine Version](https://img.shields.io/badge/v6.0.z-blue) ![Language Support](https://img.shields.io/badge/Languages-en,_de,_fr,_es,_it-green) ![Version Stage](https://img.shields.io/badge/Stage-release-important) ![ci](https://github.com/xmera-circle/redmine_workload/actions/workflows/6-1-stable.yml/badge.svg) +![Redmine Workload Version](https://img.shields.io/badge/Redmine_Plugin-v4.0.0-red) ![Redmine Version](https://img.shields.io/badge/Redmine-v6.1.z-blue) ![Language Support](https://img.shields.io/badge/Languages-en,_de,_fr,_es,_it-green) ![Version Stage](https://img.shields.io/badge/Stage-release-important) ![ci](https://github.com/xmera-circle/redmine_workload/actions/workflows/6-1-stable.yml/badge.svg) A complete rewrite of the original workload-plugin from Rafael Calleja. The plugin calculates how much work each user would have to do per day in order to hit the deadlines for all his issues. @@ -33,7 +33,19 @@ The encoding options are the same as on the page itself and might depend on your Workday settings are fixed now (see [#27](https://github.com/xmera-circle/redmine_workload/issues/27)) but lead to restrictions for PostgreSQL user. - :warning: **With PostgreSQL installed you need to run Ruby 3.1.z!** + :warning: **PostgreSQL requires Ruby 3.1 or newer.** Redmine 6.1 requires Ruby 3.2 +or newer anyway, so this is no longer a separate constraint for the 4.x line. + +## New Features in Version 4.0.0 + +### support of Redmine 6 + +Version 4.0.0 supports Redmine 6.1.z and is **not** backward compatible: the +database migrations are on `ActiveRecord::Migration[7.2]`, which Redmine 5 +(Rails 6.1) cannot load. Installations on Redmine 5 stay on the 3.x line. + +Redmine 6.0.z ships the same Rails 7.2 and is likely to work, but it is not +covered by the test workflow and therefore not claimed as supported. ## New Features in Version 2.2.0 diff --git a/init.rb b/init.rb index 2d68e56..7e6923a 100755 --- a/init.rb +++ b/init.rb @@ -11,6 +11,7 @@ 'all their assigned issus on time.' version '4.0.0' url 'https://github.com/xmera-circle/redmine_workload' + requires_redmine version_or_higher: '6.1' if RedmineWorkload.postgresql? && Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.1.0') msg = "#{name} requires at least Ruby 3.1.0 when using postgresql database." From 9e80dfc571a9d0886d44be1302aadac86030cc54 Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 08:13:48 +0000 Subject: [PATCH 11/16] Remove code that cannot run on Redmine 6 With `requires_redmine >= 6.1` the plugin always runs on Rails 7.2 and Ruby >= 3.2, which makes several branches unreachable: * init.rb: the `Rails.version < '6'` block added `app/presenters` to `autoload_paths`. That directory does not exist in this repository, so the branch was dead even on Rails 5. * user_patch.rb: the `to_prepare` fallback for Rails < 6. The after_plugins_loaded hook does this on every supported version. * after_plugins_loaded_hook.rb: the Rails >= 6 guard is now always true. * init.rb / lib/redmine_workload.rb: the PostgreSQL Ruby-version guard and `RedmineWorkload.postgresql?`, its only caller. Redmine 6.1 requires Ruby >= 3.2, so the guard can never fire. If a PostgreSQL specific check is needed again, reinstate it with a real reason. No behaviour change on Redmine 6. --- CHANGELOG.md | 6 ++++++ init.rb | 13 ------------- lib/redmine_workload.rb | 14 -------------- lib/redmine_workload/extensions/user_patch.rb | 9 --------- .../hooks/after_plugins_loaded_hook.rb | 2 -- 5 files changed, 6 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bfd71a9..59f7569 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Declared `requires_redmine version_or_higher: '6.1'` * CI now runs against Redmine 6.1-stable on Ruby 3.2 instead of 5.0-stable +### Removed + +* Dead `Rails.version < '6'` branches in `init.rb` and `user_patch.rb` +* Ruby version guard for PostgreSQL and `RedmineWorkload.postgresql?`, + unreachable since Redmine 6.1 requires Ruby >= 3.2 + ## 3.0.2 - 2023-07-24 ### Deletes diff --git a/init.rb b/init.rb index 7e6923a..31f8df1 100755 --- a/init.rb +++ b/init.rb @@ -13,11 +13,6 @@ url 'https://github.com/xmera-circle/redmine_workload' requires_redmine version_or_higher: '6.1' - if RedmineWorkload.postgresql? && Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.1.0') - msg = "#{name} requires at least Ruby 3.1.0 when using postgresql database." - raise Redmine::PluginRequirementError, msg - end - menu :top_menu, :WorkLoad, { controller: 'workloads', action: 'index' }, @@ -50,14 +45,6 @@ permission :edit_user_data, wl_user_datas: :update end -# Rails 6+ handles autoloading differently with Zeitwerk -if Gem::Version.new(Rails.version) < Gem::Version.new('6.0') - plugin = Redmine::Plugin.find(:redmine_workload) - Rails.application.configure do - config.autoload_paths << "#{plugin.directory}/app/presenters" - end -end - class RedmineToolbarHookListener < Redmine::Hook::ViewListener def view_layouts_base_html_head(_context) javascript_include_tag('slides', plugin: :redmine_workload) + diff --git a/lib/redmine_workload.rb b/lib/redmine_workload.rb index f910766..9f8265d 100644 --- a/lib/redmine_workload.rb +++ b/lib/redmine_workload.rb @@ -11,17 +11,3 @@ require File.expand_path('redmine_workload/wl_issue_state', __dir__) require File.expand_path('redmine_workload/wl_user_data_finder', __dir__) require File.expand_path('redmine_workload/wl_user_data_defaults', __dir__) - -# Simple Rails related methods -module RedmineWorkload - # Check whether Redmine is running postgresql database - def self.postgresql? - db_config = if ActiveRecord::Base.configurations.respond_to?(:configs_for) - ActiveRecord::Base.configurations.configs_for(env_name: Rails.env).first - else - ActiveRecord::Base.configurations[Rails.env] - end - adapter = db_config.respond_to?(:adapter) ? db_config.adapter : db_config['adapter'] - adapter == 'postgresql' - end -end diff --git a/lib/redmine_workload/extensions/user_patch.rb b/lib/redmine_workload/extensions/user_patch.rb index 03b84c6..568b240 100644 --- a/lib/redmine_workload/extensions/user_patch.rb +++ b/lib/redmine_workload/extensions/user_patch.rb @@ -27,12 +27,3 @@ def main_group_id end end end - -# Rails 6+ uses after_plugins_loaded hook instead -if Gem::Version.new(Rails.version) < Gem::Version.new('6.0') - Rails.configuration.to_prepare do - unless User.included_modules.include?(RedmineWorkload::Extensions::UserPatch) - User.prepend RedmineWorkload::Extensions::UserPatch - end - end -end diff --git a/lib/redmine_workload/hooks/after_plugins_loaded_hook.rb b/lib/redmine_workload/hooks/after_plugins_loaded_hook.rb index fca7dc3..a7172db 100644 --- a/lib/redmine_workload/hooks/after_plugins_loaded_hook.rb +++ b/lib/redmine_workload/hooks/after_plugins_loaded_hook.rb @@ -4,8 +4,6 @@ module RedmineWorkload module Hooks class AfterPluginsLoadedHook < Redmine::Hook::Listener def after_plugins_loaded(_context = {}) - return unless Gem::Version.new(Rails.version) >= Gem::Version.new('6.0') - patch = RedmineWorkload::Extensions::UserPatch klass = User klass.prepend patch unless klass.included_modules.include?(patch) From ddf321437b6f65529913fdfeab4aabcd85039bb3 Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 10:04:55 +0000 Subject: [PATCH 12/16] CHANGELOG: record the fixes that went into 4.0.0 The two bug fixes and the two test fixes were not listed yet. Keeps the 4.0.0 section a complete description of what changed since 3.0.2. The 4.0.0 date still reads 2026-02-06 and should be updated when the version is actually tagged. --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 59f7569..c49541d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Declared `requires_redmine version_or_higher: '6.1'` * CI now runs against Redmine 6.1-stable on Ruby 3.2 instead of 5.0-stable +### Fixed + +* HTTP 500 when an invalid date such as `2026-01-32` was entered in a workload + filter; invalid input now falls back to the default value (#41) +* HTTP 500 when the 'Use as today' date was set beyond the last day of the + displayed time span; the date is capped and a flash warning is shown (#40) +* `test/test_helper.rb` no longer uses `Rails.root` at load time. Rails 7.2 runs + plugin tests in a separate process that requires the test files before the + environment is loaded, where `Rails.root` does not exist +* `WlUserSelectionTest` accounts for Redmine 6's `fixtures :all`, which makes + `users(:users_008)` a member of two groups + ### Removed * Dead `Rails.version < '6'` branches in `init.rb` and `user_patch.rb` From f602debb3956db638b145f18c50b347bd086fc9b Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 14:38:24 +0000 Subject: [PATCH 13/16] Use sprite_icon for the four icon links Redmine 6 renders icons as SVG sprites. The plain `icon icon-add` class still works through the legacy fallback (`.icon-add:not(:has(svg))` puts a PNG behind it), but the result sits next to the core's SVG icons and looks out of place. Wrap the labels in `sprite_icon`, keeping the existing css classes, the same way the core views do (compare app/views/calendars/show.html.erb for the `link_to_function` case). All three sprite names -- add, checked, warning -- exist in Redmine 6.1's icons.svg. --- app/views/settings/_workload_settings.erb | 2 +- app/views/wl_national_holiday/index.html.erb | 2 +- app/views/wl_user_vacations/index.html.erb | 2 +- app/views/workloads/_filters.erb | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/app/views/settings/_workload_settings.erb b/app/views/settings/_workload_settings.erb index 6b1d329..950c060 100644 --- a/app/views/settings/_workload_settings.erb +++ b/app/views/settings/_workload_settings.erb @@ -140,6 +140,6 @@ <%= "checked" if settings['workload_of_parent_issues'] != '' %> > <%= l(:info_include_parent_tasks) %> - <%= l(:warning_include_parent_tasks) %> + <%= sprite_icon('warning', l(:warning_include_parent_tasks)) %>

\ No newline at end of file diff --git a/app/views/wl_national_holiday/index.html.erb b/app/views/wl_national_holiday/index.html.erb index d98d61d..e6ef126 100644 --- a/app/views/wl_national_holiday/index.html.erb +++ b/app/views/wl_national_holiday/index.html.erb @@ -5,7 +5,7 @@

<%= l(:workload_holiday_title)%>

-<%= link_to l(:label_new), {controller: "wl_national_holiday", action: "new"}, class: "icon icon-add" if @is_allowed%> +<%= link_to sprite_icon('add', l(:label_new)), {controller: "wl_national_holiday", action: "new"}, class: "icon icon-add" if @is_allowed%>

<%= link_to "<<", :controller => 'wl_national_holiday', :action => "index", :year => @this_year-1 %> diff --git a/app/views/wl_user_vacations/index.html.erb b/app/views/wl_user_vacations/index.html.erb index e259f5c..d2d1533 100644 --- a/app/views/wl_user_vacations/index.html.erb +++ b/app/views/wl_user_vacations/index.html.erb @@ -4,7 +4,7 @@

<%= l(:workload_user_vacation_site_title) %> » <%= User.current.name %>

-<%= link_to l(:label_new), new_wl_user_vacation_path, :class => 'icon icon-add' if @is_allowed %> +<%= link_to sprite_icon('add', l(:label_new)), new_wl_user_vacation_path, :class => 'icon icon-add' if @is_allowed %> <% unless @wl_user_vacations.empty?%> <%= render(partial: "show_list", locals: {wl_user_vacations: @wl_user_vacations, is_allowed: @is_allowed}) %> diff --git a/app/views/workloads/_filters.erb b/app/views/workloads/_filters.erb index 4cd1e81..fba6033 100644 --- a/app/views/workloads/_filters.erb +++ b/app/views/workloads/_filters.erb @@ -38,6 +38,6 @@ <%= label_tag :workload_groups, l(:workload_show_filter_group) %> <%= select_tag :workload_groups, group_options_for_select(@groups&.allowed_to_display, @groups&.selected), :name => 'workload[groups][]', :multiple => true, :onchange => "this.form.workload_users.selectedIndex=-1;" %> - <%= link_to_function l(:button_apply), 'jQuery("#filter_form").submit()', :class => 'apply icon icon-checked' %> + <%= link_to_function sprite_icon('checked', l(:button_apply)), 'jQuery("#filter_form").submit()', :class => 'apply icon icon-checked' %> <% end %> From 3a0b0516c3597ec8fb7b556390995a08fab2bd69 Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 14:38:40 +0000 Subject: [PATCH 14/16] Rubocop: target Ruby 3.2 The config still targeted Ruby 2.7. Redmine 6.1 requires `ruby '>= 3.2.0', '< 3.5.0'`, so 3.2 is the lowest version this plugin can actually run on. Rubocop is not part of the CI workflow, so this only affects local runs. Raising the target may surface new offences; .rubocop_todo.yml was left untouched. --- .rubocop.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.rubocop.yml b/.rubocop.yml index 9e9a678..abafd7c 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -4,7 +4,7 @@ AllCops: NewCops: enable DisplayCopNames: true DisplayStyleGuide: true - TargetRubyVersion: 2.7 + TargetRubyVersion: 3.2 Exclude: - '**/vendor/**/*' From efa2c50d21c45641d1ae71f8a1383247a8ec0fda Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Wed, 26 Aug 2026 14:39:06 +0000 Subject: [PATCH 15/16] Load the plugin's assets only on the plugin's own pages RedmineToolbarHookListener injected slides.js and style.css into the layout head of *every* Redmine page, not just the workload views. Two consequences: * every page in the installation paid for two extra requests it has no use for * style.css contained an unscoped `legend { color: ... }` rule, so the plugin silently restyled the legend of every fieldset in Redmine -- including core pages and whatever the active theme intended Restrict the hook to the four controllers whose views need the assets, and scope the legend rule to `.controller-workloads`. `#year-nav` is an id used only by this plugin's holiday view and is left as is. The plugin settings page (`settings` controller) renders with core classes only -- box, tabular, info -- and does not need style.css. --- assets/stylesheets/style.css | 2 +- init.rb | 21 ++++++++++++++++++++- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/assets/stylesheets/style.css b/assets/stylesheets/style.css index fc8b40b..61504d8 100644 --- a/assets/stylesheets/style.css +++ b/assets/stylesheets/style.css @@ -36,7 +36,7 @@ display: inline-block; } -legend { +.controller-workloads legend { color: var(--anthracite); } diff --git a/init.rb b/init.rb index 31f8df1..6958936 100755 --- a/init.rb +++ b/init.rb @@ -46,8 +46,27 @@ end class RedmineToolbarHookListener < Redmine::Hook::ViewListener - def view_layouts_base_html_head(_context) + # Controllers whose views need the plugin's assets. + WORKLOAD_CONTROLLERS = %w[ + workloads + wl_user_datas + wl_user_vacations + wl_national_holiday + ].freeze + + def view_layouts_base_html_head(context = {}) + return '' unless workload_page?(context) + javascript_include_tag('slides', plugin: :redmine_workload) + stylesheet_link_tag('style', plugin: :redmine_workload) end + + private + + def workload_page?(context) + controller = context[:controller] + return false unless controller + + WORKLOAD_CONTROLLERS.include?(controller.params[:controller].to_s) + end end From 45d55746e196fb3479c2753c9f510f42b6addb7a Mon Sep 17 00:00:00 2001 From: Markus Boremski Date: Thu, 27 Aug 2026 06:28:28 +0000 Subject: [PATCH 16/16] CHANGELOG: complete the 4.0.0 section and set the release date The date still carried 2026-02-06 from when #42 was written; 4.0.0 was never tagged, so it now reads the actual release date. Three changes that landed after the entry was first written were missing: the sprite icons, the scoping of the plugin's assets to its own views, and the Rubocop target. The unscoped `legend` rule was a defect visible in every Redmine installation using this plugin, so it is listed under Fixed rather than buried in the asset scoping note. --- CHANGELOG.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c49541d..a7bccc4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## 4.0.0 - 2026-02-06 +## 4.0.0 - 2026-08-27 ### Changed @@ -17,6 +17,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 * Fixed Ruby version comparison for PostgreSQL requirement * Declared `requires_redmine version_or_higher: '6.1'` * CI now runs against Redmine 6.1-stable on Ruby 3.2 instead of 5.0-stable +* Icons are rendered with `sprite_icon` instead of the legacy icon font + classes, so they follow the active theme +* The plugin's javascript and stylesheet are no longer injected into every + Redmine page, only into the plugin's own views +* Rubocop targets Ruby 3.2, the lowest version Redmine 6.1 allows ### Fixed @@ -29,6 +34,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 environment is loaded, where `Rails.root` does not exist * `WlUserSelectionTest` accounts for Redmine 6's `fixtures :all`, which makes `users(:users_008)` a member of two groups +* An unscoped `legend` rule in the plugin's stylesheet restyled the legend of + every fieldset in the whole Redmine installation; it is now scoped to the + plugin's own views ### Removed