Merge pull request #8335 from tchak/feat-show-dossiers-per-change

feat(revision): show number of pending dossiers for each revision
This commit is contained in:
Paul Chavard 2022-12-27 11:14:40 +00:00 committed by GitHub
commit 96d09fbf63
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 415 additions and 375 deletions

View file

@ -0,0 +1,16 @@
class Procedure::RevisionChangesComponent < ApplicationComponent
def initialize(changes:, previous_revision:)
@changes = changes
@previous_revision = previous_revision
@public_move_changes, @private_move_changes = changes.filter { _1.op == :move }.partition { !_1.private? }
end
private
def total_dossiers
@total_dossiers ||= @previous_revision.dossiers
.visible_by_administration
.state_en_construction_ou_instruction
.size
end
end

View file

@ -0,0 +1,59 @@
---
fr:
no_changes: Aucune modification
breaking_change:
one: Un dossier en cours de traitement nest pas compatible avec ce changement.
other: "%{count} dossiers en cours de traitement ne sont pas compatible avec ce changement."
add_option: "ajoutés : %{items}"
remove_option: "supprimés : %{items}"
public:
add: Le champ « %{label} » a été ajouté.
add_mandatory: Le champ obligatoire « %{label} » a été ajouté.
remove: Le champ « %{label} » a été supprimé.
move:
one: La position dun champ a été modifiée.
other: Les positions de %{count} champs ont été modifiées.
update_libelle: Le libellé du champ « %{label} » a été modifié. Le nouveau libellé est « %{to} ».
update_description: La description du champ « %{label} » a été modifiée. La nouvelle description est « %{to} ».
remove_description: La description du champ « %{label} » a été supprimée.
update_drop_down_secondary_libelle: Le libellé secondaire du champ « %{label} » a été modifié. Le nouveau libellé est « %{to} ».
update_drop_down_secondary_description: La description secondaire du champ « %{label} » a été modifiée. La nouvelle description est « %{to} ».
update_type_champ: Le type du champ « %{label} » a été modifié. Il est maintenant de type « %{to} ».
update_piece_justificative_template: Le modèle de pièce justificative du champ « %{label} » a été modifié.
update_drop_down_options: "Les options de sélection du champ « %{label} » ont été modifiées :"
enable_mandatory: Le champ « %{label} » est maintenant obligatoire.
disable_mandatory: Le champ « %{label} » nest plus obligatoire.
enable_drop_down_other: Le champ « %{label} » comporte maintenant un choix « Autre ».
disable_drop_down_other: Le champ « %{label} » ne comporte plus de choix « Autre ».
update_carte_layers: "Les référentiels cartographiques du champ « %{label} » ont été modifiés :"
enable_update_collapsible_explanation: Le texte complementaire affichable au clique du champ « %{label} » a été ajouté.
disable_update_collapsible_explanation: Le texte complementaire affichable au clique du champ « %{label} » a été supprimée.
update_collapsible_explanation_text: Le texte complementaire affichable au clique du champ « %{label} » a été modifié. Le nouveau texte est « %{to} ».
remove_collapsible_explanation_text: Le texte complementaire affichable au clique du champ « %{label} » a été supprimée.
add_condition: Une condition a été ajoutée sur le champ « %{label} ». La nouvelle condition est « %{to} ».
remove_condition: La condition du champ « %{label} » a été supprimée.
update_condition: La condition du champ « %{label} » a été modifiée. La nouvelle condition est « %{to} ».
private:
add: Lannotation privée « %{label} » a été ajoutée.
remove: Lannotation privée « %{label} » a été supprimée.
move:
one: La position dune annotation privée a été modifiée.
other: Les positions de %{count} annotations privées ont été modifiées.
update_libelle: Le libellé de lannotation privée « %{label} » a été modifié. Le nouveau libellé est « %{to} ».
update_description: La description de lannotation privée « %{label} » a été modifiée. La nouvelle description est « %{to} ».
remove_description: La description de lannotation privée « %{label} » a été supprimée.
update_drop_down_secondary_libelle: Le libellé secondaire de lannotation « %{label} » a été modifié. Le nouveau libellé est « %{to} ».
update_drop_down_secondary_description: La description secondaire de lannotation « %{label} » a été modifiée. La nouvelle description est « %{to} ».
update_type_champ_private: Le type de lannotation privée « %{label} » a été modifié. Elle est maintenant de type « %{to} ».
update_piece_justificative_template_private: Le modèle de pièce justificative de lannotation privée « %{label} » a été modifié.
update_drop_down_options_private: "Les options de sélection de lannotation privée « %{label} » ont été modifiées :"
update_carte_layers_private: "Les référentiels cartographiques de lannotation privée « %{label} » ont été modifiés :"
enable_drop_down_other: Lannotation privée « %{label} » comporte maintenant un choix « Autre ».
disable_drop_down_other: Lannotation privée « %{label} » ne comporte plus de choix « Autre ».
enable_collapsible_explanation: Le texte complementaire affichable au clique de lannotation privée « %{label} » a été ajouté.
disable_collapsible_explanation: Le texte complementaire affichable au clique de lannotation privée « %{label} » a été supprimée.
update_collapsible_explanation: Le texte complementaire affichable au clique de lannotation privée « %{label} » a été modifié. Le nouveau texte est « %{to} ».
remove_collapsible_explanation: Le texte complementaire affichable au clique de lannotation privée « %{label} » a été supprimée.
add_condition: Une condition a été ajoutée sur lannotation privée « %{label} ». La nouvelle condition est « %{to} ».
remove_condition: La condition de lannotation privée « %{label} » a été supprimée.
update_condition: La condition de lannotation privée « %{label} » a été modifiée. La nouvelle condition est « %{to} ».

View file

@ -0,0 +1,137 @@
= render Dsfr::ListComponent.new do |list|
- list.with_empty do
= t('.no_changes')
- @changes.each do |change|
- prefix = change.private? ? 'private' : 'public'
- case change.op
- when :add
- list.with_item do
- if change.mandatory?
= t('.public.add_mandatory', label: change.label)
- else
= t(".#{prefix}.add", label: change.label)
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t('.breaking_change', count: total_dossiers)
- when :remove
- list.with_item do
= t(".#{prefix}.remove", label: change.label)
- when :update
- case change.attribute
- when :libelle
- list.with_item do
= t(".#{prefix}.update_libelle", label: change.label, to: change.to)
- when :type_champ
- list.with_item do
= t(".#{prefix}.update_type_champ", label: change.label, to: t("activerecord.attributes.type_de_champ.type_champs.#{change.to}"))
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t('.breaking_change', count: total_dossiers)
- when :description
- list.with_item do
- if change.to.blank?
= t(".#{prefix}.remove_description", label: change.label, to: change.to)
- else
= t(".#{prefix}.update_description", label: change.label, to: change.to)
- when :drop_down_secondary_libelle
- list.with_item do
= t(".#{prefix}.update_drop_down_secondary_libelle", label: change.label, to: change.to)
- when :drop_down_secondary_description
- list.with_item do
= t(".#{prefix}.update_drop_down_secondary_description", label: change.label, to: change.to)
- when :mandatory
- if change.from == false
- list.with_item do
= t(".public.enable_mandatory", label: change.label)
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t(:breaking_change, count: total_dossiers)
- else
- list.with_item do
= t(".public.disable_mandatory", label: change.label)
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t(:breaking_change, count: total_dossiers)
- when :piece_justificative_template
- list.with_item do
= t(".#{prefix}.update_piece_justificative_template", label: change.label)
- when :drop_down_options
- added = change.to.sort - change.from.sort
- removed = change.from.sort - change.to.sort
- list.with_item do
= t(".#{prefix}.update_drop_down_options", label: change.label)
= render Dsfr::ListComponent.new do |list|
- if added.present?
- list.with_item do
= t('.add_option', items: added.map{ |term| "« #{term.strip} »" }.join(", "))
- if removed.present?
- list.with_item do
= t('.remove_option', items: removed.map{ |term| "« #{term.strip} »" }.join(", "))
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t('.breaking_change', count: total_dossiers)
- when :drop_down_other
- if change.from == false
- list.with_item do
= t(".#{prefix}.enable_drop_down_other", label: change.label)
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t('.breaking_change', count: total_dossiers)
- else
- list.with_item do
= t(".#{prefix}.disable_drop_down_other", label: change.label)
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t('.breaking_change', count: total_dossiers)
- when :carte_layers
- added = change.to.sort - change.from.sort
- removed = change.from.sort - change.to.sort
- list.with_item do
= t(".#{prefix}.update_carte_layers", label: change.label)
= render Dsfr::ListComponent.new do |list|
- if added.present?
- list.with_item do
= t('.add_option', items: added.map{ |term| "« #{t(term, scope: [:administrateurs, :carte_layers])} »" }.join(", "))
- if removed.present?
- list.with_item do
= t('.remove_option', items: removed.map{ |term| "« #{t(term, scope: [:administrateurs, :carte_layers])} »" }.join(", "))
- when :collapsible_explanation_enabled
- if change.to
- list.with_item do
= t(".#{prefix}.enable_collapsible_explanation", label: change.label)
- else
- list.with_item do
= t(".#{prefix}.disable_collapsible_explanation", label: change.label)
- when :collapsible_explanation_text
- list.with_item do
- if change.to.blank?
= t(".#{prefix}.remove_collapsible_explanation_text", label: change.label, to: change.to)
- else
= t(".#{prefix}.update_collapsible_explanation_text", label: change.label, to: change.to)
- when :condition
- if change.from.nil?
- list.with_item do
= t(".#{prefix}.add_condition", label: change.label, to: change.to)
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t(:breaking_change, count: total_dossiers)
- elsif change.to.nil?
- list.with_item do
= t(".#{prefix}.remove_condition", label: change.label)
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t(:breaking_change, count: total_dossiers)
- else
- list.with_item do
= t(".#{prefix}.update_condition", label: change.label, to: change.to)
- if !total_dossiers.zero? && !change.can_rebase?
%strong
= t(:breaking_change, count: total_dossiers)
- if @public_move_changes.present?
- list.with_item do
= t(".public.move", count: @public_move_changes.size)
- if @private_move_changes.present?
- list.with_item do
= t(".private.move", count: @private_move_changes.size)

View file

@ -22,33 +22,18 @@ module DossierRebaseConcern
revision.compare(procedure.published_revision)
end
def can_rebase_mandatory_change?(stable_id)
!champs.filter { _1.stable_id == stable_id }.any?(&:blank?)
end
private
def accepted_en_construction_changes?
en_construction? && pending_changes.all? { |change| accepted_change?(change) }
en_construction? && pending_changes.all? { _1.can_rebase?(self) }
end
def accepted_en_instruction_changes?
en_instruction? && pending_changes.all? { |change| accepted_change?(change) }
end
def accepted_change?(change)
return true if change[:private]
return true if change[:op].in?([:remove, :move])
return !change[:mandatory] if change[:op] == :add
case change[:attribute]
when :drop_down_options
(change[:from] - change[:to]).empty?
when :drop_down_other
!change[:from] && change[:to]
when :mandatory
(change[:from] && !change[:to]) || can_change_mandatory?(change)
when :type_champ, :condition
false
else
true
end
en_instruction? && pending_changes.all? { _1.can_rebase?(self) }
end
def rebase
@ -62,22 +47,21 @@ module DossierRebaseConcern
.index_by(&:stable_id)
changes_by_op = pending_changes
.filter { |change| change[:model] == :type_de_champ }
.group_by { |change| change[:op] }
.tap { |h| h.default = [] }
.group_by(&:op)
.tap { _1.default = [] }
# add champ
changes_by_op[:add]
.map { |change| change[:stable_id] }
.map { |stable_id| target_coordinates_by_stable_id[stable_id] }
.each { |coordinate| add_new_champs_for_revision(coordinate) }
.map(&:stable_id)
.map { target_coordinates_by_stable_id[_1] }
.each { add_new_champs_for_revision(_1) }
# remove champ
changes_by_op[:remove]
.each { |change| delete_champs_for_revision(change[:stable_id]) }
.each { delete_champs_for_revision(_1.stable_id) }
changes_by_op[:update]
.map { |change| [change, Champ.joins(:type_de_champ).where(dossier: self, type_de_champ: { stable_id: change[:stable_id] })] }
.map { |change| [change, champs.joins(:type_de_champ).where(type_de_champ: { stable_id: change.stable_id })] }
.each { |change, champs| apply(change, champs) }
# due to repetition tdc clone on update or erase
@ -85,22 +69,22 @@ module DossierRebaseConcern
Champ
.includes(:type_de_champ)
.where(dossier: self)
.map { |c| [c, target_coordinates_by_stable_id[c.stable_id].type_de_champ] }
.each { |c, target_tdc| c.update_columns(type_de_champ_id: target_tdc.id, rebased_at: Time.zone.now) }
.map { [_1, target_coordinates_by_stable_id[_1.stable_id].type_de_champ] }
.each { |champ, target_tdc| champ.update_columns(type_de_champ_id: target_tdc.id, rebased_at: Time.zone.now) }
# update dossier revision
self.update_column(:revision_id, target_revision.id)
end
def apply(change, champs)
case change[:attribute]
case change.attribute
when :type_champ
champs.each { |champ| purge_piece_justificative_file(champ) }
champs.each { purge_piece_justificative_file(_1) }
GeoArea.where(champ: champs).destroy_all
Etablissement.where(champ: champs).destroy_all
{
type: "Champs::#{change[:to].classify}Champ",
type: "Champs::#{change.to.classify}Champ",
value: nil,
value_json: nil,
external_id: nil,
@ -110,22 +94,22 @@ module DossierRebaseConcern
{ value: nil }
when :carte_layers
# if we are removing cadastres layer, we need to remove cadastre geo areas
if change[:from].include?(:cadastres) && !change[:to].include?(:cadastres)
champs.each { |champ| champ.cadastres.each(&:destroy) }
if change.from.include?(:cadastres) && !change.to.include?(:cadastres)
champs.each { _1.cadastres.each(&:destroy) }
end
nil
end
&.then { |update_params| champs.update_all(update_params) }
&.then { champs.update_all(_1) }
end
def add_new_champs_for_revision(target_coordinate)
if target_coordinate.child?
# If this type de champ is a child, we create a new champ for each row of the parent
parent_stable_id = target_coordinate.parent.stable_id
champs_repetition = Champ
champs_repetition = champs
.includes(:champs, :type_de_champ)
.where(dossier: self, type_de_champ: { stable_id: parent_stable_id })
.where(type_de_champ: { stable_id: parent_stable_id })
champs_repetition.each do |champ_repetition|
champ_repetition.champs.map(&:row).uniq.each do |row|
@ -147,17 +131,13 @@ module DossierRebaseConcern
end
def delete_champs_for_revision(stable_id)
Champ
champs
.joins(:type_de_champ)
.where(dossier: self, types_de_champ: { stable_id: stable_id })
.where(types_de_champ: { stable_id: })
.destroy_all
end
def purge_piece_justificative_file(champ)
ActiveStorage::Attachment.where(id: champ.piece_justificative_file.ids).delete_all
end
def can_change_mandatory?(change)
!champs.filter { _1.stable_id == change[:stable_id] }.any?(&:blank?)
end
end

View file

@ -247,198 +247,110 @@ class ProcedureRevision < ApplicationRecord
from_sids = from_h.keys
to_sids = to_h.keys
removed = (from_sids - to_sids).map do |sid|
{ model: :type_de_champ, op: :remove, label: from_h[sid].libelle, private: from_h[sid].private?, _position: from_sids.index(sid), stable_id: sid }
end
added = (to_sids - from_sids).map do |sid|
{ model: :type_de_champ, op: :add, label: to_h[sid].libelle, private: to_h[sid].private?, mandatory: to_h[sid].mandatory?, _position: to_sids.index(sid), stable_id: sid }
end
removed = (from_sids - to_sids).map { ProcedureRevisionChange::RemoveChamp.new(from_h[_1]) }
added = (to_sids - from_sids).map { ProcedureRevisionChange::AddChamp.new(to_h[_1]) }
kept = from_sids.intersection(to_sids)
moved = kept
.map { |sid| [sid, from_h[sid], to_h[sid]] }
.filter { |_, from, to| from.position != to.position }
.map do |sid, from, to|
{ model: :type_de_champ, op: :move, label: from.libelle, private: from.private?, from: from.position, to: to.position, _position: to_sids.index(sid), stable_id: sid }
end
.map { [from_h[_1], to_h[_1]] }
.filter { |from, to| from.position != to.position }
.map { |from, to| ProcedureRevisionChange::MoveChamp.new(from, from.position, to.position) }
changed = kept
.map { |sid| [sid, from_h[sid], to_h[sid]] }
.flat_map do |sid, from, to|
compare_type_de_champ(from.type_de_champ, to.type_de_champ, from_coordinates, to_coordinates)
.each { |h| h[:_position] = to_sids.index(sid) }
end
.map { [from_h[_1], to_h[_1]] }
.flat_map { |from, to| compare_type_de_champ(from.type_de_champ, to.type_de_champ, from_coordinates, to_coordinates) }
(removed + added + moved + changed)
.sort_by { |h| h[:_position] }
.each { |h| h.delete(:_position) }
(removed + added + moved + changed).sort_by { _1.op == :remove ? from_sids[_1.stable_id] : to_sids[_1.stable_id] }
end
end
def compare_type_de_champ(from_type_de_champ, to_type_de_champ, from_coordinates, to_coordinates)
changes = []
if from_type_de_champ.type_champ != to_type_de_champ.type_champ
changes << {
model: :type_de_champ,
op: :update,
attribute: :type_champ,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.type_champ,
to: to_type_de_champ.type_champ,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:type_champ,
from_type_de_champ.type_champ,
to_type_de_champ.type_champ)
end
if from_type_de_champ.libelle != to_type_de_champ.libelle
changes << {
model: :type_de_champ,
op: :update,
attribute: :libelle,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.libelle,
to: to_type_de_champ.libelle,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:libelle,
from_type_de_champ.libelle,
to_type_de_champ.libelle)
end
if from_type_de_champ.collapsible_explanation_enabled? != to_type_de_champ.collapsible_explanation_enabled?
changes << {
model: :type_de_champ,
op: :update,
attribute: :collapsible_explanation_enabled,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.collapsible_explanation_enabled?,
to: to_type_de_champ.collapsible_explanation_enabled?,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:collapsible_explanation_enabled,
from_type_de_champ.collapsible_explanation_enabled?,
to_type_de_champ.collapsible_explanation_enabled?)
end
if from_type_de_champ.collapsible_explanation_text != to_type_de_champ.collapsible_explanation_text
changes << {
model: :type_de_champ,
op: :update,
attribute: :collapsible_explanation_text,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.collapsible_explanation_text,
to: to_type_de_champ.collapsible_explanation_text,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:collapsible_explanation_text,
from_type_de_champ.collapsible_explanation_text,
to_type_de_champ.collapsible_explanation_text)
end
if from_type_de_champ.description != to_type_de_champ.description
changes << {
model: :type_de_champ,
op: :update,
attribute: :description,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.description,
to: to_type_de_champ.description,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:description,
from_type_de_champ.description,
to_type_de_champ.description)
end
if from_type_de_champ.mandatory? != to_type_de_champ.mandatory?
changes << {
model: :type_de_champ,
op: :update,
attribute: :mandatory,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.mandatory?,
to: to_type_de_champ.mandatory?,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:mandatory,
from_type_de_champ.mandatory?,
to_type_de_champ.mandatory?)
end
if from_type_de_champ.condition != to_type_de_champ.condition
changes << {
model: :type_de_champ,
op: :update,
attribute: :condition,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.condition&.to_s(from_coordinates.map(&:type_de_champ)),
to: to_type_de_champ.condition&.to_s(to_coordinates.map(&:type_de_champ)),
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:condition,
from_type_de_champ.condition&.to_s(from_coordinates.map(&:type_de_champ)),
to_type_de_champ.condition&.to_s(to_coordinates.map(&:type_de_champ)))
end
if to_type_de_champ.drop_down_list?
if from_type_de_champ.drop_down_list_options != to_type_de_champ.drop_down_list_options
changes << {
model: :type_de_champ,
op: :update,
attribute: :drop_down_options,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.drop_down_list_options,
to: to_type_de_champ.drop_down_list_options,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:drop_down_options,
from_type_de_champ.drop_down_list_options,
to_type_de_champ.drop_down_list_options)
end
if to_type_de_champ.linked_drop_down_list?
if from_type_de_champ.drop_down_secondary_libelle != to_type_de_champ.drop_down_secondary_libelle
changes << {
model: :type_de_champ,
op: :update,
attribute: :drop_down_secondary_libelle,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.drop_down_secondary_libelle,
to: to_type_de_champ.drop_down_secondary_libelle
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:drop_down_secondary_libelle,
from_type_de_champ.drop_down_secondary_libelle,
to_type_de_champ.drop_down_secondary_libelle)
end
if from_type_de_champ.drop_down_secondary_description != to_type_de_champ.drop_down_secondary_description
changes << {
model: :type_de_champ,
op: :update,
attribute: :drop_down_secondary_description,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.drop_down_secondary_description,
to: to_type_de_champ.drop_down_secondary_description
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:drop_down_secondary_description,
from_type_de_champ.drop_down_secondary_description,
to_type_de_champ.drop_down_secondary_description)
end
end
if from_type_de_champ.drop_down_other? != to_type_de_champ.drop_down_other?
changes << {
model: :type_de_champ,
op: :update,
attribute: :drop_down_other,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.drop_down_other?,
to: to_type_de_champ.drop_down_other?,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:drop_down_other,
from_type_de_champ.drop_down_other?,
to_type_de_champ.drop_down_other?)
end
elsif to_type_de_champ.carte?
if from_type_de_champ.carte_optional_layers != to_type_de_champ.carte_optional_layers
changes << {
model: :type_de_champ,
op: :update,
attribute: :carte_layers,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.carte_optional_layers,
to: to_type_de_champ.carte_optional_layers,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:carte_layers,
from_type_de_champ.carte_optional_layers,
to_type_de_champ.carte_optional_layers)
end
elsif to_type_de_champ.piece_justificative?
if from_type_de_champ.piece_justificative_template_checksum != to_type_de_champ.piece_justificative_template_checksum
changes << {
model: :type_de_champ,
op: :update,
attribute: :piece_justificative_template,
label: from_type_de_champ.libelle,
private: from_type_de_champ.private?,
from: from_type_de_champ.piece_justificative_template_filename,
to: to_type_de_champ.piece_justificative_template_filename,
stable_id: from_type_de_champ.stable_id
}
changes << ProcedureRevisionChange::UpdateChamp.new(from_type_de_champ,
:piece_justificative_template,
from_type_de_champ.piece_justificative_template_filename,
to_type_de_champ.piece_justificative_template_filename)
end
end
changes

View file

@ -0,0 +1,77 @@
class ProcedureRevisionChange
def initialize(type_de_champ)
@type_de_champ = type_de_champ
end
def label = @type_de_champ.libelle
def stable_id = @type_de_champ.stable_id
def private? = @type_de_champ.private?
def to_h = { op:, stable_id:, label:, private: private? }
class AddChamp < ProcedureRevisionChange
def initialize(type_de_champ)
super(type_de_champ)
end
def op = :add
def mandatory? = @type_de_champ.mandatory?
def can_rebase?(dossier = nil) = !mandatory?
def to_h = super.merge(mandatory: mandatory?)
end
class RemoveChamp < ProcedureRevisionChange
def initialize(type_de_champ)
super(type_de_champ)
end
def op = :remove
def can_rebase?(dossier = nil) = true
end
class MoveChamp < ProcedureRevisionChange
attr_reader :from, :to
def initialize(type_de_champ, from, to)
super(type_de_champ)
@from = from
@to = to
end
def op = :move
def can_rebase?(dossier = nil) = true
def to_h = super.merge(from:, to:)
end
class UpdateChamp < ProcedureRevisionChange
attr_reader :attribute, :from, :to
def initialize(type_de_champ, attribute, from, to)
super(type_de_champ)
@attribute = attribute
@from = from
@to = to
end
def op = :update
def to_h = super.merge(attribute:, from:, to:)
def can_rebase?(dossier = nil)
return true if private?
case attribute
when :drop_down_options
(from - to).empty?
when :drop_down_other
!from && to
when :mandatory
(from && !to) || dossier&.can_rebase_mandatory_change?(stable_id)
when :type_champ, :condition
false
else
true
end
end
end
end

View file

@ -5,7 +5,7 @@
.mt-2
- if procedure.draft_changed?
%p.mb-2 Publiez une nouvelle version de votre démarche. Les modifications suivantes seront appliquées :
= render partial: 'revision_changes', locals: { changes: procedure.revision_changes }
= render Procedure::RevisionChangesComponent.new changes: procedure.revision_changes, previous_revision: procedure.published_revision
- if procedure.close?
= render partial: 'publication_form_inputs', locals: { procedure: procedure, closed_procedures: @closed_procedures }
- else

View file

@ -1,93 +0,0 @@
- postfix = change[:private] ? '_private' : ''
- case change[:op]
- when :add
- list.with_item do
= t("add#{postfix}", label: change[:label], scope: [:administrateurs, :revision_changes])
- when :remove
- list.with_item do
= t("remove#{postfix}", label: change[:label], scope: [:administrateurs, :revision_changes])
- when :update
- case change[:attribute]
- when :libelle
- list.with_item do
= t("update_libelle#{postfix}", label: change[:label], to: change[:to], scope: [:administrateurs, :revision_changes])
- when :type_champ
- list.with_item do
= t("update_type_champ#{postfix}", label: change[:label], to: t("activerecord.attributes.type_de_champ.type_champs.#{change[:to]}"), scope: [:administrateurs, :revision_changes])
- when :description
- list.with_item do
= t("update_description#{postfix}", label: change[:label], to: change[:to], scope: [:administrateurs, :revision_changes])
- when :drop_down_secondary_libelle
- list.with_item do
= t("update_drop_down_secondary_libelle#{postfix}", label: change[:label], to: change[:to], scope: [:administrateurs, :revision_changes])
- when :drop_down_secondary_description
- list.with_item do
= t("update_drop_down_secondary_description#{postfix}", label: change[:label], to: change[:to], scope: [:administrateurs, :revision_changes])
- when :mandatory
- if change[:from] == false
-# i18n-tasks-use t('administrateurs.revision_changes.update_mandatory.enabled')
-# i18n-tasks-use t('administrateurs.revision_changes.update_mandatory_private.enabled')
- list.with_item do
= t("administrateurs.revision_changes.update_mandatory#{postfix}.enabled", label: change[:label])
- else
-# i18n-tasks-use t('administrateurs.revision_changes.update_mandatory.disabled')
-# i18n-tasks-use t('administrateurs.revision_changes.update_mandatory_private.disabled')
- list.with_item do
= t("administrateurs.revision_changes.update_mandatory#{postfix}.disabled", label: change[:label])
- when :piece_justificative_template
-# i18n-tasks-use t('administrateurs.revision_changes.update_piece_justificative_template')
-# i18n-tasks-use t('administrateurs.revision_changes.update_piece_justificative_template_private')
- list.with_item do
= t("administrateurs.revision_changes.update_piece_justificative_template#{postfix}", label: change[:label])
- when :drop_down_options
- added = change[:to].sort - change[:from].sort
- removed = change[:from].sort - change[:to].sort
- list.with_item do
= t("update_drop_down_options#{postfix}", scope: [:administrateurs, :revision_changes], label: change[:label])
= render Dsfr::ListComponent.new do |list|
- if added.present?
- list.with_item do
= t(:add_option, scope: [:administrateurs, :revision_changes], items: added.map{ |term| "« #{term.strip} »" }.join(", "))
- if removed.present?
- list.with_item do
= t(:remove_option, scope: [:administrateurs, :revision_changes], items: removed.map{ |term| "« #{term.strip} »" }.join(", "))
- when :drop_down_other
- if change[:from] == false
- list.with_item do
= t("administrateurs.revision_changes.update_drop_down_other#{postfix}.enabled", label: change[:label])
- else
- list.with_item do
= t("administrateurs.revision_changes.update_drop_down_other#{postfix}.disabled", label: change[:label])
- when :carte_layers
- added = change[:to].sort - change[:from].sort
- removed = change[:from].sort - change[:to].sort
- list.with_item do
= t("update_carte_layers#{postfix}", scope: [:administrateurs, :revision_changes], label: change[:label])
= render Dsfr::ListComponent.new do |list|
- if added.present?
- list.with_item do
= t(:add_option, scope: [:administrateurs, :revision_changes], items: added.map{ |term| "« #{t(term, scope: [:administrateurs, :carte_layers])} »" }.join(", "))
- if removed.present?
- list.with_item do
= t(:remove_option, scope: [:administrateurs, :revision_changes], items: removed.map{ |term| "« #{t(term, scope: [:administrateurs, :carte_layers])} »" }.join(", "))
- when :collapsible_explanation_enabled
- if change[:to]
- list.with_item do
= t("administrateurs.revision_changes.update_collapsible_explanation_enabled#{postfix}.enabled", label: change[:label])
- else
- list.with_item do
= t("administrateurs.revision_changes.update_collapsible_explanation_enabled#{postfix}.disabled", label: change[:label])
- when :collapsible_explanation_text
- list.with_item do
= t("administrateurs.revision_changes.update_collapsible_explanation_text#{postfix}", label: change[:label], text: change[:to])
- when :condition
- if change[:from].nil?
- list.with_item do
= t(:add_condition, scope: [:administrateurs, :revision_changes], label: change[:label], to: change[:to])
- elsif change[:to].nil?
- list.with_item do
= t(:remove_condition, scope: [:administrateurs, :revision_changes], label: change[:label])
- else
- list.with_item do
= t(:update_condition, scope: [:administrateurs, :revision_changes], label: change[:label], to: change[:to])

View file

@ -1,12 +0,0 @@
= render Dsfr::ListComponent.new do |list|
- list.with_empty do
= t(:no_changes, scope: [:administrateurs, :revision_changes])
= render partial: "administrateurs/procedures/revision_change_type_de_champ", collection: changes.filter { |change| change[:model] == :type_de_champ }, as: :change, locals: { list: list }
- move_changes, move_private_changes = changes.filter { |change| change[:op] == :move }.partition { |change| !change[:private] }
- if move_changes.present?
- list.with_item do
= t(:move, scope: [:administrateurs, :revision_changes], count: move_changes.size)
- if move_private_changes.present?
- list.with_item do
= t(:move_private, scope: [:administrateurs, :revision_changes], count: move_private_changes.size)

View file

@ -11,7 +11,22 @@
- @procedure.revisions.each do |revision|
- if previous_revision.present? && !revision.draft?
- changes = previous_revision.compare(revision)
- dossiers = revision.dossiers.visible_by_administration
- dossiers_en_construction_count = dossiers.state_en_construction.count
- dossiers_en_instruction_count = dossiers.state_en_instruction.count
.card.mb-4
%h2.card-title= "Modifications publiées le #{l(revision.published_at, format: '%d %B %Y à %R')}"
= render partial: 'revision_changes', locals: { changes: changes }
- if !dossiers_en_construction_count.zero? && !dossiers_en_instruction_count.zero?
%p
- if dossiers_en_construction_count == 1
= t('.dossier_en_construction_and_dossiers_en_instruction', count: dossiers_en_instruction_count)
- elsif dossiers_en_instruction_count == 1
= t('.dossier_en_instruction_and_dossiers_en_construction', count: dossiers_en_construction_count)
- else
= t('.dossiers_en_construction_and_dossiers_en_instruction', en_construction_count: dossiers_en_construction_count, en_instruction_count: dossiers_en_instruction_count)
- elsif !dossiers_en_construction_count.zero?
%p= t('.dossiers_en_construction', count: dossiers_en_construction_count)
- elsif !dossiers_en_instruction_count.zero?
%p= t('.dossiers_en_instruction', count: dossiers_en_instruction_count)
= render Procedure::RevisionChangesComponent.new changes:, previous_revision:
- previous_revision = revision

View file

@ -47,7 +47,7 @@
.card.featured
.card-title
= t(:has_changes, scope: [:administrateurs, :revision_changes])
= render partial: 'revision_changes', locals: { changes: @procedure.revision_changes }
= render Procedure::RevisionChangesComponent.new changes: @procedure.revision_changes, previous_revision: @procedure.published_revision
.flex.mt-2.justify-end
= button_to "Réinitialiser les modifications", admin_procedure_reset_draft_path(@procedure), class: 'fr-btn fr-btn--secondary fr-mr-2w', method: :put
= button_to 'Publier les modifications', admin_procedure_publication_path(@procedure), class: 'fr-btn', id: 'publish-procedure-link', data: { disable_with: "Publication..." }, disabled: !@procedure.draft_revision.valid?, method: :get

View file

@ -6,3 +6,17 @@ fr:
actions:
close_procedure: Clore la démarche
preview_unavailable: Aperçu non disponible car la démarche est mal configurée
modifications:
dossiers_en_construction_and_dossiers_en_instruction: Il y a %{en_construction_count} dossiers « en construction » et %{en_instruction_count} dossiers « en instruction » sur cette version de la démarche.
dossier_en_construction_and_dossiers_en_instruction:
one: Il y a un dossier « en construction » et un dossier « en instruction » sur cette version de la démarche.
other: Il y a un dossier « en construction » et %{count} dossiers « en instruction » sur cette version de la démarche.
dossier_en_instruction_and_dossiers_en_construction:
one: Il y a un dossier « en instruction » et un dossier « en construction » sur cette version de la démarche.
other: Il y a un dossier « en instruction » et %{count} dossiers « en construction » sur cette version de la démarche.
dossiers_en_construction:
one: Il y a un dossier « en construction » sur cette version de la démarche.
other: Il y a %{count} dossiers « en construction » sur cette version de la démarche.
dossiers_en_instruction:
one: Il y a un dossier « en instruction » sur cette version de la démarche.
other: Il y a %{count} dossiers « en instruction » sur cette version de la démarche.

View file

@ -1,56 +1,7 @@
fr:
administrateurs:
revision_changes:
no_changes: Aucune modification
has_changes: Modifications en cours (appliqué à la prochaine publication)
add: Le champ « %{label} » a été ajouté
remove: Le champ « %{label} » a été supprimé
move:
one: La position dun champ a été modifiée
other: Les positions de %{count} champs ont été modifiées
update_libelle: Le libellé du champ « %{label} » a été modifié. Le nouveau libellé est « %{to} »
update_description: La description du champ « %{label} » a été modifiée. La nouvelle description est « %{to} »
update_drop_down_secondary_libelle: Le libellé secondaire du champ « %{label} » a été modifié. Le nouveau libellé est « %{to} »
update_drop_down_secondary_description: La description secondaire du champ « %{label} » a été modifiée. La nouvelle description est « %{to} »
update_type_champ: Le type du champ « %{label} » a été modifié. Il est maintenant de type « %{to} »
update_mandatory:
enabled: Le champ « %{label} » est maintenant obligatoire
disabled: Le champ « %{label} » nest plus obligatoire
update_piece_justificative_template: Le modèle de pièce justificative du champ « %{label} » a été modifié
update_drop_down_options: Les options de sélection du champ « %{label} » ont été modifiées
update_drop_down_other:
enabled: Le champ « %{label} » comporte maintenant un choix « Autre »
disabled: Le champ « %{label} » ne comporte plus de choix « Autre »
update_carte_layers: Les référentiels cartographiques du champ « %{label} » ont été modifiés
update_collapsible_explanation_enabled:
enabled: "Le texte complementaire affichable au clique du champ « %{label} » a été ajouté"
disabled: "Le texte complementaire affichable au clique du champ « %{label} » a été supprimée"
update_collapsible_explanation_text: "Le texte complementaire affichable au clique du champ « %{label} » a été modifié. Il est maintenant « %{text} »."
add_private: Lannotation privée « %{label} » a été ajoutée
remove_private: Lannotation privée « %{label} » a été supprimée
move_private:
one: La position dune annotation privée a été modifiée
other: Les positions de %{count} annotations privées ont été modifiées
update_libelle_private: Le libellé de lannotation privée « %{label} » a été modifié. Le nouveau libellé est « %{to} »
update_description_private: La description de lannotation privée « %{label} » a été modifiée. La nouvelle description est « %{to} »
update_drop_down_secondary_libelle_private: Le libellé secondaire de lannotation « %{label} » a été modifié. Le nouveau libellé est « %{to} »
update_drop_down_secondary_description_private: La description secondaire de lannotation « %{label} » a été modifiée. La nouvelle description est « %{to} »
update_type_champ_private: Le type de lannotation privée « %{label} » a été modifié. Elle est maintenant de type « %{to} »
update_mandatory_private:
enabled: Lannotation privée « %{label} » est maintenant obligatoire
disabled: Lannotation privée « %{label} » nest plus obligatoire
update_piece_justificative_template_private: Le modèle de pièce justificative de lannotation privée « %{label} » a été modifié
update_drop_down_options_private: Les options de sélection de lannotation privée « %{label} » ont été modifiées
update_carte_layers_private: Les référentiels cartographiques de lannotation privée « %{label} » ont été modifiés
update_collapsible_explanation_enabled_private:
enabled: "Le texte complementaire affichable au clique de lannotation privée « %{label} » a été ajouté"
disabled: "Le texte complementaire affichable au clique de lannotation privée « %{label} » a été supprimée"
update_collapsible_explanation_private: "Le texte complementaire affichable au clique de lannotation privée « %{label} » a été modifié. Il est maintenant « %{text} »."
add_option: "ajoutés : %{items}"
remove_option: "supprimés : %{items}"
add_condition: Une condition a été ajoutée sur le champ « %{label} ». La nouvelle condition est « %{to} »
remove_condition: La condition du champ « %{label} » a été supprimée.
update_condition: La condition du champ « %{label} » a été modifiée. La nouvelle condition est « %{to} »
carte_layers:
unesco: UNESCO
arretes_protection: Arrêtés de protection

View file

@ -332,7 +332,7 @@ describe ProcedureRevision do
let(:second_tdc) { draft.types_de_champ_public.second }
let(:new_draft) { procedure.create_new_revision }
subject { procedure.active_revision.compare(new_draft.reload) }
subject { procedure.active_revision.compare(new_draft.reload).map(&:to_h) }
context 'with a procedure with 2 tdcs' do
let(:procedure) do
@ -354,7 +354,6 @@ describe ProcedureRevision do
attribute: :condition,
from: nil,
label: "l2",
model: :type_de_champ,
op: :update,
private: false,
stable_id: second_tdc.stable_id,
@ -379,7 +378,6 @@ describe ProcedureRevision do
attribute: :condition,
from: "(l1 == 2)",
label: "l2",
model: :type_de_champ,
op: :update,
private: false,
stable_id: second_tdc.stable_id,
@ -404,7 +402,6 @@ describe ProcedureRevision do
attribute: :condition,
from: "(l1 == 2)",
label: "l2",
model: :type_de_champ,
op: :update,
private: false,
stable_id: second_tdc.stable_id,
@ -429,7 +426,6 @@ describe ProcedureRevision do
it do
is_expected.to eq([
{
model: :type_de_champ,
op: :add,
label: "Un champ text",
private: false,
@ -453,7 +449,6 @@ describe ProcedureRevision do
it do
is_expected.to eq([
{
model: :type_de_champ,
op: :update,
attribute: :libelle,
label: first_tdc.libelle,
@ -463,7 +458,6 @@ describe ProcedureRevision do
stable_id: first_tdc.stable_id
},
{
model: :type_de_champ,
op: :update,
attribute: :description,
label: first_tdc.libelle,
@ -473,7 +467,6 @@ describe ProcedureRevision do
stable_id: first_tdc.stable_id
},
{
model: :type_de_champ,
op: :update,
attribute: :mandatory,
label: first_tdc.libelle,
@ -497,7 +490,6 @@ describe ProcedureRevision do
it do
is_expected.to eq([
{
model: :type_de_champ,
op: :update,
attribute: :collapsible_explanation_enabled,
label: first_tdc.libelle,
@ -507,7 +499,6 @@ describe ProcedureRevision do
stable_id: first_tdc.stable_id
},
{
model: :type_de_champ,
op: :update,
attribute: :collapsible_explanation_text,
label: first_tdc.libelle,
@ -535,22 +526,20 @@ describe ProcedureRevision do
it do
is_expected.to eq([
{
model: :type_de_champ,
op: :move,
label: new_draft_third_tdc.libelle,
private: false,
from: 2,
to: 1,
stable_id: new_draft_third_tdc.stable_id
},
{
model: :type_de_champ,
op: :move,
label: new_draft_second_tdc.libelle,
private: false,
from: 1,
to: 2,
stable_id: new_draft_second_tdc.stable_id
},
{
op: :move,
label: new_draft_third_tdc.libelle,
private: false,
from: 2,
to: 1,
stable_id: new_draft_third_tdc.stable_id
}
])
end
@ -566,7 +555,6 @@ describe ProcedureRevision do
it do
is_expected.to eq([
{
model: :type_de_champ,
op: :remove,
label: first_tdc.libelle,
private: false,
@ -587,7 +575,6 @@ describe ProcedureRevision do
it do
is_expected.to eq([
{
model: :type_de_champ,
op: :update,
attribute: :type_champ,
label: "sub type de champ",
@ -597,7 +584,6 @@ describe ProcedureRevision do
stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id
},
{
model: :type_de_champ,
op: :update,
attribute: :drop_down_options,
label: "sub type de champ",
@ -621,7 +607,6 @@ describe ProcedureRevision do
it do
is_expected.to eq([
{
model: :type_de_champ,
op: :update,
attribute: :type_champ,
label: "sub type de champ",
@ -631,7 +616,6 @@ describe ProcedureRevision do
stable_id: new_draft.children_of(new_draft.types_de_champ_public.last).first.stable_id
},
{
model: :type_de_champ,
op: :update,
attribute: :carte_layers,
label: "sub type de champ",