From 4ee382f72231d1d0867bd4608f2ff14480e83f7f Mon Sep 17 00:00:00 2001 From: Klaus Zanders Date: Mon, 23 Mar 2026 17:17:20 +0100 Subject: [PATCH] Show an error message, when no individual working days have been selected --- .../working_hours/days_and_hours_form.rb | 4 +++ app/models/user_working_hours.rb | 8 ++++++ config/locales/en.yml | 26 ++++++++++--------- .../users/working-hours-form.controller.ts | 4 +-- .../helpers/chronic-duration-helper.ts | 4 +-- 5 files changed, 30 insertions(+), 16 deletions(-) diff --git a/app/components/users/working_hours/days_and_hours_form.rb b/app/components/users/working_hours/days_and_hours_form.rb index e42ee2ef8e5..0b2bed8be6a 100644 --- a/app/components/users/working_hours/days_and_hours_form.rb +++ b/app/components/users/working_hours/days_and_hours_form.rb @@ -41,6 +41,10 @@ class Users::WorkingHours::DaysAndHoursForm < ApplicationForm I18n.t("users.working_hours.form.title_days_and_hours") end end + + if model.errors[:days].present? + render(Primer::Alpha::Banner.new(mb: 3, icon: :stop, scheme: :danger)) { model.errors[:days].join("\n") } + end end form.group(layout: :horizontal, mb: 2) do |group| diff --git a/app/models/user_working_hours.rb b/app/models/user_working_hours.rb index 046b7d05399..1820202e3eb 100644 --- a/app/models/user_working_hours.rb +++ b/app/models/user_working_hours.rb @@ -43,6 +43,8 @@ class UserWorkingHours < ApplicationRecord presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0, less_than_or_equal_to: 100 } + validate :at_least_one_working_day_selected + scope :for_user, ->(user) { where(user:) } scope :past, ->(date = Date.current) { where(valid_from: ..date).order(valid_from: :desc) } @@ -143,4 +145,10 @@ class UserWorkingHours < ApplicationRecord def abbr_day_name(day) I18n.t("date.abbr_day_names")[DAY_ABBR_INDEX[day]] end + + def at_least_one_working_day_selected + if DAYS.all? { |day| public_send(day).zero? } + errors.add(:days, :no_working_day) + end + end end diff --git a/config/locales/en.yml b/config/locales/en.yml index 8932ccc297b..d6932626b99 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -445,7 +445,6 @@ en: We have prepared [upgrade guides for all installation methods](upgrade_guide). You can perform the upgrade ahead of the next release at any time by following the guides. - authentication: login_and_registration: "Login and registration" @@ -1583,12 +1582,6 @@ en: dependencies: "Dependencies" activerecord: - errors: - models: - group: - attributes: - parent_id: - circular_dependency: "would create a circular group hierarchy." attributes: jira_import: projects: "Projects" @@ -1906,6 +1899,7 @@ en: sunday_hours: "Sunday hours" availability_factor: "Availability factor" shared_hours: "Work hours" + days: "Working days" version: effective_date: "Finish date" sharing: "Sharing" @@ -2033,6 +2027,10 @@ en: is not providing a "Secure Context". Either use HTTPS or a loopback address, such as localhost. wrong_length: "is the wrong length (should be %{count} characters)." models: + group: + attributes: + parent_id: + circular_dependency: "would create a circular group hierarchy." ldap_auth_source: attributes: tls_certificate_string: @@ -2353,6 +2351,10 @@ en: description: "'Password confirmation' should match the input in the 'New password' field." status: invalid_on_create: "is not a valid status for new users." + user_working_hours: + attributes: + days: + no_working_day: "At least one day needs to be configured as a working day." member: principal_blank: "Please choose at least one user or group." role_blank: "need to be assigned." @@ -5376,7 +5378,7 @@ en: activities: enable_internal_comments: "Enable internal comments" helper_text_html: > - Internal comments allow an internal team to communicate amongst themselves privately. + Internal comments allow an internal team to communicate amongst themselves privately. These are only visible to selected roles that have the necessary permissions and will not be visible publicly. [Click here to learn more](docs_url) @@ -5529,7 +5531,7 @@ en: text_plugin_assets_writable: "Plugin assets directory writable" text_powered_by: "Powered by %{link}" text_project_identifier_info: "Only lower case letters (a-z), numbers, dashes and underscores are allowed, must start with a lower case letter." - text_project_identifier_description: "The project identifier is prepended to all work package IDs. If the identifier is \"PROJ\" for example, the work package identifier will be \"PROJ-12\" or \"PROJ-246\"." + text_project_identifier_description: 'The project identifier is prepended to all work package IDs. If the identifier is "PROJ" for example, the work package identifier will be "PROJ-12" or "PROJ-246".' text_project_identifier_url_description: "The project identifier is included in the URL of the project." text_project_identifier_handle_format: "Must start with a letter and contain only uppercase letters, numbers, and underscores (max 10 characters)." text_project_identifier_format: "Must start with a lowercase letter. Only lowercase letters (a-z), numbers, dashes and underscores are allowed." @@ -5671,10 +5673,10 @@ en: The activation email has expired. We sent you a new one to %{email}. Please click the link inside of it to activate your account. warning_user_limit_reached: > - Adding additional users will exceed the current limit. + Adding additional users will exceed the current limit. Please contact an administrator to increase the user limit to ensure external users are able to access this instance. warning_user_limit_reached_admin_html: > - Adding additional users will exceed the current limit. + Adding additional users will exceed the current limit. Please [upgrade your plan](upgrade_url) to be able to ensure external users are able to access this instance. warning_user_limit_reached_instructions: > You reached your user limit (%{current}/%{max} active users). @@ -5777,7 +5779,7 @@ en: Adding additional users will exceed the current limit. Please contact an administrator to increase the user limit to ensure external users are able to access this %{entity}. warning_user_limit_reached_admin_html: > - Adding additional users will exceed the current limit. + Adding additional users will exceed the current limit. Please [upgrade your plan](upgrade_url) to be able to ensure external users are able to access this %{entity}. warning_no_selected_user: "Please select users to share this %{entity} with" warning_locked_user: "The user %{user} is locked and cannot be shared with" diff --git a/frontend/src/stimulus/controllers/dynamic/users/working-hours-form.controller.ts b/frontend/src/stimulus/controllers/dynamic/users/working-hours-form.controller.ts index d87bb006486..8e27d507359 100644 --- a/frontend/src/stimulus/controllers/dynamic/users/working-hours-form.controller.ts +++ b/frontend/src/stimulus/controllers/dynamic/users/working-hours-form.controller.ts @@ -160,11 +160,11 @@ export default class WorkingHoursFormController extends Controller { }); } - this.totalWorkHoursDisplayTarget.value = formattedHour(totalHours); + this.totalWorkHoursDisplayTarget.value = formattedHour(totalHours, false); const factor = parseFloat(this.availabilityFactorInputTarget.value); const available = totalHours * (isNaN(factor) ? 100 : factor) / 100; - this.totalAvailableHoursDisplayTarget.value = formattedHour(available); + this.totalAvailableHoursDisplayTarget.value = formattedHour(available, false); } private dayHoursInputForDay(day:string):HTMLInputElement|undefined { diff --git a/frontend/src/stimulus/helpers/chronic-duration-helper.ts b/frontend/src/stimulus/helpers/chronic-duration-helper.ts index 00a580a96b7..81b8587de5d 100644 --- a/frontend/src/stimulus/helpers/chronic-duration-helper.ts +++ b/frontend/src/stimulus/helpers/chronic-duration-helper.ts @@ -43,8 +43,8 @@ export function durationStringToSeconds(value:string):number { }) ?? 0; } -export function formattedHour(seconds:number):string { - if (isNaN(seconds) || seconds <= 0) { +export function formattedHour(seconds:number, blankOnNull = true):string { + if (blankOnNull && (isNaN(seconds) || seconds <= 0)) { return ''; }