+ {
+ setLayerOpacity(layer, value);
+ }}
+ className="mb-1"
+ title={`Réglage de l’opacité de la couche «${NBS}${name}${NBS}»`}
+ getAriaLabel={() =>
+ `Réglage de l’opacité de la couche «${NBS}${name}${NBS}»`
+ }
+ getAriaValueText={(value) =>
+ `L’opacité de la couche «${NBS}${name}${NBS}» est à ${value}${NBS}%`
+ }
+ />
+
+ )
+ )}
+
+ ) : null}
+
+
);
}
MapStyleControl.propTypes = {
style: PropTypes.string,
- setStyle: PropTypes.func
+ layers: PropTypes.object,
+ setStyle: PropTypes.func,
+ setLayerEnabled: PropTypes.func,
+ setLayerOpacity: PropTypes.func
};
export default MapStyleControl;
diff --git a/app/javascript/components/shared/mapbox/styles/base.js b/app/javascript/components/shared/mapbox/styles/base.js
index e233e607f..172187d57 100644
--- a/app/javascript/components/shared/mapbox/styles/base.js
+++ b/app/javascript/components/shared/mapbox/styles/base.js
@@ -119,9 +119,9 @@ const OPTIONAL_LAYERS = [
function buildSources() {
return Object.fromEntries(
OPTIONAL_LAYERS.filter(({ id }) => id !== 'cadastres')
- .flatMap(({ layers }) => layers)
- .map(([, code]) => [
- code.toLowerCase().replace(/\./g, '-'),
+ .flatMap(({ layers }) => layers.map(([, code]) => code))
+ .map((code) => [
+ getLayerCode(code),
rasterSource([ignServiceURL(code)], 'IGN-F/Géoportail/MNHN')
])
);
@@ -138,25 +138,40 @@ function rasterSource(tiles, attribution) {
};
}
-function rasterLayer(source) {
+function rasterLayer(source, opacity) {
return {
id: source,
source,
type: 'raster',
- paint: { 'raster-resampling': 'linear' }
+ paint: { 'raster-resampling': 'linear', 'raster-opacity': opacity }
};
}
-export function buildOptionalLayers(ids) {
+export function buildOptionalLayers(ids, opacity) {
return OPTIONAL_LAYERS.filter(({ id }) => ids.includes(id))
- .flatMap(({ layers }) => layers)
- .flatMap(([, code]) =>
+ .flatMap(({ layers, id }) =>
+ layers.map(([, code]) => [code, opacity[id] / 100])
+ )
+ .flatMap(([code, opacity]) =>
code === 'CADASTRE'
? cadastreLayers
- : [rasterLayer(code.toLowerCase().replace(/\./g, '-'))]
+ : [rasterLayer(getLayerCode(code), opacity)]
);
}
+export const NBS = ' ';
+
+export function getLayerName(layer) {
+ return OPTIONAL_LAYERS.find(({ id }) => id == layer).label.replace(
+ /\s/g,
+ NBS
+ );
+}
+
+function getLayerCode(code) {
+ return code.toLowerCase().replace(/\./g, '-');
+}
+
export default {
version: 8,
metadat: {
diff --git a/app/javascript/components/shared/mapbox/styles/images/preview-ortho.png b/app/javascript/components/shared/mapbox/styles/images/preview-ortho.png
deleted file mode 100644
index 46db7e467..000000000
Binary files a/app/javascript/components/shared/mapbox/styles/images/preview-ortho.png and /dev/null differ
diff --git a/app/javascript/components/shared/mapbox/styles/images/preview-vector.png b/app/javascript/components/shared/mapbox/styles/images/preview-vector.png
deleted file mode 100644
index 730fc77d2..000000000
Binary files a/app/javascript/components/shared/mapbox/styles/images/preview-vector.png and /dev/null differ
diff --git a/app/javascript/components/shared/mapbox/styles/index.js b/app/javascript/components/shared/mapbox/styles/index.js
index 218cd5ddf..ed97b2aee 100644
--- a/app/javascript/components/shared/mapbox/styles/index.js
+++ b/app/javascript/components/shared/mapbox/styles/index.js
@@ -1,9 +1,11 @@
-import baseStyle, { buildOptionalLayers } from './base';
+import baseStyle, { buildOptionalLayers, getLayerName, NBS } from './base';
import orthoStyle from './layers/ortho';
import vectorStyle from './layers/vector';
import ignLayers from './layers/ign';
-export function getMapStyle(id, optionalLayers) {
+export { getLayerName, NBS };
+
+export function getMapStyle(id, layers, opacity) {
const style = { ...baseStyle, id };
switch (id) {
@@ -21,7 +23,7 @@ export function getMapStyle(id, optionalLayers) {
break;
}
- style.layers = style.layers.concat(buildOptionalLayers(optionalLayers));
+ style.layers = style.layers.concat(buildOptionalLayers(layers, opacity));
return style;
}
diff --git a/app/models/procedure.rb b/app/models/procedure.rb
index 589f2d741..e02100f4b 100644
--- a/app/models/procedure.rb
+++ b/app/models/procedure.rb
@@ -307,9 +307,7 @@ class Procedure < ApplicationRecord
end
def reset!
- if locked?
- raise "Can not reset a locked procedure."
- else
+ if !locked? || draft_changed?
draft_revision.dossiers.destroy_all
end
end
@@ -426,7 +424,9 @@ class Procedure < ApplicationRecord
}
}
include_list[:groupe_instructeurs] = :instructeurs if !is_different_admin
- procedure = self.deep_clone(include: include_list, &method(:clone_attachments))
+ procedure = self.deep_clone(include: include_list) do |original, kopy|
+ PiecesJustificativesService.clone_attachments(original, kopy)
+ end
procedure.path = SecureRandom.uuid
procedure.aasm_state = :brouillon
procedure.closed_at = nil
@@ -472,29 +472,6 @@ class Procedure < ApplicationRecord
procedure
end
- def clone_attachments(original, kopy)
- if original.is_a?(TypeDeChamp)
- clone_attachment(:piece_justificative_template, original, kopy)
- elsif original.is_a?(Procedure)
- clone_attachment(:logo, original, kopy)
- clone_attachment(:notice, original, kopy)
- clone_attachment(:deliberation, original, kopy)
- end
- end
-
- def clone_attachment(attribute, original, kopy)
- original_attachment = original.send(attribute)
- if original_attachment.attached?
- kopy.send(attribute).attach({
- io: StringIO.new(original_attachment.download),
- filename: original_attachment.filename,
- content_type: original_attachment.content_type,
- # we don't want to run virus scanner on cloned file
- metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
- })
- end
- end
-
def whitelisted?
whitelisted_at.present?
end
diff --git a/app/models/procedure_revision.rb b/app/models/procedure_revision.rb
index 13c60c8d4..75513d724 100644
--- a/app/models/procedure_revision.rb
+++ b/app/models/procedure_revision.rb
@@ -249,7 +249,9 @@ class ProcedureRevision < ApplicationRecord
def revise_type_de_champ(type_de_champ)
types_de_champ_association = type_de_champ.private? ? :revision_types_de_champ_private : :revision_types_de_champ
association = send(types_de_champ_association).find_by!(type_de_champ: type_de_champ)
- cloned_type_de_champ = type_de_champ.deep_clone(include: [:types_de_champ], &type_de_champ.method(:clone_attachments))
+ cloned_type_de_champ = type_de_champ.deep_clone(include: [:types_de_champ]) do |original, kopy|
+ PiecesJustificativesService.clone_attachments(original, kopy)
+ end
cloned_type_de_champ.revision = self
association.update!(type_de_champ: cloned_type_de_champ)
cloned_type_de_champ
diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb
index 8874766fc..999d47f23 100644
--- a/app/models/type_de_champ.rb
+++ b/app/models/type_de_champ.rb
@@ -369,23 +369,4 @@ class TypeDeChamp < ApplicationRecord
types_de_champ.destroy_all
end
end
-
- def clone_attachments(original, kopy)
- if original.is_a?(TypeDeChamp)
- clone_attachment(:piece_justificative_template, original, kopy)
- end
- end
-
- def clone_attachment(attribute, original, kopy)
- original_attachment = original.send(attribute)
- if original_attachment.attached?
- kopy.send(attribute).attach({
- io: StringIO.new(original_attachment.download),
- filename: original_attachment.filename,
- content_type: original_attachment.content_type,
- # we don't want to run virus scanner on cloned file
- metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
- })
- end
- end
end
diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb
index c70ace4dc..974e774b8 100644
--- a/app/services/pieces_justificatives_service.rb
+++ b/app/services/pieces_justificatives_service.rb
@@ -49,6 +49,30 @@ class PiecesJustificativesService
end
end
+ def self.clone_attachments(original, kopy)
+ if original.is_a?(TypeDeChamp)
+ clone_attachment(original.piece_justificative_template, kopy.piece_justificative_template)
+ elsif original.is_a?(Procedure)
+ clone_attachment(original.logo, kopy.logo)
+ clone_attachment(original.notice, kopy.notice)
+ clone_attachment(original.deliberation, kopy.deliberation)
+ end
+ end
+
+ def self.clone_attachment(original_attachment, copy_attachment)
+ if original_attachment.attached?
+ original_attachment.open do |tempfile|
+ copy_attachment.attach({
+ io: File.open(tempfile.path),
+ filename: original_attachment.filename,
+ content_type: original_attachment.content_type,
+ # we don't want to run virus scanner on cloned file
+ metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
+ })
+ end
+ end
+ end
+
class FakeAttachment < Hashie::Dash
property :filename
property :name
diff --git a/app/views/commencer/show.html.haml b/app/views/commencer/show.html.haml
index 7abafdd4a..ccd867332 100644
--- a/app/views/commencer/show.html.haml
+++ b/app/views/commencer/show.html.haml
@@ -11,12 +11,12 @@
= link_to 'J’ai déjà un compte', commencer_sign_in_path(path: @procedure.path), class: ['button large expand']
- else
- - dossiers = current_user.dossiers.where(revision: @procedure.revisions)
+ - dossiers = current_user.dossiers.where(revision: @revision.draft? ? @revision : @procedure.revisions.where.not(id: @procedure.draft_revision_id))
- drafts = dossiers.merge(Dossier.state_brouillon)
- not_drafts = dossiers.merge(Dossier.state_not_brouillon)
- if dossiers.count == 0
- = link_to 'Commencer la démarche', url_for_new_dossier(@procedure), class: ['button large expand primary']
+ = link_to 'Commencer la démarche', url_for_new_dossier(@revision), class: ['button large expand primary']
- elsif drafts.count == 1 && not_drafts.count == 0
- dossier = drafts.first
@@ -25,7 +25,7 @@
Il y a #{time_ago_in_words(dossier.created_at)},
vous avez commencé à remplir un dossier sur la démarche « #{dossier.procedure.libelle} ».
= link_to 'Continuer à remplir mon dossier', brouillon_dossier_path(dossier), class: ['button large expand primary']
- = link_to 'Commencer un nouveau dossier', url_for_new_dossier(@procedure), class: ['button large expand']
+ = link_to 'Commencer un nouveau dossier', url_for_new_dossier(@revision), class: ['button large expand']
- elsif not_drafts.count == 1
- dossier = not_drafts.first
@@ -34,17 +34,15 @@
Il y a #{time_ago_in_words(dossier.en_construction_at)},
vous avez déposé un dossier sur la démarche « #{dossier.procedure.libelle} ».
= link_to 'Voir mon dossier déposé', dossier_path(dossier), class: ['button large expand primary']
- = link_to 'Commencer un nouveau dossier', url_for_new_dossier(@procedure), class: ['button large expand']
+ = link_to 'Commencer un nouveau dossier', url_for_new_dossier(@revision), class: ['button large expand']
- else
%h2.huge-title Vous avez déjà des dossiers pour cette démarche
= link_to 'Voir mes dossiers en cours', dossiers_path, class: ['button large expand primary']
- = link_to 'Commencer un nouveau dossier', url_for_new_dossier(@procedure), class: ['button large expand']
+ = link_to 'Commencer un nouveau dossier', url_for_new_dossier(@revision), class: ['button large expand']
- if @procedure.feature_enabled?(:dossier_pdf_vide)
- - pdf_link = commencer_dossier_vide_path(path: @procedure.path)
- - if @procedure.brouillon?
- - pdf_link = commencer_dossier_vide_test_path(path: @procedure.path)
+ - pdf_link = @revision.draft? ? commencer_dossier_vide_test_path(path: @procedure.path) : commencer_dossier_vide_path(path: @procedure.path)
%hr
%p
Vous souhaitez effectuer une demande par papier ? Vous pouvez télécharger un dossier vide au format PDF,
diff --git a/app/views/instructeurs/archives/index.html.haml b/app/views/instructeurs/archives/index.html.haml
index 03d6e53b4..941d3d460 100644
--- a/app/views/instructeurs/archives/index.html.haml
+++ b/app/views/instructeurs/archives/index.html.haml
@@ -30,31 +30,6 @@
%th.center Télécharger
%tbody
- %tr
- - matching_archive = @archives.find { |archive| archive.time_span_type == 'everything' }
- - weight = estimate_weight(matching_archive, @nb_dossiers_termines, @average_dossier_weight)
- %td
- Tous les dossiers
- %td.text-right
- = @nb_dossiers_termines
- %td.text-right
- = number_to_human_size(weight)
- %td.center
- - if matching_archive.try(&:available?)
- = link_to url_for(matching_archive.file), class: 'button primary' do
- %span.icon.download-white
- = t(:archive_ready_html, generated_period: time_ago_in_words(matching_archive.updated_at), scope: [:instructeurs, :procedure])
- - elsif matching_archive.try(&:pending?)
- %span.icon.retry
- = t(:archive_pending_html, created_period: time_ago_in_words(matching_archive.created_at), scope: [:instructeurs, :procedure])
- - elsif @nb_dossiers_termines == 0
- Rien à télécharger !
- - elsif weight < 1.gigabyte
- = link_to instructeur_archives_path(@procedure, type: 'everything'), method: :post, class: "button" do
- %span.icon.new-folder
- Demander la création
- - else
- Archive trop volumineuse
- @count_dossiers_termines_by_month.each do |count_by_month|
- month = count_by_month["month"].to_date
- nb_dossiers_termines = count_by_month["count"]
diff --git a/app/views/layouts/_header.haml b/app/views/layouts/_header.haml
index dbf2ba1a7..80e64b4d5 100644
--- a/app/views/layouts/_header.haml
+++ b/app/views/layouts/_header.haml
@@ -25,11 +25,7 @@
%li
= active_link_to "Démarches", instructeur_procedures_path, active: ['dossiers','procedures'].include?(controller_name), class: 'tab-link'
- if current_instructeur.user.expert && current_expert.avis_summary[:total] > 0
- %li
- = active_link_to expert_all_avis_path, active: controller_name == 'avis', class: 'tab-link' do
- Avis
- - if current_expert.avis_summary[:unanswered] > 0
- %span.badge.warning= current_expert.avis_summary[:unanswered]
+ = render partial: 'layouts/header/avis_tab', locals: { current_expert: current_expert }
- if nav_bar_profile == :expert && expert_signed_in?
%ul.header-tabs
@@ -38,16 +34,14 @@
= active_link_to "Démarches", instructeur_procedures_path, active: ['dossiers','procedures'].include?(controller_name), class: 'tab-link'
- if current_expert.avis_summary[:total] > 0
- %li
- = active_link_to expert_all_avis_path, active: controller_name == 'avis', class: 'tab-link' do
- Avis
- - if current_expert.avis_summary[:unanswered] > 0
- %span.badge.warning= current_expert.avis_summary[:unanswered]
+ = render partial: 'layouts/header/avis_tab', locals: { current_expert: current_expert }
- if nav_bar_profile == :user
%ul.header-tabs
%li
= active_link_to "Dossiers", dossiers_path, active: :inclusive, class: 'tab-link'
+ - if current_user.expert && current_expert.avis_summary[:total] > 0
+ = render partial: 'layouts/header/avis_tab', locals: { current_expert: current_expert }
%ul.header-right-content
- if params[:controller] == 'recherche'
diff --git a/app/views/layouts/header/_avis_tab.html.haml b/app/views/layouts/header/_avis_tab.html.haml
new file mode 100644
index 000000000..79eab2490
--- /dev/null
+++ b/app/views/layouts/header/_avis_tab.html.haml
@@ -0,0 +1,5 @@
+%li
+ = active_link_to expert_all_avis_path, active: controller_name == 'avis', class: 'tab-link' do
+ Avis
+ - if current_expert.avis_summary[:unanswered] > 0
+ %span.badge.warning= current_expert.avis_summary[:unanswered]
diff --git a/app/views/new_administrateur/procedures/publication.html.haml b/app/views/new_administrateur/procedures/publication.html.haml
index 4b07fd278..281966184 100644
--- a/app/views/new_administrateur/procedures/publication.html.haml
+++ b/app/views/new_administrateur/procedures/publication.html.haml
@@ -28,7 +28,7 @@
%p
Cette démarche est actuellement en test,
pour y accéder vous pouvez utiliser le lien :
- = link_to @procedure_lien, sanitize_url(@procedure_lien), target: :blank, rel: :noopener
+ = link_to @procedure_lien_test, sanitize_url(@procedure_lien_test), target: :blank, rel: :noopener
%p.mb-4
Toute personne ayant la connaissance de ce lien pourra ainsi remplir des dossiers de test sur votre démarche.
diff --git a/app/views/new_administrateur/procedures/show.html.haml b/app/views/new_administrateur/procedures/show.html.haml
index 9182af12f..f747f03f6 100644
--- a/app/views/new_administrateur/procedures/show.html.haml
+++ b/app/views/new_administrateur/procedures/show.html.haml
@@ -8,8 +8,8 @@
%span.icon.preview
Prévisualiser
- - if @procedure.brouillon?
- = link_to sanitize_url(@procedure_lien), target: :blank, rel: :noopener, class: 'button' do
+ - if @procedure.brouillon? || @procedure.draft_changed?
+ = link_to sanitize_url(@procedure_lien_test), target: :blank, rel: :noopener, class: 'button' do
%span.icon.in-progress
Tester
diff --git a/config/initializers/sentry.rb b/config/initializers/sentry.rb
index 75bc84ece..442a5f69f 100644
--- a/config/initializers/sentry.rb
+++ b/config/initializers/sentry.rb
@@ -7,13 +7,5 @@ Sentry.init do |config|
config.enabled_environments = ['production', secrets[:environment].presence].compact
config.breadcrumbs_logger = [:active_support_logger]
config.traces_sample_rate = secrets[:enabled] ? 0.001 : nil
- config.excluded_exceptions += [
- # Ignore exceptions caught by ActiveJob.retry_on
- # https://github.com/getsentry/sentry-ruby/issues/1347
- 'Excon::Error::BadRequest',
- 'ActiveStorage::IntegrityError',
- 'VirusScannerJob::FileNotAnalyzedYetError',
- 'TitreIdentiteWatermarkJob::WatermarkFileNotScannedYetError',
- 'APIEntreprise::API::Error::TimedOut'
- ]
+ config.delayed_job.report_after_job_retries = true
end
diff --git a/package.json b/package.json
index 263362691..a8d0871bd 100644
--- a/package.json
+++ b/package.json
@@ -1,13 +1,16 @@
{
"dependencies": {
"@babel/preset-react": "^7.12.13",
+ "@headlessui/react": "^1.3.0",
"@heroicons/react": "^1.0.1",
"@mapbox/mapbox-gl-draw": "^1.2.2",
+ "@popperjs/core": "^2.9.2",
"@rails/actiontext": "^6.0.3",
"@rails/activestorage": "^6.0.3",
"@rails/ujs": "^6.0.3",
"@rails/webpacker": "5.1.1",
"@reach/combobox": "^0.13.0",
+ "@reach/slider": "^0.15.0",
"@sentry/browser": "^5.15.5",
"@tmcw/togeojson": "^4.3.0",
"babel-plugin-macros": "^2.8.0",
@@ -28,6 +31,7 @@
"react-intersection-observer": "^8.31.0",
"react-mapbox-gl": "^5.1.1",
"react-mapbox-gl-draw": "^2.0.4",
+ "react-popper": "^2.2.5",
"react-query": "^3.9.7",
"react-sortable-hoc": "^1.11.0",
"react_ujs": "^2.6.1",
diff --git a/public/422.html b/public/422.html
index a21f82b3b..899adfc29 100644
--- a/public/422.html
+++ b/public/422.html
@@ -1,67 +1,59 @@
-
+
- The change you wanted was rejected (422)
-
+
+
+
+
+
+ Erreur 422 · demarches-simplifiees.fr
+
-
-
-
-
-
The change you wanted was rejected.
-
Maybe you tried to change something you didn't have access to.