Merge pull request #15283 from opf/merge-release/14.0-20240417033437

Merge release/14.0 into dev
This commit is contained in:
Jens Ulferts
2024-04-17 09:23:35 +02:00
committed by GitHub
88 changed files with 407 additions and 260 deletions
+5
View File
@@ -107,6 +107,11 @@ jobs:
- name: Prepare docker files
run: |
cp ./docker/prod/Dockerfile ./Dockerfile
# Add build information
echo "${{ steps.extract_version.outputs.checkout_ref }}" > PRODUCT_VERSION
echo "https://github.com/opf/openproject/commits/${{ steps.extract_version.outputs.checkout_ref }}" > PRODUCT_URL
date -u +"%Y-%m-%dT%H:%M:%SZ" > RELEASE_DATE
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
@@ -7,7 +7,7 @@
style: "min-height: 430px")) do |d| %>
<% d.with_header(variant: :large, mb: 3) %>
<%= render(Primer::Alpha::Dialog::Body.new) do %>
<%= render(Primer::Alpha::Dialog::Body.new(id: "op-draggable-autocomplete-container")) do %>
<%= primer_form_with(
url: projects_path,
id: COLUMN_FORM_ID,
@@ -123,8 +123,7 @@ class Queries::WorkPackages::Selects::PropertySelect < Queries::WorkPackages::Se
},
done_ratio: {
sortable: "#{WorkPackage.table_name}.done_ratio",
groupable: true,
if: ->(*) { !WorkPackage.done_ratio_disabled? }
groupable: true
},
created_at: {
sortable: "#{WorkPackage.table_name}.created_at",
+5 -4
View File
@@ -206,10 +206,6 @@ class WorkPackage < ApplicationRecord
include WorkPackage::Journalized
prepend Journable::Timestamps
def self.done_ratio_disabled?
Setting.work_package_done_ratio == "disabled"
end
def self.use_status_for_done_ratio?
Setting.work_package_done_ratio == "status"
end
@@ -310,6 +306,11 @@ class WorkPackage < ApplicationRecord
write_attribute :estimated_hours, !!converted_hours ? converted_hours : hours
end
def remaining_hours=(hours)
converted_hours = (hours.is_a?(String) ? hours.to_hours : hours)
write_attribute :remaining_hours, !!converted_hours ? converted_hours : hours
end
def duration_in_hours
duration ? duration * 24 : nil
end
@@ -116,17 +116,15 @@ class WorkPackages::UpdateAncestorsService
end
def derive_done_ratio(ancestor, loader)
return if WorkPackage.done_ratio_disabled?
ancestor.derived_done_ratio = compute_derived_done_ratio(ancestor, loader)
end
def compute_derived_done_ratio(work_package, loader)
def compute_derived_done_ratio(work_package, _loader)
return if work_package.derived_estimated_hours.nil? || work_package.derived_remaining_hours.nil?
leaves = loader.leaves_of(work_package)
if leaves.size.positive?
if work_package.derived_estimated_hours.zero?
nil
else
work_done = (work_package.derived_estimated_hours - work_package.derived_remaining_hours)
progress = (work_done.to_f / work_package.derived_estimated_hours) * 100
progress.round
@@ -153,22 +151,20 @@ class WorkPackages::UpdateAncestorsService
def derive_total_estimated_and_remaining_hours(work_package, loader)
descendants = loader.descendants_of(work_package)
work_package.derived_estimated_hours = not_zero(all_estimated_hours([work_package] + descendants).sum.to_f)
work_package.derived_remaining_hours = not_zero(all_remaining_hours([work_package] + descendants).sum.to_f)
work_package.derived_estimated_hours = total(all_estimated_hours([work_package] + descendants))
work_package.derived_remaining_hours = total(all_remaining_hours([work_package] + descendants))
end
def not_zero(value)
value unless value.zero?
def total(hours)
hours.empty? ? nil : hours.sum.to_f
end
def all_estimated_hours(work_packages)
work_packages
.map(&:estimated_hours)
.reject { |hours| hours.to_f.zero? }
work_packages.filter_map(&:estimated_hours)
end
def all_remaining_hours(work_packages)
work_packages.map(&:remaining_hours).reject { |hours| hours.to_f.zero? }
work_packages.filter_map(&:remaining_hours)
end
def modified_attributes_justify_derivation?(attributes)
@@ -40,10 +40,7 @@ See COPYRIGHT and LICENSE files for more details.
<li><%= WorkPackage.human_attribute_name(:start_date) %>: <%= work_package.start_date %></li>
<li><%= WorkPackage.human_attribute_name(:due_date) %>: <%= work_package.due_date %></li>
<li><%= WorkPackage.human_attribute_name(:estimated_hours)%>: <%= work_package.estimated_hours %></li>
<% if Setting.work_package_done_ratio != 'disabled' %>
<li><%= WorkPackage.human_attribute_name(:done_ratio) %>: <%= work_package.done_ratio %></li>
<% end %>
<li><%= WorkPackage.human_attribute_name(:done_ratio) %>: <%= work_package.done_ratio %></li>
<% work_package.custom_field_values.each do |value| %>
<li><%= value.custom_field.name %>: <%= show_value(value) %></li>
@@ -40,9 +40,7 @@ See COPYRIGHT and LICENSE files for more details.
<%= WorkPackage.human_attribute_name(:start_date) %>: <%= work_package.start_date %>
<%= WorkPackage.human_attribute_name(:due_date) %>: <%= work_package.due_date %>
<%= WorkPackage.human_attribute_name(:estimated_hours)%>: <%= work_package.estimated_hours %>
<% if Setting.work_package_done_ratio != 'disabled' %>
<%= WorkPackage.human_attribute_name(:done_ratio) %>: <%= work_package.done_ratio %>
<% end %>
<%= WorkPackage.human_attribute_name(:done_ratio) %>: <%= work_package.done_ratio %>
<% work_package.custom_field_values.each do |value| %>
<%= value.custom_field.name %>: <%= show_value(value) %>
<% end %>
@@ -53,6 +53,8 @@ class WorkPackages::UpdateProgressJob < ApplicationJob
update_totals
unset_total_p_complete
copy_progress_values_to_work_packages_and_update_journals
end
end
@@ -211,6 +213,33 @@ class WorkPackages::UpdateProgressJob < ApplicationJob
SQL
end
# The value for derived_done_ratio had been calculated wrong in the past. So prior to executing the job
# values in the work_packages and work_package_journals table sometimes contained wrong data.
# The whole job/migration is now treating the derived_done_ratio as a value newly introduced even if it, under
# the hood has existed before. But it was not shown in the activites before so the user would not have seen it.
#
# Because of this, all values, in the work_packages and work_package_journals table, for derived_done_ratio are
# reset to null.
#
# This results in two cases:
# * The value before has been something (most of the time 0) and is now null. This will hopefully be the
# majority of the cases as it would save a lot of journal creation, the slowest part of the job.
# For that case, the derived_done_ratio will be treated as not having changed by the job since with the rewrite
# the value looks to have been null before and is now null again.
# * The value before has been something and is now something. It could have been the same value as before. But
# since the job resets the value to null, it will in every case be treated as having changed (set for the first time)
def unset_total_p_complete
execute(<<~SQL)
UPDATE work_packages
SET derived_done_ratio = NULL
SQL
execute(<<~SQL)
UPDATE work_package_journals
SET derived_done_ratio = NULL
SQL
end
def copy_progress_values_to_work_packages_and_update_journals
updated_work_package_ids = copy_progress_values_to_work_packages
create_journals_for_updated_work_packages(updated_work_package_ids)
-2
View File
@@ -3411,9 +3411,7 @@ af:
unsupported_context: "Die bron gegee word nie as konteks ondersteun nie."
context_object_not_found: "Kan nie die hulpbron gegee as die konteks vind nie."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Die gekose gebruiker is nie toegelaat om '%{property}' vir hierdie werkspakket te wees nie."
start_date: "Begindatum kan nie gestel word op ouerwerkspakkette nie."
eprops:
-2
View File
@@ -3553,9 +3553,7 @@ ar:
unsupported_context: "غير معتمد المورد نظراً للسياق."
context_object_not_found: "تعذر العثور على المورد نظراً للسياق."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "غير مسموح للمستخدم الذي تم اختياره أن يكون '%{property}' لمجموعة العمل هذه."
start_date: "الوقت لإتمام المشروع لا يمكن تعيينه في حزم العمل الحالية."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ az:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3483,9 +3483,7 @@ be:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ bg:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3400,9 +3400,7 @@ ca:
unsupported_context: "El recurs proporcionat no s'admet com a context."
context_object_not_found: "No puc trobar el recurs proporionat com al context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "La data de finalització no es pot establir als paquets de treball pare."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "L'usuari escollit no pot ser \"%{property}\" per a aquest paquet de treball."
start_date: "La data d'inici no es pot definir per paquets de treball del pare."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ ckb-IR:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3481,9 +3481,7 @@ cs:
unsupported_context: "Zadaný dokument není podporován jako kontext."
context_object_not_found: "Zdroj nelze najít jako kontext."
validation:
done_ratio: "% Průběh nelze nastavit na nadřazených pracovních balíčcích, je odvozen ze stavu podřazených nebo pokud je zakázán."
due_date: "Datum ukončení nemůže být nastaveno na nadřazených pracovních balíčcích."
estimated_hours: "Práci nelze nastavit na nadřazených pracovních balíčcích." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Zvolený uživatel nesmí být '%{property}' pro tento pracovní balíček."
start_date: "Počáteční datum nelze nastavit na nadřazených pracovních balíčcích."
eprops:
-2
View File
@@ -3407,9 +3407,7 @@ da:
unsupported_context: "Den givne ressource understøttes ikke som korrekt sammenhæng."
context_object_not_found: "Kan ikke finde ressourcen, der ar angivet som sammenhæng."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Den valgte bruger er ikke tilladt at være '%{property}' for denne arbejdspakke."
start_date: "Startdato kan ikke angives for overordnede arbejdspakker."
eprops:
-2
View File
@@ -3405,9 +3405,7 @@ de:
unsupported_context: "Die übergebene Ressource wird nicht als Kontext unterstützt."
context_object_not_found: "Die als Kontext übergebene Ressource konnte nicht gefunden werden."
validation:
done_ratio: "Der Fortschritt kann nicht gesetzt werden falls es sich um ein Eltern-Arbeitspaket handelt, er durch den Status definiert wird oder wenn er komplett deaktiviert wurde."
due_date: "Der Endtermin kann für Eltern-Arbeitspakete nicht gesetzt werden."
estimated_hours: "Aufwand kann nicht für übergeordnete Arbeitspakete gesetzt werden." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Der gewählte Nutzer darf dem Arbeitspaket nicht als '%{property}' zugewiesen werden."
start_date: "Das Startdatum kann für Eltern-Arbeitspakete nicht gesetzt werden."
eprops:
-2
View File
@@ -3405,9 +3405,7 @@ el:
unsupported_context: "Ο πόρος που δόθηκε δεν υποστηρίζεται ως πλαίσιο αναφοράς."
context_object_not_found: "Δεν ήταν δυνατή η εύρεση του πόρου που δόθηκε ως πλαίσιο αναφοράς."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Η ημερομηνία λήξης δεν μπορεί να οριστεί σε πακέτα εργασίας-γονείς."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Ο επιλεγμένος χρήστης δεν επιτρέπεται να είναι '%{property}' για αυτό το πακέτο εργασίας."
start_date: "Η ημερομηνία έναρξης δεν μπορεί να οριστεί σε πακέτα εργασίας-γονείς."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ eo:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3406,9 +3406,7 @@ es:
unsupported_context: "El recurso dado no es soportado como contexto."
context_object_not_found: "No se ha podido encontrar el recurso dado como el contexto."
validation:
done_ratio: "% Completado no puede establecerse en paquetes de trabajo padres, cuando es influenciado por estado o cuando está desactivado."
due_date: "La fecha de finalización no se puede establecer en los paquetes de trabajo principales."
estimated_hours: "El trabajo no puede establecerse en paquetes de trabajo padres." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "El usuario elegido no tiene permiso para ser '%{property}' para este paquete de trabajo."
start_date: "La fecha de inicio no puede ser establecida en paquetes de trabajo padres."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ et:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ eu:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ fa:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ fi:
unsupported_context: "Resurssi koska ei ole tuettu yhteydessä."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Päättymispäivää ei voida asettaa ylätason tehtäville."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Aloituspäivää ei voi asettaa ylätehtäville."
eprops:
-2
View File
@@ -3409,9 +3409,7 @@ fil:
unsupported_context: "Ang ibinigay na mapagkukunan ay hindi suportado bilang isang konteksto."
context_object_not_found: "Hindi mahanap ang ibinigay na mapagkukunan bilang konteksto."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Ang piniling gumagamit ay hindi pinahihintulan sa '%{property}' na para sa package ng gawain ng magulang."
start_date: "Sinimulang petsa ay hindi mai-set sa mga pakete ng gawain ng magulang."
eprops:
-2
View File
@@ -3410,9 +3410,7 @@ fr:
unsupported_context: "La ressource donnée n'est pas prise en charge comme contexte."
context_object_not_found: "Impossible de trouver la ressource donnée comme contexte."
validation:
done_ratio: "Le % réalisé ne peut pas être défini sur les lots de travaux parents, lorsqu'il est déduit par le statut ou lorsqu'il est désactivé."
due_date: "La date de fin ne peut pas être définie dans les lots de travaux parents."
estimated_hours: "La valeur \"travail\" ne peut pas être définie pour les paquets de travail parents." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Lutilisateur choisi n'est pas autorisé à être « %{property} » pour ce lot de travaux."
start_date: "La date de début ne peut pas être définie dans les lots de travaux parents."
eprops:
-2
View File
@@ -3483,9 +3483,7 @@ he:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "לא ניתן לבחור '%{property}' עבור המשתמש בחבילת עבודה זו."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3409,9 +3409,7 @@ hi:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3447,9 +3447,7 @@ hr:
unsupported_context: "Dani resurs nije podržan u obliku konteksta."
context_object_not_found: "Ne mogu pronaći resurs zadan kao kontekst."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Izabranom korisniku nije dopušteno da bude '%{property}' za ovaj radni paket."
start_date: "Datum početka ne može biti postavljen na nadređenim radnim paketima."
eprops:
-2
View File
@@ -3407,9 +3407,7 @@ hu:
unsupported_context: "A megadott erőforrás nem támogatott kontextus."
context_object_not_found: "Nem található a kontextusként megadott erőforrás."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Befejezési dátumot nem lehet beállítani a szülő feladatcsoportnak."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "A kiválasztott felhasználó '%{property}'-ként való beállítása nem engedélyezett ehhez a feladatcsoporthoz."
start_date: "Kezdés dátuma nem állítható a szülő feladatcsoportokon."
eprops:
-2
View File
@@ -3364,9 +3364,7 @@ id:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Tanggal selesai tidak dapat diatur pada paket pekerjaan induk."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Pilihan pengguna tidak diperbolehkan untuk menjadi '%{property}' untuk paket pekerjaan ini."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3408,9 +3408,7 @@ it:
unsupported_context: "La risorsa non è supportata come contesto."
context_object_not_found: "Impossibile trovare la risorsa indicata come contesto."
validation:
done_ratio: "La % completamento non può essere impostata sulla macro-attività principale, quando viene dedotta dallo stato o quando è disabilitata."
due_date: "La data di fine non può essere impostata sulla macro-attività principale."
estimated_hours: "Il lavoro non può essere impostato sulla macro-attività principale." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "All'utente scelto non è consentito di essere '%{property}' per questa macro-attività."
start_date: "La data di inizio non può essere impostata sulla macro-attività principale."
eprops:
-2
View File
@@ -3370,9 +3370,7 @@ ja:
unsupported_context: "指定されたリソースは、コンテキストとしてはサポートされません。"
context_object_not_found: "コンテキストで指定されたリソースが見つかりません。"
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "終了日は親作業項目には設定できません。"
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "選択されたユーザーは、この作業項目の'%{property}' にすることはできません。"
start_date: "開始日は、親ワークパッケージに設定できません。"
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ ka:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ kk:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3371,9 +3371,7 @@ ko:
unsupported_context: "지정된 리소스는 컨텍스트로 지원되지 않습니다."
context_object_not_found: "컨텍스트로 지정된 리소스를 찾을 수 없습니다."
validation:
done_ratio: "완료 %는 상태에 의해 유추되는 경우 또는 비활성화된 경우 부모 작업 패키지에서 설정할 수 없습니다."
due_date: "완료 날짜는 부모 작업 패키지에서 설정할 수 없습니다."
estimated_hours: "작업은 부모 작업 패키지에서 설정할 수 없습니다." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "선택한 사용자는 이 작업 패키지에 대해 '%{property}' 허가되지 않았습니다."
start_date: "시작 날짜는 부모 작업 패키지에서 설정할 수 없습니다."
eprops:
-2
View File
@@ -3475,9 +3475,7 @@ lt:
unsupported_context: "Duotas resursas nėra palaikomas kaip kontekstas."
context_object_not_found: "Nepavyko rasti resurso, duoto kaip kontekstas."
validation:
done_ratio: "% baigta negali būti nurodytas tėviniams darbų paketams, kai paketas apibrėžtas pagal būseną arba kai jis deaktyvuotas."
due_date: "Tėviniams darbo paketams negalima nurodyti pabaigos datos."
estimated_hours: "Darbo negalima nustatyti tėviniams darbo paketams." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Pasirinktas vartotojas negali būti '%{property}' šiam darbų paketui."
start_date: "Pradžios data negali būti nustatyta tėviniams darbų paketams."
eprops:
-2
View File
@@ -3447,9 +3447,7 @@ lv:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ mn:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3374,9 +3374,7 @@ ms:
unsupported_context: "Sumber yang diberi tidak disokong sebagai konteks."
context_object_not_found: "Tidak dapat mencari sumber yang diberikan sebagai konteks."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Tarikh tamat tidak boleh ditetapkan pada pakej kerja induk."
estimated_hours: "Kerja tidak boleh ditetapkan pada pakej kerja induk." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Pengguna yang dipilih tidak dibenarkan untuk menjadi '%{property}' untuk pakej kerja ini."
start_date: "Tarikh mula tidak boleh ditetapkan pada pakej kerja induk."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ ne:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3406,9 +3406,7 @@ nl:
unsupported_context: "De gegeven bron wordt niet ondersteund als context."
context_object_not_found: "Kan de bron niet vind als gegeven context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Einddatum kan niet worden ingesteld op bovenliggende werkpakketten."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "De gekozen gebruiker kan geen '%{property}' zijn voor dit werkpakket."
start_date: "De startdatum kan niet worden ingesteld op bovenliggende werkpakketten."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@
unsupported_context: "Ressursen som er gitt støttes ikke som kontekst."
context_object_not_found: "Kan ikke finne ressursen som er angitt som kontekst."
validation:
done_ratio: "% ferdig kan ikke angis på overordnede arbeidspakker, de har feil status eller er avslått."
due_date: "Sluttdato kan ikke settes på overordnede arbeidspakker."
estimated_hours: "Arbeidet kan ikke angis med overordnede arbeidspakker." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Valgt bruker har ikke de nødvendige rettighetene til å være '%{property}' for denne arbeidspakken."
start_date: "Startdato kan ikke angis på overordnede arbeidspakker."
eprops:
-2
View File
@@ -3477,9 +3477,7 @@ pl:
unsupported_context: "Podany zasób nie jest obsługiwany jako kontekst."
context_object_not_found: "Nie można odnaleźć zasobu z podanym kontekstem."
validation:
done_ratio: "% ukończenia nie może być ustawiony na nadrzędnych pakietach roboczych, jeśli został wyprowadzony ze statusu lub wyłączony."
due_date: "Nie można ustawić daty zakończenia w nadrzędnych pakietach roboczych."
estimated_hours: "Pracy nie można ustawić na nadrzędnych pakietach roboczych." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Wybrany użytkownik nie może być „%{property}” dla tego pakietu roboczego."
start_date: "Daty rozpoczęcia nie można ustawić na nadrzędnych pakietach roboczych."
eprops:
-2
View File
@@ -3407,9 +3407,7 @@ pt-BR:
unsupported_context: "O recurso dado não está suportado como contexto."
context_object_not_found: "Não é possível encontrar o recurso dado como contexto."
validation:
done_ratio: "A % de conclusão não pode ser definida em pacotes de trabalho pais quando é inferida pelo estado ou quando está desabilitada."
due_date: "Data de conclusão não pode ser definida em pacote de trabalho pai."
estimated_hours: "O trabalho não pode ser definido em pacotes de trabalho pais." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "O usuário selecionado não tem permissão de '%{property}' neste pacote de trabalho."
start_date: "Data de início não pode ser definida no pacote de trabalho pai."
eprops:
-2
View File
@@ -3406,9 +3406,7 @@ pt-PT:
unsupported_context: "Não há suporte para o recurso dado como contexto."
context_object_not_found: "Não é possível encontrar o recurso dado como contexto."
validation:
done_ratio: "A % de conclusão não pode ser definida em pacotes de trabalho parentes quando é inferida pelo estado ou quando está desativada."
due_date: "Data de término não pode ser definida em pacotes de trabalho pai."
estimated_hours: "O trabalho não pode ser definido em tarefas principais." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "O utilizador escolhido não pode ser '%{property}' para esta tarefa."
start_date: "Data de início não pode ser definida em tarefas do pai."
eprops:
-2
View File
@@ -3446,9 +3446,7 @@ ro:
unsupported_context: "Resursa furnizată nu este suportată ca și context."
context_object_not_found: "Resursa furnizată ca și contet nu poate fi identificată."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Data de finalizare nu poate fi stabilită pentru pachetele de lucru părinte."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Utilizatorul selectat nu poate fi '%{property}' pentru acest pachet de lucru."
start_date: "Nu se poate seta data start pe pachetele de lucru părinte."
eprops:
-2
View File
@@ -3478,9 +3478,7 @@ ru:
unsupported_context: "Ресурс не поддерживается как контекст."
context_object_not_found: "Не удается найти ресурс заданный как контекст."
validation:
done_ratio: "% законченный не может быть установлен в родительских пакетах работ, когда он устанавливается по статусу или когда он отключен."
due_date: "Дату окончания нельзя задать на родительских пакетах работ."
estimated_hours: "Предполагаемое количество часов не может быть задано для родительских пакетов." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Выбранный пользователь не может быть «%{property}» для этого пакета работ."
start_date: "Дата начала не может быть задана на родительских пакетах работ."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ rw:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ si:
unsupported_context: "ලබා දී ඇති සම්පත සන්දර්භය ලෙස සහාය නොදක්වයි."
context_object_not_found: "සන්දර්භය ලෙස ලබා දී ඇති සම්පත සොයාගත නොහැක."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "අවසන් දිනය මව් වැඩ පැකේජ මත සැකසිය නොහැක."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "තෝරාගත් පරිශීලකයාට මෙම වැඩ පැකේජය සඳහා '%{property}' වීමට අවසර නැත."
start_date: "ආරම්භක දිනය මව් වැඩ පැකේජ මත සැකසිය නොහැක."
eprops:
-2
View File
@@ -3482,9 +3482,7 @@ sk:
unsupported_context: "Zadaný prostriedok nie je podporovaný ako kontext."
context_object_not_found: "Pre vložené vstupné podmienky neboli nájdené žiadne prostriedky."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Dátum ukončenia nie je možné nastaviť na rodičovské pracovné balíčky."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Zvolený používateľ nemôže byť \"%{property}\" v prípade tohto pracovného balíčka."
start_date: "Dátum \"Od\" nie je možné nastaviť na pracovnom balíčku obsahujúcom podriadené pracovné balíčky."
eprops:
-2
View File
@@ -3479,9 +3479,7 @@ sl:
unsupported_context: "Navedeni vir ni podprt kot kontekst."
context_object_not_found: "Ni mogoče najti vira kot konteksta."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Končnega datuma ni mogoče določiti za nadrejene delovne pakete."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Izbrani uporabnik ne sme biti '%{property}' za ta delovni paket."
start_date: "Na nadrejenih delovnih paketih začetnega datuma ni mogoče nastaviti."
eprops:
-2
View File
@@ -3447,9 +3447,7 @@ sr:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3407,9 +3407,7 @@ sv:
unsupported_context: "Resursen som angavs stöds inte som kontext."
context_object_not_found: "Kan inte hitta den angivna resursen som kontext."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Slutdatum kan inte anges på överordnade arbetspaket."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Den valda användaren tillåts inte att vara \"%{property}\" för detta arbetspaket."
start_date: "Startdatum kan inte anges för överordnade arbetspaket."
eprops:
-2
View File
@@ -3375,9 +3375,7 @@ th:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3406,9 +3406,7 @@ tr:
unsupported_context: "Verilen kaynak bağlam olarak desteklenmiyor."
context_object_not_found: "Bağlam olarak verilen kaynağı bulamıyor."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Bitiş tarihi, üst çalışma paketlerinde ayarlanamaz."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Seçilen kullanıcının bu çalışma paketi için ' %{property} ' olması için izin verilmiyor."
start_date: "Başlangıç tarihi, üst çalışma paketlerinde ayarlanamaz."
eprops:
-2
View File
@@ -3474,9 +3474,7 @@ uk:
unsupported_context: "Даний ресурс не підтримується як контекст."
context_object_not_found: "Не можу знайти ресурс з урахуванням контексту."
validation:
done_ratio: "Значення «% завершення» не можна встановити для батьківських пакетів робіт, коли воно успадковується за статусом або коли його вимкнено."
due_date: "Дата закінчення не може бути встановлена на початкових робочих пакетах."
estimated_hours: "Значення «Робота» не можна встановити для батьківських пакетів робіт." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "Вибраному користувачеві не дозволяється %{property} для цього робочого пакету."
start_date: "Дата початку не може бути встановлена на базових робочих пакетах."
eprops:
-2
View File
@@ -3411,9 +3411,7 @@ uz:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3376,9 +3376,7 @@ vi:
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
-2
View File
@@ -3364,9 +3364,7 @@ zh-CN:
unsupported_context: "所提供的资源不被上下文环境所支持。"
context_object_not_found: "找不到可作为上下文环境的资源。"
validation:
done_ratio: "无法在父级工作包上设置 % 已完成,当其由状态推导或被禁用时。"
due_date: "不能在父工作包中设置完成日期。"
estimated_hours: "不能在父工作包中设置工作。" #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "所选的用户不允许为此工作包的 '%{property}'。"
start_date: "不能在父工作包中设置开始日期。"
eprops:
-2
View File
@@ -3373,9 +3373,7 @@ zh-TW:
unsupported_context: "所提供的資源不受相對應支援。"
context_object_not_found: "Cannot find the resource given with the context.\n無法找到本文對應的資源。"
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "無法在主工作項目上設置結束日期。"
estimated_hours: "Work cannot be set on parent work packages." #feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "所指定的使用者不允許成為工作項目的 '%{property}' 。"
start_date: "無法在主工作項目設置開始日期。"
eprops:
-2
View File
@@ -3668,9 +3668,7 @@ Project attributes and sections are defined in the <a href=%{admin_settings_url}
unsupported_context: "The resource given is not supported as context."
context_object_not_found: "Cannot find the resource given as the context."
validation:
done_ratio: "% Complete cannot be set on parent work packages, when it is inferred by status or when it is disabled."
due_date: "Finish date cannot be set on parent work packages."
estimated_hours: "Work cannot be set on parent work packages." # feel like this one should be removed eventually
invalid_user_assigned_to_work_package: "The chosen user is not allowed to be '%{property}' for this work package."
start_date: "Start date cannot be set on parent work packages."
eprops:
@@ -13,7 +13,6 @@
bindLabel="name"
[multiple]="false"
[virtualScroll]="true"
appendTo="body"
[placeholder]="inputPlaceholder"
[clearSearchOnAdd]="true"
[closeOnSelect]="true"
@@ -2,19 +2,22 @@ import {
AfterViewInit,
ChangeDetectionStrategy,
Component,
ElementRef,
EventEmitter,
Input,
OnInit,
Output,
ViewChild,
ElementRef } from '@angular/core';
} from '@angular/core';
import { I18nService } from 'core-app/core/i18n/i18n.service';
import { NgSelectComponent } from '@ng-select/ng-select';
import { DragulaService, Group } from 'ng2-dragula';
import { DomAutoscrollService } from 'core-app/shared/helpers/drag-and-drop/dom-autoscroll.service';
import { UntilDestroyedMixin } from 'core-app/shared/helpers/angular/until-destroyed.mixin';
import { setBodyCursor } from 'core-app/shared/helpers/dom/set-window-cursor.helper';
import { repositionDropdownBugfix } from 'core-app/shared/components/autocompleter/op-autocompleter/autocompleter.helper';
import {
repositionDropdownBugfix,
} from 'core-app/shared/components/autocompleter/op-autocompleter/autocompleter.helper';
import { QueryFilterResource } from 'core-app/features/hal/resources/query-filter-resource';
import { AlternativeSearchService } from 'core-app/shared/components/work-packages/alternative-search.service';
import { populateInputsFromDataset } from 'core-app/shared/components/dataset-inputs';
@@ -92,7 +95,10 @@ export class DraggableAutocompleteComponent extends UntilDestroyedMixin implemen
this.updateAvailableOptions();
// Setup groups
this.columnsGroup = this.dragula.createGroup('columns', {});
this.columnsGroup = this.dragula.createGroup(
'columns',
{ mirrorContainer: this.appendToComponent ? document.getElementById('op-draggable-autocomplete-container')! : document.body },
);
// Set cursor when dragging
this.dragula.drag('columns')
@@ -64,6 +64,8 @@ export class CkeditorAugmentedTextareaComponent extends UntilDestroyedMixin impl
@Input() public macros:ICKEditorMacroType;
@Input() public removePlugins:string[] = [];
@Input() public resource?:object;
@Input() public turboMode = false;
@@ -130,6 +132,7 @@ export class CkeditorAugmentedTextareaComponent extends UntilDestroyedMixin impl
type: this.editorType,
resource: this.halResource,
previewContext: this.previewContext,
removePlugins: this.removePlugins,
};
if (this.readOnly) {
this.context.macros = 'none';
@@ -31,6 +31,7 @@ export class CKEditorSetupService {
public initialize() {
this.prefetch = this.load();
this.watchTopLayer();
}
/**
@@ -45,7 +46,8 @@ export class CKEditorSetupService {
* @returns {Promise<ICKEditorWatchdog>}
*/
public async create(
wrapper:HTMLElement, context:ICKEditorContext,
wrapper:HTMLElement,
context:ICKEditorContext,
initialData:string|null = null,
):Promise<ICKEditorWatchdog> {
// Load the bundle and the matching locale, if found.
@@ -62,6 +64,7 @@ export class CKEditorSetupService {
const config = {
openProject: this.createConfig(context),
removePlugins: context.removePlugins,
initialData,
language: {
ui: uiLocale,
@@ -144,4 +147,31 @@ export class CKEditorSetupService {
pluginContext: window.OpenProject.pluginContext.value,
};
}
private watchTopLayer() {
const targetClassNames = ['ck-body-wrapper', 'ck-inspector-'];
const observer = new MutationObserver((mutations) => {
const dialog = document.querySelector('dialog[open]');
if (!dialog) {
return;
}
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (!(node instanceof HTMLElement)) {
return;
}
if (targetClassNames.some((className) => node.classList.contains(className))) {
dialog.append(node);
}
});
});
});
observer.observe(document.body, {
childList: true,
});
}
}
@@ -71,7 +71,7 @@ export class OPContextMenuService {
if (that.active && !that.portalHostElement.contains(evt.target as Element)) {
that.close();
}
}, true);
});
// Listen if it scrolles then close the active context menu
wrapper.addEventListener('scroll', (evt:Event) => {
if (that.active && !that.portalHostElement.contains(evt.target as Element)) {
@@ -188,13 +188,11 @@ module API
schema :percentage_done,
type: "Integer",
name_source: :done_ratio,
show_if: ->(*) { Setting.work_package_done_ratio != "disabled" },
required: false
schema :derived_percentage_done,
type: "Integer",
name_source: :derived_done_ratio,
show_if: ->(*) { Setting.work_package_done_ratio != "disabled" },
required: false
schema :readonly,
@@ -444,13 +444,11 @@ module API
property :done_ratio,
as: :percentageDone,
render_nil: true,
if: ->(*) { Setting.work_package_done_ratio != "disabled" }
render_nil: true
property :derived_done_ratio,
as: :derivedPercentageDone,
render_nil: true,
if: ->(*) { Setting.work_package_done_ratio != "disabled" }
render_nil: true
date_time_property :created_at
@@ -31,6 +31,8 @@ module OpenProject::TextFormatting
class LinkAttributeFilter < HTML::Pipeline::Filter
def call
links.each do |node|
next if node["target"] || node["href"]&.start_with?("#")
node["target"] = context.fetch(:target, "_top")
end
@@ -38,7 +40,7 @@ module OpenProject::TextFormatting
end
def links
doc.css('a[href^="/"]')
doc.css("a")
end
end
end
@@ -6,7 +6,8 @@
inputs: @rich_text_options.reverse_merge(
{
textareaSelector: "##{builder.field_id(@input.name)}",
macros: 'resource',
removePlugins: ["CodeBlock"],
macros: false,
turboMode: true
}
)
@@ -53,6 +53,8 @@ module API
end
},
getter: ->(*) {
next unless embed_links
active_projects.map do |project|
Projects::ProjectRepresenter.create(project, current_user:)
end
@@ -141,8 +141,6 @@ RSpec.describe "Project details widget on dashboard", :js do
it 'has a "Project activity" entry in More menu linking to the project activity page' do
details_widget = Components::Grids::GridArea.new(".grid--area.-widgeted:nth-of-type(1)")
details_widget.expect_menu_item("Project details activity")
details_widget.click_menu_item("Project details activity")
expect(page).to have_current_path(project_activity_index_path(project), ignore_query: true)
expect(page).to have_checked_field(id: "event_types_project_attributes")
@@ -0,0 +1,71 @@
#-- copyright
# OpenProject is an open source project management software.
# Copyright (C) 2012-2024 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"
require_relative "../../support/pages/meetings/new"
require_relative "../../support/pages/structured_meeting/show"
RSpec.describe "Structured meetings links caught by turbo",
:js,
:with_cuprite do
include Rails.application.routes.url_helpers
shared_let(:project) { create(:project, enabled_module_names: %w[meetings]) }
shared_let(:user) do
create(:user,
lastname: "First",
member_with_permissions: { project => %i[view_meetings create_meetings edit_meetings delete_meetings manage_agendas
view_work_packages] }).tap do |u|
u.pref[:time_zone] = "utc"
u.save!
end
end
shared_let(:meeting1) { create(:structured_meeting, title: "First meeting", project:) }
shared_let(:meeting2) { create(:structured_meeting, title: "Other meeting", project:) }
let(:notes) do
<<~NOTES
[Meeting link](#{meeting_url(meeting2)})
NOTES
end
let!(:agenda_item) { create(:meeting_agenda_item, meeting: meeting1, notes:) }
let(:show_page) { Pages::StructuredMeeting::Show.new(meeting1) }
before do
login_as user
show_page.visit!
end
it "can link to the other meeting" do
click_link_or_button "Meeting link"
expect(page).to have_current_path meeting_path(meeting2)
expect(page).to have_css("#content", text: "Other meeting", visible: :visible)
end
end
@@ -725,13 +725,6 @@ RSpec.describe WorkPackages::BaseContract do
with_settings: { work_package_done_ratio: "status" } do
it_behaves_like "invalid if changed", :done_ratio
end
context "when % Complete disabled",
with_settings: { work_package_done_ratio: "disabled" } do
let(:changed_values) { [:done_ratio] }
it_behaves_like "invalid if changed", :done_ratio
end
end
describe "version" do
@@ -674,16 +674,6 @@ RSpec.describe API::V3::WorkPackages::Schema::WorkPackageSchemaRepresenter do
let(:required) { false }
let(:writable) { false }
end
context "as disabled" do
before do
allow(Setting).to receive(:work_package_done_ratio).and_return("disabled")
end
it "is hidden" do
expect(subject).not_to have_json_path("percentageDone")
end
end
end
describe "derivedPercentageDone" do
@@ -694,16 +684,6 @@ RSpec.describe API::V3::WorkPackages::Schema::WorkPackageSchemaRepresenter do
let(:required) { false }
let(:writable) { false }
end
context "as disabled" do
before do
allow(Setting).to receive(:work_package_done_ratio).and_return("disabled")
end
it "is hidden" do
expect(subject).not_to have_json_path("derivedPercentageDone")
end
end
end
describe "readonly" do
@@ -401,16 +401,6 @@ RSpec.describe API::V3::WorkPackages::WorkPackageRepresenter do
context "when setting enabled" do
it { expect(parse_json(subject)["percentageDone"]).to eq(50) }
end
context "when setting disabled" do
before do
allow(Setting)
.to receive(:work_package_done_ratio)
.and_return("disabled")
end
it { is_expected.not_to have_json_path("percentageDone") }
end
end
end
@@ -285,7 +285,7 @@ RSpec.describe OpenProject::TextFormatting,
<input type="checkbox" disabled="disabled">
<span class="op-uc-list__label__description">asdfasdfasdf </span>
</label>
<a class="op-uc-link" href="https://example.com/">
<a class="op-uc-link" target="_top" href="https://example.com/">
<label class="op-uc-list__label">
<span class="op-uc-list__label__description">foobar</span>
</label>
@@ -316,7 +316,7 @@ RSpec.describe OpenProject::TextFormatting,
<li class="op-uc-list--item">
<input type="checkbox" class="op-uc-list--task-checkbox" disabled>
<span>asdfasdfasdf </span>
<a class="op-uc-link" href="https://example.com/" rel="noopener noreferrer">
<a class="op-uc-link" href="https://example.com/" target="_top" rel="noopener noreferrer">
<span>foobar</span>
</a>
</li>
@@ -313,7 +313,7 @@ RSpec.describe OpenProject::TextFormatting,
let(:expected) do
<<~EXPECTED
<p class="op-uc-p">
Link to <a class="user-mention op-uc-link" href="http://openproject.org/users/#{user.id}" title="User Foo Barrit">Foo Barrit</a>
Link to <a class="user-mention op-uc-link" target="_top" href="http://openproject.org/users/#{user.id}" title="User Foo Barrit">Foo Barrit</a>
</p>
EXPECTED
end
@@ -60,11 +60,11 @@ RSpec.describe OpenProject::TextFormatting,
Inline reference to base_url variable: #{Rails.application.root_url}
</p>
<p class="op-uc-p">
<a href="#{Rails.application.root_url}/foo/bar" rel="noopener noreferrer"
<a href="#{Rails.application.root_url}/foo/bar" target="_top" rel="noopener noreferrer"
class="op-uc-link">Link with setting</a>
</p>
<p class="op-uc-p">
<a href="#{Rails.application.root_url}/foo/bar" rel="noopener noreferrer"
<a href="#{Rails.application.root_url}/foo/bar" target="_top" rel="noopener noreferrer"
class="op-uc-link">Saved and transformed link with setting</a>
</p>
<p class="op-uc-p">
@@ -121,7 +121,7 @@ RSpec.describe OpenProject::TextFormatting,
let(:expected) do
<<~EXPECTED
<p class="op-uc-p">
Link to <a href="http://openproject.org/foo/bar" class="op-uc-link" rel="noopener noreferrer">relative path</a>
Link to <a href="http://openproject.org/foo/bar" target="_top" class="op-uc-link" rel="noopener noreferrer">relative path</a>
</p>
EXPECTED
end
@@ -78,10 +78,18 @@ RSpec.describe UpdateProgressCalculation, type: :model do
run_migration
end
it "does not create a journal entry" do
table_work_packages.each do |wp|
expect(wp.journals.count).to eq(1)
end
it "does create a journal entry only for the work package with a total % complete" do
expect(wp_all_unset.journals.count).to eq(1)
expect(wp_only_pc_set.journals.count).to eq(1)
# This one will receive a journal entry since we treat the total % complete field
# as if it was introduced by the migration (OP 14.0) even though the field existed before.
# But the calculation was off and we did not present the activity on the field anyway.
expect(wp_all_set_consistent.journals.count).to eq(2)
expect(wp_all_set_consistent.last_journal.get_changes)
.to include("derived_done_ratio" => [nil, 60],
"cause" => [nil, { "feature" => "progress_calculation_changed", "type" => "system_update" }])
end
end
@@ -635,6 +643,26 @@ RSpec.describe UpdateProgressCalculation, type: :model do
)
end
end
context "when parent is open without any work or remaining work set, " \
"and children have a 100% complete status" do
it "sets parent total % complete to 100%" do
expect_migrates(
from: <<~TABLE,
hierarchy | status | work | remaining work | % complete
parent | To do (0%) | | | 0%
child1 | Done (100%) | 10h | 0h | 100%
child2 | Done (100%) | 10h | 0h | 100%
TABLE
to: <<~TABLE
hierarchy | status | work | remaining work | % complete | work | remaining work | % complete
parent | To do (0%) | | | 0% | 20h | 0h | 100%
child1 | Done (100%) | 10h | 0h | 100% | 10h | 0h | 100%
child2 | Done (100%) | 10h | 0h | 100% | 10h | 0h | 100%
TABLE
)
end
end
end
describe "totals computation" do
@@ -689,6 +717,148 @@ RSpec.describe UpdateProgressCalculation, type: :model do
)
end
end
context "when parent does not have any work or remaining work set, " \
"and children have a 100% complete status" do
it "sets parent total % complete to 100%" do
expect_migrates(
from: <<~TABLE,
hierarchy | work | remaining work | % complete
parent | | |
child1 | 10h | 0h | 100%
child2 | 10h | 0h | 100%
TABLE
to: <<~TABLE
hierarchy | work | remaining work | % complete | work | remaining work | % complete
parent | | | | 20h | 0h | 100%
child1 | 10h | 0h | 100% | 10h | 0h | 100%
child2 | 10h | 0h | 100% | 10h | 0h | 100%
TABLE
)
end
end
context "when work and remaining work are unset" do
it "does not set total work, total remaining work, and total % complete" do
expect_migrates(
from: <<~TABLE,
subject | work | remaining work | % complete
wp all unset | | |
wp 0% | | | 0%
wp 30% | | | 30%
wp 100% | | | 100%
TABLE
to: <<~TABLE
subject | work | remaining work | % complete | work | remaining work | % complete
wp all unset | | | | | |
wp 0% | | | 0% | | |
wp 30% | | | 30% | | |
wp 100% | | | 100% | | |
TABLE
)
end
end
context "when work is set to 0h and remaining work is unset" do
it "sets remaining work, total work, and total remaining work to 0h, unsets % complete, and keeps total % complete unset" do
expect_migrates(
from: <<~TABLE,
subject | work | remaining work | % complete
wp all unset | 0h | |
wp 0% | 0h | | 0%
wp 30% | 0h | | 30%
wp 100% | 0h | | 100%
TABLE
to: <<~TABLE
subject | work | remaining work | % complete | work | remaining work | % complete
wp all unset | 0h | 0h | | 0h | 0h |
wp 0% | 0h | 0h | | 0h | 0h |
wp 30% | 0h | 0h | | 0h | 0h |
wp 100% | 0h | 0h | | 0h | 0h |
TABLE
)
end
end
context "when work and remaining work are set and not 0h" do
it "sets total work, total remaining work, and total % complete accordingly same as work, remaining work and % complete" do
expect_migrates(
from: <<~TABLE,
subject | work | remaining work |
wp w set | 10h | |
wp rw set | | 5h |
wp w rw set | 10h | 5h |
TABLE
to: <<~TABLE
subject | work | remaining work | % complete | work | remaining work | % complete
wp w set | 10h | 10h | 0% | 10h | 10h | 0%
wp rw set | 5h | 5h | 0% | 5h | 5h | 0%
wp w rw set | 10h | 5h | 50% | 10h | 5h | 50%
TABLE
)
end
end
context "when ∑ % complete has had some values (including wrong ones)" do
let_work_packages(<<~TABLE)
hierarchy | work | remaining work | % complete | work | remaining work | % complete |
wp zero | | | 0 | | | 0 |
wp correct | 100h | 50h | 50 | 100h | 50h | 50 |
wp wrong | | | 90 | 100h | 50h | 90 |
wp wrong child | 100h | 50h | 20 | 10h | 10h | 20 |
TABLE
before do
run_migration
end
it "fixes the total values and sets ∑ % complete to nil (not 0) but keeps % complete (unless wrong)" do
expect_work_packages(WorkPackage.all, <<~TABLE)
subject | work | remaining work | % complete | work | remaining work | % complete |
wp zero | | | 0 | | | |
wp correct | 100h | 50h | 50 | 100h | 50h | 50 |
wp wrong | | | 90 | 100h | 50h | 50 |
wp wrong child | 100h | 50h | 50 | 100h | 50h | 50 |
TABLE
end
it "creates no journal for the work package transitioning from 0 to nil and reworks the pre migration journals" do
expect(wp_zero.journals.count).to eq(1)
expect(wp_zero.journals.first.get_changes.keys)
.not_to include("derived_done_ratio")
end
it "creates a journal for the correct work package as the old ∑ % complete value has been set to null during the job" do
expect(wp_correct.journals.count).to eq(2)
expect(wp_correct.journals.first.get_changes.keys)
.not_to include("derived_done_ratio")
expect(wp_correct.journals.last.get_changes["derived_done_ratio"])
.to eql [nil, 50]
end
it "creates a journal for the work package transitioning from 90 to 50 and reworks the pre migration journals" do
expect(wp_wrong.journals.count).to eq(2)
expect(wp_wrong.journals.first.get_changes.keys)
.not_to include("derived_done_ratio")
expect(wp_wrong.journals.last.get_changes["derived_done_ratio"])
.to eql [nil, 50]
end
it "creates a journal for the work package transitioning from 20 to 50 and reworks the pre migration journals" do
expect(wp_wrong_child.journals.count).to eq(2)
expect(wp_wrong_child.journals.first.get_changes.keys)
.not_to include("derived_done_ratio")
expect(wp_wrong_child.journals.last.get_changes["derived_done_ratio"])
.to eql [nil, 50]
end
end
end
describe "error during job execution" do
@@ -88,14 +88,7 @@ RSpec.describe CustomActions::Actions::DoneRatio do
end
describe ".all" do
context "with field disabled", with_settings: { work_package_done_ratio: "disabled" } do
it "is empty" do
expect(described_class.all)
.to be_empty
end
end
context "with field derived", with_settings: { work_package_done_ratio: "status" } do
context "in status-based progress calculation mode", with_settings: { work_package_done_ratio: "status" } do
it "is empty" do
expect(described_class.all)
.to be_empty
@@ -35,24 +35,8 @@ RSpec.describe Queries::WorkPackages::Selects::PropertySelect do
it_behaves_like "query column"
describe "instances" do
context "when done_ratio disabled" do
it "the done ratio column does not exist" do
allow(WorkPackage)
.to receive(:done_ratio_disabled?)
.and_return(true)
expect(described_class.instances.map(&:name)).not_to include :done_ratio
end
end
context "when done_ratio enabled" do
it "the done ratio column exists" do
allow(WorkPackage)
.to receive(:done_ratio_disabled?)
.and_return(false)
expect(described_class.instances.map(&:name)).to include :done_ratio
end
it "the done_ratio column exists" do
expect(described_class.instances.map(&:name)).to include :done_ratio
end
context "when duration feature flag enabled" do
+2 -14
View File
@@ -319,20 +319,8 @@ RSpec.describe Query,
end
describe "#available_columns" do
context "with work_package_done_ratio NOT disabled" do
it "includes the done_ratio column" do
expect(query.displayable_columns.map(&:name)).to include :done_ratio
end
end
context "with work_package_done_ratio disabled" do
before do
allow(WorkPackage).to receive(:done_ratio_disabled?).and_return(true)
end
it "does not include the done_ratio column" do
expect(query.displayable_columns.map(&:name)).not_to include :done_ratio
end
it "includes the done_ratio column" do
expect(query.displayable_columns.map(&:name)).to include :done_ratio
end
context "results caching" do
@@ -73,6 +73,7 @@ RSpec.describe "API v3 Render resource" do
<p class="op-uc-p">
Hello World! This <em>is</em> markdown with a
<a href="http://community.openproject.org"
target="_top"
rel="noopener noreferrer"
class="op-uc-link">link</a>
and ümläutß.</p>
@@ -32,8 +32,8 @@ RSpec.describe WorkPackages::UpdateAncestorsService, type: :model do
shared_association_default(:author, factory_name: :user) { create(:user) }
shared_association_default(:project_with_types) { create(:project_with_types) }
shared_association_default(:priority) { create(:priority) }
shared_association_default(:open_status, factory_name: :status) { create(:status) }
shared_let(:closed_status) { create(:closed_status) }
shared_association_default(:open_status, factory_name: :status) { create(:status, name: "Open", default_done_ratio: 0) }
shared_let(:closed_status) { create(:closed_status, name: "Closed", default_done_ratio: 100) }
shared_let(:user) { create(:user) }
let(:estimated_hours) { [nil, nil, nil] }
@@ -56,11 +56,14 @@ RSpec.describe WorkPackages::UpdateAncestorsService, type: :model do
describe "done_ratio/estimated_hours/remaining_hours propagation" do
context "when setting the status of a work package" do
shared_let(:open_status) { create(:status, name: "open", default_done_ratio: 0) }
shared_let(:complete_status_with_100p_done_ratio) { create(:status, name: "complete", default_done_ratio: 100) }
context 'when using the "status-based" % complete mode',
with_settings: { work_package_done_ratio: "status" } do
def call_update_ancestors_service(work_package)
changed_attributes = work_package.changes.keys.map(&:to_sym)
described_class.new(user:, work_package:)
.call(changed_attributes)
end
context "with both parent and children having estimated hours set" do
shared_let(:parent) do
create(:work_package,
@@ -80,19 +83,14 @@ RSpec.describe WorkPackages::UpdateAncestorsService, type: :model do
status: open_status)
end
def call_update_ancestors_service(work_package)
changed_attributes = work_package.changes.keys.map(&:to_sym)
described_class.new(user:, work_package:)
.call(changed_attributes)
end
context "when changing child status to a status with a default done ratio" do
%i[status status_id].each do |field|
context "with the #{field} field" do
it "recomputes child remaining work and update ancestors total % complete accordingly" do
value =
case field
when :status then complete_status_with_100p_done_ratio
when :status_id then complete_status_with_100p_done_ratio.id
when :status then closed_status
when :status_id then closed_status.id
end
set_attributes_on(child, field => value)
call_update_ancestors_service(child)
@@ -100,13 +98,40 @@ RSpec.describe WorkPackages::UpdateAncestorsService, type: :model do
expect_work_packages([parent, child], <<~TABLE)
| subject | work | total work | remaining work | total remaining work | % complete | total % complete |
| parent | 10h | 15h | 10h | 10h | 0% | 33% |
| child | 5h | 5h | 0h | | 100% | |
| child | 5h | 5h | 0h | 0h | 100% | 100% |
TABLE
end
end
end
end
end
context "with parent having nothing set, and 2 children having values set (bug #54179)" do
let_work_packages(<<~TABLE)
hierarchy | status | work | work | remaining work | remaining work | % complete | % complete
parent | Open | | 15h | | 10h | 0% | 33%
child1 | Open | 10h | | 10h | | 0% |
child2 | Closed | 5h | | 0h | | 100% |
TABLE
context "when changing children to all have 100% complete" do
before do
set_attributes_on(child1, status: closed_status)
call_update_ancestors_service(child1)
end
it "sets parent total % complete to 100% and its total remaining work to 0h, " \
"and computes totals for the updated children too" do
table_work_packages.map(&:reload)
expect_work_packages(table_work_packages, <<~TABLE)
hierarchy | status | work | work | remaining work | remaining work | % complete | % complete
parent | Open | | 15h | | 0h | 0% | 100%
child1 | Closed | 10h | 10h | 0h | 0h | 100% | 100%
child2 | Closed | 5h | | 0h | | 100% |
TABLE
end
end
end
end
end
@@ -224,7 +249,7 @@ RSpec.describe WorkPackages::UpdateAncestorsService, type: :model do
end
end
context "with all tasks having estimated hours and no tasks having any progress done yet" do
context "with all tasks having estimated hours and no tasks having any remaining hours" do
it_behaves_like "attributes of parent having children" do
let(:estimated_hours) do
[10.0, 2.0, 3.0]
@@ -237,10 +262,10 @@ RSpec.describe WorkPackages::UpdateAncestorsService, type: :model do
15.0
end
let(:aggregate_remaining_hours) do
nil # zero-values aren't accounted for
0.0
end
let(:aggregate_done_ratio) do
nil
100
end
end
end
@@ -431,7 +456,7 @@ RSpec.describe WorkPackages::UpdateAncestorsService, type: :model do
end
end
context "with all tasks having estimated hours and no tasks having any progress done yet" do
context "with all tasks having estimated hours and no tasks having remaining hours" do
it_behaves_like "attributes of parent having children" do
let(:estimated_hours) do
[10.0, 2.0, 3.0]
@@ -444,10 +469,10 @@ RSpec.describe WorkPackages::UpdateAncestorsService, type: :model do
15.0
end
let(:aggregate_remaining_hours) do
nil # zero-values aren't accounted for
0.0
end
let(:aggregate_done_ratio) do
nil
100
end
end
end